From cdffac8b5cacfc3c05e5003ab0b4895e22e8ef64 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Fri, 16 Oct 2026 14:20:30 -0400 Subject: [PATCH 01/10] deps: update V8 to 15.7.112.5 --- deps/v8/AUTHORS | 4 + deps/v8/BUILD.bazel | 135 +- deps/v8/BUILD.gn | 218 +- deps/v8/DEPS | 326 +- deps/v8/agents/PRESUBMIT.py | 17 +- deps/v8/agents/rules/git-cl.md | 58 +- deps/v8/agents/rules/git-commit.md | 11 +- deps/v8/agents/rules/v8-best-practices.md | 6 + deps/v8/agents/rules/writing-skills.md | 12 +- deps/v8/agents/scripts/upload_cl.sh | 206 +- deps/v8/agents/skills/clusterfuzz/SKILL.md | 137 + .../clusterfuzz/scripts/fetch_testcase.py | 398 ++ .../scripts/fetch_testcase_test.py | 140 + .../skills/v8-poc-classification/SKILL.md | 32 +- deps/v8/agents/skills/v8-review/OWNERS | 2 + deps/v8/agents/skills/v8-review/SKILL.md | 224 + .../skills/v8-security-triaging/SKILL.md | 211 +- deps/v8/agents/skills/v8-workflow/SKILL.md | 11 + .../skills/workflow-gerrit-fix/SKILL.md | 9 +- deps/v8/bazel/defs.bzl | 210 +- deps/v8/bazel/v8-generators.bzl | 170 + deps/v8/bazel/v8-non-pointer-compression.bzl | 44 +- deps/v8/gni/v8.gni | 13 +- deps/v8/include/js_protocol.pdl | 15 +- deps/v8/include/v8-callbacks.h | 8 + deps/v8/include/v8-internal.h | 19 +- deps/v8/include/v8-isolate.h | 15 + deps/v8/include/v8-template.h | 2 +- deps/v8/include/v8-version.h | 6 +- deps/v8/include/v8-wasm.h | 5 +- deps/v8/include/v8config.h | 4 - deps/v8/infra/mb/mb_config.pyl | 8 +- deps/v8/src/api/api-natives.cc | 19 +- deps/v8/src/api/api.cc | 31 +- deps/v8/src/ast/prettyprinter.cc | 112 +- deps/v8/src/ast/scopes.cc | 30 + deps/v8/src/ast/scopes.h | 3 + deps/v8/src/base/bits.h | 58 - deps/v8/src/base/cpu/cpu-riscv.cc | 38 + deps/v8/src/base/hashing.h | 6 + deps/v8/src/base/macros.h | 10 - deps/v8/src/base/platform/platform-posix.cc | 14 +- deps/v8/src/base/small-vector.h | 5 +- deps/v8/src/base/unique-array.h | 171 + deps/v8/src/base/vector.h | 312 +- deps/v8/src/baseline/baseline-compiler.cc | 130 +- deps/v8/src/baseline/baseline-compiler.h | 9 + deps/v8/src/builtins/accessors.cc | 42 - deps/v8/src/builtins/accessors.h | 9 +- deps/v8/src/builtins/arm/builtins-arm.cc | 144 +- deps/v8/src/builtins/arm64/builtins-arm64.cc | 164 +- deps/v8/src/builtins/base.tq | 5 - deps/v8/src/builtins/builtins-bigint.cc | 1 + deps/v8/src/builtins/builtins-console.cc | 6 +- .../src/builtins/builtins-constructor-gen.cc | 21 +- deps/v8/src/builtins/builtins-definitions.h | 17 +- deps/v8/src/builtins/builtins-function.cc | 4 - deps/v8/src/builtins/builtins-internal-gen.cc | 12 +- deps/v8/src/builtins/builtins-intl-gen.cc | 24 +- deps/v8/src/builtins/builtins-intl.cc | 11 +- deps/v8/src/builtins/builtins-iterator-inl.h | 14 + deps/v8/src/builtins/builtins-proxy-gen.cc | 25 +- deps/v8/src/builtins/builtins-regexp.cc | 11 +- deps/v8/src/builtins/builtins-string.cc | 9 +- deps/v8/src/builtins/builtins-typed-array.cc | 12 +- deps/v8/src/builtins/builtins-utils.h | 8 +- deps/v8/src/builtins/builtins-wasm-gen.cc | 17 +- deps/v8/src/builtins/cast.tq | 5 + deps/v8/src/builtins/console.tq | 2 +- deps/v8/src/builtins/ia32/builtins-ia32.cc | 155 +- deps/v8/src/builtins/internal.tq | 44 +- deps/v8/src/builtins/js-to-wasm.tq | 13 +- .../src/builtins/loong64/builtins-loong64.cc | 145 +- .../v8/src/builtins/mips64/builtins-mips64.cc | 13 +- deps/v8/src/builtins/ppc/builtins-ppc.cc | 236 +- deps/v8/src/builtins/riscv/builtins-riscv.cc | 173 +- deps/v8/src/builtins/s390/builtins-s390.cc | 139 +- .../src/builtins/setup-builtins-internal.cc | 2 + deps/v8/src/builtins/superspread.h | 3 +- .../builtins/typed-array-createtypedarray.tq | 4 + deps/v8/src/builtins/wasm.tq | 50 +- deps/v8/src/builtins/x64/builtins-x64.cc | 185 +- .../v8/src/codegen/arm/macro-assembler-arm.cc | 2 +- deps/v8/src/codegen/arm/macro-assembler-arm.h | 3 +- .../codegen/arm64/macro-assembler-arm64.cc | 22 +- .../src/codegen/arm64/macro-assembler-arm64.h | 29 +- deps/v8/src/codegen/assembler.cc | 6 +- deps/v8/src/codegen/code-stub-assembler.cc | 151 +- deps/v8/src/codegen/code-stub-assembler.h | 19 +- deps/v8/src/codegen/compiler.cc | 121 +- deps/v8/src/codegen/compiler.h | 17 +- deps/v8/src/codegen/external-reference.cc | 44 +- deps/v8/src/codegen/external-reference.h | 9 +- .../src/codegen/ia32/macro-assembler-ia32.cc | 9 +- .../src/codegen/ia32/macro-assembler-ia32.h | 3 +- .../src/codegen/interface-descriptors-inl.h | 11 + deps/v8/src/codegen/interface-descriptors.h | 35 +- .../loong64/macro-assembler-loong64.cc | 70 +- .../codegen/loong64/macro-assembler-loong64.h | 3 +- deps/v8/src/codegen/maglev-safepoint-table.cc | 2 +- deps/v8/src/codegen/maglev-safepoint-table.h | 5 +- .../codegen/mips64/macro-assembler-mips64.cc | 22 +- .../codegen/mips64/macro-assembler-mips64.h | 3 +- .../src/codegen/optimized-compilation-info.h | 1 - .../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 | 56 +- .../src/codegen/riscv/macro-assembler-riscv.h | 3 +- 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 | 7 +- deps/v8/src/codegen/safepoint-table.h | 9 +- deps/v8/src/codegen/source-position-table.cc | 7 +- deps/v8/src/codegen/source-position-table.h | 3 +- deps/v8/src/codegen/tnode.h | 3 + .../turboshaft-builtins-assembler-inl.h | 6 +- deps/v8/src/codegen/x64/assembler-x64.cc | 1 + deps/v8/src/codegen/x64/assembler-x64.h | 21 +- .../x64/interface-descriptors-x64-inl.h | 3 +- .../v8/src/codegen/x64/macro-assembler-x64.cc | 241 +- deps/v8/src/codegen/x64/macro-assembler-x64.h | 22 +- deps/v8/src/codegen/x64/register-x64.h | 3 +- deps/v8/src/common/globals.h | 69 +- .../optimizing-compile-dispatcher.cc | 4 +- .../optimizing-compile-dispatcher.h | 4 +- deps/v8/src/compiler/OWNERS | 5 +- deps/v8/src/compiler/access-builder.cc | 31 +- deps/v8/src/compiler/access-builder.h | 9 +- .../backend/arm/code-generator-arm.cc | 251 +- .../backend/arm64/code-generator-arm64.cc | 508 ++- .../backend/arm64/instruction-codes-arm64.h | 16 +- .../arm64/instruction-scheduler-arm64.cc | 42 +- .../arm64/instruction-selector-arm64.cc | 425 +- .../v8/src/compiler/backend/code-generator.cc | 109 +- deps/v8/src/compiler/backend/code-generator.h | 21 +- .../backend/ia32/code-generator-ia32.cc | 247 +- .../src/compiler/backend/instruction-codes.h | 7 +- .../compiler/backend/instruction-selector.cc | 67 +- .../compiler/backend/instruction-selector.h | 1 + deps/v8/src/compiler/backend/instruction.h | 6 +- .../backend/loong64/code-generator-loong64.cc | 237 +- .../backend/mips64/code-generator-mips64.cc | 118 +- .../backend/ppc/code-generator-ppc.cc | 276 +- .../backend/register-allocator-verifier.cc | 15 +- .../backend/register-allocator-verifier.h | 8 +- .../compiler/backend/register-allocator.cc | 126 +- .../src/compiler/backend/register-allocator.h | 78 +- .../backend/riscv/code-generator-riscv.cc | 249 +- .../backend/s390/code-generator-s390.cc | 251 +- deps/v8/src/compiler/backend/simd-shuffle.cc | 9 - deps/v8/src/compiler/backend/simd-shuffle.h | 2 - deps/v8/src/compiler/backend/spill-placer.cc | 4 +- deps/v8/src/compiler/backend/spill-placer.h | 1 - .../backend/x64/code-generator-x64.cc | 351 +- .../backend/x64/instruction-selector-x64.cc | 25 +- deps/v8/src/compiler/bytecode-analysis.cc | 40 +- deps/v8/src/compiler/bytecode-liveness-map.h | 21 + deps/v8/src/compiler/code-assembler.h | 3 + .../src/compiler/compilation-dependencies.cc | 5 +- deps/v8/src/compiler/heap-refs.cc | 3 +- deps/v8/src/compiler/heap-refs.h | 21 +- deps/v8/src/compiler/js-call-reducer.cc | 52 +- .../src/compiler/js-context-specialization.cc | 1 - deps/v8/src/compiler/js-create-lowering.cc | 18 +- deps/v8/src/compiler/js-generic-lowering.cc | 3 +- deps/v8/src/compiler/js-heap-broker.cc | 24 +- deps/v8/src/compiler/js-heap-broker.h | 8 + .../js-native-context-specialization.cc | 169 +- .../js-native-context-specialization.h | 5 - deps/v8/src/compiler/js-typed-lowering.cc | 37 +- deps/v8/src/compiler/linkage.cc | 7 +- deps/v8/src/compiler/linkage.h | 41 +- deps/v8/src/compiler/pipeline.cc | 35 +- deps/v8/src/compiler/simplified-lowering.cc | 5 +- deps/v8/src/compiler/simplified-operator.h | 8 +- .../src/compiler/turbofan-graph-visualizer.cc | 45 +- deps/v8/src/compiler/turbofan-types.cc | 2 + deps/v8/src/compiler/turboshaft/assembler.h | 84 +- .../turboshaft/branch-elimination-reducer.h | 16 +- .../duplication-optimization-reducer.h | 55 + deps/v8/src/compiler/turboshaft/fast-hash.h | 8 + deps/v8/src/compiler/turboshaft/graph.h | 24 +- .../turboshaft/growable-stacks-reducer.h | 79 +- ...truction-selection-normalization-reducer.h | 84 + .../turboshaft/int64-lowering-reducer.h | 9 +- .../late-load-elimination-reducer.cc | 20 +- .../late-load-elimination-reducer.h | 61 +- .../compiler/turboshaft/layered-hash-map.h | 3 +- .../turboshaft/loop-peeling-reducer.h | 2 +- .../turboshaft/loop-unrolling-reducer.h | 4 +- deps/v8/src/compiler/turboshaft/operations.cc | 9 +- deps/v8/src/compiler/turboshaft/operations.h | 170 +- deps/v8/src/compiler/turboshaft/opmasks.h | 1 + deps/v8/src/compiler/turboshaft/phase.h | 7 +- deps/v8/src/compiler/turboshaft/pipelines.cc | 2 +- deps/v8/src/compiler/turboshaft/pipelines.h | 12 + .../turboshaft/register-allocation-phase.h | 3 + .../required-optimization-reducer.h | 2 +- .../src/compiler/turboshaft/snapshot-table.h | 2 +- .../turboshaft/stack-check-lowering-reducer.h | 6 +- .../turboshaft/turbolev-frontend-pipeline.cc | 2 + .../turboshaft/turbolev-graph-builder.cc | 77 +- 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 | 47 +- .../wasm-gc-typed-optimization-reducer.h | 4 +- .../wasm-in-js-inlining-reducer-inl.h | 7 +- .../wasm-load-elimination-reducer.cc | 2 +- .../wasm-load-elimination-reducer.h | 35 +- .../turboshaft/wasm-lowering-reducer.h | 114 +- .../compiler/turboshaft/wasm-wrappers-inl.h | 82 +- .../src/compiler/turboshaft/wasm-wrappers.h | 41 +- .../src/compiler/wasm-compiler-definitions.cc | 7 +- deps/v8/src/compiler/wasm-gc-lowering.cc | 6 +- deps/v8/src/compiler/wasm-graph-assembler.cc | 7 +- deps/v8/src/compiler/wasm-graph-assembler.h | 2 +- deps/v8/src/d8/d8-posix.cc | 12 +- deps/v8/src/d8/d8-windows.cc | 3 +- deps/v8/src/d8/d8.cc | 359 +- deps/v8/src/d8/d8.h | 29 +- deps/v8/src/debug/debug-block-list.cc | 6 +- deps/v8/src/debug/debug-evaluate.cc | 21 +- deps/v8/src/debug/debug-interface.cc | 14 +- deps/v8/src/debug/debug-interface.h | 37 +- deps/v8/src/debug/debug-property-iterator.cc | 5 +- 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 | 162 +- deps/v8/src/debug/debug-scopes.h | 30 +- deps/v8/src/debug/debug-wasm-objects.cc | 48 +- deps/v8/src/debug/debug.cc | 144 +- deps/v8/src/debug/debug.h | 30 +- deps/v8/src/deoptimizer/deoptimizer.cc | 39 +- .../deoptimizer/frame-translation-builder.cc | 14 + .../deoptimizer/frame-translation-builder.h | 2 + deps/v8/src/deoptimizer/translated-state.cc | 145 +- deps/v8/src/deoptimizer/translated-state.h | 5 + 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 | 4 +- deps/v8/src/diagnostics/code-tracer.h | 7 +- deps/v8/src/diagnostics/disasm.h | 4 +- deps/v8/src/diagnostics/disassembler.cc | 58 +- 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 | 83 +- deps/v8/src/diagnostics/objects-printer.cc | 52 +- deps/v8/src/diagnostics/perf-jit.cc | 3 +- 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 | 30 +- deps/v8/src/dumpling/object-dumping.cc | 3 +- deps/v8/src/execution/arm/simulator-arm.cc | 16 +- .../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 | 66 +- deps/v8/src/execution/frames.h | 32 +- deps/v8/src/execution/isolate-data-fields.h | 2 + deps/v8/src/execution/isolate-data.h | 7 + deps/v8/src/execution/isolate.cc | 77 +- deps/v8/src/execution/isolate.h | 17 +- .../execution/loong64/simulator-loong64.cc | 18 +- .../src/execution/loong64/simulator-loong64.h | 4 +- deps/v8/src/execution/messages.cc | 20 + .../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 | 471 ++- deps/v8/src/execution/riscv/simulator-riscv.h | 25 +- deps/v8/src/execution/s390/simulator-s390.cc | 21 +- .../src/execution/x64/frame-constants-x64.cc | 9 +- deps/v8/src/flags/feature-flags.h | 22 +- deps/v8/src/flags/flag-definitions.h | 428 +- deps/v8/src/flags/flags.cc | 124 +- deps/v8/src/fuzzilli/cov.cc | 279 +- deps/v8/src/fuzzilli/cov.h | 13 + deps/v8/src/handles/handles-inl.h | 9 +- deps/v8/src/heap/cppgc-internal/caged-heap.cc | 8 +- deps/v8/src/heap/cppgc-internal/free-list.cc | 4 +- deps/v8/src/heap/factory-base-inl.h | 130 +- deps/v8/src/heap/factory-base.cc | 248 +- deps/v8/src/heap/factory-base.h | 35 +- deps/v8/src/heap/factory-inl.h | 3 +- deps/v8/src/heap/factory.cc | 400 +- deps/v8/src/heap/factory.h | 22 +- deps/v8/src/heap/heap-inl.h | 6 +- deps/v8/src/heap/heap-layout-inl.h | 5 + deps/v8/src/heap/heap-visitor.h | 1 + deps/v8/src/heap/heap-write-barrier.h | 2 + deps/v8/src/heap/heap.cc | 57 +- deps/v8/src/heap/heap.h | 31 +- deps/v8/src/heap/mark-compact.cc | 2 +- deps/v8/src/heap/memory-pool.cc | 18 +- 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 | 2 +- deps/v8/src/heap/read-only-heap.cc | 29 + deps/v8/src/heap/read-only-heap.h | 5 + deps/v8/src/heap/read-only-promotion.cc | 4 +- deps/v8/src/heap/scavenger.cc | 6 +- deps/v8/src/heap/setup-heap-internal.cc | 99 +- deps/v8/src/ic/accessor-assembler.cc | 54 +- deps/v8/src/ic/accessor-assembler.h | 7 +- deps/v8/src/ic/ic.cc | 50 +- deps/v8/src/init/bootstrapper.cc | 42 +- deps/v8/src/init/bootstrapper.h | 4 +- deps/v8/src/init/icu_util.cc | 29 +- deps/v8/src/init/isolate-group.cc | 14 + deps/v8/src/inspector/injected-script.cc | 99 +- deps/v8/src/inspector/injected-script.h | 1 - .../v8/src/inspector/v8-console-agent-impl.cc | 3 + deps/v8/src/inspector/v8-console-message.cc | 12 + deps/v8/src/inspector/v8-console-message.h | 1 + deps/v8/src/inspector/v8-console.cc | 63 +- .../src/inspector/v8-debugger-agent-impl.cc | 99 +- .../v8/src/inspector/v8-debugger-agent-impl.h | 15 +- deps/v8/src/inspector/v8-debugger.cc | 25 +- deps/v8/src/inspector/v8-debugger.h | 5 +- .../inspector/v8-inspector-session-impl.cc | 2 +- .../src/inspector/v8-profiler-agent-impl.cc | 3 + .../src/interpreter/bytecode-array-builder.cc | 4 +- .../interpreter/bytecode-array-iterator.cc | 19 + .../src/interpreter/bytecode-array-iterator.h | 4 + .../src/interpreter/bytecode-array-writer.cc | 2 +- deps/v8/src/interpreter/bytecode-generator.cc | 18 +- deps/v8/src/interpreter/bytecode-jump-table.h | 5 +- deps/v8/src/interpreter/bytecodes.h | 6 +- .../src/interpreter/interpreter-generator.cc | 98 +- deps/v8/src/json/json-parser.cc | 153 +- deps/v8/src/json/json-parser.h | 80 + deps/v8/src/json/json-stringifier.cc | 300 +- deps/v8/src/libsampler/DEPS | 8 +- deps/v8/src/libsampler/sampler.cc | 8 + deps/v8/src/logging/counters-definitions.h | 38 +- deps/v8/src/logging/counters-scopes.h | 4 +- deps/v8/src/logging/log.cc | 5 +- deps/v8/src/logging/runtime-call-stats.h | 2 - .../maglev/arm64/maglev-assembler-arm64-inl.h | 1 + .../loong64/maglev-assembler-loong64.cc | 12 +- deps/v8/src/maglev/maglev-assembler.h | 18 + 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 | 3 + .../maglev/maglev-concurrent-dispatcher.cc | 31 +- .../src/maglev/maglev-concurrent-dispatcher.h | 2 - deps/v8/src/maglev/maglev-graph-builder.cc | 459 +- deps/v8/src/maglev/maglev-graph-builder.h | 7 +- deps/v8/src/maglev/maglev-graph-labeller.h | 9 +- deps/v8/src/maglev/maglev-graph-optimizer.cc | 135 +- deps/v8/src/maglev/maglev-graph-optimizer.h | 9 +- deps/v8/src/maglev/maglev-graph-processor.h | 38 +- deps/v8/src/maglev/maglev-graph-serializer.cc | 27 +- deps/v8/src/maglev/maglev-inlining.cc | 46 +- .../maglev/maglev-interpreter-frame-state.h | 81 - deps/v8/src/maglev/maglev-ir.cc | 44 +- deps/v8/src/maglev/maglev-ir.h | 103 +- .../src/maglev/maglev-known-node-aspects.cc | 96 +- .../v8/src/maglev/maglev-known-node-aspects.h | 7 +- .../maglev-phi-representation-selector.cc | 31 +- .../maglev-phi-representation-selector.h | 5 +- ...maglev-post-hoc-optimizations-processors.h | 6 +- .../maglev-pre-regalloc-codegen-processors.h | 10 +- deps/v8/src/maglev/maglev-range-analysis.h | 29 + deps/v8/src/maglev/maglev-reducer-inl.h | 197 +- deps/v8/src/maglev/maglev-reducer.h | 16 + deps/v8/src/maglev/maglev-regalloc.cc | 3 + deps/v8/src/maglev/maglev-truncation.h | 10 +- .../v8/src/maglev/turbolev-escape-analysis.cc | 50 +- deps/v8/src/numbers/conversions.cc | 13 +- deps/v8/src/numbers/ieee754.cc | 7 + deps/v8/src/objects/api-callbacks-inl.h | 8 + deps/v8/src/objects/api-callbacks.h | 12 +- deps/v8/src/objects/arguments-inl.h | 9 +- deps/v8/src/objects/arguments.h | 11 +- deps/v8/src/objects/backing-store.cc | 5 +- deps/v8/src/objects/backing-store.h | 6 + deps/v8/src/objects/bigint.cc | 28 +- deps/v8/src/objects/bigint.h | 14 +- deps/v8/src/objects/bit-field-group.h | 74 + deps/v8/src/objects/bytecode-array-inl.h | 4 + deps/v8/src/objects/bytecode-array.h | 6 +- deps/v8/src/objects/call-site-info-inl.h | 32 +- deps/v8/src/objects/call-site-info.cc | 3 +- deps/v8/src/objects/call-site-info.h | 21 +- deps/v8/src/objects/casting.h | 151 +- deps/v8/src/objects/cell-inl.h | 12 + deps/v8/src/objects/cell.h | 4 + deps/v8/src/objects/code-inl.h | 4 + deps/v8/src/objects/code.cc | 7 +- deps/v8/src/objects/code.h | 2 + deps/v8/src/objects/contexts.h | 10 +- deps/v8/src/objects/contexts.tq | 3 +- deps/v8/src/objects/data-handler.h | 1 + deps/v8/src/objects/debug-objects-inl.h | 100 +- deps/v8/src/objects/debug-objects.cc | 15 +- deps/v8/src/objects/debug-objects.h | 97 +- deps/v8/src/objects/deoptimization-data.cc | 20 +- deps/v8/src/objects/deoptimization-data.h | 12 +- deps/v8/src/objects/descriptor-array-inl.h | 6 + deps/v8/src/objects/descriptor-array.h | 11 +- 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 | 14 +- deps/v8/src/objects/feedback-cell.h | 10 +- deps/v8/src/objects/feedback-vector-inl.h | 61 +- deps/v8/src/objects/feedback-vector.cc | 12 +- deps/v8/src/objects/feedback-vector.h | 56 +- deps/v8/src/objects/fixed-array-base.h | 4 +- deps/v8/src/objects/fixed-array.h | 22 +- .../src/objects/fixed-primitive-array-inl.h | 5 + deps/v8/src/objects/fixed-primitive-array.h | 11 +- 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 | 14 + deps/v8/src/objects/heap-number.h | 34 + deps/v8/src/objects/heap-number.tq | 9 + deps/v8/src/objects/heap-object-set-map-inl.h | 43 + deps/v8/src/objects/heap-object.h | 48 +- deps/v8/src/objects/hole.h | 2 +- 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 | 14 +- deps/v8/src/objects/intl-objects.cc | 17 +- deps/v8/src/objects/intl-objects.h | 5 + deps/v8/src/objects/js-array-buffer-inl.h | 22 +- deps/v8/src/objects/js-array-buffer.cc | 3 +- deps/v8/src/objects/js-array-buffer.h | 24 +- deps/v8/src/objects/js-array.h | 2 +- .../src/objects/js-data-object-builder-inl.h | 31 +- deps/v8/src/objects/js-date-time-format.cc | 5 +- 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.h | 2 +- deps/v8/src/objects/js-duration-format.h | 6 +- deps/v8/src/objects/js-function-inl.h | 6 +- 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-objects-inl.h | 33 +- deps/v8/src/objects/js-objects.cc | 42 +- deps/v8/src/objects/js-objects.h | 39 +- deps/v8/src/objects/js-plural-rules.h | 2 +- deps/v8/src/objects/js-promise.h | 2 +- deps/v8/src/objects/js-promise.tq | 2 +- deps/v8/src/objects/js-regexp-inl.h | 5 +- .../src/objects/js-regexp-string-iterator.h | 2 +- deps/v8/src/objects/js-regexp.h | 9 +- 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-weak-refs-inl.h | 4 +- deps/v8/src/objects/js-weak-refs.h | 8 +- deps/v8/src/objects/keys.cc | 4 +- deps/v8/src/objects/literal-objects-inl.h | 101 +- deps/v8/src/objects/literal-objects.cc | 24 +- deps/v8/src/objects/literal-objects.h | 92 +- deps/v8/src/objects/lookup-inl.h | 2 +- deps/v8/src/objects/lookup.cc | 15 +- deps/v8/src/objects/map-inl.h | 74 +- deps/v8/src/objects/map.cc | 73 +- deps/v8/src/objects/map.h | 136 +- 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 | 9 +- deps/v8/src/objects/module.cc | 18 +- deps/v8/src/objects/name-inl.h | 5 +- deps/v8/src/objects/name.h | 12 +- deps/v8/src/objects/number-string-cache-inl.h | 8 +- deps/v8/src/objects/object-list-macros.h | 5 +- deps/v8/src/objects/object-macros-undef.h | 13 + deps/v8/src/objects/object-macros.h | 36 + .../objects/objects-body-descriptors-inl.h | 19 +- deps/v8/src/objects/objects-definitions.h | 5 +- deps/v8/src/objects/objects-inl.h | 16 +- deps/v8/src/objects/objects.cc | 61 +- deps/v8/src/objects/objects.h | 7 +- deps/v8/src/objects/oddball-inl.h | 40 +- 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 | 26 +- 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/prototype-info-inl.h | 14 + deps/v8/src/objects/prototype-info.h | 7 +- deps/v8/src/objects/regexp-match-info.h | 2 + deps/v8/src/objects/scope-info-inl.h | 8 +- deps/v8/src/objects/scope-info.cc | 37 +- deps/v8/src/objects/scope-info.h | 75 +- deps/v8/src/objects/script-inl.h | 69 +- deps/v8/src/objects/script.h | 23 +- .../v8/src/objects/shared-function-info-inl.h | 13 + deps/v8/src/objects/shared-function-info.cc | 49 +- deps/v8/src/objects/shared-function-info.h | 62 +- deps/v8/src/objects/shared-function-info.tq | 2 +- deps/v8/src/objects/simd.cc | 14 +- deps/v8/src/objects/slots.h | 2 +- deps/v8/src/objects/sort-state.h | 2 +- deps/v8/src/objects/source-text-module-inl.h | 61 +- deps/v8/src/objects/source-text-module.h | 61 +- deps/v8/src/objects/string-inl.h | 17 +- deps/v8/src/objects/string.cc | 26 +- deps/v8/src/objects/string.h | 18 +- 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 | 134 +- deps/v8/src/objects/swiss-name-dictionary.tq | 9 +- deps/v8/src/objects/tagged-field-inl.h | 49 + deps/v8/src/objects/tagged-field.h | 38 +- 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 | 14 + deps/v8/src/objects/templates.h | 14 +- deps/v8/src/objects/trusted-pointer-inl.h | 28 + deps/v8/src/objects/trusted-pointer.h | 11 +- deps/v8/src/objects/turbofan-types.h | 6 +- deps/v8/src/objects/turboshaft-types.h | 15 +- deps/v8/src/objects/value-serializer.cc | 28 +- deps/v8/src/parsing/expression-scope.h | 56 +- deps/v8/src/parsing/literal-buffer.cc | 32 +- deps/v8/src/parsing/literal-buffer.h | 5 +- deps/v8/src/parsing/parser-base.h | 210 +- deps/v8/src/parsing/parser.cc | 29 +- deps/v8/src/parsing/parser.h | 3 +- deps/v8/src/parsing/preparse-data.cc | 2 +- deps/v8/src/parsing/preparse-data.h | 1 - deps/v8/src/parsing/preparser.cc | 49 +- deps/v8/src/parsing/preparser.h | 13 +- deps/v8/src/parsing/scanner.cc | 2 +- deps/v8/src/parsing/scanner.h | 5 + .../src/profiler/heap-snapshot-generator.cc | 89 +- .../v8/src/profiler/heap-snapshot-generator.h | 2 + deps/v8/src/profiler/output-stream-writer.h | 6 +- deps/v8/src/profiler/profiler-listener.cc | 5 +- deps/v8/src/profiler/strings-storage.cc | 25 +- .../regexp/arm/regexp-macro-assembler-arm.cc | 57 +- .../regexp/arm/regexp-macro-assembler-arm.h | 7 +- .../arm64/regexp-macro-assembler-arm64.cc | 97 +- .../arm64/regexp-macro-assembler-arm64.h | 10 +- deps/v8/src/regexp/gen-regexp-special-case.cc | 18 + .../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 | 89 +- deps/v8/src/regexp/regexp-compiler.h | 6 +- deps/v8/src/regexp/regexp-interpreter.cc | 3 +- deps/v8/src/regexp/regexp-nodes.h | 7 +- deps/v8/src/regexp/regexp-parser.cc | 173 +- deps/v8/src/regexp/regexp-stack.h | 45 +- .../riscv/regexp-macro-assembler-riscv.cc | 67 +- .../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 | 71 +- .../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 | 28 +- deps/v8/src/roots/static-roots-intl-nowasm.h | 11 +- deps/v8/src/roots/static-roots-intl-wasm.h | 11 +- .../v8/src/roots/static-roots-nointl-nowasm.h | 11 +- deps/v8/src/roots/static-roots-nointl-wasm.h | 11 +- deps/v8/src/runtime/runtime-array.cc | 21 +- deps/v8/src/runtime/runtime-compiler.cc | 61 +- deps/v8/src/runtime/runtime-debug.cc | 1 + deps/v8/src/runtime/runtime-forin.cc | 75 +- deps/v8/src/runtime/runtime-literals.cc | 9 +- deps/v8/src/runtime/runtime-object.cc | 2 +- deps/v8/src/runtime/runtime-test-wasm.cc | 5 +- deps/v8/src/runtime/runtime-test.cc | 14 +- deps/v8/src/runtime/runtime-wasm.cc | 93 +- deps/v8/src/runtime/runtime.h | 4 +- deps/v8/src/sandbox/code-entrypoint-tag.h | 15 +- .../src/sandbox/external-pointer-table-inl.h | 34 +- deps/v8/src/sandbox/indirect-pointer-tag.h | 66 +- 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 | 68 +- deps/v8/src/sandbox/sandbox-malloc.h | 32 +- deps/v8/src/sandbox/sandbox.h | 4 + deps/v8/src/sandbox/testing.cc | 71 +- deps/v8/src/snapshot/code-serializer.cc | 249 +- deps/v8/src/snapshot/code-serializer.h | 219 +- deps/v8/src/snapshot/context-deserializer.h | 5 +- deps/v8/src/snapshot/deserializer.cc | 81 +- deps/v8/src/snapshot/deserializer.h | 18 +- .../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 | 3 +- deps/v8/src/snapshot/serializer.cc | 16 +- .../src/snapshot/shared-heap-deserializer.h | 4 +- deps/v8/src/snapshot/snapshot-compression.cc | 11 +- deps/v8/src/snapshot/snapshot-data.cc | 6 +- deps/v8/src/snapshot/snapshot-source-sink.h | 10 +- deps/v8/src/snapshot/snapshot.cc | 17 +- deps/v8/src/snapshot/startup-deserializer.h | 3 +- deps/v8/src/strings/string-stream.cc | 21 +- deps/v8/src/strings/uri.cc | 8 +- deps/v8/src/torque/cpp-builder.cc | 19 +- 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 | 8 + deps/v8/src/torque/global-context.cc | 2 + deps/v8/src/torque/global-context.h | 41 + deps/v8/src/torque/implementation-visitor.cc | 252 +- 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 | 1844 ++++++++ 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 | 50 + deps/v8/src/torque/torque-parser.h | 10 + deps/v8/src/torque/torque.cc | 10 + deps/v8/src/torque/type-visitor.cc | 3 + deps/v8/src/torque/types.cc | 24 +- 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/utils.h | 105 + .../baseline/arm/liftoff-assembler-arm-inl.h | 67 +- .../arm64/liftoff-assembler-arm64-inl.h | 71 +- .../ia32/liftoff-assembler-ia32-inl.h | 66 +- .../v8/src/wasm/baseline/liftoff-assembler.cc | 7 +- deps/v8/src/wasm/baseline/liftoff-assembler.h | 7 +- deps/v8/src/wasm/baseline/liftoff-compiler.cc | 258 +- deps/v8/src/wasm/baseline/liftoff-compiler.h | 2 +- .../loong64/liftoff-assembler-loong64-inl.h | 74 +- .../mips64/liftoff-assembler-mips64-inl.h | 18 +- .../baseline/ppc/liftoff-assembler-ppc-inl.h | 83 +- .../riscv/liftoff-assembler-riscv-inl.h | 69 +- .../riscv/liftoff-assembler-riscv32-inl.h | 5 +- .../riscv/liftoff-assembler-riscv64-inl.h | 5 +- .../s390/liftoff-assembler-s390-inl.h | 82 +- .../baseline/x64/liftoff-assembler-x64-inl.h | 159 +- deps/v8/src/wasm/c-api.cc | 7 +- deps/v8/src/wasm/canonical-types.cc | 8 +- deps/v8/src/wasm/canonical-types.h | 1 + .../src/wasm/compilation-hints-generation.cc | 13 +- deps/v8/src/wasm/decoder.h | 5 +- deps/v8/src/wasm/function-body-decoder-impl.h | 15 +- deps/v8/src/wasm/function-compiler.h | 11 +- .../wasm/fuzzing/random-module-generation.cc | 20 +- .../wasm-interpreter-runtime-inl.h | 2 +- .../src/wasm/interpreter/wasm-interpreter.cc | 3 +- .../src/wasm/interpreter/wasm-interpreter.h | 7 +- deps/v8/src/wasm/jump-table-assembler.cc | 15 +- deps/v8/src/wasm/module-compiler.cc | 39 +- deps/v8/src/wasm/module-compiler.h | 7 +- deps/v8/src/wasm/module-decoder-impl.h | 22 +- deps/v8/src/wasm/module-decoder.cc | 13 +- deps/v8/src/wasm/module-decoder.h | 5 +- deps/v8/src/wasm/module-instantiate.cc | 8 +- deps/v8/src/wasm/names-provider.h | 3 +- deps/v8/src/wasm/pgo.cc | 35 +- 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 | 19 +- deps/v8/src/wasm/streaming-decoder.h | 5 +- deps/v8/src/wasm/struct-types.h | 43 +- .../v8/src/wasm/turboshaft-graph-interface.cc | 224 +- deps/v8/src/wasm/wasm-builtin-list.h | 6 +- deps/v8/src/wasm/wasm-code-coverage.h | 13 +- deps/v8/src/wasm/wasm-code-manager.cc | 18 +- deps/v8/src/wasm/wasm-code-manager.h | 5 +- deps/v8/src/wasm/wasm-debug.cc | 212 +- deps/v8/src/wasm/wasm-deopt-data.cc | 5 +- deps/v8/src/wasm/wasm-deopt-data.h | 3 +- deps/v8/src/wasm/wasm-engine.cc | 159 +- deps/v8/src/wasm/wasm-engine.h | 7 +- deps/v8/src/wasm/wasm-external-refs.cc | 127 +- deps/v8/src/wasm/wasm-external-refs.h | 5 +- deps/v8/src/wasm/wasm-js.cc | 74 +- deps/v8/src/wasm/wasm-module-builder.cc | 4 +- deps/v8/src/wasm/wasm-module.h | 5 +- deps/v8/src/wasm/wasm-objects-inl.h | 100 +- deps/v8/src/wasm/wasm-objects.cc | 180 +- deps/v8/src/wasm/wasm-objects.h | 140 +- deps/v8/src/wasm/wasm-objects.tq | 2 +- deps/v8/src/wasm/wasm-result.cc | 4 +- deps/v8/src/wasm/wasm-serialization.cc | 21 +- deps/v8/src/wasm/wasm-serialization.h | 3 +- deps/v8/src/zone/zone-chunk-list.h | 536 --- deps/v8/test/cctest/BUILD.gn | 7 +- deps/v8/test/cctest/cctest.cc | 6 +- deps/v8/test/cctest/cctest.status | 80 - deps/v8/test/cctest/collector.h | 76 +- .../cctest/compiler/test-code-generator.cc | 11 +- deps/v8/test/cctest/heap/heap-tester.h | 73 +- deps/v8/test/cctest/heap/heap-utils.cc | 79 +- deps/v8/test/cctest/heap/heap-utils.h | 29 - deps/v8/test/cctest/heap/test-heap.cc | 2784 ------------ .../heap/test-limit-based-memory-reducer.cc | 209 + deps/v8/test/cctest/heap/test-mark-compact.cc | 382 -- 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 - deps/v8/test/cctest/test-api-array-buffer.cc | 3 +- deps/v8/test/cctest/test-api-incumbent.cc | 9 +- deps/v8/test/cctest/test-api-interceptors.cc | 3 +- deps/v8/test/cctest/test-api-stack-traces.cc | 115 +- deps/v8/test/cctest/test-api-typed-array.cc | 7 +- deps/v8/test/cctest/test-api.cc | 82 +- deps/v8/test/cctest/test-cpu-profiler.cc | 32 +- deps/v8/test/cctest/test-debug-helper.cc | 26 +- deps/v8/test/cctest/test-debug.cc | 148 +- .../test/cctest/test-field-type-tracking.cc | 5 +- deps/v8/test/cctest/test-heap-profiler.cc | 19 +- deps/v8/test/cctest/test-js-to-wasm.cc | 3 +- deps/v8/test/cctest/test-log-stack-tracer.cc | 6 +- deps/v8/test/cctest/test-profile-generator.cc | 16 +- deps/v8/test/cctest/test-sampler-api.cc | 11 +- deps/v8/test/cctest/test-serialize.cc | 547 ++- deps/v8/test/cctest/test-shared-strings.cc | 5 +- 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 | 38 + deps/v8/test/cctest/test-utils.cc | 23 +- .../cctest/wasm/test-compilation-cache.cc | 13 +- deps/v8/test/cctest/wasm/test-gc.cc | 7 +- deps/v8/test/cctest/wasm/test-run-wasm-f16.cc | 93 + deps/v8/test/cctest/wasm/test-run-wasm-js.cc | 10 +- .../test/cctest/wasm/test-wasm-breakpoints.cc | 57 + deps/v8/test/cctest/wasm/test-wasm-metrics.cc | 3 +- .../cctest/wasm/test-wasm-serialization.cc | 35 +- .../cctest/wasm/test-wasm-shared-engine.cc | 3 +- deps/v8/test/common/wasm/fuzzer-common.cc | 90 +- .../v8/test/common/wasm/wasm-module-runner.cc | 3 +- deps/v8/test/common/wasm/wasm-run-utils.cc | 70 +- deps/v8/test/common/wasm/wasm-run-utils.h | 16 + .../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 +- .../debug/harmony/modules-debug-scopes1.mjs | 18 +- .../regress-debug-scopes-context-blocklist.js | 5 +- .../regress/wasm/regress-570547314.js | 68 + deps/v8/test/debugger/test-api.js | 10 +- ...ad-rest-parameter-late-inlined-mutation.js | 42 + .../wasm-turbolev-inlined-wrapper.js | 13 +- .../turbofan-extern-convert-any-static.js | 2 +- deps/v8/test/fuzzer/wasm/async.cc | 3 +- deps/v8/test/fuzzer/wasm/deopt.cc | 7 +- deps/v8/test/fuzzer/wasm/init-expr.cc | 3 +- .../wasm/interpreter/fast-interpreter.cc | 3 +- .../wasm/interpreter/interpreter-diff.cc | 3 +- .../interpreter/interpreter-fuzzer-common.cc | 7 +- .../wasm/interpreter/interpreter-init-expr.cc | 3 +- deps/v8/test/fuzzer/wasm/module.cc | 3 +- deps/v8/test/fuzzer/wasm/streaming.cc | 3 +- .../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 +- ...-constructor-anonymous-scopes-expected.txt | 1 + ...-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 + .../scope-chain-outer-scopes-expected.txt | 231 + .../debugger/scope-chain-outer-scopes.js | 248 ++ .../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 + .../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 + .../wasm-inspect-inline-trap-expected.txt | 8 +- .../debugger/wasm-inspect-inline-trap.js | 25 +- .../regress-crbug-383029265-expected.txt | 46 +- .../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 + .../runtime/console-context-expected.txt | 13 + .../test/inspector/runtime/console-context.js | 22 + ...ow-on-side-effect-wrap-result-expected.txt | 32 + ...aluate-throw-on-side-effect-wrap-result.js | 204 + ...fer-side-effect-free-evaluate-expected.txt | 25 + .../import-defer-side-effect-free-evaluate.js | 99 + deps/v8/test/intl/regexp-case-equivalence.js | 63 +- deps/v8/test/intl/regress-110086.js | 13 + .../message/fail/bundle-duplicate-module.js | 14 + .../message/fail/bundle-duplicate-module.out | 1 + .../array-index-undefined-optimized.js | 56 + .../baseline/embedded-feedback-monotonic.js | 39 + deps/v8/test/mjsunit/code-cache-sha256.js | 11 + .../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 + deps/v8/test/mjsunit/d8/regress-564550564.js | 28 + .../mjsunit/es6/classes-subclass-builtins.js | 14 +- .../es6/regress-arrow-cover-grammar-scope.js | 38 + .../regress-arrow-head-pattern-error-order.js | 61 + .../es6/regress-arrow-reparse-strict-param.js | 24 + ...ess-comma-expression-arrow-initializers.js | 15 + ...ess-conditional-chain-non-short-circuit.js | 34 + .../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-static-field-await-identifier.js | 56 + ...ss-strict-eval-destructuring-subpattern.js | 34 + .../es6/regress-strict-octal-after-rbrace.js | 57 + .../regress-subpattern-validate-expression.js | 44 + .../es6/regress-super-optional-chain.js | 18 + .../es6/regress-yield-expression-scope.js | 19 + .../modules-import-defer-terminate.mjs | 15 + ...p-unicode-sets-class-string-disjunction.js | 94 + .../mjsunit/harmony/shadowrealm-evaluate.js | 2 +- .../test/mjsunit/maglev/regress-563882510.js | 49 + .../test/mjsunit/maglev/regress-564326894.js | 29 + .../test/mjsunit/maglev/regress-569212098.js | 13 + .../mjsunit/maglev/regress-569286602-1.js | 24 + .../mjsunit/maglev/regress-569286602-2.js | 24 + .../test/mjsunit/maglev/regress-569947577.js | 24 + .../test/mjsunit/maglev/regress-570091260.js | 50 + .../maglev/script-context-specialization.js | 466 ++ .../spread-rest-parameter-element-mutation.js | 103 + deps/v8/test/mjsunit/mjsunit.js | 20 +- deps/v8/test/mjsunit/mjsunit.status | 53 +- .../mjsunit/parser/array-literal-fast-path.js | 89 + .../mjsunit/regexp-boyer-moore-backtrack.js | 9 + deps/v8/test/mjsunit/regexp-unicode-sets.js | 14 + deps/v8/test/mjsunit/regexp/drain.js | 17 + .../regress/fast-proxy-load-ic-bailouts.js | 18 +- .../test/mjsunit/regress/regress-535071448.js | 259 ++ .../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 + .../test/mjsunit/regress/regress-564012076.js | 40 + .../test/mjsunit/regress/regress-564879562.js | 75 + .../test/mjsunit/regress/regress-566091009.js | 69 + .../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 + .../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-568341998.js | 10 + .../test/mjsunit/regress/regress-568633429.js | 25 + .../test/mjsunit/regress/regress-568654095.js | 11 + .../test/mjsunit/regress/regress-568794851.js | 99 + .../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 + .../mjsunit/regress/regress-570003644-1.js | 110 + .../mjsunit/regress/regress-570003644-2.js | 111 + .../mjsunit/regress/regress-570203091-1.js | 29 + .../mjsunit/regress/regress-570203091-2.js | 35 + .../test/mjsunit/regress/regress-570547313.js | 59 + .../test/mjsunit/regress/regress-571397035.js | 93 + .../test/mjsunit/regress/regress-571871980.js | 45 + .../mjsunit/regress/regress-crbug-917076.js | 2 +- .../regress-fast-proxy-deprecated-map.js | 79 + .../regress-fast-proxy-target-toctou.js | 316 ++ .../regress/regress-homomorphic-maglev.js | 4 + .../regress/regress-homomorphic-turbofan.js | 4 + .../regress-homomorphic-unoptimized.js | 5 +- .../mjsunit/regress/wasm/regress-533578412.js | 32 + .../mjsunit/regress/wasm/regress-534275413.js | 8 +- .../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 | 42 + .../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-569886678.js | 56 + .../mjsunit/regress/wasm/regress-570433240.js | 72 + .../mjsunit/regress/wasm/regress-570433264.js | 80 + .../mjsunit/regress/wasm/regress-570538338.js | 101 + .../mjsunit/regress/wasm/regress-571155505.js | 7 + .../mjsunit/regress/wasm/regress-571700025.js | 40 + .../regress/wasm/regress-simd-570497964.js | 155 + .../sandbox/fixed-double-array-field-count.js | 38 + .../test/mjsunit/sandbox/regress-564835629.js | 16 + .../test/mjsunit/sandbox/regress-566142291.js | 75 + .../test/mjsunit/sandbox/regress-567222739.js | 37 + .../test/mjsunit/sandbox/regress-571126471.js | 69 + .../test/mjsunit/sandbox/regress-571127829.js | 125 + .../sandbox/regress/regress-555304822.js | 110 + .../sandbox/regress/regress-567526351.js | 50 + .../sandbox/regress/regress-568338771.js | 47 + .../sandbox/wasm-suspender-stack-reference.js | 56 + .../test/mjsunit/sandbox/wasmfx-jspi-uaf.js | 69 + .../string-index-undefined-optimized.js | 79 + .../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/regress-564329221.js | 22 + .../mjsunit/turbolev/regress-567129324.js | 38 + .../mjsunit/turbolev/regress-567993838.js | 32 + .../mjsunit/turbolev/regress-568010379.js | 48 + .../mjsunit/turbolev/regress-568348290.js | 149 + .../mjsunit/turbolev/regress-571002038.js | 65 + .../turbolev/regress-forin-type-confusion.js | 44 + .../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 +- .../test/mjsunit/wasm/regress-535877252-2.js | 92 + .../v8/test/mjsunit/wasm/regress-535877252.js | 92 + .../v8/test/mjsunit/wasm/regress-569014241.js | 107 + .../wasm/shared-everything/wait-queue.js | 25 + .../wasm/shared-memory-grow-bounds-check.js | 65 + .../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-replace-lane-zero.js | 32 +- .../test/mjsunit/wasm/simd-shift-left-long.js | 100 + 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 | 127 +- deps/v8/test/unittests/BUILD.gn | 7 +- .../v8/test/unittests/api/api-icu-unittest.cc | 28 + .../test/unittests/api/api-wasm-unittest.cc | 86 +- .../unittests/api/deserialize-unittest.cc | 144 + .../unittests/api/interceptor-unittest.cc | 64 + .../test/unittests/api/v8-script-unittest.cc | 334 ++ .../assembler/assembler-arm64-unittest.cc | 42 + .../assembler/assembler-riscv64-unittest.cc | 135 + .../assembler/assembler-x64-unittest.cc | 73 + .../assembler/disasm-arm-unittest.cc | 5 +- .../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 | 67 +- deps/v8/test/unittests/base/bits-unittest.cc | 43 - .../test/unittests/base/hashing-unittest.cc | 54 + .../unittests/base/unique-array-unittest.cc | 87 + .../v8/test/unittests/base/vector-unittest.cc | 147 +- .../aligned-slot-allocator-unittest.cc | 6 +- .../codegen/safepoint-table-unittest.cc | 10 +- ...aft-instruction-selector-arm64-unittest.cc | 461 +- .../compiler/bytecode-analysis-unittest.cc | 35 + .../unittests/compiler/compiler-unittest.cc | 10 +- .../unittests/compiler/node-test-utils.cc | 2 - .../run-bytecode-graph-builder-unittest.cc | 119 +- .../compiler/run-variables-unittest.cc | 8 +- ...plication-optimization-reducer-unittest.cc | 254 ++ ...election-normalization-reducer-unittest.cc | 69 +- .../machine-optimization-reducer-unittest.cc | 108 + ...shaft-instruction-selector-x64-unittest.cc | 69 + .../debug/debug-scope-info-unittest.cc | 206 +- .../deoptimizer/deoptimization-unittest.cc | 7 +- .../flags/flag-definitions-unittest.cc | 178 +- deps/v8/test/unittests/heap/heap-unittest.cc | 3767 ++++++++++++++--- deps/v8/test/unittests/heap/heap-utils.cc | 87 +- deps/v8/test/unittests/heap/heap-utils.h | 82 +- .../unittests/heap/local-factory-unittest.cc | 16 +- .../unittests/heap/mark-compact-unittest.cc | 219 + deps/v8/test/unittests/heap/pool-unittest.cc | 405 -- .../v8/test/unittests/heap/spaces-unittest.cc | 1412 +++++- .../heap/weak-references-unittest.cc} | 471 +-- .../unittests/heap/write-barrier-unittest.cc | 71 +- .../ObjectLiterals.golden | 24 + .../interpreter/bytecodes-unittest.cc | 8 +- .../unittests/libplatform/tracing-unittest.cc | 2 + .../v8/test/unittests/logging/log-unittest.cc | 33 +- .../unittests/objects/casting-unittest.cc | 215 + .../test/unittests/objects/object-unittest.cc | 2 +- .../objects/string-table-unittest.cc | 4 +- .../objects/value-serializer-unittest.cc | 38 +- .../objects/weakarraylist-unittest.cc | 13 + .../test/unittests/parser/parsing-unittest.cc | 19 +- .../unittests/parser/preparser-unittest.cc | 4 +- .../test/unittests/parser/scanner-unittest.cc | 42 + .../profiler/heap-snapshot-scopes-unittest.cc | 19 +- .../test/unittests/regexp/regexp-unittest.cc | 32 +- .../regress/regress-536954139-unittest.cc | 6 +- deps/v8/test/unittests/run-all-unittests.cc | 213 + .../sandbox/bytecode-verifier-unittest.cc | 2 +- deps/v8/test/unittests/test-utils.h | 5 +- deps/v8/test/unittests/testcfg.py | 13 + .../test/unittests/torque/torque-unittest.cc | 868 ++++ deps/v8/test/unittests/unittests.status | 65 +- .../unittests/utils/bit-vector-unittest.cc | 46 + .../v8/test/unittests/utils/utils-unittest.cc | 12 +- .../test/unittests/utils/version-unittest.cc | 14 +- .../wasm/basic-block-calculator-unittest.cc | 13 +- .../wasm/function-body-decoder-unittest.cc | 3 +- .../wasm/liftoff-register-unittests.cc | 14 +- .../wasm/memory-protection-unittest.cc | 3 +- ...imd-cross-compiler-determinism-fuzztest.cc | 219 + .../wasm/streaming-decoder-unittest.cc | 7 +- .../unittests/wasm/struct-types-unittest.cc | 17 +- .../test/unittests/wasm/subtyping-unittest.cc | 7 +- .../wasm/type-canonicalization-fuzztest.cc | 2 +- .../test/unittests/wasm/wasm-compile-module.h | 5 +- .../test/unittests/wasm/wasm-usecounters.cc | 3 +- .../zone/zone-chunk-list-unittest.cc | 436 -- deps/v8/testing/gtest-support.h | 1 - deps/v8/third_party/abseil-cpp/BUILD.gn | 1 + .../abseil-cpp/CMake/AbseilDll.cmake | 2 +- .../v8/third_party/abseil-cpp/README.chromium | 2 +- .../third_party/abseil-cpp/absl/BUILD.bazel | 12 + .../abseil-cpp/absl/base/BUILD.bazel | 3 + .../abseil-cpp/absl/base/attributes.h | 128 +- .../abseil-cpp/absl/base/attributes_test.cc | 34 +- .../third_party/abseil-cpp/absl/base/config.h | 15 +- .../absl/base/dynamic_annotations.h | 2 - .../absl/base/internal/cpu_detect.cc | 6 + .../absl/base/internal/cpu_detect.h | 3 + .../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/container/BUILD.bazel | 31 +- .../abseil-cpp/absl/container/BUILD.gn | 14 + .../abseil-cpp/absl/container/CMakeLists.txt | 22 + .../absl/container/btree_instantiate_test.cc | 731 ++++ .../abseil-cpp/absl/container/btree_test.cc | 683 +-- .../abseil-cpp/absl/container/flat_hash_map.h | 40 +- .../absl/container/flat_hash_set_test.cc | 10 + .../container/internal/container_memory.h | 67 +- .../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 | 59 +- .../absl/container/internal/raw_hash_set.cc | 319 +- .../absl/container/internal/raw_hash_set.h | 660 +-- .../internal/raw_hash_set_allocator_test.cc | 11 + .../container/internal/raw_hash_set_test.cc | 261 +- .../absl/container/linked_hash_map.h | 38 +- .../absl/container/linked_hash_map_test.cc | 131 + .../absl/container/linked_hash_set.h | 38 +- .../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 | 3 + .../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 | 543 ++- .../abseil-cpp/absl/debugging/BUILD.bazel | 1 + .../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 | 132 +- .../abseil-cpp/absl/flags/BUILD.bazel | 1 + .../abseil-cpp/absl/flags/BUILD.gn | 1 + .../abseil-cpp/absl/flags/CMakeLists.txt | 1 + .../third_party/abseil-cpp/absl/flags/flag.h | 10 + .../abseil-cpp/absl/flags/flag_test.cc | 73 +- .../abseil-cpp/absl/flags/reflection.cc | 10 +- .../abseil-cpp/absl/flags/reflection.h | 13 +- .../functional/function_type_benchmark.cc | 2 +- .../abseil-cpp/absl/hash/BUILD.bazel | 3 +- .../third_party/abseil-cpp/absl/hash/BUILD.gn | 3 +- .../abseil-cpp/absl/hash/CMakeLists.txt | 3 +- .../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/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 +- .../absl/random/internal/BUILD.bazel | 1 + .../random/log_uniform_int_distribution.h | 25 +- .../log_uniform_int_distribution_test.cc | 20 + .../absl/status/internal/status_internal.h | 13 - .../abseil-cpp/absl/status/status.cc | 2 + .../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 | 1 + .../abseil-cpp/absl/strings/BUILD.gn | 1 + .../abseil-cpp/absl/strings/CMakeLists.txt | 1 + .../abseil-cpp/absl/strings/cord.cc | 2 + .../abseil-cpp/absl/strings/cord_test.cc | 10 + .../internal/append_and_overwrite_test.cc | 2 +- .../absl/strings/internal/cordz_info.h | 6 +- .../absl/strings/internal/str_join_internal.h | 18 +- .../abseil-cpp/absl/strings/numbers.cc | 6 +- .../abseil-cpp/absl/strings/str_join_test.cc | 10 + .../abseil-cpp/absl/strings/string_view.h | 1 - .../absl/synchronization/BUILD.bazel | 1 + .../abseil-cpp/absl/synchronization/mutex.h | 7 +- .../third_party/abseil-cpp/absl/time/clock.cc | 6 +- .../abseil-cpp/absl/time/duration.cc | 18 +- .../abseil-cpp/absl/time/duration_test.cc | 11 + .../internal/cctz/include/cctz/time_zone.h | 92 +- .../internal/cctz/src/time_zone_format.cc | 9 + .../cctz/src/time_zone_format_test.cc | 279 +- .../time/internal/cctz/src/time_zone_info.cc | 3 + .../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 .../cctz/testdata/zoneinfo/Asia/Tehran | Bin 812 -> 812 bytes .../internal/cctz/testdata/zoneinfo/CST6CDT | Bin 1754 -> 922 bytes .../internal/cctz/testdata/zoneinfo/EST5EDT | Bin 1744 -> 922 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 | 2 +- .../cctz/testdata/zoneinfo/zonenow.tab | 4 +- .../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 - .../abseil-cpp/symbols_arm64_dbg.def | 237 +- .../abseil-cpp/symbols_arm64_dbg_cxx23.def | 237 +- .../abseil-cpp/symbols_arm64_rel.def | 20 +- .../abseil-cpp/symbols_arm64_rel_cxx23.def | 20 +- .../abseil-cpp/symbols_x64_dbg.def | 237 +- .../abseil-cpp/symbols_x64_dbg_cxx23.def | 237 +- .../abseil-cpp/symbols_x64_rel.def | 20 +- .../abseil-cpp/symbols_x64_rel_asan.def | 16 +- .../abseil-cpp/symbols_x64_rel_asan_cxx23.def | 16 +- .../abseil-cpp/symbols_x64_rel_cxx23.def | 20 +- .../abseil-cpp/symbols_x86_dbg.def | 237 +- .../abseil-cpp/symbols_x86_dbg_cxx23.def | 237 +- .../abseil-cpp/symbols_x86_rel.def | 19 +- .../abseil-cpp/symbols_x86_rel_cxx23.def | 20 +- .../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 +- .../crdtp/json_platform_v8.cc | 4 +- .../llvm-libc/src/hdr/CMakeLists.txt | 30 + .../llvm-libc/src/hdr/poll_macros.h | 27 + .../llvm-libc/src/hdr/poll_overlay.h | 69 + .../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 | 36 + .../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 +- .../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/include/CMakeLists.txt | 19 + .../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 + .../include/llvm-libc-macros/CMakeLists.txt | 28 + .../llvm-libc-macros/common-threads-macros.h | 19 + .../include/llvm-libc-macros/limits-macros.h | 4 +- .../llvm-libc-macros/linux/CMakeLists.txt | 14 + .../llvm-libc-macros/linux/fcntl-macros.h | 6 + .../linux/sys-inotify-macros.h | 54 + .../llvm-libc-macros/linux/sys-xattr-macros.h | 20 + .../llvm-libc-macros/linux/unistd-macros.h | 1 + .../include/llvm-libc-macros/pthread-macros.h | 10 + .../include/llvm-libc-macros/stdio-macros.h | 29 + .../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 | 3 + .../src/include/llvm-libc-types/idtype_t.h | 19 + .../include/llvm-libc-types/sighandler_t.h | 3 - .../struct___pthread_cleanup_frame.h | 23 + .../llvm-libc-types/struct_inotify_event.h | 27 + .../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 | 10 +- .../llvm-libc/src/include/stdio.yaml | 23 + .../llvm-libc/src/include/stdlib.yaml | 22 + .../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/unistd.yaml | 24 + .../src/src/__support/CMakeLists.txt | 6 +- .../src/src/__support/CPP/CMakeLists.txt | 17 - .../llvm-libc/src/src/__support/CPP/vector.h | 309 -- .../src/src/__support/FPUtil/FEnvImpl.h | 5 +- .../src/src/__support/FPUtil/double_double.h | 16 +- .../src/src/__support/File/CMakeLists.txt | 23 + .../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 | 36 +- .../llvm-libc/src/src/__support/File/file.h | 51 +- .../src/src/__support/File/file_io_result.h | 37 + .../src/src/__support/File/file_mode.h | 14 +- .../src/__support/File/linux/CMakeLists.txt | 1 + .../src/src/__support/File/linux/file.cpp | 33 +- .../src/src/__support/File/linux/file_flags.h | 2 + .../linux/syscall_wrappers/CMakeLists.txt | 266 ++ .../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/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/getcwd.h | 13 +- .../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/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/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 +- .../OSUtil/linux/syscall_wrappers/setgroups.h | 43 + .../OSUtil/linux/syscall_wrappers/setxattr.h | 35 + .../OSUtil/linux/syscall_wrappers/statx.h | 7 +- .../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 + .../llvm-libc/src/src/__support/block.h | 63 +- .../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 | 8 + .../src/src/__support/macros/optimization.h | 15 +- .../src/src/__support/math/CMakeLists.txt | 131 +- .../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 | 168 +- .../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 +- .../src/__support/math/exp10f_double_eval.h | 147 +- .../src/__support/math/exp2f_double_eval.h | 96 +- .../src/__support/math/exp2f_float_utils.h | 25 +- .../src/src/__support/math/expf_float_eval.h | 6 +- .../src/src/__support/math/lgammaf.h | 8 +- .../llvm-libc/src/src/__support/math/log10f.h | 111 +- .../llvm-libc/src/src/__support/math/log2f.h | 8 +- .../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 | 260 ++ .../src/__support/math/powf_small_tables.h | 120 - .../src/src/__support/math/powf_utils.h | 729 ++++ .../llvm-libc/src/src/__support/math/sinf.h | 190 +- .../src/src/__support/math/sinf_double_eval.h | 182 + .../src/src/__support/math/sinf_float_eval.h | 33 + .../src/src/__support/mathvec/CMakeLists.txt | 3 +- .../src/src/__support/mathvec/cosf.h | 124 +- .../src/__support/mathvec/trig_reductionf.h | 30 +- .../__support/mathvec/trig_reductionf_nofma.h | 34 +- .../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 | 10 + .../src/__support/printf_core/core_structs.h | 23 +- .../printf_core/float_dec_converter.h | 85 +- .../printf_core/float_dec_converter_limited.h | 71 +- .../printf_core/float_hex_converter.h | 136 +- .../printf_core/float_inf_nan_converter.h | 32 +- .../src/src/__support/printf_core/parser.h | 161 +- .../src/src/__support/pwd/flat_file_db.h | 17 +- .../src/src/__support/str_to_float.h | 126 +- .../src/src/__support/threads/CMakeLists.txt | 18 +- .../src/src/__support/threads/cleanup_stack.h | 45 + .../__support/threads/linux/CMakeLists.txt | 20 +- .../threads/linux/aarch64/CMakeLists.txt | 20 + .../__support/threads/linux/aarch64/tls.cpp | 81 + .../threads/linux/riscv/CMakeLists.txt | 20 + .../src/__support/threads/linux/riscv/tls.cpp | 57 + .../src/__support/threads/linux/thread.cpp | 122 +- .../threads/linux/x86_64/CMakeLists.txt | 21 + .../__support/threads/linux/x86_64/tls.cpp | 75 + .../src/src/__support/threads/thread.cpp | 35 +- .../src/src/__support/threads/thread.h | 11 +- .../src/__support/threads/thread_attributes.h | 2 + .../llvm-libc/src/src/__support/tlsf_table.h | 7 + deps/v8/third_party/zlib/chromeconf.h | 3 - .../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 | 13 +- .../clusterfuzz/foozzie/v8_foozzie_test.py | 65 +- .../foozzie/v8_fuzz_experiments_regexp.json | 6 + .../foozzie/v8_fuzz_flags_regexp.json | 11 + deps/v8/tools/debug_helper/BUILD.gn | 4 +- .../debug_helper/get-object-properties.cc | 43 + 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/setup_worktree_build.py | 204 +- deps/v8/tools/dev/update-compile-commands.py | 6 +- deps/v8/tools/gcmole/gcmole.cc | 189 +- deps/v8/tools/jj/README.md | 52 + deps/v8/tools/jj/config.toml | 66 + 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 | 159 +- deps/v8/tools/metagen/extract.py | 52 +- deps/v8/tools/metagen/layout_extract.py | 796 ++++ deps/v8/tools/metagen/layout_ir.py | 712 ++++ deps/v8/tools/metagen/metagen.py | 172 +- .../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 | 946 +++++ deps/v8/tools/metagen/tests/layout_ir_test.py | 502 +++ .../tools/regexp/correctness_fuzzer/README.md | 93 +- .../correctness_fuzzer/correctness_fuzzer.py | 94 +- .../correctness_fuzzer/grammar/menus.py | 2 + .../correctness_fuzzer/grammar/rules.py | 43 +- .../regexp/correctness_fuzzer/grammar_test.py | 352 +- .../regexp/correctness_fuzzer/harness.js | 26 +- .../regexp/correctness_fuzzer/harness.py | 88 + .../regexp/correctness_fuzzer/package.sh | 49 + .../v8/tools/regexp/correctness_fuzzer/run.py | 150 + .../run_locally_against_foozzie.py | 115 + 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/objects/testcase.py | 1 + deps/v8/tools/testrunner/test_config.py | 4 +- 1492 files changed, 62166 insertions(+), 25828 deletions(-) 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-review/OWNERS create mode 100644 deps/v8/agents/skills/v8-review/SKILL.md create mode 100644 deps/v8/bazel/v8-generators.bzl create mode 100644 deps/v8/src/base/unique-array.h create mode 100644 deps/v8/src/maglev/maglev-basic-block.cc create mode 100644 deps/v8/src/objects/bit-field-group.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-heap.cc create mode 100644 deps/v8/test/cctest/heap/test-limit-based-memory-reducer.cc delete mode 100644 deps/v8/test/cctest/heap/test-mark-compact.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 create mode 100644 deps/v8/test/debugger/regress/wasm/regress-570547314.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/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/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/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/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/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-side-effect-free-evaluate-expected.txt create mode 100644 deps/v8/test/inspector/runtime/import-defer-side-effect-free-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/baseline/embedded-feedback-monotonic.js create mode 100644 deps/v8/test/mjsunit/code-cache-sha256.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 create mode 100644 deps/v8/test/mjsunit/d8/regress-564550564.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-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-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-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-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/harmony/modules-import-defer-terminate.mjs create mode 100644 deps/v8/test/mjsunit/harmony/regexp-unicode-sets-class-string-disjunction.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-563882510.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-564326894.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-569212098.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-569286602-1.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-569286602-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/spread-rest-parameter-element-mutation.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 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-564012076.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564879562.js create mode 100644 deps/v8/test/mjsunit/regress/regress-566091009.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.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-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-570003644-1.js create mode 100644 deps/v8/test/mjsunit/regress/regress-570003644-2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-570203091-1.js create mode 100644 deps/v8/test/mjsunit/regress/regress-570203091-2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-570547313.js create mode 100644 deps/v8/test/mjsunit/regress/regress-571397035.js create mode 100644 deps/v8/test/mjsunit/regress/regress-571871980.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-target-toctou.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-569886678.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-570538338.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-571155505.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-571700025.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-simd-570497964.js create mode 100644 deps/v8/test/mjsunit/sandbox/fixed-double-array-field-count.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-564835629.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-571126471.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-571127829.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress/regress-555304822.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress/regress-567526351.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress/regress-568338771.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 create mode 100644 deps/v8/test/mjsunit/string-index-undefined-optimized.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 create mode 100644 deps/v8/test/mjsunit/turbolev/regress-564329221.js create mode 100644 deps/v8/test/mjsunit/turbolev/regress-567129324.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-568348290.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/wasm/growable-stacks-simd.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/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-shift-left-long.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/unique-array-unittest.cc create mode 100644 deps/v8/test/unittests/compiler/turboshaft/duplication-optimization-reducer-unittest.cc create mode 100644 deps/v8/test/unittests/heap/mark-compact-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%) create mode 100644 deps/v8/test/unittests/objects/casting-unittest.cc delete mode 100644 deps/v8/test/unittests/zone/zone-chunk-list-unittest.cc 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_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/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/include/llvm-libc-macros/common-threads-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-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/idtype_t.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_inotify_event.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/sys/inotify.yaml 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/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/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/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/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/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/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/setgroups.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/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/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/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/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/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/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 diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index 31ac08aa8ddb..35a30b7ad004 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -263,6 +263,7 @@ Oliver Dunk Paolo Giarrusso Patrick Gansterer Paul Lind +Pavel Atamanov Pavel Medvedev Pedro Falcato Peng Fei @@ -318,6 +319,7 @@ Steven R. Loomis Sylvestre Ledru Takeshi Yoneda Taketoshi Aono +Tamir Duberstein Tao Liqiang Tao Wang Teddy Katz @@ -330,6 +332,7 @@ Tobias Burnus Tobias Nießen Tomasz Malinowski Ujjwal Sharma +V8 AIRC Bot Vadim Gorbachev Varun Varada Victor Costan @@ -381,6 +384,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..3c5522710b4f 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,16 @@ v8_flag( default = False, ) +v8_flag( + name = "v8_x64_16byte_stack_alignment", + default = False, +) + +v8_flag( + name = "v8_support_la57", + default = True, +) + selects.config_setting_group( name = "enable_drumbrake_x64", match_all = [ @@ -410,12 +422,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,6 +557,8 @@ 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", }, defines = [ "GOOGLE3", @@ -555,8 +569,8 @@ v8_config( "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({ @@ -986,6 +1000,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", @@ -1402,6 +1417,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", @@ -2124,6 +2145,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", @@ -2776,7 +2798,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", @@ -3092,6 +3113,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", @@ -3880,6 +3902,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 +3939,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 +3948,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 +4469,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 +4512,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 +4535,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 +4589,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 +4600,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 +4623,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 +4636,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 +4682,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 +4696,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 +4910,7 @@ cc_library( }), features = ["-use_header_modules"], deps = [ + ":simdutf", ":torque_base_headers", ":v8_libbase", "@abseil-cpp//absl/container:node_hash_map", @@ -4894,8 +4947,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 +4957,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 +5104,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 +5147,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..8956a3dc3574 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,8 +26,8 @@ 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") } @@ -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. @@ -536,9 +537,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 +555,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 +571,13 @@ 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.") + # Derived defaults. if (v8_logging_level == "") { if (v8_enable_verification_features || v8_dcheck_always_on) { @@ -809,9 +821,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 +881,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") @@ -1108,6 +1126,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", @@ -1179,6 +1198,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 +1344,8 @@ 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" ] } configs = [ @@ -1681,8 +1703,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 +2084,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 +2200,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" ] } } } @@ -2453,7 +2475,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 +2483,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 +2512,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 +2537,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 +2547,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 +2599,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 +2618,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 +2643,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 +2658,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 +2808,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 } @@ -3496,6 +3552,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 @@ -4601,6 +4658,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", @@ -5017,7 +5075,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", @@ -5119,6 +5176,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", @@ -5764,8 +5822,8 @@ v8_header_set("v8_internal_headers") { if (v8_enable_experimental_tq_to_tsa) { deps += [ ":run_torque_to_tsa" ] } - if (v8_use_metagen_instance_types) { - deps += [ ":metagen_instance_types_h" ] + if (v8_use_metagen) { + deps += [ ":run_metagen" ] } } @@ -5933,6 +5991,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", @@ -6745,6 +6804,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", @@ -7344,6 +7404,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 +7445,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 +7479,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", @@ -7575,6 +7644,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", @@ -9287,7 +9357,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 +9366,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..52ef28b5c92f 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:0035961837fbcfe875d855744b3eda4fd2eefb43', # 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:7062c4f8a81f14ed840f6c6d1bbef63be5fabaae', # 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.20261003.1.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': '1b65ca87736e9edb51911e15915573bf4cda7245', # 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. @@ -129,11 +129,11 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_platform-tools_version # and whatever else without interference from each other. - 'android_sdk_platform-tools_version': 'qTD9QdBlBf3dyHsN1lJ0RH6AhHxR42Hmg2Ih-Vj4zIEC', + 'android_sdk_platform-tools_version': 'j9ae9h2iaxMBUMJcE7tpd30e97xvJWcp3UpePJDXaS0C', # 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': '8f6ca7b4a66b74e21d77bca5c3e9b9be13391d28', # 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': '868618a8d1327ea3f6ab037b947e51f93b889ce1', } 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' + '@' + 'aa268127b8cc571ebc60f200d052a09d27231843', 'buildtools': - Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + 'c202b4a9dac30e789ed6e3b2354efa94357a56f3', + Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '8790f824690e131a78f36e80ecc05a9272f061c8', 'buildtools/linux64': { 'packages': [ { @@ -226,7 +226,7 @@ deps = { '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' + '@' + '3d4673f57764ba5f999699abf34a52a3584e8b6c', '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,13 +280,13 @@ 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' + '@' + 'a03dfbf7f2d1cefa2795d81d59ca4f16c8616a8f', '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', 'condition': 'checkout_fuchsia', @@ -310,17 +312,17 @@ deps = { 'url': Var('chromium_url') + '/external/github.com/google/benchmark.git' + '@' + '8abf1e701fbd88c8170f48fe0558247e2e5f8e7d', }, 'third_party/fuzztest': - Var('chromium_url') + '/chromium/src/third_party/fuzztest.git' + '@' + '55970ac2863f6b740d3e8247ac0ec48e7acb2113', + Var('chromium_url') + '/chromium/src/third_party/fuzztest.git' + '@' + '4b524d48590b3433597a557d1a8abc134a86b611', 'third_party/fuzztest/src': - Var('chromium_url') + '/external/github.com/google/fuzztest.git' + '@' + '7a8e9056de2a4f745082a4b3861a67ada47ced36', + Var('chromium_url') + '/external/github.com/google/fuzztest.git' + '@' + 'a8861f3aa71443dabaf42dc9cba78b3982524a51', 'third_party/googletest/src': Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + '4fe3307fb2d9f86d19777c7eb0e4809e9694dde7', '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' + '@' + '19dfb44a62ae60ce6b0060de8c0cef5d5c527177', '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' + '@' + '423262e4438b032c0ba5ea61f78a85ac3690298c', 'condition': 'checkout_instrumented_libraries', }, 'third_party/ittapi': { @@ -336,178 +338,178 @@ deps = { 'third_party/libc++/src': Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + '97b436da4c33663581d394f4ee0a5977fc38c2f4', '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' + '@' + '0e691bb69ac90450d8d53bc8ee5968c62f9c15a7', 'third_party/libpfm4': - Var('chromium_url') + '/chromium/src/third_party/libpfm4.git' + '@' + 'f2fec4fe8bc40a58b1f257e631fc5b8f49b39010', + Var('chromium_url') + '/chromium/src/third_party/libpfm4.git' + '@' + 'cf4f1a05f7ec16fe8c82b1635b9978f1d7c5d976', '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' + '@' + '995ad37079531b7c3a98cbd164b7619f3b0adc0d', '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' + '@' + 'c4438dd4178c627697459a12c54eb1f7f8eefd12', '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' + '@' + '97e60a1e7f7180965cc84e22ddde9f1d4ffd640f', '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '2963958c20b4a199ece3b3687d0a6837034f9334e577a1b41f731286899529d0', + 'size_bytes': 6214188, + 'generation': 1791353531581542, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'ab8ec1e75c7f74565e9f893212262780abc9174363ce5f1ff670c415e9cd4147', + 'size_bytes': 57258740, + 'generation': 1791353523054521, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '6cb141f7c28a13391c93536e00f41a95bd496d9fb0e2b6e75888580ec855c652', + 'size_bytes': 14939640, + 'generation': 1791353523580790, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'e15fc9da48194273e35112245a74b1ff692cc3f3323d952d4fc2629fd5cdaf72', + 'size_bytes': 15087948, + 'generation': 1791353523614177, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'b69495731e398beb837f5261f62408e9d2bb44f255b4dbd403b3deeb6d8b0646', + 'size_bytes': 2374572, + 'generation': 1791353524193645, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'c575a16aa6516a47ad58c6f66ea604d3ec183d9b7a6ca72139b10d01a3ade984', + 'size_bytes': 5924452, + 'generation': 1791353523760046, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '346a08e3a7891deb809cfbbe3f17c87a64145ac6d6a37f58fed8fe18f3e89913', + 'size_bytes': 53865192, + 'generation': 1791353549543090, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '01e3edd028295244eb2f18c96d00348a3d0b5269cef17d90730a15bc6ac0c6b2', + 'size_bytes': 982956, + 'generation': 1791353573947124, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '18e694a749e4cab12ccf9bcf17ca526188edf41aa7345d70cdbf311a99750f30', + 'size_bytes': 14229572, + 'generation': 1791353549836984, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '2409045110c36e6e2c0ecd7684d717f49220dbc9a31caa884cc99822da3c81eb', + 'size_bytes': 15130608, + 'generation': 1791353549992613, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'd7d165fe73ebea5d0c7cc43d55a4ca0b98a5d55465702b0b0de8db9fe953bdbd', + 'size_bytes': 2260504, + 'generation': 1791353550517983, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '18797773ddcd446afcfd9420b51c9f43e6eb805bb0ddeabcfc0fadfe967cd818', + 'size_bytes': 5525060, + 'generation': 1791353550148753, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '7ac4fb2a7fd4996bbade60ce75835d46f0bc3e89c9d994d0510c81d53b0bb2bf', + 'size_bytes': 44479696, + 'generation': 1791353576418315, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'ec772cde3504c162f0be72487e8cf7a1c971dd747d1573b0a5a8642ff8076f9d', + 'size_bytes': 12231584, + 'generation': 1791353576774358, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'c0f299d65d980089505e97367b7a5e08c211205c64ee6d9d87d798f24a602331', + 'size_bytes': 12228724, + 'generation': 1791353576955805, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'ed52f79362b287347e30deaeab32288af97be54c60e9c067505426d2b97c08b9', + 'size_bytes': 1861748, + 'generation': 1791353577847292, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '50392b193a67eedda0c6b27b228c9beb598ffe5beb4624831c8ba66b00f9208c', + 'size_bytes': 5225884, + 'generation': 1791353577184760, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': '194d833174c9ab6ea1d5e5f9902fcc946a4b713c5ef573e112dfc48450c849e4', + 'size_bytes': 51825724, + 'generation': 1791353603126632, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'abbc16b3fbcc2fe14e1fd78fa33da69b745ad3485becfd39ee291049d01894e6', + 'size_bytes': 15137260, + 'generation': 1791353603446047, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'b207042a5986ea8a684ebea9ea918220bc034d05dc7c86dd0a2712c368358e39', + 'size_bytes': 2653336, + 'generation': 1791353626758916, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'f3d4c9447d50f6f8c50828a321cc625dbc8345c3928c2a2950fdf50077b8fbce', + 'size_bytes': 15447340, + 'generation': 1791353603658278, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'c6ffba53da37b3d037bceea588a7cc5781361f018998733cc70c897e13f53168', + 'size_bytes': 2527436, + 'generation': 1791353604155593, '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-7747-g62397f8b-67.tar.xz', + 'sha256sum': 'dbc2063e2ca76a1917a3347ff7d6807a450d14bb7d11bc3c98c3ef8d428f63fe', + 'size_bytes': 6010708, + 'generation': 1791353604178293, 'condition': '(checkout_linux or checkout_mac or checkout_android) and host_os == "win"', }, ], @@ -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' + '@' + '59400b15c6ff8186ba0bba69f78c2cd454eea8b4', 'third_party/protobuf': - Var('chromium_url') + '/chromium/src/third_party/protobuf.git' + '@' + '398c57e93a383373546bc6ae5ac2052b6155f2ba', + Var('chromium_url') + '/chromium/src/third_party/protobuf.git' + '@' + '9fbbf0b210753390b790e4f1e74ddff5d7d97bbf', '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' + '@' + '9ec0f3001f8d689e57121e7bdddca35ba285a8c5', 'tools/win': - Var('chromium_url') + '/chromium/src/tools/win' + '@' + '13cb6e5d223dc49eadd082d3aef4c2a5b0e4c0a0', + Var('chromium_url') + '/chromium/src/tools/win' + '@' + '93ff0ff4ec7531e0d71108117f6798360e06dfac', 'third_party/rust': - Var('chromium_url') + '/chromium/src/third_party/rust' + '@' + '4be2b73f368c8c2a3f5a42c16459b80d7d81b318', + Var('chromium_url') + '/chromium/src/third_party/rust' + '@' + '98ef22e4e02f422db2bbb66d334adf010e716bbd', '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-1edd55dcfcd573872c727fa3e086369a71661ee0-1125-llvmorg-24-init-7747-g62397f8b.tar.xz', + 'sha256sum': '6287ecced3bc5113122a88dbe15c910edec0828718423a67529c24de0f060e98', + 'size_bytes': 287212360, + 'generation': 1791299089231058, '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-1edd55dcfcd573872c727fa3e086369a71661ee0-1125-llvmorg-24-init-7747-g62397f8b.tar.xz', + 'sha256sum': 'bf8da1a3b76301004874c0d7cad4cae73dacabfe35f5d1faa74308720794c826', + 'size_bytes': 274684364, + 'generation': 1791299093069856, '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-1edd55dcfcd573872c727fa3e086369a71661ee0-1125-llvmorg-24-init-7747-g62397f8b.tar.xz', + 'sha256sum': '71b31b71326d7bf53eef44676f88d759c03677ae382dd9d331615c4f491e0dd1', + 'size_bytes': 258108500, + 'generation': 1791299097351015, '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-1edd55dcfcd573872c727fa3e086369a71661ee0-1125-llvmorg-24-init-7747-g62397f8b.tar.xz', + 'sha256sum': 'd921778843d10fee506621af6457b0011da63ad6882e2508c91509a92c0cae49', + 'size_bytes': 425602544, + 'generation': 1791299101162989, '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-1edd55dcfcd573872c727fa3e086369a71661ee0-1125-llvmorg-24-init-7747-g62397f8b.tar.xz', + 'sha256sum': '1472e8a5cfc4959f94ff18aa5ec864b07991d877995a563eeb4176e344a7fa59', + 'size_bytes': 22761568, + 'generation': 1791299091145399, '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-1edd55dcfcd573872c727fa3e086369a71661ee0-1125-llvmorg-24-init-7747-g62397f8b.tar.xz', + 'sha256sum': '95092fb605dfc7bc4637508eb74488e42c38bbe622a18cdf9ba698577e70ec61', + 'size_bytes': 22915648, + 'generation': 1791299094922802, '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-1edd55dcfcd573872c727fa3e086369a71661ee0-1125-llvmorg-24-init-7747-g62397f8b.tar.xz', + 'sha256sum': '4b82de2a286aeb02fa0ed99cf75a7b3f3c8dd408abd176a4e5c5fc5e7217754d', + 'size_bytes': 20585892, + 'generation': 1791299099218801, '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-1edd55dcfcd573872c727fa3e086369a71661ee0-1125-llvmorg-24-init-7747-g62397f8b.tar.xz', + 'sha256sum': '1f498ea146d1b441fb46d2bb420dfbb81c0d9d4eb3662e3c3ae072674412f9f7', + 'size_bytes': 21526692, + 'generation': 1791299103066753, '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'+ '@' + '456ae730017b9b4bd3371927abc82627fd51feef', 'tools/clang': - Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + '10f700407ca356594ea2a575572b7ce63183721d', + Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + '47fbf574c4f14e7288da3e51ff6eca0990183377', 'tools/protoc_wrapper': Var('chromium_url') + '/chromium/src/tools/protoc_wrapper.git' + '@' + 'e9dbe1bf6a2a5d2d4973725874259eed587cf18d', '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' + '@' + '9aa0c314d9bd021e48f0193f0af3316a7e8bec63', 'condition': 'not build_with_chromium', }, 'third_party/fadec/src': { 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/git-cl.md b/deps/v8/agents/rules/git-cl.md index 2a36db0e0a23..a34592368ce7 100644 --- a/deps/v8/agents/rules/git-cl.md +++ b/deps/v8/agents/rules/git-cl.md @@ -22,13 +22,35 @@ to the **`git-cl-helper`** skill exist. - **Upload Script**: In V8, all initial and patchset uploads MUST be performed using - `agents/scripts/upload_cl.sh [patchset_message] [additional flags...]`. + `agents/scripts/upload_cl.sh [patchset_message] [--wip|--ready] [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"`. + release test checks, validates commit description line lengths, and manages + WIP vs. Ready-for-Review states and CQ dry-runs. + - **Always Run as a Background Task**: Because `upload_cl.sh` blocks during + local `check` test runs and during `--ready` CQ dry-run polling, **ALWAYS** + launch `upload_cl.sh` asynchronously as a background task (and wait for the + automatic completion wakeup rather than polling in a loop). + - **Initial Upload (Always WIP)**: For a new CL without an existing issue + association, execute `agents/scripts/upload_cl.sh new check`. Initial + uploads always start in **WIP** (`-o wip`) mode; passing `--ready` with + `new` is rejected. + - **Iterative / WIP Uploads (Default)**: While iterating on a CL, running + self-reviews, or fixing bugs/tests, run + `agents/scripts/upload_cl.sh cur check "Brief patchset description"` (which + defaults to `--wip` / `-o 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 confirmed by the user and + ready for review by passing `--ready`: + `agents/scripts/upload_cl.sh cur check "Ready for review" --ready`. Passing + `--ready` automatically triggers a CQ dry-run (`--cq-dry-run`), waits for + the dry-run to finish, and **only switches the CL to non-WIP (Ready for + Review) if the dry-run passes**. If the dry-run fails, `upload_cl.sh` + ensures the CL is in **WIP** on Gerrit and exits non-zero. In this case, + investigate the failing bots (inspecting logs via `gerrit_cq`), determine + the root cause, and ask the user about next steps; keep subsequent fix + uploads in WIP mode until the failure is fixed, then re-run with `--ready` + after user confirmation. - **Checks**: The "check" flag runs all mjsunit tests. When no code was updated, or tests were already successfully run, "nocheck" can be passed. - **Updating Description**: If the changes in a new patchset make the existing @@ -99,16 +121,20 @@ to the **`git-cl-helper`** skill - **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. - - **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. + - **WIP Uploads**: Run `git cl status` after uploading to verify branch + alignment and issue status. When a CQ dry-run is triggered (`-d` / + `--cq-dry-run`), periodically monitor bot status 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. + - **Non-WIP (`--ready`) Uploads**: **ALWAYS obtain explicit user confirmation + before setting a CL to ready (non-WIP) or passing `--ready`.** + `upload_cl.sh ... --ready` automatically triggers a CQ dry-run, polls + `git cl status` and `git cl try-results` until completion, and switches the + CL to Ready for Review (non-WIP) only if the dry-run passes (or back to + **WIP** if the dry-run fails). Always run it as a background task. If the + dry-run fails, investigate the failing bots using `gerrit_cq`, analyze the + root cause, and ask the user about next steps while keeping the CL in WIP. - **Post-Upload**: Provide the `chromium-review.googlesource.com` link to the user. diff --git a/deps/v8/agents/rules/git-commit.md b/deps/v8/agents/rules/git-commit.md index d68536add77d..77c501aeb458 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 + strictly under 65 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. diff --git a/deps/v8/agents/rules/v8-best-practices.md b/deps/v8/agents/rules/v8-best-practices.md index 6609c5c88ef9..e4716adac111 100644 --- a/deps/v8/agents/rules/v8-best-practices.md +++ b/deps/v8/agents/rules/v8-best-practices.md @@ -30,6 +30,12 @@ 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. - **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. 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/upload_cl.sh b/deps/v8/agents/scripts/upload_cl.sh index 4739d64fb344..eebb788a75f5 100755 --- a/deps/v8/agents/scripts/upload_cl.sh +++ b/deps/v8/agents/scripts/upload_cl.sh @@ -7,39 +7,80 @@ 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]" + echo "Usage: upload_cl.sh [patchset_message] [--wip|--ready] [additional flags...]" 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]" + echo "Usage: upload_cl.sh [patchset_message] [--wip|--ready] [additional flags...]" 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]" + echo "Usage: upload_cl.sh [patchset_message] [--wip|--ready] [additional flags...]" exit 1 fi # Shift positional parameters so "$@" contains any additional flags passed to upload_cl.sh -if [ $# -ge 3 ]; then +if [ $# -ge 3 ] && [[ "$3" != -* ]]; then + PATCH_MSG="${3:-Update patchset}" shift 3 else - shift $# + PATCH_MSG="Update patchset" + if [ $# -ge 2 ]; then + shift 2 + else + shift $# + fi fi # Guardrail: Check commit description line lengths (max 78 chars, ignoring lines with URLs) DESC_TO_CHECK="" CHECK_DESC=false HAS_CUSTOM_DESC=false +READY_FOR_REVIEW=false +EXPLICIT_WIP=false +EXPLICIT_READY=false +HAS_DRY_RUN_OR_CQ=false +HAS_SEND_MAIL_OR_CQ=false +UPLOAD_ARGS=() prev_arg="" for arg in "$@"; do + if [ "$arg" = "--ready" ]; then + READY_FOR_REVIEW=true + EXPLICIT_READY=true + prev_arg="$arg" + continue + elif [ "$arg" = "--wip" ]; then + READY_FOR_REVIEW=false + EXPLICIT_WIP=true + prev_arg="$arg" + continue + fi + + if [ "$arg" = "-s" ] || [ "$arg" = "--send-mail" ] || [ "$arg" = "--send-email" ]; then + HAS_SEND_MAIL_OR_CQ=true + # Do not forward --send-mail to git cl upload, as git_cl.py translates it + # into %ready on git push, which would prematurely exit WIP before the CQ + # dry-run passes. + prev_arg="$arg" + continue + fi + + UPLOAD_ARGS+=("$arg") + + if [ "$arg" = "-d" ] || [ "$arg" = "--dry-run" ] || [ "$arg" = "--cq-dry-run" ] || [ "$arg" = "-c" ] || [ "$arg" = "--use-commit-queue" ]; then + HAS_DRY_RUN_OR_CQ=true + fi + if [ "$arg" = "-c" ] || [ "$arg" = "--use-commit-queue" ]; then + HAS_SEND_MAIL_OR_CQ=true + fi + if [[ "$arg" == --commit-description=* ]] || [[ "$arg" == --message=* ]] || [[ "$arg" == -m=* ]]; then HAS_CUSTOM_DESC=true val="${arg#*=}" @@ -69,6 +110,31 @@ for arg in "$@"; do prev_arg="$arg" done +if [ "$EXPLICIT_WIP" = true ] && [ "$EXPLICIT_READY" = true ]; then + echo "Error: Cannot specify both '--wip' and '--ready'." + exit 1 +fi + +if [ "$MODE" = "new" ] && [ "$READY_FOR_REVIEW" = true ]; then + echo "Error: Initial uploads ('new') must be uploaded as WIP first. Use 'cur' with '--ready' once the CL is ready for review." + exit 1 +fi + +if [ "$READY_FOR_REVIEW" = false ] && [ "$HAS_SEND_MAIL_OR_CQ" = true ]; then + echo "Error: Cannot send mail or use commit queue on a WIP upload. Pass '--ready' when the CL is ready for review." + exit 1 +fi + +if [ "$READY_FOR_REVIEW" = true ]; then + # Keep WIP CLs in WIP during the dry-run; wait-dry-run will switch the CL to + # ready only after the CQ dry-run passes. + if [ "$HAS_DRY_RUN_OR_CQ" = false ]; then + UPLOAD_ARGS+=("--cq-dry-run") + fi +else + UPLOAD_ARGS+=("-o" "wip") +fi + # 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) @@ -135,6 +201,90 @@ if [ "$CHECK_MODE" = "check" ]; then fi fi +GERRIT_WRAPPER="$SCRIPT_DIR/../shared/skills/gerrit-cli/scripts/gerrit_client_wrapper.py" +GERRIT_HOST="https://chromium-review.googlesource.com" + +set_cl_wip() { + local issue_num="$1" + local msg="$2" + local out + if out=$(vpython3 "$GERRIT_WRAPPER" rawapi \ + --host "$GERRIT_HOST" \ + --path "/changes/${issue_num}/wip" \ + --method POST \ + --body "{\"message\": \"${msg//\"/\\\"}\"}" \ + --accept_status "200,204" 2>&1); then + return 0 + fi + if [[ "$out" == *"already work in progress"* ]]; then + return 0 + fi + echo "$out" >&2 + return 1 +} + +set_cl_ready() { + local issue_num="$1" + local msg="$2" + local out + if out=$(vpython3 "$GERRIT_WRAPPER" rawapi \ + --host "$GERRIT_HOST" \ + --path "/changes/${issue_num}/ready" \ + --method POST \ + --body "{\"message\": \"${msg//\"/\\\"}\"}" \ + --accept_status "200,204" 2>&1); then + return 0 + fi + if [[ "$out" == *"not work in progress"* ]]; then + return 0 + fi + echo "$out" >&2 + return 1 +} + +wait_for_cl_dry_run() { + local issue_num="$1" + local cl_url="$2" + local poll_interval="${UPLOAD_CL_POLL_INTERVAL:-30}" + local timeout="${UPLOAD_CL_TIMEOUT:-7200}" + local start_time=$SECONDS + + while true; do + local cl_status + cl_status=$(git cl status --field=status 2>/dev/null) + local try_out + try_out=$(git cl try-results 2>&1) + + if [ "$cl_status" != "dry-run" ] && [ "$cl_status" != "commit" ] && \ + ! echo "$try_out" | grep -qE '^(Started:|Scheduled:)'; then + if echo "$try_out" | grep -q '^Successes:' && \ + ! echo "$try_out" | grep -qE '^(Failures:|Infra Failures:|Canceled:|Other:|ERROR:)'; then + echo "STATUS: passed ($cl_url)" + echo "CQ dry-run passed. Switching CL $issue_num to ready for review..." + if ! set_cl_ready "$issue_num" "CQ dry-run passed; marking ready for review."; then + echo "Error: Failed to mark CL $issue_num ready for review." >&2 + return 1 + fi + return 0 + else + echo "STATUS: failed" + echo "CQ dry-run failed. Switching CL $issue_num back to WIP until it is fixed..." + echo "$try_out" + set_cl_wip "$issue_num" "CQ dry-run failed; switching back to WIP until fixed." + return 1 + fi + fi + + if (( SECONDS - start_time >= timeout )); then + echo "Error: Timed out after ${timeout}s waiting for CQ dry-run on $cl_url. Switching back to WIP..." >&2 + set_cl_wip "$issue_num" "CQ dry-run timed out; switching back to WIP." + return 1 + fi + + sleep "$poll_interval" + done +} + ISSUE_OUTPUT=$(git cl issue 2>&1) if [[ "$ISSUE_OUTPUT" == *"None"* ]]; then HAS_ISSUE=false @@ -148,9 +298,9 @@ if [ "$MODE" = "new" ]; then 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) + UPLOAD_OUTPUT=$(SKIP_GCE_AUTH_FOR_GIT=1 EDITOR=cat git cl upload -t "Initial upload" "${UPLOAD_ARGS[@]}" 2>&1) else - UPLOAD_OUTPUT=$(SKIP_GCE_AUTH_FOR_GIT=1 EDITOR=cat git cl upload --commit-description=+ -t "Initial upload" "$@" 2>&1) + UPLOAD_OUTPUT=$(SKIP_GCE_AUTH_FOR_GIT=1 EDITOR=cat git cl upload --commit-description=+ -t "Initial upload" "${UPLOAD_ARGS[@]}" 2>&1) fi UPLOAD_STATUS=$? else @@ -158,8 +308,27 @@ else 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_OUTPUT=$(SKIP_GCE_AUTH_FOR_GIT=1 EDITOR=cat git cl upload -t "$PATCH_MSG" "${UPLOAD_ARGS[@]}" 2>&1) UPLOAD_STATUS=$? + + # If the latest commit was already uploaded and only WIP/ready state or dry-run + # is changing, git push may report "no new changes". + if [ $UPLOAD_STATUS -ne 0 ] && [[ "$UPLOAD_OUTPUT" == *"no new changes"* ]]; then + ISSUE_NUM=$(echo "$ISSUE_OUTPUT" | grep -oE 'Issue number: [0-9]+' | grep -oE '[0-9]+' | tail -n 1) + if [ -n "$ISSUE_NUM" ]; then + EXISTING_CL_URL="https://chromium-review.googlesource.com/c/v8/v8/+/$ISSUE_NUM" + if [ "$READY_FOR_REVIEW" = true ]; then + git cl set-commit -d + UPLOAD_STATUS=$? + else + set_cl_wip "$ISSUE_NUM" "$PATCH_MSG" + UPLOAD_STATUS=$? + fi + if [ $UPLOAD_STATUS -eq 0 ]; then + UPLOAD_OUTPUT="$EXISTING_CL_URL" + fi + fi + fi fi if [ $UPLOAD_STATUS -ne 0 ]; then @@ -168,9 +337,26 @@ if [ $UPLOAD_STATUS -ne 0 ]; then exit $UPLOAD_STATUS fi -CL_URL=$(echo "$UPLOAD_OUTPUT" | grep -o 'https://chromium-review.googlesource.com/c/v8/v8/+/[0-9]*' | head -n 1) +CL_URL=$(echo "$UPLOAD_OUTPUT" | grep -o 'https://chromium-review.googlesource.com/c/v8/v8/+/[0-9]*' | tail -n 1) +if [ -z "$CL_URL" ]; then + ISSUE_NUM=$(echo "$ISSUE_OUTPUT" | grep -oE 'Issue number: [0-9]+' | grep -oE '[0-9]+' | tail -n 1) + if [ -n "$ISSUE_NUM" ]; then + CL_URL="https://chromium-review.googlesource.com/c/v8/v8/+/$ISSUE_NUM" + fi +fi + if [ -n "$CL_URL" ]; then echo "$CL_URL" else echo "$UPLOAD_OUTPUT" fi + +if [ "$READY_FOR_REVIEW" = true ] && [ -n "$CL_URL" ]; then + CL_ISSUE_NUM=$(echo "$CL_URL" | grep -oE '[0-9]+$' | tail -n 1) + echo "Waiting for CQ dry-run on $CL_URL (will switch to ready if it passes, or WIP if it fails)..." + wait_for_cl_dry_run "$CL_ISSUE_NUM" "$CL_URL" + DRY_RUN_STATUS=$? + if [ $DRY_RUN_STATUS -ne 0 ]; then + exit $DRY_RUN_STATUS + fi +fi 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-poc-classification/SKILL.md b/deps/v8/agents/skills/v8-poc-classification/SKILL.md index 7d453aede493..cbdbbc793cdb 100644 --- a/deps/v8/agents/skills/v8-poc-classification/SKILL.md +++ b/deps/v8/agents/skills/v8-poc-classification/SKILL.md @@ -84,8 +84,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 +101,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 ` (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 ` (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-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..80279db39d59 --- /dev/null +++ b/deps/v8/agents/skills/v8-review/SKILL.md @@ -0,0 +1,224 @@ +--- +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 `), 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-.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`, + `IndirectPointerTag`), and `ProtectedPointerSlot` between `TrustedObject`s. + Never use `TrustedCast` on untrusted or 1:N TPT-tagged inputs (use + `SbxCast` / `TryCast`). 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` or interior pointers + held across allocations/GC (must use `DirectHandle` / `Handle`), + 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` + on the stack or raw `GarbageCollected*` in heap objects (trace all + `Member` in `Trace(Visitor*)` and call `Base::Trace(visitor)`). + - **Write barriers & heap invariants**: Missing `WriteBarrier`, + `CONDITIONAL_WRITE_BARRIER`, `IndirectPointerWriteBarrier`, 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; 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**: `assertEquals(expected, found)` order; never + include `d8.file.execute('test/mjsunit/mjsunit.js')`; minimal leaf flags + over `--fuzzing`/`--jit-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; `const`-correctness and `std::forward`; + `base::bit_cast` (never `std::bit_cast`), `UNREACHABLE()`; V8 banned + constructs (``, `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). +- 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` (\<= 72 chars, no + period), concise body (\<= 10 lines, wrapped at \<= 72 chars, explaining + *why* and high-level *what*), CL references as `https://crrev.com/c/` + (not git hashes), and trailers (`Bug: ` or `Fixed: ` with plain + numeric ID for Chromium or `b:` for Buganizer, never `BUG=`; plus + `TAG=agy` and `R=@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..75d31a5af8b0 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 @@ -117,23 +117,33 @@ Buganizer. `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 `). + 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 `). + - 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`). @@ -175,11 +185,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 +202,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: ``)." You **MUST** retrieve - the `` from the `INVOKER_INFO_SESSION_ID` environment variable. The - variable must always be present. + the `` 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 +222,63 @@ 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 ](https://chromium-review.googlesource.com/c/v8/v8/+/)`). - - - **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`. **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 ](https://chromium-review.googlesource.com/c/v8/v8/+/) ("", 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 +287,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 +299,42 @@ 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. ### 7. Phase: Cleanup & Preservation @@ -301,10 +356,16 @@ Finalize the session by securing artifacts and cleaning up the environment. 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-workflow/SKILL.md b/deps/v8/agents/skills/v8-workflow/SKILL.md index 7b20b892daf9..114da7f593ba 100644 --- a/deps/v8/agents/skills/v8-workflow/SKILL.md +++ b/deps/v8/agents/skills/v8-workflow/SKILL.md @@ -56,3 +56,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-gerrit-fix/SKILL.md b/deps/v8/agents/skills/workflow-gerrit-fix/SKILL.md index db0d24017a4b..73909b1225b2 100644 --- a/deps/v8/agents/skills/workflow-gerrit-fix/SKILL.md +++ b/deps/v8/agents/skills/workflow-gerrit-fix/SKILL.md @@ -58,9 +58,12 @@ 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, upload intermediate fixes as WIP using + `agents/scripts/upload_cl.sh cur check "<what you changed>"`, and once ready + for review, run + `agents/scripts/upload_cl.sh cur check "<what you changed>" --ready` as a + background task to run a CQ dry-run and switch the CL to ready only if the + dry-run passes (or revert to WIP if the dry-run fails). ## Example: Fixing Errors diff --git a/deps/v8/bazel/defs.bzl b/deps/v8/bazel/defs.bzl index 68f283bcfc3c..e0eb187f9ea5 100644 --- a/deps/v8/bazel/defs.bzl +++ b/deps/v8/bazel/defs.bzl @@ -330,104 +330,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 ): @@ -623,11 +525,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 +543,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 +556,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 +577,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 +596,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 +624,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 +642,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 +668,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 +697,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 +727,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 +772,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 +791,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 +812,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..63a01ac3b3e9 --- /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//:v8_enable_pointer_compression": str(attr.pointer_compression), + } + +_v8_torque_pointer_compression_transition = transition( + implementation = _v8_torque_pointer_compression_transition_impl, + inputs = [], + outputs = ["@v8//: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({ + Label("//: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/gni/v8.gni b/deps/v8/gni/v8.gni index 3fb7d2964ab1..a460f83a6d56 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 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-callbacks.h b/deps/v8/include/v8-callbacks.h index efa9de293072..19ead4e3d636 100644 --- a/deps/v8/include/v8-callbacks.h +++ b/deps/v8/include/v8-callbacks.h @@ -489,6 +489,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-internal.h b/deps/v8/include/v8-internal.h index fd8fcda6f5ec..686e53c498f5 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 @@ -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, @@ -762,6 +770,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) \ diff --git a/deps/v8/include/v8-isolate.h b/deps/v8/include/v8-isolate.h index a352b5f0164f..d43a1ba60e99 100644 --- a/deps/v8/include/v8-isolate.h +++ b/deps/v8/include/v8-isolate.h @@ -267,6 +267,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 +676,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 +1739,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. diff --git a/deps/v8/include/v8-template.h b/deps/v8/include/v8-template.h index 182293f05bd8..fafeee892f2b 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); diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index d47b8f7f5c8b..7b32d6a9a224 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 13 +#define V8_MINOR_VERSION 7 +#define V8_BUILD_NUMBER 112 +#define V8_PATCH_LEVEL 5 // 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..03f0ba46d746 100644 --- a/deps/v8/include/v8-wasm.h +++ b/deps/v8/include/v8-wasm.h @@ -130,9 +130,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/mb_config.pyl b/deps/v8/infra/mb/mb_config.pyl index 3102eaf1ee57..2bd08a12442d 100644 --- a/deps/v8/infra/mb/mb_config.pyl +++ b/deps/v8/infra/mb/mb_config.pyl @@ -759,7 +759,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 +836,7 @@ # Torque compare test 'torque_compare': [ - 'release_bot', 'verify_torque'], + 'release_bot', 'verify_torque', 'v8_disable_metagen'], # PGO 'builtins_profiling_x86': ['builtins_profiling', 'x86'], @@ -1180,8 +1180,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/src/api/api-natives.cc b/deps/v8/src/api/api-natives.cc index 68ba61b7cbc2..7574dd8be9ec 100644 --- a/deps/v8/src/api/api-natives.cc +++ b/deps/v8/src/api/api-natives.cc @@ -691,7 +691,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 +744,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..a858e0a140bb 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" @@ -1397,7 +1398,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 +1591,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 +1720,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 +1747,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); @@ -7145,6 +7142,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. @@ -9076,7 +9074,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 @@ -9376,6 +9374,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( @@ -11048,6 +11054,9 @@ 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) 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 7713cd8103dd..a8a8ea005c54 100644 --- a/deps/v8/src/ast/scopes.cc +++ b/deps/v8/src/ast/scopes.cc @@ -496,6 +496,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()); @@ -1408,6 +1411,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_; @@ -1744,6 +1766,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()); @@ -2330,6 +2354,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); diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h index f85e7420968f..3d61344044dd 100644 --- a/deps/v8/src/ast/scopes.h +++ b/deps/v8/src/ast/scopes.h @@ -1075,6 +1075,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); } 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-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/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/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/platform/platform-posix.cc b/deps/v8/src/base/platform/platform-posix.cc index df122799fdca..7add12aa4798 100644 --- a/deps/v8/src/base/platform/platform-posix.cc +++ b/deps/v8/src/base/platform/platform-posix.cc @@ -82,19 +82,7 @@ #define MAP_ANONYMOUS MAP_ANON #endif -/* - * NOTE: illumos starting with illumos#14418 (pushed April 20th, 2022) - * prototypes madvise(3C) properly with a `void *` first argument. - * The only way to detect this outside of configure-time checking is to - * check for the existence of MEMCNTL_SHARED, which gets defined for the first - * time in illumos#14418 under the same circumstances save _STRICT_POSIX, which - * thankfully neither Solaris nor illumos builds of Node or V8 do. - * - * If some future illumos push changes the MEMCNTL_SHARED assumptions made - * above, the illumos check below will have to be revisited. This check - * will work on both pre-and-post illumos#14418 illumos environments. - */ -#if defined(V8_OS_SOLARIS) && !(defined(__illumos__) && defined(MEMCNTL_SHARED)) +#if defined(V8_OS_SOLARIS) #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE > 2) || defined(__EXTENSIONS__) extern "C" int madvise(caddr_t, size_t, int); #else diff --git a/deps/v8/src/base/small-vector.h b/deps/v8/src/base/small-vector.h index 55c64c081f5d..32c4b6ffa281 100644 --- a/deps/v8/src/base/small-vector.h +++ b/deps/v8/src/base/small-vector.h @@ -6,11 +6,11 @@ #define V8_BASE_SMALL_VECTOR_H_ #include <algorithm> +#include <bit> #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" @@ -355,8 +355,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/unique-array.h b/deps/v8/src/base/unique-array.h new file mode 100644 index 000000000000..e81a4d941933 --- /dev/null +++ b/deps/v8/src/base/unique-array.h @@ -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. + +#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" +#include "src/base/vector.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 `Vector<T>` view of the data in this array. + Vector<T> as_vector() const V8_LIFETIME_BOUND { return {begin(), size()}; } + + // Returns a `std::span<T>` view of the data in this array. + std::span<T> as_span() const V8_LIFETIME_BOUND { return {begin(), size()}; } + + // 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; +}; + +// 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..420c5f6a4370 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(); + } + + constexpr T& back() const { + DCHECK_LT(0, size()); + return span_.back(); + } + + constexpr Vector<T> first(size_t count) const { + DCHECK_LE(count, size()); + return Vector<T>(span_.first(count)); + } - T& last() { - DCHECK_LT(0, length_); - return start_[length_ - 1]; + constexpr Vector<T> last(size_t count) const { + DCHECK_LE(count, size()); + return Vector<T>(span_.last(count)); } - const T& last() const { - DCHECK_LT(0, length_); - return start_[length_ - 1]; + + 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,125 +216,6 @@ 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 // {ArrayVector}. @@ -383,87 +284,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/baseline-compiler.cc b/deps/v8/src/baseline/baseline-compiler.cc index b09ed33e0085..ab4e11cb0369 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() { @@ -685,19 +685,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() { @@ -1983,6 +1976,32 @@ 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; + + switch (iterator().next_bytecode()) { + case interpreter::Bytecode::kJumpIfTrue: + case interpreter::Bytecode::kJumpIfTrueConstant: { + auto [target_offset, fallthrough_offset] = iterator_.GetNextJumpOffsets(); + return CompareBranchCandidate{target_offset, fallthrough_offset}; + } + case interpreter::Bytecode::kJumpIfFalse: + case interpreter::Bytecode::kJumpIfFalseConstant: { + auto [target_offset, fallthrough_offset] = iterator_.GetNextJumpOffsets(); + return CompareBranchCandidate{fallthrough_offset, target_offset}; + } + default: + return std::nullopt; + } +} + template <Operation kOperation, Builtin kSmiBuiltin, Builtin kGenericBuiltin> bool BaselineCompiler::TryEmitInlineSmiCompare( CompareOperationFeedback::Type feedback_type, int feedback_index_offset) { @@ -1995,51 +2014,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 +2079,6 @@ bool BaselineCompiler::TryEmitInlineSmiCompare( feedback_index_offset); } __ Bind(&done); - return true; } #endif // V8_ENABLE_SPARKPLUG_PLUS diff --git a/deps/v8/src/baseline/baseline-compiler.h b/deps/v8/src/baseline/baseline-compiler.h index 724996805a55..e06a4ce52e99 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" @@ -155,6 +157,13 @@ class BaselineCompiler { 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(); #endif // V8_ENABLE_SPARKPLUG_PLUS // Jumps based on calling ToBoolean on kInterpreterAccumulatorRegister. diff --git a/deps/v8/src/builtins/accessors.cc b/deps/v8/src/builtins/accessors.cc index 313ac22137cd..d911d40349c4 100644 --- a/deps/v8/src/builtins/accessors.cc +++ b/deps/v8/src/builtins/accessors.cc @@ -524,27 +524,6 @@ DirectHandle<Object> Accessors::GetLegacyFunctionArguments( 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); -} - -#endif // V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - // // Accessors::FunctionCaller // @@ -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..80c8f7b8019f 100644 --- a/deps/v8/src/builtins/arm/builtins-arm.cc +++ b/deps/v8/src/builtins/arm/builtins-arm.cc @@ -2917,7 +2917,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 +2964,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 +3799,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 +3818,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 +3852,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 +3921,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 +3972,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 +4047,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 +4310,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 +4339,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 +4359,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..1bee12b5d5fe 100644 --- a/deps/v8/src/builtins/arm64/builtins-arm64.cc +++ b/deps/v8/src/builtins/arm64/builtins-arm64.cc @@ -3470,7 +3470,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 +3481,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 +3525,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 +3812,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 +3845,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}); @@ -3910,10 +3922,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 +4228,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 +4362,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 +4382,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 +4411,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 +4487,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 +4552,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 +4627,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 +4927,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 +4940,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 +4958,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 +4978,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); + + __ Mov(sp, fp); + __ Pop<MacroAssembler::kAuthLR>(fp, lr); + SwitchSimulatorStackLimit(masm); + __ Ret(); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { diff --git a/deps/v8/src/builtins/base.tq b/deps/v8/src/builtins/base.tq index 3bbd3108699b..ee322cb40c47 100644 --- a/deps/v8/src/builtins/base.tq +++ b/deps/v8/src/builtins/base.tq @@ -312,8 +312,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. @@ -606,9 +604,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; 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-console.cc b/deps/v8/src/builtins/builtins-console.cc index a909d38e5e84..101621e3425c 100644 --- a/deps/v8/src/builtins/builtins-console.cc +++ b/deps/v8/src/builtins/builtins-console.cc @@ -37,8 +37,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 { @@ -207,6 +206,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) { @@ -311,6 +311,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..ffde7e7bfc21 100644 --- a/deps/v8/src/builtins/builtins-constructor-gen.cc +++ b/deps/v8/src/builtins/builtins-constructor-gen.cc @@ -724,7 +724,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 +784,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 +803,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-definitions.h b/deps/v8/src/builtins/builtins-definitions.h index cdf103579956..fec8b48643c0 100644 --- a/deps/v8/src/builtins/builtins-definitions.h +++ b/deps/v8/src/builtins/builtins-definitions.h @@ -534,6 +534,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, \ @@ -798,14 +800,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 +1495,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) \ diff --git a/deps/v8/src/builtins/builtins-function.cc b/deps/v8/src/builtins/builtins-function.cc index f7ca54126017..c001e3762eeb 100644 --- a/deps/v8/src/builtins/builtins-function.cc +++ b/deps/v8/src/builtins/builtins-function.cc @@ -314,8 +314,6 @@ BUILTIN(FunctionPrototypeToString) { isolate->factory()->Function_string())); } -#ifndef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - namespace { bool IsSloppyNormalJSFunction(Tagged<Object> receiver) { @@ -374,7 +372,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-internal-gen.cc b/deps/v8/src/builtins/builtins-internal-gen.cc index 74703bcdb5c8..4fe19f388ecb 100644 --- a/deps/v8/src/builtins/builtins-internal-gen.cc +++ b/deps/v8/src/builtins/builtins-internal-gen.cc @@ -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..bbb5ec027aa0 100644 --- a/deps/v8/src/builtins/builtins-intl.cc +++ b/deps/v8/src/builtins/builtins-intl.cc @@ -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..426a29597bd9 100644 --- a/deps/v8/src/builtins/builtins-iterator-inl.h +++ b/deps/v8/src/builtins/builtins-iterator-inl.h @@ -77,8 +77,13 @@ inline MaybeDirectHandle<JSReceiver> IteratorStep( // https://tc39.es/ecma262/#sec-iteratorclose inline void IteratorClose(Isolate* isolate, DirectHandle<JSReceiver> iterator) { DirectHandle<Object> completion_exception; + 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); isolate->clear_exception(); } @@ -91,6 +96,10 @@ inline void IteratorClose(Isolate* isolate, DirectHandle<JSReceiver> iterator) { if (!Object::GetProperty(isolate, iterator, isolate->factory()->return_string()) .ToHandle(&return_method)) { + if (isolate->is_execution_terminating()) { + // Don't swallow the termination exception. + return; + } has_inner_exception = true; inner_exception = handle(isolate->exception(), isolate); isolate->clear_exception(); @@ -103,6 +112,11 @@ inline void IteratorClose(Isolate* isolate, DirectHandle<JSReceiver> iterator) { if (!Execution::Call(isolate, return_method, iterator, base::Vector<const DirectHandle<Object>>()) .ToHandle(&inner_result)) { + if (isolate->is_execution_terminating()) { + // Don't swallow the termination exception. + return; + } + has_inner_exception = true; inner_exception = handle(isolate->exception(), isolate); isolate->clear_exception(); 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.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-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-typed-array.cc b/deps/v8/src/builtins/builtins-typed-array.cc index 8dc3fe9b1bbb..5247000c5b2b 100644 --- a/deps/v8/src/builtins/builtins-typed-array.cc +++ b/deps/v8/src/builtins/builtins-typed-array.cc @@ -846,9 +846,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). @@ -1113,9 +1113,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..9c9f71aa15c7 100644 --- a/deps/v8/src/builtins/builtins-utils.h +++ b/deps/v8/src/builtins/builtins-utils.h @@ -59,13 +59,15 @@ class BuiltinArguments : public JavaScriptArguments { 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..294ece27bf64 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), @@ -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/cast.tq b/deps/v8/src/builtins/cast.tq index 24cd719932b6..c28d4b5edf56 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); 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/ia32/builtins-ia32.cc b/deps/v8/src/builtins/ia32/builtins-ia32.cc index 5ca8c70758cf..f7d2056ead09 100644 --- a/deps/v8/src/builtins/ia32/builtins-ia32.cc +++ b/deps/v8/src/builtins/ia32/builtins-ia32.cc @@ -3263,7 +3263,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 +3319,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 +3584,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 +3627,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 +3701,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 +3749,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 +3807,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 +4508,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 +4537,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 +4561,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/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..87fa2aa2604e 100644 --- a/deps/v8/src/builtins/loong64/builtins-loong64.cc +++ b/deps/v8/src/builtins/loong64/builtins-loong64.cc @@ -3065,17 +3065,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 +3168,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 +3477,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 +3509,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}); @@ -3571,10 +3583,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 +3879,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 +4020,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 +4039,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 +4070,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 +4139,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 +4186,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 +4194,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 +4273,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 +4525,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 +4538,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 +4555,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 +4575,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) { diff --git a/deps/v8/src/builtins/mips64/builtins-mips64.cc b/deps/v8/src/builtins/mips64/builtins-mips64.cc index ba302ca33eec..da57e8522387 100644 --- a/deps/v8/src/builtins/mips64/builtins-mips64.cc +++ b/deps/v8/src/builtins/mips64/builtins-mips64.cc @@ -3037,7 +3037,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 +3120,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 +3327,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/ppc/builtins-ppc.cc b/deps/v8/src/builtins/ppc/builtins-ppc.cc index 801176b74a4e..141c39d2e480 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, @@ -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, @@ -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; @@ -1569,8 +1575,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 +1605,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); } @@ -3172,7 +3180,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 +3223,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 +4058,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 +4077,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 +4108,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 +4180,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( @@ -4173,7 +4233,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 +4310,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 @@ -4545,18 +4618,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 +4645,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 +4665,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) { diff --git a/deps/v8/src/builtins/riscv/builtins-riscv.cc b/deps/v8/src/builtins/riscv/builtins-riscv.cc index a663f76a2f2f..2a3c0cfa9599 100644 --- a/deps/v8/src/builtins/riscv/builtins-riscv.cc +++ b/deps/v8/src/builtins/riscv/builtins-riscv.cc @@ -3300,7 +3300,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 +3311,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 +3359,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 +3606,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 +3619,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 +3637,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 +3657,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); + + __ Move(sp, fp); + __ LoadWord(ra, MemOperand(fp, CommonFrameConstants::kCallerPCOffset)); + __ LoadWord(fp, MemOperand(fp, CommonFrameConstants::kCallerFPOffset)); + __ AddWord(sp, sp, Operand(CommonFrameConstants::kFixedFrameSizeAboveFp)); + SwitchSimulatorStackLimit(masm); + __ Ret(); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { @@ -3819,6 +3861,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 +4024,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}); @@ -4053,10 +4099,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 +4406,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 +4572,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 +4625,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 +4695,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 +4748,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 +4833,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 diff --git a/deps/v8/src/builtins/s390/builtins-s390.cc b/deps/v8/src/builtins/s390/builtins-s390.cc index 8d7e01cb739b..20b5a719189b 100644 --- a/deps/v8/src/builtins/s390/builtins-s390.cc +++ b/deps/v8/src/builtins/s390/builtins-s390.cc @@ -3162,7 +3162,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 +3204,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 +4041,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 +4059,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 +4090,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 +4162,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 +4215,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 +4292,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 +4628,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 +4657,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 +4677,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..4b4442943d50 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 || 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/wasm.tq b/deps/v8/src/builtins/wasm.tq index 2f85cf06de05..b7e2edd61ba9 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; @@ -130,7 +129,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; @@ -471,15 +474,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 { @@ -556,11 +564,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 +580,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; @@ -867,10 +875,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 +1096,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 +1111,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 +1220,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); diff --git a/deps/v8/src/builtins/x64/builtins-x64.cc b/deps/v8/src/builtins/x64/builtins-x64.cc index a5a151bfac75..876722109202 100644 --- a/deps/v8/src/builtins/x64/builtins-x64.cc +++ b/deps/v8/src/builtins/x64/builtins-x64.cc @@ -2506,14 +2506,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); @@ -3356,7 +3361,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 +3372,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 +3431,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 +3556,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 +3678,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 +3715,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 +3726,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 +3815,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 +3880,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 +3934,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 +3975,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, @@ -3986,10 +4047,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; @@ -4596,31 +4655,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 +4699,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 +4720,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) { 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/macro-assembler-arm64.cc b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc index a79bd6d3186d..2d931b90f086 100644 --- a/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc +++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc @@ -2489,7 +2489,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 +2499,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); } diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64.h b/deps/v8/src/codegen/arm64/macro-assembler-arm64.h index ec3b6eb71c02..74a3a1f49555 100644 --- a/deps/v8/src/codegen/arm64/macro-assembler-arm64.h +++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64.h @@ -1131,7 +1131,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, @@ -1992,19 +1993,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/code-stub-assembler.cc b/deps/v8/src/codegen/code-stub-assembler.cc index 180facb5121a..96cc1c9b2bd6 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)); @@ -2050,9 +2052,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 +2065,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 +2095,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 @@ -2199,7 +2201,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 +2218,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 +2237,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); } @@ -2323,10 +2316,10 @@ TNode<TrustedObject> CodeStubAssembler::ResolveIndirectPointerHandle( if (IsFastIndirectPointerTagRange(tag_range)) { uint64_t mask = ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); - value = WordAnd(value, UintPtrConstant(mask)); + 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 +2332,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"); @@ -4183,8 +4177,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); } @@ -4669,6 +4666,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 +4725,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); @@ -18469,17 +18482,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 +18529,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 +18563,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) { diff --git a/deps/v8/src/codegen/code-stub-assembler.h b/deps/v8/src/codegen/code-stub-assembler.h index 004d38e895c4..181fb7fbb967 100644 --- a/deps/v8/src/codegen/code-stub-assembler.h +++ b/deps/v8/src/codegen/code-stub-assembler.h @@ -1792,7 +1792,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); @@ -2077,6 +2079,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. @@ -4385,11 +4389,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 fbcf0d8ba77a..8c7a4361d502 100644 --- a/deps/v8/src/codegen/compiler.cc +++ b/deps/v8/src/codegen/compiler.cc @@ -469,29 +469,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 +1387,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; @@ -1949,6 +1964,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"); @@ -2847,18 +2870,28 @@ void BackgroundDeserializeTask::Run() { 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); DirectHandle<SharedFunctionInfo> inner_result; - off_thread_data_ = - CodeSerializer::StartDeserializeOffThread(&isolate, &cached_data_); - if (v8_flags.enable_slow_asserts && off_thread_data_.HasResult()) { + CodeSerializer::StartDeserializeOffThread(&isolate, &cached_data_, + &off_thread_data_); + 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 + } } } @@ -2866,6 +2899,11 @@ void BackgroundDeserializeTask::SourceTextAvailable( Isolate* isolate, Handle<String> source_text, const ScriptDetails& script_details) { DCHECK_EQ(isolate, isolate_for_local_isolate_); + if (!CodeSerializer::NotifySourceTextAvailable(isolate, &off_thread_data_, + &cached_data_, source_text, + script_details)) { + return; + } LanguageMode language_mode = construct_language_mode(v8_flags.use_strict); background_merge_task_.SetUpOnMainThread(isolate, source_text, script_details, language_mode); @@ -3458,6 +3496,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()); @@ -3617,10 +3663,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), @@ -3657,6 +3708,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_; @@ -3804,6 +3856,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); @@ -3974,7 +4032,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) { @@ -4031,6 +4092,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"); @@ -4057,6 +4122,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); } @@ -4091,10 +4163,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( @@ -4206,8 +4275,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); @@ -4236,6 +4305,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"); @@ -4257,6 +4332,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); @@ -4322,6 +4401,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 7f8c3152e8ac..003b30ae2dd5 100644 --- a/deps/v8/src/codegen/compiler.h +++ b/deps/v8/src/codegen/compiler.h @@ -432,6 +432,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 +446,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_; @@ -719,7 +722,7 @@ class V8_EXPORT_PRIVATE BackgroundDeserializeTask { private: Isolate* isolate_for_local_isolate_; AlignedCachedData cached_data_; - CodeSerializer::OffThreadDeserializeData off_thread_data_; + OffThreadDeserializeData off_thread_data_; BackgroundMergeTask background_merge_task_; TimedHistogram* timer_; int64_t background_time_in_microseconds_ = 0; diff --git a/deps/v8/src/codegen/external-reference.cc b/deps/v8/src/codegen/external-reference.cc index 55aa84225782..ef30dfcd16d5 100644 --- a/deps/v8/src/codegen/external-reference.cc +++ b/deps/v8/src/codegen/external-reference.cc @@ -595,7 +595,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) @@ -1153,20 +1152,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 +1881,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..7cdd490902d6 100644 --- a/deps/v8/src/codegen/external-reference.h +++ b/deps/v8/src/codegen/external-reference.h @@ -62,12 +62,8 @@ 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) \ @@ -289,7 +285,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") \ 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..880c7f60eaa4 100644 --- a/deps/v8/src/codegen/interface-descriptors-inl.h +++ b/deps/v8/src/codegen/interface-descriptors-inl.h @@ -629,6 +629,12 @@ constexpr auto GetIteratorStackParameterDescriptor::registers() { return RegisterArray(); } +// static +constexpr auto +ProxyGetPropertyTrapResultLazyDeoptContinuationDescriptor::registers() { + return RegisterArray(); +} + // static constexpr auto ForOfNextResultDeoptContinuationDescriptor::registers() { return RegisterArray(); @@ -822,6 +828,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.h b/deps/v8/src/codegen/interface-descriptors.h index 9da51025d9fc..74793f955056 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) \ @@ -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 @@ -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> { diff --git a/deps/v8/src/codegen/loong64/macro-assembler-loong64.cc b/deps/v8/src/codegen/loong64/macro-assembler-loong64.cc index cf8c680be936..650a4dc0892f 100644 --- a/deps/v8/src/codegen/loong64/macro-assembler-loong64.cc +++ b/deps/v8/src/codegen/loong64/macro-assembler-loong64.cc @@ -2839,19 +2839,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 +2884,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, @@ -5926,7 +5958,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 +5970,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..22fcf80d0f2d 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); diff --git a/deps/v8/src/codegen/maglev-safepoint-table.cc b/deps/v8/src/codegen/maglev-safepoint-table.cc index edff237eaad5..e88983dbb1d4 100644 --- a/deps/v8/src/codegen/maglev-safepoint-table.cc +++ b/deps/v8/src/codegen/maglev-safepoint-table.cc @@ -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..e404f93f7f79 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 { @@ -272,7 +273,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..3193fee1950a 100644 --- a/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc +++ b/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc @@ -6503,7 +6503,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 +6514,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.h b/deps/v8/src/codegen/optimized-compilation-info.h index 7b2a5621066b..0077a8497b8f 100644 --- a/deps/v8/src/codegen/optimized-compilation-info.h +++ b/deps/v8/src/codegen/optimized-compilation-info.h @@ -280,7 +280,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/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..9738df8c4a54 100644 --- a/deps/v8/src/codegen/riscv/macro-assembler-riscv.cc +++ b/deps/v8/src/codegen/riscv/macro-assembler-riscv.cc @@ -1891,10 +1891,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 +2087,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 +2113,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 +2134,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 +2183,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 +2199,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 +7649,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 +7662,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..db14494bbe50 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, 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..a9d63d611021 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; diff --git a/deps/v8/src/codegen/safepoint-table.h b/deps/v8/src/codegen/safepoint-table.h index 84cb4d9a04af..b1815c297f21 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" @@ -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..b45db5ab93fd 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,12 +230,12 @@ 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 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..e66c29353869 100644 --- a/deps/v8/src/codegen/tnode.h +++ b/deps/v8/src/codegen/tnode.h @@ -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..09d588b35fa0 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: diff --git a/deps/v8/src/codegen/x64/assembler-x64.cc b/deps/v8/src/codegen/x64/assembler-x64.cc index 33f173c19f6b..d88bcdfa335a 100644 --- a/deps/v8/src/codegen/x64/assembler-x64.cc +++ b/deps/v8/src/codegen/x64/assembler-x64.cc @@ -4417,6 +4417,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..b04928e8f7bf 100644 --- a/deps/v8/src/codegen/x64/assembler-x64.h +++ b/deps/v8/src/codegen/x64/assembler-x64.h @@ -753,7 +753,12 @@ 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). + }; enum OpMask { k0 = 0x0, k1 = 0x1, k2 = 0x2 }; enum MaskingType { kMerging = 0x0, kZeroing = 0x80 }; enum TupleType { @@ -2651,6 +2656,20 @@ 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 vpmullq(XMMRegister dst, XMMRegister src1, XMMRegister src2) { vinstr_evex(0x40, dst, src1, src2, k66, k0F38, kW1); } 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..bf7bc213c8e3 100644 --- a/deps/v8/src/codegen/x64/macro-assembler-x64.cc +++ b/deps/v8/src/codegen/x64/macro-assembler-x64.cc @@ -905,8 +905,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 +938,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 +956,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, @@ -1157,9 +1159,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 +1169,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) { @@ -2311,6 +2329,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 +2410,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 +2421,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 +2441,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 +2455,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 +2600,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 +2622,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 +2655,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 +2726,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 +3744,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); } @@ -4171,7 +4251,7 @@ Immediate MacroAssembler::ClearedValue() const { #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(); } } @@ -4694,13 +4774,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..b04da1a15f1a 100644 --- a/deps/v8/src/codegen/x64/macro-assembler-x64.h +++ b/deps/v8/src/codegen/x64/macro-assembler-x64.h @@ -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,7 +727,7 @@ 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; @@ -782,8 +795,9 @@ class V8_EXPORT_PRIVATE MacroAssembler 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); 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/globals.h b/deps/v8/src/common/globals.h index 16b4c069f5ef..00159e4a8131 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> @@ -378,6 +379,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 +614,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 +633,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. @@ -1342,6 +1354,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. @@ -2542,7 +2557,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 +2581,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 +2601,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 +2736,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 +2758,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 +2808,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 +2825,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 +3223,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/compiler-dispatcher/optimizing-compile-dispatcher.cc b/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.cc index 00b43f297347..6e4533e7b736 100644 --- a/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.cc +++ b/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.cc @@ -8,7 +8,7 @@ #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" @@ -115,7 +115,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..45aeeee5cca9 100644 --- a/deps/v8/src/compiler/OWNERS +++ b/deps/v8/src/compiler/OWNERS @@ -1,5 +1,6 @@ dmercadier@chromium.org jgruber@chromium.org +jkummerow@chromium.org manoskouk@chromium.org mliedtke@chromium.org nicohartmann@chromium.org @@ -10,13 +11,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..6000e528114f 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; } 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/backend/arm/code-generator-arm.cc b/deps/v8/src/compiler/backend/arm/code-generator-arm.cc index bb60c451ec06..6282bb5aab83 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()); @@ -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/arm64/code-generator-arm64.cc b/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc index f4efe50f64d1..70ddbe143354 100644 --- a/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc +++ b/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc @@ -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(); @@ -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; @@ -3048,6 +2986,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 +3130,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 +3166,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 +3338,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 +3364,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); @@ -3696,6 +3675,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 +3694,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 +3704,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 +3862,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 +4245,7 @@ void CodeGenerator::FinishFrame(Frame* frame) { } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); __ AssertSpAligned(); @@ -4283,164 +4264,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 +4495,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 +4873,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..8e845ccd4847 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) \ 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..ef2cb8538290 100644 --- a/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc +++ b/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc @@ -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: @@ -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..9ac493f16dd9 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())); @@ -2456,7 +2543,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 +3262,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 +3286,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 +5105,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 +5542,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 +5692,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 +5731,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,6 +5812,8 @@ 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(); @@ -5685,6 +5927,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 +6880,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 +7045,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 +7088,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 +7173,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..cc55103a6742 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" @@ -336,6 +339,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 +505,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 +537,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 +553,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 +568,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 +581,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; } @@ -965,9 +994,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 +1025,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 +1041,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 +1065,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 +1075,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 +1088,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 +1133,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 +1145,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 +1157,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 +1185,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 +1196,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 +1703,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..22d2b4655e20 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; @@ -4151,38 +4151,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 +4201,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 +4350,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/instruction-codes.h b/deps/v8/src/compiler/backend/instruction-codes.h index 03359d373ab0..82c602bd6333 100644 --- a/deps/v8/src/compiler/backend/instruction-codes.h +++ b/deps/v8/src/compiler/backend/instruction-codes.h @@ -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-selector.cc b/deps/v8/src/compiler/backend/instruction-selector.cc index 2fe007252dfd..6c801783033f 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()); } } } @@ -1180,6 +1164,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 = {}; @@ -2158,11 +2143,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 +2159,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 +2268,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 +2488,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 +2583,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..67f1390c29c5 100644 --- a/deps/v8/src/compiler/backend/instruction-selector.h +++ b/deps/v8/src/compiler/backend/instruction-selector.h @@ -783,6 +783,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(); diff --git a/deps/v8/src/compiler/backend/instruction.h b/deps/v8/src/compiler/backend/instruction.h index 2f07ae1d8586..fc2f464e0a2b 100644 --- a/deps/v8/src/compiler/backend/instruction.h +++ b/deps/v8/src/compiler/backend/instruction.h @@ -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 { @@ -1134,8 +1135,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..1875fc289a22 100644 --- a/deps/v8/src/compiler/backend/loong64/code-generator-loong64.cc +++ b/deps/v8/src/compiler/backend/loong64/code-generator-loong64.cc @@ -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(); @@ -5050,43 +5052,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 +5119,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 +5273,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/mips64/code-generator-mips64.cc b/deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc index 8cddfacc3709..c293d3a16264 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; @@ -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/ppc/code-generator-ppc.cc b/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc index fa085daf2a55..66ac1518ea83 100644 --- a/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc +++ b/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc @@ -950,8 +950,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 +960,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 +969,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 +977,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } } } else { - __ CallJSFunction(kJavaScriptCallTargetRegister, num_arguments); + __ CallJSFunction(kJavaScriptCallTargetRegister, + expected_parameter_count); } } else { Register func = i.InputRegister(0); @@ -990,7 +991,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()); @@ -3164,55 +3165,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 +3234,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 +3396,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/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..b813afac5525 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; @@ -232,11 +225,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 +279,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; @@ -544,8 +532,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(); @@ -696,7 +684,6 @@ TopLevelLiveRange::TopLevelLiveRange(int vreg, MachineRepresentation rep, spill_operand_(nullptr), spill_move_insertion_locations_(nullptr), children_({this}, zone), - spilled_in_deferred_blocks_(false), has_preassigned_slot_(false), spill_start_index_(kMaxInt) { bits_ |= SpillTypeField::encode(SpillType::kNoSpillType); @@ -711,8 +698,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 +707,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 +719,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); @@ -1069,8 +1054,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 +1066,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 +1182,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 +1217,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()); } @@ -1302,8 +1284,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 +1433,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 +1466,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 +1478,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 +1543,6 @@ InstructionOperand* ConstraintBuilder::AllocateFixed( instr->reference_map()->RecordReference(*AllocatedOperand::cast(operand)); } } - return operand; } void ConstraintBuilder::MeetRegisterConstraints() { @@ -2209,9 +2201,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); @@ -2457,7 +2448,6 @@ void LiveRangeBuilder::BuildLiveRanges() { pos->set_type(new_type, true); } } - range->ResetCurrentHintPosition(); } for (auto preassigned : data()->preassigned_slot_ranges()) { TopLevelLiveRange* range = preassigned.first; @@ -3568,20 +3558,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 +4122,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 +4271,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 +4629,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 +4764,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 +4894,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 +4996,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 +5021,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 +5029,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 +5078,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 +5103,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 +5167,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 +5185,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..e9471250085e 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_; @@ -499,7 +495,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; @@ -525,8 +520,6 @@ class V8_EXPORT_PRIVATE UsePosition final uint32_t flags_; }; -class SpillRange; -class TopLevelLiveRange; class LiveRangeBundle; enum GrowthDirection { kFront, kFrontOrBack }; @@ -555,9 +548,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 +812,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 +871,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 +904,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 +969,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 +1062,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 +1142,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 +1159,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,15 +1174,14 @@ 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_; } @@ -1245,15 +1208,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_; } @@ -1301,9 +1262,6 @@ class V8_EXPORT_PRIVATE TopLevelLiveRange final : public LiveRange { // 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_; @@ -1378,9 +1336,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 +1505,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 +1516,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. @@ -1594,8 +1547,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 +1715,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..e6a0851e9141 100644 --- a/deps/v8/src/compiler/backend/riscv/code-generator-riscv.cc +++ b/deps/v8/src/compiler/backend/riscv/code-generator-riscv.cc @@ -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(); @@ -2928,6 +2930,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 +2940,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); @@ -5410,30 +5418,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 +5473,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 +5628,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/s390/code-generator-s390.cc b/deps/v8/src/compiler/backend/s390/code-generator-s390.cc index d9798f6f565a..9174e1e97901 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(); @@ -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/simd-shuffle.cc b/deps/v8/src/compiler/backend/simd-shuffle.cc index 60062d9b1f21..d175a613c390 100644 --- a/deps/v8/src/compiler/backend/simd-shuffle.cc +++ b/deps/v8/src/compiler/backend/simd-shuffle.cc @@ -485,15 +485,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..d9d138c560fa 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. 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..859bfc5e15ac 100644 --- a/deps/v8/src/compiler/backend/x64/code-generator-x64.cc +++ b/deps/v8/src/compiler/backend/x64/code-generator-x64.cc @@ -907,10 +907,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 +932,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 +953,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 +965,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 +1012,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 +1658,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 +1819,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 +1830,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 +1843,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 +1851,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } } } else { - __ CallJSFunction(kJavaScriptCallTargetRegister, num_arguments); + __ CallJSFunction(kJavaScriptCallTargetRegister, + expected_parameter_count); } } else { Register func = i.InputRegister(0); @@ -1842,7 +1862,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); @@ -3388,8 +3408,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)); @@ -3470,7 +3492,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 +3502,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,7 +3530,8 @@ 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; } @@ -3527,7 +3552,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 +3574,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 +3849,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 +4041,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 @@ -4543,10 +4571,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 +4578,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: { @@ -8370,56 +8382,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 +8460,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 +8626,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-selector-x64.cc b/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc index e13d8b99d851..eb8afa9137dc 100644 --- a/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc +++ b/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc @@ -1410,6 +1410,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); } @@ -1869,7 +1872,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 +1894,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); @@ -4783,7 +4784,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) \ @@ -5263,6 +5263,22 @@ 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); + } +} + #define VISIT_SIMD_F16x8_BINOP(Name, Opcode) \ void InstructionSelector::Visit##Name(OpIndex node) { \ X64OperandGenerator g(this); \ @@ -6456,7 +6472,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..2b1062dd45df 100644 --- a/deps/v8/src/compiler/bytecode-analysis.cc +++ b/deps/v8/src/compiler/bytecode-analysis.cc @@ -41,19 +41,17 @@ 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); - } + DCHECK_IMPLIES(count > 0, + interpreter::Register(r.index() + count - 1).is_parameter()); + bit_vector_->Add(r.ToParameterIndex(), count); } 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_IMPLIES( + count > 0, + !interpreter::Register(r.index() + count - 1).is_parameter()); + bit_vector_->Add(parameter_count_ + r.index(), count); } } - void BytecodeLoopAssignments::Union(const BytecodeLoopAssignments& other) { bit_vector_->Union(*other.bit_vector_); } @@ -102,26 +100,17 @@ void UpdateInLivenessForOutOperand( 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); - } + 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); + 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); + in_liveness->MarkRegistersDead(r.index(), 3); } } else { DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_type)); @@ -141,18 +130,13 @@ 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); + 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(!Bytecodes::IsRegisterInputOperandType(operand_type)); 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.h b/deps/v8/src/compiler/code-assembler.h index 06a61b2fa0ce..0c19785d04d1 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>( 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/heap-refs.cc b/deps/v8/src/compiler/heap-refs.cc index e6c1a18c71aa..0bb11df4474e 100644 --- a/deps/v8/src/compiler/heap-refs.cc +++ b/deps/v8/src/compiler/heap-refs.cc @@ -1921,6 +1921,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) @@ -2805,7 +2806,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..b0b751464f5c 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) @@ -1208,6 +1222,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; diff --git a/deps/v8/src/compiler/js-call-reducer.cc b/deps/v8/src/compiler/js-call-reducer.cc index ef2524264c24..d7fd03abe604 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, @@ -1014,7 +1026,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 +1070,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 +1244,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 +1278,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 +1429,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 +2737,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 @@ -6215,11 +6226,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 +6580,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 +6956,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 +6967,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 +6975,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. @@ -7712,7 +7724,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(); 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..4b5358dbe3c7 100644 --- a/deps/v8/src/compiler/js-create-lowering.cc +++ b/deps/v8/src/compiler/js-create-lowering.cc @@ -1835,16 +1835,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 +1856,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..8742d1bb69c6 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(); 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-native-context-specialization.cc b/deps/v8/src/compiler/js-native-context-specialization.cc index 901ccd3d4a40..d6af387c9e1a 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) { @@ -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); @@ -3575,8 +3439,25 @@ 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()) { + // The map store must follow the value write and use release semantics + // so background threads (e.g. concurrent compiler) see a consistent + // initialized state upon observing the HeapNumber map. + effect = graph()->NewNode( + jsgraph()->machine()->MemoryBarrier(AtomicMemoryOrder::kAcqRel), + effect, control); + effect = graph()->NewNode( + simplified()->StoreField(AccessBuilder::ForMap()), storage, + jsgraph()->ConstantNoHole(broker()->heap_number_map(), broker()), + effect, control); + } } } 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-typed-lowering.cc b/deps/v8/src/compiler/js-typed-lowering.cc index 77b5ff4320a4..aea3b0ba1419 100644 --- a/deps/v8/src/compiler/js-typed-lowering.cc +++ b/deps/v8/src/compiler/js-typed-lowering.cc @@ -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; @@ -2143,9 +2143,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 +2168,11 @@ 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 | CallDescriptor::kCanUseRoots))); } else if (shared->HasBuiltinId() && Builtins::IsCpp(shared->builtin_id())) { // Patch {node} to a direct CEntry call. @@ -2177,7 +2183,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 +2215,11 @@ 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 | CallDescriptor::kCanUseRoots))); } return Changed(node); } @@ -2248,6 +2255,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 +2369,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(); diff --git a/deps/v8/src/compiler/linkage.cc b/deps/v8/src/compiler/linkage.cc index 2f8a65819476..e9119b3441ba 100644 --- a/deps/v8/src/compiler/linkage.cc +++ b/deps/v8/src/compiler/linkage.cc @@ -531,6 +531,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 +601,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. diff --git a/deps/v8/src/compiler/linkage.h b/deps/v8/src/compiler/linkage.h index badf34bf4af9..ce01600b6d88 100644 --- a/deps/v8/src/compiler/linkage.h +++ b/deps/v8/src/compiler/linkage.h @@ -109,15 +109,15 @@ class V8_EXPORT_PRIVATE CallDescriptor final }; 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 +125,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 +239,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 +359,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 +421,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/pipeline.cc b/deps/v8/src/compiler/pipeline.cc index 27f9007b2dda..855e4bb79531 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" @@ -649,14 +651,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 +824,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; } @@ -2096,8 +2097,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 +2116,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 @@ -2866,12 +2867,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; diff --git a/deps/v8/src/compiler/simplified-lowering.cc b/deps/v8/src/compiler/simplified-lowering.cc index d87dbb59d669..37a87f7fe5a5 100644 --- a/deps/v8/src/compiler/simplified-lowering.cc +++ b/deps/v8/src/compiler/simplified-lowering.cc @@ -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.h b/deps/v8/src/compiler/simplified-operator.h index f97271fad954..ae19f60a777f 100644 --- a/deps/v8/src/compiler/simplified-operator.h +++ b/deps/v8/src/compiler/simplified-operator.h @@ -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), @@ -155,7 +157,8 @@ struct FieldAccess { ExternalPointerTag external_pointer_tag = kExternalPointerNullTag, IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag, 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), @@ -169,7 +172,8 @@ struct FieldAccess { indirect_pointer_tag(indirect_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_) && 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-types.cc b/deps/v8/src/compiler/turbofan-types.cc index 11de500c4641..815e52f7e256 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: diff --git a/deps/v8/src/compiler/turboshaft/assembler.h b/deps/v8/src/compiler/turboshaft/assembler.h index 6ab086ea3768..dddcff3ce7c5 100644 --- a/deps/v8/src/compiler/turboshaft/assembler.h +++ b/deps/v8/src/compiler/turboshaft/assembler.h @@ -3178,12 +3178,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 +3202,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 +3221,10 @@ 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<Word32> LoadInstanceTypeField(V<Map> map) { @@ -3240,8 +3237,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 +3472,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 +3635,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 +4150,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 +4172,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); } @@ -5307,36 +5296,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 +5342,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 +5382,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/duplication-optimization-reducer.h b/deps/v8/src/compiler/turboshaft/duplication-optimization-reducer.h index c8b0db665c09..422e7982f696 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 @@ -144,6 +158,10 @@ class DuplicationOptimizationReducer : public Next { 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-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.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..4debdab1074c 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,12 +38,10 @@ 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. @@ -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/instruction-selection-normalization-reducer.h b/deps/v8/src/compiler/turboshaft/instruction-selection-normalization-reducer.h index d8f2d73c46ce..664fdef504dc 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,17 @@ #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 "src/base/bits.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 { @@ -26,6 +31,9 @@ namespace v8::internal::compiler::turboshaft { // // * Splitting widening SIMD loads into 64-bit zero-extending loads and // low-half extensions on ARM64. +// +// * Canonicalizing SIMD multiplications of matching widening extensions into +// ExtMul operations. #include "src/compiler/turboshaft/define-assembler-macros.inc" @@ -109,7 +117,83 @@ class InstructionSelectionNormalizationReducer : public Next { } #endif // V8_ENABLE_SIMD128 && V8_TARGET_ARCH_ARM64 +#if V8_ENABLE_SIMD128 && V8_TARGET_ARCH_ARM64 + V<Simd128> REDUCE(Simd128Binop)(V<Simd128> left, V<Simd128> right, + Simd128BinopOp::Kind kind) { + if (!ShouldSkipOptimizationStep()) { + if (std::optional<WideningMulMatch> match = + TryMatchMulOfExtends(left, right, kind)) { + return __ Simd128Binop(match->left, match->right, match->extmul_kind); + } + } + return Next::ReduceSimd128Binop(left, right, kind); + } +#endif // V8_ENABLE_SIMD128 && V8_TARGET_ARCH_ARM64 + 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..d8870de1443b 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, 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..b9b89e96c4f5 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 @@ -722,19 +717,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..c873b3d77913 100644 --- a/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.h +++ b/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.h @@ -608,32 +608,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 +678,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 +840,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 +959,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/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/operations.cc b/deps/v8/src/compiler/turboshaft/operations.cc index af0c5b0b3fcb..86f2fc1c99b7 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 << ']'; } @@ -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..800850293b3b 100644 --- a/deps/v8/src/compiler/turboshaft/operations.h +++ b/deps/v8/src/compiler/turboshaft/operations.h @@ -1044,7 +1044,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 +3150,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 +3168,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 +3177,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 +3186,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 +3195,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 +3204,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,12 +3233,19 @@ struct LoadOp : OperationT<LoadOp> { return new_kind; } + [[nodiscard]] constexpr Kind SharedBase() const { + Kind new_kind(*this); + new_kind.shared_base = true; + 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; + is_immutable == other.is_immutable && + is_atomic == other.is_atomic && shared_base == other.shared_base; } }; Kind kind; @@ -4221,9 +4236,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 +4244,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 +4261,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 +4907,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 +4924,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 +4935,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> { @@ -8334,6 +8300,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 +8318,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 +8340,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 +8348,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 +8368,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 +8392,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 +8401,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 +8415,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 +8433,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 +8479,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 +8502,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 +8529,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 +8548,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 +8566,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 +9527,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 +9592,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); } 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..18b62915e378 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 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/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/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..48f6a379355f 100644 --- a/deps/v8/src/compiler/turboshaft/stack-check-lowering-reducer.h +++ b/deps/v8/src/compiler/turboshaft/stack-check-lowering-reducer.h @@ -83,9 +83,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 +110,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 = 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..fe1cd778997a 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,6 +1608,7 @@ class GraphBuildingNodeProcessor { graph_zone(), false, std::max<int>(actual_parameter_count, node->expected_parameter_count()), + node->expected_parameter_count(), CallDescriptor::kNeedsFrameState | CallDescriptor::kCanUseRoots); LazyDeoptOnThrow lazy_deopt_on_throw = ShouldLazyDeoptOnThrow(node); @@ -2109,7 +2109,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 +2120,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; @@ -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/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..a6814c4f7aff 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; @@ -343,6 +348,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 +382,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); 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..b60c8dd5dfcf 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 @@ -740,7 +740,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 +750,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 +758,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..afd4fa7cbe76 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.cc +++ b/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.cc @@ -554,7 +554,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..756bd54e18f4 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" @@ -590,13 +591,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 +624,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 +643,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..8c1cb08e65bf 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-lowering-reducer.h +++ b/deps/v8/src/compiler/turboshaft/wasm-lowering-reducer.h @@ -87,8 +87,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; } @@ -136,7 +142,10 @@ class WasmLoweringReducer : public Next { GOTO_IF(__ IsNull(object, wasm::kWasmExternRef), null_label); } GOTO_IF(__ IsSmi(object), smi_label); - GOTO_IF(__ HasInstanceType(object, HEAP_NUMBER_TYPE), heap_number_label); + // Even non-shared externref may carry shared objects, hence the SharedFlag + // below. + GOTO_IF(__ HasInstanceType(object, HEAP_NUMBER_TYPE, SharedFlag{true}), + heap_number_label); // For anything else, just pass through the value. GOTO(end_label, object); @@ -243,6 +252,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 +263,7 @@ class WasmLoweringReducer : public Next { #if V8_MAP_PACKING UNIMPLEMENTED(); #endif + if (type->is_shared()) UNIMPLEMENTED(); return __ Load(map, LoadOp::Kind::TaggedBase().Immutable(), MemoryRepresentation::TaggedPointer(), offsetof(Map, instance_descriptors_)); @@ -348,21 +360,22 @@ class WasmLoweringReducer : public Next { 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(); - } + if (memory_order.has_value()) load_kind = load_kind.Atomic(); + if (shared_base) load_kind = load_kind.SharedBase(); return __ Load(array, __ ChangeInt32ToIntPtr(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) { @@ -378,7 +391,8 @@ class WasmLoweringReducer : public Next { DCHECK_IMPLIES(write_barrier == kFullWriteBarrier, element_type.is_ref()); __ Store(array, __ ChangeInt32ToIntPtr(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 +401,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); + 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 +422,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 +439,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,16 +462,17 @@ 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>()); @@ -477,9 +495,10 @@ 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>()); @@ -702,6 +721,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 +758,8 @@ class WasmLoweringReducer : public Next { } RejectSharedWasmObjectsIfUnshared(V<HeapObject>::Cast(object), config, end_label); - result = IsDataRefMap(__ LoadMapField(object)); + + result = IsDataRefMap(__ LoadMapField(object, shared_base)); break; } // array, struct, string: i31 fails. @@ -744,19 +769,22 @@ class WasmLoweringReducer : public Next { if (to_kind == wasm::GenericKind::kArray) { RejectSharedWasmObjectsIfUnshared(V<HeapObject>::Cast(object), config, end_label); - result = __ HasInstanceType(object, WASM_ARRAY_TYPE); + // Same as above. + 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); + // Same as above. + result = __ HasInstanceType(object, WASM_STRUCT_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 +815,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 +860,8 @@ class WasmLoweringReducer : public Next { } TrapOnSharedWasmObjectsIfUnshared(V<HeapObject>::Cast(object), config, frame_state); - __ TrapIfNot(IsDataRefMap(__ LoadMapField(object)), frame_state, - TrapId::kTrapIllegalCast); + __ TrapIfNot(IsDataRefMap(__ LoadMapField(object, shared_base)), + frame_state, TrapId::kTrapIllegalCast); break; } // array, struct, string: i31 fails. @@ -838,21 +871,24 @@ 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); + // Same as above + __ TrapIfNot(__ HasInstanceType(object, WASM_STRUCT_TYPE, shared_base), + frame_state, TrapId::kTrapIllegalCast); 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; @@ -878,6 +914,11 @@ class WasmLoweringReducer : public Next { int rtt_depth = wasm::GetSubtypingDepth(module_, config.to.ref_index()); bool object_can_be_i31 = wasm::IsSubtypeOf( wasm::kWasmI31Ref.AsNonNull(), config.from.AsNonShared(), module_); + // 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))}; Label<> end_label(&Asm()); bool is_cast_from_any = @@ -898,7 +939,7 @@ class WasmLoweringReducer : public Next { __ TrapIf(__ IsSmi(object), frame_state, TrapId::kTrapIllegalCast); } - 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); @@ -968,6 +1009,11 @@ class WasmLoweringReducer : public Next { wasm::kWasmI31Ref.AsNonNull(), config.from.AsNonShared(), module_); bool is_cast_from_any = config.from.is_reference_to(wasm::GenericKind::kAny); + // 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))}; Label<Word32> end_label(&Asm()); @@ -981,7 +1027,7 @@ class WasmLoweringReducer : public Next { GOTO_IF(__ IsSmi(object), end_label, 0); } - 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); diff --git a/deps/v8/src/compiler/turboshaft/wasm-wrappers-inl.h b/deps/v8/src/compiler/turboshaft/wasm-wrappers-inl.h index 1e95485f25de..c9a83a401b74 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-wrappers-inl.h +++ b/deps/v8/src/compiler/turboshaft/wasm-wrappers-inl.h @@ -131,6 +131,17 @@ auto WasmWrapperTSGraphBuilder<Assembler>::ToJS(OpIndex ret, } } +#ifdef V8_IS_TSAN + if (v8_flags.wasm_shared && + (type.is_shared() || type.is_reference_to(GenericKind::kAny))) { + IF_NOT (__ IsSmi(ret)) { + __ WasmCallRuntime(__ phase_zone(), + Runtime::kTsanAcquireForInitializationFence, {ret}, + __ NoContextConstant(), CanThrow{false}); + } + } +#endif + if (type.ref_type_kind() == wasm::RefTypeKind::kFunction) { // Function reference. Extract the external function. if (type.is_nullable()) { @@ -412,31 +423,6 @@ 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) { @@ -482,6 +468,42 @@ void WasmWrapperTSGraphBuilder<Assembler>::BuildWasmToJSWrapper( } } + // Check that the central stack has enough space for the outgoing parameters. + V<WordPtr> stack_limit = __ Load( + __ LoadRootRegister(), LoadOp::Kind::RawAligned().NotLoadEliminable(), + MemoryRepresentation::UintPtr(), IsolateData::real_jslimit_offset()); + 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 +511,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,8 +618,11 @@ 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, diff --git a/deps/v8/src/compiler/turboshaft/wasm-wrappers.h b/deps/v8/src/compiler/turboshaft/wasm-wrappers.h index e4376ecfbc9e..e15616ac5247 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-wrappers.h +++ b/deps/v8/src/compiler/turboshaft/wasm-wrappers.h @@ -166,7 +166,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 +188,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. @@ -352,7 +357,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 +416,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 +449,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 +499,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 +535,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 +622,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 +660,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 +887,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 +902,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) { @@ -919,7 +936,7 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { 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/wasm-compiler-definitions.cc b/deps/v8/src/compiler/wasm-compiler-definitions.cc index 1c5225d62b46..1b1a42d55ae1 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" @@ -63,12 +64,12 @@ base::Vector<const char> GetDebugName(Zone* zone, 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); + memcpy(index_name, name_vector.data(), name_len); return base::Vector<const char>(index_name, name_len); } diff --git a/deps/v8/src/compiler/wasm-gc-lowering.cc b/deps/v8/src/compiler/wasm-gc-lowering.cc index 79aa92f271ec..e935a83c47e9 100644 --- a/deps/v8/src/compiler/wasm-gc-lowering.cc +++ b/deps/v8/src/compiler/wasm-gc-lowering.cc @@ -476,7 +476,7 @@ Reduction WasmGCLowering::ReduceAssertNotNull(Node* node) { UpdateSourcePosition(gasm_.effect(), node); } else { static_assert(WasmStruct::kHeaderSize > kTaggedSize); - static_assert(WasmArray::kHeaderSize > kTaggedSize); + static_assert(WasmArray::HeaderSize(SharedFlag{false}) > kTaggedSize); static_assert(WasmInternalFunction::kHeaderSize > kTaggedSize); Node* trap_null = gasm_.LoadTrapOnNull( MachineType::Int32(), object, @@ -734,7 +734,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 +757,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 c5c4dd9160d2..19a5a278b285 100644 --- a/deps/v8/src/compiler/wasm-graph-assembler.cc +++ b/deps/v8/src/compiler/wasm-graph-assembler.cc @@ -495,12 +495,13 @@ Node* WasmGraphAssembler::FieldOffset(const wasm::StructType* type, } 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) { diff --git a/deps/v8/src/compiler/wasm-graph-assembler.h b/deps/v8/src/compiler/wasm-graph-assembler.h index f10e0205091c..38b69cac15fd 100644 --- a/deps/v8/src/compiler/wasm-graph-assembler.h +++ b/deps/v8/src/compiler/wasm-graph-assembler.h @@ -263,7 +263,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/d8/d8-posix.cc b/deps/v8/src/d8/d8-posix.cc index b8bc0ea2b8f2..c49c851449cc 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,7 +609,7 @@ void Shell::UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& info) { unsetenv(*var); } -base::OwnedVector<char> Shell::ReadCharsFromTcpPort(const char* name) { +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); @@ -688,25 +689,24 @@ base::OwnedVector<char> Shell::ReadCharsFromTcpPort(const char* name) { } // 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 {}; } 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-windows.cc b/deps/v8/src/d8/d8-windows.cc index b8958fc2da97..f9227431e6e3 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,7 +44,7 @@ void Shell::PreProcessUnicodeFilenameArg(char* argv[], int i) { void Shell::AddOSMethods(Isolate* isolate, Local<ObjectTemplate> os_templ) {} -base::OwnedVector<char> Shell::ReadCharsFromTcpPort(const char* name) { +base::UniqueArray<char> Shell::ReadCharsFromTcpPort(const char* name) { // TODO(leszeks): No reason this shouldn't exist on windows. return {}; } diff --git a/deps/v8/src/d8/d8.cc b/deps/v8/src/d8/d8.cc index 8d325f418e38..a089fe2c7463 100644 --- a/deps/v8/src/d8/d8.cc +++ b/deps/v8/src/d8/d8.cc @@ -54,6 +54,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 +159,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 +490,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 +1058,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 }; @@ -1519,11 +1536,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 +1677,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 +1734,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,7 +2363,7 @@ 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()); + base::UniqueArray<char> data = ReadChars(absolute_path.c_str()); if (data.data() == nullptr) { printf("Error reading '%s'\n", file_name); base::OS::ExitProcess(1); @@ -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) { @@ -3542,13 +3568,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()); @@ -4763,6 +4789,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 +4843,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 +4993,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 +5084,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. @@ -5248,7 +5343,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()) { @@ -5711,7 +5806,7 @@ V8_NOINLINE void FuzzerMonitor::UseOfUninitializedValue() { #endif } -base::OwnedVector<char> Shell::ReadChars(const char* name) { +base::UniqueArray<char> Shell::ReadChars(const char* name) { if (options.read_from_tcp_port >= 0) { return ReadCharsFromTcpPort(name); } @@ -5723,22 +5818,21 @@ base::OwnedVector<char> Shell::ReadChars(const char* name) { 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 {}; } } 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); + base::UniqueArray<char> data = ReadChars(name); if (data.data() == nullptr) { return MaybeLocal<PrimitiveArray>(); @@ -5774,7 +5868,7 @@ void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& info) { SafeUtf8Value filename(isolate, info[0]); if (!filename) return; - base::OwnedVector<char> data = ReadChars(*filename); + base::UniqueArray<char> data = ReadChars(*filename); if (data.data() == nullptr) { std::ostringstream error_msg; error_msg << "Error reading file \"" @@ -6104,6 +6198,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 +6258,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 +6296,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 +6340,6 @@ bool TryExecuteBundle(Isolate* isolate, const std::string& content, } } - bundle_module_files.clear(); return true; // Bundle handled successfully (even if execution failed) } @@ -6945,12 +7054,23 @@ bool FlagWithArgMatches(const char (&flag)[N], char** flag_value, int argc, 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 +7100,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,6 +7130,7 @@ 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; + disallow_developer_only_features = true; static constexpr char kFlagProcessingMode[] = "--flag-processing-mode=exit-on-error"; i::FlagList::SetFlagsFromString(kFlagProcessingMode, @@ -7016,6 +7145,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); @@ -7152,7 +7284,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])) { @@ -7223,41 +7361,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 = 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); + 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 = true; + } + }; + // Inspector security bugs must be shown through the embedder (i.e. Chrome, + // or content_shell). + handle_developer_only_d8_flag(options.enable_inspector); + // 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) { @@ -7304,13 +7468,6 @@ bool Shell::SetOptions(int argc, char* argv[]) { 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 +7477,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 +7507,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 +7575,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) { @@ -8166,6 +8331,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 +8362,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 +8428,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) { @@ -8313,6 +8491,12 @@ 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 @@ -8330,7 +8514,7 @@ 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 = + base::UniqueArray<char> trace_config_json_str = ReadChars(options.trace_config); if (trace_config_json_str.data() == nullptr) { printf("Failed to read trace config from '%s'\n", @@ -8462,6 +8646,11 @@ int Shell::Main(int argc, char* argv[]) { // Send result to parent (fuzzilli) and reset edge guards. if (fuzzilli_reprl) { int status = result << 8; + // 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( diff --git a/deps/v8/src/d8/d8.h b/deps/v8/src/d8/d8.h index eae46fa9d05c..8f49787b9219 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" @@ -459,6 +459,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 +513,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 +534,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 +546,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 +582,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. @@ -815,7 +819,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 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 +933,7 @@ class Shell : public i::AllStatic { static void SetWaitUntilDone(Isolate* isolate, bool value); - static base::OwnedVector<char> ReadCharsFromTcpPort(const char* name); + static 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 +1008,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 +1018,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-evaluate.cc b/deps/v8/src/debug/debug-evaluate.cc index 0ad559410946..46a06b4b4ab5 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); } @@ -905,12 +910,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..60ad0de1b2ba 100644 --- a/deps/v8/src/debug/debug-interface.cc +++ b/deps/v8/src/debug/debug-interface.cc @@ -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)); } @@ -1372,6 +1373,17 @@ 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(); +} + 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..9e4522f2353d 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,16 @@ class V8_NODISCARD DisableBreakScope { std::unique_ptr<i::DisableBreak> scope_; }; +class V8_NODISCARD SideEffectCheckScope { + public: + explicit SideEffectCheckScope(v8::Isolate* isolate); + ~SideEffectCheckScope(); + + 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..44788a2e743c 100644 --- a/deps/v8/src/debug/debug-property-iterator.cc +++ b/deps/v8/src/debug/debug-property-iterator.cc @@ -6,6 +6,7 @@ #include "src/api/api-inl.h" #include "src/base/flags.h" +#include "src/base/unique-array.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/keys.h" #include "src/objects/module-inl.h" @@ -133,8 +134,8 @@ 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); + auto property_message = base::UniqueArray<char>::NewForOverwrite(128); + auto name_buffer = base::UniqueArray<char>::NewForOverwrite(100); raw_name()->NameShortPrint(name_buffer.as_vector()); v8::base::SNPrintF(property_message.as_vector(), "Invalid result for property \"%s\"\n", 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..4cdc7117e71c 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) { @@ -284,10 +330,19 @@ bool ScopeIterator::NeedsContext() const { 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; + if (std::optional<DebugScriptScope> parent = current_scope().parent()) { + current_scope_index_ = parent->scope_index(); + return true; + } + if (std::optional<DebugScriptScope> outer = + FindEvalOuterScope(isolate_, script_)) { + script_ = + handle(Cast<Script>(script_->eval_from_shared()->script()), isolate_); + debug_scope_info_ = handle(*outer->info(), isolate_); + current_scope_index_ = outer->scope_index(); + return true; + } + return false; } void ScopeIterator::AdvanceOneContext() { @@ -306,7 +361,13 @@ void ScopeIterator::AdvanceScope() { AdvanceOneContext(); } - CHECK(AdvanceOneScope()); + if (!AdvanceOneScope()) { + // 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 +389,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 +484,7 @@ Handle<JSObject> ScopeIterator::ScopeObject(Mode mode) { } if (type == ScopeTypeWith) { DCHECK_EQ(Mode::ALL, mode); + DCHECK(HasContext()); return WithContextExtension(); } @@ -711,10 +757,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 +772,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 +797,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 +824,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 +870,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 +888,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 +898,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())); diff --git a/deps/v8/src/debug/debug-scopes.h b/deps/v8/src/debug/debug-scopes.h index a03b3ae42359..ddbca7cbdb86 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; @@ -116,6 +129,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 +143,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_); @@ -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..2e54633a36e0 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" @@ -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()); } @@ -924,15 +928,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 +945,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 +961,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> { @@ -1050,6 +1057,12 @@ DirectHandle<WasmValueObject> WasmValueObject::New( 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")); @@ -1062,6 +1075,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 +1098,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( + base::VectorOf(error).SubVector(0, len)); } break; } diff --git a/deps/v8/src/debug/debug.cc b/deps/v8/src/debug/debug.cc index def10a51cd7f..a0e316cf9a1f 100644 --- a/deps/v8/src/debug/debug.cc +++ b/deps/v8/src/debug/debug.cc @@ -505,6 +505,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 +593,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 +602,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 +612,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 +640,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(); @@ -789,8 +793,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 +845,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 +981,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 +1013,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 +1066,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 @@ -1207,7 +1228,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 +1305,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 +1395,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); @@ -2629,7 +2658,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 +2734,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 +2752,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 +2790,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 +2956,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_; } @@ -2937,24 +3001,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,6 +3449,25 @@ 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; 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..433eae97548d 100644 --- a/deps/v8/src/deoptimizer/deoptimizer.cc +++ b/deps/v8/src/deoptimizer/deoptimizer.cc @@ -9,6 +9,8 @@ #include "src/base/logging.h" #include "src/base/memory.h" #include "src/base/numerics/safe_conversions.h" +#include "src/base/unique-array.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 @@ -1340,25 +1346,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,16 +2065,18 @@ 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."); + "Fetching DebugBytecodeArray via SFI. This is safe because we verify " + "below that the DebugInfo's OriginalBytecodeArray matches the frame's " + "trusted BytecodeArray."); std::optional<Tagged<DebugInfo>> debug_info = translated_frame->raw_shared_info()->TryGetDebugInfo(isolate()); if (debug_info.has_value() && debug_info.value()->HasBreakInfo()) { + // Ensure the DebugInfo belongs to this frame's trusted BytecodeArray in + // case the untrusted SFI reference in the DeoptimizationLiteralArray was + // swapped. + SBXCHECK_EQ(debug_info.value()->OriginalBytecodeArray(isolate()), + bytecode_array); 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); } } @@ -3086,7 +3079,7 @@ 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); + auto str = base::UniqueArray<char>::NewForOverwrite(128); if (verbose_tracing_enabled()) { if (BuiltinContinuationModeIsJavaScript(mode) && code == kJavaScriptCallArgCountRegister.code()) { 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..735755940d68 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: @@ -1211,6 +1260,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 +1826,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 +2204,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 +2288,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 +2299,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,19 +2311,25 @@ 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 { @@ -2290,6 +2385,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: diff --git a/deps/v8/src/deoptimizer/translated-state.h b/deps/v8/src/deoptimizer/translated-state.h index 0032eb1f7712..ee52cf3c62f2 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; @@ -553,6 +555,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..1eb80ad29661 100644 --- a/deps/v8/src/diagnostics/arm64/disasm-arm64.cc +++ b/deps/v8/src/diagnostics/arm64/disasm-arm64.cc @@ -4718,7 +4718,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 +4734,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..8c2bbc1f7b30 100644 --- a/deps/v8/src/diagnostics/code-tracer.h +++ b/deps/v8/src/diagnostics/code-tracer.h @@ -5,6 +5,7 @@ #ifndef V8_DIAGNOSTICS_CODE_TRACER_H_ #define V8_DIAGNOSTICS_CODE_TRACER_H_ +#include <array> #include <optional> #include "src/base/platform/platform.h" @@ -37,7 +38,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 +80,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 +106,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..628f6809ef3a 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; } @@ -301,7 +302,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 +333,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 +341,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 +353,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 +363,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 { @@ -425,7 +427,7 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, << prev_pc - begin << " "; // 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..bf300f5351a5 100644 --- a/deps/v8/src/diagnostics/objects-debug.cc +++ b/deps/v8/src/diagnostics/objects-debug.cc @@ -508,9 +508,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 +626,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)); @@ -797,7 +796,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 +815,8 @@ 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) && (IsWasmStruct(custom_descriptor()) || + v8_flags.wasm_merged_descriptors)) { CHECK_GT(wasm_type_info()->supertypes_length(), subtyping_depth); CHECK_EQ(immediate_supertype_map(), wasm_type_info()->supertypes(subtyping_depth)); @@ -1125,8 +1126,8 @@ 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 = @@ -1871,6 +1872,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)); @@ -2709,10 +2714,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 +2756,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); @@ -3302,6 +3307,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() + ->byte_length_address())); + } } void WasmDispatchTable::WasmDispatchTableVerify(Isolate* isolate) { @@ -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..575bf5e4d4da 100644 --- a/deps/v8/src/diagnostics/objects-printer.cc +++ b/deps/v8/src/diagnostics/objects-printer.cc @@ -9,6 +9,7 @@ #include "include/v8-internal.h" #include "src/api/api-arguments.h" #include "src/base/logging.h" +#include "src/base/unique-array.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" #include "src/diagnostics/disasm.h" @@ -1786,7 +1787,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 +1813,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,7 +2313,7 @@ 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); + auto buf = base::UniqueArray<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, @@ -2814,7 +2816,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; @@ -3316,7 +3324,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 +3472,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 +3482,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 +3680,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 +3694,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(); @@ -4548,6 +4573,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 +4725,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() << "]>"; @@ -4768,7 +4802,7 @@ 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); #else constexpr bool is_wasm_map = false; #endif // V8_ENABLE_WEBASSEMBLY diff --git a/deps/v8/src/diagnostics/perf-jit.cc b/deps/v8/src/diagnostics/perf-jit.cc index 59b34a87746c..b78dd2e6572e 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,7 +141,7 @@ 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); + auto perf_dump_name = base::UniqueArray<char>::NewForOverwrite(bufferSize); int size = SNPrintF(perf_dump_name.as_vector(), kFilenameFormatString, v8_flags.perf_prof_path.value(), process_id_); CHECK_NE(size, -1); 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..96564808b1db 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,7 @@ 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_w() const { return (evex_byte2_ & 0x80) != 0; } int evex_pp() const { return evex_byte2_ & 0x3; } @@ -656,7 +658,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 +1079,21 @@ int DisassemblerX64::AVXVectorInstruction(uint8_t* data) { if (evex_w()) synth_rex |= 0x08; setRex(synth_rex); } + if (is_evex() && evex_map5()) { + // Decode the unmasked, non-broadcast XMM/YMM forms emitted by vaddph. + // Require EVEX.z, L', b and aaa to be zero; L and V' may be set. + if (evex_pp_none() && !evex_w() && opcode == 0x58 && + (evex_byte3_ & 0xd7) == 0) { + int mod, regop, rm; + get_modrm(*current, &mod, ®op, &rm); + AppendToBuffer("vaddph %s,%s,", 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); @@ -3565,7 +3583,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 +3619,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 +3674,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 +3687,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..8f5c7192394e 100644 --- a/deps/v8/src/dumpling/object-dumping.cc +++ b/deps/v8/src/dumpling/object-dumping.cc @@ -8,6 +8,7 @@ #include <iostream> #include <vector> +#include "src/base/unique-array.h" #include "src/objects/dictionary-inl.h" #include "src/objects/instance-type.h" #include "src/objects/object-conversions-inl.h" @@ -124,7 +125,7 @@ void JSObjectFuzzingPrintInternalIndexRange(Tagged<JSObject> obj, if (IsString(*key_name)) { FuzzingStringShortPrint(Cast<String>(*key_name), accumulator); } else { - auto name_buffer = base::OwnedVector<char>::NewForOverwrite(100); + auto name_buffer = base::UniqueArray<char>::NewForOverwrite(100); key_name->NameShortPrint(name_buffer.as_vector()); PrintSanitizedCString(name_buffer.begin(), accumulator); } 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-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 51055f12e0cc..e59a2ffd1d5b 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" @@ -161,7 +162,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()) {} @@ -507,12 +516,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 +894,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 +1836,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. @@ -3580,6 +3582,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); @@ -3740,9 +3770,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) { @@ -3976,6 +4015,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..1200914b0a83 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 { @@ -1425,6 +1427,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 +1436,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 +1811,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 +1986,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..33056e365eea 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) \ 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..e72b8f89a33f 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -1409,7 +1409,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 +1591,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 @@ -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(); } @@ -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 @@ -6636,29 +6642,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 +7252,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 +8169,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..21713372ba77 100644 --- a/deps/v8/src/execution/isolate.h +++ b/deps/v8/src/execution/isolate.h @@ -501,6 +501,8 @@ 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) \ @@ -1700,12 +1702,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, @@ -2539,6 +2542,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( 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..e5f9140bf2f4 100644 --- a/deps/v8/src/execution/messages.cc +++ b/deps/v8/src/execution/messages.cc @@ -839,6 +839,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); @@ -1151,6 +1158,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 +1211,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..5f332658c4f9 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" @@ -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); @@ -9443,8 +9489,7 @@ void Simulator::InstructionDecode(Instruction* instr) { 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); + new_stack.as_vector().SubVectorFrom(new_ssp).OverwriteWith( + shadow_stack_.as_vector()); + 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; } 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/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/flags/feature-flags.h b/deps/v8/src/flags/feature-flags.h index 5e9a1643f1ca..737f8306e462 100644 --- a/deps/v8/src/flags/feature-flags.h +++ b/deps/v8/src/flags/feature-flags.h @@ -84,10 +84,6 @@ "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 +115,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 +126,10 @@ #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") \ + \ /* Reference-Typed Strings Proposal. */ \ /* https://github.com/WebAssembly/stringref */ \ /* V8 side owner: jkummerow */ \ @@ -149,7 +144,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, diff --git a/deps/v8/src/flags/flag-definitions.h b/deps/v8/src/flags/flag-definitions.h index 528cf0e9c059..a7ea6f8178a5 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 @@ -351,6 +407,7 @@ 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") #endif #ifdef V8_ENABLE_DOUBLE_CONST_STORE_CHECK @@ -501,7 +558,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 +612,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, @@ -914,6 +974,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 +993,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) @@ -1473,6 +1539,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 +1799,8 @@ 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_DEVELOPER_FLAG(print_turbolev_frontend, "print Turbolev frontend (Maglev graphs)") @@ -1744,6 +1814,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 @@ -1979,8 +2050,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 +2089,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 +2129,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 +2158,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 +2200,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( @@ -2155,10 +2224,10 @@ DEFINE_DEBUG_BOOL( "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") @@ -2400,11 +2469,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 +2490,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 +2501,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) @@ -2679,18 +2746,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 +2875,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 +2958,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 +3113,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 +3125,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, @@ -3277,8 +3345,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 +3362,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 +3374,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 +3407,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, @@ -3412,6 +3482,9 @@ DEFINE_BOOL(verify_snapshot_checksum, DEBUG_BOOL, "Verify snapshot checksums when deserializing snapshots. Enable " "checksum creation and verification for code caches. Enabled by " "default in debug builds and once per process for Android.") +DEFINE_BOOL( + code_cache_source_hash_sha256, false, + "Hash code cache source string with SHA256 instead of string length") DEFINE_DEVELOPER_FLAG(profile_deserialization, "Print the time it takes to deserialize the snapshot.") DEFINE_DEVELOPER_FLAG(trace_deserialization, @@ -3420,6 +3493,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 +3524,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 +3752,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 +3923,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 // @@ -4301,96 +4372,53 @@ 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) // 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_IF(turbofan && !turbolev, array_destructure_bytecode) // 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 +4430,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 +4460,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 +4532,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.cc b/deps/v8/src/flags/flags.cc index 3a87e4c7e619..4d106983039a 100644 --- a/deps/v8/src/flags/flags.cc +++ b/deps/v8/src/flags/flags.cc @@ -24,6 +24,7 @@ #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,12 +159,6 @@ 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, @@ -172,8 +167,7 @@ bool Flag::CheckFlagChange(SetBy new_set_by, bool change_flag, (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) { @@ -346,11 +340,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 +392,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(); @@ -593,6 +554,9 @@ 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 (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + modified_args_as_string << "x64-stack-16"; + } if (base::FPU::GetFlushDenormals()) { modified_args_as_string << "flush-denormals"; } @@ -965,7 +929,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 +1150,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 +1205,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 +1256,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 +1330,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 +1393,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 +1441,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 +1453,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 +1475,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/fuzzilli/cov.cc b/deps/v8/src/fuzzilli/cov.cc index 1dc9ba72d25c..317fd36872b7 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,19 @@ #include <sys/wait.h> #include <unistd.h> +#include <algorithm> +#include <iterator> + #include "src/base/platform/memory.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 +42,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 +100,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 +127,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 +160,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 diff --git a/deps/v8/src/fuzzilli/cov.h b/deps/v8/src/fuzzilli/cov.h index 74a59ceb3f06..6b7e7acae93a 100644 --- a/deps/v8/src/fuzzilli/cov.h +++ b/deps/v8/src/fuzzilli/cov.h @@ -27,6 +27,19 @@ 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(); 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/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/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/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..04b0ef736e3c 100644 --- a/deps/v8/src/heap/factory-base.h +++ b/deps/v8/src/heap/factory-base.h @@ -98,6 +98,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 +134,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(); @@ -381,9 +381,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 +403,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 +435,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 +463,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..51e8fd30d4c0 100644 --- a/deps/v8/src/heap/factory.cc +++ b/deps/v8/src/heap/factory.cc @@ -5,14 +5,15 @@ #include "src/heap/factory.h" #include <algorithm> // For copy +#include <bit> #include <memory> // For shared_ptr<> #include <optional> #include <string> #include <utility> // For move #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" @@ -41,13 +42,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" @@ -81,7 +83,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 +312,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 +333,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 +381,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 +400,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 +477,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 +679,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 +732,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> @@ -969,18 +935,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,7 +965,7 @@ 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()); @@ -1034,7 +1000,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)), @@ -1074,14 +1040,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 +1068,7 @@ MaybeDirectHandle<String> Factory::NewStringFromUtf16( static_assert(WasmArray::MaxLength(sizeof(uint16_t)) <= kMaxInt); uint32_t length = end - start; - base::OwnedVector<uint16_t> private_copy; + base::UniqueArray<uint16_t> private_copy; if (config.source_shared()) { private_copy = CopyCodeUnits( reinterpret_cast<const base::Atomic16*>(array->ElementAddress(start)), @@ -1176,7 +1144,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,24 +1168,33 @@ 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; @@ -1883,10 +1860,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() { @@ -1907,6 +1882,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 = @@ -1934,13 +1913,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 +1939,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 +1954,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 +1980,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 +2096,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 +2160,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 +2201,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 +2318,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 +2542,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, @@ -3020,9 +2931,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()) { @@ -3282,8 +3192,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; } @@ -3677,7 +3588,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 +3617,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; @@ -4580,23 +4491,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 +4505,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 +4516,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, @@ -4927,8 +4810,8 @@ DirectHandle<String> Factory::ToPrimitiveHintString(ToPrimitiveHint hint) { DirectHandle<Map> Factory::CreateSloppyFunctionMap( 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? + // TODO(https://crbug.com/414525205): Merge sloppy and strict function maps + // now that legacy .arguments and .caller are no longer own properties. bool has_prototype = IsFunctionModeWithPrototype(function_mode); InstanceType instance_type; int header_size; @@ -4940,9 +4823,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,18 +4884,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 = @@ -5230,12 +5098,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() { diff --git a/deps/v8/src/heap/factory.h b/deps/v8/src/heap/factory.h index ad5f09a08d98..267bf80a3e16 100644 --- a/deps/v8/src/heap/factory.h +++ b/deps/v8/src/heap/factory.h @@ -142,6 +142,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,6 +253,11 @@ 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(); @@ -528,6 +535,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 +769,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 +783,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 @@ -1465,7 +1470,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 +1503,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/heap-inl.h b/deps/v8/src/heap/heap-inl.h index 335a96f3c70c..b2789efbb466 100644 --- a/deps/v8/src/heap/heap-inl.h +++ b/deps/v8/src/heap/heap-inl.h @@ -294,9 +294,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) { 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.h b/deps/v8/src/heap/heap-visitor.h index 9830a6b8b22e..05be54b3c774 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) \ diff --git a/deps/v8/src/heap/heap-write-barrier.h b/deps/v8/src/heap/heap-write-barrier.h index 1928d0d64d96..7e9c6a845093 100644 --- a/deps/v8/src/heap/heap-write-barrier.h +++ b/deps/v8/src/heap/heap-write-barrier.h @@ -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 && diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index 420c631486d5..b97cb84a8fb0 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" @@ -1937,19 +1937,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 +2634,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; @@ -3659,13 +3657,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(); } } @@ -4903,9 +4903,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 +5692,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 +6063,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)); @@ -6363,7 +6362,6 @@ void Heap::TearDown() { ephemeron_remembered_set_.reset(); if (memory_reducer_ != nullptr) { - memory_reducer_->TearDown(); memory_reducer_.reset(); } @@ -6515,13 +6513,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 +6542,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; } @@ -6827,6 +6831,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); } diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h index 39e2304d2a2e..49d824e5dc03 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, @@ -1114,7 +1117,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 +1134,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 { @@ -1209,12 +1217,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 +1933,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 +1969,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 +2003,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 +2285,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/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc index 6712456d29aa..b52c51f5041c 100644 --- a/deps/v8/src/heap/mark-compact.cc +++ b/deps/v8/src/heap/mark-compact.cc @@ -1611,7 +1611,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); } diff --git a/deps/v8/src/heap/memory-pool.cc b/deps/v8/src/heap/memory-pool.cc index aa8cc8050983..55cc6c80d6b0 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 { @@ -474,9 +469,8 @@ class MemoryPool::ReleasePooledChunksTask final : public CancelableTask { IsolateGroup::current()->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-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..e5124e07705c 100644 --- a/deps/v8/src/heap/object-stats.cc +++ b/deps/v8/src/heap/object-stats.cc @@ -1029,7 +1029,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..8063fec9ff98 100644 --- a/deps/v8/src/heap/read-only-heap.cc +++ b/deps/v8/src/heap/read-only-heap.cc @@ -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 { @@ -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_); diff --git a/deps/v8/src/heap/read-only-heap.h b/deps/v8/src/heap/read-only-heap.h index 329d0abeecb4..1dae2f0362e1 100644 --- a/deps/v8/src/heap/read-only-heap.h +++ b/deps/v8/src/heap/read-only-heap.h @@ -83,6 +83,11 @@ class ReadOnlyHeap final { 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; diff --git a/deps/v8/src/heap/read-only-promotion.cc b/deps/v8/src/heap/read-only-promotion.cc index 35164f892ce2..aba9278f07b8 100644 --- a/deps/v8/src/heap/read-only-promotion.cc +++ b/deps/v8/src/heap/read-only-promotion.cc @@ -458,9 +458,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); diff --git a/deps/v8/src/heap/scavenger.cc b/deps/v8/src/heap/scavenger.cc index 64d996f2b252..de706edff12e 100644 --- a/deps/v8/src/heap/scavenger.cc +++ b/deps/v8/src/heap/scavenger.cc @@ -1989,9 +1989,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..3c42a0d99a87 100644 --- a/deps/v8/src/heap/setup-heap-internal.cc +++ b/deps/v8/src/heap/setup-heap-internal.cc @@ -23,7 +23,7 @@ #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" @@ -460,21 +460,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 +576,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 +683,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 +739,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, @@ -1130,18 +1132,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. { @@ -1181,24 +1181,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()); diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc index c262e24e75fe..16a5f4cc479a 100644 --- a/deps/v8/src/ic/accessor-assembler.cc +++ b/deps/v8/src/ic/accessor-assembler.cc @@ -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); @@ -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); @@ -1962,9 +1965,13 @@ void AccessorAssembler::OverwriteExistingFastDataProperty( 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); + // The map store must follow the value write and use release semantics + // so background threads (e.g. concurrent compiler) see a consistent + // initialized state upon observing the HeapNumber map. + StoreMapReleaseNoWriteBarrier(heap_number, RootIndex::kHeapNumberMap); } Goto(&done); } @@ -2026,10 +2033,14 @@ 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); + // The map store must follow the value write and use release semantics + // so background threads (e.g. concurrent compiler) see a consistent + // initialized state upon observing the HeapNumber map. + StoreMapReleaseNoWriteBarrier(heap_number, RootIndex::kHeapNumberMap); Goto(&done); } BIND(&tagged_rep); @@ -2356,6 +2367,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 +2395,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 +2405,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 +2415,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 +2432,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,8 +2524,18 @@ 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(); + 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; + } if (store_value_as_double) { double_value = Float64SilenceNaN(*double_value); @@ -2540,7 +2562,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); @@ -2572,6 +2599,13 @@ void AccessorAssembler::HandleStoreFieldAndReturn( // Do the store. if (store_value_as_double) { StoreObjectFieldNoWriteBarrier(property_storage, offset, *double_value); + if (maybe_initializing_store) { + // The map store must follow the value write and use release semantics so + // background threads (e.g. concurrent compiler) see a consistent + // initialized state upon observing the HeapNumber map. + StoreMapReleaseNoWriteBarrier(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/ic.cc b/deps/v8/src/ic/ic.cc index 7ae7d8f99d02..857564cdd01e 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" @@ -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. @@ -850,10 +851,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. @@ -1760,17 +1761,6 @@ KeyedAccessLoadMode GetUpdatedLoadModeForMap(Isolate* isolate, Handle<Object> KeyedLoadIC::LoadElementHandler( DirectHandle<Map> receiver_map, KeyedAccessLoadMode new_load_mode, MaybeDirectHandle<Map> maybe_transition_target) { - // Has a getter interceptor, or is any has and has a query interceptor. - if (receiver_map->has_indexed_interceptor() && - (receiver_map->GetIndexedInterceptor()->has_getter() || - (IsAnyHas() && receiver_map->GetIndexedInterceptor()->has_query())) && - !receiver_map->GetIndexedInterceptor()->non_masking()) { - // TODO(jgruber): Update counter name. - TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub); - return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIndexedInterceptorIC) - : BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC); - } - InstanceType instance_type = receiver_map->instance_type(); if (instance_type < FIRST_NONSTRING_TYPE) { TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH); @@ -1784,6 +1774,23 @@ Handle<Object> KeyedLoadIC::LoadElementHandler( if (instance_type == JS_PROXY_TYPE) { return LoadHandler::LoadProxy(isolate()); } + if (receiver_map->is_access_check_needed()) { + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub); + return LoadHandler::LoadSlow(isolate()); + } + + // Has a getter interceptor, or is any has and has a query interceptor. + if (receiver_map->has_indexed_interceptor() && + (receiver_map->GetIndexedInterceptor()->has_getter() || + (IsAnyHas() && receiver_map->GetIndexedInterceptor()->has_query())) && + !receiver_map->GetIndexedInterceptor()->non_masking()) { + DCHECK(!receiver_map->is_access_check_needed()); + // TODO(jgruber): Update counter name. + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub); + return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIndexedInterceptorIC) + : BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC); + } + #if V8_ENABLE_WEBASSEMBLY if (InstanceTypeChecker::IsWasmObject(instance_type)) { // TODO(jgruber): Update counter name. @@ -2870,7 +2877,8 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, Handle<Object> KeyedStoreIC::StoreElementHandler( DirectHandle<Map> receiver_map, KeyedAccessStoreMode store_mode, MaybeDirectHandle<UnionOf<Smi, Cell>> prev_validity_cell) { - if (!IsJSObjectMap(*receiver_map)) { + if (!IsJSObjectMap(*receiver_map) || receiver_map->is_access_check_needed() || + 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. if (IsJSProxyMap(*receiver_map) && !IsDefineKeyedOwnIC()) { @@ -2878,7 +2886,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 @@ -3142,7 +3150,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. @@ -3306,8 +3314,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); { diff --git a/deps/v8/src/init/bootstrapper.cc b/deps/v8/src/init/bootstrapper.cc index 7299c9561a94..e4be96cbdea5 100644 --- a/deps/v8/src/init/bootstrapper.cc +++ b/deps/v8/src/init/bootstrapper.cc @@ -106,7 +106,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 +120,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 +131,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()); @@ -221,9 +221,6 @@ class Genesis { 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 @@ -904,12 +901,6 @@ void Genesis::CreateStrictModeFunctionMaps(DirectHandle<JSFunction> empty) { // 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) { @@ -1278,15 +1269,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 +1302,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 @@ -2343,7 +2311,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,7 +2318,6 @@ 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. { @@ -5337,7 +5303,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)); 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/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..ad505f6494c0 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; diff --git a/deps/v8/src/inspector/injected-script.cc b/deps/v8/src/inspector/injected-script.cc index 7dc58dc2813e..6999a35f89c6 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,29 @@ 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 && (m_wrapOptions->mode == WrapMode::kJson || + m_wrapOptions->mode == WrapMode::kDeep)) { + 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; @@ -842,11 +861,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) { @@ -977,33 +991,42 @@ 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); - } - } else { - if (tryCatch.HasTerminated() || !tryCatch.CanContinue()) { - return Response::ServerError("Execution was terminated"); + Response response = Response::Success(); + { + std::optional<v8::debug::SideEffectCheckScope> sideEffectCheckScope; + if (throwOnSideEffect && (wrapOptions.mode == WrapMode::kJson || + wrapOptions.mode == WrapMode::kDeep)) { + sideEffectCheckScope.emplace(m_context->isolate()); + } + response = wrapObject(resultValue, objectGroup, wrapOptions, result); } - v8::Local<v8::Value> exception = tryCatch.Exception(); - if (!throwOnSideEffect) { - m_context->inspector()->client()->dispatchError( - m_context->context(), tryCatch.Message(), exception); + if (response.IsSuccess()) { + if (objectGroup == "console") { + m_lastEvaluationResult.Reset(m_context->isolate(), resultValue); + m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel); + } + return Response::Success(); } - 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 (!throwOnSideEffect || !tryCatch.HasCaught()) 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(); } diff --git a/deps/v8/src/inspector/injected-script.h b/deps/v8/src/inspector/injected-script.h index d72d77daacae..faf984d37722 100644 --- a/deps/v8/src/inspector/injected-script.h +++ b/deps/v8/src/inspector/injected-script.h @@ -149,7 +149,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(); 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..5a8c91cf7b41 100644 --- a/deps/v8/src/inspector/v8-console-message.cc +++ b/deps/v8/src/inspector/v8-console-message.cc @@ -606,6 +606,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..c8058ae600af 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 = @@ -341,10 +350,14 @@ void V8Console::Count(const v8::debug::ConsoleCallArguments& info, 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)); + // 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); } @@ -356,8 +369,11 @@ void V8Console::CountReset(const v8::debug::ConsoleCallArguments& info, ConsoleHelper helper(info, consoleContext, m_inspector); String16 label = toProtocolString(m_inspector->isolate(), helper.firstArgToString()); - if (!helper.consoleMessageStorage()->countReset(helper.contextId(), - consoleContext.id(), label)) { + // 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 +394,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()) return; m_inspector->debugger()->breakProgramOnAssert(helper.groupId()); } @@ -419,8 +436,11 @@ void V8Console::Time(const v8::debug::ConsoleCallArguments& info, ConsoleHelper helper(info, consoleContext, m_inspector); v8::Local<v8::String> label = helper.firstArgToString(); 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"); @@ -435,8 +455,12 @@ void V8Console::TimeLog(const v8::debug::ConsoleCallArguments& info, ConsoleHelper helper(info, consoleContext, m_inspector); v8::Local<v8::String> label = helper.firstArgToString(); 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, @@ -454,8 +478,12 @@ void V8Console::TimeEnd(const v8::debug::ConsoleCallArguments& info, ConsoleHelper helper(info, consoleContext, m_inspector); v8::Local<v8::String> label = helper.firstArgToString(); 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, @@ -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); diff --git a/deps/v8/src/inspector/v8-debugger-agent-impl.cc b/deps/v8/src/inspector/v8-debugger-agent-impl.cc index 1c7507ddda33..eb5621c45ed5 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,7 @@ Response V8DebuggerAgentImpl::pause() { Response V8DebuggerAgentImpl::resume(std::optional<bool> terminateOnResume) { if (!isPaused()) return Response::ServerError(kDebuggerNotPaused); + m_skipList.clear(); m_session->releaseObjectGroup(kBacktraceObjectGroup); m_instrumentationFinished = true; @@ -1564,18 +1588,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 +1620,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 +1634,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(); @@ -2250,6 +2285,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 +2465,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 +2504,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 +2537,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..553064f77a06 100644 --- a/deps/v8/src/inspector/v8-debugger.cc +++ b/deps/v8/src/inspector/v8-debugger.cc @@ -316,11 +316,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); } @@ -735,6 +736,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 +868,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-inspector-session-impl.cc b/deps/v8/src/inspector/v8-inspector-session-impl.cc index 9ec526f64e96..a894e3789a1a 100644 --- a/deps/v8/src/inspector/v8-inspector-session-impl.cc +++ b/deps/v8/src/inspector/v8-inspector-session-impl.cc @@ -515,7 +515,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-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/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.cc b/deps/v8/src/interpreter/bytecode-array-iterator.cc index 0d2edcbf8c35..285477142f02 100644 --- a/deps/v8/src/interpreter/bytecode-array-iterator.cc +++ b/deps/v8/src/interpreter/bytecode-array-iterator.cc @@ -374,6 +374,25 @@ int BytecodeArrayIterator::GetJumpTargetOffset() const { return GetAbsoluteOffset(GetRelativeJumpTargetOffset()); } +std::pair<int, int> BytecodeArrayIterator::GetNextJumpOffsets() { + DCHECK(Bytecodes::IsJump(next_bytecode())); + DisallowGarbageCollection no_gc; + uint8_t* saved_cursor = cursor_; + Bytecode saved_bytecode = current_bytecode_; + OperandScale saved_scale = operand_scale_; + int saved_prefix_size = prefix_size_; + + Advance(); + std::pair<int, int> offsets{GetJumpTargetOffset(), next_offset()}; + + // Restore the iterator state. + cursor_ = saved_cursor; + current_bytecode_ = saved_bytecode; + operand_scale_ = saved_scale; + prefix_size_ = saved_prefix_size; + return offsets; +} + JumpTableTargetOffsets BytecodeArrayIterator::GetJumpTableTargetOffsets() const { uint32_t table_start, table_size; diff --git a/deps/v8/src/interpreter/bytecode-array-iterator.h b/deps/v8/src/interpreter/bytecode-array-iterator.h index 9825ed7ffdb4..2ed0bbb72b4a 100644 --- a/deps/v8/src/interpreter/bytecode-array-iterator.h +++ b/deps/v8/src/interpreter/bytecode-array-iterator.h @@ -189,6 +189,10 @@ class V8_EXPORT_PRIVATE BytecodeArrayIterator { // It is an error to call this method if the bytecode is not for a jump or // conditional jump. int GetJumpTargetOffset() const; + // Returns {target_offset, fallthrough_offset} for the following jump in O(1) + // without changing the cursor position. It is an error to call this method + // if the following bytecode is not a jump. + std::pair<int, int> GetNextJumpOffsets(); // Returns an iterator over the absolute offsets of the targets of the current // switch bytecode's jump table. It is an error to call this method if the // bytecode is not a switch. 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-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index b6b593263013..87c3091a43a5 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. @@ -6124,6 +6126,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 +6294,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); 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/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-generator.cc b/deps/v8/src/interpreter/interpreter-generator.cc index 73eee42791ae..c06297a09355 100644 --- a/deps/v8/src/interpreter/interpreter-generator.cc +++ b/deps/v8/src/interpreter/interpreter-generator.cc @@ -3343,14 +3343,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 +3374,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/json/json-parser.cc b/deps/v8/src/json/json-parser.cc index 9fb474514c55..3f76c66efd32 100644 --- a/deps/v8/src/json/json-parser.cc +++ b/deps/v8/src/json/json-parser.cc @@ -885,11 +885,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 +1460,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 +1549,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 +1557,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 +1581,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 +1617,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 +1633,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 +1658,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 +1671,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 +1681,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 +1708,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 +1727,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 +1746,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 +2076,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::FixedTag<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 +2123,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..14e72956becf 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(); diff --git a/deps/v8/src/json/json-stringifier.cc b/deps/v8/src/json/json-stringifier.cc index c7f692aed1f8..9c1092d89209 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]); @@ -1845,13 +1859,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 +1984,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 +2262,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 +2290,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 +2306,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 +2330,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 +2409,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 +2424,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 +2534,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 +2552,7 @@ FastJsonStringifier<Char>::SerializeObjectKey( String::DoesNotContainEscapeCharacters(obj)); result = sizeof(StringChar) == 1 && !needs_escaping ? FastJsonStringifierObjectKeyResult::kSuccess - : FastJsonStringifierObjectKeyResult::kSlow; + : FastJsonStringifierObjectKeyResult::kSlowKey; } AppendCharacterUnchecked('"'); AppendCharacterUnchecked(':'); @@ -2547,7 +2576,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 +2912,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) { @@ -3060,7 +3095,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; @@ -3132,6 +3169,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 +3383,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 +3403,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 +3461,23 @@ 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))) break; } return AppendStringScalar(chars, length, i, uncopied_src_index, no_gc); } 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 +3487,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::FixedTag<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 +3535,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 +3570,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 +3589,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..5302919ede29 100644 --- a/deps/v8/src/libsampler/sampler.cc +++ b/deps/v8/src/libsampler/sampler.cc @@ -68,6 +68,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" @@ -579,6 +580,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..54471411cd3d 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). */ \ @@ -307,11 +329,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..1f988567023b 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,7 +411,7 @@ 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_); @@ -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_ = diff --git a/deps/v8/src/logging/runtime-call-stats.h b/deps/v8/src/logging/runtime-call-stats.h index 1ab0baba1b4b..44dca375a585 100644 --- a/deps/v8/src/logging/runtime-call-stats.h +++ b/deps/v8/src/logging/runtime-call-stats.h @@ -381,8 +381,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..e7abef1cb6f9 100644 --- a/deps/v8/src/maglev/arm64/maglev-assembler-arm64-inl.h +++ b/deps/v8/src/maglev/arm64/maglev-assembler-arm64-inl.h @@ -162,6 +162,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; 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.h b/deps/v8/src/maglev/maglev-assembler.h index ab934b1ecba5..fb8a1abb7b40 100644 --- a/deps/v8/src/maglev/maglev-assembler.h +++ b/deps/v8/src/maglev/maglev-assembler.h @@ -120,6 +120,24 @@ 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) + 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; +#else + UNREACHABLE(); +#endif + } + static constexpr DoubleRegList GetAllocatableDoubleRegisters() { return kAllocatableDoubleRegisters; } 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..f03cac1ad145 100644 --- a/deps/v8/src/maglev/maglev-compiler.cc +++ b/deps/v8/src/maglev/maglev-compiler.cc @@ -299,6 +299,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; } diff --git a/deps/v8/src/maglev/maglev-concurrent-dispatcher.cc b/deps/v8/src/maglev/maglev-concurrent-dispatcher.cc index 45bcecaa63ad..106f2e449e75 100644 --- a/deps/v8/src/maglev/maglev-concurrent-dispatcher.cc +++ b/deps/v8/src/maglev/maglev-concurrent-dispatcher.cc @@ -179,28 +179,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 { @@ -320,7 +318,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 b0bca8d41281..e62bf0d78234 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( @@ -2635,47 +2639,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 +2658,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 +2698,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 +2741,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 +2753,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 +2818,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 +2941,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 +2952,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 +2963,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 +2983,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 +3001,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,11 +3183,14 @@ 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( @@ -3302,9 +3275,12 @@ 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( @@ -3999,9 +3975,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 +4057,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 +4079,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 +4093,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 +4118,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})); @@ -4537,8 +4530,18 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildStoreField( {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_))); + RETURN_IF_ABORT(AddNewNode<StoreFloat64>( + {heap_number, value}, + static_cast<int>(offsetof(HeapNumber, value_)))); + if (IsDefiningStore(access_mode)) { + // The map store must follow the value write so background threads + // (e.g. concurrent compiler) see a consistent initialized state upon + // observing the HeapNumber map. + RETURN_IF_ABORT(reducer_.BuildStoreMap(heap_number, + broker()->heap_number_map(), + StoreMap::Kind::kTransitioning)); + } + return ReduceResult::Done(); } } @@ -6442,11 +6445,46 @@ 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_IF_ABORT(BuildCallRuntime(Runtime::kCheckProxyGetSetTrapResult, + {argument_name, proxy_target, result, + GetSmiConstant(JSProxy::kGet)})); + return result; + }); + } - return BuildGenericCall(actual_trap, Call::TargetType::kJSFunction, args, - feedback_source); + return result; } template <typename GenericAccessFunc> @@ -6738,9 +6776,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 +6895,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 +6911,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 +6922,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 +6946,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 +6963,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() { @@ -7799,7 +7824,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); @@ -9110,16 +9135,21 @@ MaglevGraphBuilder::BuildJSArrayBuiltinMapSwitchOnElementsKind( sub_graph.GotoOrTrim(&*object_case); sub_graph.Bind(&*object_case); } - any_successful |= (!build_kind_specific(kind).IsDoneWithAbort()); + ReduceResult result = build_kind_specific(kind); if (IsSmiElementsKind(kind) && make_smi_fallthrough_to_object) { // After building the SMI specific parts (see build_kind_specific call // above), jump to the beginning of the case for the object elements // kind. DCHECK(object_case.has_value()); sub_graph.GotoOrTrim(&*object_case); + + // Whether the Smi case is successful depends on whether the object case + // is successful, so don't update any_successful here. } else { DCHECK(do_return.has_value()); sub_graph.GotoOrTrim(&*do_return); + + any_successful |= !result.IsDoneWithAbort(); } sub_graph.Bind(&check_next_map); } else { @@ -11622,11 +11652,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, @@ -11941,31 +11966,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) { @@ -13985,10 +14034,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)); } @@ -14366,12 +14420,14 @@ 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, pretenured, + compilation_unit_->specialization_context(), GetCurrentScopeInfo())); } } @@ -16415,30 +16471,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_); @@ -16553,6 +16593,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(); @@ -16971,11 +17012,11 @@ void MaglevGraphBuilder::ProcessMergePointPredecessors( ResetBuilderCachedState(); if (merge_state.is_loop()) { - DCHECK_EQ(merge_state.predecessors_so_far(), - merge_state.predecessor_count() - 1); + CHECK_EQ(merge_state.predecessors_so_far(), + merge_state.predecessor_count() - 1); } else { - DCHECK_EQ(merge_state.predecessors_so_far(), - merge_state.predecessor_count()); + CHECK_EQ(merge_state.predecessors_so_far(), + merge_state.predecessor_count()); } if (merge_state.predecessor_count() == 1) { diff --git a/deps/v8/src/maglev/maglev-graph-builder.h b/deps/v8/src/maglev/maglev-graph-builder.h index a439094bb6d8..d828649b332a 100644 --- a/deps/v8/src/maglev/maglev-graph-builder.h +++ b/deps/v8/src/maglev/maglev-graph-builder.h @@ -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(); @@ -1546,6 +1542,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 8f5ec525e29d..9a7e12481187 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}; } @@ -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>()); @@ -688,11 +704,54 @@ ValueNode* MaglevGraphOptimizer::GetConstantWithRepresentation( } } +namespace { + +// Returns the type check that `alt` is guaranteed to have already performed +// on its tagged input node. +NodeType GuaranteedInputType(UseRepresentation repr, ValueNode* alt) { + switch (repr) { + case UseRepresentation::kInt32: + case UseRepresentation::kFloat64: + return NodeType::kNumber; + case UseRepresentation::kHoleyFloat64: + return NodeType::kNumberOrUndefined; + // Unlike Int32/Float64, a Truncate node doesn't have a single fixed check, + // it depends on its assumed_input_type. + case UseRepresentation::kTruncatedInt32: + if (auto* t = alt->TryCast<TruncateCheckedNumberOrOddballToInt32>()) { + return t->assumed_input_type(); + } + if (auto* t = alt->TryCast<TruncateUnsafeNumberOrOddballToInt32>()) { + return t->assumed_input_type(); + } + return NodeType::kNumberOrOddball; + case UseRepresentation::kTagged: + case UseRepresentation::kTaggedForNumberToString: + case UseRepresentation::kUint32: + case UseRepresentation::kNonTruncated: + UNREACHABLE(); + } + UNREACHABLE(); +} + +} // namespace + +bool MaglevGraphOptimizer::CanReuseAlternative( + ValueNode* node, ValueNode* alt, UseRepresentation repr, + std::optional<NodeType> assumed_input_type) { + if (!assumed_input_type.has_value()) return true; + // We cannot replace a stricter check with a weaker one, as subsequent + // operations might rely on this node to deopt invalid inputs. + return reducer_.CheckType(node, *assumed_input_type) || + NodeTypeIs(GuaranteedInputType(repr, alt), *assumed_input_type); +} + MaybeReduceResult MaglevGraphOptimizer::GetUntaggedValueWithRepresentation( ValueNode* node, UseRepresentation use_repr, std::optional<NodeType> assumed_input_type) { DCHECK_NE(use_repr, UseRepresentation::kTagged); - if (node->value_representation() == ValueRepresentationFromUse(use_repr)) { + if (node->value_representation() == ValueRepresentationFromUse(use_repr) && + CanReuseAlternative(node, node, use_repr, assumed_input_type)) { return node; } if (node->Is<ReturnedValue>()) { @@ -710,8 +769,11 @@ MaybeReduceResult MaglevGraphOptimizer::GetUntaggedValueWithRepresentation( // Check if we already have a canonical conversion. NodeInfo* node_info = known_node_aspects().GetOrCreateInfoFor(broker(), node); - auto& alternative = node_info->alternative(); - if (ValueNode* alt = alternative.get(use_repr)) return alt; + if (ValueNode* alternative = node_info->alternative().get(use_repr); + alternative && + CanReuseAlternative(node, alternative, use_repr, assumed_input_type)) { + return alternative; + } // If `node` is itself tagging an untagged value, convert that value // directly instead of untagging the tagged result. if (node->is_conversion()) { @@ -726,6 +788,15 @@ MaybeReduceResult MaglevGraphOptimizer::GetUntaggedValueWithRepresentation( if (!CanEagerDeopt()) { return {}; } + if (node->is_holey_float64() && assumed_input_type.has_value() && + NodeTypeIs(*assumed_input_type, NodeType::kNumberOrBoolean)) { + // HoleyFloat64 can hold the hole or undefined, whereas the replaced node + // checked that the input is a number (or boolean, which cannot occur in + // HoleyFloat64). Convert to Float64 first so CheckedHoleyFloat64ToFloat64 + // preserves the check that subsequent operations may rely on. + GET_VALUE_OR_ABORT( + node, reducer_.GetFloat64ForToNumber(node, *assumed_input_type)); + } switch (use_repr) { case UseRepresentation::kInt32: return reducer_.GetInt32(node); @@ -771,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 @@ -873,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; @@ -1124,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; } @@ -1258,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(); @@ -1312,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; } @@ -2080,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; } @@ -2642,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; \ } @@ -2694,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; } @@ -2716,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; } @@ -2740,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; } @@ -3920,7 +3985,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 f41212a81abf..1155124d64f4 100644 --- a/deps/v8/src/maglev/maglev-graph-optimizer.h +++ b/deps/v8/src/maglev/maglev-graph-optimizer.h @@ -150,6 +150,12 @@ class V8_EXPORT_PRIVATE MaglevGraphOptimizer { ValueNode* node, UseRepresentation repr, std::optional<NodeType> assumed_input_type); + // Returns true if reusing the cached conversion 'alt' safely preserves all + // required type checks for 'node'. + bool CanReuseAlternative(ValueNode* node, ValueNode* alt, + UseRepresentation repr, + std::optional<NodeType> assumed_input_type); + // Records the untagged input of a tagging conversion as the matching // untagged alternative of `tagged`, so a later untagging use can reuse it. template <ValueRepresentation kRepresentation> @@ -170,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-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..c0e4f58e5353 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()); } @@ -3784,12 +3799,18 @@ void StoreMap::GenerateCode(MaglevAssembler* masm, Register object = ToRegister(ValueInput()); if (NoWriteBarrier()) { if (MaglevAssembler::kSupportsStoreTaggedConstant) { + if (kind() == Kind::kTransitioning) { + __ MemoryBarrier(AtomicMemoryOrder::kAcqRel); + } __ StoreTaggedFieldNoWriteBarrier(object, offsetof(HeapObject, map_), map_.object()); __ AssertElidedWriteBarrier(object, map_, register_snapshot()); } else { Register value = temps.Acquire(); __ MoveTagged(value, map_.object()); + if (kind() == Kind::kTransitioning) { + __ MemoryBarrier(AtomicMemoryOrder::kAcqRel); + } __ StoreTaggedFieldNoWriteBarrier(object, offsetof(HeapObject, map_), value); __ AssertElidedWriteBarrier(object, value, register_snapshot()); @@ -3800,6 +3821,9 @@ void StoreMap::GenerateCode(MaglevAssembler* masm, DCHECK_EQ(object, WriteBarrierDescriptor::ObjectRegister()); Register value = temps.Acquire(); __ MoveTagged(value, map_.object()); + if (kind() == Kind::kTransitioning) { + __ MemoryBarrier(AtomicMemoryOrder::kAcqRel); + } __ StoreTaggedFieldWithWriteBarrier( object, offsetof(HeapObject, map_), value, register_snapshot(), MaglevAssembler::kValueIsCompressed, MaglevAssembler::kValueCannotBeSmi); diff --git a/deps/v8/src/maglev/maglev-ir.h b/deps/v8/src/maglev/maglev-ir.h index c9adf3113aed..e06f71b2683a 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> @@ -1677,6 +1678,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 +1849,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 +1901,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 +2013,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 +2669,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 { @@ -6736,8 +6727,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 +6806,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 +6841,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 +6877,25 @@ class CreateClosure : public FixedInputValueNodeT<1, CreateClosure> { explicit CreateClosure(uint64_t bitfield, compiler::SharedFunctionInfoRef shared_function_info, compiler::FeedbackCellRef feedback_cell, - bool pretenured) + bool pretenured, + compiler::OptionalContextRef specialization_context, + ContextScopeInfo context_scope_info) : Base(bitfield), shared_function_info_(shared_function_info), feedback_cell_(feedback_cell), - pretenured_(pretenured) {} + 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() | @@ -6900,6 +6915,8 @@ class CreateClosure : public FixedInputValueNodeT<1, CreateClosure> { 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 +7678,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 diff --git a/deps/v8/src/maglev/maglev-known-node-aspects.cc b/deps/v8/src/maglev/maglev-known-node-aspects.cc index f4abfca24955..743fc9f0ca13 100644 --- a/deps/v8/src/maglev/maglev-known-node-aspects.cc +++ b/deps/v8/src/maglev/maglev-known-node-aspects.cc @@ -589,22 +589,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( @@ -652,22 +666,22 @@ void KnownNodeAspects::ClearUnstableNodeAspectsForStoreMap( StoreMap* node, bool is_tracing_enabled) { if (!node->is_transitioning()) return; - if (NodeInfo* node_info = TryGetInfoFor(node->ValueInput().node())) { - if (node_info->possible_maps_are_known() && !node_info->maps_are_stale() && - node_info->possible_maps().size() == 1) { - compiler::MapRef old_map = node_info->possible_maps().at(0); - auto MaybeAliases = [&](compiler::MapRef map) -> bool { - return map.equals(old_map); - }; - // Mark aliasing maps as stale. - if (MarkMapsStaleIfAny(MaybeAliases)) { - if (V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) { - std::cout << kRed << "[KNA] StoreMap: Invalidate alias " - << Brief(*old_map.object()) << kReset << std::endl; - } - } - return; - } + if (MarkSingleMapAsStale(node->ValueInput().node(), is_tracing_enabled)) { + return; + } + + // TODO(olivf): Only invalidate nodes with the same type. + OnSideEffect(); + if (V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) { + std::cout << kRed << "[KNA] StoreMap: Invalidate all unstable maps" + << kReset << std::endl; + } +} + +void KnownNodeAspects::ClearUnstableNodeAspectsForMigration( + Node* node, bool is_tracing_enabled) { + if (MarkSingleMapAsStale(node->input_node(0), is_tracing_enabled)) { + return; } // TODO(olivf): Only invalidate nodes with the same type. @@ -1009,6 +1023,28 @@ KnownNodeAspects::ContextStoreResult KnownNodeAspects::RecordContextSlotStore( return {ContextStoreResult::kSetNewValue, std::move(aliased_slots)}; } +bool KnownNodeAspects::MarkSingleMapAsStale(ValueNode* node, + bool is_tracing_enabled) { + if (NodeInfo* node_info = TryGetInfoFor(node)) { + if (node_info->possible_maps_are_known() && !node_info->maps_are_stale() && + node_info->possible_maps().size() == 1) { + compiler::MapRef old_map = node_info->possible_maps().at(0); + auto MaybeAliases = [&](compiler::MapRef map) -> bool { + return map.equals(old_map); + }; + // Mark aliasing maps as stale. + if (MarkMapsStaleIfAny(MaybeAliases)) { + if (V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) { + std::cout << kRed << "[KNA]: MarkSingleMapAsStale: Invalidate alias " + << Brief(*old_map.object()) << kReset << std::endl; + } + } + return true; + } + } + return false; +} + #ifdef DEBUG bool IsStringRootIndex(RootIndex index) { if (index > RootIndex::kLastReadOnlyRoot) return false; diff --git a/deps/v8/src/maglev/maglev-known-node-aspects.h b/deps/v8/src/maglev/maglev-known-node-aspects.h index b7f039113668..dd1ce8cc3858 100644 --- a/deps/v8/src/maglev/maglev-known-node-aspects.h +++ b/deps/v8/src/maglev/maglev-known-node-aspects.h @@ -407,6 +407,8 @@ class KnownNodeAspects { void ClearUnstableNodeAspectsForStoreMap(StoreMap* node, bool is_tracing_enabled); + void ClearUnstableNodeAspectsForMigration(Node* node, + bool is_tracing_enabled); void ClearUnstableNodeAspectsForElementsTransition( const ZoneVector<compiler::MapRef>& transition_sources, bool is_tracing_enabled); @@ -824,8 +826,7 @@ class KnownNodeAspects { std::is_same_v<NodeT, CheckMapsWithMigrationAndDeopt> || std::is_same_v<NodeT, MigrateMapIfNeeded>) { - // These instructions only migrate representations of values, not the - // values themselves, so cached values are still valid. + ClearUnstableNodeAspectsForMigration(node, is_tracing_enabled); } else if constexpr (std::is_same_v<NodeT, StoreMap>) { ClearUnstableNodeAspectsForStoreMap(node, is_tracing_enabled); } else if constexpr (std::is_same_v<NodeT, TransitionElementsKind> || @@ -910,6 +911,8 @@ class KnownNodeAspects { SmallZoneVector<LoadedContextSlotsKey, 8> ClearAliasedContextSlotsFor( Graph* graph, ValueNode* context, int offset, ValueNode* value); + bool MarkSingleMapAsStale(ValueNode* node, bool is_tracing_enabled); + static constexpr uint32_t kEffectEpochForPureInstructions = std::numeric_limits<uint32_t>::max(); static constexpr uint32_t kEffectEpochOverflow = diff --git a/deps/v8/src/maglev/maglev-phi-representation-selector.cc b/deps/v8/src/maglev/maglev-phi-representation-selector.cc index eff255ed43c5..5b44744d9e95 100644 --- a/deps/v8/src/maglev/maglev-phi-representation-selector.cc +++ b/deps/v8/src/maglev/maglev-phi-representation-selector.cc @@ -1074,7 +1074,7 @@ ValueNode* MaglevPhiRepresentationSelector::GetReplacementForPhiInputConversion( } ProcessResult MaglevPhiRepresentationSelector::UpdateUntaggingOfPhi( - Phi* phi, ValueNode* old_untagging) { + Phi* phi, ValueNode* old_untagging, const ProcessingState* state) { DCHECK_EQ(old_untagging->input_count(), 1); DCHECK(old_untagging->input(0).node()->Is<Phi>()); @@ -1192,24 +1192,27 @@ ProcessResult MaglevPhiRepresentationSelector::UpdateUntaggingOfPhi( if (old_untagging->Is<TruncateUnsafeNumberOrOddballToInt32>()) { conversion_is_truncating_float64 = true; } else if (old_untagging->Is<TruncateCheckedNumberOrOddballToInt32>()) { - if (from_repr == ValueRepresentation::kFloat64) { - // If {from_repr} is Float64, then the "CheckedNumber" part is - // guaranteed to pass and this operation just truncates its value to - // Int32. - conversion_is_truncating_float64 = true; - } else { - DCHECK_EQ(from_repr, ValueRepresentation::kHoleyFloat64); + if (from_repr == ValueRepresentation::kHoleyFloat64) { const auto* truncate = old_untagging->Cast<TruncateCheckedNumberOrOddballToInt32>(); // A HoleyFloat64 hole really means Undefined rather than the_hole: // whenever it gets rematerialized, it will always be rematerialized as - // Undefined. So, we can use a truncating conversion as long as the - // original assumed input type was allowing truncating Undefined. - // Assumptions without Undefined need to deopt for Hole/Undefined - // ==> not truncating. - conversion_is_truncating_float64 = !NodeTypeIs( - truncate->assumed_input_type(), NodeType::kNumberOrBoolean); + // Undefined. Assumptions without Undefined need to deopt on + // Hole/Undefined before truncating the Float64 value to Int32. + if (!NodeTypeCanBe(truncate->assumed_input_type(), + NodeType::kUndefined)) { + eager_deopt_frame_ = &old_untagging->eager_deopt_info()->top_frame(); + AddNewNodeNoInputConversion<CheckHoleyFloat64NotHoleOrUndefined>( + reducer_.current_block(), + BasicBlockPosition::At(state->node_index()), {phi}); +#ifdef DEBUG + eager_deopt_frame_ = nullptr; +#endif // DEBUG + } + } else { + DCHECK_EQ(from_repr, ValueRepresentation::kFloat64); } + conversion_is_truncating_float64 = true; } Opcode needed_conversion = GetOpcodeForConversion( diff --git a/deps/v8/src/maglev/maglev-phi-representation-selector.h b/deps/v8/src/maglev/maglev-phi-representation-selector.h index 5ecca6b95f2f..3007727a0999 100644 --- a/deps/v8/src/maglev/maglev-phi-representation-selector.h +++ b/deps/v8/src/maglev/maglev-phi-representation-selector.h @@ -206,7 +206,7 @@ class MaglevPhiRepresentationSelector { // removed altogether (or rather, replaced by an identity node). return UpdateUntaggingOfPhi( node->NodeBase::input(0).node()->template Cast<Phi>(), - node->template Cast<ValueNode>()); + node->template Cast<ValueNode>(), state); } return ProcessResult::kContinue; } @@ -273,7 +273,8 @@ class MaglevPhiRepresentationSelector { // Updates {old_untagging} to reflect that its Phi input has been untagged and // that a different conversion is now needed. - ProcessResult UpdateUntaggingOfPhi(Phi* phi, ValueNode* old_untagging); + ProcessResult UpdateUntaggingOfPhi(Phi* phi, ValueNode* old_untagging, + const ProcessingState* state); ProcessResult EmitUnconditionalDeopt(NodeBase* node, DeoptimizeReason reason); 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-range-analysis.h b/deps/v8/src/maglev/maglev-range-analysis.h index 51744959af0f..57d415f06ed1 100644 --- a/deps/v8/src/maglev/maglev-range-analysis.h +++ b/deps/v8/src/maglev/maglev-range-analysis.h @@ -67,6 +67,18 @@ class NodeRanges { return *range; } + void InitializeRangeIfMissing(BasicBlock* block, ValueNode* node, + Range range) { + DCHECK(ranges_initialized_.Contains(block->id())); + RangeMap& map = ranges_[block->id()]; + if (!map.find(node)) { + map = map.insert(zone(), node, range); + TRACE_RANGE("Initializing in Block b" << block->id() << ": " + << PrintNodeBrief(node) << ": " + << range); + } + } + void UnionUpdate(BasicBlock* block, ValueNode* node, Range range) { DCHECK(ranges_initialized_.Contains(block->id())); RangeMap& map = ranges_[block->id()]; @@ -210,6 +222,15 @@ class RangeProcessor { BlockProcessResult PreProcessBasicBlock(BasicBlock* block) { current_block_ = block; ranges_.EnsureMapExistsFor(block); + if (block->has_state() && block->state()->is_resumable_loop() && + block->predecessor_count() == 1) { + // Resumable loop headers might not have a live forward predecessor: that + // part of the code might be dead even though the loop is still reachable + // via a resume point. Make sure we initialize phis in such case. If the + // loop has a live predecessor, ProcessPhis is called when processing that + // live predecessor, and this code is a no-op. + InitializeLoopPhisIfMissing(block); + } return BlockProcessResult::kContinue; } BlockProcessResult PostProcessBasicBlock(BasicBlock* block) { @@ -543,6 +564,14 @@ class RangeProcessor { } } + void InitializeLoopPhisIfMissing(BasicBlock* block) { + if (!block->has_phi()) return; + for (Phi* phi : *block->phis()) { + ranges_.InitializeRangeIfMissing( + block, phi, phi->is_int32() ? Range::Int32() : Range::All()); + } + } + // Returns true if the loop reach a fixpoint. bool ProcessLoopPhisBackedge(BasicBlock* block, BasicBlock* backedge_pred) { if (!block->has_phi()) return true; diff --git a/deps/v8/src/maglev/maglev-reducer-inl.h b/deps/v8/src/maglev/maglev-reducer-inl.h index 413713365738..280e6c8fc439 100644 --- a/deps/v8/src/maglev/maglev-reducer-inl.h +++ b/deps/v8/src/maglev/maglev-reducer-inl.h @@ -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( @@ -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, @@ -1098,9 +1176,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( @@ -1285,22 +1364,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 +1395,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})); @@ -2278,14 +2358,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()) { @@ -3526,7 +3625,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,12 +3791,9 @@ 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: @@ -5143,7 +5240,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)); @@ -5711,6 +5808,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, @@ -6645,13 +6755,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 +6806,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 +6862,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..b2346457bce6 100644 --- a/deps/v8/src/maglev/maglev-reducer.h +++ b/deps/v8/src/maglev/maglev-reducer.h @@ -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); @@ -1090,6 +1096,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); @@ -1388,6 +1398,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); 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/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/numbers/conversions.cc b/deps/v8/src/numbers/conversions.cc index 3bdae78df64e..96c8477c0b17 100644 --- a/deps/v8/src/numbers/conversions.cc +++ b/deps/v8/src/numbers/conversions.cc @@ -15,6 +15,7 @@ #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 +225,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) {} @@ -1283,7 +1276,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 +1295,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()}; } 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/api-callbacks-inl.h b/deps/v8/src/objects/api-callbacks-inl.h index 9d5e062ef5de..1ceba2305321 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(); } diff --git a/deps/v8/src/objects/api-callbacks.h b/deps/v8/src/objects/api-callbacks.h index 2cb4b5cb3317..6f30759c3c3c 100644 --- a/deps/v8/src/objects/api-callbacks.h +++ b/deps/v8/src/objects/api-callbacks.h @@ -109,7 +109,7 @@ V8_OBJECT class AccessorInfo : public HeapObject { TaggedMember<Name> name_; ExternalPointerMember<kAccessorInfoGetterTag> getter_; ExternalPointerMember<kAccessorInfoSetterTag> setter_; - uint32_t flags_; + uint32_t flags_ V8_TQ_TYPE(AccessorInfoFlags); #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif // TAGGED_SIZE_8_BYTES @@ -127,6 +127,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 +160,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; @@ -295,7 +297,7 @@ V8_OBJECT class InterceptorInfo : public HeapObject { public: TaggedMember<Object> data_; - uint32_t flags_; + uint32_t flags_ V8_TQ_TYPE(InterceptorInfoFlags); #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif // TAGGED_SIZE_8_BYTES 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..53417e4a971a 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,10 @@ 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_NAME(mapped_entries); + 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/backing-store.cc b/deps/v8/src/objects/backing-store.cc index 74df6b3162c8..c5b07ffc5953 100644 --- a/deps/v8/src/objects/backing-store.cc +++ b/deps/v8/src/objects/backing-store.cc @@ -550,7 +550,7 @@ std::optional<size_t> BackingStore::GrowWasmMemoryInPlace(Isolate* isolate, // 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); + size_t old_length = byte_length_.load(std::memory_order_seq_cst); if (delta_pages == 0) { return {old_length / wasm::kWasmPageSize}; // degenerate grow. @@ -575,7 +575,7 @@ std::optional<size_t> BackingStore::GrowWasmMemoryInPlace(Isolate* isolate, return {}; } if (byte_length_.compare_exchange_weak(old_length, new_length, - std::memory_order_acq_rel)) { + std::memory_order_seq_cst)) { // Successfully updated both the length and permissions. break; } @@ -921,7 +921,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..c44763187620 100644 --- a/deps/v8/src/objects/bigint.cc +++ b/deps/v8/src/objects/bigint.cc @@ -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..6ac647a0da1d --- /dev/null +++ b/deps/v8/src/objects/bit-field-group.h @@ -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. + +#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 = base::BitField<bool, 0, 1, uint8_t>; +// using IsUndetectableBit = IsCallableBit::Next<bool, 1>; +// BIT_FIELD_GETTER(is_callable, IsCallableBit) +// BIT_FIELD_GETTER(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, which must be bit order without gaps. +// - 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. +template <typename Derived, typename U> +class BitFieldGroup { + public: + static_assert(std::is_unsigned_v<U>); + + using UnderlyingType = U; + + constexpr BitFieldGroup() = default; + // NOLINTNEXTLINE(runtime/explicit) + constexpr BitFieldGroup(U value) : value_(value) {} + constexpr operator U() 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..bf33dc7e4afe 100644 --- a/deps/v8/src/objects/bytecode-array-inl.h +++ b/deps/v8/src/objects/bytecode-array-inl.h @@ -12,6 +12,7 @@ #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/struct-inl.h" #include "src/objects/trusted-pointer-inl.h" // Has to be the last include (doesn't have include guards): @@ -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..fab5af7c787c 100644 --- a/deps/v8/src/objects/bytecode-array.h +++ b/deps/v8/src/objects/bytecode-array.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,8 @@ V8_OBJECT class BytecodeArray : public ExposedTrustedObject { #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif + V8_TQ_TAIL_NAME(bytes); + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(uint8_t, bytes); } V8_OBJECT_END; @@ -173,6 +175,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) diff --git a/deps/v8/src/objects/call-site-info-inl.h b/deps/v8/src/objects/call-site-info-inl.h index bdfbf46e7690..94af98fddfa9 100644 --- a/deps/v8/src/objects/call-site-info-inl.h +++ b/deps/v8/src/objects/call-site-info-inl.h @@ -31,6 +31,19 @@ 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 @@ -40,32 +53,13 @@ Tagged<HeapObject> CallSiteInfo::code_object(IsolateForSandbox isolate) const { 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..52288b6f30de 100644 --- a/deps/v8/src/objects/call-site-info.h +++ b/deps/v8/src/objects/call-site-info.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( @@ -179,12 +178,12 @@ V8_OBJECT class CallSiteInfo : public Struct { kCodeIndirectPointerTag); 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..1da3afc4418f 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) { @@ -486,72 +536,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..6ec920f1398a 100644 --- a/deps/v8/src/objects/code-inl.h +++ b/deps/v8/src/objects/code-inl.h @@ -19,6 +19,7 @@ #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/snapshot/embedded/embedded-data-inl.h" @@ -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..9dba947da69c 100644 --- a/deps/v8/src/objects/code.h +++ b/deps/v8/src/objects/code.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) diff --git a/deps/v8/src/objects/contexts.h b/deps/v8/src/objects/contexts.h index 90a1efd85bd9..6722396a5600 100644 --- a/deps/v8/src/objects/contexts.h +++ b/deps/v8/src/objects/contexts.h @@ -742,7 +742,9 @@ V8_OBJECT class Context : public HeapObject { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); public: - TaggedMember<Smi> length_; + V8_TQ_CONST TaggedMember<Smi> length_; + V8_TQ_TAIL_NAME(elements); + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, elements); } V8_OBJECT_END; @@ -940,9 +942,11 @@ 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_NAME(objects); + V8_TQ_TAIL_LENGTH(capacity); FLEXIBLE_ARRAY_MEMBER(typename Super::ElementMemberT, objects); } V8_OBJECT_END; @@ -996,7 +1000,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..ac7f1fb6a2dd 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; diff --git a/deps/v8/src/objects/data-handler.h b/deps/v8/src/objects/data-handler.h index 647b65367248..c3ecfaa607bc 100644 --- a/deps/v8/src/objects/data-handler.h +++ b/deps/v8/src/objects/data-handler.h @@ -65,6 +65,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..932d65e0ff6b 100644 --- a/deps/v8/src/objects/debug-objects-inl.h +++ b/deps/v8/src/objects/debug-objects-inl.h @@ -12,9 +12,11 @@ #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/struct-inl.h" #include "src/objects/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..76d0ede486ac 100644 --- a/deps/v8/src/objects/debug-objects.h +++ b/deps/v8/src/objects/debug-objects.h @@ -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,9 @@ 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_NAME(slots); + V8_TQ_TAIL_LENGTH(slot_count); FLEXIBLE_ARRAY_MEMBER(CoverageInfoSlot, slots); } V8_OBJECT_END; @@ -309,25 +315,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 +350,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 +357,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 +368,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 +382,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 +399,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 +427,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 +435,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 +446,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..05d7d253df76 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); diff --git a/deps/v8/src/objects/descriptor-array.h b/deps/v8/src/objects/descriptor-array.h index 8e020a8b4671..62ebccd6b5c2 100644 --- a/deps/v8/src/objects/descriptor-array.h +++ b/deps/v8/src/objects/descriptor-array.h @@ -38,6 +38,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); @@ -312,11 +315,13 @@ 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<uint32_t> flags_ V8_TQ_TYPE(DescriptorArrayFlags); TaggedMember<EnumCache> enum_cache_; - FLEXIBLE_ARRAY_MEMBER(Entry, entries); + V8_TQ_TAIL_NAME(descriptors); + 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/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..0ed2bb0b6a9a 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(); } @@ -54,8 +64,6 @@ void FeedbackCell::set_dispatch_handle(JSDispatchHandle new_handle) { dispatch_handle_.Relaxed_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..fcfcb756ad69 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); @@ -167,27 +198,15 @@ void FeedbackVector::set_flags(uint16_t 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 { @@ -218,8 +237,6 @@ 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(); } @@ -491,7 +508,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 +663,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 +679,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..bd3ff4fbbdaf 100644 --- a/deps/v8/src/objects/feedback-vector.cc +++ b/deps/v8/src/objects/feedback-vector.cc @@ -395,14 +395,6 @@ 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)); -} - void FeedbackVector::SetOptimizedOsrCode(Isolate* isolate, FeedbackSlot slot, Tagged<Code> code) { DCHECK(CodeKindIsOptimizedJSFunction(code->kind())); @@ -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..e8037b18d66a 100644 --- a/deps/v8/src/objects/feedback-vector.h +++ b/deps/v8/src/objects/feedback-vector.h @@ -294,6 +294,8 @@ V8_OBJECT class ClosureFeedbackCellArray public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_NAME(objects); + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(typename Super::ElementMemberT, objects); } V8_OBJECT_END; @@ -303,6 +305,12 @@ class NexusConfig; // of length determined by the feedback metadata. V8_OBJECT class FeedbackVector : public HeapObject { public: + inline FeedbackVector( + const AllocationWitness& witness, int32_t length, + Tagged<SharedFunctionInfo> shared_function_info, + Tagged<ClosureFeedbackCellArray> closure_feedback_cell_array, + Tagged<FeedbackCell> parent_feedback_cell); + // Bit positions in |osr_state|. using OsrUrgencyBits = base::BitField<uint32_t, 0, 3, uint8_t>; using MaybeHasTurbofanOsrCodeBit = OsrUrgencyBits::Next<bool, 1>; @@ -325,7 +333,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; @@ -346,18 +353,10 @@ V8_OBJECT class FeedbackVector : public HeapObject { inline void set_flags(uint16_t 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. @@ -382,9 +381,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 +416,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 +548,26 @@ 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; + uint8_t osr_state_ V8_TQ_TYPE(OsrState) = 0; + uint16_t flags_ V8_TQ_TYPE(FeedbackVectorFlags) = 0; + 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_NAME(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 +761,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 +774,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 +846,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/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..2c1c5d86f50e 100644 --- a/deps/v8/src/objects/fixed-array.h +++ b/deps/v8/src/objects/fixed-array.h @@ -318,6 +318,8 @@ V8_OBJECT class FixedArray public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_NAME(objects); + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, objects); } V8_OBJECT_END; @@ -358,6 +360,8 @@ V8_OBJECT class TrustedFixedArray public: // length_ / optional_padding_ live in TrustedFixedArrayBase. + V8_TQ_TAIL_NAME(objects); + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, objects); } V8_OBJECT_END; @@ -396,6 +400,8 @@ V8_OBJECT class ProtectedFixedArray public: // length_ / optional_padding_ live in TrustedFixedArrayBase. + // Torque splits the flexible tail into indexed sections. + V8_TQ_TAIL_SECTIONS(objects[length] : TrustedObject | Smi;); FLEXIBLE_ARRAY_MEMBER(ElementMemberT, objects); } V8_OBJECT_END; @@ -432,6 +438,8 @@ V8_OBJECT class WeakFixedArray public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_NAME(objects); + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, objects); } V8_OBJECT_END; @@ -464,6 +472,8 @@ V8_OBJECT class WeakHomomorphicFixedArray public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_NAME(objects); + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, objects); } V8_OBJECT_END; @@ -491,6 +501,8 @@ V8_OBJECT class TrustedWeakFixedArray public: // length_ / optional_padding_ live in TrustedFixedArrayBase. + V8_TQ_TAIL_NAME(objects); + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, objects); } V8_OBJECT_END; @@ -521,6 +533,8 @@ V8_OBJECT class ProtectedWeakFixedArray public: // length_ / optional_padding_ live in TrustedFixedArrayBase. + // Torque splits the flexible tail into indexed sections. + V8_TQ_TAIL_SECTIONS(objects[length] : TrustedObject | Smi;); FLEXIBLE_ARRAY_MEMBER(ElementMemberT, objects); } V8_OBJECT_END; @@ -639,8 +653,10 @@ V8_OBJECT class WeakArrayList } public: - uint32_t capacity_; + V8_TQ_CONST uint32_t capacity_; uint32_t length_; + V8_TQ_TAIL_NAME(objects); + V8_TQ_TAIL_LENGTH(capacity); FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, objects); } V8_OBJECT_END; @@ -716,8 +732,10 @@ V8_OBJECT class ArrayList AllocationType allocation = AllocationType::kYoung); public: - uint32_t capacity_; + V8_TQ_CONST uint32_t capacity_; uint32_t length_; + V8_TQ_TAIL_NAME(objects); + V8_TQ_TAIL_LENGTH(capacity); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, objects); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/fixed-primitive-array-inl.h b/deps/v8/src/objects/fixed-primitive-array-inl.h index edb27b85d258..dc51b940adc8 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)); diff --git a/deps/v8/src/objects/fixed-primitive-array.h b/deps/v8/src/objects/fixed-primitive-array.h index 528c63e9e047..2bd4d7735dca 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,10 @@ V8_OBJECT class FixedDoubleArray public: // length_ / optional_padding_ live in FixedArrayBase. - FLEXIBLE_ARRAY_MEMBER(ElementMemberT, values); + V8_TQ_TAIL_NAME(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 +199,8 @@ V8_OBJECT class ByteArray : public PrimitiveArrayBase<ByteArray, uint8_t> { public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_NAME(values); + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(uint8_t, values); } V8_OBJECT_END; @@ -201,6 +208,8 @@ V8_OBJECT class ByteArray : public PrimitiveArrayBase<ByteArray, uint8_t> { V8_OBJECT class TrustedByteArray : public PrimitiveArrayBase<TrustedByteArray, uint8_t, TrustedFixedArrayBase> { + V8_TQ_TAIL_NAME(values); + V8_TQ_TAIL_LENGTH(length); V8_IT_OWN_TYPE; using Super = PrimitiveArrayBase<TrustedByteArray, uint8_t, TrustedFixedArrayBase>; 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..afd5ef40e8e3 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); @@ -26,6 +35,11 @@ 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..71c56d3bab9f 100644 --- a/deps/v8/src/objects/heap-number.h +++ b/deps/v8/src/objects/heap-number.h @@ -29,6 +29,9 @@ 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); @@ -76,6 +79,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-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..73ccc6d20f4f 100644 --- a/deps/v8/src/objects/heap-object.h +++ b/deps/v8/src/objects/heap-object.h @@ -7,11 +7,13 @@ #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/roots/roots.h" #include "src/sandbox/indirect-pointer-tag.h" #include "src/sandbox/isolate.h" @@ -29,7 +31,6 @@ 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 { @@ -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-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..b1223c7da537 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,20 @@ #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 #include "metagen/instance-types.h" #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..8440c7b63e62 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 { diff --git a/deps/v8/src/objects/intl-objects.h b/deps/v8/src/objects/intl-objects.h index 6ea9427d1f49..ebc232ff340a 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" @@ -198,6 +199,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..cee548ec57b7 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); } @@ -204,7 +206,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 { @@ -397,21 +400,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..327f70bb2251 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); diff --git a/deps/v8/src/objects/js-array-buffer.h b/deps/v8/src/objects/js-array-buffer.h index a63e91d3b989..63bf1785af83 100644 --- a/deps/v8/src/objects/js-array-buffer.h +++ b/deps/v8/src/objects/js-array-buffer.h @@ -126,9 +126,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, @@ -238,12 +240,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_; + uint32_t bit_field_ V8_TQ_TYPE(JSArrayBufferFlags); #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif @@ -465,7 +468,7 @@ V8_OBJECT class JSArrayBufferView : public JSAPIObjectWithEmbedderSlots { public: TaggedMember<JSArrayBuffer> buffer_; - uint32_t bit_field_; + uint32_t bit_field_ V8_TQ_TYPE(JSArrayBufferViewFlags); #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif @@ -495,8 +498,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 +590,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 +601,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); 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-data-object-builder-inl.h b/deps/v8/src/objects/js-data-object-builder-inl.h index 48fedddb965a..d7be67cc905b 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); } } diff --git a/deps/v8/src/objects/js-date-time-format.cc b/deps/v8/src/objects/js-date-time-format.cc index 05999c6ad9f4..590c50f77c62 100644 --- a/deps/v8/src/objects/js-date-time-format.cc +++ b/deps/v8/src/objects/js-date-time-format.cc @@ -1366,7 +1366,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; } 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.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..6256b0e20549 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 { 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-objects-inl.h b/deps/v8/src/objects/js-objects-inl.h index c715995c87ff..1b7466f0b608 100644 --- a/deps/v8/src/objects/js-objects-inl.h +++ b/deps/v8/src/objects/js-objects-inl.h @@ -502,12 +502,16 @@ void JSObject::FastPropertyAtPut(FieldIndex index, Tagged<Object> value, } void JSObject::WriteToField(InternalIndex descriptor, PropertyDetails details, - Tagged<Object> value) { + Tagged<Object> value, bool initializing_store) { DCHECK_EQ(PropertyLocation::kField, details.location()); DCHECK_EQ(PropertyKind::kData, details.kind()); 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,21 @@ 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); + // The map store must follow the value write and use release semantics so + // background threads (e.g. concurrent compiler) see a consistent + // initialized state upon observing the HeapNumber map. + Isolate* isolate = Isolate::Current(); + box->set_map_safe_transition_no_write_barrier( + isolate, ReadOnlyRoots(isolate).heap_number_map(), kReleaseStore); + } else { + Cast<HeapNumber>(box)->set_value_as_bits(bits); + } } else { FastPropertyAtPut(index, value); } @@ -748,21 +759,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 +881,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); } diff --git a/deps/v8/src/objects/js-objects.cc b/deps/v8/src/objects/js-objects.cc index 69e7d3101a5d..8916228816e2 100644 --- a/deps/v8/src/objects/js-objects.cc +++ b/deps/v8/src/objects/js-objects.cc @@ -2524,8 +2524,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. @@ -3253,7 +3251,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 +3270,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 +3331,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 +3357,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 +3383,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 +3473,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 +3674,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 { @@ -5205,7 +5215,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 +5291,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 +5320,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..2fc59d8256c3 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) @@ -832,7 +832,8 @@ V8_OBJECT class JSObject : public JSReceiver { Tagged<Object> value, SeqCstAccessTag tag); inline void WriteToField(InternalIndex descriptor, PropertyDetails details, - Tagged<Object> value); + Tagged<Object> value, + bool initializing_store = false); inline Tagged<Object> RawFastInobjectPropertyAtSwap(FieldIndex index, Tagged<Object> value, @@ -1431,14 +1432,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 +1491,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 +1537,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 +1599,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 +1620,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.h b/deps/v8/src/objects/js-plural-rules.h index e66c3014b202..e663ed2a851c 100644 --- a/deps/v8/src/objects/js-plural-rules.h +++ b/deps/v8/src/objects/js-plural-rules.h @@ -91,7 +91,7 @@ V8_OBJECT class JSPluralRules : public JSObject { public: TaggedMember<String> locale_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSPluralRulesFlags>); TaggedMember<Foreign> icu_plural_rules_; TaggedMember<Foreign> icu_number_formatter_; } V8_OBJECT_END; diff --git a/deps/v8/src/objects/js-promise.h b/deps/v8/src/objects/js-promise.h index b76ea162d9f7..b15cb20ddc64 100644 --- a/deps/v8/src/objects/js-promise.h +++ b/deps/v8/src/objects/js-promise.h @@ -114,7 +114,7 @@ V8_OBJECT class JSPromise : public JSObjectWithEmbedderSlots { // was not settled yet, otherwise the result. TaggedMember<UnionOf<PromiseReaction, JSAny>> reactions_or_result_; // SmiTagged<JSPromiseFlags>. - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSPromiseFlags>); 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..b8d70d11a9f6 100644 --- a/deps/v8/src/objects/js-promise.tq +++ b/deps/v8/src/objects/js-promise.tq @@ -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-regexp-inl.h b/deps/v8/src/objects/js-regexp-inl.h index b5e85bab236f..02d53d7098e1 100644 --- a/deps/v8/src/objects/js-regexp-inl.h +++ b/deps/v8/src/objects/js-regexp-inl.h @@ -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..40e2c3a11f3a 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> @@ -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; @@ -175,7 +176,7 @@ V8_OBJECT class JSRegExp : public JSObject { public: TrustedPointerMember<RegExpData, kRegExpDataIndirectPointerTag> data_; - TaggedMember<Object> flags_; + 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) @@ -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-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-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..6d2305a755b7 100644 --- a/deps/v8/src/objects/keys.cc +++ b/deps/v8/src/objects/keys.cc @@ -529,7 +529,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 +548,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 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..0a207bf89477 100644 --- a/deps/v8/src/objects/literal-objects.h +++ b/deps/v8/src/objects/literal-objects.h @@ -24,19 +24,15 @@ class StructBodyDescriptor; 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 +40,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 +100,18 @@ V8_OBJECT class ObjectBoilerplateDescription // length_ / optional_padding_ live in FixedArrayBase. TaggedMember<Smi> backing_store_size_; TaggedMember<Smi> flags_; + V8_TQ_TAIL_NAME(raw_entries); + 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, kRegExpDataIndirectPointerTag> data_; + const TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSRegExpFlags>); } V8_OBJECT_END; template <> @@ -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, @@ -252,13 +236,13 @@ V8_OBJECT class ClassBoilerplate : public Struct { 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_; + 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/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..981d2dde8cd5 100644 --- a/deps/v8/src/objects/lookup.cc +++ b/deps/v8/src/objects/lookup.cc @@ -1057,13 +1057,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); @@ -1206,8 +1205,8 @@ void LookupIterator::WriteDataValue(DirectHandle<Object> value, DCHECK_IMPLIES(!initializing_store && property_details_.constness() == PropertyConstness::kConst, CanStayConst(*value)); - Cast<JSObject>(*holder)->WriteToField(descriptor_number(), - property_details_, *value); + Cast<JSObject>(*holder)->WriteToField( + descriptor_number(), property_details_, *value, initializing_store); } else { DCHECK_EQ(PropertyLocation::kDescriptor, property_details_.location()); DCHECK_EQ(PropertyConstness::kConst, property_details_.constness()); @@ -1383,7 +1382,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/map-inl.h b/deps/v8/src/objects/map-inl.h index 1cbddb0d9879..74202eccb49d 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 @@ -506,7 +506,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 +525,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 +547,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 +633,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 +722,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 @@ -1034,12 +1034,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 +1045,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 +1054,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 @@ -1155,14 +1149,16 @@ Tagged<Object> Map::raw_native_context_or_null() const { #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,21 +1282,21 @@ 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); diff --git a/deps/v8/src/objects/map.cc b/deps/v8/src/objects/map.cc index a6f6a26a9451..788ec563b805 100644 --- a/deps/v8/src/objects/map.cc +++ b/deps/v8/src/objects/map.cc @@ -7,6 +7,7 @@ #include <optional> #include "src/base/hashing.h" +#include "src/base/unique-array.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" #include "src/execution/frames.h" @@ -429,6 +430,9 @@ VisitorId Map::GetVisitorId(Tagged<Map> map) { 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: @@ -1321,20 +1326,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<Bits3::OwnsDescriptorsBit>(true) + .with<Bits3::NumberOfOwnDescriptorsBits>(0) + .with<Bits3::EnumLengthBits>(kInvalidEnumCacheSentinel) + .with<Bits3::IsDeprecatedBit>(false) + .with<Bits3::IsInRetainedMapListBit>(false); + if (!bits3.is_dictionary_map()) { + bits3 = bits3.with<Bits3::IsUnstableBit>(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)) { @@ -1862,45 +1864,10 @@ 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 + // TODO(https://crbug.com/414525205): Remove Map::AsLanguageMode and + // strict_function_transition_symbol now that strict and sloppy function maps + // have the same own descriptors. 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, @@ -2164,11 +2131,11 @@ DirectHandle<Map> Map::TransitionToDataProperty( if (!maybe_map.ToHandle(&result)) { const char* reason = "TooManyFastProperties"; #if V8_TRACE_MAPS - base::OwnedVector<char> buffer; + base::UniqueArray<char> buffer; if (v8_flags.log_maps) { - auto name_buffer = base::OwnedVector<char>::NewForOverwrite(100); + auto name_buffer = base::UniqueArray<char>::NewForOverwrite(100); name->NameShortPrint(name_buffer.as_vector()); - buffer = base::OwnedVector<char>::NewForOverwrite(128); + buffer = base::UniqueArray<char>::NewForOverwrite(128); SNPrintF(buffer.as_vector(), "TooManyFastProperties %s", name_buffer.begin()); reason = buffer.begin(); diff --git a/deps/v8/src/objects/map.h b/deps/v8/src/objects/map.h index a33c7f01ac16..04454f14e747 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) \ @@ -202,10 +204,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,57 +328,69 @@ 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 = base::BitField<bool, 0, 1, uint8_t>; + 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_GETTER(is_callable, IsCallableBit) + BIT_FIELD_GETTER(is_undetectable, IsUndetectableBit) + BIT_FIELD_GETTER(has_named_interceptor, HasNamedInterceptorBit) + BIT_FIELD_GETTER(is_access_check_needed, IsAccessCheckNeededBit) + BIT_FIELD_GETTER(has_indexed_interceptor, HasIndexedInterceptorBit) + BIT_FIELD_GETTER(is_constructor, IsConstructorBit) + BIT_FIELD_GETTER(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 { + struct Bits2 : BitFieldGroup<Bits2, uint8_t> { + using BitFieldGroup::BitFieldGroup; + using NewTargetIsBaseBit = base::BitField<bool, 0, 1, uint8_t>; using IsImmutablePrototypeBit = NewTargetIsBaseBit::Next<bool, 1>; using ElementsKindBits = IsImmutablePrototypeBit::Next<ElementsKind, 6>; + + BIT_FIELD_GETTER(new_target_is_base, NewTargetIsBaseBit) + BIT_FIELD_GETTER(is_immutable_prototype, IsImmutablePrototypeBit) + BIT_FIELD_GETTER(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 { + struct Bits3 : BitFieldGroup<Bits3, uint32_t> { + using BitFieldGroup::BitFieldGroup; + using EnumLengthBits = base::BitField<int32_t, 0, 10, uint32_t>; using NumberOfOwnDescriptorsBits = EnumLengthBits::Next<int32_t, 10>; using IsPrototypeMapBit = NumberOfOwnDescriptorsBits::Next<bool, 1>; @@ -390,6 +404,20 @@ V8_OBJECT class Map : public HeapObject { using MayHaveInterestingPropertiesBit = IsExtensibleBit::Next<bool, 1>; using ConstructionCounterBits = MayHaveInterestingPropertiesBit::Next<int32_t, 3>; + + BIT_FIELD_GETTER(enum_length, EnumLengthBits) + BIT_FIELD_GETTER(number_of_own_descriptors, NumberOfOwnDescriptorsBits) + BIT_FIELD_GETTER(is_prototype_map, IsPrototypeMapBit) + BIT_FIELD_GETTER(is_dictionary_map, IsDictionaryMapBit) + BIT_FIELD_GETTER(owns_descriptors, OwnsDescriptorsBit) + BIT_FIELD_GETTER(is_in_retained_map_list, IsInRetainedMapListBit) + BIT_FIELD_GETTER(is_deprecated, IsDeprecatedBit) + BIT_FIELD_GETTER(is_unstable, IsUnstableBit) + BIT_FIELD_GETTER(is_migration_target, IsMigrationTargetBit) + BIT_FIELD_GETTER(is_extensible, IsExtensibleBit) + BIT_FIELD_GETTER(may_have_interesting_properties, + MayHaveInterestingPropertiesBit) + BIT_FIELD_GETTER(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; @@ -989,7 +1029,6 @@ V8_OBJECT class Map : public HeapObject { static constexpr std::optional<RootIndex> TryGetMapRootIdxFor( InstanceType type); - static inline Tagged<Map> GetMapFor(ReadOnlyRoots roots, InstanceType type); bool IsMapInArrayPrototypeChain(Isolate* isolate) const; @@ -1185,10 +1224,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 +1240,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 +1266,21 @@ V8_ABSTRACT_OBJECT class ExtendedMap : public Map { public: // Bit positions for |bit_field_ex|. - struct BitsEx { + struct BitsEx : BitFieldGroup<BitsEx, uint8_t> { + using BitFieldGroup::BitFieldGroup; + using MapKindBits = base::BitField<ExtendedMapKind, 0, 3, uint8_t>; using MapSizeInWordsBits = MapKindBits::Next<uint8_t, 5>; + + BIT_FIELD_GETTER(map_kind, MapKindBits) + BIT_FIELD_GETTER(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 +1292,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..7e18f755c666 100644 --- a/deps/v8/src/objects/module-inl.h +++ b/deps/v8/src/objects/module-inl.h @@ -43,13 +43,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 { diff --git a/deps/v8/src/objects/module.cc b/deps/v8/src/objects/module.cc index 46c4748a66ce..db9dd67f4336 100644 --- a/deps/v8/src/objects/module.cc +++ b/deps/v8/src/objects/module.cc @@ -12,6 +12,7 @@ #include "src/ast/modules.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" @@ -384,12 +385,21 @@ DirectHandle<JSModuleNamespace> Module::GetModuleNamespace( 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(), @@ -538,6 +548,12 @@ void JSDeferredModuleNamespace::EvaluateModuleSync( return; } + // A side-effect-free debug-evaluate must not start the evaluation. + if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) { + isolate->debug()->FailSideEffectCheckForDeferredModuleEvaluation(); + return; + } + MaybeDirectHandle<JSPromise> maybe_result = Module::Evaluate(isolate, module); DirectHandle<JSPromise> promise; if (!maybe_result.ToHandle(&promise)) { diff --git a/deps/v8/src/objects/name-inl.h b/deps/v8/src/objects/name-inl.h index 823d7664b49b..993b6d81c368 100644 --- a/deps/v8/src/objects/name-inl.h +++ b/deps/v8/src/objects/name-inl.h @@ -25,11 +25,10 @@ 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); diff --git a/deps/v8/src/objects/name.h b/deps/v8/src/objects/name.h index ad2c6d438a59..6ce1fab3e4ce 100644 --- a/deps/v8/src/objects/name.h +++ b/deps/v8/src/objects/name.h @@ -306,7 +306,7 @@ V8_OBJECT class Name : public PrimitiveHeapObject { inline uint32_t GetRawHashFromForwardingTable(uint32_t raw_hash) const; - std::atomic_uint32_t raw_hash_field_; + std::atomic_uint32_t raw_hash_field_ V8_TQ_TYPE(NameHash); } V8_OBJECT_END; inline bool IsUniqueName(Tagged<Name> obj); @@ -319,8 +319,8 @@ V8_OBJECT class Symbol : public Name { using IsInPublicSymbolTableBit = IsWellKnownSymbolBit::Next<bool, 1>; using IsInterestingSymbolBit = IsInPublicSymbolTableBit::Next<bool, 1>; - 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); @@ -382,10 +382,8 @@ V8_OBJECT class Symbol : public Name { const char* PrivateSymbolToName() const; - uint32_t flags_; - // String|Undefined - // TODO(leszeks): Introduce a union type for this. - TaggedMember<PrimitiveHeapObject> description_; + uint32_t flags_ V8_TQ_TYPE(SymbolFlags); + TaggedMember<UnionOf<String, Undefined>> description_; } V8_OBJECT_END; template <> 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..156961405e2a 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) \ @@ -550,11 +551,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..e53160c9d7da 100644 --- a/deps/v8/src/objects/object-macros-undef.h +++ b/deps/v8/src/objects/object-macros-undef.h @@ -22,6 +22,18 @@ #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_NAME +#undef V8_TQ_TAIL_LENGTH +#undef V8_TQ_NO_TAIL +#undef V8_TQ_TAIL_SECTIONS +#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 +116,7 @@ #undef PROTECTED_POINTER_ACCESSORS #undef DECL_RELEASE_ACQUIRE_PROTECTED_POINTER_ACCESSORS #undef RELEASE_ACQUIRE_PROTECTED_POINTER_ACCESSORS +#undef BIT_FIELD_GETTER #undef BIT_FIELD_ACCESSORS2 #undef BIT_FIELD_ACCESSORS #undef RELAXED_INT16_ACCESSORS diff --git a/deps/v8/src/objects/object-macros.h b/deps/v8/src/objects/object-macros.h index 9ef97ab09344..e4bc63bce017 100644 --- a/deps/v8/src/objects/object-macros.h +++ b/deps/v8/src/objects/object-macros.h @@ -145,6 +145,38 @@ #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. +// The tail annotations describe whether Torque omits the flexible tail, +// represents it as one indexed field, or splits it into indexed sections. They +// annotate the class; 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_NAME(...) \ + V8_IT_MARK(TqTailName, "V8_TQ_TAIL_NAME(" #__VA_ARGS__ ")") +#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_TAIL_SECTIONS(...) \ + V8_IT_MARK(TqTailSections, "V8_TQ_TAIL_SECTIONS(" #__VA_ARGS__ ")") +#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); @@ -839,6 +871,10 @@ return ClearProtectedPointerField(offset, tag); \ } +// Defines a getter for one bit field of a BitFieldGroup. +#define BIT_FIELD_GETTER(name, Bit) \ + constexpr typename Bit::FieldType name() const { return get<Bit>(); } + #define BIT_FIELD_ACCESSORS2(holder, get_field, set_field, name, BitField) \ typename BitField::FieldType holder::name() const { \ return BitField::decode(get_field()); \ diff --git a/deps/v8/src/objects/objects-body-descriptors-inl.h b/deps/v8/src/objects/objects-body-descriptors-inl.h index eeaa90ad3214..edb25a0ac111 100644 --- a/deps/v8/src/objects/objects-body-descriptors-inl.h +++ b/deps/v8/src/objects/objects-body-descriptors-inl.h @@ -358,6 +358,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) { @@ -1507,9 +1515,6 @@ class WasmSuspenderObject::BodyDescriptor final : public BodyDescriptorBase { 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)); IterateProtectedPointer(obj, offsetof(WasmSuspenderObject, parent_), v); IteratePointer(obj, offsetof(WasmSuspenderObject, promise_), v); IteratePointer(obj, offsetof(WasmSuspenderObject, resume_), v); @@ -1638,7 +1643,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 +1800,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. 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..862ca9f53225 100644 --- a/deps/v8/src/objects/objects-inl.h +++ b/deps/v8/src/objects/objects-inl.h @@ -316,6 +316,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 <> @@ -964,20 +965,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..642b02a8d0cc 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 { @@ -4503,25 +4507,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 @@ -5062,9 +5047,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 +5057,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 +5083,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..154f62cd1266 100644 --- a/deps/v8/src/objects/objects.h +++ b/deps/v8/src/objects/objects.h @@ -188,9 +188,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> 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.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..d5406c1613a6 100644 --- a/deps/v8/src/objects/ordered-hash-table.h +++ b/deps/v8/src/objects/ordered-hash-table.h @@ -710,12 +710,19 @@ 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 + // Torque splits the flexible tail into indexed sections. + V8_TQ_TAIL_SECTIONS(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;); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, data_table); } V8_OBJECT_END; @@ -753,12 +760,19 @@ 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 + // Torque splits the flexible tail into indexed sections. + V8_TQ_TAIL_SECTIONS( + data_table[Convert<intptr>(number_of_buckets) * + kSmallOrderedHashTableLoadFactor] : HashMapEntry; + hash_table[number_of_buckets] : uint8; + chain_table[Convert<intptr>(number_of_buckets) * + kSmallOrderedHashTableLoadFactor] : uint8;); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, data_table); } V8_OBJECT_END; @@ -997,12 +1011,18 @@ 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 + // Torque splits the flexible tail into indexed sections. + V8_TQ_TAIL_SECTIONS( + data_table[Convert<intptr>(number_of_buckets) * + kSmallOrderedHashTableLoadFactor] : NameDictionaryEntry; + hash_table[number_of_buckets] : uint8; + chain_table[number_of_buckets] : uint8;); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, data_table); } V8_OBJECT_END; 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/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..5bfc93a62330 100644 --- a/deps/v8/src/objects/regexp-match-info.h +++ b/deps/v8/src/objects/regexp-match-info.h @@ -80,6 +80,8 @@ V8_OBJECT class RegExpMatchInfo TaggedMember<Smi> number_of_capture_registers_; TaggedMember<String> last_subject_; TaggedMember<Object> last_input_; + V8_TQ_TAIL_NAME(objects); + 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..1307d7be7d55 100644 --- a/deps/v8/src/objects/scope-info-inl.h +++ b/deps/v8/src/objects/scope-info-inl.h @@ -68,19 +68,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)); } // ----------------------------------------------------------------------- diff --git a/deps/v8/src/objects/scope-info.cc b/deps/v8/src/objects/scope-info.cc index 4986c640a57f..e87c6a7883b0 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" @@ -1314,18 +1317,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 +1340,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..f63bb9c6bed9 100644 --- a/deps/v8/src/objects/scope-info.h +++ b/deps/v8/src/objects/scope-info.h @@ -553,18 +553,83 @@ V8_OBJECT class ScopeInfo : public HeapObject { public: // Relaxed-atomic flags word (ScopeFlags bit layout). - std::atomic<uint32_t> flags_; + V8_TQ_CONST V8_TQ_RELAXED std::atomic<uint32_t> flags_ V8_TQ_TYPE(ScopeFlags); #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. + // These Torque sections correspond to the Foo...Offset() accessors below. + // clang-format off + V8_TQ_TAIL_SECTIONS( + const module_variable_count? + [flags.scope_type == ScopeType::MODULE_SCOPE]: Smi; + + // The names of inlined local variables and parameters allocated in + // the context, in increasing order of context slot index starting + // with Context::MIN_CONTEXT_SLOTS. + context_local_names + [Convert<intptr>(context_local_count) < kMaxInlinedLocalNamesSize + ? context_local_count + : 0]: String; + + // A hash_map from local names to context slot index, used only when + // the local names are not inlined above. + context_local_names_hashtable? + [kMaxInlinedLocalNamesSize <= Convert<intptr>(context_local_count)]: + NameToIndexHashTable; + + // The variable modes and initialization flags of the context locals. + context_local_infos[context_local_count]: SmiTagged<VariableProperties>; + + // For a class scope with static private methods reachable directly + // or through eval: the name of the class variable, or its slot index + // when the locals are inlined. + saved_class_variable_info?[flags.has_saved_class_variable]: Smi|Name; + + // For a named function expression: the name of the function variable + // and its context or stack slot index. + 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: the SourceTextModuleInfo and the metadata of + // the module-allocated variables. Empty for other scopes. + 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 name to its index in module_variables, once + // there are enough of them that a linear scan is too slow. + module_variables_hashtable? + [flags.scope_type == ScopeType::MODULE_SCOPE + ? kMaxInlinedLocalNamesSize <= + Convert<intptr>(module_variable_count) + : false]: NameToIndexHashTable; + + dependent_code?[flags.sloppy_eval_can_extend_vars]: DependentCode; + + const unused_parameter_bits? + [flags.scope_type == ScopeType::FUNCTION_SCOPE]: Smi;); + // clang-format on FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, data); } V8_OBJECT_END; 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 93de8a242af5..75f54410392c 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) + diff --git a/deps/v8/src/objects/shared-function-info.cc b/deps/v8/src/objects/shared-function-info.cc index 5151351c3ac4..3b985e28c65a 100644 --- a/deps/v8/src/objects/shared-function-info.cc +++ b/deps/v8/src/objects/shared-function-info.cc @@ -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) diff --git a/deps/v8/src/objects/shared-function-info.h b/deps/v8/src/objects/shared-function-info.h index d5f8a8fc2a94..e471ba2e3121 100644 --- a/deps/v8/src/objects/shared-function-info.h +++ b/deps/v8/src/objects/shared-function-info.h @@ -78,11 +78,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 +127,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; @@ -333,12 +335,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(); @@ -961,23 +965,33 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { inline Tagged<BytecodeArray> GetBytecodeArrayInternal(Isolate* isolate) const; public: + V8_TQ_CUSTOM_WEAK TrustedPointerMember<ExposedTrustedObject, kTrustedDataIndirectPointerRange> 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; + uint8_t flags2_ V8_TQ_TYPE(SharedFunctionInfoFlags2) = 0; + // All flags default to false or 0, except ConstructAsBuiltinBit just because + // we're using the kIllegal builtin. + std::atomic<uint32_t> flags_ V8_TQ_TYPE(SharedFunctionInfoFlags) = + ConstructAsBuiltinBit::encode(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 = @@ -1101,9 +1115,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 f4949b0bc77a..626938a36520 100644 --- a/deps/v8/src/objects/shared-function-info.tq +++ b/deps/v8/src/objects/shared-function-info.tq @@ -76,7 +76,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.h b/deps/v8/src/objects/slots.h index 5705a3b14c4d..33694b67c830 100644 --- a/deps/v8/src/objects/slots.h +++ b/deps/v8/src/objects/slots.h @@ -566,7 +566,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/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..701b94c09fc5 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 { diff --git a/deps/v8/src/objects/source-text-module.h b/deps/v8/src/objects/source-text-module.h index d473613ec20d..9d0bab988454 100644 --- a/deps/v8/src/objects/source-text-module.h +++ b/deps/v8/src/objects/source-text-module.h @@ -287,13 +287,13 @@ V8_OBJECT class SourceTextModule : public Module { TaggedMember<FixedArray> regular_exports_; TaggedMember<FixedArray> regular_imports_; 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 +353,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 +379,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 +420,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.cc b/deps/v8/src/objects/string.cc index 429cf2d21345..f291f7798486 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]))); @@ -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 { @@ -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..ff92c2d0a8fb 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,9 @@ V8_OBJECT class SeqOneByteString : public SeqString { friend class compiler::AccessBuilder; friend class TorqueGeneratedSeqOneByteStringAsserts; - FLEXIBLE_ARRAY_MEMBER(Char, chars); + V8_TQ_TAIL_NAME(chars); + V8_TQ_TAIL_LENGTH(length); + FLEXIBLE_ARRAY_MEMBER(Char, chars, V8_TQ_CONST V8_TQ_TYPE(char8)); } V8_OBJECT_END; template <> @@ -1036,7 +1042,9 @@ V8_OBJECT class SeqTwoByteString : public SeqString { friend class compiler::AccessBuilder; friend class TorqueGeneratedSeqTwoByteStringAsserts; - FLEXIBLE_ARRAY_MEMBER(Char, chars); + V8_TQ_TAIL_NAME(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..c0cc3947e208 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,51 @@ 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. + // Torque splits the flexible tail into indexed sections. + V8_TQ_TAIL_SECTIONS( + data_table[Convert<intptr>(capacity) * 2] : JSAny | TheHole; + ctrl_table[Convert<intptr>(capacity) + swiss_table::kGroupWidth] : uint8; + property_details_table[Convert<intptr>(capacity)] : uint8;); 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..91ca4dd734a9 100644 --- a/deps/v8/src/objects/swiss-name-dictionary.tq +++ b/deps/v8/src/objects/swiss-name-dictionary.tq @@ -7,7 +7,7 @@ @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; @@ -153,9 +153,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/tagged-field-inl.h b/deps/v8/src/objects/tagged-field-inl.h index 099ed0b78608..c4f2b2af2047 100644 --- a/deps/v8/src/objects/tagged-field-inl.h +++ b/deps/v8/src/objects/tagged-field-inl.h @@ -51,6 +51,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())); diff --git a/deps/v8/src/objects/tagged-field.h b/deps/v8/src/objects/tagged-field.h index d0057ef827d4..2ca4b56787f4 100644 --- a/deps/v8/src/objects/tagged-field.h +++ b/deps/v8/src/objects/tagged-field.h @@ -12,9 +12,12 @@ #include "src/common/globals.h" #include "src/common/ptr-compr.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 +41,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, @@ -79,6 +94,7 @@ 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 +116,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)); @@ -164,13 +190,15 @@ 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]; \ + __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..1d26a6b04cb5 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(); diff --git a/deps/v8/src/objects/templates.h b/deps/v8/src/objects/templates.h index 2f7c880c1f1f..beff0727e560 100644 --- a/deps/v8/src/objects/templates.h +++ b/deps/v8/src/objects/templates.h @@ -102,7 +102,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 +130,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( @@ -439,11 +442,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_; + uint32_t flag_ V8_TQ_TYPE(FunctionTemplateInfoFlags); int16_t length_; InstanceType instance_type_; uint32_t exception_context_; @@ -480,7 +484,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/trusted-pointer-inl.h b/deps/v8/src/objects/trusted-pointer-inl.h index de5dae748a0c..ed9a97340e51 100644 --- a/deps/v8/src/objects/trusted-pointer-inl.h +++ b/deps/v8/src/objects/trusted-pointer-inl.h @@ -122,6 +122,34 @@ void TrustedPointerField::ClearTrustedPointerField(Tagged<HeapObject> host, // semantics as the under-the-hood indirect pointer loads/stores use // acquire/release loads/stores anyway. template <typename T, IndirectPointerTagRange kTagRange> +TrustedPointerMember<T, kTagRange>::TrustedPointerMember( + const AllocationWitness& witness, Tagged<T> value) + : TrustedPointerMember(witness, value, witness.write_barrier_mode()) {} + +template <typename T, IndirectPointerTagRange kTagRange> +TrustedPointerMember<T, kTagRange>::TrustedPointerMember( + const AllocationWitness& witness, Tagged<T> value, WriteBarrierMode mode) { + store(witness.object(), value, mode); +} + +template <typename T, IndirectPointerTagRange 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, IndirectPointerTagRange 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, IndirectPointerTagRange kTagRange> Tagged<T> TrustedPointerMember<T, kTagRange>::load( IsolateForSandbox isolate) const { return Acquire_Load(isolate); diff --git a/deps/v8/src/objects/trusted-pointer.h b/deps/v8/src/objects/trusted-pointer.h index ebee854b11a4..57bfea83cffd 100644 --- a/deps/v8/src/objects/trusted-pointer.h +++ b/deps/v8/src/objects/trusted-pointer.h @@ -144,6 +144,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; @@ -168,7 +177,7 @@ class TrustedPointerMember inline Address storage_address() const; - std::atomic<IndirectPointerHandle> handle_; + std::atomic<IndirectPointerHandle> handle_{kNullIndirectPointerHandle}; #else using Base = TaggedMember<T>; #endif diff --git a/deps/v8/src/objects/turbofan-types.h b/deps/v8/src/objects/turbofan-types.h index e3e40914ecb7..458c7d4bc989 100644 --- a/deps/v8/src/objects/turbofan-types.h +++ b/deps/v8/src/objects/turbofan-types.h @@ -128,8 +128,8 @@ V8_OBJECT class TurbofanBitsetType : public TurbofanType { private: friend class TorqueGeneratedTurbofanBitsetTypeAsserts; - uint32_t bitset_low_; - uint32_t bitset_high_; + uint32_t bitset_low_ V8_TQ_TYPE(TurbofanTypeLowBits); + uint32_t bitset_high_ V8_TQ_TYPE(TurbofanTypeHighBits); } V8_OBJECT_END; V8_OBJECT class TurbofanUnionType : public TurbofanType { @@ -192,7 +192,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/turboshaft-types.h b/deps/v8/src/objects/turboshaft-types.h index 6a69afa9b0da..7605a534d827 100644 --- a/deps/v8/src/objects/turboshaft-types.h +++ b/deps/v8/src/objects/turboshaft-types.h @@ -70,7 +70,9 @@ V8_OBJECT class TurboshaftWord32SetType : public TurboshaftWord32Type { private: friend class TorqueGeneratedTurboshaftWord32SetTypeAsserts; - uint32_t set_size_; + V8_TQ_CONST uint32_t set_size_; + V8_TQ_TAIL_NAME(elements); + V8_TQ_TAIL_LENGTH(set_size); FLEXIBLE_ARRAY_MEMBER(uint32_t, elements); } V8_OBJECT_END; @@ -132,9 +134,12 @@ 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. + // Torque splits the flexible tail into indexed sections. + V8_TQ_TAIL_SECTIONS(elements_high[set_size] : uint32; + elements_low[set_size] : uint32;); FLEXIBLE_ARRAY_MEMBER(uint32_t, elements); } V8_OBJECT_END; @@ -155,7 +160,7 @@ V8_OBJECT class TurboshaftFloat64Type : public TurboshaftType { private: friend class TorqueGeneratedTurboshaftFloat64TypeAsserts; - uint32_t special_values_; + uint32_t special_values_ V8_TQ_TYPE(TurboshaftFloatSpecialValues); } V8_OBJECT_END; V8_OBJECT class TurboshaftFloat64RangeType : public TurboshaftFloat64Type { @@ -201,7 +206,9 @@ V8_OBJECT class TurboshaftFloat64SetType : public TurboshaftFloat64Type { private: friend class TorqueGeneratedTurboshaftFloat64SetTypeAsserts; - uint32_t set_size_; + V8_TQ_CONST uint32_t set_size_; + V8_TQ_TAIL_NAME(elements); + V8_TQ_TAIL_LENGTH(set_size); FLEXIBLE_ARRAY_MEMBER(UnalignedDoubleMember, elements); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/value-serializer.cc b/deps/v8/src/objects/value-serializer.cc index 36a784bcbf5a..ee2cd7506ea6 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)); @@ -1171,17 +1180,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 @@ -1875,7 +1884,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 +2551,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( diff --git a/deps/v8/src/parsing/expression-scope.h b/deps/v8/src/parsing/expression-scope.h index a448a4e50682..dc1329a5a5fa 100644 --- a/deps/v8/src/parsing/expression-scope.h +++ b/deps/v8/src/parsing/expression-scope.h @@ -197,6 +197,8 @@ class ExpressionScope { } else { parser_->parameters_->set_strict_parameter_error(loc, message); } + } else if (is_strict(parser_->language_mode())) { + AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); } else { parser_->next_arrow_function_info_.strict_parameter_error_location = loc; parser_->next_arrow_function_info_.strict_parameter_error_message = @@ -232,7 +234,7 @@ class ExpressionScope { } int SetInitializers(int variable_index, int peek_position) { - if (CanBeExpression()) { + if (CanBeArrowParameterDeclaration()) { return AsExpressionParsingScope()->SetInitializers(variable_index, peek_position); } @@ -243,6 +245,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 +297,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 +346,6 @@ class ExpressionScope { return base::IsInRange(type_, kMaybeArrowParameterDeclaration, kParameterDeclaration); } - bool CanBeArrowParameterDeclaration() const { - return base::IsInRange(type_, kMaybeArrowParameterDeclaration, - kMaybeAsyncArrowParameterDeclaration); - } bool IsCertainlyParameterDeclaration() const { return type_ == kParameterDeclaration; } @@ -525,7 +526,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, @@ -590,15 +591,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 +722,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 +758,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 +807,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 +861,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..f79896b3f420 100644 --- a/deps/v8/src/parsing/literal-buffer.cc +++ b/deps/v8/src/parsing/literal-buffer.cc @@ -5,6 +5,7 @@ #include "src/parsing/literal-buffer.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/execution/isolate.h" #include "src/execution/local-isolate.h" #include "src/heap/factory.h" @@ -36,13 +37,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 +58,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..9a9569d2377c 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; @@ -135,7 +136,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 5b552c583792..b5dda51c0517 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 { @@ -1175,7 +1174,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 @@ -1343,7 +1343,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 @@ -1356,7 +1357,8 @@ class ParserBase { ExpressionT ParseAssignmentExpressionCoverGrammar(); ExpressionT ParseAssignmentExpressionCoverGrammarContinuation( int lhs_beg_pos, ExpressionT expression); - ExpressionT ParseConditionalChainAssignmentExpressionCoverGrammar(); + ExpressionT ParseConditionalChainAssignmentExpressionCoverGrammar( + bool* else_found); ExpressionT ParseArrowParametersWithRest(ExpressionListT* list, AccumulationScope* scope, @@ -1398,7 +1400,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); @@ -1887,7 +1888,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; } @@ -2111,12 +2112,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); } @@ -2316,9 +2311,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; } @@ -2344,7 +2340,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); } @@ -2353,14 +2350,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; } @@ -2391,21 +2390,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()); @@ -2440,7 +2442,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); @@ -2460,8 +2461,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); @@ -2595,13 +2602,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); @@ -2610,7 +2619,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); } @@ -2960,7 +2969,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); @@ -3206,6 +3214,10 @@ void ParserBase<Impl>::ParseArguments( scanner()->peek_location(), MessageTemplate::kParamAfterRest); } } + variable_index = + expression_scope()->SetInitializers(variable_index, peek_position()); + } else { + accumulation_scope.ValidateExpression(); } if (is_spread) { *has_spread = true; @@ -3213,9 +3225,6 @@ void ParserBase<Impl>::ParseArguments( } args->Add(argument); - variable_index = - expression_scope()->SetInitializers(variable_index, peek_position()); - if (!Check(Token::kComma)) break; } @@ -3232,7 +3241,8 @@ void ParserBase<Impl>::ParseArguments( template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseConditionalChainAssignmentExpressionCoverGrammar() { +ParserBase<Impl>::ParseConditionalChainAssignmentExpressionCoverGrammar( + bool* else_found) { // AssignmentExpression :: // ArrowFunction // YieldExpression @@ -3240,6 +3250,7 @@ ParserBase<Impl>::ParseConditionalChainAssignmentExpressionCoverGrammar() { int lhs_beg_pos = peek_position(); if (peek() == Token::kYield && is_generator()) { + *else_found = true; return ParseYieldExpression(); } @@ -3251,10 +3262,12 @@ ParserBase<Impl>::ParseConditionalChainAssignmentExpressionCoverGrammar() { Token::Value op = peek(); - if (!Token::IsArrowOrAssignmentOp(op) || peek() == Token::kConditional) { + if (!Token::IsArrowOrAssignmentOp(op)) { + *else_found = (op != Token::kConditional); return expression; } + *else_found = true; return ParseAssignmentExpressionCoverGrammarContinuation(lhs_beg_pos, expression); } @@ -3375,6 +3388,7 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammarContinuation( end_position()); } 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); @@ -3462,7 +3476,7 @@ ParserBase<Impl>::ParseYieldExpression() { // Delegating yields require an RHS; fall through. [[fallthrough]]; default: - expression = ParseAssignmentExpressionCoverGrammar(); + expression = ParseAssignmentExpression(); break; } } @@ -3599,11 +3613,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; @@ -3643,33 +3655,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 @@ -3799,6 +3784,7 @@ ParserBase<Impl>::ParseUnaryOrPrefixExpression() { expression_scope()->MarkIdentifierAsAssigned(); } } else { + expression_scope()->ValidateAsExpression(); const bool early_error = false; expression = RewriteInvalidReferenceExpression( expression, expression_position, end_position(), @@ -3888,6 +3874,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(), @@ -3980,8 +3967,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; @@ -4261,7 +4247,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); @@ -4273,7 +4259,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); @@ -4304,15 +4290,15 @@ 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. @@ -4358,8 +4344,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); @@ -4916,7 +4901,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. @@ -4942,6 +4927,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); } } @@ -5173,11 +5162,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); @@ -5186,7 +5180,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, @@ -5197,7 +5190,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, @@ -5462,6 +5454,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()); } @@ -5563,8 +5558,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) { @@ -5646,14 +5640,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 { @@ -5672,30 +5669,32 @@ ParserBase<Impl>::ParsePossibleDestructuringSubPattern( AccumulationScope* scope) { if (scope) scope->Accumulate(); int begin = peek_position(); + AcceptINScope accept_in_scope(this, true); 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); + } + } else if (result->IsProperty()) { + expression_scope()->RecordDeclarationError( + Scanner::Location(begin, end_position()), + MessageTemplate::kInvalidPropertyBindingPattern); + if (scope != nullptr) scope->ValidateExpression(); } else if (result->is_parenthesized() || (!result->IsPattern() && !result->IsAssignment())) { + if (scope != nullptr) scope->ValidateExpression(); expression_scope()->RecordPatternError( Scanner::Location(begin, end_position()), MessageTemplate::kInvalidDestructuringTarget); @@ -6444,7 +6443,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); @@ -6730,7 +6729,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 && + bool expression_is_async = impl()->IsIdentifier(expression) && + scanner()->current_token() == Token::kAsync && !scanner()->literal_contains_escapes(); // Initializer is reference followed by in/of. lhs_end_pos = end_position(); @@ -6813,7 +6813,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(); @@ -6875,7 +6874,6 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { - AcceptINScope scope(this, true); enumerable = ParseAssignmentExpression(); } else { enumerable = ParseExpression(); @@ -7076,7 +7074,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ExpectContextualKeyword(Token::kOf); - const bool kAllowIn = true; ExpressionT iterable = impl()->NullExpression(); Scope* iterable_block_scope = NewScope(BLOCK_SCOPE); iterable_block_scope->set_start_position(position()); @@ -7084,7 +7081,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 94f19994ccf1..551deb2a78f7 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -520,6 +520,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: { @@ -859,6 +860,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 @@ -1434,7 +1440,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 : @@ -1455,8 +1461,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); @@ -1485,7 +1490,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()); @@ -1815,7 +1820,6 @@ Statement* Parser::ParseExportDefault() { default: { int pos = position(); - AcceptINScope scope(this, true); Expression* value = ParseAssignmentExpression(); SetFunctionName(value, ast_value_factory()->default_string()); @@ -1959,7 +1963,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(); @@ -1968,11 +1972,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()); @@ -1991,7 +1995,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()); } @@ -2203,7 +2207,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); @@ -2979,6 +2983,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)) { @@ -3264,7 +3272,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); diff --git a/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h index 5226a2ccea66..b83ed340e298 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 { @@ -275,7 +274,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 { 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..37cc7b936f62 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 { + allow_duplicate_parameters = + is_sloppy(function_scope->language_mode()) && !IsConciseMethod(kind); + } else { + SetLanguageMode(function_scope, inner_scope->language_mode()); + + 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); diff --git a/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h index beef2b93234e..5e7c70b7dd60 100644 --- a/deps/v8/src/parsing/preparser.h +++ b/deps/v8/src/parsing/preparser.h @@ -146,6 +146,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 +227,9 @@ class PreParserExpression { return TypeField::decode(code_) == kExpression && (ExpressionTypeField::decode(code_) == kPrivateReferenceExpression || ExpressionTypeField::decode(code_) == - kThisPrivateReferenceExpression); + kThisPrivateReferenceExpression || + ExpressionTypeField::decode(code_) == + kOptionalChainPrivateReferenceExpression); } bool IsCall() const { @@ -285,6 +293,7 @@ class PreParserExpression { kThisPrivateReferenceExpression, kPropertyExpression, kPrivateReferenceExpression, + kOptionalChainPrivateReferenceExpression, kCallExpression, kCallEvalExpression, kSuperCallReference, @@ -521,7 +530,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(); } diff --git a/deps/v8/src/parsing/scanner.cc b/deps/v8/src/parsing/scanner.cc index 374fc4616e14..6e2f4927d2fc 100644 --- a/deps/v8/src/parsing/scanner.cc +++ b/deps/v8/src/parsing/scanner.cc @@ -457,7 +457,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(); diff --git a/deps/v8/src/parsing/scanner.h b/deps/v8/src/parsing/scanner.h index 087963d1ad35..e2d13730757f 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. diff --git a/deps/v8/src/profiler/heap-snapshot-generator.cc b/deps/v8/src/profiler/heap-snapshot-generator.cc index 30994012c4b5..39db0b271d46 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); } @@ -1703,6 +1709,8 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, #if V8_ENABLE_WEBASSEMBLY } else if (IsWasmStruct(obj)) { ExtractWasmStructReferences(Cast<WasmStruct>(obj), entry); + } else if (IsWasmCustomMap(obj)) { + ExtractWasmCustomMapReferences(Cast<WasmCustomMap>(obj), entry); } else if (IsWasmArray(obj)) { ExtractWasmArrayReferences(Cast<WasmArray>(obj), entry); } else if (Is<WasmTrustedInstanceData>(obj)) { @@ -2089,6 +2097,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 +2117,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 +2883,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 +4380,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/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/strings-storage.cc b/deps/v8/src/profiler/strings-storage.cc index d43e039ab6e7..8666fa53afd5 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_vector(), src, len); dst[len] = '\0'; - entry->key = dst.begin(); + entry->key = dst.ReleaseData().release(); string_size_ += len; } entry->value = @@ -78,10 +80,11 @@ 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_vector(), utf8_buffer.data(), bytes_written); dst[bytes_written] = '\0'; - entry->key = dst.begin(); + entry->key = dst.ReleaseData().release(); string_size_ += bytes_written; } entry->value = @@ -113,12 +116,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_vector(), 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/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..f28136e4cd46 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); @@ -887,8 +881,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 +941,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 +1009,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 +1421,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 +1508,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 +1569,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 +1844,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 +1864,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 +1995,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 +2007,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 +2263,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 +2300,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/gen-regexp-special-case.cc b/deps/v8/src/regexp/gen-regexp-special-case.cc index db408405ba59..5094b0220277 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) { 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..c70e5b289a34 100644 --- a/deps/v8/src/regexp/regexp-compiler.cc +++ b/deps/v8/src/regexp/regexp-compiler.cc @@ -463,6 +463,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 +942,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, @@ -3541,6 +3562,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 +3624,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 +3975,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; } @@ -4499,6 +4521,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 +5474,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 +5635,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 +5704,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 +5716,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_) { @@ -6448,7 +6481,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())) { diff --git a/deps/v8/src/regexp/regexp-compiler.h b/deps/v8/src/regexp/regexp-compiler.h index d029f9ee6a48..48703933c2e9 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() { 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..746423a27922 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> @@ -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..e0bc0a536ea6 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; } } @@ -2610,8 +2553,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 +2657,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 +2815,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 +2869,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 +2910,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 +2929,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 +3044,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 +3361,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 +3474,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/riscv/regexp-macro-assembler-riscv.cc b/deps/v8/src/regexp/riscv/regexp-macro-assembler-riscv.cc index 5bb72cf147ac..0ee2b321f42a 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. @@ -755,26 +757,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 +774,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 +851,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 +903,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 +1127,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 +1144,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 +1263,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 +1491,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..821c9c4eec57 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); @@ -1482,36 +1481,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 +1585,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 +1651,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 +1921,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerX64::GetCode( __ pushq(rdi); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); CallCheckStackGuardState(); __ testq(rax, rax); @@ -1958,7 +1949,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerX64::GetCode( // Call GrowStack(isolate). - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); static constexpr int kNumArguments = 1; __ PrepareCallCFunction(kNumArguments); @@ -2072,20 +2063,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 +2251,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 +2289,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 +2301,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..7d7e62026239 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) \ @@ -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_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_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,9 @@ 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_RO_CONST V8_INLINE Tagged<ReadOnly<Type>> name() const; \ + V8_RO_CONST V8_INLINE Tagged<ReadOnly<Type>> unchecked_##name() const; READ_ONLY_ROOT_LIST(ROOT_ACCESSOR) #ifndef V8_ENABLE_TDZ_HOLE @@ -858,9 +864,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-intl-nowasm.h b/deps/v8/src/roots/static-roots-intl-nowasm.h index b1c5628998c4..5a54d5d3bbfa 100644 --- a/deps/v8/src/roots/static-roots-intl-nowasm.h +++ b/deps/v8/src/roots/static-roots-intl-nowasm.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 = @@ -1231,7 +1234,7 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kLastAllocatedRoot = 0x1a0189; }; -static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { +static constexpr std::array<Tagged_t, 1026> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kUndefinedValue, StaticReadOnlyRoot::kTheHoleValue, StaticReadOnlyRoot::kNullValue, @@ -1330,6 +1333,7 @@ static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kEphemeronHashTableMap, StaticReadOnlyRoot::kEmbedderDataArrayMap, StaticReadOnlyRoot::kWeakCellMap, + StaticReadOnlyRoot::kUninitializedHeapNumberMap, StaticReadOnlyRoot::kAtomRegExpDataMap, StaticReadOnlyRoot::kCodeMap, StaticReadOnlyRoot::kDebugInfoMap, @@ -2218,6 +2222,7 @@ static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kDebugScriptScopeInfoMap, StaticReadOnlyRoot::kEnumCacheMap, StaticReadOnlyRoot::kErrorStackDataMap, + StaticReadOnlyRoot::kForInEnumeratorHolderMap, StaticReadOnlyRoot::kFunctionTemplateRareDataMap, StaticReadOnlyRoot::kModuleRequestMap, StaticReadOnlyRoot::kPromiseCapabilityMap, diff --git a/deps/v8/src/roots/static-roots-intl-wasm.h b/deps/v8/src/roots/static-roots-intl-wasm.h index 37f33f1c0370..b707436be80a 100644 --- a/deps/v8/src/roots/static-roots-intl-wasm.h +++ b/deps/v8/src/roots/static-roots-intl-wasm.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 = @@ -1258,7 +1261,7 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kLastAllocatedRoot = 0x1c0199; }; -static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { +static constexpr std::array<Tagged_t, 1044> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kUndefinedValue, StaticReadOnlyRoot::kTheHoleValue, StaticReadOnlyRoot::kNullValue, @@ -1363,6 +1366,7 @@ static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kEphemeronHashTableMap, StaticReadOnlyRoot::kEmbedderDataArrayMap, StaticReadOnlyRoot::kWeakCellMap, + StaticReadOnlyRoot::kUninitializedHeapNumberMap, StaticReadOnlyRoot::kAtomRegExpDataMap, StaticReadOnlyRoot::kCodeMap, StaticReadOnlyRoot::kDebugInfoMap, @@ -2262,6 +2266,7 @@ static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kDebugScriptScopeInfoMap, StaticReadOnlyRoot::kEnumCacheMap, StaticReadOnlyRoot::kErrorStackDataMap, + StaticReadOnlyRoot::kForInEnumeratorHolderMap, StaticReadOnlyRoot::kFunctionTemplateRareDataMap, StaticReadOnlyRoot::kModuleRequestMap, StaticReadOnlyRoot::kPromiseCapabilityMap, diff --git a/deps/v8/src/roots/static-roots-nointl-nowasm.h b/deps/v8/src/roots/static-roots-nointl-nowasm.h index df5669009a4c..1257a8f5aae4 100644 --- a/deps/v8/src/roots/static-roots-nointl-nowasm.h +++ b/deps/v8/src/roots/static-roots-nointl-nowasm.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 = @@ -1075,7 +1078,7 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kLastAllocatedRoot = 0x1a0189; }; -static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { +static constexpr std::array<Tagged_t, 884> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kUndefinedValue, StaticReadOnlyRoot::kTheHoleValue, StaticReadOnlyRoot::kNullValue, @@ -1174,6 +1177,7 @@ static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kEphemeronHashTableMap, StaticReadOnlyRoot::kEmbedderDataArrayMap, StaticReadOnlyRoot::kWeakCellMap, + StaticReadOnlyRoot::kUninitializedHeapNumberMap, StaticReadOnlyRoot::kAtomRegExpDataMap, StaticReadOnlyRoot::kCodeMap, StaticReadOnlyRoot::kDebugInfoMap, @@ -1920,6 +1924,7 @@ static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kDebugScriptScopeInfoMap, StaticReadOnlyRoot::kEnumCacheMap, StaticReadOnlyRoot::kErrorStackDataMap, + StaticReadOnlyRoot::kForInEnumeratorHolderMap, StaticReadOnlyRoot::kFunctionTemplateRareDataMap, StaticReadOnlyRoot::kModuleRequestMap, StaticReadOnlyRoot::kPromiseCapabilityMap, diff --git a/deps/v8/src/roots/static-roots-nointl-wasm.h b/deps/v8/src/roots/static-roots-nointl-wasm.h index 346090858223..aebfabb60139 100644 --- a/deps/v8/src/roots/static-roots-nointl-wasm.h +++ b/deps/v8/src/roots/static-roots-nointl-wasm.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 = @@ -1102,7 +1105,7 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kLastAllocatedRoot = 0x1c0199; }; -static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { +static constexpr std::array<Tagged_t, 902> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kUndefinedValue, StaticReadOnlyRoot::kTheHoleValue, StaticReadOnlyRoot::kNullValue, @@ -1207,6 +1210,7 @@ static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kEphemeronHashTableMap, StaticReadOnlyRoot::kEmbedderDataArrayMap, StaticReadOnlyRoot::kWeakCellMap, + StaticReadOnlyRoot::kUninitializedHeapNumberMap, StaticReadOnlyRoot::kAtomRegExpDataMap, StaticReadOnlyRoot::kCodeMap, StaticReadOnlyRoot::kDebugInfoMap, @@ -1964,6 +1968,7 @@ static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kDebugScriptScopeInfoMap, StaticReadOnlyRoot::kEnumCacheMap, StaticReadOnlyRoot::kErrorStackDataMap, + StaticReadOnlyRoot::kForInEnumeratorHolderMap, StaticReadOnlyRoot::kFunctionTemplateRareDataMap, StaticReadOnlyRoot::kModuleRequestMap, StaticReadOnlyRoot::kPromiseCapabilityMap, 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-compiler.cc b/deps/v8/src/runtime/runtime-compiler.cc index e998c4d59f4f..c6c600b7653d 100644 --- a/deps/v8/src/runtime/runtime-compiler.cc +++ b/deps/v8/src/runtime/runtime-compiler.cc @@ -154,11 +154,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 +212,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 @@ -898,8 +907,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 +919,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 +931,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 +943,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 +955,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 +967,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..ba4222603c6d 100644 --- a/deps/v8/src/runtime/runtime-debug.cc +++ b/deps/v8/src/runtime/runtime-debug.cc @@ -781,6 +781,7 @@ RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) { DirectHandle<SharedFunctionInfo> shared(fun->shared(), isolate); isolate->debug()->DeoptimizeFunction(shared); if (isolate->debug()->last_step_action() >= StepInto || + isolate->debug()->step_over_enters_functions() || isolate->debug()->break_on_next_function_call()) { DCHECK_EQ(isolate->debug_execution_mode(), DebugInfo::kBreakpoints); isolate->debug()->PrepareStepIn(fun); 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-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..dc73915c3633 100644 --- a/deps/v8/src/runtime/runtime-object.cc +++ b/deps/v8/src/runtime/runtime-object.cc @@ -1747,7 +1747,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-test-wasm.cc b/deps/v8/src/runtime/runtime-test-wasm.cc index 1c55008f80dd..48a2fdd12841 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" @@ -778,7 +779,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 +1172,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..fb2b6651dd45 100644 --- a/deps/v8/src/runtime/runtime-test.cc +++ b/deps/v8/src/runtime/runtime-test.cc @@ -157,6 +157,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); @@ -391,8 +399,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; } @@ -878,6 +885,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: diff --git a/deps/v8/src/runtime/runtime-wasm.cc b/deps/v8/src/runtime/runtime-wasm.cc index c7a5cfee4b12..b17d38b7c448 100644 --- a/deps/v8/src/runtime/runtime-wasm.cc +++ b/deps/v8/src/runtime/runtime-wasm.cc @@ -4,6 +4,7 @@ #include <optional> +#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" @@ -169,10 +170,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 +203,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) { @@ -1026,6 +1034,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; @@ -1143,6 +1152,10 @@ 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); } @@ -1330,15 +1343,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 +1350,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); @@ -2131,6 +2132,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 +2155,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,9 +2171,9 @@ 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); } @@ -2282,8 +2288,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) { @@ -3029,12 +3034,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.h b/deps/v8/src/runtime/runtime.h index 9c9dfa45a44e..8bb3713a9307 100644 --- a/deps/v8/src/runtime/runtime.h +++ b/deps/v8/src/runtime/runtime.h @@ -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) \ @@ -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) \ diff --git a/deps/v8/src/sandbox/code-entrypoint-tag.h b/deps/v8/src/sandbox/code-entrypoint-tag.h index 7f4d16730525..36af5fb12fc7 100644 --- a/deps/v8/src/sandbox/code-entrypoint-tag.h +++ b/deps/v8/src/sandbox/code-entrypoint-tag.h @@ -32,7 +32,11 @@ 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) enum CodeEntrypointTag : uint64_t { kJSEntrypointTag = 0, kWasmEntrypointTag = uint64_t{1} << kCodeEntrypointTagShift, @@ -53,15 +57,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/external-pointer-table-inl.h b/deps/v8/src/sandbox/external-pointer-table-inl.h index a6ba845a9a09..9467e9a36db4 100644 --- a/deps/v8/src/sandbox/external-pointer-table-inl.h +++ b/deps/v8/src/sandbox/external-pointer-table-inl.h @@ -40,26 +40,6 @@ Address ExternalPointerTableEntry::GetExternalPointer( 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) { @@ -88,6 +69,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 +264,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/indirect-pointer-tag.h b/deps/v8/src/sandbox/indirect-pointer-tag.h index 725bc2fa966c..1a8455348c31 100644 --- a/deps/v8/src/sandbox/indirect-pointer-tag.h +++ b/deps/v8/src/sandbox/indirect-pointer-tag.h @@ -23,26 +23,43 @@ 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. +// 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 IndirectPointerTag : uint16_t { kIndirectPointerNullTag = 0, // Shared trusted pointers are owned by the shared Isolate and stored in the // shared trusted pointer table associated with that Isolate. - kFirstSharedTrustedPointerTag = 1, + kFirstSharedTrustedPointerTag, kSharedWasmTrustedInstanceDataIndirectPointerTag = kFirstSharedTrustedPointerTag, kSharedWasmDispatchTableIndirectPointerTag, @@ -50,17 +67,17 @@ enum IndirectPointerTag : uint16_t { // 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, + kFirstPerIsolateTrustedPointerTag, kWasmInternalFunctionIndirectPointerTag = kFirstPerIsolateTrustedPointerTag, // Untagging performance matters for this tag, so it should be "fast". - kWasmTrustedInstanceDataIndirectPointerTag = 4, + kWasmTrustedInstanceDataIndirectPointerTag, // 4 kWasmDispatchTableIndirectPointerTag, kWasmSuspenderIndirectPointerTag, kRegExpDataIndirectPointerTag, - kDebugInfoIndirectPointerTag, - kFirstSFITrustedDataTag = kDebugInfoIndirectPointerTag + 1, - kWasmExportedFunctionDataIndirectPointerTag = kFirstSFITrustedDataTag, + kFirstSFITrustedDataTag, + // Untagging performance matters for this tag, so it should be "fast". + kWasmExportedFunctionDataIndirectPointerTag = kFirstSFITrustedDataTag, // 8 kWasmCapiFunctionDataIndirectPointerTag, kInterpreterDataIndirectPointerTag, kUncompiledDataIndirectPointerTag, @@ -69,7 +86,8 @@ enum IndirectPointerTag : uint16_t { // instruction stream start is guarded by another tag (CodeEntrypointTag). kCodeIndirectPointerTag, kLastSFITrustedDataTag = kCodeIndirectPointerTag, - kLastPerIsolateTrustedPointerTag = kLastSFITrustedDataTag, + kDebugInfoIndirectPointerTag, + kLastPerIsolateTrustedPointerTag = kDebugInfoIndirectPointerTag, // The maximum tag in kAllIndirectPointerTags. Padded to a (pow2-1) to enable // fast, single-instruction bitwise untagging (see @@ -78,9 +96,9 @@ enum IndirectPointerTag : uint16_t { // 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,16 +113,19 @@ 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, + kUnpublishedIndirectPointerTag = 0x7c, // Tag for zapped entries in the trusted pointer table. - kIndirectPointerZappedEntryTag = 0xfd, + kIndirectPointerZappedEntryTag = 0x7d, // Not currently used for the trusted pointer table. - kIndirectPointerEvacuationEntryTag = 0xfe, + kIndirectPointerEvacuationEntryTag = 0x7e, // Tag for free entries in the trusted pointer table. - kIndirectPointerFreeEntryTag = 0xff, - kLastIndirectPointerTag = 0xff, + kIndirectPointerFreeEntryTag = 0x7f, + kLastIndirectPointerTag = 0x7f, }; +// All tags must fit into the 7 tag bits of an x64 trusted pointer table entry. +static_assert(kLastIndirectPointerTag <= 0x7f); + using IndirectPointerTagRange = TagRange<IndirectPointerTag>; #if V8_TARGET_ARCH_ARM64 @@ -200,9 +221,12 @@ static_assert(kAllIndirectPointerTagsIncludingUnpublished.Contains( kAllIndirectPointerTags)); // 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( IsFastIndirectPointerTag(kWasmTrustedInstanceDataIndirectPointerTag)); +static_assert( + IsFastIndirectPointerTag(kWasmExportedFunctionDataIndirectPointerTag)); V8_INLINE static constexpr bool IsSharedTrustedPointerType( IndirectPointerTag tag) { 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..2b467bfd2e71 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,8 +116,8 @@ 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) #elif defined(V8_TARGET_ARCH_32_BIT) static constexpr uintptr_t kParameterCountOffset = kCodeObjectOffset + kSystemPointerSize; @@ -140,12 +135,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 +174,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.h b/deps/v8/src/sandbox/sandbox.h index a5f97a979423..d21c894f7f80 100644 --- a/deps/v8/src/sandbox/sandbox.h +++ b/deps/v8/src/sandbox/sandbox.h @@ -85,7 +85,11 @@ class V8_EXPORT_PRIVATE Sandbox { // 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. diff --git a/deps/v8/src/sandbox/testing.cc b/deps/v8/src/sandbox/testing.cc index c459abf81560..824e71c00928 100644 --- a/deps/v8/src/sandbox/testing.cc +++ b/deps/v8/src/sandbox/testing.cc @@ -40,6 +40,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> @@ -1096,6 +1098,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 @@ -1328,9 +1336,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 +1434,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 +1451,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 +1479,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 @@ -1579,14 +1585,17 @@ 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; #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 +1610,7 @@ 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[FIXED_DOUBLE_ARRAY_TYPE]["length"] = offsetof(FixedDoubleArray, length_); fields[FIXED_DOUBLE_ARRAY_TYPE]["data"] = @@ -1656,6 +1666,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"] = @@ -1679,35 +1691,42 @@ SandboxTesting::FieldOffsetMap& SandboxTesting::GetFieldOffsetMap() { 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/snapshot/code-serializer.cc b/deps/v8/src/snapshot/code-serializer.cc index 034ef5f52ead..b14d5b515f19 100644 --- a/deps/v8/src/snapshot/code-serializer.cc +++ b/deps/v8/src/snapshot/code-serializer.cc @@ -9,6 +9,7 @@ #include "src/base/fpu.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" @@ -24,6 +25,7 @@ #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/snapshot/object-deserializer.h" #include "src/snapshot/snapshot-utils.h" @@ -45,9 +47,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) {} // static ScriptCompiler::CachedData* CodeSerializer::Serialize( @@ -76,9 +79,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,9 +111,10 @@ AlignedCachedData* CodeSerializer::SerializeSharedFunctionInfo( VisitRootPointer(Root::kHandleScope, nullptr, FullObjectSlot(info.location())); SerializeDeferredObjects(); - Pad(); + trusted_serializer_.FinishSection(); + FinishSection(); - SerializedCodeData data(sink_.data(), this); + SerializedCodeData data(Payload(), trusted_serializer_.Payload(), this); return data.GetScriptData(); } @@ -345,8 +349,8 @@ class StressOffThreadDeserializeThread final : public base::Thread { LocalIsolate local_isolate(isolate_, ThreadKind::kBackground); UnparkedScope unparked_scope(&local_isolate); LocalHandleScope handle_scope(&local_isolate); - off_thread_data_ = - CodeSerializer::StartDeserializeOffThread(&local_isolate, cached_data_); + CodeSerializer::StartDeserializeOffThread(&local_isolate, cached_data_, + &off_thread_data_); } MaybeDirectHandle<SharedFunctionInfo> Finalize( @@ -360,7 +364,7 @@ class StressOffThreadDeserializeThread final : public base::Thread { private: Isolate* isolate_; AlignedCachedData* cached_data_; - CodeSerializer::OffThreadDeserializeData off_thread_data_; + OffThreadDeserializeData off_thread_data_; }; void FinalizeDeserialization(Isolate* isolate, @@ -502,7 +506,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) { @@ -554,8 +558,7 @@ MaybeDirectHandle<SharedFunctionInfo> CodeSerializer::Deserialize( return scope.CloseAndEscape(result); } -DirectHandle<Script> CodeSerializer::OffThreadDeserializeData::GetOnlyScript( - LocalHeap* heap) { +DirectHandle<Script> OffThreadDeserializeData::GetOnlyScript(LocalHeap* heap) { std::unique_ptr<PersistentHandles> previous_persistent_handles = heap->DetachPersistentHandles(); heap->AttachPersistentHandles(std::move(persistent_handles)); @@ -573,32 +576,47 @@ DirectHandle<Script> CodeSerializer::OffThreadDeserializeData::GetOnlyScript( return script; } -CodeSerializer::OffThreadDeserializeData -CodeSerializer::StartDeserializeOffThread(LocalIsolate* local_isolate, - AlignedCachedData* cached_data) { - OffThreadDeserializeData result; - +void CodeSerializer::StartDeserializeOffThread(LocalIsolate* local_isolate, + AlignedCachedData* cached_data, + OffThreadDeserializeData* data) { DCHECK(!local_isolate->heap()->HasPersistentHandles()); const SerializedCodeData scd = SerializedCodeData::FromCachedDataWithoutSource( - local_isolate, cached_data, &result.sanity_check_result); - if (result.sanity_check_result != SerializedCodeSanityCheckResult::kSuccess) { + local_isolate, cached_data, &data->sanity_check_result); + if (data->sanity_check_result != SerializedCodeSanityCheckResult::kSuccess) { // Exit early but don't report yet, we'll re-check this when finishing on // the main thread DCHECK(cached_data->rejected()); - return result; + return; } MaybeDirectHandle<SharedFunctionInfo> local_maybe_result = OffThreadObjectDeserializer::DeserializeSharedFunctionInfo( - local_isolate, &scd, &result.scripts); + local_isolate, &scd, &data->scripts); - result.maybe_result = + data->maybe_result = local_isolate->heap()->NewPersistentMaybeHandle(local_maybe_result); - result.persistent_handles = local_isolate->heap()->DetachPersistentHandles(); + data->persistent_handles = local_isolate->heap()->DetachPersistentHandles(); +} - return result; +bool CodeSerializer::NotifySourceTextAvailable( + Isolate* isolate, OffThreadDeserializeData* data, + const AlignedCachedData* cached_data, DirectHandle<String> source, + const ScriptDetails& script_details) { + HandleScope scope(isolate); + + // Only check the source hash against the immutable cached_data header and + // write the main-thread-only data->source_sanity_check_result field here. Do + // not read/write data->sanity_check_result or mutate cached_data->Reject(), + // as StartDeserializeOffThread may still be running concurrently on a + // background thread. Full rejection and histogram reporting happen in + // FinishOffThreadDeserialize. + SerializedCodeData scd(cached_data); + SerializedCodeSanityCheckResult sanity_check_result = + scd.SanityCheckJustSource(isolate, source, script_details); + data->source_sanity_check_result = sanity_check_result; + return sanity_check_result == SerializedCodeSanityCheckResult::kSuccess; } MaybeDirectHandle<SharedFunctionInfo> @@ -614,11 +632,6 @@ CodeSerializer::FinishOffThreadDeserialize( HandleScope scope(isolate); - DirectHandle<FixedArray> wrapped_arguments; - if (!script_details.wrapped_arguments.is_null()) { - wrapped_arguments = script_details.wrapped_arguments.ToHandleChecked(); - } - // Do a source sanity check now that we have the source. It's important for // FromPartiallySanityCheckedCachedData call that the sanity_check_result // holds the result of the off-thread sanity check. @@ -626,10 +639,9 @@ CodeSerializer::FinishOffThreadDeserialize( data.sanity_check_result; const SerializedCodeData scd = SerializedCodeData::FromPartiallySanityCheckedCachedData( - cached_data, - SerializedCodeData::SourceHash(source, wrapped_arguments, - script_details.origin_options), + isolate, cached_data, data, source, script_details, &sanity_check_result); + USE(scd); if (sanity_check_result != SerializedCodeSanityCheckResult::kSuccess) { // The only case where the deserialization result could exist despite a // check failure is on a source mismatch, since we can't test for this @@ -723,13 +735,19 @@ 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>* trusted_payload, const CodeSerializer* cs) { DisallowGarbageCollection no_gc; + size_t trusted_length = 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); @@ -740,20 +758,25 @@ 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, trusted_payload->data(), trusted_length); + 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); @@ -761,7 +784,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; @@ -769,8 +792,22 @@ SerializedCodeSanityCheckResult SerializedCodeData::SanityCheck( } SerializedCodeSanityCheckResult SerializedCodeData::SanityCheckJustSource( - uint32_t expected_source_hash) const { - uint32_t source_hash = GetHeaderValue(kSourceHashOffset); + Isolate* isolate, DirectHandle<String> source, + const ScriptDetails& script_details) const { + DirectHandle<FixedArray> wrapped_arguments; + if (!script_details.wrapped_arguments.is_null()) { + wrapped_arguments = script_details.wrapped_arguments.ToHandleChecked(); + } + return SanityCheckJustSource(SourceHash( + source, wrapped_arguments, script_details.origin_options, isolate)); +} + +SerializedCodeSanityCheckResult SerializedCodeData::SanityCheckJustSource( + SourceHash expected_source_hash) const { + if (size_ < kHeaderSize) { + return SerializedCodeSanityCheckResult::kInvalidHeader; + } + SourceHash source_hash = GetHeaderSourceHash(); if (source_hash != expected_source_hash) { return SerializedCodeSanityCheckResult::kSourceMismatch; } @@ -804,6 +841,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) { @@ -813,20 +853,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>; - - 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; + 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); + } + } + + 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. @@ -839,20 +943,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); } -SerializedCodeData::SerializedCodeData(AlignedCachedData* data) +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); @@ -882,12 +994,14 @@ SerializedCodeData SerializedCodeData::FromCachedDataWithoutSource( } SerializedCodeData SerializedCodeData::FromPartiallySanityCheckedCachedData( - AlignedCachedData* cached_data, uint32_t expected_source_hash, + Isolate* isolate, AlignedCachedData* cached_data, + const OffThreadDeserializeData& data, DirectHandle<String> source, + const ScriptDetails& script_details, SerializedCodeSanityCheckResult* rejection_result) { - DisallowGarbageCollection no_gc; // The previous call to FromCachedDataWithoutSource may have already rejected // the cached data, so reuse the previous rejection result if it's not a // success. + *rejection_result = data.sanity_check_result; if (*rejection_result != SerializedCodeSanityCheckResult::kSuccess) { // FromCachedDataWithoutSource doesn't check the source, so there can't be // a source mismatch. @@ -897,7 +1011,14 @@ SerializedCodeData SerializedCodeData::FromPartiallySanityCheckedCachedData( return SerializedCodeData(nullptr, 0); } SerializedCodeData scd(cached_data); - *rejection_result = scd.SanityCheckJustSource(expected_source_hash); + if (data.source_sanity_check_result.has_value()) { + DCHECK_EQ(*data.source_sanity_check_result, + scd.SanityCheckJustSource(isolate, source, script_details)); + *rejection_result = *data.source_sanity_check_result; + } else { + *rejection_result = + scd.SanityCheckJustSource(isolate, source, script_details); + } if (*rejection_result != SerializedCodeSanityCheckResult::kSuccess) { // This check only checks the source, so the only possible failure is a // source mismatch. diff --git a/deps/v8/src/snapshot/code-serializer.h b/deps/v8/src/snapshot/code-serializer.h index ed2281113f4b..0f297ca95c3c 100644 --- a/deps/v8/src/snapshot/code-serializer.h +++ b/deps/v8/src/snapshot/code-serializer.h @@ -5,10 +5,14 @@ #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/utils/sha-256.h" namespace v8 { namespace internal { @@ -57,79 +61,76 @@ typedef v8::ScriptCompiler::CachedData::CompatibilityCheckResult // histogram definition. static_assert(static_cast<int>(SerializedCodeSanityCheckResult::kLast) == 9); -class CodeSerializer : public Serializer { - public: - struct OffThreadDeserializeData { - public: - bool HasResult() const { return !maybe_result.is_null(); } - DirectHandle<Script> GetOnlyScript(LocalHeap* heap); - - private: - friend class CodeSerializer; - MaybeIndirectHandle<SharedFunctionInfo> maybe_result; - std::vector<IndirectHandle<Script>> scripts; - std::unique_ptr<PersistentHandles> persistent_handles; - SerializedCodeSanityCheckResult sanity_check_result; - }; - - 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 = {}); - - V8_WARN_UNUSED_RESULT static OffThreadDeserializeData - StartDeserializeOffThread(LocalIsolate* isolate, - AlignedCachedData* cached_data); +class CodeSerializer; - 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); +struct OffThreadDeserializeData { + public: + bool HasResult() const { return !maybe_result.is_null(); } + DirectHandle<Script> GetOnlyScript(LocalHeap* heap); private: - void SerializeObjectImpl(Handle<HeapObject> o, SlotType slot_type) override; - - DISALLOW_GARBAGE_COLLECTION(no_gc_) - uint32_t source_hash_; + friend class CodeSerializer; + friend class SerializedCodeData; + MaybeIndirectHandle<SharedFunctionInfo> maybe_result; + std::vector<IndirectHandle<Script>> scripts; + std::unique_ptr<PersistentHandles> persistent_handles; + SerializedCodeSanityCheckResult sanity_check_result = + SerializedCodeSanityCheckResult::kSuccess; + std::optional<SerializedCodeSanityCheckResult> source_sanity_check_result; }; // 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). @@ -140,27 +141,31 @@ class SerializedCodeData : public SerializedData { // FromCachedDataWithoutSource. The rejection result from that call should be // passed into this one. static SerializedCodeData FromPartiallySanityCheckedCachedData( - AlignedCachedData* cached_data, uint32_t expected_source_hash, + Isolate* isolate, AlignedCachedData* cached_data, + const OffThreadDeserializeData& data, DirectHandle<String> source, + const ScriptDetails& script_details, SerializedCodeSanityCheckResult* rejection_result); // Used when producing. - SerializedCodeData(const std::vector<uint8_t>* payload, + SerializedCodeData(const std::vector<uint8_t>* untrusted_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: - explicit SerializedCodeData(AlignedCachedData* data); + friend class CodeSerializer; + explicit SerializedCodeData(const AlignedCachedData* data); 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); @@ -168,13 +173,89 @@ 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; + + 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: + class TrustedSectionSerializer final : public Serializer { + public: + explicit TrustedSectionSerializer(Isolate* isolate) + : Serializer(isolate, Snapshot::kDefaultSerializerFlags) {} + ~TrustedSectionSerializer() override { + OutputStatistics("TrustedSectionSerializer"); + } + + void FinishSection() { + sink_.Put(kSynchronize, "EndOfTrustedSection"); + Pad(); + } + + private: + void SerializeObjectImpl(Handle<HeapObject> o, + SlotType slot_type) override { + UNREACHABLE(); + } + }; + + void SerializeObjectImpl(Handle<HeapObject> o, SlotType slot_type) override; + void FinishSection() { + sink_.Put(kSynchronize, "EndOfUntrustedSection"); + Pad(); + } + + 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/deserializer.cc b/deps/v8/src/snapshot/deserializer.cc index 99d934927d49..147ad4cd6635 100644 --- a/deps/v8/src/snapshot/deserializer.cc +++ b/deps/v8/src/snapshot/deserializer.cc @@ -322,14 +322,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 +338,7 @@ Deserializer<IsolateT>::Deserializer(IsolateT* isolate, function_template_infos_(isolate), new_scripts_(isolate), new_exposed_trusted_objects_(isolate), + trusted_payload_(trusted_payload), deserializing_user_code_(deserializing_user_code), should_rehash_((v8_flags.rehash_snapshot && can_rehash) || deserializing_user_code), @@ -419,12 +419,42 @@ 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() { + 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_); + untrusted_back_refs_ = std::exchange(back_refs_, {}); + hot_objects_.Reset(); + while (source_.Peek() != kSynchronize) ReadObject(); + DCHECK_EQ(kSynchronize, source_.Get()); +} + template <typename IsolateT> void Deserializer<IsolateT>::LogNewMapEvents() { if (V8_LIKELY(!v8_flags.log_maps)) return; @@ -513,8 +543,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); } @@ -774,8 +802,8 @@ 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; + const uint32_t size_in_tagged = source_.GetUint30(); + const uint32_t 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 @@ -895,8 +923,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_tagged = source_.GetUint30(); + const uint32_t size_in_bytes = size_in_tagged * kTaggedSize; const InstanceType instance_type = static_cast<InstanceType>(source_.GetUint30()); @@ -1185,7 +1213,7 @@ 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(); RootIndex root_index = static_cast<RootIndex>(id); DirectHandle<HeapObject> heap_object = Cast<HeapObject>(isolate()->root_handle(root_index)); @@ -1207,7 +1235,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 +1255,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>( @@ -1301,7 +1329,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 +1361,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 +1386,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]); } @@ -1599,7 +1627,7 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadHotObject(uint8_t data, SlotAccessor slot_accessor) { - int index = HotObject::Decode(data); + uint32_t index = HotObject::Decode(data); DirectHandle<HeapObject> hot_object = hot_objects_.Get(index); if (v8_flags.trace_deserialization) { PrintF("%*sHotObject [%u] : ", depth_, "", index); @@ -1617,17 +1645,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]); } @@ -1694,12 +1723,12 @@ ExternalPointerTag Deserializer<IsolateT>::ReadExternalPointerTag() { template <typename IsolateT> Tagged<HeapObject> Deserializer<IsolateT>::Allocate( - AllocationType allocation, int size, AllocationAlignment alignment) { + AllocationType allocation, uint32_t size, AllocationAlignment alignment) { #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..d1c6106bc268 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(); @@ -148,6 +152,11 @@ class Deserializer : public SerializerDeserializer { return circular_queue_[index]; } + void Reset() { + for (auto& entry : circular_queue_) entry = {}; + index_ = 0; + } + private: static const int kSize = kHotObjectCount; static const int kSizeMask = kSize - 1; @@ -278,7 +287,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. @@ -325,6 +334,9 @@ class Deserializer : public SerializerDeserializer { std::vector<UnresolvedForwardRef> unresolved_forward_refs_; int num_unresolved_forward_refs_ = 0; + const base::Vector<const uint8_t> trusted_payload_; + std::vector<IndirectHandle<HeapObject>> untrusted_back_refs_; + const bool deserializing_user_code_; bool next_reference_is_weak_ = false; @@ -357,7 +369,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..1f9095ec6c02 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() { diff --git a/deps/v8/src/snapshot/serializer.cc b/deps/v8/src/snapshot/serializer.cc index 337fc8b243ed..51134f4cb582 100644 --- a/deps/v8/src/snapshot/serializer.cc +++ b/deps/v8/src/snapshot/serializer.cc @@ -159,6 +159,13 @@ void Serializer::SerializeDeferredObjects() { } 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. @@ -472,6 +479,9 @@ 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); @@ -1327,7 +1337,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 +1358,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) { 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/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..97240193c9ff 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; diff --git a/deps/v8/src/snapshot/snapshot.cc b/deps/v8/src/snapshot/snapshot.cc index 90b6076caba9..1030070ae557 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" @@ -526,16 +527,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 +620,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.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/strings/string-stream.cc b/deps/v8/src/strings/string-stream.cc index edfa98f7d71d..13b6096c7fc7 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" @@ -100,7 +101,7 @@ void StringStream::Add(base::Vector<const char> format, 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 +155,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(base::Vector<const char>(formatted.data(), length)); break; } case 'f': @@ -170,17 +171,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: 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/cpp-builder.cc b/deps/v8/src/torque/cpp-builder.cc index 986e33873c98..352c915ff418 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 << ", "; @@ -97,8 +104,14 @@ void Function::PrintBeginDefinition(std::ostream& stream, } 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..62122d356677 100644 --- a/deps/v8/src/torque/earley-parser.h +++ b/deps/v8/src/torque/earley-parser.h @@ -403,6 +403,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 +427,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..c02a0a90ca27 100644 --- a/deps/v8/src/torque/implementation-visitor.cc +++ b/deps/v8/src/torque/implementation-visitor.cc @@ -8,7 +8,9 @@ #include <iomanip> #include <optional> #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 +35,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 +231,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 +662,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 +1927,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 +1968,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( @@ -4216,6 +4367,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 +4390,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..352af6a21405 --- /dev/null +++ b/deps/v8/src/torque/layout-loader.cc @@ -0,0 +1,1844 @@ +// Copyright 2026 the V8 project 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); +} + +std::string TorqueBitFieldStructName(const JsonObject& storage, + const std::string& context) { + std::string name = RequireString(storage, "name", context); + size_t pos; + while ((pos = name.find("::")) != std::string::npos) { + name.erase(pos, 2); + } + return name; +} + +// 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_NAME", true, AnnotationOn::kClass}, + {"V8_TQ_TAIL_LENGTH", true, AnnotationOn::kClass}, + {"V8_TQ_NO_TAIL", false, AnnotationOn::kClass}, + {"V8_TQ_TAIL_SECTIONS", true, AnnotationOn::kClass}, +}; + +// Tails accept field annotations except the name overrides. V8_TQ_TAIL_NAME +// names the tail instead. +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_NAME" && + 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"; + } +} + +std::optional<StorageCategory> CategoryOfStorageKind(const std::string& kind) { + if (kind == "tagged") 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, + // Torque splits the tail into several indexed sections, as in ScopeInfo. + kIndexedSections, + // No V8_TQ_TAIL_* annotation: the tail cannot become a Torque field. + kUnspecified, +}; + +TailRepresentation GetTailRepresentation(const JsonObject& class_record, + const JsonObject* tail_record, + const std::string& context) { + bool has_name = HasAnnotation(class_record, "V8_TQ_TAIL_NAME", context); + bool has_length = HasAnnotation(class_record, "V8_TQ_TAIL_LENGTH", context); + bool no_tail = HasAnnotation(class_record, "V8_TQ_NO_TAIL", context); + bool sections = HasAnnotation(class_record, "V8_TQ_TAIL_SECTIONS", context); + if (has_name != has_length) { + ReportError("layout JSON: ", context, + ": V8_TQ_TAIL_NAME and V8_TQ_TAIL_LENGTH must be given " + "together"); + } + if (has_name + no_tail + sections > 1) { + ReportError("layout JSON: ", context, + ": V8_TQ_TAIL_NAME, V8_TQ_NO_TAIL and V8_TQ_TAIL_SECTIONS " + "are exclusive"); + } + if (tail_record == nullptr) { + if (has_name || no_tail || sections) { + ReportError("layout JSON: ", context, ": ", + has_name + ? "V8_TQ_TAIL_NAME" + : (no_tail ? "V8_TQ_NO_TAIL" : "V8_TQ_TAIL_SECTIONS"), + " without a flexible array member"); + } + return TailRepresentation::kNone; + } + if (has_name) return TailRepresentation::kIndexedField; + if (sections) return TailRepresentation::kIndexedSections; + 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() || + kind->ToString() != "bitfield") { + return; + } + const auto* type = + BitFieldStructType::DynamicCast(field.name_and_type.type); + if (type == nullptr) { + Error("field ", context, ": a bit field group 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 = + *AnnotationArgument(class_record, "V8_TQ_TAIL_NAME", 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_field = + *AnnotationArgument(class_record, "V8_TQ_TAIL_LENGTH", context); + auto* index = IdentifierExpression::DynamicCast(field.index->expr); + if (index == nullptr || index->name->value != length_field) { + Error("tail ", context, ": indexed by ", length_field, + " 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() || + kind->ToString() != "bitfield") { + 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; + for (size_t i = 0; i < built.size(); ++i) { + std::string a = BitFieldKey(decl.fields[i]); + std::string b = BitFieldKey(built[i]); + 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) { + return field.name_and_type.name->value + ": " + + TypeExpressionKey(field.name_and_type.type) + ": " + + std::to_string(field.num_bits) + " bit"; + } + + // Convert the storage width in bytes to a Torque unsigned integer type. + TypeExpression* BitFieldParent(const std::string& context, + const JsonObject& storage) { + 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; + size_t next_bit = 0; + 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); + // Torque derives each offset from declaration order; a gap there would + // silently shift every field after it. + size_t offset = RequireSize(b, "offset", context); + if (offset != next_bit) { + ReportError("layout JSON: ", context, ": bit field \"", cpp_name, + "\" starts at bit ", offset, ", expected ", next_bit); + } + next_bit = offset + num_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(RequireString(b, "type", context)))}, + static_cast<int>(num_bits)}); + } + 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 annotation. 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 = + is_tail + ? *AnnotationArgument(class_record, "V8_TQ_TAIL_NAME", class_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); + } else if (tail_representation == TailRepresentation::kIndexedSections) { + // C++ does not encode the Torque expressions that divide this tail. Parse + // them together at the tail position while still verifying its storage. + SourcePosition position = + positions != nullptr + ? positions->at(fields.size()) + : MemberPosition( + RequireString(*groups.back(), "cpp_name", class_name), + RequireString(*tail_record, "cpp_name", class_name), + default_position); + CurrentSourcePosition::Scope position_scope(position); + for (ClassFieldExpression& section : + ParseTorqueClassFields(*AnnotationArgument( + class_record, "V8_TQ_TAIL_SECTIONS", class_name))) { + fields.push_back(std::move(section)); + } + } + 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 = + *AnnotationArgument(class_record, "V8_TQ_TAIL_NAME", class_name); + std::string context = class_name + "." + name; + CurrentSourcePosition::Scope position_scope(position); + const std::string& length_field = + *AnnotationArgument(class_record, "V8_TQ_TAIL_LENGTH", context); + ClassFieldIndexInfo index{ + MakeNode<IdentifierExpression>(MakeNode<Identifier>(length_field)), + 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 == "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..756d4e031257 100644 --- a/deps/v8/src/torque/torque-parser.cc +++ b/deps/v8/src/torque/torque-parser.cc @@ -2578,6 +2578,11 @@ struct TorqueGrammar : Grammar { Token(";")}, MakeClassField)}; + // Result: std::vector<ClassFieldExpression> + // Entry point for V8_TQ_TAIL_SECTIONS payloads; not reachable from + // `declaration`. + Symbol* classFieldList = List<ClassFieldExpression>(&classField); + // Result: StructFieldExpression Symbol structField = { Rule({CheckIf(Token("const")), &name, Token(":"), &type, Token(";")}, @@ -2981,4 +2986,49 @@ 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*>(); +} + +std::vector<ClassFieldExpression> ParseTorqueClassFields( + const std::string& input) { + BuildFlags::Scope build_flags_scope; + TorqueGrammar& grammar = AnnotationGrammar(); + std::optional<ParseResult> result = grammar.Parse( + grammar.classFieldList, input, CurrentSourcePosition::Get()); + if (!result.has_value()) { + ReportError("cannot parse Torque field declarations: ", input); + } + return std::move(*result).Cast<std::vector<ClassFieldExpression>>(); +} + +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..1e7934737be4 100644 --- a/deps/v8/src/torque/torque-parser.h +++ b/deps/v8/src/torque/torque-parser.h @@ -14,6 +14,16 @@ 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); +// Parse a sequence of class field declarations, as carried by +// V8_TQ_TAIL_SECTIONS for a tail Torque splits into several indexed +// sections. +std::vector<ClassFieldExpression> ParseTorqueClassFields( + 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..9d58126394ac 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); + } } } diff --git a/deps/v8/src/torque/types.cc b/deps/v8/src/torque/types.cc index 397d63926a78..2ea95a27fc58 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" @@ -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/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/utils.h b/deps/v8/src/utils/utils.h index e4e6b703ae3e..370cbb619b07 100644 --- a/deps/v8/src/utils/utils.h +++ b/deps/v8/src/utils/utils.h @@ -18,6 +18,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 +481,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 +595,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; } 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..3f53594503e0 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: @@ -1733,9 +1685,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); } 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..8adb9e3b8dd8 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 @@ -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: @@ -1502,10 +1450,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, 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..e362f78d587f 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: @@ -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, 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..feaba99166a8 100644 --- a/deps/v8/src/wasm/baseline/liftoff-assembler.h +++ b/deps/v8/src/wasm/baseline/liftoff-assembler.h @@ -697,7 +697,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 +707,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); @@ -863,7 +862,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); diff --git a/deps/v8/src/wasm/baseline/liftoff-compiler.cc b/deps/v8/src/wasm/baseline/liftoff-compiler.cc index 8c8c46a46707..2ef1838fb2cc 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" @@ -899,7 +901,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 +919,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 +948,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 +1004,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; } @@ -1444,13 +1450,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 +1472,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 +1488,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 +1499,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 +1586,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 +1602,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,10 +1611,10 @@ 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_)); @@ -1758,16 +1770,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 +1857,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 +2238,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); @@ -3502,7 +3528,7 @@ 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(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 +3627,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 +4285,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 +4294,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 +4628,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 +4669,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); @@ -4778,13 +4793,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 +4807,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 +4816,14 @@ 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); + } // Convert bytes to pages. __ emit_ptrsize_shri(mem_size.gp(), mem_size.gp(), kWasmPageSizeLog2); if (imm.memory->is_memory64() && kNeedI64RegPair) { @@ -4892,11 +4909,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 +4922,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 +4941,7 @@ class LiftoffCompiler { #endif auto values = - base::OwnedVector<DebugSideTable::Entry::Value>::NewForOverwrite( + base::UniqueArray<DebugSideTable::Entry::Value>::NewForOverwrite( stack_state.size()); int index = 0; @@ -6054,7 +6071,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)) { @@ -7254,7 +7271,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 @@ -7318,6 +7336,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 +7349,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 +7377,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 +7396,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 +7445,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 +7488,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 +7524,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 +7540,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 +7550,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, @@ -8276,7 +8292,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 +8330,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 +8395,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 +8423,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 +8452,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 +8480,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 +8508,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) { @@ -8536,8 +8557,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 +8577,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). @@ -11263,16 +11283,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,14 +11321,18 @@ 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()); @@ -11363,17 +11387,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 +11449,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 +11479,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 +11501,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/loong64/liftoff-assembler-loong64-inl.h b/deps/v8/src/wasm/baseline/loong64/liftoff-assembler-loong64-inl.h index a83a6fd9182b..f49877da9339 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: @@ -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, @@ -4373,7 +4326,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(); 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..48d1c804e3c6 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: @@ -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, @@ -4246,7 +4239,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(); 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..7f24555b7264 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 @@ -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: @@ -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: 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..6ea2cbb03485 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); @@ -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..a92e7f340150 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 @@ -1129,10 +1129,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/s390/liftoff-assembler-s390-inl.h b/deps/v8/src/wasm/baseline/s390/liftoff-assembler-s390-inl.h index 36c104d65fa3..2851449d1c6d 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 @@ -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: @@ -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: 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..758d0ed0d71c 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 @@ -230,14 +230,15 @@ 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. @@ -247,8 +248,9 @@ void LiftoffAssembler::PatchPrepareStackFrame( frame_size -= kSystemPointerSize; } 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, GetTotalFrameSize() % (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 +310,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,8 +320,11 @@ 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); @@ -378,53 +385,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: @@ -1218,9 +1178,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); } @@ -4701,13 +4660,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 +4787,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,6 +4842,11 @@ 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); } @@ -4912,9 +4867,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 +4879,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 +4903,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 +4912,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 +4921,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 +4941,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,8 +4983,7 @@ 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; } @@ -5074,9 +4991,7 @@ bool LiftoffAssembler::emit_f16x8_qfma(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(FMA3)) { - return false; - } + if (!CpuFeatures::IsSupported(F16C)) return false; YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); YMMRegister tmp = YMMRegister::from_code(kScratchDoubleReg.code()); @@ -5089,9 +5004,7 @@ bool LiftoffAssembler::emit_f16x8_qfms(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(FMA3)) { - return false; - } + if (!CpuFeatures::IsSupported(F16C)) return false; YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); YMMRegister tmp = YMMRegister::from_code(kScratchDoubleReg.code()); diff --git a/deps/v8/src/wasm/c-api.cc b/deps/v8/src/wasm/c-api.cc index badd152eaa51..7817722765d6 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" @@ -1253,7 +1254,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); @@ -1364,8 +1365,8 @@ 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. 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..7a489ab4684c 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. diff --git a/deps/v8/src/wasm/compilation-hints-generation.cc b/deps/v8/src/wasm/compilation-hints-generation.cc index e0b4a48bc2a9..05162c70ca52 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" @@ -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/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..ae85a6c2ca4d 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" @@ -427,7 +429,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: @@ -1803,8 +1806,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); @@ -5010,14 +5013,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 +5038,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; } 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..dffc7ce65519 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); @@ -5240,10 +5240,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); } @@ -5441,7 +5441,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 +5687,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); } 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.cc b/deps/v8/src/wasm/interpreter/wasm-interpreter.cc index 18319e21875e..64645055623c 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> @@ -567,7 +568,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_); diff --git a/deps/v8/src/wasm/interpreter/wasm-interpreter.h b/deps/v8/src/wasm/interpreter/wasm-interpreter.h index f2a8cf630361..737de7caeee7 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> @@ -2288,10 +2289,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 +2337,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/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..cea84a1b05d6 100644 --- a/deps/v8/src/wasm/module-compiler.cc +++ b/deps/v8/src/wasm/module-compiler.cc @@ -16,6 +16,7 @@ #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" @@ -798,7 +799,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 @@ -1174,7 +1175,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 +1317,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_; @@ -1469,7 +1470,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,7 +1501,7 @@ void TransitiveTypeFeedbackProcessor::ProcessFunction(int func_index) { fm.FinalizeCall(); } - base::OwnedVector<CallSiteFeedback> result = std::move(fm).GetResult(); + base::UniqueArray<CallSiteFeedback> result = std::move(fm).GetResult(); EnqueueCallees(result.as_vector()); DCHECK_EQ(result.size(), feedback_for_function_[func_index].call_targets.size()); @@ -2073,7 +2074,7 @@ 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(); @@ -2155,7 +2156,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 +2240,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), @@ -2312,7 +2313,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 +2381,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 +2457,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(); @@ -3193,7 +3194,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()) { @@ -3382,7 +3383,7 @@ 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; @@ -3472,7 +3473,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 +3632,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 +3657,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) < @@ -3754,7 +3757,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. 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..792d68c1e9ee 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" @@ -292,9 +294,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 +411,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 +586,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 {}; @@ -2880,12 +2875,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..26b59a4d1e66 100644 --- a/deps/v8/src/wasm/module-instantiate.cc +++ b/deps/v8/src/wasm/module-instantiate.cc @@ -2145,12 +2145,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.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..f27dd578ce1d 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"); } @@ -201,18 +204,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 +229,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 +242,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)); 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..72205316f1ab 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 { @@ -63,7 +64,7 @@ class StreamingDecoder::SectionBuffer : public WireBytesStorage { 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..48d6bd8ff76e 100644 --- a/deps/v8/src/wasm/streaming-decoder.h +++ b/deps/v8/src/wasm/streaming-decoder.h @@ -14,6 +14,7 @@ #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 +68,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 +78,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 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.cc b/deps/v8/src/wasm/turboshaft-graph-interface.cc index 1fef1399ee8d..a988bcdf2200 100644 --- a/deps/v8/src/wasm/turboshaft-graph-interface.cc +++ b/deps/v8/src/wasm/turboshaft-graph-interface.cc @@ -410,7 +410,8 @@ class TurboshaftGraphBuildingInterface if (v8_flags.debug_code) { IF_NOT (LIKELY(__ HasInstanceType(trusted_instance_data, - WASM_TRUSTED_INSTANCE_DATA_TYPE))) { + WASM_TRUSTED_INSTANCE_DATA_TYPE, + SharedFlag{false}))) { OpIndex message_id = __ TaggedIndexConstant( static_cast<int32_t>(AbortReason::kUnexpectedInstanceType)); __ WasmCallRuntime(decoder->zone(), Runtime::kAbort, {message_id}, @@ -420,7 +421,7 @@ class TurboshaftGraphBuildingInterface } if (mode_ == kRegular) { - StackCheck(WasmStackCheckOp::Kind::kFunctionEntry, decoder); + StackCheck(WasmStackCheckOp::Kind::kFunctionEntry); // The stack check could make memory growth visible, so only initialize // the InstanceCache after that. instance_cache_.Initialize(trusted_instance_data, decoder->module_); @@ -544,7 +545,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 +912,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; @@ -1621,8 +1621,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); @@ -1846,7 +1851,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 +1868,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, @@ -2760,8 +2767,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_); @@ -3984,8 +3990,8 @@ 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; @@ -4055,8 +4061,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 +4072,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 +4081,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); @@ -4422,7 +4428,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()); @@ -5528,7 +5534,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 +5590,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 +5599,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 +5610,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 +5621,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 +5636,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 +5666,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 +5693,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 +5712,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 +5728,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 +5747,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 +5808,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 +5827,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 +5852,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 +5867,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; @@ -6724,7 +6741,7 @@ class TurboshaftGraphBuildingInterface 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_; + memory_size_cached_ = !memory_can_grow_; if (memory_size_cached_) { mem_size_ = LoadMemSize(); } @@ -6751,11 +6768,6 @@ class TurboshaftGraphBuildingInterface 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}; @@ -6773,15 +6785,23 @@ class TurboshaftGraphBuildingInterface 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_is_shared_) { + V<WordPtr> size_addr = + __ Load(trusted_data_, LoadOp::Kind::TaggedBase().Immutable(), + MemoryRepresentation::UintPtr(), + WasmTrustedInstanceData::kMemory0SizeOrAddressOffset); + // A relaxed (non-atomic) aligned word load is sufficient for bounds + // checks; `memory.size` uses an explicit atomic load. + LoadOp::Kind deref_kind = + memory_can_grow_ ? LoadOp::Kind::RawAligned().NotLoadEliminable() + : LoadOp::Kind::RawAligned().Immutable(); + return __ Load(size_addr, deref_kind, MemoryRepresentation::UintPtr(), + 0); } + LoadOp::Kind kind = LoadOp::Kind::TaggedBase(); if (!memory_can_grow_) kind = kind.Immutable(); return __ Load(trusted_data_, kind, MemoryRepresentation::UintPtr(), - WasmTrustedInstanceData::kMemory0SizeOffset); + WasmTrustedInstanceData::kMemory0SizeOrAddressOffset); } // For compatibility with `__` macro. @@ -8298,20 +8318,52 @@ 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) { 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)); + bool is_shared = env_->module->memories[index].is_shared.value(); + bool can_grow = env_->module->memories[index].can_grow(); + if (!is_shared) { + LoadOp::Kind kind = can_grow + ? LoadOp::Kind::TaggedBase().NotLoadEliminable() + : LoadOp::Kind::TaggedBase().Immutable(); + V<TrustedFixedAddressArray> instance_memories = + LOAD_IMMUTABLE_PROTECTED_INSTANCE_FIELD( + instance_cache_.trusted_instance_data(), MemoryBasesAndSizes, + TrustedFixedAddressArray); + return __ Load( + instance_memories, kind, MemoryRepresentation::UintPtr(), + TrustedFixedAddressArray::OffsetOfElementAt(2 * index + 1)); + } + 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 = + can_grow ? LoadOp::Kind::RawAligned().NotLoadEliminable() + : LoadOp::Kind::RawAligned().Immutable(); + return __ Load(size_address, deref_kind, MemoryRepresentation::UintPtr(), + 0); } } @@ -8388,24 +8440,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: @@ -9049,11 +9086,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 +9142,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); @@ -9230,8 +9268,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); } diff --git a/deps/v8/src/wasm/wasm-builtin-list.h b/deps/v8/src/wasm/wasm-builtin-list.h index 57b337bc8ca3..3625da8267df 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) \ @@ -191,8 +192,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..561b85b67db8 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" @@ -1958,7 +1959,7 @@ 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 { @@ -1973,13 +1974,13 @@ class NativeModuleWireBytesStorage final : public WireBytesStorage { } 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 +2597,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; @@ -2922,7 +2926,7 @@ 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; diff --git a/deps/v8/src/wasm/wasm-code-manager.h b/deps/v8/src/wasm/wasm-code-manager.h index 9f54c110103b..00d259504fa0 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" @@ -810,7 +811,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); @@ -1064,7 +1065,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..a9101dff1e37 100644 --- a/deps/v8/src/wasm/wasm-debug.cc +++ b/deps/v8/src/wasm/wasm-debug.cc @@ -8,6 +8,7 @@ #include <unordered_map> #include "src/base/logging.h" +#include "src/base/unique-array.h" #include "src/codegen/safepoint-table.h" #include "src/common/assert-scope.h" #include "src/common/simd128.h" @@ -221,35 +222,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); @@ -263,7 +282,7 @@ class DebugInfoImpl { it != end; ++it) { if (it->func_index == func_index && it->breakpoint_offsets.as_vector() == offsets && - it->dead_breakpoint == dead_breakpoint) { + it->dead_breakpoints.as_vector() == 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 +311,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 +337,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 +395,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 +416,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 +437,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(); @@ -442,7 +462,7 @@ class DebugInfoImpl { 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 above is a WasmTrapHandlerThrowTrap builtin call. StackFrameIterator it(frame->isolate()); Builtin last_builtin = Builtin::kNoBuiltinId; while (!it.done()) { @@ -452,7 +472,7 @@ class DebugInfoImpl { : Builtin::kNoBuiltinId; it.Advance(); } - if (last_builtin == Builtin::kWasmDebugTrap) { + if (last_builtin == Builtin::kWasmTrapHandlerThrowTrap) { return_location = kAfterWasmCall; } FloodWithBreakpoints(frame, return_location); @@ -477,8 +497,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 +546,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 +595,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 +616,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_) { @@ -677,7 +703,7 @@ class DebugInfoImpl { } 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 +719,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 +762,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 +807,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()); } @@ -893,8 +928,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 +1135,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 +1153,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 +1205,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 +1232,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 +1302,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 +1423,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 +1456,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..47ce2e2d8370 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,7 +51,7 @@ 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); + auto result = base::UniqueArray<uint8_t>::New(byte_size); base::Vector<uint8_t> remaining_buffer = result.as_vector(); std::memcpy(remaining_buffer.begin(), &data, sizeof(data)); remaining_buffer += sizeof(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..771fd29ff529 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(base::Vector<const char> source_url) const { + if (source_url.empty()) return is_default_url_; + return base::CStrVector(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,16 +525,19 @@ 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; @@ -617,7 +649,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::UniqueArray<const uint8_t> bytes, base::Vector<const char> source_url) { int compilation_id = next_compilation_id_.fetch_add(1); TRACE_EVENT("v8.wasm", "wasm.SyncCompile", "id", compilation_id); @@ -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); @@ -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(base::VectorOf(buffer).SubVector(0, 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,7 @@ DirectHandle<Script> CreateWasmScript( isolate, wire_bytes, module->name, kNoInternalize); DirectHandle<String> hash_str = isolate->factory() - ->NewStringFromUtf8(buffer.SubVector(0, hash_len)) + ->NewStringFromUtf8(base::VectorOf(buffer).SubVector(0, hash_len)) .ToHandleChecked(); // Concatenate the three parts. url_str = isolate->factory() @@ -1019,7 +1052,7 @@ MaybeDirectHandle<WasmModuleObject> WasmEngine::ImportNativeModule( ErrorThrower thrower(isolate, "WasmEngine::ImportNativeModule"); return SyncCompile( isolate, native_module->enabled_features(), target_imports, &thrower, - base::OwnedCopyOf(native_module->wire_bytes()), source_url); + base::UniqueCopyOf(native_module->wire_bytes()), source_url); } ModuleWireBytes wire_bytes(native_module->wire_bytes()); DirectHandle<Script> script = @@ -1097,7 +1130,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), @@ -1360,9 +1393,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,21 +1407,23 @@ 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()]; - 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(); - } - log_entry.code.insert(log_entry.code.end(), code_vec.begin(), - code_vec.end()); - - // Increment the reference count for the added {log_entry.code} entries. - for (WasmCode* code : code_vec) { - DCHECK_EQ(native_module, code->native_module()); - code->IncRef(); + for (WeakScriptHandle& weak_script_handle : script_it->second) { + IsolateInfo::CodeToLogPerScript& log_entry = + info->code_to_log[weak_script_handle.script_id()]; + 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(); + } + log_entry.code.insert(log_entry.code.end(), code_vec.begin(), + code_vec.end()); + + // Increment the reference count for the added {log_entry.code} entries. + for (WasmCode* code : code_vec) { + DCHECK_EQ(native_module, code->native_module()); + code->IncRef(); + } } } } @@ -1893,22 +1929,41 @@ DirectHandle<Script> WasmEngine::GetOrCreateScript( 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 +2091,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..492a5eb9518a 100644 --- a/deps/v8/src/wasm/wasm-engine.h +++ b/deps/v8/src/wasm/wasm-engine.h @@ -18,6 +18,7 @@ #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,7 +194,7 @@ 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 = {}); @@ -209,7 +210,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. @@ -460,7 +461,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); diff --git a/deps/v8/src/wasm/wasm-external-refs.cc b/deps/v8/src/wasm/wasm-external-refs.cc index abc56d404638..571dbe5f320d 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()); } @@ -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-js.cc b/deps/v8/src/wasm/wasm-js.cc index efffb941cc5e..7d52208313c9 100644 --- a/deps/v8/src/wasm/wasm-js.cc +++ b/deps/v8/src/wasm/wasm-js.cc @@ -16,6 +16,7 @@ #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" @@ -312,7 +313,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; @@ -354,7 +355,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 +757,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 +791,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 +919,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(); @@ -988,7 +989,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(); @@ -1242,7 +1243,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 +1499,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 +1538,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 +1780,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. @@ -2642,7 +2643,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) { @@ -3638,23 +3640,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-module-builder.cc b/deps/v8/src/wasm/wasm-module-builder.cc index be7cd905c954..63fbd59d3f11 100644 --- a/deps/v8/src/wasm/wasm-module-builder.cc +++ b/deps/v8/src/wasm/wasm-module-builder.cc @@ -459,14 +459,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}; } 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..0fb946c42b12 100644 --- a/deps/v8/src/wasm/wasm-objects-inl.h +++ b/deps/v8/src/wasm/wasm-objects-inl.h @@ -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,8 +427,14 @@ 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 { @@ -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 @@ -1392,27 +1399,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 +1451,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 +1477,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*, @@ -1509,10 +1528,11 @@ bool WasmTagObject::has_trusted_data_unpublished( } 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 +1555,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..fd1020925ea9 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" @@ -737,7 +740,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 +766,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 +900,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 +963,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 +980,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 +1072,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 +1087,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 = @@ -1084,21 +1117,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 +1150,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()); @@ -1152,8 +1191,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(); @@ -1393,20 +1434,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() + ->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 +1523,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 +1587,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( @@ -1996,8 +2061,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 +2178,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,7 +2984,7 @@ 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); return buffer.ReleaseData(); @@ -3065,10 +3128,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 { @@ -3416,6 +3476,12 @@ DirectHandle<Object> WasmToJSObject(Isolate* isolate, 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); @@ -3440,19 +3506,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..a79a8c4909c3 100644 --- a/deps/v8/src/wasm/wasm-objects.h +++ b/deps/v8/src/wasm/wasm-objects.h @@ -343,7 +343,7 @@ V8_OBJECT class WasmTableObject : public JSObject { TrustedPointerMember<WasmTrustedInstanceData, kWasmTrustedInstanceDataIndirectPointerTag> 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 @@ -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>, @@ -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 = @@ -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,9 @@ 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_NAME(supertypes); + V8_TQ_TAIL_LENGTH(supertypes_length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, supertypes); } V8_OBJECT_END; @@ -1889,8 +1916,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 +1942,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 +1956,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 +2012,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 +2096,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 +2109,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 { 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..4f742f212433 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; diff --git a/deps/v8/src/wasm/wasm-serialization.cc b/deps/v8/src/wasm/wasm-serialization.cc index de8e70d82b0f..a955b8f3a3d9 100644 --- a/deps/v8/src/wasm/wasm-serialization.cc +++ b/deps/v8/src/wasm/wasm-serialization.cc @@ -4,6 +4,7 @@ #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" @@ -322,7 +323,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 +363,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 +386,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 +396,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 +430,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)); @@ -680,7 +681,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 +817,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 +1037,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 = @@ -1054,7 +1055,7 @@ DeserializationUnit NativeModuleDeserializer::ReadCode(int fn_index, 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,7 +1200,7 @@ 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, + base::UniqueArray<const uint8_t>& wire_bytes_vec, const CompileTimeImports& compile_imports, base::Vector<const char> source_url) { if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) return {}; diff --git a/deps/v8/src/wasm/wasm-serialization.h b/deps/v8/src/wasm/wasm-serialization.h index 31becd542dd6..3e570ad246e0 100644 --- a/deps/v8/src/wasm/wasm-serialization.h +++ b/deps/v8/src/wasm/wasm-serialization.h @@ -9,6 +9,7 @@ #error This header should only be included if WebAssembly is enabled. #endif // !V8_ENABLE_WEBASSEMBLY +#include "src/base/unique-array.h" #include "src/wasm/wasm-code-manager.h" namespace v8::internal::wasm { @@ -50,7 +51,7 @@ 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, + base::UniqueArray<const uint8_t>& wire_bytes, const CompileTimeImports& compile_imports, base::Vector<const char> source_url); 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/cctest/BUILD.gn b/deps/v8/test/cctest/BUILD.gn index 396472aeb470..54acf332c6b5 100644 --- a/deps/v8/test/cctest/BUILD.gn +++ b/deps/v8/test/cctest/BUILD.gn @@ -113,14 +113,9 @@ v8_cluster_source_set("cctest_sources") { "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-limit-based-memory-reducer.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", 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.status b/deps/v8/test/cctest/cctest.status index c488e07a8bec..6b579409ea8a 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], @@ -98,7 +92,6 @@ '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], @@ -121,8 +114,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 +129,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. @@ -211,8 +199,6 @@ # 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], @@ -241,17 +227,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,10 +237,6 @@ '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', { @@ -304,12 +277,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. @@ -351,11 +318,6 @@ ['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' @@ -373,8 +335,6 @@ '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], @@ -440,12 +400,6 @@ }], # '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], @@ -635,7 +589,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], @@ -703,9 +656,6 @@ ############################################################################## ['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], @@ -743,12 +693,6 @@ '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 +705,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,7 +724,6 @@ ['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], @@ -835,13 +776,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 ################################################################################ @@ -866,12 +800,6 @@ ############################################################################## ['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 +810,10 @@ '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], diff --git a/deps/v8/test/cctest/collector.h b/deps/v8/test/cctest/collector.h index e535da7588c0..9728f0863abc 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_ >= current_chunk_.as_vector().length()) { 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 > current_chunk_.as_vector().length() - 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() > current_chunk_.as_vector().length() - 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_vector()); 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 = current_chunk_.as_vector().length(); 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 <= current_chunk_.as_vector().length()); } // 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_.as_vector().SubVector(sequence_start, + this->index_); } // 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 < new_chunk.as_vector().length()); 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/test-code-generator.cc b/deps/v8/test/cctest/compiler/test-code-generator.cc index 004525919d82..b0d03a3abb5f 100644 --- a/deps/v8/test/cctest/compiler/test-code-generator.cc +++ b/deps/v8/test/cctest/compiler/test-code-generator.cc @@ -1641,7 +1641,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()); @@ -1667,8 +1666,14 @@ TEST(TurboFanFrameSlotAlignment) { 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); } diff --git a/deps/v8/test/cctest/heap/heap-tester.h b/deps/v8/test/cctest/heap/heap-tester.h index 219cc501f274..6504e1477c99 100644 --- a/deps/v8/test/cctest/heap/heap-tester.h +++ b/deps/v8/test/cctest/heap/heap-tester.h @@ -5,73 +5,23 @@ #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) + V(StressHandles) #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 { @@ -84,27 +34,10 @@ class HeapTester { #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-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-limit-based-memory-reducer.cc b/deps/v8/test/cctest/heap/test-limit-based-memory-reducer.cc new file mode 100644 index 000000000000..85447ca90333 --- /dev/null +++ b/deps/v8/test/cctest/heap/test-limit-based-memory-reducer.cc @@ -0,0 +1,209 @@ +// 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/heap/heap-controller.h" +#include "src/heap/safepoint.h" +#include "test/cctest/cctest.h" +#include "test/cctest/heap/heap-utils.h" + +namespace v8 { +namespace internal { +namespace heap { + +class MemoryReducerMockPlatform : public MockPlatform { + public: + MemoryReducerMockPlatform() : MockPlatform() { + // 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; + } +}; + +TEST_WITH_PLATFORM(LimitBasedMemoryReducerTriggersGC, + MemoryReducerMockPlatform) { + if (!i::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; + 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::IncrementalMarking* marking = heap->incremental_marking(); + auto* memory_reducer = + static_cast<LimitBasedMemoryReducer*>(heap->memory_reducer()); + + heap->CollectGarbage(i::OLD_SPACE, i::GarbageCollectionReason::kTesting); + + CHECK(platform.PendingTask()); + CHECK(memory_reducer->is_scheduled()); + CHECK(platform.PendingTask()); + + i::heap::SimulateFullSpace(heap->old_space()); + i_isolate->factory()->NewFixedArray( + v8::internal::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_WITH_PLATFORM(LimitBasedMemoryReducerNotifyMarkCompact, + MemoryReducerMockPlatform) { + if (v8_flags.single_generation || !v8_flags.memory_reducer) return; + v8_flags.memory_reducer_delay_ms = 0; + + ManualGCScope manual_gc_scope; + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + + auto* memory_reducer = + static_cast<LimitBasedMemoryReducer*>(heap->memory_reducer()); + + LocalContext env; + HandleScope scope(isolate); + 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_WITH_PLATFORM(LimitBasedMemoryReducerBackgrounded, + MemoryReducerMockPlatform) { + if (v8_flags.single_generation || !v8_flags.memory_reducer) return; + v8_flags.memory_reducer_delay_ms = 0; + + ManualGCScope manual_gc_scope; + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + + auto* memory_reducer = + static_cast<LimitBasedMemoryReducer*>(heap->memory_reducer()); + + LocalContext env; + HandleScope scope(isolate); + 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_WITH_PLATFORM(LimitBasedMemoryReducerOvershoot, + MemoryReducerMockPlatform) { + if (v8_flags.single_generation || !v8_flags.memory_reducer) return; + v8_flags.memory_reducer_delay_ms = 0; + + ManualGCScope manual_gc_scope; + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + + i::IncrementalMarking* marking = heap->incremental_marking(); + auto* memory_reducer = + static_cast<LimitBasedMemoryReducer*>(heap->memory_reducer()); + + LocalContext env; + HandleScope scope(isolate); + 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 / i::kTaggedSize, + AllocationType::kOld); + } + heap->StartIncrementalMarking(i::GCFlag::kNoFlags, + i::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 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-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-api-array-buffer.cc b/deps/v8/test/cctest/test-api-array-buffer.cc index b2b29a1bcb45..cf83afa9a9a7 100644 --- a/deps/v8/test/cctest/test-api-array-buffer.cc +++ b/deps/v8/test/cctest/test-api-array-buffer.cc @@ -9,6 +9,7 @@ #include "src/api/api-inl.h" #include "src/base/logging.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/common/globals.h" #include "src/heap/heap.h" #include "src/objects/backing-store.h" @@ -45,7 +46,7 @@ void CheckIsDetached(v8::Local<v8::TypedArray> ta) { } void CheckIsTypedArrayVarDetached(const char* name) { - auto source = v8::base::OwnedVector<char>::NewForOverwrite(1024); + auto source = v8::base::UniqueArray<char>::NewForOverwrite(1024); v8::base::SNPrintF( source.as_vector(), "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", name, name, diff --git a/deps/v8/test/cctest/test-api-incumbent.cc b/deps/v8/test/cctest/test-api-incumbent.cc index 9eed1b36d05d..395e2135f07e 100644 --- a/deps/v8/test/cctest/test-api-incumbent.cc +++ b/deps/v8/test/cctest/test-api-incumbent.cc @@ -8,6 +8,7 @@ #include "include/v8-function.h" #include "src/api/api.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "test/cctest/cctest.h" using ::v8::Context; @@ -107,7 +108,7 @@ v8::LocalVector<Context> SetupCrossContextTest( { Context::Scope context_scope(context); - auto src = v8::base::OwnedVector<char>::NewForOverwrite(30); + auto src = v8::base::UniqueArray<char>::NewForOverwrite(30); v8::base::SNPrintF(src.as_vector(), "Object.prototype.id = %d", i); CompileRun(src.begin()); } @@ -125,7 +126,7 @@ 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); + auto name = v8::base::UniqueArray<char>::NewForOverwrite(30); v8::base::SNPrintF(name.as_vector(), "realm%d", j); CHECK(context->Global() @@ -133,7 +134,7 @@ v8::LocalVector<Context> SetupCrossContextTest( .FromJust()); // Check that 'id' property matches the realm index. - auto src = v8::base::OwnedVector<char>::NewForOverwrite(30); + auto src = v8::base::UniqueArray<char>::NewForOverwrite(30); v8::base::SNPrintF(src.as_vector(), "realm%d.id", j); Local<Value> value = CompileRun(src.begin()); CHECK_EQ(j, value.As<Integer>()->Value()); @@ -215,7 +216,7 @@ v8::LocalVector<Context> SetupCrossContextTest( expected_incumbent_context_ptr) .ToLocalChecked(); - auto name = v8::base::OwnedVector<char>::NewForOverwrite(30); + auto name = v8::base::UniqueArray<char>::NewForOverwrite(30); v8::base::SNPrintF(name.as_vector(), "realm%d.f", static_cast<int>(i)); func->SetName(v8_str(name.begin())); diff --git a/deps/v8/test/cctest/test-api-interceptors.cc b/deps/v8/test/cctest/test-api-interceptors.cc index 452bc8dfa2d2..a6e31ea2ede5 100644 --- a/deps/v8/test/cctest/test-api-interceptors.cc +++ b/deps/v8/test/cctest/test-api-interceptors.cc @@ -8,6 +8,7 @@ #include "include/v8-function.h" #include "src/api/api-inl.h" +#include "src/base/unique-array.h" #include "src/codegen/compilation-cache.h" #include "src/execution/execution.h" #include "src/objects/objects-inl.h" @@ -5925,7 +5926,7 @@ 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); + auto buf = v8::base::UniqueArray<char>::NewForOverwrite(256); v8::base::SNPrintF(buf.as_vector(), "%s:%s:%s: %s", *interface_name, *property_name, ToString(info.GetExceptionContext()), *message); diff --git a/deps/v8/test/cctest/test-api-stack-traces.cc b/deps/v8/test/cctest/test-api-stack-traces.cc index 0bda6c065827..7dbb45c5e0df 100644 --- a/deps/v8/test/cctest/test-api-stack-traces.cc +++ b/deps/v8/test/cctest/test-api-stack-traces.cc @@ -7,6 +7,7 @@ #include "include/v8-function.h" #include "src/api/api-inl.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "test/cctest/test-api.h" using ::v8::Array; @@ -746,7 +747,7 @@ TEST(SourceURLInStackTrace) { "}\n" "eval('(' + outer +')()%s');"; - auto code = v8::base::OwnedVector<char>::NewForOverwrite(1024); + auto code = v8::base::UniqueArray<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"); @@ -1609,6 +1610,112 @@ 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("eval('CaptureStack();');"); + CHECK(dynamicScriptCompiledEvents.empty()); +} + +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()); +} + void AnalyzeStackOfInlineScriptWithSourceURL( const v8::FunctionCallbackInfo<v8::Value>& info) { CHECK(i::ValidateCallbackInfo(info)); @@ -1647,7 +1754,7 @@ TEST(InlineScriptWithSourceURLInStackTrace) { "}\n" "outer()\n%s"; - auto code = v8::base::OwnedVector<char>::NewForOverwrite(1024); + auto code = v8::base::UniqueArray<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"); @@ -1692,7 +1799,7 @@ TEST(DynamicWithSourceURLInStackTrace) { "}\n" "outer()\n%s"; - auto code = v8::base::OwnedVector<char>::NewForOverwrite(1024); + auto code = v8::base::UniqueArray<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"); @@ -1712,7 +1819,7 @@ TEST(DynamicWithSourceURLInStackTraceString) { "}\n" "outer()\n%s"; - auto code = v8::base::OwnedVector<char>::NewForOverwrite(1024); + auto code = v8::base::UniqueArray<char>::NewForOverwrite(1024); v8::base::SNPrintF(code.as_vector(), source, "//# sourceURL=source_url"); v8::TryCatch try_catch(context.isolate()); CompileRunWithOrigin(code.begin(), "", 0, 0); diff --git a/deps/v8/test/cctest/test-api-typed-array.cc b/deps/v8/test/cctest/test-api-typed-array.cc index 1878d748dc02..2dbc1daff987 100644 --- a/deps/v8/test/cctest/test-api-typed-array.cc +++ b/deps/v8/test/cctest/test-api-typed-array.cc @@ -4,6 +4,7 @@ #include "src/api/api-inl.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-buffer.h" #include "src/objects/object-conversions-inl.h" @@ -107,7 +108,7 @@ void ObjectWithExternalArrayTestHelper(v8::Isolate* v8_isolate, "sum;"); CHECK_EQ(28, result->Int32Value(context).FromJust()); - auto test_buf = v8::base::OwnedVector<char>::NewForOverwrite(1024); + auto test_buf = v8::base::UniqueArray<char>::NewForOverwrite(1024); // Check legal boundary conditions. // The repeated loads and stores ensure the ICs are exercised. @@ -696,7 +697,7 @@ 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); + auto source = v8::base::UniqueArray<char>::NewForOverwrite(128); // Test on-heap sizes. for (size_t size = 0; size <= i::JSTypedArray::kMaxSizeInHeap; size += elem_size) { @@ -729,7 +730,7 @@ 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); + auto source = v8::base::UniqueArray<char>::NewForOverwrite(128); // Test off-heap sizes. size_t size = i::JSTypedArray::kMaxSizeInHeap; for (int i = 0; i < 3; i++) { diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index c98c4e2ecb33..8749b774f891 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -63,6 +63,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,7 +232,7 @@ THREADED_TEST(IsolateOfContext) { static void TestSignatureLooped(const char* operation, Local<Value> receiver, v8::Isolate* isolate) { - auto source = v8::base::OwnedVector<char>::NewForOverwrite(200); + auto source = v8::base::UniqueArray<char>::NewForOverwrite(200); v8::base::SNPrintF(source.as_vector(), "for (var i = 0; i < 10; i++) {" " %s" @@ -258,7 +259,7 @@ 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); + auto source = v8::base::UniqueArray<char>::NewForOverwrite(200); v8::base::SNPrintF(source.as_vector(), "function test() {" " %s" @@ -382,7 +383,7 @@ 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); + auto source = v8::base::UniqueArray<char>::NewForOverwrite(200); v8::base::SNPrintF(source.as_vector(), "var test_object = %s; test_object", test_objects[i]); Local<Value> test_object = CompileRun(source.begin()); @@ -3274,7 +3275,7 @@ 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); + auto source = v8::base::UniqueArray<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>(); @@ -4427,7 +4428,7 @@ class TwoPassCallbackData { trigger_gc_(false), metadata_(metadata) { HandleScope scope(isolate); - auto buffer = v8::base::OwnedVector<char>::NewForOverwrite(40); + auto buffer = v8::base::UniqueArray<char>::NewForOverwrite(40); v8::base::SNPrintF(buffer.as_vector(), "%p", static_cast<void*>(this)); auto string = v8::String::NewFromUtf8(isolate, buffer.begin()).ToLocalChecked(); @@ -4552,7 +4553,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,7 +7733,7 @@ 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); + auto extension_name = v8::base::UniqueArray<char>::NewForOverwrite(32); v8::base::SNPrintF(extension_name.as_vector(), "ext #%d", source_len); v8::RegisterExtension(std::make_unique<Extension>(extension_name.begin(), kEmbeddedExtensionSource, @@ -11306,7 +11307,7 @@ THREADED_TEST(Regress91517) { t4->InstanceTemplate()->Set(isolate, "baz", v8_num(4)); // Force dictionary-based properties. - auto name_buf = v8::base::OwnedVector<char>::NewForOverwrite(1024); + auto name_buf = v8::base::UniqueArray<char>::NewForOverwrite(1024); 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)); @@ -13626,6 +13627,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) @@ -15569,7 +15623,6 @@ static void MorphAString(i::Tagged<i::String> 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. @@ -15578,7 +15631,6 @@ static void MorphAString(i::Tagged<i::String> 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); } } @@ -19406,7 +19458,7 @@ 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); + auto code = v8::base::UniqueArray<char>::NewForOverwrite(1024); v8::base::SNPrintF(code.as_vector(), "function fib(n) {" " if (n <= 2) return 1;" @@ -21994,7 +22046,7 @@ 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); + auto source = v8::base::UniqueArray<char>::NewForOverwrite(1024); v8::base::SNPrintF(source.as_vector(), "try { %s; } catch (e) { catcher(e); }", script); CompileRun(source.begin()); @@ -22896,7 +22948,7 @@ class ApiCallOptimizationChecker { } } // build wrap_function - auto wrap_function = v8::base::OwnedVector<char>::NewForOverwrite(200); + auto wrap_function = v8::base::UniqueArray<char>::NewForOverwrite(200); if (global) { v8::base::SNPrintF(wrap_function.as_vector(), "function wrap_f_%d() { var f = g_f; return f(); }\n" @@ -22912,7 +22964,7 @@ class ApiCallOptimizationChecker { key, key, key); } // build source string - auto source = v8::base::OwnedVector<char>::NewForOverwrite(1000); + auto source = v8::base::UniqueArray<char>::NewForOverwrite(1000); v8::base::SNPrintF(source.as_vector(), "%s\n" // wrap functions "function wrap_f() { return wrap_f_%d(); }\n" @@ -26809,7 +26861,7 @@ TEST(ObjectTemplateArrayProtoIntrinsics) { }; for (unsigned i = 0; i < arraysize(intrinsics_comparisons); i++) { - auto test_string = v8::base::OwnedVector<char>::NewForOverwrite(64); + auto test_string = v8::base::UniqueArray<char>::NewForOverwrite(64); v8::base::SNPrintF(test_string.as_vector(), "typeof obj1.%s", intrinsics_comparisons[i].object_property_name); diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index 42067b6076bb..de7cb9f5f47e 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" @@ -166,11 +168,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 +181,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))); @@ -1294,9 +1296,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 +1326,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))); @@ -1407,7 +1409,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 +2628,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(); @@ -4945,7 +4947,7 @@ TEST(CpuProfileJSONSerialization) { cpu_profiler->Dispose(); CHECK_GT(stream.size(), 0); CHECK_EQ(1, stream.eos_signaled()); - auto json = base::OwnedVector<char>::NewForOverwrite(stream.size()); + auto json = base::UniqueArray<char>::NewForOverwrite(stream.size()); stream.WriteTo(json.as_vector()); // Verify that snapshot string is valid JSON. @@ -5032,7 +5034,7 @@ TEST(CpuProfileJSONSerializationWithEscapedStrings) { profile->Delete(); CHECK_GT(stream.size(), 0); CHECK_EQ(1, stream.eos_signaled()); - auto json = base::OwnedVector<char>::NewForOverwrite(stream.size()); + auto json = base::UniqueArray<char>::NewForOverwrite(stream.size()); stream.WriteTo(json.as_vector()); OneByteResource* json_res = new OneByteResource(json.as_vector()); diff --git a/deps/v8/test/cctest/test-debug-helper.cc b/deps/v8/test/cctest/test-debug-helper.cc index 7db98b96e910..a94d5f33ec92 100644 --- a/deps/v8/test/cctest/test-debug-helper.cc +++ b/deps/v8/test/cctest/test-debug-helper.cc @@ -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(); diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index aa7bbef607a6..20b1374b46cc 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) { @@ -3950,11 +4012,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 +4029,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 +7488,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..f965b6a51856 100644 --- a/deps/v8/test/cctest/test-field-type-tracking.cc +++ b/deps/v8/test/cctest/test-field-type-tracking.cc @@ -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-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index 81895814bfb2..0e0fb0beacb0 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,7 +295,7 @@ 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); + auto buffer = v8::base::UniqueArray<char>::NewForOverwrite(10); std::string_view str = i::IntToStringView(i, buffer.as_vector()); // GetProperty requires a null-terminated string. const v8::HeapGraphNode* internal = GetProperty( @@ -1365,7 +1367,7 @@ 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()); + auto json = v8::base::UniqueArray<char>::NewForOverwrite(stream.size()); stream.WriteTo(json.as_vector()); // Verify that snapshot string is valid JSON. @@ -3090,11 +3092,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 +3195,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; } @@ -4481,7 +4483,7 @@ TEST(SamplingHeapProfilerPretenuredInlineAllocations) { GrowNewSpaceToMaximumCapacity(CcTest::heap()); - auto source = v8::base::OwnedVector<char>::NewForOverwrite(1024); + auto source = v8::base::UniqueArray<char>::NewForOverwrite(1024); v8::base::SNPrintF(source.as_vector(), "var number_elements = %d;" "var elements = new Array(number_elements);" @@ -5004,7 +5006,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..161f9c2490bc 100644 --- a/deps/v8/test/cctest/test-js-to-wasm.cc +++ b/deps/v8/test/cctest/test-js-to-wasm.cc @@ -590,7 +590,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: 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..7df62bfc1b7c 100644 --- a/deps/v8/test/cctest/test-profile-generator.cc +++ b/deps/v8/test/cctest/test-profile-generator.cc @@ -27,10 +27,13 @@ // // Tests of profiles generator and utilities. +#include <array> + #include "include/v8-function.h" #include "include/v8-profiler.h" #include "src/api/api-inl.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/init/v8.h" #include "src/objects/abstract-code-inl.h" #include "src/objects/objects-inl.h" @@ -801,20 +804,19 @@ TEST(Issue51919) { CpuProfilesCollection collection(CcTest::i_isolate()); CpuProfiler profiler(CcTest::i_isolate()); collection.set_cpu_profiler(&profiler); - base::EmbeddedVector<char*, CpuProfilesCollection::kMaxSimultaneousProfiles> + std::array<base::UniqueArray<char>, + 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::UniqueArray<char> title = + v8::base::UniqueArray<char>::NewForOverwrite(16); + base::SNPrintF(title.as_vector(), "%d", i); CHECK_EQ(CpuProfilingStatus::kStarted, collection.StartProfiling(title.begin()).status); - titles[i] = title.begin(); + titles[i] = std::move(title); } 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-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..96a040102a24 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_vector()); + SnapshotData read_only_snapshot(blobs.read_only.as_vector()); + SnapshotData shared_space_snapshot(blobs.shared_space.as_vector()); 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,20 @@ 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) { +base::UniqueArray<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()); + auto source = base::UniqueArray<char>::NewForOverwrite(source_length); + CopyChars(source.begin(), head.begin(), head.length()); for (int i = 0; i < repeats; i++) { - CopyChars(source + head.length() + i * body.length(), body.begin(), + CopyChars(source.begin() + head.length() + i * body.length(), body.begin(), body.length()); } - CopyChars(source + head.length() + repeats * body.length(), tail.begin(), - tail.length()); - return base::VectorOf(source, source_length); + CopyChars(source.begin() + head.length() + repeats * body.length(), + tail.begin(), tail.length()); + return source; } v8::Isolate* Deserialize(const StartupBlobs& blobs) { @@ -278,7 +271,6 @@ void TestStartupSerializerOnceImpl() { SanityCheck(isolate); } isolate->Dispose(); - blobs.Dispose(); FreeCurrentEmbeddedBlob(); } @@ -296,7 +288,6 @@ UNINITIALIZED_TEST(StartupSerializerTwice) { isolate = Deserialize(blobs1); StartupBlobs blobs2 = Serialize(isolate); isolate->Dispose(); - blobs1.Dispose(); isolate = Deserialize(blobs2); { @@ -309,7 +300,6 @@ UNINITIALIZED_TEST(StartupSerializerTwice) { SanityCheck(isolate); } isolate->Dispose(); - blobs2.Dispose(); FreeCurrentEmbeddedBlob(); } @@ -333,7 +323,6 @@ UNINITIALIZED_TEST(StartupSerializerOnceRunScript) { CHECK_EQ(4, result.FromJust()); } isolate->Dispose(); - blobs.Dispose(); FreeCurrentEmbeddedBlob(); } @@ -345,7 +334,6 @@ UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) { isolate = Deserialize(blobs1); StartupBlobs blobs2 = Serialize(isolate); isolate->Dispose(); - blobs1.Dispose(); isolate = Deserialize(blobs2); { @@ -363,14 +351,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 +453,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_vector()); 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(); + CHECK_EQ(context_blob.as_vector(), decompressed.RawData()); } #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 +490,7 @@ UNINITIALIZED_TEST(ContextSerializerContext) { isolate->factory()->NewUninitializedJSGlobalProxy( JSGlobalProxy::SizeWithEmbedderFields(0)); { - SnapshotData snapshot_data(context_blob); + SnapshotData snapshot_data(context_blob.as_vector()); root = ContextDeserializer::DeserializeContext( isolate, &snapshot_data, 0, false, global_proxy, DeserializeEmbedderFieldsCallback( @@ -518,7 +502,7 @@ UNINITIALIZED_TEST(ContextSerializerContext) { DirectHandle<Object> root2; { - SnapshotData snapshot_data(context_blob); + SnapshotData snapshot_data(context_blob.as_vector()); root2 = ContextDeserializer::DeserializeContext( isolate, &snapshot_data, 0, false, global_proxy, DeserializeEmbedderFieldsCallback( @@ -527,18 +511,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 +550,14 @@ static void SerializeCustomContext( "var p = 0;" "(async ()=>{ p = await 42; })();"); - base::Vector<const char> source = ConstructSource( + base::UniqueArray<const char> source = ConstructSource( base::StaticCharVector("function g() { return [,"), base::StaticCharVector("1,"), base::StaticCharVector("];} 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.begin(), 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 +648,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 +669,7 @@ UNINITIALIZED_TEST(ContextSerializerCustomContext) { isolate->factory()->NewUninitializedJSGlobalProxy( JSGlobalProxy::SizeWithEmbedderFields(0)); { - SnapshotData snapshot_data(context_blob); + SnapshotData snapshot_data(context_blob.as_vector()); root = ContextDeserializer::DeserializeContext( isolate, &snapshot_data, 0, false, global_proxy, DeserializeEmbedderFieldsCallback( @@ -755,10 +738,8 @@ UNINITIALIZED_TEST(ContextSerializerCustomContext) { .FromJust(); CHECK_EQ(100002, b); } - context_blob.Dispose(); } v8_isolate->Dispose(); - blobs.Dispose(); FreeCurrentEmbeddedBlob(); } @@ -1809,7 +1790,7 @@ 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 = + base::UniqueArray<const char> source = ConstructSource(base::StaticCharVector("var a = [];"), base::StaticCharVector("a.push(function() {return 7});"), base::StaticCharVector("\0"), 10000); @@ -1831,7 +1812,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(); } @@ -2514,13 +2494,14 @@ TEST(CodeSerializerLargeCodeObject) { v8::HandleScope scope(CcTest::isolate()); - base::Vector<const char> source = ConstructSource( + base::UniqueArray<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); - Handle<String> source_str = - isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); + Handle<String> source_str = isolate->factory() + ->NewStringFromUtf8(source.as_vector()) + .ToHandleChecked(); DirectHandle<JSObject> global(isolate->context()->global_object(), isolate); AlignedCachedData* cache = nullptr; @@ -2557,7 +2538,6 @@ TEST(CodeSerializerLargeCodeObject) { CHECK_EQ(7, result_int); delete cache; - source.Dispose(); } TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) { @@ -2577,12 +2557,13 @@ TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) { v8::HandleScope scope(CcTest::isolate()); - base::Vector<const char> source = ConstructSource( + base::UniqueArray<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); - Handle<String> source_str = - isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); + Handle<String> source_str = isolate->factory() + ->NewStringFromUtf8(source.as_vector()) + .ToHandleChecked(); // Create a string on an evacuation candidate in old space. DirectHandle<String> moving_object; @@ -2642,7 +2623,6 @@ TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) { CHECK_EQ(7, result_int); delete cache; - source.Dispose(); } TEST(CodeSerializerLargeStrings) { @@ -2654,15 +2634,16 @@ TEST(CodeSerializerLargeStrings) { v8::HandleScope scope(CcTest::isolate()); - base::Vector<const char> source_s = ConstructSource( + base::UniqueArray<const char> source_s = ConstructSource( base::StaticCharVector("var s = \""), base::StaticCharVector("abcdef"), base::StaticCharVector("\";"), 1000000); - base::Vector<const char> source_t = ConstructSource( + base::UniqueArray<const char> source_t = ConstructSource( base::StaticCharVector("var t = \""), base::StaticCharVector("uvwxyz"), base::StaticCharVector("\"; s + t"), 999999); Handle<String> source_str = - f->NewConsString(f->NewStringFromUtf8(source_s).ToHandleChecked(), - f->NewStringFromUtf8(source_t).ToHandleChecked()) + f->NewConsString( + f->NewStringFromUtf8(source_s.as_vector()).ToHandleChecked(), + f->NewStringFromUtf8(source_t.as_vector()).ToHandleChecked()) .ToHandleChecked(); DirectHandle<JSObject> global(isolate->context()->global_object(), isolate); @@ -2705,8 +2686,6 @@ TEST(CodeSerializerLargeStrings) { #endif delete cache; - source_s.Dispose(); - source_t.Dispose(); } TEST(CodeSerializerThreeBigStrings) { @@ -2722,23 +2701,23 @@ 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::UniqueArray<const char> source_a = ConstructSource( base::StaticCharVector("var a = \""), base::StaticCharVector("a"), base::StaticCharVector("\";"), length_of_a); Handle<String> source_a_str = - f->NewStringFromUtf8(source_a).ToHandleChecked(); + f->NewStringFromUtf8(source_a.as_vector()).ToHandleChecked(); - base::Vector<const char> source_b = ConstructSource( + base::UniqueArray<const char> source_b = ConstructSource( base::StaticCharVector("var b = \""), base::StaticCharVector("b"), base::StaticCharVector("\";"), length_of_b); Handle<String> source_b_str = - f->NewStringFromUtf8(source_b).ToHandleChecked(); + f->NewStringFromUtf8(source_b.as_vector()).ToHandleChecked(); - base::Vector<const char> source_c = ConstructSource( + base::UniqueArray<const char> source_c = ConstructSource( base::StaticCharVector("var c = \""), base::StaticCharVector("c"), base::StaticCharVector("\";"), length_of_c); Handle<String> source_c_str = - f->NewStringFromUtf8(source_c).ToHandleChecked(); + f->NewStringFromUtf8(source_c.as_vector()).ToHandleChecked(); Handle<String> source_str = f->NewConsString( @@ -2792,9 +2771,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 @@ -2990,12 +2966,13 @@ 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::UniqueArray<const char> string = ConstructSource( base::StaticCharVector(""), base::StaticCharVector("abcdef"), base::StaticCharVector(""), 999999); - Handle<String> name = f->NewStringFromUtf8(string).ToHandleChecked(); + Handle<String> name = + f->NewStringFromUtf8(string.as_vector()).ToHandleChecked(); SerializerOneByteResource one_byte_resource( - reinterpret_cast<const char*>(string.begin()), string.length()); + reinterpret_cast<const char*>(string.begin()), string.size()); name = f->InternalizeString(name); name->MakeExternal(isolate, &one_byte_resource); CHECK(IsExternalOneByteString(*name)); @@ -3040,7 +3017,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) { @@ -3498,6 +3474,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'"; @@ -6682,6 +6682,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(); @@ -6882,7 +7152,6 @@ UNINITIALIZED_TEST(SharedStrings) { [isolate2]() { isolate2->Dispose(); }); isolate1->Dispose(); - blobs.Dispose(); FreeCurrentEmbeddedBlob(); } @@ -7033,14 +7302,82 @@ UNINITIALIZED_TEST(StaticRootsPredictableSnapshot) { // relative to the cage base are identical. However, we can't test this, since // when we create two isolates in the same process, the offsets will actually // be different. - CHECK_EQ(blobs1.read_only, blobs2.read_only); + CHECK_EQ(blobs1.read_only.as_vector(), blobs2.read_only.as_vector()); - 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; +} + } // 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..54a64fccfb72 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" @@ -649,8 +650,8 @@ class ExternalResourceFactory { TwoByteResource* CreateTwoByte(base::Vector<base::uc16> vector, bool copy = true) { if (copy) { - vector = base::VectorOf(base::OwnedCopyOf(vector).ReleaseData().release(), - vector.size()); + vector = base::VectorOf( + base::UniqueCopyOf(vector).ReleaseData().release(), vector.size()); } return CreateTwoByte(vector.data(), vector.size()); } diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index 7524353a07c5..3e20c04e7114 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.as_vector()).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..546412beccd1 100644 --- a/deps/v8/test/cctest/test-usecounters.cc +++ b/deps/v8/test/cctest/test-usecounters.cc @@ -281,6 +281,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-compilation-cache.cc b/deps/v8/test/cctest/wasm/test-compilation-cache.cc index 151bdd28a3b2..2bd6bd67162e 100644 --- a/deps/v8/test/cctest/wasm/test-compilation-cache.cc +++ b/deps/v8/test/cctest/wasm/test-compilation-cache.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" @@ -92,7 +93,7 @@ CppGCManaged<NativeModule>::Ptr SyncCompile(base::Vector<const uint8_t> bytes) { GetWasmEngine() ->SyncCompile(CcTest::i_isolate(), enabled_features, CompileTimeImports{}, &thrower, - base::OwnedCopyOf(bytes)) + base::UniqueCopyOf(bytes)) .ToHandleChecked(); return module->native_module(); } @@ -142,13 +143,13 @@ TEST(TestAsyncCache) { GetWasmEngine()->AsyncCompile( CcTest::i_isolate(), WasmEnabledFeatures::All(), CompileTimeImports{}, - resolverA1, base::OwnedCopyOf(bufferA), "WebAssembly.compile"); + resolverA1, base::UniqueCopyOf(bufferA), "WebAssembly.compile"); GetWasmEngine()->AsyncCompile( CcTest::i_isolate(), WasmEnabledFeatures::All(), CompileTimeImports{}, - resolverA2, base::OwnedCopyOf(bufferA), "WebAssembly.compile"); + resolverA2, base::UniqueCopyOf(bufferA), "WebAssembly.compile"); GetWasmEngine()->AsyncCompile( CcTest::i_isolate(), WasmEnabledFeatures::All(), CompileTimeImports{}, - resolverB, base::OwnedCopyOf(bufferB), "WebAssembly.compile"); + resolverB, base::UniqueCopyOf(bufferB), "WebAssembly.compile"); while (pending > 0) { v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(), @@ -208,7 +209,7 @@ 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 = @@ -249,7 +250,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"); diff --git a/deps/v8/test/cctest/wasm/test-gc.cc b/deps/v8/test/cctest/wasm/test-gc.cc index e3dd84d58414..92a406e617a9 100644 --- a/deps/v8/test/cctest/wasm/test-gc.cc +++ b/deps/v8/test/cctest/wasm/test-gc.cc @@ -98,8 +98,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 +946,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, {}, diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-f16.cc b/deps/v8/test/cctest/wasm/test-run-wasm-f16.cc index 1c30d81c3b12..486d1316c898 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-f16.cc +++ b/deps/v8/test/cctest/wasm/test-run-wasm-f16.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 "src/base/fpu.h" #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" @@ -207,6 +209,97 @@ 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 = [&]() { + // Native FP16 arithmetic must preserve half subnormals in either mode. + for (bool flush_denormals : {false, true}) { + base::FlushDenormalsScope denormals_scope(flush_denormals); + 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) { + 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(0xadd16); + 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_EXEC_TEST(F16x8ConvertI16x8) { i::v8_flags.wasm_fp16 = true; WasmRunner<int32_t, int32_t> r(execution_tier); diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-js.cc b/deps/v8/test/cctest/wasm/test-run-wasm-js.cc index 1e90333e968c..a5e101e95dcd 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-js.cc +++ b/deps/v8/test/cctest/wasm/test-run-wasm-js.cc @@ -7,6 +7,8 @@ #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" @@ -52,14 +54,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; diff --git a/deps/v8/test/cctest/wasm/test-wasm-breakpoints.cc b/deps/v8/test/cctest/wasm/test-wasm-breakpoints.cc index c7a2ce60ae59..5b99f096f591 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-breakpoints.cc +++ b/deps/v8/test/cctest/wasm/test-wasm-breakpoints.cc @@ -8,6 +8,7 @@ #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" @@ -586,6 +587,62 @@ 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, base::CStrVector("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)); +} + } // namespace wasm } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/wasm/test-wasm-metrics.cc b/deps/v8/test/cctest/wasm/test-wasm-metrics.cc index fc75c7cefa1e..e654c91ee43d 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-metrics.cc +++ b/deps/v8/test/cctest/wasm/test-wasm-metrics.cc @@ -9,6 +9,7 @@ #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" @@ -289,7 +290,7 @@ COMPILE_TEST(TestEventMetrics) { test::CompilationStatus status = test::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, diff --git a/deps/v8/test/cctest/wasm/test-wasm-serialization.cc b/deps/v8/test/cctest/wasm/test-wasm-serialization.cc index 586563809bdc..4ded28d01cb8 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-serialization.cc +++ b/deps/v8/test/cctest/wasm/test-wasm-serialization.cc @@ -9,6 +9,7 @@ #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" @@ -74,8 +75,8 @@ class WasmSerializationTest { base::Vector<const char> 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()), @@ -151,7 +152,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(); @@ -333,7 +334,7 @@ UNINITIALIZED_TEST(CompiledWasmModulesTransfer) { 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 = @@ -405,9 +406,10 @@ TEST(SerializeLiftoffModuleFails) { 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(); @@ -455,8 +457,8 @@ TEST(SerializeTieringBudget) { 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()); + base::UniqueArray<const uint8_t> wire_bytes_copy = + base::UniqueCopyOf(test.wire_bytes()); CHECK( DeserializeNativeModule( isolate, WasmEnabledFeatures::FromIsolate(isolate), @@ -566,7 +568,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(); @@ -630,7 +632,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(); } @@ -643,8 +646,8 @@ TEST(DeserializeIndirectCallWithDifferentCanonicalId) { deserialization_context->Enter(); ErrorThrower thrower(i_isolate, ""); base::Vector<const char> kNoSourceUrl; - base::OwnedVector<const uint8_t> wire_bytes_copy = - base::OwnedCopyOf(zone_buffer); + base::UniqueArray<const uint8_t> wire_bytes_copy = + base::UniqueCopyOf(zone_buffer); DirectHandle<WasmModuleObject> module_object = DeserializeNativeModule( i_isolate, WasmEnabledFeatures::FromIsolate(i_isolate), @@ -739,7 +742,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}}, @@ -801,8 +804,8 @@ TEST(SerializeDetectedFeatures) { deserialization_context->Enter(); ErrorThrower thrower(i_isolate, ""); base::Vector<const char> kNoSourceUrl; - base::OwnedVector<const uint8_t> wire_bytes_copy = - base::OwnedCopyOf(buffer); + base::UniqueArray<const uint8_t> wire_bytes_copy = + base::UniqueCopyOf(buffer); DirectHandle<WasmModuleObject> module_object = DeserializeNativeModule( i_isolate, WasmEnabledFeatures::FromIsolate(i_isolate), diff --git a/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc b/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc index f1e12776bd96..33e2a8c2880c 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc +++ b/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc @@ -5,6 +5,7 @@ #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" @@ -162,7 +163,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); diff --git a/deps/v8/test/common/wasm/fuzzer-common.cc b/deps/v8/test/common/wasm/fuzzer-common.cc index 4f3ba70d0ca3..be5bc0069698 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 @@ -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; @@ -1072,7 +1116,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 +1444,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..e6246deec2aa 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_; } @@ -385,8 +405,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,7 +492,7 @@ 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}; DirectHandle<Script> script = @@ -527,7 +547,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..17adc816d599 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 }; 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/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/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/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/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..59260906e76a 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 @@ -22,5 +22,5 @@ let instance = builder.instantiate(); // CHECK: MERGE B0 // CHECK-NEXT: 0: Parameter()[1] // CHECK-NEXT: 1: Constant()[word32: 0] -// CHECK-NEXT: 2: Return(#1, #0)[0] +// CHECK-NEXT: 2: Return(#1, #0) instance.exports.externConvertAny(); 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/deopt.cc b/deps/v8/test/fuzzer/wasm/deopt.cc index 104b5153157a..1eb0120c296d 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()); 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-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..70d91400b65d 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" @@ -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..ba536e300df1 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" @@ -137,7 +138,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/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/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..023ba5a2297d --- /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 + +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(new Array(10000).fill(0)); + 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..49dd709600e0 --- /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 + +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(new Array(10000).fill(0)); + 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/scope-chain-outer-scopes-expected.txt b/deps/v8/test/inspector/debugger/scope-chain-outer-scopes-expected.txt new file mode 100644 index 000000000000..5a2291f3227c --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-chain-outer-scopes-expected.txt @@ -0,0 +1,231 @@ +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: testSloppyDirectEvalInCatchAndWith +Paused in sloppyInner: +[0] local name=sloppyInner emptyReason=no-variables 0:44-0:60 [anonymous #1] +[1] with name=sloppyDirectEval 56:32-58:5 + withProp : "withProp" +[2] catch name=sloppyDirectEval 55:29-59:3 + caught : "err" +[3] closure name=sloppyDirectEval 53:25-60: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 64:2-68:3 + blockVar : "block" +[2] closure name=setVariableInCaller 62:28-69:1 + outerVar : "outer" + arguments : Arguments(0) +[3] global + setVariableValue(1, blockVar): ok + setVariableValue(2, outerVar): ok +Result: "new outerVar new blockVar" 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..ec8dddd1de9c --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-chain-outer-scopes.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. + +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 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; + } +} +//# 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 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)}`); + }, +]); 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/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/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/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-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/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/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..b7bfe9b34d52 --- /dev/null +++ b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result-expected.txt @@ -0,0 +1,32 @@ +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]}) + +Running test: testRuntimeEvaluateDeepSerialization +deep serialization with side-effect getter: 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) + +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 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..4719e33b0fc6 --- /dev/null +++ b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result.js @@ -0,0 +1,204 @@ +// Copyright 2026 the V8 project 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 makePureObject() { + return {a: 42, nested: [1, 2]}; + } + var globalObjEvalJson = makeObjectWithSideEffectGetter('eval-json'); + var globalObjEvalDeep = makeObjectWithSideEffectGetter('eval-deep'); + var globalProxyEvalJson = makeProxyWithSideEffectTrap('proxy-ownKeys'); + 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, + })); + }, + + async function testRuntimeEvaluateDeepSerialization() { + await logResult( + 'deep serialization with side-effect getter', + await Protocol.Runtime.evaluate({ + expression: 'globalObjEvalDeep', + 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, + })); + }, + + 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); + }, +]); 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.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/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/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/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/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/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/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/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/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-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-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-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-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-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/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/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/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/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-564326894.js b/deps/v8/test/mjsunit/maglev/regress-564326894.js new file mode 100644 index 000000000000..0a48ca5b224a --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-564326894.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 --maglev + +const arr = [1.5, ,]; + +function foo(a) { + let x = a[0]; + let y = a[0]; + for (let i = 0; i < 5; i++) { + const t = (y | 0) + y; + y = x; + x = t; + } + return x; +} + +%PrepareFunctionForOptimization(foo); +assertEquals(8.5, foo(arr)); +assertEquals(8.5, foo(arr)); +%OptimizeMaglevOnNextCall(foo); +assertEquals(8.5, foo(arr)); +assertOptimized(foo); + +// Passing a hole when feedback only saw Number must still deopt and return NaN. +assertEquals(NaN, foo([, 1.5])); +assertUnoptimized(foo); 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-569286602-1.js b/deps/v8/test/mjsunit/maglev/regress-569286602-1.js new file mode 100644 index 000000000000..b89ebdcb4828 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-569286602-1.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 --maglev + +function f(r) { + let pos; + while ('a'.startsWith('b', pos)) { do { pos = 1; } while (pos); } + r.push(pos); +} + +%PrepareFunctionForOptimization(f); +let a = [{}]; +assertEquals(undefined, f(a)); +assertEquals([{}, undefined], a); +let b = [1]; +assertEquals(undefined, f(b)); +assertEquals([1, undefined], b); + +%OptimizeMaglevOnNextCall(f); +let c = [1]; +assertEquals(undefined, f(c)); +assertEquals([1, undefined], c); diff --git a/deps/v8/test/mjsunit/maglev/regress-569286602-2.js b/deps/v8/test/mjsunit/maglev/regress-569286602-2.js new file mode 100644 index 000000000000..dc186b862a9b --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-569286602-2.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 --maglev + +function f(r) { + let pos; + while ('a'.startsWith('b', pos)) { do { pos = 1; } while (pos); } + if (r) r.push(pos); +} + +%PrepareFunctionForOptimization(f); +let a = [{}]; +assertEquals(undefined, f(a)); +assertEquals([{}, undefined], a); +let b = [1]; +assertEquals(undefined, f(b)); +assertEquals([1, undefined], b); + +%OptimizeMaglevOnNextCall(f); +let c = [1]; +assertEquals(undefined, f(c)); +assertEquals([1, undefined], c); 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/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/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 af6517a6a8f1..b7388d4574a9 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -228,6 +228,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. @@ -320,6 +321,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. @@ -949,6 +952,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 +969,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 +993,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,6 +1020,7 @@ 'regress/wasm/regress-350779988': [SKIP], 'regress/wasm/regress-366350772': [SKIP], 'regress/wasm/regress-397043084': [SKIP], + 'regress/wasm/regress-523591366': [SKIP], 'wasm/denormals': [SKIP], 'wasm/deopt/*': [SKIP], 'wasm/enter-debug-state': [SKIP], @@ -1074,6 +1083,7 @@ 'regress/wasm/regress-521064735': [SKIP], 'regress/wasm/regress-524830496': [SKIP], 'regress/wasm/regress-536581698': [SKIP], + 'regress/wasm/regress-552026580': [SKIP], 'regress/wasm/regress-565565747': [SKIP], 'wasm/shared-everything/*': [SKIP], 'wasm/subtyping-invalid': [SKIP], @@ -1099,6 +1109,9 @@ # --wasm-fp16 'regress/wasm/regress-499027764': [SKIP], 'regress/wasm/regress-504612573': [SKIP], + 'regress/wasm/regress-565847635': [SKIP], + 'regress/wasm/regress-570433264': [SKIP], + 'regress/wasm/regress-simd-526303932': [SKIP], 'wasm/fp16-load-mul': [SKIP], 'wasm/fp16-oob-trap': [SKIP], 'wasm/fp16-store': [SKIP], @@ -1139,8 +1152,11 @@ '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], 'wasm/custom-descriptors*': [SKIP], 'wasm/exact-types': [SKIP], + 'wasm/wasm-gc-js-roundtrip': [SKIP], # --wasm-compact-imports 'wasm/compact-imports': [SKIP], @@ -1149,6 +1165,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 @@ -1233,11 +1250,15 @@ '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-555760230': [SKIP], + 'regress/wasm/regress-simd-555806042*': [SKIP], + 'regress/wasm/regress-simd-557107349': [SKIP], 'wasm/bit-shift-right': [SKIP], 'wasm/bounds-check-turbofan': [SKIP], 'wasm/enter-and-leave-debug-state': [SKIP], @@ -1283,6 +1304,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 +1398,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 +1426,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 @@ -2785,6 +2810,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 +2890,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], @@ -2998,10 +3028,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', { @@ -3067,6 +3102,10 @@ 'regress/regress-425583995': [SKIP], 'regress/regress-490446682': [SKIP], 'regress/regress-506499280-extended': [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], @@ -3186,6 +3225,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], @@ -3265,12 +3306,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. 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..52b0fe148be9 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('⚽')); 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-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-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-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-566091009.js b/deps/v8/test/mjsunit/regress/regress-566091009.js new file mode 100644 index 000000000000..aaf8c217d3c7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-566091009.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: --no-lazy-feedback-allocation --allow-natives-syntax + +(function TestAccessCheck() { + const target = d8.test.createAccessCheckedObject(true); + target[0] = "secret"; + d8.test.setAccessPolicy(target, false); + + const namedObj = { a: 1 }; + + // 1. KeyedLoadIC: transition from named property access to element access. + function read(obj, key) { + return obj[key]; + } + read(namedObj, "a"); + assertThrows(() => read(target, "a"), TypeError); + read([1.1], 0); + assertThrows(() => read(target, 0), TypeError); + + // 2. KeyedHasIC: transition from named property access to element access. + function has(obj, key) { + return key in obj; + } + has(namedObj, "a"); + assertThrows(() => has(target, "a"), TypeError); + has([1.1], 0); + assertThrows(() => has(target, 0), TypeError); + + // 3. KeyedStoreIC: transition from named property access to element access. + function write(obj, key, val) { + obj[key] = val; + } + write(namedObj, "a", 2); + assertThrows(() => write(target, "a", 2), TypeError); + write([1.1], 0, 2.2); + assertThrows(() => write(target, 0, "overwritten"), TypeError); + + d8.test.setAccessPolicy(target, true); + assertEquals("secret", target[0]); +})(); + +(function TestNoElementsProtector() { + function readHole(a) { + return a[0]; + } + const holey = [, 1]; + %PrepareFunctionForOptimization(readHole); + assertEquals(undefined, readHole(holey)); + %OptimizeFunctionOnNextCall(readHole); + assertEquals(undefined, readHole(holey)); + + Object.defineProperty(Object.prototype, "prop", { + set(_) {}, + configurable: true, + }); + function write(o, k, v) { + o[k] = v; + } + write({ prop: 1 }, "prop", 1); + write(Array.prototype, "prop", 1); + write([], 0, 1); + write(Array.prototype, 0, "boom"); + + assertEquals("boom", holey[0]); + assertEquals("boom", readHole(holey)); +})(); 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.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-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..36b08d76cca4 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-568794851.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. + +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; +} + +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(); +} 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-570003644-1.js b/deps/v8/test/mjsunit/regress/regress-570003644-1.js new file mode 100644 index 000000000000..f56634f7a54b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-570003644-1.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: --maglev-non-eager-inlining --expose-gc --allow-natives-syntax + +class D { + constructor(x) { + this.x = x; + this.p = 7; + this.q = 9; + } +} + +// Map: MD1 where x is const SMI +let dOld = new D(1); + +// Map: MD2 (after adding "tail") +// Map transition: MD1 --tail--> MD2 +let dExtra = new D(1); +dExtra.tail = 1; + +class C { + constructor(z) { + this.z = z; + this.q = 11; + } +} + +// Map: MC1 where z is a const SMI +let cOld = new C(1); + +// Map: MC2 w where z is a const HeapNumber +let cTarget = new C(1.5); + +// Migrate to MC2: this makes MC2 a migration target +cOld.z = 2.5; + +// Larger than the eager-inline bytecode limit. +function noop() { + let n = 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + return n; +} +%PrepareFunctionForOptimization(noop); + +function polyQ(o) { + noop(); // Not inlined + // MigrateMapIfNeeded, then a polymorphic branch with MC2 and MD1 (in this + // order). + return o.q; +} +%PrepareFunctionForOptimization(polyQ); + +polyQ(cTarget); +polyQ(dOld); + +let smi_array = [0, 0]; + +function victim(cObj, dObj) { + // CheckMapsWithMigration(MC2) cObj; tries to migrate to MC2 (but the cTarget we + // pass already has MC2). + cObj.q; + + // CheckMaps(MD1) dObj + dObj.p; + + // Eagerly inlining polyQ. Here we need to conservatively assume that the noop + // call might change the maps, so we get: + // CallFunction noop + // MigrateMapIfNeeded dObj + // Polymoprhic branch (MC2, MD1): + // /-- Branch if dObj's map is MC2 + // | | + // | v + // | CheckMap(MD1) dObj <<< Load-bearing! Must not be eliminated + // | | + // | v + // \--> Result unused, so this is empty + polyQ(dObj); + + // The map better be MD1 or this goes wrong. + smi_array[0] = dObj.x; +} +%PrepareFunctionForOptimization(victim); +victim(cTarget, dOld); + +%OptimizeMaglevOnNextCall(victim); + +victim(cTarget, dOld); + +// Move the smi_array backing store to old space before storing a young pointer. +gc(); + +// Create a new map MD3 where x is a HeapNumber; MD1 deprecated. +new D(1.5); + +// Now the MigrateMapIfNeeded will migrate dOld to MD3 where x is a HeapNumber. +victim(cTarget, dOld); diff --git a/deps/v8/test/mjsunit/regress/regress-570003644-2.js b/deps/v8/test/mjsunit/regress/regress-570003644-2.js new file mode 100644 index 000000000000..fe9c96dd215b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-570003644-2.js @@ -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. + +// Flags: --maglev-non-eager-inlining --expose-gc --allow-natives-syntax +// Flags: --max-maglev-eager-inlined-bytecode-size=0 + +class D { + constructor(x) { + this.x = x; + this.p = 7; + this.q = 9; + } +} + +// Map: MD1 where x is const SMI +let dOld = new D(1); + +// Map: MD2 (after adding "tail") +// Map transition: MD1 --tail--> MD2 +let dExtra = new D(1); +dExtra.tail = 1; + +class C { + constructor(z) { + this.z = z; + this.q = 11; + } +} + +// Map: MC1 where z is a const SMI +let cOld = new C(1); + +// Map: MC2 w where z is a const HeapNumber +let cTarget = new C(1.5); + +// Migrate to MC2: this makes MC2 a migration target +cOld.z = 2.5; + +// Larger than the eager-inline bytecode limit. +function noop() { + let n = 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + n += 0; + return n; +} +%PrepareFunctionForOptimization(noop); + +function polyQ(o) { + noop(); // Not inlined + // MigrateMapIfNeeded, then a polymorphic branch with MC2 and MD1 (in this + // order). + return o.q; +} +%PrepareFunctionForOptimization(polyQ); + +polyQ(cTarget); +polyQ(dOld); + +let smi_array = [0, 0]; + +function victim(cObj, dObj) { + // CheckMapsWithMigration(MC2) cObj; tries to migrate to MC2 (but the cTarget we + // pass already has MC2). + cObj.q; + + // CheckMaps(MD1) dObj + dObj.p; + + // Eventually we'l inline polyQ here. Here we need to conservatively assume + // that the noop call might change the maps, so we get: + // CallFunction noop + // MigrateMapIfNeeded dObj + // Polymoprhic branch (MC2, MD1): + // /-- Branch if dObj's map is MC2 + // | | + // | v + // | CheckMap(MD1) dObj <<< Load-bearing! Must not be eliminated + // | | + // | v + // \--> Result unused, so this is empty + polyQ(dObj); + + // The map better be MD1 or this goes wrong. + smi_array[0] = dObj.x; +} +%PrepareFunctionForOptimization(victim); +victim(cTarget, dOld); + +%OptimizeMaglevOnNextCall(victim); + +victim(cTarget, dOld); + +// Move the smi_array backing store to old space before storing a young pointer. +gc(); + +// Create a new map MD3 where x is a HeapNumber; MD1 deprecated. +new D(1.5); + +// Now the MigrateMapIfNeeded will migrate dOld to MD3 where x is a HeapNumber. +victim(cTarget, dOld); diff --git a/deps/v8/test/mjsunit/regress/regress-570203091-1.js b/deps/v8/test/mjsunit/regress/regress-570203091-1.js new file mode 100644 index 000000000000..2ac6c407c776 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-570203091-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: --turbolev --allow-natives-syntax + +let sink = 0; +function* gen() { + try { unknown_global; } catch {} + let x = 0; + for (;;) { + if (x === 0) { + sink = 1; + } else { + sink = 2; + } + const is_zero = x === 0 ? true : false; + x = (yield is_zero).length; + } +} + +%PrepareFunctionForOptimization(gen); +const g = gen(); +g.next(); // x = 0 +g.next("a"); // x = 1 +g.next(""); // x = 0 + +%OptimizeFunctionOnNextCall(gen); +assertEquals(false, g.next("hello").value); diff --git a/deps/v8/test/mjsunit/regress/regress-570203091-2.js b/deps/v8/test/mjsunit/regress/regress-570203091-2.js new file mode 100644 index 000000000000..f99037288cda --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-570203091-2.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: --turbolev --allow-natives-syntax + +let sink = 0; +const arr = [1.1, 2.2]; +const victim = [3.3]; + +function* gen() { + try { unknown_global; } catch {} + let x = 0; + for (;;) { + if (x === 0) { + sink = 1; + } else { + sink = 2; + } + if (arr.length <= 0) return; + arr[x] = 1.5; + x = (yield).length; + } +} + +%PrepareFunctionForOptimization(gen); +const g = gen(); +g.next(); // x = 0 +g.next("a"); // x = 1 +g.next(""); // x = 0 + +%OptimizeFunctionOnNextCall(gen); +g.next("abcdef"); +assertEquals(3.3, victim[0]); +assertEquals(7, arr.length); diff --git a/deps/v8/test/mjsunit/regress/regress-570547313.js b/deps/v8/test/mjsunit/regress/regress-570547313.js new file mode 100644 index 000000000000..67fb8202c899 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-570547313.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: --enable-inspector + +// d8's `send` dispatches protocol messages synchronously, so a breakpoint +// condition can disable the debugger while it is being evaluated. Set two +// break points at the same location, to check that the second condition is +// not evaluated anymore once the debugger was disabled by the first one. + +let scriptId; +globalThis.receive = function(m) { + let msg = JSON.parse(m); + if (msg.method === 'Debugger.scriptParsed' && msg.params.url === 'test.js') { + scriptId = msg.params.scriptId; + } +}; +send(JSON.stringify({id: 1, method: 'Debugger.enable'})); +eval( + '//# sourceURL=test.js\n' + + 'function outer() {\n' + + ' function inner1() { return 1; }\n' + + ' function inner2() { return 2; }\n' + + ' return inner1() + inner2();\n' + + '}'); +send(JSON.stringify({ + id: 2, + method: 'Debugger.setBreakpoint', + params: { + location: {scriptId: scriptId, lineNumber: 2, columnNumber: 22}, + condition: 'globalThis.cond1()' + } +})); +send(JSON.stringify({ + id: 3, + method: 'Debugger.setBreakpointByUrl', + params: { + urlRegex: 'test\\.js', + lineNumber: 2, + columnNumber: 22, + condition: 'globalThis.cond2()' + } +})); + +let cond1Evaluated = false; +let cond2Evaluated = false; +globalThis.cond1 = function() { + cond1Evaluated = true; + send(JSON.stringify({id: 4, method: 'Debugger.disable'})); + return false; +}; +globalThis.cond2 = function() { + cond2Evaluated = true; + return false; +}; + +assertEquals(3, outer()); +assertTrue(cond1Evaluated !== cond2Evaluated); 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-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-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-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-target-toctou.js b/deps/v8/test/mjsunit/regress/regress-fast-proxy-target-toctou.js new file mode 100644 index 000000000000..ab23c9da9849 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-fast-proxy-target-toctou.js @@ -0,0 +1,316 @@ +// Copyright 2026 the V8 project 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); +} 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/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-534275413.js b/deps/v8/test/mjsunit/regress/wasm/regress-534275413.js index b3b325a50192..e9e5d2ab7d4c 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-534275413.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-534275413.js @@ -20,7 +20,13 @@ function sendDebugCommand(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/); + assertThrows( + () => instance.exports.mem2.grow(1), RangeError, /Unable to grow/); + // Growing memory 1 should also fail even when it must grow in place (via + // toResizableBuffer()). + instance.exports.mem1.toResizableBuffer(); + assertThrows( + () => instance.exports.mem1.grow(1), RangeError, /Unable to grow/); sendDebugCommand('Debugger.resume'); }; 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..c6354b754265 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-567171844.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: --wasm-custom-descriptors --wasm-js-interop + +const wasm_bytes = new Uint8Array([ + 0,97,115,109,1,0,0,0,1,26,6,94,111,1,94,112,1,94,120,1,96,4,99,0,99,1,99,2,111,0,96,0,0,96,0,0, + 2,81,4,18,119,97,115,109,58,106,115,45,112,114,111,116,111,116,121,112,101,115,12,99,111,110, + 102,105,103,117,114,101,65,108,108,0,3,1,99,12,99,111,110,115,116,114,117,99,116,111,114,115, + 3,111,0,3,109,111,100,10,111,117,116,101,114,95,102,117,110,99,0,4,1,99,5,112,114,111,116,111, + 3,111,0,3,3,2,4,5,8,1,3,9,11,2,5,111,1,35,0,11,1,0,1,2,12,1,1,10,37,2,4,0,16,1,11,30,0,65,0, + 65,1,251,10,0,0,65,0,65,1,251,10,1,1,65,0,65,14,251,9,2,0,35,0,16,0,11,11,17,1,1,14,1,0,1,0, + 8,109,121,77,101,116,104,111,100,127,0,25,4,110,97,109,101,1,18,2,2,8,109,121,77,101,116,104, + 111,100,3,5,115,116,97,114,116 +]); + +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-569886678.js b/deps/v8/test/mjsunit/regress/wasm/regress-569886678.js new file mode 100644 index 000000000000..5379ac727535 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-569886678.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: --enable-inspector --wasm-custom-descriptors --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); + +// 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'] }); + +let exception_paused = false; + +function receive(message) { + let msg = JSON.parse(message); + if (msg.error) { + throw new Error('Inspector error: ' + JSON.stringify(msg.error)); + } + if (msg.id === 1) { + send(JSON.stringify({ + id: 2, + method: 'Debugger.setPauseOnExceptions', + params: {state: 'caught'} + })); + } else if (msg.id === 2) { + runTrigger(); + } else if (msg.method === 'Debugger.paused') { + exception_paused = true; + send(JSON.stringify({id: 3, method: 'Debugger.resume'})); + } +} + +function runTrigger() { + try { + proto.myMethod.call(Symbol("sym")); + } catch(e) { + } +} + +send(JSON.stringify({id: 1, method: 'Debugger.enable'})); + +assertTrue(exception_paused); 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-570538338.js b/deps/v8/test/mjsunit/regress/wasm/regress-570538338.js new file mode 100644 index 000000000000..865cca666a52 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-570538338.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: --enable-inspector + +// d8's `send` dispatches protocol messages synchronously, so a Wasm breakpoint +// condition can disable the debugger while it is being evaluated. A second +// break point (from setBreakpointOnFunctionCall) at the same position must not +// be evaluated anymore afterwards. + +let mod_bytes = new Uint8Array([ + 0, 97, 115, 109, 1, 0, 0, 0, + 1, 5, 1, 96, 0, 1, 127, + 3, 2, 1, 0, + 7, 8, 1, 4, 109, 97, 105, 110, 0, 0, + 10, 7, 1, 5, 0, 1, 65, 42, 11, +]); + +let msgQueue = []; +function queueSend(msgObj) { + msgQueue.push(msgObj); + if (msgQueue.length === 1) setTimeout(processQueue); +} +function processQueue() { + if (msgQueue.length > 0) send(JSON.stringify(msgQueue[0])); +} +function onResponse() { + msgQueue.shift(); + processQueue(); +} + +let i1; +let cond1Evaluated = false; +let cond2Evaluated = false; +let mainResult; + +globalThis.receive = function(msg_str) { + let msg = JSON.parse(msg_str); + if (msg.id && msgQueue.length > 0 && msg.id === msgQueue[0].id) { + onResponse(); + } + if (msg.method === 'Debugger.scriptParsed' && + msg.params.url.startsWith('wasm://')) { + queueSend({ + id: 10, + method: 'Debugger.getPossibleBreakpoints', + params: {start: {scriptId: msg.params.scriptId, lineNumber: 0, + columnNumber: 0}} + }); + } + if (msg.id === 10) { + queueSend({ + id: 1, + method: 'Debugger.setBreakpoint', + params: {location: msg.result.locations[0], + condition: 'globalThis.cond1()'} + }); + queueSend({ + id: 20, + method: 'Runtime.evaluate', + params: {expression: 'globalThis.i1.exports.main'} + }); + } + if (msg.id === 20) { + queueSend({ + id: 2, + method: 'Debugger.setBreakpointOnFunctionCall', + params: {objectId: msg.result.result.objectId, + condition: 'globalThis.cond2()'} + }); + setTimeout(() => { + mainResult = i1.exports.main(); + }); + } +}; + +globalThis.cond1 = function() { + cond1Evaluated = true; + send(JSON.stringify({id: 100, method: 'Debugger.disable'})); + return false; +}; +globalThis.cond2 = function() { + cond2Evaluated = true; + return false; +}; + +queueSend({id: 1000, method: 'Debugger.enable'}); +globalThis.i1 = i1 = + new WebAssembly.Instance(new WebAssembly.Module(mod_bytes)); + +// Runs after all the tasks above. +function check() { + if (mainResult === undefined) { + setTimeout(check); + return; + } + assertEquals(42, mainResult); + assertTrue(cond1Evaluated !== cond2Evaluated); +} +setTimeout(check); 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-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-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/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-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-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-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-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-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-568338771.js b/deps/v8/test/mjsunit/sandbox/regress/regress-568338771.js new file mode 100644 index 000000000000..0d3b9daebc3b --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-568338771.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: --enable-inspector --sandbox-testing --allow-natives-syntax + +function receive(message) {} + +send(JSON.stringify({id: 1, method: 'Debugger.enable'})); + +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); + +send(JSON.stringify({ + id: 2, + method: 'Debugger.setBreakpointByUrl', + params: {url: 'donor.js', lineNumber: 0, columnNumber: 24} +})); + +function victim(a, b) { + pad(a); + pad(a); + pad(a); + pad(a); + return b + 1; +} + +%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, {}); 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..f39344b9f757 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/wasm-suspender-stack-reference.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 --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([ + 0,97,115,109,1,0,0,0,1,7,2,96,0,0,96,0,0,2,7,1,1,109,1,112,0,0, + 3,2,1,1,7,5,1,1,102,0,1,10,6,1,4,0,16,0,11 +]); +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/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/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/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-567129324.js b/deps/v8/test/mjsunit/turbolev/regress-567129324.js new file mode 100644 index 000000000000..1abeaeaafc15 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/regress-567129324.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 --turbolev +// Flags: --max-turbolev-eager-inlined-bytecode-size=0 + +// The graph optimizer must not replace a TruncateChecked...ToInt32[Number] +// with a cached truncation that only assumed NumberOrOddball: the Number check +// narrows `x` (Smi|Boolean) to Smi, which the Smi-field store relies on. +// `alt` must not be eagerly inlined, so that its truncation is only added to +// the graph by the inliner, after `x | y` has been built. + +function alt(x) { + return Math.imul(x, 3); +} + +const obj = { b: 123 }; + +function f(flag, y, obj) { + const x = flag ? true : 123; + const a = alt(x); + const b = x | y; + obj.b = x; + return b + a; +} + +%PrepareFunctionForOptimization(alt); +%PrepareFunctionForOptimization(f); +f(false, 0.125, obj); +%OptimizeFunctionOnNextCall(f); +assertEquals(123 + 369, f(false, 0.125, obj)); +assertOptimized(f); + +assertEquals(1 + 3, f(true, 0.125, obj)); +assertUnoptimized(f); +assertEquals(true, obj.b); +%HeapObjectVerify(obj); 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-568348290.js b/deps/v8/test/mjsunit/turbolev/regress-568348290.js new file mode 100644 index 000000000000..2f39a98cc33c --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/regress-568348290.js @@ -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. + +// Flags: --allow-natives-syntax --turbolev +// Flags: --max-turbolev-eager-inlined-bytecode-size=0 + +// 1. Unwrapping ReturnedValue(HoleyFloat64) for a kNumber truncation must +// preserve the number check via CheckedHoleyFloat64ToFloat64. +(function TestReturnedValueHoleyFloat64() { + function get_elem(arr, i) { + return arr[i]; + } + + function opt(arr, i) { + const x = get_elem(arr, i); + const y = x | 0; + return String(x) + y; + } + + const holey = [1.5, , 2.5]; + %PrepareFunctionForOptimization(get_elem); + %PrepareFunctionForOptimization(opt); + assertEquals('1.51', opt(holey, 0)); + assertEquals(undefined, get_elem(holey, 1)); + assertEquals('1.51', opt(holey, 0)); + %OptimizeFunctionOnNextCall(opt); + assertEquals('1.51', opt(holey, 0)); + assertOptimized(opt); + + assertEquals('undefined0', opt(holey, 1)); + assertUnoptimized(opt); +})(); + +// 2. Unwrapping HoleyFloat64ToTagged(HoleyFloat64) for a kNumber truncation +// must also preserve the number check. +(function TestHoleyFloat64ToTaggedConversion() { + function get_elem_tagged(arr, i, flag) { + let v = arr[i]; + if (flag) { + v = arr[0]; + } + return v; + } + + function opt(arr, i, flag) { + const x = get_elem_tagged(arr, i, flag); + const y = x | 0; + return String(x) + y; + } + + const holey = [1.5, , 2.5]; + %PrepareFunctionForOptimization(get_elem_tagged); + %PrepareFunctionForOptimization(opt); + assertEquals('1.51', opt(holey, 0, false)); + assertEquals(undefined, get_elem_tagged(holey, 1, false)); + assertEquals(1.5, get_elem_tagged(holey, 1, true)); + assertEquals('1.51', opt(holey, 0, false)); + %OptimizeFunctionOnNextCall(opt); + assertEquals('1.51', opt(holey, 0, false)); + assertOptimized(opt); + + assertEquals('undefined0', opt(holey, 1, false)); + assertUnoptimized(opt); +})(); + +// 3. A prior weaker truncation (NumberOrOddball via Math.imul) on the same +// HoleyFloat64 node must not cause a subsequent kNumber truncation to skip +// CheckedHoleyFloat64ToFloat64. +(function TestWeakerTruncationBeforeNumberTruncation() { + function get_elem(arr, i) { + return arr[i]; + } + + function imul(x) { + return Math.imul(x, 3); + } + + function opt(arr, i) { + const x = get_elem(arr, i); + const a = imul(x); + const b = x | 0; + return String(x) + a + b; + } + + const holey = [1.5, , 2.5]; + %PrepareFunctionForOptimization(get_elem); + %PrepareFunctionForOptimization(imul); + %PrepareFunctionForOptimization(opt); + assertEquals('1.531', opt(holey, 0)); + assertEquals(undefined, get_elem(holey, 1)); + assertEquals('1.531', opt(holey, 0)); + %OptimizeFunctionOnNextCall(opt); + assertEquals('1.531', opt(holey, 0)); + assertOptimized(opt); + + assertEquals('undefined00', opt(holey, 1)); + assertUnoptimized(opt); +})(); + +// 4. Merging kSmi and kJSReceiverOrNullOrUndefined and intersecting with +// kNumber on `x | y` narrows `x` to kSmi, eliding CheckSmi on a subsequent +// Smi-field store. Dropping the kNumber check corrupts `smi_obj.a` with +// #undefined in a Smi field. +(function TestSmiFieldCorruptionViaTypeIntersection() { + function get_elem(arr, i) { + return arr[i]; + } + + const smi_obj = {a: 100}; + smi_obj.a = 1; + + function opt(arr, i, mode, bailout, y, obj, n) { + const x = get_elem(arr, i); + let cmp = false; + if (mode === 1) { + cmp = (x + 1) === 2; + } else { + cmp = (x === n); + if (bailout) return 0; + } + const b = x | y; + obj.a = x; + return b + (cmp ? 1 : 0); + } + + const smi_arr = [1, 2]; + const holey = [1, , 2.5]; + + %PrepareFunctionForOptimization(opt); + opt(smi_arr, 0, 1, false, 0.125, smi_obj, null); + opt(smi_arr, 0, 1, false, 0.125, smi_obj, null); + + %PrepareFunctionForOptimization(get_elem); + get_elem(holey, 0); + get_elem(holey, 1); + + opt(holey, 1, 0, true, 0.125, smi_obj, null); + opt(holey, 1, 0, true, 0.125, smi_obj, null); + + %OptimizeFunctionOnNextCall(opt); + assertEquals(2, opt(holey, 0, 1, false, 0.125, smi_obj, null)); + assertOptimized(opt); + + assertEquals(0, opt(holey, 1, 0, false, 0.125, smi_obj, null)); + assertUnoptimized(opt); + assertEquals(undefined, smi_obj.a); + %HeapObjectVerify(smi_obj); +})(); 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/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/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/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-memory-grow-bounds-check.js b/deps/v8/test/mjsunit/wasm/shared-memory-grow-bounds-check.js new file mode 100644 index 000000000000..bbf0cbb7d922 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/shared-memory-grow-bounds-check.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-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) +Atomics.store(i32_grown, 16384, 0x123456); + +// 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-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.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..5a31273f4cc9 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], diff --git a/deps/v8/test/unittests/BUILD.gn b/deps/v8/test/unittests/BUILD.gn index bf8dfc2ee23d..56dd2dea3625 100644 --- a/deps/v8/test/unittests/BUILD.gn +++ b/deps/v8/test/unittests/BUILD.gn @@ -330,6 +330,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", @@ -397,6 +398,7 @@ 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", @@ -407,12 +409,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", @@ -463,6 +465,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", @@ -548,7 +551,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", @@ -652,6 +654,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", 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..0c0da3d93995 100644 --- a/deps/v8/test/unittests/api/api-wasm-unittest.cc +++ b/deps/v8/test/unittests/api/api-wasm-unittest.cc @@ -293,22 +293,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 +556,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()); diff --git a/deps/v8/test/unittests/api/deserialize-unittest.cc b/deps/v8/test/unittests/api/deserialize-unittest.cc index ecd607e46fe9..fb9fb9983b7d 100644 --- a/deps/v8/test/unittests/api/deserialize-unittest.cc +++ b/deps/v8/test/unittests/api/deserialize-unittest.cc @@ -1333,4 +1333,148 @@ TEST_F(MergeDeserializedCodeTest, MergeThatStartsButDoesNotFinish) { } } +TEST_F(MergeDeserializedCodeTest, ModuleCacheClassicScriptMismatch) { + i::v8_flags.merge_background_deserialized_script_with_compilation_cache = + true; + std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data; + IsolateAndContextScope scope(this); + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate()); + PersistentScriptOrigin default_origin( + isolate(), NewString("http://example.com/test.js")); + + constexpr char kPolyglotSource[] = + "let L0 = 1;\n" + "var z, o;\n" + "function g() { throw 1; }\n" + "function K(a, b) { var t = globalThis.top; (t.__keep = t.__keep || " + "[]).push(a, b); }\n" + "z = await /1; function lazyOuter() { function inner() {} } { try { g() " + "} catch /* 1, o = { a: function () {}, 'NAMENAMENAMENAME' //*/\n" + "(e) { K(() => e, function later() { return e }) } }\n"; + + // Setup: define `await` and `top` in global scope for classic script parse. + { + v8::HandleScope handle_scope(isolate()); + Local<Script> setup = + Script::Compile( + context(), NewString("var await = 6; globalThis.top = globalThis;")) + .ToLocalChecked(); + CHECK(!setup->Run(context()).IsEmpty()); + } + + // Step 1: Compile and run as a classic script, populating the Isolate + // compilation cache and retaining catch-block closures in globalThis.__keep. + // Also compile as a module with the same resource name and create a module + // code cache, then age and flush the classic script's top-level bytecode. + { + v8::HandleScope handle_scope(isolate()); + ScriptOrigin classic_origin = default_origin.AsScriptOrigin(); + Local<Script> script = + Script::Compile(context(), NewString(kPolyglotSource), &classic_origin) + .ToLocalChecked(); + CHECK(!script->Run(context()).IsEmpty()); + + ScriptOrigin module_origin(NewString("http://example.com/test.js"), 0, 0, + false, -1, Local<Value>(), false, false, + /*is_module=*/true); + ScriptCompiler::Source module_source(NewString(kPolyglotSource), + module_origin); + Local<Module> module = + ScriptCompiler::CompileModule(isolate(), &module_source) + .ToLocalChecked(); + cached_data.reset( + ScriptCompiler::CreateCodeCache(module->GetUnboundModuleScript())); + + i::SharedFunctionInfo::EnsureOldForTesting(GetSharedFunctionInfo(script)); + } + + // Step 2: Flush the classic script's top-level bytecode via major GC. + { + i::DisableConservativeStackScanningScopeForTesting no_css_scope( + i_isolate->heap()); + InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); + } + + // Step 3a: Start off-thread consumption of the MODULE code cache, then notify + // SourceTextAvailable with the CLASSIC ScriptOrigin after Run() completes. + { + auto task_cached_data = std::make_unique<ScriptCompiler::CachedData>( + cached_data->data, cached_data->length, + ScriptCompiler::CachedData::BufferNotOwned); + 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(); + + std::unique_ptr<ScriptCompiler::ConsumeCodeCacheTask> task = + deserialize_thread.TakeTask(); + task->SourceTextAvailable(isolate(), NewString(kPolyglotSource), + default_origin.AsScriptOrigin()); + CHECK(!task->ShouldMergeWithExistingScript()); + + v8::HandleScope handle_scope(isolate()); + ScriptCompiler::Source source(NewString(kPolyglotSource), + default_origin.AsScriptOrigin(), + task_cached_data.release(), task.release()); + Local<Script> script = + ScriptCompiler::Compile(context(), &source, + ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!script.IsEmpty()); + CHECK(source.GetCachedData()->rejected); + + // Age and flush the recompiled classic script's top-level bytecode again so + // Step 3b also sees a flushed Script in the Isolate compilation cache. + i::SharedFunctionInfo::EnsureOldForTesting(GetSharedFunctionInfo(script)); + } + { + i::DisableConservativeStackScanningScopeForTesting no_css_scope( + i_isolate->heap()); + InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); + } + + // Step 3b: Also test calling SourceTextAvailable on the main thread BEFORE + // Run() executes on the background thread. + { + auto task_cached_data = std::make_unique<ScriptCompiler::CachedData>( + cached_data->data, cached_data->length, + ScriptCompiler::CachedData::BufferNotOwned); + std::unique_ptr<ScriptCompiler::ConsumeCodeCacheTask> task( + ScriptCompiler::StartConsumingCodeCache( + isolate(), std::make_unique<ScriptCompiler::CachedData>( + cached_data->data, cached_data->length, + ScriptCompiler::CachedData::BufferNotOwned))); + task->SourceTextAvailable(isolate(), NewString(kPolyglotSource), + default_origin.AsScriptOrigin()); + + DeserializeThread deserialize_thread(task.release()); + CHECK(deserialize_thread.Start()); + deserialize_thread.Join(); + task = deserialize_thread.TakeTask(); + CHECK(!task->ShouldMergeWithExistingScript()); + + v8::HandleScope handle_scope(isolate()); + ScriptCompiler::Source source(NewString(kPolyglotSource), + default_origin.AsScriptOrigin(), + task_cached_data.release(), task.release()); + Local<Script> script = + ScriptCompiler::Compile(context(), &source, + ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!script.IsEmpty()); + CHECK(source.GetCachedData()->rejected); + + Local<Script> run_kept = + Script::Compile(context(), + NewString("for (const f of globalThis.__keep) f();")) + .ToLocalChecked(); + CHECK(!run_kept->Run(context()).IsEmpty()); + } +} + } // namespace v8 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-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/assembler/assembler-arm64-unittest.cc b/deps/v8/test/unittests/assembler/assembler-arm64-unittest.cc index e5fd46a7f87d..cda6deda1b28 100644 --- a/deps/v8/test/unittests/assembler/assembler-arm64-unittest.cc +++ b/deps/v8/test/unittests/assembler/assembler-arm64-unittest.cc @@ -11760,6 +11760,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(); 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..3adea2bcf4e0 100644 --- a/deps/v8/test/unittests/assembler/assembler-x64-unittest.cc +++ b/deps/v8/test/unittests/assembler/assembler-x64-unittest.cc @@ -3281,6 +3281,79 @@ 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, 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-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..b818f8620b93 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"); } @@ -400,7 +402,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 +413,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; }; @@ -1894,6 +1896,51 @@ 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, DisasmX64CheckOutputAVX10) { DisassemblerTester t; std::string actual; 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/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/unique-array-unittest.cc b/deps/v8/test/unittests/base/unique-array-unittest.cc new file mode 100644 index 000000000000..950725e19281 --- /dev/null +++ b/deps/v8/test/unittests/base/unique-array-unittest.cc @@ -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. + +#include "src/base/unique-array.h" + +#include <algorithm> +#include <span> + +#include "src/base/vector.h" +#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(base::ArrayVector(kInit)); + EXPECT_EQ(init_arr1.as_vector(), base::ArrayVector(kInit)); + EXPECT_EQ(init_arr1.as_vector(), init_arr2.as_vector()); +} + +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)); + EXPECT_THAT(fill_arr.as_vector(), 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.as_vector(), base::ArrayVector(kInit)); + + auto copied_span = base::UniqueArray<int>::CopiedFrom(std::span(kInit)); + EXPECT_THAT(copied_span.as_span(), testing::ElementsAreArray(kInit)); + EXPECT_EQ(copied_span.as_vector(), base::ArrayVector(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.as_vector(), base::ArrayVector(kInit)); + + auto copy_of_ptr = base::UniqueCopyOf(kInit, 2); + EXPECT_THAT(copy_of_ptr.as_span(), testing::ElementsAre(4, 11)); + EXPECT_THAT(copy_of_ptr.as_vector(), testing::ElementsAre(4, 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.as_vector(), base::ArrayVector(kValues)); + + auto move_assigned_to_empty = base::UniqueArray<int>{}; + move_assigned_to_empty = std::move(move_constructed_arr); + EXPECT_EQ(move_assigned_to_empty.as_vector(), base::ArrayVector(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.as_vector(), base::ArrayVector(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..dccca144a90b 100644 --- a/deps/v8/test/unittests/base/vector-unittest.cc +++ b/deps/v8/test/unittests/base/vector-unittest.cc @@ -60,47 +60,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}; @@ -118,5 +77,111 @@ TEST(VectorTest, ConstexprFactories) { EXPECT_THAT(kVec3, testing::ElementsAreArray(kInit3, kInit3 + 6)); } +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)); +} + +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 } // namespace v8 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/compiler/arm64/turboshaft-instruction-selector-arm64-unittest.cc b/deps/v8/test/unittests/compiler/arm64/turboshaft-instruction-selector-arm64-unittest.cc index 03b0eced4c84..bebf75f66e32 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 @@ -3518,6 +3518,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 +3698,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 +4280,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 +4329,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 +5447,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 +5462,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 +5477,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 +5865,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 +5877,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 +5887,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 +5981,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(); { @@ -10513,6 +10838,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/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/compiler-unittest.cc b/deps/v8/test/unittests/compiler/compiler-unittest.cc index 63ab3a6d48c6..d450e5acc9f2 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" @@ -15,6 +16,7 @@ #include "include/v8-profiler.h" #include "include/v8-script.h" #include "src/api/api-inl.h" +#include "src/base/unique-array.h" #include "src/codegen/compilation-cache.h" #include "src/codegen/script-details.h" #include "src/heap/factory.h" @@ -67,10 +69,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); @@ -264,7 +266,7 @@ 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); + auto buffer = base::UniqueArray<char>::NewForOverwrite(buffer_size); memset(buffer.begin(), '\n', buffer_size - 1); buffer[buffer_size - 1] = '\0'; 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/run-bytecode-graph-builder-unittest.cc b/deps/v8/test/unittests/compiler/run-bytecode-graph-builder-unittest.cc index d7cf86cc7faa..b8fbd2f05abd 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 @@ -6,6 +6,7 @@ #include "include/v8-function.h" #include "src/api/api-inl.h" +#include "src/base/unique-array.h" #include "src/codegen/optimized-compilation-info.h" #include "src/compiler/pipeline.h" #include "src/debug/debug-interface.h" @@ -223,7 +224,7 @@ 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); + auto script = base::UniqueArray<char>::NewForOverwrite(3072); SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -270,7 +271,7 @@ 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); + auto script = base::UniqueArray<char>::NewForOverwrite(2048); SNPrintF(script.as_vector(), "function %s(p1, p2) { %s };\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -392,7 +393,7 @@ 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); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -416,7 +417,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderPrimitiveExpressions) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -469,7 +470,7 @@ 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); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s(p1, p2) { %s }\n%s(0, 0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -502,7 +503,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderNamedLoad) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); + auto script = base::UniqueArray<char>::NewForOverwrite(2048); SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -547,7 +548,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderKeyedLoad) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); + auto script = base::UniqueArray<char>::NewForOverwrite(2048); SNPrintF(script.as_vector(), "function %s(p1, p2) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -580,7 +581,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderPropertyCall) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); + auto script = base::UniqueArray<char>::NewForOverwrite(2048); SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s({func() {}});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -720,7 +721,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderToName) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -745,7 +746,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLogicalNot) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -772,7 +773,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTypeOf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -814,7 +815,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCompareTypeOf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -860,7 +861,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCountOperation) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -891,7 +892,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderDelete) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -942,7 +943,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderDeleteGlobal) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "%s %s({});", snippets[i].code_snippet, kFunctionName); @@ -978,7 +979,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderDeleteLookupSlot) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "%s %s %s", function_prologue, snippets[i].code_snippet, function_epilogue); @@ -1017,7 +1018,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLookupSlot) { {factory->NewNumber(23.456)}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "%s %s %s", function_prologue, snippets[i].code_snippet, function_epilogue); @@ -1042,7 +1043,7 @@ 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); + auto script = base::UniqueArray<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, @@ -1066,7 +1067,7 @@ 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); + auto script = base::UniqueArray<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, @@ -1094,7 +1095,7 @@ 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); + auto script = base::UniqueArray<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, @@ -1118,7 +1119,7 @@ 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); + auto script = base::UniqueArray<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, @@ -1161,7 +1162,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLookupSlotWide) { {factory->NewNumber(23.456)}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(3072); + auto script = base::UniqueArray<char>::NewForOverwrite(3072); SNPrintF(script.as_vector(), "%s %s %s", function_prologue, snippets[i].code_snippet, function_epilogue); @@ -1188,7 +1189,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCallLookupSlot) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); BytecodeGraphTester tester(isolate, script.begin()); @@ -1234,7 +1235,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderEval) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); BytecodeGraphTester tester(isolate, script.begin()); @@ -1259,7 +1260,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderEvalParams) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<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()); @@ -1356,7 +1357,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCompare) { factory->NewNumberFromInt(SMI_MIN)}; for (size_t i = 0; i < arraysize(kCompareOperators); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName, get_code_snippet(kCompareOperators[i]), kFunctionName); @@ -1402,7 +1403,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTestIn) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1431,7 +1432,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTestInstanceOf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1459,7 +1460,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTryCatch) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1495,7 +1496,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTryFinally1) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1517,7 +1518,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTryFinally2) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1544,7 +1545,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderThrow) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1602,7 +1603,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderContext) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "%s", snippets[i].code_snippet); BytecodeGraphTester tester(isolate, script.begin(), "f"); @@ -1664,7 +1665,7 @@ 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); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "%s", snippets[i].code_snippet); BytecodeGraphTester tester(isolate, script.begin(), "*"); @@ -1694,7 +1695,7 @@ TEST_F(RunBytecodeGraphBuilderTest, }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "%s\n%s();", snippets[i].code_snippet, kFunctionName); @@ -1735,7 +1736,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCreateArguments) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "%s\n%s();", snippets[i].code_snippet, kFunctionName); @@ -1777,7 +1778,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCreateRestArguments) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "%s\n%s();", snippets[i].code_snippet, kFunctionName); @@ -1809,7 +1810,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderRegExpLiterals) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(4096); + auto script = base::UniqueArray<char>::NewForOverwrite(4096); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1844,7 +1845,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderArrayLiterals) { {MakeString("1t")}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(4096); + auto script = base::UniqueArray<char>::NewForOverwrite(4096); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1902,7 +1903,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderObjectLiterals) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(4096); + auto script = base::UniqueArray<char>::NewForOverwrite(4096); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); BytecodeGraphTester tester(isolate, script.begin()); @@ -2007,7 +2008,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderIf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); + auto script = base::UniqueArray<char>::NewForOverwrite(2048); SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2035,7 +2036,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderConditionalOperator) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); + auto script = base::UniqueArray<char>::NewForOverwrite(2048); SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2080,7 +2081,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderSwitch) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); + auto script = base::UniqueArray<char>::NewForOverwrite(2048); SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2127,7 +2128,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderSwitchMerge) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); + auto script = base::UniqueArray<char>::NewForOverwrite(2048); SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2184,7 +2185,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderNestedSwitch) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); + auto script = base::UniqueArray<char>::NewForOverwrite(2048); SNPrintF(script.as_vector(), "function %s(p1, p2) { %s };\n%s(0, 0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2224,7 +2225,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderBreakableBlocks) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2270,7 +2271,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderWhile) { {factory->NewNumberFromInt(16)}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2316,7 +2317,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderDo) { {factory->NewNumber(3)}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2407,7 +2408,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderFor) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2476,7 +2477,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderForIn) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2565,7 +2566,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderForOf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2602,7 +2603,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderWithStatement) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2647,7 +2648,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderConstDeclaration) { // Tests for sloppy mode. for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2659,7 +2660,7 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderConstDeclaration) { // Tests for strict mode. for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() {'use strict'; %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2688,7 +2689,7 @@ TEST_F(RunBytecodeGraphBuilderTest, // Tests for sloppy mode. for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2700,7 +2701,7 @@ TEST_F(RunBytecodeGraphBuilderTest, // Tests for strict mode. for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() {'use strict'; %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -2747,7 +2748,7 @@ 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); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "%s %s %s", prologue, const_decl[i].code_snippet, epilogue); @@ -2779,7 +2780,7 @@ 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); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, illegal_const_decl[i].code_snippet, kFunctionName); @@ -2793,7 +2794,7 @@ 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); + auto script = base::UniqueArray<char>::NewForOverwrite(1024); SNPrintF(script.as_vector(), "function %s() {'use strict'; %s }\n%s();", kFunctionName, illegal_const_decl[i].code_snippet, kFunctionName); 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/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..e85b3afb59a0 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 @@ -12,7 +12,7 @@ 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 +62,71 @@ TEST_F(InstructionSelectionNormalizationReducerTest, EXPECT_EQ(test.graph().Index(*load), extension->input()); } } -#endif // V8_ENABLE_WEBASSEMBLY && V8_TARGET_ARCH_ARM64 + +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..7388053258fd 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,111 @@ 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 + } // namespace v8::internal::compiler::turboshaft 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..2d8496e0a8a6 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 @@ -2984,7 +2984,76 @@ TEST_F(TurboshaftInstructionSelectorTest, SIMDF32x4SConvert) { EXPECT_EQ(1U, s[2]->OutputCount()); } +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()); + } +} + +#ifdef V8_ENABLE_AVX10_1 +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; 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..a2562ed16d18 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; } @@ -437,4 +475,142 @@ TEST(FlagInternalsTest, ImplicationOrderShouldNotMatter) { CHECK(!v8_flags.testing_bool_flag_A); } +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; + const char* str = "--expose-trigger-failure"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + FlagList::EnforceFlagImplications(); + CHECK(v8_flags.expose_trigger_failure); + CHECK(v8_flags.test_only_unsafe); + } +#if V8_ENABLE_WEBASSEMBLY + { + SaveFlags save_flags; + const char* str = "--no-wasm-bounds-checks"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + FlagList::EnforceFlagImplications(); + CHECK(!v8_flags.wasm_bounds_checks); + CHECK(v8_flags.test_only_unsafe); + } +#endif // V8_ENABLE_WEBASSEMBLY + { + SaveFlags save_flags; + const char* str = "--gc-fake-mmap=/tmp/foo"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + 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; + const char* str = "--stack-size=100"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + FlagList::EnforceFlagImplications(); + CHECK_EQ(100, v8_flags.stack_size); + CHECK(!v8_flags.test_only_unsafe); + } + { + SaveFlags save_flags; + const char* str = "--stack-size=40"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + 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; + const char* str = "--disallow-unsafe-flags"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + 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, ArrayDestructureBytecodeImplications) { + { + SaveFlags save_flags; + const char* str = "--array-destructure-bytecode"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + FlagList::EnforceFlagImplications(); + CHECK(v8_flags.array_destructure_bytecode); + CHECK(v8_flags.turbolev); + } +#ifdef V8_ENABLE_TURBOFAN + { + SaveFlags save_flags; + const char* str = "--fuzzing --array-destructure-bytecode --no-turbolev"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + FlagList::ResolveContradictionsWhenFuzzing(); + FlagList::EnforceFlagImplications(); + CHECK(v8_flags.turbofan); + CHECK(!v8_flags.turbolev); + CHECK(!v8_flags.array_destructure_bytecode); + } + { + SaveFlags save_flags; + const char* str = + "--fuzzing --array-destructure-bytecode --no-turbofan " + "--stress-concurrent-inlining --no-turbolev"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + FlagList::ResolveContradictionsWhenFuzzing(); + FlagList::EnforceFlagImplications(); + CHECK(v8_flags.turbofan); + CHECK(!v8_flags.turbolev); + CHECK(!v8_flags.array_destructure_bytecode); + } +#endif // V8_ENABLE_TURBOFAN +} + +TEST_F(FlagDefinitionsTest, CorrectnessFuzzerSuppressionsIsDeveloperOnly) { + SaveFlags save_flags; + const char* str = "--correctness-fuzzer-suppressions"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + FlagList::EnforceFlagImplications(); + CHECK(v8_flags.correctness_fuzzer_suppressions); + CHECK(v8_flags.developer_only_features); +} + } // namespace v8::internal diff --git a/deps/v8/test/unittests/heap/heap-unittest.cc b/deps/v8/test/unittests/heap/heap-unittest.cc index 850bfa9f06b7..ad5a1423f084 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,77 @@ #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/base/unique-array.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/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/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 +526,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 +570,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 +592,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 +684,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 +719,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 +756,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 +917,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 +937,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 +945,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 +975,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 +990,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 +1010,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 +1032,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 +1050,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 +1073,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 +1156,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 +1183,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 +1215,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 +1229,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 +1241,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 +1255,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 +1276,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 +1292,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 +1540,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 +1592,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 +1617,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 +1634,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 +1642,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 +1653,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 +1673,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 +1681,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 +1693,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 +1700,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 +1718,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 +1913,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 +1933,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 +1941,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 +1954,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 +1994,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 +2012,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 +2020,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 +2031,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 +2046,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 +2077,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 +2113,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 +2141,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 +2229,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 +2246,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 +2286,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 +2323,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 +2354,7 @@ TEST_F(HeapTest, LeakNativeContextViaMapProto) { heap_instance); InvokeMemoryReducingMajorGCs(); } - EXPECT_EQ(3, NumberOfGlobalObjects()); + EXPECT_EQ(2, NumberOfGlobalObjects()); { v8::HandleScope inner_scope(isolate); @@ -2375,14 +2395,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,7 +2425,7 @@ TEST_F(HeapTest, OptimizedPretenuringNestedDoubleLiterals) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); + auto source = base::UniqueArray<char>::NewForOverwrite(1024); base::SNPrintF(source.as_vector(), "var number_elements = %d;" "var elements = new Array(number_elements);" @@ -2455,7 +2475,7 @@ TEST_F(HeapTest, OptimizedPretenuringNestedInObjectProperties) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); + auto source = base::UniqueArray<char>::NewForOverwrite(1024); base::SNPrintF( source.as_vector(), "let number_elements = %d;" @@ -2498,7 +2518,7 @@ TEST_F(HeapTest, OptimizedPretenuringNestedObjectLiterals) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); + auto source = base::UniqueArray<char>::NewForOverwrite(1024); base::SNPrintF(source.as_vector(), "var number_elements = %d;" "var elements = new Array(number_elements);" @@ -2548,7 +2568,7 @@ TEST_F(HeapTest, OptimizedPretenuringMixedInObjectProperties) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); + auto source = base::UniqueArray<char>::NewForOverwrite(1024); base::SNPrintF(source.as_vector(), "var number_elements = %d;" "var elements = new Array(number_elements);" @@ -2599,7 +2619,7 @@ TEST_F(HeapTest, OptimizedPretenuringDoubleArrayLiterals) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); + auto source = base::UniqueArray<char>::NewForOverwrite(1024); base::SNPrintF(source.as_vector(), "var number_elements = %d;" "var elements = new Array(number_elements);" @@ -2642,7 +2662,7 @@ TEST_F(HeapTest, OptimizedPretenuringNestedMixedArrayLiterals) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); + auto source = base::UniqueArray<char>::NewForOverwrite(1024); base::SNPrintF(source.as_vector(), "var number_elements = %d;" "var elements = new Array(number_elements);" @@ -2666,14 +2686,14 @@ TEST_F(HeapTest, OptimizedPretenuringNestedMixedArrayLiterals) { .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 +2989,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 +3017,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 +3503,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 +3513,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 +3536,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 +3554,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 +3564,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 +3582,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 +3600,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 +3610,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 +3628,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 +3959,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 +3967,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 +4147,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 +4233,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 +4266,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 +4279,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 +4337,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 +4398,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 +4405,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 +4414,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 +4459,3022 @@ 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(); + v8::Local<v8::Context> new_context = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(new_context); + + 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; + + i_isolate()->SetUseCounterCallback(Counter::Callback); + + const char* source = "gc();"; + RunJS(source); + EXPECT_GT(Counter::value(), 0); +} + +#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()))); + + StdoutStream os; + Print(g->shared(), os); + os << std::endl; +} +#endif // OBJECT_PRINT + +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(); + } + + { + RunJS("function fun() {};"); + fun2 = + context()->Global()->Get(context(), NewString("fun")).ToLocalChecked(); + } + + // 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);"); + + 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()); + } + + { + 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. + 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()); + } + + { + 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); +} + +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; + } + + 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(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, AllocationSiteCreation) { + Isolate* isolate = i_isolate(); + HandleScope scope(isolate); + v8_flags.allow_natives_syntax = true; + + // 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); + } + + // 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, ObjectsInOptimizedCodeAreWeak) { + 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);" + "};" + "%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); + } + + // 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, 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()); +} + +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(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 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); +} - Tagged<FixedArray> get() { return Cast<FixedArray>(root->get(0)); } +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); +} - Handle<FixedArray> root; +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 - // 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); +TEST_F(HeapTest, CodeObjectRegistry) { + // We turn off compaction to ensure that code is not moving. + v8_flags.compact = false; - 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); + Isolate* isolate = i_isolate(); - // GC to cleanup state - InvokeMajorGC(); - if (heap->sweeping_in_progress()) { - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); + 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)); +} - CHECK(heap->lo_space()->Contains(arr.get())); - IncrementalMarking* marking = heap->incremental_marking(); - MarkingState* marking_state = heap->marking_state(); - CHECK(marking_state->IsUnmarked(arr.get())); +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(); - 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)); + 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); +} - // Start incremental marking. - CHECK(marking->IsMarking() || marking->IsStopped()); - if (marking->IsStopped()) { - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - } - CHECK(marking->IsMarking()); +#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 - // 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)); +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); } - // 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; + 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); } - SafepointScope safepoint_scope(heap->isolate(), - kGlobalSafepointForSharedSpaceIsolate); - MarkingBarrier::PublishAll(heap); + // 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); - // Finish marking with bigger steps to speed up test. - static constexpr auto kLargeStepSize = - v8::base::TimeDelta::FromMilliseconds(1000); - while (!marking->IsMajorMarkingComplete()) { - marking->AdvanceForTesting(kLargeStepSize); - } - CHECK(marking->IsMajorMarkingComplete()); + 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); + } - // 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)); + EXPECT_TRUE(HeapLayout::InAnyLargeSpace(obj)); + heap->RemoveHeapObjectAllocationTracker(&allocation_tracker); } + + isolate->Dispose(); } -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()); - } - 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, 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, Regress609761) { - ManualGCScope manual_gc_scope(i_isolate()); - int length = kMaxRegularHeapObjectSize / kTaggedSize + 1; - DirectHandle<FixedArray> array = ShrinkArrayAndCheckSize(heap(), length); - CHECK(heap()->lo_space()->Contains(*array)); +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, LiveBytes) { - ManualGCScope manual_gc_scope(i_isolate()); - DirectHandle<FixedArray> array = ShrinkArrayAndCheckSize(heap(), 2000); - CHECK(heap()->old_space()->Contains(*array)); +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, Regress615489) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope(i_isolate()); - HandleScope scope(i_isolate()); - Heap* heap = this->heap(); +TEST_F(HeapTest, IsPendingAllocationLOSpace) { Isolate* isolate = i_isolate(); - InvokeMajorGC(); + 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)); +} - IncrementalMarking* marking = heap->incremental_marking(); - if (heap->sweeping_in_progress()) { - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); +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); } - CHECK(marking->IsMarking() || marking->IsStopped()); - if (marking->IsStopped()) { - heap->StartIncrementalMarking(GCFlag::kNoFlags, - GarbageCollectionReason::kTesting); + // 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(); } - CHECK(marking->IsMarking()); - CHECK(marking->black_allocation()); - { - AlwaysAllocateScopeForTesting always_allocate(heap); - HandleScope inner(isolate); - isolate->factory()->NewFixedArray(500, AllocationType::kOld)->Size(); + 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(); } - static constexpr auto kStepSize = v8::base::TimeDelta::FromMilliseconds(100); - while (!marking->IsMajorMarkingComplete()) { - marking->AdvanceForTesting(kStepSize); + 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(); } - 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_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 internal diff --git a/deps/v8/test/unittests/heap/heap-utils.cc b/deps/v8/test/unittests/heap/heap-utils.cc index 13f8ea9afce8..c03a11ed204b 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,6 +223,7 @@ void HeapInternalsBase::SimulateFullSpace(v8::internal::PagedSpace* space) { } namespace { + std::vector<Handle<FixedArray>> CreatePadding(Heap* heap, int padding_size, AllocationType allocation) { std::vector<Handle<FixedArray>> handles; @@ -206,7 +232,7 @@ std::vector<Handle<FixedArray>> CreatePadding(Heap* heap, int padding_size, 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 { @@ -222,7 +248,7 @@ std::vector<Handle<FixedArray>> CreatePadding(Heap* heap, int padding_size, 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 +268,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,18 +287,18 @@ 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, std::vector<Handle<FixedArray>>* out_handles) { const Address top = space->heap()->NewSpaceTop(); if (top == kNullAddress) return; @@ -284,9 +311,13 @@ void FillCurrentPagedSpacePage(v8::internal::NewSpace* space, } // namespace +std::vector<Handle<FixedArray>> HeapInternalsBase::CreatePadding( + Heap* heap, int padding_size, AllocationType allocation) { + return internal::CreatePadding(heap, padding_size, allocation); +} + void HeapInternalsBase::FillCurrentPage( - v8::internal::NewSpace* space, - std::vector<Handle<FixedArray>>* out_handles) { + NewSpace* space, std::vector<Handle<FixedArray>>* out_handles) { space->heap()->FreeMainThreadLinearAllocationAreas(); PauseAllocationObserversScope pause_observers(space->heap()); if (v8_flags.minor_ms) { @@ -298,7 +329,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 +338,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 +441,8 @@ void ForceEvacuationCandidate(NormalPage* page) { page->owner()->heap()->FreeLinearAllocationAreas(); } +// 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 +479,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..6335c49486dd 100644 --- a/deps/v8/test/unittests/heap/heap-utils.h +++ b/deps/v8/test/unittests/heap/heap-utils.h @@ -21,37 +21,41 @@ class SemiSpaceNewSpace; class HeapInternalsBase { protected: size_t OldGenerationSpaceAvailable(Heap* heap); - void SimulateIncrementalMarking(Heap* heap, bool force_completion); + 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); + 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); 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); }; -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 +66,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 +76,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 +88,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() { @@ -111,22 +119,27 @@ class WithHeapInternals : public TMixin, HeapInternalsBase { 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) { + 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); @@ -142,8 +155,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 +191,7 @@ class WithHeapInternals : public TMixin, HeapInternalsBase { } void ForceEvacuationCandidate(NormalPage* page) { - i::ForceEvacuationCandidate(page); + internal::ForceEvacuationCandidate(page); } void EmptyNewSpaceUsingGC() { InvokeMajorGC(); } @@ -183,8 +205,16 @@ class WithHeapInternals : public TMixin, HeapInternalsBase { } return count; } + + std::vector<Handle<FixedArray>> CreatePadding(int padding_size, + AllocationType allocation) { + return HeapInternalsBase::CreatePadding(heap(), padding_size, allocation); + } }; +class TestWithPlatformAndHeapInternals : public TestWithPlatform, + protected HeapInternalsBase {}; + template <typename TMixin> class WithCppHeap : public TMixin { public: @@ -279,6 +309,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..56b2d1d7f59a 100644 --- a/deps/v8/test/unittests/heap/local-factory-unittest.cc +++ b/deps/v8/test/unittests/heap/local-factory-unittest.cc @@ -127,7 +127,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 +159,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 +179,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 +242,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 +269,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 +300,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 +327,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..b3aab663f04b --- /dev/null +++ b/deps/v8/test/unittests/heap/mark-compact-unittest.cc @@ -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. + +#include "src/heap/mark-compact.h" + +#include <vector> + +#include "src/common/globals.h" +#include "src/handles/handles-inl.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; + +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)); + } +} + +} // 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..53e8b6e2260e 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,967 @@ 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); + } + } + + 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..1f69e95799b6 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<ArrayBuffer> 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/interpreter/bytecode_expectations/ObjectLiterals.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/ObjectLiterals.golden index c972f099ddeb..550905203273 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/ObjectLiterals.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/ObjectLiterals.golden @@ -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(DefineNamedOwnProperty), 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/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/libplatform/tracing-unittest.cc b/deps/v8/test/unittests/libplatform/tracing-unittest.cc index f7d8a195e113..dad51f71ed0f 100644 --- a/deps/v8/test/unittests/libplatform/tracing-unittest.cc +++ b/deps/v8/test/unittests/libplatform/tracing-unittest.cc @@ -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/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/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/object-unittest.cc b/deps/v8/test/unittests/objects/object-unittest.cc index 404b56c6138b..d42c9489d22d 100644 --- a/deps/v8/test/unittests/objects/object-unittest.cc +++ b/deps/v8/test/unittests/objects/object-unittest.cc @@ -286,7 +286,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) { diff --git a/deps/v8/test/unittests/objects/string-table-unittest.cc b/deps/v8/test/unittests/objects/string-table-unittest.cc index 903d0093c03d..c671a141b8c2 100644 --- a/deps/v8/test/unittests/objects/string-table-unittest.cc +++ b/deps/v8/test/unittests/objects/string-table-unittest.cc @@ -71,10 +71,10 @@ TEST_F(StringTableTest, InternalizeUtf8String) { EXPECT_TRUE(IsInternalizedString(*a)); DirectHandle<String> b = factory()->InternalizeUtf8String(string); EXPECT_EQ(*b, *a); - EXPECT_TRUE(b->IsOneByteEqualTo(base::CStrVector(string))); + EXPECT_TRUE(b->IsOneByteEqualTo(string)); b = factory()->InternalizeUtf8String(base::CStrVector(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..63b1034b22e0 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( @@ -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..c7a3ccffb3f1 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" @@ -422,7 +423,7 @@ 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], statement_data[j], context_data[i][1]); @@ -1420,7 +1421,7 @@ TEST_F(ParsingTest, ScopeUsesArgumentsSuperThis) { strlen(surroundings[j].suffix) + strlen(source_data[i].body)); auto program = - base::OwnedVector<char>::NewForOverwrite(kProgramByteSize + 1); + base::UniqueArray<char>::NewForOverwrite(kProgramByteSize + 1); base::SNPrintF(program.as_vector(), "%s%s%s", surroundings[j].prefix, source_data[i].body, surroundings[j].suffix); i::DirectHandle<i::String> source = @@ -1751,7 +1752,7 @@ TEST_F(ParsingTest, ScopePositions) { int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen; int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen; auto program = - base::OwnedVector<char>::NewForOverwrite(kProgramByteSize + 1); + base::UniqueArray<char>::NewForOverwrite(kProgramByteSize + 1); base::SNPrintF(program.as_vector(), "%s%s%s", source_data[i].outer_prefix, source_data[i].inner_source, source_data[i].outer_suffix); @@ -1919,7 +1920,7 @@ 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 }", context_data[i][0], statement_data[j], @@ -3270,7 +3271,7 @@ TEST_F(ParsingTest, SerializationOfMaybeAssignmentFlag) { "h();"; auto program = - base::OwnedVector<char>::NewForOverwrite(Utf8LengthHelper(src) + 1); + base::UniqueArray<char>::NewForOverwrite(Utf8LengthHelper(src) + 1); base::SNPrintF(program.as_vector(), "%s", src); i::DirectHandle<i::String> source = factory->InternalizeUtf8String(program.begin()); @@ -3318,7 +3319,7 @@ TEST_F(ParsingTest, IfArgumentsArrayAccessedThenParametersMaybeAssigned) { "f(0);"; auto program = - base::OwnedVector<char>::NewForOverwrite(Utf8LengthHelper(src) + 1); + base::UniqueArray<char>::NewForOverwrite(Utf8LengthHelper(src) + 1); base::SNPrintF(program.as_vector(), "%s", src); i::DirectHandle<i::String> source = factory->InternalizeUtf8String(program.begin()); @@ -3471,7 +3472,7 @@ 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, inner, suffix); @@ -3594,7 +3595,7 @@ 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); printf("%s\n", program.begin()); @@ -12350,7 +12351,7 @@ 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); + auto program = base::UniqueArray<char>::NewForOverwrite(len + 1); base::SNPrintF(program.as_vector(), "%s", prefix); base::SNPrintF(program.as_vector() + prefix_len, inner_function, inners[i].params, inners[i].source); diff --git a/deps/v8/test/unittests/parser/preparser-unittest.cc b/deps/v8/test/unittests/parser/preparser-unittest.cc index dd38c7148b85..5bb028d4f502 100644 --- a/deps/v8/test/unittests/parser/preparser-unittest.cc +++ b/deps/v8/test/unittests/parser/preparser-unittest.cc @@ -5,7 +5,7 @@ #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" @@ -706,7 +706,7 @@ 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); + auto program = v8::base::UniqueArray<char>::NewForOverwrite(len + 1); v8::base::SNPrintF(program.as_vector(), code, inner.params, inner.source); i::HandleScope scope(isolate); 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/regexp/regexp-unittest.cc b/deps/v8/test/unittests/regexp/regexp-unittest.cc index e734bac8d75c..7d31cc05c67a 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> @@ -1512,6 +1513,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 +1550,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 +1681,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..7c5d1e621c1f 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)); diff --git a/deps/v8/test/unittests/test-utils.h b/deps/v8/test/unittests/test-utils.h index 720e244aae66..39a09763e2dd 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> @@ -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) { 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..9fb9d3c7aa6a 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,19 @@ 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, 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 +186,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); @@ -1018,6 +1070,822 @@ 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") { + 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_TAIL_NAME", "arg": "bytes"}, )" + << R"({"name": "V8_TQ_TAIL_LENGTH", "arg": ")" << length_field + << R"("}]}]})"; + 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 naming it: only the fixed header becomes Torque fields. +std::string TestNoTailJson(bool also_name_the_tail = false) { + std::string document = TestTailJson(); + size_t annotations = + document.find(R"("annotations": [{"name": "V8_TQ_TAIL_NAME")"); + CHECK_NE(annotations, std::string::npos); + std::string replacement = R"("annotations": [{"name": "V8_TQ_NO_TAIL"})"; + if (also_name_the_tail) { + replacement += R"(, {"name": "V8_TQ_TAIL_NAME", "arg": "bytes"})" + R"(, {"name": "V8_TQ_TAIL_LENGTH", "arg": "length"})"; + } + replacement += "]}]}"; + return document.substr(0, annotations) + replacement; +} + +constexpr const char* kTestLayoutNoTailClass = R"( + @cppObjectLayoutDefinition + extern class TestBlob extends HeapObject { + const length: Smi; + } +)"; + +// A tail Torque splits into two indexed sections: the section +// declarations are on the class as Torque source, because their extents +// are expressions over Torque fields that C++ does not encode. Optional +// sections (`name?[cond]`) take the same path; the test prelude has no +// Smi comparison to write a condition with, so ScopeInfo covers them in +// the real build. +std::string TestSectionedJson(const char* sections, bool also_no_tail) { + std::string document = TestTailJson(); + size_t annotations = + document.find(R"("annotations": [{"name": "V8_TQ_TAIL_NAME")"); + CHECK_NE(annotations, std::string::npos); + std::string replacement = + std::string( + R"("annotations": [{"name": "V8_TQ_TAIL_SECTIONS", "arg": ")") + + sections + R"("})"; + if (also_no_tail) replacement += R"(, {"name": "V8_TQ_NO_TAIL"})"; + return document.substr(0, annotations) + replacement + "]}]}"; +} + +constexpr const char* kTestLayoutSectionedClass = R"( + @cppObjectLayoutDefinition + extern class TestBlob extends HeapObject { + const length: Smi; + head[length]: uint8; + rest[length]: uint8; + } +)"; + +TEST(TorqueLayoutLoader, ImportsASectionedTail) { + ExpectSuccessfulLayoutCompilation( + kTestLayoutSectionedClass, + TestSectionedJson("head[length]: uint8; rest[length]: uint8;", + /*also_no_tail=*/false), + /*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( + R"( + @cppObjectLayoutDefinition + extern class TestBlob extends HeapObject { + const length: Smi; + head[Convert<intptr>(length) * 2]: uint8; + rest[length]: uint8; + } +)", + TestSectionedJson( + "head[Convert<intptr>(length) * 4]: uint8; rest[length]: uint8;", + /*also_no_tail=*/false), + /*use_cpp_layouts=*/true, "(Convert<intptr>(length) * 4)"); +} + +TEST(TorqueLayoutLoader, RejectsSectionsThatDifferFromTheTqFieldBlock) { + ExpectFailingLayoutCompilation( + kTestLayoutSectionedClass, + TestSectionedJson("head[length]: uint8; rest[capacity]: uint8;", + /*also_no_tail=*/false), + /*use_cpp_layouts=*/true, "differs from C++ field"); +} + +TEST(TorqueLayoutLoader, RejectsMalformedTailSections) { + ExpectFailingLayoutCompilation(kTestLayoutSectionedClass, + TestSectionedJson("head[length] uint8;", + /*also_no_tail=*/false), + /*use_cpp_layouts=*/true, "unexpected token"); +} + +TEST(TorqueLayoutLoader, RejectsSectionsCombinedWithNoTail) { + ExpectFailingLayoutCompilation( + kTestLayoutSectionedClass, + TestSectionedJson("head[length]: uint8; rest[length]: uint8;", + /*also_no_tail=*/true), + /*use_cpp_layouts=*/true, + "V8_TQ_TAIL_NAME, V8_TQ_NO_TAIL and V8_TQ_TAIL_SECTIONS are exclusive"); +} + +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, RejectsATailThatIsBothNamedAndOmitted) { + ExpectFailingLayoutCompilation(kTestLayoutNoTailClass, + TestNoTailJson(/*also_name_the_tail=*/true), + /*use_cpp_layouts=*/true, + "V8_TQ_TAIL_NAME, V8_TQ_NO_TAIL and " + "V8_TQ_TAIL_SECTIONS 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\" differs from C++ field " + "\"bar: uint8: 3 bit\""); +} + +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"); +} + +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); +} + +TEST(TorqueLayoutLoader, RejectsBitFieldGap) { + // Torque derives offsets from declaration order, so a hole in the record + // would shift every following field instead of being preserved. + ExpectFailingLayoutCompilation( + 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, "starts at bit 2, expected 1"); +} + +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 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_NAME", "arg": "bytes"}])"), + /*use_cpp_layouts=*/true, "V8_TQ_TAIL_NAME 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..43caf997330f 100644 --- a/deps/v8/test/unittests/unittests.status +++ b/deps/v8/test/unittests/unittests.status @@ -33,6 +33,7 @@ '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). 'LogAllTest.LogAll': [PASS, SLOW, HEAVY], @@ -139,11 +140,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,6 +192,14 @@ # 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], }], # tsan == True ############################################################################## @@ -237,6 +257,9 @@ '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]], @@ -246,6 +269,7 @@ ['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 +293,18 @@ ############################################################################## ['lite_mode or variant == jitless', { + # Slow tests. + 'HeapTest.IncrementalMarkingStepMakesBigProgressWithLargeObjects': [SKIP], # Tests that generate code at runtime. 'Assembler*': [SKIP], 'SyncPrimitivesArmTest*': [SKIP], 'CodePagesTest.*': [SKIP], + 'HeapTest.CodeLargeObjectSpace': [SKIP], + 'TestWithPlatform.CodeLargeObjectSpace64k': [SKIP], + 'HeapTest.CodeObjectRegistry': [SKIP], + 'HeapTest.FindCodeForInnerPointer': [SKIP], + 'HeapTest.Regress10900': [SKIP], 'MacroAssemblerX64Test.EmbeddedObj': [SKIP], 'RegExpTest.AssertionMergingToNode': [SKIP], 'RegExpTest.MacroAssemblernativeAtStart': [SKIP], @@ -297,6 +328,7 @@ 'RunJSObjectsTest.*': [SKIP], 'RunJSOpsTest.*': [SKIP], 'RunTailCallsTest.*': [SKIP], + 'WeakReferencesTest.WeakReferencesBasic': [SKIP], # Tests generated irregexp code. 'RegExpTestWithContext.RegExpInterruptReentrantExecution': [SKIP], @@ -365,9 +397,36 @@ '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. 'LogAllTest.LogAll': [SKIP], + 'HeapTest.Regress8014': [SKIP], + 'TestWithHeapInternals.TestInternalWeakLists': [SKIP], }], # 'clang_coverage and mode == debug' ['device_type == bullhead', { @@ -406,6 +465,8 @@ ['full_debug', { # Tests too slow in non-optimized debug mode. '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/utils-unittest.cc b/deps/v8/test/unittests/utils/utils-unittest.cc index a0fab8490254..9616eda2763a 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 { @@ -146,10 +148,10 @@ TEST(UtilsTest, PassesFilterTest) { // 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*")); + base::UniqueArray<const char> name = + base::UniqueCopyOf(base::CStrVector("abcdefgh")); + base::UniqueArray<const char> filter = + base::UniqueCopyOf(base::CStrVector("abcdefgh*")); EXPECT_TRUE(PassesFilter(name.as_vector(), filter.as_vector())); } 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/unittests/wasm/basic-block-calculator-unittest.cc b/deps/v8/test/unittests/wasm/basic-block-calculator-unittest.cc index 600a12ab9d52..46e91a39e1f6 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,8 +20,8 @@ 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()); @@ -31,7 +32,7 @@ class TestWireBytesStorage final : public WireBytesStorage { } private: - const base::OwnedVector<const uint8_t> wire_bytes_; + const base::UniqueArray<const uint8_t> wire_bytes_; }; } // namespace @@ -42,7 +43,7 @@ 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(), @@ -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/unittests/wasm/function-body-decoder-unittest.cc b/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc index 94ab2eaf96cf..bf2dbfa5ef9a 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()); diff --git a/deps/v8/test/unittests/wasm/liftoff-register-unittests.cc b/deps/v8/test/unittests/wasm/liftoff-register-unittests.cc index 9aa33ab9fc0d..59dc6e309613 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); @@ -107,7 +103,8 @@ TEST_F(LiftoffFrameAlignmentTest, AlignFrameSizeAndPatchPrepareStackFrame) { 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); @@ -121,7 +118,7 @@ TEST_F(LiftoffFrameAlignmentTest, AlignFrameSizeAndPatchPrepareStackFrame) { int64_t allocated_bytes_below_rbp = fn.Call(); 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)); @@ -136,8 +133,7 @@ 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); } } } diff --git a/deps/v8/test/unittests/wasm/memory-protection-unittest.cc b/deps/v8/test/unittests/wasm/memory-protection-unittest.cc index 6ac766961c80..bba5330b1821 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,7 +82,7 @@ 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 = 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/unittests/wasm/streaming-decoder-unittest.cc b/deps/v8/test/unittests/wasm/streaming-decoder-unittest.cc index e3b44391786d..5bcb4b56ef27 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; } 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..d820b6b966ab 100644 --- a/deps/v8/test/unittests/wasm/type-canonicalization-fuzztest.cc +++ b/deps/v8/test/unittests/wasm/type-canonicalization-fuzztest.cc @@ -207,7 +207,7 @@ struct ArrayType { constexpr ModuleTypeIndex kNoSupertype = ModuleTypeIndex::Invalid(); builder->AddArrayType( zone->New<wasm::ArrayType>(field_type.val_type.value_type(), - field_type.mutability), + field_type.mutability, SharedFlag{false}), kNotFinal, kNoSupertype); } 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/unittests/wasm/wasm-usecounters.cc b/deps/v8/test/unittests/wasm/wasm-usecounters.cc index afc750ac72b5..55d9d36639c0 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,7 +45,7 @@ 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)); 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/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/BUILD.gn b/deps/v8/third_party/abseil-cpp/BUILD.gn index 72c1655fee05..3761b75f66a9 100644 --- a/deps/v8/third_party/abseil-cpp/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/BUILD.gn @@ -306,6 +306,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..deee67e71852 100644 --- a/deps/v8/third_party/abseil-cpp/CMake/AbseilDll.cmake +++ b/deps/v8/third_party/abseil-cpp/CMake/AbseilDll.cmake @@ -522,6 +522,7 @@ set(ABSL_INTERNAL_DLL_TARGETS "any_invocable" "atomic_hook" "base" + "base_cpu_detect" "base_internal" "bind_front" "bits" @@ -544,7 +545,6 @@ set(ABSL_INTERNAL_DLL_TARGETS "core_headers" "counting_allocator" "crc_cord_state" - "crc_cpu_detect" "crc_internal" "crc32c" "debugging" diff --git a/deps/v8/third_party/abseil-cpp/README.chromium b/deps/v8/third_party/abseil-cpp/README.chromium index f224841baee7..dcddcc74b5ac 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: 8f8fe25cb768b2c10ff5ce448bdfa5ddfb8fbb0b 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/base/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/base/BUILD.bazel index e37b5b48ce86..392aba35b454 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"], 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..aa29bf24e45f 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/attributes.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/attributes.h @@ -99,10 +99,23 @@ // 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 \ + _Pragma("warning(push)") \ + _Pragma("warning(error: 4649)") /* error on misplaced attributes */ \ + [[msvc::forceinline]] /* */ \ + _Pragma("warning(pop)") +#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1 #else #define ABSL_ATTRIBUTE_ALWAYS_INLINE #endif @@ -110,6 +123,15 @@ #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 \ + _Pragma("warning(push)") \ + _Pragma("warning(error: 4649)") /* error on misplaced attributes */ \ + [[msvc::noinline]] /* */ \ + _Pragma("warning(pop)") +#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1 #else #define ABSL_ATTRIBUTE_NOINLINE #endif @@ -375,9 +397,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 +411,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 +441,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 +463,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 +479,27 @@ // Example: // // int foo() ABSL_ATTRIBUTE_HOT; -#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__)) +#if defined(__cplusplus) && defined(__clang__) && \ + ABSL_HAVE_CPP_ATTRIBUTE(gnu::hot) +#define ABSL_ATTRIBUTE_HOT \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic error \"-Wignored-attributes\"") \ + [[gnu::hot]] /* */ \ + _Pragma("clang diagnostic pop") +#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) && defined(__clang__) && \ + ABSL_HAVE_CPP_ATTRIBUTE(gnu::cold) +#define ABSL_ATTRIBUTE_COLD \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic error \"-Wignored-attributes\"") \ + [[gnu::cold]] /* */ \ + _Pragma("clang diagnostic pop") +#elif ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__)) #define ABSL_ATTRIBUTE_COLD __attribute__((cold)) #else #define ABSL_ATTRIBUTE_COLD @@ -577,11 +603,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 +700,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 +720,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 +734,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 +742,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 +779,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 @@ -1046,7 +1085,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) 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..058d1be87e59 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,32 @@ 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")}; } } // 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/internal/cpu_detect.cc b/deps/v8/third_party/abseil-cpp/absl/base/internal/cpu_detect.cc index a939bbfaa78d..b49846583ffe 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; } @@ -302,8 +304,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..5ca993fd01a1 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,6 +30,7 @@ enum class CpuType { kAmdNaples, kAmdMilan, kAmdGenoa, + kAmdSiena, kAmdTurin, kAmdRyzenV3000, kIntelCascadelakeXeon, @@ -48,7 +49,9 @@ enum class CpuType { kAmpereSiryn, kArmNeoverseN2, kArmNeoverseV2, + kArmNeoverseV3, kArmNeoverseN3, + kArmNeoverseN4, kNvidiaGrace, }; 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/container/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/container/BUILD.bazel index 91f79d6650bf..d325e39b0766 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", ], ) @@ -1279,7 +1282,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 +1294,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, 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..f65cb1130854 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" ] 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..79bcee0265f5 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/container/CMakeLists.txt @@ -89,6 +89,25 @@ absl_cc_test( GTest::gmock_main ) +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 +) + # Internal-only target, do not depend on directly. absl_cc_library( NAME @@ -485,6 +504,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 +746,7 @@ absl_cc_library( COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::bits absl::common_policy_traits absl::config absl::container_memory @@ -810,6 +831,7 @@ absl_cc_library( absl::optional absl::prefetch absl::raw_logging_internal + absl::string_view absl::utility absl::weakly_mixed_integer PUBLIC 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/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..01fe8d04f9ea 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. 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..e35954a91d36 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,12 +79,18 @@ 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>>>; + // + // MovableOrVoid is an optional, extra constraint (via SFINAE) to guard + // separate move-only overloads. + template <class K, bool Value, typename MovableOrVoid = void> + using LifetimeBoundK = std::bool_constant< + (std::is_void_v<MovableOrVoid> || + !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, typename = void> using LifetimeBoundV = HasValue<Value, type_traits_internal::IsLifetimeBoundAssignment< @@ -365,9 +374,41 @@ 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) + + // Simple trick to bypass instantiating a bunch of templates in cases + // where they're irrelevant. + using V = std::conditional_t< + sizeof...(Args) == 0 && + std::is_same_v<typename std::allocator_traits< + Alloc>::template rebind_alloc<char>, + std::allocator<char>>, + mapped_type, void>; + + if constexpr (std::is_trivially_move_constructible_v<V> && + std::is_trivially_destructible_v<V> && + // Check if size is a power of 2, to ensure cheap calls. + absl::has_single_bit(sizeof(mapped_type)) && + // Check if copying 1-2 registers is enough. We don't want + // (for example) 32 one-byte values to move around. + alignof(mapped_type) * 2 >= sizeof(mapped_type) && + sizeof(mapped_type) <= sizeof(std::pair<void*, size_t>)) { + // 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..15a80cbebc13 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,7 +175,6 @@ inline Group::NonIterableBitMaskType probe_till_first_non_full_group( return mask; } seq.next(); - ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity && "full table!"); } } @@ -285,6 +276,20 @@ 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())) { @@ -387,16 +392,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()) - @@ -811,7 +820,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 +853,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); @@ -984,7 +993,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(); @@ -1016,10 +1026,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 +1037,83 @@ 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); +} + +// Specialization that computes hash and generates new seed. +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void +ReportSingleElementTableGrowthToInfozAndForceSample( + CommonFields& common, const PolicyFunctions& __restrict policy, + absl::FunctionRef<size_t(size_t)> 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(common.seed().seed()), + /*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); +// 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); } -ABSL_ATTRIBUTE_NOINLINE void ReportResizeToInfoz(CommonFields& common, - HashtablezInfoHandle infoz, - size_t total_probe_length) { - ABSL_SWISSTABLE_ASSERT(infoz.IsSampled()); +// 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, + absl::FunctionRef<size_t(size_t)> get_hash) { + common.infoz().RecordInsertMiss(get_hash(common.seed().seed()), probe_length); +} + +// Outlines cold infoz recording with computation of probe_length so callers can +// skip tracking of probe_length. `common` is first and `hash` is third to match +// argument order in callers. +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void +ReportInsertMissToInfozAndComputeProbeLength(CommonFields& common, + size_t target, size_t hash) { + 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()); +} + +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(); @@ -1094,14 +1161,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); @@ -1115,7 +1176,7 @@ void ResizeEmptyNonAllocatedTableImpl(CommonFields& common, ResetGrowthLeft(new_capacity, blocked_element_count, common); if (ABSL_PREDICT_FALSE(has_infoz)) { - ReportResizeToInfoz(common, infoz, 0); + ReportResizeToInfozAndForceSample(common, policy, 0); } } @@ -1175,11 +1236,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,6 +1420,7 @@ template <typename ProbedItem> ABSL_ATTRIBUTE_NOINLINE size_t DecodeAndInsertImpl( CommonFields& c, const PolicyFunctions& __restrict policy, const ProbedItem* start, const ProbedItem* end, void* old_slots) { + ABSL_SWISSTABLE_ASSERT(!c.is_small()); const HashtableCapacity new_capacity = c.capacity_impl(); void* new_slots = c.slot_array(new_capacity.capacity()); @@ -1396,9 +1459,10 @@ 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 new_capacity = c.capacity(); + const size_t old_capacity = PreviousCapacity(new_capacity); const size_t slot_size = policy.slot_size; - void* new_slots = c.slot_array(c.capacity()); + void* new_slots = c.slot_array(new_capacity); size_t total_probe_length = 0; const void* hash_fn = policy.hash_fn(c); auto hash_slot = policy.hash_slot; @@ -1697,13 +1761,14 @@ 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); + 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); 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(); + const bool has_infoz = common.has_infoz(); common.set_capacity(kNewCapacity); const auto [new_ctrl, new_slots] = @@ -1720,7 +1785,7 @@ void* Grow1To3AndPrepareInsert(CommonFields& common, 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()); + size_t offset = Resize1To3NewOffset(new_hash); InitializeThreeElementsControlBytes(H2(orig_hash), new_h2, offset, new_ctrl); void* old_element_target = NextSlot(new_slots, slot_size); @@ -1730,18 +1795,18 @@ void* Grow1To3AndPrepareInsert(CommonFields& common, 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); 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, slot_align, + has_infoz, + /*blocked_element_count=*/0, policy.dealloc); return new_element_target_slot; } @@ -1757,12 +1822,12 @@ void* GrowToNextCapacityAndPrepareInsert( ABSL_ASSUME(old_capacity > kMaxSmallCapacity); const size_t new_capacity = NextCapacity(old_capacity); + ABSL_ASSUME(new_capacity > kMaxSmallCapacity); ctrl_t* old_ctrl = common.control(); void* old_slots = common.slot_array(old_capacity); size_t old_blocked_element_count = common.blocked_element_count(); - HashtablezInfoHandle infoz = common.infoz(); - const bool has_infoz = infoz.IsSampled(); + const bool has_infoz = common.has_infoz(); common.set_capacity(new_capacity); common.set_blocked_element_count_to_zero(); const size_t slot_size = policy.slot_size; @@ -1786,8 +1851,7 @@ void* GrowToNextCapacityAndPrepareInsert( 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); @@ -1806,15 +1870,18 @@ void* GrowToNextCapacityAndPrepareInsert( SetCtrlInLargeTable(common, find_info.offset, new_h2, policy.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); 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); } + // Deallocate after `ReportGrowthToInfoz`, because it reads infoz from + // old_ctrl. + DeallocBackingArrayImpl(alloc, old_capacity, old_ctrl, slot_size, slot_align, + has_infoz, old_blocked_element_count, policy.dealloc); return SlotAddress(new_slots, find_info.offset, policy.slot_size); } @@ -1828,11 +1895,14 @@ void* PrepareInsertSmallNonSoo(CommonFields& common, if (common.capacity() == 1) { if (common.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()) { - common.infoz().RecordInsertMiss(get_hash(common.seed().seed()), - /*distance_from_desired=*/0); + ReportInsertMissToInfozAndComputeHash(common, /*probe_length=*/0, + get_hash); } - return common.slot_array(/*capacity=*/1); + return res; } else { return Grow1To3AndPrepareInsert(common, policy, get_hash); } @@ -1843,14 +1913,8 @@ void* PrepareInsertSmallNonSoo(CommonFields& common, 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 bool has_infoz = + policy.is_hashtablez_enabled && ShouldSampleNextTable(); void* alloc = policy.get_char_alloc(common); const auto [new_ctrl, new_slots] = @@ -1862,9 +1926,8 @@ void* PrepareInsertSmallNonSoo(CommonFields& common, PrepareInsertCommon(common); if (ABSL_PREDICT_FALSE(has_infoz)) { - common.generate_new_seed(/*has_infoz=*/true); - ReportSingleGroupTableGrowthToInfoz(common, infoz, - get_hash(common.seed().seed())); + ReportSingleElementTableGrowthToInfozAndForceSample(common, policy, + get_hash); } return new_slots; } @@ -1873,8 +1936,8 @@ 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) { ABSL_SWISSTABLE_ASSERT(!common.GetGrowthInfoLowerBound().HasNoDeleted()); @@ -1958,9 +2021,14 @@ void* PrepareInsertLargeSlow(CommonFields& common, FindInfo target = find_first_non_full(common, hash); PrepareInsertCommon(common); common.OverwriteControlAsFull(common.control()[target.offset]); + // Compute before `SetCtrl*` to avoid reloading `control_`. + void* res = + SlotAddress(common.slot_array(cap), target.offset, policy.slot_size); 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); + if (common.has_infoz()) { + ReportInsertMissToInfoz(common, target.probe_length, hash); + } + return res; } // Resizes empty non-allocated SOO table to NextCapacity(SooCapacity()), @@ -1980,11 +2048,15 @@ GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert( PrepareInsertCommon(common); common.OverwriteEmptyAsFull(); const size_t new_hash = get_hash(common.seed().seed()); + // Compute before `SetCtrl*` to avoid reloading `control_`. + void* res = SlotAddress(common.slot_array(kNewCapacity), SooSlotIndex(), + policy.slot_size); 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); + 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 +2149,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); @@ -2142,7 +2216,7 @@ void* GrowSooTableToNextCapacityAndPrepareInsert( 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); @@ -2194,7 +2268,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 +2276,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( @@ -2262,7 +2338,7 @@ 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); @@ -2270,7 +2346,7 @@ void Copy(CommonFields& common, const PolicyFunctions& __restrict policy, : SingleSlotAddress</*kSooEnabled=*/false>(common), other_slot); - if (soo_enabled && policy.is_hashtablez_eligible && + if (soo_enabled && policy.is_hashtablez_enabled && ShouldSampleNextTable()) { GrowFullSooTableToNextCapacityForceSampling(common, policy); } @@ -2334,7 +2410,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 +2423,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); + const bool hash_infoz = common.has_infoz(); + SetCtrl(common, target_group_offset, H2(hash), policy.slot_size); + // Call NOINLINE function to move infoz instructions out of line. + if (hash_infoz) { + ReportInsertMissToInfozAndComputeProbeLength(common, target_group_offset, + hash); + } + 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 +2463,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,12 +2497,6 @@ 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>( @@ -2480,6 +2561,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 h1, 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..7c01b9e568a8 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 @@ -266,6 +271,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 +294,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 +504,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 +533,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 +554,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 +569,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 +579,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 +600,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 +743,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 +816,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 +828,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 +907,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 +941,51 @@ 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: 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). + uint8_t read_byte(size_t index) const { + return reinterpret_cast<const unsigned char*>(&data_)[index]; + } + + // 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 +1148,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. @@ -1258,6 +1276,24 @@ union HeapOrSoo { unsigned char soo_data[MaxSooSlotSize()]; }; +class CommonFields; + +// 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. @@ -1313,13 +1349,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 +1408,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 +1425,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 +1482,7 @@ class CommonFields : public CommonFieldsGenerationInfo { inline_data_.set_has_infoz(); } + HashtablezInfoHandle infoz_from_control(ctrl_t* ctrl) const; HashtablezInfoHandle infoz_ptr() const; HashtablezInfoHandle infoz() { @@ -1495,26 +1543,11 @@ 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()) { + AssertNotDebugCapacityImpl(); } - AssertNotDebugCapacityImpl(); } private: @@ -1548,10 +1581,12 @@ 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; HashtableInlineData inline_data_; @@ -1586,15 +1621,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 +1645,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 +1690,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 +1726,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 +1752,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 +1849,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`. @@ -1897,15 +1930,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 +1986,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); @@ -2255,13 +2279,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 +2297,63 @@ 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, class Alloc = std::allocator<T>> +using PreferredParamType = std::conditional_t< + IsAllocMoveSameAsCopy<T, Alloc>::value, + std::conditional_t<std::is_arithmetic_v<T> || std::is_enum_v<T> || + std::is_member_pointer_v<T>, + T, const T&>, + T&&>; + // A SwissTable. // // Policy: a policy defines how to perform different operations on @@ -2347,22 +2428,30 @@ class raw_hash_set { using slot_type = typename PolicyTraits::slot_type; + using IsDefaultPolicy = + std::bool_constant<std::is_same_v<Hash, typename Policy::DefaultHash> && + std::is_same_v<Eq, typename Policy::DefaultEq> && + std::is_same_v<Alloc, typename Policy::DefaultAlloc>>; + 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 +2459,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 +2522,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 +2601,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) { @@ -2829,7 +2933,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 +2997,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 +3006,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 +3049,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 +3058,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 +3069,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 +3077,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 +3093,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; } @@ -3447,47 +3553,43 @@ 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()); 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()); 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))) @@ -3495,7 +3597,6 @@ class raw_hash_set { } if (ABSL_PREDICT_TRUE(g.MaskEmpty())) return end(); seq.next(); - ABSL_SWISSTABLE_ASSERT(seq.index() <= cap && "full table!"); } } @@ -3507,7 +3608,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 +3705,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 +3716,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())); } } @@ -3709,6 +3808,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 +3823,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,7 +3836,6 @@ class raw_hash_set { } else { force_sampling = false; } - ABSL_SWISSTABLE_ASSERT(capacity() == 1); constexpr bool kUseMemcpy = PolicyTraits::transfer_uses_memcpy() && SooEnabled(); slot = to_slot( @@ -3751,7 +3852,6 @@ class raw_hash_set { 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); } @@ -3768,20 +3868,19 @@ class raw_hash_set { template <class K> std::pair<slot_type*, bool> find_or_prepare_insert_large(const K& key) { - ABSL_SWISSTABLE_ASSERT(!is_soo()); 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))) { @@ -3794,16 +3893,15 @@ class raw_hash_set { void* slot = SwisstableGenerationsEnabled() ? PrepareInsertLargeGenerationsEnabled( common(), GetPolicyFunctions(), hash, mask_empty, - FindInfo{target_group_offset, seq.index()}, + target_group_offset, HashKey<hasher, K, kIsAbslHash, kSeedShift>{ hash_ref(), key}) : PrepareInsertLarge( common(), GetPolicyFunctions(), hash, mask_empty, - FindInfo{target_group_offset, seq.index()}); + target_group_offset); return {to_slot(slot), true}; } seq.next(); - ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity() && "full table!"); } } @@ -3827,40 +3925,38 @@ class raw_hash_set { // 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; + + 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; + } + // We only do validation for small tables so that it's constant time. + if (capacity() > 16) return; + IterateOverFullSlots(common(), sizeof(slot_type), assert_consistent); } - // 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 @@ -3938,7 +4034,6 @@ class raw_hash_set { return common().control(); } 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 +4047,7 @@ class raw_hash_set { } slot_type* single_slot() { ABSL_SWISSTABLE_ASSERT(is_small()); - return SooEnabled() - ? soo_slot() - : to_slot(common().slot_array(/*capacity=*/1)); + return SooEnabled() ? soo_slot() : to_slot(common().single_non_soo_slot()); } const slot_type* single_slot() const { return const_cast<raw_hash_set*>(this)->single_slot(); @@ -4108,7 +4201,7 @@ 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 @@ -4310,6 +4403,31 @@ 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 h1, + 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 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..a4254ed1e333 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) { @@ -723,34 +725,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 +748,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 +797,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 +822,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 +835,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 +850,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 +864,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 +884,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 +1327,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 +1504,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 +1587,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 +1923,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) { @@ -4089,6 +4136,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 +5212,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 +5330,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..d04807bf6170 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; } @@ -621,6 +643,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..10ba28976cfb 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; } @@ -494,6 +518,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..fb9beeae51b8 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/crc/CMakeLists.txt @@ -112,7 +112,10 @@ 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 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..8a2a4009723b 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,6 +16,7 @@ #include <cstddef> #include <cstdint> +#include <cstring> #include <memory> #include <vector> @@ -200,7 +201,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,17 +218,57 @@ 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: + // 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 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 @@ -239,7 +280,7 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase #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 { + V256 v0, V256 v1, V128* partialCRC) const { V128 loopMultiplicands = V128_Load(reinterpret_cast<const V128*>(kFoldAcross512Bits)); @@ -252,10 +293,12 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase 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)); + const V128* data_ptr0 = reinterpret_cast<const V128*>(&v0); + const V128* data_ptr1 = reinterpret_cast<const V128*>(&v1); + V128 data1 = data_ptr0[0]; + V128 data2 = data_ptr0[1]; + V128 data3 = data_ptr1[0]; + V128 data4 = data_ptr1[1]; partialCRC1 = V128_PMulLow(partialCRC1, loopMultiplicands); partialCRC2 = V128_PMulLow(partialCRC2, loopMultiplicands); partialCRC3 = V128_PMulLow(partialCRC3, loopMultiplicands); @@ -308,15 +351,15 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase return crc; } - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesPclmul(const uint8_t*, + ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesPclmul(V256, V256, 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 { + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE void + Process64BytesPclmul(V256 v0, V256 v1, V128* partialCRC) const { V128 loopMultiplicands = V128_Load(reinterpret_cast<const V128*>(kFoldAcross512Bits)); @@ -329,10 +372,12 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase 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)); + const V128* data_ptr0 = reinterpret_cast<const V128*>(&v0); + const V128* data_ptr1 = reinterpret_cast<const V128*>(&v1); + V128 data1 = data_ptr0[0]; + V128 data2 = data_ptr0[1]; + V128 data3 = data_ptr1[0]; + V128 data4 = data_ptr1[1]; partialCRC1 = V128_PMulLow(partialCRC1, loopMultiplicands); partialCRC2 = V128_PMulLow(partialCRC2, loopMultiplicands); partialCRC3 = V128_PMulLow(partialCRC3, loopMultiplicands); @@ -353,7 +398,7 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase // Reduce partialCRC produced by Process64BytesPclmul into a single value, // that represents crc checksum of all the processed bytes. - ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t FinalizePclmulStream(V128* partialCRC) const { V128 partialCRC1 = partialCRC[0]; V128 partialCRC2 = partialCRC[1]; @@ -392,11 +437,12 @@ 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 + Process64BytesNeonPclmul(V256, V256, 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 @@ -452,7 +498,8 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase crc[2] = crc2; } -#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 +508,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,8 +539,9 @@ 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 void + Process64BytesVpclmul(V256 v0, V256 v1, V256* vpartialCRC, + V256 loopMultiplicands) const { __asm__ volatile( "vpclmulqdq $0x11, %3, %0, %%ymm0 \n" "vpclmulqdq $0x11, %3, %1, %%ymm1 \n" @@ -501,23 +549,23 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase "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" + "vpxor %2, %0, %0 \n" + "vpxor %4, %1, %1 \n" : "+x"(vpartialCRC[0]), "+x"(vpartialCRC[1]) - : "r"(p), "x"(loopMultiplicands) + : "x"(v0), "x"(loopMultiplicands), "x"(v1) : "ymm0", "ymm1"); } #else template <typename T = V256> - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesVpclmul(const uint8_t*, T*, - T) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesVpclmul(T, 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. @@ -551,33 +599,64 @@ 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)) { // 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; + uint64_t l641 = 0; + uint64_t l642 = 0; const uint8_t* p1 = p + bs * blockSize; const uint8_t* p2 = p1 + bs * blockSize; @@ -599,7 +678,19 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreams ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY2(l64, l641, p, p1); - V128 magic = *(reinterpret_cast<const V128*>(kClmulConstants) + bs - 1); + // 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 tmp = V128_From64WithZeroFill(l64); @@ -621,39 +712,165 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreams } } 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. + } + + 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"); + 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; + } + } else { // 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) / - (num_crc_streams + num_pclmul_streams) / 64; - const uint8_t* stream_start = p; - const uint8_t* crc_streams[kMaxStreams]; + 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; + } + 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; + } + + 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 < num_crc_streams; i++) { - crc_streams[i] = stream_start; - stream_start += bs * 64; + 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; + 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}; + + V256 pclmul_v0_0[kMaxStreams]; + V256 pclmul_v1_0[kMaxStreams]; + for (size_t j = 0; j < num_pclmul_streams; j++) { + V256_LoadPairU(pclmul_streams[j], &pclmul_v0_0[j], &pclmul_v1_0[j]); + } + + if constexpr (copy_type != CopyType::kNone) { + for (size_t j = 0; j < num_crc_streams; j++) { + Copy64Bytes<copy_type>(dst_crc_streams[j], crc_streams[j]); + dst_crc_streams[j] += 64; } + for (size_t j = 0; j < num_pclmul_streams; j++) { + Store64Bytes<copy_type>(dst_pclmul_streams[j], pclmul_v0_0[j], + pclmul_v1_0[j]); + dst_pclmul_streams[j] += 64; + } + } + + 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}; + // 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_v0_0[i], pclmul_v1_0[i], partialCRC[i]); + pclmul_streams[i] += 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(crc_streams[j] + kPrefetchHorizon); + } + for (size_t j = 0; j < num_pclmul_streams; j++) { + PrefetchToLocalCache(pclmul_streams[j] + kPrefetchHorizon); + } + + for (size_t j = 0; j < num_pclmul_streams; j++) { + if constexpr (copy_type != CopyType::kNone) { + ProcessPclmulStream<copy_type>(pclmul_streams[j], + dst_pclmul_streams[j], partialCRC[j]); + dst_pclmul_streams[j] += 64; + } else { + ProcessPclmulStream<CopyType::kNone>(pclmul_streams[j], nullptr, + partialCRC[j]); + } + pclmul_streams[j] += 64; + } - // 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; @@ -668,82 +885,52 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreams crc_streams[1] += 16 * 4; crc_streams[2] += 16 * 4; } - - // 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 i = 1; i < bs; i++) { - // Prefetch data for next iterations. + if constexpr (copy_type != CopyType::kNone) { 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)); - } - - // 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]); + Copy64Bytes<copy_type>(dst_crc_streams[j], crc_streams[j] - 64); + dst_crc_streams[j] += 64; } } + } - // 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]); - } + // 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]); + } - // 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]; - } - for (size_t i = 0; i < num_pclmul_streams; i++) { - l64 = MultiplyWithExtraX33(static_cast<uint32_t>(l64), magic); - l64 ^= l64_pclmul[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 < num_crc_streams; i++) { + l64 = MultiplyWithExtraX33(static_cast<uint32_t>(l64), magic); + l64 ^= l64_crc[i]; + } + for (size_t i = 0; i < num_pclmul_streams; i++) { + l64 = MultiplyWithExtraX33(static_cast<uint32_t>(l64), magic); + l64 ^= l64_pclmul[i]; + } - // Update p. - if constexpr (num_pclmul_streams > 0) { - p = pclmul_streams[num_pclmul_streams - 1]; - } else { - p = crc_streams[num_crc_streams - 1]; + // Update p and d. + if constexpr (num_pclmul_streams > 0) { + p = pclmul_streams[num_pclmul_streams - 1]; + if constexpr (copy_type != CopyType::kNone) { + d = reinterpret_cast<char*>(dst_pclmul_streams[num_pclmul_streams - 1]); + size_t remaining_to_copy = static_cast<size_t>(e - p); + std::memcpy(d, p, remaining_to_copy); + } + } else { + p = crc_streams[num_crc_streams - 1]; + if constexpr (copy_type != CopyType::kNone) { + d = reinterpret_cast<char*>(dst_crc_streams[num_crc_streams - 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 +952,72 @@ 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) { + 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 (pclmul_stream_type == PclmulStreamType::VPCLMUL) { 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); + template <CopyType copy_type> + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE void + ProcessPclmulStream(const uint8_t* stream, uint8_t* dst_stream, + V128* partialCRC) const { + if constexpr (pclmul_stream_type == PclmulStreamType::NONE) { + return; } else { - Process64BytesPclmul(*pclmul_stream, partialCRC); + const uint8_t* src_ptr = stream; + V256 v0, v1; + V256_LoadPairU(src_ptr, &v0, &v1); + Store64Bytes<copy_type>(dst_stream, v0, v1); + if constexpr (pclmul_stream_type == PclmulStreamType::VPCLMUL) { + V256 loopMultiplicands = V256_Broadcast128( + reinterpret_cast<const V128*>(kFoldAcross512Bits)); + Process64BytesVpclmul(v0, v1, 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>(v0, v1, partialCRC); + } else { + Process64BytesPclmul(v0, v1, partialCRC); + } } - *pclmul_stream += 16 * 4; } - ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t + 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 (pclmul_stream_type == PclmulStreamType::VPCLMUL) { return FinalizeVpclmulStream(reinterpret_cast<V256*>(partialCRC)); } else if constexpr (pclmul_stream_type == PclmulStreamType::NEON_PCLMUL || pclmul_stream_type == @@ -848,8 +1055,10 @@ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { 3, 1, PclmulStreamType::PCLMUL>(); case CpuType::kAmdMilan: case CpuType::kAmdGenoa: + case CpuType::kAmdSiena: case CpuType::kAmdTurin: -#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__)) // We don't have vector pclmul on arm, but this still needs to // compile. @@ -858,6 +1067,17 @@ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { #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 +1085,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 +1092,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 +1107,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__) @@ -905,7 +1124,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..24e528015f55 100644 --- a/deps/v8/third_party/abseil-cpp/absl/debugging/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/debugging/BUILD.bazel @@ -198,6 +198,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..8fcdb84514fa 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); @@ -421,7 +424,10 @@ TEST(Symbolize, SetSymbolDecorator) { static int in_data_section = 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..0e4008598ce2 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 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_test.cc b/deps/v8/third_party/abseil-cpp/absl/flags/flag_test.cc index 7cbce8876bc7..458f1b1cc604 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 @@ -1069,7 +1079,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 +1100,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 +1128,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 +1138,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 +1169,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/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/hash/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.bazel index 5fae4e2a2724..fe76a1d43050 100644 --- a/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.bazel @@ -96,9 +96,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..2ced4b17f8d9 100644 --- a/deps/v8/third_party/abseil-cpp/absl/hash/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/hash/CMakeLists.txt @@ -74,10 +74,9 @@ 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 ) 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/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/internal/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/random/internal/BUILD.bazel index efd013e65c26..d1bf943ca85f 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 = [ 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..3bd7b1b863aa 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; @@ -178,7 +166,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..dc7d622331c1 100644 --- a/deps/v8/third_party/abseil-cpp/absl/status/status.cc +++ b/deps/v8/third_party/abseil-cpp/absl/status/status.cc @@ -424,7 +424,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..19692b331b0d 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", 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..411a38406c5f 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", 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..23a32c9a4c39 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 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..1b60404e182d 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/cord.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/cord.cc @@ -558,6 +558,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 +638,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); } 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..1ae1f635c172 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 @@ -3030,6 +3030,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 +3080,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/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/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_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/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..977af6166521 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"], 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/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/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/time_zone_format.cc b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc index f97de2f95927..ee4341d509d6 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> @@ -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..cbaf09a1416c 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 } // 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..9d385b2772c4 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) { 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..b62e2687afbb 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 +2026d 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/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/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/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..0c6a15c5be41 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 @@ -114,7 +114,7 @@ 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..1c9b44b0499b 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 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/symbols_arm64_dbg.def b/deps/v8/third_party/abseil-cpp/symbols_arm64_dbg.def index c22828fe2d05..fc7599d47f0a 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,9 +95,6 @@ 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 @@ -126,6 +111,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 +267,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 +280,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 @@ -335,12 +321,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 +361,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 +397,11 @@ 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 + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@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 ??$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 +452,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 @@ -739,12 +724,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 +746,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 @@ -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 @@ -1373,15 +1351,15 @@ EXPORTS ??$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 +1370,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 +1389,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 +1409,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 +1426,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 +1457,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 +1518,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 @@ -1578,8 +1562,6 @@ EXPORTS ??$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@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 ??$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 +1584,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 +1603,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 @@ -1667,6 +1647,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 +1731,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 +1757,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 +2098,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 @@ -2170,9 +2152,9 @@ EXPORTS ??0Randen@random_internal@absl@@QEAA@XZ ??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 +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 @@ -2432,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 @@ -2626,6 +2609,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 +2649,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 @@ -2791,6 +2776,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 +2788,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 +2801,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 @@ -2867,6 +2849,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 @@ -3048,7 +3031,6 @@ 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 @@ -3058,14 +3040,12 @@ EXPORTS ?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 +3084,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 @@ -3198,8 +3179,8 @@ 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 + ?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 +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 @@ -3360,6 +3343,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 @@ -3489,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 @@ -3757,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 @@ -3785,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 @@ -3801,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 @@ -3958,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 @@ -4010,8 +3995,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -4405,9 +4390,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 @@ -5207,8 +5191,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 +5200,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 +5228,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 +5393,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 +5409,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,6 +5433,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@_K$07$02$00@container_internal@absl@@QEBA?AV123@XZ @@ -5504,7 +5488,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 +5511,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 +5564,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 +5605,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 +5628,23 @@ 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@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 +5659,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 +5724,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 +5757,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 +5803,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 +5847,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 +5873,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 +5899,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 +5909,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 +5925,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 +5974,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 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..b2b3d203f236 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,9 +95,6 @@ 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 @@ -125,6 +110,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 +267,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 +280,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 @@ -335,12 +321,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 +361,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 +397,11 @@ 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 + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@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 ??$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 +452,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 @@ -739,12 +724,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 +746,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 @@ -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 @@ -1379,15 +1357,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 +1376,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 +1395,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 +1415,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 +1432,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 +1463,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 +1524,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 @@ -1584,8 +1568,6 @@ EXPORTS ??$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@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 ??$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 +1590,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 +1609,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 @@ -1673,6 +1653,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 +1744,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 +1770,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 +2111,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 @@ -2183,9 +2165,9 @@ EXPORTS ??0Randen@random_internal@absl@@QEAA@XZ ??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 +2366,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 +2428,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 @@ -2639,6 +2622,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 +2662,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 @@ -2804,6 +2789,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 +2801,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 +2814,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 @@ -2880,6 +2862,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 @@ -3061,7 +3044,6 @@ 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 @@ -3071,14 +3053,12 @@ EXPORTS ?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 +3097,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 @@ -3211,8 +3192,8 @@ 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 + ?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 +3217,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 @@ -3373,6 +3356,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 @@ -3502,7 +3486,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 @@ -3769,7 +3753,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 +3781,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 +3797,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 +3954,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,8 +4007,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -4417,9 +4402,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 @@ -5232,8 +5216,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 +5225,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 +5253,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 +5418,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 +5434,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,6 +5458,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@_K$07$02$00@container_internal@absl@@QEBA?AV123@XZ @@ -5529,7 +5513,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 +5536,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 +5589,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 +5630,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 +5653,23 @@ 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@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 +5684,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 +5749,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 +5782,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 +5828,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 +5872,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 +5898,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 +5924,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 +5934,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 +5950,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 +5999,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 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..124024e0361b 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,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 @@ -491,6 +494,7 @@ EXPORTS ?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 ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ @@ -581,6 +585,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 +669,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 @@ -1026,8 +1033,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -1394,13 +1401,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 +1430,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 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..1740dfa2ef60 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,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 @@ -491,6 +494,7 @@ EXPORTS ?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 ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ @@ -581,6 +585,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 +669,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 @@ -1026,8 +1033,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -1394,13 +1401,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 +1430,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 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..b13cbbd2ac34 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,9 +95,6 @@ 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 @@ -126,6 +111,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 +267,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 +280,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 @@ -335,12 +321,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 +361,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 +397,11 @@ 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 + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@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 ??$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 +452,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 @@ -739,12 +724,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 +745,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 @@ -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 @@ -1373,15 +1351,15 @@ EXPORTS ??$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 +1370,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 +1389,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 +1409,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 +1426,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 +1457,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 +1518,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 @@ -1578,8 +1562,6 @@ EXPORTS ??$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@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 ??$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 +1584,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 +1603,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 @@ -1667,6 +1647,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 +1731,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 +1757,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 +2099,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 @@ -2171,9 +2153,9 @@ EXPORTS ??0Randen@random_internal@absl@@QEAA@XZ ??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 +2354,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 +2416,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 @@ -2627,6 +2610,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 +2650,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 @@ -2792,6 +2777,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 +2789,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 +2802,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 @@ -2868,6 +2850,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 @@ -3049,7 +3032,6 @@ 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 @@ -3059,14 +3041,12 @@ EXPORTS ?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 +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 @@ -3199,8 +3180,8 @@ 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 + ?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 +3205,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 @@ -3361,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 @@ -3490,7 +3474,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 @@ -3758,7 +3742,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 +3770,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 +3786,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 +3946,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,8 +3999,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -4409,9 +4394,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 @@ -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,23 @@ 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@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 +5664,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 +5729,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 +5762,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 +5808,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 +5852,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 +5878,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 +5904,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 +5914,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 +5930,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 +5979,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 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..df50963e9dac 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,9 +95,6 @@ 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 @@ -125,6 +110,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 +267,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 +280,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 @@ -335,12 +321,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 +361,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 +397,11 @@ 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 + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@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 ??$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 +452,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 @@ -739,12 +724,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 +745,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 @@ -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 @@ -1379,15 +1357,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 +1376,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 +1395,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 +1415,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 +1432,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 +1463,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 +1524,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 @@ -1584,8 +1568,6 @@ EXPORTS ??$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@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 ??$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 +1590,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 +1609,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 @@ -1673,6 +1653,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 +1744,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 +1770,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 +2112,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 @@ -2184,9 +2166,9 @@ EXPORTS ??0Randen@random_internal@absl@@QEAA@XZ ??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 +2367,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 +2429,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 @@ -2640,6 +2623,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 +2663,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 @@ -2805,6 +2790,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 +2802,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 +2815,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 @@ -2881,6 +2863,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 @@ -3062,7 +3045,6 @@ 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 @@ -3072,14 +3054,12 @@ EXPORTS ?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 +3098,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 @@ -3212,8 +3193,8 @@ 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 + ?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 +3218,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 @@ -3374,6 +3357,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 @@ -3503,7 +3487,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 @@ -3770,7 +3754,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 +3782,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 +3798,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 +3958,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,8 +4011,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -4421,9 +4406,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 @@ -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,23 @@ 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@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 +5689,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 +5754,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 +5787,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 +5833,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 +5877,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 +5903,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 +5929,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 +5939,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 +5955,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 +6004,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 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..f9756bcf4eb3 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 @@ -490,6 +493,7 @@ EXPORTS ?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 ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ @@ -579,6 +583,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 +667,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 @@ -1024,8 +1031,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -1393,13 +1400,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 +1427,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 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..b869046c341b 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 @@ -524,10 +527,10 @@ EXPORTS ?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 ?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 @@ -613,6 +616,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 +700,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 @@ -1059,8 +1065,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -1439,7 +1445,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 +1452,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 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..b9e0e052b4d4 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 @@ -524,10 +527,10 @@ EXPORTS ?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 ?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 @@ -613,6 +616,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 +700,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 @@ -1059,8 +1065,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -1439,7 +1445,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 +1452,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 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..01e8a6e908ea 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 @@ -490,6 +493,7 @@ EXPORTS ?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 ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ @@ -579,6 +583,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 +667,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 @@ -1024,8 +1031,8 @@ 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 + ?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@V?$FunctionRef@$$A6A_K_K@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z @@ -1393,13 +1400,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 +1427,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 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..60fbdf6034ec 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,9 +95,6 @@ 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 @@ -126,6 +111,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 +267,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 +280,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 @@ -335,12 +321,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 +361,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 +397,11 @@ 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 + ??$AssertIsFull@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBEPBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBE@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 ??$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 +452,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 @@ -738,12 +723,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 +744,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 @@ -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 @@ -1372,15 +1350,15 @@ EXPORTS ??$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 +1369,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 +1388,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 +1408,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 +1425,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 +1456,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 +1517,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 @@ -1577,8 +1561,6 @@ EXPORTS ??$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@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 ??$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 +1583,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 +1602,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 @@ -1666,6 +1646,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 +1730,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 +1756,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 +2097,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 @@ -2169,9 +2151,9 @@ EXPORTS ??0Randen@random_internal@absl@@QAE@XZ ??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 +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@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 +2414,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 @@ -2625,6 +2608,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 +2648,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 @@ -2790,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@@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 +2787,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 +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@@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 @@ -2866,6 +2848,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 @@ -3047,7 +3030,6 @@ 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 @@ -3057,14 +3039,12 @@ EXPORTS ?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 +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 @@ -3197,8 +3178,8 @@ 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 + ?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 +3203,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 @@ -3359,6 +3342,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 @@ -3488,7 +3472,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 @@ -3756,7 +3740,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 +3768,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 +3784,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 +3943,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,8 +3996,8 @@ 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 + ?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@V?$FunctionRef@$$A6AII@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AAEXXZ ?PrepareToModify@Status@absl@@CAPAVStatusRep@status_internal@2@I@Z @@ -4406,9 +4391,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 @@ -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,23 @@ 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@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 +5661,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 +5726,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 +5759,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 +5805,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 +5849,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 +5875,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 +5901,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 +5911,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 +5927,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 +5976,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 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..c74d42226c7f 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,9 +95,6 @@ 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 @@ -125,6 +110,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 +267,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 +280,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 @@ -335,12 +321,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 +361,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 +397,11 @@ 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 + ??$AssertIsFull@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBEPBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBE@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 ??$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 +452,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 @@ -738,12 +723,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 +744,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 @@ -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 @@ -1378,15 +1356,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 +1375,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 +1394,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 +1414,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 +1431,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 +1462,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 +1523,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 @@ -1583,8 +1567,6 @@ EXPORTS ??$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@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 ??$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 +1589,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 +1608,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 @@ -1672,6 +1652,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 +1743,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 +1769,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 +2110,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 @@ -2182,9 +2164,9 @@ EXPORTS ??0Randen@random_internal@absl@@QAE@XZ ??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 +2365,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 +2427,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 @@ -2638,6 +2621,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 +2661,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 @@ -2803,6 +2788,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 +2800,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 +2813,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 @@ -2879,6 +2861,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 @@ -3060,7 +3043,6 @@ 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 @@ -3070,14 +3052,12 @@ EXPORTS ?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 +3096,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 @@ -3210,8 +3191,8 @@ 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 + ?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 +3216,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 @@ -3372,6 +3355,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 @@ -3501,7 +3485,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 @@ -3768,7 +3752,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 +3780,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 +3796,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 +3955,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,8 +4008,8 @@ 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 + ?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@V?$FunctionRef@$$A6AII@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AAEXXZ ?PrepareToModify@Status@absl@@CAPAVStatusRep@status_internal@2@I@Z @@ -4418,9 +4403,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 @@ -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,23 @@ 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@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 +5686,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 +5751,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 +5784,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 +5830,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 +5874,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 +5900,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 +5926,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 +5936,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 +5952,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 +6001,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 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..f482c33dbe90 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 @@ -231,6 +232,7 @@ EXPORTS ??$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@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 ??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 @@ -492,6 +494,7 @@ EXPORTS ?AsciiStrToUpper@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPADPBDI@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 @@ -582,6 +585,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 +669,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 @@ -1028,8 +1034,8 @@ 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 + ?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@V?$FunctionRef@$$A6AII@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AAEXXZ ?PrepareToModify@Status@absl@@CAPAVStatusRep@status_internal@2@I@Z @@ -1398,13 +1404,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 +1431,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 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..b900ee8f44dd 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 @@ -230,8 +231,8 @@ EXPORTS ??$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@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 - ??$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 ??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 @@ -492,6 +493,7 @@ EXPORTS ?AsciiStrToUpper@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPADPBDI@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 @@ -582,6 +584,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 +668,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 @@ -1028,8 +1033,8 @@ 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 + ?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@V?$FunctionRef@$$A6AII@Z@2@@Z ?PrepareToDie@LogMessage@log_internal@absl@@AAEXXZ ?PrepareToModify@Status@absl@@CAPAVStatusRep@status_internal@2@I@Z @@ -1398,13 +1403,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 +1430,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 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/json_platform_v8.cc b/deps/v8/third_party/inspector_protocol/crdtp/json_platform_v8.cc index b3050427bf0a..e6394dea88fe 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 @@ -7,7 +7,7 @@ #include "json_platform.h" #include <cmath> -#include "../../../src/base/vector.h" +#include "../../../src/base/unique-array.h" #include "../../../src/numbers/conversions.h" namespace v8_crdtp { @@ -22,7 +22,7 @@ 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( + auto buffer = v8::base::UniqueArray<char>::NewForOverwrite( v8::internal::kDoubleToStringMinBufferSize); return std::string( v8::internal::DoubleToStringView(value, buffer.as_vector())); 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..cf8b1f36d349 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 @@ -194,6 +205,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 +245,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 +296,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 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_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..0c265b029b99 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 @@ -57,6 +57,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 +558,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 +569,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 +580,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 +591,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 +719,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 +738,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 @@ -783,6 +803,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 +814,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 +872,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 +882,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 +1435,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/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_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/include/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/include/CMakeLists.txt index a45026de31ee..648d75b4b511 100644 --- a/deps/v8/third_party/llvm-libc/src/include/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/include/CMakeLists.txt @@ -438,6 +438,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 @@ -584,6 +585,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 @@ -745,6 +747,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 +1108,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,6 +1118,7 @@ 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 ) @@ -1194,6 +1210,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 +1273,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/llvm-libc-macros/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/CMakeLists.txt index 9e9559056dae..2d461c279ba6 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( @@ -276,6 +292,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 +405,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/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..77964fd530cc 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 @@ -46,6 +46,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 +108,12 @@ add_header( sys-wait-macros.h ) +add_header( + sys_xattr_macros + HDR + sys-xattr-macros.h +) + add_header( sys_sysmacros_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..f21339abfaad 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 @@ -22,6 +22,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 +59,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 +87,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/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-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..0a9facd82fcb 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 @@ -30,6 +30,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/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-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..817aca0e68bb 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 @@ -60,6 +60,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 +78,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) @@ -314,6 +316,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/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/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_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/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..5c73f6dd7994 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 @@ -106,15 +107,10 @@ functions: - 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..1ac0422866fb 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 @@ -353,6 +361,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 +435,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/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/unistd.yaml b/deps/v8/third_party/llvm-libc/src/include/unistd.yaml index 890a4ae21f19..92951152b7ca 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 @@ -250,6 +252,22 @@ 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: fpathconf standards: - posix @@ -417,6 +435,12 @@ functions: arguments: - type: const char * - type: int + - name: pause + standards: + - posix + return_type: int + arguments: + - type: void - name: pipe standards: - posix 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..cc31ced36cf2 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( 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..6777c6a27c0c 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 @@ -253,20 +253,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/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/FEnvImpl.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FEnvImpl.h index 4c897e724382..6f77ce44c705 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. @@ -165,7 +165,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 +178,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 +191,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 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/File/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/File/CMakeLists.txt index f369fec9a915..9553ba2cf11e 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,11 @@ +add_header_library( + file_io_result + HDRS + file_io_result.h + DEPENDS + libc.src.__support.macros.config +) + 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,6 +20,7 @@ add_object_library( HDRS file.h DEPENDS + .file_io_result libc.hdr.stdio_macros libc.hdr.stdint_proxy libc.hdr.func.realloc @@ -32,6 +41,19 @@ add_object_library( libc.hdr.errno_macros ) +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( dir SRCS @@ -39,6 +61,7 @@ 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 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..c296b99e2ffe 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,10 +1,15 @@ -//===--- 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" @@ -459,6 +464,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. 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..84dde0560f46 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,21 +1,26 @@ -//===--- 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/config.h" #include "src/__support/macros/properties/architectures.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. @@ -228,34 +221,8 @@ class File { 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| 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..8049516da261 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; } @@ -108,6 +111,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 +122,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 +145,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..05efc0f6f613 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 @@ -14,6 +14,7 @@ add_object_library( libc.hdr.types.off_t libc.src.__support.CPP.new 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 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..1d360c15bfa8 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 @@ -15,7 +15,7 @@ #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" @@ -87,6 +87,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; } @@ -119,6 +127,14 @@ ErrorOr<File *> openfile(const char *path, const char *mode) { return file; } +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) { const FileMode file_mode(mode); @@ -139,6 +155,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)) { @@ -195,6 +217,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 +241,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_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/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt index f5f28f51f49f..a3f56b1117c2 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 @@ -215,6 +215,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 @@ -694,6 +775,20 @@ 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( ftruncate HDRS @@ -798,6 +893,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 +1037,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 @@ -1056,6 +1177,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 +1270,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 +1300,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 +1364,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 @@ -1356,3 +1544,81 @@ 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 +) 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/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/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/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/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/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/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/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/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/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/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..e251f917d985 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 @@ -37,6 +37,14 @@ #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) + #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) 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..fa62887a250c 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") 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..ef33e3f8ada7 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 @@ -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,32 @@ 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.properties.cpu_features +) + add_header_library( cosf16 HDRS @@ -3078,6 +3104,7 @@ 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 ) @@ -5402,24 +5429,82 @@ 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.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 +5538,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 +5553,32 @@ 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.properties.cpu_features +) + add_header_library( sinf16 HDRS 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..5788ee2ec86f 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,41 @@ -//===-- 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/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/exp10f_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp10f_double_eval.h index e1a7cc9d68e9..75daf79bf676 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 @@ -27,67 +27,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)); +} + +[[gnu::cold, gnu::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 +106,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/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/expf_float_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_float_eval.h index e479cb58d2fe..ab8ad649c539 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 @@ -100,11 +100,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); 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..d5858df303d6 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 @@ -435,9 +435,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 +470,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/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/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/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..023ba56d55cc --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_float_eval.h @@ -0,0 +1,260 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// 5-bit lookup table (32 entries): +// dx = r * m_x - 1 in [-2^-6, 2^-5]. +// 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_32 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^-6, 2^-5]); +// > dirtyinfnorm(((log2(1 + x) - x * log2_e) - x^2 * Q) / x, [-2^-6, 2^-5]); +// 0x1.0af1...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^-5, 1) (where e_x = -1 and R[31] = 0.5 so +// -log2(R[31]) = 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_u = ybits.uintval(); + uint32_t y_a = ybits.abs().uintval(); + + if (LIBC_UNLIKELY((x_u & 0x007F'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(); + } + + 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 - 5)); + 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^-6, 2^-5]); + // > dirtyinfnorm(((log2(1 + x) - x * log2_e) - x^2 * Q) / x, [-2^-6, 2^-5]); + // 0x1.0af1...p-34 + constexpr float COEFFS[] = {-0x1.715476p-1f, 0x1.ec709ep-2f, -0x1.71618ap-2f, + 0x1.2810e4p-2f, -0x1.ae42b2p-3f}; + + // Range reduction for log2(m_x): + // dx = r * m_x - 1 in [-2^-6, 2^-5). + // The computation is exact: m_x = (1 + dx) / r. + float r = powf_internal::R_32[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_32[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^-5, |log2(1 + dx) - dx * log2(e)| <= (dx^2 / 2) * log2(e) < + // 2^-10. 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); + int64_t k = static_cast<int64_t>(kf); + + float rem_hi = total_hi - kf; + float rem = rem_hi + total_lo; + + // Normal range: -125 <= k <= 127. + uint64_t k_u = static_cast<uint64_t>(k + 125); + if (LIBC_LIKELY(k_u <= 252)) { + float result = exp2f_eval(rem, static_cast<int>(k)); + return cpp::bit_cast<float>(cpp::bit_cast<uint32_t>(result) | sign); + } + + // Exceptional path: k > 128 (overflow), k < -150 (underflow), or subnormal. + if (k > 128) + return set_overflow(out_sign); + + if (k < -150) + return set_underflow(out_sign); + + // Subnormal range: -150 <= k <= -126. + if (k <= -126) { + float result = exp2f_eval(rem, static_cast<int>(k)); + float res = cpp::bit_cast<float>(cpp::bit_cast<uint32_t>(result) | sign); + + if (LIBC_UNLIKELY(FPBits(res).is_normal())) + return res; + + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<float>(); + return res; + } + + // Boundary case: k = 128. + float result = exp2f_eval(rem, static_cast<int>(k)); + if (LIBC_UNLIKELY(FPBits(result).is_inf())) + return set_overflow(out_sign); + + 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..2a2253bd2737 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_utils.h @@ -0,0 +1,729 @@ +//===----------------------------------------------------------------------===// +// +// 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/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 + +#ifndef LIBC_MATH_HAS_SMALL_TABLES +#include "src/__support/math/exp10f.h" +#include "src/__support/math/exp2f.h" +#endif // !LIBC_MATH_HAS_SMALL_TABLES + +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 5-bit (32 entries) range reduction for float_eval and +// double_eval fast path: +// r(0) = 1.0f +// r(i) = 2^-6 * ceil(2^6 * (1 - 2^-6) / (1 + i * 2^-5)), i = 1..31. +// 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^-6 <= dx < 2^-5. +// +// Generated by Sollya with: +// > display = hexadecimal; +// > for i from 0 to 31 do { +// if (i == 0) then { +// print("0x1.0p+0f,"); +// } else { +// r = 2^(-6) * ceil( 2^6 * (1 - 2^(-6)) / (1 + i*2^(-5)) ); +// print(r @ "f,"); +// }; +// }; +LIBC_INLINE_VAR constexpr float R_32[32] = { + 0x1.0p+0f, 0x1.fp-1f, 0x1.ep-1f, 0x1.dp-1f, 0x1.cp-1f, 0x1.b8p-1f, + 0x1.bp-1f, 0x1.ap-1f, 0x1.98p-1f, 0x1.9p-1f, 0x1.8p-1f, 0x1.78p-1f, + 0x1.7p-1f, 0x1.68p-1f, 0x1.6p-1f, 0x1.58p-1f, 0x1.5p-1f, 0x1.5p-1f, + 0x1.48p-1f, 0x1.4p-1f, 0x1.38p-1f, 0x1.38p-1f, 0x1.3p-1f, 0x1.28p-1f, + 0x1.2p-1f, 0x1.2p-1f, 0x1.18p-1f, 0x1.18p-1f, 0x1.1p-1f, 0x1.1p-1f, + 0x1.08p-1f, 0x1.0p-1f, +}; + +// R_32 represented in double precision for double_eval. +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[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_32[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_32[i].hi +// is exact in float for |e_x| <= 150. +// For i = 31, R_32[31] = 0.5, so -log2(R_32[31]) = 1.0f is exact. +// +// Generated by Sollya with: +// > display = hexadecimal; +// > prec = 200; +// > for i from 0 to 31 do { +// if (i == 0) then { +// print("{0x0.000000p+0f, 0x0.000000p+0f},"); +// } else if (i == 31) then { +// print("{0x0.000000p+0f, 0x1.000000p+0f},"); +// } else { +// r = 2^(-6) * ceil( 2^6 * (1 - 2^(-6)) / (1 + i*2^(-5)) ); +// 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_32[32] = { + {0x0.000000p+0f, 0x0.000000p+0f}, {-0x1.acd89ap-19f, 0x1.774p-5f}, + {0x1.25b3eep-22f, 0x1.7d6p-4f}, {0x1.6e155ap-18f, 0x1.22d8p-3f}, + {0x1.80abfcp-19f, 0x1.8a88p-3f}, {-0x1.858p-19f, 0x1.bfc8p-3f}, + {-0x1.3ab7cep-18f, 0x1.f6p-3f}, {-0x1.1c8f12p-22f, 0x1.32cp-2f}, + {-0x1.134c4ep-20f, 0x1.4f7p-2f}, {0x1.ed0cbap-19f, 0x1.6cbp-2f}, + {-0x1.a39fbep-20f, 0x1.a9p-2f}, {0x1.dc2d46p-18f, 0x1.c818p-2f}, + {-0x1.40358ep-19f, 0x1.e7ep-2f}, {-0x1.5a32c2p-20f, 0x1.042cp-1f}, + {-0x1.3e032ep-18f, 0x1.14c6p-1f}, {0x1.408c78p-18f, 0x1.25c0p-1f}, + {0x1.5db83ap-20f, 0x1.3722p-1f}, {0x1.5db83ap-20f, 0x1.3722p-1f}, + {0x1.e3263p-18f, 0x1.48eep-1f}, {0x1.ed0cbap-20f, 0x1.5b2cp-1f}, + {-0x1.eac382p-20f, 0x1.6de0p-1f}, {-0x1.eac382p-20f, 0x1.6de0p-1f}, + {-0x1.6b9026p-19f, 0x1.811p-1f}, {0x1.0e9258p-18f, 0x1.94c2p-1f}, + {-0x1.a39fbep-19f, 0x1.a9p-1f}, {-0x1.a39fbep-19f, 0x1.a9p-1f}, + {0x1.3b992cp-18f, 0x1.bdcep-1f}, {0x1.3b992cp-18f, 0x1.bdcep-1f}, + {0x1.20a6dep-21f, 0x1.d338p-1f}, {0x1.20a6dep-21f, 0x1.d338p-1f}, + {-0x1.a6eb1ep-18f, 0x1.e946p-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; + +// 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(float x) { + using FPBits = fputil::FPBits<float>; + FPBits xbits(x); + uint32_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(float x) { + if (x == 0.0f) + return true; + using FPBits = fputil::FPBits<float>; + FPBits xbits(x); + uint32_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 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 FPBits::inf(sign).get_val(); +} + +LIBC_INLINE float set_underflow(Sign sign = Sign::POS) { + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_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_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 FPBits::zero(sign).get_val(); +} + +// 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 && 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 FPBits::inf(out_is_neg ? Sign::NEG : 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 || is_integer(y)) { + Sign out_sign = (x_sign && 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(); + } + } + } + +#ifndef LIBC_MATH_HAS_SMALL_TABLES + 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 + + 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(); + } + + // 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()) { + // 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). + bool out_is_neg = x_sign && is_odd_integer(y); + Sign out_sign = out_is_neg ? Sign::NEG : Sign::POS; + return y_sign ? FloatBits::zero(out_sign).get_val() + : FloatBits::inf(out_sign).get_val(); + } + + if (x_a > FloatBits::inf().uintval()) { + // x is NaN. + return x; + } + + if (x_a == 0) { + bool out_is_neg = x_sign && is_odd_integer(y); + if (y_sign) { + 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(); + } + return out_is_neg ? -0.0f : 0.0f; + } + + // Handle negative base x < 0: + // - If y is an integer: (-|x|)^y = (-1)^y * |x|^y. + // - If y is not an integer: (-|x|)^y is undefined in real numbers; + // raises FE_INVALID, sets errno to EDOM, and returns quiet NaN. + if (x_sign) { + if (is_integer(y)) { + x = -x; + if (is_odd_integer(y)) { + if constexpr (sizeof(SignType) == 8) + sign = 0x8000'0000'0000'0000ULL; + else + sign = 0x8000'0000U; + } + } 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(); + } + } + + if (y_a <= Y_LOWER_BOUND) { + volatile float one = 1.0f; + volatile float eps = ((x_a < FloatBits::one().uintval()) == !y_sign) + ? -0x1.0p-50f + : 0x1.0p-50f; + return one + eps; + } + + // Normalize denormal inputs. + if (x_a < FloatBits::min_normal().uintval()) { + int shift = cpp::countl_zero(x_a) - 8; + 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/sinf.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf.h index 1f72618a2962..5e3aa24a42ca 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,41 @@ -//===-- 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/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/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/cosf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cosf.h index b6ea0c848afd..0d3cbe292289 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 @@ -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/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/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..03b680010b00 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 @@ -89,10 +89,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 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..602969622332 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 { @@ -118,11 +102,10 @@ 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; 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..974765a9667f 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 @@ -489,9 +489,10 @@ FloatWriter(Writer<mode>, bool, const PaddingWriter<mode>) -> FloatWriter<mode>; // https://doi.org/10.1145/3360595 template <typename T, OverflowMode mode, 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> *writer, + const FormatSection &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(); @@ -599,9 +600,10 @@ LIBC_INLINE int convert_float_decimal_typed(Writer<mode> *writer, template <typename T, OverflowMode mode, 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> *writer, + const FormatSection &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(); @@ -760,9 +762,10 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer<mode> *writer, template <typename T, OverflowMode mode, 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> *writer, + const FormatSection &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(); @@ -818,7 +821,7 @@ 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(); @@ -1100,7 +1103,7 @@ 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 @@ -1120,7 +1123,7 @@ 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); } } @@ -1129,13 +1132,17 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, template <OverflowMode mode> LIBC_INLINE int convert_float_decimal(Writer<mode> *writer, const FormatSection &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 +1152,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 +1164,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) { + 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 +1197,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 +1209,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) { + 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 +1242,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 +1254,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..afdfd68a5137 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 @@ -375,11 +375,11 @@ DigitsOutput decimal_digits(DigitsInput input, int precision, bool e_mode) { } 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) { +LIBC_INLINE int convert_finite_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 = '.'; // If to_conv doesn't specify a precision, the precision defaults to 6. unsigned precision = to_conv.precision < 0 ? 6 : to_conv.precision; @@ -621,26 +621,30 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, template <typename T, OverflowMode mode, 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); +convert_finite_float_typed(Writer<mode> *writer, const FormatSection &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, 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 +653,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,35 +665,44 @@ 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, 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> *writer, + const FormatSection &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, 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> *writer, + const FormatSection &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, 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> *writer, + const FormatSection &to_conv, + fputil::FPBits<T> float_bits) { + return convert_finite_float_typed<T>(writer, to_conv, float_bits, + ConversionType::G); } template <OverflowMode mode> 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..ee751901dda1 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 @@ -26,30 +26,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, }; } +// Returns relevant floating point properties for conversion using +// `to_conv.length_modifier` to infer the conversion value type. +LIBC_INLINE FloatHexExpFPBitsProperties +get_float_hex_exp_fp_bits_properties_lm(const FormatSection &to_conv) { +#if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) + if (to_conv.length_modifier == LengthModifier::Q) + return get_float_hex_exp_fp_bits_properties_typed<float128>( + fputil::FPBits<float128>(to_conv.conv_val_raw)); +#endif // LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128 +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + if (to_conv.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>( + to_conv.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>( + to_conv.conv_val_raw))); +} + template <OverflowMode mode> -LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, - const FormatSection &to_conv) { +LIBC_INLINE int +convert_finite_float_hex_exp(Writer<mode> *writer, + FloatHexExpFPBitsProperties fp_bits_properties, + const FormatSection &to_conv) { #if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) static constexpr uint32_t MAX_POSSIBLE_FRACTION_LEN = fputil::FPBits<float128>::FRACTION_LEN; @@ -67,30 +90,9 @@ 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); - } - - if (properties.is_inf_or_nan) - return convert_inf_nan(writer, to_conv); - char sign_char = 0; - if (properties.is_negative) + if (fp_bits_properties.is_negative) sign_char = '-'; else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX @@ -104,9 +106,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. @@ -117,7 +120,7 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, (MAX_POSSIBLE_FRACTION_LEN / BITS_IN_HEX_DIGIT) + 1; char 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 +131,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 +170,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,8 +181,8 @@ 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); + for (; mant_cur > 0; --mant_cur, fp_bits_properties.mantissa >>= 4) { + char mant_mod_16 = static_cast<char>(fp_bits_properties.mantissa % 16); char new_digit = internal::int_to_b36_char(mant_mod_16); if (internal::isupper(to_conv.conv_name)) new_digit = internal::toupper(new_digit); @@ -200,15 +206,16 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, char 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) { + for (; fp_bits_properties.exponent > 0; + --exp_cur, fp_bits_properties.exponent /= 10) { exp_buffer[exp_cur - 1] = - internal::int_to_b36_char(properties.exponent % 10); + internal::int_to_b36_char(fp_bits_properties.exponent % 10); } if (exp_cur == EXP_LEN) { // if nothing else was written, write a 0. exp_buffer[EXP_LEN - 1] = '0'; @@ -295,6 +302,21 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, return WRITE_OK; } +template <OverflowMode mode> +LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, + const FormatSection &to_conv) { + FloatHexExpFPBitsProperties fp_bits_properties = + get_float_hex_exp_fp_bits_properties_lm(to_conv); + 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..5d306a13d5f1 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 @@ -27,41 +27,15 @@ 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, + InfNanFPBitsProperties fp_bits_properties, const FormatSection &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; - if (properties.is_negative) + if (fp_bits_properties.is_negative) sign_char = '-'; else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX @@ -81,7 +55,7 @@ LIBC_INLINE int convert_inf_nan(Writer<mode> *writer, if (sign_char) RET_IF_RESULT_NEGATIVE(writer->write(sign_char)); - if (properties.mantissa_is_zero) { // inf + if (fp_bits_properties.mantissa_is_zero) { // inf RET_IF_RESULT_NEGATIVE( writer->write(internal::islower(to_conv.conv_name) ? "inf" : "INF")); } else { // nan 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..a04f481f79e6 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 @@ -119,7 +119,7 @@ template <typename ArgProvider, typename CharT> class Parser { LIBC_INLINE BasicFormatSection<CharT> get_next_section() { BasicFormatSection<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/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/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/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..d82b0c8e9791 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,12 +40,27 @@ 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 @@ -59,6 +74,7 @@ add_object_library( libc.src.__support.CPP.string_view libc.src.__support.common libc.src.__support.error_or + libc.src.__support.OSUtil.linux.syscall_wrappers.clone libc.src.__support.OSUtil.linux.syscall_wrappers.close libc.src.__support.OSUtil.linux.syscall_wrappers.getpid libc.src.__support.OSUtil.linux.syscall_wrappers.mmap @@ -75,10 +91,6 @@ add_object_library( 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..b83ccbb1ee05 --- /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.mmap + libc.src.__support.OSUtil.linux.syscall_wrappers.munmap + libc.src.__support.threads.linux.tcb + libc.src.string.memory_utils.inline_memcpy + COMPILE_OPTIONS + ${libc_opt_high_flag} + -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..fef46c109fa3 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/aarch64/tls.cpp @@ -0,0 +1,81 @@ +//===-- 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/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()) + syscall_impl<long>(SYS_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..b83ccbb1ee05 --- /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.mmap + libc.src.__support.OSUtil.linux.syscall_wrappers.munmap + libc.src.__support.threads.linux.tcb + libc.src.string.memory_utils.inline_memcpy + COMPILE_OPTIONS + ${libc_opt_high_flag} + -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..5bd338dbd991 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/riscv/tls.cpp @@ -0,0 +1,57 @@ +//===-- 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/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()) + syscall_impl<long>(SYS_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..948a8582ca25 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,16 +1,22 @@ -//===--- 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/syscall_wrappers/clone.h" #include "src/__support/OSUtil/linux/syscall_wrappers/close.h" #include "src/__support/OSUtil/linux/syscall_wrappers/getpid.h" #include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h" @@ -32,19 +38,15 @@ #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. -#include <linux/prctl.h> // For PR_SET_NAME -#include <sys/syscall.h> // For syscall numbers. +#include <linux/param.h> // For EXEC_PAGESIZE. +#include <linux/prctl.h> // For PR_SET_NAME +#include <sys/syscall.h> // For syscall numbers. namespace LIBC_NAMESPACE_DECL { @@ -62,16 +64,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 +150,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 +161,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 +210,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 +265,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 +342,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() + 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..e827fb2d7e9c --- /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.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 + ${libc_opt_high_flag} + -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..82462e3975ae --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/x86_64/tls.cpp @@ -0,0 +1,75 @@ +//===-- 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/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()) + syscall_impl<long>(SYS_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()) + syscall_impl(SYS_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/thread.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread.cpp index abcf7e399c16..950dea837d0f 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 { @@ -151,12 +153,29 @@ extern "C" int __cxa_thread_atexit_impl(AtExitCallback *callback, void *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..56cca8e3c915 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); 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/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..77f0e29e0d6b 100644 --- a/deps/v8/third_party/zlib/chromeconf.h +++ b/deps/v8/third_party/zlib/chromeconf.h @@ -207,8 +207,5 @@ /* Symbols added by cpu_features.c */ #define cpu_check_features Cr_z_cpu_check_features #define x86_cpu_enable_sse2 Cr_z_x86_cpu_enable_sse2 -#define x86_cpu_enable_avx512 Cr_z_x86_cpu_enable_avx512 -#define riscv_cpu_enable_rvv Cr_z_riscv_cpu_enable_rvv -#define riscv_cpu_enable_vclmul Cr_z_riscv_cpu_enable_vclmul #endif /* THIRD_PARTY_ZLIB_CHROMECONF_H_ */ 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..9ed76fd8272e 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' @@ -443,7 +447,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 +467,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_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/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..947be254ea44 100644 --- a/deps/v8/tools/debug_helper/get-object-properties.cc +++ b/deps/v8/tools/debug_helper/get-object-properties.cc @@ -826,6 +826,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/setup_worktree_build.py b/deps/v8/tools/dev/setup_worktree_build.py index 419809f1ac73..484334243dbb 100755 --- a/deps/v8/tools/dev/setup_worktree_build.py +++ b/deps/v8/tools/dev/setup_worktree_build.py @@ -2,6 +2,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. +"""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 @@ -19,22 +31,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, @@ -223,32 +246,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 +405,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/gcmole.cc b/deps/v8/tools/gcmole/gcmole.cc index 4e1b063ef7f9..4ce8ebb7f985 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); @@ -1066,7 +1070,16 @@ class FunctionAnalyzer { clang::CXXRecordDecl* cleared_weak_value_decl, clang::ClassTemplateDecl* tagged_decl, clang::CXXRecordDecl* js_dispatch_handle_decl, + clang::TypedefNameDecl* external_pointer_handle_decl, + clang::TypedefNameDecl* cpp_heap_pointer_handle_decl, + clang::TypedefNameDecl* indirect_pointer_handle_decl, clang::CXXRecordDecl* js_dispatch_handle_member_decl, + clang::ClassTemplateDecl* external_pointer_member_decl, + clang::ClassTemplateDecl* trusted_pointer_member_decl, + clang::CXXRecordDecl* cpp_heap_pointer_member_decl, + clang::CXXRecordDecl* external_pointer_slot_decl, + clang::CXXRecordDecl* cpp_heap_pointer_slot_decl, + clang::CXXRecordDecl* indirect_pointer_slot_decl, clang::ClassTemplateDecl* tagged_member_decl, clang::ClassTemplateDecl* unaligned_value_member_decl, clang::CXXRecordDecl* unaligned_double_member_decl, @@ -1080,7 +1093,16 @@ class FunctionAnalyzer { cleared_weak_value_decl_(cleared_weak_value_decl), tagged_decl_(tagged_decl), js_dispatch_handle_decl_(js_dispatch_handle_decl), + external_pointer_handle_decl_(external_pointer_handle_decl), + cpp_heap_pointer_handle_decl_(cpp_heap_pointer_handle_decl), + indirect_pointer_handle_decl_(indirect_pointer_handle_decl), js_dispatch_handle_member_decl_(js_dispatch_handle_member_decl), + external_pointer_member_decl_(external_pointer_member_decl), + trusted_pointer_member_decl_(trusted_pointer_member_decl), + cpp_heap_pointer_member_decl_(cpp_heap_pointer_member_decl), + external_pointer_slot_decl_(external_pointer_slot_decl), + cpp_heap_pointer_slot_decl_(cpp_heap_pointer_slot_decl), + indirect_pointer_slot_decl_(indirect_pointer_slot_decl), tagged_member_decl_(tagged_member_decl), unaligned_value_member_decl_(unaligned_value_member_decl), unaligned_double_member_decl_(unaligned_double_member_decl), @@ -1263,6 +1285,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 +1419,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); } @@ -1807,19 +1847,46 @@ class FunctionAnalyzer { return false; } - bool IsRawPointerToOnHeapValue(const clang::CXXRecordDecl* record) { - if (record == nullptr) return false; - - if (js_dispatch_handle_decl_ && + bool IsTableHandleType(clang::QualType qtype) { + if (qtype.isNull()) return false; + const clang::CXXRecordDecl* record = qtype->getAsCXXRecordDecl(); + if (record && js_dispatch_handle_decl_ && record->getCanonicalDecl() == js_dispatch_handle_decl_) { 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 ((external_pointer_handle_decl_ && + decl == external_pointer_handle_decl_) || + (cpp_heap_pointer_handle_decl_ && + decl == cpp_heap_pointer_handle_decl_) || + (indirect_pointer_handle_decl_ && + decl == indirect_pointer_handle_decl_)) { + return true; + } + current = decl->getUnderlyingType(); } - if (unaligned_double_member_decl_ && - record->getCanonicalDecl() == unaligned_double_member_decl_) { + return false; + } + + bool IsRawPointerToOnHeapValue(const clang::CXXRecordDecl* record) { + if (record == nullptr) return false; + + const clang::CXXRecordDecl* canonical = record->getCanonicalDecl(); + if ((js_dispatch_handle_member_decl_ && + canonical == js_dispatch_handle_member_decl_) || + (cpp_heap_pointer_member_decl_ && + canonical == cpp_heap_pointer_member_decl_) || + (external_pointer_slot_decl_ && + canonical == external_pointer_slot_decl_) || + (cpp_heap_pointer_slot_decl_ && + canonical == cpp_heap_pointer_slot_decl_) || + (indirect_pointer_slot_decl_ && + canonical == indirect_pointer_slot_decl_) || + (unaligned_double_member_decl_ && + canonical == unaligned_double_member_decl_)) { return true; } @@ -1829,6 +1896,10 @@ class FunctionAnalyzer { auto* template_decl = specialization->getSpecializedTemplate()->getCanonicalDecl(); if ((tagged_member_decl_ && template_decl == tagged_member_decl_) || + (external_pointer_member_decl_ && + template_decl == external_pointer_member_decl_) || + (trusted_pointer_member_decl_ && + template_decl == trusted_pointer_member_decl_) || (unaligned_value_member_decl_ && template_decl == unaligned_value_member_decl_)) { return true; @@ -1857,11 +1928,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; @@ -2102,7 +2172,16 @@ class FunctionAnalyzer { clang::CXXRecordDecl* cleared_weak_value_decl_; clang::ClassTemplateDecl* tagged_decl_; clang::CXXRecordDecl* js_dispatch_handle_decl_; + clang::TypedefNameDecl* external_pointer_handle_decl_; + clang::TypedefNameDecl* cpp_heap_pointer_handle_decl_; + clang::TypedefNameDecl* indirect_pointer_handle_decl_; clang::CXXRecordDecl* js_dispatch_handle_member_decl_; + clang::ClassTemplateDecl* external_pointer_member_decl_; + clang::ClassTemplateDecl* trusted_pointer_member_decl_; + clang::CXXRecordDecl* cpp_heap_pointer_member_decl_; + clang::CXXRecordDecl* external_pointer_slot_decl_; + clang::CXXRecordDecl* cpp_heap_pointer_slot_decl_; + clang::CXXRecordDecl* indirect_pointer_slot_decl_; clang::ClassTemplateDecl* tagged_member_decl_; clang::ClassTemplateDecl* unaligned_value_member_decl_; clang::CXXRecordDecl* unaligned_double_member_decl_; @@ -2261,9 +2340,36 @@ class ProblemsFinder : public clang::ASTConsumer, clang::CXXRecordDecl* js_dispatch_handle_decl = v8_internal.Resolve<clang::CXXRecordDecl>("JSDispatchHandle"); + clang::TypedefNameDecl* external_pointer_handle_decl = + v8_internal.Resolve<clang::TypedefNameDecl>("ExternalPointerHandle"); + + clang::TypedefNameDecl* cpp_heap_pointer_handle_decl = + v8_internal.Resolve<clang::TypedefNameDecl>("CppHeapPointerHandle"); + + clang::TypedefNameDecl* indirect_pointer_handle_decl = + v8_internal.Resolve<clang::TypedefNameDecl>("IndirectPointerHandle"); + clang::CXXRecordDecl* js_dispatch_handle_member_decl = v8_internal.Resolve<clang::CXXRecordDecl>("JSDispatchHandleMember"); + clang::ClassTemplateDecl* external_pointer_member_decl = + v8_internal.Resolve<clang::ClassTemplateDecl>("ExternalPointerMember"); + + clang::ClassTemplateDecl* trusted_pointer_member_decl = + v8_internal.Resolve<clang::ClassTemplateDecl>("TrustedPointerMember"); + + clang::CXXRecordDecl* cpp_heap_pointer_member_decl = + v8_internal.Resolve<clang::CXXRecordDecl>("CppHeapPointerMember"); + + clang::CXXRecordDecl* external_pointer_slot_decl = + v8_internal.Resolve<clang::CXXRecordDecl>("ExternalPointerSlot"); + + clang::CXXRecordDecl* cpp_heap_pointer_slot_decl = + v8_internal.Resolve<clang::CXXRecordDecl>("CppHeapPointerSlot"); + + clang::CXXRecordDecl* indirect_pointer_slot_decl = + v8_internal.Resolve<clang::CXXRecordDecl>("IndirectPointerSlot"); + clang::ClassTemplateDecl* tagged_member_decl = v8_internal.Resolve<clang::ClassTemplateDecl>("TaggedMember"); @@ -2293,11 +2399,56 @@ class ProblemsFinder : public clang::ASTConsumer, js_dispatch_handle_decl = js_dispatch_handle_decl->getCanonicalDecl(); } + if (external_pointer_handle_decl != nullptr) { + external_pointer_handle_decl = + external_pointer_handle_decl->getCanonicalDecl(); + } + + if (cpp_heap_pointer_handle_decl != nullptr) { + cpp_heap_pointer_handle_decl = + cpp_heap_pointer_handle_decl->getCanonicalDecl(); + } + + if (indirect_pointer_handle_decl != nullptr) { + indirect_pointer_handle_decl = + indirect_pointer_handle_decl->getCanonicalDecl(); + } + if (js_dispatch_handle_member_decl != nullptr) { js_dispatch_handle_member_decl = js_dispatch_handle_member_decl->getCanonicalDecl(); } + if (external_pointer_member_decl != nullptr) { + external_pointer_member_decl = + external_pointer_member_decl->getCanonicalDecl(); + } + + if (trusted_pointer_member_decl != nullptr) { + trusted_pointer_member_decl = + trusted_pointer_member_decl->getCanonicalDecl(); + } + + if (cpp_heap_pointer_member_decl != nullptr) { + cpp_heap_pointer_member_decl = + cpp_heap_pointer_member_decl->getCanonicalDecl(); + } + + if (external_pointer_slot_decl != nullptr) { + external_pointer_slot_decl = + external_pointer_slot_decl->getCanonicalDecl(); + } + + if (cpp_heap_pointer_slot_decl != nullptr) { + cpp_heap_pointer_slot_decl = + cpp_heap_pointer_slot_decl->getCanonicalDecl(); + } + + if (indirect_pointer_slot_decl != nullptr) { + indirect_pointer_slot_decl = + indirect_pointer_slot_decl->getCanonicalDecl(); + } + if (tagged_member_decl != nullptr) { tagged_member_decl = tagged_member_decl->getCanonicalDecl(); } @@ -2317,10 +2468,14 @@ class ProblemsFinder : public clang::ASTConsumer, 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_); + js_dispatch_handle_decl, external_pointer_handle_decl, + cpp_heap_pointer_handle_decl, indirect_pointer_handle_decl, + js_dispatch_handle_member_decl, external_pointer_member_decl, + trusted_pointer_member_decl, cpp_heap_pointer_member_decl, + external_pointer_slot_decl, cpp_heap_pointer_slot_decl, + indirect_pointer_slot_decl, tagged_member_decl, + unaligned_value_member_decl, unaligned_double_member_decl, + no_gc_mole_decl, conservative_pinning_scope_decl, d_, sm_); TraverseDecl(ctx.getTranslationUnitDecl()); } else if (g_verbose) { if (heap_object_decl == nullptr) { diff --git a/deps/v8/tools/jj/README.md b/deps/v8/tools/jj/README.md new file mode 100644 index 000000000000..a7821fa6b84e --- /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` (`clang_format.py` for C++/JS/TS and `gn format` for GN/GNI). diff --git a/deps/v8/tools/jj/config.toml b/deps/v8/tools/jj/config.toml new file mode 100644 index 000000000000..f95e95b92ddb --- /dev/null +++ b/deps/v8/tools/jj/config.toml @@ -0,0 +1,66 @@ +[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"] + +# Disable google3format for internal Piper users +[fix.tools.google3format] +enabled = false +command = ["/dev/null"] +patterns = ["null"] + +# Mirror depot_tools/git_cl.py formatters exactly as Chromium does: +[fix.tools.clang-format] +command = ["clang_format.py", "--assume-filename=$path"] +line-range-arg = "--lines=$first:$last" +patterns = [ + "glob:'**/*.cc'", + "glob:'**/*.h'", + "glob:'**/*.js'", + "glob:'**/*.mjs'", + "glob:'**/*.ts'", +] + +[fix.tools.gn-format] +command = ["gn", "format", "--stdin"] +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..eccfb195f29e 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]: @@ -226,10 +269,10 @@ 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. @@ -278,33 +321,7 @@ 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) - - -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)) + return extract.position(cursor, v8_root) or "<unknown>" def _reject_recovery_ast(tu, @@ -363,36 +380,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 +429,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 +456,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 +464,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 +523,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..2a214c96f7a5 --- /dev/null +++ b/deps/v8/tools/metagen/layout_extract.py @@ -0,0 +1,796 @@ +# Copyright 2026 the V8 project 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::IndirectPointerTag", +}) + + +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_bit_field_struct_name(decl: cindex.Cursor) -> str: + """The C++ name of a BitFieldGroup, including enclosing classes.""" + parts = [] + while decl is not None and decl.kind in (cindex.CursorKind.CLASS_DECL, + cindex.CursorKind.STRUCT_DECL, + cindex.CursorKind.CLASS_TEMPLATE): + 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. kFooIndirectPointerTag, 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) -> StorageType: + """The bit layout of a BitFieldGroup member: every type alias of + the group is a base::BitField, read in declaration order (which is + bit order) for its name, field type, shift and 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") + 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.""" + 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 decl.spelling + 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 IndirectPointerHandle 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("IndirectPointerHandle") + if handle_alias is None: + raise LayoutError( + f"{_where(field)}: missing IndirectPointerHandle 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_bit_field_struct_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 IndirectPointerHandle 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 == "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..a6f52e3b72eb --- /dev/null +++ b/deps/v8/tools/metagen/layout_ir.py @@ -0,0 +1,712 @@ +# Copyright 2026 the V8 project 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 IndirectPointerTag 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", + # 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}") + + +@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_identifier(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": the group's fields, in declaration order, which is bit + # order. + 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 IndirectPointerHandle 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 == "bitfield": + _check( + isinstance(self.name, str), "bitfield storage name must be a string") + for part in (self.name or "").split("::"): + _check_identifier(part, "bitfield storage name") + _check(self.width in (1, 2, 4, 8), "bitfield storage width invalid") + _check(bool(self.bits), "bitfield storage without fields") + # A base::BitField chain starts at bit 0 and has no holes; a gap + # means an alias is missing from the group. + next_bit = 0 + for bit in self.bits: + _check( + bit.offset == next_bit, + f"bitfield {self.name}: {bit.cpp_name} starts at {bit.offset}, " + f"expected {next_bit}") + next_bit += bit.num_bits + _check(next_bit <= self.width * 8, + f"bitfield {self.name}: {next_bit} 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..644511812022 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) @@ -438,7 +411,7 @@ 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 @@ -446,7 +419,7 @@ def normalize(text: str) -> list[str]: # 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)") + r"|endif|if !V8_USE_METAGEN)") out: list[str] = [] in_dispatch = False for ln in text.splitlines(): @@ -491,19 +464,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..be6763244881 --- /dev/null +++ b/deps/v8/tools/metagen/tests/layout_extract_test.py @@ -0,0 +1,946 @@ +# Copyright 2026 the V8 project 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 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_NAME(N) \ + V8_TQ_MARK(TqTailName, "V8_TQ_TAIL_NAME(" #N ")") +#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 IndirectPointerHandle = 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 IndirectPointerTag { 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 IndirectPointerTagRange = TagRange<IndirectPointerTag>; +template <typename T, IndirectPointerTagRange 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 IndirectPointerTagRange 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: + IndirectPointerHandle 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> { + V8_TQ_TAIL_NAME(objects); + V8_TQ_TAIL_LENGTH(length); + public: + 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 { + V8_TQ_TAIL_NAME(bytes); + V8_TQ_TAIL_LENGTH(length); + public: + V8_TQ_CONST TaggedMember<Smi> length_; + 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"), + ("V8_TQ_TAIL_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 { + U value_; + }; + 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 = base::BitField<bool, 0, 1, uint32_t>; + using KindBits = IsFooBit::Next<Kind, 2>; + using CountBits = KindBits::Next<int32_t, 5>; + }; + 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), + ]) + + 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 = base::BitField<bool, 0, 1, uint8_t>; + }; + 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_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_; + }; + """) + + 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 FailureModeTest(unittest.TestCase): + + def test_missing_indirect_pointer_handle_alias_is_fatal(self): + h = parse( + """ + class Holder : public HeapObject { + public: + std::atomic<RenamedIndirectPointerHandle> handle_; + }; + """, + prelude=_PRELUDE.replace("IndirectPointerHandle", + "RenamedIndirectPointerHandle")) + field = next(_find_class(h, "Holder").type.get_fields()) + with self.assertRaisesRegex(LayoutError, + "missing IndirectPointerHandle 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..0ee7ff3f8502 --- /dev/null +++ b/deps/v8/tools/metagen/tests/layout_ir_test.py @@ -0,0 +1,502 @@ +# Copyright 2026 the V8 project 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 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_needs_fields(self): + with self.assertRaisesRegex(LayoutError, "without fields"): + bitfield() + + def test_bitfield_chain_must_be_gapless(self): + with self.assertRaisesRegex(LayoutError, "starts at 2, expected 1"): + bitfield( + BitFieldEntry("IsFooBit", "bool", 0, 1), + BitFieldEntry("KindBits", "Kind", 2, 3)) + + 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)) + + 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..0e8a9eeb6b17 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/README.md +++ b/deps/v8/tools/regexp/correctness_fuzzer/README.md @@ -92,6 +92,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 | @@ -108,6 +117,7 @@ tools/regexp/correctness_fuzzer/correctness_fuzzer.py --ref A --test B \ | `--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 +126,74 @@ 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.py` +derives the tag from pattern metacharacters to group similar patterns, +independent of V8 output. + +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 +202,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 +216,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..848ab53ad39f 100755 --- a/deps/v8/tools/regexp/correctness_fuzzer/correctness_fuzzer.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/correctness_fuzzer.py @@ -32,6 +32,12 @@ 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. @@ -49,12 +55,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 +86,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 +98,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, *flags, casefile], capture_output=True, text=True, timeout=60) @@ -310,11 +312,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 +451,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 +482,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/menus.py b/deps/v8/tools/regexp/correctness_fuzzer/grammar/menus.py index 37ce043757ca..0f97b10dfc32 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 diff --git a/deps/v8/tools/regexp/correctness_fuzzer/grammar/rules.py b/deps/v8/tools/regexp/correctness_fuzzer/grammar/rules.py index 0977afa7c15c..cf4882c0b257 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/grammar/rules.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/grammar/rules.py @@ -19,7 +19,7 @@ from .menus import (ASCII_LETTER, CLASS_SET_SAFE, CONTROL_ESCAPE, ESCAPE_LITERALS, LATIN1_ONLY, LITERAL, LITERAL_WIDE, - RANGE_ALPHABET, UNICODE_PROPERTIES, + RANGE_ALPHABET, SURROGATES, UNICODE_PROPERTIES, UNICODE_PROPERTIES_OF_STRINGS) from .registry import (NOT_SETS, NOT_UNICODE, SETS, UNICODE, concat_terms, expand, repeat, rule) @@ -223,7 +223,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 +384,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 +413,13 @@ 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("^$\\.*+?()[]{}|/-@~"))) # CharacterClassEscape :: `d` `D` `s` `S` `w` `W` @@ -513,7 +513,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 +581,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 +607,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..e25923312684 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,29 @@ import correctness_fuzzer import grammar +import harness +import run from grammar import registry -HARNESS_PATH = os.path.join( - os.path.dirname(os.path.realpath(__file__)), "harness.js") - # 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], - capture_output=True, - text=True, - timeout=300) + 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=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): @@ -84,6 +83,8 @@ 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 +98,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 +115,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) @@ -130,7 +143,10 @@ 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 +157,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 +240,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 +258,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 +278,54 @@ 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 ClassificationTest(unittest.TestCase): """How a pair of harness results is turned into a finding. @@ -310,6 +376,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 +465,95 @@ 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_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") + + def test_tag_keeps_shape_and_drops_literals(self): + self.assertEqual( + harness.source_tag("(ab|cd)+\\d", "gi"), + harness.source_tag("(xy|zw)+\\d", "ig")) + self.assertEqual(harness.source_tag("\\.", ""), "/") + self.assertEqual(harness.source_tag("\\w\\1", ""), "/\\w\\1") + self.assertLessEqual(len(harness.source_tag("(" * 500, "")), 41) + + +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 +563,65 @@ def setUp(self): if D8 is None: self.skipTest("needs --d8") + 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 +680,53 @@ 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_generated_testcase_runs_standalone(self): + with tempfile.TemporaryDirectory() as out: + run.main( + ["--output_dir", out, "--no_of_files", "1", "--cases-per-file", "50"]) + path = os.path.join(out, "fuzz-0.js") + p = subprocess.run([D8, path], + capture_output=True, + text=True, + timeout=300) + self.assertEqual(0, p.returncode, p.stderr) + lines = p.stdout.splitlines() + self.assertEqual("DONE", lines[-1]) + self.assertEqual(50, len(correctness_fuzzer.Runner._results(p.stdout))) + 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..9f6b40db602b 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, tag] 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 = [...]`; 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,13 @@ // 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 tag as a source 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]; + const [pat, flags, sub, lastIndex, tag] = cases[i]; + if (tag !== undefined) { + print("v8-foozzie source: regexp-fuzzer:" + tag); + } let out; try { const cold = execOnce(pat, flags, sub, lastIndex); 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..0624b3791a59 --- /dev/null +++ b/deps/v8/tools/regexp/correctness_fuzzer/harness.py @@ -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. +"""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>, "<tag>"], + ... + ]; + <harness.js verbatim> + +Each case occupies one line and ends with a comma for line-based minimization. +json.dumps escapes non-ASCII characters and lone surrogates. +""" + +import json +from pathlib import Path + +HARNESS_PATH = Path(__file__).resolve().parent / "harness.js" + +_CASES_OPEN = "const cases = [" +_CASES_CLOSE = "];" + +# Characters kept when reducing a pattern to its shape for the dedup tag. +_STRUCTURAL = set("()[]{}|*+?^$.-&!=<>:,") +_TAG_MAX = 40 + + +def source_tag(pattern, flags): + """Return a bounded source tag that groups patterns by structure.""" + out = [] + i = 0 + while i < len(pattern) and len(out) < _TAG_MAX: + c = pattern[i] + if c == "\\": + nxt = pattern[i + 1] if i + 1 < len(pattern) else "" + # Keep ASCII alphanumeric escapes; other escaped characters are literals. + if nxt.isascii() and nxt.isalnum(): + out.append(c + nxt) + i += 2 + continue + if c in _STRUCTURAL: + out.append(c) + i += 1 + return "".join(sorted(flags)) + "/" + "".join(out) + + +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, + source_tag(pattern, flags)]) + ",") + lines.append(_CASES_CLOSE) + lines.append(HARNESS_PATH.read_text(encoding="utf-8")) + 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/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/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/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 From c3bc8d967c79f4096dfbd1a00667f2eafffb8ee4 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu <cwu631@bloomberg.net> Date: Fri, 16 Oct 2026 14:20:43 -0400 Subject: [PATCH 02/10] deps: update Rust crates for V8 15.7.112.5 --- deps/crates/Cargo.lock | 42 +- deps/crates/Cargo.toml | 2 +- .../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_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 .../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 +- .../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 +- .../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 +- 155 files changed, 1260 insertions(+), 69476 deletions(-) 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/{syn-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%) diff --git a/deps/crates/Cargo.lock b/deps/crates/Cargo.lock index 2dc90a16afb1..e923a0a20e97 100644 --- a/deps/crates/Cargo.lock +++ b/deps/crates/Cargo.lock @@ -32,7 +32,7 @@ dependencies = [ "diplomat_core", "proc-macro2", "quote", - "syn 3.0.5", + "syn", ] [[package]] @@ -50,7 +50,7 @@ dependencies = [ "serde", "smallvec", "strck", - "syn 3.0.5", + "syn", ] [[package]] @@ -60,7 +60,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2", "quote", - "syn 3.0.5", + "syn", ] [[package]] @@ -161,12 +161,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "node_crates" -version = "15.6.75" +version = "15.7.112" dependencies = [ "icu_locale", "icu_locale_core", "icu_provider", - "syn 3.0.5", + "syn", "temporal_capi", "temporal_rs", ] @@ -238,12 +238,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 +261,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 +271,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]] @@ -344,7 +334,7 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -369,12 +359,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 +378,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", ] @@ -424,7 +414,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..469877d4dcc1 100644 --- a/deps/crates/Cargo.toml +++ b/deps/crates/Cargo.toml @@ -3,7 +3,7 @@ [package] edition = "2021" name = "node_crates" -version = "15.6.75" +version = "15.7.112" rust-version = "1.88" [lib] 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_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/syn-v2/.cargo-checksum.json b/deps/crates/vendor/synstructure-v0_14/.cargo-checksum.json similarity index 100% rename from deps/crates/vendor/syn-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/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/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/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; } From 7ad26a4b486d50bbebb61fbeaad094e046b5f1ae Mon Sep 17 00:00:00 2001 From: Chengzhong Wu <cwu631@bloomberg.net> Date: Fri, 16 Oct 2026 14:20:44 -0400 Subject: [PATCH 03/10] 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 e70270a793b4..e817872ca516 100644 --- a/common.gypi +++ b/common.gypi @@ -44,7 +44,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.9', + 'v8_embedder_string': '-node.0', ##### V8 defaults for Node.js ##### From 2882e1389b7e9f1ce4be2e20ac0c865e45c3c538 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu <cwu631@bloomberg.net> Date: Fri, 16 Oct 2026 14:20:44 -0400 Subject: [PATCH 04/10] 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.7. 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..7072fcec6c7e 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.7", "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 ab634e0fc352ae4afd908b6e0c4720b8bb8a7afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= <targos@protonmail.com> Date: Sat, 16 Sep 2023 10:13:14 +0200 Subject: [PATCH 05/10] deps: patch V8 to avoid duplicated zlib symbol Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66601 Reviewed-By: Richard Lau <richard.lau@ibm.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> --- common.gypi | 2 +- deps/v8/third_party/zlib/chromeconf.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/common.gypi b/common.gypi index e817872ca516..565cd0a75352 100644 --- a/common.gypi +++ b/common.gypi @@ -44,7 +44,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/third_party/zlib/chromeconf.h b/deps/v8/third_party/zlib/chromeconf.h index 77f0e29e0d6b..c713e2119b44 100644 --- a/deps/v8/third_party/zlib/chromeconf.h +++ b/deps/v8/third_party/zlib/chromeconf.h @@ -207,5 +207,8 @@ /* Symbols added by cpu_features.c */ #define cpu_check_features Cr_z_cpu_check_features #define x86_cpu_enable_sse2 Cr_z_x86_cpu_enable_sse2 +#define x86_cpu_enable_avx512 Cr_z_x86_cpu_enable_avx512 +#define riscv_cpu_enable_rvv Cr_z_riscv_cpu_enable_rvv +#define riscv_cpu_enable_vclmul Cr_z_riscv_cpu_enable_vclmul #endif /* THIRD_PARTY_ZLIB_CHROMECONF_H_ */ From de6b77c6f0e925e3a98daff9fcc3c1aa3bec3063 Mon Sep 17 00:00:00 2001 From: Joyee Cheung <joyee@igalia.com> Date: Wed, 7 Oct 2026 23:39:19 +0200 Subject: [PATCH 06/10] deps: V8: cherry-pick 415b7d302d2e Original commit message: [platform] support madvise(3C) across ALL illumos revisions In illumos, madvise(3C) now takes `void *` for its first argument post-illumos#14418, but uses `caddr_t` pre-illumos#14418. This fix will detect if the illumos mman.h file in use is pre-or-post-illumos#14418 so builds can work either way. Co-Authored-By: Dan McDonald <danmcd@mnx.io> Refs: https://github.com/nodejs/node/pull/65161 Refs: https://github.com/v8/v8/commit/415b7d302d2e92344ce9a0c6da4855a2b0739037 Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66601 Reviewed-By: Richard Lau <richard.lau@ibm.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> --- common.gypi | 2 +- deps/v8/src/base/platform/platform-posix.cc | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/common.gypi b/common.gypi index 565cd0a75352..fcdd1d8a0478 100644 --- a/common.gypi +++ b/common.gypi @@ -44,7 +44,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/src/base/platform/platform-posix.cc b/deps/v8/src/base/platform/platform-posix.cc index 7add12aa4798..df122799fdca 100644 --- a/deps/v8/src/base/platform/platform-posix.cc +++ b/deps/v8/src/base/platform/platform-posix.cc @@ -82,7 +82,19 @@ #define MAP_ANONYMOUS MAP_ANON #endif -#if defined(V8_OS_SOLARIS) +/* + * NOTE: illumos starting with illumos#14418 (pushed April 20th, 2022) + * prototypes madvise(3C) properly with a `void *` first argument. + * The only way to detect this outside of configure-time checking is to + * check for the existence of MEMCNTL_SHARED, which gets defined for the first + * time in illumos#14418 under the same circumstances save _STRICT_POSIX, which + * thankfully neither Solaris nor illumos builds of Node or V8 do. + * + * If some future illumos push changes the MEMCNTL_SHARED assumptions made + * above, the illumos check below will have to be revisited. This check + * will work on both pre-and-post illumos#14418 illumos environments. + */ +#if defined(V8_OS_SOLARIS) && !(defined(__illumos__) && defined(MEMCNTL_SHARED)) #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE > 2) || defined(__EXTENSIONS__) extern "C" int madvise(caddr_t, size_t, int); #else From 859c58e28e7ff466b0e16e0c64a1007a4be276ce Mon Sep 17 00:00:00 2001 From: Joyee Cheung <joyee@igalia.com> Date: Wed, 7 Oct 2026 23:45:56 +0200 Subject: [PATCH 07/10] deps: V8: cherry-pick 5dfeb2e42380 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 Refs: https://github.com/v8/v8/commit/5dfeb2e42380ceb87d062017dd253312cdaef0a6 Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66601 Reviewed-By: Richard Lau <richard.lau@ibm.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> --- 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 fcdd1d8a0478..07137b628a13 100644 --- a/common.gypi +++ b/common.gypi @@ -44,7 +44,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.2', + 'v8_embedder_string': '-node.3', ##### 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 96cc1c9b2bd6..1680e1dc6631 100644 --- a/deps/v8/src/codegen/code-stub-assembler.cc +++ b/deps/v8/src/codegen/code-stub-assembler.cc @@ -2218,8 +2218,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), + IntPtrConstant(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..e1e1dee21789 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 2b467bfd2e71..d8ada24eb109 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 8084eb2c48a27d8d6c50546563e237193eb0b82e Mon Sep 17 00:00:00 2001 From: Joyee Cheung <joyee@igalia.com> Date: Wed, 7 Oct 2026 23:48:40 +0200 Subject: [PATCH 08/10] deps: V8: cherry-pick e10d795bfe95 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 targetting MSVC and its ABI. Co-Authored-By: Stefan Stojanovic <stefan.stojanovic@janeasystems.com> Refs: https://github.com/nodejs/node/pull/55784 Refs: https://github.com/v8/v8/commit/e10d795bfe95106dae986f0b1eafa4ef3cc6eddb Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66601 Reviewed-By: Richard Lau <richard.lau@ibm.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> --- 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 07137b628a13..6855ae18c524 100644 --- a/common.gypi +++ b/common.gypi @@ -44,7 +44,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.3', + 'v8_embedder_string': '-node.4', ##### 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 e8feb095f9b5f9c8245eb50ff80ddd21a8a994b2 Mon Sep 17 00:00:00 2001 From: Joyee Cheung <joyeec9h3@gmail.com> Date: Mon, 5 Oct 2026 20:43:00 +0200 Subject: [PATCH 09/10] 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 8abb937a16144b0e71569b8ec39f9776b1497ed2 Mon Sep 17 00:00:00 2001 From: Joyee Cheung <joyeec9h3@gmail.com> Date: Thu, 8 Oct 2026 00:25:11 +0200 Subject: [PATCH 10/10] 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 a6e2c9b0d0ef..43f73c70c061 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 }