deps: update V8 to 12.3.219.16

PR-URL: https://github.com/nodejs/node/pull/52293
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
This commit is contained in:
Michaël Zasso 2024-04-18 07:06:43 +02:00 committed by Node.js GitHub Bot
parent 07f481cfcf
commit 1d29d81c69
1088 changed files with 35820 additions and 19770 deletions

12
deps/v8/.gitignore vendored
View File

@ -63,13 +63,10 @@
/test/wasm-spec-tests/tests.tar.gz
/third_party/*
!/third_party/antlr4
!/third_party/cpu_features
/third_party/cpu_features/src
!/third_party/inspector_protocol
!/third_party/jsoncpp
/third_party/jsoncpp/source
!/third_party/colorama
/third_party/colorama/src
!/third_party/cpu_features
/third_party/cpu_features/src
!/third_party/glibc
!/third_party/googletest
/third_party/googletest/src/*
@ -80,6 +77,11 @@
!/third_party/googletest/src/googletest/include/gtest
/third_party/googletest/src/googletest/include/gtest/*
!/third_party/googletest/src/googletest/include/gtest/gtest_prod.h
!/third_party/inspector_protocol
!/third_party/jsoncpp
/third_party/jsoncpp/source
!/third_party/re2
/third_party/re2/src
!/third_party/test262-harness
!/third_party/v8
!/third_party/wasm-api

1
deps/v8/AUTHORS vendored
View File

@ -311,3 +311,4 @@ Zhongping Wang <kewpie.w.zp@gmail.com>
Yang Xiang <xiangyangemail@gmail.com>
Kotaro Ohsugi <dec4m4rk@gmail.com>
Jing Peiyang <jingpeiyang@eswincomputing.com>
magic-akari <akari.ccino@gmail.com>

17
deps/v8/BUILD.bazel vendored
View File

@ -1689,6 +1689,8 @@ filegroup(
"src/heap/memory-balancer.h",
"src/heap/memory-chunk.cc",
"src/heap/memory-chunk.h",
"src/heap/memory-chunk-header.cc",
"src/heap/memory-chunk-header.h",
"src/heap/memory-chunk-inl.h",
"src/heap/memory-chunk-layout.cc",
"src/heap/memory-chunk-layout.h",
@ -2792,6 +2794,7 @@ filegroup(
"src/wasm/code-space-access.cc",
"src/wasm/code-space-access.h",
"src/wasm/compilation-environment.h",
"src/wasm/compilation-environment-inl.h",
"src/wasm/constant-expression.cc",
"src/wasm/constant-expression.h",
"src/wasm/constant-expression-interface.cc",
@ -2883,6 +2886,7 @@ filegroup(
"src/wasm/wasm-value.h",
"src/wasm/well-known-imports.cc",
"src/wasm/well-known-imports.h",
"src/wasm/wrappers.cc",
],
"//conditions:default": [],
}),
@ -3011,6 +3015,8 @@ filegroup(
"src/compiler/compiler-source-position-table.h",
"src/compiler/constant-folding-reducer.cc",
"src/compiler/constant-folding-reducer.h",
"src/compiler/const-tracking-let-helpers.cc",
"src/compiler/const-tracking-let-helpers.h",
"src/compiler/control-equivalence.cc",
"src/compiler/control-equivalence.h",
"src/compiler/control-flow-optimizer.cc",
@ -3185,7 +3191,7 @@ filegroup(
"src/compiler/turboshaft/builtin-call-descriptors.h",
"src/compiler/turboshaft/csa-optimize-phase.cc",
"src/compiler/turboshaft/csa-optimize-phase.h",
"src/compiler/turboshaft/dataview-reducer.h",
"src/compiler/turboshaft/dataview-lowering-reducer.h",
"src/compiler/turboshaft/code-elimination-and-simplification-phase.cc",
"src/compiler/turboshaft/code-elimination-and-simplification-phase.h",
"src/compiler/turboshaft/dead-code-elimination-reducer.h",
@ -3199,7 +3205,7 @@ filegroup(
"src/compiler/turboshaft/define-assembler-macros.inc",
"src/compiler/turboshaft/deopt-data.h",
"src/compiler/turboshaft/explicit-truncation-reducer.h",
"src/compiler/turboshaft/fast-api-call-reducer.h",
"src/compiler/turboshaft/fast-api-call-lowering-reducer.h",
"src/compiler/turboshaft/fast-hash.h",
"src/compiler/turboshaft/graph.cc",
"src/compiler/turboshaft/graph.h",
@ -3249,7 +3255,6 @@ filegroup(
"src/compiler/turboshaft/recreate-schedule.h",
"src/compiler/turboshaft/recreate-schedule-phase.cc",
"src/compiler/turboshaft/recreate-schedule-phase.h",
"src/compiler/turboshaft/reduce-args-helper.h",
"src/compiler/turboshaft/reducer-traits.h",
"src/compiler/turboshaft/representations.cc",
"src/compiler/turboshaft/representations.h",
@ -3265,7 +3270,7 @@ filegroup(
"src/compiler/turboshaft/simplify-tf-loops.h",
"src/compiler/turboshaft/snapshot-table.h",
"src/compiler/turboshaft/snapshot-table-opindex.h",
"src/compiler/turboshaft/stack-check-reducer.h",
"src/compiler/turboshaft/stack-check-lowering-reducer.h",
"src/compiler/turboshaft/store-store-elimination-phase.cc",
"src/compiler/turboshaft/store-store-elimination-phase.h",
"src/compiler/turboshaft/store-store-elimination-reducer.h",
@ -3374,8 +3379,8 @@ filegroup(
"src/compiler/turboshaft/wasm-assembler-helpers.h",
"src/compiler/turboshaft/wasm-gc-optimize-phase.cc",
"src/compiler/turboshaft/wasm-gc-optimize-phase.h",
"src/compiler/turboshaft/wasm-gc-type-reducer.cc",
"src/compiler/turboshaft/wasm-gc-type-reducer.h",
"src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.cc",
"src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.h",
"src/compiler/turboshaft/wasm-load-elimination-reducer.h",
"src/compiler/turboshaft/wasm-lowering-phase.cc",
"src/compiler/turboshaft/wasm-lowering-phase.h",

68
deps/v8/BUILD.gn vendored
View File

@ -1149,6 +1149,9 @@ config("features") {
if (v8_fuzzilli) {
defines += [ "V8_FUZZILLI" ]
}
if (v8_enable_fuzztest) {
defines += [ "V8_ENABLE_FUZZTEST" ]
}
if (v8_enable_short_builtin_calls) {
defines += [ "V8_SHORT_BUILTIN_CALLS" ]
}
@ -1482,7 +1485,6 @@ config("toolchain") {
if (is_clang) {
cflags += [
"-Wmissing-field-initializers",
"-Wunreachable-code",
# TODO(v8:12245): Fix shadowing instances and remove.
@ -1496,11 +1498,6 @@ config("toolchain") {
# warning.
cflags += [ "-Wctad-maybe-unsupported" ]
}
if (v8_current_cpu == "x64" || v8_current_cpu == "arm64" ||
v8_current_cpu == "mips64el" || v8_current_cpu == "riscv64") {
cflags += [ "-Wshorten-64-to-32" ]
}
}
if (is_clang || !is_win) {
@ -1700,20 +1697,6 @@ config("toolchain") {
# Fix build with older versions of GCC
# Ported from v8 bazel: https://crrev.com/c/3368869
"-Wno-stringop-overflow",
# Fix a number of bogus errors with gcc12
# TODO(miladfarca): re-evaluate for future gcc upgrades
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111499
"-Wno-stringop-overread",
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104336
"-Wno-restrict",
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105523
"-Wno-array-bounds",
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108517
"-Wno-nonnull",
]
}
@ -1723,6 +1706,17 @@ config("toolchain") {
}
}
config("strict_warnings") {
cflags = []
if (is_clang) {
if (v8_current_cpu == "x64" || v8_current_cpu == "arm64" ||
v8_current_cpu == "mips64el" || v8_current_cpu == "riscv64") {
cflags += [ "-Wshorten-64-to-32" ]
}
cflags += [ "-Wmissing-field-initializers" ]
}
}
# For code that is hot during mksnapshot. In fast-mksnapshot builds, we
# optimize some files even in debug builds to speed up mksnapshot times.
config("always_turbofanimize") {
@ -3304,6 +3298,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/common-operator.h",
"src/compiler/compilation-dependencies.h",
"src/compiler/compiler-source-position-table.h",
"src/compiler/const-tracking-let-helpers.h",
"src/compiler/constant-folding-reducer.h",
"src/compiler/control-equivalence.h",
"src/compiler/control-flow-optimizer.h",
@ -3401,7 +3396,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/code-elimination-and-simplification-phase.h",
"src/compiler/turboshaft/copying-phase.h",
"src/compiler/turboshaft/csa-optimize-phase.h",
"src/compiler/turboshaft/dataview-reducer.h",
"src/compiler/turboshaft/dataview-lowering-reducer.h",
"src/compiler/turboshaft/dead-code-elimination-reducer.h",
"src/compiler/turboshaft/debug-feature-lowering-phase.h",
"src/compiler/turboshaft/debug-feature-lowering-reducer.h",
@ -3411,7 +3406,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/deopt-data.h",
"src/compiler/turboshaft/duplication-optimization-reducer.h",
"src/compiler/turboshaft/explicit-truncation-reducer.h",
"src/compiler/turboshaft/fast-api-call-reducer.h",
"src/compiler/turboshaft/fast-api-call-lowering-reducer.h",
"src/compiler/turboshaft/fast-hash.h",
"src/compiler/turboshaft/graph-builder.h",
"src/compiler/turboshaft/graph-visualizer.h",
@ -3440,7 +3435,6 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/pretenuring-propagation-reducer.h",
"src/compiler/turboshaft/recreate-schedule-phase.h",
"src/compiler/turboshaft/recreate-schedule.h",
"src/compiler/turboshaft/reduce-args-helper.h",
"src/compiler/turboshaft/reducer-traits.h",
"src/compiler/turboshaft/representations.h",
"src/compiler/turboshaft/required-optimization-reducer.h",
@ -3452,7 +3446,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/simplify-tf-loops.h",
"src/compiler/turboshaft/snapshot-table-opindex.h",
"src/compiler/turboshaft/snapshot-table.h",
"src/compiler/turboshaft/stack-check-reducer.h",
"src/compiler/turboshaft/stack-check-lowering-reducer.h",
"src/compiler/turboshaft/store-store-elimination-phase.h",
"src/compiler/turboshaft/store-store-elimination-reducer.h",
"src/compiler/turboshaft/structural-optimization-reducer.h",
@ -3640,6 +3634,7 @@ v8_header_set("v8_internal_headers") {
"src/heap/marking.h",
"src/heap/memory-allocator.h",
"src/heap/memory-balancer.h",
"src/heap/memory-chunk-header.h",
"src/heap/memory-chunk-inl.h",
"src/heap/memory-chunk-layout.h",
"src/heap/memory-chunk.h",
@ -4136,6 +4131,12 @@ v8_header_set("v8_internal_headers") {
if (v8_use_perfetto) {
sources -= [ "//base/trace_event/common/trace_event_common.h" ]
sources += [
"src/tracing/code-data-source.h",
"src/tracing/code-trace-context.h",
"src/tracing/perfetto-logger.h",
"src/tracing/perfetto-utils.h",
]
}
if (v8_enable_sparkplug) {
@ -4195,7 +4196,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/int64-lowering-reducer.h",
"src/compiler/turboshaft/wasm-assembler-helpers.h",
"src/compiler/turboshaft/wasm-gc-optimize-phase.h",
"src/compiler/turboshaft/wasm-gc-type-reducer.h",
"src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.h",
"src/compiler/turboshaft/wasm-js-lowering-reducer.h",
"src/compiler/turboshaft/wasm-load-elimination-reducer.h",
"src/compiler/turboshaft/wasm-lowering-phase.h",
@ -4230,6 +4231,7 @@ v8_header_set("v8_internal_headers") {
"src/wasm/baseline/parallel-move.h",
"src/wasm/canonical-types.h",
"src/wasm/code-space-access.h",
"src/wasm/compilation-environment-inl.h",
"src/wasm/compilation-environment.h",
"src/wasm/constant-expression-interface.h",
"src/wasm/constant-expression.h",
@ -4759,6 +4761,7 @@ v8_compiler_sources = [
"src/compiler/common-operator.cc",
"src/compiler/compilation-dependencies.cc",
"src/compiler/compiler-source-position-table.cc",
"src/compiler/const-tracking-let-helpers.cc",
"src/compiler/constant-folding-reducer.cc",
"src/compiler/control-equivalence.cc",
"src/compiler/control-flow-optimizer.cc",
@ -4935,7 +4938,7 @@ if (v8_enable_webassembly) {
"src/compiler/int64-lowering.cc",
"src/compiler/turboshaft/int64-lowering-phase.cc",
"src/compiler/turboshaft/wasm-gc-optimize-phase.cc",
"src/compiler/turboshaft/wasm-gc-type-reducer.cc",
"src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.cc",
"src/compiler/turboshaft/wasm-lowering-phase.cc",
"src/compiler/turboshaft/wasm-optimize-phase.cc",
"src/compiler/turboshaft/wasm-turboshaft-compiler.cc",
@ -5330,6 +5333,7 @@ v8_source_set("v8_base_without_compiler") {
"src/heap/marking.cc",
"src/heap/memory-allocator.cc",
"src/heap/memory-balancer.cc",
"src/heap/memory-chunk-header.cc",
"src/heap/memory-chunk-layout.cc",
"src/heap/memory-chunk.cc",
"src/heap/memory-measurement.cc",
@ -5651,6 +5655,14 @@ v8_source_set("v8_base_without_compiler") {
}
}
if (v8_use_perfetto) {
sources += [
"src/tracing/code-data-source.cc",
"src/tracing/perfetto-logger.cc",
"src/tracing/perfetto-utils.cc",
]
}
if (v8_enable_webassembly) {
sources += [
### gcmole(all) ###
@ -5706,6 +5718,7 @@ v8_source_set("v8_base_without_compiler") {
"src/wasm/wasm-serialization.cc",
"src/wasm/wasm-subtyping.cc",
"src/wasm/well-known-imports.cc",
"src/wasm/wrappers.cc",
]
}
@ -8131,7 +8144,6 @@ if (!build_with_chromium && v8_use_perfetto) {
"//third_party/perfetto/src/tracing/core",
# TODO(skyostil): Support non-POSIX platforms.
"//third_party/perfetto/protos/perfetto/config:cpp",
"//third_party/perfetto/protos/perfetto/trace/track_event:zero",
"//third_party/perfetto/src/tracing:in_process_backend",
"//third_party/perfetto/src/tracing:platform_impl",
@ -8139,6 +8151,8 @@ 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",
]

59
deps/v8/DEPS vendored
View File

@ -27,6 +27,7 @@ vars = {
'checkout_fuchsia_boot_images': "terminal.x64",
'checkout_fuchsia_product_bundles': '"{checkout_fuchsia_boot_images}" != ""',
'checkout_centipede_deps': False,
'checkout_instrumented_libraries': False,
'checkout_ittapi': False,
@ -41,8 +42,9 @@ vars = {
# Fetch and build V8 builtins with PGO profiles
'checkout_v8_builtins_pgo_profiles': False,
'chromium_url': 'https://chromium.googlesource.com',
'android_url': 'https://android.googlesource.com',
'boringssl_url': 'https://boringssl.googlesource.com',
'chromium_url': 'https://chromium.googlesource.com',
'download_gcmole': False,
'download_jsfunfuzz': False,
'download_prebuilt_bazel': False,
@ -55,7 +57,7 @@ vars = {
'checkout_fuchsia_no_hooks': False,
# reclient CIPD package version
'reclient_version': 're_client_version:0.126.0.4aaef37-gomaip',
'reclient_version': 're_client_version:0.131.1.784ddbb-gomaip',
# Fetch configuration files required for the 'use_remoteexec' gn arg
'download_remoteexec_cfg': False,
@ -71,19 +73,19 @@ vars = {
'build_with_chromium': False,
# GN CIPD package version.
'gn_version': 'git_revision:b5adfe5f574d7110b80feb9aae6fae97c366840b',
'gn_version': 'git_revision:0a2b8eac80f164f10b2cbc126890db0d295790cd',
# ninja CIPD package version
# https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja
'ninja_version': 'version:2@1.11.1.chromium.6',
# luci-go CIPD package version.
'luci_go': 'git_revision:0d11be367258bfe14a13ff1afcf43a0bc6aedb45',
'luci_go': 'git_revision:3df60a11d33a59614c0e8d2bccc58d8c30984901',
# 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:17.20240120.1.1',
'fuchsia_version': 'version:18.20240215.1.1',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling android_sdk_build-tools_version
@ -123,9 +125,9 @@ deps = {
'base/trace_event/common':
Var('chromium_url') + '/chromium/src/base/trace_event/common.git' + '@' + '29ac73db520575590c3aceb0a6f1f58dda8934f6',
'build':
Var('chromium_url') + '/chromium/src/build.git' + '@' + '28cd6ea727d171ec990e6174308451d4178d7f8e',
Var('chromium_url') + '/chromium/src/build.git' + '@' + 'e5cf1b3ceb3fec6aa5c57b34dede99d36cede32d',
'buildtools':
Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '17ce6d2f0416038de7989bc71d055c07d333ccb5',
Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '342659133d7d0b33f4e24b640a9ad78c0c423633',
'buildtools/linux64': {
'packages': [
{
@ -171,7 +173,7 @@ deps = {
'test/mozilla/data':
Var('chromium_url') + '/v8/deps/third_party/mozilla-tests.git' + '@' + 'f6c578a10ea707b1a8ab0b88943fe5115ce2b9be',
'test/test262/data':
Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + 'a1ba783ca340e4bf3d80b5f5e11fa54f2ee5f1ef',
Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + 'e4f91b6381d7694265031caad0c71d733ac132f3',
'third_party/android_platform': {
'url': Var('chromium_url') + '/chromium/src/third_party/android_platform.git' + '@' + 'eeb2d566f963bb66212fdc0d9bbe1dde550b4969',
'condition': 'checkout_android',
@ -224,8 +226,16 @@ deps = {
'condition': 'checkout_android',
'dep_type': 'cipd',
},
'third_party/boringssl': {
'url': Var('chromium_url') + '/chromium/src/third_party/boringssl.git' + '@' + '9ead20bdbf0ecc33219d25fd3a426876c54d126e',
'condition': "checkout_centipede_deps",
},
'third_party/boringssl/src': {
'url': Var('boringssl_url') + '/boringssl.git' + '@' + '414f69504d30d0848b69f6453ea7fb5e88004cb4',
'condition': "checkout_centipede_deps",
},
'third_party/catapult': {
'url': Var('chromium_url') + '/catapult.git' + '@' + '3e413d7b62c09fda8713146714ba2146a0369d86',
'url': Var('chromium_url') + '/catapult.git' + '@' + '3d6c15240b480da1e498a64a72ea77a61ba335e1',
'condition': 'checkout_android',
},
'third_party/clang-format/script':
@ -239,11 +249,11 @@ deps = {
'condition': 'checkout_android',
},
'third_party/depot_tools':
Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + '46cb7d0aca592cd20ddc2f6cb16ee386b2abbf0d',
Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + '9d7c8e76f82ddc6a3bbc307217e31dec44a0f73a',
'third_party/fp16/src':
Var('chromium_url') + '/external/github.com/Maratyszcza/FP16.git' + '@' + '0a92994d729ff76a58f692d3028ca1b64b145d91',
'third_party/fuchsia-gn-sdk': {
'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-gn-sdk.git' + '@' + '6ad82eadcb1a4404964a8d86c544fda1dab7af94',
'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-gn-sdk.git' + '@' + 'fa3c41d7a15127a989111fcede8dae9265f8566b',
'condition': 'checkout_fuchsia',
},
# Exists for rolling the Fuchsia SDK. Check out of the SDK should always
@ -259,17 +269,21 @@ deps = {
'dep_type': 'cipd',
},
'third_party/google_benchmark_chrome': {
'url': Var('chromium_url') + '/chromium/src/third_party/google_benchmark.git' + '@' + '992199c3cb1076d307816e963ed4b5102df53c65',
'url': Var('chromium_url') + '/chromium/src/third_party/google_benchmark.git' + '@' + 'c300add93460c31efe53fa71e61427fa1bc09e6a',
},
'third_party/google_benchmark_chrome/src': {
'url': Var('chromium_url') + '/external/github.com/google/benchmark.git' + '@' + 'b177433f3ee2513b1075140c723d73ab8901790f',
},
'third_party/fuzztest':
Var('chromium_url') + '/chromium/src/third_party/fuzztest.git' + '@' + '9fc64e5930915bfb5a593b7e12487d78283e8221',
'third_party/fuzztest/src':
Var('chromium_url') + '/external/github.com/google/fuzztest.git' + '@' + '61d95200e7ece7d121cab26f0c39fbf392e6566e',
'third_party/googletest/src':
Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + 'af29db7ec28d6df1c7f0f745186884091e602e07',
'third_party/icu':
Var('chromium_url') + '/chromium/deps/icu.git' + '@' + 'a622de35ac311c5ad390a7af80724634e5dc61ed',
'third_party/instrumented_libraries':
Var('chromium_url') + '/chromium/src/third_party/instrumented_libraries.git' + '@' + '0011c28c8d35fc5093bb29631d05428932cd1206',
Var('chromium_url') + '/chromium/src/third_party/instrumented_libraries.git' + '@' + '0893d760101b3ddf9a2408b9d20f15ec2b80b2c1',
'third_party/ittapi': {
# Force checkout ittapi libraries to pass v8 header includes check on
# bots that has check_v8_header_includes enabled.
@ -277,19 +291,19 @@ deps = {
'condition': "checkout_ittapi or check_v8_header_includes",
},
'third_party/jinja2':
Var('chromium_url') + '/chromium/src/third_party/jinja2.git' + '@' + 'e2d024354e11cc6b041b0cff032d73f0c7e43a07',
Var('chromium_url') + '/chromium/src/third_party/jinja2.git' + '@' + 'c9c77525ea20c871a1d4658f8d312b51266d4bad',
'third_party/jsoncpp/source':
Var('chromium_url') + '/external/github.com/open-source-parsers/jsoncpp.git'+ '@' + '42e892d96e47b1f6e29844cc705e148ec4856448',
'third_party/libc++/src':
Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + '28aa23ffb4c7344914a5b4ac7169f12e5a12333f',
Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + '6d83791af99ea95f04986d64f111b84ce0b3c6f5',
'third_party/libc++abi/src':
Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + 'ea028d4d2b8a901f6302f5371c68a24480766e2b',
Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + 'a7b3d968a3a923886fea64b424bd770e69dc4ea4',
'third_party/libunwind/src':
Var('chromium_url') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + 'f400fdb561d4416b59b8f8a33d8ec8b79da60495',
Var('chromium_url') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + '8bad7bd6ec30f94bce82f7cb5b58ecbd6ce02996',
'third_party/logdog/logdog':
Var('chromium_url') + '/infra/luci/luci-py/client/libs/logdog' + '@' + '0b2078a90f7a638d576b3a7c407d136f2fb62399',
'third_party/markupsafe':
Var('chromium_url') + '/chromium/src/third_party/markupsafe.git' + '@' + '0bad08bb207bbfc1d6f3bbc82b9242b0c50e5794',
Var('chromium_url') + '/chromium/src/third_party/markupsafe.git' + '@' + 'e582d7f0edb9d67499b0f5abd6ae5550e91da7f2',
'third_party/ninja': {
'packages': [
{
@ -304,14 +318,16 @@ deps = {
Var('android_url') + '/platform/external/perfetto.git' + '@' + '6fc824d618d2f06b5d9cd8655ba0419b6b3b366e',
'third_party/protobuf':
Var('chromium_url') + '/external/github.com/google/protobuf'+ '@' + '6a59a2ad1f61d9696092f79b6d74368b4d7970a3',
'third_party/re2/src':
Var('chromium_url') + '/external/github.com/google/re2.git' + '@' + 'd00d1e93781e6ebe415771a952689dff8f260d44',
'third_party/requests': {
'url': Var('chromium_url') + '/external/github.com/kennethreitz/requests.git' + '@' + 'c7e0fc087ceeadb8b4c84a0953a422c474093d6d',
'condition': 'checkout_android',
},
'third_party/zlib':
Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + '63c0cec0344e6ba70f22bd690187088299baaa94',
Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + '4b5807f344182fd392849b820642457212618e5f',
'tools/clang':
Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + 'f0b1beffd512e855db0f46571958cfc83c8b05a9',
Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + 'a4df104173dae7d49205ed8abefc920b7c5162d2',
'tools/luci-go': {
'packages': [
{
@ -327,7 +343,7 @@ deps = {
'dep_type': 'cipd',
},
'third_party/abseil-cpp': {
'url': Var('chromium_url') + '/chromium/src/third_party/abseil-cpp.git' + '@' + '5ff8c1facf6b2e54811969ae7b90152bc1f44269',
'url': Var('chromium_url') + '/chromium/src/third_party/abseil-cpp.git' + '@' + 'f1c5751a2cb4102efbffc4110ee7551b3c54cfea',
'condition': 'not build_with_chromium',
}
}
@ -338,6 +354,7 @@ include_rules = [
'+unicode',
'+third_party/fdlibm',
'+third_party/ittapi/include',
'+third_party/fuzztest',
# Abseil features are allow-listed. Please use your best judgement when adding
# to this set -- if in doubt, email v8-dev@. For general guidance, refer to
# the Chromium guidelines (though note that some requirements in V8 may be

View File

@ -443,10 +443,7 @@ def _CheckCommitMessageBugEntry(input_api, output_api):
continue
if ':' not in bug and not bug.startswith('b/'):
try:
if int(bug) > 10000000:
results.append(
'Buganizer entry requires issue tracker prefix b/{}'.format(bug))
else:
if int(bug) < 10000000:
if int(bug) > 200000:
prefix_guess = 'chromium'
else:

View File

@ -6,6 +6,13 @@
# Chromium specific targets in a client project's GN file etc.
build_with_chromium = false
# Variable that can be used to support multiple build scenarios, like when
# V8 is embedded within a target.
build_with_v8_embedder = false
# Not all of V8's dependencies are available in V8's Node.js build.
build_with_node = false
# Used by perfetto to distinguish from its own standalone build and the
# chromium build.
perfetto_build_with_embedder = true

7
deps/v8/gni/v8.gni vendored
View File

@ -8,6 +8,7 @@ import("//build/config/gclient_args.gni")
import("//build/config/ios/config.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//build/config/v8_target_cpu.gni")
import("//build_overrides/build.gni")
import("release_branch_toggle.gni")
import("split_static_library.gni")
@ -96,6 +97,11 @@ declare_args() {
# Add fuzzilli fuzzer support.
v8_fuzzilli = false
# Enable FuzzTest
v8_enable_fuzztest = !build_with_v8_embedder &&
!(defined(build_with_node) && build_with_node) &&
!(is_win && is_component_build) && is_clang
# Scan the call stack conservatively during garbage collection.
v8_enable_conservative_stack_scanning = false
@ -228,6 +234,7 @@ v8_remove_configs = []
v8_add_configs = [
v8_path_prefix + ":features",
v8_path_prefix + ":toolchain",
v8_path_prefix + ":strict_warnings",
]
if (is_debug && !v8_optimized_debug) {

View File

@ -32,7 +32,7 @@ static constexpr uint16_t kFullyConstructedBitMask = uint16_t{1};
static constexpr size_t kPageSize = size_t{1} << 17;
#if defined(V8_TARGET_ARCH_ARM64) && defined(V8_OS_DARWIN)
#if defined(V8_HOST_ARCH_ARM64) && defined(V8_OS_DARWIN)
constexpr size_t kGuardPageSize = 0;
#else
constexpr size_t kGuardPageSize = 4096;

View File

@ -318,6 +318,12 @@ class V8_EXPORT ArrayBuffer : public Object {
*/
std::shared_ptr<BackingStore> GetBackingStore();
/**
* More efficient shortcut for
* GetBackingStore()->IsResizableByUserJavaScript().
*/
bool IsResizableByUserJavaScript() const;
/**
* More efficient shortcut for GetBackingStore()->Data(). The returned pointer
* is valid as long as the ArrayBuffer is alive.

View File

@ -327,10 +327,6 @@ using WasmAsyncResolvePromiseCallback = void (*)(
using WasmLoadSourceMapCallback = Local<String> (*)(Isolate* isolate,
const char* name);
// --- Callback for checking if WebAssembly GC is enabled ---
// If the callback returns true, it will also enable Wasm stringrefs.
using WasmGCEnabledCallback = bool (*)(Local<Context> context);
// --- Callback for checking if WebAssembly imported strings are enabled ---
using WasmImportedStringsEnabledCallback = bool (*)(Local<Context> context);
@ -342,6 +338,9 @@ using SharedArrayBufferConstructorEnabledCallback =
using JavaScriptCompileHintsMagicEnabledCallback =
bool (*)(Local<Context> context);
// --- Callback for checking if WebAssembly JSPI is enabled ---
using WasmJSPIEnabledCallback = bool (*)(Local<Context> context);
/**
* HostImportModuleDynamicallyCallback is called when we
* require the embedder to load a module. This is used as part of the dynamic
@ -352,11 +351,11 @@ using JavaScriptCompileHintsMagicEnabledCallback =
*
* The specifier is the name of the module that should be imported.
*
* The import_assertions are import assertions for this request in the form:
* The import_attributes are import attributes for this request in the form:
* [key1, value1, key2, value2, ...] where the keys and values are of type
* v8::String. Note, unlike the FixedArray passed to ResolveModuleCallback and
* returned from ModuleRequest::GetImportAssertions(), this array does not
* contain the source Locations of the assertions.
* contain the source Locations of the attributes.
*
* The embedder must compile, instantiate, evaluate the Module, and
* obtain its namespace object.
@ -368,15 +367,10 @@ using JavaScriptCompileHintsMagicEnabledCallback =
* fails (e.g. due to stack overflow), the embedder must propagate
* that exception by returning an empty MaybeLocal.
*/
using HostImportModuleDynamicallyWithImportAssertionsCallback =
MaybeLocal<Promise> (*)(Local<Context> context,
Local<ScriptOrModule> referrer,
Local<String> specifier,
Local<FixedArray> import_assertions);
using HostImportModuleDynamicallyCallback = MaybeLocal<Promise> (*)(
Local<Context> context, Local<Data> host_defined_options,
Local<Value> resource_name, Local<String> specifier,
Local<FixedArray> import_assertions);
Local<FixedArray> import_attributes);
/**
* Callback for requesting a compile hint for a function from the embedder. The

View File

@ -459,12 +459,12 @@ void* Context::GetAlignedPointerFromEmbedderData(int index) {
template <class T>
MaybeLocal<T> Context::GetDataFromSnapshotOnce(size_t index) {
auto slot = GetDataFromSnapshotOnce(index);
if (slot) {
if (auto slot = GetDataFromSnapshotOnce(index); slot) {
internal::PerformCastCheck(
internal::ValueHelper::SlotAsValue<T, false>(slot));
return Local<T>::FromSlot(slot);
}
return Local<T>::FromSlot(slot);
return {};
}
Context* Context::Cast(v8::Data* data) {

View File

@ -27,6 +27,7 @@ class Context;
class DataView;
class Data;
class Date;
class DictionaryTemplate;
class Extension;
class External;
class FixedArray;

View File

@ -475,7 +475,8 @@ Local<Value> ReturnValue<T>::Get() const {
#endif // V8_STATIC_ROOTS_BOOL
return Undefined(GetIsolate());
}
return Local<Value>::New(GetIsolate(), reinterpret_cast<Value*>(value_));
return Local<Value>::New(GetIsolate(),
internal::ValueHelper::SlotAsValue<Value>(value_));
}
template <typename T>

View File

@ -616,8 +616,6 @@ constexpr bool kAllCodeObjectsLiveInTrustedSpace =
kRuntimeGeneratedCodeObjectsLiveInTrustedSpace &&
kBuiltinCodeObjectsLiveInTrustedSpace;
constexpr bool kInterpreterDataObjectsLiveInTrustedSpace = false;
// {obj} must be the raw tagged pointer representation of a HeapObject
// that's guaranteed to never be in ReadOnlySpace.
V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj);
@ -781,8 +779,6 @@ class Internals {
static const int kNodeStateMask = 0x3;
static const int kNodeStateIsWeakValue = 2;
static const int kTracedNodeClassIdOffset = kApiSystemPointerSize;
static const int kFirstNonstringType = 0x80;
static const int kOddballType = 0x83;
static const int kForeignType = 0xcc;

View File

@ -1579,19 +1579,14 @@ class V8_EXPORT Isolate {
void SetWasmLoadSourceMapCallback(WasmLoadSourceMapCallback callback);
/**
* Register callback to control whether Wasm GC is enabled.
* The callback overwrites the value of the flag.
* If the callback returns true, it will also enable Wasm stringrefs.
*/
void SetWasmGCEnabledCallback(WasmGCEnabledCallback callback);
void SetWasmImportedStringsEnabledCallback(
WasmImportedStringsEnabledCallback callback);
void SetSharedArrayBufferConstructorEnabledCallback(
SharedArrayBufferConstructorEnabledCallback callback);
void SetWasmJSPIEnabledCallback(WasmJSPIEnabledCallback callback);
/**
* Register callback to control whether compile hints magic comments are
* enabled.
@ -1751,12 +1746,12 @@ uint32_t Isolate::GetNumberOfDataSlots() {
template <class T>
MaybeLocal<T> Isolate::GetDataFromSnapshotOnce(size_t index) {
auto slot = GetDataFromSnapshotOnce(index);
if (slot) {
if (auto slot = GetDataFromSnapshotOnce(index); slot) {
internal::PerformCastCheck(
internal::ValueHelper::SlotAsValue<T, false>(slot));
return Local<T>::FromSlot(slot);
}
return Local<T>::FromSlot(slot);
return {};
}
} // namespace v8

View File

@ -62,6 +62,7 @@ class ReturnValue;
class String;
template <class F>
class Traced;
class TypecheckWitness;
class Utils;
namespace debug {
@ -405,6 +406,8 @@ class V8_TRIVIAL_ABI Local : public LocalBase<T>,
}
#ifdef V8_ENABLE_DIRECT_LOCAL
friend class TypecheckWitness;
V8_INLINE static Local<T> FromAddress(internal::Address ptr) {
return Local<T>(LocalBase<T>(ptr));
}

View File

@ -241,7 +241,7 @@ class NonCopyablePersistentTraits {
* This will clone the contents of storage cell, but not any of the flags, etc.
*/
template <class T>
struct CopyablePersistentTraits {
struct V8_DEPRECATED("Use v8::Global instead") CopyablePersistentTraits {
using CopyablePersistent = Persistent<T, CopyablePersistentTraits<T>>;
static const bool kResetInDestructor = true;
template <class S, class M>

View File

@ -136,19 +136,24 @@ class V8_EXPORT ModuleRequest : public Data {
int GetSourceOffset() const;
/**
* Contains the import assertions for this request in the form:
* Contains the import attributes for this request in the form:
* [key1, value1, source_offset1, key2, value2, source_offset2, ...].
* The keys and values are of type v8::String, and the source offsets are of
* type Int32. Use Module::SourceOffsetToLocation to convert the source
* offsets to Locations with line/column numbers.
*
* All assertions present in the module request will be supplied in this
* All attributes present in the module request will be supplied in this
* list, regardless of whether they are supported by the host. Per
* https://tc39.es/proposal-import-attributes/#sec-hostgetsupportedimportattributes,
* hosts are expected to throw for assertions that they do not support (as
* hosts are expected to throw for attributes that they do not support (as
* opposed to, for example, ignoring them).
*/
Local<FixedArray> GetImportAssertions() const;
Local<FixedArray> GetImportAttributes() const;
V8_DEPRECATE_SOON("Use GetImportAttributes instead")
Local<FixedArray> GetImportAssertions() const {
return GetImportAttributes();
}
V8_INLINE static ModuleRequest* Cast(Data* data);

View File

@ -14,6 +14,10 @@ namespace v8 {
class Object;
namespace internal {
class SnapshotCreatorImpl;
} // namespace internal
class V8_EXPORT StartupData {
public:
/**
@ -206,7 +210,8 @@ class V8_EXPORT SnapshotCreator {
size_t AddData(Local<Context> context, internal::Address object);
size_t AddData(internal::Address object);
void* data_;
internal::SnapshotCreatorImpl* impl_;
friend class internal::SnapshotCreatorImpl;
};
template <class T>

View File

@ -5,6 +5,9 @@
#ifndef INCLUDE_V8_TEMPLATE_H_
#define INCLUDE_V8_TEMPLATE_H_
#include <cstddef>
#include <string_view>
#include "v8-data.h" // NOLINT(build/include_directory)
#include "v8-function-callback.h" // NOLINT(build/include_directory)
#include "v8-local-handle.h" // NOLINT(build/include_directory)
@ -778,7 +781,11 @@ class V8_EXPORT ObjectTemplate : public Template {
Isolate* isolate,
Local<FunctionTemplate> constructor = Local<FunctionTemplate>());
/** Creates a new instance of this template.*/
/**
* Creates a new instance of this template.
*
* \param context The context in which the instance is created.
*/
V8_WARN_UNUSED_RESULT MaybeLocal<Object> NewInstance(Local<Context> context);
/**
@ -950,6 +957,41 @@ class V8_EXPORT ObjectTemplate : public Template {
friend class FunctionTemplate;
};
/**
* A template to create dictionary objects at runtime.
*/
class V8_EXPORT DictionaryTemplate final {
public:
/** Creates a new template. Also declares data properties that can be passed
* on instantiation of the template. Properties can only be declared on
* construction and are then immutable. The values are passed on creating the
* object via `NewInstance()`.
*
* \param names the keys that can be passed on instantiation.
*/
static Local<DictionaryTemplate> New(
Isolate* isolate, MemorySpan<const std::string_view> names);
/**
* Creates a new instance of this template.
*
* \param context The context used to create the dictionary object.
* \param property_values Values of properties that were declared using
* `DeclareDataProperties()`. The span only passes values and expectes the
* order to match the declaration. Non-existent properties are signaled via
* empty `MaybeLocal`s.
*/
V8_WARN_UNUSED_RESULT Local<Object> NewInstance(
Local<Context> context, MemorySpan<MaybeLocal<Value>> property_values);
V8_INLINE static DictionaryTemplate* Cast(Data* data);
private:
static void CheckCast(Data* that);
DictionaryTemplate();
};
/**
* A Signature specifies which receiver is valid for a function.
*
@ -995,6 +1037,13 @@ ObjectTemplate* ObjectTemplate::Cast(Data* data) {
return reinterpret_cast<ObjectTemplate*>(data);
}
DictionaryTemplate* DictionaryTemplate::Cast(Data* data) {
#ifdef V8_ENABLE_CHECKS
CheckCast(data);
#endif
return reinterpret_cast<DictionaryTemplate*>(data);
}
Signature* Signature::Cast(Data* data) {
#ifdef V8_ENABLE_CHECKS
CheckCast(data);

View File

@ -77,19 +77,6 @@ class TracedReferenceBase : public api_internal::IndirectHandleBase {
return this->GetSlotThreadSafe() == nullptr;
}
/**
* Assigns a wrapper class ID to the handle.
*/
V8_DEPRECATED("Embedders need to maintain state for references themselves.")
V8_INLINE void SetWrapperClassId(uint16_t class_id);
/**
* Returns the class ID previously assigned to this handle or 0 if no class ID
* was previously assigned.
*/
V8_DEPRECATED("Embedders need to maintain state for references themselves.")
V8_INLINE uint16_t WrapperClassId() const;
protected:
V8_INLINE TracedReferenceBase() = default;
@ -440,22 +427,6 @@ TracedReference<T>& TracedReference<T>::operator=(const TracedReference& rhs) {
return *this;
}
void TracedReferenceBase::SetWrapperClassId(uint16_t class_id) {
using I = internal::Internals;
if (IsEmpty()) return;
uint8_t* addr =
reinterpret_cast<uint8_t*>(slot()) + I::kTracedNodeClassIdOffset;
*reinterpret_cast<uint16_t*>(addr) = class_id;
}
uint16_t TracedReferenceBase::WrapperClassId() const {
using I = internal::Internals;
if (IsEmpty()) return 0;
uint8_t* addr =
reinterpret_cast<uint8_t*>(slot()) + I::kTracedNodeClassIdOffset;
return *reinterpret_cast<uint16_t*>(addr);
}
} // namespace v8
#endif // INCLUDE_V8_TRACED_HANDLE_H_

View File

@ -240,8 +240,9 @@ class PersistentValueMapBase {
: value_(other.value_) { }
Local<V> NewLocal(Isolate* isolate) const {
return Local<V>::New(
isolate, internal::ValueHelper::SlotAsValue<V>(FromVal(value_)));
return Local<V>::New(isolate,
internal::ValueHelper::SlotAsValue<V>(
reinterpret_cast<internal::Address*>(value_)));
}
bool IsEmpty() const {
return value_ == kPersistentContainerNotFound;
@ -298,7 +299,8 @@ class PersistentValueMapBase {
typename Traits::Impl* impl() { return &impl_; }
static V* FromVal(PersistentContainerValue v) {
return reinterpret_cast<V*>(v);
return internal::ValueHelper::SlotAsValue<V>(
reinterpret_cast<internal::Address*>(v));
}
static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
@ -318,7 +320,7 @@ class PersistentValueMapBase {
*/
static Global<V> Release(PersistentContainerValue v) {
Global<V> p;
p.slot() = reinterpret_cast<internal::Address*>(FromVal(v));
p.slot() = reinterpret_cast<internal::Address*>(v);
if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
Traits::DisposeCallbackData(
p.template ClearWeak<typename Traits::WeakCallbackDataType>());
@ -328,8 +330,8 @@ class PersistentValueMapBase {
void RemoveWeak(const K& key) {
Global<V> p;
p.slot() = reinterpret_cast<internal::Address*>(
FromVal(Traits::Remove(&impl_, key)));
p.slot() =
reinterpret_cast<internal::Address*>(Traits::Remove(&impl_, key));
p.Reset();
}
@ -345,8 +347,7 @@ class PersistentValueMapBase {
PersistentContainerValue value) {
bool hasValue = value != kPersistentContainerNotFound;
if (hasValue) {
returnValue->SetInternal(
*reinterpret_cast<internal::Address*>(FromVal(value)));
returnValue->SetInternal(*reinterpret_cast<internal::Address*>(value));
}
return hasValue;
}
@ -620,7 +621,7 @@ class V8_DEPRECATE_SOON("Use std::vector<Global<V>>.") PersistentValueVector {
*/
Local<V> Get(size_t index) const {
return Local<V>::New(isolate_, internal::ValueHelper::SlotAsValue<V>(
FromVal(Traits::Get(&impl_, index))));
Traits::Get(&impl_, index)));
}
/**
@ -630,8 +631,7 @@ class V8_DEPRECATE_SOON("Use std::vector<Global<V>>.") PersistentValueVector {
size_t length = Traits::Size(&impl_);
for (size_t i = 0; i < length; i++) {
Global<V> p;
p.slot() =
reinterpret_cast<internal::Address>(FromVal(Traits::Get(&impl_, i)));
p.slot() = reinterpret_cast<internal::Address>(Traits::Get(&impl_, i));
}
Traits::Clear(&impl_);
}
@ -652,7 +652,8 @@ class V8_DEPRECATE_SOON("Use std::vector<Global<V>>.") PersistentValueVector {
}
static V* FromVal(PersistentContainerValue v) {
return reinterpret_cast<V*>(v);
return internal::ValueHelper::SlotAsValue<V>(
reinterpret_cast<internal::Address*>(v));
}
Isolate* isolate_;

View File

@ -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 12
#define V8_MINOR_VERSION 2
#define V8_BUILD_NUMBER 281
#define V8_PATCH_LEVEL 27
#define V8_MINOR_VERSION 3
#define V8_BUILD_NUMBER 219
#define V8_PATCH_LEVEL 16
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)

View File

@ -376,7 +376,6 @@
},
'tests': [
{'name': 'v8testing', 'variant': 'default'},
{'name': 'v8testing', 'variant': 'future'},
],
},
'v8_linux64_coverage_rel': {
@ -1435,7 +1434,6 @@
},
'tests': [
{'name': 'v8testing', 'variant': 'default'},
{'name': 'v8testing', 'variant': 'future'},
],
},
'V8 Linux64 - custom snapshot - debug': {

View File

@ -48,11 +48,11 @@
* For a more sophisticated shell, consider using the debug shell D8.
*/
v8::Local<v8::Context> CreateShellContext(v8::Isolate* isolate);
void RunShell(v8::Local<v8::Context> context, v8::Platform* platform);
int RunMain(v8::Isolate* isolate, v8::Platform* platform, int argc,
char* argv[]);
v8::Global<v8::Context> CreateShellContext(v8::Isolate* isolate);
void RunShell(v8::Isolate* isolate, const v8::Global<v8::Context>& context,
v8::Platform* platform);
int RunMain(v8::Isolate* isolate, const v8::Global<v8::Context>& context,
v8::Platform* platform, int argc, char* argv[]);
bool ExecuteString(v8::Isolate* isolate, v8::Local<v8::String> source,
v8::Local<v8::Value> name, bool print_result,
bool report_exceptions);
@ -64,10 +64,8 @@ void Version(const v8::FunctionCallbackInfo<v8::Value>& info);
v8::MaybeLocal<v8::String> ReadFile(v8::Isolate* isolate, const char* name);
void ReportException(v8::Isolate* isolate, v8::TryCatch* handler);
static bool run_shell;
int main(int argc, char* argv[]) {
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
@ -83,15 +81,13 @@ int main(int argc, char* argv[]) {
int result;
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = CreateShellContext(isolate);
v8::Global<v8::Context> context = CreateShellContext(isolate);
if (context.IsEmpty()) {
fprintf(stderr, "Error creating context\n");
return 1;
}
v8::Context::Scope context_scope(context);
result = RunMain(isolate, platform.get(), argc, argv);
if (run_shell) RunShell(context, platform.get());
result = RunMain(isolate, context, platform.get(), argc, argv);
if (run_shell) RunShell(isolate, context, platform.get());
}
isolate->Dispose();
v8::V8::Dispose();
@ -100,16 +96,15 @@ int main(int argc, char* argv[]) {
return result;
}
// Extracts a C string from a V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}
// Creates a new execution environment containing the built-in
// functions.
v8::Local<v8::Context> CreateShellContext(v8::Isolate* isolate) {
v8::Global<v8::Context> CreateShellContext(v8::Isolate* isolate) {
v8::HandleScope handle_scope(isolate);
// Create a template for the global object.
v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
// Bind the global 'print' function to the C++ Print callback.
@ -122,10 +117,11 @@ v8::Local<v8::Context> CreateShellContext(v8::Isolate* isolate) {
global->Set(isolate, "quit", v8::FunctionTemplate::New(isolate, Quit));
// Bind the 'version' function
global->Set(isolate, "version", v8::FunctionTemplate::New(isolate, Version));
return v8::Context::New(isolate, NULL, global);
// Return the context.
v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
return v8::Global<v8::Context>(isolate, context);
}
// The callback that is invoked by v8 whenever the JavaScript 'print'
// function is called. Prints its arguments on stdout separated by
// spaces and ending with a newline.
@ -155,7 +151,7 @@ void Read(const v8::FunctionCallbackInfo<v8::Value>& info) {
return;
}
v8::String::Utf8Value file(info.GetIsolate(), info[0]);
if (*file == NULL) {
if (*file == nullptr) {
info.GetIsolate()->ThrowError("Error loading file");
return;
}
@ -175,7 +171,7 @@ void Load(const v8::FunctionCallbackInfo<v8::Value>& info) {
for (int i = 0; i < info.Length(); i++) {
v8::HandleScope handle_scope(info.GetIsolate());
v8::String::Utf8Value file(info.GetIsolate(), info[i]);
if (*file == NULL) {
if (*file == nullptr) {
info.GetIsolate()->ThrowError("Error loading file");
return;
}
@ -203,6 +199,8 @@ void Quit(const v8::FunctionCallbackInfo<v8::Value>& info) {
exit(exit_code);
}
// The callback that is invoked by v8 whenever the JavaScript 'version'
// function is called. Returns a string containing the current V8 version.
void Version(const v8::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(
v8::String::NewFromUtf8(info.GetIsolate(), v8::V8::GetVersion())
@ -212,7 +210,7 @@ void Version(const v8::FunctionCallbackInfo<v8::Value>& info) {
// Reads a file into a v8 string.
v8::MaybeLocal<v8::String> ReadFile(v8::Isolate* isolate, const char* name) {
FILE* file = fopen(name, "rb");
if (file == NULL) return v8::MaybeLocal<v8::String>();
if (file == nullptr) return {};
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
@ -224,7 +222,7 @@ v8::MaybeLocal<v8::String> ReadFile(v8::Isolate* isolate, const char* name) {
i += fread(&chars[i], 1, size - i, file);
if (ferror(file)) {
fclose(file);
return v8::MaybeLocal<v8::String>();
return {};
}
}
fclose(file);
@ -234,10 +232,9 @@ v8::MaybeLocal<v8::String> ReadFile(v8::Isolate* isolate, const char* name) {
return result;
}
// Process remaining command line arguments and execute files
int RunMain(v8::Isolate* isolate, v8::Platform* platform, int argc,
char* argv[]) {
int RunMain(v8::Isolate* isolate, const v8::Global<v8::Context>& context,
v8::Platform* platform, int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
const char* str = argv[i];
if (strcmp(str, "--shell") == 0) {
@ -251,25 +248,41 @@ int RunMain(v8::Isolate* isolate, v8::Platform* platform, int argc,
"Warning: unknown flag %s.\nTry --help for options\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
// Execute argument given to -e option directly.
v8::Local<v8::String> file_name =
v8::String::NewFromUtf8Literal(isolate, "unnamed");
v8::Local<v8::String> source;
if (!v8::String::NewFromUtf8(isolate, argv[++i]).ToLocal(&source)) {
return 1;
bool success;
{
// Enter the execution environment before evaluating any code.
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context.Get(isolate));
v8::Local<v8::String> file_name =
v8::String::NewFromUtf8Literal(isolate, "unnamed");
v8::Local<v8::String> source;
if (!v8::String::NewFromUtf8(isolate, argv[++i]).ToLocal(&source)) {
return 1;
}
success = ExecuteString(isolate, source, file_name, false, true);
}
bool success = ExecuteString(isolate, source, file_name, false, true);
// It is important not to pump the message loop when there are v8::Local
// handles on the stack, as this may trigger a stackless GC.
while (v8::platform::PumpMessageLoop(platform, isolate)) continue;
if (!success) return 1;
} else {
// Use all other arguments as names of files to load and run.
v8::Local<v8::String> file_name =
v8::String::NewFromUtf8(isolate, str).ToLocalChecked();
v8::Local<v8::String> source;
if (!ReadFile(isolate, str).ToLocal(&source)) {
fprintf(stderr, "Error reading '%s'\n", str);
continue;
bool success;
{
// Enter the execution environment before evaluating any code.
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context.Get(isolate));
v8::Local<v8::String> file_name =
v8::String::NewFromUtf8(isolate, str).ToLocalChecked();
v8::Local<v8::String> source;
if (!ReadFile(isolate, str).ToLocal(&source)) {
fprintf(stderr, "Error reading '%s'\n", str);
continue;
}
success = ExecuteString(isolate, source, file_name, false, true);
}
bool success = ExecuteString(isolate, source, file_name, false, true);
// It is important not to pump the message loop when there are v8::Local
// handles on the stack, as this may trigger a stackless GC.
while (v8::platform::PumpMessageLoop(platform, isolate)) continue;
if (!success) return 1;
}
@ -277,32 +290,33 @@ int RunMain(v8::Isolate* isolate, v8::Platform* platform, int argc,
return 0;
}
// The read-eval-execute loop of the shell.
void RunShell(v8::Local<v8::Context> context, v8::Platform* platform) {
void RunShell(v8::Isolate* isolate, const v8::Global<v8::Context>& context,
v8::Platform* platform) {
fprintf(stderr, "V8 version %s [sample shell]\n", v8::V8::GetVersion());
static const int kBufferSize = 256;
// Enter the execution environment before evaluating any code.
v8::Context::Scope context_scope(context);
v8::Local<v8::String> name(
v8::String::NewFromUtf8Literal(context->GetIsolate(), "(shell)"));
while (true) {
char buffer[kBufferSize];
fprintf(stderr, "> ");
char* str = fgets(buffer, kBufferSize, stdin);
if (str == NULL) break;
v8::HandleScope handle_scope(context->GetIsolate());
ExecuteString(
context->GetIsolate(),
v8::String::NewFromUtf8(context->GetIsolate(), str).ToLocalChecked(),
name, true, true);
while (v8::platform::PumpMessageLoop(platform, context->GetIsolate()))
continue;
if (str == nullptr) break;
{
// Enter the execution environment before evaluating any code.
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context.Get(isolate));
v8::Local<v8::String> name(
v8::String::NewFromUtf8Literal(isolate, "(shell)"));
ExecuteString(isolate,
v8::String::NewFromUtf8(isolate, str).ToLocalChecked(),
name, true, true);
}
// It is important not to pump the message loop when there are v8::Local
// handles on the stack, as this may trigger a stackless GC.
while (v8::platform::PumpMessageLoop(platform, isolate)) continue;
}
fprintf(stderr, "\n");
}
// Executes a string within the current v8 context.
bool ExecuteString(v8::Isolate* isolate, v8::Local<v8::String> source,
v8::Local<v8::Value> name, bool print_result,
@ -339,7 +353,6 @@ bool ExecuteString(v8::Isolate* isolate, v8::Local<v8::String> source,
}
}
void ReportException(v8::Isolate* isolate, v8::TryCatch* try_catch) {
v8::HandleScope handle_scope(isolate);
v8::String::Utf8Value exception(isolate, try_catch->Exception());

7
deps/v8/src/DEPS vendored
View File

@ -39,6 +39,7 @@ include_rules = [
# TODO(v8:10496): Don't expose memory chunk outside of heap/.
"+src/heap/memory-chunk.h",
"+src/heap/memory-chunk-inl.h",
"+src/heap/memory-chunk-header.h",
"+src/heap/paged-spaces-inl.h",
"+src/heap/parked-scope-inl.h",
"+src/heap/parked-scope.h",
@ -107,6 +108,12 @@ specific_include_rules = {
"external-pointer-table\.cc": [
"+src/heap/read-only-spaces.h",
],
# keep the includes to a minimum since this header will be included via write barriers.
"memory-chunk-header\.h": [
"-src",
"+src/base/build_config.h",
"+src/flags/flags.h",
],
"script\.h": [
"+src/heap/factory.h",
"+src/heap/factory-base.h",

View File

@ -179,7 +179,7 @@ class V8_NODISCARD CallDepthScope {
CallDepthScope(i::Isolate* isolate, Local<Context> context)
: isolate_(isolate), saved_context_(isolate->context(), isolate_) {
isolate_->thread_local_top()->IncrementCallDepth<do_callback>(this);
i::Tagged<i::NativeContext> env = *Utils::OpenHandle(*context);
i::Tagged<i::NativeContext> env = *Utils::OpenDirectHandle(*context);
isolate->set_context(env);
if (do_callback) isolate_->FireBeforeCallEnteredCallback();
@ -304,7 +304,7 @@ bool CopyAndConvertArrayToCppBuffer(Local<Array> src, T* dst,
}
i::DisallowGarbageCollection no_gc;
i::Tagged<i::JSArray> obj = *Utils::OpenHandle(*src);
i::Tagged<i::JSArray> obj = *Utils::OpenDirectHandle(*src);
if (i::Object::IterationHasObservableEffects(obj)) {
// The array has a custom iterator.
return false;

157
deps/v8/src/api/api.cc vendored
View File

@ -24,6 +24,7 @@
#include "include/v8-primitive-object.h"
#include "include/v8-profiler.h"
#include "include/v8-source-location.h"
#include "include/v8-template.h"
#include "include/v8-unwinder-state.h"
#include "include/v8-util.h"
#include "include/v8-wasm.h"
@ -86,6 +87,7 @@
#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/js-objects.h"
#include "src/objects/js-promise-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/js-weak-refs-inl.h"
@ -101,6 +103,7 @@
#include "src/objects/shared-function-info.h"
#include "src/objects/slots.h"
#include "src/objects/smi.h"
#include "src/objects/string.h"
#include "src/objects/synthetic-module-inl.h"
#include "src/objects/templates.h"
#include "src/objects/value-serializer.h"
@ -537,7 +540,7 @@ SnapshotCreator::SnapshotCreator(Isolate* v8_isolate,
const intptr_t* external_references,
const StartupData* existing_snapshot,
bool owns_isolate)
: data_(new i::SnapshotCreatorImpl(
: impl_(new i::SnapshotCreatorImpl(
reinterpret_cast<i::Isolate*>(v8_isolate), external_references,
existing_snapshot, owns_isolate)) {}
@ -546,50 +549,43 @@ SnapshotCreator::SnapshotCreator(const intptr_t* external_references,
: SnapshotCreator(nullptr, external_references, existing_snapshot) {}
SnapshotCreator::SnapshotCreator(const v8::Isolate::CreateParams& params)
: data_(new i::SnapshotCreatorImpl(params)) {}
: impl_(new i::SnapshotCreatorImpl(params)) {}
SnapshotCreator::SnapshotCreator(v8::Isolate* isolate,
const v8::Isolate::CreateParams& params)
: data_(new i::SnapshotCreatorImpl(reinterpret_cast<i::Isolate*>(isolate),
: impl_(new i::SnapshotCreatorImpl(reinterpret_cast<i::Isolate*>(isolate),
params)) {}
SnapshotCreator::~SnapshotCreator() {
DCHECK_NOT_NULL(data_);
auto impl = static_cast<i::SnapshotCreatorImpl*>(data_);
delete impl;
DCHECK_NOT_NULL(impl_);
delete impl_;
}
Isolate* SnapshotCreator::GetIsolate() {
auto impl = static_cast<i::SnapshotCreatorImpl*>(data_);
return reinterpret_cast<v8::Isolate*>(impl->isolate());
return reinterpret_cast<v8::Isolate*>(impl_->isolate());
}
void SnapshotCreator::SetDefaultContext(
Local<Context> context, SerializeInternalFieldsCallback callback) {
auto impl = static_cast<i::SnapshotCreatorImpl*>(data_);
impl->SetDefaultContext(Utils::OpenHandle(*context), callback);
impl_->SetDefaultContext(Utils::OpenHandle(*context), callback);
}
size_t SnapshotCreator::AddContext(Local<Context> context,
SerializeInternalFieldsCallback callback) {
auto impl = static_cast<i::SnapshotCreatorImpl*>(data_);
return impl->AddContext(Utils::OpenHandle(*context), callback);
return impl_->AddContext(Utils::OpenHandle(*context), callback);
}
size_t SnapshotCreator::AddData(i::Address object) {
auto impl = static_cast<i::SnapshotCreatorImpl*>(data_);
return impl->AddData(object);
return impl_->AddData(object);
}
size_t SnapshotCreator::AddData(Local<Context> context, i::Address object) {
auto impl = static_cast<i::SnapshotCreatorImpl*>(data_);
return impl->AddData(Utils::OpenHandle(*context), object);
return impl_->AddData(Utils::OpenHandle(*context), object);
}
StartupData SnapshotCreator::CreateBlob(
SnapshotCreator::FunctionCodeHandling function_code_handling) {
auto impl = static_cast<i::SnapshotCreatorImpl*>(data_);
return impl->CreateBlob(function_code_handling);
return impl_->CreateBlob(function_code_handling);
}
bool StartupData::CanBeRehashed() const {
@ -1949,6 +1945,24 @@ void ObjectTemplate::SetCodeLike() {
self->set_code_like(true);
}
Local<DictionaryTemplate> DictionaryTemplate::New(
Isolate* isolate, MemorySpan<const std::string_view> names) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
API_RCS_SCOPE(i_isolate, DictionaryTemplate, New);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
return Utils::ToLocal(i::DictionaryTemplateInfo::Create(i_isolate, names));
}
Local<Object> DictionaryTemplate::NewInstance(
Local<Context> context, MemorySpan<MaybeLocal<Value>> property_values) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
API_RCS_SCOPE(i_isolate, DictionaryTemplate, NewInstance);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
auto self = Utils::OpenDirectHandle(this);
return ToApiHandle<Object>(i::DictionaryTemplateInfo::NewInstance(
Utils::OpenHandle(*context), self, property_values));
}
// --- S c r i p t s ---
// Internally, UnboundScript and UnboundModuleScript are SharedFunctionInfos,
@ -2294,11 +2308,11 @@ int ModuleRequest::GetSourceOffset() const {
return Utils::OpenDirectHandle(this)->position();
}
Local<FixedArray> ModuleRequest::GetImportAssertions() const {
Local<FixedArray> ModuleRequest::GetImportAttributes() const {
auto self = Utils::OpenDirectHandle(this);
i::Isolate* i_isolate = self->GetIsolate();
return ToApiHandle<FixedArray>(
i::direct_handle(self->import_assertions(), i_isolate), i_isolate);
i::direct_handle(self->import_attributes(), i_isolate), i_isolate);
}
Module::Status Module::GetStatus() const {
@ -3866,7 +3880,7 @@ bool Value::IsInt32() const {
}
bool Value::IsUint32() const {
auto obj = *Utils::OpenHandle(this);
auto obj = *Utils::OpenDirectHandle(this);
if (i::IsSmi(obj)) return i::Smi::ToInt(obj) >= 0;
if (i::IsNumber(obj)) {
double value = i::Object::Number(obj);
@ -4271,6 +4285,10 @@ void* v8::ArrayBuffer::Data() const {
return Utils::OpenDirectHandle(this)->backing_store();
}
bool v8::ArrayBuffer::IsResizableByUserJavaScript() const {
return Utils::OpenDirectHandle(this)->is_resizable_by_js();
}
std::shared_ptr<v8::BackingStore> v8::SharedArrayBuffer::GetBackingStore() {
auto self = Utils::OpenDirectHandle(this);
std::shared_ptr<i::BackingStore> backing_store = self->GetBackingStore();
@ -4306,7 +4324,7 @@ void v8::TypedArray::CheckCast(Value* that) {
#define CHECK_TYPED_ARRAY_CAST(Type, typeName, TYPE, ctype) \
void v8::Type##Array::CheckCast(Value* that) { \
auto obj = *Utils::OpenHandle(that); \
auto obj = *Utils::OpenDirectHandle(that); \
Utils::ApiCheck( \
i::IsJSTypedArray(obj) && \
i::JSTypedArray::cast(obj)->type() == i::kExternal##Type##Array, \
@ -5359,6 +5377,30 @@ bool v8::Object::IsUndetectable() const {
return i::IsUndetectable(*self);
}
namespace {
#ifdef V8_ENABLE_DIRECT_LOCAL
// A newly allocated vector is required to convert from an array of direct
// locals to an array of indirect handles.
std::vector<i::Handle<i::Object>> PrepareArguments(int argc,
Local<Value> argv[]) {
std::vector<i::Handle<i::Object>> args(argc);
for (int i = 0; i < argc; ++i) {
args[i] = Utils::OpenHandle(*argv[i]);
}
return args;
}
#else // !V8_ENABLE_DIRECT_LOCAL
// A simple cast is used to convert from an array of indirect locals to an
// array of indirect handles. A MemorySpan object is returned, as no
// deallocation is necessary.
v8::MemorySpan<i::Handle<i::Object>> PrepareArguments(int argc,
Local<Value> argv[]) {
return {reinterpret_cast<i::Handle<i::Object>*>(argv),
static_cast<size_t>(argc)};
}
#endif // V8_ENABLE_DIRECT_LOCAL
} // namespace
MaybeLocal<Value> Object::CallAsFunction(Local<Context> context,
Local<Value> recv, int argc,
Local<Value> argv[]) {
@ -5371,10 +5413,11 @@ MaybeLocal<Value> Object::CallAsFunction(Local<Context> context,
auto self = Utils::OpenHandle(this);
auto recv_obj = Utils::OpenHandle(*recv);
static_assert(sizeof(v8::Local<v8::Value>) == sizeof(i::Handle<i::Object>));
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
auto args = PrepareArguments(argc, argv);
Local<Value> result;
has_exception = !ToLocal<Value>(
i::Execution::Call(i_isolate, self, recv_obj, argc, args), &result);
i::Execution::Call(i_isolate, self, recv_obj, argc, args.data()),
&result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
@ -5390,10 +5433,10 @@ MaybeLocal<Value> Object::CallAsConstructor(Local<Context> context, int argc,
i_isolate);
auto self = Utils::OpenHandle(this);
static_assert(sizeof(v8::Local<v8::Value>) == sizeof(i::Handle<i::Object>));
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
auto args = PrepareArguments(argc, argv);
Local<Value> result;
has_exception = !ToLocal<Value>(
i::Execution::New(i_isolate, self, self, argc, args), &result);
i::Execution::New(i_isolate, self, self, argc, args.data()), &result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
@ -5446,10 +5489,10 @@ MaybeLocal<Object> Function::NewInstanceWithSideEffectType(
}
}
}
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
auto args = PrepareArguments(argc, argv);
Local<Object> result;
has_exception = !ToLocal<Object>(
i::Execution::New(i_isolate, self, self, argc, args), &result);
i::Execution::New(i_isolate, self, self, argc, args.data()), &result);
RETURN_ON_FAILED_EXECUTION(Object);
RETURN_ESCAPED(result);
}
@ -5468,19 +5511,11 @@ MaybeLocal<v8::Value> Function::Call(Local<Context> context,
"Function to be called is a null pointer");
auto recv_obj = Utils::OpenHandle(*recv);
static_assert(sizeof(v8::Local<v8::Value>) == sizeof(i::Handle<i::Object>));
#ifdef V8_ENABLE_DIRECT_LOCAL
i::Handle<i::Object>* args = new i::Handle<i::Object>[argc];
for (int i = 0; i < argc; ++i) {
args[i] = Utils::OpenHandle(*argv[i]);
}
#else // !V8_ENABLE_DIRECT_LOCAL
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
#endif // V8_ENABLE_DIRECT_LOCAL
auto args = PrepareArguments(argc, argv);
Local<Value> result;
has_exception = !ToLocal<Value>(
i::Execution::Call(i_isolate, self, recv_obj, argc, args), &result);
i::Execution::Call(i_isolate, self, recv_obj, argc, args.data()),
&result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}
@ -7328,6 +7363,13 @@ void v8::ObjectTemplate::CheckCast(Data* that) {
"Value is not an ObjectTemplate");
}
void v8::DictionaryTemplate::CheckCast(Data* that) {
auto obj = Utils::OpenDirectHandle(that);
Utils::ApiCheck(i::IsDictionaryTemplateInfo(*obj),
"v8::DictionaryTemplate::Cast",
"Value is not an DictionaryTemplate");
}
void v8::FunctionTemplate::CheckCast(Data* that) {
auto obj = Utils::OpenDirectHandle(that);
Utils::ApiCheck(i::IsFunctionTemplateInfo(*obj), "v8::FunctionTemplate::Cast",
@ -8087,7 +8129,7 @@ uint32_t GetLength(Tagged<JSArray> array) {
} // namespace internal
uint32_t v8::Array::Length() const {
return i::GetLength(*Utils::OpenHandle(this));
return i::GetLength(*Utils::OpenDirectHandle(this));
}
namespace internal {
@ -8259,13 +8301,27 @@ Maybe<void> v8::Array::Iterate(Local<Context> context,
}
v8::TypecheckWitness::TypecheckWitness(Isolate* isolate)
#ifdef V8_ENABLE_DIRECT_LOCAL
// An empty local suffices.
: cached_map_()
#else
// We need to reserve a handle that we can patch later.
// TODO(13270): When we switch to CSS, we can use a direct pointer
// instead of a handle.
: cached_map_(v8::Number::New(isolate, 1)) {}
// We initialize it with something that cannot compare equal to any map.
: cached_map_(v8::Number::New(isolate, 1))
#endif
{
}
void v8::TypecheckWitness::Update(Local<Value> baseline) {
i::Tagged<i::Object> obj = *Utils::OpenDirectHandle(*baseline);
#ifdef V8_ENABLE_DIRECT_LOCAL
if (IsSmi(obj)) {
cached_map_ = Local<Data>();
} else {
i::Tagged<i::HeapObject> map = i::HeapObject::cast(obj)->map();
cached_map_ = Local<Data>::FromAddress(map->ptr());
}
#else
i::Tagged<i::Object> map = i::Smi::zero();
if (!IsSmi(obj)) map = i::HeapObject::cast(obj)->map();
// Design overview: in the {TypecheckWitness} constructor, we create
@ -8274,12 +8330,12 @@ void v8::TypecheckWitness::Update(Local<Value> baseline) {
// to allow having short-lived HandleScopes (e.g. in {FastIterateArray}
// above) while a {TypecheckWitness} is alive: it therefore cannot hold
// on to one of the short-lived handles.
// Calling {OpenHandle} on the {cached_map_} only serves to "reinterpret_cast"
// it to an {i::Handle} on which we can call {PatchValue}.
// TODO(13270): When we switch to CSS, this can become simpler: we can
// then simply overwrite the direct pointer.
// Calling {OpenIndirectHandle} on the {cached_map_} only serves to
// "reinterpret_cast" it to an {i::IndirectHandle} on which we can call
// {PatchValue}.
auto cache = Utils::OpenIndirectHandle(*cached_map_);
cache.PatchValue(map);
#endif
}
Local<v8::Map> v8::Map::New(Isolate* v8_isolate) {
@ -10384,13 +10440,13 @@ CALLBACK_SETTER(WasmAsyncResolvePromiseCallback,
CALLBACK_SETTER(WasmLoadSourceMapCallback, WasmLoadSourceMapCallback,
wasm_load_source_map_callback)
CALLBACK_SETTER(WasmGCEnabledCallback, WasmGCEnabledCallback,
wasm_gc_enabled_callback)
CALLBACK_SETTER(WasmImportedStringsEnabledCallback,
WasmImportedStringsEnabledCallback,
wasm_imported_strings_enabled_callback)
CALLBACK_SETTER(WasmJSPIEnabledCallback, WasmJSPIEnabledCallback,
wasm_jspi_enabled_callback)
CALLBACK_SETTER(SharedArrayBufferConstructorEnabledCallback,
SharedArrayBufferConstructorEnabledCallback,
sharedarraybuffer_constructor_enabled_callback)
@ -10410,6 +10466,7 @@ void Isolate::InstallConditionalFeatures(Local<Context> context) {
i::WasmJs::InstallConditionalFeatures(i_isolate,
Utils::OpenHandle(*context));
}
#endif // V8_ENABLE_WEBASSEMBLY
}

181
deps/v8/src/api/api.h vendored
View File

@ -30,6 +30,7 @@
namespace v8 {
class DictionaryTemplate;
class Extension;
class Signature;
class Template;
@ -96,97 +97,99 @@ class RegisteredExtension {
static RegisteredExtension* first_extension_;
};
#define TO_LOCAL_LIST(V) \
V(ToLocal, AccessorPair, debug::AccessorPair) \
V(ToLocal, NativeContext, Context) \
V(ToLocal, Object, Value) \
V(ToLocal, Module, Module) \
V(ToLocal, Name, Name) \
V(ToLocal, String, String) \
V(ToLocal, Symbol, Symbol) \
V(ToLocal, JSRegExp, RegExp) \
V(ToLocal, JSReceiver, Object) \
V(ToLocal, JSObject, Object) \
V(ToLocal, JSFunction, Function) \
V(ToLocal, JSArray, Array) \
V(ToLocal, JSMap, Map) \
V(ToLocal, JSSet, Set) \
V(ToLocal, JSProxy, Proxy) \
V(ToLocal, JSArrayBuffer, ArrayBuffer) \
V(ToLocal, JSArrayBufferView, ArrayBufferView) \
V(ToLocal, JSDataView, DataView) \
V(ToLocal, JSRabGsabDataView, DataView) \
V(ToLocal, JSTypedArray, TypedArray) \
V(ToLocalShared, JSArrayBuffer, SharedArrayBuffer) \
V(ToLocal, FunctionTemplateInfo, FunctionTemplate) \
V(ToLocal, ObjectTemplateInfo, ObjectTemplate) \
V(SignatureToLocal, FunctionTemplateInfo, Signature) \
V(MessageToLocal, Object, Message) \
V(PromiseToLocal, JSObject, Promise) \
V(StackTraceToLocal, FixedArray, StackTrace) \
V(StackFrameToLocal, StackFrameInfo, StackFrame) \
V(NumberToLocal, Object, Number) \
V(IntegerToLocal, Object, Integer) \
V(Uint32ToLocal, Object, Uint32) \
V(ToLocal, BigInt, BigInt) \
V(ExternalToLocal, JSObject, External) \
V(CallableToLocal, JSReceiver, Function) \
V(ToLocalPrimitive, Object, Primitive) \
V(FixedArrayToLocal, FixedArray, FixedArray) \
V(PrimitiveArrayToLocal, FixedArray, PrimitiveArray) \
#define TO_LOCAL_LIST(V) \
V(ToLocal, AccessorPair, debug::AccessorPair) \
V(ToLocal, NativeContext, Context) \
V(ToLocal, Object, Value) \
V(ToLocal, Module, Module) \
V(ToLocal, Name, Name) \
V(ToLocal, String, String) \
V(ToLocal, Symbol, Symbol) \
V(ToLocal, JSRegExp, RegExp) \
V(ToLocal, JSReceiver, Object) \
V(ToLocal, JSObject, Object) \
V(ToLocal, JSFunction, Function) \
V(ToLocal, JSArray, Array) \
V(ToLocal, JSMap, Map) \
V(ToLocal, JSSet, Set) \
V(ToLocal, JSProxy, Proxy) \
V(ToLocal, JSArrayBuffer, ArrayBuffer) \
V(ToLocal, JSArrayBufferView, ArrayBufferView) \
V(ToLocal, JSDataView, DataView) \
V(ToLocal, JSRabGsabDataView, DataView) \
V(ToLocal, JSTypedArray, TypedArray) \
V(ToLocalShared, JSArrayBuffer, SharedArrayBuffer) \
V(ToLocal, FunctionTemplateInfo, FunctionTemplate) \
V(ToLocal, ObjectTemplateInfo, ObjectTemplate) \
V(ToLocal, DictionaryTemplateInfo, DictionaryTemplate) \
V(SignatureToLocal, FunctionTemplateInfo, Signature) \
V(MessageToLocal, Object, Message) \
V(PromiseToLocal, JSObject, Promise) \
V(StackTraceToLocal, FixedArray, StackTrace) \
V(StackFrameToLocal, StackFrameInfo, StackFrame) \
V(NumberToLocal, Object, Number) \
V(IntegerToLocal, Object, Integer) \
V(Uint32ToLocal, Object, Uint32) \
V(ToLocal, BigInt, BigInt) \
V(ExternalToLocal, JSObject, External) \
V(CallableToLocal, JSReceiver, Function) \
V(ToLocalPrimitive, Object, Primitive) \
V(FixedArrayToLocal, FixedArray, FixedArray) \
V(PrimitiveArrayToLocal, FixedArray, PrimitiveArray) \
V(ToLocal, ScriptOrModule, ScriptOrModule)
#define OPEN_HANDLE_LIST(V) \
V(Template, TemplateInfo) \
V(FunctionTemplate, FunctionTemplateInfo) \
V(ObjectTemplate, ObjectTemplateInfo) \
V(Signature, FunctionTemplateInfo) \
V(Data, Object) \
V(RegExp, JSRegExp) \
V(Object, JSReceiver) \
V(Array, JSArray) \
V(Map, JSMap) \
V(Set, JSSet) \
V(ArrayBuffer, JSArrayBuffer) \
V(ArrayBufferView, JSArrayBufferView) \
V(TypedArray, JSTypedArray) \
V(Uint8Array, JSTypedArray) \
V(Uint8ClampedArray, JSTypedArray) \
V(Int8Array, JSTypedArray) \
V(Uint16Array, JSTypedArray) \
V(Int16Array, JSTypedArray) \
V(Uint32Array, JSTypedArray) \
V(Int32Array, JSTypedArray) \
V(Float32Array, JSTypedArray) \
V(Float64Array, JSTypedArray) \
V(DataView, JSDataViewOrRabGsabDataView) \
V(SharedArrayBuffer, JSArrayBuffer) \
V(Name, Name) \
V(String, String) \
V(Symbol, Symbol) \
V(Script, JSFunction) \
V(UnboundModuleScript, SharedFunctionInfo) \
V(UnboundScript, SharedFunctionInfo) \
V(Module, Module) \
V(Function, JSReceiver) \
V(Message, JSMessageObject) \
V(Context, NativeContext) \
V(External, Object) \
V(StackTrace, FixedArray) \
V(StackFrame, StackFrameInfo) \
V(Proxy, JSProxy) \
V(debug::GeneratorObject, JSGeneratorObject) \
V(debug::ScriptSource, HeapObject) \
V(debug::Script, Script) \
V(debug::EphemeronTable, EphemeronHashTable) \
V(debug::AccessorPair, AccessorPair) \
V(Promise, JSPromise) \
V(Primitive, Object) \
V(PrimitiveArray, FixedArray) \
V(BigInt, BigInt) \
V(ScriptOrModule, ScriptOrModule) \
V(FixedArray, FixedArray) \
V(ModuleRequest, ModuleRequest) \
#define OPEN_HANDLE_LIST(V) \
V(Template, TemplateInfo) \
V(FunctionTemplate, FunctionTemplateInfo) \
V(ObjectTemplate, ObjectTemplateInfo) \
V(DictionaryTemplate, DictionaryTemplateInfo) \
V(Signature, FunctionTemplateInfo) \
V(Data, Object) \
V(RegExp, JSRegExp) \
V(Object, JSReceiver) \
V(Array, JSArray) \
V(Map, JSMap) \
V(Set, JSSet) \
V(ArrayBuffer, JSArrayBuffer) \
V(ArrayBufferView, JSArrayBufferView) \
V(TypedArray, JSTypedArray) \
V(Uint8Array, JSTypedArray) \
V(Uint8ClampedArray, JSTypedArray) \
V(Int8Array, JSTypedArray) \
V(Uint16Array, JSTypedArray) \
V(Int16Array, JSTypedArray) \
V(Uint32Array, JSTypedArray) \
V(Int32Array, JSTypedArray) \
V(Float32Array, JSTypedArray) \
V(Float64Array, JSTypedArray) \
V(DataView, JSDataViewOrRabGsabDataView) \
V(SharedArrayBuffer, JSArrayBuffer) \
V(Name, Name) \
V(String, String) \
V(Symbol, Symbol) \
V(Script, JSFunction) \
V(UnboundModuleScript, SharedFunctionInfo) \
V(UnboundScript, SharedFunctionInfo) \
V(Module, Module) \
V(Function, JSReceiver) \
V(Message, JSMessageObject) \
V(Context, NativeContext) \
V(External, Object) \
V(StackTrace, FixedArray) \
V(StackFrame, StackFrameInfo) \
V(Proxy, JSProxy) \
V(debug::GeneratorObject, JSGeneratorObject) \
V(debug::ScriptSource, HeapObject) \
V(debug::Script, Script) \
V(debug::EphemeronTable, EphemeronHashTable) \
V(debug::AccessorPair, AccessorPair) \
V(Promise, JSPromise) \
V(Primitive, Object) \
V(PrimitiveArray, FixedArray) \
V(BigInt, BigInt) \
V(ScriptOrModule, ScriptOrModule) \
V(FixedArray, FixedArray) \
V(ModuleRequest, ModuleRequest) \
IF_WASM(V, WasmMemoryObject, WasmMemoryObject)
class Utils {

View File

@ -46,6 +46,7 @@ struct SourceRange {
V(BinaryOperation) \
V(Block) \
V(CaseClause) \
V(ConditionalChain) \
V(Conditional) \
V(Expression) \
V(FunctionLiteral) \
@ -142,6 +143,39 @@ class CaseClauseSourceRanges final : public AstNodeSourceRanges {
SourceRange body_range_;
};
class ConditionalChainSourceRanges final : public AstNodeSourceRanges {
public:
explicit ConditionalChainSourceRanges(Zone* zone)
: then_ranges_(zone), else_ranges_(zone) {}
SourceRange GetRangeAtIndex(SourceRangeKind kind, size_t index) {
if (kind == SourceRangeKind::kThen) {
DCHECK_LT(index, then_ranges_.size());
return then_ranges_[index];
}
DCHECK_EQ(kind, SourceRangeKind::kElse);
DCHECK_LT(index, else_ranges_.size());
return else_ranges_[index];
}
void AddThenRanges(const SourceRange& range) {
then_ranges_.push_back(range);
}
void AddElseRange(const SourceRange& else_range) {
else_ranges_.push_back(else_range);
}
size_t RangeCount() const { return then_ranges_.size(); }
SourceRange GetRange(SourceRangeKind kind) override { UNREACHABLE(); }
bool HasRange(SourceRangeKind kind) override { return false; }
private:
ZoneVector<SourceRange> then_ranges_;
ZoneVector<SourceRange> else_ranges_;
};
class ConditionalSourceRanges final : public AstNodeSourceRanges {
public:
explicit ConditionalSourceRanges(const SourceRange& then_range,

View File

@ -295,6 +295,17 @@ void AstTraversalVisitor<Subclass>::VisitNativeFunctionLiteral(
PROCESS_EXPRESSION(expr);
}
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitConditionalChain(
ConditionalChain* expr) {
PROCESS_EXPRESSION(expr);
for (size_t i = 0; i < expr->conditional_chain_length(); ++i) {
RECURSE_EXPRESSION(Visit(expr->condition_at(i)));
RECURSE_EXPRESSION(Visit(expr->then_expression_at(i)));
}
RECURSE(Visit(expr->else_expression()));
}
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitConditional(Conditional* expr) {
PROCESS_EXPRESSION(expr);
@ -561,8 +572,8 @@ void AstTraversalVisitor<Subclass>::VisitImportCallExpression(
ImportCallExpression* expr) {
PROCESS_EXPRESSION(expr);
RECURSE_EXPRESSION(Visit(expr->specifier()));
if (expr->import_assertions()) {
RECURSE_EXPRESSION(Visit(expr->import_assertions()));
if (expr->import_options()) {
RECURSE_EXPRESSION(Visit(expr->import_options()));
}
}

View File

@ -60,7 +60,7 @@ class OneByteStringStream {
template <typename IsolateT>
void AstRawString::Internalize(IsolateT* isolate) {
DCHECK(!has_string_);
if (literal_bytes_.length() == 0) {
if (literal_bytes_.empty()) {
set_string(isolate->factory()->empty_string());
} else if (is_one_byte()) {
OneByteStringKey key(raw_hash_field_, literal_bytes_);

View File

@ -847,8 +847,8 @@ template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT)
static bool IsCommutativeOperationWithSmiLiteral(Token::Value op) {
// Add is not commutative due to potential for string addition.
return op == Token::MUL || op == Token::BIT_AND || op == Token::BIT_OR ||
op == Token::BIT_XOR;
return op == Token::kMul || op == Token::kBitAnd || op == Token::kBitOr ||
op == Token::kBitXor;
}
// Check for the pattern: x + 1.
@ -869,32 +869,9 @@ bool BinaryOperation::IsSmiLiteralOperation(Expression** subexpr,
MatchSmiLiteralOperation(right_, left_, subexpr, literal));
}
static bool IsTypeof(Expression* expr) {
UnaryOperation* maybe_unary = expr->AsUnaryOperation();
return maybe_unary != nullptr && maybe_unary->op() == Token::TYPEOF;
}
// Check for the pattern: typeof <expression> equals <string literal>.
static bool MatchLiteralCompareTypeof(Expression* left, Token::Value op,
Expression* right, Expression** expr,
Literal** literal) {
if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
*expr = left->AsUnaryOperation()->expression();
*literal = right->AsLiteral();
return true;
}
return false;
}
bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
Literal** literal) {
return MatchLiteralCompareTypeof(left_, op(), right_, expr, literal) ||
MatchLiteralCompareTypeof(right_, op(), left_, expr, literal);
}
static bool IsVoidOfLiteral(Expression* expr) {
UnaryOperation* maybe_unary = expr->AsUnaryOperation();
return maybe_unary != nullptr && maybe_unary->op() == Token::VOID &&
return maybe_unary != nullptr && maybe_unary->op() == Token::kVoid &&
maybe_unary->expression()->IsLiteral();
}
@ -902,7 +879,7 @@ static bool MatchLiteralStrictCompareBoolean(Expression* left, Token::Value op,
Expression* right,
Expression** expr,
Literal** literal) {
if (left->IsBooleanLiteral() && op == Token::EQ_STRICT) {
if (left->IsBooleanLiteral() && op == Token::kEqStrict) {
*expr = right;
*literal = left->AsLiteral();
return true;

97
deps/v8/src/ast/ast.h vendored
View File

@ -91,6 +91,7 @@ namespace internal {
V(ClassLiteral) \
V(CompareOperation) \
V(CompoundAssignment) \
V(ConditionalChain) \
V(Conditional) \
V(CountOperation) \
V(EmptyParentheses) \
@ -1938,7 +1939,7 @@ class NaryOperation final : public Expression {
subsequent_(zone) {
bit_field_ |= OperatorField::encode(op);
DCHECK(Token::IsBinaryOp(op));
DCHECK_NE(op, Token::EXP);
DCHECK_NE(op, Token::kExp);
subsequent_.reserve(initial_subsequent_size);
}
@ -2002,7 +2003,6 @@ class CompareOperation final : public Expression {
Expression* right() const { return right_; }
// Match special cases.
bool IsLiteralCompareTypeof(Expression** expr, Literal** literal);
bool IsLiteralStrictCompareBoolean(Expression** expr, Literal** literal);
bool IsLiteralCompareUndefined(Expression** expr);
bool IsLiteralCompareNull(Expression** expr);
@ -2045,6 +2045,77 @@ class Spread final : public Expression {
Expression* expression_;
};
class ConditionalChain : public Expression {
public:
Expression* condition_at(size_t index) const {
return conditional_chain_entries_[index].condition;
}
Expression* then_expression_at(size_t index) const {
return conditional_chain_entries_[index].then_expression;
}
int condition_position_at(size_t index) const {
return conditional_chain_entries_[index].condition_position;
}
size_t conditional_chain_length() const {
return conditional_chain_entries_.size();
}
Expression* else_expression() const { return else_expression_; }
void set_else_expression(Expression* s) { else_expression_ = s; }
void AddChainEntry(Expression* cond, Expression* then, int pos) {
conditional_chain_entries_.emplace_back(cond, then, pos);
}
private:
friend class AstNodeFactory;
friend Zone;
ConditionalChain(Zone* zone, size_t initial_size, int pos)
: Expression(pos, kConditionalChain),
conditional_chain_entries_(zone),
else_expression_(nullptr) {
conditional_chain_entries_.reserve(initial_size);
}
// Conditional Chain Expression stores the conditional chain entries out of
// line, along with their operation's position. The else expression is stored
// inline. This Expression is reserved for ternary operations that have more
// than one conditional chain entry. For ternary operations with only one
// conditional chain entry, the Conditional Expression is used instead.
//
// So an conditional chain:
//
// cond ? then : cond ? then : cond ? then : else
//
// is stored as:
//
// [(cond, then), (cond, then),...] else
// '-----------------------------' '----'
// conditional chain entries else
//
// Example:
//
// Expression: v1 == 1 ? "a" : v2 == 2 ? "b" : "c"
//
// conditionat_chain_entries_: [(v1 == 1, "a", 0), (v2 == 2, "b", 14)]
// else_expression_: "c"
//
// Example of a _not_ expected expression (only one chain entry):
//
// Expression: v1 == 1 ? "a" : "b"
//
struct ConditionalChainEntry {
Expression* condition;
Expression* then_expression;
int condition_position;
ConditionalChainEntry(Expression* cond, Expression* then, int pos)
: condition(cond), then_expression(then), condition_position(pos) {}
};
ZoneVector<ConditionalChainEntry> conditional_chain_entries_;
Expression* else_expression_;
};
class Conditional final : public Expression {
public:
Expression* condition() const { return condition_; }
@ -2666,7 +2737,7 @@ class SuperCallReference final : public Expression {
class ImportCallExpression final : public Expression {
public:
Expression* specifier() const { return specifier_; }
Expression* import_assertions() const { return import_assertions_; }
Expression* import_options() const { return import_options_; }
private:
friend class AstNodeFactory;
@ -2675,16 +2746,16 @@ class ImportCallExpression final : public Expression {
ImportCallExpression(Expression* specifier, int pos)
: Expression(pos, kImportCallExpression),
specifier_(specifier),
import_assertions_(nullptr) {}
import_options_(nullptr) {}
ImportCallExpression(Expression* specifier, Expression* import_assertions,
ImportCallExpression(Expression* specifier, Expression* import_options,
int pos)
: Expression(pos, kImportCallExpression),
specifier_(specifier),
import_assertions_(import_assertions) {}
import_options_(import_options) {}
Expression* specifier_;
Expression* import_assertions_;
Expression* import_options_;
};
// This class is produced when parsing the () in arrow functions without any
@ -3216,6 +3287,10 @@ class AstNodeFactory final {
return zone_->New<Spread>(expression, pos, expr_pos);
}
ConditionalChain* NewConditionalChain(size_t initial_size, int pos) {
return zone_->New<ConditionalChain>(zone_, initial_size, pos);
}
Conditional* NewConditional(Expression* condition,
Expression* then_expression,
Expression* else_expression,
@ -3232,11 +3307,11 @@ class AstNodeFactory final {
DCHECK_NOT_NULL(target);
DCHECK_NOT_NULL(value);
if (op != Token::INIT && target->IsVariableProxy()) {
if (op != Token::kInit && target->IsVariableProxy()) {
target->AsVariableProxy()->set_is_assigned();
}
if (op == Token::ASSIGN || op == Token::INIT) {
if (op == Token::kAssign || op == Token::kInit) {
return zone_->New<Assignment>(AstNode::kAssignment, op, target, value,
pos);
} else {
@ -3371,9 +3446,9 @@ class AstNodeFactory final {
}
ImportCallExpression* NewImportCallExpression(Expression* specifier,
Expression* import_assertions,
Expression* import_options,
int pos) {
return zone_->New<ImportCallExpression>(specifier, import_assertions, pos);
return zone_->New<ImportCallExpression>(specifier, import_options, pos);
}
InitializeClassMembersStatement* NewInitializeClassMembersStatement(

View File

@ -27,10 +27,10 @@ bool SourceTextModuleDescriptor::ModuleRequestComparer::operator()(
return specifier_comparison < 0;
}
auto lhsIt = lhs->import_assertions()->cbegin();
auto rhsIt = rhs->import_assertions()->cbegin();
for (; lhsIt != lhs->import_assertions()->cend() &&
rhsIt != rhs->import_assertions()->cend();
auto lhsIt = lhs->import_attributes()->cbegin();
auto rhsIt = rhs->import_attributes()->cbegin();
for (; lhsIt != lhs->import_attributes()->cend() &&
rhsIt != rhs->import_attributes()->cend();
++lhsIt, ++rhsIt) {
if (int assertion_key_comparison =
AstRawString::Compare(lhsIt->first, rhsIt->first)) {
@ -43,9 +43,9 @@ bool SourceTextModuleDescriptor::ModuleRequestComparer::operator()(
}
}
if (lhs->import_assertions()->size() != rhs->import_assertions()->size()) {
return (lhs->import_assertions()->size() <
rhs->import_assertions()->size());
if (lhs->import_attributes()->size() != rhs->import_attributes()->size()) {
return (lhs->import_attributes()->size() <
rhs->import_attributes()->size());
}
return false;
@ -54,32 +54,32 @@ bool SourceTextModuleDescriptor::ModuleRequestComparer::operator()(
void SourceTextModuleDescriptor::AddImport(
const AstRawString* import_name, const AstRawString* local_name,
const AstRawString* module_request,
const ImportAssertions* import_assertions, const Scanner::Location loc,
const ImportAttributes* import_attributes, const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone) {
Entry* entry = zone->New<Entry>(loc);
entry->local_name = local_name;
entry->import_name = import_name;
entry->module_request =
AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
AddModuleRequest(module_request, import_attributes, specifier_loc, zone);
AddRegularImport(entry);
}
void SourceTextModuleDescriptor::AddStarImport(
const AstRawString* local_name, const AstRawString* module_request,
const ImportAssertions* import_assertions, const Scanner::Location loc,
const ImportAttributes* import_attributes, const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone) {
Entry* entry = zone->New<Entry>(loc);
entry->local_name = local_name;
entry->module_request =
AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
AddModuleRequest(module_request, import_attributes, specifier_loc, zone);
AddNamespaceImport(entry, zone);
}
void SourceTextModuleDescriptor::AddEmptyImport(
const AstRawString* module_request,
const ImportAssertions* import_assertions,
const ImportAttributes* import_attributes,
const Scanner::Location specifier_loc, Zone* zone) {
AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
AddModuleRequest(module_request, import_attributes, specifier_loc, zone);
}
void SourceTextModuleDescriptor::AddExport(const AstRawString* local_name,
@ -94,7 +94,7 @@ void SourceTextModuleDescriptor::AddExport(const AstRawString* local_name,
void SourceTextModuleDescriptor::AddExport(
const AstRawString* import_name, const AstRawString* export_name,
const AstRawString* module_request,
const ImportAssertions* import_assertions, const Scanner::Location loc,
const ImportAttributes* import_attributes, const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone) {
DCHECK_NOT_NULL(import_name);
DCHECK_NOT_NULL(export_name);
@ -102,17 +102,17 @@ void SourceTextModuleDescriptor::AddExport(
entry->export_name = export_name;
entry->import_name = import_name;
entry->module_request =
AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
AddModuleRequest(module_request, import_attributes, specifier_loc, zone);
AddSpecialExport(entry, zone);
}
void SourceTextModuleDescriptor::AddStarExport(
const AstRawString* module_request,
const ImportAssertions* import_assertions, const Scanner::Location loc,
const ImportAttributes* import_attributes, const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone) {
Entry* entry = zone->New<Entry>(loc);
entry->module_request =
AddModuleRequest(module_request, import_assertions, specifier_loc, zone);
AddModuleRequest(module_request, import_attributes, specifier_loc, zone);
AddSpecialExport(entry, zone);
}
@ -128,28 +128,28 @@ Handle<PrimitiveHeapObject> ToStringOrUndefined(IsolateT* isolate,
template <typename IsolateT>
Handle<ModuleRequest> SourceTextModuleDescriptor::AstModuleRequest::Serialize(
IsolateT* isolate) const {
// The import assertions will be stored in this array in the form:
// The import attributes will be stored in this array in the form:
// [key1, value1, location1, key2, value2, location2, ...]
Handle<FixedArray> import_assertions_array =
Handle<FixedArray> import_attributes_array =
isolate->factory()->NewFixedArray(
static_cast<int>(import_assertions()->size() *
ModuleRequest::kAssertionEntrySize),
static_cast<int>(import_attributes()->size() *
ModuleRequest::kAttributeEntrySize),
AllocationType::kOld);
{
DisallowGarbageCollection no_gc;
Tagged<FixedArray> raw_import_assertions = *import_assertions_array;
Tagged<FixedArray> raw_import_attributes = *import_attributes_array;
int i = 0;
for (auto iter = import_assertions()->cbegin();
iter != import_assertions()->cend();
++iter, i += ModuleRequest::kAssertionEntrySize) {
raw_import_assertions->set(i, *iter->first->string());
raw_import_assertions->set(i + 1, *iter->second.first->string());
raw_import_assertions->set(i + 2,
for (auto iter = import_attributes()->cbegin();
iter != import_attributes()->cend();
++iter, i += ModuleRequest::kAttributeEntrySize) {
raw_import_attributes->set(i, *iter->first->string());
raw_import_attributes->set(i + 1, *iter->second.first->string());
raw_import_attributes->set(i + 2,
Smi::FromInt(iter->second.second.beg_pos));
}
}
return v8::internal::ModuleRequest::New(isolate, specifier()->string(),
import_assertions_array, position());
import_attributes_array, position());
}
template Handle<ModuleRequest>
SourceTextModuleDescriptor::AstModuleRequest::Serialize(Isolate* isolate) const;

View File

@ -38,14 +38,14 @@ class SourceTextModuleDescriptor : public ZoneObject {
void AddImport(const AstRawString* import_name,
const AstRawString* local_name,
const AstRawString* module_request,
const ImportAssertions* import_assertions,
const ImportAttributes* import_attributes,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
// import * as x from "foo.js";
void AddStarImport(const AstRawString* local_name,
const AstRawString* module_request,
const ImportAssertions* import_assertions,
const ImportAttributes* import_attributes,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
@ -53,7 +53,7 @@ class SourceTextModuleDescriptor : public ZoneObject {
// import {} from "foo.js";
// export {} from "foo.js"; (sic!)
void AddEmptyImport(const AstRawString* module_request,
const ImportAssertions* import_assertions,
const ImportAttributes* import_attributes,
const Scanner::Location specifier_loc, Zone* zone);
// export {x};
@ -70,13 +70,13 @@ class SourceTextModuleDescriptor : public ZoneObject {
void AddExport(const AstRawString* export_name,
const AstRawString* import_name,
const AstRawString* module_request,
const ImportAssertions* import_assertions,
const ImportAttributes* import_attributes,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
// export * from "foo.js";
void AddStarExport(const AstRawString* module_request,
const ImportAssertions* import_assertions,
const ImportAttributes* import_attributes,
const Scanner::Location loc,
const Scanner::Location specifier_loc, Zone* zone);
@ -125,10 +125,10 @@ class SourceTextModuleDescriptor : public ZoneObject {
class AstModuleRequest : public ZoneObject {
public:
AstModuleRequest(const AstRawString* specifier,
const ImportAssertions* import_assertions, int position,
const ImportAttributes* import_attributes, int position,
int index)
: specifier_(specifier),
import_assertions_(import_assertions),
import_attributes_(import_attributes),
position_(position),
index_(index) {}
@ -136,8 +136,8 @@ class SourceTextModuleDescriptor : public ZoneObject {
Handle<v8::internal::ModuleRequest> Serialize(IsolateT* isolate) const;
const AstRawString* specifier() const { return specifier_; }
const ImportAssertions* import_assertions() const {
return import_assertions_;
const ImportAttributes* import_attributes() const {
return import_attributes_;
}
int position() const { return position_; }
@ -145,7 +145,7 @@ class SourceTextModuleDescriptor : public ZoneObject {
private:
const AstRawString* specifier_;
const ImportAssertions* import_assertions_;
const ImportAttributes* import_attributes_;
// The JS source code position of the request, used for reporting errors.
int position_;
@ -264,13 +264,13 @@ class SourceTextModuleDescriptor : public ZoneObject {
void AssignCellIndices();
int AddModuleRequest(const AstRawString* specifier,
const ImportAssertions* import_assertions,
const ImportAttributes* import_attributes,
Scanner::Location specifier_loc, Zone* zone) {
DCHECK_NOT_NULL(specifier);
int module_requests_count = static_cast<int>(module_requests_.size());
auto it = module_requests_
.insert(zone->New<AstModuleRequest>(
specifier, import_assertions, specifier_loc.beg_pos,
specifier, import_attributes, specifier_loc.beg_pos,
module_requests_count))
.first;
return (*it)->index();

View File

@ -256,6 +256,13 @@ void CallPrinter::VisitInitializeClassStaticElementsStatement(
void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {}
void CallPrinter::VisitConditionalChain(ConditionalChain* node) {
for (size_t i = 0; i < node->conditional_chain_length(); ++i) {
Find(node->condition_at(i));
Find(node->then_expression_at(i));
}
Find(node->else_expression());
}
void CallPrinter::VisitConditional(Conditional* node) {
Find(node->condition());
@ -500,7 +507,7 @@ void CallPrinter::VisitSuperCallForwardArgs(SuperCallForwardArgs* node) {
void CallPrinter::VisitUnaryOperation(UnaryOperation* node) {
Token::Value op = node->op();
bool needsSpace =
op == Token::DELETE || op == Token::TYPEOF || op == Token::VOID;
op == Token::kDelete || op == Token::kTypeOf || op == Token::kVoid;
Print("(");
Print(Token::String(op));
if (needsSpace) Print(" ");
@ -572,8 +579,8 @@ void CallPrinter::VisitTemplateLiteral(TemplateLiteral* node) {
void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) {
Print("ImportCall(");
Find(node->specifier(), true);
if (node->import_assertions()) {
Find(node->import_assertions(), true);
if (node->import_options()) {
Find(node->import_options(), true);
}
Print(")");
}
@ -1176,6 +1183,17 @@ void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {
PrintLiteralIndented("NAME", node->raw_name(), false);
}
void AstPrinter::VisitConditionalChain(ConditionalChain* node) {
IndentedScope indent(this, "CONDITIONAL_CHAIN", node->position());
PrintIndentedVisit("CONDITION", node->condition_at(0));
PrintIndentedVisit("THEN", node->then_expression_at(0));
for (size_t i = 1; i < node->conditional_chain_length(); ++i) {
IndentedScope indent(this, "ELSE IF", node->condition_position_at(i));
PrintIndentedVisit("CONDITION", node->condition_at(i));
PrintIndentedVisit("THEN", node->then_expression_at(i));
}
PrintIndentedVisit("ELSE", node->else_expression());
}
void AstPrinter::VisitConditional(Conditional* node) {
IndentedScope indent(this, "CONDITIONAL", node->position());
@ -1471,8 +1489,8 @@ void AstPrinter::VisitTemplateLiteral(TemplateLiteral* node) {
void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) {
IndentedScope indent(this, "IMPORT-CALL", node->position());
Visit(node->specifier());
if (node->import_assertions()) {
Visit(node->import_assertions());
if (node->import_options()) {
Visit(node->import_options());
}
}

View File

@ -679,7 +679,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
DCHECK(is_being_lazily_parsed_);
bool was_added;
Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added);
if (sloppy_block_function->init() == Token::ASSIGN) {
if (sloppy_block_function->init() == Token::kAssign) {
var->SetMaybeAssigned();
}
}
@ -1077,14 +1077,15 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
DCHECK(!already_resolved_);
// Private methods should be declared with ClassScope::DeclarePrivateName()
DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode));
// This function handles VariableMode::kVar, VariableMode::kLet, and
// VariableMode::kConst modes. VariableMode::kDynamic variables are
// introduced during variable allocation, and VariableMode::kTemporary
// variables are allocated via NewTemporary().
// This function handles VariableMode::kVar, VariableMode::kLet,
// VariableMode::kConst, and VariableMode::kUsing modes.
// VariableMode::kDynamic variables are introduced during variable allocation,
// and VariableMode::kTemporary variables are allocated via NewTemporary().
DCHECK(IsDeclaredVariableMode(mode));
DCHECK_IMPLIES(GetDeclarationScope()->is_being_lazily_parsed(),
mode == VariableMode::kVar || mode == VariableMode::kLet ||
mode == VariableMode::kConst);
mode == VariableMode::kConst ||
mode == VariableMode::kUsing);
DCHECK(!GetDeclarationScope()->was_lazily_parsed());
Variable* var =
Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added);

View File

@ -486,6 +486,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
switch (scope_type_) {
case MODULE_SCOPE:
case WITH_SCOPE: // DebugEvaluateContext as well
case SCRIPT_SCOPE: // Side data for const tracking let.
return true;
default:
DCHECK_IMPLIES(sloppy_eval_can_extend_vars_,

View File

@ -25,6 +25,20 @@ inline constexpr bool IsInRange(T value, U lower_limit, U higher_limit) {
static_cast<unsigned_T>(lower_limit));
}
// Like IsInRange but for the half-open range [lower_limit, higher_limit).
template <typename T, typename U>
inline constexpr bool IsInHalfOpenRange(T value, U lower_limit,
U higher_limit) {
DCHECK_LE(lower_limit, higher_limit);
static_assert(sizeof(U) <= sizeof(T));
using unsigned_T = typename std::make_unsigned<T>::type;
// Use static_cast to support enum classes.
return static_cast<unsigned_T>(static_cast<unsigned_T>(value) -
static_cast<unsigned_T>(lower_limit)) <
static_cast<unsigned_T>(static_cast<unsigned_T>(higher_limit) -
static_cast<unsigned_T>(lower_limit));
}
// Checks if [index, index+length) is in range [0, max). Note that this check
// works even if {index+length} would wrap around.
template <typename T,

View File

@ -368,9 +368,9 @@ bool is_inbounds(float_t v) {
// Setup for Windows shared library export.
#define V8_EXPORT_ENUM
#ifdef BUILDING_V8_SHARED_PRIVATE
#define V8_EXPORT_PRIVATE
#define V8_EXPORT_PRIVATE __declspec(dllexport)
#elif USING_V8_SHARED_PRIVATE
#define V8_EXPORT_PRIVATE
#define V8_EXPORT_PRIVATE __declspec(dllimport)
#else
#define V8_EXPORT_PRIVATE
#endif // BUILDING_V8_SHARED
@ -380,8 +380,8 @@ bool is_inbounds(float_t v) {
// Setup for Linux shared library export.
#if V8_HAS_ATTRIBUTE_VISIBILITY
#ifdef BUILDING_V8_SHARED_PRIVATE
#define V8_EXPORT_PRIVATE
#define V8_EXPORT_ENUM
#define V8_EXPORT_PRIVATE __attribute__((visibility("default")))
#define V8_EXPORT_ENUM V8_EXPORT_PRIVATE
#else
#define V8_EXPORT_PRIVATE
#define V8_EXPORT_ENUM

View File

@ -9,872 +9,19 @@
#ifndef V8_BASE_OPTIONAL_H_
#define V8_BASE_OPTIONAL_H_
#include <type_traits>
#include <utility>
#include "src/base/logging.h"
#include <optional>
namespace v8 {
namespace base {
// Specification:
// http://en.cppreference.com/w/cpp/utility/optional/in_place_t
struct in_place_t {};
// Specification:
// http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
struct nullopt_t {
constexpr explicit nullopt_t(int) {}
};
// Specification:
// http://en.cppreference.com/w/cpp/utility/optional/in_place
constexpr in_place_t in_place = {};
// Specification:
// http://en.cppreference.com/w/cpp/utility/optional/nullopt
constexpr nullopt_t nullopt(0);
// Forward declaration, which is referred by following helpers.
// These aliases are deprecated, use std::optional directly.
template <typename T>
class Optional;
using Optional [[deprecated]] = std::optional<T>;
namespace internal {
template <typename T, bool = std::is_trivially_destructible<T>::value>
struct OptionalStorageBase {
// Initializing |empty_| here instead of using default member initializing
// to avoid errors in g++ 4.8.
constexpr OptionalStorageBase() : empty_('\0') {}
template <class... Args>
constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
: is_populated_(true), value_(std::forward<Args>(args)...) {}
// When T is not trivially destructible we must call its
// destructor before deallocating its memory.
// Note that this hides the (implicitly declared) move constructor, which
// would be used for constexpr move constructor in OptionalStorage<T>.
// It is needed iff T is trivially move constructible. However, the current
// is_trivially_{copy,move}_constructible implementation requires
// is_trivially_destructible (which looks a bug, cf:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 and
// http://cplusplus.github.io/LWG/lwg-active.html#2116), so it is not
// necessary for this case at the moment. Please see also the destructor
// comment in "is_trivially_destructible = true" specialization below.
~OptionalStorageBase() {
if (is_populated_) value_.~T();
}
template <class... Args>
void Init(Args&&... args) {
DCHECK(!is_populated_);
::new (&value_) T(std::forward<Args>(args)...);
is_populated_ = true;
}
bool is_populated_ = false;
union {
// |empty_| exists so that the union will always be initialized, even when
// it doesn't contain a value. Union members must be initialized for the
// constructor to be 'constexpr'.
char empty_;
T value_;
};
};
template <typename T>
struct OptionalStorageBase<T, true /* trivially destructible */> {
// Initializing |empty_| here instead of using default member initializing
// to avoid errors in g++ 4.8.
constexpr OptionalStorageBase() : empty_('\0') {}
template <class... Args>
constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
: is_populated_(true), value_(std::forward<Args>(args)...) {}
// When T is trivially destructible (i.e. its destructor does nothing) there
// is no need to call it. Implicitly defined destructor is trivial, because
// both members (bool and union containing only variants which are trivially
// destructible) are trivially destructible.
// Explicitly-defaulted destructor is also trivial, but do not use it here,
// because it hides the implicit move constructor. It is needed to implement
// constexpr move constructor in OptionalStorage iff T is trivially move
// constructible. Note that, if T is trivially move constructible, the move
// constructor of OptionalStorageBase<T> is also implicitly defined and it is
// trivially move constructor. If T is not trivially move constructible,
// "not declaring move constructor without destructor declaration" here means
// "delete move constructor", which works because any move constructor of
// OptionalStorage will not refer to it in that case.
template <class... Args>
void Init(Args&&... args) {
DCHECK(!is_populated_);
::new (&value_) T(std::forward<Args>(args)...);
is_populated_ = true;
}
bool is_populated_ = false;
union {
// |empty_| exists so that the union will always be initialized, even when
// it doesn't contain a value. Union members must be initialized for the
// constructor to be 'constexpr'.
char empty_;
T value_;
};
};
// Implement conditional constexpr copy and move constructors. These are
// constexpr if is_trivially_{copy,move}_constructible<T>::value is true
// respectively. If each is true, the corresponding constructor is defined as
// "= default;", which generates a constexpr constructor (In this case,
// the condition of constexpr-ness is satisfied because the base class also has
// compiler generated constexpr {copy,move} constructors). Note that
// placement-new is prohibited in constexpr.
template <typename T, bool = std::is_trivially_copy_constructible<T>::value,
bool = std::is_trivially_move_constructible<T>::value>
struct OptionalStorage : OptionalStorageBase<T> {
// This is no trivially {copy,move} constructible case. Other cases are
// defined below as specializations.
// Accessing the members of template base class requires explicit
// declaration.
using OptionalStorageBase<T>::is_populated_;
using OptionalStorageBase<T>::value_;
using OptionalStorageBase<T>::Init;
// Inherit constructors (specifically, the in_place constructor).
using OptionalStorageBase<T>::OptionalStorageBase;
// User defined constructor deletes the default constructor.
// Define it explicitly.
OptionalStorage() = default;
OptionalStorage(const OptionalStorage& other) V8_NOEXCEPT {
if (other.is_populated_) Init(other.value_);
}
OptionalStorage(OptionalStorage&& other) V8_NOEXCEPT {
if (other.is_populated_) Init(std::move(other.value_));
}
};
template <typename T>
struct OptionalStorage<T, true /* trivially copy constructible */,
false /* trivially move constructible */>
: OptionalStorageBase<T> {
using OptionalStorageBase<T>::is_populated_;
using OptionalStorageBase<T>::value_;
using OptionalStorageBase<T>::Init;
using OptionalStorageBase<T>::OptionalStorageBase;
OptionalStorage() = default;
OptionalStorage(const OptionalStorage& other) V8_NOEXCEPT = default;
OptionalStorage(OptionalStorage&& other) V8_NOEXCEPT {
if (other.is_populated_) Init(std::move(other.value_));
}
};
template <typename T>
struct OptionalStorage<T, false /* trivially copy constructible */,
true /* trivially move constructible */>
: OptionalStorageBase<T> {
using OptionalStorageBase<T>::is_populated_;
using OptionalStorageBase<T>::value_;
using OptionalStorageBase<T>::Init;
using OptionalStorageBase<T>::OptionalStorageBase;
OptionalStorage() = default;
OptionalStorage(OptionalStorage&& other) V8_NOEXCEPT = default;
OptionalStorage(const OptionalStorage& other) V8_NOEXCEPT {
if (other.is_populated_) Init(other.value_);
}
};
template <typename T>
struct OptionalStorage<T, true /* trivially copy constructible */,
true /* trivially move constructible */>
: OptionalStorageBase<T> {
// If both trivially {copy,move} constructible are true, it is not necessary
// to use user-defined constructors. So, just inheriting constructors
// from the base class works.
using OptionalStorageBase<T>::OptionalStorageBase;
};
// Base class to support conditionally usable copy-/move- constructors
// and assign operators.
template <typename T>
class OptionalBase {
// This class provides implementation rather than public API, so everything
// should be hidden. Often we use composition, but we cannot in this case
// because of C++ language restriction.
protected:
constexpr OptionalBase() = default;
constexpr OptionalBase(const OptionalBase& other) V8_NOEXCEPT = default;
constexpr OptionalBase(OptionalBase&& other) V8_NOEXCEPT = default;
template <class... Args>
constexpr explicit OptionalBase(in_place_t, Args&&... args)
: storage_(in_place, std::forward<Args>(args)...) {}
// Implementation of converting constructors.
template <typename U>
explicit OptionalBase(const OptionalBase<U>& other) V8_NOEXCEPT {
if (other.storage_.is_populated_) storage_.Init(other.storage_.value_);
}
template <typename U>
explicit OptionalBase(OptionalBase<U>&& other) V8_NOEXCEPT {
if (other.storage_.is_populated_)
storage_.Init(std::move(other.storage_.value_));
}
~OptionalBase() = default;
OptionalBase& operator=(const OptionalBase& other) V8_NOEXCEPT {
CopyAssign(other);
return *this;
}
OptionalBase& operator=(OptionalBase&& other) V8_NOEXCEPT {
MoveAssign(std::move(other));
return *this;
}
template <typename U>
void CopyAssign(const OptionalBase<U>& other) {
if (other.storage_.is_populated_)
InitOrAssign(other.storage_.value_);
else
FreeIfNeeded();
}
template <typename U>
void MoveAssign(OptionalBase<U>&& other) {
if (other.storage_.is_populated_)
InitOrAssign(std::move(other.storage_.value_));
else
FreeIfNeeded();
}
template <typename U>
void InitOrAssign(U&& value) {
if (storage_.is_populated_)
storage_.value_ = std::forward<U>(value);
else
storage_.Init(std::forward<U>(value));
}
void FreeIfNeeded() {
if (!storage_.is_populated_) return;
storage_.value_.~T();
storage_.is_populated_ = false;
}
// For implementing conversion, allow access to other typed OptionalBase
// class.
template <typename U>
friend class OptionalBase;
OptionalStorage<T> storage_;
};
// The following {Copy,Move}{Constructible,Assignable} structs are helpers to
// implement constructor/assign-operator overloading. Specifically, if T is
// is not movable but copyable, Optional<T>'s move constructor should not
// participate in overload resolution. This inheritance trick implements that.
template <bool is_copy_constructible>
struct CopyConstructible {};
template <>
struct CopyConstructible<false> {
constexpr CopyConstructible() = default;
constexpr CopyConstructible(const CopyConstructible&) V8_NOEXCEPT = delete;
constexpr CopyConstructible(CopyConstructible&&) V8_NOEXCEPT = default;
CopyConstructible& operator=(const CopyConstructible&) V8_NOEXCEPT = default;
CopyConstructible& operator=(CopyConstructible&&) V8_NOEXCEPT = default;
};
template <bool is_move_constructible>
struct MoveConstructible {};
template <>
struct MoveConstructible<false> {
constexpr MoveConstructible() = default;
constexpr MoveConstructible(const MoveConstructible&) V8_NOEXCEPT = default;
constexpr MoveConstructible(MoveConstructible&&) V8_NOEXCEPT = delete;
MoveConstructible& operator=(const MoveConstructible&) V8_NOEXCEPT = default;
MoveConstructible& operator=(MoveConstructible&&) V8_NOEXCEPT = default;
};
template <bool is_copy_assignable>
struct CopyAssignable {};
template <>
struct CopyAssignable<false> {
constexpr CopyAssignable() = default;
constexpr CopyAssignable(const CopyAssignable&) V8_NOEXCEPT = default;
constexpr CopyAssignable(CopyAssignable&&) V8_NOEXCEPT = default;
CopyAssignable& operator=(const CopyAssignable&) V8_NOEXCEPT = delete;
CopyAssignable& operator=(CopyAssignable&&) V8_NOEXCEPT = default;
};
template <bool is_move_assignable>
struct MoveAssignable {};
template <>
struct MoveAssignable<false> {
constexpr MoveAssignable() = default;
constexpr MoveAssignable(const MoveAssignable&) V8_NOEXCEPT = default;
constexpr MoveAssignable(MoveAssignable&&) V8_NOEXCEPT = default;
MoveAssignable& operator=(const MoveAssignable&) V8_NOEXCEPT = default;
MoveAssignable& operator=(MoveAssignable&&) V8_NOEXCEPT = delete;
};
// Helper to conditionally enable converting constructors and assign operators.
template <typename T, typename U>
struct IsConvertibleFromOptional
: std::integral_constant<
bool, std::is_constructible<T, Optional<U>&>::value ||
std::is_constructible<T, const Optional<U>&>::value ||
std::is_constructible<T, Optional<U>&&>::value ||
std::is_constructible<T, const Optional<U>&&>::value ||
std::is_convertible<Optional<U>&, T>::value ||
std::is_convertible<const Optional<U>&, T>::value ||
std::is_convertible<Optional<U>&&, T>::value ||
std::is_convertible<const Optional<U>&&, T>::value> {};
template <typename T, typename U>
struct IsAssignableFromOptional
: std::integral_constant<
bool, IsConvertibleFromOptional<T, U>::value ||
std::is_assignable<T&, Optional<U>&>::value ||
std::is_assignable<T&, const Optional<U>&>::value ||
std::is_assignable<T&, Optional<U>&&>::value ||
std::is_assignable<T&, const Optional<U>&&>::value> {};
// Forward compatibility for C++17.
// Introduce one more deeper nested namespace to avoid leaking using std::swap.
namespace swappable_impl {
using std::swap;
struct IsSwappableImpl {
// Tests if swap can be called. Check<T&>(0) returns true_type iff swap
// is available for T. Otherwise, Check's overload resolution falls back
// to Check(...) declared below thanks to SFINAE, so returns false_type.
template <typename T>
static auto Check(int i)
-> decltype(swap(std::declval<T>(), std::declval<T>()), std::true_type());
template <typename T>
static std::false_type Check(...);
};
} // namespace swappable_impl
template <typename T>
struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check<T&>(0)) {};
// Forward compatibility for C++20.
template <typename T>
using RemoveCvRefT =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
} // namespace internal
// On Windows, by default, empty-base class optimization does not work,
// which means even if the base class is empty struct, it still consumes one
// byte for its body. __declspec(empty_bases) enables the optimization.
// cf)
// https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/
#ifdef OS_WIN
#define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
#else
#define OPTIONAL_DECLSPEC_EMPTY_BASES
#endif
// base::Optional is a Chromium version of the C++17 optional class:
// std::optional documentation:
// http://en.cppreference.com/w/cpp/utility/optional
// Chromium documentation:
// https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
//
// These are the differences between the specification and the implementation:
// - Constructors do not use 'constexpr' as it is a C++14 extension.
// - 'constexpr' might be missing in some places for reasons specified locally.
// - No exceptions are thrown, because they are banned from Chromium.
// All copy/move constructors or assignment operators are marked V8_NOEXCEPT.
// - All the non-members are in the 'base' namespace instead of 'std'.
//
// Note that T cannot have a constructor T(Optional<T>) etc. Optional<T> checks
// T's constructor (specifically via IsConvertibleFromOptional), and in the
// check whether T can be constructible from Optional<T>, which is recursive
// so it does not work. As of Feb 2018, std::optional C++17 implementation in
// both clang and gcc has same limitation. MSVC SFINAE looks to have different
// behavior, but anyway it reports an error, too.
template <typename T>
class OPTIONAL_DECLSPEC_EMPTY_BASES Optional
: public internal::OptionalBase<T>,
public internal::CopyConstructible<std::is_copy_constructible<T>::value>,
public internal::MoveConstructible<std::is_move_constructible<T>::value>,
public internal::CopyAssignable<std::is_copy_constructible<T>::value &&
std::is_copy_assignable<T>::value>,
public internal::MoveAssignable<std::is_move_constructible<T>::value &&
std::is_move_assignable<T>::value> {
public:
#undef OPTIONAL_DECLSPEC_EMPTY_BASES
using value_type = T;
// Defer default/copy/move constructor implementation to OptionalBase.
constexpr Optional() = default;
constexpr Optional(const Optional& other) V8_NOEXCEPT = default;
constexpr Optional(Optional&& other) V8_NOEXCEPT = default;
constexpr Optional(nullopt_t) {} // NOLINT(runtime/explicit)
// Converting copy constructor. "explicit" only if
// std::is_convertible<const U&, T>::value is false. It is implemented by
// declaring two almost same constructors, but that condition in enable_if
// is different, so that either one is chosen, thanks to SFINAE.
template <typename U,
typename std::enable_if<
std::is_constructible<T, const U&>::value &&
!internal::IsConvertibleFromOptional<T, U>::value &&
std::is_convertible<const U&, T>::value,
bool>::type = false>
Optional(const Optional<U>& other) V8_NOEXCEPT
: internal::OptionalBase<T>(other) {}
template <typename U,
typename std::enable_if<
std::is_constructible<T, const U&>::value &&
!internal::IsConvertibleFromOptional<T, U>::value &&
!std::is_convertible<const U&, T>::value,
bool>::type = false>
explicit Optional(const Optional<U>& other) V8_NOEXCEPT
: internal::OptionalBase<T>(other) {}
// Converting move constructor. Similar to converting copy constructor,
// declaring two (explicit and non-explicit) constructors.
template <typename U,
typename std::enable_if<
std::is_constructible<T, U&&>::value &&
!internal::IsConvertibleFromOptional<T, U>::value &&
std::is_convertible<U&&, T>::value,
bool>::type = false>
Optional(Optional<U>&& other) V8_NOEXCEPT
: internal::OptionalBase<T>(std::move(other)) {}
template <typename U,
typename std::enable_if<
std::is_constructible<T, U&&>::value &&
!internal::IsConvertibleFromOptional<T, U>::value &&
!std::is_convertible<U&&, T>::value,
bool>::type = false>
explicit Optional(Optional<U>&& other) V8_NOEXCEPT
: internal::OptionalBase<T>(std::move(other)) {}
template <class... Args>
constexpr explicit Optional(in_place_t, Args&&... args)
: internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
template <class U, class... Args,
class = typename std::enable_if<std::is_constructible<
value_type, std::initializer_list<U>&, Args...>::value>::type>
constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
Args&&... args)
: internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
// Forward value constructor. Similar to converting constructors,
// conditionally explicit.
template <
typename U = value_type,
typename std::enable_if<
std::is_constructible<T, U&&>::value &&
!std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
!std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
std::is_convertible<U&&, T>::value,
bool>::type = false>
constexpr Optional(U&& value) // NOLINT(runtime/explicit)
: internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
template <
typename U = value_type,
typename std::enable_if<
std::is_constructible<T, U&&>::value &&
!std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
!std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
!std::is_convertible<U&&, T>::value,
bool>::type = false>
constexpr explicit Optional(U&& value)
: internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
~Optional() = default;
// Defer copy-/move- assign operator implementation to OptionalBase.
Optional& operator=(const Optional& other) V8_NOEXCEPT = default;
Optional& operator=(Optional&& other) V8_NOEXCEPT = default;
Optional& operator=(nullopt_t) {
FreeIfNeeded();
return *this;
}
// Perfect-forwarded assignment.
template <typename U>
typename std::enable_if<
!std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
std::is_constructible<T, U>::value &&
std::is_assignable<T&, U>::value &&
(!std::is_scalar<T>::value ||
!std::is_same<typename std::decay<U>::type, T>::value),
Optional&>::type
operator=(U&& value) V8_NOEXCEPT {
InitOrAssign(std::forward<U>(value));
return *this;
}
// Copy assign the state of other.
template <typename U>
typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
std::is_constructible<T, const U&>::value &&
std::is_assignable<T&, const U&>::value,
Optional&>::type
operator=(const Optional<U>& other) V8_NOEXCEPT {
CopyAssign(other);
return *this;
}
// Move assign the state of other.
template <typename U>
typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
std::is_constructible<T, U>::value &&
std::is_assignable<T&, U>::value,
Optional&>::type
operator=(Optional<U>&& other) V8_NOEXCEPT {
MoveAssign(std::move(other));
return *this;
}
constexpr const T* operator->() const {
DCHECK(storage_.is_populated_);
return &storage_.value_;
}
constexpr T* operator->() {
DCHECK(storage_.is_populated_);
return &storage_.value_;
}
constexpr const T& operator*() const& {
DCHECK(storage_.is_populated_);
return storage_.value_;
}
constexpr T& operator*() & {
DCHECK(storage_.is_populated_);
return storage_.value_;
}
constexpr const T&& operator*() const&& {
DCHECK(storage_.is_populated_);
return std::move(storage_.value_);
}
constexpr T&& operator*() && {
DCHECK(storage_.is_populated_);
return std::move(storage_.value_);
}
constexpr explicit operator bool() const { return storage_.is_populated_; }
constexpr bool has_value() const { return storage_.is_populated_; }
T& value() & {
CHECK(storage_.is_populated_);
return storage_.value_;
}
const T& value() const & {
CHECK(storage_.is_populated_);
return storage_.value_;
}
T&& value() && {
CHECK(storage_.is_populated_);
return std::move(storage_.value_);
}
const T&& value() const && {
CHECK(storage_.is_populated_);
return std::move(storage_.value_);
}
template <class U>
constexpr T value_or(U&& default_value) const & {
// TODO(mlamouri): add the following assert when possible:
// static_assert(std::is_copy_constructible<T>::value,
// "T must be copy constructible");
static_assert(std::is_convertible<U, T>::value,
"U must be convertible to T");
return storage_.is_populated_
? storage_.value_
: static_cast<T>(std::forward<U>(default_value));
}
template <class U>
constexpr T value_or(U&& default_value) && {
// TODO(mlamouri): add the following assert when possible:
// static_assert(std::is_move_constructible<T>::value,
// "T must be move constructible");
static_assert(std::is_convertible<U, T>::value,
"U must be convertible to T");
return storage_.is_populated_
? std::move(storage_.value_)
: static_cast<T>(std::forward<U>(default_value));
}
void swap(Optional& other) {
if (!storage_.is_populated_ && !other.storage_.is_populated_) return;
if (storage_.is_populated_ != other.storage_.is_populated_) {
if (storage_.is_populated_) {
other.storage_.Init(std::move(storage_.value_));
FreeIfNeeded();
} else {
storage_.Init(std::move(other.storage_.value_));
other.FreeIfNeeded();
}
return;
}
DCHECK(storage_.is_populated_ && other.storage_.is_populated_);
using std::swap;
swap(**this, *other);
}
void reset() { FreeIfNeeded(); }
template <class... Args>
T& emplace(Args&&... args) {
FreeIfNeeded();
storage_.Init(std::forward<Args>(args)...);
return storage_.value_;
}
template <class U, class... Args>
typename std::enable_if<
std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
T&>::type
emplace(std::initializer_list<U> il, Args&&... args) {
FreeIfNeeded();
storage_.Init(il, std::forward<Args>(args)...);
return storage_.value_;
}
private:
// Accessing template base class's protected member needs explicit
// declaration to do so.
using internal::OptionalBase<T>::CopyAssign;
using internal::OptionalBase<T>::FreeIfNeeded;
using internal::OptionalBase<T>::InitOrAssign;
using internal::OptionalBase<T>::MoveAssign;
using internal::OptionalBase<T>::storage_;
};
// Here after defines comparation operators. The definition follows
// http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
// while bool() casting is replaced by has_value() to meet the chromium
// style guide.
template <class T, class U>
bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
if (lhs.has_value() != rhs.has_value()) return false;
if (!lhs.has_value()) return true;
return *lhs == *rhs;
}
template <class T, class U>
bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
if (lhs.has_value() != rhs.has_value()) return true;
if (!lhs.has_value()) return false;
return *lhs != *rhs;
}
template <class T, class U>
bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
if (!rhs.has_value()) return false;
if (!lhs.has_value()) return true;
return *lhs < *rhs;
}
template <class T, class U>
bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
if (!lhs.has_value()) return true;
if (!rhs.has_value()) return false;
return *lhs <= *rhs;
}
template <class T, class U>
bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
if (!lhs.has_value()) return false;
if (!rhs.has_value()) return true;
return *lhs > *rhs;
}
template <class T, class U>
bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
if (!rhs.has_value()) return true;
if (!lhs.has_value()) return false;
return *lhs >= *rhs;
}
template <class T>
constexpr bool operator==(const Optional<T>& opt, nullopt_t) {
return !opt;
}
template <class T>
constexpr bool operator==(nullopt_t, const Optional<T>& opt) {
return !opt;
}
template <class T>
constexpr bool operator!=(const Optional<T>& opt, nullopt_t) {
return opt.has_value();
}
template <class T>
constexpr bool operator!=(nullopt_t, const Optional<T>& opt) {
return opt.has_value();
}
template <class T>
constexpr bool operator<(const Optional<T>& opt, nullopt_t) {
return false;
}
template <class T>
constexpr bool operator<(nullopt_t, const Optional<T>& opt) {
return opt.has_value();
}
template <class T>
constexpr bool operator<=(const Optional<T>& opt, nullopt_t) {
return !opt;
}
template <class T>
constexpr bool operator<=(nullopt_t, const Optional<T>& opt) {
return true;
}
template <class T>
constexpr bool operator>(const Optional<T>& opt, nullopt_t) {
return opt.has_value();
}
template <class T>
constexpr bool operator>(nullopt_t, const Optional<T>& opt) {
return false;
}
template <class T>
constexpr bool operator>=(const Optional<T>& opt, nullopt_t) {
return true;
}
template <class T>
constexpr bool operator>=(nullopt_t, const Optional<T>& opt) {
return !opt;
}
template <class T, class U>
constexpr bool operator==(const Optional<T>& opt, const U& value) {
return opt.has_value() ? *opt == value : false;
}
template <class T, class U>
constexpr bool operator==(const U& value, const Optional<T>& opt) {
return opt.has_value() ? value == *opt : false;
}
template <class T, class U>
constexpr bool operator!=(const Optional<T>& opt, const U& value) {
return opt.has_value() ? *opt != value : true;
}
template <class T, class U>
constexpr bool operator!=(const U& value, const Optional<T>& opt) {
return opt.has_value() ? value != *opt : true;
}
template <class T, class U>
constexpr bool operator<(const Optional<T>& opt, const U& value) {
return opt.has_value() ? *opt < value : true;
}
template <class T, class U>
constexpr bool operator<(const U& value, const Optional<T>& opt) {
return opt.has_value() ? value < *opt : false;
}
template <class T, class U>
constexpr bool operator<=(const Optional<T>& opt, const U& value) {
return opt.has_value() ? *opt <= value : true;
}
template <class T, class U>
constexpr bool operator<=(const U& value, const Optional<T>& opt) {
return opt.has_value() ? value <= *opt : false;
}
template <class T, class U>
constexpr bool operator>(const Optional<T>& opt, const U& value) {
return opt.has_value() ? *opt > value : false;
}
template <class T, class U>
constexpr bool operator>(const U& value, const Optional<T>& opt) {
return opt.has_value() ? value > *opt : true;
}
template <class T, class U>
constexpr bool operator>=(const Optional<T>& opt, const U& value) {
return opt.has_value() ? *opt >= value : false;
}
template <class T, class U>
constexpr bool operator>=(const U& value, const Optional<T>& opt) {
return opt.has_value() ? value >= *opt : true;
}
template <class T>
constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) {
return Optional<typename std::decay<T>::type>(std::forward<T>(value));
}
template <class T, class... Args>
constexpr Optional<T> make_optional(Args&&... args) {
return Optional<T>(in_place, std::forward<Args>(args)...);
}
template <class T, class U, class... Args>
constexpr Optional<T> make_optional(std::initializer_list<U> il,
Args&&... args) {
return Optional<T>(in_place, il, std::forward<Args>(args)...);
}
// Partial specialization for a function template is not allowed. Also, it is
// not allowed to add overload function to std namespace, while it is allowed
// to specialize the template in std. Thus, swap() (kind of) overloading is
// defined in base namespace, instead.
template <class T>
typename std::enable_if<std::is_move_constructible<T>::value &&
internal::IsSwappable<T>::value>::type
swap(Optional<T>& lhs, Optional<T>& rhs) {
lhs.swap(rhs);
}
using std::in_place;
using std::make_optional;
using std::nullopt;
using std::nullopt_t;
} // namespace base
} // namespace v8

View File

@ -190,7 +190,7 @@ void ConditionVariable::Wait(Mutex* mutex) {
}
bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
SbTime microseconds = static_cast<SbTime>(rel_time.InMicroseconds());
int64_t microseconds = static_cast<int64_t>(rel_time.InMicroseconds());
SbConditionVariableResult result = SbConditionVariableWaitTimed(
&native_handle_, &mutex->native_handle(), microseconds);
DCHECK(result != kSbConditionVariableFailed);

View File

@ -83,8 +83,6 @@ inline void* AlignedAlloc(size_t size, size_t alignment) {
// posix_memalign is not exposed in some Android versions, so we fall back to
// memalign. See http://code.google.com/p/android/issues/detail?id=35391.
return memalign(alignment, size);
#elif V8_OS_STARBOARD
return SbMemoryAllocateAligned(alignment, size);
#else // POSIX
void* ptr;
if (posix_memalign(&ptr, alignment, size)) ptr = nullptr;
@ -95,8 +93,6 @@ inline void* AlignedAlloc(size_t size, size_t alignment) {
inline void AlignedFree(void* ptr) {
#if V8_OS_WIN
_aligned_free(ptr);
#elif V8_OS_STARBOARD
SbMemoryFreeAligned(ptr);
#else
// Using regular Free() is not correct in general. For most platforms,
// including V8_LIBC_BIONIC, it is though.

View File

@ -967,6 +967,7 @@ void OS::PrintError(const char* format, ...) {
va_start(args, format);
VPrintError(format, args);
va_end(args);
fflush(stderr);
}

View File

@ -6,6 +6,9 @@
// abstraction layer for Cobalt, an HTML5 container used mainly by YouTube
// apps in the living room.
#include <stdio.h>
#include <sys/mman.h>
#include "src/base/lazy-instance.h"
#include "src/base/macros.h"
#include "src/base/platform/platform.h"
@ -16,10 +19,9 @@
#include "starboard/common/condition_variable.h"
#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/common/time.h"
#include "starboard/configuration.h"
#include "starboard/configuration_constants.h"
#include "starboard/memory.h"
#include "starboard/time.h"
#include "starboard/time_zone.h"
namespace v8 {
@ -82,18 +84,11 @@ void OS::Initialize(AbortMode abort_mode, const char* const gc_fake_mmap) {
}
int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
#if SB_API_VERSION >= 12
if (!SbTimeIsTimeThreadNowSupported()) return -1;
#endif
#if SB_API_VERSION >= 12 || SB_HAS(TIME_THREAD_NOW)
SbTimeMonotonic thread_now = SbTimeGetMonotonicThreadNow();
*secs = thread_now / kSbTimeSecond;
*usecs = thread_now % kSbTimeSecond;
const int64_t us_time = starboard::CurrentMonotonicThreadTime();
if (us_time == 0) return -1;
*secs = us_time / TimeConstants::kMicroSecondsPerSecond;
*usecs = us_time % TimeConstants::kMicroSecondsPerSecond;
return 0;
#else
return -1;
#endif
}
double OS::TimeCurrentMillis() { return Time::Now().ToJsTime(); }
@ -130,13 +125,13 @@ void OS::SetRandomMmapSeed(int64_t seed) { SB_NOTIMPLEMENTED(); }
void* OS::GetRandomMmapAddr() { return nullptr; }
void* Allocate(void* address, size_t size, OS::MemoryPermission access) {
SbMemoryMapFlags sb_flags;
int prot_flags;
switch (access) {
case OS::MemoryPermission::kNoAccess:
sb_flags = SbMemoryMapFlags(0);
prot_flags = PROT_NONE;
break;
case OS::MemoryPermission::kReadWrite:
sb_flags = SbMemoryMapFlags(kSbMemoryMapProtectReadWrite);
prot_flags = PROT_READ | PROT_WRITE;
break;
default:
SB_LOG(ERROR) << "The requested memory allocation access is not"
@ -144,8 +139,8 @@ void* Allocate(void* address, size_t size, OS::MemoryPermission access) {
<< static_cast<int>(access);
return nullptr;
}
void* result = SbMemoryMap(size, sb_flags, "v8::Base::Allocate");
if (result == SB_MEMORY_MAP_FAILED) {
void* result = mmap(nullptr, size, prot_flags, MAP_PRIVATE | MAP_ANON, -1, 0);
if (result == MAP_FAILED) {
return nullptr;
}
return result;
@ -188,30 +183,29 @@ void* OS::Allocate(void* address, size_t size, size_t alignment,
// static
void OS::Free(void* address, const size_t size) {
CHECK(SbMemoryUnmap(address, size));
CHECK_EQ(munmap(address, size), 0);
}
// static
void OS::Release(void* address, size_t size) {
CHECK(SbMemoryUnmap(address, size));
CHECK_EQ(munmap(address, size), 0);
}
// static
bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
SbMemoryMapFlags new_protection;
int new_protection;
switch (access) {
case OS::MemoryPermission::kNoAccess:
new_protection = SbMemoryMapFlags(0);
new_protection = PROT_NONE;
break;
case OS::MemoryPermission::kRead:
new_protection = SbMemoryMapFlags(kSbMemoryMapProtectRead);
new_protection = PROT_READ;
case OS::MemoryPermission::kReadWrite:
new_protection = SbMemoryMapFlags(kSbMemoryMapProtectReadWrite);
new_protection = PROT_READ | PROT_WRITE;
break;
case OS::MemoryPermission::kReadExecute:
#if SB_CAN(MAP_EXECUTABLE_MEMORY)
new_protection =
SbMemoryMapFlags(kSbMemoryMapProtectRead | kSbMemoryMapProtectExec);
new_protection = PROT_READ | PROT_EXEC;
#else
UNREACHABLE();
#endif
@ -220,7 +214,7 @@ bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
// All other types are not supported by Starboard.
return false;
}
return SbMemoryProtect(address, size, new_protection);
return mprotect(address, size, new_protection) == 0;
}
// static
@ -348,7 +342,7 @@ int OS::SNPrintF(char* str, int length, const char* format, ...) {
}
int OS::VSNPrintF(char* str, int length, const char* format, va_list args) {
int n = SbStringFormat(str, length, format, args);
int n = vsnprintf(str, length, format, args);
if (n < 0 || n >= length) {
// If the length is zero, the assignment fails.
if (length > 0) str[length - 1] = '\0';
@ -363,7 +357,7 @@ int OS::VSNPrintF(char* str, int length, const char* format, va_list args) {
//
void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
SbStringCopy(dest, src, n);
strncpy(dest, src, n);
}
// ----------------------------------------------------------------------------
@ -448,14 +442,18 @@ class StarboardDefaultTimezoneCache : public StarboardTimezoneCache {
return SbTimeZoneGetName();
}
double LocalTimeOffset(double time_ms, bool is_utc) override {
// SbTimeZOneGetCurrent returns an offset west of Greenwich, which has the
// SbTimeZoneGetCurrent returns an offset west of Greenwich, which has the
// opposite sign V8 expects.
// The starboard function returns offset in minutes. We convert to return
// value in milliseconds.
return SbTimeZoneGetCurrent() * 60.0 * msPerSecond * (-1);
}
double DaylightSavingsOffset(double time_ms) override {
EzTimeValue value = EzTimeValueFromSbTime(SbTimeGetNow());
int64_t posix_microseconds = starboard::CurrentPosixTime();
EzTimeValue value = {
posix_microseconds / TimeConstants::kMicroSecondsPerSecond,
(int32_t)(posix_microseconds % TimeConstants::kMicroSecondsPerSecond)
};
EzTimeExploded ez_exploded;
bool result =
EzTimeValueExplode(&value, kEzTimeZoneLocal, &ez_exploded, NULL);
@ -489,6 +487,12 @@ bool OS::DiscardSystemPages(void* address, size_t size) {
return true;
}
// static
Stack::StackSlot Stack::GetStackStart() {
SB_NOTIMPLEMENTED();
return nullptr;
}
// static
Stack::StackSlot Stack::GetCurrentStackPosition() {
void* addresses[kStackSize];

View File

@ -702,6 +702,7 @@ void OS::PrintError(const char* format, ...) {
va_start(args, format);
VPrintError(format, args);
va_end(args);
fflush(stderr);
}

View File

@ -170,7 +170,7 @@ void Semaphore::Signal() { native_handle_.Put(); }
void Semaphore::Wait() { native_handle_.Take(); }
bool Semaphore::WaitFor(const TimeDelta& rel_time) {
SbTime microseconds = rel_time.InMicroseconds();
int64_t microseconds = rel_time.InMicroseconds();
return native_handle_.TakeWait(microseconds);
}

View File

@ -22,6 +22,10 @@
#include <zircon/threads.h>
#endif
#if V8_OS_STARBOARD
#include <sys/time.h>
#endif // V8_OS_STARBOARD
#include <cstring>
#include <ostream>
@ -41,7 +45,7 @@
#include "src/base/platform/platform.h"
#if V8_OS_STARBOARD
#include "starboard/time.h"
#include "starboard/common/time.h"
#endif
namespace {
@ -402,7 +406,7 @@ FILETIME Time::ToFiletime() const {
return ft;
}
#elif V8_OS_POSIX
#elif V8_OS_POSIX || V8_OS_STARBOARD
Time Time::Now() {
struct timeval tv;
@ -482,13 +486,7 @@ struct timeval Time::ToTimeval() const {
return tv;
}
#elif V8_OS_STARBOARD
Time Time::Now() { return Time(SbTimeToPosix(SbTimeGetNow())); }
Time Time::NowFromSystemTime() { return Now(); }
#endif // V8_OS_STARBOARD
#endif // V8_OS_POSIX || V8_OS_STARBOARD
Time Time::FromJsTime(double ms_since_epoch) {
// The epoch is a valid time, so this constructor doesn't interpret
@ -753,7 +751,7 @@ TimeTicks TimeTicks::Now() {
#elif V8_OS_POSIX
ticks = ClockNow(CLOCK_MONOTONIC);
#elif V8_OS_STARBOARD
ticks = SbTimeGetMonotonicNow();
ticks = starboard::CurrentMonotonicTime();
#else
#error platform does not implement TimeTicks::Now.
#endif // V8_OS_DARWIN
@ -780,13 +778,7 @@ bool TimeTicks::IsHighResolution() {
bool ThreadTicks::IsSupported() {
#if V8_OS_STARBOARD
#if SB_API_VERSION >= 12
return SbTimeIsTimeThreadNowSupported();
#elif SB_HAS(TIME_THREAD_NOW)
return true;
#else
return false;
#endif
return starboard::CurrentMonotonicThreadTime() != 0;
#elif defined(__PASE__)
// Thread CPU time accounting is unavailable in PASE
return false;
@ -803,15 +795,10 @@ bool ThreadTicks::IsSupported() {
ThreadTicks ThreadTicks::Now() {
#if V8_OS_STARBOARD
#if SB_API_VERSION >= 12
if (SbTimeIsTimeThreadNowSupported())
return ThreadTicks(SbTimeGetMonotonicThreadNow());
const int64_t now = starboard::CurrentMonotonicThreadTime();
if (now != 0)
return ThreadTicks(now);
UNREACHABLE();
#elif SB_HAS(TIME_THREAD_NOW)
return ThreadTicks(SbTimeGetMonotonicThreadNow());
#else
UNREACHABLE();
#endif
#elif V8_OS_DARWIN
return ThreadTicks(ComputeThreadTicks());
#elif V8_OS_FUCHSIA

View File

@ -422,6 +422,9 @@ Tagged<Smi> BaselineCompiler::IndexAsSmi(int operand_index) {
Tagged<Smi> BaselineCompiler::IntAsSmi(int operand_index) {
return Smi::FromInt(Int(operand_index));
}
Tagged<Smi> BaselineCompiler::UintAsSmi(int operand_index) {
return Smi::FromInt(Uint(operand_index));
}
Tagged<Smi> BaselineCompiler::Flag8AsSmi(int operand_index) {
return Smi::FromInt(Flag8(operand_index));
}
@ -647,6 +650,8 @@ constexpr static bool BuiltinMayDeopt(Builtin id) {
case Builtin::kBaselineOutOfLinePrologue:
case Builtin::kIncBlockCounter:
case Builtin::kToObject:
case Builtin::kStoreScriptContextSlotBaseline:
case Builtin::kStoreCurrentScriptContextSlotBaseline:
// This one explicitly skips the construct if the debugger is enabled.
case Builtin::kFindNonDefaultConstructorOrConstruct:
return false;
@ -812,6 +817,30 @@ void BaselineCompiler::VisitStaCurrentContextSlot() {
context, Context::OffsetOfElementAt(Index(0)), value);
}
void BaselineCompiler::VisitStaScriptContextSlot() {
Register value = WriteBarrierDescriptor::ValueRegister();
Register context = WriteBarrierDescriptor::ObjectRegister();
DCHECK(!AreAliased(value, context, kInterpreterAccumulatorRegister));
__ Move(value, kInterpreterAccumulatorRegister);
LoadRegister(context, 0);
SaveAccumulatorScope accumulator_scope(this, &basm_);
CallBuiltin<Builtin::kStoreScriptContextSlotBaseline>(
context, // context
value, // value
IndexAsSmi(1), // slot
UintAsTagged(2)); // depth
}
void BaselineCompiler::VisitStaCurrentScriptContextSlot() {
Register value = WriteBarrierDescriptor::ValueRegister();
DCHECK(!AreAliased(value, kInterpreterAccumulatorRegister));
SaveAccumulatorScope accumulator_scope(this, &basm_);
__ Move(value, kInterpreterAccumulatorRegister);
CallBuiltin<Builtin::kStoreCurrentScriptContextSlotBaseline>(
value, // value
IndexAsSmi(0)); // slot
}
void BaselineCompiler::VisitLdaLookupSlot() {
CallRuntime(Runtime::kLoadLookupSlot, Constant<Name>(0));
}

View File

@ -91,6 +91,7 @@ class BaselineCompiler {
Tagged<TaggedIndex> UintAsTagged(int operand_index);
Tagged<Smi> IndexAsSmi(int operand_index);
Tagged<Smi> IntAsSmi(int operand_index);
Tagged<Smi> UintAsSmi(int operand_index);
Tagged<Smi> Flag8AsSmi(int operand_index);
Tagged<Smi> Flag16AsSmi(int operand_index);

View File

@ -151,7 +151,8 @@ void Accessors::ArrayLengthGetter(
RCS_SCOPE(isolate, RuntimeCallCounterId::kArrayLengthGetter);
DisallowGarbageCollection no_gc;
HandleScope scope(isolate);
Tagged<JSArray> holder = JSArray::cast(*Utils::OpenHandle(*info.Holder()));
Tagged<JSArray> holder =
JSArray::cast(*Utils::OpenDirectHandle(*info.Holder()));
Tagged<Object> result = holder->length();
info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
}
@ -163,7 +164,7 @@ void Accessors::ArrayLengthSetter(
RCS_SCOPE(isolate, RuntimeCallCounterId::kArrayLengthSetter);
HandleScope scope(isolate);
DCHECK(Object::SameValue(*Utils::OpenHandle(*name),
DCHECK(Object::SameValue(*Utils::OpenDirectHandle(*name),
ReadOnlyRoots(isolate).length_string()));
Handle<JSReceiver> object = Utils::OpenHandle(*info.Holder());
@ -233,7 +234,7 @@ void Accessors::ModuleNamespaceEntryGetter(
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
Tagged<JSModuleNamespace> holder =
JSModuleNamespace::cast(*Utils::OpenHandle(*info.Holder()));
JSModuleNamespace::cast(*Utils::OpenDirectHandle(*info.Holder()));
Handle<Object> result;
if (holder->GetExport(isolate, Handle<String>::cast(Utils::OpenHandle(*name)))
.ToHandle(&result)) {
@ -281,12 +282,13 @@ void Accessors::StringLengthGetter(
// v8::Object, but internally we have callbacks on entities which are higher
// in the hierarchy, in this case for String values.
Tagged<Object> value = *Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
Tagged<Object> value =
*Utils::OpenDirectHandle(*v8::Local<v8::Value>(info.This()));
if (!IsString(value)) {
// Not a string value. That means that we either got a String wrapper or
// a Value with a String wrapper in its prototype chain.
value =
JSPrimitiveWrapper::cast(*Utils::OpenHandle(*info.Holder()))->value();
value = JSPrimitiveWrapper::cast(*Utils::OpenDirectHandle(*info.Holder()))
->value();
}
Tagged<Object> result = Smi::FromInt(String::cast(value)->length());
info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));

View File

@ -930,7 +930,7 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm,
void Builtins::Generate_BaselineOutOfLinePrologue(MacroAssembler* masm) {
UseScratchRegisterScope temps(masm);
// Need a few extra registers
temps.Include({r4, r8, r9});
temps.Include({r4, r5, r8, r9});
auto descriptor =
Builtins::CallInterfaceDescriptorFor(Builtin::kBaselineOutOfLinePrologue);
@ -943,7 +943,11 @@ void Builtins::Generate_BaselineOutOfLinePrologue(MacroAssembler* masm) {
FieldMemOperand(closure, JSFunction::kFeedbackCellOffset));
__ ldr(feedback_vector,
FieldMemOperand(feedback_cell, FeedbackCell::kValueOffset));
__ AssertFeedbackVector(feedback_vector);
{
UseScratchRegisterScope temps(masm);
Register temporary = temps.Acquire();
__ AssertFeedbackVector(feedback_vector, temporary);
}
// Check the tiering state.
Label flags_need_processing;

View File

@ -491,9 +491,8 @@ static void GetSharedFunctionInfoBytecodeOrBaseline(
&done);
}
__ LoadTrustedPointerField(
bytecode, FieldMemOperand(data, InterpreterData::kBytecodeArrayOffset),
kBytecodeArrayIndirectPointerTag);
__ LoadProtectedPointerField(
bytecode, FieldMemOperand(data, InterpreterData::kBytecodeArrayOffset));
__ Bind(&done);
__ IsObjectType(bytecode, scratch1, scratch1, BYTECODE_ARRAY_TYPE);
@ -1557,7 +1556,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(
__ Move(x2, kInterpreterBytecodeArrayRegister);
static_assert(kJavaScriptCallCodeStartRegister == x2, "ABI mismatch");
__ ReplaceClosureCodeWithOptimizedCode(x2, closure);
__ JumpCodeObject(x2);
__ JumpCodeObject(x2, kJSEntrypointTag);
__ bind(&install_baseline_code);
__ GenerateTailCallToReturnedCode(Runtime::kInstallBaselineCode);
@ -2026,9 +2025,9 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
kInterpreterDispatchTableRegister, INTERPRETER_DATA_TYPE);
__ B(ne, &builtin_trampoline);
__ LoadCodePointerField(
__ LoadProtectedPointerField(
x1, FieldMemOperand(x1, InterpreterData::kInterpreterTrampolineOffset));
__ LoadCodeInstructionStart(x1, x1);
__ LoadCodeInstructionStart(x1, x1, kJSEntrypointTag);
__ B(&trampoline_loaded);
__ Bind(&builtin_trampoline);
@ -2280,17 +2279,17 @@ void OnStackReplacement(MacroAssembler* masm, OsrSourceTier source,
// Load deoptimization data from the code object.
// <deopt_data> = <code>[#deoptimization_data_offset]
__ LoadTaggedField(
__ LoadProtectedPointerField(
x1,
FieldMemOperand(x0, Code::kDeoptimizationDataOrInterpreterDataOffset));
// Load the OSR entrypoint offset from the deoptimization data.
// <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
__ SmiUntagField(
x1, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(
x1, FieldMemOperand(x1, TrustedFixedArray::OffsetOfElementAt(
DeoptimizationData::kOsrPcOffsetIndex)));
__ LoadCodeInstructionStart(x0, x0);
__ LoadCodeInstructionStart(x0, x0, kJSEntrypointTag);
// Compute the target address = code_entry + osr_offset
// <entry_addr> = <code_entry> + <osr_offset>
@ -5509,7 +5508,7 @@ void Generate_BaselineOrInterpreterEntry(MacroAssembler* masm,
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallCFunction(get_baseline_pc, 3, 0);
}
__ LoadCodeInstructionStart(code_obj, code_obj);
__ LoadCodeInstructionStart(code_obj, code_obj, kJSEntrypointTag);
__ Add(code_obj, code_obj, kReturnRegister0);
__ Pop(kInterpreterAccumulatorRegister, padreg);

View File

@ -243,7 +243,10 @@ type IndirectPointer
generates 'TNode<IndirectPointerHandleT>'
constexpr 'IndirectPointerHandle';
// TODO(saelo): implement accessors and type checkers for these fields.
type IndirectPointer<To: type> extends IndirectPointer;
type IndirectPointer<To : type extends ExposedTrustedObject> extends
IndirectPointer;
type ProtectedPointer extends Tagged;
type ProtectedPointer<To : type extends TrustedObject> extends ProtectedPointer;
extern class InstructionStream extends TrustedObject;
type BuiltinPtr extends Smi generates 'TNode<BuiltinPtr>';
@ -419,6 +422,7 @@ extern enum MessageTemplate {
kTypedArraySetOffsetOutOfBounds,
kInvalidArgument,
kInvalidRegExpExecResult,
kInvalidSizeValue,
kRegExpNonRegExp,
kRegExpNonObject,
kPromiseNonCallable,
@ -477,6 +481,7 @@ extern enum MessageTemplate {
kIteratorResultNotAnObject,
kFlattenPastSafeLength,
kStrictReadOnlyProperty,
kInvalidUsingInForInLoop,
...
}

View File

@ -413,8 +413,10 @@ TF_BUILTIN(AsyncGeneratorAwaitResolveClosure, AsyncGeneratorBuiltinsAssembler) {
TF_BUILTIN(AsyncGeneratorAwaitRejectClosure, AsyncGeneratorBuiltinsAssembler) {
auto value = Parameter<Object>(Descriptor::kValue);
auto context = Parameter<Context>(Descriptor::kContext);
// Restart in Rethrow mode, as this exception was already thrown and we don't
// want to trigger a second debug break event or change the message location.
AsyncGeneratorAwaitResumeClosure(context, value,
JSAsyncGeneratorObject::kThrow);
JSAsyncGeneratorObject::kRethrow);
}
TF_BUILTIN(AsyncGeneratorAwaitUncaught, AsyncGeneratorBuiltinsAssembler) {

View File

@ -2782,9 +2782,10 @@ TNode<Word32T> WeakCollectionsBuiltinsAssembler::ShouldShrink(
TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::ValueIndexFromKeyIndex(
TNode<IntPtrT> key_index) {
return IntPtrAdd(key_index,
IntPtrConstant(EphemeronHashTable::ShapeT::kEntryValueIndex -
EphemeronHashTable::kEntryKeyIndex));
return IntPtrAdd(
key_index,
IntPtrConstant(EphemeronHashTable::TodoShape::kEntryValueIndex -
EphemeronHashTable::kEntryKeyIndex));
}
TF_BUILTIN(WeakMapConstructor, WeakCollectionsBuiltinsAssembler) {

View File

@ -373,12 +373,8 @@ TNode<JSObject> ConstructorBuiltinsAssembler::FastNewObject(
}
BIND(&allocate_properties);
{
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
properties =
AllocateSwissNameDictionary(SwissNameDictionary::kInitialCapacity);
} else {
properties = AllocateNameDictionary(NameDictionary::kInitialCapacity);
}
properties =
AllocatePropertyDictionary(PropertyDictionary::kInitialCapacity);
Goto(&instantiate_map);
}

View File

@ -665,7 +665,9 @@ namespace internal {
TFH(StoreGlobalICTrampoline, StoreGlobal) \
TFH(StoreGlobalICBaseline, StoreGlobalBaseline) \
TFH(StoreIC, StoreWithVector) \
TFH(StoreIC_Megamorphic, StoreWithVector) \
TFH(StoreICTrampoline, Store) \
TFH(StoreICTrampoline_Megamorphic, Store) \
TFH(StoreICBaseline, StoreBaseline) \
TFH(DefineNamedOwnIC, StoreWithVector) \
TFH(DefineNamedOwnICTrampoline, Store) \
@ -892,8 +894,8 @@ namespace internal {
kMatchInfo) \
TFS(RegExpExecInternal, NeedsContext::kYes, kRegExp, kString, kLastIndex, \
kMatchInfo) \
ASM(RegExpInterpreterTrampoline, CCall) \
ASM(RegExpExperimentalTrampoline, CCall) \
ASM(RegExpInterpreterTrampoline, RegExpTrampoline) \
ASM(RegExpExperimentalTrampoline, RegExpTrampoline) \
\
/* Set */ \
TFS(FindOrderedHashSetEntry, NeedsContext::kYes, kTable, kKey) \
@ -2029,14 +2031,6 @@ namespace internal {
BUILTIN_LIST(V, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
#define BUILTIN_LIST_A(V) \
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN, V)
#define BUILTIN_LIST_TFS(V) \
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, V, \
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
#define BUILTIN_LIST_TFJ(V) \
BUILTIN_LIST(IGNORE_BUILTIN, V, IGNORE_BUILTIN, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
@ -2045,6 +2039,22 @@ namespace internal {
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, V, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
#define BUILTIN_LIST_TFS(V) \
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, V, \
IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
#define BUILTIN_LIST_TFH(V) \
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \
V, IGNORE_BUILTIN, IGNORE_BUILTIN)
#define BUILTIN_LIST_BCH(V) \
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \
IGNORE_BUILTIN, V, IGNORE_BUILTIN)
#define BUILTIN_LIST_A(V) \
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \
IGNORE_BUILTIN, IGNORE_BUILTIN, V)
} // namespace internal
} // namespace v8

View File

@ -106,6 +106,9 @@ void GeneratorBuiltinsAssembler::InnerResume(
case JSGeneratorObject::kThrow:
builtin_result = CallRuntime(Runtime::kThrow, context, value);
break;
case JSGeneratorObject::kRethrow:
// Currently only async generators use this mode.
UNREACHABLE();
}
args->PopAndReturn(builtin_result);
}

View File

@ -101,10 +101,20 @@ void Builtins::Generate_StoreIC(compiler::CodeAssemblerState* state) {
AccessorAssembler assembler(state);
assembler.GenerateStoreIC();
}
void Builtins::Generate_StoreIC_Megamorphic(
compiler::CodeAssemblerState* state) {
AccessorAssembler assembler(state);
assembler.GenerateStoreIC_Megamorphic();
}
void Builtins::Generate_StoreICTrampoline(compiler::CodeAssemblerState* state) {
AccessorAssembler assembler(state);
assembler.GenerateStoreICTrampoline();
}
void Builtins::Generate_StoreICTrampoline_Megamorphic(
compiler::CodeAssemblerState* state) {
AccessorAssembler assembler(state);
assembler.GenerateStoreICTrampoline_Megamorphic();
}
void Builtins::Generate_StoreICBaseline(compiler::CodeAssemblerState* state) {
AccessorAssembler assembler(state);
assembler.GenerateStoreICBaseline();

View File

@ -137,10 +137,10 @@ class WriteBarrierCodeStubAssembler : public CodeStubAssembler {
}
TNode<BoolT> IsPageFlagSet(TNode<IntPtrT> object, int mask) {
TNode<IntPtrT> page = PageFromAddress(object);
TNode<IntPtrT> header = PageHeaderFromAddress(object);
TNode<IntPtrT> flags = UncheckedCast<IntPtrT>(
Load(MachineType::Pointer(), page,
IntPtrConstant(BasicMemoryChunk::kFlagsOffset)));
Load(MachineType::Pointer(), header,
IntPtrConstant(MemoryChunkLayout::kFlagsOffset)));
return WordNotEqual(WordAnd(flags, IntPtrConstant(mask)),
IntPtrConstant(0));
}
@ -156,8 +156,8 @@ class WriteBarrierCodeStubAssembler : public CodeStubAssembler {
void GetMarkBit(TNode<IntPtrT> object, TNode<IntPtrT>* cell,
TNode<IntPtrT>* mask) {
TNode<IntPtrT> page = PageFromAddress(object);
TNode<IntPtrT> bitmap =
IntPtrAdd(page, IntPtrConstant(MemoryChunk::kMarkingBitmapOffset));
TNode<IntPtrT> bitmap = IntPtrAdd(
page, IntPtrConstant(MemoryChunkLayout::kMarkingBitmapOffset));
{
// Temp variable to calculate cell offset in bitmap.
@ -165,8 +165,10 @@ class WriteBarrierCodeStubAssembler : public CodeStubAssembler {
int shift = MarkingBitmap::kBitsPerCellLog2 + kTaggedSizeLog2 -
MarkingBitmap::kBytesPerCellLog2;
r0 = WordShr(object, IntPtrConstant(shift));
r0 = WordAnd(r0, IntPtrConstant((kPageAlignmentMask >> shift) &
~(MarkingBitmap::kBytesPerCell - 1)));
r0 = WordAnd(
r0, IntPtrConstant(
(MemoryChunkHeader::GetAlignmentMaskForAssembler() >> shift) &
~(MarkingBitmap::kBytesPerCell - 1)));
*cell = IntPtrAdd(bitmap, Signed(r0));
}
{
@ -185,11 +187,12 @@ class WriteBarrierCodeStubAssembler : public CodeStubAssembler {
void InsertIntoRememberedSet(TNode<IntPtrT> object, TNode<IntPtrT> slot,
SaveFPRegsMode fp_mode) {
Label slow_path(this), next(this);
TNode<IntPtrT> page = PageFromAddress(object);
TNode<IntPtrT> page_header = PageHeaderFromAddress(object);
TNode<IntPtrT> page = PageFromPageHeader(page_header);
// Load address of SlotSet
TNode<IntPtrT> slot_set = LoadSlotSet(page, &slow_path);
TNode<IntPtrT> slot_offset = IntPtrSub(slot, page);
TNode<IntPtrT> slot_offset = IntPtrSub(slot, page_header);
// Load bucket
TNode<IntPtrT> bucket = LoadBucket(slot_set, slot_offset, &slow_path);
@ -1423,7 +1426,8 @@ void Builtins::Generate_MaglevOptimizeCodeOrTailCallOptimizedCodeSlot(
using D = MaglevOptimizeCodeOrTailCallOptimizedCodeSlotDescriptor;
Register flags = D::GetRegisterParameter(D::kFlags);
Register feedback_vector = D::GetRegisterParameter(D::kFeedbackVector);
masm->AssertFeedbackVector(feedback_vector);
Register temporary = D::GetRegisterParameter(D::kTemporary);
masm->AssertFeedbackVector(feedback_vector, temporary);
masm->OptimizeCodeOrTailCallOptimizedCodeSlot(flags, feedback_vector);
masm->Trap();
}

View File

@ -1072,13 +1072,8 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
BIND(&null_proto);
{
map = LoadSlowObjectWithNullPrototypeMap(native_context);
if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
new_properties =
AllocateSwissNameDictionary(SwissNameDictionary::kInitialCapacity);
} else {
new_properties =
AllocateNameDictionary(NameDictionary::kInitialCapacity);
}
new_properties =
AllocatePropertyDictionary(PropertyDictionary::kInitialCapacity);
Goto(&instantiate_map);
}
@ -1419,10 +1414,7 @@ TNode<JSObject> ObjectBuiltinsAssembler::FromPropertyDescriptor(
native_context, Context::SLOW_OBJECT_WITH_OBJECT_PROTOTYPE_MAP));
// We want to preallocate the slots for value, writable, get, set,
// enumerable and configurable - a total of 6
TNode<HeapObject> properties =
V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
? TNode<HeapObject>(AllocateSwissNameDictionary(6))
: AllocateNameDictionary(6);
TNode<HeapObject> properties = AllocatePropertyDictionary(6);
TNode<JSObject> js_desc = AllocateJSObjectFromMap(map, properties);
Label bailout(this, Label::kDeferred);

View File

@ -115,10 +115,9 @@ Tagged<Object> ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
LookupIterator it(isolate, object, lookup_key,
LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
for (; it.IsFound(); it.Next()) {
for (;; it.Next()) {
switch (it.state()) {
case LookupIterator::INTERCEPTOR:
case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION:
UNREACHABLE();
@ -151,8 +150,9 @@ Tagged<Object> ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
return ObjectLookupAccessor(isolate, prototype, key, component);
}
case LookupIterator::WASM_OBJECT:
case LookupIterator::INTEGER_INDEXED_EXOTIC:
case LookupIterator::TYPED_ARRAY_INDEX_NOT_FOUND:
case LookupIterator::DATA:
case LookupIterator::NOT_FOUND:
return ReadOnlyRoots(isolate).undefined_value();
case LookupIterator::ACCESSOR: {
@ -165,11 +165,11 @@ Tagged<Object> ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
isolate, holder_realm, Handle<AccessorPair>::cast(maybe_pair),
component);
}
continue;
}
}
UNREACHABLE();
}
return ReadOnlyRoots(isolate).undefined_value();
}
} // namespace

View File

@ -312,19 +312,45 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
// implementation of CreateDataProperty instead.
// At this point the spec says to call CreateDataProperty. However, we can
// skip most of the steps and go straight to adding a dictionary entry
// because we know a bunch of useful facts:
// skip most of the steps and go straight to adding/updating a dictionary
// entry because we know a bunch of useful facts:
// - All keys are non-numeric internalized strings
// - No keys repeat
// - Receiver has no prototype
// - Receiver isn't used as a prototype
// - Receiver isn't any special object like a Promise intrinsic object
// - Receiver is extensible
// - Receiver has no interceptors
Label add_dictionary_property_slow(this, Label::kDeferred);
AddToDictionary<PropertyDictionary>(CAST(properties), name, capture,
&add_dictionary_property_slow);
TVARIABLE(IntPtrT, var_name_index);
Label add_name_entry_find_index(this),
add_name_entry_known_index(this, &var_name_index),
duplicate_name(this, &var_name_index), next(this);
NameDictionaryLookup<PropertyDictionary>(
CAST(properties), name, &duplicate_name, &var_name_index,
&add_name_entry_find_index, kFindExisting,
&add_name_entry_known_index);
BIND(&duplicate_name);
GotoIf(IsUndefined(capture), &next);
CSA_DCHECK(this,
TaggedEqual(LoadValueByKeyIndex<PropertyDictionary>(
CAST(properties), var_name_index.value()),
UndefinedConstant()));
StoreValueByKeyIndex<PropertyDictionary>(CAST(properties),
var_name_index.value(), capture);
Goto(&next);
BIND(&add_name_entry_find_index);
FindInsertionEntry<PropertyDictionary>(CAST(properties), name,
&var_name_index);
Goto(&add_name_entry_known_index);
BIND(&add_name_entry_known_index);
AddToDictionary<PropertyDictionary>(CAST(properties), name, capture,
&add_dictionary_property_slow,
var_name_index.value());
Goto(&next);
BIND(&next);
var_i = i_plus_2;
Branch(IntPtrGreaterThanOrEqual(var_i.value(), names_length),
&maybe_build_indices, &inner_loop);
@ -578,7 +604,8 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
// instead of referencing the CodeWrapper object, we could directly load
// the entrypoint from that via LoadCodeEntrypointViaCodePointerField. This
// will save an indirection when the sandbox is enabled.
TNode<RawPtrT> code_entry = LoadCodeInstructionStart(code);
TNode<RawPtrT> code_entry =
LoadCodeInstructionStart(code, kRegExpEntrypointTag);
// AIX uses function descriptors on CFunction calls. code_entry in this case
// may also point to a Regex interpreter entry trampoline which does not

View File

@ -462,6 +462,28 @@ bool Builtins::IsCpp(Builtin builtin) {
return Builtins::KindOf(builtin) == CPP;
}
// static
CodeEntrypointTag Builtins::EntrypointTagFor(Builtin builtin) {
if (builtin == Builtin::kNoBuiltinId) {
// Special case needed for example for tests.
return kDefaultCodeEntrypointTag;
}
Kind kind = Builtins::KindOf(builtin);
switch (kind) {
case BCH:
return kBytecodeHandlerEntrypointTag;
case TFH:
return kICHandlerEntrypointTag;
case ASM:
// TODO(saelo) consider using this approach for the other kinds as well.
return CallInterfaceDescriptorFor(builtin).tag();
default:
// TODO(saelo): use more fine-grained tags here.
return kDefaultCodeEntrypointTag;
}
}
// static
bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
Handle<JSObject> target_global_proxy) {

View File

@ -9,6 +9,7 @@
#include "src/builtins/builtins-definitions.h"
#include "src/common/globals.h"
#include "src/objects/type-hints.h"
#include "src/sandbox/code-entrypoint-tag.h"
namespace v8 {
namespace internal {
@ -193,6 +194,9 @@ class Builtins {
static Kind KindOf(Builtin builtin);
static const char* KindNameOf(Builtin builtin);
// The tag for the builtins entrypoint.
V8_EXPORT_PRIVATE static CodeEntrypointTag EntrypointTagFor(Builtin builtin);
static bool IsCpp(Builtin builtin);
// True, iff the given code object is a builtin. Note that this does not

View File

@ -288,21 +288,26 @@ transitioning macro GetSetRecord(
// 6. Let intSize be ! ToIntegerOrInfinity(numSize).
const intSize = ToInteger_Inline(numSize);
// 7. Let has be ? Get(obj, "has").
// 7. If intSize < 0, throw a RangeError exception.
if (intSize < 0) {
ThrowRangeError(MessageTemplate::kInvalidSizeValue, intSize);
}
// 8. Let has be ? Get(obj, "has").
let has = GetProperty(obj, kHasString);
// 8. If IsCallable(has) is false, throw a TypeError exception.
// 9. If IsCallable(has) is false, throw a TypeError exception.
has = Cast<Callable>(has)
otherwise ThrowCalledNonCallable(kHasString);
// 9. Let keys be ? Get(obj, "keys").
// 10. Let keys be ? Get(obj, "keys").
let keys = GetProperty(obj, kKeysString);
// 10. If IsCallable(keys) is false, throw a TypeError exception.
// 11. If IsCallable(keys) is false, throw a TypeError exception.
keys = Cast<Callable>(keys)
otherwise ThrowCalledNonCallable(kKeysString);
// 11. Return a new Set Record { [[Set]]: obj, [[Size]]: intSize, [[Has]]:
// 12. Return a new Set Record { [[Set]]: obj, [[Size]]: intSize, [[Has]]:
// has, [[Keys]]: keys }.
return SetRecord{object: obj, size: intSize, has: has, keys: keys};
}

View File

@ -42,6 +42,8 @@ macro ConvertToAndFromWasm(context: Context, wasmType: int32, value: JSAny):
} else if (wasmType == kWasmF64Type) {
return Convert<Number>(WasmTaggedToFloat64(value));
} else {
const wasmKind = wasmType & kValueTypeKindBitsMask;
dcheck(wasmKind == ValueKind::kRef || wasmKind == ValueKind::kRefNull);
if (value == Null) {
// At the moment it is not possible to define non-nullable types for
// WebAssembly.Functions.
@ -61,6 +63,13 @@ macro ConvertToAndFromWasm(context: Context, wasmType: int32, value: JSAny):
}
}
extern runtime WasmThrowJSTypeError(Context): never;
transitioning javascript builtin JSToJSWrapperInvalidSig(
js-implicit context: NativeContext)(): JSAny {
runtime::WasmThrowJSTypeError(context);
}
transitioning javascript builtin JSToJSWrapper(
js-implicit context: NativeContext, receiver: JSAny, target: JSFunction)(
...arguments): JSAny {

View File

@ -504,6 +504,8 @@ macro JSToWasmWrapperHelper(
} else if (retType == kWasmF64Type) {
allocator.AllocFP64();
} else {
const retKind = retType & kValueTypeKindBitsMask;
dcheck(retKind == ValueKind::kRef || retKind == ValueKind::kRefNull);
// Also check if there are any reference return values, as this allows
// us to skip code when we process return values.
hasRefReturns = true;
@ -600,6 +602,8 @@ macro JSToWasmWrapperHelper(
*toHighRef = Signed(pair.high);
}
} else {
const paramKind = paramType & kValueTypeKindBitsMask;
dcheck(paramKind == ValueKind::kRef || paramKind == ValueKind::kRefNull);
// The byte array where we store converted parameters is not GC-safe.
// Therefore we can only copy references into this array once no GC can
// happen anymore. Any conversion of a primitive type can execute

View File

@ -305,6 +305,7 @@ macro CreatePromiseCapability(
struct PromiseResolvingFunctions {
resolve: JSFunction;
reject: JSFunction;
context: Context;
}
@export
@ -322,7 +323,11 @@ macro CreatePromiseResolvingFunctions(
const rejectInfo = PromiseCapabilityDefaultRejectSharedFunConstant();
const reject: JSFunction =
AllocateFunctionWithMapAndContext(map, rejectInfo, promiseContext);
return PromiseResolvingFunctions{resolve: resolve, reject: reject};
return PromiseResolvingFunctions{
resolve: resolve,
reject: reject,
context: promiseContext
};
}
transitioning macro InnerNewPromiseCapability(

View File

@ -82,6 +82,13 @@ transitioning javascript builtin PromiseConstructor(
try {
Call(context, UnsafeCast<Callable>(executor), Undefined, resolve, reject);
} catch (e, _message) {
// We need to disable the debug event, as we have already paused on this
// exception.
const promiseContext =
%RawDownCast<PromiseResolvingFunctionContext>(funcs.context);
*ContextSlot(
promiseContext, PromiseResolvingFunctionContextSlot::kDebugEventSlot) =
False;
Call(context, reject, Undefined, e);
}

View File

@ -3028,7 +3028,10 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
// Check result for exception sentinel.
Label exception_returned;
__ Branch(&exception_returned, eq, a0, RootIndex::kException);
// The returned value may be a trusted object, living outside of the main
// pointer compression cage, so we need to use full pointer comparison here.
__ CompareRootAndBranch(a0, RootIndex::kException, eq, &exception_returned,
ComparisonMode::kFullPointer);
// Check that there is no exception, otherwise we
// should have returned the exception sentinel.

View File

@ -63,6 +63,16 @@ transitioning javascript builtin WebAssemblyStringIntoUtf8Array(
}
}
transitioning javascript builtin WebAssemblyStringToUtf8Array(
js-implicit context: Context)(...arguments): JSAny {
try {
const string = Cast<String>(arguments[0]) otherwise goto IllegalCast;
return runtime::WasmStringToUtf8Array(context, string);
} label IllegalCast deferred {
Trap(context, MessageTemplate::kWasmTrapIllegalCast);
}
}
transitioning javascript builtin WebAssemblyStringToWtf16Array(
js-implicit context: Context)(...arguments): JSAny {
try {

View File

@ -81,6 +81,7 @@ transitioning macro WasmToJSWrapper(ref: WasmApiFunctionRef): WasmToJSResult {
const returnCount =
Convert<intptr>(*torque_internal::unsafe::NewReference<int32>(
serializedSig.object, serializedSig.offset));
dcheck(returnCount < serializedSig.length);
const paramCount: intptr = serializedSig.length - returnCount - 1;
const returnTypes = Subslice(serializedSig, Convert<intptr>(1), returnCount)
otherwise unreachable;
@ -261,6 +262,8 @@ transitioning macro WasmToJSWrapper(ref: WasmApiFunctionRef): WasmToJSResult {
*toHighRef = Signed(pair.high);
}
} else {
const retKind = retType & kValueTypeKindBitsMask;
dcheck(retKind == ValueKind::kRef || retKind == ValueKind::kRefNull);
dcheck(ref.instance == Undefined || Is<WasmInstanceObject>(ref.instance));
const trustedData = ref.instance == Undefined ?
Undefined :

View File

@ -62,6 +62,7 @@ extern runtime WasmStringEncodeWtf8(
Context, WasmTrustedInstanceData, Smi, Smi, String, Number): Number;
extern runtime WasmStringEncodeWtf8Array(
Context, Smi, String, WasmArray, Number): Number;
extern runtime WasmStringToUtf8Array(Context, String): WasmArray;
extern runtime WasmStringEncodeWtf16(
Context, WasmTrustedInstanceData, Smi, String, Number, Smi, Smi): JSAny;
extern runtime WasmStringAsWtf8(Context, String): ByteArray;
@ -995,6 +996,9 @@ builtin WasmStringEncodeWtf8Array(
WasmUint32ToNumber(start));
return ChangeNumberToUint32(result);
}
builtin WasmStringToUtf8Array(string: String): WasmArray {
return runtime::WasmStringToUtf8Array(LoadContextFromFrame(), string);
}
builtin WasmStringEncodeWtf16(string: String, offset: uint32, memory: Smi):
uint32 {
const trustedData = LoadInstanceDataFromFrame();

View File

@ -759,9 +759,8 @@ static void GetSharedFunctionInfoBytecodeOrBaseline(
&done);
}
__ LoadTrustedPointerField(
bytecode, FieldOperand(data, InterpreterData::kBytecodeArrayOffset),
kBytecodeArrayIndirectPointerTag, scratch1);
__ LoadProtectedPointerField(
bytecode, FieldOperand(data, InterpreterData::kBytecodeArrayOffset));
__ bind(&done);
__ IsObjectType(bytecode, BYTECODE_ARRAY_TYPE, scratch1);
@ -1298,7 +1297,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(
__ ReplaceClosureCodeWithOptimizedCode(
rcx, closure, kInterpreterBytecodeArrayRegister,
WriteBarrierDescriptor::SlotAddressRegister());
__ JumpCodeObject(rcx);
__ JumpCodeObject(rcx, kJSEntrypointTag);
__ bind(&install_baseline_code);
__ GenerateTailCallToReturnedCode(Runtime::kInstallBaselineCode);
@ -1707,11 +1706,9 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
GetSharedFunctionInfoData(masm, rbx, shared_function_info, kScratchRegister);
__ IsObjectType(rbx, INTERPRETER_DATA_TYPE, kScratchRegister);
__ j(not_equal, &builtin_trampoline, Label::kNear);
__ LoadCodePointerField(
rbx, FieldOperand(rbx, InterpreterData::kInterpreterTrampolineOffset),
kScratchRegister);
__ LoadCodeInstructionStart(rbx, rbx);
__ LoadProtectedPointerField(
rbx, FieldOperand(rbx, InterpreterData::kInterpreterTrampolineOffset));
__ LoadCodeInstructionStart(rbx, rbx, kJSEntrypointTag);
__ jmp(&trampoline_loaded, Label::kNear);
__ bind(&builtin_trampoline);
@ -1841,7 +1838,7 @@ void Builtins::Generate_BaselineOutOfLinePrologue(MacroAssembler* masm) {
FieldOperand(closure, JSFunction::kFeedbackCellOffset));
__ LoadTaggedField(feedback_vector,
FieldOperand(feedback_cell, FeedbackCell::kValueOffset));
__ AssertFeedbackVector(feedback_vector);
__ AssertFeedbackVector(feedback_vector, kScratchRegister);
// Check the tiering state.
Label flags_need_processing;
@ -2935,18 +2932,18 @@ void OnStackReplacement(MacroAssembler* masm, OsrSourceTier source,
}
// Load deoptimization data from the code object.
const TaggedRegister deopt_data(rbx);
__ LoadTaggedField(
const Register deopt_data(rbx);
__ LoadProtectedPointerField(
deopt_data,
FieldOperand(rax, Code::kDeoptimizationDataOrInterpreterDataOffset));
// Load the OSR entrypoint offset from the deoptimization data.
__ SmiUntagField(
rbx,
FieldOperand(deopt_data, FixedArray::OffsetOfElementAt(
FieldOperand(deopt_data, TrustedFixedArray::OffsetOfElementAt(
DeoptimizationData::kOsrPcOffsetIndex)));
__ LoadCodeInstructionStart(rax, rax);
__ LoadCodeInstructionStart(rax, rax, kJSEntrypointTag);
// Compute the target address = code_entry + osr_offset
__ addq(rax, rbx);
@ -4990,7 +4987,7 @@ void Generate_BaselineOrInterpreterEntry(MacroAssembler* masm,
__ movq(kCArgRegs[2], kInterpreterBytecodeArrayRegister);
__ CallCFunction(get_baseline_pc, 3);
}
__ LoadCodeInstructionStart(code_obj, code_obj);
__ LoadCodeInstructionStart(code_obj, code_obj, kJSEntrypointTag);
__ addq(code_obj, kReturnRegister0);
__ popq(kInterpreterAccumulatorRegister);

View File

@ -1250,7 +1250,7 @@ void Assembler::AddrMode1(Instr instr, Register rd, Register rn,
// pool only for a MOV instruction which does not set the flags.
DCHECK(!rn.is_valid());
Move32BitImmediate(rd, x, cond);
} else if ((opcode == ADD) && !set_flags && (rd == rn) &&
} else if ((opcode == ADD || opcode == SUB) && !set_flags && (rd == rn) &&
!temps.CanAcquire()) {
// Split the operation into a sequence of additions if we cannot use a
// scratch register. In this case, we cannot re-use rn and the assembler
@ -1266,10 +1266,20 @@ void Assembler::AddrMode1(Instr instr, Register rd, Register rn,
// immediate allows us to more efficiently split it:
int trailing_zeroes = base::bits::CountTrailingZeros(imm) & ~1u;
uint32_t mask = (0xFF << trailing_zeroes);
add(rd, rd, Operand(imm & mask), LeaveCC, cond);
if (opcode == ADD) {
add(rd, rd, Operand(imm & mask), LeaveCC, cond);
} else {
DCHECK_EQ(opcode, SUB);
sub(rd, rd, Operand(imm & mask), LeaveCC, cond);
}
imm = imm & ~mask;
} while (!ImmediateFitsAddrMode1Instruction(imm));
add(rd, rd, Operand(imm), LeaveCC, cond);
if (opcode == ADD) {
add(rd, rd, Operand(imm), LeaveCC, cond);
} else {
DCHECK_EQ(opcode, SUB);
sub(rd, rd, Operand(imm), LeaveCC, cond);
}
} else {
// The immediate operand cannot be encoded as a shifter operand, so load
// it first to a scratch register and change the original instruction to

View File

@ -164,6 +164,11 @@ constexpr Register MaglevOptimizeCodeOrTailCallOptimizedCodeSlotDescriptor::
FeedbackVectorRegister() {
return r5;
}
// static
constexpr Register
MaglevOptimizeCodeOrTailCallOptimizedCodeSlotDescriptor::TemporaryRegister() {
return r4;
}
// static
constexpr auto CallTrampolineDescriptor::registers() {

View File

@ -363,7 +363,8 @@ void MacroAssembler::TailCallBuiltin(Builtin builtin, Condition cond) {
}
void MacroAssembler::LoadCodeInstructionStart(Register destination,
Register code_object) {
Register code_object,
CodeEntrypointTag tag) {
ASM_CODE_COMMENT(this);
ldr(destination, FieldMemOperand(code_object, Code::kInstructionStartOffset));
}
@ -2006,10 +2007,8 @@ void MacroAssembler::AssertFeedbackCell(Register object, Register scratch) {
Assert(eq, AbortReason::kExpectedFeedbackCell);
}
}
void MacroAssembler::AssertFeedbackVector(Register object) {
void MacroAssembler::AssertFeedbackVector(Register object, Register scratch) {
if (v8_flags.debug_code) {
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
CompareObjectType(object, scratch, scratch, FEEDBACK_VECTOR_TYPE);
Assert(eq, AbortReason::kExpectedFeedbackVector);
}
@ -2729,20 +2728,22 @@ void MacroAssembler::MovToFloatParameters(DwVfpRegister src1,
}
}
void MacroAssembler::CallCFunction(ExternalReference function,
int num_reg_arguments,
int num_double_arguments,
SetIsolateDataSlots set_isolate_data_slots) {
int MacroAssembler::CallCFunction(ExternalReference function,
int num_reg_arguments,
int num_double_arguments,
SetIsolateDataSlots set_isolate_data_slots,
Label* return_label) {
UseScratchRegisterScope temps(this);
Register scratch = temps.Acquire();
Move(scratch, function);
CallCFunction(scratch, num_reg_arguments, num_double_arguments,
set_isolate_data_slots);
return CallCFunction(scratch, num_reg_arguments, num_double_arguments,
set_isolate_data_slots, return_label);
}
void MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
int num_double_arguments,
SetIsolateDataSlots set_isolate_data_slots) {
int MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
int num_double_arguments,
SetIsolateDataSlots set_isolate_data_slots,
Label* return_label) {
ASM_CODE_COMMENT(this);
DCHECK_LE(num_reg_arguments + num_double_arguments, kMaxCParameters);
DCHECK(has_frame());
@ -2767,13 +2768,19 @@ void MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
}
#endif
Label get_pc;
if (set_isolate_data_slots == SetIsolateDataSlots::kYes) {
Register pc_scratch = r5;
Push(pc_scratch);
GetLabelAddress(pc_scratch, &get_pc);
// Save the frame pointer and PC so that the stack layout remains iterable,
// even without an ExitFrame which normally exists between JS and C frames.
// See x64 code for reasoning about how to address the isolate data fields.
if (root_array_available()) {
str(pc, MemOperand(kRootRegister,
IsolateData::fast_c_call_caller_pc_offset()));
str(pc_scratch, MemOperand(kRootRegister,
IsolateData::fast_c_call_caller_pc_offset()));
str(fp, MemOperand(kRootRegister,
IsolateData::fast_c_call_caller_fp_offset()));
} else {
@ -2783,19 +2790,24 @@ void MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
Move(addr_scratch,
ExternalReference::fast_c_call_caller_pc_address(isolate()));
str(pc, MemOperand(addr_scratch));
str(pc_scratch, MemOperand(addr_scratch));
Move(addr_scratch,
ExternalReference::fast_c_call_caller_fp_address(isolate()));
str(fp, MemOperand(addr_scratch));
Pop(addr_scratch);
}
Pop(pc_scratch);
}
// Just call directly. The function called cannot cause a GC, or
// allow preemption, so the return address in the link register
// stays correct.
Call(function);
int call_pc_offset = pc_offset();
bind(&get_pc);
if (return_label) bind(return_label);
if (set_isolate_data_slots == SetIsolateDataSlots::kYes) {
// We don't unset the PC; the FP is the source of truth.
@ -2827,17 +2839,22 @@ void MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
} else {
add(sp, sp, Operand(stack_passed_arguments * kPointerSize));
}
return call_pc_offset;
}
void MacroAssembler::CallCFunction(ExternalReference function,
int num_arguments,
SetIsolateDataSlots set_isolate_data_slots) {
CallCFunction(function, num_arguments, 0, set_isolate_data_slots);
int MacroAssembler::CallCFunction(ExternalReference function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots,
Label* return_label) {
return CallCFunction(function, num_arguments, 0, set_isolate_data_slots,
return_label);
}
void MacroAssembler::CallCFunction(Register function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots) {
CallCFunction(function, num_arguments, 0, set_isolate_data_slots);
int MacroAssembler::CallCFunction(Register function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots,
Label* return_label) {
return CallCFunction(function, num_arguments, 0, set_isolate_data_slots,
return_label);
}
void MacroAssembler::CheckPageFlag(Register object, int mask, Condition cc,
@ -2848,7 +2865,7 @@ void MacroAssembler::CheckPageFlag(Register object, int mask, Condition cc,
DCHECK(!AreAliased(object, scratch));
DCHECK(cc == eq || cc == ne);
Bfc(scratch, object, 0, kPageSizeBits);
ldr(scratch, MemOperand(scratch, BasicMemoryChunk::kFlagsOffset));
ldr(scratch, MemOperand(scratch, MemoryChunkLayout::kFlagsOffset));
tst(scratch, Operand(mask));
b(cc, condition_met);
}

View File

@ -252,23 +252,23 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase {
// garbage collection, since that might move the code and invalidate the
// return address (unless this is somehow accounted for by the called
// function).
enum class SetIsolateDataSlots {
kNo,
kYes,
};
void CallCFunction(
int CallCFunction(
ExternalReference function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);
void CallCFunction(
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes,
Label* return_label = nullptr);
int CallCFunction(
Register function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);
void CallCFunction(
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes,
Label* return_label = nullptr);
int CallCFunction(
ExternalReference function, int num_reg_arguments,
int num_double_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);
void CallCFunction(
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes,
Label* return_label = nullptr);
int CallCFunction(
Register function, int num_reg_arguments, int num_double_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes,
Label* return_label = nullptr);
void MovFromFloatParameter(DwVfpRegister dst);
void MovFromFloatResult(DwVfpRegister dst);
@ -337,7 +337,9 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase {
void TailCallBuiltin(Builtin builtin, Condition cond = al);
// Load the code entry point from the Code object.
void LoadCodeInstructionStart(Register destination, Register code_object);
void LoadCodeInstructionStart(
Register destination, Register code_object,
CodeEntrypointTag tag = kDefaultCodeEntrypointTag);
void CallCodeObject(Register code_object);
void JumpCodeObject(Register code_object,
JumpMode jump_mode = JumpMode::kJump);
@ -875,7 +877,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase {
// Tiering support.
void AssertFeedbackCell(Register object,
Register scratch) NOOP_UNLESS_DEBUG_CODE;
void AssertFeedbackVector(Register object) NOOP_UNLESS_DEBUG_CODE;
void AssertFeedbackVector(Register object,
Register scratch) NOOP_UNLESS_DEBUG_CODE;
void ReplaceClosureCodeWithOptimizedCode(Register optimized_code,
Register closure);
void GenerateTailCallToReturnedCode(Runtime::FunctionId function_id);

View File

@ -154,6 +154,11 @@ constexpr Register MaglevOptimizeCodeOrTailCallOptimizedCodeSlotDescriptor::
FeedbackVectorRegister() {
return x9;
}
// static
constexpr Register
MaglevOptimizeCodeOrTailCallOptimizedCodeSlotDescriptor::TemporaryRegister() {
return x4;
}
// static
constexpr auto TypeofDescriptor::registers() { return RegisterArray(x0); }

View File

@ -1440,7 +1440,7 @@ void TailCallOptimizedCodeSlot(MacroAssembler* masm,
__ ReplaceClosureCodeWithOptimizedCode(optimized_code_entry, closure);
static_assert(kJavaScriptCallCodeStartRegister == x2, "ABI mismatch");
__ Move(x2, optimized_code_entry);
__ JumpCodeObject(x2);
__ JumpCodeObject(x2, kJSEntrypointTag);
// Optimized code slot contains deoptimized code or code is cleared and
// optimized code marker isn't updated. Evict the code, update the marker
@ -1507,7 +1507,7 @@ void MacroAssembler::GenerateTailCallToReturnedCode(
}
static_assert(kJavaScriptCallCodeStartRegister == x2, "ABI mismatch");
JumpCodeObject(x2);
JumpCodeObject(x2, kJSEntrypointTag);
}
// Read off the flags in the feedback vector and check if there
@ -2061,31 +2061,37 @@ int MacroAssembler::ActivationFrameAlignment() {
#endif // V8_HOST_ARCH_ARM64
}
void MacroAssembler::CallCFunction(ExternalReference function,
int num_of_reg_args,
SetIsolateDataSlots set_isolate_data_slots) {
CallCFunction(function, num_of_reg_args, 0, set_isolate_data_slots);
int MacroAssembler::CallCFunction(ExternalReference function,
int num_of_reg_args,
SetIsolateDataSlots set_isolate_data_slots,
Label* return_location) {
return CallCFunction(function, num_of_reg_args, 0, set_isolate_data_slots,
return_location);
}
void MacroAssembler::CallCFunction(ExternalReference function,
int num_of_reg_args, int num_of_double_args,
SetIsolateDataSlots set_isolate_data_slots) {
int MacroAssembler::CallCFunction(ExternalReference function,
int num_of_reg_args, int num_of_double_args,
SetIsolateDataSlots set_isolate_data_slots,
Label* return_location) {
// Note: The "CallCFunction" code comment will be generated by the other
// CallCFunction method called below.
UseScratchRegisterScope temps(this);
Register temp = temps.AcquireX();
Mov(temp, function);
CallCFunction(temp, num_of_reg_args, num_of_double_args,
set_isolate_data_slots);
return CallCFunction(temp, num_of_reg_args, num_of_double_args,
set_isolate_data_slots, return_location);
}
void MacroAssembler::CallCFunction(Register function, int num_of_reg_args,
int num_of_double_args,
SetIsolateDataSlots set_isolate_data_slots) {
int MacroAssembler::CallCFunction(Register function, int num_of_reg_args,
int num_of_double_args,
SetIsolateDataSlots set_isolate_data_slots,
Label* return_location) {
ASM_CODE_COMMENT(this);
DCHECK_LE(num_of_reg_args + num_of_double_args, kMaxCParameters);
DCHECK(has_frame());
Label get_pc;
if (set_isolate_data_slots == SetIsolateDataSlots::kYes) {
// Save the frame pointer and PC so that the stack layout remains iterable,
// even without an ExitFrame which normally exists between JS and C frames.
@ -2093,8 +2099,6 @@ void MacroAssembler::CallCFunction(Register function, int num_of_reg_args,
Register addr_scratch = x5;
Push(pc_scratch, addr_scratch);
Label get_pc;
Bind(&get_pc);
Adr(pc_scratch, &get_pc);
// See x64 code for reasoning about how to address the isolate data fields.
@ -2119,6 +2123,9 @@ void MacroAssembler::CallCFunction(Register function, int num_of_reg_args,
// Call directly. The function called cannot cause a GC, or allow preemption,
// so the return address in the link register stays correct.
Call(function);
int call_pc_offset = pc_offset();
bind(&get_pc);
if (return_location) bind(return_location);
if (set_isolate_data_slots == SetIsolateDataSlots::kYes) {
// We don't unset the PC; the FP is the source of truth.
@ -2148,6 +2155,8 @@ void MacroAssembler::CallCFunction(Register function, int num_of_reg_args,
RoundUp(num_of_double_args - kFPRegisterPassedArguments, 2);
Drop(claim_slots);
}
return call_pc_offset;
}
void MacroAssembler::LoadFromConstantsTable(Register destination,
@ -2459,27 +2468,30 @@ void MacroAssembler::TailCallBuiltin(Builtin builtin, Condition cond) {
}
void MacroAssembler::LoadCodeInstructionStart(Register destination,
Register code_object) {
Register code_object,
CodeEntrypointTag tag) {
ASM_CODE_COMMENT(this);
#ifdef V8_ENABLE_SANDBOX
LoadCodeEntrypointViaCodePointer(
destination,
FieldMemOperand(code_object, Code::kSelfIndirectPointerOffset));
FieldMemOperand(code_object, Code::kSelfIndirectPointerOffset), tag);
#else
Ldr(destination, FieldMemOperand(code_object, Code::kInstructionStartOffset));
#endif
}
void MacroAssembler::CallCodeObject(Register code_object) {
void MacroAssembler::CallCodeObject(Register code_object,
CodeEntrypointTag tag) {
ASM_CODE_COMMENT(this);
LoadCodeInstructionStart(code_object, code_object);
LoadCodeInstructionStart(code_object, code_object, tag);
Call(code_object);
}
void MacroAssembler::JumpCodeObject(Register code_object, JumpMode jump_mode) {
void MacroAssembler::JumpCodeObject(Register code_object, CodeEntrypointTag tag,
JumpMode jump_mode) {
ASM_CODE_COMMENT(this);
DCHECK_EQ(JumpMode::kJump, jump_mode);
LoadCodeInstructionStart(code_object, code_object);
LoadCodeInstructionStart(code_object, code_object, tag);
// We jump through x17 here because for Branch Identification (BTI) we use
// "Call" (`bti c`) rather than "Jump" (`bti j`) landing pads for tail-called
// code. See TailCallBuiltin for more information.
@ -2496,12 +2508,13 @@ void MacroAssembler::CallJSFunction(Register function_object) {
// from the code pointer table instead of going through the Code object. In
// this way, we avoid one memory load on this code path.
LoadCodeEntrypointViaCodePointer(
code, FieldMemOperand(function_object, JSFunction::kCodeOffset));
code, FieldMemOperand(function_object, JSFunction::kCodeOffset),
kJSEntrypointTag);
Call(code);
#else
LoadTaggedField(code,
FieldMemOperand(function_object, JSFunction::kCodeOffset));
CallCodeObject(code);
CallCodeObject(code, kJSEntrypointTag);
#endif
}
@ -2513,7 +2526,8 @@ void MacroAssembler::JumpJSFunction(Register function_object,
// from the code pointer table instead of going through the Code object. In
// this way, we avoid one memory load on this code path.
LoadCodeEntrypointViaCodePointer(
code, FieldMemOperand(function_object, JSFunction::kCodeOffset));
code, FieldMemOperand(function_object, JSFunction::kCodeOffset),
kJSEntrypointTag);
DCHECK_EQ(jump_mode, JumpMode::kJump);
// We jump through x17 here because for Branch Identification (BTI) we use
// "Call" (`bti c`) rather than "Jump" (`bti j`) landing pads for tail-called
@ -2524,7 +2538,7 @@ void MacroAssembler::JumpJSFunction(Register function_object,
#else
LoadTaggedField(code,
FieldMemOperand(function_object, JSFunction::kCodeOffset));
JumpCodeObject(code, jump_mode);
JumpCodeObject(code, kJSEntrypointTag, jump_mode);
#endif
}
@ -3479,8 +3493,8 @@ void MacroAssembler::CheckPageFlag(const Register& object, int mask,
ASM_CODE_COMMENT(this);
UseScratchRegisterScope temps(this);
Register scratch = temps.AcquireX();
And(scratch, object, ~kPageAlignmentMask);
Ldr(scratch, MemOperand(scratch, BasicMemoryChunk::kFlagsOffset));
And(scratch, object, ~MemoryChunkHeader::GetAlignmentMaskForAssembler());
Ldr(scratch, MemOperand(scratch, MemoryChunkLayout::kFlagsOffset));
if (cc == ne) {
TestAndBranchIfAnySet(scratch, mask, condition_met);
} else {
@ -3705,17 +3719,23 @@ void MacroAssembler::ResolveCodePointerHandle(Register destination,
Orr(destination, destination, Immediate(kHeapObjectTag));
}
void MacroAssembler::LoadCodeEntrypointViaCodePointer(
Register destination, MemOperand field_operand) {
void MacroAssembler::LoadCodeEntrypointViaCodePointer(Register destination,
MemOperand field_operand,
CodeEntrypointTag tag) {
DCHECK_NE(tag, kInvalidEntrypointTag);
ASM_CODE_COMMENT(this);
UseScratchRegisterScope temps(this);
Register table = temps.AcquireX();
Mov(table, ExternalReference::code_pointer_table_address());
Register scratch = temps.AcquireX();
Mov(scratch, ExternalReference::code_pointer_table_address());
Ldr(destination.W(), field_operand);
// TODO(saelo): can the offset computation be done more efficiently?
Mov(destination, Operand(destination, LSR, kCodePointerHandleShift));
Mov(destination, Operand(destination, LSL, kCodePointerTableEntrySizeLog2));
Ldr(destination, MemOperand(table, destination));
Ldr(destination, MemOperand(scratch, destination));
if (tag != 0) {
Mov(scratch, Immediate(tag));
Eor(destination, destination, scratch);
}
}
#endif // V8_ENABLE_SANDBOX

View File

@ -1063,9 +1063,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase {
void TailCallBuiltin(Builtin builtin, Condition cond = al);
// Load code entry point from the Code object.
void LoadCodeInstructionStart(Register destination, Register code_object);
void CallCodeObject(Register code_object);
void JumpCodeObject(Register code_object,
void LoadCodeInstructionStart(Register destination, Register code_object,
CodeEntrypointTag tag);
void CallCodeObject(Register code_object, CodeEntrypointTag tag);
void JumpCodeObject(Register code_object, CodeEntrypointTag tag,
JumpMode jump_mode = JumpMode::kJump);
// Convenience functions to call/jmp to the code of a JSFunction object.
@ -1083,25 +1084,24 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase {
DeoptimizeKind kind, Label* ret,
Label* jump_deoptimization_entry_label);
// Calls a C function.
// The called function is not allowed to trigger a
// Calls a C function and cleans up the space for arguments allocated
// by PrepareCallCFunction. The called function is not allowed to trigger a
// garbage collection, since that might move the code and invalidate the
// return address (unless this is somehow accounted for by the called
// function).
enum class SetIsolateDataSlots {
kNo,
kYes,
};
void CallCFunction(
int CallCFunction(
ExternalReference function, int num_reg_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);
void CallCFunction(
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes,
Label* return_location = nullptr);
int CallCFunction(
ExternalReference function, int num_reg_arguments,
int num_double_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);
void CallCFunction(
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes,
Label* return_location = nullptr);
int CallCFunction(
Register function, int num_reg_arguments, int num_double_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes,
Label* return_location = nullptr);
// Performs a truncating conversion of a floating point number as used by
// the JS bitwise operations. See ECMA-262 9.5: ToInt32.
@ -1632,7 +1632,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase {
// Only available when the sandbox is enabled as it requires the code pointer
// table.
void LoadCodeEntrypointViaCodePointer(Register destination,
MemOperand field_operand);
MemOperand field_operand,
CodeEntrypointTag tag);
#endif
// Load a protected pointer field.

View File

@ -1842,12 +1842,12 @@ void CodeStubAssembler::StoreExternalPointerToObject(TNode<HeapObject> object,
#endif // V8_ENABLE_SANDBOX
}
TNode<HeapObject> CodeStubAssembler::LoadTrustedPointerFromObject(
TNode<TrustedObject> CodeStubAssembler::LoadTrustedPointerFromObject(
TNode<HeapObject> object, int field_offset, IndirectPointerTag tag) {
#ifdef V8_ENABLE_SANDBOX
return LoadIndirectPointerFromObject(object, field_offset, tag);
#else
return LoadObjectField<HeapObject>(object, field_offset);
return LoadObjectField<TrustedObject>(object, field_offset);
#endif // V8_ENABLE_SANDBOX
}
@ -1858,7 +1858,7 @@ TNode<Code> CodeStubAssembler::LoadCodePointerFromObject(
}
#ifdef V8_ENABLE_SANDBOX
TNode<HeapObject> CodeStubAssembler::LoadIndirectPointerFromObject(
TNode<TrustedObject> CodeStubAssembler::LoadIndirectPointerFromObject(
TNode<HeapObject> object, int field_offset, IndirectPointerTag tag) {
TNode<IndirectPointerHandleT> handle =
LoadObjectField<IndirectPointerHandleT>(object, field_offset);
@ -1871,13 +1871,13 @@ TNode<BoolT> CodeStubAssembler::IsTrustedPointerHandle(
Int32Constant(0));
}
TNode<HeapObject> CodeStubAssembler::ResolveIndirectPointerHandle(
TNode<TrustedObject> CodeStubAssembler::ResolveIndirectPointerHandle(
TNode<IndirectPointerHandleT> handle, IndirectPointerTag tag) {
// The tag implies which pointer table to use.
if (tag == kUnknownIndirectPointerTag) {
// In this case we have to rely on the handle marking to determine which
// pointer table to use.
return Select<HeapObject>(
return Select<TrustedObject>(
IsTrustedPointerHandle(handle),
[=] { return ResolveTrustedPointerHandle(handle, tag); },
[=] { return ResolveCodePointerHandle(handle); });
@ -1903,7 +1903,7 @@ TNode<Code> CodeStubAssembler::ResolveCodePointerHandle(
return UncheckedCast<Code>(BitcastWordToTagged(value));
}
TNode<HeapObject> CodeStubAssembler::ResolveTrustedPointerHandle(
TNode<TrustedObject> CodeStubAssembler::ResolveTrustedPointerHandle(
TNode<IndirectPointerHandleT> handle, IndirectPointerTag tag) {
TNode<RawPtrT> table = ExternalConstant(
ExternalReference::trusted_pointer_table_base_address(isolate()));
@ -1919,7 +1919,7 @@ TNode<HeapObject> CodeStubAssembler::ResolveTrustedPointerHandle(
// to set it using a bitwise OR as it may or may not be set.
value =
UncheckedCast<UintPtrT>(WordOr(value, UintPtrConstant(kHeapObjectTag)));
return UncheckedCast<HeapObject>(BitcastWordToTagged(value));
return UncheckedCast<TrustedObject>(BitcastWordToTagged(value));
}
TNode<UintPtrT> CodeStubAssembler::ComputeCodePointerTableEntryOffset(
@ -1935,16 +1935,36 @@ TNode<UintPtrT> CodeStubAssembler::ComputeCodePointerTableEntryOffset(
}
TNode<RawPtrT> CodeStubAssembler::LoadCodeEntrypointViaCodePointerField(
TNode<HeapObject> object, TNode<IntPtrT> field_offset) {
TNode<HeapObject> object, TNode<IntPtrT> field_offset,
CodeEntrypointTag tag) {
TNode<IndirectPointerHandleT> handle =
LoadObjectField<IndirectPointerHandleT>(object, field_offset);
TNode<RawPtrT> table =
ExternalConstant(ExternalReference::code_pointer_table_address());
TNode<UintPtrT> offset = ComputeCodePointerTableEntryOffset(handle);
return Load<RawPtrT>(table, offset);
TNode<UintPtrT> entry = Load<UintPtrT>(table, offset);
if (tag != 0) {
entry = UncheckedCast<UintPtrT>(WordXor(entry, UintPtrConstant(tag)));
}
return UncheckedCast<RawPtrT>(UncheckedCast<WordT>(entry));
}
#endif // V8_ENABLE_SANDBOX
TNode<TrustedObject> CodeStubAssembler::LoadProtectedPointerFromObject(
TNode<TrustedObject> object, int offset) {
#ifdef V8_ENABLE_SANDBOX
TNode<RawPtrT> trusted_cage_base = LoadPointerFromRootRegister(
IntPtrConstant(IsolateData::trusted_cage_base_offset()));
TNode<UintPtrT> offset_from_cage_base =
ChangeUint32ToWord(LoadObjectField<Uint32T>(object, offset));
TNode<UintPtrT> pointer =
UncheckedCast<UintPtrT>(WordOr(trusted_cage_base, offset_from_cage_base));
return UncheckedCast<TrustedObject>(BitcastWordToTagged(pointer));
#else
return LoadObjectField<TrustedObject>(object, offset);
#endif
}
TNode<Object> CodeStubAssembler::LoadFromParentFrame(int offset) {
TNode<RawPtrT> frame_pointer = LoadParentFramePointer();
return LoadFullTagged(frame_pointer, IntPtrConstant(offset));
@ -2099,13 +2119,8 @@ TNode<HeapObject> CodeStubAssembler::LoadSlowProperties(
};
NodeGenerator<HeapObject> cast_properties = [=] {
TNode<HeapObject> dict = CAST(properties);
if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
CSA_DCHECK(this, Word32Or(IsSwissNameDictionary(dict),
IsGlobalDictionary(dict)));
} else {
CSA_DCHECK(this,
Word32Or(IsNameDictionary(dict), IsGlobalDictionary(dict)));
}
CSA_DCHECK(this,
Word32Or(IsPropertyDictionary(dict), IsGlobalDictionary(dict)));
return dict;
};
return Select<HeapObject>(TaggedIsSmi(properties), make_empty,
@ -2640,6 +2655,12 @@ TNode<IntPtrT> CodeStubAssembler::LoadArrayLength(
return LoadAndUntagWeakFixedArrayLength(array);
}
template <>
TNode<IntPtrT> CodeStubAssembler::LoadArrayLength(
TNode<TrustedFixedArray> array) {
return SmiUntag(LoadArrayCapacity(array));
}
template <typename Array, typename TIndex, typename TValue>
TNode<TValue> CodeStubAssembler::LoadArrayElement(TNode<Array> array,
int array_header_size,
@ -2673,6 +2694,9 @@ template V8_EXPORT_PRIVATE TNode<Smi> CodeStubAssembler::LoadArrayElement<
template V8_EXPORT_PRIVATE TNode<Context>
CodeStubAssembler::LoadArrayElement<ScriptContextTable, IntPtrT>(
TNode<ScriptContextTable>, int, TNode<IntPtrT>, int);
template V8_EXPORT_PRIVATE TNode<MaybeObject>
CodeStubAssembler::LoadArrayElement<TrustedFixedArray, IntPtrT>(
TNode<TrustedFixedArray>, int, TNode<IntPtrT>, int);
template <typename TIndex>
TNode<Object> CodeStubAssembler::LoadFixedArrayElement(
@ -3468,27 +3492,17 @@ TNode<BytecodeArray> CodeStubAssembler::LoadSharedFunctionInfoBytecodeArray(
this, Word32Equal(DecodeWord32<Code::KindField>(code_flags),
Int32Constant(static_cast<int>(CodeKind::BASELINE))));
#endif // DEBUG
TNode<HeapObject> baseline_data = LoadObjectField<HeapObject>(
TNode<HeapObject> baseline_data = LoadProtectedPointerFromObject(
code, Code::kDeoptimizationDataOrInterpreterDataOffset);
var_result = baseline_data;
// As long as InterpreterData objects still live inside the sandbox, Code
// references BytecodeArrays through their in-sandbox wrapper object.
static_assert(!kInterpreterDataObjectsLiveInTrustedSpace);
GotoIfNot(HasInstanceType(var_result.value(), BYTECODE_WRAPPER_TYPE),
&check_for_interpreter_data);
TNode<HeapObject> bytecode = LoadTrustedPointerFromObject(
var_result.value(), BytecodeWrapper::kBytecodeOffset,
kBytecodeArrayIndirectPointerTag);
var_result = bytecode;
Goto(&done);
}
Goto(&check_for_interpreter_data);
BIND(&check_for_interpreter_data);
GotoIfNot(HasInstanceType(var_result.value(), INTERPRETER_DATA_TYPE), &done);
TNode<BytecodeArray> bytecode_array = CAST(LoadTrustedPointerFromObject(
var_result.value(), InterpreterData::kBytecodeArrayOffset,
kBytecodeArrayIndirectPointerTag));
TNode<BytecodeArray> bytecode_array = CAST(LoadProtectedPointerFromObject(
CAST(var_result.value()), InterpreterData::kBytecodeArrayOffset));
var_result = bytecode_array;
Goto(&done);
@ -4229,6 +4243,40 @@ TNode<NameDictionary> CodeStubAssembler::AllocateNameDictionaryWithCapacity(
return result;
}
TNode<PropertyDictionary> CodeStubAssembler::AllocatePropertyDictionary(
int at_least_space_for) {
TNode<HeapObject> dict;
if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
dict = AllocateSwissNameDictionary(at_least_space_for);
} else {
dict = AllocateNameDictionary(at_least_space_for);
}
return TNode<PropertyDictionary>::UncheckedCast(dict);
}
TNode<PropertyDictionary> CodeStubAssembler::AllocatePropertyDictionary(
TNode<IntPtrT> at_least_space_for, AllocationFlags flags) {
TNode<HeapObject> dict;
if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
dict = AllocateSwissNameDictionary(at_least_space_for);
} else {
dict = AllocateNameDictionary(at_least_space_for, flags);
}
return TNode<PropertyDictionary>::UncheckedCast(dict);
}
TNode<PropertyDictionary>
CodeStubAssembler::AllocatePropertyDictionaryWithCapacity(
TNode<IntPtrT> capacity, AllocationFlags flags) {
TNode<HeapObject> dict;
if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
dict = AllocateSwissNameDictionaryWithCapacity(capacity);
} else {
dict = AllocateNameDictionaryWithCapacity(capacity, flags);
}
return TNode<PropertyDictionary>::UncheckedCast(dict);
}
TNode<NameDictionary> CodeStubAssembler::CopyNameDictionary(
TNode<NameDictionary> dictionary, Label* large_object_fallback) {
Comment("Copy boilerplate property dict");
@ -4423,9 +4471,8 @@ void CodeStubAssembler::InitializeJSObjectFromMap(
StoreObjectFieldRoot(object, JSObject::kPropertiesOrHashOffset,
RootIndex::kEmptyFixedArray);
} else {
CSA_DCHECK(this, Word32Or(Word32Or(Word32Or(IsPropertyArray(*properties),
IsNameDictionary(*properties)),
IsSwissNameDictionary(*properties)),
CSA_DCHECK(this, Word32Or(Word32Or(IsPropertyArray(*properties),
IsPropertyDictionary(*properties)),
IsEmptyFixedArray(*properties)));
StoreObjectFieldNoWriteBarrier(object, JSObject::kPropertiesOrHashOffset,
*properties);
@ -5013,9 +5060,9 @@ TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
#ifndef V8_ENABLE_SINGLE_GENERATION
#ifdef DEBUG
TNode<IntPtrT> object_word = BitcastTaggedToWord(to_elements);
TNode<IntPtrT> object_page = PageFromAddress(object_word);
TNode<IntPtrT> page_flags =
Load<IntPtrT>(object_page, IntPtrConstant(Page::kFlagsOffset));
TNode<IntPtrT> object_page_header = PageHeaderFromAddress(object_word);
TNode<IntPtrT> page_flags = Load<IntPtrT>(
object_page_header, IntPtrConstant(MemoryChunkLayout::kFlagsOffset));
CSA_DCHECK(
this,
WordNotEqual(
@ -5414,9 +5461,10 @@ void CodeStubAssembler::JumpIfPointersFromHereAreInteresting(
TNode<Object> object, Label* interesting) {
Label finished(this);
TNode<IntPtrT> object_word = BitcastTaggedToWord(object);
TNode<IntPtrT> object_page = PageFromAddress(object_word);
TNode<IntPtrT> page_flags = UncheckedCast<IntPtrT>(Load(
MachineType::IntPtr(), object_page, IntPtrConstant(Page::kFlagsOffset)));
TNode<IntPtrT> object_page_header = PageHeaderFromAddress(object_word);
TNode<IntPtrT> page_flags = UncheckedCast<IntPtrT>(
Load(MachineType::IntPtr(), object_page_header,
IntPtrConstant(MemoryChunkLayout::kFlagsOffset)));
Branch(
WordEqual(WordAnd(page_flags,
IntPtrConstant(
@ -7617,19 +7665,15 @@ TNode<BoolT> CodeStubAssembler::IsEphemeronHashTable(TNode<HeapObject> object) {
return HasInstanceType(object, EPHEMERON_HASH_TABLE_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsNameDictionary(TNode<HeapObject> object) {
return HasInstanceType(object, NAME_DICTIONARY_TYPE);
TNode<BoolT> CodeStubAssembler::IsPropertyDictionary(TNode<HeapObject> object) {
return HasInstanceType(object, PROPERTY_DICTIONARY_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsOrderedNameDictionary(
TNode<HeapObject> object) {
return HasInstanceType(object, ORDERED_NAME_DICTIONARY_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsSwissNameDictionary(
TNode<HeapObject> object) {
return HasInstanceType(object, SWISS_NAME_DICTIONARY_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsGlobalDictionary(TNode<HeapObject> object) {
return HasInstanceType(object, GLOBAL_DICTIONARY_TYPE);
}
@ -7823,10 +7867,10 @@ TNode<BoolT> CodeStubAssembler::IsNumberArrayIndex(TNode<Number> number) {
TNode<IntPtrT> CodeStubAssembler::LoadBasicMemoryChunkFlags(
TNode<HeapObject> object) {
TNode<IntPtrT> object_word = BitcastTaggedToWord(object);
TNode<IntPtrT> page = PageFromAddress(object_word);
TNode<IntPtrT> page_header = PageHeaderFromAddress(object_word);
return UncheckedCast<IntPtrT>(
Load(MachineType::Pointer(), page,
IntPtrConstant(BasicMemoryChunk::kFlagsOffset)));
Load(MachineType::Pointer(), page_header,
IntPtrConstant(MemoryChunkLayout::kFlagsOffset)));
}
template <typename TIndex>
@ -9410,7 +9454,8 @@ TNode<IntPtrT> CodeStubAssembler::NameToIndexHashTableLookup(
template <typename Dictionary>
void CodeStubAssembler::NameDictionaryLookup(
TNode<Dictionary> dictionary, TNode<Name> unique_name, Label* if_found,
TVariable<IntPtrT>* var_name_index, Label* if_not_found, LookupMode mode) {
TVariable<IntPtrT>* var_name_index, Label* if_not_found_no_insertion_index,
LookupMode mode, Label* if_not_found_with_insertion_index) {
static_assert(std::is_same<Dictionary, NameDictionary>::value ||
std::is_same<Dictionary, GlobalDictionary>::value ||
std::is_same<Dictionary, NameToIndexHashTable>::value,
@ -9418,8 +9463,13 @@ void CodeStubAssembler::NameDictionaryLookup(
DCHECK_IMPLIES(var_name_index != nullptr,
MachineType::PointerRepresentation() == var_name_index->rep());
DCHECK_IMPLIES(mode == kFindInsertionIndex, if_found == nullptr);
DCHECK_IMPLIES(if_not_found_with_insertion_index != nullptr,
var_name_index != nullptr);
Comment("NameDictionaryLookup");
CSA_DCHECK(this, IsUniqueName(unique_name));
if (if_not_found_with_insertion_index == nullptr) {
if_not_found_with_insertion_index = if_not_found_no_insertion_index;
}
Label if_not_computed(this, Label::kDeferred);
@ -9453,16 +9503,17 @@ void CodeStubAssembler::NameDictionaryLookup(
TNode<HeapObject> current =
CAST(UnsafeLoadFixedArrayElement(dictionary, index));
GotoIf(TaggedEqual(current, undefined), if_not_found);
GotoIf(TaggedEqual(current, undefined), if_not_found_with_insertion_index);
if (mode == kFindExisting) {
if (Dictionary::ShapeT::kMatchNeedsHoleCheck) {
if (Dictionary::TodoShape::kMatchNeedsHoleCheck) {
GotoIf(TaggedEqual(current, TheHoleConstant()), &next_probe);
}
current = LoadName<Dictionary>(current);
GotoIf(TaggedEqual(current, unique_name), if_found);
} else {
DCHECK_EQ(kFindInsertionIndex, mode);
GotoIf(TaggedEqual(current, TheHoleConstant()), if_not_found);
GotoIf(TaggedEqual(current, TheHoleConstant()),
if_not_found_with_insertion_index);
}
Goto(&next_probe);
@ -9507,14 +9558,19 @@ void CodeStubAssembler::NameDictionaryLookup(
std::make_pair(MachineType::Pointer(), isolate_ptr),
std::make_pair(MachineType::TaggedPointer(), dictionary),
std::make_pair(MachineType::TaggedPointer(), unique_name)));
if (var_name_index) *var_name_index = EntryToIndex<Dictionary>(entry);
if (mode == kFindExisting) {
GotoIf(IntPtrEqual(entry,
IntPtrConstant(InternalIndex::NotFound().raw_value())),
if_not_found);
if_not_found_no_insertion_index);
Goto(if_found);
} else {
Goto(if_not_found);
CSA_DCHECK(
this,
WordNotEqual(entry,
IntPtrConstant(InternalIndex::NotFound().raw_value())));
Goto(if_not_found_with_insertion_index);
}
}
}
@ -9524,10 +9580,11 @@ template V8_EXPORT_PRIVATE void
CodeStubAssembler::NameDictionaryLookup<NameDictionary>(TNode<NameDictionary>,
TNode<Name>, Label*,
TVariable<IntPtrT>*,
Label*, LookupMode);
Label*, LookupMode,
Label*);
template V8_EXPORT_PRIVATE void CodeStubAssembler::NameDictionaryLookup<
GlobalDictionary>(TNode<GlobalDictionary>, TNode<Name>, Label*,
TVariable<IntPtrT>*, Label*, LookupMode);
TVariable<IntPtrT>*, Label*, LookupMode, Label*);
TNode<Word32T> CodeStubAssembler::ComputeSeededHash(TNode<IntPtrT> key) {
const TNode<ExternalReference> function_addr =
@ -9547,10 +9604,13 @@ TNode<Word32T> CodeStubAssembler::ComputeSeededHash(TNode<IntPtrT> key) {
template <>
void CodeStubAssembler::NameDictionaryLookup(
TNode<SwissNameDictionary> dictionary, TNode<Name> unique_name,
Label* if_found, TVariable<IntPtrT>* var_name_index, Label* if_not_found,
LookupMode mode) {
Label* if_found, TVariable<IntPtrT>* var_name_index,
Label* if_not_found_no_insertion_index, LookupMode mode,
Label* if_not_found_with_insertion_index) {
// TODO(pthier): Support path for not found with valid insertion index for
// SwissNameDictionary.
SwissNameDictionaryFindEntry(dictionary, unique_name, if_found,
var_name_index, if_not_found);
var_name_index, if_not_found_no_insertion_index);
}
void CodeStubAssembler::NumberDictionaryLookup(
@ -9707,9 +9767,9 @@ void CodeStubAssembler::InsertEntry<GlobalDictionary>(
}
template <class Dictionary>
void CodeStubAssembler::AddToDictionary(TNode<Dictionary> dictionary,
TNode<Name> key, TNode<Object> value,
Label* bailout) {
void CodeStubAssembler::AddToDictionary(
TNode<Dictionary> dictionary, TNode<Name> key, TNode<Object> value,
Label* bailout, base::Optional<TNode<IntPtrT>> insertion_index) {
CSA_DCHECK(this, Word32BinaryNot(IsEmptyPropertyDictionary(dictionary)));
TNode<Smi> capacity = GetCapacity<Dictionary>(dictionary);
TNode<Smi> nof = GetNumberOfElements<Dictionary>(dictionary);
@ -9737,16 +9797,21 @@ void CodeStubAssembler::AddToDictionary(TNode<Dictionary> dictionary,
SetNextEnumerationIndex<Dictionary>(dictionary, new_enum_index);
SetNumberOfElements<Dictionary>(dictionary, new_nof);
TVARIABLE(IntPtrT, var_key_index);
FindInsertionEntry<Dictionary>(dictionary, key, &var_key_index);
InsertEntry<Dictionary>(dictionary, key, value, var_key_index.value(),
enum_index);
if (insertion_index.has_value()) {
InsertEntry<Dictionary>(dictionary, key, value, *insertion_index,
enum_index);
} else {
TVARIABLE(IntPtrT, var_key_index);
FindInsertionEntry<Dictionary>(dictionary, key, &var_key_index);
InsertEntry<Dictionary>(dictionary, key, value, var_key_index.value(),
enum_index);
}
}
template <>
void CodeStubAssembler::AddToDictionary(TNode<SwissNameDictionary> dictionary,
TNode<Name> key, TNode<Object> value,
Label* bailout) {
void CodeStubAssembler::AddToDictionary(
TNode<SwissNameDictionary> dictionary, TNode<Name> key, TNode<Object> value,
Label* bailout, base::Optional<TNode<IntPtrT>> insertion_index) {
PropertyDetails d(PropertyKind::kData, NONE,
PropertyDetails::kConstIfDictConstnessTracking);
@ -9765,11 +9830,13 @@ void CodeStubAssembler::AddToDictionary(TNode<SwissNameDictionary> dictionary,
Goto(&not_private);
BIND(&not_private);
// TODO(pthier): Use insertion_index if it was provided.
SwissNameDictionaryAdd(dictionary, key, value, var_details.value(), bailout);
}
template void CodeStubAssembler::AddToDictionary<NameDictionary>(
TNode<NameDictionary>, TNode<Name>, TNode<Object>, Label*);
TNode<NameDictionary>, TNode<Name>, TNode<Object>, Label*,
base::Optional<TNode<IntPtrT>>);
template <class Dictionary>
TNode<Smi> CodeStubAssembler::GetNumberOfElements(
@ -11083,9 +11150,9 @@ TNode<Object> CodeStubAssembler::GetInterestingProperty(
TNode<Object> properties =
LoadObjectField(holder, JSObject::kPropertiesOrHashOffset);
CSA_DCHECK(this, TaggedIsNotSmi(properties));
CSA_DCHECK(this, IsPropertyDictionary(CAST(properties)));
// TODO(pthier): Support swiss dictionaries.
if constexpr (!V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
CSA_DCHECK(this, IsNameDictionary(CAST(properties)));
TNode<Smi> flags =
GetNameDictionaryFlags<NameDictionary>(CAST(properties));
GotoIf(IsSetSmi(flags,
@ -12748,10 +12815,10 @@ void CodeStubAssembler::TrapAllocationMemento(TNode<JSObject> object,
TNode<IntPtrT> object_word = BitcastTaggedToWord(object);
// TODO(v8:11641): Skip TrapAllocationMemento when allocation-site
// tracking is disabled.
TNode<IntPtrT> object_page = PageFromAddress(object_word);
TNode<IntPtrT> object_page_header = PageHeaderFromAddress(object_word);
{
TNode<IntPtrT> page_flags =
Load<IntPtrT>(object_page, IntPtrConstant(Page::kFlagsOffset));
TNode<IntPtrT> page_flags = Load<IntPtrT>(
object_page_header, IntPtrConstant(MemoryChunkLayout::kFlagsOffset));
GotoIf(WordEqual(
WordAnd(page_flags,
IntPtrConstant(MemoryChunk::kIsInYoungGenerationMask)),
@ -12767,20 +12834,23 @@ void CodeStubAssembler::TrapAllocationMemento(TNode<JSObject> object,
TNode<IntPtrT> memento_last_word = IntPtrAdd(
object_word, IntPtrConstant(kMementoLastWordOffset - kHeapObjectTag));
TNode<IntPtrT> memento_last_word_page = PageFromAddress(memento_last_word);
TNode<IntPtrT> memento_last_word_page_header =
PageHeaderFromAddress(memento_last_word);
TNode<IntPtrT> new_space_top = Load<IntPtrT>(new_space_top_address);
TNode<IntPtrT> new_space_top_page = PageFromAddress(new_space_top);
TNode<IntPtrT> new_space_top_page_header =
PageHeaderFromAddress(new_space_top);
// If the object is in new space, we need to check whether respective
// potential memento object is on the same page as the current top.
GotoIf(WordEqual(memento_last_word_page, new_space_top_page), &top_check);
GotoIf(WordEqual(memento_last_word_page_header, new_space_top_page_header),
&top_check);
// The object is on a different page than allocation top. Bail out if the
// object sits on the page boundary as no memento can follow and we cannot
// touch the memory following it.
Branch(WordEqual(object_page, memento_last_word_page), &map_check,
&no_memento_found);
Branch(WordEqual(object_page_header, memento_last_word_page_header),
&map_check, &no_memento_found);
// If top is on the same page as the current object, we need to check whether
// we are below top.
@ -12804,9 +12874,22 @@ void CodeStubAssembler::TrapAllocationMemento(TNode<JSObject> object,
Comment("] TrapAllocationMemento");
}
TNode<IntPtrT> CodeStubAssembler::PageHeaderFromAddress(
TNode<IntPtrT> address) {
DCHECK(!V8_ENABLE_THIRD_PARTY_HEAP_BOOL);
return WordAnd(
address,
IntPtrConstant(~MemoryChunkHeader::GetAlignmentMaskForAssembler()));
}
TNode<IntPtrT> CodeStubAssembler::PageFromPageHeader(TNode<IntPtrT> address) {
DCHECK(!V8_ENABLE_THIRD_PARTY_HEAP_BOOL);
return address;
}
TNode<IntPtrT> CodeStubAssembler::PageFromAddress(TNode<IntPtrT> address) {
DCHECK(!V8_ENABLE_THIRD_PARTY_HEAP_BOOL);
return WordAnd(address, IntPtrConstant(~kPageAlignmentMask));
return PageFromPageHeader(PageHeaderFromAddress(address));
}
TNode<AllocationSite> CodeStubAssembler::CreateAllocationSiteInFeedbackVector(
@ -13230,6 +13313,18 @@ TNode<Context> CodeStubAssembler::GotoIfHasContextExtensionUpToDepth(
Goto(&context_search);
BIND(&context_search);
{
#if DEBUG
// Const tracking let data is stored in the extension slot of a
// ScriptContext - however, it's unrelated to the sloppy eval variable
// extension. We should never iterate through a ScriptContext here.
auto scope_info = LoadScopeInfo(cur_context.value());
TNode<Int32T> flags =
LoadAndUntagToWord32ObjectField(scope_info, ScopeInfo::kFlagsOffset);
auto scope_type = DecodeWord32<ScopeInfo::ScopeTypeBits>(flags);
CSA_DCHECK(this, Word32NotEqual(scope_type,
Int32Constant(ScopeType::SCRIPT_SCOPE)));
#endif
// Check if context has an extension slot.
TNode<BoolT> has_extension =
LoadScopeInfoHasExtensionField(LoadScopeInfo(cur_context.value()));
@ -16301,8 +16396,8 @@ TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode(
CSA_DCHECK(this,
Word32Equal(data_type, Int32Constant(INTERPRETER_DATA_TYPE)));
{
TNode<Code> trampoline = LoadCodePointerFromObject(
CAST(sfi_data), InterpreterData::kInterpreterTrampolineOffset);
TNode<Code> trampoline = CAST(LoadProtectedPointerFromObject(
CAST(sfi_data), InterpreterData::kInterpreterTrampolineOffset));
sfi_code = trampoline;
}
Goto(&done);
@ -16329,12 +16424,13 @@ TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode(
return sfi_code.value();
}
TNode<RawPtrT> CodeStubAssembler::LoadCodeInstructionStart(TNode<Code> code) {
TNode<RawPtrT> CodeStubAssembler::LoadCodeInstructionStart(
TNode<Code> code, CodeEntrypointTag tag) {
#ifdef V8_ENABLE_SANDBOX
// In this case, the entrypoint is stored in the code pointer table entry
// referenced via the Code object's 'self' indirect pointer.
return LoadCodeEntrypointViaCodePointerField(
code, Code::kSelfIndirectPointerOffset);
code, Code::kSelfIndirectPointerOffset, tag);
#else
return LoadObjectField<RawPtrT>(code, Code::kInstructionStartOffset);
#endif
@ -16439,15 +16535,14 @@ TNode<Map> CodeStubAssembler::CheckEnumCache(TNode<JSReceiver> receiver,
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85149
// TODO(miladfarca): Use `if constexpr` once all compilers handle this
// properly.
CSA_DCHECK(this, Word32Or(IsPropertyDictionary(properties),
IsGlobalDictionary(properties)));
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
CSA_DCHECK(this, Word32Or(IsSwissNameDictionary(properties),
IsGlobalDictionary(properties)));
length = Select<Smi>(
IsSwissNameDictionary(properties),
IsPropertyDictionary(properties),
[=] {
return GetNumberOfElements(
UncheckedCast<SwissNameDictionary>(properties));
UncheckedCast<PropertyDictionary>(properties));
},
[=] {
return GetNumberOfElements(
@ -16455,8 +16550,6 @@ TNode<Map> CodeStubAssembler::CheckEnumCache(TNode<JSReceiver> receiver,
});
} else {
CSA_DCHECK(this, Word32Or(IsNameDictionary(properties),
IsGlobalDictionary(properties)));
static_assert(static_cast<int>(NameDictionary::kNumberOfElementsIndex) ==
static_cast<int>(GlobalDictionary::kNumberOfElementsIndex));
length = GetNumberOfElements(UncheckedCast<HashTableBase>(properties));

View File

@ -18,6 +18,7 @@
#include "src/objects/arguments.h"
#include "src/objects/bigint.h"
#include "src/objects/cell.h"
#include "src/objects/dictionary.h"
#include "src/objects/feedback-vector.h"
#include "src/objects/heap-number.h"
#include "src/objects/hole.h"
@ -358,6 +359,14 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
#define CSA_SLOW_DCHECK(csa, ...) ((void)0)
#endif
// Similar to SBXCHECK in C++, these become a CSA_CHECK in sandbox-enabled
// builds, otherwise a CSA_DCHECK.
#ifdef V8_ENABLE_SANDBOX
#define CSA_SBXCHECK(csa, ...) CSA_CHECK(csa, __VA_ARGS__)
#else
#define CSA_SBXCHECK(csa, ...) CSA_DCHECK(csa, __VA_ARGS__)
#endif
// Provides JavaScript-specific "macro-assembler" functionality on top of the
// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
// it's possible to add JavaScript-specific useful CodeAssembler "macros"
@ -922,7 +931,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
void FastCheck(TNode<BoolT> condition);
TNode<RawPtrT> LoadCodeInstructionStart(TNode<Code> code);
TNode<RawPtrT> LoadCodeInstructionStart(TNode<Code> code,
CodeEntrypointTag tag);
TNode<BoolT> IsMarkedForDeoptimization(TNode<Code> code);
// The following Call wrappers call an object according to the semantics that
@ -1193,9 +1203,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Load a trusted pointer field.
// When the sandbox is enabled, these are indirect pointers using the trusted
// pointer table. Otherwise they are regular tagged fields.
TNode<HeapObject> LoadTrustedPointerFromObject(TNode<HeapObject> object,
int offset,
IndirectPointerTag tag);
TNode<TrustedObject> LoadTrustedPointerFromObject(TNode<HeapObject> object,
int offset,
IndirectPointerTag tag);
// Load a code pointer field.
// These are special versions of trusted pointers that, when the sandbox is
@ -1204,9 +1214,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
#ifdef V8_ENABLE_SANDBOX
// Load an indirect pointer field.
TNode<HeapObject> LoadIndirectPointerFromObject(TNode<HeapObject> object,
int offset,
IndirectPointerTag tag);
TNode<TrustedObject> LoadIndirectPointerFromObject(TNode<HeapObject> object,
int offset,
IndirectPointerTag tag);
// Determines whether the given indirect pointer handle is a trusted pointer
// handle or a code pointer handle.
@ -1214,14 +1224,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Retrieve the heap object referenced by the given indirect pointer handle,
// which can either be a trusted pointer handle or a code pointer handle.
TNode<HeapObject> ResolveIndirectPointerHandle(
TNode<TrustedObject> ResolveIndirectPointerHandle(
TNode<IndirectPointerHandleT> handle, IndirectPointerTag tag);
// Retrieve the Code object referenced by the given trusted pointer handle.
TNode<Code> ResolveCodePointerHandle(TNode<IndirectPointerHandleT> handle);
// Retrieve the heap object referenced by the given trusted pointer handle.
TNode<HeapObject> ResolveTrustedPointerHandle(
TNode<TrustedObject> ResolveTrustedPointerHandle(
TNode<IndirectPointerHandleT> handle, IndirectPointerTag tag);
// Helper function to compute the offset into the code pointer table from a
@ -1233,14 +1243,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Only available when the sandbox is enabled as it requires the code pointer
// table.
TNode<RawPtrT> LoadCodeEntrypointViaCodePointerField(TNode<HeapObject> object,
int offset) {
return LoadCodeEntrypointViaCodePointerField(object,
IntPtrConstant(offset));
int offset,
CodeEntrypointTag tag) {
return LoadCodeEntrypointViaCodePointerField(object, IntPtrConstant(offset),
tag);
}
TNode<RawPtrT> LoadCodeEntrypointViaCodePointerField(TNode<HeapObject> object,
TNode<IntPtrT> offset);
TNode<IntPtrT> offset,
CodeEntrypointTag tag);
#endif
TNode<TrustedObject> LoadProtectedPointerFromObject(
TNode<TrustedObject> object, int offset);
TNode<RawPtrT> LoadForeignForeignAddressPtr(TNode<Foreign> object) {
return LoadExternalPointerFromObject(object, Foreign::kForeignAddressOffset,
kForeignForeignAddressTag);
@ -1289,11 +1304,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<WasmInternalFunction> object) {
#ifdef V8_ENABLE_SANDBOX
return LoadCodeEntrypointViaCodePointerField(
object, WasmInternalFunction::kCodeOffset);
object, WasmInternalFunction::kCodeOffset, kWasmEntrypointTag);
#else
TNode<Code> code =
LoadObjectField<Code>(object, WasmInternalFunction::kCodeOffset);
return LoadCodeInstructionStart(code);
return LoadCodeInstructionStart(code, kWasmEntrypointTag);
#endif // V8_ENABLE_SANDBOX
}
@ -2192,6 +2207,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
AllocationFlags = AllocationFlag::kNone);
TNode<NameDictionary> AllocateNameDictionaryWithCapacity(
TNode<IntPtrT> capacity, AllocationFlags = AllocationFlag::kNone);
TNode<PropertyDictionary> AllocatePropertyDictionary(int at_least_space_for);
TNode<PropertyDictionary> AllocatePropertyDictionary(
TNode<IntPtrT> at_least_space_for,
AllocationFlags = AllocationFlag::kNone);
TNode<PropertyDictionary> AllocatePropertyDictionaryWithCapacity(
TNode<IntPtrT> capacity, AllocationFlags = AllocationFlag::kNone);
TNode<NameDictionary> CopyNameDictionary(TNode<NameDictionary> dictionary,
Label* large_object_fallback);
@ -2865,7 +2888,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsConstructorMap(TNode<Map> map);
TNode<BoolT> IsConstructor(TNode<HeapObject> object);
TNode<BoolT> IsDeprecatedMap(TNode<Map> map);
TNode<BoolT> IsNameDictionary(TNode<HeapObject> object);
TNode<BoolT> IsPropertyDictionary(TNode<HeapObject> object);
TNode<BoolT> IsOrderedNameDictionary(TNode<HeapObject> object);
TNode<BoolT> IsGlobalDictionary(TNode<HeapObject> object);
TNode<BoolT> IsExtensibleMap(TNode<Map> map);
@ -2978,7 +3001,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsStringInstanceType(TNode<Int32T> instance_type);
TNode<BoolT> IsString(TNode<HeapObject> object);
TNode<BoolT> IsSeqOneByteString(TNode<HeapObject> object);
TNode<BoolT> IsSwissNameDictionary(TNode<HeapObject> object);
TNode<BoolT> IsSymbolInstanceType(TNode<Int32T> instance_type);
TNode<BoolT> IsInternalizedStringInstanceType(TNode<Int32T> instance_type);
@ -3511,24 +3533,40 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
template <class Dictionary>
void SetNameDictionaryFlags(TNode<Dictionary>, TNode<Smi> flags);
// Looks up an entry in a NameDictionaryBase successor. If the entry is found
// control goes to {if_found} and {var_name_index} contains an index of the
// key field of the entry found. If the key is not found control goes to
// {if_not_found}.
enum LookupMode { kFindExisting, kFindInsertionIndex };
template <typename Dictionary>
TNode<HeapObject> LoadName(TNode<HeapObject> key);
// Looks up an entry in a NameDictionaryBase successor.
// For {mode} == kFindExisting:
// If the entry is found control goes to {if_found} and {var_name_index}
// contains an index of the key field of the entry found.
// If the key is not found and {if_not_found_with_insertion_index} is
// provided, control goes to {if_not_found_with_insertion_index} and
// {var_name_index} contains the index of the key field to insert the given
// name at.
// Otherwise control goes to {if_not_found_no_insertion_index}.
// For {mode} == kFindInsertionIndex:
// {if_not_found_no_insertion_index} and {if_not_found_with_insertion_index}
// are treated equally. If {if_not_found_with_insertion_index} is provided,
// control goes to {if_not_found_with_insertion_index}, otherwise control
// goes to {if_not_found_no_insertion_index}. In both cases {var_name_index}
// contains the index of the key field to insert the given name at.
template <typename Dictionary>
void NameDictionaryLookup(TNode<Dictionary> dictionary,
TNode<Name> unique_name, Label* if_found,
TVariable<IntPtrT>* var_name_index,
Label* if_not_found,
LookupMode mode = kFindExisting);
Label* if_not_found_no_insertion_index,
LookupMode mode = kFindExisting,
Label* if_not_found_with_insertion_index = nullptr);
TNode<Word32T> ComputeSeededHash(TNode<IntPtrT> key);
// Looks up an entry in a NameDictionaryBase successor. If the entry is found
// control goes to {if_found} and {var_name_index} contains an index of the
// key field of the entry found. If the key is not found control goes to
// {if_not_found}.
void NumberDictionaryLookup(TNode<NumberDictionary> dictionary,
TNode<IntPtrT> intptr_index, Label* if_found,
TVariable<IntPtrT>* var_entry,
@ -3548,8 +3586,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Smi> enum_index);
template <class Dictionary>
void AddToDictionary(TNode<Dictionary> dictionary, TNode<Name> key,
TNode<Object> value, Label* bailout);
void AddToDictionary(
TNode<Dictionary> dictionary, TNode<Name> key, TNode<Object> value,
Label* bailout,
base::Optional<TNode<IntPtrT>> insertion_index = base::nullopt);
// Tries to check if {object} has own {unique_name} property.
void TryHasOwnProperty(TNode<HeapObject> object, TNode<Map> map,
@ -3875,6 +3915,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
void TrapAllocationMemento(TNode<JSObject> object, Label* memento_found);
// Helpers to look up MemoryChunk/Page metadata for a given address.
// Equivalent to MemoryChunkHeader::FromAddress().
TNode<IntPtrT> PageHeaderFromAddress(TNode<IntPtrT> address);
// Equivalent to MemoryChunkHeader::MemoryChunk().
TNode<IntPtrT> PageFromPageHeader(TNode<IntPtrT> address);
// Equivalent to BasicMemoryChunk::FromAddress().
TNode<IntPtrT> PageFromAddress(TNode<IntPtrT> address);
// Store a weak in-place reference into the FeedbackVector.

View File

@ -1720,8 +1720,10 @@ BackgroundCompileTask::BackgroundCompileTask(
BackgroundCompileTask::~BackgroundCompileTask() = default;
namespace {
void SetScriptFieldsFromDetails(Isolate* isolate, Tagged<Script> script,
const ScriptDetails& script_details,
ScriptDetails script_details,
DisallowGarbageCollection* no_gc) {
Handle<Object> script_name;
if (script_details.name_obj.ToHandle(&script_name)) {
@ -1747,8 +1749,6 @@ void SetScriptFieldsFromDetails(Isolate* isolate, Tagged<Script> script,
}
}
namespace {
#ifdef ENABLE_SLOW_DCHECKS
// A class which traverses the object graph for a newly compiled Script and
@ -2032,34 +2032,44 @@ class ConstantPoolPointerForwarder {
for (Handle<BytecodeArray> bytecode_array : bytecode_arrays_to_update_) {
local_heap_->Safepoint();
DisallowGarbageCollection no_gc;
Tagged<FixedArray> constant_pool = bytecode_array->constant_pool();
IterateConstantPool(constant_pool);
IterateConstantPool(bytecode_array->constant_pool());
}
}
bool HasAnythingToForward() const { return !forwarding_table_.empty(); }
private:
void IterateConstantPool(Tagged<FixedArray> constant_pool) {
for (int i = 0, length = constant_pool->length(); i < length; ++i) {
Tagged<Object> obj = constant_pool->get(i);
if (IsSmi(obj)) continue;
Tagged<HeapObject> heap_obj = HeapObject::cast(obj);
if (IsFixedArray(heap_obj, cage_base_)) {
// Constant pools can have nested fixed arrays, but such relationships
// are acyclic and never more than a few layers deep, so recursion is
// fine here.
IterateConstantPool(FixedArray::cast(heap_obj));
} else if (IsSharedFunctionInfo(heap_obj, cage_base_)) {
auto it = forwarding_table_.find(
SharedFunctionInfo::cast(heap_obj)->function_literal_id());
if (it != forwarding_table_.end()) {
constant_pool->set(i, *it->second);
}
template <typename TArray>
void IterateConstantPoolEntry(Tagged<TArray> constant_pool, int i) {
Tagged<Object> obj = constant_pool->get(i);
if (IsSmi(obj)) return;
Tagged<HeapObject> heap_obj = HeapObject::cast(obj);
if (IsFixedArray(heap_obj, cage_base_)) {
// Constant pools can have nested fixed arrays, but such relationships
// are acyclic and never more than a few layers deep, so recursion is
// fine here.
IterateConstantPoolNestedArray(FixedArray::cast(heap_obj));
} else if (IsSharedFunctionInfo(heap_obj, cage_base_)) {
auto it = forwarding_table_.find(
SharedFunctionInfo::cast(heap_obj)->function_literal_id());
if (it != forwarding_table_.end()) {
constant_pool->set(i, *it->second);
}
}
}
void IterateConstantPool(Tagged<TrustedFixedArray> constant_pool) {
for (int i = 0, length = constant_pool->length(); i < length; ++i) {
IterateConstantPoolEntry(constant_pool, i);
}
}
void IterateConstantPoolNestedArray(Tagged<FixedArray> nested_array) {
for (int i = 0, length = nested_array->length(); i < length; ++i) {
IterateConstantPoolEntry(nested_array, i);
}
}
PtrComprCageBase cage_base_;
LocalHeap* local_heap_;
std::vector<Handle<BytecodeArray>> bytecode_arrays_to_update_;
@ -2450,10 +2460,10 @@ void BackgroundDeserializeTask::MergeWithExistingScript() {
MaybeHandle<SharedFunctionInfo> BackgroundDeserializeTask::Finish(
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details) {
ScriptOriginOptions origin_options) {
return CodeSerializer::FinishOffThreadDeserialize(
isolate, std::move(off_thread_data_), &cached_data_, source,
script_details, &background_merge_task_);
origin_options, &background_merge_task_);
}
// ----------------------------------------------------------------------------
@ -3630,8 +3640,8 @@ MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl(
"V8.CompileDeserialize");
if (deserialize_task) {
// If there's a cache consume task, finish it.
maybe_result =
deserialize_task->Finish(isolate, source, script_details);
maybe_result = deserialize_task->Finish(isolate, source,
script_details.origin_options);
// It is possible at this point that there is a Script object for this
// script in the compilation cache (held in the variable maybe_script),
// which does not match maybe_result->script(). This could happen any of
@ -3652,7 +3662,8 @@ MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl(
// would be non-trivial.
} else {
maybe_result = CodeSerializer::Deserialize(
isolate, cached_data, source, script_details, maybe_script);
isolate, cached_data, source, script_details.origin_options,
maybe_script);
}
bool consuming_code_cache_succeeded = false;
@ -3828,7 +3839,7 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileDeserialize");
maybe_result = CodeSerializer::Deserialize(isolate, cached_data, source,
script_details);
script_details.origin_options);
bool consuming_code_cache_succeeded = false;
if (maybe_result.ToHandle(&result)) {
is_compiled_scope = result->is_compiled_scope(isolate);

View File

@ -682,7 +682,7 @@ class V8_EXPORT_PRIVATE BackgroundDeserializeTask {
MaybeHandle<SharedFunctionInfo> Finish(Isolate* isolate,
Handle<String> source,
const ScriptDetails& script_details);
ScriptOriginOptions origin_options);
bool rejected() const { return cached_data_.rejected(); }

View File

@ -288,26 +288,19 @@ void ExternalReferenceTable::AddStubCache(Isolate* isolate, int* index) {
kIsolateAddressReferenceCount,
*index);
StubCache* load_stub_cache = isolate->load_stub_cache();
// Stub cache tables
Add(load_stub_cache->key_reference(StubCache::kPrimary).address(), index);
Add(load_stub_cache->value_reference(StubCache::kPrimary).address(), index);
Add(load_stub_cache->map_reference(StubCache::kPrimary).address(), index);
Add(load_stub_cache->key_reference(StubCache::kSecondary).address(), index);
Add(load_stub_cache->value_reference(StubCache::kSecondary).address(), index);
Add(load_stub_cache->map_reference(StubCache::kSecondary).address(), index);
std::array<StubCache*, 3> stub_caches{isolate->load_stub_cache(),
isolate->store_stub_cache(),
isolate->define_own_stub_cache()};
StubCache* store_stub_cache = isolate->store_stub_cache();
// Stub cache tables
Add(store_stub_cache->key_reference(StubCache::kPrimary).address(), index);
Add(store_stub_cache->value_reference(StubCache::kPrimary).address(), index);
Add(store_stub_cache->map_reference(StubCache::kPrimary).address(), index);
Add(store_stub_cache->key_reference(StubCache::kSecondary).address(), index);
Add(store_stub_cache->value_reference(StubCache::kSecondary).address(),
index);
Add(store_stub_cache->map_reference(StubCache::kSecondary).address(), index);
for (StubCache* stub_cache : stub_caches) {
Add(stub_cache->key_reference(StubCache::kPrimary).address(), index);
Add(stub_cache->value_reference(StubCache::kPrimary).address(), index);
Add(stub_cache->map_reference(StubCache::kPrimary).address(), index);
Add(stub_cache->key_reference(StubCache::kSecondary).address(), index);
Add(stub_cache->value_reference(StubCache::kSecondary).address(), index);
Add(stub_cache->map_reference(StubCache::kSecondary).address(), index);
}
CHECK_EQ(kSizeIsolateIndependent + kExternalReferenceCountIsolateDependent +
kIsolateAddressReferenceCount + kStubCacheReferenceCount,

View File

@ -38,7 +38,7 @@ class ExternalReferenceTable {
Accessors::kAccessorInfoCount + Accessors::kAccessorGetterCount +
Accessors::kAccessorSetterCount + Accessors::kAccessorCallbackCount;
// The number of stub cache external references, see AddStubCache.
static constexpr int kStubCacheReferenceCount = 12;
static constexpr int kStubCacheReferenceCount = 6 * 3; // 3 stub caches
static constexpr int kStatsCountersReferenceCount =
#define SC(...) +1
STATS_COUNTER_NATIVE_CODE_LIST(SC);

View File

@ -1948,18 +1948,20 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
}
}
void MacroAssembler::CallCFunction(ExternalReference function,
int num_arguments,
SetIsolateDataSlots set_isolate_data_slots) {
int MacroAssembler::CallCFunction(ExternalReference function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots,
Label* return_location) {
// Note: The "CallCFunction" code comment will be generated by the other
// CallCFunction method called below.
// Trashing eax is ok as it will be the return value.
Move(eax, Immediate(function));
CallCFunction(eax, num_arguments);
return CallCFunction(eax, num_arguments, set_isolate_data_slots,
return_location);
}
void MacroAssembler::CallCFunction(Register function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots) {
int MacroAssembler::CallCFunction(Register function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots,
Label* return_location) {
ASM_CODE_COMMENT(this);
DCHECK_LE(num_arguments, kMaxCParameters);
DCHECK(has_frame());
@ -1968,6 +1970,8 @@ void MacroAssembler::CallCFunction(Register function, int num_arguments,
CheckStackAlignment();
}
Label get_pc;
if (set_isolate_data_slots == SetIsolateDataSlots::kYes) {
// Save the frame pointer and PC so that the stack layout remains iterable,
// even without an ExitFrame which normally exists between JS and C frames.
@ -1976,8 +1980,7 @@ void MacroAssembler::CallCFunction(Register function, int num_arguments,
Register scratch = ecx;
if (function == eax) pc_scratch = edx;
if (function == ecx) scratch = edx;
PushPC();
pop(pc_scratch);
LoadLabelAddress(pc_scratch, &get_pc);
// See x64 code for reasoning about how to address the isolate data fields.
DCHECK_IMPLIES(!root_array_available(), isolate() != nullptr);
@ -1998,6 +2001,9 @@ void MacroAssembler::CallCFunction(Register function, int num_arguments,
}
call(function);
int call_pc_offset = pc_offset();
bind(&get_pc);
if (return_location) bind(return_location);
if (set_isolate_data_slots == SetIsolateDataSlots::kYes) {
// We don't unset the PC; the FP is the source of truth.
@ -2016,6 +2022,8 @@ void MacroAssembler::CallCFunction(Register function, int num_arguments,
} else {
add(esp, Immediate(num_arguments * kSystemPointerSize));
}
return call_pc_offset;
}
void MacroAssembler::PushPC() {
@ -2112,7 +2120,8 @@ Operand MacroAssembler::EntryFromBuiltinAsOperand(Builtin builtin) {
}
void MacroAssembler::LoadCodeInstructionStart(Register destination,
Register code_object) {
Register code_object,
CodeEntrypointTag tag) {
ASM_CODE_COMMENT(this);
mov(destination, FieldOperand(code_object, Code::kInstructionStartOffset));
}
@ -2185,21 +2194,28 @@ void MacroAssembler::LoadLabelAddress(Register dst, Label* lbl) {
DCHECK(pc_offset() - kStart == kInsDelta);
}
void MacroAssembler::MemoryChunkHeaderFromObject(Register object,
Register header) {
constexpr intptr_t alignment_mask =
MemoryChunkHeader::GetAlignmentMaskForAssembler();
if (header == object) {
and_(header, Immediate(~alignment_mask));
} else {
mov(header, Immediate(~alignment_mask));
and_(header, object);
}
}
void MacroAssembler::CheckPageFlag(Register object, Register scratch, int mask,
Condition cc, Label* condition_met,
Label::Distance condition_met_distance) {
ASM_CODE_COMMENT(this);
DCHECK(cc == zero || cc == not_zero);
if (scratch == object) {
and_(scratch, Immediate(~kPageAlignmentMask));
} else {
mov(scratch, Immediate(~kPageAlignmentMask));
and_(scratch, object);
}
MemoryChunkHeaderFromObject(object, scratch);
if (mask < (1 << kBitsPerByte)) {
test_b(Operand(scratch, BasicMemoryChunk::kFlagsOffset), Immediate(mask));
test_b(Operand(scratch, MemoryChunkLayout::kFlagsOffset), Immediate(mask));
} else {
test(Operand(scratch, BasicMemoryChunk::kFlagsOffset), Immediate(mask));
test(Operand(scratch, MemoryChunkLayout::kFlagsOffset), Immediate(mask));
}
j(cc, condition_met, condition_met_distance);
}

View File

@ -74,6 +74,7 @@ class V8_EXPORT_PRIVATE MacroAssembler
public:
using SharedMacroAssembler<MacroAssembler>::SharedMacroAssembler;
void MemoryChunkHeaderFromObject(Register object, Register header);
void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
Label* condition_met,
Label::Distance condition_met_distance = Label::kFar);
@ -162,7 +163,8 @@ class V8_EXPORT_PRIVATE MacroAssembler
void TailCallBuiltin(Builtin builtin);
// Load the code entry point from the Code object.
void LoadCodeInstructionStart(Register destination, Register code_object);
void LoadCodeInstructionStart(Register destination, Register code_object,
CodeEntrypointTag = kDefaultCodeEntrypointTag);
void CallCodeObject(Register code_object);
void JumpCodeObject(Register code_object,
JumpMode jump_mode = JumpMode::kJump);
@ -234,16 +236,14 @@ class V8_EXPORT_PRIVATE MacroAssembler
// garbage collection, since that might move the code and invalidate the
// return address (unless this is somehow accounted for by the called
// function).
enum class SetIsolateDataSlots {
kNo,
kYes,
};
void CallCFunction(
int CallCFunction(
ExternalReference function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);
void CallCFunction(
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes,
Label* return_location = nullptr);
int CallCFunction(
Register function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes,
Label* return_location = nullptr);
void ShlPair(Register high, Register low, uint8_t imm8);
void ShlPair_cl(Register high, Register low);

View File

@ -115,8 +115,8 @@ void StaticCallInterfaceDescriptor<DerivedDescriptor>::Initialize(
DCHECK_GE(return_registers.size(), DerivedDescriptor::kReturnCount);
DCHECK_GE(return_double_registers.size(), DerivedDescriptor::kReturnCount);
data->InitializeRegisters(
DerivedDescriptor::flags(), DerivedDescriptor::kReturnCount,
DerivedDescriptor::GetParameterCount(),
DerivedDescriptor::flags(), DerivedDescriptor::kEntrypointTag,
DerivedDescriptor::kReturnCount, DerivedDescriptor::GetParameterCount(),
DerivedDescriptor::kStackArgumentOrder,
DerivedDescriptor::GetRegisterParameterCount(), registers.data(),
double_registers.data(), return_registers.data(),
@ -138,7 +138,7 @@ StaticCallInterfaceDescriptor<DerivedDescriptor>::GetReturnCount() {
static_assert(
DerivedDescriptor::kReturnCount >= 0,
"DerivedDescriptor subclass should override return count with a value "
"that is greater than 0");
"that is greater than or equal to 0");
return DerivedDescriptor::kReturnCount;
}
@ -150,7 +150,7 @@ StaticCallInterfaceDescriptor<DerivedDescriptor>::GetParameterCount() {
static_assert(
DerivedDescriptor::kParameterCount >= 0,
"DerivedDescriptor subclass should override parameter count with a "
"value that is greater than 0");
"value that is greater than or equal to 0");
return DerivedDescriptor::kParameterCount;
}
@ -502,7 +502,8 @@ constexpr auto OnStackReplacementDescriptor::registers() {
constexpr auto
MaglevOptimizeCodeOrTailCallOptimizedCodeSlotDescriptor::registers() {
#ifdef V8_ENABLE_MAGLEV
return RegisterArray(FlagsRegister(), FeedbackVectorRegister());
return RegisterArray(FlagsRegister(), FeedbackVectorRegister(),
TemporaryRegister());
#else
return DefaultRegisterArray();
#endif

View File

@ -37,7 +37,7 @@ void CheckRegisterConfiguration(int count, const Register* registers,
#endif
void CallInterfaceDescriptorData::InitializeRegisters(
Flags flags, int return_count, int parameter_count,
Flags flags, CodeEntrypointTag tag, int return_count, int parameter_count,
StackArgumentOrder stack_order, int register_parameter_count,
const Register* registers, const DoubleRegister* double_registers,
const Register* return_registers,
@ -52,6 +52,7 @@ void CallInterfaceDescriptorData::InitializeRegisters(
#endif
flags_ = flags;
tag_ = tag;
stack_order_ = stack_order;
return_count_ = return_count;
param_count_ = parameter_count;

View File

@ -53,6 +53,8 @@ namespace internal {
V(CallWithSpread) \
V(CallWithSpread_Baseline) \
V(CallWithSpread_WithFeedback) \
V(CCall) \
V(CEntryDummy) \
V(CEntry1ArgvOnStack) \
V(CloneObjectBaseline) \
V(CloneObjectWithVector) \
@ -117,6 +119,7 @@ namespace internal {
V(NewHeapNumber) \
V(NoContext) \
V(OnStackReplacement) \
V(RegExpTrampoline) \
V(RestartFrameTrampoline) \
V(ResumeGenerator) \
V(ResumeGeneratorBaseline) \
@ -141,6 +144,7 @@ namespace internal {
V(UnaryOp_Baseline) \
V(UnaryOp_WithFeedback) \
V(Void) \
V(WasmDummy) \
V(WasmFloat32ToNumber) \
V(WasmFloat64ToTagged) \
V(WasmJSToWasmWrapper) \
@ -191,8 +195,8 @@ class V8_EXPORT_PRIVATE CallInterfaceDescriptorData {
// The passed registers are owned by the caller, and their lifetime is
// expected to exceed that of this data. In practice, they are expected to
// be in a static local.
void InitializeRegisters(Flags flags, int return_count, int parameter_count,
StackArgumentOrder stack_order,
void InitializeRegisters(Flags flags, CodeEntrypointTag tag, int return_count,
int parameter_count, StackArgumentOrder stack_order,
int register_parameter_count,
const Register* registers,
const DoubleRegister* double_registers,
@ -217,6 +221,7 @@ class V8_EXPORT_PRIVATE CallInterfaceDescriptorData {
}
Flags flags() const { return flags_; }
CodeEntrypointTag tag() const { return tag_; }
int return_count() const { return return_count_; }
int param_count() const { return param_count_; }
int register_param_count() const { return register_param_count_; }
@ -271,6 +276,7 @@ class V8_EXPORT_PRIVATE CallInterfaceDescriptorData {
int return_count_ = kUninitializedCount;
int param_count_ = kUninitializedCount;
Flags flags_ = kNoFlags;
CodeEntrypointTag tag_ = kDefaultCodeEntrypointTag;
StackArgumentOrder stack_order_ = StackArgumentOrder::kDefault;
// Specifying the set of registers that could be used by the register
@ -354,6 +360,8 @@ class V8_EXPORT_PRIVATE CallInterfaceDescriptor {
Flags flags() const { return data()->flags(); }
CodeEntrypointTag tag() const { return data()->tag(); }
bool HasContextParameter() const {
return (flags() & CallInterfaceDescriptorData::kNoContext) == 0;
}
@ -474,6 +482,9 @@ class StaticCallInterfaceDescriptor : public CallInterfaceDescriptor {
static constexpr bool kNoContext = false;
static constexpr bool kAllowVarArgs = false;
static constexpr bool kNoStackScan = false;
// TODO(saelo): we should not have a default value here to force all interface
// descriptors to define a (unique) tag.
static constexpr CodeEntrypointTag kEntrypointTag = kDefaultCodeEntrypointTag;
static constexpr auto kStackArgumentOrder = StackArgumentOrder::kDefault;
// The set of registers available to the parameters, as a
@ -752,6 +763,7 @@ constexpr EmptyDoubleRegisterArray DoubleRegisterArray() { return {}; }
class V8_EXPORT_PRIVATE VoidDescriptor
: public StaticCallInterfaceDescriptor<VoidDescriptor> {
public:
static constexpr CodeEntrypointTag kEntrypointTag = kInvalidEntrypointTag;
// The void descriptor could (and indeed probably should) also be NO_CONTEXT,
// but this breaks some code assembler unittests.
DEFINE_PARAMETERS()
@ -761,10 +773,6 @@ class V8_EXPORT_PRIVATE VoidDescriptor
static constexpr auto registers();
};
// Dummy descriptor that marks builtins with C calling convention.
// TODO(jgruber): Define real descriptors for C calling conventions.
using CCallDescriptor = VoidDescriptor;
// Marks deoptimization entry builtins. Precise calling conventions currently
// differ based on the platform.
// TODO(jgruber): Once this is unified, we could create a better description
@ -777,15 +785,39 @@ using JSEntryDescriptor = VoidDescriptor;
// TODO(jgruber): Consider filling in the details here; however, this doesn't
// make too much sense as long as the descriptor isn't used or verified.
using CEntryDummyDescriptor = VoidDescriptor;
using ContinueToBuiltinDescriptor = VoidDescriptor;
// Dummy descriptor that marks builtins with C calling convention.
// TODO(jgruber): Define real descriptors for C calling conventions.
class CCallDescriptor : public StaticCallInterfaceDescriptor<CCallDescriptor> {
public:
static constexpr CodeEntrypointTag kEntrypointTag = kDefaultCodeEntrypointTag;
DEFINE_PARAMETERS()
DEFINE_PARAMETER_TYPES()
DECLARE_DESCRIPTOR(CCallDescriptor)
};
// TODO(jgruber): Consider filling in the details here; however, this doesn't
// make too much sense as long as the descriptor isn't used or verified.
using ContinueToBuiltinDescriptor = VoidDescriptor;
class CEntryDummyDescriptor
: public StaticCallInterfaceDescriptor<CEntryDummyDescriptor> {
public:
static constexpr CodeEntrypointTag kEntrypointTag = kDefaultCodeEntrypointTag;
DEFINE_PARAMETERS()
DEFINE_PARAMETER_TYPES()
DECLARE_DESCRIPTOR(CEntryDummyDescriptor)
};
// TODO(wasm): Consider filling in details / defining real descriptors for all
// builtins still using this placeholder descriptor.
using WasmDummyDescriptor = VoidDescriptor;
class WasmDummyDescriptor
: public StaticCallInterfaceDescriptor<WasmDummyDescriptor> {
public:
static constexpr CodeEntrypointTag kEntrypointTag = kWasmEntrypointTag;
DEFINE_PARAMETERS()
DEFINE_PARAMETER_TYPES()
DECLARE_DESCRIPTOR(WasmDummyDescriptor)
};
class AllocateDescriptor
: public StaticCallInterfaceDescriptor<AllocateDescriptor> {
@ -819,6 +851,17 @@ class JSTrampolineDescriptor
DECLARE_JS_COMPATIBLE_DESCRIPTOR(JSTrampolineDescriptor)
};
// Descriptor used for code using the RegExp calling convention, in particular
// the RegExp interpreter trampolines.
class RegExpTrampolineDescriptor
: public StaticCallInterfaceDescriptor<RegExpTrampolineDescriptor> {
public:
static constexpr CodeEntrypointTag kEntrypointTag = kRegExpEntrypointTag;
DEFINE_PARAMETERS()
DEFINE_PARAMETER_TYPES()
DECLARE_DESCRIPTOR(RegExpTrampolineDescriptor)
};
class ContextOnlyDescriptor
: public StaticCallInterfaceDescriptor<ContextOnlyDescriptor> {
public:
@ -953,14 +996,17 @@ class MaglevOptimizeCodeOrTailCallOptimizedCodeSlotDescriptor
: public StaticCallInterfaceDescriptor<
MaglevOptimizeCodeOrTailCallOptimizedCodeSlotDescriptor> {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kFlags, kFeedbackVector)
DEFINE_PARAMETERS_NO_CONTEXT(kFlags, kFeedbackVector, kTemporary)
DEFINE_PARAMETER_TYPES(MachineType::Int32(), // kFlags
MachineType::TaggedPointer()) // kFeedbackVector
MachineType::TaggedPointer(), // kFeedbackVector
MachineType::AnyTagged()) // kTemporary
DECLARE_DESCRIPTOR(MaglevOptimizeCodeOrTailCallOptimizedCodeSlotDescriptor)
static constexpr inline Register FlagsRegister();
static constexpr inline Register FeedbackVectorRegister();
static constexpr inline Register TemporaryRegister();
static constexpr inline auto registers();
};
@ -1009,6 +1055,8 @@ class StoreBaselineDescriptor
class StoreTransitionDescriptor
: public StaticCallInterfaceDescriptor<StoreTransitionDescriptor> {
public:
static constexpr CodeEntrypointTag kEntrypointTag = kICHandlerEntrypointTag;
DEFINE_PARAMETERS(kReceiver, kName, kMap, kValue, kSlot, kVector)
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kReceiver
MachineType::AnyTagged(), // kName
@ -1026,6 +1074,8 @@ class StoreTransitionDescriptor
class StoreWithVectorDescriptor
: public StaticCallInterfaceDescriptor<StoreWithVectorDescriptor> {
public:
static constexpr CodeEntrypointTag kEntrypointTag = kICHandlerEntrypointTag;
DEFINE_PARAMETERS(kReceiver, kName, kValue, kSlot, kVector)
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kReceiver
MachineType::AnyTagged(), // kName
@ -1127,6 +1177,8 @@ class DefineKeyedOwnWithVectorDescriptor
class LoadWithVectorDescriptor
: public StaticCallInterfaceDescriptor<LoadWithVectorDescriptor> {
public:
static constexpr CodeEntrypointTag kEntrypointTag = kICHandlerEntrypointTag;
// TODO(v8:9497): Revert the Machine type for kSlot to the
// TaggedSigned once Torque can emit better call descriptors
DEFINE_PARAMETERS(kReceiver, kName, kSlot, kVector)

View File

@ -4555,8 +4555,9 @@ void MacroAssembler::CheckPageFlag(Register object, int mask, Condition cc,
UseScratchRegisterScope temps(this);
temps.Include(t8);
Register scratch = temps.Acquire();
And(scratch, object, Operand(~kPageAlignmentMask));
Ld_d(scratch, MemOperand(scratch, BasicMemoryChunk::kFlagsOffset));
And(scratch, object,
Operand(~MemoryChunkHeader::GetAlignmentMaskForAssembler()));
Ld_d(scratch, MemOperand(scratch, MemoryChunkLayout::kFlagsOffset));
And(scratch, scratch, Operand(mask));
Branch(condition_met, cc, scratch, Operand(zero_reg));
}

View File

@ -518,10 +518,6 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase {
// garbage collection, since that might move the code and invalidate the
// return address (unless this is somehow accounted for by the called
// function).
enum class SetIsolateDataSlots {
kNo,
kYes,
};
void CallCFunction(
ExternalReference function, int num_arguments,
SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes);

View File

@ -45,6 +45,11 @@ enum class ComparisonMode {
kFullPointer,
};
enum class SetIsolateDataSlots {
kNo,
kYes,
};
// This is the only place allowed to include the platform-specific headers.
#define INCLUDED_FROM_MACRO_ASSEMBLER_H
#if V8_TARGET_ARCH_IA32

View File

@ -6172,8 +6172,9 @@ void MacroAssembler::CallCFunctionHelper(
void MacroAssembler::CheckPageFlag(Register object, Register scratch, int mask,
Condition cc, Label* condition_met) {
ASM_CODE_COMMENT(this);
And(scratch, object, Operand(~kPageAlignmentMask));
Ld(scratch, MemOperand(scratch, BasicMemoryChunk::kFlagsOffset));
And(scratch, object,
Operand(~MemoryChunkHeader::GetAlignmentMaskForAssembler()));
Ld(scratch, MemOperand(scratch, MemoryChunkLayout::kFlagsOffset));
And(scratch, scratch, Operand(mask));
Branch(condition_met, cc, scratch, Operand(zero_reg));
}

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