summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
authorMyles Borins <mylesborins@google.com>2019-09-24 11:56:38 -0400
committerMyles Borins <myles.borins@gmail.com>2019-10-07 03:19:23 -0400
commitf7f6c928c1c9c136b7926f892b8a2fda11d8b4b2 (patch)
treef5edbccb3ffda2573d70a6e291e7157f290e0ae0 /deps
parentffd22e81983056d09c064c59343a0e488236272d (diff)
downloadandroid-node-v8-f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2.tar.gz
android-node-v8-f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2.tar.bz2
android-node-v8-f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2.zip
deps: update V8 to 7.8.279.9
PR-URL: https://github.com/nodejs/node/pull/29694 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Diffstat (limited to 'deps')
-rw-r--r--deps/v8/.gitignore2
-rw-r--r--deps/v8/.gn3
-rw-r--r--deps/v8/AUTHORS3
-rw-r--r--deps/v8/BUILD.gn73
-rw-r--r--deps/v8/ChangeLog1450
-rw-r--r--deps/v8/DEPS64
-rw-r--r--deps/v8/OWNERS42
-rw-r--r--deps/v8/base/trace_event/common/trace_event_common.h52
-rw-r--r--deps/v8/benchmarks/OWNERS2
-rw-r--r--deps/v8/build_overrides/OWNERS2
-rw-r--r--deps/v8/build_overrides/build.gni15
-rw-r--r--deps/v8/custom_deps/OWNERS2
-rw-r--r--deps/v8/gni/OWNERS2
-rw-r--r--deps/v8/gni/snapshot_toolchain.gni9
-rw-r--r--deps/v8/include/OWNERS4
-rw-r--r--deps/v8/include/libplatform/v8-tracing.h2
-rw-r--r--deps/v8/include/v8-internal.h15
-rw-r--r--deps/v8/include/v8-platform.h8
-rw-r--r--deps/v8/include/v8-profiler.h117
-rw-r--r--deps/v8/include/v8-version.h6
-rw-r--r--deps/v8/include/v8.h335
-rw-r--r--deps/v8/include/v8config.h17
-rw-r--r--deps/v8/infra/OWNERS2
-rw-r--r--deps/v8/infra/testing/builders.pyl21
-rw-r--r--deps/v8/src/OWNERS6
-rw-r--r--deps/v8/src/api/OWNERS2
-rw-r--r--deps/v8/src/api/api-inl.h2
-rw-r--r--deps/v8/src/api/api-natives.cc102
-rw-r--r--deps/v8/src/api/api-natives.h11
-rw-r--r--deps/v8/src/api/api.cc177
-rw-r--r--deps/v8/src/api/api.h18
-rw-r--r--deps/v8/src/ast/ast-traversal-visitor.h6
-rw-r--r--deps/v8/src/ast/ast.cc12
-rw-r--r--deps/v8/src/ast/ast.h291
-rw-r--r--deps/v8/src/ast/modules.cc7
-rw-r--r--deps/v8/src/ast/prettyprinter.cc80
-rw-r--r--deps/v8/src/ast/prettyprinter.h8
-rw-r--r--deps/v8/src/ast/scopes.cc165
-rw-r--r--deps/v8/src/ast/scopes.h95
-rw-r--r--deps/v8/src/ast/source-range-ast-visitor.cc8
-rw-r--r--deps/v8/src/ast/source-range-ast-visitor.h1
-rw-r--r--deps/v8/src/ast/variables.h58
-rw-r--r--deps/v8/src/base/address-region.h7
-rw-r--r--deps/v8/src/base/flags.h6
-rw-r--r--deps/v8/src/base/page-allocator.cc4
-rw-r--r--deps/v8/src/base/page-allocator.h2
-rw-r--r--deps/v8/src/base/platform/mutex.h2
-rw-r--r--deps/v8/src/base/platform/platform-cygwin.cc10
-rw-r--r--deps/v8/src/base/platform/platform-posix.cc25
-rw-r--r--deps/v8/src/base/platform/platform-win32.cc20
-rw-r--r--deps/v8/src/base/platform/platform.h7
-rw-r--r--deps/v8/src/base/utils/random-number-generator.cc7
-rw-r--r--deps/v8/src/builtins/OWNERS2
-rw-r--r--deps/v8/src/builtins/arguments.tq2
-rw-r--r--deps/v8/src/builtins/arm/builtins-arm.cc26
-rw-r--r--deps/v8/src/builtins/arm64/builtins-arm64.cc53
-rw-r--r--deps/v8/src/builtins/array-copywithin.tq4
-rw-r--r--deps/v8/src/builtins/array-every.tq35
-rw-r--r--deps/v8/src/builtins/array-filter.tq35
-rw-r--r--deps/v8/src/builtins/array-find.tq40
-rw-r--r--deps/v8/src/builtins/array-findindex.tq38
-rw-r--r--deps/v8/src/builtins/array-foreach.tq29
-rw-r--r--deps/v8/src/builtins/array-join.tq104
-rw-r--r--deps/v8/src/builtins/array-lastindexof.tq26
-rw-r--r--deps/v8/src/builtins/array-map.tq43
-rw-r--r--deps/v8/src/builtins/array-of.tq9
-rw-r--r--deps/v8/src/builtins/array-reduce-right.tq95
-rw-r--r--deps/v8/src/builtins/array-reduce.tq95
-rw-r--r--deps/v8/src/builtins/array-reverse.tq24
-rw-r--r--deps/v8/src/builtins/array-shift.tq57
-rw-r--r--deps/v8/src/builtins/array-slice.tq29
-rw-r--r--deps/v8/src/builtins/array-some.tq35
-rw-r--r--deps/v8/src/builtins/array-splice.tq29
-rw-r--r--deps/v8/src/builtins/array-unshift.tq36
-rw-r--r--deps/v8/src/builtins/array.tq29
-rw-r--r--deps/v8/src/builtins/base.tq755
-rw-r--r--deps/v8/src/builtins/boolean.tq4
-rw-r--r--deps/v8/src/builtins/builtins-arguments-gen.cc74
-rw-r--r--deps/v8/src/builtins/builtins-array-gen.cc707
-rw-r--r--deps/v8/src/builtins/builtins-array.cc21
-rw-r--r--deps/v8/src/builtins/builtins-async-function-gen.cc6
-rw-r--r--deps/v8/src/builtins/builtins-async-gen.cc59
-rw-r--r--deps/v8/src/builtins/builtins-async-generator-gen.cc71
-rw-r--r--deps/v8/src/builtins/builtins-async-iterator-gen.cc28
-rw-r--r--deps/v8/src/builtins/builtins-bigint-gen.cc36
-rw-r--r--deps/v8/src/builtins/builtins-bigint.cc2
-rw-r--r--deps/v8/src/builtins/builtins-call-gen.cc42
-rw-r--r--deps/v8/src/builtins/builtins-collections-gen.cc440
-rw-r--r--deps/v8/src/builtins/builtins-console-gen.cc3
-rw-r--r--deps/v8/src/builtins/builtins-constructor-gen.cc184
-rw-r--r--deps/v8/src/builtins/builtins-conversion-gen.cc38
-rw-r--r--deps/v8/src/builtins/builtins-date-gen.cc40
-rw-r--r--deps/v8/src/builtins/builtins-date.cc21
-rw-r--r--deps/v8/src/builtins/builtins-definitions.h48
-rw-r--r--deps/v8/src/builtins/builtins-function-gen.cc54
-rw-r--r--deps/v8/src/builtins/builtins-function.cc11
-rw-r--r--deps/v8/src/builtins/builtins-generator-gen.cc22
-rw-r--r--deps/v8/src/builtins/builtins-global-gen.cc4
-rw-r--r--deps/v8/src/builtins/builtins-handler-gen.cc50
-rw-r--r--deps/v8/src/builtins/builtins-ic-gen.cc2
-rw-r--r--deps/v8/src/builtins/builtins-internal-gen.cc81
-rw-r--r--deps/v8/src/builtins/builtins-intl-gen.cc51
-rw-r--r--deps/v8/src/builtins/builtins-iterator-gen.cc34
-rw-r--r--deps/v8/src/builtins/builtins-iterator-gen.h17
-rw-r--r--deps/v8/src/builtins/builtins-lazy-gen.cc4
-rw-r--r--deps/v8/src/builtins/builtins-math-gen.cc33
-rw-r--r--deps/v8/src/builtins/builtins-math.cc61
-rw-r--r--deps/v8/src/builtins/builtins-microtask-queue-gen.cc88
-rw-r--r--deps/v8/src/builtins/builtins-number-gen.cc103
-rw-r--r--deps/v8/src/builtins/builtins-object-gen.cc393
-rw-r--r--deps/v8/src/builtins/builtins-object.cc5
-rw-r--r--deps/v8/src/builtins/builtins-promise-gen.cc477
-rw-r--r--deps/v8/src/builtins/builtins-promise-gen.h15
-rw-r--r--deps/v8/src/builtins/builtins-proxy-gen.cc65
-rw-r--r--deps/v8/src/builtins/builtins-reflect-gen.cc6
-rw-r--r--deps/v8/src/builtins/builtins-regexp-gen.cc941
-rw-r--r--deps/v8/src/builtins/builtins-regexp-gen.h116
-rw-r--r--deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc40
-rw-r--r--deps/v8/src/builtins/builtins-sharedarraybuffer.cc81
-rw-r--r--deps/v8/src/builtins/builtins-string-gen.cc565
-rw-r--r--deps/v8/src/builtins/builtins-string-gen.h53
-rw-r--r--deps/v8/src/builtins/builtins-string.cc12
-rw-r--r--deps/v8/src/builtins/builtins-symbol-gen.cc22
-rw-r--r--deps/v8/src/builtins/builtins-symbol.cc2
-rw-r--r--deps/v8/src/builtins/builtins-typed-array-gen.cc44
-rw-r--r--deps/v8/src/builtins/builtins-wasm-gen.cc50
-rw-r--r--deps/v8/src/builtins/builtins-weak-refs.cc7
-rw-r--r--deps/v8/src/builtins/builtins.cc14
-rw-r--r--deps/v8/src/builtins/builtins.h2
-rw-r--r--deps/v8/src/builtins/collections.tq8
-rw-r--r--deps/v8/src/builtins/data-view.tq164
-rw-r--r--deps/v8/src/builtins/extras-utils.tq13
-rw-r--r--deps/v8/src/builtins/frames.tq2
-rw-r--r--deps/v8/src/builtins/growable-fixed-array-gen.cc2
-rw-r--r--deps/v8/src/builtins/ia32/builtins-ia32.cc7
-rw-r--r--deps/v8/src/builtins/internal-coverage.tq2
-rw-r--r--deps/v8/src/builtins/iterator.tq33
-rw-r--r--deps/v8/src/builtins/math.tq96
-rw-r--r--deps/v8/src/builtins/mips/builtins-mips.cc28
-rw-r--r--deps/v8/src/builtins/mips64/builtins-mips64.cc29
-rw-r--r--deps/v8/src/builtins/object-fromentries.tq14
-rw-r--r--deps/v8/src/builtins/object.tq57
-rw-r--r--deps/v8/src/builtins/ppc/builtins-ppc.cc33
-rw-r--r--deps/v8/src/builtins/proxy-constructor.tq4
-rw-r--r--deps/v8/src/builtins/proxy-delete-property.tq8
-rw-r--r--deps/v8/src/builtins/proxy-get-property.tq6
-rw-r--r--deps/v8/src/builtins/proxy-get-prototype-of.tq8
-rw-r--r--deps/v8/src/builtins/proxy-has-property.tq6
-rw-r--r--deps/v8/src/builtins/proxy-is-extensible.tq4
-rw-r--r--deps/v8/src/builtins/proxy-prevent-extensions.tq10
-rw-r--r--deps/v8/src/builtins/proxy-revocable.tq5
-rw-r--r--deps/v8/src/builtins/proxy-set-property.tq20
-rw-r--r--deps/v8/src/builtins/proxy-set-prototype-of.tq8
-rw-r--r--deps/v8/src/builtins/reflect.tq51
-rw-r--r--deps/v8/src/builtins/regexp-match.tq49
-rw-r--r--deps/v8/src/builtins/regexp-replace.tq25
-rw-r--r--deps/v8/src/builtins/regexp-source.tq30
-rw-r--r--deps/v8/src/builtins/regexp-test.tq37
-rw-r--r--deps/v8/src/builtins/regexp.tq153
-rw-r--r--deps/v8/src/builtins/s390/builtins-s390.cc29
-rw-r--r--deps/v8/src/builtins/setup-builtins-internal.cc13
-rw-r--r--deps/v8/src/builtins/string-endswith.tq8
-rw-r--r--deps/v8/src/builtins/string-html.tq30
-rw-r--r--deps/v8/src/builtins/string-iterator.tq4
-rw-r--r--deps/v8/src/builtins/string-pad.tq111
-rw-r--r--deps/v8/src/builtins/string-repeat.tq2
-rw-r--r--deps/v8/src/builtins/string-slice.tq2
-rw-r--r--deps/v8/src/builtins/string-startswith.tq8
-rw-r--r--deps/v8/src/builtins/string-substring.tq4
-rw-r--r--deps/v8/src/builtins/string.tq76
-rw-r--r--deps/v8/src/builtins/torque-internal.tq106
-rw-r--r--deps/v8/src/builtins/typed-array-createtypedarray.tq30
-rw-r--r--deps/v8/src/builtins/typed-array-every.tq8
-rw-r--r--deps/v8/src/builtins/typed-array-filter.tq10
-rw-r--r--deps/v8/src/builtins/typed-array-find.tq8
-rw-r--r--deps/v8/src/builtins/typed-array-findindex.tq8
-rw-r--r--deps/v8/src/builtins/typed-array-foreach.tq8
-rw-r--r--deps/v8/src/builtins/typed-array-reduce.tq33
-rw-r--r--deps/v8/src/builtins/typed-array-reduceright.tq33
-rw-r--r--deps/v8/src/builtins/typed-array-slice.tq4
-rw-r--r--deps/v8/src/builtins/typed-array-some.tq8
-rw-r--r--deps/v8/src/builtins/typed-array-subarray.tq2
-rw-r--r--deps/v8/src/builtins/typed-array.tq35
-rw-r--r--deps/v8/src/builtins/x64/builtins-x64.cc28
-rw-r--r--deps/v8/src/codegen/DEPS2
-rw-r--r--deps/v8/src/codegen/arm/assembler-arm.cc27
-rw-r--r--deps/v8/src/codegen/arm/assembler-arm.h2
-rw-r--r--deps/v8/src/codegen/arm/macro-assembler-arm.cc34
-rw-r--r--deps/v8/src/codegen/arm/macro-assembler-arm.h2
-rw-r--r--deps/v8/src/codegen/arm64/assembler-arm64.cc25
-rw-r--r--deps/v8/src/codegen/arm64/assembler-arm64.h32
-rw-r--r--deps/v8/src/codegen/arm64/constants-arm64.h12
-rw-r--r--deps/v8/src/codegen/arm64/instructions-arm64.cc6
-rw-r--r--deps/v8/src/codegen/arm64/instructions-arm64.h2
-rw-r--r--deps/v8/src/codegen/arm64/macro-assembler-arm64.cc104
-rw-r--r--deps/v8/src/codegen/arm64/macro-assembler-arm64.h68
-rw-r--r--deps/v8/src/codegen/arm64/register-arm64.h14
-rw-r--r--deps/v8/src/codegen/code-factory.cc4
-rw-r--r--deps/v8/src/codegen/code-stub-assembler.cc2251
-rw-r--r--deps/v8/src/codegen/code-stub-assembler.h454
-rw-r--r--deps/v8/src/codegen/compiler.cc129
-rw-r--r--deps/v8/src/codegen/compiler.h22
-rw-r--r--deps/v8/src/codegen/external-reference.cc31
-rw-r--r--deps/v8/src/codegen/external-reference.h15
-rw-r--r--deps/v8/src/codegen/handler-table.h4
-rw-r--r--deps/v8/src/codegen/ia32/assembler-ia32.h4
-rw-r--r--deps/v8/src/codegen/ia32/macro-assembler-ia32.cc55
-rw-r--r--deps/v8/src/codegen/ia32/macro-assembler-ia32.h3
-rw-r--r--deps/v8/src/codegen/interface-descriptors.cc10
-rw-r--r--deps/v8/src/codegen/interface-descriptors.h38
-rw-r--r--deps/v8/src/codegen/macro-assembler.h2
-rw-r--r--deps/v8/src/codegen/mips/assembler-mips.h4
-rw-r--r--deps/v8/src/codegen/mips/macro-assembler-mips.cc24
-rw-r--r--deps/v8/src/codegen/mips/macro-assembler-mips.h4
-rw-r--r--deps/v8/src/codegen/mips64/assembler-mips64.h4
-rw-r--r--deps/v8/src/codegen/mips64/macro-assembler-mips64.cc12
-rw-r--r--deps/v8/src/codegen/mips64/macro-assembler-mips64.h1
-rw-r--r--deps/v8/src/codegen/optimized-compilation-info.cc1
-rw-r--r--deps/v8/src/codegen/pending-optimization-table.cc50
-rw-r--r--deps/v8/src/codegen/pending-optimization-table.h9
-rw-r--r--deps/v8/src/codegen/ppc/macro-assembler-ppc.cc12
-rw-r--r--deps/v8/src/codegen/ppc/macro-assembler-ppc.h1
-rw-r--r--deps/v8/src/codegen/register.cc16
-rw-r--r--deps/v8/src/codegen/register.h3
-rw-r--r--deps/v8/src/codegen/s390/assembler-s390.cc2
-rw-r--r--deps/v8/src/codegen/s390/macro-assembler-s390.cc12
-rw-r--r--deps/v8/src/codegen/s390/macro-assembler-s390.h1
-rw-r--r--deps/v8/src/codegen/safepoint-table.cc14
-rw-r--r--deps/v8/src/codegen/safepoint-table.h12
-rw-r--r--deps/v8/src/codegen/source-position-table.cc4
-rw-r--r--deps/v8/src/codegen/turbo-assembler.h2
-rw-r--r--deps/v8/src/codegen/x64/assembler-x64.cc40
-rw-r--r--deps/v8/src/codegen/x64/assembler-x64.h16
-rw-r--r--deps/v8/src/codegen/x64/macro-assembler-x64.cc30
-rw-r--r--deps/v8/src/codegen/x64/macro-assembler-x64.h3
-rw-r--r--deps/v8/src/codegen/x64/sse-instr.h10
-rw-r--r--deps/v8/src/common/OWNERS2
-rw-r--r--deps/v8/src/common/assert-scope.cc12
-rw-r--r--deps/v8/src/common/assert-scope.h2
-rw-r--r--deps/v8/src/common/globals.h71
-rw-r--r--deps/v8/src/common/message-template.h25
-rw-r--r--deps/v8/src/common/ptr-compr-inl.h7
-rw-r--r--deps/v8/src/compiler/access-builder.cc124
-rw-r--r--deps/v8/src/compiler/access-builder.h25
-rw-r--r--deps/v8/src/compiler/access-info.cc106
-rw-r--r--deps/v8/src/compiler/access-info.h15
-rw-r--r--deps/v8/src/compiler/allocation-builder-inl.h16
-rw-r--r--deps/v8/src/compiler/allocation-builder.h8
-rw-r--r--deps/v8/src/compiler/backend/arm/code-generator-arm.cc86
-rw-r--r--deps/v8/src/compiler/backend/arm/instruction-codes-arm.h1
-rw-r--r--deps/v8/src/compiler/backend/arm/instruction-scheduler-arm.cc1
-rw-r--r--deps/v8/src/compiler/backend/arm/instruction-selector-arm.cc53
-rw-r--r--deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc200
-rw-r--r--deps/v8/src/compiler/backend/arm64/instruction-codes-arm64.h36
-rw-r--r--deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc36
-rw-r--r--deps/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc176
-rw-r--r--deps/v8/src/compiler/backend/code-generator-impl.h55
-rw-r--r--deps/v8/src/compiler/backend/code-generator.cc186
-rw-r--r--deps/v8/src/compiler/backend/code-generator.h76
-rw-r--r--deps/v8/src/compiler/backend/frame-elider.cc2
-rw-r--r--deps/v8/src/compiler/backend/ia32/code-generator-ia32.cc290
-rw-r--r--deps/v8/src/compiler/backend/ia32/instruction-codes-ia32.h6
-rw-r--r--deps/v8/src/compiler/backend/ia32/instruction-scheduler-ia32.cc3
-rw-r--r--deps/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc142
-rw-r--r--deps/v8/src/compiler/backend/instruction-codes.h5
-rw-r--r--deps/v8/src/compiler/backend/instruction-scheduler.cc7
-rw-r--r--deps/v8/src/compiler/backend/instruction-selector.cc187
-rw-r--r--deps/v8/src/compiler/backend/instruction-selector.h31
-rw-r--r--deps/v8/src/compiler/backend/instruction.cc82
-rw-r--r--deps/v8/src/compiler/backend/instruction.h62
-rw-r--r--deps/v8/src/compiler/backend/mips/code-generator-mips.cc56
-rw-r--r--deps/v8/src/compiler/backend/mips/instruction-codes-mips.h1
-rw-r--r--deps/v8/src/compiler/backend/mips/instruction-scheduler-mips.cc2
-rw-r--r--deps/v8/src/compiler/backend/mips/instruction-selector-mips.cc16
-rw-r--r--deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc56
-rw-r--r--deps/v8/src/compiler/backend/mips64/instruction-codes-mips64.h1
-rw-r--r--deps/v8/src/compiler/backend/mips64/instruction-scheduler-mips64.cc2
-rw-r--r--deps/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc16
-rw-r--r--deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc38
-rw-r--r--deps/v8/src/compiler/backend/ppc/instruction-selector-ppc.cc40
-rw-r--r--deps/v8/src/compiler/backend/register-allocator.cc103
-rw-r--r--deps/v8/src/compiler/backend/register-allocator.h7
-rw-r--r--deps/v8/src/compiler/backend/s390/code-generator-s390.cc16
-rw-r--r--deps/v8/src/compiler/backend/s390/instruction-selector-s390.cc30
-rw-r--r--deps/v8/src/compiler/backend/x64/code-generator-x64.cc673
-rw-r--r--deps/v8/src/compiler/backend/x64/instruction-codes-x64.h15
-rw-r--r--deps/v8/src/compiler/backend/x64/instruction-scheduler-x64.cc15
-rw-r--r--deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc235
-rw-r--r--deps/v8/src/compiler/branch-elimination.cc81
-rw-r--r--deps/v8/src/compiler/branch-elimination.h9
-rw-r--r--deps/v8/src/compiler/bytecode-analysis.cc106
-rw-r--r--deps/v8/src/compiler/bytecode-graph-builder.cc456
-rw-r--r--deps/v8/src/compiler/bytecode-graph-builder.h6
-rw-r--r--deps/v8/src/compiler/c-linkage.cc10
-rw-r--r--deps/v8/src/compiler/code-assembler.cc171
-rw-r--r--deps/v8/src/compiler/code-assembler.h106
-rw-r--r--deps/v8/src/compiler/common-operator.cc41
-rw-r--r--deps/v8/src/compiler/common-operator.h16
-rw-r--r--deps/v8/src/compiler/compilation-dependencies.cc8
-rw-r--r--deps/v8/src/compiler/effect-control-linearizer.cc219
-rw-r--r--deps/v8/src/compiler/escape-analysis.cc3
-rw-r--r--deps/v8/src/compiler/feedback-source.cc45
-rw-r--r--deps/v8/src/compiler/feedback-source.h52
-rw-r--r--deps/v8/src/compiler/frame-states.cc30
-rw-r--r--deps/v8/src/compiler/graph-assembler.cc12
-rw-r--r--deps/v8/src/compiler/graph-assembler.h9
-rw-r--r--deps/v8/src/compiler/graph.cc7
-rw-r--r--deps/v8/src/compiler/heap-refs.h362
-rw-r--r--deps/v8/src/compiler/int64-lowering.cc42
-rw-r--r--deps/v8/src/compiler/int64-lowering.h28
-rw-r--r--deps/v8/src/compiler/js-call-reducer.cc396
-rw-r--r--deps/v8/src/compiler/js-call-reducer.h7
-rw-r--r--deps/v8/src/compiler/js-create-lowering.cc167
-rw-r--r--deps/v8/src/compiler/js-generic-lowering.cc90
-rw-r--r--deps/v8/src/compiler/js-generic-lowering.h4
-rw-r--r--deps/v8/src/compiler/js-graph.cc20
-rw-r--r--deps/v8/src/compiler/js-graph.h8
-rw-r--r--deps/v8/src/compiler/js-heap-broker.cc1321
-rw-r--r--deps/v8/src/compiler/js-heap-broker.h171
-rw-r--r--deps/v8/src/compiler/js-heap-copy-reducer.cc164
-rw-r--r--deps/v8/src/compiler/js-inlining-heuristic.cc30
-rw-r--r--deps/v8/src/compiler/js-inlining.cc82
-rw-r--r--deps/v8/src/compiler/js-inlining.h3
-rw-r--r--deps/v8/src/compiler/js-intrinsic-lowering.cc11
-rw-r--r--deps/v8/src/compiler/js-intrinsic-lowering.h4
-rw-r--r--deps/v8/src/compiler/js-native-context-specialization.cc633
-rw-r--r--deps/v8/src/compiler/js-native-context-specialization.h35
-rw-r--r--deps/v8/src/compiler/js-operator.cc78
-rw-r--r--deps/v8/src/compiler/js-operator.h108
-rw-r--r--deps/v8/src/compiler/js-type-hint-lowering.cc154
-rw-r--r--deps/v8/src/compiler/js-type-hint-lowering.h20
-rw-r--r--deps/v8/src/compiler/js-typed-lowering.cc43
-rw-r--r--deps/v8/src/compiler/linkage.cc44
-rw-r--r--deps/v8/src/compiler/linkage.h33
-rw-r--r--deps/v8/src/compiler/load-elimination.cc291
-rw-r--r--deps/v8/src/compiler/load-elimination.h75
-rw-r--r--deps/v8/src/compiler/machine-graph-verifier.cc47
-rw-r--r--deps/v8/src/compiler/machine-operator-reducer.cc46
-rw-r--r--deps/v8/src/compiler/machine-operator-reducer.h2
-rw-r--r--deps/v8/src/compiler/machine-operator.cc68
-rw-r--r--deps/v8/src/compiler/machine-operator.h44
-rw-r--r--deps/v8/src/compiler/map-inference.cc8
-rw-r--r--deps/v8/src/compiler/map-inference.h8
-rw-r--r--deps/v8/src/compiler/memory-optimizer.cc77
-rw-r--r--deps/v8/src/compiler/memory-optimizer.h6
-rw-r--r--deps/v8/src/compiler/node-matchers.h60
-rw-r--r--deps/v8/src/compiler/node-properties.cc7
-rw-r--r--deps/v8/src/compiler/node.cc20
-rw-r--r--deps/v8/src/compiler/node.h5
-rw-r--r--deps/v8/src/compiler/opcodes.h75
-rw-r--r--deps/v8/src/compiler/operator-properties.cc4
-rw-r--r--deps/v8/src/compiler/per-isolate-compiler-cache.h36
-rw-r--r--deps/v8/src/compiler/pipeline.cc232
-rw-r--r--deps/v8/src/compiler/pipeline.h7
-rw-r--r--deps/v8/src/compiler/processed-feedback.h226
-rw-r--r--deps/v8/src/compiler/property-access-builder.cc36
-rw-r--r--deps/v8/src/compiler/raw-machine-assembler.cc108
-rw-r--r--deps/v8/src/compiler/raw-machine-assembler.h14
-rw-r--r--deps/v8/src/compiler/representation-change.cc128
-rw-r--r--deps/v8/src/compiler/representation-change.h34
-rw-r--r--deps/v8/src/compiler/schedule.cc48
-rw-r--r--deps/v8/src/compiler/schedule.h3
-rw-r--r--deps/v8/src/compiler/scheduler.cc15
-rw-r--r--deps/v8/src/compiler/serializer-for-background-compilation.cc1692
-rw-r--r--deps/v8/src/compiler/simd-scalar-lowering.cc4
-rw-r--r--deps/v8/src/compiler/simplified-lowering.cc52
-rw-r--r--deps/v8/src/compiler/simplified-operator-reducer.cc51
-rw-r--r--deps/v8/src/compiler/simplified-operator.cc111
-rw-r--r--deps/v8/src/compiler/simplified-operator.h152
-rw-r--r--deps/v8/src/compiler/store-store-elimination.cc393
-rw-r--r--deps/v8/src/compiler/store-store-elimination.h194
-rw-r--r--deps/v8/src/compiler/typer.cc20
-rw-r--r--deps/v8/src/compiler/types.cc2
-rw-r--r--deps/v8/src/compiler/vector-slot-pair.cc41
-rw-r--r--deps/v8/src/compiler/vector-slot-pair.h51
-rw-r--r--deps/v8/src/compiler/verifier.cc10
-rw-r--r--deps/v8/src/compiler/wasm-compiler.cc715
-rw-r--r--deps/v8/src/compiler/wasm-compiler.h57
-rw-r--r--deps/v8/src/d8/d8.cc203
-rw-r--r--deps/v8/src/d8/d8.h29
-rw-r--r--deps/v8/src/date/dateparser-inl.h3
-rw-r--r--deps/v8/src/date/dateparser.cc24
-rw-r--r--deps/v8/src/date/dateparser.h32
-rw-r--r--deps/v8/src/debug/debug-coverage.cc41
-rw-r--r--deps/v8/src/debug/debug-evaluate.cc14
-rw-r--r--deps/v8/src/debug/debug-frames.cc4
-rw-r--r--deps/v8/src/debug/debug-scopes.cc9
-rw-r--r--deps/v8/src/debug/debug-stack-trace-iterator.cc3
-rw-r--r--deps/v8/src/debug/debug-type-profile.cc7
-rw-r--r--deps/v8/src/debug/debug.cc45
-rw-r--r--deps/v8/src/debug/debug.h3
-rw-r--r--deps/v8/src/deoptimizer/arm/deoptimizer-arm.cc30
-rw-r--r--deps/v8/src/deoptimizer/arm64/deoptimizer-arm64.cc32
-rw-r--r--deps/v8/src/deoptimizer/deoptimizer.cc417
-rw-r--r--deps/v8/src/deoptimizer/deoptimizer.h69
-rw-r--r--deps/v8/src/deoptimizer/ia32/deoptimizer-ia32.cc29
-rw-r--r--deps/v8/src/deoptimizer/mips/deoptimizer-mips.cc32
-rw-r--r--deps/v8/src/deoptimizer/mips64/deoptimizer-mips64.cc33
-rw-r--r--deps/v8/src/deoptimizer/ppc/deoptimizer-ppc.cc32
-rw-r--r--deps/v8/src/deoptimizer/s390/deoptimizer-s390.cc34
-rw-r--r--deps/v8/src/deoptimizer/x64/deoptimizer-x64.cc32
-rw-r--r--deps/v8/src/diagnostics/OWNERS2
-rw-r--r--deps/v8/src/diagnostics/arm64/disasm-arm64.cc21
-rw-r--r--deps/v8/src/diagnostics/objects-debug.cc106
-rw-r--r--deps/v8/src/diagnostics/objects-printer.cc54
-rw-r--r--deps/v8/src/diagnostics/perf-jit.cc71
-rw-r--r--deps/v8/src/diagnostics/perf-jit.h1
-rw-r--r--deps/v8/src/diagnostics/unwinding-info-win64.cc404
-rw-r--r--deps/v8/src/diagnostics/unwinding-info-win64.h105
-rw-r--r--deps/v8/src/diagnostics/x64/disasm-x64.cc23
-rw-r--r--deps/v8/src/execution/arm/simulator-arm.cc84
-rw-r--r--deps/v8/src/execution/arm64/pointer-auth-arm64.cc269
-rw-r--r--deps/v8/src/execution/arm64/simulator-arm64.cc41
-rw-r--r--deps/v8/src/execution/arm64/simulator-arm64.h39
-rw-r--r--deps/v8/src/execution/frames.cc178
-rw-r--r--deps/v8/src/execution/frames.h170
-rw-r--r--deps/v8/src/execution/futex-emulation.cc24
-rw-r--r--deps/v8/src/execution/futex-emulation.h8
-rw-r--r--deps/v8/src/execution/interrupts-scope.cc2
-rw-r--r--deps/v8/src/execution/interrupts-scope.h6
-rw-r--r--deps/v8/src/execution/isolate-data.h35
-rw-r--r--deps/v8/src/execution/isolate-inl.h27
-rw-r--r--deps/v8/src/execution/isolate.cc170
-rw-r--r--deps/v8/src/execution/isolate.h46
-rw-r--r--deps/v8/src/execution/messages.cc246
-rw-r--r--deps/v8/src/execution/messages.h18
-rw-r--r--deps/v8/src/execution/microtask-queue.cc17
-rw-r--r--deps/v8/src/execution/mips/simulator-mips.cc11
-rw-r--r--deps/v8/src/execution/mips64/simulator-mips64.cc11
-rw-r--r--deps/v8/src/execution/ppc/simulator-ppc.cc27
-rw-r--r--deps/v8/src/execution/protectors-inl.h36
-rw-r--r--deps/v8/src/execution/protectors.cc48
-rw-r--r--deps/v8/src/execution/protectors.h42
-rw-r--r--deps/v8/src/execution/runtime-profiler.cc12
-rw-r--r--deps/v8/src/execution/s390/simulator-s390.cc23
-rw-r--r--deps/v8/src/execution/stack-guard.cc62
-rw-r--r--deps/v8/src/execution/stack-guard.h34
-rw-r--r--deps/v8/src/execution/thread-local-top.cc10
-rw-r--r--deps/v8/src/execution/thread-local-top.h30
-rw-r--r--deps/v8/src/execution/v8threads.cc5
-rw-r--r--deps/v8/src/extensions/OWNERS2
-rw-r--r--deps/v8/src/extensions/cputracemark-extension.cc2
-rw-r--r--deps/v8/src/flags/OWNERS2
-rw-r--r--deps/v8/src/flags/flag-definitions.h81
-rw-r--r--deps/v8/src/handles/global-handles.cc100
-rw-r--r--deps/v8/src/handles/global-handles.h6
-rw-r--r--deps/v8/src/heap/array-buffer-tracker-inl.h3
-rw-r--r--deps/v8/src/heap/array-buffer-tracker.cc3
-rw-r--r--deps/v8/src/heap/embedder-tracing.h6
-rw-r--r--deps/v8/src/heap/factory-inl.h18
-rw-r--r--deps/v8/src/heap/factory.cc52
-rw-r--r--deps/v8/src/heap/factory.h23
-rw-r--r--deps/v8/src/heap/gc-tracer.cc70
-rw-r--r--deps/v8/src/heap/gc-tracer.h27
-rw-r--r--deps/v8/src/heap/heap-inl.h14
-rw-r--r--deps/v8/src/heap/heap.cc186
-rw-r--r--deps/v8/src/heap/heap.h42
-rw-r--r--deps/v8/src/heap/invalidated-slots-inl.h42
-rw-r--r--deps/v8/src/heap/invalidated-slots.cc59
-rw-r--r--deps/v8/src/heap/invalidated-slots.h33
-rw-r--r--deps/v8/src/heap/local-allocator-inl.h11
-rw-r--r--deps/v8/src/heap/local-allocator.h2
-rw-r--r--deps/v8/src/heap/mark-compact.cc63
-rw-r--r--deps/v8/src/heap/object-stats.cc63
-rw-r--r--deps/v8/src/heap/object-stats.h3
-rw-r--r--deps/v8/src/heap/remembered-set.h4
-rw-r--r--deps/v8/src/heap/scavenger-inl.h8
-rw-r--r--deps/v8/src/heap/scavenger.cc29
-rw-r--r--deps/v8/src/heap/setup-heap-internal.cc14
-rw-r--r--deps/v8/src/heap/slot-set.h12
-rw-r--r--deps/v8/src/heap/spaces-inl.h121
-rw-r--r--deps/v8/src/heap/spaces.cc601
-rw-r--r--deps/v8/src/heap/spaces.h419
-rw-r--r--deps/v8/src/heap/store-buffer-inl.h10
-rw-r--r--deps/v8/src/heap/store-buffer.cc35
-rw-r--r--deps/v8/src/heap/store-buffer.h30
-rw-r--r--deps/v8/src/heap/sweeper.cc66
-rw-r--r--deps/v8/src/heap/sweeper.h23
-rw-r--r--deps/v8/src/ic/OWNERS1
-rw-r--r--deps/v8/src/ic/accessor-assembler.cc803
-rw-r--r--deps/v8/src/ic/accessor-assembler.h50
-rw-r--r--deps/v8/src/ic/binary-op-assembler.cc33
-rw-r--r--deps/v8/src/ic/handler-configuration-inl.h4
-rw-r--r--deps/v8/src/ic/handler-configuration.cc41
-rw-r--r--deps/v8/src/ic/handler-configuration.h76
-rw-r--r--deps/v8/src/ic/ic.cc90
-rw-r--r--deps/v8/src/ic/keyed-store-generic.cc309
-rw-r--r--deps/v8/src/ic/keyed-store-generic.h2
-rw-r--r--deps/v8/src/init/bootstrapper.cc117
-rw-r--r--deps/v8/src/init/isolate-allocator.cc63
-rw-r--r--deps/v8/src/init/setup-isolate-deserialize.cc1
-rw-r--r--deps/v8/src/init/v8.cc7
-rw-r--r--deps/v8/src/inspector/DEPS1
-rw-r--r--deps/v8/src/inspector/OWNERS2
-rw-r--r--deps/v8/src/inspector/injected-script.cc74
-rw-r--r--deps/v8/src/inspector/injected-script.h6
-rw-r--r--deps/v8/src/inspector/v8-runtime-agent-impl.cc2
-rw-r--r--deps/v8/src/inspector/value-mirror.cc75
-rw-r--r--deps/v8/src/interpreter/bytecode-array-builder.cc30
-rw-r--r--deps/v8/src/interpreter/bytecode-array-builder.h12
-rw-r--r--deps/v8/src/interpreter/bytecode-array-writer.cc47
-rw-r--r--deps/v8/src/interpreter/bytecode-array-writer.h7
-rw-r--r--deps/v8/src/interpreter/bytecode-flags.h17
-rw-r--r--deps/v8/src/interpreter/bytecode-generator.cc631
-rw-r--r--deps/v8/src/interpreter/bytecode-generator.h45
-rw-r--r--deps/v8/src/interpreter/bytecodes.h11
-rw-r--r--deps/v8/src/interpreter/interpreter-assembler.cc517
-rw-r--r--deps/v8/src/interpreter/interpreter-assembler.h124
-rw-r--r--deps/v8/src/interpreter/interpreter-generator.cc911
-rw-r--r--deps/v8/src/interpreter/interpreter-intrinsics-generator.cc31
-rw-r--r--deps/v8/src/interpreter/interpreter.cc59
-rw-r--r--deps/v8/src/interpreter/interpreter.h11
-rw-r--r--deps/v8/src/json/json-parser.cc24
-rw-r--r--deps/v8/src/json/json-stringifier.cc7
-rw-r--r--deps/v8/src/libplatform/default-worker-threads-task-runner.cc2
-rw-r--r--deps/v8/src/libplatform/tracing/trace-buffer.h1
-rw-r--r--deps/v8/src/libplatform/tracing/tracing-controller.cc28
-rw-r--r--deps/v8/src/libplatform/worker-thread.cc2
-rw-r--r--deps/v8/src/logging/OWNERS2
-rw-r--r--deps/v8/src/logging/code-events.h4
-rw-r--r--deps/v8/src/logging/counters-definitions.h2
-rw-r--r--deps/v8/src/logging/counters.h1
-rw-r--r--deps/v8/src/logging/log.cc18
-rw-r--r--deps/v8/src/logging/log.h8
-rw-r--r--deps/v8/src/objects/OWNERS2
-rw-r--r--deps/v8/src/objects/allocation-site.h10
-rw-r--r--deps/v8/src/objects/api-callbacks-inl.h22
-rw-r--r--deps/v8/src/objects/api-callbacks.h35
-rw-r--r--deps/v8/src/objects/arguments-inl.h9
-rw-r--r--deps/v8/src/objects/arguments.h18
-rw-r--r--deps/v8/src/objects/bigint.cc2
-rw-r--r--deps/v8/src/objects/bigint.h6
-rw-r--r--deps/v8/src/objects/cell-inl.h6
-rw-r--r--deps/v8/src/objects/cell.h15
-rw-r--r--deps/v8/src/objects/code-inl.h1
-rw-r--r--deps/v8/src/objects/code.cc15
-rw-r--r--deps/v8/src/objects/code.h17
-rw-r--r--deps/v8/src/objects/contexts.cc10
-rw-r--r--deps/v8/src/objects/contexts.h9
-rw-r--r--deps/v8/src/objects/dictionary.h3
-rw-r--r--deps/v8/src/objects/elements-inl.h10
-rw-r--r--deps/v8/src/objects/elements-kind.cc6
-rw-r--r--deps/v8/src/objects/elements-kind.h38
-rw-r--r--deps/v8/src/objects/elements.cc241
-rw-r--r--deps/v8/src/objects/elements.h16
-rw-r--r--deps/v8/src/objects/embedder-data-array-inl.h6
-rw-r--r--deps/v8/src/objects/embedder-data-array.h11
-rw-r--r--deps/v8/src/objects/feedback-vector.cc19
-rw-r--r--deps/v8/src/objects/field-index.h18
-rw-r--r--deps/v8/src/objects/fixed-array.h5
-rw-r--r--deps/v8/src/objects/function-kind.h7
-rw-r--r--deps/v8/src/objects/function-syntax-kind.h46
-rw-r--r--deps/v8/src/objects/heap-number-inl.h17
-rw-r--r--deps/v8/src/objects/heap-number.h25
-rw-r--r--deps/v8/src/objects/instance-type.h7
-rw-r--r--deps/v8/src/objects/js-collection-inl.h26
-rw-r--r--deps/v8/src/objects/js-collection-iterator.h16
-rw-r--r--deps/v8/src/objects/js-collection.h65
-rw-r--r--deps/v8/src/objects/js-date-time-format.cc9
-rw-r--r--deps/v8/src/objects/js-generator-inl.h33
-rw-r--r--deps/v8/src/objects/js-generator.h79
-rw-r--r--deps/v8/src/objects/js-number-format.cc27
-rw-r--r--deps/v8/src/objects/js-objects-inl.h47
-rw-r--r--deps/v8/src/objects/js-objects.cc100
-rw-r--r--deps/v8/src/objects/js-objects.h71
-rw-r--r--deps/v8/src/objects/js-promise-inl.h6
-rw-r--r--deps/v8/src/objects/js-promise.h15
-rw-r--r--deps/v8/src/objects/js-regexp-inl.h26
-rw-r--r--deps/v8/src/objects/js-regexp-string-iterator-inl.h11
-rw-r--r--deps/v8/src/objects/js-regexp-string-iterator.h19
-rw-r--r--deps/v8/src/objects/js-regexp.h65
-rw-r--r--deps/v8/src/objects/js-segment-iterator.cc8
-rw-r--r--deps/v8/src/objects/js-weak-refs-inl.h6
-rw-r--r--deps/v8/src/objects/js-weak-refs.h31
-rw-r--r--deps/v8/src/objects/keys.cc136
-rw-r--r--deps/v8/src/objects/keys.h16
-rw-r--r--deps/v8/src/objects/literal-objects-inl.h9
-rw-r--r--deps/v8/src/objects/literal-objects.cc3
-rw-r--r--deps/v8/src/objects/literal-objects.h15
-rw-r--r--deps/v8/src/objects/lookup.cc73
-rw-r--r--deps/v8/src/objects/map-inl.h8
-rw-r--r--deps/v8/src/objects/map-updater.cc2
-rw-r--r--deps/v8/src/objects/map.cc35
-rw-r--r--deps/v8/src/objects/map.h3
-rw-r--r--deps/v8/src/objects/microtask-inl.h16
-rw-r--r--deps/v8/src/objects/microtask.h33
-rw-r--r--deps/v8/src/objects/module-inl.h40
-rw-r--r--deps/v8/src/objects/module.cc15
-rw-r--r--deps/v8/src/objects/module.h14
-rw-r--r--deps/v8/src/objects/name-inl.h3
-rw-r--r--deps/v8/src/objects/name.h28
-rw-r--r--deps/v8/src/objects/object-list-macros.h3
-rw-r--r--deps/v8/src/objects/object-macros.h24
-rw-r--r--deps/v8/src/objects/objects-body-descriptors-inl.h1
-rw-r--r--deps/v8/src/objects/objects-definitions.h6
-rw-r--r--deps/v8/src/objects/objects-inl.h9
-rw-r--r--deps/v8/src/objects/objects.cc99
-rw-r--r--deps/v8/src/objects/objects.h2
-rw-r--r--deps/v8/src/objects/ordered-hash-table.cc207
-rw-r--r--deps/v8/src/objects/ordered-hash-table.h67
-rw-r--r--deps/v8/src/objects/promise-inl.h41
-rw-r--r--deps/v8/src/objects/promise.h89
-rw-r--r--deps/v8/src/objects/property-array.h6
-rw-r--r--deps/v8/src/objects/property-details.h34
-rw-r--r--deps/v8/src/objects/scope-info.cc59
-rw-r--r--deps/v8/src/objects/scope-info.h67
-rw-r--r--deps/v8/src/objects/shared-function-info-inl.h25
-rw-r--r--deps/v8/src/objects/shared-function-info.h28
-rw-r--r--deps/v8/src/objects/source-text-module.cc2
-rw-r--r--deps/v8/src/objects/source-text-module.h56
-rw-r--r--deps/v8/src/objects/stack-frame-info-inl.h12
-rw-r--r--deps/v8/src/objects/stack-frame-info.cc13
-rw-r--r--deps/v8/src/objects/stack-frame-info.h22
-rw-r--r--deps/v8/src/objects/string-inl.h94
-rw-r--r--deps/v8/src/objects/string.cc12
-rw-r--r--deps/v8/src/objects/string.h7
-rw-r--r--deps/v8/src/objects/struct-inl.h7
-rw-r--r--deps/v8/src/objects/struct.h12
-rw-r--r--deps/v8/src/objects/synthetic-module.h15
-rw-r--r--deps/v8/src/objects/template-objects-inl.h7
-rw-r--r--deps/v8/src/objects/template-objects.h17
-rw-r--r--deps/v8/src/objects/templates-inl.h54
-rw-r--r--deps/v8/src/objects/templates.h94
-rw-r--r--deps/v8/src/objects/value-serializer.cc8
-rw-r--r--deps/v8/src/objects/value-serializer.h2
-rw-r--r--deps/v8/src/parsing/expression-scope-reparenter.cc2
-rw-r--r--deps/v8/src/parsing/expression-scope.h90
-rw-r--r--deps/v8/src/parsing/parse-info.cc12
-rw-r--r--deps/v8/src/parsing/parse-info.h75
-rw-r--r--deps/v8/src/parsing/parser-base.h266
-rw-r--r--deps/v8/src/parsing/parser.cc115
-rw-r--r--deps/v8/src/parsing/parser.h27
-rw-r--r--deps/v8/src/parsing/parsing.cc39
-rw-r--r--deps/v8/src/parsing/parsing.h18
-rw-r--r--deps/v8/src/parsing/preparse-data.cc41
-rw-r--r--deps/v8/src/parsing/preparser.cc19
-rw-r--r--deps/v8/src/parsing/preparser.h84
-rw-r--r--deps/v8/src/parsing/scanner-character-streams.cc2
-rw-r--r--deps/v8/src/parsing/scanner-inl.h13
-rw-r--r--deps/v8/src/parsing/scanner.cc79
-rw-r--r--deps/v8/src/parsing/scanner.h20
-rw-r--r--deps/v8/src/parsing/token.h6
-rw-r--r--deps/v8/src/profiler/cpu-profiler.cc229
-rw-r--r--deps/v8/src/profiler/cpu-profiler.h103
-rw-r--r--deps/v8/src/profiler/heap-profiler.cc11
-rw-r--r--deps/v8/src/profiler/heap-profiler.h1
-rw-r--r--deps/v8/src/profiler/heap-snapshot-generator.cc72
-rw-r--r--deps/v8/src/profiler/heap-snapshot-generator.h9
-rw-r--r--deps/v8/src/profiler/profile-generator-inl.h2
-rw-r--r--deps/v8/src/profiler/profile-generator.cc106
-rw-r--r--deps/v8/src/profiler/profile-generator.h47
-rw-r--r--deps/v8/src/profiler/profiler-listener.cc10
-rw-r--r--deps/v8/src/profiler/profiler-listener.h1
-rw-r--r--deps/v8/src/profiler/tick-sample.cc115
-rw-r--r--deps/v8/src/profiler/tick-sample.h76
-rw-r--r--deps/v8/src/regexp/arm/regexp-macro-assembler-arm.cc37
-rw-r--r--deps/v8/src/regexp/arm/regexp-macro-assembler-arm.h9
-rw-r--r--deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc42
-rw-r--r--deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h9
-rw-r--r--deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc36
-rw-r--r--deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h9
-rw-r--r--deps/v8/src/regexp/mips/regexp-macro-assembler-mips.cc30
-rw-r--r--deps/v8/src/regexp/mips/regexp-macro-assembler-mips.h9
-rw-r--r--deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.cc31
-rw-r--r--deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.h9
-rw-r--r--deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc34
-rw-r--r--deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.h8
-rw-r--r--deps/v8/src/regexp/regexp-bytecode-generator.cc21
-rw-r--r--deps/v8/src/regexp/regexp-bytecode-generator.h8
-rw-r--r--deps/v8/src/regexp/regexp-bytecodes.h39
-rw-r--r--deps/v8/src/regexp/regexp-compiler-tonode.cc6
-rw-r--r--deps/v8/src/regexp/regexp-compiler.cc616
-rw-r--r--deps/v8/src/regexp/regexp-compiler.h51
-rw-r--r--deps/v8/src/regexp/regexp-dotprinter.cc11
-rw-r--r--deps/v8/src/regexp/regexp-interpreter.cc1166
-rw-r--r--deps/v8/src/regexp/regexp-interpreter.h37
-rw-r--r--deps/v8/src/regexp/regexp-macro-assembler-tracer.cc35
-rw-r--r--deps/v8/src/regexp/regexp-macro-assembler-tracer.h8
-rw-r--r--deps/v8/src/regexp/regexp-macro-assembler.cc75
-rw-r--r--deps/v8/src/regexp/regexp-macro-assembler.h28
-rw-r--r--deps/v8/src/regexp/regexp-nodes.h144
-rw-r--r--deps/v8/src/regexp/regexp-parser.cc4
-rw-r--r--deps/v8/src/regexp/regexp-parser.h1
-rw-r--r--deps/v8/src/regexp/regexp-stack.cc4
-rw-r--r--deps/v8/src/regexp/regexp-stack.h19
-rw-r--r--deps/v8/src/regexp/regexp-utils.cc10
-rw-r--r--deps/v8/src/regexp/regexp-utils.h3
-rw-r--r--deps/v8/src/regexp/regexp.cc176
-rw-r--r--deps/v8/src/regexp/regexp.h23
-rw-r--r--deps/v8/src/regexp/s390/regexp-macro-assembler-s390.cc32
-rw-r--r--deps/v8/src/regexp/s390/regexp-macro-assembler-s390.h8
-rw-r--r--deps/v8/src/regexp/x64/regexp-macro-assembler-x64.cc40
-rw-r--r--deps/v8/src/regexp/x64/regexp-macro-assembler-x64.h8
-rw-r--r--deps/v8/src/roots/roots.h6
-rw-r--r--deps/v8/src/runtime/OWNERS2
-rw-r--r--deps/v8/src/runtime/runtime-array.cc7
-rw-r--r--deps/v8/src/runtime/runtime-collections.cc14
-rw-r--r--deps/v8/src/runtime/runtime-compiler.cc21
-rw-r--r--deps/v8/src/runtime/runtime-debug.cc13
-rw-r--r--deps/v8/src/runtime/runtime-internal.cc219
-rw-r--r--deps/v8/src/runtime/runtime-literals.cc28
-rw-r--r--deps/v8/src/runtime/runtime-object.cc63
-rw-r--r--deps/v8/src/runtime/runtime-regexp.cc27
-rw-r--r--deps/v8/src/runtime/runtime-scopes.cc3
-rw-r--r--deps/v8/src/runtime/runtime-test.cc61
-rw-r--r--deps/v8/src/runtime/runtime-wasm.cc23
-rw-r--r--deps/v8/src/runtime/runtime-weak-refs.cc29
-rw-r--r--deps/v8/src/runtime/runtime.cc3
-rw-r--r--deps/v8/src/runtime/runtime.h88
-rw-r--r--deps/v8/src/sanitizer/OWNERS2
-rw-r--r--deps/v8/src/sanitizer/lsan-page-allocator.cc5
-rw-r--r--deps/v8/src/snapshot/code-serializer.cc23
-rw-r--r--deps/v8/src/snapshot/embedded/embedded-data.cc25
-rw-r--r--deps/v8/src/snapshot/embedded/embedded-file-writer.cc4
-rw-r--r--deps/v8/src/snapshot/embedded/embedded-file-writer.h19
-rw-r--r--deps/v8/src/snapshot/embedded/platform-embedded-file-writer-win.cc119
-rw-r--r--deps/v8/src/snapshot/references.h10
-rw-r--r--deps/v8/src/snapshot/serializer-common.h8
-rw-r--r--deps/v8/src/snapshot/snapshot.h1
-rw-r--r--deps/v8/src/snapshot/startup-serializer.cc8
-rw-r--r--deps/v8/src/strings/char-predicates-inl.h16
-rw-r--r--deps/v8/src/strings/unicode.h4
-rw-r--r--deps/v8/src/third_party/valgrind/OWNERS2
-rw-r--r--deps/v8/src/third_party/vtune/OWNERS2
-rw-r--r--deps/v8/src/torque/ast.h203
-rw-r--r--deps/v8/src/torque/class-debug-reader-generator.cc222
-rw-r--r--deps/v8/src/torque/constants.h5
-rw-r--r--deps/v8/src/torque/contextual.h32
-rw-r--r--deps/v8/src/torque/csa-generator.cc23
-rw-r--r--deps/v8/src/torque/declarable.cc72
-rw-r--r--deps/v8/src/torque/declarable.h69
-rw-r--r--deps/v8/src/torque/declaration-visitor.cc166
-rw-r--r--deps/v8/src/torque/declaration-visitor.h40
-rw-r--r--deps/v8/src/torque/declarations.cc61
-rw-r--r--deps/v8/src/torque/declarations.h23
-rw-r--r--deps/v8/src/torque/earley-parser.h4
-rw-r--r--deps/v8/src/torque/global-context.cc7
-rw-r--r--deps/v8/src/torque/global-context.h13
-rw-r--r--deps/v8/src/torque/implementation-visitor.cc663
-rw-r--r--deps/v8/src/torque/implementation-visitor.h82
-rw-r--r--deps/v8/src/torque/instructions.cc15
-rw-r--r--deps/v8/src/torque/instructions.h7
-rw-r--r--deps/v8/src/torque/torque-compiler.cc2
-rw-r--r--deps/v8/src/torque/torque-compiler.h6
-rw-r--r--deps/v8/src/torque/torque-parser.cc259
-rw-r--r--deps/v8/src/torque/torque.cc25
-rw-r--r--deps/v8/src/torque/type-inference.cc121
-rw-r--r--deps/v8/src/torque/type-inference.h84
-rw-r--r--deps/v8/src/torque/type-oracle.cc23
-rw-r--r--deps/v8/src/torque/type-oracle.h36
-rw-r--r--deps/v8/src/torque/type-visitor.cc164
-rw-r--r--deps/v8/src/torque/type-visitor.h12
-rw-r--r--deps/v8/src/torque/types.cc90
-rw-r--r--deps/v8/src/torque/types.h99
-rw-r--r--deps/v8/src/torque/utils.cc42
-rw-r--r--deps/v8/src/torque/utils.h50
-rw-r--r--deps/v8/src/utils/OWNERS2
-rw-r--r--deps/v8/src/utils/allocation.cc19
-rw-r--r--deps/v8/src/utils/allocation.h9
-rw-r--r--deps/v8/src/utils/utils.h23
-rw-r--r--deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h4
-rw-r--r--deps/v8/src/wasm/baseline/liftoff-compiler.cc33
-rw-r--r--deps/v8/src/wasm/c-api.cc1396
-rw-r--r--deps/v8/src/wasm/c-api.h16
-rw-r--r--deps/v8/src/wasm/function-body-decoder-impl.h103
-rw-r--r--deps/v8/src/wasm/function-compiler.cc22
-rw-r--r--deps/v8/src/wasm/function-compiler.h11
-rw-r--r--deps/v8/src/wasm/graph-builder-interface.cc53
-rw-r--r--deps/v8/src/wasm/jump-table-assembler.h15
-rw-r--r--deps/v8/src/wasm/module-compiler.cc341
-rw-r--r--deps/v8/src/wasm/module-compiler.h4
-rw-r--r--deps/v8/src/wasm/module-instantiate.cc52
-rw-r--r--deps/v8/src/wasm/wasm-code-manager.cc239
-rw-r--r--deps/v8/src/wasm/wasm-code-manager.h68
-rw-r--r--deps/v8/src/wasm/wasm-engine.cc40
-rw-r--r--deps/v8/src/wasm/wasm-engine.h3
-rw-r--r--deps/v8/src/wasm/wasm-external-refs.cc96
-rw-r--r--deps/v8/src/wasm/wasm-feature-flags.h46
-rw-r--r--deps/v8/src/wasm/wasm-features.cc16
-rw-r--r--deps/v8/src/wasm/wasm-features.h57
-rw-r--r--deps/v8/src/wasm/wasm-interpreter.cc85
-rw-r--r--deps/v8/src/wasm/wasm-js.cc203
-rw-r--r--deps/v8/src/wasm/wasm-module-builder.cc73
-rw-r--r--deps/v8/src/wasm/wasm-module-builder.h12
-rw-r--r--deps/v8/src/wasm/wasm-module-sourcemap.cc161
-rw-r--r--deps/v8/src/wasm/wasm-module-sourcemap.h83
-rw-r--r--deps/v8/src/wasm/wasm-module.cc203
-rw-r--r--deps/v8/src/wasm/wasm-module.h21
-rw-r--r--deps/v8/src/wasm/wasm-objects-inl.h21
-rw-r--r--deps/v8/src/wasm/wasm-objects.cc96
-rw-r--r--deps/v8/src/wasm/wasm-objects.h65
-rw-r--r--deps/v8/src/wasm/wasm-opcodes.cc17
-rw-r--r--deps/v8/src/wasm/wasm-opcodes.h67
-rw-r--r--deps/v8/src/wasm/wasm-serialization.cc16
-rw-r--r--deps/v8/src/wasm/wasm-text.cc17
-rw-r--r--deps/v8/src/zone/zone.h61
-rw-r--r--deps/v8/test/OWNERS2
-rw-r--r--deps/v8/test/cctest/BUILD.gn16
-rw-r--r--deps/v8/test/cctest/DEPS5
-rw-r--r--deps/v8/test/cctest/cctest.status1
-rw-r--r--deps/v8/test/cctest/compiler/codegen-tester.h6
-rw-r--r--deps/v8/test/cctest/compiler/serializer-tester.cc32
-rw-r--r--deps/v8/test/cctest/compiler/test-code-assembler.cc67
-rw-r--r--deps/v8/test/cctest/compiler/test-code-generator.cc5
-rw-r--r--deps/v8/test/cctest/compiler/test-instruction-scheduler.cc2
-rw-r--r--deps/v8/test/cctest/compiler/test-js-constant-cache.cc32
-rw-r--r--deps/v8/test/cctest/compiler/test-js-context-specialization.cc18
-rw-r--r--deps/v8/test/cctest/compiler/test-multiple-return.cc30
-rw-r--r--deps/v8/test/cctest/compiler/test-representation-change.cc28
-rw-r--r--deps/v8/test/cctest/compiler/test-run-native-calls.cc24
-rw-r--r--deps/v8/test/cctest/compiler/test-run-retpoline.cc3
-rw-r--r--deps/v8/test/cctest/compiler/test-run-tail-calls.cc5
-rw-r--r--deps/v8/test/cctest/heap/heap-tester.h4
-rw-r--r--deps/v8/test/cctest/heap/test-embedder-tracing.cc298
-rw-r--r--deps/v8/test/cctest/heap/test-heap.cc30
-rw-r--r--deps/v8/test/cctest/heap/test-invalidated-slots.cc106
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/ArrayLiterals.golden18
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden277
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/CallAndSpread.golden17
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/DestructuringAssignment.golden342
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden527
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/ForIn.golden20
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/ForOf.golden347
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden776
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/Generators.golden170
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/NewAndSpread.golden17
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateAccessorAccess.golden192
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateAccessorDeclaration.golden398
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethodAccess.golden104
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethodDeclaration.golden198
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethods.golden160
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden5
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/SuperCallAndSpread.golden18
-rw-r--r--deps/v8/test/cctest/interpreter/bytecode_expectations/WideRegisters.golden5
-rw-r--r--deps/v8/test/cctest/interpreter/test-bytecode-generator.cc171
-rw-r--r--deps/v8/test/cctest/libplatform/test-tracing.cc56
-rw-r--r--deps/v8/test/cctest/parsing/test-scanner-streams.cc37
-rw-r--r--deps/v8/test/cctest/test-accessor-assembler.cc13
-rw-r--r--deps/v8/test/cctest/test-api-stack-traces.cc10
-rw-r--r--deps/v8/test/cctest/test-api.cc87
-rw-r--r--deps/v8/test/cctest/test-assembler-arm64.cc372
-rw-r--r--deps/v8/test/cctest/test-circular-queue.cc6
-rw-r--r--deps/v8/test/cctest/test-code-stub-assembler.cc247
-rw-r--r--deps/v8/test/cctest/test-conversions.cc14
-rw-r--r--deps/v8/test/cctest/test-cpu-profiler.cc366
-rw-r--r--deps/v8/test/cctest/test-debug-helper.cc227
-rw-r--r--deps/v8/test/cctest/test-debug.cc108
-rw-r--r--deps/v8/test/cctest/test-disasm-arm64.cc10
-rw-r--r--deps/v8/test/cctest/test-disasm-x64.cc2
-rw-r--r--deps/v8/test/cctest/test-elements-kind.cc1
-rw-r--r--deps/v8/test/cctest/test-feedback-vector.cc7
-rw-r--r--deps/v8/test/cctest/test-field-type-tracking.cc24
-rw-r--r--deps/v8/test/cctest/test-flags.cc6
-rw-r--r--deps/v8/test/cctest/test-heap-profiler.cc149
-rw-r--r--deps/v8/test/cctest/test-inobject-slack-tracking.cc4
-rw-r--r--deps/v8/test/cctest/test-js-weak-refs.cc4
-rw-r--r--deps/v8/test/cctest/test-lockers.cc10
-rw-r--r--deps/v8/test/cctest/test-log-stack-tracer.cc1
-rw-r--r--deps/v8/test/cctest/test-orderedhashtable.cc111
-rw-r--r--deps/v8/test/cctest/test-parsing.cc320
-rw-r--r--deps/v8/test/cctest/test-pointer-auth-arm64.cc76
-rw-r--r--deps/v8/test/cctest/test-poison-disasm-arm.cc1
-rw-r--r--deps/v8/test/cctest/test-poison-disasm-arm64.cc3
-rw-r--r--deps/v8/test/cctest/test-profile-generator.cc13
-rw-r--r--deps/v8/test/cctest/test-regexp.cc164
-rw-r--r--deps/v8/test/cctest/test-serialize.cc46
-rw-r--r--deps/v8/test/cctest/test-stack-unwinding-win64.cc (renamed from deps/v8/test/cctest/test-stack-unwinding-x64.cc)37
-rw-r--r--deps/v8/test/cctest/test-sync-primitives-arm.cc2
-rw-r--r--deps/v8/test/cctest/test-sync-primitives-arm64.cc2
-rw-r--r--deps/v8/test/cctest/test-thread-termination.cc6
-rw-r--r--deps/v8/test/cctest/test-threads.cc4
-rw-r--r--deps/v8/test/cctest/test-unboxed-doubles.cc6
-rw-r--r--deps/v8/test/cctest/torque/test-torque.cc63
-rw-r--r--deps/v8/test/cctest/trace-extension.cc10
-rw-r--r--deps/v8/test/cctest/trace-extension.h5
-rw-r--r--deps/v8/test/cctest/wasm/test-jump-table-assembler.cc105
-rw-r--r--deps/v8/test/cctest/wasm/test-run-wasm-64.cc4
-rw-r--r--deps/v8/test/cctest/wasm/test-run-wasm-atomics.cc48
-rw-r--r--deps/v8/test/cctest/wasm/test-run-wasm-atomics64.cc48
-rw-r--r--deps/v8/test/cctest/wasm/test-run-wasm-module.cc4
-rw-r--r--deps/v8/test/cctest/wasm/test-run-wasm-simd.cc593
-rw-r--r--deps/v8/test/cctest/wasm/test-streaming-compilation.cc2
-rw-r--r--deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc14
-rw-r--r--deps/v8/test/cctest/wasm/wasm-run-utils.cc21
-rw-r--r--deps/v8/test/common/wasm/OWNERS2
-rw-r--r--deps/v8/test/common/wasm/wasm-module-runner.cc6
-rw-r--r--deps/v8/test/debugger/OWNERS2
-rw-r--r--deps/v8/test/fuzzer/multi-return.cc11
-rw-r--r--deps/v8/test/fuzzer/regexp-builtins.cc8
-rw-r--r--deps/v8/test/fuzzer/wasm-fuzzer-common.cc19
-rw-r--r--deps/v8/test/fuzzer/wasm.cc11
-rw-r--r--deps/v8/test/inspector/OWNERS2
-rw-r--r--deps/v8/test/inspector/debugger/class-private-fields-scopes-expected.txt141
-rw-r--r--deps/v8/test/inspector/debugger/class-private-fields-scopes.js32
-rw-r--r--deps/v8/test/inspector/debugger/object-preview-internal-properties-expected.txt16
-rw-r--r--deps/v8/test/inspector/debugger/object-preview-internal-properties.js6
-rw-r--r--deps/v8/test/inspector/runtime/await-promise-expected.txt18
-rw-r--r--deps/v8/test/inspector/runtime/call-function-on-async-expected.txt90
-rw-r--r--deps/v8/test/inspector/runtime/call-function-on-async.js22
-rw-r--r--deps/v8/test/inspector/runtime/console-table-expected.txt94
-rw-r--r--deps/v8/test/inspector/runtime/console-table.js12
-rw-r--r--deps/v8/test/inspector/runtime/evaluate-new-function-error-expected.txt27
-rw-r--r--deps/v8/test/inspector/runtime/evaluate-new-function-error.js11
-rw-r--r--deps/v8/test/inspector/runtime/remote-object-expected.txt12
-rw-r--r--deps/v8/test/inspector/runtime/remote-object.js5
-rw-r--r--deps/v8/test/inspector/runtime/run-script-async-expected.txt18
-rw-r--r--deps/v8/test/inspector/runtime/terminate-execution-expected.txt7
-rw-r--r--deps/v8/test/inspector/runtime/terminate-execution.js12
-rw-r--r--deps/v8/test/inspector/task-runner.cc2
-rw-r--r--deps/v8/test/intl/number-format/unified/style-unit.js14
-rw-r--r--deps/v8/test/intl/regress-9475.js62
-rw-r--r--deps/v8/test/intl/regress-9642.js8
-rw-r--r--deps/v8/test/js-perf-test/IC/loadconstantfromprototype.js23
-rw-r--r--deps/v8/test/js-perf-test/IC/run.js24
-rw-r--r--deps/v8/test/js-perf-test/JSTests5.json12
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-getter-count.js14
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-getter-count.out9
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-getter-nested.js19
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-getter-nested.out10
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-getter.js13
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-getter.out9
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-setter-compound.js13
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-setter-compound.out9
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-setter-count.js14
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-setter-count.out9
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-setter-nested.js19
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-setter-nested.out10
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-setter.js13
-rw-r--r--deps/v8/test/message/fail/class-accessors-private-undefined-setter.out9
-rw-r--r--deps/v8/test/message/fail/class-fields-private-source-positions.out4
-rw-r--r--deps/v8/test/message/fail/class-fields-private-throw-early-2.out4
-rw-r--r--deps/v8/test/message/fail/class-fields-private-throw-read.out4
-rw-r--r--deps/v8/test/message/fail/class-fields-private-throw-write.out4
-rw-r--r--deps/v8/test/message/fail/destructuring-undefined-computed-property.out6
-rw-r--r--deps/v8/test/message/fail/destructuring-undefined-number-property.out8
-rw-r--r--deps/v8/test/message/fail/destructuring-undefined-string-property.out6
-rw-r--r--deps/v8/test/message/regress/fail/regress-9603.js5
-rw-r--r--deps/v8/test/message/regress/fail/regress-9603.out7
-rw-r--r--deps/v8/test/mjsunit/code-coverage-block.js53
-rw-r--r--deps/v8/test/mjsunit/code-coverage-utils.js29
-rw-r--r--deps/v8/test/mjsunit/compiler/bigint-int64-lowered.js1
-rw-r--r--deps/v8/test/mjsunit/compiler/dataview-detached.js (renamed from deps/v8/test/mjsunit/compiler/dataview-neutered.js)0
-rw-r--r--deps/v8/test/mjsunit/compiler/diamond-followedby-branch.js22
-rw-r--r--deps/v8/test/mjsunit/compiler/instanceof4.js80
-rw-r--r--deps/v8/test/mjsunit/compiler/object-isprototypeof.js13
-rw-r--r--deps/v8/test/mjsunit/compiler/regress-9041.js88
-rw-r--r--deps/v8/test/mjsunit/compiler/regress-992684.js26
-rw-r--r--deps/v8/test/mjsunit/compiler/regress-995430.js12
-rw-r--r--deps/v8/test/mjsunit/compiler/regress-995562.js14
-rw-r--r--deps/v8/test/mjsunit/compiler/regress-997100.js15
-rw-r--r--deps/v8/test/mjsunit/compiler/regress-nonextensiblearray-store-outofbounds.js19
-rw-r--r--deps/v8/test/mjsunit/d8/d8-worker-sharedarraybuffer.js4
-rw-r--r--deps/v8/test/mjsunit/d8/d8-worker-shutdown-empty.js42
-rw-r--r--deps/v8/test/mjsunit/d8/d8-worker-shutdown-gc.js56
-rw-r--r--deps/v8/test/mjsunit/d8/d8-worker-shutdown-spawn.js47
-rw-r--r--deps/v8/test/mjsunit/d8/d8-worker-shutdown.js55
-rw-r--r--deps/v8/test/mjsunit/d8/d8-worker.js4
-rw-r--r--deps/v8/test/mjsunit/detach-twice.js (renamed from deps/v8/test/mjsunit/neuter-twice.js)0
-rw-r--r--deps/v8/test/mjsunit/es6/classes.js2
-rw-r--r--deps/v8/test/mjsunit/es6/function-name.js2
-rw-r--r--deps/v8/test/mjsunit/es6/large-classes-properties.js4
-rw-r--r--deps/v8/test/mjsunit/es6/throw-type-error-function-restrictions.js8
-rw-r--r--deps/v8/test/mjsunit/es9/regexp-lookbehind.js1
-rw-r--r--deps/v8/test/mjsunit/es9/regress/regress-904167.js2
-rw-r--r--deps/v8/test/mjsunit/harmony/atomics.js251
-rw-r--r--deps/v8/test/mjsunit/harmony/nullish.js143
-rw-r--r--deps/v8/test/mjsunit/harmony/numeric-separator.js11
-rw-r--r--deps/v8/test/mjsunit/harmony/optional-chaining.js119
-rw-r--r--deps/v8/test/mjsunit/harmony/private-accessors.js91
-rw-r--r--deps/v8/test/mjsunit/harmony/private-methods.js14
-rw-r--r--deps/v8/test/mjsunit/harmony/weakrefs/cleanup-doesnt-iterate-all-holdings.js11
-rw-r--r--deps/v8/test/mjsunit/harmony/weakrefs/cleanup-is-not-a-microtask.js (renamed from deps/v8/test/mjsunit/harmony/weakrefs/cleanup-is-a-microtask.js)36
-rw-r--r--deps/v8/test/mjsunit/harmony/weakrefs/cleanup-on-detached-realm.js5
-rw-r--r--deps/v8/test/mjsunit/harmony/weakrefs/finalizationgroup-and-weakref.js20
-rw-r--r--deps/v8/test/mjsunit/harmony/weakrefs/two-weakrefs.js51
-rw-r--r--deps/v8/test/mjsunit/harmony/weakrefs/weakref-creation-keeps-alive.js13
-rw-r--r--deps/v8/test/mjsunit/harmony/weakrefs/weakref-deref-keeps-alive.js44
-rw-r--r--deps/v8/test/mjsunit/interrupt-budget-override.js3
-rw-r--r--deps/v8/test/mjsunit/mjsunit.js1
-rw-r--r--deps/v8/test/mjsunit/mjsunit.status35
-rw-r--r--deps/v8/test/mjsunit/object-prevent-extensions.js107
-rw-r--r--deps/v8/test/mjsunit/regexp-tier-up.js92
-rw-r--r--deps/v8/test/mjsunit/regress/regress-1000635.js15
-rw-r--r--deps/v8/test/mjsunit/regress/regress-7773.js9
-rw-r--r--deps/v8/test/mjsunit/regress/regress-8510-2.js38
-rw-r--r--deps/v8/test/mjsunit/regress/regress-9546.js53
-rw-r--r--deps/v8/test/mjsunit/regress/regress-9560.js9
-rw-r--r--deps/v8/test/mjsunit/regress/regress-988973.js5
-rw-r--r--deps/v8/test/mjsunit/regress/regress-989914.js12
-rw-r--r--deps/v8/test/mjsunit/regress/regress-991133.js176
-rw-r--r--deps/v8/test/mjsunit/regress/regress-992389.js14
-rw-r--r--deps/v8/test/mjsunit/regress/regress-996234.js18
-rw-r--r--deps/v8/test/mjsunit/regress/regress-996751.js26
-rw-r--r--deps/v8/test/mjsunit/regress/regress-bind-deoptimize.js24
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-1000094.js15
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-1000170.js10
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-109362.js8
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-734051.js12
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-918301.js5
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-980183.js39
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-980422.js29
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-981701.js6
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-986187.js14
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-987205.js68
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-988304.js14
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-990582.js19
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-992914.js59
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-993980.js20
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-994041.js9
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-994719.js12
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-997056.js12
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-997057.js31
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-997320.js8
-rw-r--r--deps/v8/test/mjsunit/regress/regress-crbug-999450.js10
-rw-r--r--deps/v8/test/mjsunit/regress/regress-inlining-printing.js24
-rw-r--r--deps/v8/test/mjsunit/regress/regress-unlink-closures-on-deopt.js6
-rw-r--r--deps/v8/test/mjsunit/regress/regress-v8-9511.js11
-rw-r--r--deps/v8/test/mjsunit/regress/regress-v8-9656.js14
-rw-r--r--deps/v8/test/mjsunit/regress/wasm/regress-8505.js14
-rw-r--r--deps/v8/test/mjsunit/regress/wasm/regress-crbug-1002388.js12
-rw-r--r--deps/v8/test/mjsunit/wasm/asm-wasm-math-intrinsic.js1
-rw-r--r--deps/v8/test/mjsunit/wasm/bigint.js75
-rw-r--r--deps/v8/test/mjsunit/wasm/exceptions-global.js6
-rw-r--r--deps/v8/test/mjsunit/wasm/multi-value.js31
-rw-r--r--deps/v8/test/mjsunit/wasm/test-wasm-module-builder.js261
-rw-r--r--deps/v8/test/mjsunit/wasm/type-reflection-with-anyref.js12
-rw-r--r--deps/v8/test/mjsunit/wasm/type-reflection-with-exnref.js21
-rw-r--r--deps/v8/test/mjsunit/wasm/type-reflection.js268
-rw-r--r--deps/v8/test/mjsunit/wasm/wasm-module-builder.js29
-rw-r--r--deps/v8/test/mkgrokdump/mkgrokdump.cc58
-rw-r--r--deps/v8/test/test262/local-tests/test/language/expressions/class/elements/private-field-on-nested-class.js45
-rw-r--r--deps/v8/test/test262/local-tests/test/language/statements/class/elements/private-field-on-nested-class.js45
-rw-r--r--deps/v8/test/test262/test262.status325
-rw-r--r--deps/v8/test/test262/testcfg.py5
-rw-r--r--deps/v8/test/torque/OWNERS2
-rw-r--r--deps/v8/test/torque/test-torque.tq235
-rw-r--r--deps/v8/test/unittests/BUILD.gn3
-rw-r--r--deps/v8/test/unittests/api/access-check-unittest.cc132
-rw-r--r--deps/v8/test/unittests/base/atomic-utils-unittest.cc4
-rw-r--r--deps/v8/test/unittests/base/platform/condition-variable-unittest.cc6
-rw-r--r--deps/v8/test/unittests/base/platform/platform-unittest.cc2
-rw-r--r--deps/v8/test/unittests/base/platform/semaphore-unittest.cc8
-rw-r--r--deps/v8/test/unittests/codegen/code-stub-assembler-unittest.cc17
-rw-r--r--deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc2
-rw-r--r--deps/v8/test/unittests/compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc3
-rw-r--r--deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc48
-rw-r--r--deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc48
-rw-r--r--deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc6
-rw-r--r--deps/v8/test/unittests/compiler/branch-elimination-unittest.cc19
-rw-r--r--deps/v8/test/unittests/compiler/code-assembler-unittest.cc119
-rw-r--r--deps/v8/test/unittests/compiler/graph-unittest.cc2
-rw-r--r--deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc52
-rw-r--r--deps/v8/test/unittests/compiler/int64-lowering-unittest.cc117
-rw-r--r--deps/v8/test/unittests/compiler/js-call-reducer-unittest.cc4
-rw-r--r--deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc6
-rw-r--r--deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc2
-rw-r--r--deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc28
-rw-r--r--deps/v8/test/unittests/compiler/linkage-tail-call-unittest.cc26
-rw-r--r--deps/v8/test/unittests/compiler/machine-operator-unittest.cc2
-rw-r--r--deps/v8/test/unittests/compiler/node-test-utils.cc1
-rw-r--r--deps/v8/test/unittests/compiler/node-test-utils.h2
-rw-r--r--deps/v8/test/unittests/compiler/redundancy-elimination-unittest.cc177
-rw-r--r--deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc10
-rw-r--r--deps/v8/test/unittests/compiler/typer-unittest.cc2
-rw-r--r--deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc52
-rw-r--r--deps/v8/test/unittests/date/date-cache-unittest.cc16
-rw-r--r--deps/v8/test/unittests/execution/microtask-queue-unittest.cc26
-rw-r--r--deps/v8/test/unittests/heap/barrier-unittest.cc6
-rw-r--r--deps/v8/test/unittests/heap/gc-tracer-unittest.cc47
-rw-r--r--deps/v8/test/unittests/heap/spaces-unittest.cc141
-rw-r--r--deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc22
-rw-r--r--deps/v8/test/unittests/interpreter/bytecode-array-writer-unittest.cc8
-rw-r--r--deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.cc72
-rw-r--r--deps/v8/test/unittests/libplatform/task-queue-unittest.cc4
-rw-r--r--deps/v8/test/unittests/tasks/background-compile-task-unittest.cc2
-rw-r--r--deps/v8/test/unittests/tasks/cancelable-tasks-unittest.cc20
-rw-r--r--deps/v8/test/unittests/torque/torque-unittest.cc7
-rw-r--r--deps/v8/test/unittests/unittests.status13
-rw-r--r--deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc57
-rw-r--r--deps/v8/test/unittests/wasm/trap-handler-x64-unittest.cc2
-rw-r--r--deps/v8/test/unittests/wasm/wasm-code-manager-unittest.cc35
-rw-r--r--deps/v8/test/unittests/wasm/wasm-module-sourcemap-unittest.cc224
-rw-r--r--deps/v8/test/wasm-api-tests/BUILD.gn3
-rw-r--r--deps/v8/test/wasm-api-tests/callbacks.cc40
-rw-r--r--deps/v8/test/wasm-api-tests/finalize.cc144
-rw-r--r--deps/v8/test/wasm-api-tests/globals.cc19
-rw-r--r--deps/v8/test/wasm-api-tests/hostref.cc178
-rw-r--r--deps/v8/test/wasm-api-tests/memory.cc9
-rw-r--r--deps/v8/test/wasm-api-tests/multi-return.cc58
-rw-r--r--deps/v8/test/wasm-api-tests/reflect.cc8
-rw-r--r--deps/v8/test/wasm-api-tests/serialize.cc15
-rw-r--r--deps/v8/test/wasm-api-tests/startup-errors.cc62
-rw-r--r--deps/v8/test/wasm-api-tests/table.cc15
-rw-r--r--deps/v8/test/wasm-api-tests/threads.cc30
-rw-r--r--deps/v8/test/wasm-api-tests/traps.cc63
-rw-r--r--deps/v8/test/wasm-api-tests/wasm-api-test.h55
-rw-r--r--deps/v8/test/wasm-js/OWNERS2
-rw-r--r--deps/v8/test/wasm-js/testcfg.py41
-rw-r--r--deps/v8/test/wasm-js/tests.tar.gz.sha11
-rw-r--r--deps/v8/test/wasm-js/wasm-js.status1
-rw-r--r--deps/v8/test/wasm-spec-tests/testcfg.py15
-rw-r--r--deps/v8/test/wasm-spec-tests/tests.tar.gz.sha12
-rw-r--r--deps/v8/test/wasm-spec-tests/wasm-spec-tests.status69
-rw-r--r--deps/v8/testing/OWNERS2
-rw-r--r--deps/v8/third_party/binutils/OWNERS2
-rw-r--r--deps/v8/third_party/colorama/OWNERS2
-rw-r--r--deps/v8/third_party/inspector_protocol/README.v82
-rwxr-xr-xdeps/v8/third_party/inspector_protocol/code_generator.py5
-rw-r--r--deps/v8/third_party/inspector_protocol/encoding/encoding.cc66
-rw-r--r--deps/v8/third_party/inspector_protocol/encoding/encoding.h32
-rw-r--r--deps/v8/third_party/inspector_protocol/encoding/encoding_test.cc97
-rw-r--r--deps/v8/third_party/v8/builtins/array-sort.tq118
-rw-r--r--deps/v8/third_party/wasm-api/README.v84
-rw-r--r--deps/v8/third_party/wasm-api/example/callback.c3
-rw-r--r--deps/v8/third_party/wasm-api/example/callback.cc22
-rw-r--r--deps/v8/third_party/wasm-api/example/finalize.c58
-rw-r--r--deps/v8/third_party/wasm-api/example/finalize.cc53
-rw-r--r--deps/v8/third_party/wasm-api/example/global.c20
-rw-r--r--deps/v8/third_party/wasm-api/example/global.cc13
-rw-r--r--deps/v8/third_party/wasm-api/example/hello.c3
-rw-r--r--deps/v8/third_party/wasm-api/example/hello.cc14
-rw-r--r--deps/v8/third_party/wasm-api/example/hostref.c269
-rw-r--r--deps/v8/third_party/wasm-api/example/hostref.cc232
-rw-r--r--deps/v8/third_party/wasm-api/example/hostref.wasmbin0 -> 231 bytes
-rw-r--r--deps/v8/third_party/wasm-api/example/hostref.wat24
-rw-r--r--deps/v8/third_party/wasm-api/example/memory.c8
-rw-r--r--deps/v8/third_party/wasm-api/example/memory.cc13
-rw-r--r--deps/v8/third_party/wasm-api/example/multi.c154
-rw-r--r--deps/v8/third_party/wasm-api/example/multi.cc118
-rw-r--r--deps/v8/third_party/wasm-api/example/multi.wasmbin0 -> 81 bytes
-rw-r--r--deps/v8/third_party/wasm-api/example/multi.wat7
-rw-r--r--deps/v8/third_party/wasm-api/example/reflect.c17
-rw-r--r--deps/v8/third_party/wasm-api/example/reflect.cc8
-rw-r--r--deps/v8/third_party/wasm-api/example/serialize.c3
-rw-r--r--deps/v8/third_party/wasm-api/example/serialize.cc18
-rw-r--r--deps/v8/third_party/wasm-api/example/start.c105
-rw-r--r--deps/v8/third_party/wasm-api/example/start.cc88
-rw-r--r--deps/v8/third_party/wasm-api/example/start.wasmbin0 -> 48 bytes
-rw-r--r--deps/v8/third_party/wasm-api/example/start.wat4
-rw-r--r--deps/v8/third_party/wasm-api/example/table.c8
-rw-r--r--deps/v8/third_party/wasm-api/example/table.cc19
-rw-r--r--deps/v8/third_party/wasm-api/example/threads.c3
-rw-r--r--deps/v8/third_party/wasm-api/example/threads.cc12
-rw-r--r--deps/v8/third_party/wasm-api/example/trap.c44
-rw-r--r--deps/v8/third_party/wasm-api/example/trap.cc44
-rw-r--r--deps/v8/third_party/wasm-api/wasm.h60
-rw-r--r--deps/v8/third_party/wasm-api/wasm.hh284
-rw-r--r--deps/v8/tools/BUILD.gn1
-rw-r--r--deps/v8/tools/OWNERS2
-rw-r--r--deps/v8/tools/clusterfuzz/BUILD.gn1
-rw-r--r--deps/v8/tools/clusterfuzz/OWNERS2
-rw-r--r--deps/v8/tools/clusterfuzz/testdata/failure_output.txt4
-rw-r--r--deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt4
-rwxr-xr-xdeps/v8/tools/clusterfuzz/v8_foozzie.py2
-rw-r--r--deps/v8/tools/clusterfuzz/v8_suppressions.py1
-rw-r--r--deps/v8/tools/debug_helper/BUILD.gn104
-rw-r--r--deps/v8/tools/debug_helper/DEPS3
-rw-r--r--deps/v8/tools/debug_helper/README.md6
-rw-r--r--deps/v8/tools/debug_helper/debug-helper-internal.cc58
-rw-r--r--deps/v8/tools/debug_helper/debug-helper-internal.h130
-rw-r--r--deps/v8/tools/debug_helper/debug-helper.h177
-rw-r--r--deps/v8/tools/debug_helper/gen-heap-constants.py63
-rw-r--r--deps/v8/tools/debug_helper/get-object-properties.cc535
-rw-r--r--deps/v8/tools/debug_helper/heap-constants.cc51
-rw-r--r--deps/v8/tools/debug_helper/heap-constants.h28
-rw-r--r--deps/v8/tools/gcmole/BUILD.gn4
-rw-r--r--deps/v8/tools/gcmole/GCMOLE.gn6
-rw-r--r--deps/v8/tools/gcmole/README6
-rw-r--r--deps/v8/tools/gcmole/gcmole-test.cc69
-rw-r--r--deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha12
-rw-r--r--deps/v8/tools/gcmole/gcmole.cc91
-rw-r--r--deps/v8/tools/gcmole/gcmole.lua69
-rw-r--r--deps/v8/tools/gcmole/suspects.whitelist4
-rw-r--r--deps/v8/tools/gcmole/test-expectations.txt20
-rw-r--r--deps/v8/tools/gen-postmortem-metadata.py2
-rw-r--r--deps/v8/tools/heap-stats/categories.js2
-rw-r--r--deps/v8/tools/heap-stats/global-timeline.js18
-rw-r--r--deps/v8/tools/heap-stats/trace-file-reader.js17
-rwxr-xr-xdeps/v8/tools/run-wasm-api-tests.py3
-rw-r--r--deps/v8/tools/testrunner/OWNERS2
-rw-r--r--deps/v8/tools/testrunner/base_runner.py6
-rw-r--r--deps/v8/tools/testrunner/local/junit_output.py49
-rw-r--r--deps/v8/tools/testrunner/local/pool.py13
-rw-r--r--deps/v8/tools/testrunner/local/variants.py2
-rw-r--r--deps/v8/tools/testrunner/testproc/base.py14
-rw-r--r--deps/v8/tools/testrunner/testproc/execution.py2
-rw-r--r--deps/v8/tools/testrunner/testproc/progress.py44
-rw-r--r--deps/v8/tools/testrunner/testproc/timeout.py8
-rwxr-xr-xdeps/v8/tools/torque/format-torque.py27
-rw-r--r--deps/v8/tools/turbolizer/info-view.html2
-rw-r--r--deps/v8/tools/turbolizer/package-lock.json47
-rw-r--r--deps/v8/tools/turbolizer/src/disassembly-view.ts58
-rw-r--r--deps/v8/tools/turbolizer/src/sequence-view.ts2
-rw-r--r--deps/v8/tools/turbolizer/src/source-resolver.ts119
-rw-r--r--deps/v8/tools/turbolizer/src/text-view.ts14
-rw-r--r--deps/v8/tools/turbolizer/turbo-visualizer.css58
-rw-r--r--deps/v8/tools/v8heapconst.py654
-rwxr-xr-xdeps/v8/tools/wasm/update-wasm-spec-tests.sh46
-rw-r--r--deps/v8/tools/whitespace.txt4
-rw-r--r--deps/v8/tools/windbg.js448
1200 files changed, 49580 insertions, 25755 deletions
diff --git a/deps/v8/.gitignore b/deps/v8/.gitignore
index ce47fa3610..6a9bbd6799 100644
--- a/deps/v8/.gitignore
+++ b/deps/v8/.gitignore
@@ -52,6 +52,8 @@
/test/test262/data
/test/test262/harness
/test/wasm-js/data
+/test/wasm-js/tests
+/test/wasm-js/tests.tar.gz
/test/wasm-spec-tests/tests
/test/wasm-spec-tests/tests.tar.gz
/third_party/*
diff --git a/deps/v8/.gn b/deps/v8/.gn
index 328778fb46..d4ad959954 100644
--- a/deps/v8/.gn
+++ b/deps/v8/.gn
@@ -16,4 +16,5 @@ check_targets = []
# These are the list of GN files that run exec_script. This whitelist exists
# to force additional review for new uses of exec_script, which is strongly
# discouraged except for gypi_to_gn calls.
-exec_script_whitelist = build_dotfile_settings.exec_script_whitelist + []
+exec_script_whitelist = build_dotfile_settings.exec_script_whitelist +
+ [ "//build_overrides/build.gni" ]
diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS
index 827d124b0d..1198de8f35 100644
--- a/deps/v8/AUTHORS
+++ b/deps/v8/AUTHORS
@@ -39,6 +39,7 @@ Vewd Software AS <*@vewd.com>
Groupon <*@groupon.com>
Meteor Development Group <*@meteor.com>
Cloudflare, Inc. <*@cloudflare.com>
+Julia Computing, Inc. <*@juliacomputing.com>
Aaron Bieber <deftly@gmail.com>
Abdulla Kamar <abdulla.kamar@gmail.com>
@@ -74,6 +75,7 @@ Colin Ihrig <cjihrig@gmail.com>
Daniel Andersson <kodandersson@gmail.com>
Daniel Bevenius <daniel.bevenius@gmail.com>
Daniel James <dnljms@gmail.com>
+David Carlier <devnexen@gmail.com>
Deepak Mohan <hop2deep@gmail.com>
Deon Dior <diaoyuanjie@gmail.com>
Dominic Farolini <domfarolino@gmail.com>
@@ -163,6 +165,7 @@ Rob Wu <rob@robwu.nl>
Robert Meijer <robert.s.meijer@gmail.com>
Robert Mustacchi <rm@fingolfin.org>
Robert Nagy <robert.nagy@gmail.com>
+Rong Wang <wangrong089@gmail.com>
Ross Kirsling <rkirsling@gmail.com>
Ruben Bridgewater <ruben@bridgewater.de>
Ryan Dahl <ry@tinyclouds.org>
diff --git a/deps/v8/BUILD.gn b/deps/v8/BUILD.gn
index efca4a626f..c486f1a1c8 100644
--- a/deps/v8/BUILD.gn
+++ b/deps/v8/BUILD.gn
@@ -91,7 +91,7 @@ declare_args() {
# Enable embedded builtins.
v8_enable_embedded_builtins = true
- # Enable the registration of unwinding info for Windows/x64.
+ # Enable the registration of unwinding info for Windows x64 and ARM64.
v8_win64_unwinding_info = true
# Enable code comments for builtins in the snapshot (impacts performance).
@@ -187,15 +187,21 @@ declare_args() {
# Enable sharing read-only space across isolates.
# Sets -DV8_SHARED_RO_HEAP.
v8_enable_shared_ro_heap = ""
-}
-# We reuse the snapshot toolchain for building torque and other generators to
-# avoid building v8_libbase on the host more than once. On mips with big endian,
-# the snapshot toolchain is the target toolchain and, hence, can't be used.
-v8_generator_toolchain = v8_snapshot_toolchain
-if (host_cpu == "x64" &&
- (v8_current_cpu == "mips" || v8_current_cpu == "mips64")) {
- v8_generator_toolchain = "//build/toolchain/linux:clang_x64"
+ # Enable lazy source positions by default.
+ v8_enable_lazy_source_positions = true
+
+ # Disable write barriers when GCs are non-incremental and
+ # heap has single generation.
+ v8_disable_write_barriers = false
+
+ # Redirect allocation in young generation so that there will be
+ # only one single generation.
+ v8_enable_single_generation = ""
+
+ # Use token threaded dispatch for the regular expression interpreter.
+ # Use switch-based dispatch if this is false
+ v8_enable_regexp_interpreter_threaded_dispatch = true
}
# Derived defaults.
@@ -231,6 +237,13 @@ if (v8_enable_fast_torque == "") {
v8_enable_fast_torque = v8_enable_fast_mksnapshot
}
+if (v8_enable_single_generation == "") {
+ v8_enable_single_generation = v8_disable_write_barriers
+}
+
+assert(!v8_disable_write_barriers || v8_enable_single_generation,
+ "Disabling write barriers works only with single generation")
+
assert(v8_current_cpu != "x86" || !v8_untrusted_code_mitigations,
"Untrusted code mitigations are unsupported on ia32")
@@ -424,12 +437,21 @@ config("features") {
defines += [ "V8_SNAPSHOT_NATIVE_CODE_COUNTERS" ]
}
}
+ if (v8_enable_single_generation) {
+ defines += [ "V8_ENABLE_SINGLE_GENERATION" ]
+ }
+ if (v8_disable_write_barriers) {
+ defines += [ "V8_DISABLE_WRITE_BARRIERS" ]
+ }
if (v8_use_external_startup_data) {
defines += [ "V8_USE_EXTERNAL_STARTUP_DATA" ]
}
if (v8_enable_concurrent_marking) {
defines += [ "V8_CONCURRENT_MARKING" ]
}
+ if (v8_enable_lazy_source_positions) {
+ defines += [ "V8_ENABLE_LAZY_SOURCE_POSITIONS" ]
+ }
if (v8_check_microtasks_scopes_consistency) {
defines += [ "V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY" ]
}
@@ -451,6 +473,9 @@ config("features") {
if (v8_win64_unwinding_info) {
defines += [ "V8_WIN64_UNWINDING_INFO" ]
}
+ if (v8_enable_regexp_interpreter_threaded_dispatch) {
+ defines += [ "V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH" ]
+ }
}
config("toolchain") {
@@ -968,16 +993,21 @@ torque_files = [
"src/builtins/proxy-set-prototype-of.tq",
"src/builtins/proxy.tq",
"src/builtins/reflect.tq",
+ "src/builtins/regexp-match.tq",
"src/builtins/regexp-replace.tq",
+ "src/builtins/regexp-source.tq",
+ "src/builtins/regexp-test.tq",
"src/builtins/regexp.tq",
"src/builtins/string.tq",
"src/builtins/string-endswith.tq",
"src/builtins/string-html.tq",
"src/builtins/string-iterator.tq",
+ "src/builtins/string-pad.tq",
"src/builtins/string-repeat.tq",
"src/builtins/string-slice.tq",
"src/builtins/string-startswith.tq",
"src/builtins/string-substring.tq",
+ "src/builtins/torque-internal.tq",
"src/builtins/typed-array-createtypedarray.tq",
"src/builtins/typed-array-every.tq",
"src/builtins/typed-array-filter.tq",
@@ -1002,6 +1032,7 @@ if (!v8_enable_i18n_support) {
action("run_torque") {
visibility = [
":*",
+ "tools/debug_helper/:*",
"tools/gcmole/:*",
"test/cctest/:*",
]
@@ -1023,6 +1054,8 @@ action("run_torque") {
"$target_gen_dir/torque-generated/class-definitions-tq.cc",
"$target_gen_dir/torque-generated/class-definitions-tq-inl.h",
"$target_gen_dir/torque-generated/class-definitions-tq.h",
+ "$target_gen_dir/torque-generated/class-debug-readers-tq.cc",
+ "$target_gen_dir/torque-generated/class-debug-readers-tq.h",
"$target_gen_dir/torque-generated/exported-macros-assembler-tq.cc",
"$target_gen_dir/torque-generated/exported-macros-assembler-tq.h",
"$target_gen_dir/torque-generated/csa-types-tq.h",
@@ -1752,6 +1785,8 @@ v8_compiler_sources = [
"src/compiler/escape-analysis-reducer.h",
"src/compiler/escape-analysis.cc",
"src/compiler/escape-analysis.h",
+ "src/compiler/feedback-source.cc",
+ "src/compiler/feedback-source.h",
"src/compiler/frame-states.cc",
"src/compiler/frame-states.h",
"src/compiler/frame.cc",
@@ -1892,8 +1927,6 @@ v8_compiler_sources = [
"src/compiler/types.h",
"src/compiler/value-numbering-reducer.cc",
"src/compiler/value-numbering-reducer.h",
- "src/compiler/vector-slot-pair.cc",
- "src/compiler/vector-slot-pair.h",
"src/compiler/verifier.cc",
"src/compiler/verifier.h",
"src/compiler/wasm-compiler.cc",
@@ -2031,7 +2064,6 @@ v8_source_set("v8_base_without_compiler") {
"src/builtins/builtins-internal.cc",
"src/builtins/builtins-intl.cc",
"src/builtins/builtins-json.cc",
- "src/builtins/builtins-math.cc",
"src/builtins/builtins-number.cc",
"src/builtins/builtins-object.cc",
"src/builtins/builtins-promise.cc",
@@ -2095,6 +2127,7 @@ v8_source_set("v8_base_without_compiler") {
"src/codegen/register-arch.h",
"src/codegen/register-configuration.cc",
"src/codegen/register-configuration.h",
+ "src/codegen/register.cc",
"src/codegen/register.h",
"src/codegen/reglist.h",
"src/codegen/reloc-info.cc",
@@ -2194,6 +2227,9 @@ v8_source_set("v8_base_without_compiler") {
"src/execution/messages.h",
"src/execution/microtask-queue.cc",
"src/execution/microtask-queue.h",
+ "src/execution/protectors-inl.h",
+ "src/execution/protectors.cc",
+ "src/execution/protectors.h",
"src/execution/runtime-profiler.cc",
"src/execution/runtime-profiler.h",
"src/execution/simulator-base.cc",
@@ -2758,7 +2794,6 @@ v8_source_set("v8_base_without_compiler") {
"src/runtime/runtime-typedarray.cc",
"src/runtime/runtime-utils.h",
"src/runtime/runtime-wasm.cc",
- "src/runtime/runtime-weak-refs.cc",
"src/runtime/runtime.cc",
"src/runtime/runtime.h",
"src/sanitizer/asan.h",
@@ -2922,6 +2957,8 @@ v8_source_set("v8_base_without_compiler") {
"src/wasm/wasm-memory.h",
"src/wasm/wasm-module-builder.cc",
"src/wasm/wasm-module-builder.h",
+ "src/wasm/wasm-module-sourcemap.cc",
+ "src/wasm/wasm-module-sourcemap.h",
"src/wasm/wasm-module.cc",
"src/wasm/wasm-module.h",
"src/wasm/wasm-objects-inl.h",
@@ -3109,6 +3146,7 @@ v8_source_set("v8_base_without_compiler") {
"src/diagnostics/arm64/eh-frame-arm64.cc",
"src/execution/arm64/frame-constants-arm64.cc",
"src/execution/arm64/frame-constants-arm64.h",
+ "src/execution/arm64/pointer-auth-arm64.cc",
"src/execution/arm64/simulator-arm64.cc",
"src/execution/arm64/simulator-arm64.h",
"src/execution/arm64/simulator-logic-arm64.cc",
@@ -3116,6 +3154,12 @@ v8_source_set("v8_base_without_compiler") {
"src/regexp/arm64/regexp-macro-assembler-arm64.h",
"src/wasm/baseline/arm64/liftoff-assembler-arm64.h",
]
+ if (is_win) {
+ sources += [
+ "src/diagnostics/unwinding-info-win64.cc",
+ "src/diagnostics/unwinding-info-win64.h",
+ ]
+ }
jumbo_excluded_sources += [
# TODO(mostynb@vewd.com): fix this code so it doesn't need
# to be excluded, see the comments inside.
@@ -3325,6 +3369,7 @@ v8_source_set("torque_base") {
"src/torque/ast.h",
"src/torque/cfg.cc",
"src/torque/cfg.h",
+ "src/torque/class-debug-reader-generator.cc",
"src/torque/constants.h",
"src/torque/contextual.h",
"src/torque/csa-generator.cc",
@@ -3351,6 +3396,8 @@ v8_source_set("torque_base") {
"src/torque/torque-compiler.h",
"src/torque/torque-parser.cc",
"src/torque/torque-parser.h",
+ "src/torque/type-inference.cc",
+ "src/torque/type-inference.h",
"src/torque/type-oracle.cc",
"src/torque/type-oracle.h",
"src/torque/type-visitor.cc",
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog
index 27afc18a51..be6a58859c 100644
--- a/deps/v8/ChangeLog
+++ b/deps/v8/ChangeLog
@@ -1,3 +1,1453 @@
+2019-09-04: Version 7.8.279
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-04: Version 7.8.278
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-04: Version 7.8.277
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-04: Version 7.8.276
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-04: Version 7.8.275
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-04: Version 7.8.274
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-04: Version 7.8.273
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-04: Version 7.8.272
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-04: Version 7.8.271
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-04: Version 7.8.270
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-03: Version 7.8.269
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-03: Version 7.8.268
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-03: Version 7.8.267
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-03: Version 7.8.266
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-03: Version 7.8.265
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-03: Version 7.8.264
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-03: Version 7.8.263
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-03: Version 7.8.262
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-03: Version 7.8.261
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.260
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.259
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.258
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.257
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.256
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.255
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.254
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.253
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.252
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.251
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.250
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.249
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.248
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.247
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.246
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-02: Version 7.8.245
+
+ Performance and stability improvements on all platforms.
+
+
+2019-09-01: Version 7.8.244
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-31: Version 7.8.243
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-31: Version 7.8.242
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.241
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.240
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.239
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.238
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.237
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.236
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.235
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.234
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.233
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-30: Version 7.8.232
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.231
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.230
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.229
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.228
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.227
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.226
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.225
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.224
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.223
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.222
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-29: Version 7.8.221
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.220
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.219
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.218
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.217
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.216
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.215
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.214
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.213
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.212
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.211
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.210
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.209
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-28: Version 7.8.208
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-27: Version 7.8.207
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-27: Version 7.8.206
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-27: Version 7.8.205
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-27: Version 7.8.204
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-27: Version 7.8.203
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-27: Version 7.8.202
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-27: Version 7.8.201
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.200
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.199
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.198
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.197
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.196
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.195
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.194
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.193
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.192
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.191
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-26: Version 7.8.190
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-25: Version 7.8.189
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.188
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.187
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.186
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.185
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.184
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.183
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.182
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.181
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.180
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.179
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-23: Version 7.8.178
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.177
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.176
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.175
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.174
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.173
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.172
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.171
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.170
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.169
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.168
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.167
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.166
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.165
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.164
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.163
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.162
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.161
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.160
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.159
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.158
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-22: Version 7.8.157
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.156
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.155
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.154
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.153
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.152
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.151
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.150
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.149
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.148
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.147
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.146
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.145
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.144
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.143
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.142
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.141
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.140
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-21: Version 7.8.139
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.138
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.137
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.136
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.135
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.134
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.133
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.132
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.131
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.130
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.129
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.128
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.127
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.126
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.125
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.124
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.123
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.122
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.121
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-20: Version 7.8.120
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-19: Version 7.8.119
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-19: Version 7.8.118
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-19: Version 7.8.117
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-19: Version 7.8.116
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-19: Version 7.8.115
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-19: Version 7.8.114
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-16: Version 7.8.113
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-15: Version 7.8.112
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-14: Version 7.8.111
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-14: Version 7.8.110
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-14: Version 7.8.109
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-14: Version 7.8.108
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-14: Version 7.8.107
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-14: Version 7.8.106
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.105
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.104
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.103
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.102
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.101
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.100
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.99
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.98
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.97
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.96
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.95
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.94
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-13: Version 7.8.93
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.92
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.91
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.90
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.89
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.88
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.87
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.86
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.85
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.84
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.83
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.82
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.81
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.80
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.79
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-12: Version 7.8.78
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-09: Version 7.8.77
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-09: Version 7.8.76
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-09: Version 7.8.75
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-09: Version 7.8.74
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-09: Version 7.8.73
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-09: Version 7.8.72
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-08: Version 7.8.71
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-08: Version 7.8.70
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-08: Version 7.8.69
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-08: Version 7.8.68
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-07: Version 7.8.67
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-07: Version 7.8.66
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-07: Version 7.8.65
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-06: Version 7.8.64
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-06: Version 7.8.63
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-06: Version 7.8.62
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-05: Version 7.8.61
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-05: Version 7.8.60
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-04: Version 7.8.59
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-02: Version 7.8.58
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-02: Version 7.8.57
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-02: Version 7.8.56
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-02: Version 7.8.55
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-02: Version 7.8.54
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-02: Version 7.8.53
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-01: Version 7.8.52
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-01: Version 7.8.51
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-01: Version 7.8.50
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-01: Version 7.8.49
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-01: Version 7.8.48
+
+ Performance and stability improvements on all platforms.
+
+
+2019-08-01: Version 7.8.47
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.46
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.45
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.44
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.43
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.42
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.41
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.40
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.39
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.38
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-31: Version 7.8.37
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.36
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.35
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.34
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.33
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.32
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.31
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.30
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.29
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.28
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.27
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.26
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.25
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.24
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.23
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.22
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.21
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.20
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.19
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.18
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.17
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-30: Version 7.8.16
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.15
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.14
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.13
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.12
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.11
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.10
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.9
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.8
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.7
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.6
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.5
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.4
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.3
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-29: Version 7.8.2
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-28: Version 7.8.1
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.310
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.309
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.308
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.307
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.306
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.305
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.304
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.303
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.302
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.301
+
+ Performance and stability improvements on all platforms.
+
+
+2019-07-24: Version 7.7.300
+
+ Performance and stability improvements on all platforms.
+
+
2019-07-23: Version 7.7.299
Performance and stability improvements on all platforms.
diff --git a/deps/v8/DEPS b/deps/v8/DEPS
index 986264356f..a7d4081edb 100644
--- a/deps/v8/DEPS
+++ b/deps/v8/DEPS
@@ -3,6 +3,21 @@
# all paths in here must match this assumption.
vars = {
+ # Fetches only the SDK boot images which match at least one of the whitelist
+ # entries in a comma-separated list.
+ #
+ # Only the X64 and ARM64 QEMU images are downloaded by default. Developers
+ # that need to boot on other target architectures or devices can opt to
+ # download more boot images. Example of images include:
+ #
+ # Emulation:
+ # qemu.x64, qemu.arm64
+ # Hardware:
+ # generic.x64, generic.arm64
+ #
+ # Wildcards are supported (e.g. "qemu.*").
+ 'checkout_fuchsia_boot_images': "qemu.x64,qemu.arm64",
+
'checkout_instrumented_libraries': False,
'chromium_url': 'https://chromium.googlesource.com',
'android_url': 'https://android.googlesource.com',
@@ -12,7 +27,7 @@ vars = {
'check_v8_header_includes': False,
# GN CIPD package version.
- 'gn_version': 'git_revision:972ed755f8e6d31cae9ba15fcd08136ae1a7886f',
+ 'gn_version': 'git_revision:152c5144ceed9592c20f0c8fd55769646077569b',
# luci-go CIPD package version.
'luci_go': 'git_revision:7d11fd9e66407c49cb6c8546a2ae45ea993a240c',
@@ -20,7 +35,7 @@ vars = {
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling android_sdk_build-tools_version
# and whatever else without interference from each other.
- 'android_sdk_build-tools_version': 'DLK621q5_Bga5EsOr7cp6bHWWxFKx6UHLu_Ix_m3AckC',
+ 'android_sdk_build-tools_version': '5DL7LQQjVMLClXLzLgmGysccPGsGcjJdvH9z5-uetiIC',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling android_sdk_emulator_version
# and whatever else without interference from each other.
@@ -57,15 +72,15 @@ vars = {
deps = {
'v8/build':
- Var('chromium_url') + '/chromium/src/build.git' + '@' + '1e5d7d692f816af8136c738b79fe9e8dde8057f6',
+ Var('chromium_url') + '/chromium/src/build.git' + '@' + '693faeda4ee025796c7e473d953a5a7b6ad64c93',
'v8/third_party/depot_tools':
- Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + 'ee7b9dda90e409fb92031d511151debe5db7db9f',
+ Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + 'f38bc1796282c61087dcf15abc61b8fd18a68402',
'v8/third_party/icu':
- Var('chromium_url') + '/chromium/deps/icu.git' + '@' + 'fd97d4326fac6da84452b2d5fe75ff0949368dab',
+ Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '53f6b233a41ec982d8445996247093f7aaf41639',
'v8/third_party/instrumented_libraries':
Var('chromium_url') + '/chromium/src/third_party/instrumented_libraries.git' + '@' + 'b1c3ca20848c117eb935b02c25d441f03e6fbc5e',
'v8/buildtools':
- Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '67b293ca1316d06f7f00160ce35c92b8849a9dc9',
+ Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '74cfb57006f83cfe050817526db359d5c8a11628',
'v8/buildtools/clang_format/script':
Var('chromium_url') + '/chromium/llvm-project/cfe/tools/clang-format.git' + '@' + '96636aa0e9f047f17447f2d45a094d0b59ed7917',
'v8/buildtools/linux64': {
@@ -105,9 +120,9 @@ deps = {
'condition': 'host_os == "win"',
},
'v8/base/trace_event/common':
- Var('chromium_url') + '/chromium/src/base/trace_event/common.git' + '@' + 'cfe8887fa6ac3170e23a68949930e28d4705a16f',
+ Var('chromium_url') + '/chromium/src/base/trace_event/common.git' + '@' + '5e4fce17a9d2439c44a7b57ceecef6df9287ec2f',
'v8/third_party/android_ndk': {
- 'url': Var('chromium_url') + '/android_ndk.git' + '@' + '4e2cea441bfd43f0863d14f57b1e1844260b9884',
+ 'url': Var('chromium_url') + '/android_ndk.git' + '@' + '62582753e869484bf0cc7f7e8d184ce0077033c2',
'condition': 'checkout_android',
},
'v8/third_party/android_sdk/public': {
@@ -153,7 +168,7 @@ deps = {
'dep_type': 'cipd',
},
'v8/third_party/catapult': {
- 'url': Var('chromium_url') + '/catapult.git' + '@' + '53913cecb11a3ef993f6496b9110964e2e2aeec3',
+ 'url': Var('chromium_url') + '/catapult.git' + '@' + 'e7c719c3e85f76938bf4fef0ba37c27f89246f71',
'condition': 'checkout_android',
},
'v8/third_party/colorama/src': {
@@ -161,11 +176,11 @@ deps = {
'condition': 'checkout_android',
},
'v8/third_party/fuchsia-sdk': {
- 'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-sdk.git' + '@' + '5fd29151cf35c0813c33cc368a7c78389e3f5caa',
+ 'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-sdk.git' + '@' + '1785f0ac8e1fe81cb25e260acbe7de8f62fa3e44',
'condition': 'checkout_fuchsia',
},
'v8/third_party/googletest/src':
- Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + '6077f444da944d96d311d358d761164261f1cdd0',
+ Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + '565f1b848215b77c3732bca345fe76a0431d8b34',
'v8/third_party/jinja2':
Var('chromium_url') + '/chromium/src/third_party/jinja2.git' + '@' + 'b41863e42637544c2941b574c7877d3e1f663e25',
'v8/third_party/markupsafe':
@@ -177,7 +192,7 @@ deps = {
'v8/test/mozilla/data':
Var('chromium_url') + '/v8/deps/third_party/mozilla-tests.git' + '@' + 'f6c578a10ea707b1a8ab0b88943fe5115ce2b9be',
'v8/test/test262/data':
- Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + '26a2268436f28f64c4539d9aab9ebd0f0b7c99c5',
+ Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + '59a1a016b7cf5cf43f66b274c7d1db4ec6066935',
'v8/test/test262/harness':
Var('chromium_url') + '/external/github.com/test262-utils/test262-harness-py.git' + '@' + '4555345a943d0c99a9461182705543fb171dda4b',
'v8/third_party/qemu-linux-x64': {
@@ -201,7 +216,7 @@ deps = {
'dep_type': 'cipd',
},
'v8/tools/clang':
- Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + 'f485a21a9cb05494161d97d545c3b29447610ffb',
+ Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + '2fef805e5b05b26a8c87c47865590b5f43218611',
'v8/tools/luci-go': {
'packages': [
{
@@ -230,10 +245,8 @@ deps = {
'condition': 'checkout_mac',
'dep_type': 'cipd',
},
- 'v8/test/wasm-js/data':
- Var('chromium_url') + '/external/github.com/WebAssembly/spec.git' + '@' + '1a411f713d9850ce7da24719aba5bb80c535f562',
'v8/third_party/perfetto':
- Var('android_url') + '/platform/external/perfetto.git' + '@' + '0e8281399fd854de13461f2c1c9f2fb0b8e9c3ae',
+ Var('android_url') + '/platform/external/perfetto.git' + '@' + '01615892494a9a8dc84414962d0a817bf97de2c2',
'v8/third_party/protobuf':
Var('chromium_url') + '/external/github.com/google/protobuf'+ '@' + 'b68a347f56137b4b1a746e8c7438495a6ac1bd91',
}
@@ -347,6 +360,17 @@ hooks = [
],
},
{
+ 'name': 'wasm_js',
+ 'pattern': '.',
+ 'action': [ 'download_from_google_storage',
+ '--no_resume',
+ '--no_auth',
+ '-u',
+ '--bucket', 'v8-wasm-spec-tests',
+ '-s', 'v8/test/wasm-js/tests.tar.gz.sha1',
+ ],
+ },
+ {
'name': 'sysroot_arm',
'pattern': '.',
'condition': '(checkout_linux and checkout_arm)',
@@ -410,6 +434,13 @@ hooks = [
'condition': 'checkout_win',
'action': ['python', 'v8/build/vs_toolchain.py', 'update'],
},
+ {
+ # Update the Mac toolchain if necessary.
+ 'name': 'mac_toolchain',
+ 'pattern': '.',
+ 'condition': 'checkout_mac',
+ 'action': ['python', 'v8/build/mac_toolchain.py'],
+ },
# Pull binutils for linux, enabled debug fission for faster linking /
# debugging when used with clang on Ubuntu Precise.
# https://code.google.com/p/chromium/issues/detail?id=352046
@@ -444,6 +475,7 @@ hooks = [
'action': [
'python',
'v8/build/fuchsia/update_sdk.py',
+ '--boot-images={checkout_fuchsia_boot_images}',
],
},
{
diff --git a/deps/v8/OWNERS b/deps/v8/OWNERS
index be36096666..9ab84b1e27 100644
--- a/deps/v8/OWNERS
+++ b/deps/v8/OWNERS
@@ -1,31 +1,31 @@
# Eng reviewer. Please reach out before adding new top-level directories.
# Disagreement among owners should be escalated to eng reviewers.
-file://ENG_REVIEW_OWNERS
+file:ENG_REVIEW_OWNERS
-per-file .clang-format=file://INFRA_OWNERS
-per-file .clang-tidy=file://INFRA_OWNERS
-per-file .editorconfig=file://INFRA_OWNERS
-per-file .flake8=file://INFRA_OWNERS
-per-file .git-blame-ignore-revs=file://INFRA_OWNERS
-per-file .gitattributes=file://INFRA_OWNERS
-per-file .gitignore=file://INFRA_OWNERS
-per-file .gn=file://INFRA_OWNERS
-per-file .vpython=file://INFRA_OWNERS
-per-file .ycm_extra_conf.py=file://INFRA_OWNERS
-per-file BUILD.gn=file://COMMON_OWNERS
-per-file DEPS=file://INFRA_OWNERS
+per-file .clang-format=file:INFRA_OWNERS
+per-file .clang-tidy=file:INFRA_OWNERS
+per-file .editorconfig=file:INFRA_OWNERS
+per-file .flake8=file:INFRA_OWNERS
+per-file .git-blame-ignore-revs=file:INFRA_OWNERS
+per-file .gitattributes=file:INFRA_OWNERS
+per-file .gitignore=file:INFRA_OWNERS
+per-file .gn=file:INFRA_OWNERS
+per-file .vpython=file:INFRA_OWNERS
+per-file .ycm_extra_conf.py=file:INFRA_OWNERS
+per-file BUILD.gn=file:COMMON_OWNERS
+per-file DEPS=file:INFRA_OWNERS
# For Test262 rolls.
per-file DEPS=mathias@chromium.org
-per-file PRESUBMIT=file://INFRA_OWNERS
-per-file codereview.settings=file://INFRA_OWNERS
+per-file PRESUBMIT=file:INFRA_OWNERS
+per-file codereview.settings=file:INFRA_OWNERS
-per-file AUTHORS=file://COMMON_OWNERS
-per-file WATCHLIST=file://COMMON_OWNERS
+per-file AUTHORS=file:COMMON_OWNERS
+per-file WATCHLIST=file:COMMON_OWNERS
-per-file *-mips*=file://MIPS_OWNERS
-per-file *-mips64*=file://MIPS_OWNERS
-per-file *-ppc*=file://PPC_OWNERS
-per-file *-s390*=file://S390_OWNERS
+per-file *-mips*=file:MIPS_OWNERS
+per-file *-mips64*=file:MIPS_OWNERS
+per-file *-ppc*=file:PPC_OWNERS
+per-file *-s390*=file:S390_OWNERS
# TEAM: v8-dev@googlegroups.com
# COMPONENT: Blink>JavaScript
diff --git a/deps/v8/base/trace_event/common/trace_event_common.h b/deps/v8/base/trace_event/common/trace_event_common.h
index f1878a18da..57ac0254d9 100644
--- a/deps/v8/base/trace_event/common/trace_event_common.h
+++ b/deps/v8/base/trace_event/common/trace_event_common.h
@@ -256,6 +256,13 @@
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \
TRACE_EVENT_FLAG_COPY | scope, arg1_name, arg1_val, \
arg2_name, arg2_val)
+#define TRACE_EVENT_INSTANT_WITH_FLAGS0(category_group, name, scope_and_flags) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \
+ scope_and_flags)
+#define TRACE_EVENT_INSTANT_WITH_FLAGS1(category_group, name, scope_and_flags, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \
+ scope_and_flags, arg1_name, arg1_val)
#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope, \
timestamp) \
@@ -285,12 +292,12 @@
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
arg2_name, arg2_val)
-#define TRACE_EVENT_COPY_BEGIN0(category_group, name) \
- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
- TRACE_EVENT_FLAG_COPY)
-#define TRACE_EVENT_COPY_BEGIN1(category_group, name, arg1_name, arg1_val) \
- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
- TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_BEGIN_WITH_FLAGS0(category_group, name, flags) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, flags)
+#define TRACE_EVENT_BEGIN_WITH_FLAGS1(category_group, name, flags, arg1_name, \
+ arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
+ flags, arg1_name, arg1_val)
#define TRACE_EVENT_COPY_BEGIN2(category_group, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
@@ -341,12 +348,12 @@
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \
TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
arg2_name, arg2_val)
-#define TRACE_EVENT_COPY_END0(category_group, name) \
- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \
- TRACE_EVENT_FLAG_COPY)
-#define TRACE_EVENT_COPY_END1(category_group, name, arg1_name, arg1_val) \
- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \
- TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_END_WITH_FLAGS0(category_group, name, flags) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, flags)
+#define TRACE_EVENT_END_WITH_FLAGS1(category_group, name, flags, arg1_name, \
+ arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, flags, \
+ arg1_name, arg1_val)
#define TRACE_EVENT_COPY_END2(category_group, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \
@@ -580,6 +587,9 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_FLAGS0(category_group, name, id, flags) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+ category_group, name, id, flags)
// Similar to TRACE_EVENT_ASYNC_BEGINx but with a custom |at| timestamp
// provided.
@@ -606,6 +616,11 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP_AND_FLAGS0( \
+ category_group, name, id, timestamp, flags) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, flags)
// Records a single ASYNC_STEP_INTO event for |step| immediately. If the
// category is not enabled, then this does nothing. The |name| and |id| must
@@ -677,6 +692,9 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID( \
TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_ASYNC_END_WITH_FLAGS0(category_group, name, id, flags) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+ category_group, name, id, flags)
// Similar to TRACE_EVENT_ASYNC_ENDx but with a custom |at| timestamp provided.
#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(category_group, name, id, \
@@ -702,6 +720,11 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP_AND_FLAGS0(category_group, name, \
+ id, timestamp, flags) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, flags)
// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
@@ -935,6 +958,9 @@
#define TRACE_TASK_EXECUTION(run_function, task) \
INTERNAL_TRACE_TASK_EXECUTION(run_function, task)
+#define TRACE_LOG_MESSAGE(file, message, line) \
+ INTERNAL_TRACE_LOG_MESSAGE(file, message, line)
+
// TRACE_EVENT_METADATA* events are information related to other
// injected events, not events in their own right.
#define TRACE_EVENT_METADATA1(category_group, name, arg1_name, arg1_val) \
@@ -1075,6 +1101,8 @@
// TODO(eseckler): Remove once we have native support for typed proto events in
// TRACE_EVENT macros.
#define TRACE_EVENT_FLAG_TYPED_PROTO_ARGS (static_cast<unsigned int>(1 << 15))
+#define TRACE_EVENT_FLAG_JAVA_STRING_LITERALS \
+ (static_cast<unsigned int>(1 << 16))
#define TRACE_EVENT_FLAG_SCOPE_MASK \
(static_cast<unsigned int>(TRACE_EVENT_FLAG_SCOPE_OFFSET | \
diff --git a/deps/v8/benchmarks/OWNERS b/deps/v8/benchmarks/OWNERS
index 852d438bb0..3c70cea2fd 100644
--- a/deps/v8/benchmarks/OWNERS
+++ b/deps/v8/benchmarks/OWNERS
@@ -1 +1 @@
-file://COMMON_OWNERS
+file:../COMMON_OWNERS
diff --git a/deps/v8/build_overrides/OWNERS b/deps/v8/build_overrides/OWNERS
index bdb1d555a4..cb04fa0838 100644
--- a/deps/v8/build_overrides/OWNERS
+++ b/deps/v8/build_overrides/OWNERS
@@ -1 +1 @@
-file://INFRA_OWNERS
+file:../INFRA_OWNERS
diff --git a/deps/v8/build_overrides/build.gni b/deps/v8/build_overrides/build.gni
index 12ef8b28d6..5b99eb9402 100644
--- a/deps/v8/build_overrides/build.gni
+++ b/deps/v8/build_overrides/build.gni
@@ -35,5 +35,16 @@ tsan_suppressions_file = "//build/sanitizers/tsan_suppressions.cc"
# Skip assertions about 4GiB file size limit.
ignore_elf32_limitations = true
-# Use the system install of Xcode for tools like ibtool, libtool, etc.
-use_system_xcode = true
+if (host_os == "mac") {
+ _result = exec_script("//build/mac/should_use_hermetic_xcode.py",
+ [ target_os ],
+ "value")
+ assert(_result != 2,
+ "Do not allow building targets with the default" +
+ "hermetic toolchain if the minimum OS version is not met.")
+ assert(_result != 3,
+ "iOS does not support building with a hermetic toolchain. " +
+ "Please install Xcode.")
+
+ use_system_xcode = _result == 0
+}
diff --git a/deps/v8/custom_deps/OWNERS b/deps/v8/custom_deps/OWNERS
index bdb1d555a4..cb04fa0838 100644
--- a/deps/v8/custom_deps/OWNERS
+++ b/deps/v8/custom_deps/OWNERS
@@ -1 +1 @@
-file://INFRA_OWNERS
+file:../INFRA_OWNERS
diff --git a/deps/v8/gni/OWNERS b/deps/v8/gni/OWNERS
index bdb1d555a4..cb04fa0838 100644
--- a/deps/v8/gni/OWNERS
+++ b/deps/v8/gni/OWNERS
@@ -1 +1 @@
-file://INFRA_OWNERS
+file:../INFRA_OWNERS
diff --git a/deps/v8/gni/snapshot_toolchain.gni b/deps/v8/gni/snapshot_toolchain.gni
index f4f1f1d88e..b5fb1823b3 100644
--- a/deps/v8/gni/snapshot_toolchain.gni
+++ b/deps/v8/gni/snapshot_toolchain.gni
@@ -107,3 +107,12 @@ if (v8_snapshot_toolchain == "") {
assert(v8_snapshot_toolchain != "",
"Do not know how to build a snapshot for $current_toolchain " +
"on $host_os $host_cpu")
+
+# We reuse the snapshot toolchain for building torque and other generators to
+# avoid building v8_libbase on the host more than once. On mips with big endian,
+# the snapshot toolchain is the target toolchain and, hence, can't be used.
+v8_generator_toolchain = v8_snapshot_toolchain
+if (host_cpu == "x64" &&
+ (v8_current_cpu == "mips" || v8_current_cpu == "mips64")) {
+ v8_generator_toolchain = "//build/toolchain/linux:clang_x64"
+}
diff --git a/deps/v8/include/OWNERS b/deps/v8/include/OWNERS
index 7ffbf74ce9..b64069847b 100644
--- a/deps/v8/include/OWNERS
+++ b/deps/v8/include/OWNERS
@@ -3,8 +3,8 @@ danno@chromium.org
ulan@chromium.org
yangguo@chromium.org
-per-file *DEPS=file://COMMON_OWNERS
-per-file v8-internal.h=file://COMMON_OWNERS
+per-file *DEPS=file:../COMMON_OWNERS
+per-file v8-internal.h=file:../COMMON_OWNERS
per-file v8-inspector.h=dgozman@chromium.org
per-file v8-inspector.h=pfeldman@chromium.org
per-file v8-inspector.h=kozyatinskiy@chromium.org
diff --git a/deps/v8/include/libplatform/v8-tracing.h b/deps/v8/include/libplatform/v8-tracing.h
index e7cd8bfcdb..df145e95bf 100644
--- a/deps/v8/include/libplatform/v8-tracing.h
+++ b/deps/v8/include/libplatform/v8-tracing.h
@@ -244,6 +244,8 @@ class V8_PLATFORM_EXPORT TracingController
TracingController();
~TracingController() override;
+
+ // Takes ownership of |trace_buffer|.
void Initialize(TraceBuffer* trace_buffer);
#ifdef V8_USE_PERFETTO
// Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides
diff --git a/deps/v8/include/v8-internal.h b/deps/v8/include/v8-internal.h
index ef13006d13..6ecddf45d6 100644
--- a/deps/v8/include/v8-internal.h
+++ b/deps/v8/include/v8-internal.h
@@ -63,8 +63,8 @@ struct SmiTagging<4> {
V8_INLINE static int SmiToInt(const internal::Address value) {
int shift_bits = kSmiTagSize + kSmiShiftSize;
- // Shift down (requires >> to be sign extending).
- return static_cast<int>(static_cast<intptr_t>(value)) >> shift_bits;
+ // Truncate and shift down (requires >> to be sign extending).
+ return static_cast<int32_t>(static_cast<uint32_t>(value)) >> shift_bits;
}
V8_INLINE static constexpr bool IsValidSmi(intptr_t value) {
// Is value in range [kSmiMinValue, kSmiMaxValue].
@@ -152,6 +152,7 @@ class Internals {
static const uint32_t kNumIsolateDataSlots = 4;
+ // IsolateData layout guarantees.
static const int kIsolateEmbedderDataOffset = 0;
static const int kExternalMemoryOffset =
kNumIsolateDataSlots * kApiSystemPointerSize;
@@ -159,8 +160,14 @@ class Internals {
kExternalMemoryOffset + kApiInt64Size;
static const int kExternalMemoryAtLastMarkCompactOffset =
kExternalMemoryLimitOffset + kApiInt64Size;
- static const int kIsolateRootsOffset =
+ static const int kIsolateFastCCallCallerFpOffset =
kExternalMemoryAtLastMarkCompactOffset + kApiInt64Size;
+ static const int kIsolateFastCCallCallerPcOffset =
+ kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize;
+ static const int kIsolateStackGuardOffset =
+ kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize;
+ static const int kIsolateRootsOffset =
+ kIsolateStackGuardOffset + 7 * kApiSystemPointerSize;
static const int kUndefinedValueRootIndex = 4;
static const int kTheHoleValueRootIndex = 5;
@@ -177,7 +184,7 @@ class Internals {
static const int kFirstNonstringType = 0x40;
static const int kOddballType = 0x43;
- static const int kForeignType = 0x47;
+ static const int kForeignType = 0x46;
static const int kJSSpecialApiObjectType = 0x410;
static const int kJSApiObjectType = 0x420;
static const int kJSObjectType = 0x421;
diff --git a/deps/v8/include/v8-platform.h b/deps/v8/include/v8-platform.h
index 7e43b0d9db..b707fafc49 100644
--- a/deps/v8/include/v8-platform.h
+++ b/deps/v8/include/v8-platform.h
@@ -439,14 +439,6 @@ class Platform {
*/
virtual void DumpWithoutCrashing() {}
- /**
- * Lets the embedder to add crash keys.
- */
- virtual void AddCrashKey(int id, const char* name, uintptr_t value) {
- // "noop" is a valid implementation if the embedder doesn't care to log
- // additional data for crashes.
- }
-
protected:
/**
* Default implementation of current wall-clock time in milliseconds
diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h
index 46d3eb8aa4..360850b631 100644
--- a/deps/v8/include/v8-profiler.h
+++ b/deps/v8/include/v8-profiler.h
@@ -18,14 +18,18 @@ namespace v8 {
class HeapGraphNode;
struct HeapStatsUpdate;
-typedef uint32_t SnapshotObjectId;
-
+using NativeObject = void*;
+using SnapshotObjectId = uint32_t;
struct CpuProfileDeoptFrame {
int script_id;
size_t position;
};
+namespace internal {
+class CpuProfile;
+} // namespace internal
+
} // namespace v8
#ifdef V8_OS_WIN
@@ -48,75 +52,6 @@ template class V8_EXPORT std::vector<v8::CpuProfileDeoptInfo>;
namespace v8 {
-// TickSample captures the information collected for each sample.
-struct V8_EXPORT TickSample {
- // Internal profiling (with --prof + tools/$OS-tick-processor) wants to
- // include the runtime function we're calling. Externally exposed tick
- // samples don't care.
- enum RecordCEntryFrame { kIncludeCEntryFrame, kSkipCEntryFrame };
-
- TickSample()
- : state(OTHER),
- pc(nullptr),
- external_callback_entry(nullptr),
- frames_count(0),
- has_external_callback(false),
- update_stats(true) {}
-
- /**
- * Initialize a tick sample from the isolate.
- * \param isolate The isolate.
- * \param state Execution state.
- * \param record_c_entry_frame Include or skip the runtime function.
- * \param update_stats Whether update the sample to the aggregated stats.
- * \param use_simulator_reg_state When set to true and V8 is running under a
- * simulator, the method will use the simulator
- * register state rather than the one provided
- * with |state| argument. Otherwise the method
- * will use provided register |state| as is.
- */
- void Init(Isolate* isolate, const v8::RegisterState& state,
- RecordCEntryFrame record_c_entry_frame, bool update_stats,
- bool use_simulator_reg_state = true);
- /**
- * Get a call stack sample from the isolate.
- * \param isolate The isolate.
- * \param state Register state.
- * \param record_c_entry_frame Include or skip the runtime function.
- * \param frames Caller allocated buffer to store stack frames.
- * \param frames_limit Maximum number of frames to capture. The buffer must
- * be large enough to hold the number of frames.
- * \param sample_info The sample info is filled up by the function
- * provides number of actual captured stack frames and
- * the current VM state.
- * \param use_simulator_reg_state When set to true and V8 is running under a
- * simulator, the method will use the simulator
- * register state rather than the one provided
- * with |state| argument. Otherwise the method
- * will use provided register |state| as is.
- * \note GetStackSample is thread and signal safe and should only be called
- * when the JS thread is paused or interrupted.
- * Otherwise the behavior is undefined.
- */
- static bool GetStackSample(Isolate* isolate, v8::RegisterState* state,
- RecordCEntryFrame record_c_entry_frame,
- void** frames, size_t frames_limit,
- v8::SampleInfo* sample_info,
- bool use_simulator_reg_state = true);
- StateTag state; // The state of the VM.
- void* pc; // Instruction pointer.
- union {
- void* tos; // Top stack value (*sp).
- void* external_callback_entry;
- };
- static const unsigned kMaxFramesCountLog2 = 8;
- static const unsigned kMaxFramesCount = (1 << kMaxFramesCountLog2) - 1;
- void* stack[kMaxFramesCount]; // Call stack.
- unsigned frames_count : kMaxFramesCountLog2; // Number of captured frames.
- bool has_external_callback : 1;
- bool update_stats : 1; // Whether the sample should update aggregated stats.
-};
-
/**
* CpuProfileNode represents a node in a call graph.
*/
@@ -307,6 +242,15 @@ enum CpuProfilingNamingMode {
kDebugNaming,
};
+enum CpuProfilingLoggingMode {
+ // Enables logging when a profile is active, and disables logging when all
+ // profiles are detached.
+ kLazyLogging,
+ // Enables logging for the lifetime of the CpuProfiler. Calls to
+ // StartRecording are faster, at the expense of runtime overhead.
+ kEagerLogging,
+};
+
/**
* Optional profiling attributes.
*/
@@ -328,21 +272,25 @@ class V8_EXPORT CpuProfilingOptions {
* zero, the sampling interval will be equal to
* the profiler's sampling interval.
*/
- CpuProfilingOptions(CpuProfilingMode mode = kLeafNodeLineNumbers,
- unsigned max_samples = kNoSampleLimit,
- int sampling_interval_us = 0)
- : mode_(mode),
- max_samples_(max_samples),
- sampling_interval_us_(sampling_interval_us) {}
+ CpuProfilingOptions(
+ CpuProfilingMode mode = kLeafNodeLineNumbers,
+ unsigned max_samples = kNoSampleLimit, int sampling_interval_us = 0,
+ MaybeLocal<Context> filter_context = MaybeLocal<Context>());
CpuProfilingMode mode() const { return mode_; }
unsigned max_samples() const { return max_samples_; }
int sampling_interval_us() const { return sampling_interval_us_; }
private:
+ friend class internal::CpuProfile;
+
+ bool has_filter_context() const { return !filter_context_.IsEmpty(); }
+ void* raw_filter_context() const;
+
CpuProfilingMode mode_;
unsigned max_samples_;
int sampling_interval_us_;
+ CopyablePersistentTraits<Context>::CopyablePersistent filter_context_;
};
/**
@@ -357,7 +305,8 @@ class V8_EXPORT CpuProfiler {
* |Dispose| method.
*/
static CpuProfiler* New(Isolate* isolate,
- CpuProfilingNamingMode = kDebugNaming);
+ CpuProfilingNamingMode = kDebugNaming,
+ CpuProfilingLoggingMode = kLazyLogging);
/**
* Synchronously collect current stack sample in all profilers attached to
@@ -798,6 +747,12 @@ class V8_EXPORT EmbedderGraph {
*/
virtual const char* NamePrefix() { return nullptr; }
+ /**
+ * Returns the NativeObject that can be used for querying the
+ * |HeapSnapshot|.
+ */
+ virtual NativeObject GetNativeObject() { return nullptr; }
+
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
};
@@ -861,6 +816,12 @@ class V8_EXPORT HeapProfiler {
SnapshotObjectId GetObjectId(Local<Value> value);
/**
+ * Returns SnapshotObjectId for a native object referenced by |value| if it
+ * has been seen by the heap profiler, kUnknownObjectId otherwise.
+ */
+ SnapshotObjectId GetObjectId(NativeObject value);
+
+ /**
* Returns heap object with given SnapshotObjectId if the object is alive,
* otherwise empty handle is returned.
*/
diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h
index 0406f65b08..6e61e2af99 100644
--- a/deps/v8/include/v8-version.h
+++ b/deps/v8/include/v8-version.h
@@ -9,9 +9,9 @@
// NOTE these macros are used by some of the tool scripts and the build
// system so their names cannot be changed without changing the scripts.
#define V8_MAJOR_VERSION 7
-#define V8_MINOR_VERSION 7
-#define V8_BUILD_NUMBER 299
-#define V8_PATCH_LEVEL 11
+#define V8_MINOR_VERSION 8
+#define V8_BUILD_NUMBER 279
+#define V8_PATCH_LEVEL 9
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h
index e1a467ddee..d66f360c99 100644
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <stdio.h>
#include <memory>
+#include <type_traits>
#include <utility>
#include <vector>
@@ -128,6 +129,7 @@ class PropertyCallbackArguments;
class FunctionCallbackArguments;
class GlobalHandles;
class ScopedExternalStringLock;
+class ThreadLocalTop;
namespace wasm {
class NativeModule;
@@ -790,24 +792,43 @@ template <class T>
using UniquePersistent = Global<T>;
/**
- * A traced handle with move semantics, similar to std::unique_ptr. The handle
- * is to be used together with |v8::EmbedderHeapTracer| and specifies edges from
- * the embedder into V8's heap.
+ * Trait specifying behavior of |TracedGlobal<T>|.
+ */
+template <typename T>
+struct TracedGlobalTrait {
+ /**
+ * Specifies whether |TracedGlobal<T>| should clear its handle on destruction.
+ *
+ * V8 will *not* clear the embedder-side memory of the handle. The embedder is
+ * expected to report all |TracedGlobal<T>| handles through
+ * |EmbedderHeapTracer| upon garabge collection.
+ *
+ * See |EmbedderHeapTracer::IsRootForNonTracingGC| for handling with
+ * non-tracing GCs in V8.
+ */
+ static constexpr bool kRequiresExplicitDestruction = true;
+};
+
+/**
+ * A traced handle with copy and move semantics. The handle is to be used
+ * together with |v8::EmbedderHeapTracer| and specifies edges from the embedder
+ * into V8's heap.
*
* The exact semantics are:
* - Tracing garbage collections use |v8::EmbedderHeapTracer|.
* - Non-tracing garbage collections refer to
* |v8::EmbedderHeapTracer::IsRootForNonTracingGC()| whether the handle should
* be treated as root or not.
+ *
+ * For destruction semantics see |TracedGlobalTrait<T>|.
*/
template <typename T>
-class V8_EXPORT TracedGlobal {
+class TracedGlobal {
public:
/**
* An empty TracedGlobal without storage cell.
*/
TracedGlobal() = default;
- ~TracedGlobal() { Reset(); }
/**
* Construct a TracedGlobal from a Local.
@@ -824,7 +845,41 @@ class V8_EXPORT TracedGlobal {
/**
* Move constructor initializing TracedGlobal from an existing one.
*/
- V8_INLINE TracedGlobal(TracedGlobal&& other);
+ V8_INLINE TracedGlobal(TracedGlobal&& other) {
+ // Forward to operator=.
+ *this = std::move(other);
+ }
+
+ /**
+ * Move constructor initializing TracedGlobal from an existing one.
+ */
+ template <typename S>
+ V8_INLINE TracedGlobal(TracedGlobal<S>&& other) {
+ // Forward to operator=.
+ *this = std::move(other);
+ }
+
+ /**
+ * Copy constructor initializing TracedGlobal from an existing one.
+ */
+ V8_INLINE TracedGlobal(const TracedGlobal& other) {
+ // Forward to operator=;
+ *this = other;
+ }
+
+ /**
+ * Copy constructor initializing TracedGlobal from an existing one.
+ */
+ template <typename S>
+ V8_INLINE TracedGlobal(const TracedGlobal<S>& other) {
+ // Forward to operator=;
+ *this = other;
+ }
+
+ /**
+ * Move assignment operator initializing TracedGlobal from an existing one.
+ */
+ V8_INLINE TracedGlobal& operator=(TracedGlobal&& rhs);
/**
* Move assignment operator initializing TracedGlobal from an existing one.
@@ -833,10 +888,21 @@ class V8_EXPORT TracedGlobal {
V8_INLINE TracedGlobal& operator=(TracedGlobal<S>&& rhs);
/**
- * TracedGlobal only supports move semantics and forbids copying.
+ * Copy assignment operator initializing TracedGlobal from an existing one.
+ *
+ * Note: Prohibited when |other| has a finalization callback set through
+ * |SetFinalizationCallback|.
+ */
+ V8_INLINE TracedGlobal& operator=(const TracedGlobal& rhs);
+
+ /**
+ * Copy assignment operator initializing TracedGlobal from an existing one.
+ *
+ * Note: Prohibited when |other| has a finalization callback set through
+ * |SetFinalizationCallback|.
*/
- TracedGlobal(const TracedGlobal&) = delete;
- void operator=(const TracedGlobal&) = delete;
+ template <class S>
+ V8_INLINE TracedGlobal& operator=(const TracedGlobal<S>& rhs);
/**
* Returns true if this TracedGlobal is empty, i.e., has not been assigned an
@@ -870,8 +936,8 @@ class V8_EXPORT TracedGlobal {
template <class S>
V8_INLINE bool operator==(const TracedGlobal<S>& that) const {
- internal::Address* a = reinterpret_cast<internal::Address*>(this->val_);
- internal::Address* b = reinterpret_cast<internal::Address*>(that.val_);
+ internal::Address* a = reinterpret_cast<internal::Address*>(**this);
+ internal::Address* b = reinterpret_cast<internal::Address*>(*that);
if (a == nullptr) return b == nullptr;
if (b == nullptr) return false;
return *a == *b;
@@ -879,8 +945,8 @@ class V8_EXPORT TracedGlobal {
template <class S>
V8_INLINE bool operator==(const Local<S>& that) const {
- internal::Address* a = reinterpret_cast<internal::Address*>(this->val_);
- internal::Address* b = reinterpret_cast<internal::Address*>(that.val_);
+ internal::Address* a = reinterpret_cast<internal::Address*>(**this);
+ internal::Address* b = reinterpret_cast<internal::Address*>(*that);
if (a == nullptr) return b == nullptr;
if (b == nullptr) return false;
return *a == *b;
@@ -921,11 +987,32 @@ class V8_EXPORT TracedGlobal {
void* parameter, WeakCallbackInfo<void>::Callback callback);
private:
- V8_INLINE static T* New(Isolate* isolate, T* that, T** slot);
+ // Wrapping type used when clearing on destruction is required.
+ struct WrappedForDestruction {
+ T* value;
+
+ explicit WrappedForDestruction(T* val) : value(val) {}
+ ~WrappedForDestruction();
+ operator T*() const { return value; }
+ T* operator*() const { return value; }
+ T* operator->() const { return value; }
+ WrappedForDestruction& operator=(const WrappedForDestruction& other) {
+ value = other.value;
+ return *this;
+ }
+ WrappedForDestruction& operator=(T* val) {
+ value = val;
+ return *this;
+ }
+ };
+
+ V8_INLINE static T* New(Isolate* isolate, T* that, void* slot);
T* operator*() const { return this->val_; }
- T* val_ = nullptr;
+ typename std::conditional<
+ TracedGlobalTrait<TracedGlobal<T>>::kRequiresExplicitDestruction,
+ WrappedForDestruction, T*>::type val_{nullptr};
friend class EmbedderHeapTracer;
template <typename F>
@@ -1968,6 +2055,7 @@ struct SampleInfo {
StateTag vm_state; // Current VM state.
void* external_callback_entry; // External callback address if VM is
// executing an external callback.
+ void* top_context; // Incumbent native context address.
};
struct MemoryRange {
@@ -3698,6 +3786,15 @@ class V8_EXPORT Object : public Value {
bool IsConstructor();
/**
+ * True if this object can carry information relevant to the embedder in its
+ * embedder fields, false otherwise. This is generally true for objects
+ * constructed through function templates but also holds for other types where
+ * V8 automatically adds internal fields at compile time, such as e.g.
+ * v8::ArrayBuffer.
+ */
+ bool IsApiWrapper();
+
+ /**
* Call an Object as a function if a callback is set by the
* ObjectTemplate::SetCallAsFunctionHandler method.
*/
@@ -4762,8 +4859,8 @@ class V8_EXPORT ArrayBuffer : public Object {
bool IsDetachable() const;
// TODO(913887): fix the use of 'neuter' in the API.
- V8_DEPRECATE_SOON("Use IsDetachable() instead.",
- inline bool IsNeuterable() const) {
+ V8_DEPRECATED("Use IsDetachable() instead.",
+ inline bool IsNeuterable() const) {
return IsDetachable();
}
@@ -4776,7 +4873,7 @@ class V8_EXPORT ArrayBuffer : public Object {
void Detach();
// TODO(913887): fix the use of 'neuter' in the API.
- V8_DEPRECATE_SOON("Use Detach() instead.", inline void Neuter()) { Detach(); }
+ V8_DEPRECATED("Use Detach() instead.", inline void Neuter()) { Detach(); }
/**
* Make this ArrayBuffer external. The pointer to underlying memory block
@@ -5379,6 +5476,32 @@ class V8_EXPORT RegExp : public Object {
static void CheckCast(Value* obj);
};
+/**
+ * An instance of the built-in FinalizationGroup constructor.
+ *
+ * This API is experimental and may change significantly.
+ */
+class V8_EXPORT FinalizationGroup : public Object {
+ public:
+ /**
+ * Runs the cleanup callback of the given FinalizationGroup.
+ *
+ * V8 will inform the embedder that there are finalizer callbacks be
+ * called through HostCleanupFinalizationGroupCallback.
+ *
+ * HostCleanupFinalizationGroupCallback should schedule a task to
+ * call FinalizationGroup::Cleanup() at some point in the
+ * future. It's the embedders responsiblity to make this call at a
+ * time which does not interrupt synchronous ECMAScript code
+ * execution.
+ *
+ * If the result is Nothing<bool> then an exception has
+ * occurred. Otherwise the result is |true| if the cleanup callback
+ * was called successfully. The result is never |false|.
+ */
+ static V8_WARN_UNUSED_RESULT Maybe<bool> Cleanup(
+ Local<FinalizationGroup> finalization_group);
+};
/**
* A JavaScript value that wraps a C++ void*. This type of value is mainly used
@@ -6439,11 +6562,18 @@ class V8_EXPORT ResourceConstraints {
* provided heap size limit. The heap size includes both the young and
* the old generation.
*
+ * \param initial_heap_size_in_bytes The initial heap size or zero.
+ * By default V8 starts with a small heap and dynamically grows it to
+ * match the set of live objects. This may lead to ineffective
+ * garbage collections at startup if the live set is large.
+ * Setting the initial heap size avoids such garbage collections.
+ * Note that this does not affect young generation garbage collections.
+ *
* \param maximum_heap_size_in_bytes The hard limit for the heap size.
* When the heap size approaches this limit, V8 will perform series of
- * garbage collections and invoke the NearHeapLimitCallback.
- * If the garbage collections do not help and the callback does not
- * increase the limit, then V8 will crash with V8::FatalProcessOutOfMemory.
+ * garbage collections and invoke the NearHeapLimitCallback. If the garbage
+ * collections do not help and the callback does not increase the limit,
+ * then V8 will crash with V8::FatalProcessOutOfMemory.
*/
void ConfigureDefaultsFromHeapSize(size_t initial_heap_size_in_bytes,
size_t maximum_heap_size_in_bytes);
@@ -6611,11 +6741,35 @@ typedef void* (*CreateHistogramCallback)(const char* name,
typedef void (*AddHistogramSampleCallback)(void* histogram, int sample);
+// --- Crashkeys Callback ---
+enum class CrashKeyId {
+ kIsolateAddress,
+ kReadonlySpaceFirstPageAddress,
+ kMapSpaceFirstPageAddress,
+ kCodeSpaceFirstPageAddress,
+};
+
+typedef void (*AddCrashKeyCallback)(CrashKeyId id, const std::string& value);
+
// --- Enter/Leave Script Callback ---
typedef void (*BeforeCallEnteredCallback)(Isolate*);
typedef void (*CallCompletedCallback)(Isolate*);
/**
+ * HostCleanupFinalizationGroupCallback is called when we require the
+ * embedder to enqueue a task that would call
+ * FinalizationGroup::Cleanup().
+ *
+ * The FinalizationGroup is the one for which the embedder needs to
+ * call FinalizationGroup::Cleanup() on.
+ *
+ * The context provided is the one in which the FinalizationGroup was
+ * created in.
+ */
+typedef void (*HostCleanupFinalizationGroupCallback)(
+ Local<Context> context, Local<FinalizationGroup> fg);
+
+/**
* HostImportModuleDynamicallyCallback is called when we require the
* embedder to load a module. This is used as part of the dynamic
* import syntax.
@@ -6712,7 +6866,8 @@ class PromiseRejectMessage {
typedef void (*PromiseRejectCallback)(PromiseRejectMessage message);
// --- Microtasks Callbacks ---
-typedef void (*MicrotasksCompletedCallback)(Isolate*);
+V8_DEPRECATE_SOON("Use *WithData version.",
+ typedef void (*MicrotasksCompletedCallback)(Isolate*));
typedef void (*MicrotasksCompletedCallbackWithData)(Isolate*, void*);
typedef void (*MicrotaskCallback)(void* data);
@@ -6884,6 +7039,10 @@ typedef void (*WasmStreamingCallback)(const FunctionCallbackInfo<Value>&);
// --- Callback for checking if WebAssembly threads are enabled ---
typedef bool (*WasmThreadsEnabledCallback)(Local<Context> context);
+// --- Callback for loading source map file for WASM profiling support
+typedef Local<String> (*WasmLoadSourceMapCallback)(Isolate* isolate,
+ const char* name);
+
// --- Garbage Collection Callbacks ---
/**
@@ -7260,7 +7419,7 @@ class V8_EXPORT EmbedderHeapTracer {
/**
* Called at the beginning of a GC cycle.
*/
- V8_DEPRECATE_SOON("Use version with flags.", virtual void TracePrologue()) {}
+ V8_DEPRECATED("Use version with flags.", virtual void TracePrologue()) {}
virtual void TracePrologue(TraceFlags flags);
/**
@@ -7288,8 +7447,9 @@ class V8_EXPORT EmbedderHeapTracer {
* overriden to fill a |TraceSummary| that is used by V8 to schedule future
* garbage collections.
*/
- virtual void TraceEpilogue() {}
- virtual void TraceEpilogue(TraceSummary* trace_summary) { TraceEpilogue(); }
+ V8_DEPRECATE_SOON("Use version with parameter.",
+ virtual void TraceEpilogue()) {}
+ virtual void TraceEpilogue(TraceSummary* trace_summary);
/**
* Called upon entering the final marking pause. No more incremental marking
@@ -7311,14 +7471,37 @@ class V8_EXPORT EmbedderHeapTracer {
/**
* Returns true if the TracedGlobal handle should be considered as root for
* the currently running non-tracing garbage collection and false otherwise.
+ * The default implementation will keep all TracedGlobal references as roots.
+ *
+ * If this returns false, then V8 may decide that the object referred to by
+ * such a handle is reclaimed. In that case:
+ * - No action is required if handles are used with destructors.
+ * - When run without destructors (by specializing
+ * |TracedGlobalTrait::kRequiresExplicitDestruction|) V8 calls
+ * |ResetHandleInNonTracingGC|.
*
- * Default implementation will keep all TracedGlobal references as roots.
+ * Note that the |handle| is different from the |TracedGlobal<T>| handle that
+ * the embedder holds for retaining the object. The embedder may use
+ * |TracedGlobal<T>::WrapperClassId()| to distinguish cases where it wants
+ * handles to be treated as roots from not being treated as roots.
*/
virtual bool IsRootForNonTracingGC(
const v8::TracedGlobal<v8::Value>& handle) {
return true;
}
+ /**
+ * Used in combination with |IsRootForNonTracingGC|. Called by V8 when an
+ * object that is backed by a handle is reclaimed by a non-tracing garbage
+ * collection. It is up to the embedder to reset the original handle.
+ *
+ * Note that the |handle| is different from the |TracedGlobal<T>| handle that
+ * the embedder holds for retaining the object. It is up to the embedder to
+ * find the orignal |TracedGlobal<T>| handle via the object or class id.
+ */
+ virtual void ResetHandleInNonTracingGC(
+ const v8::TracedGlobal<v8::Value>& handle) {}
+
/*
* Called by the embedder to immediately perform a full garbage collection.
*
@@ -7550,6 +7733,9 @@ class V8_EXPORT Isolate {
private:
internal::Isolate* const isolate_;
internal::MicrotaskQueue* const microtask_queue_;
+ internal::Address previous_stack_height_;
+
+ friend class internal::ThreadLocalTop;
};
/**
@@ -7663,9 +7849,10 @@ class V8_EXPORT Isolate {
kStringNormalize = 75,
kCallSiteAPIGetFunctionSloppyCall = 76,
kCallSiteAPIGetThisSloppyCall = 77,
+ kRegExpMatchAllWithNonGlobalRegExp = 78,
// If you add new values here, you'll also need to update Chromium's:
- // web_feature.mojom, UseCounterCallback.cpp, and enums.xml. V8 changes to
+ // web_feature.mojom, use_counter_callback.cc, and enums.xml. V8 changes to
// this list need to be landed first, then changes on the Chromium side.
kUseCounterFeatureCount // This enum value must be last.
};
@@ -7724,6 +7911,18 @@ class V8_EXPORT Isolate {
static Isolate* GetCurrent();
/**
+ * Clears the set of objects held strongly by the heap. This set of
+ * objects are originally built when a WeakRef is created or
+ * successfully dereferenced.
+ *
+ * The embedder is expected to call this when a synchronous sequence
+ * of ECMAScript execution completes. It's the embedders
+ * responsiblity to make this call at a time which does not
+ * interrupt synchronous ECMAScript code execution.
+ */
+ void ClearKeptObjects();
+
+ /**
* Custom callback used by embedders to help V8 determine if it should abort
* when it throws and no internal handler is predicted to catch the
* exception. If --abort-on-uncaught-exception is used on the command line,
@@ -7737,6 +7936,14 @@ class V8_EXPORT Isolate {
AbortOnUncaughtExceptionCallback callback);
/**
+ * This specifies the callback to be called when finalization groups
+ * are ready to be cleaned up and require FinalizationGroup::Cleanup()
+ * to be called in a future task.
+ */
+ void SetHostCleanupFinalizationGroupCallback(
+ HostCleanupFinalizationGroupCallback callback);
+
+ /**
* This specifies the callback called by the upcoming dynamic
* import() language feature to load modules.
*/
@@ -8290,6 +8497,13 @@ class V8_EXPORT Isolate {
void SetAddHistogramSampleFunction(AddHistogramSampleCallback);
/**
+ * Enables the host application to provide a mechanism for recording a
+ * predefined set of data as crash keys to be used in postmortem debugging in
+ * case of a crash.
+ */
+ void SetAddCrashKeyCallback(AddCrashKeyCallback);
+
+ /**
* Optional notification that the embedder is idle.
* V8 uses the notification to perform garbage collection.
* This call can be used repeatedly if the embedder remains idle.
@@ -8488,6 +8702,8 @@ class V8_EXPORT Isolate {
void SetWasmThreadsEnabledCallback(WasmThreadsEnabledCallback callback);
+ void SetWasmLoadSourceMapCallback(WasmLoadSourceMapCallback callback);
+
/**
* Check if V8 is dead and therefore unusable. This is the case after
* fatal errors such as out-of-memory situations.
@@ -8850,11 +9066,14 @@ class V8_EXPORT V8 {
internal::Address* handle);
static internal::Address* GlobalizeTracedReference(internal::Isolate* isolate,
internal::Address* handle,
- internal::Address* slot);
+ internal::Address* slot,
+ bool has_destructor);
static void MoveGlobalReference(internal::Address** from,
internal::Address** to);
static void MoveTracedGlobalReference(internal::Address** from,
internal::Address** to);
+ static void CopyTracedGlobalReference(const internal::Address* const* from,
+ internal::Address** to);
static internal::Address* CopyGlobalReference(internal::Address* from);
static void DisposeGlobal(internal::Address* global_handle);
static void DisposeTracedGlobal(internal::Address* global_handle);
@@ -9937,18 +10156,26 @@ Global<T>& Global<T>::operator=(Global<S>&& rhs) {
}
template <class T>
-T* TracedGlobal<T>::New(Isolate* isolate, T* that, T** slot) {
+TracedGlobal<T>::WrappedForDestruction::~WrappedForDestruction() {
+ if (value == nullptr) return;
+ V8::DisposeTracedGlobal(reinterpret_cast<internal::Address*>(value));
+ value = nullptr;
+}
+
+template <class T>
+T* TracedGlobal<T>::New(Isolate* isolate, T* that, void* slot) {
if (that == nullptr) return nullptr;
internal::Address* p = reinterpret_cast<internal::Address*>(that);
return reinterpret_cast<T*>(V8::GlobalizeTracedReference(
reinterpret_cast<internal::Isolate*>(isolate), p,
- reinterpret_cast<internal::Address*>(slot)));
+ reinterpret_cast<internal::Address*>(slot),
+ TracedGlobalTrait<TracedGlobal<T>>::kRequiresExplicitDestruction));
}
template <class T>
void TracedGlobal<T>::Reset() {
if (IsEmpty()) return;
- V8::DisposeTracedGlobal(reinterpret_cast<internal::Address*>(val_));
+ V8::DisposeTracedGlobal(reinterpret_cast<internal::Address*>(**this));
val_ = nullptr;
}
@@ -9962,19 +10189,23 @@ void TracedGlobal<T>::Reset(Isolate* isolate, const Local<S>& other) {
}
template <class T>
-TracedGlobal<T>::TracedGlobal(TracedGlobal&& other) : val_(other.val_) {
- if (other.val_ != nullptr) {
- V8::MoveTracedGlobalReference(
- reinterpret_cast<internal::Address**>(&other.val_),
- reinterpret_cast<internal::Address**>(&this->val_));
- other.val_ = nullptr;
- }
+template <class S>
+TracedGlobal<T>& TracedGlobal<T>::operator=(TracedGlobal<S>&& rhs) {
+ TYPE_CHECK(T, S);
+ *this = std::move(rhs.template As<T>());
+ return *this;
}
template <class T>
template <class S>
-TracedGlobal<T>& TracedGlobal<T>::operator=(TracedGlobal<S>&& rhs) {
+TracedGlobal<T>& TracedGlobal<T>::operator=(const TracedGlobal<S>& rhs) {
TYPE_CHECK(T, S);
+ *this = rhs.template As<T>();
+ return *this;
+}
+
+template <class T>
+TracedGlobal<T>& TracedGlobal<T>::operator=(TracedGlobal&& rhs) {
if (this != &rhs) {
this->Reset();
if (rhs.val_ != nullptr) {
@@ -9989,10 +10220,23 @@ TracedGlobal<T>& TracedGlobal<T>::operator=(TracedGlobal<S>&& rhs) {
}
template <class T>
+TracedGlobal<T>& TracedGlobal<T>::operator=(const TracedGlobal& rhs) {
+ if (this != &rhs) {
+ this->Reset();
+ if (rhs.val_ != nullptr) {
+ V8::CopyTracedGlobalReference(
+ reinterpret_cast<const internal::Address* const*>(&rhs.val_),
+ reinterpret_cast<internal::Address**>(&this->val_));
+ }
+ }
+ return *this;
+}
+
+template <class T>
void TracedGlobal<T>::SetWrapperClassId(uint16_t class_id) {
typedef internal::Internals I;
if (IsEmpty()) return;
- internal::Address* obj = reinterpret_cast<internal::Address*>(this->val_);
+ internal::Address* obj = reinterpret_cast<internal::Address*>(**this);
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + I::kNodeClassIdOffset;
*reinterpret_cast<uint16_t*>(addr) = class_id;
}
@@ -10001,7 +10245,7 @@ template <class T>
uint16_t TracedGlobal<T>::WrapperClassId() const {
typedef internal::Internals I;
if (IsEmpty()) return 0;
- internal::Address* obj = reinterpret_cast<internal::Address*>(this->val_);
+ internal::Address* obj = reinterpret_cast<internal::Address*>(**this);
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + I::kNodeClassIdOffset;
return *reinterpret_cast<uint16_t*>(addr);
}
@@ -10010,7 +10254,7 @@ template <class T>
void TracedGlobal<T>::SetFinalizationCallback(
void* parameter, typename WeakCallbackInfo<void>::Callback callback) {
V8::SetFinalizationCallbackTraced(
- reinterpret_cast<internal::Address*>(this->val_), parameter, callback);
+ reinterpret_cast<internal::Address*>(**this), parameter, callback);
}
template <typename T>
@@ -10944,9 +11188,12 @@ int64_t Isolate::AdjustAmountOfExternalAllocatedMemory(
}
if (change_in_bytes < 0) {
- const int64_t lower_limit = *external_memory_limit + change_in_bytes;
- if (lower_limit > I::kExternalAllocationSoftLimit)
+ const int64_t lower_limit =
+ static_cast<int64_t>(static_cast<uint64_t>(*external_memory_limit) +
+ static_cast<uint64_t>(change_in_bytes));
+ if (lower_limit > I::kExternalAllocationSoftLimit) {
*external_memory_limit = lower_limit;
+ }
} else if (change_in_bytes > 0 && amount > *external_memory_limit) {
ReportExternalAllocationLimitReached();
}
diff --git a/deps/v8/include/v8config.h b/deps/v8/include/v8config.h
index 7bd2938225..7670c0e449 100644
--- a/deps/v8/include/v8config.h
+++ b/deps/v8/include/v8config.h
@@ -186,6 +186,8 @@
// V8_HAS_BUILTIN_SADD_OVERFLOW - __builtin_sadd_overflow() supported
// V8_HAS_BUILTIN_SSUB_OVERFLOW - __builtin_ssub_overflow() supported
// V8_HAS_BUILTIN_UADD_OVERFLOW - __builtin_uadd_overflow() supported
+// V8_HAS_COMPUTED_GOTO - computed goto/labels as values
+// supported
// V8_HAS_DECLSPEC_DEPRECATED - __declspec(deprecated) supported
// V8_HAS_DECLSPEC_NOINLINE - __declspec(noinline) supported
// V8_HAS_DECLSPEC_SELECTANY - __declspec(selectany) supported
@@ -214,6 +216,7 @@
# define V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT \
(__has_attribute(warn_unused_result))
+# define V8_HAS_BUILTIN_ASSUME_ALIGNED (__has_builtin(__builtin_assume_aligned))
# define V8_HAS_BUILTIN_BSWAP16 (__has_builtin(__builtin_bswap16))
# define V8_HAS_BUILTIN_BSWAP32 (__has_builtin(__builtin_bswap32))
# define V8_HAS_BUILTIN_BSWAP64 (__has_builtin(__builtin_bswap64))
@@ -226,6 +229,10 @@
# define V8_HAS_BUILTIN_SSUB_OVERFLOW (__has_builtin(__builtin_ssub_overflow))
# define V8_HAS_BUILTIN_UADD_OVERFLOW (__has_builtin(__builtin_uadd_overflow))
+// Clang has no __has_feature for computed gotos.
+// GCC doc: https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
+# define V8_HAS_COMPUTED_GOTO 1
+
# if __cplusplus >= 201402L
# define V8_CAN_HAVE_DCHECK_IN_CONSTEXPR 1
# endif
@@ -256,12 +263,16 @@
# define V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT \
(!V8_CC_INTEL && V8_GNUC_PREREQ(4, 1, 0))
+# define V8_HAS_BUILTIN_ASSUME_ALIGNED (V8_GNUC_PREREQ(4, 7, 0))
# define V8_HAS_BUILTIN_CLZ (V8_GNUC_PREREQ(3, 4, 0))
# define V8_HAS_BUILTIN_CTZ (V8_GNUC_PREREQ(3, 4, 0))
# define V8_HAS_BUILTIN_EXPECT (V8_GNUC_PREREQ(2, 96, 0))
# define V8_HAS_BUILTIN_FRAME_ADDRESS (V8_GNUC_PREREQ(2, 96, 0))
# define V8_HAS_BUILTIN_POPCOUNT (V8_GNUC_PREREQ(3, 4, 0))
+// GCC doc: https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
+#define V8_HAS_COMPUTED_GOTO (V8_GNUC_PREREQ(2, 0, 0))
+
#endif
#if defined(_MSC_VER)
@@ -291,6 +302,12 @@
# define V8_INLINE inline
#endif
+#if V8_HAS_BUILTIN_ASSUME_ALIGNED
+# define V8_ASSUME_ALIGNED(ptr, alignment) \
+ __builtin_assume_aligned((ptr), (alignment))
+#else
+# define V8_ASSUME_ALIGNED(ptr) (ptr)
+#endif
// A macro used to tell the compiler to never inline a particular function.
// Don't bother for debug builds.
diff --git a/deps/v8/infra/OWNERS b/deps/v8/infra/OWNERS
index a75a43666e..a33a8ba8ed 100644
--- a/deps/v8/infra/OWNERS
+++ b/deps/v8/infra/OWNERS
@@ -1,3 +1,3 @@
-file://INFRA_OWNERS
+file:../INFRA_OWNERS
tandrii@chromium.org
diff --git a/deps/v8/infra/testing/builders.pyl b/deps/v8/infra/testing/builders.pyl
index 13a73f3e94..759d920b7b 100644
--- a/deps/v8/infra/testing/builders.pyl
+++ b/deps/v8/infra/testing/builders.pyl
@@ -483,13 +483,8 @@
'swarming_dimensions' : {
'os': 'Ubuntu-16.04',
},
- 'swarming_task_attrs': {
- 'expiration': 14400,
- 'hard_timeout': 3600,
- 'priority': 35,
- },
'tests': [
- {'name': 'v8testing', 'shards': 7},
+ {'name': 'v8testing', 'shards': 12},
],
},
##############################################################################
@@ -546,7 +541,7 @@
# Win64
'v8_win64_asan_rel_ng_triggered': {
'swarming_dimensions' : {
- 'os': 'Windows-10',
+ 'os': 'Windows-10-15063',
},
'tests': [
{'name': 'v8testing', 'shards': 5},
@@ -830,7 +825,7 @@
},
'tests': [
{'name': 'mozilla', 'variant': 'default'},
- {'name': 'test262', 'variant': 'default', 'shards': 4},
+ {'name': 'test262', 'variant': 'default', 'shards': 6},
{'name': 'v8testing', 'variant': 'default', 'shards': 3},
],
},
@@ -1253,7 +1248,7 @@
},
'V8 Win64 ASAN': {
'swarming_dimensions': {
- 'os': 'Windows-10',
+ 'os': 'Windows-10-15063',
},
'tests': [
{'name': 'v8testing', 'shards': 5},
@@ -1395,8 +1390,8 @@
'os': 'Ubuntu-16.04',
},
'tests': [
- {'name': 'mjsunit_sp_frame_access'},
- {'name': 'mozilla'},
+ {'name': 'mjsunit_sp_frame_access', 'shards': 4},
+ {'name': 'mozilla', 'shards': 4},
{'name': 'test262'},
{'name': 'v8testing', 'shards': 8},
{'name': 'v8testing', 'variant': 'extra', 'shards': 4},
@@ -1406,13 +1401,13 @@
'name': 'mozilla',
'suffix': 'armv8-a',
'test_args': ['--extra-flags', '--enable-armv8'],
- 'shards': 2,
+ 'shards': 3,
},
{
'name': 'test262',
'suffix': 'armv8-a',
'test_args': ['--extra-flags', '--enable-armv8'],
- 'shards': 2,
+ 'shards': 3,
},
{
'name': 'v8testing',
diff --git a/deps/v8/src/OWNERS b/deps/v8/src/OWNERS
index c6881f2321..3e21b6ea36 100644
--- a/deps/v8/src/OWNERS
+++ b/deps/v8/src/OWNERS
@@ -1,5 +1,5 @@
-per-file *DEPS=file://COMMON_OWNERS
-per-file intl-*=file://INTL_OWNERS
-per-file *-intl*=file://INTL_OWNERS
+per-file *DEPS=file:../COMMON_OWNERS
+per-file intl-*=file:../INTL_OWNERS
+per-file *-intl*=file:../INTL_OWNERS
# COMPONENT: Blink>JavaScript
diff --git a/deps/v8/src/api/OWNERS b/deps/v8/src/api/OWNERS
index ce6fb20af8..ef5a56dbfc 100644
--- a/deps/v8/src/api/OWNERS
+++ b/deps/v8/src/api/OWNERS
@@ -1,4 +1,4 @@
-file://include/OWNERS
+file:../../include/OWNERS
clemensh@chromium.org
ishell@chromium.org
jkummerow@chromium.org
diff --git a/deps/v8/src/api/api-inl.h b/deps/v8/src/api/api-inl.h
index d152412b47..1a6b512e83 100644
--- a/deps/v8/src/api/api-inl.h
+++ b/deps/v8/src/api/api-inl.h
@@ -8,6 +8,7 @@
#include "src/api/api.h"
#include "src/handles/handles-inl.h"
#include "src/objects/foreign-inl.h"
+#include "src/objects/js-weak-refs.h"
#include "src/objects/objects-inl.h"
#include "src/objects/stack-frame-info.h"
@@ -84,6 +85,7 @@ MAKE_TO_LOCAL(ToLocal, JSArrayBufferView, ArrayBufferView)
MAKE_TO_LOCAL(ToLocal, JSDataView, DataView)
MAKE_TO_LOCAL(ToLocal, JSTypedArray, TypedArray)
MAKE_TO_LOCAL(ToLocalShared, JSArrayBuffer, SharedArrayBuffer)
+MAKE_TO_LOCAL(ToLocal, JSFinalizationGroup, FinalizationGroup)
TYPED_ARRAYS(MAKE_TO_LOCAL_TYPED_ARRAY)
diff --git a/deps/v8/src/api/api-natives.cc b/deps/v8/src/api/api-natives.cc
index cd380d3cda..b96b6fc4f6 100644
--- a/deps/v8/src/api/api-natives.cc
+++ b/deps/v8/src/api/api-natives.cc
@@ -42,9 +42,17 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
bool is_prototype);
MaybeHandle<JSFunction> InstantiateFunction(
- Isolate* isolate, Handle<FunctionTemplateInfo> data,
+ Isolate* isolate, Handle<NativeContext> native_context,
+ Handle<FunctionTemplateInfo> data,
MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
+MaybeHandle<JSFunction> InstantiateFunction(
+ Isolate* isolate, Handle<FunctionTemplateInfo> data,
+ MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
+ return InstantiateFunction(isolate, isolate->native_context(), data,
+ maybe_name);
+}
+
MaybeHandle<Object> Instantiate(
Isolate* isolate, Handle<Object> data,
MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
@@ -277,73 +285,73 @@ MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
// the cache for those cases.
enum class CachingMode { kLimited, kUnlimited };
-MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
- int serial_number,
- CachingMode caching_mode) {
+MaybeHandle<JSObject> ProbeInstantiationsCache(
+ Isolate* isolate, Handle<NativeContext> native_context, int serial_number,
+ CachingMode caching_mode) {
DCHECK_LE(1, serial_number);
if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
- Handle<FixedArray> fast_cache =
- isolate->fast_template_instantiations_cache();
- Handle<Object> object{fast_cache->get(serial_number - 1), isolate};
+ FixedArray fast_cache =
+ native_context->fast_template_instantiations_cache();
+ Handle<Object> object{fast_cache.get(serial_number - 1), isolate};
if (object->IsUndefined(isolate)) return {};
return Handle<JSObject>::cast(object);
}
if (caching_mode == CachingMode::kUnlimited ||
(serial_number <= TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
- Handle<SimpleNumberDictionary> slow_cache =
- isolate->slow_template_instantiations_cache();
- int entry = slow_cache->FindEntry(isolate, serial_number);
+ SimpleNumberDictionary slow_cache =
+ native_context->slow_template_instantiations_cache();
+ int entry = slow_cache.FindEntry(isolate, serial_number);
if (entry != SimpleNumberDictionary::kNotFound) {
- return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
+ return handle(JSObject::cast(slow_cache.ValueAt(entry)), isolate);
}
}
return {};
}
-void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
- CachingMode caching_mode,
+void CacheTemplateInstantiation(Isolate* isolate,
+ Handle<NativeContext> native_context,
+ int serial_number, CachingMode caching_mode,
Handle<JSObject> object) {
DCHECK_LE(1, serial_number);
if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
Handle<FixedArray> fast_cache =
- isolate->fast_template_instantiations_cache();
+ handle(native_context->fast_template_instantiations_cache(), isolate);
Handle<FixedArray> new_cache =
FixedArray::SetAndGrow(isolate, fast_cache, serial_number - 1, object);
if (*new_cache != *fast_cache) {
- isolate->native_context()->set_fast_template_instantiations_cache(
- *new_cache);
+ native_context->set_fast_template_instantiations_cache(*new_cache);
}
} else if (caching_mode == CachingMode::kUnlimited ||
(serial_number <=
TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
Handle<SimpleNumberDictionary> cache =
- isolate->slow_template_instantiations_cache();
+ handle(native_context->slow_template_instantiations_cache(), isolate);
auto new_cache =
SimpleNumberDictionary::Set(isolate, cache, serial_number, object);
if (*new_cache != *cache) {
- isolate->native_context()->set_slow_template_instantiations_cache(
- *new_cache);
+ native_context->set_slow_template_instantiations_cache(*new_cache);
}
}
}
-void UncacheTemplateInstantiation(Isolate* isolate, int serial_number,
- CachingMode caching_mode) {
+void UncacheTemplateInstantiation(Isolate* isolate,
+ Handle<NativeContext> native_context,
+ int serial_number, CachingMode caching_mode) {
DCHECK_LE(1, serial_number);
if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
- Handle<FixedArray> fast_cache =
- isolate->fast_template_instantiations_cache();
- DCHECK(!fast_cache->get(serial_number - 1).IsUndefined(isolate));
- fast_cache->set_undefined(serial_number - 1);
+ FixedArray fast_cache =
+ native_context->fast_template_instantiations_cache();
+ DCHECK(!fast_cache.get(serial_number - 1).IsUndefined(isolate));
+ fast_cache.set_undefined(serial_number - 1);
} else if (caching_mode == CachingMode::kUnlimited ||
(serial_number <=
TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
Handle<SimpleNumberDictionary> cache =
- isolate->slow_template_instantiations_cache();
+ handle(native_context->slow_template_instantiations_cache(), isolate);
int entry = cache->FindEntry(isolate, serial_number);
DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry);
- isolate->native_context()->set_slow_template_instantiations_cache(*cache);
+ native_context->set_slow_template_instantiations_cache(*cache);
}
}
@@ -375,7 +383,8 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
// Fast path.
Handle<JSObject> result;
if (serial_number) {
- if (ProbeInstantiationsCache(isolate, serial_number, CachingMode::kLimited)
+ if (ProbeInstantiationsCache(isolate, isolate->native_context(),
+ serial_number, CachingMode::kLimited)
.ToHandle(&result)) {
return isolate->factory()->CopyJSObject(result);
}
@@ -419,8 +428,8 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
// Don't cache prototypes.
if (serial_number) {
- CacheTemplateInstantiation(isolate, serial_number, CachingMode::kLimited,
- result);
+ CacheTemplateInstantiation(isolate, isolate->native_context(),
+ serial_number, CachingMode::kLimited, result);
result = isolate->factory()->CopyJSObject(result);
}
}
@@ -451,13 +460,13 @@ MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
}
} // namespace
-MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
- Handle<FunctionTemplateInfo> data,
- MaybeHandle<Name> maybe_name) {
+MaybeHandle<JSFunction> InstantiateFunction(
+ Isolate* isolate, Handle<NativeContext> native_context,
+ Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
int serial_number = Smi::ToInt(data->serial_number());
if (serial_number) {
Handle<JSObject> result;
- if (ProbeInstantiationsCache(isolate, serial_number,
+ if (ProbeInstantiationsCache(isolate, native_context, serial_number,
CachingMode::kUnlimited)
.ToHandle(&result)) {
return Handle<JSFunction>::cast(result);
@@ -503,17 +512,17 @@ MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
: JS_SPECIAL_API_OBJECT_TYPE;
Handle<JSFunction> function = ApiNatives::CreateApiFunction(
- isolate, data, prototype, function_type, maybe_name);
+ isolate, native_context, data, prototype, function_type, maybe_name);
if (serial_number) {
// Cache the function.
- CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
- function);
+ CacheTemplateInstantiation(isolate, native_context, serial_number,
+ CachingMode::kUnlimited, function);
}
MaybeHandle<JSObject> result = ConfigureInstance(isolate, function, data);
if (result.is_null()) {
// Uncache on error.
if (serial_number) {
- UncacheTemplateInstantiation(isolate, serial_number,
+ UncacheTemplateInstantiation(isolate, native_context, serial_number,
CachingMode::kUnlimited);
}
return MaybeHandle<JSFunction>();
@@ -544,6 +553,14 @@ void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
} // namespace
MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
+ Isolate* isolate, Handle<NativeContext> native_context,
+ Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
+ InvokeScope invoke_scope(isolate);
+ return ::v8::internal::InstantiateFunction(isolate, native_context, data,
+ maybe_name);
+}
+
+MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
Isolate* isolate = data->GetIsolate();
InvokeScope invoke_scope(isolate);
@@ -626,8 +643,9 @@ void ApiNatives::AddNativeDataProperty(Isolate* isolate,
}
Handle<JSFunction> ApiNatives::CreateApiFunction(
- Isolate* isolate, Handle<FunctionTemplateInfo> obj,
- Handle<Object> prototype, InstanceType type, MaybeHandle<Name> maybe_name) {
+ Isolate* isolate, Handle<NativeContext> native_context,
+ Handle<FunctionTemplateInfo> obj, Handle<Object> prototype,
+ InstanceType type, MaybeHandle<Name> maybe_name) {
Handle<SharedFunctionInfo> shared =
FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
maybe_name);
@@ -635,8 +653,8 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
DCHECK(shared->HasSharedName());
Handle<JSFunction> result =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(
- shared, isolate->native_context());
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
+ native_context);
if (obj->remove_prototype()) {
DCHECK(prototype.is_null());
diff --git a/deps/v8/src/api/api-natives.h b/deps/v8/src/api/api-natives.h
index 153212cc6c..fb59eb6cfc 100644
--- a/deps/v8/src/api/api-natives.h
+++ b/deps/v8/src/api/api-natives.h
@@ -25,6 +25,11 @@ class ApiNatives {
static const int kInitialFunctionCacheSize = 256;
V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> InstantiateFunction(
+ Isolate* isolate, Handle<NativeContext> native_context,
+ Handle<FunctionTemplateInfo> data,
+ MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
+
+ V8_WARN_UNUSED_RESULT static MaybeHandle<JSFunction> InstantiateFunction(
Handle<FunctionTemplateInfo> data,
MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
@@ -36,9 +41,9 @@ class ApiNatives {
Handle<ObjectTemplateInfo> data);
static Handle<JSFunction> CreateApiFunction(
- Isolate* isolate, Handle<FunctionTemplateInfo> obj,
- Handle<Object> prototype, InstanceType type,
- MaybeHandle<Name> name = MaybeHandle<Name>());
+ Isolate* isolate, Handle<NativeContext> native_context,
+ Handle<FunctionTemplateInfo> obj, Handle<Object> prototype,
+ InstanceType type, MaybeHandle<Name> name = MaybeHandle<Name>());
static void AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
Handle<Name> name, Handle<Object> value,
diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc
index e02c74416b..30eceb6223 100644
--- a/deps/v8/src/api/api.cc
+++ b/deps/v8/src/api/api.cc
@@ -68,6 +68,7 @@
#include "src/objects/js-generator-inl.h"
#include "src/objects/js-promise-inl.h"
#include "src/objects/js-regexp-inl.h"
+#include "src/objects/js-weak-refs-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/oddball.h"
@@ -121,9 +122,9 @@
#include <windows.h>
#include "include/v8-wasm-trap-handler-win.h"
#include "src/trap-handler/handler-inside-win.h"
-#if V8_TARGET_ARCH_X64
+#if defined(V8_OS_WIN64)
#include "src/diagnostics/unwinding-info-win64.h"
-#endif // V8_TARGET_ARCH_X64
+#endif // V8_OS_WIN64
#endif // V8_OS_WIN
namespace v8 {
@@ -261,7 +262,7 @@ void CheckMicrotasksScopesConsistency(i::MicrotaskQueue* microtask_queue) {
template <bool do_callback>
class CallDepthScope {
public:
- explicit CallDepthScope(i::Isolate* isolate, Local<Context> context)
+ CallDepthScope(i::Isolate* isolate, Local<Context> context)
: isolate_(isolate),
context_(context),
escaped_(false),
@@ -272,7 +273,7 @@ class CallDepthScope {
? i::InterruptsScope::kRunInterrupts
: i::InterruptsScope::kPostponeInterrupts)
: i::InterruptsScope::kNoop) {
- isolate_->handle_scope_implementer()->IncrementCallDepth();
+ isolate_->thread_local_top()->IncrementCallDepth(this);
isolate_->set_next_v8_call_is_safe_for_termination(false);
if (!context.IsEmpty()) {
i::Handle<i::Context> env = Utils::OpenHandle(*context);
@@ -296,7 +297,7 @@ class CallDepthScope {
i::Handle<i::Context> env = Utils::OpenHandle(*context_);
microtask_queue = env->native_context().microtask_queue();
}
- if (!escaped_) isolate_->handle_scope_implementer()->DecrementCallDepth();
+ if (!escaped_) isolate_->thread_local_top()->DecrementCallDepth(this);
if (do_callback) isolate_->FireCallCompletedCallback(microtask_queue);
// TODO(jochen): This should be #ifdef DEBUG
#ifdef V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY
@@ -308,11 +309,10 @@ class CallDepthScope {
void Escape() {
DCHECK(!escaped_);
escaped_ = true;
- auto handle_scope_implementer = isolate_->handle_scope_implementer();
- handle_scope_implementer->DecrementCallDepth();
- bool clear_exception =
- handle_scope_implementer->CallDepthIsZero() &&
- isolate_->thread_local_top()->try_catch_handler_ == nullptr;
+ auto thread_local_top = isolate_->thread_local_top();
+ thread_local_top->DecrementCallDepth(this);
+ bool clear_exception = thread_local_top->CallDepthIsZero() &&
+ thread_local_top->try_catch_handler_ == nullptr;
isolate_->OptionalRescheduleException(clear_exception);
}
@@ -323,6 +323,12 @@ class CallDepthScope {
bool do_callback_;
bool safe_for_termination_;
i::InterruptsScope interrupts_scope_;
+ i::Address previous_stack_height_;
+
+ friend class i::ThreadLocalTop;
+
+ DISALLOW_NEW_AND_DELETE()
+ DISALLOW_COPY_AND_ASSIGN(CallDepthScope);
};
} // namespace
@@ -811,10 +817,15 @@ StartupData SnapshotCreator::CreateBlob(
// Complete in-object slack tracking for all functions.
fun.CompleteInobjectSlackTrackingIfActive();
- fun.ResetIfBytecodeFlushed();
-
// Also, clear out feedback vectors, or any optimized code.
- if (fun.IsOptimized() || fun.IsInterpreted()) {
+ // Note that checking for fun.IsOptimized() || fun.IsInterpreted() is not
+ // sufficient because the function can have a feedback vector even if it
+ // is not compiled (e.g. when the bytecode was flushed). On the other
+ // hand, only checking for the feedback vector is not sufficient because
+ // there can be multiple functions sharing the same feedback vector. So we
+ // need all these checks.
+ if (fun.IsOptimized() || fun.IsInterpreted() ||
+ !fun.raw_feedback_cell().value().IsUndefined()) {
fun.raw_feedback_cell().set_value(
i::ReadOnlyRoots(isolate).undefined_value());
fun.set_code(isolate->builtins()->builtin(i::Builtins::kCompileLazy));
@@ -1022,10 +1033,11 @@ i::Address* V8::GlobalizeReference(i::Isolate* isolate, i::Address* obj) {
}
i::Address* V8::GlobalizeTracedReference(i::Isolate* isolate, i::Address* obj,
- internal::Address* slot) {
+ internal::Address* slot,
+ bool has_destructor) {
LOG_API(isolate, TracedGlobal, New);
i::Handle<i::Object> result =
- isolate->global_handles()->CreateTraced(*obj, slot);
+ isolate->global_handles()->CreateTraced(*obj, slot, has_destructor);
#ifdef VERIFY_HEAP
if (i::FLAG_verify_heap) {
i::Object(*obj).ObjectVerify(isolate);
@@ -1048,6 +1060,11 @@ void V8::MoveTracedGlobalReference(internal::Address** from,
i::GlobalHandles::MoveTracedGlobal(from, to);
}
+void V8::CopyTracedGlobalReference(const internal::Address* const* from,
+ internal::Address** to) {
+ i::GlobalHandles::CopyTracedGlobal(from, to);
+}
+
void V8::MakeWeak(i::Address* location, void* parameter,
WeakCallbackInfo<void>::Callback weak_callback,
WeakCallbackType type) {
@@ -2336,7 +2353,8 @@ Local<Module> Module::CreateSyntheticModule(
i::Handle<i::FixedArray> i_export_names = i_isolate->factory()->NewFixedArray(
static_cast<int>(export_names.size()));
for (int i = 0; i < i_export_names->length(); ++i) {
- i::Handle<i::String> str = Utils::OpenHandle(*export_names[i]);
+ i::Handle<i::String> str = i_isolate->factory()->InternalizeString(
+ Utils::OpenHandle(*export_names[i]));
i_export_names->set(i, *str);
}
return v8::Utils::ToLocal(
@@ -4690,6 +4708,11 @@ bool v8::Object::IsConstructor() {
return self->IsConstructor();
}
+bool v8::Object::IsApiWrapper() {
+ auto self = i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
+ return self->IsApiWrapper();
+}
+
MaybeLocal<Value> Object::CallAsFunction(Local<Context> context,
Local<Value> recv, int argc,
Local<Value> argv[]) {
@@ -4870,7 +4893,7 @@ Local<Value> Function::GetDisplayName() const {
}
auto func = i::Handle<i::JSFunction>::cast(self);
i::Handle<i::String> property_name =
- isolate->factory()->NewStringFromStaticChars("displayName");
+ isolate->factory()->display_name_string();
i::Handle<i::Object> value =
i::JSReceiver::GetDataProperty(func, property_name);
if (value->IsString()) {
@@ -5582,14 +5605,14 @@ bool V8::EnableWebAssemblyTrapHandler(bool use_v8_signal_handler) {
#if defined(V8_OS_WIN)
void V8::SetUnhandledExceptionCallback(
UnhandledExceptionCallback unhandled_exception_callback) {
-#if defined(V8_TARGET_ARCH_X64)
+#if defined(V8_OS_WIN64)
v8::internal::win64_unwindinfo::SetUnhandledExceptionCallback(
unhandled_exception_callback);
#else
- // Not implemented on ARM64.
-#endif
+ // Not implemented, port needed.
+#endif // V8_OS_WIN64
}
-#endif
+#endif // V8_OS_WIN
void v8::V8::SetEntropySource(EntropySource entropy_source) {
base::RandomNumberGenerator::SetEntropySource(entropy_source);
@@ -6228,7 +6251,7 @@ MaybeLocal<String> v8::String::NewExternalTwoByte(
MaybeLocal<String> v8::String::NewExternalOneByte(
Isolate* isolate, v8::String::ExternalOneByteStringResource* resource) {
- CHECK(resource && resource->data());
+ CHECK_NOT_NULL(resource);
// TODO(dcarney): throw a context free exception.
if (resource->length() > static_cast<size_t>(i::String::kMaxLength)) {
return MaybeLocal<String>();
@@ -6236,16 +6259,16 @@ MaybeLocal<String> v8::String::NewExternalOneByte(
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
LOG_API(i_isolate, String, NewExternalOneByte);
- if (resource->length() > 0) {
- i::Handle<i::String> string = i_isolate->factory()
- ->NewExternalStringFromOneByte(resource)
- .ToHandleChecked();
- return Utils::ToLocal(string);
- } else {
+ if (resource->length() == 0) {
// The resource isn't going to be used, free it immediately.
resource->Dispose();
return Utils::ToLocal(i_isolate->factory()->empty_string());
}
+ CHECK_NOT_NULL(resource->data());
+ i::Handle<i::String> string = i_isolate->factory()
+ ->NewExternalStringFromOneByte(resource)
+ .ToHandleChecked();
+ return Utils::ToLocal(string);
}
bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) {
@@ -7693,6 +7716,11 @@ bool Isolate::InContext() {
return !isolate->context().is_null();
}
+void Isolate::ClearKeptObjects() {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ isolate->ClearKeptObjects();
+}
+
v8::Local<v8::Context> Isolate::GetCurrentContext() {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
i::Context context = isolate->context();
@@ -7956,6 +7984,28 @@ void Isolate::SetAbortOnUncaughtExceptionCallback(
isolate->SetAbortOnUncaughtExceptionCallback(callback);
}
+void Isolate::SetHostCleanupFinalizationGroupCallback(
+ HostCleanupFinalizationGroupCallback callback) {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ isolate->SetHostCleanupFinalizationGroupCallback(callback);
+}
+
+Maybe<bool> FinalizationGroup::Cleanup(
+ Local<FinalizationGroup> finalization_group) {
+ i::Handle<i::JSFinalizationGroup> fg = Utils::OpenHandle(*finalization_group);
+ i::Isolate* isolate = fg->native_context().GetIsolate();
+ i::Handle<i::Context> i_context(fg->native_context(), isolate);
+ Local<Context> context = Utils::ToLocal(i_context);
+ ENTER_V8(isolate, context, FinalizationGroup, Cleanup, Nothing<bool>(),
+ i::HandleScope);
+ i::Handle<i::Object> callback(fg->cleanup(), isolate);
+ fg->set_scheduled_for_cleanup(false);
+ has_pending_exception =
+ i::JSFinalizationGroup::Cleanup(isolate, fg, callback).IsNothing();
+ RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
+ return Just(true);
+}
+
void Isolate::SetHostImportModuleDynamicallyCallback(
HostImportModuleDynamicallyCallback callback) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
@@ -8034,13 +8084,13 @@ Isolate::SuppressMicrotaskExecutionScope::SuppressMicrotaskExecutionScope(
Isolate* isolate)
: isolate_(reinterpret_cast<i::Isolate*>(isolate)),
microtask_queue_(isolate_->default_microtask_queue()) {
- isolate_->handle_scope_implementer()->IncrementCallDepth();
+ isolate_->thread_local_top()->IncrementCallDepth(this);
microtask_queue_->IncrementMicrotasksSuppressions();
}
Isolate::SuppressMicrotaskExecutionScope::~SuppressMicrotaskExecutionScope() {
microtask_queue_->DecrementMicrotasksSuppressions();
- isolate_->handle_scope_implementer()->DecrementCallDepth();
+ isolate_->thread_local_top()->DecrementCallDepth(this);
}
Isolate::SafeForTerminationScope::SafeForTerminationScope(v8::Isolate* isolate)
@@ -8165,8 +8215,10 @@ bool Isolate::GetHeapCodeAndMetadataStatistics(
void Isolate::GetStackSample(const RegisterState& state, void** frames,
size_t frames_limit, SampleInfo* sample_info) {
RegisterState regs = state;
- if (TickSample::GetStackSample(this, &regs, TickSample::kSkipCEntryFrame,
- frames, frames_limit, sample_info)) {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ if (i::TickSample::GetStackSample(isolate, &regs,
+ i::TickSample::kSkipCEntryFrame, frames,
+ frames_limit, sample_info)) {
return;
}
sample_info->frames_count = 0;
@@ -8326,6 +8378,11 @@ void Isolate::SetAddHistogramSampleFunction(
->SetAddHistogramSampleFunction(callback);
}
+void Isolate::SetAddCrashKeyCallback(AddCrashKeyCallback callback) {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ isolate->SetAddCrashKeyCallback(callback);
+}
+
bool Isolate::IdleNotificationDeadline(double deadline_in_seconds) {
// Returning true tells the caller that it need not
// continue to call IdleNotification.
@@ -8481,6 +8538,9 @@ CALLBACK_SETTER(WasmStreamingCallback, WasmStreamingCallback,
CALLBACK_SETTER(WasmThreadsEnabledCallback, WasmThreadsEnabledCallback,
wasm_threads_enabled_callback)
+CALLBACK_SETTER(WasmLoadSourceMapCallback, WasmLoadSourceMapCallback,
+ wasm_load_source_map_callback)
+
void Isolate::AddNearHeapLimitCallback(v8::NearHeapLimitCallback callback,
void* data) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
@@ -8641,7 +8701,11 @@ MicrotasksScope::MicrotasksScope(Isolate* isolate,
MicrotasksScope::~MicrotasksScope() {
if (run_) {
microtask_queue_->DecrementMicrotasksScopeDepth();
- if (MicrotasksPolicy::kScoped == microtask_queue_->microtasks_policy()) {
+ if (MicrotasksPolicy::kScoped == microtask_queue_->microtasks_policy() &&
+ !isolate_->has_scheduled_exception()) {
+ DCHECK_IMPLIES(isolate_->has_scheduled_exception(),
+ isolate_->scheduled_exception() ==
+ i::ReadOnlyRoots(isolate_).termination_exception());
microtask_queue_->PerformCheckpoint(reinterpret_cast<Isolate*>(isolate_));
}
}
@@ -9800,9 +9864,32 @@ int CpuProfile::GetSamplesCount() const {
return reinterpret_cast<const i::CpuProfile*>(this)->samples_count();
}
-CpuProfiler* CpuProfiler::New(Isolate* isolate, CpuProfilingNamingMode mode) {
- return reinterpret_cast<CpuProfiler*>(
- new i::CpuProfiler(reinterpret_cast<i::Isolate*>(isolate), mode));
+CpuProfiler* CpuProfiler::New(Isolate* isolate,
+ CpuProfilingNamingMode naming_mode,
+ CpuProfilingLoggingMode logging_mode) {
+ return reinterpret_cast<CpuProfiler*>(new i::CpuProfiler(
+ reinterpret_cast<i::Isolate*>(isolate), naming_mode, logging_mode));
+}
+
+CpuProfilingOptions::CpuProfilingOptions(CpuProfilingMode mode,
+ unsigned max_samples,
+ int sampling_interval_us,
+ MaybeLocal<Context> filter_context)
+ : mode_(mode),
+ max_samples_(max_samples),
+ sampling_interval_us_(sampling_interval_us) {
+ if (!filter_context.IsEmpty()) {
+ Local<Context> local_filter_context = filter_context.ToLocalChecked();
+ filter_context_.Reset(local_filter_context->GetIsolate(),
+ local_filter_context);
+ }
+}
+
+void* CpuProfilingOptions::raw_filter_context() const {
+ return reinterpret_cast<void*>(
+ i::Context::cast(*Utils::OpenPersistent(filter_context_))
+ .native_context()
+ .address());
}
void CpuProfiler::Dispose() { delete reinterpret_cast<i::CpuProfiler*>(this); }
@@ -10068,6 +10155,10 @@ SnapshotObjectId HeapProfiler::GetObjectId(Local<Value> value) {
return reinterpret_cast<i::HeapProfiler*>(this)->GetSnapshotObjectId(obj);
}
+SnapshotObjectId HeapProfiler::GetObjectId(NativeObject value) {
+ return reinterpret_cast<i::HeapProfiler*>(this)->GetSnapshotObjectId(value);
+}
+
Local<Value> HeapProfiler::FindObjectById(SnapshotObjectId id) {
i::Handle<i::Object> obj =
reinterpret_cast<i::HeapProfiler*>(this)->FindHeapObjectById(id);
@@ -10200,6 +10291,17 @@ void EmbedderHeapTracer::TracePrologue(TraceFlags flags) {
#endif
}
+void EmbedderHeapTracer::TraceEpilogue(TraceSummary* trace_summary) {
+#if __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
+#endif
+ TraceEpilogue();
+#if __clang__
+#pragma clang diagnostic pop
+#endif
+}
+
void EmbedderHeapTracer::FinalizeTracing() {
if (isolate_) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(isolate_);
@@ -10248,8 +10350,7 @@ void EmbedderHeapTracer::RegisterEmbedderReference(
if (ref.IsEmpty()) return;
i::Heap* const heap = reinterpret_cast<i::Isolate*>(isolate_)->heap();
- heap->RegisterExternallyReferencedObject(
- reinterpret_cast<i::Address*>(ref.val_));
+ heap->RegisterExternallyReferencedObject(reinterpret_cast<i::Address*>(*ref));
}
void EmbedderHeapTracer::IterateTracedGlobalHandles(
diff --git a/deps/v8/src/api/api.h b/deps/v8/src/api/api.h
index 6135a7dfc6..21bbb3a101 100644
--- a/deps/v8/src/api/api.h
+++ b/deps/v8/src/api/api.h
@@ -90,6 +90,7 @@ class RegisteredExtension {
V(Data, Object) \
V(RegExp, JSRegExp) \
V(Object, JSReceiver) \
+ V(FinalizationGroup, JSFinalizationGroup) \
V(Array, JSArray) \
V(Map, JSMap) \
V(Set, JSSet) \
@@ -198,6 +199,8 @@ class Utils {
v8::internal::Handle<v8::internal::JSTypedArray> obj);
static inline Local<BigUint64Array> ToLocalBigUint64Array(
v8::internal::Handle<v8::internal::JSTypedArray> obj);
+ static inline Local<FinalizationGroup> ToLocal(
+ v8::internal::Handle<v8::internal::JSFinalizationGroup> obj);
static inline Local<SharedArrayBuffer> ToLocalShared(
v8::internal::Handle<v8::internal::JSArrayBuffer> obj);
@@ -248,9 +251,9 @@ class Utils {
template <class From, class To>
static inline Local<To> Convert(v8::internal::Handle<From> obj);
- template <class T>
+ template <class T, class M>
static inline v8::internal::Handle<v8::internal::Object> OpenPersistent(
- const v8::Persistent<T>& persistent) {
+ const v8::Persistent<T, M>& persistent) {
return v8::internal::Handle<v8::internal::Object>(
reinterpret_cast<v8::internal::Address*>(persistent.val_));
}
@@ -354,7 +357,6 @@ class HandleScopeImplementer {
explicit HandleScopeImplementer(Isolate* isolate)
: isolate_(isolate),
spare_(nullptr),
- call_depth_(0),
last_handle_before_deferred_block_(nullptr) {}
~HandleScopeImplementer() { DeleteArray(spare_); }
@@ -373,11 +375,6 @@ class HandleScopeImplementer {
inline internal::Address* GetSpareOrNewBlock();
inline void DeleteExtensions(internal::Address* prev_limit);
- // Call depth represents nested v8 api calls.
- inline void IncrementCallDepth() { call_depth_++; }
- inline void DecrementCallDepth() { call_depth_--; }
- inline bool CallDepthIsZero() { return call_depth_ == 0; }
-
inline void EnterContext(Context context);
inline void LeaveContext();
inline bool LastEnteredContextWas(Context context);
@@ -414,7 +411,6 @@ class HandleScopeImplementer {
saved_contexts_.detach();
spare_ = nullptr;
last_handle_before_deferred_block_ = nullptr;
- call_depth_ = 0;
}
void Free() {
@@ -431,7 +427,7 @@ class HandleScopeImplementer {
DeleteArray(spare_);
spare_ = nullptr;
}
- DCHECK_EQ(call_depth_, 0);
+ DCHECK(isolate_->thread_local_top()->CallDepthIsZero());
}
void BeginDeferredScope();
@@ -451,8 +447,6 @@ class HandleScopeImplementer {
// Used as a stack to keep track of saved contexts.
DetachableVector<Context> saved_contexts_;
Address* spare_;
- int call_depth_;
-
Address* last_handle_before_deferred_block_;
// This is only used for threading support.
HandleScopeData handle_scope_data_;
diff --git a/deps/v8/src/ast/ast-traversal-visitor.h b/deps/v8/src/ast/ast-traversal-visitor.h
index b4836ff784..2796e59a8d 100644
--- a/deps/v8/src/ast/ast-traversal-visitor.h
+++ b/deps/v8/src/ast/ast-traversal-visitor.h
@@ -383,6 +383,12 @@ void AstTraversalVisitor<Subclass>::VisitThrow(Throw* expr) {
}
template <class Subclass>
+void AstTraversalVisitor<Subclass>::VisitOptionalChain(OptionalChain* expr) {
+ PROCESS_EXPRESSION(expr);
+ RECURSE_EXPRESSION(Visit(expr->expression()));
+}
+
+template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitProperty(Property* expr) {
PROCESS_EXPRESSION(expr);
RECURSE_EXPRESSION(Visit(expr->obj()));
diff --git a/deps/v8/src/ast/ast.cc b/deps/v8/src/ast/ast.cc
index 9987eb2844..4b6c4805de 100644
--- a/deps/v8/src/ast/ast.cc
+++ b/deps/v8/src/ast/ast.cc
@@ -122,6 +122,10 @@ bool Expression::IsUndefinedLiteral() const {
var_proxy->raw_name()->IsOneByteEqualTo("undefined");
}
+bool Expression::IsLiteralButNotNullOrUndefined() const {
+ return IsLiteral() && !IsNullOrUndefinedLiteral();
+}
+
bool Expression::ToBooleanIsTrue() const {
return IsLiteral() && AsLiteral()->ToBooleanIsTrue();
}
@@ -217,13 +221,7 @@ bool FunctionLiteral::AllowsLazyCompilation() {
}
bool FunctionLiteral::SafeToSkipArgumentsAdaptor() const {
- // TODO(bmeurer,verwaest): The --fast_calls_with_arguments_mismatches
- // is mostly here for checking the real-world impact of the calling
- // convention. There's not really a point in turning off this flag
- // otherwise, so we should remove it at some point, when we're done
- // with the experiments (https://crbug.com/v8/8895).
- return FLAG_fast_calls_with_arguments_mismatches &&
- language_mode() == LanguageMode::kStrict &&
+ return language_mode() == LanguageMode::kStrict &&
scope()->arguments() == nullptr &&
scope()->rest_parameter() == nullptr;
}
diff --git a/deps/v8/src/ast/ast.h b/deps/v8/src/ast/ast.h
index bd52d1b2c0..ced9f775dd 100644
--- a/deps/v8/src/ast/ast.h
+++ b/deps/v8/src/ast/ast.h
@@ -16,6 +16,7 @@
#include "src/common/globals.h"
#include "src/execution/isolate.h"
#include "src/heap/factory.h"
+#include "src/objects/function-syntax-kind.h"
#include "src/objects/literal-objects.h"
#include "src/objects/smi.h"
#include "src/parsing/token.h"
@@ -94,6 +95,7 @@ namespace internal {
V(ImportCallExpression) \
V(Literal) \
V(NativeFunctionLiteral) \
+ V(OptionalChain) \
V(Property) \
V(ResolvedProperty) \
V(Spread) \
@@ -168,11 +170,13 @@ class AstNode: public ZoneObject {
void* operator new(size_t size);
int position_;
- class NodeTypeField : public BitField<NodeType, 0, 6> {};
+ using NodeTypeField = BitField<NodeType, 0, 6>;
protected:
uint32_t bit_field_;
- static const uint8_t kNextBitFieldIndex = NodeTypeField::kNext;
+
+ template <class T, int size>
+ using NextBitField = NodeTypeField::Next<T, size>;
AstNode(int position, NodeType type)
: position_(position), bit_field_(NodeTypeField::encode(type)) {}
@@ -182,8 +186,6 @@ class AstNode: public ZoneObject {
class Statement : public AstNode {
protected:
Statement(int position, NodeType type) : AstNode(position, type) {}
-
- static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex;
};
@@ -245,6 +247,14 @@ class Expression : public AstNode {
// that this also checks for loads of the global "undefined" variable.
bool IsUndefinedLiteral() const;
+ // True if either null literal or undefined literal.
+ inline bool IsNullOrUndefinedLiteral() const {
+ return IsNullLiteral() || IsUndefinedLiteral();
+ }
+
+ // True if a literal and not null or undefined.
+ bool IsLiteralButNotNullOrUndefined() const;
+
bool IsCompileTimeValue();
bool IsPattern() {
@@ -265,15 +275,15 @@ class Expression : public AstNode {
}
private:
- class IsParenthesizedField
- : public BitField<bool, AstNode::kNextBitFieldIndex, 1> {};
+ using IsParenthesizedField = AstNode::NextBitField<bool, 1>;
protected:
Expression(int pos, NodeType type) : AstNode(pos, type) {
DCHECK(!is_parenthesized());
}
- static const uint8_t kNextBitFieldIndex = IsParenthesizedField::kNext;
+ template <class T, int size>
+ using NextBitField = IsParenthesizedField::Next<T, size>;
};
class FailureExpression : public Expression {
@@ -321,8 +331,7 @@ class BreakableStatement : public Statement {
}
private:
- class BreakableTypeField
- : public BitField<BreakableType, Statement::kNextBitFieldIndex, 1> {};
+ using BreakableTypeField = Statement::NextBitField<BreakableType, 1>;
protected:
BreakableStatement(BreakableType breakable_type, int position, NodeType type)
@@ -330,7 +339,8 @@ class BreakableStatement : public Statement {
bit_field_ |= BreakableTypeField::encode(breakable_type);
}
- static const uint8_t kNextBitFieldIndex = BreakableTypeField::kNext;
+ template <class T, int size>
+ using NextBitField = BreakableTypeField::Next<T, size>;
};
class Block : public BreakableStatement {
@@ -357,10 +367,8 @@ class Block : public BreakableStatement {
ZonePtrList<Statement> statements_;
Scope* scope_;
- class IgnoreCompletionField
- : public BitField<bool, BreakableStatement::kNextBitFieldIndex, 1> {};
- class IsLabeledField
- : public BitField<bool, IgnoreCompletionField::kNext, 1> {};
+ using IgnoreCompletionField = BreakableStatement::NextBitField<bool, 1>;
+ using IsLabeledField = IgnoreCompletionField::Next<bool, 1>;
protected:
Block(Zone* zone, ZonePtrList<const AstRawString>* labels, int capacity,
@@ -448,8 +456,7 @@ class VariableDeclaration : public Declaration {
private:
friend class AstNodeFactory;
- class IsNestedField
- : public BitField<bool, Declaration::kNextBitFieldIndex, 1> {};
+ using IsNestedField = Declaration::NextBitField<bool, 1>;
protected:
explicit VariableDeclaration(int pos, bool is_nested = false)
@@ -457,7 +464,8 @@ class VariableDeclaration : public Declaration {
bit_field_ = IsNestedField::update(bit_field_, is_nested);
}
- static const uint8_t kNextBitFieldIndex = IsNestedField::kNext;
+ template <class T, int size>
+ using NextBitField = IsNestedField::Next<T, size>;
};
// For var declarations that appear in a block scope.
@@ -524,9 +532,6 @@ class IterationStatement : public BreakableStatement {
body_(nullptr) {}
void Initialize(Statement* body) { body_ = body; }
- static const uint8_t kNextBitFieldIndex =
- BreakableStatement::kNextBitFieldIndex;
-
private:
ZonePtrList<const AstRawString>* labels_;
ZonePtrList<const AstRawString>* own_labels_;
@@ -740,8 +745,7 @@ class ReturnStatement final : public JumpStatement {
Expression* expression_;
int end_position_;
- class TypeField
- : public BitField<Type, JumpStatement::kNextBitFieldIndex, 1> {};
+ using TypeField = JumpStatement::NextBitField<Type, 1>;
};
@@ -977,8 +981,7 @@ class SloppyBlockFunctionStatement final : public Statement {
private:
friend class AstNodeFactory;
- class TokenField
- : public BitField<Token::Value, Statement::kNextBitFieldIndex, 8> {};
+ using TokenField = Statement::NextBitField<Token::Value, 8>;
SloppyBlockFunctionStatement(int pos, Variable* var, Token::Value init,
Statement* statement)
@@ -1079,7 +1082,7 @@ class Literal final : public Expression {
private:
friend class AstNodeFactory;
- class TypeField : public BitField<Type, Expression::kNextBitFieldIndex, 4> {};
+ using TypeField = Expression::NextBitField<Type, 4>;
Literal(int smi, int position) : Expression(position, kLiteral), smi_(smi) {
bit_field_ = TypeField::update(bit_field_, kSmi);
@@ -1210,10 +1213,9 @@ class AggregateLiteral : public MaterializedLiteral {
private:
int depth_ : 31;
- class NeedsInitialAllocationSiteField
- : public BitField<bool, MaterializedLiteral::kNextBitFieldIndex, 1> {};
- class IsSimpleField
- : public BitField<bool, NeedsInitialAllocationSiteField::kNext, 1> {};
+ using NeedsInitialAllocationSiteField =
+ MaterializedLiteral::NextBitField<bool, 1>;
+ using IsSimpleField = NeedsInitialAllocationSiteField::Next<bool, 1>;
protected:
friend class AstNodeFactory;
@@ -1236,7 +1238,8 @@ class AggregateLiteral : public MaterializedLiteral {
bit_field_ = NeedsInitialAllocationSiteField::update(bit_field_, required);
}
- static const uint8_t kNextBitFieldIndex = IsSimpleField::kNext;
+ template <class T, int size>
+ using NextBitField = IsSimpleField::Next<T, size>;
};
// Common supertype for ObjectLiteralProperty and ClassLiteralProperty
@@ -1375,12 +1378,6 @@ class ObjectLiteral final : public AggregateLiteral {
static_cast<int>(AggregateLiteral::kNeedsInitialAllocationSite) <
static_cast<int>(kFastElements));
- struct Accessors: public ZoneObject {
- Accessors() : getter(nullptr), setter(nullptr) {}
- ObjectLiteralProperty* getter;
- ObjectLiteralProperty* setter;
- };
-
private:
friend class AstNodeFactory;
@@ -1408,19 +1405,14 @@ class ObjectLiteral final : public AggregateLiteral {
void set_has_null_protoype(bool has_null_prototype) {
bit_field_ = HasNullPrototypeField::update(bit_field_, has_null_prototype);
}
-
uint32_t boilerplate_properties_;
Handle<ObjectBoilerplateDescription> boilerplate_description_;
ZoneList<Property*> properties_;
- class HasElementsField
- : public BitField<bool, AggregateLiteral::kNextBitFieldIndex, 1> {};
- class HasRestPropertyField
- : public BitField<bool, HasElementsField::kNext, 1> {};
- class FastElementsField
- : public BitField<bool, HasRestPropertyField::kNext, 1> {};
- class HasNullPrototypeField
- : public BitField<bool, FastElementsField::kNext, 1> {};
+ using HasElementsField = AggregateLiteral::NextBitField<bool, 1>;
+ using HasRestPropertyField = HasElementsField::Next<bool, 1>;
+ using FastElementsField = HasRestPropertyField::Next<bool, 1>;
+ using HasNullPrototypeField = FastElementsField::Next<bool, 1>;
};
// An array literal has a literals object that is used
@@ -1512,6 +1504,9 @@ class VariableProxy final : public Expression {
var()->SetMaybeAssigned();
}
}
+ void clear_is_assigned() {
+ bit_field_ = IsAssignedField::update(bit_field_, false);
+ }
bool is_resolved() const { return IsResolvedField::decode(bit_field_); }
void set_is_resolved() {
@@ -1586,15 +1581,11 @@ class VariableProxy final : public Expression {
explicit VariableProxy(const VariableProxy* copy_from);
- class IsAssignedField
- : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
- class IsResolvedField : public BitField<bool, IsAssignedField::kNext, 1> {};
- class IsRemovedFromUnresolvedField
- : public BitField<bool, IsResolvedField::kNext, 1> {};
- class IsNewTargetField
- : public BitField<bool, IsRemovedFromUnresolvedField::kNext, 1> {};
- class HoleCheckModeField
- : public BitField<HoleCheckMode, IsNewTargetField::kNext, 1> {};
+ using IsAssignedField = Expression::NextBitField<bool, 1>;
+ using IsResolvedField = IsAssignedField::Next<bool, 1>;
+ using IsRemovedFromUnresolvedField = IsResolvedField::Next<bool, 1>;
+ using IsNewTargetField = IsRemovedFromUnresolvedField::Next<bool, 1>;
+ using HoleCheckModeField = IsNewTargetField::Next<HoleCheckMode, 1>;
union {
const AstRawString* raw_name_; // if !is_resolved_
@@ -1607,20 +1598,41 @@ class VariableProxy final : public Expression {
friend base::ThreadedListTraits<VariableProxy>;
};
+// Wraps an optional chain to provide a wrapper for jump labels.
+class OptionalChain final : public Expression {
+ public:
+ Expression* expression() const { return expression_; }
+
+ private:
+ friend class AstNodeFactory;
+
+ explicit OptionalChain(Expression* expression)
+ : Expression(0, kOptionalChain), expression_(expression) {}
+
+ Expression* expression_;
+};
+
// Assignments to a property will use one of several types of property access.
// Otherwise, the assignment is to a non-property (a global, a local slot, a
// parameter slot, or a destructuring pattern).
enum AssignType {
- NON_PROPERTY, // destructuring
- NAMED_PROPERTY, // obj.key
- KEYED_PROPERTY, // obj[key]
- NAMED_SUPER_PROPERTY, // super.key
- KEYED_SUPER_PROPERTY, // super[key]
- PRIVATE_METHOD // obj.#key: #key is a private method
+ NON_PROPERTY, // destructuring
+ NAMED_PROPERTY, // obj.key
+ KEYED_PROPERTY, // obj[key]
+ NAMED_SUPER_PROPERTY, // super.key
+ KEYED_SUPER_PROPERTY, // super[key]
+ PRIVATE_METHOD, // obj.#key: #key is a private method
+ PRIVATE_GETTER_ONLY, // obj.#key: #key only has a getter defined
+ PRIVATE_SETTER_ONLY, // obj.#key: #key only has a setter defined
+ PRIVATE_GETTER_AND_SETTER // obj.#key: #key has both accessors defined
};
class Property final : public Expression {
public:
+ bool is_optional_chain_link() const {
+ return IsOptionalChainLinkField::decode(bit_field_);
+ }
+
bool IsValidReferenceExpression() const { return true; }
Expression* obj() const { return obj_; }
@@ -1637,8 +1649,21 @@ class Property final : public Expression {
VariableProxy* proxy = property->key()->AsVariableProxy();
DCHECK_NOT_NULL(proxy);
Variable* var = proxy->var();
- // Use KEYED_PROPERTY for private fields.
- return var->requires_brand_check() ? PRIVATE_METHOD : KEYED_PROPERTY;
+
+ switch (var->mode()) {
+ case VariableMode::kPrivateMethod:
+ return PRIVATE_METHOD;
+ case VariableMode::kConst:
+ return KEYED_PROPERTY; // Use KEYED_PROPERTY for private fields.
+ case VariableMode::kPrivateGetterOnly:
+ return PRIVATE_GETTER_ONLY;
+ case VariableMode::kPrivateSetterOnly:
+ return PRIVATE_SETTER_ONLY;
+ case VariableMode::kPrivateGetterAndSetter:
+ return PRIVATE_GETTER_AND_SETTER;
+ default:
+ UNREACHABLE();
+ }
}
bool super_access = property->IsSuperAccess();
return (property->key()->IsPropertyName())
@@ -1649,10 +1674,13 @@ class Property final : public Expression {
private:
friend class AstNodeFactory;
- Property(Expression* obj, Expression* key, int pos)
+ Property(Expression* obj, Expression* key, int pos, bool optional_chain)
: Expression(pos, kProperty), obj_(obj), key_(key) {
+ bit_field_ |= IsOptionalChainLinkField::encode(optional_chain);
}
+ using IsOptionalChainLinkField = Expression::NextBitField<bool, 1>;
+
Expression* obj_;
Expression* key_;
};
@@ -1690,6 +1718,10 @@ class Call final : public Expression {
return IsTaggedTemplateField::decode(bit_field_);
}
+ bool is_optional_chain_link() const {
+ return IsOptionalChainLinkField::decode(bit_field_);
+ }
+
bool only_last_arg_is_spread() {
return !arguments_.is_empty() && arguments_.last()->IsSpread();
}
@@ -1722,13 +1754,14 @@ class Call final : public Expression {
Call(Zone* zone, Expression* expression,
const ScopedPtrList<Expression>& arguments, int pos,
- PossiblyEval possibly_eval)
+ PossiblyEval possibly_eval, bool optional_chain)
: Expression(pos, kCall),
expression_(expression),
arguments_(0, nullptr) {
bit_field_ |=
IsPossiblyEvalField::encode(possibly_eval == IS_POSSIBLY_EVAL) |
- IsTaggedTemplateField::encode(false);
+ IsTaggedTemplateField::encode(false) |
+ IsOptionalChainLinkField::encode(optional_chain);
arguments.CopyTo(&arguments_, zone);
}
@@ -1739,14 +1772,14 @@ class Call final : public Expression {
expression_(expression),
arguments_(0, nullptr) {
bit_field_ |= IsPossiblyEvalField::encode(false) |
- IsTaggedTemplateField::encode(true);
+ IsTaggedTemplateField::encode(true) |
+ IsOptionalChainLinkField::encode(false);
arguments.CopyTo(&arguments_, zone);
}
- class IsPossiblyEvalField
- : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
- class IsTaggedTemplateField
- : public BitField<bool, IsPossiblyEvalField::kNext, 1> {};
+ using IsPossiblyEvalField = Expression::NextBitField<bool, 1>;
+ using IsTaggedTemplateField = IsPossiblyEvalField::Next<bool, 1>;
+ using IsOptionalChainLinkField = IsTaggedTemplateField::Next<bool, 1>;
Expression* expression_;
ZonePtrList<Expression> arguments_;
@@ -1838,8 +1871,7 @@ class UnaryOperation final : public Expression {
Expression* expression_;
- class OperatorField
- : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
+ using OperatorField = Expression::NextBitField<Token::Value, 7>;
};
@@ -1865,8 +1897,7 @@ class BinaryOperation final : public Expression {
Expression* left_;
Expression* right_;
- class OperatorField
- : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
+ using OperatorField = Expression::NextBitField<Token::Value, 7>;
};
class NaryOperation final : public Expression {
@@ -1925,8 +1956,7 @@ class NaryOperation final : public Expression {
};
ZoneVector<NaryOperationEntry> subsequent_;
- class OperatorField
- : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
+ using OperatorField = Expression::NextBitField<Token::Value, 7>;
};
class CountOperation final : public Expression {
@@ -1946,9 +1976,8 @@ class CountOperation final : public Expression {
bit_field_ |= IsPrefixField::encode(is_prefix) | TokenField::encode(op);
}
- class IsPrefixField
- : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
- class TokenField : public BitField<Token::Value, IsPrefixField::kNext, 7> {};
+ using IsPrefixField = Expression::NextBitField<bool, 1>;
+ using TokenField = IsPrefixField::Next<Token::Value, 7>;
Expression* expression_;
};
@@ -1978,8 +2007,7 @@ class CompareOperation final : public Expression {
Expression* left_;
Expression* right_;
- class OperatorField
- : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
+ using OperatorField = Expression::NextBitField<Token::Value, 7>;
};
@@ -2071,10 +2099,8 @@ class Assignment : public Expression {
private:
friend class AstNodeFactory;
- class TokenField
- : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
- class LookupHoistingModeField : public BitField<bool, TokenField::kNext, 1> {
- };
+ using TokenField = Expression::NextBitField<Token::Value, 7>;
+ using LookupHoistingModeField = TokenField::Next<bool, 1>;
Expression* target_;
Expression* value_;
@@ -2132,8 +2158,7 @@ class Suspend : public Expression {
Expression* expression_;
- class OnAbruptResumeField
- : public BitField<OnAbruptResume, Expression::kNextBitFieldIndex, 1> {};
+ using OnAbruptResumeField = Expression::NextBitField<OnAbruptResume, 1>;
};
class Yield final : public Suspend {
@@ -2175,14 +2200,6 @@ class Throw final : public Expression {
class FunctionLiteral final : public Expression {
public:
- enum FunctionType {
- kAnonymousExpression,
- kNamedExpression,
- kDeclaration,
- kAccessorOrMethod,
- kWrapped,
- };
-
enum ParameterFlag : uint8_t {
kNoDuplicateParameters,
kHasDuplicateParameters
@@ -2204,12 +2221,8 @@ class FunctionLiteral final : public Expression {
int function_token_position() const { return function_token_position_; }
int start_position() const;
int end_position() const;
- bool is_declaration() const { return function_type() == kDeclaration; }
- bool is_named_expression() const {
- return function_type() == kNamedExpression;
- }
bool is_anonymous_expression() const {
- return function_type() == kAnonymousExpression;
+ return syntax_kind() == FunctionSyntaxKind::kAnonymousExpression;
}
void mark_as_oneshot_iife() {
@@ -2219,7 +2232,6 @@ class FunctionLiteral final : public Expression {
bool is_toplevel() const {
return function_literal_id() == kFunctionLiteralIdTopLevel;
}
- bool is_wrapped() const { return function_type() == kWrapped; }
V8_EXPORT_PRIVATE LanguageMode language_mode() const;
static bool NeedsHomeObject(Expression* expr);
@@ -2289,8 +2301,8 @@ class FunctionLiteral final : public Expression {
V8_EXPORT_PRIVATE bool ShouldEagerCompile() const;
V8_EXPORT_PRIVATE void SetShouldEagerCompile();
- FunctionType function_type() const {
- return FunctionTypeBits::decode(bit_field_);
+ FunctionSyntaxKind syntax_kind() const {
+ return FunctionSyntaxKindBits::decode(bit_field_);
}
FunctionKind kind() const;
@@ -2342,7 +2354,7 @@ class FunctionLiteral final : public Expression {
AstValueFactory* ast_value_factory, DeclarationScope* scope,
const ScopedPtrList<Statement>& body,
int expected_property_count, int parameter_count,
- int function_length, FunctionType function_type,
+ int function_length, FunctionSyntaxKind function_syntax_kind,
ParameterFlag has_duplicate_parameters,
EagerCompileHint eager_compile_hint, int position,
bool has_braces, int function_literal_id,
@@ -2359,28 +2371,28 @@ class FunctionLiteral final : public Expression {
body_(0, nullptr),
raw_inferred_name_(ast_value_factory->empty_cons_string()),
produced_preparse_data_(produced_preparse_data) {
- bit_field_ |=
- FunctionTypeBits::encode(function_type) | Pretenure::encode(false) |
- HasDuplicateParameters::encode(has_duplicate_parameters ==
- kHasDuplicateParameters) |
- DontOptimizeReasonField::encode(BailoutReason::kNoReason) |
- RequiresInstanceMembersInitializer::encode(false) |
- HasBracesField::encode(has_braces) | OneshotIIFEBit::encode(false);
+ bit_field_ |= FunctionSyntaxKindBits::encode(function_syntax_kind) |
+ Pretenure::encode(false) |
+ HasDuplicateParameters::encode(has_duplicate_parameters ==
+ kHasDuplicateParameters) |
+ DontOptimizeReasonField::encode(BailoutReason::kNoReason) |
+ RequiresInstanceMembersInitializer::encode(false) |
+ HasBracesField::encode(has_braces) |
+ OneshotIIFEBit::encode(false);
if (eager_compile_hint == kShouldEagerCompile) SetShouldEagerCompile();
body.CopyTo(&body_, zone);
}
- class FunctionTypeBits
- : public BitField<FunctionType, Expression::kNextBitFieldIndex, 3> {};
- class Pretenure : public BitField<bool, FunctionTypeBits::kNext, 1> {};
- class HasDuplicateParameters : public BitField<bool, Pretenure::kNext, 1> {};
- class DontOptimizeReasonField
- : public BitField<BailoutReason, HasDuplicateParameters::kNext, 8> {};
- class RequiresInstanceMembersInitializer
- : public BitField<bool, DontOptimizeReasonField::kNext, 1> {};
- class HasBracesField
- : public BitField<bool, RequiresInstanceMembersInitializer::kNext, 1> {};
- class OneshotIIFEBit : public BitField<bool, HasBracesField::kNext, 1> {};
+ using FunctionSyntaxKindBits =
+ Expression::NextBitField<FunctionSyntaxKind, 3>;
+ using Pretenure = FunctionSyntaxKindBits::Next<bool, 1>;
+ using HasDuplicateParameters = Pretenure::Next<bool, 1>;
+ using DontOptimizeReasonField =
+ HasDuplicateParameters::Next<BailoutReason, 8>;
+ using RequiresInstanceMembersInitializer =
+ DontOptimizeReasonField::Next<bool, 1>;
+ using HasBracesField = RequiresInstanceMembersInitializer::Next<bool, 1>;
+ using OneshotIIFEBit = HasBracesField::Next<bool, 1>;
// expected_property_count_ is the sum of instance fields and properties.
// It can vary depending on whether a function is lazily or eagerly parsed.
@@ -2432,6 +2444,11 @@ class ClassLiteralProperty final : public LiteralProperty {
return private_or_computed_name_var_;
}
+ bool NeedsHomeObjectOnClassPrototype() const {
+ return is_private() && kind_ == METHOD &&
+ FunctionLiteral::NeedsHomeObject(value_);
+ }
+
private:
friend class AstNodeFactory;
@@ -2525,12 +2542,9 @@ class ClassLiteral final : public Expression {
ZonePtrList<Property>* properties_;
FunctionLiteral* static_fields_initializer_;
FunctionLiteral* instance_members_initializer_function_;
- class HasNameStaticProperty
- : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
- class HasStaticComputedNames
- : public BitField<bool, HasNameStaticProperty::kNext, 1> {};
- class IsAnonymousExpression
- : public BitField<bool, HasStaticComputedNames::kNext, 1> {};
+ using HasNameStaticProperty = Expression::NextBitField<bool, 1>;
+ using HasStaticComputedNames = HasNameStaticProperty::Next<bool, 1>;
+ using IsAnonymousExpression = HasStaticComputedNames::Next<bool, 1>;
};
@@ -3046,8 +3060,13 @@ class AstNodeFactory final {
return new (zone_) Variable(variable);
}
- Property* NewProperty(Expression* obj, Expression* key, int pos) {
- return new (zone_) Property(obj, key, pos);
+ OptionalChain* NewOptionalChain(Expression* expression) {
+ return new (zone_) OptionalChain(expression);
+ }
+
+ Property* NewProperty(Expression* obj, Expression* key, int pos,
+ bool optional_chain = false) {
+ return new (zone_) Property(obj, key, pos, optional_chain);
}
ResolvedProperty* NewResolvedProperty(VariableProxy* obj,
@@ -3058,8 +3077,10 @@ class AstNodeFactory final {
Call* NewCall(Expression* expression,
const ScopedPtrList<Expression>& arguments, int pos,
- Call::PossiblyEval possibly_eval = Call::NOT_EVAL) {
- return new (zone_) Call(zone_, expression, arguments, pos, possibly_eval);
+ Call::PossiblyEval possibly_eval = Call::NOT_EVAL,
+ bool optional_chain = false) {
+ return new (zone_)
+ Call(zone_, expression, arguments, pos, possibly_eval, optional_chain);
}
Call* NewTaggedTemplate(Expression* expression,
@@ -3189,13 +3210,13 @@ class AstNodeFactory final {
const ScopedPtrList<Statement>& body, int expected_property_count,
int parameter_count, int function_length,
FunctionLiteral::ParameterFlag has_duplicate_parameters,
- FunctionLiteral::FunctionType function_type,
+ FunctionSyntaxKind function_syntax_kind,
FunctionLiteral::EagerCompileHint eager_compile_hint, int position,
bool has_braces, int function_literal_id,
ProducedPreparseData* produced_preparse_data = nullptr) {
return new (zone_) FunctionLiteral(
zone_, name, ast_value_factory_, scope, body, expected_property_count,
- parameter_count, function_length, function_type,
+ parameter_count, function_length, function_syntax_kind,
has_duplicate_parameters, eager_compile_hint, position, has_braces,
function_literal_id, produced_preparse_data);
}
@@ -3209,7 +3230,7 @@ class AstNodeFactory final {
return new (zone_) FunctionLiteral(
zone_, ast_value_factory_->empty_string(), ast_value_factory_, scope,
body, expected_property_count, parameter_count, parameter_count,
- FunctionLiteral::kAnonymousExpression,
+ FunctionSyntaxKind::kAnonymousExpression,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kShouldLazyCompile, 0, /* has_braces */ false,
kFunctionLiteralIdTopLevel);
diff --git a/deps/v8/src/ast/modules.cc b/deps/v8/src/ast/modules.cc
index 261b72c352..dbd20f50a8 100644
--- a/deps/v8/src/ast/modules.cc
+++ b/deps/v8/src/ast/modules.cc
@@ -84,10 +84,11 @@ void SourceTextModuleDescriptor::AddStarExport(
}
namespace {
-Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) {
+Handle<HeapObject> ToStringOrUndefined(Isolate* isolate,
+ const AstRawString* s) {
return (s == nullptr)
- ? Handle<Object>::cast(isolate->factory()->undefined_value())
- : Handle<Object>::cast(s->string());
+ ? Handle<HeapObject>::cast(isolate->factory()->undefined_value())
+ : Handle<HeapObject>::cast(s->string());
}
} // namespace
diff --git a/deps/v8/src/ast/prettyprinter.cc b/deps/v8/src/ast/prettyprinter.cc
index c0fe3baff3..581517ee4e 100644
--- a/deps/v8/src/ast/prettyprinter.cc
+++ b/deps/v8/src/ast/prettyprinter.cc
@@ -27,6 +27,8 @@ CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js)
is_call_error_ = false;
is_iterator_error_ = false;
is_async_iterator_error_ = false;
+ destructuring_prop_ = nullptr;
+ destructuring_assignment_ = nullptr;
is_user_js_ = is_user_js;
function_kind_ = kNormalFunction;
InitializeAstVisitor(isolate);
@@ -299,24 +301,50 @@ void CallPrinter::VisitVariableProxy(VariableProxy* node) {
void CallPrinter::VisitAssignment(Assignment* node) {
- Find(node->target());
- if (node->target()->IsArrayLiteral()) {
- // Special case the visit for destructuring array assignment.
- bool was_found = false;
- if (node->value()->position() == position_) {
- is_iterator_error_ = true;
+ bool was_found = false;
+ if (node->target()->IsObjectLiteral()) {
+ ObjectLiteral* target = node->target()->AsObjectLiteral();
+ if (target->position() == position_) {
was_found = !found_;
- if (was_found) {
- found_ = true;
+ found_ = true;
+ destructuring_assignment_ = node;
+ } else {
+ for (ObjectLiteralProperty* prop : *target->properties()) {
+ if (prop->value()->position() == position_) {
+ was_found = !found_;
+ found_ = true;
+ destructuring_prop_ = prop;
+ destructuring_assignment_ = node;
+ break;
+ }
}
}
- Find(node->value(), true);
- if (was_found) {
- done_ = true;
- found_ = false;
+ }
+ if (!was_found) {
+ Find(node->target());
+ if (node->target()->IsArrayLiteral()) {
+ // Special case the visit for destructuring array assignment.
+ bool was_found = false;
+ if (node->value()->position() == position_) {
+ is_iterator_error_ = true;
+ was_found = !found_;
+ found_ = true;
+ }
+ Find(node->value(), true);
+ if (was_found) {
+ done_ = true;
+ found_ = false;
+ }
+ } else {
+ Find(node->value());
}
} else {
- Find(node->value());
+ Find(node->value(), true);
+ }
+
+ if (was_found) {
+ done_ = true;
+ found_ = false;
}
}
@@ -342,6 +370,9 @@ void CallPrinter::VisitAwait(Await* node) { Find(node->expression()); }
void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); }
+void CallPrinter::VisitOptionalChain(OptionalChain* node) {
+ Find(node->expression());
+}
void CallPrinter::VisitProperty(Property* node) {
Expression* key = node->key();
@@ -349,12 +380,18 @@ void CallPrinter::VisitProperty(Property* node) {
if (literal != nullptr &&
literal->BuildValue(isolate_)->IsInternalizedString()) {
Find(node->obj(), true);
+ if (node->is_optional_chain_link()) {
+ Print("?");
+ }
Print(".");
// TODO(adamk): Teach Literal how to print its values without
// allocating on the heap.
PrintLiteral(literal->BuildValue(isolate_), false);
} else {
Find(node->obj(), true);
+ if (node->is_optional_chain_link()) {
+ Print("?.");
+ }
Print("[");
Find(key, true);
Print("]");
@@ -1272,6 +1309,11 @@ void AstPrinter::VisitThrow(Throw* node) {
Visit(node->exception());
}
+void AstPrinter::VisitOptionalChain(OptionalChain* node) {
+ IndentedScope indent(this, "OPTIONAL_CHAIN", node->position());
+ Visit(node->expression());
+}
+
void AstPrinter::VisitProperty(Property* node) {
EmbeddedVector<char, 128> buf;
SNPrintF(buf, "PROPERTY");
@@ -1289,6 +1331,18 @@ void AstPrinter::VisitProperty(Property* node) {
PrintIndentedVisit("PRIVATE_METHOD", node->key());
break;
}
+ case PRIVATE_GETTER_ONLY: {
+ PrintIndentedVisit("PRIVATE_GETTER_ONLY", node->key());
+ break;
+ }
+ case PRIVATE_SETTER_ONLY: {
+ PrintIndentedVisit("PRIVATE_SETTER_ONLY", node->key());
+ break;
+ }
+ case PRIVATE_GETTER_AND_SETTER: {
+ PrintIndentedVisit("PRIVATE_GETTER_AND_SETTER", node->key());
+ break;
+ }
case KEYED_PROPERTY:
case KEYED_SUPER_PROPERTY: {
PrintIndentedVisit("KEY", node->key());
diff --git a/deps/v8/src/ast/prettyprinter.h b/deps/v8/src/ast/prettyprinter.h
index cceb5fc269..322fd9fb14 100644
--- a/deps/v8/src/ast/prettyprinter.h
+++ b/deps/v8/src/ast/prettyprinter.h
@@ -31,6 +31,12 @@ class CallPrinter final : public AstVisitor<CallPrinter> {
kCallAndAsyncIterator
};
ErrorHint GetErrorHint() const;
+ ObjectLiteralProperty* destructuring_prop() const {
+ return destructuring_prop_;
+ }
+ Assignment* destructuring_assignment() const {
+ return destructuring_assignment_;
+ }
// Individual nodes
#define DECLARE_VISIT(type) void Visit##type(type* node);
@@ -54,6 +60,8 @@ class CallPrinter final : public AstVisitor<CallPrinter> {
bool is_iterator_error_;
bool is_async_iterator_error_;
bool is_call_error_;
+ ObjectLiteralProperty* destructuring_prop_;
+ Assignment* destructuring_assignment_;
FunctionKind function_kind_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc
index 237d98ec60..c4d0999978 100644
--- a/deps/v8/src/ast/scopes.cc
+++ b/deps/v8/src/ast/scopes.cc
@@ -40,7 +40,6 @@ Variable* VariableMap::Declare(Zone* zone, Scope* scope,
VariableKind kind,
InitializationFlag initialization_flag,
MaybeAssignedFlag maybe_assigned_flag,
- RequiresBrandCheckFlag requires_brand_check,
bool* was_added) {
// AstRawStrings are unambiguous, i.e., the same string is always represented
// by the same AstRawString*.
@@ -52,9 +51,8 @@ Variable* VariableMap::Declare(Zone* zone, Scope* scope,
if (*was_added) {
// The variable has not been declared yet -> insert it.
DCHECK_EQ(name, p->key);
- Variable* variable =
- new (zone) Variable(scope, name, mode, kind, initialization_flag,
- maybe_assigned_flag, requires_brand_check);
+ Variable* variable = new (zone) Variable(
+ scope, name, mode, kind, initialization_flag, maybe_assigned_flag);
p->value = variable;
}
return reinterpret_cast<Variable*>(p->value);
@@ -170,7 +168,6 @@ Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info)
#ifdef DEBUG
already_resolved_ = true;
#endif
- if (scope_info->CallsSloppyEval()) scope_calls_eval_ = true;
set_language_mode(scope_info->language_mode());
num_heap_slots_ = scope_info->ContextLength();
DCHECK_LE(Context::MIN_CONTEXT_SLOTS, num_heap_slots_);
@@ -186,6 +183,10 @@ DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type,
params_(0, zone) {
DCHECK_NE(scope_type, SCRIPT_SCOPE);
SetDefaults();
+ if (scope_info->SloppyEvalCanExtendVars()) {
+ DCHECK(!is_eval_scope());
+ sloppy_eval_can_extend_vars_ = true;
+ }
}
Scope::Scope(Zone* zone, const AstRawString* catch_variable_name,
@@ -258,7 +259,8 @@ void Scope::SetDefaults() {
set_language_mode(LanguageMode::kSloppy);
- scope_calls_eval_ = false;
+ calls_eval_ = false;
+ sloppy_eval_can_extend_vars_ = false;
scope_nonlinear_ = false;
is_hidden_ = false;
is_debug_evaluate_scope_ = false;
@@ -380,11 +382,8 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
if (deserialization_mode == DeserializationMode::kIncludingVariables &&
script_scope->scope_info_.is_null()) {
- Handle<ScriptContextTable> table(
- isolate->native_context()->script_context_table(), isolate);
- Handle<Context> first = ScriptContextTable::GetContext(isolate, table, 0);
- Handle<ScopeInfo> scope_info(first->scope_info(), isolate);
- script_scope->SetScriptScopeInfo(scope_info);
+ script_scope->SetScriptScopeInfo(
+ ReadOnlyRoots(isolate).global_this_binding_scope_info_handle());
}
if (innermost_scope == nullptr) return script_scope;
@@ -626,7 +625,7 @@ Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name,
: NORMAL_VARIABLE;
function_ = new (zone())
Variable(this, name, VariableMode::kConst, kind, kCreatedInitialized);
- if (calls_sloppy_eval()) {
+ if (sloppy_eval_can_extend_vars()) {
cache->NonLocal(name, VariableMode::kDynamic);
} else {
cache->variables_.Add(zone(), function_);
@@ -652,7 +651,8 @@ Scope* Scope::FinalizeBlockScope() {
#endif
if (variables_.occupancy() > 0 ||
- (is_declaration_scope() && AsDeclarationScope()->calls_sloppy_eval())) {
+ (is_declaration_scope() &&
+ AsDeclarationScope()->sloppy_eval_can_extend_vars())) {
return this;
}
@@ -682,10 +682,10 @@ Scope* Scope::FinalizeBlockScope() {
if (inner_scope_calls_eval_) outer_scope()->inner_scope_calls_eval_ = true;
- // No need to propagate scope_calls_eval_, since if it was relevant to
- // this scope we would have had to bail out at the top.
- DCHECK(!scope_calls_eval_ || !is_declaration_scope() ||
- !is_sloppy(language_mode()));
+ // No need to propagate sloppy_eval_can_extend_vars_, since if it was relevant
+ // to this scope we would have had to bail out at the top.
+ DCHECK(!is_declaration_scope() ||
+ !AsDeclarationScope()->sloppy_eval_can_extend_vars());
// This block does not need a context.
num_heap_slots_ = 0;
@@ -750,8 +750,8 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) {
outer_closure->locals_.Rewind(top_local_);
// Move eval calls since Snapshot's creation into new_parent.
- if (outer_scope_and_calls_eval_->scope_calls_eval_) {
- new_parent->scope_calls_eval_ = true;
+ if (outer_scope_and_calls_eval_->calls_eval_) {
+ new_parent->RecordDeclarationScopeEvalCall();
new_parent->inner_scope_calls_eval_ = true;
}
@@ -787,13 +787,11 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
VariableMode mode;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
- RequiresBrandCheckFlag requires_brand_check = kNoBrandCheck;
{
location = VariableLocation::CONTEXT;
index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode,
- &init_flag, &maybe_assigned_flag,
- &requires_brand_check);
+ &init_flag, &maybe_assigned_flag);
found = index >= 0;
}
@@ -818,9 +816,9 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
}
bool was_added;
- Variable* var = cache->variables_.Declare(
- zone(), this, name, mode, NORMAL_VARIABLE, init_flag, maybe_assigned_flag,
- requires_brand_check, &was_added);
+ Variable* var =
+ cache->variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
+ init_flag, maybe_assigned_flag, &was_added);
DCHECK(was_added);
var->AllocateTo(location, index);
return var;
@@ -873,6 +871,8 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
VariableKind kind, bool* was_added,
InitializationFlag init_flag) {
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
@@ -905,6 +905,8 @@ Variable* Scope::DeclareVariable(
VariableMode mode, VariableKind kind, InitializationFlag init,
bool* was_added, bool* sloppy_mode_block_scope_function_redefinition,
bool* ok) {
+ // Private methods should be declared with ClassScope::DeclarePrivateName()
+ DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode));
DCHECK(IsDeclaredVariableMode(mode));
DCHECK(!already_resolved_);
DCHECK(!GetDeclarationScope()->is_being_lazily_parsed());
@@ -990,7 +992,8 @@ Variable* Scope::DeclareVariableName(const AstRawString* name,
DCHECK(IsDeclaredVariableMode(mode));
DCHECK(!already_resolved_);
DCHECK(GetDeclarationScope()->is_being_lazily_parsed());
-
+ // Private methods should be declared with ClassScope::DeclarePrivateName()
+ DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode));
if (mode == VariableMode::kVar && !is_declaration_scope()) {
return GetDeclarationScope()->DeclareVariableName(name, mode, was_added,
kind);
@@ -1044,7 +1047,7 @@ Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name,
bool was_added;
return cache->variables_.Declare(
zone(), this, name, VariableMode::kDynamicGlobal, kind,
- kCreatedInitialized, kNotAssigned, kNoBrandCheck, &was_added);
+ kCreatedInitialized, kNotAssigned, &was_added);
// TODO(neis): Mark variable as maybe-assigned?
}
@@ -1243,7 +1246,7 @@ int Scope::ContextChainLengthUntilOutermostSloppyEval() const {
if (!s->NeedsContext()) continue;
length++;
if (s->is_declaration_scope() &&
- s->AsDeclarationScope()->calls_sloppy_eval()) {
+ s->AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
result = length;
}
}
@@ -1384,9 +1387,10 @@ void Scope::CollectNonLocals(DeclarationScope* max_outer_scope,
void Scope::AnalyzePartially(DeclarationScope* max_outer_scope,
AstNodeFactory* ast_node_factory,
- UnresolvedList* new_unresolved_list) {
- this->ForEach([max_outer_scope, ast_node_factory,
- new_unresolved_list](Scope* scope) {
+ UnresolvedList* new_unresolved_list,
+ bool maybe_in_arrowhead) {
+ this->ForEach([max_outer_scope, ast_node_factory, new_unresolved_list,
+ maybe_in_arrowhead](Scope* scope) {
DCHECK_IMPLIES(scope->is_declaration_scope(),
!scope->AsDeclarationScope()->was_lazily_parsed());
@@ -1399,7 +1403,8 @@ void Scope::AnalyzePartially(DeclarationScope* max_outer_scope,
// Don't copy unresolved references to the script scope, unless it's a
// reference to a private name or method. In that case keep it so we
// can fail later.
- if (!max_outer_scope->outer_scope()->is_script_scope()) {
+ if (!max_outer_scope->outer_scope()->is_script_scope() ||
+ maybe_in_arrowhead) {
VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
new_unresolved_list->Add(copy);
}
@@ -1434,6 +1439,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
sloppy_block_functions_.Clear();
rare_data_ = nullptr;
has_rest_ = false;
+ function_ = nullptr;
DCHECK_NE(zone_, ast_value_factory->zone());
zone_->ReleaseMemory();
@@ -1487,17 +1493,19 @@ void DeclarationScope::SavePreparseDataForDeclarationScope(Parser* parser) {
}
void DeclarationScope::AnalyzePartially(Parser* parser,
- AstNodeFactory* ast_node_factory) {
+ AstNodeFactory* ast_node_factory,
+ bool maybe_in_arrowhead) {
DCHECK(!force_eager_compilation_);
UnresolvedList new_unresolved_list;
if (!IsArrowFunction(function_kind_) &&
- (!outer_scope_->is_script_scope() ||
+ (!outer_scope_->is_script_scope() || maybe_in_arrowhead ||
(preparse_data_builder_ != nullptr &&
preparse_data_builder_->HasInnerFunctions()))) {
// Try to resolve unresolved variables for this Scope and migrate those
// which cannot be resolved inside. It doesn't make sense to try to resolve
// them in the outer Scopes here, because they are incomplete.
- Scope::AnalyzePartially(this, ast_node_factory, &new_unresolved_list);
+ Scope::AnalyzePartially(this, ast_node_factory, &new_unresolved_list,
+ maybe_in_arrowhead);
// Migrate function_ to the right Zone.
if (function_ != nullptr) {
@@ -1596,10 +1604,6 @@ void PrintVar(int indent, Variable* var) {
if (comma) PrintF(", ");
PrintF("hole initialization elided");
}
- if (var->requires_brand_check()) {
- if (comma) PrintF(", ");
- PrintF("requires brand check");
- }
PrintF("\n");
}
@@ -1676,7 +1680,8 @@ void Scope::Print(int n) {
Indent(n1, "// strict mode scope\n");
}
if (IsAsmModule()) Indent(n1, "// scope is an asm module\n");
- if (is_declaration_scope() && AsDeclarationScope()->calls_sloppy_eval()) {
+ if (is_declaration_scope() &&
+ AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
Indent(n1, "// scope calls sloppy 'eval'\n");
}
if (is_declaration_scope() && AsDeclarationScope()->NeedsHomeObject()) {
@@ -1774,9 +1779,9 @@ Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
// Declare a new non-local.
DCHECK(IsDynamicVariableMode(mode));
bool was_added;
- Variable* var = variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
- kCreatedInitialized, kNotAssigned,
- kNoBrandCheck, &was_added);
+ Variable* var =
+ variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
+ kCreatedInitialized, kNotAssigned, &was_added);
// Allocate it by giving it a dynamic lookup.
var->AllocateTo(VariableLocation::LOOKUP, -1);
return var;
@@ -1814,7 +1819,18 @@ Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope,
// We found a variable and we are done. (Even if there is an 'eval' in this
// scope which introduces the same variable again, the resulting variable
// remains the same.)
- if (var != nullptr) {
+ //
+ // For sloppy eval though, we skip dynamic variable to avoid resolving to a
+ // variable when the variable and proxy are in the same eval execution. The
+ // variable is not available on subsequent lazy executions of functions in
+ // the eval, so this avoids inner functions from looking up different
+ // variables during eager and lazy compilation.
+ //
+ // TODO(leszeks): Maybe we want to restrict this to e.g. lookups of a proxy
+ // living in a different scope to the current one, or some other
+ // optimisation.
+ if (var != nullptr &&
+ !(scope->is_eval_scope() && var->mode() == VariableMode::kDynamic)) {
if (mode == kParsedScope && force_context_allocation &&
!var->is_dynamic()) {
var->ForceContextAllocation();
@@ -1829,8 +1845,9 @@ Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope,
return LookupWith(proxy, scope, outer_scope_end, entry_point,
force_context_allocation);
}
- if (V8_UNLIKELY(scope->is_declaration_scope() &&
- scope->AsDeclarationScope()->calls_sloppy_eval())) {
+ if (V8_UNLIKELY(
+ scope->is_declaration_scope() &&
+ scope->AsDeclarationScope()->sloppy_eval_can_extend_vars())) {
return LookupSloppyEval(proxy, scope, outer_scope_end, entry_point,
force_context_allocation);
}
@@ -1901,7 +1918,7 @@ Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope,
Scope* outer_scope_end, Scope* entry_point,
bool force_context_allocation) {
DCHECK(scope->is_declaration_scope() &&
- scope->AsDeclarationScope()->calls_sloppy_eval());
+ scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
// If we're compiling eval, it's possible that the outer scope is the first
// ScopeInfo-backed scope.
@@ -2065,7 +2082,7 @@ bool Scope::MustAllocate(Variable* var) {
if (!var->raw_name()->IsEmpty() &&
(inner_scope_calls_eval_ || is_catch_scope() || is_script_scope())) {
var->set_is_used();
- if (inner_scope_calls_eval_) var->SetMaybeAssigned();
+ if (inner_scope_calls_eval_ && !var->is_this()) var->SetMaybeAssigned();
}
DCHECK(!var->has_forced_context_allocation() || var->is_used());
// Global variables do not need to be allocated.
@@ -2081,11 +2098,14 @@ bool Scope::MustAllocateInContext(Variable* var) {
//
// Temporary variables are always stack-allocated. Catch-bound variables are
// always context-allocated.
- if (var->mode() == VariableMode::kTemporary) return false;
+ VariableMode mode = var->mode();
+ if (mode == VariableMode::kTemporary) return false;
if (is_catch_scope()) return true;
- if ((is_script_scope() || is_eval_scope()) &&
- IsLexicalVariableMode(var->mode())) {
- return true;
+ if (is_script_scope() || is_eval_scope()) {
+ if (IsLexicalVariableMode(mode) ||
+ IsPrivateMethodOrAccessorVariableMode(mode)) {
+ return true;
+ }
}
return var->has_forced_context_allocation() || inner_scope_calls_eval_;
}
@@ -2248,9 +2268,9 @@ void Scope::AllocateVariablesRecursively() {
scope->is_with_scope() || scope->is_module_scope() ||
scope->IsAsmModule() || scope->ForceContextForLanguageMode() ||
(scope->is_function_scope() &&
- scope->AsDeclarationScope()->calls_sloppy_eval()) ||
+ scope->AsDeclarationScope()->sloppy_eval_can_extend_vars()) ||
(scope->is_block_scope() && scope->is_declaration_scope() &&
- scope->AsDeclarationScope()->calls_sloppy_eval());
+ scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
// If we didn't allocate any locals in the local context, then we only
// need the minimal number of slots if we must have a context.
@@ -2326,15 +2346,28 @@ int Scope::ContextLocalCount() const {
(is_function_var_in_context ? 1 : 0);
}
-Variable* ClassScope::DeclarePrivateName(
- const AstRawString* name, RequiresBrandCheckFlag requires_brand_check,
- bool* was_added) {
+bool IsComplementaryAccessorPair(VariableMode a, VariableMode b) {
+ switch (a) {
+ case VariableMode::kPrivateGetterOnly:
+ return b == VariableMode::kPrivateSetterOnly;
+ case VariableMode::kPrivateSetterOnly:
+ return b == VariableMode::kPrivateGetterOnly;
+ default:
+ return false;
+ }
+}
+
+Variable* ClassScope::DeclarePrivateName(const AstRawString* name,
+ VariableMode mode, bool* was_added) {
Variable* result = EnsureRareData()->private_name_map.Declare(
- zone(), this, name, VariableMode::kConst, NORMAL_VARIABLE,
+ zone(), this, name, mode, NORMAL_VARIABLE,
InitializationFlag::kNeedsInitialization,
- MaybeAssignedFlag::kMaybeAssigned, requires_brand_check, was_added);
+ MaybeAssignedFlag::kMaybeAssigned, was_added);
if (*was_added) {
locals_.Add(result);
+ } else if (IsComplementaryAccessorPair(result->mode(), mode)) {
+ *was_added = true;
+ result->set_mode(VariableMode::kPrivateGetterAndSetter);
}
result->ForceContextAllocation();
return result;
@@ -2416,22 +2449,20 @@ Variable* ClassScope::LookupPrivateNameInScopeInfo(const AstRawString* name) {
VariableMode mode;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
- RequiresBrandCheckFlag requires_brand_check;
- int index =
- ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode, &init_flag,
- &maybe_assigned_flag, &requires_brand_check);
+ int index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode,
+ &init_flag, &maybe_assigned_flag);
if (index < 0) {
return nullptr;
}
- DCHECK_EQ(mode, VariableMode::kConst);
+ DCHECK(IsConstVariableMode(mode));
DCHECK_EQ(init_flag, InitializationFlag::kNeedsInitialization);
DCHECK_EQ(maybe_assigned_flag, MaybeAssignedFlag::kMaybeAssigned);
// Add the found private name to the map to speed up subsequent
// lookups for the same name.
bool was_added;
- Variable* var = DeclarePrivateName(name, requires_brand_check, &was_added);
+ Variable* var = DeclarePrivateName(name, mode, &was_added);
DCHECK(was_added);
var->AllocateTo(VariableLocation::CONTEXT, index);
return var;
@@ -2450,7 +2481,9 @@ Variable* ClassScope::LookupPrivateName(VariableProxy* proxy) {
if (var == nullptr && !class_scope->scope_info_.is_null()) {
var = class_scope->LookupPrivateNameInScopeInfo(proxy->raw_name());
}
- return var;
+ if (var != nullptr) {
+ return var;
+ }
}
return nullptr;
}
diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h
index 932d5c70b9..73e6e8fd89 100644
--- a/deps/v8/src/ast/scopes.h
+++ b/deps/v8/src/ast/scopes.h
@@ -5,6 +5,7 @@
#ifndef V8_AST_SCOPES_H_
#define V8_AST_SCOPES_H_
+#include <numeric>
#include "src/ast/ast.h"
#include "src/base/compiler-specific.h"
#include "src/base/hashmap.h"
@@ -13,6 +14,7 @@
#include "src/objects/function-kind.h"
#include "src/objects/objects.h"
#include "src/utils/pointer-with-payload.h"
+#include "src/utils/utils.h"
#include "src/zone/zone.h"
namespace v8 {
@@ -42,7 +44,6 @@ class VariableMap : public ZoneHashMap {
VariableMode mode, VariableKind kind,
InitializationFlag initialization_flag,
MaybeAssignedFlag maybe_assigned_flag,
- RequiresBrandCheckFlag requires_brand_check,
bool* was_added);
V8_EXPORT_PRIVATE Variable* Lookup(const AstRawString* name);
@@ -111,8 +112,10 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
}
void RestoreEvalFlag() {
- outer_scope_and_calls_eval_->scope_calls_eval_ =
- outer_scope_and_calls_eval_.GetPayload();
+ if (outer_scope_and_calls_eval_.GetPayload()) {
+ // This recreates both calls_eval and sloppy_eval_can_extend_vars.
+ outer_scope_and_calls_eval_.GetPointer()->RecordEvalCall();
+ }
}
void Reparent(DeclarationScope* new_parent);
@@ -265,9 +268,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// Inform the scope and outer scopes that the corresponding code contains an
// eval call.
- void RecordEvalCall() {
- scope_calls_eval_ = true;
- }
+ inline void RecordEvalCall();
void RecordInnerScopeEvalCall() {
inner_scope_calls_eval_ = true;
@@ -460,7 +461,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
int ContextChainLength(Scope* scope) const;
// The number of contexts between this and the outermost context that has a
- // sloppy eval call. One if this->calls_sloppy_eval().
+ // sloppy eval call. One if this->sloppy_eval_can_extend_vars().
int ContextChainLengthUntilOutermostSloppyEval() const;
// Find the closest class scope in the current scope and outer scopes. If no
@@ -558,7 +559,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
MaybeAssignedFlag maybe_assigned_flag, bool* was_added) {
Variable* result =
variables_.Declare(zone, this, name, mode, kind, initialization_flag,
- maybe_assigned_flag, kNoBrandCheck, was_added);
+ maybe_assigned_flag, was_added);
if (*was_added) locals_.Add(result);
return result;
}
@@ -610,7 +611,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// list along the way, so full resolution cannot be done afterwards.
void AnalyzePartially(DeclarationScope* max_outer_scope,
AstNodeFactory* ast_node_factory,
- UnresolvedList* new_unresolved_list);
+ UnresolvedList* new_unresolved_list,
+ bool maybe_in_arrowhead);
void CollectNonLocals(DeclarationScope* max_outer_scope, Isolate* isolate,
ParseInfo* info, Handle<StringSet>* non_locals);
@@ -703,9 +705,11 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// The language mode of this scope.
STATIC_ASSERT(LanguageModeSize == 2);
bool is_strict_ : 1;
- // This scope or a nested catch scope or with scope contain an 'eval' call. At
- // the 'eval' call site this scope is the declaration scope.
- bool scope_calls_eval_ : 1;
+ // This scope contains an 'eval' call.
+ bool calls_eval_ : 1;
+ // The context associated with this scope can be extended by a sloppy eval
+ // called inside of it.
+ bool sloppy_eval_can_extend_vars_ : 1;
// This scope's declarations might not be executed in order (e.g., switch).
bool scope_nonlinear_ : 1;
bool is_hidden_ : 1;
@@ -753,11 +757,50 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
IsClassConstructor(function_kind())));
}
- bool calls_sloppy_eval() const {
- // TODO(delphick): Calculate this when setting and change the name of
- // scope_calls_eval_.
- return !is_script_scope() && scope_calls_eval_ &&
- is_sloppy(language_mode());
+ // Inform the scope and outer scopes that the corresponding code contains an
+ // eval call.
+ void RecordDeclarationScopeEvalCall() {
+ calls_eval_ = true;
+
+ // If this isn't a sloppy eval, we don't care about it.
+ if (language_mode() != LanguageMode::kSloppy) return;
+
+ // Sloppy eval in script scopes can only introduce global variables anyway,
+ // so we don't care that it calls sloppy eval.
+ if (is_script_scope()) return;
+
+ // Sloppy eval in a eval scope can only introduce variables into the outer
+ // (non-eval) declaration scope, not into this eval scope.
+ if (is_eval_scope()) {
+#ifdef DEBUG
+ // One of three things must be true:
+ // 1. The outer non-eval declaration scope should already be marked as
+ // being extendable by sloppy eval, by the current sloppy eval rather
+ // than the inner one,
+ // 2. The outer non-eval declaration scope is a script scope and thus
+ // isn't extendable anyway, or
+ // 3. This is a debug evaluate and all bets are off.
+ DeclarationScope* outer_decl_scope = outer_scope()->GetDeclarationScope();
+ while (outer_decl_scope->is_eval_scope()) {
+ outer_decl_scope = outer_decl_scope->GetDeclarationScope();
+ }
+ if (outer_decl_scope->is_debug_evaluate_scope()) {
+ // Don't check anything.
+ // TODO(9662): Figure out where variables declared by an eval inside a
+ // debug-evaluate actually go.
+ } else if (!outer_decl_scope->is_script_scope()) {
+ DCHECK(outer_decl_scope->sloppy_eval_can_extend_vars_);
+ }
+#endif
+
+ return;
+ }
+
+ sloppy_eval_can_extend_vars_ = true;
+ }
+
+ bool sloppy_eval_can_extend_vars() const {
+ return sloppy_eval_can_extend_vars_;
}
bool was_lazily_parsed() const { return was_lazily_parsed_; }
@@ -972,7 +1015,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// this records variables which cannot be resolved inside the Scope (we don't
// yet know what they will resolve to since the outer Scopes are incomplete)
// and recreates them with the correct Zone with ast_node_factory.
- void AnalyzePartially(Parser* parser, AstNodeFactory* ast_node_factory);
+ void AnalyzePartially(Parser* parser, AstNodeFactory* ast_node_factory,
+ bool maybe_in_arrowhead);
// Allocate ScopeInfos for top scope and any inner scopes that need them.
// Does nothing if ScopeInfo is already allocated.
@@ -1138,13 +1182,21 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
RareData* rare_data_ = nullptr;
};
+void Scope::RecordEvalCall() {
+ calls_eval_ = true;
+ GetDeclarationScope()->RecordDeclarationScopeEvalCall();
+ RecordInnerScopeEvalCall();
+}
+
Scope::Snapshot::Snapshot(Scope* scope)
- : outer_scope_and_calls_eval_(scope, scope->scope_calls_eval_),
+ : outer_scope_and_calls_eval_(scope, scope->calls_eval_),
top_inner_scope_(scope->inner_scope_),
top_unresolved_(scope->unresolved_list_.end()),
top_local_(scope->GetClosureScope()->locals_.end()) {
// Reset in order to record eval calls during this Snapshot's lifetime.
- outer_scope_and_calls_eval_.GetPointer()->scope_calls_eval_ = false;
+ outer_scope_and_calls_eval_.GetPointer()->calls_eval_ = false;
+ outer_scope_and_calls_eval_.GetPointer()->sloppy_eval_can_extend_vars_ =
+ false;
}
class ModuleScope final : public DeclarationScope {
@@ -1175,8 +1227,7 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
// Declare a private name in the private name map and add it to the
// local variables of this scope.
- Variable* DeclarePrivateName(const AstRawString* name,
- RequiresBrandCheckFlag requires_brand_check,
+ Variable* DeclarePrivateName(const AstRawString* name, VariableMode mode,
bool* was_added);
void AddUnresolvedPrivateName(VariableProxy* proxy);
diff --git a/deps/v8/src/ast/source-range-ast-visitor.cc b/deps/v8/src/ast/source-range-ast-visitor.cc
index 2fcf151999..d171e30587 100644
--- a/deps/v8/src/ast/source-range-ast-visitor.cc
+++ b/deps/v8/src/ast/source-range-ast-visitor.cc
@@ -25,14 +25,6 @@ void SourceRangeAstVisitor::VisitBlock(Block* stmt) {
}
}
-void SourceRangeAstVisitor::VisitSwitchStatement(SwitchStatement* stmt) {
- AstTraversalVisitor::VisitSwitchStatement(stmt);
- ZonePtrList<CaseClause>* clauses = stmt->cases();
- for (CaseClause* clause : *clauses) {
- MaybeRemoveLastContinuationRange(clause->statements());
- }
-}
-
void SourceRangeAstVisitor::VisitFunctionLiteral(FunctionLiteral* expr) {
AstTraversalVisitor::VisitFunctionLiteral(expr);
ZonePtrList<Statement>* stmts = expr->body();
diff --git a/deps/v8/src/ast/source-range-ast-visitor.h b/deps/v8/src/ast/source-range-ast-visitor.h
index 4ba5feb2d2..4ea36a947f 100644
--- a/deps/v8/src/ast/source-range-ast-visitor.h
+++ b/deps/v8/src/ast/source-range-ast-visitor.h
@@ -34,7 +34,6 @@ class SourceRangeAstVisitor final
friend class AstTraversalVisitor<SourceRangeAstVisitor>;
void VisitBlock(Block* stmt);
- void VisitSwitchStatement(SwitchStatement* stmt);
void VisitFunctionLiteral(FunctionLiteral* expr);
bool VisitNode(AstNode* node);
diff --git a/deps/v8/src/ast/variables.h b/deps/v8/src/ast/variables.h
index 7805fa20c8..1ff6f9f422 100644
--- a/deps/v8/src/ast/variables.h
+++ b/deps/v8/src/ast/variables.h
@@ -21,8 +21,7 @@ class Variable final : public ZoneObject {
public:
Variable(Scope* scope, const AstRawString* name, VariableMode mode,
VariableKind kind, InitializationFlag initialization_flag,
- MaybeAssignedFlag maybe_assigned_flag = kNotAssigned,
- RequiresBrandCheckFlag requires_brand_check = kNoBrandCheck)
+ MaybeAssignedFlag maybe_assigned_flag = kNotAssigned)
: scope_(scope),
name_(name),
local_if_not_shadowed_(nullptr),
@@ -32,7 +31,6 @@ class Variable final : public ZoneObject {
bit_field_(MaybeAssignedFlagField::encode(maybe_assigned_flag) |
InitializationFlagField::encode(initialization_flag) |
VariableModeField::encode(mode) |
- RequiresBrandCheckField::encode(requires_brand_check) |
IsUsedField::encode(false) |
ForceContextAllocationField::encode(false) |
ForceHoleInitializationField::encode(false) |
@@ -58,6 +56,9 @@ class Variable final : public ZoneObject {
Handle<String> name() const { return name_->string(); }
const AstRawString* raw_name() const { return name_; }
VariableMode mode() const { return VariableModeField::decode(bit_field_); }
+ void set_mode(VariableMode mode) {
+ bit_field_ = VariableModeField::update(bit_field_, mode);
+ }
bool has_forced_context_allocation() const {
return ForceContextAllocationField::decode(bit_field_);
}
@@ -72,6 +73,8 @@ class Variable final : public ZoneObject {
return MaybeAssignedFlagField::decode(bit_field_);
}
void SetMaybeAssigned() {
+ if (mode() == VariableMode::kConst) return;
+
// If this variable is dynamically shadowing another variable, then that
// variable could also be assigned (in the non-shadowing case).
if (has_local_if_not_shadowed()) {
@@ -80,22 +83,14 @@ class Variable final : public ZoneObject {
if (!maybe_assigned()) {
local_if_not_shadowed()->SetMaybeAssigned();
}
- DCHECK(local_if_not_shadowed()->maybe_assigned());
+ DCHECK_IMPLIES(local_if_not_shadowed()->mode() != VariableMode::kConst,
+ local_if_not_shadowed()->maybe_assigned());
}
set_maybe_assigned();
}
- RequiresBrandCheckFlag get_requires_brand_check_flag() const {
- return RequiresBrandCheckField::decode(bit_field_);
- }
-
bool requires_brand_check() const {
- return get_requires_brand_check_flag() == kRequiresBrandCheck;
- }
-
- void set_requires_brand_check() {
- bit_field_ =
- RequiresBrandCheckField::update(bit_field_, kRequiresBrandCheck);
+ return IsPrivateMethodOrAccessorVariableMode(mode());
}
int initializer_position() { return initializer_position_; }
@@ -125,7 +120,8 @@ class Variable final : public ZoneObject {
// declaration time. Only returns valid results after scope analysis.
bool binding_needs_init() const {
DCHECK_IMPLIES(initialization_flag() == kNeedsInitialization,
- IsLexicalVariableMode(mode()));
+ IsLexicalVariableMode(mode()) ||
+ IsPrivateMethodOrAccessorVariableMode(mode()));
DCHECK_IMPLIES(ForceHoleInitializationField::decode(bit_field_),
initialization_flag() == kNeedsInitialization);
@@ -149,7 +145,8 @@ class Variable final : public ZoneObject {
// be required at runtime.
void ForceHoleInitialization() {
DCHECK_EQ(kNeedsInitialization, initialization_flag());
- DCHECK(IsLexicalVariableMode(mode()));
+ DCHECK(IsLexicalVariableMode(mode()) ||
+ IsPrivateMethodOrAccessorVariableMode(mode()));
bit_field_ = ForceHoleInitializationField::update(bit_field_, true);
}
@@ -243,25 +240,16 @@ class Variable final : public ZoneObject {
bit_field_ = MaybeAssignedFlagField::update(bit_field_, kMaybeAssigned);
}
- class VariableModeField : public BitField16<VariableMode, 0, 3> {};
- class VariableKindField
- : public BitField16<VariableKind, VariableModeField::kNext, 3> {};
- class LocationField
- : public BitField16<VariableLocation, VariableKindField::kNext, 3> {};
- class ForceContextAllocationField
- : public BitField16<bool, LocationField::kNext, 1> {};
- class IsUsedField
- : public BitField16<bool, ForceContextAllocationField::kNext, 1> {};
- class InitializationFlagField
- : public BitField16<InitializationFlag, IsUsedField::kNext, 1> {};
- class ForceHoleInitializationField
- : public BitField16<bool, InitializationFlagField::kNext, 1> {};
- class MaybeAssignedFlagField
- : public BitField16<MaybeAssignedFlag,
- ForceHoleInitializationField::kNext, 1> {};
- class RequiresBrandCheckField
- : public BitField16<RequiresBrandCheckFlag, MaybeAssignedFlagField::kNext,
- 1> {};
+ using VariableModeField = BitField16<VariableMode, 0, 4>;
+ using VariableKindField = VariableModeField::Next<VariableKind, 3>;
+ using LocationField = VariableKindField::Next<VariableLocation, 3>;
+ using ForceContextAllocationField = LocationField::Next<bool, 1>;
+ using IsUsedField = ForceContextAllocationField::Next<bool, 1>;
+ using InitializationFlagField = IsUsedField::Next<InitializationFlag, 1>;
+ using ForceHoleInitializationField = InitializationFlagField::Next<bool, 1>;
+ using MaybeAssignedFlagField =
+ ForceHoleInitializationField::Next<MaybeAssignedFlag, 1>;
+
Variable** next() { return &next_; }
friend List;
friend base::ThreadedListTraits<Variable>;
diff --git a/deps/v8/src/base/address-region.h b/deps/v8/src/base/address-region.h
index 1fdc479f6f..0f4809f9e8 100644
--- a/deps/v8/src/base/address-region.h
+++ b/deps/v8/src/base/address-region.h
@@ -45,6 +45,13 @@ class AddressRegion {
return contains(region.address_, region.size_);
}
+ base::AddressRegion GetOverlap(AddressRegion region) const {
+ Address overlap_start = std::max(begin(), region.begin());
+ Address overlap_end =
+ std::max(overlap_start, std::min(end(), region.end()));
+ return {overlap_start, overlap_end - overlap_start};
+ }
+
bool operator==(AddressRegion other) const {
return address_ == other.address_ && size_ == other.size_;
}
diff --git a/deps/v8/src/base/flags.h b/deps/v8/src/base/flags.h
index 055f0ff498..c2b7952260 100644
--- a/deps/v8/src/base/flags.h
+++ b/deps/v8/src/base/flags.h
@@ -53,13 +53,13 @@ class Flags final {
}
constexpr Flags operator&(const Flags& flags) const {
- return Flags(*this) &= flags;
+ return Flags(mask_ & flags.mask_);
}
constexpr Flags operator|(const Flags& flags) const {
- return Flags(*this) |= flags;
+ return Flags(mask_ | flags.mask_);
}
constexpr Flags operator^(const Flags& flags) const {
- return Flags(*this) ^= flags;
+ return Flags(mask_ ^ flags.mask_);
}
Flags& operator&=(flag_type flag) { return operator&=(Flags(flag)); }
diff --git a/deps/v8/src/base/page-allocator.cc b/deps/v8/src/base/page-allocator.cc
index b339f528d2..76a0aff399 100644
--- a/deps/v8/src/base/page-allocator.cc
+++ b/deps/v8/src/base/page-allocator.cc
@@ -36,9 +36,9 @@ void* PageAllocator::GetRandomMmapAddr() {
return base::OS::GetRandomMmapAddr();
}
-void* PageAllocator::AllocatePages(void* address, size_t size, size_t alignment,
+void* PageAllocator::AllocatePages(void* hint, size_t size, size_t alignment,
PageAllocator::Permission access) {
- return base::OS::Allocate(address, size, alignment,
+ return base::OS::Allocate(hint, size, alignment,
static_cast<base::OS::MemoryPermission>(access));
}
diff --git a/deps/v8/src/base/page-allocator.h b/deps/v8/src/base/page-allocator.h
index ced1156cca..2b8ee1a5e5 100644
--- a/deps/v8/src/base/page-allocator.h
+++ b/deps/v8/src/base/page-allocator.h
@@ -26,7 +26,7 @@ class V8_BASE_EXPORT PageAllocator
void* GetRandomMmapAddr() override;
- void* AllocatePages(void* address, size_t size, size_t alignment,
+ void* AllocatePages(void* hint, size_t size, size_t alignment,
PageAllocator::Permission access) override;
bool FreePages(void* address, size_t size) override;
diff --git a/deps/v8/src/base/platform/mutex.h b/deps/v8/src/base/platform/mutex.h
index 2b8b55eeb5..c48cf8d339 100644
--- a/deps/v8/src/base/platform/mutex.h
+++ b/deps/v8/src/base/platform/mutex.h
@@ -67,6 +67,8 @@ class V8_BASE_EXPORT Mutex final {
return native_handle_;
}
+ V8_INLINE void AssertHeld() { DCHECK_EQ(1, level_); }
+
private:
NativeHandle native_handle_;
#ifdef DEBUG
diff --git a/deps/v8/src/base/platform/platform-cygwin.cc b/deps/v8/src/base/platform/platform-cygwin.cc
index 17f9aa3f17..92a5fbe490 100644
--- a/deps/v8/src/base/platform/platform-cygwin.cc
+++ b/deps/v8/src/base/platform/platform-cygwin.cc
@@ -95,13 +95,13 @@ double LocalTimeOffset(double time_ms, bool is_utc) {
}
// static
-void* OS::Allocate(void* address, size_t size, size_t alignment,
+void* OS::Allocate(void* hint, size_t size, size_t alignment,
MemoryPermission access) {
size_t page_size = AllocatePageSize();
DCHECK_EQ(0, size % page_size);
DCHECK_EQ(0, alignment % page_size);
DCHECK_LE(page_size, alignment);
- address = AlignedAddress(address, alignment);
+ hint = AlignedAddress(hint, alignment);
DWORD flags = (access == OS::MemoryPermission::kNoAccess)
? MEM_RESERVE
@@ -109,7 +109,7 @@ void* OS::Allocate(void* address, size_t size, size_t alignment,
DWORD protect = GetProtectionFromMemoryPermission(access);
// First, try an exact size aligned allocation.
- uint8_t* base = RandomizedVirtualAlloc(size, flags, protect, address);
+ uint8_t* base = RandomizedVirtualAlloc(size, flags, protect, hint);
if (base == nullptr) return nullptr; // Can't allocate, we're OOM.
// If address is suitably aligned, we're done.
@@ -120,7 +120,7 @@ void* OS::Allocate(void* address, size_t size, size_t alignment,
CHECK(Free(base, size));
// Clear the hint. It's unlikely we can allocate at this address.
- address = nullptr;
+ hint = nullptr;
// Add the maximum misalignment so we are guaranteed an aligned base address
// in the allocated region.
@@ -128,7 +128,7 @@ void* OS::Allocate(void* address, size_t size, size_t alignment,
const int kMaxAttempts = 3;
aligned_base = nullptr;
for (int i = 0; i < kMaxAttempts; ++i) {
- base = RandomizedVirtualAlloc(padded_size, flags, protect, address);
+ base = RandomizedVirtualAlloc(padded_size, flags, protect, hint);
if (base == nullptr) return nullptr; // Can't allocate, we're OOM.
// Try to trim the allocation by freeing the padded allocation and then
diff --git a/deps/v8/src/base/platform/platform-posix.cc b/deps/v8/src/base/platform/platform-posix.cc
index 6da83d7e02..c50cdd7a98 100644
--- a/deps/v8/src/base/platform/platform-posix.cc
+++ b/deps/v8/src/base/platform/platform-posix.cc
@@ -137,10 +137,10 @@ int GetFlagsForMemoryPermission(OS::MemoryPermission access) {
return flags;
}
-void* Allocate(void* address, size_t size, OS::MemoryPermission access) {
+void* Allocate(void* hint, size_t size, OS::MemoryPermission access) {
int prot = GetProtectionFromMemoryPermission(access);
int flags = GetFlagsForMemoryPermission(access);
- void* result = mmap(address, size, prot, flags, kMmapFd, kMmapFdOffset);
+ void* result = mmap(hint, size, prot, flags, kMmapFd, kMmapFdOffset);
if (result == MAP_FAILED) return nullptr;
return result;
}
@@ -278,16 +278,16 @@ void* OS::GetRandomMmapAddr() {
// TODO(bbudge) Move Cygwin and Fuchsia stuff into platform-specific files.
#if !V8_OS_CYGWIN && !V8_OS_FUCHSIA
// static
-void* OS::Allocate(void* address, size_t size, size_t alignment,
+void* OS::Allocate(void* hint, size_t size, size_t alignment,
MemoryPermission access) {
size_t page_size = AllocatePageSize();
DCHECK_EQ(0, size % page_size);
DCHECK_EQ(0, alignment % page_size);
- address = AlignedAddress(address, alignment);
+ hint = AlignedAddress(hint, alignment);
// Add the maximum misalignment so we are guaranteed an aligned base address.
size_t request_size = size + (alignment - page_size);
request_size = RoundUp(request_size, OS::AllocatePageSize());
- void* result = base::Allocate(address, request_size, access);
+ void* result = base::Allocate(hint, request_size, access);
if (result == nullptr) return nullptr;
// Unmap memory allocated before the aligned base address.
@@ -761,13 +761,12 @@ void Thread::set_name(const char* name) {
name_[sizeof(name_) - 1] = '\0';
}
-
-void Thread::Start() {
+bool Thread::Start() {
int result;
pthread_attr_t attr;
memset(&attr, 0, sizeof(attr));
result = pthread_attr_init(&attr);
- DCHECK_EQ(0, result);
+ if (result != 0) return false;
size_t stack_size = stack_size_;
if (stack_size == 0) {
#if V8_OS_MACOSX
@@ -780,17 +779,17 @@ void Thread::Start() {
}
if (stack_size > 0) {
result = pthread_attr_setstacksize(&attr, stack_size);
- DCHECK_EQ(0, result);
+ if (result != 0) return pthread_attr_destroy(&attr), false;
}
{
MutexGuard lock_guard(&data_->thread_creation_mutex_);
result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
+ if (result != 0 || data_->thread_ == kNoThread) {
+ return pthread_attr_destroy(&attr), false;
+ }
}
- DCHECK_EQ(0, result);
result = pthread_attr_destroy(&attr);
- DCHECK_EQ(0, result);
- DCHECK_NE(data_->thread_, kNoThread);
- USE(result);
+ return result == 0;
}
void Thread::Join() { pthread_join(data_->thread_, nullptr); }
diff --git a/deps/v8/src/base/platform/platform-win32.cc b/deps/v8/src/base/platform/platform-win32.cc
index d01b1c07fe..04ef8a30f2 100644
--- a/deps/v8/src/base/platform/platform-win32.cc
+++ b/deps/v8/src/base/platform/platform-win32.cc
@@ -798,13 +798,13 @@ uint8_t* RandomizedVirtualAlloc(size_t size, DWORD flags, DWORD protect,
} // namespace
// static
-void* OS::Allocate(void* address, size_t size, size_t alignment,
+void* OS::Allocate(void* hint, size_t size, size_t alignment,
MemoryPermission access) {
size_t page_size = AllocatePageSize();
DCHECK_EQ(0, size % page_size);
DCHECK_EQ(0, alignment % page_size);
DCHECK_LE(page_size, alignment);
- address = AlignedAddress(address, alignment);
+ hint = AlignedAddress(hint, alignment);
DWORD flags = (access == OS::MemoryPermission::kNoAccess)
? MEM_RESERVE
@@ -812,7 +812,7 @@ void* OS::Allocate(void* address, size_t size, size_t alignment,
DWORD protect = GetProtectionFromMemoryPermission(access);
// First, try an exact size aligned allocation.
- uint8_t* base = RandomizedVirtualAlloc(size, flags, protect, address);
+ uint8_t* base = RandomizedVirtualAlloc(size, flags, protect, hint);
if (base == nullptr) return nullptr; // Can't allocate, we're OOM.
// If address is suitably aligned, we're done.
@@ -824,7 +824,7 @@ void* OS::Allocate(void* address, size_t size, size_t alignment,
CHECK(Free(base, size));
// Clear the hint. It's unlikely we can allocate at this address.
- address = nullptr;
+ hint = nullptr;
// Add the maximum misalignment so we are guaranteed an aligned base address
// in the allocated region.
@@ -832,7 +832,7 @@ void* OS::Allocate(void* address, size_t size, size_t alignment,
const int kMaxAttempts = 3;
aligned_base = nullptr;
for (int i = 0; i < kMaxAttempts; ++i) {
- base = RandomizedVirtualAlloc(padded_size, flags, protect, address);
+ base = RandomizedVirtualAlloc(padded_size, flags, protect, hint);
if (base == nullptr) return nullptr; // Can't allocate, we're OOM.
// Try to trim the allocation by freeing the padded allocation and then
@@ -1352,13 +1352,13 @@ Thread::~Thread() {
// Create a new thread. It is important to use _beginthreadex() instead of
// the Win32 function CreateThread(), because the CreateThread() does not
// initialize thread specific structures in the C runtime library.
-void Thread::Start() {
- data_->thread_ = reinterpret_cast<HANDLE>(
- _beginthreadex(nullptr, static_cast<unsigned>(stack_size_), ThreadEntry,
- this, 0, &data_->thread_id_));
+bool Thread::Start() {
+ uintptr_t result = _beginthreadex(nullptr, static_cast<unsigned>(stack_size_),
+ ThreadEntry, this, 0, &data_->thread_id_);
+ data_->thread_ = reinterpret_cast<HANDLE>(result);
+ return result != 0;
}
-
// Wait for thread to terminate.
void Thread::Join() {
if (data_->thread_id_ != GetCurrentThreadId()) {
diff --git a/deps/v8/src/base/platform/platform.h b/deps/v8/src/base/platform/platform.h
index e073704b2c..e1f84043eb 100644
--- a/deps/v8/src/base/platform/platform.h
+++ b/deps/v8/src/base/platform/platform.h
@@ -333,15 +333,16 @@ class V8_BASE_EXPORT Thread {
virtual ~Thread();
// Start new thread by calling the Run() method on the new thread.
- void Start();
+ V8_WARN_UNUSED_RESULT bool Start();
// Start new thread and wait until Run() method is called on the new thread.
- void StartSynchronously() {
+ bool StartSynchronously() {
start_semaphore_ = new Semaphore(0);
- Start();
+ if (!Start()) return false;
start_semaphore_->Wait();
delete start_semaphore_;
start_semaphore_ = nullptr;
+ return true;
}
// Wait until thread terminates.
diff --git a/deps/v8/src/base/utils/random-number-generator.cc b/deps/v8/src/base/utils/random-number-generator.cc
index 3b38858192..17c2cced8a 100644
--- a/deps/v8/src/base/utils/random-number-generator.cc
+++ b/deps/v8/src/base/utils/random-number-generator.cc
@@ -51,6 +51,13 @@ RandomNumberGenerator::RandomNumberGenerator() {
result = rand_s(&second_half);
DCHECK_EQ(0, result);
SetSeed((static_cast<int64_t>(first_half) << 32) + second_half);
+#elif V8_OS_MACOSX
+ // Despite its prefix suggests it is not RC4 algorithm anymore.
+ // It always succeeds while having decent performance and
+ // no file descriptor involved.
+ int64_t seed;
+ arc4random_buf(&seed, sizeof(seed));
+ SetSeed(seed);
#else
// Gather entropy from /dev/urandom if available.
FILE* fp = fopen("/dev/urandom", "rb");
diff --git a/deps/v8/src/builtins/OWNERS b/deps/v8/src/builtins/OWNERS
index 450423f878..f52e1c9ca8 100644
--- a/deps/v8/src/builtins/OWNERS
+++ b/deps/v8/src/builtins/OWNERS
@@ -1,3 +1,3 @@
-file://COMMON_OWNERS
+file:../../COMMON_OWNERS
# COMPONENT: Blink>JavaScript>Runtime
diff --git a/deps/v8/src/builtins/arguments.tq b/deps/v8/src/builtins/arguments.tq
index 6df5f801a3..18d6c23b3d 100644
--- a/deps/v8/src/builtins/arguments.tq
+++ b/deps/v8/src/builtins/arguments.tq
@@ -8,7 +8,7 @@ struct Arguments {
const length: intptr;
}
-extern operator '[]' macro GetArgumentValue(Arguments, intptr): Object;
+extern operator '[]' macro GetArgumentValue(Arguments, intptr): JSAny;
extern macro GetFrameArguments(FrameWithArguments, intptr): Arguments;
diff --git a/deps/v8/src/builtins/arm/builtins-arm.cc b/deps/v8/src/builtins/arm/builtins-arm.cc
index 9b9956b0fb..e9b562620f 100644
--- a/deps/v8/src/builtins/arm/builtins-arm.cc
+++ b/deps/v8/src/builtins/arm/builtins-arm.cc
@@ -90,12 +90,24 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
namespace {
+void LoadRealStackLimit(MacroAssembler* masm, Register destination) {
+ DCHECK(masm->root_array_available());
+ Isolate* isolate = masm->isolate();
+ ExternalReference limit = ExternalReference::address_of_real_jslimit(isolate);
+ DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
+
+ intptr_t offset =
+ TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
+ CHECK(is_int32(offset));
+ __ ldr(destination, MemOperand(kRootRegister, offset));
+}
+
void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch, Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
- __ LoadRoot(scratch, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch);
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
__ sub(scratch, sp, scratch);
@@ -428,7 +440,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
- __ CompareRoot(sp, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch);
+ __ cmp(sp, scratch);
__ b(lo, &stack_overflow);
// Push receiver.
@@ -1116,7 +1129,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Do a stack check to ensure we don't go over the limit.
Label ok;
__ sub(r9, sp, Operand(r4));
- __ LoadRoot(r2, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, r2);
__ cmp(r9, Operand(r2));
__ b(hs, &ok);
__ CallRuntime(Runtime::kThrowStackOverflow);
@@ -2089,7 +2102,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
// Compute the space we have left. The stack might already be overflowed
// here which will cause remaining_stack_size to become negative.
- __ LoadRoot(remaining_stack_size, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, remaining_stack_size);
__ sub(remaining_stack_size, sp, remaining_stack_size);
// Check if the arguments will overflow the stack.
@@ -2517,7 +2530,10 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ push(kWasmCompileLazyFuncIndexRegister);
// Load the correct CEntry builtin from the instance object.
__ ldr(r2, FieldMemOperand(kWasmInstanceRegister,
- WasmInstanceObject::kCEntryStubOffset));
+ WasmInstanceObject::kIsolateRootOffset));
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ __ ldr(r2, MemOperand(r2, IsolateData::builtin_slot_offset(centry_id)));
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Move(cp, Smi::zero());
diff --git a/deps/v8/src/builtins/arm64/builtins-arm64.cc b/deps/v8/src/builtins/arm64/builtins-arm64.cc
index bcee8f0b5d..4e159a69b7 100644
--- a/deps/v8/src/builtins/arm64/builtins-arm64.cc
+++ b/deps/v8/src/builtins/arm64/builtins-arm64.cc
@@ -24,6 +24,10 @@
#include "src/runtime/runtime.h"
#include "src/wasm/wasm-objects.h"
+#if defined(V8_OS_WIN)
+#include "src/diagnostics/unwinding-info-win64.h"
+#endif // V8_OS_WIN
+
namespace v8 {
namespace internal {
@@ -85,6 +89,17 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
namespace {
+void LoadRealStackLimit(MacroAssembler* masm, Register destination) {
+ DCHECK(masm->root_array_available());
+ Isolate* isolate = masm->isolate();
+ ExternalReference limit = ExternalReference::address_of_real_jslimit(isolate);
+ DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
+
+ intptr_t offset =
+ TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
+ __ Ldr(destination, MemOperand(kRootRegister, offset));
+}
+
void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Label* stack_overflow) {
UseScratchRegisterScope temps(masm);
@@ -94,7 +109,7 @@ void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
// We are not trying to catch interruptions (e.g. debug break and
// preemption) here, so the "real stack limit" is checked.
- __ LoadRoot(scratch, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch);
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
__ Sub(scratch, sp, scratch);
@@ -476,7 +491,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
- __ CompareRoot(sp, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, x10);
+ __ Cmp(sp, x10);
__ B(lo, &stack_overflow);
// Get number of arguments for generator function.
@@ -623,6 +639,23 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type,
// will have no effect on the model or real hardware.
__ EnableInstrumentation();
+#if defined(V8_OS_WIN)
+ // Windows ARM64 relies on a frame pointer (fp/x29 which are aliases to each
+ // other) chain to do stack unwinding, but JSEntry breaks that by setting fp
+ // to point to bad_frame_pointer below. To fix unwind information for this
+ // case, JSEntry registers the offset (from current fp to the caller's fp
+ // saved by PushCalleeSavedRegisters on stack) to xdata_encoder which then
+ // emits the offset value as part of result unwind data accordingly. The
+ // current offset is kFramePointerOffset which includes bad_frame_pointer
+ // saved below plus kFramePointerOffsetInPushCalleeSavedRegisters.
+ const int kFramePointerOffset =
+ kFramePointerOffsetInPushCalleeSavedRegisters + kSystemPointerSize;
+ win64_unwindinfo::XdataEncoder* xdata_encoder = masm->GetXdataEncoder();
+ if (xdata_encoder) {
+ xdata_encoder->onFramePointerAdjustment(kFramePointerOffset);
+ }
+#endif
+
__ PushCalleeSavedRegisters();
// Set up the reserved register for 0.0.
@@ -1223,7 +1256,12 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Do a stack check to ensure we don't go over the limit.
Label ok;
__ Sub(x10, sp, Operand(x11));
- __ CompareRoot(x10, RootIndex::kRealStackLimit);
+ {
+ UseScratchRegisterScope temps(masm);
+ Register scratch = temps.AcquireX();
+ LoadRealStackLimit(masm, scratch);
+ __ Cmp(x10, scratch);
+ }
__ B(hs, &ok);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ Bind(&ok);
@@ -2469,7 +2507,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
// (i.e. debug break and preemption) here, so check the "real stack
// limit".
Label done;
- __ LoadRoot(x10, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, x10);
// Make x10 the space we have left. The stack might already be overflowed
// here which will cause x10 to become negative.
__ Sub(x10, sp, x10);
@@ -3031,9 +3069,12 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
// function.
__ Push(kWasmInstanceRegister, kWasmCompileLazyFuncIndexRegister);
// Load the correct CEntry builtin from the instance object.
+ __ Ldr(x2, FieldMemOperand(kWasmInstanceRegister,
+ WasmInstanceObject::kIsolateRootOffset));
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
__ LoadTaggedPointerField(
- x2, FieldMemOperand(kWasmInstanceRegister,
- WasmInstanceObject::kCEntryStubOffset));
+ x2, MemOperand(x2, IsolateData::builtin_slot_offset(centry_id)));
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Mov(cp, Smi::zero());
diff --git a/deps/v8/src/builtins/array-copywithin.tq b/deps/v8/src/builtins/array-copywithin.tq
index 94d871e8f7..574eaf9b9d 100644
--- a/deps/v8/src/builtins/array-copywithin.tq
+++ b/deps/v8/src/builtins/array-copywithin.tq
@@ -9,7 +9,7 @@ namespace array_copywithin {
// https://tc39.github.io/ecma262/#sec-array.prototype.copyWithin
transitioning javascript builtin ArrayPrototypeCopyWithin(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
// 1. Let O be ? ToObject(this value).
const object: JSReceiver = ToObject_Inline(context, receiver);
@@ -68,7 +68,7 @@ namespace array_copywithin {
// d. If fromPresent is true, then.
if (fromPresent == True) {
// i. Let fromVal be ? Get(O, fromKey).
- const fromVal: Object = GetProperty(object, from);
+ const fromVal: JSAny = GetProperty(object, from);
// ii. Perform ? Set(O, toKey, fromVal, true).
SetProperty(object, to, fromVal);
diff --git a/deps/v8/src/builtins/array-every.tq b/deps/v8/src/builtins/array-every.tq
index 3451cd769b..8f4c0e1f23 100644
--- a/deps/v8/src/builtins/array-every.tq
+++ b/deps/v8/src/builtins/array-every.tq
@@ -5,15 +5,14 @@
namespace array {
transitioning javascript builtin
ArrayEveryLoopEagerDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object,
- length: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny {
// All continuation points in the optimized every implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -27,9 +26,9 @@ namespace array {
transitioning javascript builtin
ArrayEveryLoopLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object, length: Object,
- result: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny,
+ result: JSAny): JSAny {
// All continuation points in the optimized every implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -53,9 +52,9 @@ namespace array {
}
transitioning builtin ArrayEveryLoopContinuation(implicit context: Context)(
- _receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
- _array: Object, o: JSReceiver, initialK: Number, length: Number,
- _initialTo: Object): Object {
+ _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny,
+ _array: JSAny, o: JSReceiver, initialK: Number, length: Number,
+ _initialTo: JSAny): JSAny {
// 5. Let k be 0.
// 6. Repeat, while k < len
for (let k: Number = initialK; k < length; k++) {
@@ -69,10 +68,10 @@ namespace array {
// 6c. If kPresent is true, then
if (kPresent == True) {
// 6c. i. Let kValue be ? Get(O, Pk).
- const kValue: Object = GetProperty(o, k);
+ const kValue: JSAny = GetProperty(o, k);
// 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
- const result: Object = Call(context, callbackfn, thisArg, kValue, k, o);
+ const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o);
// iii. If selected is true, then...
if (!ToBoolean(result)) {
@@ -86,7 +85,7 @@ namespace array {
}
transitioning macro FastArrayEvery(implicit context: Context)(
- o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
+ o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny
labels Bailout(Smi) {
let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
@@ -99,8 +98,8 @@ namespace array {
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastOW.Get().length) goto Bailout(k);
- const value: Object = fastOW.LoadElementNoHole(k) otherwise continue;
- const result: Object =
+ const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue;
+ const result: JSAny =
Call(context, callbackfn, thisArg, value, k, fastOW.Get());
if (!ToBoolean(result)) {
return False;
@@ -111,8 +110,8 @@ namespace array {
// https://tc39.github.io/ecma262/#sec-array.prototype.every
transitioning javascript builtin
- ArrayEvery(js-implicit context: Context, receiver: Object)(...arguments):
- Object {
+ ArrayEvery(js-implicit context: Context, receiver: JSAny)(...arguments):
+ JSAny {
try {
RequireObjectCoercible(receiver, 'Array.prototype.every');
@@ -129,7 +128,7 @@ namespace array {
const callbackfn = Cast<Callable>(arguments[0]) otherwise TypeError;
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
- const thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
+ const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
// Special cases.
try {
diff --git a/deps/v8/src/builtins/array-filter.tq b/deps/v8/src/builtins/array-filter.tq
index 9acd0d04ee..4d23144329 100644
--- a/deps/v8/src/builtins/array-filter.tq
+++ b/deps/v8/src/builtins/array-filter.tq
@@ -5,15 +5,15 @@
namespace array_filter {
transitioning javascript builtin
ArrayFilterLoopEagerDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, array: Object, initialK: Object,
- length: Object, initialTo: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny,
+ length: JSAny, initialTo: JSAny): JSAny {
// All continuation points in the optimized filter implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -29,10 +29,9 @@ namespace array_filter {
transitioning javascript builtin
ArrayFilterLoopLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, array: Object, initialK: Object,
- length: Object, valueK: Object, initialTo: Object,
- result: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny,
+ length: JSAny, valueK: JSAny, initialTo: JSAny, result: JSAny): JSAny {
// All continuation points in the optimized filter implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -60,9 +59,9 @@ namespace array_filter {
}
transitioning builtin ArrayFilterLoopContinuation(implicit context: Context)(
- _receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
+ _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny,
array: JSReceiver, o: JSReceiver, initialK: Number, length: Number,
- initialTo: Number): Object {
+ initialTo: Number): JSAny {
let to: Number = initialTo;
// 5. Let k be 0.
// 6. Repeat, while k < len
@@ -77,10 +76,10 @@ namespace array_filter {
// 6c. If kPresent is true, then
if (kPresent == True) {
// 6c. i. Let kValue be ? Get(O, Pk).
- const kValue: Object = GetProperty(o, k);
+ const kValue: JSAny = GetProperty(o, k);
// 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
- const result: Object = Call(context, callbackfn, thisArg, kValue, k, o);
+ const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o);
// iii. If selected is true, then...
if (ToBoolean(result)) {
@@ -97,7 +96,7 @@ namespace array_filter {
}
transitioning macro FastArrayFilter(implicit context: Context)(
- fastO: FastJSArray, len: Smi, callbackfn: Callable, thisArg: Object,
+ fastO: FastJSArray, len: Smi, callbackfn: Callable, thisArg: JSAny,
output: FastJSArray) labels Bailout(Number, Number) {
let k: Smi = 0;
let to: Smi = 0;
@@ -112,8 +111,8 @@ namespace array_filter {
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastOW.Get().length) goto Bailout(k, to);
- const value: Object = fastOW.LoadElementNoHole(k) otherwise continue;
- const result: Object =
+ const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue;
+ const result: JSAny =
Call(context, callbackfn, thisArg, value, k, fastOW.Get());
if (ToBoolean(result)) {
try {
@@ -147,8 +146,8 @@ namespace array_filter {
// https://tc39.github.io/ecma262/#sec-array.prototype.filter
transitioning javascript builtin
- ArrayFilter(js-implicit context: Context, receiver: Object)(...arguments):
- Object {
+ ArrayFilter(js-implicit context: Context, receiver: JSAny)(...arguments):
+ JSAny {
try {
RequireObjectCoercible(receiver, 'Array.prototype.filter');
@@ -165,7 +164,7 @@ namespace array_filter {
const callbackfn = Cast<Callable>(arguments[0]) otherwise TypeError;
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
- const thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
+ const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
let output: JSReceiver;
// Special cases.
diff --git a/deps/v8/src/builtins/array-find.tq b/deps/v8/src/builtins/array-find.tq
index ef54dd4666..ec840a4c98 100644
--- a/deps/v8/src/builtins/array-find.tq
+++ b/deps/v8/src/builtins/array-find.tq
@@ -5,15 +5,14 @@
namespace array_find {
transitioning javascript builtin
ArrayFindLoopEagerDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object,
- length: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny {
// All continuation points in the optimized find implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -26,9 +25,9 @@ namespace array_find {
transitioning javascript builtin
ArrayFindLoopLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- _callback: Object, _thisArg: Object, _initialK: Object, _length: Object,
- _result: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ _callback: JSAny, _thisArg: JSAny, _initialK: JSAny, _length: JSAny,
+ _result: JSAny): JSAny {
// This deopt continuation point is never actually called, it just
// exists to make stack traces correct from a ThrowTypeError if the
// callback was found to be non-callable.
@@ -40,9 +39,9 @@ namespace array_find {
// before iteration continues.
transitioning javascript builtin
ArrayFindLoopAfterCallbackLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object, length: Object,
- foundValue: Object, isFound: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny,
+ foundValue: JSAny, isFound: JSAny): JSAny {
// All continuation points in the optimized find implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -65,8 +64,8 @@ namespace array_find {
}
transitioning builtin ArrayFindLoopContinuation(implicit context: Context)(
- _receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
- o: JSReceiver, initialK: Number, length: Number): Object {
+ _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny,
+ o: JSReceiver, initialK: Number, length: Number): JSAny {
// 5. Let k be 0.
// 6. Repeat, while k < len
for (let k: Number = initialK; k < length; k++) {
@@ -75,12 +74,11 @@ namespace array_find {
// side-effect free and HasProperty/GetProperty do the conversion inline.
// 6b. i. Let kValue be ? Get(O, Pk).
- const value: Object = GetProperty(o, k);
+ const value: JSAny = GetProperty(o, k);
// 6c. Let testResult be ToBoolean(? Call(predicate, T, <<kValue, k,
// O>>)).
- const testResult: Object =
- Call(context, callbackfn, thisArg, value, k, o);
+ const testResult: JSAny = Call(context, callbackfn, thisArg, value, k, o);
// 6d. If testResult is true, return kValue.
if (ToBoolean(testResult)) {
@@ -93,7 +91,7 @@ namespace array_find {
}
transitioning macro FastArrayFind(implicit context: Context)(
- o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
+ o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny
labels Bailout(Smi) {
let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
@@ -107,8 +105,8 @@ namespace array_find {
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastOW.Get().length) goto Bailout(k);
- const value: Object = fastOW.LoadElementOrUndefined(k);
- const testResult: Object =
+ const value: JSAny = fastOW.LoadElementOrUndefined(k);
+ const testResult: JSAny =
Call(context, callbackfn, thisArg, value, k, fastOW.Get());
if (ToBoolean(testResult)) {
return value;
@@ -119,8 +117,8 @@ namespace array_find {
// https://tc39.github.io/ecma262/#sec-array.prototype.find
transitioning javascript builtin
- ArrayPrototypeFind(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ ArrayPrototypeFind(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
try {
RequireObjectCoercible(receiver, 'Array.prototype.find');
@@ -138,7 +136,7 @@ namespace array_find {
Cast<Callable>(arguments[0]) otherwise NotCallableError;
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
- const thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
+ const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
// Special cases.
try {
diff --git a/deps/v8/src/builtins/array-findindex.tq b/deps/v8/src/builtins/array-findindex.tq
index 5a8bb85fba..6145c81464 100644
--- a/deps/v8/src/builtins/array-findindex.tq
+++ b/deps/v8/src/builtins/array-findindex.tq
@@ -5,15 +5,14 @@
namespace array_findindex {
transitioning javascript builtin
ArrayFindIndexLoopEagerDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object,
- length: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny {
// All continuation points in the optimized findIndex implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -26,9 +25,9 @@ namespace array_findindex {
transitioning javascript builtin
ArrayFindIndexLoopLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- _callback: Object, _thisArg: Object, _initialK: Object, _length: Object,
- _result: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ _callback: JSAny, _thisArg: JSAny, _initialK: JSAny, _length: JSAny,
+ _result: JSAny): JSAny {
// This deopt continuation point is never actually called, it just
// exists to make stack traces correct from a ThrowTypeError if the
// callback was found to be non-callable.
@@ -40,9 +39,9 @@ namespace array_findindex {
// before iteration continues.
transitioning javascript builtin
ArrayFindIndexLoopAfterCallbackLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object, length: Object,
- foundValue: Object, isFound: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny,
+ foundValue: JSAny, isFound: JSAny): JSAny {
// All continuation points in the optimized findIndex implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -66,7 +65,7 @@ namespace array_findindex {
transitioning builtin ArrayFindIndexLoopContinuation(implicit context:
Context)(
- _receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
+ _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny,
o: JSReceiver, initialK: Number, length: Number): Number {
// 5. Let k be 0.
// 6. Repeat, while k < len
@@ -76,12 +75,11 @@ namespace array_findindex {
// side-effect free and HasProperty/GetProperty do the conversion inline.
// 6b. i. Let kValue be ? Get(O, Pk).
- const value: Object = GetProperty(o, k);
+ const value: JSAny = GetProperty(o, k);
// 6c. Let testResult be ToBoolean(? Call(predicate, T, <<kValue, k,
// O>>)).
- const testResult: Object =
- Call(context, callbackfn, thisArg, value, k, o);
+ const testResult: JSAny = Call(context, callbackfn, thisArg, value, k, o);
// 6d. If testResult is true, return k.
if (ToBoolean(testResult)) {
@@ -94,7 +92,7 @@ namespace array_findindex {
}
transitioning macro FastArrayFindIndex(implicit context: Context)(
- o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Number
+ o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): Number
labels Bailout(Smi) {
let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
@@ -108,8 +106,8 @@ namespace array_findindex {
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastOW.Get().length) goto Bailout(k);
- const value: Object = fastOW.LoadElementOrUndefined(k);
- const testResult: Object =
+ const value: JSAny = fastOW.LoadElementOrUndefined(k);
+ const testResult: JSAny =
Call(context, callbackfn, thisArg, value, k, fastOW.Get());
if (ToBoolean(testResult)) {
return k;
@@ -120,8 +118,8 @@ namespace array_findindex {
// https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
transitioning javascript builtin
- ArrayPrototypeFindIndex(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ ArrayPrototypeFindIndex(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
try {
RequireObjectCoercible(receiver, 'Array.prototype.findIndex');
@@ -139,7 +137,7 @@ namespace array_findindex {
Cast<Callable>(arguments[0]) otherwise NotCallableError;
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
- const thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
+ const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
// Special cases.
try {
diff --git a/deps/v8/src/builtins/array-foreach.tq b/deps/v8/src/builtins/array-foreach.tq
index f52d944291..5b6e392601 100644
--- a/deps/v8/src/builtins/array-foreach.tq
+++ b/deps/v8/src/builtins/array-foreach.tq
@@ -5,9 +5,8 @@
namespace array_foreach {
transitioning javascript builtin
ArrayForEachLoopEagerDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object,
- length: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny {
// All continuation points in the optimized forEach implemntation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -23,9 +22,9 @@ namespace array_foreach {
transitioning javascript builtin
ArrayForEachLoopLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object, length: Object,
- _result: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny,
+ _result: JSAny): JSAny {
// All continuation points in the optimized forEach implemntation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -40,9 +39,9 @@ namespace array_foreach {
}
transitioning builtin ArrayForEachLoopContinuation(implicit context: Context)(
- _receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
- _array: Object, o: JSReceiver, initialK: Number, len: Number,
- _to: Object): Object {
+ _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny,
+ _array: JSAny, o: JSReceiver, initialK: Number, len: Number,
+ _to: JSAny): JSAny {
// variables {array} and {to} are ignored.
// 5. Let k be 0.
@@ -58,7 +57,7 @@ namespace array_foreach {
// 6c. If kPresent is true, then
if (kPresent == True) {
// 6c. i. Let kValue be ? Get(O, Pk).
- const kValue: Object = GetProperty(o, k);
+ const kValue: JSAny = GetProperty(o, k);
// 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
Call(context, callbackfn, thisArg, kValue, k, o);
@@ -70,7 +69,7 @@ namespace array_foreach {
}
transitioning macro FastArrayForEach(implicit context: Context)(
- o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
+ o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny
labels Bailout(Smi) {
let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
@@ -83,7 +82,7 @@ namespace array_foreach {
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastOW.Get().length) goto Bailout(k);
- const value: Object = fastOW.LoadElementNoHole(k)
+ const value: JSAny = fastOW.LoadElementNoHole(k)
otherwise continue;
Call(context, callbackfn, thisArg, value, k, fastOW.Get());
}
@@ -92,8 +91,8 @@ namespace array_foreach {
// https://tc39.github.io/ecma262/#sec-array.prototype.foreach
transitioning javascript builtin
- ArrayForEach(js-implicit context: Context, receiver: Object)(...arguments):
- Object {
+ ArrayForEach(js-implicit context: Context, receiver: JSAny)(...arguments):
+ JSAny {
try {
RequireObjectCoercible(receiver, 'Array.prototype.forEach');
@@ -110,7 +109,7 @@ namespace array_foreach {
const callbackfn = Cast<Callable>(arguments[0]) otherwise TypeError;
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
- const thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
+ const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
// Special cases.
let k: Number = 0;
diff --git a/deps/v8/src/builtins/array-join.tq b/deps/v8/src/builtins/array-join.tq
index c04233b222..08b5221e09 100644
--- a/deps/v8/src/builtins/array-join.tq
+++ b/deps/v8/src/builtins/array-join.tq
@@ -3,7 +3,7 @@
// found in the LICENSE file.
namespace array_join {
- type LoadJoinElementFn = builtin(Context, JSReceiver, Number) => Object;
+ type LoadJoinElementFn = builtin(Context, JSReceiver, Number) => JSAny;
// Fast C call to write a fixed array (see Buffer.fixedArray) to a single
// string.
@@ -12,12 +12,12 @@ namespace array_join {
FixedArray, intptr, String, String): String;
transitioning builtin LoadJoinElement<T: type>(
- context: Context, receiver: JSReceiver, k: Number): Object {
+ context: Context, receiver: JSReceiver, k: Number): JSAny {
return GetProperty(receiver, k);
}
- LoadJoinElement<array::DictionaryElements>(
- context: Context, receiver: JSReceiver, k: Number): Object {
+ transitioning LoadJoinElement<array::DictionaryElements>(
+ context: Context, receiver: JSReceiver, k: Number): JSAny {
const array: JSArray = UnsafeCast<JSArray>(receiver);
const dict: NumberDictionary = UnsafeCast<NumberDictionary>(array.elements);
try {
@@ -33,15 +33,15 @@ namespace array_join {
}
LoadJoinElement<array::FastSmiOrObjectElements>(
- context: Context, receiver: JSReceiver, k: Number): Object {
+ context: Context, receiver: JSReceiver, k: Number): JSAny {
const array: JSArray = UnsafeCast<JSArray>(receiver);
const fixedArray: FixedArray = UnsafeCast<FixedArray>(array.elements);
const element: Object = fixedArray.objects[UnsafeCast<Smi>(k)];
- return element == TheHole ? kEmptyString : element;
+ return element == TheHole ? kEmptyString : UnsafeCast<JSAny>(element);
}
LoadJoinElement<array::FastDoubleElements>(
- context: Context, receiver: JSReceiver, k: Number): Object {
+ context: Context, receiver: JSReceiver, k: Number): JSAny {
const array: JSArray = UnsafeCast<JSArray>(receiver);
const fixedDoubleArray: FixedDoubleArray =
UnsafeCast<FixedDoubleArray>(array.elements);
@@ -51,7 +51,7 @@ namespace array_join {
}
builtin LoadJoinTypedElement<T: type>(
- context: Context, receiver: JSReceiver, k: Number): Object {
+ context: Context, receiver: JSReceiver, k: Number): JSAny {
const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
assert(!IsDetachedBuffer(typedArray.buffer));
return typed_array::LoadFixedTypedArrayElementAsTagged(
@@ -60,14 +60,14 @@ namespace array_join {
}
transitioning builtin ConvertToLocaleString(
- context: Context, element: Object, locales: Object,
- options: Object): String {
+ context: Context, element: JSAny, locales: JSAny,
+ options: JSAny): String {
if (IsNullOrUndefined(element)) return kEmptyString;
- const prop: Object = GetProperty(element, 'toLocaleString');
+ const prop: JSAny = GetProperty(element, 'toLocaleString');
try {
const callable: Callable = Cast<Callable>(prop) otherwise TypeError;
- let result: Object;
+ let result: JSAny;
if (IsNullOrUndefined(locales)) {
result = Call(context, callable, element);
} else if (IsNullOrUndefined(options)) {
@@ -86,29 +86,25 @@ namespace array_join {
// (see LoadJoinElement<ElementsAccessor>).
macro CannotUseSameArrayAccessor<T: type>(implicit context: Context)(
loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map,
- originalLen: Number): never
- labels Cannot, Can;
+ originalLen: Number): bool;
CannotUseSameArrayAccessor<JSArray>(implicit context: Context)(
loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map,
- originalLen: Number): never
- labels Cannot, Can {
- if (loadFn == LoadJoinElement<array::GenericElementsAccessor>) goto Can;
+ originalLen: Number): bool {
+ if (loadFn == LoadJoinElement<array::GenericElementsAccessor>) return false;
const array: JSArray = UnsafeCast<JSArray>(receiver);
- if (originalMap != array.map) goto Cannot;
- if (originalLen != array.length) goto Cannot;
- if (IsNoElementsProtectorCellInvalid()) goto Cannot;
- goto Can;
+ if (originalMap != array.map) return true;
+ if (originalLen != array.length) return true;
+ if (IsNoElementsProtectorCellInvalid()) return true;
+ return false;
}
CannotUseSameArrayAccessor<JSTypedArray>(implicit context: Context)(
_loadFn: LoadJoinElementFn, receiver: JSReceiver, _initialMap: Map,
- _initialLen: Number): never
- labels Cannot, Can {
+ _initialLen: Number): bool {
const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
- if (IsDetachedBuffer(typedArray.buffer)) goto Cannot;
- goto Can;
+ return IsDetachedBuffer(typedArray.buffer);
}
// Calculates the running total length of the resulting string. If the
@@ -261,7 +257,7 @@ namespace array_join {
transitioning macro ArrayJoinImpl<T: type>(implicit context: Context)(
receiver: JSReceiver, sep: String, lengthNumber: Number,
- useToLocaleString: constexpr bool, locales: Object, options: Object,
+ useToLocaleString: constexpr bool, locales: JSAny, options: JSAny,
initialLoadFn: LoadJoinElementFn): String {
const initialMap: Map = receiver.map;
const len: uintptr = Convert<uintptr>(lengthNumber);
@@ -287,7 +283,7 @@ namespace array_join {
}
// b. Let element be ? Get(O, ! ToString(k)).
- const element: Object = loadFn(context, receiver, Convert<Number>(k++));
+ const element: JSAny = loadFn(context, receiver, Convert<Number>(k++));
// c. If element is undefined or null, let next be the empty String;
// otherwise, let next be ? ToString(element).
@@ -304,7 +300,7 @@ namespace array_join {
case (num: Number): {
next = NumberToString(num);
}
- case (obj: HeapObject): {
+ case (obj: JSAny): {
if (IsNullOrUndefined(obj)) continue;
next = ToString(context, obj);
}
@@ -325,11 +321,11 @@ namespace array_join {
transitioning macro ArrayJoin<T: type>(implicit context: Context)(
useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String,
- lenNumber: Number, locales: Object, options: Object): Object;
+ lenNumber: Number, locales: JSAny, options: JSAny): JSAny;
- ArrayJoin<JSArray>(implicit context: Context)(
+ transitioning ArrayJoin<JSArray>(implicit context: Context)(
useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String,
- lenNumber: Number, locales: Object, options: Object): Object {
+ lenNumber: Number, locales: JSAny, options: JSAny): JSAny {
const map: Map = receiver.map;
const kind: ElementsKind = map.elements_kind;
let loadFn: LoadJoinElementFn;
@@ -374,9 +370,9 @@ namespace array_join {
receiver, sep, lenNumber, useToLocaleString, locales, options, loadFn);
}
- ArrayJoin<JSTypedArray>(implicit context: Context)(
+ transitioning ArrayJoin<JSTypedArray>(implicit context: Context)(
useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String,
- lenNumber: Number, locales: Object, options: Object): Object {
+ lenNumber: Number, locales: JSAny, options: JSAny): JSAny {
const map: Map = receiver.map;
const kind: ElementsKind = map.elements_kind;
let loadFn: LoadJoinElementFn;
@@ -465,11 +461,9 @@ namespace array_join {
}
// Fast path the common non-nested calls. If the receiver is not already on
- // the stack, add it to the stack and go to ReceiverAdded. Otherwise go to
- // ReceiverNotAdded.
+ // the stack, add it to the stack and return true. Otherwise return false.
macro JoinStackPushInline(implicit context: Context)(receiver: JSReceiver):
- never
- labels ReceiverAdded, ReceiverNotAdded {
+ bool {
try {
const stack: FixedArray = LoadJoinStack()
otherwise IfUninitialized;
@@ -477,7 +471,7 @@ namespace array_join {
stack.objects[0] = receiver;
} else if (JoinStackPush(stack, receiver) == False)
deferred {
- goto ReceiverNotAdded;
+ return false;
}
}
label IfUninitialized {
@@ -486,13 +480,13 @@ namespace array_join {
stack.objects[0] = receiver;
SetJoinStack(stack);
}
- goto ReceiverAdded;
+ return true;
}
// Removes a receiver from the stack. The FixedArray will automatically shrink
// to Heap::kMinJoinStackSize once the stack becomes empty.
builtin JoinStackPop(implicit context: Context)(
- stack: FixedArray, receiver: JSReceiver): Object {
+ stack: FixedArray, receiver: JSReceiver): JSAny {
const len: intptr = stack.length_intptr;
for (let i: intptr = 0; i < len; i++) {
if (stack.objects[i] == receiver) {
@@ -532,7 +526,7 @@ namespace array_join {
transitioning macro CycleProtectedArrayJoin<T: type>(implicit context:
Context)(
useToLocaleString: constexpr bool, o: JSReceiver, len: Number,
- sepObj: Object, locales: Object, options: Object): Object {
+ sepObj: JSAny, locales: JSAny, options: JSAny): JSAny {
// 3. If separator is undefined, let sep be the single-element String ",".
// 4. Else, let sep be ? ToString(separator).
const sep: String =
@@ -542,7 +536,7 @@ namespace array_join {
// the normal join algorithm.
if (len > 0 && JoinStackPushInline(o)) {
try {
- const result: Object =
+ const result: JSAny =
ArrayJoin<T>(useToLocaleString, o, sep, len, locales, options);
JoinStackPopInline(o);
return result;
@@ -557,9 +551,9 @@ namespace array_join {
// https://tc39.github.io/ecma262/#sec-array.prototype.join
transitioning javascript builtin
- ArrayPrototypeJoin(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
- const separator: Object = arguments[0];
+ ArrayPrototypeJoin(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
+ const separator: JSAny = arguments[0];
// 1. Let O be ? ToObject(this value).
const o: JSReceiver = ToObject_Inline(context, receiver);
@@ -577,9 +571,9 @@ namespace array_join {
// https://tc39.github.io/ecma262/#sec-array.prototype.tolocalestring
transitioning javascript builtin ArrayPrototypeToLocaleString(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const locales: Object = arguments[0];
- const options: Object = arguments[1];
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const locales: JSAny = arguments[0];
+ const options: JSAny = arguments[1];
// 1. Let O be ? ToObject(this value).
const o: JSReceiver = ToObject_Inline(context, receiver);
@@ -597,12 +591,12 @@ namespace array_join {
// https://tc39.github.io/ecma262/#sec-array.prototype.tostring
transitioning javascript builtin ArrayPrototypeToString(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
// 1. Let array be ? ToObject(this value).
const array: JSReceiver = ToObject_Inline(context, receiver);
// 2. Let func be ? Get(array, "join").
- const prop: Object = GetProperty(array, 'join');
+ const prop: JSAny = GetProperty(array, 'join');
try {
// 3. If IsCallable(func) is false, let func be the intrinsic function
// %ObjProto_toString%.
@@ -618,8 +612,8 @@ namespace array_join {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.join
transitioning javascript builtin TypedArrayPrototypeJoin(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const separator: Object = arguments[0];
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const separator: JSAny = arguments[0];
// Spec: ValidateTypedArray is applied to the this value prior to evaluating
// the algorithm.
@@ -633,9 +627,9 @@ namespace array_join {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tolocalestring
transitioning javascript builtin TypedArrayPrototypeToLocaleString(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const locales: Object = arguments[0];
- const options: Object = arguments[1];
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const locales: JSAny = arguments[0];
+ const options: JSAny = arguments[1];
// Spec: ValidateTypedArray is applied to the this value prior to evaluating
// the algorithm.
diff --git a/deps/v8/src/builtins/array-lastindexof.tq b/deps/v8/src/builtins/array-lastindexof.tq
index 5ebc451e43..7765eff682 100644
--- a/deps/v8/src/builtins/array-lastindexof.tq
+++ b/deps/v8/src/builtins/array-lastindexof.tq
@@ -4,20 +4,20 @@
namespace array_lastindexof {
macro LoadWithHoleCheck<Elements: type>(
- elements: FixedArrayBase, index: Smi): Object
+ elements: FixedArrayBase, index: Smi): JSAny
labels IfHole;
LoadWithHoleCheck<FixedArray>(implicit context: Context)(
- elements: FixedArrayBase, index: Smi): Object
+ elements: FixedArrayBase, index: Smi): JSAny
labels IfHole {
const elements: FixedArray = UnsafeCast<FixedArray>(elements);
const element: Object = elements.objects[index];
if (element == TheHole) goto IfHole;
- return element;
+ return UnsafeCast<JSAny>(element);
}
LoadWithHoleCheck<FixedDoubleArray>(implicit context: Context)(
- elements: FixedArrayBase, index: Smi): Object
+ elements: FixedArrayBase, index: Smi): JSAny
labels IfHole {
const elements: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements);
const element: float64 = LoadDoubleWithHoleCheck(elements, index)
@@ -26,7 +26,7 @@ namespace array_lastindexof {
}
macro FastArrayLastIndexOf<Elements: type>(
- context: Context, array: JSArray, from: Smi, searchElement: Object): Smi {
+ context: Context, array: JSArray, from: Smi, searchElement: JSAny): Smi {
const elements: FixedArrayBase = array.elements;
let k: Smi = from;
@@ -40,7 +40,7 @@ namespace array_lastindexof {
while (k >= 0) {
try {
- const element: Object = LoadWithHoleCheck<Elements>(elements, k)
+ const element: JSAny = LoadWithHoleCheck<Elements>(elements, k)
otherwise Hole;
const same: Boolean = StrictEqual(searchElement, element);
@@ -80,8 +80,8 @@ namespace array_lastindexof {
}
macro TryFastArrayLastIndexOf(
- context: Context, receiver: JSReceiver, searchElement: Object,
- from: Number): Object
+ context: Context, receiver: JSReceiver, searchElement: JSAny,
+ from: Number): JSAny
labels Slow {
const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
const length: Smi = array.length;
@@ -99,8 +99,8 @@ namespace array_lastindexof {
}
transitioning macro GenericArrayLastIndexOf(
- context: Context, object: JSReceiver, searchElement: Object,
- from: Number): Object {
+ context: Context, object: JSReceiver, searchElement: JSAny,
+ from: Number): JSAny {
let k: Number = from;
// 7. Repeat, while k >= 0.
@@ -111,7 +111,7 @@ namespace array_lastindexof {
// b. If kPresent is true, then.
if (kPresent == True) {
// i. Let elementK be ? Get(O, ! ToString(k)).
- const element: Object = GetProperty(object, k);
+ const element: JSAny = GetProperty(object, k);
// ii. Let same be the result of performing Strict Equality Comparison
// searchElement === elementK.
@@ -131,7 +131,7 @@ namespace array_lastindexof {
// https://tc39.github.io/ecma262/#sec-array.prototype.lastIndexOf
transitioning javascript builtin ArrayPrototypeLastIndexOf(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
// 1. Let O be ? ToObject(this value).
const object: JSReceiver = ToObject_Inline(context, receiver);
@@ -144,7 +144,7 @@ namespace array_lastindexof {
// Step 4 - 6.
const from: Number = GetFromIndex(context, length, arguments);
- const searchElement: Object = arguments[0];
+ const searchElement: JSAny = arguments[0];
try {
return TryFastArrayLastIndexOf(context, object, searchElement, from)
diff --git a/deps/v8/src/builtins/array-map.tq b/deps/v8/src/builtins/array-map.tq
index dda569c682..c4b0e8a358 100644
--- a/deps/v8/src/builtins/array-map.tq
+++ b/deps/v8/src/builtins/array-map.tq
@@ -5,15 +5,15 @@
namespace array_map {
transitioning javascript builtin
ArrayMapLoopEagerDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, array: Object, initialK: Object,
- length: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny,
+ length: JSAny): JSAny {
// All continuation points in the optimized filter implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -28,9 +28,9 @@ namespace array_map {
transitioning javascript builtin
ArrayMapLoopLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, array: Object, initialK: Object,
- length: Object, result: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny,
+ length: JSAny, result: JSAny): JSAny {
// All continuation points in the optimized filter implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -57,9 +57,9 @@ namespace array_map {
}
transitioning builtin ArrayMapLoopContinuation(implicit context: Context)(
- _receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
+ _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny,
array: JSReceiver, o: JSReceiver, initialK: Number,
- length: Number): Object {
+ length: Number): JSAny {
// 6. Let k be 0.
// 7. Repeat, while k < len
for (let k: Number = initialK; k < length; k++) {
@@ -73,10 +73,10 @@ namespace array_map {
// 7c. If kPresent is true, then:
if (kPresent == True) {
// i. Let kValue be ? Get(O, Pk).
- const kValue: Object = GetProperty(o, k);
+ const kValue: JSAny = GetProperty(o, k);
// ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
- const mappedValue: Object =
+ const mappedValue: JSAny =
Call(context, callbackfn, thisArg, kValue, k, o);
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
@@ -127,12 +127,12 @@ namespace array_map {
SmiUntag(length), kAllowLargeObjectAllocation);
a = NewJSArray(map, this.fixedArray);
for (let i: Smi = 0; i < validLength; i++) {
- typeswitch (this.fixedArray.objects[i]) {
+ typeswitch (
+ UnsafeCast<(Number | TheHole)>(this.fixedArray.objects[i])) {
case (n: Number): {
elements.floats[i] = Convert<float64>(n);
}
- case (h: HeapObject): {
- assert(h == TheHole);
+ case (TheHole): {
}
}
}
@@ -147,7 +147,7 @@ namespace array_map {
return a;
}
- StoreResult(implicit context: Context)(index: Smi, result: Object) {
+ StoreResult(implicit context: Context)(index: Smi, result: JSAny) {
typeswitch (result) {
case (s: Smi): {
this.fixedArray.objects[index] = s;
@@ -156,7 +156,7 @@ namespace array_map {
this.onlySmis = false;
this.fixedArray.objects[index] = s;
}
- case (s: HeapObject): {
+ case (s: JSAnyNotNumber): {
this.onlySmis = false;
this.onlyNumbers = false;
this.fixedArray.objects[index] = s;
@@ -185,7 +185,7 @@ namespace array_map {
transitioning macro FastArrayMap(implicit context: Context)(
fastO: FastJSArrayForRead, len: Smi, callbackfn: Callable,
- thisArg: Object): JSArray
+ thisArg: JSAny): JSArray
labels Bailout(JSArray, Smi) {
let k: Smi = 0;
let fastOW = NewFastJSArrayForReadWitness(fastO);
@@ -201,9 +201,9 @@ namespace array_map {
if (k >= fastOW.Get().length) goto PrepareBailout(k);
try {
- const value: Object = fastOW.LoadElementNoHole(k)
+ const value: JSAny = fastOW.LoadElementNoHole(k)
otherwise FoundHole;
- const result: Object =
+ const result: JSAny =
Call(context, callbackfn, thisArg, value, k, fastOW.Get());
vector.StoreResult(k, result);
}
@@ -224,8 +224,7 @@ namespace array_map {
// https://tc39.github.io/ecma262/#sec-array.prototype.map
transitioning javascript builtin
- ArrayMap(js-implicit context: Context, receiver: Object)(...arguments):
- Object {
+ ArrayMap(js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
try {
RequireObjectCoercible(receiver, 'Array.prototype.map');
@@ -241,7 +240,7 @@ namespace array_map {
const callbackfn = Cast<Callable>(arguments[0]) otherwise TypeError;
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
- const thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
+ const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
let array: JSReceiver;
let k: Number = 0;
diff --git a/deps/v8/src/builtins/array-of.tq b/deps/v8/src/builtins/array-of.tq
index 7293318625..ceb9edff63 100644
--- a/deps/v8/src/builtins/array-of.tq
+++ b/deps/v8/src/builtins/array-of.tq
@@ -5,8 +5,7 @@
namespace array_of {
// https://tc39.github.io/ecma262/#sec-array.of
transitioning javascript builtin
- ArrayOf(js-implicit context: Context, receiver: Object)(...arguments):
- Object {
+ ArrayOf(js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
// 1. Let len be the actual number of arguments passed to this function.
const len: Smi = Convert<Smi>(arguments.length);
@@ -14,7 +13,7 @@ namespace array_of {
const items: Arguments = arguments;
// 3. Let C be the this value.
- const c: Object = receiver;
+ const c: JSAny = receiver;
let a: JSReceiver;
@@ -24,7 +23,7 @@ namespace array_of {
// a. Let A be ? Construct(C, « len »).
a = Construct(c, len);
}
- case (Object): {
+ case (JSAny): {
// a. Let A be ? ArrayCreate(len).
a = ArrayCreate(len);
}
@@ -36,7 +35,7 @@ namespace array_of {
// 7. Repeat, while k < len
while (k < len) {
// a. Let kValue be items[k].
- const kValue: Object = items[Convert<intptr>(k)];
+ const kValue: JSAny = items[Convert<intptr>(k)];
// b. Let Pk be ! ToString(k).
// c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue).
diff --git a/deps/v8/src/builtins/array-reduce-right.tq b/deps/v8/src/builtins/array-reduce-right.tq
index b1aa71b85b..ae5ca99d3d 100644
--- a/deps/v8/src/builtins/array-reduce-right.tq
+++ b/deps/v8/src/builtins/array-reduce-right.tq
@@ -6,13 +6,13 @@ namespace array {
transitioning javascript builtin
ArrayReduceRightPreLoopEagerDeoptContinuation(
js-implicit context: Context,
- receiver: Object)(callback: Object, length: Object): Object {
+ receiver: JSAny)(callback: JSAny, length: JSAny): JSAny {
// All continuation points in the optimized every implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -27,15 +27,15 @@ namespace array {
transitioning javascript builtin
ArrayReduceRightLoopEagerDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, initialK: Object, length: Object,
- accumulator: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, initialK: JSAny, length: JSAny,
+ accumulator: JSAny): JSAny {
// All continuation points in the optimized every implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -48,9 +48,8 @@ namespace array {
transitioning javascript builtin
ArrayReduceRightLoopLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, initialK: Object, length: Object,
- result: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, initialK: JSAny, length: JSAny, result: JSAny): JSAny {
// All continuation points in the optimized every implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -67,8 +66,9 @@ namespace array {
transitioning builtin ArrayReduceRightLoopContinuation(implicit context:
Context)(
- _receiver: JSReceiver, callbackfn: Callable, initialAccumulator: Object,
- o: JSReceiver, initialK: Number, _length: Number): Object {
+ _receiver: JSReceiver, callbackfn: Callable,
+ initialAccumulator: JSAny | TheHole, o: JSReceiver, initialK: Number,
+ _length: Number): JSAny {
let accumulator = initialAccumulator;
// 8b and 9. Repeat, while k >= 0
@@ -83,16 +83,20 @@ namespace array {
// 8b iii and 9c. If kPresent is true, then
if (present == True) {
// 8b iii and 9c i. Let kValue be ? Get(O, Pk).
- const value: Object = GetProperty(o, k);
-
- if (accumulator == TheHole) {
- // 8b iii 1.
- accumulator = value;
- } else {
- // 9c. ii. Set accumulator to ? Call(callbackfn, undefined,
- // <accumulator, kValue, k, O>).
- accumulator =
- Call(context, callbackfn, Undefined, accumulator, value, k, o);
+ const value: JSAny = GetProperty(o, k);
+
+ typeswitch (accumulator) {
+ case (TheHole): {
+ // 8b iii 1.
+ accumulator = value;
+ }
+ case (accumulatorNotHole: JSAny): {
+ // 9c. ii. Set accumulator to ? Call(callbackfn, undefined,
+ // <accumulator, kValue, k, O>).
+ accumulator = Call(
+ context, callbackfn, Undefined, accumulatorNotHole, value, k,
+ o);
+ }
}
}
@@ -102,16 +106,20 @@ namespace array {
// 8c. if kPresent is false, throw a TypeError exception.
// If the accumulator is discovered with the sentinel hole value,
// this means kPresent is false.
- if (accumulator == TheHole) {
- ThrowTypeError(kReduceNoInitial, 'Array.prototype.reduceRight');
+ typeswitch (accumulator) {
+ case (TheHole): {
+ ThrowTypeError(kReduceNoInitial, 'Array.prototype.reduceRight');
+ }
+ case (accumulator: JSAny): {
+ return accumulator;
+ }
}
- return accumulator;
}
transitioning macro FastArrayReduceRight(implicit context: Context)(
o: JSReceiver, len: Number, callbackfn: Callable,
- initialAccumulator: Object): Object
- labels Bailout(Number, Object) {
+ initialAccumulator: JSAny | TheHole): JSAny
+ labels Bailout(Number, JSAny | TheHole) {
let accumulator = initialAccumulator;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(len - 1, accumulator);
const fastO = Cast<FastJSArrayForRead>(o)
@@ -125,25 +133,32 @@ namespace array {
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastOW.Get().length) goto Bailout(k, accumulator);
- const value: Object = fastOW.LoadElementNoHole(k) otherwise continue;
- if (accumulator == TheHole) {
- accumulator = value;
- } else {
- accumulator = Call(
- context, callbackfn, Undefined, accumulator, value, k,
- fastOW.Get());
+ const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue;
+ typeswitch (accumulator) {
+ case (TheHole): {
+ accumulator = value;
+ }
+ case (accumulatorNotHole: JSAny): {
+ accumulator = Call(
+ context, callbackfn, Undefined, accumulatorNotHole, value, k,
+ fastOW.Get());
+ }
}
}
- if (accumulator == TheHole) {
- ThrowTypeError(kReduceNoInitial, 'Array.prototype.reduceRight');
+ typeswitch (accumulator) {
+ case (TheHole): {
+ ThrowTypeError(kReduceNoInitial, 'Array.prototype.reduceRight');
+ }
+ case (accumulator: JSAny): {
+ return accumulator;
+ }
}
- return accumulator;
}
// https://tc39.github.io/ecma262/#sec-array.prototype.reduceRight
transitioning javascript builtin
- ArrayReduceRight(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ ArrayReduceRight(js-implicit context: Context, receiver: JSAny)(...arguments):
+ JSAny {
try {
RequireObjectCoercible(receiver, 'Array.prototype.reduceRight');
@@ -163,14 +178,14 @@ namespace array {
// exception. (This case is handled at the end of
// ArrayReduceRightLoopContinuation).
- const initialValue: Object =
+ const initialValue: JSAny | TheHole =
arguments.length > 1 ? arguments[1] : TheHole;
try {
return FastArrayReduceRight(o, len, callbackfn, initialValue)
otherwise Bailout;
}
- label Bailout(value: Number, accumulator: Object) {
+ label Bailout(value: Number, accumulator: JSAny | TheHole) {
return ArrayReduceRightLoopContinuation(
o, callbackfn, accumulator, o, value, len);
}
diff --git a/deps/v8/src/builtins/array-reduce.tq b/deps/v8/src/builtins/array-reduce.tq
index a5f6feb9cc..1021c48642 100644
--- a/deps/v8/src/builtins/array-reduce.tq
+++ b/deps/v8/src/builtins/array-reduce.tq
@@ -6,13 +6,13 @@ namespace array {
transitioning javascript builtin
ArrayReducePreLoopEagerDeoptContinuation(
js-implicit context: Context,
- receiver: Object)(callback: Object, length: Object): Object {
+ receiver: JSAny)(callback: JSAny, length: JSAny): JSAny {
// All continuation points in the optimized every implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -27,15 +27,15 @@ namespace array {
transitioning javascript builtin
ArrayReduceLoopEagerDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, initialK: Object, length: Object,
- accumulator: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, initialK: JSAny, length: JSAny,
+ accumulator: JSAny): JSAny {
// All continuation points in the optimized every implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -48,9 +48,8 @@ namespace array {
transitioning javascript builtin
ArrayReduceLoopLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, initialK: Object, length: Object,
- result: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, initialK: JSAny, length: JSAny, result: JSAny): JSAny {
// All continuation points in the optimized every implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -66,8 +65,9 @@ namespace array {
}
transitioning builtin ArrayReduceLoopContinuation(implicit context: Context)(
- _receiver: JSReceiver, callbackfn: Callable, initialAccumulator: Object,
- o: JSReceiver, initialK: Number, length: Number): Object {
+ _receiver: JSReceiver, callbackfn: Callable,
+ initialAccumulator: JSAny | TheHole, o: JSReceiver, initialK: Number,
+ length: Number): JSAny {
let accumulator = initialAccumulator;
// 8b and 9. Repeat, while k < len
@@ -82,16 +82,20 @@ namespace array {
// 6c. If kPresent is true, then
if (present == True) {
// 6c. i. Let kValue be ? Get(O, Pk).
- const value: Object = GetProperty(o, k);
-
- if (accumulator == TheHole) {
- // 8b.
- accumulator = value;
- } else {
- // 9c. ii. Set accumulator to ? Call(callbackfn, undefined,
- // <accumulator, kValue, k, O>).
- accumulator =
- Call(context, callbackfn, Undefined, accumulator, value, k, o);
+ const value: JSAny = GetProperty(o, k);
+
+ typeswitch (accumulator) {
+ case (TheHole): {
+ // 8b.
+ accumulator = value;
+ }
+ case (accumulatorNotHole: JSAny): {
+ // 9c. ii. Set accumulator to ? Call(callbackfn, undefined,
+ // <accumulator, kValue, k, O>).
+ accumulator = Call(
+ context, callbackfn, Undefined, accumulatorNotHole, value, k,
+ o);
+ }
}
}
@@ -101,16 +105,20 @@ namespace array {
// 8c. if kPresent is false, throw a TypeError exception.
// If the accumulator is discovered with the sentinel hole value,
// this means kPresent is false.
- if (accumulator == TheHole) {
- ThrowTypeError(kReduceNoInitial, 'Array.prototype.reduce');
+ typeswitch (accumulator) {
+ case (TheHole): {
+ ThrowTypeError(kReduceNoInitial, 'Array.prototype.reduce');
+ }
+ case (accumulator: JSAny): {
+ return accumulator;
+ }
}
- return accumulator;
}
transitioning macro FastArrayReduce(implicit context: Context)(
o: JSReceiver, len: Number, callbackfn: Callable,
- initialAccumulator: Object): Object
- labels Bailout(Number, Object) {
+ initialAccumulator: JSAny | TheHole): JSAny
+ labels Bailout(Number, JSAny | TheHole) {
const k = 0;
let accumulator = initialAccumulator;
Cast<Smi>(len) otherwise goto Bailout(k, accumulator);
@@ -125,25 +133,32 @@ namespace array {
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastOW.Get().length) goto Bailout(k, accumulator);
- const value: Object = fastOW.LoadElementNoHole(k) otherwise continue;
- if (accumulator == TheHole) {
- accumulator = value;
- } else {
- accumulator = Call(
- context, callbackfn, Undefined, accumulator, value, k,
- fastOW.Get());
+ const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue;
+ typeswitch (accumulator) {
+ case (TheHole): {
+ accumulator = value;
+ }
+ case (accumulatorNotHole: JSAny): {
+ accumulator = Call(
+ context, callbackfn, Undefined, accumulatorNotHole, value, k,
+ fastOW.Get());
+ }
}
}
- if (accumulator == TheHole) {
- ThrowTypeError(kReduceNoInitial, 'Array.prototype.reduce');
+ typeswitch (accumulator) {
+ case (TheHole): {
+ ThrowTypeError(kReduceNoInitial, 'Array.prototype.reduce');
+ }
+ case (accumulator: JSAny): {
+ return accumulator;
+ }
}
- return accumulator;
}
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
transitioning javascript builtin
- ArrayReduce(js-implicit context: Context, receiver: Object)(...arguments):
- Object {
+ ArrayReduce(js-implicit context: Context, receiver: JSAny)(...arguments):
+ JSAny {
try {
RequireObjectCoercible(receiver, 'Array.prototype.reduce');
@@ -163,14 +178,14 @@ namespace array {
// exception. (This case is handled at the end of
// ArrayReduceLoopContinuation).
- const initialValue: Object =
+ const initialValue: JSAny | TheHole =
arguments.length > 1 ? arguments[1] : TheHole;
try {
return FastArrayReduce(o, len, callbackfn, initialValue)
otherwise Bailout;
}
- label Bailout(value: Number, accumulator: Object) {
+ label Bailout(value: Number, accumulator: JSAny | TheHole) {
return ArrayReduceLoopContinuation(
o, callbackfn, accumulator, o, value, len);
}
diff --git a/deps/v8/src/builtins/array-reverse.tq b/deps/v8/src/builtins/array-reverse.tq
index 82d2e6b605..5e9d3a00f3 100644
--- a/deps/v8/src/builtins/array-reverse.tq
+++ b/deps/v8/src/builtins/array-reverse.tq
@@ -12,10 +12,10 @@ namespace array_reverse {
return UnsafeCast<Smi>(elements.objects[index]);
}
- LoadElement<array::FastPackedObjectElements, Object>(
- implicit context: Context)(elements: FixedArrayBase, index: Smi): Object {
+ LoadElement<array::FastPackedObjectElements, JSAny>(
+ implicit context: Context)(elements: FixedArrayBase, index: Smi): JSAny {
const elements: FixedArray = UnsafeCast<FixedArray>(elements);
- return elements.objects[index];
+ return UnsafeCast<JSAny>(elements.objects[index]);
}
LoadElement<array::FastPackedDoubleElements, float64>(
@@ -38,9 +38,9 @@ namespace array_reverse {
StoreFixedArrayElement(elems, index, value, SKIP_WRITE_BARRIER);
}
- StoreElement<array::FastPackedObjectElements, Object>(
+ StoreElement<array::FastPackedObjectElements, JSAny>(
implicit context:
- Context)(elements: FixedArrayBase, index: Smi, value: Object) {
+ Context)(elements: FixedArrayBase, index: Smi, value: JSAny) {
const elements: FixedArray = UnsafeCast<FixedArray>(elements);
elements.objects[index] = value;
}
@@ -70,8 +70,8 @@ namespace array_reverse {
}
}
- transitioning macro GenericArrayReverse(context: Context, receiver: Object):
- Object {
+ transitioning macro GenericArrayReverse(context: Context, receiver: JSAny):
+ JSAny {
// 1. Let O be ? ToObject(this value).
const object: JSReceiver = ToObject_Inline(context, receiver);
@@ -89,8 +89,8 @@ namespace array_reverse {
let upper: Number = length - 1;
while (lower < upper) {
- let lowerValue: Object = Undefined;
- let upperValue: Object = Undefined;
+ let lowerValue: JSAny = Undefined;
+ let upperValue: JSAny = Undefined;
// b. Let upperP be ! ToString(upper).
// c. Let lowerP be ! ToString(lower).
@@ -142,7 +142,7 @@ namespace array_reverse {
return object;
}
- macro TryFastPackedArrayReverse(implicit context: Context)(receiver: Object)
+ macro TryFastPackedArrayReverse(implicit context: Context)(receiver: JSAny)
labels Slow {
const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
@@ -153,7 +153,7 @@ namespace array_reverse {
array.elements, array.length);
} else if (kind == PACKED_ELEMENTS) {
array::EnsureWriteableFastElements(array);
- FastPackedArrayReverse<array::FastPackedObjectElements, Object>(
+ FastPackedArrayReverse<array::FastPackedObjectElements, JSAny>(
array.elements, array.length);
} else if (kind == PACKED_DOUBLE_ELEMENTS) {
FastPackedArrayReverse<array::FastPackedDoubleElements, float64>(
@@ -165,7 +165,7 @@ namespace array_reverse {
// https://tc39.github.io/ecma262/#sec-array.prototype.reverse
transitioning javascript builtin ArrayPrototypeReverse(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
try {
TryFastPackedArrayReverse(receiver) otherwise Baseline;
return receiver;
diff --git a/deps/v8/src/builtins/array-shift.tq b/deps/v8/src/builtins/array-shift.tq
index 4dd82d7b88..48ffe3b487 100644
--- a/deps/v8/src/builtins/array-shift.tq
+++ b/deps/v8/src/builtins/array-shift.tq
@@ -3,11 +3,10 @@
// found in the LICENSE file.
namespace array_shift {
- extern builtin ArrayShift(Context, JSFunction, Object, int32);
+ extern builtin ArrayShift(Context, JSFunction, JSAny, int32): JSAny;
- macro TryFastArrayShift(implicit context: Context)(
- receiver: Object, arguments: Arguments): Object
- labels Slow {
+ macro TryFastArrayShift(implicit context: Context)(receiver: JSAny): JSAny
+ labels Slow, Runtime {
const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
let witness = NewFastJSArrayWitness(array);
@@ -17,35 +16,28 @@ namespace array_shift {
return Undefined;
}
- try {
- const newLength = array.length - 1;
+ const newLength = array.length - 1;
- // Check that we're not supposed to right-trim the backing store, as
- // implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
- if ((newLength + newLength + kMinAddedElementsCapacity) <
- array.elements.length) {
- goto Runtime;
- }
+ // Check that we're not supposed to right-trim the backing store, as
+ // implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
+ if ((newLength + newLength + kMinAddedElementsCapacity) <
+ array.elements.length) {
+ goto Runtime;
+ }
- // Check that we're not supposed to left-trim the backing store, as
- // implemented in elements.cc:FastElementsAccessor::MoveElements.
- if (newLength > kMaxCopyElements) goto Runtime;
+ // Check that we're not supposed to left-trim the backing store, as
+ // implemented in elements.cc:FastElementsAccessor::MoveElements.
+ if (newLength > kMaxCopyElements) goto Runtime;
- const result = witness.LoadElementOrUndefined(0);
- witness.ChangeLength(newLength);
- witness.MoveElements(0, 1, Convert<intptr>(newLength));
- witness.StoreHole(newLength);
- return result;
- }
- label Runtime {
- tail ArrayShift(
- context, LoadTargetFromFrame(), Undefined,
- Convert<int32>(arguments.length));
- }
+ const result = witness.LoadElementOrUndefined(0);
+ witness.ChangeLength(newLength);
+ witness.MoveElements(0, 1, Convert<intptr>(newLength));
+ witness.StoreHole(newLength);
+ return result;
}
transitioning macro GenericArrayShift(implicit context:
- Context)(receiver: Object): Object {
+ Context)(receiver: JSAny): JSAny {
// 1. Let O be ? ToObject(this value).
const object: JSReceiver = ToObject_Inline(context, receiver);
@@ -78,7 +70,7 @@ namespace array_shift {
// d. If fromPresent is true, then
if (fromPresent == True) {
// i. Let fromVal be ? Get(O, from).
- const fromValue: Object = GetProperty(object, from);
+ const fromValue: JSAny = GetProperty(object, from);
// ii. Perform ? Set(O, to, fromValue, true).
SetProperty(object, to, fromValue);
@@ -103,12 +95,17 @@ namespace array_shift {
// https://tc39.github.io/ecma262/#sec-array.prototype.shift
transitioning javascript builtin ArrayPrototypeShift(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
try {
- return TryFastArrayShift(receiver, arguments) otherwise Slow;
+ return TryFastArrayShift(receiver) otherwise Slow, Runtime;
}
label Slow {
return GenericArrayShift(receiver);
}
+ label Runtime {
+ tail ArrayShift(
+ context, LoadTargetFromFrame(), Undefined,
+ Convert<int32>(arguments.length));
+ }
}
}
diff --git a/deps/v8/src/builtins/array-slice.tq b/deps/v8/src/builtins/array-slice.tq
index c3a6ac75cb..57ddc8dea1 100644
--- a/deps/v8/src/builtins/array-slice.tq
+++ b/deps/v8/src/builtins/array-slice.tq
@@ -4,7 +4,7 @@
namespace array_slice {
macro HandleSimpleArgumentsSlice(
- context: Context, args: JSArgumentsObjectWithLength, start: Smi,
+ context: NativeContext, args: JSArgumentsObjectWithLength, start: Smi,
count: Smi): JSArray
labels Bailout {
// If the resulting array doesn't fit in new space, use the slow path.
@@ -27,7 +27,7 @@ namespace array_slice {
}
macro HandleFastAliasedSloppyArgumentsSlice(
- context: Context, args: JSArgumentsObjectWithLength, start: Smi,
+ context: NativeContext, args: JSArgumentsObjectWithLength, start: Smi,
count: Smi): JSArray
labels Bailout {
// If the resulting array doesn't fit in new space, use the slow path.
@@ -63,9 +63,9 @@ namespace array_slice {
for (let current: Smi = start; current < to; ++current) {
const e: Object =
sloppyElements.objects[current + kSloppyArgumentsParameterMapStart];
- const newElement: Object = e != TheHole ?
- argumentsContext[UnsafeCast<Smi>(e)] :
- unmappedElements.objects[current];
+ const newElement: JSAny = UnsafeCast<JSAny>(
+ e != TheHole ? argumentsContext[UnsafeCast<Smi>(e)] :
+ unmappedElements.objects[current]);
// It is safe to skip the write barrier here because resultElements was
// allocated together with result in a folded allocation.
// TODO(tebbi): The verification of this fails at the moment due to
@@ -86,7 +86,7 @@ namespace array_slice {
}
macro HandleFastSlice(
- context: Context, o: Object, startNumber: Number,
+ context: NativeContext, o: JSAny, startNumber: Number,
countNumber: Number): JSArray
labels Bailout {
const start: Smi = Cast<Smi>(startNumber) otherwise Bailout;
@@ -114,7 +114,7 @@ namespace array_slice {
otherwise Bailout;
}
}
- case (Object): {
+ case (JSAny): {
}
}
goto Bailout;
@@ -122,15 +122,15 @@ namespace array_slice {
// https://tc39.github.io/ecma262/#sec-array.prototype.slice
transitioning javascript builtin
- ArrayPrototypeSlice(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ ArrayPrototypeSlice(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
// Handle array cloning case if the receiver is a fast array.
if (arguments.length == 0) {
typeswitch (receiver) {
case (a: FastJSArrayForCopy): {
return CloneFastJSArray(context, a);
}
- case (Object): {
+ case (JSAny): {
}
}
}
@@ -142,7 +142,7 @@ namespace array_slice {
const len: Number = GetLengthProperty(o);
// 3. Let relativeStart be ? ToInteger(start).
- const start: Object = arguments[0];
+ const start: JSAny = arguments[0];
const relativeStart: Number = ToInteger_Inline(context, start);
// 4. If relativeStart < 0, let k be max((len + relativeStart), 0);
@@ -152,7 +152,7 @@ namespace array_slice {
// 5. If end is undefined, let relativeEnd be len;
// else let relativeEnd be ? ToInteger(end).
- const end: Object = arguments[1];
+ const end: JSAny = arguments[1];
const relativeEnd: Number =
end == Undefined ? len : ToInteger_Inline(context, end);
@@ -172,7 +172,8 @@ namespace array_slice {
assert(count <= len);
try {
- return HandleFastSlice(context, o, k, count) otherwise Slow;
+ return HandleFastSlice(UnsafeCast<NativeContext>(context), o, k, count)
+ otherwise Slow;
}
label Slow {}
@@ -193,7 +194,7 @@ namespace array_slice {
// c. If kPresent is true, then
if (fromPresent == True) {
// i. Let kValue be ? Get(O, Pk).
- const kValue: Object = GetProperty(o, pK);
+ const kValue: JSAny = GetProperty(o, pK);
// ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(n), kValue).
FastCreateDataProperty(a, n, kValue);
diff --git a/deps/v8/src/builtins/array-some.tq b/deps/v8/src/builtins/array-some.tq
index a30af4e47a..5d93dd0b72 100644
--- a/deps/v8/src/builtins/array-some.tq
+++ b/deps/v8/src/builtins/array-some.tq
@@ -5,15 +5,14 @@
namespace array {
transitioning javascript builtin
ArraySomeLoopEagerDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object,
- length: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny {
// All continuation points in the optimized some implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
//
// Also, this great mass of casts is necessary because the signature
- // of Torque javascript builtins requires Object type for all parameters
+ // of Torque javascript builtins requires JSAny type for all parameters
// other than {context}.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable;
@@ -27,9 +26,9 @@ namespace array {
transitioning javascript builtin
ArraySomeLoopLazyDeoptContinuation(
- js-implicit context: Context, receiver: Object)(
- callback: Object, thisArg: Object, initialK: Object, length: Object,
- result: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(
+ callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny,
+ result: JSAny): JSAny {
// All continuation points in the optimized some implementation are
// after the ToObject(O) call that ensures we are dealing with a
// JSReceiver.
@@ -53,9 +52,9 @@ namespace array {
}
transitioning builtin ArraySomeLoopContinuation(implicit context: Context)(
- _receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
- _array: Object, o: JSReceiver, initialK: Number, length: Number,
- _initialTo: Object): Object {
+ _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny,
+ _array: JSAny, o: JSReceiver, initialK: Number, length: Number,
+ _initialTo: JSAny): JSAny {
// 5. Let k be 0.
// 6. Repeat, while k < len
for (let k: Number = initialK; k < length; k++) {
@@ -69,10 +68,10 @@ namespace array {
// 6c. If kPresent is true, then
if (kPresent == True) {
// 6c. i. Let kValue be ? Get(O, Pk).
- const kValue: Object = GetProperty(o, k);
+ const kValue: JSAny = GetProperty(o, k);
// 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
- const result: Object = Call(context, callbackfn, thisArg, kValue, k, o);
+ const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o);
// iii. If selected is true, then...
if (ToBoolean(result)) {
@@ -86,7 +85,7 @@ namespace array {
}
transitioning macro FastArraySome(implicit context: Context)(
- o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
+ o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny
labels Bailout(Smi) {
let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
@@ -99,8 +98,8 @@ namespace array {
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastOW.Get().length) goto Bailout(k);
- const value: Object = fastOW.LoadElementNoHole(k) otherwise continue;
- const result: Object =
+ const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue;
+ const result: JSAny =
Call(context, callbackfn, thisArg, value, k, fastOW.Get());
if (ToBoolean(result)) {
return True;
@@ -111,8 +110,8 @@ namespace array {
// https://tc39.github.io/ecma262/#sec-array.prototype.some
transitioning javascript builtin
- ArraySome(js-implicit context: Context, receiver: Object)(...arguments):
- Object {
+ ArraySome(js-implicit context: Context, receiver: JSAny)(...arguments):
+ JSAny {
try {
RequireObjectCoercible(receiver, 'Array.prototype.some');
@@ -129,7 +128,7 @@ namespace array {
const callbackfn = Cast<Callable>(arguments[0]) otherwise TypeError;
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
- const thisArg: Object = arguments.length > 1 ? arguments[1] : Undefined;
+ const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
// Special cases.
try {
diff --git a/deps/v8/src/builtins/array-splice.tq b/deps/v8/src/builtins/array-splice.tq
index 3b65bb03d4..04885dbb9c 100644
--- a/deps/v8/src/builtins/array-splice.tq
+++ b/deps/v8/src/builtins/array-splice.tq
@@ -95,7 +95,7 @@ namespace array_splice {
const typedNewElements: FixedArrayType =
UnsafeCast<FixedArrayType>(a.elements);
for (let i: intptr = 2; i < args.length; ++i) {
- const e: Object = args[i];
+ const e: JSAny = args[i];
// The argument elements were already validated to be an appropriate
// {ElementType} to store in {FixedArrayType}.
typedNewElements[k++] = UnsafeCast<ElementType>(e);
@@ -109,7 +109,7 @@ namespace array_splice {
transitioning macro FastArraySplice(
context: Context, args: Arguments, o: JSReceiver,
originalLengthNumber: Number, actualStartNumber: Number, insertCount: Smi,
- actualDeleteCountNumber: Number): Object
+ actualDeleteCountNumber: Number): JSAny
labels Bailout {
const originalLength: Smi =
Cast<Smi>(originalLengthNumber) otherwise Bailout;
@@ -132,7 +132,7 @@ namespace array_splice {
const oldElementsKind: ElementsKind = elementsKind;
for (let i: intptr = 2; i < args.length; ++i) {
- const e: Object = args[i];
+ const e: JSAny = args[i];
if (IsFastSmiElementsKind(elementsKind)) {
if (TaggedIsNotSmi(e)) {
const heapObject: HeapObject = UnsafeCast<HeapObject>(e);
@@ -166,7 +166,7 @@ namespace array_splice {
}
if (IsFastSmiOrTaggedElementsKind(elementsKind)) {
- FastSplice<FixedArray, Object>(
+ FastSplice<FixedArray, JSAny>(
args, a, length, newLength, actualStart, insertCount,
actualDeleteCount);
} else {
@@ -180,7 +180,7 @@ namespace array_splice {
transitioning macro FillDeletedElementsArray(
context: Context, o: JSReceiver, actualStart: Number,
- actualDeleteCount: Number, a: JSReceiver): Object {
+ actualDeleteCount: Number, a: JSReceiver): JSAny {
// 10. Let k be 0.
let k: Number = 0;
@@ -195,7 +195,7 @@ namespace array_splice {
// c. If fromPresent is true, then
if (fromPresent == True) {
// i. Let fromValue be ? Get(O, from).
- const fromValue: Object = GetProperty(o, from);
+ const fromValue: JSAny = GetProperty(o, from);
// ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(k), fromValue).
FastCreateDataProperty(a, k, fromValue);
@@ -231,7 +231,7 @@ namespace array_splice {
// iv. If fromPresent is true, then
if (fromPresent == True) {
// 1. Let fromValue be ? Get(O, from).
- const fromValue: Object = GetProperty(o, from);
+ const fromValue: JSAny = GetProperty(o, from);
// 2. Perform ? Set(O, to, fromValue, true).
SetProperty(o, to, fromValue);
@@ -280,7 +280,7 @@ namespace array_splice {
// iv. If fromPresent is true, then
if (fromPresent == True) {
// 1. Let fromValue be ? Get(O, from).
- const fromValue: Object = GetProperty(o, from);
+ const fromValue: JSAny = GetProperty(o, from);
// 2. Perform ? Set(O, to, fromValue, true).
SetProperty(o, to, fromValue);
@@ -298,8 +298,7 @@ namespace array_splice {
transitioning macro SlowSplice(
context: Context, arguments: Arguments, o: JSReceiver, len: Number,
- actualStart: Number, insertCount: Smi,
- actualDeleteCount: Number): Object {
+ actualStart: Number, insertCount: Smi, actualDeleteCount: Number): JSAny {
// 9. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
const a: JSReceiver = ArraySpeciesCreate(context, o, actualDeleteCount);
const itemCount: Number = insertCount;
@@ -332,7 +331,7 @@ namespace array_splice {
// element.
if (arguments.length > 2) {
for (let i: intptr = 2; i < arguments.length; ++i) {
- const e: Object = arguments[i];
+ const e: JSAny = arguments[i];
// b. Perform ? Set(O, ! ToString(k), E, true).
SetProperty(o, k, e);
@@ -350,8 +349,8 @@ namespace array_splice {
// https://tc39.github.io/ecma262/#sec-array.prototype.splice
transitioning javascript builtin
- ArrayPrototypeSplice(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ ArrayPrototypeSplice(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
// 1. Let O be ? ToObject(this value).
const o: JSReceiver = ToObject(context, receiver);
@@ -359,7 +358,7 @@ namespace array_splice {
const len: Number = GetLengthProperty(o);
// 3. Let relativeStart be ? ToInteger(start).
- const start: Object = arguments[0];
+ const start: JSAny = arguments[0];
const relativeStart: Number = ToInteger_Inline(context, start);
// 4. If relativeStart < 0, let actualStart be max((len + relativeStart),
@@ -388,7 +387,7 @@ namespace array_splice {
// a. Let insertCount be the Number of actual arguments minus 2.
insertCount = Convert<Smi>(arguments.length) - 2;
// b. Let dc be ? ToInteger(deleteCount).
- const deleteCount: Object = arguments[1];
+ const deleteCount: JSAny = arguments[1];
const dc: Number = ToInteger_Inline(context, deleteCount);
// c. Let actualDeleteCount be min(max(dc, 0), len - actualStart).
actualDeleteCount = Min(Max(dc, 0), len - actualStart);
diff --git a/deps/v8/src/builtins/array-unshift.tq b/deps/v8/src/builtins/array-unshift.tq
index e685d520cd..422eee158d 100644
--- a/deps/v8/src/builtins/array-unshift.tq
+++ b/deps/v8/src/builtins/array-unshift.tq
@@ -3,25 +3,10 @@
// found in the LICENSE file.
namespace array_unshift {
- extern builtin ArrayUnshift(Context, JSFunction, Object, int32);
-
- macro TryFastArrayUnshift(
- context: Context, receiver: Object, arguments: Arguments): never
- labels Slow {
- const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
- array::EnsureWriteableFastElements(array);
-
- const map: Map = array.map;
- if (!IsExtensibleMap(map)) goto Slow;
- EnsureArrayLengthWritable(map) otherwise Slow;
-
- tail ArrayUnshift(
- context, LoadTargetFromFrame(), Undefined,
- Convert<int32>(arguments.length));
- }
+ extern builtin ArrayUnshift(Context, JSFunction, JSAny, int32): JSAny;
transitioning macro GenericArrayUnshift(
- context: Context, receiver: Object, arguments: Arguments): Number {
+ context: Context, receiver: JSAny, arguments: Arguments): Number {
// 1. Let O be ? ToObject(this value).
const object: JSReceiver = ToObject_Inline(context, receiver);
@@ -55,7 +40,7 @@ namespace array_unshift {
// iv. If fromPresent is true, then
if (fromPresent == True) {
// 1. Let fromValue be ? Get(O, from).
- const fromValue: Object = GetProperty(object, from);
+ const fromValue: JSAny = GetProperty(object, from);
// 2. Perform ? Set(O, to, fromValue, true).
SetProperty(object, to, fromValue);
@@ -93,11 +78,20 @@ namespace array_unshift {
// https://tc39.github.io/ecma262/#sec-array.prototype.unshift
transitioning javascript builtin ArrayPrototypeUnshift(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
try {
- TryFastArrayUnshift(context, receiver, arguments) otherwise Baseline;
+ const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
+ array::EnsureWriteableFastElements(array);
+
+ const map: Map = array.map;
+ if (!IsExtensibleMap(map)) goto Slow;
+ EnsureArrayLengthWritable(map) otherwise Slow;
+
+ tail ArrayUnshift(
+ context, LoadTargetFromFrame(), Undefined,
+ Convert<int32>(arguments.length));
}
- label Baseline {
+ label Slow {
return GenericArrayUnshift(context, receiver, arguments);
}
}
diff --git a/deps/v8/src/builtins/array.tq b/deps/v8/src/builtins/array.tq
index 7e044e086b..b9ae314c08 100644
--- a/deps/v8/src/builtins/array.tq
+++ b/deps/v8/src/builtins/array.tq
@@ -32,30 +32,15 @@ namespace array {
assert(array.elements.map != kCOWMap);
}
- macro IsJSArray(implicit context: Context)(o: Object): bool {
- typeswitch (o) {
- case (JSArray): {
- return true;
- }
- case (Object): {
- return false;
- }
- }
- }
-
- macro LoadElementOrUndefined(a: FixedArray, i: Smi): Object {
- const e: Object = a.objects[i];
- return e == TheHole ? Undefined : e;
+ macro LoadElementOrUndefined(implicit context:
+ Context)(a: FixedArray, i: Smi): JSAny {
+ const e = UnsafeCast<(JSAny | TheHole)>(a.objects[i]);
+ return ReplaceTheHoleWithUndefined(e);
}
macro LoadElementOrUndefined(a: FixedDoubleArray, i: Smi): NumberOrUndefined {
- try {
- const f: float64 = LoadDoubleWithHoleCheck(a, i) otherwise IfHole;
- return AllocateHeapNumberWithValue(f);
- }
- label IfHole {
- return Undefined;
- }
+ const f: float64 = LoadDoubleWithHoleCheck(a, i) otherwise return Undefined;
+ return AllocateHeapNumberWithValue(f);
}
macro StoreArrayHole(elements: FixedDoubleArray, k: Smi): void {
@@ -66,5 +51,5 @@ namespace array {
elements.objects[k] = TheHole;
}
- extern macro SetPropertyLength(implicit context: Context)(Object, Number);
+ extern macro SetPropertyLength(implicit context: Context)(JSAny, Number);
}
diff --git a/deps/v8/src/builtins/base.tq b/deps/v8/src/builtins/base.tq
index 07af1f441f..aa5d4cc50a 100644
--- a/deps/v8/src/builtins/base.tq
+++ b/deps/v8/src/builtins/base.tq
@@ -43,6 +43,29 @@ extern class HeapObject extends Tagged {
type Object = Smi | HeapObject;
+// Defined to coincide with https://tc39.es/ecma262/#sec-ispropertykey
+// Doesn't include PrivateSymbol.
+type PropertyKey = String | PublicSymbol;
+
+// TODO(tebbi): PrivateSymbol is only exposed to JavaScript through the debugger
+// API. We should reconsider this and try not to expose it at all. Then JSAny
+// would not need to contain it.
+
+// A JavaScript primitive value as defined in
+// https://tc39.es/ecma262/#sec-primitive-value.
+type JSPrimitive = Numeric | String | Symbol | Boolean |
+ Null | Undefined;
+
+// A user-exposed JavaScript value, as opposed to V8-internal values like
+// TheHole or FixedArray.
+type JSAny = JSReceiver | JSPrimitive;
+
+type JSAnyNotNumber = BigInt | String | Symbol | Boolean |
+ Null | Undefined | JSReceiver;
+
+// This is the intersection of JSAny and HeapObject.
+type JSAnyNotSmi = JSAnyNotNumber | HeapNumber;
+
type int32 generates 'TNode<Int32T>' constexpr 'int32_t';
type uint32 generates 'TNode<Uint32T>' constexpr 'uint32_t';
type int31 extends int32
@@ -56,6 +79,8 @@ type uint16 extends uint31
type int8 extends int16 generates 'TNode<Int8T>' constexpr 'int8_t';
type uint8 extends uint16
generates 'TNode<Uint8T>' constexpr 'uint8_t';
+type char8 extends int8 constexpr 'char';
+type char16 extends uint16 constexpr 'char16_t';
type int64 generates 'TNode<Int64T>' constexpr 'int64_t';
type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t';
type uintptr generates 'TNode<UintPtrT>' constexpr 'uintptr_t';
@@ -77,7 +102,7 @@ extern class Context extends HeapObject {
extension: Object;
native_context: Object;
}
-type NativeContext extends Context;
+type NativeContext extends Context generates 'TNode<NativeContext>';
@generateCppClass
extern class Oddball extends HeapObject {
@@ -97,6 +122,9 @@ type Numeric = Number | BigInt;
extern class Name extends HeapObject {
hash_field: uint32;
}
+// This is the same as Name, but with the information that there are no other
+// kinds of names.
+type AnyName = PrivateSymbol | PublicSymbol | String;
@generateCppClass
extern class Symbol extends Name {
@@ -104,6 +132,9 @@ extern class Symbol extends Name {
name: Object; // The print name of a symbol, or undefined if none.
}
+type PublicSymbol extends Symbol;
+type PrivateSymbol extends Symbol;
+
@abstract
@generateCppClass
extern class String extends Name {
@@ -136,9 +167,11 @@ extern class SeqString extends String {
}
@generateCppClass
extern class SeqOneByteString extends SeqString {
+ chars[length]: char8;
}
@generateCppClass
extern class SeqTwoByteString extends SeqString {
+ chars[length]: char16;
}
@generateCppClass
@@ -185,7 +218,6 @@ type DirectString extends String;
type RootIndex generates 'TNode<Int32T>' constexpr 'RootIndex';
@abstract
-@generateCppClass
extern class FixedArrayBase extends HeapObject {
length: Smi;
}
@@ -205,7 +237,7 @@ type LayoutDescriptor extends ByteArray
type TransitionArray extends WeakFixedArray
generates 'TNode<TransitionArray>';
-type InstanceType extends uint16 constexpr 'InstanceType';
+type InstanceType extends uint16 constexpr 'v8::internal::InstanceType';
extern class Map extends HeapObject {
instance_size_in_words: uint8;
@@ -388,8 +420,8 @@ extern class JSProxy extends JSReceiver {
// Just a starting shape for JSObject; properties can move after initialization.
@noVerifier
extern class JSProxyRevocableResult extends JSObject {
- proxy: Object;
- revoke: Object;
+ proxy: JSAny;
+ revoke: JSAny;
}
macro NewJSProxyRevocableResult(implicit context: Context)(
@@ -412,22 +444,24 @@ extern class JSGlobalProxy extends JSObject {
@generateCppClass
extern class JSPrimitiveWrapper extends JSObject {
- value: Object;
+ value: JSAny;
}
-extern class JSArgumentsObject extends JSObject {}
+@generateCppClass
+extern class JSArgumentsObject extends JSObject {
+}
// Just a starting shape for JSObject; properties can move after initialization.
@noVerifier
@hasSameInstanceTypeAsParent
extern class JSArgumentsObjectWithLength extends JSArgumentsObject {
- length: Object;
+ length: JSAny;
}
// Just a starting shape for JSObject; properties can move after initialization.
@hasSameInstanceTypeAsParent
extern class JSSloppyArgumentsObject extends JSArgumentsObjectWithLength {
- callee: Object;
+ callee: JSAny;
}
// Just a starting shape for JSObject; properties can move after initialization.
@@ -492,8 +526,8 @@ type NoSharedNameSentinel extends Smi;
@generateCppClass
extern class CallHandlerInfo extends Struct {
- callback: Foreign | Undefined;
- js_callback: Foreign | Undefined;
+ callback: NonNullForeign | Undefined | Zero;
+ js_callback: NonNullForeign | Undefined | Zero;
data: Object;
}
@@ -510,18 +544,37 @@ extern class Module extends HeapObject {
type SourceTextModuleInfo extends FixedArray;
+@generateCppClass
extern class SourceTextModule extends Module {
+ // The code representing this module, or an abstraction thereof.
code: SharedFunctionInfo | JSFunction |
JSGeneratorObject | SourceTextModuleInfo;
+
+ // Arrays of cells corresponding to regular exports and regular imports.
+ // A cell's position in the array is determined by the cell index of the
+ // associated module entry (which coincides with the variable index of the
+ // associated variable).
regular_exports: FixedArray;
regular_imports: FixedArray;
+
+ // Modules imported or re-exported by this module.
+ // Corresponds 1-to-1 to the module specifier strings in
+ // SourceTextModuleInfo::module_requests.
requested_modules: FixedArray;
+
+ // Script from which the module originates.
script: Script;
+
+ // The value of import.meta inside of this module.
+ // Lazily initialized on first access. It's the hole before first access and
+ // a JSObject afterwards.
import_meta: TheHole | JSObject;
+
dfs_index: Smi;
dfs_ancestor_index: Smi;
}
+@generateCppClass
extern class SyntheticModule extends Module {
name: String;
export_names: FixedArray;
@@ -529,6 +582,7 @@ extern class SyntheticModule extends Module {
}
@abstract
+@generateCppClass
extern class JSModuleNamespace extends JSObject {
module: Module;
}
@@ -539,14 +593,23 @@ extern class TemplateList extends FixedArray {
}
@abstract
+@generateCppClass
extern class JSWeakCollection extends JSObject {
+ // The backing hash table mapping keys to values.
table: Object;
}
-extern class JSWeakSet extends JSWeakCollection {}
-extern class JSWeakMap extends JSWeakCollection {}
+@generateCppClass
+extern class JSWeakSet extends JSWeakCollection {
+}
+@generateCppClass
+extern class JSWeakMap extends JSWeakCollection {
+}
+@generateCppClass
extern class JSCollectionIterator extends JSObject {
+ // The backing hash table mapping keys to values.
table: Object;
+ // The index into the data table.
index: Object;
}
@@ -601,7 +664,10 @@ extern class Script extends Struct {
host_defined_options: Object;
}
-extern class EmbedderDataArray extends HeapObject { length: Smi; }
+@generateCppClass
+extern class EmbedderDataArray extends HeapObject {
+ length: Smi;
+}
type ScopeInfo extends HeapObject generates 'TNode<ScopeInfo>';
@@ -631,9 +697,15 @@ extern class SharedFunctionInfo extends HeapObject {
@if(V8_SFI_HAS_UNIQUE_ID) unique_id: int32;
}
+@generateCppClass
extern class JSBoundFunction extends JSObject {
+ // The wrapped function object.
bound_target_function: Callable;
- bound_this: Object;
+ // The value that is always passed as the this value when calling the wrapped
+ // function.
+ bound_this: JSAny;
+ // A list of values whose elements are used as the first arguments to any call
+ // to the wrapped function.
bound_arguments: FixedArray;
}
@@ -644,7 +716,7 @@ extern class JSBoundFunction extends JSObject {
type NonNullForeign extends Foreign;
// A function built with InstantiateFunction for the public API.
-type CallableApiObject extends HeapObject;
+type CallableApiObject extends JSObject;
// A JSProxy with the callable bit set.
type CallableJSProxy extends JSProxy;
@@ -729,14 +801,26 @@ extern class JSTypedArray extends JSArrayBufferView {
}
@abstract
+@generateCppClass
extern class JSCollection extends JSObject {
+ // The backing hash table.
table: Object;
}
-extern class JSSet extends JSCollection {}
-extern class JSMap extends JSCollection {}
+@generateCppClass
+extern class JSSet extends JSCollection {
+}
+@generateCppClass
+extern class JSMap extends JSCollection {
+}
+@generateCppClass
extern class JSDate extends JSObject {
+ // If one component is NaN, all of them are, indicating a NaN time value.
+
+ // The time value.
value: NumberOrUndefined;
+
+ // Cached values:
year: Undefined | Smi | NaN;
month: Undefined | Smi | NaN;
day: Undefined | Smi | NaN;
@@ -744,6 +828,9 @@ extern class JSDate extends JSObject {
hour: Undefined | Smi | NaN;
min: Undefined | Smi | NaN;
sec: Undefined | Smi | NaN;
+
+ // Sample of the date cache stamp at the moment when chached fields were
+ // cached.
cache_stamp: Undefined | Smi | NaN;
}
@@ -752,8 +839,11 @@ extern class JSGlobalObject extends JSObject {
global_proxy: JSGlobalProxy;
}
+@generateCppClass
extern class JSAsyncFromSyncIterator extends JSObject {
sync_iterator: JSReceiver;
+ // The "next" method is loaded during GetIterator, and is not reloaded for
+ // subsequent "next" invocations.
next: Object;
}
@@ -763,6 +853,7 @@ extern class JSStringIterator extends JSObject {
}
@abstract
+@generateCppClass
extern class TemplateInfo extends Struct {
tag: Object;
serial_number: Object;
@@ -772,12 +863,15 @@ extern class TemplateInfo extends Struct {
}
@generatePrint
+@generateCppClass
extern class TemplateObjectDescription extends Struct {
raw_strings: FixedArray;
cooked_strings: FixedArray;
}
+@generateCppClass
extern class FunctionTemplateRareData extends Struct {
+ // See DECL_RARE_ACCESSORS in FunctionTemplateInfo.
prototype_template: Object;
prototype_provider_template: Object;
parent_template: Object;
@@ -788,17 +882,31 @@ extern class FunctionTemplateRareData extends Struct {
access_check_info: Object;
}
+@generateCppClass
extern class FunctionTemplateInfo extends TemplateInfo {
+ // Handler invoked when calling an instance of this FunctionTemplateInfo.
+ // Either CallInfoHandler or Undefined.
call_code: Object;
class_name: Object;
+ // If the signature is a FunctionTemplateInfo it is used to check whether the
+ // receiver calling the associated JSFunction is a compatible receiver, i.e.
+ // it is an instance of the signature FunctionTemplateInfo or any of the
+ // receiver's prototypes are.
signature: Object;
- function_template_rare_data: Object;
+ // If any of the setters declared by DECL_RARE_ACCESSORS are used then a
+ // FunctionTemplateRareData will be stored here. Until then this contains
+ // undefined.
+ rare_data: HeapObject;
shared_function_info: Object;
flag: Smi;
length: Smi;
+ // Either the_hole or a private symbol. Used to cache the result on
+ // the receiver under the the cached_property_name when this
+ // FunctionTemplateInfo is used as a getter.
cached_property_name: Object;
}
+@generateCppClass
extern class ObjectTemplateInfo extends TemplateInfo {
constructor: Object;
data: Object;
@@ -809,7 +917,7 @@ extern class PropertyArray extends HeapObject { length_and_hash: Smi; }
type DependentCode extends WeakFixedArray;
extern class PropertyCell extends HeapObject {
- name: Name;
+ name: AnyName;
property_details_raw: Smi;
value: Object;
dependent_code: DependentCode;
@@ -840,6 +948,7 @@ const UTF32:
extern class Foreign extends HeapObject { foreign_address: RawPtr; }
+@generateCppClass
extern class InterceptorInfo extends Struct {
getter: NonNullForeign | Zero | Undefined;
setter: NonNullForeign | Zero | Undefined;
@@ -852,6 +961,7 @@ extern class InterceptorInfo extends Struct {
flags: Smi;
}
+@generateCppClass
extern class AccessCheckInfo extends Struct {
callback: Foreign | Zero | Undefined;
named_interceptor: InterceptorInfo | Zero | Undefined;
@@ -859,14 +969,21 @@ extern class AccessCheckInfo extends Struct {
data: Object;
}
+@generateCppClass
extern class ArrayBoilerplateDescription extends Struct {
flags: Smi;
constant_elements: FixedArrayBase;
}
-extern class AliasedArgumentsEntry extends Struct { aliased_context_slot: Smi; }
+@generateCppClass
+extern class AliasedArgumentsEntry extends Struct {
+ aliased_context_slot: Smi;
+}
-extern class Cell extends HeapObject { value: Object; }
+@generateCppClass
+extern class Cell extends HeapObject {
+ value: Object;
+}
extern class DataHandler extends Struct {
smi_handler: Smi | Code;
@@ -881,39 +998,58 @@ extern class DataHandler extends Struct {
@abstract
@dirtyInstantiatedAbstractClass
+@generateCppClass
extern class JSGeneratorObject extends JSObject {
function: JSFunction;
context: Context;
- receiver: Object;
+ receiver: JSAny;
+
+ // For executing generators: the most recent input value.
+ // For suspended generators: debug information (bytecode offset).
+ // There is currently no need to remember the most recent input value for a
+ // suspended generator.
input_or_debug_pos: Object;
+
resume_mode: Smi;
continuation: Smi;
+
+ // Saved interpreter register file.
parameters_and_registers: FixedArray;
}
+@generateCppClass
extern class JSAsyncFunctionObject extends JSGeneratorObject {
promise: JSPromise;
}
+@generateCppClass
extern class JSAsyncGeneratorObject extends JSGeneratorObject {
+ // Pointer to the head of a singly linked list of AsyncGeneratorRequest, or
+ // undefined.
queue: HeapObject;
is_awaiting: Smi;
}
+@generateCppClass
extern class JSPromise extends JSObject {
+ // Smi 0 terminated list of PromiseReaction objects in case the JSPromise was
+ // not settled yet, otherwise the result.
reactions_or_result: Object;
flags: Smi;
}
@abstract
+@generateCppClass
extern class Microtask extends Struct {
}
+@generateCppClass
extern class CallbackTask extends Microtask {
callback: Foreign;
data: Foreign;
}
+@generateCppClass
extern class CallableTask extends Microtask {
callable: JSReceiver;
context: Context;
@@ -931,11 +1067,13 @@ extern class StackFrameInfo extends Struct {
type_name: String | Null | Undefined;
eval_origin: String | Null | Undefined;
wasm_module_name: String | Null | Undefined;
+ wasm_instance: WasmInstanceObject | Null | Undefined;
flag: Smi;
}
type FrameArray extends FixedArray;
+@generateCppClass
extern class StackTraceFrame extends Struct {
frame_array: FrameArray | Undefined;
frame_index: Smi;
@@ -943,6 +1081,7 @@ extern class StackTraceFrame extends Struct {
id: Smi;
}
+@generateCppClass
extern class ClassPositions extends Struct {
start: Smi;
end: Smi;
@@ -958,7 +1097,7 @@ extern class WasmExportedFunctionData extends Struct {
// The remaining fields are for fast calling from C++. The contract is
// that they are lazily populated, and either all will be present or none.
c_wrapper_code: Object;
- wasm_call_target: Smi; // Pseudo-smi: one-bit shift on all platforms.
+ wasm_call_target: Smi | Foreign;
packed_args_size: Smi;
}
@@ -972,7 +1111,7 @@ extern class WasmJSFunctionData extends Struct {
extern class WasmCapiFunctionData extends Struct {
call_target: RawPtr;
- embedder_data: RawPtr;
+ embedder_data: Foreign; // Managed<wasm::FuncData>
wrapper_code: Code;
serialized_signature: ByteArray; // PodArray<wasm::ValueType>
}
@@ -995,7 +1134,13 @@ extern class WasmDebugInfo extends Struct {
c_wasm_entry_map: Foreign | Undefined; // Managed<wasm::SignatureMap>
}
-extern class WasmExceptionTag extends Struct { index: Smi; }
+@generateCppClass
+extern class WasmExceptionTag extends Struct {
+ index: Smi;
+}
+
+const kTaggedSize: constexpr int31 generates 'kTaggedSize';
+const kDoubleSize: constexpr int31 generates 'kDoubleSize';
const kSmiTagSize: constexpr int31 generates 'kSmiTagSize';
const V8_INFINITY: constexpr float64 generates 'V8_INFINITY';
@@ -1013,8 +1158,8 @@ const PACKED_DOUBLE_ELEMENTS:
constexpr ElementsKind generates 'PACKED_DOUBLE_ELEMENTS';
const HOLEY_DOUBLE_ELEMENTS:
constexpr ElementsKind generates 'HOLEY_DOUBLE_ELEMENTS';
-const LAST_FROZEN_ELEMENTS_KIND:
- constexpr ElementsKind generates 'LAST_FROZEN_ELEMENTS_KIND';
+const LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND: constexpr ElementsKind
+ generates 'LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND';
const DICTIONARY_ELEMENTS:
constexpr ElementsKind generates 'DICTIONARY_ELEMENTS';
@@ -1186,6 +1331,7 @@ extern macro Int32FalseConstant(): bool;
extern macro EmptyStringConstant(): EmptyString;
extern macro LengthStringConstant(): String;
extern macro NanConstant(): NaN;
+extern macro IteratorSymbolConstant(): Symbol;
const TheHole: TheHole = TheHoleConstant();
const Null: Null = NullConstant();
@@ -1207,6 +1353,7 @@ const SKIP_WRITE_BARRIER:
const UNSAFE_SKIP_WRITE_BARRIER:
constexpr WriteBarrierMode generates 'UNSAFE_SKIP_WRITE_BARRIER';
+@generateCppClass
extern class AsyncGeneratorRequest extends Struct {
next: AsyncGeneratorRequest | Undefined;
resume_mode: Smi;
@@ -1214,6 +1361,7 @@ extern class AsyncGeneratorRequest extends Struct {
promise: JSPromise;
}
+@generateCppClass
extern class SourceTextModuleInfoEntry extends Struct {
export_name: String | Undefined;
local_name: String | Undefined;
@@ -1224,31 +1372,43 @@ extern class SourceTextModuleInfoEntry extends Struct {
end_pos: Smi;
}
+@generateCppClass
extern class PromiseCapability extends Struct {
promise: JSReceiver | Undefined;
resolve: Object;
reject: Object;
}
+@generateCppClass
extern class PromiseReaction extends Struct {
next: PromiseReaction | Zero;
reject_handler: Callable | Undefined;
fulfill_handler: Callable | Undefined;
+ // Either a JSPromise (in case of native promises), a PromiseCapability
+ // (general case), or undefined (in case of await).
promise_or_capability: JSPromise | PromiseCapability | Undefined;
}
@abstract
+@generateCppClass
extern class PromiseReactionJobTask extends Microtask {
argument: Object;
context: Context;
handler: Callable | Undefined;
+ // Either a JSPromise (in case of native promises), a PromiseCapability
+ // (general case), or undefined (in case of await).
promise_or_capability: JSPromise | PromiseCapability | Undefined;
}
-extern class PromiseFulfillReactionJobTask extends PromiseReactionJobTask {}
+@generateCppClass
+extern class PromiseFulfillReactionJobTask extends PromiseReactionJobTask {
+}
-extern class PromiseRejectReactionJobTask extends PromiseReactionJobTask {}
+@generateCppClass
+extern class PromiseRejectReactionJobTask extends PromiseReactionJobTask {
+}
+@generateCppClass
extern class PromiseResolveThenableJobTask extends Microtask {
context: Context;
promise_to_resolve: JSPromise;
@@ -1256,6 +1416,7 @@ extern class PromiseResolveThenableJobTask extends Microtask {
thenable: JSReceiver;
}
+@generateCppClass
extern class JSRegExp extends JSObject {
data: FixedArray | Undefined;
source: String | Undefined;
@@ -1263,7 +1424,7 @@ extern class JSRegExp extends JSObject {
}
extern transitioning macro AllocateJSIteratorResult(implicit context: Context)(
- Object, Boolean): JSObject;
+ JSAny, Boolean): JSObject;
// Note: Although a condition for a FastJSRegExp is having a positive smi
// lastIndex (see RegExpBuiltinsAssembler::BranchIfFastRegExp), it is possible
@@ -1282,13 +1443,16 @@ RegExpBuiltinsAssembler::FastStoreLastIndex(FastJSRegExp, Smi): void;
@hasSameInstanceTypeAsParent
extern class JSRegExpResult extends JSArray {
- index: Object;
- input: Object;
- groups: Object;
+ index: JSAny;
+ input: JSAny;
+ groups: JSAny;
}
+@generateCppClass
extern class JSRegExpStringIterator extends JSObject {
- iterating_reg_exp: Object;
+ // The [[IteratingRegExp]] internal property.
+ iterating_reg_exp: JSAny;
+ // The [[IteratedString]] internal property.
iterated_string: String;
flags: Smi;
}
@@ -1466,32 +1630,33 @@ extern macro Comment(constexpr string);
extern macro StaticAssert(bool);
extern macro Print(Object);
extern macro DebugBreak();
-extern transitioning macro ToInteger_Inline(Context, Object): Number;
+extern transitioning macro ToInteger_Inline(Context, JSAny): Number;
extern transitioning macro ToInteger_Inline(
- Context, Object, constexpr ToIntegerTruncationMode): Number;
-extern transitioning macro ToLength_Inline(Context, Object): Number;
-extern transitioning macro ToNumber_Inline(Context, Object): Number;
-extern transitioning macro ToSmiIndex(implicit context: Context)(Object):
+ Context, JSAny, constexpr ToIntegerTruncationMode): Number;
+extern transitioning macro ToLength_Inline(Context, JSAny): Number;
+extern transitioning macro ToNumber_Inline(Context, JSAny): Number;
+extern transitioning macro ToSmiIndex(implicit context: Context)(JSAny):
PositiveSmi labels IfRangeError;
-extern transitioning macro ToSmiLength(implicit context: Context)(Object):
+extern transitioning macro ToSmiLength(implicit context: Context)(JSAny):
PositiveSmi labels IfRangeError;
-extern transitioning macro ToString_Inline(Context, Object): String;
+extern transitioning macro ToString_Inline(Context, JSAny): String;
extern transitioning macro ToThisString(implicit context: Context)(
- Object, String): String;
+ JSAny, String): String;
extern transitioning macro ToThisValue(implicit context: Context)(
- Object, constexpr PrimitiveType, constexpr string): Object;
+ JSAny, constexpr PrimitiveType, constexpr string): JSAny;
extern transitioning macro GetProperty(implicit context: Context)(
- Object, Object): Object;
+ JSAny, JSAny): JSAny;
extern transitioning builtin SetProperty(implicit context: Context)(
- Object, Object, Object);
+ JSAny, JSAny, JSAny);
extern transitioning builtin SetPropertyInLiteral(implicit context: Context)(
- Object, Object, Object);
+ JSAny, JSAny, JSAny);
extern transitioning builtin DeleteProperty(implicit context: Context)(
- Object, Object, LanguageMode): Object;
+ JSAny, JSAny | PrivateSymbol, LanguageMode): Boolean;
extern transitioning builtin HasProperty(implicit context: Context)(
- Object, Object): Boolean;
+ JSAny, JSAny): Boolean;
extern transitioning macro HasProperty_Inline(implicit context: Context)(
- JSReceiver, Object): Boolean;
+ JSReceiver, JSAny): Boolean;
+extern builtin LoadIC(Context, JSAny, JSAny, Smi, FeedbackVector): JSAny;
extern macro ThrowRangeError(implicit context: Context)(
constexpr MessageTemplate): never;
@@ -1510,43 +1675,60 @@ extern macro ThrowTypeError(implicit context: Context)(
extern transitioning runtime ThrowTypeErrorIfStrict(implicit context: Context)(
Smi, Object, Object): void;
-extern macro ArraySpeciesCreate(Context, Object, Number): JSReceiver;
+extern transitioning macro ThrowIfNotJSReceiver(implicit context: Context)(
+ JSAny, constexpr MessageTemplate, constexpr string): void;
+
+extern macro ArraySpeciesCreate(Context, JSAny, Number): JSReceiver;
extern macro ArrayCreate(implicit context: Context)(Number): JSArray;
extern macro BuildAppendJSArray(
- constexpr ElementsKind, FastJSArray, Object): void labels Bailout;
+ constexpr ElementsKind, FastJSArray, JSAny): void labels Bailout;
extern macro EnsureArrayPushable(Map): ElementsKind
labels Bailout;
extern macro EnsureArrayLengthWritable(Map) labels Bailout;
// TODO: Reduce duplication once varargs are supported in macros.
extern macro Construct(implicit context: Context)(
- Constructor, Object): JSReceiver;
+ Constructor, JSAny): JSReceiver;
extern macro Construct(implicit context: Context)(
- Constructor, Object, Object): JSReceiver;
+ Constructor, JSAny, JSAny): JSReceiver;
extern macro Construct(implicit context: Context)(
- Constructor, Object, Object, Object): JSReceiver;
+ Constructor, JSAny, JSAny, JSAny): JSReceiver;
extern macro ConstructWithTarget(implicit context: Context)(
Constructor, JSReceiver): JSReceiver;
extern macro ConstructWithTarget(implicit context: Context)(
- Constructor, JSReceiver, Object): JSReceiver;
+ Constructor, JSReceiver, JSAny): JSReceiver;
extern macro SpeciesConstructor(implicit context: Context)(
- Object, JSReceiver): JSReceiver;
+ JSAny, JSReceiver): JSReceiver;
extern macro ConstructorBuiltinsAssembler::IsDictionaryMap(Map): bool;
extern macro CodeStubAssembler::AllocateNameDictionary(constexpr int32):
NameDictionary;
-extern builtin ToObject(Context, Object): JSReceiver;
-extern macro ToObject_Inline(Context, Object): JSReceiver;
+extern builtin ToObject(Context, JSAny): JSReceiver;
+extern macro ToObject_Inline(Context, JSAny): JSReceiver;
extern macro IsNullOrUndefined(Object): bool;
extern macro IsTheHole(Object): bool;
extern macro IsString(HeapObject): bool;
-transitioning builtin ToString(context: Context, o: Object): String {
+transitioning builtin ToString(context: Context, o: JSAny): String {
return ToStringImpl(context, o);
}
-extern transitioning runtime ToStringRT(Context, Object): String;
+extern transitioning runtime ToStringRT(Context, JSAny): String;
extern transitioning builtin NonPrimitiveToPrimitive_String(
- Context, Object): Object;
+ Context, JSAny): JSPrimitive;
+extern transitioning builtin NonPrimitiveToPrimitive_Default(
+ Context, JSAny): JSPrimitive;
+
+transitioning macro ToPrimitiveDefault(implicit context: Context)(v: JSAny):
+ JSPrimitive {
+ typeswitch (v) {
+ case (v: JSReceiver): {
+ return NonPrimitiveToPrimitive_Default(context, v);
+ }
+ case (v: JSPrimitive): {
+ return v;
+ }
+ }
+}
extern transitioning runtime NormalizeElements(Context, JSObject);
extern transitioning runtime TransitionElementsKindWithKind(
@@ -1556,18 +1738,15 @@ extern macro LoadBufferObject(RawPtr, constexpr int32): Object;
extern macro LoadBufferPointer(RawPtr, constexpr int32): RawPtr;
extern macro LoadBufferSmi(RawPtr, constexpr int32): Smi;
-extern macro LoadRoot(constexpr RootIndex): Object;
-extern macro StoreRoot(constexpr RootIndex, Object): Object;
-
extern runtime StringEqual(Context, String, String): Oddball;
extern builtin StringLessThan(Context, String, String): Boolean;
extern macro StringCharCodeAt(String, intptr): int32;
extern runtime StringCompareSequence(Context, String, String, Number): Boolean;
extern macro StringFromSingleCharCode(int32): String;
-extern macro StrictEqual(Object, Object): Boolean;
+extern macro StrictEqual(JSAny, JSAny): Boolean;
extern macro SmiLexicographicCompare(Smi, Smi): Smi;
-extern runtime ReThrow(Context, Object): never;
+extern runtime ReThrow(Context, JSAny): never;
extern runtime ThrowInvalidStringLength(Context): never;
extern operator '==' macro WordEqual(RawPtr, RawPtr): bool;
@@ -1638,38 +1817,51 @@ extern operator '<' macro Float64LessThan(float64, float64): bool;
extern macro BranchIfNumberEqual(Number, Number): never
labels Taken, NotTaken;
operator '==' macro IsNumberEqual(a: Number, b: Number): bool {
- return (BranchIfNumberEqual(a, b)) ? true : false;
+ BranchIfNumberEqual(a, b) otherwise return true, return false;
}
operator '!=' macro IsNumberNotEqual(a: Number, b: Number): bool {
- return (BranchIfNumberEqual(a, b)) ? false : true;
+ return !(a == b);
}
-extern operator '<' macro BranchIfNumberLessThan(Number, Number): never
+extern macro BranchIfNumberLessThan(Number, Number): never
labels Taken, NotTaken;
-extern operator '<=' macro BranchIfNumberLessThanOrEqual(Number, Number): never
+operator '<' macro NumberIsLessThan(a: Number, b: Number): bool {
+ BranchIfNumberLessThan(a, b) otherwise return true, return false;
+}
+extern macro BranchIfNumberLessThanOrEqual(Number, Number): never
labels Taken, NotTaken;
+operator '<=' macro NumberIsLessThanOrEqual(a: Number, b: Number): bool {
+ BranchIfNumberLessThanOrEqual(a, b) otherwise return true, return false;
+}
-extern operator '>' macro BranchIfNumberGreaterThan(Number, Number): never
- labels Taken, NotTaken;
-extern operator '>=' macro BranchIfNumberGreaterThanOrEqual(
- Number, Number): never
+operator '>' macro NumberIsGreaterThan(a: Number, b: Number): bool {
+ return b < a;
+}
+operator '>=' macro NumberIsGreaterThanOrEqual(a: Number, b: Number): bool {
+ return b <= a;
+}
+
+extern macro BranchIfFloat64IsNaN(float64): never
labels Taken, NotTaken;
+macro Float64IsNaN(n: float64): bool {
+ BranchIfFloat64IsNaN(n) otherwise return true, return false;
+}
-// The type of all tagged values that can safely be compared with WordEqual.
+// The type of all tagged values that can safely be compared with TaggedEqual.
type TaggedWithIdentity =
JSReceiver | FixedArrayBase | Oddball | Map | EmptyString;
-extern operator '==' macro WordEqual(TaggedWithIdentity, Object): bool;
-extern operator '==' macro WordEqual(Object, TaggedWithIdentity): bool;
-extern operator '==' macro WordEqual(
+extern operator '==' macro TaggedEqual(TaggedWithIdentity, Object): bool;
+extern operator '==' macro TaggedEqual(Object, TaggedWithIdentity): bool;
+extern operator '==' macro TaggedEqual(
TaggedWithIdentity, TaggedWithIdentity): bool;
-extern operator '!=' macro WordNotEqual(TaggedWithIdentity, Object): bool;
-extern operator '!=' macro WordNotEqual(Object, TaggedWithIdentity): bool;
-extern operator '!=' macro WordNotEqual(
+extern operator '!=' macro TaggedNotEqual(TaggedWithIdentity, Object): bool;
+extern operator '!=' macro TaggedNotEqual(Object, TaggedWithIdentity): bool;
+extern operator '!=' macro TaggedNotEqual(
TaggedWithIdentity, TaggedWithIdentity): bool;
// Do not overload == and != if it is unclear if object identity is the right
// equality.
-extern macro WordEqual(Object, Object): bool;
-extern macro WordNotEqual(Object, Object): bool;
+extern macro TaggedEqual(Object, Object): bool;
+extern macro TaggedNotEqual(Object, Object): bool;
extern operator '+' macro SmiAdd(Smi, Smi): Smi;
extern operator '-' macro SmiSub(Smi, Smi): Smi;
@@ -1707,11 +1899,14 @@ extern operator '*' macro ConstexprInt31Mul(
constexpr int31, constexpr int31): constexpr int31;
extern operator '-' macro Int32Sub(int32, int32): int32;
extern operator '*' macro Int32Mul(int32, int32): int32;
+extern operator '/' macro Int32Div(int32, int32): int32;
extern operator '%' macro Int32Mod(int32, int32): int32;
extern operator '&' macro Word32And(int32, int32): int32;
extern operator '&' macro Word32And(uint32, uint32): uint32;
extern operator '==' macro
ConstexprInt31Equal(constexpr int31, constexpr int31): constexpr bool;
+extern operator '!=' macro
+ConstexprInt31NotEqual(constexpr int31, constexpr int31): constexpr bool;
extern operator '>=' macro
ConstexprInt31GreaterThanEqual(
constexpr int31, constexpr int31): constexpr bool;
@@ -1732,6 +1927,8 @@ extern operator '!=' macro Word32NotEqual(bool, bool): bool;
extern operator '+' macro Float64Add(float64, float64): float64;
extern operator '-' macro Float64Sub(float64, float64): float64;
+extern operator '*' macro Float64Mul(float64, float64): float64;
+extern operator '/' macro Float64Div(float64, float64): float64;
extern operator '+' macro NumberAdd(Number, Number): Number;
extern operator '-' macro NumberSub(Number, Number): Number;
@@ -1845,6 +2042,146 @@ Cast<Number>(o: Object): Number
return TaggedToNumber(o) otherwise CastError;
}
+Cast<Undefined>(o: Object): Undefined
+ labels CastError {
+ if (o != Undefined) goto CastError;
+ return %RawDownCast<Undefined>(o);
+}
+
+Cast<Numeric>(o: Object): Numeric labels CastError {
+ typeswitch (o) {
+ case (o: Number): {
+ return o;
+ }
+ case (o: BigInt): {
+ return o;
+ }
+ case (HeapObject): {
+ goto CastError;
+ }
+ }
+}
+
+Cast<TheHole>(o: Object): TheHole labels CastError {
+ if (o == TheHole) return %RawDownCast<TheHole>(o);
+ goto CastError;
+}
+
+Cast<TheHole>(o: HeapObject): TheHole labels CastError {
+ const o: Object = o;
+ return Cast<TheHole>(o) otherwise CastError;
+}
+
+Cast<True>(o: Object): True labels CastError {
+ if (o == True) return %RawDownCast<True>(o);
+ goto CastError;
+}
+
+Cast<True>(o: HeapObject): True labels CastError {
+ const o: Object = o;
+ return Cast<True>(o) otherwise CastError;
+}
+
+Cast<False>(o: Object): False labels CastError {
+ if (o == False) return %RawDownCast<False>(o);
+ goto CastError;
+}
+
+Cast<False>(o: HeapObject): False labels CastError {
+ const o: Object = o;
+ return Cast<False>(o) otherwise CastError;
+}
+
+Cast<Boolean>(o: Object): Boolean labels CastError {
+ typeswitch (o) {
+ case (o: True): {
+ return o;
+ }
+ case (o: False): {
+ return o;
+ }
+ case (Object): {
+ goto CastError;
+ }
+ }
+}
+
+Cast<Boolean>(o: HeapObject): Boolean labels CastError {
+ const o: Object = o;
+ return Cast<Boolean>(o) otherwise CastError;
+}
+
+// TODO(tebbi): These trivial casts for union types should be generated
+// automatically.
+
+Cast<JSPrimitive>(o: Object): JSPrimitive labels CastError {
+ typeswitch (o) {
+ case (o: Numeric): {
+ return o;
+ }
+ case (o: String): {
+ return o;
+ }
+ case (o: Symbol): {
+ return o;
+ }
+ case (o: Boolean): {
+ return o;
+ }
+ case (o: Undefined): {
+ return o;
+ }
+ case (o: Null): {
+ return o;
+ }
+ case (Object): {
+ goto CastError;
+ }
+ }
+}
+
+Cast<JSAny>(o: Object): JSAny labels CastError {
+ typeswitch (o) {
+ case (o: JSPrimitive): {
+ return o;
+ }
+ case (o: JSReceiver): {
+ return o;
+ }
+ case (Object): {
+ goto CastError;
+ }
+ }
+}
+
+Cast<JSAny | TheHole>(o: Object): JSAny | TheHole labels CastError {
+ typeswitch (o) {
+ case (o: JSAny): {
+ return o;
+ }
+ case (o: TheHole): {
+ return o;
+ }
+ case (Object): {
+ goto CastError;
+ }
+ }
+}
+
+Cast<Number | TheHole>(o: Object): Number | TheHole labels CastError {
+ typeswitch (o) {
+ case (o: Number): {
+ return o;
+ }
+ case (o: TheHole): {
+ return o;
+ }
+ case (Object): {
+ goto CastError;
+ }
+ }
+}
+
macro Cast<A: type>(o: HeapObject): A
labels CastError;
@@ -1859,6 +2196,12 @@ Cast<Null>(o: HeapObject): Null
return %RawDownCast<Null>(o);
}
+Cast<Undefined>(o: HeapObject): Undefined
+ labels CastError {
+ const o: Object = o;
+ return Cast<Undefined>(o) otherwise CastError;
+}
+
Cast<FixedArray>(o: HeapObject): FixedArray
labels CastError {
return HeapObjectToFixedArray(o) otherwise CastError;
@@ -1928,6 +2271,12 @@ Cast<Context>(o: HeapObject): Context
goto CastError;
}
+Cast<NativeContext>(o: HeapObject): NativeContext
+ labels CastError {
+ if (IsNativeContext(o)) return %RawDownCast<NativeContext>(o);
+ goto CastError;
+}
+
Cast<JSObject>(o: HeapObject): JSObject
labels CastError {
if (IsJSObject(o)) return %RawDownCast<JSObject>(o);
@@ -1957,6 +2306,27 @@ Cast<Symbol>(o: HeapObject): Symbol
goto CastError;
}
+macro Cast<T: type>(o: Symbol): T labels CastError;
+Cast<PublicSymbol>(o: Symbol): PublicSymbol labels CastError {
+ if (IsPrivateSymbol(o)) goto CastError;
+ return %RawDownCast<PublicSymbol>(o);
+}
+Cast<PrivateSymbol>(o: Symbol): PrivateSymbol labels CastError {
+ if (IsPrivateSymbol(o)) {
+ return %RawDownCast<PrivateSymbol>(o);
+ }
+ goto CastError;
+}
+
+Cast<PublicSymbol>(o: HeapObject): PublicSymbol labels CastError {
+ const o = Cast<Symbol>(o) otherwise CastError;
+ return Cast<PublicSymbol>(o) otherwise CastError;
+}
+Cast<PrivateSymbol>(o: HeapObject): PrivateSymbol labels CastError {
+ const o = Cast<Symbol>(o) otherwise CastError;
+ return Cast<PrivateSymbol>(o) otherwise CastError;
+}
+
Cast<DirectString>(o: HeapObject): DirectString
labels CastError {
return TaggedToDirectString(o) otherwise CastError;
@@ -2014,7 +2384,13 @@ Cast<JSArgumentsObjectWithLength>(implicit context: Context)(o: HeapObject):
Cast<FastJSRegExp>(implicit context: Context)(o: HeapObject): FastJSRegExp
labels CastError {
- if (regexp::BranchIfFastRegExp(o)) return %RawDownCast<FastJSRegExp>(o);
+ // TODO(jgruber): Remove or redesign this. There is no single 'fast' regexp,
+ // the conditions to make a regexp object fast differ based on the callsite.
+ // For now, run the strict variant since replace (the only current callsite)
+ // accesses flag getters.
+ if (regexp::IsFastRegExpStrict(o)) {
+ return %RawDownCast<FastJSRegExp>(o);
+ }
goto CastError;
}
@@ -2042,7 +2418,8 @@ Cast<FastJSArrayForRead>(implicit context: Context)(o: HeapObject):
// Bailout if receiver has slow elements.
const elementsKind: ElementsKind = LoadMapElementsKind(map);
- if (!IsElementsKindLessThanOrEqual(elementsKind, LAST_FROZEN_ELEMENTS_KIND))
+ if (!IsElementsKindLessThanOrEqual(
+ elementsKind, LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND))
goto CastError;
// Verify that our prototype is the initial array prototype.
@@ -2076,7 +2453,7 @@ Cast<FastJSArrayForReadWithNoCustomIteration>(implicit context: Context)(
return %RawDownCast<FastJSArrayForReadWithNoCustomIteration>(a);
}
-Cast<JSReceiver>(implicit context: Context)(o: HeapObject): JSReceiver
+Cast<JSReceiver>(o: HeapObject): JSReceiver
labels CastError {
if (IsJSReceiver(o)) return %RawDownCast<JSReceiver>(o);
goto CastError;
@@ -2103,6 +2480,21 @@ Cast<CoverageInfo>(implicit context: Context)(o: HeapObject): CoverageInfo
goto CastError;
}
+Cast<JSReceiver | Null>(o: HeapObject): JSReceiver | Null
+ labels CastError {
+ typeswitch (o) {
+ case (o: Null): {
+ return o;
+ }
+ case (o: JSReceiver): {
+ return o;
+ }
+ case (HeapObject): {
+ goto CastError;
+ }
+ }
+}
+
extern macro AllocateHeapNumberWithValue(float64): HeapNumber;
extern macro ChangeInt32ToTagged(int32): Number;
extern macro ChangeUint32ToTagged(uint32): Number;
@@ -2132,8 +2524,8 @@ extern macro ChangeUint32ToWord(uint32): uintptr; // Doesn't sign-extend.
extern macro LoadNativeContext(Context): NativeContext;
extern macro TruncateFloat64ToFloat32(float64): float32;
extern macro TruncateHeapNumberValueToWord32(HeapNumber): int32;
-extern macro LoadJSArrayElementsMap(constexpr ElementsKind, Context): Map;
-extern macro LoadJSArrayElementsMap(ElementsKind, Context): Map;
+extern macro LoadJSArrayElementsMap(constexpr ElementsKind, NativeContext): Map;
+extern macro LoadJSArrayElementsMap(ElementsKind, NativeContext): Map;
extern macro ChangeNonnegativeNumberToUintPtr(Number): uintptr;
extern macro TryNumberToUintPtr(Number): uintptr labels IfNegative;
extern macro NumberConstant(constexpr float64): Number;
@@ -2157,6 +2549,7 @@ extern macro IntPtrConstant(constexpr ContextSlot): ContextSlot;
extern macro IntPtrConstant(constexpr intptr): intptr;
extern macro PointerConstant(constexpr RawPtr): RawPtr;
extern macro SingleCharacterStringConstant(constexpr string): String;
+extern macro Float64SilenceNaN(float64): float64;
extern macro BitcastWordToTaggedSigned(intptr): Smi;
extern macro BitcastWordToTaggedSigned(uintptr): Smi;
@@ -2241,6 +2634,9 @@ FromConstexpr<ElementsKind, constexpr ElementsKind>(e: constexpr ElementsKind):
FromConstexpr<Object, constexpr string>(s: constexpr string): Object {
return StringConstant(s);
}
+FromConstexpr<JSAny, constexpr string>(s: constexpr string): JSAny {
+ return StringConstant(s);
+}
FromConstexpr<NativeContextSlot, constexpr NativeContextSlot>(
c: constexpr NativeContextSlot): NativeContextSlot {
return IntPtrConstant(c);
@@ -2384,20 +2780,9 @@ Convert<bint, Smi>(v: Smi): bint {
return SmiToBInt(v);
}
-macro BranchIf<A: type, B: type>(implicit context: Context)(o: B): never
- labels True, False {
- Cast<A>(o) otherwise False;
- goto True;
-}
-
-macro BranchIfNot<A: type, B: type>(implicit context: Context)(o: B): never
- labels True, False {
- Cast<A>(o) otherwise True;
- goto False;
-}
-
macro Is<A: type, B: type>(implicit context: Context)(o: B): bool {
- return (BranchIf<A, B>(o)) ? true : false;
+ Cast<A>(o) otherwise return false;
+ return true;
}
macro UnsafeCast<A: type>(implicit context: Context)(o: Object): A {
@@ -2405,17 +2790,15 @@ macro UnsafeCast<A: type>(implicit context: Context)(o: Object): A {
return %RawDownCast<A>(o);
}
-UnsafeCast<Object>(o: Object): Object {
- return o;
-}
+extern macro FixedArrayMapConstant(): Map;
+extern macro FixedCOWArrayMapConstant(): Map;
+extern macro EmptyByteArrayConstant(): ByteArray;
+extern macro EmptyFixedArrayConstant(): FixedArray;
-const kFixedArrayMap: Map =
- %RawDownCast<Map>(LoadRoot(kFixedArrayMapRootIndex));
-const kCOWMap: Map = %RawDownCast<Map>(LoadRoot(kFixedCOWArrayMapRootIndex));
-const kEmptyByteArray: ByteArray =
- %RawDownCast<ByteArray>(LoadRoot(kEmptyByteArrayRootIndex));
-const kEmptyFixedArray: FixedArray =
- %RawDownCast<FixedArray>(LoadRoot(kEmptyFixedArrayRootIndex));
+const kFixedArrayMap: Map = FixedArrayMapConstant();
+const kCOWMap: Map = FixedCOWArrayMapConstant();
+const kEmptyByteArray: ByteArray = EmptyByteArrayConstant();
+const kEmptyFixedArray: FixedArray = EmptyFixedArrayConstant();
extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map):
bool;
@@ -2478,6 +2861,8 @@ extern operator '.floats[]=' macro StoreFixedDoubleArrayElement(
FixedDoubleArray, intptr, float64): void;
extern operator '.floats[]=' macro StoreFixedDoubleArrayElementSmi(
FixedDoubleArray, Smi, float64): void;
+extern operator '.floats[]' macro LoadFixedDoubleArrayElement(
+ FixedDoubleArray, intptr): float64;
operator '[]=' macro StoreFixedDoubleArrayDirect(
a: FixedDoubleArray, i: Smi, v: Number) {
a.floats[i] = Convert<float64>(v);
@@ -2487,14 +2872,14 @@ operator '[]=' macro StoreFixedArrayDirect(a: FixedArray, i: Smi, v: Object) {
}
extern macro GetNumberDictionaryNumberOfElements(NumberDictionary): Smi;
-extern macro GetIteratorMethod(implicit context: Context)(HeapObject): Object
+extern macro GetIteratorMethod(implicit context: Context)(HeapObject): JSAny
labels IfIteratorUndefined;
extern macro LoadConstructorOrBackPointer(Map): Object;
-extern macro BasicLoadNumberDictionaryElement(NumberDictionary, intptr): Object
+extern macro BasicLoadNumberDictionaryElement(NumberDictionary, intptr): JSAny
labels NotData, IfHole;
-extern macro BasicStoreNumberDictionaryElement(NumberDictionary, intptr, Object)
+extern macro BasicStoreNumberDictionaryElement(NumberDictionary, intptr, JSAny)
labels NotData, IfHole, ReadOnly;
extern macro IsFastElementsKind(ElementsKind): bool;
@@ -2607,16 +2992,15 @@ macro GetRegExpLastMatchInfo(implicit context: Context)(): RegExpMatchInfo {
LoadNativeContext(context)[REGEXP_LAST_MATCH_INFO_INDEX]);
}
-extern transitioning macro Call(Context, Callable, Object): Object;
-extern transitioning macro Call(Context, Callable, Object, Object): Object;
-extern transitioning macro Call(
- Context, Callable, Object, Object, Object): Object;
+extern transitioning macro Call(Context, Callable, JSAny): JSAny;
+extern transitioning macro Call(Context, Callable, JSAny, JSAny): JSAny;
+extern transitioning macro Call(Context, Callable, JSAny, JSAny, JSAny): JSAny;
extern transitioning macro Call(
- Context, Callable, Object, Object, Object, Object): Object;
+ Context, Callable, JSAny, JSAny, JSAny, JSAny): JSAny;
extern transitioning macro Call(
- Context, Callable, Object, Object, Object, Object, Object): Object;
+ Context, Callable, JSAny, JSAny, JSAny, JSAny, JSAny): JSAny;
extern transitioning macro Call(
- Context, Callable, Object, Object, Object, Object, Object, Object): Object;
+ Context, Callable, JSAny, JSAny, JSAny, JSAny, JSAny, JSAny): JSAny;
extern builtin CloneFastJSArray(Context, FastJSArrayForCopy): JSArray;
extern macro ExtractFixedArray(FixedArrayBase, Smi, Smi, Smi): FixedArrayBase;
@@ -2665,20 +3049,24 @@ macro TorqueCopyElements(
count);
}
-macro LoadElementNoHole<T: type>(a: JSArray, index: Smi): Object
+macro LoadElementNoHole<T: type>(a: JSArray, index: Smi): JSAny
labels IfHole;
LoadElementNoHole<FixedArray>(implicit context: Context)(
- a: JSArray, index: Smi): Object
+ a: JSArray, index: Smi): JSAny
labels IfHole {
try {
const elements: FixedArray =
Cast<FixedArray>(a.elements) otherwise Unexpected;
- const e: Object = elements.objects[index];
- if (e == TheHole) {
- goto IfHole;
+ const e = UnsafeCast<(JSAny | TheHole)>(elements.objects[index]);
+ typeswitch (e) {
+ case (TheHole): {
+ goto IfHole;
+ }
+ case (e: JSAny): {
+ return e;
+ }
}
- return e;
}
label Unexpected {
unreachable;
@@ -2686,7 +3074,7 @@ LoadElementNoHole<FixedArray>(implicit context: Context)(
}
LoadElementNoHole<FixedDoubleArray>(implicit context: Context)(
- a: JSArray, index: Smi): Object
+ a: JSArray, index: Smi): JSAny
labels IfHole {
try {
const elements: FixedDoubleArray =
@@ -2717,7 +3105,7 @@ struct FastJSArrayWitness {
this.unstable = %RawDownCast<FastJSArray>(this.stable);
}
- LoadElementNoHole(implicit context: Context)(k: Smi): Object
+ LoadElementNoHole(implicit context: Context)(k: Smi): JSAny
labels FoundHole {
if (this.hasDoubles) {
return LoadElementNoHole<FixedDoubleArray>(this.unstable, k)
@@ -2740,7 +3128,7 @@ struct FastJSArrayWitness {
}
}
- LoadElementOrUndefined(implicit context: Context)(k: Smi): Object {
+ LoadElementOrUndefined(implicit context: Context)(k: Smi): JSAny {
try {
return this.LoadElementNoHole(k) otherwise FoundHole;
}
@@ -2760,7 +3148,7 @@ struct FastJSArrayWitness {
this.unstable.length = newLength;
}
- Push(value: Object) labels Failed {
+ Push(value: JSAny) labels Failed {
assert(this.arrayIsPushable);
if (this.hasDoubles) {
BuildAppendJSArray(HOLEY_DOUBLE_ELEMENTS, this.unstable, value)
@@ -2832,7 +3220,7 @@ struct FastJSArrayForReadWitness {
this.unstable = %RawDownCast<FastJSArrayForRead>(this.stable);
}
- LoadElementNoHole(implicit context: Context)(k: Smi): Object
+ LoadElementNoHole(implicit context: Context)(k: Smi): JSAny
labels FoundHole {
if (this.hasDoubles) {
return LoadElementNoHole<FixedDoubleArray>(this.unstable, k)
@@ -2876,6 +3264,7 @@ extern macro IsJSObject(HeapObject): bool;
extern macro IsJSTypedArray(HeapObject): bool;
extern macro IsNumberDictionary(HeapObject): bool;
extern macro IsContext(HeapObject): bool;
+extern macro IsNativeContext(HeapObject): bool;
extern macro IsJSReceiver(HeapObject): bool;
extern macro TaggedIsCallable(Object): bool;
extern macro IsDetachedBuffer(JSArrayBuffer): bool;
@@ -2892,7 +3281,7 @@ extern macro IsJSArrayMap(Map): bool;
extern macro IsExtensibleMap(Map): bool;
extern macro IsJSPrimitiveWrapper(HeapObject): bool;
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
-extern macro Typeof(Object): Object;
+extern macro Typeof(JSAny): String;
// Return true iff number is NaN.
macro NumberIsNaN(number: Number): bool {
@@ -2908,31 +3297,35 @@ macro NumberIsNaN(number: Number): bool {
}
extern macro GotoIfForceSlowPath() labels Taken;
-extern macro BranchIfToBooleanIsTrue(Object): never
+macro IsForceSlowPath(): bool {
+ GotoIfForceSlowPath() otherwise return true;
+ return false;
+}
+
+extern macro BranchIfToBooleanIsTrue(JSAny): never
labels Taken, NotTaken;
-extern macro BranchIfToBooleanIsFalse(Object): never
+extern macro BranchIfToBooleanIsFalse(JSAny): never
labels Taken, NotTaken;
-macro ToBoolean(obj: Object): bool {
- if (BranchIfToBooleanIsTrue(obj)) {
- return true;
- } else {
- return false;
- }
+macro ToBoolean(obj: JSAny): bool {
+ BranchIfToBooleanIsTrue(obj) otherwise return true, return false;
}
@export
macro RequireObjectCoercible(implicit context: Context)(
- value: Object, name: constexpr string): Object {
+ value: JSAny, name: constexpr string): JSAny {
if (IsNullOrUndefined(value)) {
ThrowTypeError(kCalledOnNullOrUndefined, name);
}
return value;
}
-extern macro BranchIfSameValue(Object, Object): never labels Taken, NotTaken;
+extern macro BranchIfSameValue(JSAny, JSAny): never labels Taken, NotTaken;
+macro SameValue(a: JSAny, b: JSAny): bool {
+ BranchIfSameValue(a, b) otherwise return true, return false;
+}
-transitioning macro ToIndex(input: Object, context: Context): Number
+transitioning macro ToIndex(input: JSAny, context: Context): Number
labels RangeError {
if (input == Undefined) {
return 0;
@@ -2946,7 +3339,7 @@ transitioning macro ToIndex(input: Object, context: Context): Number
return value;
}
-transitioning macro GetLengthProperty(implicit context: Context)(o: Object):
+transitioning macro GetLengthProperty(implicit context: Context)(o: JSAny):
Number {
try {
typeswitch (o) {
@@ -2956,18 +3349,18 @@ transitioning macro GetLengthProperty(implicit context: Context)(o: Object):
case (a: JSArgumentsObjectWithLength): {
goto ToLength(a.length);
}
- case (Object): deferred {
+ case (JSAny): deferred {
goto ToLength(GetProperty(o, kLengthString));
}
}
}
- label ToLength(length: Object) deferred {
+ label ToLength(length: JSAny) deferred {
return ToLength_Inline(context, length);
}
}
transitioning macro GetMethod(implicit context: Context)(
- o: Object, name: constexpr string): Callable labels IfNullOrUndefined {
+ o: JSAny, name: constexpr string): Callable labels IfNullOrUndefined {
const value = GetProperty(o, name);
if (value == Undefined || value == Null) goto IfNullOrUndefined;
return Cast<Callable>(value)
@@ -2976,44 +3369,37 @@ transitioning macro GetMethod(implicit context: Context)(
extern macro NumberToString(Number): String;
extern macro IsOneByteStringInstanceType(InstanceType): bool;
-extern macro AllocateSeqOneByteString(implicit context: Context)(uint32):
- String;
-extern macro AllocateSeqTwoByteString(implicit context: Context)(uint32):
- String;
+extern macro AllocateSeqOneByteString(uint32): String;
+extern macro AllocateSeqTwoByteString(uint32): String;
extern macro ConvertToRelativeIndex(implicit context: Context)(
- Object, intptr): intptr;
+ JSAny, intptr): intptr;
-extern builtin ObjectToString(Context, Object): Object;
+extern builtin ObjectToString(Context, JSAny): JSAny;
extern builtin StringRepeat(Context, String, Number): String;
struct KeyValuePair {
- key: Object;
- value: Object;
+ key: JSAny;
+ value: JSAny;
}
// Macro definitions for compatibility that expose functionality to the CSA
// using "legacy" APIs. In Torque code, these should not be used.
@export
macro IsFastJSArray(o: Object, context: Context): bool {
- try {
- // Long-term, it's likely not a good idea to have this slow-path test here,
- // since it fundamentally breaks the type system.
- GotoIfForceSlowPath() otherwise ForceSlow;
- }
- label ForceSlow {
- return false;
- }
-
+ // Long-term, it's likely not a good idea to have this slow-path test here,
+ // since it fundamentally breaks the type system.
+ if (IsForceSlowPath()) return false;
return Is<FastJSArray>(o);
}
@export
macro BranchIfFastJSArray(o: Object, context: Context): never labels True,
False {
- // Long-term, it's likely not a good idea to have this slow-path test here,
- // since it fundamentally breaks the type system.
- GotoIfForceSlowPath() otherwise False;
- BranchIf<FastJSArray>(o) otherwise True, False;
+ if (IsFastJSArray(o, context)) {
+ goto True;
+ } else {
+ goto False;
+ }
}
@export
@@ -3021,8 +3407,12 @@ macro BranchIfFastJSArrayForRead(o: Object, context: Context):
never labels True, False {
// Long-term, it's likely not a good idea to have this slow-path test here,
// since it fundamentally breaks the type system.
- GotoIfForceSlowPath() otherwise False;
- BranchIf<FastJSArrayForRead>(o) otherwise True, False;
+ if (IsForceSlowPath()) goto False;
+ if (Is<FastJSArrayForRead>(o)) {
+ goto True;
+ } else {
+ goto False;
+ }
}
@export
@@ -3037,7 +3427,7 @@ macro IsFastJSArrayForReadWithNoCustomIteration(context: Context, o: Object):
}
extern transitioning runtime
-CreateDataProperty(implicit context: Context)(JSReceiver, Object, Object);
+CreateDataProperty(implicit context: Context)(JSReceiver, JSAny, JSAny);
namespace runtime {
extern runtime
@@ -3045,7 +3435,7 @@ namespace runtime {
}
transitioning builtin FastCreateDataProperty(implicit context: Context)(
- receiver: JSReceiver, key: Object, value: Object): Object {
+ receiver: JSReceiver, key: JSAny, value: JSAny): Object {
try {
const array = Cast<FastJSArray>(receiver) otherwise Slow;
const index: Smi = Cast<Smi>(key) otherwise goto Slow;
@@ -3090,8 +3480,8 @@ transitioning builtin FastCreateDataProperty(implicit context: Context)(
}
@export
-transitioning macro ToStringImpl(context: Context, o: Object): String {
- let result: Object = o;
+transitioning macro ToStringImpl(context: Context, o: JSAny): String {
+ let result: JSAny = o;
while (true) {
typeswitch (result) {
case (num: Number): {
@@ -3110,7 +3500,7 @@ transitioning macro ToStringImpl(context: Context, o: Object): String {
case (Symbol): {
ThrowTypeError(kSymbolToString);
}
- case (Object): {
+ case (JSAny): {
return ToStringRT(context, o);
}
}
@@ -3160,3 +3550,14 @@ builtin CheckNumberInRange(implicit context: Context)(
unreachable;
}
}
+
+macro ReplaceTheHoleWithUndefined(o: JSAny | TheHole): JSAny {
+ typeswitch (o) {
+ case (TheHole): {
+ return Undefined;
+ }
+ case (a: JSAny): {
+ return a;
+ }
+ }
+}
diff --git a/deps/v8/src/builtins/boolean.tq b/deps/v8/src/builtins/boolean.tq
index 25f9ebd396..e8feaf1cf1 100644
--- a/deps/v8/src/builtins/boolean.tq
+++ b/deps/v8/src/builtins/boolean.tq
@@ -5,8 +5,8 @@
namespace boolean {
javascript builtin
BooleanConstructor(
- js-implicit context: Context, receiver: Object, newTarget: Object,
- target: JSFunction)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny, newTarget: JSAny,
+ target: JSFunction)(...arguments): JSAny {
const value = SelectBooleanConstant(ToBoolean(arguments[0]));
if (newTarget == Undefined) {
diff --git a/deps/v8/src/builtins/builtins-arguments-gen.cc b/deps/v8/src/builtins/builtins-arguments-gen.cc
index d65d57cc79..c4399175e9 100644
--- a/deps/v8/src/builtins/builtins-arguments-gen.cc
+++ b/deps/v8/src/builtins/builtins-arguments-gen.cc
@@ -40,20 +40,20 @@ ArgumentsBuiltinsAssembler::AllocateArgumentsObject(Node* map,
empty ? IntPtrConstant(base_size)
: ElementOffsetFromIndex(element_count, PACKED_ELEMENTS, mode,
base_size + FixedArray::kHeaderSize);
- TNode<Object> result = Allocate(size);
+ TNode<HeapObject> result = Allocate(size);
Comment("Initialize arguments object");
StoreMapNoWriteBarrier(result, map);
- Node* empty_fixed_array = LoadRoot(RootIndex::kEmptyFixedArray);
+ TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
StoreObjectField(result, JSArray::kPropertiesOrHashOffset, empty_fixed_array);
- Node* smi_arguments_count = ParameterToTagged(arguments_count, mode);
+ TNode<Smi> smi_arguments_count = ParameterToTagged(arguments_count, mode);
StoreObjectFieldNoWriteBarrier(result, JSArray::kLengthOffset,
smi_arguments_count);
Node* arguments = nullptr;
if (!empty) {
- arguments = InnerAllocate(CAST(result), elements_offset);
+ arguments = InnerAllocate(result, elements_offset);
StoreObjectFieldNoWriteBarrier(arguments, FixedArray::kLengthOffset,
smi_arguments_count);
- Node* fixed_array_map = LoadRoot(RootIndex::kFixedArrayMap);
+ TNode<Map> fixed_array_map = FixedArrayMapConstant();
StoreMapNoWriteBarrier(arguments, fixed_array_map);
}
Node* parameter_map = nullptr;
@@ -63,8 +63,7 @@ ArgumentsBuiltinsAssembler::AllocateArgumentsObject(Node* map,
parameter_map = InnerAllocate(CAST(arguments), parameter_map_offset);
StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset,
parameter_map);
- Node* sloppy_elements_map =
- LoadRoot(RootIndex::kSloppyArgumentsElementsMap);
+ TNode<Map> sloppy_elements_map = SloppyArgumentsElementsMapConstant();
StoreMapNoWriteBarrier(parameter_map, sloppy_elements_map);
parameter_map_count = ParameterToTagged(parameter_map_count, mode);
StoreObjectFieldNoWriteBarrier(parameter_map, FixedArray::kLengthOffset,
@@ -97,13 +96,14 @@ Node* ArgumentsBuiltinsAssembler::ConstructParametersObjectFromArgs(
VARIABLE(offset, MachineType::PointerRepresentation());
offset.Bind(IntPtrConstant(FixedArrayBase::kHeaderSize - kHeapObjectTag));
VariableList list({&offset}, zone());
- arguments.ForEach(list,
- [this, elements, &offset](Node* arg) {
- StoreNoWriteBarrier(MachineRepresentation::kTagged,
- elements, offset.value(), arg);
- Increment(&offset, kTaggedSize);
- },
- first_arg, nullptr, param_mode);
+ arguments.ForEach(
+ list,
+ [this, elements, &offset](Node* arg) {
+ StoreNoWriteBarrier(MachineRepresentation::kTagged, elements,
+ offset.value(), arg);
+ Increment(&offset, kTaggedSize);
+ },
+ first_arg, nullptr, param_mode);
return result;
}
@@ -121,8 +121,8 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewRestParameter(Node* context,
Node* rest_count =
IntPtrOrSmiSub(info.argument_count, info.formal_parameter_count, mode);
- Node* const native_context = LoadNativeContext(context);
- Node* const array_map =
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Map> const array_map =
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
GotoIf(IntPtrOrSmiLessThanOrEqual(rest_count, zero, mode),
&no_rest_parameters);
@@ -164,7 +164,7 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewStrictArguments(Node* context,
Label done(this, &result), empty(this), runtime(this, Label::kDeferred);
ParameterMode mode = OptimalParameterMode();
- Node* zero = IntPtrOrSmiConstant(0, mode);
+ TNode<BInt> zero = BIntConstant(0);
TorqueStructArgumentsInfo info = GetArgumentsFrameAndCount(
CAST(context), UncheckedCast<JSFunction>(function));
@@ -173,10 +173,10 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewStrictArguments(Node* context,
info.argument_count, &runtime,
JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
- Node* const native_context = LoadNativeContext(context);
- Node* const map =
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const map =
LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
- GotoIf(WordEqual(info.argument_count, zero), &empty);
+ GotoIf(BIntEqual(info.argument_count, zero), &empty);
result.Bind(ConstructParametersObjectFromArgs(
map, info.frame, info.argument_count, zero, info.argument_count, mode,
@@ -209,7 +209,7 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
VARIABLE(result, MachineRepresentation::kTagged);
ParameterMode mode = OptimalParameterMode();
- Node* zero = IntPtrOrSmiConstant(0, mode);
+ TNode<BInt> zero = BIntConstant(0);
Label done(this, &result), empty(this), no_parameters(this),
runtime(this, Label::kDeferred);
@@ -217,9 +217,9 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
TorqueStructArgumentsInfo info = GetArgumentsFrameAndCount(
CAST(context), UncheckedCast<JSFunction>(function));
- GotoIf(WordEqual(info.argument_count, zero), &empty);
+ GotoIf(BIntEqual(info.argument_count, zero), &empty);
- GotoIf(WordEqual(info.formal_parameter_count, zero), &no_parameters);
+ GotoIf(BIntEqual(info.formal_parameter_count, zero), &no_parameters);
{
Comment("Mapped parameter JSSloppyArgumentsObject");
@@ -237,8 +237,8 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
elements_allocated, &runtime,
JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize * 2, mode);
- Node* const native_context = LoadNativeContext(context);
- Node* const map = LoadContextElement(
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const map = LoadContextElement(
native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
Node* argument_object;
Node* elements;
@@ -252,26 +252,26 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
StoreFixedArrayElement(CAST(map_array), 1, elements, SKIP_WRITE_BARRIER);
Comment("Fill in non-mapped parameters");
- Node* argument_offset =
+ TNode<IntPtrT> argument_offset =
ElementOffsetFromIndex(info.argument_count, PACKED_ELEMENTS, mode,
FixedArray::kHeaderSize - kHeapObjectTag);
- Node* mapped_offset =
+ TNode<IntPtrT> mapped_offset =
ElementOffsetFromIndex(mapped_count, PACKED_ELEMENTS, mode,
FixedArray::kHeaderSize - kHeapObjectTag);
CodeStubArguments arguments(this, info.argument_count, info.frame, mode);
VARIABLE(current_argument, MachineType::PointerRepresentation());
current_argument.Bind(arguments.AtIndexPtr(info.argument_count, mode));
VariableList var_list1({&current_argument}, zone());
- mapped_offset = BuildFastLoop(
+ mapped_offset = UncheckedCast<IntPtrT>(BuildFastLoop(
var_list1, argument_offset, mapped_offset,
[this, elements, &current_argument](Node* offset) {
Increment(&current_argument, kSystemPointerSize);
- Node* arg = LoadBufferObject(
+ TNode<Object> arg = LoadBufferObject(
UncheckedCast<RawPtrT>(current_argument.value()), 0);
StoreNoWriteBarrier(MachineRepresentation::kTagged, elements, offset,
arg);
},
- -kTaggedSize, INTPTR_PARAMETERS);
+ -kTaggedSize, INTPTR_PARAMETERS));
// Copy the parameter slots and the holes in the arguments.
// We need to fill in mapped_count slots. They index the context,
@@ -287,13 +287,13 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
IntPtrOrSmiAdd(IntPtrOrSmiConstant(Context::MIN_CONTEXT_SLOTS, mode),
info.formal_parameter_count, mode),
mapped_count, mode));
- Node* the_hole = TheHoleConstant();
+ TNode<Oddball> the_hole = TheHoleConstant();
VariableList var_list2({&context_index}, zone());
const int kParameterMapHeaderSize = FixedArray::OffsetOfElementAt(2);
- Node* adjusted_map_array = IntPtrAdd(
+ TNode<IntPtrT> adjusted_map_array = IntPtrAdd(
BitcastTaggedToWord(map_array),
IntPtrConstant(kParameterMapHeaderSize - FixedArray::kHeaderSize));
- Node* zero_offset = ElementOffsetFromIndex(
+ TNode<IntPtrT> zero_offset = ElementOffsetFromIndex(
zero, PACKED_ELEMENTS, mode, FixedArray::kHeaderSize - kHeapObjectTag);
BuildFastLoop(
var_list2, mapped_offset, zero_offset,
@@ -317,8 +317,8 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
GotoIfFixedArraySizeDoesntFitInNewSpace(
info.argument_count, &runtime,
JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize, mode);
- Node* const native_context = LoadNativeContext(context);
- Node* const map =
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const map =
LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
result.Bind(ConstructParametersObjectFromArgs(
map, info.frame, info.argument_count, zero, info.argument_count, mode,
@@ -331,8 +331,8 @@ Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context,
BIND(&empty);
{
Comment("Empty JSSloppyArgumentsObject");
- Node* const native_context = LoadNativeContext(context);
- Node* const map =
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const map =
LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
Node* arguments;
Node* elements;
diff --git a/deps/v8/src/builtins/builtins-array-gen.cc b/deps/v8/src/builtins/builtins-array-gen.cc
index 07f74cb429..c7d8eb0091 100644
--- a/deps/v8/src/builtins/builtins-array-gen.cc
+++ b/deps/v8/src/builtins/builtins-array-gen.cc
@@ -30,272 +30,267 @@ ArrayBuiltinsAssembler::ArrayBuiltinsAssembler(
to_(this, MachineRepresentation::kTagged, SmiConstant(0)),
fully_spec_compliant_(this, {&k_, &a_, &to_}) {}
- void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() {
- // 6. Let A be ? TypedArraySpeciesCreate(O, len).
- TNode<JSTypedArray> original_array = CAST(o());
- TNode<Smi> length = CAST(len_);
- const char* method_name = "%TypedArray%.prototype.map";
-
- TNode<JSTypedArray> a = TypedArraySpeciesCreateByLength(
- context(), method_name, original_array, length);
- // In the Spec and our current implementation, the length check is already
- // performed in TypedArraySpeciesCreate.
- CSA_ASSERT(this, UintPtrLessThanOrEqual(SmiUntag(CAST(len_)),
- LoadJSTypedArrayLength(a)));
- fast_typed_array_target_ =
- Word32Equal(LoadElementsKind(original_array), LoadElementsKind(a));
- a_.Bind(a);
- }
-
- // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map.
- Node* ArrayBuiltinsAssembler::TypedArrayMapProcessor(Node* k_value, Node* k) {
- // 8. c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »).
- Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
- callbackfn(), this_arg(), k_value, k, o());
- Label fast(this), slow(this), done(this), detached(this, Label::kDeferred);
-
- // 8. d. Perform ? Set(A, Pk, mapped_value, true).
- // Since we know that A is a TypedArray, this always ends up in
- // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then
- // tc39.github.io/ecma262/#sec-integerindexedelementset .
- Branch(fast_typed_array_target_, &fast, &slow);
-
- BIND(&fast);
- // #sec-integerindexedelementset
- // 5. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let
- // numValue be ? ToBigInt(v).
- // 6. Otherwise, let numValue be ? ToNumber(value).
- Node* num_value;
- if (source_elements_kind_ == BIGINT64_ELEMENTS ||
- source_elements_kind_ == BIGUINT64_ELEMENTS) {
- num_value = ToBigInt(context(), mapped_value);
- } else {
- num_value = ToNumber_Inline(context(), mapped_value);
- }
- // The only way how this can bailout is because of a detached buffer.
- EmitElementStore(a(), k, num_value, source_elements_kind_,
- KeyedAccessStoreMode::STANDARD_STORE, &detached,
- context());
- Goto(&done);
+void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() {
+ // 6. Let A be ? TypedArraySpeciesCreate(O, len).
+ TNode<JSTypedArray> original_array = CAST(o());
+ TNode<Smi> length = CAST(len_);
+ const char* method_name = "%TypedArray%.prototype.map";
+
+ TNode<JSTypedArray> a = TypedArraySpeciesCreateByLength(
+ context(), method_name, original_array, length);
+ // In the Spec and our current implementation, the length check is already
+ // performed in TypedArraySpeciesCreate.
+ CSA_ASSERT(this, UintPtrLessThanOrEqual(SmiUntag(CAST(len_)),
+ LoadJSTypedArrayLength(a)));
+ fast_typed_array_target_ =
+ Word32Equal(LoadElementsKind(original_array), LoadElementsKind(a));
+ a_.Bind(a);
+}
- BIND(&slow);
- SetPropertyStrict(context(), CAST(a()), CAST(k), CAST(mapped_value));
- Goto(&done);
+// See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map.
+Node* ArrayBuiltinsAssembler::TypedArrayMapProcessor(Node* k_value, Node* k) {
+ // 8. c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »).
+ Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
+ callbackfn(), this_arg(), k_value, k, o());
+ Label fast(this), slow(this), done(this), detached(this, Label::kDeferred);
- BIND(&detached);
- // tc39.github.io/ecma262/#sec-integerindexedelementset
- // 8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
- ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
+ // 8. d. Perform ? Set(A, Pk, mapped_value, true).
+ // Since we know that A is a TypedArray, this always ends up in
+ // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then
+ // tc39.github.io/ecma262/#sec-integerindexedelementset .
+ Branch(fast_typed_array_target_, &fast, &slow);
- BIND(&done);
- return a();
+ BIND(&fast);
+ // #sec-integerindexedelementset
+ // 5. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let
+ // numValue be ? ToBigInt(v).
+ // 6. Otherwise, let numValue be ? ToNumber(value).
+ Node* num_value;
+ if (source_elements_kind_ == BIGINT64_ELEMENTS ||
+ source_elements_kind_ == BIGUINT64_ELEMENTS) {
+ num_value = ToBigInt(context(), mapped_value);
+ } else {
+ num_value = ToNumber_Inline(context(), mapped_value);
}
+ // The only way how this can bailout is because of a detached buffer.
+ EmitElementStore(a(), k, num_value, source_elements_kind_,
+ KeyedAccessStoreMode::STANDARD_STORE, &detached, context());
+ Goto(&done);
- void ArrayBuiltinsAssembler::NullPostLoopAction() {}
-
- void ArrayBuiltinsAssembler::FillFixedArrayWithSmiZero(
- TNode<FixedArray> array, TNode<Smi> smi_length) {
- CSA_ASSERT(this, Word32BinaryNot(IsFixedDoubleArray(array)));
+ BIND(&slow);
+ SetPropertyStrict(context(), CAST(a()), CAST(k), CAST(mapped_value));
+ Goto(&done);
- TNode<IntPtrT> length = SmiToIntPtr(smi_length);
- TNode<WordT> byte_length = TimesTaggedSize(length);
- CSA_ASSERT(this, UintPtrLessThan(length, byte_length));
+ BIND(&detached);
+ // tc39.github.io/ecma262/#sec-integerindexedelementset
+ // 8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
+ ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
- static const int32_t fa_base_data_offset =
- FixedArray::kHeaderSize - kHeapObjectTag;
- TNode<IntPtrT> backing_store = IntPtrAdd(
- BitcastTaggedToWord(array), IntPtrConstant(fa_base_data_offset));
+ BIND(&done);
+ return a();
+}
- // Call out to memset to perform initialization.
- TNode<ExternalReference> memset =
- ExternalConstant(ExternalReference::libc_memset_function());
- STATIC_ASSERT(kSizetSize == kIntptrSize);
- CallCFunction(memset, MachineType::Pointer(),
- std::make_pair(MachineType::Pointer(), backing_store),
- std::make_pair(MachineType::IntPtr(), IntPtrConstant(0)),
- std::make_pair(MachineType::UintPtr(), byte_length));
- }
+void ArrayBuiltinsAssembler::NullPostLoopAction() {}
+
+void ArrayBuiltinsAssembler::FillFixedArrayWithSmiZero(TNode<FixedArray> array,
+ TNode<Smi> smi_length) {
+ CSA_ASSERT(this, Word32BinaryNot(IsFixedDoubleArray(array)));
+
+ TNode<IntPtrT> length = SmiToIntPtr(smi_length);
+ TNode<IntPtrT> byte_length = TimesTaggedSize(length);
+ CSA_ASSERT(this, UintPtrLessThan(length, byte_length));
+
+ static const int32_t fa_base_data_offset =
+ FixedArray::kHeaderSize - kHeapObjectTag;
+ TNode<IntPtrT> backing_store = IntPtrAdd(BitcastTaggedToWord(array),
+ IntPtrConstant(fa_base_data_offset));
+
+ // Call out to memset to perform initialization.
+ TNode<ExternalReference> memset =
+ ExternalConstant(ExternalReference::libc_memset_function());
+ STATIC_ASSERT(kSizetSize == kIntptrSize);
+ CallCFunction(memset, MachineType::Pointer(),
+ std::make_pair(MachineType::Pointer(), backing_store),
+ std::make_pair(MachineType::IntPtr(), IntPtrConstant(0)),
+ std::make_pair(MachineType::UintPtr(), byte_length));
+}
- void ArrayBuiltinsAssembler::ReturnFromBuiltin(Node* value) {
- if (argc_ == nullptr) {
- Return(value);
- } else {
- // argc_ doesn't include the receiver, so it has to be added back in
- // manually.
- PopAndReturn(IntPtrAdd(argc_, IntPtrConstant(1)), value);
- }
+void ArrayBuiltinsAssembler::ReturnFromBuiltin(Node* value) {
+ if (argc_ == nullptr) {
+ Return(value);
+ } else {
+ // argc_ doesn't include the receiver, so it has to be added back in
+ // manually.
+ PopAndReturn(IntPtrAdd(argc_, IntPtrConstant(1)), value);
}
+}
- void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinBody(
- TNode<Context> context, TNode<Object> receiver, Node* callbackfn,
- Node* this_arg, TNode<IntPtrT> argc) {
- context_ = context;
- receiver_ = receiver;
- callbackfn_ = callbackfn;
- this_arg_ = this_arg;
- argc_ = argc;
- }
+void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinBody(
+ TNode<Context> context, TNode<Object> receiver, Node* callbackfn,
+ Node* this_arg, TNode<IntPtrT> argc) {
+ context_ = context;
+ receiver_ = receiver;
+ callbackfn_ = callbackfn;
+ this_arg_ = this_arg;
+ argc_ = argc;
+}
- void ArrayBuiltinsAssembler::GenerateIteratingTypedArrayBuiltinBody(
- const char* name, const BuiltinResultGenerator& generator,
- const CallResultProcessor& processor, const PostLoopAction& action,
- ForEachDirection direction) {
- name_ = name;
+void ArrayBuiltinsAssembler::GenerateIteratingTypedArrayBuiltinBody(
+ const char* name, const BuiltinResultGenerator& generator,
+ const CallResultProcessor& processor, const PostLoopAction& action,
+ ForEachDirection direction) {
+ name_ = name;
- // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray
+ // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray
- Label throw_not_typed_array(this, Label::kDeferred);
+ Label throw_not_typed_array(this, Label::kDeferred);
- GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array);
- TNode<Map> typed_array_map = LoadMap(CAST(receiver_));
- GotoIfNot(IsJSTypedArrayMap(typed_array_map), &throw_not_typed_array);
+ GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array);
+ TNode<Map> typed_array_map = LoadMap(CAST(receiver_));
+ GotoIfNot(IsJSTypedArrayMap(typed_array_map), &throw_not_typed_array);
- TNode<JSTypedArray> typed_array = CAST(receiver_);
- o_ = typed_array;
+ TNode<JSTypedArray> typed_array = CAST(receiver_);
+ o_ = typed_array;
- TNode<JSArrayBuffer> array_buffer =
- LoadJSArrayBufferViewBuffer(typed_array);
- ThrowIfArrayBufferIsDetached(context_, array_buffer, name_);
+ TNode<JSArrayBuffer> array_buffer = LoadJSArrayBufferViewBuffer(typed_array);
+ ThrowIfArrayBufferIsDetached(context_, array_buffer, name_);
- len_ = ChangeUintPtrToTagged(LoadJSTypedArrayLength(typed_array));
+ len_ = ChangeUintPtrToTagged(LoadJSTypedArrayLength(typed_array));
- Label throw_not_callable(this, Label::kDeferred);
- Label distinguish_types(this);
- GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable);
- Branch(IsCallableMap(LoadMap(callbackfn_)), &distinguish_types,
- &throw_not_callable);
+ Label throw_not_callable(this, Label::kDeferred);
+ Label distinguish_types(this);
+ GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable);
+ Branch(IsCallableMap(LoadMap(callbackfn_)), &distinguish_types,
+ &throw_not_callable);
- BIND(&throw_not_typed_array);
- ThrowTypeError(context_, MessageTemplate::kNotTypedArray);
+ BIND(&throw_not_typed_array);
+ ThrowTypeError(context_, MessageTemplate::kNotTypedArray);
- BIND(&throw_not_callable);
- ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_);
+ BIND(&throw_not_callable);
+ ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_);
- Label unexpected_instance_type(this);
- BIND(&unexpected_instance_type);
- Unreachable();
+ Label unexpected_instance_type(this);
+ BIND(&unexpected_instance_type);
+ Unreachable();
- std::vector<int32_t> elements_kinds = {
+ std::vector<int32_t> elements_kinds = {
#define ELEMENTS_KIND(Type, type, TYPE, ctype) TYPE##_ELEMENTS,
- TYPED_ARRAYS(ELEMENTS_KIND)
+ TYPED_ARRAYS(ELEMENTS_KIND)
#undef ELEMENTS_KIND
- };
- std::list<Label> labels;
- for (size_t i = 0; i < elements_kinds.size(); ++i) {
- labels.emplace_back(this);
- }
- std::vector<Label*> label_ptrs;
- for (Label& label : labels) {
- label_ptrs.push_back(&label);
- }
+ };
+ std::list<Label> labels;
+ for (size_t i = 0; i < elements_kinds.size(); ++i) {
+ labels.emplace_back(this);
+ }
+ std::vector<Label*> label_ptrs;
+ for (Label& label : labels) {
+ label_ptrs.push_back(&label);
+ }
- BIND(&distinguish_types);
+ BIND(&distinguish_types);
- generator(this);
+ generator(this);
- if (direction == ForEachDirection::kForward) {
- k_.Bind(SmiConstant(0));
- } else {
- k_.Bind(NumberDec(len()));
- }
- CSA_ASSERT(this, IsSafeInteger(k()));
- TNode<Int32T> elements_kind = LoadMapElementsKind(typed_array_map);
- Switch(elements_kind, &unexpected_instance_type, elements_kinds.data(),
- label_ptrs.data(), labels.size());
-
- size_t i = 0;
- for (auto it = labels.begin(); it != labels.end(); ++i, ++it) {
- BIND(&*it);
- Label done(this);
- source_elements_kind_ = static_cast<ElementsKind>(elements_kinds[i]);
- // TODO(tebbi): Silently cancelling the loop on buffer detachment is a
- // spec violation. Should go to &throw_detached and throw a TypeError
- // instead.
- VisitAllTypedArrayElements(array_buffer, processor, &done, direction,
- typed_array);
- Goto(&done);
- // No exception, return success
- BIND(&done);
- action(this);
- ReturnFromBuiltin(a_.value());
- }
+ if (direction == ForEachDirection::kForward) {
+ k_.Bind(SmiConstant(0));
+ } else {
+ k_.Bind(NumberDec(len()));
+ }
+ CSA_ASSERT(this, IsSafeInteger(k()));
+ TNode<Int32T> elements_kind = LoadMapElementsKind(typed_array_map);
+ Switch(elements_kind, &unexpected_instance_type, elements_kinds.data(),
+ label_ptrs.data(), labels.size());
+
+ size_t i = 0;
+ for (auto it = labels.begin(); it != labels.end(); ++i, ++it) {
+ BIND(&*it);
+ Label done(this);
+ source_elements_kind_ = static_cast<ElementsKind>(elements_kinds[i]);
+ // TODO(tebbi): Silently cancelling the loop on buffer detachment is a
+ // spec violation. Should go to &throw_detached and throw a TypeError
+ // instead.
+ VisitAllTypedArrayElements(array_buffer, processor, &done, direction,
+ typed_array);
+ Goto(&done);
+ // No exception, return success
+ BIND(&done);
+ action(this);
+ ReturnFromBuiltin(a_.value());
}
+}
- void ArrayBuiltinsAssembler::VisitAllTypedArrayElements(
- Node* array_buffer, const CallResultProcessor& processor, Label* detached,
- ForEachDirection direction, TNode<JSTypedArray> typed_array) {
- VariableList list({&a_, &k_, &to_}, zone());
-
- FastLoopBody body = [&](Node* index) {
- GotoIf(IsDetachedBuffer(CAST(array_buffer)), detached);
- TNode<RawPtrT> data_ptr = LoadJSTypedArrayBackingStore(typed_array);
- Node* value = LoadFixedTypedArrayElementAsTagged(
- data_ptr, index, source_elements_kind_, SMI_PARAMETERS);
- k_.Bind(index);
- a_.Bind(processor(this, value, index));
- };
- Node* start = SmiConstant(0);
- Node* end = len_;
- IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost;
- int incr = 1;
- if (direction == ForEachDirection::kReverse) {
- std::swap(start, end);
- advance_mode = IndexAdvanceMode::kPre;
- incr = -1;
- }
- BuildFastLoop(list, start, end, body, incr, ParameterMode::SMI_PARAMETERS,
- advance_mode);
- }
-
- // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
- void ArrayBuiltinsAssembler::GenerateArraySpeciesCreate(TNode<Number> len) {
- Label runtime(this, Label::kDeferred), done(this);
-
- Node* const original_map = LoadMap(o());
- GotoIfNot(
- InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
- &runtime);
-
- GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
- &runtime);
-
- Node* species_protector = ArraySpeciesProtectorConstant();
- Node* value =
- LoadObjectField(species_protector, PropertyCell::kValueOffset);
- Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
- GotoIf(WordEqual(value, protector_invalid), &runtime);
-
- GotoIfNot(TaggedIsPositiveSmi(len), &runtime);
- GotoIfNot(
- IsValidFastJSArrayCapacity(len, CodeStubAssembler::SMI_PARAMETERS),
- &runtime);
-
- // We need to be conservative and start with holey because the builtins
- // that create output arrays aren't guaranteed to be called for every
- // element in the input array (maybe the callback deletes an element).
- const ElementsKind elements_kind =
- GetHoleyElementsKind(GetInitialFastElementsKind());
- TNode<Context> native_context = LoadNativeContext(context());
- TNode<Map> array_map =
- LoadJSArrayElementsMap(elements_kind, native_context);
- a_.Bind(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, len, CAST(len),
- nullptr, CodeStubAssembler::SMI_PARAMETERS,
- kAllowLargeObjectAllocation));
+void ArrayBuiltinsAssembler::VisitAllTypedArrayElements(
+ Node* array_buffer, const CallResultProcessor& processor, Label* detached,
+ ForEachDirection direction, TNode<JSTypedArray> typed_array) {
+ VariableList list({&a_, &k_, &to_}, zone());
+
+ FastLoopBody body = [&](Node* index) {
+ GotoIf(IsDetachedBuffer(CAST(array_buffer)), detached);
+ TNode<RawPtrT> data_ptr = LoadJSTypedArrayBackingStore(typed_array);
+ auto value = LoadFixedTypedArrayElementAsTagged(
+ data_ptr, index, source_elements_kind_, SMI_PARAMETERS);
+ k_.Bind(index);
+ a_.Bind(processor(this, value, index));
+ };
+ Node* start = SmiConstant(0);
+ Node* end = len_;
+ IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost;
+ int incr = 1;
+ if (direction == ForEachDirection::kReverse) {
+ std::swap(start, end);
+ advance_mode = IndexAdvanceMode::kPre;
+ incr = -1;
+ }
+ BuildFastLoop(list, start, end, body, incr, ParameterMode::SMI_PARAMETERS,
+ advance_mode);
+}
- Goto(&done);
+// Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
+void ArrayBuiltinsAssembler::GenerateArraySpeciesCreate(TNode<Number> len) {
+ Label runtime(this, Label::kDeferred), done(this);
- BIND(&runtime);
- {
- // 5. Let A be ? ArraySpeciesCreate(O, len).
- TNode<JSReceiver> constructor =
- CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context(), o()));
- a_.Bind(Construct(context(), constructor, len));
- Goto(&fully_spec_compliant_);
- }
+ TNode<Map> const original_map = LoadMap(o());
+ GotoIfNot(InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
+ &runtime);
- BIND(&done);
+ GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
+ &runtime);
+
+ TNode<PropertyCell> species_protector = ArraySpeciesProtectorConstant();
+ TNode<Object> value =
+ LoadObjectField(species_protector, PropertyCell::kValueOffset);
+ TNode<Smi> const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
+ GotoIf(TaggedEqual(value, protector_invalid), &runtime);
+
+ GotoIfNot(TaggedIsPositiveSmi(len), &runtime);
+ GotoIfNot(IsValidFastJSArrayCapacity(len, CodeStubAssembler::SMI_PARAMETERS),
+ &runtime);
+
+ // We need to be conservative and start with holey because the builtins
+ // that create output arrays aren't guaranteed to be called for every
+ // element in the input array (maybe the callback deletes an element).
+ const ElementsKind elements_kind =
+ GetHoleyElementsKind(GetInitialFastElementsKind());
+ TNode<NativeContext> native_context = LoadNativeContext(context());
+ TNode<Map> array_map = LoadJSArrayElementsMap(elements_kind, native_context);
+ a_.Bind(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, len, CAST(len),
+ nullptr, CodeStubAssembler::SMI_PARAMETERS,
+ kAllowLargeObjectAllocation));
+
+ Goto(&done);
+
+ BIND(&runtime);
+ {
+ // 5. Let A be ? ArraySpeciesCreate(O, len).
+ TNode<JSReceiver> constructor =
+ CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context(), o()));
+ a_.Bind(Construct(context(), constructor, len));
+ Goto(&fully_spec_compliant_);
}
+ BIND(&done);
+}
+
TF_BUILTIN(ArrayPrototypePop, CodeStubAssembler) {
TNode<Int32T> argc =
UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
@@ -331,7 +326,7 @@ TF_BUILTIN(ArrayPrototypePop, CodeStubAssembler) {
// 3) Check that the elements backing store isn't copy-on-write.
TNode<FixedArrayBase> elements = LoadElements(array_receiver);
- GotoIf(WordEqual(LoadMap(elements), LoadRoot(RootIndex::kFixedCOWArrayMap)),
+ GotoIf(TaggedEqual(LoadMap(elements), FixedCOWArrayMapConstant()),
&runtime);
TNode<IntPtrT> new_length = IntPtrSub(length, IntPtrConstant(1));
@@ -353,17 +348,24 @@ TF_BUILTIN(ArrayPrototypePop, CodeStubAssembler) {
Int32Constant(TERMINAL_FAST_ELEMENTS_KIND)),
&fast_elements);
- Node* value = LoadFixedDoubleArrayElement(CAST(elements), new_length,
- &return_undefined);
+ {
+ TNode<FixedDoubleArray> elements_known_double_array =
+ ReinterpretCast<FixedDoubleArray>(elements);
+ TNode<Float64T> value = LoadFixedDoubleArrayElement(
+ elements_known_double_array, new_length, &return_undefined);
- StoreFixedDoubleArrayHole(CAST(elements), new_length);
- args.PopAndReturn(AllocateHeapNumberWithValue(value));
+ StoreFixedDoubleArrayHole(elements_known_double_array, new_length);
+ args.PopAndReturn(AllocateHeapNumberWithValue(value));
+ }
BIND(&fast_elements);
{
- Node* value = LoadFixedArrayElement(CAST(elements), new_length);
- StoreFixedArrayElement(CAST(elements), new_length, TheHoleConstant());
- GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
+ TNode<FixedArray> elements_known_fixed_array = CAST(elements);
+ TNode<Object> value =
+ LoadFixedArrayElement(elements_known_fixed_array, new_length);
+ StoreFixedArrayElement(elements_known_fixed_array, new_length,
+ TheHoleConstant());
+ GotoIf(TaggedEqual(value, TheHoleConstant()), &return_undefined);
args.PopAndReturn(value);
}
@@ -415,8 +417,9 @@ TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) {
GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
&object_push_pre);
- Node* new_length = BuildAppendJSArray(PACKED_SMI_ELEMENTS, array_receiver,
- &args, &arg_index, &smi_transition);
+ TNode<Smi> new_length =
+ BuildAppendJSArray(PACKED_SMI_ELEMENTS, array_receiver, &args,
+ &arg_index, &smi_transition);
args.PopAndReturn(new_length);
}
@@ -426,16 +429,16 @@ TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) {
// the most generic implementation for the rest of the array.
BIND(&smi_transition);
{
- Node* arg = args.AtIndex(arg_index.value());
+ TNode<Object> arg = args.AtIndex(arg_index.value());
GotoIf(TaggedIsSmi(arg), &default_label);
- Node* length = LoadJSArrayLength(array_receiver);
+ TNode<Number> length = LoadJSArrayLength(array_receiver);
// TODO(danno): Use the KeyedStoreGeneric stub here when possible,
// calling into the runtime to do the elements transition is overkill.
- SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
+ SetPropertyStrict(context, array_receiver, length, arg);
Increment(&arg_index);
// The runtime SetProperty call could have converted the array to dictionary
// mode, which must be detected to abort the fast-path.
- Node* kind = LoadElementsKind(array_receiver);
+ TNode<Int32T> kind = LoadElementsKind(array_receiver);
GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
&default_label);
@@ -451,14 +454,14 @@ TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) {
BIND(&object_push);
{
- Node* new_length = BuildAppendJSArray(PACKED_ELEMENTS, array_receiver,
- &args, &arg_index, &default_label);
+ TNode<Smi> new_length = BuildAppendJSArray(
+ PACKED_ELEMENTS, array_receiver, &args, &arg_index, &default_label);
args.PopAndReturn(new_length);
}
BIND(&double_push);
{
- Node* new_length =
+ TNode<Smi> new_length =
BuildAppendJSArray(PACKED_DOUBLE_ELEMENTS, array_receiver, &args,
&arg_index, &double_transition);
args.PopAndReturn(new_length);
@@ -470,16 +473,16 @@ TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) {
// on the most generic implementation for the rest of the array.
BIND(&double_transition);
{
- Node* arg = args.AtIndex(arg_index.value());
+ TNode<Object> arg = args.AtIndex(arg_index.value());
GotoIfNumber(arg, &default_label);
- Node* length = LoadJSArrayLength(array_receiver);
+ TNode<Number> length = LoadJSArrayLength(array_receiver);
// TODO(danno): Use the KeyedStoreGeneric stub here when possible,
// calling into the runtime to do the elements transition is overkill.
- SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
+ SetPropertyStrict(context, array_receiver, length, arg);
Increment(&arg_index);
// The runtime SetProperty call could have converted the array to dictionary
// mode, which must be detected to abort the fast-path.
- Node* kind = LoadElementsKind(array_receiver);
+ TNode<Int32T> kind = LoadElementsKind(array_receiver);
GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
&default_label);
Goto(&object_push);
@@ -491,8 +494,8 @@ TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) {
{
args.ForEach(
[this, array_receiver, context](Node* arg) {
- Node* length = LoadJSArrayLength(array_receiver);
- SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
+ TNode<Number> length = LoadJSArrayLength(array_receiver);
+ SetPropertyStrict(context, array_receiver, length, CAST(arg));
},
arg_index.value());
args.PopAndReturn(LoadJSArrayLength(array_receiver));
@@ -635,7 +638,7 @@ TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
GotoIfNot(Word32Equal(argc, Int32Constant(1)), &normal_iterate);
TNode<Object> array_function = LoadContextElement(
LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
- Branch(WordEqual(array_function, receiver), &fast_iterate, &normal_iterate);
+ Branch(TaggedEqual(array_function, receiver), &fast_iterate, &normal_iterate);
BIND(&fast_iterate);
{
@@ -674,7 +677,7 @@ TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
// Determine whether items[Symbol.iterator] is defined:
IteratorBuiltinsAssembler iterator_assembler(state());
- Node* iterator_method =
+ TNode<Object> iterator_method =
iterator_assembler.GetIteratorMethod(context, array_like);
Branch(IsNullOrUndefined(iterator_method), &not_iterable, &iterable);
@@ -708,7 +711,7 @@ TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
IteratorRecord iterator_record =
iterator_assembler.GetIterator(context, items, iterator_method);
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> fast_iterator_result_map = CAST(
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX));
@@ -741,7 +744,7 @@ TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
// Store the result in the output object (catching any exceptions so the
// iterator can be closed).
- Node* define_status =
+ TNode<Object> define_status =
CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
index.value(), value.value());
GotoIfException(define_status, &on_exception, &var_exception);
@@ -789,9 +792,7 @@ TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
TVARIABLE(Number, index, SmiConstant(0));
- // TODO(ishell): remove <Object, Object>
- GotoIf(WordEqual<Object, Object>(length.value(), SmiConstant(0)),
- &finished);
+ GotoIf(TaggedEqual(length.value(), SmiConstant(0)), &finished);
// Loop from 0 to length-1.
{
@@ -837,8 +838,8 @@ TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) {
CodeStubArguments args(this, argc);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = args.GetReceiver();
- Node* callbackfn = args.GetOptionalArgumentValue(0);
- Node* this_arg = args.GetOptionalArgumentValue(1);
+ TNode<Object> callbackfn = args.GetOptionalArgumentValue(0);
+ TNode<Object> this_arg = args.GetOptionalArgumentValue(1);
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
@@ -856,7 +857,7 @@ TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
Label call_runtime(this), return_true(this), return_false(this);
GotoIf(TaggedIsSmi(object), &return_false);
- TNode<Int32T> instance_type = LoadInstanceType(CAST(object));
+ TNode<Uint16T> instance_type = LoadInstanceType(CAST(object));
GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &return_true);
@@ -884,7 +885,7 @@ class ArrayIncludesIndexofAssembler : public CodeStubAssembler {
void Generate(SearchVariant variant, TNode<IntPtrT> argc,
TNode<Context> context);
void GenerateSmiOrObject(SearchVariant variant, Node* context, Node* elements,
- Node* search_element, Node* array_length,
+ TNode<Object> search_element, Node* array_length,
Node* from_index);
void GeneratePackedDoubles(SearchVariant variant, Node* elements,
Node* search_element, Node* array_length,
@@ -906,7 +907,7 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
TNode<Object> search_element =
args.GetOptionalArgumentValue(kSearchElementArg);
- Node* intptr_zero = IntPtrConstant(0);
+ TNode<IntPtrT> intptr_zero = IntPtrConstant(0);
Label init_index(this), return_not_found(this), call_runtime(this);
@@ -920,8 +921,8 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
// JSArray length is always a positive Smi for fast arrays.
CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array)));
- Node* array_length = LoadFastJSArrayLength(array);
- Node* array_length_untagged = SmiUntag(array_length);
+ TNode<Smi> array_length = LoadFastJSArrayLength(array);
+ TNode<IntPtrT> array_length_untagged = SmiUntag(array_length);
{
// Initialize fromIndex.
@@ -930,7 +931,7 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
// If no fromIndex was passed, default to 0.
GotoIf(IntPtrLessThanOrEqual(argc, IntPtrConstant(kFromIndexArg)), &done);
- Node* start_from = args.AtIndex(kFromIndexArg);
+ TNode<Object> start_from = args.AtIndex(kFromIndexArg);
// Handle Smis and undefined here and everything else in runtime.
// We must be very careful with side effects from the ToInteger conversion,
// as the side effects might render previously checked assumptions about
@@ -944,7 +945,7 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
}
BIND(&is_smi);
{
- Node* intptr_start_from = SmiUntag(start_from);
+ TNode<IntPtrT> intptr_start_from = SmiUntag(CAST(start_from));
index_var.Bind(intptr_start_from);
GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
@@ -965,7 +966,7 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
TNode<Int32T> elements_kind = LoadElementsKind(array);
- Node* elements = LoadElements(array);
+ TNode<FixedArrayBase> elements = LoadElements(array);
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
STATIC_ASSERT(PACKED_ELEMENTS == 2);
@@ -977,9 +978,9 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
&if_packed_doubles);
GotoIf(ElementsKindEqual(elements_kind, Int32Constant(HOLEY_DOUBLE_ELEMENTS)),
&if_holey_doubles);
- GotoIf(
- IsElementsKindLessThanOrEqual(elements_kind, LAST_FROZEN_ELEMENTS_KIND),
- &if_smiorobjects);
+ GotoIf(IsElementsKindLessThanOrEqual(elements_kind,
+ LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND),
+ &if_smiorobjects);
Goto(&return_not_found);
BIND(&if_smiorobjects);
@@ -990,8 +991,8 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
Builtins::kArrayIncludesSmiOrObject)
: Builtins::CallableFor(isolate(),
Builtins::kArrayIndexOfSmiOrObject);
- Node* result = CallStub(callable, context, elements, search_element,
- array_length, SmiTag(index_var.value()));
+ TNode<Object> result = CallStub(callable, context, elements, search_element,
+ array_length, SmiTag(index_var.value()));
args.PopAndReturn(result);
}
@@ -1003,8 +1004,8 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
Builtins::kArrayIncludesPackedDoubles)
: Builtins::CallableFor(isolate(),
Builtins::kArrayIndexOfPackedDoubles);
- Node* result = CallStub(callable, context, elements, search_element,
- array_length, SmiTag(index_var.value()));
+ TNode<Object> result = CallStub(callable, context, elements, search_element,
+ array_length, SmiTag(index_var.value()));
args.PopAndReturn(result);
}
@@ -1016,8 +1017,8 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
Builtins::kArrayIncludesHoleyDoubles)
: Builtins::CallableFor(isolate(),
Builtins::kArrayIndexOfHoleyDoubles);
- Node* result = CallStub(callable, context, elements, search_element,
- array_length, SmiTag(index_var.value()));
+ TNode<Object> result = CallStub(callable, context, elements, search_element,
+ array_length, SmiTag(index_var.value()));
args.PopAndReturn(result);
}
@@ -1030,7 +1031,7 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
BIND(&call_runtime);
{
- Node* start_from =
+ TNode<Object> start_from =
args.GetOptionalArgumentValue(kFromIndexArg, UndefinedConstant());
Runtime::FunctionId function = variant == kIncludes
? Runtime::kArrayIncludes_Slow
@@ -1041,12 +1042,11 @@ void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
}
void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
- SearchVariant variant, Node* context, Node* elements, Node* search_element,
- Node* array_length, Node* from_index) {
- VARIABLE(index_var, MachineType::PointerRepresentation(),
- SmiUntag(from_index));
- VARIABLE(search_num, MachineRepresentation::kFloat64);
- Node* array_length_untagged = SmiUntag(array_length);
+ SearchVariant variant, Node* context, Node* elements,
+ TNode<Object> search_element, Node* array_length, Node* from_index) {
+ TVARIABLE(IntPtrT, index_var, SmiUntag(from_index));
+ TVARIABLE(Float64T, search_num);
+ TNode<IntPtrT> array_length_untagged = SmiUntag(array_length);
Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
string_loop(this), bigint_loop(this, &index_var),
@@ -1054,20 +1054,20 @@ void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
return_found(this), return_not_found(this);
GotoIfNot(TaggedIsSmi(search_element), &not_smi);
- search_num.Bind(SmiToFloat64(search_element));
+ search_num = SmiToFloat64(CAST(search_element));
Goto(&heap_num_loop);
BIND(&not_smi);
if (variant == kIncludes) {
GotoIf(IsUndefined(search_element), &undef_loop);
}
- Node* map = LoadMap(search_element);
+ TNode<Map> map = LoadMap(CAST(search_element));
GotoIfNot(IsHeapNumberMap(map), &not_heap_num);
- search_num.Bind(LoadHeapNumberValue(search_element));
+ search_num = LoadHeapNumberValue(CAST(search_element));
Goto(&heap_num_loop);
BIND(&not_heap_num);
- Node* search_type = LoadMapInstanceType(map);
+ TNode<Uint16T> search_type = LoadMapInstanceType(map);
GotoIf(IsStringInstanceType(search_type), &string_loop);
GotoIf(IsBigIntInstanceType(search_type), &bigint_loop);
Goto(&ident_loop);
@@ -1076,9 +1076,9 @@ void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
{
GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
&return_not_found);
- Node* element_k =
+ TNode<Object> element_k =
UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
- GotoIf(WordEqual(element_k, search_element), &return_found);
+ GotoIf(TaggedEqual(element_k, search_element), &return_found);
Increment(&index_var);
Goto(&ident_loop);
@@ -1089,7 +1089,7 @@ void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
&return_not_found);
- Node* element_k =
+ TNode<Object> element_k =
UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
GotoIf(IsUndefined(element_k), &return_found);
GotoIf(IsTheHole(element_k), &return_found);
@@ -1109,15 +1109,16 @@ void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
Label continue_loop(this), not_smi(this);
GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
&return_not_found);
- Node* element_k =
+ TNode<Object> element_k =
UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
GotoIfNot(TaggedIsSmi(element_k), &not_smi);
- Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
+ Branch(Float64Equal(search_num.value(), SmiToFloat64(CAST(element_k))),
&return_found, &continue_loop);
BIND(&not_smi);
- GotoIfNot(IsHeapNumber(element_k), &continue_loop);
- Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
+ GotoIfNot(IsHeapNumber(CAST(element_k)), &continue_loop);
+ Branch(Float64Equal(search_num.value(),
+ LoadHeapNumberValue(CAST(element_k))),
&return_found, &continue_loop);
BIND(&continue_loop);
@@ -1131,11 +1132,11 @@ void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
Label continue_loop(this);
GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
&return_not_found);
- Node* element_k =
+ TNode<Object> element_k =
UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
GotoIf(TaggedIsSmi(element_k), &continue_loop);
GotoIfNot(IsHeapNumber(CAST(element_k)), &continue_loop);
- BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_found,
+ BranchIfFloat64IsNaN(LoadHeapNumberValue(CAST(element_k)), &return_found,
&continue_loop);
BIND(&continue_loop);
@@ -1155,24 +1156,24 @@ void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
BIND(&next_iteration);
GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
&return_not_found);
- Node* element_k =
+ TNode<Object> element_k =
UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
GotoIf(TaggedIsSmi(element_k), &continue_loop);
- GotoIf(WordEqual(search_element_string, element_k), &return_found);
- Node* element_k_type = LoadInstanceType(element_k);
+ GotoIf(TaggedEqual(search_element_string, element_k), &return_found);
+ TNode<Uint16T> element_k_type = LoadInstanceType(CAST(element_k));
GotoIfNot(IsStringInstanceType(element_k_type), &continue_loop);
- Branch(WordEqual(search_length, LoadStringLengthAsWord(element_k)),
+ Branch(IntPtrEqual(search_length, LoadStringLengthAsWord(CAST(element_k))),
&slow_compare, &continue_loop);
BIND(&slow_compare);
StringBuiltinsAssembler string_asm(state());
- string_asm.StringEqual_Core(context, search_element_string, search_type,
- element_k, element_k_type, search_length,
+ string_asm.StringEqual_Core(search_element_string, search_type,
+ CAST(element_k), element_k_type, search_length,
&return_found, &continue_loop, &runtime);
BIND(&runtime);
TNode<Object> result = CallRuntime(Runtime::kStringEqual, context,
search_element_string, element_k);
- Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);
+ Branch(TaggedEqual(result, TrueConstant()), &return_found, &continue_loop);
BIND(&continue_loop);
Increment(&index_var);
@@ -1184,14 +1185,14 @@ void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
&return_not_found);
- Node* element_k =
+ TNode<Object> element_k =
UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
Label continue_loop(this);
GotoIf(TaggedIsSmi(element_k), &continue_loop);
GotoIfNot(IsBigInt(CAST(element_k)), &continue_loop);
TNode<Object> result = CallRuntime(Runtime::kBigIntEqualToBigInt, context,
search_element, element_k);
- Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);
+ Branch(TaggedEqual(result, TrueConstant()), &return_found, &continue_loop);
BIND(&continue_loop);
Increment(&index_var);
@@ -1217,24 +1218,23 @@ void ArrayIncludesIndexofAssembler::GeneratePackedDoubles(SearchVariant variant,
Node* search_element,
Node* array_length,
Node* from_index) {
- VARIABLE(index_var, MachineType::PointerRepresentation(),
- SmiUntag(from_index));
- Node* array_length_untagged = SmiUntag(array_length);
+ TVARIABLE(IntPtrT, index_var, SmiUntag(from_index));
+ TNode<IntPtrT> array_length_untagged = SmiUntag(array_length);
Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
hole_loop(this, &index_var), search_notnan(this), return_found(this),
return_not_found(this);
- VARIABLE(search_num, MachineRepresentation::kFloat64);
- search_num.Bind(Float64Constant(0));
+ TVARIABLE(Float64T, search_num);
+ search_num = Float64Constant(0);
GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
- search_num.Bind(SmiToFloat64(search_element));
+ search_num = SmiToFloat64(search_element);
Goto(&not_nan_loop);
BIND(&search_notnan);
GotoIfNot(IsHeapNumber(search_element), &return_not_found);
- search_num.Bind(LoadHeapNumberValue(search_element));
+ search_num = LoadHeapNumberValue(search_element);
Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
@@ -1244,8 +1244,8 @@ void ArrayIncludesIndexofAssembler::GeneratePackedDoubles(SearchVariant variant,
Label continue_loop(this);
GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
&return_not_found);
- Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
- MachineType::Float64());
+ TNode<Float64T> element_k = LoadFixedDoubleArrayElement(
+ elements, index_var.value(), MachineType::Float64());
Branch(Float64Equal(element_k, search_num.value()), &return_found,
&continue_loop);
BIND(&continue_loop);
@@ -1259,8 +1259,8 @@ void ArrayIncludesIndexofAssembler::GeneratePackedDoubles(SearchVariant variant,
Label continue_loop(this);
GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
&return_not_found);
- Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
- MachineType::Float64());
+ TNode<Float64T> element_k = LoadFixedDoubleArrayElement(
+ elements, index_var.value(), MachineType::Float64());
BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
BIND(&continue_loop);
Increment(&index_var);
@@ -1287,18 +1287,17 @@ void ArrayIncludesIndexofAssembler::GenerateHoleyDoubles(SearchVariant variant,
Node* search_element,
Node* array_length,
Node* from_index) {
- VARIABLE(index_var, MachineType::PointerRepresentation(),
- SmiUntag(from_index));
- Node* array_length_untagged = SmiUntag(array_length);
+ TVARIABLE(IntPtrT, index_var, SmiUntag(from_index));
+ TNode<IntPtrT> array_length_untagged = SmiUntag(array_length);
Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
hole_loop(this, &index_var), search_notnan(this), return_found(this),
return_not_found(this);
- VARIABLE(search_num, MachineRepresentation::kFloat64);
- search_num.Bind(Float64Constant(0));
+ TVARIABLE(Float64T, search_num);
+ search_num = Float64Constant(0);
GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
- search_num.Bind(SmiToFloat64(search_element));
+ search_num = SmiToFloat64(search_element);
Goto(&not_nan_loop);
BIND(&search_notnan);
@@ -1307,7 +1306,7 @@ void ArrayIncludesIndexofAssembler::GenerateHoleyDoubles(SearchVariant variant,
}
GotoIfNot(IsHeapNumber(search_element), &return_not_found);
- search_num.Bind(LoadHeapNumberValue(search_element));
+ search_num = LoadHeapNumberValue(search_element);
Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
@@ -1320,8 +1319,8 @@ void ArrayIncludesIndexofAssembler::GenerateHoleyDoubles(SearchVariant variant,
// No need for hole checking here; the following Float64Equal will
// return 'not equal' for holes anyway.
- Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
- MachineType::Float64());
+ TNode<Float64T> element_k = LoadFixedDoubleArrayElement(
+ elements, index_var.value(), MachineType::Float64());
Branch(Float64Equal(element_k, search_num.value()), &return_found,
&continue_loop);
@@ -1338,7 +1337,7 @@ void ArrayIncludesIndexofAssembler::GenerateHoleyDoubles(SearchVariant variant,
&return_not_found);
// Load double value or continue if it's the hole NaN.
- Node* element_k = LoadFixedDoubleArrayElement(
+ TNode<Float64T> element_k = LoadFixedDoubleArrayElement(
elements, index_var.value(), MachineType::Float64(), 0,
INTPTR_PARAMETERS, &continue_loop);
@@ -1387,9 +1386,9 @@ TF_BUILTIN(ArrayIncludes, ArrayIncludesIndexofAssembler) {
}
TF_BUILTIN(ArrayIncludesSmiOrObject, ArrayIncludesIndexofAssembler) {
- Node* context = Parameter(Descriptor::kContext);
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Node* elements = Parameter(Descriptor::kElements);
- Node* search_element = Parameter(Descriptor::kSearchElement);
+ TNode<Object> search_element = CAST(Parameter(Descriptor::kSearchElement));
Node* array_length = Parameter(Descriptor::kLength);
Node* from_index = Parameter(Descriptor::kFromIndex);
@@ -1426,9 +1425,9 @@ TF_BUILTIN(ArrayIndexOf, ArrayIncludesIndexofAssembler) {
}
TF_BUILTIN(ArrayIndexOfSmiOrObject, ArrayIncludesIndexofAssembler) {
- Node* context = Parameter(Descriptor::kContext);
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Node* elements = Parameter(Descriptor::kElements);
- Node* search_element = Parameter(Descriptor::kSearchElement);
+ TNode<Object> search_element = CAST(Parameter(Descriptor::kSearchElement));
Node* array_length = Parameter(Descriptor::kLength);
Node* from_index = Parameter(Descriptor::kFromIndex);
@@ -1512,7 +1511,7 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
// Dispatch based on the type of the {array}.
TNode<Map> array_map = LoadMap(array);
- TNode<Int32T> array_type = LoadMapInstanceType(array_map);
+ TNode<Uint16T> array_type = LoadMapInstanceType(array_map);
GotoIf(InstanceTypeEqual(array_type, JS_ARRAY_TYPE), &if_array);
Branch(InstanceTypeEqual(array_type, JS_TYPED_ARRAY_TYPE), &if_typedarray,
&if_other);
@@ -1662,7 +1661,7 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
BIND(&allocate_iterator_result);
{
- Node* result =
+ TNode<JSObject> result =
AllocateJSIteratorResult(context, var_value.value(), var_done.value());
Return(result);
}
@@ -1705,7 +1704,7 @@ class ArrayFlattenAssembler : public CodeStubAssembler {
// b. Let exists be ? HasProperty(source, P).
CSA_ASSERT(this,
SmiGreaterThanOrEqual(CAST(source_index), SmiConstant(0)));
- Node* const exists =
+ TNode<Oddball> const exists =
HasProperty(context, source, source_index, kHasProperty);
// c. If exists is true, then
@@ -1713,7 +1712,8 @@ class ArrayFlattenAssembler : public CodeStubAssembler {
GotoIfNot(IsTrue(exists), &next);
{
// i. Let element be ? Get(source, P).
- Node* element = GetProperty(context, source, source_index);
+ TNode<Object> element_maybe_smi =
+ GetProperty(context, source, source_index);
// ii. If mapperFunction is present, then
if (mapper_function != nullptr) {
@@ -1723,9 +1723,9 @@ class ArrayFlattenAssembler : public CodeStubAssembler {
// 1. Set element to ? Call(mapperFunction, thisArg , « element,
// sourceIndex, source »).
- element =
+ element_maybe_smi = CAST(
CallJS(CodeFactory::Call(isolate()), context, mapper_function,
- this_arg, element, source_index, source);
+ this_arg, element_maybe_smi, source_index, source));
}
// iii. Let shouldFlatten be false.
@@ -1734,7 +1734,8 @@ class ArrayFlattenAssembler : public CodeStubAssembler {
// iv. If depth > 0, then
GotoIfNumberGreaterThanOrEqual(SmiConstant(0), depth, &if_noflatten);
// 1. Set shouldFlatten to ? IsArray(element).
- GotoIf(TaggedIsSmi(element), &if_noflatten);
+ GotoIf(TaggedIsSmi(element_maybe_smi), &if_noflatten);
+ TNode<HeapObject> element = CAST(element_maybe_smi);
GotoIf(IsJSArray(element), &if_flatten_array);
GotoIfNot(IsJSProxy(element), &if_noflatten);
Branch(IsTrue(CallRuntime(Runtime::kArrayIsArray, context, element)),
@@ -1745,7 +1746,7 @@ class ArrayFlattenAssembler : public CodeStubAssembler {
CSA_ASSERT(this, IsJSArray(element));
// 1. Let elementLen be ? ToLength(? Get(element, "length")).
- Node* const element_length =
+ TNode<Object> const element_length =
LoadObjectField(element, JSArray::kLengthOffset);
// 2. Set targetIndex to ? FlattenIntoArray(target, element,
@@ -1762,7 +1763,7 @@ class ArrayFlattenAssembler : public CodeStubAssembler {
CSA_ASSERT(this, IsJSProxy(element));
// 1. Let elementLen be ? ToLength(? Get(element, "length")).
- Node* const element_length = ToLength_Inline(
+ TNode<Number> const element_length = ToLength_Inline(
context, GetProperty(context, element, LengthStringConstant()));
// 2. Set targetIndex to ? FlattenIntoArray(target, element,
@@ -1872,7 +1873,7 @@ TF_BUILTIN(ArrayPrototypeFlat, CodeStubAssembler) {
// 5. Let A be ? ArraySpeciesCreate(O, 0).
TNode<JSReceiver> const constructor =
CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context, o));
- Node* const a = Construct(context, constructor, SmiConstant(0));
+ TNode<JSReceiver> const a = Construct(context, constructor, SmiConstant(0));
// 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
CallBuiltin(Builtins::kFlattenIntoArray, context, a, o, source_length,
@@ -1937,7 +1938,7 @@ TF_BUILTIN(ArrayConstructor, ArrayBuiltinsAssembler) {
SelectConstant<Object>(IsUndefined(new_target), function, new_target);
// Run the native code for the Array function called as a normal function.
- TNode<Object> no_allocation_site = UndefinedConstant();
+ TNode<Oddball> no_allocation_site = UndefinedConstant();
TailCallBuiltin(Builtins::kArrayConstructorImpl, context, function,
new_target, argc, no_allocation_site);
}
@@ -2105,7 +2106,7 @@ TF_BUILTIN(ArrayConstructorImpl, ArrayBuiltinsAssembler) {
CAST(LoadObjectField(target, JSFunction::kContextOffset));
Label runtime(this, Label::kDeferred);
- GotoIf(WordNotEqual(target, new_target), &runtime);
+ GotoIf(TaggedNotEqual(target, new_target), &runtime);
Label no_info(this);
// If the feedback vector is the undefined value call an array constructor
@@ -2143,7 +2144,8 @@ void ArrayBuiltinsAssembler::GenerateConstructor(
Branch(SmiEqual(CAST(array_size), SmiConstant(0)), &small_smi_size, &abort);
BIND(&abort);
- Node* reason = SmiConstant(AbortReason::kAllocatingNonEmptyPackedArray);
+ TNode<Smi> reason =
+ SmiConstant(AbortReason::kAllocatingNonEmptyPackedArray);
TailCallRuntime(Runtime::kAbort, context, reason);
} else {
int element_size =
@@ -2175,8 +2177,8 @@ void ArrayBuiltinsAssembler::GenerateConstructor(
void ArrayBuiltinsAssembler::GenerateArrayNoArgumentConstructor(
ElementsKind kind, AllocationSiteOverrideMode mode) {
using Descriptor = ArrayNoArgumentConstructorDescriptor;
- Node* native_context = LoadObjectField(Parameter(Descriptor::kFunction),
- JSFunction::kContextOffset);
+ TNode<NativeContext> native_context = CAST(LoadObjectField(
+ Parameter(Descriptor::kFunction), JSFunction::kContextOffset));
bool track_allocation_site =
AllocationSite::ShouldTrack(kind) && mode != DISABLE_ALLOCATION_SITES;
Node* allocation_site =
@@ -2191,10 +2193,11 @@ void ArrayBuiltinsAssembler::GenerateArrayNoArgumentConstructor(
void ArrayBuiltinsAssembler::GenerateArraySingleArgumentConstructor(
ElementsKind kind, AllocationSiteOverrideMode mode) {
using Descriptor = ArraySingleArgumentConstructorDescriptor;
- Node* context = Parameter(Descriptor::kContext);
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Node* function = Parameter(Descriptor::kFunction);
- Node* native_context = LoadObjectField(function, JSFunction::kContextOffset);
- Node* array_map = LoadJSArrayElementsMap(kind, native_context);
+ TNode<NativeContext> native_context =
+ CAST(LoadObjectField(function, JSFunction::kContextOffset));
+ TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context);
AllocationSiteMode allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
if (mode == DONT_OVERRIDE) {
diff --git a/deps/v8/src/builtins/builtins-array.cc b/deps/v8/src/builtins/builtins-array.cc
index 96c10ed0fd..6c3e724649 100644
--- a/deps/v8/src/builtins/builtins-array.cc
+++ b/deps/v8/src/builtins/builtins-array.cc
@@ -7,6 +7,7 @@
#include "src/codegen/code-factory.h"
#include "src/debug/debug.h"
#include "src/execution/isolate.h"
+#include "src/execution/protectors-inl.h"
#include "src/handles/global-handles.h"
#include "src/logging/counters.h"
#include "src/objects/contexts.h"
@@ -782,10 +783,10 @@ class ArrayConcatVisitor {
storage_ = isolate_->global_handles()->Create(storage);
}
- class FastElementsField : public BitField<bool, 0, 1> {};
- class ExceedsLimitField : public BitField<bool, 1, 1> {};
- class IsFixedArrayField : public BitField<bool, 2, 1> {};
- class HasSimpleElementsField : public BitField<bool, 3, 1> {};
+ using FastElementsField = BitField<bool, 0, 1>;
+ using ExceedsLimitField = BitField<bool, 1, 1>;
+ using IsFixedArrayField = BitField<bool, 2, 1>;
+ using HasSimpleElementsField = BitField<bool, 3, 1>;
bool fast_elements() const { return FastElementsField::decode(bit_field_); }
void set_fast_elements(bool fast) {
@@ -819,8 +820,10 @@ uint32_t EstimateElementCount(Isolate* isolate, Handle<JSArray> array) {
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case HOLEY_ELEMENTS: {
// Fast elements can't have lengths that are not representable by
// a 32-bit signed integer.
@@ -887,9 +890,11 @@ void CollectElementIndices(Isolate* isolate, Handle<JSObject> object,
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case HOLEY_SMI_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case HOLEY_ELEMENTS: {
DisallowHeapAllocation no_gc;
FixedArray elements = FixedArray::cast(object->elements());
@@ -1063,9 +1068,11 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case HOLEY_SMI_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case HOLEY_ELEMENTS: {
// Run through the elements FixedArray and use HasElement and GetElement
// to check the prototype for missing elements.
@@ -1219,7 +1226,7 @@ Object Slow_ArrayConcat(BuiltinArguments* args, Handle<Object> species,
if (length_estimate != 0) {
ElementsKind array_kind =
GetPackedElementsKind(array->GetElementsKind());
- if (IsFrozenOrSealedElementsKind(array_kind)) {
+ if (IsAnyNonextensibleElementsKind(array_kind)) {
array_kind = PACKED_ELEMENTS;
}
kind = GetMoreGeneralElementsKind(kind, array_kind);
@@ -1315,9 +1322,11 @@ Object Slow_ArrayConcat(BuiltinArguments* args, Handle<Object> species,
case HOLEY_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NO_ELEMENTS:
DCHECK_EQ(0u, length);
@@ -1460,7 +1469,7 @@ BUILTIN(ArrayConcat) {
// Avoid a real species read to avoid extra lookups to the array constructor
if (V8_LIKELY(receiver->IsJSArray() &&
Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) &&
- isolate->IsArraySpeciesLookupChainIntact())) {
+ Protectors::IsArraySpeciesLookupChainIntact(isolate))) {
if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
return *result_array;
}
diff --git a/deps/v8/src/builtins/builtins-async-function-gen.cc b/deps/v8/src/builtins/builtins-async-function-gen.cc
index a95365e425..6ac37da3f6 100644
--- a/deps/v8/src/builtins/builtins-async-function-gen.cc
+++ b/deps/v8/src/builtins/builtins-async-function-gen.cc
@@ -109,7 +109,7 @@ TF_BUILTIN(AsyncFunctionEnter, AsyncFunctionBuiltinsAssembler) {
TNode<HeapObject> base = AllocateInNewSpace(size);
// Initialize the promise.
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<JSFunction> promise_function =
CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
TNode<Map> promise_map = LoadObjectField<Map>(
@@ -263,8 +263,8 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* outer_promise = LoadObjectField(async_function_object,
- JSAsyncFunctionObject::kPromiseOffset);
+ TNode<Object> outer_promise = LoadObjectField(
+ async_function_object, JSAsyncFunctionObject::kPromiseOffset);
Label after_debug_hook(this), call_debug_hook(this, Label::kDeferred);
GotoIf(HasAsyncEventDelegate(), &call_debug_hook);
diff --git a/deps/v8/src/builtins/builtins-async-gen.cc b/deps/v8/src/builtins/builtins-async-gen.cc
index 6c04037a63..70d4eac9c8 100644
--- a/deps/v8/src/builtins/builtins-async-gen.cc
+++ b/deps/v8/src/builtins/builtins-async-gen.cc
@@ -28,7 +28,7 @@ Node* AsyncBuiltinsAssembler::AwaitOld(Node* context, Node* generator,
Node* on_resolve_context_index,
Node* on_reject_context_index,
Node* is_predicted_as_caught) {
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
static const int kWrappedPromiseOffset =
FixedArray::SizeFor(Context::MIN_CONTEXT_SLOTS);
@@ -46,7 +46,7 @@ Node* AsyncBuiltinsAssembler::AwaitOld(Node* context, Node* generator,
StoreMapNoWriteBarrier(closure_context, RootIndex::kAwaitContextMap);
StoreObjectFieldNoWriteBarrier(closure_context, Context::kLengthOffset,
SmiConstant(Context::MIN_CONTEXT_SLOTS));
- Node* const empty_scope_info =
+ TNode<Object> const empty_scope_info =
LoadContextElement(native_context, Context::SCOPE_INFO_INDEX);
StoreContextElementNoWriteBarrier(
closure_context, Context::SCOPE_INFO_INDEX, empty_scope_info);
@@ -59,16 +59,17 @@ Node* AsyncBuiltinsAssembler::AwaitOld(Node* context, Node* generator,
}
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
- Node* const promise_fun =
- LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
+ TNode<JSFunction> const promise_fun =
+ CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun)));
- Node* const promise_map =
- LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
+ TNode<Map> const promise_map = CAST(
+ LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset));
// Assert that the JSPromise map has an instance size is
// JSPromise::kSizeWithEmbedderFields.
- CSA_ASSERT(this, WordEqual(LoadMapInstanceSizeInWords(promise_map),
- IntPtrConstant(JSPromise::kSizeWithEmbedderFields /
- kTaggedSize)));
+ CSA_ASSERT(this,
+ IntPtrEqual(LoadMapInstanceSizeInWords(promise_map),
+ IntPtrConstant(JSPromise::kSizeWithEmbedderFields /
+ kTaggedSize)));
TNode<HeapObject> wrapped_value = InnerAllocate(base, kWrappedPromiseOffset);
{
// Initialize Promise
@@ -118,7 +119,7 @@ Node* AsyncBuiltinsAssembler::AwaitOptimized(Node* context, Node* generator,
Node* on_resolve_context_index,
Node* on_reject_context_index,
Node* is_predicted_as_caught) {
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
CSA_ASSERT(this, IsJSPromise(promise));
static const int kResolveClosureOffset =
@@ -139,7 +140,7 @@ Node* AsyncBuiltinsAssembler::AwaitOptimized(Node* context, Node* generator,
StoreMapNoWriteBarrier(closure_context, RootIndex::kAwaitContextMap);
StoreObjectFieldNoWriteBarrier(closure_context, Context::kLengthOffset,
SmiConstant(Context::MIN_CONTEXT_SLOTS));
- Node* const empty_scope_info =
+ TNode<Object> const empty_scope_info =
LoadContextElement(native_context, Context::SCOPE_INFO_INDEX);
StoreContextElementNoWriteBarrier(
closure_context, Context::SCOPE_INFO_INDEX, empty_scope_info);
@@ -196,16 +197,16 @@ Node* AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
// to allocate the wrapper promise and can just use the `AwaitOptimized`
// logic.
GotoIf(TaggedIsSmi(value), &if_old);
- Node* const value_map = LoadMap(value);
+ TNode<Map> const value_map = LoadMap(value);
GotoIfNot(IsJSPromiseMap(value_map), &if_old);
// We can skip the "constructor" lookup on {value} if it's [[Prototype]]
// is the (initial) Promise.prototype and the @@species protector is
// intact, as that guards the lookup path for "constructor" on
// JSPromise instances which have the (initial) Promise.prototype.
- Node* const native_context = LoadNativeContext(context);
- Node* const promise_prototype =
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const promise_prototype =
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
- GotoIfNot(WordEqual(LoadMapPrototype(value_map), promise_prototype),
+ GotoIfNot(TaggedEqual(LoadMapPrototype(value_map), promise_prototype),
&if_slow_constructor);
Branch(IsPromiseSpeciesProtectorCellInvalid(), &if_slow_constructor, &if_new);
@@ -214,11 +215,11 @@ Node* AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
// have the %Promise% as its "constructor", so we need to check that as well.
BIND(&if_slow_constructor);
{
- Node* const value_constructor =
+ TNode<Object> const value_constructor =
GetProperty(context, value, isolate()->factory()->constructor_string());
- Node* const promise_function =
+ TNode<Object> const promise_function =
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
- Branch(WordEqual(value_constructor, promise_function), &if_new, &if_old);
+ Branch(TaggedEqual(value_constructor, promise_function), &if_new, &if_old);
}
BIND(&if_old);
@@ -245,9 +246,10 @@ void AsyncBuiltinsAssembler::InitializeNativeClosure(Node* context,
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX));
// Ensure that we don't have to initialize prototype_or_initial_map field of
// JSFunction.
- CSA_ASSERT(this, WordEqual(LoadMapInstanceSizeInWords(function_map),
- IntPtrConstant(JSFunction::kSizeWithoutPrototype /
- kTaggedSize)));
+ CSA_ASSERT(this,
+ IntPtrEqual(LoadMapInstanceSizeInWords(function_map),
+ IntPtrConstant(JSFunction::kSizeWithoutPrototype /
+ kTaggedSize)));
STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kTaggedSize);
StoreMapNoWriteBarrier(function, function_map);
StoreObjectFieldRoot(function, JSObject::kPropertiesOrHashOffset,
@@ -276,12 +278,10 @@ void AsyncBuiltinsAssembler::InitializeNativeClosure(Node* context,
Node* AsyncBuiltinsAssembler::CreateUnwrapClosure(Node* native_context,
Node* done) {
- Node* const map = LoadContextElement(
+ TNode<Object> const map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
- Node* const on_fulfilled_shared = LoadContextElement(
- native_context, Context::ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN);
- CSA_ASSERT(this,
- HasInstanceType(on_fulfilled_shared, SHARED_FUNCTION_INFO_TYPE));
+ TNode<SharedFunctionInfo> const on_fulfilled_shared = CAST(LoadContextElement(
+ native_context, Context::ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN));
Node* const closure_context =
AllocateAsyncIteratorValueUnwrapContext(native_context, done);
return AllocateFunctionWithMapAndContext(map, on_fulfilled_shared,
@@ -304,10 +304,11 @@ TF_BUILTIN(AsyncIteratorValueUnwrap, AsyncBuiltinsAssembler) {
Node* const value = Parameter(Descriptor::kValue);
Node* const context = Parameter(Descriptor::kContext);
- Node* const done = LoadContextElement(context, ValueUnwrapContext::kDoneSlot);
- CSA_ASSERT(this, IsBoolean(done));
+ TNode<Object> const done =
+ LoadContextElement(context, ValueUnwrapContext::kDoneSlot);
+ CSA_ASSERT(this, IsBoolean(CAST(done)));
- Node* const unwrapped_value =
+ TNode<Object> const unwrapped_value =
CallBuiltin(Builtins::kCreateIterResultObject, context, value, done);
Return(unwrapped_value);
diff --git a/deps/v8/src/builtins/builtins-async-generator-gen.cc b/deps/v8/src/builtins/builtins-async-generator-gen.cc
index d14e811db8..8053cf0dc8 100644
--- a/deps/v8/src/builtins/builtins-async-generator-gen.cc
+++ b/deps/v8/src/builtins/builtins-async-generator-gen.cc
@@ -25,12 +25,12 @@ class AsyncGeneratorBuiltinsAssembler : public AsyncBuiltinsAssembler {
inline Node* TaggedIsAsyncGenerator(Node* tagged_object) {
TNode<BoolT> if_notsmi = TaggedIsNotSmi(tagged_object);
- return Select<BoolT>(if_notsmi,
- [=] {
- return HasInstanceType(
- tagged_object, JS_ASYNC_GENERATOR_OBJECT_TYPE);
- },
- [=] { return if_notsmi; });
+ return Select<BoolT>(
+ if_notsmi,
+ [=] {
+ return HasInstanceType(tagged_object, JS_ASYNC_GENERATOR_OBJECT_TYPE);
+ },
+ [=] { return if_notsmi; });
}
inline Node* LoadGeneratorState(Node* const generator) {
return LoadObjectField(generator, JSGeneratorObject::kContinuationOffset);
@@ -68,7 +68,7 @@ class AsyncGeneratorBuiltinsAssembler : public AsyncBuiltinsAssembler {
inline TNode<BoolT> IsGeneratorAwaiting(Node* const generator) {
TNode<Object> is_generator_awaiting =
LoadObjectField(generator, JSAsyncGeneratorObject::kIsAwaitingOffset);
- return WordEqual(is_generator_awaiting, SmiConstant(1));
+ return TaggedEqual(is_generator_awaiting, SmiConstant(1));
}
inline void SetGeneratorAwaiting(Node* const generator) {
@@ -93,8 +93,8 @@ class AsyncGeneratorBuiltinsAssembler : public AsyncBuiltinsAssembler {
inline Node* IsFastJSIterResult(Node* const value, Node* const context) {
CSA_ASSERT(this, TaggedIsNotSmi(value));
- Node* const native_context = LoadNativeContext(context);
- return WordEqual(
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ return TaggedEqual(
LoadMap(value),
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX));
}
@@ -200,7 +200,7 @@ Node* AsyncGeneratorBuiltinsAssembler::AllocateAsyncGeneratorRequest(
JSAsyncGeneratorObject::ResumeMode resume_mode, Node* resume_value,
Node* promise) {
CSA_SLOW_ASSERT(this, HasInstanceType(promise, JS_PROMISE_TYPE));
- Node* request = Allocate(AsyncGeneratorRequest::kSize);
+ TNode<HeapObject> request = Allocate(AsyncGeneratorRequest::kSize);
StoreMapNoWriteBarrier(request, RootIndex::kAsyncGeneratorRequestMap);
StoreObjectFieldNoWriteBarrier(request, AsyncGeneratorRequest::kNextOffset,
UndefinedConstant());
@@ -219,7 +219,8 @@ Node* AsyncGeneratorBuiltinsAssembler::AllocateAsyncGeneratorRequest(
void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure(
Node* context, Node* value,
JSAsyncGeneratorObject::ResumeMode resume_mode) {
- Node* const generator = LoadContextElement(context, Context::EXTENSION_INDEX);
+ TNode<Object> const generator =
+ LoadContextElement(context, Context::EXTENSION_INDEX);
CSA_SLOW_ASSERT(this, TaggedIsAsyncGenerator(generator));
SetGeneratorNotAwaiting(generator);
@@ -276,7 +277,8 @@ void AsyncGeneratorBuiltinsAssembler::AddAsyncGeneratorRequestToQueue(
{
Label loop_next(this), next_empty(this);
Node* current = var_current.value();
- Node* next = LoadObjectField(current, AsyncGeneratorRequest::kNextOffset);
+ TNode<Object> next =
+ LoadObjectField(current, AsyncGeneratorRequest::kNextOffset);
Branch(IsUndefined(next), &next_empty, &loop_next);
BIND(&next_empty);
@@ -299,11 +301,11 @@ Node* AsyncGeneratorBuiltinsAssembler::TakeFirstAsyncGeneratorRequestFromQueue(
// Removes and returns the first AsyncGeneratorRequest from a
// JSAsyncGeneratorObject's queue. Asserts that the queue is not empty.
CSA_ASSERT(this, TaggedIsAsyncGenerator(generator));
- Node* request =
- LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset);
- CSA_ASSERT(this, IsNotUndefined(request));
+ TNode<AsyncGeneratorRequest> request =
+ CAST(LoadObjectField(generator, JSAsyncGeneratorObject::kQueueOffset));
- Node* next = LoadObjectField(request, AsyncGeneratorRequest::kNextOffset);
+ TNode<Object> next =
+ LoadObjectField(request, AsyncGeneratorRequest::kNextOffset);
StoreObjectField(generator, JSAsyncGeneratorObject::kQueueOffset, next);
return request;
@@ -315,12 +317,12 @@ Node* AsyncGeneratorBuiltinsAssembler::TakeFirstAsyncGeneratorRequestFromQueue(
TF_BUILTIN(AsyncGeneratorPrototypeNext, AsyncGeneratorBuiltinsAssembler) {
const int kValueArg = 0;
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
- Node* generator = args.GetReceiver();
- Node* value = args.GetOptionalArgumentValue(kValueArg);
+ TNode<Object> generator = args.GetReceiver();
+ TNode<Object> value = args.GetOptionalArgumentValue(kValueArg);
Node* context = Parameter(Descriptor::kContext);
AsyncGeneratorEnqueue(&args, context, generator, value,
@@ -333,12 +335,12 @@ TF_BUILTIN(AsyncGeneratorPrototypeNext, AsyncGeneratorBuiltinsAssembler) {
TF_BUILTIN(AsyncGeneratorPrototypeReturn, AsyncGeneratorBuiltinsAssembler) {
const int kValueArg = 0;
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
- Node* generator = args.GetReceiver();
- Node* value = args.GetOptionalArgumentValue(kValueArg);
+ TNode<Object> generator = args.GetReceiver();
+ TNode<Object> value = args.GetOptionalArgumentValue(kValueArg);
Node* context = Parameter(Descriptor::kContext);
AsyncGeneratorEnqueue(&args, context, generator, value,
@@ -351,12 +353,12 @@ TF_BUILTIN(AsyncGeneratorPrototypeReturn, AsyncGeneratorBuiltinsAssembler) {
TF_BUILTIN(AsyncGeneratorPrototypeThrow, AsyncGeneratorBuiltinsAssembler) {
const int kValueArg = 0;
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
- Node* generator = args.GetReceiver();
- Node* value = args.GetOptionalArgumentValue(kValueArg);
+ TNode<Object> generator = args.GetReceiver();
+ TNode<Object> value = args.GetOptionalArgumentValue(kValueArg);
Node* context = Parameter(Descriptor::kContext);
AsyncGeneratorEnqueue(&args, context, generator, value,
@@ -446,8 +448,8 @@ TF_BUILTIN(AsyncGeneratorResumeNext, AsyncGeneratorBuiltinsAssembler) {
// generator is not closed, resume the generator with a "throw" completion.
// If the generator was closed, perform AsyncGeneratorReject(thrownValue).
// In all cases, the last step is to call AsyncGeneratorResumeNext.
- Node* is_caught = CallRuntime(Runtime::kAsyncGeneratorHasCatchHandlerForPC,
- context, generator);
+ TNode<Object> is_caught = CallRuntime(
+ Runtime::kAsyncGeneratorHasCatchHandlerForPC, context, generator);
TailCallBuiltin(Builtins::kAsyncGeneratorReturn, context, generator,
next_value, is_caught);
@@ -501,10 +503,10 @@ TF_BUILTIN(AsyncGeneratorResolve, AsyncGeneratorBuiltinsAssembler) {
Node* const promise = LoadPromiseFromAsyncGeneratorRequest(next);
// Let iteratorResult be CreateIterResultObject(value, done).
- Node* const iter_result = Allocate(JSIteratorResult::kSize);
+ TNode<HeapObject> const iter_result = Allocate(JSIteratorResult::kSize);
{
- Node* map = LoadContextElement(LoadNativeContext(context),
- Context::ITERATOR_RESULT_MAP_INDEX);
+ TNode<Object> map = LoadContextElement(LoadNativeContext(context),
+ Context::ITERATOR_RESULT_MAP_INDEX);
StoreMapNoWriteBarrier(iter_result, map);
StoreObjectFieldRoot(iter_result, JSIteratorResult::kPropertiesOrHashOffset,
RootIndex::kEmptyFixedArray);
@@ -585,7 +587,8 @@ TF_BUILTIN(AsyncGeneratorYield, AsyncGeneratorBuiltinsAssembler) {
TF_BUILTIN(AsyncGeneratorYieldResolveClosure, AsyncGeneratorBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue);
- Node* const generator = LoadContextElement(context, Context::EXTENSION_INDEX);
+ TNode<Object> const generator =
+ LoadContextElement(context, Context::EXTENSION_INDEX);
SetGeneratorNotAwaiting(generator);
@@ -665,7 +668,8 @@ TF_BUILTIN(AsyncGeneratorReturnClosedResolveClosure,
AsyncGeneratorBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue);
- Node* const generator = LoadContextElement(context, Context::EXTENSION_INDEX);
+ TNode<Object> const generator =
+ LoadContextElement(context, Context::EXTENSION_INDEX);
SetGeneratorNotAwaiting(generator);
@@ -682,7 +686,8 @@ TF_BUILTIN(AsyncGeneratorReturnClosedRejectClosure,
AsyncGeneratorBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue);
- Node* const generator = LoadContextElement(context, Context::EXTENSION_INDEX);
+ TNode<Object> const generator =
+ LoadContextElement(context, Context::EXTENSION_INDEX);
SetGeneratorNotAwaiting(generator);
diff --git a/deps/v8/src/builtins/builtins-async-iterator-gen.cc b/deps/v8/src/builtins/builtins-async-iterator-gen.cc
index 215faa73b1..0b5c5ef8b9 100644
--- a/deps/v8/src/builtins/builtins-async-iterator-gen.cc
+++ b/deps/v8/src/builtins/builtins-async-iterator-gen.cc
@@ -98,7 +98,7 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
const UndefinedMethodHandler& if_method_undefined,
const char* operation_name, Label::Type reject_label_type,
Node* const initial_exception_value) {
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
Node* const promise = AllocateAndInitJSPromise(context);
VARIABLE(var_exception, MachineRepresentation::kTagged,
@@ -109,7 +109,7 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
ThrowIfNotAsyncFromSyncIterator(context, iterator, &reject_promise,
&var_exception, operation_name);
- Node* const sync_iterator =
+ TNode<Object> const sync_iterator =
LoadObjectField(iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset);
Node* const method = get_method(sync_iterator);
@@ -132,13 +132,13 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
std::tie(value, done) = LoadIteratorResult(
context, native_context, iter_result, &reject_promise, &var_exception);
- Node* const promise_fun =
- LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
+ TNode<JSFunction> const promise_fun =
+ CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
CSA_ASSERT(this, IsConstructor(promise_fun));
// Let valueWrapper be PromiseResolve(%Promise%, « value »).
- Node* const value_wrapper = CallBuiltin(Builtins::kPromiseResolve,
- native_context, promise_fun, value);
+ TNode<Object> const value_wrapper = CallBuiltin(
+ Builtins::kPromiseResolve, native_context, promise_fun, value);
// IfAbruptRejectPromise(valueWrapper, promiseCapability).
GotoIfException(value_wrapper, &reject_promise, &var_exception);
@@ -167,15 +167,15 @@ std::pair<Node*, Node*> AsyncFromSyncBuiltinsAssembler::LoadIteratorResult(
done(this), if_notanobject(this, Label::kDeferred);
GotoIf(TaggedIsSmi(iter_result), &if_notanobject);
- Node* const iter_result_map = LoadMap(iter_result);
+ TNode<Map> const iter_result_map = LoadMap(iter_result);
GotoIfNot(IsJSReceiverMap(iter_result_map), &if_notanobject);
- Node* const fast_iter_result_map =
+ TNode<Object> const fast_iter_result_map =
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
VARIABLE(var_value, MachineRepresentation::kTagged);
VARIABLE(var_done, MachineRepresentation::kTagged);
- Branch(WordEqual(iter_result_map, fast_iter_result_map), &if_fastpath,
+ Branch(TaggedEqual(iter_result_map, fast_iter_result_map), &if_fastpath,
&if_slowpath);
BIND(&if_fastpath);
@@ -190,13 +190,13 @@ std::pair<Node*, Node*> AsyncFromSyncBuiltinsAssembler::LoadIteratorResult(
{
// Let nextDone be IteratorComplete(nextResult).
// IfAbruptRejectPromise(nextDone, promiseCapability).
- Node* const done =
+ TNode<Object> const done =
GetProperty(context, iter_result, factory()->done_string());
GotoIfException(done, if_exception, var_exception);
// Let nextValue be IteratorValue(nextResult).
// IfAbruptRejectPromise(nextValue, promiseCapability).
- Node* const value =
+ TNode<Object> const value =
GetProperty(context, iter_result, factory()->value_string());
GotoIfException(value, if_exception, var_exception);
@@ -222,7 +222,7 @@ std::pair<Node*, Node*> AsyncFromSyncBuiltinsAssembler::LoadIteratorResult(
BIND(&to_boolean);
{
- Node* const result =
+ TNode<Object> const result =
CallBuiltin(Builtins::kToBoolean, context, var_done.value());
var_done.Bind(result);
Goto(&done);
@@ -261,8 +261,8 @@ TF_BUILTIN(AsyncFromSyncIteratorPrototypeReturn,
Node* const promise, Label* if_exception) {
// If return is undefined, then
// Let iterResult be ! CreateIterResultObject(value, true)
- Node* const iter_result = CallBuiltin(Builtins::kCreateIterResultObject,
- context, value, TrueConstant());
+ TNode<Object> const iter_result = CallBuiltin(
+ Builtins::kCreateIterResultObject, context, value, TrueConstant());
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »).
// IfAbruptRejectPromise(nextDone, promiseCapability).
diff --git a/deps/v8/src/builtins/builtins-bigint-gen.cc b/deps/v8/src/builtins/builtins-bigint-gen.cc
index d4818f0e01..691ec7f8ce 100644
--- a/deps/v8/src/builtins/builtins-bigint-gen.cc
+++ b/deps/v8/src/builtins/builtins-bigint-gen.cc
@@ -19,15 +19,32 @@ TF_BUILTIN(BigIntToI64, CodeStubAssembler) {
TNode<Object> value = CAST(Parameter(Descriptor::kArgument));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
+ TNode<BigInt> n = ToBigInt(context, value);
+
+ TVARIABLE(UintPtrT, var_low);
+ TVARIABLE(UintPtrT, var_high);
+
+ BigIntToRawBytes(n, &var_low, &var_high);
+ ReturnRaw(var_low.value());
+}
+
+// https://tc39.github.io/proposal-bigint/#sec-to-big-int64
+TF_BUILTIN(BigIntToI32Pair, CodeStubAssembler) {
+ if (!Is32()) {
+ Unreachable();
+ return;
+ }
+
+ TNode<Object> value = CAST(Parameter(Descriptor::kArgument));
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<BigInt> bigint = ToBigInt(context, value);
TVARIABLE(UintPtrT, var_low);
TVARIABLE(UintPtrT, var_high);
- // 2. Let int64bit be n modulo 2^64.
- // 3. If int64bit ≥ 2^63, return int64bit - 2^64;
BigIntToRawBytes(bigint, &var_low, &var_high);
- ReturnRaw(var_low.value());
+ Return(SloppyTNode<Object>(var_low.value()),
+ SloppyTNode<Object>(var_high.value()));
}
// https://tc39.github.io/proposal-bigint/#sec-bigint-constructor-number-value
@@ -43,5 +60,18 @@ TF_BUILTIN(I64ToBigInt, CodeStubAssembler) {
Return(BigIntFromInt64(argument));
}
+// https://tc39.github.io/proposal-bigint/#sec-bigint-constructor-number-value
+TF_BUILTIN(I32PairToBigInt, CodeStubAssembler) {
+ if (!Is32()) {
+ Unreachable();
+ return;
+ }
+
+ TNode<IntPtrT> low = UncheckedCast<IntPtrT>(Parameter(Descriptor::kLow));
+ TNode<IntPtrT> high = UncheckedCast<IntPtrT>(Parameter(Descriptor::kHigh));
+
+ Return(BigIntFromInt32Pair(low, high));
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/builtins/builtins-bigint.cc b/deps/v8/src/builtins/builtins-bigint.cc
index 09d71a0562..1201ce9730 100644
--- a/deps/v8/src/builtins/builtins-bigint.cc
+++ b/deps/v8/src/builtins/builtins-bigint.cc
@@ -91,7 +91,7 @@ MaybeHandle<BigInt> ThisBigIntValue(Isolate* isolate, Handle<Object> value,
isolate,
NewTypeError(MessageTemplate::kNotGeneric,
isolate->factory()->NewStringFromAsciiChecked(caller),
- isolate->factory()->NewStringFromStaticChars("BigInt")),
+ isolate->factory()->BigInt_string()),
BigInt);
}
diff --git a/deps/v8/src/builtins/builtins-call-gen.cc b/deps/v8/src/builtins/builtins-call-gen.cc
index deb91dee24..91370b0896 100644
--- a/deps/v8/src/builtins/builtins-call-gen.cc
+++ b/deps/v8/src/builtins/builtins-call-gen.cc
@@ -118,15 +118,15 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
GotoIf(TaggedIsSmi(arguments_list), &if_runtime);
TNode<Map> arguments_list_map = LoadMap(CAST(arguments_list));
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
// Check if {arguments_list} is an (unmodified) arguments object.
TNode<Map> sloppy_arguments_map = CAST(
LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
- GotoIf(WordEqual(arguments_list_map, sloppy_arguments_map), &if_arguments);
+ GotoIf(TaggedEqual(arguments_list_map, sloppy_arguments_map), &if_arguments);
TNode<Map> strict_arguments_map = CAST(
LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX));
- GotoIf(WordEqual(arguments_list_map, strict_arguments_map), &if_arguments);
+ GotoIf(TaggedEqual(arguments_list_map, strict_arguments_map), &if_arguments);
// Check if {arguments_list} is a fast JSArray.
Branch(IsJSArrayMap(arguments_list_map), &if_array, &if_runtime);
@@ -135,10 +135,11 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
TVARIABLE(Int32T, var_length);
BIND(&if_array);
{
+ TNode<JSObject> js_object = CAST(arguments_list);
// Try to extract the elements from a JSArray object.
- var_elements = LoadElements(CAST(arguments_list));
+ var_elements = LoadElements(js_object);
var_length =
- LoadAndUntagToWord32ObjectField(arguments_list, JSArray::kLengthOffset);
+ LoadAndUntagToWord32ObjectField(js_object, JSArray::kLengthOffset);
// Holey arrays and double backing stores need special treatment.
STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
@@ -151,8 +152,9 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
TNode<Int32T> kind = LoadMapElementsKind(arguments_list_map);
- GotoIf(IsElementsKindGreaterThan(kind, LAST_FROZEN_ELEMENTS_KIND),
- &if_runtime);
+ GotoIf(
+ IsElementsKindGreaterThan(kind, LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND),
+ &if_runtime);
Branch(Word32And(kind, Int32Constant(1)), &if_holey_array, &if_done);
}
@@ -173,7 +175,7 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithArrayLike(
js_arguments, JSArgumentsObjectWithLength::kLengthOffset);
TNode<FixedArrayBase> elements = LoadElements(js_arguments);
TNode<Smi> elements_length = LoadFixedArrayBaseLength(elements);
- GotoIfNot(WordEqual(length, elements_length), &if_runtime);
+ GotoIfNot(TaggedEqual(length, elements_length), &if_runtime);
var_elements = elements;
var_length = SmiToInt32(CAST(length));
Goto(&if_done);
@@ -292,11 +294,11 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread(
// Check that the Array.prototype hasn't been modified in a way that would
// affect iteration.
- TNode<PropertyCell> protector_cell =
- CAST(LoadRoot(RootIndex::kArrayIteratorProtector));
- GotoIf(WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
- SmiConstant(Isolate::kProtectorInvalid)),
- &if_generic);
+ TNode<PropertyCell> protector_cell = ArrayIteratorProtectorConstant();
+ GotoIf(
+ TaggedEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
+ SmiConstant(Isolate::kProtectorInvalid)),
+ &if_generic);
{
// The fast-path accesses the {spread} elements directly.
TNode<Int32T> spread_kind = LoadMapElementsKind(spread_map);
@@ -310,9 +312,9 @@ void CallOrConstructBuiltinsAssembler::CallOrConstructWithSpread(
&if_smiorobject);
GotoIf(IsElementsKindLessThanOrEqual(spread_kind, LAST_FAST_ELEMENTS_KIND),
&if_double);
- Branch(
- IsElementsKindLessThanOrEqual(spread_kind, LAST_FROZEN_ELEMENTS_KIND),
- &if_smiorobject, &if_generic);
+ Branch(IsElementsKindLessThanOrEqual(spread_kind,
+ LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND),
+ &if_smiorobject, &if_generic);
}
BIND(&if_generic);
@@ -430,7 +432,7 @@ TNode<JSReceiver> CallOrConstructBuiltinsAssembler::GetCompatibleReceiver(
// will be ruled out there).
//
var_template = CAST(constructor);
- TNode<Int32T> template_type = LoadInstanceType(var_template.value());
+ TNode<Uint16T> template_type = LoadInstanceType(var_template.value());
GotoIf(InstanceTypeEqual(template_type, JS_FUNCTION_TYPE),
&template_from_closure);
Branch(InstanceTypeEqual(template_type, MAP_TYPE), &template_map_loop,
@@ -461,12 +463,12 @@ TNode<JSReceiver> CallOrConstructBuiltinsAssembler::GetCompatibleReceiver(
// end, in which case we continue with the next holder (the
// hidden prototype) if there's any.
TNode<HeapObject> current = var_template.value();
- GotoIf(WordEqual(current, signature), &holder_found);
+ GotoIf(TaggedEqual(current, signature), &holder_found);
GotoIfNot(IsFunctionTemplateInfoMap(LoadMap(current)), &holder_next);
TNode<HeapObject> current_rare = LoadObjectField<HeapObject>(
- current, FunctionTemplateInfo::kFunctionTemplateRareDataOffset);
+ current, FunctionTemplateInfo::kRareDataOffset);
GotoIf(IsUndefined(current_rare), &holder_next);
var_template = LoadObjectField<HeapObject>(
current_rare, FunctionTemplateRareData::kParentTemplateOffset);
@@ -514,7 +516,7 @@ void CallOrConstructBuiltinsAssembler::CallFunctionTemplate(
GotoIfNot(
IsSetWord32<Map::IsAccessCheckNeededBit>(LoadMapBitField(receiver_map)),
&receiver_done);
- TNode<WordT> function_template_info_flags = LoadAndUntagObjectField(
+ TNode<IntPtrT> function_template_info_flags = LoadAndUntagObjectField(
function_template_info, FunctionTemplateInfo::kFlagOffset);
Branch(IsSetWord(function_template_info_flags,
1 << FunctionTemplateInfo::kAcceptAnyReceiver),
diff --git a/deps/v8/src/builtins/builtins-collections-gen.cc b/deps/v8/src/builtins/builtins-collections-gen.cc
index 613e5f10ff..dec4142c65 100644
--- a/deps/v8/src/builtins/builtins-collections-gen.cc
+++ b/deps/v8/src/builtins/builtins-collections-gen.cc
@@ -108,8 +108,8 @@ class BaseCollectionsAssembler : public CodeStubAssembler {
// Checks whether {collection}'s initial add/set function has been modified
// (depending on {variant}, loaded from {native_context}).
void GotoIfInitialAddFunctionModified(Variant variant,
- TNode<Context> native_context,
- TNode<Object> collection,
+ TNode<NativeContext> native_context,
+ TNode<HeapObject> collection,
Label* if_modified);
// Gets root index for the name of the add/set function.
@@ -186,8 +186,8 @@ void BaseCollectionsAssembler::AddConstructorEntries(
TNode<Object> table = AllocateTable(variant, context, at_least_space_for);
StoreObjectField(collection, GetTableOffset(variant), table);
GotoIf(IsNullOrUndefined(initial_entries), &exit);
- GotoIfInitialAddFunctionModified(variant, native_context, collection,
- &slow_loop);
+ GotoIfInitialAddFunctionModified(variant, CAST(native_context),
+ CAST(collection), &slow_loop);
Branch(use_fast_loop.value(), &fast_loop, &slow_loop);
}
BIND(&fast_loop);
@@ -212,15 +212,15 @@ void BaseCollectionsAssembler::AddConstructorEntries(
{
// Check that add/set function has not been modified.
Label if_not_modified(this), if_modified(this);
- GotoIfInitialAddFunctionModified(variant, native_context, collection,
- &if_modified);
+ GotoIfInitialAddFunctionModified(variant, CAST(native_context),
+ CAST(collection), &if_modified);
Goto(&if_not_modified);
BIND(&if_modified);
Unreachable();
BIND(&if_not_modified);
}
- CSA_ASSERT(this, WordEqual(original_initial_entries_map,
- LoadMap(initial_entries_jsarray)));
+ CSA_ASSERT(this, TaggedEqual(original_initial_entries_map,
+ LoadMap(initial_entries_jsarray)));
#endif
use_fast_loop = Int32FalseConstant();
Goto(&allocate_table);
@@ -242,9 +242,9 @@ void BaseCollectionsAssembler::AddConstructorEntriesFromFastJSArray(
TNode<FixedArrayBase> elements = LoadElements(fast_jsarray);
TNode<Int32T> elements_kind = LoadElementsKind(fast_jsarray);
TNode<JSFunction> add_func = GetInitialAddFunction(variant, native_context);
- CSA_ASSERT(
- this,
- WordEqual(GetAddFunction(variant, native_context, collection), add_func));
+ CSA_ASSERT(this,
+ TaggedEqual(GetAddFunction(variant, native_context, collection),
+ add_func));
CSA_ASSERT(this, IsFastJSArrayWithNoCustomIteration(context, fast_jsarray));
TNode<IntPtrT> length = SmiUntag(LoadFastJSArrayLength(fast_jsarray));
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(length, IntPtrConstant(0)));
@@ -301,9 +301,9 @@ void BaseCollectionsAssembler::AddConstructorEntriesFromFastJSArray(
BIND(&exit);
#if DEBUG
CSA_ASSERT(this,
- WordEqual(original_collection_map, LoadMap(CAST(collection))));
+ TaggedEqual(original_collection_map, LoadMap(CAST(collection))));
CSA_ASSERT(this,
- WordEqual(original_fast_js_array_map, LoadMap(fast_jsarray)));
+ TaggedEqual(original_fast_js_array_map, LoadMap(fast_jsarray)));
#endif
}
@@ -356,21 +356,44 @@ RootIndex BaseCollectionsAssembler::GetAddFunctionNameIndex(Variant variant) {
}
void BaseCollectionsAssembler::GotoIfInitialAddFunctionModified(
- Variant variant, TNode<Context> native_context, TNode<Object> collection,
- Label* if_modified) {
+ Variant variant, TNode<NativeContext> native_context,
+ TNode<HeapObject> collection, Label* if_modified) {
STATIC_ASSERT(JSCollection::kAddFunctionDescriptorIndex ==
JSWeakCollection::kAddFunctionDescriptorIndex);
- GotoIfInitialPrototypePropertyModified(
- LoadMap(CAST(collection)),
- GetInitialCollectionPrototype(variant, native_context),
+
+ // TODO(jgruber): Investigate if this should also fall back to full prototype
+ // verification.
+ static constexpr PrototypeCheckAssembler::Flags flags{
+ PrototypeCheckAssembler::kCheckPrototypePropertyConstness};
+
+ static constexpr int kNoContextIndex = -1;
+ STATIC_ASSERT(
+ (flags & PrototypeCheckAssembler::kCheckPrototypePropertyIdentity) == 0);
+
+ using DescriptorIndexNameValue =
+ PrototypeCheckAssembler::DescriptorIndexNameValue;
+
+ DescriptorIndexNameValue property_to_check{
JSCollection::kAddFunctionDescriptorIndex,
- GetAddFunctionNameIndex(variant), if_modified);
+ GetAddFunctionNameIndex(variant), kNoContextIndex};
+
+ PrototypeCheckAssembler prototype_check_assembler(
+ state(), flags, native_context,
+ GetInitialCollectionPrototype(variant, native_context),
+ Vector<DescriptorIndexNameValue>(&property_to_check, 1));
+
+ TNode<HeapObject> prototype = LoadMapPrototype(LoadMap(collection));
+ Label if_unmodified(this);
+ prototype_check_assembler.CheckAndBranch(prototype, &if_unmodified,
+ if_modified);
+
+ BIND(&if_unmodified);
}
TNode<JSObject> BaseCollectionsAssembler::AllocateJSCollection(
TNode<Context> context, TNode<JSFunction> constructor,
TNode<JSReceiver> new_target) {
- TNode<BoolT> is_target_unmodified = WordEqual(constructor, new_target);
+ TNode<BoolT> is_target_unmodified = TaggedEqual(constructor, new_target);
return Select<JSObject>(
is_target_unmodified,
@@ -406,8 +429,8 @@ void BaseCollectionsAssembler::GenerateConstructor(
Label if_undefined(this, Label::kDeferred);
GotoIf(IsUndefined(new_target), &if_undefined);
- TNode<Context> native_context = LoadNativeContext(context);
- TNode<Object> collection = AllocateJSCollection(
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSObject> collection = AllocateJSCollection(
context, GetConstructor(variant, native_context), CAST(new_target));
AddConstructorEntries(variant, context, native_context, collection, iterable);
@@ -531,8 +554,8 @@ TNode<BoolT> BaseCollectionsAssembler::HasInitialCollectionPrototype(
TNode<Map> collection_proto_map =
LoadMap(LoadMapPrototype(LoadMap(CAST(collection))));
- return WordEqual(collection_proto_map,
- GetInitialCollectionPrototype(variant, native_context));
+ return TaggedEqual(collection_proto_map,
+ GetInitialCollectionPrototype(variant, native_context));
}
TNode<Object> BaseCollectionsAssembler::LoadAndNormalizeFixedArrayElement(
@@ -585,13 +608,13 @@ class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
protected:
template <typename IteratorType>
- Node* AllocateJSCollectionIterator(Node* context, int map_index,
- Node* collection);
+ Node* AllocateJSCollectionIterator(SloppyTNode<Context> context,
+ int map_index, Node* collection);
TNode<Object> AllocateTable(Variant variant, TNode<Context> context,
TNode<IntPtrT> at_least_space_for) override;
- Node* GetHash(Node* const key);
- Node* CallGetHashRaw(Node* const key);
- Node* CallGetOrCreateHashRaw(Node* const key);
+ TNode<IntPtrT> GetHash(SloppyTNode<HeapObject> const key);
+ TNode<IntPtrT> CallGetHashRaw(SloppyTNode<HeapObject> const key);
+ TNode<Smi> CallGetOrCreateHashRaw(SloppyTNode<HeapObject> const key);
// Transitions the iterator to the non obsolete backing store.
// This is a NOP if the [table] is not obsolete.
@@ -612,23 +635,25 @@ class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
// The {result} variable will contain the entry index if the key was found,
// or the hash code otherwise.
template <typename CollectionType>
- void FindOrderedHashTableEntryForSmiKey(Node* table, Node* key_tagged,
+ void FindOrderedHashTableEntryForSmiKey(Node* table,
+ SloppyTNode<Smi> key_tagged,
Variable* result, Label* entry_found,
Label* not_found);
- void SameValueZeroSmi(Node* key_smi, Node* candidate_key, Label* if_same,
+ void SameValueZeroSmi(SloppyTNode<Smi> key_smi,
+ SloppyTNode<Object> candidate_key, Label* if_same,
Label* if_not_same);
// Specialization for heap numbers.
// The {result} variable will contain the entry index if the key was found,
// or the hash code otherwise.
- void SameValueZeroHeapNumber(Node* key_string, Node* candidate_key,
+ void SameValueZeroHeapNumber(SloppyTNode<Float64T> key_float,
+ SloppyTNode<Object> candidate_key,
Label* if_same, Label* if_not_same);
template <typename CollectionType>
- void FindOrderedHashTableEntryForHeapNumberKey(Node* context, Node* table,
- Node* key_heap_number,
- Variable* result,
- Label* entry_found,
- Label* not_found);
+ void FindOrderedHashTableEntryForHeapNumberKey(
+ SloppyTNode<Context> context, Node* table,
+ SloppyTNode<HeapNumber> key_heap_number, Variable* result,
+ Label* entry_found, Label* not_found);
// Specialization for bigints.
// The {result} variable will contain the entry index if the key was found,
@@ -636,8 +661,9 @@ class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
void SameValueZeroBigInt(Node* key, Node* candidate_key, Label* if_same,
Label* if_not_same);
template <typename CollectionType>
- void FindOrderedHashTableEntryForBigIntKey(Node* context, Node* table,
- Node* key, Variable* result,
+ void FindOrderedHashTableEntryForBigIntKey(SloppyTNode<Context> context,
+ Node* table, Node* key,
+ Variable* result,
Label* entry_found,
Label* not_found);
@@ -645,13 +671,15 @@ class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
// The {result} variable will contain the entry index if the key was found,
// or the hash code otherwise.
template <typename CollectionType>
- void FindOrderedHashTableEntryForStringKey(Node* context, Node* table,
- Node* key_tagged, Variable* result,
- Label* entry_found,
- Label* not_found);
- Node* ComputeStringHash(Node* context, Node* string_key);
- void SameValueZeroString(Node* context, Node* key_string, Node* candidate_key,
- Label* if_same, Label* if_not_same);
+ void FindOrderedHashTableEntryForStringKey(
+ SloppyTNode<Context> context, Node* table, SloppyTNode<String> key_tagged,
+ Variable* result, Label* entry_found, Label* not_found);
+ TNode<IntPtrT> ComputeStringHash(TNode<Context> context,
+ TNode<String> string_key);
+ void SameValueZeroString(SloppyTNode<Context> context,
+ SloppyTNode<String> key_string,
+ SloppyTNode<Object> candidate_key, Label* if_same,
+ Label* if_not_same);
// Specialization for non-strings, non-numbers. For those we only need
// reference equality to compare the keys.
@@ -659,10 +687,9 @@ class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
// or the hash code otherwise. If the hash-code has not been computed, it
// should be Smi -1.
template <typename CollectionType>
- void FindOrderedHashTableEntryForOtherKey(Node* context, Node* table,
- Node* key, Variable* result,
- Label* entry_found,
- Label* not_found);
+ void FindOrderedHashTableEntryForOtherKey(
+ SloppyTNode<Context> context, Node* table, SloppyTNode<HeapObject> key,
+ Variable* result, Label* entry_found, Label* not_found);
template <typename CollectionType>
void TryLookupOrderedHashTableIndex(Node* const table, Node* const key,
@@ -704,11 +731,13 @@ class CollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
template <typename IteratorType>
Node* CollectionsBuiltinsAssembler::AllocateJSCollectionIterator(
- Node* context, int map_index, Node* collection) {
- Node* const table = LoadObjectField(collection, JSCollection::kTableOffset);
- Node* const native_context = LoadNativeContext(context);
- Node* const iterator_map = LoadContextElement(native_context, map_index);
- Node* const iterator = AllocateInNewSpace(IteratorType::kSize);
+ SloppyTNode<Context> context, int map_index, Node* collection) {
+ TNode<Object> const table =
+ LoadObjectField(collection, JSCollection::kTableOffset);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const iterator_map =
+ LoadContextElement(native_context, map_index);
+ TNode<HeapObject> const iterator = AllocateInNewSpace(IteratorType::kSize);
StoreMapNoWriteBarrier(iterator, iterator_map);
StoreObjectFieldRoot(iterator, IteratorType::kPropertiesOrHashOffset,
RootIndex::kEmptyFixedArray);
@@ -748,10 +777,11 @@ TF_BUILTIN(SetConstructor, CollectionsBuiltinsAssembler) {
argc, context);
}
-Node* CollectionsBuiltinsAssembler::CallGetOrCreateHashRaw(Node* const key) {
- Node* const function_addr =
+TNode<Smi> CollectionsBuiltinsAssembler::CallGetOrCreateHashRaw(
+ SloppyTNode<HeapObject> const key) {
+ TNode<ExternalReference> const function_addr =
ExternalConstant(ExternalReference::get_or_create_hash_raw());
- Node* const isolate_ptr =
+ TNode<ExternalReference> const isolate_ptr =
ExternalConstant(ExternalReference::isolate_address(isolate()));
MachineType type_ptr = MachineType::Pointer();
@@ -761,13 +791,14 @@ Node* CollectionsBuiltinsAssembler::CallGetOrCreateHashRaw(Node* const key) {
std::make_pair(type_ptr, isolate_ptr),
std::make_pair(type_tagged, key));
- return result;
+ return CAST(result);
}
-Node* CollectionsBuiltinsAssembler::CallGetHashRaw(Node* const key) {
- Node* const function_addr =
+TNode<IntPtrT> CollectionsBuiltinsAssembler::CallGetHashRaw(
+ SloppyTNode<HeapObject> const key) {
+ TNode<ExternalReference> const function_addr =
ExternalConstant(ExternalReference::orderedhashmap_gethash_raw());
- Node* const isolate_ptr =
+ TNode<ExternalReference> const isolate_ptr =
ExternalConstant(ExternalReference::isolate_address(isolate()));
MachineType type_ptr = MachineType::Pointer();
@@ -780,20 +811,21 @@ Node* CollectionsBuiltinsAssembler::CallGetHashRaw(Node* const key) {
return SmiUntag(result);
}
-Node* CollectionsBuiltinsAssembler::GetHash(Node* const key) {
- VARIABLE(var_hash, MachineType::PointerRepresentation());
+TNode<IntPtrT> CollectionsBuiltinsAssembler::GetHash(
+ SloppyTNode<HeapObject> const key) {
+ TVARIABLE(IntPtrT, var_hash);
Label if_receiver(this), if_other(this), done(this);
Branch(IsJSReceiver(key), &if_receiver, &if_other);
BIND(&if_receiver);
{
- var_hash.Bind(LoadJSReceiverIdentityHash(key));
+ var_hash = LoadJSReceiverIdentityHash(key);
Goto(&done);
}
BIND(&if_other);
{
- var_hash.Bind(CallGetHashRaw(key));
+ var_hash = CallGetHashRaw(key);
Goto(&done);
}
@@ -801,12 +833,11 @@ Node* CollectionsBuiltinsAssembler::GetHash(Node* const key) {
return var_hash.value();
}
-void CollectionsBuiltinsAssembler::SameValueZeroSmi(Node* key_smi,
- Node* candidate_key,
- Label* if_same,
- Label* if_not_same) {
+void CollectionsBuiltinsAssembler::SameValueZeroSmi(
+ SloppyTNode<Smi> key_smi, SloppyTNode<Object> candidate_key, Label* if_same,
+ Label* if_not_same) {
// If the key is the same, we are done.
- GotoIf(WordEqual(candidate_key, key_smi), if_same);
+ GotoIf(TaggedEqual(candidate_key, key_smi), if_same);
// If the candidate key is smi, then it must be different (because
// we already checked for equality above).
@@ -814,10 +845,11 @@ void CollectionsBuiltinsAssembler::SameValueZeroSmi(Node* key_smi,
// If the candidate key is not smi, we still have to check if it is a
// heap number with the same value.
- GotoIfNot(IsHeapNumber(candidate_key), if_not_same);
+ GotoIfNot(IsHeapNumber(CAST(candidate_key)), if_not_same);
- Node* const candidate_key_number = LoadHeapNumberValue(candidate_key);
- Node* const key_number = SmiToFloat64(key_smi);
+ TNode<Float64T> const candidate_key_number =
+ LoadHeapNumberValue(CAST(candidate_key));
+ TNode<Float64T> const key_number = SmiToFloat64(key_smi);
GotoIf(Float64Equal(candidate_key_number, key_number), if_same);
@@ -826,11 +858,12 @@ void CollectionsBuiltinsAssembler::SameValueZeroSmi(Node* key_smi,
void CollectionsBuiltinsAssembler::BranchIfMapIteratorProtectorValid(
Label* if_true, Label* if_false) {
- Node* protector_cell = LoadRoot(RootIndex::kMapIteratorProtector);
+ TNode<PropertyCell> protector_cell = MapIteratorProtectorConstant();
DCHECK(isolate()->heap()->map_iterator_protector().IsPropertyCell());
- Branch(WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
- SmiConstant(Isolate::kProtectorValid)),
- if_true, if_false);
+ Branch(
+ TaggedEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
+ SmiConstant(Isolate::kProtectorValid)),
+ if_true, if_false);
}
void CollectionsBuiltinsAssembler::
@@ -843,7 +876,7 @@ void CollectionsBuiltinsAssembler::
// Check if iterator is a keys or values JSMapIterator.
GotoIf(TaggedIsSmi(iterator), if_false);
TNode<Map> iter_map = LoadMap(CAST(iterator));
- Node* const instance_type = LoadMapInstanceType(iter_map);
+ TNode<Uint16T> const instance_type = LoadMapInstanceType(iter_map);
GotoIf(InstanceTypeEqual(instance_type, JS_MAP_KEY_ITERATOR_TYPE),
&if_key_or_value_iterator);
Branch(InstanceTypeEqual(instance_type, JS_MAP_VALUE_ITERATOR_TYPE),
@@ -851,25 +884,26 @@ void CollectionsBuiltinsAssembler::
BIND(&if_key_or_value_iterator);
// Check that the iterator is not partially consumed.
- Node* const index =
+ TNode<Object> const index =
LoadObjectField(CAST(iterator), JSMapIterator::kIndexOffset);
- GotoIfNot(WordEqual(index, SmiConstant(0)), if_false);
+ GotoIfNot(TaggedEqual(index, SmiConstant(0)), if_false);
BranchIfMapIteratorProtectorValid(&extra_checks, if_false);
BIND(&extra_checks);
// Check if the iterator object has the original %MapIteratorPrototype%.
- Node* const native_context = LoadNativeContext(context);
- Node* const initial_map_iter_proto = LoadContextElement(
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const initial_map_iter_proto = LoadContextElement(
native_context, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX);
- Node* const map_iter_proto = LoadMapPrototype(iter_map);
- GotoIfNot(WordEqual(map_iter_proto, initial_map_iter_proto), if_false);
+ TNode<HeapObject> const map_iter_proto = LoadMapPrototype(iter_map);
+ GotoIfNot(TaggedEqual(map_iter_proto, initial_map_iter_proto), if_false);
// Check if the original MapIterator prototype has the original
// %IteratorPrototype%.
- Node* const initial_iter_proto = LoadContextElement(
+ TNode<Object> const initial_iter_proto = LoadContextElement(
native_context, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX);
- Node* const iter_proto = LoadMapPrototype(LoadMap(map_iter_proto));
- Branch(WordEqual(iter_proto, initial_iter_proto), if_true, if_false);
+ TNode<HeapObject> const iter_proto =
+ LoadMapPrototype(LoadMap(map_iter_proto));
+ Branch(TaggedEqual(iter_proto, initial_iter_proto), if_true, if_false);
}
void BranchIfIterableWithOriginalKeyOrValueMapIterator(
@@ -883,11 +917,12 @@ void BranchIfIterableWithOriginalKeyOrValueMapIterator(
void CollectionsBuiltinsAssembler::BranchIfSetIteratorProtectorValid(
Label* if_true, Label* if_false) {
- Node* const protector_cell = LoadRoot(RootIndex::kSetIteratorProtector);
+ TNode<PropertyCell> const protector_cell = SetIteratorProtectorConstant();
DCHECK(isolate()->heap()->set_iterator_protector().IsPropertyCell());
- Branch(WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
- SmiConstant(Isolate::kProtectorValid)),
- if_true, if_false);
+ Branch(
+ TaggedEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
+ SmiConstant(Isolate::kProtectorValid)),
+ if_true, if_false);
}
void CollectionsBuiltinsAssembler::BranchIfIterableWithOriginalValueSetIterator(
@@ -898,7 +933,7 @@ void CollectionsBuiltinsAssembler::BranchIfIterableWithOriginalValueSetIterator(
GotoIf(TaggedIsSmi(iterable), if_false);
TNode<Map> iterable_map = LoadMap(CAST(iterable));
- Node* const instance_type = LoadMapInstanceType(iterable_map);
+ TNode<Uint16T> const instance_type = LoadMapInstanceType(iterable_map);
GotoIf(InstanceTypeEqual(instance_type, JS_SET_TYPE), &if_set);
Branch(InstanceTypeEqual(instance_type, JS_SET_VALUE_ITERATOR_TYPE),
@@ -906,31 +941,32 @@ void CollectionsBuiltinsAssembler::BranchIfIterableWithOriginalValueSetIterator(
BIND(&if_set);
// Check if the set object has the original Set prototype.
- Node* const initial_set_proto = LoadContextElement(
+ TNode<Object> const initial_set_proto = LoadContextElement(
LoadNativeContext(context), Context::INITIAL_SET_PROTOTYPE_INDEX);
- Node* const set_proto = LoadMapPrototype(iterable_map);
- GotoIfNot(WordEqual(set_proto, initial_set_proto), if_false);
+ TNode<HeapObject> const set_proto = LoadMapPrototype(iterable_map);
+ GotoIfNot(TaggedEqual(set_proto, initial_set_proto), if_false);
Goto(&check_protector);
BIND(&if_value_iterator);
// Check that the iterator is not partially consumed.
- Node* const index =
+ TNode<Object> const index =
LoadObjectField(CAST(iterable), JSSetIterator::kIndexOffset);
- GotoIfNot(WordEqual(index, SmiConstant(0)), if_false);
+ GotoIfNot(TaggedEqual(index, SmiConstant(0)), if_false);
// Check if the iterator object has the original SetIterator prototype.
- Node* const native_context = LoadNativeContext(context);
- Node* const initial_set_iter_proto = LoadContextElement(
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const initial_set_iter_proto = LoadContextElement(
native_context, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX);
- Node* const set_iter_proto = LoadMapPrototype(iterable_map);
- GotoIfNot(WordEqual(set_iter_proto, initial_set_iter_proto), if_false);
+ TNode<HeapObject> const set_iter_proto = LoadMapPrototype(iterable_map);
+ GotoIfNot(TaggedEqual(set_iter_proto, initial_set_iter_proto), if_false);
// Check if the original SetIterator prototype has the original
// %IteratorPrototype%.
- Node* const initial_iter_proto = LoadContextElement(
+ TNode<Object> const initial_iter_proto = LoadContextElement(
native_context, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX);
- Node* const iter_proto = LoadMapPrototype(LoadMap(set_iter_proto));
- GotoIfNot(WordEqual(iter_proto, initial_iter_proto), if_false);
+ TNode<HeapObject> const iter_proto =
+ LoadMapPrototype(LoadMap(set_iter_proto));
+ GotoIfNot(TaggedEqual(iter_proto, initial_iter_proto), if_false);
Goto(&check_protector);
BIND(&check_protector);
@@ -1043,7 +1079,7 @@ TNode<JSArray> CollectionsBuiltinsAssembler::SetOrSetIteratorToList(
TVARIABLE(OrderedHashSet, var_table);
Label if_set(this), if_iterator(this), copy(this);
- Node* const instance_type = LoadInstanceType(CAST(iterable));
+ TNode<Uint16T> const instance_type = LoadInstanceType(CAST(iterable));
Branch(InstanceTypeEqual(instance_type, JS_SET_TYPE), &if_set, &if_iterator);
BIND(&if_set);
@@ -1128,15 +1164,16 @@ TF_BUILTIN(SetOrSetIteratorToList, CollectionsBuiltinsAssembler) {
template <typename CollectionType>
void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForSmiKey(
- Node* table, Node* smi_key, Variable* result, Label* entry_found,
+ Node* table, SloppyTNode<Smi> smi_key, Variable* result, Label* entry_found,
Label* not_found) {
- Node* const key_untagged = SmiUntag(smi_key);
- Node* const hash = ChangeInt32ToIntPtr(ComputeUnseededHash(key_untagged));
+ TNode<IntPtrT> const key_untagged = SmiUntag(smi_key);
+ TNode<IntPtrT> const hash =
+ ChangeInt32ToIntPtr(ComputeUnseededHash(key_untagged));
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
result->Bind(hash);
FindOrderedHashTableEntry<CollectionType>(
table, hash,
- [&](Node* other_key, Label* if_same, Label* if_not_same) {
+ [&](TNode<Object> other_key, Label* if_same, Label* if_not_same) {
SameValueZeroSmi(smi_key, other_key, if_same, if_not_same);
},
result, entry_found, not_found);
@@ -1144,14 +1181,14 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForSmiKey(
template <typename CollectionType>
void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForStringKey(
- Node* context, Node* table, Node* key_tagged, Variable* result,
- Label* entry_found, Label* not_found) {
- Node* const hash = ComputeStringHash(context, key_tagged);
+ SloppyTNode<Context> context, Node* table, SloppyTNode<String> key_tagged,
+ Variable* result, Label* entry_found, Label* not_found) {
+ TNode<IntPtrT> const hash = ComputeStringHash(context, key_tagged);
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
result->Bind(hash);
FindOrderedHashTableEntry<CollectionType>(
table, hash,
- [&](Node* other_key, Label* if_same, Label* if_not_same) {
+ [&](TNode<Object> other_key, Label* if_same, Label* if_not_same) {
SameValueZeroString(context, key_tagged, other_key, if_same,
if_not_same);
},
@@ -1160,15 +1197,16 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForStringKey(
template <typename CollectionType>
void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForHeapNumberKey(
- Node* context, Node* table, Node* key_heap_number, Variable* result,
+ SloppyTNode<Context> context, Node* table,
+ SloppyTNode<HeapNumber> key_heap_number, Variable* result,
Label* entry_found, Label* not_found) {
- Node* hash = CallGetHashRaw(key_heap_number);
+ TNode<IntPtrT> const hash = CallGetHashRaw(key_heap_number);
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
result->Bind(hash);
- Node* const key_float = LoadHeapNumberValue(key_heap_number);
+ TNode<Float64T> const key_float = LoadHeapNumberValue(key_heap_number);
FindOrderedHashTableEntry<CollectionType>(
table, hash,
- [&](Node* other_key, Label* if_same, Label* if_not_same) {
+ [&](TNode<Object> other_key, Label* if_same, Label* if_not_same) {
SameValueZeroHeapNumber(key_float, other_key, if_same, if_not_same);
},
result, entry_found, not_found);
@@ -1176,14 +1214,14 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForHeapNumberKey(
template <typename CollectionType>
void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForBigIntKey(
- Node* context, Node* table, Node* key, Variable* result, Label* entry_found,
- Label* not_found) {
- Node* hash = CallGetHashRaw(key);
+ SloppyTNode<Context> context, Node* table, Node* key, Variable* result,
+ Label* entry_found, Label* not_found) {
+ TNode<IntPtrT> const hash = CallGetHashRaw(key);
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
result->Bind(hash);
FindOrderedHashTableEntry<CollectionType>(
table, hash,
- [&](Node* other_key, Label* if_same, Label* if_not_same) {
+ [&](TNode<Object> other_key, Label* if_same, Label* if_not_same) {
SameValueZeroBigInt(key, other_key, if_same, if_not_same);
},
result, entry_found, not_found);
@@ -1191,49 +1229,47 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForBigIntKey(
template <typename CollectionType>
void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForOtherKey(
- Node* context, Node* table, Node* key, Variable* result, Label* entry_found,
- Label* not_found) {
- Node* hash = GetHash(key);
+ SloppyTNode<Context> context, Node* table, SloppyTNode<HeapObject> key,
+ Variable* result, Label* entry_found, Label* not_found) {
+ TNode<IntPtrT> const hash = GetHash(key);
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
result->Bind(hash);
FindOrderedHashTableEntry<CollectionType>(
table, hash,
- [&](Node* other_key, Label* if_same, Label* if_not_same) {
- Branch(WordEqual(key, other_key), if_same, if_not_same);
+ [&](TNode<Object> other_key, Label* if_same, Label* if_not_same) {
+ Branch(TaggedEqual(key, other_key), if_same, if_not_same);
},
result, entry_found, not_found);
}
-Node* CollectionsBuiltinsAssembler::ComputeStringHash(Node* context,
- Node* string_key) {
- VARIABLE(var_result, MachineType::PointerRepresentation());
+TNode<IntPtrT> CollectionsBuiltinsAssembler::ComputeStringHash(
+ TNode<Context> context, TNode<String> string_key) {
+ TVARIABLE(IntPtrT, var_result);
Label hash_not_computed(this), done(this, &var_result);
- Node* hash =
+ TNode<IntPtrT> const hash =
ChangeInt32ToIntPtr(LoadNameHash(string_key, &hash_not_computed));
- var_result.Bind(hash);
+ var_result = hash;
Goto(&done);
BIND(&hash_not_computed);
- var_result.Bind(CallGetHashRaw(string_key));
+ var_result = CallGetHashRaw(string_key);
Goto(&done);
BIND(&done);
return var_result.value();
}
-void CollectionsBuiltinsAssembler::SameValueZeroString(Node* context,
- Node* key_string,
- Node* candidate_key,
- Label* if_same,
- Label* if_not_same) {
+void CollectionsBuiltinsAssembler::SameValueZeroString(
+ SloppyTNode<Context> context, SloppyTNode<String> key_string,
+ SloppyTNode<Object> candidate_key, Label* if_same, Label* if_not_same) {
// If the candidate is not a string, the keys are not equal.
GotoIf(TaggedIsSmi(candidate_key), if_not_same);
- GotoIfNot(IsString(candidate_key), if_not_same);
+ GotoIfNot(IsString(CAST(candidate_key)), if_not_same);
- Branch(WordEqual(CallBuiltin(Builtins::kStringEqual, context, key_string,
- candidate_key),
- TrueConstant()),
+ Branch(TaggedEqual(CallBuiltin(Builtins::kStringEqual, context, key_string,
+ candidate_key),
+ TrueConstant()),
if_same, if_not_same);
}
@@ -1245,24 +1281,24 @@ void CollectionsBuiltinsAssembler::SameValueZeroBigInt(Node* key,
GotoIf(TaggedIsSmi(candidate_key), if_not_same);
GotoIfNot(IsBigInt(candidate_key), if_not_same);
- Branch(WordEqual(CallRuntime(Runtime::kBigIntEqualToBigInt,
- NoContextConstant(), key, candidate_key),
- TrueConstant()),
+ Branch(TaggedEqual(CallRuntime(Runtime::kBigIntEqualToBigInt,
+ NoContextConstant(), key, candidate_key),
+ TrueConstant()),
if_same, if_not_same);
}
-void CollectionsBuiltinsAssembler::SameValueZeroHeapNumber(Node* key_float,
- Node* candidate_key,
- Label* if_same,
- Label* if_not_same) {
+void CollectionsBuiltinsAssembler::SameValueZeroHeapNumber(
+ SloppyTNode<Float64T> key_float, SloppyTNode<Object> candidate_key,
+ Label* if_same, Label* if_not_same) {
Label if_smi(this), if_keyisnan(this);
GotoIf(TaggedIsSmi(candidate_key), &if_smi);
- GotoIfNot(IsHeapNumber(candidate_key), if_not_same);
+ GotoIfNot(IsHeapNumber(CAST(candidate_key)), if_not_same);
{
// {candidate_key} is a heap number.
- Node* const candidate_float = LoadHeapNumberValue(candidate_key);
+ TNode<Float64T> const candidate_float =
+ LoadHeapNumberValue(CAST(candidate_key));
GotoIf(Float64Equal(key_float, candidate_float), if_same);
// SameValueZero needs to treat NaNs as equal. First check if {key_float}
@@ -1279,7 +1315,7 @@ void CollectionsBuiltinsAssembler::SameValueZeroHeapNumber(Node* key_float,
BIND(&if_smi);
{
- Node* const candidate_float = SmiToFloat64(candidate_key);
+ TNode<Float64T> const candidate_float = SmiToFloat64(CAST(candidate_key));
Branch(Float64Equal(key_float, candidate_float), if_same, if_not_same);
}
}
@@ -1295,12 +1331,12 @@ TF_BUILTIN(OrderedHashTableHealIndex, CollectionsBuiltinsAssembler) {
// Check if the {table} was cleared.
STATIC_ASSERT(OrderedHashMap::NumberOfDeletedElementsOffset() ==
OrderedHashSet::NumberOfDeletedElementsOffset());
- Node* number_of_deleted_elements = LoadAndUntagObjectField(
+ TNode<IntPtrT> number_of_deleted_elements = LoadAndUntagObjectField(
table, OrderedHashMap::NumberOfDeletedElementsOffset());
STATIC_ASSERT(OrderedHashMap::kClearedTableSentinel ==
OrderedHashSet::kClearedTableSentinel);
- GotoIf(WordEqual(number_of_deleted_elements,
- IntPtrConstant(OrderedHashMap::kClearedTableSentinel)),
+ GotoIf(IntPtrEqual(number_of_deleted_elements,
+ IntPtrConstant(OrderedHashMap::kClearedTableSentinel)),
&return_zero);
VARIABLE(var_i, MachineType::PointerRepresentation(), IntPtrConstant(0));
@@ -1430,7 +1466,7 @@ TF_BUILTIN(MapPrototypeGet, CollectionsBuiltinsAssembler) {
ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.get");
- Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
+ TNode<Object> const table = LoadObjectField(receiver, JSMap::kTableOffset);
TNode<Smi> index = CAST(
CallBuiltin(Builtins::kFindOrderedHashMapEntry, context, table, key));
@@ -1455,7 +1491,7 @@ TF_BUILTIN(MapPrototypeHas, CollectionsBuiltinsAssembler) {
ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, "Map.prototype.has");
- Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
+ TNode<Object> const table = LoadObjectField(receiver, JSMap::kTableOffset);
TNode<Smi> index = CAST(
CallBuiltin(Builtins::kFindOrderedHashMapEntry, context, table, key));
@@ -1476,7 +1512,7 @@ Node* CollectionsBuiltinsAssembler::NormalizeNumberKey(Node* const key) {
GotoIf(TaggedIsSmi(key), &done);
GotoIfNot(IsHeapNumber(key), &done);
- Node* const number = LoadHeapNumberValue(key);
+ TNode<Float64T> const number = LoadHeapNumberValue(key);
GotoIfNot(Float64Equal(number, Float64Constant(0.0)), &done);
// We know the value is zero, so we take the key to be Smi 0.
// Another option would be to normalize to Smi here.
@@ -1539,10 +1575,10 @@ TF_BUILTIN(MapPrototypeSet, CollectionsBuiltinsAssembler) {
table, OrderedHashMap::NumberOfBucketsIndex()))));
STATIC_ASSERT(OrderedHashMap::kLoadFactor == 2);
- Node* const capacity = WordShl(number_of_buckets.value(), 1);
- Node* const number_of_elements = SmiUntag(
+ TNode<WordT> const capacity = WordShl(number_of_buckets.value(), 1);
+ TNode<IntPtrT> const number_of_elements = SmiUntag(
CAST(LoadObjectField(table, OrderedHashMap::NumberOfElementsOffset())));
- Node* const number_of_deleted = SmiUntag(CAST(LoadObjectField(
+ TNode<IntPtrT> const number_of_deleted = SmiUntag(CAST(LoadObjectField(
table, OrderedHashMap::NumberOfDeletedElementsOffset())));
occupancy.Bind(IntPtrAdd(number_of_elements, number_of_deleted));
GotoIf(IntPtrLessThan(occupancy.value(), capacity), &store_new_entry);
@@ -1553,9 +1589,9 @@ TF_BUILTIN(MapPrototypeSet, CollectionsBuiltinsAssembler) {
table_var = CAST(LoadObjectField(receiver, JSMap::kTableOffset));
number_of_buckets.Bind(SmiUntag(CAST(UnsafeLoadFixedArrayElement(
table_var.value(), OrderedHashMap::NumberOfBucketsIndex()))));
- Node* const new_number_of_elements = SmiUntag(CAST(LoadObjectField(
+ TNode<IntPtrT> const new_number_of_elements = SmiUntag(CAST(LoadObjectField(
table_var.value(), OrderedHashMap::NumberOfElementsOffset())));
- Node* const new_number_of_deleted = SmiUntag(CAST(LoadObjectField(
+ TNode<IntPtrT> const new_number_of_deleted = SmiUntag(CAST(LoadObjectField(
table_var.value(), OrderedHashMap::NumberOfDeletedElementsOffset())));
occupancy.Bind(IntPtrAdd(new_number_of_elements, new_number_of_deleted));
Goto(&store_new_entry);
@@ -1571,13 +1607,13 @@ TF_BUILTIN(MapPrototypeSet, CollectionsBuiltinsAssembler) {
void CollectionsBuiltinsAssembler::StoreOrderedHashMapNewEntry(
TNode<OrderedHashMap> const table, Node* const key, Node* const value,
Node* const hash, Node* const number_of_buckets, Node* const occupancy) {
- Node* const bucket =
+ TNode<WordT> const bucket =
WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1)));
TNode<Smi> bucket_entry = CAST(UnsafeLoadFixedArrayElement(
table, bucket, OrderedHashMap::HashTableStartIndex() * kTaggedSize));
// Store the entry elements.
- Node* const entry_start = IntPtrAdd(
+ TNode<WordT> const entry_start = IntPtrAdd(
IntPtrMul(occupancy, IntPtrConstant(OrderedHashMap::kEntrySize)),
number_of_buckets);
UnsafeStoreFixedArrayElement(
@@ -1713,10 +1749,10 @@ TF_BUILTIN(SetPrototypeAdd, CollectionsBuiltinsAssembler) {
table, OrderedHashSet::NumberOfBucketsIndex()))));
STATIC_ASSERT(OrderedHashSet::kLoadFactor == 2);
- Node* const capacity = WordShl(number_of_buckets.value(), 1);
- Node* const number_of_elements = SmiUntag(
+ TNode<WordT> const capacity = WordShl(number_of_buckets.value(), 1);
+ TNode<IntPtrT> const number_of_elements = SmiUntag(
CAST(LoadObjectField(table, OrderedHashSet::NumberOfElementsOffset())));
- Node* const number_of_deleted = SmiUntag(CAST(LoadObjectField(
+ TNode<IntPtrT> const number_of_deleted = SmiUntag(CAST(LoadObjectField(
table, OrderedHashSet::NumberOfDeletedElementsOffset())));
occupancy.Bind(IntPtrAdd(number_of_elements, number_of_deleted));
GotoIf(IntPtrLessThan(occupancy.value(), capacity), &store_new_entry);
@@ -1727,9 +1763,9 @@ TF_BUILTIN(SetPrototypeAdd, CollectionsBuiltinsAssembler) {
table_var = CAST(LoadObjectField(receiver, JSMap::kTableOffset));
number_of_buckets.Bind(SmiUntag(CAST(UnsafeLoadFixedArrayElement(
table_var.value(), OrderedHashSet::NumberOfBucketsIndex()))));
- Node* const new_number_of_elements = SmiUntag(CAST(LoadObjectField(
+ TNode<IntPtrT> const new_number_of_elements = SmiUntag(CAST(LoadObjectField(
table_var.value(), OrderedHashSet::NumberOfElementsOffset())));
- Node* const new_number_of_deleted = SmiUntag(CAST(LoadObjectField(
+ TNode<IntPtrT> const new_number_of_deleted = SmiUntag(CAST(LoadObjectField(
table_var.value(), OrderedHashSet::NumberOfDeletedElementsOffset())));
occupancy.Bind(IntPtrAdd(new_number_of_elements, new_number_of_deleted));
Goto(&store_new_entry);
@@ -1745,13 +1781,13 @@ TF_BUILTIN(SetPrototypeAdd, CollectionsBuiltinsAssembler) {
void CollectionsBuiltinsAssembler::StoreOrderedHashSetNewEntry(
TNode<OrderedHashSet> const table, Node* const key, Node* const hash,
Node* const number_of_buckets, Node* const occupancy) {
- Node* const bucket =
+ TNode<WordT> const bucket =
WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1)));
TNode<Smi> bucket_entry = CAST(UnsafeLoadFixedArrayElement(
table, bucket, OrderedHashSet::HashTableStartIndex() * kTaggedSize));
// Store the entry elements.
- Node* const entry_start = IntPtrAdd(
+ TNode<WordT> const entry_start = IntPtrAdd(
IntPtrMul(occupancy, IntPtrConstant(OrderedHashSet::kEntrySize)),
number_of_buckets);
UnsafeStoreFixedArrayElement(
@@ -1846,7 +1882,8 @@ TF_BUILTIN(MapPrototypeGetSize, CollectionsBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE,
"get Map.prototype.size");
- Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
+ TNode<OrderedHashMap> const table =
+ CAST(LoadObjectField(receiver, JSMap::kTableOffset));
Return(LoadObjectField(table, OrderedHashMap::NumberOfElementsOffset()));
}
@@ -1855,20 +1892,20 @@ TF_BUILTIN(MapPrototypeForEach, CollectionsBuiltinsAssembler) {
Node* const argc = Parameter(Descriptor::kJSActualArgumentsCount);
Node* const context = Parameter(Descriptor::kContext);
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
- Node* const receiver = args.GetReceiver();
- Node* const callback = args.GetOptionalArgumentValue(0);
- Node* const this_arg = args.GetOptionalArgumentValue(1);
+ TNode<Object> const receiver = args.GetReceiver();
+ TNode<Object> const callback = args.GetOptionalArgumentValue(0);
+ TNode<Object> const this_arg = args.GetOptionalArgumentValue(1);
ThrowIfNotInstanceType(context, receiver, JS_MAP_TYPE, kMethodName);
// Ensure that {callback} is actually callable.
Label callback_not_callable(this, Label::kDeferred);
GotoIf(TaggedIsSmi(callback), &callback_not_callable);
- GotoIfNot(IsCallable(callback), &callback_not_callable);
+ GotoIfNot(IsCallable(CAST(callback)), &callback_not_callable);
TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
TVARIABLE(OrderedHashMap, var_table,
- CAST(LoadObjectField(receiver, JSMap::kTableOffset)));
+ CAST(LoadObjectField(CAST(receiver), JSMap::kTableOffset)));
Label loop(this, {&var_index, &var_table}), done_loop(this);
Goto(&loop);
BIND(&loop);
@@ -1887,7 +1924,7 @@ TF_BUILTIN(MapPrototypeForEach, CollectionsBuiltinsAssembler) {
NextSkipHoles<OrderedHashMap>(table, index, &done_loop);
// Load the entry value as well.
- Node* entry_value = LoadFixedArrayElement(
+ TNode<Object> entry_value = LoadFixedArrayElement(
table, entry_start_position,
(OrderedHashMap::HashTableStartIndex() + OrderedHashMap::kValueOffset) *
kTaggedSize);
@@ -1938,7 +1975,7 @@ TF_BUILTIN(MapIteratorPrototypeNext, CollectionsBuiltinsAssembler) {
// Ensure that the {receiver} is actually a JSMapIterator.
Label if_receiver_valid(this), if_receiver_invalid(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &if_receiver_invalid);
- Node* const receiver_instance_type = LoadInstanceType(receiver);
+ TNode<Uint16T> const receiver_instance_type = LoadInstanceType(receiver);
GotoIf(
InstanceTypeEqual(receiver_instance_type, JS_MAP_KEY_VALUE_ITERATOR_TYPE),
&if_receiver_valid);
@@ -1992,7 +2029,7 @@ TF_BUILTIN(MapIteratorPrototypeNext, CollectionsBuiltinsAssembler) {
BIND(&return_value);
{
- Node* result =
+ TNode<JSObject> result =
AllocateJSIteratorResult(context, var_value.value(), var_done.value());
Return(result);
}
@@ -2012,7 +2049,7 @@ TF_BUILTIN(SetPrototypeHas, CollectionsBuiltinsAssembler) {
ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE, "Set.prototype.has");
- Node* const table = LoadObjectField(receiver, JSMap::kTableOffset);
+ TNode<Object> const table = LoadObjectField(receiver, JSMap::kTableOffset);
VARIABLE(entry_start_position, MachineType::PointerRepresentation(),
IntPtrConstant(0));
@@ -2022,8 +2059,8 @@ TF_BUILTIN(SetPrototypeHas, CollectionsBuiltinsAssembler) {
GotoIf(TaggedIsSmi(key), &if_key_smi);
- Node* key_map = LoadMap(key);
- Node* key_instance_type = LoadMapInstanceType(key_map);
+ TNode<Map> key_map = LoadMap(key);
+ TNode<Uint16T> key_instance_type = LoadMapInstanceType(key_map);
GotoIf(IsStringInstanceType(key_instance_type), &if_key_string);
GotoIf(IsHeapNumberMap(key_map), &if_key_heap_number);
@@ -2077,7 +2114,8 @@ TF_BUILTIN(SetPrototypeGetSize, CollectionsBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE,
"get Set.prototype.size");
- Node* const table = LoadObjectField(receiver, JSSet::kTableOffset);
+ TNode<OrderedHashSet> const table =
+ CAST(LoadObjectField(receiver, JSSet::kTableOffset));
Return(LoadObjectField(table, OrderedHashSet::NumberOfElementsOffset()));
}
@@ -2086,20 +2124,20 @@ TF_BUILTIN(SetPrototypeForEach, CollectionsBuiltinsAssembler) {
Node* const argc = Parameter(Descriptor::kJSActualArgumentsCount);
Node* const context = Parameter(Descriptor::kContext);
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
- Node* const receiver = args.GetReceiver();
- Node* const callback = args.GetOptionalArgumentValue(0);
- Node* const this_arg = args.GetOptionalArgumentValue(1);
+ TNode<Object> const receiver = args.GetReceiver();
+ TNode<Object> const callback = args.GetOptionalArgumentValue(0);
+ TNode<Object> const this_arg = args.GetOptionalArgumentValue(1);
ThrowIfNotInstanceType(context, receiver, JS_SET_TYPE, kMethodName);
// Ensure that {callback} is actually callable.
Label callback_not_callable(this, Label::kDeferred);
GotoIf(TaggedIsSmi(callback), &callback_not_callable);
- GotoIfNot(IsCallable(callback), &callback_not_callable);
+ GotoIfNot(IsCallable(CAST(callback)), &callback_not_callable);
TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
TVARIABLE(OrderedHashSet, var_table,
- CAST(LoadObjectField(receiver, JSSet::kTableOffset)));
+ CAST(LoadObjectField(CAST(receiver), JSSet::kTableOffset)));
Label loop(this, {&var_index, &var_table}), done_loop(this);
Goto(&loop);
BIND(&loop);
@@ -2154,7 +2192,7 @@ TF_BUILTIN(SetIteratorPrototypeNext, CollectionsBuiltinsAssembler) {
// Ensure that the {receiver} is actually a JSSetIterator.
Label if_receiver_valid(this), if_receiver_invalid(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &if_receiver_invalid);
- Node* const receiver_instance_type = LoadInstanceType(receiver);
+ TNode<Uint16T> const receiver_instance_type = LoadInstanceType(receiver);
GotoIf(InstanceTypeEqual(receiver_instance_type, JS_SET_VALUE_ITERATOR_TYPE),
&if_receiver_valid);
Branch(
@@ -2200,7 +2238,7 @@ TF_BUILTIN(SetIteratorPrototypeNext, CollectionsBuiltinsAssembler) {
BIND(&return_value);
{
- Node* result =
+ TNode<JSObject> result =
AllocateJSIteratorResult(context, var_value.value(), var_done.value());
Return(result);
}
@@ -2222,8 +2260,8 @@ void CollectionsBuiltinsAssembler::TryLookupOrderedHashTableIndex(
GotoIf(TaggedIsSmi(key), &if_key_smi);
- Node* key_map = LoadMap(key);
- Node* key_instance_type = LoadMapInstanceType(key_map);
+ TNode<Map> key_map = LoadMap(key);
+ TNode<Uint16T> key_instance_type = LoadMapInstanceType(key_map);
GotoIf(IsStringInstanceType(key_instance_type), &if_key_string);
GotoIf(IsHeapNumberMap(key_map), &if_key_heap_number);
@@ -2449,7 +2487,7 @@ TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::FindKeyIndexForKey(
auto match_key_or_exit_on_empty = [&](TNode<Object> entry_key,
Label* if_same) {
GotoIf(IsUndefined(entry_key), if_not_found);
- GotoIf(WordEqual(entry_key, key), if_same);
+ GotoIf(TaggedEqual(entry_key, key), if_same);
};
return FindKeyIndex(table, hash, entry_mask, match_key_or_exit_on_empty);
}
@@ -2606,7 +2644,7 @@ TF_BUILTIN(WeakMapGet, WeakCollectionsBuiltinsAssembler) {
TNode<Smi> const index =
CAST(CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key));
- GotoIf(WordEqual(index, SmiConstant(-1)), &return_undefined);
+ GotoIf(TaggedEqual(index, SmiConstant(-1)), &return_undefined);
Return(LoadFixedArrayElement(table, SmiUntag(index)));
@@ -2625,10 +2663,10 @@ TF_BUILTIN(WeakMapPrototypeHas, WeakCollectionsBuiltinsAssembler) {
"WeakMap.prototype.has");
TNode<EphemeronHashTable> const table = LoadTable(CAST(receiver));
- Node* const index =
+ TNode<Object> const index =
CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key);
- GotoIf(WordEqual(index, SmiConstant(-1)), &return_false);
+ GotoIf(TaggedEqual(index, SmiConstant(-1)), &return_false);
Return(TrueConstant());
@@ -2788,11 +2826,11 @@ TF_BUILTIN(WeakSetPrototypeHas, WeakCollectionsBuiltinsAssembler) {
ThrowIfNotInstanceType(context, receiver, JS_WEAK_SET_TYPE,
"WeakSet.prototype.has");
- Node* const table = LoadTable(CAST(receiver));
- Node* const index =
+ TNode<EphemeronHashTable> const table = LoadTable(CAST(receiver));
+ TNode<Object> const index =
CallBuiltin(Builtins::kWeakMapLookupHashIndex, context, table, key);
- GotoIf(WordEqual(index, SmiConstant(-1)), &return_false);
+ GotoIf(TaggedEqual(index, SmiConstant(-1)), &return_false);
Return(TrueConstant());
diff --git a/deps/v8/src/builtins/builtins-console-gen.cc b/deps/v8/src/builtins/builtins-console-gen.cc
index 8dc7e5e8f6..1d6a22f611 100644
--- a/deps/v8/src/builtins/builtins-console-gen.cc
+++ b/deps/v8/src/builtins/builtins-console-gen.cc
@@ -17,7 +17,8 @@ TF_BUILTIN(FastConsoleAssert, CodeStubAssembler) {
// TODO(ishell): use constants from Descriptor once the JSFunction linkage
// arguments are reordered.
- Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);
+ TNode<Int32T> argc =
+ UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
Node* context = Parameter(Descriptor::kContext);
Node* new_target = Parameter(Descriptor::kJSNewTarget);
GotoIf(Word32Equal(argc, Int32Constant(0)), &runtime);
diff --git a/deps/v8/src/builtins/builtins-constructor-gen.cc b/deps/v8/src/builtins/builtins-constructor-gen.cc
index 767e626432..856718cedf 100644
--- a/deps/v8/src/builtins/builtins-constructor-gen.cc
+++ b/deps/v8/src/builtins/builtins-constructor-gen.cc
@@ -68,7 +68,7 @@ TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) {
// Bump the closure counter encoded the {feedback_cell}s map.
{
- Node* const feedback_cell_map = LoadMap(feedback_cell);
+ TNode<Map> const feedback_cell_map = LoadMap(feedback_cell);
Label no_closures(this), one_closure(this), cell_done(this);
GotoIf(IsNoClosuresCellMap(feedback_cell_map), &no_closures);
@@ -93,23 +93,23 @@ TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) {
Node* const flags =
LoadObjectField(shared_function_info, SharedFunctionInfo::kFlagsOffset,
MachineType::Uint32());
- Node* const function_map_index = IntPtrAdd(
+ TNode<IntPtrT> const function_map_index = Signed(IntPtrAdd(
DecodeWordFromWord32<SharedFunctionInfo::FunctionMapIndexBits>(flags),
- IntPtrConstant(Context::FIRST_FUNCTION_MAP_INDEX));
+ IntPtrConstant(Context::FIRST_FUNCTION_MAP_INDEX)));
CSA_ASSERT(this, UintPtrLessThanOrEqual(
function_map_index,
IntPtrConstant(Context::LAST_FUNCTION_MAP_INDEX)));
// Get the function map in the current native context and set that
// as the map of the allocated object.
- Node* const native_context = LoadNativeContext(context);
- Node* const function_map =
- LoadContextElement(native_context, function_map_index);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Map> const function_map =
+ CAST(LoadContextElement(native_context, function_map_index));
// Create a new closure from the given function info in new space
TNode<IntPtrT> instance_size_in_bytes =
TimesTaggedSize(LoadMapInstanceSizeInWords(function_map));
- TNode<Object> result = Allocate(instance_size_in_bytes);
+ TNode<HeapObject> result = Allocate(instance_size_in_bytes);
StoreMapNoWriteBarrier(result, function_map);
InitializeJSObjectBodyNoSlackTracking(result, function_map,
instance_size_in_bytes,
@@ -141,7 +141,7 @@ TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) {
StoreObjectFieldNoWriteBarrier(result, JSFunction::kContextOffset, context);
Handle<Code> lazy_builtin_handle =
isolate()->builtins()->builtin_handle(Builtins::kCompileLazy);
- Node* lazy_builtin = HeapConstant(lazy_builtin_handle);
+ TNode<Code> lazy_builtin = HeapConstant(lazy_builtin_handle);
StoreObjectFieldNoWriteBarrier(result, JSFunction::kCodeOffset, lazy_builtin);
Return(result);
}
@@ -189,16 +189,18 @@ compiler::TNode<JSObject> ConstructorBuiltinsAssembler::EmitFastNewObject(
BIND(&fast);
// Load the initial map and verify that it's in fact a map.
- Node* initial_map =
+ TNode<Object> initial_map_or_proto =
LoadObjectField(new_target, JSFunction::kPrototypeOrInitialMapOffset);
- GotoIf(TaggedIsSmi(initial_map), call_runtime);
- GotoIf(DoesntHaveInstanceType(initial_map, MAP_TYPE), call_runtime);
+ GotoIf(TaggedIsSmi(initial_map_or_proto), call_runtime);
+ GotoIf(DoesntHaveInstanceType(CAST(initial_map_or_proto), MAP_TYPE),
+ call_runtime);
+ TNode<Map> initial_map = CAST(initial_map_or_proto);
// Fall back to runtime if the target differs from the new target's
// initial map constructor.
- Node* new_target_constructor =
+ TNode<Object> new_target_constructor =
LoadObjectField(initial_map, Map::kConstructorOrBackPointerOffset);
- GotoIf(WordNotEqual(target, new_target_constructor), call_runtime);
+ GotoIf(TaggedNotEqual(target, new_target_constructor), call_runtime);
VARIABLE(properties, MachineRepresentation::kTagged);
@@ -253,12 +255,12 @@ Node* ConstructorBuiltinsAssembler::EmitFastNewFunctionContext(
context);
StoreObjectFieldNoWriteBarrier(function_context, Context::kExtensionOffset,
TheHoleConstant());
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
StoreObjectFieldNoWriteBarrier(function_context,
Context::kNativeContextOffset, native_context);
// Initialize the varrest of the slots to undefined.
- TNode<HeapObject> undefined = UndefinedConstant();
+ TNode<Oddball> undefined = UndefinedConstant();
TNode<IntPtrT> start_offset = IntPtrConstant(Context::kTodoHeaderSize);
CodeStubAssembler::VariableList vars(0, zone());
BuildFastLoop(
@@ -302,9 +304,9 @@ Node* ConstructorBuiltinsAssembler::EmitCreateRegExpLiteral(
Node* boilerplate = literal_site;
CSA_ASSERT(this, IsJSRegExp(boilerplate));
int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kTaggedSize;
- Node* copy = Allocate(size);
+ TNode<HeapObject> copy = Allocate(size);
for (int offset = 0; offset < size; offset += kTaggedSize) {
- Node* value = LoadObjectField(boilerplate, offset);
+ TNode<Object> value = LoadObjectField(boilerplate, offset);
StoreObjectFieldNoWriteBarrier(copy, offset, value);
}
result.Bind(copy);
@@ -324,7 +326,7 @@ Node* ConstructorBuiltinsAssembler::EmitCreateRegExpLiteral(
TF_BUILTIN(CreateRegExpLiteral, ConstructorBuiltinsAssembler) {
Node* feedback_vector = Parameter(Descriptor::kFeedbackVector);
- Node* slot = SmiUntag(Parameter(Descriptor::kSlot));
+ TNode<IntPtrT> slot = SmiUntag(Parameter(Descriptor::kSlot));
Node* pattern = Parameter(Descriptor::kPattern);
Node* flags = Parameter(Descriptor::kFlags);
Node* context = Parameter(Descriptor::kContext);
@@ -357,7 +359,7 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowArrayLiteral(
TF_BUILTIN(CreateShallowArrayLiteral, ConstructorBuiltinsAssembler) {
Node* feedback_vector = Parameter(Descriptor::kFeedbackVector);
- Node* slot = SmiUntag(Parameter(Descriptor::kSlot));
+ TNode<IntPtrT> slot = SmiUntag(Parameter(Descriptor::kSlot));
Node* constant_elements = Parameter(Descriptor::kConstantElements);
Node* context = Parameter(Descriptor::kContext);
Label call_runtime(this, Label::kDeferred);
@@ -400,7 +402,7 @@ Node* ConstructorBuiltinsAssembler::EmitCreateEmptyArrayLiteral(
BIND(&create_empty_array);
TNode<Int32T> kind = LoadElementsKind(allocation_site.value());
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
Comment("LoadJSArrayElementsMap");
TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context);
TNode<Smi> zero = SmiConstant(0);
@@ -417,7 +419,7 @@ Node* ConstructorBuiltinsAssembler::EmitCreateEmptyArrayLiteral(
TF_BUILTIN(CreateEmptyArrayLiteral, ConstructorBuiltinsAssembler) {
Node* feedback_vector = Parameter(Descriptor::kFeedbackVector);
- Node* slot = SmiUntag(Parameter(Descriptor::kSlot));
+ TNode<IntPtrT> slot = SmiUntag(Parameter(Descriptor::kSlot));
Node* context = Parameter(Descriptor::kContext);
Node* result = EmitCreateEmptyArrayLiteral(feedback_vector, slot, context);
Return(result);
@@ -436,7 +438,7 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
VARIABLE(var_properties, MachineRepresentation::kTagged);
{
- Node* bit_field_3 = LoadMapBitField3(boilerplate_map);
+ TNode<Uint32T> bit_field_3 = LoadMapBitField3(boilerplate_map);
GotoIf(IsSetWord32<Map::IsDeprecatedBit>(bit_field_3), call_runtime);
// Directly copy over the property store for dict-mode boilerplates.
Label if_dictionary(this), if_fast(this), done(this);
@@ -453,7 +455,8 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
BIND(&if_fast);
{
// TODO(cbruni): support copying out-of-object properties.
- Node* boilerplate_properties = LoadFastProperties(boilerplate);
+ TNode<HeapObject> boilerplate_properties =
+ LoadFastProperties(boilerplate);
GotoIfNot(IsEmptyFixedArray(boilerplate_properties), call_runtime);
var_properties.Bind(EmptyFixedArrayConstant());
Goto(&done);
@@ -465,7 +468,7 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
{
// Copy the elements backing store, assuming that it's flat.
Label if_empty_fixed_array(this), if_copy_elements(this), done(this);
- Node* boilerplate_elements = LoadElements(boilerplate);
+ TNode<FixedArrayBase> boilerplate_elements = LoadElements(boilerplate);
Branch(IsEmptyFixedArray(boilerplate_elements), &if_empty_fixed_array,
&if_copy_elements);
@@ -520,26 +523,28 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
// Copy over in-object properties.
Label continue_with_write_barrier(this), done_init(this);
TVARIABLE(IntPtrT, offset, IntPtrConstant(JSObject::kHeaderSize));
- // Mutable heap numbers only occur on 32-bit platforms.
+ // Heap numbers are only mutable on 32-bit platforms.
bool may_use_mutable_heap_numbers = !FLAG_unbox_double_fields;
{
Comment("Copy in-object properties fast");
Label continue_fast(this, &offset);
- Branch(WordEqual(offset.value(), instance_size), &done_init,
+ Branch(IntPtrEqual(offset.value(), instance_size), &done_init,
&continue_fast);
BIND(&continue_fast);
if (may_use_mutable_heap_numbers) {
TNode<Object> field = LoadObjectField(boilerplate, offset.value());
Label store_field(this);
GotoIf(TaggedIsSmi(field), &store_field);
- GotoIf(IsMutableHeapNumber(CAST(field)), &continue_with_write_barrier);
+ // TODO(leszeks): Read the field descriptor to decide if this heap
+ // number is mutable or not.
+ GotoIf(IsHeapNumber(CAST(field)), &continue_with_write_barrier);
Goto(&store_field);
BIND(&store_field);
StoreObjectFieldNoWriteBarrier(copy, offset.value(), field);
} else {
// Copy fields as raw data.
- TNode<IntPtrT> field =
- LoadObjectField<IntPtrT>(boilerplate, offset.value());
+ TNode<TaggedT> field =
+ LoadObjectField<TaggedT>(boilerplate, offset.value());
StoreObjectFieldNoWriteBarrier(copy, offset.value(), field);
}
offset = IntPtrAdd(offset.value(), IntPtrConstant(kTaggedSize));
@@ -562,7 +567,7 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
offset.value(), instance_size,
[=](Node* offset) {
// TODO(ishell): value decompression is not necessary here.
- Node* field = LoadObjectField(boilerplate, offset);
+ TNode<Object> field = LoadObjectField(boilerplate, offset);
StoreObjectFieldNoWriteBarrier(copy, offset, field);
},
kTaggedSize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
@@ -570,19 +575,20 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
BuildFastLoop(
offset.value(), instance_size,
[=](Node* offset) {
- Node* field = LoadObjectField(copy, offset);
- Label copy_mutable_heap_number(this, Label::kDeferred),
- continue_loop(this);
+ TNode<Object> field = LoadObjectField(copy, offset);
+ Label copy_heap_number(this, Label::kDeferred), continue_loop(this);
// We only have to clone complex field values.
GotoIf(TaggedIsSmi(field), &continue_loop);
- Branch(IsMutableHeapNumber(field), &copy_mutable_heap_number,
+ // TODO(leszeks): Read the field descriptor to decide if this heap
+ // number is mutable or not.
+ Branch(IsHeapNumber(CAST(field)), &copy_heap_number,
&continue_loop);
- BIND(&copy_mutable_heap_number);
+ BIND(&copy_heap_number);
{
- Node* double_value = LoadHeapNumberValue(field);
- Node* mutable_heap_number =
- AllocateMutableHeapNumberWithValue(double_value);
- StoreObjectField(copy, offset, mutable_heap_number);
+ TNode<Float64T> double_value = LoadHeapNumberValue(CAST(field));
+ TNode<HeapNumber> heap_number =
+ AllocateHeapNumberWithValue(double_value);
+ StoreObjectField(copy, offset, heap_number);
Goto(&continue_loop);
}
BIND(&continue_loop);
@@ -598,7 +604,7 @@ Node* ConstructorBuiltinsAssembler::EmitCreateShallowObjectLiteral(
TF_BUILTIN(CreateShallowObjectLiteral, ConstructorBuiltinsAssembler) {
Label call_runtime(this);
Node* feedback_vector = Parameter(Descriptor::kFeedbackVector);
- Node* slot = SmiUntag(Parameter(Descriptor::kSlot));
+ TNode<IntPtrT> slot = SmiUntag(Parameter(Descriptor::kSlot));
Node* copy =
EmitCreateShallowObjectLiteral(feedback_vector, slot, &call_runtime);
Return(copy);
@@ -615,18 +621,17 @@ TF_BUILTIN(CreateShallowObjectLiteral, ConstructorBuiltinsAssembler) {
// Used by the CreateEmptyObjectLiteral bytecode and the Object constructor.
Node* ConstructorBuiltinsAssembler::EmitCreateEmptyObjectLiteral(
Node* context) {
- Node* native_context = LoadNativeContext(context);
- Node* object_function =
- LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX);
- Node* map = LoadObjectField(object_function,
- JSFunction::kPrototypeOrInitialMapOffset);
- CSA_ASSERT(this, IsMap(map));
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> object_function =
+ CAST(LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX));
+ TNode<Map> map = CAST(LoadObjectField(
+ object_function, JSFunction::kPrototypeOrInitialMapOffset));
// Ensure that slack tracking is disabled for the map.
STATIC_ASSERT(Map::kNoSlackTracking == 0);
CSA_ASSERT(
this, IsClearWord32<Map::ConstructionCounterBits>(LoadMapBitField3(map)));
- Node* empty_fixed_array = EmptyFixedArrayConstant();
- Node* result =
+ TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
+ TNode<JSObject> result =
AllocateJSObjectFromMap(map, empty_fixed_array, empty_fixed_array);
return result;
}
@@ -634,22 +639,22 @@ Node* ConstructorBuiltinsAssembler::EmitCreateEmptyObjectLiteral(
// ES #sec-object-constructor
TF_BUILTIN(ObjectConstructor, ConstructorBuiltinsAssembler) {
int const kValueArg = 0;
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
Node* context = Parameter(Descriptor::kContext);
- Node* new_target = Parameter(Descriptor::kJSNewTarget);
+ TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
VARIABLE(var_result, MachineRepresentation::kTagged);
Label if_subclass(this, Label::kDeferred), if_notsubclass(this),
return_result(this);
GotoIf(IsUndefined(new_target), &if_notsubclass);
TNode<JSFunction> target = CAST(Parameter(Descriptor::kJSTarget));
- Branch(WordEqual(new_target, target), &if_notsubclass, &if_subclass);
+ Branch(TaggedEqual(new_target, target), &if_notsubclass, &if_subclass);
BIND(&if_subclass);
{
- Node* result =
+ TNode<Object> result =
CallBuiltin(Builtins::kFastNewObject, context, target, new_target);
var_result.Bind(result);
Goto(&return_result);
@@ -659,9 +664,9 @@ TF_BUILTIN(ObjectConstructor, ConstructorBuiltinsAssembler) {
{
Label if_newobject(this, Label::kDeferred), if_toobject(this);
- Node* value_index = IntPtrConstant(kValueArg);
+ TNode<IntPtrT> value_index = IntPtrConstant(kValueArg);
GotoIf(UintPtrGreaterThanOrEqual(value_index, argc), &if_newobject);
- Node* value = args.AtIndex(value_index);
+ TNode<Object> value = args.AtIndex(value_index);
GotoIf(IsNull(value), &if_newobject);
Branch(IsUndefined(value), &if_newobject, &if_toobject);
@@ -674,7 +679,7 @@ TF_BUILTIN(ObjectConstructor, ConstructorBuiltinsAssembler) {
BIND(&if_toobject);
{
- Node* result = CallBuiltin(Builtins::kToObject, context, value);
+ TNode<Object> result = CallBuiltin(Builtins::kToObject, context, value);
var_result.Bind(result);
Goto(&return_result);
}
@@ -687,20 +692,20 @@ TF_BUILTIN(ObjectConstructor, ConstructorBuiltinsAssembler) {
// ES #sec-number-constructor
TF_BUILTIN(NumberConstructor, ConstructorBuiltinsAssembler) {
Node* context = Parameter(Descriptor::kContext);
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
// 1. If no arguments were passed to this function invocation, let n be +0.
VARIABLE(var_n, MachineRepresentation::kTagged, SmiConstant(0));
Label if_nloaded(this, &var_n);
- GotoIf(WordEqual(argc, IntPtrConstant(0)), &if_nloaded);
+ GotoIf(IntPtrEqual(argc, IntPtrConstant(0)), &if_nloaded);
// 2. Else,
// a. Let prim be ? ToNumeric(value).
// b. If Type(prim) is BigInt, let n be the Number value for prim.
// c. Otherwise, let n be prim.
- Node* value = args.AtIndex(0);
+ TNode<Object> value = args.AtIndex(0);
var_n.Bind(ToNumber(context, value, BigIntHandling::kConvertToNumber));
Goto(&if_nloaded);
@@ -726,7 +731,7 @@ TF_BUILTIN(NumberConstructor, ConstructorBuiltinsAssembler) {
// from the current frame here in order to reduce register pressure on the
// fast path.
TNode<JSFunction> target = LoadTargetFromFrame();
- Node* result =
+ TNode<Object> result =
CallBuiltin(Builtins::kFastNewObject, context, target, new_target);
StoreObjectField(result, JSPrimitiveWrapper::kValueOffset, n_value);
args.PopAndReturn(result);
@@ -739,66 +744,5 @@ TF_BUILTIN(GenericLazyDeoptContinuation, ConstructorBuiltinsAssembler) {
Return(result);
}
-// https://tc39.github.io/ecma262/#sec-string-constructor
-TF_BUILTIN(StringConstructor, ConstructorBuiltinsAssembler) {
- Node* context = Parameter(Descriptor::kContext);
- Node* argc =
- ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
- CodeStubArguments args(this, argc);
-
- TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
-
- // 1. If no arguments were passed to this function invocation, let s be "".
- VARIABLE(var_s, MachineRepresentation::kTagged, EmptyStringConstant());
- Label if_sloaded(this, &var_s);
- GotoIf(WordEqual(argc, IntPtrConstant(0)), &if_sloaded);
-
- // 2. Else,
- // a. If NewTarget is undefined [...]
- Node* value = args.AtIndex(0);
- Label if_tostring(this, &var_s);
- GotoIfNot(IsUndefined(new_target), &if_tostring);
-
- // 2a. [...] and Type(value) is Symbol, return SymbolDescriptiveString(value).
- GotoIf(TaggedIsSmi(value), &if_tostring);
- GotoIfNot(IsSymbol(value), &if_tostring);
- {
- Node* result =
- CallRuntime(Runtime::kSymbolDescriptiveString, context, value);
- args.PopAndReturn(result);
- }
-
- // 2b. Let s be ? ToString(value).
- BIND(&if_tostring);
- {
- var_s.Bind(CallBuiltin(Builtins::kToString, context, value));
- Goto(&if_sloaded);
- }
-
- // 3. If NewTarget is undefined, return s.
- BIND(&if_sloaded);
- {
- Node* s_value = var_s.value();
- Label return_s(this), constructstring(this, Label::kDeferred);
- Branch(IsUndefined(new_target), &return_s, &constructstring);
-
- BIND(&return_s);
- { args.PopAndReturn(s_value); }
-
- BIND(&constructstring);
- {
- // We are not using Parameter(Descriptor::kJSTarget) and loading the value
- // from the current frame here in order to reduce register pressure on the
- // fast path.
- TNode<JSFunction> target = LoadTargetFromFrame();
-
- Node* result =
- CallBuiltin(Builtins::kFastNewObject, context, target, new_target);
- StoreObjectField(result, JSPrimitiveWrapper::kValueOffset, s_value);
- args.PopAndReturn(result);
- }
- }
-}
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/builtins/builtins-conversion-gen.cc b/deps/v8/src/builtins/builtins-conversion-gen.cc
index 71a9cbf145..8a0c73b292 100644
--- a/deps/v8/src/builtins/builtins-conversion-gen.cc
+++ b/deps/v8/src/builtins/builtins-conversion-gen.cc
@@ -29,7 +29,7 @@ class ConversionBuiltinsAssembler : public CodeStubAssembler {
void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive(
Node* context, Node* input, ToPrimitiveHint hint) {
// Lookup the @@toPrimitive property on the {input}.
- Node* exotic_to_prim =
+ TNode<Object> exotic_to_prim =
GetProperty(context, input, factory()->to_primitive_symbol());
// Check if {exotic_to_prim} is neither null nor undefined.
@@ -40,7 +40,8 @@ void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive(
// representation of the {hint}.
Callable callable =
CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined);
- Node* hint_string = HeapConstant(factory()->ToPrimitiveHintString(hint));
+ TNode<String> hint_string =
+ HeapConstant(factory()->ToPrimitiveHintString(hint));
Node* result =
CallJS(callable, context, exotic_to_prim, input, hint_string);
@@ -48,7 +49,7 @@ void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive(
Label if_resultisprimitive(this),
if_resultisnotprimitive(this, Label::kDeferred);
GotoIf(TaggedIsSmi(result), &if_resultisprimitive);
- Node* result_instance_type = LoadInstanceType(result);
+ TNode<Uint16T> result_instance_type = LoadInstanceType(result);
Branch(IsPrimitiveInstanceType(result_instance_type), &if_resultisprimitive,
&if_resultisnotprimitive);
@@ -119,7 +120,7 @@ TF_BUILTIN(ToName, CodeStubAssembler) {
Label if_inputisbigint(this), if_inputisname(this), if_inputisnumber(this),
if_inputisoddball(this), if_inputisreceiver(this, Label::kDeferred);
GotoIf(TaggedIsSmi(input), &if_inputisnumber);
- Node* input_instance_type = LoadInstanceType(input);
+ TNode<Uint16T> input_instance_type = LoadInstanceType(input);
STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE);
GotoIf(IsNameInstanceType(input_instance_type), &if_inputisname);
GotoIf(IsJSReceiverInstanceType(input_instance_type), &if_inputisreceiver);
@@ -230,13 +231,13 @@ void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive(
}
for (Handle<String> name : method_names) {
// Lookup the {name} on the {input}.
- Node* method = GetProperty(context, input, name);
+ TNode<Object> method = GetProperty(context, input, name);
// Check if the {method} is callable.
Label if_methodiscallable(this),
if_methodisnotcallable(this, Label::kDeferred);
GotoIf(TaggedIsSmi(method), &if_methodisnotcallable);
- Node* method_map = LoadMap(method);
+ TNode<Map> method_map = LoadMap(CAST(method));
Branch(IsCallableMap(method_map), &if_methodiscallable,
&if_methodisnotcallable);
@@ -250,7 +251,7 @@ void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive(
// Return the {result} if it is a primitive.
GotoIf(TaggedIsSmi(result), &return_result);
- Node* result_instance_type = LoadInstanceType(result);
+ TNode<Uint16T> result_instance_type = LoadInstanceType(result);
GotoIf(IsPrimitiveInstanceType(result_instance_type), &return_result);
}
@@ -340,7 +341,7 @@ TF_BUILTIN(ToLength, CodeStubAssembler) {
BIND(&if_lenisheapnumber);
{
// Load the floating-point value of {len}.
- Node* len_value = LoadHeapNumberValue(len);
+ TNode<Float64T> len_value = LoadHeapNumberValue(len);
// Check if {len} is not greater than zero.
GotoIfNot(Float64GreaterThan(len_value, Float64Constant(0.0)),
@@ -352,8 +353,8 @@ TF_BUILTIN(ToLength, CodeStubAssembler) {
&return_two53minus1);
// Round the {len} towards -Infinity.
- Node* value = Float64Floor(len_value);
- Node* result = ChangeFloat64ToTagged(value);
+ TNode<Float64T> value = Float64Floor(len_value);
+ TNode<Number> result = ChangeFloat64ToTagged(value);
Return(result);
}
@@ -403,11 +404,12 @@ TF_BUILTIN(ToObject, CodeStubAssembler) {
GotoIf(TaggedIsSmi(object), &if_smi);
- Node* map = LoadMap(object);
- Node* instance_type = LoadMapInstanceType(map);
+ TNode<Map> map = LoadMap(object);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
GotoIf(IsJSReceiverInstanceType(instance_type), &if_jsreceiver);
- Node* constructor_function_index = LoadMapConstructorFunctionIndex(map);
+ TNode<IntPtrT> constructor_function_index =
+ LoadMapConstructorFunctionIndex(map);
GotoIf(WordEqual(constructor_function_index,
IntPtrConstant(Map::kNoConstructorFunctionIndex)),
&if_noconstructor);
@@ -420,12 +422,12 @@ TF_BUILTIN(ToObject, CodeStubAssembler) {
Goto(&if_wrapjs_primitive_wrapper);
BIND(&if_wrapjs_primitive_wrapper);
- TNode<Context> native_context = LoadNativeContext(context);
- Node* constructor = LoadContextElement(
- native_context, constructor_function_index_var.value());
- Node* initial_map =
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> constructor = CAST(LoadContextElement(
+ native_context, constructor_function_index_var.value()));
+ TNode<Object> initial_map =
LoadObjectField(constructor, JSFunction::kPrototypeOrInitialMapOffset);
- Node* js_primitive_wrapper = Allocate(JSPrimitiveWrapper::kSize);
+ TNode<HeapObject> js_primitive_wrapper = Allocate(JSPrimitiveWrapper::kSize);
StoreMapNoWriteBarrier(js_primitive_wrapper, initial_map);
StoreObjectFieldRoot(js_primitive_wrapper,
JSPrimitiveWrapper::kPropertiesOrHashOffset,
diff --git a/deps/v8/src/builtins/builtins-date-gen.cc b/deps/v8/src/builtins/builtins-date-gen.cc
index ca84948d48..97600efaa4 100644
--- a/deps/v8/src/builtins/builtins-date-gen.cc
+++ b/deps/v8/src/builtins/builtins-date-gen.cc
@@ -28,7 +28,7 @@ void DateBuiltinsAssembler::Generate_DatePrototype_GetField(Node* context,
Label receiver_not_date(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &receiver_not_date);
- Node* receiver_instance_type = LoadInstanceType(receiver);
+ TNode<Uint16T> receiver_instance_type = LoadInstanceType(receiver);
GotoIfNot(InstanceTypeEqual(receiver_instance_type, JS_DATE_TYPE),
&receiver_not_date);
@@ -38,20 +38,20 @@ void DateBuiltinsAssembler::Generate_DatePrototype_GetField(Node* context,
} else {
if (field_index < JSDate::kFirstUncachedField) {
Label stamp_mismatch(this, Label::kDeferred);
- Node* date_cache_stamp = Load(
- MachineType::AnyTagged(),
+ TNode<Object> date_cache_stamp = Load<Object>(
ExternalConstant(ExternalReference::date_cache_stamp(isolate())));
- Node* cache_stamp = LoadObjectField(receiver, JSDate::kCacheStampOffset);
- GotoIf(WordNotEqual(date_cache_stamp, cache_stamp), &stamp_mismatch);
+ TNode<Object> cache_stamp =
+ LoadObjectField(receiver, JSDate::kCacheStampOffset);
+ GotoIf(TaggedNotEqual(date_cache_stamp, cache_stamp), &stamp_mismatch);
Return(LoadObjectField(receiver,
JSDate::kValueOffset + field_index * kTaggedSize));
BIND(&stamp_mismatch);
}
- Node* field_index_smi = SmiConstant(field_index);
- Node* function =
+ TNode<Smi> field_index_smi = SmiConstant(field_index);
+ TNode<ExternalReference> function =
ExternalConstant(ExternalReference::get_date_field_function());
Node* result = CallCFunction(
function, MachineType::AnyTagged(),
@@ -182,7 +182,7 @@ TF_BUILTIN(DatePrototypeValueOf, DateBuiltinsAssembler) {
TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* hint = Parameter(Descriptor::kHint);
+ TNode<Object> hint = CAST(Parameter(Descriptor::kHint));
// Check if the {receiver} is actually a JSReceiver.
Label receiver_is_invalid(this, Label::kDeferred);
@@ -194,25 +194,25 @@ TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
hint_is_invalid(this, Label::kDeferred);
// Fast cases for internalized strings.
- Node* number_string = LoadRoot(RootIndex::knumber_string);
- GotoIf(WordEqual(hint, number_string), &hint_is_number);
- Node* default_string = LoadRoot(RootIndex::kdefault_string);
- GotoIf(WordEqual(hint, default_string), &hint_is_string);
- Node* string_string = LoadRoot(RootIndex::kstring_string);
- GotoIf(WordEqual(hint, string_string), &hint_is_string);
+ TNode<String> number_string = numberStringConstant();
+ GotoIf(TaggedEqual(hint, number_string), &hint_is_number);
+ TNode<String> default_string = DefaultStringConstant();
+ GotoIf(TaggedEqual(hint, default_string), &hint_is_string);
+ TNode<String> string_string = StringStringConstant();
+ GotoIf(TaggedEqual(hint, string_string), &hint_is_string);
// Slow-case with actual string comparisons.
GotoIf(TaggedIsSmi(hint), &hint_is_invalid);
- GotoIfNot(IsString(hint), &hint_is_invalid);
- GotoIf(WordEqual(
+ GotoIfNot(IsString(CAST(hint)), &hint_is_invalid);
+ GotoIf(TaggedEqual(
CallBuiltin(Builtins::kStringEqual, context, hint, number_string),
TrueConstant()),
&hint_is_number);
- GotoIf(WordEqual(
+ GotoIf(TaggedEqual(
CallBuiltin(Builtins::kStringEqual, context, hint, default_string),
TrueConstant()),
&hint_is_string);
- GotoIf(WordEqual(
+ GotoIf(TaggedEqual(
CallBuiltin(Builtins::kStringEqual, context, hint, string_string),
TrueConstant()),
&hint_is_string);
@@ -223,7 +223,7 @@ TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
{
Callable callable = CodeFactory::OrdinaryToPrimitive(
isolate(), OrdinaryToPrimitiveHint::kNumber);
- Node* result = CallStub(callable, context, receiver);
+ TNode<Object> result = CallStub(callable, context, receiver);
Return(result);
}
@@ -232,7 +232,7 @@ TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
{
Callable callable = CodeFactory::OrdinaryToPrimitive(
isolate(), OrdinaryToPrimitiveHint::kString);
- Node* result = CallStub(callable, context, receiver);
+ TNode<Object> result = CallStub(callable, context, receiver);
Return(result);
}
diff --git a/deps/v8/src/builtins/builtins-date.cc b/deps/v8/src/builtins/builtins-date.cc
index d333873542..c3e7601832 100644
--- a/deps/v8/src/builtins/builtins-date.cc
+++ b/deps/v8/src/builtins/builtins-date.cc
@@ -111,24 +111,23 @@ const char* kShortMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
// ES6 section 20.3.1.16 Date Time String Format
double ParseDateTimeString(Isolate* isolate, Handle<String> str) {
str = String::Flatten(isolate, str);
- // TODO(bmeurer): Change DateParser to not use the FixedArray.
- Handle<FixedArray> tmp =
- isolate->factory()->NewFixedArray(DateParser::OUTPUT_SIZE);
+ double out[DateParser::OUTPUT_SIZE];
DisallowHeapAllocation no_gc;
String::FlatContent str_content = str->GetFlatContent(no_gc);
bool result;
if (str_content.IsOneByte()) {
- result = DateParser::Parse(isolate, str_content.ToOneByteVector(), *tmp);
+ result = DateParser::Parse(isolate, str_content.ToOneByteVector(), out);
} else {
- result = DateParser::Parse(isolate, str_content.ToUC16Vector(), *tmp);
+ result = DateParser::Parse(isolate, str_content.ToUC16Vector(), out);
}
if (!result) return std::numeric_limits<double>::quiet_NaN();
- double const day =
- MakeDay(tmp->get(0).Number(), tmp->get(1).Number(), tmp->get(2).Number());
- double const time = MakeTime(tmp->get(3).Number(), tmp->get(4).Number(),
- tmp->get(5).Number(), tmp->get(6).Number());
+ double const day = MakeDay(out[DateParser::YEAR], out[DateParser::MONTH],
+ out[DateParser::DAY]);
+ double const time =
+ MakeTime(out[DateParser::HOUR], out[DateParser::MINUTE],
+ out[DateParser::SECOND], out[DateParser::MILLISECOND]);
double date = MakeDate(day, time);
- if (tmp->get(7).IsNull(isolate)) {
+ if (std::isnan(out[DateParser::UTC_OFFSET])) {
if (date >= -DateCache::kMaxTimeBeforeUTCInMs &&
date <= DateCache::kMaxTimeBeforeUTCInMs) {
date = isolate->date_cache()->ToUTC(static_cast<int64_t>(date));
@@ -136,7 +135,7 @@ double ParseDateTimeString(Isolate* isolate, Handle<String> str) {
return std::numeric_limits<double>::quiet_NaN();
}
} else {
- date -= tmp->get(7).Number() * 1000.0;
+ date -= out[DateParser::UTC_OFFSET] * 1000.0;
}
return DateCache::TimeClip(date);
}
diff --git a/deps/v8/src/builtins/builtins-definitions.h b/deps/v8/src/builtins/builtins-definitions.h
index 23ab4a88ca..95f5273f14 100644
--- a/deps/v8/src/builtins/builtins-definitions.h
+++ b/deps/v8/src/builtins/builtins-definitions.h
@@ -207,7 +207,9 @@ namespace internal {
TFC(Typeof, Typeof) \
TFC(GetSuperConstructor, Typeof) \
TFC(BigIntToI64, BigIntToI64) \
+ TFC(BigIntToI32Pair, BigIntToI32Pair) \
TFC(I64ToBigInt, I64ToBigInt) \
+ TFC(I32PairToBigInt, I32PairToBigInt) \
\
/* Type conversions continuations */ \
TFC(ToBooleanLazyDeoptContinuation, TypeConversionStackParameter) \
@@ -222,9 +224,9 @@ namespace internal {
TFH(LoadIC_Slow, LoadWithVector) \
TFH(LoadIC_StringLength, LoadWithVector) \
TFH(LoadIC_StringWrapperLength, LoadWithVector) \
- TFH(LoadIC_Uninitialized, LoadWithVector) \
+ TFH(LoadIC_NoFeedback, Load) \
TFH(StoreGlobalIC_Slow, StoreWithVector) \
- TFH(StoreIC_Uninitialized, StoreWithVector) \
+ TFH(StoreIC_NoFeedback, Store) \
TFH(StoreInArrayLiteralIC_Slow, StoreWithVector) \
TFH(KeyedLoadIC_SloppyArguments, LoadWithVector) \
TFH(LoadIndexedInterceptorIC, LoadWithVector) \
@@ -644,8 +646,6 @@ namespace internal {
TFJ(MathCeil, 1, kReceiver, kX) \
/* ES6 #sec-math.floor */ \
TFJ(MathFloor, 1, kReceiver, kX) \
- /* ES6 #sec-math.hypot */ \
- CPP(MathHypot) \
/* ES6 #sec-math.imul */ \
TFJ(MathImul, 2, kReceiver, kX, kY) \
/* ES6 #sec-math.max */ \
@@ -847,32 +847,11 @@ namespace internal {
TFJ(RegExpPrototypeCompile, 2, kReceiver, kPattern, kFlags) \
/* ES #sec-regexp.prototype.exec */ \
TFJ(RegExpPrototypeExec, 1, kReceiver, kString) \
- /* ES #sec-get-regexp.prototype.dotAll */ \
- TFJ(RegExpPrototypeDotAllGetter, 0, kReceiver) \
- /* ES #sec-get-regexp.prototype.flags */ \
- TFJ(RegExpPrototypeFlagsGetter, 0, kReceiver) \
- /* ES #sec-get-regexp.prototype.global */ \
- TFJ(RegExpPrototypeGlobalGetter, 0, kReceiver) \
- /* ES #sec-get-regexp.prototype.ignorecase */ \
- TFJ(RegExpPrototypeIgnoreCaseGetter, 0, kReceiver) \
- /* ES #sec-regexp.prototype-@@match */ \
- TFJ(RegExpPrototypeMatch, 1, kReceiver, kString) \
/* https://tc39.github.io/proposal-string-matchall/ */ \
TFJ(RegExpPrototypeMatchAll, 1, kReceiver, kString) \
- /* ES #sec-get-regexp.prototype.multiline */ \
- TFJ(RegExpPrototypeMultilineGetter, 0, kReceiver) \
/* ES #sec-regexp.prototype-@@search */ \
TFJ(RegExpPrototypeSearch, 1, kReceiver, kString) \
- /* ES #sec-get-regexp.prototype.source */ \
- TFJ(RegExpPrototypeSourceGetter, 0, kReceiver) \
- /* ES #sec-get-regexp.prototype.sticky */ \
- TFJ(RegExpPrototypeStickyGetter, 0, kReceiver) \
- /* ES #sec-regexp.prototype.test */ \
- TFJ(RegExpPrototypeTest, 1, kReceiver, kString) \
- TFS(RegExpPrototypeTestFast, kReceiver, kString) \
CPP(RegExpPrototypeToString) \
- /* ES #sec-get-regexp.prototype.unicode */ \
- TFJ(RegExpPrototypeUnicodeGetter, 0, kReceiver) \
CPP(RegExpRightContextGetter) \
\
/* ES #sec-regexp.prototype-@@split */ \
@@ -880,7 +859,7 @@ namespace internal {
/* RegExp helpers */ \
TFS(RegExpExecAtom, kRegExp, kString, kLastIndex, kMatchInfo) \
TFS(RegExpExecInternal, kRegExp, kString, kLastIndex, kMatchInfo) \
- TFS(RegExpMatchFast, kReceiver, kPattern) \
+ ASM(RegExpInterpreterTrampoline, CCall) \
TFS(RegExpPrototypeExecSlow, kReceiver, kString) \
TFS(RegExpSearchFast, kReceiver, kPattern) \
TFS(RegExpSplit, kRegExp, kString, kLimit) \
@@ -926,8 +905,6 @@ namespace internal {
CPP(AtomicsWake) \
\
/* String */ \
- /* ES #sec-string-constructor */ \
- TFJ(StringConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES #sec-string.fromcodepoint */ \
CPP(StringFromCodePoint) \
/* ES6 #sec-string.fromcharcode */ \
@@ -945,11 +922,6 @@ namespace internal {
TFJ(StringPrototypeMatchAll, 1, kReceiver, kRegexp) \
/* ES6 #sec-string.prototype.localecompare */ \
CPP(StringPrototypeLocaleCompare) \
- /* ES6 #sec-string.prototype.padEnd */ \
- TFJ(StringPrototypePadEnd, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
- /* ES6 #sec-string.prototype.padStart */ \
- TFJ(StringPrototypePadStart, \
- SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-string.prototype.replace */ \
TFJ(StringPrototypeReplace, 2, kReceiver, kSearch, kReplace) \
/* ES6 #sec-string.prototype.search */ \
@@ -1028,7 +1000,6 @@ namespace internal {
TFC(WasmAtomicNotify, WasmAtomicNotify) \
TFC(WasmI32AtomicWait, WasmI32AtomicWait) \
TFC(WasmI64AtomicWait, WasmI64AtomicWait) \
- TFC(WasmCallJavaScript, CallTrampoline) \
TFC(WasmMemoryGrow, WasmMemoryGrow) \
TFC(WasmTableGet, WasmTableGet) \
TFC(WasmTableSet, WasmTableSet) \
@@ -1051,7 +1022,9 @@ namespace internal {
TFS(ThrowWasmTrapElemSegmentDropped) \
TFS(ThrowWasmTrapTableOutOfBounds) \
TFC(WasmI64ToBigInt, I64ToBigInt) \
+ TFC(WasmI32PairToBigInt, I32PairToBigInt) \
TFC(WasmBigIntToI64, BigIntToI64) \
+ TFC(WasmBigIntToI32Pair, BigIntToI32Pair) \
\
/* WeakMap */ \
TFJ(WeakMapConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
@@ -1134,8 +1107,6 @@ namespace internal {
\
/* String helpers */ \
TFS(StringAdd_CheckNone, kLeft, kRight) \
- TFS(StringAdd_ConvertLeft, kLeft, kRight) \
- TFS(StringAdd_ConvertRight, kLeft, kRight) \
TFS(SubString, kString, kFrom, kTo) \
\
/* Miscellaneous */ \
@@ -1344,7 +1315,6 @@ namespace internal {
V(WasmAtomicNotify) \
V(WasmI32AtomicWait) \
V(WasmI64AtomicWait) \
- V(WasmCallJavaScript) \
V(WasmMemoryGrow) \
V(WasmTableGet) \
V(WasmTableSet) \
@@ -1356,7 +1326,9 @@ namespace internal {
V(WasmRethrow) \
V(DoubleToI) \
V(WasmI64ToBigInt) \
- V(WasmBigIntToI64)
+ V(WasmI32PairToBigInt) \
+ V(WasmBigIntToI64) \
+ V(WasmBigIntToI32Pair)
// The exception thrown in the following builtins are caught internally and will
// not be propagated further or re-thrown
diff --git a/deps/v8/src/builtins/builtins-function-gen.cc b/deps/v8/src/builtins/builtins-function-gen.cc
index 411d9a6930..ee1f67d434 100644
--- a/deps/v8/src/builtins/builtins-function-gen.cc
+++ b/deps/v8/src/builtins/builtins-function-gen.cc
@@ -17,19 +17,20 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
// TODO(ishell): use constants from Descriptor once the JSFunction linkage
// arguments are reordered.
- Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);
+ TNode<Int32T> argc =
+ UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
Node* context = Parameter(Descriptor::kContext);
Node* new_target = Parameter(Descriptor::kJSNewTarget);
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
// Check that receiver has instance type of JS_FUNCTION_TYPE
- Node* receiver = args.GetReceiver();
+ TNode<Object> receiver = args.GetReceiver();
GotoIf(TaggedIsSmi(receiver), &slow);
- Node* receiver_map = LoadMap(receiver);
+ TNode<Map> receiver_map = LoadMap(CAST(receiver));
{
- Node* instance_type = LoadMapInstanceType(receiver_map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
GotoIfNot(
Word32Or(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE),
InstanceTypeEqual(instance_type, JS_BOUND_FUNCTION_TYPE)),
@@ -45,35 +46,34 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
// AccessorInfo objects. In that case, their value can be recomputed even if
// the actual value on the object changes.
Comment("Check descriptor array length");
- TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
// Minimum descriptor array length required for fast path.
const int min_nof_descriptors = i::Max(JSFunction::kLengthDescriptorIndex,
- JSFunction::kNameDescriptorIndex);
- TNode<Int32T> nof_descriptors = LoadNumberOfDescriptors(descriptors);
- GotoIf(
- Int32LessThanOrEqual(nof_descriptors, Int32Constant(min_nof_descriptors)),
- &slow);
+ JSFunction::kNameDescriptorIndex) +
+ 1;
+ TNode<Int32T> nof_descriptors = LoadNumberOfOwnDescriptors(receiver_map);
+ GotoIf(Int32LessThan(nof_descriptors, Int32Constant(min_nof_descriptors)),
+ &slow);
// Check whether the length and name properties are still present as
// AccessorInfo objects. In that case, their value can be recomputed even if
// the actual value on the object changes.
Comment("Check name and length properties");
{
+ TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
const int length_index = JSFunction::kLengthDescriptorIndex;
TNode<Name> maybe_length =
LoadKeyByDescriptorEntry(descriptors, length_index);
- GotoIf(WordNotEqual(maybe_length, LoadRoot(RootIndex::klength_string)),
- &slow);
+ GotoIf(TaggedNotEqual(maybe_length, LengthStringConstant()), &slow);
TNode<Object> maybe_length_accessor =
LoadValueByDescriptorEntry(descriptors, length_index);
GotoIf(TaggedIsSmi(maybe_length_accessor), &slow);
- Node* length_value_map = LoadMap(CAST(maybe_length_accessor));
+ TNode<Map> length_value_map = LoadMap(CAST(maybe_length_accessor));
GotoIfNot(IsAccessorInfoMap(length_value_map), &slow);
const int name_index = JSFunction::kNameDescriptorIndex;
TNode<Name> maybe_name = LoadKeyByDescriptorEntry(descriptors, name_index);
- GotoIf(WordNotEqual(maybe_name, LoadRoot(RootIndex::kname_string)), &slow);
+ GotoIf(TaggedNotEqual(maybe_name, NameStringConstant()), &slow);
TNode<Object> maybe_name_accessor =
LoadValueByDescriptorEntry(descriptors, name_index);
@@ -89,7 +89,7 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
{
Label with_constructor(this);
VariableList vars({&bound_function_map}, zone());
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
Label map_done(this, vars);
GotoIf(IsConstructorMap(receiver_map), &with_constructor);
@@ -108,9 +108,10 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
// Verify that __proto__ matches that of a the target bound function.
Comment("Verify that __proto__ matches target bound function");
- Node* prototype = LoadMapPrototype(receiver_map);
- Node* expected_prototype = LoadMapPrototype(bound_function_map.value());
- GotoIf(WordNotEqual(prototype, expected_prototype), &slow);
+ TNode<HeapObject> prototype = LoadMapPrototype(receiver_map);
+ TNode<HeapObject> expected_prototype =
+ LoadMapPrototype(bound_function_map.value());
+ GotoIf(TaggedNotEqual(prototype, expected_prototype), &slow);
// Allocate the arguments array.
Comment("Allocate the arguments array");
@@ -126,12 +127,13 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
VARIABLE(index, MachineType::PointerRepresentation());
index.Bind(IntPtrConstant(0));
VariableList foreach_vars({&index}, zone());
- args.ForEach(foreach_vars,
- [this, elements, &index](Node* arg) {
- StoreFixedArrayElement(elements, index.value(), arg);
- Increment(&index);
- },
- IntPtrConstant(1));
+ args.ForEach(
+ foreach_vars,
+ [this, elements, &index](Node* arg) {
+ StoreFixedArrayElement(elements, index.value(), arg);
+ Increment(&index);
+ },
+ IntPtrConstant(1));
argument_array.Bind(elements);
Goto(&arguments_done);
@@ -162,7 +164,7 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
// Allocate the resulting bound function.
Comment("Allocate the resulting bound function");
{
- Node* bound_function = Allocate(JSBoundFunction::kSize);
+ TNode<HeapObject> bound_function = Allocate(JSBoundFunction::kSize);
StoreMapNoWriteBarrier(bound_function, bound_function_map.value());
StoreObjectFieldNoWriteBarrier(
bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver);
@@ -172,7 +174,7 @@ TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
StoreObjectFieldNoWriteBarrier(bound_function,
JSBoundFunction::kBoundArgumentsOffset,
argument_array.value());
- Node* empty_fixed_array = EmptyFixedArrayConstant();
+ TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
StoreObjectFieldNoWriteBarrier(
bound_function, JSObject::kPropertiesOrHashOffset, empty_fixed_array);
StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset,
diff --git a/deps/v8/src/builtins/builtins-function.cc b/deps/v8/src/builtins/builtins-function.cc
index f9a356f94b..f75014d034 100644
--- a/deps/v8/src/builtins/builtins-function.cc
+++ b/deps/v8/src/builtins/builtins-function.cc
@@ -93,6 +93,17 @@ MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate,
function->shared().set_name_should_print_as_anonymous(true);
}
+ // The spec says that we have to wrap code created via the function
+ // constructor in e.g. 'function anonymous(' as above, including with extra
+ // line breaks. Ths is confusing when reporting stack traces from the eval'd
+ // code as the line number of the error is always reported with 2 extra line
+ // breaks e.g. line 1 is reported as line 3. We fix this up here by setting
+ // line_offset which is read by stack trace code.
+ Handle<Script> script(Script::cast(function->shared().script()), isolate);
+ if (script->line_offset() == 0) {
+ script->set_line_offset(-2);
+ }
+
// If new.target is equal to target then the function created
// is already correctly setup and nothing else should be done
// here. But if new.target is not equal to target then we are
diff --git a/deps/v8/src/builtins/builtins-generator-gen.cc b/deps/v8/src/builtins/builtins-generator-gen.cc
index 7e75bbcee0..d884c417fc 100644
--- a/deps/v8/src/builtins/builtins-generator-gen.cc
+++ b/deps/v8/src/builtins/builtins-generator-gen.cc
@@ -50,8 +50,8 @@ void GeneratorBuiltinsAssembler::GeneratorPrototypeResume(
// Resume the {receiver} using our trampoline.
VARIABLE(var_exception, MachineRepresentation::kTagged, UndefinedConstant());
Label if_exception(this, Label::kDeferred), if_final_return(this);
- Node* result = CallStub(CodeFactory::ResumeGenerator(isolate()), context,
- value, receiver);
+ TNode<Object> result = CallStub(CodeFactory::ResumeGenerator(isolate()),
+ context, value, receiver);
// Make sure we close the generator if there was an exception.
GotoIfException(result, &if_exception, &var_exception);
@@ -115,12 +115,12 @@ void GeneratorBuiltinsAssembler::GeneratorPrototypeResume(
TF_BUILTIN(GeneratorPrototypeNext, GeneratorBuiltinsAssembler) {
const int kValueArg = 0;
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
- Node* receiver = args.GetReceiver();
- Node* value = args.GetOptionalArgumentValue(kValueArg);
+ TNode<Object> receiver = args.GetReceiver();
+ TNode<Object> value = args.GetOptionalArgumentValue(kValueArg);
Node* context = Parameter(Descriptor::kContext);
GeneratorPrototypeResume(&args, receiver, value, context,
@@ -132,12 +132,12 @@ TF_BUILTIN(GeneratorPrototypeNext, GeneratorBuiltinsAssembler) {
TF_BUILTIN(GeneratorPrototypeReturn, GeneratorBuiltinsAssembler) {
const int kValueArg = 0;
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
- Node* receiver = args.GetReceiver();
- Node* value = args.GetOptionalArgumentValue(kValueArg);
+ TNode<Object> receiver = args.GetReceiver();
+ TNode<Object> value = args.GetOptionalArgumentValue(kValueArg);
Node* context = Parameter(Descriptor::kContext);
GeneratorPrototypeResume(&args, receiver, value, context,
@@ -149,12 +149,12 @@ TF_BUILTIN(GeneratorPrototypeReturn, GeneratorBuiltinsAssembler) {
TF_BUILTIN(GeneratorPrototypeThrow, GeneratorBuiltinsAssembler) {
const int kExceptionArg = 0;
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
- Node* receiver = args.GetReceiver();
- Node* exception = args.GetOptionalArgumentValue(kExceptionArg);
+ TNode<Object> receiver = args.GetReceiver();
+ TNode<Object> exception = args.GetOptionalArgumentValue(kExceptionArg);
Node* context = Parameter(Descriptor::kContext);
GeneratorPrototypeResume(&args, receiver, exception, context,
diff --git a/deps/v8/src/builtins/builtins-global-gen.cc b/deps/v8/src/builtins/builtins-global-gen.cc
index fa21f81650..ca29ab3cd2 100644
--- a/deps/v8/src/builtins/builtins-global-gen.cc
+++ b/deps/v8/src/builtins/builtins-global-gen.cc
@@ -35,7 +35,7 @@ TF_BUILTIN(GlobalIsFinite, CodeStubAssembler) {
BIND(&if_numisheapnumber);
{
// Check if {num} contains a finite, non-NaN value.
- Node* num_value = LoadHeapNumberValue(num);
+ TNode<Float64T> num_value = LoadHeapNumberValue(num);
BranchIfFloat64IsNaN(Float64Sub(num_value, num_value), &return_false,
&return_true);
}
@@ -81,7 +81,7 @@ TF_BUILTIN(GlobalIsNaN, CodeStubAssembler) {
BIND(&if_numisheapnumber);
{
// Check if {num} contains a NaN.
- Node* num_value = LoadHeapNumberValue(num);
+ TNode<Float64T> num_value = LoadHeapNumberValue(num);
BranchIfFloat64IsNaN(num_value, &return_true, &return_false);
}
diff --git a/deps/v8/src/builtins/builtins-handler-gen.cc b/deps/v8/src/builtins/builtins-handler-gen.cc
index 973356f569..eae8690f1f 100644
--- a/deps/v8/src/builtins/builtins-handler-gen.cc
+++ b/deps/v8/src/builtins/builtins-handler-gen.cc
@@ -66,9 +66,9 @@ void Builtins::Generate_KeyedStoreIC_Megamorphic(
KeyedStoreGenericGenerator::Generate(state);
}
-void Builtins::Generate_StoreIC_Uninitialized(
+void Builtins::Generate_StoreIC_NoFeedback(
compiler::CodeAssemblerState* state) {
- StoreICUninitializedGenerator::Generate(state);
+ StoreICNoFeedbackGenerator::Generate(state);
}
// TODO(mythria): Check if we can remove feedback vector and slot parameters in
@@ -180,7 +180,7 @@ void HandlerBuiltinsAssembler::DispatchForElementsKindTransition(
STATIC_ASSERT(arraysize(combined_elements_kinds) ==
arraysize(elements_kind_labels));
- TNode<Word32T> combined_elements_kind =
+ TNode<Int32T> combined_elements_kind =
Word32Or(Word32Shl(from_kind, Int32Constant(kBitsPerByte)), to_kind);
Switch(combined_elements_kind, &if_unknown_type, combined_elements_kinds,
@@ -259,25 +259,27 @@ TF_BUILTIN(ElementsTransitionAndStore_NoTransitionHandleCOW,
// All elements kinds handled by EmitElementStore. Specifically, this includes
// fast elements and fixed typed array elements.
-#define ELEMENTS_KINDS(V) \
- V(PACKED_SMI_ELEMENTS) \
- V(HOLEY_SMI_ELEMENTS) \
- V(PACKED_ELEMENTS) \
- V(PACKED_SEALED_ELEMENTS) \
- V(HOLEY_ELEMENTS) \
- V(HOLEY_SEALED_ELEMENTS) \
- V(PACKED_DOUBLE_ELEMENTS) \
- V(HOLEY_DOUBLE_ELEMENTS) \
- V(UINT8_ELEMENTS) \
- V(INT8_ELEMENTS) \
- V(UINT16_ELEMENTS) \
- V(INT16_ELEMENTS) \
- V(UINT32_ELEMENTS) \
- V(INT32_ELEMENTS) \
- V(FLOAT32_ELEMENTS) \
- V(FLOAT64_ELEMENTS) \
- V(UINT8_CLAMPED_ELEMENTS) \
- V(BIGUINT64_ELEMENTS) \
+#define ELEMENTS_KINDS(V) \
+ V(PACKED_SMI_ELEMENTS) \
+ V(HOLEY_SMI_ELEMENTS) \
+ V(PACKED_ELEMENTS) \
+ V(PACKED_NONEXTENSIBLE_ELEMENTS) \
+ V(PACKED_SEALED_ELEMENTS) \
+ V(HOLEY_ELEMENTS) \
+ V(HOLEY_NONEXTENSIBLE_ELEMENTS) \
+ V(HOLEY_SEALED_ELEMENTS) \
+ V(PACKED_DOUBLE_ELEMENTS) \
+ V(HOLEY_DOUBLE_ELEMENTS) \
+ V(UINT8_ELEMENTS) \
+ V(INT8_ELEMENTS) \
+ V(UINT16_ELEMENTS) \
+ V(INT16_ELEMENTS) \
+ V(UINT32_ELEMENTS) \
+ V(INT32_ELEMENTS) \
+ V(FLOAT32_ELEMENTS) \
+ V(FLOAT64_ELEMENTS) \
+ V(UINT8_CLAMPED_ELEMENTS) \
+ V(BIGUINT64_ELEMENTS) \
V(BIGINT64_ELEMENTS)
void HandlerBuiltinsAssembler::DispatchByElementsKind(
@@ -311,7 +313,7 @@ void HandlerBuiltinsAssembler::DispatchByElementsKind(
BIND(&if_##KIND); \
{ \
if (!FLAG_enable_sealed_frozen_elements_kind && \
- IsFrozenOrSealedElementsKindUnchecked(KIND)) { \
+ IsAnyNonextensibleElementsKindUnchecked(KIND)) { \
/* Disable support for frozen or sealed elements kinds. */ \
Unreachable(); \
} else if (!handle_typed_elements_kind && \
@@ -403,7 +405,7 @@ TF_BUILTIN(LoadIC_FunctionPrototype, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Label miss(this, Label::kDeferred);
- Return(LoadJSFunctionPrototype(receiver, &miss));
+ Return(LoadJSFunctionPrototype(CAST(receiver), &miss));
BIND(&miss);
TailCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name, slot, vector);
diff --git a/deps/v8/src/builtins/builtins-ic-gen.cc b/deps/v8/src/builtins/builtins-ic-gen.cc
index ce944784ea..605b2a6b1a 100644
--- a/deps/v8/src/builtins/builtins-ic-gen.cc
+++ b/deps/v8/src/builtins/builtins-ic-gen.cc
@@ -23,7 +23,7 @@ namespace internal {
IC_BUILTIN(LoadIC)
IC_BUILTIN(LoadIC_Megamorphic)
IC_BUILTIN(LoadIC_Noninlined)
-IC_BUILTIN(LoadIC_Uninitialized)
+IC_BUILTIN(LoadIC_NoFeedback)
IC_BUILTIN(LoadICTrampoline)
IC_BUILTIN(LoadICTrampoline_Megamorphic)
IC_BUILTIN(KeyedLoadIC)
diff --git a/deps/v8/src/builtins/builtins-internal-gen.cc b/deps/v8/src/builtins/builtins-internal-gen.cc
index 8d22767b58..445c8c9517 100644
--- a/deps/v8/src/builtins/builtins-internal-gen.cc
+++ b/deps/v8/src/builtins/builtins-internal-gen.cc
@@ -35,7 +35,7 @@ TF_BUILTIN(CopyFastSmiOrObjectElements, CodeStubAssembler) {
Node* object = Parameter(Descriptor::kObject);
// Load the {object}s elements.
- Node* source = LoadObjectField(object, JSObject::kElementsOffset);
+ TNode<Object> source = LoadObjectField(object, JSObject::kElementsOffset);
Node* target = CloneFixedArray(source, ExtractFixedArrayFlag::kFixedArrays);
StoreObjectField(object, JSObject::kElementsOffset, target);
Return(target);
@@ -104,7 +104,7 @@ TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) {
// the mapped elements (i.e. the first {mapped_count}) with the hole, but
// make sure not to overshoot the {length} if some arguments are missing.
TNode<IntPtrT> number_of_holes = IntPtrMin(mapped_count, length);
- Node* the_hole = TheHoleConstant();
+ TNode<Oddball> the_hole = TheHoleConstant();
// Fill the first elements up to {number_of_holes} with the hole.
TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
@@ -116,7 +116,7 @@ TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) {
TNode<IntPtrT> index = var_index.value();
// Check if we are done.
- GotoIf(WordEqual(index, number_of_holes), &done_loop1);
+ GotoIf(IntPtrEqual(index, number_of_holes), &done_loop1);
// Store the hole into the {result}.
StoreFixedArrayElement(result, index, the_hole, SKIP_WRITE_BARRIER);
@@ -139,7 +139,7 @@ TF_BUILTIN(NewArgumentsElements, CodeStubAssembler) {
TNode<IntPtrT> index = var_index.value();
// Check if we are done.
- GotoIf(WordEqual(index, length), &done_loop2);
+ GotoIf(IntPtrEqual(index, length), &done_loop2);
// Load the parameter at the given {index}.
TNode<Object> value = BitcastWordToTagged(
@@ -213,7 +213,7 @@ class RecordWriteCodeStubAssembler : public CodeStubAssembler {
: CodeStubAssembler(state) {}
Node* IsMarking() {
- Node* is_marking_addr = ExternalConstant(
+ TNode<ExternalReference> is_marking_addr = ExternalConstant(
ExternalReference::heap_is_marking_flag_address(this->isolate()));
return Load(MachineType::Uint8(), is_marking_addr);
}
@@ -266,12 +266,12 @@ class RecordWriteCodeStubAssembler : public CodeStubAssembler {
}
}
- Node* ShouldSkipFPRegs(Node* mode) {
- return WordEqual(mode, SmiConstant(kDontSaveFPRegs));
+ Node* ShouldSkipFPRegs(SloppyTNode<Object> mode) {
+ return TaggedEqual(mode, SmiConstant(kDontSaveFPRegs));
}
- Node* ShouldEmitRememberSet(Node* remembered_set) {
- return WordEqual(remembered_set, SmiConstant(EMIT_REMEMBERED_SET));
+ Node* ShouldEmitRememberSet(SloppyTNode<Object> remembered_set) {
+ return TaggedEqual(remembered_set, SmiConstant(EMIT_REMEMBERED_SET));
}
void CallCFunction1WithCallerSavedRegistersMode(MachineType return_type,
@@ -323,26 +323,27 @@ class RecordWriteCodeStubAssembler : public CodeStubAssembler {
void InsertToStoreBufferAndGoto(Node* isolate, Node* slot, Node* mode,
Label* next) {
- Node* store_buffer_top_addr =
+ TNode<ExternalReference> store_buffer_top_addr =
ExternalConstant(ExternalReference::store_buffer_top(this->isolate()));
Node* store_buffer_top =
Load(MachineType::Pointer(), store_buffer_top_addr);
StoreNoWriteBarrier(MachineType::PointerRepresentation(), store_buffer_top,
slot);
- Node* new_store_buffer_top =
+ TNode<WordT> new_store_buffer_top =
IntPtrAdd(store_buffer_top, IntPtrConstant(kSystemPointerSize));
StoreNoWriteBarrier(MachineType::PointerRepresentation(),
store_buffer_top_addr, new_store_buffer_top);
- Node* test = WordAnd(new_store_buffer_top,
- IntPtrConstant(Heap::store_buffer_mask_constant()));
+ TNode<WordT> test =
+ WordAnd(new_store_buffer_top,
+ IntPtrConstant(Heap::store_buffer_mask_constant()));
Label overflow(this);
- Branch(WordEqual(test, IntPtrConstant(0)), &overflow, next);
+ Branch(IntPtrEqual(test, IntPtrConstant(0)), &overflow, next);
BIND(&overflow);
{
- Node* function =
+ TNode<ExternalReference> function =
ExternalConstant(ExternalReference::store_buffer_overflow_function());
CallCFunction1WithCallerSavedRegistersMode(MachineType::Int32(),
MachineType::Pointer(),
@@ -395,7 +396,7 @@ TF_BUILTIN(RecordWrite, RecordWriteCodeStubAssembler) {
BIND(&store_buffer_exit);
{
- Node* isolate_constant =
+ TNode<ExternalReference> isolate_constant =
ExternalConstant(ExternalReference::isolate_address(isolate()));
Node* fp_mode = Parameter(Descriptor::kFPMode);
InsertToStoreBufferAndGoto(isolate_constant, slot, fp_mode, &exit);
@@ -403,7 +404,7 @@ TF_BUILTIN(RecordWrite, RecordWriteCodeStubAssembler) {
BIND(&store_buffer_incremental_wb);
{
- Node* isolate_constant =
+ TNode<ExternalReference> isolate_constant =
ExternalConstant(ExternalReference::isolate_address(isolate()));
Node* fp_mode = Parameter(Descriptor::kFPMode);
InsertToStoreBufferAndGoto(isolate_constant, slot, fp_mode,
@@ -435,9 +436,9 @@ TF_BUILTIN(RecordWrite, RecordWriteCodeStubAssembler) {
BIND(&call_incremental_wb);
{
- Node* function = ExternalConstant(
+ TNode<ExternalReference> function = ExternalConstant(
ExternalReference::incremental_marking_record_write_function());
- Node* isolate_constant =
+ TNode<ExternalReference> isolate_constant =
ExternalConstant(ExternalReference::isolate_address(isolate()));
Node* fp_mode = Parameter(Descriptor::kFPMode);
TNode<IntPtrT> object =
@@ -457,12 +458,12 @@ TF_BUILTIN(RecordWrite, RecordWriteCodeStubAssembler) {
TF_BUILTIN(EphemeronKeyBarrier, RecordWriteCodeStubAssembler) {
Label exit(this);
- Node* function = ExternalConstant(
+ TNode<ExternalReference> function = ExternalConstant(
ExternalReference::ephemeron_key_write_barrier_function());
- Node* isolate_constant =
+ TNode<ExternalReference> isolate_constant =
ExternalConstant(ExternalReference::isolate_address(isolate()));
Node* address = Parameter(Descriptor::kSlotAddress);
- Node* object = BitcastTaggedToWord(Parameter(Descriptor::kObject));
+ TNode<IntPtrT> object = BitcastTaggedToWord(Parameter(Descriptor::kObject));
Node* fp_mode = Parameter(Descriptor::kFPMode);
CallCFunction3WithCallerSavedRegistersMode(
MachineType::Int32(), MachineType::Pointer(), MachineType::Pointer(),
@@ -495,7 +496,7 @@ class DeletePropertyBaseAssembler : public AccessorAssembler {
GotoIf(IsSetWord32(details, PropertyDetails::kAttributesDontDeleteMask),
dont_delete);
// Overwrite the entry itself (see NameDictionary::SetEntry).
- TNode<HeapObject> filler = TheHoleConstant();
+ TNode<Oddball> filler = TheHoleConstant();
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kTheHoleValue));
StoreFixedArrayElement(properties, key_index, filler, SKIP_WRITE_BARRIER);
StoreValueByKeyIndex<NameDictionary>(properties, key_index, filler,
@@ -534,11 +535,12 @@ TF_BUILTIN(DeleteProperty, DeletePropertyBaseAssembler) {
VARIABLE(var_index, MachineType::PointerRepresentation());
VARIABLE(var_unique, MachineRepresentation::kTagged, key);
Label if_index(this), if_unique_name(this), if_notunique(this),
- if_notfound(this), slow(this);
+ if_notfound(this), slow(this), if_proxy(this);
GotoIf(TaggedIsSmi(receiver), &slow);
TNode<Map> receiver_map = LoadMap(CAST(receiver));
- TNode<Int32T> instance_type = LoadMapInstanceType(receiver_map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
+ GotoIf(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), &if_proxy);
GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &slow);
TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique, &slow,
&if_notunique);
@@ -592,6 +594,14 @@ TF_BUILTIN(DeleteProperty, DeletePropertyBaseAssembler) {
BIND(&if_notfound);
Return(TrueConstant());
+ BIND(&if_proxy);
+ {
+ TNode<Name> name = CAST(CallBuiltin(Builtins::kToName, context, key));
+ GotoIf(IsPrivateSymbol(name), &slow);
+ TailCallBuiltin(Builtins::kProxyDeleteProperty, context, receiver, name,
+ language_mode);
+ }
+
BIND(&slow);
{
TailCallRuntime(Runtime::kDeleteProperty, context, receiver, key,
@@ -622,7 +632,7 @@ class SetOrCopyDataPropertiesAssembler : public CodeStubAssembler {
// Otherwise check if {source} is a proper JSObject, and if not, defer
// to testing for non-empty strings below.
TNode<Map> source_map = LoadMap(CAST(source));
- TNode<Int32T> source_instance_type = LoadMapInstanceType(source_map);
+ TNode<Uint16T> source_instance_type = LoadMapInstanceType(source_map);
GotoIfNot(IsJSObjectInstanceType(source_instance_type),
&if_sourcenotjsobject);
@@ -670,7 +680,8 @@ class SetOrCopyDataPropertiesAssembler : public CodeStubAssembler {
// handled explicitly by Object.assign() and CopyDataProperties.
GotoIfNot(IsStringInstanceType(source_instance_type), &if_done);
TNode<IntPtrT> source_length = LoadStringLengthAsWord(CAST(source));
- Branch(WordEqual(source_length, IntPtrConstant(0)), &if_done, if_runtime);
+ Branch(IntPtrEqual(source_length, IntPtrConstant(0)), &if_done,
+ if_runtime);
}
BIND(&if_done);
@@ -686,7 +697,7 @@ TF_BUILTIN(CopyDataProperties, SetOrCopyDataPropertiesAssembler) {
TNode<Object> source = CAST(Parameter(Descriptor::kSource));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- CSA_ASSERT(this, WordNotEqual(target, source));
+ CSA_ASSERT(this, TaggedNotEqual(target, source));
Label if_runtime(this, Label::kDeferred);
Return(SetOrCopyDataProperties(context, target, source, &if_runtime, false));
@@ -980,7 +991,7 @@ TF_BUILTIN(GetProperty, CodeStubAssembler) {
BIND(&if_proxy);
{
// Convert the {key} to a Name first.
- Node* name = CallBuiltin(Builtins::kToName, context, key);
+ TNode<Object> name = CallBuiltin(Builtins::kToName, context, key);
// The {object} is a JSProxy instance, look up the {name} on it, passing
// {object} both as receiver and holder. If {name} is absent we can safely
@@ -996,7 +1007,7 @@ TF_BUILTIN(GetPropertyWithReceiver, CodeStubAssembler) {
Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* on_non_existent = Parameter(Descriptor::kOnNonExistent);
+ TNode<Object> on_non_existent = CAST(Parameter(Descriptor::kOnNonExistent));
Label if_notfound(this), if_proxy(this, Label::kDeferred),
if_slow(this, Label::kDeferred);
@@ -1028,11 +1039,11 @@ TF_BUILTIN(GetPropertyWithReceiver, CodeStubAssembler) {
BIND(&if_notfound);
Label throw_reference_error(this);
- GotoIf(WordEqual(on_non_existent,
- SmiConstant(OnNonExistent::kThrowReferenceError)),
+ GotoIf(TaggedEqual(on_non_existent,
+ SmiConstant(OnNonExistent::kThrowReferenceError)),
&throw_reference_error);
- CSA_ASSERT(this, WordEqual(on_non_existent,
- SmiConstant(OnNonExistent::kReturnUndefined)));
+ CSA_ASSERT(this, TaggedEqual(on_non_existent,
+ SmiConstant(OnNonExistent::kReturnUndefined)));
Return(UndefinedConstant());
BIND(&throw_reference_error);
@@ -1045,7 +1056,7 @@ TF_BUILTIN(GetPropertyWithReceiver, CodeStubAssembler) {
BIND(&if_proxy);
{
// Convert the {key} to a Name first.
- Node* name = CallBuiltin(Builtins::kToName, context, key);
+ TNode<Name> name = CAST(CallBuiltin(Builtins::kToName, context, key));
// Proxy cannot handle private symbol so bailout.
GotoIf(IsPrivateSymbol(name), &if_slow);
diff --git a/deps/v8/src/builtins/builtins-intl-gen.cc b/deps/v8/src/builtins/builtins-intl-gen.cc
index 991790b490..1a9a3b7fd9 100644
--- a/deps/v8/src/builtins/builtins-intl-gen.cc
+++ b/deps/v8/src/builtins/builtins-intl-gen.cc
@@ -33,10 +33,7 @@ class IntlBuiltinsAssembler : public CodeStubAssembler {
};
TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
- Node* const string = Parameter(Descriptor::kString);
- Node* const context = Parameter(Descriptor::kContext);
-
- CSA_ASSERT(this, IsString(string));
+ TNode<String> const string = CAST(Parameter(Descriptor::kString));
Label call_c(this), return_string(this), runtime(this, Label::kDeferred);
@@ -50,14 +47,14 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
state(), string, ToDirectStringAssembler::kDontUnpackSlicedStrings);
to_direct.TryToDirect(&runtime);
- Node* const instance_type = to_direct.instance_type();
+ TNode<Int32T> const instance_type = to_direct.instance_type();
CSA_ASSERT(this,
Word32BinaryNot(IsIndirectStringInstanceType(instance_type)));
GotoIfNot(IsOneByteStringInstanceType(instance_type), &runtime);
// For short strings, do the conversion in CSA through the lookup table.
- Node* const dst = AllocateSeqOneByteString(context, length);
+ TNode<String> const dst = AllocateSeqOneByteString(length);
const int kMaxShortStringLength = 24; // Determined empirically.
GotoIf(Uint32GreaterThan(length, Uint32Constant(kMaxShortStringLength)),
@@ -68,31 +65,31 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
VARIABLE(var_cursor, MachineType::PointerRepresentation(),
IntPtrConstant(0));
- Node* const start_address = to_direct.PointerToData(&call_c);
+ TNode<RawPtrT> const start_address = to_direct.PointerToData(&call_c);
TNode<IntPtrT> const end_address =
Signed(IntPtrAdd(start_address, ChangeUint32ToWord(length)));
- Node* const to_lower_table_addr =
+ TNode<ExternalReference> const to_lower_table_addr =
ExternalConstant(ExternalReference::intl_to_latin1_lower_table());
VARIABLE(var_did_change, MachineRepresentation::kWord32, Int32Constant(0));
VariableList push_vars({&var_cursor, &var_did_change}, zone());
- BuildFastLoop(push_vars, start_address, end_address,
- [=, &var_cursor, &var_did_change](Node* current) {
- Node* c = Load(MachineType::Uint8(), current);
- Node* lower =
- Load(MachineType::Uint8(), to_lower_table_addr,
- ChangeInt32ToIntPtr(c));
- StoreNoWriteBarrier(MachineRepresentation::kWord8, dst_ptr,
- var_cursor.value(), lower);
-
- var_did_change.Bind(Word32Or(Word32NotEqual(c, lower),
- var_did_change.value()));
-
- Increment(&var_cursor);
- },
- kCharSize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
+ BuildFastLoop(
+ push_vars, start_address, end_address,
+ [=, &var_cursor, &var_did_change](Node* current) {
+ TNode<Uint8T> c = Load<Uint8T>(current);
+ TNode<Uint8T> lower =
+ Load<Uint8T>(to_lower_table_addr, ChangeInt32ToIntPtr(c));
+ StoreNoWriteBarrier(MachineRepresentation::kWord8, dst_ptr,
+ var_cursor.value(), lower);
+
+ var_did_change.Bind(
+ Word32Or(Word32NotEqual(c, lower), var_did_change.value()));
+
+ Increment(&var_cursor);
+ },
+ kCharSize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
// Return the original string if it remained unchanged in order to preserve
// e.g. internalization and private symbols (such as the preserved object
@@ -106,9 +103,9 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
// String ConvertOneByteToLower(String src, String dst);
BIND(&call_c);
{
- Node* const src = to_direct.string();
+ TNode<String> const src = to_direct.string();
- Node* const function_addr =
+ TNode<ExternalReference> const function_addr =
ExternalConstant(ExternalReference::intl_convert_one_byte_to_lower());
MachineType type_tagged = MachineType::AnyTagged();
@@ -125,8 +122,8 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
BIND(&runtime);
{
- Node* const result = CallRuntime(Runtime::kStringToLowerCaseIntl,
- NoContextConstant(), string);
+ TNode<Object> const result = CallRuntime(Runtime::kStringToLowerCaseIntl,
+ NoContextConstant(), string);
Return(result);
}
}
diff --git a/deps/v8/src/builtins/builtins-iterator-gen.cc b/deps/v8/src/builtins/builtins-iterator-gen.cc
index b3d8e27dbc..7bd5acfdcd 100644
--- a/deps/v8/src/builtins/builtins-iterator-gen.cc
+++ b/deps/v8/src/builtins/builtins-iterator-gen.cc
@@ -27,7 +27,7 @@ IteratorRecord IteratorBuiltinsAssembler::GetIterator(Node* context,
Node* object,
Label* if_exception,
Variable* exception) {
- Node* method = GetIteratorMethod(context, object);
+ TNode<Object> method = GetIteratorMethod(context, object);
return GetIterator(context, object, method, if_exception, exception);
}
@@ -44,7 +44,8 @@ IteratorRecord IteratorBuiltinsAssembler::GetIterator(Node* context,
BIND(&if_not_callable);
{
- Node* ret = CallRuntime(Runtime::kThrowIteratorError, context, object);
+ TNode<Object> ret =
+ CallRuntime(Runtime::kThrowIteratorError, context, object);
GotoIfException(ret, if_exception, exception);
Unreachable();
}
@@ -61,13 +62,15 @@ IteratorRecord IteratorBuiltinsAssembler::GetIterator(Node* context,
BIND(&if_notobject);
{
- Node* ret = CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context);
+ TNode<Object> ret =
+ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context);
GotoIfException(ret, if_exception, exception);
Unreachable();
}
BIND(&get_next);
- Node* const next = GetProperty(context, iterator, factory()->next_string());
+ TNode<Object> const next =
+ GetProperty(context, iterator, factory()->next_string());
GotoIfException(next, if_exception, exception);
return IteratorRecord{TNode<JSReceiver>::UncheckedCast(iterator),
@@ -76,8 +79,9 @@ IteratorRecord IteratorBuiltinsAssembler::GetIterator(Node* context,
}
TNode<JSReceiver> IteratorBuiltinsAssembler::IteratorStep(
- Node* context, const IteratorRecord& iterator, Label* if_done,
- Node* fast_iterator_result_map, Label* if_exception, Variable* exception) {
+ TNode<Context> context, const IteratorRecord& iterator, Label* if_done,
+ base::Optional<TNode<Map>> fast_iterator_result_map, Label* if_exception,
+ Variable* exception) {
DCHECK_NOT_NULL(if_done);
// 1. a. Let result be ? Invoke(iterator, "next", « »).
Callable callable = CodeFactory::Call(isolate());
@@ -87,18 +91,18 @@ TNode<JSReceiver> IteratorBuiltinsAssembler::IteratorStep(
// 3. If Type(result) is not Object, throw a TypeError exception.
Label if_notobject(this, Label::kDeferred), return_result(this);
GotoIf(TaggedIsSmi(result), &if_notobject);
- Node* result_map = LoadMap(result);
+ TNode<Map> result_map = LoadMap(result);
- if (fast_iterator_result_map != nullptr) {
+ if (fast_iterator_result_map) {
// Fast iterator result case:
Label if_generic(this);
// 4. Return result.
- GotoIfNot(WordEqual(result_map, fast_iterator_result_map), &if_generic);
+ GotoIfNot(TaggedEqual(result_map, *fast_iterator_result_map), &if_generic);
// IteratorComplete
// 2. Return ToBoolean(? Get(iterResult, "done")).
- Node* done = LoadObjectField(result, JSIteratorResult::kDoneOffset);
+ TNode<Object> done = LoadObjectField(result, JSIteratorResult::kDoneOffset);
BranchIfToBooleanIsTrue(done, if_done, &return_result);
BIND(&if_generic);
@@ -111,14 +115,14 @@ TNode<JSReceiver> IteratorBuiltinsAssembler::IteratorStep(
// IteratorComplete
// 2. Return ToBoolean(? Get(iterResult, "done")).
- Node* done = GetProperty(context, result, factory()->done_string());
+ TNode<Object> done = GetProperty(context, result, factory()->done_string());
GotoIfException(done, if_exception, exception);
BranchIfToBooleanIsTrue(done, if_done, &return_result);
}
BIND(&if_notobject);
{
- Node* ret =
+ TNode<Object> ret =
CallRuntime(Runtime::kThrowIteratorResultNotAnObject, context, result);
GotoIfException(ret, if_exception, exception);
Unreachable();
@@ -137,8 +141,8 @@ TNode<Object> IteratorBuiltinsAssembler::IteratorValue(
if (fast_iterator_result_map) {
// Fast iterator result case:
Label if_generic(this);
- Node* map = LoadMap(result);
- GotoIfNot(WordEqual(map, *fast_iterator_result_map), &if_generic);
+ TNode<Map> map = LoadMap(result);
+ GotoIfNot(TaggedEqual(map, *fast_iterator_result_map), &if_generic);
var_value = LoadObjectField(result, JSIteratorResult::kValueOffset);
Goto(&exit);
@@ -169,7 +173,7 @@ void IteratorBuiltinsAssembler::IteratorCloseOnException(
CSA_ASSERT(this, IsJSReceiver(iterator.object));
// Let return be ? GetMethod(iterator, "return").
- Node* method =
+ TNode<Object> method =
GetProperty(context, iterator.object, factory()->return_string());
GotoIfException(method, if_exception, exception);
diff --git a/deps/v8/src/builtins/builtins-iterator-gen.h b/deps/v8/src/builtins/builtins-iterator-gen.h
index db86c65385..2a0a510f73 100644
--- a/deps/v8/src/builtins/builtins-iterator-gen.h
+++ b/deps/v8/src/builtins/builtins-iterator-gen.h
@@ -36,15 +36,14 @@ class IteratorBuiltinsAssembler : public CodeStubAssembler {
// result.
// `fast_iterator_result_map` refers to the map for the JSIteratorResult
// object, loaded from the native context.
- TNode<JSReceiver> IteratorStep(Node* context, const IteratorRecord& iterator,
- Label* if_done,
- Node* fast_iterator_result_map = nullptr,
- Label* if_exception = nullptr,
- Variable* exception = nullptr);
-
- TNode<JSReceiver> IteratorStep(Node* context, const IteratorRecord& iterator,
- Node* fast_iterator_result_map,
- Label* if_done) {
+ TNode<JSReceiver> IteratorStep(
+ TNode<Context> context, const IteratorRecord& iterator, Label* if_done,
+ base::Optional<TNode<Map>> fast_iterator_result_map = base::nullopt,
+ Label* if_exception = nullptr, Variable* exception = nullptr);
+
+ TNode<JSReceiver> IteratorStep(
+ TNode<Context> context, const IteratorRecord& iterator,
+ base::Optional<TNode<Map>> fast_iterator_result_map, Label* if_done) {
return IteratorStep(context, iterator, if_done, fast_iterator_result_map);
}
diff --git a/deps/v8/src/builtins/builtins-lazy-gen.cc b/deps/v8/src/builtins/builtins-lazy-gen.cc
index c73cbee1bc..95d5229974 100644
--- a/deps/v8/src/builtins/builtins-lazy-gen.cc
+++ b/deps/v8/src/builtins/builtins-lazy-gen.cc
@@ -146,8 +146,8 @@ void LazyBuiltinsAssembler::CompileLazy(TNode<JSFunction> function) {
BIND(&use_sfi_code);
// If not, install the SFI's code entry and jump to that.
- CSA_ASSERT(this, WordNotEqual(sfi_code, HeapConstant(BUILTIN_CODE(
- isolate(), CompileLazy))));
+ CSA_ASSERT(this, TaggedNotEqual(sfi_code, HeapConstant(BUILTIN_CODE(
+ isolate(), CompileLazy))));
StoreObjectField(function, JSFunction::kCodeOffset, sfi_code);
GenerateTailCallToJSCode(sfi_code, function);
diff --git a/deps/v8/src/builtins/builtins-math-gen.cc b/deps/v8/src/builtins/builtins-math-gen.cc
index 46195e74ed..42d0162f38 100644
--- a/deps/v8/src/builtins/builtins-math-gen.cc
+++ b/deps/v8/src/builtins/builtins-math-gen.cc
@@ -8,6 +8,7 @@
#include "src/builtins/builtins.h"
#include "src/codegen/code-factory.h"
#include "src/codegen/code-stub-assembler.h"
+#include "src/objects/fixed-array.h"
namespace v8 {
namespace internal {
@@ -39,7 +40,7 @@ TF_BUILTIN(MathAbs, CodeStubAssembler) {
// check if support abs function
if (IsIntPtrAbsWithOverflowSupported()) {
- Node* pair = IntPtrAbsWithOverflow(x);
+ TNode<PairT<IntPtrT, BoolT>> pair = IntPtrAbsWithOverflow(x);
Node* overflow = Projection(1, pair);
GotoIf(overflow, &if_overflow);
@@ -79,9 +80,9 @@ TF_BUILTIN(MathAbs, CodeStubAssembler) {
BIND(&if_xisheapnumber);
{
- Node* x_value = LoadHeapNumberValue(x);
- Node* value = Float64Abs(x_value);
- Node* result = AllocateHeapNumberWithValue(value);
+ TNode<Float64T> x_value = LoadHeapNumberValue(x);
+ TNode<Float64T> value = Float64Abs(x_value);
+ TNode<HeapNumber> result = AllocateHeapNumberWithValue(value);
Return(result);
}
@@ -125,9 +126,9 @@ void MathBuiltinsAssembler::MathRoundingOperation(
BIND(&if_xisheapnumber);
{
- Node* x_value = LoadHeapNumberValue(x);
- Node* value = (this->*float64op)(x_value);
- Node* result = ChangeFloat64ToTagged(value);
+ TNode<Float64T> x_value = LoadHeapNumberValue(x);
+ TNode<Float64T> value = (this->*float64op)(x_value);
+ TNode<Number> result = ChangeFloat64ToTagged(value);
Return(result);
}
@@ -182,8 +183,8 @@ TF_BUILTIN(MathImul, CodeStubAssembler) {
Node* y = Parameter(Descriptor::kY);
Node* x_value = TruncateTaggedToWord32(context, x);
Node* y_value = TruncateTaggedToWord32(context, y);
- Node* value = Int32Mul(x_value, y_value);
- Node* result = ChangeInt32ToTagged(value);
+ TNode<Int32T> value = Signed(Int32Mul(x_value, y_value));
+ TNode<Number> result = ChangeInt32ToTagged(value);
Return(result);
}
@@ -192,7 +193,7 @@ CodeStubAssembler::Node* MathBuiltinsAssembler::MathPow(Node* context,
Node* exponent) {
Node* base_value = TruncateTaggedToFloat64(context, base);
Node* exponent_value = TruncateTaggedToFloat64(context, exponent);
- Node* value = Float64Pow(base_value, exponent_value);
+ TNode<Float64T> value = Float64Pow(base_value, exponent_value);
return ChangeFloat64ToTagged(value);
}
@@ -205,7 +206,7 @@ TF_BUILTIN(MathPow, MathBuiltinsAssembler) {
// ES6 #sec-math.random
TF_BUILTIN(MathRandom, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
// Load cache index.
TVARIABLE(Smi, smi_index);
@@ -217,9 +218,9 @@ TF_BUILTIN(MathRandom, CodeStubAssembler) {
GotoIf(SmiAbove(smi_index.value(), SmiConstant(0)), &if_cached);
// Cache exhausted, populate the cache. Return value is the new index.
- Node* const refill_math_random =
+ TNode<ExternalReference> const refill_math_random =
ExternalConstant(ExternalReference::refill_math_random());
- Node* const isolate_ptr =
+ TNode<ExternalReference> const isolate_ptr =
ExternalConstant(ExternalReference::isolate_address(isolate()));
MachineType type_tagged = MachineType::AnyTagged();
MachineType type_ptr = MachineType::Pointer();
@@ -236,9 +237,9 @@ TF_BUILTIN(MathRandom, CodeStubAssembler) {
new_smi_index);
// Load and return next cached random number.
- Node* array =
- LoadContextElement(native_context, Context::MATH_RANDOM_CACHE_INDEX);
- Node* random = LoadFixedDoubleArrayElement(
+ TNode<FixedDoubleArray> array = CAST(
+ LoadContextElement(native_context, Context::MATH_RANDOM_CACHE_INDEX));
+ TNode<Float64T> random = LoadFixedDoubleArrayElement(
array, new_smi_index, MachineType::Float64(), 0, SMI_PARAMETERS);
Return(AllocateHeapNumberWithValue(random));
}
diff --git a/deps/v8/src/builtins/builtins-math.cc b/deps/v8/src/builtins/builtins-math.cc
deleted file mode 100644
index cce780ab9f..0000000000
--- a/deps/v8/src/builtins/builtins-math.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2016 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/builtins/builtins-utils.h"
-#include "src/builtins/builtins.h"
-#include "src/logging/counters.h"
-#include "src/objects/objects-inl.h"
-
-namespace v8 {
-namespace internal {
-
-// -----------------------------------------------------------------------------
-// ES6 section 20.2.2 Function Properties of the Math Object
-
-// ES6 section 20.2.2.18 Math.hypot ( value1, value2, ...values )
-BUILTIN(MathHypot) {
- HandleScope scope(isolate);
- int const length = args.length() - 1;
- if (length == 0) return Smi::kZero;
- DCHECK_LT(0, length);
- double max = 0;
- std::vector<double> abs_values;
- abs_values.reserve(length);
- for (int i = 0; i < length; i++) {
- Handle<Object> x = args.at(i + 1);
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x,
- Object::ToNumber(isolate, x));
- double abs_value = std::abs(x->Number());
- abs_values.push_back(abs_value);
- // Use negation here to make sure that {max} is NaN
- // in the end in case any of the arguments was NaN.
- if (!(abs_value <= max)) {
- max = abs_value;
- }
- }
-
- if (max == 0) {
- return Smi::kZero;
- } else if (max == V8_INFINITY) {
- return ReadOnlyRoots(isolate).infinity_value();
- }
- DCHECK(!(max <= 0));
-
- // Kahan summation to avoid rounding errors.
- // Normalize the numbers to the largest one to avoid overflow.
- double sum = 0;
- double compensation = 0;
- for (int i = 0; i < length; i++) {
- double n = abs_values[i] / max;
- double summand = n * n - compensation;
- double preliminary = sum + summand;
- compensation = (preliminary - sum) - summand;
- sum = preliminary;
- }
-
- return *isolate->factory()->NewNumber(std::sqrt(sum) * max);
-}
-
-} // namespace internal
-} // namespace v8
diff --git a/deps/v8/src/builtins/builtins-microtask-queue-gen.cc b/deps/v8/src/builtins/builtins-microtask-queue-gen.cc
index 4987787c35..427fd6edb6 100644
--- a/deps/v8/src/builtins/builtins-microtask-queue-gen.cc
+++ b/deps/v8/src/builtins/builtins-microtask-queue-gen.cc
@@ -123,7 +123,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
StoreRoot(RootIndex::kCurrentMicrotask, microtask);
TNode<IntPtrT> saved_entered_context_count = GetEnteredContextCount();
TNode<Map> microtask_map = LoadMap(microtask);
- TNode<Int32T> microtask_type = LoadMapInstanceType(microtask_map);
+ TNode<Uint16T> microtask_type = LoadMapInstanceType(microtask_map);
VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
Label if_exception(this, Label::kDeferred);
@@ -131,21 +131,15 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
is_promise_fulfill_reaction_job(this),
is_promise_reject_reaction_job(this),
is_promise_resolve_thenable_job(this),
- is_finalization_group_cleanup_job(this),
is_unreachable(this, Label::kDeferred), done(this);
- int32_t case_values[] = {CALLABLE_TASK_TYPE,
- CALLBACK_TASK_TYPE,
+ int32_t case_values[] = {CALLABLE_TASK_TYPE, CALLBACK_TASK_TYPE,
PROMISE_FULFILL_REACTION_JOB_TASK_TYPE,
PROMISE_REJECT_REACTION_JOB_TASK_TYPE,
- PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE,
- FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE};
- Label* case_labels[] = {&is_callable,
- &is_callback,
- &is_promise_fulfill_reaction_job,
- &is_promise_reject_reaction_job,
- &is_promise_resolve_thenable_job,
- &is_finalization_group_cleanup_job};
+ PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE};
+ Label* case_labels[] = {
+ &is_callable, &is_callback, &is_promise_fulfill_reaction_job,
+ &is_promise_reject_reaction_job, &is_promise_resolve_thenable_job};
static_assert(arraysize(case_values) == arraysize(case_labels), "");
Switch(microtask_type, &is_unreachable, case_values, case_labels,
arraysize(case_labels));
@@ -155,7 +149,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
// Enter the context of the {microtask}.
TNode<Context> microtask_context =
LoadObjectField<Context>(microtask, CallableTask::kContextOffset);
- TNode<Context> native_context = LoadNativeContext(microtask_context);
+ TNode<NativeContext> native_context = LoadNativeContext(microtask_context);
PrepareForContext(native_context, &done);
TNode<JSReceiver> callable =
@@ -171,9 +165,9 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
BIND(&is_callback);
{
- Node* const microtask_callback =
+ TNode<Object> const microtask_callback =
LoadObjectField(microtask, CallbackTask::kCallbackOffset);
- Node* const microtask_data =
+ TNode<Object> const microtask_data =
LoadObjectField(microtask, CallbackTask::kDataOffset);
// If this turns out to become a bottleneck because of the calls
@@ -186,7 +180,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
// But from our current measurements it doesn't seem to be a
// serious performance problem, even if the microtask is full
// of CallHandlerTasks (which is not a realistic use case anyways).
- Node* const result =
+ TNode<Object> const result =
CallRuntime(Runtime::kRunMicrotaskCallback, current_context,
microtask_callback, microtask_data);
GotoIfException(result, &if_exception, &var_exception);
@@ -198,17 +192,17 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
// Enter the context of the {microtask}.
TNode<Context> microtask_context = LoadObjectField<Context>(
microtask, PromiseResolveThenableJobTask::kContextOffset);
- TNode<Context> native_context = LoadNativeContext(microtask_context);
+ TNode<NativeContext> native_context = LoadNativeContext(microtask_context);
PrepareForContext(native_context, &done);
- Node* const promise_to_resolve = LoadObjectField(
+ TNode<Object> const promise_to_resolve = LoadObjectField(
microtask, PromiseResolveThenableJobTask::kPromiseToResolveOffset);
- Node* const then =
+ TNode<Object> const then =
LoadObjectField(microtask, PromiseResolveThenableJobTask::kThenOffset);
- Node* const thenable = LoadObjectField(
+ TNode<Object> const thenable = LoadObjectField(
microtask, PromiseResolveThenableJobTask::kThenableOffset);
- Node* const result =
+ TNode<Object> const result =
CallBuiltin(Builtins::kPromiseResolveThenableJob, native_context,
promise_to_resolve, thenable, then);
GotoIfException(result, &if_exception, &var_exception);
@@ -222,21 +216,21 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
// Enter the context of the {microtask}.
TNode<Context> microtask_context = LoadObjectField<Context>(
microtask, PromiseReactionJobTask::kContextOffset);
- TNode<Context> native_context = LoadNativeContext(microtask_context);
+ TNode<NativeContext> native_context = LoadNativeContext(microtask_context);
PrepareForContext(native_context, &done);
- Node* const argument =
+ TNode<Object> const argument =
LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset);
- Node* const handler =
+ TNode<Object> const handler =
LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset);
- Node* const promise_or_capability = LoadObjectField(
- microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset);
+ TNode<HeapObject> const promise_or_capability = CAST(LoadObjectField(
+ microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset));
// Run the promise before/debug hook if enabled.
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
promise_or_capability);
- Node* const result =
+ TNode<Object> const result =
CallBuiltin(Builtins::kPromiseFulfillReactionJob, microtask_context,
argument, handler, promise_or_capability);
GotoIfException(result, &if_exception, &var_exception);
@@ -255,21 +249,21 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
// Enter the context of the {microtask}.
TNode<Context> microtask_context = LoadObjectField<Context>(
microtask, PromiseReactionJobTask::kContextOffset);
- TNode<Context> native_context = LoadNativeContext(microtask_context);
+ TNode<NativeContext> native_context = LoadNativeContext(microtask_context);
PrepareForContext(native_context, &done);
- Node* const argument =
+ TNode<Object> const argument =
LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset);
- Node* const handler =
+ TNode<Object> const handler =
LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset);
- Node* const promise_or_capability = LoadObjectField(
- microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset);
+ TNode<HeapObject> const promise_or_capability = CAST(LoadObjectField(
+ microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset));
// Run the promise before/debug hook if enabled.
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
promise_or_capability);
- Node* const result =
+ TNode<Object> const result =
CallBuiltin(Builtins::kPromiseRejectReactionJob, microtask_context,
argument, handler, promise_or_capability);
GotoIfException(result, &if_exception, &var_exception);
@@ -283,26 +277,6 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
Goto(&done);
}
- BIND(&is_finalization_group_cleanup_job);
- {
- // Enter the context of the {finalization_group}.
- TNode<JSFinalizationGroup> finalization_group =
- LoadObjectField<JSFinalizationGroup>(
- microtask,
- FinalizationGroupCleanupJobTask::kFinalizationGroupOffset);
- TNode<Context> native_context = LoadObjectField<Context>(
- finalization_group, JSFinalizationGroup::kNativeContextOffset);
- PrepareForContext(native_context, &done);
-
- Node* const result = CallRuntime(Runtime::kFinalizationGroupCleanupJob,
- native_context, finalization_group);
-
- GotoIfException(result, &if_exception, &var_exception);
- RewindEnteredContext(saved_entered_context_count);
- SetCurrentContext(current_context);
- Goto(&done);
- }
-
BIND(&is_unreachable);
Unreachable();
@@ -407,7 +381,7 @@ void MicrotaskQueueBuiltinsAssembler::EnterMicrotaskContext(
BIND(&if_grow);
{
- Node* function =
+ TNode<ExternalReference> function =
ExternalConstant(ExternalReference::call_enter_context_function());
CallCFunction(function, MachineType::Int32(),
std::make_pair(MachineType::Pointer(), hsi),
@@ -475,7 +449,7 @@ TF_BUILTIN(EnqueueMicrotask, MicrotaskQueueBuiltinsAssembler) {
TNode<Microtask> microtask =
UncheckedCast<Microtask>(Parameter(Descriptor::kMicrotask));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<RawPtrT> microtask_queue = GetMicrotaskQueue(native_context);
// Do not store the microtask if MicrotaskQueue is not available, that may
@@ -506,9 +480,9 @@ TF_BUILTIN(EnqueueMicrotask, MicrotaskQueueBuiltinsAssembler) {
// implementation to grow the buffer.
BIND(&if_grow);
{
- Node* isolate_constant =
+ TNode<ExternalReference> isolate_constant =
ExternalConstant(ExternalReference::isolate_address(isolate()));
- Node* function =
+ TNode<ExternalReference> function =
ExternalConstant(ExternalReference::call_enqueue_microtask_function());
CallCFunction(function, MachineType::AnyTagged(),
std::make_pair(MachineType::Pointer(), isolate_constant),
diff --git a/deps/v8/src/builtins/builtins-number-gen.cc b/deps/v8/src/builtins/builtins-number-gen.cc
index f5c4477c23..2aa996eba0 100644
--- a/deps/v8/src/builtins/builtins-number-gen.cc
+++ b/deps/v8/src/builtins/builtins-number-gen.cc
@@ -83,7 +83,7 @@ TF_BUILTIN(NumberIsFinite, CodeStubAssembler) {
GotoIfNot(IsHeapNumber(number), &return_false);
// Check if {number} contains a finite, non-NaN value.
- Node* number_value = LoadHeapNumberValue(number);
+ TNode<Float64T> number_value = LoadHeapNumberValue(number);
BranchIfFloat64IsNaN(Float64Sub(number_value, number_value), &return_false,
&return_true);
@@ -95,7 +95,7 @@ TF_BUILTIN(NumberIsFinite, CodeStubAssembler) {
}
TF_BUILTIN(AllocateHeapNumber, CodeStubAssembler) {
- Node* result = AllocateHeapNumber();
+ TNode<HeapNumber> result = AllocateHeapNumber();
Return(result);
}
@@ -118,7 +118,7 @@ TF_BUILTIN(NumberIsNaN, CodeStubAssembler) {
GotoIfNot(IsHeapNumber(number), &return_false);
// Check if {number} contains a NaN value.
- Node* number_value = LoadHeapNumberValue(number);
+ TNode<Float64T> number_value = LoadHeapNumberValue(number);
BranchIfFloat64IsNaN(number_value, &return_true, &return_false);
BIND(&return_true);
@@ -162,8 +162,8 @@ TF_BUILTIN(NumberParseFloat, CodeStubAssembler) {
{
// The {input} is a HeapObject, check if it's already a String.
Label if_inputisstring(this), if_inputisnotstring(this);
- Node* input_map = LoadMap(input);
- Node* input_instance_type = LoadMapInstanceType(input_map);
+ TNode<Map> input_map = LoadMap(input);
+ TNode<Uint16T> input_instance_type = LoadMapInstanceType(input_map);
Branch(IsStringInstanceType(input_instance_type), &if_inputisstring,
&if_inputisnotstring);
@@ -172,7 +172,7 @@ TF_BUILTIN(NumberParseFloat, CodeStubAssembler) {
// The {input} is already a String, check if {input} contains
// a cached array index.
Label if_inputcached(this), if_inputnotcached(this);
- Node* input_hash = LoadNameHashField(input);
+ TNode<Uint32T> input_hash = LoadNameHashField(input);
Branch(IsClearWord32(input_hash,
Name::kDoesNotContainCachedArrayIndexMask),
&if_inputcached, &if_inputnotcached);
@@ -180,9 +180,9 @@ TF_BUILTIN(NumberParseFloat, CodeStubAssembler) {
BIND(&if_inputcached);
{
// Just return the {input}s cached array index.
- Node* input_array_index =
+ TNode<UintPtrT> input_array_index =
DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash);
- Return(SmiTag(input_array_index));
+ Return(SmiTag(Signed(input_array_index)));
}
BIND(&if_inputnotcached);
@@ -204,7 +204,7 @@ TF_BUILTIN(NumberParseFloat, CodeStubAssembler) {
{
// The {input} is already a Number, take care of -0.
Label if_inputiszero(this), if_inputisnotzero(this);
- Node* input_value = LoadHeapNumberValue(input);
+ TNode<Float64T> input_value = LoadHeapNumberValue(input);
Branch(Float64Equal(input_value, Float64Constant(0.0)),
&if_inputiszero, &if_inputisnotzero);
@@ -229,15 +229,15 @@ TF_BUILTIN(NumberParseFloat, CodeStubAssembler) {
// ES6 #sec-number.parseint
TF_BUILTIN(ParseInt, CodeStubAssembler) {
- Node* context = Parameter(Descriptor::kContext);
- Node* input = Parameter(Descriptor::kString);
- Node* radix = Parameter(Descriptor::kRadix);
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
+ TNode<Object> input = CAST(Parameter(Descriptor::kString));
+ TNode<Object> radix = CAST(Parameter(Descriptor::kRadix));
// Check if {radix} is treated as 10 (i.e. undefined, 0 or 10).
Label if_radix10(this), if_generic(this, Label::kDeferred);
GotoIf(IsUndefined(radix), &if_radix10);
- GotoIf(WordEqual(radix, SmiConstant(10)), &if_radix10);
- GotoIf(WordEqual(radix, SmiConstant(0)), &if_radix10);
+ GotoIf(TaggedEqual(radix, SmiConstant(10)), &if_radix10);
+ GotoIf(TaggedEqual(radix, SmiConstant(0)), &if_radix10);
Goto(&if_generic);
BIND(&if_radix10);
@@ -246,9 +246,9 @@ TF_BUILTIN(ParseInt, CodeStubAssembler) {
Label if_inputissmi(this), if_inputisheapnumber(this),
if_inputisstring(this);
GotoIf(TaggedIsSmi(input), &if_inputissmi);
- Node* input_map = LoadMap(input);
+ TNode<Map> input_map = LoadMap(CAST(input));
GotoIf(IsHeapNumberMap(input_map), &if_inputisheapnumber);
- Node* input_instance_type = LoadMapInstanceType(input_map);
+ TNode<Uint16T> input_instance_type = LoadMapInstanceType(input_map);
Branch(IsStringInstanceType(input_instance_type), &if_inputisstring,
&if_generic);
@@ -262,15 +262,16 @@ TF_BUILTIN(ParseInt, CodeStubAssembler) {
{
// Check if the {input} value is in Signed32 range.
Label if_inputissigned32(this);
- Node* input_value = LoadHeapNumberValue(input);
- Node* input_value32 = TruncateFloat64ToWord32(input_value);
+ TNode<Float64T> input_value = LoadHeapNumberValue(CAST(input));
+ TNode<Int32T> input_value32 =
+ Signed(TruncateFloat64ToWord32(input_value));
GotoIf(Float64Equal(input_value, ChangeInt32ToFloat64(input_value32)),
&if_inputissigned32);
// Check if the absolute {input} value is in the [1,1<<31[ range.
// Take the generic path for the range [0,1[ because the result
// could be -0.
- Node* input_value_abs = Float64Abs(input_value);
+ TNode<Float64T> input_value_abs = Float64Abs(input_value);
GotoIfNot(Float64LessThan(input_value_abs, Float64Constant(1u << 31)),
&if_generic);
@@ -279,28 +280,29 @@ TF_BUILTIN(ParseInt, CodeStubAssembler) {
// Return the truncated int32 value, and return the tagged result.
BIND(&if_inputissigned32);
- Node* result = ChangeInt32ToTagged(input_value32);
+ TNode<Number> result = ChangeInt32ToTagged(input_value32);
Return(result);
}
BIND(&if_inputisstring);
{
// Check if the String {input} has a cached array index.
- Node* input_hash = LoadNameHashField(input);
+ TNode<Uint32T> input_hash = LoadNameHashField(CAST(input));
GotoIf(IsSetWord32(input_hash, Name::kDoesNotContainCachedArrayIndexMask),
&if_generic);
// Return the cached array index as result.
- Node* input_index =
+ TNode<UintPtrT> input_index =
DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash);
- Node* result = SmiTag(input_index);
+ TNode<Smi> result = SmiTag(Signed(input_index));
Return(result);
}
}
BIND(&if_generic);
{
- Node* result = CallRuntime(Runtime::kStringParseInt, context, input, radix);
+ TNode<Object> result =
+ CallRuntime(Runtime::kStringParseInt, context, input, radix);
Return(result);
}
}
@@ -318,8 +320,8 @@ TF_BUILTIN(NumberPrototypeValueOf, CodeStubAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- Node* result = ToThisValue(context, receiver, PrimitiveType::kNumber,
- "Number.prototype.valueOf");
+ TNode<Object> result = ToThisValue(context, receiver, PrimitiveType::kNumber,
+ "Number.prototype.valueOf");
Return(result);
}
@@ -406,7 +408,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&if_right_heapobject);
{
- Node* right_map = LoadMap(right);
+ TNode<Map> right_map = LoadMap(right);
Label if_right_not_number(this, Label::kDeferred);
GotoIfNot(IsHeapNumberMap(right_map), &if_right_not_number);
@@ -418,7 +420,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&if_right_not_number);
{
- Node* right_instance_type = LoadMapInstanceType(right_map);
+ TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map);
GotoIf(IsStringInstanceType(right_instance_type),
&string_add_convert_left);
GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add);
@@ -429,7 +431,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&if_left_heapobject);
{
- Node* left_map = LoadMap(left);
+ TNode<Map> left_map = LoadMap(left);
Label if_right_smi(this), if_right_heapobject(this);
Branch(TaggedIsSmi(right), &if_right_smi, &if_right_heapobject);
@@ -445,7 +447,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&if_left_not_number);
{
- Node* left_instance_type = LoadMapInstanceType(left_map);
+ TNode<Uint16T> left_instance_type = LoadMapInstanceType(left_map);
GotoIf(IsStringInstanceType(left_instance_type),
&string_add_convert_right);
GotoIf(IsBigIntInstanceType(left_instance_type), &do_bigint_add);
@@ -456,7 +458,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&if_right_heapobject);
{
- Node* right_map = LoadMap(right);
+ TNode<Map> right_map = LoadMap(right);
Label if_left_number(this), if_left_not_number(this, Label::kDeferred);
Branch(IsHeapNumberMap(left_map), &if_left_number, &if_left_not_number);
@@ -473,7 +475,7 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&if_right_not_number);
{
- Node* right_instance_type = LoadMapInstanceType(right_map);
+ TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map);
GotoIf(IsStringInstanceType(right_instance_type),
&string_add_convert_left);
GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add);
@@ -485,10 +487,10 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&if_left_not_number);
{
Label if_left_bigint(this);
- Node* left_instance_type = LoadMapInstanceType(left_map);
+ TNode<Uint16T> left_instance_type = LoadMapInstanceType(left_map);
GotoIf(IsStringInstanceType(left_instance_type),
&string_add_convert_right);
- Node* right_instance_type = LoadMapInstanceType(right_map);
+ TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map);
GotoIf(IsStringInstanceType(right_instance_type),
&string_add_convert_left);
GotoIf(IsBigIntInstanceType(left_instance_type), &if_left_bigint);
@@ -525,15 +527,15 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&string_add_convert_left);
{
// Convert {left} to a String and concatenate it with the String {right}.
- TailCallBuiltin(Builtins::kStringAdd_ConvertLeft, context, var_left.value(),
+ TailCallBuiltin(Builtins::kStringAddConvertLeft, context, var_left.value(),
var_right.value());
}
BIND(&string_add_convert_right);
{
// Convert {right} to a String and concatenate it with the String {left}.
- TailCallBuiltin(Builtins::kStringAdd_ConvertRight, context,
- var_left.value(), var_right.value());
+ TailCallBuiltin(Builtins::kStringAddConvertRight, context, var_left.value(),
+ var_right.value());
}
BIND(&do_bigint_add);
@@ -544,7 +546,8 @@ TF_BUILTIN(Add, AddStubAssembler) {
BIND(&do_double_add);
{
- Node* value = Float64Add(var_left_double.value(), var_right_double.value());
+ TNode<Float64T> value =
+ Float64Add(var_left_double.value(), var_right_double.value());
Return(AllocateHeapNumberWithValue(value));
}
}
@@ -696,7 +699,8 @@ TF_BUILTIN(Subtract, NumberBuiltinsAssembler) {
BIND(&do_double_sub);
{
- Node* value = Float64Sub(var_left_double.value(), var_right_double.value());
+ TNode<Float64T> value =
+ Float64Sub(var_left_double.value(), var_right_double.value());
Return(AllocateHeapNumberWithValue(value));
}
@@ -780,7 +784,8 @@ TF_BUILTIN(Negate, NumberBuiltinsAssembler) {
BIND(&do_double);
{
- Node* value = Float64Mul(var_input_double.value(), Float64Constant(-1));
+ TNode<Float64T> value =
+ Float64Mul(var_input_double.value(), Float64Constant(-1));
Return(AllocateHeapNumberWithValue(value));
}
@@ -807,7 +812,8 @@ TF_BUILTIN(Multiply, NumberBuiltinsAssembler) {
Return(SmiMul(CAST(var_left.value()), CAST(var_right.value())));
BIND(&do_double_mul);
- Node* value = Float64Mul(var_left_double.value(), var_right_double.value());
+ TNode<Float64T> value =
+ Float64Mul(var_left_double.value(), var_right_double.value());
Return(AllocateHeapNumberWithValue(value));
BIND(&do_bigint_mul);
@@ -851,8 +857,8 @@ TF_BUILTIN(Divide, NumberBuiltinsAssembler) {
}
BIND(&dividend_is_not_zero);
- Node* untagged_divisor = SmiToInt32(divisor);
- Node* untagged_dividend = SmiToInt32(dividend);
+ TNode<Int32T> untagged_divisor = SmiToInt32(divisor);
+ TNode<Int32T> untagged_dividend = SmiToInt32(dividend);
// Do floating point division if {dividend} is kMinInt (or kMinInt - 1
// if the Smi size is 31) and {divisor} is -1.
@@ -872,8 +878,9 @@ TF_BUILTIN(Divide, NumberBuiltinsAssembler) {
// TODO(epertoso): consider adding a machine instruction that returns
// both the result and the remainder.
- Node* untagged_result = Int32Div(untagged_dividend, untagged_divisor);
- Node* truncated = Int32Mul(untagged_result, untagged_divisor);
+ TNode<Int32T> untagged_result =
+ Int32Div(untagged_dividend, untagged_divisor);
+ TNode<Int32T> truncated = Int32Mul(untagged_result, untagged_divisor);
// Do floating point division if the remainder is not 0.
GotoIf(Word32NotEqual(untagged_dividend, truncated), &bailout);
Return(SmiFromInt32(untagged_result));
@@ -890,7 +897,8 @@ TF_BUILTIN(Divide, NumberBuiltinsAssembler) {
BIND(&do_double_div);
{
- Node* value = Float64Div(var_left_double.value(), var_right_double.value());
+ TNode<Float64T> value =
+ Float64Div(var_left_double.value(), var_right_double.value());
Return(AllocateHeapNumberWithValue(value));
}
@@ -916,7 +924,8 @@ TF_BUILTIN(Modulus, NumberBuiltinsAssembler) {
Return(SmiMod(CAST(var_left.value()), CAST(var_right.value())));
BIND(&do_double_mod);
- Node* value = Float64Mod(var_left_double.value(), var_right_double.value());
+ TNode<Float64T> value =
+ Float64Mod(var_left_double.value(), var_right_double.value());
Return(AllocateHeapNumberWithValue(value));
BIND(&do_bigint_mod);
diff --git a/deps/v8/src/builtins/builtins-object-gen.cc b/deps/v8/src/builtins/builtins-object-gen.cc
index 8d59ee3bd1..db9d4ed657 100644
--- a/deps/v8/src/builtins/builtins-object-gen.cc
+++ b/deps/v8/src/builtins/builtins-object-gen.cc
@@ -11,6 +11,7 @@
#include "src/ic/accessor-assembler.h"
#include "src/ic/keyed-store-generic.h"
#include "src/objects/js-generator.h"
+#include "src/objects/js-objects.h"
#include "src/objects/property-descriptor-object.h"
#include "src/objects/property-details.h"
#include "src/objects/shared-function-info.h"
@@ -44,10 +45,6 @@ class ObjectBuiltinsAssembler : public CodeStubAssembler {
Node* ConstructDataDescriptor(Node* context, Node* value, Node* writable,
Node* enumerable, Node* configurable);
Node* GetAccessorOrUndefined(Node* accessor, Label* if_bailout);
-
- Node* IsSpecialReceiverMap(SloppyTNode<Map> map);
-
- TNode<Word32T> IsStringWrapperElementsKind(TNode<Map> map);
};
class ObjectEntriesValuesBuiltinsAssembler : public ObjectBuiltinsAssembler {
@@ -72,8 +69,6 @@ class ObjectEntriesValuesBuiltinsAssembler : public ObjectBuiltinsAssembler {
void GetOwnValuesOrEntries(TNode<Context> context, TNode<Object> maybe_object,
CollectType collect_type);
- void GotoIfMapHasSlowProperties(TNode<Map> map, Label* if_slow);
-
TNode<JSArray> FastGetOwnValuesOrEntries(
TNode<Context> context, TNode<JSObject> object,
Label* if_call_runtime_with_fast_path, Label* if_no_properties,
@@ -86,8 +81,8 @@ class ObjectEntriesValuesBuiltinsAssembler : public ObjectBuiltinsAssembler {
void ObjectBuiltinsAssembler::ReturnToStringFormat(Node* context,
Node* string) {
- Node* lhs = StringConstant("[object ");
- Node* rhs = StringConstant("]");
+ TNode<String> lhs = StringConstant("[object ");
+ TNode<String> rhs = StringConstant("]");
Callable callable = CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE);
@@ -100,10 +95,10 @@ Node* ObjectBuiltinsAssembler::ConstructAccessorDescriptor(Node* context,
Node* setter,
Node* enumerable,
Node* configurable) {
- Node* native_context = LoadNativeContext(context);
- Node* map = LoadContextElement(
- native_context, Context::ACCESSOR_PROPERTY_DESCRIPTOR_MAP_INDEX);
- Node* js_desc = AllocateJSObjectFromMap(map);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<Map> map = CAST(LoadContextElement(
+ native_context, Context::ACCESSOR_PROPERTY_DESCRIPTOR_MAP_INDEX));
+ TNode<JSObject> js_desc = AllocateJSObjectFromMap(map);
StoreObjectFieldNoWriteBarrier(
js_desc, JSAccessorPropertyDescriptor::kGetOffset, getter);
@@ -124,10 +119,10 @@ Node* ObjectBuiltinsAssembler::ConstructDataDescriptor(Node* context,
Node* writable,
Node* enumerable,
Node* configurable) {
- Node* native_context = LoadNativeContext(context);
- Node* map = LoadContextElement(native_context,
- Context::DATA_PROPERTY_DESCRIPTOR_MAP_INDEX);
- Node* js_desc = AllocateJSObjectFromMap(map);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<Map> map = CAST(LoadContextElement(
+ native_context, Context::DATA_PROPERTY_DESCRIPTOR_MAP_INDEX));
+ TNode<JSObject> js_desc = AllocateJSObjectFromMap(map);
StoreObjectFieldNoWriteBarrier(js_desc,
JSDataPropertyDescriptor::kValueOffset, value);
@@ -144,28 +139,6 @@ Node* ObjectBuiltinsAssembler::ConstructDataDescriptor(Node* context,
return js_desc;
}
-Node* ObjectBuiltinsAssembler::IsSpecialReceiverMap(SloppyTNode<Map> map) {
- CSA_SLOW_ASSERT(this, IsMap(map));
- TNode<BoolT> is_special =
- IsSpecialReceiverInstanceType(LoadMapInstanceType(map));
- uint32_t mask =
- Map::HasNamedInterceptorBit::kMask | Map::IsAccessCheckNeededBit::kMask;
- USE(mask);
- // Interceptors or access checks imply special receiver.
- CSA_ASSERT(this,
- SelectConstant<BoolT>(IsSetWord32(LoadMapBitField(map), mask),
- is_special, Int32TrueConstant()));
- return is_special;
-}
-
-TNode<Word32T> ObjectBuiltinsAssembler::IsStringWrapperElementsKind(
- TNode<Map> map) {
- Node* kind = LoadMapElementsKind(map);
- return Word32Or(
- Word32Equal(kind, Int32Constant(FAST_STRING_WRAPPER_ELEMENTS)),
- Word32Equal(kind, Int32Constant(SLOW_STRING_WRAPPER_ELEMENTS)));
-}
-
TNode<BoolT> ObjectEntriesValuesBuiltinsAssembler::IsPropertyEnumerable(
TNode<Uint32T> details) {
TNode<Uint32T> attributes =
@@ -209,7 +182,7 @@ void ObjectEntriesValuesBuiltinsAssembler::GetOwnValuesOrEntries(
BIND(&if_no_properties);
{
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> array_map =
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
TNode<JSArray> empty_array = AllocateJSArray(
@@ -242,18 +215,11 @@ void ObjectEntriesValuesBuiltinsAssembler::GetOwnValuesOrEntries(
}
}
-void ObjectEntriesValuesBuiltinsAssembler::GotoIfMapHasSlowProperties(
- TNode<Map> map, Label* if_slow) {
- GotoIf(IsStringWrapperElementsKind(map), if_slow);
- GotoIf(IsSpecialReceiverMap(map), if_slow);
- GotoIf(IsDictionaryMap(map), if_slow);
-}
-
TNode<JSArray> ObjectEntriesValuesBuiltinsAssembler::FastGetOwnValuesOrEntries(
TNode<Context> context, TNode<JSObject> object,
Label* if_call_runtime_with_fast_path, Label* if_no_properties,
CollectType collect_type) {
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> array_map =
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
TNode<Map> map = LoadMap(object);
@@ -308,9 +274,10 @@ TNode<JSArray> ObjectEntriesValuesBuiltinsAssembler::FastGetOwnValuesOrEntries(
{
// Currently, we will not invoke getters,
// so, map will not be changed.
- CSA_ASSERT(this, WordEqual(map, LoadMap(object)));
+ CSA_ASSERT(this, TaggedEqual(map, LoadMap(object)));
TNode<IntPtrT> descriptor_entry = var_descriptor_number.value();
- Node* next_key = LoadKeyByDescriptorEntry(descriptors, descriptor_entry);
+ TNode<Name> next_key =
+ LoadKeyByDescriptorEntry(descriptors, descriptor_entry);
// Skip Symbols.
GotoIf(IsSymbol(next_key), &next_descriptor);
@@ -378,7 +345,7 @@ ObjectEntriesValuesBuiltinsAssembler::FinalizeValuesOrEntriesJSArray(
CSA_ASSERT(this, IsJSArrayMap(array_map));
GotoIf(IntPtrEqual(size, IntPtrConstant(0)), if_empty);
- Node* array = AllocateJSArray(array_map, result, SmiTag(size));
+ TNode<JSArray> array = AllocateJSArray(array_map, result, SmiTag(size));
return TNode<JSArray>::UncheckedCast(array);
}
@@ -412,8 +379,8 @@ TF_BUILTIN(ObjectPrototypeHasOwnProperty, ObjectBuiltinsAssembler) {
Branch(TaggedIsSmi(object), &to_primitive, &if_objectisnotsmi);
BIND(&if_objectisnotsmi);
- Node* map = LoadMap(object);
- TNode<Int32T> instance_type = LoadMapInstanceType(map);
+ TNode<Map> map = LoadMap(object);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
{
VARIABLE(var_index, MachineType::PointerRepresentation());
@@ -510,9 +477,9 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
// Check if the {object} has a usable enum cache.
GotoIf(TaggedIsSmi(object), &if_slow);
- Node* object_map = LoadMap(object);
- Node* object_bit_field3 = LoadMapBitField3(object_map);
- Node* object_enum_length =
+ TNode<Map> object_map = LoadMap(object);
+ TNode<Uint32T> object_bit_field3 = LoadMapBitField3(object_map);
+ TNode<UintPtrT> object_enum_length =
DecodeWordFromWord32<Map::EnumLengthBits>(object_bit_field3);
GotoIf(
WordEqual(object_enum_length, IntPtrConstant(kInvalidEnumCacheSentinel)),
@@ -520,7 +487,7 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
// Ensure that the {object} doesn't have any elements.
CSA_ASSERT(this, IsJSObjectMap(object_map));
- Node* object_elements = LoadElements(object);
+ TNode<FixedArrayBase> object_elements = LoadElements(object);
GotoIf(IsEmptyFixedArray(object_elements), &if_empty_elements);
Branch(IsEmptySlowElementDictionary(object_elements), &if_empty_elements,
&if_slow);
@@ -532,19 +499,19 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
BIND(&if_fast);
{
// The {object} has a usable enum cache, use that.
- Node* object_descriptors = LoadMapDescriptors(object_map);
- Node* object_enum_cache =
- LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset);
- Node* object_enum_keys =
+ TNode<DescriptorArray> object_descriptors = LoadMapDescriptors(object_map);
+ TNode<EnumCache> object_enum_cache = CAST(
+ LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset));
+ TNode<Object> object_enum_keys =
LoadObjectField(object_enum_cache, EnumCache::kKeysOffset);
// Allocate a JSArray and copy the elements from the {object_enum_keys}.
Node* array = nullptr;
Node* elements = nullptr;
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> array_map =
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
- TNode<Smi> array_length = SmiTag(object_enum_length);
+ TNode<Smi> array_length = SmiTag(Signed(object_enum_length));
std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
PACKED_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
INTPTR_PARAMETERS);
@@ -564,7 +531,8 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
BIND(&if_slow);
{
// Let the runtime compute the elements.
- Node* elements = CallRuntime(Runtime::kObjectKeys, context, object);
+ TNode<FixedArray> elements =
+ CAST(CallRuntime(Runtime::kObjectKeys, context, object));
var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
var_elements.Bind(elements);
Goto(&if_join);
@@ -573,7 +541,7 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
BIND(&if_join);
{
// Wrap the elements into a proper JSArray and return that.
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> array_map =
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
TNode<JSArray> array = AllocateJSArray(
@@ -596,25 +564,25 @@ TF_BUILTIN(ObjectGetOwnPropertyNames, ObjectBuiltinsAssembler) {
// Take the slow path if the {object} IsCustomElementsReceiverInstanceType or
// has any elements.
GotoIf(TaggedIsSmi(object), &if_slow);
- Node* object_map = LoadMap(object);
- TNode<Int32T> instance_type = LoadMapInstanceType(object_map);
+ TNode<Map> object_map = LoadMap(object);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(object_map);
GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &if_slow);
- Node* object_elements = LoadElements(object);
+ TNode<FixedArrayBase> object_elements = LoadElements(object);
GotoIf(IsEmptyFixedArray(object_elements), &if_empty_elements);
Branch(IsEmptySlowElementDictionary(object_elements), &if_empty_elements,
&if_slow);
// Check if the {object} has a usable enum cache.
BIND(&if_empty_elements);
- Node* object_bit_field3 = LoadMapBitField3(object_map);
- Node* object_enum_length =
+ TNode<Uint32T> object_bit_field3 = LoadMapBitField3(object_map);
+ TNode<UintPtrT> object_enum_length =
DecodeWordFromWord32<Map::EnumLengthBits>(object_bit_field3);
GotoIf(
WordEqual(object_enum_length, IntPtrConstant(kInvalidEnumCacheSentinel)),
&try_fast);
// Check whether all own properties are enumerable.
- Node* number_descriptors =
+ TNode<UintPtrT> number_descriptors =
DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(object_bit_field3);
GotoIfNot(WordEqual(object_enum_length, number_descriptors), &if_slow);
@@ -625,19 +593,19 @@ TF_BUILTIN(ObjectGetOwnPropertyNames, ObjectBuiltinsAssembler) {
{
// The {object} has a usable enum cache and all own properties are
// enumerable, use that.
- Node* object_descriptors = LoadMapDescriptors(object_map);
- Node* object_enum_cache =
- LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset);
- Node* object_enum_keys =
+ TNode<DescriptorArray> object_descriptors = LoadMapDescriptors(object_map);
+ TNode<EnumCache> object_enum_cache = CAST(
+ LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset));
+ TNode<Object> object_enum_keys =
LoadObjectField(object_enum_cache, EnumCache::kKeysOffset);
// Allocate a JSArray and copy the elements from the {object_enum_keys}.
Node* array = nullptr;
Node* elements = nullptr;
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> array_map =
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
- TNode<Smi> array_length = SmiTag(object_enum_length);
+ TNode<Smi> array_length = SmiTag(Signed(object_enum_length));
std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
PACKED_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
INTPTR_PARAMETERS);
@@ -649,8 +617,8 @@ TF_BUILTIN(ObjectGetOwnPropertyNames, ObjectBuiltinsAssembler) {
BIND(&try_fast);
{
// Let the runtime compute the elements and try initializing enum cache.
- Node* elements = CallRuntime(Runtime::kObjectGetOwnPropertyNamesTryFast,
- context, object);
+ TNode<FixedArray> elements = CAST(CallRuntime(
+ Runtime::kObjectGetOwnPropertyNamesTryFast, context, object));
var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
var_elements.Bind(elements);
Goto(&if_join);
@@ -667,8 +635,8 @@ TF_BUILTIN(ObjectGetOwnPropertyNames, ObjectBuiltinsAssembler) {
BIND(&if_slow);
{
// Let the runtime compute the elements.
- Node* elements =
- CallRuntime(Runtime::kObjectGetOwnPropertyNames, context, object);
+ TNode<FixedArray> elements =
+ CAST(CallRuntime(Runtime::kObjectGetOwnPropertyNames, context, object));
var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
var_elements.Bind(elements);
Goto(&if_join);
@@ -677,7 +645,7 @@ TF_BUILTIN(ObjectGetOwnPropertyNames, ObjectBuiltinsAssembler) {
BIND(&if_join);
{
// Wrap the elements into a proper JSArray and return that.
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> array_map =
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
TNode<JSArray> array = AllocateJSArray(
@@ -770,8 +738,8 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
VARIABLE(var_default, MachineRepresentation::kTagged);
VARIABLE(var_holder, MachineRepresentation::kTagged, receiver);
GotoIf(TaggedIsSmi(receiver), &if_number);
- Node* receiver_map = LoadMap(receiver);
- Node* receiver_instance_type = LoadMapInstanceType(receiver_map);
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> receiver_instance_type = LoadMapInstanceType(receiver_map);
GotoIf(IsPrimitiveInstanceType(receiver_instance_type), &if_primitive);
const struct {
InstanceType value;
@@ -818,58 +786,58 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
BIND(&if_arguments);
{
- var_default.Bind(LoadRoot(RootIndex::karguments_to_string));
+ var_default.Bind(ArgumentsToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_array);
{
- var_default.Bind(LoadRoot(RootIndex::karray_to_string));
+ var_default.Bind(ArrayToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_boolean);
{
- Node* native_context = LoadNativeContext(context);
- Node* boolean_constructor =
- LoadContextElement(native_context, Context::BOOLEAN_FUNCTION_INDEX);
- Node* boolean_initial_map = LoadObjectField(
- boolean_constructor, JSFunction::kPrototypeOrInitialMapOffset);
- Node* boolean_prototype =
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> boolean_constructor = CAST(
+ LoadContextElement(native_context, Context::BOOLEAN_FUNCTION_INDEX));
+ TNode<Map> boolean_initial_map = CAST(LoadObjectField(
+ boolean_constructor, JSFunction::kPrototypeOrInitialMapOffset));
+ TNode<Object> boolean_prototype =
LoadObjectField(boolean_initial_map, Map::kPrototypeOffset);
- var_default.Bind(LoadRoot(RootIndex::kboolean_to_string));
+ var_default.Bind(BooleanToStringConstant());
var_holder.Bind(boolean_prototype);
Goto(&checkstringtag);
}
BIND(&if_date);
{
- var_default.Bind(LoadRoot(RootIndex::kdate_to_string));
+ var_default.Bind(DateToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_error);
{
- var_default.Bind(LoadRoot(RootIndex::kerror_to_string));
+ var_default.Bind(ErrorToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_function);
{
- var_default.Bind(LoadRoot(RootIndex::kfunction_to_string));
+ var_default.Bind(FunctionToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_number);
{
- Node* native_context = LoadNativeContext(context);
- Node* number_constructor =
- LoadContextElement(native_context, Context::NUMBER_FUNCTION_INDEX);
- Node* number_initial_map = LoadObjectField(
- number_constructor, JSFunction::kPrototypeOrInitialMapOffset);
- Node* number_prototype =
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> number_constructor = CAST(
+ LoadContextElement(native_context, Context::NUMBER_FUNCTION_INDEX));
+ TNode<Map> number_initial_map = CAST(LoadObjectField(
+ number_constructor, JSFunction::kPrototypeOrInitialMapOffset));
+ TNode<Object> number_prototype =
LoadObjectField(number_initial_map, Map::kPrototypeOffset);
- var_default.Bind(LoadRoot(RootIndex::knumber_to_string));
+ var_default.Bind(NumberToStringConstant());
var_holder.Bind(number_prototype);
Goto(&checkstringtag);
}
@@ -877,7 +845,7 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
BIND(&if_object);
{
CSA_ASSERT(this, IsJSReceiver(receiver));
- var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
+ var_default.Bind(ObjectToStringConstant());
Goto(&checkstringtag);
}
@@ -892,10 +860,10 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
GotoIf(IsSymbolMap(receiver_map), &if_symbol);
GotoIf(IsUndefined(receiver), &return_undefined);
CSA_ASSERT(this, IsNull(receiver));
- Return(LoadRoot(RootIndex::knull_to_string));
+ Return(NullToStringConstant());
BIND(&return_undefined);
- Return(LoadRoot(RootIndex::kundefined_to_string));
+ Return(UndefinedToStringConstant());
}
BIND(&if_proxy);
@@ -905,16 +873,15 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
// depending on whether the {receiver} is callable. The order matters here,
// i.e. we need to execute the %ArrayIsArray check before the [[Get]] below,
// as the exception is observable.
- Node* receiver_is_array =
+ TNode<Object> receiver_is_array =
CallRuntime(Runtime::kArrayIsArray, context, receiver);
TNode<String> builtin_tag = Select<String>(
- IsTrue(receiver_is_array),
- [=] { return CAST(LoadRoot(RootIndex::kArray_string)); },
+ IsTrue(receiver_is_array), [=] { return ArrayStringConstant(); },
[=] {
return Select<String>(
IsCallableMap(receiver_map),
- [=] { return CAST(LoadRoot(RootIndex::kFunction_string)); },
- [=] { return CAST(LoadRoot(RootIndex::kObject_string)); });
+ [=] { return FunctionStringConstant(); },
+ [=] { return ObjectStringConstant(); });
});
// Lookup the @@toStringTag property on the {receiver}.
@@ -935,48 +902,48 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
BIND(&if_regexp);
{
- var_default.Bind(LoadRoot(RootIndex::kregexp_to_string));
+ var_default.Bind(RegexpToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_string);
{
- Node* native_context = LoadNativeContext(context);
- Node* string_constructor =
- LoadContextElement(native_context, Context::STRING_FUNCTION_INDEX);
- Node* string_initial_map = LoadObjectField(
- string_constructor, JSFunction::kPrototypeOrInitialMapOffset);
- Node* string_prototype =
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> string_constructor = CAST(
+ LoadContextElement(native_context, Context::STRING_FUNCTION_INDEX));
+ TNode<Map> string_initial_map = CAST(LoadObjectField(
+ string_constructor, JSFunction::kPrototypeOrInitialMapOffset));
+ TNode<Object> string_prototype =
LoadObjectField(string_initial_map, Map::kPrototypeOffset);
- var_default.Bind(LoadRoot(RootIndex::kstring_to_string));
+ var_default.Bind(StringToStringConstant());
var_holder.Bind(string_prototype);
Goto(&checkstringtag);
}
BIND(&if_symbol);
{
- Node* native_context = LoadNativeContext(context);
- Node* symbol_constructor =
- LoadContextElement(native_context, Context::SYMBOL_FUNCTION_INDEX);
- Node* symbol_initial_map = LoadObjectField(
- symbol_constructor, JSFunction::kPrototypeOrInitialMapOffset);
- Node* symbol_prototype =
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> symbol_constructor = CAST(
+ LoadContextElement(native_context, Context::SYMBOL_FUNCTION_INDEX));
+ TNode<Map> symbol_initial_map = CAST(LoadObjectField(
+ symbol_constructor, JSFunction::kPrototypeOrInitialMapOffset));
+ TNode<Object> symbol_prototype =
LoadObjectField(symbol_initial_map, Map::kPrototypeOffset);
- var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
+ var_default.Bind(ObjectToStringConstant());
var_holder.Bind(symbol_prototype);
Goto(&checkstringtag);
}
BIND(&if_bigint);
{
- Node* native_context = LoadNativeContext(context);
- Node* bigint_constructor =
- LoadContextElement(native_context, Context::BIGINT_FUNCTION_INDEX);
- Node* bigint_initial_map = LoadObjectField(
- bigint_constructor, JSFunction::kPrototypeOrInitialMapOffset);
- Node* bigint_prototype =
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> bigint_constructor = CAST(
+ LoadContextElement(native_context, Context::BIGINT_FUNCTION_INDEX));
+ TNode<Map> bigint_initial_map = CAST(LoadObjectField(
+ bigint_constructor, JSFunction::kPrototypeOrInitialMapOffset));
+ TNode<Object> bigint_prototype =
LoadObjectField(bigint_initial_map, Map::kPrototypeOffset);
- var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
+ var_default.Bind(ObjectToStringConstant());
var_holder.Bind(bigint_prototype);
Goto(&checkstringtag);
}
@@ -994,11 +961,11 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
// which might have interesting properties.
var_holder.Bind(receiver);
GotoIf(TaggedIsSmi(receiver_value), &if_value_is_number);
- Node* receiver_value_map = LoadMap(receiver_value);
+ TNode<Map> receiver_value_map = LoadMap(receiver_value);
GotoIf(IsHeapNumberMap(receiver_value_map), &if_value_is_number);
GotoIf(IsBooleanMap(receiver_value_map), &if_value_is_boolean);
GotoIf(IsSymbolMap(receiver_value_map), &if_value_is_symbol);
- Node* receiver_value_instance_type =
+ TNode<Uint16T> receiver_value_instance_type =
LoadMapInstanceType(receiver_value_map);
GotoIf(IsBigIntInstanceType(receiver_value_instance_type),
&if_value_is_bigint);
@@ -1007,31 +974,31 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
BIND(&if_value_is_number);
{
- var_default.Bind(LoadRoot(RootIndex::knumber_to_string));
+ var_default.Bind(NumberToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_value_is_boolean);
{
- var_default.Bind(LoadRoot(RootIndex::kboolean_to_string));
+ var_default.Bind(BooleanToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_value_is_string);
{
- var_default.Bind(LoadRoot(RootIndex::kstring_to_string));
+ var_default.Bind(StringToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_value_is_bigint);
{
- var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
+ var_default.Bind(ObjectToStringConstant());
Goto(&checkstringtag);
}
BIND(&if_value_is_symbol);
{
- var_default.Bind(LoadRoot(RootIndex::kobject_to_string));
+ var_default.Bind(ObjectToStringConstant());
Goto(&checkstringtag);
}
}
@@ -1048,8 +1015,8 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
{
Node* holder = var_holder.value();
GotoIf(IsNull(holder), &return_default);
- Node* holder_map = LoadMap(holder);
- Node* holder_bit_field3 = LoadMapBitField3(holder_map);
+ TNode<Map> holder_map = LoadMap(holder);
+ TNode<Uint32T> holder_bit_field3 = LoadMapBitField3(holder_map);
GotoIf(IsSetWord32<Map::MayHaveInterestingSymbolsBit>(holder_bit_field3),
&return_generic);
var_holder.Bind(LoadMapPrototype(holder_map));
@@ -1058,10 +1025,10 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
BIND(&return_generic);
{
- Node* tag = GetProperty(context, ToObject(context, receiver),
- LoadRoot(RootIndex::kto_string_tag_symbol));
+ TNode<Object> tag = GetProperty(context, ToObject(context, receiver),
+ ToStringTagSymbolConstant());
GotoIf(TaggedIsSmi(tag), &return_default);
- GotoIfNot(IsString(tag), &return_default);
+ GotoIfNot(IsString(CAST(tag)), &return_default);
ReturnToStringFormat(context, tag);
}
@@ -1080,9 +1047,9 @@ TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) {
// ES #sec-object.create
TF_BUILTIN(CreateObjectWithoutProperties, ObjectBuiltinsAssembler) {
- Node* const prototype = Parameter(Descriptor::kPrototypeArg);
- Node* const context = Parameter(Descriptor::kContext);
- Node* const native_context = LoadNativeContext(context);
+ TNode<Object> const prototype = CAST(Parameter(Descriptor::kPrototypeArg));
+ TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
Label call_runtime(this, Label::kDeferred), prototype_null(this),
prototype_jsreceiver(this);
{
@@ -1108,16 +1075,16 @@ TF_BUILTIN(CreateObjectWithoutProperties, ObjectBuiltinsAssembler) {
{
Comment("Prototype is JSReceiver");
properties.Bind(EmptyFixedArrayConstant());
- Node* object_function =
- LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX);
- Node* object_function_map = LoadObjectField(
+ TNode<HeapObject> object_function = CAST(
+ LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX));
+ TNode<Object> object_function_map = LoadObjectField(
object_function, JSFunction::kPrototypeOrInitialMapOffset);
map.Bind(object_function_map);
- GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())),
+ GotoIf(TaggedEqual(prototype, LoadMapPrototype(map.value())),
&instantiate_map);
Comment("Try loading the prototype info");
- Node* prototype_info =
- LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime);
+ TNode<PrototypeInfo> prototype_info =
+ LoadMapPrototypeInfo(LoadMap(CAST(prototype)), &call_runtime);
TNode<MaybeObject> maybe_map = LoadMaybeWeakObjectField(
prototype_info, PrototypeInfo::kObjectCreateMapOffset);
GotoIf(IsStrongReferenceTo(maybe_map, UndefinedConstant()), &call_runtime);
@@ -1128,15 +1095,16 @@ TF_BUILTIN(CreateObjectWithoutProperties, ObjectBuiltinsAssembler) {
BIND(&instantiate_map);
{
Comment("Instantiate map");
- Node* instance = AllocateJSObjectFromMap(map.value(), properties.value());
+ TNode<JSObject> instance =
+ AllocateJSObjectFromMap(map.value(), properties.value());
Return(instance);
}
BIND(&call_runtime);
{
Comment("Call Runtime (prototype is not null/jsreceiver)");
- Node* result = CallRuntime(Runtime::kObjectCreate, context, prototype,
- UndefinedConstant());
+ TNode<Object> result = CallRuntime(Runtime::kObjectCreate, context,
+ prototype, UndefinedConstant());
Return(result);
}
}
@@ -1146,13 +1114,13 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
int const kPrototypeArg = 0;
int const kPropertiesArg = 1;
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
- Node* prototype = args.GetOptionalArgumentValue(kPrototypeArg);
- Node* properties = args.GetOptionalArgumentValue(kPropertiesArg);
- Node* context = Parameter(Descriptor::kContext);
+ TNode<Object> prototype = args.GetOptionalArgumentValue(kPrototypeArg);
+ TNode<Object> properties = args.GetOptionalArgumentValue(kPropertiesArg);
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Label call_runtime(this, Label::kDeferred), prototype_valid(this),
no_properties(this);
@@ -1169,14 +1137,14 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
GotoIf(TaggedIsSmi(properties), &call_runtime);
// Undefined implies no properties.
GotoIf(IsUndefined(properties), &no_properties);
- Node* properties_map = LoadMap(properties);
+ TNode<Map> properties_map = LoadMap(CAST(properties));
GotoIf(IsSpecialReceiverMap(properties_map), &call_runtime);
// Stay on the fast path only if there are no elements.
- GotoIfNot(WordEqual(LoadElements(properties),
- LoadRoot(RootIndex::kEmptyFixedArray)),
- &call_runtime);
+ GotoIfNot(
+ TaggedEqual(LoadElements(CAST(properties)), EmptyFixedArrayConstant()),
+ &call_runtime);
// Handle dictionary objects or fast objects with properties in runtime.
- Node* bit_field3 = LoadMapBitField3(properties_map);
+ TNode<Uint32T> bit_field3 = LoadMapBitField3(properties_map);
GotoIf(IsSetWord32<Map::IsDictionaryMapBit>(bit_field3), &call_runtime);
Branch(IsSetWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3),
&call_runtime, &no_properties);
@@ -1202,16 +1170,16 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
BIND(&non_null_proto);
{
properties.Bind(EmptyFixedArrayConstant());
- Node* object_function =
- LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX);
- Node* object_function_map = LoadObjectField(
+ TNode<HeapObject> object_function =
+ CAST(LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX));
+ TNode<Object> object_function_map = LoadObjectField(
object_function, JSFunction::kPrototypeOrInitialMapOffset);
map.Bind(object_function_map);
- GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())),
+ GotoIf(TaggedEqual(prototype, LoadMapPrototype(map.value())),
&instantiate_map);
// Try loading the prototype info.
- Node* prototype_info =
- LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime);
+ TNode<PrototypeInfo> prototype_info =
+ LoadMapPrototypeInfo(LoadMap(CAST(prototype)), &call_runtime);
Comment("Load ObjectCreateMap from PrototypeInfo");
TNode<MaybeObject> maybe_map = LoadMaybeWeakObjectField(
prototype_info, PrototypeInfo::kObjectCreateMapOffset);
@@ -1223,14 +1191,15 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
BIND(&instantiate_map);
{
- Node* instance = AllocateJSObjectFromMap(map.value(), properties.value());
+ TNode<JSObject> instance =
+ AllocateJSObjectFromMap(map.value(), properties.value());
args.PopAndReturn(instance);
}
}
BIND(&call_runtime);
{
- Node* result =
+ TNode<Object> result =
CallRuntime(Runtime::kObjectCreate, context, prototype, properties);
args.PopAndReturn(result);
}
@@ -1256,11 +1225,11 @@ TF_BUILTIN(CreateIterResultObject, ObjectBuiltinsAssembler) {
Node* const done = Parameter(Descriptor::kDone);
Node* const context = Parameter(Descriptor::kContext);
- Node* const native_context = LoadNativeContext(context);
- Node* const map =
- LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Map> const map = CAST(
+ LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX));
- Node* const result = AllocateJSObjectFromMap(map);
+ TNode<JSObject> const result = AllocateJSObjectFromMap(map);
StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value);
StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done);
@@ -1309,27 +1278,31 @@ TF_BUILTIN(CreateGeneratorObject, ObjectBuiltinsAssembler) {
// have one.
Label done(this), runtime(this);
GotoIfNot(IsFunctionWithPrototypeSlotMap(LoadMap(closure)), &runtime);
- Node* maybe_map =
- LoadObjectField(closure, JSFunction::kPrototypeOrInitialMapOffset);
+ TNode<HeapObject> maybe_map =
+ CAST(LoadObjectField(closure, JSFunction::kPrototypeOrInitialMapOffset));
GotoIf(DoesntHaveInstanceType(maybe_map, MAP_TYPE), &runtime);
+ TNode<Map> map = CAST(maybe_map);
- Node* shared =
- LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
- Node* bytecode_array = LoadSharedFunctionInfoBytecodeArray(shared);
+ TNode<SharedFunctionInfo> shared =
+ CAST(LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset));
+ TNode<BytecodeArray> bytecode_array =
+ LoadSharedFunctionInfoBytecodeArray(shared);
- Node* formal_parameter_count = ChangeInt32ToIntPtr(
+ TNode<IntPtrT> formal_parameter_count = ChangeInt32ToIntPtr(
LoadObjectField(shared, SharedFunctionInfo::kFormalParameterCountOffset,
MachineType::Uint16()));
- Node* frame_size = ChangeInt32ToIntPtr(LoadObjectField(
+ TNode<IntPtrT> frame_size = ChangeInt32ToIntPtr(LoadObjectField(
bytecode_array, BytecodeArray::kFrameSizeOffset, MachineType::Int32()));
- Node* size = IntPtrAdd(WordSar(frame_size, IntPtrConstant(kTaggedSizeLog2)),
- formal_parameter_count);
- Node* parameters_and_registers = AllocateFixedArray(HOLEY_ELEMENTS, size);
+ TNode<WordT> size =
+ IntPtrAdd(WordSar(frame_size, IntPtrConstant(kTaggedSizeLog2)),
+ formal_parameter_count);
+ TNode<FixedArrayBase> parameters_and_registers =
+ AllocateFixedArray(HOLEY_ELEMENTS, size);
FillFixedArrayWithValue(HOLEY_ELEMENTS, parameters_and_registers,
IntPtrConstant(0), size, RootIndex::kUndefinedValue);
// TODO(cbruni): support start_offset to avoid double initialization.
- Node* result = AllocateJSObjectFromMap(maybe_map, nullptr, nullptr, kNone,
- kWithSlackTracking);
+ TNode<JSObject> result =
+ AllocateJSObjectFromMap(map, nullptr, nullptr, kNone, kWithSlackTracking);
StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kFunctionOffset,
closure);
StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kContextOffset,
@@ -1339,13 +1312,13 @@ TF_BUILTIN(CreateGeneratorObject, ObjectBuiltinsAssembler) {
StoreObjectFieldNoWriteBarrier(
result, JSGeneratorObject::kParametersAndRegistersOffset,
parameters_and_registers);
- Node* resume_mode = SmiConstant(JSGeneratorObject::ResumeMode::kNext);
+ TNode<Smi> resume_mode = SmiConstant(JSGeneratorObject::ResumeMode::kNext);
StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kResumeModeOffset,
resume_mode);
- Node* executing = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
+ TNode<Smi> executing = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kContinuationOffset,
executing);
- GotoIfNot(InstanceTypeEqual(LoadMapInstanceType(maybe_map),
+ GotoIfNot(InstanceTypeEqual(LoadMapInstanceType(map),
JS_ASYNC_GENERATOR_OBJECT_TYPE),
&done);
StoreObjectFieldNoWriteBarrier(
@@ -1369,11 +1342,11 @@ TF_BUILTIN(ObjectGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
- Node* object = args.GetOptionalArgumentValue(0);
- Node* key = args.GetOptionalArgumentValue(1);
+ TNode<Object> object_input = args.GetOptionalArgumentValue(0);
+ TNode<Object> key = args.GetOptionalArgumentValue(1);
// 1. Let obj be ? ToObject(O).
- object = ToObject_Inline(CAST(context), CAST(object));
+ TNode<JSReceiver> object = ToObject_Inline(CAST(context), object_input);
// 2. Let key be ? ToPropertyKey(P).
key = CallBuiltin(Builtins::kToName, context, key);
@@ -1382,8 +1355,8 @@ TF_BUILTIN(ObjectGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
Label if_keyisindex(this), if_iskeyunique(this),
call_runtime(this, Label::kDeferred),
return_undefined(this, Label::kDeferred), if_notunique_name(this);
- Node* map = LoadMap(object);
- TNode<Int32T> instance_type = LoadMapInstanceType(map);
+ TNode<Map> map = LoadMap(object);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
GotoIf(IsSpecialReceiverInstanceType(instance_type), &call_runtime);
{
VARIABLE(var_index, MachineType::PointerRepresentation(),
@@ -1440,15 +1413,15 @@ TF_BUILTIN(ObjectGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
BIND(&call_runtime);
{
- Node* desc =
+ TNode<Object> desc =
CallRuntime(Runtime::kGetOwnPropertyDescriptor, context, object, key);
GotoIf(IsUndefined(desc), &return_undefined);
- CSA_ASSERT(this, IsFixedArray(desc));
+ TNode<FixedArray> desc_array = CAST(desc);
// 4. Return FromPropertyDescriptor(desc).
- Node* js_desc = FromPropertyDescriptor(context, desc);
+ Node* js_desc = FromPropertyDescriptor(context, desc_array);
args.PopAndReturn(js_desc);
}
BIND(&return_undefined);
@@ -1471,10 +1444,10 @@ Node* ObjectBuiltinsAssembler::FromPropertyDescriptor(Node* context,
Node* desc) {
VARIABLE(js_descriptor, MachineRepresentation::kTagged);
- Node* flags = LoadAndUntagToWord32ObjectField(
+ TNode<Int32T> flags = LoadAndUntagToWord32ObjectField(
desc, PropertyDescriptorObject::kFlagsOffset);
- Node* has_flags =
+ TNode<Word32T> has_flags =
Word32And(flags, Int32Constant(PropertyDescriptorObject::kHasMask));
Label if_accessor_desc(this), if_data_desc(this), if_generic_desc(this),
@@ -1512,13 +1485,13 @@ Node* ObjectBuiltinsAssembler::FromPropertyDescriptor(Node* context,
BIND(&if_generic_desc);
{
- Node* native_context = LoadNativeContext(context);
- Node* map = LoadContextElement(
- native_context, Context::SLOW_OBJECT_WITH_OBJECT_PROTOTYPE_MAP);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<Map> map = CAST(LoadContextElement(
+ 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<NameDictionary> properties = AllocateNameDictionary(6);
- Node* js_desc = AllocateJSObjectFromMap(map, properties);
+ TNode<JSObject> js_desc = AllocateJSObjectFromMap(map, properties);
Label bailout(this, Label::kDeferred);
@@ -1579,8 +1552,10 @@ Node* ObjectBuiltinsAssembler::FromPropertyDetails(Node* context,
BIND(&if_accessor_desc);
{
- Node* getter = LoadObjectField(raw_value, AccessorPair::kGetterOffset);
- Node* setter = LoadObjectField(raw_value, AccessorPair::kSetterOffset);
+ TNode<Object> getter =
+ LoadObjectField(raw_value, AccessorPair::kGetterOffset);
+ TNode<Object> setter =
+ LoadObjectField(raw_value, AccessorPair::kSetterOffset);
js_descriptor.Bind(ConstructAccessorDescriptor(
context, GetAccessorOrUndefined(getter, if_bailout),
GetAccessorOrUndefined(setter, if_bailout),
@@ -1610,7 +1585,7 @@ Node* ObjectBuiltinsAssembler::GetAccessorOrUndefined(Node* accessor,
GotoIf(IsNull(accessor), &bind_undefined);
result.Bind(accessor);
- Node* map = LoadMap(accessor);
+ TNode<Map> map = LoadMap(accessor);
// TODO(ishell): probe template instantiations cache.
GotoIf(IsFunctionTemplateInfoMap(map), if_bailout);
Goto(&return_result);
diff --git a/deps/v8/src/builtins/builtins-object.cc b/deps/v8/src/builtins/builtins-object.cc
index 1ca5fffd8d..93f011ffa1 100644
--- a/deps/v8/src/builtins/builtins-object.cc
+++ b/deps/v8/src/builtins/builtins-object.cc
@@ -156,8 +156,11 @@ Object ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
case LookupIterator::ACCESSOR: {
Handle<Object> maybe_pair = it.GetAccessors();
if (maybe_pair->IsAccessorPair()) {
+ Handle<NativeContext> native_context =
+ it.GetHolder<JSReceiver>()->GetCreationContext();
return *AccessorPair::GetComponent(
- isolate, Handle<AccessorPair>::cast(maybe_pair), component);
+ isolate, native_context, Handle<AccessorPair>::cast(maybe_pair),
+ component);
}
}
}
diff --git a/deps/v8/src/builtins/builtins-promise-gen.cc b/deps/v8/src/builtins/builtins-promise-gen.cc
index 1339e2dccd..a1da55e0d9 100644
--- a/deps/v8/src/builtins/builtins-promise-gen.cc
+++ b/deps/v8/src/builtins/builtins-promise-gen.cc
@@ -11,6 +11,8 @@
#include "src/builtins/builtins.h"
#include "src/codegen/code-factory.h"
#include "src/codegen/code-stub-assembler.h"
+#include "src/objects/fixed-array.h"
+#include "src/objects/js-objects.h"
#include "src/objects/js-promise.h"
#include "src/objects/objects-inl.h"
#include "src/objects/smi.h"
@@ -24,13 +26,14 @@ using TNode = CodeStubAssembler::TNode<T>;
using IteratorRecord = TorqueStructIteratorRecord;
Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) {
- Node* const native_context = LoadNativeContext(context);
- Node* const promise_fun =
- LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<JSFunction> const promise_fun =
+ CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun)));
- Node* const promise_map =
+ TNode<Object> const promise_map =
LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
- Node* const promise = Allocate(JSPromise::kSizeWithEmbedderFields);
+ TNode<HeapObject> const promise =
+ Allocate(JSPromise::kSizeWithEmbedderFields);
StoreMapNoWriteBarrier(promise, promise_map);
StoreObjectFieldRoot(promise, JSPromise::kPropertiesOrHashOffset,
RootIndex::kEmptyFixedArray);
@@ -99,14 +102,14 @@ PromiseBuiltinsAssembler::CreatePromiseResolvingFunctions(
Node* promise, Node* debug_event, Node* native_context) {
Node* const promise_context = CreatePromiseResolvingFunctionsContext(
promise, debug_event, native_context);
- Node* const map = LoadContextElement(
+ TNode<Object> const map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
- Node* const resolve_info = LoadContextElement(
+ TNode<Object> const resolve_info = LoadContextElement(
native_context,
Context::PROMISE_CAPABILITY_DEFAULT_RESOLVE_SHARED_FUN_INDEX);
Node* const resolve =
AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
- Node* const reject_info = LoadContextElement(
+ TNode<Object> const reject_info = LoadContextElement(
native_context,
Context::PROMISE_CAPABILITY_DEFAULT_REJECT_SHARED_FUN_INDEX);
Node* const reject =
@@ -137,7 +140,7 @@ void PromiseBuiltinsAssembler::ExtractHandlerContext(Node* handler,
};
static_assert(arraysize(case_values) == arraysize(case_labels), "");
TNode<Map> handler_map = LoadMap(var_handler.value());
- TNode<Int32T> handler_type = LoadMapInstanceType(handler_map);
+ TNode<Uint16T> handler_type = LoadMapInstanceType(handler_map);
Switch(handler_type, &done, case_values, case_labels,
arraysize(case_labels));
@@ -162,7 +165,7 @@ void PromiseBuiltinsAssembler::ExtractHandlerContext(Node* handler,
BIND(&if_function);
{
// Use the function's context.
- Node* handler_context =
+ TNode<Object> handler_context =
LoadObjectField(var_handler.value(), JSFunction::kContextOffset);
var_context->Bind(LoadNativeContext(CAST(handler_context)));
Goto(&done);
@@ -176,19 +179,19 @@ void PromiseBuiltinsAssembler::ExtractHandlerContext(Node* handler,
// ES #sec-newpromisecapability
TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
- Node* const context = Parameter(Descriptor::kContext);
- Node* const constructor = Parameter(Descriptor::kConstructor);
- Node* const debug_event = Parameter(Descriptor::kDebugEvent);
- TNode<Context> const native_context = LoadNativeContext(context);
+ TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
+ TNode<Object> const constructor = CAST(Parameter(Descriptor::kConstructor));
+ TNode<Object> const debug_event = CAST(Parameter(Descriptor::kDebugEvent));
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
Label if_not_constructor(this, Label::kDeferred),
if_notcallable(this, Label::kDeferred), if_fast_promise_capability(this),
if_slow_promise_capability(this, Label::kDeferred);
GotoIf(TaggedIsSmi(constructor), &if_not_constructor);
- GotoIfNot(IsConstructorMap(LoadMap(constructor)), &if_not_constructor);
- Branch(WordEqual(constructor,
- LoadContextElement(native_context,
- Context::PROMISE_FUNCTION_INDEX)),
+ GotoIfNot(IsConstructorMap(LoadMap(CAST(constructor))), &if_not_constructor);
+ Branch(TaggedEqual(constructor,
+ LoadContextElement(native_context,
+ Context::PROMISE_FUNCTION_INDEX)),
&if_fast_promise_capability, &if_slow_promise_capability);
BIND(&if_fast_promise_capability);
@@ -201,7 +204,7 @@ TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
std::tie(resolve, reject) =
CreatePromiseResolvingFunctions(promise, debug_event, native_context);
- Node* capability = Allocate(PromiseCapability::kSize);
+ TNode<HeapObject> capability = Allocate(PromiseCapability::kSize);
StoreMapNoWriteBarrier(capability, RootIndex::kPromiseCapabilityMap);
StoreObjectFieldNoWriteBarrier(capability,
PromiseCapability::kPromiseOffset, promise);
@@ -214,7 +217,7 @@ TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
BIND(&if_slow_promise_capability);
{
- Node* capability = Allocate(PromiseCapability::kSize);
+ TNode<HeapObject> capability = Allocate(PromiseCapability::kSize);
StoreMapNoWriteBarrier(capability, RootIndex::kPromiseCapabilityMap);
StoreObjectFieldRoot(capability, PromiseCapability::kPromiseOffset,
RootIndex::kUndefinedValue);
@@ -225,25 +228,26 @@ TF_BUILTIN(NewPromiseCapability, PromiseBuiltinsAssembler) {
Node* executor_context =
CreatePromiseGetCapabilitiesExecutorContext(capability, native_context);
- Node* executor_info = LoadContextElement(
+ TNode<Object> executor_info = LoadContextElement(
native_context, Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN);
- Node* function_map = LoadContextElement(
+ TNode<Object> function_map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
TNode<JSFunction> executor = CAST(AllocateFunctionWithMapAndContext(
function_map, executor_info, executor_context));
- Node* promise = Construct(native_context, CAST(constructor), executor);
+ TNode<JSReceiver> promise =
+ Construct(native_context, CAST(constructor), executor);
StoreObjectField(capability, PromiseCapability::kPromiseOffset, promise);
- Node* resolve =
+ TNode<Object> resolve =
LoadObjectField(capability, PromiseCapability::kResolveOffset);
GotoIf(TaggedIsSmi(resolve), &if_notcallable);
- GotoIfNot(IsCallable(resolve), &if_notcallable);
+ GotoIfNot(IsCallable(CAST(resolve)), &if_notcallable);
- Node* reject =
+ TNode<Object> reject =
LoadObjectField(capability, PromiseCapability::kRejectOffset);
GotoIf(TaggedIsSmi(reject), &if_notcallable);
- GotoIfNot(IsCallable(reject), &if_notcallable);
+ GotoIfNot(IsCallable(CAST(reject)), &if_notcallable);
Return(capability);
}
@@ -258,7 +262,8 @@ Node* PromiseBuiltinsAssembler::CreatePromiseContext(Node* native_context,
int slots) {
DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
- Node* const context = AllocateInNewSpace(FixedArray::SizeFor(slots));
+ TNode<HeapObject> const context =
+ AllocateInNewSpace(FixedArray::SizeFor(slots));
InitializeFunctionContext(native_context, context, slots);
return context;
}
@@ -296,9 +301,10 @@ PromiseBuiltinsAssembler::CreatePromiseAllResolveElementFunction(
index, SmiConstant(PropertyArray::HashField::kMax)));
CSA_ASSERT(this, IsNativeContext(native_context));
- Node* const map = LoadContextElement(
+ TNode<Object> const map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
- Node* const resolve_info = LoadContextElement(native_context, slot_index);
+ TNode<Object> const resolve_info =
+ LoadContextElement(native_context, slot_index);
TNode<JSFunction> resolve =
Cast(AllocateFunctionWithMapAndContext(map, resolve_info, context));
@@ -332,7 +338,8 @@ Node* PromiseBuiltinsAssembler::CreatePromiseGetCapabilitiesExecutorContext(
}
Node* PromiseBuiltinsAssembler::PromiseHasHandler(Node* promise) {
- Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
+ TNode<Smi> const flags =
+ CAST(LoadObjectField(promise, JSPromise::kFlagsOffset));
return IsSetWord(SmiUntag(flags), 1 << JSPromise::kHasHandlerBit);
}
@@ -344,12 +351,12 @@ void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) {
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
}
-Node* PromiseBuiltinsAssembler::IsPromiseStatus(
- Node* actual, v8::Promise::PromiseState expected) {
+TNode<BoolT> PromiseBuiltinsAssembler::IsPromiseStatus(
+ TNode<Word32T> actual, v8::Promise::PromiseState expected) {
return Word32Equal(actual, Int32Constant(expected));
}
-Node* PromiseBuiltinsAssembler::PromiseStatus(Node* promise) {
+TNode<Word32T> PromiseBuiltinsAssembler::PromiseStatus(Node* promise) {
STATIC_ASSERT(JSPromise::kStatusShift == 0);
TNode<Smi> const flags =
CAST(LoadObjectField(promise, JSPromise::kFlagsOffset));
@@ -394,7 +401,7 @@ void PromiseBuiltinsAssembler::PerformPromiseThen(
IsUndefined(result_promise_or_capability)));
Label if_pending(this), if_notpending(this), done(this);
- Node* const status = PromiseStatus(promise);
+ TNode<Word32T> const status = PromiseStatus(promise);
Branch(IsPromiseStatus(status, v8::Promise::kPending), &if_pending,
&if_notpending);
@@ -404,7 +411,7 @@ void PromiseBuiltinsAssembler::PerformPromiseThen(
// PromiseReaction holding both the onFulfilled and onRejected callbacks.
// Once the {promise} is resolved we decide on the concrete handler to
// push onto the microtask queue.
- Node* const promise_reactions =
+ TNode<Object> const promise_reactions =
LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
Node* const reaction =
AllocatePromiseReaction(promise_reactions, result_promise_or_capability,
@@ -426,7 +433,7 @@ void PromiseBuiltinsAssembler::PerformPromiseThen(
BIND(&if_fulfilled);
{
- var_map.Bind(LoadRoot(RootIndex::kPromiseFulfillReactionJobTaskMap));
+ var_map.Bind(PromiseFulfillReactionJobTaskMapConstant());
var_handler.Bind(on_fulfilled);
Label use_fallback(this, Label::kDeferred), done(this);
@@ -445,7 +452,7 @@ void PromiseBuiltinsAssembler::PerformPromiseThen(
BIND(&if_rejected);
{
CSA_ASSERT(this, IsPromiseStatus(status, v8::Promise::kRejected));
- var_map.Bind(LoadRoot(RootIndex::kPromiseRejectReactionJobTaskMap));
+ var_map.Bind(PromiseRejectReactionJobTaskMapConstant());
var_handler.Bind(on_rejected);
Label use_fallback(this, Label::kDeferred), done(this);
@@ -465,7 +472,7 @@ void PromiseBuiltinsAssembler::PerformPromiseThen(
BIND(&enqueue);
{
- Node* argument =
+ TNode<Object> argument =
LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
Node* microtask = AllocatePromiseReactionJobTask(
var_map.value(), var_handler_context.value(), argument,
@@ -500,7 +507,7 @@ TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) {
Node* PromiseBuiltinsAssembler::AllocatePromiseReaction(
Node* next, Node* promise_or_capability, Node* fulfill_handler,
Node* reject_handler) {
- Node* const reaction = Allocate(PromiseReaction::kSize);
+ TNode<HeapObject> const reaction = Allocate(PromiseReaction::kSize);
StoreMapNoWriteBarrier(reaction, RootIndex::kPromiseReactionMap);
StoreObjectFieldNoWriteBarrier(reaction, PromiseReaction::kNextOffset, next);
StoreObjectFieldNoWriteBarrier(reaction,
@@ -516,7 +523,7 @@ Node* PromiseBuiltinsAssembler::AllocatePromiseReaction(
Node* PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask(
Node* map, Node* context, Node* argument, Node* handler,
Node* promise_or_capability) {
- Node* const microtask =
+ TNode<HeapObject> const microtask =
Allocate(PromiseReactionJobTask::kSizeOfAllPromiseReactionJobTasks);
StoreMapNoWriteBarrier(microtask, map);
StoreObjectFieldNoWriteBarrier(
@@ -531,19 +538,10 @@ Node* PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask(
return microtask;
}
-Node* PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask(
- RootIndex map_root_index, Node* context, Node* argument, Node* handler,
- Node* promise_or_capability) {
- DCHECK(map_root_index == RootIndex::kPromiseFulfillReactionJobTaskMap ||
- map_root_index == RootIndex::kPromiseRejectReactionJobTaskMap);
- Node* const map = LoadRoot(map_root_index);
- return AllocatePromiseReactionJobTask(map, context, argument, handler,
- promise_or_capability);
-}
-
Node* PromiseBuiltinsAssembler::AllocatePromiseResolveThenableJobTask(
Node* promise_to_resolve, Node* then, Node* thenable, Node* context) {
- Node* const microtask = Allocate(PromiseResolveThenableJobTask::kSize);
+ TNode<HeapObject> const microtask =
+ Allocate(PromiseResolveThenableJobTask::kSize);
StoreMapNoWriteBarrier(microtask,
RootIndex::kPromiseResolveThenableJobTaskMap);
StoreObjectFieldNoWriteBarrier(
@@ -574,8 +572,7 @@ Node* PromiseBuiltinsAssembler::TriggerPromiseReactions(
// PromiseReaction instances and not actual JavaScript values (which
// would indicate that we're rejecting or resolving an already settled
// promise), see https://crbug.com/931640 for details on this.
- TNode<Map> promise_reaction_map =
- CAST(LoadRoot(RootIndex::kPromiseReactionMap));
+ TNode<Map> promise_reaction_map = PromiseReactionMapConstant();
Label loop(this, {&var_current, &var_reversed}), done_loop(this);
Goto(&loop);
@@ -583,7 +580,8 @@ Node* PromiseBuiltinsAssembler::TriggerPromiseReactions(
{
Node* current = var_current.value();
GotoIf(TaggedIsSmi(current), &done_loop);
- CSA_CHECK(this, WordEqual(LoadMap(CAST(current)), promise_reaction_map));
+ CSA_CHECK(this,
+ TaggedEqual(LoadMap(CAST(current)), promise_reaction_map));
var_current.Bind(LoadObjectField(current, PromiseReaction::kNextOffset));
StoreObjectField(current, PromiseReaction::kNextOffset,
var_reversed.value());
@@ -690,7 +688,7 @@ Node* PromiseBuiltinsAssembler::InvokeThen(Node* native_context, Node* receiver,
VARIABLE(var_result, MachineRepresentation::kTagged);
Label if_fast(this), if_slow(this, Label::kDeferred), done(this, &var_result);
GotoIf(TaggedIsSmi(receiver), &if_slow);
- Node* const receiver_map = LoadMap(receiver);
+ TNode<Map> const receiver_map = LoadMap(receiver);
// We can skip the "then" lookup on {receiver} if it's [[Prototype]]
// is the (initial) Promise.prototype and the Promise#then protector
// is intact, as that guards the lookup path for the "then" property
@@ -700,7 +698,7 @@ Node* PromiseBuiltinsAssembler::InvokeThen(Node* native_context, Node* receiver,
BIND(&if_fast);
{
- Node* const then =
+ TNode<Object> const then =
LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
Node* const result =
CallJS(CodeFactory::CallFunction(
@@ -712,8 +710,8 @@ Node* PromiseBuiltinsAssembler::InvokeThen(Node* native_context, Node* receiver,
BIND(&if_slow);
{
- Node* const then = GetProperty(native_context, receiver,
- isolate()->factory()->then_string());
+ TNode<Object> const then = GetProperty(native_context, receiver,
+ isolate()->factory()->then_string());
Node* const result = CallJS(
CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
native_context, then, receiver, args...);
@@ -740,8 +738,8 @@ Node* PromiseBuiltinsAssembler::CallResolve(Node* native_context,
BIND(&if_fast);
{
- Node* const result = CallBuiltin(Builtins::kPromiseResolve, native_context,
- constructor, value);
+ TNode<Object> const result = CallBuiltin(
+ Builtins::kPromiseResolve, native_context, constructor, value);
GotoIfException(result, if_exception, var_exception);
var_result.Bind(result);
@@ -766,18 +764,19 @@ Node* PromiseBuiltinsAssembler::CallResolve(Node* native_context,
}
void PromiseBuiltinsAssembler::BranchIfPromiseResolveLookupChainIntact(
- Node* native_context, Node* constructor, Label* if_fast, Label* if_slow) {
+ Node* native_context, SloppyTNode<Object> constructor, Label* if_fast,
+ Label* if_slow) {
CSA_ASSERT(this, IsNativeContext(native_context));
GotoIfForceSlowPath(if_slow);
- Node* const promise_fun =
+ TNode<Object> promise_fun =
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
- GotoIfNot(WordEqual(promise_fun, constructor), if_slow);
+ GotoIfNot(TaggedEqual(promise_fun, constructor), if_slow);
Branch(IsPromiseResolveProtectorCellInvalid(), if_slow, if_fast);
}
void PromiseBuiltinsAssembler::GotoIfNotPromiseResolveLookupChainIntact(
- Node* native_context, Node* constructor, Label* if_slow) {
+ Node* native_context, SloppyTNode<Object> constructor, Label* if_slow) {
Label if_fast(this);
BranchIfPromiseResolveLookupChainIntact(native_context, constructor, &if_fast,
if_slow);
@@ -789,10 +788,10 @@ void PromiseBuiltinsAssembler::BranchIfPromiseSpeciesLookupChainIntact(
CSA_ASSERT(this, IsNativeContext(native_context));
CSA_ASSERT(this, IsJSPromiseMap(promise_map));
- Node* const promise_prototype =
+ TNode<Object> promise_prototype =
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
GotoIfForceSlowPath(if_slow);
- GotoIfNot(WordEqual(LoadMapPrototype(promise_map), promise_prototype),
+ GotoIfNot(TaggedEqual(LoadMapPrototype(promise_map), promise_prototype),
if_slow);
Branch(IsPromiseSpeciesProtectorCellInvalid(), if_slow, if_fast);
}
@@ -804,16 +803,16 @@ void PromiseBuiltinsAssembler::BranchIfPromiseThenLookupChainIntact(
GotoIfForceSlowPath(if_slow);
GotoIfNot(IsJSPromiseMap(receiver_map), if_slow);
- Node* const promise_prototype =
+ TNode<Object> const promise_prototype =
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
- GotoIfNot(WordEqual(LoadMapPrototype(receiver_map), promise_prototype),
+ GotoIfNot(TaggedEqual(LoadMapPrototype(receiver_map), promise_prototype),
if_slow);
Branch(IsPromiseThenProtectorCellInvalid(), if_slow, if_fast);
}
void PromiseBuiltinsAssembler::BranchIfAccessCheckFailed(
- Node* context, Node* native_context, Node* promise_constructor,
- Node* executor, Label* if_noaccess) {
+ SloppyTNode<Context> context, SloppyTNode<Context> native_context,
+ Node* promise_constructor, Node* executor, Label* if_noaccess) {
VARIABLE(var_executor, MachineRepresentation::kTagged);
var_executor.Bind(executor);
Label has_access(this), call_runtime(this, Label::kDeferred);
@@ -824,7 +823,7 @@ void PromiseBuiltinsAssembler::BranchIfAccessCheckFailed(
Goto(&loop_over_bound_function);
BIND(&loop_over_bound_function);
{
- Node* executor_type = LoadInstanceType(var_executor.value());
+ TNode<Uint16T> executor_type = LoadInstanceType(var_executor.value());
GotoIf(InstanceTypeEqual(executor_type, JS_FUNCTION_TYPE), &found_function);
GotoIfNot(InstanceTypeEqual(executor_type, JS_BOUND_FUNCTION_TYPE),
&call_runtime);
@@ -838,18 +837,19 @@ void PromiseBuiltinsAssembler::BranchIfAccessCheckFailed(
// out to the runtime.
BIND(&found_function);
{
- Node* function_context =
- LoadObjectField(var_executor.value(), JSFunction::kContextOffset);
- Node* native_function_context = LoadNativeContext(function_context);
- Branch(WordEqual(native_context, native_function_context), &has_access,
+ TNode<Context> function_context =
+ CAST(LoadObjectField(var_executor.value(), JSFunction::kContextOffset));
+ TNode<NativeContext> native_function_context =
+ LoadNativeContext(function_context);
+ Branch(TaggedEqual(native_context, native_function_context), &has_access,
&call_runtime);
}
BIND(&call_runtime);
{
- Branch(WordEqual(CallRuntime(Runtime::kAllowDynamicFunction, context,
- promise_constructor),
- TrueConstant()),
+ Branch(TaggedEqual(CallRuntime(Runtime::kAllowDynamicFunction, context,
+ promise_constructor),
+ TrueConstant()),
&has_access, if_noaccess);
}
@@ -888,12 +888,12 @@ TF_BUILTIN(PromiseCapabilityDefaultReject, PromiseBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
// 2. Let promise be F.[[Promise]].
- Node* const promise =
+ TNode<Object> const promise =
LoadContextElement(context, PromiseBuiltins::kPromiseSlot);
// 3. Let alreadyResolved be F.[[AlreadyResolved]].
Label if_already_resolved(this, Label::kDeferred);
- Node* const already_resolved =
+ TNode<Object> const already_resolved =
LoadContextElement(context, PromiseBuiltins::kAlreadyResolvedSlot);
// 4. If alreadyResolved.[[Value]] is true, return undefined.
@@ -904,7 +904,7 @@ TF_BUILTIN(PromiseCapabilityDefaultReject, PromiseBuiltinsAssembler) {
context, PromiseBuiltins::kAlreadyResolvedSlot, TrueConstant());
// 6. Return RejectPromise(promise, reason).
- Node* const debug_event =
+ TNode<Object> const debug_event =
LoadContextElement(context, PromiseBuiltins::kDebugEventSlot);
Return(CallBuiltin(Builtins::kRejectPromise, context, promise, reason,
debug_event));
@@ -922,12 +922,12 @@ TF_BUILTIN(PromiseCapabilityDefaultResolve, PromiseBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
// 2. Let promise be F.[[Promise]].
- Node* const promise =
+ TNode<Object> const promise =
LoadContextElement(context, PromiseBuiltins::kPromiseSlot);
// 3. Let alreadyResolved be F.[[AlreadyResolved]].
Label if_already_resolved(this, Label::kDeferred);
- Node* const already_resolved =
+ TNode<Object> const already_resolved =
LoadContextElement(context, PromiseBuiltins::kAlreadyResolvedSlot);
// 4. If alreadyResolved.[[Value]] is true, return undefined.
@@ -967,9 +967,9 @@ TF_BUILTIN(PromiseConstructorLazyDeoptContinuation, PromiseBuiltinsAssembler) {
// ES6 #sec-promise-executor
TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
- Node* const executor = Parameter(Descriptor::kExecutor);
- Node* const new_target = Parameter(Descriptor::kJSNewTarget);
- Node* const context = Parameter(Descriptor::kContext);
+ TNode<Object> executor = CAST(Parameter(Descriptor::kExecutor));
+ TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Isolate* isolate = this->isolate();
Label if_targetisundefined(this, Label::kDeferred);
@@ -980,12 +980,12 @@ TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
GotoIf(TaggedIsSmi(executor), &if_notcallable);
- Node* const executor_map = LoadMap(executor);
+ TNode<Map> const executor_map = LoadMap(CAST(executor));
GotoIfNot(IsCallableMap(executor_map), &if_notcallable);
- Node* const native_context = LoadNativeContext(context);
- Node* const promise_fun =
- LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<JSFunction> const promise_fun =
+ CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
Node* const is_debug_active = IsDebugActive();
Label if_targetisnotmodified(this),
if_targetismodified(this, Label::kDeferred), run_executor(this),
@@ -994,7 +994,7 @@ TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
BranchIfAccessCheckFailed(context, native_context, promise_fun, executor,
&if_noaccess);
- Branch(WordEqual(promise_fun, new_target), &if_targetisnotmodified,
+ Branch(TaggedEqual(promise_fun, new_target), &if_targetisnotmodified,
&if_targetismodified);
VARIABLE(var_result, MachineRepresentation::kTagged);
@@ -1011,8 +1011,8 @@ TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
BIND(&if_targetismodified);
{
ConstructorBuiltinsAssembler constructor_assembler(this->state());
- Node* const instance = constructor_assembler.EmitFastNewObject(
- context, promise_fun, new_target);
+ TNode<JSObject> instance = constructor_assembler.EmitFastNewObject(
+ context, promise_fun, CAST(new_target));
PromiseInit(instance);
var_result.Bind(instance);
@@ -1071,7 +1071,7 @@ TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) {
// Silently fail if the stack looks fishy.
BIND(&if_noaccess);
{
- Node* const counter_id =
+ TNode<Smi> const counter_id =
SmiConstant(v8::Isolate::kPromiseConstructorReturnedUndefined);
CallRuntime(Runtime::kIncrementUseCounter, context, counter_id);
Return(UndefinedConstant());
@@ -1139,17 +1139,17 @@ TF_BUILTIN(PromisePrototypeThen, PromiseBuiltinsAssembler) {
// 3. Let C be ? SpeciesConstructor(promise, %Promise%).
Label fast_promise_capability(this), slow_constructor(this, Label::kDeferred),
slow_promise_capability(this, Label::kDeferred);
- Node* const native_context = LoadNativeContext(context);
- Node* const promise_fun =
- LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
- Node* const promise_map = LoadMap(promise);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<JSFunction> promise_fun =
+ CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
+ TNode<Map> const promise_map = LoadMap(promise);
BranchIfPromiseSpeciesLookupChainIntact(
native_context, promise_map, &fast_promise_capability, &slow_constructor);
BIND(&slow_constructor);
- Node* const constructor =
+ TNode<JSReceiver> constructor =
SpeciesConstructor(native_context, promise, promise_fun);
- Branch(WordEqual(constructor, promise_fun), &fast_promise_capability,
+ Branch(TaggedEqual(constructor, promise_fun), &fast_promise_capability,
&slow_promise_capability);
// 4. Let resultCapability be ? NewPromiseCapability(C).
@@ -1167,9 +1167,9 @@ TF_BUILTIN(PromisePrototypeThen, PromiseBuiltinsAssembler) {
BIND(&slow_promise_capability);
{
- Node* const debug_event = TrueConstant();
- Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability,
- context, constructor, debug_event);
+ TNode<Oddball> const debug_event = TrueConstant();
+ TNode<PromiseCapability> const capability = CAST(CallBuiltin(
+ Builtins::kNewPromiseCapability, context, constructor, debug_event));
var_result_promise.Bind(
LoadObjectField(capability, PromiseCapability::kPromiseOffset));
var_result_promise_or_capability.Bind(capability);
@@ -1221,26 +1221,22 @@ TF_BUILTIN(PromisePrototypeThen, PromiseBuiltinsAssembler) {
TF_BUILTIN(PromisePrototypeCatch, PromiseBuiltinsAssembler) {
// 1. Let promise be the this value.
Node* const receiver = Parameter(Descriptor::kReceiver);
- Node* const on_fulfilled = UndefinedConstant();
+ TNode<Oddball> const on_fulfilled = UndefinedConstant();
Node* const on_rejected = Parameter(Descriptor::kOnRejected);
Node* const context = Parameter(Descriptor::kContext);
// 2. Return ? Invoke(promise, "then", « undefined, onRejected »).
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
Return(InvokeThen(native_context, receiver, on_fulfilled, on_rejected));
}
// ES #sec-promiseresolvethenablejob
TF_BUILTIN(PromiseResolveThenableJob, PromiseBuiltinsAssembler) {
- Node* const native_context = Parameter(Descriptor::kContext);
- Node* const promise_to_resolve = Parameter(Descriptor::kPromiseToResolve);
- Node* const thenable = Parameter(Descriptor::kThenable);
- Node* const then = Parameter(Descriptor::kThen);
-
- CSA_ASSERT(this, TaggedIsNotSmi(thenable));
- CSA_ASSERT(this, IsJSReceiver(thenable));
- CSA_ASSERT(this, IsJSPromise(promise_to_resolve));
- CSA_ASSERT(this, IsNativeContext(native_context));
+ TNode<NativeContext> native_context = CAST(Parameter(Descriptor::kContext));
+ TNode<JSPromise> promise_to_resolve =
+ CAST(Parameter(Descriptor::kPromiseToResolve));
+ TNode<JSReceiver> thenable = CAST(Parameter(Descriptor::kThenable));
+ TNode<Object> then = CAST(Parameter(Descriptor::kThen));
// We can use a simple optimization here if we know that {then} is the initial
// Promise.prototype.then method, and {thenable} is a JSPromise whose
@@ -1251,10 +1247,10 @@ TF_BUILTIN(PromiseResolveThenableJob, PromiseBuiltinsAssembler) {
// We take the generic (slow-)path if a PromiseHook is enabled or the debugger
// is active, to make sure we expose spec compliant behavior.
Label if_fast(this), if_slow(this, Label::kDeferred);
- Node* const promise_then =
+ TNode<Object> promise_then =
LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
- GotoIfNot(WordEqual(then, promise_then), &if_slow);
- Node* const thenable_map = LoadMap(thenable);
+ GotoIfNot(TaggedEqual(then, promise_then), &if_slow);
+ TNode<Map> const thenable_map = LoadMap(thenable);
GotoIfNot(IsJSPromiseMap(thenable_map), &if_slow);
GotoIf(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
&if_slow);
@@ -1379,8 +1375,8 @@ void PromiseBuiltinsAssembler::PromiseReactionJob(Node* context, Node* argument,
{
// In the general case we need to call the (user provided)
// promiseCapability.[[Resolve]] function.
- Node* const resolve = LoadObjectField(promise_or_capability,
- PromiseCapability::kResolveOffset);
+ TNode<Object> const resolve = LoadObjectField(
+ promise_or_capability, PromiseCapability::kResolveOffset);
Node* const result = CallJS(
CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
context, resolve, UndefinedConstant(), value);
@@ -1412,8 +1408,8 @@ void PromiseBuiltinsAssembler::PromiseReactionJob(Node* context, Node* argument,
Label if_exception(this, Label::kDeferred);
VARIABLE(var_exception, MachineRepresentation::kTagged,
TheHoleConstant());
- Node* const reject = LoadObjectField(promise_or_capability,
- PromiseCapability::kRejectOffset);
+ TNode<Object> const reject = LoadObjectField(
+ promise_or_capability, PromiseCapability::kRejectOffset);
Node* const result = CallJS(
CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
context, reject, UndefinedConstant(), reason);
@@ -1463,64 +1459,63 @@ TF_BUILTIN(PromiseResolveTrampoline, PromiseBuiltinsAssembler) {
// 1. Let C be the this value.
Node* receiver = Parameter(Descriptor::kReceiver);
Node* value = Parameter(Descriptor::kValue);
- Node* context = Parameter(Descriptor::kContext);
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// 2. If Type(C) is not Object, throw a TypeError exception.
- ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
- "PromiseResolve");
+ ThrowIfNotJSReceiver(context, CAST(receiver),
+ MessageTemplate::kCalledOnNonObject, "PromiseResolve");
// 3. Return ? PromiseResolve(C, x).
Return(CallBuiltin(Builtins::kPromiseResolve, context, receiver, value));
}
TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
- Node* constructor = Parameter(Descriptor::kConstructor);
- Node* value = Parameter(Descriptor::kValue);
- Node* context = Parameter(Descriptor::kContext);
-
- CSA_ASSERT(this, IsJSReceiver(constructor));
+ TNode<JSReceiver> constructor = CAST(Parameter(Descriptor::kConstructor));
+ TNode<Object> value = CAST(Parameter(Descriptor::kValue));
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* const native_context = LoadNativeContext(context);
- Node* const promise_fun =
- LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> promise_fun =
+ CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
Label if_slow_constructor(this, Label::kDeferred), if_need_to_allocate(this);
// Check if {value} is a JSPromise.
GotoIf(TaggedIsSmi(value), &if_need_to_allocate);
- Node* const value_map = LoadMap(value);
+ TNode<Map> const value_map = LoadMap(CAST(value));
GotoIfNot(IsJSPromiseMap(value_map), &if_need_to_allocate);
// We can skip the "constructor" lookup on {value} if it's [[Prototype]]
// is the (initial) Promise.prototype and the @@species protector is
// intact, as that guards the lookup path for "constructor" on
// JSPromise instances which have the (initial) Promise.prototype.
- Node* const promise_prototype =
+ TNode<Object> promise_prototype =
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
- GotoIfNot(WordEqual(LoadMapPrototype(value_map), promise_prototype),
+ GotoIfNot(TaggedEqual(LoadMapPrototype(value_map), promise_prototype),
&if_slow_constructor);
GotoIf(IsPromiseSpeciesProtectorCellInvalid(), &if_slow_constructor);
// If the {constructor} is the Promise function, we just immediately
// return the {value} here and don't bother wrapping it into a
// native Promise.
- GotoIfNot(WordEqual(promise_fun, constructor), &if_slow_constructor);
+ GotoIfNot(TaggedEqual(promise_fun, constructor), &if_slow_constructor);
Return(value);
// At this point, value or/and constructor are not native promises, but
// they could be of the same subclass.
BIND(&if_slow_constructor);
{
- Node* const value_constructor =
+ TNode<Object> value_constructor =
GetProperty(context, value, isolate()->factory()->constructor_string());
- GotoIfNot(WordEqual(value_constructor, constructor), &if_need_to_allocate);
+ GotoIfNot(TaggedEqual(value_constructor, constructor),
+ &if_need_to_allocate);
Return(value);
}
BIND(&if_need_to_allocate);
{
Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred);
- Branch(WordEqual(promise_fun, constructor), &if_nativepromise,
+ Branch(TaggedEqual(promise_fun, constructor), &if_nativepromise,
&if_notnativepromise);
// This adds a fast path for native promises that don't need to
@@ -1534,17 +1529,17 @@ TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
BIND(&if_notnativepromise);
{
- Node* const debug_event = TrueConstant();
- Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability,
- context, constructor, debug_event);
+ TNode<Oddball> const debug_event = TrueConstant();
+ TNode<PromiseCapability> const capability = CAST(CallBuiltin(
+ Builtins::kNewPromiseCapability, context, constructor, debug_event));
- Node* const resolve =
+ TNode<Object> const resolve =
LoadObjectField(capability, PromiseCapability::kResolveOffset);
CallJS(
CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
context, resolve, UndefinedConstant(), value);
- Node* const result =
+ TNode<Object> const result =
LoadObjectField(capability, PromiseCapability::kPromiseOffset);
Return(result);
}
@@ -1557,8 +1552,8 @@ TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
Node* const reject = Parameter(Descriptor::kReject);
Node* const context = Parameter(Descriptor::kContext);
- Node* const capability =
- LoadContextElement(context, PromiseBuiltins::kCapabilitySlot);
+ TNode<PromiseCapability> const capability =
+ CAST(LoadContextElement(context, PromiseBuiltins::kCapabilitySlot));
Label if_alreadyinvoked(this, Label::kDeferred);
GotoIfNot(IsUndefined(
@@ -1579,20 +1574,20 @@ TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
// 1. Let C be the this value.
- Node* const receiver = Parameter(Descriptor::kReceiver);
- Node* const reason = Parameter(Descriptor::kReason);
- Node* const context = Parameter(Descriptor::kContext);
+ TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
+ TNode<Object> reason = CAST(Parameter(Descriptor::kReason));
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// 2. If Type(C) is not Object, throw a TypeError exception.
ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
"PromiseReject");
Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
- Node* const promise_fun =
+ TNode<Object> promise_fun =
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
- Branch(WordEqual(promise_fun, receiver), &if_nativepromise,
+ Branch(TaggedEqual(promise_fun, receiver), &if_nativepromise,
&if_custompromise);
BIND(&if_nativepromise);
@@ -1607,18 +1602,18 @@ TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
BIND(&if_custompromise);
{
// 3. Let promiseCapability be ? NewPromiseCapability(C).
- Node* const debug_event = TrueConstant();
- Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability,
- context, receiver, debug_event);
+ TNode<Oddball> const debug_event = TrueConstant();
+ TNode<PromiseCapability> const capability = CAST(CallBuiltin(
+ Builtins::kNewPromiseCapability, context, receiver, debug_event));
// 4. Perform ? Call(promiseCapability.[[Reject]], undefined, « r »).
- Node* const reject =
+ TNode<Object> const reject =
LoadObjectField(capability, PromiseCapability::kRejectOffset);
CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
context, reject, UndefinedConstant(), reason);
// 5. Return promiseCapability.[[Promise]].
- Node* const promise =
+ TNode<Object> const promise =
LoadObjectField(capability, PromiseCapability::kPromiseOffset);
Return(promise);
}
@@ -1632,13 +1627,13 @@ std::pair<Node*, Node*> PromiseBuiltinsAssembler::CreatePromiseFinallyFunctions(
promise_context, PromiseBuiltins::kOnFinallySlot, on_finally);
StoreContextElementNoWriteBarrier(
promise_context, PromiseBuiltins::kConstructorSlot, constructor);
- Node* const map = LoadContextElement(
+ TNode<Object> const map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
- Node* const then_finally_info = LoadContextElement(
+ TNode<Object> const then_finally_info = LoadContextElement(
native_context, Context::PROMISE_THEN_FINALLY_SHARED_FUN);
Node* const then_finally = AllocateFunctionWithMapAndContext(
map, then_finally_info, promise_context);
- Node* const catch_finally_info = LoadContextElement(
+ TNode<Object> const catch_finally_info = LoadContextElement(
native_context, Context::PROMISE_CATCH_FINALLY_SHARED_FUN);
Node* const catch_finally = AllocateFunctionWithMapAndContext(
map, catch_finally_info, promise_context);
@@ -1648,7 +1643,8 @@ std::pair<Node*, Node*> PromiseBuiltinsAssembler::CreatePromiseFinallyFunctions(
TF_BUILTIN(PromiseValueThunkFinally, PromiseBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
- Node* const value = LoadContextElement(context, PromiseBuiltins::kValueSlot);
+ TNode<Object> const value =
+ LoadContextElement(context, PromiseBuiltins::kValueSlot);
Return(value);
}
@@ -1658,9 +1654,9 @@ Node* PromiseBuiltinsAssembler::CreateValueThunkFunction(Node* value,
native_context, PromiseBuiltins::kPromiseValueThunkOrReasonContextLength);
StoreContextElementNoWriteBarrier(value_thunk_context,
PromiseBuiltins::kValueSlot, value);
- Node* const map = LoadContextElement(
+ TNode<Object> const map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
- Node* const value_thunk_info = LoadContextElement(
+ TNode<Object> const value_thunk_info = LoadContextElement(
native_context, Context::PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN);
Node* const value_thunk = AllocateFunctionWithMapAndContext(
map, value_thunk_info, value_thunk_context);
@@ -1674,8 +1670,8 @@ TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
// 1. Let onFinally be F.[[OnFinally]].
- Node* const on_finally =
- LoadContextElement(context, PromiseBuiltins::kOnFinallySlot);
+ TNode<HeapObject> const on_finally =
+ CAST(LoadContextElement(context, PromiseBuiltins::kOnFinallySlot));
// 2. Assert: IsCallable(onFinally) is true.
CSA_ASSERT(this, IsCallable(on_finally));
@@ -1686,18 +1682,18 @@ TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) {
context, on_finally, UndefinedConstant());
// 4. Let C be F.[[Constructor]].
- Node* const constructor =
- LoadContextElement(context, PromiseBuiltins::kConstructorSlot);
+ TNode<JSFunction> const constructor =
+ CAST(LoadContextElement(context, PromiseBuiltins::kConstructorSlot));
// 5. Assert: IsConstructor(C) is true.
CSA_ASSERT(this, IsConstructor(constructor));
// 6. Let promise be ? PromiseResolve(C, result).
- Node* const promise =
- CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
+ TNode<Object> const promise =
+ CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
// 7. Let valueThunk be equivalent to a function that returns value.
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
Node* const value_thunk = CreateValueThunkFunction(value, native_context);
// 8. Return ? Invoke(promise, "then", « valueThunk »).
@@ -1707,7 +1703,8 @@ TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) {
TF_BUILTIN(PromiseThrowerFinally, PromiseBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
- Node* const reason = LoadContextElement(context, PromiseBuiltins::kValueSlot);
+ TNode<Object> const reason =
+ LoadContextElement(context, PromiseBuiltins::kValueSlot);
CallRuntime(Runtime::kThrow, context, reason);
Unreachable();
}
@@ -1718,9 +1715,9 @@ Node* PromiseBuiltinsAssembler::CreateThrowerFunction(Node* reason,
native_context, PromiseBuiltins::kPromiseValueThunkOrReasonContextLength);
StoreContextElementNoWriteBarrier(thrower_context,
PromiseBuiltins::kValueSlot, reason);
- Node* const map = LoadContextElement(
+ TNode<Object> const map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
- Node* const thrower_info = LoadContextElement(
+ TNode<Object> const thrower_info = LoadContextElement(
native_context, Context::PROMISE_THROWER_FINALLY_SHARED_FUN);
Node* const thrower =
AllocateFunctionWithMapAndContext(map, thrower_info, thrower_context);
@@ -1734,8 +1731,8 @@ TF_BUILTIN(PromiseCatchFinally, PromiseBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
// 1. Let onFinally be F.[[OnFinally]].
- Node* const on_finally =
- LoadContextElement(context, PromiseBuiltins::kOnFinallySlot);
+ TNode<HeapObject> const on_finally =
+ CAST(LoadContextElement(context, PromiseBuiltins::kOnFinallySlot));
// 2. Assert: IsCallable(onFinally) is true.
CSA_ASSERT(this, IsCallable(on_finally));
@@ -1746,18 +1743,18 @@ TF_BUILTIN(PromiseCatchFinally, PromiseBuiltinsAssembler) {
context, on_finally, UndefinedConstant());
// 4. Let C be F.[[Constructor]].
- Node* const constructor =
- LoadContextElement(context, PromiseBuiltins::kConstructorSlot);
+ TNode<JSFunction> const constructor =
+ CAST(LoadContextElement(context, PromiseBuiltins::kConstructorSlot));
// 5. Assert: IsConstructor(C) is true.
CSA_ASSERT(this, IsConstructor(constructor));
// 6. Let promise be ? PromiseResolve(C, result).
- Node* const promise =
- CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
+ TNode<Object> const promise =
+ CallBuiltin(Builtins::kPromiseResolve, context, constructor, result);
// 7. Let thrower be equivalent to a function that throws reason.
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
Node* const thrower = CreateThrowerFunction(reason, native_context);
// 8. Return ? Invoke(promise, "then", « thrower »).
@@ -1770,26 +1767,27 @@ TF_BUILTIN(PromisePrototypeFinally, PromiseBuiltinsAssembler) {
// 1. Let promise be the this value.
Node* const receiver = Parameter(Descriptor::kReceiver);
Node* const on_finally = Parameter(Descriptor::kOnFinally);
- Node* const context = Parameter(Descriptor::kContext);
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// 2. If Type(promise) is not Object, throw a TypeError exception.
- ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
+ ThrowIfNotJSReceiver(context, CAST(receiver),
+ MessageTemplate::kCalledOnNonObject,
"Promise.prototype.finally");
// 3. Let C be ? SpeciesConstructor(promise, %Promise%).
- Node* const native_context = LoadNativeContext(context);
- Node* const promise_fun =
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const promise_fun =
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
VARIABLE(var_constructor, MachineRepresentation::kTagged, promise_fun);
Label slow_constructor(this, Label::kDeferred), done_constructor(this);
- Node* const receiver_map = LoadMap(receiver);
+ TNode<Map> const receiver_map = LoadMap(receiver);
GotoIfNot(IsJSPromiseMap(receiver_map), &slow_constructor);
BranchIfPromiseSpeciesLookupChainIntact(native_context, receiver_map,
&done_constructor, &slow_constructor);
BIND(&slow_constructor);
{
- Node* const constructor =
- SpeciesConstructor(context, receiver, promise_fun);
+ TNode<JSReceiver> const constructor =
+ SpeciesConstructor(context, receiver, CAST(promise_fun));
var_constructor.Bind(constructor);
Goto(&done_constructor);
}
@@ -1819,7 +1817,7 @@ TF_BUILTIN(PromisePrototypeFinally, PromiseBuiltinsAssembler) {
Node* then_finally = nullptr;
Node* catch_finally = nullptr;
std::tie(then_finally, catch_finally) =
- CreatePromiseFinallyFunctions(on_finally, constructor, native_context);
+ CreatePromiseFinallyFunctions(on_finally, constructor, native_context);
var_then_finally.Bind(then_finally);
var_catch_finally.Bind(catch_finally);
Goto(&perform_finally);
@@ -1850,7 +1848,7 @@ TF_BUILTIN(FulfillPromise, PromiseBuiltinsAssembler) {
CSA_ASSERT(this, IsJSPromise(promise));
// 2. Let reactions be promise.[[PromiseFulfillReactions]].
- Node* const reactions =
+ TNode<Object> const reactions =
LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
// 3. Set promise.[[PromiseResult]] to value.
@@ -1892,7 +1890,7 @@ TF_BUILTIN(RejectPromise, PromiseBuiltinsAssembler) {
GotoIfNot(PromiseHasHandler(promise), &if_runtime);
// 2. Let reactions be promise.[[PromiseRejectReactions]].
- Node* reactions =
+ TNode<Object> reactions =
LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
// 3. Set promise.[[PromiseResult]] to reason.
@@ -1914,17 +1912,14 @@ TF_BUILTIN(RejectPromise, PromiseBuiltinsAssembler) {
// ES #sec-promise-resolve-functions
TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
- Node* const promise = Parameter(Descriptor::kPromise);
- Node* const resolution = Parameter(Descriptor::kResolution);
- Node* const context = Parameter(Descriptor::kContext);
-
- CSA_ASSERT(this, TaggedIsNotSmi(promise));
- CSA_ASSERT(this, IsJSPromise(promise));
+ TNode<JSPromise> const promise = CAST(Parameter(Descriptor::kPromise));
+ TNode<Object> const resolution = CAST(Parameter(Descriptor::kResolution));
+ TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
Label do_enqueue(this), if_fulfill(this), if_reject(this, Label::kDeferred),
if_runtime(this, Label::kDeferred);
- VARIABLE(var_reason, MachineRepresentation::kTagged);
- VARIABLE(var_then, MachineRepresentation::kTagged);
+ TVARIABLE(Object, var_reason);
+ TVARIABLE(Object, var_then);
// If promise hook is enabled or the debugger is active, let
// the runtime handle this operation, which greatly reduces
@@ -1936,11 +1931,11 @@ TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
// 6. If SameValue(resolution, promise) is true, then
// We can use pointer comparison here, since the {promise} is guaranteed
// to be a JSPromise inside this function and thus is reference comparable.
- GotoIf(WordEqual(promise, resolution), &if_runtime);
+ GotoIf(TaggedEqual(promise, resolution), &if_runtime);
// 7. If Type(resolution) is not Object, then
GotoIf(TaggedIsSmi(resolution), &if_fulfill);
- Node* const resolution_map = LoadMap(resolution);
+ TNode<Map> resolution_map = LoadMap(CAST(resolution));
GotoIfNot(IsJSReceiverMap(resolution_map), &if_fulfill);
// We can skip the "then" lookup on {resolution} if its [[Prototype]]
@@ -1948,21 +1943,19 @@ TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
// is intact, as that guards the lookup path for the "then" property
// on JSPromise instances which have the (initial) %PromisePrototype%.
Label if_fast(this), if_receiver(this), if_slow(this, Label::kDeferred);
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
GotoIfForceSlowPath(&if_slow);
GotoIf(IsPromiseThenProtectorCellInvalid(), &if_slow);
GotoIfNot(IsJSPromiseMap(resolution_map), &if_receiver);
- Node* const promise_prototype =
+ TNode<Object> const promise_prototype =
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
- Branch(WordEqual(LoadMapPrototype(resolution_map), promise_prototype),
+ Branch(TaggedEqual(LoadMapPrototype(resolution_map), promise_prototype),
&if_fast, &if_slow);
BIND(&if_fast);
{
// The {resolution} is a native Promise in this case.
- Node* const then =
- LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
- var_then.Bind(then);
+ var_then = LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
Goto(&do_enqueue);
}
@@ -1975,16 +1968,16 @@ TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
// results from async generators.
CSA_ASSERT(this, IsJSReceiverMap(resolution_map));
CSA_ASSERT(this, Word32BinaryNot(IsPromiseThenProtectorCellInvalid()));
- Node* const iterator_result_map =
+ TNode<Object> const iterator_result_map =
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
- Branch(WordEqual(resolution_map, iterator_result_map), &if_fulfill,
+ Branch(TaggedEqual(resolution_map, iterator_result_map), &if_fulfill,
&if_slow);
}
BIND(&if_slow);
{
// 8. Let then be Get(resolution, "then").
- Node* const then =
+ TNode<Object> then =
GetProperty(context, resolution, isolate()->factory()->then_string());
// 9. If then is an abrupt completion, then
@@ -1992,9 +1985,9 @@ TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
// 11. If IsCallable(thenAction) is false, then
GotoIf(TaggedIsSmi(then), &if_fulfill);
- Node* const then_map = LoadMap(then);
+ TNode<Map> const then_map = LoadMap(CAST(then));
GotoIfNot(IsCallableMap(then_map), &if_fulfill);
- var_then.Bind(then);
+ var_then = then;
Goto(&do_enqueue);
}
@@ -2032,7 +2025,7 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
Label* if_exception, Variable* var_exception) {
IteratorBuiltinsAssembler iter_assembler(state());
- TNode<NativeContext> native_context = Cast(LoadNativeContext(context));
+ TNode<NativeContext> native_context = LoadNativeContext(context);
// For catch prediction, don't treat the .then calls as handling it;
// instead, recurse outwards.
@@ -2120,9 +2113,9 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
// Set resolveElement.[[Values]] to values.
// Set resolveElement.[[Capability]] to resultCapability.
// Set resolveElement.[[RemainingElements]] to remainingElementsCount.
- Node* const resolve_element_fun = create_resolve_element_function(
+ TNode<Object> const resolve_element_fun = create_resolve_element_function(
resolve_element_context, index, native_context, Cast(capability));
- Node* const reject_element_fun = create_reject_element_function(
+ TNode<Object> const reject_element_fun = create_reject_element_function(
resolve_element_context, index, native_context, Cast(capability));
// We can skip the "resolve" lookup on the {constructor} as well as the
@@ -2148,7 +2141,7 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
&if_slow);
GotoIf(IsPromiseSpeciesProtectorCellInvalid(), &if_slow);
GotoIf(TaggedIsSmi(next_value), &if_slow);
- Node* const next_value_map = LoadMap(CAST(next_value));
+ TNode<Map> const next_value_map = LoadMap(CAST(next_value));
BranchIfPromiseThenLookupChainIntact(native_context, next_value_map,
&if_fast, &if_slow);
@@ -2172,7 +2165,7 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
// Perform ? Invoke(nextPromise, "then", « resolveElement,
// resultCapability.[[Reject]] »).
- Node* const then =
+ TNode<Object> const then =
GetProperty(native_context, next_promise, factory()->then_string());
GotoIfException(then, &close_iterator, var_exception);
@@ -2205,7 +2198,7 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
// function and pass the larger indices via a separate context, but it
// doesn't seem likely that we need this, and it's unclear how the rest
// of the system deals with 2**21 live Promises anyways.
- Node* const result =
+ TNode<Object> const result =
CallRuntime(Runtime::kThrowRangeError, native_context,
SmiConstant(MessageTemplate::kTooManyElementsInPromiseAll));
GotoIfException(result, &close_iterator, var_exception);
@@ -2241,14 +2234,14 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
// capacity here. We may already have elements here in case of some
// fancy Thenable that calls the resolve callback immediately, so we need
// to handle that correctly here.
- Node* const values_array = LoadContextElement(
+ TNode<JSArray> const values_array = CAST(LoadContextElement(
resolve_element_context,
- PromiseBuiltins::kPromiseAllResolveElementValuesArraySlot);
- Node* const old_elements = LoadElements(values_array);
+ PromiseBuiltins::kPromiseAllResolveElementValuesArraySlot));
+ TNode<FixedArrayBase> const old_elements = LoadElements(values_array);
TNode<Smi> const old_capacity = LoadFixedArrayBaseLength(old_elements);
TNode<Smi> const new_capacity = var_index.value();
GotoIf(SmiGreaterThanOrEqual(old_capacity, new_capacity), &return_promise);
- Node* const new_elements =
+ TNode<FixedArrayBase> const new_elements =
AllocateFixedArray(PACKED_ELEMENTS, new_capacity, SMI_PARAMETERS,
AllocationFlag::kAllowLargeObjectAllocation);
CopyFixedArrayElements(PACKED_ELEMENTS, old_elements, PACKED_ELEMENTS,
@@ -2263,9 +2256,9 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
// « valuesArray »).
BIND(&resolve_promise);
{
- Node* const resolve =
+ TNode<Object> const resolve =
LoadObjectField(capability, PromiseCapability::kResolveOffset);
- Node* const values_array = LoadContextElement(
+ TNode<Object> const values_array = LoadContextElement(
resolve_element_context,
PromiseBuiltins::kPromiseAllResolveElementValuesArraySlot);
Node* const resolve_call = CallJS(
@@ -2279,7 +2272,7 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
BIND(&return_promise);
}
- Node* const promise =
+ TNode<Object> const promise =
LoadObjectField(capability, PromiseCapability::kPromiseOffset);
return promise;
}
@@ -2298,9 +2291,9 @@ void PromiseBuiltinsAssembler::Generate_PromiseAll(
// Let promiseCapability be ? NewPromiseCapability(C).
// Don't fire debugEvent so that forwarding the rejection through all does not
// trigger redundant ExceptionEvents
- Node* const debug_event = FalseConstant();
- Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability, context,
- receiver, debug_event);
+ TNode<Oddball> const debug_event = FalseConstant();
+ TNode<PromiseCapability> const capability = CAST(CallBuiltin(
+ Builtins::kNewPromiseCapability, context, receiver, debug_event));
VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
Label reject_promise(this, &var_exception, Label::kDeferred);
@@ -2325,12 +2318,12 @@ void PromiseBuiltinsAssembler::Generate_PromiseAll(
{
// Exception must be bound to a JS value.
CSA_SLOW_ASSERT(this, IsNotTheHole(var_exception.value()));
- Node* const reject =
+ TNode<Object> const reject =
LoadObjectField(capability, PromiseCapability::kRejectOffset);
CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
context, reject, UndefinedConstant(), var_exception.value());
- Node* const promise =
+ TNode<Object> const promise =
LoadObjectField(capability, PromiseCapability::kPromiseOffset);
Return(promise);
}
@@ -2397,7 +2390,7 @@ void PromiseBuiltinsAssembler::Generate_PromiseAllResolveElementClosure(
this,
SmiEqual(LoadObjectField<Smi>(context, Context::kLengthOffset),
SmiConstant(PromiseBuiltins::kPromiseAllResolveElementLength)));
- TNode<NativeContext> native_context = Cast(LoadNativeContext(context));
+ TNode<NativeContext> native_context = LoadNativeContext(context);
StoreObjectField(function, JSFunction::kContextOffset, native_context);
// Update the value depending on whether Promise.all or
@@ -2578,19 +2571,19 @@ TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
Node* const receiver = Parameter(Descriptor::kReceiver);
TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
- ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
- "Promise.race");
+ ThrowIfNotJSReceiver(context, CAST(receiver),
+ MessageTemplate::kCalledOnNonObject, "Promise.race");
// Let promiseCapability be ? NewPromiseCapability(C).
// Don't fire debugEvent so that forwarding the rejection through all does not
// trigger redundant ExceptionEvents
- Node* const debug_event = FalseConstant();
- Node* const capability = CallBuiltin(Builtins::kNewPromiseCapability, context,
- receiver, debug_event);
+ TNode<Oddball> const debug_event = FalseConstant();
+ TNode<PromiseCapability> const capability = CAST(CallBuiltin(
+ Builtins::kNewPromiseCapability, context, receiver, debug_event));
- Node* const resolve =
+ TNode<Object> const resolve =
LoadObjectField(capability, PromiseCapability::kResolveOffset);
- Node* const reject =
+ TNode<Object> const reject =
LoadObjectField(capability, PromiseCapability::kRejectOffset);
Label close_iterator(this, Label::kDeferred);
@@ -2613,7 +2606,7 @@ TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
// as that guards the lookup path for the "resolve" property on the
// Promise constructor.
Label loop(this), break_loop(this), if_slow(this, Label::kDeferred);
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TVARIABLE(Object, var_promise_resolve_function, UndefinedConstant());
GotoIfNotPromiseResolveLookupChainIntact(native_context, receiver,
&if_slow);
@@ -2662,7 +2655,7 @@ TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
// Perform ? Invoke(nextPromise, "then", « resolveElement,
// resultCapability.[[Reject]] »).
- Node* const then =
+ TNode<Object> const then =
GetProperty(context, next_promise, factory()->then_string());
GotoIfException(then, &close_iterator, &var_exception);
@@ -2694,12 +2687,12 @@ TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
BIND(&reject_promise);
{
- Node* const reject =
+ TNode<Object> const reject =
LoadObjectField(capability, PromiseCapability::kRejectOffset);
CallJS(CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
context, reject, UndefinedConstant(), var_exception.value());
- Node* const promise =
+ TNode<Object> const promise =
LoadObjectField(capability, PromiseCapability::kPromiseOffset);
Return(promise);
}
diff --git a/deps/v8/src/builtins/builtins-promise-gen.h b/deps/v8/src/builtins/builtins-promise-gen.h
index 71443ca920..633e3321aa 100644
--- a/deps/v8/src/builtins/builtins-promise-gen.h
+++ b/deps/v8/src/builtins/builtins-promise-gen.h
@@ -35,9 +35,6 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
Node* AllocatePromiseReaction(Node* next, Node* promise_or_capability,
Node* fulfill_handler, Node* reject_handler);
- Node* AllocatePromiseReactionJobTask(RootIndex map_root_index, Node* context,
- Node* argument, Node* handler,
- Node* promise_or_capability);
Node* AllocatePromiseReactionJobTask(Node* map, Node* context, Node* argument,
Node* handler,
Node* promise_or_capability);
@@ -91,10 +88,10 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
// that guards the lookup path for the "resolve" property on the %Promise%
// intrinsic object.
void BranchIfPromiseResolveLookupChainIntact(Node* native_context,
- Node* constructor,
+ SloppyTNode<Object> constructor,
Label* if_fast, Label* if_slow);
void GotoIfNotPromiseResolveLookupChainIntact(Node* native_context,
- Node* constructor,
+ SloppyTNode<Object> constructor,
Label* if_slow);
// We can shortcut the SpeciesConstructor on {promise_map} if it's
@@ -120,7 +117,8 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
template <typename... TArgs>
Node* InvokeThen(Node* native_context, Node* receiver, TArgs... args);
- void BranchIfAccessCheckFailed(Node* context, Node* native_context,
+ void BranchIfAccessCheckFailed(SloppyTNode<Context> context,
+ SloppyTNode<Context> native_context,
Node* promise_constructor, Node* executor,
Label* if_noaccess);
@@ -153,13 +151,14 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
void SetPromiseHandledByIfTrue(Node* context, Node* condition, Node* promise,
const NodeGenerator& handled_by);
- Node* PromiseStatus(Node* promise);
+ TNode<Word32T> PromiseStatus(Node* promise);
void PromiseReactionJob(Node* context, Node* argument, Node* handler,
Node* promise_or_capability,
PromiseReaction::Type type);
- Node* IsPromiseStatus(Node* actual, v8::Promise::PromiseState expected);
+ TNode<BoolT> IsPromiseStatus(TNode<Word32T> actual,
+ v8::Promise::PromiseState expected);
void PromiseSetStatus(Node* promise, v8::Promise::PromiseState status);
Node* AllocateJSPromise(Node* context);
diff --git a/deps/v8/src/builtins/builtins-proxy-gen.cc b/deps/v8/src/builtins/builtins-proxy-gen.cc
index 948540ea5f..bb1137735c 100644
--- a/deps/v8/src/builtins/builtins-proxy-gen.cc
+++ b/deps/v8/src/builtins/builtins-proxy-gen.cc
@@ -8,6 +8,7 @@
#include "src/builtins/builtins.h"
#include "src/logging/counters.h"
+#include "src/objects/js-proxy.h"
#include "src/objects/objects-inl.h"
namespace v8 {
@@ -21,7 +22,7 @@ compiler::TNode<JSProxy> ProxiesCodeStubAssembler::AllocateProxy(
Label callable_target(this), constructor_target(this), none_target(this),
create_proxy(this);
- Node* nativeContext = LoadNativeContext(context);
+ TNode<NativeContext> nativeContext = LoadNativeContext(context);
Branch(IsCallable(target), &callable_target, &none_target);
@@ -47,7 +48,7 @@ compiler::TNode<JSProxy> ProxiesCodeStubAssembler::AllocateProxy(
}
BIND(&create_proxy);
- Node* proxy = Allocate(JSProxy::kSize);
+ TNode<HeapObject> proxy = Allocate(JSProxy::kSize);
StoreMapNoWriteBarrier(proxy, map.value());
StoreObjectFieldRoot(proxy, JSProxy::kPropertiesOrHashOffset,
RootIndex::kEmptyPropertyDictionary);
@@ -69,8 +70,8 @@ Node* ProxiesCodeStubAssembler::AllocateJSArrayForCodeStubArguments(
GotoIf(SmiEqual(length, SmiConstant(0)), &if_empty_array);
{
Label if_large_object(this, Label::kDeferred);
- Node* allocated_elements = AllocateFixedArray(PACKED_ELEMENTS, argc, mode,
- kAllowLargeObjectAllocation);
+ TNode<FixedArrayBase> allocated_elements = AllocateFixedArray(
+ PACKED_ELEMENTS, argc, mode, kAllowLargeObjectAllocation);
elements.Bind(allocated_elements);
TVARIABLE(IntPtrT, offset,
@@ -104,7 +105,7 @@ Node* ProxiesCodeStubAssembler::AllocateJSArrayForCodeStubArguments(
BIND(&allocate_js_array);
// Allocate the result JSArray.
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> array_map =
LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
TNode<JSArray> array =
@@ -115,23 +116,24 @@ Node* ProxiesCodeStubAssembler::AllocateJSArrayForCodeStubArguments(
Node* ProxiesCodeStubAssembler::CreateProxyRevokeFunctionContext(
Node* proxy, Node* native_context) {
- Node* const context = Allocate(FixedArray::SizeFor(kProxyContextLength));
+ TNode<HeapObject> const context =
+ Allocate(FixedArray::SizeFor(kProxyContextLength));
StoreMapNoWriteBarrier(context, RootIndex::kFunctionContextMap);
InitializeFunctionContext(native_context, context, kProxyContextLength);
- StoreContextElementNoWriteBarrier(context, kProxySlot, proxy);
+ StoreContextElementNoWriteBarrier(CAST(context), kProxySlot, proxy);
return context;
}
compiler::TNode<JSFunction>
ProxiesCodeStubAssembler::AllocateProxyRevokeFunction(TNode<Context> context,
TNode<JSProxy> proxy) {
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
Node* const proxy_context =
CreateProxyRevokeFunctionContext(proxy, native_context);
- Node* const revoke_map = LoadContextElement(
+ TNode<Object> const revoke_map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
- Node* const revoke_info =
+ TNode<Object> const revoke_info =
LoadContextElement(native_context, Context::PROXY_REVOKE_SHARED_FUN);
return CAST(AllocateFunctionWithMapAndContext(revoke_map, revoke_info,
@@ -140,11 +142,10 @@ ProxiesCodeStubAssembler::AllocateProxyRevokeFunction(TNode<Context> context,
TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
Node* argc = Parameter(Descriptor::kActualArgumentsCount);
- Node* argc_ptr = ChangeInt32ToIntPtr(argc);
- Node* proxy = Parameter(Descriptor::kFunction);
+ TNode<IntPtrT> argc_ptr = ChangeInt32ToIntPtr(argc);
+ TNode<JSProxy> proxy = CAST(Parameter(Descriptor::kFunction));
Node* context = Parameter(Descriptor::kContext);
- CSA_ASSERT(this, IsJSProxy(proxy));
CSA_ASSERT(this, IsCallable(proxy));
PerformStackCheck(CAST(context));
@@ -153,7 +154,8 @@ TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
trap_undefined(this);
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
- Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
+ TNode<HeapObject> handler =
+ CAST(LoadObjectField(proxy, JSProxy::kHandlerOffset));
// 2. If handler is null, throw a TypeError exception.
CSA_ASSERT(this, IsNullOrJSReceiver(handler));
@@ -163,7 +165,7 @@ TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
CSA_ASSERT(this, IsJSReceiver(handler));
// 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
- Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
+ TNode<Object> target = LoadObjectField(proxy, JSProxy::kTargetOffset);
// 5. Let trap be ? GetMethod(handler, "apply").
// 6. If trap is undefined, then
@@ -171,7 +173,7 @@ TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
CodeStubArguments args(this, argc_ptr);
- Node* receiver = args.GetReceiver();
+ TNode<Object> receiver = args.GetReceiver();
// 7. Let argArray be CreateArrayFromList(argumentsList).
Node* array = AllocateJSArrayForCodeStubArguments(context, args, argc_ptr,
@@ -194,7 +196,7 @@ TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
TF_BUILTIN(ConstructProxy, ProxiesCodeStubAssembler) {
Node* argc = Parameter(Descriptor::kActualArgumentsCount);
- Node* argc_ptr = ChangeInt32ToIntPtr(argc);
+ TNode<IntPtrT> argc_ptr = ChangeInt32ToIntPtr(argc);
Node* proxy = Parameter(Descriptor::kTarget);
Node* new_target = Parameter(Descriptor::kNewTarget);
Node* context = Parameter(Descriptor::kContext);
@@ -206,7 +208,8 @@ TF_BUILTIN(ConstructProxy, ProxiesCodeStubAssembler) {
trap_undefined(this), not_an_object(this, Label::kDeferred);
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
- Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
+ TNode<HeapObject> handler =
+ CAST(LoadObjectField(proxy, JSProxy::kHandlerOffset));
// 2. If handler is null, throw a TypeError exception.
CSA_ASSERT(this, IsNullOrJSReceiver(handler));
@@ -216,7 +219,7 @@ TF_BUILTIN(ConstructProxy, ProxiesCodeStubAssembler) {
CSA_ASSERT(this, IsJSReceiver(handler));
// 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
- Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
+ TNode<Object> target = LoadObjectField(proxy, JSProxy::kTargetOffset);
// 5. Let trap be ? GetMethod(handler, "construct").
// 6. If trap is undefined, then
@@ -248,7 +251,7 @@ TF_BUILTIN(ConstructProxy, ProxiesCodeStubAssembler) {
BIND(&trap_undefined);
{
// 6.a. Assert: target has a [[Construct]] internal method.
- CSA_ASSERT(this, IsConstructor(target));
+ CSA_ASSERT(this, IsConstructor(CAST(target)));
// 6.b. Return ? Construct(target, argumentsList, newTarget).
TailCallStub(CodeFactory::Construct(isolate()), context, target, new_target,
@@ -264,7 +267,7 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
TNode<Name> name, TNode<Object> trap_result,
JSProxy::AccessKind access_kind) {
// TODO(mslekova): Think of a better name for the trap_result param.
- Node* map = LoadMap(target);
+ TNode<Map> map = LoadMap(target);
VARIABLE(var_value, MachineRepresentation::kTagged);
VARIABLE(var_details, MachineRepresentation::kWord32);
VARIABLE(var_raw_value, MachineRepresentation::kTagged);
@@ -273,7 +276,7 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
check_passed(this);
GotoIfNot(IsUniqueNameNoIndex(name), &check_in_runtime);
- Node* instance_type = LoadInstanceType(target);
+ TNode<Uint16T> instance_type = LoadInstanceType(target);
TryGetOwnProperty(context, target, target, map, instance_type, name,
&if_found_value, &var_value, &var_details, &var_raw_value,
&check_passed, &check_in_runtime, kReturnAccessorPair);
@@ -296,8 +299,8 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
BIND(&check_data);
{
- Node* read_only = IsSetWord32(var_details.value(),
- PropertyDetails::kAttributesReadOnlyMask);
+ TNode<BoolT> read_only = IsSetWord32(
+ var_details.value(), PropertyDetails::kAttributesReadOnlyMask);
GotoIfNot(read_only, &check_passed);
// If SameValue(trapResult, targetDesc.[[Value]]) is false,
@@ -314,7 +317,7 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
Label continue_check(this, Label::kDeferred);
// 10.b. If IsAccessorDescriptor(targetDesc) is true and
// targetDesc.[[Get]] is undefined, then:
- Node* getter =
+ TNode<Object> getter =
LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
// Here we check for null as well because if the getter was never
// defined it's set as null.
@@ -328,7 +331,7 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
} else {
// 11.b.i. If targetDesc.[[Set]] is undefined, throw a TypeError
// exception.
- Node* setter =
+ TNode<Object> setter =
LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
GotoIf(IsUndefined(setter), &throw_non_configurable_accessor);
GotoIf(IsNull(setter), &throw_non_configurable_accessor);
@@ -372,7 +375,7 @@ void ProxiesCodeStubAssembler::CheckHasTrapResult(TNode<Context> context,
TNode<JSReceiver> target,
TNode<JSProxy> proxy,
TNode<Name> name) {
- Node* target_map = LoadMap(target);
+ TNode<Map> target_map = LoadMap(target);
VARIABLE(var_value, MachineRepresentation::kTagged);
VARIABLE(var_details, MachineRepresentation::kWord32);
VARIABLE(var_raw_value, MachineRepresentation::kTagged);
@@ -384,7 +387,7 @@ void ProxiesCodeStubAssembler::CheckHasTrapResult(TNode<Context> context,
// 9.a. Let targetDesc be ? target.[[GetOwnProperty]](P).
GotoIfNot(IsUniqueNameNoIndex(name), &check_in_runtime);
- Node* instance_type = LoadInstanceType(target);
+ TNode<Uint16T> instance_type = LoadInstanceType(target);
TryGetOwnProperty(context, target, target, target_map, instance_type, name,
&if_found_value, &var_value, &var_details, &var_raw_value,
&check_passed, &check_in_runtime, kReturnAccessorPair);
@@ -394,12 +397,12 @@ void ProxiesCodeStubAssembler::CheckHasTrapResult(TNode<Context> context,
{
// 9.b.i. If targetDesc.[[Configurable]] is false, throw a TypeError
// exception.
- Node* non_configurable = IsSetWord32(
+ TNode<BoolT> non_configurable = IsSetWord32(
var_details.value(), PropertyDetails::kAttributesDontDeleteMask);
GotoIf(non_configurable, &throw_non_configurable);
// 9.b.ii. Let extensibleTarget be ? IsExtensible(target).
- Node* target_extensible = IsExtensibleMap(target_map);
+ TNode<BoolT> target_extensible = IsExtensibleMap(target_map);
// 9.b.iii. If extensibleTarget is false, throw a TypeError exception.
GotoIfNot(target_extensible, &throw_non_extensible);
@@ -437,7 +440,7 @@ void ProxiesCodeStubAssembler::CheckDeleteTrapResult(TNode<Context> context,
// 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
GotoIfNot(IsUniqueNameNoIndex(name), &check_in_runtime);
- TNode<Int32T> instance_type = LoadInstanceType(target);
+ TNode<Uint16T> instance_type = LoadInstanceType(target);
TryGetOwnProperty(context, target, target, target_map, instance_type, name,
&if_found_value, &var_value, &var_details, &var_raw_value,
&check_passed, &check_in_runtime, kReturnAccessorPair);
diff --git a/deps/v8/src/builtins/builtins-reflect-gen.cc b/deps/v8/src/builtins/builtins-reflect-gen.cc
index dade25b7c7..744a443ecc 100644
--- a/deps/v8/src/builtins/builtins-reflect-gen.cc
+++ b/deps/v8/src/builtins/builtins-reflect-gen.cc
@@ -13,10 +13,10 @@ namespace internal {
TF_BUILTIN(ReflectHas, CodeStubAssembler) {
Node* target = Parameter(Descriptor::kTarget);
Node* key = Parameter(Descriptor::kKey);
- Node* context = Parameter(Descriptor::kContext);
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- ThrowIfNotJSReceiver(context, target, MessageTemplate::kCalledOnNonObject,
- "Reflect.has");
+ ThrowIfNotJSReceiver(context, CAST(target),
+ MessageTemplate::kCalledOnNonObject, "Reflect.has");
Return(CallBuiltin(Builtins::kHasProperty, context, target, key));
}
diff --git a/deps/v8/src/builtins/builtins-regexp-gen.cc b/deps/v8/src/builtins/builtins-regexp-gen.cc
index d53518ff7e..f879d70c67 100644
--- a/deps/v8/src/builtins/builtins-regexp-gen.cc
+++ b/deps/v8/src/builtins/builtins-regexp-gen.cc
@@ -10,6 +10,8 @@
#include "src/builtins/growable-fixed-array-gen.h"
#include "src/codegen/code-factory.h"
#include "src/codegen/code-stub-assembler.h"
+#include "src/codegen/macro-assembler.h"
+#include "src/execution/protectors.h"
#include "src/heap/factory-inl.h"
#include "src/logging/counters.h"
#include "src/objects/js-regexp-string-iterator.h"
@@ -24,12 +26,55 @@ using compiler::Node;
template <class T>
using TNode = compiler::TNode<T>;
+// Tail calls the regular expression interpreter.
+// static
+void Builtins::Generate_RegExpInterpreterTrampoline(MacroAssembler* masm) {
+ ExternalReference interpreter_code_entry =
+ ExternalReference::re_match_for_call_from_js(masm->isolate());
+ masm->Jump(interpreter_code_entry);
+}
+
TNode<Smi> RegExpBuiltinsAssembler::SmiZero() { return SmiConstant(0); }
TNode<IntPtrT> RegExpBuiltinsAssembler::IntPtrZero() {
return IntPtrConstant(0);
}
+// If code is a builtin, return the address to the (possibly embedded) builtin
+// code entry, otherwise return the entry of the code object itself.
+TNode<RawPtrT> RegExpBuiltinsAssembler::LoadCodeObjectEntry(TNode<Code> code) {
+ TVARIABLE(RawPtrT, var_result);
+
+ Label if_code_is_off_heap(this), out(this);
+ TNode<Int32T> builtin_index = UncheckedCast<Int32T>(
+ LoadObjectField(code, Code::kBuiltinIndexOffset, MachineType::Int32()));
+ {
+ GotoIfNot(Word32Equal(builtin_index, Int32Constant(Builtins::kNoBuiltinId)),
+ &if_code_is_off_heap);
+ var_result = ReinterpretCast<RawPtrT>(
+ IntPtrAdd(BitcastTaggedToWord(code),
+ IntPtrConstant(Code::kHeaderSize - kHeapObjectTag)));
+ Goto(&out);
+ }
+
+ BIND(&if_code_is_off_heap);
+ {
+ TNode<IntPtrT> builtin_entry_offset_from_isolate_root =
+ IntPtrAdd(IntPtrConstant(IsolateData::builtin_entry_table_offset()),
+ ChangeInt32ToIntPtr(Word32Shl(
+ builtin_index, Int32Constant(kSystemPointerSizeLog2))));
+
+ var_result = ReinterpretCast<RawPtrT>(
+ Load(MachineType::Pointer(),
+ ExternalConstant(ExternalReference::isolate_root(isolate())),
+ builtin_entry_offset_from_isolate_root));
+ Goto(&out);
+ }
+
+ BIND(&out);
+ return var_result.value();
+}
+
// -----------------------------------------------------------------------------
// ES6 section 21.2 RegExp Objects
@@ -131,8 +176,8 @@ void RegExpBuiltinsAssembler::FastStoreLastIndex(TNode<JSRegExp> regexp,
void RegExpBuiltinsAssembler::SlowStoreLastIndex(SloppyTNode<Context> context,
SloppyTNode<Object> regexp,
- SloppyTNode<Number> value) {
- TNode<Name> name = HeapConstant(isolate()->factory()->lastIndex_string());
+ SloppyTNode<Object> value) {
+ TNode<String> name = HeapConstant(isolate()->factory()->lastIndex_string());
SetPropertyStrict(context, regexp, name, value);
}
@@ -236,7 +281,7 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
// index at odd indices.
TNode<Object> maybe_names =
LoadFixedArrayElement(data, JSRegExp::kIrregexpCaptureNameMapIndex);
- GotoIf(WordEqual(maybe_names, SmiZero()), &out);
+ GotoIf(TaggedEqual(maybe_names, SmiZero()), &out);
// One or more named captures exist, add a property for each one.
@@ -249,7 +294,7 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
// root list.
TNode<IntPtrT> num_properties = WordSar(names_length, 1);
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> map = CAST(LoadContextElement(
native_context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP));
TNode<NameDictionary> properties =
@@ -320,11 +365,11 @@ void RegExpBuiltinsAssembler::GetStringPointers(
? UINT8_ELEMENTS
: UINT16_ELEMENTS;
- Node* const from_offset = ElementOffsetFromIndex(
+ TNode<IntPtrT> const from_offset = ElementOffsetFromIndex(
IntPtrAdd(offset, last_index), kind, INTPTR_PARAMETERS);
var_string_start->Bind(IntPtrAdd(string_data, from_offset));
- Node* const to_offset = ElementOffsetFromIndex(
+ TNode<IntPtrT> const to_offset = ElementOffsetFromIndex(
IntPtrAdd(offset, string_length), kind, INTPTR_PARAMETERS);
var_string_end->Bind(IntPtrAdd(string_data, to_offset));
}
@@ -340,9 +385,8 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
// External constants.
TNode<ExternalReference> isolate_address =
ExternalConstant(ExternalReference::isolate_address(isolate()));
- TNode<ExternalReference> regexp_stack_memory_address_address =
- ExternalConstant(
- ExternalReference::address_of_regexp_stack_memory_address(isolate()));
+ TNode<ExternalReference> regexp_stack_memory_top_address = ExternalConstant(
+ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()));
TNode<ExternalReference> regexp_stack_memory_size_address = ExternalConstant(
ExternalReference::address_of_regexp_stack_memory_size(isolate()));
TNode<ExternalReference> static_offsets_vector_address = ExternalConstant(
@@ -374,7 +418,9 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
data, IntPtrConstant(JSRegExp::kTagIndex));
int32_t values[] = {
- JSRegExp::IRREGEXP, JSRegExp::ATOM, JSRegExp::NOT_COMPILED,
+ JSRegExp::IRREGEXP,
+ JSRegExp::ATOM,
+ JSRegExp::NOT_COMPILED,
};
Label* labels[] = {&next, &atom, &runtime};
@@ -398,24 +444,17 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
&runtime);
}
- // Ensure that a RegExp stack is allocated. This check is after branching off
- // for ATOM regexps to avoid unnecessary trips to runtime.
- {
- TNode<IntPtrT> stack_size = UncheckedCast<IntPtrT>(
- Load(MachineType::IntPtr(), regexp_stack_memory_size_address));
- GotoIf(IntPtrEqual(stack_size, IntPtrZero()), &runtime);
- }
-
// Unpack the string if possible.
to_direct.TryToDirect(&runtime);
- // Load the irregexp code object and offsets into the subject string. Both
- // depend on whether the string is one- or two-byte.
+ // Load the irregexp code or bytecode object and offsets into the subject
+ // string. Both depend on whether the string is one- or two-byte.
TVARIABLE(RawPtrT, var_string_start);
TVARIABLE(RawPtrT, var_string_end);
TVARIABLE(Object, var_code);
+ TVARIABLE(Object, var_bytecode);
{
TNode<RawPtrT> direct_string_data = to_direct.PointerToData(&runtime);
@@ -431,6 +470,8 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
&var_string_start, &var_string_end);
var_code =
UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpLatin1CodeIndex);
+ var_bytecode = UnsafeLoadFixedArrayElement(
+ data, JSRegExp::kIrregexpLatin1BytecodeIndex);
Goto(&next);
}
@@ -441,6 +482,8 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
&var_string_start, &var_string_end);
var_code =
UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpUC16CodeIndex);
+ var_bytecode = UnsafeLoadFixedArrayElement(
+ data, JSRegExp::kIrregexpUC16BytecodeIndex);
Goto(&next);
}
@@ -462,9 +505,32 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
#endif
GotoIf(TaggedIsSmi(var_code.value()), &runtime);
- GotoIfNot(IsCode(CAST(var_code.value())), &runtime);
TNode<Code> code = CAST(var_code.value());
+ // Tier-up in runtime if ticks are non-zero and tier-up hasn't happened yet
+ // and ensure that a RegExp stack is allocated when using compiled Irregexp.
+ {
+ Label next(this), check_tier_up(this);
+ GotoIfNot(TaggedIsSmi(var_bytecode.value()), &check_tier_up);
+ CSA_ASSERT(this, SmiEqual(CAST(var_bytecode.value()),
+ SmiConstant(JSRegExp::kUninitializedValue)));
+
+ // Ensure RegExp stack is allocated.
+ TNode<IntPtrT> stack_size = UncheckedCast<IntPtrT>(
+ Load(MachineType::IntPtr(), regexp_stack_memory_size_address));
+ GotoIf(IntPtrEqual(stack_size, IntPtrZero()), &runtime);
+ Goto(&next);
+
+ // Check if tier-up is requested.
+ BIND(&check_tier_up);
+ TNode<Smi> ticks = CAST(
+ UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpTierUpTicksIndex));
+ GotoIf(SmiToInt32(ticks), &runtime);
+
+ Goto(&next);
+ BIND(&next);
+ }
+
Label if_success(this), if_exception(this, Label::kDeferred);
{
IncrementCounter(isolate()->counters()->regexp_entry_native(), 1);
@@ -486,11 +552,13 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
MachineType arg1_type = type_int32;
TNode<Int32T> arg1 = TruncateIntPtrToInt32(int_last_index);
- // Argument 2: Start of string data.
+ // Argument 2: Start of string data. This argument is ignored in the
+ // interpreter.
MachineType arg2_type = type_ptr;
TNode<RawPtrT> arg2 = var_string_start.value();
- // Argument 3: End of string data.
+ // Argument 3: End of string data. This argument is ignored in the
+ // interpreter.
MachineType arg3_type = type_ptr;
TNode<RawPtrT> arg3 = var_string_end.value();
@@ -498,41 +566,50 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
MachineType arg4_type = type_ptr;
TNode<ExternalReference> arg4 = static_offsets_vector_address;
- // Argument 5: Set the number of capture registers to zero to force global
- // regexps to behave as non-global. This does not affect non-global
- // regexps.
+ // Argument 5: Number of capture registers.
+ // Setting this to the number of registers required to store all captures
+ // forces global regexps to behave as non-global.
+ TNode<Smi> capture_count = CAST(UnsafeLoadFixedArrayElement(
+ data, JSRegExp::kIrregexpCaptureCountIndex));
+ // capture_count is the number of captures without the match itself.
+ // Required registers = (capture_count + 1) * 2.
+ STATIC_ASSERT(Internals::IsValidSmi((JSRegExp::kMaxCaptures + 1) << 1));
+ TNode<Smi> register_count =
+ SmiShl(SmiAdd(capture_count, SmiConstant(1)), 1);
+
MachineType arg5_type = type_int32;
- TNode<Int32T> arg5 = Int32Constant(0);
+ TNode<Int32T> arg5 = SmiToInt32(register_count);
- // Argument 6: Start (high end) of backtracking stack memory area.
- TNode<RawPtrT> stack_start = UncheckedCast<RawPtrT>(
- Load(MachineType::Pointer(), regexp_stack_memory_address_address));
- TNode<IntPtrT> stack_size = UncheckedCast<IntPtrT>(
- Load(MachineType::IntPtr(), regexp_stack_memory_size_address));
- TNode<RawPtrT> stack_end =
- ReinterpretCast<RawPtrT>(IntPtrAdd(stack_start, stack_size));
+ // Argument 6: Start (high end) of backtracking stack memory area. This
+ // argument is ignored in the interpreter.
+ TNode<RawPtrT> stack_top = UncheckedCast<RawPtrT>(
+ Load(MachineType::Pointer(), regexp_stack_memory_top_address));
MachineType arg6_type = type_ptr;
- TNode<RawPtrT> arg6 = stack_end;
+ TNode<RawPtrT> arg6 = stack_top;
// Argument 7: Indicate that this is a direct call from JavaScript.
MachineType arg7_type = type_int32;
- TNode<Int32T> arg7 = Int32Constant(1);
+ TNode<Int32T> arg7 = Int32Constant(RegExp::CallOrigin::kFromJs);
// Argument 8: Pass current isolate address.
MachineType arg8_type = type_ptr;
TNode<ExternalReference> arg8 = isolate_address;
- TNode<RawPtrT> code_entry = ReinterpretCast<RawPtrT>(
- IntPtrAdd(BitcastTaggedToWord(code),
- IntPtrConstant(Code::kHeaderSize - kHeapObjectTag)));
+ // Argument 9: Regular expression object. This argument is ignored in native
+ // irregexp code.
+ MachineType arg9_type = type_tagged;
+ TNode<JSRegExp> arg9 = regexp;
+
+ TNode<RawPtrT> code_entry = LoadCodeObjectEntry(code);
TNode<Int32T> result = UncheckedCast<Int32T>(CallCFunction(
code_entry, retval_type, std::make_pair(arg0_type, arg0),
std::make_pair(arg1_type, arg1), std::make_pair(arg2_type, arg2),
std::make_pair(arg3_type, arg3), std::make_pair(arg4_type, arg4),
std::make_pair(arg5_type, arg5), std::make_pair(arg6_type, arg6),
- std::make_pair(arg7_type, arg7), std::make_pair(arg8_type, arg8)));
+ std::make_pair(arg7_type, arg7), std::make_pair(arg8_type, arg8),
+ std::make_pair(arg9_type, arg9)));
// Check the result.
// We expect exactly one result since we force the called regexp to behave
@@ -734,7 +811,7 @@ RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
BIND(&run_exec);
{
// Get last match info from the context.
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<RegExpMatchInfo> last_match_info = CAST(LoadContextElement(
native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX));
@@ -771,8 +848,8 @@ RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
TNode<RegExpMatchInfo>
RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResultFast(
- TNode<Context> context, TNode<JSReceiver> maybe_regexp,
- TNode<String> string, Label* if_didnotmatch) {
+ TNode<Context> context, TNode<JSRegExp> maybe_regexp, TNode<String> string,
+ Label* if_didnotmatch) {
return RegExpPrototypeExecBodyWithoutResult(context, maybe_regexp, string,
if_didnotmatch, true);
}
@@ -805,36 +882,21 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpPrototypeExecBody(
return var_result.value();
}
-Node* RegExpBuiltinsAssembler::ThrowIfNotJSReceiver(
- Node* context, Node* maybe_receiver, MessageTemplate msg_template,
- char const* method_name) {
- Label out(this), throw_exception(this, Label::kDeferred);
- VARIABLE(var_value_map, MachineRepresentation::kTagged);
-
- GotoIf(TaggedIsSmi(maybe_receiver), &throw_exception);
-
- // Load the instance type of the {value}.
- var_value_map.Bind(LoadMap(maybe_receiver));
- Node* const value_instance_type = LoadMapInstanceType(var_value_map.value());
-
- Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception);
-
- // The {value} is not a compatible receiver for this method.
- BIND(&throw_exception);
- {
- Node* const value_str =
- CallBuiltin(Builtins::kToString, context, maybe_receiver);
- ThrowTypeError(context, msg_template, StringConstant(method_name),
- value_str);
- }
-
- BIND(&out);
- return var_value_map.value();
+TNode<BoolT> RegExpBuiltinsAssembler::IsReceiverInitialRegExpPrototype(
+ SloppyTNode<Context> context, SloppyTNode<Object> receiver) {
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> const regexp_fun =
+ CAST(LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX));
+ TNode<Object> const initial_map =
+ LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
+ TNode<HeapObject> const initial_prototype =
+ LoadMapPrototype(CAST(initial_map));
+ return TaggedEqual(receiver, initial_prototype);
}
-Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(Node* const context,
- Node* const object,
- Node* const map) {
+Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(
+ SloppyTNode<Context> context, SloppyTNode<Object> object,
+ SloppyTNode<Map> map) {
Label out(this);
VARIABLE(var_result, MachineRepresentation::kWord32);
@@ -843,12 +905,12 @@ Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(Node* const context,
GotoIfForceSlowPath(&out);
#endif
- Node* const native_context = LoadNativeContext(context);
- Node* const regexp_fun =
- LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
- Node* const initial_map =
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<HeapObject> const regexp_fun =
+ CAST(LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX));
+ TNode<Object> const initial_map =
LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
- Node* const has_initialmap = WordEqual(map, initial_map);
+ TNode<BoolT> const has_initialmap = TaggedEqual(map, initial_map);
var_result.Bind(has_initialmap);
GotoIfNot(has_initialmap, &out);
@@ -882,14 +944,14 @@ TNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExpWithOriginalExec(
var_result = is_regexp;
GotoIfNot(is_regexp, &out);
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Object> original_exec =
LoadContextElement(native_context, Context::REGEXP_EXEC_FUNCTION_INDEX);
TNode<Object> regexp_exec =
GetProperty(context, object, isolate()->factory()->exec_string());
- TNode<BoolT> has_initialexec = WordEqual(regexp_exec, original_exec);
+ TNode<BoolT> has_initialexec = TaggedEqual(regexp_exec, original_exec);
var_result = has_initialexec;
GotoIf(has_initialexec, &check_last_index);
TNode<BoolT> is_undefined = IsUndefined(regexp_exec);
@@ -908,85 +970,80 @@ TNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExpWithOriginalExec(
return var_result.value();
}
-Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(Node* const context,
- Node* const object) {
+Node* RegExpBuiltinsAssembler::IsFastRegExpNoPrototype(
+ SloppyTNode<Context> context, SloppyTNode<Object> object) {
CSA_ASSERT(this, TaggedIsNotSmi(object));
- return IsFastRegExpNoPrototype(context, object, LoadMap(object));
+ return IsFastRegExpNoPrototype(context, object, LoadMap(CAST(object)));
}
-// RegExp fast path implementations rely on unmodified JSRegExp instances.
-// We use a fairly coarse granularity for this and simply check whether both
-// the regexp itself is unmodified (i.e. its map has not changed), its
-// prototype is unmodified, and lastIndex is a non-negative smi.
void RegExpBuiltinsAssembler::BranchIfFastRegExp(
- Node* const context, Node* const object, Node* const map,
- base::Optional<DescriptorIndexAndName> additional_property_to_check,
- Label* const if_isunmodified, Label* const if_ismodified) {
- CSA_ASSERT(this, WordEqual(LoadMap(object), map));
+ TNode<Context> context, TNode<HeapObject> object, TNode<Map> map,
+ PrototypeCheckAssembler::Flags prototype_check_flags,
+ base::Optional<DescriptorIndexNameValue> additional_property_to_check,
+ Label* if_isunmodified, Label* if_ismodified) {
+ CSA_ASSERT(this, TaggedEqual(LoadMap(object), map));
GotoIfForceSlowPath(if_ismodified);
// This should only be needed for String.p.(split||matchAll), but we are
// conservative here.
- TNode<Context> native_context = LoadNativeContext(context);
+ // Note: we are using the current native context here, which may or may not
+ // match the object's native context. That's fine: in case of a mismatch, we
+ // will bail in the next step when comparing the object's map against the
+ // current native context's initial regexp map.
+ TNode<NativeContext> native_context = LoadNativeContext(context);
GotoIf(IsRegExpSpeciesProtectorCellInvalid(native_context), if_ismodified);
- Node* const regexp_fun =
- LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
- Node* const initial_map =
- LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
- Node* const has_initialmap = WordEqual(map, initial_map);
+ TNode<JSFunction> regexp_fun =
+ CAST(LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX));
+ TNode<Map> initial_map = CAST(
+ LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset));
+ TNode<BoolT> has_initialmap = TaggedEqual(map, initial_map);
GotoIfNot(has_initialmap, if_ismodified);
- Node* const initial_proto_initial_map =
- LoadContextElement(native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX);
+ // The smi check is required to omit ToLength(lastIndex) calls with possible
+ // user-code execution on the fast path.
+ TNode<Object> last_index = FastLoadLastIndexBeforeSmiCheck(CAST(object));
+ GotoIfNot(TaggedIsPositiveSmi(last_index), if_ismodified);
+
+ // Verify the prototype.
+
+ TNode<Map> initial_proto_initial_map = CAST(
+ LoadContextElement(native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX));
- DescriptorIndexAndName properties_to_check[2];
+ DescriptorIndexNameValue properties_to_check[2];
int property_count = 0;
- properties_to_check[property_count++] = DescriptorIndexAndName{
- JSRegExp::kExecFunctionDescriptorIndex, RootIndex::kexec_string};
+ properties_to_check[property_count++] = DescriptorIndexNameValue{
+ JSRegExp::kExecFunctionDescriptorIndex, RootIndex::kexec_string,
+ Context::REGEXP_EXEC_FUNCTION_INDEX};
if (additional_property_to_check) {
properties_to_check[property_count++] = *additional_property_to_check;
}
- GotoIfInitialPrototypePropertiesModified(
- CAST(map), CAST(initial_proto_initial_map),
- Vector<DescriptorIndexAndName>(properties_to_check, property_count),
- if_ismodified);
+ PrototypeCheckAssembler prototype_check_assembler(
+ state(), prototype_check_flags, native_context, initial_proto_initial_map,
+ Vector<DescriptorIndexNameValue>(properties_to_check, property_count));
- // The smi check is required to omit ToLength(lastIndex) calls with possible
- // user-code execution on the fast path.
- TNode<Object> last_index = FastLoadLastIndexBeforeSmiCheck(CAST(object));
- Branch(TaggedIsPositiveSmi(last_index), if_isunmodified, if_ismodified);
+ TNode<HeapObject> prototype = LoadMapPrototype(map);
+ prototype_check_assembler.CheckAndBranch(prototype, if_isunmodified,
+ if_ismodified);
}
-void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context,
- Node* const object,
- Label* const if_isunmodified,
- Label* const if_ismodified) {
- CSA_ASSERT(this, TaggedIsNotSmi(object));
- BranchIfFastRegExp(context, object, LoadMap(object), base::nullopt,
- if_isunmodified, if_ismodified);
+void RegExpBuiltinsAssembler::BranchIfFastRegExp_Strict(
+ TNode<Context> context, TNode<HeapObject> object, Label* if_isunmodified,
+ Label* if_ismodified) {
+ BranchIfFastRegExp(context, object, LoadMap(object),
+ PrototypeCheckAssembler::kCheckPrototypePropertyConstness,
+ base::nullopt, if_isunmodified, if_ismodified);
}
-TNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExp(SloppyTNode<Context> context,
- SloppyTNode<Object> object) {
- Label yup(this), nope(this), out(this);
- TVARIABLE(BoolT, var_result);
-
- BranchIfFastRegExp(context, object, &yup, &nope);
-
- BIND(&yup);
- var_result = Int32TrueConstant();
- Goto(&out);
-
- BIND(&nope);
- var_result = Int32FalseConstant();
- Goto(&out);
-
- BIND(&out);
- return var_result.value();
+void RegExpBuiltinsAssembler::BranchIfFastRegExp_Permissive(
+ TNode<Context> context, TNode<HeapObject> object, Label* if_isunmodified,
+ Label* if_ismodified) {
+ BranchIfFastRegExp(context, object, LoadMap(object),
+ PrototypeCheckAssembler::kCheckFull, base::nullopt,
+ if_isunmodified, if_ismodified);
}
void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* const context,
@@ -994,13 +1051,13 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* const context,
Label* if_isunmodified,
Label* if_ismodified) {
// Could be a Smi.
- Node* const map = LoadReceiverMap(object);
+ TNode<Map> const map = LoadReceiverMap(object);
- Node* const native_context = LoadNativeContext(context);
- Node* const initial_regexp_result_map =
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const initial_regexp_result_map =
LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX);
- Branch(WordEqual(map, initial_regexp_result_map), if_isunmodified,
+ Branch(TaggedEqual(map, initial_regexp_result_map), if_isunmodified,
if_ismodified);
}
@@ -1036,9 +1093,8 @@ TF_BUILTIN(RegExpExecAtom, RegExpBuiltinsAssembler) {
UintPtrLessThanOrEqual(SmiUntag(last_index),
LoadStringLengthAsWord(subject_string)));
- Node* const needle_string =
- UnsafeLoadFixedArrayElement(data, JSRegExp::kAtomPatternIndex);
- CSA_ASSERT(this, IsString(needle_string));
+ TNode<String> const needle_string =
+ CAST(UnsafeLoadFixedArrayElement(data, JSRegExp::kAtomPatternIndex));
TNode<Smi> const match_from =
CAST(CallBuiltin(Builtins::kStringIndexOf, context, subject_string,
@@ -1120,9 +1176,9 @@ TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) {
string));
}
-Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
- Node* const regexp,
- bool is_fastpath) {
+TNode<String> RegExpBuiltinsAssembler::FlagsGetter(TNode<Context> context,
+ TNode<Object> regexp,
+ bool is_fastpath) {
Isolate* isolate = this->isolate();
TNode<IntPtrT> const int_one = IntPtrConstant(1);
@@ -1134,8 +1190,9 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
if (is_fastpath) {
// Refer to JSRegExp's flag property on the fast-path.
- CSA_ASSERT(this, IsJSRegExp(regexp));
- Node* const flags_smi = LoadObjectField(regexp, JSRegExp::kFlagsOffset);
+ CSA_ASSERT(this, IsJSRegExp(CAST(regexp)));
+ TNode<Smi> const flags_smi =
+ CAST(LoadObjectField(CAST(regexp), JSRegExp::kFlagsOffset));
var_flags = SmiUntag(flags_smi);
#define CASE_FOR_FLAG(FLAG) \
@@ -1163,7 +1220,7 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
#define CASE_FOR_FLAG(NAME, FLAG) \
do { \
Label next(this); \
- Node* const flag = GetProperty( \
+ TNode<Object> const flag = GetProperty( \
context, regexp, isolate->factory()->InternalizeUtf8String(NAME)); \
Label if_isflagset(this); \
BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \
@@ -1187,7 +1244,7 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
// char for each set flag.
{
- Node* const result = AllocateSeqOneByteString(context, var_length.value());
+ TNode<String> const result = AllocateSeqOneByteString(var_length.value());
VARIABLE(var_offset, MachineType::PointerRepresentation(),
IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag));
@@ -1196,7 +1253,7 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
do { \
Label next(this); \
GotoIfNot(IsSetWord(var_flags.value(), FLAG), &next); \
- Node* const value = Int32Constant(CHAR); \
+ TNode<Int32T> const value = Int32Constant(CHAR); \
StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \
var_offset.value(), value); \
var_offset.Bind(IntPtrAdd(var_offset.value(), int_one)); \
@@ -1290,27 +1347,6 @@ Node* RegExpBuiltinsAssembler::RegExpInitialize(Node* const context,
pattern, flags);
}
-// ES #sec-get-regexp.prototype.flags
-TF_BUILTIN(RegExpPrototypeFlagsGetter, RegExpBuiltinsAssembler) {
- TNode<Object> maybe_receiver = CAST(Parameter(Descriptor::kReceiver));
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
-
- TNode<Map> map = CAST(ThrowIfNotJSReceiver(context, maybe_receiver,
- MessageTemplate::kRegExpNonObject,
- "RegExp.prototype.flags"));
- TNode<JSReceiver> receiver = CAST(maybe_receiver);
-
- Label if_isfastpath(this), if_isslowpath(this, Label::kDeferred);
- BranchIfFastRegExp(context, receiver, map, base::nullopt, &if_isfastpath,
- &if_isslowpath);
-
- BIND(&if_isfastpath);
- Return(FlagsGetter(context, receiver, true));
-
- BIND(&if_isslowpath);
- Return(FlagsGetter(context, receiver, false));
-}
-
// ES#sec-regexp-pattern-flags
// RegExp ( pattern, flags )
TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
@@ -1321,13 +1357,13 @@ TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
Isolate* isolate = this->isolate();
- VARIABLE(var_flags, MachineRepresentation::kTagged, flags);
- VARIABLE(var_pattern, MachineRepresentation::kTagged, pattern);
- VARIABLE(var_new_target, MachineRepresentation::kTagged, new_target);
+ TVARIABLE(Object, var_flags, flags);
+ TVARIABLE(Object, var_pattern, pattern);
+ TVARIABLE(Object, var_new_target, new_target);
- Node* const native_context = LoadNativeContext(context);
- Node* const regexp_function =
- LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<JSFunction> regexp_function =
+ CAST(LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX));
TNode<BoolT> pattern_is_regexp = IsRegExp(context, pattern);
@@ -1335,15 +1371,15 @@ TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
Label next(this);
GotoIfNot(IsUndefined(new_target), &next);
- var_new_target.Bind(regexp_function);
+ var_new_target = regexp_function;
GotoIfNot(pattern_is_regexp, &next);
GotoIfNot(IsUndefined(flags), &next);
- Node* const value =
+ TNode<Object> value =
GetProperty(context, pattern, isolate->factory()->constructor_string());
- GotoIfNot(WordEqual(value, regexp_function), &next);
+ GotoIfNot(TaggedEqual(value, regexp_function), &next);
Return(pattern);
BIND(&next);
@@ -1360,16 +1396,15 @@ TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
BIND(&if_patternisfastregexp);
{
- Node* const source =
+ TNode<Object> source =
LoadObjectField(CAST(pattern), JSRegExp::kSourceOffset);
- var_pattern.Bind(source);
+ var_pattern = source;
{
Label inner_next(this);
GotoIfNot(IsUndefined(flags), &inner_next);
- Node* const value = FlagsGetter(context, pattern, true);
- var_flags.Bind(value);
+ var_flags = FlagsGetter(context, pattern, true);
Goto(&inner_next);
BIND(&inner_next);
@@ -1380,19 +1415,15 @@ TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
BIND(&if_patternisslowregexp);
{
- {
- Node* const value =
- GetProperty(context, pattern, isolate->factory()->source_string());
- var_pattern.Bind(value);
- }
+ var_pattern =
+ GetProperty(context, pattern, isolate->factory()->source_string());
{
Label inner_next(this);
GotoIfNot(IsUndefined(flags), &inner_next);
- Node* const value =
+ var_flags =
GetProperty(context, pattern, isolate->factory()->flags_string());
- var_flags.Bind(value);
Goto(&inner_next);
BIND(&inner_next);
@@ -1410,14 +1441,14 @@ TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
{
Label allocate_jsregexp(this), allocate_generic(this, Label::kDeferred),
next(this);
- Branch(WordEqual(var_new_target.value(), regexp_function),
+ Branch(TaggedEqual(var_new_target.value(), regexp_function),
&allocate_jsregexp, &allocate_generic);
BIND(&allocate_jsregexp);
{
- Node* const initial_map = LoadObjectField(
- regexp_function, JSFunction::kPrototypeOrInitialMapOffset);
- Node* const regexp = AllocateJSObjectFromMap(initial_map);
+ TNode<Map> const initial_map = CAST(LoadObjectField(
+ regexp_function, JSFunction::kPrototypeOrInitialMapOffset));
+ TNode<JSObject> const regexp = AllocateJSObjectFromMap(initial_map);
var_regexp.Bind(regexp);
Goto(&next);
}
@@ -1425,8 +1456,8 @@ TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
BIND(&allocate_generic);
{
ConstructorBuiltinsAssembler constructor_assembler(this->state());
- Node* const regexp = constructor_assembler.EmitFastNewObject(
- context, regexp_function, var_new_target.value());
+ TNode<JSObject> const regexp = constructor_assembler.EmitFastNewObject(
+ context, regexp_function, CAST(var_new_target.value()));
var_regexp.Bind(regexp);
Goto(&next);
}
@@ -1473,8 +1504,9 @@ TF_BUILTIN(RegExpPrototypeCompile, RegExpBuiltinsAssembler) {
BIND(&next);
}
- Node* const new_flags = FlagsGetter(context, pattern, true);
- Node* const new_pattern = LoadObjectField(pattern, JSRegExp::kSourceOffset);
+ TNode<String> const new_flags = FlagsGetter(context, CAST(pattern), true);
+ TNode<Object> const new_pattern =
+ LoadObjectField(pattern, JSRegExp::kSourceOffset);
var_flags.Bind(new_flags);
var_pattern.Bind(new_pattern);
@@ -1488,69 +1520,22 @@ TF_BUILTIN(RegExpPrototypeCompile, RegExpBuiltinsAssembler) {
Return(result);
}
-// ES6 21.2.5.10.
-// ES #sec-get-regexp.prototype.source
-TF_BUILTIN(RegExpPrototypeSourceGetter, RegExpBuiltinsAssembler) {
- TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
-
- // Check whether we have an unmodified regexp instance.
- Label if_isjsregexp(this), if_isnotjsregexp(this, Label::kDeferred);
-
- GotoIf(TaggedIsSmi(receiver), &if_isnotjsregexp);
- Branch(IsJSRegExp(CAST(receiver)), &if_isjsregexp, &if_isnotjsregexp);
-
- BIND(&if_isjsregexp);
- Return(LoadObjectField(CAST(receiver), JSRegExp::kSourceOffset));
-
- BIND(&if_isnotjsregexp);
- {
- Isolate* isolate = this->isolate();
- Node* const native_context = LoadNativeContext(context);
- Node* const regexp_fun =
- LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
- Node* const initial_map =
- LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
- Node* const initial_prototype = LoadMapPrototype(initial_map);
-
- Label if_isprototype(this), if_isnotprototype(this);
- Branch(WordEqual(receiver, initial_prototype), &if_isprototype,
- &if_isnotprototype);
-
- BIND(&if_isprototype);
- {
- const int counter = v8::Isolate::kRegExpPrototypeSourceGetter;
- Node* const counter_smi = SmiConstant(counter);
- CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi);
-
- Node* const result =
- HeapConstant(isolate->factory()->NewStringFromAsciiChecked("(?:)"));
- Return(result);
- }
-
- BIND(&if_isnotprototype);
- {
- ThrowTypeError(context, MessageTemplate::kRegExpNonRegExp,
- "RegExp.prototype.source");
- }
- }
-}
-
// Fast-path implementation for flag checks on an unmodified JSRegExp instance.
-TNode<Int32T> RegExpBuiltinsAssembler::FastFlagGetter(TNode<JSRegExp> regexp,
- JSRegExp::Flag flag) {
+TNode<BoolT> RegExpBuiltinsAssembler::FastFlagGetter(TNode<JSRegExp> regexp,
+ JSRegExp::Flag flag) {
TNode<Smi> flags = CAST(LoadObjectField(regexp, JSRegExp::kFlagsOffset));
TNode<Smi> mask = SmiConstant(flag);
- return SmiToInt32(SmiShr(SmiAnd(flags, mask), base::bits::CountTrailingZeros(
- static_cast<int>(flag))));
+ return ReinterpretCast<BoolT>(SmiToInt32(
+ SmiShr(SmiAnd(flags, mask),
+ base::bits::CountTrailingZeros(static_cast<int>(flag)))));
}
// Load through the GetProperty stub.
-TNode<Int32T> RegExpBuiltinsAssembler::SlowFlagGetter(TNode<Context> context,
- TNode<Object> regexp,
- JSRegExp::Flag flag) {
+TNode<BoolT> RegExpBuiltinsAssembler::SlowFlagGetter(TNode<Context> context,
+ TNode<Object> regexp,
+ JSRegExp::Flag flag) {
Label out(this);
- TVARIABLE(Int32T, var_result);
+ TVARIABLE(BoolT, var_result);
Handle<String> name;
switch (flag) {
@@ -1582,140 +1567,36 @@ TNode<Int32T> RegExpBuiltinsAssembler::SlowFlagGetter(TNode<Context> context,
BranchIfToBooleanIsTrue(value, &if_true, &if_false);
BIND(&if_true);
- var_result = Int32Constant(1);
+ var_result = BoolConstant(true);
Goto(&out);
BIND(&if_false);
- var_result = Int32Constant(0);
+ var_result = BoolConstant(false);
Goto(&out);
BIND(&out);
return var_result.value();
}
-TNode<Int32T> RegExpBuiltinsAssembler::FlagGetter(TNode<Context> context,
- TNode<Object> regexp,
- JSRegExp::Flag flag,
- bool is_fastpath) {
+TNode<BoolT> RegExpBuiltinsAssembler::FlagGetter(TNode<Context> context,
+ TNode<Object> regexp,
+ JSRegExp::Flag flag,
+ bool is_fastpath) {
return is_fastpath ? FastFlagGetter(CAST(regexp), flag)
: SlowFlagGetter(context, regexp, flag);
}
-void RegExpBuiltinsAssembler::FlagGetter(Node* context, Node* receiver,
- JSRegExp::Flag flag, int counter,
- const char* method_name) {
- // Check whether we have an unmodified regexp instance.
- Label if_isunmodifiedjsregexp(this),
- if_isnotunmodifiedjsregexp(this, Label::kDeferred);
-
- GotoIf(TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp);
- Branch(IsJSRegExp(receiver), &if_isunmodifiedjsregexp,
- &if_isnotunmodifiedjsregexp);
-
- BIND(&if_isunmodifiedjsregexp);
- {
- // Refer to JSRegExp's flag property on the fast-path.
- Node* const is_flag_set = FastFlagGetter(CAST(receiver), flag);
- Return(SelectBooleanConstant(is_flag_set));
- }
-
- BIND(&if_isnotunmodifiedjsregexp);
- {
- Node* const native_context = LoadNativeContext(context);
- Node* const regexp_fun =
- LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
- Node* const initial_map =
- LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
- Node* const initial_prototype = LoadMapPrototype(initial_map);
-
- Label if_isprototype(this), if_isnotprototype(this);
- Branch(WordEqual(receiver, initial_prototype), &if_isprototype,
- &if_isnotprototype);
-
- BIND(&if_isprototype);
- {
- if (counter != -1) {
- Node* const counter_smi = SmiConstant(counter);
- CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi);
- }
- Return(UndefinedConstant());
- }
-
- BIND(&if_isnotprototype);
- { ThrowTypeError(context, MessageTemplate::kRegExpNonRegExp, method_name); }
- }
-}
-
-// ES6 21.2.5.4.
-// ES #sec-get-regexp.prototype.global
-TF_BUILTIN(RegExpPrototypeGlobalGetter, RegExpBuiltinsAssembler) {
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- FlagGetter(context, receiver, JSRegExp::kGlobal,
- v8::Isolate::kRegExpPrototypeOldFlagGetter,
- "RegExp.prototype.global");
-}
-
-// ES6 21.2.5.5.
-// ES #sec-get-regexp.prototype.ignorecase
-TF_BUILTIN(RegExpPrototypeIgnoreCaseGetter, RegExpBuiltinsAssembler) {
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- FlagGetter(context, receiver, JSRegExp::kIgnoreCase,
- v8::Isolate::kRegExpPrototypeOldFlagGetter,
- "RegExp.prototype.ignoreCase");
-}
-
-// ES6 21.2.5.7.
-// ES #sec-get-regexp.prototype.multiline
-TF_BUILTIN(RegExpPrototypeMultilineGetter, RegExpBuiltinsAssembler) {
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- FlagGetter(context, receiver, JSRegExp::kMultiline,
- v8::Isolate::kRegExpPrototypeOldFlagGetter,
- "RegExp.prototype.multiline");
-}
-
-// ES #sec-get-regexp.prototype.dotAll
-TF_BUILTIN(RegExpPrototypeDotAllGetter, RegExpBuiltinsAssembler) {
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- static const int kNoCounter = -1;
- FlagGetter(context, receiver, JSRegExp::kDotAll, kNoCounter,
- "RegExp.prototype.dotAll");
-}
-
-// ES6 21.2.5.12.
-// ES #sec-get-regexp.prototype.sticky
-TF_BUILTIN(RegExpPrototypeStickyGetter, RegExpBuiltinsAssembler) {
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- FlagGetter(context, receiver, JSRegExp::kSticky,
- v8::Isolate::kRegExpPrototypeStickyGetter,
- "RegExp.prototype.sticky");
-}
-
-// ES6 21.2.5.15.
-// ES #sec-get-regexp.prototype.unicode
-TF_BUILTIN(RegExpPrototypeUnicodeGetter, RegExpBuiltinsAssembler) {
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- FlagGetter(context, receiver, JSRegExp::kUnicode,
- v8::Isolate::kRegExpPrototypeUnicodeGetter,
- "RegExp.prototype.unicode");
-}
-
// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
-Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
- Node* string) {
- VARIABLE(var_result, MachineRepresentation::kTagged);
+TNode<Object> RegExpBuiltinsAssembler::RegExpExec(TNode<Context> context,
+ Node* regexp, Node* string) {
+ TVARIABLE(Object, var_result);
Label out(this);
// Take the slow path of fetching the exec property, calling it, and
// verifying its return value.
// Get the exec property.
- Node* const exec =
+ TNode<Object> const exec =
GetProperty(context, regexp, isolate()->factory()->exec_string());
// Is {exec} callable?
@@ -1723,18 +1604,17 @@ Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
GotoIf(TaggedIsSmi(exec), &if_isnotcallable);
- Node* const exec_map = LoadMap(exec);
+ TNode<Map> const exec_map = LoadMap(CAST(exec));
Branch(IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable);
BIND(&if_iscallable);
{
Callable call_callable = CodeFactory::Call(isolate());
- Node* const result = CallJS(call_callable, context, exec, regexp, string);
+ var_result = CAST(CallJS(call_callable, context, exec, regexp, string));
- var_result.Bind(result);
- GotoIf(IsNull(result), &out);
+ GotoIf(IsNull(var_result.value()), &out);
- ThrowIfNotJSReceiver(context, result,
+ ThrowIfNotJSReceiver(context, var_result.value(),
MessageTemplate::kInvalidRegExpExecResult, "");
Goto(&out);
@@ -1745,9 +1625,8 @@ Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE,
"RegExp.prototype.exec");
- Node* const result = CallBuiltin(Builtins::kRegExpPrototypeExecSlow,
- context, regexp, string);
- var_result.Bind(result);
+ var_result = CallBuiltin(Builtins::kRegExpPrototypeExecSlow, context,
+ regexp, string);
Goto(&out);
}
@@ -1755,62 +1634,6 @@ Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
return var_result.value();
}
-// ES#sec-regexp.prototype.test
-// RegExp.prototype.test ( S )
-TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) {
- TNode<Object> maybe_receiver = CAST(Parameter(Descriptor::kReceiver));
- TNode<Object> maybe_string = CAST(Parameter(Descriptor::kString));
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
-
- // Ensure {maybe_receiver} is a JSReceiver.
- ThrowIfNotJSReceiver(context, maybe_receiver,
- MessageTemplate::kIncompatibleMethodReceiver,
- "RegExp.prototype.test");
- TNode<JSReceiver> receiver = CAST(maybe_receiver);
-
- // Convert {maybe_string} to a String.
- TNode<String> string = ToString_Inline(context, maybe_string);
-
- Label fast_path(this), slow_path(this);
- BranchIfFastRegExp(context, receiver, &fast_path, &slow_path);
-
- BIND(&fast_path);
- {
- Label if_didnotmatch(this);
- RegExpPrototypeExecBodyWithoutResult(context, receiver, string,
- &if_didnotmatch, true);
- Return(TrueConstant());
-
- BIND(&if_didnotmatch);
- Return(FalseConstant());
- }
-
- BIND(&slow_path);
- {
- // Call exec.
- TNode<HeapObject> match_indices =
- CAST(RegExpExec(context, receiver, string));
-
- // Return true iff exec matched successfully.
- Return(SelectBooleanConstant(IsNotNull(match_indices)));
- }
-}
-
-TF_BUILTIN(RegExpPrototypeTestFast, RegExpBuiltinsAssembler) {
- TNode<JSRegExp> regexp = CAST(Parameter(Descriptor::kReceiver));
- TNode<String> string = CAST(Parameter(Descriptor::kString));
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
-
- Label if_didnotmatch(this);
- CSA_ASSERT(this, IsFastRegExpWithOriginalExec(context, regexp));
- RegExpPrototypeExecBodyWithoutResult(context, regexp, string, &if_didnotmatch,
- true);
- Return(TrueConstant());
-
- BIND(&if_didnotmatch);
- Return(FalseConstant());
-}
-
TNode<Number> RegExpBuiltinsAssembler::AdvanceStringIndex(
SloppyTNode<String> string, SloppyTNode<Number> index,
SloppyTNode<BoolT> is_unicode, bool is_fastpath) {
@@ -1852,12 +1675,12 @@ TNode<Number> RegExpBuiltinsAssembler::AdvanceStringIndex(
TNode<IntPtrT> untagged_plus_one = SmiUntag(CAST(index_plus_one));
GotoIfNot(IntPtrLessThan(untagged_plus_one, string_length), &out);
- Node* const lead = StringCharCodeAt(string, SmiUntag(CAST(index)));
+ TNode<Int32T> const lead = StringCharCodeAt(string, SmiUntag(CAST(index)));
GotoIfNot(Word32Equal(Word32And(lead, Int32Constant(0xFC00)),
Int32Constant(0xD800)),
&out);
- Node* const trail = StringCharCodeAt(string, untagged_plus_one);
+ TNode<Int32T> const trail = StringCharCodeAt(string, untagged_plus_one);
GotoIfNot(Word32Equal(Word32And(trail, Int32Constant(0xFC00)),
Int32Constant(0xDC00)),
&out);
@@ -1873,29 +1696,34 @@ TNode<Number> RegExpBuiltinsAssembler::AdvanceStringIndex(
return var_result.value();
}
-void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(TNode<Context> context,
- TNode<Object> regexp,
- TNode<String> string,
- const bool is_fastpath) {
- if (is_fastpath) CSA_ASSERT(this, IsFastRegExp(context, regexp));
+TNode<Object> RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(
+ TNode<Context> context, TNode<Object> regexp, TNode<String> string,
+ const bool is_fastpath) {
+ if (is_fastpath) {
+ CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) {
+ BranchIfFastRegExp_Strict(context, CAST(regexp), ok, not_ok);
+ });
+ }
- Node* const is_global =
+ TVARIABLE(Object, var_result);
+
+ TNode<BoolT> const is_global =
FlagGetter(context, regexp, JSRegExp::kGlobal, is_fastpath);
- Label if_isglobal(this), if_isnotglobal(this);
+ Label if_isglobal(this), if_isnotglobal(this), done(this);
Branch(is_global, &if_isglobal, &if_isnotglobal);
BIND(&if_isnotglobal);
{
- Node* const result = is_fastpath ? RegExpPrototypeExecBody(
- context, CAST(regexp), string, true)
- : RegExpExec(context, regexp, string);
- Return(result);
+ var_result = is_fastpath ? RegExpPrototypeExecBody(context, CAST(regexp),
+ string, true)
+ : RegExpExec(context, regexp, string);
+ Goto(&done);
}
BIND(&if_isglobal);
{
- Node* const is_unicode =
+ TNode<BoolT> const is_unicode =
FlagGetter(context, regexp, JSRegExp::kUnicode, is_fastpath);
StoreLastIndex(context, regexp, SmiZero(), is_fastpath);
@@ -1939,15 +1767,14 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(TNode<Context> context,
TNode<RegExpMatchInfo> match_indices =
RegExpPrototypeExecBodyWithoutResult(context, CAST(regexp), string,
&if_didnotmatch, true);
-
Label dosubstring(this), donotsubstring(this);
Branch(var_atom.value(), &donotsubstring, &dosubstring);
BIND(&dosubstring);
{
- Node* const match_from = UnsafeLoadFixedArrayElement(
+ TNode<Object> const match_from = UnsafeLoadFixedArrayElement(
match_indices, RegExpMatchInfo::kFirstCaptureIndex);
- Node* const match_to = UnsafeLoadFixedArrayElement(
+ TNode<Object> const match_to = UnsafeLoadFixedArrayElement(
match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1);
var_match.Bind(CallBuiltin(Builtins::kSubString, context, string,
match_from, match_to));
@@ -1959,7 +1786,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(TNode<Context> context,
Goto(&if_didmatch);
} else {
DCHECK(!is_fastpath);
- Node* const result = RegExpExec(context, regexp, string);
+ TNode<Object> const result = RegExpExec(context, regexp, string);
Label load_match(this);
Branch(IsNull(result), &if_didnotmatch, &load_match);
@@ -1974,7 +1801,8 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(TNode<Context> context,
{
// Return null if there were no matches, otherwise just exit the loop.
GotoIfNot(IntPtrEqual(array.length(), IntPtrZero()), &out);
- Return(NullConstant());
+ var_result = NullConstant();
+ Goto(&done);
}
BIND(&if_didmatch);
@@ -1990,15 +1818,15 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(TNode<Context> context,
TNode<Smi> const match_length = LoadStringLengthAsSmi(match);
GotoIfNot(SmiEqual(match_length, SmiZero()), &loop);
- Node* last_index = LoadLastIndex(context, regexp, is_fastpath);
+ TNode<Object> last_index = LoadLastIndex(context, regexp, is_fastpath);
if (is_fastpath) {
CSA_ASSERT(this, TaggedIsPositiveSmi(last_index));
} else {
last_index = ToLength_Inline(context, last_index);
}
- TNode<Number> new_last_index =
- AdvanceStringIndex(string, last_index, is_unicode, is_fastpath);
+ TNode<Number> new_last_index = AdvanceStringIndex(
+ string, CAST(last_index), is_unicode, is_fastpath);
if (is_fastpath) {
// On the fast path, we can be certain that lastIndex can never be
@@ -2018,38 +1846,13 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(TNode<Context> context,
{
// Wrap the match in a JSArray.
- Node* const result = array.ToJSArray(context);
- Return(result);
+ var_result = array.ToJSArray(context);
+ Goto(&done);
}
}
-}
-
-// ES#sec-regexp.prototype-@@match
-// RegExp.prototype [ @@match ] ( string )
-TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) {
- TNode<Object> maybe_receiver = CAST(Parameter(Descriptor::kReceiver));
- TNode<Object> maybe_string = CAST(Parameter(Descriptor::kString));
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- // Ensure {maybe_receiver} is a JSReceiver.
- ThrowIfNotJSReceiver(context, maybe_receiver,
- MessageTemplate::kIncompatibleMethodReceiver,
- "RegExp.prototype.@@match");
- TNode<JSReceiver> receiver = CAST(maybe_receiver);
-
- // Convert {maybe_string} to a String.
- TNode<String> const string = ToString_Inline(context, maybe_string);
-
- Label fast_path(this), slow_path(this);
- BranchIfFastRegExp(context, receiver, &fast_path, &slow_path);
-
- BIND(&fast_path);
- // TODO(pwong): Could be optimized to remove the overhead of calling the
- // builtin (at the cost of a larger builtin).
- Return(CallBuiltin(Builtins::kRegExpMatchFast, context, receiver, string));
-
- BIND(&slow_path);
- RegExpPrototypeMatchBody(context, receiver, string, false);
+ BIND(&done);
+ return var_result.value();
}
void RegExpMatchAllAssembler::Generate(TNode<Context> context,
@@ -2066,12 +1869,17 @@ void RegExpMatchAllAssembler::Generate(TNode<Context> context,
TNode<String> string = ToString_Inline(context, maybe_string);
TVARIABLE(Object, var_matcher);
- TVARIABLE(Int32T, var_global);
- TVARIABLE(Int32T, var_unicode);
+ TVARIABLE(BoolT, var_global);
+ TVARIABLE(BoolT, var_unicode);
Label create_iterator(this), if_fast_regexp(this),
if_slow_regexp(this, Label::kDeferred);
- BranchIfFastRegExp(context, receiver, &if_fast_regexp, &if_slow_regexp);
+ // Strict, because following code uses the flags property.
+ // TODO(jgruber): Handle slow flag accesses on the fast path and make this
+ // permissive.
+ BranchIfFastRegExp_Strict(context, CAST(receiver), &if_fast_regexp,
+ &if_slow_regexp);
+
BIND(&if_fast_regexp);
{
TNode<JSRegExp> fast_regexp = CAST(receiver);
@@ -2081,9 +1889,10 @@ void RegExpMatchAllAssembler::Generate(TNode<Context> context,
// 4. Let C be ? SpeciesConstructor(R, %RegExp%).
// 5. Let flags be ? ToString(? Get(R, "flags")).
// 6. Let matcher be ? Construct(C, « R, flags »).
- TNode<String> flags = CAST(FlagsGetter(context, fast_regexp, true));
+ TNode<String> flags = FlagsGetter(context, fast_regexp, true);
var_matcher = RegExpCreate(context, native_context, source, flags);
- CSA_ASSERT(this, IsFastRegExp(context, var_matcher.value()));
+ CSA_ASSERT(this,
+ IsFastRegExpPermissive(context, CAST(var_matcher.value())));
// 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
// 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
@@ -2130,8 +1939,7 @@ void RegExpMatchAllAssembler::Generate(TNode<Context> context,
TNode<Smi> global_ix =
CAST(CallBuiltin(Builtins::kStringIndexOf, context, flags_string,
global_char_string, SmiZero()));
- var_global =
- SelectInt32Constant(SmiEqual(global_ix, SmiConstant(-1)), 0, 1);
+ var_global = SmiNotEqual(global_ix, SmiConstant(-1));
// 11. If flags contains "u", let fullUnicode be true.
// 12. Else, let fullUnicode be false.
@@ -2139,13 +1947,23 @@ void RegExpMatchAllAssembler::Generate(TNode<Context> context,
TNode<Smi> unicode_ix =
CAST(CallBuiltin(Builtins::kStringIndexOf, context, flags_string,
unicode_char_string, SmiZero()));
- var_unicode =
- SelectInt32Constant(SmiEqual(unicode_ix, SmiConstant(-1)), 0, 1);
+ var_unicode = SmiNotEqual(unicode_ix, SmiConstant(-1));
Goto(&create_iterator);
}
BIND(&create_iterator);
{
+ {
+ // UseCounter for matchAll with non-g RegExp.
+ // https://crbug.com/v8/9551
+ Label next(this);
+ GotoIf(var_global.value(), &next);
+ CallRuntime(Runtime::kIncrementUseCounter, context,
+ SmiConstant(v8::Isolate::kRegExpMatchAllWithNonGlobalRegExp));
+ Goto(&next);
+ BIND(&next);
+ }
+
// 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode).
TNode<Object> iterator =
CreateRegExpStringIterator(native_context, var_matcher.value(), string,
@@ -2158,7 +1976,7 @@ void RegExpMatchAllAssembler::Generate(TNode<Context> context,
// CreateRegExpStringIterator ( R, S, global, fullUnicode )
TNode<Object> RegExpMatchAllAssembler::CreateRegExpStringIterator(
TNode<Context> native_context, TNode<Object> regexp, TNode<String> string,
- TNode<Int32T> global, TNode<Int32T> full_unicode) {
+ TNode<BoolT> global, TNode<BoolT> full_unicode) {
TNode<Map> map = CAST(LoadContextElement(
native_context,
Context::INITIAL_REGEXP_STRING_ITERATOR_PROTOTYPE_MAP_INDEX));
@@ -2166,7 +1984,7 @@ TNode<Object> RegExpMatchAllAssembler::CreateRegExpStringIterator(
// 4. Let iterator be ObjectCreate(%RegExpStringIteratorPrototype%, «
// [[IteratingRegExp]], [[IteratedString]], [[Global]], [[Unicode]],
// [[Done]] »).
- TNode<Object> iterator = Allocate(JSRegExpStringIterator::kSize);
+ TNode<HeapObject> iterator = Allocate(JSRegExpStringIterator::kSize);
StoreMapNoWriteBarrier(iterator, map);
StoreObjectFieldRoot(iterator,
JSRegExpStringIterator::kPropertiesOrHashOffset,
@@ -2182,26 +2000,18 @@ TNode<Object> RegExpMatchAllAssembler::CreateRegExpStringIterator(
StoreObjectFieldNoWriteBarrier(
iterator, JSRegExpStringIterator::kIteratedStringOffset, string);
-#ifdef DEBUG
- // Verify global and full_unicode can be bitwise shifted without masking.
- TNode<Int32T> zero = Int32Constant(0);
- TNode<Int32T> one = Int32Constant(1);
- CSA_ASSERT(this,
- Word32Or(Word32Equal(global, zero), Word32Equal(global, one)));
- CSA_ASSERT(this, Word32Or(Word32Equal(full_unicode, zero),
- Word32Equal(full_unicode, one)));
-#endif // DEBUG
-
// 7. Set iterator.[[Global]] to global.
// 8. Set iterator.[[Unicode]] to fullUnicode.
// 9. Set iterator.[[Done]] to false.
- TNode<Word32T> global_flag =
- Word32Shl(global, Int32Constant(JSRegExpStringIterator::kGlobalBit));
- TNode<Word32T> unicode_flag = Word32Shl(
- full_unicode, Int32Constant(JSRegExpStringIterator::kUnicodeBit));
- TNode<Word32T> iterator_flags = Word32Or(global_flag, unicode_flag);
+ TNode<Int32T> global_flag =
+ Word32Shl(ReinterpretCast<Int32T>(global),
+ Int32Constant(JSRegExpStringIterator::kGlobalBit));
+ TNode<Int32T> unicode_flag =
+ Word32Shl(ReinterpretCast<Int32T>(full_unicode),
+ Int32Constant(JSRegExpStringIterator::kUnicodeBit));
+ TNode<Int32T> iterator_flags = Word32Or(global_flag, unicode_flag);
StoreObjectFieldNoWriteBarrier(iterator, JSRegExpStringIterator::kFlagsOffset,
- SmiFromInt32(Signed(iterator_flags)));
+ SmiFromInt32(iterator_flags));
return iterator;
}
@@ -2210,26 +2020,15 @@ TNode<Object> RegExpMatchAllAssembler::CreateRegExpStringIterator(
// RegExp.prototype [ @@matchAll ] ( string )
TF_BUILTIN(RegExpPrototypeMatchAll, RegExpMatchAllAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<Object> maybe_string = CAST(Parameter(Descriptor::kString));
Generate(context, native_context, receiver, maybe_string);
}
-// Helper that skips a few initial checks. and assumes...
-// 1) receiver is a "fast" RegExp
-// 2) pattern is a string
-TF_BUILTIN(RegExpMatchFast, RegExpBuiltinsAssembler) {
- TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- TNode<String> string = CAST(Parameter(Descriptor::kPattern));
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
-
- RegExpPrototypeMatchBody(context, receiver, string, true);
-}
-
void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast(
TNode<Context> context, TNode<JSRegExp> regexp, TNode<String> string) {
- CSA_ASSERT(this, IsFastRegExp(context, regexp));
+ CSA_ASSERT(this, IsFastRegExpPermissive(context, regexp));
// Grab the initial value of last index.
TNode<Smi> previous_last_index = FastLoadLastIndex(regexp);
@@ -2248,7 +2047,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast(
FastStoreLastIndex(regexp, previous_last_index);
// Return the index of the match.
- Node* const index = LoadFixedArrayElement(
+ TNode<Object> const index = LoadFixedArrayElement(
match_indices, RegExpMatchInfo::kFirstCaptureIndex);
Return(index);
}
@@ -2262,17 +2061,17 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast(
}
void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
- Node* const context, Node* const regexp, Node* const string) {
+ TNode<Context> context, Node* const regexp, Node* const string) {
CSA_ASSERT(this, IsJSReceiver(regexp));
CSA_ASSERT(this, IsString(string));
Isolate* const isolate = this->isolate();
- Node* const smi_zero = SmiZero();
+ TNode<Smi> const smi_zero = SmiZero();
// Grab the initial value of last index.
- Node* const previous_last_index =
- SlowLoadLastIndex(CAST(context), CAST(regexp));
+ TNode<Object> const previous_last_index =
+ SlowLoadLastIndex(context, CAST(regexp));
// Ensure last index is 0.
{
@@ -2286,13 +2085,13 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
}
// Call exec.
- Node* const exec_result = RegExpExec(context, regexp, string);
+ TNode<Object> const exec_result = RegExpExec(context, regexp, string);
// Reset last index if necessary.
{
Label next(this), slow(this, Label::kDeferred);
- Node* const current_last_index =
- SlowLoadLastIndex(CAST(context), CAST(regexp));
+ TNode<Object> const current_last_index =
+ SlowLoadLastIndex(context, CAST(regexp));
BranchIfSameValue(current_last_index, previous_last_index, &next, &slow);
@@ -2317,8 +2116,8 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
BIND(&fast_result);
{
- Node* const index =
- LoadObjectField(exec_result, JSRegExpResult::kIndexOffset);
+ TNode<Object> const index =
+ LoadObjectField(CAST(exec_result), JSRegExpResult::kIndexOffset);
Return(index);
}
@@ -2341,13 +2140,13 @@ TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) {
ThrowIfNotJSReceiver(context, maybe_receiver,
MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.@@search");
- Node* const receiver = maybe_receiver;
+ TNode<JSReceiver> receiver = CAST(maybe_receiver);
// Convert {maybe_string} to a String.
TNode<String> const string = ToString_Inline(context, maybe_string);
Label fast_path(this), slow_path(this);
- BranchIfFastRegExp(context, receiver, &fast_path, &slow_path);
+ BranchIfFastRegExp_Permissive(context, receiver, &fast_path, &slow_path);
BIND(&fast_path);
// TODO(pwong): Could be optimized to remove the overhead of calling the
@@ -2371,13 +2170,12 @@ TF_BUILTIN(RegExpSearchFast, RegExpBuiltinsAssembler) {
// Generates the fast path for @@split. {regexp} is an unmodified, non-sticky
// JSRegExp, {string} is a String, and {limit} is a Smi.
-void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
- Node* const regexp,
+void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(TNode<Context> context,
+ TNode<JSRegExp> regexp,
TNode<String> string,
TNode<Smi> const limit) {
- CSA_ASSERT(this, IsFastRegExp(context, regexp));
- CSA_ASSERT(this,
- Word32BinaryNot(FastFlagGetter(CAST(regexp), JSRegExp::kSticky)));
+ CSA_ASSERT(this, IsFastRegExpPermissive(context, regexp));
+ CSA_ASSERT(this, Word32BinaryNot(FastFlagGetter(regexp, JSRegExp::kSticky)));
TNode<IntPtrT> const int_limit = SmiUntag(limit);
@@ -2385,7 +2183,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS;
Node* const allocation_site = nullptr;
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context);
Label return_empty_array(this, Label::kDeferred);
@@ -2407,10 +2205,10 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
BIND(&if_stringisempty);
{
- Node* const last_match_info = LoadContextElement(
+ TNode<Object> const last_match_info = LoadContextElement(
native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
- Node* const match_indices =
+ TNode<Object> const match_indices =
CallBuiltin(Builtins::kRegExpExecInternal, context, regexp, string,
SmiZero(), last_match_info);
@@ -2464,7 +2262,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
// Search for the given {regexp}.
- Node* const last_match_info = LoadContextElement(
+ TNode<Object> const last_match_info = LoadContextElement(
native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
TNode<HeapObject> const match_indices_ho =
@@ -2499,8 +2297,9 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
GotoIfNot(SmiEqual(match_to, next_search_from), &next);
GotoIfNot(SmiEqual(match_to, last_matched_until), &next);
- Node* const is_unicode = FastFlagGetter(CAST(regexp), JSRegExp::kUnicode);
- Node* const new_next_search_from =
+ TNode<BoolT> const is_unicode =
+ FastFlagGetter(regexp, JSRegExp::kUnicode);
+ TNode<Number> const new_next_search_from =
AdvanceStringIndex(string, next_search_from, is_unicode, true);
var_next_search_from = CAST(new_next_search_from);
Goto(&loop);
@@ -2518,9 +2317,9 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
// Add all captures to the array.
{
- Node* const num_registers = LoadFixedArrayElement(
- match_indices, RegExpMatchInfo::kNumberOfCapturesIndex);
- Node* const int_num_registers = SmiUntag(num_registers);
+ TNode<Smi> const num_registers = CAST(LoadFixedArrayElement(
+ match_indices, RegExpMatchInfo::kNumberOfCapturesIndex));
+ TNode<IntPtrT> const int_num_registers = SmiUntag(num_registers);
VARIABLE(var_reg, MachineType::PointerRepresentation());
var_reg.Bind(IntPtrConstant(2));
@@ -2535,7 +2334,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
BIND(&nested_loop);
{
Node* const reg = var_reg.value();
- Node* const from = LoadFixedArrayElement(
+ TNode<Object> const from = LoadFixedArrayElement(
match_indices, reg,
RegExpMatchInfo::kFirstCaptureIndex * kTaggedSize, mode);
TNode<Smi> const to = CAST(LoadFixedArrayElement(
@@ -2565,7 +2364,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
array.Push(CAST(var_value.value()));
GotoIf(WordEqual(array.length(), int_limit), &out);
- Node* const new_reg = IntPtrAdd(reg, IntPtrConstant(2));
+ TNode<WordT> const new_reg = IntPtrAdd(reg, IntPtrConstant(2));
var_reg.Bind(new_reg);
Branch(IntPtrLessThan(new_reg, int_num_registers), &nested_loop,
@@ -2583,7 +2382,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
BIND(&push_suffix_and_out);
{
- Node* const from = var_last_matched_until.value();
+ TNode<Smi> const from = var_last_matched_until.value();
Node* const to = string_length;
array.Push(CallBuiltin(Builtins::kSubString, context, string, from, to));
Goto(&out);
@@ -2591,7 +2390,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
BIND(&out);
{
- Node* const result = array.ToJSArray(CAST(context));
+ TNode<JSArray> const result = array.ToJSArray(context);
Return(result);
}
@@ -2612,11 +2411,9 @@ TF_BUILTIN(RegExpSplit, RegExpBuiltinsAssembler) {
TNode<Object> maybe_limit = CAST(Parameter(Descriptor::kLimit));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- CSA_ASSERT(this, IsFastRegExp(context, regexp));
-
- // TODO(jgruber): Even if map checks send us to the fast path, we still need
- // to verify the constructor property and jump to the slow path if it has
- // been changed.
+ CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) {
+ BranchIfFastRegExp_Strict(context, regexp, ok, not_ok);
+ });
// Verify {maybe_limit}.
@@ -2679,13 +2476,16 @@ TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
ThrowIfNotJSReceiver(context, maybe_receiver,
MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.@@split");
- Node* const receiver = maybe_receiver;
+ TNode<JSReceiver> receiver = CAST(maybe_receiver);
// Convert {maybe_string} to a String.
- TNode<String> const string = ToString_Inline(context, maybe_string);
+ TNode<String> string = ToString_Inline(context, maybe_string);
+ // Strict: Reads the flags property.
+ // TODO(jgruber): Handle slow flag accesses on the fast path and make this
+ // permissive.
Label stub(this), runtime(this, Label::kDeferred);
- BranchIfFastRegExp(context, receiver, &stub, &runtime);
+ BranchIfFastRegExp_Strict(context, receiver, &stub, &runtime);
BIND(&stub);
args.PopAndReturn(CallBuiltin(Builtins::kRegExpSplit, context, receiver,
@@ -2753,12 +2553,11 @@ TF_BUILTIN(RegExpStringIteratorPrototypeNext, RegExpStringIteratorAssembler) {
GotoIf(HasDoneFlag(flags), &return_empty_done_result);
// 5. Let R be O.[[IteratingRegExp]].
- TNode<Object> iterating_regexp =
- LoadObjectField(receiver, JSRegExpStringIterator::kIteratingRegExpOffset);
+ TNode<JSReceiver> iterating_regexp = CAST(LoadObjectField(
+ receiver, JSRegExpStringIterator::kIteratingRegExpOffset));
- // TODO(jgruber): Verify that this is guaranteed.
- CSA_CHECK(this, TaggedIsNotSmi(iterating_regexp));
- CSA_CHECK(this, IsJSReceiver(CAST(iterating_regexp)));
+ // For extra safety, also check the type in release mode.
+ CSA_CHECK(this, IsJSReceiver(iterating_regexp));
// 6. Let S be O.[[IteratedString]].
TNode<String> iterating_string = CAST(
@@ -2775,23 +2574,23 @@ TF_BUILTIN(RegExpStringIteratorPrototypeNext, RegExpStringIteratorAssembler) {
TVARIABLE(BoolT, var_is_fast_regexp);
{
Label if_fast(this), if_slow(this, Label::kDeferred);
- BranchIfFastRegExp(context, iterating_regexp, &if_fast, &if_slow);
+ BranchIfFastRegExp_Permissive(context, iterating_regexp, &if_fast,
+ &if_slow);
BIND(&if_fast);
{
TNode<RegExpMatchInfo> match_indices =
- RegExpPrototypeExecBodyWithoutResult(context, CAST(iterating_regexp),
- iterating_string, &if_no_match,
- true);
+ RegExpPrototypeExecBodyWithoutResult(
+ context, iterating_regexp, iterating_string, &if_no_match, true);
var_match = ConstructNewResultFromMatchInfo(
- context, CAST(iterating_regexp), match_indices, iterating_string);
+ context, iterating_regexp, match_indices, iterating_string);
var_is_fast_regexp = Int32TrueConstant();
Goto(&if_match);
}
BIND(&if_slow);
{
- var_match = CAST(RegExpExec(context, iterating_regexp, iterating_string));
+ var_match = RegExpExec(context, iterating_regexp, iterating_string);
var_is_fast_regexp = Int32FalseConstant();
Branch(IsNull(var_match.value()), &if_no_match, &if_match);
}
@@ -2836,7 +2635,7 @@ TF_BUILTIN(RegExpStringIteratorPrototypeNext, RegExpStringIteratorAssembler) {
// When iterating_regexp is fast, we assume it stays fast even after
// accessing the first match from the RegExp result.
- CSA_ASSERT(this, IsFastRegExp(context, iterating_regexp));
+ CSA_ASSERT(this, IsFastRegExpPermissive(context, iterating_regexp));
GotoIfNot(IsEmptyString(match_str), &return_result);
// 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
diff --git a/deps/v8/src/builtins/builtins-regexp-gen.h b/deps/v8/src/builtins/builtins-regexp-gen.h
index 3677314f19..de841f57b2 100644
--- a/deps/v8/src/builtins/builtins-regexp-gen.h
+++ b/deps/v8/src/builtins/builtins-regexp-gen.h
@@ -17,11 +17,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
explicit RegExpBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
- void BranchIfFastRegExp(
- Node* const context, Node* const object, Node* const map,
- base::Optional<DescriptorIndexAndName> additional_property_to_check,
- Label* const if_isunmodified, Label* const if_ismodified);
-
// Create and initialize a RegExp object.
TNode<Object> RegExpCreate(TNode<Context> context,
TNode<Context> native_context,
@@ -35,6 +30,8 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
TNode<Smi> SmiZero();
TNode<IntPtrT> IntPtrZero();
+ TNode<RawPtrT> LoadCodeObjectEntry(TNode<Code> code);
+
// Allocate a RegExpResult with the given length (the number of captures,
// including the match itself), index (the index where the match starts),
// and input string.
@@ -53,7 +50,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
void FastStoreLastIndex(TNode<JSRegExp> regexp, TNode<Smi> value);
void SlowStoreLastIndex(SloppyTNode<Context> context,
SloppyTNode<Object> regexp,
- SloppyTNode<Number> value);
+ SloppyTNode<Object> value);
void StoreLastIndex(TNode<Context> context, TNode<Object> regexp,
TNode<Number> value, bool is_fastpath);
@@ -79,7 +76,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
TNode<Context> context, TNode<JSReceiver> maybe_regexp,
TNode<String> string, Label* if_didnotmatch, const bool is_fastpath);
TNode<RegExpMatchInfo> RegExpPrototypeExecBodyWithoutResultFast(
- TNode<Context> context, TNode<JSReceiver> maybe_regexp,
+ TNode<Context> context, TNode<JSRegExp> maybe_regexp,
TNode<String> string, Label* if_didnotmatch);
TNode<HeapObject> RegExpPrototypeExecBody(TNode<Context> context,
@@ -87,50 +84,90 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
TNode<String> string,
const bool is_fastpath);
- Node* ThrowIfNotJSReceiver(Node* context, Node* maybe_receiver,
- MessageTemplate msg_template,
- char const* method_name);
-
- // Analogous to BranchIfFastRegExp, for use in asserts.
- TNode<BoolT> IsFastRegExp(SloppyTNode<Context> context,
- SloppyTNode<Object> object);
+ TNode<BoolT> IsReceiverInitialRegExpPrototype(SloppyTNode<Context> context,
+ SloppyTNode<Object> receiver);
+
+ // Fast path check logic.
+ //
+ // Are you afraid? If not, you should be.
+ //
+ // It's complicated. Fast path checks protect certain assumptions, e.g. that
+ // relevant properties on the regexp prototype (such as exec, @@split, global)
+ // are unmodified.
+ //
+ // These assumptions differ by callsite. For example, RegExpPrototypeExec
+ // cares whether the exec property has been modified; but it's totally fine
+ // to modify other prototype properties. On the other hand,
+ // StringPrototypeSplit does care very much whether @@split has been changed.
+ //
+ // We want to keep regexp execution on the fast path as much as possible.
+ // Ideally, we could simply check if the regexp prototype has been modified;
+ // yet common web frameworks routinely mutate it for various reasons. But most
+ // of these mutations should happen in a way that still allows us to remain
+ // on the fast path. To support this, the fast path check logic necessarily
+ // becomes more involved.
+ //
+ // There are multiple knobs to twiddle for regexp fast path checks. We support
+ // checks that completely ignore the prototype, checks that verify specific
+ // properties on the prototype (the caller must ensure it passes in the right
+ // ones), and strict checks that additionally ensure the prototype is
+ // unchanged (we use these when we'd have to check multiple properties we
+ // don't care too much about, e.g. all individual flag getters).
+
+ using DescriptorIndexNameValue =
+ PrototypeCheckAssembler::DescriptorIndexNameValue;
- void BranchIfFastRegExp(Node* const context, Node* const object,
- Label* const if_isunmodified,
- Label* const if_ismodified);
+ void BranchIfFastRegExp(
+ TNode<Context> context, TNode<HeapObject> object, TNode<Map> map,
+ PrototypeCheckAssembler::Flags prototype_check_flags,
+ base::Optional<DescriptorIndexNameValue> additional_property_to_check,
+ Label* if_isunmodified, Label* if_ismodified);
+
+ // Strict: Does not tolerate any changes to the prototype map.
+ // Permissive: Allows changes to the prototype map except for the exec
+ // property.
+ void BranchIfFastRegExp_Strict(TNode<Context> context,
+ TNode<HeapObject> object,
+ Label* if_isunmodified, Label* if_ismodified);
+ void BranchIfFastRegExp_Permissive(TNode<Context> context,
+ TNode<HeapObject> object,
+ Label* if_isunmodified,
+ Label* if_ismodified);
// Performs fast path checks on the given object itself, but omits prototype
// checks.
- Node* IsFastRegExpNoPrototype(Node* const context, Node* const object);
+ Node* IsFastRegExpNoPrototype(SloppyTNode<Context> context,
+ SloppyTNode<Object> object);
+ Node* IsFastRegExpNoPrototype(SloppyTNode<Context> context,
+ SloppyTNode<Object> object,
+ SloppyTNode<Map> map);
+
+ // For debugging only. Uses a slow GetProperty call to fetch object.exec.
TNode<BoolT> IsFastRegExpWithOriginalExec(TNode<Context> context,
TNode<JSRegExp> object);
- Node* IsFastRegExpNoPrototype(Node* const context, Node* const object,
- Node* const map);
void BranchIfFastRegExpResult(Node* const context, Node* const object,
Label* if_isunmodified, Label* if_ismodified);
- Node* FlagsGetter(Node* const context, Node* const regexp, bool is_fastpath);
+ TNode<String> FlagsGetter(TNode<Context> context, TNode<Object> regexp,
+ const bool is_fastpath);
- TNode<Int32T> FastFlagGetter(TNode<JSRegExp> regexp, JSRegExp::Flag flag);
+ TNode<BoolT> FastFlagGetter(TNode<JSRegExp> regexp, JSRegExp::Flag flag);
TNode<BoolT> FastFlagGetterGlobal(TNode<JSRegExp> regexp) {
- return ReinterpretCast<BoolT>(FastFlagGetter(regexp, JSRegExp::kGlobal));
+ return FastFlagGetter(regexp, JSRegExp::kGlobal);
}
TNode<BoolT> FastFlagGetterUnicode(TNode<JSRegExp> regexp) {
- return ReinterpretCast<BoolT>(FastFlagGetter(regexp, JSRegExp::kUnicode));
+ return FastFlagGetter(regexp, JSRegExp::kUnicode);
}
- TNode<Int32T> SlowFlagGetter(TNode<Context> context, TNode<Object> regexp,
- JSRegExp::Flag flag);
- TNode<Int32T> FlagGetter(TNode<Context> context, TNode<Object> regexp,
- JSRegExp::Flag flag, bool is_fastpath);
-
- void FlagGetter(Node* context, Node* receiver, JSRegExp::Flag flag,
- int counter, const char* method_name);
+ TNode<BoolT> SlowFlagGetter(TNode<Context> context, TNode<Object> regexp,
+ JSRegExp::Flag flag);
+ TNode<BoolT> FlagGetter(TNode<Context> context, TNode<Object> regexp,
+ JSRegExp::Flag flag, bool is_fastpath);
Node* RegExpInitialize(Node* const context, Node* const regexp,
Node* const maybe_pattern, Node* const maybe_flags);
- Node* RegExpExec(Node* context, Node* regexp, Node* string);
+ TNode<Object> RegExpExec(TNode<Context> context, Node* regexp, Node* string);
TNode<Number> AdvanceStringIndex(SloppyTNode<String> string,
SloppyTNode<Number> index,
@@ -142,17 +179,18 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
return CAST(AdvanceStringIndex(string, index, is_unicode, true));
}
- void RegExpPrototypeMatchBody(TNode<Context> context, TNode<Object> regexp,
- TNode<String> const string,
- const bool is_fastpath);
+ TNode<Object> RegExpPrototypeMatchBody(TNode<Context> context,
+ TNode<Object> regexp,
+ TNode<String> const string,
+ const bool is_fastpath);
void RegExpPrototypeSearchBodyFast(TNode<Context> context,
TNode<JSRegExp> regexp,
TNode<String> string);
- void RegExpPrototypeSearchBodySlow(Node* const context, Node* const regexp,
+ void RegExpPrototypeSearchBodySlow(TNode<Context> context, Node* const regexp,
Node* const string);
- void RegExpPrototypeSplitBody(Node* const context, Node* const regexp,
+ void RegExpPrototypeSplitBody(TNode<Context> context, TNode<JSRegExp> regexp,
TNode<String> const string,
TNode<Smi> const limit);
};
@@ -165,8 +203,8 @@ class RegExpMatchAllAssembler : public RegExpBuiltinsAssembler {
TNode<Object> CreateRegExpStringIterator(TNode<Context> native_context,
TNode<Object> regexp,
TNode<String> string,
- TNode<Int32T> global,
- TNode<Int32T> full_unicode);
+ TNode<BoolT> global,
+ TNode<BoolT> full_unicode);
void Generate(TNode<Context> context, TNode<Context> native_context,
TNode<Object> receiver, TNode<Object> maybe_string);
};
diff --git a/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc b/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc
index 1e9ac8377c..8ae89187ec 100644
--- a/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc
+++ b/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc
@@ -26,7 +26,7 @@ class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler {
Node* value,
Node* value_high);
void ValidateSharedTypedArray(Node* tagged, Node* context,
- Node** out_elements_kind,
+ TNode<Int32T>* out_elements_kind,
Node** out_backing_store);
Node* ConvertTaggedAtomicIndexToWord32(Node* tagged, Node* context,
Node** number_index);
@@ -46,7 +46,7 @@ class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler {
};
void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
- Node* tagged, Node* context, Node** out_elements_kind,
+ Node* tagged, Node* context, TNode<Int32T>* out_elements_kind,
Node** out_backing_store) {
Label not_float_or_clamped(this), invalid(this);
@@ -54,7 +54,7 @@ void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
GotoIf(TaggedIsSmi(tagged), &invalid);
// Fail if the array's instance type is not JSTypedArray.
- Node* tagged_map = LoadMap(tagged);
+ TNode<Map> tagged_map = LoadMap(tagged);
GotoIfNot(IsJSTypedArrayMap(tagged_map), &invalid);
// Fail if the array's JSArrayBuffer is not shared.
@@ -69,7 +69,7 @@ void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
STATIC_ASSERT(UINT8_ELEMENTS < FLOAT32_ELEMENTS);
STATIC_ASSERT(UINT16_ELEMENTS < FLOAT32_ELEMENTS);
STATIC_ASSERT(UINT32_ELEMENTS < FLOAT32_ELEMENTS);
- Node* elements_kind = LoadMapElementsKind(tagged_map);
+ TNode<Int32T> elements_kind = LoadMapElementsKind(tagged_map);
GotoIf(Int32LessThan(elements_kind, Int32Constant(FLOAT32_ELEMENTS)),
&not_float_or_clamped);
STATIC_ASSERT(BIGINT64_ELEMENTS > UINT8_CLAMPED_ELEMENTS);
@@ -167,7 +167,7 @@ TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) {
Node* index = Parameter(Descriptor::kIndex);
Node* context = Parameter(Descriptor::kContext);
- Node* elements_kind;
+ TNode<Int32T> elements_kind;
Node* backing_store;
ValidateSharedTypedArray(array, context, &elements_kind, &backing_store);
@@ -175,7 +175,7 @@ TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) {
Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
ValidateAtomicIndex(array, index_word32, context);
- Node* index_word = ChangeUint32ToWord(index_word32);
+ TNode<UintPtrT> index_word = ChangeUint32ToWord(index_word32);
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
i64(this), u64(this), other(this);
@@ -239,7 +239,7 @@ TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) {
Node* value = Parameter(Descriptor::kValue);
Node* context = Parameter(Descriptor::kContext);
- Node* elements_kind;
+ TNode<Int32T> elements_kind;
Node* backing_store;
ValidateSharedTypedArray(array, context, &elements_kind, &backing_store);
@@ -247,14 +247,14 @@ TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) {
Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
ValidateAtomicIndex(array, index_word32, context);
- Node* index_word = ChangeUint32ToWord(index_word32);
+ TNode<UintPtrT> index_word = ChangeUint32ToWord(index_word32);
Label u8(this), u16(this), u32(this), u64(this), other(this);
STATIC_ASSERT(BIGINT64_ELEMENTS > INT32_ELEMENTS);
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &u64);
- Node* value_integer = ToInteger_Inline(CAST(context), CAST(value));
+ TNode<Number> value_integer = ToInteger_Inline(CAST(context), CAST(value));
Node* value_word32 = TruncateTaggedToWord32(context, value_integer);
#if DEBUG
@@ -313,7 +313,7 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
Node* value = Parameter(Descriptor::kValue);
Node* context = Parameter(Descriptor::kContext);
- Node* elements_kind;
+ TNode<Int32T> elements_kind;
Node* backing_store;
ValidateSharedTypedArray(array, context, &elements_kind, &backing_store);
@@ -326,7 +326,7 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
Return(CallRuntime(Runtime::kAtomicsExchange, context, array, index_integer,
value));
#else
- Node* index_word = ChangeUint32ToWord(index_word32);
+ TNode<UintPtrT> index_word = ChangeUint32ToWord(index_word32);
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
i64(this), u64(this), big(this), other(this);
@@ -334,7 +334,7 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big);
- Node* value_integer = ToInteger_Inline(CAST(context), CAST(value));
+ TNode<Number> value_integer = ToInteger_Inline(CAST(context), CAST(value));
#if DEBUG
DebugSanityCheckAtomicIndex(array, index_word32, context);
#endif
@@ -415,7 +415,7 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
Node* new_value = Parameter(Descriptor::kNewValue);
Node* context = Parameter(Descriptor::kContext);
- Node* elements_kind;
+ TNode<Int32T> elements_kind;
Node* backing_store;
ValidateSharedTypedArray(array, context, &elements_kind, &backing_store);
@@ -429,7 +429,7 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
Return(CallRuntime(Runtime::kAtomicsCompareExchange, context, array,
index_integer, old_value, new_value));
#else
- Node* index_word = ChangeUint32ToWord(index_word32);
+ TNode<UintPtrT> index_word = ChangeUint32ToWord(index_word32);
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
i64(this), u64(this), big(this), other(this);
@@ -437,8 +437,10 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big);
- Node* old_value_integer = ToInteger_Inline(CAST(context), CAST(old_value));
- Node* new_value_integer = ToInteger_Inline(CAST(context), CAST(new_value));
+ TNode<Number> old_value_integer =
+ ToInteger_Inline(CAST(context), CAST(old_value));
+ TNode<Number> new_value_integer =
+ ToInteger_Inline(CAST(context), CAST(new_value));
#if DEBUG
DebugSanityCheckAtomicIndex(array, index_word32, context);
#endif
@@ -543,7 +545,7 @@ BINOP_BUILTIN(Xor)
void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon(
Node* array, Node* index, Node* value, Node* context,
AssemblerFunction function, Runtime::FunctionId runtime_function) {
- Node* elements_kind;
+ TNode<Int32T> elements_kind;
Node* backing_store;
ValidateSharedTypedArray(array, context, &elements_kind, &backing_store);
@@ -556,7 +558,7 @@ void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon(
V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
Return(CallRuntime(runtime_function, context, array, index_integer, value));
#else
- Node* index_word = ChangeUint32ToWord(index_word32);
+ TNode<UintPtrT> index_word = ChangeUint32ToWord(index_word32);
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
i64(this), u64(this), big(this), other(this);
@@ -565,7 +567,7 @@ void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon(
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big);
- Node* value_integer = ToInteger_Inline(CAST(context), CAST(value));
+ TNode<Number> value_integer = ToInteger_Inline(CAST(context), CAST(value));
#if DEBUG
DebugSanityCheckAtomicIndex(array, index_word32, context);
#endif
diff --git a/deps/v8/src/builtins/builtins-sharedarraybuffer.cc b/deps/v8/src/builtins/builtins-sharedarraybuffer.cc
index fa6534d463..e6251c9480 100644
--- a/deps/v8/src/builtins/builtins-sharedarraybuffer.cc
+++ b/deps/v8/src/builtins/builtins-sharedarraybuffer.cc
@@ -22,8 +22,23 @@ namespace internal {
// See builtins-arraybuffer.cc for implementations of
// SharedArrayBuffer.prototye.byteLength and SharedArrayBuffer.prototype.slice
+// #sec-atomics.islockfree
inline bool AtomicIsLockFree(double size) {
- return size == 1 || size == 2 || size == 4;
+ // According to the standard, 1, 2, and 4 byte atomics are supposed to be
+ // 'lock free' on every platform. But what exactly does 'lock free' mean?
+ // For example, on x64 V8 uses a lock prefix to implement the semantics of
+ // many atomic operations. Is that considered a lock? Probably not.
+ //
+ // On the other hand, V8 emits a few instructions for some arm atomics which
+ // do appear to be a low level form of a spin lock. With an abundance of
+ // caution, we only claim to have 'true lock free' support for 8 byte sizes
+ // on x64 platforms. If people care about this function returning true, then
+ // we need to clarify exactly what 'lock free' means at the standard level.
+ bool is_lock_free = size == 1 || size == 2 || size == 4;
+#if V8_TARGET_ARCH_x64
+ is_lock_free |= size == 8;
+#endif
+ return is_lock_free;
}
// ES #sec-atomics.islockfree
@@ -37,12 +52,16 @@ BUILTIN(AtomicsIsLockFree) {
// ES #sec-validatesharedintegertypedarray
V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray(
- Isolate* isolate, Handle<Object> object, bool only_int32 = false) {
+ Isolate* isolate, Handle<Object> object,
+ bool only_int32_and_big_int64 = false) {
if (object->IsJSTypedArray()) {
Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object);
if (typed_array->GetBuffer()->is_shared()) {
- if (only_int32) {
- if (typed_array->type() == kExternalInt32Array) return typed_array;
+ if (only_int32_and_big_int64) {
+ if (typed_array->type() == kExternalInt32Array ||
+ typed_array->type() == kExternalBigInt64Array) {
+ return typed_array;
+ }
} else {
if (typed_array->type() != kExternalFloat32Array &&
typed_array->type() != kExternalFloat64Array &&
@@ -54,8 +73,9 @@ V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray(
THROW_NEW_ERROR(
isolate,
- NewTypeError(only_int32 ? MessageTemplate::kNotInt32SharedTypedArray
- : MessageTemplate::kNotIntegerSharedTypedArray,
+ NewTypeError(only_int32_and_big_int64
+ ? MessageTemplate::kNotInt32OrBigInt64SharedTypedArray
+ : MessageTemplate::kNotIntegerSharedTypedArray,
object),
JSTypedArray);
}
@@ -83,6 +103,15 @@ V8_WARN_UNUSED_RESULT Maybe<size_t> ValidateAtomicAccess(
}
namespace {
+
+inline size_t GetAddress64(size_t index, size_t byte_offset) {
+ return (index << 3) + byte_offset;
+}
+
+inline size_t GetAddress32(size_t index, size_t byte_offset) {
+ return (index << 2) + byte_offset;
+}
+
MaybeHandle<Object> AtomicsWake(Isolate* isolate, Handle<Object> array,
Handle<Object> index, Handle<Object> count) {
Handle<JSTypedArray> sta;
@@ -109,9 +138,19 @@ MaybeHandle<Object> AtomicsWake(Isolate* isolate, Handle<Object> array,
}
Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
- size_t addr = (i << 2) + sta->byte_offset();
- return Handle<Object>(FutexEmulation::Wake(array_buffer, addr, c), isolate);
+ if (sta->type() == kExternalBigInt64Array) {
+ return Handle<Object>(
+ FutexEmulation::Wake(array_buffer, GetAddress64(i, sta->byte_offset()),
+ c),
+ isolate);
+ } else {
+ DCHECK(sta->type() == kExternalInt32Array);
+ return Handle<Object>(
+ FutexEmulation::Wake(array_buffer, GetAddress32(i, sta->byte_offset()),
+ c),
+ isolate);
+ }
}
} // namespace
@@ -157,9 +196,16 @@ BUILTIN(AtomicsWait) {
if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
size_t i = maybe_index.FromJust();
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
- Object::ToInt32(isolate, value));
- int32_t value_int32 = NumberToInt32(*value);
+ // According to the spec, we have to check value's type before
+ // looking at the timeout.
+ if (sta->type() == kExternalBigInt64Array) {
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
+ BigInt::FromObject(isolate, value));
+ } else {
+ DCHECK(sta->type() == kExternalInt32Array);
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
+ Object::ToInt32(isolate, value));
+ }
double timeout_number;
if (timeout->IsUndefined(isolate)) {
@@ -180,10 +226,17 @@ BUILTIN(AtomicsWait) {
}
Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
- size_t addr = (i << 2) + sta->byte_offset();
- return FutexEmulation::WaitJs(isolate, array_buffer, addr, value_int32,
- timeout_number);
+ if (sta->type() == kExternalBigInt64Array) {
+ return FutexEmulation::WaitJs64(
+ isolate, array_buffer, GetAddress64(i, sta->byte_offset()),
+ Handle<BigInt>::cast(value)->AsInt64(), timeout_number);
+ } else {
+ DCHECK(sta->type() == kExternalInt32Array);
+ return FutexEmulation::WaitJs32(isolate, array_buffer,
+ GetAddress32(i, sta->byte_offset()),
+ NumberToInt32(*value), timeout_number);
+ }
}
} // namespace internal
diff --git a/deps/v8/src/builtins/builtins-string-gen.cc b/deps/v8/src/builtins/builtins-string-gen.cc
index 97dc8ca895..fc2745ed0a 100644
--- a/deps/v8/src/builtins/builtins-string-gen.cc
+++ b/deps/v8/src/builtins/builtins-string-gen.cc
@@ -65,11 +65,13 @@ void StringBuiltinsAssembler::DispatchOnStringEncodings(
// First combine the encodings.
- Node* const encoding_mask = Int32Constant(kStringEncodingMask);
- Node* const lhs_encoding = Word32And(lhs_instance_type, encoding_mask);
- Node* const rhs_encoding = Word32And(rhs_instance_type, encoding_mask);
+ TNode<Int32T> const encoding_mask = Int32Constant(kStringEncodingMask);
+ TNode<Word32T> const lhs_encoding =
+ Word32And(lhs_instance_type, encoding_mask);
+ TNode<Word32T> const rhs_encoding =
+ Word32And(rhs_instance_type, encoding_mask);
- Node* const combined_encodings =
+ TNode<Word32T> const combined_encodings =
Word32Or(lhs_encoding, Word32Shr(rhs_encoding, 1));
// Then dispatch on the combined encoding.
@@ -99,9 +101,9 @@ Node* StringBuiltinsAssembler::CallSearchStringRaw(Node* const subject_ptr,
Node* const search_ptr,
Node* const search_length,
Node* const start_position) {
- Node* const function_addr = ExternalConstant(
+ TNode<ExternalReference> const function_addr = ExternalConstant(
ExternalReference::search_string_raw<SubjectChar, PatternChar>());
- Node* const isolate_ptr =
+ TNode<ExternalReference> const isolate_ptr =
ExternalConstant(ExternalReference::isolate_address(isolate()));
MachineType type_ptr = MachineType::Pointer();
@@ -118,20 +120,20 @@ Node* StringBuiltinsAssembler::CallSearchStringRaw(Node* const subject_ptr,
return result;
}
-Node* StringBuiltinsAssembler::PointerToStringDataAtIndex(
+TNode<IntPtrT> StringBuiltinsAssembler::PointerToStringDataAtIndex(
Node* const string_data, Node* const index, String::Encoding encoding) {
const ElementsKind kind = (encoding == String::ONE_BYTE_ENCODING)
? UINT8_ELEMENTS
: UINT16_ELEMENTS;
- Node* const offset_in_bytes =
+ TNode<IntPtrT> const offset_in_bytes =
ElementOffsetFromIndex(index, kind, INTPTR_PARAMETERS);
- return IntPtrAdd(string_data, offset_in_bytes);
+ return Signed(IntPtrAdd(string_data, offset_in_bytes));
}
-void StringBuiltinsAssembler::GenerateStringEqual(Node* context, Node* left,
- Node* right) {
- VARIABLE(var_left, MachineRepresentation::kTagged, left);
- VARIABLE(var_right, MachineRepresentation::kTagged, right);
+void StringBuiltinsAssembler::GenerateStringEqual(TNode<String> left,
+ TNode<String> right) {
+ TVARIABLE(String, var_left, left);
+ TVARIABLE(String, var_right, right);
Label if_equal(this), if_notequal(this), if_indirect(this, Label::kDeferred),
restart(this, {&var_left, &var_right});
@@ -143,14 +145,14 @@ void StringBuiltinsAssembler::GenerateStringEqual(Node* context, Node* left,
Goto(&restart);
BIND(&restart);
- Node* lhs = var_left.value();
- Node* rhs = var_right.value();
+ TNode<String> lhs = var_left.value();
+ TNode<String> rhs = var_right.value();
- Node* lhs_instance_type = LoadInstanceType(lhs);
- Node* rhs_instance_type = LoadInstanceType(rhs);
+ TNode<Uint16T> lhs_instance_type = LoadInstanceType(lhs);
+ TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs);
- StringEqual_Core(context, lhs, lhs_instance_type, rhs, rhs_instance_type,
- lhs_length, &if_equal, &if_notequal, &if_indirect);
+ StringEqual_Core(lhs, lhs_instance_type, rhs, rhs_instance_type, lhs_length,
+ &if_equal, &if_notequal, &if_indirect);
BIND(&if_indirect);
{
@@ -158,7 +160,7 @@ void StringBuiltinsAssembler::GenerateStringEqual(Node* context, Node* left,
MaybeDerefIndirectStrings(&var_left, lhs_instance_type, &var_right,
rhs_instance_type, &restart);
- TailCallRuntime(Runtime::kStringEqual, context, lhs, rhs);
+ TailCallRuntime(Runtime::kStringEqual, NoContextConstant(), lhs, rhs);
}
BIND(&if_equal);
@@ -169,19 +171,17 @@ void StringBuiltinsAssembler::GenerateStringEqual(Node* context, Node* left,
}
void StringBuiltinsAssembler::StringEqual_Core(
- Node* context, Node* lhs, Node* lhs_instance_type, Node* rhs,
+ SloppyTNode<String> lhs, Node* lhs_instance_type, SloppyTNode<String> rhs,
Node* rhs_instance_type, TNode<IntPtrT> length, Label* if_equal,
Label* if_not_equal, Label* if_indirect) {
- CSA_ASSERT(this, IsString(lhs));
- CSA_ASSERT(this, IsString(rhs));
CSA_ASSERT(this, WordEqual(LoadStringLengthAsWord(lhs), length));
CSA_ASSERT(this, WordEqual(LoadStringLengthAsWord(rhs), length));
// Fast check to see if {lhs} and {rhs} refer to the same String object.
- GotoIf(WordEqual(lhs, rhs), if_equal);
+ GotoIf(TaggedEqual(lhs, rhs), if_equal);
// Combine the instance types into a single 16-bit value, so we can check
// both of them at once.
- Node* both_instance_types = Word32Or(
+ TNode<Word32T> both_instance_types = Word32Or(
lhs_instance_type, Word32Shl(rhs_instance_type, Int32Constant(8)));
// Check if both {lhs} and {rhs} are internalized. Since we already know
@@ -214,7 +214,7 @@ void StringBuiltinsAssembler::StringEqual_Core(
int const kOneTwoByteStringTag = kOneByteStringTag | (kTwoByteStringTag << 8);
Label if_oneonebytestring(this), if_twotwobytestring(this),
if_onetwobytestring(this), if_twoonebytestring(this);
- Node* masked_instance_types =
+ TNode<Word32T> masked_instance_types =
Word32And(both_instance_types, Int32Constant(kBothStringEncodingMask));
GotoIf(
Word32Equal(masked_instance_types, Int32Constant(kOneOneByteStringTag)),
@@ -271,14 +271,14 @@ void StringBuiltinsAssembler::StringEqual_Loop(
GotoIf(WordEqual(var_offset.value(), length), if_equal);
// Load the next characters from {lhs} and {rhs}.
- Node* lhs_value =
+ TNode<Word32T> lhs_value = UncheckedCast<Word32T>(
Load(lhs_type, lhs_data,
WordShl(var_offset.value(),
- ElementSizeLog2Of(lhs_type.representation())));
- Node* rhs_value =
+ ElementSizeLog2Of(lhs_type.representation()))));
+ TNode<Word32T> rhs_value = UncheckedCast<Word32T>(
Load(rhs_type, rhs_data,
WordShl(var_offset.value(),
- ElementSizeLog2Of(rhs_type.representation())));
+ ElementSizeLog2Of(rhs_type.representation()))));
// Check if the characters match.
GotoIf(Word32NotEqual(lhs_value, rhs_value), if_not_equal);
@@ -296,28 +296,6 @@ TF_BUILTIN(StringAdd_CheckNone, StringBuiltinsAssembler) {
Return(StringAdd(context, left, right));
}
-TF_BUILTIN(StringAdd_ConvertLeft, StringBuiltinsAssembler) {
- TNode<Object> left = CAST(Parameter(Descriptor::kLeft));
- TNode<String> right = CAST(Parameter(Descriptor::kRight));
- Node* context = Parameter(Descriptor::kContext);
- // TODO(danno): The ToString and JSReceiverToPrimitive below could be
- // combined to avoid duplicate smi and instance type checks.
- left =
- ToStringImpl(CAST(context), CAST(JSReceiverToPrimitive(context, left)));
- TailCallBuiltin(Builtins::kStringAdd_CheckNone, context, left, right);
-}
-
-TF_BUILTIN(StringAdd_ConvertRight, StringBuiltinsAssembler) {
- TNode<String> left = CAST(Parameter(Descriptor::kLeft));
- TNode<Object> right = CAST(Parameter(Descriptor::kRight));
- Node* context = Parameter(Descriptor::kContext);
- // TODO(danno): The ToString and JSReceiverToPrimitive below could be
- // combined to avoid duplicate smi and instance type checks.
- right =
- ToStringImpl(CAST(context), CAST(JSReceiverToPrimitive(context, right)));
- TailCallBuiltin(Builtins::kStringAdd_CheckNone, context, left, right);
-}
-
TF_BUILTIN(SubString, StringBuiltinsAssembler) {
TNode<String> string = CAST(Parameter(Descriptor::kString));
TNode<Smi> from = CAST(Parameter(Descriptor::kFrom));
@@ -325,12 +303,10 @@ TF_BUILTIN(SubString, StringBuiltinsAssembler) {
Return(SubString(string, SmiUntag(from), SmiUntag(to)));
}
-void StringBuiltinsAssembler::GenerateStringRelationalComparison(Node* context,
- Node* left,
- Node* right,
- Operation op) {
- VARIABLE(var_left, MachineRepresentation::kTagged, left);
- VARIABLE(var_right, MachineRepresentation::kTagged, right);
+void StringBuiltinsAssembler::GenerateStringRelationalComparison(
+ TNode<String> left, TNode<String> right, Operation op) {
+ TVARIABLE(String, var_left, left);
+ TVARIABLE(String, var_right, right);
Variable* input_vars[2] = {&var_left, &var_right};
Label if_less(this), if_equal(this), if_greater(this);
@@ -338,18 +314,18 @@ void StringBuiltinsAssembler::GenerateStringRelationalComparison(Node* context,
Goto(&restart);
BIND(&restart);
- Node* lhs = var_left.value();
- Node* rhs = var_right.value();
+ TNode<String> lhs = var_left.value();
+ TNode<String> rhs = var_right.value();
// Fast check to see if {lhs} and {rhs} refer to the same String object.
- GotoIf(WordEqual(lhs, rhs), &if_equal);
+ GotoIf(TaggedEqual(lhs, rhs), &if_equal);
// Load instance types of {lhs} and {rhs}.
- Node* lhs_instance_type = LoadInstanceType(lhs);
- Node* rhs_instance_type = LoadInstanceType(rhs);
+ TNode<Uint16T> lhs_instance_type = LoadInstanceType(lhs);
+ TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs);
// Combine the instance types into a single 16-bit value, so we can check
// both of them at once.
- Node* both_instance_types = Word32Or(
+ TNode<Int32T> both_instance_types = Word32Or(
lhs_instance_type, Word32Shl(rhs_instance_type, Int32Constant(8)));
// Check that both {lhs} and {rhs} are flat one-byte strings.
@@ -394,8 +370,8 @@ void StringBuiltinsAssembler::GenerateStringRelationalComparison(Node* context,
BIND(&if_notdone);
{
// Load the next characters from {lhs} and {rhs}.
- Node* lhs_value = Load(MachineType::Uint8(), lhs, var_offset.value());
- Node* rhs_value = Load(MachineType::Uint8(), rhs, var_offset.value());
+ TNode<Uint8T> lhs_value = Load<Uint8T>(lhs, var_offset.value());
+ TNode<Uint8T> rhs_value = Load<Uint8T>(rhs, var_offset.value());
// Check if the characters match.
Label if_valueissame(this), if_valueisnotsame(this);
@@ -431,16 +407,20 @@ void StringBuiltinsAssembler::GenerateStringRelationalComparison(Node* context,
// TODO(bmeurer): Add support for two byte string relational comparisons.
switch (op) {
case Operation::kLessThan:
- TailCallRuntime(Runtime::kStringLessThan, context, lhs, rhs);
+ TailCallRuntime(Runtime::kStringLessThan, NoContextConstant(), lhs,
+ rhs);
break;
case Operation::kLessThanOrEqual:
- TailCallRuntime(Runtime::kStringLessThanOrEqual, context, lhs, rhs);
+ TailCallRuntime(Runtime::kStringLessThanOrEqual, NoContextConstant(),
+ lhs, rhs);
break;
case Operation::kGreaterThan:
- TailCallRuntime(Runtime::kStringGreaterThan, context, lhs, rhs);
+ TailCallRuntime(Runtime::kStringGreaterThan, NoContextConstant(), lhs,
+ rhs);
break;
case Operation::kGreaterThanOrEqual:
- TailCallRuntime(Runtime::kStringGreaterThanOrEqual, context, lhs, rhs);
+ TailCallRuntime(Runtime::kStringGreaterThanOrEqual, NoContextConstant(),
+ lhs, rhs);
break;
default:
UNREACHABLE();
@@ -494,41 +474,33 @@ void StringBuiltinsAssembler::GenerateStringRelationalComparison(Node* context,
}
TF_BUILTIN(StringEqual, StringBuiltinsAssembler) {
- Node* context = Parameter(Descriptor::kContext);
- Node* left = Parameter(Descriptor::kLeft);
- Node* right = Parameter(Descriptor::kRight);
- GenerateStringEqual(context, left, right);
+ TNode<String> left = CAST(Parameter(Descriptor::kLeft));
+ TNode<String> right = CAST(Parameter(Descriptor::kRight));
+ GenerateStringEqual(left, right);
}
TF_BUILTIN(StringLessThan, StringBuiltinsAssembler) {
- Node* context = Parameter(Descriptor::kContext);
- Node* left = Parameter(Descriptor::kLeft);
- Node* right = Parameter(Descriptor::kRight);
- GenerateStringRelationalComparison(context, left, right,
- Operation::kLessThan);
+ TNode<String> left = CAST(Parameter(Descriptor::kLeft));
+ TNode<String> right = CAST(Parameter(Descriptor::kRight));
+ GenerateStringRelationalComparison(left, right, Operation::kLessThan);
}
TF_BUILTIN(StringLessThanOrEqual, StringBuiltinsAssembler) {
- Node* context = Parameter(Descriptor::kContext);
- Node* left = Parameter(Descriptor::kLeft);
- Node* right = Parameter(Descriptor::kRight);
- GenerateStringRelationalComparison(context, left, right,
- Operation::kLessThanOrEqual);
+ TNode<String> left = CAST(Parameter(Descriptor::kLeft));
+ TNode<String> right = CAST(Parameter(Descriptor::kRight));
+ GenerateStringRelationalComparison(left, right, Operation::kLessThanOrEqual);
}
TF_BUILTIN(StringGreaterThan, StringBuiltinsAssembler) {
- Node* context = Parameter(Descriptor::kContext);
- Node* left = Parameter(Descriptor::kLeft);
- Node* right = Parameter(Descriptor::kRight);
- GenerateStringRelationalComparison(context, left, right,
- Operation::kGreaterThan);
+ TNode<String> left = CAST(Parameter(Descriptor::kLeft));
+ TNode<String> right = CAST(Parameter(Descriptor::kRight));
+ GenerateStringRelationalComparison(left, right, Operation::kGreaterThan);
}
TF_BUILTIN(StringGreaterThanOrEqual, StringBuiltinsAssembler) {
- Node* context = Parameter(Descriptor::kContext);
- Node* left = Parameter(Descriptor::kLeft);
- Node* right = Parameter(Descriptor::kRight);
- GenerateStringRelationalComparison(context, left, right,
+ TNode<String> left = CAST(Parameter(Descriptor::kLeft));
+ TNode<String> right = CAST(Parameter(Descriptor::kRight));
+ GenerateStringRelationalComparison(left, right,
Operation::kGreaterThanOrEqual);
}
@@ -598,11 +570,11 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
// Single argument case, perform fast single character string cache lookup
// for one-byte code units, or fall back to creating a single character
// string on the fly otherwise.
- Node* code = arguments.AtIndex(0);
+ TNode<Object> code = arguments.AtIndex(0);
Node* code32 = TruncateTaggedToWord32(context, code);
TNode<Int32T> code16 =
Signed(Word32And(code32, Int32Constant(String::kMaxUtf16CodeUnit)));
- Node* result = StringFromSingleCharCode(code16);
+ TNode<String> result = StringFromSingleCharCode(code16);
arguments.PopAndReturn(result);
}
@@ -611,7 +583,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
{
Label two_byte(this);
// Assume that the resulting string contains only one-byte characters.
- Node* one_byte_result = AllocateSeqOneByteString(context, Unsigned(argc));
+ TNode<String> one_byte_result = AllocateSeqOneByteString(Unsigned(argc));
TVARIABLE(IntPtrT, var_max_index);
var_max_index = IntPtrConstant(0);
@@ -630,7 +602,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
&two_byte);
// The {code16} fits into the SeqOneByteString {one_byte_result}.
- Node* offset = ElementOffsetFromIndex(
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(
var_max_index.value(), UINT8_ELEMENTS,
CodeStubAssembler::INTPTR_PARAMETERS,
SeqOneByteString::kHeaderSize - kHeapObjectTag);
@@ -645,7 +617,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
// At least one of the characters in the string requires a 16-bit
// representation. Allocate a SeqTwoByteString to hold the resulting
// string.
- Node* two_byte_result = AllocateSeqTwoByteString(context, Unsigned(argc));
+ TNode<String> two_byte_result = AllocateSeqTwoByteString(Unsigned(argc));
// Copy the characters that have already been put in the 8-bit string into
// their corresponding positions in the new 16-bit string.
@@ -655,7 +627,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
String::TWO_BYTE_ENCODING);
// Write the character that caused the 8-bit to 16-bit fault.
- Node* max_index_offset =
+ TNode<IntPtrT> max_index_offset =
ElementOffsetFromIndex(var_max_index.value(), UINT16_ELEMENTS,
CodeStubAssembler::INTPTR_PARAMETERS,
SeqTwoByteString::kHeaderSize - kHeapObjectTag);
@@ -670,10 +642,10 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
vars,
[this, context, two_byte_result, &var_max_index](Node* arg) {
Node* code32 = TruncateTaggedToWord32(context, arg);
- Node* code16 =
+ TNode<Word32T> code16 =
Word32And(code32, Int32Constant(String::kMaxUtf16CodeUnit));
- Node* offset = ElementOffsetFromIndex(
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(
var_max_index.value(), UINT16_ELEMENTS,
CodeStubAssembler::INTPTR_PARAMETERS,
SeqTwoByteString::kHeaderSize - kHeapObjectTag);
@@ -688,12 +660,9 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
}
void StringBuiltinsAssembler::StringIndexOf(
- Node* const subject_string, Node* const search_string, Node* const position,
- const std::function<void(Node*)>& f_return) {
- CSA_ASSERT(this, IsString(subject_string));
- CSA_ASSERT(this, IsString(search_string));
- CSA_ASSERT(this, TaggedIsSmi(position));
-
+ TNode<String> const subject_string, TNode<String> const search_string,
+ TNode<Smi> const position,
+ const std::function<void(TNode<Smi>)>& f_return) {
TNode<IntPtrT> const int_zero = IntPtrConstant(0);
TNode<IntPtrT> const search_length = LoadStringLengthAsWord(search_string);
TNode<IntPtrT> const subject_length = LoadStringLengthAsWord(subject_string);
@@ -712,7 +681,7 @@ void StringBuiltinsAssembler::StringIndexOf(
// If the string pointers are identical, we can just return 0. Note that this
// implies {start_position} == 0 since we've passed the check above.
Label return_zero(this);
- GotoIf(WordEqual(subject_string, search_string), &return_zero);
+ GotoIf(TaggedEqual(subject_string, search_string), &return_zero);
// Try to unpack subject and search strings. Bail to runtime if either needs
// to be flattened.
@@ -725,13 +694,13 @@ void StringBuiltinsAssembler::StringIndexOf(
search_to_direct.TryToDirect(&call_runtime_unchecked);
// Load pointers to string data.
- Node* const subject_ptr =
+ TNode<RawPtrT> const subject_ptr =
subject_to_direct.PointerToData(&call_runtime_unchecked);
- Node* const search_ptr =
+ TNode<RawPtrT> const search_ptr =
search_to_direct.PointerToData(&call_runtime_unchecked);
- Node* const subject_offset = subject_to_direct.offset();
- Node* const search_offset = search_to_direct.offset();
+ TNode<IntPtrT> const subject_offset = subject_to_direct.offset();
+ TNode<IntPtrT> const search_offset = search_to_direct.offset();
// Like String::IndexOf, the actual matching is done by the optimized
// SearchString method in string-search.h. Dispatch based on string instance
@@ -754,9 +723,9 @@ void StringBuiltinsAssembler::StringIndexOf(
BIND(&one_one);
{
- Node* const adjusted_subject_ptr = PointerToStringDataAtIndex(
+ TNode<IntPtrT> const adjusted_subject_ptr = PointerToStringDataAtIndex(
subject_ptr, subject_offset, String::ONE_BYTE_ENCODING);
- Node* const adjusted_search_ptr = PointerToStringDataAtIndex(
+ TNode<IntPtrT> const adjusted_search_ptr = PointerToStringDataAtIndex(
search_ptr, search_offset, String::ONE_BYTE_ENCODING);
Label direct_memchr_call(this), generic_fast_path(this);
@@ -767,20 +736,22 @@ void StringBuiltinsAssembler::StringIndexOf(
// search strings.
BIND(&direct_memchr_call);
{
- Node* const string_addr = IntPtrAdd(adjusted_subject_ptr, start_position);
- Node* const search_length = IntPtrSub(subject_length, start_position);
- Node* const search_byte =
+ TNode<IntPtrT> const string_addr =
+ IntPtrAdd(adjusted_subject_ptr, start_position);
+ TNode<IntPtrT> const search_length =
+ IntPtrSub(subject_length, start_position);
+ TNode<IntPtrT> const search_byte =
ChangeInt32ToIntPtr(Load(MachineType::Uint8(), adjusted_search_ptr));
- Node* const memchr =
+ TNode<ExternalReference> const memchr =
ExternalConstant(ExternalReference::libc_memchr_function());
- Node* const result_address =
+ TNode<IntPtrT> const result_address = UncheckedCast<IntPtrT>(
CallCFunction(memchr, MachineType::Pointer(),
std::make_pair(MachineType::Pointer(), string_addr),
std::make_pair(MachineType::IntPtr(), search_byte),
- std::make_pair(MachineType::UintPtr(), search_length));
+ std::make_pair(MachineType::UintPtr(), search_length)));
GotoIf(WordEqual(result_address, int_zero), &return_minus_1);
- Node* const result_index =
+ TNode<IntPtrT> const result_index =
IntPtrAdd(IntPtrSub(result_address, string_addr), start_position);
f_return(SmiTag(result_index));
}
@@ -796,9 +767,9 @@ void StringBuiltinsAssembler::StringIndexOf(
BIND(&one_two);
{
- Node* const adjusted_subject_ptr = PointerToStringDataAtIndex(
+ TNode<IntPtrT> const adjusted_subject_ptr = PointerToStringDataAtIndex(
subject_ptr, subject_offset, String::ONE_BYTE_ENCODING);
- Node* const adjusted_search_ptr = PointerToStringDataAtIndex(
+ TNode<IntPtrT> const adjusted_search_ptr = PointerToStringDataAtIndex(
search_ptr, search_offset, String::TWO_BYTE_ENCODING);
Node* const result = CallSearchStringRaw<onebyte_t, twobyte_t>(
@@ -809,9 +780,9 @@ void StringBuiltinsAssembler::StringIndexOf(
BIND(&two_one);
{
- Node* const adjusted_subject_ptr = PointerToStringDataAtIndex(
+ TNode<IntPtrT> const adjusted_subject_ptr = PointerToStringDataAtIndex(
subject_ptr, subject_offset, String::TWO_BYTE_ENCODING);
- Node* const adjusted_search_ptr = PointerToStringDataAtIndex(
+ TNode<IntPtrT> const adjusted_search_ptr = PointerToStringDataAtIndex(
search_ptr, search_offset, String::ONE_BYTE_ENCODING);
Node* const result = CallSearchStringRaw<twobyte_t, onebyte_t>(
@@ -822,9 +793,9 @@ void StringBuiltinsAssembler::StringIndexOf(
BIND(&two_two);
{
- Node* const adjusted_subject_ptr = PointerToStringDataAtIndex(
+ TNode<IntPtrT> const adjusted_subject_ptr = PointerToStringDataAtIndex(
subject_ptr, subject_offset, String::TWO_BYTE_ENCODING);
- Node* const adjusted_search_ptr = PointerToStringDataAtIndex(
+ TNode<IntPtrT> const adjusted_search_ptr = PointerToStringDataAtIndex(
search_ptr, search_offset, String::TWO_BYTE_ENCODING);
Node* const result = CallSearchStringRaw<twobyte_t, twobyte_t>(
@@ -850,9 +821,9 @@ void StringBuiltinsAssembler::StringIndexOf(
// Simplified version of the runtime call where the types of the arguments
// are already known due to type checks in this stub.
Comment("Call Runtime Unchecked");
- Node* result =
- CallRuntime(Runtime::kStringIndexOfUnchecked, NoContextConstant(),
- subject_string, search_string, position);
+ TNode<Smi> result =
+ CAST(CallRuntime(Runtime::kStringIndexOfUnchecked, NoContextConstant(),
+ subject_string, search_string, position));
f_return(result);
}
}
@@ -861,11 +832,11 @@ void StringBuiltinsAssembler::StringIndexOf(
// #sec-string.prototype.indexof
// Unchecked helper for builtins lowering.
TF_BUILTIN(StringIndexOf, StringBuiltinsAssembler) {
- Node* receiver = Parameter(Descriptor::kReceiver);
- Node* search_string = Parameter(Descriptor::kSearchString);
- Node* position = Parameter(Descriptor::kPosition);
+ TNode<String> receiver = CAST(Parameter(Descriptor::kReceiver));
+ TNode<String> search_string = CAST(Parameter(Descriptor::kSearchString));
+ TNode<Smi> position = CAST(Parameter(Descriptor::kPosition));
StringIndexOf(receiver, search_string, position,
- [this](Node* result) { this->Return(result); });
+ [this](TNode<Smi> result) { this->Return(result); });
}
// ES6 String.prototype.includes(searchString [, position])
@@ -890,10 +861,10 @@ void StringIncludesIndexOfAssembler::Generate(SearchVariant variant,
TNode<IntPtrT> argc,
TNode<Context> context) {
CodeStubArguments arguments(this, argc);
- Node* const receiver = arguments.GetReceiver();
+ TNode<Object> const receiver = arguments.GetReceiver();
- VARIABLE(var_search_string, MachineRepresentation::kTagged);
- VARIABLE(var_position, MachineRepresentation::kTagged);
+ TVARIABLE(Object, var_search_string);
+ TVARIABLE(Object, var_position);
Label argc_1(this), argc_2(this), call_runtime(this, Label::kDeferred),
fast_path(this);
@@ -902,43 +873,45 @@ void StringIncludesIndexOfAssembler::Generate(SearchVariant variant,
{
Comment("0 Argument case");
CSA_ASSERT(this, IntPtrEqual(argc, IntPtrConstant(0)));
- Node* const undefined = UndefinedConstant();
- var_search_string.Bind(undefined);
- var_position.Bind(undefined);
+ TNode<Oddball> undefined = UndefinedConstant();
+ var_search_string = undefined;
+ var_position = undefined;
Goto(&call_runtime);
}
BIND(&argc_1);
{
Comment("1 Argument case");
- var_search_string.Bind(arguments.AtIndex(0));
- var_position.Bind(SmiConstant(0));
+ var_search_string = arguments.AtIndex(0);
+ var_position = SmiConstant(0);
Goto(&fast_path);
}
BIND(&argc_2);
{
Comment("2 Argument case");
- var_search_string.Bind(arguments.AtIndex(0));
- var_position.Bind(arguments.AtIndex(1));
+ var_search_string = arguments.AtIndex(0);
+ var_position = arguments.AtIndex(1);
GotoIfNot(TaggedIsSmi(var_position.value()), &call_runtime);
Goto(&fast_path);
}
BIND(&fast_path);
{
Comment("Fast Path");
- Node* const search = var_search_string.value();
- Node* const position = var_position.value();
+ TNode<Object> const search = var_search_string.value();
+ TNode<Smi> const position = CAST(var_position.value());
GotoIf(TaggedIsSmi(receiver), &call_runtime);
GotoIf(TaggedIsSmi(search), &call_runtime);
- GotoIfNot(IsString(receiver), &call_runtime);
- GotoIfNot(IsString(search), &call_runtime);
-
- StringIndexOf(receiver, search, position, [&](Node* result) {
- CSA_ASSERT(this, TaggedIsSmi(result));
- arguments.PopAndReturn((variant == kIndexOf)
- ? result
- : SelectBooleanConstant(SmiGreaterThanOrEqual(
- CAST(result), SmiConstant(0))));
- });
+ GotoIfNot(IsString(CAST(receiver)), &call_runtime);
+ GotoIfNot(IsString(CAST(search)), &call_runtime);
+
+ StringIndexOf(CAST(receiver), CAST(search), position,
+ [&](TNode<Smi> result) {
+ if (variant == kIndexOf) {
+ arguments.PopAndReturn(result);
+ } else {
+ arguments.PopAndReturn(SelectBooleanConstant(
+ SmiGreaterThanOrEqual(result, SmiConstant(0))));
+ }
+ });
}
BIND(&call_runtime);
{
@@ -946,7 +919,7 @@ void StringIncludesIndexOfAssembler::Generate(SearchVariant variant,
Runtime::FunctionId runtime = variant == kIndexOf
? Runtime::kStringIndexOf
: Runtime::kStringIncludes;
- Node* const result =
+ TNode<Object> const result =
CallRuntime(runtime, context, receiver, var_search_string.value(),
var_position.value());
arguments.PopAndReturn(result);
@@ -955,7 +928,8 @@ void StringIncludesIndexOfAssembler::Generate(SearchVariant variant,
void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
Node* const context, Node* const object, Node* const maybe_string,
- Handle<Symbol> symbol, DescriptorIndexAndName symbol_index,
+ Handle<Symbol> symbol,
+ DescriptorIndexNameValue additional_property_to_check,
const NodeFunction0& regexp_call, const NodeFunction1& generic_call) {
Label out(this);
@@ -972,9 +946,17 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
GotoIf(TaggedIsSmi(maybe_string), &slow_lookup);
GotoIfNot(IsString(maybe_string), &slow_lookup);
+ // Note we don't run a full (= permissive) check here, because passing the
+ // check implies calling the fast variants of target builtins, which assume
+ // we've already made their appropriate fast path checks. This is not the
+ // case though; e.g.: some of the target builtins access flag getters.
+ // TODO(jgruber): Handle slow flag accesses on the fast path and make this
+ // permissive.
RegExpBuiltinsAssembler regexp_asm(state());
- regexp_asm.BranchIfFastRegExp(context, object, LoadMap(object),
- symbol_index, &stub_call, &slow_lookup);
+ regexp_asm.BranchIfFastRegExp(
+ CAST(context), CAST(object), LoadMap(object),
+ PrototypeCheckAssembler::kCheckPrototypePropertyConstness,
+ additional_property_to_check, &stub_call, &slow_lookup);
BIND(&stub_call);
// TODO(jgruber): Add a no-JS scope once it exists.
@@ -993,7 +975,7 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
// We handle the former by jumping to {out} for null values as well, while
// the latter is already handled by the Call({maybe_func}) operation.
- Node* const maybe_func = GetProperty(context, object, symbol);
+ TNode<Object> const maybe_func = GetProperty(context, object, symbol);
GotoIf(IsUndefined(maybe_func), &out);
GotoIf(IsNull(maybe_func), &out);
@@ -1041,10 +1023,10 @@ compiler::Node* StringBuiltinsAssembler::GetSubstitution(
{
CSA_ASSERT(this, TaggedIsPositiveSmi(dollar_index));
- Node* const matched =
+ TNode<Object> const matched =
CallBuiltin(Builtins::kStringSubstring, context, subject_string,
SmiUntag(match_start_index), SmiUntag(match_end_index));
- Node* const replacement_string =
+ TNode<Object> const replacement_string =
CallRuntime(Runtime::kGetSubstitution, context, matched, subject_string,
match_start_index, replace_string, dollar_index);
var_result.Bind(replacement_string);
@@ -1073,8 +1055,9 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
MaybeCallFunctionAtSymbol(
context, search, receiver, isolate()->factory()->replace_symbol(),
- DescriptorIndexAndName{JSRegExp::kSymbolReplaceFunctionDescriptorIndex,
- RootIndex::kreplace_symbol},
+ DescriptorIndexNameValue{JSRegExp::kSymbolReplaceFunctionDescriptorIndex,
+ RootIndex::kreplace_symbol,
+ Context::REGEXP_REPLACE_FUNCTION_INDEX},
[=]() {
Return(CallBuiltin(Builtins::kRegExpReplace, context, search, receiver,
replace));
@@ -1102,7 +1085,8 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
GotoIf(TaggedIsSmi(replace), &next);
GotoIfNot(IsString(replace), &next);
- Node* const subject_instance_type = LoadInstanceType(subject_string);
+ TNode<Uint16T> const subject_instance_type =
+ LoadInstanceType(subject_string);
GotoIfNot(IsConsStringInstanceType(subject_instance_type), &next);
GotoIf(TaggedIsPositiveSmi(IndexOfDollarChar(context, replace)), &next);
@@ -1160,7 +1144,7 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
Label next(this);
GotoIf(SmiEqual(match_start_index, smi_zero), &next);
- Node* const prefix =
+ TNode<Object> const prefix =
CallBuiltin(Builtins::kStringSubstring, context, subject_string,
IntPtrConstant(0), SmiUntag(match_start_index));
var_result.Bind(prefix);
@@ -1182,7 +1166,8 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
Node* const replacement =
CallJS(call_callable, context, replace, UndefinedConstant(),
search_string, match_start_index, subject_string);
- Node* const replacement_string = ToString_Inline(context, replacement);
+ TNode<String> const replacement_string =
+ ToString_Inline(context, replacement);
var_result.Bind(CallBuiltin(Builtins::kStringAdd_CheckNone, context,
var_result.value(), replacement_string));
Goto(&out);
@@ -1190,7 +1175,7 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
BIND(&if_notcallablereplace);
{
- Node* const replace_string = ToString_Inline(context, replace);
+ TNode<String> const replace_string = ToString_Inline(context, replace);
Node* const replacement =
GetSubstitution(context, subject_string, match_start_index,
match_end_index, replace_string);
@@ -1201,11 +1186,11 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
BIND(&out);
{
- Node* const suffix =
+ TNode<Object> const suffix =
CallBuiltin(Builtins::kStringSubstring, context, subject_string,
SmiUntag(match_end_index), subject_length);
- Node* const result = CallBuiltin(Builtins::kStringAdd_CheckNone, context,
- var_result.value(), suffix);
+ TNode<Object> const result = CallBuiltin(
+ Builtins::kStringAdd_CheckNone, context, var_result.value(), suffix);
Return(result);
}
}
@@ -1225,19 +1210,19 @@ class StringMatchSearchAssembler : public StringBuiltinsAssembler {
Builtins::Name builtin;
Handle<Symbol> symbol;
- DescriptorIndexAndName property_to_check;
+ DescriptorIndexNameValue property_to_check;
if (variant == kMatch) {
builtin = Builtins::kRegExpMatchFast;
symbol = isolate()->factory()->match_symbol();
- property_to_check =
- DescriptorIndexAndName{JSRegExp::kSymbolMatchFunctionDescriptorIndex,
- RootIndex::kmatch_symbol};
+ property_to_check = DescriptorIndexNameValue{
+ JSRegExp::kSymbolMatchFunctionDescriptorIndex,
+ RootIndex::kmatch_symbol, Context::REGEXP_MATCH_FUNCTION_INDEX};
} else {
builtin = Builtins::kRegExpSearchFast;
symbol = isolate()->factory()->search_symbol();
- property_to_check =
- DescriptorIndexAndName{JSRegExp::kSymbolSearchFunctionDescriptorIndex,
- RootIndex::ksearch_symbol};
+ property_to_check = DescriptorIndexNameValue{
+ JSRegExp::kSymbolSearchFunctionDescriptorIndex,
+ RootIndex::ksearch_symbol, Context::REGEXP_SEARCH_FUNCTION_INDEX};
}
RequireObjectCoercible(context, receiver, method_name);
@@ -1255,7 +1240,7 @@ class StringMatchSearchAssembler : public StringBuiltinsAssembler {
RegExpBuiltinsAssembler regexp_asm(state());
TNode<String> receiver_string = ToString_Inline(context, receiver);
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<HeapObject> regexp_function = CAST(
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX));
TNode<Map> initial_map = CAST(LoadObjectField(
@@ -1263,9 +1248,13 @@ class StringMatchSearchAssembler : public StringBuiltinsAssembler {
TNode<Object> regexp = regexp_asm.RegExpCreate(
context, initial_map, maybe_regexp, EmptyStringConstant());
+ // TODO(jgruber): Handle slow flag accesses on the fast path and make this
+ // permissive.
Label fast_path(this), slow_path(this);
- regexp_asm.BranchIfFastRegExp(context, regexp, initial_map,
- property_to_check, &fast_path, &slow_path);
+ regexp_asm.BranchIfFastRegExp(
+ context, CAST(regexp), initial_map,
+ PrototypeCheckAssembler::kCheckPrototypePropertyConstness,
+ property_to_check, &fast_path, &slow_path);
BIND(&fast_path);
Return(CallBuiltin(builtin, context, regexp, receiver_string));
@@ -1297,7 +1286,7 @@ TF_BUILTIN(StringPrototypeMatchAll, StringBuiltinsAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> maybe_regexp = CAST(Parameter(Descriptor::kRegexp));
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
// 1. Let O be ? RequireObjectCoercible(this value).
RequireObjectCoercible(context, receiver, method_name);
@@ -1320,8 +1309,9 @@ TF_BUILTIN(StringPrototypeMatchAll, StringBuiltinsAssembler) {
};
MaybeCallFunctionAtSymbol(
context, maybe_regexp, receiver, isolate()->factory()->match_all_symbol(),
- DescriptorIndexAndName{JSRegExp::kSymbolMatchAllFunctionDescriptorIndex,
- RootIndex::kmatch_all_symbol},
+ DescriptorIndexNameValue{JSRegExp::kSymbolMatchAllFunctionDescriptorIndex,
+ RootIndex::kmatch_all_symbol,
+ Context::REGEXP_MATCH_ALL_FUNCTION_INDEX},
if_regexp_call, if_generic_call);
RegExpMatchAllAssembler regexp_asm(state());
@@ -1340,141 +1330,6 @@ TF_BUILTIN(StringPrototypeMatchAll, StringBuiltinsAssembler) {
Return(CallJS(callable, context, match_all_func, rx, s));
}
-class StringPadAssembler : public StringBuiltinsAssembler {
- public:
- explicit StringPadAssembler(compiler::CodeAssemblerState* state)
- : StringBuiltinsAssembler(state) {}
-
- protected:
- enum Variant { kStart, kEnd };
-
- void Generate(Variant variant, const char* method_name, TNode<IntPtrT> argc,
- TNode<Context> context) {
- CodeStubArguments arguments(this, argc);
- TNode<Object> receiver = arguments.GetReceiver();
- TNode<String> receiver_string =
- ToThisString(context, receiver, method_name);
- TNode<Smi> const string_length = LoadStringLengthAsSmi(receiver_string);
-
- TVARIABLE(String, var_fill_string, StringConstant(" "));
- TVARIABLE(IntPtrT, var_fill_length, IntPtrConstant(1));
-
- Label check_fill(this), dont_pad(this), invalid_string_length(this),
- pad(this);
-
- // If no max_length was provided, return the string.
- GotoIf(IntPtrEqual(argc, IntPtrConstant(0)), &dont_pad);
-
- TNode<Number> const max_length =
- ToLength_Inline(context, arguments.AtIndex(0));
- CSA_ASSERT(this, IsNumberNormalized(max_length));
-
- // If max_length <= string_length, return the string.
- GotoIfNot(TaggedIsSmi(max_length), &check_fill);
- Branch(SmiLessThanOrEqual(CAST(max_length), string_length), &dont_pad,
- &check_fill);
-
- BIND(&check_fill);
- {
- GotoIf(IntPtrEqual(argc, IntPtrConstant(1)), &pad);
- Node* const fill = arguments.AtIndex(1);
- GotoIf(IsUndefined(fill), &pad);
-
- var_fill_string = ToString_Inline(context, fill);
- var_fill_length = LoadStringLengthAsWord(var_fill_string.value());
- Branch(WordEqual(var_fill_length.value(), IntPtrConstant(0)), &dont_pad,
- &pad);
- }
-
- BIND(&pad);
- {
- CSA_ASSERT(this,
- IntPtrGreaterThan(var_fill_length.value(), IntPtrConstant(0)));
-
- // Throw if max_length is greater than String::kMaxLength.
- GotoIfNot(TaggedIsSmi(max_length), &invalid_string_length);
- TNode<Smi> smi_max_length = CAST(max_length);
- GotoIfNot(
- SmiLessThanOrEqual(smi_max_length, SmiConstant(String::kMaxLength)),
- &invalid_string_length);
-
- CSA_ASSERT(this, SmiGreaterThan(smi_max_length, string_length));
- TNode<Smi> const pad_length = SmiSub(smi_max_length, string_length);
-
- VARIABLE(var_pad, MachineRepresentation::kTagged);
- Label single_char_fill(this), multi_char_fill(this), return_result(this);
- Branch(IntPtrEqual(var_fill_length.value(), IntPtrConstant(1)),
- &single_char_fill, &multi_char_fill);
-
- // Fast path for a single character fill. No need to calculate number of
- // repetitions or remainder.
- BIND(&single_char_fill);
- {
- var_pad.Bind(CallBuiltin(Builtins::kStringRepeat, context,
- static_cast<Node*>(var_fill_string.value()),
- pad_length));
- Goto(&return_result);
- }
- BIND(&multi_char_fill);
- {
- TNode<Int32T> const fill_length_word32 =
- TruncateIntPtrToInt32(var_fill_length.value());
- TNode<Int32T> const pad_length_word32 = SmiToInt32(pad_length);
- TNode<Int32T> const repetitions_word32 =
- Int32Div(pad_length_word32, fill_length_word32);
- TNode<Int32T> const remaining_word32 =
- Int32Mod(pad_length_word32, fill_length_word32);
-
- var_pad.Bind(CallBuiltin(Builtins::kStringRepeat, context,
- var_fill_string.value(),
- SmiFromInt32(repetitions_word32)));
-
- GotoIfNot(remaining_word32, &return_result);
- {
- Node* const remainder_string = CallBuiltin(
- Builtins::kStringSubstring, context, var_fill_string.value(),
- IntPtrConstant(0), ChangeInt32ToIntPtr(remaining_word32));
- var_pad.Bind(CallBuiltin(Builtins::kStringAdd_CheckNone, context,
- var_pad.value(), remainder_string));
- Goto(&return_result);
- }
- }
- BIND(&return_result);
- CSA_ASSERT(this,
- SmiEqual(pad_length, LoadStringLengthAsSmi(var_pad.value())));
- arguments.PopAndReturn(
- variant == kStart
- ? CallBuiltin(Builtins::kStringAdd_CheckNone, context,
- var_pad.value(), receiver_string)
- : CallBuiltin(Builtins::kStringAdd_CheckNone, context,
- receiver_string, var_pad.value()));
- }
- BIND(&dont_pad);
- arguments.PopAndReturn(receiver_string);
- BIND(&invalid_string_length);
- {
- CallRuntime(Runtime::kThrowInvalidStringLength, context);
- Unreachable();
- }
- }
-};
-
-TF_BUILTIN(StringPrototypePadEnd, StringPadAssembler) {
- TNode<IntPtrT> argc =
- ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
-
- Generate(kEnd, "String.prototype.padEnd", argc, context);
-}
-
-TF_BUILTIN(StringPrototypePadStart, StringPadAssembler) {
- TNode<IntPtrT> argc =
- ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
-
- Generate(kStart, "String.prototype.padStart", argc, context);
-}
-
// ES6 #sec-string.prototype.search
TF_BUILTIN(StringPrototypeSearch, StringMatchSearchAssembler) {
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
@@ -1484,7 +1339,7 @@ TF_BUILTIN(StringPrototypeSearch, StringMatchSearchAssembler) {
}
TNode<JSArray> StringBuiltinsAssembler::StringToArray(
- TNode<Context> context, TNode<String> subject_string,
+ TNode<NativeContext> context, TNode<String> subject_string,
TNode<Smi> subject_length, TNode<Number> limit_number) {
CSA_ASSERT(this, SmiGreaterThan(subject_length, SmiConstant(0)));
@@ -1492,7 +1347,7 @@ TNode<JSArray> StringBuiltinsAssembler::StringToArray(
fill_thehole_and_call_runtime(this, Label::kDeferred);
TVARIABLE(JSArray, result_array);
- TNode<Int32T> instance_type = LoadInstanceType(subject_string);
+ TNode<Uint16T> instance_type = LoadInstanceType(subject_string);
GotoIfNot(IsOneByteStringInstanceType(instance_type), &call_runtime);
// Try to use cached one byte characters.
@@ -1508,10 +1363,10 @@ TNode<JSArray> StringBuiltinsAssembler::StringToArray(
TNode<FixedArray> elements = CAST(AllocateFixedArray(
PACKED_ELEMENTS, length, AllocationFlag::kAllowLargeObjectAllocation));
// Don't allocate anything while {string_data} is live!
- TNode<RawPtrT> string_data = UncheckedCast<RawPtrT>(
- to_direct.PointerToData(&fill_thehole_and_call_runtime));
+ TNode<RawPtrT> string_data =
+ to_direct.PointerToData(&fill_thehole_and_call_runtime);
TNode<IntPtrT> string_data_offset = to_direct.offset();
- TNode<Object> cache = LoadRoot(RootIndex::kSingleCharacterStringCache);
+ TNode<FixedArray> cache = SingleCharacterStringCacheConstant();
BuildFastLoop(
IntPtrConstant(0), length,
@@ -1523,8 +1378,8 @@ TNode<JSArray> StringBuiltinsAssembler::StringToArray(
TNode<Int32T> char_code =
UncheckedCast<Int32T>(Load(MachineType::Uint8(), string_data,
IntPtrAdd(index, string_data_offset)));
- Node* code_index = ChangeUint32ToWord(char_code);
- TNode<Object> entry = LoadFixedArrayElement(CAST(cache), code_index);
+ TNode<UintPtrT> code_index = ChangeUint32ToWord(char_code);
+ TNode<Object> entry = LoadFixedArrayElement(cache, code_index);
// If we cannot find a char in the cache, fill the hole for the fixed
// array, and call runtime.
@@ -1562,14 +1417,14 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
const int kSeparatorArg = 0;
const int kLimitArg = 1;
- Node* const argc =
+ TNode<IntPtrT> const argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
TNode<Object> receiver = args.GetReceiver();
- Node* const separator = args.GetOptionalArgumentValue(kSeparatorArg);
- Node* const limit = args.GetOptionalArgumentValue(kLimitArg);
- TNode<Context> context = CAST(Parameter(Descriptor::kContext));
+ TNode<Object> const separator = args.GetOptionalArgumentValue(kSeparatorArg);
+ TNode<Object> const limit = args.GetOptionalArgumentValue(kLimitArg);
+ TNode<NativeContext> context = CAST(Parameter(Descriptor::kContext));
TNode<Smi> smi_zero = SmiConstant(0);
@@ -1579,8 +1434,9 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
MaybeCallFunctionAtSymbol(
context, separator, receiver, isolate()->factory()->split_symbol(),
- DescriptorIndexAndName{JSRegExp::kSymbolSplitFunctionDescriptorIndex,
- RootIndex::ksplit_symbol},
+ DescriptorIndexNameValue{JSRegExp::kSymbolSplitFunctionDescriptorIndex,
+ RootIndex::ksplit_symbol,
+ Context::REGEXP_SPLIT_FUNCTION_INDEX},
[&]() {
args.PopAndReturn(CallBuiltin(Builtins::kRegExpSplit, context,
separator, receiver, limit));
@@ -1597,13 +1453,12 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
TNode<Number> limit_number = Select<Number>(
IsUndefined(limit), [=] { return NumberConstant(kMaxUInt32); },
[=] { return ToUint32(context, limit); });
- Node* const separator_string = ToString_Inline(context, separator);
+ TNode<String> const separator_string = ToString_Inline(context, separator);
Label return_empty_array(this);
// Shortcut for {limit} == 0.
- GotoIf(WordEqual<Object, Object>(limit_number, smi_zero),
- &return_empty_array);
+ GotoIf(TaggedEqual(limit_number, smi_zero), &return_empty_array);
// ECMA-262 says that if {separator} is undefined, the result should
// be an array of size 1 containing the entire string.
@@ -1612,7 +1467,7 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
GotoIfNot(IsUndefined(separator), &next);
const ElementsKind kind = PACKED_ELEMENTS;
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context);
TNode<Smi> length = SmiConstant(1);
@@ -1642,7 +1497,7 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
BIND(&next);
}
- Node* const result =
+ TNode<Object> const result =
CallRuntime(Runtime::kStringSplit, context, subject_string,
separator_string, limit_number);
args.PopAndReturn(result);
@@ -1650,7 +1505,7 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
BIND(&return_empty_array);
{
const ElementsKind kind = PACKED_ELEMENTS;
- Node* const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context);
TNode<Smi> length = smi_zero;
@@ -1666,7 +1521,7 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) {
const int kStartArg = 0;
const int kLengthArg = 1;
- Node* const argc =
+ TNode<IntPtrT> const argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
@@ -1808,10 +1663,11 @@ void StringTrimAssembler::Generate(String::TrimMode mode,
ToDirectStringAssembler to_direct(state(), string);
to_direct.TryToDirect(&if_runtime);
- Node* const string_data = to_direct.PointerToData(&if_runtime);
- Node* const instance_type = to_direct.instance_type();
- Node* const is_stringonebyte = IsOneByteStringInstanceType(instance_type);
- Node* const string_data_offset = to_direct.offset();
+ TNode<RawPtrT> const string_data = to_direct.PointerToData(&if_runtime);
+ TNode<Int32T> const instance_type = to_direct.instance_type();
+ TNode<BoolT> const is_stringonebyte =
+ IsOneByteStringInstanceType(instance_type);
+ TNode<IntPtrT> const string_data_offset = to_direct.offset();
TVARIABLE(IntPtrT, var_start, IntPtrConstant(0));
TVARIABLE(IntPtrT, var_end, IntPtrSub(string_length, IntPtrConstant(1)));
@@ -1841,8 +1697,8 @@ void StringTrimAssembler::Generate(String::TrimMode mode,
void StringTrimAssembler::ScanForNonWhiteSpaceOrLineTerminator(
Node* const string_data, Node* const string_data_offset,
- Node* const is_stringonebyte, Variable* const var_index, Node* const end,
- int increment, Label* const if_none_found) {
+ Node* const is_stringonebyte, TVariable<IntPtrT>* const var_index,
+ TNode<IntPtrT> const end, int increment, Label* const if_none_found) {
Label if_stringisonebyte(this), out(this);
GotoIf(is_stringonebyte, &if_stringisonebyte);
@@ -1866,14 +1722,14 @@ void StringTrimAssembler::ScanForNonWhiteSpaceOrLineTerminator(
}
void StringTrimAssembler::BuildLoop(
- Variable* const var_index, Node* const end, int increment,
- Label* const if_none_found, Label* const out,
+ TVariable<IntPtrT>* const var_index, TNode<IntPtrT> const end,
+ int increment, Label* const if_none_found, Label* const out,
const std::function<Node*(Node*)>& get_character) {
Label loop(this, var_index);
Goto(&loop);
BIND(&loop);
{
- Node* const index = var_index->value();
+ TNode<IntPtrT> index = var_index->value();
GotoIf(IntPtrEqual(index, end), if_none_found);
GotoIfNotWhiteSpaceOrLineTerminator(
UncheckedCast<Uint32T>(get_character(index)), out);
@@ -1883,7 +1739,7 @@ void StringTrimAssembler::BuildLoop(
}
void StringTrimAssembler::GotoIfNotWhiteSpaceOrLineTerminator(
- Node* const char_code, Label* const if_not_whitespace) {
+ TNode<Word32T> const char_code, Label* const if_not_whitespace) {
Label out(this);
// 0x0020 - SPACE (Intentionally out of order to fast path a commmon case)
@@ -2010,11 +1866,12 @@ void StringBuiltinsAssembler::BranchIfStringPrimitiveWithNoCustomIteration(
// Check that the String iterator hasn't been modified in a way that would
// affect iteration.
- Node* protector_cell = LoadRoot(RootIndex::kStringIteratorProtector);
+ TNode<PropertyCell> protector_cell = StringIteratorProtectorConstant();
DCHECK(isolate()->heap()->string_iterator_protector().IsPropertyCell());
- Branch(WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
- SmiConstant(Isolate::kProtectorValid)),
- if_true, if_false);
+ Branch(
+ TaggedEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
+ SmiConstant(Isolate::kProtectorValid)),
+ if_true, if_false);
}
} // namespace internal
diff --git a/deps/v8/src/builtins/builtins-string-gen.h b/deps/v8/src/builtins/builtins-string-gen.h
index 679ce0e17f..64d5a77615 100644
--- a/deps/v8/src/builtins/builtins-string-gen.h
+++ b/deps/v8/src/builtins/builtins-string-gen.h
@@ -19,8 +19,8 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
Node* GetSubstitution(Node* context, Node* subject_string,
Node* match_start_index, Node* match_end_index,
Node* replace_string);
- void StringEqual_Core(Node* context, Node* lhs, Node* lhs_instance_type,
- Node* rhs, Node* rhs_instance_type,
+ void StringEqual_Core(SloppyTNode<String> lhs, Node* lhs_instance_type,
+ SloppyTNode<String> rhs, Node* rhs_instance_type,
TNode<IntPtrT> length, Label* if_equal,
Label* if_not_equal, Label* if_indirect);
void BranchIfStringPrimitiveWithNoCustomIteration(TNode<Object> object,
@@ -51,27 +51,29 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
Node* const search_ptr, Node* const search_length,
Node* const start_position);
- Node* PointerToStringDataAtIndex(Node* const string_data, Node* const index,
- String::Encoding encoding);
+ TNode<IntPtrT> PointerToStringDataAtIndex(Node* const string_data,
+ Node* const index,
+ String::Encoding encoding);
// substr and slice have a common way of handling the {start} argument.
void ConvertAndBoundsCheckStartArgument(Node* context, Variable* var_start,
Node* start, Node* string_length);
- void GenerateStringEqual(Node* context, Node* left, Node* right);
- void GenerateStringRelationalComparison(Node* context, Node* left,
- Node* right, Operation op);
+ void GenerateStringEqual(TNode<String> left, TNode<String> right);
+ void GenerateStringRelationalComparison(TNode<String> left,
+ TNode<String> right, Operation op);
using StringAtAccessor = std::function<TNode<Object>(
TNode<String> receiver, TNode<IntPtrT> length, TNode<IntPtrT> index)>;
- void StringIndexOf(Node* const subject_string, Node* const search_string,
- Node* const position,
- const std::function<void(Node*)>& f_return);
+ void StringIndexOf(TNode<String> const subject_string,
+ TNode<String> const search_string,
+ TNode<Smi> const position,
+ const std::function<void(TNode<Smi>)>& f_return);
TNode<Smi> IndexOfDollarChar(Node* const context, Node* const string);
- TNode<JSArray> StringToArray(TNode<Context> context,
+ TNode<JSArray> StringToArray(TNode<NativeContext> context,
TNode<String> subject_string,
TNode<Smi> subject_length,
TNode<Number> limit_number);
@@ -94,12 +96,13 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
// Important: {regexp_call} may not contain any code that can call into JS.
using NodeFunction0 = std::function<void()>;
using NodeFunction1 = std::function<void(Node* fn)>;
- void MaybeCallFunctionAtSymbol(Node* const context, Node* const object,
- Node* const maybe_string,
- Handle<Symbol> symbol,
- DescriptorIndexAndName symbol_index,
- const NodeFunction0& regexp_call,
- const NodeFunction1& generic_call);
+ using DescriptorIndexNameValue =
+ PrototypeCheckAssembler::DescriptorIndexNameValue;
+ void MaybeCallFunctionAtSymbol(
+ Node* const context, Node* const object, Node* const maybe_string,
+ Handle<Symbol> symbol,
+ DescriptorIndexNameValue additional_property_to_check,
+ const NodeFunction0& regexp_call, const NodeFunction1& generic_call);
};
class StringIncludesIndexOfAssembler : public StringBuiltinsAssembler {
@@ -120,21 +123,19 @@ class StringTrimAssembler : public StringBuiltinsAssembler {
: StringBuiltinsAssembler(state) {}
V8_EXPORT_PRIVATE void GotoIfNotWhiteSpaceOrLineTerminator(
- Node* const char_code, Label* const if_not_whitespace);
+ TNode<Word32T> const char_code, Label* const if_not_whitespace);
protected:
void Generate(String::TrimMode mode, const char* method, TNode<IntPtrT> argc,
TNode<Context> context);
- void ScanForNonWhiteSpaceOrLineTerminator(Node* const string_data,
- Node* const string_data_offset,
- Node* const is_stringonebyte,
- Variable* const var_index,
- Node* const end, int increment,
- Label* const if_none_found);
+ void ScanForNonWhiteSpaceOrLineTerminator(
+ Node* const string_data, Node* const string_data_offset,
+ Node* const is_stringonebyte, TVariable<IntPtrT>* const var_index,
+ TNode<IntPtrT> const end, int increment, Label* const if_none_found);
- void BuildLoop(Variable* const var_index, Node* const end, int increment,
- Label* const if_none_found, Label* const out,
+ void BuildLoop(TVariable<IntPtrT>* const var_index, TNode<IntPtrT> const end,
+ int increment, Label* const if_none_found, Label* const out,
const std::function<Node*(Node*)>& get_character);
};
diff --git a/deps/v8/src/builtins/builtins-string.cc b/deps/v8/src/builtins/builtins-string.cc
index 74b15cf99b..04a96c7e46 100644
--- a/deps/v8/src/builtins/builtins-string.cc
+++ b/deps/v8/src/builtins/builtins-string.cc
@@ -208,14 +208,10 @@ BUILTIN(StringPrototypeNormalize) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, form,
Object::ToString(isolate, form_input));
- if (!(String::Equals(isolate, form,
- isolate->factory()->NewStringFromStaticChars("NFC")) ||
- String::Equals(isolate, form,
- isolate->factory()->NewStringFromStaticChars("NFD")) ||
- String::Equals(isolate, form,
- isolate->factory()->NewStringFromStaticChars("NFKC")) ||
- String::Equals(isolate, form,
- isolate->factory()->NewStringFromStaticChars("NFKD")))) {
+ if (!(String::Equals(isolate, form, isolate->factory()->NFC_string()) ||
+ String::Equals(isolate, form, isolate->factory()->NFD_string()) ||
+ String::Equals(isolate, form, isolate->factory()->NFKC_string()) ||
+ String::Equals(isolate, form, isolate->factory()->NFKD_string()))) {
Handle<String> valid_forms =
isolate->factory()->NewStringFromStaticChars("NFC, NFD, NFKC, NFKD");
THROW_NEW_ERROR_RETURN_FAILURE(
diff --git a/deps/v8/src/builtins/builtins-symbol-gen.cc b/deps/v8/src/builtins/builtins-symbol-gen.cc
index 610a8baeb3..cb1ee28501 100644
--- a/deps/v8/src/builtins/builtins-symbol-gen.cc
+++ b/deps/v8/src/builtins/builtins-symbol-gen.cc
@@ -16,9 +16,10 @@ TF_BUILTIN(SymbolPrototypeDescriptionGetter, CodeStubAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- Node* value = ToThisValue(context, receiver, PrimitiveType::kSymbol,
- "Symbol.prototype.description");
- Node* result = LoadObjectField(value, Symbol::kNameOffset);
+ TNode<Symbol> value =
+ CAST(ToThisValue(context, receiver, PrimitiveType::kSymbol,
+ "Symbol.prototype.description"));
+ TNode<Object> result = LoadObjectField(value, Symbol::kNameOffset);
Return(result);
}
@@ -27,8 +28,8 @@ TF_BUILTIN(SymbolPrototypeToPrimitive, CodeStubAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- Node* result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
- "Symbol.prototype [ @@toPrimitive ]");
+ TNode<Object> result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
+ "Symbol.prototype [ @@toPrimitive ]");
Return(result);
}
@@ -37,9 +38,10 @@ TF_BUILTIN(SymbolPrototypeToString, CodeStubAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- Node* value = ToThisValue(context, receiver, PrimitiveType::kSymbol,
- "Symbol.prototype.toString");
- Node* result = CallRuntime(Runtime::kSymbolDescriptiveString, context, value);
+ TNode<Object> value = ToThisValue(context, receiver, PrimitiveType::kSymbol,
+ "Symbol.prototype.toString");
+ TNode<Object> result =
+ CallRuntime(Runtime::kSymbolDescriptiveString, context, value);
Return(result);
}
@@ -48,8 +50,8 @@ TF_BUILTIN(SymbolPrototypeValueOf, CodeStubAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
- Node* result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
- "Symbol.prototype.valueOf");
+ TNode<Object> result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
+ "Symbol.prototype.valueOf");
Return(result);
}
diff --git a/deps/v8/src/builtins/builtins-symbol.cc b/deps/v8/src/builtins/builtins-symbol.cc
index ea6e594706..e705aec8b0 100644
--- a/deps/v8/src/builtins/builtins-symbol.cc
+++ b/deps/v8/src/builtins/builtins-symbol.cc
@@ -54,7 +54,7 @@ BUILTIN(SymbolKeyFor) {
Handle<Symbol> symbol = Handle<Symbol>::cast(obj);
DisallowHeapAllocation no_gc;
Object result;
- if (symbol->is_public()) {
+ if (symbol->is_in_public_symbol_table()) {
result = symbol->name();
DCHECK(result.IsString());
} else {
diff --git a/deps/v8/src/builtins/builtins-typed-array-gen.cc b/deps/v8/src/builtins/builtins-typed-array-gen.cc
index 857d33988f..448ff66603 100644
--- a/deps/v8/src/builtins/builtins-typed-array-gen.cc
+++ b/deps/v8/src/builtins/builtins-typed-array-gen.cc
@@ -35,11 +35,10 @@ void TypedArrayBuiltinsAssembler::SetupTypedArrayEmbedderFields(
// TODO(bmeurer,v8:4153): Rename this and maybe fix up the implementation a bit.
TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
TNode<Context> context, TNode<UintPtrT> byte_length) {
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> map =
CAST(LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX));
- TNode<FixedArray> empty_fixed_array =
- CAST(LoadRoot(RootIndex::kEmptyFixedArray));
+ TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
TNode<JSArrayBuffer> buffer = UncheckedCast<JSArrayBuffer>(
Allocate(JSArrayBuffer::kSizeWithEmbedderFields));
@@ -90,12 +89,12 @@ TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<JSFunction> target = CAST(Parameter(Descriptor::kJSTarget));
TNode<Object> new_target = CAST(Parameter(Descriptor::kJSNewTarget));
- Node* argc =
+ TNode<IntPtrT> argc =
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
CodeStubArguments args(this, argc);
- Node* arg1 = args.GetOptionalArgumentValue(0);
- Node* arg2 = args.GetOptionalArgumentValue(1);
- Node* arg3 = args.GetOptionalArgumentValue(2);
+ TNode<Object> arg1 = args.GetOptionalArgumentValue(0);
+ TNode<Object> arg2 = args.GetOptionalArgumentValue(1);
+ TNode<Object> arg3 = args.GetOptionalArgumentValue(2);
// If NewTarget is undefined, throw a TypeError exception.
// All the TypedArray constructors have this as the first step:
@@ -103,8 +102,8 @@ TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
Label throwtypeerror(this, Label::kDeferred);
GotoIf(IsUndefined(new_target), &throwtypeerror);
- Node* result = CallBuiltin(Builtins::kCreateTypedArray, context, target,
- new_target, arg1, arg2, arg3);
+ TNode<Object> result = CallBuiltin(Builtins::kCreateTypedArray, context,
+ target, new_target, arg1, arg2, arg3);
args.PopAndReturn(result);
BIND(&throwtypeerror);
@@ -221,7 +220,7 @@ TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(TNode<Map> map) {
TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
TNode<Context> context, TNode<JSTypedArray> exemplar) {
TVARIABLE(IntPtrT, context_slot);
- TNode<Word32T> elements_kind = LoadElementsKind(exemplar);
+ TNode<Int32T> elements_kind = LoadElementsKind(exemplar);
DispatchTypedArrayByElementsKind(
elements_kind,
@@ -322,8 +321,8 @@ void TypedArrayBuiltinsAssembler::SetTypedArraySource(
TNode<RawPtrT> target_data_ptr = LoadJSTypedArrayBackingStore(target);
TNode<RawPtrT> source_data_ptr = LoadJSTypedArrayBackingStore(source);
- TNode<Word32T> source_el_kind = LoadElementsKind(source);
- TNode<Word32T> target_el_kind = LoadElementsKind(target);
+ TNode<Int32T> source_el_kind = LoadElementsKind(source);
+ TNode<Int32T> target_el_kind = LoadElementsKind(target);
TNode<IntPtrT> source_el_size = GetTypedArrayElementSize(source_el_kind);
TNode<IntPtrT> target_el_size = GetTypedArrayElementSize(target_el_kind);
@@ -650,7 +649,7 @@ TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
// that this can be turned into a non-sparse table switch for ideal
// performance.
BIND(&if_receiverisheapobject);
- Node* elements_kind =
+ TNode<Int32T> elements_kind =
Int32Sub(LoadElementsKind(receiver),
Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
Switch(elements_kind, &return_undefined, elements_kinds, elements_kind_labels,
@@ -727,7 +726,7 @@ TF_BUILTIN(TypedArrayOf, TypedArrayBuiltinsAssembler) {
TNode<JSTypedArray> new_typed_array = TypedArrayCreateByLength(
context, receiver, SmiTag(length), "%TypedArray%.of");
- TNode<Word32T> elements_kind = LoadElementsKind(new_typed_array);
+ TNode<Int32T> elements_kind = LoadElementsKind(new_typed_array);
// 6. Let k be 0.
// 7. Repeat, while k < len
@@ -858,17 +857,16 @@ TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
CAST(iterator_fn), JSFunction::kSharedFunctionInfoOffset);
GotoIfNot(
- WordEqual(LoadObjectField(shared_info,
- SharedFunctionInfo::kFunctionDataOffset),
- SmiConstant(Builtins::kTypedArrayPrototypeValues)),
+ TaggedEqual(LoadObjectField(shared_info,
+ SharedFunctionInfo::kFunctionDataOffset),
+ SmiConstant(Builtins::kTypedArrayPrototypeValues)),
&check_iterator);
// Check that the ArrayIterator prototype's "next" method hasn't been
// overridden
- TNode<PropertyCell> protector_cell =
- CAST(LoadRoot(RootIndex::kArrayIteratorProtector));
+ TNode<PropertyCell> protector_cell = ArrayIteratorProtectorConstant();
GotoIfNot(
- WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
- SmiConstant(Isolate::kProtectorValid)),
+ TaggedEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
+ SmiConstant(Isolate::kProtectorValid)),
&check_iterator);
// Source is a TypedArray with unmodified iterator behavior. Use the
@@ -895,7 +893,7 @@ TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
// This is not a spec'd limit, so it doesn't particularly matter when we
// throw the range error for typed array length > MaxSmi.
- TNode<Object> raw_length = LoadJSArrayLength(values);
+ TNode<Number> raw_length = LoadJSArrayLength(values);
GotoIfNot(TaggedIsSmi(raw_length), &if_length_not_smi);
final_length = CAST(raw_length);
@@ -949,7 +947,7 @@ TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
}
BIND(&slow_path);
- TNode<Word32T> elements_kind = LoadElementsKind(target_obj.value());
+ TNode<Int32T> elements_kind = LoadElementsKind(target_obj.value());
// 7e/13 : Copy the elements
BuildFastLoop(
diff --git a/deps/v8/src/builtins/builtins-wasm-gen.cc b/deps/v8/src/builtins/builtins-wasm-gen.cc
index 0b86d35853..12270495c1 100644
--- a/deps/v8/src/builtins/builtins-wasm-gen.cc
+++ b/deps/v8/src/builtins/builtins-wasm-gen.cc
@@ -4,6 +4,7 @@
#include "src/builtins/builtins-utils-gen.h"
#include "src/codegen/code-stub-assembler.h"
+#include "src/codegen/interface-descriptors.h"
#include "src/objects/objects-inl.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-opcodes.h"
@@ -46,10 +47,16 @@ class WasmBuiltinsAssembler : public CodeStubAssembler {
}
TNode<Code> LoadCEntryFromInstance(TNode<Object> instance) {
- return UncheckedCast<Code>(
- Load(MachineType::AnyTagged(), instance,
- IntPtrConstant(WasmInstanceObject::kCEntryStubOffset -
+ TNode<IntPtrT> isolate_root = UncheckedCast<IntPtrT>(
+ Load(MachineType::Pointer(), instance,
+ IntPtrConstant(WasmInstanceObject::kIsolateRootOffset -
kHeapObjectTag)));
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ TNode<Code> target = UncheckedCast<Code>(
+ Load(MachineType::TaggedPointer(), isolate_root,
+ IntPtrConstant(IsolateData::builtin_slot_offset(centry_id))));
+ return target;
}
};
@@ -58,14 +65,6 @@ TF_BUILTIN(WasmAllocateHeapNumber, WasmBuiltinsAssembler) {
TailCallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant());
}
-TF_BUILTIN(WasmCallJavaScript, WasmBuiltinsAssembler) {
- TNode<Object> context = UncheckedParameter(Descriptor::kContext);
- TNode<Object> function = UncheckedParameter(Descriptor::kFunction);
- TNode<Object> argc = UncheckedParameter(Descriptor::kActualArgumentsCount);
- TNode<Code> target = LoadBuiltinFromFrame(Builtins::kCall_ReceiverIsAny);
- TailCallStub(CallTrampolineDescriptor{}, target, context, function, argc);
-}
-
TF_BUILTIN(WasmRecordWrite, WasmBuiltinsAssembler) {
TNode<Object> object = UncheckedParameter(Descriptor::kObject);
TNode<Object> slot = UncheckedParameter(Descriptor::kSlot);
@@ -299,6 +298,20 @@ TF_BUILTIN(WasmI64ToBigInt, WasmBuiltinsAssembler) {
TailCallStub(I64ToBigIntDescriptor(), target, NoContextConstant(), argument);
}
+TF_BUILTIN(WasmI32PairToBigInt, WasmBuiltinsAssembler) {
+ if (!Is32()) {
+ Unreachable();
+ return;
+ }
+
+ TNode<Code> target = LoadBuiltinFromFrame(Builtins::kI32PairToBigInt);
+ TNode<IntPtrT> low = UncheckedCast<IntPtrT>(Parameter(Descriptor::kLow));
+ TNode<IntPtrT> high = UncheckedCast<IntPtrT>(Parameter(Descriptor::kHigh));
+
+ TailCallStub(I32PairToBigIntDescriptor(), target, NoContextConstant(), low,
+ high);
+}
+
TF_BUILTIN(WasmBigIntToI64, WasmBuiltinsAssembler) {
if (!Is64()) {
Unreachable();
@@ -314,6 +327,21 @@ TF_BUILTIN(WasmBigIntToI64, WasmBuiltinsAssembler) {
TailCallStub(BigIntToI64Descriptor(), target, context, argument);
}
+TF_BUILTIN(WasmBigIntToI32Pair, WasmBuiltinsAssembler) {
+ if (!Is32()) {
+ Unreachable();
+ return;
+ }
+
+ TNode<Object> context =
+ UncheckedCast<Object>(Parameter(Descriptor::kContext));
+ TNode<Code> target = LoadBuiltinFromFrame(Builtins::kBigIntToI32Pair);
+ TNode<IntPtrT> argument =
+ UncheckedCast<IntPtrT>(Parameter(Descriptor::kArgument));
+
+ TailCallStub(BigIntToI32PairDescriptor(), target, context, argument);
+}
+
#define DECLARE_ENUM(name) \
TF_BUILTIN(ThrowWasm##name, WasmBuiltinsAssembler) { \
TNode<Object> instance = LoadInstanceFromFrame(); \
diff --git a/deps/v8/src/builtins/builtins-weak-refs.cc b/deps/v8/src/builtins/builtins-weak-refs.cc
index 18738d2c48..28fb9c9cbd 100644
--- a/deps/v8/src/builtins/builtins-weak-refs.cc
+++ b/deps/v8/src/builtins/builtins-weak-refs.cc
@@ -151,8 +151,11 @@ BUILTIN(FinalizationGroupCleanupSome) {
// Don't do set_scheduled_for_cleanup(false); we still have the microtask
// scheduled and don't want to schedule another one in case the user never
// executes microtasks.
- JSFinalizationGroup::Cleanup(isolate, finalization_group, callback);
-
+ if (JSFinalizationGroup::Cleanup(isolate, finalization_group, callback)
+ .IsNothing()) {
+ DCHECK(isolate->has_pending_exception());
+ return ReadOnlyRoots(isolate).exception();
+ }
return ReadOnlyRoots(isolate).undefined_value();
}
diff --git a/deps/v8/src/builtins/builtins.cc b/deps/v8/src/builtins/builtins.cc
index ed4a844c98..e5829dd1b3 100644
--- a/deps/v8/src/builtins/builtins.cc
+++ b/deps/v8/src/builtins/builtins.cc
@@ -158,8 +158,7 @@ int Builtins::GetStackParameterCount(Name name) {
}
// static
-Callable Builtins::CallableFor(Isolate* isolate, Name name) {
- Handle<Code> code = isolate->builtins()->builtin_handle(name);
+CallInterfaceDescriptor Builtins::CallInterfaceDescriptorFor(Name name) {
CallDescriptors::Key key;
switch (name) {
// This macro is deliberately crafted so as to emit very little code,
@@ -176,12 +175,17 @@ Callable Builtins::CallableFor(Isolate* isolate, Name name) {
Builtins::Kind kind = Builtins::KindOf(name);
DCHECK_NE(BCH, kind);
if (kind == TFJ || kind == CPP) {
- return Callable(code, JSTrampolineDescriptor{});
+ return JSTrampolineDescriptor{};
}
UNREACHABLE();
}
- CallInterfaceDescriptor descriptor(key);
- return Callable(code, descriptor);
+ return CallInterfaceDescriptor{key};
+}
+
+// static
+Callable Builtins::CallableFor(Isolate* isolate, Name name) {
+ Handle<Code> code = isolate->builtins()->builtin_handle(name);
+ return Callable{code, CallInterfaceDescriptorFor(name)};
}
// static
diff --git a/deps/v8/src/builtins/builtins.h b/deps/v8/src/builtins/builtins.h
index f885c6f29f..0b9f2a2b57 100644
--- a/deps/v8/src/builtins/builtins.h
+++ b/deps/v8/src/builtins/builtins.h
@@ -13,6 +13,7 @@ namespace v8 {
namespace internal {
class ByteArray;
+class CallInterfaceDescriptor;
class Callable;
template <typename T>
class Handle;
@@ -92,6 +93,7 @@ class Builtins {
V8_EXPORT_PRIVATE Code builtin(int index);
V8_EXPORT_PRIVATE Handle<Code> builtin_handle(int index);
+ static CallInterfaceDescriptor CallInterfaceDescriptorFor(Name name);
V8_EXPORT_PRIVATE static Callable CallableFor(Isolate* isolate, Name name);
static int GetStackParameterCount(Name name);
diff --git a/deps/v8/src/builtins/collections.tq b/deps/v8/src/builtins/collections.tq
index b83906d109..47d9ec664a 100644
--- a/deps/v8/src/builtins/collections.tq
+++ b/deps/v8/src/builtins/collections.tq
@@ -6,7 +6,7 @@
namespace collections {
@export
- macro LoadKeyValuePairNoSideEffects(implicit context: Context)(o: Object):
+ macro LoadKeyValuePairNoSideEffects(implicit context: Context)(o: JSAny):
KeyValuePair labels MayHaveSideEffects {
typeswitch (o) {
case (a: FastJSArray): {
@@ -28,7 +28,7 @@ namespace collections {
Undefined
};
}
- case (Object): deferred {
+ case (FixedArrayBase): deferred {
unreachable;
}
}
@@ -36,14 +36,14 @@ namespace collections {
case (JSReceiver): {
goto MayHaveSideEffects;
}
- case (o: Object): deferred {
+ case (o: JSAny): deferred {
ThrowTypeError(kIteratorValueNotAnObject, o);
}
}
}
@export
- transitioning macro LoadKeyValuePair(implicit context: Context)(o: Object):
+ transitioning macro LoadKeyValuePair(implicit context: Context)(o: JSAny):
KeyValuePair {
try {
return LoadKeyValuePairNoSideEffects(o) otherwise Generic;
diff --git a/deps/v8/src/builtins/data-view.tq b/deps/v8/src/builtins/data-view.tq
index 62a0cc31c3..2cf0609561 100644
--- a/deps/v8/src/builtins/data-view.tq
+++ b/deps/v8/src/builtins/data-view.tq
@@ -58,11 +58,11 @@ namespace data_view {
}
}
- macro WasNeutered(view: JSArrayBufferView): bool {
+ macro WasDetached(view: JSArrayBufferView): bool {
return IsDetachedBuffer(view.buffer);
}
- macro ValidateDataView(context: Context, o: Object, method: String):
+ macro ValidateDataView(context: Context, o: JSAny, method: String):
JSDataView {
try {
return Cast<JSDataView>(o) otherwise CastError;
@@ -75,7 +75,7 @@ namespace data_view {
// ES6 section 24.2.4.1 get DataView.prototype.buffer
javascript builtin DataViewPrototypeGetBuffer(
js-implicit context: Context,
- receiver: Object)(...arguments): JSArrayBuffer {
+ receiver: JSAny)(...arguments): JSArrayBuffer {
const dataView: JSDataView =
ValidateDataView(context, receiver, 'get DataView.prototype.buffer');
return dataView.buffer;
@@ -83,12 +83,12 @@ namespace data_view {
// ES6 section 24.2.4.2 get DataView.prototype.byteLength
javascript builtin DataViewPrototypeGetByteLength(
- js-implicit context: Context, receiver: Object)(...arguments): Number {
+ js-implicit context: Context, receiver: JSAny)(...arguments): Number {
const dataView: JSDataView = ValidateDataView(
context, receiver, 'get DataView.prototype.byte_length');
- if (WasNeutered(dataView)) {
+ if (WasDetached(dataView)) {
// TODO(bmeurer): According to the ES6 spec, we should throw a TypeError
- // here if the JSArrayBuffer of the {dataView} was neutered.
+ // here if the JSArrayBuffer of the {dataView} was detached.
return 0;
}
return Convert<Number>(dataView.byte_length);
@@ -96,12 +96,12 @@ namespace data_view {
// ES6 section 24.2.4.3 get DataView.prototype.byteOffset
javascript builtin DataViewPrototypeGetByteOffset(
- js-implicit context: Context, receiver: Object)(...arguments): Number {
+ js-implicit context: Context, receiver: JSAny)(...arguments): Number {
const dataView: JSDataView = ValidateDataView(
context, receiver, 'get DataView.prototype.byte_offset');
- if (WasNeutered(dataView)) {
+ if (WasDetached(dataView)) {
// TODO(bmeurer): According to the ES6 spec, we should throw a TypeError
- // here if the JSArrayBuffer of the {dataView} was neutered.
+ // here if the JSArrayBuffer of the {dataView} was detached.
return 0;
}
return Convert<Number>(dataView.byte_offset);
@@ -351,14 +351,14 @@ namespace data_view {
return MakeBigInt(lowWord, highWord, signed);
}
- extern macro ToSmiIndex(Object, Context): Smi
+ extern macro ToSmiIndex(JSAny, Context): Smi
labels RangeError;
extern macro DataViewBuiltinsAssembler::DataViewElementSize(
constexpr ElementsKind): constexpr int31;
transitioning macro DataViewGet(
- context: Context, receiver: Object, offset: Object,
- requestedLittleEndian: Object, kind: constexpr ElementsKind): Numeric {
+ context: Context, receiver: JSAny, offset: JSAny,
+ requestedLittleEndian: JSAny, kind: constexpr ElementsKind): Numeric {
const dataView: JSDataView =
ValidateDataView(context, receiver, MakeDataViewGetterNameString(kind));
@@ -416,91 +416,91 @@ namespace data_view {
}
transitioning javascript builtin DataViewPrototypeGetUint8(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
return DataViewGet(context, receiver, offset, Undefined, UINT8_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeGetInt8(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
return DataViewGet(context, receiver, offset, Undefined, INT8_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeGetUint16(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 1 ? arguments[1] : Undefined;
return DataViewGet(
context, receiver, offset, isLittleEndian, UINT16_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeGetInt16(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 1 ? arguments[1] : Undefined;
return DataViewGet(
context, receiver, offset, isLittleEndian, INT16_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeGetUint32(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 1 ? arguments[1] : Undefined;
return DataViewGet(
context, receiver, offset, isLittleEndian, UINT32_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeGetInt32(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 1 ? arguments[1] : Undefined;
return DataViewGet(
context, receiver, offset, isLittleEndian, INT32_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeGetFloat32(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 1 ? arguments[1] : Undefined;
return DataViewGet(
context, receiver, offset, isLittleEndian, FLOAT32_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeGetFloat64(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 1 ? arguments[1] : Undefined;
return DataViewGet(
context, receiver, offset, isLittleEndian, FLOAT64_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeGetBigUint64(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 1 ? arguments[1] : Undefined;
return DataViewGet(
context, receiver, offset, isLittleEndian, BIGUINT64_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeGetBigInt64(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 1 ? arguments[1] : Undefined;
return DataViewGet(
context, receiver, offset, isLittleEndian, BIGINT64_ELEMENTS);
}
- extern macro ToNumber(Context, Object): Number;
- extern macro ToBigInt(Context, Object): BigInt;
+ extern macro ToNumber(Context, JSAny): Number;
+ extern macro ToBigInt(Context, JSAny): BigInt;
extern macro TruncateFloat64ToWord32(float64): uint32;
extern macro DataViewBuiltinsAssembler::StoreWord8(RawPtr, uintptr, uint32):
@@ -632,8 +632,8 @@ namespace data_view {
}
transitioning macro DataViewSet(
- context: Context, receiver: Object, offset: Object, value: Object,
- requestedLittleEndian: Object, kind: constexpr ElementsKind): Object {
+ context: Context, receiver: JSAny, offset: JSAny, value: JSAny,
+ requestedLittleEndian: JSAny, kind: constexpr ElementsKind): JSAny {
const dataView: JSDataView =
ValidateDataView(context, receiver, MakeDataViewSetterNameString(kind));
@@ -718,96 +718,96 @@ namespace data_view {
}
transitioning javascript builtin DataViewPrototypeSetUint8(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
return DataViewSet(
context, receiver, offset, value, Undefined, UINT8_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeSetInt8(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
return DataViewSet(
context, receiver, offset, value, Undefined, INT8_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeSetUint16(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 2 ? arguments[2] : Undefined;
return DataViewSet(
context, receiver, offset, value, isLittleEndian, UINT16_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeSetInt16(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 2 ? arguments[2] : Undefined;
return DataViewSet(
context, receiver, offset, value, isLittleEndian, INT16_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeSetUint32(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 2 ? arguments[2] : Undefined;
return DataViewSet(
context, receiver, offset, value, isLittleEndian, UINT32_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeSetInt32(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 2 ? arguments[2] : Undefined;
return DataViewSet(
context, receiver, offset, value, isLittleEndian, INT32_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeSetFloat32(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 2 ? arguments[2] : Undefined;
return DataViewSet(
context, receiver, offset, value, isLittleEndian, FLOAT32_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeSetFloat64(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 2 ? arguments[2] : Undefined;
return DataViewSet(
context, receiver, offset, value, isLittleEndian, FLOAT64_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeSetBigUint64(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 2 ? arguments[2] : Undefined;
return DataViewSet(
context, receiver, offset, value, isLittleEndian, BIGUINT64_ELEMENTS);
}
transitioning javascript builtin DataViewPrototypeSetBigInt64(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
- const offset: Object = arguments.length > 0 ? arguments[0] : Undefined;
- const value: Object = arguments.length > 1 ? arguments[1] : Undefined;
- const isLittleEndian: Object =
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
+ const offset: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
+ const value: JSAny = arguments.length > 1 ? arguments[1] : Undefined;
+ const isLittleEndian: JSAny =
arguments.length > 2 ? arguments[2] : Undefined;
return DataViewSet(
context, receiver, offset, value, isLittleEndian, BIGINT64_ELEMENTS);
diff --git a/deps/v8/src/builtins/extras-utils.tq b/deps/v8/src/builtins/extras-utils.tq
index 3675fda191..0b48b962e2 100644
--- a/deps/v8/src/builtins/extras-utils.tq
+++ b/deps/v8/src/builtins/extras-utils.tq
@@ -3,23 +3,22 @@
// found in the LICENSE file.
namespace extras_utils {
- extern runtime CreatePrivateSymbol(Context, Object): HeapObject;
- extern runtime PromiseMarkAsHandled(Context, Object): Undefined;
- extern runtime PromiseStatus(Context, Object): Smi;
+ extern runtime CreatePrivateSymbol(Context, JSAny): PrivateSymbol;
+ extern runtime PromiseMarkAsHandled(Context, JSAny): Undefined;
+ extern runtime PromiseStatus(Context, JSAny): Smi;
javascript builtin ExtrasUtilsCreatePrivateSymbol(
- js-implicit context: Context,
- receiver: Object)(...arguments): HeapObject {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
return CreatePrivateSymbol(context, arguments[0]);
}
javascript builtin ExtrasUtilsMarkPromiseAsHandled(
- js-implicit context: Context, receiver: Object)(...arguments): Undefined {
+ js-implicit context: Context, receiver: JSAny)(...arguments): Undefined {
return PromiseMarkAsHandled(context, arguments[0]);
}
javascript builtin ExtrasUtilsPromiseState(
- js-implicit context: Context, receiver: Object)(...arguments): Smi {
+ js-implicit context: Context, receiver: JSAny)(...arguments): Smi {
return PromiseStatus(context, arguments[0]);
}
}
diff --git a/deps/v8/src/builtins/frames.tq b/deps/v8/src/builtins/frames.tq
index 5559188347..7467381690 100644
--- a/deps/v8/src/builtins/frames.tq
+++ b/deps/v8/src/builtins/frames.tq
@@ -102,7 +102,7 @@ macro LoadLengthFromAdapterFrame(implicit context: Context)(
}
operator '==' macro FrameTypeEquals(f1: FrameType, f2: FrameType): bool {
- return WordEqual(f1, f2);
+ return TaggedEqual(f1, f2);
}
macro Cast<A: type>(implicit context: Context)(o: Frame): A labels CastError;
diff --git a/deps/v8/src/builtins/growable-fixed-array-gen.cc b/deps/v8/src/builtins/growable-fixed-array-gen.cc
index dd23ac5b5a..4fc051eb14 100644
--- a/deps/v8/src/builtins/growable-fixed-array-gen.cc
+++ b/deps/v8/src/builtins/growable-fixed-array-gen.cc
@@ -36,7 +36,7 @@ void GrowableFixedArray::Push(TNode<Object> const value) {
TNode<JSArray> GrowableFixedArray::ToJSArray(TNode<Context> const context) {
const ElementsKind kind = PACKED_ELEMENTS;
- TNode<Context> const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TNode<Map> const array_map = LoadJSArrayElementsMap(kind, native_context);
// Shrink to fit if necessary.
diff --git a/deps/v8/src/builtins/ia32/builtins-ia32.cc b/deps/v8/src/builtins/ia32/builtins-ia32.cc
index 995be77f75..feabac3b66 100644
--- a/deps/v8/src/builtins/ia32/builtins-ia32.cc
+++ b/deps/v8/src/builtins/ia32/builtins-ia32.cc
@@ -72,7 +72,7 @@ void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
ExternalReference real_stack_limit =
- ExternalReference::address_of_real_stack_limit(masm->isolate());
+ ExternalReference::address_of_real_jslimit(masm->isolate());
// Compute the space that is left as a negative number in scratch. If
// we already overflowed, this will be a positive number.
__ mov(scratch, __ ExternalReferenceAsOperand(real_stack_limit, scratch));
@@ -2676,7 +2676,10 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Push(kWasmCompileLazyFuncIndexRegister);
// Load the correct CEntry builtin from the instance object.
__ mov(ecx, FieldOperand(kWasmInstanceRegister,
- WasmInstanceObject::kCEntryStubOffset));
+ WasmInstanceObject::kIsolateRootOffset));
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ __ mov(ecx, MemOperand(ecx, IsolateData::builtin_slot_offset(centry_id)));
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Move(kContextRegister, Smi::zero());
diff --git a/deps/v8/src/builtins/internal-coverage.tq b/deps/v8/src/builtins/internal-coverage.tq
index d96fa924ab..41ec0c36e4 100644
--- a/deps/v8/src/builtins/internal-coverage.tq
+++ b/deps/v8/src/builtins/internal-coverage.tq
@@ -51,7 +51,7 @@ namespace internal_coverage {
}
builtin IncBlockCounter(implicit context: Context)(
- function: JSFunction, coverageArraySlotIndex: Smi): Object {
+ function: JSFunction, coverageArraySlotIndex: Smi): Undefined {
// It's quite possible that a function contains IncBlockCounter bytecodes,
// but no coverage info exists. This happens e.g. by selecting the
// best-effort coverage collection mode, which triggers deletion of all
diff --git a/deps/v8/src/builtins/iterator.tq b/deps/v8/src/builtins/iterator.tq
index b770f1b652..06e8ea539c 100644
--- a/deps/v8/src/builtins/iterator.tq
+++ b/deps/v8/src/builtins/iterator.tq
@@ -11,13 +11,13 @@ namespace iterator {
object: JSReceiver;
// iteratorRecord.[[NextMethod]]
- next: Object;
+ next: JSAny;
}
extern macro IteratorBuiltinsAssembler::GetIteratorMethod(
- implicit context: Context)(Object): Object;
+ implicit context: Context)(JSAny): JSAny;
extern macro IteratorBuiltinsAssembler::GetIterator(
- implicit context: Context)(Object): IteratorRecord;
+ implicit context: Context)(JSAny): IteratorRecord;
extern macro IteratorBuiltinsAssembler::IteratorStep(
implicit context: Context)(IteratorRecord): JSReceiver
@@ -27,18 +27,33 @@ namespace iterator {
labels Done;
extern macro IteratorBuiltinsAssembler::IteratorValue(
- implicit context: Context)(JSReceiver): Object;
+ implicit context: Context)(JSReceiver): JSAny;
extern macro IteratorBuiltinsAssembler::IteratorValue(
- implicit context: Context)(JSReceiver, Map): Object;
+ implicit context: Context)(JSReceiver, Map): JSAny;
extern macro IteratorBuiltinsAssembler::IteratorCloseOnException(
- implicit context: Context)(IteratorRecord, Object): never;
+ implicit context: Context)(IteratorRecord, JSAny): never;
extern macro IteratorBuiltinsAssembler::IterableToList(
- implicit context: Context)(Object, Object): JSArray;
+ implicit context: Context)(JSAny, JSAny): JSArray;
extern builtin IterableToListMayPreserveHoles(implicit context:
- Context)(Object, Object);
+ Context)(JSAny, JSAny);
extern builtin IterableToListWithSymbolLookup(implicit context:
- Context)(Object);
+ Context)(JSAny);
+
+ transitioning builtin GetIteratorWithFeedback(
+ context: Context, receiver: JSAny, feedbackSlot: Smi,
+ feedback: Undefined | FeedbackVector): JSAny {
+ typeswitch (feedback) {
+ case (Undefined): {
+ return GetProperty(receiver, IteratorSymbolConstant());
+ }
+ case (feedback: FeedbackVector): {
+ return LoadIC(
+ context, receiver, IteratorSymbolConstant(), feedbackSlot,
+ feedback);
+ }
+ }
+ }
}
diff --git a/deps/v8/src/builtins/math.tq b/deps/v8/src/builtins/math.tq
index df43b30efc..99a29bd5cb 100644
--- a/deps/v8/src/builtins/math.tq
+++ b/deps/v8/src/builtins/math.tq
@@ -7,7 +7,7 @@ namespace math {
extern macro Float64Acos(float64): float64;
transitioning javascript builtin
- MathAcos(context: Context, _receiver: Object, x: Object): Number {
+ MathAcos(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Acos(value));
}
@@ -16,7 +16,7 @@ namespace math {
extern macro Float64Acosh(float64): float64;
transitioning javascript builtin
- MathAcosh(context: Context, _receiver: Object, x: Object): Number {
+ MathAcosh(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Acosh(value));
}
@@ -25,7 +25,7 @@ namespace math {
extern macro Float64Asin(float64): float64;
transitioning javascript builtin
- MathAsin(context: Context, _receiver: Object, x: Object): Number {
+ MathAsin(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Asin(value));
}
@@ -34,7 +34,7 @@ namespace math {
extern macro Float64Asinh(float64): float64;
transitioning javascript builtin
- MathAsinh(context: Context, _receiver: Object, x: Object): Number {
+ MathAsinh(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Asinh(value));
}
@@ -43,7 +43,7 @@ namespace math {
extern macro Float64Atan(float64): float64;
transitioning javascript builtin
- MathAtan(context: Context, _receiver: Object, x: Object): Number {
+ MathAtan(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Atan(value));
}
@@ -52,7 +52,7 @@ namespace math {
extern macro Float64Atan2(float64, float64): float64;
transitioning javascript builtin
- MathAtan2(context: Context, _receiver: Object, y: Object, x: Object): Number {
+ MathAtan2(js-implicit context: Context)(y: JSAny, x: JSAny): Number {
const yValue = Convert<float64>(ToNumber_Inline(context, y));
const xValue = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Atan2(yValue, xValue));
@@ -62,7 +62,7 @@ namespace math {
extern macro Float64Atanh(float64): float64;
transitioning javascript builtin
- MathAtanh(context: Context, _receiver: Object, x: Object): Number {
+ MathAtanh(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Atanh(value));
}
@@ -71,7 +71,7 @@ namespace math {
extern macro Float64Cbrt(float64): float64;
transitioning javascript builtin
- MathCbrt(context: Context, _receiver: Object, x: Object): Number {
+ MathCbrt(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Cbrt(value));
}
@@ -80,7 +80,7 @@ namespace math {
extern macro Word32Clz(int32): int32;
transitioning javascript builtin
- MathClz32(context: Context, _receiver: Object, x: Object): Number {
+ MathClz32(js-implicit context: Context)(x: JSAny): Number {
const num = ToNumber_Inline(context, x);
let value: int32;
@@ -100,7 +100,7 @@ namespace math {
extern macro Float64Cos(float64): float64;
transitioning javascript builtin
- MathCos(context: Context, _receiver: Object, x: Object): Number {
+ MathCos(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Cos(value));
}
@@ -109,7 +109,7 @@ namespace math {
extern macro Float64Cosh(float64): float64;
transitioning javascript builtin
- MathCosh(context: Context, _receiver: Object, x: Object): Number {
+ MathCosh(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Cosh(value));
}
@@ -118,7 +118,7 @@ namespace math {
extern macro Float64Exp(float64): float64;
transitioning javascript builtin
- MathExp(context: Context, _receiver: Object, x: Object): Number {
+ MathExp(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Exp(value));
}
@@ -127,14 +127,14 @@ namespace math {
extern macro Float64Expm1(float64): float64;
transitioning javascript builtin
- MathExpm1(context: Context, _receiver: Object, x: Object): Number {
+ MathExpm1(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Expm1(value));
}
// ES6 #sec-math.fround
transitioning javascript builtin
- MathFround(context: Context, _receiver: Object, x: Object): Number {
+ MathFround(js-implicit context: Context)(x: JSAny): Number {
const x32 = Convert<float32>(ToNumber_Inline(context, x));
const x64 = Convert<float64>(x32);
return Convert<Number>(x64);
@@ -144,7 +144,7 @@ namespace math {
extern macro Float64Log(float64): float64;
transitioning javascript builtin
- MathLog(context: Context, _receiver: Object, x: Object): Number {
+ MathLog(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Log(value));
}
@@ -153,7 +153,7 @@ namespace math {
extern macro Float64Log1p(float64): float64;
transitioning javascript builtin
- MathLog1p(context: Context, _receiver: Object, x: Object): Number {
+ MathLog1p(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Log1p(value));
}
@@ -162,7 +162,7 @@ namespace math {
extern macro Float64Log10(float64): float64;
transitioning javascript builtin
- MathLog10(context: Context, _receiver: Object, x: Object): Number {
+ MathLog10(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Log10(value));
}
@@ -171,7 +171,7 @@ namespace math {
extern macro Float64Log2(float64): float64;
transitioning javascript builtin
- MathLog2(context: Context, _receiver: Object, x: Object): Number {
+ MathLog2(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Log2(value));
}
@@ -180,14 +180,14 @@ namespace math {
extern macro Float64Sin(float64): float64;
transitioning javascript builtin
- MathSin(context: Context, _receiver: Object, x: Object): Number {
+ MathSin(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Sin(value));
}
// ES6 #sec-math.sign
transitioning javascript builtin
- MathSign(context: Context, _receiver: Object, x: Object): Number {
+ MathSign(js-implicit context: Context)(x: JSAny): Number {
const num = ToNumber_Inline(context, x);
const value = Convert<float64>(num);
@@ -204,7 +204,7 @@ namespace math {
extern macro Float64Sinh(float64): float64;
transitioning javascript builtin
- MathSinh(context: Context, _receiver: Object, x: Object): Number {
+ MathSinh(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Sinh(value));
}
@@ -213,7 +213,7 @@ namespace math {
extern macro Float64Sqrt(float64): float64;
transitioning javascript builtin
- MathSqrt(context: Context, _receiver: Object, x: Object): Number {
+ MathSqrt(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Sqrt(value));
}
@@ -222,7 +222,7 @@ namespace math {
extern macro Float64Tan(float64): float64;
transitioning javascript builtin
- MathTan(context: Context, _receiver: Object, x: Object): Number {
+ MathTan(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Tan(value));
}
@@ -231,8 +231,56 @@ namespace math {
extern macro Float64Tanh(float64): float64;
transitioning javascript builtin
- MathTanh(context: Context, _receiver: Object, x: Object): Number {
+ MathTanh(js-implicit context: Context)(x: JSAny): Number {
const value = Convert<float64>(ToNumber_Inline(context, x));
return Convert<Number>(Float64Tanh(value));
}
+
+ extern macro Float64Abs(float64): float64;
+
+ // ES6 #sec-math.hypot
+ transitioning javascript builtin
+ MathHypot(js-implicit context: Context, receiver: JSAny)(...arguments):
+ Number {
+ const length = arguments.length;
+ if (length == 0) {
+ return 0;
+ }
+ const absValues = AllocateZeroedFixedDoubleArray(length);
+ let oneArgIsNaN: bool = false;
+ let max: float64 = 0;
+ for (let i: intptr = 0; i < length; ++i) {
+ const value = Convert<float64>(ToNumber_Inline(context, arguments[i]));
+ if (Float64IsNaN(value)) {
+ oneArgIsNaN = true;
+ } else {
+ const absValue = Float64Abs(value);
+ absValues.floats[i] = absValue;
+ if (absValue > max) {
+ max = absValue;
+ }
+ }
+ }
+ if (max == V8_INFINITY) {
+ return V8_INFINITY;
+ } else if (oneArgIsNaN) {
+ return kNaN;
+ } else if (max == 0) {
+ return 0;
+ }
+ assert(max > 0);
+
+ // Kahan summation to avoid rounding errors.
+ // Normalize the numbers to the largest one to avoid overflow.
+ let sum: float64 = 0;
+ let compensation: float64 = 0;
+ for (let i: intptr = 0; i < length; ++i) {
+ const n = absValues.floats[i] / max;
+ const summand = n * n - compensation;
+ const preliminary = sum + summand;
+ compensation = (preliminary - sum) - summand;
+ sum = preliminary;
+ }
+ return Convert<Number>(Float64Sqrt(sum) * max);
+ }
}
diff --git a/deps/v8/src/builtins/mips/builtins-mips.cc b/deps/v8/src/builtins/mips/builtins-mips.cc
index a359b2436f..d3237a1c38 100644
--- a/deps/v8/src/builtins/mips/builtins-mips.cc
+++ b/deps/v8/src/builtins/mips/builtins-mips.cc
@@ -84,6 +84,17 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
namespace {
+void LoadRealStackLimit(MacroAssembler* masm, Register destination) {
+ DCHECK(masm->root_array_available());
+ Isolate* isolate = masm->isolate();
+ ExternalReference limit = ExternalReference::address_of_real_jslimit(isolate);
+ DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
+
+ intptr_t offset =
+ TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
+ __ Lw(destination, MemOperand(kRootRegister, static_cast<int32_t>(offset)));
+}
+
void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
@@ -156,7 +167,7 @@ static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
- __ LoadRoot(scratch1, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch1);
// Make scratch1 the space we have left. The stack might already be overflowed
// here which will cause scratch1 to become negative.
__ subu(scratch1, sp, scratch1);
@@ -368,7 +379,7 @@ static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc,
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
- __ LoadRoot(scratch1, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch1);
// Make a2 the space we have left. The stack might already be overflowed
// here which will cause a2 to become negative.
__ Subu(scratch1, sp, scratch1);
@@ -715,7 +726,7 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
- __ LoadRoot(kScratchReg, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, kScratchReg);
__ Branch(&stack_overflow, lo, sp, Operand(kScratchReg));
// Push receiver.
@@ -1082,7 +1093,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Do a stack check to ensure we don't go over the limit.
Label ok;
__ Subu(t1, sp, Operand(t0));
- __ LoadRoot(a2, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, a2);
__ Branch(&ok, hs, t1, Operand(a2));
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bind(&ok);
@@ -2061,7 +2072,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
__ Subu(sp, sp, Operand(t1));
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
- __ LoadRoot(kScratchReg, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, kScratchReg);
__ Branch(&done, hs, sp, Operand(kScratchReg));
// Restore the stack pointer.
__ Addu(sp, sp, Operand(t1));
@@ -2219,7 +2230,7 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
__ Subu(sp, sp, Operand(t1));
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
- __ LoadRoot(kScratchReg, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, kScratchReg);
__ Branch(&done, hs, sp, Operand(kScratchReg));
// Restore the stack pointer.
__ Addu(sp, sp, Operand(t1));
@@ -2488,7 +2499,10 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Push(kWasmInstanceRegister, kWasmCompileLazyFuncIndexRegister);
// Load the correct CEntry builtin from the instance object.
__ lw(a2, FieldMemOperand(kWasmInstanceRegister,
- WasmInstanceObject::kCEntryStubOffset));
+ WasmInstanceObject::kIsolateRootOffset));
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ __ lw(a2, MemOperand(a2, IsolateData::builtin_slot_offset(centry_id)));
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Move(kContextRegister, Smi::zero());
diff --git a/deps/v8/src/builtins/mips64/builtins-mips64.cc b/deps/v8/src/builtins/mips64/builtins-mips64.cc
index c5565b90de..7cb66470a3 100644
--- a/deps/v8/src/builtins/mips64/builtins-mips64.cc
+++ b/deps/v8/src/builtins/mips64/builtins-mips64.cc
@@ -83,6 +83,18 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
namespace {
+void LoadRealStackLimit(MacroAssembler* masm, Register destination) {
+ DCHECK(masm->root_array_available());
+ Isolate* isolate = masm->isolate();
+ ExternalReference limit = ExternalReference::address_of_real_jslimit(isolate);
+ DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
+
+ intptr_t offset =
+ TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
+ CHECK(is_int32(offset));
+ __ Ld(destination, MemOperand(kRootRegister, static_cast<int32_t>(offset)));
+}
+
void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : number of arguments
@@ -156,7 +168,7 @@ static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
- __ LoadRoot(scratch1, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch1);
// Make scratch1 the space we have left. The stack might already be overflowed
// here which will cause scratch1 to become negative.
__ dsubu(scratch1, sp, scratch1);
@@ -407,7 +419,7 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
- __ LoadRoot(kScratchReg, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, kScratchReg);
__ Branch(&stack_overflow, lo, sp, Operand(kScratchReg));
// Push receiver.
@@ -514,7 +526,7 @@ static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc,
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
- __ LoadRoot(scratch1, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch1);
// Make a2 the space we have left. The stack might already be overflowed
// here which will cause r2 to become negative.
__ dsubu(scratch1, sp, scratch1);
@@ -1099,7 +1111,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Do a stack check to ensure we don't go over the limit.
Label ok;
__ Dsubu(a5, sp, Operand(a4));
- __ LoadRoot(a2, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, a2);
__ Branch(&ok, hs, a5, Operand(a2));
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bind(&ok);
@@ -2100,7 +2112,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
__ Dsubu(sp, sp, Operand(a5));
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
- __ LoadRoot(kScratchReg, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, kScratchReg);
__ Branch(&done, hs, sp, Operand(kScratchReg));
// Restore the stack pointer.
__ Daddu(sp, sp, Operand(a5));
@@ -2254,7 +2266,7 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
__ Dsubu(sp, sp, Operand(a5));
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
- __ LoadRoot(kScratchReg, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, kScratchReg);
__ Branch(&done, hs, sp, Operand(kScratchReg));
// Restore the stack pointer.
__ Daddu(sp, sp, Operand(a5));
@@ -2525,7 +2537,10 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Push(kWasmInstanceRegister, kWasmCompileLazyFuncIndexRegister);
// Load the correct CEntry builtin from the instance object.
__ Ld(a2, FieldMemOperand(kWasmInstanceRegister,
- WasmInstanceObject::kCEntryStubOffset));
+ WasmInstanceObject::kIsolateRootOffset));
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ __ Ld(a2, MemOperand(a2, IsolateData::builtin_slot_offset(centry_id)));
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Move(kContextRegister, Smi::zero());
diff --git a/deps/v8/src/builtins/object-fromentries.tq b/deps/v8/src/builtins/object-fromentries.tq
index 32115e78ea..fc36e34038 100644
--- a/deps/v8/src/builtins/object-fromentries.tq
+++ b/deps/v8/src/builtins/object-fromentries.tq
@@ -5,7 +5,7 @@
namespace object {
transitioning macro ObjectFromEntriesFastCase(implicit context: Context)(
- iterable: Object): JSObject labels IfSlow {
+ iterable: JSAny): JSObject labels IfSlow {
typeswitch (iterable) {
case (array: FastJSArrayWithNoCustomIteration): {
const elements: FixedArray =
@@ -14,7 +14,7 @@ namespace object {
const result: JSObject = NewJSObject();
for (let k: Smi = 0; k < length; ++k) {
- const value: Object = array::LoadElementOrUndefined(elements, k);
+ const value: JSAny = array::LoadElementOrUndefined(elements, k);
const pair: KeyValuePair =
collections::LoadKeyValuePairNoSideEffects(value)
otherwise IfSlow;
@@ -26,16 +26,16 @@ namespace object {
}
return result;
}
- case (Object): {
+ case (JSAny): {
goto IfSlow;
}
}
}
transitioning javascript builtin
- ObjectFromEntries(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
- const iterable: Object = arguments[0];
+ ObjectFromEntries(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
+ const iterable: JSAny = arguments[0];
try {
if (IsNullOrUndefined(iterable)) goto Throw;
return ObjectFromEntriesFastCase(iterable) otherwise IfSlow;
@@ -50,7 +50,7 @@ namespace object {
const step: JSReceiver =
iterator::IteratorStep(i, fastIteratorResultMap)
otherwise return result;
- const iteratorValue: Object =
+ const iteratorValue: JSAny =
iterator::IteratorValue(step, fastIteratorResultMap);
const pair: KeyValuePair =
collections::LoadKeyValuePair(iteratorValue);
diff --git a/deps/v8/src/builtins/object.tq b/deps/v8/src/builtins/object.tq
index 6706a8f943..3dc973cf40 100644
--- a/deps/v8/src/builtins/object.tq
+++ b/deps/v8/src/builtins/object.tq
@@ -4,31 +4,31 @@
namespace runtime {
extern transitioning runtime
- ObjectIsExtensible(implicit context: Context)(Object): Object;
+ ObjectIsExtensible(implicit context: Context)(JSAny): JSAny;
extern transitioning runtime
JSReceiverPreventExtensionsThrow(implicit context: Context)(JSReceiver):
- Object;
+ JSAny;
extern transitioning runtime
JSReceiverPreventExtensionsDontThrow(implicit context: Context)(JSReceiver):
- Object;
+ JSAny;
extern transitioning runtime
- JSReceiverGetPrototypeOf(implicit context: Context)(JSReceiver): Object;
+ JSReceiverGetPrototypeOf(implicit context: Context)(JSReceiver): JSAny;
extern transitioning runtime
- JSReceiverSetPrototypeOfThrow(implicit context: Context)(JSReceiver, Object):
- Object;
+ JSReceiverSetPrototypeOfThrow(implicit context: Context)(JSReceiver, JSAny):
+ JSAny;
extern transitioning runtime
JSReceiverSetPrototypeOfDontThrow(implicit context:
- Context)(JSReceiver, Object): Object;
+ Context)(JSReceiver, JSAny): JSAny;
} // namespace runtime
namespace object {
transitioning macro
- ObjectIsExtensible(implicit context: Context)(object: Object): Object {
+ ObjectIsExtensible(implicit context: Context)(object: JSAny): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return False;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::ObjectIsExtensible(objectJSReceiver);
@@ -36,8 +36,8 @@ namespace object {
}
transitioning macro
- ObjectPreventExtensionsThrow(implicit context: Context)(object: Object):
- Object {
+ ObjectPreventExtensionsThrow(implicit context: Context)(object: JSAny):
+ JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return object;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::JSReceiverPreventExtensionsThrow(
@@ -47,8 +47,8 @@ namespace object {
}
transitioning macro
- ObjectPreventExtensionsDontThrow(implicit context: Context)(object: Object):
- Object {
+ ObjectPreventExtensionsDontThrow(implicit context: Context)(object: JSAny):
+ JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return False;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::JSReceiverPreventExtensionsDontThrow(
@@ -57,14 +57,14 @@ namespace object {
}
transitioning macro
- ObjectGetPrototypeOf(implicit context: Context)(object: Object): Object {
+ ObjectGetPrototypeOf(implicit context: Context)(object: JSAny): JSAny {
const objectJSReceiver: JSReceiver = ToObject_Inline(context, object);
return object::JSReceiverGetPrototypeOf(objectJSReceiver);
}
transitioning macro
JSReceiverGetPrototypeOf(implicit context: Context)(object: JSReceiver):
- Object {
+ JSAny {
const objectJSProxy = Cast<JSProxy>(object)
otherwise return runtime::JSReceiverGetPrototypeOf(object);
return proxy::ProxyGetPrototypeOf(objectJSProxy);
@@ -72,7 +72,7 @@ namespace object {
transitioning macro
ObjectSetPrototypeOfThrow(implicit context: Context)(
- object: Object, proto: Object): Object {
+ object: JSAny, proto: JSReceiver | Null): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return object;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::JSReceiverSetPrototypeOfThrow(
@@ -83,7 +83,7 @@ namespace object {
transitioning macro
ObjectSetPrototypeOfDontThrow(implicit context: Context)(
- object: Object, proto: Object): Object {
+ object: JSAny, proto: JSReceiver | Null): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object) otherwise return False;
const objectJSProxy = Cast<JSProxy>(objectJSReceiver)
otherwise return runtime::JSReceiverSetPrototypeOfDontThrow(
@@ -94,24 +94,24 @@ namespace object {
namespace object_isextensible {
// ES6 section 19.1.2.11 Object.isExtensible ( O )
- transitioning javascript builtin ObjectIsExtensible(
- js-implicit context: Context)(_receiver: Object, object: Object): Object {
+ transitioning javascript builtin
+ ObjectIsExtensible(js-implicit context: Context)(object: JSAny): JSAny {
return object::ObjectIsExtensible(object);
}
} // namespace object_isextensible
namespace object_preventextensions {
// ES6 section 19.1.2.11 Object.isExtensible ( O )
- transitioning javascript builtin ObjectPreventExtensions(
- js-implicit context: Context)(_receiver: Object, object: Object): Object {
+ transitioning javascript builtin
+ ObjectPreventExtensions(js-implicit context: Context)(object: JSAny): JSAny {
return object::ObjectPreventExtensionsThrow(object);
}
} // namespace object_preventextensions
namespace object_getprototypeof {
// ES6 section 19.1.2.9 Object.getPrototypeOf ( O )
- transitioning javascript builtin ObjectGetPrototypeOf(
- js-implicit context: Context)(_receiver: Object, object: Object): Object {
+ transitioning javascript builtin
+ ObjectGetPrototypeOf(js-implicit context: Context)(object: JSAny): JSAny {
return object::ObjectGetPrototypeOf(object);
}
} // namespace object_getprototypeof
@@ -119,8 +119,7 @@ namespace object_getprototypeof {
namespace object_setprototypeof {
// ES6 section 19.1.2.21 Object.setPrototypeOf ( O, proto )
transitioning javascript builtin ObjectSetPrototypeOf(
- js-implicit context:
- Context)(_receiver: Object, object: Object, proto: Object): Object {
+ js-implicit context: Context)(object: JSAny, proto: JSAny): JSAny {
// 1. Set O to ? RequireObjectCoercible(O).
RequireObjectCoercible(object, 'Object.setPrototypeOf');
@@ -130,9 +129,13 @@ namespace object_setprototypeof {
// 4. Let status be ? O.[[SetPrototypeOf]](proto).
// 5. If status is false, throw a TypeError exception.
// 6. Return O.
- if (proto == Null || Is<JSReceiver>(proto)) {
- return object::ObjectSetPrototypeOfThrow(object, proto);
+ typeswitch (proto) {
+ case (proto: JSReceiver | Null): {
+ return object::ObjectSetPrototypeOfThrow(object, proto);
+ }
+ case (JSAny): {
+ ThrowTypeError(kProtoObjectOrNull, proto);
+ }
}
- ThrowTypeError(kProtoObjectOrNull, proto);
}
} // namespace object_setprototypeof
diff --git a/deps/v8/src/builtins/ppc/builtins-ppc.cc b/deps/v8/src/builtins/ppc/builtins-ppc.cc
index a42cb9bebd..485b793395 100644
--- a/deps/v8/src/builtins/ppc/builtins-ppc.cc
+++ b/deps/v8/src/builtins/ppc/builtins-ppc.cc
@@ -81,12 +81,24 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
namespace {
+void LoadRealStackLimit(MacroAssembler* masm, Register destination) {
+ DCHECK(masm->root_array_available());
+ Isolate* isolate = masm->isolate();
+ ExternalReference limit = ExternalReference::address_of_real_jslimit(isolate);
+ DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
+
+ intptr_t offset =
+ TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
+ CHECK(is_int32(offset));
+ __ LoadP(destination, MemOperand(kRootRegister, offset));
+}
+
void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch, Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
- __ LoadRoot(scratch, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch);
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
__ sub(scratch, sp, scratch);
@@ -437,7 +449,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
- __ CompareRoot(sp, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch);
+ __ cmpl(sp, scratch);
__ blt(&stack_overflow);
// Push receiver.
@@ -729,7 +742,7 @@ static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc,
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
- __ LoadRoot(scratch1, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, scratch1);
// Make scratch1 the space we have left. The stack might already be overflowed
// here which will cause scratch1 to become negative.
__ sub(scratch1, sp, scratch1);
@@ -1144,7 +1157,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Do a stack check to ensure we don't go over the limit.
Label ok;
__ sub(r8, sp, r5);
- __ LoadRoot(r0, RootIndex::kRealStackLimit);
+ LoadRealStackLimit(masm, r0);
__ cmpl(r8, r0);
__ bge(&ok);
__ CallRuntime(Runtime::kThrowStackOverflow);
@@ -2163,7 +2176,12 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack
// limit".
- __ CompareRoot(sp, RootIndex::kRealStackLimit);
+ {
+ UseScratchRegisterScope temps(masm);
+ Register scratch = temps.Acquire();
+ LoadRealStackLimit(masm, scratch);
+ __ cmpl(sp, scratch);
+ }
__ bgt(&done); // Signed comparison.
// Restore the stack pointer.
__ mr(sp, scratch);
@@ -2599,7 +2617,10 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Push(kWasmInstanceRegister, kWasmCompileLazyFuncIndexRegister);
// Load the correct CEntry builtin from the instance object.
__ LoadP(r5, FieldMemOperand(kWasmInstanceRegister,
- WasmInstanceObject::kCEntryStubOffset));
+ WasmInstanceObject::kIsolateRootOffset));
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ __ LoadP(r5, MemOperand(r5, IsolateData::builtin_slot_offset(centry_id)));
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ LoadSmiLiteral(cp, Smi::zero());
diff --git a/deps/v8/src/builtins/proxy-constructor.tq b/deps/v8/src/builtins/proxy-constructor.tq
index ad60c20e2c..cfb11046a7 100644
--- a/deps/v8/src/builtins/proxy-constructor.tq
+++ b/deps/v8/src/builtins/proxy-constructor.tq
@@ -10,8 +10,8 @@ namespace proxy {
// https://tc39.github.io/ecma262/#sec-proxy-constructor
transitioning javascript builtin
ProxyConstructor(
- js-implicit context: Context, receiver: Object,
- newTarget: Object)(target: Object, handler: Object): JSProxy {
+ js-implicit context: Context, receiver: JSAny,
+ newTarget: JSAny)(target: JSAny, handler: JSAny): JSProxy {
try {
// 1. If NewTarget is undefined, throw a TypeError exception.
if (newTarget == Undefined) {
diff --git a/deps/v8/src/builtins/proxy-delete-property.tq b/deps/v8/src/builtins/proxy-delete-property.tq
index 759de766ef..3054c0d07a 100644
--- a/deps/v8/src/builtins/proxy-delete-property.tq
+++ b/deps/v8/src/builtins/proxy-delete-property.tq
@@ -10,8 +10,10 @@ namespace proxy {
// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-delete-p
transitioning builtin
ProxyDeleteProperty(implicit context: Context)(
- proxy: JSProxy, name: Name, languageMode: LanguageMode): Object {
+ proxy: JSProxy, name: PropertyKey, languageMode: LanguageMode): JSAny {
const kTrapName: constexpr string = 'deleteProperty';
+ // Handle deeply nested proxy.
+ PerformStackCheck();
// 1. Assert: IsPropertyKey(P) is true.
assert(TaggedIsNotSmi(name));
assert(IsName(name));
@@ -38,7 +40,7 @@ namespace proxy {
const trapResult = Call(context, trap, handler, target, name);
// 9. If booleanTrapResult is false, return false.
- if (BranchIfToBooleanIsFalse(trapResult)) {
+ if (!ToBoolean(trapResult)) {
if (languageMode == SmiConstant(kStrict)) {
ThrowTypeError(kProxyTrapReturnedFalsishFor, kTrapName, name);
}
@@ -56,7 +58,7 @@ namespace proxy {
// 15. Return true.
return True;
}
- label TrapUndefined(target: Object) {
+ label TrapUndefined(target: JSAny) {
// 7.a. Return ? target.[[Delete]](P).
return DeleteProperty(target, name, languageMode);
}
diff --git a/deps/v8/src/builtins/proxy-get-property.tq b/deps/v8/src/builtins/proxy-get-property.tq
index bac07f550c..54b8cde243 100644
--- a/deps/v8/src/builtins/proxy-get-property.tq
+++ b/deps/v8/src/builtins/proxy-get-property.tq
@@ -7,14 +7,14 @@
namespace proxy {
extern transitioning builtin GetPropertyWithReceiver(
- implicit context: Context)(Object, Name, Object, Smi): Object;
+ implicit context: Context)(JSAny, Name, JSAny, Smi): JSAny;
// ES #sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver
// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver
transitioning builtin
ProxyGetProperty(implicit context: Context)(
- proxy: JSProxy, name: Name, receiverValue: Object,
- onNonExistent: Smi): Object {
+ proxy: JSProxy, name: PropertyKey, receiverValue: JSAny,
+ onNonExistent: Smi): JSAny {
PerformStackCheck();
// 1. Assert: IsPropertyKey(P) is true.
assert(TaggedIsNotSmi(name));
diff --git a/deps/v8/src/builtins/proxy-get-prototype-of.tq b/deps/v8/src/builtins/proxy-get-prototype-of.tq
index 2418eaf423..653d4503d1 100644
--- a/deps/v8/src/builtins/proxy-get-prototype-of.tq
+++ b/deps/v8/src/builtins/proxy-get-prototype-of.tq
@@ -9,7 +9,7 @@ namespace proxy {
// ES #sec-proxy-object-internal-methods-and-internal-slots-isextensible
// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-isextensible
transitioning builtin
- ProxyGetPrototypeOf(implicit context: Context)(proxy: JSProxy): Object {
+ ProxyGetPrototypeOf(implicit context: Context)(proxy: JSProxy): JSAny {
PerformStackCheck();
const kTrapName: constexpr string = 'getPrototypeOf';
try {
@@ -39,7 +39,7 @@ namespace proxy {
// 9. Let extensibleTarget be ? IsExtensible(target).
// 10. If extensibleTarget is true, return handlerProto.
- const extensibleTarget: Object = object::ObjectIsExtensible(target);
+ const extensibleTarget: JSAny = object::ObjectIsExtensible(target);
assert(extensibleTarget == True || extensibleTarget == False);
if (extensibleTarget == True) {
return handlerProto;
@@ -51,12 +51,12 @@ namespace proxy {
// 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError
// exception.
// 13. Return handlerProto.
- if (BranchIfSameValue(targetProto, handlerProto)) {
+ if (SameValue(targetProto, handlerProto)) {
return handlerProto;
}
ThrowTypeError(kProxyGetPrototypeOfNonExtensible);
}
- label TrapUndefined(target: Object) {
+ label TrapUndefined(target: JSAny) {
// 6.a. Return ? target.[[GetPrototypeOf]]().
return object::ObjectGetPrototypeOf(target);
}
diff --git a/deps/v8/src/builtins/proxy-has-property.tq b/deps/v8/src/builtins/proxy-has-property.tq
index ee394c5d84..1f14c68903 100644
--- a/deps/v8/src/builtins/proxy-has-property.tq
+++ b/deps/v8/src/builtins/proxy-has-property.tq
@@ -9,7 +9,7 @@ namespace proxy {
// ES #sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p
// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p
transitioning builtin ProxyHasProperty(implicit context: Context)(
- proxy: JSProxy, name: Name): Object {
+ proxy: JSProxy, name: PropertyKey): JSAny {
assert(IsJSProxy(proxy));
PerformStackCheck();
@@ -40,13 +40,13 @@ namespace proxy {
// CheckHasTrapResult).
// 10. Return booleanTrapResult.
const trapResult = Call(context, trap, handler, target, name);
- if (BranchIfToBooleanIsTrue(trapResult)) {
+ if (ToBoolean(trapResult)) {
return True;
}
CheckHasTrapResult(target, proxy, name);
return False;
}
- label TrapUndefined(target: Object) {
+ label TrapUndefined(target: JSAny) {
// 7.a. Return ? target.[[HasProperty]](P).
tail HasProperty(target, name);
}
diff --git a/deps/v8/src/builtins/proxy-is-extensible.tq b/deps/v8/src/builtins/proxy-is-extensible.tq
index 82f4a5b955..dfbdc6f734 100644
--- a/deps/v8/src/builtins/proxy-is-extensible.tq
+++ b/deps/v8/src/builtins/proxy-is-extensible.tq
@@ -9,7 +9,7 @@ namespace proxy {
// ES #sec-proxy-object-internal-methods-and-internal-slots-isextensible
// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-isextensible
transitioning builtin ProxyIsExtensible(implicit context:
- Context)(proxy: JSProxy): Object {
+ Context)(proxy: JSProxy): JSAny {
PerformStackCheck();
const kTrapName: constexpr string = 'isExtensible';
try {
@@ -45,7 +45,7 @@ namespace proxy {
// 10. Return booleanTrapResult.
return SelectBooleanConstant(trapResult);
}
- label TrapUndefined(target: Object) {
+ label TrapUndefined(target: JSAny) {
// 6.a. Return ? IsExtensible(target).
return object::ObjectIsExtensible(target);
}
diff --git a/deps/v8/src/builtins/proxy-prevent-extensions.tq b/deps/v8/src/builtins/proxy-prevent-extensions.tq
index 6d5d2569fb..ab75cfc4cb 100644
--- a/deps/v8/src/builtins/proxy-prevent-extensions.tq
+++ b/deps/v8/src/builtins/proxy-prevent-extensions.tq
@@ -9,8 +9,8 @@ namespace proxy {
// ES #sec-proxy-object-internal-methods-and-internal-slots-preventextensions
// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-preventextensions
transitioning builtin
- ProxyPreventExtensions(implicit context: Context)(
- proxy: JSProxy, doThrow: Boolean): Object {
+ ProxyPreventExtensions(implicit context:
+ Context)(proxy: JSProxy, doThrow: Boolean): JSAny {
PerformStackCheck();
const kTrapName: constexpr string = 'preventExtensions';
try {
@@ -36,8 +36,8 @@ namespace proxy {
// 8. If booleanTrapResult is true, then
// 8.a. Let extensibleTarget be ? IsExtensible(target).
// 8.b If extensibleTarget is true, throw a TypeError exception.
- if (BranchIfToBooleanIsTrue(trapResult)) {
- const extensibleTarget: Object = object::ObjectIsExtensible(target);
+ if (ToBoolean(trapResult)) {
+ const extensibleTarget: JSAny = object::ObjectIsExtensible(target);
assert(extensibleTarget == True || extensibleTarget == False);
if (extensibleTarget == True) {
ThrowTypeError(kProxyPreventExtensionsExtensible);
@@ -52,7 +52,7 @@ namespace proxy {
// 9. Return booleanTrapResult.
return True;
}
- label TrapUndefined(target: Object) {
+ label TrapUndefined(target: JSAny) {
// 6.a. Return ? target.[[PreventExtensions]]().
if (doThrow == True) {
return object::ObjectPreventExtensionsThrow(target);
diff --git a/deps/v8/src/builtins/proxy-revocable.tq b/deps/v8/src/builtins/proxy-revocable.tq
index b09baab9cf..465b1aef96 100644
--- a/deps/v8/src/builtins/proxy-revocable.tq
+++ b/deps/v8/src/builtins/proxy-revocable.tq
@@ -12,9 +12,8 @@ namespace proxy {
// Proxy.revocable(target, handler)
// https://tc39.github.io/ecma262/#sec-proxy.revocable
transitioning javascript builtin
- ProxyRevocable(
- context: Context, _receiver: Object, target: Object,
- handler: Object): JSProxyRevocableResult {
+ ProxyRevocable(js-implicit context: Context)(target: JSAny, handler: JSAny):
+ JSProxyRevocableResult {
try {
const targetJSReceiver =
Cast<JSReceiver>(target) otherwise ThrowProxyNonObject;
diff --git a/deps/v8/src/builtins/proxy-set-property.tq b/deps/v8/src/builtins/proxy-set-property.tq
index d0411a8e89..2d9636c881 100644
--- a/deps/v8/src/builtins/proxy-set-property.tq
+++ b/deps/v8/src/builtins/proxy-set-property.tq
@@ -19,15 +19,21 @@ namespace proxy {
// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver
transitioning builtin
ProxySetProperty(implicit context: Context)(
- proxy: JSProxy, name: Name, value: Object,
- receiverValue: Object): Object {
+ proxy: JSProxy, name: PropertyKey | PrivateSymbol, value: JSAny,
+ receiverValue: JSAny): JSAny {
// 1. Assert: IsPropertyKey(P) is true.
assert(TaggedIsNotSmi(name));
assert(IsName(name));
- if (IsPrivateSymbol(name)) {
- CallThrowTypeErrorIfStrict(kProxyPrivate);
- return Undefined;
+ let key: PropertyKey;
+ typeswitch (name) {
+ case (PrivateSymbol): {
+ CallThrowTypeErrorIfStrict(kProxyPrivate);
+ return Undefined;
+ }
+ case (name: PropertyKey): {
+ key = name;
+ }
}
try {
@@ -61,8 +67,8 @@ namespace proxy {
// exception.
// 12. Return true.
const trapResult =
- Call(context, trap, handler, target, name, value, receiverValue);
- if (BranchIfToBooleanIsTrue(trapResult)) {
+ Call(context, trap, handler, target, key, value, receiverValue);
+ if (ToBoolean(trapResult)) {
CheckGetSetTrapResult(target, proxy, name, value, kProxySet);
return value;
}
diff --git a/deps/v8/src/builtins/proxy-set-prototype-of.tq b/deps/v8/src/builtins/proxy-set-prototype-of.tq
index bbd99be411..355c258ab8 100644
--- a/deps/v8/src/builtins/proxy-set-prototype-of.tq
+++ b/deps/v8/src/builtins/proxy-set-prototype-of.tq
@@ -10,7 +10,7 @@ namespace proxy {
// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
transitioning builtin
ProxySetPrototypeOf(implicit context: Context)(
- proxy: JSProxy, proto: Object, doThrow: Boolean): Object {
+ proxy: JSProxy, proto: Null | JSReceiver, doThrow: Boolean): JSAny {
PerformStackCheck();
const kTrapName: constexpr string = 'setPrototypeOf';
try {
@@ -37,7 +37,7 @@ namespace proxy {
const trapResult = Call(context, trap, handler, target, proto);
// 9. If booleanTrapResult is false, return false.
- if (BranchIfToBooleanIsFalse(trapResult)) {
+ if (!ToBoolean(trapResult)) {
if (doThrow == True) {
ThrowTypeError(kProxyTrapReturnedFalsishFor, kTrapName);
}
@@ -58,12 +58,12 @@ namespace proxy {
// 13. If SameValue(V, targetProto) is false, throw a TypeError
// exception.
// 14. Return true.
- if (BranchIfSameValue(proto, targetProto)) {
+ if (SameValue(proto, targetProto)) {
return True;
}
ThrowTypeError(kProxySetPrototypeOfNonExtensible);
}
- label TrapUndefined(target: Object, proto: Object) {
+ label TrapUndefined(target: JSAny, proto: JSReceiver | Null) {
// 7.a. Return ? target.[[SetPrototypeOf]]().
if (doThrow == True) {
return object::ObjectSetPrototypeOfThrow(target, proto);
diff --git a/deps/v8/src/builtins/reflect.tq b/deps/v8/src/builtins/reflect.tq
index 4c25e8338f..97c6ec81a7 100644
--- a/deps/v8/src/builtins/reflect.tq
+++ b/deps/v8/src/builtins/reflect.tq
@@ -8,24 +8,24 @@ namespace reflect {
generates 'MessageTemplate::kCalledOnNonObject';
// ES6 section 26.1.10 Reflect.isExtensible
- transitioning javascript builtin ReflectIsExtensible(
- js-implicit context: Context)(_receiver: Object, object: Object): Object {
+ transitioning javascript builtin
+ ReflectIsExtensible(js-implicit context: Context)(object: JSAny): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object)
otherwise ThrowTypeError(kCalledOnNonObject, 'Reflect.isExtensible');
return object::ObjectIsExtensible(objectJSReceiver);
}
// ES6 section 26.1.12 Reflect.preventExtensions
- transitioning javascript builtin ReflectPreventExtensions(
- js-implicit context: Context)(_receiver: Object, object: Object): Object {
+ transitioning javascript builtin
+ ReflectPreventExtensions(js-implicit context: Context)(object: JSAny): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object)
otherwise ThrowTypeError(kCalledOnNonObject, 'Reflect.preventExtensions');
return object::ObjectPreventExtensionsDontThrow(objectJSReceiver);
}
// ES6 section 26.1.8 Reflect.getPrototypeOf
- transitioning javascript builtin ReflectGetPrototypeOf(
- js-implicit context: Context)(_receiver: Object, object: Object): Object {
+ transitioning javascript builtin
+ ReflectGetPrototypeOf(js-implicit context: Context)(object: JSAny): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object)
otherwise ThrowTypeError(kCalledOnNonObject, 'Reflect.getPrototypeOf');
return object::JSReceiverGetPrototypeOf(objectJSReceiver);
@@ -33,50 +33,47 @@ namespace reflect {
// ES6 section 26.1.14 Reflect.setPrototypeOf
transitioning javascript builtin ReflectSetPrototypeOf(
- js-implicit context:
- Context)(_receiver: Object, object: Object, proto: Object): Object {
+ js-implicit context: Context)(object: JSAny, proto: JSAny): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object)
otherwise ThrowTypeError(kCalledOnNonObject, 'Reflect.setPrototypeOf');
- if (proto == Null || Is<JSReceiver>(proto)) {
- return object::ObjectSetPrototypeOfDontThrow(objectJSReceiver, proto);
+ typeswitch (proto) {
+ case (proto: JSReceiver | Null): {
+ return object::ObjectSetPrototypeOfDontThrow(objectJSReceiver, proto);
+ }
+ case (JSAny): {
+ ThrowTypeError(kProtoObjectOrNull, proto);
+ }
}
- ThrowTypeError(kProtoObjectOrNull, proto);
}
- extern transitioning builtin ToName(implicit context: Context)(Object): Name;
+ extern transitioning builtin ToName(implicit context: Context)(JSAny):
+ AnyName;
type OnNonExistent constexpr 'OnNonExistent';
const kReturnUndefined: constexpr OnNonExistent
generates 'OnNonExistent::kReturnUndefined';
extern macro SmiConstant(constexpr OnNonExistent): Smi;
extern transitioning builtin GetPropertyWithReceiver(
- implicit context: Context)(Object, Name, Object, Smi): Object;
+ implicit context: Context)(JSAny, Name, JSAny, Smi): JSAny;
// ES6 section 26.1.6 Reflect.get
transitioning javascript builtin
- ReflectGet(js-implicit context: Context)(...arguments): Object {
+ ReflectGet(js-implicit context: Context)(...arguments): JSAny {
const length = arguments.length;
- const object: Object = length > 0 ? arguments[0] : Undefined;
+ const object: JSAny = length > 0 ? arguments[0] : Undefined;
const objectJSReceiver = Cast<JSReceiver>(object)
otherwise ThrowTypeError(kCalledOnNonObject, 'Reflect.get');
- const propertyKey: Object = length > 1 ? arguments[1] : Undefined;
- const name: Name = ToName(propertyKey);
- const receiver: Object = length > 2 ? arguments[2] : objectJSReceiver;
+ const propertyKey: JSAny = length > 1 ? arguments[1] : Undefined;
+ const name: AnyName = ToName(propertyKey);
+ const receiver: JSAny = length > 2 ? arguments[2] : objectJSReceiver;
return GetPropertyWithReceiver(
objectJSReceiver, name, receiver, SmiConstant(kReturnUndefined));
}
// ES6 section 26.1.4 Reflect.deleteProperty
transitioning javascript builtin ReflectDeleteProperty(
- js-implicit context:
- Context)(_receiver: Object, object: Object, key: Object): Object {
+ js-implicit context: Context)(object: JSAny, key: JSAny): JSAny {
const objectJSReceiver = Cast<JSReceiver>(object)
otherwise ThrowTypeError(kCalledOnNonObject, 'Reflect.deleteProperty');
- const name: Name = ToName(key);
- if (IsPrivateSymbol(name)) {
- return DeleteProperty(objectJSReceiver, name, kSloppy);
- }
- const proxy = Cast<JSProxy>(objectJSReceiver)
- otherwise return DeleteProperty(objectJSReceiver, name, kSloppy);
- return proxy::ProxyDeleteProperty(proxy, name, kSloppy);
+ return DeleteProperty(objectJSReceiver, key, kSloppy);
}
} // namespace reflect
diff --git a/deps/v8/src/builtins/regexp-match.tq b/deps/v8/src/builtins/regexp-match.tq
new file mode 100644
index 0000000000..dbee8a616a
--- /dev/null
+++ b/deps/v8/src/builtins/regexp-match.tq
@@ -0,0 +1,49 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include 'src/builtins/builtins-regexp-gen.h'
+
+namespace regexp {
+
+ extern transitioning macro RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(
+ implicit context: Context)(Object, String, constexpr bool): JSAny;
+
+ transitioning macro FastRegExpPrototypeMatchBody(implicit context: Context)(
+ receiver: FastJSRegExp, string: String): JSAny {
+ return RegExpPrototypeMatchBody(receiver, string, true);
+ }
+
+ transitioning macro SlowRegExpPrototypeMatchBody(implicit context: Context)(
+ receiver: Object, string: String): JSAny {
+ return RegExpPrototypeMatchBody(receiver, string, false);
+ }
+
+ // Helper that skips a few initial checks. and assumes...
+ // 1) receiver is a "fast" RegExp
+ // 2) pattern is a string
+ transitioning builtin RegExpMatchFast(implicit context: Context)(
+ receiver: FastJSRegExp, string: String): JSAny {
+ return FastRegExpPrototypeMatchBody(receiver, string);
+ }
+
+ // ES#sec-regexp.prototype-@@match
+ // RegExp.prototype [ @@match ] ( string )
+ transitioning javascript builtin RegExpPrototypeMatch(
+ js-implicit context: Context, receiver: JSAny)(string: JSAny): JSAny {
+ ThrowIfNotJSReceiver(
+ receiver, kIncompatibleMethodReceiver, 'RegExp.prototype.@@match');
+ const receiver = UnsafeCast<JSReceiver>(receiver);
+ const string: String = ToString_Inline(context, string);
+
+ // Strict: Reads global and unicode properties.
+ // TODO(jgruber): Handle slow flag accesses on the fast path and make this
+ // permissive.
+ const fastRegExp = Cast<FastJSRegExp>(receiver)
+ otherwise return SlowRegExpPrototypeMatchBody(receiver, string);
+
+ // TODO(pwong): Could be optimized to remove the overhead of calling the
+ // builtin (at the cost of a larger builtin).
+ return RegExpMatchFast(fastRegExp, string);
+ }
+}
diff --git a/deps/v8/src/builtins/regexp-replace.tq b/deps/v8/src/builtins/regexp-replace.tq
index cb0038c6b6..f13724b476 100644
--- a/deps/v8/src/builtins/regexp-replace.tq
+++ b/deps/v8/src/builtins/regexp-replace.tq
@@ -4,7 +4,7 @@
#include 'src/builtins/builtins-regexp-gen.h'
-namespace regexp_replace {
+namespace regexp {
extern builtin
StringIndexOf(implicit context: Context)(String, String, Smi): Smi;
@@ -23,10 +23,6 @@ namespace regexp_replace {
extern macro
RegExpBuiltinsAssembler::AdvanceStringIndexFast(String, Smi, bool): Smi;
- extern macro
- RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResultFast(
- implicit context: Context)(JSReceiver, String):
- RegExpMatchInfo labels IfDidNotMatch;
transitioning macro RegExpReplaceCallableNoExplicitCaptures(implicit context:
Context)(
@@ -57,7 +53,7 @@ namespace regexp_replace {
// Element represents the matched substring, which is then passed to the
// replace function.
case (elString: String): {
- const replacementObj: Object =
+ const replacementObj: JSAny =
Call(context, replaceFn, Undefined, elString, matchStart, string);
const replacement: String = ToString_Inline(context, replacementObj);
matchesElements.objects[i] = replacement;
@@ -79,7 +75,7 @@ namespace regexp_replace {
// The JSArray is expanded into the function args by Reflect.apply().
// TODO(jgruber): Remove indirection through Call->ReflectApply.
- const replacementObj: Object = Call(
+ const replacementObj: JSAny = Call(
context, GetReflectApply(), Undefined, replaceFn, Undefined, elArray);
// Overwrite the i'th element in the results with the string
@@ -146,8 +142,9 @@ namespace regexp_replace {
}
while (true) {
- const match: RegExpMatchInfo = RegExpPrototypeExecBodyWithoutResultFast(
- regexp, string) otherwise break;
+ const match: RegExpMatchInfo =
+ regexp::RegExpPrototypeExecBodyWithoutResultFast(regexp, string)
+ otherwise break;
const matchStart: Smi = match.GetStartOfCapture(0);
const matchEnd: Smi = match.GetEndOfCapture(0);
@@ -172,7 +169,7 @@ namespace regexp_replace {
}
transitioning builtin RegExpReplace(implicit context: Context)(
- regexp: FastJSRegExp, string: String, replaceValue: Object): String {
+ regexp: FastJSRegExp, string: String, replaceValue: JSAny): String {
// TODO(pwong): Remove assert when all callers (StringPrototypeReplace) are
// from Torque.
assert(Is<FastJSRegExp>(regexp));
@@ -184,7 +181,7 @@ namespace regexp_replace {
RegExpReplaceFastGlobalCallable(regexp, string, replaceFn) :
StringReplaceNonGlobalRegExpWithFunction(string, regexp, replaceFn);
}
- case (Object): {
+ case (JSAny): {
const stableRegexp: JSRegExp = regexp;
const replaceString: String = ToString_Inline(context, replaceValue);
@@ -208,7 +205,7 @@ namespace regexp_replace {
}
transitioning javascript builtin RegExpPrototypeReplace(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
const methodName: constexpr string = 'RegExp.prototype.@@replace';
// RegExpPrototypeReplace is a bit of a beast - a summary of dispatch logic:
@@ -229,8 +226,8 @@ namespace regexp_replace {
// }
// }
- const string: Object = arguments[0];
- const replaceValue: Object = arguments[1];
+ const string: JSAny = arguments[0];
+ const replaceValue: JSAny = arguments[1];
// Let rx be the this value.
// If Type(rx) is not Object, throw a TypeError exception.
diff --git a/deps/v8/src/builtins/regexp-source.tq b/deps/v8/src/builtins/regexp-source.tq
new file mode 100644
index 0000000000..c1ce1c5e9a
--- /dev/null
+++ b/deps/v8/src/builtins/regexp-source.tq
@@ -0,0 +1,30 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include 'src/builtins/builtins-regexp-gen.h'
+
+namespace regexp {
+
+ const kRegExpPrototypeSourceGetter: constexpr int31
+ generates 'v8::Isolate::kRegExpPrototypeSourceGetter';
+
+ // ES6 21.2.5.10.
+ // ES #sec-get-regexp.prototype.source
+ transitioning javascript builtin RegExpPrototypeSourceGetter(
+ js-implicit context: Context, receiver: JSAny)(): JSAny {
+ typeswitch (receiver) {
+ case (receiver: JSRegExp): {
+ return receiver.source;
+ }
+ case (Object): {
+ }
+ }
+ if (!IsReceiverInitialRegExpPrototype(receiver)) {
+ const methodName: constexpr string = 'RegExp.prototype.source';
+ ThrowTypeError(kRegExpNonRegExp, methodName);
+ }
+ IncrementUseCounter(context, SmiConstant(kRegExpPrototypeSourceGetter));
+ return '(?:)';
+ }
+}
diff --git a/deps/v8/src/builtins/regexp-test.tq b/deps/v8/src/builtins/regexp-test.tq
new file mode 100644
index 0000000000..938dfa51f3
--- /dev/null
+++ b/deps/v8/src/builtins/regexp-test.tq
@@ -0,0 +1,37 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include 'src/builtins/builtins-regexp-gen.h'
+
+namespace regexp {
+
+ // ES#sec-regexp.prototype.test
+ // RegExp.prototype.test ( S )
+ transitioning javascript builtin RegExpPrototypeTest(
+ js-implicit context: Context, receiver: JSAny)(string: JSAny): JSAny {
+ const methodName: constexpr string = 'RegExp.prototype.test';
+ const receiver = Cast<JSReceiver>(receiver)
+ otherwise ThrowTypeError(kIncompatibleMethodReceiver, methodName);
+ const str: String = ToString_Inline(context, string);
+ if (IsFastRegExpPermissive(receiver)) {
+ RegExpPrototypeExecBodyWithoutResultFast(
+ UnsafeCast<JSRegExp>(receiver), str)
+ otherwise return False;
+ return True;
+ }
+ const matchIndices = RegExpExec(context, receiver, str);
+ return SelectBooleanConstant(matchIndices != Null);
+ }
+
+ extern macro RegExpBuiltinsAssembler::IsFastRegExpWithOriginalExec(
+ implicit context: Context)(JSRegExp): bool;
+
+ transitioning builtin RegExpPrototypeTestFast(implicit context: Context)(
+ receiver: JSRegExp, string: String): Object {
+ assert(IsFastRegExpWithOriginalExec(receiver));
+ RegExpPrototypeExecBodyWithoutResultFast(receiver, string)
+ otherwise return False;
+ return True;
+ }
+}
diff --git a/deps/v8/src/builtins/regexp.tq b/deps/v8/src/builtins/regexp.tq
index a36e1a14eb..7352d2738f 100644
--- a/deps/v8/src/builtins/regexp.tq
+++ b/deps/v8/src/builtins/regexp.tq
@@ -6,8 +6,159 @@
namespace regexp {
- extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp(
+ extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp_Strict(
implicit context: Context)(HeapObject): never labels IsFast,
IsSlow;
+ macro IsFastRegExpStrict(implicit context: Context)(o: HeapObject): bool {
+ BranchIfFastRegExp_Strict(o) otherwise return true, return false;
+ }
+ extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp_Permissive(
+ implicit context: Context)(HeapObject): never labels IsFast,
+ IsSlow;
+
+ @export
+ macro IsFastRegExpPermissive(implicit context: Context)(o: HeapObject): bool {
+ BranchIfFastRegExp_Permissive(o) otherwise return true, return false;
+ }
+
+ extern macro RegExpBuiltinsAssembler::RegExpExec(Context, Object, Object):
+ Object;
+
+ extern macro
+ RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResultFast(
+ implicit context: Context)(JSRegExp, String):
+ RegExpMatchInfo labels IfDidNotMatch;
+
+ extern macro RegExpBuiltinsAssembler::IsReceiverInitialRegExpPrototype(
+ implicit context: Context)(Object): bool;
+
+ type Flag constexpr 'JSRegExp::Flag';
+ const kGlobal: constexpr Flag
+ generates 'JSRegExp::kGlobal';
+ const kIgnoreCase: constexpr Flag
+ generates 'JSRegExp::kIgnoreCase';
+ const kMultiline: constexpr Flag
+ generates 'JSRegExp::kMultiline';
+ const kDotAll: constexpr Flag
+ generates 'JSRegExp::kDotAll';
+ const kSticky: constexpr Flag
+ generates 'JSRegExp::kSticky';
+ const kUnicode: constexpr Flag
+ generates 'JSRegExp::kUnicode';
+
+ const kRegExpPrototypeOldFlagGetter: constexpr int31
+ generates 'v8::Isolate::kRegExpPrototypeOldFlagGetter';
+ const kRegExpPrototypeStickyGetter: constexpr int31
+ generates 'v8::Isolate::kRegExpPrototypeStickyGetter';
+ const kRegExpPrototypeUnicodeGetter: constexpr int31
+ generates 'v8::Isolate::kRegExpPrototypeUnicodeGetter';
+
+ extern macro RegExpBuiltinsAssembler::FastFlagGetter(
+ JSRegExp, constexpr Flag): bool;
+ const kRegExpNonRegExp: constexpr MessageTemplate
+ generates 'MessageTemplate::kRegExpNonRegExp';
+ extern runtime IncrementUseCounter(Context, Smi): void;
+
+ macro FlagGetter(implicit context: Context)(
+ receiver: Object, flag: constexpr Flag, counter: constexpr int31,
+ methodName: constexpr string): JSAny {
+ typeswitch (receiver) {
+ case (receiver: JSRegExp): {
+ return SelectBooleanConstant(FastFlagGetter(receiver, flag));
+ }
+ case (Object): {
+ }
+ }
+ if (!IsReceiverInitialRegExpPrototype(receiver)) {
+ ThrowTypeError(kRegExpNonRegExp, methodName);
+ }
+ if constexpr (counter != -1) {
+ IncrementUseCounter(context, SmiConstant(counter));
+ }
+ return Undefined;
+ }
+
+ // ES6 21.2.5.4.
+ // ES #sec-get-regexp.prototype.global
+ transitioning javascript builtin RegExpPrototypeGlobalGetter(
+ js-implicit context: Context, receiver: JSAny)(): JSAny {
+ return FlagGetter(
+ receiver, kGlobal, kRegExpPrototypeOldFlagGetter,
+ 'RegExp.prototype.global');
+ }
+
+ // ES6 21.2.5.5.
+ // ES #sec-get-regexp.prototype.ignorecase
+ transitioning javascript builtin RegExpPrototypeIgnoreCaseGetter(
+ js-implicit context: Context, receiver: JSAny)(): JSAny {
+ return FlagGetter(
+ receiver, kIgnoreCase, kRegExpPrototypeOldFlagGetter,
+ 'RegExp.prototype.ignoreCase');
+ }
+
+ // ES6 21.2.5.7.
+ // ES #sec-get-regexp.prototype.multiline
+ transitioning javascript builtin RegExpPrototypeMultilineGetter(
+ js-implicit context: Context, receiver: JSAny)(): JSAny {
+ return FlagGetter(
+ receiver, kMultiline, kRegExpPrototypeOldFlagGetter,
+ 'RegExp.prototype.multiline');
+ }
+
+ // ES #sec-get-regexp.prototype.dotAll
+ transitioning javascript builtin RegExpPrototypeDotAllGetter(
+ js-implicit context: Context, receiver: JSAny)(): JSAny {
+ const kNoCounter: constexpr int31 = -1;
+ return FlagGetter(receiver, kDotAll, kNoCounter, 'RegExp.prototype.dotAll');
+ }
+
+ // ES6 21.2.5.12.
+ // ES #sec-get-regexp.prototype.sticky
+ transitioning javascript builtin RegExpPrototypeStickyGetter(
+ js-implicit context: Context, receiver: JSAny)(): JSAny {
+ return FlagGetter(
+ receiver, kSticky, kRegExpPrototypeStickyGetter,
+ 'RegExp.prototype.sticky');
+ }
+
+ // ES6 21.2.5.15.
+ // ES #sec-get-regexp.prototype.unicode
+ transitioning javascript builtin RegExpPrototypeUnicodeGetter(
+ js-implicit context: Context, receiver: JSAny)(): JSAny {
+ return FlagGetter(
+ receiver, kUnicode, kRegExpPrototypeUnicodeGetter,
+ 'RegExp.prototype.unicode');
+ }
+
+ extern transitioning macro
+ RegExpBuiltinsAssembler::FlagsGetter(implicit context: Context)(
+ Object, constexpr bool): String;
+
+ transitioning macro
+ FastFlagsGetter(implicit context: Context)(receiver: FastJSRegExp): String {
+ return FlagsGetter(receiver, true);
+ }
+
+ transitioning macro SlowFlagsGetter(implicit context:
+ Context)(receiver: JSAny): String {
+ return FlagsGetter(receiver, false);
+ }
+
+ const kRegExpNonObject: constexpr MessageTemplate
+ generates 'MessageTemplate::kRegExpNonObject';
+
+ // ES #sec-get-regexp.prototype.flags
+ // TFJ(RegExpPrototypeFlagsGetter, 0, kReceiver) \
+ transitioning javascript builtin RegExpPrototypeFlagsGetter(
+ js-implicit context: Context, receiver: JSAny)(): String {
+ ThrowIfNotJSReceiver(receiver, kRegExpNonObject, 'RegExp.prototype.flags');
+
+ // The check is strict because the following code relies on individual flag
+ // getters on the regexp prototype (e.g.: global, sticky, ...). We don't
+ // bother to check these individually.
+ const fastRegexp = Cast<FastJSRegExp>(receiver)
+ otherwise return SlowFlagsGetter(receiver);
+ return FastFlagsGetter(fastRegexp);
+ }
}
diff --git a/deps/v8/src/builtins/s390/builtins-s390.cc b/deps/v8/src/builtins/s390/builtins-s390.cc
index 854f31cece..7dca12d17e 100644
--- a/deps/v8/src/builtins/s390/builtins-s390.cc
+++ b/deps/v8/src/builtins/s390/builtins-s390.cc
@@ -81,12 +81,24 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
namespace {
+MemOperand RealStackLimitAsMemOperand(MacroAssembler* masm) {
+ DCHECK(masm->root_array_available());
+ Isolate* isolate = masm->isolate();
+ ExternalReference limit = ExternalReference::address_of_real_jslimit(isolate);
+ DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
+
+ intptr_t offset =
+ TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
+ CHECK(is_int32(offset));
+ return MemOperand(kRootRegister, offset);
+}
+
void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
Register scratch, Label* stack_overflow) {
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
- __ LoadRoot(scratch, RootIndex::kRealStackLimit);
+ __ LoadP(scratch, RealStackLimitAsMemOperand(masm));
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
__ SubP(scratch, sp, scratch);
@@ -429,7 +441,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
- __ CompareRoot(sp, RootIndex::kRealStackLimit);
+ __ LoadP(scratch, RealStackLimitAsMemOperand(masm));
+ __ CmpLogicalP(sp, scratch);
__ blt(&stack_overflow);
// Push receiver.
@@ -772,7 +785,7 @@ static void Generate_CheckStackOverflow(MacroAssembler* masm, Register argc,
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
- __ LoadRoot(scratch1, RootIndex::kRealStackLimit);
+ __ LoadP(scratch1, RealStackLimitAsMemOperand(masm));
// Make scratch1 the space we have left. The stack might already be overflowed
// here which will cause scratch1 to become negative.
__ SubP(scratch1, sp, scratch1);
@@ -1197,8 +1210,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Do a stack check to ensure we don't go over the limit.
Label ok;
__ SubP(r8, sp, r4);
- __ LoadRoot(r0, RootIndex::kRealStackLimit);
- __ CmpLogicalP(r8, r0);
+ __ CmpLogicalP(r8, RealStackLimitAsMemOperand(masm));
__ bge(&ok);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bind(&ok);
@@ -2219,7 +2231,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack
// limit".
- __ CompareRoot(sp, RootIndex::kRealStackLimit);
+ __ CmpLogicalP(sp, RealStackLimitAsMemOperand(masm));
__ bgt(&done); // Signed comparison.
// Restore the stack pointer.
__ LoadRR(sp, scratch);
@@ -2657,7 +2669,10 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Push(kWasmInstanceRegister, r7);
// Load the correct CEntry builtin from the instance object.
__ LoadP(r4, FieldMemOperand(kWasmInstanceRegister,
- WasmInstanceObject::kCEntryStubOffset));
+ WasmInstanceObject::kIsolateRootOffset));
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ __ LoadP(r4, MemOperand(r4, IsolateData::builtin_slot_offset(centry_id)));
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ LoadSmiLiteral(cp, Smi::zero());
diff --git a/deps/v8/src/builtins/setup-builtins-internal.cc b/deps/v8/src/builtins/setup-builtins-internal.cc
index 3c637db636..99ac0d6b1f 100644
--- a/deps/v8/src/builtins/setup-builtins-internal.cc
+++ b/deps/v8/src/builtins/setup-builtins-internal.cc
@@ -119,9 +119,9 @@ Code BuildWithMacroAssembler(Isolate* isolate, int32_t builtin_index,
.set_self_reference(masm.CodeObject())
.set_builtin_index(builtin_index)
.Build();
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
isolate->SetBuiltinUnwindData(builtin_index, masm.GetUnwindInfo());
-#endif
+#endif // V8_OS_WIN64
return *code;
}
@@ -276,10 +276,6 @@ Code GenerateBytecodeHandler(Isolate* isolate, int builtin_index,
} // namespace
-#ifdef _MSC_VER
-#pragma optimize( "", off )
-#endif
-
// static
void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
Builtins* builtins = isolate->builtins();
@@ -357,10 +353,5 @@ void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
builtins->MarkInitialized();
}
-#ifdef _MSC_VER
-#pragma optimize( "", on )
-#endif
-
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/builtins/string-endswith.tq b/deps/v8/src/builtins/string-endswith.tq
index 8b9fe84dfb..c3cc7d949b 100644
--- a/deps/v8/src/builtins/string-endswith.tq
+++ b/deps/v8/src/builtins/string-endswith.tq
@@ -28,13 +28,13 @@ namespace string {
// https://tc39.github.io/ecma262/#sec-string.prototype.endswith
transitioning javascript builtin StringPrototypeEndsWith(
- js-implicit context: Context, receiver: Object)(...arguments): Boolean {
- const searchString: Object = arguments[0];
- const endPosition: Object = arguments[1];
+ js-implicit context: Context, receiver: JSAny)(...arguments): Boolean {
+ const searchString: JSAny = arguments[0];
+ const endPosition: JSAny = arguments[1];
const kBuiltinName: constexpr string = 'String.prototype.endsWith';
// 1. Let O be ? RequireObjectCoercible(this value).
- const object: Object = RequireObjectCoercible(receiver, kBuiltinName);
+ const object: JSAny = RequireObjectCoercible(receiver, kBuiltinName);
// 2. Let S be ? ToString(O).
const string: String = ToString_Inline(context, object);
diff --git a/deps/v8/src/builtins/string-html.tq b/deps/v8/src/builtins/string-html.tq
index 80b5f77887..0b0fdfeaef 100644
--- a/deps/v8/src/builtins/string-html.tq
+++ b/deps/v8/src/builtins/string-html.tq
@@ -7,8 +7,8 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-createhtml
transitioning builtin CreateHTML(implicit context: Context)(
- receiver: Object, methodName: String, tagName: String, attr: String,
- attrValue: Object): String {
+ receiver: JSAny, methodName: String, tagName: String, attr: String,
+ attrValue: JSAny): String {
const tagContents: String = ToThisString(receiver, methodName);
let result = '<' + tagName;
if (attr != kEmptyString) {
@@ -22,14 +22,14 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.anchor
transitioning javascript builtin StringPrototypeAnchor(
- js-implicit context: Context, receiver: Object)(...arguments): String {
+ js-implicit context: Context, receiver: JSAny)(...arguments): String {
return CreateHTML(
receiver, 'String.prototype.anchor', 'a', 'name', arguments[0]);
}
// https://tc39.github.io/ecma262/#sec-string.prototype.big
transitioning javascript builtin
- StringPrototypeBig(js-implicit context: Context, receiver: Object)(
+ StringPrototypeBig(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.big', 'big', kEmptyString, kEmptyString);
@@ -37,7 +37,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.blink
transitioning javascript builtin
- StringPrototypeBlink(js-implicit context: Context, receiver: Object)(
+ StringPrototypeBlink(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.blink', 'blink', kEmptyString,
@@ -46,7 +46,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.bold
transitioning javascript builtin
- StringPrototypeBold(js-implicit context: Context, receiver: Object)(
+ StringPrototypeBold(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.bold', 'b', kEmptyString, kEmptyString);
@@ -54,7 +54,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.fontcolor
transitioning javascript builtin
- StringPrototypeFontcolor(js-implicit context: Context, receiver: Object)(
+ StringPrototypeFontcolor(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.fontcolor', 'font', 'color', arguments[0]);
@@ -62,7 +62,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.fontsize
transitioning javascript builtin
- StringPrototypeFontsize(js-implicit context: Context, receiver: Object)(
+ StringPrototypeFontsize(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.fontsize', 'font', 'size', arguments[0]);
@@ -70,7 +70,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.fixed
transitioning javascript builtin
- StringPrototypeFixed(js-implicit context: Context, receiver: Object)(
+ StringPrototypeFixed(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.fixed', 'tt', kEmptyString, kEmptyString);
@@ -78,7 +78,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.italics
transitioning javascript builtin
- StringPrototypeItalics(js-implicit context: Context, receiver: Object)(
+ StringPrototypeItalics(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.italics', 'i', kEmptyString, kEmptyString);
@@ -86,7 +86,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.link
transitioning javascript builtin
- StringPrototypeLink(js-implicit context: Context, receiver: Object)(
+ StringPrototypeLink(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.link', 'a', 'href', arguments[0]);
@@ -94,7 +94,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.small
transitioning javascript builtin
- StringPrototypeSmall(js-implicit context: Context, receiver: Object)(
+ StringPrototypeSmall(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.small', 'small', kEmptyString,
@@ -103,7 +103,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.strike
transitioning javascript builtin
- StringPrototypeStrike(js-implicit context: Context, receiver: Object)(
+ StringPrototypeStrike(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.strike', 'strike', kEmptyString,
@@ -112,7 +112,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.sub
transitioning javascript builtin
- StringPrototypeSub(js-implicit context: Context, receiver: Object)(
+ StringPrototypeSub(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.sub', 'sub', kEmptyString, kEmptyString);
@@ -120,7 +120,7 @@ namespace string_html {
// https://tc39.github.io/ecma262/#sec-string.prototype.sup
transitioning javascript builtin
- StringPrototypeSup(js-implicit context: Context, receiver: Object)(
+ StringPrototypeSup(js-implicit context: Context, receiver: JSAny)(
...arguments): String {
return CreateHTML(
receiver, 'String.prototype.sup', 'sup', kEmptyString, kEmptyString);
diff --git a/deps/v8/src/builtins/string-iterator.tq b/deps/v8/src/builtins/string-iterator.tq
index 5b8f864661..d36a44fa97 100644
--- a/deps/v8/src/builtins/string-iterator.tq
+++ b/deps/v8/src/builtins/string-iterator.tq
@@ -17,7 +17,7 @@ namespace string_iterator {
// ES6 #sec-string.prototype-@@iterator
transitioning javascript builtin StringPrototypeIterator(
- js-implicit context: Context)(receiver: Object): JSStringIterator {
+ js-implicit context: Context, receiver: JSAny)(): JSStringIterator {
const name: String =
ToThisString(receiver, 'String.prototype[Symbol.iterator]');
const index: Smi = 0;
@@ -26,7 +26,7 @@ namespace string_iterator {
// ES6 #sec-%stringiteratorprototype%.next
transitioning javascript builtin StringIteratorPrototypeNext(
- js-implicit context: Context)(receiver: Object): JSObject {
+ js-implicit context: Context, receiver: JSAny)(): JSObject {
const iterator = Cast<JSStringIterator>(receiver) otherwise ThrowTypeError(
kIncompatibleMethodReceiver, 'String Iterator.prototype.next',
receiver);
diff --git a/deps/v8/src/builtins/string-pad.tq b/deps/v8/src/builtins/string-pad.tq
new file mode 100644
index 0000000000..2368067c4e
--- /dev/null
+++ b/deps/v8/src/builtins/string-pad.tq
@@ -0,0 +1,111 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include 'src/builtins/builtins-string-gen.h'
+
+namespace string {
+
+ extern transitioning builtin
+ StringSubstring(implicit context: Context)(String, intptr, intptr): String;
+
+ const kStringPadStart: constexpr int31 = 0;
+ const kStringPadEnd: constexpr int31 = 1;
+
+ transitioning macro StringPad(implicit context: Context)(
+ receiver: JSAny, arguments: Arguments, methodName: constexpr string,
+ variant: constexpr int31): String {
+ const receiverString: String = ToThisString(receiver, methodName);
+ const stringLength: Smi = receiverString.length_smi;
+
+ if (arguments.length == 0) {
+ return receiverString;
+ }
+ const maxLength: Number = ToLength_Inline(context, arguments[0]);
+ assert(IsNumberNormalized(maxLength));
+
+ typeswitch (maxLength) {
+ case (smiMaxLength: Smi): {
+ if (smiMaxLength <= stringLength) {
+ return receiverString;
+ }
+ }
+ case (Number): {
+ }
+ }
+
+ let fillString: String = ' ';
+ let fillLength: intptr = 1;
+
+ if (arguments.length != 1) {
+ const fill = arguments[1];
+ if (fill != Undefined) {
+ fillString = ToString_Inline(context, fill);
+ fillLength = fillString.length_intptr;
+ if (fillLength == 0) {
+ return receiverString;
+ }
+ }
+ }
+
+ // Pad.
+ assert(fillLength > 0);
+ // Throw if max_length is greater than String::kMaxLength.
+ if (!TaggedIsSmi(maxLength)) {
+ ThrowInvalidStringLength(context);
+ }
+
+ const smiMaxLength: Smi = UnsafeCast<Smi>(maxLength);
+ if (smiMaxLength > SmiConstant(kStringMaxLength)) {
+ ThrowInvalidStringLength(context);
+ }
+ assert(smiMaxLength > stringLength);
+ const padLength: Smi = smiMaxLength - stringLength;
+
+ let padding: String;
+ if (fillLength == 1) {
+ // Single char fill.
+ // Fast path for a single character fill. No need to calculate number of
+ // repetitions or remainder.
+ padding = StringRepeat(context, fillString, padLength);
+ } else {
+ // Multi char fill.
+ const fillLengthWord32: int32 = TruncateIntPtrToInt32(fillLength);
+ const padLengthWord32: int32 = Convert<int32>(padLength);
+ const repetitionsWord32: int32 = padLengthWord32 / fillLengthWord32;
+ const remainingWord32: int32 = padLengthWord32 % fillLengthWord32;
+ padding =
+ StringRepeat(context, fillString, Convert<Smi>(repetitionsWord32));
+
+ if (remainingWord32 != 0) {
+ const remainderString =
+ StringSubstring(fillString, 0, Convert<intptr>(remainingWord32));
+ padding = padding + remainderString;
+ }
+ }
+
+ // Return result.
+ assert(padLength == padding.length_smi);
+ if (variant == kStringPadStart) {
+ return padding + receiverString;
+ }
+ assert(variant == kStringPadEnd);
+ return receiverString + padding;
+ }
+
+ // ES6 #sec-string.prototype.padstart
+ transitioning javascript builtin
+ StringPrototypePadStart(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): String {
+ const methodName: constexpr string = 'String.prototype.padStart';
+ return StringPad(receiver, arguments, methodName, kStringPadStart);
+ }
+
+ // ES6 #sec-string.prototype.padend
+ transitioning javascript builtin
+ StringPrototypePadEnd(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): String {
+ const methodName: constexpr string = 'String.prototype.padEnd';
+ return StringPad(receiver, arguments, methodName, kStringPadEnd);
+ }
+}
diff --git a/deps/v8/src/builtins/string-repeat.tq b/deps/v8/src/builtins/string-repeat.tq
index 0d9d4ee498..f341ed4336 100644
--- a/deps/v8/src/builtins/string-repeat.tq
+++ b/deps/v8/src/builtins/string-repeat.tq
@@ -28,7 +28,7 @@ namespace string_repeat {
// https://tc39.github.io/ecma262/#sec-string.prototype.repeat
transitioning javascript builtin StringPrototypeRepeat(
- js-implicit context: Context, receiver: Object)(count: Object): String {
+ js-implicit context: Context, receiver: JSAny)(count: JSAny): String {
// 1. Let O be ? RequireObjectCoercible(this value).
// 2. Let S be ? ToString(O).
const s: String = ToThisString(receiver, kBuiltinName);
diff --git a/deps/v8/src/builtins/string-slice.tq b/deps/v8/src/builtins/string-slice.tq
index b066fb7669..661cc264c5 100644
--- a/deps/v8/src/builtins/string-slice.tq
+++ b/deps/v8/src/builtins/string-slice.tq
@@ -9,7 +9,7 @@ namespace string_slice {
// ES6 #sec-string.prototype.slice ( start, end )
// https://tc39.github.io/ecma262/#sec-string.prototype.slice
transitioning javascript builtin StringPrototypeSlice(
- js-implicit context: Context, receiver: Object)(...arguments): String {
+ js-implicit context: Context, receiver: JSAny)(...arguments): String {
// 1. Let O be ? RequireObjectCoercible(this value).
// 2. Let S be ? ToString(O).
const string: String = ToThisString(receiver, 'String.prototype.slice');
diff --git a/deps/v8/src/builtins/string-startswith.tq b/deps/v8/src/builtins/string-startswith.tq
index b03e67ecf5..7fa7ec6d5c 100644
--- a/deps/v8/src/builtins/string-startswith.tq
+++ b/deps/v8/src/builtins/string-startswith.tq
@@ -10,13 +10,13 @@ namespace string {
// https://tc39.github.io/ecma262/#sec-string.prototype.startswith
transitioning javascript builtin StringPrototypeStartsWith(
- js-implicit context: Context, receiver: Object)(...arguments): Boolean {
- const searchString: Object = arguments[0];
- const position: Object = arguments[1];
+ js-implicit context: Context, receiver: JSAny)(...arguments): Boolean {
+ const searchString: JSAny = arguments[0];
+ const position: JSAny = arguments[1];
const kBuiltinName: constexpr string = 'String.prototype.startsWith';
// 1. Let O be ? RequireObjectCoercible(this value).
- const object: Object = RequireObjectCoercible(receiver, kBuiltinName);
+ const object: JSAny = RequireObjectCoercible(receiver, kBuiltinName);
// 2. Let S be ? ToString(O).
const string: String = ToString_Inline(context, object);
diff --git a/deps/v8/src/builtins/string-substring.tq b/deps/v8/src/builtins/string-substring.tq
index 1fafb8af43..c97b294a34 100644
--- a/deps/v8/src/builtins/string-substring.tq
+++ b/deps/v8/src/builtins/string-substring.tq
@@ -7,7 +7,7 @@ namespace string_substring {
extern macro SubString(String, intptr, intptr): String;
transitioning macro ToSmiBetweenZeroAnd(implicit context: Context)(
- value: Object, limit: Smi): Smi {
+ value: JSAny, limit: Smi): Smi {
const valueInt: Number =
ToInteger_Inline(context, value, kTruncateMinusZero);
typeswitch (valueInt) {
@@ -28,7 +28,7 @@ namespace string_substring {
// ES6 #sec-string.prototype.substring
transitioning javascript builtin StringPrototypeSubstring(
- js-implicit context: Context, receiver: Object)(...arguments): String {
+ js-implicit context: Context, receiver: JSAny)(...arguments): String {
// Check that {receiver} is coercible to Object and convert it to a String.
const string: String = ToThisString(receiver, 'String.prototype.substring');
const length = string.length_smi;
diff --git a/deps/v8/src/builtins/string.tq b/deps/v8/src/builtins/string.tq
index dbcc5799e1..7f007680e9 100644
--- a/deps/v8/src/builtins/string.tq
+++ b/deps/v8/src/builtins/string.tq
@@ -7,15 +7,15 @@
namespace string {
// ES6 #sec-string.prototype.tostring
transitioning javascript builtin
- StringPrototypeToString(js-implicit context: Context)(receiver: Object):
- Object {
+ StringPrototypeToString(js-implicit context: Context, receiver: JSAny)():
+ JSAny {
return ToThisValue(receiver, kString, 'String.prototype.toString');
}
// ES6 #sec-string.prototype.valueof
transitioning javascript builtin
- StringPrototypeValueOf(js-implicit context: Context)(receiver: Object):
- Object {
+ StringPrototypeValueOf(js-implicit context: Context, receiver: JSAny)():
+ JSAny {
return ToThisValue(receiver, kString, 'String.prototype.valueOf');
}
@@ -29,7 +29,8 @@ namespace string {
const kind = PACKED_ELEMENTS;
const stringLength: intptr = string.length_intptr;
- const map: Map = LoadJSArrayElementsMap(kind, LoadNativeContext(context));
+ const nativeContext = LoadNativeContext(context);
+ const map: Map = LoadJSArrayElementsMap(kind, nativeContext);
const array: JSArray = AllocateJSArray(
kind, map, stringLength, SmiTag(stringLength),
kAllowLargeObjectAllocation);
@@ -53,7 +54,7 @@ namespace string {
}
transitioning macro GenerateStringAt(implicit context: Context)(
- receiver: Object, position: Object,
+ receiver: JSAny, position: JSAny,
methodName: constexpr string): never labels
IfInBounds(String, intptr, intptr), IfOutOfBounds {
// Check that {receiver} is coercible to Object and convert it to a String.
@@ -71,8 +72,7 @@ namespace string {
// ES6 #sec-string.prototype.charat
transitioning javascript builtin StringPrototypeCharAt(
- js-implicit context: Context,
- receiver: Object)(position: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(position: JSAny): JSAny {
try {
GenerateStringAt(receiver, position, 'String.prototype.charAt')
otherwise IfInBounds, IfOutOfBounds;
@@ -88,8 +88,7 @@ namespace string {
// ES6 #sec-string.prototype.charcodeat
transitioning javascript builtin StringPrototypeCharCodeAt(
- js-implicit context: Context,
- receiver: Object)(position: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(position: JSAny): JSAny {
try {
GenerateStringAt(receiver, position, 'String.prototype.charCodeAt')
otherwise IfInBounds, IfOutOfBounds;
@@ -105,8 +104,7 @@ namespace string {
// ES6 #sec-string.prototype.codepointat
transitioning javascript builtin StringPrototypeCodePointAt(
- js-implicit context: Context,
- receiver: Object)(position: Object): Object {
+ js-implicit context: Context, receiver: JSAny)(position: JSAny): JSAny {
try {
GenerateStringAt(receiver, position, 'String.prototype.codePointAt')
otherwise IfInBounds, IfOutOfBounds;
@@ -125,7 +123,7 @@ namespace string {
// ES6 String.prototype.concat(...args)
// ES6 #sec-string.prototype.concat
transitioning javascript builtin StringPrototypeConcat(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
// Check that {receiver} is coercible to Object and convert it to a String.
let string: String = ToThisString(receiver, 'String.prototype.concat');
@@ -137,4 +135,56 @@ namespace string {
}
return string;
}
+
+ extern transitioning runtime
+ SymbolDescriptiveString(implicit context: Context)(Symbol): String;
+
+ // ES #sec-string-constructor
+ // https://tc39.github.io/ecma262/#sec-string-constructor
+ transitioning javascript builtin StringConstructor(
+ js-implicit context: Context, receiver: JSAny, newTarget: JSAny,
+ target: JSFunction)(...arguments): JSAny {
+ const length: intptr = Convert<intptr>(arguments.length);
+ let s: String;
+ // 1. If no arguments were passed to this function invocation, let s be "".
+ if (length == 0) {
+ s = EmptyStringConstant();
+ } else {
+ // 2. Else,
+ // 2. a. If NewTarget is undefined and Type(value) is Symbol, return
+ // SymbolDescriptiveString(value).
+ if (newTarget == Undefined) {
+ typeswitch (arguments[0]) {
+ case (value: Symbol): {
+ return SymbolDescriptiveString(value);
+ }
+ case (JSAny): {
+ }
+ }
+ }
+ // 2. b. Let s be ? ToString(value).
+ s = ToString_Inline(context, arguments[0]);
+ }
+ // 3. If NewTarget is undefined, return s.
+ if (newTarget == Undefined) {
+ return s;
+ }
+ // 4. Return ! StringCreate(s, ? GetPrototypeFromConstructor(NewTarget,
+ // "%String.prototype%")).
+ const map = GetDerivedMap(target, UnsafeCast<JSReceiver>(newTarget));
+ const obj =
+ UnsafeCast<JSPrimitiveWrapper>(AllocateFastOrSlowJSObjectFromMap(map));
+ obj.value = s;
+ return obj;
+ }
+
+ transitioning builtin StringAddConvertLeft(implicit context: Context)(
+ left: JSAny, right: String): String {
+ return ToStringImpl(context, ToPrimitiveDefault(left)) + right;
+ }
+
+ transitioning builtin StringAddConvertRight(implicit context: Context)(
+ left: String, right: JSAny): String {
+ return left + ToStringImpl(context, ToPrimitiveDefault(right));
+ }
}
diff --git a/deps/v8/src/builtins/torque-internal.tq b/deps/v8/src/builtins/torque-internal.tq
new file mode 100644
index 0000000000..48a08deb0a
--- /dev/null
+++ b/deps/v8/src/builtins/torque-internal.tq
@@ -0,0 +1,106 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+namespace torque_internal {
+ // TODO(gsps): Synthesize SizeOf<T> in the compiler
+
+ macro SizeOf<T: type>(): constexpr int31;
+ SizeOf<Object>(): constexpr int31 {
+ return kTaggedSize;
+ }
+ SizeOf<float64>(): constexpr int31 {
+ return kDoubleSize;
+ }
+
+ // Unsafe is a marker that we require to be passed when calling internal APIs
+ // that might lead to unsoundness when used incorrectly. Unsafe markers should
+ // therefore not be instantiated anywhere outside of this namespace.
+ struct Unsafe {}
+
+ struct Reference<T: type> {
+ const object: HeapObject;
+ const offset: intptr;
+ unsafeMarker: Unsafe;
+ }
+
+ macro UnsafeNewReference<T: type>(object: HeapObject, offset: intptr):&T {
+ return Reference<T>{
+ object: object,
+ offset: offset,
+ unsafeMarker: Unsafe {}
+ };
+ }
+
+ struct Slice<T: type> {
+ TryAtIndex(index: intptr):&T labels OutOfBounds {
+ if (Convert<uintptr>(index) < Convert<uintptr>(this.length)) {
+ return UnsafeNewReference<T>(
+ this.object, this.offset + index * SizeOf<T>());
+ } else {
+ goto OutOfBounds;
+ }
+ }
+
+ AtIndex(index: intptr):&T {
+ return this.TryAtIndex(index) otherwise unreachable;
+ }
+
+ AtIndex(index: constexpr int31):&T {
+ const i: intptr = Convert<intptr>(index);
+ return this.TryAtIndex(i) otherwise unreachable;
+ }
+
+ AtIndex(index: Smi):&T {
+ const i: intptr = Convert<intptr>(index);
+ return this.TryAtIndex(i) otherwise unreachable;
+ }
+
+ Iterator(): SliceIterator<T> {
+ const end = this.offset + this.length * SizeOf<T>();
+ return SliceIterator<T>{
+ object: this.object,
+ start: this.offset,
+ end: end,
+ unsafeMarker: Unsafe {}
+ };
+ }
+
+ const object: HeapObject;
+ const offset: intptr;
+ const length: intptr;
+ unsafeMarker: Unsafe;
+ }
+
+ macro UnsafeNewSlice<T: type>(
+ object: HeapObject, offset: intptr, length: intptr): Slice<T> {
+ return Slice<T>{
+ object: object,
+ offset: offset,
+ length: length,
+ unsafeMarker: Unsafe {}
+ };
+ }
+
+ struct SliceIterator<T: type> {
+ Empty(): bool {
+ return this.start == this.end;
+ }
+
+ Next():&T labels NoMore {
+ if (this.Empty()) {
+ goto NoMore;
+ } else {
+ const result = UnsafeNewReference<T>(this.object, this.start);
+ this.start += SizeOf<T>();
+ return result;
+ }
+ }
+
+ object: HeapObject;
+ start: intptr;
+ end: intptr;
+ unsafeMarker: Unsafe;
+ }
+
+} // namespace torque_internal
diff --git a/deps/v8/src/builtins/typed-array-createtypedarray.tq b/deps/v8/src/builtins/typed-array-createtypedarray.tq
index f6ab289e12..a476739861 100644
--- a/deps/v8/src/builtins/typed-array-createtypedarray.tq
+++ b/deps/v8/src/builtins/typed-array-createtypedarray.tq
@@ -122,7 +122,7 @@ namespace typed_array_createtypedarray {
// 22.2.4.2 TypedArray ( length )
// ES #sec-typedarray-length
transitioning macro ConstructByLength(implicit context: Context)(
- map: Map, length: Object,
+ map: Map, length: JSAny,
elementsInfo: typed_array::TypedArrayElementsInfo): JSTypedArray {
const convertedLength: Number =
ToInteger_Inline(context, length, kTruncateMinusZero);
@@ -141,7 +141,7 @@ namespace typed_array_createtypedarray {
// 22.2.4.4 TypedArray ( object )
// ES #sec-typedarray-object
transitioning macro ConstructByArrayLike(implicit context: Context)(
- map: Map, arrayLike: HeapObject, initialLength: Object,
+ map: Map, arrayLike: HeapObject, initialLength: JSAny,
elementsInfo: typed_array::TypedArrayElementsInfo,
bufferConstructor: JSReceiver): JSTypedArray {
// The caller has looked up length on arrayLike, which is observable.
@@ -178,7 +178,7 @@ namespace typed_array_createtypedarray {
// ES #sec-typedarray-object
transitioning macro ConstructByIterable(implicit context: Context)(
iterable: JSReceiver, iteratorFn: Callable): never
- labels IfConstructByArrayLike(HeapObject, Object, JSReceiver) {
+ labels IfConstructByArrayLike(JSArray, Number, JSReceiver) {
const array: JSArray =
IterableToListMayPreserveHoles(context, iterable, iteratorFn);
goto IfConstructByArrayLike(array, array.length, GetArrayBufferFunction());
@@ -188,7 +188,7 @@ namespace typed_array_createtypedarray {
// ES #sec-typedarray-typedarray
transitioning macro ConstructByTypedArray(implicit context: Context)(
srcTypedArray: JSTypedArray): never
- labels IfConstructByArrayLike(HeapObject, Object, JSReceiver) {
+ labels IfConstructByArrayLike(JSTypedArray, Number, JSReceiver) {
let bufferConstructor: JSReceiver = GetArrayBufferFunction();
const srcBuffer: JSArrayBuffer = srcTypedArray.buffer;
// TODO(petermarshall): Throw on detached typedArray.
@@ -210,7 +210,7 @@ namespace typed_array_createtypedarray {
// 22.2.4.5 TypedArray ( buffer, byteOffset, length )
// ES #sec-typedarray-buffer-byteoffset-length
transitioning macro ConstructByArrayBuffer(implicit context: Context)(
- map: Map, buffer: JSArrayBuffer, byteOffset: Object, length: Object,
+ map: Map, buffer: JSArrayBuffer, byteOffset: JSAny, length: JSAny,
elementsInfo: typed_array::TypedArrayElementsInfo): JSTypedArray {
try {
let offset: uintptr = 0;
@@ -294,7 +294,7 @@ namespace typed_array_createtypedarray {
transitioning macro ConstructByJSReceiver(implicit context:
Context)(obj: JSReceiver): never
- labels IfConstructByArrayLike(HeapObject, Object, JSReceiver) {
+ labels IfConstructByArrayLike(JSReceiver, Number, JSReceiver) {
try {
const iteratorMethod: Object =
GetIteratorMethod(obj) otherwise IfIteratorUndefined;
@@ -304,7 +304,7 @@ namespace typed_array_createtypedarray {
otherwise IfConstructByArrayLike;
}
label IfIteratorUndefined {
- const lengthObj: Object = GetProperty(obj, kLengthString);
+ const lengthObj: JSAny = GetProperty(obj, kLengthString);
const length: Smi = ToSmiLength(lengthObj)
otherwise goto IfInvalidLength(lengthObj);
goto IfConstructByArrayLike(obj, length, GetArrayBufferFunction());
@@ -317,8 +317,8 @@ namespace typed_array_createtypedarray {
// 22.2.4 The TypedArray Constructors
// ES #sec-typedarray-constructors
transitioning builtin CreateTypedArray(
- context: Context, target: JSFunction, newTarget: JSReceiver, arg1: Object,
- arg2: Object, arg3: Object): JSTypedArray {
+ context: Context, target: JSFunction, newTarget: JSReceiver, arg1: JSAny,
+ arg2: JSAny, arg3: JSAny): JSTypedArray {
assert(IsConstructor(target));
// 4. Let O be ? AllocateTypedArray(constructorName, NewTarget,
// "%TypedArrayPrototype%").
@@ -345,16 +345,16 @@ namespace typed_array_createtypedarray {
}
// The first argument was a number or fell through and is treated as
// a number. https://tc39.github.io/ecma262/#sec-typedarray-length
- case (lengthObj: HeapObject): {
+ case (lengthObj: JSAny): {
goto IfConstructByLength(lengthObj);
}
}
}
- label IfConstructByLength(length: Object) {
+ label IfConstructByLength(length: JSAny) {
return ConstructByLength(map, length, elementsInfo);
}
label IfConstructByArrayLike(
- arrayLike: HeapObject, length: Object, bufferConstructor: JSReceiver) {
+ arrayLike: JSReceiver, length: Number, bufferConstructor: JSReceiver) {
return ConstructByArrayLike(
map, arrayLike, length, elementsInfo, bufferConstructor);
}
@@ -362,8 +362,8 @@ namespace typed_array_createtypedarray {
transitioning macro TypedArraySpeciesCreate(implicit context: Context)(
methodName: constexpr string, numArgs: constexpr int31,
- exemplar: JSTypedArray, arg0: Object, arg1: Object,
- arg2: Object): JSTypedArray {
+ exemplar: JSTypedArray, arg0: JSAny, arg1: JSAny,
+ arg2: JSAny): JSTypedArray {
const defaultConstructor = GetDefaultConstructor(exemplar);
try {
@@ -386,7 +386,7 @@ namespace typed_array_createtypedarray {
// TODO(pwong): Simplify and remove numArgs when varargs are supported in
// macros.
- let newObj: Object = Undefined;
+ let newObj: JSAny = Undefined;
if constexpr (numArgs == 1) {
newObj = Construct(constructor, arg0);
} else {
diff --git a/deps/v8/src/builtins/typed-array-every.tq b/deps/v8/src/builtins/typed-array-every.tq
index 221814cb79..4b4fe72eb1 100644
--- a/deps/v8/src/builtins/typed-array-every.tq
+++ b/deps/v8/src/builtins/typed-array-every.tq
@@ -9,7 +9,7 @@ namespace typed_array_every {
transitioning macro EveryAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
- thisArg: Object): Boolean {
+ thisArg: JSAny): Boolean {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
// TODO(v8:4153): Support huge TypedArrays here.
const length =
@@ -17,7 +17,7 @@ namespace typed_array_every {
for (let k: Smi = 0; k < length; k++) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
- const value: Object = witness.Load(k);
+ const value: JSAny = witness.Load(k);
const result =
Call(context, callbackfn, thisArg, value, k, witness.GetStable());
if (!ToBoolean(result)) {
@@ -29,8 +29,8 @@ namespace typed_array_every {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every
transitioning javascript builtin
- TypedArrayPrototypeEvery(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ TypedArrayPrototypeEvery(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
// arguments[0] = callback
// arguments[1] = thisArg
try {
diff --git a/deps/v8/src/builtins/typed-array-filter.tq b/deps/v8/src/builtins/typed-array-filter.tq
index 3937699c73..66823f29e1 100644
--- a/deps/v8/src/builtins/typed-array-filter.tq
+++ b/deps/v8/src/builtins/typed-array-filter.tq
@@ -10,7 +10,7 @@ namespace typed_array_filter {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.filter
transitioning javascript builtin TypedArrayPrototypeFilter(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
// arguments[0] = callback
// arguments[1] = thisArg
try {
@@ -29,7 +29,7 @@ namespace typed_array_filter {
otherwise ThrowTypeError(kCalledNonCallable, arguments[0]);
// 5. If thisArg is present, let T be thisArg; else let T be undefined.
- const thisArg: Object = arguments[1];
+ const thisArg: JSAny = arguments[1];
// 6. Let kept be a new empty List.
let kept = growable_fixed_array::NewGrowableFixedArray();
@@ -43,17 +43,17 @@ namespace typed_array_filter {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
- const value: Object = witness.Load(k);
+ const value: JSAny = witness.Load(k);
// c. Let selected be ToBoolean(? Call(callbackfn, T, « kValue, k, O
// »)).
- const selected: Object =
+ const selected: JSAny =
Call(context, callbackfn, thisArg, value, k, witness.GetStable());
// d. If selected is true, then
// i. Append kValue to the end of kept.
// ii. Increase captured by 1.
- if (BranchIfToBooleanIsTrue(selected)) kept.Push(value);
+ if (ToBoolean(selected)) kept.Push(value);
// e.Increase k by 1.
}
diff --git a/deps/v8/src/builtins/typed-array-find.tq b/deps/v8/src/builtins/typed-array-find.tq
index be1943ccf4..9922abdc17 100644
--- a/deps/v8/src/builtins/typed-array-find.tq
+++ b/deps/v8/src/builtins/typed-array-find.tq
@@ -9,7 +9,7 @@ namespace typed_array_find {
transitioning macro FindAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
- thisArg: Object): Object {
+ thisArg: JSAny): JSAny {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
// TODO(v8:4153): Support huge TypedArrays here.
const length =
@@ -17,7 +17,7 @@ namespace typed_array_find {
for (let k: Smi = 0; k < length; k++) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
- const value: Object = witness.Load(k);
+ const value: JSAny = witness.Load(k);
const result =
Call(context, callbackfn, thisArg, value, k, witness.GetStable());
if (ToBoolean(result)) {
@@ -29,8 +29,8 @@ namespace typed_array_find {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.find
transitioning javascript builtin
- TypedArrayPrototypeFind(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ TypedArrayPrototypeFind(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
// arguments[0] = callback
// arguments[1] = thisArg
try {
diff --git a/deps/v8/src/builtins/typed-array-findindex.tq b/deps/v8/src/builtins/typed-array-findindex.tq
index a5ee7897d3..5438f3dbfe 100644
--- a/deps/v8/src/builtins/typed-array-findindex.tq
+++ b/deps/v8/src/builtins/typed-array-findindex.tq
@@ -9,7 +9,7 @@ namespace typed_array_findindex {
transitioning macro FindIndexAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
- thisArg: Object): Number {
+ thisArg: JSAny): Number {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
// TODO(v8:4153): Support huge TypedArrays here.
const length =
@@ -17,7 +17,7 @@ namespace typed_array_findindex {
for (let k: Smi = 0; k < length; k++) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
- const value: Object = witness.Load(k);
+ const value: JSAny = witness.Load(k);
const result =
Call(context, callbackfn, thisArg, value, k, witness.GetStable());
if (ToBoolean(result)) {
@@ -29,8 +29,8 @@ namespace typed_array_findindex {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.findIndex
transitioning javascript builtin
- TypedArrayPrototypeFindIndex(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ TypedArrayPrototypeFindIndex(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
// arguments[0] = callback
// arguments[1] = thisArg.
try {
diff --git a/deps/v8/src/builtins/typed-array-foreach.tq b/deps/v8/src/builtins/typed-array-foreach.tq
index 656a22e07d..b1ad894122 100644
--- a/deps/v8/src/builtins/typed-array-foreach.tq
+++ b/deps/v8/src/builtins/typed-array-foreach.tq
@@ -9,7 +9,7 @@ namespace typed_array_foreach {
transitioning macro ForEachAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
- thisArg: Object): Object {
+ thisArg: JSAny): Undefined {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
// TODO(v8:4153): Support huge TypedArrays here.
const length =
@@ -17,7 +17,7 @@ namespace typed_array_foreach {
for (let k: Smi = 0; k < length; k++) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
- const value: Object = witness.Load(k);
+ const value: JSAny = witness.Load(k);
Call(context, callbackfn, thisArg, value, k, witness.GetStable());
}
return Undefined;
@@ -25,8 +25,8 @@ namespace typed_array_foreach {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every
transitioning javascript builtin
- TypedArrayPrototypeForEach(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ TypedArrayPrototypeForEach(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): Undefined {
// arguments[0] = callback
// arguments[1] = this_arg.
diff --git a/deps/v8/src/builtins/typed-array-reduce.tq b/deps/v8/src/builtins/typed-array-reduce.tq
index d69dc9a98d..7f8eeb7de5 100644
--- a/deps/v8/src/builtins/typed-array-reduce.tq
+++ b/deps/v8/src/builtins/typed-array-reduce.tq
@@ -9,7 +9,7 @@ namespace typed_array_reduce {
transitioning macro ReduceAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
- initialValue: Object): Object {
+ initialValue: JSAny | TheHole): JSAny {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
// TODO(v8:4153): Support huge TypedArrays here.
const length =
@@ -18,25 +18,32 @@ namespace typed_array_reduce {
for (let k: Smi = 0; k < length; k++) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
- const value: Object = witness.Load(k);
- if (accumulator == TheHole) {
- accumulator = value;
- } else {
- accumulator = Call(
- context, callbackfn, Undefined, accumulator, value, k,
- witness.GetStable());
+ const value: JSAny = witness.Load(k);
+ typeswitch (accumulator) {
+ case (TheHole): {
+ accumulator = value;
+ }
+ case (accumulatorNotHole: JSAny): {
+ accumulator = Call(
+ context, callbackfn, Undefined, accumulatorNotHole, value, k,
+ witness.GetStable());
+ }
}
}
- if (accumulator == TheHole) {
- ThrowTypeError(kReduceNoInitial, kBuiltinName);
+ typeswitch (accumulator) {
+ case (TheHole): {
+ ThrowTypeError(kReduceNoInitial, kBuiltinName);
+ }
+ case (accumulator: JSAny): {
+ return accumulator;
+ }
}
- return accumulator;
}
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduce
transitioning javascript builtin
- TypedArrayPrototypeReduce(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ TypedArrayPrototypeReduce(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
// arguments[0] = callback
// arguments[1] = initialValue.
try {
diff --git a/deps/v8/src/builtins/typed-array-reduceright.tq b/deps/v8/src/builtins/typed-array-reduceright.tq
index 99a84401ed..c8e4fe83d3 100644
--- a/deps/v8/src/builtins/typed-array-reduceright.tq
+++ b/deps/v8/src/builtins/typed-array-reduceright.tq
@@ -9,7 +9,7 @@ namespace typed_array_reduceright {
transitioning macro ReduceRightAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
- initialValue: Object): Object {
+ initialValue: JSAny | TheHole): JSAny {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
// TODO(v8:4153): Support huge TypedArrays here.
const length =
@@ -18,25 +18,32 @@ namespace typed_array_reduceright {
for (let k: Smi = length - 1; k >= 0; k--) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
- const value: Object = witness.Load(k);
- if (accumulator == TheHole) {
- accumulator = value;
- } else {
- accumulator = Call(
- context, callbackfn, Undefined, accumulator, value, k,
- witness.GetStable());
+ const value: JSAny = witness.Load(k);
+ typeswitch (accumulator) {
+ case (TheHole): {
+ accumulator = value;
+ }
+ case (accumulatorNotHole: JSAny): {
+ accumulator = Call(
+ context, callbackfn, Undefined, accumulatorNotHole, value, k,
+ witness.GetStable());
+ }
}
}
- if (accumulator == TheHole) {
- ThrowTypeError(kReduceNoInitial, kBuiltinName);
+ typeswitch (accumulator) {
+ case (TheHole): {
+ ThrowTypeError(kReduceNoInitial, kBuiltinName);
+ }
+ case (accumulator: JSAny): {
+ return accumulator;
+ }
}
- return accumulator;
}
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduceright
transitioning javascript builtin
- TypedArrayPrototypeReduceRight(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ TypedArrayPrototypeReduceRight(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
// arguments[0] = callback
// arguments[1] = initialValue.
try {
diff --git a/deps/v8/src/builtins/typed-array-slice.tq b/deps/v8/src/builtins/typed-array-slice.tq
index c0087ae1be..dc13865590 100644
--- a/deps/v8/src/builtins/typed-array-slice.tq
+++ b/deps/v8/src/builtins/typed-array-slice.tq
@@ -13,7 +13,7 @@ namespace typed_array_slice {
macro FastCopy(
src: typed_array::AttachedJSTypedArray, dest: JSTypedArray, k: intptr,
count: PositiveSmi) labels IfSlow {
- GotoIfForceSlowPath() otherwise IfSlow;
+ if (IsForceSlowPath()) goto IfSlow;
const srcKind: ElementsKind = src.elements_kind;
const destInfo = typed_array::GetTypedArrayElementsInfo(dest);
@@ -53,7 +53,7 @@ namespace typed_array_slice {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.slice
transitioning javascript builtin TypedArrayPrototypeSlice(
- js-implicit context: Context, receiver: Object)(...arguments): Object {
+ js-implicit context: Context, receiver: JSAny)(...arguments): JSAny {
// arguments[0] = start
// arguments[1] = end
diff --git a/deps/v8/src/builtins/typed-array-some.tq b/deps/v8/src/builtins/typed-array-some.tq
index 7056650fba..7d08b1433b 100644
--- a/deps/v8/src/builtins/typed-array-some.tq
+++ b/deps/v8/src/builtins/typed-array-some.tq
@@ -9,7 +9,7 @@ namespace typed_array_some {
transitioning macro SomeAllElements(implicit context: Context)(
array: typed_array::AttachedJSTypedArray, callbackfn: Callable,
- thisArg: Object): Boolean {
+ thisArg: JSAny): Boolean {
let witness = typed_array::NewAttachedJSTypedArrayWitness(array);
// TODO(v8:4153): Support huge TypedArrays here.
const length =
@@ -17,7 +17,7 @@ namespace typed_array_some {
for (let k: Smi = 0; k < length; k++) {
// BUG(4895): We should throw on detached buffers rather than simply exit.
witness.Recheck() otherwise break;
- const value: Object = witness.Load(k);
+ const value: JSAny = witness.Load(k);
const result =
Call(context, callbackfn, thisArg, value, k, witness.GetStable());
if (ToBoolean(result)) {
@@ -29,8 +29,8 @@ namespace typed_array_some {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.some
transitioning javascript builtin
- TypedArrayPrototypeSome(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ TypedArrayPrototypeSome(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
// arguments[0] = callback
// arguments[1] = thisArg.
try {
diff --git a/deps/v8/src/builtins/typed-array-subarray.tq b/deps/v8/src/builtins/typed-array-subarray.tq
index 4f98123f82..589e67230c 100644
--- a/deps/v8/src/builtins/typed-array-subarray.tq
+++ b/deps/v8/src/builtins/typed-array-subarray.tq
@@ -6,7 +6,7 @@ namespace typed_array_subarray {
// ES %TypedArray%.prototype.subarray
transitioning javascript builtin TypedArrayPrototypeSubArray(
js-implicit context: Context,
- receiver: Object)(...arguments): JSTypedArray {
+ receiver: JSAny)(...arguments): JSTypedArray {
const methodName: constexpr string = '%TypedArray%.prototype.subarray';
// 1. Let O be the this value.
diff --git a/deps/v8/src/builtins/typed-array.tq b/deps/v8/src/builtins/typed-array.tq
index d03c1a0be9..59100736a5 100644
--- a/deps/v8/src/builtins/typed-array.tq
+++ b/deps/v8/src/builtins/typed-array.tq
@@ -51,9 +51,9 @@ namespace typed_array {
sizeLog2: uintptr;
kind: ElementsKind;
}
- extern runtime TypedArraySortFast(Context, Object): JSTypedArray;
+ extern runtime TypedArraySortFast(Context, JSAny): JSTypedArray;
extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray(
- Context, Object, constexpr string): JSTypedArray;
+ Context, JSAny, constexpr string): JSTypedArray;
extern macro TypedArrayBuiltinsAssembler::CallCMemcpy(
RawPtr, RawPtr, uintptr): void;
@@ -72,10 +72,10 @@ namespace typed_array {
extern macro LoadFixedTypedArrayElementAsTagged(
RawPtr, Smi, constexpr ElementsKind): Numeric;
extern macro StoreJSTypedArrayElementFromTagged(
- Context, JSTypedArray, Smi, Object, constexpr ElementsKind);
+ Context, JSTypedArray, Smi, JSAny, constexpr ElementsKind);
- type LoadFn = builtin(Context, JSTypedArray, Smi) => Object;
- type StoreFn = builtin(Context, JSTypedArray, Smi, Object) => Object;
+ type LoadFn = builtin(Context, JSTypedArray, Smi) => JSAny;
+ type StoreFn = builtin(Context, JSTypedArray, Smi, JSAny) => JSAny;
// AttachedJSTypedArray guards that the array's buffer is not detached.
transient type AttachedJSTypedArray extends JSTypedArray;
@@ -100,7 +100,7 @@ namespace typed_array {
this.unstable = %RawDownCast<AttachedJSTypedArray>(this.stable);
}
- Load(implicit context: Context)(k: Smi): Object {
+ Load(implicit context: Context)(k: Smi): JSAny {
const lf: LoadFn = this.loadfn;
return lf(context, this.unstable, k);
}
@@ -190,14 +190,14 @@ namespace typed_array {
}
builtin LoadFixedElement<T: type>(
- _context: Context, array: JSTypedArray, index: Smi): Object {
+ _context: Context, array: JSTypedArray, index: Smi): JSAny {
return LoadFixedTypedArrayElementAsTagged(
array.data_ptr, index, KindForArrayType<T>());
}
builtin StoreFixedElement<T: type>(
context: Context, typedArray: JSTypedArray, index: Smi,
- value: Object): Object {
+ value: JSAny): JSAny {
StoreJSTypedArrayElementFromTagged(
context, typedArray, index, value, KindForArrayType<T>());
return Undefined;
@@ -205,7 +205,7 @@ namespace typed_array {
transitioning macro CallCompare(
implicit context: Context, array: JSTypedArray,
- comparefn: Callable)(a: Object, b: Object): Number {
+ comparefn: Callable)(a: JSAny, b: JSAny): Number {
// a. Let v be ? ToNumber(? Call(comparefn, undefined, x, y)).
const v: Number =
ToNumber_Inline(context, Call(context, comparefn, Undefined, a, b));
@@ -238,8 +238,8 @@ namespace typed_array {
target.objects[targetIndex] = source.objects[left++];
} else if (left < middle) {
// If both have elements, we need to compare.
- const leftElement: Object = source.objects[left];
- const rightElement: Object = source.objects[right];
+ const leftElement = UnsafeCast<JSAny>(source.objects[left]);
+ const rightElement = UnsafeCast<JSAny>(source.objects[right]);
if (CallCompare(leftElement, rightElement) <= 0) {
target.objects[targetIndex] = leftElement;
left++;
@@ -259,7 +259,7 @@ namespace typed_array {
transitioning builtin
TypedArrayMergeSort(
implicit context: Context, array: JSTypedArray, comparefn: Callable)(
- source: FixedArray, from: Smi, to: Smi, target: FixedArray): Object {
+ source: FixedArray, from: Smi, to: Smi, target: FixedArray): JSAny {
assert(to - from > 1);
const middle: Smi = from + ((to - from) >> 1);
@@ -277,17 +277,16 @@ namespace typed_array {
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.sort
transitioning javascript builtin TypedArrayPrototypeSort(
js-implicit context: Context,
- receiver: Object)(...arguments): JSTypedArray {
+ receiver: JSAny)(...arguments): JSTypedArray {
// 1. If comparefn is not undefined and IsCallable(comparefn) is false,
// throw a TypeError exception.
- const comparefnObj: Object =
- arguments.length > 0 ? arguments[0] : Undefined;
+ const comparefnObj: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
if (comparefnObj != Undefined && !TaggedIsCallable(comparefnObj)) {
ThrowTypeError(kBadSortComparisonFunction, comparefnObj);
}
// 2. Let obj be the this value.
- const obj: Object = receiver;
+ const obj: JSAny = receiver;
// 3. Let buffer be ? ValidateTypedArray(obj).
// ValidateTypedArray currently returns the array, not the ViewBuffer.
@@ -363,7 +362,7 @@ namespace typed_array {
const work2: FixedArray = AllocateZeroedFixedArray(Convert<intptr>(len));
for (let i: Smi = 0; i < len; ++i) {
- const element: Object = loadfn(context, array, i);
+ const element: JSAny = loadfn(context, array, i);
work1.objects[i] = element;
work2.objects[i] = element;
}
@@ -372,7 +371,7 @@ namespace typed_array {
// work1 contains the sorted numbers. Write them back.
for (let i: Smi = 0; i < len; ++i)
- storefn(context, array, i, work1.objects[i]);
+ storefn(context, array, i, UnsafeCast<JSAny>(work1.objects[i]));
return array;
}
diff --git a/deps/v8/src/builtins/x64/builtins-x64.cc b/deps/v8/src/builtins/x64/builtins-x64.cc
index f15c8ba29f..b6b407fb33 100644
--- a/deps/v8/src/builtins/x64/builtins-x64.cc
+++ b/deps/v8/src/builtins/x64/builtins-x64.cc
@@ -64,6 +64,18 @@ static void GenerateTailCallToReturnedCode(MacroAssembler* masm,
namespace {
+Operand RealStackLimitAsOperand(MacroAssembler* masm) {
+ DCHECK(masm->root_array_available());
+ Isolate* isolate = masm->isolate();
+ ExternalReference limit = ExternalReference::address_of_real_jslimit(isolate);
+ DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
+
+ intptr_t offset =
+ TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
+ CHECK(is_int32(offset));
+ return Operand(kRootRegister, static_cast<int32_t>(offset));
+}
+
void Generate_StackOverflowCheck(
MacroAssembler* masm, Register num_args, Register scratch,
Label* stack_overflow,
@@ -71,7 +83,7 @@ void Generate_StackOverflowCheck(
// Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
- __ LoadRoot(kScratchRegister, RootIndex::kRealStackLimit);
+ __ movq(kScratchRegister, RealStackLimitAsOperand(masm));
__ movq(scratch, rsp);
// Make scratch the space we have left. The stack might already be overflowed
// here which will cause scratch to become negative.
@@ -735,7 +747,7 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit".
Label stack_overflow;
- __ CompareRoot(rsp, RootIndex::kRealStackLimit);
+ __ cmpq(rsp, RealStackLimitAsOperand(masm));
__ j(below, &stack_overflow);
// Pop return address.
@@ -1134,7 +1146,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
Label ok;
__ movq(rax, rsp);
__ subq(rax, rcx);
- __ CompareRoot(rax, RootIndex::kRealStackLimit);
+ __ cmpq(rax, RealStackLimitAsOperand(masm));
__ j(above_equal, &ok, Label::kNear);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bind(&ok);
@@ -2339,9 +2351,10 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
__ shlq(rbx, Immediate(kSystemPointerSizeLog2));
__ movq(kScratchRegister, rsp);
__ subq(kScratchRegister, rbx);
+
// We are not trying to catch interruptions (i.e. debug break and
// preemption) here, so check the "real stack limit".
- __ CompareRoot(kScratchRegister, RootIndex::kRealStackLimit);
+ __ cmpq(kScratchRegister, RealStackLimitAsOperand(masm));
__ j(above_equal, &done, Label::kNear);
{
FrameScope scope(masm, StackFrame::MANUAL);
@@ -2663,9 +2676,12 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
// Push the function index as second argument.
__ Push(r11);
// Load the correct CEntry builtin from the instance object.
+ __ movq(rcx, FieldOperand(kWasmInstanceRegister,
+ WasmInstanceObject::kIsolateRootOffset));
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
__ LoadTaggedPointerField(
- rcx, FieldOperand(kWasmInstanceRegister,
- WasmInstanceObject::kCEntryStubOffset));
+ rcx, MemOperand(rcx, IsolateData::builtin_slot_offset(centry_id)));
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Move(kContextRegister, Smi::zero());
diff --git a/deps/v8/src/codegen/DEPS b/deps/v8/src/codegen/DEPS
index f3715e6ad0..ca53b61541 100644
--- a/deps/v8/src/codegen/DEPS
+++ b/deps/v8/src/codegen/DEPS
@@ -4,6 +4,8 @@
specific_include_rules = {
"external-reference.cc": [
+ # Required to call IrregexpInterpreter::NativeMatch from builtin.
+ "+src/regexp/regexp-interpreter.h",
"+src/regexp/regexp-macro-assembler-arch.h",
],
}
diff --git a/deps/v8/src/codegen/arm/assembler-arm.cc b/deps/v8/src/codegen/arm/assembler-arm.cc
index 7ca49a3f9f..9c46063537 100644
--- a/deps/v8/src/codegen/arm/assembler-arm.cc
+++ b/deps/v8/src/codegen/arm/assembler-arm.cc
@@ -4258,6 +4258,24 @@ void Assembler::vmax(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src1,
enum NeonShiftOp { VSHL, VSHR, VSLI, VSRI };
+static Instr EncodeNeonShiftRegisterOp(NeonShiftOp op, NeonDataType dt,
+ NeonRegType reg_type, int dst_code,
+ int src_code, int shift_code) {
+ DCHECK_EQ(op, VSHL);
+ int op_encoding = 0;
+ int vd, d;
+ NeonSplitCode(reg_type, dst_code, &vd, &d, &op_encoding);
+ int vm, m;
+ NeonSplitCode(reg_type, src_code, &vm, &m, &op_encoding);
+ int vn, n;
+ NeonSplitCode(reg_type, shift_code, &vn, &n, &op_encoding);
+ int size = NeonSz(dt);
+ int u = NeonU(dt);
+
+ return 0x1E4U * B23 | u * B24 | d * B22 | size * B20 | vn * B16 | vd * B12 |
+ 0x4 * B8 | n * B7 | m * B5 | vm | op_encoding;
+}
+
static Instr EncodeNeonShiftOp(NeonShiftOp op, NeonSize size, bool is_unsigned,
NeonRegType reg_type, int dst_code, int src_code,
int shift) {
@@ -4315,6 +4333,15 @@ void Assembler::vshl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src,
dst.code(), src.code(), shift));
}
+void Assembler::vshl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src,
+ QwNeonRegister shift) {
+ DCHECK(IsEnabled(NEON));
+ // Qd = vshl(Qm, Qn) SIMD shift left Register.
+ // Instruction details available in ARM DDI 0487A.a, F8-3340..
+ emit(EncodeNeonShiftRegisterOp(VSHL, dt, NEON_Q, dst.code(), src.code(),
+ shift.code()));
+}
+
void Assembler::vshr(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src,
int shift) {
DCHECK(IsEnabled(NEON));
diff --git a/deps/v8/src/codegen/arm/assembler-arm.h b/deps/v8/src/codegen/arm/assembler-arm.h
index f383632f73..f669943f34 100644
--- a/deps/v8/src/codegen/arm/assembler-arm.h
+++ b/deps/v8/src/codegen/arm/assembler-arm.h
@@ -899,6 +899,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
void vpmax(NeonDataType dt, DwVfpRegister dst, DwVfpRegister src1,
DwVfpRegister src2);
void vshl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src, int shift);
+ void vshl(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src,
+ QwNeonRegister shift);
void vshr(NeonDataType dt, QwNeonRegister dst, QwNeonRegister src, int shift);
void vsli(NeonSize size, DwVfpRegister dst, DwVfpRegister src, int shift);
void vsri(NeonSize size, DwVfpRegister dst, DwVfpRegister src, int shift);
diff --git a/deps/v8/src/codegen/arm/macro-assembler-arm.cc b/deps/v8/src/codegen/arm/macro-assembler-arm.cc
index ba334cd0b6..7f6d82518e 100644
--- a/deps/v8/src/codegen/arm/macro-assembler-arm.cc
+++ b/deps/v8/src/codegen/arm/macro-assembler-arm.cc
@@ -217,6 +217,13 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
Jump(static_cast<intptr_t>(code.address()), rmode, cond);
}
+void TurboAssembler::Jump(const ExternalReference& reference) {
+ UseScratchRegisterScope temps(this);
+ Register scratch = temps.Acquire();
+ Move(scratch, reference);
+ Jump(scratch);
+}
+
void TurboAssembler::Call(Register target, Condition cond) {
// Block constant pool for the call instruction sequence.
BlockConstPoolScope block_const_pool(this);
@@ -289,13 +296,7 @@ void TurboAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
} else if (target_is_isolate_independent_builtin &&
options().inline_offheap_trampolines) {
// Inline the trampoline.
- RecordCommentForOffHeapTrampoline(builtin_index);
- EmbeddedData d = EmbeddedData::FromBlob();
- Address entry = d.InstructionStartOfBuiltin(builtin_index);
- // Use ip directly instead of using UseScratchRegisterScope, as we do not
- // preserve scratch registers across calls.
- mov(ip, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
- Call(ip, cond);
+ CallBuiltin(builtin_index);
return;
}
@@ -323,6 +324,18 @@ void TurboAssembler::CallBuiltinByIndex(Register builtin_index) {
Call(builtin_index);
}
+void TurboAssembler::CallBuiltin(int builtin_index, Condition cond) {
+ DCHECK(Builtins::IsBuiltinId(builtin_index));
+ DCHECK(FLAG_embedded_builtins);
+ RecordCommentForOffHeapTrampoline(builtin_index);
+ EmbeddedData d = EmbeddedData::FromBlob();
+ Address entry = d.InstructionStartOfBuiltin(builtin_index);
+ // Use ip directly instead of using UseScratchRegisterScope, as we do not
+ // preserve scratch registers across calls.
+ mov(ip, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
+ Call(ip, cond);
+}
+
void TurboAssembler::LoadCodeObjectEntry(Register destination,
Register code_object) {
// Code objects are called differently depending on whether we are generating
@@ -795,8 +808,9 @@ void MacroAssembler::RecordWrite(Register object, Operand offset,
Check(eq, AbortReason::kWrongAddressOrValuePassedToRecordWrite);
}
- if (remembered_set_action == OMIT_REMEMBERED_SET &&
- !FLAG_incremental_marking) {
+ if ((remembered_set_action == OMIT_REMEMBERED_SET &&
+ !FLAG_incremental_marking) ||
+ FLAG_disable_write_barriers) {
return;
}
@@ -1832,6 +1846,8 @@ void TurboAssembler::TruncateDoubleToI(Isolate* isolate, Zone* zone,
if (stub_mode == StubCallMode::kCallWasmRuntimeStub) {
Call(wasm::WasmCode::kDoubleToI, RelocInfo::WASM_STUB_CALL);
+ } else if (options().inline_offheap_trampolines) {
+ CallBuiltin(Builtins::kDoubleToI);
} else {
Call(BUILTIN_CODE(isolate, DoubleToI), RelocInfo::CODE_TARGET);
}
diff --git a/deps/v8/src/codegen/arm/macro-assembler-arm.h b/deps/v8/src/codegen/arm/macro-assembler-arm.h
index e4ce734f52..bbea40b9a6 100644
--- a/deps/v8/src/codegen/arm/macro-assembler-arm.h
+++ b/deps/v8/src/codegen/arm/macro-assembler-arm.h
@@ -304,6 +304,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
// register.
void LoadEntryFromBuiltinIndex(Register builtin_index);
void CallBuiltinByIndex(Register builtin_index) override;
+ void CallBuiltin(int builtin_index, Condition cond = al);
void LoadCodeObjectEntry(Register destination, Register code_object) override;
void CallCodeObject(Register code_object) override;
@@ -408,6 +409,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Jump(Register target, Condition cond = al);
void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
+ void Jump(const ExternalReference& reference) override;
// Perform a floating-point min or max operation with the
// (IEEE-754-compatible) semantics of ARM64's fmin/fmax. Some cases, typically
diff --git a/deps/v8/src/codegen/arm64/assembler-arm64.cc b/deps/v8/src/codegen/arm64/assembler-arm64.cc
index 159e763ba2..c798d3a8a0 100644
--- a/deps/v8/src/codegen/arm64/assembler-arm64.cc
+++ b/deps/v8/src/codegen/arm64/assembler-arm64.cc
@@ -327,6 +327,12 @@ Assembler::Assembler(const AssemblerOptions& options,
constpool_(this) {
veneer_pool_blocked_nesting_ = 0;
Reset();
+
+#if defined(V8_OS_WIN)
+ if (options.collect_win64_unwind_info) {
+ xdata_encoder_ = std::make_unique<win64_unwindinfo::XdataEncoder>(*this);
+ }
+#endif
}
Assembler::~Assembler() {
@@ -349,6 +355,14 @@ void Assembler::Reset() {
next_veneer_pool_check_ = kMaxInt;
}
+#if defined(V8_OS_WIN)
+win64_unwindinfo::BuiltinUnwindInfo Assembler::GetUnwindInfo() const {
+ DCHECK(options().collect_win64_unwind_info);
+ DCHECK_NOT_NULL(xdata_encoder_);
+ return xdata_encoder_->unwinding_info();
+}
+#endif
+
void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty());
for (auto& request : heap_object_requests_) {
@@ -1166,6 +1180,11 @@ void Assembler::cls(const Register& rd, const Register& rn) {
DataProcessing1Source(rd, rn, CLS);
}
+void Assembler::pacia1716() { Emit(PACIA1716); }
+void Assembler::autia1716() { Emit(AUTIA1716); }
+void Assembler::paciasp() { Emit(PACIASP); }
+void Assembler::autiasp() { Emit(AUTIASP); }
+
void Assembler::ldp(const CPURegister& rt, const CPURegister& rt2,
const MemOperand& src) {
LoadStorePair(rt, rt2, src, LoadPairOpFor(rt, rt2));
@@ -1174,6 +1193,12 @@ void Assembler::ldp(const CPURegister& rt, const CPURegister& rt2,
void Assembler::stp(const CPURegister& rt, const CPURegister& rt2,
const MemOperand& dst) {
LoadStorePair(rt, rt2, dst, StorePairOpFor(rt, rt2));
+
+#if defined(V8_OS_WIN)
+ if (xdata_encoder_ && rt == x29 && rt2 == lr && dst.base().IsSP()) {
+ xdata_encoder_->onSaveFpLr();
+ }
+#endif
}
void Assembler::ldpsw(const Register& rt, const Register& rt2,
diff --git a/deps/v8/src/codegen/arm64/assembler-arm64.h b/deps/v8/src/codegen/arm64/assembler-arm64.h
index 6a6bf633c1..04ee6d8b75 100644
--- a/deps/v8/src/codegen/arm64/assembler-arm64.h
+++ b/deps/v8/src/codegen/arm64/assembler-arm64.h
@@ -25,6 +25,10 @@
#undef mvn
#endif
+#if defined(V8_OS_WIN)
+#include "src/diagnostics/unwinding-info-win64.h"
+#endif // V8_OS_WIN
+
namespace v8 {
namespace internal {
@@ -786,6 +790,22 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
void clz(const Register& rd, const Register& rn);
void cls(const Register& rd, const Register& rn);
+ // Pointer Authentication Code for Instruction address, using key A, with
+ // address in x17 and modifier in x16 [Armv8.3].
+ void pacia1716();
+
+ // Pointer Authentication Code for Instruction address, using key A, with
+ // address in LR and modifier in SP [Armv8.3].
+ void paciasp();
+
+ // Authenticate Instruction address, using key A, with address in x17 and
+ // modifier in x16 [Armv8.3].
+ void autia1716();
+
+ // Authenticate Instruction address, using key A, with address in LR and
+ // modifier in SP [Armv8.3].
+ void autiasp();
+
// Memory instructions.
// Load integer or FP register.
@@ -2400,6 +2420,14 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
DISALLOW_IMPLICIT_CONSTRUCTORS(BlockPoolsScope);
};
+#if defined(V8_OS_WIN)
+ win64_unwindinfo::XdataEncoder* GetXdataEncoder() {
+ return xdata_encoder_.get();
+ }
+
+ win64_unwindinfo::BuiltinUnwindInfo GetUnwindInfo() const;
+#endif
+
protected:
inline const Register& AppropriateZeroRegFor(const CPURegister& reg) const;
@@ -2670,6 +2698,10 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// veneer margin (or kMaxInt if there are no unresolved branches).
int next_veneer_pool_check_;
+#if defined(V8_OS_WIN)
+ std::unique_ptr<win64_unwindinfo::XdataEncoder> xdata_encoder_;
+#endif
+
private:
// Avoid overflows for displacements etc.
static const int kMaximalBufferSize = 512 * MB;
diff --git a/deps/v8/src/codegen/arm64/constants-arm64.h b/deps/v8/src/codegen/arm64/constants-arm64.h
index a1e962452b..914268644a 100644
--- a/deps/v8/src/codegen/arm64/constants-arm64.h
+++ b/deps/v8/src/codegen/arm64/constants-arm64.h
@@ -130,6 +130,8 @@ const uint64_t kAddressTagMask = ((UINT64_C(1) << kAddressTagWidth) - 1)
static_assert(kAddressTagMask == UINT64_C(0xff00000000000000),
"AddressTagMask must represent most-significant eight bits.");
+const uint64_t kTTBRMask = UINT64_C(1) << 55;
+
// AArch64 floating-point specifics. These match IEEE-754.
const unsigned kDoubleMantissaBits = 52;
const unsigned kDoubleExponentBits = 11;
@@ -760,6 +762,16 @@ enum MemBarrierOp : uint32_t {
ISB = MemBarrierFixed | 0x00000040
};
+enum SystemPAuthOp : uint32_t {
+ SystemPAuthFixed = 0xD503211F,
+ SystemPAuthFMask = 0xFFFFFD1F,
+ SystemPAuthMask = 0xFFFFFFFF,
+ PACIA1716 = SystemPAuthFixed | 0x00000100,
+ AUTIA1716 = SystemPAuthFixed | 0x00000180,
+ PACIASP = SystemPAuthFixed | 0x00000320,
+ AUTIASP = SystemPAuthFixed | 0x000003A0
+};
+
// Any load or store (including pair).
enum LoadStoreAnyOp : uint32_t {
LoadStoreAnyFMask = 0x0a000000,
diff --git a/deps/v8/src/codegen/arm64/instructions-arm64.cc b/deps/v8/src/codegen/arm64/instructions-arm64.cc
index dfc2ef1323..05f3654da9 100644
--- a/deps/v8/src/codegen/arm64/instructions-arm64.cc
+++ b/deps/v8/src/codegen/arm64/instructions-arm64.cc
@@ -211,7 +211,8 @@ Instruction* Instruction::ImmPCOffsetTarget() {
bool Instruction::IsValidImmPCOffset(ImmBranchType branch_type,
ptrdiff_t offset) {
- return is_intn(offset, ImmBranchRangeBitwidth(branch_type));
+ DCHECK_EQ(offset % kInstrSize, 0);
+ return is_intn(offset / kInstrSize, ImmBranchRangeBitwidth(branch_type));
}
bool Instruction::IsTargetInImmPCOffsetRange(Instruction* target) {
@@ -251,8 +252,7 @@ void Instruction::SetPCRelImmTarget(const AssemblerOptions& options,
void Instruction::SetBranchImmTarget(Instruction* target) {
DCHECK(IsAligned(DistanceTo(target), kInstrSize));
- DCHECK(
- IsValidImmPCOffset(BranchType(), DistanceTo(target) >> kInstrSizeLog2));
+ DCHECK(IsValidImmPCOffset(BranchType(), DistanceTo(target)));
int offset = static_cast<int>(DistanceTo(target) >> kInstrSizeLog2);
Instr branch_imm = 0;
uint32_t imm_mask = 0;
diff --git a/deps/v8/src/codegen/arm64/instructions-arm64.h b/deps/v8/src/codegen/arm64/instructions-arm64.h
index a73c3feed7..1132ba39db 100644
--- a/deps/v8/src/codegen/arm64/instructions-arm64.h
+++ b/deps/v8/src/codegen/arm64/instructions-arm64.h
@@ -390,6 +390,8 @@ class Instruction {
// PC-relative addressing instruction.
V8_EXPORT_PRIVATE Instruction* ImmPCOffsetTarget();
+ // Check if the offset is in range of a given branch type. The offset is
+ // a byte offset, unscaled.
static bool IsValidImmPCOffset(ImmBranchType branch_type, ptrdiff_t offset);
bool IsTargetInImmPCOffsetRange(Instruction* target);
// Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc
index 792a8637f6..0a721b0647 100644
--- a/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc
+++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc
@@ -13,6 +13,7 @@
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/debug/debug.h"
+#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/frame-constants.h"
#include "src/execution/frames-inl.h"
#include "src/heap/heap-inl.h" // For MemoryChunk.
@@ -1138,43 +1139,28 @@ void MacroAssembler::PushMultipleTimes(CPURegister src, Register count) {
UseScratchRegisterScope temps(this);
Register temp = temps.AcquireSameSizeAs(count);
- if (FLAG_optimize_for_size) {
- Label loop, done;
+ Label loop, leftover2, leftover1, done;
- Subs(temp, count, 1);
- B(mi, &done);
+ Subs(temp, count, 4);
+ B(mi, &leftover2);
- // Push all registers individually, to save code size.
- Bind(&loop);
- Subs(temp, temp, 1);
- PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg);
- B(pl, &loop);
-
- Bind(&done);
- } else {
- Label loop, leftover2, leftover1, done;
-
- Subs(temp, count, 4);
- B(mi, &leftover2);
-
- // Push groups of four first.
- Bind(&loop);
- Subs(temp, temp, 4);
- PushHelper(4, src.SizeInBytes(), src, src, src, src);
- B(pl, &loop);
+ // Push groups of four first.
+ Bind(&loop);
+ Subs(temp, temp, 4);
+ PushHelper(4, src.SizeInBytes(), src, src, src, src);
+ B(pl, &loop);
- // Push groups of two.
- Bind(&leftover2);
- Tbz(count, 1, &leftover1);
- PushHelper(2, src.SizeInBytes(), src, src, NoReg, NoReg);
+ // Push groups of two.
+ Bind(&leftover2);
+ Tbz(count, 1, &leftover1);
+ PushHelper(2, src.SizeInBytes(), src, src, NoReg, NoReg);
- // Push the last one (if required).
- Bind(&leftover1);
- Tbz(count, 0, &done);
- PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg);
+ // Push the last one (if required).
+ Bind(&leftover1);
+ Tbz(count, 0, &done);
+ PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg);
- Bind(&done);
- }
+ Bind(&done);
}
void TurboAssembler::PushHelper(int count, int size, const CPURegister& src0,
@@ -1301,6 +1287,14 @@ void MacroAssembler::PushCalleeSavedRegisters() {
stp(d8, d9, tos);
stp(x29, x30, tos);
+#if defined(V8_OS_WIN)
+ // kFramePointerOffsetInPushCalleeSavedRegisters is the offset from tos at
+ // the end of this function to the saved caller's fp/x29 pointer. It includes
+ // registers from x19 to x28, which is 10 pointers defined by below stp
+ // instructions.
+ STATIC_ASSERT(kFramePointerOffsetInPushCalleeSavedRegisters ==
+ 10 * kSystemPointerSize);
+#endif // defined(V8_OS_WIN)
stp(x27, x28, tos);
stp(x25, x26, tos);
stp(x23, x24, tos);
@@ -1873,6 +1867,13 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
}
}
+void TurboAssembler::Jump(const ExternalReference& reference) {
+ UseScratchRegisterScope temps(this);
+ Register scratch = temps.AcquireX();
+ Mov(scratch, reference);
+ Jump(scratch);
+}
+
void TurboAssembler::Call(Register target) {
BlockPoolsScope scope(this);
Blr(target);
@@ -1900,14 +1901,7 @@ void TurboAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode) {
if (isolate()->builtins()->IsBuiltinHandle(code, &builtin_index) &&
Builtins::IsIsolateIndependent(builtin_index)) {
// Inline the trampoline.
- RecordCommentForOffHeapTrampoline(builtin_index);
- CHECK_NE(builtin_index, Builtins::kNoBuiltinId);
- UseScratchRegisterScope temps(this);
- Register scratch = temps.AcquireX();
- EmbeddedData d = EmbeddedData::FromBlob();
- Address entry = d.InstructionStartOfBuiltin(builtin_index);
- Ldr(scratch, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
- Call(scratch);
+ CallBuiltin(builtin_index);
return;
}
}
@@ -1951,6 +1945,19 @@ void TurboAssembler::CallBuiltinByIndex(Register builtin_index) {
Call(builtin_index);
}
+void TurboAssembler::CallBuiltin(int builtin_index) {
+ DCHECK(Builtins::IsBuiltinId(builtin_index));
+ DCHECK(FLAG_embedded_builtins);
+ RecordCommentForOffHeapTrampoline(builtin_index);
+ CHECK_NE(builtin_index, Builtins::kNoBuiltinId);
+ UseScratchRegisterScope temps(this);
+ Register scratch = temps.AcquireX();
+ EmbeddedData d = EmbeddedData::FromBlob();
+ Address entry = d.InstructionStartOfBuiltin(builtin_index);
+ Ldr(scratch, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
+ Call(scratch);
+}
+
void TurboAssembler::LoadCodeObjectEntry(Register destination,
Register code_object) {
// Code objects are called differently depending on whether we are generating
@@ -2051,22 +2058,17 @@ bool TurboAssembler::IsNearCallOffset(int64_t offset) {
void TurboAssembler::CallForDeoptimization(Address target, int deopt_id) {
BlockPoolsScope scope(this);
- NoRootArrayScope no_root_array(this);
-
#ifdef DEBUG
Label start;
- Bind(&start);
+ bind(&start);
#endif
- // Make sure that the deopt id can be encoded in 16 bits, so can be encoded
- // in a single movz instruction with a zero shift.
- DCHECK(is_uint16(deopt_id));
- movz(x26, deopt_id);
int64_t offset = static_cast<int64_t>(target) -
static_cast<int64_t>(options().code_range_start);
DCHECK_EQ(offset % kInstrSize, 0);
offset = offset / static_cast<int>(kInstrSize);
DCHECK(IsNearCallOffset(offset));
near_call(static_cast<int>(offset), RelocInfo::RUNTIME_ENTRY);
+ DCHECK_EQ(SizeOfCodeGeneratedSince(&start), Deoptimizer::kDeoptExitSize);
}
void TurboAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
@@ -2374,6 +2376,8 @@ void TurboAssembler::TruncateDoubleToI(Isolate* isolate, Zone* zone,
// DoubleToI preserves any registers it needs to clobber.
if (stub_mode == StubCallMode::kCallWasmRuntimeStub) {
Call(wasm::WasmCode::kDoubleToI, RelocInfo::WASM_STUB_CALL);
+ } else if (options().inline_offheap_trampolines) {
+ CallBuiltin(Builtins::kDoubleToI);
} else {
Call(BUILTIN_CODE(isolate, DoubleToI), RelocInfo::CODE_TARGET);
}
@@ -3002,6 +3006,12 @@ void MacroAssembler::RecordWrite(Register object, Operand offset,
Check(eq, AbortReason::kWrongAddressOrValuePassedToRecordWrite);
}
+ if ((remembered_set_action == OMIT_REMEMBERED_SET &&
+ !FLAG_incremental_marking) ||
+ FLAG_disable_write_barriers) {
+ return;
+ }
+
// First, check if a write barrier is even needed. The tests below
// catch stores of smis and stores into the young generation.
Label done;
diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64.h b/deps/v8/src/codegen/arm64/macro-assembler-arm64.h
index d4e9c3055b..94091e8624 100644
--- a/deps/v8/src/codegen/arm64/macro-assembler-arm64.h
+++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64.h
@@ -83,6 +83,12 @@ inline MemOperand FieldMemOperand(Register object, int offset);
// ----------------------------------------------------------------------------
// MacroAssembler
+#if defined(V8_OS_WIN)
+// This offset is originated from PushCalleeSavedRegisters.
+static constexpr int kFramePointerOffsetInPushCalleeSavedRegisters =
+ 10 * kSystemPointerSize;
+#endif // V8_OS_WIN
+
enum BranchType {
// Copies of architectural conditions.
// The associated conditions can be used in place of those, the code will
@@ -515,6 +521,46 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Cbnz(const Register& rt, Label* label);
void Cbz(const Register& rt, Label* label);
+ void Paciasp() {
+ DCHECK(allow_macro_instructions_);
+ paciasp();
+ }
+ void Autiasp() {
+ DCHECK(allow_macro_instructions_);
+ autiasp();
+ }
+
+ // The 1716 pac and aut instructions encourage people to use x16 and x17
+ // directly, perhaps without realising that this is forbidden. For example:
+ //
+ // UseScratchRegisterScope temps(&masm);
+ // Register temp = temps.AcquireX(); // temp will be x16
+ // __ Mov(x17, ptr);
+ // __ Mov(x16, modifier); // Will override temp!
+ // __ Pacia1716();
+ //
+ // To work around this issue, you must exclude x16 and x17 from the scratch
+ // register list. You may need to replace them with other registers:
+ //
+ // UseScratchRegisterScope temps(&masm);
+ // temps.Exclude(x16, x17);
+ // temps.Include(x10, x11);
+ // __ Mov(x17, ptr);
+ // __ Mov(x16, modifier);
+ // __ Pacia1716();
+ void Pacia1716() {
+ DCHECK(allow_macro_instructions_);
+ DCHECK(!TmpList()->IncludesAliasOf(x16));
+ DCHECK(!TmpList()->IncludesAliasOf(x17));
+ pacia1716();
+ }
+ void Autia1716() {
+ DCHECK(allow_macro_instructions_);
+ DCHECK(!TmpList()->IncludesAliasOf(x16));
+ DCHECK(!TmpList()->IncludesAliasOf(x17));
+ autia1716();
+ }
+
inline void Dmb(BarrierDomain domain, BarrierType type);
inline void Dsb(BarrierDomain domain, BarrierType type);
inline void Isb();
@@ -843,6 +889,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Jump(Register target, Condition cond = al);
void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
+ void Jump(const ExternalReference& reference) override;
void Call(Register target);
void Call(Address target, RelocInfo::Mode rmode);
@@ -856,6 +903,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
// register.
void LoadEntryFromBuiltinIndex(Register builtin_index);
void CallBuiltinByIndex(Register builtin_index) override;
+ void CallBuiltin(int builtin_index);
void LoadCodeObjectEntry(Register destination, Register code_object) override;
void CallCodeObject(Register code_object) override;
@@ -1997,6 +2045,26 @@ class UseScratchRegisterScope {
Register AcquireSameSizeAs(const Register& reg);
V8_EXPORT_PRIVATE VRegister AcquireSameSizeAs(const VRegister& reg);
+ void Include(const CPURegList& list) { available_->Combine(list); }
+ void Exclude(const CPURegList& list) {
+#if DEBUG
+ CPURegList copy(list);
+ while (!copy.IsEmpty()) {
+ const CPURegister& reg = copy.PopHighestIndex();
+ DCHECK(available_->IncludesAliasOf(reg));
+ }
+#endif
+ available_->Remove(list);
+ }
+ void Include(const Register& reg1, const Register& reg2) {
+ CPURegList list(reg1, reg2);
+ Include(list);
+ }
+ void Exclude(const Register& reg1, const Register& reg2) {
+ CPURegList list(reg1, reg2);
+ Exclude(list);
+ }
+
private:
V8_EXPORT_PRIVATE static CPURegister AcquireNextAvailable(
CPURegList* available);
diff --git a/deps/v8/src/codegen/arm64/register-arm64.h b/deps/v8/src/codegen/arm64/register-arm64.h
index b429786aa9..7b938579f4 100644
--- a/deps/v8/src/codegen/arm64/register-arm64.h
+++ b/deps/v8/src/codegen/arm64/register-arm64.h
@@ -151,13 +151,21 @@ class CPURegister : public RegisterBase<CPURegister, kRegAfterLast> {
}
bool IsValid() const { return reg_type_ != kNoRegister; }
bool IsNone() const { return reg_type_ == kNoRegister; }
- bool Is(const CPURegister& other) const {
+ constexpr bool Is(const CPURegister& other) const {
return Aliases(other) && (reg_size_ == other.reg_size_);
}
- bool Aliases(const CPURegister& other) const {
+ constexpr bool Aliases(const CPURegister& other) const {
return (reg_code_ == other.reg_code_) && (reg_type_ == other.reg_type_);
}
+ constexpr bool operator==(const CPURegister& other) const {
+ return Is(other);
+ }
+
+ constexpr bool operator!=(const CPURegister& other) const {
+ return !(*this == other);
+ }
+
bool IsZero() const;
bool IsSP() const;
@@ -559,8 +567,6 @@ using Simd128Register = VRegister;
// Lists of registers.
class V8_EXPORT_PRIVATE CPURegList {
public:
- CPURegList() = default;
-
template <typename... CPURegisters>
explicit CPURegList(CPURegister reg0, CPURegisters... regs)
: list_(CPURegister::ListOf(reg0, regs...)),
diff --git a/deps/v8/src/codegen/code-factory.cc b/deps/v8/src/codegen/code-factory.cc
index 931b783730..c8838b0566 100644
--- a/deps/v8/src/codegen/code-factory.cc
+++ b/deps/v8/src/codegen/code-factory.cc
@@ -267,9 +267,9 @@ Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags) {
case STRING_ADD_CHECK_NONE:
return Builtins::CallableFor(isolate, Builtins::kStringAdd_CheckNone);
case STRING_ADD_CONVERT_LEFT:
- return Builtins::CallableFor(isolate, Builtins::kStringAdd_ConvertLeft);
+ return Builtins::CallableFor(isolate, Builtins::kStringAddConvertLeft);
case STRING_ADD_CONVERT_RIGHT:
- return Builtins::CallableFor(isolate, Builtins::kStringAdd_ConvertRight);
+ return Builtins::CallableFor(isolate, Builtins::kStringAddConvertRight);
}
UNREACHABLE();
}
diff --git a/deps/v8/src/codegen/code-stub-assembler.cc b/deps/v8/src/codegen/code-stub-assembler.cc
index e4f35ddcc8..7dad8cb95e 100644
--- a/deps/v8/src/codegen/code-stub-assembler.cc
+++ b/deps/v8/src/codegen/code-stub-assembler.cc
@@ -4,7 +4,10 @@
#include "src/codegen/code-stub-assembler.h"
+#include "include/v8-internal.h"
+#include "src/base/macros.h"
#include "src/codegen/code-factory.h"
+#include "src/common/globals.h"
#include "src/execution/frames-inl.h"
#include "src/execution/frames.h"
#include "src/heap/heap-inl.h" // For Page/MemoryChunk. TODO(jkummerow): Drop.
@@ -81,6 +84,16 @@ void CodeStubAssembler::Assert(const NodeGenerator& condition_body,
#endif
}
+void CodeStubAssembler::Assert(SloppyTNode<Word32T> condition_node,
+ const char* message, const char* file, int line,
+ std::initializer_list<ExtraNode> extra_nodes) {
+#if defined(DEBUG)
+ if (FLAG_debug_code) {
+ Check(condition_node, message, file, line, extra_nodes);
+ }
+#endif
+}
+
void CodeStubAssembler::Check(const BranchGenerator& branch,
const char* message, const char* file, int line,
std::initializer_list<ExtraNode> extra_nodes) {
@@ -112,6 +125,16 @@ void CodeStubAssembler::Check(const NodeGenerator& condition_body,
Check(branch, message, file, line, extra_nodes);
}
+void CodeStubAssembler::Check(SloppyTNode<Word32T> condition_node,
+ const char* message, const char* file, int line,
+ std::initializer_list<ExtraNode> extra_nodes) {
+ BranchGenerator branch = [=](Label* ok, Label* not_ok) {
+ Branch(condition_node, ok, not_ok);
+ };
+
+ Check(branch, message, file, line, extra_nodes);
+}
+
void CodeStubAssembler::FastCheck(TNode<BoolT> condition) {
Label ok(this), not_ok(this, Label::kDeferred);
Branch(condition, &ok, &not_ok);
@@ -132,7 +155,7 @@ void CodeStubAssembler::FailAssert(
SNPrintF(chars, "%s [%s:%d]", message, file, line);
message = chars.begin();
}
- Node* message_node = StringConstant(message);
+ TNode<String> message_node = StringConstant(message);
#ifdef DEBUG
// Only print the extra nodes in debug builds.
@@ -222,15 +245,25 @@ HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR)
#define HEAP_CONSTANT_TEST(rootIndexName, rootAccessorName, name) \
compiler::TNode<BoolT> CodeStubAssembler::Is##name( \
SloppyTNode<Object> value) { \
- return WordEqual(value, name##Constant()); \
+ return TaggedEqual(value, name##Constant()); \
} \
compiler::TNode<BoolT> CodeStubAssembler::IsNot##name( \
SloppyTNode<Object> value) { \
- return WordNotEqual(value, name##Constant()); \
+ return TaggedNotEqual(value, name##Constant()); \
}
HEAP_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_TEST)
#undef HEAP_CONSTANT_TEST
+TNode<BInt> CodeStubAssembler::BIntConstant(int value) {
+#if defined(BINT_IS_SMI)
+ return SmiConstant(value);
+#elif defined(BINT_IS_INTPTR)
+ return IntPtrConstant(value);
+#else
+#error Unknown architecture.
+#endif
+}
+
Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) {
if (mode == SMI_PARAMETERS) {
return SmiConstant(value);
@@ -240,12 +273,34 @@ Node* CodeStubAssembler::IntPtrOrSmiConstant(int value, ParameterMode mode) {
}
}
+TNode<BoolT> CodeStubAssembler::IntPtrOrSmiEqual(Node* left, Node* right,
+ ParameterMode mode) {
+ if (mode == SMI_PARAMETERS) {
+ return SmiEqual(CAST(left), CAST(right));
+ } else {
+ DCHECK_EQ(INTPTR_PARAMETERS, mode);
+ return IntPtrEqual(UncheckedCast<IntPtrT>(left),
+ UncheckedCast<IntPtrT>(right));
+ }
+}
+
+TNode<BoolT> CodeStubAssembler::IntPtrOrSmiNotEqual(Node* left, Node* right,
+ ParameterMode mode) {
+ if (mode == SMI_PARAMETERS) {
+ return SmiNotEqual(CAST(left), CAST(right));
+ } else {
+ DCHECK_EQ(INTPTR_PARAMETERS, mode);
+ return WordNotEqual(UncheckedCast<IntPtrT>(left),
+ UncheckedCast<IntPtrT>(right));
+ }
+}
+
bool CodeStubAssembler::IsIntPtrOrSmiConstantZero(Node* test,
ParameterMode mode) {
int32_t constant_test;
Smi smi_test;
if (mode == INTPTR_PARAMETERS) {
- if (ToInt32Constant(test, constant_test) && constant_test == 0) {
+ if (ToInt32Constant(test, &constant_test) && constant_test == 0) {
return true;
}
} else {
@@ -262,7 +317,7 @@ bool CodeStubAssembler::TryGetIntPtrOrSmiConstantValue(Node* maybe_constant,
ParameterMode mode) {
int32_t int32_constant;
if (mode == INTPTR_PARAMETERS) {
- if (ToInt32Constant(maybe_constant, int32_constant)) {
+ if (ToInt32Constant(maybe_constant, &int32_constant)) {
*value = int32_constant;
return true;
}
@@ -298,17 +353,17 @@ Node* CodeStubAssembler::MatchesParameterMode(Node* value, ParameterMode mode) {
TNode<BoolT> CodeStubAssembler::WordIsPowerOfTwo(SloppyTNode<IntPtrT> value) {
// value && !(value & (value - 1))
- return WordEqual(
+ return IntPtrEqual(
Select<IntPtrT>(
- WordEqual(value, IntPtrConstant(0)),
+ IntPtrEqual(value, IntPtrConstant(0)),
[=] { return IntPtrConstant(1); },
[=] { return WordAnd(value, IntPtrSub(value, IntPtrConstant(1))); }),
IntPtrConstant(0));
}
TNode<Float64T> CodeStubAssembler::Float64Round(SloppyTNode<Float64T> x) {
- Node* one = Float64Constant(1.0);
- Node* one_half = Float64Constant(0.5);
+ TNode<Float64T> one = Float64Constant(1.0);
+ TNode<Float64T> one_half = Float64Constant(0.5);
Label return_x(this);
@@ -329,10 +384,10 @@ TNode<Float64T> CodeStubAssembler::Float64Ceil(SloppyTNode<Float64T> x) {
return Float64RoundUp(x);
}
- Node* one = Float64Constant(1.0);
- Node* zero = Float64Constant(0.0);
- Node* two_52 = Float64Constant(4503599627370496.0E0);
- Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
+ TNode<Float64T> one = Float64Constant(1.0);
+ TNode<Float64T> zero = Float64Constant(0.0);
+ TNode<Float64T> two_52 = Float64Constant(4503599627370496.0E0);
+ TNode<Float64T> minus_two_52 = Float64Constant(-4503599627370496.0E0);
VARIABLE(var_x, MachineRepresentation::kFloat64, x);
Label return_x(this), return_minus_x(this);
@@ -361,7 +416,7 @@ TNode<Float64T> CodeStubAssembler::Float64Ceil(SloppyTNode<Float64T> x) {
GotoIfNot(Float64LessThan(x, zero), &return_x);
// Round negated {x} towards Infinity and return the result negated.
- Node* minus_x = Float64Neg(x);
+ TNode<Float64T> minus_x = Float64Neg(x);
var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
GotoIfNot(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x);
var_x.Bind(Float64Sub(var_x.value(), one));
@@ -381,10 +436,10 @@ TNode<Float64T> CodeStubAssembler::Float64Floor(SloppyTNode<Float64T> x) {
return Float64RoundDown(x);
}
- Node* one = Float64Constant(1.0);
- Node* zero = Float64Constant(0.0);
- Node* two_52 = Float64Constant(4503599627370496.0E0);
- Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
+ TNode<Float64T> one = Float64Constant(1.0);
+ TNode<Float64T> zero = Float64Constant(0.0);
+ TNode<Float64T> two_52 = Float64Constant(4503599627370496.0E0);
+ TNode<Float64T> minus_two_52 = Float64Constant(-4503599627370496.0E0);
VARIABLE(var_x, MachineRepresentation::kFloat64, x);
Label return_x(this), return_minus_x(this);
@@ -413,7 +468,7 @@ TNode<Float64T> CodeStubAssembler::Float64Floor(SloppyTNode<Float64T> x) {
GotoIfNot(Float64LessThan(x, zero), &return_x);
// Round negated {x} towards -Infinity and return the result negated.
- Node* minus_x = Float64Neg(x);
+ TNode<Float64T> minus_x = Float64Neg(x);
var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
GotoIfNot(Float64LessThan(var_x.value(), minus_x), &return_minus_x);
var_x.Bind(Float64Add(var_x.value(), one));
@@ -433,8 +488,8 @@ TNode<Float64T> CodeStubAssembler::Float64RoundToEven(SloppyTNode<Float64T> x) {
return Float64RoundTiesEven(x);
}
// See ES#sec-touint8clamp for details.
- Node* f = Float64Floor(x);
- Node* f_and_half = Float64Add(f, Float64Constant(0.5));
+ TNode<Float64T> f = Float64Floor(x);
+ TNode<Float64T> f_and_half = Float64Add(f, Float64Constant(0.5));
VARIABLE(var_result, MachineRepresentation::kFloat64);
Label return_f(this), return_f_plus_one(this), done(this);
@@ -442,7 +497,7 @@ TNode<Float64T> CodeStubAssembler::Float64RoundToEven(SloppyTNode<Float64T> x) {
GotoIf(Float64LessThan(f_and_half, x), &return_f_plus_one);
GotoIf(Float64LessThan(x, f_and_half), &return_f);
{
- Node* f_mod_2 = Float64Mod(f, Float64Constant(2.0));
+ TNode<Float64T> f_mod_2 = Float64Mod(f, Float64Constant(2.0));
Branch(Float64Equal(f_mod_2, Float64Constant(0.0)), &return_f,
&return_f_plus_one);
}
@@ -464,10 +519,10 @@ TNode<Float64T> CodeStubAssembler::Float64Trunc(SloppyTNode<Float64T> x) {
return Float64RoundTruncate(x);
}
- Node* one = Float64Constant(1.0);
- Node* zero = Float64Constant(0.0);
- Node* two_52 = Float64Constant(4503599627370496.0E0);
- Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
+ TNode<Float64T> one = Float64Constant(1.0);
+ TNode<Float64T> zero = Float64Constant(0.0);
+ TNode<Float64T> two_52 = Float64Constant(4503599627370496.0E0);
+ TNode<Float64T> minus_two_52 = Float64Constant(-4503599627370496.0E0);
VARIABLE(var_x, MachineRepresentation::kFloat64, x);
Label return_x(this), return_minus_x(this);
@@ -504,7 +559,7 @@ TNode<Float64T> CodeStubAssembler::Float64Trunc(SloppyTNode<Float64T> x) {
GotoIfNot(Float64LessThan(x, zero), &return_x);
// Round negated {x} towards -Infinity and return result negated.
- Node* minus_x = Float64Neg(x);
+ TNode<Float64T> minus_x = Float64Neg(x);
var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
GotoIfNot(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x);
var_x.Bind(Float64Sub(var_x.value(), one));
@@ -521,10 +576,10 @@ TNode<Float64T> CodeStubAssembler::Float64Trunc(SloppyTNode<Float64T> x) {
}
TNode<BoolT> CodeStubAssembler::IsValidSmi(TNode<Smi> smi) {
- if (SmiValuesAre31Bits() && kSystemPointerSize == kInt64Size) {
- // Check that the Smi value is properly sign-extended.
- TNode<IntPtrT> value = Signed(BitcastTaggedSignedToWord(smi));
- return WordEqual(value, ChangeInt32ToIntPtr(TruncateIntPtrToInt32(value)));
+ if (SmiValuesAre32Bits() && kSystemPointerSize == kInt64Size) {
+ // Check that the Smi value is zero in the lower bits.
+ TNode<IntPtrT> value = BitcastTaggedSignedToWord(smi);
+ return Word32Equal(Int32Constant(0), TruncateIntPtrToInt32(value));
}
return Int32TrueConstant();
}
@@ -542,7 +597,7 @@ TNode<Smi> CodeStubAssembler::SmiFromInt32(SloppyTNode<Int32T> value) {
TNode<BoolT> CodeStubAssembler::IsValidPositiveSmi(TNode<IntPtrT> value) {
intptr_t constant_value;
- if (ToIntPtrConstant(value, constant_value)) {
+ if (ToIntPtrConstant(value, &constant_value)) {
return (static_cast<uintptr_t>(constant_value) <=
static_cast<uintptr_t>(Smi::kMaxValue))
? Int32TrueConstant()
@@ -554,7 +609,7 @@ TNode<BoolT> CodeStubAssembler::IsValidPositiveSmi(TNode<IntPtrT> value) {
TNode<Smi> CodeStubAssembler::SmiTag(SloppyTNode<IntPtrT> value) {
int32_t constant_value;
- if (ToInt32Constant(value, constant_value) && Smi::IsValid(constant_value)) {
+ if (ToInt32Constant(value, &constant_value) && Smi::IsValid(constant_value)) {
return SmiConstant(constant_value);
}
TNode<Smi> smi =
@@ -564,7 +619,7 @@ TNode<Smi> CodeStubAssembler::SmiTag(SloppyTNode<IntPtrT> value) {
TNode<IntPtrT> CodeStubAssembler::SmiUntag(SloppyTNode<Smi> value) {
intptr_t constant_value;
- if (ToIntPtrConstant(value, constant_value)) {
+ if (ToIntPtrConstant(value, &constant_value)) {
return IntPtrConstant(constant_value >> (kSmiShiftSize + kSmiTagSize));
}
return Signed(
@@ -799,11 +854,11 @@ TNode<Number> CodeStubAssembler::SmiMul(TNode<Smi> a, TNode<Smi> b) {
Label return_result(this, &var_result);
// Both {a} and {b} are Smis. Convert them to integers and multiply.
- Node* lhs32 = SmiToInt32(a);
- Node* rhs32 = SmiToInt32(b);
- Node* pair = Int32MulWithOverflow(lhs32, rhs32);
+ TNode<Int32T> lhs32 = SmiToInt32(a);
+ TNode<Int32T> rhs32 = SmiToInt32(b);
+ auto pair = Int32MulWithOverflow(lhs32, rhs32);
- Node* overflow = Projection(1, pair);
+ TNode<BoolT> overflow = Projection<1>(pair);
// Check if the multiplication overflowed.
Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
@@ -813,8 +868,8 @@ TNode<Number> CodeStubAssembler::SmiMul(TNode<Smi> a, TNode<Smi> b) {
// If the answer is zero, we may need to return -0.0, depending on the
// input.
Label answer_zero(this), answer_not_zero(this);
- Node* answer = Projection(0, pair);
- Node* zero = Int32Constant(0);
+ TNode<Int32T> answer = Projection<0>(pair);
+ TNode<Int32T> zero = Int32Constant(0);
Branch(Word32Equal(answer, zero), &answer_zero, &answer_not_zero);
BIND(&answer_not_zero);
{
@@ -823,7 +878,7 @@ TNode<Number> CodeStubAssembler::SmiMul(TNode<Smi> a, TNode<Smi> b) {
}
BIND(&answer_zero);
{
- Node* or_result = Word32Or(lhs32, rhs32);
+ TNode<Word32T> or_result = Word32Or(lhs32, rhs32);
Label if_should_be_negative_zero(this), if_should_be_zero(this);
Branch(Int32LessThan(or_result, zero), &if_should_be_negative_zero,
&if_should_be_zero);
@@ -843,7 +898,8 @@ TNode<Number> CodeStubAssembler::SmiMul(TNode<Smi> a, TNode<Smi> b) {
{
var_lhs_float64.Bind(SmiToFloat64(a));
var_rhs_float64.Bind(SmiToFloat64(b));
- Node* value = Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
+ TNode<Float64T> value =
+ Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
var_result = AllocateHeapNumberWithValue(value);
Goto(&return_result);
}
@@ -856,12 +912,12 @@ TNode<Smi> CodeStubAssembler::TrySmiDiv(TNode<Smi> dividend, TNode<Smi> divisor,
Label* bailout) {
// Both {a} and {b} are Smis. Bailout to floating point division if {divisor}
// is zero.
- GotoIf(WordEqual(divisor, SmiConstant(0)), bailout);
+ GotoIf(TaggedEqual(divisor, SmiConstant(0)), bailout);
// Do floating point division if {dividend} is zero and {divisor} is
// negative.
Label dividend_is_zero(this), dividend_is_not_zero(this);
- Branch(WordEqual(dividend, SmiConstant(0)), &dividend_is_zero,
+ Branch(TaggedEqual(dividend, SmiConstant(0)), &dividend_is_zero,
&dividend_is_not_zero);
BIND(&dividend_is_zero);
@@ -911,6 +967,13 @@ TNode<Smi> CodeStubAssembler::SmiLexicographicCompare(TNode<Smi> x,
std::make_pair(MachineType::AnyTagged(), y)));
}
+TNode<Int32T> CodeStubAssembler::TruncateWordToInt32(SloppyTNode<WordT> value) {
+ if (Is64()) {
+ return TruncateInt64ToInt32(ReinterpretCast<Int64T>(value));
+ }
+ return ReinterpretCast<Int32T>(value);
+}
+
TNode<Int32T> CodeStubAssembler::TruncateIntPtrToInt32(
SloppyTNode<IntPtrT> value) {
if (Is64()) {
@@ -920,14 +983,18 @@ TNode<Int32T> CodeStubAssembler::TruncateIntPtrToInt32(
}
TNode<BoolT> CodeStubAssembler::TaggedIsSmi(SloppyTNode<Object> a) {
- return WordEqual(WordAnd(BitcastTaggedToWord(a), IntPtrConstant(kSmiTagMask)),
- IntPtrConstant(0));
+ STATIC_ASSERT(kSmiTagMask < kMaxUInt32);
+ return Word32Equal(Word32And(TruncateIntPtrToInt32(BitcastTaggedToWord(a)),
+ Int32Constant(kSmiTagMask)),
+ Int32Constant(0));
}
TNode<BoolT> CodeStubAssembler::TaggedIsSmi(TNode<MaybeObject> a) {
- return WordEqual(
- WordAnd(BitcastMaybeObjectToWord(a), IntPtrConstant(kSmiTagMask)),
- IntPtrConstant(0));
+ STATIC_ASSERT(kSmiTagMask < kMaxUInt32);
+ return Word32Equal(
+ Word32And(TruncateIntPtrToInt32(BitcastMaybeObjectToWord(a)),
+ Int32Constant(kSmiTagMask)),
+ Int32Constant(0));
}
TNode<BoolT> CodeStubAssembler::TaggedIsNotSmi(SloppyTNode<Object> a) {
@@ -935,21 +1002,34 @@ TNode<BoolT> CodeStubAssembler::TaggedIsNotSmi(SloppyTNode<Object> a) {
// can nonetheless use it to inspect the Smi tag. The assumption here is that
// the GC will not exchange Smis for HeapObjects or vice-versa.
TNode<IntPtrT> a_bitcast = BitcastTaggedSignedToWord(UncheckedCast<Smi>(a));
- return WordNotEqual(WordAnd(a_bitcast, IntPtrConstant(kSmiTagMask)),
- IntPtrConstant(0));
+ STATIC_ASSERT(kSmiTagMask < kMaxUInt32);
+ return Word32NotEqual(
+ Word32And(TruncateIntPtrToInt32(a_bitcast), Int32Constant(kSmiTagMask)),
+ Int32Constant(0));
}
TNode<BoolT> CodeStubAssembler::TaggedIsPositiveSmi(SloppyTNode<Object> a) {
+#if defined(V8_HOST_ARCH_32_BIT) || defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
+ return Word32Equal(
+ Word32And(
+ TruncateIntPtrToInt32(BitcastTaggedToWord(a)),
+ Uint32Constant(kSmiTagMask | static_cast<int32_t>(kSmiSignMask))),
+ Int32Constant(0));
+#else
return WordEqual(WordAnd(BitcastTaggedToWord(a),
IntPtrConstant(kSmiTagMask | kSmiSignMask)),
IntPtrConstant(0));
+#endif
}
TNode<BoolT> CodeStubAssembler::WordIsAligned(SloppyTNode<WordT> word,
size_t alignment) {
DCHECK(base::bits::IsPowerOfTwo(alignment));
- return WordEqual(IntPtrConstant(0),
- WordAnd(word, IntPtrConstant(alignment - 1)));
+ DCHECK_LE(alignment, kMaxUInt32);
+ return Word32Equal(
+ Int32Constant(0),
+ Word32And(TruncateWordToInt32(word),
+ Uint32Constant(static_cast<uint32_t>(alignment) - 1)));
}
#if DEBUG
@@ -978,18 +1058,18 @@ void CodeStubAssembler::BranchIfPrototypesHaveNoElements(
CSA_SLOW_ASSERT(this, IsMap(receiver_map));
VARIABLE(var_map, MachineRepresentation::kTagged, receiver_map);
Label loop_body(this, &var_map);
- Node* empty_fixed_array = LoadRoot(RootIndex::kEmptyFixedArray);
- Node* empty_slow_element_dictionary =
- LoadRoot(RootIndex::kEmptySlowElementDictionary);
+ TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
+ TNode<NumberDictionary> empty_slow_element_dictionary =
+ EmptySlowElementDictionaryConstant();
Goto(&loop_body);
BIND(&loop_body);
{
Node* map = var_map.value();
- Node* prototype = LoadMapPrototype(map);
+ TNode<HeapObject> prototype = LoadMapPrototype(map);
GotoIf(IsNull(prototype), definitely_no_elements);
- Node* prototype_map = LoadMap(prototype);
- TNode<Int32T> prototype_instance_type = LoadMapInstanceType(prototype_map);
+ TNode<Map> prototype_map = LoadMap(prototype);
+ TNode<Uint16T> prototype_instance_type = LoadMapInstanceType(prototype_map);
// Pessimistically assume elements if a Proxy, Special API Object,
// or JSPrimitiveWrapper wrapper is found on the prototype chain. After this
@@ -1012,25 +1092,25 @@ void CodeStubAssembler::BranchIfPrototypesHaveNoElements(
BIND(&if_notcustom);
{
- Node* prototype_elements = LoadElements(prototype);
+ TNode<FixedArrayBase> prototype_elements = LoadElements(CAST(prototype));
var_map.Bind(prototype_map);
- GotoIf(WordEqual(prototype_elements, empty_fixed_array), &loop_body);
- Branch(WordEqual(prototype_elements, empty_slow_element_dictionary),
+ GotoIf(TaggedEqual(prototype_elements, empty_fixed_array), &loop_body);
+ Branch(TaggedEqual(prototype_elements, empty_slow_element_dictionary),
&loop_body, possibly_elements);
}
}
}
-void CodeStubAssembler::BranchIfJSReceiver(Node* object, Label* if_true,
- Label* if_false) {
+void CodeStubAssembler::BranchIfJSReceiver(SloppyTNode<Object> object,
+ Label* if_true, Label* if_false) {
GotoIf(TaggedIsSmi(object), if_false);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
- Branch(IsJSReceiver(object), if_true, if_false);
+ Branch(IsJSReceiver(CAST(object)), if_true, if_false);
}
void CodeStubAssembler::GotoIfForceSlowPath(Label* if_true) {
#ifdef V8_ENABLE_FORCE_SLOW_PATH
- Node* const force_slow_path_addr =
+ TNode<ExternalReference> const force_slow_path_addr =
ExternalConstant(ExternalReference::force_slow_path(isolate()));
Node* const force_slow = Load(MachineType::Uint8(), force_slow_path_addr);
@@ -1065,7 +1145,7 @@ TNode<HeapObject> CodeStubAssembler::AllocateRaw(TNode<IntPtrT> size_in_bytes,
intptr_t size_in_bytes_constant;
bool size_in_bytes_is_constant = false;
- if (ToIntPtrConstant(size_in_bytes, size_in_bytes_constant)) {
+ if (ToIntPtrConstant(size_in_bytes, &size_in_bytes_constant)) {
size_in_bytes_is_constant = true;
CHECK(Internals::IsValidSmi(size_in_bytes_constant));
CHECK_GT(size_in_bytes_constant, 0);
@@ -1155,7 +1235,7 @@ TNode<HeapObject> CodeStubAssembler::AllocateRaw(TNode<IntPtrT> size_in_bytes,
// Store a filler and increase the address by 4.
StoreNoWriteBarrier(MachineRepresentation::kTagged, top,
- LoadRoot(RootIndex::kOnePointerFillerMap));
+ OnePointerFillerMapConstant());
address = IntPtrAdd(UncheckedCast<IntPtrT>(top), IntPtrConstant(4));
Goto(&next);
@@ -1224,7 +1304,7 @@ TNode<HeapObject> CodeStubAssembler::Allocate(TNode<IntPtrT> size_in_bytes,
!new_space || !allow_large_objects || FLAG_young_generation_large_objects;
if (!allow_large_objects) {
intptr_t size_constant;
- if (ToIntPtrConstant(size_in_bytes, size_constant)) {
+ if (ToIntPtrConstant(size_in_bytes, &size_constant)) {
CHECK_LE(size_constant, kMaxRegularHeapObjectSize);
} else {
CSA_ASSERT(this, IsRegularHeapObjectSize(size_in_bytes));
@@ -1294,12 +1374,13 @@ TNode<BoolT> CodeStubAssembler::IsRegularHeapObjectSize(TNode<IntPtrT> size) {
IntPtrConstant(kMaxRegularHeapObjectSize));
}
-void CodeStubAssembler::BranchIfToBooleanIsTrue(Node* value, Label* if_true,
+void CodeStubAssembler::BranchIfToBooleanIsTrue(SloppyTNode<Object> value,
+ Label* if_true,
Label* if_false) {
Label if_smi(this), if_notsmi(this), if_heapnumber(this, Label::kDeferred),
if_bigint(this, Label::kDeferred);
// Rule out false {value}.
- GotoIf(WordEqual(value, FalseConstant()), if_false);
+ GotoIf(TaggedEqual(value, FalseConstant()), if_false);
// Check if {value} is a Smi or a HeapObject.
Branch(TaggedIsSmi(value), &if_smi, &if_notsmi);
@@ -1312,11 +1393,13 @@ void CodeStubAssembler::BranchIfToBooleanIsTrue(Node* value, Label* if_true,
BIND(&if_notsmi);
{
+ TNode<HeapObject> value_heapobject = CAST(value);
+
// Check if {value} is the empty string.
- GotoIf(IsEmptyString(value), if_false);
+ GotoIf(IsEmptyString(value_heapobject), if_false);
// The {value} is a HeapObject, load its map.
- Node* value_map = LoadMap(value);
+ TNode<Map> value_map = LoadMap(value_heapobject);
// Only null, undefined and document.all have the undetectable bit set,
// so we can return false immediately when that bit is set.
@@ -1325,13 +1408,13 @@ void CodeStubAssembler::BranchIfToBooleanIsTrue(Node* value, Label* if_true,
// We still need to handle numbers specially, but all other {value}s
// that make it here yield true.
GotoIf(IsHeapNumberMap(value_map), &if_heapnumber);
- Branch(IsBigInt(value), &if_bigint, if_true);
+ Branch(IsBigInt(value_heapobject), &if_bigint, if_true);
BIND(&if_heapnumber);
{
// Load the floating point value of {value}.
- Node* value_value = LoadObjectField(value, HeapNumber::kValueOffset,
- MachineType::Float64());
+ Node* value_value = LoadObjectField(
+ value_heapobject, HeapNumber::kValueOffset, MachineType::Float64());
// Check if the floating point {value} is neither 0.0, -0.0 nor NaN.
Branch(Float64LessThan(Float64Constant(0.0), Float64Abs(value_value)),
@@ -1349,7 +1432,7 @@ void CodeStubAssembler::BranchIfToBooleanIsTrue(Node* value, Label* if_true,
}
Node* CodeStubAssembler::LoadFromParentFrame(int offset, MachineType type) {
- Node* frame_pointer = LoadParentFramePointer();
+ TNode<RawPtrT> frame_pointer = LoadParentFramePointer();
return Load(type, frame_pointer, IntPtrConstant(offset));
}
@@ -1382,12 +1465,12 @@ TNode<IntPtrT> CodeStubAssembler::LoadAndUntagObjectField(
LoadObjectField(object, offset, MachineType::Int32()));
} else {
return SmiToIntPtr(
- LoadObjectField(object, offset, MachineType::AnyTagged()));
+ LoadObjectField(object, offset, MachineType::TaggedSigned()));
}
}
-TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32ObjectField(Node* object,
- int offset) {
+TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32ObjectField(
+ SloppyTNode<HeapObject> object, int offset) {
if (SmiValuesAre32Bits()) {
#if V8_TARGET_LITTLE_ENDIAN
offset += 4;
@@ -1396,43 +1479,14 @@ TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32ObjectField(Node* object,
LoadObjectField(object, offset, MachineType::Int32()));
} else {
return SmiToInt32(
- LoadObjectField(object, offset, MachineType::AnyTagged()));
- }
-}
-
-TNode<IntPtrT> CodeStubAssembler::LoadAndUntagSmi(Node* base, int index) {
- if (SmiValuesAre32Bits()) {
-#if V8_TARGET_LITTLE_ENDIAN
- index += 4;
-#endif
- return ChangeInt32ToIntPtr(
- Load(MachineType::Int32(), base, IntPtrConstant(index)));
- } else {
- return SmiToIntPtr(
- Load(MachineType::AnyTagged(), base, IntPtrConstant(index)));
- }
-}
-
-void CodeStubAssembler::StoreAndTagSmi(Node* base, int offset, Node* value) {
- if (SmiValuesAre32Bits()) {
- int zero_offset = offset + 4;
- int payload_offset = offset;
-#if V8_TARGET_LITTLE_ENDIAN
- std::swap(zero_offset, payload_offset);
-#endif
- StoreNoWriteBarrier(MachineRepresentation::kWord32, base,
- IntPtrConstant(zero_offset), Int32Constant(0));
- StoreNoWriteBarrier(MachineRepresentation::kWord32, base,
- IntPtrConstant(payload_offset),
- TruncateInt64ToInt32(value));
- } else {
- StoreNoWriteBarrier(MachineRepresentation::kTaggedSigned, base,
- IntPtrConstant(offset), SmiTag(value));
+ LoadObjectField(object, offset, MachineType::TaggedSigned()));
}
}
TNode<Float64T> CodeStubAssembler::LoadHeapNumberValue(
- SloppyTNode<HeapNumber> object) {
+ SloppyTNode<HeapObject> object) {
+ CSA_ASSERT(this, Word32Or(IsHeapNumber(object), IsOddball(object)));
+ STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
return TNode<Float64T>::UncheckedCast(LoadObjectField(
object, HeapNumber::kValueOffset, MachineType::Float64()));
}
@@ -1444,6 +1498,8 @@ TNode<Map> CodeStubAssembler::GetStructMap(InstanceType instance_type) {
}
TNode<Map> CodeStubAssembler::LoadMap(SloppyTNode<HeapObject> object) {
+ // TODO(v8:9637): Do a proper LoadObjectField<Map> and remove UncheckedCast
+ // when we can avoid making Large code objects due to TNodification.
return UncheckedCast<Map>(LoadObjectField(object, HeapObject::kMapOffset,
MachineType::TaggedPointer()));
}
@@ -1472,6 +1528,34 @@ TNode<BoolT> CodeStubAssembler::TaggedDoesntHaveInstanceType(
[=]() { return DoesntHaveInstanceType(any_tagged, type); });
}
+TNode<BoolT> CodeStubAssembler::IsSpecialReceiverMap(SloppyTNode<Map> map) {
+ CSA_SLOW_ASSERT(this, IsMap(map));
+ TNode<BoolT> is_special =
+ IsSpecialReceiverInstanceType(LoadMapInstanceType(map));
+ uint32_t mask =
+ Map::HasNamedInterceptorBit::kMask | Map::IsAccessCheckNeededBit::kMask;
+ USE(mask);
+ // Interceptors or access checks imply special receiver.
+ CSA_ASSERT(this,
+ SelectConstant<BoolT>(IsSetWord32(LoadMapBitField(map), mask),
+ is_special, Int32TrueConstant()));
+ return is_special;
+}
+
+TNode<Word32T> CodeStubAssembler::IsStringWrapperElementsKind(TNode<Map> map) {
+ TNode<Int32T> kind = LoadMapElementsKind(map);
+ return Word32Or(
+ Word32Equal(kind, Int32Constant(FAST_STRING_WRAPPER_ELEMENTS)),
+ Word32Equal(kind, Int32Constant(SLOW_STRING_WRAPPER_ELEMENTS)));
+}
+
+void CodeStubAssembler::GotoIfMapHasSlowProperties(TNode<Map> map,
+ Label* if_slow) {
+ GotoIf(IsStringWrapperElementsKind(map), if_slow);
+ GotoIf(IsSpecialReceiverMap(map), if_slow);
+ GotoIf(IsDictionaryMap(map), if_slow);
+}
+
TNode<HeapObject> CodeStubAssembler::LoadFastProperties(
SloppyTNode<JSObject> object) {
CSA_SLOW_ASSERT(this, Word32BinaryNot(IsDictionaryMap(LoadMap(object))));
@@ -1503,11 +1587,12 @@ TNode<Object> CodeStubAssembler::LoadJSArgumentsObjectWithLength(
TNode<Smi> CodeStubAssembler::LoadFastJSArrayLength(
SloppyTNode<JSArray> array) {
- TNode<Object> length = LoadJSArrayLength(array);
+ TNode<Number> length = LoadJSArrayLength(array);
CSA_ASSERT(this, Word32Or(IsFastElementsKind(LoadElementsKind(array)),
- IsElementsKindInRange(LoadElementsKind(array),
- PACKED_SEALED_ELEMENTS,
- HOLEY_FROZEN_ELEMENTS)));
+ IsElementsKindInRange(
+ LoadElementsKind(array),
+ FIRST_ANY_NONEXTENSIBLE_ELEMENTS_KIND,
+ LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND)));
// JSArray length is always a positive Smi for fast arrays.
CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length));
return UncheckedCast<Smi>(length);
@@ -1532,7 +1617,7 @@ TNode<IntPtrT> CodeStubAssembler::LoadFeedbackVectorLength(
TNode<Smi> CodeStubAssembler::LoadWeakFixedArrayLength(
TNode<WeakFixedArray> array) {
- return CAST(LoadObjectField(array, WeakFixedArray::kLengthOffset));
+ return LoadObjectField<Smi>(array, WeakFixedArray::kLengthOffset);
}
TNode<IntPtrT> CodeStubAssembler::LoadAndUntagWeakFixedArrayLength(
@@ -1547,6 +1632,12 @@ TNode<Int32T> CodeStubAssembler::LoadNumberOfDescriptors(
MachineType::Int16()));
}
+TNode<Int32T> CodeStubAssembler::LoadNumberOfOwnDescriptors(TNode<Map> map) {
+ TNode<Uint32T> bit_field3 = LoadMapBitField3(map);
+ return UncheckedCast<Int32T>(
+ DecodeWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3));
+}
+
TNode<Int32T> CodeStubAssembler::LoadMapBitField(SloppyTNode<Map> map) {
CSA_SLOW_ASSERT(this, IsMap(map));
return UncheckedCast<Int32T>(
@@ -1566,13 +1657,12 @@ TNode<Uint32T> CodeStubAssembler::LoadMapBitField3(SloppyTNode<Map> map) {
}
TNode<Uint16T> CodeStubAssembler::LoadMapInstanceType(SloppyTNode<Map> map) {
- return UncheckedCast<Uint16T>(
- LoadObjectField(map, Map::kInstanceTypeOffset, MachineType::Uint16()));
+ return LoadObjectField<Uint16T>(map, Map::kInstanceTypeOffset);
}
TNode<Int32T> CodeStubAssembler::LoadMapElementsKind(SloppyTNode<Map> map) {
CSA_SLOW_ASSERT(this, IsMap(map));
- Node* bit_field2 = LoadMapBitField2(map);
+ TNode<Int32T> bit_field2 = LoadMapBitField2(map);
return Signed(DecodeWord32<Map::ElementsKindBits>(bit_field2));
}
@@ -1584,12 +1674,12 @@ TNode<Int32T> CodeStubAssembler::LoadElementsKind(
TNode<DescriptorArray> CodeStubAssembler::LoadMapDescriptors(
SloppyTNode<Map> map) {
CSA_SLOW_ASSERT(this, IsMap(map));
- return CAST(LoadObjectField(map, Map::kInstanceDescriptorsOffset));
+ return LoadObjectField<DescriptorArray>(map, Map::kInstanceDescriptorsOffset);
}
TNode<HeapObject> CodeStubAssembler::LoadMapPrototype(SloppyTNode<Map> map) {
CSA_SLOW_ASSERT(this, IsMap(map));
- return CAST(LoadObjectField(map, Map::kPrototypeOffset));
+ return LoadObjectField<HeapObject>(map, Map::kPrototypeOffset);
}
TNode<PrototypeInfo> CodeStubAssembler::LoadMapPrototypeInfo(
@@ -1604,8 +1694,8 @@ TNode<PrototypeInfo> CodeStubAssembler::LoadMapPrototypeInfo(
&prototype_info);
BIND(&if_strong_heap_object);
- GotoIfNot(WordEqual(LoadMap(CAST(prototype_info.value())),
- LoadRoot(RootIndex::kPrototypeInfoMap)),
+ GotoIfNot(TaggedEqual(LoadMap(CAST(prototype_info.value())),
+ PrototypeInfoMapConstant()),
if_no_proto_info);
return CAST(prototype_info.value());
}
@@ -1647,7 +1737,7 @@ TNode<Object> CodeStubAssembler::LoadMapConstructor(SloppyTNode<Map> map) {
BIND(&loop);
{
GotoIf(TaggedIsSmi(result.value()), &done);
- Node* is_map_type =
+ TNode<BoolT> is_map_type =
InstanceTypeEqual(LoadInstanceType(CAST(result.value())), MAP_TYPE);
GotoIfNot(is_map_type, &done);
result = LoadObjectField(CAST(result.value()),
@@ -1658,9 +1748,9 @@ TNode<Object> CodeStubAssembler::LoadMapConstructor(SloppyTNode<Map> map) {
return result.value();
}
-Node* CodeStubAssembler::LoadMapEnumLength(SloppyTNode<Map> map) {
+TNode<WordT> CodeStubAssembler::LoadMapEnumLength(SloppyTNode<Map> map) {
CSA_SLOW_ASSERT(this, IsMap(map));
- Node* bit_field3 = LoadMapBitField3(map);
+ TNode<Uint32T> bit_field3 = LoadMapBitField3(map);
return DecodeWordFromWord32<Map::EnumLengthBits>(bit_field3);
}
@@ -1697,7 +1787,7 @@ TNode<IntPtrT> CodeStubAssembler::LoadJSReceiverIdentityHash(
TNode<HeapObject> properties =
TNode<HeapObject>::UncheckedCast(properties_or_hash);
- TNode<Int32T> properties_instance_type = LoadInstanceType(properties);
+ TNode<Uint16T> properties_instance_type = LoadInstanceType(properties);
GotoIf(InstanceTypeEqual(properties_instance_type, PROPERTY_ARRAY_TYPE),
&if_property_array);
@@ -1818,9 +1908,10 @@ void CodeStubAssembler::DispatchMaybeObject(TNode<MaybeObject> maybe_object,
}
TNode<BoolT> CodeStubAssembler::IsStrong(TNode<MaybeObject> value) {
- return WordEqual(WordAnd(BitcastMaybeObjectToWord(value),
- IntPtrConstant(kHeapObjectTagMask)),
- IntPtrConstant(kHeapObjectTag));
+ return Word32Equal(
+ Word32And(TruncateIntPtrToInt32(BitcastMaybeObjectToWord(value)),
+ Int32Constant(kHeapObjectTagMask)),
+ Int32Constant(kHeapObjectTag));
}
TNode<HeapObject> CodeStubAssembler::GetHeapObjectIfStrong(
@@ -1862,22 +1953,41 @@ TNode<HeapObject> CodeStubAssembler::GetHeapObjectAssumeWeak(
TNode<BoolT> CodeStubAssembler::IsWeakReferenceTo(TNode<MaybeObject> object,
TNode<Object> value) {
+#if defined(V8_HOST_ARCH_32_BIT) || defined(V8_COMPRESS_POINTERS)
+ STATIC_ASSERT(kTaggedSize == kInt32Size);
+ return Word32Equal(
+ Word32And(TruncateWordToInt32(BitcastMaybeObjectToWord(object)),
+ Uint32Constant(
+ static_cast<uint32_t>(~kWeakHeapObjectMask & kMaxUInt32))),
+ TruncateWordToInt32(BitcastTaggedToWord(value)));
+#else
return WordEqual(WordAnd(BitcastMaybeObjectToWord(object),
IntPtrConstant(~kWeakHeapObjectMask)),
BitcastTaggedToWord(value));
+
+#endif
}
TNode<BoolT> CodeStubAssembler::IsStrongReferenceTo(TNode<MaybeObject> object,
TNode<Object> value) {
- return WordEqual(BitcastMaybeObjectToWord(object),
- BitcastTaggedToWord(value));
+ return TaggedEqual(BitcastWordToTagged(BitcastMaybeObjectToWord(object)),
+ value);
}
TNode<BoolT> CodeStubAssembler::IsNotWeakReferenceTo(TNode<MaybeObject> object,
TNode<Object> value) {
+#if defined(V8_HOST_ARCH_32_BIT) || defined(V8_COMPRESS_POINTERS)
+ return Word32NotEqual(
+ Word32And(TruncateWordToInt32(BitcastMaybeObjectToWord(object)),
+ Uint32Constant(
+ static_cast<uint32_t>(~kWeakHeapObjectMask & kMaxUInt32))),
+ TruncateWordToInt32(BitcastTaggedToWord(value)));
+#else
return WordNotEqual(WordAnd(BitcastMaybeObjectToWord(object),
IntPtrConstant(~kWeakHeapObjectMask)),
BitcastTaggedToWord(value));
+
+#endif
}
TNode<MaybeObject> CodeStubAssembler::MakeWeak(TNode<HeapObject> value) {
@@ -2019,7 +2129,7 @@ TNode<RawPtrT> CodeStubAssembler::LoadJSTypedArrayBackingStore(
Node* external_pointer =
LoadObjectField(typed_array, JSTypedArray::kExternalPointerOffset,
MachineType::Pointer());
- Node* base_pointer =
+ TNode<Object> base_pointer =
LoadObjectField(typed_array, JSTypedArray::kBasePointerOffset);
return UncheckedCast<RawPtrT>(
IntPtrAdd(external_pointer, BitcastTaggedToWord(base_pointer)));
@@ -2062,12 +2172,12 @@ TNode<BigInt> CodeStubAssembler::BigIntFromInt32Pair(TNode<IntPtrT> low,
Label high_zero(this), negative(this), allocate_one_digit(this),
allocate_two_digits(this), if_zero(this), done(this);
- GotoIf(WordEqual(var_high.value(), IntPtrConstant(0)), &high_zero);
+ GotoIf(IntPtrEqual(var_high.value(), IntPtrConstant(0)), &high_zero);
Branch(IntPtrLessThan(var_high.value(), IntPtrConstant(0)), &negative,
&allocate_two_digits);
BIND(&high_zero);
- Branch(WordEqual(var_low.value(), IntPtrConstant(0)), &if_zero,
+ Branch(IntPtrEqual(var_low.value(), IntPtrConstant(0)), &if_zero,
&allocate_one_digit);
BIND(&negative);
@@ -2078,7 +2188,7 @@ TNode<BigInt> CodeStubAssembler::BigIntFromInt32Pair(TNode<IntPtrT> low,
// of the carry bit (which is 1 iff low != 0).
var_high = IntPtrSub(IntPtrConstant(0), var_high.value());
Label carry(this), no_carry(this);
- Branch(WordEqual(var_low.value(), IntPtrConstant(0)), &no_carry, &carry);
+ Branch(IntPtrEqual(var_low.value(), IntPtrConstant(0)), &no_carry, &carry);
BIND(&carry);
var_high = IntPtrSub(var_high.value(), IntPtrConstant(1));
Goto(&no_carry);
@@ -2086,8 +2196,8 @@ TNode<BigInt> CodeStubAssembler::BigIntFromInt32Pair(TNode<IntPtrT> low,
var_low = IntPtrSub(IntPtrConstant(0), var_low.value());
// var_high was non-zero going into this block, but subtracting the
// carry bit from it could bring us back onto the "one digit" path.
- Branch(WordEqual(var_high.value(), IntPtrConstant(0)), &allocate_one_digit,
- &allocate_two_digits);
+ Branch(IntPtrEqual(var_high.value(), IntPtrConstant(0)),
+ &allocate_one_digit, &allocate_two_digits);
}
BIND(&allocate_one_digit);
@@ -2123,7 +2233,7 @@ TNode<BigInt> CodeStubAssembler::BigIntFromInt64(TNode<IntPtrT> value) {
DCHECK(Is64());
TVARIABLE(BigInt, var_result);
Label done(this), if_positive(this), if_negative(this), if_zero(this);
- GotoIf(WordEqual(value, IntPtrConstant(0)), &if_zero);
+ GotoIf(IntPtrEqual(value, IntPtrConstant(0)), &if_zero);
var_result = AllocateRawBigInt(IntPtrConstant(1));
Branch(IntPtrGreaterThan(value, IntPtrConstant(0)), &if_positive,
&if_negative);
@@ -2192,14 +2302,14 @@ TNode<BigInt> CodeStubAssembler::BigIntFromUint32Pair(TNode<UintPtrT> low,
TVARIABLE(BigInt, var_result);
Label high_zero(this), if_zero(this), done(this);
- GotoIf(WordEqual(high, IntPtrConstant(0)), &high_zero);
+ GotoIf(IntPtrEqual(high, IntPtrConstant(0)), &high_zero);
var_result = AllocateBigInt(IntPtrConstant(2));
StoreBigIntDigit(var_result.value(), 0, low);
StoreBigIntDigit(var_result.value(), 1, high);
Goto(&done);
BIND(&high_zero);
- GotoIf(WordEqual(low, IntPtrConstant(0)), &if_zero);
+ GotoIf(IntPtrEqual(low, IntPtrConstant(0)), &if_zero);
var_result = AllocateBigInt(IntPtrConstant(1));
StoreBigIntDigit(var_result.value(), 0, low);
Goto(&done);
@@ -2216,7 +2326,7 @@ TNode<BigInt> CodeStubAssembler::BigIntFromUint64(TNode<UintPtrT> value) {
DCHECK(Is64());
TVARIABLE(BigInt, var_result);
Label done(this), if_zero(this);
- GotoIf(WordEqual(value, IntPtrConstant(0)), &if_zero);
+ GotoIf(IntPtrEqual(value, IntPtrConstant(0)), &if_zero);
var_result = AllocateBigInt(IntPtrConstant(1));
StoreBigIntDigit(var_result.value(), 0, value);
Goto(&done);
@@ -2350,8 +2460,8 @@ TNode<MaybeObject> CodeStubAssembler::LoadFeedbackVectorSlot(
CSA_SLOW_ASSERT(this, MatchesParameterMode(slot_index_node, parameter_mode));
int32_t header_size =
FeedbackVector::kFeedbackSlotsOffset + additional_offset - kHeapObjectTag;
- Node* offset = ElementOffsetFromIndex(slot_index_node, HOLEY_ELEMENTS,
- parameter_mode, header_size);
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(
+ slot_index_node, HOLEY_ELEMENTS, parameter_mode, header_size);
CSA_SLOW_ASSERT(
this, IsOffsetInBounds(offset, LoadFeedbackVectorLength(CAST(object)),
FeedbackVector::kHeaderSize));
@@ -2371,14 +2481,14 @@ TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32ArrayElement(
#endif
int32_t header_size = array_header_size + additional_offset - kHeapObjectTag +
endian_correction;
- Node* offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS,
- parameter_mode, header_size);
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS,
+ parameter_mode, header_size);
CSA_ASSERT(this, IsOffsetInBounds(offset, LoadArrayLength(object),
array_header_size + endian_correction));
if (SmiValuesAre32Bits()) {
return UncheckedCast<Int32T>(Load(MachineType::Int32(), object, offset));
} else {
- return SmiToInt32(Load(MachineType::AnyTagged(), object, offset));
+ return SmiToInt32(Load(MachineType::TaggedSigned(), object, offset));
}
}
@@ -2422,20 +2532,21 @@ TNode<Object> CodeStubAssembler::LoadFixedArrayBaseElementAsTagged(
Label done(this), if_packed(this), if_holey(this), if_packed_double(this),
if_holey_double(this), if_dictionary(this, Label::kDeferred);
- int32_t kinds[] = {// Handled by if_packed.
- PACKED_SMI_ELEMENTS, PACKED_ELEMENTS,
- PACKED_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS,
- // Handled by if_holey.
- HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS, HOLEY_SEALED_ELEMENTS,
- HOLEY_FROZEN_ELEMENTS,
- // Handled by if_packed_double.
- PACKED_DOUBLE_ELEMENTS,
- // Handled by if_holey_double.
- HOLEY_DOUBLE_ELEMENTS};
+ int32_t kinds[] = {
+ // Handled by if_packed.
+ PACKED_SMI_ELEMENTS, PACKED_ELEMENTS, PACKED_NONEXTENSIBLE_ELEMENTS,
+ PACKED_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS,
+ // Handled by if_holey.
+ HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS, HOLEY_NONEXTENSIBLE_ELEMENTS,
+ HOLEY_SEALED_ELEMENTS, HOLEY_FROZEN_ELEMENTS,
+ // Handled by if_packed_double.
+ PACKED_DOUBLE_ELEMENTS,
+ // Handled by if_holey_double.
+ HOLEY_DOUBLE_ELEMENTS};
Label* labels[] = {// PACKED_{SMI,}_ELEMENTS
- &if_packed, &if_packed, &if_packed, &if_packed,
+ &if_packed, &if_packed, &if_packed, &if_packed, &if_packed,
// HOLEY_{SMI,}_ELEMENTS
- &if_holey, &if_holey, &if_holey, &if_holey,
+ &if_holey, &if_holey, &if_holey, &if_holey, &if_holey,
// PACKED_DOUBLE_ELEMENTS
&if_packed_double,
// HOLEY_DOUBLE_ELEMENTS
@@ -2451,7 +2562,7 @@ TNode<Object> CodeStubAssembler::LoadFixedArrayBaseElementAsTagged(
BIND(&if_holey);
{
var_result = LoadFixedArrayElement(CAST(elements), index);
- Branch(WordEqual(var_result.value(), TheHoleConstant()), if_hole, &done);
+ Branch(TaggedEqual(var_result.value(), TheHoleConstant()), if_hole, &done);
}
BIND(&if_packed_double);
@@ -2489,11 +2600,11 @@ TNode<Float64T> CodeStubAssembler::LoadDoubleWithHoleCheck(
// compiler is able to fold addition of already complex |offset| with
// |kIeeeDoubleExponentWordOffset| into one addressing mode.
if (Is64()) {
- Node* element = Load(MachineType::Uint64(), base, offset);
+ TNode<Uint64T> element = Load<Uint64T>(base, offset);
GotoIf(Word64Equal(element, Int64Constant(kHoleNanInt64)), if_hole);
} else {
- Node* element_upper = Load(
- MachineType::Uint32(), base,
+ TNode<Uint32T> element_upper = Load<Uint32T>(
+ base,
IntPtrAdd(offset, IntPtrConstant(kIeeeDoubleExponentWordOffset)));
GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)),
if_hole);
@@ -2515,15 +2626,15 @@ TNode<Object> CodeStubAssembler::LoadContextElement(
TNode<Object> CodeStubAssembler::LoadContextElement(
SloppyTNode<Context> context, SloppyTNode<IntPtrT> slot_index) {
- Node* offset = ElementOffsetFromIndex(
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(
slot_index, PACKED_ELEMENTS, INTPTR_PARAMETERS, Context::SlotOffset(0));
return UncheckedCast<Object>(Load(MachineType::AnyTagged(), context, offset));
}
TNode<Object> CodeStubAssembler::LoadContextElement(TNode<Context> context,
TNode<Smi> slot_index) {
- Node* offset = ElementOffsetFromIndex(slot_index, PACKED_ELEMENTS,
- SMI_PARAMETERS, Context::SlotOffset(0));
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(
+ slot_index, PACKED_ELEMENTS, SMI_PARAMETERS, Context::SlotOffset(0));
return UncheckedCast<Object>(Load(MachineType::AnyTagged(), context, offset));
}
@@ -2537,8 +2648,8 @@ void CodeStubAssembler::StoreContextElement(SloppyTNode<Context> context,
void CodeStubAssembler::StoreContextElement(SloppyTNode<Context> context,
SloppyTNode<IntPtrT> slot_index,
SloppyTNode<Object> value) {
- Node* offset = IntPtrAdd(TimesTaggedSize(slot_index),
- IntPtrConstant(Context::SlotOffset(0)));
+ TNode<IntPtrT> offset = IntPtrAdd(TimesTaggedSize(slot_index),
+ IntPtrConstant(Context::SlotOffset(0)));
Store(context, offset, value);
}
@@ -2549,15 +2660,15 @@ void CodeStubAssembler::StoreContextElementNoWriteBarrier(
IntPtrConstant(offset), value);
}
-TNode<Context> CodeStubAssembler::LoadNativeContext(
+TNode<NativeContext> CodeStubAssembler::LoadNativeContext(
SloppyTNode<Context> context) {
- return UncheckedCast<Context>(
+ return UncheckedCast<NativeContext>(
LoadContextElement(context, Context::NATIVE_CONTEXT_INDEX));
}
TNode<Context> CodeStubAssembler::LoadModuleContext(
SloppyTNode<Context> context) {
- Node* module_map = LoadRoot(RootIndex::kModuleContextMap);
+ TNode<Map> module_map = ModuleContextMapConstant();
Variable cur_context(this, MachineRepresentation::kTaggedPointer);
cur_context.Bind(context);
@@ -2571,7 +2682,8 @@ TNode<Context> CodeStubAssembler::LoadModuleContext(
BIND(&context_search);
{
CSA_ASSERT(this, Word32BinaryNot(IsNativeContext(cur_context.value())));
- GotoIf(WordEqual(LoadMap(cur_context.value()), module_map), &context_found);
+ GotoIf(TaggedEqual(LoadMap(cur_context.value()), module_map),
+ &context_found);
cur_context.Bind(
LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX));
@@ -2583,17 +2695,16 @@ TNode<Context> CodeStubAssembler::LoadModuleContext(
}
TNode<Map> CodeStubAssembler::LoadJSArrayElementsMap(
- SloppyTNode<Int32T> kind, SloppyTNode<Context> native_context) {
+ SloppyTNode<Int32T> kind, SloppyTNode<NativeContext> native_context) {
CSA_ASSERT(this, IsFastElementsKind(kind));
- CSA_ASSERT(this, IsNativeContext(native_context));
- Node* offset = IntPtrAdd(IntPtrConstant(Context::FIRST_JS_ARRAY_MAP_SLOT),
- ChangeInt32ToIntPtr(kind));
+ TNode<IntPtrT> offset =
+ IntPtrAdd(IntPtrConstant(Context::FIRST_JS_ARRAY_MAP_SLOT),
+ ChangeInt32ToIntPtr(kind));
return UncheckedCast<Map>(LoadContextElement(native_context, offset));
}
TNode<Map> CodeStubAssembler::LoadJSArrayElementsMap(
- ElementsKind kind, SloppyTNode<Context> native_context) {
- CSA_ASSERT(this, IsNativeContext(native_context));
+ ElementsKind kind, SloppyTNode<NativeContext> native_context) {
return UncheckedCast<Map>(
LoadContextElement(native_context, Context::ArrayMapIndex(kind)));
}
@@ -2601,7 +2712,8 @@ TNode<Map> CodeStubAssembler::LoadJSArrayElementsMap(
TNode<BoolT> CodeStubAssembler::IsGeneratorFunction(
TNode<JSFunction> function) {
TNode<SharedFunctionInfo> const shared_function_info =
- CAST(LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset));
+ LoadObjectField<SharedFunctionInfo>(
+ function, JSFunction::kSharedFunctionInfoOffset);
TNode<Uint32T> const function_kind =
DecodeWord32<SharedFunctionInfo::FunctionKindBits>(LoadObjectField(
@@ -2646,22 +2758,20 @@ void CodeStubAssembler::GotoIfPrototypeRequiresRuntimeLookup(
runtime);
}
-Node* CodeStubAssembler::LoadJSFunctionPrototype(Node* function,
+Node* CodeStubAssembler::LoadJSFunctionPrototype(TNode<JSFunction> function,
Label* if_bailout) {
- CSA_ASSERT(this, TaggedIsNotSmi(function));
- CSA_ASSERT(this, IsJSFunction(function));
CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(function)));
CSA_ASSERT(this, IsClearWord32<Map::HasNonInstancePrototypeBit>(
LoadMapBitField(LoadMap(function))));
- Node* proto_or_map =
- LoadObjectField(function, JSFunction::kPrototypeOrInitialMapOffset);
+ TNode<HeapObject> proto_or_map = LoadObjectField<HeapObject>(
+ function, JSFunction::kPrototypeOrInitialMapOffset);
GotoIf(IsTheHole(proto_or_map), if_bailout);
- VARIABLE(var_result, MachineRepresentation::kTagged, proto_or_map);
+ TVARIABLE(HeapObject, var_result, proto_or_map);
Label done(this, &var_result);
GotoIfNot(IsMap(proto_or_map), &done);
- var_result.Bind(LoadMapPrototype(proto_or_map));
+ var_result = LoadMapPrototype(CAST(proto_or_map));
Goto(&done);
BIND(&done);
@@ -2670,15 +2780,15 @@ Node* CodeStubAssembler::LoadJSFunctionPrototype(Node* function,
TNode<BytecodeArray> CodeStubAssembler::LoadSharedFunctionInfoBytecodeArray(
SloppyTNode<SharedFunctionInfo> shared) {
- Node* function_data =
+ TNode<Object> function_data =
LoadObjectField(shared, SharedFunctionInfo::kFunctionDataOffset);
VARIABLE(var_result, MachineRepresentation::kTagged, function_data);
Label done(this, &var_result);
- GotoIfNot(HasInstanceType(function_data, INTERPRETER_DATA_TYPE), &done);
- Node* bytecode_array =
- LoadObjectField(function_data, InterpreterData::kBytecodeArrayOffset);
+ GotoIfNot(HasInstanceType(CAST(function_data), INTERPRETER_DATA_TYPE), &done);
+ TNode<Object> bytecode_array = LoadObjectField(
+ CAST(function_data), InterpreterData::kBytecodeArrayOffset);
var_result.Bind(bytecode_array);
Goto(&done);
@@ -2699,12 +2809,6 @@ void CodeStubAssembler::StoreHeapNumberValue(SloppyTNode<HeapNumber> object,
MachineRepresentation::kFloat64);
}
-void CodeStubAssembler::StoreMutableHeapNumberValue(
- SloppyTNode<MutableHeapNumber> object, SloppyTNode<Float64T> value) {
- StoreObjectFieldNoWriteBarrier(object, MutableHeapNumber::kValueOffset, value,
- MachineRepresentation::kFloat64);
-}
-
void CodeStubAssembler::StoreObjectField(Node* object, int offset,
Node* value) {
DCHECK_NE(HeapObject::kMapOffset, offset); // Use StoreMap instead.
@@ -2716,7 +2820,7 @@ void CodeStubAssembler::StoreObjectField(Node* object, int offset,
void CodeStubAssembler::StoreObjectField(Node* object, Node* offset,
Node* value) {
int const_offset;
- if (ToInt32Constant(offset, const_offset)) {
+ if (ToInt32Constant(offset, &const_offset)) {
StoreObjectField(object, const_offset, value);
} else {
Store(object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)), value);
@@ -2744,7 +2848,7 @@ void CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
Node* object, SloppyTNode<IntPtrT> offset, Node* value,
MachineRepresentation rep) {
int const_offset;
- if (ToInt32Constant(offset, const_offset)) {
+ if (ToInt32Constant(offset, &const_offset)) {
return StoreObjectFieldNoWriteBarrier(object, const_offset, value, rep);
}
StoreNoWriteBarrier(rep, object,
@@ -2776,16 +2880,6 @@ void CodeStubAssembler::StoreObjectFieldRoot(Node* object, int offset,
}
}
-void CodeStubAssembler::StoreJSArrayLength(TNode<JSArray> array,
- TNode<Smi> length) {
- StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
-}
-
-void CodeStubAssembler::StoreElements(TNode<Object> object,
- TNode<FixedArrayBase> elements) {
- StoreObjectField(object, JSObject::kElementsOffset, elements);
-}
-
void CodeStubAssembler::StoreFixedArrayOrPropertyArrayElement(
Node* object, Node* index_node, Node* value, WriteBarrierMode barrier_mode,
int additional_offset, ParameterMode parameter_mode) {
@@ -2801,8 +2895,8 @@ void CodeStubAssembler::StoreFixedArrayOrPropertyArrayElement(
static_cast<int>(PropertyArray::kHeaderSize));
int header_size =
FixedArray::kHeaderSize + additional_offset - kHeapObjectTag;
- Node* offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS,
- parameter_mode, header_size);
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS,
+ parameter_mode, header_size);
STATIC_ASSERT(static_cast<int>(FixedArrayBase::kLengthOffset) ==
static_cast<int>(WeakFixedArray::kLengthOffset));
STATIC_ASSERT(static_cast<int>(FixedArrayBase::kLengthOffset) ==
@@ -2846,7 +2940,7 @@ void CodeStubAssembler::StoreFixedDoubleArrayElement(
if (NeedsBoundsCheck(check_bounds)) {
FixedArrayBoundsCheck(object, index_node, 0, parameter_mode);
}
- Node* offset =
+ TNode<IntPtrT> offset =
ElementOffsetFromIndex(index_node, PACKED_DOUBLE_ELEMENTS, parameter_mode,
FixedArray::kHeaderSize - kHeapObjectTag);
MachineRepresentation rep = MachineRepresentation::kFloat64;
@@ -2869,8 +2963,8 @@ void CodeStubAssembler::StoreFeedbackVectorSlot(Node* object,
barrier_mode == UPDATE_WRITE_BARRIER);
int header_size =
FeedbackVector::kFeedbackSlotsOffset + additional_offset - kHeapObjectTag;
- Node* offset = ElementOffsetFromIndex(slot_index_node, HOLEY_ELEMENTS,
- parameter_mode, header_size);
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(
+ slot_index_node, HOLEY_ELEMENTS, parameter_mode, header_size);
// Check that slot_index_node <= object.length.
CSA_ASSERT(this,
IsOffsetInBounds(offset, LoadFeedbackVectorLength(CAST(object)),
@@ -2899,8 +2993,7 @@ void CodeStubAssembler::EnsureArrayLengthWritable(TNode<Map> map,
#ifdef DEBUG
TNode<Name> maybe_length =
LoadKeyByDescriptorEntry(descriptors, length_index);
- CSA_ASSERT(this,
- WordEqual(maybe_length, LoadRoot(RootIndex::klength_string)));
+ CSA_ASSERT(this, TaggedEqual(maybe_length, LengthStringConstant()));
#endif
TNode<Uint32T> details =
@@ -2988,7 +3081,7 @@ TNode<Smi> CodeStubAssembler::BuildAppendJSArray(ElementsKind kind,
{
TNode<Smi> length = ParameterToTagged(var_length.value(), mode);
var_tagged_length = length;
- Node* diff = SmiSub(length, LoadFastJSArrayLength(array));
+ TNode<Smi> diff = SmiSub(length, LoadFastJSArrayLength(array));
StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
*arg_index = IntPtrAdd(arg_index->value(), SmiUntag(diff));
Goto(bailout);
@@ -3033,13 +3126,13 @@ void CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array,
var_length.value(), value);
Increment(&var_length, 1, mode);
- Node* length = ParameterToTagged(var_length.value(), mode);
+ TNode<Smi> length = ParameterToTagged(var_length.value(), mode);
StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
}
Node* CodeStubAssembler::AllocateCellWithValue(Node* value,
WriteBarrierMode mode) {
- Node* result = Allocate(Cell::kSize, kNone);
+ TNode<HeapObject> result = Allocate(Cell::kSize, kNone);
StoreMapNoWriteBarrier(result, RootIndex::kCellMap);
StoreCellValue(result, value, mode);
return result;
@@ -3063,7 +3156,7 @@ void CodeStubAssembler::StoreCellValue(Node* cell, Node* value,
}
TNode<HeapNumber> CodeStubAssembler::AllocateHeapNumber() {
- Node* result = Allocate(HeapNumber::kSize, kNone);
+ TNode<HeapObject> result = Allocate(HeapNumber::kSize, kNone);
RootIndex heap_map_index = RootIndex::kHeapNumberMap;
StoreMapNoWriteBarrier(result, heap_map_index);
return UncheckedCast<HeapNumber>(result);
@@ -3076,24 +3169,19 @@ TNode<HeapNumber> CodeStubAssembler::AllocateHeapNumberWithValue(
return result;
}
-TNode<MutableHeapNumber> CodeStubAssembler::AllocateMutableHeapNumber() {
- Node* result = Allocate(MutableHeapNumber::kSize, kNone);
- RootIndex heap_map_index = RootIndex::kMutableHeapNumberMap;
- StoreMapNoWriteBarrier(result, heap_map_index);
- return UncheckedCast<MutableHeapNumber>(result);
-}
-
TNode<Object> CodeStubAssembler::CloneIfMutablePrimitive(TNode<Object> object) {
TVARIABLE(Object, result, object);
Label done(this);
GotoIf(TaggedIsSmi(object), &done);
- GotoIfNot(IsMutableHeapNumber(UncheckedCast<HeapObject>(object)), &done);
+ // TODO(leszeks): Read the field descriptor to decide if this heap number is
+ // mutable or not.
+ GotoIfNot(IsHeapNumber(UncheckedCast<HeapObject>(object)), &done);
{
// Mutable heap number found --- allocate a clone.
TNode<Float64T> value =
LoadHeapNumberValue(UncheckedCast<HeapNumber>(object));
- result = AllocateMutableHeapNumberWithValue(value);
+ result = AllocateHeapNumberWithValue(value);
Goto(&done);
}
@@ -3101,13 +3189,6 @@ TNode<Object> CodeStubAssembler::CloneIfMutablePrimitive(TNode<Object> object) {
return result.value();
}
-TNode<MutableHeapNumber> CodeStubAssembler::AllocateMutableHeapNumberWithValue(
- SloppyTNode<Float64T> value) {
- TNode<MutableHeapNumber> result = AllocateMutableHeapNumber();
- StoreMutableHeapNumberValue(result, value);
- return result;
-}
-
TNode<BigInt> CodeStubAssembler::AllocateBigInt(TNode<IntPtrT> length) {
TNode<BigInt> result = AllocateRawBigInt(length);
StoreBigIntBitfield(result,
@@ -3120,7 +3201,7 @@ TNode<BigInt> CodeStubAssembler::AllocateRawBigInt(TNode<IntPtrT> length) {
TNode<IntPtrT> size =
IntPtrAdd(IntPtrConstant(BigInt::kHeaderSize),
Signed(WordShl(length, kSystemPointerSizeLog2)));
- Node* raw_result = Allocate(size, kAllowLargeObjectAllocation);
+ TNode<HeapObject> raw_result = Allocate(size, kAllowLargeObjectAllocation);
StoreMapNoWriteBarrier(raw_result, RootIndex::kBigIntMap);
if (FIELD_SIZE(BigInt::kOptionalPaddingOffset) != 0) {
DCHECK_EQ(4, FIELD_SIZE(BigInt::kOptionalPaddingOffset));
@@ -3194,7 +3275,7 @@ TNode<ByteArray> CodeStubAssembler::AllocateByteArray(TNode<UintPtrT> length,
if_notsizeissmall(this, Label::kDeferred), if_join(this);
GotoIf(WordEqual(length, UintPtrConstant(0)), &if_lengthiszero);
- Node* raw_size =
+ TNode<IntPtrT> raw_size =
GetArrayAllocationSize(Signed(length), UINT8_ELEMENTS, INTPTR_PARAMETERS,
ByteArray::kHeaderSize + kObjectAlignmentMask);
TNode<WordT> size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask));
@@ -3204,7 +3285,7 @@ TNode<ByteArray> CodeStubAssembler::AllocateByteArray(TNode<UintPtrT> length,
BIND(&if_sizeissmall);
{
// Just allocate the ByteArray in new space.
- TNode<Object> result =
+ TNode<HeapObject> result =
AllocateInNewSpace(UncheckedCast<IntPtrT>(size), flags);
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kByteArrayMap));
StoreMapNoWriteBarrier(result, RootIndex::kByteArrayMap);
@@ -3217,15 +3298,16 @@ TNode<ByteArray> CodeStubAssembler::AllocateByteArray(TNode<UintPtrT> length,
BIND(&if_notsizeissmall);
{
// We might need to allocate in large object space, go to the runtime.
- Node* result = CallRuntime(Runtime::kAllocateByteArray, NoContextConstant(),
- ChangeUintPtrToTagged(length));
+ TNode<Object> result =
+ CallRuntime(Runtime::kAllocateByteArray, NoContextConstant(),
+ ChangeUintPtrToTagged(length));
var_result.Bind(result);
Goto(&if_join);
}
BIND(&if_lengthiszero);
{
- var_result.Bind(LoadRoot(RootIndex::kEmptyByteArray));
+ var_result.Bind(EmptyByteArrayConstant());
Goto(&if_join);
}
@@ -3237,9 +3319,9 @@ TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
uint32_t length, AllocationFlags flags) {
Comment("AllocateSeqOneByteString");
if (length == 0) {
- return CAST(LoadRoot(RootIndex::kempty_string));
+ return EmptyStringConstant();
}
- Node* result = Allocate(SeqOneByteString::SizeFor(length), flags);
+ TNode<HeapObject> result = Allocate(SeqOneByteString::SizeFor(length), flags);
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kOneByteStringMap));
StoreMapNoWriteBarrier(result, RootIndex::kOneByteStringMap);
StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset,
@@ -3253,14 +3335,13 @@ TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
TNode<BoolT> CodeStubAssembler::IsZeroOrContext(SloppyTNode<Object> object) {
return Select<BoolT>(
- WordEqual(object, SmiConstant(0)), [=] { return Int32TrueConstant(); },
+ TaggedEqual(object, SmiConstant(0)), [=] { return Int32TrueConstant(); },
[=] { return IsContext(CAST(object)); });
}
TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
- Node* context, TNode<Uint32T> length, AllocationFlags flags) {
+ TNode<Uint32T> length, AllocationFlags flags) {
Comment("AllocateSeqOneByteString");
- CSA_SLOW_ASSERT(this, IsZeroOrContext(context));
VARIABLE(var_result, MachineRepresentation::kTagged);
// Compute the SeqOneByteString size and check if it fits into new space.
@@ -3268,7 +3349,7 @@ TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
if_notsizeissmall(this, Label::kDeferred), if_join(this);
GotoIf(Word32Equal(length, Uint32Constant(0)), &if_lengthiszero);
- Node* raw_size = GetArrayAllocationSize(
+ TNode<IntPtrT> raw_size = GetArrayAllocationSize(
Signed(ChangeUint32ToWord(length)), UINT8_ELEMENTS, INTPTR_PARAMETERS,
SeqOneByteString::kHeaderSize + kObjectAlignmentMask);
TNode<WordT> size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask));
@@ -3278,7 +3359,7 @@ TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
BIND(&if_sizeissmall);
{
// Just allocate the SeqOneByteString in new space.
- TNode<Object> result =
+ TNode<HeapObject> result =
AllocateInNewSpace(UncheckedCast<IntPtrT>(size), flags);
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kOneByteStringMap));
StoreMapNoWriteBarrier(result, RootIndex::kOneByteStringMap);
@@ -3294,15 +3375,16 @@ TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
BIND(&if_notsizeissmall);
{
// We might need to allocate in large object space, go to the runtime.
- Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context,
- ChangeUint32ToTagged(length));
+ TNode<Object> result =
+ CallRuntime(Runtime::kAllocateSeqOneByteString, NoContextConstant(),
+ ChangeUint32ToTagged(length));
var_result.Bind(result);
Goto(&if_join);
}
BIND(&if_lengthiszero);
{
- var_result.Bind(LoadRoot(RootIndex::kempty_string));
+ var_result.Bind(EmptyStringConstant());
Goto(&if_join);
}
@@ -3314,9 +3396,9 @@ TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
uint32_t length, AllocationFlags flags) {
Comment("AllocateSeqTwoByteString");
if (length == 0) {
- return CAST(LoadRoot(RootIndex::kempty_string));
+ return EmptyStringConstant();
}
- Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags);
+ TNode<HeapObject> result = Allocate(SeqTwoByteString::SizeFor(length), flags);
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kStringMap));
StoreMapNoWriteBarrier(result, RootIndex::kStringMap);
StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset,
@@ -3329,8 +3411,7 @@ TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
}
TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
- Node* context, TNode<Uint32T> length, AllocationFlags flags) {
- CSA_SLOW_ASSERT(this, IsZeroOrContext(context));
+ TNode<Uint32T> length, AllocationFlags flags) {
Comment("AllocateSeqTwoByteString");
VARIABLE(var_result, MachineRepresentation::kTagged);
@@ -3339,7 +3420,7 @@ TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
if_notsizeissmall(this, Label::kDeferred), if_join(this);
GotoIf(Word32Equal(length, Uint32Constant(0)), &if_lengthiszero);
- Node* raw_size = GetArrayAllocationSize(
+ TNode<IntPtrT> raw_size = GetArrayAllocationSize(
Signed(ChangeUint32ToWord(length)), UINT16_ELEMENTS, INTPTR_PARAMETERS,
SeqOneByteString::kHeaderSize + kObjectAlignmentMask);
TNode<WordT> size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask));
@@ -3349,7 +3430,7 @@ TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
BIND(&if_sizeissmall);
{
// Just allocate the SeqTwoByteString in new space.
- TNode<Object> result =
+ TNode<HeapObject> result =
AllocateInNewSpace(UncheckedCast<IntPtrT>(size), flags);
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kStringMap));
StoreMapNoWriteBarrier(result, RootIndex::kStringMap);
@@ -3365,15 +3446,16 @@ TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
BIND(&if_notsizeissmall);
{
// We might need to allocate in large object space, go to the runtime.
- Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context,
- ChangeUint32ToTagged(length));
+ TNode<Object> result =
+ CallRuntime(Runtime::kAllocateSeqTwoByteString, NoContextConstant(),
+ ChangeUint32ToTagged(length));
var_result.Bind(result);
Goto(&if_join);
}
BIND(&if_lengthiszero);
{
- var_result.Bind(LoadRoot(RootIndex::kempty_string));
+ var_result.Bind(EmptyStringConstant());
Goto(&if_join);
}
@@ -3387,7 +3469,7 @@ TNode<String> CodeStubAssembler::AllocateSlicedString(RootIndex map_root_index,
TNode<Smi> offset) {
DCHECK(map_root_index == RootIndex::kSlicedOneByteStringMap ||
map_root_index == RootIndex::kSlicedStringMap);
- Node* result = Allocate(SlicedString::kSize);
+ TNode<HeapObject> result = Allocate(SlicedString::kSize);
DCHECK(RootsTable::IsImmortalImmovable(map_root_index));
StoreMapNoWriteBarrier(result, map_root_index);
StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset,
@@ -3419,20 +3501,20 @@ TNode<String> CodeStubAssembler::AllocateConsString(TNode<Uint32T> length,
TNode<String> right) {
// Added string can be a cons string.
Comment("Allocating ConsString");
- Node* left_instance_type = LoadInstanceType(left);
- Node* right_instance_type = LoadInstanceType(right);
+ TNode<Int32T> left_instance_type = LoadInstanceType(left);
+ TNode<Int32T> right_instance_type = LoadInstanceType(right);
// Determine the resulting ConsString map to use depending on whether
// any of {left} or {right} has two byte encoding.
STATIC_ASSERT(kOneByteStringTag != 0);
STATIC_ASSERT(kTwoByteStringTag == 0);
- Node* combined_instance_type =
+ TNode<Int32T> combined_instance_type =
Word32And(left_instance_type, right_instance_type);
TNode<Map> result_map = CAST(Select<Object>(
IsSetWord32(combined_instance_type, kStringEncodingMask),
- [=] { return LoadRoot(RootIndex::kConsOneByteStringMap); },
- [=] { return LoadRoot(RootIndex::kConsStringMap); }));
- Node* result = AllocateInNewSpace(ConsString::kSize);
+ [=] { return ConsOneByteStringMapConstant(); },
+ [=] { return ConsStringMapConstant(); }));
+ TNode<HeapObject> result = AllocateInNewSpace(ConsString::kSize);
StoreMapNoWriteBarrier(result, result_map);
StoreObjectFieldNoWriteBarrier(result, ConsString::kLengthOffset, length,
MachineRepresentation::kWord32);
@@ -3498,15 +3580,15 @@ TNode<NameDictionary> CodeStubAssembler::AllocateNameDictionaryWithCapacity(
// Initialize NameDictionary elements.
{
- TNode<WordT> result_word = BitcastTaggedToWord(result);
- TNode<WordT> start_address = IntPtrAdd(
+ TNode<IntPtrT> result_word = BitcastTaggedToWord(result);
+ TNode<IntPtrT> start_address = IntPtrAdd(
result_word, IntPtrConstant(NameDictionary::OffsetOfElementAt(
NameDictionary::kElementsStartIndex) -
kHeapObjectTag));
- TNode<WordT> end_address = IntPtrAdd(
+ TNode<IntPtrT> end_address = IntPtrAdd(
result_word, IntPtrSub(store_size, IntPtrConstant(kHeapObjectTag)));
- TNode<HeapObject> filler = UndefinedConstant();
+ TNode<Oddball> filler = UndefinedConstant();
DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kUndefinedValue));
StoreFieldsNoWriteBarrier(start_address, end_address, filler);
@@ -3623,7 +3705,7 @@ TNode<CollectionType> CodeStubAssembler::AllocateSmallOrderedHashTable(
// Allocate the table and add the proper map.
TNode<Map> small_ordered_hash_map =
CAST(LoadRoot(CollectionType::GetMapRootIndex()));
- TNode<Object> table_obj = AllocateInNewSpace(total_size_word_aligned);
+ TNode<HeapObject> table_obj = AllocateInNewSpace(total_size_word_aligned);
StoreMapNoWriteBarrier(table_obj, small_ordered_hash_map);
TNode<CollectionType> table = UncheckedCast<CollectionType>(table_obj);
@@ -3653,7 +3735,8 @@ TNode<CollectionType> CodeStubAssembler::AllocateSmallOrderedHashTable(
IntPtrAdd(table_address, hash_table_start_offset);
// Initialize the HashTable part.
- Node* memset = ExternalConstant(ExternalReference::libc_memset_function());
+ TNode<ExternalReference> memset =
+ ExternalConstant(ExternalReference::libc_memset_function());
CallCFunction(
memset, MachineType::AnyTagged(),
std::make_pair(MachineType::Pointer(), hash_table_start_address),
@@ -3661,10 +3744,10 @@ TNode<CollectionType> CodeStubAssembler::AllocateSmallOrderedHashTable(
std::make_pair(MachineType::UintPtr(), hash_table_and_chain_table_size));
// Initialize the DataTable part.
- TNode<HeapObject> filler = TheHoleConstant();
- TNode<WordT> data_table_start_address =
+ TNode<Oddball> filler = TheHoleConstant();
+ TNode<IntPtrT> data_table_start_address =
IntPtrAdd(table_address, data_table_start_offset);
- TNode<WordT> data_table_end_address =
+ TNode<IntPtrT> data_table_end_address =
IntPtrAdd(data_table_start_address, data_table_size);
StoreFieldsNoWriteBarrier(data_table_start_address, data_table_end_address,
filler);
@@ -3682,31 +3765,32 @@ CodeStubAssembler::AllocateSmallOrderedHashTable<SmallOrderedHashSet>(
template <typename CollectionType>
void CodeStubAssembler::FindOrderedHashTableEntry(
Node* table, Node* hash,
- const std::function<void(Node*, Label*, Label*)>& key_compare,
+ const std::function<void(TNode<Object>, Label*, Label*)>& key_compare,
Variable* entry_start_position, Label* entry_found, Label* not_found) {
// Get the index of the bucket.
- Node* const number_of_buckets = SmiUntag(CAST(UnsafeLoadFixedArrayElement(
- CAST(table), CollectionType::NumberOfBucketsIndex())));
- Node* const bucket =
+ TNode<IntPtrT> const number_of_buckets =
+ SmiUntag(CAST(UnsafeLoadFixedArrayElement(
+ CAST(table), CollectionType::NumberOfBucketsIndex())));
+ TNode<WordT> const bucket =
WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1)));
- Node* const first_entry = SmiUntag(CAST(UnsafeLoadFixedArrayElement(
+ TNode<IntPtrT> const first_entry = SmiUntag(CAST(UnsafeLoadFixedArrayElement(
CAST(table), bucket,
CollectionType::HashTableStartIndex() * kTaggedSize)));
// Walk the bucket chain.
- Node* entry_start;
+ TNode<IntPtrT> entry_start;
Label if_key_found(this);
{
- VARIABLE(var_entry, MachineType::PointerRepresentation(), first_entry);
+ TVARIABLE(IntPtrT, var_entry, first_entry);
Label loop(this, {&var_entry, entry_start_position}),
continue_next_entry(this);
Goto(&loop);
BIND(&loop);
// If the entry index is the not-found sentinel, we are done.
- GotoIf(
- WordEqual(var_entry.value(), IntPtrConstant(CollectionType::kNotFound)),
- not_found);
+ GotoIf(IntPtrEqual(var_entry.value(),
+ IntPtrConstant(CollectionType::kNotFound)),
+ not_found);
// Make sure the entry index is within range.
CSA_ASSERT(
@@ -3727,7 +3811,7 @@ void CodeStubAssembler::FindOrderedHashTableEntry(
number_of_buckets);
// Load the key from the entry.
- Node* const candidate_key = UnsafeLoadFixedArrayElement(
+ TNode<Object> const candidate_key = UnsafeLoadFixedArrayElement(
CAST(table), entry_start,
CollectionType::HashTableStartIndex() * kTaggedSize);
@@ -3735,10 +3819,10 @@ void CodeStubAssembler::FindOrderedHashTableEntry(
BIND(&continue_next_entry);
// Load the index of the next entry in the bucket chain.
- var_entry.Bind(SmiUntag(CAST(UnsafeLoadFixedArrayElement(
+ var_entry = SmiUntag(CAST(UnsafeLoadFixedArrayElement(
CAST(table), entry_start,
(CollectionType::HashTableStartIndex() + CollectionType::kChainOffset) *
- kTaggedSize))));
+ kTaggedSize)));
Goto(&loop);
}
@@ -3750,18 +3834,18 @@ void CodeStubAssembler::FindOrderedHashTableEntry(
template void CodeStubAssembler::FindOrderedHashTableEntry<OrderedHashMap>(
Node* table, Node* hash,
- const std::function<void(Node*, Label*, Label*)>& key_compare,
+ const std::function<void(TNode<Object>, Label*, Label*)>& key_compare,
Variable* entry_start_position, Label* entry_found, Label* not_found);
template void CodeStubAssembler::FindOrderedHashTableEntry<OrderedHashSet>(
Node* table, Node* hash,
- const std::function<void(Node*, Label*, Label*)>& key_compare,
+ const std::function<void(TNode<Object>, Label*, Label*)>& key_compare,
Variable* entry_start_position, Label* entry_found, Label* not_found);
Node* CodeStubAssembler::AllocateStruct(Node* map, AllocationFlags flags) {
Comment("AllocateStruct");
CSA_ASSERT(this, IsMap(map));
TNode<IntPtrT> size = TimesTaggedSize(LoadMapInstanceSizeInWords(map));
- TNode<Object> object = Allocate(size, flags);
+ TNode<HeapObject> object = Allocate(size, flags);
StoreMapNoWriteBarrier(object, map);
InitializeStructBody(object, map, size, Struct::kHeaderSize);
return object;
@@ -3771,12 +3855,12 @@ void CodeStubAssembler::InitializeStructBody(Node* object, Node* map,
Node* size, int start_offset) {
CSA_SLOW_ASSERT(this, IsMap(map));
Comment("InitializeStructBody");
- Node* filler = UndefinedConstant();
+ TNode<Oddball> filler = UndefinedConstant();
// Calculate the untagged field addresses.
object = BitcastTaggedToWord(object);
- Node* start_address =
+ TNode<WordT> start_address =
IntPtrAdd(object, IntPtrConstant(start_offset - kHeapObjectTag));
- Node* end_address =
+ TNode<WordT> end_address =
IntPtrSub(IntPtrAdd(object, size), IntPtrConstant(kHeapObjectTag));
StoreFieldsNoWriteBarrier(start_address, end_address, filler);
}
@@ -3791,7 +3875,7 @@ TNode<JSObject> CodeStubAssembler::AllocateJSObjectFromMap(
JS_GLOBAL_OBJECT_TYPE)));
TNode<IntPtrT> instance_size =
TimesTaggedSize(LoadMapInstanceSizeInWords(map));
- TNode<Object> object = AllocateInNewSpace(instance_size, flags);
+ TNode<HeapObject> object = AllocateInNewSpace(instance_size, flags);
StoreMapNoWriteBarrier(object, map);
InitializeJSObjectFromMap(object, map, instance_size, properties, elements,
slack_tracking_mode);
@@ -3846,7 +3930,7 @@ void CodeStubAssembler::InitializeJSObjectBodyWithSlackTracking(
// Perform in-object slack tracking if requested.
int start_offset = JSObject::kHeaderSize;
- Node* bit_field3 = LoadMapBitField3(map);
+ TNode<Uint32T> bit_field3 = LoadMapBitField3(map);
Label end(this), slack_tracking(this), complete(this, Label::kDeferred);
STATIC_ASSERT(Map::kNoSlackTracking == 0);
GotoIf(IsSetWord32<Map::ConstructionCounterBits>(bit_field3),
@@ -3860,8 +3944,8 @@ void CodeStubAssembler::InitializeJSObjectBodyWithSlackTracking(
Comment("Decrease construction counter");
// Slack tracking is only done on initial maps.
CSA_ASSERT(this, IsUndefined(LoadMapBackPointer(map)));
- STATIC_ASSERT(Map::ConstructionCounterBits::kNext == 32);
- Node* new_bit_field3 = Int32Sub(
+ STATIC_ASSERT(Map::ConstructionCounterBits::kLastUsedBit == 31);
+ TNode<Word32T> new_bit_field3 = Int32Sub(
bit_field3, Int32Constant(1 << Map::ConstructionCounterBits::kShift));
StoreObjectFieldNoWriteBarrier(map, Map::kBitField3Offset, new_bit_field3,
MachineRepresentation::kWord32);
@@ -3869,7 +3953,7 @@ void CodeStubAssembler::InitializeJSObjectBodyWithSlackTracking(
// The object still has in-object slack therefore the |unsed_or_unused|
// field contain the "used" value.
- Node* used_size = TimesTaggedSize(ChangeUint32ToWord(
+ TNode<UintPtrT> used_size = TimesTaggedSize(ChangeUint32ToWord(
LoadObjectField(map, Map::kUsedOrUnusedInstanceSizeInWordsOffset,
MachineType::Uint8())));
@@ -3957,7 +4041,7 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements(
int capacity_int;
if (TryGetIntPtrOrSmiConstantValue(capacity, &capacity_int, capacity_mode)) {
if (capacity_int == 0) {
- TNode<FixedArrayBase> empty_array = EmptyFixedArrayConstant();
+ TNode<FixedArray> empty_array = EmptyFixedArrayConstant();
array = AllocateJSArray(array_map, empty_array, length, allocation_site,
array_header_size);
return {array.value(), empty_array};
@@ -3970,7 +4054,7 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements(
BIND(&empty);
{
- TNode<FixedArrayBase> empty_array = EmptyFixedArrayConstant();
+ TNode<FixedArray> empty_array = EmptyFixedArrayConstant();
array = AllocateJSArray(array_map, empty_array, length, allocation_site,
array_header_size);
elements = empty_array;
@@ -4059,7 +4143,7 @@ TNode<JSArray> CodeStubAssembler::AllocateUninitializedJSArray(
CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length));
// Allocate space for the JSArray and the elements FixedArray in one go.
- TNode<Object> array = AllocateInNewSpace(size_in_bytes);
+ TNode<HeapObject> array = AllocateInNewSpace(size_in_bytes);
StoreMapNoWriteBarrier(array, array_map);
StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
@@ -4109,18 +4193,18 @@ Node* CodeStubAssembler::ExtractFastJSArray(Node* context, Node* array,
Node* begin, Node* count,
ParameterMode mode, Node* capacity,
Node* allocation_site) {
- Node* original_array_map = LoadMap(array);
- Node* elements_kind = LoadMapElementsKind(original_array_map);
+ TNode<Map> original_array_map = LoadMap(array);
+ TNode<Int32T> elements_kind = LoadMapElementsKind(original_array_map);
// Use the cannonical map for the Array's ElementsKind
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> array_map = LoadJSArrayElementsMap(elements_kind, native_context);
TNode<FixedArrayBase> new_elements = ExtractFixedArray(
LoadElements(array), begin, count, capacity,
ExtractFixedArrayFlag::kAllFixedArrays, mode, nullptr, elements_kind);
- TNode<Object> result = AllocateJSArray(
+ TNode<JSArray> result = AllocateJSArray(
array_map, new_elements, ParameterToTagged(count, mode), allocation_site);
return result;
}
@@ -4134,7 +4218,7 @@ Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array,
// protector is invalid. This function should be renamed to reflect its uses.
CSA_ASSERT(this, IsJSArray(array));
- Node* length = LoadJSArrayLength(array);
+ TNode<Number> length = LoadJSArrayLength(array);
Node* new_elements = nullptr;
VARIABLE(var_new_elements, MachineRepresentation::kTagged);
TVARIABLE(Int32T, var_elements_kind, LoadMapElementsKind(LoadMap(array)));
@@ -4153,7 +4237,7 @@ Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array,
// Simple extraction that preserves holes.
new_elements =
ExtractFixedArray(LoadElements(array), IntPtrOrSmiConstant(0, mode),
- TaggedToParameter(length, mode), nullptr,
+ TaggedToParameter(CAST(length), mode), nullptr,
ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW, mode,
nullptr, var_elements_kind.value());
var_new_elements.Bind(new_elements);
@@ -4171,7 +4255,7 @@ Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array,
// ExtractFixedArrayFlag::kDontCopyCOW.
new_elements = ExtractFixedArray(
LoadElements(array), IntPtrOrSmiConstant(0, mode),
- TaggedToParameter(length, mode), nullptr,
+ TaggedToParameter(CAST(length), mode), nullptr,
ExtractFixedArrayFlag::kAllFixedArrays, mode, &var_holes_converted);
var_new_elements.Bind(new_elements);
// If the array type didn't change, use the original elements kind.
@@ -4183,9 +4267,10 @@ Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array,
BIND(&allocate_jsarray);
- // Handle sealed, frozen elements kinds
- CSA_ASSERT(this, IsElementsKindLessThanOrEqual(var_elements_kind.value(),
- LAST_FROZEN_ELEMENTS_KIND));
+ // Handle any nonextensible elements kinds
+ CSA_ASSERT(this, IsElementsKindLessThanOrEqual(
+ var_elements_kind.value(),
+ LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND));
GotoIf(IsElementsKindLessThanOrEqual(var_elements_kind.value(),
LAST_FAST_ELEMENTS_KIND),
&allocate_jsarray_main);
@@ -4194,11 +4279,11 @@ Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array,
BIND(&allocate_jsarray_main);
// Use the cannonical map for the chosen elements kind.
- Node* native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> array_map =
LoadJSArrayElementsMap(var_elements_kind.value(), native_context);
- TNode<Object> result = AllocateJSArray(
+ TNode<JSArray> result = AllocateJSArray(
array_map, CAST(var_new_elements.value()), CAST(length), allocation_site);
return result;
}
@@ -4236,7 +4321,7 @@ TNode<FixedArrayBase> CodeStubAssembler::AllocateFixedArray(
if (IsDoubleElementsKind(kind)) flags |= kDoubleAlignment;
// Allocate both array and elements object, and initialize the JSArray.
- Node* array = Allocate(total_size, flags);
+ TNode<HeapObject> array = Allocate(total_size, flags);
if (fixed_array_map != nullptr) {
// Conservatively only skip the write barrier if there are no allocation
// flags, this ensures that the object hasn't ended up in LOS. Note that the
@@ -4256,27 +4341,27 @@ TNode<FixedArrayBase> CodeStubAssembler::AllocateFixedArray(
DCHECK(RootsTable::IsImmortalImmovable(map_index));
StoreMapNoWriteBarrier(array, map_index);
}
- StoreObjectFieldNoWriteBarrier(array, FixedArray::kLengthOffset,
+ StoreObjectFieldNoWriteBarrier(array, FixedArrayBase::kLengthOffset,
ParameterToTagged(capacity, mode));
- return UncheckedCast<FixedArray>(array);
+ return UncheckedCast<FixedArrayBase>(array);
}
TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
- Node* source, Node* first, Node* count, Node* capacity, Node* source_map,
- ElementsKind from_kind, AllocationFlags allocation_flags,
- ExtractFixedArrayFlags extract_flags, ParameterMode parameter_mode,
- HoleConversionMode convert_holes, TVariable<BoolT>* var_holes_converted,
- Node* source_elements_kind) {
+ SloppyTNode<FixedArrayBase> source, Node* first, Node* count,
+ Node* capacity, SloppyTNode<Map> source_map, ElementsKind from_kind,
+ AllocationFlags allocation_flags, ExtractFixedArrayFlags extract_flags,
+ ParameterMode parameter_mode, HoleConversionMode convert_holes,
+ TVariable<BoolT>* var_holes_converted, Node* source_elements_kind) {
DCHECK_NE(first, nullptr);
DCHECK_NE(count, nullptr);
DCHECK_NE(capacity, nullptr);
DCHECK(extract_flags & ExtractFixedArrayFlag::kFixedArrays);
- CSA_ASSERT(this,
- WordNotEqual(IntPtrOrSmiConstant(0, parameter_mode), capacity));
- CSA_ASSERT(this, WordEqual(source_map, LoadMap(source)));
+ CSA_ASSERT(this, IntPtrOrSmiNotEqual(IntPtrOrSmiConstant(0, parameter_mode),
+ capacity, parameter_mode));
+ CSA_ASSERT(this, TaggedEqual(source_map, LoadMap(source)));
- VARIABLE(var_result, MachineRepresentation::kTagged);
- VARIABLE(var_target_map, MachineRepresentation::kTagged, source_map);
+ TVARIABLE(FixedArrayBase, var_result);
+ TVARIABLE(Map, var_target_map, source_map);
Label done(this, {&var_result}), is_cow(this),
new_space_check(this, {&var_target_map});
@@ -4286,12 +4371,11 @@ TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
// source_map as the target map.
if (IsDoubleElementsKind(from_kind)) {
CSA_ASSERT(this, IsFixedDoubleArrayMap(source_map));
- var_target_map.Bind(LoadRoot(RootIndex::kFixedArrayMap));
+ var_target_map = FixedArrayMapConstant();
Goto(&new_space_check);
} else {
CSA_ASSERT(this, Word32BinaryNot(IsFixedDoubleArrayMap(source_map)));
- Branch(WordEqual(var_target_map.value(),
- LoadRoot(RootIndex::kFixedCOWArrayMap)),
+ Branch(TaggedEqual(var_target_map.value(), FixedCOWArrayMapConstant()),
&is_cow, &new_space_check);
BIND(&is_cow);
@@ -4301,13 +4385,14 @@ TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
// 1) |extract_flags| forces us to, or
// 2) we're asked to extract only part of the |source| (|first| != 0).
if (extract_flags & ExtractFixedArrayFlag::kDontCopyCOW) {
- Branch(WordNotEqual(IntPtrOrSmiConstant(0, parameter_mode), first),
+ Branch(IntPtrOrSmiNotEqual(IntPtrOrSmiConstant(0, parameter_mode),
+ first, parameter_mode),
&new_space_check, [&] {
- var_result.Bind(source);
+ var_result = source;
Goto(&done);
});
} else {
- var_target_map.Bind(LoadRoot(RootIndex::kFixedArrayMap));
+ var_target_map = FixedArrayMapConstant();
Goto(&new_space_check);
}
}
@@ -4344,8 +4429,9 @@ TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
TNode<FixedArrayBase> to_elements =
AllocateFixedArray(to_kind, capacity, parameter_mode, allocation_flags,
var_target_map.value());
- var_result.Bind(to_elements);
+ var_result = to_elements;
+#ifndef V8_ENABLE_SINGLE_GENERATION
#ifdef DEBUG
TNode<IntPtrT> object_word = BitcastTaggedToWord(to_elements);
TNode<IntPtrT> object_page = PageFromAddress(object_word);
@@ -4359,6 +4445,7 @@ TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
IntPtrConstant(MemoryChunk::kIsInYoungGenerationMask)),
IntPtrConstant(0)));
#endif
+#endif
if (convert_holes == HoleConversionMode::kDontConvert &&
!IsDoubleElementsKind(from_kind)) {
@@ -4367,7 +4454,7 @@ TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
// will efficiently use memcpy.
FillFixedArrayWithValue(to_kind, to_elements, count, capacity,
RootIndex::kTheHoleValue, parameter_mode);
- CopyElements(to_kind, to_elements, IntPtrConstant(0), CAST(source),
+ CopyElements(to_kind, to_elements, IntPtrConstant(0), source,
ParameterToIntPtr(first, parameter_mode),
ParameterToIntPtr(count, parameter_mode),
SKIP_WRITE_BARRIER);
@@ -4396,15 +4483,15 @@ TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
to_elements =
AllocateFixedArray(to_smi_kind, capacity, parameter_mode,
allocation_flags, var_target_map.value());
- var_result.Bind(to_elements);
+ var_result = to_elements;
FillFixedArrayWithValue(to_smi_kind, to_elements, count, capacity,
RootIndex::kTheHoleValue, parameter_mode);
// CopyElements will try to use memcpy if it's not conflicting with
// GC. Otherwise it will copy elements by elements, but skip write
// barriers (since we're copying smis to smis).
- CopyElements(to_smi_kind, to_elements, IntPtrConstant(0),
- CAST(source), ParameterToIntPtr(first, parameter_mode),
+ CopyElements(to_smi_kind, to_elements, IntPtrConstant(0), source,
+ ParameterToIntPtr(first, parameter_mode),
ParameterToIntPtr(count, parameter_mode),
SKIP_WRITE_BARRIER);
Goto(&done);
@@ -4417,7 +4504,7 @@ TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
to_elements =
AllocateFixedArray(to_kind, capacity, parameter_mode,
allocation_flags, var_target_map.value());
- var_result.Bind(to_elements);
+ var_result = to_elements;
CopyFixedArrayElements(from_kind, source, to_kind, to_elements, first,
count, capacity, UPDATE_WRITE_BARRIER,
parameter_mode, convert_holes,
@@ -4445,8 +4532,8 @@ TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedDoubleArrayFillingHoles(
VARIABLE(var_result, MachineRepresentation::kTagged);
const ElementsKind kind = PACKED_DOUBLE_ELEMENTS;
- Node* to_elements = AllocateFixedArray(kind, capacity, mode, allocation_flags,
- fixed_array_map);
+ TNode<FixedArrayBase> to_elements = AllocateFixedArray(
+ kind, capacity, mode, allocation_flags, fixed_array_map);
var_result.Bind(to_elements);
// We first try to copy the FixedDoubleArray to a new FixedDoubleArray.
// |var_holes_converted| is set to False preliminarily.
@@ -4466,25 +4553,25 @@ TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedDoubleArrayFillingHoles(
capacity, RootIndex::kTheHoleValue, mode);
const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
- Node* first_from_element_offset =
+ TNode<IntPtrT> first_from_element_offset =
ElementOffsetFromIndex(first, kind, mode, 0);
- Node* limit_offset = IntPtrAdd(first_from_element_offset,
- IntPtrConstant(first_element_offset));
- VARIABLE(var_from_offset, MachineType::PointerRepresentation(),
- ElementOffsetFromIndex(IntPtrOrSmiAdd(first, count, mode), kind,
- mode, first_element_offset));
+ TNode<WordT> limit_offset = IntPtrAdd(first_from_element_offset,
+ IntPtrConstant(first_element_offset));
+ TVARIABLE(IntPtrT, var_from_offset,
+ ElementOffsetFromIndex(IntPtrOrSmiAdd(first, count, mode), kind,
+ mode, first_element_offset));
Label decrement(this, {&var_from_offset}), done(this);
- Node* to_array_adjusted =
+ TNode<WordT> to_array_adjusted =
IntPtrSub(BitcastTaggedToWord(to_elements), first_from_element_offset);
Branch(WordEqual(var_from_offset.value(), limit_offset), &done, &decrement);
BIND(&decrement);
{
- Node* from_offset =
+ TNode<IntPtrT> from_offset =
IntPtrSub(var_from_offset.value(), IntPtrConstant(kDoubleSize));
- var_from_offset.Bind(from_offset);
+ var_from_offset = from_offset;
Node* to_offset = from_offset;
@@ -4496,7 +4583,7 @@ TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedDoubleArrayFillingHoles(
StoreNoWriteBarrier(MachineRepresentation::kFloat64, to_array_adjusted,
to_offset, value);
- Node* compare = WordNotEqual(from_offset, limit_offset);
+ TNode<BoolT> compare = WordNotEqual(from_offset, limit_offset);
Branch(compare, &decrement, &done);
BIND(&if_hole);
@@ -4557,8 +4644,10 @@ TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedArray(
}
Label if_fixed_double_array(this), empty(this), done(this, {&var_result});
- Node* source_map = LoadMap(source);
- GotoIf(WordEqual(IntPtrOrSmiConstant(0, parameter_mode), capacity), &empty);
+ TNode<Map> source_map = LoadMap(source);
+ GotoIf(IntPtrOrSmiEqual(IntPtrOrSmiConstant(0, parameter_mode), capacity,
+ parameter_mode),
+ &empty);
if (extract_flags & ExtractFixedArrayFlag::kFixedDoubleArrays) {
if (extract_flags & ExtractFixedArrayFlag::kFixedArrays) {
@@ -4571,7 +4660,7 @@ TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedArray(
if (extract_flags & ExtractFixedArrayFlag::kFixedArrays) {
// Here we can only get |source| as FixedArray, never FixedDoubleArray.
// PACKED_ELEMENTS is used to signify that the source is a FixedArray.
- Node* to_elements = ExtractToFixedArray(
+ TNode<FixedArray> to_elements = ExtractToFixedArray(
source, first, count, capacity, source_map, PACKED_ELEMENTS,
allocation_flags, extract_flags, parameter_mode, convert_holes,
var_holes_converted, source_runtime_kind);
@@ -4584,7 +4673,7 @@ TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedArray(
Comment("Copy FixedDoubleArray");
if (convert_holes == HoleConversionMode::kConvertToUndefined) {
- Node* to_elements = ExtractFixedDoubleArrayFillingHoles(
+ TNode<FixedArrayBase> to_elements = ExtractFixedDoubleArrayFillingHoles(
source, first, count, capacity, source_map, var_holes_converted,
allocation_flags, extract_flags, parameter_mode);
var_result.Bind(to_elements);
@@ -4643,7 +4732,7 @@ Node* CodeStubAssembler::AllocatePropertyArray(Node* capacity_node,
TNode<IntPtrT> total_size =
GetPropertyArrayAllocationSize(capacity_node, mode);
- TNode<Object> array = Allocate(total_size, flags);
+ TNode<HeapObject> array = Allocate(total_size, flags);
RootIndex map_index = RootIndex::kPropertyArrayMap;
DCHECK(RootsTable::IsImmortalImmovable(map_index));
StoreMapNoWriteBarrier(array, map_index);
@@ -4659,7 +4748,7 @@ void CodeStubAssembler::FillPropertyArrayWithUndefined(Node* array,
CSA_SLOW_ASSERT(this, MatchesParameterMode(to_node, mode));
CSA_SLOW_ASSERT(this, IsPropertyArray(array));
ElementsKind kind = PACKED_ELEMENTS;
- Node* value = UndefinedConstant();
+ TNode<Oddball> value = UndefinedConstant();
BuildFastFixedArrayForEach(
array, kind, from_node, to_node,
[this, value](Node* array, Node* offset) {
@@ -4681,17 +4770,18 @@ void CodeStubAssembler::FillFixedArrayWithValue(ElementsKind kind, Node* array,
// Determine the value to initialize the {array} based
// on the {value_root_index} and the elements {kind}.
- Node* value = LoadRoot(value_root_index);
+ TNode<Object> value = LoadRoot(value_root_index);
+ TNode<Float64T> float_value;
if (IsDoubleElementsKind(kind)) {
- value = LoadHeapNumberValue(value);
+ float_value = LoadHeapNumberValue(CAST(value));
}
BuildFastFixedArrayForEach(
array, kind, from_node, to_node,
- [this, value, kind](Node* array, Node* offset) {
+ [this, value, float_value, kind](Node* array, Node* offset) {
if (IsDoubleElementsKind(kind)) {
StoreNoWriteBarrier(MachineRepresentation::kFloat64, array, offset,
- value);
+ float_value);
} else {
StoreNoWriteBarrier(MachineRepresentation::kTagged, array, offset,
value);
@@ -4703,13 +4793,13 @@ void CodeStubAssembler::FillFixedArrayWithValue(ElementsKind kind, Node* array,
void CodeStubAssembler::StoreFixedDoubleArrayHole(
TNode<FixedDoubleArray> array, Node* index, ParameterMode parameter_mode) {
CSA_SLOW_ASSERT(this, MatchesParameterMode(index, parameter_mode));
- Node* offset =
+ TNode<IntPtrT> offset =
ElementOffsetFromIndex(index, PACKED_DOUBLE_ELEMENTS, parameter_mode,
FixedArray::kHeaderSize - kHeapObjectTag);
CSA_ASSERT(this, IsOffsetInBounds(
offset, LoadAndUntagFixedArrayBaseLength(array),
FixedDoubleArray::kHeaderSize, PACKED_DOUBLE_ELEMENTS));
- Node* double_hole =
+ TNode<UintPtrT> double_hole =
Is64() ? ReinterpretCast<UintPtrT>(Int64Constant(kHoleNanInt64))
: ReinterpretCast<UintPtrT>(Int32Constant(kHoleNanLower32));
// TODO(danno): When we have a Float32/Float64 wrapper class that
@@ -4845,7 +4935,7 @@ void CodeStubAssembler::MoveElements(ElementsKind kind,
IntPtrConstant(ElementsKindToByteSize(kind)));
auto loop_body = [&](Node* array, Node* offset) {
Node* const element = Load(MachineType::AnyTagged(), array, offset);
- Node* const delta_offset = IntPtrAdd(offset, delta);
+ TNode<WordT> const delta_offset = IntPtrAdd(offset, delta);
Store(array, delta_offset, element);
};
@@ -4894,8 +4984,8 @@ void CodeStubAssembler::CopyElements(ElementsKind kind,
CSA_ASSERT(this, IntPtrLessThanOrEqual(
IntPtrAdd(src_index, length),
LoadAndUntagFixedArrayBaseLength(src_elements)));
- CSA_ASSERT(this, Word32Or(WordNotEqual(dst_elements, src_elements),
- WordEqual(length, IntPtrConstant(0))));
+ CSA_ASSERT(this, Word32Or(TaggedNotEqual(dst_elements, src_elements),
+ IntPtrEqual(length, IntPtrConstant(0))));
// The write barrier can be ignored if {dst_elements} is in new space, or if
// the elements pointer is FixedDoubleArray.
@@ -4938,7 +5028,7 @@ void CodeStubAssembler::CopyElements(ElementsKind kind,
src_elements, kind, begin, end,
[&](Node* array, Node* offset) {
Node* const element = Load(MachineType::AnyTagged(), array, offset);
- Node* const delta_offset = IntPtrAdd(offset, delta);
+ TNode<WordT> const delta_offset = IntPtrAdd(offset, delta);
if (write_barrier == SKIP_WRITE_BARRIER) {
StoreNoWriteBarrier(MachineRepresentation::kTagged, dst_elements,
delta_offset, element);
@@ -4984,7 +5074,7 @@ void CodeStubAssembler::CopyFixedArrayElements(
!needs_write_barrier &&
(kTaggedSize == kDoubleSize ||
IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind));
- Node* double_hole =
+ TNode<UintPtrT> double_hole =
Is64() ? ReinterpretCast<UintPtrT>(Int64Constant(kHoleNanInt64))
: ReinterpretCast<UintPtrT>(Int32Constant(kHoleNanLower32));
@@ -5009,12 +5099,12 @@ void CodeStubAssembler::CopyFixedArrayElements(
RootIndex::kTheHoleValue, mode);
}
- Node* first_from_element_offset =
+ TNode<IntPtrT> first_from_element_offset =
ElementOffsetFromIndex(first_element, from_kind, mode, 0);
- Node* limit_offset = IntPtrAdd(first_from_element_offset,
- IntPtrConstant(first_element_offset));
- VARIABLE(
- var_from_offset, MachineType::PointerRepresentation(),
+ TNode<IntPtrT> limit_offset = Signed(IntPtrAdd(
+ first_from_element_offset, IntPtrConstant(first_element_offset)));
+ TVARIABLE(
+ IntPtrT, var_from_offset,
ElementOffsetFromIndex(IntPtrOrSmiAdd(first_element, element_count, mode),
from_kind, mode, first_element_offset));
// This second variable is used only when the element sizes of source and
@@ -5041,10 +5131,10 @@ void CodeStubAssembler::CopyFixedArrayElements(
BIND(&decrement);
{
- Node* from_offset = IntPtrSub(
+ TNode<IntPtrT> from_offset = Signed(IntPtrSub(
var_from_offset.value(),
- IntPtrConstant(from_double_elements ? kDoubleSize : kTaggedSize));
- var_from_offset.Bind(from_offset);
+ IntPtrConstant(from_double_elements ? kDoubleSize : kTaggedSize)));
+ var_from_offset = from_offset;
Node* to_offset;
if (element_offset_matches) {
@@ -5119,7 +5209,7 @@ void CodeStubAssembler::CopyFixedArrayElements(
}
BIND(&next_iter);
- Node* compare = WordNotEqual(from_offset, limit_offset);
+ TNode<BoolT> compare = WordNotEqual(from_offset, limit_offset);
Branch(compare, &decrement, &done);
}
@@ -5131,8 +5221,8 @@ TNode<FixedArray> CodeStubAssembler::HeapObjectToFixedArray(
TNode<HeapObject> base, Label* cast_fail) {
Label fixed_array(this);
TNode<Map> map = LoadMap(base);
- GotoIf(WordEqual(map, LoadRoot(RootIndex::kFixedArrayMap)), &fixed_array);
- GotoIf(WordNotEqual(map, LoadRoot(RootIndex::kFixedCOWArrayMap)), cast_fail);
+ GotoIf(TaggedEqual(map, FixedArrayMapConstant()), &fixed_array);
+ GotoIf(TaggedNotEqual(map, FixedCOWArrayMapConstant()), cast_fail);
Goto(&fixed_array);
BIND(&fixed_array);
return UncheckedCast<FixedArray>(base);
@@ -5153,8 +5243,8 @@ void CodeStubAssembler::CopyPropertyArrayValues(Node* from_array,
bool needs_write_barrier = barrier_mode == UPDATE_WRITE_BARRIER;
if (destroy_source == DestroySource::kNo) {
- // PropertyArray may contain MutableHeapNumbers, which will be cloned on the
- // heap, requiring a write barrier.
+ // PropertyArray may contain mutable HeapNumbers, which will be cloned on
+ // the heap, requiring a write barrier.
needs_write_barrier = true;
}
@@ -5213,13 +5303,13 @@ void CodeStubAssembler::CopyStringCharacters(Node* from_string, Node* to_string,
ElementsKind to_kind = to_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
int header_size = SeqOneByteString::kHeaderSize - kHeapObjectTag;
- Node* from_offset = ElementOffsetFromIndex(from_index, from_kind,
- INTPTR_PARAMETERS, header_size);
- Node* to_offset =
+ TNode<IntPtrT> from_offset = ElementOffsetFromIndex(
+ from_index, from_kind, INTPTR_PARAMETERS, header_size);
+ TNode<IntPtrT> to_offset =
ElementOffsetFromIndex(to_index, to_kind, INTPTR_PARAMETERS, header_size);
- Node* byte_count =
+ TNode<IntPtrT> byte_count =
ElementOffsetFromIndex(character_count, from_kind, INTPTR_PARAMETERS);
- Node* limit_offset = IntPtrAdd(from_offset, byte_count);
+ TNode<WordT> limit_offset = IntPtrAdd(from_offset, byte_count);
// Prepare the fast loop
MachineType type =
@@ -5234,8 +5324,8 @@ void CodeStubAssembler::CopyStringCharacters(Node* from_string, Node* to_string,
int to_index_constant = 0, from_index_constant = 0;
bool index_same = (from_encoding == to_encoding) &&
(from_index == to_index ||
- (ToInt32Constant(from_index, from_index_constant) &&
- ToInt32Constant(to_index, to_index_constant) &&
+ (ToInt32Constant(from_index, &from_index_constant) &&
+ ToInt32Constant(to_index, &to_index_constant) &&
from_index_constant == to_index_constant));
BuildFastLoop(
vars, from_offset, limit_offset,
@@ -5259,24 +5349,23 @@ Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array,
Label* if_hole) {
CSA_ASSERT(this, IsFixedArrayWithKind(array, from_kind));
if (IsDoubleElementsKind(from_kind)) {
- Node* value =
+ TNode<Float64T> value =
LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64());
if (!IsDoubleElementsKind(to_kind)) {
- value = AllocateHeapNumberWithValue(value);
+ return AllocateHeapNumberWithValue(value);
}
return value;
} else {
- Node* value = Load(MachineType::AnyTagged(), array, offset);
+ TNode<Object> value = CAST(Load(MachineType::AnyTagged(), array, offset));
if (if_hole) {
- GotoIf(WordEqual(value, TheHoleConstant()), if_hole);
+ GotoIf(TaggedEqual(value, TheHoleConstant()), if_hole);
}
if (IsDoubleElementsKind(to_kind)) {
if (IsSmiElementsKind(from_kind)) {
- value = SmiToFloat64(value);
- } else {
- value = LoadHeapNumberValue(value);
+ return SmiToFloat64(CAST(value));
}
+ return LoadHeapNumberValue(CAST(value));
}
return value;
}
@@ -5298,14 +5387,12 @@ Node* CodeStubAssembler::TryGrowElementsCapacity(Node* object, Node* elements,
CSA_SLOW_ASSERT(this, TaggedIsNotSmi(object));
CSA_SLOW_ASSERT(this, IsFixedArrayWithKindOrEmpty(elements, kind));
CSA_SLOW_ASSERT(this, TaggedIsSmi(key));
- Node* capacity = LoadFixedArrayBaseLength(elements);
+ TNode<Smi> capacity = LoadFixedArrayBaseLength(elements);
ParameterMode mode = OptimalParameterMode();
- capacity = TaggedToParameter(capacity, mode);
- key = TaggedToParameter(key, mode);
-
- return TryGrowElementsCapacity(object, elements, kind, key, capacity, mode,
- bailout);
+ return TryGrowElementsCapacity(
+ object, elements, kind, TaggedToParameter(key, mode),
+ TaggedToParameter(capacity, mode), mode, bailout);
}
Node* CodeStubAssembler::TryGrowElementsCapacity(Node* object, Node* elements,
@@ -5348,7 +5435,8 @@ Node* CodeStubAssembler::GrowElementsCapacity(
bailout);
// Allocate the new backing store.
- Node* new_elements = AllocateFixedArray(to_kind, new_capacity, mode);
+ TNode<FixedArrayBase> new_elements =
+ AllocateFixedArray(to_kind, new_capacity, mode);
// Copy the elements from the old elements store to the new.
// The size-check above guarantees that the |new_elements| is allocated
@@ -5365,7 +5453,7 @@ void CodeStubAssembler::InitializeAllocationMemento(Node* base,
Node* base_allocation_size,
Node* allocation_site) {
Comment("[Initialize AllocationMemento");
- TNode<Object> memento =
+ TNode<HeapObject> memento =
InnerAllocate(CAST(base), UncheckedCast<IntPtrT>(base_allocation_size));
StoreMapNoWriteBarrier(memento, RootIndex::kAllocationMementoMap);
StoreObjectFieldNoWriteBarrier(
@@ -5509,9 +5597,9 @@ void CodeStubAssembler::TaggedToWord32OrBigIntImpl(
Goto(if_number);
BIND(&not_smi);
- Node* map = LoadMap(value);
+ TNode<Map> map = LoadMap(value);
GotoIf(IsHeapNumberMap(map), &is_heap_number);
- Node* instance_type = LoadMapInstanceType(map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
if (conversion == Object::Conversion::kToNumeric) {
GotoIf(IsBigIntInstanceType(instance_type), &is_bigint);
}
@@ -5557,7 +5645,7 @@ void CodeStubAssembler::TaggedToWord32OrBigIntImpl(
TNode<Int32T> CodeStubAssembler::TruncateHeapNumberValueToWord32(
TNode<HeapNumber> object) {
- Node* value = LoadHeapNumberValue(object);
+ TNode<Float64T> value = LoadHeapNumberValue(object);
return Signed(TruncateFloat64ToWord32(value));
}
@@ -5715,7 +5803,7 @@ TNode<String> CodeStubAssembler::ToThisString(TNode<Context> context,
BIND(&if_valueisnotsmi);
{
// Load the instance type of the {value}.
- Node* value_instance_type = LoadInstanceType(CAST(value));
+ TNode<Uint16T> value_instance_type = LoadInstanceType(CAST(value));
// Check if the {value} is already String.
Label if_valueisnotstring(this, Label::kDeferred);
@@ -5867,16 +5955,16 @@ TNode<Object> CodeStubAssembler::ToThisValue(TNode<Context> context,
{
switch (primitive_type) {
case PrimitiveType::kBoolean:
- GotoIf(WordEqual(value_map, BooleanMapConstant()), &done_loop);
+ GotoIf(TaggedEqual(value_map, BooleanMapConstant()), &done_loop);
break;
case PrimitiveType::kNumber:
- GotoIf(WordEqual(value_map, HeapNumberMapConstant()), &done_loop);
+ GotoIf(TaggedEqual(value_map, HeapNumberMapConstant()), &done_loop);
break;
case PrimitiveType::kString:
GotoIf(IsStringInstanceType(value_instance_type), &done_loop);
break;
case PrimitiveType::kSymbol:
- GotoIf(WordEqual(value_map, SymbolMapConstant()), &done_loop);
+ GotoIf(TaggedEqual(value_map, SymbolMapConstant()), &done_loop);
break;
}
Goto(&done_throw);
@@ -5921,7 +6009,8 @@ Node* CodeStubAssembler::ThrowIfNotInstanceType(Node* context, Node* value,
// Load the instance type of the {value}.
var_value_map.Bind(LoadMap(value));
- Node* const value_instance_type = LoadMapInstanceType(var_value_map.value());
+ TNode<Uint16T> const value_instance_type =
+ LoadMapInstanceType(var_value_map.value());
Branch(Word32Equal(value_instance_type, Int32Constant(instance_type)), &out,
&throw_exception);
@@ -5935,26 +6024,26 @@ Node* CodeStubAssembler::ThrowIfNotInstanceType(Node* context, Node* value,
return var_value_map.value();
}
-Node* CodeStubAssembler::ThrowIfNotJSReceiver(Node* context, Node* value,
- MessageTemplate msg_template,
- const char* method_name) {
- Label out(this), throw_exception(this, Label::kDeferred);
- VARIABLE(var_value_map, MachineRepresentation::kTagged);
+void CodeStubAssembler::ThrowIfNotJSReceiver(TNode<Context> context,
+ TNode<Object> value,
+ MessageTemplate msg_template,
+ const char* method_name) {
+ Label done(this), throw_exception(this, Label::kDeferred);
GotoIf(TaggedIsSmi(value), &throw_exception);
// Load the instance type of the {value}.
- var_value_map.Bind(LoadMap(value));
- Node* const value_instance_type = LoadMapInstanceType(var_value_map.value());
+ TNode<Map> value_map = LoadMap(CAST(value));
+ TNode<Uint16T> const value_instance_type = LoadMapInstanceType(value_map);
- Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception);
+ Branch(IsJSReceiverInstanceType(value_instance_type), &done,
+ &throw_exception);
// The {value} is not a compatible receiver for this method.
BIND(&throw_exception);
- ThrowTypeError(context, msg_template, method_name);
+ ThrowTypeError(context, msg_template, StringConstant(method_name), value);
- BIND(&out);
- return var_value_map.value();
+ BIND(&done);
}
void CodeStubAssembler::ThrowIfNotCallable(TNode<Context> context,
@@ -5974,7 +6063,7 @@ void CodeStubAssembler::ThrowIfNotCallable(TNode<Context> context,
void CodeStubAssembler::ThrowRangeError(Node* context, MessageTemplate message,
Node* arg0, Node* arg1, Node* arg2) {
- Node* template_index = SmiConstant(static_cast<int>(message));
+ TNode<Smi> template_index = SmiConstant(static_cast<int>(message));
if (arg0 == nullptr) {
CallRuntime(Runtime::kThrowRangeError, context, template_index);
} else if (arg1 == nullptr) {
@@ -5999,7 +6088,7 @@ void CodeStubAssembler::ThrowTypeError(Node* context, MessageTemplate message,
void CodeStubAssembler::ThrowTypeError(Node* context, MessageTemplate message,
Node* arg0, Node* arg1, Node* arg2) {
- Node* template_index = SmiConstant(static_cast<int>(message));
+ TNode<Smi> template_index = SmiConstant(static_cast<int>(message));
if (arg0 == nullptr) {
CallRuntime(Runtime::kThrowTypeError, context, template_index);
} else if (arg1 == nullptr) {
@@ -6028,13 +6117,6 @@ TNode<BoolT> CodeStubAssembler::IsExtensibleMap(SloppyTNode<Map> map) {
return IsSetWord32<Map::IsExtensibleBit>(LoadMapBitField3(map));
}
-TNode<BoolT> CodeStubAssembler::IsFrozenOrSealedElementsKindMap(
- SloppyTNode<Map> map) {
- CSA_ASSERT(this, IsMap(map));
- return IsElementsKindInRange(LoadMapElementsKind(map), PACKED_SEALED_ELEMENTS,
- HOLEY_FROZEN_ELEMENTS);
-}
-
TNode<BoolT> CodeStubAssembler::IsExtensibleNonPrototypeMap(TNode<Map> map) {
int kMask = Map::IsExtensibleBit::kMask | Map::IsPrototypeMapBit::kMask;
int kExpected = Map::IsExtensibleBit::kMask;
@@ -6062,115 +6144,114 @@ TNode<BoolT> CodeStubAssembler::IsUndetectableMap(SloppyTNode<Map> map) {
}
TNode<BoolT> CodeStubAssembler::IsNoElementsProtectorCellInvalid() {
- Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
- Node* cell = LoadRoot(RootIndex::kNoElementsProtector);
- Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
- return WordEqual(cell_value, invalid);
+ TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid);
+ TNode<PropertyCell> cell = NoElementsProtectorConstant();
+ TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
+ return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsArrayIteratorProtectorCellInvalid() {
- Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
- Node* cell = LoadRoot(RootIndex::kArrayIteratorProtector);
- Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
- return WordEqual(cell_value, invalid);
+ TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid);
+ TNode<PropertyCell> cell = ArrayIteratorProtectorConstant();
+ TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
+ return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsPromiseResolveProtectorCellInvalid() {
- Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
- Node* cell = LoadRoot(RootIndex::kPromiseResolveProtector);
- Node* cell_value = LoadObjectField(cell, Cell::kValueOffset);
- return WordEqual(cell_value, invalid);
+ TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid);
+ TNode<Cell> cell = PromiseResolveProtectorConstant();
+ TNode<Object> cell_value = LoadObjectField(cell, Cell::kValueOffset);
+ return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsPromiseThenProtectorCellInvalid() {
- Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
- Node* cell = LoadRoot(RootIndex::kPromiseThenProtector);
- Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
- return WordEqual(cell_value, invalid);
+ TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid);
+ TNode<PropertyCell> cell = PromiseThenProtectorConstant();
+ TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
+ return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsArraySpeciesProtectorCellInvalid() {
- Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
- Node* cell = LoadRoot(RootIndex::kArraySpeciesProtector);
- Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
- return WordEqual(cell_value, invalid);
+ TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid);
+ TNode<PropertyCell> cell = ArraySpeciesProtectorConstant();
+ TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
+ return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsTypedArraySpeciesProtectorCellInvalid() {
- Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
- Node* cell = LoadRoot(RootIndex::kTypedArraySpeciesProtector);
- Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
- return WordEqual(cell_value, invalid);
+ TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid);
+ TNode<PropertyCell> cell = TypedArraySpeciesProtectorConstant();
+ TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
+ return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsRegExpSpeciesProtectorCellInvalid(
- TNode<Context> native_context) {
- CSA_ASSERT(this, IsNativeContext(native_context));
+ TNode<NativeContext> native_context) {
TNode<PropertyCell> cell = CAST(LoadContextElement(
native_context, Context::REGEXP_SPECIES_PROTECTOR_INDEX));
TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid);
- return WordEqual(cell_value, invalid);
+ return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsPromiseSpeciesProtectorCellInvalid() {
- Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
- Node* cell = LoadRoot(RootIndex::kPromiseSpeciesProtector);
- Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
- return WordEqual(cell_value, invalid);
+ TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid);
+ TNode<PropertyCell> cell = PromiseSpeciesProtectorConstant();
+ TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
+ return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsPrototypeInitialArrayPrototype(
SloppyTNode<Context> context, SloppyTNode<Map> map) {
- Node* const native_context = LoadNativeContext(context);
- Node* const initial_array_prototype = LoadContextElement(
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
+ TNode<Object> const initial_array_prototype = LoadContextElement(
native_context, Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
- Node* proto = LoadMapPrototype(map);
- return WordEqual(proto, initial_array_prototype);
+ TNode<HeapObject> proto = LoadMapPrototype(map);
+ return TaggedEqual(proto, initial_array_prototype);
}
TNode<BoolT> CodeStubAssembler::IsPrototypeTypedArrayPrototype(
SloppyTNode<Context> context, SloppyTNode<Map> map) {
- TNode<Context> const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TNode<Object> const typed_array_prototype =
LoadContextElement(native_context, Context::TYPED_ARRAY_PROTOTYPE_INDEX);
TNode<HeapObject> proto = LoadMapPrototype(map);
TNode<HeapObject> proto_of_proto = Select<HeapObject>(
IsJSObject(proto), [=] { return LoadMapPrototype(LoadMap(proto)); },
[=] { return NullConstant(); });
- return WordEqual(proto_of_proto, typed_array_prototype);
+ return TaggedEqual(proto_of_proto, typed_array_prototype);
}
TNode<BoolT> CodeStubAssembler::IsFastAliasedArgumentsMap(
TNode<Context> context, TNode<Map> map) {
- TNode<Context> const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TNode<Object> const arguments_map = LoadContextElement(
native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
- return WordEqual(arguments_map, map);
+ return TaggedEqual(arguments_map, map);
}
TNode<BoolT> CodeStubAssembler::IsSlowAliasedArgumentsMap(
TNode<Context> context, TNode<Map> map) {
- TNode<Context> const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TNode<Object> const arguments_map = LoadContextElement(
native_context, Context::SLOW_ALIASED_ARGUMENTS_MAP_INDEX);
- return WordEqual(arguments_map, map);
+ return TaggedEqual(arguments_map, map);
}
TNode<BoolT> CodeStubAssembler::IsSloppyArgumentsMap(TNode<Context> context,
TNode<Map> map) {
- TNode<Context> const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TNode<Object> const arguments_map =
LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
- return WordEqual(arguments_map, map);
+ return TaggedEqual(arguments_map, map);
}
TNode<BoolT> CodeStubAssembler::IsStrictArgumentsMap(TNode<Context> context,
TNode<Map> map) {
- TNode<Context> const native_context = LoadNativeContext(context);
+ TNode<NativeContext> const native_context = LoadNativeContext(context);
TNode<Object> const arguments_map =
LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
- return WordEqual(arguments_map, map);
+ return TaggedEqual(arguments_map, map);
}
TNode<BoolT> CodeStubAssembler::TaggedIsCallable(TNode<Object> object) {
@@ -6186,7 +6267,7 @@ TNode<BoolT> CodeStubAssembler::IsCallable(SloppyTNode<HeapObject> object) {
}
TNode<BoolT> CodeStubAssembler::IsCell(SloppyTNode<HeapObject> object) {
- return WordEqual(LoadMap(object), LoadRoot(RootIndex::kCellMap));
+ return TaggedEqual(LoadMap(object), CellMapConstant());
}
TNode<BoolT> CodeStubAssembler::IsCode(SloppyTNode<HeapObject> object) {
@@ -6389,7 +6470,7 @@ TNode<BoolT> CodeStubAssembler::IsJSAsyncGeneratorObject(
}
TNode<BoolT> CodeStubAssembler::IsContext(SloppyTNode<HeapObject> object) {
- Node* instance_type = LoadInstanceType(object);
+ TNode<Uint16T> instance_type = LoadInstanceType(object);
return UncheckedCast<BoolT>(Word32And(
Int32GreaterThanOrEqual(instance_type, Int32Constant(FIRST_CONTEXT_TYPE)),
Int32LessThanOrEqual(instance_type, Int32Constant(LAST_CONTEXT_TYPE))));
@@ -6401,7 +6482,7 @@ TNode<BoolT> CodeStubAssembler::IsFixedArray(SloppyTNode<HeapObject> object) {
TNode<BoolT> CodeStubAssembler::IsFixedArraySubclass(
SloppyTNode<HeapObject> object) {
- Node* instance_type = LoadInstanceType(object);
+ TNode<Uint16T> instance_type = LoadInstanceType(object);
return UncheckedCast<BoolT>(
Word32And(Int32GreaterThanOrEqual(instance_type,
Int32Constant(FIRST_FIXED_ARRAY_TYPE)),
@@ -6411,7 +6492,7 @@ TNode<BoolT> CodeStubAssembler::IsFixedArraySubclass(
TNode<BoolT> CodeStubAssembler::IsNotWeakFixedArraySubclass(
SloppyTNode<HeapObject> object) {
- Node* instance_type = LoadInstanceType(object);
+ TNode<Uint16T> instance_type = LoadInstanceType(object);
return UncheckedCast<BoolT>(Word32Or(
Int32LessThan(instance_type, Int32Constant(FIRST_WEAK_FIXED_ARRAY_TYPE)),
Int32GreaterThan(instance_type,
@@ -6459,7 +6540,8 @@ TNode<BoolT> CodeStubAssembler::IsFixedArrayWithKind(
if (IsDoubleElementsKind(kind)) {
return IsFixedDoubleArray(object);
} else {
- DCHECK(IsSmiOrObjectElementsKind(kind) || IsSealedElementsKind(kind));
+ DCHECK(IsSmiOrObjectElementsKind(kind) || IsSealedElementsKind(kind) ||
+ IsNonextensibleElementsKind(kind));
return IsFixedArraySubclass(object);
}
}
@@ -6485,12 +6567,6 @@ TNode<BoolT> CodeStubAssembler::IsAllocationSite(
return IsAllocationSiteInstanceType(LoadInstanceType(object));
}
-TNode<BoolT> CodeStubAssembler::IsAnyHeapNumber(
- SloppyTNode<HeapObject> object) {
- return UncheckedCast<BoolT>(
- Word32Or(IsMutableHeapNumber(object), IsHeapNumber(object)));
-}
-
TNode<BoolT> CodeStubAssembler::IsHeapNumber(SloppyTNode<HeapObject> object) {
return IsHeapNumberMap(LoadMap(object));
}
@@ -6509,11 +6585,6 @@ TNode<BoolT> CodeStubAssembler::IsOddballInstanceType(
return InstanceTypeEqual(instance_type, ODDBALL_TYPE);
}
-TNode<BoolT> CodeStubAssembler::IsMutableHeapNumber(
- SloppyTNode<HeapObject> object) {
- return IsMutableHeapNumberMap(LoadMap(object));
-}
-
TNode<BoolT> CodeStubAssembler::IsFeedbackCell(SloppyTNode<HeapObject> object) {
return HasInstanceType(object, FEEDBACK_CELL_TYPE);
}
@@ -6555,7 +6626,7 @@ TNode<BoolT> CodeStubAssembler::IsInternalizedStringInstanceType(
}
TNode<BoolT> CodeStubAssembler::IsUniqueName(TNode<HeapObject> object) {
- TNode<Int32T> instance_type = LoadInstanceType(object);
+ TNode<Uint16T> instance_type = LoadInstanceType(object);
return Select<BoolT>(
IsInternalizedStringInstanceType(instance_type),
[=] { return Int32TrueConstant(); },
@@ -6563,7 +6634,7 @@ TNode<BoolT> CodeStubAssembler::IsUniqueName(TNode<HeapObject> object) {
}
TNode<BoolT> CodeStubAssembler::IsUniqueNameNoIndex(TNode<HeapObject> object) {
- TNode<Int32T> instance_type = LoadInstanceType(object);
+ TNode<Uint16T> instance_type = LoadInstanceType(object);
return Select<BoolT>(
IsInternalizedStringInstanceType(instance_type),
[=] {
@@ -6608,16 +6679,16 @@ TNode<BoolT> CodeStubAssembler::IsPrivateName(SloppyTNode<Symbol> symbol) {
TNode<BoolT> CodeStubAssembler::IsNativeContext(
SloppyTNode<HeapObject> object) {
- return WordEqual(LoadMap(object), LoadRoot(RootIndex::kNativeContextMap));
+ return TaggedEqual(LoadMap(object), NativeContextMapConstant());
}
TNode<BoolT> CodeStubAssembler::IsFixedDoubleArray(
SloppyTNode<HeapObject> object) {
- return WordEqual(LoadMap(object), FixedDoubleArrayMapConstant());
+ return TaggedEqual(LoadMap(object), FixedDoubleArrayMapConstant());
}
TNode<BoolT> CodeStubAssembler::IsHashTable(SloppyTNode<HeapObject> object) {
- Node* instance_type = LoadInstanceType(object);
+ TNode<Uint16T> instance_type = LoadInstanceType(object);
return UncheckedCast<BoolT>(
Word32And(Int32GreaterThanOrEqual(instance_type,
Int32Constant(FIRST_HASH_TABLE_TYPE)),
@@ -6848,10 +6919,9 @@ TNode<Int32T> CodeStubAssembler::StringCharCodeAt(SloppyTNode<String> string,
ToDirectStringAssembler to_direct(state(), string);
to_direct.TryToDirect(&if_runtime);
- Node* const offset = IntPtrAdd(index, to_direct.offset());
- Node* const instance_type = to_direct.instance_type();
-
- Node* const string_data = to_direct.PointerToData(&if_runtime);
+ TNode<IntPtrT> const offset = IntPtrAdd(index, to_direct.offset());
+ TNode<Int32T> const instance_type = to_direct.instance_type();
+ TNode<RawPtrT> const string_data = to_direct.PointerToData(&if_runtime);
// Check if the {string} is a TwoByteSeqString or a OneByteSeqString.
Branch(IsOneByteStringInstanceType(instance_type), &if_stringisonebyte,
@@ -6874,9 +6944,9 @@ TNode<Int32T> CodeStubAssembler::StringCharCodeAt(SloppyTNode<String> string,
BIND(&if_runtime);
{
- Node* result = CallRuntime(Runtime::kStringCharCodeAt, NoContextConstant(),
- string, SmiTag(index));
- var_result = SmiToInt32(result);
+ TNode<Object> result = CallRuntime(
+ Runtime::kStringCharCodeAt, NoContextConstant(), string, SmiTag(index));
+ var_result = SmiToInt32(CAST(result));
Goto(&return_result);
}
@@ -6895,15 +6965,14 @@ TNode<String> CodeStubAssembler::StringFromSingleCharCode(TNode<Int32T> code) {
BIND(&if_codeisonebyte);
{
// Load the isolate wide single character string cache.
- TNode<FixedArray> cache =
- CAST(LoadRoot(RootIndex::kSingleCharacterStringCache));
+ TNode<FixedArray> cache = SingleCharacterStringCacheConstant();
TNode<IntPtrT> code_index = Signed(ChangeUint32ToWord(code));
// Check if we have an entry for the {code} in the single character string
// cache already.
Label if_entryisundefined(this, Label::kDeferred),
if_entryisnotundefined(this);
- Node* entry = UnsafeLoadFixedArrayElement(cache, code_index);
+ TNode<Object> entry = UnsafeLoadFixedArrayElement(cache, code_index);
Branch(IsUndefined(entry), &if_entryisundefined, &if_entryisnotundefined);
BIND(&if_entryisundefined);
@@ -6929,7 +6998,7 @@ TNode<String> CodeStubAssembler::StringFromSingleCharCode(TNode<Int32T> code) {
BIND(&if_codeistwobyte);
{
// Allocate a new SeqTwoByteString for {code}.
- Node* result = AllocateSeqTwoByteString(1);
+ TNode<String> result = AllocateSeqTwoByteString(1);
StoreNoWriteBarrier(
MachineRepresentation::kWord16, result,
IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code);
@@ -6960,7 +7029,7 @@ TNode<String> CodeStubAssembler::AllocAndCopyStringCharacters(
BIND(&one_byte_sequential);
{
TNode<String> result = AllocateSeqOneByteString(
- NoContextConstant(), Unsigned(TruncateIntPtrToInt32(character_count)));
+ Unsigned(TruncateIntPtrToInt32(character_count)));
CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
character_count, String::ONE_BYTE_ENCODING,
String::ONE_BYTE_ENCODING);
@@ -6972,7 +7041,7 @@ TNode<String> CodeStubAssembler::AllocAndCopyStringCharacters(
BIND(&two_byte_sequential);
{
TNode<String> result = AllocateSeqTwoByteString(
- NoContextConstant(), Unsigned(TruncateIntPtrToInt32(character_count)));
+ Unsigned(TruncateIntPtrToInt32(character_count)));
CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
character_count, String::TWO_BYTE_ENCODING,
String::TWO_BYTE_ENCODING);
@@ -7012,7 +7081,7 @@ TNode<String> CodeStubAssembler::SubString(TNode<String> string,
TNode<String> direct_string = to_direct.TryToDirect(&runtime);
TNode<IntPtrT> offset = IntPtrAdd(from, to_direct.offset());
- Node* const instance_type = to_direct.instance_type();
+ TNode<Int32T> const instance_type = to_direct.instance_type();
// The subject string can only be external or sequential string of either
// encoding at this point.
@@ -7070,7 +7139,8 @@ TNode<String> CodeStubAssembler::SubString(TNode<String> string,
// Handle external string.
BIND(&external_string);
{
- Node* const fake_sequential_string = to_direct.PointerToString(&runtime);
+ TNode<RawPtrT> const fake_sequential_string =
+ to_direct.PointerToString(&runtime);
var_result = AllocAndCopyStringCharacters(
fake_sequential_string, instance_type, offset, substr_length);
@@ -7125,21 +7195,13 @@ TNode<String> CodeStubAssembler::SubString(TNode<String> string,
}
ToDirectStringAssembler::ToDirectStringAssembler(
- compiler::CodeAssemblerState* state, Node* string, Flags flags)
+ compiler::CodeAssemblerState* state, TNode<String> string, Flags flags)
: CodeStubAssembler(state),
- var_string_(this, MachineRepresentation::kTagged, string),
- var_instance_type_(this, MachineRepresentation::kWord32),
- var_offset_(this, MachineType::PointerRepresentation()),
- var_is_external_(this, MachineRepresentation::kWord32),
- flags_(flags) {
- CSA_ASSERT(this, TaggedIsNotSmi(string));
- CSA_ASSERT(this, IsString(string));
-
- var_string_.Bind(string);
- var_offset_.Bind(IntPtrConstant(0));
- var_instance_type_.Bind(LoadInstanceType(string));
- var_is_external_.Bind(Int32Constant(0));
-}
+ var_string_(string, this),
+ var_instance_type_(LoadInstanceType(string), this),
+ var_offset_(IntPtrConstant(0), this),
+ var_is_external_(Int32Constant(0), this),
+ flags_(flags) {}
TNode<String> ToDirectStringAssembler::TryToDirect(Label* if_bailout) {
VariableList vars({&var_string_, &var_offset_, &var_instance_type_}, zone());
@@ -7165,7 +7227,7 @@ TNode<String> ToDirectStringAssembler::TryToDirect(Label* if_bailout) {
};
STATIC_ASSERT(arraysize(values) == arraysize(labels));
- Node* const representation = Word32And(
+ TNode<Int32T> const representation = Word32And(
var_instance_type_.value(), Int32Constant(kStringRepresentationMask));
Switch(representation, if_bailout, values, labels, arraysize(values));
}
@@ -7174,13 +7236,15 @@ TNode<String> ToDirectStringAssembler::TryToDirect(Label* if_bailout) {
// Flat cons strings have an empty second part.
BIND(&if_iscons);
{
- Node* const string = var_string_.value();
- GotoIfNot(IsEmptyString(LoadObjectField(string, ConsString::kSecondOffset)),
+ TNode<String> const string = var_string_.value();
+ GotoIfNot(IsEmptyString(
+ LoadObjectField<String>(string, ConsString::kSecondOffset)),
if_bailout);
- Node* const lhs = LoadObjectField(string, ConsString::kFirstOffset);
- var_string_.Bind(lhs);
- var_instance_type_.Bind(LoadInstanceType(lhs));
+ TNode<String> const lhs =
+ LoadObjectField<String>(string, ConsString::kFirstOffset);
+ var_string_ = lhs;
+ var_instance_type_ = LoadInstanceType(lhs);
Goto(&dispatch);
}
@@ -7191,14 +7255,15 @@ TNode<String> ToDirectStringAssembler::TryToDirect(Label* if_bailout) {
if (!FLAG_string_slices || (flags_ & kDontUnpackSlicedStrings)) {
Goto(if_bailout);
} else {
- Node* const string = var_string_.value();
- Node* const sliced_offset =
+ TNode<String> const string = var_string_.value();
+ TNode<IntPtrT> const sliced_offset =
LoadAndUntagObjectField(string, SlicedString::kOffsetOffset);
- var_offset_.Bind(IntPtrAdd(var_offset_.value(), sliced_offset));
+ var_offset_ = IntPtrAdd(var_offset_.value(), sliced_offset);
- Node* const parent = LoadObjectField(string, SlicedString::kParentOffset);
- var_string_.Bind(parent);
- var_instance_type_.Bind(LoadInstanceType(parent));
+ TNode<String> const parent =
+ LoadObjectField<String>(string, SlicedString::kParentOffset);
+ var_string_ = parent;
+ var_instance_type_ = LoadInstanceType(parent);
Goto(&dispatch);
}
@@ -7207,24 +7272,24 @@ TNode<String> ToDirectStringAssembler::TryToDirect(Label* if_bailout) {
// Thin string. Fetch the actual string.
BIND(&if_isthin);
{
- Node* const string = var_string_.value();
- Node* const actual_string =
- LoadObjectField(string, ThinString::kActualOffset);
- Node* const actual_instance_type = LoadInstanceType(actual_string);
+ TNode<String> const string = var_string_.value();
+ TNode<String> const actual_string =
+ LoadObjectField<String>(string, ThinString::kActualOffset);
+ TNode<Uint16T> const actual_instance_type = LoadInstanceType(actual_string);
- var_string_.Bind(actual_string);
- var_instance_type_.Bind(actual_instance_type);
+ var_string_ = actual_string;
+ var_instance_type_ = actual_instance_type;
Goto(&dispatch);
}
// External string.
BIND(&if_isexternal);
- var_is_external_.Bind(Int32Constant(1));
+ var_is_external_ = Int32Constant(1);
Goto(&out);
BIND(&out);
- return CAST(var_string_.value());
+ return var_string_.value();
}
TNode<RawPtrT> ToDirectStringAssembler::TryToSequential(
@@ -7253,7 +7318,7 @@ TNode<RawPtrT> ToDirectStringAssembler::TryToSequential(
GotoIf(IsUncachedExternalStringInstanceType(var_instance_type_.value()),
if_bailout);
- TNode<String> string = CAST(var_string_.value());
+ TNode<String> string = var_string_.value();
TNode<IntPtrT> result =
LoadObjectField<IntPtrT>(string, ExternalString::kResourceDataOffset);
if (ptr_kind == PTR_TO_STRING) {
@@ -7268,35 +7333,33 @@ TNode<RawPtrT> ToDirectStringAssembler::TryToSequential(
return var_result.value();
}
-void CodeStubAssembler::BranchIfCanDerefIndirectString(Node* string,
- Node* instance_type,
- Label* can_deref,
- Label* cannot_deref) {
- CSA_ASSERT(this, IsString(string));
- Node* representation =
+void CodeStubAssembler::BranchIfCanDerefIndirectString(
+ TNode<String> string, TNode<Int32T> instance_type, Label* can_deref,
+ Label* cannot_deref) {
+ TNode<Int32T> representation =
Word32And(instance_type, Int32Constant(kStringRepresentationMask));
GotoIf(Word32Equal(representation, Int32Constant(kThinStringTag)), can_deref);
GotoIf(Word32NotEqual(representation, Int32Constant(kConsStringTag)),
cannot_deref);
// Cons string.
- Node* rhs = LoadObjectField(string, ConsString::kSecondOffset);
+ TNode<String> rhs =
+ LoadObjectField<String>(string, ConsString::kSecondOffset);
GotoIf(IsEmptyString(rhs), can_deref);
Goto(cannot_deref);
}
-Node* CodeStubAssembler::DerefIndirectString(TNode<String> string,
- TNode<Int32T> instance_type,
- Label* cannot_deref) {
+TNode<String> CodeStubAssembler::DerefIndirectString(
+ TNode<String> string, TNode<Int32T> instance_type, Label* cannot_deref) {
Label deref(this);
BranchIfCanDerefIndirectString(string, instance_type, &deref, cannot_deref);
BIND(&deref);
STATIC_ASSERT(static_cast<int>(ThinString::kActualOffset) ==
static_cast<int>(ConsString::kFirstOffset));
- return LoadObjectField(string, ThinString::kActualOffset);
+ return LoadObjectField<String>(string, ThinString::kActualOffset);
}
-void CodeStubAssembler::DerefIndirectString(Variable* var_string,
- Node* instance_type) {
+void CodeStubAssembler::DerefIndirectString(TVariable<String>* var_string,
+ TNode<Int32T> instance_type) {
#ifdef DEBUG
Label can_deref(this), cannot_deref(this);
BranchIfCanDerefIndirectString(var_string->value(), instance_type, &can_deref,
@@ -7309,12 +7372,12 @@ void CodeStubAssembler::DerefIndirectString(Variable* var_string,
STATIC_ASSERT(static_cast<int>(ThinString::kActualOffset) ==
static_cast<int>(ConsString::kFirstOffset));
- var_string->Bind(
- LoadObjectField(var_string->value(), ThinString::kActualOffset));
+ *var_string =
+ LoadObjectField<String>(var_string->value(), ThinString::kActualOffset);
}
-void CodeStubAssembler::MaybeDerefIndirectString(Variable* var_string,
- Node* instance_type,
+void CodeStubAssembler::MaybeDerefIndirectString(TVariable<String>* var_string,
+ TNode<Int32T> instance_type,
Label* did_deref,
Label* cannot_deref) {
Label deref(this);
@@ -7328,11 +7391,10 @@ void CodeStubAssembler::MaybeDerefIndirectString(Variable* var_string,
}
}
-void CodeStubAssembler::MaybeDerefIndirectStrings(Variable* var_left,
- Node* left_instance_type,
- Variable* var_right,
- Node* right_instance_type,
- Label* did_something) {
+void CodeStubAssembler::MaybeDerefIndirectStrings(
+ TVariable<String>* var_left, TNode<Int32T> left_instance_type,
+ TVariable<String>* var_right, TNode<Int32T> right_instance_type,
+ Label* did_something) {
Label did_nothing_left(this), did_something_left(this),
didnt_do_anything(this);
MaybeDerefIndirectString(var_left, left_instance_type, &did_something_left,
@@ -7397,13 +7459,13 @@ TNode<String> CodeStubAssembler::StringAdd(Node* context, TNode<String> left,
BIND(&non_cons);
Comment("Full string concatenate");
- Node* left_instance_type = LoadInstanceType(var_left.value());
- Node* right_instance_type = LoadInstanceType(var_right.value());
+ TNode<Int32T> left_instance_type = LoadInstanceType(var_left.value());
+ TNode<Int32T> right_instance_type = LoadInstanceType(var_right.value());
// Compute intersection and difference of instance types.
- Node* ored_instance_types =
+ TNode<Int32T> ored_instance_types =
Word32Or(left_instance_type, right_instance_type);
- Node* xored_instance_types =
+ TNode<Word32T> xored_instance_types =
Word32Xor(left_instance_type, right_instance_type);
// Check if both strings have the same encoding and both are sequential.
@@ -7419,7 +7481,7 @@ TNode<String> CodeStubAssembler::StringAdd(Node* context, TNode<String> left,
Int32Constant(kTwoByteStringTag)),
&two_byte);
// One-byte sequential string case
- result = AllocateSeqOneByteString(context, new_length);
+ result = AllocateSeqOneByteString(new_length);
CopyStringCharacters(var_left.value(), result.value(), IntPtrConstant(0),
IntPtrConstant(0), word_left_length,
String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING);
@@ -7431,7 +7493,7 @@ TNode<String> CodeStubAssembler::StringAdd(Node* context, TNode<String> left,
BIND(&two_byte);
{
// Two-byte sequential string case
- result = AllocateSeqTwoByteString(context, new_length);
+ result = AllocateSeqTwoByteString(new_length);
CopyStringCharacters(var_left.value(), result.value(), IntPtrConstant(0),
IntPtrConstant(0), word_left_length,
String::TWO_BYTE_ENCODING,
@@ -7484,7 +7546,7 @@ TNode<String> CodeStubAssembler::StringFromSingleUTF16EncodedCodePoint(
BIND(&if_isword32);
{
- Node* value = AllocateSeqTwoByteString(2);
+ TNode<String> value = AllocateSeqTwoByteString(2);
StoreNoWriteBarrier(
MachineRepresentation::kWord32, value,
IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag),
@@ -7530,12 +7592,12 @@ TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) {
done(this, &result);
// Load the number string cache.
- Node* number_string_cache = LoadRoot(RootIndex::kNumberStringCache);
+ TNode<FixedArray> number_string_cache = NumberStringCacheConstant();
// Make the hash mask from the length of the number string cache. It
// contains two elements (number and string) for each cache entry.
// TODO(ishell): cleanup mask handling.
- Node* mask =
+ TNode<IntPtrT> mask =
BitcastTaggedSignedToWord(LoadFixedArrayBaseLength(number_string_cache));
TNode<IntPtrT> one = IntPtrConstant(1);
mask = IntPtrSub(mask, one);
@@ -7546,6 +7608,7 @@ TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) {
BIND(&if_heap_number);
{
+ Comment("NumberToString - HeapNumber");
TNode<HeapNumber> heap_number_input = CAST(input);
// Try normalizing the HeapNumber.
TryHeapNumberToSmi(heap_number_input, smi_input, &if_smi);
@@ -7556,42 +7619,44 @@ TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) {
TNode<Int32T> high = LoadObjectField<Int32T>(
heap_number_input, HeapNumber::kValueOffset + kIntSize);
TNode<Word32T> hash = Word32Xor(low, high);
- TNode<WordT> word_hash = WordShl(ChangeInt32ToIntPtr(hash), one);
+ TNode<IntPtrT> word_hash = WordShl(ChangeInt32ToIntPtr(hash), one);
TNode<WordT> index =
WordAnd(word_hash, WordSar(mask, SmiShiftBitsConstant()));
// Cache entry's key must be a heap number
- Node* number_key =
- UnsafeLoadFixedArrayElement(CAST(number_string_cache), index);
+ TNode<Object> number_key =
+ UnsafeLoadFixedArrayElement(number_string_cache, index);
GotoIf(TaggedIsSmi(number_key), &runtime);
- GotoIfNot(IsHeapNumber(number_key), &runtime);
+ TNode<HeapObject> number_key_heap_object = CAST(number_key);
+ GotoIfNot(IsHeapNumber(number_key_heap_object), &runtime);
// Cache entry's key must match the heap number value we're looking for.
- Node* low_compare = LoadObjectField(number_key, HeapNumber::kValueOffset,
- MachineType::Int32());
- Node* high_compare = LoadObjectField(
- number_key, HeapNumber::kValueOffset + kIntSize, MachineType::Int32());
+ TNode<Int32T> low_compare = LoadObjectField<Int32T>(
+ number_key_heap_object, HeapNumber::kValueOffset);
+ TNode<Int32T> high_compare = LoadObjectField<Int32T>(
+ number_key_heap_object, HeapNumber::kValueOffset + kIntSize);
GotoIfNot(Word32Equal(low, low_compare), &runtime);
GotoIfNot(Word32Equal(high, high_compare), &runtime);
// Heap number match, return value from cache entry.
- result = CAST(UnsafeLoadFixedArrayElement(CAST(number_string_cache), index,
- kTaggedSize));
+ result = CAST(
+ UnsafeLoadFixedArrayElement(number_string_cache, index, kTaggedSize));
Goto(&done);
}
BIND(&if_smi);
{
+ Comment("NumberToString - Smi");
// Load the smi key, make sure it matches the smi we're looking for.
- Node* smi_index = BitcastWordToTagged(WordAnd(
+ TNode<Object> smi_index = BitcastWordToTagged(WordAnd(
WordShl(BitcastTaggedSignedToWord(smi_input.value()), one), mask));
- Node* smi_key = UnsafeLoadFixedArrayElement(CAST(number_string_cache),
- smi_index, 0, SMI_PARAMETERS);
- GotoIf(WordNotEqual(smi_key, smi_input.value()), &runtime);
+ TNode<Object> smi_key = UnsafeLoadFixedArrayElement(
+ number_string_cache, smi_index, 0, SMI_PARAMETERS);
+ GotoIf(TaggedNotEqual(smi_key, smi_input.value()), &runtime);
// Smi match, return value from cache entry.
- result = CAST(UnsafeLoadFixedArrayElement(
- CAST(number_string_cache), smi_index, kTaggedSize, SMI_PARAMETERS));
+ result = CAST(UnsafeLoadFixedArrayElement(number_string_cache, smi_index,
+ kTaggedSize, SMI_PARAMETERS));
Goto(&done);
}
@@ -7624,7 +7689,7 @@ Node* CodeStubAssembler::NonNumberToNumberOrNumeric(
Node* input = var_input.value();
// Dispatch on the {input} instance type.
- Node* input_instance_type = LoadInstanceType(input);
+ TNode<Uint16T> input_instance_type = LoadInstanceType(input);
Label if_inputisstring(this), if_inputisoddball(this),
if_inputisbigint(this), if_inputisreceiver(this, Label::kDeferred),
if_inputisother(this, Label::kDeferred);
@@ -7671,7 +7736,7 @@ Node* CodeStubAssembler::NonNumberToNumberOrNumeric(
// using the ToPrimitive type conversion, preferably yielding a Number.
Callable callable = CodeFactory::NonPrimitiveToPrimitive(
isolate(), ToPrimitiveHint::kNumber);
- Node* result = CallStub(callable, context, input);
+ TNode<Object> result = CallStub(callable, context, input);
// Check if the {result} is already a Number/Numeric.
Label if_done(this), if_notdone(this);
@@ -7833,9 +7898,9 @@ void CodeStubAssembler::TaggedToNumeric(Node* context, Node* value, Label* done,
var_numeric->Bind(value);
Label if_smi(this), if_heapnumber(this), if_bigint(this), if_oddball(this);
GotoIf(TaggedIsSmi(value), &if_smi);
- Node* map = LoadMap(value);
+ TNode<Map> map = LoadMap(value);
GotoIf(IsHeapNumberMap(map), &if_heapnumber);
- Node* instance_type = LoadMapInstanceType(map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
GotoIf(IsBigIntInstanceType(instance_type), &if_bigint);
// {value} is not a Numeric yet.
@@ -7865,8 +7930,9 @@ void CodeStubAssembler::TaggedToNumeric(Node* context, Node* value, Label* done,
// ES#sec-touint32
TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
SloppyTNode<Object> input) {
- Node* const float_zero = Float64Constant(0.0);
- Node* const float_two_32 = Float64Constant(static_cast<double>(1ULL << 32));
+ TNode<Float64T> const float_zero = Float64Constant(0.0);
+ TNode<Float64T> const float_two_32 =
+ Float64Constant(static_cast<double>(1ULL << 32));
Label out(this);
@@ -7881,7 +7947,7 @@ TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
BIND(&next);
}
- Node* const number = ToNumber(context, input);
+ TNode<Number> const number = ToNumber(context, input);
var_result.Bind(number);
// Perhaps we have a positive smi now.
@@ -7896,8 +7962,8 @@ TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
BIND(&if_isnegativesmi);
{
- Node* const uint32_value = SmiToInt32(number);
- Node* float64_value = ChangeUint32ToFloat64(uint32_value);
+ TNode<Int32T> const uint32_value = SmiToInt32(CAST(number));
+ TNode<Float64T> float64_value = ChangeUint32ToFloat64(uint32_value);
var_result.Bind(AllocateHeapNumberWithValue(float64_value));
Goto(&out);
}
@@ -7905,7 +7971,7 @@ TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
BIND(&if_isheapnumber);
{
Label return_zero(this);
- Node* const value = LoadHeapNumberValue(number);
+ TNode<Float64T> const value = LoadHeapNumberValue(CAST(number));
{
// +-0.
@@ -7924,7 +7990,7 @@ TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
{
// +Infinity.
Label next(this);
- Node* const positive_infinity =
+ TNode<Float64T> const positive_infinity =
Float64Constant(std::numeric_limits<double>::infinity());
Branch(Float64Equal(value, positive_infinity), &return_zero, &next);
BIND(&next);
@@ -7933,7 +7999,7 @@ TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
{
// -Infinity.
Label next(this);
- Node* const negative_infinity =
+ TNode<Float64T> const negative_infinity =
Float64Constant(-1.0 * std::numeric_limits<double>::infinity());
Branch(Float64Equal(value, negative_infinity), &return_zero, &next);
BIND(&next);
@@ -7944,12 +8010,12 @@ TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
// * Let int32bit be int modulo 2^32.
// * Return int32bit.
{
- Node* x = Float64Trunc(value);
+ TNode<Float64T> x = Float64Trunc(value);
x = Float64Mod(x, float_two_32);
x = Float64Add(x, float_two_32);
x = Float64Mod(x, float_two_32);
- Node* const result = ChangeFloat64ToTagged(x);
+ TNode<Number> const result = ChangeFloat64ToTagged(x);
var_result.Bind(result);
Goto(&out);
}
@@ -7981,31 +8047,6 @@ TNode<String> CodeStubAssembler::ToString_Inline(SloppyTNode<Context> context,
return CAST(var_result.value());
}
-Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) {
- Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this);
- VARIABLE(result, MachineRepresentation::kTagged);
- Label done(this, &result);
-
- BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver);
-
- BIND(&if_isreceiver);
- {
- // Convert {input} to a primitive first passing Number hint.
- Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate());
- result.Bind(CallStub(callable, context, input));
- Goto(&done);
- }
-
- BIND(&if_isnotreceiver);
- {
- result.Bind(input);
- Goto(&done);
- }
-
- BIND(&done);
- return result.value();
-}
-
TNode<JSReceiver> CodeStubAssembler::ToObject(SloppyTNode<Context> context,
SloppyTNode<Object> input) {
return CAST(CallBuiltin(Builtins::kToObject, context, input));
@@ -8152,7 +8193,7 @@ TNode<Number> CodeStubAssembler::ToInteger(SloppyTNode<Context> context,
{
TNode<HeapNumber> arg_hn = CAST(arg);
// Load the floating-point value of {arg}.
- Node* arg_value = LoadHeapNumberValue(arg_hn);
+ TNode<Float64T> arg_value = LoadHeapNumberValue(arg_hn);
// Check if {arg} is NaN.
GotoIfNot(Float64Equal(arg_value, arg_value), &return_zero);
@@ -8214,7 +8255,7 @@ TNode<WordT> CodeStubAssembler::UpdateWord(TNode<WordT> word,
void CodeStubAssembler::SetCounter(StatsCounter* counter, int value) {
if (FLAG_native_code_counters && counter->Enabled()) {
- Node* counter_address =
+ TNode<ExternalReference> counter_address =
ExternalConstant(ExternalReference::Create(counter));
StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address,
Int32Constant(value));
@@ -8224,7 +8265,7 @@ void CodeStubAssembler::SetCounter(StatsCounter* counter, int value) {
void CodeStubAssembler::IncrementCounter(StatsCounter* counter, int delta) {
DCHECK_GT(delta, 0);
if (FLAG_native_code_counters && counter->Enabled()) {
- Node* counter_address =
+ TNode<ExternalReference> counter_address =
ExternalConstant(ExternalReference::Create(counter));
// This operation has to be exactly 32-bit wide in case the external
// reference table redirects the counter to a uint32_t dummy_stats_counter_
@@ -8238,7 +8279,7 @@ void CodeStubAssembler::IncrementCounter(StatsCounter* counter, int delta) {
void CodeStubAssembler::DecrementCounter(StatsCounter* counter, int delta) {
DCHECK_GT(delta, 0);
if (FLAG_native_code_counters && counter->Enabled()) {
- Node* counter_address =
+ TNode<ExternalReference> counter_address =
ExternalConstant(ExternalReference::Create(counter));
// This operation has to be exactly 32-bit wide in case the external
// reference table redirects the counter to a uint32_t dummy_stats_counter_
@@ -8277,17 +8318,17 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
Goto(if_keyisindex);
BIND(&if_keyisnotindex);
- Node* key_map = LoadMap(key);
+ TNode<Map> key_map = LoadMap(key);
var_unique->Bind(key);
// Symbols are unique.
GotoIf(IsSymbolMap(key_map), if_keyisunique);
- Node* key_instance_type = LoadMapInstanceType(key_map);
+ TNode<Uint16T> key_instance_type = LoadMapInstanceType(key_map);
// Miss if |key| is not a String.
STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE);
GotoIfNot(IsStringInstanceType(key_instance_type), &if_keyisother);
// |key| is a String. Check if it has a cached array index.
- Node* hash = LoadNameHashField(key);
+ TNode<Uint32T> hash = LoadNameHashField(key);
GotoIf(IsClearWord32(hash, Name::kDoesNotContainCachedArrayIndexMask),
&if_hascachedindex);
// No cached array index. If the string knows that it contains an index,
@@ -8305,7 +8346,8 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
Goto(if_keyisunique);
BIND(&if_thinstring);
- var_unique->Bind(LoadObjectField(key, ThinString::kActualOffset));
+ var_unique->Bind(
+ LoadObjectField<String>(CAST(key), ThinString::kActualOffset));
Goto(if_keyisunique);
BIND(&if_hascachedindex);
@@ -8324,9 +8366,9 @@ void CodeStubAssembler::TryInternalizeString(
DCHECK(var_index->rep() == MachineType::PointerRepresentation());
DCHECK_EQ(var_internalized->rep(), MachineRepresentation::kTagged);
CSA_SLOW_ASSERT(this, IsString(string));
- Node* function =
+ TNode<ExternalReference> function =
ExternalConstant(ExternalReference::try_internalize_string_function());
- Node* const isolate_ptr =
+ TNode<ExternalReference> const isolate_ptr =
ExternalConstant(ExternalReference::isolate_address(isolate()));
Node* result =
CallCFunction(function, MachineType::AnyTagged(),
@@ -8334,10 +8376,10 @@ void CodeStubAssembler::TryInternalizeString(
std::make_pair(MachineType::AnyTagged(), string));
Label internalized(this);
GotoIf(TaggedIsNotSmi(result), &internalized);
- Node* word_result = SmiUntag(result);
- GotoIf(WordEqual(word_result, IntPtrConstant(ResultSentinel::kNotFound)),
+ TNode<IntPtrT> word_result = SmiUntag(result);
+ GotoIf(IntPtrEqual(word_result, IntPtrConstant(ResultSentinel::kNotFound)),
if_not_internalized);
- GotoIf(WordEqual(word_result, IntPtrConstant(ResultSentinel::kUnsupported)),
+ GotoIf(IntPtrEqual(word_result, IntPtrConstant(ResultSentinel::kUnsupported)),
if_bailout);
var_index->Bind(word_result);
Goto(if_index);
@@ -8461,8 +8503,8 @@ TNode<IntPtrT> CodeStubAssembler::IntPtrMax(SloppyTNode<IntPtrT> left,
SloppyTNode<IntPtrT> right) {
intptr_t left_constant;
intptr_t right_constant;
- if (ToIntPtrConstant(left, left_constant) &&
- ToIntPtrConstant(right, right_constant)) {
+ if (ToIntPtrConstant(left, &left_constant) &&
+ ToIntPtrConstant(right, &right_constant)) {
return IntPtrConstant(std::max(left_constant, right_constant));
}
return SelectConstant<IntPtrT>(IntPtrGreaterThanOrEqual(left, right), left,
@@ -8473,8 +8515,8 @@ TNode<IntPtrT> CodeStubAssembler::IntPtrMin(SloppyTNode<IntPtrT> left,
SloppyTNode<IntPtrT> right) {
intptr_t left_constant;
intptr_t right_constant;
- if (ToIntPtrConstant(left, left_constant) &&
- ToIntPtrConstant(right, right_constant)) {
+ if (ToIntPtrConstant(left, &left_constant) &&
+ ToIntPtrConstant(right, &right_constant)) {
return IntPtrConstant(std::min(left_constant, right_constant));
}
return SelectConstant<IntPtrT>(IntPtrLessThanOrEqual(left, right), left,
@@ -8508,13 +8550,13 @@ void CodeStubAssembler::NameDictionaryLookup(
CSA_ASSERT(this, IsUniqueName(unique_name));
TNode<IntPtrT> capacity = SmiUntag(GetCapacity<Dictionary>(dictionary));
- TNode<WordT> mask = IntPtrSub(capacity, IntPtrConstant(1));
- TNode<WordT> hash = ChangeUint32ToWord(LoadNameHash(unique_name));
+ TNode<IntPtrT> mask = IntPtrSub(capacity, IntPtrConstant(1));
+ TNode<UintPtrT> hash = ChangeUint32ToWord(LoadNameHash(unique_name));
// See Dictionary::FirstProbe().
TNode<IntPtrT> count = IntPtrConstant(0);
TNode<IntPtrT> entry = Signed(WordAnd(hash, mask));
- Node* undefined = UndefinedConstant();
+ TNode<Oddball> undefined = UndefinedConstant();
// Appease the variable merging algorithm for "Goto(&loop)" below.
*var_name_index = IntPtrConstant(0);
@@ -8533,13 +8575,13 @@ void CodeStubAssembler::NameDictionaryLookup(
TNode<HeapObject> current =
CAST(UnsafeLoadFixedArrayElement(dictionary, index));
- GotoIf(WordEqual(current, undefined), if_not_found);
+ GotoIf(TaggedEqual(current, undefined), if_not_found);
if (mode == kFindExisting) {
current = LoadName<Dictionary>(current);
- GotoIf(WordEqual(current, unique_name), if_found);
+ GotoIf(TaggedEqual(current, unique_name), if_found);
} else {
DCHECK_EQ(kFindInsertionIndex, mode);
- GotoIf(WordEqual(current, TheHoleConstant()), if_not_found);
+ GotoIf(TaggedEqual(current, TheHoleConstant()), if_not_found);
}
// See Dictionary::NextProbe().
@@ -8563,7 +8605,7 @@ template V8_EXPORT_PRIVATE void CodeStubAssembler::NameDictionaryLookup<
Node* CodeStubAssembler::ComputeUnseededHash(Node* key) {
// See v8::internal::ComputeUnseededHash()
- Node* hash = TruncateIntPtrToInt32(key);
+ TNode<Word32T> hash = TruncateIntPtrToInt32(key);
hash = Int32Add(Word32Xor(hash, Int32Constant(0xFFFFFFFF)),
Word32Shl(hash, Int32Constant(15)));
hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(12)));
@@ -8575,9 +8617,9 @@ Node* CodeStubAssembler::ComputeUnseededHash(Node* key) {
}
Node* CodeStubAssembler::ComputeSeededHash(Node* key) {
- Node* const function_addr =
+ TNode<ExternalReference> const function_addr =
ExternalConstant(ExternalReference::compute_integer_hash());
- Node* const isolate_ptr =
+ TNode<ExternalReference> const isolate_ptr =
ExternalConstant(ExternalReference::isolate_address(isolate()));
MachineType type_ptr = MachineType::Pointer();
@@ -8597,17 +8639,17 @@ void CodeStubAssembler::NumberDictionaryLookup(
Comment("NumberDictionaryLookup");
TNode<IntPtrT> capacity = SmiUntag(GetCapacity<NumberDictionary>(dictionary));
- TNode<WordT> mask = IntPtrSub(capacity, IntPtrConstant(1));
+ TNode<IntPtrT> mask = IntPtrSub(capacity, IntPtrConstant(1));
- TNode<WordT> hash = ChangeUint32ToWord(ComputeSeededHash(intptr_index));
+ TNode<UintPtrT> hash = ChangeUint32ToWord(ComputeSeededHash(intptr_index));
Node* key_as_float64 = RoundIntPtrToFloat64(intptr_index);
// See Dictionary::FirstProbe().
TNode<IntPtrT> count = IntPtrConstant(0);
TNode<IntPtrT> entry = Signed(WordAnd(hash, mask));
- Node* undefined = UndefinedConstant();
- Node* the_hole = TheHoleConstant();
+ TNode<Oddball> undefined = UndefinedConstant();
+ TNode<Oddball> the_hole = TheHoleConstant();
TVARIABLE(IntPtrT, var_count, count);
Variable* loop_vars[] = {&var_count, var_entry};
@@ -8619,22 +8661,22 @@ void CodeStubAssembler::NumberDictionaryLookup(
TNode<IntPtrT> entry = var_entry->value();
TNode<IntPtrT> index = EntryToIndex<NumberDictionary>(entry);
- Node* current = UnsafeLoadFixedArrayElement(dictionary, index);
- GotoIf(WordEqual(current, undefined), if_not_found);
+ TNode<Object> current = UnsafeLoadFixedArrayElement(dictionary, index);
+ GotoIf(TaggedEqual(current, undefined), if_not_found);
Label next_probe(this);
{
Label if_currentissmi(this), if_currentisnotsmi(this);
Branch(TaggedIsSmi(current), &if_currentissmi, &if_currentisnotsmi);
BIND(&if_currentissmi);
{
- Node* current_value = SmiUntag(current);
+ TNode<IntPtrT> current_value = SmiUntag(CAST(current));
Branch(WordEqual(current_value, intptr_index), if_found, &next_probe);
}
BIND(&if_currentisnotsmi);
{
- GotoIf(WordEqual(current, the_hole), &next_probe);
+ GotoIf(TaggedEqual(current, the_hole), &next_probe);
// Current must be the Number.
- Node* current_value = LoadHeapNumberValue(current);
+ TNode<Float64T> current_value = LoadHeapNumberValue(CAST(current));
Branch(Float64Equal(current_value, key_as_float64), if_found,
&next_probe);
}
@@ -8823,7 +8865,7 @@ void CodeStubAssembler::LookupLinear(TNode<Name> unique_name,
LoadArrayElement(array, Array::kHeaderSize, name_index);
TNode<Name> candidate_name = CAST(element);
*var_name_index = name_index;
- GotoIf(WordEqual(candidate_name, unique_name), if_found);
+ GotoIf(TaggedEqual(candidate_name, unique_name), if_found);
},
-Array::kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPre);
Goto(if_not_found);
@@ -8968,7 +9010,7 @@ void CodeStubAssembler::LookupBinary(TNode<Name> unique_name,
TNode<Uint32T> current_hash = LoadNameHashField(current_name);
GotoIf(Word32NotEqual(current_hash, hash), if_not_found);
Label next(this);
- GotoIf(WordNotEqual(current_name, unique_name), &next);
+ GotoIf(TaggedNotEqual(current_name, unique_name), &next);
GotoIf(Uint32GreaterThanOrEqual(sort_index, number_of_valid_entries),
if_not_found);
*var_name_index = ToKeyIndex<Array>(sort_index);
@@ -8984,7 +9026,7 @@ void CodeStubAssembler::ForEachEnumerableOwnProperty(
TNode<Context> context, TNode<Map> map, TNode<JSObject> object,
ForEachEnumerationMode mode, const ForEachKeyValueFunction& body,
Label* bailout) {
- TNode<Int32T> type = LoadMapInstanceType(map);
+ TNode<Uint16T> type = LoadMapInstanceType(map);
TNode<Uint32T> bit_field3 = EnsureOnlyHasSimpleProperties(map, type, bailout);
TNode<DescriptorArray> descriptors = LoadMapDescriptors(map);
@@ -9145,7 +9187,7 @@ void CodeStubAssembler::ForEachEnumerableOwnProperty(
// property details from preloaded |descriptors|.
var_stable = Select<BoolT>(
var_stable.value(),
- [=] { return WordEqual(LoadMap(object), map); },
+ [=] { return TaggedEqual(LoadMap(object), map); },
[=] { return Int32FalseConstant(); });
Goto(&next_iteration);
@@ -9322,7 +9364,7 @@ void CodeStubAssembler::TryHasOwnProperty(Node* object, Node* map,
Node* CodeStubAssembler::GetMethod(Node* context, Node* object,
Handle<Name> name,
Label* if_null_or_undefined) {
- Node* method = GetProperty(context, object, name);
+ TNode<Object> method = GetProperty(context, object, name);
GotoIf(IsUndefined(method), if_null_or_undefined);
GotoIf(IsNull(method), if_null_or_undefined);
@@ -9344,7 +9386,7 @@ void CodeStubAssembler::LoadPropertyFromFastObject(
DCHECK_EQ(MachineRepresentation::kWord32, var_details->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
- Node* details =
+ TNode<Uint32T> details =
LoadDetailsByKeyIndex(descriptors, UncheckedCast<IntPtrT>(name_index));
var_details->Bind(details);
@@ -9357,21 +9399,22 @@ void CodeStubAssembler::LoadPropertyFromFastObject(
Node* name_index, Node* details, Variable* var_value) {
Comment("[ LoadPropertyFromFastObject");
- Node* location = DecodeWord32<PropertyDetails::LocationField>(details);
+ TNode<Uint32T> location =
+ DecodeWord32<PropertyDetails::LocationField>(details);
Label if_in_field(this), if_in_descriptor(this), done(this);
Branch(Word32Equal(location, Int32Constant(kField)), &if_in_field,
&if_in_descriptor);
BIND(&if_in_field);
{
- Node* field_index =
- DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
- Node* representation =
+ TNode<IntPtrT> field_index =
+ Signed(DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details));
+ TNode<Uint32T> representation =
DecodeWord32<PropertyDetails::RepresentationField>(details);
field_index =
IntPtrAdd(field_index, LoadMapInobjectPropertiesStartInWords(map));
- Node* instance_size_in_words = LoadMapInstanceSizeInWords(map);
+ TNode<IntPtrT> instance_size_in_words = LoadMapInstanceSizeInWords(map);
Label if_inobject(this), if_backing_store(this);
VARIABLE(var_double_value, MachineRepresentation::kFloat64);
@@ -9381,7 +9424,7 @@ void CodeStubAssembler::LoadPropertyFromFastObject(
BIND(&if_inobject);
{
Comment("if_inobject");
- Node* field_offset = TimesTaggedSize(field_index);
+ TNode<IntPtrT> field_offset = TimesTaggedSize(field_index);
Label if_double(this), if_tagged(this);
Branch(Word32NotEqual(representation,
@@ -9398,8 +9441,9 @@ void CodeStubAssembler::LoadPropertyFromFastObject(
var_double_value.Bind(
LoadObjectField(object, field_offset, MachineType::Float64()));
} else {
- Node* mutable_heap_number = LoadObjectField(object, field_offset);
- var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
+ TNode<HeapNumber> heap_number =
+ CAST(LoadObjectField(object, field_offset));
+ var_double_value.Bind(LoadHeapNumberValue(heap_number));
}
Goto(&rebox_double);
}
@@ -9408,8 +9452,9 @@ void CodeStubAssembler::LoadPropertyFromFastObject(
{
Comment("if_backing_store");
TNode<HeapObject> properties = LoadFastProperties(object);
- field_index = IntPtrSub(field_index, instance_size_in_words);
- Node* value = LoadPropertyArrayElement(CAST(properties), field_index);
+ field_index = Signed(IntPtrSub(field_index, instance_size_in_words));
+ TNode<Object> value =
+ LoadPropertyArrayElement(CAST(properties), field_index);
Label if_double(this), if_tagged(this);
Branch(Word32NotEqual(representation,
@@ -9422,14 +9467,15 @@ void CodeStubAssembler::LoadPropertyFromFastObject(
}
BIND(&if_double);
{
- var_double_value.Bind(LoadHeapNumberValue(value));
+ var_double_value.Bind(LoadHeapNumberValue(CAST(value)));
Goto(&rebox_double);
}
}
BIND(&rebox_double);
{
Comment("rebox_double");
- Node* heap_number = AllocateHeapNumberWithValue(var_double_value.value());
+ TNode<HeapNumber> heap_number =
+ AllocateHeapNumberWithValue(var_double_value.value());
var_value->Bind(heap_number);
Goto(&done);
}
@@ -9467,15 +9513,16 @@ void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary,
Comment("[ LoadPropertyFromGlobalDictionary");
CSA_ASSERT(this, IsGlobalDictionary(dictionary));
- Node* property_cell = LoadFixedArrayElement(CAST(dictionary), name_index);
- CSA_ASSERT(this, IsPropertyCell(property_cell));
+ TNode<PropertyCell> property_cell =
+ CAST(LoadFixedArrayElement(CAST(dictionary), name_index));
- Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
- GotoIf(WordEqual(value, TheHoleConstant()), if_deleted);
+ TNode<Object> value =
+ LoadObjectField(property_cell, PropertyCell::kValueOffset);
+ GotoIf(TaggedEqual(value, TheHoleConstant()), if_deleted);
var_value->Bind(value);
- Node* details = LoadAndUntagToWord32ObjectField(
+ TNode<Int32T> details = LoadAndUntagToWord32ObjectField(
property_cell, PropertyCell::kPropertyDetailsRawOffset);
var_details->Bind(details);
@@ -9491,7 +9538,7 @@ TNode<Object> CodeStubAssembler::CallGetterIfAccessor(
VARIABLE(var_value, MachineRepresentation::kTagged, value);
Label done(this), if_accessor_info(this, Label::kDeferred);
- Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
+ TNode<Uint32T> kind = DecodeWord32<PropertyDetails::KindField>(details);
GotoIf(Word32Equal(kind, Int32Constant(kData)), &done);
// Accessor case.
@@ -9501,10 +9548,10 @@ TNode<Object> CodeStubAssembler::CallGetterIfAccessor(
{
if (mode == kCallJSGetter) {
Node* accessor_pair = value;
- Node* getter =
- LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
- Node* getter_map = LoadMap(getter);
- Node* instance_type = LoadMapInstanceType(getter_map);
+ TNode<HeapObject> getter =
+ CAST(LoadObjectField(accessor_pair, AccessorPair::kGetterOffset));
+ TNode<Map> getter_map = LoadMap(getter);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(getter_map);
// FunctionTemplateInfo getters are not supported yet.
GotoIf(InstanceTypeEqual(instance_type, FUNCTION_TEMPLATE_INFO_TYPE),
if_bailout);
@@ -9530,8 +9577,8 @@ TNode<Object> CodeStubAssembler::CallGetterIfAccessor(
Label if_array(this), if_function(this), if_wrapper(this);
// Dispatch based on {receiver} instance type.
- Node* receiver_map = LoadMap(receiver);
- Node* receiver_instance_type = LoadMapInstanceType(receiver_map);
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> receiver_instance_type = LoadMapInstanceType(receiver_map);
GotoIf(IsJSArrayInstanceType(receiver_instance_type), &if_array);
GotoIf(IsJSFunctionInstanceType(receiver_instance_type), &if_function);
Branch(IsJSPrimitiveWrapperInstanceType(receiver_instance_type),
@@ -9556,9 +9603,9 @@ TNode<Object> CodeStubAssembler::CallGetterIfAccessor(
LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
if_bailout);
- GotoIfPrototypeRequiresRuntimeLookup(CAST(receiver), CAST(receiver_map),
+ GotoIfPrototypeRequiresRuntimeLookup(CAST(receiver), receiver_map,
if_bailout);
- var_value.Bind(LoadJSFunctionPrototype(receiver, if_bailout));
+ var_value.Bind(LoadJSFunctionPrototype(CAST(receiver), if_bailout));
Goto(&done);
}
@@ -9617,7 +9664,7 @@ void CodeStubAssembler::TryGetOwnProperty(
BIND(&if_found_fast);
{
TNode<DescriptorArray> descriptors = CAST(var_meta_storage.value());
- Node* name_index = var_entry.value();
+ TNode<IntPtrT> name_index = var_entry.value();
LoadPropertyFromFastObject(object, map, descriptors, name_index,
var_details, var_value);
@@ -9625,15 +9672,15 @@ void CodeStubAssembler::TryGetOwnProperty(
}
BIND(&if_found_dict);
{
- Node* dictionary = var_meta_storage.value();
- Node* entry = var_entry.value();
+ TNode<HeapObject> dictionary = var_meta_storage.value();
+ TNode<IntPtrT> entry = var_entry.value();
LoadPropertyFromNameDictionary(dictionary, entry, var_details, var_value);
Goto(&if_found);
}
BIND(&if_found_global);
{
- Node* dictionary = var_meta_storage.value();
- Node* entry = var_entry.value();
+ TNode<HeapObject> dictionary = var_meta_storage.value();
+ TNode<IntPtrT> entry = var_entry.value();
LoadPropertyFromGlobalDictionary(dictionary, entry, var_details, var_value,
if_not_found);
@@ -9646,8 +9693,9 @@ void CodeStubAssembler::TryGetOwnProperty(
if (var_raw_value) {
var_raw_value->Bind(var_value->value());
}
- Node* value = CallGetterIfAccessor(var_value->value(), var_details->value(),
- context, receiver, if_bailout, mode);
+ TNode<Object> value =
+ CallGetterIfAccessor(var_value->value(), var_details->value(), context,
+ receiver, if_bailout, mode);
var_value->Bind(value);
Goto(if_found_value);
}
@@ -9662,7 +9710,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
// Handle special objects in runtime.
GotoIf(IsSpecialReceiverInstanceType(instance_type), if_bailout);
- Node* elements_kind = LoadMapElementsKind(map);
+ TNode<Int32T> elements_kind = LoadMapElementsKind(map);
// TODO(verwaest): Support other elements kinds as well.
Label if_isobjectorsmi(this), if_isdouble(this), if_isdictionary(this),
@@ -9672,8 +9720,9 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
int32_t values[] = {
// Handled by {if_isobjectorsmi}.
PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_ELEMENTS, HOLEY_ELEMENTS,
- PACKED_SEALED_ELEMENTS, HOLEY_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS,
- HOLEY_FROZEN_ELEMENTS,
+ PACKED_NONEXTENSIBLE_ELEMENTS, PACKED_SEALED_ELEMENTS,
+ HOLEY_NONEXTENSIBLE_ELEMENTS, HOLEY_SEALED_ELEMENTS,
+ PACKED_FROZEN_ELEMENTS, HOLEY_FROZEN_ELEMENTS,
// Handled by {if_isdouble}.
PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS,
// Handled by {if_isdictionary}.
@@ -9700,7 +9749,8 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Label* labels[] = {
&if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi,
&if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi,
- &if_isobjectorsmi, &if_isobjectorsmi,
+ &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi,
+ &if_isobjectorsmi,
&if_isdouble, &if_isdouble,
&if_isdictionary,
&if_isfaststringwrapper,
@@ -9731,7 +9781,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
TNode<Object> element = UnsafeLoadFixedArrayElement(elements, intptr_index);
TNode<Oddball> the_hole = TheHoleConstant();
- Branch(WordEqual(element, the_hole), if_not_found, if_found);
+ Branch(TaggedEqual(element, the_hole), if_not_found, if_found);
}
BIND(&if_isdouble);
{
@@ -9761,7 +9811,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
CSA_ASSERT(this, HasInstanceType(object, JS_PRIMITIVE_WRAPPER_TYPE));
Node* string = LoadJSPrimitiveWrapperValue(object);
CSA_ASSERT(this, IsString(string));
- Node* length = LoadStringLengthAsWord(string);
+ TNode<IntPtrT> length = LoadStringLengthAsWord(string);
GotoIf(UintPtrLessThan(intptr_index, length), if_found);
Goto(&if_isobjectorsmi);
}
@@ -9770,7 +9820,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
CSA_ASSERT(this, HasInstanceType(object, JS_PRIMITIVE_WRAPPER_TYPE));
Node* string = LoadJSPrimitiveWrapperValue(object);
CSA_ASSERT(this, IsString(string));
- Node* length = LoadStringLengthAsWord(string);
+ TNode<IntPtrT> length = LoadStringLengthAsWord(string);
GotoIf(UintPtrLessThan(intptr_index, length), if_found);
Goto(&if_isdictionary);
}
@@ -9829,8 +9879,8 @@ void CodeStubAssembler::TryPrototypeChainLookup(
GotoIf(TaggedIsSmi(receiver), if_bailout);
CSA_ASSERT(this, TaggedIsNotSmi(object));
- Node* map = LoadMap(object);
- Node* instance_type = LoadMapInstanceType(map);
+ TNode<Map> map = LoadMap(object);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
{
Label if_objectisreceiver(this);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
@@ -9851,19 +9901,18 @@ void CodeStubAssembler::TryPrototypeChainLookup(
BIND(&if_iskeyunique);
{
- VARIABLE(var_holder, MachineRepresentation::kTagged, object);
- VARIABLE(var_holder_map, MachineRepresentation::kTagged, map);
- VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32,
- instance_type);
+ TVARIABLE(HeapObject, var_holder, CAST(object));
+ TVARIABLE(Map, var_holder_map, map);
+ TVARIABLE(Int32T, var_holder_instance_type, instance_type);
- Variable* merged_variables[] = {&var_holder, &var_holder_map,
- &var_holder_instance_type};
- Label loop(this, arraysize(merged_variables), merged_variables);
+ VariableList merged_variables(
+ {&var_holder, &var_holder_map, &var_holder_instance_type}, zone());
+ Label loop(this, merged_variables);
Goto(&loop);
BIND(&loop);
{
- Node* holder_map = var_holder_map.value();
- Node* holder_instance_type = var_holder_instance_type.value();
+ TNode<Map> holder_map = var_holder_map.value();
+ TNode<Int32T> holder_instance_type = var_holder_instance_type.value();
Label next_proto(this), check_integer_indexed_exotic(this);
lookup_property_in_holder(receiver, var_holder.value(), holder_map,
@@ -9882,29 +9931,28 @@ void CodeStubAssembler::TryPrototypeChainLookup(
BIND(&next_proto);
- Node* proto = LoadMapPrototype(holder_map);
+ TNode<HeapObject> proto = LoadMapPrototype(holder_map);
GotoIf(IsNull(proto), if_end);
- Node* map = LoadMap(proto);
- Node* instance_type = LoadMapInstanceType(map);
+ TNode<Map> map = LoadMap(proto);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
- var_holder.Bind(proto);
- var_holder_map.Bind(map);
- var_holder_instance_type.Bind(instance_type);
+ var_holder = proto;
+ var_holder_map = map;
+ var_holder_instance_type = instance_type;
Goto(&loop);
}
}
BIND(&if_keyisindex);
{
- VARIABLE(var_holder, MachineRepresentation::kTagged, object);
- VARIABLE(var_holder_map, MachineRepresentation::kTagged, map);
- VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32,
- instance_type);
+ TVARIABLE(HeapObject, var_holder, CAST(object));
+ TVARIABLE(Map, var_holder_map, map);
+ TVARIABLE(Int32T, var_holder_instance_type, instance_type);
- Variable* merged_variables[] = {&var_holder, &var_holder_map,
- &var_holder_instance_type};
- Label loop(this, arraysize(merged_variables), merged_variables);
+ VariableList merged_variables(
+ {&var_holder, &var_holder_map, &var_holder_instance_type}, zone());
+ Label loop(this, merged_variables);
Goto(&loop);
BIND(&loop);
{
@@ -9915,23 +9963,23 @@ void CodeStubAssembler::TryPrototypeChainLookup(
var_index.value(), &next_proto, if_bailout);
BIND(&next_proto);
- Node* proto = LoadMapPrototype(var_holder_map.value());
+ TNode<HeapObject> proto = LoadMapPrototype(var_holder_map.value());
GotoIf(IsNull(proto), if_end);
- Node* map = LoadMap(proto);
- Node* instance_type = LoadMapInstanceType(map);
+ TNode<Map> map = LoadMap(proto);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
- var_holder.Bind(proto);
- var_holder_map.Bind(map);
- var_holder_instance_type.Bind(instance_type);
+ var_holder = proto;
+ var_holder_map = map;
+ var_holder_instance_type = instance_type;
Goto(&loop);
}
}
}
Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object,
- Node* prototype) {
+ SloppyTNode<Object> prototype) {
CSA_ASSERT(this, TaggedIsNotSmi(object));
VARIABLE(var_result, MachineRepresentation::kTagged);
Label return_false(this), return_true(this),
@@ -9946,7 +9994,7 @@ Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object,
// Check if we can determine the prototype directly from the {object_map}.
Label if_objectisdirect(this), if_objectisspecial(this, Label::kDeferred);
Node* object_map = var_object_map.value();
- TNode<Int32T> object_instance_type = LoadMapInstanceType(object_map);
+ TNode<Uint16T> object_instance_type = LoadMapInstanceType(object_map);
Branch(IsSpecialReceiverInstanceType(object_instance_type),
&if_objectisspecial, &if_objectisdirect);
BIND(&if_objectisspecial);
@@ -9955,7 +10003,7 @@ Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object,
// if we need to use the if_objectisspecial path in the runtime.
GotoIf(InstanceTypeEqual(object_instance_type, JS_PROXY_TYPE),
&return_runtime);
- Node* object_bitfield = LoadMapBitField(object_map);
+ TNode<Int32T> object_bitfield = LoadMapBitField(object_map);
int mask = Map::HasNamedInterceptorBit::kMask |
Map::IsAccessCheckNeededBit::kMask;
Branch(IsSetWord32(object_bitfield, mask), &return_runtime,
@@ -9964,9 +10012,9 @@ Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node* object,
BIND(&if_objectisdirect);
// Check the current {object} prototype.
- Node* object_prototype = LoadMapPrototype(object_map);
+ TNode<HeapObject> object_prototype = LoadMapPrototype(object_map);
GotoIf(IsNull(object_prototype), &return_false);
- GotoIf(WordEqual(object_prototype, prototype), &return_true);
+ GotoIf(TaggedEqual(object_prototype, prototype), &return_true);
// Continue with the prototype.
CSA_ASSERT(this, TaggedIsNotSmi(object_prototype));
@@ -10008,34 +10056,33 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
GotoIf(TaggedIsSmi(callable), &return_runtime);
// Load map of {callable}.
- Node* callable_map = LoadMap(callable);
+ TNode<Map> callable_map = LoadMap(callable);
// Goto runtime if {callable} is not a JSFunction.
- Node* callable_instance_type = LoadMapInstanceType(callable_map);
+ TNode<Uint16T> callable_instance_type = LoadMapInstanceType(callable_map);
GotoIfNot(InstanceTypeEqual(callable_instance_type, JS_FUNCTION_TYPE),
&return_runtime);
- GotoIfPrototypeRequiresRuntimeLookup(CAST(callable), CAST(callable_map),
+ GotoIfPrototypeRequiresRuntimeLookup(CAST(callable), callable_map,
&return_runtime);
// Get the "prototype" (or initial map) of the {callable}.
- Node* callable_prototype =
- LoadObjectField(callable, JSFunction::kPrototypeOrInitialMapOffset);
+ TNode<HeapObject> callable_prototype = LoadObjectField<HeapObject>(
+ CAST(callable), JSFunction::kPrototypeOrInitialMapOffset);
{
Label no_initial_map(this), walk_prototype_chain(this);
- VARIABLE(var_callable_prototype, MachineRepresentation::kTagged,
- callable_prototype);
+ TVARIABLE(HeapObject, var_callable_prototype, callable_prototype);
// Resolve the "prototype" if the {callable} has an initial map.
GotoIfNot(IsMap(callable_prototype), &no_initial_map);
- var_callable_prototype.Bind(
- LoadObjectField(callable_prototype, Map::kPrototypeOffset));
+ var_callable_prototype =
+ LoadObjectField<HeapObject>(callable_prototype, Map::kPrototypeOffset);
Goto(&walk_prototype_chain);
BIND(&no_initial_map);
// {callable_prototype} is the hole if the "prototype" property hasn't been
// requested so far.
- Branch(WordEqual(callable_prototype, TheHoleConstant()), &return_runtime,
+ Branch(TaggedEqual(callable_prototype, TheHoleConstant()), &return_runtime,
&walk_prototype_chain);
BIND(&walk_prototype_chain);
@@ -10077,7 +10124,7 @@ TNode<IntPtrT> CodeStubAssembler::ElementOffsetFromIndex(Node* index_node,
index_node = BitcastTaggedSignedToWord(index_node);
} else {
DCHECK(mode == INTPTR_PARAMETERS);
- constant_index = ToIntPtrConstant(index_node, index);
+ constant_index = ToIntPtrConstant(index_node, &index);
}
if (constant_index) {
return IntPtrConstant(base_size + element_size * index);
@@ -10107,8 +10154,8 @@ TNode<BoolT> CodeStubAssembler::IsOffsetInBounds(SloppyTNode<IntPtrT> offset,
TNode<HeapObject> CodeStubAssembler::LoadFeedbackCellValue(
SloppyTNode<JSFunction> closure) {
TNode<FeedbackCell> feedback_cell =
- CAST(LoadObjectField(closure, JSFunction::kFeedbackCellOffset));
- return CAST(LoadObjectField(feedback_cell, FeedbackCell::kValueOffset));
+ LoadObjectField<FeedbackCell>(closure, JSFunction::kFeedbackCellOffset);
+ return LoadObjectField<HeapObject>(feedback_cell, FeedbackCell::kValueOffset);
}
TNode<HeapObject> CodeStubAssembler::LoadFeedbackVector(
@@ -10218,26 +10265,23 @@ void CodeStubAssembler::CombineFeedback(Variable* existing_feedback,
SmiOr(CAST(existing_feedback->value()), CAST(feedback)));
}
-void CodeStubAssembler::CheckForAssociatedProtector(Node* name,
+void CodeStubAssembler::CheckForAssociatedProtector(SloppyTNode<Name> name,
Label* if_protector) {
// This list must be kept in sync with LookupIterator::UpdateProtector!
// TODO(jkummerow): Would it be faster to have a bit in Symbol::flags()?
- GotoIf(WordEqual(name, LoadRoot(RootIndex::kconstructor_string)),
- if_protector);
- GotoIf(WordEqual(name, LoadRoot(RootIndex::kiterator_symbol)), if_protector);
- GotoIf(WordEqual(name, LoadRoot(RootIndex::knext_string)), if_protector);
- GotoIf(WordEqual(name, LoadRoot(RootIndex::kspecies_symbol)), if_protector);
- GotoIf(WordEqual(name, LoadRoot(RootIndex::kis_concat_spreadable_symbol)),
- if_protector);
- GotoIf(WordEqual(name, LoadRoot(RootIndex::kresolve_string)), if_protector);
- GotoIf(WordEqual(name, LoadRoot(RootIndex::kthen_string)), if_protector);
+ GotoIf(TaggedEqual(name, ConstructorStringConstant()), if_protector);
+ GotoIf(TaggedEqual(name, IteratorSymbolConstant()), if_protector);
+ GotoIf(TaggedEqual(name, NextStringConstant()), if_protector);
+ GotoIf(TaggedEqual(name, SpeciesSymbolConstant()), if_protector);
+ GotoIf(TaggedEqual(name, IsConcatSpreadableSymbolConstant()), if_protector);
+ GotoIf(TaggedEqual(name, ResolveStringConstant()), if_protector);
+ GotoIf(TaggedEqual(name, ThenStringConstant()), if_protector);
// Fall through if no case matched.
}
TNode<Map> CodeStubAssembler::LoadReceiverMap(SloppyTNode<Object> receiver) {
return Select<Map>(
- TaggedIsSmi(receiver),
- [=] { return CAST(LoadRoot(RootIndex::kHeapNumberMap)); },
+ TaggedIsSmi(receiver), [=] { return HeapNumberMapConstant(); },
[=] { return LoadMap(UncheckedCast<HeapObject>(receiver)); });
}
@@ -10309,22 +10353,24 @@ Node* CodeStubAssembler::EmitKeyedSloppyArguments(
access_mode == ArgumentsAccessMode::kHas);
}
Label if_mapped(this), if_unmapped(this), end(this, &var_result);
- Node* intptr_two = IntPtrConstant(2);
- Node* adjusted_length = IntPtrSub(elements_length, intptr_two);
+ TNode<IntPtrT> intptr_two = IntPtrConstant(2);
+ TNode<WordT> adjusted_length = IntPtrSub(elements_length, intptr_two);
GotoIf(UintPtrGreaterThanOrEqual(key, adjusted_length), &if_unmapped);
TNode<Object> mapped_index =
LoadFixedArrayElement(elements, IntPtrAdd(key, intptr_two));
- Branch(WordEqual(mapped_index, TheHoleConstant()), &if_unmapped, &if_mapped);
+ Branch(TaggedEqual(mapped_index, TheHoleConstant()), &if_unmapped,
+ &if_mapped);
BIND(&if_mapped);
{
TNode<IntPtrT> mapped_index_intptr = SmiUntag(CAST(mapped_index));
TNode<Context> the_context = CAST(LoadFixedArrayElement(elements, 0));
if (access_mode == ArgumentsAccessMode::kLoad) {
- Node* result = LoadContextElement(the_context, mapped_index_intptr);
- CSA_ASSERT(this, WordNotEqual(result, TheHoleConstant()));
+ TNode<Object> result =
+ LoadContextElement(the_context, mapped_index_intptr);
+ CSA_ASSERT(this, TaggedNotEqual(result, TheHoleConstant()));
var_result.Bind(result);
} else if (access_mode == ArgumentsAccessMode::kHas) {
CSA_ASSERT(this, Word32BinaryNot(IsTheHole(LoadContextElement(
@@ -10340,7 +10386,7 @@ Node* CodeStubAssembler::EmitKeyedSloppyArguments(
{
TNode<HeapObject> backing_store_ho =
CAST(LoadFixedArrayElement(elements, 1));
- GotoIf(WordNotEqual(LoadMap(backing_store_ho), FixedArrayMapConstant()),
+ GotoIf(TaggedNotEqual(LoadMap(backing_store_ho), FixedArrayMapConstant()),
bailout);
TNode<FixedArray> backing_store = CAST(backing_store_ho);
@@ -10350,9 +10396,9 @@ Node* CodeStubAssembler::EmitKeyedSloppyArguments(
Label out_of_bounds(this);
GotoIf(UintPtrGreaterThanOrEqual(key, backing_store_length),
&out_of_bounds);
- Node* result = LoadFixedArrayElement(backing_store, key);
+ TNode<Object> result = LoadFixedArrayElement(backing_store, key);
var_result.Bind(
- SelectBooleanConstant(WordNotEqual(result, TheHoleConstant())));
+ SelectBooleanConstant(TaggedNotEqual(result, TheHoleConstant())));
Goto(&end);
BIND(&out_of_bounds);
@@ -10363,8 +10409,8 @@ Node* CodeStubAssembler::EmitKeyedSloppyArguments(
// The key falls into unmapped range.
if (access_mode == ArgumentsAccessMode::kLoad) {
- Node* result = LoadFixedArrayElement(backing_store, key);
- GotoIf(WordEqual(result, TheHoleConstant()), bailout);
+ TNode<Object> result = LoadFixedArrayElement(backing_store, key);
+ GotoIf(TaggedEqual(result, TheHoleConstant()), bailout);
var_result.Bind(result);
} else {
StoreFixedArrayElement(backing_store, key, value);
@@ -10379,7 +10425,7 @@ Node* CodeStubAssembler::EmitKeyedSloppyArguments(
TNode<Context> CodeStubAssembler::LoadScriptContext(
TNode<Context> context, TNode<IntPtrT> context_index) {
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<ScriptContextTable> script_context_table = CAST(
LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX));
@@ -10445,10 +10491,10 @@ void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind,
#endif
} else if (IsTypedArrayElementsKind(kind)) {
if (kind == UINT8_CLAMPED_ELEMENTS) {
- CSA_ASSERT(this,
- Word32Equal(value, Word32And(Int32Constant(0xFF), value)));
+ CSA_ASSERT(this, Word32Equal(UncheckedCast<Word32T>(value),
+ Word32And(Int32Constant(0xFF), value)));
}
- Node* offset = ElementOffsetFromIndex(index, kind, mode, 0);
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(index, kind, mode, 0);
// TODO(cbruni): Add OOB check once typed.
MachineRepresentation rep = ElementsKindToMachineRepresentation(kind);
StoreNoWriteBarrier(rep, elements, offset, value);
@@ -10466,8 +10512,8 @@ void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind,
Node* CodeStubAssembler::Int32ToUint8Clamped(Node* int32_value) {
Label done(this);
- Node* int32_zero = Int32Constant(0);
- Node* int32_255 = Int32Constant(255);
+ TNode<Int32T> int32_zero = Int32Constant(0);
+ TNode<Int32T> int32_255 = Int32Constant(255);
VARIABLE(var_value, MachineRepresentation::kWord32, int32_value);
GotoIf(Uint32LessThanOrEqual(int32_value, int32_255), &done);
var_value.Bind(int32_zero);
@@ -10485,7 +10531,7 @@ Node* CodeStubAssembler::Float64ToUint8Clamped(Node* float64_value) {
var_value.Bind(Int32Constant(255));
GotoIf(Float64LessThanOrEqual(Float64Constant(255.0), float64_value), &done);
{
- Node* rounded_value = Float64RoundToEven(float64_value);
+ TNode<Float64T> rounded_value = Float64RoundToEven(float64_value);
var_value.Bind(TruncateFloat64ToWord32(rounded_value));
Goto(&done);
}
@@ -10539,37 +10585,38 @@ Node* CodeStubAssembler::PrepareValueForWriteToTypedArray(
BIND(&if_heapnumber_or_oddball);
{
- Node* value = UncheckedCast<Float64T>(LoadObjectField(
+ TNode<Float64T> value = UncheckedCast<Float64T>(LoadObjectField(
var_input.value(), HeapNumber::kValueOffset, MachineType::Float64()));
if (rep == MachineRepresentation::kWord32) {
if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
- value = Float64ToUint8Clamped(value);
+ var_result.Bind(Float64ToUint8Clamped(value));
} else {
- value = TruncateFloat64ToWord32(value);
+ var_result.Bind(TruncateFloat64ToWord32(value));
}
} else if (rep == MachineRepresentation::kFloat32) {
- value = TruncateFloat64ToFloat32(value);
+ var_result.Bind(TruncateFloat64ToFloat32(value));
} else {
DCHECK_EQ(MachineRepresentation::kFloat64, rep);
+ var_result.Bind(value);
}
- var_result.Bind(value);
Goto(&done);
}
BIND(&if_smi);
{
- Node* value = SmiToInt32(var_input.value());
+ TNode<Int32T> value = SmiToInt32(var_input.value());
if (rep == MachineRepresentation::kFloat32) {
- value = RoundInt32ToFloat32(value);
+ var_result.Bind(RoundInt32ToFloat32(value));
} else if (rep == MachineRepresentation::kFloat64) {
- value = ChangeInt32ToFloat64(value);
+ var_result.Bind(ChangeInt32ToFloat64(value));
} else {
DCHECK_EQ(MachineRepresentation::kWord32, rep);
if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
- value = Int32ToUint8Clamped(value);
+ var_result.Bind(Int32ToUint8Clamped(value));
+ } else {
+ var_result.Bind(value);
}
}
- var_result.Bind(value);
Goto(&done);
}
@@ -10606,7 +10653,7 @@ void CodeStubAssembler::BigIntToRawBytes(TNode<BigInt> bigint,
if (!Is64()) {
*var_high = Unsigned(IntPtrSub(IntPtrConstant(0), var_high->value()));
Label no_carry(this);
- GotoIf(WordEqual(var_low->value(), IntPtrConstant(0)), &no_carry);
+ GotoIf(IntPtrEqual(var_low->value(), IntPtrConstant(0)), &no_carry);
*var_high = Unsigned(IntPtrSub(var_high->value(), IntPtrConstant(1)));
Goto(&no_carry);
BIND(&no_carry);
@@ -10623,9 +10670,10 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
Variable* maybe_converted_value) {
CSA_ASSERT(this, Word32BinaryNot(IsJSProxy(object)));
- Node* elements = LoadElements(object);
+ TNode<FixedArrayBase> elements = LoadElements(object);
if (!(IsSmiOrObjectElementsKind(elements_kind) ||
- IsSealedElementsKind(elements_kind))) {
+ IsSealedElementsKind(elements_kind) ||
+ IsNonextensibleElementsKind(elements_kind))) {
CSA_ASSERT(this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements))));
} else if (!IsCOWHandlingStoreMode(store_mode)) {
GotoIf(IsFixedCOWArrayMap(LoadMap(elements)), bailout);
@@ -10744,7 +10792,8 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
return;
}
DCHECK(IsFastElementsKind(elements_kind) ||
- IsSealedElementsKind(elements_kind));
+ IsSealedElementsKind(elements_kind) ||
+ IsNonextensibleElementsKind(elements_kind));
Node* length = SelectImpl(
IsJSArray(object), [=]() { return LoadJSArrayLength(object); },
@@ -10761,15 +10810,19 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
value = TryTaggedToFloat64(value, bailout);
}
- if (IsGrowStoreMode(store_mode) && !IsSealedElementsKind(elements_kind)) {
- elements = CheckForCapacityGrow(object, elements, elements_kind, length,
- intptr_key, parameter_mode, bailout);
+ if (IsGrowStoreMode(store_mode) &&
+ !(IsSealedElementsKind(elements_kind) ||
+ IsNonextensibleElementsKind(elements_kind))) {
+ elements =
+ CAST(CheckForCapacityGrow(object, elements, elements_kind, length,
+ intptr_key, parameter_mode, bailout));
} else {
GotoIfNot(UintPtrLessThan(intptr_key, length), bailout);
}
// Cannot store to a hole in holey sealed elements so bailout.
- if (elements_kind == HOLEY_SEALED_ELEMENTS) {
+ if (elements_kind == HOLEY_SEALED_ELEMENTS ||
+ elements_kind == HOLEY_NONEXTENSIBLE_ELEMENTS) {
TNode<Object> target_value =
LoadFixedArrayElement(CAST(elements), intptr_key);
GotoIf(IsTheHole(target_value), bailout);
@@ -10778,11 +10831,12 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
// If we didn't grow {elements}, it might still be COW, in which case we
// copy it now.
if (!(IsSmiOrObjectElementsKind(elements_kind) ||
- IsSealedElementsKind(elements_kind))) {
+ IsSealedElementsKind(elements_kind) ||
+ IsNonextensibleElementsKind(elements_kind))) {
CSA_ASSERT(this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements))));
} else if (IsCOWHandlingStoreMode(store_mode)) {
- elements = CopyElementsOnWrite(object, elements, elements_kind, length,
- parameter_mode, bailout);
+ elements = CAST(CopyElementsOnWrite(object, elements, elements_kind, length,
+ parameter_mode, bailout));
}
CSA_ASSERT(this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements))));
@@ -10790,8 +10844,10 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
}
Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements,
- ElementsKind kind, Node* length,
- Node* key, ParameterMode mode,
+ ElementsKind kind,
+ SloppyTNode<UintPtrT> length,
+ SloppyTNode<WordT> key,
+ ParameterMode mode,
Label* bailout) {
DCHECK(IsFastElementsKind(kind));
VARIABLE(checked_elements, MachineRepresentation::kTagged);
@@ -10826,12 +10882,12 @@ Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements,
BIND(&grow_bailout);
{
Node* tagged_key = mode == SMI_PARAMETERS
- ? key
- : ChangeInt32ToTagged(TruncateIntPtrToInt32(key));
- Node* maybe_elements = CallRuntime(
+ ? static_cast<Node*>(key)
+ : ChangeInt32ToTagged(TruncateWordToInt32(key));
+ TNode<Object> maybe_elements = CallRuntime(
Runtime::kGrowArrayElements, NoContextConstant(), object, tagged_key);
GotoIf(TaggedIsSmi(maybe_elements), bailout);
- CSA_ASSERT(this, IsFixedArrayWithKind(maybe_elements, kind));
+ CSA_ASSERT(this, IsFixedArrayWithKind(CAST(maybe_elements), kind));
checked_elements.Bind(maybe_elements);
Goto(&fits_capacity);
}
@@ -10839,7 +10895,7 @@ Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements,
BIND(&fits_capacity);
GotoIfNot(IsJSArray(object), &done);
- Node* new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode));
+ TNode<WordT> new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode));
StoreObjectFieldNoWriteBarrier(object, JSArray::kLengthOffset,
ParameterToTagged(new_length, mode));
Goto(&done);
@@ -10888,14 +10944,15 @@ void CodeStubAssembler::TransitionElementsKind(Node* object, Node* map,
if (!IsSimpleMapChangeTransition(from_kind, to_kind)) {
Comment("Non-simple map transition");
- Node* elements = LoadElements(object);
+ TNode<FixedArrayBase> elements = LoadElements(object);
Label done(this);
- GotoIf(WordEqual(elements, EmptyFixedArrayConstant()), &done);
+ GotoIf(TaggedEqual(elements, EmptyFixedArrayConstant()), &done);
// TODO(ishell): Use OptimalParameterMode().
ParameterMode mode = INTPTR_PARAMETERS;
- Node* elements_length = SmiUntag(LoadFixedArrayBaseLength(elements));
+ TNode<IntPtrT> elements_length =
+ SmiUntag(LoadFixedArrayBaseLength(elements));
Node* array_length = SelectImpl(
IsJSArray(object),
[=]() {
@@ -10978,7 +11035,7 @@ void CodeStubAssembler::TrapAllocationMemento(Node* object,
BIND(&map_check);
{
TNode<Object> memento_map = LoadObjectField(object, kMementoMapOffset);
- Branch(WordEqual(memento_map, LoadRoot(RootIndex::kAllocationMementoMap)),
+ Branch(TaggedEqual(memento_map, AllocationMementoMapConstant()),
memento_found, &no_memento_found);
}
BIND(&no_memento_found);
@@ -10992,7 +11049,7 @@ TNode<IntPtrT> CodeStubAssembler::PageFromAddress(TNode<IntPtrT> address) {
TNode<AllocationSite> CodeStubAssembler::CreateAllocationSiteInFeedbackVector(
SloppyTNode<FeedbackVector> feedback_vector, TNode<Smi> slot) {
TNode<IntPtrT> size = IntPtrConstant(AllocationSite::kSizeWithWeakNext);
- Node* site = Allocate(size, CodeStubAssembler::kPretenured);
+ TNode<HeapObject> site = Allocate(size, CodeStubAssembler::kPretenured);
StoreMapNoWriteBarrier(site, RootIndex::kAllocationSiteWithWeakNextMap);
// Should match AllocationSite::Initialize.
TNode<WordT> field = UpdateWord<AllocationSite::ElementsKindBits>(
@@ -11097,9 +11154,10 @@ Node* CodeStubAssembler::BuildFastLoop(
// to force the loop header check at the end of the loop and branch forward to
// it from the pre-header). The extra branch is slower in the case that the
// loop actually iterates.
- Node* first_check = WordEqual(var.value(), end_index);
+ TNode<BoolT> first_check =
+ IntPtrOrSmiEqual(var.value(), end_index, parameter_mode);
int32_t first_check_val;
- if (ToInt32Constant(first_check, first_check_val)) {
+ if (ToInt32Constant(first_check, &first_check_val)) {
if (first_check_val) return var.value();
Goto(&loop);
} else {
@@ -11115,7 +11173,8 @@ Node* CodeStubAssembler::BuildFastLoop(
if (advance_mode == IndexAdvanceMode::kPost) {
Increment(&var, increment, parameter_mode);
}
- Branch(WordNotEqual(var.value(), end_index), &loop, &after_loop);
+ Branch(IntPtrOrSmiNotEqual(var.value(), end_index, parameter_mode), &loop,
+ &after_loop);
}
BIND(&after_loop);
return var.value();
@@ -11132,25 +11191,25 @@ void CodeStubAssembler::BuildFastFixedArrayForEach(
CSA_SLOW_ASSERT(this, Word32Or(IsFixedArrayWithKind(fixed_array, kind),
IsPropertyArray(fixed_array)));
int32_t first_val;
- bool constant_first = ToInt32Constant(first_element_inclusive, first_val);
+ bool constant_first = ToInt32Constant(first_element_inclusive, &first_val);
int32_t last_val;
- bool constent_last = ToInt32Constant(last_element_exclusive, last_val);
+ bool constent_last = ToInt32Constant(last_element_exclusive, &last_val);
if (constant_first && constent_last) {
int delta = last_val - first_val;
DCHECK_GE(delta, 0);
if (delta <= kElementLoopUnrollThreshold) {
if (direction == ForEachDirection::kForward) {
for (int i = first_val; i < last_val; ++i) {
- Node* index = IntPtrConstant(i);
- Node* offset =
+ TNode<IntPtrT> index = IntPtrConstant(i);
+ TNode<IntPtrT> offset =
ElementOffsetFromIndex(index, kind, INTPTR_PARAMETERS,
FixedArray::kHeaderSize - kHeapObjectTag);
body(fixed_array, offset);
}
} else {
for (int i = last_val - 1; i >= first_val; --i) {
- Node* index = IntPtrConstant(i);
- Node* offset =
+ TNode<IntPtrT> index = IntPtrConstant(i);
+ TNode<IntPtrT> offset =
ElementOffsetFromIndex(index, kind, INTPTR_PARAMETERS,
FixedArray::kHeaderSize - kHeapObjectTag);
body(fixed_array, offset);
@@ -11160,10 +11219,10 @@ void CodeStubAssembler::BuildFastFixedArrayForEach(
}
}
- Node* start =
+ TNode<IntPtrT> start =
ElementOffsetFromIndex(first_element_inclusive, kind, mode,
FixedArray::kHeaderSize - kHeapObjectTag);
- Node* limit =
+ TNode<IntPtrT> limit =
ElementOffsetFromIndex(last_element_exclusive, kind, mode,
FixedArray::kHeaderSize - kHeapObjectTag);
if (direction == ForEachDirection::kReverse) std::swap(start, limit);
@@ -11191,7 +11250,7 @@ void CodeStubAssembler::InitializeFieldsWithRoot(Node* object,
CSA_SLOW_ASSERT(this, TaggedIsNotSmi(object));
start_offset = IntPtrAdd(start_offset, IntPtrConstant(-kHeapObjectTag));
end_offset = IntPtrAdd(end_offset, IntPtrConstant(-kHeapObjectTag));
- Node* root_value = LoadRoot(root_index);
+ TNode<Object> root_value = LoadRoot(root_index);
BuildFastLoop(
end_offset, start_offset,
[this, object, root_value](Node* current) {
@@ -11203,7 +11262,8 @@ void CodeStubAssembler::InitializeFieldsWithRoot(Node* object,
}
void CodeStubAssembler::BranchIfNumberRelationalComparison(
- Operation op, Node* left, Node* right, Label* if_true, Label* if_false) {
+ Operation op, SloppyTNode<Number> left, SloppyTNode<Number> right,
+ Label* if_true, Label* if_false) {
CSA_SLOW_ASSERT(this, IsNumber(left));
CSA_SLOW_ASSERT(this, IsNumber(right));
@@ -11246,25 +11306,22 @@ void CodeStubAssembler::BranchIfNumberRelationalComparison(
}
},
[&] {
- CSA_ASSERT(this, IsHeapNumber(right));
var_left_float = SmiToFloat64(smi_left);
- var_right_float = LoadHeapNumberValue(right);
+ var_right_float = LoadHeapNumberValue(CAST(right));
Goto(&do_float_comparison);
});
},
[&] {
- CSA_ASSERT(this, IsHeapNumber(left));
- var_left_float = LoadHeapNumberValue(left);
+ var_left_float = LoadHeapNumberValue(CAST(left));
Branch(
TaggedIsSmi(right),
[&] {
- var_right_float = SmiToFloat64(right);
+ var_right_float = SmiToFloat64(CAST(right));
Goto(&do_float_comparison);
},
[&] {
- CSA_ASSERT(this, IsHeapNumber(right));
- var_right_float = LoadHeapNumberValue(right);
+ var_right_float = LoadHeapNumberValue(CAST(right));
Goto(&do_float_comparison);
});
});
@@ -11327,8 +11384,10 @@ Operation Reverse(Operation op) {
}
} // anonymous namespace
-Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
- Node* right, Node* context,
+Node* CodeStubAssembler::RelationalComparison(Operation op,
+ SloppyTNode<Object> left,
+ SloppyTNode<Object> right,
+ SloppyTNode<Context> context,
Variable* var_type_feedback) {
Label return_true(this), return_false(this), do_float_comparison(this),
end(this);
@@ -11338,8 +11397,8 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
// We might need to loop several times due to ToPrimitive and/or ToNumeric
// conversions.
- VARIABLE(var_left, MachineRepresentation::kTagged, left);
- VARIABLE(var_right, MachineRepresentation::kTagged, right);
+ TVARIABLE(Object, var_left, left);
+ TVARIABLE(Object, var_right, right);
VariableList loop_variable_list({&var_left, &var_right}, zone());
if (var_type_feedback != nullptr) {
// Initialize the type feedback to None. The current feedback is combined
@@ -11364,9 +11423,9 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
if_right_bigint(this, Label::kDeferred),
if_right_not_numeric(this, Label::kDeferred);
GotoIf(TaggedIsSmi(right), &if_right_smi);
- Node* right_map = LoadMap(right);
+ TNode<Map> right_map = LoadMap(CAST(right));
GotoIf(IsHeapNumberMap(right_map), &if_right_heapnumber);
- Node* right_instance_type = LoadMapInstanceType(right_map);
+ TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map);
Branch(IsBigIntInstanceType(right_instance_type), &if_right_bigint,
&if_right_not_numeric);
@@ -11401,7 +11460,7 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
{
CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
var_left_float = SmiToFloat64(smi_left);
- var_right_float = LoadHeapNumberValue(right);
+ var_right_float = LoadHeapNumberValue(CAST(right));
Goto(&do_float_comparison);
}
@@ -11421,15 +11480,14 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
// dedicated ToPrimitive(right, hint Number) operation, as the
// ToNumeric(right) will by itself already invoke ToPrimitive with
// a Number hint.
- var_right.Bind(
- CallBuiltin(Builtins::kNonNumberToNumeric, context, right));
+ var_right = CallBuiltin(Builtins::kNonNumberToNumeric, context, right);
Goto(&loop);
}
}
BIND(&if_left_not_smi);
{
- Node* left_map = LoadMap(left);
+ TNode<Map> left_map = LoadMap(CAST(left));
Label if_right_smi(this), if_right_not_smi(this);
Branch(TaggedIsSmi(right), &if_right_smi, &if_right_not_smi);
@@ -11439,15 +11497,15 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
Label if_left_heapnumber(this), if_left_bigint(this, Label::kDeferred),
if_left_not_numeric(this, Label::kDeferred);
GotoIf(IsHeapNumberMap(left_map), &if_left_heapnumber);
- Node* left_instance_type = LoadMapInstanceType(left_map);
+ TNode<Uint16T> left_instance_type = LoadMapInstanceType(left_map);
Branch(IsBigIntInstanceType(left_instance_type), &if_left_bigint,
&if_left_not_numeric);
BIND(&if_left_heapnumber);
{
CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
- var_left_float = LoadHeapNumberValue(left);
- var_right_float = SmiToFloat64(right);
+ var_left_float = LoadHeapNumberValue(CAST(left));
+ var_right_float = SmiToFloat64(CAST(right));
Goto(&do_float_comparison);
}
@@ -11467,21 +11525,20 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
// dedicated ToPrimitive(left, hint Number) operation, as the
// ToNumeric(left) will by itself already invoke ToPrimitive with
// a Number hint.
- var_left.Bind(
- CallBuiltin(Builtins::kNonNumberToNumeric, context, left));
+ var_left = CallBuiltin(Builtins::kNonNumberToNumeric, context, left);
Goto(&loop);
}
}
BIND(&if_right_not_smi);
{
- Node* right_map = LoadMap(right);
+ TNode<Map> right_map = LoadMap(CAST(right));
Label if_left_heapnumber(this), if_left_bigint(this, Label::kDeferred),
if_left_string(this, Label::kDeferred),
if_left_other(this, Label::kDeferred);
GotoIf(IsHeapNumberMap(left_map), &if_left_heapnumber);
- Node* left_instance_type = LoadMapInstanceType(left_map);
+ TNode<Uint16T> left_instance_type = LoadMapInstanceType(left_map);
GotoIf(IsBigIntInstanceType(left_instance_type), &if_left_bigint);
Branch(IsStringInstanceType(left_instance_type), &if_left_string,
&if_left_other);
@@ -11491,8 +11548,8 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
Label if_right_heapnumber(this),
if_right_bigint(this, Label::kDeferred),
if_right_not_numeric(this, Label::kDeferred);
- GotoIf(WordEqual(right_map, left_map), &if_right_heapnumber);
- Node* right_instance_type = LoadMapInstanceType(right_map);
+ GotoIf(TaggedEqual(right_map, left_map), &if_right_heapnumber);
+ TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map);
Branch(IsBigIntInstanceType(right_instance_type), &if_right_bigint,
&if_right_not_numeric);
@@ -11500,8 +11557,8 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
{
CombineFeedback(var_type_feedback,
CompareOperationFeedback::kNumber);
- var_left_float = LoadHeapNumberValue(left);
- var_right_float = LoadHeapNumberValue(right);
+ var_left_float = LoadHeapNumberValue(CAST(left));
+ var_right_float = LoadHeapNumberValue(CAST(right));
Goto(&do_float_comparison);
}
@@ -11523,8 +11580,8 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
// dedicated ToPrimitive(right, hint Number) operation, as the
// ToNumeric(right) will by itself already invoke ToPrimitive with
// a Number hint.
- var_right.Bind(
- CallBuiltin(Builtins::kNonNumberToNumeric, context, right));
+ var_right =
+ CallBuiltin(Builtins::kNonNumberToNumeric, context, right);
Goto(&loop);
}
}
@@ -11534,7 +11591,7 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
Label if_right_heapnumber(this), if_right_bigint(this),
if_right_string(this), if_right_other(this);
GotoIf(IsHeapNumberMap(right_map), &if_right_heapnumber);
- Node* right_instance_type = LoadMapInstanceType(right_map);
+ TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map);
GotoIf(IsBigIntInstanceType(right_instance_type), &if_right_bigint);
Branch(IsStringInstanceType(right_instance_type), &if_right_string,
&if_right_other);
@@ -11578,15 +11635,15 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
// dedicated ToPrimitive(right, hint Number) operation, as the
// ToNumeric(right) will by itself already invoke ToPrimitive with
// a Number hint.
- var_right.Bind(
- CallBuiltin(Builtins::kNonNumberToNumeric, context, right));
+ var_right =
+ CallBuiltin(Builtins::kNonNumberToNumeric, context, right);
Goto(&loop);
}
}
BIND(&if_left_string);
{
- Node* right_instance_type = LoadMapInstanceType(right_map);
+ TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map);
Label if_right_not_string(this, Label::kDeferred);
GotoIfNot(IsStringInstanceType(right_instance_type),
@@ -11629,9 +11686,9 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
GotoIf(IsJSReceiverInstanceType(right_instance_type),
&if_right_receiver);
- var_left.Bind(
- CallBuiltin(Builtins::kNonNumberToNumeric, context, left));
- var_right.Bind(CallBuiltin(Builtins::kToNumeric, context, right));
+ var_left =
+ CallBuiltin(Builtins::kNonNumberToNumeric, context, left);
+ var_right = CallBuiltin(Builtins::kToNumeric, context, right);
Goto(&loop);
BIND(&if_right_bigint);
@@ -11646,7 +11703,7 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
{
Callable callable = CodeFactory::NonPrimitiveToPrimitive(
isolate(), ToPrimitiveHint::kNumber);
- var_right.Bind(CallStub(callable, context, right));
+ var_right = CallStub(callable, context, right);
Goto(&loop);
}
}
@@ -11665,7 +11722,7 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
&collect_any_feedback);
GotoIf(IsHeapNumberMap(right_map), &collect_oddball_feedback);
- Node* right_instance_type = LoadMapInstanceType(right_map);
+ TNode<Uint16T> right_instance_type = LoadMapInstanceType(right_map);
Branch(InstanceTypeEqual(right_instance_type, ODDBALL_TYPE),
&collect_oddball_feedback, &collect_any_feedback);
@@ -11694,16 +11751,15 @@ Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
GotoIf(IsJSReceiverInstanceType(left_instance_type),
&if_left_receiver);
- var_right.Bind(CallBuiltin(Builtins::kToNumeric, context, right));
- var_left.Bind(
- CallBuiltin(Builtins::kNonNumberToNumeric, context, left));
+ var_right = CallBuiltin(Builtins::kToNumeric, context, right);
+ var_left = CallBuiltin(Builtins::kNonNumberToNumeric, context, left);
Goto(&loop);
BIND(&if_left_receiver);
{
Callable callable = CodeFactory::NonPrimitiveToPrimitive(
isolate(), ToPrimitiveHint::kNumber);
- var_left.Bind(CallStub(callable, context, left));
+ var_left = CallStub(callable, context, left);
Goto(&loop);
}
}
@@ -11765,8 +11821,8 @@ TNode<Smi> CodeStubAssembler::CollectFeedbackForString(
return feedback;
}
-void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal,
- Label* if_notequal,
+void CodeStubAssembler::GenerateEqual_Same(SloppyTNode<Object> value,
+ Label* if_equal, Label* if_notequal,
Variable* var_type_feedback) {
// In case of abstract or strict equality checks, we need additional checks
// for NaN values because they are not considered equal, even if both the
@@ -11775,12 +11831,13 @@ void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal,
Label if_smi(this), if_heapnumber(this);
GotoIf(TaggedIsSmi(value), &if_smi);
- Node* value_map = LoadMap(value);
+ TNode<HeapObject> value_heapobject = CAST(value);
+ TNode<Map> value_map = LoadMap(value_heapobject);
GotoIf(IsHeapNumberMap(value_map), &if_heapnumber);
// For non-HeapNumbers, all we do is collect type feedback.
if (var_type_feedback != nullptr) {
- Node* instance_type = LoadMapInstanceType(value_map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(value_map);
Label if_string(this), if_receiver(this), if_oddball(this), if_symbol(this),
if_bigint(this);
@@ -11791,7 +11848,7 @@ void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal,
BIND(&if_string);
{
- CSA_ASSERT(this, IsString(value));
+ CSA_ASSERT(this, IsString(value_heapobject));
CombineFeedback(var_type_feedback,
CollectFeedbackForString(instance_type));
Goto(if_equal);
@@ -11799,28 +11856,28 @@ void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal,
BIND(&if_symbol);
{
- CSA_ASSERT(this, IsSymbol(value));
+ CSA_ASSERT(this, IsSymbol(value_heapobject));
CombineFeedback(var_type_feedback, CompareOperationFeedback::kSymbol);
Goto(if_equal);
}
BIND(&if_receiver);
{
- CSA_ASSERT(this, IsJSReceiver(value));
+ CSA_ASSERT(this, IsJSReceiver(value_heapobject));
CombineFeedback(var_type_feedback, CompareOperationFeedback::kReceiver);
Goto(if_equal);
}
BIND(&if_bigint);
{
- CSA_ASSERT(this, IsBigInt(value));
+ CSA_ASSERT(this, IsBigInt(value_heapobject));
CombineFeedback(var_type_feedback, CompareOperationFeedback::kBigInt);
Goto(if_equal);
}
BIND(&if_oddball);
{
- CSA_ASSERT(this, IsOddball(value));
+ CSA_ASSERT(this, IsOddball(value_heapobject));
Label if_boolean(this), if_not_boolean(this);
Branch(IsBooleanMap(value_map), &if_boolean, &if_not_boolean);
@@ -11832,7 +11889,7 @@ void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal,
BIND(&if_not_boolean);
{
- CSA_ASSERT(this, IsNullOrUndefined(value));
+ CSA_ASSERT(this, IsNullOrUndefined(value_heapobject));
CombineFeedback(var_type_feedback,
CompareOperationFeedback::kReceiverOrNullOrUndefined);
Goto(if_equal);
@@ -11845,7 +11902,7 @@ void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal,
BIND(&if_heapnumber);
{
CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
- Node* number_value = LoadHeapNumberValue(value);
+ TNode<Float64T> number_value = LoadHeapNumberValue(value_heapobject);
BranchIfFloat64IsNaN(number_value, if_notequal, if_equal);
}
@@ -11857,7 +11914,9 @@ void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal,
}
// ES6 section 7.2.12 Abstract Equality Comparison
-Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
+Node* CodeStubAssembler::Equal(SloppyTNode<Object> left,
+ SloppyTNode<Object> right,
+ SloppyTNode<Context> context,
Variable* var_type_feedback) {
// This is a slightly optimized version of Object::Equals. Whenever you
// change something functionality wise in here, remember to update the
@@ -11875,8 +11934,8 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
// We might need to loop several times due to ToPrimitive and/or ToNumber
// conversions.
- VARIABLE(var_left, MachineRepresentation::kTagged, left);
- VARIABLE(var_right, MachineRepresentation::kTagged, right);
+ TVARIABLE(Object, var_left, left);
+ TVARIABLE(Object, var_right, right);
VariableList loop_variable_list({&var_left, &var_right}, zone());
if (var_type_feedback != nullptr) {
// Initialize the type feedback to None. The current feedback will be
@@ -11892,7 +11951,7 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
right = var_right.value();
Label if_notsame(this);
- GotoIf(WordNotEqual(left, right), &if_notsame);
+ GotoIf(TaggedNotEqual(left, right), &if_notsame);
{
// {left} and {right} reference the exact same value, yet we need special
// treatment for HeapNumber, as NaN is not equal to NaN.
@@ -11918,7 +11977,7 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
}
BIND(&if_right_not_smi);
- Node* right_map = LoadMap(right);
+ TNode<Map> right_map = LoadMap(CAST(right));
Label if_right_heapnumber(this), if_right_boolean(this),
if_right_bigint(this, Label::kDeferred),
if_right_receiver(this, Label::kDeferred);
@@ -11928,7 +11987,7 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kAny));
}
GotoIf(IsBooleanMap(right_map), &if_right_boolean);
- Node* right_type = LoadMapInstanceType(right_map);
+ TNode<Uint16T> right_type = LoadMapInstanceType(right_map);
GotoIf(IsStringInstanceType(right_type), &do_right_stringtonumber);
GotoIf(IsBigIntInstanceType(right_type), &if_right_bigint);
Branch(IsJSReceiverInstanceType(right_type), &if_right_receiver,
@@ -11936,15 +11995,15 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
BIND(&if_right_heapnumber);
{
- var_left_float = SmiToFloat64(left);
- var_right_float = LoadHeapNumberValue(right);
+ var_left_float = SmiToFloat64(CAST(left));
+ var_right_float = LoadHeapNumberValue(CAST(right));
CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
Goto(&do_float_comparison);
}
BIND(&if_right_boolean);
{
- var_right.Bind(LoadObjectField(right, Oddball::kToNumberOffset));
+ var_right = LoadObjectField(CAST(right), Oddball::kToNumberOffset);
Goto(&loop);
}
@@ -11958,7 +12017,7 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
BIND(&if_right_receiver);
{
Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate());
- var_right.Bind(CallStub(callable, context, right));
+ var_right = CallStub(callable, context, right);
Goto(&loop);
}
}
@@ -11972,10 +12031,10 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
if_left_bigint(this, Label::kDeferred), if_left_oddball(this),
if_left_receiver(this);
- Node* left_map = LoadMap(left);
- Node* right_map = LoadMap(right);
- Node* left_type = LoadMapInstanceType(left_map);
- Node* right_type = LoadMapInstanceType(right_map);
+ TNode<Map> left_map = LoadMap(CAST(left));
+ TNode<Map> right_map = LoadMap(CAST(right));
+ TNode<Uint16T> left_type = LoadMapInstanceType(left_map);
+ TNode<Uint16T> right_type = LoadMapInstanceType(right_map);
GotoIf(IsStringInstanceType(left_type), &if_left_string);
GotoIf(IsSymbolInstanceType(left_type), &if_left_symbol);
@@ -11999,8 +12058,8 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
Label if_right_not_number(this);
GotoIf(Word32NotEqual(left_type, right_type), &if_right_not_number);
- var_left_float = LoadHeapNumberValue(left);
- var_right_float = LoadHeapNumberValue(right);
+ var_left_float = LoadHeapNumberValue(CAST(left));
+ var_right_float = LoadHeapNumberValue(CAST(right));
CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
Goto(&do_float_comparison);
@@ -12019,7 +12078,7 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
BIND(&if_right_boolean);
{
- var_right.Bind(LoadObjectField(right, Oddball::kToNumberOffset));
+ var_right = LoadObjectField(CAST(right), Oddball::kToNumberOffset);
Goto(&loop);
}
}
@@ -12072,7 +12131,7 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
var_type_feedback->Bind(
SmiConstant(CompareOperationFeedback::kAny));
}
- var_right.Bind(LoadObjectField(right, Oddball::kToNumberOffset));
+ var_right = LoadObjectField(CAST(right), Oddball::kToNumberOffset);
Goto(&loop);
}
}
@@ -12124,10 +12183,10 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
}
// If {right} is a Boolean too, it must be a different Boolean.
- GotoIf(WordEqual(right_map, left_map), &if_notequal);
+ GotoIf(TaggedEqual(right_map, left_map), &if_notequal);
// Otherwise, convert {left} to number and try again.
- var_left.Bind(LoadObjectField(left, Oddball::kToNumberOffset));
+ var_left = LoadObjectField(CAST(left), Oddball::kToNumberOffset);
Goto(&loop);
}
}
@@ -12210,7 +12269,7 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
SmiConstant(CompareOperationFeedback::kAny));
}
Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate());
- var_left.Bind(CallStub(callable, context, left));
+ var_left = CallStub(callable, context, left);
Goto(&loop);
}
}
@@ -12219,14 +12278,14 @@ Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
BIND(&do_right_stringtonumber);
{
- var_right.Bind(CallBuiltin(Builtins::kStringToNumber, context, right));
+ var_right = CallBuiltin(Builtins::kStringToNumber, context, right);
Goto(&loop);
}
BIND(&use_symmetry);
{
- var_left.Bind(right);
- var_right.Bind(left);
+ var_left = right;
+ var_right = left;
Goto(&loop);
}
}
@@ -12313,7 +12372,7 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(SloppyTNode<Object> lhs,
// Check if {lhs} and {rhs} refer to the same object.
Label if_same(this), if_notsame(this);
- Branch(WordEqual(lhs, rhs), &if_same, &if_notsame);
+ Branch(TaggedEqual(lhs, rhs), &if_same, &if_notsame);
BIND(&if_same);
{
@@ -12349,8 +12408,8 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(SloppyTNode<Object> lhs,
BIND(&if_rhsissmi);
{
// Convert {lhs} and {rhs} to floating point values.
- Node* lhs_value = LoadHeapNumberValue(CAST(lhs));
- Node* rhs_value = SmiToFloat64(CAST(rhs));
+ TNode<Float64T> lhs_value = LoadHeapNumberValue(CAST(lhs));
+ TNode<Float64T> rhs_value = SmiToFloat64(CAST(rhs));
CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
@@ -12371,8 +12430,8 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(SloppyTNode<Object> lhs,
BIND(&if_rhsisnumber);
{
// Convert {lhs} and {rhs} to floating point values.
- Node* lhs_value = LoadHeapNumberValue(CAST(lhs));
- Node* rhs_value = LoadHeapNumberValue(CAST(rhs));
+ TNode<Float64T> lhs_value = LoadHeapNumberValue(CAST(lhs));
+ TNode<Float64T> rhs_value = LoadHeapNumberValue(CAST(rhs));
CombineFeedback(var_type_feedback,
CompareOperationFeedback::kNumber);
@@ -12398,7 +12457,7 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(SloppyTNode<Object> lhs,
BIND(&if_rhsisnotsmi);
{
// Load the instance type of {lhs}.
- Node* lhs_instance_type = LoadMapInstanceType(lhs_map);
+ TNode<Uint16T> lhs_instance_type = LoadMapInstanceType(lhs_map);
// Check if {lhs} is a String.
Label if_lhsisstring(this, Label::kDeferred), if_lhsisnotstring(this);
@@ -12408,7 +12467,7 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(SloppyTNode<Object> lhs,
BIND(&if_lhsisstring);
{
// Load the instance type of {rhs}.
- Node* rhs_instance_type = LoadInstanceType(CAST(rhs));
+ TNode<Uint16T> rhs_instance_type = LoadInstanceType(CAST(rhs));
// Check if {rhs} is also a String.
Label if_rhsisstring(this, Label::kDeferred),
@@ -12591,15 +12650,17 @@ TNode<Oddball> CodeStubAssembler::StrictEqual(SloppyTNode<Object> lhs,
// ECMA#sec-samevalue
// This algorithm differs from the Strict Equality Comparison Algorithm in its
// treatment of signed zeroes and NaNs.
-void CodeStubAssembler::BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true,
- Label* if_false, SameValueMode mode) {
+void CodeStubAssembler::BranchIfSameValue(SloppyTNode<Object> lhs,
+ SloppyTNode<Object> rhs,
+ Label* if_true, Label* if_false,
+ SameValueMode mode) {
VARIABLE(var_lhs_value, MachineRepresentation::kFloat64);
VARIABLE(var_rhs_value, MachineRepresentation::kFloat64);
Label do_fcmp(this);
// Immediately jump to {if_true} if {lhs} == {rhs}, because - unlike
// StrictEqual - SameValue considers two NaNs to be equal.
- GotoIf(WordEqual(lhs, rhs), if_true);
+ GotoIf(TaggedEqual(lhs, rhs), if_true);
// Check if the {lhs} is a Smi.
Label if_lhsissmi(this), if_lhsisheapobject(this);
@@ -12610,9 +12671,9 @@ void CodeStubAssembler::BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true,
// Since {lhs} is a Smi, the comparison can only yield true
// iff the {rhs} is a HeapNumber with the same float64 value.
Branch(TaggedIsSmi(rhs), if_false, [&] {
- GotoIfNot(IsHeapNumber(rhs), if_false);
- var_lhs_value.Bind(SmiToFloat64(lhs));
- var_rhs_value.Bind(LoadHeapNumberValue(rhs));
+ GotoIfNot(IsHeapNumber(CAST(rhs)), if_false);
+ var_lhs_value.Bind(SmiToFloat64(CAST(lhs)));
+ var_rhs_value.Bind(LoadHeapNumberValue(CAST(rhs)));
Goto(&do_fcmp);
});
}
@@ -12625,9 +12686,9 @@ void CodeStubAssembler::BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true,
[&] {
// Since {rhs} is a Smi, the comparison can only yield true
// iff the {lhs} is a HeapNumber with the same float64 value.
- GotoIfNot(IsHeapNumber(lhs), if_false);
- var_lhs_value.Bind(LoadHeapNumberValue(lhs));
- var_rhs_value.Bind(SmiToFloat64(rhs));
+ GotoIfNot(IsHeapNumber(CAST(lhs)), if_false);
+ var_lhs_value.Bind(LoadHeapNumberValue(CAST(lhs)));
+ var_rhs_value.Bind(SmiToFloat64(CAST(rhs)));
Goto(&do_fcmp);
},
[&] {
@@ -12637,10 +12698,11 @@ void CodeStubAssembler::BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true,
// value.
Label if_lhsisheapnumber(this), if_lhsisstring(this),
if_lhsisbigint(this);
- Node* const lhs_map = LoadMap(lhs);
+ TNode<Map> const lhs_map = LoadMap(CAST(lhs));
GotoIf(IsHeapNumberMap(lhs_map), &if_lhsisheapnumber);
if (mode != SameValueMode::kNumbersOnly) {
- Node* const lhs_instance_type = LoadMapInstanceType(lhs_map);
+ TNode<Uint16T> const lhs_instance_type =
+ LoadMapInstanceType(lhs_map);
GotoIf(IsStringInstanceType(lhs_instance_type), &if_lhsisstring);
GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_lhsisbigint);
}
@@ -12648,9 +12710,9 @@ void CodeStubAssembler::BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true,
BIND(&if_lhsisheapnumber);
{
- GotoIfNot(IsHeapNumber(rhs), if_false);
- var_lhs_value.Bind(LoadHeapNumberValue(lhs));
- var_rhs_value.Bind(LoadHeapNumberValue(rhs));
+ GotoIfNot(IsHeapNumber(CAST(rhs)), if_false);
+ var_lhs_value.Bind(LoadHeapNumberValue(CAST(lhs)));
+ var_rhs_value.Bind(LoadHeapNumberValue(CAST(rhs)));
Goto(&do_fcmp);
}
@@ -12659,17 +12721,17 @@ void CodeStubAssembler::BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true,
{
// Now we can only yield true if {rhs} is also a String
// with the same sequence of characters.
- GotoIfNot(IsString(rhs), if_false);
- Node* const result = CallBuiltin(Builtins::kStringEqual,
- NoContextConstant(), lhs, rhs);
+ GotoIfNot(IsString(CAST(rhs)), if_false);
+ TNode<Object> const result = CallBuiltin(
+ Builtins::kStringEqual, NoContextConstant(), lhs, rhs);
Branch(IsTrue(result), if_true, if_false);
}
BIND(&if_lhsisbigint);
{
- GotoIfNot(IsBigInt(rhs), if_false);
- Node* const result = CallRuntime(Runtime::kBigIntEqualToBigInt,
- NoContextConstant(), lhs, rhs);
+ GotoIfNot(IsBigInt(CAST(rhs)), if_false);
+ TNode<Object> const result = CallRuntime(
+ Runtime::kBigIntEqualToBigInt, NoContextConstant(), lhs, rhs);
Branch(IsTrue(result), if_true, if_false);
}
}
@@ -12696,8 +12758,8 @@ void CodeStubAssembler::BranchIfSameNumberValue(TNode<Float64T> lhs_value,
// We still need to handle the case when {lhs} and {rhs} are -0.0 and
// 0.0 (or vice versa). Compare the high word to
// distinguish between the two.
- Node* const lhs_hi_word = Float64ExtractHighWord32(lhs_value);
- Node* const rhs_hi_word = Float64ExtractHighWord32(rhs_value);
+ TNode<Uint32T> const lhs_hi_word = Float64ExtractHighWord32(lhs_value);
+ TNode<Uint32T> const rhs_hi_word = Float64ExtractHighWord32(rhs_value);
// If x is +0 and y is -0, return false.
// If x is -0 and y is +0, return false.
@@ -12802,15 +12864,15 @@ Node* CodeStubAssembler::Typeof(Node* value) {
GotoIf(TaggedIsSmi(value), &return_number);
- Node* map = LoadMap(value);
+ TNode<Map> map = LoadMap(value);
GotoIf(IsHeapNumberMap(map), &return_number);
- Node* instance_type = LoadMapInstanceType(map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
GotoIf(InstanceTypeEqual(instance_type, ODDBALL_TYPE), &if_oddball);
- Node* callable_or_undetectable_mask = Word32And(
+ TNode<Int32T> callable_or_undetectable_mask = Word32And(
LoadMapBitField(map),
Int32Constant(Map::IsCallableBit::kMask | Map::IsUndetectableBit::kMask));
@@ -12839,7 +12901,7 @@ Node* CodeStubAssembler::Typeof(Node* value) {
BIND(&if_oddball);
{
- Node* type = LoadObjectField(value, Oddball::kTypeOfOffset);
+ TNode<Object> type = LoadObjectField(value, Oddball::kTypeOfOffset);
result_var.Bind(type);
Goto(&return_result);
}
@@ -12884,8 +12946,8 @@ TNode<Object> CodeStubAssembler::GetSuperConstructor(
TVARIABLE(Object, result);
TNode<Map> map = LoadMap(active_function);
- TNode<Object> prototype = LoadMapPrototype(map);
- TNode<Map> prototype_map = LoadMap(CAST(prototype));
+ TNode<HeapObject> prototype = LoadMapPrototype(map);
+ TNode<Map> prototype_map = LoadMap(prototype);
GotoIfNot(IsConstructorMap(prototype_map), &is_not_constructor);
result = prototype;
@@ -12918,7 +12980,7 @@ TNode<JSReceiver> CodeStubAssembler::SpeciesConstructor(
// 4. If Type(C) is not Object, throw a TypeError exception.
ThrowIfNotJSReceiver(context, constructor,
- MessageTemplate::kConstructorNotReceiver);
+ MessageTemplate::kConstructorNotReceiver, "");
// 5. Let S be ? Get(C, @@species).
TNode<Object> species =
@@ -12955,16 +13017,16 @@ Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable,
GotoIfNot(IsJSReceiver(callable), &if_notreceiver);
// Load the @@hasInstance property from {callable}.
- Node* inst_of_handler =
+ TNode<Object> inst_of_handler =
GetProperty(context, callable, HasInstanceSymbolConstant());
// Optimize for the likely case where {inst_of_handler} is the builtin
// Function.prototype[@@hasInstance] method, and emit a direct call in
// that case without any additional checking.
- Node* native_context = LoadNativeContext(context);
- Node* function_has_instance =
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<Object> function_has_instance =
LoadContextElement(native_context, Context::FUNCTION_HAS_INSTANCE_INDEX);
- GotoIfNot(WordEqual(inst_of_handler, function_has_instance),
+ GotoIfNot(TaggedEqual(inst_of_handler, function_has_instance),
&if_otherhandler);
{
// Call to Function.prototype[@@hasInstance] directly.
@@ -12996,7 +13058,7 @@ Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable,
GotoIfNot(IsCallable(callable), &if_notcallable);
// Use the OrdinaryHasInstance algorithm.
- Node* result =
+ TNode<Object> result =
CallBuiltin(Builtins::kOrdinaryHasInstance, context, callable, object);
var_result.Bind(result);
Goto(&return_result);
@@ -13195,10 +13257,10 @@ TNode<Number> CodeStubAssembler::BitwiseOp(Node* left32, Node* right32,
// ES #sec-createarrayiterator
TNode<JSArrayIterator> CodeStubAssembler::CreateArrayIterator(
TNode<Context> context, TNode<Object> object, IterationKind kind) {
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<Map> iterator_map = CAST(LoadContextElement(
native_context, Context::INITIAL_ARRAY_ITERATOR_MAP_INDEX));
- Node* iterator = Allocate(JSArrayIterator::kSize);
+ TNode<HeapObject> iterator = Allocate(JSArrayIterator::kSize);
StoreMapNoWriteBarrier(iterator, iterator_map);
StoreObjectFieldRoot(iterator, JSArrayIterator::kPropertiesOrHashOffset,
RootIndex::kEmptyFixedArray);
@@ -13218,10 +13280,10 @@ TNode<JSObject> CodeStubAssembler::AllocateJSIteratorResult(
SloppyTNode<Context> context, SloppyTNode<Object> value,
SloppyTNode<Oddball> done) {
CSA_ASSERT(this, IsBoolean(done));
- Node* native_context = LoadNativeContext(context);
- Node* map =
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<Object> map =
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
- Node* result = Allocate(JSIteratorResult::kSize);
+ TNode<HeapObject> result = Allocate(JSIteratorResult::kSize);
StoreMapNoWriteBarrier(result, map);
StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOrHashOffset,
RootIndex::kEmptyFixedArray);
@@ -13235,8 +13297,8 @@ TNode<JSObject> CodeStubAssembler::AllocateJSIteratorResult(
Node* CodeStubAssembler::AllocateJSIteratorResultForEntry(Node* context,
Node* key,
Node* value) {
- Node* native_context = LoadNativeContext(context);
- Node* length = SmiConstant(2);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ TNode<Smi> length = SmiConstant(2);
int const elements_size = FixedArray::SizeFor(2);
TNode<FixedArray> elements = UncheckedCast<FixedArray>(
Allocate(elements_size + JSArray::kSize + JSIteratorResult::kSize));
@@ -13245,7 +13307,7 @@ Node* CodeStubAssembler::AllocateJSIteratorResultForEntry(Node* context,
StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
StoreFixedArrayElement(elements, 0, key);
StoreFixedArrayElement(elements, 1, value);
- Node* array_map = LoadContextElement(
+ TNode<Object> array_map = LoadContextElement(
native_context, Context::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
TNode<HeapObject> array = InnerAllocate(elements, elements_size);
StoreMapNoWriteBarrier(array, array_map);
@@ -13253,7 +13315,7 @@ Node* CodeStubAssembler::AllocateJSIteratorResultForEntry(Node* context,
RootIndex::kEmptyFixedArray);
StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset, elements);
StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
- Node* iterator_map =
+ TNode<Object> iterator_map =
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
TNode<HeapObject> result = InnerAllocate(array, JSArray::kSize);
StoreMapNoWriteBarrier(result, iterator_map);
@@ -13340,7 +13402,7 @@ CodeStubArguments::CodeStubArguments(
argc_(argc),
base_(),
fp_(fp != nullptr ? fp : assembler_->LoadFramePointer()) {
- Node* offset = assembler_->ElementOffsetFromIndex(
+ TNode<IntPtrT> offset = assembler_->ElementOffsetFromIndex(
argc_, SYSTEM_POINTER_ELEMENTS, param_mode,
(StandardFrameConstants::kFixedSlotCountAboveFp - 1) *
kSystemPointerSize);
@@ -13365,7 +13427,7 @@ TNode<WordT> CodeStubArguments::AtIndexPtr(
using Node = compiler::Node;
Node* negated_index = assembler_->IntPtrOrSmiSub(
assembler_->IntPtrOrSmiConstant(0, mode), index, mode);
- Node* offset = assembler_->ElementOffsetFromIndex(
+ TNode<IntPtrT> offset = assembler_->ElementOffsetFromIndex(
negated_index, SYSTEM_POINTER_ELEMENTS, mode, 0);
return assembler_->IntPtrAdd(assembler_->UncheckedCast<IntPtrT>(base_),
offset);
@@ -13438,10 +13500,10 @@ void CodeStubArguments::ForEach(
DCHECK_EQ(mode, argc_mode_);
last = argc_;
}
- Node* start = assembler_->IntPtrSub(
+ TNode<IntPtrT> start = assembler_->IntPtrSub(
assembler_->UncheckedCast<IntPtrT>(base_),
assembler_->ElementOffsetFromIndex(first, SYSTEM_POINTER_ELEMENTS, mode));
- Node* end = assembler_->IntPtrSub(
+ TNode<IntPtrT> end = assembler_->IntPtrSub(
assembler_->UncheckedCast<IntPtrT>(base_),
assembler_->ElementOffsetFromIndex(last, SYSTEM_POINTER_ELEMENTS, mode));
assembler_->BuildFastLoop(
@@ -13510,13 +13572,15 @@ TNode<BoolT> CodeStubAssembler::IsHoleyFastElementsKind(
TNode<BoolT> CodeStubAssembler::IsHoleyFastElementsKindForRead(
TNode<Int32T> elements_kind) {
- CSA_ASSERT(this,
- Uint32LessThanOrEqual(elements_kind,
- Int32Constant(LAST_FROZEN_ELEMENTS_KIND)));
+ CSA_ASSERT(this, Uint32LessThanOrEqual(
+ elements_kind,
+ Int32Constant(LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND)));
STATIC_ASSERT(HOLEY_SMI_ELEMENTS == (PACKED_SMI_ELEMENTS | 1));
STATIC_ASSERT(HOLEY_ELEMENTS == (PACKED_ELEMENTS | 1));
STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == (PACKED_DOUBLE_ELEMENTS | 1));
+ STATIC_ASSERT(HOLEY_NONEXTENSIBLE_ELEMENTS ==
+ (PACKED_NONEXTENSIBLE_ELEMENTS | 1));
STATIC_ASSERT(HOLEY_SEALED_ELEMENTS == (PACKED_SEALED_ELEMENTS | 1));
STATIC_ASSERT(HOLEY_FROZEN_ELEMENTS == (PACKED_FROZEN_ELEMENTS | 1));
return IsSetWord32(elements_kind, 1);
@@ -13541,41 +13605,35 @@ TNode<BoolT> CodeStubAssembler::IsElementsKindInRange(
}
Node* CodeStubAssembler::IsDebugActive() {
- Node* is_debug_active = Load(
- MachineType::Uint8(),
+ TNode<Uint8T> is_debug_active = Load<Uint8T>(
ExternalConstant(ExternalReference::debug_is_active_address(isolate())));
return Word32NotEqual(is_debug_active, Int32Constant(0));
}
Node* CodeStubAssembler::IsPromiseHookEnabled() {
- Node* const promise_hook = Load(
- MachineType::Pointer(),
+ TNode<RawPtrT> const promise_hook = Load<RawPtrT>(
ExternalConstant(ExternalReference::promise_hook_address(isolate())));
return WordNotEqual(promise_hook, IntPtrConstant(0));
}
Node* CodeStubAssembler::HasAsyncEventDelegate() {
- Node* const async_event_delegate =
- Load(MachineType::Pointer(),
- ExternalConstant(
- ExternalReference::async_event_delegate_address(isolate())));
+ TNode<RawPtrT> const async_event_delegate = Load<RawPtrT>(ExternalConstant(
+ ExternalReference::async_event_delegate_address(isolate())));
return WordNotEqual(async_event_delegate, IntPtrConstant(0));
}
Node* CodeStubAssembler::IsPromiseHookEnabledOrHasAsyncEventDelegate() {
- Node* const promise_hook_or_async_event_delegate =
- Load(MachineType::Uint8(),
- ExternalConstant(
- ExternalReference::promise_hook_or_async_event_delegate_address(
- isolate())));
+ TNode<Uint8T> const promise_hook_or_async_event_delegate =
+ Load<Uint8T>(ExternalConstant(
+ ExternalReference::promise_hook_or_async_event_delegate_address(
+ isolate())));
return Word32NotEqual(promise_hook_or_async_event_delegate, Int32Constant(0));
}
Node* CodeStubAssembler::
IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() {
- Node* const promise_hook_or_debug_is_active_or_async_event_delegate = Load(
- MachineType::Uint8(),
- ExternalConstant(
+ TNode<Uint8T> const promise_hook_or_debug_is_active_or_async_event_delegate =
+ Load<Uint8T>(ExternalConstant(
ExternalReference::
promise_hook_or_debug_is_active_or_async_event_delegate_address(
isolate())));
@@ -13622,7 +13680,7 @@ TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode(
// Switch on data's instance type.
BIND(&check_instance_type);
- TNode<Int32T> data_type = LoadInstanceType(CAST(sfi_data));
+ TNode<Uint16T> data_type = LoadInstanceType(CAST(sfi_data));
int32_t case_values[] = {BYTECODE_ARRAY_TYPE,
WASM_EXPORTED_FUNCTION_DATA_TYPE,
@@ -13712,14 +13770,14 @@ Node* CodeStubAssembler::AllocateFunctionWithMapAndContext(Node* map,
Node* context) {
CSA_SLOW_ASSERT(this, IsMap(map));
- Node* const code = GetSharedFunctionInfoCode(shared_info);
+ TNode<Code> const code = GetSharedFunctionInfoCode(shared_info);
// TODO(ishell): All the callers of this function pass map loaded from
// Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX. So we can remove
// map parameter.
CSA_ASSERT(this, Word32BinaryNot(IsConstructorMap(map)));
CSA_ASSERT(this, Word32BinaryNot(IsFunctionWithPrototypeSlotMap(map)));
- Node* const fun = Allocate(JSFunction::kSizeWithoutPrototype);
+ TNode<HeapObject> const fun = Allocate(JSFunction::kSizeWithoutPrototype);
STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kTaggedSize);
StoreMapNoWriteBarrier(fun, map);
StoreObjectFieldRoot(fun, JSObject::kPropertiesOrHashOffset,
@@ -13756,14 +13814,16 @@ void CodeStubAssembler::CheckPrototypeEnumCache(Node* receiver,
// backing store.
STATIC_ASSERT(static_cast<int>(JSObject::kElementsOffset) ==
static_cast<int>(JSProxy::kTargetOffset));
- Node* object_elements = LoadObjectField(object, JSObject::kElementsOffset);
+ TNode<Object> object_elements =
+ LoadObjectField(object, JSObject::kElementsOffset);
GotoIf(IsEmptyFixedArray(object_elements), &if_no_elements);
GotoIf(IsEmptySlowElementDictionary(object_elements), &if_no_elements);
// It might still be an empty JSArray.
GotoIfNot(IsJSArrayMap(object_map), if_slow);
- Node* object_length = LoadJSArrayLength(object);
- Branch(WordEqual(object_length, SmiConstant(0)), &if_no_elements, if_slow);
+ TNode<Number> object_length = LoadJSArrayLength(object);
+ Branch(TaggedEqual(object_length, SmiConstant(0)), &if_no_elements,
+ if_slow);
// Continue with the {object}s prototype.
BIND(&if_no_elements);
@@ -13774,7 +13834,7 @@ void CodeStubAssembler::CheckPrototypeEnumCache(Node* receiver,
var_object.Bind(object);
object_map = LoadMap(object);
var_object_map.Bind(object_map);
- Node* object_enum_length = LoadMapEnumLength(object_map);
+ TNode<WordT> object_enum_length = LoadMapEnumLength(object_map);
Branch(WordEqual(object_enum_length, IntPtrConstant(0)), &loop, if_slow);
}
}
@@ -13782,11 +13842,11 @@ void CodeStubAssembler::CheckPrototypeEnumCache(Node* receiver,
Node* CodeStubAssembler::CheckEnumCache(Node* receiver, Label* if_empty,
Label* if_runtime) {
Label if_fast(this), if_cache(this), if_no_cache(this, Label::kDeferred);
- Node* receiver_map = LoadMap(receiver);
+ TNode<Map> receiver_map = LoadMap(receiver);
// Check if the enum length field of the {receiver} is properly initialized,
// indicating that there is an enum cache.
- Node* receiver_enum_length = LoadMapEnumLength(receiver_map);
+ TNode<WordT> receiver_enum_length = LoadMapEnumLength(receiver_map);
Branch(WordEqual(receiver_enum_length,
IntPtrConstant(kInvalidEnumCacheSentinel)),
&if_no_cache, &if_cache);
@@ -13797,7 +13857,7 @@ Node* CodeStubAssembler::CheckEnumCache(Node* receiver, Label* if_empty,
GotoIfNot(IsDictionaryMap(receiver_map), if_runtime);
TNode<NameDictionary> properties = CAST(LoadSlowProperties(receiver));
TNode<Smi> length = GetNumberOfElements(properties);
- GotoIfNot(WordEqual(length, SmiConstant(0)), if_runtime);
+ GotoIfNot(TaggedEqual(length, SmiConstant(0)), if_runtime);
// Check that there are no elements on the {receiver} and its prototype
// chain. Given that we do not create an EnumCache for dict-mode objects,
// directly jump to {if_empty} if there are no elements and no properties
@@ -13847,15 +13907,10 @@ void CodeStubAssembler::Print(const char* prefix, Node* tagged_value) {
void CodeStubAssembler::PerformStackCheck(TNode<Context> context) {
Label ok(this), stack_check_interrupt(this, Label::kDeferred);
- // The instruction sequence below is carefully crafted to hit our pattern
- // matcher for stack checks within instruction selection.
- // See StackCheckMatcher::Matched and JSGenericLowering::LowerJSStackCheck.
-
- TNode<UintPtrT> sp = UncheckedCast<UintPtrT>(LoadStackPointer());
- TNode<UintPtrT> stack_limit = UncheckedCast<UintPtrT>(Load(
- MachineType::Pointer(),
- ExternalConstant(ExternalReference::address_of_stack_limit(isolate()))));
- TNode<BoolT> sp_within_limit = UintPtrLessThan(stack_limit, sp);
+ TNode<UintPtrT> stack_limit = UncheckedCast<UintPtrT>(
+ Load(MachineType::Pointer(),
+ ExternalConstant(ExternalReference::address_of_jslimit(isolate()))));
+ TNode<BoolT> sp_within_limit = StackPointerGreaterThan(stack_limit);
Branch(sp_within_limit, &ok, &stack_check_interrupt);
@@ -13873,7 +13928,7 @@ void CodeStubAssembler::InitializeFunctionContext(Node* native_context,
StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset,
SmiConstant(slots));
- Node* const empty_scope_info =
+ TNode<Object> const empty_scope_info =
LoadContextElement(native_context, Context::SCOPE_INFO_INDEX);
StoreContextElementNoWriteBarrier(context, Context::SCOPE_INFO_INDEX,
empty_scope_info);
@@ -13904,7 +13959,7 @@ TNode<JSArray> CodeStubAssembler::ArrayCreate(TNode<Context> context,
BIND(&runtime);
{
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<JSFunction> array_function =
CAST(LoadContextElement(native_context, Context::ARRAY_FUNCTION_INDEX));
array = CAST(CallRuntime(Runtime::kNewArray, context, array_function,
@@ -13971,63 +14026,139 @@ void CodeStubAssembler::SetPropertyLength(TNode<Context> context,
BIND(&done);
}
-void CodeStubAssembler::GotoIfInitialPrototypePropertyModified(
- TNode<Map> object_map, TNode<Map> initial_prototype_map, int descriptor,
- RootIndex field_name_root_index, Label* if_modified) {
- DescriptorIndexAndName index_name{descriptor, field_name_root_index};
- GotoIfInitialPrototypePropertiesModified(
- object_map, initial_prototype_map,
- Vector<DescriptorIndexAndName>(&index_name, 1), if_modified);
+TNode<String> CodeStubAssembler::TaggedToDirectString(TNode<Object> value,
+ Label* fail) {
+ ToDirectStringAssembler to_direct(state(), CAST(value));
+ to_direct.TryToDirect(fail);
+ to_direct.PointerToData(fail);
+ return CAST(value);
}
-void CodeStubAssembler::GotoIfInitialPrototypePropertiesModified(
- TNode<Map> object_map, TNode<Map> initial_prototype_map,
- Vector<DescriptorIndexAndName> properties, Label* if_modified) {
- TNode<Map> prototype_map = LoadMap(LoadMapPrototype(object_map));
- GotoIfNot(WordEqual(prototype_map, initial_prototype_map), if_modified);
-
- // We need to make sure that relevant properties in the prototype have
- // not been tampered with. We do this by checking that their slots
- // in the prototype's descriptor array are still marked as const.
+PrototypeCheckAssembler::PrototypeCheckAssembler(
+ compiler::CodeAssemblerState* state, Flags flags,
+ TNode<NativeContext> native_context, TNode<Map> initial_prototype_map,
+ Vector<DescriptorIndexNameValue> properties)
+ : CodeStubAssembler(state),
+ flags_(flags),
+ native_context_(native_context),
+ initial_prototype_map_(initial_prototype_map),
+ properties_(properties) {}
+
+void PrototypeCheckAssembler::CheckAndBranch(TNode<HeapObject> prototype,
+ Label* if_unmodified,
+ Label* if_modified) {
+ TNode<Map> prototype_map = LoadMap(prototype);
TNode<DescriptorArray> descriptors = LoadMapDescriptors(prototype_map);
- TNode<Uint32T> combined_details;
- for (int i = 0; i < properties.length(); i++) {
- // Assert the descriptor index is in-bounds.
- int descriptor = properties[i].descriptor_index;
- CSA_ASSERT(this, Int32LessThan(Int32Constant(descriptor),
- LoadNumberOfDescriptors(descriptors)));
- // Assert that the name is correct. This essentially checks that
- // the descriptor index corresponds to the insertion order in
- // the bootstrapper.
- CSA_ASSERT(this,
- WordEqual(LoadKeyByDescriptorEntry(descriptors, descriptor),
- LoadRoot(properties[i].name_root_index)));
-
- TNode<Uint32T> details =
- DescriptorArrayGetDetails(descriptors, Uint32Constant(descriptor));
- if (i == 0) {
- combined_details = details;
- } else {
- combined_details = Word32And(combined_details, details);
+ // The continuation of a failed fast check: if property identity checks are
+ // enabled, we continue there (since they may still classify the prototype as
+ // fast), otherwise we bail out.
+ Label property_identity_check(this, Label::kDeferred);
+ Label* if_fast_check_failed =
+ ((flags_ & kCheckPrototypePropertyIdentity) == 0)
+ ? if_modified
+ : &property_identity_check;
+
+ if ((flags_ & kCheckPrototypePropertyConstness) != 0) {
+ // A simple prototype map identity check. Note that map identity does not
+ // guarantee unmodified properties. It does guarantee that no new properties
+ // have been added, or old properties deleted.
+
+ GotoIfNot(TaggedEqual(prototype_map, initial_prototype_map_),
+ if_fast_check_failed);
+
+ // We need to make sure that relevant properties in the prototype have
+ // not been tampered with. We do this by checking that their slots
+ // in the prototype's descriptor array are still marked as const.
+
+ TNode<Uint32T> combined_details;
+ for (int i = 0; i < properties_.length(); i++) {
+ // Assert the descriptor index is in-bounds.
+ int descriptor = properties_[i].descriptor_index;
+ CSA_ASSERT(this, Int32LessThan(Int32Constant(descriptor),
+ LoadNumberOfDescriptors(descriptors)));
+
+ // Assert that the name is correct. This essentially checks that
+ // the descriptor index corresponds to the insertion order in
+ // the bootstrapper.
+ CSA_ASSERT(
+ this,
+ TaggedEqual(LoadKeyByDescriptorEntry(descriptors, descriptor),
+ CodeAssembler::LoadRoot(properties_[i].name_root_index)));
+
+ TNode<Uint32T> details =
+ DescriptorArrayGetDetails(descriptors, Uint32Constant(descriptor));
+
+ if (i == 0) {
+ combined_details = details;
+ } else {
+ combined_details = Word32And(combined_details, details);
+ }
}
+
+ TNode<Uint32T> constness =
+ DecodeWord32<PropertyDetails::ConstnessField>(combined_details);
+
+ Branch(
+ Word32Equal(constness,
+ Int32Constant(static_cast<int>(PropertyConstness::kConst))),
+ if_unmodified, if_fast_check_failed);
}
- TNode<Uint32T> constness =
- DecodeWord32<PropertyDetails::ConstnessField>(combined_details);
+ if ((flags_ & kCheckPrototypePropertyIdentity) != 0) {
+ // The above checks have failed, for whatever reason (maybe the prototype
+ // map has changed, or a property is no longer const). This block implements
+ // a more thorough check that can also accept maps which 1. do not have the
+ // initial map, 2. have mutable relevant properties, but 3. still match the
+ // expected value for all relevant properties.
- GotoIfNot(
- Word32Equal(constness,
- Int32Constant(static_cast<int>(PropertyConstness::kConst))),
- if_modified);
-}
+ BIND(&property_identity_check);
-TNode<String> CodeStubAssembler::TaggedToDirectString(TNode<Object> value,
- Label* fail) {
- ToDirectStringAssembler to_direct(state(), value);
- to_direct.TryToDirect(fail);
- to_direct.PointerToData(fail);
- return CAST(value);
+ int max_descriptor_index = -1;
+ for (int i = 0; i < properties_.length(); i++) {
+ max_descriptor_index =
+ std::max(max_descriptor_index, properties_[i].descriptor_index);
+ }
+
+ // If the greatest descriptor index is out of bounds, the map cannot be
+ // fast.
+ GotoIfNot(Int32LessThan(Int32Constant(max_descriptor_index),
+ LoadNumberOfDescriptors(descriptors)),
+ if_modified);
+
+ // Logic below only handles maps with fast properties.
+ GotoIfMapHasSlowProperties(prototype_map, if_modified);
+
+ for (int i = 0; i < properties_.length(); i++) {
+ const DescriptorIndexNameValue& p = properties_[i];
+ const int descriptor = p.descriptor_index;
+
+ // Check if the name is correct. This essentially checks that
+ // the descriptor index corresponds to the insertion order in
+ // the bootstrapper.
+ GotoIfNot(TaggedEqual(LoadKeyByDescriptorEntry(descriptors, descriptor),
+ CodeAssembler::LoadRoot(p.name_root_index)),
+ if_modified);
+
+ // Finally, check whether the actual value equals the expected value.
+ TNode<Uint32T> details =
+ DescriptorArrayGetDetails(descriptors, Uint32Constant(descriptor));
+ TVARIABLE(Uint32T, var_details, details);
+ TVARIABLE(Object, var_value);
+
+ const int key_index = DescriptorArray::ToKeyIndex(descriptor);
+ LoadPropertyFromFastObject(prototype, prototype_map, descriptors,
+ IntPtrConstant(key_index), &var_details,
+ &var_value);
+
+ TNode<Object> actual_value = var_value.value();
+ TNode<Object> expected_value =
+ LoadContextElement(native_context_, p.expected_value_context_index);
+ GotoIfNot(TaggedEqual(actual_value, expected_value), if_modified);
+ }
+
+ Goto(if_unmodified);
+ }
}
} // namespace internal
diff --git a/deps/v8/src/codegen/code-stub-assembler.h b/deps/v8/src/codegen/code-stub-assembler.h
index 47abd02749..9884d04e66 100644
--- a/deps/v8/src/codegen/code-stub-assembler.h
+++ b/deps/v8/src/codegen/code-stub-assembler.h
@@ -32,65 +32,124 @@ class StubCache;
enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
-#define HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \
- V(ArraySpeciesProtector, array_species_protector, ArraySpeciesProtector) \
- V(PromiseSpeciesProtector, promise_species_protector, \
- PromiseSpeciesProtector) \
- V(TypedArraySpeciesProtector, typed_array_species_protector, \
- TypedArraySpeciesProtector) \
+#define HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V) \
+ V(ArrayIteratorProtector, array_iterator_protector, ArrayIteratorProtector) \
+ V(ArraySpeciesProtector, array_species_protector, ArraySpeciesProtector) \
+ V(MapIteratorProtector, map_iterator_protector, MapIteratorProtector) \
+ V(NoElementsProtector, no_elements_protector, NoElementsProtector) \
+ V(NumberStringCache, number_string_cache, NumberStringCache) \
+ V(PromiseResolveProtector, promise_resolve_protector, \
+ PromiseResolveProtector) \
+ V(PromiseSpeciesProtector, promise_species_protector, \
+ PromiseSpeciesProtector) \
+ V(PromiseThenProtector, promise_then_protector, PromiseThenProtector) \
+ V(SetIteratorProtector, set_iterator_protector, SetIteratorProtector) \
+ V(SingleCharacterStringCache, single_character_string_cache, \
+ SingleCharacterStringCache) \
+ V(StringIteratorProtector, string_iterator_protector, \
+ StringIteratorProtector) \
+ V(TypedArraySpeciesProtector, typed_array_species_protector, \
+ TypedArraySpeciesProtector)
#define HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(V) \
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
- V(AllocationSiteWithWeakNextMap, allocation_site_map, AllocationSiteMap) \
+ V(AllocationMementoMap, allocation_memento_map, AllocationMementoMap) \
V(AllocationSiteWithoutWeakNextMap, allocation_site_without_weaknext_map, \
AllocationSiteWithoutWeakNextMap) \
+ V(AllocationSiteWithWeakNextMap, allocation_site_map, AllocationSiteMap) \
+ V(arguments_to_string, arguments_to_string, ArgumentsToString) \
+ V(ArrayBoilerplateDescriptionMap, array_boilerplate_description_map, \
+ ArrayBoilerplateDescriptionMap) \
+ V(Array_string, Array_string, ArrayString) \
+ V(array_to_string, array_to_string, ArrayToString) \
V(BooleanMap, boolean_map, BooleanMap) \
+ V(boolean_to_string, boolean_to_string, BooleanToString) \
+ V(CellMap, cell_map, CellMap) \
V(CodeMap, code_map, CodeMap) \
+ V(ConsOneByteStringMap, cons_one_byte_string_map, ConsOneByteStringMap) \
+ V(ConsStringMap, cons_string_map, ConsStringMap) \
+ V(constructor_string, constructor_string, ConstructorString) \
+ V(date_to_string, date_to_string, DateToString) \
+ V(default_string, default_string, DefaultString) \
+ V(EmptyByteArray, empty_byte_array, EmptyByteArray) \
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
V(EmptyPropertyDictionary, empty_property_dictionary, \
EmptyPropertyDictionary) \
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
EmptySlowElementDictionary) \
V(empty_string, empty_string, EmptyString) \
+ V(error_to_string, error_to_string, ErrorToString) \
V(FalseValue, false_value, False) \
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
+ V(Function_string, function_string, FunctionString) \
V(FunctionTemplateInfoMap, function_template_info_map, \
FunctionTemplateInfoMap) \
+ V(function_to_string, function_to_string, FunctionToString) \
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
+ V(is_concat_spreadable_symbol, is_concat_spreadable_symbol, \
+ IsConcatSpreadableSymbol) \
V(iterator_symbol, iterator_symbol, IteratorSymbol) \
V(length_string, length_string, LengthString) \
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
+ V(megamorphic_symbol, megamorphic_symbol, MegamorphicSymbol) \
V(MetaMap, meta_map, MetaMap) \
V(MinusZeroValue, minus_zero_value, MinusZero) \
- V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
+ V(ModuleContextMap, module_context_map, ModuleContextMap) \
+ V(name_string, name_string, NameString) \
V(NanValue, nan_value, Nan) \
+ V(NativeContextMap, native_context_map, NativeContextMap) \
+ V(next_string, next_string, NextString) \
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
+ V(null_to_string, null_to_string, NullToString) \
V(NullValue, null_value, Null) \
+ V(number_string, number_string, numberString) \
+ V(number_to_string, number_to_string, NumberToString) \
+ V(Object_string, Object_string, ObjectString) \
+ V(object_to_string, object_to_string, ObjectToString) \
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
+ V(OnePointerFillerMap, one_pointer_filler_map, OnePointerFillerMap) \
+ V(premonomorphic_symbol, premonomorphic_symbol, PremonomorphicSymbol) \
V(PreparseDataMap, preparse_data_map, PreparseDataMap) \
+ V(PromiseCapabilityMap, promise_capability_map, PromiseCapabilityMap) \
+ V(PromiseFulfillReactionJobTaskMap, promise_fulfill_reaction_job_task_map, \
+ PromiseFulfillReactionJobTaskMap) \
+ V(PromiseReactionMap, promise_reaction_map, PromiseReactionMap) \
+ V(PromiseRejectReactionJobTaskMap, promise_reject_reaction_job_task_map, \
+ PromiseRejectReactionJobTaskMap) \
V(prototype_string, prototype_string, PrototypeString) \
+ V(PrototypeInfoMap, prototype_info_map, PrototypeInfoMap) \
+ V(regexp_to_string, regexp_to_string, RegexpToString) \
+ V(resolve_string, resolve_string, ResolveString) \
V(SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfoMap) \
+ V(SloppyArgumentsElementsMap, sloppy_arguments_elements_map, \
+ SloppyArgumentsElementsMap) \
+ V(species_symbol, species_symbol, SpeciesSymbol) \
+ V(StaleRegister, stale_register, StaleRegister) \
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
+ V(string_string, string_string, StringString) \
+ V(string_to_string, string_to_string, StringToString) \
V(SymbolMap, symbol_map, SymbolMap) \
V(TheHoleValue, the_hole_value, TheHole) \
+ V(then_string, then_string, ThenString) \
+ V(to_string_tag_symbol, to_string_tag_symbol, ToStringTagSymbol) \
V(TransitionArrayMap, transition_array_map, TransitionArrayMap) \
V(TrueValue, true_value, True) \
V(Tuple2Map, tuple2_map, Tuple2Map) \
V(Tuple3Map, tuple3_map, Tuple3Map) \
- V(ArrayBoilerplateDescriptionMap, array_boilerplate_description_map, \
- ArrayBoilerplateDescriptionMap) \
V(UncompiledDataWithoutPreparseDataMap, \
uncompiled_data_without_preparse_data_map, \
UncompiledDataWithoutPreparseDataMap) \
V(UncompiledDataWithPreparseDataMap, uncompiled_data_with_preparse_data_map, \
UncompiledDataWithPreparseDataMap) \
+ V(undefined_to_string, undefined_to_string, UndefinedToString) \
V(UndefinedValue, undefined_value, Undefined) \
+ V(uninitialized_symbol, uninitialized_symbol, UninitializedSymbol) \
V(WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArrayMap)
#define HEAP_IMMOVABLE_OBJECT_LIST(V) \
@@ -119,18 +178,17 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
#define CSA_ASSERT_2_ARGS(a, b, ...) {{a, #a}, {b, #b}}
// clang-format on
#define SWITCH_CSA_ASSERT_ARGS(dummy, a, b, FUNC, ...) FUNC(a, b)
-#define CSA_ASSERT_ARGS(...) \
- SWITCH_CSA_ASSERT_ARGS(dummy, ##__VA_ARGS__, CSA_ASSERT_2_ARGS, \
- CSA_ASSERT_1_ARG, CSA_ASSERT_0_ARGS)
+#define CSA_ASSERT_ARGS(...) \
+ CALL(SWITCH_CSA_ASSERT_ARGS, (, ##__VA_ARGS__, CSA_ASSERT_2_ARGS, \
+ CSA_ASSERT_1_ARG, CSA_ASSERT_0_ARGS))
+// Workaround for MSVC to skip comma in empty __VA_ARGS__.
+#define CALL(x, y) x y
// CSA_ASSERT(csa, <condition>, <extra values to print...>)
-#define CSA_ASSERT(csa, condition_node, ...) \
- (csa)->Assert( \
- [&]() -> compiler::Node* { \
- return implicit_cast<compiler::SloppyTNode<Word32T>>(condition_node); \
- }, \
- #condition_node, __FILE__, __LINE__, CSA_ASSERT_ARGS(__VA_ARGS__))
+#define CSA_ASSERT(csa, condition_node, ...) \
+ (csa)->Assert(condition_node, #condition_node, __FILE__, __LINE__, \
+ CSA_ASSERT_ARGS(__VA_ARGS__))
// CSA_ASSERT_BRANCH(csa, [](Label* ok, Label* not_ok) {...},
// <extra values to print...>)
@@ -141,8 +199,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
#define CSA_ASSERT_JS_ARGC_OP(csa, Op, op, expected) \
(csa)->Assert( \
[&]() -> compiler::Node* { \
- compiler::Node* const argc = \
- (csa)->Parameter(Descriptor::kJSActualArgumentsCount); \
+ TNode<Word32T> const argc = UncheckedCast<Word32T>( \
+ (csa)->Parameter(Descriptor::kJSActualArgumentsCount)); \
return (csa)->Op(argc, (csa)->Int32Constant(expected)); \
}, \
"argc " #op " " #expected, __FILE__, __LINE__, \
@@ -161,6 +219,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
name(this, CSA_DEBUG_INFO(name), __VA_ARGS__)
#define TYPED_VARIABLE_DEF(type, name, ...) \
TVariable<type> name(CSA_DEBUG_INFO(name), __VA_ARGS__)
+#define TYPED_VARIABLE_CONSTRUCTOR(name, ...) \
+ name(CSA_DEBUG_INFO(name), __VA_ARGS__)
#else // DEBUG
#define CSA_ASSERT(csa, ...) ((void)0)
#define CSA_ASSERT_BRANCH(csa, ...) ((void)0)
@@ -169,9 +229,12 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
#define VARIABLE(name, ...) Variable name(this, __VA_ARGS__)
#define VARIABLE_CONSTRUCTOR(name, ...) name(this, __VA_ARGS__)
#define TYPED_VARIABLE_DEF(type, name, ...) TVariable<type> name(__VA_ARGS__)
+#define TYPED_VARIABLE_CONSTRUCTOR(name, ...) name(__VA_ARGS__)
#endif // DEBUG
#define TVARIABLE(...) EXPAND(TYPED_VARIABLE_DEF(__VA_ARGS__, this))
+#define TVARIABLE_CONSTRUCTOR(...) \
+ EXPAND(TYPED_VARIABLE_CONSTRUCTOR(__VA_ARGS__, this))
#ifdef ENABLE_SLOW_DCHECKS
#define CSA_SLOW_ASSERT(csa, ...) \
@@ -222,7 +285,13 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// fewer live ranges. Thus only convert indices to untagged value on 64-bit
// platforms.
ParameterMode OptimalParameterMode() const {
- return Is64() ? INTPTR_PARAMETERS : SMI_PARAMETERS;
+#if defined(BINT_IS_SMI)
+ return SMI_PARAMETERS;
+#elif defined(BINT_IS_INTPTR)
+ return INTPTR_PARAMETERS;
+#else
+#error Unknown BInt type.
+#endif
}
MachineRepresentation ParameterRepresentation(ParameterMode mode) const {
@@ -268,7 +337,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
} else {
DCHECK_EQ(mode, ParameterMode::INTPTR_PARAMETERS);
intptr_t constant;
- if (ToIntPtrConstant(node, constant)) {
+ if (ToIntPtrConstant(node, &constant)) {
*out = constant;
return true;
}
@@ -277,7 +346,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return false;
}
-#if defined(V8_HOST_ARCH_32_BIT)
+#if defined(BINT_IS_SMI)
TNode<Smi> BIntToSmi(TNode<BInt> source) { return source; }
TNode<IntPtrT> BIntToIntPtr(TNode<BInt> source) {
return SmiToIntPtr(source);
@@ -286,7 +355,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BInt> IntPtrToBInt(TNode<IntPtrT> source) {
return SmiFromIntPtr(source);
}
-#elif defined(V8_HOST_ARCH_64_BIT)
+#elif defined(BINT_IS_INTPTR)
TNode<Smi> BIntToSmi(TNode<BInt> source) { return SmiFromIntPtr(source); }
TNode<IntPtrT> BIntToIntPtr(TNode<BInt> source) { return source; }
TNode<BInt> SmiToBInt(TNode<Smi> source) { return SmiToIntPtr(source); }
@@ -404,6 +473,20 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
intptr_t ConstexprWordNot(intptr_t a) { return ~a; }
uintptr_t ConstexprWordNot(uintptr_t a) { return ~a; }
+ TNode<BoolT> TaggedEqual(TNode<UnionT<Object, MaybeObject>> a,
+ TNode<UnionT<Object, MaybeObject>> b) {
+ // In pointer-compressed architectures, the instruction selector will narrow
+ // this comparison to a 32-bit one.
+ return WordEqual(ReinterpretCast<WordT>(a), ReinterpretCast<WordT>(b));
+ }
+
+ TNode<BoolT> TaggedNotEqual(TNode<UnionT<Object, MaybeObject>> a,
+ TNode<UnionT<Object, MaybeObject>> b) {
+ // In pointer-compressed architectures, the instruction selector will narrow
+ // this comparison to a 32-bit one.
+ return WordNotEqual(ReinterpretCast<WordT>(a), ReinterpretCast<WordT>(b));
+ }
+
TNode<Object> NoContextConstant();
#define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \
@@ -426,7 +509,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
HEAP_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_TEST)
#undef HEAP_CONSTANT_TEST
+ TNode<BInt> BIntConstant(int value);
+
Node* IntPtrOrSmiConstant(int value, ParameterMode mode);
+ TNode<BoolT> IntPtrOrSmiEqual(Node* left, Node* right, ParameterMode mode);
+ TNode<BoolT> IntPtrOrSmiNotEqual(Node* left, Node* right, ParameterMode mode);
bool IsIntPtrOrSmiConstantZero(Node* test, ParameterMode mode);
bool TryGetIntPtrOrSmiConstantValue(Node* maybe_constant, int* value,
@@ -512,15 +599,35 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
}
TNode<Smi> SmiShr(TNode<Smi> a, int shift) {
- return BitcastWordToTaggedSigned(
- WordAnd(WordShr(BitcastTaggedSignedToWord(a), shift),
- BitcastTaggedSignedToWord(SmiConstant(-1))));
+ if (kTaggedSize == kInt64Size) {
+ return BitcastWordToTaggedSigned(
+ WordAnd(WordShr(BitcastTaggedSignedToWord(a), shift),
+ BitcastTaggedSignedToWord(SmiConstant(-1))));
+ } else {
+ // For pointer compressed Smis, we want to make sure that we truncate to
+ // int32 before shifting, to avoid the values of the top 32-bits from
+ // leaking into the sign bit of the smi.
+ return BitcastWordToTaggedSigned(WordAnd(
+ ChangeInt32ToIntPtr(Word32Shr(
+ TruncateWordToInt32(BitcastTaggedSignedToWord(a)), shift)),
+ BitcastTaggedSignedToWord(SmiConstant(-1))));
+ }
}
TNode<Smi> SmiSar(TNode<Smi> a, int shift) {
- return BitcastWordToTaggedSigned(
- WordAnd(WordSar(BitcastTaggedSignedToWord(a), shift),
- BitcastTaggedSignedToWord(SmiConstant(-1))));
+ if (kTaggedSize == kInt64Size) {
+ return BitcastWordToTaggedSigned(
+ WordAnd(WordSar(BitcastTaggedSignedToWord(a), shift),
+ BitcastTaggedSignedToWord(SmiConstant(-1))));
+ } else {
+ // For pointer compressed Smis, we want to make sure that we truncate to
+ // int32 before shifting, to avoid the values of the top 32-bits from
+ // changing the sign bit of the smi.
+ return BitcastWordToTaggedSigned(WordAnd(
+ ChangeInt32ToIntPtr(Word32Sar(
+ TruncateWordToInt32(BitcastTaggedSignedToWord(a)), shift)),
+ BitcastTaggedSignedToWord(SmiConstant(-1))));
+ }
}
Node* WordOrSmiShl(Node* a, int shift, ParameterMode mode) {
@@ -543,10 +650,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
#define SMI_COMPARISON_OP(SmiOpName, IntPtrOpName, Int32OpName) \
TNode<BoolT> SmiOpName(TNode<Smi> a, TNode<Smi> b) { \
- if (SmiValuesAre32Bits()) { \
+ if (kTaggedSize == kInt64Size) { \
return IntPtrOpName(BitcastTaggedSignedToWord(a), \
BitcastTaggedSignedToWord(b)); \
} else { \
+ DCHECK_EQ(kTaggedSize, kInt32Size); \
DCHECK(SmiValuesAre31Bits()); \
if (kSystemPointerSize == kInt64Size) { \
CSA_ASSERT(this, IsValidSmi(a)); \
@@ -586,6 +694,31 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// 1 iff x > y.
TNode<Smi> SmiLexicographicCompare(TNode<Smi> x, TNode<Smi> y);
+#ifdef BINT_IS_SMI
+#define BINT_COMPARISON_OP(BIntOpName, SmiOpName, IntPtrOpName) \
+ TNode<BoolT> BIntOpName(TNode<BInt> a, TNode<BInt> b) { \
+ return SmiOpName(a, b); \
+ }
+#else
+#define BINT_COMPARISON_OP(BIntOpName, SmiOpName, IntPtrOpName) \
+ TNode<BoolT> BIntOpName(TNode<BInt> a, TNode<BInt> b) { \
+ return IntPtrOpName(a, b); \
+ }
+#endif
+ BINT_COMPARISON_OP(BIntEqual, SmiEqual, WordEqual)
+ BINT_COMPARISON_OP(BIntNotEqual, SmiNotEqual, WordNotEqual)
+ BINT_COMPARISON_OP(BIntAbove, SmiAbove, UintPtrGreaterThan)
+ BINT_COMPARISON_OP(BIntAboveOrEqual, SmiAboveOrEqual,
+ UintPtrGreaterThanOrEqual)
+ BINT_COMPARISON_OP(BIntBelow, SmiBelow, UintPtrLessThan)
+ BINT_COMPARISON_OP(BIntLessThan, SmiLessThan, IntPtrLessThan)
+ BINT_COMPARISON_OP(BIntLessThanOrEqual, SmiLessThanOrEqual,
+ IntPtrLessThanOrEqual)
+ BINT_COMPARISON_OP(BIntGreaterThan, SmiGreaterThan, IntPtrGreaterThan)
+ BINT_COMPARISON_OP(BIntGreaterThanOrEqual, SmiGreaterThanOrEqual,
+ IntPtrGreaterThanOrEqual)
+#undef BINT_COMPARISON_OP
+
// Smi | HeapNumber operations.
TNode<Number> NumberInc(SloppyTNode<Number> value);
TNode<Number> NumberDec(SloppyTNode<Number> value);
@@ -620,12 +753,18 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
void Assert(const NodeGenerator& condition_body, const char* message,
const char* file, int line,
std::initializer_list<ExtraNode> extra_nodes = {});
+ void Assert(SloppyTNode<Word32T> condition_node, const char* message,
+ const char* file, int line,
+ std::initializer_list<ExtraNode> extra_nodes = {});
void Check(const BranchGenerator& branch, const char* message,
const char* file, int line,
std::initializer_list<ExtraNode> extra_nodes = {});
void Check(const NodeGenerator& condition_body, const char* message,
const char* file, int line,
std::initializer_list<ExtraNode> extra_nodes = {});
+ void Check(SloppyTNode<Word32T> condition_node, const char* message,
+ const char* file, int line,
+ std::initializer_list<ExtraNode> extra_nodes = {});
void FailAssert(const char* message, const char* file, int line,
std::initializer_list<ExtraNode> extra_nodes = {});
@@ -713,6 +852,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
single_char[0]));
}
+ TNode<Int32T> TruncateWordToInt32(SloppyTNode<WordT> value);
TNode<Int32T> TruncateIntPtrToInt32(SloppyTNode<IntPtrT> value);
// Check a value for smi-ness
@@ -751,21 +891,25 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
Branch(SmiLessThanOrEqual(a, b), if_true, if_false);
}
- void BranchIfFloat64IsNaN(Node* value, Label* if_true, Label* if_false) {
+ void BranchIfFloat64IsNaN(TNode<Float64T> value, Label* if_true,
+ Label* if_false) {
Branch(Float64Equal(value, value), if_false, if_true);
}
// Branches to {if_true} if ToBoolean applied to {value} yields true,
// otherwise goes to {if_false}.
- void BranchIfToBooleanIsTrue(Node* value, Label* if_true, Label* if_false);
+ void BranchIfToBooleanIsTrue(SloppyTNode<Object> value, Label* if_true,
+ Label* if_false);
// Branches to {if_false} if ToBoolean applied to {value} yields false,
// otherwise goes to {if_true}.
- void BranchIfToBooleanIsFalse(Node* value, Label* if_false, Label* if_true) {
+ void BranchIfToBooleanIsFalse(SloppyTNode<Object> value, Label* if_false,
+ Label* if_true) {
BranchIfToBooleanIsTrue(value, if_true, if_false);
}
- void BranchIfJSReceiver(Node* object, Label* if_true, Label* if_false);
+ void BranchIfJSReceiver(SloppyTNode<Object> object, Label* if_true,
+ Label* if_false);
// Branches to {if_true} when --force-slow-path flag has been passed.
// It's used for testing to ensure that slow path implementation behave
@@ -831,9 +975,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<IntPtrT> LoadAndUntagObjectField(SloppyTNode<HeapObject> object,
int offset);
// Load a SMI field, untag it, and convert to Word32.
- TNode<Int32T> LoadAndUntagToWord32ObjectField(Node* object, int offset);
- // Load a SMI and untag it.
- TNode<IntPtrT> LoadAndUntagSmi(Node* base, int index);
+ TNode<Int32T> LoadAndUntagToWord32ObjectField(SloppyTNode<HeapObject> object,
+ int offset);
TNode<MaybeObject> LoadMaybeWeakObjectField(SloppyTNode<HeapObject> object,
int offset) {
@@ -847,6 +990,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Reference is the CSA-equivalent of a Torque reference value,
// representing an inner pointer into a HeapObject.
+ // TODO(gsps): Remove in favor of flattened {Load,Store}Reference interface
struct Reference {
TNode<HeapObject> object;
TNode<IntPtrT> offset;
@@ -899,11 +1043,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
value, StoreToObjectWriteBarrier::kNone);
}
- // Tag a smi and store it.
- void StoreAndTagSmi(Node* base, int offset, Node* value);
-
// Load the floating point value of a HeapNumber.
- TNode<Float64T> LoadHeapNumberValue(SloppyTNode<HeapNumber> object);
+ TNode<Float64T> LoadHeapNumberValue(SloppyTNode<HeapObject> object);
// Load the Map of an HeapObject.
TNode<Map> LoadMap(SloppyTNode<HeapObject> object);
// Load the instance type of an HeapObject.
@@ -915,6 +1056,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
InstanceType type);
TNode<BoolT> TaggedDoesntHaveInstanceType(SloppyTNode<HeapObject> any_tagged,
InstanceType type);
+
+ TNode<Word32T> IsStringWrapperElementsKind(TNode<Map> map);
+ void GotoIfMapHasSlowProperties(TNode<Map> map, Label* if_slow);
+
// Load the properties backing store of a JSObject.
TNode<HeapObject> LoadSlowProperties(SloppyTNode<JSObject> object);
TNode<HeapObject> LoadFastProperties(SloppyTNode<JSObject> object);
@@ -940,6 +1085,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
SloppyTNode<WeakFixedArray> array);
// Load the number of descriptors in DescriptorArray.
TNode<Int32T> LoadNumberOfDescriptors(TNode<DescriptorArray> array);
+ // Load the number of own descriptors of a map.
+ TNode<Int32T> LoadNumberOfOwnDescriptors(TNode<Map> map);
// Load the bit field of a Map.
TNode<Int32T> LoadMapBitField(SloppyTNode<Map> map);
// Load bit field 2 of a map.
@@ -968,7 +1115,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Load the constructor of a Map (equivalent to Map::GetConstructor()).
TNode<Object> LoadMapConstructor(SloppyTNode<Map> map);
// Load the EnumLength of a Map.
- Node* LoadMapEnumLength(SloppyTNode<Map> map);
+ TNode<WordT> LoadMapEnumLength(SloppyTNode<Map> map);
// Load the back-pointer of a Map.
TNode<Object> LoadMapBackPointer(SloppyTNode<Map> map);
// Checks that |map| has only simple properties, returns bitfield3.
@@ -1176,9 +1323,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
SMI_PARAMETERS, if_hole);
}
- Node* LoadFixedDoubleArrayElement(TNode<FixedDoubleArray> object,
- TNode<IntPtrT> index,
- Label* if_hole = nullptr) {
+ TNode<Float64T> LoadFixedDoubleArrayElement(TNode<FixedDoubleArray> object,
+ TNode<IntPtrT> index,
+ Label* if_hole = nullptr) {
return LoadFixedDoubleArrayElement(object, index, MachineType::Float64(), 0,
INTPTR_PARAMETERS, if_hole);
}
@@ -1257,20 +1404,21 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
void StoreContextElementNoWriteBarrier(SloppyTNode<Context> context,
int slot_index,
SloppyTNode<Object> value);
- TNode<Context> LoadNativeContext(SloppyTNode<Context> context);
+ TNode<NativeContext> LoadNativeContext(SloppyTNode<Context> context);
// Calling this is only valid if there's a module context in the chain.
TNode<Context> LoadModuleContext(SloppyTNode<Context> context);
- void GotoIfContextElementEqual(Node* value, Node* native_context,
- int slot_index, Label* if_equal) {
- GotoIf(WordEqual(value, LoadContextElement(native_context, slot_index)),
+ void GotoIfContextElementEqual(SloppyTNode<Object> value,
+ Node* native_context, int slot_index,
+ Label* if_equal) {
+ GotoIf(TaggedEqual(value, LoadContextElement(native_context, slot_index)),
if_equal);
}
TNode<Map> LoadJSArrayElementsMap(ElementsKind kind,
- SloppyTNode<Context> native_context);
+ SloppyTNode<NativeContext> native_context);
TNode<Map> LoadJSArrayElementsMap(SloppyTNode<Int32T> kind,
- SloppyTNode<Context> native_context);
+ SloppyTNode<NativeContext> native_context);
TNode<BoolT> HasPrototypeSlot(TNode<JSFunction> function);
TNode<BoolT> IsGeneratorFunction(TNode<JSFunction> function);
@@ -1278,7 +1426,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
void GotoIfPrototypeRequiresRuntimeLookup(TNode<JSFunction> function,
TNode<Map> map, Label* runtime);
// Load the "prototype" property of a JSFunction.
- Node* LoadJSFunctionPrototype(Node* function, Label* if_bailout);
+ Node* LoadJSFunctionPrototype(TNode<JSFunction> function, Label* if_bailout);
TNode<BytecodeArray> LoadSharedFunctionInfoBytecodeArray(
SloppyTNode<SharedFunctionInfo> shared);
@@ -1289,8 +1437,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Store the floating point value of a HeapNumber.
void StoreHeapNumberValue(SloppyTNode<HeapNumber> object,
SloppyTNode<Float64T> value);
- void StoreMutableHeapNumberValue(SloppyTNode<MutableHeapNumber> object,
- SloppyTNode<Float64T> value);
// Store a field to an object on the heap.
void StoreObjectField(Node* object, int offset, Node* value);
void StoreObjectField(Node* object, Node* offset, Node* value);
@@ -1361,9 +1507,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
CheckBounds::kDebugOnly);
}
- void StoreJSArrayLength(TNode<JSArray> array, TNode<Smi> length);
- void StoreElements(TNode<Object> object, TNode<FixedArrayBase> elements);
-
void StoreFixedArrayOrPropertyArrayElement(
Node* array, Node* index, Node* value,
WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
@@ -1512,10 +1655,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return AllocateHeapNumberWithValue(Float64Constant(value));
}
- // Allocate a MutableHeapNumber with a specific value.
- TNode<MutableHeapNumber> AllocateMutableHeapNumberWithValue(
- SloppyTNode<Float64T> value);
-
// Allocate a BigInt with {length} digits. Sets the sign bit to {false}.
// Does not initialize the digits.
TNode<BigInt> AllocateBigInt(TNode<IntPtrT> length);
@@ -1539,12 +1678,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Allocate a SeqOneByteString with the given length.
TNode<String> AllocateSeqOneByteString(uint32_t length,
AllocationFlags flags = kNone);
- TNode<String> AllocateSeqOneByteString(Node* context, TNode<Uint32T> length,
+ TNode<String> AllocateSeqOneByteString(TNode<Uint32T> length,
AllocationFlags flags = kNone);
// Allocate a SeqTwoByteString with the given length.
TNode<String> AllocateSeqTwoByteString(uint32_t length,
AllocationFlags flags = kNone);
- TNode<String> AllocateSeqTwoByteString(Node* context, TNode<Uint32T> length,
+ TNode<String> AllocateSeqTwoByteString(TNode<Uint32T> length,
AllocationFlags flags = kNone);
// Allocate a SlicedOneByteString with the given length, parent and offset.
@@ -1587,7 +1726,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
template <typename CollectionType>
void FindOrderedHashTableEntry(
Node* table, Node* hash,
- const std::function<void(Node*, Label*, Label*)>& key_compare,
+ const std::function<void(TNode<Object>, Label*, Label*)>& key_compare,
Variable* entry_start_position, Label* entry_found, Label* not_found);
template <typename CollectionType>
@@ -1770,7 +1909,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// array word by word. The source may be destroyed at the end of this macro.
//
// Otherwise, specify DestroySource::kNo for operations where an Object is
- // being cloned, to ensure that MutableHeapNumbers are unique between the
+ // being cloned, to ensure that mutable HeapNumbers are unique between the
// source and cloned object.
void CopyPropertyArrayValues(Node* from_array, Node* to_array, Node* length,
WriteBarrierMode barrier_mode,
@@ -1856,16 +1995,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<FixedDoubleArray> HeapObjectToFixedDoubleArray(TNode<HeapObject> base,
Label* cast_fail) {
- GotoIf(
- WordNotEqual(LoadMap(base), LoadRoot(RootIndex::kFixedDoubleArrayMap)),
- cast_fail);
+ GotoIf(TaggedNotEqual(LoadMap(base), FixedDoubleArrayMapConstant()),
+ cast_fail);
return UncheckedCast<FixedDoubleArray>(base);
}
TNode<SloppyArgumentsElements> HeapObjectToSloppyArgumentsElements(
TNode<HeapObject> base, Label* cast_fail) {
- GotoIf(WordNotEqual(LoadMap(base),
- LoadRoot(RootIndex::kSloppyArgumentsElementsMap)),
+ GotoIf(TaggedNotEqual(LoadMap(base), SloppyArgumentsElementsMapConstant()),
cast_fail);
return UncheckedCast<SloppyArgumentsElements>(base);
}
@@ -1968,7 +2105,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// HOLEY_SMI_ELEMENTS kind, and a conversion took place, the result will be
// compatible only with HOLEY_ELEMENTS and PACKED_ELEMENTS.
TNode<FixedArray> ExtractToFixedArray(
- Node* source, Node* first, Node* count, Node* capacity, Node* source_map,
+ SloppyTNode<FixedArrayBase> source, Node* first, Node* count,
+ Node* capacity, SloppyTNode<Map> source_map,
ElementsKind from_kind = PACKED_ELEMENTS,
AllocationFlags allocation_flags = AllocationFlag::kNone,
ExtractFixedArrayFlags extract_flags =
@@ -2169,10 +2307,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
InstanceType instance_type,
char const* method_name);
// Throws a TypeError for {method_name} if {value} is not a JSReceiver.
- // Returns the {value}'s map.
- Node* ThrowIfNotJSReceiver(Node* context, Node* value,
- MessageTemplate msg_template,
- const char* method_name = nullptr);
+ void ThrowIfNotJSReceiver(TNode<Context> context, TNode<Object> value,
+ MessageTemplate msg_template,
+ const char* method_name);
void ThrowIfNotCallable(TNode<Context> context, TNode<Object> value,
const char* method_name);
@@ -2191,7 +2328,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsAccessorInfo(SloppyTNode<HeapObject> object);
TNode<BoolT> IsAccessorPair(SloppyTNode<HeapObject> object);
TNode<BoolT> IsAllocationSite(SloppyTNode<HeapObject> object);
- TNode<BoolT> IsAnyHeapNumber(SloppyTNode<HeapObject> object);
TNode<BoolT> IsNoElementsProtectorCellInvalid();
TNode<BoolT> IsArrayIteratorProtectorCellInvalid();
TNode<BoolT> IsBigIntInstanceType(SloppyTNode<Int32T> instance_type);
@@ -2210,7 +2346,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsNameDictionary(SloppyTNode<HeapObject> object);
TNode<BoolT> IsGlobalDictionary(SloppyTNode<HeapObject> object);
TNode<BoolT> IsExtensibleMap(SloppyTNode<Map> map);
- TNode<BoolT> IsFrozenOrSealedElementsKindMap(SloppyTNode<Map> map);
TNode<BoolT> IsExtensibleNonPrototypeMap(TNode<Map> map);
TNode<BoolT> IsExternalStringInstanceType(SloppyTNode<Int32T> instance_type);
TNode<BoolT> IsFeedbackCell(SloppyTNode<HeapObject> object);
@@ -2265,7 +2400,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsJSPrimitiveWrapperMap(SloppyTNode<Map> map);
TNode<BoolT> IsJSPrimitiveWrapper(SloppyTNode<HeapObject> object);
TNode<BoolT> IsMap(SloppyTNode<HeapObject> object);
- TNode<BoolT> IsMutableHeapNumber(SloppyTNode<HeapObject> object);
TNode<BoolT> IsName(SloppyTNode<HeapObject> object);
TNode<BoolT> IsNameInstanceType(SloppyTNode<Int32T> instance_type);
TNode<BoolT> IsNativeContext(SloppyTNode<HeapObject> object);
@@ -2322,7 +2456,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsArraySpeciesProtectorCellInvalid();
TNode<BoolT> IsTypedArraySpeciesProtectorCellInvalid();
TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid(
- TNode<Context> native_context);
+ TNode<NativeContext> native_context);
TNode<BoolT> IsPromiseSpeciesProtectorCellInvalid();
TNode<BoolT> IsMockArrayBufferAllocatorFlag() {
@@ -2414,21 +2548,27 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Check if |string| is an indirect (thin or flat cons) string type that can
// be dereferenced by DerefIndirectString.
- void BranchIfCanDerefIndirectString(Node* string, Node* instance_type,
+ void BranchIfCanDerefIndirectString(TNode<String> string,
+ TNode<Int32T> instance_type,
Label* can_deref, Label* cannot_deref);
// Unpack an indirect (thin or flat cons) string type.
- void DerefIndirectString(Variable* var_string, Node* instance_type);
+ void DerefIndirectString(TVariable<String>* var_string,
+ TNode<Int32T> instance_type);
// Check if |var_string| has an indirect (thin or flat cons) string type,
// and unpack it if so.
- void MaybeDerefIndirectString(Variable* var_string, Node* instance_type,
- Label* did_deref, Label* cannot_deref);
+ void MaybeDerefIndirectString(TVariable<String>* var_string,
+ TNode<Int32T> instance_type, Label* did_deref,
+ Label* cannot_deref);
// Check if |var_left| or |var_right| has an indirect (thin or flat cons)
// string type, and unpack it/them if so. Fall through if nothing was done.
- void MaybeDerefIndirectStrings(Variable* var_left, Node* left_instance_type,
- Variable* var_right, Node* right_instance_type,
+ void MaybeDerefIndirectStrings(TVariable<String>* var_left,
+ TNode<Int32T> left_instance_type,
+ TVariable<String>* var_right,
+ TNode<Int32T> right_instance_type,
Label* did_something);
- Node* DerefIndirectString(TNode<String> string, TNode<Int32T> instance_type,
- Label* cannot_deref);
+ TNode<String> DerefIndirectString(TNode<String> string,
+ TNode<Int32T> instance_type,
+ Label* cannot_deref);
TNode<String> StringFromSingleUTF16EncodedCodePoint(TNode<Int32T> codepoint);
@@ -2470,9 +2610,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<String> ToString_Inline(SloppyTNode<Context> context,
SloppyTNode<Object> input);
- // Convert any object to a Primitive.
- Node* JSReceiverToPrimitive(Node* context, Node* input);
-
TNode<JSReceiver> ToObject(SloppyTNode<Context> context,
SloppyTNode<Object> input);
@@ -2618,7 +2755,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Returns true if all of the mask's bits in given |word| are clear.
TNode<BoolT> IsClearWord(SloppyTNode<WordT> word, uint32_t mask) {
- return WordEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0));
+ return IntPtrEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0));
}
void SetCounter(StatsCounter* counter, int value);
@@ -2976,7 +3113,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Returns true if {object} has {prototype} somewhere in it's prototype
// chain, otherwise false is returned. Might cause arbitrary side effects
// due to [[GetPrototypeOf]] invocations.
- Node* HasInPrototypeChain(Node* context, Node* object, Node* prototype);
+ Node* HasInPrototypeChain(Node* context, Node* object,
+ SloppyTNode<Object> prototype);
// ES6 section 7.3.19 OrdinaryHasInstance (C, O)
Node* OrdinaryHasInstance(Node* context, Node* callable, Node* object);
@@ -3017,7 +3155,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Check if a property name might require protector invalidation when it is
// used for a property store or deletion.
- void CheckForAssociatedProtector(Node* name, Label* if_protector);
+ void CheckForAssociatedProtector(SloppyTNode<Name> name, Label* if_protector);
TNode<Map> LoadReceiverMap(SloppyTNode<Object> receiver);
@@ -3075,7 +3213,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
Variable* maybe_converted_value = nullptr);
Node* CheckForCapacityGrow(Node* object, Node* elements, ElementsKind kind,
- Node* length, Node* key, ParameterMode mode,
+ SloppyTNode<UintPtrT> length,
+ SloppyTNode<WordT> key, ParameterMode mode,
Label* bailout);
Node* CopyElementsOnWrite(Node* object, Node* elements, ElementsKind kind,
@@ -3168,11 +3307,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
void InitializeFieldsWithRoot(Node* object, Node* start_offset,
Node* end_offset, RootIndex root);
- Node* RelationalComparison(Operation op, Node* left, Node* right,
- Node* context,
+ Node* RelationalComparison(Operation op, SloppyTNode<Object> left,
+ SloppyTNode<Object> right,
+ SloppyTNode<Context> context,
Variable* var_type_feedback = nullptr);
- void BranchIfNumberRelationalComparison(Operation op, Node* left, Node* right,
+ void BranchIfNumberRelationalComparison(Operation op,
+ SloppyTNode<Number> left,
+ SloppyTNode<Number> right,
Label* if_true, Label* if_false);
void BranchIfNumberEqual(TNode<Number> left, TNode<Number> right,
@@ -3218,7 +3360,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
void GotoIfNumberGreaterThanOrEqual(Node* left, Node* right, Label* if_false);
- Node* Equal(Node* lhs, Node* rhs, Node* context,
+ Node* Equal(SloppyTNode<Object> lhs, SloppyTNode<Object> rhs,
+ SloppyTNode<Context> context,
Variable* var_type_feedback = nullptr);
TNode<Oddball> StrictEqual(SloppyTNode<Object> lhs, SloppyTNode<Object> rhs,
@@ -3228,7 +3371,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Similar to StrictEqual except that NaNs are treated as equal and minus zero
// differs from positive zero.
enum class SameValueMode { kNumbersOnly, kFull };
- void BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true, Label* if_false,
+ void BranchIfSameValue(SloppyTNode<Object> lhs, SloppyTNode<Object> rhs,
+ Label* if_true, Label* if_false,
SameValueMode mode = SameValueMode::kFull);
// A part of BranchIfSameValue() that handles two double values.
// Treats NaN == NaN and +0 != -0.
@@ -3340,7 +3484,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
template <class... TArgs>
Node* MakeTypeError(MessageTemplate message, Node* context, TArgs... args) {
STATIC_ASSERT(sizeof...(TArgs) <= 3);
- Node* const make_type_error = LoadContextElement(
+ TNode<Object> const make_type_error = LoadContextElement(
LoadNativeContext(context), Context::MAKE_TYPE_ERROR_INDEX);
return CallJS(CodeFactory::Call(isolate()), context, make_type_error,
UndefinedConstant(), SmiConstant(message), args...);
@@ -3354,6 +3498,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
bool ConstexprBoolNot(bool value) { return !value; }
bool ConstexprInt31Equal(int31_t a, int31_t b) { return a == b; }
+ bool ConstexprInt31NotEqual(int31_t a, int31_t b) { return a != b; }
bool ConstexprInt31GreaterThanEqual(int31_t a, int31_t b) { return a >= b; }
uint32_t ConstexprUint32Add(uint32_t a, uint32_t b) { return a + b; }
int31_t ConstexprInt31Add(int31_t a, int31_t b) {
@@ -3372,34 +3517,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
void SetPropertyLength(TNode<Context> context, TNode<Object> array,
TNode<Number> length);
- // Checks that {object_map}'s prototype map is the {initial_prototype_map} and
- // makes sure that the field with name at index {descriptor} is still
- // constant. If it is not, go to label {if_modified}.
- //
- // To make the checks robust, the method also asserts that the descriptor has
- // the right key, the caller must pass the root index of the key
- // in {field_name_root_index}.
- //
- // This is useful for checking that given function has not been patched
- // on the prototype.
- void GotoIfInitialPrototypePropertyModified(TNode<Map> object_map,
- TNode<Map> initial_prototype_map,
- int descfriptor,
- RootIndex field_name_root_index,
- Label* if_modified);
- struct DescriptorIndexAndName {
- DescriptorIndexAndName() {}
- DescriptorIndexAndName(int descriptor_index, RootIndex name_root_index)
- : descriptor_index(descriptor_index),
- name_root_index(name_root_index) {}
-
- int descriptor_index;
- RootIndex name_root_index;
- };
- void GotoIfInitialPrototypePropertiesModified(
- TNode<Map> object_map, TNode<Map> initial_prototype_map,
- Vector<DescriptorIndexAndName> properties, Label* if_modified);
-
// Implements DescriptorArray::Search().
void DescriptorLookup(SloppyTNode<Name> unique_name,
SloppyTNode<DescriptorArray> descriptors,
@@ -3514,8 +3631,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<JSArray> ArrayCreate(TNode<Context> context, TNode<Number> length);
- // Allocate a clone of a mutable primitive, if {object} is a
- // MutableHeapNumber.
+ // Allocate a clone of a mutable primitive, if {object} is a mutable
+ // HeapNumber.
TNode<Object> CloneIfMutablePrimitive(TNode<Object> object);
private:
@@ -3556,9 +3673,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Uint32T> length,
TNode<String> parent, TNode<Smi> offset);
- // Allocate a MutableHeapNumber without initializing its value.
- TNode<MutableHeapNumber> AllocateMutableHeapNumber();
-
Node* SelectImpl(TNode<BoolT> condition, const NodeGenerator& true_body,
const NodeGenerator& false_body, MachineRepresentation rep);
@@ -3572,7 +3686,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Uint32T> entry_index);
TNode<Smi> CollectFeedbackForString(SloppyTNode<Int32T> instance_type);
- void GenerateEqual_Same(Node* value, Label* if_equal, Label* if_notequal,
+ void GenerateEqual_Same(SloppyTNode<Object> value, Label* if_equal,
+ Label* if_notequal,
Variable* var_type_feedback = nullptr);
TNode<String> AllocAndCopyStringCharacters(Node* from,
Node* from_instance_type,
@@ -3602,6 +3717,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<T> LoadDescriptorArrayElement(TNode<DescriptorArray> object,
TNode<IntPtrT> index,
int additional_offset);
+
+ // Hide LoadRoot for subclasses of CodeStubAssembler. If you get an error
+ // complaining about this method, don't make it public, add your root to
+ // HEAP_(IM)MUTABLE_IMMOVABLE_OBJECT_LIST instead. If you *really* need
+ // LoadRoot, use CodeAssembler::LoadRoot.
+ TNode<Object> LoadRoot(RootIndex root_index) {
+ return CodeAssembler::LoadRoot(root_index);
+ }
};
class V8_EXPORT_PRIVATE CodeStubArguments {
@@ -3725,8 +3848,8 @@ class ToDirectStringAssembler : public CodeStubAssembler {
};
using Flags = base::Flags<Flag>;
- ToDirectStringAssembler(compiler::CodeAssemblerState* state, Node* string,
- Flags flags = Flags());
+ ToDirectStringAssembler(compiler::CodeAssemblerState* state,
+ TNode<String> string, Flags flags = Flags());
// Converts flat cons, thin, and sliced strings and returns the direct
// string. The result can be either a sequential or external string.
@@ -3746,22 +3869,57 @@ class ToDirectStringAssembler : public CodeStubAssembler {
return TryToSequential(PTR_TO_STRING, if_bailout);
}
- Node* string() { return var_string_.value(); }
- Node* instance_type() { return var_instance_type_.value(); }
- TNode<IntPtrT> offset() {
- return UncheckedCast<IntPtrT>(var_offset_.value());
- }
- Node* is_external() { return var_is_external_.value(); }
+ TNode<String> string() { return var_string_.value(); }
+ TNode<Int32T> instance_type() { return var_instance_type_.value(); }
+ TNode<IntPtrT> offset() { return var_offset_.value(); }
+ TNode<Word32T> is_external() { return var_is_external_.value(); }
private:
TNode<RawPtrT> TryToSequential(StringPointerKind ptr_kind, Label* if_bailout);
- Variable var_string_;
- Variable var_instance_type_;
- Variable var_offset_;
- Variable var_is_external_;
+ TVariable<String> var_string_;
+ TVariable<Int32T> var_instance_type_;
+ TVariable<IntPtrT> var_offset_;
+ TVariable<Word32T> var_is_external_;
+
+ const Flags flags_;
+};
+
+// Performs checks on a given prototype (e.g. map identity, property
+// verification), intended for use in fast path checks.
+class PrototypeCheckAssembler : public CodeStubAssembler {
+ public:
+ enum Flag {
+ kCheckPrototypePropertyConstness = 1 << 0,
+ kCheckPrototypePropertyIdentity = 1 << 1,
+ kCheckFull =
+ kCheckPrototypePropertyConstness | kCheckPrototypePropertyIdentity,
+ };
+ using Flags = base::Flags<Flag>;
+
+ // A tuple describing a relevant property. It contains the descriptor index of
+ // the property (within the descriptor array), the property's expected name
+ // (stored as a root), and the property's expected value (stored on the native
+ // context).
+ struct DescriptorIndexNameValue {
+ int descriptor_index;
+ RootIndex name_root_index;
+ int expected_value_context_index;
+ };
+
+ PrototypeCheckAssembler(compiler::CodeAssemblerState* state, Flags flags,
+ TNode<NativeContext> native_context,
+ TNode<Map> initial_prototype_map,
+ Vector<DescriptorIndexNameValue> properties);
+ void CheckAndBranch(TNode<HeapObject> prototype, Label* if_unmodified,
+ Label* if_modified);
+
+ private:
const Flags flags_;
+ const TNode<NativeContext> native_context_;
+ const TNode<Map> initial_prototype_map_;
+ const Vector<DescriptorIndexNameValue> properties_;
};
DEFINE_OPERATORS_FOR_FLAGS(CodeStubAssembler::AllocationFlags)
diff --git a/deps/v8/src/codegen/compiler.cc b/deps/v8/src/codegen/compiler.cc
index 906eb0f0ca..3a8ab3398a 100644
--- a/deps/v8/src/codegen/compiler.cc
+++ b/deps/v8/src/codegen/compiler.cc
@@ -410,6 +410,12 @@ void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
DCHECK(!compilation_info->has_asm_wasm_data());
DCHECK(!shared_info->HasFeedbackMetadata());
+ // If the function failed asm-wasm compilation, mark asm_wasm as broken
+ // to ensure we don't try to compile as asm-wasm.
+ if (compilation_info->literal()->scope()->IsAsmModule()) {
+ shared_info->set_is_asm_wasm_broken(true);
+ }
+
InstallBytecodeArray(compilation_info->bytecode_array(), shared_info,
parse_info, isolate);
@@ -529,20 +535,16 @@ std::unique_ptr<UnoptimizedCompilationJob> GenerateUnoptimizedCode(
DisallowHeapAccess no_heap_access;
DCHECK(inner_function_jobs->empty());
- if (!Compiler::Analyze(parse_info)) {
- return std::unique_ptr<UnoptimizedCompilationJob>();
+ std::unique_ptr<UnoptimizedCompilationJob> job;
+ if (Compiler::Analyze(parse_info)) {
+ job = ExecuteUnoptimizedCompileJobs(parse_info, parse_info->literal(),
+ allocator, inner_function_jobs);
}
- // Prepare and execute compilation of the outer-most function.
- std::unique_ptr<UnoptimizedCompilationJob> outer_function_job(
- ExecuteUnoptimizedCompileJobs(parse_info, parse_info->literal(),
- allocator, inner_function_jobs));
- if (!outer_function_job) return std::unique_ptr<UnoptimizedCompilationJob>();
-
// Character stream shouldn't be used again.
parse_info->ResetCharacterStream();
- return outer_function_job;
+ return job;
}
MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel(
@@ -1181,6 +1183,9 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
DCHECK(shared_info->HasBytecodeArray());
DCHECK(!shared_info->GetBytecodeArray().HasSourcePositionTable());
+ // Source position collection should be context independent.
+ NullContextScope null_context_scope(isolate);
+
// Collecting source positions requires allocating a new source position
// table.
DCHECK(AllowHeapAllocation::IsAllowed());
@@ -1215,59 +1220,51 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
parse_info.set_collect_source_positions();
if (FLAG_allow_natives_syntax) parse_info.set_allow_natives_syntax();
- // Parse and update ParseInfo with the results.
- if (!parsing::ParseAny(&parse_info, shared_info, isolate)) {
+ // Parse and update ParseInfo with the results. Don't update parsing
+ // statistics since we've already parsed the code before.
+ if (!parsing::ParseAny(&parse_info, shared_info, isolate,
+ parsing::ReportErrorsAndStatisticsMode::kNo)) {
// Parsing failed probably as a result of stack exhaustion.
bytecode->SetSourcePositionsFailedToCollect();
return FailWithPendingException(
isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
}
+ // Character stream shouldn't be used again.
+ parse_info.ResetCharacterStream();
+
// Generate the unoptimized bytecode.
// TODO(v8:8510): Consider forcing preparsing of inner functions to avoid
// wasting time fully parsing them when they won't ever be used.
- UnoptimizedCompilationJobList inner_function_jobs;
- std::unique_ptr<UnoptimizedCompilationJob> outer_function_job(
- GenerateUnoptimizedCode(&parse_info, isolate->allocator(),
- &inner_function_jobs));
- if (!outer_function_job) {
- // Recompiling failed probably as a result of stack exhaustion.
- bytecode->SetSourcePositionsFailedToCollect();
- return FailWithPendingException(
- isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
- }
+ std::unique_ptr<UnoptimizedCompilationJob> job;
+ {
+ if (!Compiler::Analyze(&parse_info)) {
+ // Recompiling failed probably as a result of stack exhaustion.
+ bytecode->SetSourcePositionsFailedToCollect();
+ return FailWithPendingException(
+ isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
+ }
- DCHECK(outer_function_job->compilation_info()->collect_source_positions());
+ job = interpreter::Interpreter::NewSourcePositionCollectionJob(
+ &parse_info, parse_info.literal(), bytecode, isolate->allocator());
- // TODO(v8:8510) Avoid re-allocating bytecode array/constant pool and
- // re-internalizeing the ast values. Maybe we could use the
- // unoptimized_compilation_flag to signal that all we need is the source
- // position table (and we could do the DCHECK that the bytecode array is the
- // same in the bytecode-generator, by comparing the real bytecode array on the
- // SFI with the off-heap bytecode array).
+ if (!job || job->ExecuteJob() != CompilationJob::SUCCEEDED ||
+ job->FinalizeJob(shared_info, isolate) != CompilationJob::SUCCEEDED) {
+ // Recompiling failed probably as a result of stack exhaustion.
+ bytecode->SetSourcePositionsFailedToCollect();
+ return FailWithPendingException(
+ isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION);
+ }
+ }
- // Internalize ast values onto the heap.
- parse_info.ast_value_factory()->Internalize(isolate);
+ DCHECK(job->compilation_info()->collect_source_positions());
- {
- // Allocate scope infos for the literal.
- DeclarationScope::AllocateScopeInfos(&parse_info, isolate);
- CHECK_EQ(outer_function_job->FinalizeJob(shared_info, isolate),
- CompilationJob::SUCCEEDED);
- }
-
- // Update the source position table on the original bytecode.
- DCHECK(bytecode->IsBytecodeEqual(
- *outer_function_job->compilation_info()->bytecode_array()));
- DCHECK(outer_function_job->compilation_info()->has_bytecode_array());
- ByteArray source_position_table = outer_function_job->compilation_info()
- ->bytecode_array()
- ->SourcePositionTable();
- bytecode->set_source_position_table(source_position_table);
// If debugging, make sure that instrumented bytecode has the source position
// table set on it as well.
if (shared_info->HasDebugInfo() &&
shared_info->GetDebugInfo().HasInstrumentedBytecodeArray()) {
+ ByteArray source_position_table =
+ job->compilation_info()->bytecode_array()->SourcePositionTable();
shared_info->GetDebugBytecodeArray().set_source_position_table(
source_position_table);
}
@@ -1352,6 +1349,16 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
// Collect source positions immediately to try and flush out bytecode
// mismatches.
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
+
+ // Do the same for eagerly compiled inner functions.
+ for (auto&& inner_job : inner_function_jobs) {
+ Handle<SharedFunctionInfo> inner_shared_info =
+ Compiler::GetSharedFunctionInfo(
+ inner_job->compilation_info()->literal(), parse_info.script(),
+ isolate);
+ SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate,
+ inner_shared_info);
+ }
}
return true;
@@ -2110,7 +2117,11 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
script->set_wrapped_arguments(*arguments);
parse_info.set_eval(); // Use an eval scope as declaration scope.
- parse_info.set_wrapped_as_function();
+ parse_info.set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
+ // TODO(delphick): Remove this and instead make the wrapped and wrapper
+ // functions fully non-lazy instead thus preventing source positions from
+ // being omitted.
+ parse_info.set_collect_source_positions(true);
// parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile);
if (!context->IsNativeContext()) {
parse_info.set_outer_scope_info(handle(context->scope_info(), isolate));
@@ -2217,7 +2228,28 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
// If we found an existing shared function info, return it.
Handle<SharedFunctionInfo> existing;
- if (maybe_existing.ToHandle(&existing)) return existing;
+ if (maybe_existing.ToHandle(&existing)) {
+ // If the function has been uncompiled (bytecode flushed) it will have lost
+ // any preparsed data. If we produced preparsed data during this compile for
+ // this function, replace the uncompiled data with one that includes it.
+ if (literal->produced_preparse_data() != nullptr &&
+ existing->HasUncompiledDataWithoutPreparseData()) {
+ DCHECK(literal->inferred_name()->Equals(
+ existing->uncompiled_data().inferred_name()));
+ DCHECK_EQ(literal->start_position(),
+ existing->uncompiled_data().start_position());
+ DCHECK_EQ(literal->end_position(),
+ existing->uncompiled_data().end_position());
+ Handle<PreparseData> preparse_data =
+ literal->produced_preparse_data()->Serialize(isolate);
+ Handle<UncompiledData> new_uncompiled_data =
+ isolate->factory()->NewUncompiledDataWithPreparseData(
+ literal->inferred_name(), literal->start_position(),
+ literal->end_position(), preparse_data);
+ existing->set_uncompiled_data(*new_uncompiled_data);
+ }
+ return existing;
+ }
// Allocate a shared function info object which will be compiled lazily.
Handle<SharedFunctionInfo> result =
@@ -2294,8 +2326,7 @@ bool Compiler::FinalizeOptimizedCompilationJob(OptimizedCompilationJob* job,
return CompilationJob::FAILED;
}
-void Compiler::PostInstantiation(Handle<JSFunction> function,
- AllocationType allocation) {
+void Compiler::PostInstantiation(Handle<JSFunction> function) {
Isolate* isolate = function->GetIsolate();
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
IsCompiledScope is_compiled_scope(shared->is_compiled_scope());
diff --git a/deps/v8/src/codegen/compiler.h b/deps/v8/src/codegen/compiler.h
index 836f738123..83d44dea29 100644
--- a/deps/v8/src/codegen/compiler.h
+++ b/deps/v8/src/codegen/compiler.h
@@ -86,7 +86,7 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
// Give the compiler a chance to perform low-latency initialization tasks of
// the given {function} on its instantiation. Note that only the runtime will
// offer this chance, optimized closure instantiation will not call this.
- static void PostInstantiation(Handle<JSFunction> function, AllocationType);
+ static void PostInstantiation(Handle<JSFunction> function);
// Parser::Parse, then Compiler::Analyze.
static bool ParseAndAnalyze(ParseInfo* parse_info,
@@ -201,15 +201,11 @@ class V8_EXPORT_PRIVATE CompilationJob {
kFailed,
};
- CompilationJob(uintptr_t stack_limit, State initial_state)
- : state_(initial_state), stack_limit_(stack_limit) {
+ explicit CompilationJob(State initial_state) : state_(initial_state) {
timer_.Start();
}
virtual ~CompilationJob() = default;
- void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
- uintptr_t stack_limit() const { return stack_limit_; }
-
State state() const { return state_; }
protected:
@@ -228,7 +224,6 @@ class V8_EXPORT_PRIVATE CompilationJob {
private:
State state_;
- uintptr_t stack_limit_;
base::ElapsedTimer timer_;
};
@@ -242,9 +237,10 @@ class V8_EXPORT_PRIVATE CompilationJob {
// Either of phases can either fail or succeed.
class UnoptimizedCompilationJob : public CompilationJob {
public:
- UnoptimizedCompilationJob(intptr_t stack_limit, ParseInfo* parse_info,
+ UnoptimizedCompilationJob(uintptr_t stack_limit, ParseInfo* parse_info,
UnoptimizedCompilationInfo* compilation_info)
- : CompilationJob(stack_limit, State::kReadyToExecute),
+ : CompilationJob(State::kReadyToExecute),
+ stack_limit_(stack_limit),
parse_info_(parse_info),
compilation_info_(compilation_info) {}
@@ -265,6 +261,8 @@ class UnoptimizedCompilationJob : public CompilationJob {
return compilation_info_;
}
+ uintptr_t stack_limit() const { return stack_limit_; }
+
protected:
// Overridden by the actual implementation.
virtual Status ExecuteJobImpl() = 0;
@@ -272,6 +270,7 @@ class UnoptimizedCompilationJob : public CompilationJob {
Isolate* isolate) = 0;
private:
+ uintptr_t stack_limit_;
ParseInfo* parse_info_;
UnoptimizedCompilationInfo* compilation_info_;
base::TimeDelta time_taken_to_execute_;
@@ -289,11 +288,10 @@ class UnoptimizedCompilationJob : public CompilationJob {
// Each of the three phases can either fail or succeed.
class OptimizedCompilationJob : public CompilationJob {
public:
- OptimizedCompilationJob(uintptr_t stack_limit,
- OptimizedCompilationInfo* compilation_info,
+ OptimizedCompilationJob(OptimizedCompilationInfo* compilation_info,
const char* compiler_name,
State initial_state = State::kReadyToPrepare)
- : CompilationJob(stack_limit, initial_state),
+ : CompilationJob(initial_state),
compilation_info_(compilation_info),
compiler_name_(compiler_name) {}
diff --git a/deps/v8/src/codegen/external-reference.cc b/deps/v8/src/codegen/external-reference.cc
index c077407931..44503e532d 100644
--- a/deps/v8/src/codegen/external-reference.cc
+++ b/deps/v8/src/codegen/external-reference.cc
@@ -26,6 +26,7 @@
#include "src/logging/log.h"
#include "src/numbers/math-random.h"
#include "src/objects/objects-inl.h"
+#include "src/regexp/regexp-interpreter.h"
#include "src/regexp/regexp-macro-assembler-arch.h"
#include "src/regexp/regexp-stack.h"
#include "src/strings/string-search.h"
@@ -327,13 +328,18 @@ ExternalReference ExternalReference::allocation_sites_list_address(
return ExternalReference(isolate->heap()->allocation_sites_list_address());
}
-ExternalReference ExternalReference::address_of_stack_limit(Isolate* isolate) {
- return ExternalReference(isolate->stack_guard()->address_of_jslimit());
+ExternalReference ExternalReference::address_of_jslimit(Isolate* isolate) {
+ Address address = isolate->stack_guard()->address_of_jslimit();
+ // For efficient generated code, this should be root-register-addressable.
+ DCHECK(isolate->root_register_addressable_region().contains(address));
+ return ExternalReference(address);
}
-ExternalReference ExternalReference::address_of_real_stack_limit(
- Isolate* isolate) {
- return ExternalReference(isolate->stack_guard()->address_of_real_jslimit());
+ExternalReference ExternalReference::address_of_real_jslimit(Isolate* isolate) {
+ Address address = isolate->stack_guard()->address_of_real_jslimit();
+ // For efficient generated code, this should be root-register-addressable.
+ DCHECK(isolate->root_register_addressable_region().contains(address));
+ return ExternalReference(address);
}
ExternalReference ExternalReference::store_buffer_top(Isolate* isolate) {
@@ -481,6 +487,9 @@ FUNCTION_REFERENCE_WITH_ISOLATE(re_check_stack_guard_state, re_stack_check_func)
FUNCTION_REFERENCE_WITH_ISOLATE(re_grow_stack,
NativeRegExpMacroAssembler::GrowStack)
+FUNCTION_REFERENCE_WITH_ISOLATE(re_match_for_call_from_js,
+ IrregexpInterpreter::MatchForCallFromJs)
+
FUNCTION_REFERENCE_WITH_ISOLATE(
re_case_insensitive_compare_uc16,
NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16)
@@ -496,14 +505,14 @@ ExternalReference ExternalReference::address_of_static_offsets_vector(
reinterpret_cast<Address>(isolate->jsregexp_static_offsets_vector()));
}
-ExternalReference ExternalReference::address_of_regexp_stack_limit(
+ExternalReference ExternalReference::address_of_regexp_stack_limit_address(
Isolate* isolate) {
- return ExternalReference(isolate->regexp_stack()->limit_address());
+ return ExternalReference(isolate->regexp_stack()->limit_address_address());
}
ExternalReference ExternalReference::address_of_regexp_stack_memory_address(
Isolate* isolate) {
- return ExternalReference(isolate->regexp_stack()->memory_address());
+ return ExternalReference(isolate->regexp_stack()->memory_address_address());
}
ExternalReference ExternalReference::address_of_regexp_stack_memory_size(
@@ -511,6 +520,12 @@ ExternalReference ExternalReference::address_of_regexp_stack_memory_size(
return ExternalReference(isolate->regexp_stack()->memory_size_address());
}
+ExternalReference ExternalReference::address_of_regexp_stack_memory_top_address(
+ Isolate* isolate) {
+ return ExternalReference(
+ isolate->regexp_stack()->memory_top_address_address());
+}
+
FUNCTION_REFERENCE_WITH_TYPE(ieee754_acos_function, base::ieee754::acos,
BUILTIN_FP_CALL)
FUNCTION_REFERENCE_WITH_TYPE(ieee754_acosh_function, base::ieee754::acosh,
diff --git a/deps/v8/src/codegen/external-reference.h b/deps/v8/src/codegen/external-reference.h
index b663ae1621..45c26bdfb0 100644
--- a/deps/v8/src/codegen/external-reference.h
+++ b/deps/v8/src/codegen/external-reference.h
@@ -36,8 +36,8 @@ class StatsCounter;
V(force_slow_path, "Isolate::force_slow_path_address()") \
V(isolate_root, "Isolate::isolate_root()") \
V(allocation_sites_list_address, "Heap::allocation_sites_list_address()") \
- V(address_of_stack_limit, "StackGuard::address_of_jslimit()") \
- V(address_of_real_stack_limit, "StackGuard::address_of_real_jslimit()") \
+ V(address_of_jslimit, "StackGuard::address_of_jslimit()") \
+ V(address_of_real_jslimit, "StackGuard::address_of_real_jslimit()") \
V(store_buffer_top, "store_buffer_top") \
V(heap_is_marking_flag_address, "heap_is_marking_flag_address") \
V(new_space_allocation_top_address, "Heap::NewSpaceAllocationTopAddress()") \
@@ -73,15 +73,20 @@ class StatsCounter;
V(fast_c_call_caller_pc_address, \
"IsolateData::fast_c_call_caller_pc_address") \
V(stack_is_iterable_address, "IsolateData::stack_is_iterable_address") \
- V(address_of_regexp_stack_limit, "RegExpStack::limit_address()") \
- V(address_of_regexp_stack_memory_address, "RegExpStack::memory_address()") \
- V(address_of_regexp_stack_memory_size, "RegExpStack::memory_size()") \
+ V(address_of_regexp_stack_limit_address, \
+ "RegExpStack::limit_address_address()") \
+ V(address_of_regexp_stack_memory_address, \
+ "RegExpStack::memory_address_address()") \
+ V(address_of_regexp_stack_memory_size, "RegExpStack::memory_size_address()") \
+ V(address_of_regexp_stack_memory_top_address, \
+ "RegExpStack::memory_top_address_address()") \
V(address_of_static_offsets_vector, "OffsetsVector::static_offsets_vector") \
V(re_case_insensitive_compare_uc16, \
"NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()") \
V(re_check_stack_guard_state, \
"RegExpMacroAssembler*::CheckStackGuardState()") \
V(re_grow_stack, "NativeRegExpMacroAssembler::GrowStack()") \
+ V(re_match_for_call_from_js, "IrregexpInterpreter::MatchForCallFromJs") \
V(re_word_character_map, "NativeRegExpMacroAssembler::word_character_map")
#define EXTERNAL_REFERENCE_LIST(V) \
diff --git a/deps/v8/src/codegen/handler-table.h b/deps/v8/src/codegen/handler-table.h
index 362412525d..1aa6b81203 100644
--- a/deps/v8/src/codegen/handler-table.h
+++ b/deps/v8/src/codegen/handler-table.h
@@ -129,8 +129,8 @@ class V8_EXPORT_PRIVATE HandlerTable {
static const int kReturnEntrySize = 2;
// Encoding of the {handler} field.
- class HandlerPredictionField : public BitField<CatchPrediction, 0, 3> {};
- class HandlerOffsetField : public BitField<int, 3, 29> {};
+ using HandlerPredictionField = BitField<CatchPrediction, 0, 3>;
+ using HandlerOffsetField = BitField<int, 3, 29>;
};
} // namespace internal
diff --git a/deps/v8/src/codegen/ia32/assembler-ia32.h b/deps/v8/src/codegen/ia32/assembler-ia32.h
index 2423f73bdb..5225621276 100644
--- a/deps/v8/src/codegen/ia32/assembler-ia32.h
+++ b/deps/v8/src/codegen/ia32/assembler-ia32.h
@@ -342,8 +342,8 @@ class Displacement {
private:
int data_;
- class TypeField : public BitField<Type, 0, 2> {};
- class NextField : public BitField<int, 2, 32 - 2> {};
+ using TypeField = BitField<Type, 0, 2>;
+ using NextField = BitField<int, 2, 32 - 2>;
void init(Label* L, Type type);
};
diff --git a/deps/v8/src/codegen/ia32/macro-assembler-ia32.cc b/deps/v8/src/codegen/ia32/macro-assembler-ia32.cc
index f6f0153e54..070f315977 100644
--- a/deps/v8/src/codegen/ia32/macro-assembler-ia32.cc
+++ b/deps/v8/src/codegen/ia32/macro-assembler-ia32.cc
@@ -91,26 +91,16 @@ void TurboAssembler::CompareRoot(Register with, RootIndex index) {
}
}
-void TurboAssembler::CompareStackLimit(Register with) {
- if (root_array_available()) {
- CompareRoot(with, RootIndex::kStackLimit);
- } else {
- DCHECK(!options().isolate_independent_code);
- ExternalReference ref =
- ExternalReference::address_of_stack_limit(isolate());
- cmp(with, Operand(ref.address(), RelocInfo::EXTERNAL_REFERENCE));
- }
-}
-
void TurboAssembler::CompareRealStackLimit(Register with) {
- if (root_array_available()) {
- CompareRoot(with, RootIndex::kRealStackLimit);
- } else {
- DCHECK(!options().isolate_independent_code);
- ExternalReference ref =
- ExternalReference::address_of_real_stack_limit(isolate());
- cmp(with, Operand(ref.address(), RelocInfo::EXTERNAL_REFERENCE));
- }
+ CHECK(root_array_available()); // Only used by builtins.
+
+ // Address through the root register. No load is needed.
+ ExternalReference limit =
+ ExternalReference::address_of_real_jslimit(isolate());
+ DCHECK(IsAddressableThroughRootRegister(isolate(), limit));
+
+ intptr_t offset = RootRegisterOffsetForExternalReference(isolate(), limit);
+ cmp(with, Operand(kRootRegister, offset));
}
void MacroAssembler::PushRoot(RootIndex index) {
@@ -465,8 +455,9 @@ void MacroAssembler::RecordWrite(Register object, Register address,
DCHECK(value != address);
AssertNotSmi(object);
- if (remembered_set_action == OMIT_REMEMBERED_SET &&
- !FLAG_incremental_marking) {
+ if ((remembered_set_action == OMIT_REMEMBERED_SET &&
+ !FLAG_incremental_marking) ||
+ FLAG_disable_write_barriers) {
return;
}
@@ -1875,11 +1866,7 @@ void TurboAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
if (isolate()->builtins()->IsBuiltinHandle(code_object, &builtin_index) &&
Builtins::IsIsolateIndependent(builtin_index)) {
// Inline the trampoline.
- RecordCommentForOffHeapTrampoline(builtin_index);
- CHECK_NE(builtin_index, Builtins::kNoBuiltinId);
- EmbeddedData d = EmbeddedData::FromBlob();
- Address entry = d.InstructionStartOfBuiltin(builtin_index);
- call(entry, RelocInfo::OFF_HEAP_TARGET);
+ CallBuiltin(builtin_index);
return;
}
}
@@ -1907,6 +1894,16 @@ void TurboAssembler::CallBuiltinByIndex(Register builtin_index) {
call(builtin_index);
}
+void TurboAssembler::CallBuiltin(int builtin_index) {
+ DCHECK(Builtins::IsBuiltinId(builtin_index));
+ DCHECK(FLAG_embedded_builtins);
+ RecordCommentForOffHeapTrampoline(builtin_index);
+ CHECK_NE(builtin_index, Builtins::kNoBuiltinId);
+ EmbeddedData d = EmbeddedData::FromBlob();
+ Address entry = d.InstructionStartOfBuiltin(builtin_index);
+ call(entry, RelocInfo::OFF_HEAP_TARGET);
+}
+
void TurboAssembler::LoadCodeObjectEntry(Register destination,
Register code_object) {
// Code objects are called differently depending on whether we are generating
@@ -1960,6 +1957,12 @@ void TurboAssembler::JumpCodeObject(Register code_object) {
jmp(code_object);
}
+void TurboAssembler::Jump(const ExternalReference& reference) {
+ DCHECK(root_array_available());
+ jmp(Operand(kRootRegister, RootRegisterOffsetForExternalReferenceTableEntry(
+ isolate(), reference)));
+}
+
void TurboAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
DCHECK_IMPLIES(options().isolate_independent_code,
Builtins::IsIsolateIndependentBuiltin(*code_object));
diff --git a/deps/v8/src/codegen/ia32/macro-assembler-ia32.h b/deps/v8/src/codegen/ia32/macro-assembler-ia32.h
index 9b13e87447..c65871cfad 100644
--- a/deps/v8/src/codegen/ia32/macro-assembler-ia32.h
+++ b/deps/v8/src/codegen/ia32/macro-assembler-ia32.h
@@ -91,10 +91,12 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
// register.
void LoadEntryFromBuiltinIndex(Register builtin_index);
void CallBuiltinByIndex(Register builtin_index) override;
+ void CallBuiltin(int builtin_index);
void LoadCodeObjectEntry(Register destination, Register code_object) override;
void CallCodeObject(Register code_object) override;
void JumpCodeObject(Register code_object) override;
+ void Jump(const ExternalReference& reference) override;
void RetpolineCall(Register reg);
void RetpolineCall(Address destination, RelocInfo::Mode rmode);
@@ -213,7 +215,6 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void LoadAddress(Register destination, ExternalReference source);
- void CompareStackLimit(Register with);
void CompareRealStackLimit(Register with);
void CompareRoot(Register with, RootIndex index);
void CompareRoot(Register with, Register scratch, RootIndex index);
diff --git a/deps/v8/src/codegen/interface-descriptors.cc b/deps/v8/src/codegen/interface-descriptors.cc
index 5934c80a7d..f537ebc899 100644
--- a/deps/v8/src/codegen/interface-descriptors.cc
+++ b/deps/v8/src/codegen/interface-descriptors.cc
@@ -416,10 +416,20 @@ void I64ToBigIntDescriptor::InitializePlatformSpecific(
DefaultInitializePlatformSpecific(data, kParameterCount);
}
+void I32PairToBigIntDescriptor::InitializePlatformSpecific(
+ CallInterfaceDescriptorData* data) {
+ DefaultInitializePlatformSpecific(data, kParameterCount);
+}
+
void BigIntToI64Descriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
DefaultInitializePlatformSpecific(data, kParameterCount);
}
+void BigIntToI32PairDescriptor::InitializePlatformSpecific(
+ CallInterfaceDescriptorData* data) {
+ DefaultInitializePlatformSpecific(data, kParameterCount);
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/codegen/interface-descriptors.h b/deps/v8/src/codegen/interface-descriptors.h
index f6c1adfe47..544d62fd9f 100644
--- a/deps/v8/src/codegen/interface-descriptors.h
+++ b/deps/v8/src/codegen/interface-descriptors.h
@@ -28,7 +28,9 @@ namespace internal {
V(ArraySingleArgumentConstructor) \
V(AsyncFunctionStackParameter) \
V(BigIntToI64) \
+ V(BigIntToI32Pair) \
V(I64ToBigInt) \
+ V(I32PairToBigInt) \
V(BinaryOp) \
V(CallForwardVarargs) \
V(CallFunctionTemplate) \
@@ -660,11 +662,13 @@ class StoreGlobalWithVectorDescriptor : public StoreGlobalDescriptor {
class LoadWithVectorDescriptor : public LoadDescriptor {
public:
+ // 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)
- DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kReceiver
- MachineType::AnyTagged(), // kName
- MachineType::TaggedSigned(), // kSlot
- MachineType::AnyTagged()) // kVector
+ DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kReceiver
+ MachineType::AnyTagged(), // kName
+ MachineType::AnyTagged(), // kSlot
+ MachineType::AnyTagged()) // kVector
DECLARE_DESCRIPTOR(LoadWithVectorDescriptor, LoadDescriptor)
static const Register VectorRegister();
@@ -1205,14 +1209,26 @@ class WasmThrowDescriptor final : public CallInterfaceDescriptor {
DECLARE_DESCRIPTOR(WasmThrowDescriptor, CallInterfaceDescriptor)
};
-class I64ToBigIntDescriptor final : public CallInterfaceDescriptor {
+class V8_EXPORT_PRIVATE I64ToBigIntDescriptor final
+ : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kArgument)
DEFINE_PARAMETER_TYPES(MachineType::Int64()) // kArgument
DECLARE_DESCRIPTOR(I64ToBigIntDescriptor, CallInterfaceDescriptor)
};
-class BigIntToI64Descriptor final : public CallInterfaceDescriptor {
+// 32 bits version of the I64ToBigIntDescriptor call interface descriptor
+class V8_EXPORT_PRIVATE I32PairToBigIntDescriptor final
+ : public CallInterfaceDescriptor {
+ public:
+ DEFINE_PARAMETERS_NO_CONTEXT(kLow, kHigh)
+ DEFINE_PARAMETER_TYPES(MachineType::Uint32(), // kLow
+ MachineType::Uint32()) // kHigh
+ DECLARE_DESCRIPTOR(I32PairToBigIntDescriptor, CallInterfaceDescriptor)
+};
+
+class V8_EXPORT_PRIVATE BigIntToI64Descriptor final
+ : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kArgument)
DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::Int64(), // result 1
@@ -1220,6 +1236,16 @@ class BigIntToI64Descriptor final : public CallInterfaceDescriptor {
DECLARE_DESCRIPTOR(BigIntToI64Descriptor, CallInterfaceDescriptor)
};
+class V8_EXPORT_PRIVATE BigIntToI32PairDescriptor final
+ : public CallInterfaceDescriptor {
+ public:
+ DEFINE_RESULT_AND_PARAMETERS(2, kArgument)
+ DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::Uint32(), // result 1
+ MachineType::Uint32(), // result 2
+ MachineType::AnyTagged()) // kArgument
+ DECLARE_DESCRIPTOR(BigIntToI32PairDescriptor, CallInterfaceDescriptor)
+};
+
class WasmAtomicNotifyDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kAddress, kCount)
diff --git a/deps/v8/src/codegen/macro-assembler.h b/deps/v8/src/codegen/macro-assembler.h
index 29da269e8c..0e588c0805 100644
--- a/deps/v8/src/codegen/macro-assembler.h
+++ b/deps/v8/src/codegen/macro-assembler.h
@@ -61,7 +61,7 @@ namespace v8 {
namespace internal {
// Simulators only support C calls with up to kMaxCParameters parameters.
-static constexpr int kMaxCParameters = 9;
+static constexpr int kMaxCParameters = 10;
class FrameScope {
public:
diff --git a/deps/v8/src/codegen/mips/assembler-mips.h b/deps/v8/src/codegen/mips/assembler-mips.h
index 86a07ab06e..0359be2c94 100644
--- a/deps/v8/src/codegen/mips/assembler-mips.h
+++ b/deps/v8/src/codegen/mips/assembler-mips.h
@@ -122,7 +122,7 @@ class Operand {
// On MIPS we have only one addressing mode with base_reg + offset.
// Class MemOperand represents a memory operand in load and store instructions.
-class MemOperand : public Operand {
+class V8_EXPORT_PRIVATE MemOperand : public Operand {
public:
// Immediate value attached to offset.
enum OffsetAddend { offset_minus_one = -1, offset_zero = 0 };
@@ -1872,7 +1872,7 @@ class EnsureSpace {
explicit inline EnsureSpace(Assembler* assembler);
};
-class UseScratchRegisterScope {
+class V8_EXPORT_PRIVATE UseScratchRegisterScope {
public:
explicit UseScratchRegisterScope(Assembler* assembler);
~UseScratchRegisterScope();
diff --git a/deps/v8/src/codegen/mips/macro-assembler-mips.cc b/deps/v8/src/codegen/mips/macro-assembler-mips.cc
index 79373c1b5b..2e4698a9e7 100644
--- a/deps/v8/src/codegen/mips/macro-assembler-mips.cc
+++ b/deps/v8/src/codegen/mips/macro-assembler-mips.cc
@@ -330,8 +330,9 @@ void MacroAssembler::RecordWrite(Register object, Register address,
Operand(value));
}
- if (remembered_set_action == OMIT_REMEMBERED_SET &&
- !FLAG_incremental_marking) {
+ if ((remembered_set_action == OMIT_REMEMBERED_SET &&
+ !FLAG_incremental_marking) ||
+ FLAG_disable_write_barriers) {
return;
}
@@ -1302,6 +1303,18 @@ void TurboAssembler::Sdc1(FPURegister fd, const MemOperand& src) {
CheckTrampolinePoolQuick(1);
}
+void TurboAssembler::Lw(Register rd, const MemOperand& rs) {
+ MemOperand source = rs;
+ AdjustBaseAndOffset(source);
+ lw(rd, source);
+}
+
+void TurboAssembler::Sw(Register rd, const MemOperand& rs) {
+ MemOperand dest = rs;
+ AdjustBaseAndOffset(dest);
+ sw(rd, dest);
+}
+
void TurboAssembler::Ll(Register rd, const MemOperand& rs) {
bool is_one_instruction = IsMipsArchVariant(kMips32r6)
? is_int9(rs.offset())
@@ -3839,6 +3852,13 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
Jump(static_cast<intptr_t>(code.address()), rmode, cond, rs, rt, bd);
}
+void TurboAssembler::Jump(const ExternalReference& reference) {
+ UseScratchRegisterScope temps(this);
+ Register scratch = temps.Acquire();
+ li(scratch, reference);
+ Jump(scratch);
+}
+
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
unsigned higher_limit,
Label* on_in_range) {
diff --git a/deps/v8/src/codegen/mips/macro-assembler-mips.h b/deps/v8/src/codegen/mips/macro-assembler-mips.h
index 3dfc7bfbad..d9c372f868 100644
--- a/deps/v8/src/codegen/mips/macro-assembler-mips.h
+++ b/deps/v8/src/codegen/mips/macro-assembler-mips.h
@@ -206,6 +206,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Jump(intptr_t target, RelocInfo::Mode rmode, COND_ARGS);
void Jump(Address target, RelocInfo::Mode rmode, COND_ARGS);
void Jump(Handle<Code> code, RelocInfo::Mode rmode, COND_ARGS);
+ void Jump(const ExternalReference& reference) override;
void Call(Register target, int16_t offset = 0, COND_ARGS);
void Call(Register target, Register base, int16_t offset = 0, COND_ARGS);
void Call(Address target, RelocInfo::Mode rmode, COND_ARGS);
@@ -258,6 +259,9 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void DropAndRet(int drop, Condition cond, Register reg, const Operand& op);
+ void Lw(Register rd, const MemOperand& rs);
+ void Sw(Register rd, const MemOperand& rs);
+
void push(Register src) {
Addu(sp, sp, Operand(-kPointerSize));
sw(src, MemOperand(sp, 0));
diff --git a/deps/v8/src/codegen/mips64/assembler-mips64.h b/deps/v8/src/codegen/mips64/assembler-mips64.h
index a22ddf0e7d..9695aa6524 100644
--- a/deps/v8/src/codegen/mips64/assembler-mips64.h
+++ b/deps/v8/src/codegen/mips64/assembler-mips64.h
@@ -121,7 +121,7 @@ class Operand {
// On MIPS we have only one addressing mode with base_reg + offset.
// Class MemOperand represents a memory operand in load and store instructions.
-class MemOperand : public Operand {
+class V8_EXPORT_PRIVATE MemOperand : public Operand {
public:
// Immediate value attached to offset.
enum OffsetAddend { offset_minus_one = -1, offset_zero = 0 };
@@ -1899,7 +1899,7 @@ class EnsureSpace {
explicit inline EnsureSpace(Assembler* assembler);
};
-class UseScratchRegisterScope {
+class V8_EXPORT_PRIVATE UseScratchRegisterScope {
public:
explicit UseScratchRegisterScope(Assembler* assembler);
~UseScratchRegisterScope();
diff --git a/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc b/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc
index 97e5af1fa8..b353786064 100644
--- a/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc
+++ b/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc
@@ -328,8 +328,9 @@ void MacroAssembler::RecordWrite(Register object, Register address,
Operand(value));
}
- if (remembered_set_action == OMIT_REMEMBERED_SET &&
- !FLAG_incremental_marking) {
+ if ((remembered_set_action == OMIT_REMEMBERED_SET &&
+ !FLAG_incremental_marking) ||
+ FLAG_disable_write_barriers) {
return;
}
@@ -4200,6 +4201,13 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
Jump(static_cast<intptr_t>(code.address()), rmode, cond, rs, rt, bd);
}
+void TurboAssembler::Jump(const ExternalReference& reference) {
+ UseScratchRegisterScope temps(this);
+ Register scratch = temps.Acquire();
+ li(scratch, reference);
+ Jump(scratch);
+}
+
// Note: To call gcc-compiled C code on mips, you must call through t9.
void TurboAssembler::Call(Register target, Condition cond, Register rs,
const Operand& rt, BranchDelaySlot bd) {
diff --git a/deps/v8/src/codegen/mips64/macro-assembler-mips64.h b/deps/v8/src/codegen/mips64/macro-assembler-mips64.h
index eb62bec0e8..c2b701a5af 100644
--- a/deps/v8/src/codegen/mips64/macro-assembler-mips64.h
+++ b/deps/v8/src/codegen/mips64/macro-assembler-mips64.h
@@ -229,6 +229,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Jump(intptr_t target, RelocInfo::Mode rmode, COND_ARGS);
void Jump(Address target, RelocInfo::Mode rmode, COND_ARGS);
void Jump(Handle<Code> code, RelocInfo::Mode rmode, COND_ARGS);
+ void Jump(const ExternalReference& reference) override;
void Call(Register target, COND_ARGS);
void Call(Address target, RelocInfo::Mode rmode, COND_ARGS);
void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
diff --git a/deps/v8/src/codegen/optimized-compilation-info.cc b/deps/v8/src/codegen/optimized-compilation-info.cc
index f3582d868a..7dc94f39cd 100644
--- a/deps/v8/src/codegen/optimized-compilation-info.cc
+++ b/deps/v8/src/codegen/optimized-compilation-info.cc
@@ -21,6 +21,7 @@ OptimizedCompilationInfo::OptimizedCompilationInfo(
Zone* zone, Isolate* isolate, Handle<SharedFunctionInfo> shared,
Handle<JSFunction> closure)
: OptimizedCompilationInfo(Code::OPTIMIZED_FUNCTION, zone) {
+ DCHECK_EQ(*shared, closure->shared());
DCHECK(shared->is_compiled());
bytecode_array_ = handle(shared->GetBytecodeArray(), isolate);
shared_info_ = shared;
diff --git a/deps/v8/src/codegen/pending-optimization-table.cc b/deps/v8/src/codegen/pending-optimization-table.cc
index 9e33de7918..b7be9c7775 100644
--- a/deps/v8/src/codegen/pending-optimization-table.cc
+++ b/deps/v8/src/codegen/pending-optimization-table.cc
@@ -4,6 +4,7 @@
#include "src/codegen/pending-optimization-table.h"
+#include "src/base/flags.h"
#include "src/execution/isolate-inl.h"
#include "src/heap/heap-inl.h"
#include "src/objects/hash-table.h"
@@ -12,12 +13,24 @@
namespace v8 {
namespace internal {
-enum class FunctionStatus { kPrepareForOptimize, kMarkForOptimize };
+enum class FunctionStatus : int {
+ kPrepareForOptimize = 1 << 0,
+ kMarkForOptimize = 1 << 1,
+ kAllowHeuristicOptimization = 1 << 2,
+};
+
+using FunctionStatusFlags = base::Flags<FunctionStatus>;
void PendingOptimizationTable::PreparedForOptimization(
- Isolate* isolate, Handle<JSFunction> function) {
+ Isolate* isolate, Handle<JSFunction> function,
+ bool allow_heuristic_optimization) {
DCHECK(FLAG_testing_d8_test_runner);
+ FunctionStatusFlags status = FunctionStatus::kPrepareForOptimize;
+ if (allow_heuristic_optimization) {
+ status |= FunctionStatus::kAllowHeuristicOptimization;
+ }
+
Handle<ObjectHashTable> table =
isolate->heap()->pending_optimize_for_test_bytecode().IsUndefined()
? ObjectHashTable::New(isolate, 1)
@@ -26,15 +39,33 @@ void PendingOptimizationTable::PreparedForOptimization(
isolate);
Handle<Tuple2> tuple = isolate->factory()->NewTuple2(
handle(function->shared().GetBytecodeArray(), isolate),
- handle(
- Smi::FromInt(static_cast<int>(FunctionStatus::kPrepareForOptimize)),
- isolate),
- AllocationType::kYoung);
+ handle(Smi::FromInt(status), isolate), AllocationType::kYoung);
table =
ObjectHashTable::Put(table, handle(function->shared(), isolate), tuple);
isolate->heap()->SetPendingOptimizeForTestBytecode(*table);
}
+bool PendingOptimizationTable::IsHeuristicOptimizationAllowed(
+ Isolate* isolate, JSFunction function) {
+ DCHECK(FLAG_testing_d8_test_runner);
+
+ Handle<Object> table =
+ handle(isolate->heap()->pending_optimize_for_test_bytecode(), isolate);
+ Handle<Object> entry =
+ table->IsUndefined()
+ ? handle(ReadOnlyRoots(isolate).the_hole_value(), isolate)
+ : handle(Handle<ObjectHashTable>::cast(table)->Lookup(
+ handle(function.shared(), isolate)),
+ isolate);
+ if (entry->IsTheHole()) {
+ return true;
+ }
+ DCHECK(entry->IsTuple2());
+ DCHECK(Handle<Tuple2>::cast(entry)->value2().IsSmi());
+ FunctionStatusFlags status(Smi::ToInt(Handle<Tuple2>::cast(entry)->value2()));
+ return status & FunctionStatus::kAllowHeuristicOptimization;
+}
+
void PendingOptimizationTable::MarkedForOptimization(
Isolate* isolate, Handle<JSFunction> function) {
DCHECK(FLAG_testing_d8_test_runner);
@@ -58,8 +89,11 @@ void PendingOptimizationTable::MarkedForOptimization(
}
DCHECK(entry->IsTuple2());
- Handle<Tuple2>::cast(entry)->set_value2(
- Smi::FromInt(static_cast<int>(FunctionStatus::kMarkForOptimize)));
+ DCHECK(Handle<Tuple2>::cast(entry)->value2().IsSmi());
+ FunctionStatusFlags status(Smi::ToInt(Handle<Tuple2>::cast(entry)->value2()));
+ status = status.without(FunctionStatus::kPrepareForOptimize) |
+ FunctionStatus::kMarkForOptimize;
+ Handle<Tuple2>::cast(entry)->set_value2(Smi::FromInt(status));
table = ObjectHashTable::Put(Handle<ObjectHashTable>::cast(table),
handle(function->shared(), isolate), entry);
isolate->heap()->SetPendingOptimizeForTestBytecode(*table);
diff --git a/deps/v8/src/codegen/pending-optimization-table.h b/deps/v8/src/codegen/pending-optimization-table.h
index 2a2782d17a..43b939726d 100644
--- a/deps/v8/src/codegen/pending-optimization-table.h
+++ b/deps/v8/src/codegen/pending-optimization-table.h
@@ -21,7 +21,8 @@ class PendingOptimizationTable {
// strongly in pending optimization table preventing the bytecode to be
// flushed.
static void PreparedForOptimization(Isolate* isolate,
- Handle<JSFunction> function);
+ Handle<JSFunction> function,
+ bool allow_heuristic_optimization);
// This function should be called when the function is marked for optimization
// via the intrinsics. This will update the state of the bytecode array in the
@@ -36,6 +37,12 @@ class PendingOptimizationTable {
// then this function removes the entry from pending optimization table.
static void FunctionWasOptimized(Isolate* isolate,
Handle<JSFunction> function);
+
+ // This function returns whether a heuristic is allowed to trigger
+ // optimization the function. This mechanism is used in tests to prevent
+ // heuristics from interfering with manually triggered optimization.
+ static bool IsHeuristicOptimizationAllowed(Isolate* isolate,
+ JSFunction function);
};
} // namespace internal
diff --git a/deps/v8/src/codegen/ppc/macro-assembler-ppc.cc b/deps/v8/src/codegen/ppc/macro-assembler-ppc.cc
index 8ab3e5b83b..4116206333 100644
--- a/deps/v8/src/codegen/ppc/macro-assembler-ppc.cc
+++ b/deps/v8/src/codegen/ppc/macro-assembler-ppc.cc
@@ -205,6 +205,13 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
Jump(static_cast<intptr_t>(code.address()), rmode, cond, cr);
}
+void TurboAssembler::Jump(const ExternalReference& reference) {
+ UseScratchRegisterScope temps(this);
+ Register scratch = temps.Acquire();
+ Move(scratch, reference);
+ Jump(scratch);
+}
+
void TurboAssembler::Call(Register target) {
BlockTrampolinePoolScope block_trampoline_pool(this);
// branch via link register and set LK bit for return point
@@ -558,8 +565,9 @@ void MacroAssembler::RecordWrite(Register object, Register address,
Check(eq, AbortReason::kWrongAddressOrValuePassedToRecordWrite);
}
- if (remembered_set_action == OMIT_REMEMBERED_SET &&
- !FLAG_incremental_marking) {
+ if ((remembered_set_action == OMIT_REMEMBERED_SET &&
+ !FLAG_incremental_marking) ||
+ FLAG_disable_write_barriers) {
return;
}
diff --git a/deps/v8/src/codegen/ppc/macro-assembler-ppc.h b/deps/v8/src/codegen/ppc/macro-assembler-ppc.h
index 6249c405e3..fd4cb6014b 100644
--- a/deps/v8/src/codegen/ppc/macro-assembler-ppc.h
+++ b/deps/v8/src/codegen/ppc/macro-assembler-ppc.h
@@ -400,6 +400,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
CRegister cr = cr7);
void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al,
CRegister cr = cr7);
+ void Jump(const ExternalReference& reference) override;
void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al,
CRegister cr = cr7);
void Call(Register target);
diff --git a/deps/v8/src/codegen/register.cc b/deps/v8/src/codegen/register.cc
new file mode 100644
index 0000000000..4ad76c6caa
--- /dev/null
+++ b/deps/v8/src/codegen/register.cc
@@ -0,0 +1,16 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/codegen/register.h"
+#include "src/codegen/register-arch.h"
+
+namespace v8 {
+namespace internal {
+
+bool ShouldPadArguments(int argument_count) {
+ return kPadArguments && (argument_count % 2 != 0);
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/codegen/register.h b/deps/v8/src/codegen/register.h
index 619f4f2890..406a423892 100644
--- a/deps/v8/src/codegen/register.h
+++ b/deps/v8/src/codegen/register.h
@@ -105,6 +105,9 @@ class RegisterBase {
int reg_code_;
};
+// Whether padding is needed for the given stack argument count.
+bool ShouldPadArguments(int argument_count);
+
template <typename RegType,
typename = decltype(RegisterName(std::declval<RegType>()))>
inline std::ostream& operator<<(std::ostream& os, RegType reg) {
diff --git a/deps/v8/src/codegen/s390/assembler-s390.cc b/deps/v8/src/codegen/s390/assembler-s390.cc
index 6776626a23..873c0a2ad0 100644
--- a/deps/v8/src/codegen/s390/assembler-s390.cc
+++ b/deps/v8/src/codegen/s390/assembler-s390.cc
@@ -35,7 +35,6 @@
// Copyright 2014 the V8 project authors. All rights reserved.
#include "src/codegen/s390/assembler-s390.h"
-#include <sys/auxv.h>
#include <set>
#include <string>
@@ -43,6 +42,7 @@
#if V8_HOST_ARCH_S390
#include <elf.h> // Required for auxv checks for STFLE support
+#include <sys/auxv.h>
#endif
#include "src/base/bits.h"
diff --git a/deps/v8/src/codegen/s390/macro-assembler-s390.cc b/deps/v8/src/codegen/s390/macro-assembler-s390.cc
index f6c2314a84..355d536379 100644
--- a/deps/v8/src/codegen/s390/macro-assembler-s390.cc
+++ b/deps/v8/src/codegen/s390/macro-assembler-s390.cc
@@ -193,6 +193,13 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
jump(code, RelocInfo::RELATIVE_CODE_TARGET, cond);
}
+void TurboAssembler::Jump(const ExternalReference& reference) {
+ UseScratchRegisterScope temps(this);
+ Register scratch = temps.Acquire();
+ Move(scratch, reference);
+ Jump(scratch);
+}
+
void TurboAssembler::Call(Register target) {
// Branch to target via indirect branch
basr(r14, target);
@@ -576,8 +583,9 @@ void MacroAssembler::RecordWrite(Register object, Register address,
Check(eq, AbortReason::kWrongAddressOrValuePassedToRecordWrite);
}
- if (remembered_set_action == OMIT_REMEMBERED_SET &&
- !FLAG_incremental_marking) {
+ if ((remembered_set_action == OMIT_REMEMBERED_SET &&
+ !FLAG_incremental_marking) ||
+ FLAG_disable_write_barriers) {
return;
}
// First, check if a write barrier is even needed. The tests below
diff --git a/deps/v8/src/codegen/s390/macro-assembler-s390.h b/deps/v8/src/codegen/s390/macro-assembler-s390.h
index 52f668d175..856e4b592e 100644
--- a/deps/v8/src/codegen/s390/macro-assembler-s390.h
+++ b/deps/v8/src/codegen/s390/macro-assembler-s390.h
@@ -137,6 +137,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Jump(Register target, Condition cond = al);
void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
+ void Jump(const ExternalReference& reference) override;
// Jump the register contains a smi.
inline void JumpIfSmi(Register value, Label* smi_label) {
TestIfSmi(value);
diff --git a/deps/v8/src/codegen/safepoint-table.cc b/deps/v8/src/codegen/safepoint-table.cc
index 2afdb5f90c..962b1ea17f 100644
--- a/deps/v8/src/codegen/safepoint-table.cc
+++ b/deps/v8/src/codegen/safepoint-table.cc
@@ -91,32 +91,24 @@ Safepoint SafepointTableBuilder::DefineSafepoint(
Assembler* assembler, Safepoint::DeoptMode deopt_mode) {
deoptimization_info_.push_back(
DeoptimizationInfo(zone_, assembler->pc_offset()));
- if (deopt_mode == Safepoint::kNoLazyDeopt) {
- last_lazy_safepoint_ = deoptimization_info_.size();
- }
DeoptimizationInfo& new_info = deoptimization_info_.back();
return Safepoint(new_info.indexes);
}
-void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) {
- for (auto it = deoptimization_info_.Find(last_lazy_safepoint_);
- it != deoptimization_info_.end(); it++, last_lazy_safepoint_++) {
- it->deopt_index = index;
- }
-}
-
unsigned SafepointTableBuilder::GetCodeOffset() const {
DCHECK(emitted_);
return offset_;
}
int SafepointTableBuilder::UpdateDeoptimizationInfo(int pc, int trampoline,
- int start) {
+ int start,
+ unsigned deopt_index) {
int index = start;
for (auto it = deoptimization_info_.Find(start);
it != deoptimization_info_.end(); it++, index++) {
if (static_cast<int>(it->pc) == pc) {
it->trampoline = trampoline;
+ it->deopt_index = deopt_index;
return index;
}
}
diff --git a/deps/v8/src/codegen/safepoint-table.h b/deps/v8/src/codegen/safepoint-table.h
index fccce1a7a6..1df4311036 100644
--- a/deps/v8/src/codegen/safepoint-table.h
+++ b/deps/v8/src/codegen/safepoint-table.h
@@ -164,7 +164,6 @@ class SafepointTableBuilder {
explicit SafepointTableBuilder(Zone* zone)
: deoptimization_info_(zone),
emitted_(false),
- last_lazy_safepoint_(0),
zone_(zone) {}
// Get the offset of the emitted safepoint table in the code.
@@ -173,13 +172,6 @@ class SafepointTableBuilder {
// Define a new safepoint for the current position in the body.
Safepoint DefineSafepoint(Assembler* assembler, Safepoint::DeoptMode mode);
- // Record deoptimization index for lazy deoptimization for the last
- // outstanding safepoints.
- void RecordLazyDeoptimizationIndex(int index);
- void BumpLastLazySafepointIndex() {
- last_lazy_safepoint_ = deoptimization_info_.size();
- }
-
// Emit the safepoint table after the body. The number of bits per
// entry must be enough to hold all the pointer indexes.
V8_EXPORT_PRIVATE void Emit(Assembler* assembler, int bits_per_entry);
@@ -188,7 +180,8 @@ class SafepointTableBuilder {
// trampoline field. Calling this function ensures that the safepoint
// table contains the trampoline PC {trampoline} that replaced the
// return PC {pc} on the stack.
- int UpdateDeoptimizationInfo(int pc, int trampoline, int start);
+ int UpdateDeoptimizationInfo(int pc, int trampoline, int start,
+ unsigned deopt_index);
private:
struct DeoptimizationInfo {
@@ -215,7 +208,6 @@ class SafepointTableBuilder {
unsigned offset_;
bool emitted_;
- size_t last_lazy_safepoint_;
Zone* zone_;
diff --git a/deps/v8/src/codegen/source-position-table.cc b/deps/v8/src/codegen/source-position-table.cc
index e10cc07571..870241eac6 100644
--- a/deps/v8/src/codegen/source-position-table.cc
+++ b/deps/v8/src/codegen/source-position-table.cc
@@ -27,8 +27,8 @@ namespace internal {
namespace {
// Each byte is encoded as MoreBit | ValueBits.
-class MoreBit : public BitField8<bool, 7, 1> {};
-class ValueBits : public BitField8<unsigned, 0, 7> {};
+using MoreBit = BitField8<bool, 7, 1>;
+using ValueBits = BitField8<unsigned, 0, 7>;
// Helper: Add the offsets from 'other' to 'value'. Also set is_statement.
void AddAndSetEntry(PositionTableEntry& value, // NOLINT(runtime/references)
diff --git a/deps/v8/src/codegen/turbo-assembler.h b/deps/v8/src/codegen/turbo-assembler.h
index 2f058eda19..3a3e65a41e 100644
--- a/deps/v8/src/codegen/turbo-assembler.h
+++ b/deps/v8/src/codegen/turbo-assembler.h
@@ -50,6 +50,8 @@ class V8_EXPORT_PRIVATE TurboAssemblerBase : public Assembler {
void set_has_frame(bool v) { has_frame_ = v; }
bool has_frame() const { return has_frame_; }
+ virtual void Jump(const ExternalReference& reference) = 0;
+
// Calls the builtin given by the Smi in |builtin|. If builtins are embedded,
// the trampoline Code object on the heap is not used.
virtual void CallBuiltinByIndex(Register builtin_index) = 0;
diff --git a/deps/v8/src/codegen/x64/assembler-x64.cc b/deps/v8/src/codegen/x64/assembler-x64.cc
index 1d28f1d45d..1783da700b 100644
--- a/deps/v8/src/codegen/x64/assembler-x64.cc
+++ b/deps/v8/src/codegen/x64/assembler-x64.cc
@@ -109,15 +109,16 @@ void CpuFeatures::ProbeImpl(bool cross_compile) {
void CpuFeatures::PrintTarget() {}
void CpuFeatures::PrintFeatures() {
printf(
- "SSE3=%d SSSE3=%d SSE4_1=%d SAHF=%d AVX=%d FMA3=%d BMI1=%d BMI2=%d "
+ "SSE3=%d SSSE3=%d SSE4_1=%d SSE4_2=%d SAHF=%d AVX=%d FMA3=%d BMI1=%d "
+ "BMI2=%d "
"LZCNT=%d "
"POPCNT=%d ATOM=%d\n",
CpuFeatures::IsSupported(SSE3), CpuFeatures::IsSupported(SSSE3),
- CpuFeatures::IsSupported(SSE4_1), CpuFeatures::IsSupported(SAHF),
- CpuFeatures::IsSupported(AVX), CpuFeatures::IsSupported(FMA3),
- CpuFeatures::IsSupported(BMI1), CpuFeatures::IsSupported(BMI2),
- CpuFeatures::IsSupported(LZCNT), CpuFeatures::IsSupported(POPCNT),
- CpuFeatures::IsSupported(ATOM));
+ CpuFeatures::IsSupported(SSE4_1), CpuFeatures::IsSupported(SSE4_2),
+ CpuFeatures::IsSupported(SAHF), CpuFeatures::IsSupported(AVX),
+ CpuFeatures::IsSupported(FMA3), CpuFeatures::IsSupported(BMI1),
+ CpuFeatures::IsSupported(BMI2), CpuFeatures::IsSupported(LZCNT),
+ CpuFeatures::IsSupported(POPCNT), CpuFeatures::IsSupported(ATOM));
}
// -----------------------------------------------------------------------------
@@ -428,6 +429,9 @@ Assembler::Assembler(const AssemblerOptions& options,
std::unique_ptr<AssemblerBuffer> buffer)
: AssemblerBase(options, std::move(buffer)), constpool_(this) {
reloc_info_writer.Reposition(buffer_start_ + buffer_->size(), pc_);
+ if (CpuFeatures::IsSupported(SSE4_2)) {
+ EnableCpuFeature(SSE4_1);
+ }
if (CpuFeatures::IsSupported(SSE4_1)) {
EnableCpuFeature(SSSE3);
}
@@ -3524,8 +3528,8 @@ void Assembler::cmpps(XMMRegister dst, Operand src, int8_t cmp) {
void Assembler::cmppd(XMMRegister dst, XMMRegister src, int8_t cmp) {
EnsureSpace ensure_space(this);
- emit_optional_rex_32(dst, src);
emit(0x66);
+ emit_optional_rex_32(dst, src);
emit(0x0F);
emit(0xC2);
emit_sse_operand(dst, src);
@@ -3534,8 +3538,8 @@ void Assembler::cmppd(XMMRegister dst, XMMRegister src, int8_t cmp) {
void Assembler::cmppd(XMMRegister dst, Operand src, int8_t cmp) {
EnsureSpace ensure_space(this);
- emit_optional_rex_32(dst, src);
emit(0x66);
+ emit_optional_rex_32(dst, src);
emit(0x0F);
emit(0xC2);
emit_sse_operand(dst, src);
@@ -4716,6 +4720,26 @@ void Assembler::lddqu(XMMRegister dst, Operand src) {
emit_sse_operand(dst, src);
}
+void Assembler::movddup(XMMRegister dst, XMMRegister src) {
+ DCHECK(IsEnabled(SSE3));
+ EnsureSpace ensure_space(this);
+ emit(0xF2);
+ emit_optional_rex_32(dst, src);
+ emit(0x0F);
+ emit(0x12);
+ emit_sse_operand(dst, src);
+}
+
+void Assembler::movddup(XMMRegister dst, Operand src) {
+ DCHECK(IsEnabled(SSE3));
+ EnsureSpace ensure_space(this);
+ emit(0xF2);
+ emit_optional_rex_32(dst, src);
+ emit(0x0F);
+ emit(0x12);
+ emit_sse_operand(dst, src);
+}
+
void Assembler::psrldq(XMMRegister dst, uint8_t shift) {
EnsureSpace ensure_space(this);
emit(0x66);
diff --git a/deps/v8/src/codegen/x64/assembler-x64.h b/deps/v8/src/codegen/x64/assembler-x64.h
index acb4fce82c..7c69b4c473 100644
--- a/deps/v8/src/codegen/x64/assembler-x64.h
+++ b/deps/v8/src/codegen/x64/assembler-x64.h
@@ -916,6 +916,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// SSE3
void lddqu(XMMRegister dst, Operand src);
+ void movddup(XMMRegister dst, Operand src);
+ void movddup(XMMRegister dst, XMMRegister src);
// SSSE3
void ssse3_instr(XMMRegister dst, XMMRegister src, byte prefix, byte escape1,
@@ -1329,14 +1331,14 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
}
AVX_SP_3(vsqrt, 0x51)
- AVX_SP_3(vadd, 0x58)
- AVX_SP_3(vsub, 0x5c)
- AVX_SP_3(vmul, 0x59)
- AVX_SP_3(vdiv, 0x5e)
- AVX_SP_3(vmin, 0x5d)
- AVX_SP_3(vmax, 0x5f)
+ AVX_S_3(vadd, 0x58)
+ AVX_S_3(vsub, 0x5c)
+ AVX_S_3(vmul, 0x59)
+ AVX_S_3(vdiv, 0x5e)
+ AVX_S_3(vmin, 0x5d)
+ AVX_S_3(vmax, 0x5f)
AVX_P_3(vand, 0x54)
- AVX_P_3(vandn, 0x55)
+ AVX_3(vandnps, 0x55, vps)
AVX_P_3(vor, 0x56)
AVX_P_3(vxor, 0x57)
AVX_3(vcvtsd2ss, 0x5a, vsd)
diff --git a/deps/v8/src/codegen/x64/macro-assembler-x64.cc b/deps/v8/src/codegen/x64/macro-assembler-x64.cc
index f13811b1ae..4deeb1bc02 100644
--- a/deps/v8/src/codegen/x64/macro-assembler-x64.cc
+++ b/deps/v8/src/codegen/x64/macro-assembler-x64.cc
@@ -505,8 +505,9 @@ void MacroAssembler::RecordWrite(Register object, Register address,
DCHECK(value != address);
AssertNotSmi(object);
- if (remembered_set_action == OMIT_REMEMBERED_SET &&
- !FLAG_incremental_marking) {
+ if ((remembered_set_action == OMIT_REMEMBERED_SET &&
+ !FLAG_incremental_marking) ||
+ FLAG_disable_write_barriers) {
return;
}
@@ -1523,9 +1524,10 @@ void MacroAssembler::Pop(Operand dst) { popq(dst); }
void MacroAssembler::PopQuad(Operand dst) { popq(dst); }
-void TurboAssembler::Jump(ExternalReference ext) {
- LoadAddress(kScratchRegister, ext);
- jmp(kScratchRegister);
+void TurboAssembler::Jump(const ExternalReference& reference) {
+ DCHECK(root_array_available());
+ jmp(Operand(kRootRegister, RootRegisterOffsetForExternalReferenceTableEntry(
+ isolate(), reference)));
}
void TurboAssembler::Jump(Operand op) { jmp(op); }
@@ -1594,12 +1596,7 @@ void TurboAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
if (isolate()->builtins()->IsBuiltinHandle(code_object, &builtin_index) &&
Builtins::IsIsolateIndependent(builtin_index)) {
// Inline the trampoline.
- RecordCommentForOffHeapTrampoline(builtin_index);
- CHECK_NE(builtin_index, Builtins::kNoBuiltinId);
- EmbeddedData d = EmbeddedData::FromBlob();
- Address entry = d.InstructionStartOfBuiltin(builtin_index);
- Move(kScratchRegister, entry, RelocInfo::OFF_HEAP_TARGET);
- call(kScratchRegister);
+ CallBuiltin(builtin_index);
return;
}
}
@@ -1634,6 +1631,17 @@ void TurboAssembler::CallBuiltinByIndex(Register builtin_index) {
Call(EntryFromBuiltinIndexAsOperand(builtin_index));
}
+void TurboAssembler::CallBuiltin(int builtin_index) {
+ DCHECK(Builtins::IsBuiltinId(builtin_index));
+ DCHECK(FLAG_embedded_builtins);
+ RecordCommentForOffHeapTrampoline(builtin_index);
+ CHECK_NE(builtin_index, Builtins::kNoBuiltinId);
+ EmbeddedData d = EmbeddedData::FromBlob();
+ Address entry = d.InstructionStartOfBuiltin(builtin_index);
+ Move(kScratchRegister, entry, RelocInfo::OFF_HEAP_TARGET);
+ call(kScratchRegister);
+}
+
void TurboAssembler::LoadCodeObjectEntry(Register destination,
Register code_object) {
// Code objects are called differently depending on whether we are generating
diff --git a/deps/v8/src/codegen/x64/macro-assembler-x64.h b/deps/v8/src/codegen/x64/macro-assembler-x64.h
index 139690bb8d..8e7766c7e1 100644
--- a/deps/v8/src/codegen/x64/macro-assembler-x64.h
+++ b/deps/v8/src/codegen/x64/macro-assembler-x64.h
@@ -344,6 +344,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
Operand EntryFromBuiltinIndexAsOperand(Register builtin_index);
void CallBuiltinByIndex(Register builtin_index) override;
+ void CallBuiltin(int builtin_index);
void LoadCodeObjectEntry(Register destination, Register code_object) override;
void CallCodeObject(Register code_object) override;
@@ -353,7 +354,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void RetpolineCall(Address destination, RelocInfo::Mode rmode);
void Jump(Address destination, RelocInfo::Mode rmode);
- void Jump(ExternalReference ext);
+ void Jump(const ExternalReference& reference) override;
void Jump(Operand op);
void Jump(Handle<Code> code_object, RelocInfo::Mode rmode,
Condition cc = always);
diff --git a/deps/v8/src/codegen/x64/sse-instr.h b/deps/v8/src/codegen/x64/sse-instr.h
index 56618d20e0..8ba54e85b4 100644
--- a/deps/v8/src/codegen/x64/sse-instr.h
+++ b/deps/v8/src/codegen/x64/sse-instr.h
@@ -6,7 +6,14 @@
#define V8_CODEGEN_X64_SSE_INSTR_H_
#define SSE2_INSTRUCTION_LIST(V) \
+ V(andnpd, 66, 0F, 55) \
+ V(addpd, 66, 0F, 58) \
+ V(mulpd, 66, 0F, 59) \
V(cvtps2dq, 66, 0F, 5B) \
+ V(subpd, 66, 0F, 5C) \
+ V(minpd, 66, 0F, 5D) \
+ V(maxpd, 66, 0F, 5F) \
+ V(divpd, 66, 0F, 5E) \
V(punpcklbw, 66, 0F, 60) \
V(punpcklwd, 66, 0F, 61) \
V(punpckldq, 66, 0F, 62) \
@@ -40,10 +47,12 @@
V(pmuludq, 66, 0F, F4) \
V(psllw, 66, 0F, F1) \
V(pslld, 66, 0F, F2) \
+ V(psllq, 66, 0F, F3) \
V(psraw, 66, 0F, E1) \
V(psrad, 66, 0F, E2) \
V(psrlw, 66, 0F, D1) \
V(psrld, 66, 0F, D2) \
+ V(psrlq, 66, 0F, D3) \
V(psubb, 66, 0F, F8) \
V(psubw, 66, 0F, F9) \
V(psubd, 66, 0F, FA) \
@@ -68,6 +77,7 @@
V(psignd, 66, 0F, 38, 0A)
#define SSE4_INSTRUCTION_LIST(V) \
+ V(blendvpd, 66, 0F, 38, 15) \
V(pcmpeqq, 66, 0F, 38, 29) \
V(ptest, 66, 0F, 38, 17) \
V(pmovsxbw, 66, 0F, 38, 20) \
diff --git a/deps/v8/src/common/OWNERS b/deps/v8/src/common/OWNERS
index 3f9de7e204..4750620072 100644
--- a/deps/v8/src/common/OWNERS
+++ b/deps/v8/src/common/OWNERS
@@ -1,3 +1,3 @@
-file://COMMON_OWNERS
+file:../../COMMON_OWNERS
# COMPONENT: Blink>JavaScript
diff --git a/deps/v8/src/common/assert-scope.cc b/deps/v8/src/common/assert-scope.cc
index 5a299fa1ee..f1fe717cc0 100644
--- a/deps/v8/src/common/assert-scope.cc
+++ b/deps/v8/src/common/assert-scope.cc
@@ -92,16 +92,18 @@ bool PerThreadAssertScope<kType, kAllow>::IsAllowed() {
return current_data == nullptr || current_data->Get(kType);
}
-template <PerIsolateAssertType kType, bool kAllow>
-class PerIsolateAssertScope<kType, kAllow>::DataBit
- : public BitField<bool, kType, 1> {};
+namespace {
+template <PerIsolateAssertType kType>
+using DataBit = BitField<bool, kType, 1>;
+}
template <PerIsolateAssertType kType, bool kAllow>
PerIsolateAssertScope<kType, kAllow>::PerIsolateAssertScope(Isolate* isolate)
: isolate_(isolate), old_data_(isolate->per_isolate_assert_data()) {
DCHECK_NOT_NULL(isolate);
STATIC_ASSERT(kType < 32);
- isolate_->set_per_isolate_assert_data(DataBit::update(old_data_, kAllow));
+ isolate_->set_per_isolate_assert_data(
+ DataBit<kType>::update(old_data_, kAllow));
}
template <PerIsolateAssertType kType, bool kAllow>
@@ -112,7 +114,7 @@ PerIsolateAssertScope<kType, kAllow>::~PerIsolateAssertScope() {
// static
template <PerIsolateAssertType kType, bool kAllow>
bool PerIsolateAssertScope<kType, kAllow>::IsAllowed(Isolate* isolate) {
- return DataBit::decode(isolate->per_isolate_assert_data());
+ return DataBit<kType>::decode(isolate->per_isolate_assert_data());
}
// -----------------------------------------------------------------------------
diff --git a/deps/v8/src/common/assert-scope.h b/deps/v8/src/common/assert-scope.h
index 606439d42b..73729400ac 100644
--- a/deps/v8/src/common/assert-scope.h
+++ b/deps/v8/src/common/assert-scope.h
@@ -81,8 +81,6 @@ class PerIsolateAssertScope {
static bool IsAllowed(Isolate* isolate);
private:
- class DataBit;
-
Isolate* isolate_;
uint32_t old_data_;
diff --git a/deps/v8/src/common/globals.h b/deps/v8/src/common/globals.h
index 8d1bf5dfcc..a0584b95c4 100644
--- a/deps/v8/src/common/globals.h
+++ b/deps/v8/src/common/globals.h
@@ -101,6 +101,14 @@ constexpr int kStackSpaceRequiredForCompilation = 40;
#define V8_OS_WIN_X64 true
#endif
+#if defined(V8_OS_WIN) && defined(V8_TARGET_ARCH_ARM64)
+#define V8_OS_WIN_ARM64 true
+#endif
+
+#if defined(V8_OS_WIN_X64) || defined(V8_OS_WIN_ARM64)
+#define V8_OS_WIN64 true
+#endif
+
// Superclass for classes only using static method functions.
// The subclass of AllStatic cannot be instantiated at all.
class AllStatic {
@@ -882,14 +890,14 @@ constexpr int kIeeeDoubleExponentWordOffset = 0;
// Testers for test.
#define HAS_SMI_TAG(value) \
- ((static_cast<intptr_t>(value) & ::i::kSmiTagMask) == ::i::kSmiTag)
+ ((static_cast<i::Tagged_t>(value) & ::i::kSmiTagMask) == ::i::kSmiTag)
-#define HAS_STRONG_HEAP_OBJECT_TAG(value) \
- (((static_cast<intptr_t>(value) & ::i::kHeapObjectTagMask) == \
+#define HAS_STRONG_HEAP_OBJECT_TAG(value) \
+ (((static_cast<i::Tagged_t>(value) & ::i::kHeapObjectTagMask) == \
::i::kHeapObjectTag))
-#define HAS_WEAK_HEAP_OBJECT_TAG(value) \
- (((static_cast<intptr_t>(value) & ::i::kHeapObjectTagMask) == \
+#define HAS_WEAK_HEAP_OBJECT_TAG(value) \
+ (((static_cast<i::Tagged_t>(value) & ::i::kHeapObjectTagMask) == \
::i::kWeakHeapObjectTag))
// OBJECT_POINTER_ALIGN returns the value aligned as a HeapObject pointer
@@ -1060,6 +1068,25 @@ enum class VariableMode : uint8_t {
// has been shadowed by an eval-introduced
// variable
+ // Variables for private methods or accessors whose access require
+ // brand check. Declared only in class scopes by the compiler
+ // and allocated only in class contexts:
+ kPrivateMethod, // Does not coexist with any other variable with the same
+ // name in the same scope.
+
+ kPrivateSetterOnly, // Incompatible with variables with the same name but
+ // any mode other than kPrivateGetterOnly. Transition to
+ // kPrivateGetterAndSetter if a later declaration for the
+ // same name with kPrivateGetterOnly is made.
+
+ kPrivateGetterOnly, // Incompatible with variables with the same name but
+ // any mode other than kPrivateSetterOnly. Transition to
+ // kPrivateGetterAndSetter if a later declaration for the
+ // same name with kPrivateSetterOnly is made.
+
+ kPrivateGetterAndSetter, // Does not coexist with any other variable with the
+ // same name in the same scope.
+
kLastLexicalVariableMode = kConst,
};
@@ -1071,6 +1098,14 @@ inline const char* VariableMode2String(VariableMode mode) {
return "VAR";
case VariableMode::kLet:
return "LET";
+ case VariableMode::kPrivateGetterOnly:
+ return "PRIVATE_GETTER_ONLY";
+ case VariableMode::kPrivateSetterOnly:
+ return "PRIVATE_SETTER_ONLY";
+ case VariableMode::kPrivateMethod:
+ return "PRIVATE_METHOD";
+ case VariableMode::kPrivateGetterAndSetter:
+ return "PRIVATE_GETTER_AND_SETTER";
case VariableMode::kConst:
return "CONST";
case VariableMode::kDynamic:
@@ -1104,6 +1139,21 @@ inline bool IsDeclaredVariableMode(VariableMode mode) {
return mode <= VariableMode::kVar;
}
+inline bool IsPrivateMethodOrAccessorVariableMode(VariableMode mode) {
+ return mode >= VariableMode::kPrivateMethod &&
+ mode <= VariableMode::kPrivateGetterAndSetter;
+}
+
+inline bool IsSerializableVariableMode(VariableMode mode) {
+ return IsDeclaredVariableMode(mode) ||
+ IsPrivateMethodOrAccessorVariableMode(mode);
+}
+
+inline bool IsConstVariableMode(VariableMode mode) {
+ return mode == VariableMode::kConst ||
+ IsPrivateMethodOrAccessorVariableMode(mode);
+}
+
inline bool IsLexicalVariableMode(VariableMode mode) {
STATIC_ASSERT(static_cast<uint8_t>(VariableMode::kLet) ==
0); // Implies that mode >= VariableMode::kLet.
@@ -1168,8 +1218,6 @@ enum InitializationFlag : uint8_t { kNeedsInitialization, kCreatedInitialized };
enum MaybeAssignedFlag : uint8_t { kNotAssigned, kMaybeAssigned };
-enum RequiresBrandCheckFlag : uint8_t { kNoBrandCheck, kRequiresBrandCheck };
-
enum class InterpreterPushArgsMode : unsigned {
kArrayFunction,
kWithFinalSpread,
@@ -1498,12 +1546,12 @@ enum KeyedAccessStoreMode {
enum MutableMode { MUTABLE, IMMUTABLE };
-static inline bool IsCOWHandlingStoreMode(KeyedAccessStoreMode store_mode) {
+inline bool IsCOWHandlingStoreMode(KeyedAccessStoreMode store_mode) {
return store_mode == STORE_HANDLE_COW ||
store_mode == STORE_AND_GROW_HANDLE_COW;
}
-static inline bool IsGrowStoreMode(KeyedAccessStoreMode store_mode) {
+inline bool IsGrowStoreMode(KeyedAccessStoreMode store_mode) {
return store_mode == STORE_AND_GROW_HANDLE_COW;
}
@@ -1535,6 +1583,11 @@ constexpr int kSmallOrderedHashMapMinCapacity = 4;
// has correct value range (see Issue 830 for more details).
enum StackFrameId { ID_MIN_VALUE = kMinInt, ID_MAX_VALUE = kMaxInt, NO_ID = 0 };
+enum class ExceptionStatus : bool { kException = false, kSuccess = true };
+V8_INLINE bool operator!(ExceptionStatus status) {
+ return !static_cast<bool>(status);
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/common/message-template.h b/deps/v8/src/common/message-template.h
index fedbfa5a10..e3307a525c 100644
--- a/deps/v8/src/common/message-template.h
+++ b/deps/v8/src/common/message-template.h
@@ -118,9 +118,9 @@ namespace internal {
T(NoAccess, "no access") \
T(NonCallableInInstanceOfCheck, \
"Right-hand side of 'instanceof' is not callable") \
- T(NonCoercible, "Cannot destructure 'undefined' or 'null'.") \
+ T(NonCoercible, "Cannot destructure '%' as it is %.") \
T(NonCoercibleWithProperty, \
- "Cannot destructure property `%` of 'undefined' or 'null'.") \
+ "Cannot destructure property '%' of '%' as it is %.") \
T(NonExtensibleProto, "% is not extensible") \
T(NonObjectInInstanceOfCheck, \
"Right-hand side of 'instanceof' is not an object") \
@@ -146,7 +146,8 @@ namespace internal {
T(NotSuperConstructorAnonymousClass, \
"Super constructor % of anonymous class is not a constructor") \
T(NotIntegerSharedTypedArray, "% is not an integer shared typed array.") \
- T(NotInt32SharedTypedArray, "% is not an int32 shared typed array.") \
+ T(NotInt32OrBigInt64SharedTypedArray, \
+ "% is not an int32 or BigInt64 shared typed array.") \
T(ObjectGetterExpectingFunction, \
"Object.prototype.__defineGetter__: Expecting function") \
T(ObjectGetterCallable, "Getter must be a function: %") \
@@ -412,11 +413,15 @@ namespace internal {
T(InvalidOrUnexpectedToken, "Invalid or unexpected token") \
T(InvalidPrivateFieldResolution, \
"Private field '%' must be declared in an enclosing class") \
- T(InvalidPrivateFieldRead, \
- "Read of private field % from an object which did not contain the field") \
- T(InvalidPrivateFieldWrite, \
- "Write of private field % to an object which did not contain the field") \
+ T(InvalidPrivateMemberRead, \
+ "Cannot read private member % from an object whose class did not declare " \
+ "it") \
+ T(InvalidPrivateMemberWrite, \
+ "Cannot write private member % to an object whose class did not declare " \
+ "it") \
T(InvalidPrivateMethodWrite, "Private method '%' is not writable") \
+ T(InvalidPrivateGetterAccess, "'%' was defined without a getter") \
+ T(InvalidPrivateSetterAccess, "'%' was defined without a setter") \
T(JsonParseUnexpectedEOS, "Unexpected end of JSON input") \
T(JsonParseUnexpectedToken, "Unexpected token % in JSON at position %") \
T(JsonParseUnexpectedTokenNumber, "Unexpected number in JSON at position %") \
@@ -484,6 +489,7 @@ namespace internal {
"Too many arguments in function call (only 65535 allowed)") \
T(TooManyParameters, \
"Too many parameters in function definition (only 65534 allowed)") \
+ T(TooManyProperties, "Too many properties to enumerate") \
T(TooManySpreads, \
"Literal containing too many nested spreads (up to 65534 allowed)") \
T(TooManyVariables, "Too many variables declared (only 4194303 allowed)") \
@@ -574,7 +580,10 @@ namespace internal {
"FinalizationGroup.prototype.register: target and holdings must not be " \
"same") \
T(WeakRefsWeakRefConstructorTargetMustBeObject, \
- "WeakRef: target must be an object")
+ "WeakRef: target must be an object") \
+ T(OptionalChainingNoNew, "Invalid optional chain from new expression") \
+ T(OptionalChainingNoSuper, "Invalid optional chain from super property") \
+ T(OptionalChainingNoTemplate, "Invalid tagged template on optional chain")
enum class MessageTemplate {
#define TEMPLATE(NAME, STRING) k##NAME,
diff --git a/deps/v8/src/common/ptr-compr-inl.h b/deps/v8/src/common/ptr-compr-inl.h
index 00a79bb291..a8fd7f245c 100644
--- a/deps/v8/src/common/ptr-compr-inl.h
+++ b/deps/v8/src/common/ptr-compr-inl.h
@@ -35,7 +35,12 @@ V8_INLINE Address GetIsolateRoot<Address>(Address on_heap_addr) {
template <>
V8_INLINE Address GetIsolateRoot<Isolate*>(Isolate* isolate) {
- return isolate->isolate_root();
+ Address isolate_root = isolate->isolate_root();
+#ifdef V8_COMPRESS_POINTERS
+ isolate_root = reinterpret_cast<Address>(V8_ASSUME_ALIGNED(
+ reinterpret_cast<void*>(isolate_root), kPtrComprIsolateRootAlignment));
+#endif
+ return isolate_root;
}
// Decompresses smi value.
diff --git a/deps/v8/src/compiler/access-builder.cc b/deps/v8/src/compiler/access-builder.cc
index a369de4885..7a72be8028 100644
--- a/deps/v8/src/compiler/access-builder.cc
+++ b/deps/v8/src/compiler/access-builder.cc
@@ -32,18 +32,6 @@ FieldAccess AccessBuilder::ForExternalTaggedValue() {
}
// static
-FieldAccess AccessBuilder::ForExternalUint8Value() {
- FieldAccess access = {kUntaggedBase,
- 0,
- MaybeHandle<Name>(),
- MaybeHandle<Map>(),
- TypeCache::Get()->kUint8,
- MachineType::Uint8(),
- kNoWriteBarrier};
- return access;
-}
-
-// static
FieldAccess AccessBuilder::ForMap() {
FieldAccess access = {
kTaggedBase, HeapObject::kMapOffset,
@@ -94,9 +82,19 @@ FieldAccess AccessBuilder::ForBigIntLeastSignificantDigit64() {
// static
FieldAccess AccessBuilder::ForJSObjectPropertiesOrHash() {
FieldAccess access = {
+ kTaggedBase, JSObject::kPropertiesOrHashOffset,
+ MaybeHandle<Name>(), MaybeHandle<Map>(),
+ Type::Any(), MachineType::TypeCompressedTagged(),
+ kFullWriteBarrier, LoadSensitivity::kCritical};
+ return access;
+}
+
+// static
+FieldAccess AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer() {
+ FieldAccess access = {
kTaggedBase, JSObject::kPropertiesOrHashOffset,
MaybeHandle<Name>(), MaybeHandle<Map>(),
- Type::Any(), MachineType::TypeCompressedTagged(),
+ Type::Any(), MachineType::TypeCompressedTaggedPointer(),
kPointerWriteBarrier, LoadSensitivity::kCritical};
return access;
}
@@ -172,8 +170,8 @@ FieldAccess AccessBuilder::ForJSFunctionPrototypeOrInitialMap() {
FieldAccess access = {
kTaggedBase, JSFunction::kPrototypeOrInitialMapOffset,
MaybeHandle<Name>(), MaybeHandle<Map>(),
- Type::Any(), MachineType::TypeCompressedTagged(),
- kFullWriteBarrier};
+ Type::Any(), MachineType::TypeCompressedTaggedPointer(),
+ kPointerWriteBarrier};
return access;
}
@@ -182,7 +180,7 @@ FieldAccess AccessBuilder::ForJSFunctionContext() {
FieldAccess access = {
kTaggedBase, JSFunction::kContextOffset,
MaybeHandle<Name>(), MaybeHandle<Map>(),
- Type::Internal(), MachineType::TypeCompressedTagged(),
+ Type::Internal(), MachineType::TypeCompressedTaggedPointer(),
kPointerWriteBarrier};
return access;
}
@@ -304,7 +302,7 @@ FieldAccess AccessBuilder::ForJSGeneratorObjectParametersAndRegisters() {
FieldAccess access = {
kTaggedBase, JSGeneratorObject::kParametersAndRegistersOffset,
Handle<Name>(), MaybeHandle<Map>(),
- Type::Internal(), MachineType::TypeCompressedTagged(),
+ Type::Internal(), MachineType::TypeCompressedTaggedPointer(),
kPointerWriteBarrier};
return access;
}
@@ -325,7 +323,7 @@ FieldAccess AccessBuilder::ForJSAsyncFunctionObjectPromise() {
kTaggedBase, JSAsyncFunctionObject::kPromiseOffset,
Handle<Name>(), MaybeHandle<Map>(),
Type::OtherObject(), MachineType::TypeCompressedTaggedPointer(),
- kFullWriteBarrier};
+ kPointerWriteBarrier};
return access;
}
@@ -357,29 +355,20 @@ FieldAccess AccessBuilder::ForJSArrayLength(ElementsKind elements_kind) {
Handle<Name>(),
MaybeHandle<Map>(),
type_cache->kJSArrayLengthType,
- MachineType::TypeCompressedTaggedSigned(),
+ MachineType::TypeCompressedTagged(),
kFullWriteBarrier};
if (IsDoubleElementsKind(elements_kind)) {
access.type = type_cache->kFixedDoubleArrayLengthType;
+ access.machine_type = MachineType::TypeCompressedTaggedSigned();
access.write_barrier_kind = kNoWriteBarrier;
} else if (IsFastElementsKind(elements_kind)) {
access.type = type_cache->kFixedArrayLengthType;
+ access.machine_type = MachineType::TypeCompressedTaggedSigned();
access.write_barrier_kind = kNoWriteBarrier;
}
return access;
}
-
-// static
-FieldAccess AccessBuilder::ForJSArrayBufferBackingStore() {
- FieldAccess access = {
- kTaggedBase, JSArrayBuffer::kBackingStoreOffset,
- MaybeHandle<Name>(), MaybeHandle<Map>(),
- Type::OtherInternal(), MachineType::Pointer(),
- kNoWriteBarrier};
- return access;
-}
-
// static
FieldAccess AccessBuilder::ForJSArrayBufferBitField() {
FieldAccess access = {
@@ -441,7 +430,7 @@ FieldAccess AccessBuilder::ForJSTypedArrayBasePointer() {
kTaggedBase, JSTypedArray::kBasePointerOffset,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::OtherInternal(), MachineType::TypeCompressedTagged(),
- kPointerWriteBarrier, LoadSensitivity::kCritical};
+ kFullWriteBarrier, LoadSensitivity::kCritical};
return access;
}
@@ -747,20 +736,6 @@ FieldAccess AccessBuilder::ForExternalStringResourceData() {
}
// static
-ElementAccess AccessBuilder::ForExternalOneByteStringCharacter() {
- ElementAccess access = {kUntaggedBase, 0, TypeCache::Get()->kUint8,
- MachineType::Uint8(), kNoWriteBarrier};
- return access;
-}
-
-// static
-ElementAccess AccessBuilder::ForExternalTwoByteStringCharacter() {
- ElementAccess access = {kUntaggedBase, 0, TypeCache::Get()->kUint16,
- MachineType::Uint16(), kNoWriteBarrier};
- return access;
-}
-
-// static
ElementAccess AccessBuilder::ForSeqOneByteStringCharacter() {
ElementAccess access = {kTaggedBase, SeqOneByteString::kHeaderSize,
TypeCache::Get()->kUint8, MachineType::Uint8(),
@@ -777,26 +752,6 @@ ElementAccess AccessBuilder::ForSeqTwoByteStringCharacter() {
}
// static
-FieldAccess AccessBuilder::ForJSGlobalObjectGlobalProxy() {
- FieldAccess access = {
- kTaggedBase, JSGlobalObject::kGlobalProxyOffset,
- Handle<Name>(), MaybeHandle<Map>(),
- Type::Receiver(), MachineType::TypeCompressedTaggedPointer(),
- kPointerWriteBarrier};
- return access;
-}
-
-// static
-FieldAccess AccessBuilder::ForJSGlobalObjectNativeContext() {
- FieldAccess access = {
- kTaggedBase, JSGlobalObject::kNativeContextOffset,
- Handle<Name>(), MaybeHandle<Map>(),
- Type::Internal(), MachineType::TypeCompressedTaggedPointer(),
- kPointerWriteBarrier};
- return access;
-}
-
-// static
FieldAccess AccessBuilder::ForJSGlobalProxyNativeContext() {
FieldAccess access = {
kTaggedBase, JSGlobalProxy::kNativeContextOffset,
@@ -865,17 +820,6 @@ FieldAccess AccessBuilder::ForJSStringIteratorIndex() {
}
// static
-FieldAccess AccessBuilder::ForValue() {
- FieldAccess access = {
- kTaggedBase, JSPrimitiveWrapper::kValueOffset,
- Handle<Name>(), MaybeHandle<Map>(),
- Type::NonInternal(), MachineType::TypeCompressedTagged(),
- kFullWriteBarrier};
- return access;
-}
-
-
-// static
FieldAccess AccessBuilder::ForArgumentsLength() {
FieldAccess access = {
kTaggedBase, JSArgumentsObjectWithLength::kLengthOffset,
@@ -892,7 +836,7 @@ FieldAccess AccessBuilder::ForArgumentsCallee() {
kTaggedBase, JSSloppyArgumentsObject::kCalleeOffset,
Handle<Name>(), MaybeHandle<Map>(),
Type::NonInternal(), MachineType::TypeCompressedTagged(),
- kPointerWriteBarrier};
+ kFullWriteBarrier};
return access;
}
@@ -931,6 +875,19 @@ FieldAccess AccessBuilder::ForContextSlot(size_t index) {
}
// static
+FieldAccess AccessBuilder::ForContextSlotKnownPointer(size_t index) {
+ int offset = Context::OffsetOfElementAt(static_cast<int>(index));
+ DCHECK_EQ(offset,
+ Context::SlotOffset(static_cast<int>(index)) + kHeapObjectTag);
+ FieldAccess access = {
+ kTaggedBase, offset,
+ Handle<Name>(), MaybeHandle<Map>(),
+ Type::Any(), MachineType::TypeCompressedTaggedPointer(),
+ kPointerWriteBarrier};
+ return access;
+}
+
+// static
ElementAccess AccessBuilder::ForFixedArrayElement() {
ElementAccess access = {kTaggedBase, FixedArray::kHeaderSize, Type::Any(),
MachineType::TypeCompressedTagged(),
@@ -1189,19 +1146,6 @@ ElementAccess AccessBuilder::ForOrderedHashMapEntryValue() {
}
// static
-FieldAccess AccessBuilder::ForDictionaryMaxNumberKey() {
- FieldAccess access = {
- kTaggedBase,
- FixedArray::OffsetOfElementAt(NumberDictionary::kMaxNumberKeyIndex),
- MaybeHandle<Name>(),
- MaybeHandle<Map>(),
- Type::Any(),
- MachineType::TypeCompressedTagged(),
- kNoWriteBarrier};
- return access;
-}
-
-// static
FieldAccess AccessBuilder::ForDictionaryNextEnumerationIndex() {
FieldAccess access = {
kTaggedBase,
diff --git a/deps/v8/src/compiler/access-builder.h b/deps/v8/src/compiler/access-builder.h
index e3a17fe257..231e75f819 100644
--- a/deps/v8/src/compiler/access-builder.h
+++ b/deps/v8/src/compiler/access-builder.h
@@ -54,6 +54,9 @@ class V8_EXPORT_PRIVATE AccessBuilder final
// Provides access to JSObject::properties() field.
static FieldAccess ForJSObjectPropertiesOrHash();
+ // Provides access to JSObject::properties() field for known pointers.
+ static FieldAccess ForJSObjectPropertiesOrHashKnownPointer();
+
// Provides access to JSObject::elements() field.
static FieldAccess ForJSObjectElements();
@@ -128,9 +131,6 @@ class V8_EXPORT_PRIVATE AccessBuilder final
// Provides access to JSArray::length() field.
static FieldAccess ForJSArrayLength(ElementsKind elements_kind);
- // Provides access to JSArrayBuffer::backing_store() field.
- static FieldAccess ForJSArrayBufferBackingStore();
-
// Provides access to JSArrayBuffer::bit_field() field.
static FieldAccess ForJSArrayBufferBitField();
@@ -236,24 +236,12 @@ class V8_EXPORT_PRIVATE AccessBuilder final
// Provides access to ExternalString::resource_data() field.
static FieldAccess ForExternalStringResourceData();
- // Provides access to ExternalOneByteString characters.
- static ElementAccess ForExternalOneByteStringCharacter();
-
- // Provides access to ExternalTwoByteString characters.
- static ElementAccess ForExternalTwoByteStringCharacter();
-
// Provides access to SeqOneByteString characters.
static ElementAccess ForSeqOneByteStringCharacter();
// Provides access to SeqTwoByteString characters.
static ElementAccess ForSeqTwoByteStringCharacter();
- // Provides access to JSGlobalObject::global_proxy() field.
- static FieldAccess ForJSGlobalObjectGlobalProxy();
-
- // Provides access to JSGlobalObject::native_context() field.
- static FieldAccess ForJSGlobalObjectNativeContext();
-
// Provides access to JSGlobalProxy::native_context() field.
static FieldAccess ForJSGlobalProxyNativeContext();
@@ -272,9 +260,6 @@ class V8_EXPORT_PRIVATE AccessBuilder final
// Provides access to JSStringIterator::index() field.
static FieldAccess ForJSStringIteratorIndex();
- // Provides access to JSPrimitiveWrapper::value() field.
- static FieldAccess ForValue();
-
// Provides access to Cell::value() field.
static FieldAccess ForCellValue();
@@ -289,6 +274,9 @@ class V8_EXPORT_PRIVATE AccessBuilder final
// Provides access to Context slots.
static FieldAccess ForContextSlot(size_t index);
+ // Provides access to Context slots that are known to be pointers.
+ static FieldAccess ForContextSlotKnownPointer(size_t index);
+
// Provides access to FixedArray elements.
static ElementAccess ForFixedArrayElement();
static ElementAccess ForFixedArrayElement(
@@ -327,7 +315,6 @@ class V8_EXPORT_PRIVATE AccessBuilder final
static ElementAccess ForOrderedHashMapEntryValue();
// Provides access to Dictionary fields.
- static FieldAccess ForDictionaryMaxNumberKey();
static FieldAccess ForDictionaryNextEnumerationIndex();
static FieldAccess ForDictionaryObjectHashIndex();
diff --git a/deps/v8/src/compiler/access-info.cc b/deps/v8/src/compiler/access-info.cc
index 6fc9e8214e..269ef90375 100644
--- a/deps/v8/src/compiler/access-info.cc
+++ b/deps/v8/src/compiler/access-info.cc
@@ -9,6 +9,7 @@
#include "src/builtins/accessors.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/compilation-dependency.h"
+#include "src/compiler/simplified-operator.h"
#include "src/compiler/type-cache.h"
#include "src/ic/call-optimization.h"
#include "src/logging/counters.h"
@@ -81,11 +82,12 @@ PropertyAccessInfo PropertyAccessInfo::DataField(
Zone* zone, Handle<Map> receiver_map,
ZoneVector<CompilationDependency const*>&& dependencies,
FieldIndex field_index, Representation field_representation,
- Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
- MaybeHandle<Map> transition_map) {
+ Type field_type, Handle<Map> field_owner_map, MaybeHandle<Map> field_map,
+ MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map) {
return PropertyAccessInfo(kDataField, holder, transition_map, field_index,
- field_representation, field_type, field_map,
- {{receiver_map}, zone}, std::move(dependencies));
+ field_representation, field_type, field_owner_map,
+ field_map, {{receiver_map}, zone},
+ std::move(dependencies));
}
// static
@@ -93,11 +95,12 @@ PropertyAccessInfo PropertyAccessInfo::DataConstant(
Zone* zone, Handle<Map> receiver_map,
ZoneVector<CompilationDependency const*>&& dependencies,
FieldIndex field_index, Representation field_representation,
- Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
- MaybeHandle<Map> transition_map) {
+ Type field_type, Handle<Map> field_owner_map, MaybeHandle<Map> field_map,
+ MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map) {
return PropertyAccessInfo(kDataConstant, holder, transition_map, field_index,
- field_representation, field_type, field_map,
- {{receiver_map}, zone}, std::move(dependencies));
+ field_representation, field_type, field_owner_map,
+ field_map, {{receiver_map}, zone},
+ std::move(dependencies));
}
// static
@@ -155,7 +158,7 @@ PropertyAccessInfo::PropertyAccessInfo(Zone* zone, Kind kind,
PropertyAccessInfo::PropertyAccessInfo(
Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
FieldIndex field_index, Representation field_representation,
- Type field_type, MaybeHandle<Map> field_map,
+ Type field_type, Handle<Map> field_owner_map, MaybeHandle<Map> field_map,
ZoneVector<Handle<Map>>&& receiver_maps,
ZoneVector<CompilationDependency const*>&& unrecorded_dependencies)
: kind_(kind),
@@ -166,7 +169,11 @@ PropertyAccessInfo::PropertyAccessInfo(
field_index_(field_index),
field_representation_(field_representation),
field_type_(field_type),
- field_map_(field_map) {}
+ field_owner_map_(field_owner_map),
+ field_map_(field_map) {
+ DCHECK_IMPLIES(!transition_map.is_null(),
+ field_owner_map.address() == transition_map.address());
+}
bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
AccessMode access_mode, Zone* zone) {
@@ -258,6 +265,13 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
}
}
+ConstFieldInfo PropertyAccessInfo::GetConstFieldInfo() const {
+ if (IsDataConstant()) {
+ return ConstFieldInfo(field_owner_map_.ToHandleChecked());
+ }
+ return ConstFieldInfo::None();
+}
+
AccessInfoFactory::AccessInfoFactory(JSHeapBroker* broker,
CompilationDependencies* dependencies,
Zone* zone)
@@ -276,35 +290,32 @@ base::Optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo(
}
bool AccessInfoFactory::ComputeElementAccessInfos(
- ElementAccessFeedback const& processed, AccessMode access_mode,
+ ElementAccessFeedback const& feedback,
ZoneVector<ElementAccessInfo>* access_infos) const {
+ AccessMode access_mode = feedback.keyed_mode().access_mode();
if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
// For polymorphic loads of similar elements kinds (i.e. all tagged or all
// double), always use the "worst case" code without a transition. This is
// much faster than transitioning the elements to the worst case, trading a
// TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
base::Optional<ElementAccessInfo> access_info =
- ConsolidateElementLoad(processed);
+ ConsolidateElementLoad(feedback);
if (access_info.has_value()) {
access_infos->push_back(*access_info);
return true;
}
}
- for (Handle<Map> receiver_map : processed.receiver_maps) {
- // Compute the element access information.
+ for (auto const& group : feedback.transition_groups()) {
+ DCHECK(!group.empty());
+ Handle<Map> target = group.front();
base::Optional<ElementAccessInfo> access_info =
- ComputeElementAccessInfo(receiver_map, access_mode);
+ ComputeElementAccessInfo(target, access_mode);
if (!access_info.has_value()) return false;
- // Collect the possible transitions for the {receiver_map}.
- for (auto transition : processed.transitions) {
- if (transition.second.equals(receiver_map)) {
- access_info->AddTransitionSource(transition.first);
- }
+ for (size_t i = 1; i < group.size(); ++i) {
+ access_info->AddTransitionSource(group[i]);
}
-
- // Schedule the access information.
access_infos->push_back(*access_info);
}
return true;
@@ -378,15 +389,19 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
map_ref.SerializeOwnDescriptor(descriptor);
constness = dependencies()->DependOnFieldConstness(map_ref, descriptor);
}
+ Handle<Map> field_owner_map(map->FindFieldOwner(isolate(), descriptor),
+ isolate());
switch (constness) {
case PropertyConstness::kMutable:
return PropertyAccessInfo::DataField(
zone(), receiver_map, std::move(unrecorded_dependencies), field_index,
- details_representation, field_type, field_map, holder);
+ details_representation, field_type, field_owner_map, field_map,
+ holder);
case PropertyConstness::kConst:
return PropertyAccessInfo::DataConstant(
zone(), receiver_map, std::move(unrecorded_dependencies), field_index,
- details_representation, field_type, field_map, holder);
+ details_representation, field_type, field_owner_map, field_map,
+ holder);
}
UNREACHABLE();
}
@@ -431,7 +446,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeAccessorDescriptorAccessInfo(
CallOptimization optimization(isolate(), accessor);
if (!optimization.is_simple_api_call() ||
optimization.IsCrossContextLazyAccessorPair(
- *broker()->native_context().object(), *map)) {
+ *broker()->target_native_context().object(), *map)) {
return PropertyAccessInfo::Invalid(zone());
}
@@ -537,11 +552,13 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
}
// Walk up the prototype chain.
+ MapRef(broker(), map).SerializePrototype();
if (!map->prototype().IsJSObject()) {
// Perform the implicit ToObject for primitives here.
// Implemented according to ES6 section 7.3.2 GetV (V, P).
Handle<JSFunction> constructor;
- if (Map::GetConstructorFunction(map, broker()->native_context().object())
+ if (Map::GetConstructorFunction(
+ map, broker()->target_native_context().object())
.ToHandle(&constructor)) {
map = handle(constructor->initial_map(), isolate());
DCHECK(map->prototype().IsJSObject());
@@ -615,6 +632,7 @@ void PropertyAccessInfo::RecordDependencies(
bool AccessInfoFactory::FinalizePropertyAccessInfos(
ZoneVector<PropertyAccessInfo> access_infos, AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* result) const {
+ if (access_infos.empty()) return false;
MergePropertyAccessInfos(access_infos, access_mode, result);
for (PropertyAccessInfo const& info : *result) {
if (info.IsInvalid()) return false;
@@ -668,22 +686,28 @@ Maybe<ElementsKind> GeneralizeElementsKind(ElementsKind this_kind,
} // namespace
base::Optional<ElementAccessInfo> AccessInfoFactory::ConsolidateElementLoad(
- ElementAccessFeedback const& processed) const {
- ElementAccessFeedback::MapIterator it = processed.all_maps(broker());
- MapRef first_map = it.current();
+ ElementAccessFeedback const& feedback) const {
+ if (feedback.transition_groups().empty()) return base::nullopt;
+
+ DCHECK(!feedback.transition_groups().front().empty());
+ MapRef first_map(broker(), feedback.transition_groups().front().front());
InstanceType instance_type = first_map.instance_type();
ElementsKind elements_kind = first_map.elements_kind();
+
ZoneVector<Handle<Map>> maps(zone());
- for (; !it.done(); it.advance()) {
- MapRef map = it.current();
- if (map.instance_type() != instance_type || !CanInlineElementAccess(map)) {
- return base::nullopt;
- }
- if (!GeneralizeElementsKind(elements_kind, map.elements_kind())
- .To(&elements_kind)) {
- return base::nullopt;
+ for (auto const& group : feedback.transition_groups()) {
+ for (Handle<Map> map_handle : group) {
+ MapRef map(broker(), map_handle);
+ if (map.instance_type() != instance_type ||
+ !CanInlineElementAccess(map)) {
+ return base::nullopt;
+ }
+ if (!GeneralizeElementsKind(elements_kind, map.elements_kind())
+ .To(&elements_kind)) {
+ return base::nullopt;
+ }
+ maps.push_back(map.object());
}
- maps.push_back(map.object());
}
return ElementAccessInfo(std::move(maps), elements_kind, zone());
@@ -723,7 +747,7 @@ PropertyAccessInfo AccessInfoFactory::LookupSpecialFieldAccessor(
}
// Special fields are always mutable.
return PropertyAccessInfo::DataField(zone(), map, {{}, zone()}, field_index,
- field_representation, field_type);
+ field_representation, field_type, map);
}
return PropertyAccessInfo::Invalid(zone());
}
@@ -799,12 +823,12 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition(
case PropertyConstness::kMutable:
return PropertyAccessInfo::DataField(
zone(), map, std::move(unrecorded_dependencies), field_index,
- details_representation, field_type, field_map, holder,
+ details_representation, field_type, transition_map, field_map, holder,
transition_map);
case PropertyConstness::kConst:
return PropertyAccessInfo::DataConstant(
zone(), map, std::move(unrecorded_dependencies), field_index,
- details_representation, field_type, field_map, holder,
+ details_representation, field_type, transition_map, field_map, holder,
transition_map);
}
UNREACHABLE();
diff --git a/deps/v8/src/compiler/access-info.h b/deps/v8/src/compiler/access-info.h
index 4c7c3611df..e2f6e6d453 100644
--- a/deps/v8/src/compiler/access-info.h
+++ b/deps/v8/src/compiler/access-info.h
@@ -29,6 +29,7 @@ class CompilationDependency;
class ElementAccessFeedback;
class JSHeapBroker;
class TypeCache;
+struct ConstFieldInfo;
std::ostream& operator<<(std::ostream&, AccessMode);
@@ -77,14 +78,16 @@ class PropertyAccessInfo final {
Zone* zone, Handle<Map> receiver_map,
ZoneVector<CompilationDependency const*>&& unrecorded_dependencies,
FieldIndex field_index, Representation field_representation,
- Type field_type, MaybeHandle<Map> field_map = MaybeHandle<Map>(),
+ Type field_type, Handle<Map> field_owner_map,
+ MaybeHandle<Map> field_map = MaybeHandle<Map>(),
MaybeHandle<JSObject> holder = MaybeHandle<JSObject>(),
MaybeHandle<Map> transition_map = MaybeHandle<Map>());
static PropertyAccessInfo DataConstant(
Zone* zone, Handle<Map> receiver_map,
ZoneVector<CompilationDependency const*>&& unrecorded_dependencies,
FieldIndex field_index, Representation field_representation,
- Type field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
+ Type field_type, Handle<Map> field_owner_map, MaybeHandle<Map> field_map,
+ MaybeHandle<JSObject> holder,
MaybeHandle<Map> transition_map = MaybeHandle<Map>());
static PropertyAccessInfo AccessorConstant(Zone* zone,
Handle<Map> receiver_map,
@@ -109,6 +112,7 @@ class PropertyAccessInfo final {
bool IsStringLength() const { return kind() == kStringLength; }
bool HasTransitionMap() const { return !transition_map().is_null(); }
+ ConstFieldInfo GetConstFieldInfo() const;
Kind kind() const { return kind_; }
MaybeHandle<JSObject> holder() const {
@@ -137,7 +141,7 @@ class PropertyAccessInfo final {
PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
MaybeHandle<Map> transition_map, FieldIndex field_index,
Representation field_representation, Type field_type,
- MaybeHandle<Map> field_map,
+ Handle<Map> field_owner_map, MaybeHandle<Map> field_map,
ZoneVector<Handle<Map>>&& receiver_maps,
ZoneVector<CompilationDependency const*>&& dependencies);
@@ -150,6 +154,7 @@ class PropertyAccessInfo final {
FieldIndex field_index_;
Representation field_representation_;
Type field_type_;
+ MaybeHandle<Map> field_owner_map_;
MaybeHandle<Map> field_map_;
};
@@ -163,7 +168,7 @@ class AccessInfoFactory final {
base::Optional<ElementAccessInfo> ComputeElementAccessInfo(
Handle<Map> map, AccessMode access_mode) const;
bool ComputeElementAccessInfos(
- ElementAccessFeedback const& processed, AccessMode access_mode,
+ ElementAccessFeedback const& feedback,
ZoneVector<ElementAccessInfo>* access_infos) const;
PropertyAccessInfo ComputePropertyAccessInfo(Handle<Map> map,
@@ -191,7 +196,7 @@ class AccessInfoFactory final {
private:
base::Optional<ElementAccessInfo> ConsolidateElementLoad(
- ElementAccessFeedback const& processed) const;
+ ElementAccessFeedback const& feedback) const;
PropertyAccessInfo LookupSpecialFieldAccessor(Handle<Map> map,
Handle<Name> name) const;
PropertyAccessInfo LookupTransition(Handle<Map> map, Handle<Name> name,
diff --git a/deps/v8/src/compiler/allocation-builder-inl.h b/deps/v8/src/compiler/allocation-builder-inl.h
index 8da7c685a1..4cab0a7e6e 100644
--- a/deps/v8/src/compiler/allocation-builder-inl.h
+++ b/deps/v8/src/compiler/allocation-builder-inl.h
@@ -14,11 +14,9 @@ namespace v8 {
namespace internal {
namespace compiler {
-void AllocationBuilder::AllocateContext(int variadic_part_length,
- Handle<Map> map) {
- DCHECK(
- IsInRange(map->instance_type(), FIRST_CONTEXT_TYPE, LAST_CONTEXT_TYPE));
- DCHECK_NE(NATIVE_CONTEXT_TYPE, map->instance_type());
+void AllocationBuilder::AllocateContext(int variadic_part_length, MapRef map) {
+ DCHECK(IsInRange(map.instance_type(), FIRST_CONTEXT_TYPE, LAST_CONTEXT_TYPE));
+ DCHECK_NE(NATIVE_CONTEXT_TYPE, map.instance_type());
int size = Context::SizeFor(variadic_part_length);
Allocate(size, AllocationType::kYoung, Type::OtherInternal());
Store(AccessBuilder::ForMap(), map);
@@ -29,11 +27,11 @@ void AllocationBuilder::AllocateContext(int variadic_part_length,
}
// Compound allocation of a FixedArray.
-void AllocationBuilder::AllocateArray(int length, Handle<Map> map,
+void AllocationBuilder::AllocateArray(int length, MapRef map,
AllocationType allocation) {
- DCHECK(map->instance_type() == FIXED_ARRAY_TYPE ||
- map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE);
- int size = (map->instance_type() == FIXED_ARRAY_TYPE)
+ DCHECK(map.instance_type() == FIXED_ARRAY_TYPE ||
+ map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE);
+ int size = (map.instance_type() == FIXED_ARRAY_TYPE)
? FixedArray::SizeFor(length)
: FixedDoubleArray::SizeFor(length);
Allocate(size, allocation, Type::OtherInternal());
diff --git a/deps/v8/src/compiler/allocation-builder.h b/deps/v8/src/compiler/allocation-builder.h
index d92e0f769b..040dd01405 100644
--- a/deps/v8/src/compiler/allocation-builder.h
+++ b/deps/v8/src/compiler/allocation-builder.h
@@ -49,17 +49,13 @@ class AllocationBuilder final {
}
// Compound allocation of a context.
- inline void AllocateContext(int variadic_part_length, Handle<Map> map);
+ inline void AllocateContext(int variadic_part_length, MapRef map);
// Compound allocation of a FixedArray.
- inline void AllocateArray(int length, Handle<Map> map,
+ inline void AllocateArray(int length, MapRef map,
AllocationType allocation = AllocationType::kYoung);
// Compound store of a constant into a field.
- void Store(const FieldAccess& access, Handle<Object> value) {
- Store(access, jsgraph()->Constant(value));
- }
- // Compound store of a constant into a field.
void Store(const FieldAccess& access, const ObjectRef& value) {
Store(access, jsgraph()->Constant(value));
}
diff --git a/deps/v8/src/compiler/backend/arm/code-generator-arm.cc b/deps/v8/src/compiler/backend/arm/code-generator-arm.cc
index 88a9c52a33..65a569d755 100644
--- a/deps/v8/src/compiler/backend/arm/code-generator-arm.cc
+++ b/deps/v8/src/compiler/backend/arm/code-generator-arm.cc
@@ -909,10 +909,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArchDeoptimize: {
- int deopt_state_id =
+ DeoptimizationExit* exit =
BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
- CodeGenResult result =
- AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
+ CodeGenResult result = AssembleDeoptimizerCall(exit);
if (result != kSuccess) return result;
unwinding_info_writer_.MarkBlockWillExit();
break;
@@ -921,10 +920,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
AssembleReturn(instr->InputAt(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
- case kArchStackPointer:
- __ mov(i.OutputRegister(), sp);
- DCHECK_EQ(LeaveCC, i.OutputSBit());
- break;
case kArchFramePointer:
__ mov(i.OutputRegister(), fp);
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -936,6 +931,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ mov(i.OutputRegister(), fp);
}
break;
+ case kArchStackPointerGreaterThan: {
+ constexpr size_t kValueIndex = 0;
+ DCHECK(instr->InputAt(kValueIndex)->IsRegister());
+ __ cmp(sp, i.InputRegister(kValueIndex));
+ break;
+ }
case kArchTruncateDoubleToI:
__ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
i.InputDoubleRegister(0), DetermineStubCallMode());
@@ -1838,6 +1839,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputSimd128Register(1));
break;
}
+ case kArmF32x4Div: {
+ QwNeonRegister dst = i.OutputSimd128Register();
+ QwNeonRegister src1 = i.InputSimd128Register(0);
+ QwNeonRegister src2 = i.InputSimd128Register(1);
+ DCHECK_EQ(dst, q0);
+ DCHECK_EQ(src1, q0);
+ DCHECK_EQ(src2, q1);
+#define S_FROM_Q(reg, lane) SwVfpRegister::from_code(reg.code() * 4 + lane)
+ __ vdiv(S_FROM_Q(dst, 0), S_FROM_Q(src1, 0), S_FROM_Q(src2, 0));
+ __ vdiv(S_FROM_Q(dst, 1), S_FROM_Q(src1, 1), S_FROM_Q(src2, 1));
+ __ vdiv(S_FROM_Q(dst, 2), S_FROM_Q(src1, 2), S_FROM_Q(src2, 2));
+ __ vdiv(S_FROM_Q(dst, 3), S_FROM_Q(src1, 3), S_FROM_Q(src2, 3));
+#undef S_FROM_Q
+ break;
+ }
case kArmF32x4Min: {
__ vmin(i.OutputSimd128Register(), i.InputSimd128Register(0),
i.InputSimd128Register(1));
@@ -1902,13 +1918,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kArmI32x4Shl: {
+ QwNeonRegister tmp = i.TempSimd128Register(0);
+ __ vdup(Neon32, tmp, i.InputRegister(1));
__ vshl(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt5(1));
+ tmp);
break;
}
case kArmI32x4ShrS: {
- __ vshr(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt5(1));
+ QwNeonRegister tmp = i.TempSimd128Register(0);
+ __ vdup(Neon32, tmp, i.InputRegister(1));
+ __ vneg(Neon32, tmp, tmp);
+ __ vshl(NeonS32, i.OutputSimd128Register(), i.InputSimd128Register(0),
+ tmp);
break;
}
case kArmI32x4Add: {
@@ -1976,8 +1997,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kArmI32x4ShrU: {
- __ vshr(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt5(1));
+ QwNeonRegister tmp = i.TempSimd128Register(0);
+ __ vdup(Neon32, tmp, i.InputRegister(1));
+ __ vneg(Neon32, tmp, tmp);
+ __ vshl(NeonU32, i.OutputSimd128Register(), i.InputSimd128Register(0),
+ tmp);
break;
}
case kArmI32x4MinU: {
@@ -2029,13 +2053,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kArmI16x8Shl: {
+ QwNeonRegister tmp = i.TempSimd128Register(0);
+ __ vdup(Neon16, tmp, i.InputRegister(1));
__ vshl(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt4(1));
+ tmp);
break;
}
case kArmI16x8ShrS: {
- __ vshr(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt4(1));
+ QwNeonRegister tmp = i.TempSimd128Register(0);
+ __ vdup(Neon16, tmp, i.InputRegister(1));
+ __ vneg(Neon16, tmp, tmp);
+ __ vshl(NeonS16, i.OutputSimd128Register(), i.InputSimd128Register(0),
+ tmp);
break;
}
case kArmI16x8SConvertI32x4:
@@ -2112,8 +2141,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kArmI16x8ShrU: {
- __ vshr(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt4(1));
+ QwNeonRegister tmp = i.TempSimd128Register(0);
+ __ vdup(Neon16, tmp, i.InputRegister(1));
+ __ vneg(Neon16, tmp, tmp);
+ __ vshl(NeonU16, i.OutputSimd128Register(), i.InputSimd128Register(0),
+ tmp);
break;
}
case kArmI16x8UConvertI32x4:
@@ -2168,13 +2200,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kArmI8x16Shl: {
+ QwNeonRegister tmp = i.TempSimd128Register(0);
+ __ vdup(Neon8, tmp, i.InputRegister(1));
__ vshl(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt3(1));
+ tmp);
break;
}
case kArmI8x16ShrS: {
- __ vshr(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt3(1));
+ QwNeonRegister tmp = i.TempSimd128Register(0);
+ __ vdup(Neon8, tmp, i.InputRegister(1));
+ __ vneg(Neon8, tmp, tmp);
+ __ vshl(NeonS8, i.OutputSimd128Register(), i.InputSimd128Register(0),
+ tmp);
break;
}
case kArmI8x16SConvertI16x8:
@@ -2237,8 +2274,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kArmI8x16ShrU: {
- __ vshr(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt3(1));
+ QwNeonRegister tmp = i.TempSimd128Register(0);
+ __ vdup(Neon8, tmp, i.InputRegister(1));
+ __ vneg(Neon8, tmp, tmp);
+ __ vshl(NeonU8, i.OutputSimd128Register(), i.InputSimd128Register(0),
+ tmp);
break;
}
case kArmI8x16UConvertI16x8:
@@ -3192,6 +3232,8 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::FinishCode() { __ CheckConstPool(true, false); }
+void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {}
+
void CodeGenerator::AssembleMove(InstructionOperand* source,
InstructionOperand* destination) {
ArmOperandConverter g(this, nullptr);
diff --git a/deps/v8/src/compiler/backend/arm/instruction-codes-arm.h b/deps/v8/src/compiler/backend/arm/instruction-codes-arm.h
index 165ca39f9d..3551e26aea 100644
--- a/deps/v8/src/compiler/backend/arm/instruction-codes-arm.h
+++ b/deps/v8/src/compiler/backend/arm/instruction-codes-arm.h
@@ -141,6 +141,7 @@ namespace compiler {
V(ArmF32x4AddHoriz) \
V(ArmF32x4Sub) \
V(ArmF32x4Mul) \
+ V(ArmF32x4Div) \
V(ArmF32x4Min) \
V(ArmF32x4Max) \
V(ArmF32x4Eq) \
diff --git a/deps/v8/src/compiler/backend/arm/instruction-scheduler-arm.cc b/deps/v8/src/compiler/backend/arm/instruction-scheduler-arm.cc
index 41d7b4055f..1d7cf61dfe 100644
--- a/deps/v8/src/compiler/backend/arm/instruction-scheduler-arm.cc
+++ b/deps/v8/src/compiler/backend/arm/instruction-scheduler-arm.cc
@@ -121,6 +121,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArmF32x4AddHoriz:
case kArmF32x4Sub:
case kArmF32x4Mul:
+ case kArmF32x4Div:
case kArmF32x4Min:
case kArmF32x4Max:
case kArmF32x4Eq:
diff --git a/deps/v8/src/compiler/backend/arm/instruction-selector-arm.cc b/deps/v8/src/compiler/backend/arm/instruction-selector-arm.cc
index 06aba4491a..ce74faa4a6 100644
--- a/deps/v8/src/compiler/backend/arm/instruction-selector-arm.cc
+++ b/deps/v8/src/compiler/backend/arm/instruction-selector-arm.cc
@@ -74,17 +74,6 @@ class ArmOperandGenerator : public OperandGenerator {
}
return false;
}
-
- // Use the stack pointer if the node is LoadStackPointer, otherwise assign a
- // register.
- InstructionOperand UseRegisterOrStackPointer(Node* node) {
- if (node->opcode() == IrOpcode::kLoadStackPointer) {
- return LocationOperand(LocationOperand::EXPLICIT,
- LocationOperand::REGISTER,
- MachineRepresentation::kWord32, sp.code());
- }
- return UseRegister(node);
- }
};
namespace {
@@ -102,6 +91,15 @@ void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
g.UseRegister(node->InputAt(1)));
}
+void VisitSimdShiftRRR(InstructionSelector* selector, ArchOpcode opcode,
+ Node* node) {
+ ArmOperandGenerator g(selector);
+ InstructionOperand temps[] = {g.TempSimd128Register()};
+ selector->Emit(opcode, g.DefineAsRegister(node),
+ g.UseRegister(node->InputAt(0)),
+ g.UseRegister(node->InputAt(1)), arraysize(temps), temps);
+}
+
void VisitRRRShuffle(InstructionSelector* selector, ArchOpcode opcode,
Node* node) {
ArmOperandGenerator g(selector);
@@ -509,7 +507,8 @@ void InstructionSelector::VisitStore(Node* node) {
WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
MachineRepresentation rep = store_rep.representation();
- if (write_barrier_kind != kNoWriteBarrier) {
+ if (write_barrier_kind != kNoWriteBarrier &&
+ V8_LIKELY(!FLAG_disable_write_barriers)) {
DCHECK(CanBeTaggedPointer(rep));
AddressingMode addressing_mode;
InstructionOperand inputs[3];
@@ -887,6 +886,15 @@ void InstructionSelector::VisitWord32Xor(Node* node) {
VisitBinop(this, node, kArmEor, kArmEor);
}
+void InstructionSelector::VisitStackPointerGreaterThan(
+ Node* node, FlagsContinuation* cont) {
+ Node* const value = node->InputAt(0);
+ InstructionCode opcode = kArchStackPointerGreaterThan;
+
+ ArmOperandGenerator g(this);
+ EmitWithContinuation(opcode, g.UseRegister(value), cont);
+}
+
namespace {
template <typename TryMatchShift>
@@ -1686,17 +1694,17 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
&input_count, &inputs[1])) {
- inputs[0] = g.UseRegisterOrStackPointer(m.left().node());
+ inputs[0] = g.UseRegister(m.left().node());
input_count++;
} else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
&input_count, &inputs[1])) {
if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
- inputs[0] = g.UseRegisterOrStackPointer(m.right().node());
+ inputs[0] = g.UseRegister(m.right().node());
input_count++;
} else {
opcode |= AddressingModeField::encode(kMode_Operand2_R);
- inputs[input_count++] = g.UseRegisterOrStackPointer(m.left().node());
- inputs[input_count++] = g.UseRegisterOrStackPointer(m.right().node());
+ inputs[input_count++] = g.UseRegister(m.left().node());
+ inputs[input_count++] = g.UseRegister(m.right().node());
}
if (has_result) {
@@ -1848,6 +1856,9 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
return VisitShift(this, value, TryMatchLSR, cont);
case IrOpcode::kWord32Ror:
return VisitShift(this, value, TryMatchROR, cont);
+ case IrOpcode::kStackPointerGreaterThan:
+ cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
+ return VisitStackPointerGreaterThan(value, cont);
default:
break;
}
@@ -2488,7 +2499,7 @@ SIMD_UNOP_LIST(SIMD_VISIT_UNOP)
#define SIMD_VISIT_SHIFT_OP(Name) \
void InstructionSelector::Visit##Name(Node* node) { \
- VisitRRI(this, kArm##Name, node); \
+ VisitSimdShiftRRR(this, kArm##Name, node); \
}
SIMD_SHIFT_OP_LIST(SIMD_VISIT_SHIFT_OP)
#undef SIMD_VISIT_SHIFT_OP
@@ -2502,6 +2513,14 @@ SIMD_BINOP_LIST(SIMD_VISIT_BINOP)
#undef SIMD_VISIT_BINOP
#undef SIMD_BINOP_LIST
+void InstructionSelector::VisitF32x4Div(Node* node) {
+ ArmOperandGenerator g(this);
+ // Use fixed registers in the lower 8 Q-registers so we can directly access
+ // mapped registers S0-S31.
+ Emit(kArmF32x4Div, g.DefineAsFixed(node, q0),
+ g.UseFixed(node->InputAt(0), q0), g.UseFixed(node->InputAt(1), q1));
+}
+
void InstructionSelector::VisitS128Select(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmS128Select, g.DefineSameAsFirst(node),
diff --git a/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc b/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc
index c71a63cc3d..66ca7f6cf0 100644
--- a/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc
+++ b/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc
@@ -820,20 +820,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// don't emit code for nops.
break;
case kArchDeoptimize: {
- int deopt_state_id =
+ DeoptimizationExit* exit =
BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
- CodeGenResult result =
- AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
- if (result != kSuccess) return result;
- unwinding_info_writer_.MarkBlockWillExit();
+ __ B(exit->label());
break;
}
case kArchRet:
AssembleReturn(instr->InputAt(0));
break;
- case kArchStackPointer:
- __ mov(i.OutputRegister(), sp);
- break;
case kArchFramePointer:
__ mov(i.OutputRegister(), fp);
break;
@@ -844,6 +838,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ mov(i.OutputRegister(), fp);
}
break;
+ case kArchStackPointerGreaterThan: {
+ constexpr size_t kValueIndex = 0;
+ DCHECK(instr->InputAt(kValueIndex)->IsRegister());
+ __ Cmp(sp, i.InputRegister(kValueIndex));
+ break;
+ }
case kArchTruncateDoubleToI:
__ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
i.InputDoubleRegister(0), DetermineStubCallMode());
@@ -1598,12 +1598,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ DecompressAnyTagged(i.OutputRegister(), i.InputRegister(0));
break;
}
- case kArm64CompressSigned: // Fall through.
- case kArm64CompressPointer: // Fall through.
- case kArm64CompressAny: {
- __ Uxtw(i.OutputRegister(), i.InputRegister(0));
- break;
- }
case kArm64LdrS:
__ Ldr(i.OutputDoubleRegister().S(), i.MemoryOperand());
break;
@@ -1780,6 +1774,50 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputSimd128Register(1).V##FORMAT()); \
break;
+ case kArm64F64x2Splat: {
+ __ Dup(i.OutputSimd128Register().V2D(), i.InputSimd128Register(0).D(), 0);
+ break;
+ }
+ case kArm64F64x2ExtractLane: {
+ __ Mov(i.OutputSimd128Register().D(), i.InputSimd128Register(0).V2D(),
+ i.InputInt8(1));
+ break;
+ }
+ case kArm64F64x2ReplaceLane: {
+ VRegister dst = i.OutputSimd128Register().V2D(),
+ src1 = i.InputSimd128Register(0).V2D();
+ if (!dst.is(src1)) {
+ __ Mov(dst, src1);
+ }
+ __ Mov(dst, i.InputInt8(1), i.InputSimd128Register(2).V2D(), 0);
+ break;
+ }
+ SIMD_UNOP_CASE(kArm64F64x2Abs, Fabs, 2D);
+ SIMD_UNOP_CASE(kArm64F64x2Neg, Fneg, 2D);
+ SIMD_BINOP_CASE(kArm64F64x2Add, Fadd, 2D);
+ SIMD_BINOP_CASE(kArm64F64x2Sub, Fsub, 2D);
+ SIMD_BINOP_CASE(kArm64F64x2Mul, Fmul, 2D);
+ SIMD_BINOP_CASE(kArm64F64x2Div, Fdiv, 2D);
+ SIMD_BINOP_CASE(kArm64F64x2Min, Fmin, 2D);
+ SIMD_BINOP_CASE(kArm64F64x2Max, Fmax, 2D);
+ SIMD_BINOP_CASE(kArm64F64x2Eq, Fcmeq, 2D);
+ case kArm64F64x2Ne: {
+ VRegister dst = i.OutputSimd128Register().V2D();
+ __ Fcmeq(dst, i.InputSimd128Register(0).V2D(),
+ i.InputSimd128Register(1).V2D());
+ __ Mvn(dst, dst);
+ break;
+ }
+ case kArm64F64x2Lt: {
+ __ Fcmgt(i.OutputSimd128Register().V2D(), i.InputSimd128Register(1).V2D(),
+ i.InputSimd128Register(0).V2D());
+ break;
+ }
+ case kArm64F64x2Le: {
+ __ Fcmge(i.OutputSimd128Register().V2D(), i.InputSimd128Register(1).V2D(),
+ i.InputSimd128Register(0).V2D());
+ break;
+ }
case kArm64F32x4Splat: {
__ Dup(i.OutputSimd128Register().V4S(), i.InputSimd128Register(0).S(), 0);
break;
@@ -1808,6 +1846,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
SIMD_BINOP_CASE(kArm64F32x4AddHoriz, Faddp, 4S);
SIMD_BINOP_CASE(kArm64F32x4Sub, Fsub, 4S);
SIMD_BINOP_CASE(kArm64F32x4Mul, Fmul, 4S);
+ SIMD_BINOP_CASE(kArm64F32x4Div, Fdiv, 4S);
SIMD_BINOP_CASE(kArm64F32x4Min, Fmin, 4S);
SIMD_BINOP_CASE(kArm64F32x4Max, Fmax, 4S);
SIMD_BINOP_CASE(kArm64F32x4Eq, Fcmeq, 4S);
@@ -1828,6 +1867,62 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputSimd128Register(0).V4S());
break;
}
+ case kArm64I64x2Splat: {
+ __ Dup(i.OutputSimd128Register().V2D(), i.InputRegister64(0));
+ break;
+ }
+ case kArm64I64x2ExtractLane: {
+ __ Mov(i.OutputRegister64(), i.InputSimd128Register(0).V2D(),
+ i.InputInt8(1));
+ break;
+ }
+ case kArm64I64x2ReplaceLane: {
+ VRegister dst = i.OutputSimd128Register().V2D(),
+ src1 = i.InputSimd128Register(0).V2D();
+ if (!dst.is(src1)) {
+ __ Mov(dst, src1);
+ }
+ __ Mov(dst, i.InputInt8(1), i.InputRegister64(2));
+ break;
+ }
+ SIMD_UNOP_CASE(kArm64I64x2Neg, Neg, 2D);
+ case kArm64I64x2Shl: {
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V2D(), i.InputRegister64(1));
+ __ Sshl(i.OutputSimd128Register().V2D(), i.InputSimd128Register(0).V2D(),
+ tmp.V2D());
+ break;
+ }
+ case kArm64I64x2ShrS: {
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V2D(), i.InputRegister64(1));
+ __ Neg(tmp.V2D(), tmp.V2D());
+ __ Sshl(i.OutputSimd128Register().V2D(), i.InputSimd128Register(0).V2D(),
+ tmp.V2D());
+ break;
+ }
+ SIMD_BINOP_CASE(kArm64I64x2Add, Add, 2D);
+ SIMD_BINOP_CASE(kArm64I64x2Sub, Sub, 2D);
+ SIMD_BINOP_CASE(kArm64I64x2Eq, Cmeq, 2D);
+ case kArm64I64x2Ne: {
+ VRegister dst = i.OutputSimd128Register().V2D();
+ __ Cmeq(dst, i.InputSimd128Register(0).V2D(),
+ i.InputSimd128Register(1).V2D());
+ __ Mvn(dst, dst);
+ break;
+ }
+ SIMD_BINOP_CASE(kArm64I64x2GtS, Cmgt, 2D);
+ SIMD_BINOP_CASE(kArm64I64x2GeS, Cmge, 2D);
+ case kArm64I64x2ShrU: {
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V2D(), i.InputRegister64(1));
+ __ Neg(tmp.V2D(), tmp.V2D());
+ __ Ushl(i.OutputSimd128Register().V2D(), i.InputSimd128Register(0).V2D(),
+ tmp.V2D());
+ break;
+ }
+ SIMD_BINOP_CASE(kArm64I64x2GtU, Cmhi, 2D);
+ SIMD_BINOP_CASE(kArm64I64x2GeU, Cmhs, 2D);
case kArm64I32x4Splat: {
__ Dup(i.OutputSimd128Register().V4S(), i.InputRegister32(0));
break;
@@ -1851,13 +1946,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
SIMD_WIDENING_UNOP_CASE(kArm64I32x4SConvertI16x8High, Sxtl2, 4S, 8H);
SIMD_UNOP_CASE(kArm64I32x4Neg, Neg, 4S);
case kArm64I32x4Shl: {
- __ Shl(i.OutputSimd128Register().V4S(), i.InputSimd128Register(0).V4S(),
- i.InputInt5(1));
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V4S(), i.InputRegister32(1));
+ __ Sshl(i.OutputSimd128Register().V4S(), i.InputSimd128Register(0).V4S(),
+ tmp.V4S());
break;
}
case kArm64I32x4ShrS: {
- __ Sshr(i.OutputSimd128Register().V4S(), i.InputSimd128Register(0).V4S(),
- i.InputInt5(1));
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V4S(), i.InputRegister32(1));
+ __ Neg(tmp.V4S(), tmp.V4S());
+ __ Sshl(i.OutputSimd128Register().V4S(), i.InputSimd128Register(0).V4S(),
+ tmp.V4S());
break;
}
SIMD_BINOP_CASE(kArm64I32x4Add, Add, 4S);
@@ -1880,8 +1980,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
SIMD_WIDENING_UNOP_CASE(kArm64I32x4UConvertI16x8Low, Uxtl, 4S, 4H);
SIMD_WIDENING_UNOP_CASE(kArm64I32x4UConvertI16x8High, Uxtl2, 4S, 8H);
case kArm64I32x4ShrU: {
- __ Ushr(i.OutputSimd128Register().V4S(), i.InputSimd128Register(0).V4S(),
- i.InputInt5(1));
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V4S(), i.InputRegister32(1));
+ __ Neg(tmp.V4S(), tmp.V4S());
+ __ Ushl(i.OutputSimd128Register().V4S(), i.InputSimd128Register(0).V4S(),
+ tmp.V4S());
break;
}
SIMD_BINOP_CASE(kArm64I32x4MinU, Umin, 4S);
@@ -1910,13 +2013,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
SIMD_WIDENING_UNOP_CASE(kArm64I16x8SConvertI8x16High, Sxtl2, 8H, 16B);
SIMD_UNOP_CASE(kArm64I16x8Neg, Neg, 8H);
case kArm64I16x8Shl: {
- __ Shl(i.OutputSimd128Register().V8H(), i.InputSimd128Register(0).V8H(),
- i.InputInt5(1));
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V8H(), i.InputRegister32(1));
+ __ Sshl(i.OutputSimd128Register().V8H(), i.InputSimd128Register(0).V8H(),
+ tmp.V8H());
break;
}
case kArm64I16x8ShrS: {
- __ Sshr(i.OutputSimd128Register().V8H(), i.InputSimd128Register(0).V8H(),
- i.InputInt5(1));
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V8H(), i.InputRegister32(1));
+ __ Neg(tmp.V8H(), tmp.V8H());
+ __ Sshl(i.OutputSimd128Register().V8H(), i.InputSimd128Register(0).V8H(),
+ tmp.V8H());
break;
}
case kArm64I16x8SConvertI32x4: {
@@ -1961,8 +2069,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kArm64I16x8ShrU: {
- __ Ushr(i.OutputSimd128Register().V8H(), i.InputSimd128Register(0).V8H(),
- i.InputInt5(1));
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V8H(), i.InputRegister32(1));
+ __ Neg(tmp.V8H(), tmp.V8H());
+ __ Ushl(i.OutputSimd128Register().V8H(), i.InputSimd128Register(0).V8H(),
+ tmp.V8H());
break;
}
case kArm64I16x8UConvertI32x4: {
@@ -2005,13 +2116,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
SIMD_UNOP_CASE(kArm64I8x16Neg, Neg, 16B);
case kArm64I8x16Shl: {
- __ Shl(i.OutputSimd128Register().V16B(), i.InputSimd128Register(0).V16B(),
- i.InputInt5(1));
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V16B(), i.InputRegister32(1));
+ __ Sshl(i.OutputSimd128Register().V16B(),
+ i.InputSimd128Register(0).V16B(), tmp.V16B());
break;
}
case kArm64I8x16ShrS: {
- __ Sshr(i.OutputSimd128Register().V16B(),
- i.InputSimd128Register(0).V16B(), i.InputInt5(1));
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V16B(), i.InputRegister32(1));
+ __ Neg(tmp.V16B(), tmp.V16B());
+ __ Sshl(i.OutputSimd128Register().V16B(),
+ i.InputSimd128Register(0).V16B(), tmp.V16B());
break;
}
case kArm64I8x16SConvertI16x8: {
@@ -2046,8 +2162,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
SIMD_BINOP_CASE(kArm64I8x16GtS, Cmgt, 16B);
SIMD_BINOP_CASE(kArm64I8x16GeS, Cmge, 16B);
case kArm64I8x16ShrU: {
- __ Ushr(i.OutputSimd128Register().V16B(),
- i.InputSimd128Register(0).V16B(), i.InputInt5(1));
+ VRegister tmp = i.TempSimd128Register(0);
+ __ Dup(tmp.V16B(), i.InputRegister32(1));
+ __ Neg(tmp.V16B(), tmp.V16B());
+ __ Ushl(i.OutputSimd128Register().V16B(),
+ i.InputSimd128Register(0).V16B(), tmp.V16B());
break;
}
case kArm64I8x16UConvertI16x8: {
@@ -2192,7 +2311,17 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
SIMD_UNOP_CASE(kArm64S8x8Reverse, Rev64, 16B);
SIMD_UNOP_CASE(kArm64S8x4Reverse, Rev32, 16B);
SIMD_UNOP_CASE(kArm64S8x2Reverse, Rev16, 16B);
+ case kArm64S1x2AllTrue: {
+ UseScratchRegisterScope scope(tasm());
+ VRegister temp1 = scope.AcquireV(kFormat2D);
+ VRegister temp2 = scope.AcquireV(kFormatS);
+ __ Cmeq(temp1, i.InputSimd128Register(0).V2D(), 0);
+ __ Umaxv(temp2, temp1.V4S());
+ __ Umov(i.OutputRegister32(), temp2, 0);
+ __ Add(i.OutputRegister32(), i.OutputRegister32(), 1);
+ break;
+ }
#define SIMD_REDUCE_OP_CASE(Op, Instr, format, FORMAT) \
case Op: { \
UseScratchRegisterScope scope(tasm()); \
@@ -2203,6 +2332,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Cset(i.OutputRegister32(), ne); \
break; \
}
+ // for AnyTrue, the format does not matter, umaxv does not support 2D
+ SIMD_REDUCE_OP_CASE(kArm64S1x2AnyTrue, Umaxv, kFormatS, 4S);
SIMD_REDUCE_OP_CASE(kArm64S1x4AnyTrue, Umaxv, kFormatS, 4S);
SIMD_REDUCE_OP_CASE(kArm64S1x4AllTrue, Uminv, kFormatS, 4S);
SIMD_REDUCE_OP_CASE(kArm64S1x8AnyTrue, Umaxv, kFormatH, 8H);
@@ -2669,6 +2800,11 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::FinishCode() { __ ForceConstantPoolEmissionWithoutJump(); }
+void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {
+ __ ForceConstantPoolEmissionWithoutJump();
+ __ CheckVeneerPool(false, false, deopt_count * Deoptimizer::kDeoptExitSize);
+}
+
void CodeGenerator::AssembleMove(InstructionOperand* source,
InstructionOperand* destination) {
Arm64OperandConverter g(this, nullptr);
diff --git a/deps/v8/src/compiler/backend/arm64/instruction-codes-arm64.h b/deps/v8/src/compiler/backend/arm64/instruction-codes-arm64.h
index 1c4c0e3335..4b56e402c1 100644
--- a/deps/v8/src/compiler/backend/arm64/instruction-codes-arm64.h
+++ b/deps/v8/src/compiler/backend/arm64/instruction-codes-arm64.h
@@ -168,11 +168,23 @@ namespace compiler {
V(Arm64DecompressSigned) \
V(Arm64DecompressPointer) \
V(Arm64DecompressAny) \
- V(Arm64CompressSigned) \
- V(Arm64CompressPointer) \
- V(Arm64CompressAny) \
V(Arm64DmbIsh) \
V(Arm64DsbIsb) \
+ V(Arm64F64x2Splat) \
+ V(Arm64F64x2ExtractLane) \
+ V(Arm64F64x2ReplaceLane) \
+ V(Arm64F64x2Abs) \
+ V(Arm64F64x2Neg) \
+ V(Arm64F64x2Add) \
+ V(Arm64F64x2Sub) \
+ V(Arm64F64x2Mul) \
+ V(Arm64F64x2Div) \
+ V(Arm64F64x2Min) \
+ V(Arm64F64x2Max) \
+ V(Arm64F64x2Eq) \
+ V(Arm64F64x2Ne) \
+ V(Arm64F64x2Lt) \
+ V(Arm64F64x2Le) \
V(Arm64F32x4Splat) \
V(Arm64F32x4ExtractLane) \
V(Arm64F32x4ReplaceLane) \
@@ -186,12 +198,28 @@ namespace compiler {
V(Arm64F32x4AddHoriz) \
V(Arm64F32x4Sub) \
V(Arm64F32x4Mul) \
+ V(Arm64F32x4Div) \
V(Arm64F32x4Min) \
V(Arm64F32x4Max) \
V(Arm64F32x4Eq) \
V(Arm64F32x4Ne) \
V(Arm64F32x4Lt) \
V(Arm64F32x4Le) \
+ V(Arm64I64x2Splat) \
+ V(Arm64I64x2ExtractLane) \
+ V(Arm64I64x2ReplaceLane) \
+ V(Arm64I64x2Neg) \
+ V(Arm64I64x2Shl) \
+ V(Arm64I64x2ShrS) \
+ V(Arm64I64x2Add) \
+ V(Arm64I64x2Sub) \
+ V(Arm64I64x2Eq) \
+ V(Arm64I64x2Ne) \
+ V(Arm64I64x2GtS) \
+ V(Arm64I64x2GeS) \
+ V(Arm64I64x2ShrU) \
+ V(Arm64I64x2GtU) \
+ V(Arm64I64x2GeU) \
V(Arm64I32x4Splat) \
V(Arm64I32x4ExtractLane) \
V(Arm64I32x4ReplaceLane) \
@@ -310,6 +338,8 @@ namespace compiler {
V(Arm64S8x8Reverse) \
V(Arm64S8x4Reverse) \
V(Arm64S8x2Reverse) \
+ V(Arm64S1x2AnyTrue) \
+ V(Arm64S1x2AllTrue) \
V(Arm64S1x4AnyTrue) \
V(Arm64S1x4AllTrue) \
V(Arm64S1x8AnyTrue) \
diff --git a/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc b/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc
index 8344887ec2..7cba2d50ea 100644
--- a/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc
+++ b/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc
@@ -137,6 +137,21 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArm64Float64MoveU64:
case kArm64U64MoveFloat64:
case kArm64Float64SilenceNaN:
+ case kArm64F64x2Splat:
+ case kArm64F64x2ExtractLane:
+ case kArm64F64x2ReplaceLane:
+ case kArm64F64x2Abs:
+ case kArm64F64x2Neg:
+ case kArm64F64x2Add:
+ case kArm64F64x2Sub:
+ case kArm64F64x2Mul:
+ case kArm64F64x2Div:
+ case kArm64F64x2Min:
+ case kArm64F64x2Max:
+ case kArm64F64x2Eq:
+ case kArm64F64x2Ne:
+ case kArm64F64x2Lt:
+ case kArm64F64x2Le:
case kArm64F32x4Splat:
case kArm64F32x4ExtractLane:
case kArm64F32x4ReplaceLane:
@@ -150,12 +165,28 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArm64F32x4AddHoriz:
case kArm64F32x4Sub:
case kArm64F32x4Mul:
+ case kArm64F32x4Div:
case kArm64F32x4Min:
case kArm64F32x4Max:
case kArm64F32x4Eq:
case kArm64F32x4Ne:
case kArm64F32x4Lt:
case kArm64F32x4Le:
+ case kArm64I64x2Splat:
+ case kArm64I64x2ExtractLane:
+ case kArm64I64x2ReplaceLane:
+ case kArm64I64x2Neg:
+ case kArm64I64x2Shl:
+ case kArm64I64x2ShrS:
+ case kArm64I64x2Add:
+ case kArm64I64x2Sub:
+ case kArm64I64x2Eq:
+ case kArm64I64x2Ne:
+ case kArm64I64x2GtS:
+ case kArm64I64x2GeS:
+ case kArm64I64x2ShrU:
+ case kArm64I64x2GtU:
+ case kArm64I64x2GeU:
case kArm64I32x4Splat:
case kArm64I32x4ExtractLane:
case kArm64I32x4ReplaceLane:
@@ -274,6 +305,8 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArm64S8x8Reverse:
case kArm64S8x4Reverse:
case kArm64S8x2Reverse:
+ case kArm64S1x2AnyTrue:
+ case kArm64S1x2AllTrue:
case kArm64S1x4AnyTrue:
case kArm64S1x4AllTrue:
case kArm64S1x8AnyTrue:
@@ -287,9 +320,6 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kArm64DecompressSigned:
case kArm64DecompressPointer:
case kArm64DecompressAny:
- case kArm64CompressSigned:
- case kArm64CompressPointer:
- case kArm64CompressAny:
return kNoOpcodeFlags;
case kArm64LdrS:
diff --git a/deps/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc b/deps/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc
index a953e35a66..4abbd68c49 100644
--- a/deps/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc
+++ b/deps/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc
@@ -48,16 +48,6 @@ class Arm64OperandGenerator final : public OperandGenerator {
return UseRegister(node);
}
- // Use the stack pointer if the node is LoadStackPointer, otherwise assign a
- // register.
- InstructionOperand UseRegisterOrStackPointer(Node* node, bool sp_allowed) {
- if (sp_allowed && node->opcode() == IrOpcode::kLoadStackPointer)
- return LocationOperand(LocationOperand::EXPLICIT,
- LocationOperand::REGISTER,
- MachineRepresentation::kWord64, sp.code());
- return UseRegister(node);
- }
-
// Use the provided node if it has the required value, or create a
// TempImmediate otherwise.
InstructionOperand UseImmediateOrTemp(Node* node, int32_t value) {
@@ -160,6 +150,15 @@ void VisitRRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
g.UseRegister(node->InputAt(1)));
}
+void VisitSimdShiftRRR(InstructionSelector* selector, ArchOpcode opcode,
+ Node* node) {
+ Arm64OperandGenerator g(selector);
+ InstructionOperand temps[] = {g.TempSimd128Register()};
+ selector->Emit(opcode, g.DefineAsRegister(node),
+ g.UseRegister(node->InputAt(0)),
+ g.UseRegister(node->InputAt(1)), arraysize(temps), temps);
+}
+
void VisitRRI(InstructionSelector* selector, ArchOpcode opcode, Node* node) {
Arm64OperandGenerator g(selector);
int32_t imm = OpParameter<int32_t>(node->op());
@@ -554,23 +553,21 @@ void EmitLoad(InstructionSelector* selector, Node* node, InstructionCode opcode,
// is used when we merge a conversion into the load.
outputs[0] = g.DefineAsRegister(output == nullptr ? node : output);
- if (selector->CanAddressRelativeToRootsRegister()) {
- ExternalReferenceMatcher m(base);
- if (m.HasValue() && g.IsIntegerConstant(index)) {
- ptrdiff_t const delta =
- g.GetIntegerConstantValue(index) +
- TurboAssemblerBase::RootRegisterOffsetForExternalReference(
- selector->isolate(), m.Value());
- input_count = 1;
- // Check that the delta is a 32-bit integer due to the limitations of
- // immediate operands.
- if (is_int32(delta)) {
- inputs[0] = g.UseImmediate(static_cast<int32_t>(delta));
- opcode |= AddressingModeField::encode(kMode_Root);
- selector->Emit(opcode, arraysize(outputs), outputs, input_count,
- inputs);
- return;
- }
+ ExternalReferenceMatcher m(base);
+ if (m.HasValue() && g.IsIntegerConstant(index) &&
+ selector->CanAddressRelativeToRootsRegister(m.Value())) {
+ ptrdiff_t const delta =
+ g.GetIntegerConstantValue(index) +
+ TurboAssemblerBase::RootRegisterOffsetForExternalReference(
+ selector->isolate(), m.Value());
+ input_count = 1;
+ // Check that the delta is a 32-bit integer due to the limitations of
+ // immediate operands.
+ if (is_int32(delta)) {
+ inputs[0] = g.UseImmediate(static_cast<int32_t>(delta));
+ opcode |= AddressingModeField::encode(kMode_Root);
+ selector->Emit(opcode, arraysize(outputs), outputs, input_count, inputs);
+ return;
}
}
@@ -670,7 +667,8 @@ void InstructionSelector::VisitStore(Node* node) {
MachineRepresentation rep = store_rep.representation();
// TODO(arm64): I guess this could be done in a better way.
- if (write_barrier_kind != kNoWriteBarrier) {
+ if (write_barrier_kind != kNoWriteBarrier &&
+ V8_LIKELY(!FLAG_disable_write_barriers)) {
DCHECK(CanBeTaggedOrCompressedPointer(rep));
AddressingMode addressing_mode;
InstructionOperand inputs[3];
@@ -1004,6 +1002,15 @@ void InstructionSelector::VisitWord64Shl(Node* node) {
VisitRRO(this, kArm64Lsl, node, kShift64Imm);
}
+void InstructionSelector::VisitStackPointerGreaterThan(
+ Node* node, FlagsContinuation* cont) {
+ Node* const value = node->InputAt(0);
+ InstructionCode opcode = kArchStackPointerGreaterThan;
+
+ Arm64OperandGenerator g(this);
+ EmitWithContinuation(opcode, g.UseRegister(value), cont);
+}
+
namespace {
bool TryEmitBitfieldExtract32(InstructionSelector* selector, Node* node) {
@@ -1625,23 +1632,23 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
}
void InstructionSelector::VisitChangeTaggedToCompressed(Node* node) {
- Arm64OperandGenerator g(this);
- Node* value = node->InputAt(0);
- Emit(kArm64CompressAny, g.DefineAsRegister(node), g.UseRegister(value));
+ // The top 32 bits in the 64-bit register will be undefined, and
+ // must not be used by a dependent node.
+ EmitIdentity(node);
}
void InstructionSelector::VisitChangeTaggedPointerToCompressedPointer(
Node* node) {
- Arm64OperandGenerator g(this);
- Node* value = node->InputAt(0);
- Emit(kArm64CompressPointer, g.DefineAsRegister(node), g.UseRegister(value));
+ // The top 32 bits in the 64-bit register will be undefined, and
+ // must not be used by a dependent node.
+ EmitIdentity(node);
}
void InstructionSelector::VisitChangeTaggedSignedToCompressedSigned(
Node* node) {
- Arm64OperandGenerator g(this);
- Node* value = node->InputAt(0);
- Emit(kArm64CompressSigned, g.DefineAsRegister(node), g.UseRegister(value));
+ // The top 32 bits in the 64-bit register will be undefined, and
+ // must not be used by a dependent node.
+ EmitIdentity(node);
}
void InstructionSelector::VisitChangeCompressedToTagged(Node* node) {
@@ -1826,26 +1833,25 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
// Shared routine for multiple word compare operations.
void VisitWordCompare(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont,
- bool commutative, ImmediateMode immediate_mode) {
+ ImmediateMode immediate_mode) {
Arm64OperandGenerator g(selector);
+
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
- if (right->opcode() == IrOpcode::kLoadStackPointer ||
+ // If one of the two inputs is an immediate, make sure it's on the right.
+ if (!g.CanBeImmediate(right, immediate_mode) &&
g.CanBeImmediate(left, immediate_mode)) {
- if (!commutative) cont->Commute();
+ cont->Commute();
std::swap(left, right);
}
- // Match immediates on left or right side of comparison.
if (g.CanBeImmediate(right, immediate_mode)) {
- VisitCompare(selector, opcode,
- g.UseRegisterOrStackPointer(left, opcode == kArm64Cmp),
- g.UseImmediate(right), cont);
+ VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
+ cont);
} else {
- VisitCompare(selector, opcode,
- g.UseRegisterOrStackPointer(left, opcode == kArm64Cmp),
- g.UseRegister(right), cont);
+ VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
+ cont);
}
}
@@ -2370,8 +2376,7 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
if (m.right().Is(0)) {
Node* const left = m.left().node();
if (CanCover(value, left) && left->opcode() == IrOpcode::kWord64And) {
- return VisitWordCompare(this, left, kArm64Tst, cont, true,
- kLogical64Imm);
+ return VisitWordCompare(this, left, kArm64Tst, cont, kLogical64Imm);
}
// Merge the Word64Equal(x, 0) comparison into a cbz instruction.
if ((cont->IsBranch() || cont->IsDeoptimize()) &&
@@ -2381,25 +2386,20 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
return;
}
}
- return VisitWordCompare(this, value, kArm64Cmp, cont, false,
- kArithmeticImm);
+ return VisitWordCompare(this, value, kArm64Cmp, cont, kArithmeticImm);
}
case IrOpcode::kInt64LessThan:
cont->OverwriteAndNegateIfEqual(kSignedLessThan);
- return VisitWordCompare(this, value, kArm64Cmp, cont, false,
- kArithmeticImm);
+ return VisitWordCompare(this, value, kArm64Cmp, cont, kArithmeticImm);
case IrOpcode::kInt64LessThanOrEqual:
cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
- return VisitWordCompare(this, value, kArm64Cmp, cont, false,
- kArithmeticImm);
+ return VisitWordCompare(this, value, kArm64Cmp, cont, kArithmeticImm);
case IrOpcode::kUint64LessThan:
cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
- return VisitWordCompare(this, value, kArm64Cmp, cont, false,
- kArithmeticImm);
+ return VisitWordCompare(this, value, kArm64Cmp, cont, kArithmeticImm);
case IrOpcode::kUint64LessThanOrEqual:
cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
- return VisitWordCompare(this, value, kArm64Cmp, cont, false,
- kArithmeticImm);
+ return VisitWordCompare(this, value, kArm64Cmp, cont, kArithmeticImm);
case IrOpcode::kFloat32Equal:
cont->OverwriteAndNegateIfEqual(kEqual);
return VisitFloat32Compare(this, value, cont);
@@ -2461,16 +2461,16 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
}
break;
case IrOpcode::kInt32Add:
- return VisitWordCompare(this, value, kArm64Cmn32, cont, true,
- kArithmeticImm);
+ return VisitWordCompare(this, value, kArm64Cmn32, cont, kArithmeticImm);
case IrOpcode::kInt32Sub:
return VisitWord32Compare(this, value, cont);
case IrOpcode::kWord32And:
- return VisitWordCompare(this, value, kArm64Tst32, cont, true,
- kLogical32Imm);
+ return VisitWordCompare(this, value, kArm64Tst32, cont, kLogical32Imm);
case IrOpcode::kWord64And:
- return VisitWordCompare(this, value, kArm64Tst, cont, true,
- kLogical64Imm);
+ return VisitWordCompare(this, value, kArm64Tst, cont, kLogical64Imm);
+ case IrOpcode::kStackPointerGreaterThan:
+ cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
+ return VisitStackPointerGreaterThan(value, cont);
default:
break;
}
@@ -2530,7 +2530,7 @@ void InstructionSelector::VisitWord32Equal(Node* const node) {
case IrOpcode::kWord32And:
return VisitWord32Compare(this, node, &cont);
case IrOpcode::kInt32Sub:
- return VisitWordCompare(this, value, kArm64Cmp32, &cont, false,
+ return VisitWordCompare(this, value, kArm64Cmp32, &cont,
kArithmeticImm);
case IrOpcode::kWord32Equal: {
// Word32Equal(Word32Equal(x, y), 0) => Word32Compare(x, y, ne).
@@ -2587,15 +2587,14 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
if (CanCover(user, value)) {
switch (value->opcode()) {
case IrOpcode::kWord64And:
- return VisitWordCompare(this, value, kArm64Tst, &cont, true,
- kLogical64Imm);
+ return VisitWordCompare(this, value, kArm64Tst, &cont, kLogical64Imm);
default:
break;
}
return VisitWord64Test(this, value, &cont);
}
}
- VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
+ VisitWordCompare(this, node, kArm64Cmp, &cont, kArithmeticImm);
}
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
@@ -2653,24 +2652,24 @@ void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
void InstructionSelector::VisitInt64LessThan(Node* node) {
FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node);
- VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
+ VisitWordCompare(this, node, kArm64Cmp, &cont, kArithmeticImm);
}
void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForSet(kSignedLessThanOrEqual, node);
- VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
+ VisitWordCompare(this, node, kArm64Cmp, &cont, kArithmeticImm);
}
void InstructionSelector::VisitUint64LessThan(Node* node) {
FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node);
- VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
+ VisitWordCompare(this, node, kArm64Cmp, &cont, kArithmeticImm);
}
void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) {
FlagsContinuation cont =
FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node);
- VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm);
+ VisitWordCompare(this, node, kArm64Cmp, &cont, kArithmeticImm);
}
void InstructionSelector::VisitFloat32Neg(Node* node) {
@@ -3045,18 +3044,23 @@ void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
}
#define SIMD_TYPE_LIST(V) \
+ V(F64x2) \
V(F32x4) \
+ V(I64x2) \
V(I32x4) \
V(I16x8) \
V(I8x16)
#define SIMD_UNOP_LIST(V) \
+ V(F64x2Abs, kArm64F64x2Abs) \
+ V(F64x2Neg, kArm64F64x2Neg) \
V(F32x4SConvertI32x4, kArm64F32x4SConvertI32x4) \
V(F32x4UConvertI32x4, kArm64F32x4UConvertI32x4) \
V(F32x4Abs, kArm64F32x4Abs) \
V(F32x4Neg, kArm64F32x4Neg) \
V(F32x4RecipApprox, kArm64F32x4RecipApprox) \
V(F32x4RecipSqrtApprox, kArm64F32x4RecipSqrtApprox) \
+ V(I64x2Neg, kArm64I64x2Neg) \
V(I32x4SConvertF32x4, kArm64I32x4SConvertF32x4) \
V(I32x4SConvertI16x8Low, kArm64I32x4SConvertI16x8Low) \
V(I32x4SConvertI16x8High, kArm64I32x4SConvertI16x8High) \
@@ -3071,6 +3075,8 @@ void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
V(I16x8UConvertI8x16High, kArm64I16x8UConvertI8x16High) \
V(I8x16Neg, kArm64I8x16Neg) \
V(S128Not, kArm64S128Not) \
+ V(S1x2AnyTrue, kArm64S1x2AnyTrue) \
+ V(S1x2AllTrue, kArm64S1x2AllTrue) \
V(S1x4AnyTrue, kArm64S1x4AnyTrue) \
V(S1x4AllTrue, kArm64S1x4AllTrue) \
V(S1x8AnyTrue, kArm64S1x8AnyTrue) \
@@ -3079,6 +3085,9 @@ void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
V(S1x16AllTrue, kArm64S1x16AllTrue)
#define SIMD_SHIFT_OP_LIST(V) \
+ V(I64x2Shl) \
+ V(I64x2ShrS) \
+ V(I64x2ShrU) \
V(I32x4Shl) \
V(I32x4ShrS) \
V(I32x4ShrU) \
@@ -3090,16 +3099,35 @@ void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
V(I8x16ShrU)
#define SIMD_BINOP_LIST(V) \
+ V(F64x2Add, kArm64F64x2Add) \
+ V(F64x2Sub, kArm64F64x2Sub) \
+ V(F64x2Mul, kArm64F64x2Mul) \
+ V(F64x2Div, kArm64F64x2Div) \
+ V(F64x2Min, kArm64F64x2Min) \
+ V(F64x2Max, kArm64F64x2Max) \
+ V(F64x2Eq, kArm64F64x2Eq) \
+ V(F64x2Ne, kArm64F64x2Ne) \
+ V(F64x2Lt, kArm64F64x2Lt) \
+ V(F64x2Le, kArm64F64x2Le) \
V(F32x4Add, kArm64F32x4Add) \
V(F32x4AddHoriz, kArm64F32x4AddHoriz) \
V(F32x4Sub, kArm64F32x4Sub) \
V(F32x4Mul, kArm64F32x4Mul) \
+ V(F32x4Div, kArm64F32x4Div) \
V(F32x4Min, kArm64F32x4Min) \
V(F32x4Max, kArm64F32x4Max) \
V(F32x4Eq, kArm64F32x4Eq) \
V(F32x4Ne, kArm64F32x4Ne) \
V(F32x4Lt, kArm64F32x4Lt) \
V(F32x4Le, kArm64F32x4Le) \
+ V(I64x2Add, kArm64I64x2Add) \
+ V(I64x2Sub, kArm64I64x2Sub) \
+ V(I64x2Eq, kArm64I64x2Eq) \
+ V(I64x2Ne, kArm64I64x2Ne) \
+ V(I64x2GtS, kArm64I64x2GtS) \
+ V(I64x2GeS, kArm64I64x2GeS) \
+ V(I64x2GtU, kArm64I64x2GtU) \
+ V(I64x2GeU, kArm64I64x2GeU) \
V(I32x4Add, kArm64I32x4Add) \
V(I32x4AddHoriz, kArm64I32x4AddHoriz) \
V(I32x4Sub, kArm64I32x4Sub) \
@@ -3194,7 +3222,7 @@ SIMD_UNOP_LIST(SIMD_VISIT_UNOP)
#define SIMD_VISIT_SHIFT_OP(Name) \
void InstructionSelector::Visit##Name(Node* node) { \
- VisitRRI(this, kArm64##Name, node); \
+ VisitSimdShiftRRR(this, kArm64##Name, node); \
}
SIMD_SHIFT_OP_LIST(SIMD_VISIT_SHIFT_OP)
#undef SIMD_VISIT_SHIFT_OP
diff --git a/deps/v8/src/compiler/backend/code-generator-impl.h b/deps/v8/src/compiler/backend/code-generator-impl.h
index 75f8e70203..2bfb009980 100644
--- a/deps/v8/src/compiler/backend/code-generator-impl.h
+++ b/deps/v8/src/compiler/backend/code-generator-impl.h
@@ -116,6 +116,10 @@ class InstructionOperandConverter {
return ToSimd128Register(instr_->Output());
}
+ Simd128Register TempSimd128Register(size_t index) {
+ return ToSimd128Register(instr_->TempAt(index));
+ }
+
// -- Conversions for operands -----------------------------------------------
Label* ToLabel(InstructionOperand* op) {
@@ -176,20 +180,55 @@ class InstructionOperandConverter {
Instruction* instr_;
};
-// Eager deoptimization exit.
+// Deoptimization exit.
class DeoptimizationExit : public ZoneObject {
public:
- explicit DeoptimizationExit(int deoptimization_id, SourcePosition pos)
- : deoptimization_id_(deoptimization_id), pos_(pos) {}
-
- int deoptimization_id() const { return deoptimization_id_; }
- Label* label() { return &label_; }
+ explicit DeoptimizationExit(SourcePosition pos, BailoutId bailout_id,
+ int translation_id, int pc_offset,
+ DeoptimizeKind kind, DeoptimizeReason reason)
+ : deoptimization_id_(kNoDeoptIndex),
+ pos_(pos),
+ bailout_id_(bailout_id),
+ translation_id_(translation_id),
+ pc_offset_(pc_offset),
+ kind_(kind),
+ reason_(reason),
+ emitted_(false) {}
+
+ bool has_deoptimization_id() const {
+ return deoptimization_id_ != kNoDeoptIndex;
+ }
+ int deoptimization_id() const {
+ DCHECK(has_deoptimization_id());
+ return deoptimization_id_;
+ }
+ void set_deoptimization_id(int deoptimization_id) {
+ deoptimization_id_ = deoptimization_id;
+ }
SourcePosition pos() const { return pos_; }
+ Label* label() { return &label_; }
+ BailoutId bailout_id() const { return bailout_id_; }
+ int translation_id() const { return translation_id_; }
+ int pc_offset() const { return pc_offset_; }
+ DeoptimizeKind kind() const { return kind_; }
+ DeoptimizeReason reason() const { return reason_; }
+ // Returns whether the deopt exit has already been emitted. Most deopt exits
+ // are emitted contiguously at the end of the code, but unconditional deopt
+ // exits (kArchDeoptimize) may be inlined where they are encountered.
+ bool emitted() const { return emitted_; }
+ void set_emitted() { emitted_ = true; }
private:
- int const deoptimization_id_;
+ static const int kNoDeoptIndex = kMaxInt16 + 1;
+ int deoptimization_id_;
+ const SourcePosition pos_;
Label label_;
- SourcePosition const pos_;
+ const BailoutId bailout_id_;
+ const int translation_id_;
+ const int pc_offset_;
+ const DeoptimizeKind kind_;
+ const DeoptimizeReason reason_;
+ bool emitted_;
};
// Generator for out-of-line code that is emitted after the main code is done.
diff --git a/deps/v8/src/compiler/backend/code-generator.cc b/deps/v8/src/compiler/backend/code-generator.cc
index 9ce92dadaa..e7702bcdf6 100644
--- a/deps/v8/src/compiler/backend/code-generator.cc
+++ b/deps/v8/src/compiler/backend/code-generator.cc
@@ -47,7 +47,8 @@ CodeGenerator::CodeGenerator(
Isolate* isolate, base::Optional<OsrHelper> osr_helper,
int start_source_position, JumpOptimizationInfo* jump_opt,
PoisoningMitigationLevel poisoning_level, const AssemblerOptions& options,
- int32_t builtin_index, std::unique_ptr<AssemblerBuffer> buffer)
+ int32_t builtin_index, size_t max_unoptimized_frame_height,
+ std::unique_ptr<AssemblerBuffer> buffer)
: zone_(codegen_zone),
isolate_(isolate),
frame_access_state_(nullptr),
@@ -64,9 +65,9 @@ CodeGenerator::CodeGenerator(
safepoints_(zone()),
handlers_(zone()),
deoptimization_exits_(zone()),
- deoptimization_states_(zone()),
deoptimization_literals_(zone()),
translations_(zone()),
+ max_unoptimized_frame_height_(max_unoptimized_frame_height),
caller_registers_saved_(false),
jump_tables_(nullptr),
ools_(nullptr),
@@ -91,6 +92,7 @@ CodeGenerator::CodeGenerator(
code_kind == Code::WASM_TO_CAPI_FUNCTION ||
code_kind == Code::WASM_TO_JS_FUNCTION ||
code_kind == Code::WASM_INTERPRETER_ENTRY ||
+ code_kind == Code::JS_TO_WASM_FUNCTION ||
(Builtins::IsBuiltinId(builtin_index) &&
Builtins::IsWasmRuntimeStub(builtin_index))) {
tasm_.set_abort_hard(true);
@@ -114,20 +116,22 @@ void CodeGenerator::CreateFrameAccessState(Frame* frame) {
}
CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
- int deoptimization_id, SourcePosition pos) {
+ DeoptimizationExit* exit) {
+ int deoptimization_id = exit->deoptimization_id();
if (deoptimization_id > Deoptimizer::kMaxNumberOfEntries) {
return kTooManyDeoptimizationBailouts;
}
- DeoptimizeKind deopt_kind = GetDeoptimizationKind(deoptimization_id);
- DeoptimizeReason deoptimization_reason =
- GetDeoptimizationReason(deoptimization_id);
+ DeoptimizeKind deopt_kind = exit->kind();
+ DeoptimizeReason deoptimization_reason = exit->reason();
Address deopt_entry =
Deoptimizer::GetDeoptimizationEntry(tasm()->isolate(), deopt_kind);
if (info()->is_source_positions_enabled()) {
- tasm()->RecordDeoptReason(deoptimization_reason, pos, deoptimization_id);
+ tasm()->RecordDeoptReason(deoptimization_reason, exit->pos(),
+ deoptimization_id);
}
tasm()->CallForDeoptimization(deopt_entry, deoptimization_id);
+ exit->set_emitted();
return kSuccess;
}
@@ -146,7 +150,7 @@ void CodeGenerator::AssembleCode() {
if (info->is_source_positions_enabled()) {
AssembleSourcePosition(start_source_position());
}
-
+ offsets_info_.code_start_register_check = tasm()->pc_offset();
// Check that {kJavaScriptCallCodeStartRegister} has been set correctly.
if (FLAG_debug_code && (info->code_kind() == Code::OPTIMIZED_FUNCTION ||
info->code_kind() == Code::BYTECODE_HANDLER)) {
@@ -154,6 +158,7 @@ void CodeGenerator::AssembleCode() {
AssembleCodeStartRegisterCheck();
}
+ offsets_info_.deopt_check = tasm()->pc_offset();
// We want to bailout only from JS functions, which are the only ones
// that are optimized.
if (info->IsOptimizing()) {
@@ -162,6 +167,7 @@ void CodeGenerator::AssembleCode() {
BailoutIfDeoptimized();
}
+ offsets_info_.init_poison = tasm()->pc_offset();
InitializeSpeculationPoison();
// Define deoptimization literals for all inlined functions.
@@ -191,10 +197,10 @@ void CodeGenerator::AssembleCode() {
if (info->trace_turbo_json_enabled()) {
block_starts_.assign(instructions()->instruction_blocks().size(), -1);
- instr_starts_.assign(instructions()->instructions().size(), -1);
+ instr_starts_.assign(instructions()->instructions().size(), {});
}
-
// Assemble instructions in assembly order.
+ offsets_info_.blocks_start = tasm()->pc_offset();
for (const InstructionBlock* block : instructions()->ao_blocks()) {
// Align loop headers on vendor recommended boundaries.
if (block->ShouldAlign() && !tasm()->jump_optimization_info()) {
@@ -252,6 +258,7 @@ void CodeGenerator::AssembleCode() {
}
// Assemble all out-of-line code.
+ offsets_info_.out_of_line_code = tasm()->pc_offset();
if (ools_) {
tasm()->RecordComment("-- Out of line code --");
for (OutOfLineCode* ool = ools_; ool; ool = ool->next()) {
@@ -266,28 +273,45 @@ void CodeGenerator::AssembleCode() {
// The test regress/regress-259 is an example of where we need it.
tasm()->nop();
+ // For some targets, we must make sure that constant and veneer pools are
+ // emitted before emitting the deoptimization exits.
+ PrepareForDeoptimizationExits(static_cast<int>(deoptimization_exits_.size()));
+
+ if (Deoptimizer::kSupportsFixedDeoptExitSize) {
+ deopt_exit_start_offset_ = tasm()->pc_offset();
+ }
+
// Assemble deoptimization exits.
+ offsets_info_.deoptimization_exits = tasm()->pc_offset();
int last_updated = 0;
for (DeoptimizationExit* exit : deoptimization_exits_) {
+ if (exit->emitted()) continue;
+ if (Deoptimizer::kSupportsFixedDeoptExitSize) {
+ exit->set_deoptimization_id(next_deoptimization_id_++);
+ }
tasm()->bind(exit->label());
- int trampoline_pc = tasm()->pc_offset();
- int deoptimization_id = exit->deoptimization_id();
- DeoptimizationState* ds = deoptimization_states_[deoptimization_id];
- if (ds->kind() == DeoptimizeKind::kLazy) {
+ // UpdateDeoptimizationInfo expects lazy deopts to be visited in pc_offset
+ // order, which is always the case since they are added to
+ // deoptimization_exits_ in that order.
+ if (exit->kind() == DeoptimizeKind::kLazy) {
+ int trampoline_pc = tasm()->pc_offset();
last_updated = safepoints()->UpdateDeoptimizationInfo(
- ds->pc_offset(), trampoline_pc, last_updated);
+ exit->pc_offset(), trampoline_pc, last_updated,
+ exit->deoptimization_id());
}
- result_ = AssembleDeoptimizerCall(deoptimization_id, exit->pos());
+ result_ = AssembleDeoptimizerCall(exit);
if (result_ != kSuccess) return;
}
+ offsets_info_.pools = tasm()->pc_offset();
// TODO(jgruber): Move all inlined metadata generation into a new,
// architecture-independent version of FinishCode. Currently, this includes
// the safepoint table, handler table, constant pool, and code comments, in
// that order.
FinishCode();
+ offsets_info_.jump_tables = tasm()->pc_offset();
// Emit the jump tables.
if (jump_tables_) {
tasm()->Align(kSystemPointerSize);
@@ -396,12 +420,12 @@ MaybeHandle<Code> CodeGenerator::FinalizeCode() {
CodeDesc desc;
tasm()->GetCode(isolate(), &desc, safepoints(), handler_table_offset_);
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
if (Builtins::IsBuiltinId(info_->builtin_index())) {
isolate_->SetBuiltinUnwindData(info_->builtin_index(),
tasm()->GetUnwindInfo());
}
-#endif
+#endif // V8_OS_WIN64
if (unwinding_info_writer_.eh_frame_writer()) {
unwinding_info_writer_.eh_frame_writer()->GetEhFrame(&desc);
@@ -473,11 +497,7 @@ bool CodeGenerator::IsMaterializableFromRoot(Handle<HeapObject> object,
CodeGenerator::CodeGenResult CodeGenerator::AssembleBlock(
const InstructionBlock* block) {
for (int i = block->code_start(); i < block->code_end(); ++i) {
- if (info()->trace_turbo_json_enabled()) {
- instr_starts_[i] = tasm()->pc_offset();
- }
- Instruction* instr = instructions()->InstructionAt(i);
- CodeGenResult result = AssembleInstruction(instr, block);
+ CodeGenResult result = AssembleInstruction(i, block);
if (result != kSuccess) return result;
}
return kSuccess;
@@ -631,7 +651,11 @@ RpoNumber CodeGenerator::ComputeBranchInfo(BranchInfo* branch,
}
CodeGenerator::CodeGenResult CodeGenerator::AssembleInstruction(
- Instruction* instr, const InstructionBlock* block) {
+ int instruction_index, const InstructionBlock* block) {
+ Instruction* instr = instructions()->InstructionAt(instruction_index);
+ if (info()->trace_turbo_json_enabled()) {
+ instr_starts_[instruction_index].gap_pc_offset = tasm()->pc_offset();
+ }
int first_unused_stack_slot;
FlagsMode mode = FlagsModeField::decode(instr->opcode());
if (mode != kFlags_trap) {
@@ -649,10 +673,17 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleInstruction(
if (instr->IsJump() && block->must_deconstruct_frame()) {
AssembleDeconstructFrame();
}
+ if (info()->trace_turbo_json_enabled()) {
+ instr_starts_[instruction_index].arch_instr_pc_offset = tasm()->pc_offset();
+ }
// Assemble architecture-specific code for the instruction.
CodeGenResult result = AssembleArchInstruction(instr);
if (result != kSuccess) return result;
+ if (info()->trace_turbo_json_enabled()) {
+ instr_starts_[instruction_index].condition_pc_offset = tasm()->pc_offset();
+ }
+
FlagsCondition condition = FlagsConditionField::decode(instr->opcode());
switch (mode) {
case kFlags_branch:
@@ -801,7 +832,7 @@ Handle<PodArray<InliningPosition>> CreateInliningPositions(
Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() {
OptimizedCompilationInfo* info = this->info();
- int deopt_count = static_cast<int>(deoptimization_states_.size());
+ int deopt_count = static_cast<int>(deoptimization_exits_.size());
if (deopt_count == 0 && !info->is_osr()) {
return DeoptimizationData::Empty(isolate());
}
@@ -816,6 +847,8 @@ Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() {
Smi::FromInt(static_cast<int>(inlined_function_count_)));
data->SetOptimizationId(Smi::FromInt(info->optimization_id()));
+ data->SetDeoptExitStart(Smi::FromInt(deopt_exit_start_offset_));
+
if (info->has_shared_info()) {
data->SetSharedFunctionInfo(*info->shared_info());
} else {
@@ -846,12 +879,13 @@ Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() {
// Populate deoptimization entries.
for (int i = 0; i < deopt_count; i++) {
- DeoptimizationState* deoptimization_state = deoptimization_states_[i];
- data->SetBytecodeOffset(i, deoptimization_state->bailout_id());
- CHECK(deoptimization_state);
+ DeoptimizationExit* deoptimization_exit = deoptimization_exits_[i];
+ CHECK_NOT_NULL(deoptimization_exit);
+ DCHECK_EQ(i, deoptimization_exit->deoptimization_id());
+ data->SetBytecodeOffset(i, deoptimization_exit->bailout_id());
data->SetTranslationIndex(
- i, Smi::FromInt(deoptimization_state->translation_id()));
- data->SetPc(i, Smi::FromInt(deoptimization_state->pc_offset()));
+ i, Smi::FromInt(deoptimization_exit->translation_id()));
+ data->SetPc(i, Smi::FromInt(deoptimization_exit->pc_offset()));
}
return data;
@@ -885,13 +919,8 @@ void CodeGenerator::RecordCallPosition(Instruction* instr) {
FrameStateDescriptor* descriptor =
GetDeoptimizationEntry(instr, frame_state_offset).descriptor();
int pc_offset = tasm()->pc_offset();
- int deopt_state_id = BuildTranslation(instr, pc_offset, frame_state_offset,
- descriptor->state_combine());
-
- DeoptimizationExit* const exit = new (zone())
- DeoptimizationExit(deopt_state_id, current_source_position_);
- deoptimization_exits_.push_back(exit);
- safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id);
+ BuildTranslation(instr, pc_offset, frame_state_offset,
+ descriptor->state_combine());
}
}
@@ -911,20 +940,6 @@ DeoptimizationEntry const& CodeGenerator::GetDeoptimizationEntry(
return instructions()->GetDeoptimizationEntry(state_id);
}
-DeoptimizeKind CodeGenerator::GetDeoptimizationKind(
- int deoptimization_id) const {
- size_t const index = static_cast<size_t>(deoptimization_id);
- DCHECK_LT(index, deoptimization_states_.size());
- return deoptimization_states_[index]->kind();
-}
-
-DeoptimizeReason CodeGenerator::GetDeoptimizationReason(
- int deoptimization_id) const {
- size_t const index = static_cast<size_t>(deoptimization_id);
- DCHECK_LT(index, deoptimization_states_.size());
- return deoptimization_states_[index]->reason();
-}
-
void CodeGenerator::TranslateStateValueDescriptor(
StateValueDescriptor* desc, StateValueList* nested,
Translation* translation, InstructionOperandIterator* iter) {
@@ -996,8 +1011,12 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
}
shared_info = info()->shared_info();
}
- int shared_info_id =
+
+ const BailoutId bailout_id = descriptor->bailout_id();
+ const int shared_info_id =
DefineDeoptimizationLiteral(DeoptimizationLiteral(shared_info));
+ const unsigned int height =
+ static_cast<unsigned int>(descriptor->GetHeight());
switch (descriptor->type()) {
case FrameStateType::kInterpretedFunction: {
@@ -1007,45 +1026,30 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
return_offset = static_cast<int>(state_combine.GetOffsetToPokeAt());
return_count = static_cast<int>(iter->instruction()->OutputCount());
}
- translation->BeginInterpretedFrame(
- descriptor->bailout_id(), shared_info_id,
- static_cast<unsigned int>(descriptor->locals_count() + 1),
- return_offset, return_count);
+ translation->BeginInterpretedFrame(bailout_id, shared_info_id, height,
+ return_offset, return_count);
break;
}
case FrameStateType::kArgumentsAdaptor:
- translation->BeginArgumentsAdaptorFrame(
- shared_info_id,
- static_cast<unsigned int>(descriptor->parameters_count()));
+ translation->BeginArgumentsAdaptorFrame(shared_info_id, height);
break;
case FrameStateType::kConstructStub:
- DCHECK(descriptor->bailout_id().IsValidForConstructStub());
- translation->BeginConstructStubFrame(
- descriptor->bailout_id(), shared_info_id,
- static_cast<unsigned int>(descriptor->parameters_count() + 1));
+ DCHECK(bailout_id.IsValidForConstructStub());
+ translation->BeginConstructStubFrame(bailout_id, shared_info_id, height);
break;
case FrameStateType::kBuiltinContinuation: {
- BailoutId bailout_id = descriptor->bailout_id();
- int parameter_count =
- static_cast<unsigned int>(descriptor->parameters_count());
translation->BeginBuiltinContinuationFrame(bailout_id, shared_info_id,
- parameter_count);
+ height);
break;
}
case FrameStateType::kJavaScriptBuiltinContinuation: {
- BailoutId bailout_id = descriptor->bailout_id();
- int parameter_count =
- static_cast<unsigned int>(descriptor->parameters_count());
translation->BeginJavaScriptBuiltinContinuationFrame(
- bailout_id, shared_info_id, parameter_count);
+ bailout_id, shared_info_id, height);
break;
}
case FrameStateType::kJavaScriptBuiltinContinuationWithCatch: {
- BailoutId bailout_id = descriptor->bailout_id();
- int parameter_count =
- static_cast<unsigned int>(descriptor->parameters_count());
translation->BeginJavaScriptBuiltinContinuationWithCatchFrame(
- bailout_id, shared_info_id, parameter_count);
+ bailout_id, shared_info_id, height);
break;
}
}
@@ -1053,9 +1057,9 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
TranslateFrameStateDescriptorOperands(descriptor, iter, translation);
}
-int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset,
- size_t frame_state_offset,
- OutputFrameStateCombine state_combine) {
+DeoptimizationExit* CodeGenerator::BuildTranslation(
+ Instruction* instr, int pc_offset, size_t frame_state_offset,
+ OutputFrameStateCombine state_combine) {
DeoptimizationEntry const& entry =
GetDeoptimizationEntry(instr, frame_state_offset);
FrameStateDescriptor* const descriptor = entry.descriptor();
@@ -1068,21 +1072,24 @@ int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset,
update_feedback_count, zone());
if (entry.feedback().IsValid()) {
DeoptimizationLiteral literal =
- DeoptimizationLiteral(entry.feedback().vector());
+ DeoptimizationLiteral(entry.feedback().vector);
int literal_id = DefineDeoptimizationLiteral(literal);
- translation.AddUpdateFeedback(literal_id, entry.feedback().slot().ToInt());
+ translation.AddUpdateFeedback(literal_id, entry.feedback().slot.ToInt());
}
InstructionOperandIterator iter(instr, frame_state_offset);
BuildTranslationForFrameStateDescriptor(descriptor, &iter, &translation,
state_combine);
- int deoptimization_id = static_cast<int>(deoptimization_states_.size());
+ DeoptimizationExit* const exit = new (zone()) DeoptimizationExit(
+ current_source_position_, descriptor->bailout_id(), translation.index(),
+ pc_offset, entry.kind(), entry.reason());
- deoptimization_states_.push_back(new (zone()) DeoptimizationState(
- descriptor->bailout_id(), translation.index(), pc_offset, entry.kind(),
- entry.reason()));
+ if (!Deoptimizer::kSupportsFixedDeoptExitSize) {
+ exit->set_deoptimization_id(next_deoptimization_id_++);
+ }
- return deoptimization_id;
+ deoptimization_exits_.push_back(exit);
+ return exit;
}
void CodeGenerator::AddTranslationForOperand(Translation* translation,
@@ -1236,13 +1243,8 @@ void CodeGenerator::MarkLazyDeoptSite() {
DeoptimizationExit* CodeGenerator::AddDeoptimizationExit(
Instruction* instr, size_t frame_state_offset) {
- int const deoptimization_id = BuildTranslation(
- instr, -1, frame_state_offset, OutputFrameStateCombine::Ignore());
-
- DeoptimizationExit* const exit = new (zone())
- DeoptimizationExit(deoptimization_id, current_source_position_);
- deoptimization_exits_.push_back(exit);
- return exit;
+ return BuildTranslation(instr, -1, frame_state_offset,
+ OutputFrameStateCombine::Ignore());
}
void CodeGenerator::InitializeSpeculationPoison() {
diff --git a/deps/v8/src/compiler/backend/code-generator.h b/deps/v8/src/compiler/backend/code-generator.h
index 74dd90c5de..e9ebf67590 100644
--- a/deps/v8/src/compiler/backend/code-generator.h
+++ b/deps/v8/src/compiler/backend/code-generator.h
@@ -85,6 +85,25 @@ class DeoptimizationLiteral {
const StringConstantBase* string_ = nullptr;
};
+// These structs hold pc offsets for generated instructions and is only used
+// when tracing for turbolizer is enabled.
+struct TurbolizerCodeOffsetsInfo {
+ int code_start_register_check = -1;
+ int deopt_check = -1;
+ int init_poison = -1;
+ int blocks_start = -1;
+ int out_of_line_code = -1;
+ int deoptimization_exits = -1;
+ int pools = -1;
+ int jump_tables = -1;
+};
+
+struct TurbolizerInstructionStartInfo {
+ int gap_pc_offset = -1;
+ int arch_instr_pc_offset = -1;
+ int condition_pc_offset = -1;
+};
+
// Generates native code for a sequence of instructions.
class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
public:
@@ -96,6 +115,7 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
JumpOptimizationInfo* jump_opt,
PoisoningMitigationLevel poisoning_level,
const AssemblerOptions& options, int32_t builtin_index,
+ size_t max_unoptimized_frame_height,
std::unique_ptr<AssemblerBuffer> = {});
// Generate native code. After calling AssembleCode, call FinalizeCode to
@@ -139,7 +159,13 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
size_t GetHandlerTableOffset() const { return handler_table_offset_; }
const ZoneVector<int>& block_starts() const { return block_starts_; }
- const ZoneVector<int>& instr_starts() const { return instr_starts_; }
+ const ZoneVector<TurbolizerInstructionStartInfo>& instr_starts() const {
+ return instr_starts_;
+ }
+
+ const TurbolizerCodeOffsetsInfo& offsets_info() const {
+ return offsets_info_;
+ }
static constexpr int kBinarySearchSwitchMinimalCases = 4;
@@ -182,7 +208,7 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
void GenerateSpeculationPoisonFromCodeStartRegister();
// Assemble code for the specified instruction.
- CodeGenResult AssembleInstruction(Instruction* instr,
+ CodeGenResult AssembleInstruction(int instruction_index,
const InstructionBlock* block);
void AssembleGaps(Instruction* instr);
@@ -199,8 +225,7 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
// Determines how to call helper stubs depending on the code kind.
StubCallMode DetermineStubCallMode() const;
- CodeGenResult AssembleDeoptimizerCall(int deoptimization_id,
- SourcePosition pos);
+ CodeGenResult AssembleDeoptimizerCall(DeoptimizationExit* exit);
// ===========================================================================
// ============= Architecture-specific code generation methods. ==============
@@ -342,11 +367,9 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
int DefineDeoptimizationLiteral(DeoptimizationLiteral literal);
DeoptimizationEntry const& GetDeoptimizationEntry(Instruction* instr,
size_t frame_state_offset);
- DeoptimizeKind GetDeoptimizationKind(int deoptimization_id) const;
- DeoptimizeReason GetDeoptimizationReason(int deoptimization_id) const;
- int BuildTranslation(Instruction* instr, int pc_offset,
- size_t frame_state_offset,
- OutputFrameStateCombine state_combine);
+ DeoptimizationExit* BuildTranslation(Instruction* instr, int pc_offset,
+ size_t frame_state_offset,
+ OutputFrameStateCombine state_combine);
void BuildTranslationForFrameStateDescriptor(
FrameStateDescriptor* descriptor, InstructionOperandIterator* iter,
Translation* translation, OutputFrameStateCombine state_combine);
@@ -361,35 +384,12 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
InstructionOperand* op, MachineType type);
void MarkLazyDeoptSite();
+ void PrepareForDeoptimizationExits(int deopt_count);
DeoptimizationExit* AddDeoptimizationExit(Instruction* instr,
size_t frame_state_offset);
// ===========================================================================
- class DeoptimizationState final : public ZoneObject {
- public:
- DeoptimizationState(BailoutId bailout_id, int translation_id, int pc_offset,
- DeoptimizeKind kind, DeoptimizeReason reason)
- : bailout_id_(bailout_id),
- translation_id_(translation_id),
- pc_offset_(pc_offset),
- kind_(kind),
- reason_(reason) {}
-
- BailoutId bailout_id() const { return bailout_id_; }
- int translation_id() const { return translation_id_; }
- int pc_offset() const { return pc_offset_; }
- DeoptimizeKind kind() const { return kind_; }
- DeoptimizeReason reason() const { return reason_; }
-
- private:
- BailoutId bailout_id_;
- int translation_id_;
- int pc_offset_;
- DeoptimizeKind kind_;
- DeoptimizeReason reason_;
- };
-
struct HandlerInfo {
Label* handler;
int pc_offset;
@@ -414,14 +414,19 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
GapResolver resolver_;
SafepointTableBuilder safepoints_;
ZoneVector<HandlerInfo> handlers_;
+ int next_deoptimization_id_ = 0;
+ int deopt_exit_start_offset_ = 0;
ZoneDeque<DeoptimizationExit*> deoptimization_exits_;
- ZoneDeque<DeoptimizationState*> deoptimization_states_;
ZoneDeque<DeoptimizationLiteral> deoptimization_literals_;
size_t inlined_function_count_ = 0;
TranslationBuffer translations_;
int handler_table_offset_ = 0;
int last_lazy_deopt_pc_ = 0;
+ // The maximal combined height of all frames produced upon deoptimization.
+ // Applied as an offset to the first stack check of an optimized function.
+ const size_t max_unoptimized_frame_height_;
+
// kArchCallCFunction could be reached either:
// kArchCallCFunction;
// or:
@@ -444,7 +449,8 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
CodeGenResult result_;
PoisoningMitigationLevel poisoning_level_;
ZoneVector<int> block_starts_;
- ZoneVector<int> instr_starts_;
+ TurbolizerCodeOffsetsInfo offsets_info_;
+ ZoneVector<TurbolizerInstructionStartInfo> instr_starts_;
};
} // namespace compiler
diff --git a/deps/v8/src/compiler/backend/frame-elider.cc b/deps/v8/src/compiler/backend/frame-elider.cc
index 2167d0abaa..064501b097 100644
--- a/deps/v8/src/compiler/backend/frame-elider.cc
+++ b/deps/v8/src/compiler/backend/frame-elider.cc
@@ -24,7 +24,7 @@ void FrameElider::MarkBlocks() {
for (int i = block->code_start(); i < block->code_end(); ++i) {
const Instruction* instr = InstructionAt(i);
if (instr->IsCall() || instr->IsDeoptimizeCall() ||
- instr->arch_opcode() == ArchOpcode::kArchStackPointer ||
+ instr->arch_opcode() == ArchOpcode::kArchStackPointerGreaterThan ||
instr->arch_opcode() == ArchOpcode::kArchFramePointer) {
block->mark_needs_frame();
break;
diff --git a/deps/v8/src/compiler/backend/ia32/code-generator-ia32.cc b/deps/v8/src/compiler/backend/ia32/code-generator-ia32.cc
index ed4be7a47c..4542da643b 100644
--- a/deps/v8/src/compiler/backend/ia32/code-generator-ia32.cc
+++ b/deps/v8/src/compiler/backend/ia32/code-generator-ia32.cc
@@ -165,6 +165,11 @@ class IA32OperandConverter : public InstructionOperandConverter {
Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset)));
return Operand(ctant.ToInt32(), ctant.rmode());
}
+ case kMode_Root: {
+ Register base = kRootRegister;
+ int32_t disp = InputInt32(NextOffset(offset));
+ return Operand(base, disp);
+ }
case kMode_None:
UNREACHABLE();
}
@@ -205,10 +210,18 @@ class IA32OperandConverter : public InstructionOperandConverter {
namespace {
+bool HasAddressingMode(Instruction* instr) {
+ return instr->addressing_mode() != kMode_None;
+}
+
bool HasImmediateInput(Instruction* instr, size_t index) {
return instr->InputAt(index)->IsImmediate();
}
+bool HasRegisterInput(Instruction* instr, size_t index) {
+ return instr->InputAt(index)->IsRegister();
+}
+
class OutOfLineLoadFloat32NaN final : public OutOfLineCode {
public:
OutOfLineLoadFloat32NaN(CodeGenerator* gen, XMMRegister result)
@@ -256,6 +269,8 @@ class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
// Just encode the stub index. This will be patched when the code
// is added to the native module and copied into wasm code space.
__ wasm_call(wasm::WasmCode::kDoubleToI, RelocInfo::WASM_STUB_CALL);
+ } else if (tasm()->options().inline_offheap_trampolines) {
+ __ CallBuiltin(Builtins::kDoubleToI);
} else {
__ Call(BUILTIN_CODE(isolate_, DoubleToI), RelocInfo::CODE_TARGET);
}
@@ -326,31 +341,31 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
} // namespace
-#define ASSEMBLE_COMPARE(asm_instr) \
- do { \
- if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \
- size_t index = 0; \
- Operand left = i.MemoryOperand(&index); \
- if (HasImmediateInput(instr, index)) { \
- __ asm_instr(left, i.InputImmediate(index)); \
- } else { \
- __ asm_instr(left, i.InputRegister(index)); \
- } \
- } else { \
- if (HasImmediateInput(instr, 1)) { \
- if (instr->InputAt(0)->IsRegister()) { \
- __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
- } else { \
- __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
- } \
- } else { \
- if (instr->InputAt(1)->IsRegister()) { \
- __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
- } else { \
- __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
- } \
- } \
- } \
+#define ASSEMBLE_COMPARE(asm_instr) \
+ do { \
+ if (HasAddressingMode(instr)) { \
+ size_t index = 0; \
+ Operand left = i.MemoryOperand(&index); \
+ if (HasImmediateInput(instr, index)) { \
+ __ asm_instr(left, i.InputImmediate(index)); \
+ } else { \
+ __ asm_instr(left, i.InputRegister(index)); \
+ } \
+ } else { \
+ if (HasImmediateInput(instr, 1)) { \
+ if (HasRegisterInput(instr, 0)) { \
+ __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
+ } else { \
+ __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
+ } \
+ } else { \
+ if (HasRegisterInput(instr, 1)) { \
+ __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
+ } else { \
+ __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
+ } \
+ } \
+ } \
} while (0)
#define ASSEMBLE_IEEE754_BINOP(name) \
@@ -382,19 +397,19 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
__ add(esp, Immediate(kDoubleSize)); \
} while (false)
-#define ASSEMBLE_BINOP(asm_instr) \
- do { \
- if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \
- size_t index = 1; \
- Operand right = i.MemoryOperand(&index); \
- __ asm_instr(i.InputRegister(0), right); \
- } else { \
- if (HasImmediateInput(instr, 1)) { \
- __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
- } else { \
- __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
- } \
- } \
+#define ASSEMBLE_BINOP(asm_instr) \
+ do { \
+ if (HasAddressingMode(instr)) { \
+ size_t index = 1; \
+ Operand right = i.MemoryOperand(&index); \
+ __ asm_instr(i.InputRegister(0), right); \
+ } else { \
+ if (HasImmediateInput(instr, 1)) { \
+ __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
+ } else { \
+ __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
+ } \
+ } \
} while (0)
#define ASSEMBLE_ATOMIC_BINOP(bin_inst, mov_inst, cmpxchg_inst) \
@@ -431,9 +446,9 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
#define ASSEMBLE_MOVX(mov_instr) \
do { \
- if (instr->addressing_mode() != kMode_None) { \
+ if (HasAddressingMode(instr)) { \
__ mov_instr(i.OutputRegister(), i.MemoryOperand()); \
- } else if (instr->InputAt(0)->IsRegister()) { \
+ } else if (HasRegisterInput(instr, 0)) { \
__ mov_instr(i.OutputRegister(), i.InputRegister(0)); \
} else { \
__ mov_instr(i.OutputRegister(), i.InputOperand(0)); \
@@ -905,19 +920,15 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// don't emit code for nops.
break;
case kArchDeoptimize: {
- int deopt_state_id =
+ DeoptimizationExit* exit =
BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
- CodeGenResult result =
- AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
+ CodeGenResult result = AssembleDeoptimizerCall(exit);
if (result != kSuccess) return result;
break;
}
case kArchRet:
AssembleReturn(instr->InputAt(0));
break;
- case kArchStackPointer:
- __ mov(i.OutputRegister(), esp);
- break;
case kArchFramePointer:
__ mov(i.OutputRegister(), ebp);
break;
@@ -928,6 +939,15 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ mov(i.OutputRegister(), ebp);
}
break;
+ case kArchStackPointerGreaterThan: {
+ constexpr size_t kValueIndex = 0;
+ if (HasAddressingMode(instr)) {
+ __ cmp(esp, i.MemoryOperand(kValueIndex));
+ } else {
+ __ cmp(esp, i.InputRegister(kValueIndex));
+ }
+ break;
+ }
case kArchTruncateDoubleToI: {
auto result = i.OutputRegister();
auto input = i.InputDoubleRegister(0);
@@ -1115,7 +1135,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// i.InputRegister(2) ... right low word.
// i.InputRegister(3) ... right high word.
bool use_temp = false;
- if ((instr->InputAt(1)->IsRegister() &&
+ if ((HasRegisterInput(instr, 1) &&
i.OutputRegister(0).code() == i.InputRegister(1).code()) ||
i.OutputRegister(0).code() == i.InputRegister(3).code()) {
// We cannot write to the output register directly, because it would
@@ -1140,7 +1160,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// i.InputRegister(2) ... right low word.
// i.InputRegister(3) ... right high word.
bool use_temp = false;
- if ((instr->InputAt(1)->IsRegister() &&
+ if ((HasRegisterInput(instr, 1) &&
i.OutputRegister(0).code() == i.InputRegister(1).code()) ||
i.OutputRegister(0).code() == i.InputRegister(3).code()) {
// We cannot write to the output register directly, because it would
@@ -1671,7 +1691,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
break;
case kIA32BitcastIF:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ movd(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ movss(i.OutputDoubleRegister(), i.InputOperand(0));
@@ -1762,7 +1782,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
frame_access_state()->IncreaseSPDelta(kSimd128Size / kSystemPointerSize);
break;
case kIA32Push:
- if (AddressingModeField::decode(instr->opcode()) != kMode_None) {
+ if (HasAddressingMode(instr)) {
size_t index = 0;
Operand operand = i.MemoryOperand(&index);
__ push(operand);
@@ -1984,6 +2004,17 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputOperand(1));
break;
}
+ case kSSEF32x4Div: {
+ DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
+ __ divps(i.OutputSimd128Register(), i.InputOperand(1));
+ break;
+ }
+ case kAVXF32x4Div: {
+ CpuFeatureScope avx_scope(tasm(), AVX);
+ __ vdivps(i.OutputSimd128Register(), i.InputSimd128Register(0),
+ i.InputOperand(1));
+ break;
+ }
case kSSEF32x4Min: {
XMMRegister src1 = i.InputSimd128Register(1),
dst = i.OutputSimd128Register();
@@ -2180,24 +2211,30 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kSSEI32x4Shl: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
- __ pslld(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ pslld(i.OutputSimd128Register(), tmp);
break;
}
case kAVXI32x4Shl: {
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpslld(i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ vpslld(i.OutputSimd128Register(), i.InputSimd128Register(0), tmp);
break;
}
case kSSEI32x4ShrS: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
- __ psrad(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ psrad(i.OutputSimd128Register(), tmp);
break;
}
case kAVXI32x4ShrS: {
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpsrad(i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ vpsrad(i.OutputSimd128Register(), i.InputSimd128Register(0), tmp);
break;
}
case kSSEI32x4Add: {
@@ -2329,7 +2366,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
CpuFeatureScope sse_scope(tasm(), SSE4_1);
XMMRegister dst = i.OutputSimd128Register();
- XMMRegister tmp = i.ToSimd128Register(instr->TempAt(0));
+ XMMRegister tmp = i.TempSimd128Register(0);
// NAN->0, negative->0
__ pxor(kScratchDoubleReg, kScratchDoubleReg);
__ maxps(dst, kScratchDoubleReg);
@@ -2357,7 +2394,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
CpuFeatureScope avx_scope(tasm(), AVX);
XMMRegister dst = i.OutputSimd128Register();
- XMMRegister tmp = i.ToSimd128Register(instr->TempAt(0));
+ XMMRegister tmp = i.TempSimd128Register(0);
// NAN->0, negative->0
__ vpxor(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
__ vmaxps(dst, dst, kScratchDoubleReg);
@@ -2392,13 +2429,16 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kSSEI32x4ShrU: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
- __ psrld(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ psrld(i.OutputSimd128Register(), tmp);
break;
}
case kAVXI32x4ShrU: {
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpsrld(i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ vpsrld(i.OutputSimd128Register(), i.InputSimd128Register(0), tmp);
break;
}
case kSSEI32x4MinU: {
@@ -2512,24 +2552,30 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kSSEI16x8Shl: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
- __ psllw(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ psllw(i.OutputSimd128Register(), tmp);
break;
}
case kAVXI16x8Shl: {
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpsllw(i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ vpsllw(i.OutputSimd128Register(), i.InputSimd128Register(0), tmp);
break;
}
case kSSEI16x8ShrS: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
- __ psraw(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ psraw(i.OutputSimd128Register(), tmp);
break;
}
case kAVXI16x8ShrS: {
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpsraw(i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ vpsraw(i.OutputSimd128Register(), i.InputSimd128Register(0), tmp);
break;
}
case kSSEI16x8SConvertI32x4: {
@@ -2698,13 +2744,16 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kSSEI16x8ShrU: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
- __ psrlw(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ psrlw(i.OutputSimd128Register(), tmp);
break;
}
case kAVXI16x8ShrU: {
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpsrlw(i.OutputSimd128Register(), i.InputSimd128Register(0),
- i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movd(tmp, i.InputRegister(1));
+ __ vpsrlw(i.OutputSimd128Register(), i.InputSimd128Register(0), tmp);
break;
}
case kSSEI16x8UConvertI32x4: {
@@ -2867,53 +2916,54 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kSSEI8x16Shl: {
XMMRegister dst = i.OutputSimd128Register();
DCHECK_EQ(dst, i.InputSimd128Register(0));
- int8_t shift = i.InputInt8(1) & 0x7;
- if (shift < 4) {
- // For small shifts, doubling is faster.
- for (int i = 0; i < shift; ++i) {
- __ paddb(dst, dst);
- }
- } else {
- // Mask off the unwanted bits before word-shifting.
- __ pcmpeqw(kScratchDoubleReg, kScratchDoubleReg);
- __ psrlw(kScratchDoubleReg, 8 + shift);
- __ packuswb(kScratchDoubleReg, kScratchDoubleReg);
- __ pand(dst, kScratchDoubleReg);
- __ psllw(dst, shift);
- }
+ Register shift = i.InputRegister(1);
+ Register tmp = i.ToRegister(instr->TempAt(0));
+ XMMRegister tmp_simd = i.TempSimd128Register(1);
+ // Mask off the unwanted bits before word-shifting.
+ __ pcmpeqw(kScratchDoubleReg, kScratchDoubleReg);
+ __ mov(tmp, shift);
+ __ add(tmp, Immediate(8));
+ __ movd(tmp_simd, tmp);
+ __ psrlw(kScratchDoubleReg, tmp_simd);
+ __ packuswb(kScratchDoubleReg, kScratchDoubleReg);
+ __ pand(dst, kScratchDoubleReg);
+ __ movd(tmp_simd, shift);
+ __ psllw(dst, tmp_simd);
break;
}
case kAVXI8x16Shl: {
CpuFeatureScope avx_scope(tasm(), AVX);
XMMRegister dst = i.OutputSimd128Register();
XMMRegister src = i.InputSimd128Register(0);
- int8_t shift = i.InputInt8(1) & 0x7;
- if (shift < 4) {
- // For small shifts, doubling is faster.
- for (int i = 0; i < shift; ++i) {
- __ vpaddb(dst, src, src);
- src = dst;
- }
- } else {
- // Mask off the unwanted bits before word-shifting.
- __ vpcmpeqw(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
- __ vpsrlw(kScratchDoubleReg, kScratchDoubleReg, 8 + shift);
- __ vpackuswb(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
- __ vpand(dst, src, kScratchDoubleReg);
- __ vpsllw(dst, dst, shift);
- }
+ Register shift = i.InputRegister(1);
+ Register tmp = i.ToRegister(instr->TempAt(0));
+ XMMRegister tmp_simd = i.TempSimd128Register(1);
+ // Mask off the unwanted bits before word-shifting.
+ __ vpcmpeqw(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
+ __ mov(tmp, shift);
+ __ add(tmp, Immediate(8));
+ __ movd(tmp_simd, tmp);
+ __ vpsrlw(kScratchDoubleReg, kScratchDoubleReg, tmp_simd);
+ __ vpackuswb(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
+ __ vpand(dst, src, kScratchDoubleReg);
+ __ movd(tmp_simd, shift);
+ __ vpsllw(dst, dst, tmp_simd);
break;
}
case kIA32I8x16ShrS: {
XMMRegister dst = i.OutputSimd128Register();
- XMMRegister src = i.InputSimd128Register(0);
- int8_t shift = i.InputInt8(1) & 0x7;
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ Register tmp = i.ToRegister(instr->TempAt(0));
+ XMMRegister tmp_simd = i.TempSimd128Register(1);
// Unpack the bytes into words, do arithmetic shifts, and repack.
- __ Punpckhbw(kScratchDoubleReg, src);
- __ Punpcklbw(dst, src);
- __ Psraw(kScratchDoubleReg, 8 + shift);
- __ Psraw(dst, 8 + shift);
- __ Packsswb(dst, kScratchDoubleReg);
+ __ punpckhbw(kScratchDoubleReg, dst);
+ __ punpcklbw(dst, dst);
+ __ mov(tmp, i.InputRegister(1));
+ __ add(tmp, Immediate(8));
+ __ movd(tmp_simd, tmp);
+ __ psraw(kScratchDoubleReg, tmp_simd);
+ __ psraw(dst, tmp_simd);
+ __ packsswb(dst, kScratchDoubleReg);
break;
}
case kSSEI8x16Add: {
@@ -2964,7 +3014,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
XMMRegister dst = i.OutputSimd128Register();
DCHECK_EQ(dst, i.InputSimd128Register(0));
XMMRegister right = i.InputSimd128Register(1);
- XMMRegister tmp = i.ToSimd128Register(instr->TempAt(0));
+ XMMRegister tmp = i.TempSimd128Register(0);
// I16x8 view of I8x16
// left = AAaa AAaa ... AAaa AAaa
@@ -3004,7 +3054,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
XMMRegister dst = i.OutputSimd128Register();
XMMRegister left = i.InputSimd128Register(0);
XMMRegister right = i.InputSimd128Register(1);
- XMMRegister tmp = i.ToSimd128Register(instr->TempAt(0));
+ XMMRegister tmp = i.TempSimd128Register(0);
// I16x8 view of I8x16
// left = AAaa AAaa ... AAaa AAaa
@@ -3165,15 +3215,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kIA32I8x16ShrU: {
+ DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
XMMRegister dst = i.OutputSimd128Register();
- XMMRegister src = i.InputSimd128Register(0);
- int8_t shift = i.InputInt8(1) & 0x7;
+ Register tmp = i.ToRegister(instr->TempAt(0));
+ XMMRegister tmp_simd = i.TempSimd128Register(1);
// Unpack the bytes into words, do logical shifts, and repack.
- __ Punpckhbw(kScratchDoubleReg, src);
- __ Punpcklbw(dst, src);
- __ Psrlw(kScratchDoubleReg, 8 + shift);
- __ Psrlw(dst, 8 + shift);
- __ Packuswb(dst, kScratchDoubleReg);
+ __ punpckhbw(kScratchDoubleReg, dst);
+ __ punpcklbw(dst, dst);
+ __ mov(tmp, i.InputRegister(1));
+ __ add(tmp, Immediate(8));
+ __ movd(tmp_simd, tmp);
+ __ psrlw(kScratchDoubleReg, tmp_simd);
+ __ psrlw(dst, tmp_simd);
+ __ packuswb(dst, kScratchDoubleReg);
break;
}
case kSSEI8x16MinU: {
@@ -3693,10 +3747,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ASSEMBLE_SIMD_ALL_TRUE(pcmpeqb);
break;
}
- case kIA32StackCheck: {
- __ CompareStackLimit(esp);
- break;
- }
case kIA32Word32AtomicPairLoad: {
XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
__ movq(tmp, i.MemoryOperand());
@@ -4402,6 +4452,8 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::FinishCode() {}
+void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {}
+
void CodeGenerator::AssembleMove(InstructionOperand* source,
InstructionOperand* destination) {
IA32OperandConverter g(this, nullptr);
diff --git a/deps/v8/src/compiler/backend/ia32/instruction-codes-ia32.h b/deps/v8/src/compiler/backend/ia32/instruction-codes-ia32.h
index 56dea82fe2..7530c716b8 100644
--- a/deps/v8/src/compiler/backend/ia32/instruction-codes-ia32.h
+++ b/deps/v8/src/compiler/backend/ia32/instruction-codes-ia32.h
@@ -116,7 +116,6 @@ namespace compiler {
V(IA32PushSimd128) \
V(IA32Poke) \
V(IA32Peek) \
- V(IA32StackCheck) \
V(SSEF32x4Splat) \
V(AVXF32x4Splat) \
V(SSEF32x4ExtractLane) \
@@ -140,6 +139,8 @@ namespace compiler {
V(AVXF32x4Sub) \
V(SSEF32x4Mul) \
V(AVXF32x4Mul) \
+ V(SSEF32x4Div) \
+ V(AVXF32x4Div) \
V(SSEF32x4Min) \
V(AVXF32x4Min) \
V(SSEF32x4Max) \
@@ -394,7 +395,8 @@ namespace compiler {
V(M2I) /* [ %r2*2 + K] */ \
V(M4I) /* [ %r2*4 + K] */ \
V(M8I) /* [ %r2*8 + K] */ \
- V(MI) /* [ K] */
+ V(MI) /* [ K] */ \
+ V(Root) /* [%root + K] */
} // namespace compiler
} // namespace internal
diff --git a/deps/v8/src/compiler/backend/ia32/instruction-scheduler-ia32.cc b/deps/v8/src/compiler/backend/ia32/instruction-scheduler-ia32.cc
index 15f69b991c..c2097a6691 100644
--- a/deps/v8/src/compiler/backend/ia32/instruction-scheduler-ia32.cc
+++ b/deps/v8/src/compiler/backend/ia32/instruction-scheduler-ia32.cc
@@ -120,6 +120,8 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kAVXF32x4Sub:
case kSSEF32x4Mul:
case kAVXF32x4Mul:
+ case kSSEF32x4Div:
+ case kAVXF32x4Div:
case kSSEF32x4Min:
case kAVXF32x4Min:
case kSSEF32x4Max:
@@ -356,7 +358,6 @@ int InstructionScheduler::GetTargetInstructionFlags(
// Moves are used for memory load/store operations.
return instr->HasOutput() ? kIsLoadOperation : kHasSideEffect;
- case kIA32StackCheck:
case kIA32Peek:
return kIsLoadOperation;
diff --git a/deps/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc b/deps/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc
index e1fc66b4ba..ebef39a93a 100644
--- a/deps/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc
+++ b/deps/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc
@@ -152,6 +152,21 @@ class IA32OperandGenerator final : public OperandGenerator {
AddressingMode GetEffectiveAddressMemoryOperand(Node* node,
InstructionOperand inputs[],
size_t* input_count) {
+ {
+ LoadMatcher<ExternalReferenceMatcher> m(node);
+ if (m.index().HasValue() && m.object().HasValue() &&
+ selector()->CanAddressRelativeToRootsRegister(m.object().Value())) {
+ ptrdiff_t const delta =
+ m.index().Value() +
+ TurboAssemblerBase::RootRegisterOffsetForExternalReference(
+ selector()->isolate(), m.object().Value());
+ if (is_int32(delta)) {
+ inputs[(*input_count)++] = TempImmediate(static_cast<int32_t>(delta));
+ return kMode_Root;
+ }
+ }
+ }
+
BaseWithIndexAndDisplacement32Matcher m(node, AddressOption::kAllowAll);
DCHECK(m.matches());
if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
@@ -261,6 +276,31 @@ void VisitRRISimd(InstructionSelector* selector, Node* node,
}
}
+void VisitRROSimdShift(InstructionSelector* selector, Node* node,
+ ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
+ IA32OperandGenerator g(selector);
+ InstructionOperand operand0 = g.UseUniqueRegister(node->InputAt(0));
+ InstructionOperand operand1 = g.UseUniqueRegister(node->InputAt(1));
+ InstructionOperand temps[] = {g.TempSimd128Register()};
+ if (selector->IsSupported(AVX)) {
+ selector->Emit(avx_opcode, g.DefineAsRegister(node), operand0, operand1,
+ arraysize(temps), temps);
+ } else {
+ selector->Emit(sse_opcode, g.DefineSameAsFirst(node), operand0, operand1,
+ arraysize(temps), temps);
+ }
+}
+
+void VisitRROI8x16SimdRightShift(InstructionSelector* selector, Node* node,
+ ArchOpcode opcode) {
+ IA32OperandGenerator g(selector);
+ InstructionOperand operand0 = g.UseUniqueRegister(node->InputAt(0));
+ InstructionOperand operand1 = g.UseUniqueRegister(node->InputAt(1));
+ InstructionOperand temps[] = {g.TempRegister(), g.TempSimd128Register()};
+ selector->Emit(opcode, g.DefineSameAsFirst(node), operand0, operand1,
+ arraysize(temps), temps);
+}
+
} // namespace
void InstructionSelector::VisitStackSlot(Node* node) {
@@ -344,7 +384,8 @@ void InstructionSelector::VisitStore(Node* node) {
WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
MachineRepresentation rep = store_rep.representation();
- if (write_barrier_kind != kNoWriteBarrier) {
+ if (write_barrier_kind != kNoWriteBarrier &&
+ V8_LIKELY(!FLAG_disable_write_barriers)) {
DCHECK(CanBeTaggedPointer(rep));
AddressingMode addressing_mode;
InstructionOperand inputs[] = {
@@ -516,6 +557,35 @@ void InstructionSelector::VisitWord32Xor(Node* node) {
}
}
+void InstructionSelector::VisitStackPointerGreaterThan(
+ Node* node, FlagsContinuation* cont) {
+ Node* const value = node->InputAt(0);
+ InstructionCode opcode = kArchStackPointerGreaterThan;
+
+ DCHECK(cont->IsBranch());
+ const int effect_level =
+ GetEffectLevel(cont->true_block()->PredecessorAt(0)->control_input());
+
+ IA32OperandGenerator g(this);
+ if (g.CanBeMemoryOperand(kIA32Cmp, node, value, effect_level)) {
+ DCHECK_EQ(IrOpcode::kLoad, value->opcode());
+
+ // GetEffectiveAddressMemoryOperand can create at most 3 inputs.
+ static constexpr int kMaxInputCount = 3;
+
+ size_t input_count = 0;
+ InstructionOperand inputs[kMaxInputCount];
+ AddressingMode addressing_mode =
+ g.GetEffectiveAddressMemoryOperand(value, inputs, &input_count);
+ opcode |= AddressingModeField::encode(addressing_mode);
+ DCHECK_LE(input_count, kMaxInputCount);
+
+ EmitWithContinuation(opcode, 0, nullptr, input_count, inputs, cont);
+ } else {
+ EmitWithContinuation(opcode, g.UseRegister(value), cont);
+ }
+}
+
// Shared routine for multiple shift operations.
static inline void VisitShift(InstructionSelector* selector, Node* node,
ArchOpcode opcode) {
@@ -1243,30 +1313,6 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
void VisitWordCompare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
- if (selector->isolate() != nullptr) {
- StackCheckMatcher<Int32BinopMatcher, IrOpcode::kUint32LessThan> m(
- selector->isolate(), node);
- if (m.Matched()) {
- // Compare(Load(js_stack_limit), LoadStackPointer)
- if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
- InstructionCode opcode = cont->Encode(kIA32StackCheck);
- CHECK(cont->IsBranch());
- selector->EmitWithContinuation(opcode, cont);
- return;
- }
- }
- WasmStackCheckMatcher<Int32BinopMatcher, IrOpcode::kUint32LessThan> wasm_m(
- node);
- if (wasm_m.Matched()) {
- // This is a wasm stack check. By structure, we know that we can use the
- // stack pointer directly, as wasm code does not modify the stack at points
- // where stack checks are performed.
- Node* left = node->InputAt(0);
- LocationOperand esp(InstructionOperand::EXPLICIT, LocationOperand::REGISTER,
- InstructionSequence::DefaultRepresentation(),
- RegisterCode::kRegCode_esp);
- return VisitCompareWithMemoryOperand(selector, kIA32Cmp, left, esp, cont);
- }
VisitWordCompare(selector, node, kIA32Cmp, cont);
}
@@ -1433,6 +1479,9 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
return VisitWordCompare(this, value, cont);
case IrOpcode::kWord32And:
return VisitWordCompare(this, value, kIA32Test, cont);
+ case IrOpcode::kStackPointerGreaterThan:
+ cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
+ return VisitStackPointerGreaterThan(value, cont);
default:
break;
}
@@ -1842,6 +1891,7 @@ void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
V(F32x4AddHoriz) \
V(F32x4Sub) \
V(F32x4Mul) \
+ V(F32x4Div) \
V(F32x4Min) \
V(F32x4Max) \
V(F32x4Eq) \
@@ -1939,8 +1989,7 @@ void InstructionSelector::VisitWord32AtomicPairCompareExchange(Node* node) {
V(I32x4ShrU) \
V(I16x8Shl) \
V(I16x8ShrS) \
- V(I16x8ShrU) \
- V(I8x16Shl)
+ V(I16x8ShrU)
#define SIMD_I8X16_RIGHT_SHIFT_OPCODES(V) \
V(I8x16ShrS) \
@@ -2037,22 +2086,21 @@ VISIT_SIMD_REPLACE_LANE(F32x4)
#undef VISIT_SIMD_REPLACE_LANE
#undef SIMD_INT_TYPES
-#define VISIT_SIMD_SHIFT(Opcode) \
- void InstructionSelector::Visit##Opcode(Node* node) { \
- VisitRRISimd(this, node, kAVX##Opcode, kSSE##Opcode); \
+#define VISIT_SIMD_SHIFT(Opcode) \
+ void InstructionSelector::Visit##Opcode(Node* node) { \
+ VisitRROSimdShift(this, node, kAVX##Opcode, kSSE##Opcode); \
}
SIMD_SHIFT_OPCODES(VISIT_SIMD_SHIFT)
#undef VISIT_SIMD_SHIFT
#undef SIMD_SHIFT_OPCODES
-#define VISIT_SIMD_I8X16_RIGHT_SHIFT(Op) \
- void InstructionSelector::Visit##Op(Node* node) { \
- VisitRRISimd(this, node, kIA32##Op); \
+#define VISIT_SIMD_I8x16_RIGHT_SHIFT(Opcode) \
+ void InstructionSelector::Visit##Opcode(Node* node) { \
+ VisitRROI8x16SimdRightShift(this, node, kIA32##Opcode); \
}
-
-SIMD_I8X16_RIGHT_SHIFT_OPCODES(VISIT_SIMD_I8X16_RIGHT_SHIFT)
+SIMD_I8X16_RIGHT_SHIFT_OPCODES(VISIT_SIMD_I8x16_RIGHT_SHIFT)
#undef SIMD_I8X16_RIGHT_SHIFT_OPCODES
-#undef VISIT_SIMD_I8X16_RIGHT_SHIFT
+#undef VISIT_SIMD_I8x16_RIGHT_SHIFT
#define VISIT_SIMD_UNOP(Opcode) \
void InstructionSelector::Visit##Opcode(Node* node) { \
@@ -2123,6 +2171,20 @@ void InstructionSelector::VisitI8x16UConvertI16x8(Node* node) {
VisitPack(this, node, kAVXI8x16UConvertI16x8, kSSEI8x16UConvertI16x8);
}
+void InstructionSelector::VisitI8x16Shl(Node* node) {
+ IA32OperandGenerator g(this);
+ InstructionOperand operand0 = g.UseUniqueRegister(node->InputAt(0));
+ InstructionOperand operand1 = g.UseUniqueRegister(node->InputAt(1));
+ InstructionOperand temps[] = {g.TempRegister(), g.TempSimd128Register()};
+ if (IsSupported(AVX)) {
+ Emit(kAVXI8x16Shl, g.DefineAsRegister(node), operand0, operand1,
+ arraysize(temps), temps);
+ } else {
+ Emit(kSSEI8x16Shl, g.DefineSameAsFirst(node), operand0, operand1,
+ arraysize(temps), temps);
+ }
+}
+
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
@@ -2259,13 +2321,13 @@ static const ShuffleEntry arch_shuffles[] = {
{{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8},
kSSES8x8Reverse,
kAVXS8x8Reverse,
- false,
- false},
+ true,
+ true},
{{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
kSSES8x4Reverse,
kAVXS8x4Reverse,
- false,
- false},
+ true,
+ true},
{{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14},
kSSES8x2Reverse,
kAVXS8x2Reverse,
diff --git a/deps/v8/src/compiler/backend/instruction-codes.h b/deps/v8/src/compiler/backend/instruction-codes.h
index 1085de2196..589c1bda3b 100644
--- a/deps/v8/src/compiler/backend/instruction-codes.h
+++ b/deps/v8/src/compiler/backend/instruction-codes.h
@@ -88,13 +88,13 @@ inline RecordWriteMode WriteBarrierKindToRecordWriteMode(
V(ArchThrowTerminator) \
V(ArchDeoptimize) \
V(ArchRet) \
- V(ArchStackPointer) \
V(ArchFramePointer) \
V(ArchParentFramePointer) \
V(ArchTruncateDoubleToI) \
V(ArchStoreWithWriteBarrier) \
V(ArchStackSlot) \
V(ArchWordPoisonOnSpeculation) \
+ V(ArchStackPointerGreaterThan) \
V(Word32AtomicLoadInt8) \
V(Word32AtomicLoadUint8) \
V(Word32AtomicLoadInt16) \
@@ -238,6 +238,9 @@ enum FlagsCondition {
kNegative
};
+static constexpr FlagsCondition kStackPointerGreaterThanCondition =
+ kUnsignedGreaterThan;
+
inline FlagsCondition NegateFlagsCondition(FlagsCondition condition) {
return static_cast<FlagsCondition>(condition ^ 1);
}
diff --git a/deps/v8/src/compiler/backend/instruction-scheduler.cc b/deps/v8/src/compiler/backend/instruction-scheduler.cc
index 538af71bb4..dc66813740 100644
--- a/deps/v8/src/compiler/backend/instruction-scheduler.cc
+++ b/deps/v8/src/compiler/backend/instruction-scheduler.cc
@@ -275,9 +275,10 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
case kIeee754Float64Tanh:
return kNoOpcodeFlags;
- case kArchStackPointer:
- // ArchStackPointer instruction loads the current stack pointer value and
- // must not be reordered with instruction with side effects.
+ case kArchStackPointerGreaterThan:
+ // The ArchStackPointerGreaterThan instruction loads the current stack
+ // pointer value and must not be reordered with instructions with side
+ // effects.
return kIsLoadOperation;
case kArchWordPoisonOnSpeculation:
diff --git a/deps/v8/src/compiler/backend/instruction-selector.cc b/deps/v8/src/compiler/backend/instruction-selector.cc
index 11ba910405..43193ec2b1 100644
--- a/deps/v8/src/compiler/backend/instruction-selector.cc
+++ b/deps/v8/src/compiler/backend/instruction-selector.cc
@@ -26,6 +26,7 @@ InstructionSelector::InstructionSelector(
InstructionSequence* sequence, Schedule* schedule,
SourcePositionTable* source_positions, Frame* frame,
EnableSwitchJumpTable enable_switch_jump_table, TickCounter* tick_counter,
+ size_t* max_unoptimized_frame_height,
SourcePositionMode source_position_mode, Features features,
EnableScheduling enable_scheduling,
EnableRootsRelativeAddressing enable_roots_relative_addressing,
@@ -56,7 +57,10 @@ InstructionSelector::InstructionSelector(
instruction_selection_failed_(false),
instr_origins_(sequence->zone()),
trace_turbo_(trace_turbo),
- tick_counter_(tick_counter) {
+ tick_counter_(tick_counter),
+ max_unoptimized_frame_height_(max_unoptimized_frame_height) {
+ DCHECK_EQ(*max_unoptimized_frame_height, 0); // Caller-initialized.
+
instructions_.reserve(node_count);
continuation_inputs_.reserve(5);
continuation_outputs_.reserve(2);
@@ -421,9 +425,27 @@ void InstructionSelector::SetEffectLevel(Node* node, int effect_level) {
effect_level_[id] = effect_level;
}
-bool InstructionSelector::CanAddressRelativeToRootsRegister() const {
- return enable_roots_relative_addressing_ == kEnableRootsRelativeAddressing &&
- CanUseRootsRegister();
+bool InstructionSelector::CanAddressRelativeToRootsRegister(
+ const ExternalReference& reference) const {
+ // There are three things to consider here:
+ // 1. CanUseRootsRegister: Is kRootRegister initialized?
+ const bool root_register_is_available_and_initialized = CanUseRootsRegister();
+ if (!root_register_is_available_and_initialized) return false;
+
+ // 2. enable_roots_relative_addressing_: Can we address everything on the heap
+ // through the root register, i.e. are root-relative addresses to arbitrary
+ // addresses guaranteed not to change between code generation and
+ // execution?
+ const bool all_root_relative_offsets_are_constant =
+ (enable_roots_relative_addressing_ == kEnableRootsRelativeAddressing);
+ if (all_root_relative_offsets_are_constant) return true;
+
+ // 3. IsAddressableThroughRootRegister: Is the target address guaranteed to
+ // have a fixed root-relative offset? If so, we can ignore 2.
+ const bool this_root_relative_offset_is_constant =
+ TurboAssemblerBase::IsAddressableThroughRootRegister(isolate(),
+ reference);
+ return this_root_relative_offset_is_constant;
}
bool InstructionSelector::CanUseRootsRegister() const {
@@ -744,7 +766,7 @@ Instruction* InstructionSelector::EmitWithContinuation(
void InstructionSelector::AppendDeoptimizeArguments(
InstructionOperandVector* args, DeoptimizeKind kind,
- DeoptimizeReason reason, VectorSlotPair const& feedback,
+ DeoptimizeReason reason, FeedbackSource const& feedback,
Node* frame_state) {
OperandGenerator g(this);
FrameStateDescriptor* const descriptor = GetFrameStateDescriptor(frame_state);
@@ -761,7 +783,7 @@ void InstructionSelector::AppendDeoptimizeArguments(
Instruction* InstructionSelector::EmitDeoptimize(
InstructionCode opcode, size_t output_count, InstructionOperand* outputs,
size_t input_count, InstructionOperand* inputs, DeoptimizeKind kind,
- DeoptimizeReason reason, VectorSlotPair const& feedback,
+ DeoptimizeReason reason, FeedbackSource const& feedback,
Node* frame_state) {
InstructionOperandVector args(instruction_zone());
for (size_t i = 0; i < input_count; ++i) {
@@ -972,7 +994,7 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
int const state_id = sequence()->AddDeoptimizationEntry(
buffer->frame_state_descriptor, DeoptimizeKind::kLazy,
- DeoptimizeReason::kUnknown, VectorSlotPair());
+ DeoptimizeReason::kUnknown, FeedbackSource());
buffer->instruction_args.push_back(g.TempImmediate(state_id));
StateObjectDeduplicator deduplicator(instruction_zone());
@@ -1056,7 +1078,6 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
bool InstructionSelector::IsSourcePositionUsed(Node* node) {
return (source_position_mode_ == kAllSourcePositions ||
node->opcode() == IrOpcode::kCall ||
- node->opcode() == IrOpcode::kCallWithCallerSavedRegisters ||
node->opcode() == IrOpcode::kTrapIf ||
node->opcode() == IrOpcode::kTrapUnless ||
node->opcode() == IrOpcode::kProtectedLoad ||
@@ -1078,10 +1099,13 @@ void InstructionSelector::VisitBlock(BasicBlock* block) {
if (node->opcode() == IrOpcode::kStore ||
node->opcode() == IrOpcode::kUnalignedStore ||
node->opcode() == IrOpcode::kCall ||
- node->opcode() == IrOpcode::kCallWithCallerSavedRegisters ||
node->opcode() == IrOpcode::kProtectedLoad ||
node->opcode() == IrOpcode::kProtectedStore ||
- node->opcode() == IrOpcode::kMemoryBarrier) {
+#define ADD_EFFECT_FOR_ATOMIC_OP(Opcode) \
+ node->opcode() == IrOpcode::k##Opcode ||
+ MACHINE_ATOMIC_OP_LIST(ADD_EFFECT_FOR_ATOMIC_OP)
+#undef ADD_EFFECT_FOR_ATOMIC_OP
+ node->opcode() == IrOpcode::kMemoryBarrier) {
++effect_level;
}
}
@@ -1274,9 +1298,9 @@ void InstructionSelector::VisitNode(Node* node) {
// No code needed for these graph artifacts.
return;
case IrOpcode::kIfException:
- return MarkAsReference(node), VisitIfException(node);
+ return MarkAsTagged(node), VisitIfException(node);
case IrOpcode::kFinishRegion:
- return MarkAsReference(node), VisitFinishRegion(node);
+ return MarkAsTagged(node), VisitFinishRegion(node);
case IrOpcode::kParameter: {
MachineType type =
linkage()->GetParameterType(ParameterIndexOf(node->op()));
@@ -1284,7 +1308,7 @@ void InstructionSelector::VisitNode(Node* node) {
return VisitParameter(node);
}
case IrOpcode::kOsrValue:
- return MarkAsReference(node), VisitOsrValue(node);
+ return MarkAsTagged(node), VisitOsrValue(node);
case IrOpcode::kPhi: {
MachineRepresentation rep = PhiRepresentationOf(node->op());
if (rep == MachineRepresentation::kNone) return;
@@ -1304,20 +1328,18 @@ void InstructionSelector::VisitNode(Node* node) {
case IrOpcode::kFloat64Constant:
return MarkAsFloat64(node), VisitConstant(node);
case IrOpcode::kHeapConstant:
- return MarkAsReference(node), VisitConstant(node);
+ return MarkAsTagged(node), VisitConstant(node);
case IrOpcode::kCompressedHeapConstant:
return MarkAsCompressed(node), VisitConstant(node);
case IrOpcode::kNumberConstant: {
double value = OpParameter<double>(node->op());
- if (!IsSmiDouble(value)) MarkAsReference(node);
+ if (!IsSmiDouble(value)) MarkAsTagged(node);
return VisitConstant(node);
}
case IrOpcode::kDelayedStringConstant:
- return MarkAsReference(node), VisitConstant(node);
+ return MarkAsTagged(node), VisitConstant(node);
case IrOpcode::kCall:
return VisitCall(node);
- case IrOpcode::kCallWithCallerSavedRegisters:
- return VisitCallWithCallerSavedRegisters(node);
case IrOpcode::kDeoptimizeIf:
return VisitDeoptimizeIf(node);
case IrOpcode::kDeoptimizeUnless:
@@ -1484,10 +1506,16 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsRepresentation(MachineType::PointerRepresentation(), node),
VisitBitcastTaggedToWord(node);
case IrOpcode::kBitcastWordToTagged:
- return MarkAsReference(node), VisitBitcastWordToTagged(node);
+ return MarkAsTagged(node), VisitBitcastWordToTagged(node);
case IrOpcode::kBitcastWordToTaggedSigned:
return MarkAsRepresentation(MachineRepresentation::kTaggedSigned, node),
EmitIdentity(node);
+ case IrOpcode::kBitcastWord32ToCompressedSigned:
+ return MarkAsRepresentation(MachineRepresentation::kCompressedSigned,
+ node),
+ EmitIdentity(node);
+ case IrOpcode::kBitcastCompressedSignedToWord32:
+ return MarkAsWord32(node), EmitIdentity(node);
case IrOpcode::kChangeFloat32ToFloat64:
return MarkAsFloat64(node), VisitChangeFloat32ToFloat64(node);
case IrOpcode::kChangeInt32ToFloat64:
@@ -1536,18 +1564,20 @@ void InstructionSelector::VisitNode(Node* node) {
case IrOpcode::kChangeTaggedToCompressed:
return MarkAsCompressed(node), VisitChangeTaggedToCompressed(node);
case IrOpcode::kChangeTaggedPointerToCompressedPointer:
- return MarkAsCompressed(node),
+ return MarkAsRepresentation(MachineRepresentation::kCompressedPointer,
+ node),
VisitChangeTaggedPointerToCompressedPointer(node);
case IrOpcode::kChangeTaggedSignedToCompressedSigned:
- return MarkAsWord32(node),
+ return MarkAsRepresentation(MachineRepresentation::kCompressedSigned,
+ node),
VisitChangeTaggedSignedToCompressedSigned(node);
case IrOpcode::kChangeCompressedToTagged:
- return MarkAsReference(node), VisitChangeCompressedToTagged(node);
+ return MarkAsTagged(node), VisitChangeCompressedToTagged(node);
case IrOpcode::kChangeCompressedPointerToTaggedPointer:
- return MarkAsReference(node),
+ return MarkAsRepresentation(MachineRepresentation::kTaggedPointer, node),
VisitChangeCompressedPointerToTaggedPointer(node);
case IrOpcode::kChangeCompressedSignedToTaggedSigned:
- return MarkAsWord64(node),
+ return MarkAsRepresentation(MachineRepresentation::kTaggedSigned, node),
VisitChangeCompressedSignedToTaggedSigned(node);
#endif
case IrOpcode::kTruncateFloat64ToFloat32:
@@ -1697,15 +1727,15 @@ void InstructionSelector::VisitNode(Node* node) {
case IrOpcode::kFloat64InsertHighWord32:
return MarkAsFloat64(node), VisitFloat64InsertHighWord32(node);
case IrOpcode::kTaggedPoisonOnSpeculation:
- return MarkAsReference(node), VisitTaggedPoisonOnSpeculation(node);
+ return MarkAsTagged(node), VisitTaggedPoisonOnSpeculation(node);
case IrOpcode::kWord32PoisonOnSpeculation:
return MarkAsWord32(node), VisitWord32PoisonOnSpeculation(node);
case IrOpcode::kWord64PoisonOnSpeculation:
return MarkAsWord64(node), VisitWord64PoisonOnSpeculation(node);
case IrOpcode::kStackSlot:
return VisitStackSlot(node);
- case IrOpcode::kLoadStackPointer:
- return VisitLoadStackPointer(node);
+ case IrOpcode::kStackPointerGreaterThan:
+ return VisitStackPointerGreaterThan(node);
case IrOpcode::kLoadFramePointer:
return VisitLoadFramePointer(node);
case IrOpcode::kLoadParentFramePointer:
@@ -1827,6 +1857,18 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsSimd128(node), VisitF64x2Abs(node);
case IrOpcode::kF64x2Neg:
return MarkAsSimd128(node), VisitF64x2Neg(node);
+ case IrOpcode::kF64x2Add:
+ return MarkAsSimd128(node), VisitF64x2Add(node);
+ case IrOpcode::kF64x2Sub:
+ return MarkAsSimd128(node), VisitF64x2Sub(node);
+ case IrOpcode::kF64x2Mul:
+ return MarkAsSimd128(node), VisitF64x2Mul(node);
+ case IrOpcode::kF64x2Div:
+ return MarkAsSimd128(node), VisitF64x2Div(node);
+ case IrOpcode::kF64x2Min:
+ return MarkAsSimd128(node), VisitF64x2Min(node);
+ case IrOpcode::kF64x2Max:
+ return MarkAsSimd128(node), VisitF64x2Max(node);
case IrOpcode::kF64x2Eq:
return MarkAsSimd128(node), VisitF64x2Eq(node);
case IrOpcode::kF64x2Ne:
@@ -1861,6 +1903,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsSimd128(node), VisitF32x4Sub(node);
case IrOpcode::kF32x4Mul:
return MarkAsSimd128(node), VisitF32x4Mul(node);
+ case IrOpcode::kF32x4Div:
+ return MarkAsSimd128(node), VisitF32x4Div(node);
case IrOpcode::kF32x4Min:
return MarkAsSimd128(node), VisitF32x4Min(node);
case IrOpcode::kF32x4Max:
@@ -1891,6 +1935,10 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsSimd128(node), VisitI64x2Sub(node);
case IrOpcode::kI64x2Mul:
return MarkAsSimd128(node), VisitI64x2Mul(node);
+ case IrOpcode::kI64x2MinS:
+ return MarkAsSimd128(node), VisitI64x2MinS(node);
+ case IrOpcode::kI64x2MaxS:
+ return MarkAsSimd128(node), VisitI64x2MaxS(node);
case IrOpcode::kI64x2Eq:
return MarkAsSimd128(node), VisitI64x2Eq(node);
case IrOpcode::kI64x2Ne:
@@ -1901,6 +1949,10 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsSimd128(node), VisitI64x2GeS(node);
case IrOpcode::kI64x2ShrU:
return MarkAsSimd128(node), VisitI64x2ShrU(node);
+ case IrOpcode::kI64x2MinU:
+ return MarkAsSimd128(node), VisitI64x2MinU(node);
+ case IrOpcode::kI64x2MaxU:
+ return MarkAsSimd128(node), VisitI64x2MaxU(node);
case IrOpcode::kI64x2GtU:
return MarkAsSimd128(node), VisitI64x2GtU(node);
case IrOpcode::kI64x2GeU:
@@ -2134,9 +2186,10 @@ void InstructionSelector::VisitTaggedPoisonOnSpeculation(Node* node) {
EmitWordPoisonOnSpeculation(node);
}
-void InstructionSelector::VisitLoadStackPointer(Node* node) {
- OperandGenerator g(this);
- Emit(kArchStackPointer, g.DefineAsRegister(node));
+void InstructionSelector::VisitStackPointerGreaterThan(Node* node) {
+ FlagsContinuation cont =
+ FlagsContinuation::ForSet(kStackPointerGreaterThanCondition, node);
+ VisitStackPointerGreaterThan(node, &cont);
}
void InstructionSelector::VisitLoadFramePointer(Node* node) {
@@ -2553,11 +2606,18 @@ void InstructionSelector::VisitWord64AtomicCompareExchange(Node* node) {
// !V8_TARGET_ARCH_MIPS64 && !V8_TARGET_ARCH_S390
#if !V8_TARGET_ARCH_X64
+#if !V8_TARGET_ARCH_ARM64
void InstructionSelector::VisitF64x2Splat(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2ExtractLane(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2ReplaceLane(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2Abs(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2Neg(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitF64x2Add(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitF64x2Sub(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitF64x2Mul(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitF64x2Div(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitF64x2Min(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitF64x2Max(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2Eq(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2Ne(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF64x2Lt(Node* node) { UNIMPLEMENTED(); }
@@ -2566,20 +2626,25 @@ void InstructionSelector::VisitI64x2Splat(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2ExtractLane(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2ReplaceLane(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2Neg(Node* node) { UNIMPLEMENTED(); }
-void InstructionSelector::VisitS1x2AnyTrue(Node* node) { UNIMPLEMENTED(); }
-void InstructionSelector::VisitS1x2AllTrue(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2Shl(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2ShrS(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2Add(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2Sub(Node* node) { UNIMPLEMENTED(); }
-void InstructionSelector::VisitI64x2Mul(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2Eq(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2Ne(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitI64x2ShrU(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2GtS(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2GeS(Node* node) { UNIMPLEMENTED(); }
-void InstructionSelector::VisitI64x2ShrU(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2GtU(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitI64x2GeU(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitS1x2AnyTrue(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitS1x2AllTrue(Node* node) { UNIMPLEMENTED(); }
+#endif // !V8_TARGET_ARCH_ARM64
+void InstructionSelector::VisitI64x2Mul(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitI64x2MinS(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitI64x2MaxS(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitI64x2MinU(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitI64x2MaxU(Node* node) { UNIMPLEMENTED(); }
#endif // !V8_TARGET_ARCH_X64
void InstructionSelector::VisitFinishRegion(Node* node) { EmitIdentity(node); }
@@ -2677,6 +2742,12 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
OperandGenerator g(this);
auto call_descriptor = CallDescriptorOf(node->op());
+ if (call_descriptor->NeedsCallerSavedRegisters()) {
+ Emit(kArchSaveCallerRegisters | MiscField::encode(static_cast<int>(
+ call_descriptor->get_save_fp_mode())),
+ g.NoOutput());
+ }
+
FrameStateDescriptor* frame_state_descriptor = nullptr;
if (call_descriptor->NeedsFrameState()) {
frame_state_descriptor = GetFrameStateDescriptor(
@@ -2745,18 +2816,13 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
call_instr->MarkAsCall();
EmitPrepareResults(&(buffer.output_nodes), call_descriptor, node);
-}
-void InstructionSelector::VisitCallWithCallerSavedRegisters(
- Node* node, BasicBlock* handler) {
- OperandGenerator g(this);
- const auto fp_mode = CallDescriptorOf(node->op())->get_save_fp_mode();
- Emit(kArchSaveCallerRegisters | MiscField::encode(static_cast<int>(fp_mode)),
- g.NoOutput());
- VisitCall(node, handler);
- Emit(kArchRestoreCallerRegisters |
- MiscField::encode(static_cast<int>(fp_mode)),
- g.NoOutput());
+ if (call_descriptor->NeedsCallerSavedRegisters()) {
+ Emit(kArchRestoreCallerRegisters |
+ MiscField::encode(
+ static_cast<int>(call_descriptor->get_save_fp_mode())),
+ g.NoOutput());
+ }
}
void InstructionSelector::VisitTailCall(Node* node) {
@@ -2764,7 +2830,7 @@ void InstructionSelector::VisitTailCall(Node* node) {
auto call_descriptor = CallDescriptorOf(node->op());
CallDescriptor* caller = linkage()->GetIncomingDescriptor();
- DCHECK(caller->CanTailCall(node));
+ DCHECK(caller->CanTailCall(CallDescriptorOf(node->op())));
const CallDescriptor* callee = CallDescriptorOf(node->op());
int stack_param_delta = callee->GetStackParameterDelta(caller);
CallBuffer buffer(zone(), call_descriptor, nullptr);
@@ -2912,14 +2978,13 @@ void InstructionSelector::VisitTrapUnless(Node* node, TrapId trap_id) {
}
void InstructionSelector::EmitIdentity(Node* node) {
- OperandGenerator g(this);
MarkAsUsed(node->InputAt(0));
SetRename(node, node->InputAt(0));
}
void InstructionSelector::VisitDeoptimize(DeoptimizeKind kind,
DeoptimizeReason reason,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
Node* value) {
EmitDeoptimize(kArchDeoptimize, 0, nullptr, 0, nullptr, kind, reason,
feedback, value);
@@ -2980,8 +3045,9 @@ bool InstructionSelector::CanProduceSignalingNaN(Node* node) {
return true;
}
-FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
- Node* state) {
+namespace {
+
+FrameStateDescriptor* GetFrameStateDescriptorInternal(Zone* zone, Node* state) {
DCHECK_EQ(IrOpcode::kFrameState, state->opcode());
DCHECK_EQ(kFrameStateInputCount, state->InputCount());
FrameStateInfo state_info = FrameStateInfoOf(state->op());
@@ -2999,13 +3065,24 @@ FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
FrameStateDescriptor* outer_state = nullptr;
Node* outer_node = state->InputAt(kFrameStateOuterStateInput);
if (outer_node->opcode() == IrOpcode::kFrameState) {
- outer_state = GetFrameStateDescriptor(outer_node);
+ outer_state = GetFrameStateDescriptorInternal(zone, outer_node);
}
- return new (instruction_zone()) FrameStateDescriptor(
- instruction_zone(), state_info.type(), state_info.bailout_id(),
- state_info.state_combine(), parameters, locals, stack,
- state_info.shared_info(), outer_state);
+ return new (zone)
+ FrameStateDescriptor(zone, state_info.type(), state_info.bailout_id(),
+ state_info.state_combine(), parameters, locals,
+ stack, state_info.shared_info(), outer_state);
+}
+
+} // namespace
+
+FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
+ Node* state) {
+ auto* desc = GetFrameStateDescriptorInternal(instruction_zone(), state);
+ *max_unoptimized_frame_height_ =
+ std::max(*max_unoptimized_frame_height_,
+ desc->total_conservative_frame_size_in_bytes());
+ return desc;
}
// static
diff --git a/deps/v8/src/compiler/backend/instruction-selector.h b/deps/v8/src/compiler/backend/instruction-selector.h
index 16f88bb516..eb3e098427 100644
--- a/deps/v8/src/compiler/backend/instruction-selector.h
+++ b/deps/v8/src/compiler/backend/instruction-selector.h
@@ -12,6 +12,7 @@
#include "src/compiler/backend/instruction-scheduler.h"
#include "src/compiler/backend/instruction.h"
#include "src/compiler/common-operator.h"
+#include "src/compiler/feedback-source.h"
#include "src/compiler/linkage.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node.h"
@@ -60,7 +61,7 @@ class FlagsContinuation final {
static FlagsContinuation ForDeoptimize(FlagsCondition condition,
DeoptimizeKind kind,
DeoptimizeReason reason,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
Node* frame_state) {
return FlagsContinuation(kFlags_deoptimize, condition, kind, reason,
feedback, frame_state);
@@ -69,7 +70,7 @@ class FlagsContinuation final {
// Creates a new flags continuation for an eager deoptimization exit.
static FlagsContinuation ForDeoptimizeAndPoison(
FlagsCondition condition, DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback, Node* frame_state) {
+ FeedbackSource const& feedback, Node* frame_state) {
return FlagsContinuation(kFlags_deoptimize_and_poison, condition, kind,
reason, feedback, frame_state);
}
@@ -110,7 +111,7 @@ class FlagsContinuation final {
DCHECK(IsDeoptimize());
return reason_;
}
- VectorSlotPair const& feedback() const {
+ FeedbackSource const& feedback() const {
DCHECK(IsDeoptimize());
return feedback_;
}
@@ -196,7 +197,7 @@ class FlagsContinuation final {
FlagsContinuation(FlagsMode mode, FlagsCondition condition,
DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback, Node* frame_state)
+ FeedbackSource const& feedback, Node* frame_state)
: mode_(mode),
condition_(condition),
kind_(kind),
@@ -226,7 +227,7 @@ class FlagsContinuation final {
FlagsCondition condition_;
DeoptimizeKind kind_; // Only valid if mode_ == kFlags_deoptimize*
DeoptimizeReason reason_; // Only valid if mode_ == kFlags_deoptimize*
- VectorSlotPair feedback_; // Only valid if mode_ == kFlags_deoptimize*
+ FeedbackSource feedback_; // Only valid if mode_ == kFlags_deoptimize*
Node* frame_state_or_result_; // Only valid if mode_ == kFlags_deoptimize*
// or mode_ == kFlags_set.
BasicBlock* true_block_; // Only valid if mode_ == kFlags_branch*.
@@ -270,6 +271,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
InstructionSequence* sequence, Schedule* schedule,
SourcePositionTable* source_positions, Frame* frame,
EnableSwitchJumpTable enable_switch_jump_table, TickCounter* tick_counter,
+ size_t* max_unoptimized_frame_height,
SourcePositionMode source_position_mode = kCallSourcePositions,
Features features = SupportedFeatures(),
EnableScheduling enable_scheduling = FLAG_turbo_instruction_scheduling
@@ -352,7 +354,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
InstructionOperand* outputs, size_t input_count,
InstructionOperand* inputs, DeoptimizeKind kind,
DeoptimizeReason reason,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
Node* frame_state);
// ===========================================================================
@@ -446,7 +448,8 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
// Check if we can generate loads and stores of ExternalConstants relative
// to the roots register.
- bool CanAddressRelativeToRootsRegister() const;
+ bool CanAddressRelativeToRootsRegister(
+ const ExternalReference& reference) const;
// Check if we can use the roots register to access GC roots.
bool CanUseRootsRegister() const;
@@ -496,7 +499,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void AppendDeoptimizeArguments(InstructionOperandVector* args,
DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
Node* frame_state);
void EmitTableSwitch(
@@ -543,7 +546,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void MarkAsSimd128(Node* node) {
MarkAsRepresentation(MachineRepresentation::kSimd128, node);
}
- void MarkAsReference(Node* node) {
+ void MarkAsTagged(Node* node) {
MarkAsRepresentation(MachineRepresentation::kTagged, node);
}
void MarkAsCompressed(Node* node) {
@@ -621,8 +624,6 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void VisitProjection(Node* node);
void VisitConstant(Node* node);
void VisitCall(Node* call, BasicBlock* handler = nullptr);
- void VisitCallWithCallerSavedRegisters(Node* call,
- BasicBlock* handler = nullptr);
void VisitDeoptimizeIf(Node* node);
void VisitDeoptimizeUnless(Node* node);
void VisitTrapIf(Node* node, TrapId trap_id);
@@ -632,7 +633,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
void VisitSwitch(Node* node, const SwitchInfo& sw);
void VisitDeoptimize(DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback, Node* value);
+ FeedbackSource const& feedback, Node* value);
void VisitReturn(Node* ret);
void VisitThrow(Node* node);
void VisitRetain(Node* node);
@@ -640,6 +641,8 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
void VisitStaticAssert(Node* node);
void VisitDeadValue(Node* node);
+ void VisitStackPointerGreaterThan(Node* node, FlagsContinuation* cont);
+
void VisitWordCompareZero(Node* user, Node* value, FlagsContinuation* cont);
void EmitWordPoisonOnSpeculation(Node* node);
@@ -782,6 +785,10 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
ZoneVector<std::pair<int, int>> instr_origins_;
EnableTraceTurboJson trace_turbo_;
TickCounter* const tick_counter_;
+
+ // Store the maximal unoptimized frame height. Later used to apply an offset
+ // to stack checks.
+ size_t* max_unoptimized_frame_height_;
};
} // namespace compiler
diff --git a/deps/v8/src/compiler/backend/instruction.cc b/deps/v8/src/compiler/backend/instruction.cc
index 09c7fe22c5..06158b0c72 100644
--- a/deps/v8/src/compiler/backend/instruction.cc
+++ b/deps/v8/src/compiler/backend/instruction.cc
@@ -6,12 +6,14 @@
#include <iomanip>
+#include "src/codegen/interface-descriptors.h"
#include "src/codegen/register-configuration.h"
#include "src/codegen/source-position.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/graph.h"
#include "src/compiler/schedule.h"
#include "src/compiler/state-values-utils.h"
+#include "src/execution/frames.h"
namespace v8 {
namespace internal {
@@ -942,7 +944,7 @@ void InstructionSequence::MarkAsRepresentation(MachineRepresentation rep,
int InstructionSequence::AddDeoptimizationEntry(
FrameStateDescriptor* descriptor, DeoptimizeKind kind,
- DeoptimizeReason reason, VectorSlotPair const& feedback) {
+ DeoptimizeReason reason, FeedbackSource const& feedback) {
int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
deoptimization_entries_.push_back(
DeoptimizationEntry(descriptor, kind, reason, feedback));
@@ -1002,6 +1004,59 @@ void InstructionSequence::SetRegisterConfigurationForTesting(
GetRegConfig = InstructionSequence::RegisterConfigurationForTesting;
}
+namespace {
+
+size_t GetConservativeFrameSizeInBytes(FrameStateType type,
+ size_t parameters_count,
+ size_t locals_count,
+ BailoutId bailout_id) {
+ switch (type) {
+ case FrameStateType::kInterpretedFunction: {
+ auto info = InterpretedFrameInfo::Conservative(
+ static_cast<int>(parameters_count), static_cast<int>(locals_count));
+ return info.frame_size_in_bytes();
+ }
+ case FrameStateType::kArgumentsAdaptor: {
+ auto info = ArgumentsAdaptorFrameInfo::Conservative(
+ static_cast<int>(parameters_count));
+ return info.frame_size_in_bytes();
+ }
+ case FrameStateType::kConstructStub: {
+ auto info = ConstructStubFrameInfo::Conservative(
+ static_cast<int>(parameters_count));
+ return info.frame_size_in_bytes();
+ }
+ case FrameStateType::kBuiltinContinuation:
+ case FrameStateType::kJavaScriptBuiltinContinuation:
+ case FrameStateType::kJavaScriptBuiltinContinuationWithCatch: {
+ const RegisterConfiguration* config = RegisterConfiguration::Default();
+ auto info = BuiltinContinuationFrameInfo::Conservative(
+ static_cast<int>(parameters_count),
+ Builtins::CallInterfaceDescriptorFor(
+ Builtins::GetBuiltinFromBailoutId(bailout_id)),
+ config);
+ return info.frame_size_in_bytes();
+ }
+ }
+ UNREACHABLE();
+}
+
+size_t GetTotalConservativeFrameSizeInBytes(FrameStateType type,
+ size_t parameters_count,
+ size_t locals_count,
+ BailoutId bailout_id,
+ FrameStateDescriptor* outer_state) {
+ size_t outer_total_conservative_frame_size_in_bytes =
+ (outer_state == nullptr)
+ ? 0
+ : outer_state->total_conservative_frame_size_in_bytes();
+ return GetConservativeFrameSizeInBytes(type, parameters_count, locals_count,
+ bailout_id) +
+ outer_total_conservative_frame_size_in_bytes;
+}
+
+} // namespace
+
FrameStateDescriptor::FrameStateDescriptor(
Zone* zone, FrameStateType type, BailoutId bailout_id,
OutputFrameStateCombine state_combine, size_t parameters_count,
@@ -1014,10 +1069,35 @@ FrameStateDescriptor::FrameStateDescriptor(
parameters_count_(parameters_count),
locals_count_(locals_count),
stack_count_(stack_count),
+ total_conservative_frame_size_in_bytes_(
+ GetTotalConservativeFrameSizeInBytes(
+ type, parameters_count, locals_count, bailout_id, outer_state)),
values_(zone),
shared_info_(shared_info),
outer_state_(outer_state) {}
+size_t FrameStateDescriptor::GetHeight() const {
+ switch (type()) {
+ case FrameStateType::kInterpretedFunction:
+ return locals_count(); // The accumulator is *not* included.
+ case FrameStateType::kBuiltinContinuation:
+ // Custom, non-JS calling convention (that does not have a notion of
+ // a receiver or context).
+ return parameters_count();
+ case FrameStateType::kArgumentsAdaptor:
+ case FrameStateType::kConstructStub:
+ case FrameStateType::kJavaScriptBuiltinContinuation:
+ case FrameStateType::kJavaScriptBuiltinContinuationWithCatch:
+ // JS linkage. The parameters count
+ // - includes the receiver (input 1 in CreateArtificialFrameState, and
+ // passed as part of stack parameters to
+ // CreateJavaScriptBuiltinContinuationFrameState), and
+ // - does *not* include the context.
+ return parameters_count();
+ }
+ UNREACHABLE();
+}
+
size_t FrameStateDescriptor::GetSize() const {
return 1 + parameters_count() + locals_count() + stack_count() +
(HasContext() ? 1 : 0);
diff --git a/deps/v8/src/compiler/backend/instruction.h b/deps/v8/src/compiler/backend/instruction.h
index 9b32204055..f5f7f64c51 100644
--- a/deps/v8/src/compiler/backend/instruction.h
+++ b/deps/v8/src/compiler/backend/instruction.h
@@ -17,6 +17,7 @@
#include "src/common/globals.h"
#include "src/compiler/backend/instruction-codes.h"
#include "src/compiler/common-operator.h"
+#include "src/compiler/feedback-source.h"
#include "src/compiler/frame.h"
#include "src/compiler/opcodes.h"
#include "src/numbers/double.h"
@@ -130,7 +131,7 @@ class V8_EXPORT_PRIVATE InstructionOperand {
inline uint64_t GetCanonicalizedValue() const;
- class KindField : public BitField64<Kind, 0, 3> {};
+ using KindField = BitField64<Kind, 0, 3>;
uint64_t value_;
};
@@ -331,20 +332,20 @@ class UnallocatedOperand final : public InstructionOperand {
STATIC_ASSERT(KindField::kSize == 3);
- class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {};
+ using VirtualRegisterField = BitField64<uint32_t, 3, 32>;
// BitFields for all unallocated operands.
- class BasicPolicyField : public BitField64<BasicPolicy, 35, 1> {};
+ using BasicPolicyField = BitField64<BasicPolicy, 35, 1>;
// BitFields specific to BasicPolicy::FIXED_SLOT.
- class FixedSlotIndexField : public BitField64<int, 36, 28> {};
+ using FixedSlotIndexField = BitField64<int, 36, 28>;
// BitFields specific to BasicPolicy::EXTENDED_POLICY.
- class ExtendedPolicyField : public BitField64<ExtendedPolicy, 36, 3> {};
- class LifetimeField : public BitField64<Lifetime, 39, 1> {};
- class HasSecondaryStorageField : public BitField64<bool, 40, 1> {};
- class FixedRegisterField : public BitField64<int, 41, 6> {};
- class SecondaryStorageField : public BitField64<int, 47, 3> {};
+ using ExtendedPolicyField = BitField64<ExtendedPolicy, 36, 3>;
+ using LifetimeField = BitField64<Lifetime, 39, 1>;
+ using HasSecondaryStorageField = BitField64<bool, 40, 1>;
+ using FixedRegisterField = BitField64<int, 41, 6>;
+ using SecondaryStorageField = BitField64<int, 47, 3>;
private:
explicit UnallocatedOperand(int virtual_register)
@@ -373,7 +374,7 @@ class ConstantOperand : public InstructionOperand {
INSTRUCTION_OPERAND_CASTS(ConstantOperand, CONSTANT)
STATIC_ASSERT(KindField::kSize == 3);
- class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {};
+ using VirtualRegisterField = BitField64<uint32_t, 3, 32>;
};
class ImmediateOperand : public InstructionOperand {
@@ -406,8 +407,8 @@ class ImmediateOperand : public InstructionOperand {
INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE)
STATIC_ASSERT(KindField::kSize == 3);
- class TypeField : public BitField64<ImmediateType, 3, 1> {};
- class ValueField : public BitField64<int32_t, 32, 32> {};
+ using TypeField = BitField64<ImmediateType, 3, 1>;
+ using ValueField = BitField64<int32_t, 32, 32>;
};
class LocationOperand : public InstructionOperand {
@@ -509,9 +510,9 @@ class LocationOperand : public InstructionOperand {
}
STATIC_ASSERT(KindField::kSize == 3);
- class LocationKindField : public BitField64<LocationKind, 3, 2> {};
- class RepresentationField : public BitField64<MachineRepresentation, 5, 8> {};
- class IndexField : public BitField64<int32_t, 35, 29> {};
+ using LocationKindField = BitField64<LocationKind, 3, 2>;
+ using RepresentationField = BitField64<MachineRepresentation, 5, 8>;
+ using IndexField = BitField64<int32_t, 35, 29>;
};
class V8_EXPORT_PRIVATE ExplicitOperand
@@ -1270,6 +1271,20 @@ class FrameStateDescriptor : public ZoneObject {
type_ == FrameStateType::kConstructStub;
}
+ // The frame height on the stack, in number of slots, as serialized into a
+ // Translation and later used by the deoptimizer. Does *not* include
+ // information from the chain of outer states. Unlike |GetSize| this does not
+ // always include parameters, locals, and stack slots; instead, the returned
+ // slot kinds depend on the frame type.
+ size_t GetHeight() const;
+
+ // Returns an overapproximation of the unoptimized stack frame size in bytes,
+ // as later produced by the deoptimizer. Considers both this and the chain of
+ // outer states.
+ size_t total_conservative_frame_size_in_bytes() const {
+ return total_conservative_frame_size_in_bytes_;
+ }
+
size_t GetSize() const;
size_t GetTotalSize() const;
size_t GetFrameCount() const;
@@ -1283,12 +1298,13 @@ class FrameStateDescriptor : public ZoneObject {
FrameStateType type_;
BailoutId bailout_id_;
OutputFrameStateCombine frame_state_combine_;
- size_t parameters_count_;
- size_t locals_count_;
- size_t stack_count_;
+ const size_t parameters_count_;
+ const size_t locals_count_;
+ const size_t stack_count_;
+ const size_t total_conservative_frame_size_in_bytes_;
StateValueList values_;
MaybeHandle<SharedFunctionInfo> const shared_info_;
- FrameStateDescriptor* outer_state_;
+ FrameStateDescriptor* const outer_state_;
};
// A deoptimization entry is a pair of the reason why we deoptimize and the
@@ -1297,7 +1313,7 @@ class DeoptimizationEntry final {
public:
DeoptimizationEntry() = default;
DeoptimizationEntry(FrameStateDescriptor* descriptor, DeoptimizeKind kind,
- DeoptimizeReason reason, VectorSlotPair const& feedback)
+ DeoptimizeReason reason, FeedbackSource const& feedback)
: descriptor_(descriptor),
kind_(kind),
reason_(reason),
@@ -1306,13 +1322,13 @@ class DeoptimizationEntry final {
FrameStateDescriptor* descriptor() const { return descriptor_; }
DeoptimizeKind kind() const { return kind_; }
DeoptimizeReason reason() const { return reason_; }
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
private:
FrameStateDescriptor* descriptor_ = nullptr;
DeoptimizeKind kind_ = DeoptimizeKind::kEager;
DeoptimizeReason reason_ = DeoptimizeReason::kUnknown;
- VectorSlotPair feedback_ = VectorSlotPair();
+ FeedbackSource feedback_ = FeedbackSource();
};
using DeoptimizationVector = ZoneVector<DeoptimizationEntry>;
@@ -1577,7 +1593,7 @@ class V8_EXPORT_PRIVATE InstructionSequence final
int AddDeoptimizationEntry(FrameStateDescriptor* descriptor,
DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback);
+ FeedbackSource const& feedback);
DeoptimizationEntry const& GetDeoptimizationEntry(int deoptimization_id);
int GetDeoptimizationEntryCount() const {
return static_cast<int>(deoptimization_entries_.size());
diff --git a/deps/v8/src/compiler/backend/mips/code-generator-mips.cc b/deps/v8/src/compiler/backend/mips/code-generator-mips.cc
index 5cec4a8a16..239075392a 100644
--- a/deps/v8/src/compiler/backend/mips/code-generator-mips.cc
+++ b/deps/v8/src/compiler/backend/mips/code-generator-mips.cc
@@ -850,18 +850,17 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// don't emit code for nops.
break;
case kArchDeoptimize: {
- int deopt_state_id =
+ DeoptimizationExit* exit =
BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
- CodeGenResult result =
- AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
+ CodeGenResult result = AssembleDeoptimizerCall(exit);
if (result != kSuccess) return result;
break;
}
case kArchRet:
AssembleReturn(instr->InputAt(0));
break;
- case kArchStackPointer:
- __ mov(i.OutputRegister(), sp);
+ case kArchStackPointerGreaterThan:
+ // Pseudo-instruction used for cmp/branch. No opcode emitted here.
break;
case kArchFramePointer:
__ mov(i.OutputRegister(), fp);
@@ -2067,6 +2066,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputSimd128Register(1));
break;
}
+ case kMipsF32x4Div: {
+ CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
+ __ fdiv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
+ i.InputSimd128Register(1));
+ break;
+ }
case kMipsF32x4Max: {
CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
__ fmax_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
@@ -3015,6 +3020,9 @@ void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
} else if (instr->arch_opcode() == kMipsCmp) {
cc = FlagsConditionToConditionCmp(condition);
__ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
+ } else if (instr->arch_opcode() == kArchStackPointerGreaterThan) {
+ cc = FlagsConditionToConditionCmp(condition);
+ __ Branch(tlabel, cc, sp, Operand(i.InputRegister(0)));
} else if (instr->arch_opcode() == kMipsCmpS ||
instr->arch_opcode() == kMipsCmpD) {
bool predicate;
@@ -3444,6 +3452,42 @@ void CodeGenerator::AssembleConstructFrame() {
const RegList saves = call_descriptor->CalleeSavedRegisters();
const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
+
+ if (required_slots > 0) {
+ DCHECK(frame_access_state()->has_frame());
+ if (info()->IsWasm() && required_slots > 128) {
+ // For WebAssembly functions with big frames we have to do the stack
+ // overflow check before we construct the frame. Otherwise we may not
+ // have enough space on the stack to call the runtime for the stack
+ // overflow.
+ Label done;
+
+ // If the frame is bigger than the stack, we throw the stack overflow
+ // exception unconditionally. Thereby we can avoid the integer overflow
+ // check in the condition code.
+ if ((required_slots * kSystemPointerSize) < (FLAG_stack_size * 1024)) {
+ __ Lw(
+ kScratchReg,
+ FieldMemOperand(kWasmInstanceRegister,
+ WasmInstanceObject::kRealStackLimitAddressOffset));
+ __ Lw(kScratchReg, MemOperand(kScratchReg));
+ __ Addu(kScratchReg, kScratchReg,
+ Operand(required_slots * kSystemPointerSize));
+ __ Branch(&done, uge, sp, Operand(kScratchReg));
+ }
+
+ __ Call(wasm::WasmCode::kWasmStackOverflow, RelocInfo::WASM_STUB_CALL);
+ // We come from WebAssembly, there are no references for the GC.
+ ReferenceMap* reference_map = new (zone()) ReferenceMap(zone());
+ RecordSafepoint(reference_map, Safepoint::kNoLazyDeopt);
+ if (FLAG_debug_code) {
+ __ stop();
+ }
+
+ __ bind(&done);
+ }
+ }
+
const int returns = frame()->GetReturnSlotCount();
// Skip callee-saved and return slots, which are pushed below.
@@ -3527,6 +3571,8 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::FinishCode() {}
+void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {}
+
void CodeGenerator::AssembleMove(InstructionOperand* source,
InstructionOperand* destination) {
MipsOperandConverter g(this, nullptr);
diff --git a/deps/v8/src/compiler/backend/mips/instruction-codes-mips.h b/deps/v8/src/compiler/backend/mips/instruction-codes-mips.h
index 44e53ac044..e8020d9e89 100644
--- a/deps/v8/src/compiler/backend/mips/instruction-codes-mips.h
+++ b/deps/v8/src/compiler/backend/mips/instruction-codes-mips.h
@@ -165,6 +165,7 @@ namespace compiler {
V(MipsF32x4AddHoriz) \
V(MipsF32x4Sub) \
V(MipsF32x4Mul) \
+ V(MipsF32x4Div) \
V(MipsF32x4Max) \
V(MipsF32x4Min) \
V(MipsF32x4Eq) \
diff --git a/deps/v8/src/compiler/backend/mips/instruction-scheduler-mips.cc b/deps/v8/src/compiler/backend/mips/instruction-scheduler-mips.cc
index 92ab3f9344..4e6aef52f4 100644
--- a/deps/v8/src/compiler/backend/mips/instruction-scheduler-mips.cc
+++ b/deps/v8/src/compiler/backend/mips/instruction-scheduler-mips.cc
@@ -51,6 +51,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kMipsF32x4Max:
case kMipsF32x4Min:
case kMipsF32x4Mul:
+ case kMipsF32x4Div:
case kMipsF32x4Ne:
case kMipsF32x4Neg:
case kMipsF32x4RecipApprox:
@@ -1673,7 +1674,6 @@ int InstructionScheduler::GetInstructionLatency(const Instruction* instr) {
case kMipsCmp:
return 0;
case kArchDebugBreak:
- case kArchStackPointer:
case kArchFramePointer:
case kArchParentFramePointer:
case kMipsShl:
diff --git a/deps/v8/src/compiler/backend/mips/instruction-selector-mips.cc b/deps/v8/src/compiler/backend/mips/instruction-selector-mips.cc
index 452e92a174..bb47262c6c 100644
--- a/deps/v8/src/compiler/backend/mips/instruction-selector-mips.cc
+++ b/deps/v8/src/compiler/backend/mips/instruction-selector-mips.cc
@@ -352,7 +352,8 @@ void InstructionSelector::VisitStore(Node* node) {
MachineRepresentation rep = store_rep.representation();
// TODO(mips): I guess this could be done in a better way.
- if (write_barrier_kind != kNoWriteBarrier) {
+ if (write_barrier_kind != kNoWriteBarrier &&
+ V8_LIKELY(!FLAG_disable_write_barriers)) {
DCHECK(CanBeTaggedPointer(rep));
InstructionOperand inputs[3];
size_t input_count = 0;
@@ -1529,6 +1530,15 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
} // namespace
+void InstructionSelector::VisitStackPointerGreaterThan(
+ Node* node, FlagsContinuation* cont) {
+ Node* const value = node->InputAt(0);
+ InstructionCode opcode = kArchStackPointerGreaterThan;
+
+ MipsOperandGenerator g(this);
+ EmitWithContinuation(opcode, g.UseRegister(value), cont);
+}
+
// Shared routine for word comparisons against zero.
void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
FlagsContinuation* cont) {
@@ -1607,6 +1617,9 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
break;
case IrOpcode::kWord32And:
return VisitWordCompare(this, value, kMipsTst, cont, true);
+ case IrOpcode::kStackPointerGreaterThan:
+ cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
+ return VisitStackPointerGreaterThan(value, cont);
default:
break;
}
@@ -2041,6 +2054,7 @@ void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
V(F32x4AddHoriz, kMipsF32x4AddHoriz) \
V(F32x4Sub, kMipsF32x4Sub) \
V(F32x4Mul, kMipsF32x4Mul) \
+ V(F32x4Div, kMipsF32x4Div) \
V(F32x4Max, kMipsF32x4Max) \
V(F32x4Min, kMipsF32x4Min) \
V(F32x4Eq, kMipsF32x4Eq) \
diff --git a/deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc b/deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc
index f746b52df6..5682bed71a 100644
--- a/deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc
+++ b/deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc
@@ -828,18 +828,17 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// don't emit code for nops.
break;
case kArchDeoptimize: {
- int deopt_state_id =
+ DeoptimizationExit* exit =
BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
- CodeGenResult result =
- AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
+ CodeGenResult result = AssembleDeoptimizerCall(exit);
if (result != kSuccess) return result;
break;
}
case kArchRet:
AssembleReturn(instr->InputAt(0));
break;
- case kArchStackPointer:
- __ mov(i.OutputRegister(), sp);
+ case kArchStackPointerGreaterThan:
+ // Pseudo-instruction used for cmp/branch. No opcode emitted here.
break;
case kArchFramePointer:
__ mov(i.OutputRegister(), fp);
@@ -2182,6 +2181,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
i.InputSimd128Register(1));
break;
}
+ case kMips64F32x4Div: {
+ CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
+ __ fdiv_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
+ i.InputSimd128Register(1));
+ break;
+ }
case kMips64F32x4Max: {
CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
__ fmax_w(i.OutputSimd128Register(), i.InputSimd128Register(0),
@@ -3140,6 +3145,9 @@ void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
} else if (instr->arch_opcode() == kMips64Cmp) {
cc = FlagsConditionToConditionCmp(condition);
__ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
+ } else if (instr->arch_opcode() == kArchStackPointerGreaterThan) {
+ cc = FlagsConditionToConditionCmp(condition);
+ __ Branch(tlabel, cc, sp, Operand(i.InputRegister(0)));
} else if (instr->arch_opcode() == kMips64CmpS ||
instr->arch_opcode() == kMips64CmpD) {
bool predicate;
@@ -3603,6 +3611,42 @@ void CodeGenerator::AssembleConstructFrame() {
const RegList saves = call_descriptor->CalleeSavedRegisters();
const RegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
+
+ if (required_slots > 0) {
+ DCHECK(frame_access_state()->has_frame());
+ if (info()->IsWasm() && required_slots > 128) {
+ // For WebAssembly functions with big frames we have to do the stack
+ // overflow check before we construct the frame. Otherwise we may not
+ // have enough space on the stack to call the runtime for the stack
+ // overflow.
+ Label done;
+
+ // If the frame is bigger than the stack, we throw the stack overflow
+ // exception unconditionally. Thereby we can avoid the integer overflow
+ // check in the condition code.
+ if ((required_slots * kSystemPointerSize) < (FLAG_stack_size * 1024)) {
+ __ Ld(
+ kScratchReg,
+ FieldMemOperand(kWasmInstanceRegister,
+ WasmInstanceObject::kRealStackLimitAddressOffset));
+ __ Ld(kScratchReg, MemOperand(kScratchReg));
+ __ Daddu(kScratchReg, kScratchReg,
+ Operand(required_slots * kSystemPointerSize));
+ __ Branch(&done, uge, sp, Operand(kScratchReg));
+ }
+
+ __ Call(wasm::WasmCode::kWasmStackOverflow, RelocInfo::WASM_STUB_CALL);
+ // We come from WebAssembly, there are no references for the GC.
+ ReferenceMap* reference_map = new (zone()) ReferenceMap(zone());
+ RecordSafepoint(reference_map, Safepoint::kNoLazyDeopt);
+ if (FLAG_debug_code) {
+ __ stop();
+ }
+
+ __ bind(&done);
+ }
+ }
+
const int returns = frame()->GetReturnSlotCount();
// Skip callee-saved and return slots, which are pushed below.
@@ -3686,6 +3730,8 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::FinishCode() {}
+void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {}
+
void CodeGenerator::AssembleMove(InstructionOperand* source,
InstructionOperand* destination) {
MipsOperandConverter g(this, nullptr);
diff --git a/deps/v8/src/compiler/backend/mips64/instruction-codes-mips64.h b/deps/v8/src/compiler/backend/mips64/instruction-codes-mips64.h
index e375ee8d07..edc8924757 100644
--- a/deps/v8/src/compiler/backend/mips64/instruction-codes-mips64.h
+++ b/deps/v8/src/compiler/backend/mips64/instruction-codes-mips64.h
@@ -195,6 +195,7 @@ namespace compiler {
V(Mips64F32x4AddHoriz) \
V(Mips64F32x4Sub) \
V(Mips64F32x4Mul) \
+ V(Mips64F32x4Div) \
V(Mips64F32x4Max) \
V(Mips64F32x4Min) \
V(Mips64F32x4Eq) \
diff --git a/deps/v8/src/compiler/backend/mips64/instruction-scheduler-mips64.cc b/deps/v8/src/compiler/backend/mips64/instruction-scheduler-mips64.cc
index 4dcafe4197..880b424c41 100644
--- a/deps/v8/src/compiler/backend/mips64/instruction-scheduler-mips64.cc
+++ b/deps/v8/src/compiler/backend/mips64/instruction-scheduler-mips64.cc
@@ -79,6 +79,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kMips64F32x4Max:
case kMips64F32x4Min:
case kMips64F32x4Mul:
+ case kMips64F32x4Div:
case kMips64F32x4Ne:
case kMips64F32x4Neg:
case kMips64F32x4RecipApprox:
@@ -1275,7 +1276,6 @@ int InstructionScheduler::GetInstructionLatency(const Instruction* instr) {
return 0;
case kArchRet:
return AssemblerReturnLatency();
- case kArchStackPointer:
case kArchFramePointer:
return 1;
case kArchParentFramePointer:
diff --git a/deps/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc b/deps/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc
index 95f11ebed1..9c717ab1e9 100644
--- a/deps/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc
+++ b/deps/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc
@@ -422,7 +422,8 @@ void InstructionSelector::VisitStore(Node* node) {
MachineRepresentation rep = store_rep.representation();
// TODO(mips): I guess this could be done in a better way.
- if (write_barrier_kind != kNoWriteBarrier) {
+ if (write_barrier_kind != kNoWriteBarrier &&
+ V8_LIKELY(!FLAG_disable_write_barriers)) {
DCHECK(CanBeTaggedPointer(rep));
InstructionOperand inputs[3];
size_t input_count = 0;
@@ -2090,6 +2091,15 @@ void VisitAtomicBinop(InstructionSelector* selector, Node* node,
} // namespace
+void InstructionSelector::VisitStackPointerGreaterThan(
+ Node* node, FlagsContinuation* cont) {
+ Node* const value = node->InputAt(0);
+ InstructionCode opcode = kArchStackPointerGreaterThan;
+
+ Mips64OperandGenerator g(this);
+ EmitWithContinuation(opcode, g.UseRegister(value), cont);
+}
+
// Shared routine for word comparisons against zero.
void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
FlagsContinuation* cont) {
@@ -2199,6 +2209,9 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
case IrOpcode::kWord32And:
case IrOpcode::kWord64And:
return VisitWordCompare(this, value, kMips64Tst, cont, true);
+ case IrOpcode::kStackPointerGreaterThan:
+ cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
+ return VisitStackPointerGreaterThan(value, cont);
default:
break;
}
@@ -2704,6 +2717,7 @@ void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
V(F32x4AddHoriz, kMips64F32x4AddHoriz) \
V(F32x4Sub, kMips64F32x4Sub) \
V(F32x4Mul, kMips64F32x4Mul) \
+ V(F32x4Div, kMips64F32x4Div) \
V(F32x4Max, kMips64F32x4Max) \
V(F32x4Min, kMips64F32x4Min) \
V(F32x4Eq, kMips64F32x4Eq) \
diff --git a/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc b/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc
index 5289812cb5..5c69bc34a1 100644
--- a/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc
+++ b/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc
@@ -1024,13 +1024,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
Label start_call;
bool isWasmCapiFunction =
linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
- constexpr int offset = 12;
+ constexpr int offset = 9 * kInstrSize;
if (isWasmCapiFunction) {
- __ mflr(kScratchReg);
+ __ mflr(r0);
__ bind(&start_call);
- __ LoadPC(r0);
- __ addi(r0, r0, Operand(offset));
- __ StoreP(r0, MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
+ __ LoadPC(kScratchReg);
+ __ addi(kScratchReg, kScratchReg, Operand(offset));
+ __ StoreP(kScratchReg,
+ MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
__ mtlr(r0);
}
if (instr->InputAt(0)->IsImmediate()) {
@@ -1040,11 +1041,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
Register func = i.InputRegister(0);
__ CallCFunction(func, num_parameters);
}
- // TODO(miladfar): In the above block, r0 must be populated with the
- // strictly-correct PC, which is the return address at this spot. The
- // offset is set to 12 right now, which is counted from where we are
- // binding to the label and ends at this spot. If failed, replace it it
- // with the correct offset suggested. More info on f5ab7d3.
+ // TODO(miladfar): In the above block, kScratchReg must be populated with
+ // the strictly-correct PC, which is the return address at this spot. The
+ // offset is set to 36 (9 * kInstrSize) right now, which is counted from
+ // where we are binding to the label and ends at this spot. If failed,
+ // replace it with the correct offset suggested. More info on f5ab7d3.
if (isWasmCapiFunction)
CHECK_EQ(offset, __ SizeOfCodeGeneratedSince(&start_call));
@@ -1104,10 +1105,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
DCHECK_EQ(LeaveRC, i.OutputRCBit());
break;
case kArchDeoptimize: {
- int deopt_state_id =
+ DeoptimizationExit* exit =
BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
- CodeGenResult result =
- AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
+ CodeGenResult result = AssembleDeoptimizerCall(exit);
if (result != kSuccess) return result;
break;
}
@@ -1115,10 +1115,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
AssembleReturn(instr->InputAt(0));
DCHECK_EQ(LeaveRC, i.OutputRCBit());
break;
- case kArchStackPointer:
- __ mr(i.OutputRegister(), sp);
- DCHECK_EQ(LeaveRC, i.OutputRCBit());
- break;
case kArchFramePointer:
__ mr(i.OutputRegister(), fp);
DCHECK_EQ(LeaveRC, i.OutputRCBit());
@@ -1130,6 +1126,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ mr(i.OutputRegister(), fp);
}
break;
+ case kArchStackPointerGreaterThan: {
+ constexpr size_t kValueIndex = 0;
+ DCHECK(instr->InputAt(kValueIndex)->IsRegister());
+ __ cmpl(sp, i.InputRegister(kValueIndex), cr0);
+ break;
+ }
case kArchTruncateDoubleToI:
__ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
i.InputDoubleRegister(0), DetermineStubCallMode());
@@ -2516,6 +2518,8 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::FinishCode() {}
+void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {}
+
void CodeGenerator::AssembleMove(InstructionOperand* source,
InstructionOperand* destination) {
PPCOperandConverter g(this, nullptr);
diff --git a/deps/v8/src/compiler/backend/ppc/instruction-selector-ppc.cc b/deps/v8/src/compiler/backend/ppc/instruction-selector-ppc.cc
index bfc77b9412..ef8490a726 100644
--- a/deps/v8/src/compiler/backend/ppc/instruction-selector-ppc.cc
+++ b/deps/v8/src/compiler/backend/ppc/instruction-selector-ppc.cc
@@ -65,17 +65,6 @@ class PPCOperandGenerator final : public OperandGenerator {
}
return false;
}
-
- // Use the stack pointer if the node is LoadStackPointer, otherwise assign a
- // register.
- InstructionOperand UseRegisterOrStackPointer(Node* node) {
- if (node->opcode() == IrOpcode::kLoadStackPointer) {
- return LocationOperand(LocationOperand::EXPLICIT,
- LocationOperand::REGISTER,
- MachineRepresentation::kWord32, sp.code());
- }
- return UseRegister(node);
- }
};
namespace {
@@ -267,7 +256,8 @@ void InstructionSelector::VisitStore(Node* node) {
rep = store_rep.representation();
}
- if (write_barrier_kind != kNoWriteBarrier) {
+ if (write_barrier_kind != kNoWriteBarrier &&
+ V8_LIKELY(!FLAG_disable_write_barriers)) {
DCHECK(CanBeTaggedPointer(rep));
AddressingMode addressing_mode;
InstructionOperand inputs[3];
@@ -558,6 +548,15 @@ void InstructionSelector::VisitWord32Xor(Node* node) {
}
}
+void InstructionSelector::VisitStackPointerGreaterThan(
+ Node* node, FlagsContinuation* cont) {
+ Node* const value = node->InputAt(0);
+ InstructionCode opcode = kArchStackPointerGreaterThan;
+
+ PPCOperandGenerator g(this);
+ EmitWithContinuation(opcode, g.UseRegister(value), cont);
+}
+
#if V8_TARGET_ARCH_PPC64
void InstructionSelector::VisitWord64Xor(Node* node) {
PPCOperandGenerator g(this);
@@ -1456,15 +1455,15 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
// Match immediates on left or right side of comparison.
if (g.CanBeImmediate(right, immediate_mode)) {
- VisitCompare(selector, opcode, g.UseRegisterOrStackPointer(left),
- g.UseImmediate(right), cont);
+ VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
+ cont);
} else if (g.CanBeImmediate(left, immediate_mode)) {
if (!commutative) cont->Commute();
- VisitCompare(selector, opcode, g.UseRegisterOrStackPointer(right),
- g.UseImmediate(left), cont);
+ VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
+ cont);
} else {
- VisitCompare(selector, opcode, g.UseRegisterOrStackPointer(left),
- g.UseRegisterOrStackPointer(right), cont);
+ VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right),
+ cont);
}
}
@@ -1639,6 +1638,9 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
// case IrOpcode::kWord64Shr:
// case IrOpcode::kWord64Ror:
#endif
+ case IrOpcode::kStackPointerGreaterThan:
+ cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
+ return VisitStackPointerGreaterThan(value, cont);
default:
break;
}
@@ -2281,6 +2283,8 @@ void InstructionSelector::VisitF32x4Sub(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF32x4Mul(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitF32x4Div(Node* node) { UNIMPLEMENTED(); }
+
void InstructionSelector::VisitF32x4Min(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF32x4Max(Node* node) { UNIMPLEMENTED(); }
diff --git a/deps/v8/src/compiler/backend/register-allocator.cc b/deps/v8/src/compiler/backend/register-allocator.cc
index 44701f8159..21eef0485c 100644
--- a/deps/v8/src/compiler/backend/register-allocator.cc
+++ b/deps/v8/src/compiler/backend/register-allocator.cc
@@ -2989,34 +2989,72 @@ LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start,
}
LifetimePosition RegisterAllocator::FindOptimalSpillingPos(
- LiveRange* range, LifetimePosition pos) {
+ LiveRange* range, LifetimePosition pos, SpillMode spill_mode,
+ LiveRange** begin_spill_out) {
+ *begin_spill_out = range;
+ // TODO(herhut): Be more clever here as long as we do not move pos out of
+ // deferred code.
+ if (spill_mode == SpillMode::kSpillDeferred) return pos;
const InstructionBlock* block = GetInstructionBlock(code(), pos.Start());
const InstructionBlock* loop_header =
block->IsLoopHeader() ? block : GetContainingLoop(code(), block);
-
if (loop_header == nullptr) return pos;
- const UsePosition* prev_use =
- range->PreviousUsePositionRegisterIsBeneficial(pos);
-
- while (loop_header != nullptr) {
- // We are going to spill live range inside the loop.
- // If possible try to move spilling position backwards to loop header.
- // This will reduce number of memory moves on the back edge.
- LifetimePosition loop_start = LifetimePosition::GapFromInstructionIndex(
- loop_header->first_instruction_index());
-
- if (range->Covers(loop_start)) {
- if (prev_use == nullptr || prev_use->pos() < loop_start) {
+ if (data()->is_turbo_control_flow_aware_allocation()) {
+ while (loop_header != nullptr) {
+ // We are going to spill live range inside the loop.
+ // If possible try to move spilling position backwards to loop header.
+ // This will reduce number of memory moves on the back edge.
+ LifetimePosition loop_start = LifetimePosition::GapFromInstructionIndex(
+ loop_header->first_instruction_index());
+ auto& loop_header_state =
+ data()->GetSpillState(loop_header->rpo_number());
+ for (LiveRange* live_at_header : loop_header_state) {
+ if (live_at_header->TopLevel() != range->TopLevel() ||
+ !live_at_header->Covers(loop_start) || live_at_header->spilled()) {
+ continue;
+ }
+ LiveRange* check_use = live_at_header;
+ for (; check_use != nullptr && check_use->Start() < pos;
+ check_use = check_use->next()) {
+ UsePosition* next_use =
+ check_use->NextUsePositionRegisterIsBeneficial(loop_start);
+ if (next_use != nullptr && next_use->pos() < pos) {
+ return pos;
+ }
+ }
// No register beneficial use inside the loop before the pos.
+ *begin_spill_out = live_at_header;
pos = loop_start;
+ break;
}
+
+ // Try hoisting out to an outer loop.
+ loop_header = GetContainingLoop(code(), loop_header);
}
+ } else {
+ const UsePosition* prev_use =
+ range->PreviousUsePositionRegisterIsBeneficial(pos);
+
+ while (loop_header != nullptr) {
+ // We are going to spill live range inside the loop.
+ // If possible try to move spilling position backwards to loop header
+ // inside the current range. This will reduce number of memory moves on
+ // the back edge.
+ LifetimePosition loop_start = LifetimePosition::GapFromInstructionIndex(
+ loop_header->first_instruction_index());
+
+ if (range->Covers(loop_start)) {
+ if (prev_use == nullptr || prev_use->pos() < loop_start) {
+ // No register beneficial use inside the loop before the pos.
+ pos = loop_start;
+ }
+ }
- // Try hoisting out to an outer loop.
- loop_header = GetContainingLoop(code(), loop_header);
+ // Try hoisting out to an outer loop.
+ loop_header = GetContainingLoop(code(), loop_header);
+ }
}
-
return pos;
}
@@ -3064,6 +3102,28 @@ LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data,
inactive_live_ranges().reserve(8);
}
+void LinearScanAllocator::MaybeSpillPreviousRanges(LiveRange* begin_range,
+ LifetimePosition begin_pos,
+ LiveRange* end_range) {
+ // Spill begin_range after begin_pos, then spill every live range of this
+ // virtual register until but excluding end_range.
+ DCHECK(begin_range->Covers(begin_pos));
+ DCHECK_EQ(begin_range->TopLevel(), end_range->TopLevel());
+
+ if (begin_range != end_range) {
+ DCHECK_LE(begin_range->End(), end_range->Start());
+ if (!begin_range->spilled()) {
+ SpillAfter(begin_range, begin_pos, SpillMode::kSpillAtDefinition);
+ }
+ for (LiveRange* range = begin_range->next(); range != end_range;
+ range = range->next()) {
+ if (!range->spilled()) {
+ range->Spill();
+ }
+ }
+ }
+}
+
void LinearScanAllocator::MaybeUndoPreviousSplit(LiveRange* range) {
if (range->next() != nullptr && range->next()->ShouldRecombine()) {
LiveRange* to_remove = range->next();
@@ -4407,11 +4467,10 @@ void LinearScanAllocator::SplitAndSpillIntersecting(LiveRange* current,
}
UsePosition* next_pos = range->NextRegisterPosition(current->Start());
- // TODO(herhut): Be more clever here as long as we do not move split_pos
- // out of deferred code.
- LifetimePosition spill_pos = spill_mode == SpillMode::kSpillDeferred
- ? split_pos
- : FindOptimalSpillingPos(range, split_pos);
+ LiveRange* begin_spill = nullptr;
+ LifetimePosition spill_pos =
+ FindOptimalSpillingPos(range, split_pos, spill_mode, &begin_spill);
+ MaybeSpillPreviousRanges(begin_spill, spill_pos, range);
if (next_pos == nullptr) {
SpillAfter(range, spill_pos, spill_mode);
} else {
diff --git a/deps/v8/src/compiler/backend/register-allocator.h b/deps/v8/src/compiler/backend/register-allocator.h
index 55f8a8dd1f..bc7b09d147 100644
--- a/deps/v8/src/compiler/backend/register-allocator.h
+++ b/deps/v8/src/compiler/backend/register-allocator.h
@@ -1238,7 +1238,9 @@ class RegisterAllocator : public ZoneObject {
// If we are trying to spill a range inside the loop try to
// hoist spill position out to the point just before the loop.
LifetimePosition FindOptimalSpillingPos(LiveRange* range,
- LifetimePosition pos);
+ LifetimePosition pos,
+ SpillMode spill_mode,
+ LiveRange** begin_spill_out);
const ZoneVector<TopLevelLiveRange*>& GetFixedRegisters() const;
const char* RegisterName(int allocation_index) const;
@@ -1292,6 +1294,9 @@ class LinearScanAllocator final : public RegisterAllocator {
ZoneUnorderedSet<RangeWithRegister, RangeWithRegister::Hash,
RangeWithRegister::Equals>;
+ void MaybeSpillPreviousRanges(LiveRange* begin_range,
+ LifetimePosition begin_pos,
+ LiveRange* end_range);
void MaybeUndoPreviousSplit(LiveRange* range);
void SpillNotLiveRanges(
RangeWithRegisterSet& to_be_live, // NOLINT(runtime/references)
diff --git a/deps/v8/src/compiler/backend/s390/code-generator-s390.cc b/deps/v8/src/compiler/backend/s390/code-generator-s390.cc
index 6457b7c8b4..4c2d862fc4 100644
--- a/deps/v8/src/compiler/backend/s390/code-generator-s390.cc
+++ b/deps/v8/src/compiler/backend/s390/code-generator-s390.cc
@@ -1578,19 +1578,15 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// don't emit code for nops.
break;
case kArchDeoptimize: {
- int deopt_state_id =
+ DeoptimizationExit* exit =
BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
- CodeGenResult result =
- AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
+ CodeGenResult result = AssembleDeoptimizerCall(exit);
if (result != kSuccess) return result;
break;
}
case kArchRet:
AssembleReturn(instr->InputAt(0));
break;
- case kArchStackPointer:
- __ LoadRR(i.OutputRegister(), sp);
- break;
case kArchFramePointer:
__ LoadRR(i.OutputRegister(), fp);
break;
@@ -1601,6 +1597,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ LoadRR(i.OutputRegister(), fp);
}
break;
+ case kArchStackPointerGreaterThan: {
+ constexpr size_t kValueIndex = 0;
+ DCHECK(instr->InputAt(kValueIndex)->IsRegister());
+ __ CmpLogicalP(sp, i.InputRegister(kValueIndex));
+ break;
+ }
case kArchTruncateDoubleToI:
__ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
i.InputDoubleRegister(0), DetermineStubCallMode());
@@ -3193,6 +3195,8 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::FinishCode() {}
+void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {}
+
void CodeGenerator::AssembleMove(InstructionOperand* source,
InstructionOperand* destination) {
S390OperandConverter g(this, nullptr);
diff --git a/deps/v8/src/compiler/backend/s390/instruction-selector-s390.cc b/deps/v8/src/compiler/backend/s390/instruction-selector-s390.cc
index 99d3b0fa0f..7f3277fc68 100644
--- a/deps/v8/src/compiler/backend/s390/instruction-selector-s390.cc
+++ b/deps/v8/src/compiler/backend/s390/instruction-selector-s390.cc
@@ -243,17 +243,6 @@ class S390OperandGenerator final : public OperandGenerator {
bool Is64BitOperand(Node* node) {
return MachineRepresentation::kWord64 == GetRepresentation(node);
}
-
- // Use the stack pointer if the node is LoadStackPointer, otherwise assign a
- // register.
- InstructionOperand UseRegisterOrStackPointer(Node* node) {
- if (node->opcode() == IrOpcode::kLoadStackPointer) {
- return LocationOperand(LocationOperand::EXPLICIT,
- LocationOperand::REGISTER,
- MachineRepresentation::kWord32, sp.code());
- }
- return UseRegister(node);
- }
};
namespace {
@@ -727,7 +716,8 @@ static void VisitGeneralStore(
Node* base = node->InputAt(0);
Node* offset = node->InputAt(1);
Node* value = node->InputAt(2);
- if (write_barrier_kind != kNoWriteBarrier) {
+ if (write_barrier_kind != kNoWriteBarrier &&
+ V8_LIKELY(!FLAG_disable_write_barriers)) {
DCHECK(CanBeTaggedPointer(rep));
AddressingMode addressing_mode;
InstructionOperand inputs[3];
@@ -837,6 +827,15 @@ void InstructionSelector::VisitUnalignedLoad(Node* node) { UNREACHABLE(); }
// Architecture supports unaligned access, therefore VisitStore is used instead
void InstructionSelector::VisitUnalignedStore(Node* node) { UNREACHABLE(); }
+void InstructionSelector::VisitStackPointerGreaterThan(
+ Node* node, FlagsContinuation* cont) {
+ Node* const value = node->InputAt(0);
+ InstructionCode opcode = kArchStackPointerGreaterThan;
+
+ S390OperandGenerator g(this);
+ EmitWithContinuation(opcode, g.UseRegister(value), cont);
+}
+
#if 0
static inline bool IsContiguousMask32(uint32_t value, int* mb, int* me) {
int mask_width = base::bits::CountPopulation(value);
@@ -1681,7 +1680,7 @@ void VisitWordCompare(InstructionSelector* selector, Node* node,
return VisitLoadAndTest(selector, load_and_test, node, left, cont, true);
}
- inputs[input_count++] = g.UseRegisterOrStackPointer(left);
+ inputs[input_count++] = g.UseRegister(left);
if (g.CanBeMemoryOperand(opcode, node, right, effect_level)) {
// generate memory operand
AddressingMode addressing_mode = g.GetEffectiveAddressMemoryOperand(
@@ -2008,6 +2007,9 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
// doesn't generate cc, so ignore
break;
#endif
+ case IrOpcode::kStackPointerGreaterThan:
+ cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
+ return VisitStackPointerGreaterThan(value, cont);
default:
break;
}
@@ -2689,6 +2691,8 @@ void InstructionSelector::VisitF32x4Sub(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF32x4Mul(Node* node) { UNIMPLEMENTED(); }
+void InstructionSelector::VisitF32x4Div(Node* node) { UNIMPLEMENTED(); }
+
void InstructionSelector::VisitF32x4Min(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitF32x4Max(Node* node) { UNIMPLEMENTED(); }
diff --git a/deps/v8/src/compiler/backend/x64/code-generator-x64.cc b/deps/v8/src/compiler/backend/x64/code-generator-x64.cc
index a108edeff0..a4f82b153b 100644
--- a/deps/v8/src/compiler/backend/x64/code-generator-x64.cc
+++ b/deps/v8/src/compiler/backend/x64/code-generator-x64.cc
@@ -155,10 +155,18 @@ class X64OperandConverter : public InstructionOperandConverter {
namespace {
+bool HasAddressingMode(Instruction* instr) {
+ return instr->addressing_mode() != kMode_None;
+}
+
bool HasImmediateInput(Instruction* instr, size_t index) {
return instr->InputAt(index)->IsImmediate();
}
+bool HasRegisterInput(Instruction* instr, size_t index) {
+ return instr->InputAt(index)->IsRegister();
+}
+
class OutOfLineLoadFloat32NaN final : public OutOfLineCode {
public:
OutOfLineLoadFloat32NaN(CodeGenerator* gen, XMMRegister result)
@@ -210,6 +218,10 @@ class OutOfLineTruncateDoubleToI final : public OutOfLineCode {
// Just encode the stub index. This will be patched when the code
// is added to the native module and copied into wasm code space.
__ near_call(wasm::WasmCode::kDoubleToI, RelocInfo::WASM_STUB_CALL);
+ } else if (tasm()->options().inline_offheap_trampolines) {
+ // With embedded builtins we do not need the isolate here. This allows
+ // the call to be generated asynchronously.
+ __ CallBuiltin(Builtins::kDoubleToI);
} else {
__ Call(BUILTIN_CODE(isolate_, DoubleToI), RelocInfo::CODE_TARGET);
}
@@ -380,60 +392,60 @@ void EmitWordLoadPoisoningIfNeeded(
} \
} while (false)
-#define ASSEMBLE_BINOP(asm_instr) \
- do { \
- if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \
- size_t index = 1; \
- Operand right = i.MemoryOperand(&index); \
- __ asm_instr(i.InputRegister(0), right); \
- } else { \
- if (HasImmediateInput(instr, 1)) { \
- if (instr->InputAt(0)->IsRegister()) { \
- __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
- } else { \
- __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
- } \
- } else { \
- if (instr->InputAt(1)->IsRegister()) { \
- __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
- } else { \
- __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
- } \
- } \
- } \
+#define ASSEMBLE_BINOP(asm_instr) \
+ do { \
+ if (HasAddressingMode(instr)) { \
+ size_t index = 1; \
+ Operand right = i.MemoryOperand(&index); \
+ __ asm_instr(i.InputRegister(0), right); \
+ } else { \
+ if (HasImmediateInput(instr, 1)) { \
+ if (HasRegisterInput(instr, 0)) { \
+ __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
+ } else { \
+ __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
+ } \
+ } else { \
+ if (HasRegisterInput(instr, 1)) { \
+ __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
+ } else { \
+ __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
+ } \
+ } \
+ } \
} while (false)
-#define ASSEMBLE_COMPARE(asm_instr) \
- do { \
- if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \
- size_t index = 0; \
- Operand left = i.MemoryOperand(&index); \
- if (HasImmediateInput(instr, index)) { \
- __ asm_instr(left, i.InputImmediate(index)); \
- } else { \
- __ asm_instr(left, i.InputRegister(index)); \
- } \
- } else { \
- if (HasImmediateInput(instr, 1)) { \
- if (instr->InputAt(0)->IsRegister()) { \
- __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
- } else { \
- __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
- } \
- } else { \
- if (instr->InputAt(1)->IsRegister()) { \
- __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
- } else { \
- __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
- } \
- } \
- } \
+#define ASSEMBLE_COMPARE(asm_instr) \
+ do { \
+ if (HasAddressingMode(instr)) { \
+ size_t index = 0; \
+ Operand left = i.MemoryOperand(&index); \
+ if (HasImmediateInput(instr, index)) { \
+ __ asm_instr(left, i.InputImmediate(index)); \
+ } else { \
+ __ asm_instr(left, i.InputRegister(index)); \
+ } \
+ } else { \
+ if (HasImmediateInput(instr, 1)) { \
+ if (HasRegisterInput(instr, 0)) { \
+ __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \
+ } else { \
+ __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \
+ } \
+ } else { \
+ if (HasRegisterInput(instr, 1)) { \
+ __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \
+ } else { \
+ __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \
+ } \
+ } \
+ } \
} while (false)
#define ASSEMBLE_MULT(asm_instr) \
do { \
if (HasImmediateInput(instr, 1)) { \
- if (instr->InputAt(0)->IsRegister()) { \
+ if (HasRegisterInput(instr, 0)) { \
__ asm_instr(i.OutputRegister(), i.InputRegister(0), \
i.InputImmediate(1)); \
} else { \
@@ -441,7 +453,7 @@ void EmitWordLoadPoisoningIfNeeded(
i.InputImmediate(1)); \
} \
} else { \
- if (instr->InputAt(1)->IsRegister()) { \
+ if (HasRegisterInput(instr, 1)) { \
__ asm_instr(i.OutputRegister(), i.InputRegister(1)); \
} else { \
__ asm_instr(i.OutputRegister(), i.InputOperand(1)); \
@@ -468,9 +480,9 @@ void EmitWordLoadPoisoningIfNeeded(
#define ASSEMBLE_MOVX(asm_instr) \
do { \
- if (instr->addressing_mode() != kMode_None) { \
+ if (HasAddressingMode(instr)) { \
__ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
- } else if (instr->InputAt(0)->IsRegister()) { \
+ } else if (HasRegisterInput(instr, 0)) { \
__ asm_instr(i.OutputRegister(), i.InputRegister(0)); \
} else { \
__ asm_instr(i.OutputRegister(), i.InputOperand(0)); \
@@ -576,17 +588,18 @@ void EmitWordLoadPoisoningIfNeeded(
__ opcode(i.OutputSimd128Register(), i.InputSimd128Register(1), imm); \
} while (false)
-#define ASSEMBLE_SIMD_ALL_TRUE(opcode) \
- do { \
- CpuFeatureScope sse_scope(tasm(), SSE4_1); \
- Register dst = i.OutputRegister(); \
- Register tmp = i.TempRegister(0); \
- __ movq(tmp, Immediate(1)); \
- __ xorq(dst, dst); \
- __ pxor(kScratchDoubleReg, kScratchDoubleReg); \
- __ opcode(kScratchDoubleReg, i.InputSimd128Register(0)); \
- __ ptest(kScratchDoubleReg, kScratchDoubleReg); \
- __ cmovq(zero, dst, tmp); \
+#define ASSEMBLE_SIMD_ALL_TRUE(opcode) \
+ do { \
+ CpuFeatureScope sse_scope(tasm(), SSE4_1); \
+ Register dst = i.OutputRegister(); \
+ Register tmp1 = i.TempRegister(0); \
+ XMMRegister tmp2 = i.TempSimd128Register(1); \
+ __ movq(tmp1, Immediate(1)); \
+ __ xorq(dst, dst); \
+ __ pxor(tmp2, tmp2); \
+ __ opcode(tmp2, i.InputSimd128Register(0)); \
+ __ ptest(tmp2, tmp2); \
+ __ cmovq(zero, dst, tmp1); \
} while (false)
void CodeGenerator::AssembleDeconstructFrame() {
@@ -989,10 +1002,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// don't emit code for nops.
break;
case kArchDeoptimize: {
- int deopt_state_id =
+ DeoptimizationExit* exit =
BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
- CodeGenResult result =
- AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
+ CodeGenResult result = AssembleDeoptimizerCall(exit);
if (result != kSuccess) return result;
unwinding_info_writer_.MarkBlockWillExit();
break;
@@ -1000,9 +1012,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchRet:
AssembleReturn(instr->InputAt(0));
break;
- case kArchStackPointer:
- __ movq(i.OutputRegister(), rsp);
- break;
case kArchFramePointer:
__ movq(i.OutputRegister(), rbp);
break;
@@ -1013,6 +1022,15 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ movq(i.OutputRegister(), rbp);
}
break;
+ case kArchStackPointerGreaterThan: {
+ constexpr size_t kValueIndex = 0;
+ if (HasAddressingMode(instr)) {
+ __ cmpq(rsp, i.MemoryOperand(kValueIndex));
+ } else {
+ __ cmpq(rsp, i.InputRegister(kValueIndex));
+ }
+ break;
+ }
case kArchTruncateDoubleToI: {
auto result = i.OutputRegister();
auto input = i.InputDoubleRegister(0);
@@ -1176,14 +1194,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ASSEMBLE_MULT(imulq);
break;
case kX64ImulHigh32:
- if (instr->InputAt(1)->IsRegister()) {
+ if (HasRegisterInput(instr, 1)) {
__ imull(i.InputRegister(1));
} else {
__ imull(i.InputOperand(1));
}
break;
case kX64UmulHigh32:
- if (instr->InputAt(1)->IsRegister()) {
+ if (HasRegisterInput(instr, 1)) {
__ mull(i.InputRegister(1));
} else {
__ mull(i.InputOperand(1));
@@ -1254,42 +1272,42 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ASSEMBLE_SHIFT(rorq, 6);
break;
case kX64Lzcnt:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Lzcntq(i.OutputRegister(), i.InputRegister(0));
} else {
__ Lzcntq(i.OutputRegister(), i.InputOperand(0));
}
break;
case kX64Lzcnt32:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Lzcntl(i.OutputRegister(), i.InputRegister(0));
} else {
__ Lzcntl(i.OutputRegister(), i.InputOperand(0));
}
break;
case kX64Tzcnt:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Tzcntq(i.OutputRegister(), i.InputRegister(0));
} else {
__ Tzcntq(i.OutputRegister(), i.InputOperand(0));
}
break;
case kX64Tzcnt32:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Tzcntl(i.OutputRegister(), i.InputRegister(0));
} else {
__ Tzcntl(i.OutputRegister(), i.InputOperand(0));
}
break;
case kX64Popcnt:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Popcntq(i.OutputRegister(), i.InputRegister(0));
} else {
__ Popcntq(i.OutputRegister(), i.InputOperand(0));
}
break;
case kX64Popcnt32:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Popcntl(i.OutputRegister(), i.InputRegister(0));
} else {
__ Popcntl(i.OutputRegister(), i.InputOperand(0));
@@ -1321,16 +1339,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
case kSSEFloat32Abs: {
// TODO(bmeurer): Use RIP relative 128-bit constants.
- __ Pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
- __ Psrlq(kScratchDoubleReg, 33);
- __ Andps(i.OutputDoubleRegister(), kScratchDoubleReg);
+ XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
+ __ Pcmpeqd(tmp, tmp);
+ __ Psrlq(tmp, 33);
+ __ Andps(i.OutputDoubleRegister(), tmp);
break;
}
case kSSEFloat32Neg: {
// TODO(bmeurer): Use RIP relative 128-bit constants.
- __ Pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
- __ Psllq(kScratchDoubleReg, 31);
- __ Xorps(i.OutputDoubleRegister(), kScratchDoubleReg);
+ XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
+ __ Pcmpeqd(tmp, tmp);
+ __ Psllq(tmp, 31);
+ __ Xorps(i.OutputDoubleRegister(), tmp);
break;
}
case kSSEFloat32Sqrt:
@@ -1532,17 +1552,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kX64F64x2Abs:
case kSSEFloat64Abs: {
// TODO(bmeurer): Use RIP relative 128-bit constants.
- __ Pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
- __ Psrlq(kScratchDoubleReg, 1);
- __ Andpd(i.OutputDoubleRegister(), kScratchDoubleReg);
+ XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
+ __ Pcmpeqd(tmp, tmp);
+ __ Psrlq(tmp, 1);
+ __ Andpd(i.OutputDoubleRegister(), tmp);
break;
}
case kX64F64x2Neg:
case kSSEFloat64Neg: {
// TODO(bmeurer): Use RIP relative 128-bit constants.
- __ Pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
- __ Psllq(kScratchDoubleReg, 63);
- __ Xorpd(i.OutputDoubleRegister(), kScratchDoubleReg);
+ XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
+ __ Pcmpeqd(tmp, tmp);
+ __ Psllq(tmp, 63);
+ __ Xorpd(i.OutputDoubleRegister(), tmp);
break;
}
case kSSEFloat64Sqrt:
@@ -1659,56 +1681,56 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kSSEInt32ToFloat64:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Cvtlsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kSSEInt32ToFloat32:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Cvtlsi2ss(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Cvtlsi2ss(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kSSEInt64ToFloat32:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Cvtqsi2ss(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Cvtqsi2ss(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kSSEInt64ToFloat64:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Cvtqsi2sd(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Cvtqsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kSSEUint64ToFloat32:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Cvtqui2ss(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Cvtqui2ss(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kSSEUint64ToFloat64:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Cvtqui2sd(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Cvtqui2sd(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kSSEUint32ToFloat64:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Cvtlui2sd(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Cvtlui2sd(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kSSEUint32ToFloat32:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Cvtlui2ss(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Cvtlui2ss(i.OutputDoubleRegister(), i.InputOperand(0));
@@ -1729,21 +1751,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
break;
case kSSEFloat64InsertLowWord32:
- if (instr->InputAt(1)->IsRegister()) {
+ if (HasRegisterInput(instr, 1)) {
__ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 0);
} else {
__ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 0);
}
break;
case kSSEFloat64InsertHighWord32:
- if (instr->InputAt(1)->IsRegister()) {
+ if (HasRegisterInput(instr, 1)) {
__ Pinsrd(i.OutputDoubleRegister(), i.InputRegister(1), 1);
} else {
__ Pinsrd(i.OutputDoubleRegister(), i.InputOperand(1), 1);
}
break;
case kSSEFloat64LoadLowWord32:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Movd(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Movd(i.OutputDoubleRegister(), i.InputOperand(0));
@@ -1800,56 +1822,52 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kAVXFloat32Abs: {
// TODO(bmeurer): Use RIP relative 128-bit constants.
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
- __ vpsrlq(kScratchDoubleReg, kScratchDoubleReg, 33);
+ XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
+ __ vpcmpeqd(tmp, tmp, tmp);
+ __ vpsrlq(tmp, tmp, 33);
if (instr->InputAt(0)->IsFPRegister()) {
- __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
- i.InputDoubleRegister(0));
+ __ vandps(i.OutputDoubleRegister(), tmp, i.InputDoubleRegister(0));
} else {
- __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg,
- i.InputOperand(0));
+ __ vandps(i.OutputDoubleRegister(), tmp, i.InputOperand(0));
}
break;
}
case kAVXFloat32Neg: {
// TODO(bmeurer): Use RIP relative 128-bit constants.
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
- __ vpsllq(kScratchDoubleReg, kScratchDoubleReg, 31);
+ XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
+ __ vpcmpeqd(tmp, tmp, tmp);
+ __ vpsllq(tmp, tmp, 31);
if (instr->InputAt(0)->IsFPRegister()) {
- __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
- i.InputDoubleRegister(0));
+ __ vxorps(i.OutputDoubleRegister(), tmp, i.InputDoubleRegister(0));
} else {
- __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg,
- i.InputOperand(0));
+ __ vxorps(i.OutputDoubleRegister(), tmp, i.InputOperand(0));
}
break;
}
case kAVXFloat64Abs: {
// TODO(bmeurer): Use RIP relative 128-bit constants.
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
- __ vpsrlq(kScratchDoubleReg, kScratchDoubleReg, 1);
+ XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
+ __ vpcmpeqd(tmp, tmp, tmp);
+ __ vpsrlq(tmp, tmp, 1);
if (instr->InputAt(0)->IsFPRegister()) {
- __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
- i.InputDoubleRegister(0));
+ __ vandpd(i.OutputDoubleRegister(), tmp, i.InputDoubleRegister(0));
} else {
- __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg,
- i.InputOperand(0));
+ __ vandpd(i.OutputDoubleRegister(), tmp, i.InputOperand(0));
}
break;
}
case kAVXFloat64Neg: {
// TODO(bmeurer): Use RIP relative 128-bit constants.
CpuFeatureScope avx_scope(tasm(), AVX);
- __ vpcmpeqd(kScratchDoubleReg, kScratchDoubleReg, kScratchDoubleReg);
- __ vpsllq(kScratchDoubleReg, kScratchDoubleReg, 63);
+ XMMRegister tmp = i.ToDoubleRegister(instr->TempAt(0));
+ __ vpcmpeqd(tmp, tmp, tmp);
+ __ vpsllq(tmp, tmp, 63);
if (instr->InputAt(0)->IsFPRegister()) {
- __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
- i.InputDoubleRegister(0));
+ __ vxorpd(i.OutputDoubleRegister(), tmp, i.InputDoubleRegister(0));
} else {
- __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg,
- i.InputOperand(0));
+ __ vxorpd(i.OutputDoubleRegister(), tmp, i.InputOperand(0));
}
break;
}
@@ -1929,14 +1947,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kX64Movl:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, i, __ pc_offset());
if (instr->HasOutput()) {
- if (instr->addressing_mode() == kMode_None) {
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasAddressingMode(instr)) {
+ __ movl(i.OutputRegister(), i.MemoryOperand());
+ } else {
+ if (HasRegisterInput(instr, 0)) {
__ movl(i.OutputRegister(), i.InputRegister(0));
} else {
__ movl(i.OutputRegister(), i.InputOperand(0));
}
- } else {
- __ movl(i.OutputRegister(), i.MemoryOperand());
}
__ AssertZeroExtended(i.OutputRegister());
} else {
@@ -2002,12 +2020,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
EmitWordLoadPoisoningIfNeeded(this, opcode, instr, i);
break;
}
- case kX64CompressSigned: // Fall through.
- case kX64CompressPointer: // Fall through.
- case kX64CompressAny: {
- ASSEMBLE_MOVX(movl);
- break;
- }
case kX64Movq:
EmitOOLTrapIfNeeded(zone(), this, opcode, instr, i, __ pc_offset());
if (instr->HasOutput()) {
@@ -2082,14 +2094,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
break;
case kX64BitcastIF:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Movd(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Movss(i.OutputDoubleRegister(), i.InputOperand(0));
}
break;
case kX64BitcastLD:
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ Movq(i.OutputDoubleRegister(), i.InputRegister(0));
} else {
__ Movsd(i.OutputDoubleRegister(), i.InputOperand(0));
@@ -2177,7 +2189,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ incl(i.OutputRegister());
break;
case kX64Push:
- if (AddressingModeField::decode(instr->opcode()) != kMode_None) {
+ if (HasAddressingMode(instr)) {
size_t index = 0;
Operand operand = i.MemoryOperand(&index);
__ pushq(operand);
@@ -2189,7 +2201,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
frame_access_state()->IncreaseSPDelta(1);
unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
kSystemPointerSize);
- } else if (instr->InputAt(0)->IsRegister()) {
+ } else if (HasRegisterInput(instr, 0)) {
__ pushq(i.InputRegister(0));
frame_access_state()->IncreaseSPDelta(1);
unwinding_info_writer_.MaybeIncreaseBaseOffsetAt(__ pc_offset(),
@@ -2256,11 +2268,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64F64x2Splat: {
+ CpuFeatureScope sse_scope(tasm(), SSE3);
XMMRegister dst = i.OutputSimd128Register();
if (instr->InputAt(0)->IsFPRegister()) {
- __ pshufd(dst, i.InputDoubleRegister(0), 0x44);
+ __ movddup(dst, i.InputDoubleRegister(0));
} else {
- __ pshufd(dst, i.InputOperand(0), 0x44);
+ __ movddup(dst, i.InputOperand(0));
}
break;
}
@@ -2280,6 +2293,61 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ movq(i.OutputDoubleRegister(), kScratchRegister);
break;
}
+ case kX64F64x2Add: {
+ ASSEMBLE_SSE_BINOP(addpd);
+ break;
+ }
+ case kX64F64x2Sub: {
+ ASSEMBLE_SSE_BINOP(subpd);
+ break;
+ }
+ case kX64F64x2Mul: {
+ ASSEMBLE_SSE_BINOP(mulpd);
+ break;
+ }
+ case kX64F64x2Div: {
+ ASSEMBLE_SSE_BINOP(divpd);
+ break;
+ }
+ case kX64F64x2Min: {
+ XMMRegister src1 = i.InputSimd128Register(1),
+ dst = i.OutputSimd128Register();
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ // The minpd instruction doesn't propagate NaNs and +0's in its first
+ // operand. Perform minpd in both orders, merge the resuls, and adjust.
+ __ movapd(kScratchDoubleReg, src1);
+ __ minpd(kScratchDoubleReg, dst);
+ __ minpd(dst, src1);
+ // propagate -0's and NaNs, which may be non-canonical.
+ __ orpd(kScratchDoubleReg, dst);
+ // Canonicalize NaNs by quieting and clearing the payload.
+ __ cmppd(dst, kScratchDoubleReg, 3);
+ __ orpd(kScratchDoubleReg, dst);
+ __ psrlq(dst, 13);
+ __ andnpd(dst, kScratchDoubleReg);
+ break;
+ }
+ case kX64F64x2Max: {
+ XMMRegister src1 = i.InputSimd128Register(1),
+ dst = i.OutputSimd128Register();
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ // The maxpd instruction doesn't propagate NaNs and +0's in its first
+ // operand. Perform maxpd in both orders, merge the resuls, and adjust.
+ __ movapd(kScratchDoubleReg, src1);
+ __ maxpd(kScratchDoubleReg, dst);
+ __ maxpd(dst, src1);
+ // Find discrepancies.
+ __ xorpd(dst, kScratchDoubleReg);
+ // Propagate NaNs, which may be non-canonical.
+ __ orpd(kScratchDoubleReg, dst);
+ // Propagate sign discrepancy and (subtle) quiet NaNs.
+ __ subpd(kScratchDoubleReg, dst);
+ // Canonicalize NaNs by clearing the payload. Sign is non-deterministic.
+ __ cmppd(dst, kScratchDoubleReg, 3);
+ __ psrlq(dst, 13);
+ __ andnpd(dst, kScratchDoubleReg);
+ break;
+ }
case kX64F64x2Eq: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
__ cmpeqpd(i.OutputSimd128Register(), i.InputSimd128Register(1));
@@ -2406,6 +2474,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ mulps(i.OutputSimd128Register(), i.InputSimd128Register(1));
break;
}
+ case kX64F32x4Div: {
+ DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
+ __ divps(i.OutputSimd128Register(), i.InputSimd128Register(1));
+ break;
+ }
case kX64F32x4Min: {
XMMRegister src1 = i.InputSimd128Register(1),
dst = i.OutputSimd128Register();
@@ -2466,13 +2539,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I64x2Splat: {
+ CpuFeatureScope sse_scope(tasm(), SSE3);
XMMRegister dst = i.OutputSimd128Register();
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ movq(dst, i.InputRegister(0));
} else {
__ movq(dst, i.InputOperand(0));
}
- __ pshufd(dst, dst, 0x44);
+ __ movddup(dst, dst);
break;
}
case kX64I64x2ExtractLane: {
@@ -2482,7 +2556,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kX64I64x2ReplaceLane: {
CpuFeatureScope sse_scope(tasm(), SSE4_1);
- if (instr->InputAt(2)->IsRegister()) {
+ if (HasRegisterInput(instr, 2)) {
__ pinsrq(i.OutputSimd128Register(), i.InputRegister(2),
i.InputInt8(1));
} else {
@@ -2502,7 +2576,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I64x2Shl: {
- __ psllq(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movq(tmp, i.InputRegister(1));
+ __ psllq(i.OutputSimd128Register(), tmp);
break;
}
case kX64I64x2ShrS: {
@@ -2511,16 +2587,17 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
// ShrS on each quadword one at a time
XMMRegister dst = i.OutputSimd128Register();
XMMRegister src = i.InputSimd128Register(0);
+ Register tmp = i.ToRegister(instr->TempAt(0));
// lower quadword
- __ pextrq(kScratchRegister, src, 0x0);
- __ sarq(kScratchRegister, Immediate(i.InputInt8(1)));
- __ pinsrq(dst, kScratchRegister, 0x0);
+ __ pextrq(tmp, src, 0x0);
+ __ sarq_cl(tmp);
+ __ pinsrq(dst, tmp, 0x0);
// upper quadword
- __ pextrq(kScratchRegister, src, 0x1);
- __ sarq(kScratchRegister, Immediate(i.InputInt8(1)));
- __ pinsrq(dst, kScratchRegister, 0x1);
+ __ pextrq(tmp, src, 0x1);
+ __ sarq_cl(tmp);
+ __ pinsrq(dst, tmp, 0x1);
break;
}
case kX64I64x2Add: {
@@ -2538,8 +2615,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
CpuFeatureScope sse_scope(tasm(), SSE4_1);
XMMRegister left = i.InputSimd128Register(0);
XMMRegister right = i.InputSimd128Register(1);
- XMMRegister tmp1 = i.ToSimd128Register(instr->TempAt(0));
- XMMRegister tmp2 = i.ToSimd128Register(instr->TempAt(1));
+ XMMRegister tmp1 = i.TempSimd128Register(0);
+ XMMRegister tmp2 = i.TempSimd128Register(1);
__ movaps(tmp1, left);
__ movaps(tmp2, right);
@@ -2559,6 +2636,66 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ paddq(left, tmp2); // left == dst
break;
}
+ case kX64I64x2MinS: {
+ if (CpuFeatures::IsSupported(SSE4_2)) {
+ CpuFeatureScope sse_scope_4_2(tasm(), SSE4_2);
+ XMMRegister dst = i.OutputSimd128Register();
+ XMMRegister src = i.InputSimd128Register(1);
+ XMMRegister tmp = i.TempSimd128Register(0);
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ DCHECK_EQ(src, xmm0);
+
+ __ movaps(tmp, src);
+ __ pcmpgtq(src, dst);
+ __ blendvpd(tmp, dst); // implicit use of xmm0 as mask
+ __ movaps(dst, tmp);
+ } else {
+ CpuFeatureScope sse_scope_4_1(tasm(), SSE4_1);
+ XMMRegister dst = i.OutputSimd128Register();
+ XMMRegister src = i.InputSimd128Register(1);
+ XMMRegister tmp = i.TempSimd128Register(0);
+ Register tmp1 = i.TempRegister(1);
+ Register tmp2 = i.TempRegister(2);
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ // backup src since we cannot change it
+ __ movaps(tmp, src);
+
+ // compare the lower quardwords
+ __ movq(tmp1, dst);
+ __ movq(tmp2, tmp);
+ __ cmpq(tmp1, tmp2);
+ // tmp2 now has the min of lower quadwords
+ __ cmovq(less_equal, tmp2, tmp1);
+ // tmp1 now has the higher quadword
+ // must do this before movq, movq clears top quadword
+ __ pextrq(tmp1, dst, 1);
+ // save tmp2 into dst
+ __ movq(dst, tmp2);
+ // tmp2 now has the higher quadword
+ __ pextrq(tmp2, tmp, 1);
+ // compare higher quadwords
+ __ cmpq(tmp1, tmp2);
+ // tmp2 now has the min of higher quadwords
+ __ cmovq(less_equal, tmp2, tmp1);
+ __ movq(tmp, tmp2);
+ // dst = [tmp[0], dst[0]]
+ __ punpcklqdq(dst, tmp);
+ }
+ break;
+ }
+ case kX64I64x2MaxS: {
+ CpuFeatureScope sse_scope_4_2(tasm(), SSE4_2);
+ XMMRegister dst = i.OutputSimd128Register();
+ XMMRegister src = i.InputSimd128Register(1);
+ XMMRegister tmp = i.TempSimd128Register(0);
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ DCHECK_EQ(src, xmm0);
+
+ __ movaps(tmp, src);
+ __ pcmpgtq(src, dst);
+ __ blendvpd(dst, tmp); // implicit use of xmm0 as mask
+ break;
+ }
case kX64I64x2Eq: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
CpuFeatureScope sse_scope(tasm(), SSE4_1);
@@ -2568,9 +2705,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kX64I64x2Ne: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
CpuFeatureScope sse_scope(tasm(), SSE4_1);
+ XMMRegister tmp = i.TempSimd128Register(0);
__ pcmpeqq(i.OutputSimd128Register(), i.InputSimd128Register(1));
- __ pcmpeqq(kScratchDoubleReg, kScratchDoubleReg);
- __ pxor(i.OutputSimd128Register(), kScratchDoubleReg);
+ __ pcmpeqq(tmp, tmp);
+ __ pxor(i.OutputSimd128Register(), tmp);
break;
}
case kX64I64x2GtS: {
@@ -2584,7 +2722,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
CpuFeatureScope sse_scope(tasm(), SSE4_2);
XMMRegister dst = i.OutputSimd128Register();
XMMRegister src = i.InputSimd128Register(1);
- XMMRegister tmp = i.ToSimd128Register(instr->TempAt(0));
+ XMMRegister tmp = i.TempSimd128Register(0);
__ movaps(tmp, src);
__ pcmpgtq(tmp, dst);
@@ -2593,7 +2731,56 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I64x2ShrU: {
- __ psrlq(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movq(tmp, i.InputRegister(1));
+ __ psrlq(i.OutputSimd128Register(), tmp);
+ break;
+ }
+ case kX64I64x2MinU: {
+ CpuFeatureScope sse_scope_4_2(tasm(), SSE4_2);
+ CpuFeatureScope sse_scope_4_1(tasm(), SSE4_1);
+ XMMRegister dst = i.OutputSimd128Register();
+ XMMRegister src = i.InputSimd128Register(1);
+ XMMRegister src_tmp = i.TempSimd128Register(0);
+ XMMRegister dst_tmp = i.TempSimd128Register(1);
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ DCHECK_EQ(src, xmm0);
+
+ __ movaps(src_tmp, src);
+ __ movaps(dst_tmp, dst);
+
+ __ pcmpeqd(src, src);
+ __ psllq(src, 63);
+
+ __ pxor(dst_tmp, src);
+ __ pxor(src, src_tmp);
+
+ __ pcmpgtq(src, dst_tmp);
+ __ blendvpd(src_tmp, dst); // implicit use of xmm0 as mask
+ __ movaps(dst, src_tmp);
+ break;
+ }
+ case kX64I64x2MaxU: {
+ CpuFeatureScope sse_scope_4_2(tasm(), SSE4_2);
+ CpuFeatureScope sse_scope_4_1(tasm(), SSE4_1);
+ XMMRegister dst = i.OutputSimd128Register();
+ XMMRegister src = i.InputSimd128Register(1);
+ XMMRegister src_tmp = i.TempSimd128Register(0);
+ XMMRegister dst_tmp = i.TempSimd128Register(1);
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ DCHECK_EQ(src, xmm0);
+
+ __ movaps(src_tmp, src);
+ __ movaps(dst_tmp, dst);
+
+ __ pcmpeqd(src, src);
+ __ psllq(src, 63);
+
+ __ pxor(dst_tmp, src);
+ __ pxor(src, src_tmp);
+
+ __ pcmpgtq(src, dst_tmp);
+ __ blendvpd(dst, src_tmp); // implicit use of xmm0 as mask
break;
}
case kX64I64x2GtU: {
@@ -2601,7 +2788,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
CpuFeatureScope sse_scope(tasm(), SSE4_2);
XMMRegister dst = i.OutputSimd128Register();
XMMRegister src = i.InputSimd128Register(1);
- XMMRegister tmp = i.ToSimd128Register(instr->TempAt(0));
+ XMMRegister tmp = i.TempSimd128Register(0);
__ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
__ psllq(kScratchDoubleReg, 63);
@@ -2617,7 +2804,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
CpuFeatureScope sse_scope(tasm(), SSE4_2);
XMMRegister dst = i.OutputSimd128Register();
XMMRegister src = i.InputSimd128Register(1);
- XMMRegister tmp = i.ToSimd128Register(instr->TempAt(0));
+ XMMRegister tmp = i.TempSimd128Register(0);
__ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
__ psllq(kScratchDoubleReg, 63);
@@ -2632,7 +2819,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kX64I32x4Splat: {
XMMRegister dst = i.OutputSimd128Register();
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ movd(dst, i.InputRegister(0));
} else {
__ movd(dst, i.InputOperand(0));
@@ -2647,7 +2834,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kX64I32x4ReplaceLane: {
CpuFeatureScope sse_scope(tasm(), SSE4_1);
- if (instr->InputAt(2)->IsRegister()) {
+ if (HasRegisterInput(instr, 2)) {
__ Pinsrd(i.OutputSimd128Register(), i.InputRegister(2),
i.InputInt8(1));
} else {
@@ -2658,19 +2845,20 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kX64I32x4SConvertF32x4: {
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
XMMRegister dst = i.OutputSimd128Register();
+ XMMRegister tmp = i.TempSimd128Register(0);
// NAN->0
- __ movaps(kScratchDoubleReg, dst);
- __ cmpeqps(kScratchDoubleReg, kScratchDoubleReg);
- __ pand(dst, kScratchDoubleReg);
+ __ movaps(tmp, dst);
+ __ cmpeqps(tmp, tmp);
+ __ pand(dst, tmp);
// Set top bit if >= 0 (but not -0.0!)
- __ pxor(kScratchDoubleReg, dst);
+ __ pxor(tmp, dst);
// Convert
__ cvttps2dq(dst, dst);
// Set top bit if >=0 is now < 0
- __ pand(kScratchDoubleReg, dst);
- __ psrad(kScratchDoubleReg, 31);
+ __ pand(tmp, dst);
+ __ psrad(tmp, 31);
// Set positive overflow lanes to 0x7FFFFFFF
- __ pxor(dst, kScratchDoubleReg);
+ __ pxor(dst, tmp);
break;
}
case kX64I32x4SConvertI16x8Low: {
@@ -2699,11 +2887,15 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I32x4Shl: {
- __ pslld(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movq(tmp, i.InputRegister(1));
+ __ pslld(i.OutputSimd128Register(), tmp);
break;
}
case kX64I32x4ShrS: {
- __ psrad(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movq(tmp, i.InputRegister(1));
+ __ psrad(i.OutputSimd128Register(), tmp);
break;
}
case kX64I32x4Add: {
@@ -2739,9 +2931,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I32x4Ne: {
+ XMMRegister tmp = i.TempSimd128Register(0);
__ pcmpeqd(i.OutputSimd128Register(), i.InputSimd128Register(1));
- __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
- __ pxor(i.OutputSimd128Register(), kScratchDoubleReg);
+ __ pcmpeqd(tmp, tmp);
+ __ pxor(i.OutputSimd128Register(), tmp);
break;
}
case kX64I32x4GtS: {
@@ -2760,24 +2953,25 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
CpuFeatureScope sse_scope(tasm(), SSE4_1);
XMMRegister dst = i.OutputSimd128Register();
- XMMRegister tmp = i.ToSimd128Register(instr->TempAt(0));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ XMMRegister tmp2 = i.TempSimd128Register(1);
// NAN->0, negative->0
- __ pxor(kScratchDoubleReg, kScratchDoubleReg);
- __ maxps(dst, kScratchDoubleReg);
+ __ pxor(tmp2, tmp2);
+ __ maxps(dst, tmp2);
// scratch: float representation of max_signed
- __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
- __ psrld(kScratchDoubleReg, 1); // 0x7fffffff
- __ cvtdq2ps(kScratchDoubleReg, kScratchDoubleReg); // 0x4f000000
+ __ pcmpeqd(tmp2, tmp2);
+ __ psrld(tmp2, 1); // 0x7fffffff
+ __ cvtdq2ps(tmp2, tmp2); // 0x4f000000
// tmp: convert (src-max_signed).
// Positive overflow lanes -> 0x7FFFFFFF
// Negative lanes -> 0
__ movaps(tmp, dst);
- __ subps(tmp, kScratchDoubleReg);
- __ cmpleps(kScratchDoubleReg, tmp);
+ __ subps(tmp, tmp2);
+ __ cmpleps(tmp2, tmp);
__ cvttps2dq(tmp, tmp);
- __ pxor(tmp, kScratchDoubleReg);
- __ pxor(kScratchDoubleReg, kScratchDoubleReg);
- __ pmaxsd(tmp, kScratchDoubleReg);
+ __ pxor(tmp, tmp2);
+ __ pxor(tmp2, tmp2);
+ __ pmaxsd(tmp, tmp2);
// convert. Overflow lanes above max_signed will be 0x80000000
__ cvttps2dq(dst, dst);
// Add (src-max_signed) for overflow lanes.
@@ -2797,7 +2991,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I32x4ShrU: {
- __ psrld(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movq(tmp, i.InputRegister(1));
+ __ psrld(i.OutputSimd128Register(), tmp);
break;
}
case kX64I32x4MinU: {
@@ -2814,10 +3010,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
CpuFeatureScope sse_scope(tasm(), SSE4_1);
XMMRegister dst = i.OutputSimd128Register();
XMMRegister src = i.InputSimd128Register(1);
+ XMMRegister tmp = i.TempSimd128Register(0);
__ pmaxud(dst, src);
__ pcmpeqd(dst, src);
- __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg);
- __ pxor(dst, kScratchDoubleReg);
+ __ pcmpeqd(tmp, tmp);
+ __ pxor(dst, tmp);
break;
}
case kX64I32x4GeU: {
@@ -2835,7 +3032,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kX64I16x8Splat: {
XMMRegister dst = i.OutputSimd128Register();
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ movd(dst, i.InputRegister(0));
} else {
__ movd(dst, i.InputOperand(0));
@@ -2853,7 +3050,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kX64I16x8ReplaceLane: {
CpuFeatureScope sse_scope(tasm(), SSE4_1);
- if (instr->InputAt(2)->IsRegister()) {
+ if (HasRegisterInput(instr, 2)) {
__ pinsrw(i.OutputSimd128Register(), i.InputRegister(2),
i.InputInt8(1));
} else {
@@ -2887,11 +3084,15 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I16x8Shl: {
- __ psllw(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movq(tmp, i.InputRegister(1));
+ __ psllw(i.OutputSimd128Register(), tmp);
break;
}
case kX64I16x8ShrS: {
- __ psraw(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movq(tmp, i.InputRegister(1));
+ __ psraw(i.OutputSimd128Register(), tmp);
break;
}
case kX64I16x8SConvertI32x4: {
@@ -2940,9 +3141,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I16x8Ne: {
+ XMMRegister tmp = i.TempSimd128Register(0);
__ pcmpeqw(i.OutputSimd128Register(), i.InputSimd128Register(1));
- __ pcmpeqw(kScratchDoubleReg, kScratchDoubleReg);
- __ pxor(i.OutputSimd128Register(), kScratchDoubleReg);
+ __ pcmpeqw(tmp, tmp);
+ __ pxor(i.OutputSimd128Register(), tmp);
break;
}
case kX64I16x8GtS: {
@@ -2970,7 +3172,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I16x8ShrU: {
- __ psrlw(i.OutputSimd128Register(), i.InputInt8(1));
+ XMMRegister tmp = i.TempSimd128Register(0);
+ __ movq(tmp, i.InputRegister(1));
+ __ psrlw(i.OutputSimd128Register(), tmp);
break;
}
case kX64I16x8UConvertI32x4: {
@@ -3007,10 +3211,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
CpuFeatureScope sse_scope(tasm(), SSE4_1);
XMMRegister dst = i.OutputSimd128Register();
XMMRegister src = i.InputSimd128Register(1);
+ XMMRegister tmp = i.TempSimd128Register(0);
__ pmaxuw(dst, src);
__ pcmpeqw(dst, src);
- __ pcmpeqw(kScratchDoubleReg, kScratchDoubleReg);
- __ pxor(dst, kScratchDoubleReg);
+ __ pcmpeqw(tmp, tmp);
+ __ pxor(dst, tmp);
break;
}
case kX64I16x8GeU: {
@@ -3024,7 +3229,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kX64I8x16Splat: {
CpuFeatureScope sse_scope(tasm(), SSSE3);
XMMRegister dst = i.OutputSimd128Register();
- if (instr->InputAt(0)->IsRegister()) {
+ if (HasRegisterInput(instr, 0)) {
__ movd(dst, i.InputRegister(0));
} else {
__ movd(dst, i.InputOperand(0));
@@ -3042,7 +3247,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kX64I8x16ReplaceLane: {
CpuFeatureScope sse_scope(tasm(), SSE4_1);
- if (instr->InputAt(2)->IsRegister()) {
+ if (HasRegisterInput(instr, 2)) {
__ pinsrb(i.OutputSimd128Register(), i.InputRegister(2),
i.InputInt8(1));
} else {
@@ -3071,31 +3276,36 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kX64I8x16Shl: {
XMMRegister dst = i.OutputSimd128Register();
DCHECK_EQ(dst, i.InputSimd128Register(0));
- int8_t shift = i.InputInt8(1) & 0x7;
- if (shift < 4) {
- // For small shifts, doubling is faster.
- for (int i = 0; i < shift; ++i) {
- __ paddb(dst, dst);
- }
- } else {
- // Mask off the unwanted bits before word-shifting.
- __ pcmpeqw(kScratchDoubleReg, kScratchDoubleReg);
- __ psrlw(kScratchDoubleReg, 8 + shift);
- __ packuswb(kScratchDoubleReg, kScratchDoubleReg);
- __ pand(dst, kScratchDoubleReg);
- __ psllw(dst, shift);
- }
+ // Temp registers for shift mask andadditional moves to XMM registers.
+ Register tmp = i.ToRegister(instr->TempAt(0));
+ XMMRegister tmp_simd = i.TempSimd128Register(1);
+ // Mask off the unwanted bits before word-shifting.
+ __ pcmpeqw(kScratchDoubleReg, kScratchDoubleReg);
+ __ movq(tmp, i.InputRegister(1));
+ __ addq(tmp, Immediate(8));
+ __ movq(tmp_simd, tmp);
+ __ psrlw(kScratchDoubleReg, tmp_simd);
+ __ packuswb(kScratchDoubleReg, kScratchDoubleReg);
+ __ pand(dst, kScratchDoubleReg);
+ __ movq(tmp_simd, i.InputRegister(1));
+ __ psllw(dst, tmp_simd);
break;
}
case kX64I8x16ShrS: {
XMMRegister dst = i.OutputSimd128Register();
- XMMRegister src = i.InputSimd128Register(0);
- int8_t shift = i.InputInt8(1) & 0x7;
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ // Temp registers for shift mask andadditional moves to XMM registers.
+ Register tmp = i.ToRegister(instr->TempAt(0));
+ XMMRegister tmp_simd = i.TempSimd128Register(1);
// Unpack the bytes into words, do arithmetic shifts, and repack.
- __ punpckhbw(kScratchDoubleReg, src);
- __ punpcklbw(dst, src);
- __ psraw(kScratchDoubleReg, 8 + shift);
- __ psraw(dst, 8 + shift);
+ __ punpckhbw(kScratchDoubleReg, dst);
+ __ punpcklbw(dst, dst);
+ // Prepare shift value
+ __ movq(tmp, i.InputRegister(1));
+ __ addq(tmp, Immediate(8));
+ __ movq(tmp_simd, tmp);
+ __ psraw(kScratchDoubleReg, tmp_simd);
+ __ psraw(dst, tmp_simd);
__ packsswb(dst, kScratchDoubleReg);
break;
}
@@ -3119,7 +3329,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
XMMRegister dst = i.OutputSimd128Register();
DCHECK_EQ(dst, i.InputSimd128Register(0));
XMMRegister right = i.InputSimd128Register(1);
- XMMRegister tmp = i.ToSimd128Register(instr->TempAt(0));
+ XMMRegister tmp = i.TempSimd128Register(0);
// I16x8 view of I8x16
// left = AAaa AAaa ... AAaa AAaa
// right= BBbb BBbb ... BBbb BBbb
@@ -3163,9 +3373,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
}
case kX64I8x16Ne: {
+ XMMRegister tmp = i.TempSimd128Register(0);
__ pcmpeqb(i.OutputSimd128Register(), i.InputSimd128Register(1));
- __ pcmpeqb(kScratchDoubleReg, kScratchDoubleReg);
- __ pxor(i.OutputSimd128Register(), kScratchDoubleReg);
+ __ pcmpeqb(tmp, tmp);
+ __ pxor(i.OutputSimd128Register(), tmp);
break;
}
case kX64I8x16GtS: {
@@ -3194,13 +3405,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
case kX64I8x16ShrU: {
XMMRegister dst = i.OutputSimd128Register();
- XMMRegister src = i.InputSimd128Register(0);
- int8_t shift = i.InputInt8(1) & 0x7;
// Unpack the bytes into words, do logical shifts, and repack.
- __ punpckhbw(kScratchDoubleReg, src);
- __ punpcklbw(dst, src);
- __ psrlw(kScratchDoubleReg, 8 + shift);
- __ psrlw(dst, 8 + shift);
+ DCHECK_EQ(dst, i.InputSimd128Register(0));
+ // Temp registers for shift mask andadditional moves to XMM registers.
+ Register tmp = i.ToRegister(instr->TempAt(0));
+ XMMRegister tmp_simd = i.TempSimd128Register(1);
+ __ punpckhbw(kScratchDoubleReg, dst);
+ __ punpcklbw(dst, dst);
+ // Prepare shift value
+ __ movq(tmp, i.InputRegister(1));
+ __ addq(tmp, Immediate(8));
+ __ movq(tmp_simd, tmp);
+ __ psrlw(kScratchDoubleReg, tmp_simd);
+ __ psrlw(dst, tmp_simd);
__ packuswb(dst, kScratchDoubleReg);
break;
}
@@ -3226,10 +3443,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
CpuFeatureScope sse_scope(tasm(), SSE4_1);
XMMRegister dst = i.OutputSimd128Register();
XMMRegister src = i.InputSimd128Register(1);
+ XMMRegister tmp = i.TempSimd128Register(0);
__ pmaxub(dst, src);
__ pcmpeqb(dst, src);
- __ pcmpeqb(kScratchDoubleReg, kScratchDoubleReg);
- __ pxor(dst, kScratchDoubleReg);
+ __ pcmpeqb(tmp, tmp);
+ __ pxor(dst, tmp);
break;
}
case kX64I8x16GeU: {
@@ -3561,9 +3779,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ASSEMBLE_SIMD_ALL_TRUE(pcmpeqb);
break;
}
- case kX64StackCheck:
- __ CompareRoot(rsp, RootIndex::kStackLimit);
- break;
case kWord32AtomicExchangeInt8: {
__ xchgb(i.InputRegister(0), i.MemoryOperand(1));
__ movsxbl(i.InputRegister(0), i.InputRegister(0));
@@ -4167,6 +4382,8 @@ void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::FinishCode() { tasm()->PatchConstPool(); }
+void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {}
+
void CodeGenerator::AssembleMove(InstructionOperand* source,
InstructionOperand* destination) {
X64OperandConverter g(this, nullptr);
diff --git a/deps/v8/src/compiler/backend/x64/instruction-codes-x64.h b/deps/v8/src/compiler/backend/x64/instruction-codes-x64.h
index d6ac3f43df..8a0a45a916 100644
--- a/deps/v8/src/compiler/backend/x64/instruction-codes-x64.h
+++ b/deps/v8/src/compiler/backend/x64/instruction-codes-x64.h
@@ -140,9 +140,6 @@ namespace compiler {
V(X64DecompressSigned) \
V(X64DecompressPointer) \
V(X64DecompressAny) \
- V(X64CompressSigned) \
- V(X64CompressPointer) \
- V(X64CompressAny) \
V(X64Movq) \
V(X64Movsd) \
V(X64Movss) \
@@ -158,12 +155,17 @@ namespace compiler {
V(X64Push) \
V(X64Poke) \
V(X64Peek) \
- V(X64StackCheck) \
V(X64F64x2Splat) \
V(X64F64x2ExtractLane) \
V(X64F64x2ReplaceLane) \
V(X64F64x2Abs) \
V(X64F64x2Neg) \
+ V(X64F64x2Add) \
+ V(X64F64x2Sub) \
+ V(X64F64x2Mul) \
+ V(X64F64x2Div) \
+ V(X64F64x2Min) \
+ V(X64F64x2Max) \
V(X64F64x2Eq) \
V(X64F64x2Ne) \
V(X64F64x2Lt) \
@@ -181,6 +183,7 @@ namespace compiler {
V(X64F32x4AddHoriz) \
V(X64F32x4Sub) \
V(X64F32x4Mul) \
+ V(X64F32x4Div) \
V(X64F32x4Min) \
V(X64F32x4Max) \
V(X64F32x4Eq) \
@@ -196,11 +199,15 @@ namespace compiler {
V(X64I64x2Add) \
V(X64I64x2Sub) \
V(X64I64x2Mul) \
+ V(X64I64x2MinS) \
+ V(X64I64x2MaxS) \
V(X64I64x2Eq) \
V(X64I64x2Ne) \
V(X64I64x2GtS) \
V(X64I64x2GeS) \
V(X64I64x2ShrU) \
+ V(X64I64x2MinU) \
+ V(X64I64x2MaxU) \
V(X64I64x2GtU) \
V(X64I64x2GeU) \
V(X64I32x4Splat) \
diff --git a/deps/v8/src/compiler/backend/x64/instruction-scheduler-x64.cc b/deps/v8/src/compiler/backend/x64/instruction-scheduler-x64.cc
index 6389ef2e50..e9fa450c38 100644
--- a/deps/v8/src/compiler/backend/x64/instruction-scheduler-x64.cc
+++ b/deps/v8/src/compiler/backend/x64/instruction-scheduler-x64.cc
@@ -129,6 +129,12 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kX64F64x2ReplaceLane:
case kX64F64x2Abs:
case kX64F64x2Neg:
+ case kX64F64x2Add:
+ case kX64F64x2Sub:
+ case kX64F64x2Mul:
+ case kX64F64x2Div:
+ case kX64F64x2Min:
+ case kX64F64x2Max:
case kX64F64x2Eq:
case kX64F64x2Ne:
case kX64F64x2Lt:
@@ -146,6 +152,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kX64F32x4AddHoriz:
case kX64F32x4Sub:
case kX64F32x4Mul:
+ case kX64F32x4Div:
case kX64F32x4Min:
case kX64F32x4Max:
case kX64F32x4Eq:
@@ -161,11 +168,15 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kX64I64x2Add:
case kX64I64x2Sub:
case kX64I64x2Mul:
+ case kX64I64x2MinS:
+ case kX64I64x2MaxS:
case kX64I64x2Eq:
case kX64I64x2Ne:
case kX64I64x2GtS:
case kX64I64x2GeS:
case kX64I64x2ShrU:
+ case kX64I64x2MinU:
+ case kX64I64x2MaxU:
case kX64I64x2GtU:
case kX64I64x2GeU:
case kX64I32x4Splat:
@@ -295,9 +306,6 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kX64DecompressSigned:
case kX64DecompressPointer:
case kX64DecompressAny:
- case kX64CompressSigned:
- case kX64CompressPointer:
- case kX64CompressAny:
return (instr->addressing_mode() == kMode_None)
? kNoOpcodeFlags
: kIsLoadOperation | kHasSideEffect;
@@ -346,7 +354,6 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kX64Movdqu:
return instr->HasOutput() ? kIsLoadOperation : kHasSideEffect;
- case kX64StackCheck:
case kX64Peek:
return kIsLoadOperation;
diff --git a/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc b/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc
index a4908fb846..5379074bac 100644
--- a/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc
+++ b/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc
@@ -170,9 +170,10 @@ class X64OperandGenerator final : public OperandGenerator {
AddressingMode GetEffectiveAddressMemoryOperand(Node* operand,
InstructionOperand inputs[],
size_t* input_count) {
- if (selector()->CanAddressRelativeToRootsRegister()) {
+ {
LoadMatcher<ExternalReferenceMatcher> m(operand);
- if (m.index().HasValue() && m.object().HasValue()) {
+ if (m.index().HasValue() && m.object().HasValue() &&
+ selector()->CanAddressRelativeToRootsRegister(m.object().Value())) {
ptrdiff_t const delta =
m.index().Value() +
TurboAssemblerBase::RootRegisterOffsetForExternalReference(
@@ -350,7 +351,8 @@ void InstructionSelector::VisitStore(Node* node) {
StoreRepresentation store_rep = StoreRepresentationOf(node->op());
WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind();
- if (write_barrier_kind != kNoWriteBarrier) {
+ if (write_barrier_kind != kNoWriteBarrier &&
+ V8_LIKELY(!FLAG_disable_write_barriers)) {
DCHECK(CanBeTaggedOrCompressedPointer(store_rep.representation()));
AddressingMode addressing_mode;
InstructionOperand inputs[] = {
@@ -528,6 +530,35 @@ void InstructionSelector::VisitWord64Xor(Node* node) {
}
}
+void InstructionSelector::VisitStackPointerGreaterThan(
+ Node* node, FlagsContinuation* cont) {
+ Node* const value = node->InputAt(0);
+ InstructionCode opcode = kArchStackPointerGreaterThan;
+
+ DCHECK(cont->IsBranch());
+ const int effect_level =
+ GetEffectLevel(cont->true_block()->PredecessorAt(0)->control_input());
+
+ X64OperandGenerator g(this);
+ if (g.CanBeMemoryOperand(kX64Cmp, node, value, effect_level)) {
+ DCHECK_EQ(IrOpcode::kLoad, value->opcode());
+
+ // GetEffectiveAddressMemoryOperand can create at most 3 inputs.
+ static constexpr int kMaxInputCount = 3;
+
+ size_t input_count = 0;
+ InstructionOperand inputs[kMaxInputCount];
+ AddressingMode addressing_mode =
+ g.GetEffectiveAddressMemoryOperand(value, inputs, &input_count);
+ opcode |= AddressingModeField::encode(addressing_mode);
+ DCHECK_LE(input_count, kMaxInputCount);
+
+ EmitWithContinuation(opcode, 0, nullptr, input_count, inputs, cont);
+ } else {
+ EmitWithContinuation(opcode, g.UseRegister(value), cont);
+ }
+}
+
namespace {
bool TryMergeTruncateInt64ToInt32IntoLoad(InstructionSelector* selector,
@@ -1238,23 +1269,23 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
}
void InstructionSelector::VisitChangeTaggedToCompressed(Node* node) {
- X64OperandGenerator g(this);
- Node* value = node->InputAt(0);
- Emit(kX64CompressAny, g.DefineAsRegister(node), g.Use(value));
+ // The top 32 bits in the 64-bit register will be undefined, and
+ // must not be used by a dependent node.
+ return EmitIdentity(node);
}
void InstructionSelector::VisitChangeTaggedPointerToCompressedPointer(
Node* node) {
- X64OperandGenerator g(this);
- Node* value = node->InputAt(0);
- Emit(kX64CompressPointer, g.DefineAsRegister(node), g.Use(value));
+ // The top 32 bits in the 64-bit register will be undefined, and
+ // must not be used by a dependent node.
+ return EmitIdentity(node);
}
void InstructionSelector::VisitChangeTaggedSignedToCompressedSigned(
Node* node) {
- X64OperandGenerator g(this);
- Node* value = node->InputAt(0);
- Emit(kX64CompressSigned, g.DefineAsRegister(node), g.Use(value));
+ // The top 32 bits in the 64-bit register will be undefined, and
+ // must not be used by a dependent node.
+ return EmitIdentity(node);
}
void InstructionSelector::VisitChangeCompressedToTagged(Node* node) {
@@ -1338,10 +1369,13 @@ void VisitFloatBinop(InstructionSelector* selector, Node* node,
void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input,
ArchOpcode avx_opcode, ArchOpcode sse_opcode) {
X64OperandGenerator g(selector);
+ InstructionOperand temps[] = {g.TempDoubleRegister()};
if (selector->IsSupported(AVX)) {
- selector->Emit(avx_opcode, g.DefineAsRegister(node), g.Use(input));
+ selector->Emit(avx_opcode, g.DefineAsRegister(node), g.UseUnique(input),
+ arraysize(temps), temps);
} else {
- selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input));
+ selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input),
+ arraysize(temps), temps);
}
}
@@ -1838,30 +1872,6 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node,
g.UseRegister(m.right().node()), cont);
}
}
- if (selector->isolate() != nullptr) {
- StackCheckMatcher<Int64BinopMatcher, IrOpcode::kUint64LessThan> m(
- selector->isolate(), node);
- if (m.Matched()) {
- // Compare(Load(js_stack_limit), LoadStackPointer)
- if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
- InstructionCode opcode = cont->Encode(kX64StackCheck);
- CHECK(cont->IsBranch());
- selector->EmitWithContinuation(opcode, cont);
- return;
- }
- }
- WasmStackCheckMatcher<Int64BinopMatcher, IrOpcode::kUint64LessThan> wasm_m(
- node);
- if (wasm_m.Matched()) {
- // This is a wasm stack check. By structure, we know that we can use the
- // stack pointer directly, as wasm code does not modify the stack at points
- // where stack checks are performed.
- Node* left = node->InputAt(0);
- LocationOperand rsp(InstructionOperand::EXPLICIT, LocationOperand::REGISTER,
- InstructionSequence::DefaultRepresentation(),
- RegisterCode::kRegCode_rsp);
- return VisitCompareWithMemoryOperand(selector, kX64Cmp, left, rsp, cont);
- }
VisitWordCompare(selector, node, kX64Cmp, cont);
}
@@ -2157,6 +2167,9 @@ void InstructionSelector::VisitWordCompareZero(Node* user, Node* value,
return VisitWordCompare(this, value, kX64Cmp32, cont);
case IrOpcode::kWord32And:
return VisitWordCompare(this, value, kX64Test32, cont);
+ case IrOpcode::kStackPointerGreaterThan:
+ cont->OverwriteAndNegateIfEqual(kStackPointerGreaterThanCondition);
+ return VisitStackPointerGreaterThan(value, cont);
default:
break;
}
@@ -2586,6 +2599,12 @@ VISIT_ATOMIC_BINOP(Xor)
V(I8x16)
#define SIMD_BINOP_LIST(V) \
+ V(F64x2Add) \
+ V(F64x2Sub) \
+ V(F64x2Mul) \
+ V(F64x2Div) \
+ V(F64x2Min) \
+ V(F64x2Max) \
V(F64x2Eq) \
V(F64x2Ne) \
V(F64x2Lt) \
@@ -2594,6 +2613,7 @@ VISIT_ATOMIC_BINOP(Xor)
V(F32x4AddHoriz) \
V(F32x4Sub) \
V(F32x4Mul) \
+ V(F32x4Div) \
V(F32x4Min) \
V(F32x4Max) \
V(F32x4Eq) \
@@ -2603,7 +2623,6 @@ VISIT_ATOMIC_BINOP(Xor)
V(I64x2Add) \
V(I64x2Sub) \
V(I64x2Eq) \
- V(I64x2Ne) \
V(I64x2GtS) \
V(I32x4Add) \
V(I32x4AddHoriz) \
@@ -2612,12 +2631,10 @@ VISIT_ATOMIC_BINOP(Xor)
V(I32x4MinS) \
V(I32x4MaxS) \
V(I32x4Eq) \
- V(I32x4Ne) \
V(I32x4GtS) \
V(I32x4GeS) \
V(I32x4MinU) \
V(I32x4MaxU) \
- V(I32x4GtU) \
V(I32x4GeU) \
V(I16x8SConvertI32x4) \
V(I16x8Add) \
@@ -2629,14 +2646,12 @@ VISIT_ATOMIC_BINOP(Xor)
V(I16x8MinS) \
V(I16x8MaxS) \
V(I16x8Eq) \
- V(I16x8Ne) \
V(I16x8GtS) \
V(I16x8GeS) \
V(I16x8AddSaturateU) \
V(I16x8SubSaturateU) \
V(I16x8MinU) \
V(I16x8MaxU) \
- V(I16x8GtU) \
V(I16x8GeU) \
V(I8x16SConvertI16x8) \
V(I8x16Add) \
@@ -2646,23 +2661,28 @@ VISIT_ATOMIC_BINOP(Xor)
V(I8x16MinS) \
V(I8x16MaxS) \
V(I8x16Eq) \
- V(I8x16Ne) \
V(I8x16GtS) \
V(I8x16GeS) \
V(I8x16AddSaturateU) \
V(I8x16SubSaturateU) \
V(I8x16MinU) \
V(I8x16MaxU) \
- V(I8x16GtU) \
V(I8x16GeU) \
V(S128And) \
V(S128Or) \
V(S128Xor)
#define SIMD_BINOP_ONE_TEMP_LIST(V) \
+ V(I64x2Ne) \
V(I64x2GeS) \
V(I64x2GtU) \
- V(I64x2GeU)
+ V(I64x2GeU) \
+ V(I32x4Ne) \
+ V(I32x4GtU) \
+ V(I16x8Ne) \
+ V(I16x8GtU) \
+ V(I8x16Ne) \
+ V(I8x16GtU)
#define SIMD_UNOP_LIST(V) \
V(F32x4SConvertI32x4) \
@@ -2686,16 +2706,17 @@ VISIT_ATOMIC_BINOP(Xor)
#define SIMD_SHIFT_OPCODES(V) \
V(I64x2Shl) \
- V(I64x2ShrS) \
V(I64x2ShrU) \
V(I32x4Shl) \
V(I32x4ShrS) \
V(I32x4ShrU) \
V(I16x8Shl) \
V(I16x8ShrS) \
- V(I16x8ShrU) \
- V(I8x16Shl) \
- V(I8x16ShrS) \
+ V(I16x8ShrU)
+
+#define SIMD_NARROW_SHIFT_OPCODES(V) \
+ V(I8x16Shl) \
+ V(I8x16ShrS) \
V(I8x16ShrU)
#define SIMD_ANYTRUE_LIST(V) \
@@ -2745,17 +2766,30 @@ SIMD_TYPES(VISIT_SIMD_EXTRACT_LANE)
SIMD_TYPES(VISIT_SIMD_REPLACE_LANE)
#undef VISIT_SIMD_REPLACE_LANE
-#define VISIT_SIMD_SHIFT(Opcode) \
- void InstructionSelector::Visit##Opcode(Node* node) { \
- X64OperandGenerator g(this); \
- int32_t value = OpParameter<int32_t>(node->op()); \
- Emit(kX64##Opcode, g.DefineSameAsFirst(node), \
- g.UseRegister(node->InputAt(0)), g.UseImmediate(value)); \
+#define VISIT_SIMD_SHIFT(Opcode) \
+ void InstructionSelector::Visit##Opcode(Node* node) { \
+ X64OperandGenerator g(this); \
+ InstructionOperand temps[] = {g.TempSimd128Register()}; \
+ Emit(kX64##Opcode, g.DefineSameAsFirst(node), \
+ g.UseUniqueRegister(node->InputAt(0)), \
+ g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps); \
}
SIMD_SHIFT_OPCODES(VISIT_SIMD_SHIFT)
#undef VISIT_SIMD_SHIFT
#undef SIMD_SHIFT_OPCODES
+#define VISIT_SIMD_NARROW_SHIFT(Opcode) \
+ void InstructionSelector::Visit##Opcode(Node* node) { \
+ X64OperandGenerator g(this); \
+ InstructionOperand temps[] = {g.TempRegister(), g.TempSimd128Register()}; \
+ Emit(kX64##Opcode, g.DefineSameAsFirst(node), \
+ g.UseUniqueRegister(node->InputAt(0)), \
+ g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps); \
+ }
+SIMD_NARROW_SHIFT_OPCODES(VISIT_SIMD_NARROW_SHIFT)
+#undef VISIT_SIMD_NARROW_SHIFT
+#undef SIMD_NARROW_SHIFT_OPCODES
+
#define VISIT_SIMD_UNOP(Opcode) \
void InstructionSelector::Visit##Opcode(Node* node) { \
X64OperandGenerator g(this); \
@@ -2799,12 +2833,12 @@ SIMD_ANYTRUE_LIST(VISIT_SIMD_ANYTRUE)
#undef VISIT_SIMD_ANYTRUE
#undef SIMD_ANYTRUE_LIST
-#define VISIT_SIMD_ALLTRUE(Opcode) \
- void InstructionSelector::Visit##Opcode(Node* node) { \
- X64OperandGenerator g(this); \
- InstructionOperand temps[] = {g.TempRegister()}; \
- Emit(kX64##Opcode, g.DefineAsRegister(node), \
- g.UseUniqueRegister(node->InputAt(0)), arraysize(temps), temps); \
+#define VISIT_SIMD_ALLTRUE(Opcode) \
+ void InstructionSelector::Visit##Opcode(Node* node) { \
+ X64OperandGenerator g(this); \
+ InstructionOperand temps[] = {g.TempRegister(), g.TempSimd128Register()}; \
+ Emit(kX64##Opcode, g.DefineAsRegister(node), \
+ g.UseUniqueRegister(node->InputAt(0)), arraysize(temps), temps); \
}
SIMD_ALLTRUE_LIST(VISIT_SIMD_ALLTRUE)
#undef VISIT_SIMD_ALLTRUE
@@ -2820,14 +2854,16 @@ void InstructionSelector::VisitS128Select(Node* node) {
void InstructionSelector::VisitF64x2Abs(Node* node) {
X64OperandGenerator g(this);
- Emit(kX64F64x2Abs, g.DefineSameAsFirst(node),
- g.UseRegister(node->InputAt(0)));
+ InstructionOperand temps[] = {g.TempDoubleRegister()};
+ Emit(kX64F64x2Abs, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
+ arraysize(temps), temps);
}
void InstructionSelector::VisitF64x2Neg(Node* node) {
X64OperandGenerator g(this);
- Emit(kX64F64x2Neg, g.DefineSameAsFirst(node),
- g.UseRegister(node->InputAt(0)));
+ InstructionOperand temps[] = {g.TempDoubleRegister()};
+ Emit(kX64F64x2Neg, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
+ arraysize(temps), temps);
}
void InstructionSelector::VisitF32x4UConvertI32x4(Node* node) {
@@ -2836,6 +2872,15 @@ void InstructionSelector::VisitF32x4UConvertI32x4(Node* node) {
g.UseRegister(node->InputAt(0)));
}
+void InstructionSelector::VisitI64x2ShrS(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand temps[] = {g.TempRegister()};
+ // Use fixed to rcx, to use sarq_cl in codegen.
+ Emit(kX64I64x2ShrS, g.DefineSameAsFirst(node),
+ g.UseUniqueRegister(node->InputAt(0)), g.UseFixed(node->InputAt(1), rcx),
+ arraysize(temps), temps);
+}
+
void InstructionSelector::VisitI64x2Mul(Node* node) {
X64OperandGenerator g(this);
InstructionOperand temps[] = {g.TempSimd128Register(),
@@ -2845,15 +2890,59 @@ void InstructionSelector::VisitI64x2Mul(Node* node) {
g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
}
+void InstructionSelector::VisitI64x2MinS(Node* node) {
+ X64OperandGenerator g(this);
+ if (this->IsSupported(SSE4_2)) {
+ InstructionOperand temps[] = {g.TempSimd128Register()};
+ Emit(kX64I64x2MinS, g.DefineSameAsFirst(node),
+ g.UseRegister(node->InputAt(0)), g.UseFixed(node->InputAt(1), xmm0),
+ arraysize(temps), temps);
+ } else {
+ InstructionOperand temps[] = {g.TempSimd128Register(), g.TempRegister(),
+ g.TempRegister()};
+ Emit(kX64I64x2MinS, g.DefineSameAsFirst(node),
+ g.UseRegister(node->InputAt(0)), g.UseRegister(node->InputAt(1)),
+ arraysize(temps), temps);
+ }
+}
+
+void InstructionSelector::VisitI64x2MaxS(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand temps[] = {g.TempSimd128Register()};
+ Emit(kX64I64x2MaxS, g.DefineSameAsFirst(node),
+ g.UseRegister(node->InputAt(0)), g.UseFixed(node->InputAt(1), xmm0),
+ arraysize(temps), temps);
+}
+
+void InstructionSelector::VisitI64x2MinU(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand temps[] = {g.TempSimd128Register(),
+ g.TempSimd128Register()};
+ Emit(kX64I64x2MinU, g.DefineSameAsFirst(node),
+ g.UseRegister(node->InputAt(0)), g.UseFixed(node->InputAt(1), xmm0),
+ arraysize(temps), temps);
+}
+
+void InstructionSelector::VisitI64x2MaxU(Node* node) {
+ X64OperandGenerator g(this);
+ InstructionOperand temps[] = {g.TempSimd128Register(),
+ g.TempSimd128Register()};
+ Emit(kX64I64x2MaxU, g.DefineSameAsFirst(node),
+ g.UseRegister(node->InputAt(0)), g.UseFixed(node->InputAt(1), xmm0),
+ arraysize(temps), temps);
+}
+
void InstructionSelector::VisitI32x4SConvertF32x4(Node* node) {
X64OperandGenerator g(this);
+ InstructionOperand temps[] = {g.TempSimd128Register()};
Emit(kX64I32x4SConvertF32x4, g.DefineSameAsFirst(node),
- g.UseRegister(node->InputAt(0)));
+ g.UseRegister(node->InputAt(0)), arraysize(temps), temps);
}
void InstructionSelector::VisitI32x4UConvertF32x4(Node* node) {
X64OperandGenerator g(this);
- InstructionOperand temps[] = {g.TempSimd128Register()};
+ InstructionOperand temps[] = {g.TempSimd128Register(),
+ g.TempSimd128Register()};
Emit(kX64I32x4UConvertF32x4, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)), arraysize(temps), temps);
}
@@ -2997,12 +3086,12 @@ static const ShuffleEntry arch_shuffles[] = {
true},
{{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8},
kX64S8x8Reverse,
- false,
- false},
+ true,
+ true},
{{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
kX64S8x4Reverse,
- false,
- false},
+ true,
+ true},
{{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14},
kX64S8x2Reverse,
true,
@@ -3060,6 +3149,8 @@ void InstructionSelector::VisitS8x16Shuffle(Node* node) {
SwapShuffleInputs(node);
is_swizzle = false; // It's simpler to just handle the general case.
no_same_as_first = false; // SSE requires same-as-first.
+ // TODO(v8:9608): also see v8:9083
+ src1_needs_reg = true;
opcode = kX64S8x16Alignr;
// palignr takes a single imm8 offset.
imms[imm_count++] = offset;
diff --git a/deps/v8/src/compiler/branch-elimination.cc b/deps/v8/src/compiler/branch-elimination.cc
index 2583262c07..ffc149ea5d 100644
--- a/deps/v8/src/compiler/branch-elimination.cc
+++ b/deps/v8/src/compiler/branch-elimination.cc
@@ -4,6 +4,7 @@
#include "src/compiler/branch-elimination.h"
+#include "src/base/small-vector.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/simplified-operator.h"
@@ -13,17 +14,17 @@ namespace internal {
namespace compiler {
BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph,
- Zone* zone)
+ Zone* zone, Phase phase)
: AdvancedReducer(editor),
jsgraph_(js_graph),
node_conditions_(js_graph->graph()->NodeCount(), zone),
reduced_(js_graph->graph()->NodeCount(), zone),
zone_(zone),
- dead_(js_graph->Dead()) {}
+ dead_(js_graph->Dead()),
+ phase_(phase) {}
BranchElimination::~BranchElimination() = default;
-
Reduction BranchElimination::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kDead:
@@ -52,6 +53,74 @@ Reduction BranchElimination::Reduce(Node* node) {
return NoChange();
}
+void BranchElimination::SimplifyBranchCondition(Node* branch) {
+ // Try to use a phi as a branch condition if the control flow from the branch
+ // is known from previous branches. For example, in the graph below, the
+ // control flow of the second_branch is predictable because the first_branch
+ // use the same branch condition. In such case, create a new phi with constant
+ // inputs and let the second branch use the phi as its branch condition. From
+ // this transformation, more branch folding opportunities would be exposed to
+ // later passes through branch cloning in effect-control-linearizer.
+ //
+ // condition condition
+ // | \ |
+ // | first_branch first_branch
+ // | / \ / \
+ // | / \ / \
+ // |first_true first_false first_true first_false
+ // | \ / \ /
+ // | \ / \ /
+ // | first_merge ==> first_merge
+ // | | |
+ // second_branch 1 0 |
+ // / \ \ / |
+ // / \ phi |
+ // second_true second_false \ |
+ // second_branch
+ // / \
+ // / \
+ // second_true second_false
+ //
+
+ DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
+ Node* merge = NodeProperties::GetControlInput(branch);
+ if (merge->opcode() != IrOpcode::kMerge) return;
+
+ Node* branch_condition = branch->InputAt(0);
+ Node* previous_branch;
+ bool condition_value;
+ Graph* graph = jsgraph()->graph();
+ base::SmallVector<Node*, 2> phi_inputs;
+
+ Node::Inputs inputs = merge->inputs();
+ int input_count = inputs.count();
+ for (int i = 0; i != input_count; ++i) {
+ Node* input = inputs[i];
+ ControlPathConditions from_input = node_conditions_.Get(input);
+ if (!from_input.LookupCondition(branch_condition, &previous_branch,
+ &condition_value))
+ return;
+
+ if (phase_ == kEARLY) {
+ phi_inputs.emplace_back(condition_value ? jsgraph()->TrueConstant()
+ : jsgraph()->FalseConstant());
+ } else {
+ phi_inputs.emplace_back(
+ condition_value
+ ? graph->NewNode(jsgraph()->common()->Int32Constant(1))
+ : graph->NewNode(jsgraph()->common()->Int32Constant(0)));
+ }
+ }
+ phi_inputs.emplace_back(merge);
+ Node* new_phi = graph->NewNode(
+ common()->Phi(phase_ == kEARLY ? MachineRepresentation::kTagged
+ : MachineRepresentation::kWord32,
+ input_count),
+ input_count + 1, &phi_inputs.at(0));
+
+ // Replace the branch condition with the new phi.
+ NodeProperties::ReplaceValueInput(branch, new_phi, 0);
+}
Reduction BranchElimination::ReduceBranch(Node* node) {
Node* condition = node->InputAt(0);
@@ -87,6 +156,7 @@ Reduction BranchElimination::ReduceBranch(Node* node) {
}
return Replace(dead());
}
+ SimplifyBranchCondition(node);
return TakeConditionsFromFirstControl(node);
}
@@ -151,7 +221,6 @@ Reduction BranchElimination::ReduceIf(Node* node, bool is_true_branch) {
return UpdateConditions(node, from_branch, condition, branch, is_true_branch);
}
-
Reduction BranchElimination::ReduceLoop(Node* node) {
// Here we rely on having only reducible loops:
// The loop entry edge always dominates the header, so we can just use
@@ -159,7 +228,6 @@ Reduction BranchElimination::ReduceLoop(Node* node) {
return TakeConditionsFromFirstControl(node);
}
-
Reduction BranchElimination::ReduceMerge(Node* node) {
// Shortcut for the case when we do not know anything about some
// input.
@@ -188,18 +256,15 @@ Reduction BranchElimination::ReduceMerge(Node* node) {
return UpdateConditions(node, conditions);
}
-
Reduction BranchElimination::ReduceStart(Node* node) {
return UpdateConditions(node, {});
}
-
Reduction BranchElimination::ReduceOtherControl(Node* node) {
DCHECK_EQ(1, node->op()->ControlInputCount());
return TakeConditionsFromFirstControl(node);
}
-
Reduction BranchElimination::TakeConditionsFromFirstControl(Node* node) {
// We just propagate the information from the control input (ideally,
// we would only revisit control uses if there is change).
diff --git a/deps/v8/src/compiler/branch-elimination.h b/deps/v8/src/compiler/branch-elimination.h
index 2730da9c75..b3d9ef7752 100644
--- a/deps/v8/src/compiler/branch-elimination.h
+++ b/deps/v8/src/compiler/branch-elimination.h
@@ -22,7 +22,12 @@ class JSGraph;
class V8_EXPORT_PRIVATE BranchElimination final
: public NON_EXPORTED_BASE(AdvancedReducer) {
public:
- BranchElimination(Editor* editor, JSGraph* js_graph, Zone* zone);
+ enum Phase {
+ kEARLY,
+ kLATE,
+ };
+ BranchElimination(Editor* editor, JSGraph* js_graph, Zone* zone,
+ Phase phase = kLATE);
~BranchElimination() final;
const char* reducer_name() const override { return "BranchElimination"; }
@@ -62,6 +67,7 @@ class V8_EXPORT_PRIVATE BranchElimination final
Reduction ReduceMerge(Node* node);
Reduction ReduceStart(Node* node);
Reduction ReduceOtherControl(Node* node);
+ void SimplifyBranchCondition(Node* branch);
Reduction TakeConditionsFromFirstControl(Node* node);
Reduction UpdateConditions(Node* node, ControlPathConditions conditions);
@@ -84,6 +90,7 @@ class V8_EXPORT_PRIVATE BranchElimination final
NodeAuxData<bool> reduced_;
Zone* zone_;
Node* dead_;
+ Phase phase_;
};
} // namespace compiler
diff --git a/deps/v8/src/compiler/bytecode-analysis.cc b/deps/v8/src/compiler/bytecode-analysis.cc
index b44bec5fc8..f1d43fc1a6 100644
--- a/deps/v8/src/compiler/bytecode-analysis.cc
+++ b/deps/v8/src/compiler/bytecode-analysis.cc
@@ -97,37 +97,35 @@ BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array,
namespace {
-void UpdateInLiveness(
- Bytecode bytecode,
- BytecodeLivenessState& in_liveness, // NOLINT(runtime/references)
- const interpreter::BytecodeArrayAccessor& accessor) {
+void UpdateInLiveness(Bytecode bytecode, BytecodeLivenessState* in_liveness,
+ const interpreter::BytecodeArrayAccessor& accessor) {
int num_operands = Bytecodes::NumberOfOperands(bytecode);
const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode);
// Special case Suspend and Resume to just pass through liveness.
if (bytecode == Bytecode::kSuspendGenerator) {
// The generator object has to be live.
- in_liveness.MarkRegisterLive(accessor.GetRegisterOperand(0).index());
+ in_liveness->MarkRegisterLive(accessor.GetRegisterOperand(0).index());
// Suspend additionally reads and returns the accumulator
DCHECK(Bytecodes::ReadsAccumulator(bytecode));
- in_liveness.MarkAccumulatorLive();
+ in_liveness->MarkAccumulatorLive();
return;
}
if (bytecode == Bytecode::kResumeGenerator) {
// The generator object has to be live.
- in_liveness.MarkRegisterLive(accessor.GetRegisterOperand(0).index());
+ in_liveness->MarkRegisterLive(accessor.GetRegisterOperand(0).index());
return;
}
if (Bytecodes::WritesAccumulator(bytecode)) {
- in_liveness.MarkAccumulatorDead();
+ in_liveness->MarkAccumulatorDead();
}
for (int i = 0; i < num_operands; ++i) {
switch (operand_types[i]) {
case OperandType::kRegOut: {
interpreter::Register r = accessor.GetRegisterOperand(i);
if (!r.is_parameter()) {
- in_liveness.MarkRegisterDead(r.index());
+ in_liveness->MarkRegisterDead(r.index());
}
break;
}
@@ -137,7 +135,7 @@ void UpdateInLiveness(
if (!r.is_parameter()) {
for (uint32_t j = 0; j < reg_count; ++j) {
DCHECK(!interpreter::Register(r.index() + j).is_parameter());
- in_liveness.MarkRegisterDead(r.index() + j);
+ in_liveness->MarkRegisterDead(r.index() + j);
}
}
break;
@@ -146,8 +144,8 @@ void UpdateInLiveness(
interpreter::Register r = accessor.GetRegisterOperand(i);
if (!r.is_parameter()) {
DCHECK(!interpreter::Register(r.index() + 1).is_parameter());
- in_liveness.MarkRegisterDead(r.index());
- in_liveness.MarkRegisterDead(r.index() + 1);
+ in_liveness->MarkRegisterDead(r.index());
+ in_liveness->MarkRegisterDead(r.index() + 1);
}
break;
}
@@ -156,9 +154,9 @@ void UpdateInLiveness(
if (!r.is_parameter()) {
DCHECK(!interpreter::Register(r.index() + 1).is_parameter());
DCHECK(!interpreter::Register(r.index() + 2).is_parameter());
- in_liveness.MarkRegisterDead(r.index());
- in_liveness.MarkRegisterDead(r.index() + 1);
- in_liveness.MarkRegisterDead(r.index() + 2);
+ in_liveness->MarkRegisterDead(r.index());
+ in_liveness->MarkRegisterDead(r.index() + 1);
+ in_liveness->MarkRegisterDead(r.index() + 2);
}
break;
}
@@ -169,14 +167,14 @@ void UpdateInLiveness(
}
if (Bytecodes::ReadsAccumulator(bytecode)) {
- in_liveness.MarkAccumulatorLive();
+ in_liveness->MarkAccumulatorLive();
}
for (int i = 0; i < num_operands; ++i) {
switch (operand_types[i]) {
case OperandType::kReg: {
interpreter::Register r = accessor.GetRegisterOperand(i);
if (!r.is_parameter()) {
- in_liveness.MarkRegisterLive(r.index());
+ in_liveness->MarkRegisterLive(r.index());
}
break;
}
@@ -184,8 +182,8 @@ void UpdateInLiveness(
interpreter::Register r = accessor.GetRegisterOperand(i);
if (!r.is_parameter()) {
DCHECK(!interpreter::Register(r.index() + 1).is_parameter());
- in_liveness.MarkRegisterLive(r.index());
- in_liveness.MarkRegisterLive(r.index() + 1);
+ in_liveness->MarkRegisterLive(r.index());
+ in_liveness->MarkRegisterLive(r.index() + 1);
}
break;
}
@@ -195,7 +193,7 @@ void UpdateInLiveness(
if (!r.is_parameter()) {
for (uint32_t j = 0; j < reg_count; ++j) {
DCHECK(!interpreter::Register(r.index() + j).is_parameter());
- in_liveness.MarkRegisterLive(r.index() + j);
+ in_liveness->MarkRegisterLive(r.index() + j);
}
}
break;
@@ -207,19 +205,17 @@ void UpdateInLiveness(
}
}
-void UpdateOutLiveness(
- Bytecode bytecode,
- BytecodeLivenessState& out_liveness, // NOLINT(runtime/references)
- BytecodeLivenessState* next_bytecode_in_liveness,
- const interpreter::BytecodeArrayAccessor& accessor,
- Handle<BytecodeArray> bytecode_array,
- const BytecodeLivenessMap& liveness_map) {
+void UpdateOutLiveness(Bytecode bytecode, BytecodeLivenessState* out_liveness,
+ BytecodeLivenessState* next_bytecode_in_liveness,
+ const interpreter::BytecodeArrayAccessor& accessor,
+ Handle<BytecodeArray> bytecode_array,
+ const BytecodeLivenessMap& liveness_map) {
int current_offset = accessor.current_offset();
// Special case Suspend and Resume to just pass through liveness.
if (bytecode == Bytecode::kSuspendGenerator ||
bytecode == Bytecode::kResumeGenerator) {
- out_liveness.Union(*next_bytecode_in_liveness);
+ out_liveness->Union(*next_bytecode_in_liveness);
return;
}
@@ -227,10 +223,10 @@ void UpdateOutLiveness(
// the liveness iterations.
if (Bytecodes::IsForwardJump(bytecode)) {
int target_offset = accessor.GetJumpTargetOffset();
- out_liveness.Union(*liveness_map.GetInLiveness(target_offset));
+ out_liveness->Union(*liveness_map.GetInLiveness(target_offset));
} else if (Bytecodes::IsSwitch(bytecode)) {
for (const auto& entry : accessor.GetJumpTableTargetOffsets()) {
- out_liveness.Union(*liveness_map.GetInLiveness(entry.target_offset));
+ out_liveness->Union(*liveness_map.GetInLiveness(entry.target_offset));
}
}
@@ -238,7 +234,7 @@ void UpdateOutLiveness(
// unconditional jump).
if (next_bytecode_in_liveness != nullptr &&
!Bytecodes::IsUnconditionalJump(bytecode)) {
- out_liveness.Union(*next_bytecode_in_liveness);
+ out_liveness->Union(*next_bytecode_in_liveness);
}
// Update from exception handler (if any).
@@ -250,15 +246,15 @@ void UpdateOutLiveness(
table.LookupRange(current_offset, &handler_context, nullptr);
if (handler_offset != -1) {
- bool was_accumulator_live = out_liveness.AccumulatorIsLive();
- out_liveness.Union(*liveness_map.GetInLiveness(handler_offset));
- out_liveness.MarkRegisterLive(handler_context);
+ bool was_accumulator_live = out_liveness->AccumulatorIsLive();
+ out_liveness->Union(*liveness_map.GetInLiveness(handler_offset));
+ out_liveness->MarkRegisterLive(handler_context);
if (!was_accumulator_live) {
// The accumulator is reset to the exception on entry into a handler,
// and so shouldn't be considered live coming out of this bytecode just
// because it's live coming into the handler. So, kill the accumulator
// if the handler is the only thing that made it live.
- out_liveness.MarkAccumulatorDead();
+ out_liveness->MarkAccumulatorDead();
// TODO(leszeks): Ideally the accumulator wouldn't be considered live at
// the start of the handler, but looking up if the current bytecode is
@@ -269,45 +265,42 @@ void UpdateOutLiveness(
}
}
-void UpdateLiveness(Bytecode bytecode,
- BytecodeLiveness& liveness, // NOLINT(runtime/references)
+void UpdateLiveness(Bytecode bytecode, BytecodeLiveness const& liveness,
BytecodeLivenessState** next_bytecode_in_liveness,
const interpreter::BytecodeArrayAccessor& accessor,
Handle<BytecodeArray> bytecode_array,
const BytecodeLivenessMap& liveness_map) {
- UpdateOutLiveness(bytecode, *liveness.out, *next_bytecode_in_liveness,
+ UpdateOutLiveness(bytecode, liveness.out, *next_bytecode_in_liveness,
accessor, bytecode_array, liveness_map);
liveness.in->CopyFrom(*liveness.out);
- UpdateInLiveness(bytecode, *liveness.in, accessor);
+ UpdateInLiveness(bytecode, liveness.in, accessor);
*next_bytecode_in_liveness = liveness.in;
}
-void UpdateAssignments(
- Bytecode bytecode,
- BytecodeLoopAssignments& assignments, // NOLINT(runtime/references)
- const interpreter::BytecodeArrayAccessor& accessor) {
+void UpdateAssignments(Bytecode bytecode, BytecodeLoopAssignments* assignments,
+ const interpreter::BytecodeArrayAccessor& accessor) {
int num_operands = Bytecodes::NumberOfOperands(bytecode);
const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode);
for (int i = 0; i < num_operands; ++i) {
switch (operand_types[i]) {
case OperandType::kRegOut: {
- assignments.Add(accessor.GetRegisterOperand(i));
+ assignments->Add(accessor.GetRegisterOperand(i));
break;
}
case OperandType::kRegOutList: {
interpreter::Register r = accessor.GetRegisterOperand(i++);
uint32_t reg_count = accessor.GetRegisterCountOperand(i);
- assignments.AddList(r, reg_count);
+ assignments->AddList(r, reg_count);
break;
}
case OperandType::kRegOutPair: {
- assignments.AddList(accessor.GetRegisterOperand(i), 2);
+ assignments->AddList(accessor.GetRegisterOperand(i), 2);
break;
}
case OperandType::kRegOutTriple: {
- assignments.AddList(accessor.GetRegisterOperand(i), 3);
+ assignments->AddList(accessor.GetRegisterOperand(i), 3);
break;
}
default:
@@ -365,7 +358,7 @@ void BytecodeAnalysis::Analyze() {
// the loop *and* are live when the loop exits. However, this requires
// tracking the out-liveness of *all* loop exits, which is not
// information we currently have.
- UpdateAssignments(bytecode, current_loop_info->assignments(), iterator);
+ UpdateAssignments(bytecode, &current_loop_info->assignments(), iterator);
// Update suspend counts for this loop.
if (bytecode == Bytecode::kSuspendGenerator) {
@@ -433,7 +426,7 @@ void BytecodeAnalysis::Analyze() {
}
if (analyze_liveness_) {
- BytecodeLiveness& liveness = liveness_map_.InitializeLiveness(
+ BytecodeLiveness const& liveness = liveness_map_.InitializeLiveness(
current_offset, bytecode_array()->register_count(), zone());
UpdateLiveness(bytecode, liveness, &next_bytecode_in_liveness, iterator,
bytecode_array(), liveness_map_);
@@ -496,14 +489,14 @@ void BytecodeAnalysis::Analyze() {
for (; iterator.current_offset() > header_offset; --iterator) {
Bytecode bytecode = iterator.current_bytecode();
int current_offset = iterator.current_offset();
- BytecodeLiveness& liveness = liveness_map_.GetLiveness(current_offset);
-
+ BytecodeLiveness const& liveness =
+ liveness_map_.GetLiveness(current_offset);
UpdateLiveness(bytecode, liveness, &next_bytecode_in_liveness, iterator,
bytecode_array(), liveness_map_);
}
// Now we are at the loop header. Since the in-liveness of the header
// can't change, we need only to update the out-liveness.
- UpdateOutLiveness(iterator.current_bytecode(), *header_liveness.out,
+ UpdateOutLiveness(iterator.current_bytecode(), header_liveness.out,
next_bytecode_in_liveness, iterator, bytecode_array(),
liveness_map_);
}
@@ -532,13 +525,14 @@ void BytecodeAnalysis::Analyze() {
// bytecodes before it.
if (any_changed) {
switch_liveness.in->CopyFrom(*switch_liveness.out);
- UpdateInLiveness(Bytecode::kSwitchOnGeneratorState, *switch_liveness.in,
+ UpdateInLiveness(Bytecode::kSwitchOnGeneratorState, switch_liveness.in,
iterator);
next_bytecode_in_liveness = switch_liveness.in;
for (--iterator; iterator.IsValid(); --iterator) {
Bytecode bytecode = iterator.current_bytecode();
int current_offset = iterator.current_offset();
- BytecodeLiveness& liveness = liveness_map_.GetLiveness(current_offset);
+ BytecodeLiveness const& liveness =
+ liveness_map_.GetLiveness(current_offset);
// There shouldn't be any more loops.
DCHECK_NE(bytecode, Bytecode::kJumpLoop);
@@ -829,7 +823,7 @@ bool BytecodeAnalysis::LivenessIsValid() {
previous_liveness.CopyFrom(*liveness.out);
- UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness,
+ UpdateOutLiveness(bytecode, liveness.out, next_bytecode_in_liveness,
iterator, bytecode_array(), liveness_map_);
// UpdateOutLiveness skips kJumpLoop, so we update it manually.
if (bytecode == Bytecode::kJumpLoop) {
@@ -848,7 +842,7 @@ bool BytecodeAnalysis::LivenessIsValid() {
previous_liveness.CopyFrom(*liveness.in);
liveness.in->CopyFrom(*liveness.out);
- UpdateInLiveness(bytecode, *liveness.in, iterator);
+ UpdateInLiveness(bytecode, liveness.in, iterator);
if (!liveness.in->Equals(previous_liveness)) {
// Reset the invalid liveness.
diff --git a/deps/v8/src/compiler/bytecode-graph-builder.cc b/deps/v8/src/compiler/bytecode-graph-builder.cc
index 7c71446320..b1051be571 100644
--- a/deps/v8/src/compiler/bytecode-graph-builder.cc
+++ b/deps/v8/src/compiler/bytecode-graph-builder.cc
@@ -16,7 +16,6 @@
#include "src/compiler/operator-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/state-values-utils.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/interpreter/bytecode-flags.h"
#include "src/interpreter/bytecodes.h"
@@ -34,13 +33,12 @@ namespace compiler {
class BytecodeGraphBuilder {
public:
BytecodeGraphBuilder(JSHeapBroker* broker, Zone* local_zone,
- BytecodeArrayRef bytecode_array,
- SharedFunctionInfoRef shared,
- FeedbackVectorRef feedback_vector, BailoutId osr_offset,
- JSGraph* jsgraph,
+ NativeContextRef const& native_context,
+ SharedFunctionInfoRef const& shared_info,
+ FeedbackVectorRef const& feedback_vector,
+ BailoutId osr_offset, JSGraph* jsgraph,
CallFrequency const& invocation_frequency,
- SourcePositionTable* source_positions,
- NativeContextRef native_context, int inlining_id,
+ SourcePositionTable* source_positions, int inlining_id,
BytecodeGraphBuilderFlags flags,
TickCounter* tick_counter);
@@ -68,9 +66,9 @@ class BytecodeGraphBuilder {
// Builder for loading the a native context field.
Node* BuildLoadNativeContextField(int index);
- // Helper function for creating a pair containing type feedback vector and
- // a feedback slot.
- VectorSlotPair CreateVectorSlotPair(int slot_id);
+ // Helper function for creating a feedback source containing type feedback
+ // vector and a feedback slot.
+ FeedbackSource CreateFeedbackSource(int slot_id);
void set_environment(Environment* env) { environment_ = env; }
const Environment* environment() const { return environment_; }
@@ -168,7 +166,7 @@ class BytecodeGraphBuilder {
void PrepareFrameState(Node* node, OutputFrameStateCombine combine);
void BuildCreateArguments(CreateArgumentsType type);
- Node* BuildLoadGlobal(Handle<Name> name, uint32_t feedback_slot_index,
+ Node* BuildLoadGlobal(NameRef name, uint32_t feedback_slot_index,
TypeofMode typeof_mode);
enum class StoreMode {
@@ -245,11 +243,12 @@ class BytecodeGraphBuilder {
ForInMode GetForInMode(int operand_index);
// Helper function to compute call frequency from the recorded type
- // feedback.
+ // feedback. Returns unknown if invocation count is unknown. Returns 0 if
+ // feedback is insufficient.
CallFrequency ComputeCallFrequency(int slot_id) const;
// Helper function to extract the speculation mode from the recorded type
- // feedback.
+ // feedback. Returns kDisallowSpeculation if feedback is insufficient.
SpeculationMode GetSpeculationMode(int slot_id) const;
// Control flow plumbing.
@@ -310,7 +309,6 @@ class BytecodeGraphBuilder {
int context_register_; // Index of register holding handler context.
};
- // Field accessors
Graph* graph() const { return jsgraph_->graph(); }
CommonOperatorBuilder* common() const { return jsgraph_->common(); }
Zone* graph_zone() const { return graph()->zone(); }
@@ -321,55 +319,44 @@ class BytecodeGraphBuilder {
return jsgraph_->simplified();
}
Zone* local_zone() const { return local_zone_; }
- const BytecodeArrayRef bytecode_array() const { return bytecode_array_; }
- FeedbackVectorRef feedback_vector() const { return feedback_vector_; }
+ BytecodeArrayRef bytecode_array() const {
+ return shared_info().GetBytecodeArray();
+ }
+ FeedbackVectorRef const& feedback_vector() const { return feedback_vector_; }
const JSTypeHintLowering& type_hint_lowering() const {
return type_hint_lowering_;
}
const FrameStateFunctionInfo* frame_state_function_info() const {
return frame_state_function_info_;
}
-
SourcePositionTableIterator& source_position_iterator() {
return *source_position_iterator_.get();
}
-
interpreter::BytecodeArrayIterator& bytecode_iterator() {
return bytecode_iterator_;
}
-
BytecodeAnalysis const& bytecode_analysis() const {
return bytecode_analysis_;
}
-
int currently_peeled_loop_offset() const {
return currently_peeled_loop_offset_;
}
-
void set_currently_peeled_loop_offset(int offset) {
currently_peeled_loop_offset_ = offset;
}
-
bool skip_next_stack_check() const { return skip_next_stack_check_; }
-
void unset_skip_next_stack_check() { skip_next_stack_check_ = false; }
-
- int current_exception_handler() { return current_exception_handler_; }
-
+ int current_exception_handler() const { return current_exception_handler_; }
void set_current_exception_handler(int index) {
current_exception_handler_ = index;
}
-
bool needs_eager_checkpoint() const { return needs_eager_checkpoint_; }
void mark_as_needing_eager_checkpoint(bool value) {
needs_eager_checkpoint_ = value;
}
-
- SharedFunctionInfoRef shared_info() const { return shared_info_; }
-
- NativeContextRef native_context() const { return native_context_; }
-
JSHeapBroker* broker() const { return broker_; }
+ NativeContextRef native_context() const { return native_context_; }
+ SharedFunctionInfoRef shared_info() const { return shared_info_; }
#define DECLARE_VISIT_BYTECODE(name, ...) void Visit##name();
BYTECODE_LIST(DECLARE_VISIT_BYTECODE)
@@ -378,9 +365,11 @@ class BytecodeGraphBuilder {
JSHeapBroker* const broker_;
Zone* const local_zone_;
JSGraph* const jsgraph_;
+ // The native context for which we optimize.
+ NativeContextRef const native_context_;
+ SharedFunctionInfoRef const shared_info_;
+ FeedbackVectorRef const feedback_vector_;
CallFrequency const invocation_frequency_;
- BytecodeArrayRef const bytecode_array_;
- FeedbackVectorRef feedback_vector_;
JSTypeHintLowering const type_hint_lowering_;
const FrameStateFunctionInfo* const frame_state_function_info_;
std::unique_ptr<SourcePositionTableIterator> source_position_iterator_;
@@ -431,11 +420,6 @@ class BytecodeGraphBuilder {
SourcePosition const start_position_;
- SharedFunctionInfoRef const shared_info_;
-
- // The native context for which we optimize.
- NativeContextRef const native_context_;
-
TickCounter* const tick_counter_;
static int const kBinaryOperationHintIndex = 1;
@@ -937,33 +921,36 @@ Node* BytecodeGraphBuilder::Environment::Checkpoint(
}
BytecodeGraphBuilder::BytecodeGraphBuilder(
- JSHeapBroker* broker, Zone* local_zone, BytecodeArrayRef bytecode_array,
- SharedFunctionInfoRef shared_info, FeedbackVectorRef feedback_vector,
- BailoutId osr_offset, JSGraph* jsgraph,
- CallFrequency const& invocation_frequency,
- SourcePositionTable* source_positions, NativeContextRef native_context,
- int inlining_id, BytecodeGraphBuilderFlags flags, TickCounter* tick_counter)
+ JSHeapBroker* broker, Zone* local_zone,
+ NativeContextRef const& native_context,
+ SharedFunctionInfoRef const& shared_info,
+ FeedbackVectorRef const& feedback_vector, BailoutId osr_offset,
+ JSGraph* jsgraph, CallFrequency const& invocation_frequency,
+ SourcePositionTable* source_positions, int inlining_id,
+ BytecodeGraphBuilderFlags flags, TickCounter* tick_counter)
: broker_(broker),
local_zone_(local_zone),
jsgraph_(jsgraph),
- invocation_frequency_(invocation_frequency),
- bytecode_array_(bytecode_array),
+ native_context_(native_context),
+ shared_info_(shared_info),
feedback_vector_(feedback_vector),
+ invocation_frequency_(invocation_frequency),
type_hint_lowering_(
- jsgraph, feedback_vector.object(),
+ broker, jsgraph, feedback_vector,
(flags & BytecodeGraphBuilderFlag::kBailoutOnUninitialized)
? JSTypeHintLowering::kBailoutOnUninitialized
: JSTypeHintLowering::kNoFlags),
frame_state_function_info_(common()->CreateFrameStateFunctionInfo(
FrameStateType::kInterpretedFunction,
- bytecode_array.parameter_count(), bytecode_array.register_count(),
+ bytecode_array().parameter_count(), bytecode_array().register_count(),
shared_info.object())),
bytecode_iterator_(
- base::make_unique<OffHeapBytecodeArray>(bytecode_array)),
+ base::make_unique<OffHeapBytecodeArray>(bytecode_array())),
bytecode_analysis_(broker_->GetBytecodeAnalysis(
- bytecode_array.object(), osr_offset,
+ bytecode_array().object(), osr_offset,
flags & BytecodeGraphBuilderFlag::kAnalyzeEnvironmentLiveness,
- !FLAG_concurrent_inlining)),
+ FLAG_concurrent_inlining ? SerializationPolicy::kAssumeSerialized
+ : SerializationPolicy::kSerializeIfNeeded)),
environment_(nullptr),
osr_(!osr_offset.IsNone()),
currently_peeled_loop_offset_(-1),
@@ -980,19 +967,17 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
state_values_cache_(jsgraph),
source_positions_(source_positions),
start_position_(shared_info.StartPosition(), inlining_id),
- shared_info_(shared_info),
- native_context_(native_context),
tick_counter_(tick_counter) {
if (FLAG_concurrent_inlining) {
// With concurrent inlining on, the source position address doesn't change
// because it's been copied from the heap.
source_position_iterator_ = base::make_unique<SourcePositionTableIterator>(
- Vector<const byte>(bytecode_array.source_positions_address(),
- bytecode_array.source_positions_size()));
+ Vector<const byte>(bytecode_array().source_positions_address(),
+ bytecode_array().source_positions_size()));
} else {
// Otherwise, we need to access the table through a handle.
source_position_iterator_ = base::make_unique<SourcePositionTableIterator>(
- handle(bytecode_array.object()->SourcePositionTableIfCollected(),
+ handle(bytecode_array().object()->SourcePositionTableIfCollected(),
isolate()));
}
}
@@ -1014,13 +999,13 @@ Node* BytecodeGraphBuilder::BuildLoadNativeContextField(int index) {
return result;
}
-VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) {
+FeedbackSource BytecodeGraphBuilder::CreateFeedbackSource(int slot_id) {
FeedbackSlot slot = FeedbackVector::ToSlot(slot_id);
- FeedbackNexus nexus(feedback_vector().object(), slot);
- return VectorSlotPair(feedback_vector().object(), slot, nexus.ic_state());
+ return FeedbackSource(feedback_vector(), slot);
}
void BytecodeGraphBuilder::CreateGraph() {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
SourcePositionTable::Scope pos_scope(source_positions_, start_position_);
// Set up the basic structure of the graph. Outputs for {Start} are the formal
@@ -1321,7 +1306,8 @@ void BytecodeGraphBuilder::VisitBytecodes() {
VisitSingleBytecode();
}
- if (has_one_shot_bytecode) {
+ if (!FLAG_concurrent_inlining && has_one_shot_bytecode) {
+ // (For concurrent inlining this is done in the serializer instead.)
isolate()->CountUsage(
v8::Isolate::UseCounterFeature::kOptimizedFunctionWithOneShotBytecode);
}
@@ -1340,8 +1326,9 @@ void BytecodeGraphBuilder::VisitLdaSmi() {
}
void BytecodeGraphBuilder::VisitLdaConstant() {
- Node* node = jsgraph()->Constant(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ ObjectRef object(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ Node* node = jsgraph()->Constant(object);
environment()->BindAccumulator(node);
}
@@ -1387,20 +1374,20 @@ void BytecodeGraphBuilder::VisitMov() {
environment()->BindRegister(bytecode_iterator().GetRegisterOperand(1), value);
}
-Node* BytecodeGraphBuilder::BuildLoadGlobal(Handle<Name> name,
+Node* BytecodeGraphBuilder::BuildLoadGlobal(NameRef name,
uint32_t feedback_slot_index,
TypeofMode typeof_mode) {
- VectorSlotPair feedback = CreateVectorSlotPair(feedback_slot_index);
- DCHECK(
- IsLoadGlobalICKind(feedback_vector().object()->GetKind(feedback.slot())));
- const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode);
+ FeedbackSource feedback = CreateFeedbackSource(feedback_slot_index);
+ DCHECK(IsLoadGlobalICKind(broker()->GetFeedbackSlotKind(feedback)));
+ const Operator* op =
+ javascript()->LoadGlobal(name.object(), feedback, typeof_mode);
return NewNode(op);
}
void BytecodeGraphBuilder::VisitLdaGlobal() {
PrepareEagerCheckpoint();
- Handle<Name> name = Handle<Name>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ NameRef name(broker(),
+ bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1);
Node* node =
BuildLoadGlobal(name, feedback_slot_index, TypeofMode::NOT_INSIDE_TYPEOF);
@@ -1409,8 +1396,8 @@ void BytecodeGraphBuilder::VisitLdaGlobal() {
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeof() {
PrepareEagerCheckpoint();
- Handle<Name> name = Handle<Name>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ NameRef name(broker(),
+ bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1);
Node* node =
BuildLoadGlobal(name, feedback_slot_index, TypeofMode::INSIDE_TYPEOF);
@@ -1419,15 +1406,16 @@ void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeof() {
void BytecodeGraphBuilder::VisitStaGlobal() {
PrepareEagerCheckpoint();
- Handle<Name> name = Handle<Name>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
- VectorSlotPair feedback =
- CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1));
+ NameRef name(broker(),
+ bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ FeedbackSource feedback =
+ CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
Node* value = environment()->LookupAccumulator();
LanguageMode language_mode =
- feedback.vector()->GetLanguageMode(feedback.slot());
- const Operator* op = javascript()->StoreGlobal(language_mode, name, feedback);
+ GetLanguageModeFromSlotKind(broker()->GetFeedbackSlotKind(feedback));
+ const Operator* op =
+ javascript()->StoreGlobal(language_mode, name.object(), feedback);
Node* node = NewNode(op, value);
environment()->RecordAfterState(node, Environment::kAttachFrameState);
}
@@ -1439,12 +1427,12 @@ void BytecodeGraphBuilder::VisitStaInArrayLiteral() {
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* index =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
- VectorSlotPair feedback =
- CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
+ FeedbackSource feedback =
+ CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
const Operator* op = javascript()->StoreInArrayLiteral(feedback);
JSTypeHintLowering::LoweringResult lowering =
- TryBuildSimplifiedStoreKeyed(op, array, index, value, feedback.slot());
+ TryBuildSimplifiedStoreKeyed(op, array, index, value, feedback.slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
@@ -1467,11 +1455,22 @@ void BytecodeGraphBuilder::VisitStaDataPropertyInLiteral() {
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
Node* value = environment()->LookupAccumulator();
int flags = bytecode_iterator().GetFlagOperand(2);
- VectorSlotPair feedback =
- CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3));
-
+ FeedbackSource feedback =
+ CreateFeedbackSource(bytecode_iterator().GetIndexOperand(3));
const Operator* op = javascript()->StoreDataPropertyInLiteral(feedback);
- Node* node = NewNode(op, object, name, value, jsgraph()->Constant(flags));
+
+ JSTypeHintLowering::LoweringResult lowering =
+ TryBuildSimplifiedStoreKeyed(op, object, name, value, feedback.slot);
+ if (lowering.IsExit()) return;
+
+ Node* node = nullptr;
+ if (lowering.IsSideEffectFree()) {
+ node = lowering.value();
+ } else {
+ DCHECK(!lowering.Changed());
+ node = NewNode(op, object, name, value, jsgraph()->Constant(flags));
+ }
+
environment()->RecordAfterState(node, Environment::kAttachFrameState);
}
@@ -1545,8 +1544,8 @@ void BytecodeGraphBuilder::VisitStaCurrentContextSlot() {
void BytecodeGraphBuilder::BuildLdaLookupSlot(TypeofMode typeof_mode) {
PrepareEagerCheckpoint();
- Node* name = jsgraph()->Constant(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ Node* name = jsgraph()->Constant(ObjectRef(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate())));
const Operator* op =
javascript()->CallRuntime(typeof_mode == TypeofMode::NOT_INSIDE_TYPEOF
? Runtime::kLoadLookupSlot
@@ -1630,8 +1629,9 @@ void BytecodeGraphBuilder::BuildLdaLookupContextSlot(TypeofMode typeof_mode) {
// Slow path, do a runtime load lookup.
set_environment(slow_environment);
{
- Node* name = jsgraph()->Constant(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ Node* name = jsgraph()->Constant(ObjectRef(
+ broker(),
+ bytecode_iterator().GetConstantForIndexOperand(0, isolate())));
const Operator* op =
javascript()->CallRuntime(typeof_mode == TypeofMode::NOT_INSIDE_TYPEOF
@@ -1666,8 +1666,8 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) {
// Fast path, do a global load.
{
PrepareEagerCheckpoint();
- Handle<Name> name = Handle<Name>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ NameRef name(broker(),
+ bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1);
Node* node = BuildLoadGlobal(name, feedback_slot_index, typeof_mode);
environment()->BindAccumulator(node, Environment::kAttachFrameState);
@@ -1682,8 +1682,9 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) {
// Slow path, do a runtime load lookup.
set_environment(slow_environment);
{
- Node* name = jsgraph()->Constant(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ Node* name = jsgraph()->Constant(NameRef(
+ broker(),
+ bytecode_iterator().GetConstantForIndexOperand(0, isolate())));
const Operator* op =
javascript()->CallRuntime(typeof_mode == TypeofMode::NOT_INSIDE_TYPEOF
@@ -1712,8 +1713,8 @@ void BytecodeGraphBuilder::VisitLdaLookupGlobalSlotInsideTypeof() {
void BytecodeGraphBuilder::VisitStaLookupSlot() {
PrepareEagerCheckpoint();
Node* value = environment()->LookupAccumulator();
- Node* name = jsgraph()->Constant(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ Node* name = jsgraph()->Constant(ObjectRef(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate())));
int bytecode_flags = bytecode_iterator().GetFlagOperand(1);
LanguageMode language_mode = static_cast<LanguageMode>(
interpreter::StoreLookupSlotFlags::LanguageModeBit::decode(
@@ -1737,14 +1738,14 @@ void BytecodeGraphBuilder::VisitLdaNamedProperty() {
PrepareEagerCheckpoint();
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- Handle<Name> name = Handle<Name>::cast(
- bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
- VectorSlotPair feedback =
- CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
- const Operator* op = javascript()->LoadNamed(name, feedback);
+ NameRef name(broker(),
+ bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
+ FeedbackSource feedback =
+ CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
+ const Operator* op = javascript()->LoadNamed(name.object(), feedback);
JSTypeHintLowering::LoweringResult lowering =
- TryBuildSimplifiedLoadNamed(op, object, feedback.slot());
+ TryBuildSimplifiedLoadNamed(op, object, feedback.slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
@@ -1761,9 +1762,9 @@ void BytecodeGraphBuilder::VisitLdaNamedPropertyNoFeedback() {
PrepareEagerCheckpoint();
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- Handle<Name> name = Handle<Name>::cast(
- bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
- const Operator* op = javascript()->LoadNamed(name, VectorSlotPair());
+ NameRef name(broker(),
+ bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
+ const Operator* op = javascript()->LoadNamed(name.object(), FeedbackSource());
Node* node = NewNode(op, object);
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
@@ -1773,12 +1774,12 @@ void BytecodeGraphBuilder::VisitLdaKeyedProperty() {
Node* key = environment()->LookupAccumulator();
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- VectorSlotPair feedback =
- CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1));
+ FeedbackSource feedback =
+ CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
const Operator* op = javascript()->LoadProperty(feedback);
JSTypeHintLowering::LoweringResult lowering =
- TryBuildSimplifiedLoadKeyed(op, object, key, feedback.slot());
+ TryBuildSimplifiedLoadKeyed(op, object, key, feedback.slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
@@ -1796,25 +1797,26 @@ void BytecodeGraphBuilder::BuildNamedStore(StoreMode store_mode) {
Node* value = environment()->LookupAccumulator();
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- Handle<Name> name = Handle<Name>::cast(
- bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
- VectorSlotPair feedback =
- CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
+ NameRef name(broker(),
+ bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
+ FeedbackSource feedback =
+ CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
const Operator* op;
if (store_mode == StoreMode::kOwn) {
DCHECK_EQ(FeedbackSlotKind::kStoreOwnNamed,
- feedback.vector()->GetKind(feedback.slot()));
- op = javascript()->StoreNamedOwn(name, feedback);
+ broker()->GetFeedbackSlotKind(feedback));
+
+ op = javascript()->StoreNamedOwn(name.object(), feedback);
} else {
DCHECK_EQ(StoreMode::kNormal, store_mode);
LanguageMode language_mode =
- feedback.vector()->GetLanguageMode(feedback.slot());
- op = javascript()->StoreNamed(language_mode, name, feedback);
+ GetLanguageModeFromSlotKind(broker()->GetFeedbackSlotKind(feedback));
+ op = javascript()->StoreNamed(language_mode, name.object(), feedback);
}
JSTypeHintLowering::LoweringResult lowering =
- TryBuildSimplifiedStoreNamed(op, object, value, feedback.slot());
+ TryBuildSimplifiedStoreNamed(op, object, value, feedback.slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
@@ -1836,12 +1838,12 @@ void BytecodeGraphBuilder::VisitStaNamedPropertyNoFeedback() {
Node* value = environment()->LookupAccumulator();
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- Handle<Name> name = Handle<Name>::cast(
- bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
+ NameRef name(broker(),
+ bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
LanguageMode language_mode =
static_cast<LanguageMode>(bytecode_iterator().GetFlagOperand(2));
const Operator* op =
- javascript()->StoreNamed(language_mode, name, VectorSlotPair());
+ javascript()->StoreNamed(language_mode, name.object(), FeedbackSource());
Node* node = NewNode(op, object, value);
environment()->RecordAfterState(node, Environment::kAttachFrameState);
}
@@ -1857,14 +1859,14 @@ void BytecodeGraphBuilder::VisitStaKeyedProperty() {
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* key =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
- VectorSlotPair feedback =
- CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
+ FeedbackSource source =
+ CreateFeedbackSource(bytecode_iterator().GetIndexOperand(2));
LanguageMode language_mode =
- feedback.vector()->GetLanguageMode(feedback.slot());
- const Operator* op = javascript()->StoreProperty(language_mode, feedback);
+ GetLanguageModeFromSlotKind(broker()->GetFeedbackSlotKind(source));
+ const Operator* op = javascript()->StoreProperty(language_mode, source);
JSTypeHintLowering::LoweringResult lowering =
- TryBuildSimplifiedStoreKeyed(op, object, key, value, feedback.slot());
+ TryBuildSimplifiedStoreKeyed(op, object, key, value, source.slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
@@ -1910,71 +1912,76 @@ void BytecodeGraphBuilder::VisitPopContext() {
}
void BytecodeGraphBuilder::VisitCreateClosure() {
- Handle<SharedFunctionInfo> shared_info = Handle<SharedFunctionInfo>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ SharedFunctionInfoRef shared_info(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
AllocationType allocation =
interpreter::CreateClosureFlags::PretenuredBit::decode(
bytecode_iterator().GetFlagOperand(2))
? AllocationType::kOld
: AllocationType::kYoung;
+
const Operator* op = javascript()->CreateClosure(
- shared_info,
- feedback_vector().object()->GetClosureFeedbackCell(
- bytecode_iterator().GetIndexOperand(1)),
- handle(jsgraph()->isolate()->builtins()->builtin(Builtins::kCompileLazy),
- isolate()),
+ shared_info.object(),
+ feedback_vector()
+ .GetClosureFeedbackCell(bytecode_iterator().GetIndexOperand(1))
+ .object(),
+ jsgraph()->isolate()->builtins()->builtin_handle(Builtins::kCompileLazy),
allocation);
Node* closure = NewNode(op);
environment()->BindAccumulator(closure);
}
void BytecodeGraphBuilder::VisitCreateBlockContext() {
- Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
-
- const Operator* op = javascript()->CreateBlockContext(scope_info);
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
+ ScopeInfoRef scope_info(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ const Operator* op = javascript()->CreateBlockContext(scope_info.object());
Node* context = NewNode(op);
environment()->BindAccumulator(context);
}
void BytecodeGraphBuilder::VisitCreateFunctionContext() {
- Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
+ ScopeInfoRef scope_info(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
uint32_t slots = bytecode_iterator().GetUnsignedImmediateOperand(1);
- const Operator* op =
- javascript()->CreateFunctionContext(scope_info, slots, FUNCTION_SCOPE);
+ const Operator* op = javascript()->CreateFunctionContext(
+ scope_info.object(), slots, FUNCTION_SCOPE);
Node* context = NewNode(op);
environment()->BindAccumulator(context);
}
void BytecodeGraphBuilder::VisitCreateEvalContext() {
- Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
+ ScopeInfoRef scope_info(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
uint32_t slots = bytecode_iterator().GetUnsignedImmediateOperand(1);
- const Operator* op =
- javascript()->CreateFunctionContext(scope_info, slots, EVAL_SCOPE);
+ const Operator* op = javascript()->CreateFunctionContext(scope_info.object(),
+ slots, EVAL_SCOPE);
Node* context = NewNode(op);
environment()->BindAccumulator(context);
}
void BytecodeGraphBuilder::VisitCreateCatchContext() {
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
interpreter::Register reg = bytecode_iterator().GetRegisterOperand(0);
Node* exception = environment()->LookupRegister(reg);
- Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::cast(
- bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
+ ScopeInfoRef scope_info(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
- const Operator* op = javascript()->CreateCatchContext(scope_info);
+ const Operator* op = javascript()->CreateCatchContext(scope_info.object());
Node* context = NewNode(op, exception);
environment()->BindAccumulator(context);
}
void BytecodeGraphBuilder::VisitCreateWithContext() {
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::cast(
- bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
+ ScopeInfoRef scope_info(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(1, isolate()));
- const Operator* op = javascript()->CreateWithContext(scope_info);
+ const Operator* op = javascript()->CreateWithContext(scope_info.object());
Node* context = NewNode(op, object);
environment()->BindAccumulator(context);
}
@@ -1998,22 +2005,21 @@ void BytecodeGraphBuilder::VisitCreateRestParameter() {
}
void BytecodeGraphBuilder::VisitCreateRegExpLiteral() {
- Handle<String> constant_pattern = Handle<String>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ StringRef constant_pattern(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
int const slot_id = bytecode_iterator().GetIndexOperand(1);
- VectorSlotPair pair = CreateVectorSlotPair(slot_id);
+ FeedbackSource pair = CreateFeedbackSource(slot_id);
int literal_flags = bytecode_iterator().GetFlagOperand(2);
- Node* literal = NewNode(
- javascript()->CreateLiteralRegExp(constant_pattern, pair, literal_flags));
+ Node* literal = NewNode(javascript()->CreateLiteralRegExp(
+ constant_pattern.object(), pair, literal_flags));
environment()->BindAccumulator(literal, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitCreateArrayLiteral() {
- Handle<ArrayBoilerplateDescription> array_boilerplate_description =
- Handle<ArrayBoilerplateDescription>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ ArrayBoilerplateDescriptionRef array_boilerplate_description(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
int const slot_id = bytecode_iterator().GetIndexOperand(1);
- VectorSlotPair pair = CreateVectorSlotPair(slot_id);
+ FeedbackSource pair = CreateFeedbackSource(slot_id);
int bytecode_flags = bytecode_iterator().GetFlagOperand(2);
int literal_flags =
interpreter::CreateArrayLiteralFlags::FlagsBits::decode(bytecode_flags);
@@ -2025,15 +2031,16 @@ void BytecodeGraphBuilder::VisitCreateArrayLiteral() {
// TODO(mstarzinger): Thread through number of elements. The below number is
// only an estimate and does not match {ArrayLiteral::values::length}.
int number_of_elements =
- array_boilerplate_description->constant_elements().length();
+ array_boilerplate_description.constants_elements_length();
Node* literal = NewNode(javascript()->CreateLiteralArray(
- array_boilerplate_description, pair, literal_flags, number_of_elements));
+ array_boilerplate_description.object(), pair, literal_flags,
+ number_of_elements));
environment()->BindAccumulator(literal, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitCreateEmptyArrayLiteral() {
int const slot_id = bytecode_iterator().GetIndexOperand(0);
- VectorSlotPair pair = CreateVectorSlotPair(slot_id);
+ FeedbackSource pair = CreateFeedbackSource(slot_id);
Node* literal = NewNode(javascript()->CreateEmptyLiteralArray(pair));
environment()->BindAccumulator(literal);
}
@@ -2045,19 +2052,18 @@ void BytecodeGraphBuilder::VisitCreateArrayFromIterable() {
}
void BytecodeGraphBuilder::VisitCreateObjectLiteral() {
- Handle<ObjectBoilerplateDescription> constant_properties =
- Handle<ObjectBoilerplateDescription>::cast(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ ObjectBoilerplateDescriptionRef constant_properties(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
int const slot_id = bytecode_iterator().GetIndexOperand(1);
- VectorSlotPair pair = CreateVectorSlotPair(slot_id);
+ FeedbackSource pair = CreateFeedbackSource(slot_id);
int bytecode_flags = bytecode_iterator().GetFlagOperand(2);
int literal_flags =
interpreter::CreateObjectLiteralFlags::FlagsBits::decode(bytecode_flags);
// TODO(mstarzinger): Thread through number of properties. The below number is
// only an estimate and does not match {ObjectLiteral::properties_count}.
- int number_of_properties = constant_properties->size();
+ int number_of_properties = constant_properties.size();
Node* literal = NewNode(javascript()->CreateLiteralObject(
- constant_properties, pair, literal_flags, number_of_properties));
+ constant_properties.object(), pair, literal_flags, number_of_properties));
environment()->BindAccumulator(literal, Environment::kAttachFrameState);
}
@@ -2074,7 +2080,7 @@ void BytecodeGraphBuilder::VisitCloneObject() {
int flags = bytecode_iterator().GetFlagOperand(1);
int slot = bytecode_iterator().GetIndexOperand(2);
const Operator* op =
- javascript()->CloneObject(CreateVectorSlotPair(slot), flags);
+ javascript()->CloneObject(CreateFeedbackSource(slot), flags);
Node* value = NewNode(op, source);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
@@ -2140,14 +2146,14 @@ void BytecodeGraphBuilder::BuildCall(ConvertReceiverMode receiver_mode,
receiver_mode);
PrepareEagerCheckpoint();
- VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
-
+ FeedbackSource feedback = CreateFeedbackSource(slot_id);
CallFrequency frequency = ComputeCallFrequency(slot_id);
- const Operator* op =
- javascript()->Call(arg_count, frequency, feedback, receiver_mode,
- GetSpeculationMode(slot_id));
+ SpeculationMode speculation_mode = GetSpeculationMode(slot_id);
+ const Operator* op = javascript()->Call(arg_count, frequency, feedback,
+ receiver_mode, speculation_mode);
+
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
- op, args, static_cast<int>(arg_count), feedback.slot());
+ op, args, static_cast<int>(arg_count), feedback.slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
@@ -2325,14 +2331,13 @@ void BytecodeGraphBuilder::VisitCallWithSpread() {
Node* const* args = GetCallArgumentsFromRegisters(callee, receiver_node,
first_arg, arg_count);
int const slot_id = bytecode_iterator().GetIndexOperand(3);
- VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
-
+ FeedbackSource feedback = CreateFeedbackSource(slot_id);
CallFrequency frequency = ComputeCallFrequency(slot_id);
const Operator* op = javascript()->CallWithSpread(
static_cast<int>(reg_count + 1), frequency, feedback);
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
- op, args, static_cast<int>(arg_count), feedback.slot());
+ op, args, static_cast<int>(arg_count), feedback.slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
@@ -2438,7 +2443,7 @@ void BytecodeGraphBuilder::VisitConstruct() {
interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
int const slot_id = bytecode_iterator().GetIndexOperand(3);
- VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
+ FeedbackSource feedback = CreateFeedbackSource(slot_id);
Node* new_target = environment()->LookupAccumulator();
Node* callee = environment()->LookupRegister(callee_reg);
@@ -2450,7 +2455,7 @@ void BytecodeGraphBuilder::VisitConstruct() {
Node* const* args = GetConstructArgumentsFromRegister(callee, new_target,
first_reg, arg_count);
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedConstruct(
- op, args, static_cast<int>(arg_count), feedback.slot());
+ op, args, static_cast<int>(arg_count), feedback.slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
@@ -2469,7 +2474,7 @@ void BytecodeGraphBuilder::VisitConstructWithSpread() {
interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
int const slot_id = bytecode_iterator().GetIndexOperand(3);
- VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
+ FeedbackSource feedback = CreateFeedbackSource(slot_id);
Node* new_target = environment()->LookupAccumulator();
Node* callee = environment()->LookupRegister(callee_reg);
@@ -2481,7 +2486,7 @@ void BytecodeGraphBuilder::VisitConstructWithSpread() {
Node* const* args = GetConstructArgumentsFromRegister(callee, new_target,
first_reg, arg_count);
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedConstruct(
- op, args, static_cast<int>(arg_count), feedback.slot());
+ op, args, static_cast<int>(arg_count), feedback.slot);
if (lowering.IsExit()) return;
Node* node = nullptr;
@@ -2568,8 +2573,8 @@ void BytecodeGraphBuilder::VisitThrowReferenceErrorIfHole() {
Node* accumulator = environment()->LookupAccumulator();
Node* check_for_hole = NewNode(simplified()->ReferenceEqual(), accumulator,
jsgraph()->TheHoleConstant());
- Node* name = jsgraph()->Constant(
- bytecode_iterator().GetConstantForIndexOperand(0, isolate()));
+ Node* name = jsgraph()->Constant(ObjectRef(
+ broker(), bytecode_iterator().GetConstantForIndexOperand(0, isolate())));
BuildHoleCheckAndThrow(check_for_hole,
Runtime::kThrowAccessedUninitializedVariable, name);
}
@@ -2640,23 +2645,23 @@ void BytecodeGraphBuilder::BuildBinaryOp(const Operator* op) {
BinaryOperationHint BytecodeGraphBuilder::GetBinaryOperationHint(
int operand_index) {
FeedbackSlot slot = bytecode_iterator().GetSlotOperand(operand_index);
- FeedbackNexus nexus(feedback_vector().object(), slot);
- return nexus.GetBinaryOperationFeedback();
+ FeedbackSource source(feedback_vector(), slot);
+ return broker()->GetFeedbackForBinaryOperation(source);
}
// Helper function to create compare operation hint from the recorded type
// feedback.
CompareOperationHint BytecodeGraphBuilder::GetCompareOperationHint() {
FeedbackSlot slot = bytecode_iterator().GetSlotOperand(1);
- FeedbackNexus nexus(feedback_vector().object(), slot);
- return nexus.GetCompareOperationFeedback();
+ FeedbackSource source(feedback_vector(), slot);
+ return broker()->GetFeedbackForCompareOperation(source);
}
// Helper function to create for-in mode from the recorded type feedback.
ForInMode BytecodeGraphBuilder::GetForInMode(int operand_index) {
FeedbackSlot slot = bytecode_iterator().GetSlotOperand(operand_index);
- FeedbackNexus nexus(feedback_vector().object(), slot);
- switch (nexus.GetForInFeedback()) {
+ FeedbackSource source(feedback_vector(), slot);
+ switch (broker()->GetFeedbackForForIn(source)) {
case ForInHint::kNone:
case ForInHint::kEnumCacheKeysAndIndices:
return ForInMode::kUseEnumCacheKeysAndIndices;
@@ -2670,11 +2675,12 @@ ForInMode BytecodeGraphBuilder::GetForInMode(int operand_index) {
CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
if (invocation_frequency_.IsUnknown()) return CallFrequency();
- FeedbackNexus nexus(feedback_vector().object(),
- FeedbackVector::ToSlot(slot_id));
- float feedback_frequency = nexus.ComputeCallFrequency();
- if (feedback_frequency == 0.0f) {
- // This is to prevent multiplying zero and infinity.
+ FeedbackSlot slot = FeedbackVector::ToSlot(slot_id);
+ FeedbackSource source(feedback_vector(), slot);
+ ProcessedFeedback const& feedback = broker()->GetFeedbackForCall(source);
+ float feedback_frequency =
+ feedback.IsInsufficient() ? 0.0f : feedback.AsCall().frequency();
+ if (feedback_frequency == 0.0f) { // Prevent multiplying zero and infinity.
return CallFrequency(0.0f);
} else {
return CallFrequency(feedback_frequency * invocation_frequency_.value());
@@ -2682,9 +2688,11 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
}
SpeculationMode BytecodeGraphBuilder::GetSpeculationMode(int slot_id) const {
- FeedbackNexus nexus(feedback_vector().object(),
- FeedbackVector::ToSlot(slot_id));
- return nexus.GetSpeculationMode();
+ FeedbackSlot slot = FeedbackVector::ToSlot(slot_id);
+ FeedbackSource source(feedback_vector(), slot);
+ ProcessedFeedback const& feedback = broker()->GetFeedbackForCall(source);
+ return feedback.IsInsufficient() ? SpeculationMode::kDisallowSpeculation
+ : feedback.AsCall().speculation_mode();
}
void BytecodeGraphBuilder::VisitBitwiseNot() {
@@ -2922,15 +2930,15 @@ void BytecodeGraphBuilder::VisitTestIn() {
Node* object = environment()->LookupAccumulator();
Node* key =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- VectorSlotPair feedback =
- CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1));
+ FeedbackSource feedback =
+ CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
Node* node = NewNode(javascript()->HasProperty(feedback), object, key);
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitTestInstanceOf() {
int const slot_index = bytecode_iterator().GetIndexOperand(1);
- BuildCompareOp(javascript()->InstanceOf(CreateVectorSlotPair(slot_index)));
+ BuildCompareOp(javascript()->InstanceOf(CreateFeedbackSource(slot_index)));
}
void BytecodeGraphBuilder::VisitTestUndetectable() {
@@ -3132,6 +3140,16 @@ void BytecodeGraphBuilder::VisitJumpIfNotUndefinedConstant() {
BuildJumpIfNotEqual(jsgraph()->UndefinedConstant());
}
+void BytecodeGraphBuilder::VisitJumpIfUndefinedOrNull() {
+ BuildJumpIfEqual(jsgraph()->UndefinedConstant());
+ BuildJumpIfEqual(jsgraph()->NullConstant());
+}
+
+void BytecodeGraphBuilder::VisitJumpIfUndefinedOrNullConstant() {
+ BuildJumpIfEqual(jsgraph()->UndefinedConstant());
+ BuildJumpIfEqual(jsgraph()->NullConstant());
+}
+
void BytecodeGraphBuilder::VisitJumpLoop() { BuildJump(); }
void BytecodeGraphBuilder::BuildSwitchOnSmi(Node* condition) {
@@ -3151,7 +3169,7 @@ void BytecodeGraphBuilder::VisitSwitchOnSmiNoFeedback() {
PrepareEagerCheckpoint();
Node* acc = environment()->LookupAccumulator();
- Node* acc_smi = NewNode(simplified()->CheckSmi(VectorSlotPair()), acc);
+ Node* acc_smi = NewNode(simplified()->CheckSmi(FeedbackSource()), acc);
BuildSwitchOnSmi(acc_smi);
}
@@ -3277,6 +3295,23 @@ void BytecodeGraphBuilder::VisitForInStep() {
environment()->BindAccumulator(index, Environment::kAttachFrameState);
}
+void BytecodeGraphBuilder::VisitGetIterator() {
+ PrepareEagerCheckpoint();
+ Node* object =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
+ FeedbackSource feedback =
+ CreateFeedbackSource(bytecode_iterator().GetIndexOperand(1));
+ const Operator* op = javascript()->GetIterator(feedback);
+
+ JSTypeHintLowering::LoweringResult lowering =
+ TryBuildSimplifiedLoadNamed(op, object, feedback.slot);
+ if (lowering.IsExit()) return;
+
+ DCHECK(!lowering.Changed());
+ Node* node = NewNode(op, object);
+ environment()->BindAccumulator(node, Environment::kAttachFrameState);
+}
+
void BytecodeGraphBuilder::VisitSuspendGenerator() {
Node* generator = environment()->LookupRegister(
bytecode_iterator().GetRegisterOperand(0));
@@ -4016,25 +4051,18 @@ void BytecodeGraphBuilder::UpdateSourcePosition(int offset) {
}
void BuildGraphFromBytecode(JSHeapBroker* broker, Zone* local_zone,
- Handle<BytecodeArray> bytecode_array,
- Handle<SharedFunctionInfo> shared,
- Handle<FeedbackVector> feedback_vector,
+ SharedFunctionInfoRef const& shared_info,
+ FeedbackVectorRef const& feedback_vector,
BailoutId osr_offset, JSGraph* jsgraph,
CallFrequency const& invocation_frequency,
SourcePositionTable* source_positions,
- Handle<NativeContext> native_context,
int inlining_id, BytecodeGraphBuilderFlags flags,
TickCounter* tick_counter) {
- BytecodeArrayRef bytecode_array_ref(broker, bytecode_array);
- DCHECK(bytecode_array_ref.IsSerializedForCompilation());
- FeedbackVectorRef feedback_vector_ref(broker, feedback_vector);
- SharedFunctionInfoRef shared_ref(broker, shared);
- DCHECK(shared_ref.IsSerializedForCompilation(feedback_vector_ref));
- NativeContextRef native_context_ref(broker, native_context);
+ DCHECK(shared_info.IsSerializedForCompilation(feedback_vector));
BytecodeGraphBuilder builder(
- broker, local_zone, bytecode_array_ref, shared_ref, feedback_vector_ref,
- osr_offset, jsgraph, invocation_frequency, source_positions,
- native_context_ref, inlining_id, flags, tick_counter);
+ broker, local_zone, broker->target_native_context(), shared_info,
+ feedback_vector, osr_offset, jsgraph, invocation_frequency,
+ source_positions, inlining_id, flags, tick_counter);
builder.CreateGraph();
}
diff --git a/deps/v8/src/compiler/bytecode-graph-builder.h b/deps/v8/src/compiler/bytecode-graph-builder.h
index 682569778f..03e900c214 100644
--- a/deps/v8/src/compiler/bytecode-graph-builder.h
+++ b/deps/v8/src/compiler/bytecode-graph-builder.h
@@ -39,13 +39,11 @@ using BytecodeGraphBuilderFlags = base::Flags<BytecodeGraphBuilderFlag>;
// Note: {invocation_frequency} is taken by reference to work around a GCC bug
// on AIX (v8:8193).
void BuildGraphFromBytecode(JSHeapBroker* broker, Zone* local_zone,
- Handle<BytecodeArray> bytecode_array,
- Handle<SharedFunctionInfo> shared,
- Handle<FeedbackVector> feedback_vector,
+ SharedFunctionInfoRef const& shared_info,
+ FeedbackVectorRef const& feedback_vector,
BailoutId osr_offset, JSGraph* jsgraph,
CallFrequency const& invocation_frequency,
SourcePositionTable* source_positions,
- Handle<NativeContext> native_context,
int inlining_id, BytecodeGraphBuilderFlags flags,
TickCounter* tick_counter);
diff --git a/deps/v8/src/compiler/c-linkage.cc b/deps/v8/src/compiler/c-linkage.cc
index e472a6a72c..428ba058a7 100644
--- a/deps/v8/src/compiler/c-linkage.cc
+++ b/deps/v8/src/compiler/c-linkage.cc
@@ -140,8 +140,9 @@ namespace {
// General code uses the above configuration data.
-CallDescriptor* Linkage::GetSimplifiedCDescriptor(
- Zone* zone, const MachineSignature* msig, bool set_initialize_root_flag) {
+CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
+ const MachineSignature* msig,
+ CallDescriptor::Flags flags) {
DCHECK_LE(msig->parameter_count(), static_cast<size_t>(kMaxCParameters));
LocationSignature::Builder locations(zone, msig->return_count(),
@@ -220,10 +221,7 @@ CallDescriptor* Linkage::GetSimplifiedCDescriptor(
// The target for C calls is always an address (i.e. machine pointer).
MachineType target_type = MachineType::Pointer();
LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
- CallDescriptor::Flags flags = CallDescriptor::kNoAllocate;
- if (set_initialize_root_flag) {
- flags |= CallDescriptor::kInitializeRootRegister;
- }
+ flags |= CallDescriptor::kNoAllocate;
return new (zone) CallDescriptor( // --
CallDescriptor::kCallAddress, // kind
diff --git a/deps/v8/src/compiler/code-assembler.cc b/deps/v8/src/compiler/code-assembler.cc
index af0ba98ffd..4f18011463 100644
--- a/deps/v8/src/compiler/code-assembler.cc
+++ b/deps/v8/src/compiler/code-assembler.cc
@@ -34,9 +34,9 @@ namespace compiler {
static_assert(std::is_convertible<TNode<Number>, TNode<Object>>::value,
"test subtyping");
-static_assert(std::is_convertible<TNode<UnionT<Smi, HeapNumber>>,
- TNode<UnionT<Smi, HeapObject>>>::value,
- "test subtyping");
+static_assert(
+ std::is_convertible<TNode<Number>, TNode<UnionT<Smi, HeapObject>>>::value,
+ "test subtyping");
static_assert(
!std::is_convertible<TNode<UnionT<Smi, HeapObject>>, TNode<Number>>::value,
"test subtyping");
@@ -188,6 +188,7 @@ Handle<Code> CodeAssembler::GenerateCode(CodeAssemblerState* state,
}
bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); }
+bool CodeAssembler::Is32() const { return raw_assembler()->machine()->Is32(); }
bool CodeAssembler::IsFloat64RoundUpSupported() const {
return raw_assembler()->machine()->Float64RoundUp().IsSupported();
@@ -228,7 +229,7 @@ void CodeAssembler::GenerateCheckMaybeObjectIsObject(Node* node,
&ok);
EmbeddedVector<char, 1024> message;
SNPrintF(message, "no Object: %s", location);
- Node* message_node = StringConstant(message.begin());
+ TNode<String> message_node = StringConstant(message.begin());
// This somewhat misuses the AbortCSAAssert runtime function. This will print
// "abort: CSA_ASSERT failed: <message>", which is good enough.
AbortCSAAssert(message_node);
@@ -259,7 +260,7 @@ TNode<Number> CodeAssembler::NumberConstant(double value) {
// (see AllocateAndInstallRequestedHeapObjects) since that makes it easier
// to generate constant lookups for embedded builtins.
return UncheckedCast<Number>(HeapConstant(
- isolate()->factory()->NewHeapNumber(value, AllocationType::kOld)));
+ isolate()->factory()->NewHeapNumberForCodeAssembler(value)));
}
}
@@ -299,16 +300,12 @@ TNode<Float64T> CodeAssembler::Float64Constant(double value) {
return UncheckedCast<Float64T>(raw_assembler()->Float64Constant(value));
}
-TNode<HeapNumber> CodeAssembler::NaNConstant() {
- return UncheckedCast<HeapNumber>(LoadRoot(RootIndex::kNanValue));
-}
-
-bool CodeAssembler::ToInt32Constant(Node* node, int32_t& out_value) {
+bool CodeAssembler::ToInt32Constant(Node* node, int32_t* out_value) {
{
Int64Matcher m(node);
if (m.HasValue() && m.IsInRange(std::numeric_limits<int32_t>::min(),
std::numeric_limits<int32_t>::max())) {
- out_value = static_cast<int32_t>(m.Value());
+ *out_value = static_cast<int32_t>(m.Value());
return true;
}
}
@@ -316,7 +313,7 @@ bool CodeAssembler::ToInt32Constant(Node* node, int32_t& out_value) {
{
Int32Matcher m(node);
if (m.HasValue()) {
- out_value = m.Value();
+ *out_value = m.Value();
return true;
}
}
@@ -324,9 +321,9 @@ bool CodeAssembler::ToInt32Constant(Node* node, int32_t& out_value) {
return false;
}
-bool CodeAssembler::ToInt64Constant(Node* node, int64_t& out_value) {
+bool CodeAssembler::ToInt64Constant(Node* node, int64_t* out_value) {
Int64Matcher m(node);
- if (m.HasValue()) out_value = m.Value();
+ if (m.HasValue()) *out_value = m.Value();
return m.HasValue();
}
@@ -345,13 +342,13 @@ bool CodeAssembler::ToSmiConstant(Node* node, Smi* out_value) {
return false;
}
-bool CodeAssembler::ToIntPtrConstant(Node* node, intptr_t& out_value) {
+bool CodeAssembler::ToIntPtrConstant(Node* node, intptr_t* out_value) {
if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned ||
node->opcode() == IrOpcode::kBitcastWordToTagged) {
node = node->InputAt(0);
}
IntPtrMatcher m(node);
- if (m.HasValue()) out_value = m.Value();
+ if (m.HasValue()) *out_value = m.Value();
return m.HasValue();
}
@@ -383,6 +380,9 @@ TNode<Context> CodeAssembler::GetJSContextParameter() {
}
void CodeAssembler::Return(SloppyTNode<Object> value) {
+ // TODO(leszeks): This could also return a non-object, depending on the call
+ // descriptor. We should probably have multiple return overloads with
+ // different TNode types which DCHECK the call descriptor.
return raw_assembler()->Return(value);
}
@@ -453,10 +453,6 @@ TNode<RawPtrT> CodeAssembler::LoadParentFramePointer() {
return UncheckedCast<RawPtrT>(raw_assembler()->LoadParentFramePointer());
}
-TNode<RawPtrT> CodeAssembler::LoadStackPointer() {
- return UncheckedCast<RawPtrT>(raw_assembler()->LoadStackPointer());
-}
-
TNode<Object> CodeAssembler::TaggedPoisonOnSpeculation(
SloppyTNode<Object> value) {
return UncheckedCast<Object>(
@@ -478,9 +474,9 @@ CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)
TNode<WordT> CodeAssembler::IntPtrAdd(SloppyTNode<WordT> left,
SloppyTNode<WordT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return IntPtrConstant(left_constant + right_constant);
@@ -499,9 +495,9 @@ TNode<WordT> CodeAssembler::IntPtrAdd(SloppyTNode<WordT> left,
TNode<IntPtrT> CodeAssembler::IntPtrDiv(TNode<IntPtrT> left,
TNode<IntPtrT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_right_constant) {
if (is_left_constant) {
return IntPtrConstant(left_constant / right_constant);
@@ -516,9 +512,9 @@ TNode<IntPtrT> CodeAssembler::IntPtrDiv(TNode<IntPtrT> left,
TNode<WordT> CodeAssembler::IntPtrSub(SloppyTNode<WordT> left,
SloppyTNode<WordT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return IntPtrConstant(left_constant - right_constant);
@@ -534,9 +530,9 @@ TNode<WordT> CodeAssembler::IntPtrSub(SloppyTNode<WordT> left,
TNode<WordT> CodeAssembler::IntPtrMul(SloppyTNode<WordT> left,
SloppyTNode<WordT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return IntPtrConstant(left_constant * right_constant);
@@ -568,12 +564,16 @@ TNode<Word32T> CodeAssembler::Word32Shr(SloppyTNode<Word32T> value, int shift) {
return (shift != 0) ? Word32Shr(value, Int32Constant(shift)) : value;
}
+TNode<Word32T> CodeAssembler::Word32Sar(SloppyTNode<Word32T> value, int shift) {
+ return (shift != 0) ? Word32Sar(value, Int32Constant(shift)) : value;
+}
+
TNode<WordT> CodeAssembler::WordOr(SloppyTNode<WordT> left,
SloppyTNode<WordT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return IntPtrConstant(left_constant | right_constant);
@@ -592,9 +592,9 @@ TNode<WordT> CodeAssembler::WordOr(SloppyTNode<WordT> left,
TNode<WordT> CodeAssembler::WordAnd(SloppyTNode<WordT> left,
SloppyTNode<WordT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return IntPtrConstant(left_constant & right_constant);
@@ -606,9 +606,9 @@ TNode<WordT> CodeAssembler::WordAnd(SloppyTNode<WordT> left,
TNode<WordT> CodeAssembler::WordXor(SloppyTNode<WordT> left,
SloppyTNode<WordT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return IntPtrConstant(left_constant ^ right_constant);
@@ -620,9 +620,9 @@ TNode<WordT> CodeAssembler::WordXor(SloppyTNode<WordT> left,
TNode<WordT> CodeAssembler::WordShl(SloppyTNode<WordT> left,
SloppyTNode<IntegralT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return IntPtrConstant(left_constant << right_constant);
@@ -638,9 +638,9 @@ TNode<WordT> CodeAssembler::WordShl(SloppyTNode<WordT> left,
TNode<WordT> CodeAssembler::WordShr(SloppyTNode<WordT> left,
SloppyTNode<IntegralT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return IntPtrConstant(static_cast<uintptr_t>(left_constant) >>
@@ -657,9 +657,9 @@ TNode<WordT> CodeAssembler::WordShr(SloppyTNode<WordT> left,
TNode<WordT> CodeAssembler::WordSar(SloppyTNode<WordT> left,
SloppyTNode<IntegralT> right) {
intptr_t left_constant;
- bool is_left_constant = ToIntPtrConstant(left, left_constant);
+ bool is_left_constant = ToIntPtrConstant(left, &left_constant);
intptr_t right_constant;
- bool is_right_constant = ToIntPtrConstant(right, right_constant);
+ bool is_right_constant = ToIntPtrConstant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return IntPtrConstant(left_constant >> right_constant);
@@ -675,9 +675,9 @@ TNode<WordT> CodeAssembler::WordSar(SloppyTNode<WordT> left,
TNode<Word32T> CodeAssembler::Word32Or(SloppyTNode<Word32T> left,
SloppyTNode<Word32T> right) {
int32_t left_constant;
- bool is_left_constant = ToInt32Constant(left, left_constant);
+ bool is_left_constant = ToInt32Constant(left, &left_constant);
int32_t right_constant;
- bool is_right_constant = ToInt32Constant(right, right_constant);
+ bool is_right_constant = ToInt32Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int32Constant(left_constant | right_constant);
@@ -696,9 +696,9 @@ TNode<Word32T> CodeAssembler::Word32Or(SloppyTNode<Word32T> left,
TNode<Word32T> CodeAssembler::Word32And(SloppyTNode<Word32T> left,
SloppyTNode<Word32T> right) {
int32_t left_constant;
- bool is_left_constant = ToInt32Constant(left, left_constant);
+ bool is_left_constant = ToInt32Constant(left, &left_constant);
int32_t right_constant;
- bool is_right_constant = ToInt32Constant(right, right_constant);
+ bool is_right_constant = ToInt32Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int32Constant(left_constant & right_constant);
@@ -710,9 +710,9 @@ TNode<Word32T> CodeAssembler::Word32And(SloppyTNode<Word32T> left,
TNode<Word32T> CodeAssembler::Word32Xor(SloppyTNode<Word32T> left,
SloppyTNode<Word32T> right) {
int32_t left_constant;
- bool is_left_constant = ToInt32Constant(left, left_constant);
+ bool is_left_constant = ToInt32Constant(left, &left_constant);
int32_t right_constant;
- bool is_right_constant = ToInt32Constant(right, right_constant);
+ bool is_right_constant = ToInt32Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int32Constant(left_constant ^ right_constant);
@@ -724,9 +724,9 @@ TNode<Word32T> CodeAssembler::Word32Xor(SloppyTNode<Word32T> left,
TNode<Word32T> CodeAssembler::Word32Shl(SloppyTNode<Word32T> left,
SloppyTNode<Word32T> right) {
int32_t left_constant;
- bool is_left_constant = ToInt32Constant(left, left_constant);
+ bool is_left_constant = ToInt32Constant(left, &left_constant);
int32_t right_constant;
- bool is_right_constant = ToInt32Constant(right, right_constant);
+ bool is_right_constant = ToInt32Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int32Constant(left_constant << right_constant);
@@ -742,9 +742,9 @@ TNode<Word32T> CodeAssembler::Word32Shl(SloppyTNode<Word32T> left,
TNode<Word32T> CodeAssembler::Word32Shr(SloppyTNode<Word32T> left,
SloppyTNode<Word32T> right) {
int32_t left_constant;
- bool is_left_constant = ToInt32Constant(left, left_constant);
+ bool is_left_constant = ToInt32Constant(left, &left_constant);
int32_t right_constant;
- bool is_right_constant = ToInt32Constant(right, right_constant);
+ bool is_right_constant = ToInt32Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int32Constant(static_cast<uint32_t>(left_constant) >>
@@ -761,9 +761,9 @@ TNode<Word32T> CodeAssembler::Word32Shr(SloppyTNode<Word32T> left,
TNode<Word32T> CodeAssembler::Word32Sar(SloppyTNode<Word32T> left,
SloppyTNode<Word32T> right) {
int32_t left_constant;
- bool is_left_constant = ToInt32Constant(left, left_constant);
+ bool is_left_constant = ToInt32Constant(left, &left_constant);
int32_t right_constant;
- bool is_right_constant = ToInt32Constant(right, right_constant);
+ bool is_right_constant = ToInt32Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int32Constant(left_constant >> right_constant);
@@ -779,9 +779,9 @@ TNode<Word32T> CodeAssembler::Word32Sar(SloppyTNode<Word32T> left,
TNode<Word64T> CodeAssembler::Word64Or(SloppyTNode<Word64T> left,
SloppyTNode<Word64T> right) {
int64_t left_constant;
- bool is_left_constant = ToInt64Constant(left, left_constant);
+ bool is_left_constant = ToInt64Constant(left, &left_constant);
int64_t right_constant;
- bool is_right_constant = ToInt64Constant(right, right_constant);
+ bool is_right_constant = ToInt64Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int64Constant(left_constant | right_constant);
@@ -800,9 +800,9 @@ TNode<Word64T> CodeAssembler::Word64Or(SloppyTNode<Word64T> left,
TNode<Word64T> CodeAssembler::Word64And(SloppyTNode<Word64T> left,
SloppyTNode<Word64T> right) {
int64_t left_constant;
- bool is_left_constant = ToInt64Constant(left, left_constant);
+ bool is_left_constant = ToInt64Constant(left, &left_constant);
int64_t right_constant;
- bool is_right_constant = ToInt64Constant(right, right_constant);
+ bool is_right_constant = ToInt64Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int64Constant(left_constant & right_constant);
@@ -814,9 +814,9 @@ TNode<Word64T> CodeAssembler::Word64And(SloppyTNode<Word64T> left,
TNode<Word64T> CodeAssembler::Word64Xor(SloppyTNode<Word64T> left,
SloppyTNode<Word64T> right) {
int64_t left_constant;
- bool is_left_constant = ToInt64Constant(left, left_constant);
+ bool is_left_constant = ToInt64Constant(left, &left_constant);
int64_t right_constant;
- bool is_right_constant = ToInt64Constant(right, right_constant);
+ bool is_right_constant = ToInt64Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int64Constant(left_constant ^ right_constant);
@@ -828,9 +828,9 @@ TNode<Word64T> CodeAssembler::Word64Xor(SloppyTNode<Word64T> left,
TNode<Word64T> CodeAssembler::Word64Shl(SloppyTNode<Word64T> left,
SloppyTNode<Word64T> right) {
int64_t left_constant;
- bool is_left_constant = ToInt64Constant(left, left_constant);
+ bool is_left_constant = ToInt64Constant(left, &left_constant);
int64_t right_constant;
- bool is_right_constant = ToInt64Constant(right, right_constant);
+ bool is_right_constant = ToInt64Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int64Constant(left_constant << right_constant);
@@ -846,9 +846,9 @@ TNode<Word64T> CodeAssembler::Word64Shl(SloppyTNode<Word64T> left,
TNode<Word64T> CodeAssembler::Word64Shr(SloppyTNode<Word64T> left,
SloppyTNode<Word64T> right) {
int64_t left_constant;
- bool is_left_constant = ToInt64Constant(left, left_constant);
+ bool is_left_constant = ToInt64Constant(left, &left_constant);
int64_t right_constant;
- bool is_right_constant = ToInt64Constant(right, right_constant);
+ bool is_right_constant = ToInt64Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int64Constant(static_cast<uint64_t>(left_constant) >>
@@ -865,9 +865,9 @@ TNode<Word64T> CodeAssembler::Word64Shr(SloppyTNode<Word64T> left,
TNode<Word64T> CodeAssembler::Word64Sar(SloppyTNode<Word64T> left,
SloppyTNode<Word64T> right) {
int64_t left_constant;
- bool is_left_constant = ToInt64Constant(left, left_constant);
+ bool is_left_constant = ToInt64Constant(left, &left_constant);
int64_t right_constant;
- bool is_right_constant = ToInt64Constant(right, right_constant);
+ bool is_right_constant = ToInt64Constant(right, &right_constant);
if (is_left_constant) {
if (is_right_constant) {
return Int64Constant(left_constant >> right_constant);
@@ -880,14 +880,13 @@ TNode<Word64T> CodeAssembler::Word64Sar(SloppyTNode<Word64T> left,
return UncheckedCast<Word64T>(raw_assembler()->Word64Sar(left, right));
}
-#define CODE_ASSEMBLER_COMPARE(Name, ArgT, VarT, ToConstant, op) \
- TNode<BoolT> CodeAssembler::Name(SloppyTNode<ArgT> left, \
- SloppyTNode<ArgT> right) { \
- VarT lhs, rhs; \
- if (ToConstant(left, lhs) && ToConstant(right, rhs)) { \
- return BoolConstant(lhs op rhs); \
- } \
- return UncheckedCast<BoolT>(raw_assembler()->Name(left, right)); \
+#define CODE_ASSEMBLER_COMPARE(Name, ArgT, VarT, ToConstant, op) \
+ TNode<BoolT> CodeAssembler::Name(TNode<ArgT> left, TNode<ArgT> right) { \
+ VarT lhs, rhs; \
+ if (ToConstant(left, &lhs) && ToConstant(right, &rhs)) { \
+ return BoolConstant(lhs op rhs); \
+ } \
+ return UncheckedCast<BoolT>(raw_assembler()->Name(left, right)); \
}
CODE_ASSEMBLER_COMPARE(IntPtrEqual, WordT, intptr_t, ToIntPtrConstant, ==)
@@ -959,14 +958,14 @@ Node* CodeAssembler::Load(MachineType type, Node* base, Node* offset,
return raw_assembler()->Load(type, base, offset, needs_poisoning);
}
-Node* CodeAssembler::LoadFullTagged(Node* base,
- LoadSensitivity needs_poisoning) {
+TNode<Object> CodeAssembler::LoadFullTagged(Node* base,
+ LoadSensitivity needs_poisoning) {
return BitcastWordToTagged(
Load(MachineType::Pointer(), base, needs_poisoning));
}
-Node* CodeAssembler::LoadFullTagged(Node* base, Node* offset,
- LoadSensitivity needs_poisoning) {
+TNode<Object> CodeAssembler::LoadFullTagged(Node* base, Node* offset,
+ LoadSensitivity needs_poisoning) {
return BitcastWordToTagged(
Load(MachineType::Pointer(), base, offset, needs_poisoning));
}
@@ -993,7 +992,7 @@ TNode<Object> CodeAssembler::LoadRoot(RootIndex root_index) {
// TODO(jgruber): In theory we could generate better code for this by
// letting the macro assembler decide how to load from the roots list. In most
// cases, it would boil down to loading from a fixed kRootRegister offset.
- Node* isolate_root =
+ TNode<ExternalReference> isolate_root =
ExternalConstant(ExternalReference::isolate_root(isolate()));
int offset = IsolateData::root_slot_offset(root_index);
return UncheckedCast<Object>(
@@ -1133,7 +1132,7 @@ Node* CodeAssembler::AtomicCompareExchange(MachineType type, Node* base,
Node* CodeAssembler::StoreRoot(RootIndex root_index, Node* value) {
DCHECK(!RootsTable::IsImmortalImmovable(root_index));
- Node* isolate_root =
+ TNode<ExternalReference> isolate_root =
ExternalConstant(ExternalReference::isolate_root(isolate()));
int offset = IsolateData::root_slot_offset(root_index);
return StoreFullTaggedNoWriteBarrier(isolate_root, IntPtrConstant(offset),
@@ -1248,8 +1247,9 @@ TNode<Object> CodeAssembler::CallRuntimeWithCEntryImpl(
Runtime::MayAllocate(function) ? CallDescriptor::kNoFlags
: CallDescriptor::kNoAllocate);
- Node* ref = ExternalConstant(ExternalReference::Create(function));
- Node* arity = Int32Constant(argc);
+ TNode<ExternalReference> ref =
+ ExternalConstant(ExternalReference::Create(function));
+ TNode<Int32T> arity = Int32Constant(argc);
NodeArray<kMaxNumArgs + 4> inputs;
inputs.Add(centry);
@@ -1285,7 +1285,8 @@ void CodeAssembler::TailCallRuntimeWithCEntryImpl(
zone(), function, argc, Operator::kNoProperties,
CallDescriptor::kNoFlags);
- Node* ref = ExternalConstant(ExternalReference::Create(function));
+ TNode<ExternalReference> ref =
+ ExternalConstant(ExternalReference::Create(function));
NodeArray<kMaxNumArgs + 4> inputs;
inputs.Add(centry);
@@ -1468,7 +1469,7 @@ void CodeAssembler::GotoIfNot(SloppyTNode<IntegralT> condition,
void CodeAssembler::Branch(SloppyTNode<IntegralT> condition, Label* true_label,
Label* false_label) {
int32_t constant;
- if (ToInt32Constant(condition, constant)) {
+ if (ToInt32Constant(condition, &constant)) {
if ((true_label->is_used() || true_label->is_bound()) &&
(false_label->is_used() || false_label->is_bound())) {
return Goto(constant ? true_label : false_label);
@@ -1484,7 +1485,7 @@ void CodeAssembler::Branch(TNode<BoolT> condition,
const std::function<void()>& true_body,
const std::function<void()>& false_body) {
int32_t constant;
- if (ToInt32Constant(condition, constant)) {
+ if (ToInt32Constant(condition, &constant)) {
return constant ? true_body() : false_body();
}
@@ -1501,7 +1502,7 @@ void CodeAssembler::Branch(TNode<BoolT> condition,
void CodeAssembler::Branch(TNode<BoolT> condition, Label* true_label,
const std::function<void()>& false_body) {
int32_t constant;
- if (ToInt32Constant(condition, constant)) {
+ if (ToInt32Constant(condition, &constant)) {
return constant ? Goto(true_label) : false_body();
}
@@ -1515,7 +1516,7 @@ void CodeAssembler::Branch(TNode<BoolT> condition,
const std::function<void()>& true_body,
Label* false_label) {
int32_t constant;
- if (ToInt32Constant(condition, constant)) {
+ if (ToInt32Constant(condition, &constant)) {
return constant ? true_body() : Goto(false_label);
}
diff --git a/deps/v8/src/compiler/code-assembler.h b/deps/v8/src/compiler/code-assembler.h
index cc432214aa..c9adb1601d 100644
--- a/deps/v8/src/compiler/code-assembler.h
+++ b/deps/v8/src/compiler/code-assembler.h
@@ -5,9 +5,9 @@
#ifndef V8_COMPILER_CODE_ASSEMBLER_H_
#define V8_COMPILER_CODE_ASSEMBLER_H_
+#include <initializer_list>
#include <map>
#include <memory>
-#include <initializer_list>
// Clients of this interface shouldn't depend on lots of compiler internals.
// Do not include anything from src/compiler here!
@@ -43,7 +43,6 @@ class BigInt;
class CallInterfaceDescriptor;
class Callable;
class Factory;
-class FinalizationGroupCleanupJobTask;
class InterpreterData;
class Isolate;
class JSAsyncFunctionObject;
@@ -317,6 +316,7 @@ class CompilationCacheTable;
class Constructor;
class Filler;
class FunctionTemplateRareData;
+class HeapNumber;
class InternalizedString;
class JSArgumentsObject;
class JSArrayBufferView;
@@ -324,7 +324,6 @@ class JSContextExtensionObject;
class JSError;
class JSSloppyArgumentsObject;
class MapCache;
-class MutableHeapNumber;
class NativeContext;
class NumberWrapper;
class ScriptWrapper;
@@ -645,7 +644,7 @@ TNode<Float64T> Float64Add(TNode<Float64T> a, TNode<Float64T> b);
V(BitcastInt32ToFloat32, Float32T, Word32T) \
V(BitcastFloat32ToInt32, Uint32T, Float32T) \
V(RoundFloat64ToInt32, Int32T, Float64T) \
- V(RoundInt32ToFloat32, Int32T, Float32T) \
+ V(RoundInt32ToFloat32, Float32T, Int32T) \
V(Float64SilenceNaN, Float64T, Float64T) \
V(Float64RoundDown, Float64T, Float64T) \
V(Float64RoundUp, Float64T, Float64T) \
@@ -657,7 +656,8 @@ TNode<Float64T> Float64Add(TNode<Float64T> a, TNode<Float64T> b);
V(Int32AbsWithOverflow, PAIR_TYPE(Int32T, BoolT), Int32T) \
V(Int64AbsWithOverflow, PAIR_TYPE(Int64T, BoolT), Int64T) \
V(IntPtrAbsWithOverflow, PAIR_TYPE(IntPtrT, BoolT), IntPtrT) \
- V(Word32BinaryNot, BoolT, Word32T)
+ V(Word32BinaryNot, BoolT, Word32T) \
+ V(StackPointerGreaterThan, BoolT, WordT)
// A "public" interface used by components outside of compiler directory to
// create code objects with TurboFan's backend. This class is mostly a thin
@@ -688,6 +688,7 @@ class V8_EXPORT_PRIVATE CodeAssembler {
const AssemblerOptions& options);
bool Is64() const;
+ bool Is32() const;
bool IsFloat64RoundUpSupported() const;
bool IsFloat64RoundDownSupported() const;
bool IsFloat64RoundTiesEvenSupported() const;
@@ -738,7 +739,7 @@ class V8_EXPORT_PRIVATE CodeAssembler {
if (std::is_same<PreviousType, MaybeObject>::value) {
code_assembler_->GenerateCheckMaybeObjectIsObject(node_, location_);
}
- Node* function = code_assembler_->ExternalConstant(
+ TNode<ExternalReference> function = code_assembler_->ExternalConstant(
ExternalReference::check_object_type());
code_assembler_->CallCFunction(
function, MachineType::AnyTagged(),
@@ -842,7 +843,6 @@ class V8_EXPORT_PRIVATE CodeAssembler {
TNode<Oddball> BooleanConstant(bool value);
TNode<ExternalReference> ExternalConstant(ExternalReference address);
TNode<Float64T> Float64Constant(double value);
- TNode<HeapNumber> NaNConstant();
TNode<BoolT> Int32TrueConstant() {
return ReinterpretCast<BoolT>(Int32Constant(1));
}
@@ -853,15 +853,10 @@ class V8_EXPORT_PRIVATE CodeAssembler {
return value ? Int32TrueConstant() : Int32FalseConstant();
}
- // TODO(jkummerow): The style guide wants pointers for output parameters.
- // https://google.github.io/styleguide/cppguide.html#Output_Parameters
- bool ToInt32Constant(Node* node,
- int32_t& out_value); // NOLINT(runtime/references)
- bool ToInt64Constant(Node* node,
- int64_t& out_value); // NOLINT(runtime/references)
+ bool ToInt32Constant(Node* node, int32_t* out_value);
+ bool ToInt64Constant(Node* node, int64_t* out_value);
+ bool ToIntPtrConstant(Node* node, intptr_t* out_value);
bool ToSmiConstant(Node* node, Smi* out_value);
- bool ToIntPtrConstant(Node* node,
- intptr_t& out_value); // NOLINT(runtime/references)
bool IsUndefinedConstant(TNode<Object> node);
bool IsNullConstant(TNode<Object> node);
@@ -959,9 +954,6 @@ class V8_EXPORT_PRIVATE CodeAssembler {
TNode<RawPtrT> LoadFramePointer();
TNode<RawPtrT> LoadParentFramePointer();
- // Access to the stack pointer
- TNode<RawPtrT> LoadStackPointer();
-
// Poison |value| on speculative paths.
TNode<Object> TaggedPoisonOnSpeculation(SloppyTNode<Object> value);
TNode<WordT> WordPoisonOnSpeculation(SloppyTNode<WordT> value);
@@ -977,12 +969,24 @@ class V8_EXPORT_PRIVATE CodeAssembler {
}
Node* Load(MachineType type, Node* base, Node* offset,
LoadSensitivity needs_poisoning = LoadSensitivity::kSafe);
+ template <class Type>
+ TNode<Type> Load(Node* base,
+ LoadSensitivity needs_poisoning = LoadSensitivity::kSafe) {
+ return UncheckedCast<Type>(
+ Load(MachineTypeOf<Type>::value, base, needs_poisoning));
+ }
+ template <class Type>
+ TNode<Type> Load(Node* base, SloppyTNode<WordT> offset,
+ LoadSensitivity needs_poisoning = LoadSensitivity::kSafe) {
+ return UncheckedCast<Type>(
+ Load(MachineTypeOf<Type>::value, base, offset, needs_poisoning));
+ }
Node* AtomicLoad(MachineType type, Node* base, Node* offset);
// Load uncompressed tagged value from (most likely off JS heap) memory
// location.
- Node* LoadFullTagged(
+ TNode<Object> LoadFullTagged(
Node* base, LoadSensitivity needs_poisoning = LoadSensitivity::kSafe);
- Node* LoadFullTagged(
+ TNode<Object> LoadFullTagged(
Node* base, Node* offset,
LoadSensitivity needs_poisoning = LoadSensitivity::kSafe);
@@ -1119,50 +1123,13 @@ class V8_EXPORT_PRIVATE CodeAssembler {
Word32Or(static_cast<Node*>(left), static_cast<Node*>(right)));
}
- template <class Left, class Right,
- class = typename std::enable_if<
- std::is_base_of<Object, Left>::value &&
- std::is_base_of<Object, Right>::value>::type>
- TNode<BoolT> WordEqual(TNode<Left> left, TNode<Right> right) {
- return WordEqual(ReinterpretCast<WordT>(left),
- ReinterpretCast<WordT>(right));
- }
- TNode<BoolT> WordEqual(TNode<Object> left, Node* right) {
- return WordEqual(ReinterpretCast<WordT>(left),
- ReinterpretCast<WordT>(right));
- }
- TNode<BoolT> WordEqual(Node* left, TNode<Object> right) {
- return WordEqual(ReinterpretCast<WordT>(left),
- ReinterpretCast<WordT>(right));
- }
- template <class Left, class Right,
- class = typename std::enable_if<
- std::is_base_of<Object, Left>::value &&
- std::is_base_of<Object, Right>::value>::type>
- TNode<BoolT> WordNotEqual(TNode<Left> left, TNode<Right> right) {
- return WordNotEqual(ReinterpretCast<WordT>(left),
- ReinterpretCast<WordT>(right));
- }
- TNode<BoolT> WordNotEqual(TNode<Object> left, Node* right) {
- return WordNotEqual(ReinterpretCast<WordT>(left),
- ReinterpretCast<WordT>(right));
- }
- TNode<BoolT> WordNotEqual(Node* left, TNode<Object> right) {
- return WordNotEqual(ReinterpretCast<WordT>(left),
- ReinterpretCast<WordT>(right));
- }
-
- TNode<BoolT> IntPtrEqual(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
- TNode<BoolT> WordEqual(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
- TNode<BoolT> WordNotEqual(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
- TNode<BoolT> Word32Equal(SloppyTNode<Word32T> left,
- SloppyTNode<Word32T> right);
- TNode<BoolT> Word32NotEqual(SloppyTNode<Word32T> left,
- SloppyTNode<Word32T> right);
- TNode<BoolT> Word64Equal(SloppyTNode<Word64T> left,
- SloppyTNode<Word64T> right);
- TNode<BoolT> Word64NotEqual(SloppyTNode<Word64T> left,
- SloppyTNode<Word64T> right);
+ TNode<BoolT> IntPtrEqual(TNode<WordT> left, TNode<WordT> right);
+ TNode<BoolT> WordEqual(TNode<WordT> left, TNode<WordT> right);
+ TNode<BoolT> WordNotEqual(TNode<WordT> left, TNode<WordT> right);
+ TNode<BoolT> Word32Equal(TNode<Word32T> left, TNode<Word32T> right);
+ TNode<BoolT> Word32NotEqual(TNode<Word32T> left, TNode<Word32T> right);
+ TNode<BoolT> Word64Equal(TNode<Word64T> left, TNode<Word64T> right);
+ TNode<BoolT> Word64NotEqual(TNode<Word64T> left, TNode<Word64T> right);
TNode<BoolT> Word32Or(TNode<BoolT> left, TNode<BoolT> right) {
return UncheckedCast<BoolT>(
@@ -1234,6 +1201,7 @@ class V8_EXPORT_PRIVATE CodeAssembler {
return UncheckedCast<IntPtrT>(WordSar(static_cast<Node*>(value), shift));
}
TNode<Word32T> Word32Shr(SloppyTNode<Word32T> value, int shift);
+ TNode<Word32T> Word32Sar(SloppyTNode<Word32T> value, int shift);
TNode<WordT> WordOr(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
TNode<WordT> WordAnd(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
@@ -1433,7 +1401,7 @@ class V8_EXPORT_PRIVATE CodeAssembler {
Node* CallJS(Callable const& callable, Node* context, Node* function,
Node* receiver, TArgs... args) {
int argc = static_cast<int>(sizeof...(args));
- Node* arity = Int32Constant(argc);
+ TNode<Int32T> arity = Int32Constant(argc);
return CallStub(callable, context, function, arity, receiver, args...);
}
@@ -1441,8 +1409,8 @@ class V8_EXPORT_PRIVATE CodeAssembler {
Node* ConstructJSWithTarget(Callable const& callable, Node* context,
Node* target, Node* new_target, TArgs... args) {
int argc = static_cast<int>(sizeof...(args));
- Node* arity = Int32Constant(argc);
- Node* receiver = LoadRoot(RootIndex::kUndefinedValue);
+ TNode<Int32T> arity = Int32Constant(argc);
+ TNode<Object> receiver = LoadRoot(RootIndex::kUndefinedValue);
// Construct(target, new_target, arity, receiver, arguments...)
return CallStub(callable, context, target, new_target, arity, receiver,
@@ -1842,9 +1810,11 @@ class V8_EXPORT_PRIVATE CodeAssemblerScopedExceptionHandler {
} // namespace compiler
-#if defined(V8_HOST_ARCH_32_BIT)
+#if defined(V8_HOST_ARCH_32_BIT) || defined(V8_COMPRESS_POINTERS)
+#define BINT_IS_SMI
using BInt = Smi;
#elif defined(V8_HOST_ARCH_64_BIT)
+#define BINT_IS_INTPTR
using BInt = IntPtrT;
#else
#error Unknown architecture.
diff --git a/deps/v8/src/compiler/common-operator.cc b/deps/v8/src/compiler/common-operator.cc
index 0ef6402264..c2d8cf4469 100644
--- a/deps/v8/src/compiler/common-operator.cc
+++ b/deps/v8/src/compiler/common-operator.cc
@@ -99,7 +99,8 @@ bool operator!=(DeoptimizeParameters lhs, DeoptimizeParameters rhs) {
}
size_t hash_value(DeoptimizeParameters p) {
- return base::hash_combine(p.kind(), p.reason(), p.feedback(),
+ FeedbackSource::Hash feebdack_hash;
+ return base::hash_combine(p.kind(), p.reason(), feebdack_hash(p.feedback()),
p.is_safety_check());
}
@@ -179,7 +180,6 @@ SelectParameters const& SelectParametersOf(const Operator* const op) {
CallDescriptor const* CallDescriptorOf(const Operator* const op) {
DCHECK(op->opcode() == IrOpcode::kCall ||
- op->opcode() == IrOpcode::kCallWithCallerSavedRegisters ||
op->opcode() == IrOpcode::kTailCall);
return OpParameter<CallDescriptor const*>(op);
}
@@ -729,7 +729,7 @@ struct CommonOperatorGlobalCache final {
Operator::kFoldable | Operator::kNoThrow, // properties
"Deoptimize", // name
1, 1, 1, 0, 0, 1, // counts
- DeoptimizeParameters(kKind, kReason, VectorSlotPair(),
+ DeoptimizeParameters(kKind, kReason, FeedbackSource(),
IsSafetyCheck::kNoSafetyCheck)) {}
};
#define CACHED_DEOPTIMIZE(Kind, Reason) \
@@ -747,7 +747,7 @@ struct CommonOperatorGlobalCache final {
Operator::kFoldable | Operator::kNoThrow, // properties
"DeoptimizeIf", // name
2, 1, 1, 0, 1, 1, // counts
- DeoptimizeParameters(kKind, kReason, VectorSlotPair(),
+ DeoptimizeParameters(kKind, kReason, FeedbackSource(),
is_safety_check)) {}
};
#define CACHED_DEOPTIMIZE_IF(Kind, Reason, IsCheck) \
@@ -767,7 +767,7 @@ struct CommonOperatorGlobalCache final {
Operator::kFoldable | Operator::kNoThrow, // properties
"DeoptimizeUnless", // name
2, 1, 1, 0, 1, 1, // counts
- DeoptimizeParameters(kKind, kReason, VectorSlotPair(),
+ DeoptimizeParameters(kKind, kReason, FeedbackSource(),
is_safety_check)) {}
};
#define CACHED_DEOPTIMIZE_UNLESS(Kind, Reason, IsCheck) \
@@ -948,7 +948,7 @@ const Operator* CommonOperatorBuilder::Branch(BranchHint hint,
const Operator* CommonOperatorBuilder::Deoptimize(
DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback) {
+ FeedbackSource const& feedback) {
#define CACHED_DEOPTIMIZE(Kind, Reason) \
if (kind == DeoptimizeKind::k##Kind && \
reason == DeoptimizeReason::k##Reason && !feedback.IsValid()) { \
@@ -969,7 +969,7 @@ const Operator* CommonOperatorBuilder::Deoptimize(
const Operator* CommonOperatorBuilder::DeoptimizeIf(
DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback, IsSafetyCheck is_safety_check) {
+ FeedbackSource const& feedback, IsSafetyCheck is_safety_check) {
#define CACHED_DEOPTIMIZE_IF(Kind, Reason, IsCheck) \
if (kind == DeoptimizeKind::k##Kind && \
reason == DeoptimizeReason::k##Reason && \
@@ -990,7 +990,7 @@ const Operator* CommonOperatorBuilder::DeoptimizeIf(
const Operator* CommonOperatorBuilder::DeoptimizeUnless(
DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback, IsSafetyCheck is_safety_check) {
+ FeedbackSource const& feedback, IsSafetyCheck is_safety_check) {
#define CACHED_DEOPTIMIZE_UNLESS(Kind, Reason, IsCheck) \
if (kind == DeoptimizeKind::k##Kind && \
reason == DeoptimizeReason::k##Reason && \
@@ -1481,31 +1481,6 @@ const Operator* CommonOperatorBuilder::Call(
return new (zone()) CallOperator(call_descriptor);
}
-const Operator* CommonOperatorBuilder::CallWithCallerSavedRegisters(
- const CallDescriptor* call_descriptor) {
- class CallOperator final : public Operator1<const CallDescriptor*> {
- public:
- explicit CallOperator(const CallDescriptor* call_descriptor)
- : Operator1<const CallDescriptor*>(
- IrOpcode::kCallWithCallerSavedRegisters,
- call_descriptor->properties(), "CallWithCallerSavedRegisters",
- call_descriptor->InputCount() +
- call_descriptor->FrameStateCount(),
- Operator::ZeroIfPure(call_descriptor->properties()),
- Operator::ZeroIfEliminatable(call_descriptor->properties()),
- call_descriptor->ReturnCount(),
- Operator::ZeroIfPure(call_descriptor->properties()),
- Operator::ZeroIfNoThrow(call_descriptor->properties()),
- call_descriptor) {}
-
- void PrintParameter(std::ostream& os,
- PrintVerbosity verbose) const override {
- os << "[" << *parameter() << "]";
- }
- };
- return new (zone()) CallOperator(call_descriptor);
-}
-
const Operator* CommonOperatorBuilder::TailCall(
const CallDescriptor* call_descriptor) {
class TailCallOperator final : public Operator1<const CallDescriptor*> {
diff --git a/deps/v8/src/compiler/common-operator.h b/deps/v8/src/compiler/common-operator.h
index 9f634e72ec..2b0dcc7db9 100644
--- a/deps/v8/src/compiler/common-operator.h
+++ b/deps/v8/src/compiler/common-operator.h
@@ -10,8 +10,8 @@
#include "src/codegen/reloc-info.h"
#include "src/codegen/string-constants.h"
#include "src/common/globals.h"
+#include "src/compiler/feedback-source.h"
#include "src/compiler/frame-states.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/deoptimizer/deoptimize-reason.h"
#include "src/zone/zone-containers.h"
#include "src/zone/zone-handle-set.h"
@@ -104,7 +104,7 @@ int ValueInputCountOfReturn(Operator const* const op);
class DeoptimizeParameters final {
public:
DeoptimizeParameters(DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
IsSafetyCheck is_safety_check)
: kind_(kind),
reason_(reason),
@@ -113,13 +113,13 @@ class DeoptimizeParameters final {
DeoptimizeKind kind() const { return kind_; }
DeoptimizeReason reason() const { return reason_; }
- const VectorSlotPair& feedback() const { return feedback_; }
+ const FeedbackSource& feedback() const { return feedback_; }
IsSafetyCheck is_safety_check() const { return is_safety_check_; }
private:
DeoptimizeKind const kind_;
DeoptimizeReason const reason_;
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
IsSafetyCheck is_safety_check_;
};
@@ -468,14 +468,14 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
const Operator* IfDefault(BranchHint hint = BranchHint::kNone);
const Operator* Throw();
const Operator* Deoptimize(DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback);
+ FeedbackSource const& feedback);
const Operator* DeoptimizeIf(
DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
const Operator* DeoptimizeUnless(
DeoptimizeKind kind, DeoptimizeReason reason,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
const Operator* TrapIf(TrapId trap_id);
const Operator* TrapUnless(TrapId trap_id);
@@ -530,8 +530,6 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
OutputFrameStateCombine state_combine,
const FrameStateFunctionInfo* function_info);
const Operator* Call(const CallDescriptor* call_descriptor);
- const Operator* CallWithCallerSavedRegisters(
- const CallDescriptor* call_descriptor);
const Operator* TailCall(const CallDescriptor* call_descriptor);
const Operator* Projection(size_t index);
const Operator* Retain();
diff --git a/deps/v8/src/compiler/compilation-dependencies.cc b/deps/v8/src/compiler/compilation-dependencies.cc
index 673f4a341b..592d85440c 100644
--- a/deps/v8/src/compiler/compilation-dependencies.cc
+++ b/deps/v8/src/compiler/compilation-dependencies.cc
@@ -550,13 +550,7 @@ namespace {
// This function expects to never see a JSProxy.
void DependOnStablePrototypeChain(CompilationDependencies* deps, MapRef map,
base::Optional<JSObjectRef> last_prototype) {
- // TODO(neis): Remove heap access (SerializePrototype call).
- AllowCodeDependencyChange dependency_change_;
- AllowHandleAllocation handle_allocation_;
- AllowHandleDereference handle_dereference_;
- AllowHeapAllocation heap_allocation_;
while (true) {
- map.SerializePrototype();
HeapObjectRef proto = map.prototype();
if (!proto.IsJSObject()) {
CHECK_EQ(proto.map().oddball_type(), OddballType::kNull);
@@ -580,7 +574,7 @@ void CompilationDependencies::DependOnStablePrototypeChains(
// Perform the implicit ToObject for primitives here.
// Implemented according to ES6 section 7.3.2 GetV (V, P).
base::Optional<JSFunctionRef> constructor =
- broker_->native_context().GetConstructorFunction(receiver_map);
+ broker_->target_native_context().GetConstructorFunction(receiver_map);
if (constructor.has_value()) receiver_map = constructor->initial_map();
}
DependOnStablePrototypeChain(this, receiver_map, last_prototype);
diff --git a/deps/v8/src/compiler/effect-control-linearizer.cc b/deps/v8/src/compiler/effect-control-linearizer.cc
index 788638fe68..8dfe356c34 100644
--- a/deps/v8/src/compiler/effect-control-linearizer.cc
+++ b/deps/v8/src/compiler/effect-control-linearizer.cc
@@ -9,6 +9,7 @@
#include "src/common/ptr-compr-inl.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/compiler-source-position-table.h"
+#include "src/compiler/feedback-source.h"
#include "src/compiler/graph-assembler.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
@@ -209,13 +210,13 @@ class EffectControlLinearizer {
Node* AllocateHeapNumberWithValue(Node* node);
Node* BuildCheckedFloat64ToInt32(CheckForMinusZeroMode mode,
- const VectorSlotPair& feedback, Node* value,
+ const FeedbackSource& feedback, Node* value,
Node* frame_state);
Node* BuildCheckedFloat64ToInt64(CheckForMinusZeroMode mode,
- const VectorSlotPair& feedback, Node* value,
+ const FeedbackSource& feedback, Node* value,
Node* frame_state);
Node* BuildCheckedHeapNumberOrOddballToFloat64(CheckTaggedInputMode mode,
- const VectorSlotPair& feedback,
+ const FeedbackSource& feedback,
Node* value,
Node* frame_state);
Node* BuildReverseBytes(ExternalArrayType type, Node* value);
@@ -239,6 +240,7 @@ class EffectControlLinearizer {
Node* ChangeSmiToInt32(Node* value);
Node* ChangeSmiToInt64(Node* value);
Node* ObjectIsSmi(Node* value);
+ Node* CompressedObjectIsSmi(Node* value);
Node* LoadFromSeqString(Node* receiver, Node* position, Node* is_one_byte);
Node* SmiMaxValueConstant();
@@ -1525,7 +1527,7 @@ Node* EffectControlLinearizer::LowerChangeTaggedSignedToInt64(Node* node) {
Node* EffectControlLinearizer::LowerChangeTaggedToBit(Node* node) {
Node* value = node->InputAt(0);
- return __ WordEqual(value, __ TrueConstant());
+ return __ TaggedEqual(value, __ TrueConstant());
}
void EffectControlLinearizer::TruncateTaggedPointerToBit(
@@ -1539,10 +1541,10 @@ void EffectControlLinearizer::TruncateTaggedPointerToBit(
Node* fzero = __ Float64Constant(0.0);
// Check if {value} is false.
- __ GotoIf(__ WordEqual(value, __ FalseConstant()), done, zero);
+ __ GotoIf(__ TaggedEqual(value, __ FalseConstant()), done, zero);
// Check if {value} is the empty string.
- __ GotoIf(__ WordEqual(value, __ EmptyStringConstant()), done, zero);
+ __ GotoIf(__ TaggedEqual(value, __ EmptyStringConstant()), done, zero);
// Load the map of {value}.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
@@ -1559,11 +1561,11 @@ void EffectControlLinearizer::TruncateTaggedPointerToBit(
done, zero);
// Check if {value} is a HeapNumber.
- __ GotoIf(__ WordEqual(value_map, __ HeapNumberMapConstant()),
+ __ GotoIf(__ TaggedEqual(value_map, __ HeapNumberMapConstant()),
&if_heapnumber);
// Check if {value} is a BigInt.
- __ GotoIf(__ WordEqual(value_map, __ BigIntMapConstant()), &if_bigint);
+ __ GotoIf(__ TaggedEqual(value_map, __ BigIntMapConstant()), &if_bigint);
// All other values that reach here are true.
__ Goto(done, __ Int32Constant(1));
@@ -1599,7 +1601,7 @@ Node* EffectControlLinearizer::LowerTruncateTaggedToBit(Node* node) {
__ Bind(&if_smi);
{
// If {value} is a Smi, then we only need to check that it's not zero.
- __ Goto(&done, __ Word32Equal(__ WordEqual(value, __ IntPtrConstant(0)),
+ __ Goto(&done, __ Word32Equal(__ IntPtrEqual(value, __ IntPtrConstant(0)),
__ Int32Constant(0)));
}
@@ -1711,7 +1713,7 @@ Node* EffectControlLinearizer::LowerChangeCompressedToTaggedSigned(Node* node) {
auto if_not_smi = __ MakeDeferredLabel();
auto done = __ MakeLabel(MachineRepresentation::kWord32);
- Node* check = ObjectIsSmi(value);
+ Node* check = CompressedObjectIsSmi(value);
__ GotoIfNot(check, &if_not_smi);
__ Goto(&done, __ ChangeCompressedSignedToTaggedSigned(value));
@@ -1795,7 +1797,7 @@ void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
// Perform the map checks.
for (size_t i = 0; i < map_count; ++i) {
Node* map = __ HeapConstant(maps[i]);
- Node* check = __ WordEqual(value_map, map);
+ Node* check = __ TaggedEqual(value_map, map);
if (i == map_count - 1) {
__ Branch(check, &done, &migrate, IsSafetyCheck::kCriticalSafetyCheck);
} else {
@@ -1811,7 +1813,7 @@ void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
// If map is not deprecated the migration attempt does not make sense.
Node* bitfield3 =
__ LoadField(AccessBuilder::ForMapBitField3(), value_map);
- Node* if_not_deprecated = __ WordEqual(
+ Node* if_not_deprecated = __ Word32Equal(
__ Word32And(bitfield3,
__ Int32Constant(Map::IsDeprecatedBit::kMask)),
__ Int32Constant(0));
@@ -1837,7 +1839,7 @@ void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
// Perform the map checks again.
for (size_t i = 0; i < map_count; ++i) {
Node* map = __ HeapConstant(maps[i]);
- Node* check = __ WordEqual(value_map, map);
+ Node* check = __ TaggedEqual(value_map, map);
if (i == map_count - 1) {
__ DeoptimizeIfNot(DeoptimizeReason::kWrongMap, p.feedback(), check,
frame_state, IsSafetyCheck::kCriticalSafetyCheck);
@@ -1858,7 +1860,7 @@ void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
for (size_t i = 0; i < map_count; ++i) {
Node* map = __ HeapConstant(maps[i]);
- Node* check = __ WordEqual(value_map, map);
+ Node* check = __ TaggedEqual(value_map, map);
if (i == map_count - 1) {
__ DeoptimizeIfNot(DeoptimizeReason::kWrongMap, p.feedback(), check,
@@ -1886,7 +1888,7 @@ Node* EffectControlLinearizer::LowerCompareMaps(Node* node) {
for (size_t i = 0; i < map_count; ++i) {
Node* map = __ HeapConstant(maps[i]);
- Node* check = __ WordEqual(value_map, map);
+ Node* check = __ TaggedEqual(value_map, map);
auto next_map = __ MakeLabel();
auto passed = __ MakeLabel();
@@ -1916,7 +1918,7 @@ Node* EffectControlLinearizer::LowerCheckNumber(Node* node, Node* frame_state) {
__ Bind(&if_not_smi);
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
- Node* check1 = __ WordEqual(value_map, __ HeapNumberMapConstant());
+ Node* check1 = __ TaggedEqual(value_map, __ HeapNumberMapConstant());
__ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, params.feedback(),
check1, frame_state);
__ Goto(&done);
@@ -1936,7 +1938,7 @@ Node* EffectControlLinearizer::LowerCheckReceiver(Node* node,
STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
Node* check = __ Uint32LessThanOrEqual(
__ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type);
- __ DeoptimizeIfNot(DeoptimizeReason::kNotAJavaScriptObject, VectorSlotPair(),
+ __ DeoptimizeIfNot(DeoptimizeReason::kNotAJavaScriptObject, FeedbackSource(),
check, frame_state);
return value;
}
@@ -1955,12 +1957,12 @@ Node* EffectControlLinearizer::LowerCheckReceiverOrNullOrUndefined(
Node* check0 = __ Uint32LessThanOrEqual(__ Uint32Constant(ODDBALL_TYPE),
value_instance_type);
__ DeoptimizeIfNot(DeoptimizeReason::kNotAJavaScriptObjectOrNullOrUndefined,
- VectorSlotPair(), check0, frame_state);
+ FeedbackSource(), check0, frame_state);
// Rule out booleans.
- Node* check1 = __ WordEqual(value_map, __ BooleanMapConstant());
+ Node* check1 = __ TaggedEqual(value_map, __ BooleanMapConstant());
__ DeoptimizeIf(DeoptimizeReason::kNotAJavaScriptObjectOrNullOrUndefined,
- VectorSlotPair(), check1, frame_state);
+ FeedbackSource(), check1, frame_state);
return value;
}
@@ -1970,8 +1972,8 @@ Node* EffectControlLinearizer::LowerCheckSymbol(Node* node, Node* frame_state) {
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
Node* check =
- __ WordEqual(value_map, __ HeapConstant(factory()->symbol_map()));
- __ DeoptimizeIfNot(DeoptimizeReason::kNotASymbol, VectorSlotPair(), check,
+ __ TaggedEqual(value_map, __ HeapConstant(factory()->symbol_map()));
+ __ DeoptimizeIfNot(DeoptimizeReason::kNotASymbol, FeedbackSource(), check,
frame_state);
return value;
}
@@ -2003,7 +2005,7 @@ Node* EffectControlLinearizer::LowerCheckInternalizedString(Node* node,
__ Word32And(value_instance_type,
__ Int32Constant(kIsNotStringMask | kIsNotInternalizedMask)),
__ Int32Constant(kInternalizedTag));
- __ DeoptimizeIfNot(DeoptimizeReason::kWrongInstanceType, VectorSlotPair(),
+ __ DeoptimizeIfNot(DeoptimizeReason::kWrongInstanceType, FeedbackSource(),
check, frame_state);
return value;
@@ -2040,7 +2042,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Add(Node* node,
Node* value = __ Int32AddWithOverflow(lhs, rhs);
Node* check = __ Projection(1, value);
- __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), check,
+ __ DeoptimizeIf(DeoptimizeReason::kOverflow, FeedbackSource(), check,
frame_state);
return __ Projection(0, value);
}
@@ -2052,7 +2054,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Sub(Node* node,
Node* value = __ Int32SubWithOverflow(lhs, rhs);
Node* check = __ Projection(1, value);
- __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), check,
+ __ DeoptimizeIf(DeoptimizeReason::kOverflow, FeedbackSource(), check,
frame_state);
return __ Projection(0, value);
}
@@ -2075,7 +2077,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node,
Node* mask = __ Int32Constant(divisor - 1);
Node* shift = __ Int32Constant(WhichPowerOf2(divisor));
Node* check = __ Word32Equal(__ Word32And(lhs, mask), zero);
- __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, VectorSlotPair(),
+ __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, FeedbackSource(),
check, frame_state);
return __ Word32Sar(lhs, shift);
} else {
@@ -2100,12 +2102,12 @@ Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node,
// Check if {rhs} is zero.
Node* check_rhs_zero = __ Word32Equal(rhs, zero);
- __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(),
+ __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, FeedbackSource(),
check_rhs_zero, frame_state);
// Check if {lhs} is zero, as that would produce minus zero.
Node* check_lhs_zero = __ Word32Equal(lhs, zero);
- __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(),
+ __ DeoptimizeIf(DeoptimizeReason::kMinusZero, FeedbackSource(),
check_lhs_zero, frame_state);
// Check if {lhs} is kMinInt and {rhs} is -1, in which case we'd have
@@ -2118,7 +2120,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node,
{
// Check that {rhs} is not -1, otherwise result would be -kMinInt.
Node* check_rhs_minusone = __ Word32Equal(rhs, __ Int32Constant(-1));
- __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(),
+ __ DeoptimizeIf(DeoptimizeReason::kOverflow, FeedbackSource(),
check_rhs_minusone, frame_state);
// Perform the actual integer division.
@@ -2137,7 +2139,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node,
// Check if the remainder is non-zero.
Node* check = __ Word32Equal(lhs, __ Int32Mul(value, rhs));
- __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, VectorSlotPair(),
+ __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, FeedbackSource(),
check, frame_state);
return value;
@@ -2219,7 +2221,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Mod(Node* node,
Node* vtrue0 = __ Int32Sub(zero, rhs);
// Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
- __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(),
+ __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, FeedbackSource(),
__ Word32Equal(vtrue0, zero), frame_state);
__ Goto(&rhs_checked, vtrue0);
}
@@ -2242,7 +2244,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Mod(Node* node,
Node* res = __ Uint32Mod(__ Int32Sub(zero, lhs), rhs);
// Check if we would have to return -0.
- __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(),
+ __ DeoptimizeIf(DeoptimizeReason::kMinusZero, FeedbackSource(),
__ Word32Equal(res, zero), frame_state);
__ Goto(&done, __ Int32Sub(zero, res));
}
@@ -2269,13 +2271,13 @@ Node* EffectControlLinearizer::LowerCheckedUint32Div(Node* node,
Node* mask = __ Uint32Constant(divisor - 1);
Node* shift = __ Uint32Constant(WhichPowerOf2(divisor));
Node* check = __ Word32Equal(__ Word32And(lhs, mask), zero);
- __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, VectorSlotPair(),
+ __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, FeedbackSource(),
check, frame_state);
return __ Word32Shr(lhs, shift);
} else {
// Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
Node* check = __ Word32Equal(rhs, zero);
- __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(), check,
+ __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, FeedbackSource(), check,
frame_state);
// Perform the actual unsigned integer division.
@@ -2283,7 +2285,7 @@ Node* EffectControlLinearizer::LowerCheckedUint32Div(Node* node,
// Check if the remainder is non-zero.
check = __ Word32Equal(lhs, __ Int32Mul(rhs, value));
- __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, VectorSlotPair(),
+ __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, FeedbackSource(),
check, frame_state);
return value;
}
@@ -2298,7 +2300,7 @@ Node* EffectControlLinearizer::LowerCheckedUint32Mod(Node* node,
// Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
Node* check = __ Word32Equal(rhs, zero);
- __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, VectorSlotPair(), check,
+ __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, FeedbackSource(), check,
frame_state);
// Perform the actual unsigned integer modulus.
@@ -2313,7 +2315,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Mul(Node* node,
Node* projection = __ Int32MulWithOverflow(lhs, rhs);
Node* check = __ Projection(1, projection);
- __ DeoptimizeIf(DeoptimizeReason::kOverflow, VectorSlotPair(), check,
+ __ DeoptimizeIf(DeoptimizeReason::kOverflow, FeedbackSource(), check,
frame_state);
Node* value = __ Projection(0, projection);
@@ -2329,7 +2331,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Mul(Node* node,
__ Bind(&if_zero);
// We may need to return negative zero.
Node* check_or = __ Int32LessThan(__ Word32Or(lhs, rhs), zero);
- __ DeoptimizeIf(DeoptimizeReason::kMinusZero, VectorSlotPair(), check_or,
+ __ DeoptimizeIf(DeoptimizeReason::kMinusZero, FeedbackSource(), check_or,
frame_state);
__ Goto(&check_done);
@@ -2489,7 +2491,7 @@ Node* EffectControlLinearizer::LowerCheckedUint64ToTaggedSigned(
}
Node* EffectControlLinearizer::BuildCheckedFloat64ToInt32(
- CheckForMinusZeroMode mode, const VectorSlotPair& feedback, Node* value,
+ CheckForMinusZeroMode mode, const FeedbackSource& feedback, Node* value,
Node* frame_state) {
Node* value32 = __ RoundFloat64ToInt32(value);
Node* check_same = __ Float64Equal(value, __ ChangeInt32ToFloat64(value32));
@@ -2528,7 +2530,7 @@ Node* EffectControlLinearizer::LowerCheckedFloat64ToInt32(Node* node,
}
Node* EffectControlLinearizer::BuildCheckedFloat64ToInt64(
- CheckForMinusZeroMode mode, const VectorSlotPair& feedback, Node* value,
+ CheckForMinusZeroMode mode, const FeedbackSource& feedback, Node* value,
Node* frame_state) {
Node* value64 = __ TruncateFloat64ToInt64(value);
Node* check_same = __ Float64Equal(value, __ ChangeInt64ToFloat64(value64));
@@ -2594,7 +2596,7 @@ Node* EffectControlLinearizer::LowerCheckedTaggedToInt32(Node* node,
// to int32.
__ Bind(&if_not_smi);
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
- Node* check_map = __ WordEqual(value_map, __ HeapNumberMapConstant());
+ Node* check_map = __ TaggedEqual(value_map, __ HeapNumberMapConstant());
__ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, params.feedback(),
check_map, frame_state);
Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
@@ -2624,7 +2626,7 @@ Node* EffectControlLinearizer::LowerCheckedTaggedToInt64(Node* node,
// to int64.
__ Bind(&if_not_smi);
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
- Node* check_map = __ WordEqual(value_map, __ HeapNumberMapConstant());
+ Node* check_map = __ TaggedEqual(value_map, __ HeapNumberMapConstant());
__ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, params.feedback(),
check_map, frame_state);
Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
@@ -2637,10 +2639,10 @@ Node* EffectControlLinearizer::LowerCheckedTaggedToInt64(Node* node,
}
Node* EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64(
- CheckTaggedInputMode mode, const VectorSlotPair& feedback, Node* value,
+ CheckTaggedInputMode mode, const FeedbackSource& feedback, Node* value,
Node* frame_state) {
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
- Node* check_number = __ WordEqual(value_map, __ HeapNumberMapConstant());
+ Node* check_number = __ TaggedEqual(value_map, __ HeapNumberMapConstant());
switch (mode) {
case CheckTaggedInputMode::kNumber: {
__ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, feedback,
@@ -2731,7 +2733,7 @@ Node* EffectControlLinearizer::LowerCheckBigInt(Node* node, Node* frame_state) {
// Check for BigInt.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
- Node* bi_check = __ WordEqual(value_map, __ BigIntMapConstant());
+ Node* bi_check = __ TaggedEqual(value_map, __ BigIntMapConstant());
__ DeoptimizeIfNot(DeoptimizeReason::kWrongInstanceType, params.feedback(),
bi_check, frame_state);
@@ -2840,7 +2842,7 @@ Node* EffectControlLinearizer::LowerCheckedCompressedToTaggedSigned(
Node* value = node->InputAt(0);
const CheckParameters& params = CheckParametersOf(node->op());
- Node* check = ObjectIsSmi(value);
+ Node* check = CompressedObjectIsSmi(value);
__ DeoptimizeIfNot(DeoptimizeReason::kNotASmi, params.feedback(), check,
frame_state);
@@ -2852,7 +2854,7 @@ Node* EffectControlLinearizer::LowerCheckedCompressedToTaggedPointer(
Node* value = node->InputAt(0);
const CheckParameters& params = CheckParametersOf(node->op());
- Node* check = ObjectIsSmi(value);
+ Node* check = CompressedObjectIsSmi(value);
__ DeoptimizeIf(DeoptimizeReason::kSmi, params.feedback(), check,
frame_state);
return __ ChangeCompressedPointerToTaggedPointer(value);
@@ -2983,7 +2985,7 @@ Node* EffectControlLinearizer::LowerObjectIsBigInt(Node* node) {
Node* check = ObjectIsSmi(value);
__ GotoIf(check, &if_smi);
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
- Node* vfalse = __ WordEqual(value_map, __ BigIntMapConstant());
+ Node* vfalse = __ TaggedEqual(value_map, __ BigIntMapConstant());
__ Goto(&done, vfalse);
__ Bind(&if_smi);
@@ -3095,7 +3097,7 @@ Node* EffectControlLinearizer::LowerObjectIsFiniteNumber(Node* node) {
// Check if {object} is a HeapNumber.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), object);
- __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
+ __ GotoIfNot(__ TaggedEqual(value_map, __ HeapNumberMapConstant()), &done,
zero);
// {object} is a HeapNumber.
@@ -3128,7 +3130,7 @@ Node* EffectControlLinearizer::LowerObjectIsInteger(Node* node) {
// Check if {object} is a HeapNumber.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), object);
- __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
+ __ GotoIfNot(__ TaggedEqual(value_map, __ HeapNumberMapConstant()), &done,
zero);
// {object} is a HeapNumber.
@@ -3171,7 +3173,7 @@ Node* EffectControlLinearizer::LowerObjectIsSafeInteger(Node* node) {
// Check if {object} is a HeapNumber.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), object);
- __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
+ __ GotoIfNot(__ TaggedEqual(value_map, __ HeapNumberMapConstant()), &done,
zero);
// {object} is a HeapNumber.
@@ -3190,9 +3192,14 @@ Node* EffectControlLinearizer::LowerObjectIsSafeInteger(Node* node) {
namespace {
-const int64_t kMinusZeroBits = bit_cast<int64_t>(-0.0);
-const int32_t kMinusZeroLoBits = static_cast<int32_t>(kMinusZeroBits);
-const int32_t kMinusZeroHiBits = static_cast<int32_t>(kMinusZeroBits >> 32);
+// There is no (currently) available constexpr version of bit_cast, so we have
+// to make do with constructing the -0.0 bits manually (by setting the sign bit
+// to 1 and everything else to 0).
+// TODO(leszeks): Revisit when upgrading to C++20.
+constexpr int32_t kMinusZeroLoBits = static_cast<int32_t>(0);
+constexpr int32_t kMinusZeroHiBits = static_cast<int32_t>(1) << 31;
+constexpr int64_t kMinusZeroBits =
+ (static_cast<uint64_t>(kMinusZeroHiBits) << 32) | kMinusZeroLoBits;
} // namespace
@@ -3207,7 +3214,7 @@ Node* EffectControlLinearizer::LowerObjectIsMinusZero(Node* node) {
// Check if {value} is a HeapNumber.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
- __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
+ __ GotoIfNot(__ TaggedEqual(value_map, __ HeapNumberMapConstant()), &done,
zero);
// Check if {value} contains -0.
@@ -3260,7 +3267,7 @@ Node* EffectControlLinearizer::LowerObjectIsNaN(Node* node) {
// Check if {value} is a HeapNumber.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
- __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
+ __ GotoIfNot(__ TaggedEqual(value_map, __ HeapNumberMapConstant()), &done,
zero);
// Check if {value} contains a NaN.
@@ -3319,7 +3326,7 @@ Node* EffectControlLinearizer::LowerObjectIsNumber(Node* node) {
__ GotoIf(ObjectIsSmi(value), &if_smi);
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
- __ Goto(&done, __ WordEqual(value_map, __ HeapNumberMapConstant()));
+ __ Goto(&done, __ TaggedEqual(value_map, __ HeapNumberMapConstant()));
__ Bind(&if_smi);
__ Goto(&done, __ Int32Constant(1));
@@ -3467,7 +3474,7 @@ Node* EffectControlLinearizer::LowerArgumentsLength(Node* node) {
auto done = __ MakeLabel(MachineRepresentation::kTaggedSigned);
Node* frame = __ LoadFramePointer();
- __ GotoIf(__ WordEqual(arguments_frame, frame), &done, __ SmiConstant(0));
+ __ GotoIf(__ TaggedEqual(arguments_frame, frame), &done, __ SmiConstant(0));
__ Goto(&if_adaptor_frame);
__ Bind(&if_adaptor_frame);
@@ -3491,7 +3498,7 @@ Node* EffectControlLinearizer::LowerArgumentsLength(Node* node) {
auto done = __ MakeLabel(MachineRepresentation::kTaggedSigned);
Node* frame = __ LoadFramePointer();
- __ GotoIf(__ WordEqual(arguments_frame, frame), &done,
+ __ GotoIf(__ TaggedEqual(arguments_frame, frame), &done,
__ SmiConstant(formal_parameter_count));
__ Goto(&if_adaptor_frame);
@@ -3517,9 +3524,9 @@ Node* EffectControlLinearizer::LowerArgumentsFrame(Node* node) {
MachineType::TypeCompressedTagged(), parent_frame,
__ IntPtrConstant(CommonFrameConstants::kContextOrFrameTypeOffset));
- __ GotoIf(__ WordEqual(parent_frame_type,
- __ IntPtrConstant(StackFrame::TypeToMarker(
- StackFrame::ARGUMENTS_ADAPTOR))),
+ __ GotoIf(__ IntPtrEqual(parent_frame_type,
+ __ IntPtrConstant(StackFrame::TypeToMarker(
+ StackFrame::ARGUMENTS_ADAPTOR))),
&done, parent_frame);
__ Goto(&done, frame);
@@ -3532,7 +3539,7 @@ Node* EffectControlLinearizer::LowerNewDoubleElements(Node* node) {
Node* length = node->InputAt(0);
auto done = __ MakeLabel(MachineRepresentation::kTaggedPointer);
- Node* zero_length = __ WordEqual(length, __ IntPtrConstant(0));
+ Node* zero_length = __ IntPtrEqual(length, __ IntPtrConstant(0));
__ GotoIf(zero_length, &done,
jsgraph()->HeapConstant(factory()->empty_fixed_array()));
@@ -3580,7 +3587,7 @@ Node* EffectControlLinearizer::LowerNewSmiOrObjectElements(Node* node) {
Node* length = node->InputAt(0);
auto done = __ MakeLabel(MachineRepresentation::kTaggedPointer);
- Node* zero_length = __ WordEqual(length, __ IntPtrConstant(0));
+ Node* zero_length = __ IntPtrEqual(length, __ IntPtrConstant(0));
__ GotoIf(zero_length, &done,
jsgraph()->HeapConstant(factory()->empty_fixed_array()));
@@ -3832,7 +3839,7 @@ Node* EffectControlLinearizer::LowerStringCharCodeAt(Node* node) {
{
Node* receiver_second =
__ LoadField(AccessBuilder::ForConsStringSecond(), receiver);
- __ GotoIfNot(__ WordEqual(receiver_second, __ EmptyStringConstant()),
+ __ GotoIfNot(__ TaggedEqual(receiver_second, __ EmptyStringConstant()),
&if_runtime);
Node* receiver_first =
__ LoadField(AccessBuilder::ForConsStringFirst(), receiver);
@@ -3967,7 +3974,7 @@ Node* EffectControlLinearizer::LowerStringFromSingleCharCode(Node* node) {
Node* entry =
__ LoadElement(AccessBuilder::ForFixedArrayElement(), cache, index);
- Node* check2 = __ WordEqual(entry, __ UndefinedConstant());
+ Node* check2 = __ TaggedEqual(entry, __ UndefinedConstant());
__ GotoIf(check2, &cache_miss);
// Use the {entry} from the {cache}.
@@ -4093,7 +4100,7 @@ Node* EffectControlLinearizer::LowerStringFromSingleCodePoint(Node* node) {
Node* entry =
__ LoadElement(AccessBuilder::ForFixedArrayElement(), cache, index);
- Node* check2 = __ WordEqual(entry, __ UndefinedConstant());
+ Node* check2 = __ TaggedEqual(entry, __ UndefinedConstant());
__ GotoIf(check2, &cache_miss);
// Use the {entry} from the {cache}.
@@ -4285,7 +4292,7 @@ Node* EffectControlLinearizer::LowerBigIntAdd(Node* node, Node* frame_state) {
rhs, __ NoContextConstant());
// Check for exception sentinel: Smi is returned to signal BigIntTooBig.
- __ DeoptimizeIf(DeoptimizeReason::kBigIntTooBig, VectorSlotPair{},
+ __ DeoptimizeIf(DeoptimizeReason::kBigIntTooBig, FeedbackSource{},
ObjectIsSmi(value), frame_state);
return value;
@@ -4338,8 +4345,8 @@ Node* EffectControlLinearizer::LowerCheckFloat64Hole(Node* node,
Node* EffectControlLinearizer::LowerCheckNotTaggedHole(Node* node,
Node* frame_state) {
Node* value = node->InputAt(0);
- Node* check = __ WordEqual(value, __ TheHoleConstant());
- __ DeoptimizeIf(DeoptimizeReason::kHole, VectorSlotPair(), check,
+ Node* check = __ TaggedEqual(value, __ TheHoleConstant());
+ __ DeoptimizeIf(DeoptimizeReason::kHole, FeedbackSource(), check,
frame_state);
return value;
}
@@ -4350,7 +4357,7 @@ Node* EffectControlLinearizer::LowerConvertTaggedHoleToUndefined(Node* node) {
auto if_is_hole = __ MakeDeferredLabel();
auto done = __ MakeLabel(MachineRepresentation::kTagged);
- Node* check = __ WordEqual(value, __ TheHoleConstant());
+ Node* check = __ TaggedEqual(value, __ TheHoleConstant());
__ GotoIf(check, &if_is_hole);
__ Goto(&done, value);
@@ -4372,12 +4379,12 @@ void EffectControlLinearizer::LowerCheckEqualsInternalizedString(
auto if_notthinstring = __ MakeLabel();
// Check if {exp} and {val} are the same, which is the likely case.
- __ Branch(__ WordEqual(exp, val), &if_same, &if_notsame);
+ __ Branch(__ TaggedEqual(exp, val), &if_same, &if_notsame);
__ Bind(&if_notsame);
{
// Now {val} could still be a non-internalized String that matches {exp}.
- __ DeoptimizeIf(DeoptimizeReason::kWrongName, VectorSlotPair(),
+ __ DeoptimizeIf(DeoptimizeReason::kWrongName, FeedbackSource(),
ObjectIsSmi(val), frame_state);
Node* val_map = __ LoadField(AccessBuilder::ForMap(), val);
Node* val_instance_type =
@@ -4396,7 +4403,7 @@ void EffectControlLinearizer::LowerCheckEqualsInternalizedString(
// Check that the {val} is a non-internalized String, if it's anything
// else it cannot match the recorded feedback {exp} anyways.
__ DeoptimizeIfNot(
- DeoptimizeReason::kWrongName, VectorSlotPair(),
+ DeoptimizeReason::kWrongName, FeedbackSource(),
__ Word32Equal(__ Word32And(val_instance_type,
__ Int32Constant(kIsNotStringMask |
kIsNotInternalizedMask)),
@@ -4419,8 +4426,8 @@ void EffectControlLinearizer::LowerCheckEqualsInternalizedString(
try_internalize_string_function, isolate_ptr, val);
// Now see if the results match.
- __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, VectorSlotPair(),
- __ WordEqual(exp, val_internalized), frame_state);
+ __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, FeedbackSource(),
+ __ TaggedEqual(exp, val_internalized), frame_state);
__ Goto(&if_same);
}
@@ -4429,8 +4436,8 @@ void EffectControlLinearizer::LowerCheckEqualsInternalizedString(
// The {val} is a ThinString, let's check the actual value.
Node* val_actual =
__ LoadField(AccessBuilder::ForThinStringActual(), val);
- __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, VectorSlotPair(),
- __ WordEqual(exp, val_actual), frame_state);
+ __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, FeedbackSource(),
+ __ TaggedEqual(exp, val_actual), frame_state);
__ Goto(&if_same);
}
}
@@ -4442,8 +4449,8 @@ void EffectControlLinearizer::LowerCheckEqualsSymbol(Node* node,
Node* frame_state) {
Node* exp = node->InputAt(0);
Node* val = node->InputAt(1);
- Node* check = __ WordEqual(exp, val);
- __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, VectorSlotPair(), check,
+ Node* check = __ TaggedEqual(exp, val);
+ __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, FeedbackSource(), check,
frame_state);
}
@@ -4543,8 +4550,13 @@ Node* EffectControlLinearizer::ChangeSmiToInt64(Node* value) {
}
Node* EffectControlLinearizer::ObjectIsSmi(Node* value) {
- return __ WordEqual(__ WordAnd(value, __ IntPtrConstant(kSmiTagMask)),
- __ IntPtrConstant(kSmiTag));
+ return __ IntPtrEqual(__ WordAnd(value, __ IntPtrConstant(kSmiTagMask)),
+ __ IntPtrConstant(kSmiTag));
+}
+
+Node* EffectControlLinearizer::CompressedObjectIsSmi(Node* value) {
+ return __ Word32Equal(__ Word32And(value, __ Int32Constant(kSmiTagMask)),
+ __ Int32Constant(kSmiTag));
}
Node* EffectControlLinearizer::SmiMaxValueConstant() {
@@ -4629,7 +4641,7 @@ Node* EffectControlLinearizer::LowerEnsureWritableFastElements(Node* node) {
Node* elements_map = __ LoadField(AccessBuilder::ForMap(), elements);
// Check if {elements} is not a copy-on-write FixedArray.
- Node* check = __ WordEqual(elements_map, __ FixedArrayMapConstant());
+ Node* check = __ TaggedEqual(elements_map, __ FixedArrayMapConstant());
__ GotoIfNot(check, &if_not_fixed_array);
// Nothing to do if the {elements} are not copy-on-write.
__ Goto(&done, elements);
@@ -4707,7 +4719,7 @@ void EffectControlLinearizer::LowerTransitionElementsKind(Node* node) {
Node* object_map = __ LoadField(AccessBuilder::ForMap(), object);
// Check if {object_map} is the same as {source_map}.
- Node* check = __ WordEqual(object_map, source_map);
+ Node* check = __ TaggedEqual(object_map, source_map);
__ GotoIf(check, &if_map_same);
__ Goto(&done);
@@ -4749,7 +4761,7 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) {
auto done = __ MakeLabel(MachineRepresentation::kTagged);
// Check if field is a mutable double field.
- __ GotoIfNot(__ WordEqual(__ WordAnd(index, one), zero), &if_double);
+ __ GotoIfNot(__ IntPtrEqual(__ WordAnd(index, one), zero), &if_double);
// The field is a proper Tagged field on {object}. The {index} is shifted
// to the left by one in the code below.
@@ -4772,8 +4784,8 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) {
// The {index} is equal to the negated out of property index plus 1.
__ Bind(&if_outofobject);
{
- Node* properties =
- __ LoadField(AccessBuilder::ForJSObjectPropertiesOrHash(), object);
+ Node* properties = __ LoadField(
+ AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(), object);
Node* offset =
__ IntAdd(__ WordShl(__ IntSub(zero, index),
__ IntPtrConstant(kTaggedSizeLog2 - 1)),
@@ -4786,7 +4798,7 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) {
}
// The field is a Double field, either unboxed in the object on 64-bit
- // architectures, or as MutableHeapNumber.
+ // architectures, or a mutable HeapNumber.
__ Bind(&if_double);
{
auto done_double = __ MakeLabel(MachineRepresentation::kFloat64);
@@ -4815,8 +4827,8 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) {
__ Bind(&if_outofobject);
{
- Node* properties =
- __ LoadField(AccessBuilder::ForJSObjectPropertiesOrHash(), object);
+ Node* properties = __ LoadField(
+ AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(), object);
Node* offset =
__ IntAdd(__ WordShl(__ IntSub(zero, index),
__ IntPtrConstant(kTaggedSizeLog2)),
@@ -5123,7 +5135,7 @@ void EffectControlLinearizer::LowerTransitionAndStoreElement(Node* node) {
// without effecting a transition.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
Node* heap_number_map = __ HeapNumberMapConstant();
- Node* check = __ WordEqual(value_map, heap_number_map);
+ Node* check = __ TaggedEqual(value_map, heap_number_map);
__ GotoIfNot(check, &transition_double_to_fast);
__ Goto(&do_store, kind);
}
@@ -5135,7 +5147,7 @@ void EffectControlLinearizer::LowerTransitionAndStoreElement(Node* node) {
auto if_value_not_heap_number = __ MakeLabel();
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
Node* heap_number_map = __ HeapNumberMapConstant();
- Node* check = __ WordEqual(value_map, heap_number_map);
+ Node* check = __ TaggedEqual(value_map, heap_number_map);
__ GotoIfNot(check, &if_value_not_heap_number);
{
// {value} is a HeapNumber.
@@ -5478,9 +5490,10 @@ Node* EffectControlLinearizer::LowerConvertReceiver(Node* node) {
// Wrap the primitive {value} into a JSPrimitiveWrapper.
__ Bind(&convert_to_object);
- __ GotoIf(__ WordEqual(value, __ UndefinedConstant()),
+ __ GotoIf(__ TaggedEqual(value, __ UndefinedConstant()),
+ &convert_global_proxy);
+ __ GotoIf(__ TaggedEqual(value, __ NullConstant()),
&convert_global_proxy);
- __ GotoIf(__ WordEqual(value, __ NullConstant()), &convert_global_proxy);
Operator::Properties properties = Operator::kEliminatable;
Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
@@ -5891,7 +5904,7 @@ Node* EffectControlLinearizer::LowerFindOrderedHashMapEntryForInt32Key(
{
Node* entry = loop.PhiAt(0);
Node* check =
- __ WordEqual(entry, __ IntPtrConstant(OrderedHashMap::kNotFound));
+ __ IntPtrEqual(entry, __ IntPtrConstant(OrderedHashMap::kNotFound));
__ GotoIf(check, &done, entry);
entry = __ IntAdd(
__ IntMul(entry, __ IntPtrConstant(OrderedHashMap::kEntrySize)),
@@ -5906,14 +5919,20 @@ Node* EffectControlLinearizer::LowerFindOrderedHashMapEntryForInt32Key(
auto if_match = __ MakeLabel();
auto if_notmatch = __ MakeLabel();
auto if_notsmi = __ MakeDeferredLabel();
- __ GotoIfNot(ObjectIsSmi(candidate_key), &if_notsmi);
- __ Branch(__ Word32Equal(ChangeSmiToInt32(candidate_key), key), &if_match,
- &if_notmatch);
+ if (COMPRESS_POINTERS_BOOL) {
+ __ GotoIfNot(CompressedObjectIsSmi(candidate_key), &if_notsmi);
+ __ Branch(__ Word32Equal(ChangeCompressedSmiToInt32(candidate_key), key),
+ &if_match, &if_notmatch);
+ } else {
+ __ GotoIfNot(ObjectIsSmi(candidate_key), &if_notsmi);
+ __ Branch(__ Word32Equal(ChangeSmiToInt32(candidate_key), key), &if_match,
+ &if_notmatch);
+ }
__ Bind(&if_notsmi);
__ GotoIfNot(
- __ WordEqual(__ LoadField(AccessBuilder::ForMap(), candidate_key),
- __ HeapNumberMapConstant()),
+ __ TaggedEqual(__ LoadField(AccessBuilder::ForMap(), candidate_key),
+ __ HeapNumberMapConstant()),
&if_notmatch);
__ Branch(__ Float64Equal(__ LoadField(AccessBuilder::ForHeapNumberValue(),
candidate_key),
diff --git a/deps/v8/src/compiler/escape-analysis.cc b/deps/v8/src/compiler/escape-analysis.cc
index aee0121384..b3f684ea61 100644
--- a/deps/v8/src/compiler/escape-analysis.cc
+++ b/deps/v8/src/compiler/escape-analysis.cc
@@ -736,10 +736,9 @@ void ReduceNode(const Operator* op, EscapeAnalysisTracker::Scope* current,
current->Get(map_field).To(&map)) {
if (map) {
Type const map_type = NodeProperties::GetType(map);
- AllowHandleDereference handle_dereference;
if (map_type.IsHeapConstant() &&
params.maps().contains(
- Handle<Map>::cast(map_type.AsHeapConstant()->Value()))) {
+ map_type.AsHeapConstant()->Ref().AsMap().object())) {
current->MarkForDeletion();
break;
}
diff --git a/deps/v8/src/compiler/feedback-source.cc b/deps/v8/src/compiler/feedback-source.cc
new file mode 100644
index 0000000000..8c3d175c28
--- /dev/null
+++ b/deps/v8/src/compiler/feedback-source.cc
@@ -0,0 +1,45 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/feedback-source.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+FeedbackSource::FeedbackSource(Handle<FeedbackVector> vector_,
+ FeedbackSlot slot_)
+ : vector(vector_), slot(slot_) {
+ DCHECK(!slot.IsInvalid());
+}
+
+FeedbackSource::FeedbackSource(FeedbackVectorRef vector_, FeedbackSlot slot_)
+ : FeedbackSource(vector_.object(), slot_) {}
+
+FeedbackSource::FeedbackSource(FeedbackNexus const& nexus)
+ : FeedbackSource(nexus.vector_handle(), nexus.slot()) {}
+
+int FeedbackSource::index() const {
+ CHECK(IsValid());
+ return FeedbackVector::GetIndex(slot);
+}
+
+bool operator==(FeedbackSource const& lhs, FeedbackSource const& rhs) {
+ return FeedbackSource::Equal()(lhs, rhs);
+}
+
+bool operator!=(FeedbackSource const& lhs, FeedbackSource const& rhs) {
+ return !(lhs == rhs);
+}
+
+std::ostream& operator<<(std::ostream& os, const FeedbackSource& p) {
+ if (p.IsValid()) {
+ return os << "FeedbackSource(" << p.slot << ")";
+ }
+ return os << "FeedbackSource(INVALID)";
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/compiler/feedback-source.h b/deps/v8/src/compiler/feedback-source.h
new file mode 100644
index 0000000000..8484acb455
--- /dev/null
+++ b/deps/v8/src/compiler/feedback-source.h
@@ -0,0 +1,52 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_FEEDBACK_SOURCE_H_
+#define V8_COMPILER_FEEDBACK_SOURCE_H_
+
+#include "src/compiler/heap-refs.h"
+#include "src/objects/feedback-vector.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+struct FeedbackSource {
+ FeedbackSource() { DCHECK(!IsValid()); }
+ V8_EXPORT_PRIVATE FeedbackSource(Handle<FeedbackVector> vector_,
+ FeedbackSlot slot_);
+ FeedbackSource(FeedbackVectorRef vector_, FeedbackSlot slot_);
+ explicit FeedbackSource(FeedbackNexus const& nexus);
+
+ bool IsValid() const { return !vector.is_null() && !slot.IsInvalid(); }
+ int index() const;
+
+ Handle<FeedbackVector> vector;
+ FeedbackSlot slot;
+
+ struct Hash {
+ size_t operator()(FeedbackSource const& source) const {
+ return base::hash_combine(source.vector.address(), source.slot);
+ }
+ };
+
+ struct Equal {
+ bool operator()(FeedbackSource const& lhs,
+ FeedbackSource const& rhs) const {
+ return lhs.vector.equals(rhs.vector) && lhs.slot == rhs.slot;
+ }
+ };
+};
+
+bool operator==(FeedbackSource const&, FeedbackSource const&);
+bool operator!=(FeedbackSource const&, FeedbackSource const&);
+
+V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+ FeedbackSource const&);
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
+
+#endif // V8_COMPILER_FEEDBACK_SOURCE_H_
diff --git a/deps/v8/src/compiler/frame-states.cc b/deps/v8/src/compiler/frame-states.cc
index 5fbf11cdbc..9478c08c6c 100644
--- a/deps/v8/src/compiler/frame-states.cc
+++ b/deps/v8/src/compiler/frame-states.cc
@@ -106,28 +106,22 @@ Node* CreateBuiltinContinuationFrameStateCommon(
Node* closure, Node* context, Node** parameters, int parameter_count,
Node* outer_frame_state,
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>()) {
- Isolate* const isolate = jsgraph->isolate();
Graph* const graph = jsgraph->graph();
CommonOperatorBuilder* const common = jsgraph->common();
- BailoutId bailout_id = Builtins::GetContinuationBailoutId(name);
- Callable callable = Builtins::CallableFor(isolate, name);
-
const Operator* op_param =
common->StateValues(parameter_count, SparseInputMask::Dense());
Node* params_node = graph->NewNode(op_param, parameter_count, parameters);
+ BailoutId bailout_id = Builtins::GetContinuationBailoutId(name);
const FrameStateFunctionInfo* state_info =
common->CreateFrameStateFunctionInfo(frame_type, parameter_count, 0,
shared);
const Operator* op = common->FrameState(
bailout_id, OutputFrameStateCombine::Ignore(), state_info);
-
- Node* frame_state = graph->NewNode(
- op, params_node, jsgraph->EmptyStateValues(), jsgraph->EmptyStateValues(),
- context, closure, outer_frame_state);
-
- return frame_state;
+ return graph->NewNode(op, params_node, jsgraph->EmptyStateValues(),
+ jsgraph->EmptyStateValues(), context, closure,
+ outer_frame_state);
}
} // namespace
@@ -136,8 +130,7 @@ Node* CreateStubBuiltinContinuationFrameState(
JSGraph* jsgraph, Builtins::Name name, Node* context,
Node* const* parameters, int parameter_count, Node* outer_frame_state,
ContinuationFrameStateMode mode) {
- Isolate* isolate = jsgraph->isolate();
- Callable callable = Builtins::CallableFor(isolate, name);
+ Callable callable = Builtins::CallableFor(jsgraph->isolate(), name);
CallInterfaceDescriptor descriptor = callable.descriptor();
std::vector<Node*> actual_parameters;
@@ -172,9 +165,6 @@ Node* CreateJavaScriptBuiltinContinuationFrameState(
Node* target, Node* context, Node* const* stack_parameters,
int stack_parameter_count, Node* outer_frame_state,
ContinuationFrameStateMode mode) {
- Isolate* const isolate = jsgraph->isolate();
- Callable const callable = Builtins::CallableFor(isolate, name);
-
// Depending on {mode}, final parameters are added by the deoptimizer
// and aren't explicitly passed in the frame state.
DCHECK_EQ(Builtins::GetStackParameterCount(name) + 1, // add receiver
@@ -190,11 +180,13 @@ Node* CreateJavaScriptBuiltinContinuationFrameState(
actual_parameters.push_back(stack_parameters[i]);
}
- // Register parameters follow stack paraemters. The context will be added by
+ Node* new_target = jsgraph->UndefinedConstant();
+
+ // Register parameters follow stack parameters. The context will be added by
// instruction selector during FrameState translation.
- actual_parameters.push_back(target);
- actual_parameters.push_back(jsgraph->UndefinedConstant());
- actual_parameters.push_back(argc);
+ actual_parameters.push_back(target); // kJavaScriptCallTargetRegister
+ actual_parameters.push_back(new_target); // kJavaScriptCallNewTargetRegister
+ actual_parameters.push_back(argc); // kJavaScriptCallArgCountRegister
return CreateBuiltinContinuationFrameStateCommon(
jsgraph,
diff --git a/deps/v8/src/compiler/graph-assembler.cc b/deps/v8/src/compiler/graph-assembler.cc
index 50f29d968b..b4ad81ecda 100644
--- a/deps/v8/src/compiler/graph-assembler.cc
+++ b/deps/v8/src/compiler/graph-assembler.cc
@@ -94,6 +94,14 @@ PURE_ASSEMBLER_MACH_BINOP_LIST(PURE_BINOP_DEF)
CHECKED_ASSEMBLER_MACH_BINOP_LIST(CHECKED_BINOP_DEF)
#undef CHECKED_BINOP_DEF
+Node* GraphAssembler::IntPtrEqual(Node* left, Node* right) {
+ return WordEqual(left, right);
+}
+
+Node* GraphAssembler::TaggedEqual(Node* left, Node* right) {
+ return WordEqual(left, right);
+}
+
Node* GraphAssembler::Float64RoundDown(Node* value) {
CHECK(machine()->Float64RoundDown().IsSupported());
return graph()->NewNode(machine()->Float64RoundDown().op(), value);
@@ -237,7 +245,7 @@ Node* GraphAssembler::Word32PoisonOnSpeculation(Node* value) {
}
Node* GraphAssembler::DeoptimizeIf(DeoptimizeReason reason,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
Node* condition, Node* frame_state,
IsSafetyCheck is_safety_check) {
return current_control_ = current_effect_ = graph()->NewNode(
@@ -247,7 +255,7 @@ Node* GraphAssembler::DeoptimizeIf(DeoptimizeReason reason,
}
Node* GraphAssembler::DeoptimizeIfNot(DeoptimizeReason reason,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
Node* condition, Node* frame_state,
IsSafetyCheck is_safety_check) {
return current_control_ = current_effect_ = graph()->NewNode(
diff --git a/deps/v8/src/compiler/graph-assembler.h b/deps/v8/src/compiler/graph-assembler.h
index e2c0005d15..0088f867c5 100644
--- a/deps/v8/src/compiler/graph-assembler.h
+++ b/deps/v8/src/compiler/graph-assembler.h
@@ -5,10 +5,10 @@
#ifndef V8_COMPILER_GRAPH_ASSEMBLER_H_
#define V8_COMPILER_GRAPH_ASSEMBLER_H_
+#include "src/compiler/feedback-source.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node.h"
#include "src/compiler/simplified-operator.h"
-#include "src/compiler/vector-slot-pair.h"
namespace v8 {
namespace internal {
@@ -224,6 +224,9 @@ class GraphAssembler {
Node* Unreachable();
+ Node* IntPtrEqual(Node* left, Node* right);
+ Node* TaggedEqual(Node* left, Node* right);
+
Node* Float64RoundDown(Node* value);
Node* Float64RoundTruncate(Node* value);
@@ -251,11 +254,11 @@ class GraphAssembler {
Node* Word32PoisonOnSpeculation(Node* value);
Node* DeoptimizeIf(
- DeoptimizeReason reason, VectorSlotPair const& feedback, Node* condition,
+ DeoptimizeReason reason, FeedbackSource const& feedback, Node* condition,
Node* frame_state,
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
Node* DeoptimizeIfNot(
- DeoptimizeReason reason, VectorSlotPair const& feedback, Node* condition,
+ DeoptimizeReason reason, FeedbackSource const& feedback, Node* condition,
Node* frame_state,
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
template <typename... Args>
diff --git a/deps/v8/src/compiler/graph.cc b/deps/v8/src/compiler/graph.cc
index fea76bff81..99e9d5ffdb 100644
--- a/deps/v8/src/compiler/graph.cc
+++ b/deps/v8/src/compiler/graph.cc
@@ -68,9 +68,10 @@ Node* Graph::CloneNode(const Node* node) {
NodeId Graph::NextNodeId() {
- NodeId const id = next_node_id_;
- CHECK(!base::bits::UnsignedAddOverflow32(id, 1, &next_node_id_));
- return id;
+ // A node's id is internally stored in a bit field using fewer bits than
+ // NodeId (see Node::IdField). Hence the addition below won't ever overflow.
+ DCHECK_LT(next_node_id_, std::numeric_limits<NodeId>::max());
+ return next_node_id_++;
}
void Graph::Print() const { StdoutStream{} << AsRPO(*this); }
diff --git a/deps/v8/src/compiler/heap-refs.h b/deps/v8/src/compiler/heap-refs.h
index 5547039fa6..9b1aa53eb9 100644
--- a/deps/v8/src/compiler/heap-refs.h
+++ b/deps/v8/src/compiler/heap-refs.h
@@ -27,7 +27,6 @@ class JSRegExp;
class JSTypedArray;
class NativeContext;
class ScriptContextTable;
-class VectorSlotPair;
namespace compiler {
@@ -35,6 +34,8 @@ namespace compiler {
// For a store during literal creation, do not walk up the prototype chain.
enum class AccessMode { kLoad, kStore, kStoreInLiteral, kHas };
+enum class SerializationPolicy { kAssumeSerialized, kSerializeIfNeeded };
+
enum class OddballType : uint8_t {
kNone, // Not an Oddball.
kBoolean, // True or False.
@@ -53,6 +54,7 @@ enum class OddballType : uint8_t {
V(JSBoundFunction) \
V(JSDataView) \
V(JSFunction) \
+ V(JSGlobalObject) \
V(JSGlobalProxy) \
V(JSRegExp) \
V(JSTypedArray) \
@@ -70,8 +72,12 @@ enum class OddballType : uint8_t {
V(InternalizedString) \
V(String) \
V(Symbol) \
+ /* Subtypes of JSReceiver */ \
+ V(JSObject) \
/* Subtypes of HeapObject */ \
+ V(AccessorInfo) \
V(AllocationSite) \
+ V(ArrayBoilerplateDescription) \
V(BigInt) \
V(CallHandlerInfo) \
V(Cell) \
@@ -82,10 +88,10 @@ enum class OddballType : uint8_t {
V(FixedArrayBase) \
V(FunctionTemplateInfo) \
V(HeapNumber) \
- V(JSObject) \
+ V(JSReceiver) \
V(Map) \
- V(MutableHeapNumber) \
V(Name) \
+ V(ObjectBoilerplateDescription) \
V(PropertyCell) \
V(SharedFunctionInfo) \
V(SourceTextModule) \
@@ -103,8 +109,9 @@ HEAP_BROKER_OBJECT_LIST(FORWARD_DECL)
class V8_EXPORT_PRIVATE ObjectRef {
public:
- ObjectRef(JSHeapBroker* broker, Handle<Object> object);
- ObjectRef(JSHeapBroker* broker, ObjectData* data)
+ ObjectRef(JSHeapBroker* broker, Handle<Object> object,
+ bool check_type = true);
+ ObjectRef(JSHeapBroker* broker, ObjectData* data, bool check_type = true)
: data_(data), broker_(broker) {
CHECK_NOT_NULL(data_);
}
@@ -131,8 +138,9 @@ class V8_EXPORT_PRIVATE ObjectRef {
// Return the element at key {index} if {index} is known to be an own data
// property of the object that is non-writable and non-configurable.
- base::Optional<ObjectRef> GetOwnConstantElement(uint32_t index,
- bool serialize = false) const;
+ base::Optional<ObjectRef> GetOwnConstantElement(
+ uint32_t index, SerializationPolicy policy =
+ SerializationPolicy::kAssumeSerialized) const;
Isolate* isolate() const;
@@ -157,6 +165,7 @@ class V8_EXPORT_PRIVATE ObjectRef {
friend class JSArrayData;
friend class JSGlobalProxyRef;
friend class JSGlobalProxyData;
+ friend class JSHeapBroker;
friend class JSObjectData;
friend class StringData;
@@ -200,9 +209,27 @@ class HeapObjectType {
Flags const flags_;
};
+// Constructors are carefully defined such that we do a type check on
+// the outermost Ref class in the inheritance chain only.
+#define DEFINE_REF_CONSTRUCTOR(name, base) \
+ name##Ref(JSHeapBroker* broker, Handle<Object> object, \
+ bool check_type = true) \
+ : base(broker, object, false) { \
+ if (check_type) { \
+ CHECK(Is##name()); \
+ } \
+ } \
+ name##Ref(JSHeapBroker* broker, ObjectData* data, bool check_type = true) \
+ : base(broker, data, false) { \
+ if (check_type) { \
+ CHECK(Is##name()); \
+ } \
+ }
+
class HeapObjectRef : public ObjectRef {
public:
- using ObjectRef::ObjectRef;
+ DEFINE_REF_CONSTRUCTOR(HeapObject, ObjectRef)
+
Handle<HeapObject> object() const;
MapRef map() const;
@@ -213,7 +240,8 @@ class HeapObjectRef : public ObjectRef {
class PropertyCellRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(PropertyCell, HeapObjectRef)
+
Handle<PropertyCell> object() const;
PropertyDetails property_details() const;
@@ -222,9 +250,17 @@ class PropertyCellRef : public HeapObjectRef {
ObjectRef value() const;
};
-class JSObjectRef : public HeapObjectRef {
+class JSReceiverRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(JSReceiver, HeapObjectRef)
+
+ Handle<JSReceiver> object() const;
+};
+
+class JSObjectRef : public JSReceiverRef {
+ public:
+ DEFINE_REF_CONSTRUCTOR(JSObject, JSReceiverRef)
+
Handle<JSObject> object() const;
uint64_t RawFastDoublePropertyAsBitsAt(FieldIndex index) const;
@@ -233,10 +269,10 @@ class JSObjectRef : public HeapObjectRef {
// Return the value of the property identified by the field {index}
// if {index} is known to be an own data property of the object.
- base::Optional<ObjectRef> GetOwnProperty(Representation field_representation,
- FieldIndex index,
- bool serialize = false) const;
-
+ base::Optional<ObjectRef> GetOwnDataProperty(
+ Representation field_representation, FieldIndex index,
+ SerializationPolicy policy =
+ SerializationPolicy::kAssumeSerialized) const;
FixedArrayBaseRef elements() const;
void SerializeElements();
void EnsureElementsTenured();
@@ -248,7 +284,8 @@ class JSObjectRef : public HeapObjectRef {
class JSDataViewRef : public JSObjectRef {
public:
- using JSObjectRef::JSObjectRef;
+ DEFINE_REF_CONSTRUCTOR(JSDataView, JSObjectRef)
+
Handle<JSDataView> object() const;
size_t byte_length() const;
@@ -257,20 +294,23 @@ class JSDataViewRef : public JSObjectRef {
class JSBoundFunctionRef : public JSObjectRef {
public:
- using JSObjectRef::JSObjectRef;
+ DEFINE_REF_CONSTRUCTOR(JSBoundFunction, JSObjectRef)
+
Handle<JSBoundFunction> object() const;
void Serialize();
+ bool serialized() const;
// The following are available only after calling Serialize().
- ObjectRef bound_target_function() const;
+ JSReceiverRef bound_target_function() const;
ObjectRef bound_this() const;
FixedArrayRef bound_arguments() const;
};
class V8_EXPORT_PRIVATE JSFunctionRef : public JSObjectRef {
public:
- using JSObjectRef::JSObjectRef;
+ DEFINE_REF_CONSTRUCTOR(JSFunction, JSObjectRef)
+
Handle<JSFunction> object() const;
bool has_feedback_vector() const;
@@ -295,7 +335,8 @@ class V8_EXPORT_PRIVATE JSFunctionRef : public JSObjectRef {
class JSRegExpRef : public JSObjectRef {
public:
- using JSObjectRef::JSObjectRef;
+ DEFINE_REF_CONSTRUCTOR(JSRegExp, JSObjectRef)
+
Handle<JSRegExp> object() const;
ObjectRef raw_properties_or_hash() const;
@@ -307,33 +348,31 @@ class JSRegExpRef : public JSObjectRef {
class HeapNumberRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
- Handle<HeapNumber> object() const;
+ DEFINE_REF_CONSTRUCTOR(HeapNumber, HeapObjectRef)
- double value() const;
-};
-
-class MutableHeapNumberRef : public HeapObjectRef {
- public:
- using HeapObjectRef::HeapObjectRef;
- Handle<MutableHeapNumber> object() const;
+ Handle<HeapNumber> object() const;
double value() const;
};
class ContextRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(Context, HeapObjectRef)
+
Handle<Context> object() const;
// {previous} decrements {depth} by 1 for each previous link successfully
// followed. If {depth} != 0 on function return, then it only got
// partway to the desired depth. If {serialize} is true, then
// {previous} will cache its findings.
- ContextRef previous(size_t* depth, bool serialize = false) const;
+ ContextRef previous(size_t* depth,
+ SerializationPolicy policy =
+ SerializationPolicy::kAssumeSerialized) const;
// Only returns a value if the index is valid for this ContextRef.
- base::Optional<ObjectRef> get(int index, bool serialize = false) const;
+ base::Optional<ObjectRef> get(
+ int index, SerializationPolicy policy =
+ SerializationPolicy::kAssumeSerialized) const;
// We only serialize the ScopeInfo if certain Promise
// builtins are called.
@@ -351,6 +390,7 @@ class ContextRef : public HeapObjectRef {
V(JSFunction, promise_then) \
V(JSFunction, string_function) \
V(JSFunction, symbol_function) \
+ V(JSGlobalObject, global_object) \
V(JSGlobalProxy, global_proxy_object) \
V(JSObject, promise_prototype) \
V(Map, bound_function_with_constructor_map) \
@@ -391,7 +431,8 @@ class ContextRef : public HeapObjectRef {
class NativeContextRef : public ContextRef {
public:
- using ContextRef::ContextRef;
+ DEFINE_REF_CONSTRUCTOR(NativeContext, ContextRef)
+
Handle<NativeContext> object() const;
void Serialize();
@@ -408,7 +449,8 @@ class NativeContextRef : public ContextRef {
class NameRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(Name, HeapObjectRef)
+
Handle<Name> object() const;
bool IsUniqueName() const;
@@ -416,7 +458,8 @@ class NameRef : public HeapObjectRef {
class ScriptContextTableRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(ScriptContextTable, HeapObjectRef)
+
Handle<ScriptContextTable> object() const;
struct LookupResult {
@@ -430,13 +473,15 @@ class ScriptContextTableRef : public HeapObjectRef {
class DescriptorArrayRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(DescriptorArray, HeapObjectRef)
+
Handle<DescriptorArray> object() const;
};
class FeedbackCellRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(FeedbackCell, HeapObjectRef)
+
Handle<FeedbackCell> object() const;
HeapObjectRef value() const;
@@ -444,17 +489,21 @@ class FeedbackCellRef : public HeapObjectRef {
class FeedbackVectorRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(FeedbackVector, HeapObjectRef)
+
Handle<FeedbackVector> object() const;
- ObjectRef get(FeedbackSlot slot) const;
+ double invocation_count() const;
- void SerializeSlots();
+ void Serialize();
+ ObjectRef get(FeedbackSlot slot) const;
+ FeedbackCellRef GetClosureFeedbackCell(int index) const;
};
class CallHandlerInfoRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(CallHandlerInfo, HeapObjectRef)
+
Handle<CallHandlerInfo> object() const;
Address callback() const;
@@ -463,9 +512,17 @@ class CallHandlerInfoRef : public HeapObjectRef {
ObjectRef data() const;
};
+class AccessorInfoRef : public HeapObjectRef {
+ public:
+ DEFINE_REF_CONSTRUCTOR(AccessorInfo, HeapObjectRef)
+
+ Handle<AccessorInfo> object() const;
+};
+
class AllocationSiteRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(AllocationSite, HeapObjectRef)
+
Handle<AllocationSite> object() const;
bool PointsToLiteral() const;
@@ -487,7 +544,8 @@ class AllocationSiteRef : public HeapObjectRef {
class BigIntRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(BigInt, HeapObjectRef)
+
Handle<BigInt> object() const;
uint64_t AsUint64() const;
@@ -495,7 +553,8 @@ class BigIntRef : public HeapObjectRef {
class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(Map, HeapObjectRef)
+
Handle<Map> object() const;
int instance_size() const;
@@ -526,7 +585,8 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
bool is_migration_target() const;
bool supports_fast_array_iteration() const;
bool supports_fast_array_resize() const;
- bool IsMapOfCurrentGlobalProxy() const;
+ bool IsMapOfTargetGlobalProxy() const;
+ bool is_abandoned_prototype_map() const;
OddballType oddball_type() const;
@@ -550,12 +610,17 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
// Concerning the underlying instance_descriptors:
void SerializeOwnDescriptors();
void SerializeOwnDescriptor(int descriptor_index);
+ bool serialized_own_descriptor(int descriptor_index) const;
MapRef FindFieldOwner(int descriptor_index) const;
PropertyDetails GetPropertyDetails(int descriptor_index) const;
NameRef GetPropertyKey(int descriptor_index) const;
FieldIndex GetFieldIndexFor(int descriptor_index) const;
ObjectRef GetFieldType(int descriptor_index) const;
bool IsUnboxedDoubleField(int descriptor_index) const;
+ ObjectRef GetStrongValue(int descriptor_number) const;
+
+ void SerializeRootMap();
+ base::Optional<MapRef> FindRootMap() const;
// Available after calling JSFunctionRef::Serialize on a function that has
// this map as initial map.
@@ -574,7 +639,8 @@ struct HolderLookupResult {
class FunctionTemplateInfoRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(FunctionTemplateInfo, HeapObjectRef)
+
Handle<FunctionTemplateInfo> object() const;
bool is_signature_undefined() const;
@@ -585,21 +651,40 @@ class FunctionTemplateInfoRef : public HeapObjectRef {
void SerializeCallCode();
base::Optional<CallHandlerInfoRef> call_code() const;
- HolderLookupResult LookupHolderOfExpectedType(MapRef receiver_map,
- bool serialize);
+ HolderLookupResult LookupHolderOfExpectedType(
+ MapRef receiver_map,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
};
class FixedArrayBaseRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(FixedArrayBase, HeapObjectRef)
+
Handle<FixedArrayBase> object() const;
int length() const;
};
+class ArrayBoilerplateDescriptionRef : public HeapObjectRef {
+ public:
+ using HeapObjectRef::HeapObjectRef;
+ Handle<ArrayBoilerplateDescription> object() const;
+
+ int constants_elements_length() const;
+};
+
+class ObjectBoilerplateDescriptionRef : public HeapObjectRef {
+ public:
+ using HeapObjectRef::HeapObjectRef;
+ Handle<ObjectBoilerplateDescription> object() const;
+
+ int size() const;
+};
+
class FixedArrayRef : public FixedArrayBaseRef {
public:
- using FixedArrayBaseRef::FixedArrayBaseRef;
+ DEFINE_REF_CONSTRUCTOR(FixedArray, FixedArrayBaseRef)
+
Handle<FixedArray> object() const;
ObjectRef get(int i) const;
@@ -607,7 +692,8 @@ class FixedArrayRef : public FixedArrayBaseRef {
class FixedDoubleArrayRef : public FixedArrayBaseRef {
public:
- using FixedArrayBaseRef::FixedArrayBaseRef;
+ DEFINE_REF_CONSTRUCTOR(FixedDoubleArray, FixedArrayBaseRef)
+
Handle<FixedDoubleArray> object() const;
double get_scalar(int i) const;
@@ -616,7 +702,8 @@ class FixedDoubleArrayRef : public FixedArrayBaseRef {
class BytecodeArrayRef : public FixedArrayBaseRef {
public:
- using FixedArrayBaseRef::FixedArrayBaseRef;
+ DEFINE_REF_CONSTRUCTOR(BytecodeArray, FixedArrayBaseRef)
+
Handle<BytecodeArray> object() const;
int register_count() const;
@@ -646,20 +733,23 @@ class BytecodeArrayRef : public FixedArrayBaseRef {
class JSArrayRef : public JSObjectRef {
public:
- using JSObjectRef::JSObjectRef;
+ DEFINE_REF_CONSTRUCTOR(JSArray, JSObjectRef)
+
Handle<JSArray> object() const;
ObjectRef length() const;
// Return the element at key {index} if the array has a copy-on-write elements
// storage and {index} is known to be an own data property.
- base::Optional<ObjectRef> GetOwnCowElement(uint32_t index,
- bool serialize = false) const;
+ base::Optional<ObjectRef> GetOwnCowElement(
+ uint32_t index, SerializationPolicy policy =
+ SerializationPolicy::kAssumeSerialized) const;
};
class ScopeInfoRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(ScopeInfo, HeapObjectRef)
+
Handle<ScopeInfo> object() const;
int ContextLength() const;
@@ -683,7 +773,8 @@ class ScopeInfoRef : public HeapObjectRef {
class V8_EXPORT_PRIVATE SharedFunctionInfoRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(SharedFunctionInfo, HeapObjectRef)
+
Handle<SharedFunctionInfo> object() const;
int builtin_id() const;
@@ -699,8 +790,9 @@ class V8_EXPORT_PRIVATE SharedFunctionInfoRef : public HeapObjectRef {
// Template objects may not be created at compilation time. This method
// wraps the retrieval of the template object and creates it if
// necessary.
- JSArrayRef GetTemplateObject(ObjectRef description, FeedbackVectorRef vector,
- FeedbackSlot slot, bool serialize = false);
+ JSArrayRef GetTemplateObject(
+ ObjectRef description, FeedbackVectorRef vector, FeedbackSlot slot,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
void SerializeFunctionTemplateInfo();
base::Optional<FunctionTemplateInfoRef> function_template_info() const;
@@ -708,7 +800,8 @@ class V8_EXPORT_PRIVATE SharedFunctionInfoRef : public HeapObjectRef {
class StringRef : public NameRef {
public:
- using NameRef::NameRef;
+ DEFINE_REF_CONSTRUCTOR(String, NameRef)
+
Handle<String> object() const;
int length() const;
@@ -720,13 +813,15 @@ class StringRef : public NameRef {
class SymbolRef : public NameRef {
public:
- using NameRef::NameRef;
+ DEFINE_REF_CONSTRUCTOR(Symbol, NameRef)
+
Handle<Symbol> object() const;
};
class JSTypedArrayRef : public JSObjectRef {
public:
- using JSObjectRef::JSObjectRef;
+ DEFINE_REF_CONSTRUCTOR(JSTypedArray, JSObjectRef)
+
Handle<JSTypedArray> object() const;
bool is_on_heap() const;
@@ -741,25 +836,35 @@ class JSTypedArrayRef : public JSObjectRef {
class SourceTextModuleRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(SourceTextModule, HeapObjectRef)
+
Handle<SourceTextModule> object() const;
void Serialize();
- CellRef GetCell(int cell_index) const;
+ base::Optional<CellRef> GetCell(int cell_index) const;
};
class CellRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(Cell, HeapObjectRef)
+
Handle<Cell> object() const;
ObjectRef value() const;
};
+class JSGlobalObjectRef : public JSObjectRef {
+ public:
+ DEFINE_REF_CONSTRUCTOR(JSGlobalObject, JSObjectRef)
+
+ Handle<JSGlobalObject> object() const;
+};
+
class JSGlobalProxyRef : public JSObjectRef {
public:
- using JSObjectRef::JSObjectRef;
+ DEFINE_REF_CONSTRUCTOR(JSGlobalProxy, JSObjectRef)
+
Handle<JSGlobalProxy> object() const;
// If {serialize} is false:
@@ -769,135 +874,26 @@ class JSGlobalProxyRef : public JSObjectRef {
// If {serialize} is true:
// Like above but potentially access the heap and serialize the necessary
// information.
- base::Optional<PropertyCellRef> GetPropertyCell(NameRef const& name,
- bool serialize = false) const;
+ base::Optional<PropertyCellRef> GetPropertyCell(
+ NameRef const& name, SerializationPolicy policy =
+ SerializationPolicy::kAssumeSerialized) const;
};
class CodeRef : public HeapObjectRef {
public:
- using HeapObjectRef::HeapObjectRef;
+ DEFINE_REF_CONSTRUCTOR(Code, HeapObjectRef)
+
Handle<Code> object() const;
};
class InternalizedStringRef : public StringRef {
public:
- using StringRef::StringRef;
- Handle<InternalizedString> object() const;
-};
-
-class ElementAccessFeedback;
-class NamedAccessFeedback;
-
-class ProcessedFeedback : public ZoneObject {
- public:
- enum Kind { kInsufficient, kGlobalAccess, kNamedAccess, kElementAccess };
- Kind kind() const { return kind_; }
-
- ElementAccessFeedback const* AsElementAccess() const;
- NamedAccessFeedback const* AsNamedAccess() const;
-
- protected:
- explicit ProcessedFeedback(Kind kind) : kind_(kind) {}
-
- private:
- Kind const kind_;
-};
+ DEFINE_REF_CONSTRUCTOR(InternalizedString, StringRef)
-class InsufficientFeedback final : public ProcessedFeedback {
- public:
- InsufficientFeedback();
-};
-
-class GlobalAccessFeedback : public ProcessedFeedback {
- public:
- explicit GlobalAccessFeedback(PropertyCellRef cell);
- GlobalAccessFeedback(ContextRef script_context, int slot_index,
- bool immutable);
-
- bool IsPropertyCell() const;
- PropertyCellRef property_cell() const;
-
- bool IsScriptContextSlot() const { return !IsPropertyCell(); }
- ContextRef script_context() const;
- int slot_index() const;
- bool immutable() const;
-
- base::Optional<ObjectRef> GetConstantHint() const;
-
- private:
- ObjectRef const cell_or_context_;
- int const index_and_immutable_;
-};
-
-class KeyedAccessMode {
- public:
- static KeyedAccessMode FromNexus(FeedbackNexus const& nexus);
-
- AccessMode access_mode() const;
- bool IsLoad() const;
- bool IsStore() const;
- KeyedAccessLoadMode load_mode() const;
- KeyedAccessStoreMode store_mode() const;
-
- private:
- AccessMode const access_mode_;
- union LoadStoreMode {
- LoadStoreMode(KeyedAccessLoadMode load_mode);
- LoadStoreMode(KeyedAccessStoreMode store_mode);
- KeyedAccessLoadMode load_mode;
- KeyedAccessStoreMode store_mode;
- } const load_store_mode_;
-
- KeyedAccessMode(AccessMode access_mode, KeyedAccessLoadMode load_mode);
- KeyedAccessMode(AccessMode access_mode, KeyedAccessStoreMode store_mode);
-};
-
-class ElementAccessFeedback : public ProcessedFeedback {
- public:
- ElementAccessFeedback(Zone* zone, KeyedAccessMode const& keyed_mode);
-
- // No transition sources appear in {receiver_maps}.
- // All transition targets appear in {receiver_maps}.
- ZoneVector<Handle<Map>> receiver_maps;
- ZoneVector<std::pair<Handle<Map>, Handle<Map>>> transitions;
-
- KeyedAccessMode const keyed_mode;
-
- class MapIterator {
- public:
- bool done() const;
- void advance();
- MapRef current() const;
-
- private:
- friend class ElementAccessFeedback;
-
- explicit MapIterator(ElementAccessFeedback const& processed,
- JSHeapBroker* broker);
-
- ElementAccessFeedback const& processed_;
- JSHeapBroker* const broker_;
- size_t index_ = 0;
- };
-
- // Iterator over all maps: first {receiver_maps}, then transition sources.
- MapIterator all_maps(JSHeapBroker* broker) const;
+ Handle<InternalizedString> object() const;
};
-class NamedAccessFeedback : public ProcessedFeedback {
- public:
- NamedAccessFeedback(NameRef const& name,
- ZoneVector<PropertyAccessInfo> const& access_infos);
-
- NameRef const& name() const { return name_; }
- ZoneVector<PropertyAccessInfo> const& access_infos() const {
- return access_infos_;
- }
-
- private:
- NameRef const name_;
- ZoneVector<PropertyAccessInfo> const access_infos_;
-};
+#undef DEFINE_REF_CONSTRUCTOR
} // namespace compiler
} // namespace internal
diff --git a/deps/v8/src/compiler/int64-lowering.cc b/deps/v8/src/compiler/int64-lowering.cc
index eda866e5f2..45b49757fb 100644
--- a/deps/v8/src/compiler/int64-lowering.cc
+++ b/deps/v8/src/compiler/int64-lowering.cc
@@ -21,9 +21,11 @@ namespace v8 {
namespace internal {
namespace compiler {
-Int64Lowering::Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
- CommonOperatorBuilder* common, Zone* zone,
- Signature<MachineRepresentation>* signature)
+Int64Lowering::Int64Lowering(
+ Graph* graph, MachineOperatorBuilder* machine,
+ CommonOperatorBuilder* common, Zone* zone,
+ Signature<MachineRepresentation>* signature,
+ std::unique_ptr<Int64LoweringSpecialCase> special_case)
: zone_(zone),
graph_(graph),
machine_(machine),
@@ -32,8 +34,9 @@ Int64Lowering::Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
stack_(zone),
replacements_(nullptr),
signature_(signature),
- placeholder_(graph->NewNode(common->Parameter(-2, "placeholder"),
- graph->start())) {
+ placeholder_(
+ graph->NewNode(common->Parameter(-2, "placeholder"), graph->start())),
+ special_case_(std::move(special_case)) {
DCHECK_NOT_NULL(graph);
DCHECK_NOT_NULL(graph->end());
replacements_ = zone->NewArray<Replacement>(graph->NodeCount());
@@ -77,7 +80,7 @@ void Int64Lowering::LowerGraph() {
namespace {
-int GetReturnIndexAfterLowering(CallDescriptor* call_descriptor,
+int GetReturnIndexAfterLowering(const CallDescriptor* call_descriptor,
int old_index) {
int result = old_index;
for (int i = 0; i < old_index; i++) {
@@ -89,7 +92,7 @@ int GetReturnIndexAfterLowering(CallDescriptor* call_descriptor,
return result;
}
-int GetReturnCountAfterLowering(CallDescriptor* call_descriptor) {
+int GetReturnCountAfterLowering(const CallDescriptor* call_descriptor) {
return GetReturnIndexAfterLowering(
call_descriptor, static_cast<int>(call_descriptor->ReturnCount()));
}
@@ -336,21 +339,21 @@ void Int64Lowering::LowerNode(Node* node) {
if (DefaultLowering(node) || returns_require_lowering) {
// Tail calls do not have return values, so adjusting the call
// descriptor is enough.
- auto new_descriptor = GetI32WasmCallDescriptor(zone(), call_descriptor);
- NodeProperties::ChangeOp(node, common()->TailCall(new_descriptor));
+ NodeProperties::ChangeOp(
+ node, common()->TailCall(LowerCallDescriptor(call_descriptor)));
}
break;
}
case IrOpcode::kCall: {
- auto call_descriptor =
- const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
+ auto call_descriptor = CallDescriptorOf(node->op());
+
bool returns_require_lowering =
GetReturnCountAfterLowering(call_descriptor) !=
static_cast<int>(call_descriptor->ReturnCount());
if (DefaultLowering(node) || returns_require_lowering) {
// We have to adjust the call descriptor.
- NodeProperties::ChangeOp(node, common()->Call(GetI32WasmCallDescriptor(
- zone(), call_descriptor)));
+ NodeProperties::ChangeOp(
+ node, common()->Call(LowerCallDescriptor(call_descriptor)));
}
if (returns_require_lowering) {
size_t return_arity = call_descriptor->ReturnCount();
@@ -994,6 +997,19 @@ bool Int64Lowering::DefaultLowering(Node* node, bool low_word_only) {
return something_changed;
}
+CallDescriptor* Int64Lowering::LowerCallDescriptor(
+ const CallDescriptor* call_descriptor) {
+ if (special_case_) {
+ if (call_descriptor == special_case_->bigint_to_i64_call_descriptor) {
+ return special_case_->bigint_to_i32_pair_call_descriptor;
+ }
+ if (call_descriptor == special_case_->i64_to_bigint_call_descriptor) {
+ return special_case_->i32_pair_to_bigint_call_descriptor;
+ }
+ }
+ return GetI32WasmCallDescriptor(zone(), call_descriptor);
+}
+
void Int64Lowering::ReplaceNode(Node* old, Node* new_low, Node* new_high) {
// if new_low == nullptr, then also new_high == nullptr.
DCHECK(new_low != nullptr || new_high == nullptr);
diff --git a/deps/v8/src/compiler/int64-lowering.h b/deps/v8/src/compiler/int64-lowering.h
index 9c77cf41a3..1e2a36089b 100644
--- a/deps/v8/src/compiler/int64-lowering.h
+++ b/deps/v8/src/compiler/int64-lowering.h
@@ -20,11 +20,30 @@ class Signature;
namespace compiler {
+// Struct for CallDescriptors that need special lowering.
+struct V8_EXPORT_PRIVATE Int64LoweringSpecialCase {
+ Int64LoweringSpecialCase()
+ : bigint_to_i64_call_descriptor(nullptr),
+ i64_to_bigint_call_descriptor(nullptr),
+ bigint_to_i32_pair_call_descriptor(nullptr),
+ i32_pair_to_bigint_call_descriptor(nullptr) {}
+
+ // CallDescriptors that need special lowering.
+ CallDescriptor* bigint_to_i64_call_descriptor;
+ CallDescriptor* i64_to_bigint_call_descriptor;
+
+ // The replacement CallDescriptors.
+ CallDescriptor* bigint_to_i32_pair_call_descriptor;
+ CallDescriptor* i32_pair_to_bigint_call_descriptor;
+};
+
class V8_EXPORT_PRIVATE Int64Lowering {
public:
- Int64Lowering(Graph* graph, MachineOperatorBuilder* machine,
- CommonOperatorBuilder* common, Zone* zone,
- Signature<MachineRepresentation>* signature);
+ Int64Lowering(
+ Graph* graph, MachineOperatorBuilder* machine,
+ CommonOperatorBuilder* common, Zone* zone,
+ Signature<MachineRepresentation>* signature,
+ std::unique_ptr<Int64LoweringSpecialCase> special_case = nullptr);
void LowerGraph();
@@ -53,6 +72,8 @@ class V8_EXPORT_PRIVATE Int64Lowering {
void LowerWord64AtomicBinop(Node* node, const Operator* op);
void LowerWord64AtomicNarrowOp(Node* node, const Operator* op);
+ CallDescriptor* LowerCallDescriptor(const CallDescriptor* call_descriptor);
+
void ReplaceNode(Node* old, Node* new_low, Node* new_high);
bool HasReplacementLow(Node* node);
Node* GetReplacementLow(Node* node);
@@ -77,6 +98,7 @@ class V8_EXPORT_PRIVATE Int64Lowering {
Replacement* replacements_;
Signature<MachineRepresentation>* signature_;
Node* placeholder_;
+ std::unique_ptr<Int64LoweringSpecialCase> special_case_;
};
} // namespace compiler
diff --git a/deps/v8/src/compiler/js-call-reducer.cc b/deps/v8/src/compiler/js-call-reducer.cc
index 8128f89949..0b7b4a65f4 100644
--- a/deps/v8/src/compiler/js-call-reducer.cc
+++ b/deps/v8/src/compiler/js-call-reducer.cc
@@ -14,6 +14,7 @@
#include "src/compiler/access-info.h"
#include "src/compiler/allocation-builder.h"
#include "src/compiler/compilation-dependencies.h"
+#include "src/compiler/feedback-source.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/map-inference.h"
@@ -21,7 +22,6 @@
#include "src/compiler/property-access-builder.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/type-cache.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/ic/call-optimization.h"
#include "src/logging/counters.h"
#include "src/objects/arguments-inl.h"
@@ -179,101 +179,9 @@ Reduction JSCallReducer::ReduceMathMinMax(Node* node, const Operator* op,
return Replace(value);
}
-// ES section #sec-math.hypot Math.hypot ( value1, value2, ...values )
-Reduction JSCallReducer::ReduceMathHypot(Node* node) {
- CallParameters const& p = CallParametersOf(node->op());
- if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
- return NoChange();
- }
- if (node->op()->ValueInputCount() < 3) {
- Node* value = jsgraph()->ZeroConstant();
- ReplaceWithValue(node, value);
- return Replace(value);
- }
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* control = NodeProperties::GetControlInput(node);
- NodeVector values(graph()->zone());
-
- Node* max = effect =
- graph()->NewNode(simplified()->SpeculativeToNumber(
- NumberOperationHint::kNumberOrOddball, p.feedback()),
- NodeProperties::GetValueInput(node, 2), effect, control);
- max = graph()->NewNode(simplified()->NumberAbs(), max);
- values.push_back(max);
- for (int i = 3; i < node->op()->ValueInputCount(); ++i) {
- Node* input = effect = graph()->NewNode(
- simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
- p.feedback()),
- NodeProperties::GetValueInput(node, i), effect, control);
- input = graph()->NewNode(simplified()->NumberAbs(), input);
- values.push_back(input);
-
- // Make sure {max} is NaN in the end in case any argument was NaN.
- max = graph()->NewNode(
- common()->Select(MachineRepresentation::kTagged),
- graph()->NewNode(simplified()->NumberLessThanOrEqual(), input, max),
- max, input);
- }
-
- Node* check0 = graph()->NewNode(simplified()->NumberEqual(), max,
- jsgraph()->ZeroConstant());
- Node* branch0 =
- graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
-
- Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
- Node* vtrue0 = jsgraph()->ZeroConstant();
-
- Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
- Node* vfalse0;
- {
- Node* check1 = graph()->NewNode(simplified()->NumberEqual(), max,
- jsgraph()->Constant(V8_INFINITY));
- Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
- check1, if_false0);
-
- Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
- Node* vtrue1 = jsgraph()->Constant(V8_INFINITY);
-
- Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
- Node* vfalse1;
- {
- // Kahan summation to avoid rounding errors.
- // Normalize the numbers to the largest one to avoid overflow.
- Node* sum = jsgraph()->ZeroConstant();
- Node* compensation = jsgraph()->ZeroConstant();
- for (Node* value : values) {
- Node* n = graph()->NewNode(simplified()->NumberDivide(), value, max);
- Node* summand = graph()->NewNode(
- simplified()->NumberSubtract(),
- graph()->NewNode(simplified()->NumberMultiply(), n, n),
- compensation);
- Node* preliminary =
- graph()->NewNode(simplified()->NumberAdd(), sum, summand);
- compensation = graph()->NewNode(
- simplified()->NumberSubtract(),
- graph()->NewNode(simplified()->NumberSubtract(), preliminary, sum),
- summand);
- sum = preliminary;
- }
- vfalse1 = graph()->NewNode(
- simplified()->NumberMultiply(),
- graph()->NewNode(simplified()->NumberSqrt(), sum), max);
- }
-
- if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
- vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
- vtrue1, vfalse1, if_false0);
- }
-
- control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
- Node* value =
- graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), vtrue0,
- vfalse0, control);
- ReplaceWithValue(node, value, effect, control);
- return Replace(value);
-}
-
Reduction JSCallReducer::Reduce(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
switch (node->opcode()) {
case IrOpcode::kJSConstruct:
return ReduceJSConstruct(node);
@@ -313,6 +221,8 @@ void JSCallReducer::Finalize() {
// ES6 section 22.1.1 The Array Constructor
Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* target = NodeProperties::GetValueInput(node, 0);
CallParameters const& p = CallParametersOf(node->op());
@@ -480,14 +390,11 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
// TODO(mslekova): Since this introduces a Call that will get optimized by
// the JSCallReducer, we basically might have to do all the serialization
// that we do for that here as well. The only difference is that here we
- // disable speculation (cf. the empty VectorSlotPair above), causing the
+ // disable speculation (cf. the empty FeedbackSource above), causing the
// JSCallReducer to do much less work. We should revisit this later.
NodeProperties::ChangeOp(
node,
- javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode));
- // TODO(mslekova): Remove once ReduceJSCall is brokerized.
- AllowHandleDereference allow_handle_dereference;
- AllowHandleAllocation allow_handle_allocation;
+ javascript()->Call(arity, p.frequency(), FeedbackSource(), convert_mode));
// Try to further reduce the JSCall {node}.
Reduction const reduction = ReduceJSCall(node);
return reduction.Changed() ? reduction : Changed(node);
@@ -495,6 +402,8 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
// ES section #sec-function.prototype.bind
Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
+ DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
+
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
@@ -506,7 +415,7 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
// - target, which is Function.prototype.bind JSFunction
// - receiver, which is the [[BoundTargetFunction]]
// - bound_this (optional), which is the [[BoundThis]]
- // - and all the remaining value inouts are [[BoundArguments]]
+ // - and all the remaining value inputs are [[BoundArguments]]
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* bound_this = (node->op()->ValueInputCount() < 3)
? jsgraph()->UndefinedConstant()
@@ -525,14 +434,24 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
MapRef first_receiver_map(broker(), receiver_maps[0]);
bool const is_constructor = first_receiver_map.is_constructor();
- first_receiver_map.SerializePrototype();
+
+ if (FLAG_concurrent_inlining && !first_receiver_map.serialized_prototype()) {
+ TRACE_BROKER_MISSING(broker(),
+ "serialized prototype on map " << first_receiver_map);
+ return inference.NoChange();
+ }
ObjectRef const prototype = first_receiver_map.prototype();
for (Handle<Map> const map : receiver_maps) {
MapRef receiver_map(broker(), map);
+ if (FLAG_concurrent_inlining && !receiver_map.serialized_prototype()) {
+ TRACE_BROKER_MISSING(broker(),
+ "serialized prototype on map " << receiver_map);
+ return inference.NoChange();
+ }
+
// Check for consistency among the {receiver_maps}.
STATIC_ASSERT(LAST_TYPE == LAST_FUNCTION_TYPE);
- receiver_map.SerializePrototype();
if (!receiver_map.prototype().equals(prototype) ||
receiver_map.is_constructor() != is_constructor ||
receiver_map.instance_type() < FIRST_FUNCTION_TYPE) {
@@ -548,22 +467,31 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
// recomputed even if the actual value of the object changes.
// This mirrors the checks done in builtins-function-gen.cc at
// runtime otherwise.
- Handle<DescriptorArray> descriptors(
- receiver_map.object()->instance_descriptors(), isolate());
- if (descriptors->number_of_descriptors() < 2) return inference.NoChange();
- if (descriptors->GetKey(JSFunction::kLengthDescriptorIndex) !=
- ReadOnlyRoots(isolate()).length_string()) {
- return inference.NoChange();
- }
- if (!descriptors->GetStrongValue(JSFunction::kLengthDescriptorIndex)
- .IsAccessorInfo()) {
+ int minimum_nof_descriptors = i::Max(JSFunction::kLengthDescriptorIndex,
+ JSFunction::kNameDescriptorIndex) +
+ 1;
+ if (receiver_map.NumberOfOwnDescriptors() < minimum_nof_descriptors) {
return inference.NoChange();
}
- if (descriptors->GetKey(JSFunction::kNameDescriptorIndex) !=
- ReadOnlyRoots(isolate()).name_string()) {
+ if (!receiver_map.serialized_own_descriptor(
+ JSFunction::kLengthDescriptorIndex) ||
+ !receiver_map.serialized_own_descriptor(
+ JSFunction::kNameDescriptorIndex)) {
+ TRACE_BROKER_MISSING(broker(),
+ "serialized descriptors on map " << receiver_map);
return inference.NoChange();
}
- if (!descriptors->GetStrongValue(JSFunction::kNameDescriptorIndex)
+ ReadOnlyRoots roots(isolate());
+ StringRef length_string(broker(), roots.length_string_handle());
+ StringRef name_string(broker(), roots.name_string_handle());
+
+ if (!receiver_map.GetPropertyKey(JSFunction::kLengthDescriptorIndex)
+ .equals(length_string) ||
+ !receiver_map.GetStrongValue(JSFunction::kLengthDescriptorIndex)
+ .IsAccessorInfo() ||
+ !receiver_map.GetPropertyKey(JSFunction::kNameDescriptorIndex)
+ .equals(name_string) ||
+ !receiver_map.GetStrongValue(JSFunction::kNameDescriptorIndex)
.IsAccessorInfo()) {
return inference.NoChange();
}
@@ -646,10 +574,7 @@ Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
}
NodeProperties::ChangeOp(
node,
- javascript()->Call(arity, p.frequency(), VectorSlotPair(), convert_mode));
- // TODO(mslekova): Remove once ReduceJSCall is brokerized.
- AllowHandleDereference allow_handle_dereference;
- AllowHandleAllocation allow_handle_allocation;
+ javascript()->Call(arity, p.frequency(), FeedbackSource(), convert_mode));
// Try to further reduce the JSCall {node}.
Reduction const reduction = ReduceJSCall(node);
return reduction.Changed() ? reduction : Changed(node);
@@ -693,13 +618,19 @@ Reduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) {
MapHandles const& object_maps = inference.GetMaps();
MapRef candidate_map(broker(), object_maps[0]);
- candidate_map.SerializePrototype();
+ if (FLAG_concurrent_inlining && !candidate_map.serialized_prototype()) {
+ TRACE_BROKER_MISSING(broker(), "prototype for map " << candidate_map);
+ return inference.NoChange();
+ }
ObjectRef candidate_prototype = candidate_map.prototype();
// Check if we can constant-fold the {candidate_prototype}.
for (size_t i = 0; i < object_maps.size(); ++i) {
MapRef object_map(broker(), object_maps[i]);
- object_map.SerializePrototype();
+ if (FLAG_concurrent_inlining && !object_map.serialized_prototype()) {
+ TRACE_BROKER_MISSING(broker(), "prototype for map " << object_map);
+ return inference.NoChange();
+ }
if (IsSpecialReceiverInstanceType(object_map.instance_type()) ||
!object_map.prototype().equals(candidate_prototype)) {
// We exclude special receivers, like JSProxy or API objects that
@@ -830,6 +761,8 @@ Reduction JSCallReducer::ReduceObjectPrototypeHasOwnProperty(Node* node) {
// ES #sec-object.prototype.isprototypeof
Reduction JSCallReducer::ReduceObjectPrototypeIsPrototypeOf(Node* node) {
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
+
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* value = node->op()->ValueInputCount() > 2
@@ -1048,7 +981,7 @@ Reduction JSCallReducer::ReduceReflectHas(Node* node) {
{
// TODO(magardn): collect feedback so this can be optimized
vtrue = etrue = if_true =
- graph()->NewNode(javascript()->HasProperty(VectorSlotPair()), target,
+ graph()->NewNode(javascript()->HasProperty(FeedbackSource()), target,
key, context, frame_state, etrue, if_true);
}
@@ -1114,10 +1047,10 @@ bool CanInlineArrayIteratingBuiltin(JSHeapBroker* broker,
return true;
}
-bool CanInlineArrayResizingBuiltin(
- JSHeapBroker* broker, MapHandles const& receiver_maps,
- std::vector<ElementsKind>& kinds, // NOLINT(runtime/references)
- bool builtin_is_push = false) {
+bool CanInlineArrayResizingBuiltin(JSHeapBroker* broker,
+ MapHandles const& receiver_maps,
+ std::vector<ElementsKind>* kinds,
+ bool builtin_is_push = false) {
DCHECK_NE(0, receiver_maps.size());
for (auto receiver_map : receiver_maps) {
MapRef map(broker, receiver_map);
@@ -1128,14 +1061,14 @@ bool CanInlineArrayResizingBuiltin(
return false;
}
ElementsKind current_kind = map.elements_kind();
- auto kind_ptr = kinds.data();
+ auto kind_ptr = kinds->data();
size_t i;
- for (i = 0; i < kinds.size(); i++, kind_ptr++) {
+ for (i = 0; i < kinds->size(); i++, kind_ptr++) {
if (UnionElementsKindUptoPackedness(kind_ptr, current_kind)) {
break;
}
}
- if (i == kinds.size()) kinds.push_back(current_kind);
+ if (i == kinds->size()) kinds->push_back(current_kind);
}
return true;
}
@@ -1143,6 +1076,8 @@ bool CanInlineArrayResizingBuiltin(
Reduction JSCallReducer::ReduceArrayForEach(
Node* node, const SharedFunctionInfoRef& shared) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -1309,6 +1244,8 @@ Reduction JSCallReducer::ReduceArrayForEach(
Reduction JSCallReducer::ReduceArrayReduce(
Node* node, ArrayReduceDirection direction,
const SharedFunctionInfoRef& shared) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -1567,6 +1504,8 @@ Reduction JSCallReducer::ReduceArrayReduce(
Reduction JSCallReducer::ReduceArrayMap(Node* node,
const SharedFunctionInfoRef& shared) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -1759,6 +1698,8 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
Reduction JSCallReducer::ReduceArrayFilter(
Node* node, const SharedFunctionInfoRef& shared) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -1809,7 +1750,8 @@ Reduction JSCallReducer::ReduceArrayFilter(
Type::Array());
ab.Store(AccessBuilder::ForMap(), initial_map);
Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
- ab.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), empty_fixed_array);
+ ab.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ empty_fixed_array);
ab.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
ab.Store(AccessBuilder::ForJSArrayLength(packed_kind),
jsgraph()->ZeroConstant());
@@ -1998,6 +1940,8 @@ Reduction JSCallReducer::ReduceArrayFilter(
Reduction JSCallReducer::ReduceArrayFind(Node* node, ArrayFindVariant variant,
const SharedFunctionInfoRef& shared) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -2218,7 +2162,7 @@ Node* JSCallReducer::DoFilterPostCallbackWork(ElementsKind kind, Node** control,
IsDoubleElementsKind(kind) ? GrowFastElementsMode::kDoubleElements
: GrowFastElementsMode::kSmiOrObjectElements;
elements = etrue = graph()->NewNode(
- simplified()->MaybeGrowFastElements(mode, VectorSlotPair()), a,
+ simplified()->MaybeGrowFastElements(mode, FeedbackSource()), a,
elements, checked_to, elements_length, etrue, if_true);
// Update the length of {a}.
@@ -2288,7 +2232,7 @@ void JSCallReducer::RewirePostCallbackExceptionEdges(Node* check_throw,
Node* JSCallReducer::SafeLoadElement(ElementsKind kind, Node* receiver,
Node* control, Node** effect, Node** k,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
// Make sure that the access is still in bounds, since the callback could
// have changed the array's size.
Node* length = *effect = graph()->NewNode(
@@ -2313,6 +2257,8 @@ Node* JSCallReducer::SafeLoadElement(ElementsKind kind, Node* receiver,
Reduction JSCallReducer::ReduceArrayEvery(Node* node,
const SharedFunctionInfoRef& shared) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -2567,6 +2513,8 @@ Callable GetCallableForArrayIncludes(ElementsKind elements_kind,
// #sec-array.prototype.includes
Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
SearchVariant search_variant, Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
@@ -2638,6 +2586,8 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
Reduction JSCallReducer::ReduceArraySome(Node* node,
const SharedFunctionInfoRef& shared) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -2906,8 +2856,7 @@ Reduction JSCallReducer::ReduceCallApiFunction(
// See if we can constant-fold the compatible receiver checks.
HolderLookupResult api_holder =
- function_template_info.LookupHolderOfExpectedType(first_receiver_map,
- false);
+ function_template_info.LookupHolderOfExpectedType(first_receiver_map);
if (api_holder.lookup == CallOptimization::kHolderNotFound)
return inference.NoChange();
@@ -2937,8 +2886,7 @@ Reduction JSCallReducer::ReduceCallApiFunction(
for (size_t i = 1; i < receiver_maps.size(); ++i) {
MapRef receiver_map(broker(), receiver_maps[i]);
HolderLookupResult holder_i =
- function_template_info.LookupHolderOfExpectedType(receiver_map,
- false);
+ function_template_info.LookupHolderOfExpectedType(receiver_map);
if (api_holder.lookup != holder_i.lookup) return inference.NoChange();
if (!(api_holder.holder.has_value() && holder_i.holder.has_value()))
@@ -3059,7 +3007,7 @@ bool IsSafeArgumentsElements(Node* node) {
Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
Node* node, int arity, CallFrequency const& frequency,
- VectorSlotPair const& feedback) {
+ FeedbackSource const& feedback) {
DCHECK(node->opcode() == IrOpcode::kJSCallWithArrayLike ||
node->opcode() == IrOpcode::kJSCallWithSpread ||
node->opcode() == IrOpcode::kJSConstructWithArrayLike ||
@@ -3285,13 +3233,6 @@ bool ShouldUseCallICFeedback(Node* node) {
return true;
}
-base::Optional<HeapObjectRef> GetHeapObjectFeedback(
- JSHeapBroker* broker, const FeedbackNexus& nexus) {
- HeapObject object;
- if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
- return HeapObjectRef(broker, handle(object, broker->isolate()));
-}
-
} // namespace
Reduction JSCallReducer::ReduceJSCall(Node* node) {
@@ -3309,7 +3250,10 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
ObjectRef target_ref = m.Ref(broker());
if (target_ref.IsJSFunction()) {
JSFunctionRef function = target_ref.AsJSFunction();
- function.Serialize();
+ if (FLAG_concurrent_inlining && !function.serialized()) {
+ TRACE_BROKER_MISSING(broker(), "data for function " << function);
+ return NoChange();
+ }
// Don't inline cross native context.
if (!function.native_context().equals(native_context())) {
@@ -3319,7 +3263,10 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return ReduceJSCall(node, function.shared());
} else if (target_ref.IsJSBoundFunction()) {
JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
- function.Serialize();
+ if (FLAG_concurrent_inlining && !function.serialized()) {
+ TRACE_BROKER_MISSING(broker(), "data for function " << function);
+ return NoChange();
+ }
ObjectRef bound_this = function.bound_this();
ConvertReceiverMode const convert_mode =
@@ -3342,7 +3289,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
}
NodeProperties::ChangeOp(
- node, javascript()->Call(arity, p.frequency(), VectorSlotPair(),
+ node, javascript()->Call(arity, p.frequency(), FeedbackSource(),
convert_mode));
// Try to further reduce the JSCall {node}.
@@ -3390,7 +3337,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
? ConvertReceiverMode::kAny
: ConvertReceiverMode::kNotNullOrUndefined;
NodeProperties::ChangeOp(
- node, javascript()->Call(arity, p.frequency(), VectorSlotPair(),
+ node, javascript()->Call(arity, p.frequency(), FeedbackSource(),
convert_mode));
// Try to further reduce the JSCall {node}.
@@ -3398,19 +3345,18 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return reduction.Changed() ? reduction : Changed(node);
}
- // Extract feedback from the {node} using the FeedbackNexus.
if (!p.feedback().IsValid()) return NoChange();
- FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
- if (nexus.IsUninitialized()) {
+ ProcessedFeedback const& feedback =
+ broker()->GetFeedbackForCall(FeedbackSource(p.feedback()));
+ if (feedback.IsInsufficient()) {
return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForCall);
}
- base::Optional<HeapObjectRef> feedback =
- GetHeapObjectFeedback(broker(), nexus);
- if (feedback.has_value() && ShouldUseCallICFeedback(target) &&
- feedback->map().is_callable()) {
- Node* target_function = jsgraph()->Constant(*feedback);
+ base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target();
+ if (feedback_target.has_value() && ShouldUseCallICFeedback(target) &&
+ feedback_target->map().is_callable()) {
+ Node* target_function = jsgraph()->Constant(*feedback_target);
// Check that the {target} is still the {target_function}.
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
@@ -3630,8 +3576,6 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
return ReduceMathUnary(node, simplified()->NumberFloor());
case Builtins::kMathFround:
return ReduceMathUnary(node, simplified()->NumberFround());
- case Builtins::kMathHypot:
- return ReduceMathHypot(node);
case Builtins::kMathLog:
return ReduceMathUnary(node, simplified()->NumberLog());
case Builtins::kMathLog1p:
@@ -3785,22 +3729,17 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
break;
}
- if (shared.object()->IsApiFunction()) {
+ if (shared.function_template_info().has_value()) {
return ReduceCallApiFunction(node, shared);
}
return NoChange();
}
Reduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) {
- // TODO(mslekova): Remove once ReduceJSCallWithArrayLike is brokerized.
- AllowHandleDereference allow_handle_dereference;
- AllowHandleAllocation allow_handle_allocation;
-
DCHECK_EQ(IrOpcode::kJSCallWithArrayLike, node->opcode());
CallFrequency frequency = CallFrequencyOf(node->op());
- VectorSlotPair feedback;
return ReduceCallOrConstructWithArrayLikeOrSpread(node, 2, frequency,
- feedback);
+ FeedbackSource());
}
Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
@@ -3809,7 +3748,7 @@ Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
DCHECK_LE(3u, p.arity());
int arity = static_cast<int>(p.arity() - 1);
CallFrequency frequency = p.frequency();
- VectorSlotPair feedback = p.feedback();
+ FeedbackSource feedback = p.feedback();
return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency,
feedback);
}
@@ -3824,17 +3763,16 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- // Extract feedback from the {node} using the FeedbackNexus.
if (p.feedback().IsValid()) {
- FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
- if (nexus.IsUninitialized()) {
+ ProcessedFeedback const& feedback =
+ broker()->GetFeedbackForCall(p.feedback());
+ if (feedback.IsInsufficient()) {
return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct);
}
- base::Optional<HeapObjectRef> feedback =
- GetHeapObjectFeedback(broker(), nexus);
- if (feedback.has_value() && feedback->IsAllocationSite()) {
+ base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target();
+ if (feedback_target.has_value() && feedback_target->IsAllocationSite()) {
// The feedback is an AllocationSite, which means we have called the
// Array function and collected transition (and pretenuring) feedback
// for the resulting arrays. This has to be kept in sync with the
@@ -3859,12 +3797,12 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
NodeProperties::ReplaceValueInput(node, array_function, 1);
NodeProperties::ChangeOp(
node, javascript()->CreateArray(
- arity, feedback->AsAllocationSite().object()));
+ arity, feedback_target->AsAllocationSite().object()));
return Changed(node);
- } else if (feedback.has_value() &&
+ } else if (feedback_target.has_value() &&
!HeapObjectMatcher(new_target).HasValue() &&
- feedback->map().is_constructor()) {
- Node* new_target_feedback = jsgraph()->Constant(*feedback);
+ feedback_target->map().is_constructor()) {
+ Node* new_target_feedback = jsgraph()->Constant(*feedback_target);
// Check that the {new_target} is still the {new_target_feedback}.
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), new_target,
@@ -3902,7 +3840,11 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
if (target_ref.IsJSFunction()) {
JSFunctionRef function = target_ref.AsJSFunction();
- function.Serialize();
+ if (FLAG_concurrent_inlining && !function.serialized()) {
+ TRACE_BROKER_MISSING(broker(),
+ "function, not serialized: " << function);
+ return NoChange();
+ }
// Do not reduce constructors with break points.
if (function.shared().HasBreakInfo()) return NoChange();
@@ -3959,7 +3901,11 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
}
} else if (target_ref.IsJSBoundFunction()) {
JSBoundFunctionRef function = target_ref.AsJSBoundFunction();
- function.Serialize();
+ if (FLAG_concurrent_inlining && !function.serialized()) {
+ TRACE_BROKER_MISSING(broker(),
+ "function, not serialized: " << function);
+ return NoChange();
+ }
ObjectRef bound_target_function = function.bound_target_function();
FixedArrayRef bound_arguments = function.bound_arguments();
@@ -3989,7 +3935,7 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
// Update the JSConstruct operator on {node}.
NodeProperties::ChangeOp(
node,
- javascript()->Construct(arity + 2, p.frequency(), VectorSlotPair()));
+ javascript()->Construct(arity + 2, p.frequency(), FeedbackSource()));
// Try to further reduce the JSConstruct {node}.
Reduction const reduction = ReduceJSConstruct(node);
@@ -4030,7 +3976,7 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
// Update the JSConstruct operator on {node}.
NodeProperties::ChangeOp(
node,
- javascript()->Construct(arity + 2, p.frequency(), VectorSlotPair()));
+ javascript()->Construct(arity + 2, p.frequency(), FeedbackSource()));
// Try to further reduce the JSConstruct {node}.
Reduction const reduction = ReduceJSConstruct(node);
@@ -4350,9 +4296,8 @@ Reduction JSCallReducer::ReduceStringPrototypeSubstr(Node* node) {
Reduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) {
DCHECK_EQ(IrOpcode::kJSConstructWithArrayLike, node->opcode());
CallFrequency frequency = CallFrequencyOf(node->op());
- VectorSlotPair feedback;
return ReduceCallOrConstructWithArrayLikeOrSpread(node, 1, frequency,
- feedback);
+ FeedbackSource());
}
Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
@@ -4361,7 +4306,7 @@ Reduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) {
DCHECK_LE(3u, p.arity());
int arity = static_cast<int>(p.arity() - 2);
CallFrequency frequency = p.frequency();
- VectorSlotPair feedback = p.feedback();
+ FeedbackSource feedback = p.feedback();
return ReduceCallOrConstructWithArrayLikeOrSpread(node, arity, frequency,
feedback);
}
@@ -4382,7 +4327,7 @@ Reduction JSCallReducer::ReduceSoftDeoptimize(Node* node,
Node* frame_state =
NodeProperties::FindFrameStateBefore(node, jsgraph()->Dead());
Node* deoptimize = graph()->NewNode(
- common()->Deoptimize(DeoptimizeKind::kSoft, reason, VectorSlotPair()),
+ common()->Deoptimize(DeoptimizeKind::kSoft, reason, FeedbackSource()),
frame_state, effect, control);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
@@ -4440,6 +4385,8 @@ void JSCallReducer::CheckIfElementsKind(Node* receiver_elements_kind,
// ES6 section 22.1.3.18 Array.prototype.push ( )
Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
@@ -4456,7 +4403,7 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
MapHandles const& receiver_maps = inference.GetMaps();
std::vector<ElementsKind> kinds;
- if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, kinds, true)) {
+ if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds, true)) {
return inference.NoChange();
}
if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE();
@@ -4574,6 +4521,8 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
// ES6 section 22.1.3.17 Array.prototype.pop ( )
Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
@@ -4589,7 +4538,7 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
MapHandles const& receiver_maps = inference.GetMaps();
std::vector<ElementsKind> kinds;
- if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, kinds)) {
+ if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds)) {
return inference.NoChange();
}
if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE();
@@ -4707,6 +4656,8 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
// ES6 section 22.1.3.22 Array.prototype.shift ( )
Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
@@ -4725,7 +4676,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
MapHandles const& receiver_maps = inference.GetMaps();
std::vector<ElementsKind> kinds;
- if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, kinds)) {
+ if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds)) {
return inference.NoChange();
}
if (!dependencies()->DependOnNoElementsProtector()) UNREACHABLE();
@@ -4923,6 +4874,8 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
// ES6 section 22.1.3.23 Array.prototype.slice ( )
Reduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -4999,6 +4952,8 @@ Reduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) {
// ES6 section 22.1.2.2 Array.isArray ( arg )
Reduction JSCallReducer::ReduceArrayIsArray(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
// We certainly know that undefined is not an array.
if (node->op()->ValueInputCount() < 3) {
Node* value = jsgraph()->FalseConstant();
@@ -5022,6 +4977,8 @@ Reduction JSCallReducer::ReduceArrayIsArray(Node* node) {
}
Reduction JSCallReducer::ReduceArrayIterator(Node* node, IterationKind kind) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* context = NodeProperties::GetContextInput(node);
@@ -5047,6 +5004,8 @@ Reduction JSCallReducer::ReduceArrayIterator(Node* node, IterationKind kind) {
// ES #sec-%arrayiteratorprototype%.next
Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
Node* iterator = NodeProperties::GetValueInput(node, 1);
@@ -5681,10 +5640,14 @@ Node* JSCallReducer::CreateArtificialFrameState(
bailout_id, OutputFrameStateCombine::Ignore(), state_info);
const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense());
Node* node0 = graph()->NewNode(op0);
+
+ static constexpr int kTargetInputIndex = 0;
+ static constexpr int kReceiverInputIndex = 1;
+ const int parameter_count_with_receiver = parameter_count + 1;
std::vector<Node*> params;
- params.reserve(parameter_count + 1);
- for (int parameter = 0; parameter < parameter_count + 1; ++parameter) {
- params.push_back(node->InputAt(1 + parameter));
+ params.reserve(parameter_count_with_receiver);
+ for (int i = 0; i < parameter_count_with_receiver; i++) {
+ params.push_back(node->InputAt(kReceiverInputIndex + i));
}
const Operator* op_param = common()->StateValues(
static_cast<int>(params.size()), SparseInputMask::Dense());
@@ -5694,7 +5657,7 @@ Node* JSCallReducer::CreateArtificialFrameState(
context = jsgraph()->UndefinedConstant();
}
return graph()->NewNode(op, params_node, node0, node0, context,
- node->InputAt(0), outer_frame_state);
+ node->InputAt(kTargetInputIndex), outer_frame_state);
}
Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
@@ -5804,7 +5767,7 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
// 9. Call executor with both resolving functions
effect = control = graph()->NewNode(
- javascript()->Call(4, p.frequency(), VectorSlotPair(),
+ javascript()->Call(4, p.frequency(), FeedbackSource(),
ConvertReceiverMode::kNullOrUndefined,
SpeculationMode::kDisallowSpeculation),
executor, jsgraph()->UndefinedConstant(), resolve, reject, context,
@@ -5817,7 +5780,7 @@ Reduction JSCallReducer::ReducePromiseConstructor(Node* node) {
common()->IfException(), exception_control, exception_effect);
// 10a. Call reject if the call to executor threw.
exception_effect = exception_control = graph()->NewNode(
- javascript()->Call(3, p.frequency(), VectorSlotPair(),
+ javascript()->Call(3, p.frequency(), FeedbackSource(),
ConvertReceiverMode::kNullOrUndefined,
SpeculationMode::kDisallowSpeculation),
reject, jsgraph()->UndefinedConstant(), reason, context, frame_state,
@@ -5928,9 +5891,7 @@ bool JSCallReducer::DoPromiseChecks(MapInference* inference) {
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
if (!receiver_map.IsJSPromiseMap()) return false;
- if (!FLAG_concurrent_inlining) {
- receiver_map.SerializePrototype();
- } else if (!receiver_map.serialized_prototype()) {
+ if (FLAG_concurrent_inlining && !receiver_map.serialized_prototype()) {
TRACE_BROKER_MISSING(broker(), "prototype for map " << receiver_map);
return false;
}
@@ -6109,7 +6070,7 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
}
Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
- DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
@@ -6177,7 +6138,7 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
// ES section #sec-promise.resolve
Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) {
- DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 1);
@@ -6293,8 +6254,13 @@ Reduction JSCallReducer::ReduceTypedArrayPrototypeToStringTag(Node* node) {
jsgraph()->Constant(TYPE##_ELEMENTS - \
FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)); \
control = graph()->NewNode(common()->Branch(), check, control); \
- values.push_back(jsgraph()->HeapConstant( \
- factory()->InternalizeUtf8String(#Type "Array"))); \
+ if (FLAG_concurrent_inlining) { \
+ values.push_back(jsgraph()->Constant( \
+ broker()->GetTypedArrayStringTag(TYPE##_ELEMENTS))); \
+ } else { \
+ values.push_back(jsgraph()->HeapConstant( \
+ factory()->InternalizeUtf8String(#Type "Array"))); \
+ } \
effects.push_back(effect); \
controls.push_back(graph()->NewNode(common()->IfTrue(), control)); \
control = graph()->NewNode(common()->IfFalse(), control); \
@@ -6536,9 +6502,10 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
MapInference inference(broker(), receiver, effect);
if (!inference.HaveMaps()) return NoChange();
MapHandles const& receiver_maps = inference.GetMaps();
- receiver_instance_type = receiver_maps[0]->instance_type();
+ receiver_instance_type = MapRef(broker(), receiver_maps[0]).instance_type();
for (size_t i = 1; i < receiver_maps.size(); ++i) {
- if (receiver_maps[i]->instance_type() != receiver_instance_type) {
+ if (MapRef(broker(), receiver_maps[i]).instance_type() !=
+ receiver_instance_type) {
return inference.NoChange();
}
}
@@ -6799,6 +6766,8 @@ Reduction JSCallReducer::ReduceCollectionIteratorPrototypeNext(
}
Reduction JSCallReducer::ReduceArrayBufferIsView(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
Node* value = node->op()->ValueInputCount() >= 3
? NodeProperties::GetValueInput(node, 2)
: jsgraph()->UndefinedConstant();
@@ -6811,6 +6780,8 @@ Reduction JSCallReducer::ReduceArrayBufferIsView(Node* node) {
Reduction JSCallReducer::ReduceArrayBufferViewAccessor(
Node* node, InstanceType instance_type, FieldAccess const& access) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
@@ -7142,19 +7113,20 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
ZoneVector<PropertyAccessInfo> access_infos(graph()->zone());
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
- if (!FLAG_concurrent_inlining) {
- // Compute property access info for "exec" on {resolution}.
- access_info_factory.ComputePropertyAccessInfos(
- MapHandles(regexp_maps.begin(), regexp_maps.end()),
- factory()->exec_string(), AccessMode::kLoad, &access_infos);
- } else {
+ if (FLAG_concurrent_inlining) {
// Obtain precomputed access infos from the broker.
for (auto map : regexp_maps) {
MapRef map_ref(broker(), map);
- PropertyAccessInfo access_info =
- broker()->GetAccessInfoForLoadingExec(map_ref);
+ PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
+ map_ref, NameRef(broker(), isolate()->factory()->exec_string()),
+ AccessMode::kLoad);
access_infos.push_back(access_info);
}
+ } else {
+ // Compute property access info for "exec" on {resolution}.
+ access_info_factory.ComputePropertyAccessInfos(
+ MapHandles(regexp_maps.begin(), regexp_maps.end()),
+ factory()->exec_string(), AccessMode::kLoad, &access_infos);
}
PropertyAccessInfo ai_exec =
@@ -7171,7 +7143,7 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
JSObjectRef holder_ref(broker(), holder);
// Bail out if the exec method is not the original one.
- base::Optional<ObjectRef> constant = holder_ref.GetOwnProperty(
+ base::Optional<ObjectRef> constant = holder_ref.GetOwnDataProperty(
ai_exec.field_representation(), ai_exec.field_index());
if (!constant.has_value() ||
!constant->equals(native_context().regexp_exec_function())) {
@@ -7287,7 +7259,7 @@ Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
Factory* JSCallReducer::factory() const { return isolate()->factory(); }
NativeContextRef JSCallReducer::native_context() const {
- return broker()->native_context();
+ return broker()->target_native_context();
}
CommonOperatorBuilder* JSCallReducer::common() const {
diff --git a/deps/v8/src/compiler/js-call-reducer.h b/deps/v8/src/compiler/js-call-reducer.h
index bf3676c5b2..66c42cfb63 100644
--- a/deps/v8/src/compiler/js-call-reducer.h
+++ b/deps/v8/src/compiler/js-call-reducer.h
@@ -17,7 +17,6 @@ namespace internal {
// Forward declarations.
class Factory;
class JSGlobalProxy;
-class VectorSlotPair;
namespace compiler {
@@ -25,6 +24,7 @@ namespace compiler {
class CallFrequency;
class CommonOperatorBuilder;
class CompilationDependencies;
+struct FeedbackSource;
struct FieldAccess;
class JSGraph;
class JSHeapBroker;
@@ -106,7 +106,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceCallOrConstructWithArrayLikeOrSpread(
Node* node, int arity, CallFrequency const& frequency,
- VectorSlotPair const& feedback);
+ FeedbackSource const& feedback);
Reduction ReduceJSConstruct(Node* node);
Reduction ReduceJSConstructWithArrayLike(Node* node);
Reduction ReduceJSConstructWithSpread(Node* node);
@@ -156,7 +156,6 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceMathImul(Node* node);
Reduction ReduceMathClz32(Node* node);
Reduction ReduceMathMinMax(Node* node, const Operator* op, Node* empty_value);
- Reduction ReduceMathHypot(Node* node);
Reduction ReduceNumberIsFinite(Node* node);
Reduction ReduceNumberIsInteger(Node* node);
@@ -234,7 +233,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
// k is thusly changed, and the effect is changed as well.
Node* SafeLoadElement(ElementsKind kind, Node* receiver, Node* control,
Node** effect, Node** k,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
Node* CreateArtificialFrameState(Node* node, Node* outer_frame_state,
int parameter_count, BailoutId bailout_id,
diff --git a/deps/v8/src/compiler/js-create-lowering.cc b/deps/v8/src/compiler/js-create-lowering.cc
index 4e69db6b9b..cb52ccaccb 100644
--- a/deps/v8/src/compiler/js-create-lowering.cc
+++ b/deps/v8/src/compiler/js-create-lowering.cc
@@ -127,7 +127,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(slack_tracking_prediction.instance_size());
a.Store(AccessBuilder::ForMap(), *initial_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
@@ -180,11 +180,11 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
: native_context().sloppy_arguments_map());
// Actually allocate and initialize the arguments object.
AllocationBuilder a(jsgraph(), effect, control);
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kTaggedSize);
a.Allocate(JSSloppyArgumentsObject::kSize);
a.Store(AccessBuilder::ForMap(), arguments_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
a.Store(AccessBuilder::ForArgumentsCallee(), callee);
@@ -209,11 +209,11 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
jsgraph()->Constant(native_context().strict_arguments_map());
// Actually allocate and initialize the arguments object.
AllocationBuilder a(jsgraph(), effect, control);
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kTaggedSize);
a.Allocate(JSStrictArgumentsObject::kSize);
a.Store(AccessBuilder::ForMap(), arguments_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);
RelaxControls(node);
@@ -239,11 +239,11 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
native_context().js_array_packed_elements_map());
// Actually allocate and initialize the jsarray.
AllocationBuilder a(jsgraph(), effect, control);
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
STATIC_ASSERT(JSArray::kSize == 4 * kTaggedSize);
a.Allocate(JSArray::kSize);
a.Store(AccessBuilder::ForMap(), jsarray_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), rest_length);
RelaxControls(node);
@@ -284,12 +284,12 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
: native_context().sloppy_arguments_map());
// Actually allocate and initialize the arguments object.
AllocationBuilder a(jsgraph(), effect, control);
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
int length = args_state_info.parameter_count() - 1; // Minus receiver.
STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kTaggedSize);
a.Allocate(JSSloppyArgumentsObject::kSize);
a.Store(AccessBuilder::ForMap(), arguments_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
a.Store(AccessBuilder::ForArgumentsCallee(), callee);
@@ -320,12 +320,12 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
jsgraph()->Constant(native_context().strict_arguments_map());
// Actually allocate and initialize the arguments object.
AllocationBuilder a(jsgraph(), effect, control);
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
int length = args_state_info.parameter_count() - 1; // Minus receiver.
STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kTaggedSize);
a.Allocate(JSStrictArgumentsObject::kSize);
a.Store(AccessBuilder::ForMap(), arguments_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
RelaxControls(node);
@@ -357,7 +357,6 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
jsgraph()->Constant(native_context().js_array_packed_elements_map());
// Actually allocate and initialize the jsarray.
AllocationBuilder a(jsgraph(), effect, control);
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
// -1 to minus receiver
int argument_count = args_state_info.parameter_count() - 1;
@@ -365,7 +364,8 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {
STATIC_ASSERT(JSArray::kSize == 4 * kTaggedSize);
a.Allocate(JSArray::kSize);
a.Store(AccessBuilder::ForMap(), jsarray_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS),
jsgraph()->Constant(length));
@@ -406,7 +406,7 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
int size = parameter_count_no_receiver +
shared.GetBytecodeArray().register_count();
AllocationBuilder ab(jsgraph(), effect, control);
- ab.AllocateArray(size, factory()->fixed_array_map());
+ ab.AllocateArray(size, MapRef(broker(), factory()->fixed_array_map()));
for (int i = 0; i < size; ++i) {
ab.Store(AccessBuilder::ForFixedArraySlot(i),
jsgraph()->UndefinedConstant());
@@ -416,11 +416,12 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) {
// Emit code to allocate the JS[Async]GeneratorObject instance.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(slack_tracking_prediction.instance_size());
- Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
Node* undefined = jsgraph()->UndefinedConstant();
a.Store(AccessBuilder::ForMap(), initial_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), empty_fixed_array);
- a.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
+ a.Store(AccessBuilder::ForJSObjectElements(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSGeneratorObjectContext(), context);
a.Store(AccessBuilder::ForJSGeneratorObjectFunction(), closure);
a.Store(AccessBuilder::ForJSGeneratorObjectReceiver(), receiver);
@@ -470,7 +471,7 @@ Reduction JSCreateLowering::ReduceNewArray(
// This has to be kept in sync with src/runtime/runtime-array.cc,
// where this limit is protected.
length = effect = graph()->NewNode(
- simplified()->CheckBounds(VectorSlotPair()), length,
+ simplified()->CheckBounds(FeedbackSource()), length,
jsgraph()->Constant(JSArray::kInitialMaxFastElementArray), effect,
control);
@@ -480,13 +481,13 @@ Reduction JSCreateLowering::ReduceNewArray(
? simplified()->NewDoubleElements(allocation)
: simplified()->NewSmiOrObjectElements(allocation),
length, effect, control);
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
// Perform the allocation of the actual JSArray object.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(slack_tracking_prediction.instance_size(), allocation);
a.Store(AccessBuilder::ForMap(), initial_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(initial_map.elements_kind()), length);
for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
@@ -526,13 +527,13 @@ Reduction JSCreateLowering::ReduceNewArray(
elements = effect =
AllocateElements(effect, control, elements_kind, capacity, allocation);
}
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
// Perform the allocation of the actual JSArray object.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(slack_tracking_prediction.instance_size(), allocation);
a.Store(AccessBuilder::ForMap(), initial_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
@@ -565,14 +566,14 @@ Reduction JSCreateLowering::ReduceNewArray(
for (auto& value : values) {
if (!NodeProperties::GetType(value).Is(Type::SignedSmall())) {
value = effect = graph()->NewNode(
- simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
+ simplified()->CheckSmi(FeedbackSource()), value, effect, control);
}
}
} else if (IsDoubleElementsKind(elements_kind)) {
for (auto& value : values) {
if (!NodeProperties::GetType(value).Is(Type::Number())) {
value = effect =
- graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), value,
+ graph()->NewNode(simplified()->CheckNumber(FeedbackSource()), value,
effect, control);
}
// Make sure we do not store signaling NaNs into double arrays.
@@ -583,14 +584,14 @@ Reduction JSCreateLowering::ReduceNewArray(
// Setup elements, properties and length.
Node* elements = effect =
AllocateElements(effect, control, elements_kind, values, allocation);
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
Node* length = jsgraph()->Constant(static_cast<int>(values.size()));
// Perform the allocation of the actual JSArray object.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(slack_tracking_prediction.instance_size(), allocation);
a.Store(AccessBuilder::ForMap(), initial_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
for (int i = 0; i < slack_tracking_prediction.inobject_property_count();
@@ -735,7 +736,7 @@ Reduction JSCreateLowering::ReduceJSCreateArrayIterator(Node* node) {
Type::OtherObject());
a.Store(AccessBuilder::ForMap(),
native_context().initial_array_iterator_map());
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
@@ -761,7 +762,8 @@ Reduction JSCreateLowering::ReduceJSCreateAsyncFunctionObject(Node* node) {
// Create the register file.
AllocationBuilder ab(jsgraph(), effect, control);
- ab.AllocateArray(register_count, factory()->fixed_array_map());
+ ab.AllocateArray(register_count,
+ MapRef(broker(), factory()->fixed_array_map()));
for (int i = 0; i < register_count; ++i) {
ab.Store(AccessBuilder::ForFixedArraySlot(i),
jsgraph()->UndefinedConstant());
@@ -771,11 +773,12 @@ Reduction JSCreateLowering::ReduceJSCreateAsyncFunctionObject(Node* node) {
// Create the JSAsyncFunctionObject result.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(JSAsyncFunctionObject::kSize);
- Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
a.Store(AccessBuilder::ForMap(),
native_context().async_function_object_map());
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), empty_fixed_array);
- a.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
+ a.Store(AccessBuilder::ForJSObjectElements(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSGeneratorObjectContext(), context);
a.Store(AccessBuilder::ForJSGeneratorObjectFunction(), closure);
a.Store(AccessBuilder::ForJSGeneratorObjectReceiver(), receiver);
@@ -844,7 +847,7 @@ Reduction JSCreateLowering::ReduceJSCreateCollectionIterator(Node* node) {
a.Store(AccessBuilder::ForMap(),
MapForCollectionIterationKind(native_context(), p.collection_kind(),
p.iteration_kind()));
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
@@ -871,7 +874,7 @@ Reduction JSCreateLowering::ReduceJSCreateBoundFunction(Node* node) {
Node* bound_arguments = jsgraph()->EmptyFixedArrayConstant();
if (arity > 0) {
AllocationBuilder a(jsgraph(), effect, control);
- a.AllocateArray(arity, factory()->fixed_array_map());
+ a.AllocateArray(arity, MapRef(broker(), factory()->fixed_array_map()));
for (int i = 0; i < arity; ++i) {
a.Store(AccessBuilder::ForFixedArraySlot(i),
NodeProperties::GetValueInput(node, 2 + i));
@@ -884,7 +887,7 @@ Reduction JSCreateLowering::ReduceJSCreateBoundFunction(Node* node) {
a.Allocate(JSBoundFunction::kSize, AllocationType::kYoung,
Type::BoundFunction());
a.Store(AccessBuilder::ForMap(), map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
@@ -936,7 +939,7 @@ Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) {
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(function_map.instance_size(), allocation, Type::Function());
a.Store(AccessBuilder::ForMap(), function_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
@@ -972,7 +975,7 @@ Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
AllocationBuilder a(jsgraph(), effect, graph()->start());
a.Allocate(JSIteratorResult::kSize);
a.Store(AccessBuilder::ForMap(), iterator_result_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
@@ -995,7 +998,7 @@ Reduction JSCreateLowering::ReduceJSCreateStringIterator(Node* node) {
a.Allocate(JSStringIterator::kSize, AllocationType::kYoung,
Type::OtherObject());
a.Store(AccessBuilder::ForMap(), map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
@@ -1014,11 +1017,10 @@ Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) {
Node* array_map =
jsgraph()->Constant(native_context().js_array_packed_elements_map());
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
Node* length = jsgraph()->Constant(2);
AllocationBuilder aa(jsgraph(), effect, graph()->start());
- aa.AllocateArray(2, factory()->fixed_array_map());
+ aa.AllocateArray(2, MapRef(broker(), factory()->fixed_array_map()));
aa.Store(AccessBuilder::ForFixedArrayElement(PACKED_ELEMENTS),
jsgraph()->ZeroConstant(), key);
aa.Store(AccessBuilder::ForFixedArrayElement(PACKED_ELEMENTS),
@@ -1028,7 +1030,8 @@ Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) {
AllocationBuilder a(jsgraph(), elements, graph()->start());
a.Allocate(JSArray::kSize);
a.Store(AccessBuilder::ForMap(), array_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), length);
STATIC_ASSERT(JSArray::kSize == 4 * kTaggedSize);
@@ -1045,7 +1048,7 @@ Reduction JSCreateLowering::ReduceJSCreatePromise(Node* node) {
AllocationBuilder a(jsgraph(), effect, graph()->start());
a.Allocate(promise_map.instance_size());
a.Store(AccessBuilder::ForMap(), promise_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
@@ -1071,8 +1074,12 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- FeedbackVectorRef feedback_vector(broker(), p.feedback().vector());
- ObjectRef feedback = feedback_vector.get(p.feedback().slot());
+ FeedbackVectorRef feedback_vector(broker(), p.feedback().vector);
+ ObjectRef feedback = feedback_vector.get(p.feedback().slot);
+ // TODO(turbofan): we should consider creating a ProcessedFeedback for
+ // allocation sites/boiler plates so that we use GetFeedback here. Then
+ // we can eventually get rid of the additional copy of feedback slots that
+ // we currently have in FeedbackVectorData.
if (feedback.IsAllocationSite()) {
AllocationSiteRef site = feedback.AsAllocationSite();
if (site.IsFastLiteral()) {
@@ -1094,8 +1101,12 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralArrayOrObject(Node* node) {
Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralArray(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateEmptyLiteralArray, node->opcode());
FeedbackParameter const& p = FeedbackParameterOf(node->op());
- FeedbackVectorRef fv(broker(), p.feedback().vector());
- ObjectRef feedback = fv.get(p.feedback().slot());
+ FeedbackVectorRef fv(broker(), p.feedback().vector);
+ ObjectRef feedback = fv.get(p.feedback().slot);
+ // TODO(turbofan): we should consider creating a ProcessedFeedback for
+ // allocation sites/boiler plates so that we use GetFeedback here. Then
+ // we can eventually get rid of the additional copy of feedback slots that
+ // we currently have in FeedbackVectorData.
if (feedback.IsAllocationSite()) {
AllocationSiteRef site = feedback.AsAllocationSite();
DCHECK(!site.PointsToLiteral());
@@ -1128,13 +1139,13 @@ Reduction JSCreateLowering::ReduceJSCreateEmptyLiteralObject(Node* node) {
// Setup elements and properties.
Node* elements = jsgraph()->EmptyFixedArrayConstant();
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
// Perform the allocation of the actual JSArray object.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(map.instance_size());
a.Store(AccessBuilder::ForMap(), js_object_map);
- a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(), elements);
for (int i = 0; i < map.GetInObjectProperties(); i++) {
a.Store(AccessBuilder::ForJSObjectInObjectProperty(map, i),
@@ -1152,8 +1163,12 @@ Reduction JSCreateLowering::ReduceJSCreateLiteralRegExp(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- FeedbackVectorRef feedback_vector(broker(), p.feedback().vector());
- ObjectRef feedback = feedback_vector.get(p.feedback().slot());
+ FeedbackVectorRef feedback_vector(broker(), p.feedback().vector);
+ ObjectRef feedback = feedback_vector.get(p.feedback().slot);
+ // TODO(turbofan): we should consider creating a ProcessedFeedback for
+ // allocation sites/boiler plates so that we use GetFeedback here. Then
+ // we can eventually get rid of the additional copy of feedback slots that
+ // we currently have in FeedbackVectorData.
if (feedback.IsJSRegExp()) {
JSRegExpRef boilerplate = feedback.AsJSRegExp();
Node* value = effect = AllocateLiteralRegExp(effect, control, boilerplate);
@@ -1192,7 +1207,7 @@ Reduction JSCreateLowering::ReduceJSCreateFunctionContext(Node* node) {
default:
UNREACHABLE();
}
- a.AllocateContext(context_length, map);
+ a.AllocateContext(context_length, MapRef(broker(), map));
a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX),
scope_info);
a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
@@ -1220,7 +1235,8 @@ Reduction JSCreateLowering::ReduceJSCreateWithContext(Node* node) {
AllocationBuilder a(jsgraph(), effect, control);
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
- a.AllocateContext(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
+ a.AllocateContext(Context::MIN_CONTEXT_SLOTS,
+ MapRef(broker(), factory()->with_context_map()));
a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX), scope_info);
a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
@@ -1243,7 +1259,7 @@ Reduction JSCreateLowering::ReduceJSCreateCatchContext(Node* node) {
AllocationBuilder a(jsgraph(), effect, control);
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
a.AllocateContext(Context::MIN_CONTEXT_SLOTS + 1,
- factory()->catch_context_map());
+ MapRef(broker(), factory()->catch_context_map()));
a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX), scope_info);
a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
@@ -1271,7 +1287,8 @@ Reduction JSCreateLowering::ReduceJSCreateBlockContext(Node* node) {
AllocationBuilder a(jsgraph(), effect, control);
STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
- a.AllocateContext(context_length, factory()->block_context_map());
+ a.AllocateContext(context_length,
+ MapRef(broker(), factory()->block_context_map()));
a.Store(AccessBuilder::ForContextSlot(Context::SCOPE_INFO_INDEX),
scope_info);
a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
@@ -1293,12 +1310,13 @@ namespace {
base::Optional<MapRef> GetObjectCreateMap(JSHeapBroker* broker,
HeapObjectRef prototype) {
MapRef standard_map =
- broker->native_context().object_function().initial_map();
+ broker->target_native_context().object_function().initial_map();
if (prototype.equals(standard_map.prototype())) {
return standard_map;
}
if (prototype.map().oddball_type() == OddballType::kNull) {
- return broker->native_context().slow_object_with_null_prototype_map();
+ return broker->target_native_context()
+ .slow_object_with_null_prototype_map();
}
if (prototype.IsJSObject()) {
return prototype.AsJSObject().GetObjectCreateMap();
@@ -1401,7 +1419,8 @@ Node* JSCreateLowering::AllocateArguments(Node* effect, Node* control,
// Actually allocate the backing store.
AllocationBuilder a(jsgraph(), effect, control);
- a.AllocateArray(argument_count, factory()->fixed_array_map());
+ a.AllocateArray(argument_count,
+ MapRef(broker(), factory()->fixed_array_map()));
for (int i = 0; i < argument_count; ++i, ++parameters_it) {
DCHECK_NOT_NULL((*parameters_it).node);
a.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(i),
@@ -1432,7 +1451,7 @@ Node* JSCreateLowering::AllocateRestArguments(Node* effect, Node* control,
// Actually allocate the backing store.
AllocationBuilder a(jsgraph(), effect, control);
- a.AllocateArray(num_elements, factory()->fixed_array_map());
+ a.AllocateArray(num_elements, MapRef(broker(), factory()->fixed_array_map()));
for (int i = 0; i < num_elements; ++i, ++parameters_it) {
DCHECK_NOT_NULL((*parameters_it).node);
a.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(i),
@@ -1471,7 +1490,8 @@ Node* JSCreateLowering::AllocateAliasedArguments(
// another indirection away and then linked into the parameter map below,
// whereas mapped argument values are replaced with a hole instead.
AllocationBuilder aa(jsgraph(), effect, control);
- aa.AllocateArray(argument_count, factory()->fixed_array_map());
+ aa.AllocateArray(argument_count,
+ MapRef(broker(), factory()->fixed_array_map()));
for (int i = 0; i < mapped_count; ++i, ++parameters_it) {
aa.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(i),
jsgraph()->TheHoleConstant());
@@ -1485,7 +1505,8 @@ Node* JSCreateLowering::AllocateAliasedArguments(
// Actually allocate the backing store.
AllocationBuilder a(jsgraph(), arguments, control);
- a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
+ a.AllocateArray(mapped_count + 2,
+ MapRef(broker(), factory()->sloppy_arguments_elements_map()));
a.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(0),
context);
a.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(1),
@@ -1530,7 +1551,8 @@ Node* JSCreateLowering::AllocateAliasedArguments(
// Actually allocate the backing store.
AllocationBuilder a(jsgraph(), arguments, control);
- a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
+ a.AllocateArray(mapped_count + 2,
+ MapRef(broker(), factory()->sloppy_arguments_elements_map()));
a.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(0),
context);
a.Store(AccessBuilder::ForFixedArrayElement(), jsgraph()->Constant(1),
@@ -1565,7 +1587,7 @@ Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
// Actually allocate the backing store.
AllocationBuilder a(jsgraph(), effect, control);
- a.AllocateArray(capacity, elements_map, allocation);
+ a.AllocateArray(capacity, MapRef(broker(), elements_map), allocation);
for (int i = 0; i < capacity; ++i) {
Node* index = jsgraph()->Constant(i);
a.Store(access, index, value);
@@ -1590,7 +1612,7 @@ Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
// Actually allocate the backing store.
AllocationBuilder a(jsgraph(), effect, control);
- a.AllocateArray(capacity, elements_map, allocation);
+ a.AllocateArray(capacity, MapRef(broker(), elements_map), allocation);
for (int i = 0; i < capacity; ++i) {
Node* index = jsgraph()->Constant(i);
a.Store(access, index, values[i]);
@@ -1601,9 +1623,6 @@ Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
JSObjectRef boilerplate,
AllocationType allocation) {
- // Setup the properties backing store.
- Node* properties = jsgraph()->EmptyFixedArrayConstant();
-
// Compute the in-object properties to store first (might have effects).
MapRef boilerplate_map = boilerplate.map();
ZoneVector<std::pair<FieldAccess, Node*>> inobject_fields(zone());
@@ -1616,6 +1635,7 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
DCHECK_EQ(kData, property_details.kind());
NameRef property_name = boilerplate_map.GetPropertyKey(i);
FieldIndex index = boilerplate_map.GetFieldIndexFor(i);
+ ConstFieldInfo const_field_info(boilerplate_map.object());
FieldAccess access = {kTaggedBase,
index.offset(),
property_name.object(),
@@ -1624,7 +1644,7 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
MachineType::TypeCompressedTagged(),
kFullWriteBarrier,
LoadSensitivity::kUnsafe,
- property_details.constness()};
+ const_field_info};
Node* value;
if (boilerplate_map.IsUnboxedDoubleField(i)) {
access.machine_type = MachineType::Float64();
@@ -1637,7 +1657,7 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
// the field. The hole NaN should therefore be unobservable.
// Load elimination expects there to be at most one const store to any
// given field, so we always mark the unobservable ones as mutable.
- access.constness = PropertyConstness::kMutable;
+ access.const_field_info = ConstFieldInfo::None();
}
value = jsgraph()->Constant(bit_cast<double>(value_bits));
} else {
@@ -1647,19 +1667,19 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
boilerplate_value.AsHeapObject().map().oddball_type() ==
OddballType::kUninitialized;
if (is_uninitialized) {
- access.constness = PropertyConstness::kMutable;
+ access.const_field_info = ConstFieldInfo::None();
}
if (boilerplate_value.IsJSObject()) {
JSObjectRef boilerplate_object = boilerplate_value.AsJSObject();
value = effect = AllocateFastLiteral(effect, control,
boilerplate_object, allocation);
} else if (property_details.representation().IsDouble()) {
- double number = boilerplate_value.AsMutableHeapNumber().value();
+ double number = boilerplate_value.AsHeapNumber().value();
// Allocate a mutable HeapNumber box and store the value into it.
AllocationBuilder builder(jsgraph(), effect, control);
builder.Allocate(HeapNumber::kSize, allocation);
builder.Store(AccessBuilder::ForMap(),
- factory()->mutable_heap_number_map());
+ MapRef(broker(), factory()->heap_number_map()));
builder.Store(AccessBuilder::ForHeapNumberValue(),
jsgraph()->Constant(number));
value = effect = builder.Finish();
@@ -1695,7 +1715,8 @@ Node* JSCreateLowering::AllocateFastLiteral(Node* effect, Node* control,
builder.Allocate(boilerplate_map.instance_size(), allocation,
Type::For(boilerplate_map));
builder.Store(AccessBuilder::ForMap(), boilerplate_map);
- builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);
+ builder.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(),
+ jsgraph()->EmptyFixedArrayConstant());
builder.Store(AccessBuilder::ForJSObjectElements(), elements);
if (boilerplate.IsJSArray()) {
JSArrayRef boilerplate_array = boilerplate.AsJSArray();
@@ -1751,7 +1772,7 @@ Node* JSCreateLowering::AllocateFastLiteralElements(Node* effect, Node* control,
// Allocate the backing store array and store the elements.
AllocationBuilder builder(jsgraph(), effect, control);
- builder.AllocateArray(elements_length, elements_map.object(), allocation);
+ builder.AllocateArray(elements_length, elements_map, allocation);
ElementAccess const access =
(elements_map.instance_type() == FIXED_DOUBLE_ARRAY_TYPE)
? AccessBuilder::ForFixedDoubleArrayElement()
@@ -1811,7 +1832,7 @@ SimplifiedOperatorBuilder* JSCreateLowering::simplified() const {
}
NativeContextRef JSCreateLowering::native_context() const {
- return broker()->native_context();
+ return broker()->target_native_context();
}
} // namespace compiler
diff --git a/deps/v8/src/compiler/js-generic-lowering.cc b/deps/v8/src/compiler/js-generic-lowering.cc
index 0a6f90975f..d2a9b675f9 100644
--- a/deps/v8/src/compiler/js-generic-lowering.cc
+++ b/deps/v8/src/compiler/js-generic-lowering.cc
@@ -9,10 +9,12 @@
#include "src/codegen/code-factory.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/js-graph.h"
+#include "src/compiler/js-heap-broker.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
+#include "src/compiler/processed-feedback.h"
#include "src/objects/feedback-cell.h"
#include "src/objects/feedback-vector.h"
#include "src/objects/scope-info.h"
@@ -31,8 +33,9 @@ CallDescriptor::Flags FrameStateFlagForCall(Node* node) {
} // namespace
-JSGenericLowering::JSGenericLowering(JSGraph* jsgraph, Editor* editor)
- : AdvancedReducer(editor), jsgraph_(jsgraph) {}
+JSGenericLowering::JSGenericLowering(JSGraph* jsgraph, Editor* editor,
+ JSHeapBroker* broker)
+ : AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
JSGenericLowering::~JSGenericLowering() = default;
@@ -144,6 +147,22 @@ void JSGenericLowering::LowerJSStrictEqual(Node* node) {
Operator::kEliminatable);
}
+namespace {
+bool ShouldUseMegamorphicLoadBuiltin(FeedbackSource const& source,
+ JSHeapBroker* broker) {
+ ProcessedFeedback const& feedback = broker->GetFeedback(source);
+
+ if (feedback.kind() == ProcessedFeedback::kElementAccess) {
+ return feedback.AsElementAccess().transition_groups().empty();
+ } else if (feedback.kind() == ProcessedFeedback::kNamedAccess) {
+ return feedback.AsNamedAccess().maps().empty();
+ } else if (feedback.kind() == ProcessedFeedback::kInsufficient) {
+ return false;
+ }
+ UNREACHABLE();
+}
+} // namespace
+
void JSGenericLowering::LowerJSLoadProperty(Node* node) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
const PropertyAccess& p = PropertyAccessOf(node->op());
@@ -152,16 +171,16 @@ void JSGenericLowering::LowerJSLoadProperty(Node* node) {
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
if (outer_state->opcode() != IrOpcode::kFrameState) {
Callable callable = Builtins::CallableFor(
- isolate(), p.feedback().ic_state() == MEGAMORPHIC
+ isolate(), ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
? Builtins::kKeyedLoadICTrampoline_Megamorphic
: Builtins::kKeyedLoadICTrampoline);
ReplaceWithStubCall(node, callable, flags);
} else {
Callable callable = Builtins::CallableFor(
- isolate(), p.feedback().ic_state() == MEGAMORPHIC
+ isolate(), ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
? Builtins::kKeyedLoadIC_Megamorphic
: Builtins::kKeyedLoadIC);
- Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
+ Node* vector = jsgraph()->HeapConstant(p.feedback().vector);
node->InsertInput(zone(), 3, vector);
ReplaceWithStubCall(node, callable, flags);
}
@@ -182,16 +201,16 @@ void JSGenericLowering::LowerJSLoadNamed(Node* node) {
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
if (outer_state->opcode() != IrOpcode::kFrameState) {
Callable callable = Builtins::CallableFor(
- isolate(), p.feedback().ic_state() == MEGAMORPHIC
+ isolate(), ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
? Builtins::kLoadICTrampoline_Megamorphic
: Builtins::kLoadICTrampoline);
ReplaceWithStubCall(node, callable, flags);
} else {
- Callable callable =
- Builtins::CallableFor(isolate(), p.feedback().ic_state() == MEGAMORPHIC
- ? Builtins::kLoadIC_Megamorphic
- : Builtins::kLoadIC);
- Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
+ Callable callable = Builtins::CallableFor(
+ isolate(), ShouldUseMegamorphicLoadBuiltin(p.feedback(), broker())
+ ? Builtins::kLoadIC_Megamorphic
+ : Builtins::kLoadIC);
+ Node* vector = jsgraph()->HeapConstant(p.feedback().vector);
node->InsertInput(zone(), 3, vector);
ReplaceWithStubCall(node, callable, flags);
}
@@ -210,12 +229,23 @@ void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
} else {
Callable callable =
CodeFactory::LoadGlobalICInOptimizedCode(isolate(), p.typeof_mode());
- Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
+ Node* vector = jsgraph()->HeapConstant(p.feedback().vector);
node->InsertInput(zone(), 2, vector);
ReplaceWithStubCall(node, callable, flags);
}
}
+void JSGenericLowering::LowerJSGetIterator(Node* node) {
+ CallDescriptor::Flags flags = FrameStateFlagForCall(node);
+ const PropertyAccess& p = PropertyAccessOf(node->op());
+ node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
+ Node* vector = jsgraph()->HeapConstant(p.feedback().vector);
+ node->InsertInput(zone(), 2, vector);
+ Callable callable =
+ Builtins::CallableFor(isolate(), Builtins::kGetIteratorWithFeedback);
+ ReplaceWithStubCall(node, callable, flags);
+}
+
void JSGenericLowering::LowerJSStoreProperty(Node* node) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
PropertyAccess const& p = PropertyAccessOf(node->op());
@@ -229,7 +259,7 @@ void JSGenericLowering::LowerJSStoreProperty(Node* node) {
} else {
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kKeyedStoreIC);
- Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
+ Node* vector = jsgraph()->HeapConstant(p.feedback().vector);
node->InsertInput(zone(), 4, vector);
ReplaceWithStubCall(node, callable, flags);
}
@@ -252,7 +282,7 @@ void JSGenericLowering::LowerJSStoreNamed(Node* node) {
ReplaceWithStubCall(node, callable, flags);
} else {
Callable callable = Builtins::CallableFor(isolate(), Builtins::kStoreIC);
- Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
+ Node* vector = jsgraph()->HeapConstant(p.feedback().vector);
node->InsertInput(zone(), 4, vector);
ReplaceWithStubCall(node, callable, flags);
}
@@ -270,7 +300,7 @@ void JSGenericLowering::LowerJSStoreNamedOwn(Node* node) {
ReplaceWithStubCall(node, callable, flags);
} else {
Callable callable = CodeFactory::StoreOwnICInOptimizedCode(isolate());
- Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
+ Node* vector = jsgraph()->HeapConstant(p.feedback().vector);
node->InsertInput(zone(), 4, vector);
ReplaceWithStubCall(node, callable, flags);
}
@@ -290,7 +320,7 @@ void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
} else {
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kStoreGlobalIC);
- Node* vector = jsgraph()->HeapConstant(p.feedback().vector());
+ Node* vector = jsgraph()->HeapConstant(p.feedback().vector);
node->InsertInput(zone(), 3, vector);
ReplaceWithStubCall(node, callable, flags);
}
@@ -298,8 +328,9 @@ void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
void JSGenericLowering::LowerJSStoreDataPropertyInLiteral(Node* node) {
FeedbackParameter const& p = FeedbackParameterOf(node->op());
+ RelaxControls(node);
node->InsertInputs(zone(), 4, 2);
- node->ReplaceInput(4, jsgraph()->HeapConstant(p.feedback().vector()));
+ node->ReplaceInput(4, jsgraph()->HeapConstant(p.feedback().vector));
node->ReplaceInput(5, jsgraph()->SmiConstant(p.feedback().index()));
ReplaceWithRuntimeCall(node, Runtime::kDefineDataPropertyInLiteral);
}
@@ -311,7 +342,7 @@ void JSGenericLowering::LowerJSStoreInArrayLiteral(Node* node) {
FeedbackParameter const& p = FeedbackParameterOf(node->op());
RelaxControls(node);
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
- node->InsertInput(zone(), 4, jsgraph()->HeapConstant(p.feedback().vector()));
+ node->InsertInput(zone(), 4, jsgraph()->HeapConstant(p.feedback().vector));
ReplaceWithStubCall(node, callable, flags);
}
@@ -513,7 +544,7 @@ void JSGenericLowering::LowerJSCreateTypedArray(Node* node) {
void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
- node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
+ node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector));
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
@@ -533,7 +564,7 @@ void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) {
void JSGenericLowering::LowerJSCreateEmptyLiteralArray(Node* node) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
FeedbackParameter const& p = FeedbackParameterOf(node->op());
- node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
+ node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector));
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
node->RemoveInput(4); // control
Callable callable =
@@ -551,7 +582,7 @@ void JSGenericLowering::LowerJSCreateArrayFromIterable(Node* node) {
void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) {
CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
- node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
+ node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector));
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
@@ -576,7 +607,7 @@ void JSGenericLowering::LowerJSCloneObject(Node* node) {
Builtins::CallableFor(isolate(), Builtins::kCloneObjectIC);
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.flags()));
node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
- node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector()));
+ node->InsertInput(zone(), 3, jsgraph()->HeapConstant(p.feedback().vector));
ReplaceWithStubCall(node, callable, flags);
}
@@ -589,7 +620,7 @@ void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kCreateRegExpLiteral);
- node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector()));
+ node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.feedback().vector));
node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.feedback().index()));
node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant()));
node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags()));
@@ -812,14 +843,13 @@ void JSGenericLowering::LowerJSStackCheck(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- Node* limit = effect = graph()->NewNode(
- machine()->Load(MachineType::Pointer()),
- jsgraph()->ExternalConstant(
- ExternalReference::address_of_stack_limit(isolate())),
- jsgraph()->IntPtrConstant(0), effect, control);
- Node* pointer = graph()->NewNode(machine()->LoadStackPointer());
+ Node* limit = effect =
+ graph()->NewNode(machine()->Load(MachineType::Pointer()),
+ jsgraph()->ExternalConstant(
+ ExternalReference::address_of_jslimit(isolate())),
+ jsgraph()->IntPtrConstant(0), effect, control);
- Node* check = graph()->NewNode(machine()->UintLessThan(), limit, pointer);
+ Node* check = graph()->NewNode(machine()->StackPointerGreaterThan(), limit);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
diff --git a/deps/v8/src/compiler/js-generic-lowering.h b/deps/v8/src/compiler/js-generic-lowering.h
index 2a395ca5e8..2a4ac808b1 100644
--- a/deps/v8/src/compiler/js-generic-lowering.h
+++ b/deps/v8/src/compiler/js-generic-lowering.h
@@ -23,7 +23,7 @@ class Linkage;
// Lowers JS-level operators to runtime and IC calls in the "generic" case.
class JSGenericLowering final : public AdvancedReducer {
public:
- JSGenericLowering(JSGraph* jsgraph, Editor* editor);
+ JSGenericLowering(JSGraph* jsgraph, Editor* editor, JSHeapBroker* broker);
~JSGenericLowering() final;
const char* reducer_name() const override { return "JSGenericLowering"; }
@@ -48,9 +48,11 @@ class JSGenericLowering final : public AdvancedReducer {
Graph* graph() const;
CommonOperatorBuilder* common() const;
MachineOperatorBuilder* machine() const;
+ JSHeapBroker* broker() const { return broker_; }
private:
JSGraph* const jsgraph_;
+ JSHeapBroker* const broker_;
};
} // namespace compiler
diff --git a/deps/v8/src/compiler/js-graph.cc b/deps/v8/src/compiler/js-graph.cc
index 43a4beadee..beed7820b4 100644
--- a/deps/v8/src/compiler/js-graph.cc
+++ b/deps/v8/src/compiler/js-graph.cc
@@ -46,26 +46,6 @@ Node* JSGraph::CEntryStubConstant(int result_size, SaveFPRegsMode save_doubles,
argv_mode, builtin_exit_frame));
}
-Node* JSGraph::Constant(Handle<Object> value) {
- // Dereference the handle to determine if a number constant or other
- // canonicalized node can be used.
- if (value->IsNumber()) {
- return Constant(value->Number());
- } else if (value->IsUndefined(isolate())) {
- return UndefinedConstant();
- } else if (value->IsTrue(isolate())) {
- return TrueConstant();
- } else if (value->IsFalse(isolate())) {
- return FalseConstant();
- } else if (value->IsNull(isolate())) {
- return NullConstant();
- } else if (value->IsTheHole(isolate())) {
- return TheHoleConstant();
- } else {
- return HeapConstant(Handle<HeapObject>::cast(value));
- }
-}
-
Node* JSGraph::Constant(const ObjectRef& ref) {
if (ref.IsSmi()) return Constant(ref.AsSmi());
OddballType oddball_type =
diff --git a/deps/v8/src/compiler/js-graph.h b/deps/v8/src/compiler/js-graph.h
index ec36c26034..83c81b1010 100644
--- a/deps/v8/src/compiler/js-graph.h
+++ b/deps/v8/src/compiler/js-graph.h
@@ -46,16 +46,12 @@ class V8_EXPORT_PRIVATE JSGraph : public MachineGraph {
// Used for stubs and runtime functions with no context. (alias: SMI zero)
Node* NoContextConstant() { return ZeroConstant(); }
- // Creates a HeapConstant node, possibly canonicalized, and may access the
- // heap to inspect the object.
+ // Creates a HeapConstant node, possibly canonicalized.
Node* HeapConstant(Handle<HeapObject> value);
// Creates a Constant node of the appropriate type for the given object.
- // Accesses the heap to inspect the object and determine whether one of the
+ // Inspect the (serialized) object and determine whether one of the
// canonicalized globals or a number constant should be returned.
- Node* Constant(Handle<Object> value);
-
- // Like above, but doesn't access the heap directly.
Node* Constant(const ObjectRef& value);
// Creates a NumberConstant node, usually canonicalized.
diff --git a/deps/v8/src/compiler/js-heap-broker.cc b/deps/v8/src/compiler/js-heap-broker.cc
index c79c793ae6..7466a80f85 100644
--- a/deps/v8/src/compiler/js-heap-broker.cc
+++ b/deps/v8/src/compiler/js-heap-broker.cc
@@ -16,7 +16,6 @@
#include "src/compiler/bytecode-analysis.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/per-isolate-compiler-cache.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/init/bootstrapper.h"
#include "src/objects/allocation-site-inl.h"
#include "src/objects/api-callbacks.h"
@@ -26,6 +25,7 @@
#include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/js-regexp-inl.h"
+#include "src/objects/literal-objects-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/template-objects-inl.h"
@@ -256,13 +256,14 @@ class JSObjectField {
uint64_t number_bits_ = 0;
};
-struct FieldIndexHasher {
- size_t operator()(FieldIndex field_index) const {
- return field_index.index();
- }
+class JSReceiverData : public HeapObjectData {
+ public:
+ JSReceiverData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<JSReceiver> object)
+ : HeapObjectData(broker, storage, object) {}
};
-class JSObjectData : public HeapObjectData {
+class JSObjectData : public JSReceiverData {
public:
JSObjectData(JSHeapBroker* broker, ObjectData** storage,
Handle<JSObject> object);
@@ -277,16 +278,22 @@ class JSObjectData : public HeapObjectData {
FixedArrayBaseData* elements() const;
void SerializeObjectCreateMap(JSHeapBroker* broker);
- MapData* object_create_map() const { // Can be nullptr.
- CHECK(serialized_object_create_map_);
+
+ MapData* object_create_map(JSHeapBroker* broker) const { // Can be nullptr.
+ if (!serialized_object_create_map_) {
+ DCHECK_NULL(object_create_map_);
+ TRACE_MISSING(broker, "object_create_map on " << this);
+ }
return object_create_map_;
}
- ObjectData* GetOwnConstantElement(JSHeapBroker* broker, uint32_t index,
- bool serialize);
- ObjectData* GetOwnProperty(JSHeapBroker* broker,
- Representation representation,
- FieldIndex field_index, bool serialize);
+ ObjectData* GetOwnConstantElement(
+ JSHeapBroker* broker, uint32_t index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
+ ObjectData* GetOwnDataProperty(
+ JSHeapBroker* broker, Representation representation,
+ FieldIndex field_index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
// This method is only used to assert our invariants.
bool cow_or_empty_elements_tenured() const;
@@ -316,7 +323,9 @@ class JSObjectData : public HeapObjectData {
// (2) are known not to (possibly they don't exist at all).
// In case (2), the second pair component is nullptr.
// For simplicity, this may in theory overlap with inobject_fields_.
- ZoneUnorderedMap<FieldIndex, ObjectData*, FieldIndexHasher> own_properties_;
+ // The keys of the map are the property_index() values of the
+ // respective property FieldIndex'es.
+ ZoneUnorderedMap<int, ObjectData*> own_properties_;
};
void JSObjectData::SerializeObjectCreateMap(JSHeapBroker* broker) {
@@ -353,24 +362,25 @@ base::Optional<ObjectRef> GetOwnElementFromHeap(JSHeapBroker* broker,
return base::nullopt;
}
-ObjectRef GetOwnPropertyFromHeap(JSHeapBroker* broker,
- Handle<JSObject> receiver,
- Representation representation,
- FieldIndex field_index) {
+ObjectRef GetOwnDataPropertyFromHeap(JSHeapBroker* broker,
+ Handle<JSObject> receiver,
+ Representation representation,
+ FieldIndex field_index) {
Handle<Object> constant =
JSObject::FastPropertyAt(receiver, representation, field_index);
return ObjectRef(broker, constant);
}
+
} // namespace
ObjectData* JSObjectData::GetOwnConstantElement(JSHeapBroker* broker,
uint32_t index,
- bool serialize) {
+ SerializationPolicy policy) {
for (auto const& p : own_constant_elements_) {
if (p.first == index) return p.second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about index " << index << " on " << this);
return nullptr;
}
@@ -382,24 +392,24 @@ ObjectData* JSObjectData::GetOwnConstantElement(JSHeapBroker* broker,
return result;
}
-ObjectData* JSObjectData::GetOwnProperty(JSHeapBroker* broker,
- Representation representation,
- FieldIndex field_index,
- bool serialize) {
- auto p = own_properties_.find(field_index);
+ObjectData* JSObjectData::GetOwnDataProperty(JSHeapBroker* broker,
+ Representation representation,
+ FieldIndex field_index,
+ SerializationPolicy policy) {
+ auto p = own_properties_.find(field_index.property_index());
if (p != own_properties_.end()) return p->second;
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about property with index "
<< field_index.property_index() << " on "
<< this);
return nullptr;
}
- ObjectRef property = GetOwnPropertyFromHeap(
+ ObjectRef property = GetOwnDataPropertyFromHeap(
broker, Handle<JSObject>::cast(object()), representation, field_index);
ObjectData* result(property.data());
- own_properties_.insert(std::make_pair(field_index, result));
+ own_properties_.insert(std::make_pair(field_index.property_index(), result));
return result;
}
@@ -446,6 +456,31 @@ void JSTypedArrayData::Serialize(JSHeapBroker* broker) {
}
}
+class ArrayBoilerplateDescriptionData : public HeapObjectData {
+ public:
+ ArrayBoilerplateDescriptionData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<ArrayBoilerplateDescription> object)
+ : HeapObjectData(broker, storage, object),
+ constants_elements_length_(object->constant_elements().length()) {}
+
+ int constants_elements_length() const { return constants_elements_length_; }
+
+ private:
+ int const constants_elements_length_;
+};
+
+class ObjectBoilerplateDescriptionData : public HeapObjectData {
+ public:
+ ObjectBoilerplateDescriptionData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<ObjectBoilerplateDescription> object)
+ : HeapObjectData(broker, storage, object), size_(object->size()) {}
+
+ int size() const { return size_; }
+
+ private:
+ int const size_;
+};
+
class JSDataViewData : public JSObjectData {
public:
JSDataViewData(JSHeapBroker* broker, ObjectData** storage,
@@ -465,6 +500,7 @@ class JSBoundFunctionData : public JSObjectData {
Handle<JSBoundFunction> object);
void Serialize(JSHeapBroker* broker);
+ bool serialized() const { return serialized_; }
ObjectData* bound_target_function() const { return bound_target_function_; }
ObjectData* bound_this() const { return bound_this_; }
@@ -557,18 +593,6 @@ class HeapNumberData : public HeapObjectData {
double const value_;
};
-class MutableHeapNumberData : public HeapObjectData {
- public:
- MutableHeapNumberData(JSHeapBroker* broker, ObjectData** storage,
- Handle<MutableHeapNumber> object)
- : HeapObjectData(broker, storage, object), value_(object->value()) {}
-
- double value() const { return value_; }
-
- private:
- double const value_;
-};
-
class ContextData : public HeapObjectData {
public:
ContextData(JSHeapBroker* broker, ObjectData** storage,
@@ -576,12 +600,15 @@ class ContextData : public HeapObjectData {
// {previous} will return the closest valid context possible to desired
// {depth}, decrementing {depth} for each previous link successfully followed.
- // If {serialize} is true, it will serialize contexts along the way.
- ContextData* previous(JSHeapBroker* broker, size_t* depth, bool serialize);
+ ContextData* previous(
+ JSHeapBroker* broker, size_t* depth,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
- // Returns nullptr if the slot index isn't valid or wasn't serialized
- // (unless {serialize} is true).
- ObjectData* GetSlot(JSHeapBroker* broker, int index, bool serialize);
+ // Returns nullptr if the slot index isn't valid or wasn't serialized,
+ // unless {policy} is {kSerializeIfNeeded}.
+ ObjectData* GetSlot(
+ JSHeapBroker* broker, int index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
private:
ZoneMap<int, ObjectData*> slots_;
@@ -593,10 +620,11 @@ ContextData::ContextData(JSHeapBroker* broker, ObjectData** storage,
: HeapObjectData(broker, storage, object), slots_(broker->zone()) {}
ContextData* ContextData::previous(JSHeapBroker* broker, size_t* depth,
- bool serialize) {
+ SerializationPolicy policy) {
if (*depth == 0) return this;
- if (serialize && previous_ == nullptr) {
+ if (policy == SerializationPolicy::kSerializeIfNeeded &&
+ previous_ == nullptr) {
TraceScope tracer(broker, this, "ContextData::previous");
Handle<Context> context = Handle<Context>::cast(object());
Object prev = context->unchecked_previous();
@@ -607,20 +635,20 @@ ContextData* ContextData::previous(JSHeapBroker* broker, size_t* depth,
if (previous_ != nullptr) {
*depth = *depth - 1;
- return previous_->previous(broker, depth, serialize);
+ return previous_->previous(broker, depth, policy);
}
return this;
}
ObjectData* ContextData::GetSlot(JSHeapBroker* broker, int index,
- bool serialize) {
+ SerializationPolicy policy) {
CHECK_GE(index, 0);
auto search = slots_.find(index);
if (search != slots_.end()) {
return search->second;
}
- if (serialize) {
+ if (policy == SerializationPolicy::kSerializeIfNeeded) {
Handle<Context> context = Handle<Context>::cast(object());
if (index < context->length()) {
TraceScope tracer(broker, this, "ContextData::GetSlot");
@@ -680,8 +708,9 @@ class StringData : public NameData {
bool is_external_string() const { return is_external_string_; }
bool is_seq_string() const { return is_seq_string_; }
- StringData* GetCharAsString(JSHeapBroker* broker, uint32_t index,
- bool serialize);
+ StringData* GetCharAsString(
+ JSHeapBroker* broker, uint32_t index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
private:
int const length_;
@@ -730,14 +759,14 @@ class InternalizedStringData : public StringData {
};
StringData* StringData::GetCharAsString(JSHeapBroker* broker, uint32_t index,
- bool serialize) {
+ SerializationPolicy policy) {
if (index >= static_cast<uint32_t>(length())) return nullptr;
for (auto const& p : chars_as_strings_) {
if (p.first == index) return p.second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about index " << index << " on " << this);
return nullptr;
}
@@ -842,6 +871,12 @@ bool IsInlinableFastLiteral(Handle<JSObject> boilerplate) {
} // namespace
+class AccessorInfoData : public HeapObjectData {
+ public:
+ AccessorInfoData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<AccessorInfo> object);
+};
+
class AllocationSiteData : public HeapObjectData {
public:
AllocationSiteData(JSHeapBroker* broker, ObjectData** storage,
@@ -891,6 +926,7 @@ class ScriptContextTableData : public HeapObjectData {
struct PropertyDescriptor {
NameData* key = nullptr;
+ ObjectData* value = nullptr;
PropertyDetails details = PropertyDetails::Empty();
FieldIndex field_index;
MapData* field_owner = nullptr;
@@ -926,8 +962,11 @@ class MapData : public HeapObjectData {
bool supports_fast_array_resize() const {
return supports_fast_array_resize_;
}
- bool IsMapOfCurrentGlobalProxy() const {
- return is_map_of_current_global_proxy_;
+ bool IsMapOfTargetGlobalProxy() const {
+ return is_map_of_target_global_proxy_;
+ }
+ bool is_abandoned_prototype_map() const {
+ return is_abandoned_prototype_map_;
}
// Extra information.
@@ -942,10 +981,14 @@ class MapData : public HeapObjectData {
// on field owner(s).
void SerializeOwnDescriptor(JSHeapBroker* broker, int descriptor_index);
void SerializeOwnDescriptors(JSHeapBroker* broker);
+ ObjectData* GetStrongValue(int descriptor_index) const;
DescriptorArrayData* instance_descriptors() const {
return instance_descriptors_;
}
+ void SerializeRootMap(JSHeapBroker* broker);
+ MapData* FindRootMap() const;
+
void SerializeConstructor(JSHeapBroker* broker);
ObjectData* GetConstructor() const {
CHECK(serialized_constructor_);
@@ -984,7 +1027,8 @@ class MapData : public HeapObjectData {
int const unused_property_fields_;
bool const supports_fast_array_iteration_;
bool const supports_fast_array_resize_;
- bool const is_map_of_current_global_proxy_;
+ bool const is_map_of_target_global_proxy_;
+ bool const is_abandoned_prototype_map_;
bool serialized_elements_kind_generalizations_ = false;
ZoneVector<MapData*> elements_kind_generalizations_;
@@ -1001,11 +1045,18 @@ class MapData : public HeapObjectData {
bool serialized_prototype_ = false;
ObjectData* prototype_ = nullptr;
+ bool serialized_root_map_ = false;
+ MapData* root_map_ = nullptr;
+
bool serialized_for_element_load_ = false;
bool serialized_for_element_store_ = false;
};
+AccessorInfoData::AccessorInfoData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<AccessorInfo> object)
+ : HeapObjectData(broker, storage, object) {}
+
AllocationSiteData::AllocationSiteData(JSHeapBroker* broker,
ObjectData** storage,
Handle<AllocationSite> object)
@@ -1103,8 +1154,9 @@ MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object)
SupportsFastArrayIteration(broker->isolate(), object)),
supports_fast_array_resize_(
SupportsFastArrayResize(broker->isolate(), object)),
- is_map_of_current_global_proxy_(
- object->IsMapOfGlobalProxy(broker->isolate()->native_context())),
+ is_map_of_target_global_proxy_(
+ object->IsMapOfGlobalProxy(broker->target_native_context().object())),
+ is_abandoned_prototype_map_(object->is_abandoned_prototype_map()),
elements_kind_generalizations_(broker->zone()) {}
JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
@@ -1210,28 +1262,52 @@ FeedbackCellData::FeedbackCellData(JSHeapBroker* broker, ObjectData** storage,
class FeedbackVectorData : public HeapObjectData {
public:
- const ZoneVector<ObjectData*>& feedback() { return feedback_; }
-
FeedbackVectorData(JSHeapBroker* broker, ObjectData** storage,
Handle<FeedbackVector> object);
- void SerializeSlots(JSHeapBroker* broker);
+ double invocation_count() const { return invocation_count_; }
+
+ void Serialize(JSHeapBroker* broker);
+ const ZoneVector<ObjectData*>& feedback() { return feedback_; }
+ FeedbackCellData* GetClosureFeedbackCell(JSHeapBroker* broker,
+ int index) const;
private:
+ double const invocation_count_;
+
bool serialized_ = false;
ZoneVector<ObjectData*> feedback_;
+ ZoneVector<ObjectData*> closure_feedback_cell_array_;
};
FeedbackVectorData::FeedbackVectorData(JSHeapBroker* broker,
ObjectData** storage,
Handle<FeedbackVector> object)
- : HeapObjectData(broker, storage, object), feedback_(broker->zone()) {}
+ : HeapObjectData(broker, storage, object),
+ invocation_count_(object->invocation_count()),
+ feedback_(broker->zone()),
+ closure_feedback_cell_array_(broker->zone()) {}
+
+FeedbackCellData* FeedbackVectorData::GetClosureFeedbackCell(
+ JSHeapBroker* broker, int index) const {
+ CHECK_GE(index, 0);
+
+ size_t cell_array_size = closure_feedback_cell_array_.size();
+ if (!serialized_) {
+ DCHECK_EQ(cell_array_size, 0);
+ TRACE_BROKER_MISSING(broker,
+ " closure feedback cell array for vector " << this);
+ return nullptr;
+ }
+ CHECK_LT(index, cell_array_size);
+ return closure_feedback_cell_array_[index]->AsFeedbackCell();
+}
-void FeedbackVectorData::SerializeSlots(JSHeapBroker* broker) {
+void FeedbackVectorData::Serialize(JSHeapBroker* broker) {
if (serialized_) return;
serialized_ = true;
- TraceScope tracer(broker, this, "FeedbackVectorData::SerializeSlots");
+ TraceScope tracer(broker, this, "FeedbackVectorData::Serialize");
Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(object());
DCHECK(feedback_.empty());
feedback_.reserve(vector->length());
@@ -1252,6 +1328,16 @@ void FeedbackVectorData::SerializeSlots(JSHeapBroker* broker) {
}
DCHECK_EQ(vector->length(), feedback_.size());
TRACE(broker, "Copied " << feedback_.size() << " slots");
+
+ DCHECK(closure_feedback_cell_array_.empty());
+ int length = vector->closure_feedback_cell_array().length();
+ closure_feedback_cell_array_.reserve(length);
+ for (int i = 0; i < length; ++i) {
+ Handle<FeedbackCell> cell = vector->GetClosureFeedbackCell(i);
+ ObjectData* cell_data = broker->GetOrCreateData(cell);
+ closure_feedback_cell_array_.push_back(cell_data);
+ }
+ TRACE(broker, "Copied " << length << " feedback cells");
}
class FixedArrayBaseData : public HeapObjectData {
@@ -1300,21 +1386,26 @@ void JSBoundFunctionData::Serialize(JSHeapBroker* broker) {
Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object());
DCHECK_NULL(bound_target_function_);
- DCHECK_NULL(bound_this_);
- DCHECK_NULL(bound_arguments_);
-
bound_target_function_ =
broker->GetOrCreateData(function->bound_target_function());
- bound_this_ = broker->GetOrCreateData(function->bound_this());
+ if (bound_target_function_->IsJSBoundFunction()) {
+ bound_target_function_->AsJSBoundFunction()->Serialize(broker);
+ } else if (bound_target_function_->IsJSFunction()) {
+ bound_target_function_->AsJSFunction()->Serialize(broker);
+ }
+
+ DCHECK_NULL(bound_arguments_);
bound_arguments_ =
broker->GetOrCreateData(function->bound_arguments())->AsFixedArray();
-
bound_arguments_->SerializeContents(broker);
+
+ DCHECK_NULL(bound_this_);
+ bound_this_ = broker->GetOrCreateData(function->bound_this());
}
JSObjectData::JSObjectData(JSHeapBroker* broker, ObjectData** storage,
Handle<JSObject> object)
- : HeapObjectData(broker, storage, object),
+ : JSReceiverData(broker, storage, object),
inobject_fields_(broker->zone()),
own_constant_elements_(broker->zone()),
own_properties_(broker->zone()) {}
@@ -1494,8 +1585,9 @@ class JSArrayData : public JSObjectData {
void Serialize(JSHeapBroker* broker);
ObjectData* length() const { return length_; }
- ObjectData* GetOwnElement(JSHeapBroker* broker, uint32_t index,
- bool serialize);
+ ObjectData* GetOwnElement(
+ JSHeapBroker* broker, uint32_t index,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
private:
bool serialized_ = false;
@@ -1524,12 +1616,12 @@ void JSArrayData::Serialize(JSHeapBroker* broker) {
}
ObjectData* JSArrayData::GetOwnElement(JSHeapBroker* broker, uint32_t index,
- bool serialize) {
+ SerializationPolicy policy) {
for (auto const& p : own_elements_) {
if (p.first == index) return p.second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about index " << index << " on " << this);
return nullptr;
}
@@ -1654,7 +1746,7 @@ class SourceTextModuleData : public HeapObjectData {
Handle<SourceTextModule> object);
void Serialize(JSHeapBroker* broker);
- CellData* GetCell(int cell_index) const;
+ CellData* GetCell(JSHeapBroker* broker, int cell_index) const;
private:
bool serialized_ = false;
@@ -1669,8 +1761,14 @@ SourceTextModuleData::SourceTextModuleData(JSHeapBroker* broker,
imports_(broker->zone()),
exports_(broker->zone()) {}
-CellData* SourceTextModuleData::GetCell(int cell_index) const {
- CHECK(serialized_);
+CellData* SourceTextModuleData::GetCell(JSHeapBroker* broker,
+ int cell_index) const {
+ if (!serialized_) {
+ DCHECK(imports_.empty());
+ TRACE_BROKER_MISSING(broker,
+ "module cell " << cell_index << " on " << this);
+ return nullptr;
+ }
CellData* cell;
switch (SourceTextModuleDescriptor::GetCellIndexKind(cell_index)) {
case SourceTextModuleDescriptor::kImport:
@@ -1741,13 +1839,25 @@ void CellData::Serialize(JSHeapBroker* broker) {
value_ = broker->GetOrCreateData(cell->value());
}
+class JSGlobalObjectData : public JSObjectData {
+ public:
+ JSGlobalObjectData(JSHeapBroker* broker, ObjectData** storage,
+ Handle<JSGlobalObject> object);
+};
+
+JSGlobalObjectData::JSGlobalObjectData(JSHeapBroker* broker,
+ ObjectData** storage,
+ Handle<JSGlobalObject> object)
+ : JSObjectData(broker, storage, object) {}
+
class JSGlobalProxyData : public JSObjectData {
public:
JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage,
Handle<JSGlobalProxy> object);
- PropertyCellData* GetPropertyCell(JSHeapBroker* broker, NameData* name,
- bool serialize);
+ PropertyCellData* GetPropertyCell(
+ JSHeapBroker* broker, NameData* name,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
private:
// Properties that either
@@ -1764,10 +1874,11 @@ JSGlobalProxyData::JSGlobalProxyData(JSHeapBroker* broker, ObjectData** storage,
namespace {
base::Optional<PropertyCellRef> GetPropertyCellFromHeap(JSHeapBroker* broker,
Handle<Name> name) {
- LookupIterator it(broker->isolate(),
- handle(broker->native_context().object()->global_object(),
- broker->isolate()),
- name, LookupIterator::OWN);
+ LookupIterator it(
+ broker->isolate(),
+ handle(broker->target_native_context().object()->global_object(),
+ broker->isolate()),
+ name, LookupIterator::OWN);
it.TryLookupCachedProperty();
if (it.state() == LookupIterator::DATA &&
it.GetHolder<JSObject>()->IsJSGlobalObject()) {
@@ -1777,15 +1888,14 @@ base::Optional<PropertyCellRef> GetPropertyCellFromHeap(JSHeapBroker* broker,
}
} // namespace
-PropertyCellData* JSGlobalProxyData::GetPropertyCell(JSHeapBroker* broker,
- NameData* name,
- bool serialize) {
+PropertyCellData* JSGlobalProxyData::GetPropertyCell(
+ JSHeapBroker* broker, NameData* name, SerializationPolicy policy) {
CHECK_NOT_NULL(name);
for (auto const& p : properties_) {
if (p.first == name) return p.second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_MISSING(broker, "knowledge about global property " << name);
return nullptr;
}
@@ -1896,6 +2006,13 @@ void MapData::SerializeOwnDescriptors(JSHeapBroker* broker) {
}
}
+ObjectData* MapData::GetStrongValue(int descriptor_index) const {
+ auto data = instance_descriptors_->contents().find(descriptor_index);
+ if (data == instance_descriptors_->contents().end()) return nullptr;
+
+ return data->second.value;
+}
+
void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
int descriptor_index) {
TraceScope tracer(broker, this, "MapData::SerializeOwnDescriptor");
@@ -1907,7 +2024,7 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
}
ZoneMap<int, PropertyDescriptor>& contents =
- instance_descriptors_->contents();
+ instance_descriptors()->contents();
CHECK_LT(descriptor_index, map->NumberOfOwnDescriptors());
if (contents.find(descriptor_index) != contents.end()) return;
@@ -1919,6 +2036,11 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
PropertyDescriptor d;
d.key =
broker->GetOrCreateData(descriptors->GetKey(descriptor_index))->AsName();
+ MaybeObject value = descriptors->GetValue(descriptor_index);
+ HeapObject obj;
+ if (value.GetHeapObjectIfStrong(&obj)) {
+ d.value = broker->GetOrCreateData(handle(obj, broker->isolate()));
+ }
d.details = descriptors->GetDetails(descriptor_index);
if (d.details.location() == kField) {
d.field_index = FieldIndex::ForDescriptor(*map, descriptor_index);
@@ -1941,6 +2063,19 @@ void MapData::SerializeOwnDescriptor(JSHeapBroker* broker,
<< contents.size() << " total)");
}
+void MapData::SerializeRootMap(JSHeapBroker* broker) {
+ if (serialized_root_map_) return;
+ serialized_root_map_ = true;
+
+ TraceScope tracer(broker, this, "MapData::SerializeRootMap");
+ Handle<Map> map = Handle<Map>::cast(object());
+ DCHECK_NULL(root_map_);
+ root_map_ =
+ broker->GetOrCreateData(map->FindRootMap(broker->isolate()))->AsMap();
+}
+
+MapData* MapData::FindRootMap() const { return root_map_; }
+
void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
int depth) {
if (serialized_as_boilerplate_) return;
@@ -2029,15 +2164,16 @@ void JSObjectData::SerializeRecursiveAsBoilerplate(JSHeapBroker* broker,
} else {
Handle<Object> value(boilerplate->RawFastPropertyAt(field_index),
isolate);
- // In case of unboxed double fields we use a sentinel NaN value to mark
+ // In case of double fields we use a sentinel NaN value to mark
// uninitialized fields. A boilerplate value with such a field may migrate
- // from its unboxed double to a tagged representation. In the process the
- // raw double is converted to a heap number. The sentinel value carries no
- // special meaning when it occurs in a heap number, so we would like to
- // recover the uninitialized value.
- // We check for the sentinel here, specifically, since migrations might
- // have been triggered as part of boilerplate serialization.
- if (value->IsHeapNumber() &&
+ // from its double to a tagged representation. If the double is unboxed,
+ // the raw double is converted to a heap number, otherwise the (boxed)
+ // double ceases to be mutable, and becomes a normal heap number. The
+ // sentinel value carries no special meaning when it occurs in a heap
+ // number, so we would like to recover the uninitialized value. We check
+ // for the sentinel here, specifically, since migrations might have been
+ // triggered as part of boilerplate serialization.
+ if (!details.representation().IsDouble() && value->IsHeapNumber() &&
HeapNumber::cast(*value).value_as_bits() == kHoleNanInt64) {
value = isolate->factory()->uninitialized_value();
}
@@ -2079,7 +2215,8 @@ bool ObjectRef::equals(const ObjectRef& other) const {
Isolate* ObjectRef::isolate() const { return broker()->isolate(); }
-ContextRef ContextRef::previous(size_t* depth, bool serialize) const {
+ContextRef ContextRef::previous(size_t* depth,
+ SerializationPolicy policy) const {
DCHECK_NOT_NULL(depth);
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
@@ -2092,10 +2229,11 @@ ContextRef ContextRef::previous(size_t* depth, bool serialize) const {
return ContextRef(broker(), handle(current, broker()->isolate()));
}
ContextData* current = this->data()->AsContext();
- return ContextRef(broker(), current->previous(broker(), depth, serialize));
+ return ContextRef(broker(), current->previous(broker(), depth, policy));
}
-base::Optional<ObjectRef> ContextRef::get(int index, bool serialize) const {
+base::Optional<ObjectRef> ContextRef::get(int index,
+ SerializationPolicy policy) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
AllowHandleDereference handle_dereference;
@@ -2103,7 +2241,7 @@ base::Optional<ObjectRef> ContextRef::get(int index, bool serialize) const {
return ObjectRef(broker(), value);
}
ObjectData* optional_slot =
- data()->AsContext()->GetSlot(broker(), index, serialize);
+ data()->AsContext()->GetSlot(broker(), index, policy);
if (optional_slot != nullptr) {
return ObjectRef(broker(), optional_slot);
}
@@ -2121,13 +2259,13 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
tracing_enabled_(tracing_enabled),
feedback_(zone()),
bytecode_analyses_(zone()),
- ais_for_loading_then_(zone()),
- ais_for_loading_exec_(zone()) {
- // Note that this initialization of the refs_ pointer with the minimal
- // initial capacity is redundant in the normal use case (concurrent
- // compilation enabled, standard objects to be serialized), as the map
- // is going to be replaced immediatelly with a larger capacity one.
- // It doesn't seem to affect the performance in a noticeable way though.
+ property_access_infos_(zone()),
+ typed_array_string_tags_(zone()) {
+ // Note that this initialization of {refs_} with the minimal initial capacity
+ // is redundant in the normal use case (concurrent compilation enabled,
+ // standard objects to be serialized), as the map is going to be replaced
+ // immediately with a larger-capacity one. It doesn't seem to affect the
+ // performance in a noticeable way though.
TRACE(this, "Constructing heap broker");
}
@@ -2136,13 +2274,6 @@ std::ostream& JSHeapBroker::Trace() {
<< std::string(trace_indentation_ * 2, ' ');
}
-void JSHeapBroker::StartSerializing() {
- CHECK_EQ(mode_, kDisabled);
- TRACE(this, "Starting serialization");
- mode_ = kSerializing;
- refs_->Clear();
-}
-
void JSHeapBroker::StopSerializing() {
CHECK_EQ(mode_, kSerializing);
TRACE(this, "Stopping serialization");
@@ -2157,39 +2288,54 @@ void JSHeapBroker::Retire() {
bool JSHeapBroker::SerializingAllowed() const { return mode() == kSerializing; }
-void JSHeapBroker::SetNativeContextRef() {
- native_context_ = NativeContextRef(this, isolate()->native_context());
+void JSHeapBroker::SetTargetNativeContextRef(
+ Handle<NativeContext> native_context) {
+ // The MapData constructor uses {target_native_context_}. This creates a
+ // benign cycle that we break by setting {target_native_context_} right before
+ // starting to serialize (thus creating dummy data), and then again properly
+ // right after.
+ DCHECK((mode() == kDisabled && !target_native_context_.has_value()) ||
+ (mode() == kSerializing &&
+ target_native_context_->object().equals(native_context) &&
+ target_native_context_->data_->kind() == kUnserializedHeapObject));
+ target_native_context_ = NativeContextRef(this, native_context);
}
bool IsShareable(Handle<Object> object, Isolate* isolate) {
- Builtins* const b = isolate->builtins();
-
int index;
RootIndex root_index;
- return (object->IsHeapObject() &&
- b->IsBuiltinHandle(Handle<HeapObject>::cast(object), &index)) ||
+ bool is_builtin_handle =
+ object->IsHeapObject() && isolate->builtins()->IsBuiltinHandle(
+ Handle<HeapObject>::cast(object), &index);
+ return is_builtin_handle ||
isolate->roots_table().IsRootHandle(object, &root_index);
}
-void JSHeapBroker::SerializeShareableObjects() {
+void JSHeapBroker::InitializeRefsMap() {
+ TraceScope tracer(this, "JSHeapBroker::InitializeRefsMap");
+
+ DCHECK_NULL(compiler_cache_);
PerIsolateCompilerCache::Setup(isolate());
compiler_cache_ = isolate()->compiler_cache();
if (compiler_cache_->HasSnapshot()) {
- RefsMap* snapshot = compiler_cache_->GetSnapshot();
-
- refs_ = new (zone()) RefsMap(snapshot, zone());
+ TRACE(this, "Importing existing RefsMap snapshot");
+ DCHECK_NULL(refs_);
+ refs_ = new (zone()) RefsMap(compiler_cache_->GetSnapshot(), zone());
return;
}
- TraceScope tracer(
- this, "JSHeapBroker::SerializeShareableObjects (building snapshot)");
-
+ TRACE(this, "Building RefsMap snapshot");
+ DCHECK_NULL(refs_);
refs_ =
new (zone()) RefsMap(kInitialRefsBucketCount, AddressMatcher(), zone());
+ // Temporarily use the "compiler zone" for serialization, such that the
+ // serialized data survives this compilation.
+ DCHECK_EQ(current_zone_, broker_zone_);
current_zone_ = compiler_cache_->zone();
+ // Serialize various builtins.
Builtins* const b = isolate()->builtins();
{
Builtins::Name builtins[] = {
@@ -2199,17 +2345,28 @@ void JSHeapBroker::SerializeShareableObjects() {
Builtins::kAllocateRegularInOldGeneration,
Builtins::kArgumentsAdaptorTrampoline,
Builtins::kArrayConstructorImpl,
+ Builtins::kArrayIncludesHoleyDoubles,
+ Builtins::kArrayIncludesPackedDoubles,
+ Builtins::kArrayIncludesSmiOrObject,
+ Builtins::kArrayIndexOfHoleyDoubles,
+ Builtins::kArrayIndexOfPackedDoubles,
+ Builtins::kArrayIndexOfSmiOrObject,
+ Builtins::kCallApiCallback,
Builtins::kCallFunctionForwardVarargs,
Builtins::kCallFunction_ReceiverIsAny,
Builtins::kCallFunction_ReceiverIsNotNullOrUndefined,
Builtins::kCallFunction_ReceiverIsNullOrUndefined,
+ Builtins::kCloneFastJSArray,
+ Builtins::kCompileLazy,
Builtins::kConstructFunctionForwardVarargs,
Builtins::kForInFilter,
+ Builtins::kGetProperty,
+ Builtins::kIncBlockCounter,
Builtins::kJSBuiltinsConstructStub,
Builtins::kJSConstructStubGeneric,
Builtins::kStringAdd_CheckNone,
- Builtins::kStringAdd_ConvertLeft,
- Builtins::kStringAdd_ConvertRight,
+ Builtins::kStringAddConvertLeft,
+ Builtins::kStringAddConvertRight,
Builtins::kToNumber,
Builtins::kToObject,
};
@@ -2223,12 +2380,13 @@ void JSHeapBroker::SerializeShareableObjects() {
}
}
+ // TODO(mslekova): Serialize root objects (from factory).
+
+ // Verify.
for (RefsMap::Entry* p = refs_->Start(); p != nullptr; p = refs_->Next(p)) {
CHECK(IsShareable(p->value->object(), isolate()));
}
- // TODO(mslekova):
- // Serialize root objects (from factory).
compiler_cache()->SetSnapshot(refs_);
current_zone_ = broker_zone_;
}
@@ -2252,6 +2410,25 @@ void JSHeapBroker::CollectArrayAndObjectPrototypes() {
CHECK(!array_and_object_prototypes_.empty());
}
+void JSHeapBroker::SerializeTypedArrayStringTags() {
+#define TYPED_ARRAY_STRING_TAG(Type, type, TYPE, ctype) \
+ do { \
+ ObjectData* data = GetOrCreateData( \
+ isolate()->factory()->InternalizeUtf8String(#Type "Array")); \
+ typed_array_string_tags_.push_back(data); \
+ } while (false);
+
+ TYPED_ARRAYS(TYPED_ARRAY_STRING_TAG)
+#undef TYPED_ARRAY_STRING_TAG
+}
+
+StringRef JSHeapBroker::GetTypedArrayStringTag(ElementsKind kind) {
+ DCHECK(IsTypedArrayElementsKind(kind));
+ size_t idx = kind - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND;
+ CHECK_LT(idx, typed_array_string_tags_.size());
+ return StringRef(this, typed_array_string_tags_[idx]);
+}
+
bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
if (mode() == kDisabled) {
return isolate()->IsInAnyContext(*object.object(),
@@ -2264,22 +2441,29 @@ bool JSHeapBroker::IsArrayOrObjectPrototype(const JSObjectRef& object) const {
array_and_object_prototypes_.end();
}
-void JSHeapBroker::SerializeStandardObjects() {
- if (mode() == kDisabled) return;
- CHECK_EQ(mode(), kSerializing);
+void JSHeapBroker::InitializeAndStartSerializing(
+ Handle<NativeContext> native_context) {
+ TraceScope tracer(this, "JSHeapBroker::InitializeAndStartSerializing");
- SerializeShareableObjects();
+ CHECK_EQ(mode_, kDisabled);
+ mode_ = kSerializing;
- TraceScope tracer(this, "JSHeapBroker::SerializeStandardObjects");
+ // Throw away the dummy data that we created while disabled.
+ refs_->Clear();
+ refs_ = nullptr;
- CollectArrayAndObjectPrototypes();
+ InitializeRefsMap();
- SetNativeContextRef();
- native_context().Serialize();
+ SetTargetNativeContextRef(native_context);
+ target_native_context().Serialize();
- Factory* const f = isolate()->factory();
+ CollectArrayAndObjectPrototypes();
+ SerializeTypedArrayStringTags();
- // Maps, strings, oddballs
+ // Serialize standard objects.
+ //
+ // - Maps, strings, oddballs
+ Factory* const f = isolate()->factory();
GetOrCreateData(f->arguments_marker_map());
GetOrCreateData(f->bigint_string());
GetOrCreateData(f->block_context_map());
@@ -2300,7 +2484,6 @@ void JSHeapBroker::SerializeStandardObjects() {
GetOrCreateData(f->length_string());
GetOrCreateData(f->many_closures_cell_map());
GetOrCreateData(f->minus_zero_value());
- GetOrCreateData(f->mutable_heap_number_map());
GetOrCreateData(f->name_dictionary_map());
GetOrCreateData(f->NaN_string());
GetOrCreateData(f->null_map());
@@ -2312,6 +2495,8 @@ void JSHeapBroker::SerializeStandardObjects() {
GetOrCreateData(f->optimized_out());
GetOrCreateData(f->optimized_out_map());
GetOrCreateData(f->property_array_map());
+ GetOrCreateData(f->ReflectHas_string());
+ GetOrCreateData(f->ReflectGet_string());
GetOrCreateData(f->sloppy_arguments_elements_map());
GetOrCreateData(f->stale_register());
GetOrCreateData(f->stale_register_map());
@@ -2328,8 +2513,7 @@ void JSHeapBroker::SerializeStandardObjects() {
GetOrCreateData(f->uninitialized_map());
GetOrCreateData(f->with_context_map());
GetOrCreateData(f->zero_string());
-
- // Protector cells
+ // - Cells
GetOrCreateData(f->array_buffer_detaching_protector())
->AsPropertyCell()
->Serialize(this);
@@ -2340,6 +2524,7 @@ void JSHeapBroker::SerializeStandardObjects() {
GetOrCreateData(f->array_species_protector())
->AsPropertyCell()
->Serialize(this);
+ GetOrCreateData(f->many_closures_cell())->AsFeedbackCell();
GetOrCreateData(f->no_elements_protector())
->AsPropertyCell()
->Serialize(this);
@@ -2353,8 +2538,7 @@ void JSHeapBroker::SerializeStandardObjects() {
->AsPropertyCell()
->Serialize(this);
GetOrCreateData(f->string_length_protector())->AsCell()->Serialize(this);
-
- // CEntry stub
+ // - CEntry stub
GetOrCreateData(
CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, true));
@@ -2425,7 +2609,7 @@ base::Optional<MapRef> JSObjectRef::GetObjectCreateMap() const {
return base::Optional<MapRef>();
}
}
- MapData* map_data = data()->AsJSObject()->object_create_map();
+ MapData* map_data = data()->AsJSObject()->object_create_map(broker());
return map_data != nullptr ? MapRef(broker(), map_data)
: base::Optional<MapRef>();
}
@@ -2535,13 +2719,14 @@ bool MapRef::supports_fast_array_resize() const {
return data()->AsMap()->supports_fast_array_resize();
}
-bool MapRef::IsMapOfCurrentGlobalProxy() const {
+bool MapRef::IsMapOfTargetGlobalProxy() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation handle_allocation;
- return object()->IsMapOfGlobalProxy(broker()->isolate()->native_context());
+ return object()->IsMapOfGlobalProxy(
+ broker()->target_native_context().object());
}
- return data()->AsMap()->IsMapOfCurrentGlobalProxy();
+ return data()->AsMap()->IsMapOfTargetGlobalProxy();
}
int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const {
@@ -2612,6 +2797,18 @@ ObjectRef FeedbackVectorRef::get(FeedbackSlot slot) const {
return ObjectRef(broker(), data()->AsFeedbackVector()->feedback().at(i));
}
+FeedbackCellRef FeedbackVectorRef::GetClosureFeedbackCell(int index) const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleAllocation handle_allocation;
+ AllowHandleDereference handle_dereference;
+ return FeedbackCellRef(broker(), object()->GetClosureFeedbackCell(index));
+ }
+
+ return FeedbackCellRef(
+ broker(),
+ data()->AsFeedbackVector()->GetClosureFeedbackCell(broker(), index));
+}
+
double JSObjectRef::RawFastDoublePropertyAt(FieldIndex index) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference handle_dereference;
@@ -2789,6 +2986,22 @@ base::Optional<double> StringRef::ToNumber() {
return data()->AsString()->to_number();
}
+int ArrayBoilerplateDescriptionRef::constants_elements_length() const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleDereference allow_handle_dereference;
+ return object()->constant_elements().length();
+ }
+ return data()->AsArrayBoilerplateDescription()->constants_elements_length();
+}
+
+int ObjectBoilerplateDescriptionRef::size() const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleDereference allow_handle_dereference;
+ return object()->size();
+ }
+ return data()->AsObjectBoilerplateDescription()->size();
+}
+
ObjectRef FixedArrayRef::get(int i) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
@@ -2954,11 +3167,13 @@ BIMODAL_ACCESSOR_C(BytecodeArray, interpreter::Register,
BIMODAL_ACCESSOR(Cell, Object, value)
+BIMODAL_ACCESSOR_C(FeedbackVector, double, invocation_count)
+
BIMODAL_ACCESSOR(HeapObject, Map, map)
BIMODAL_ACCESSOR(JSArray, Object, length)
-BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_target_function)
+BIMODAL_ACCESSOR(JSBoundFunction, JSReceiver, bound_target_function)
BIMODAL_ACCESSOR(JSBoundFunction, Object, bound_this)
BIMODAL_ACCESSOR(JSBoundFunction, FixedArray, bound_arguments)
@@ -3003,6 +3218,7 @@ BIMODAL_ACCESSOR(Map, HeapObject, prototype)
BIMODAL_ACCESSOR_C(Map, InstanceType, instance_type)
BIMODAL_ACCESSOR(Map, Object, GetConstructor)
BIMODAL_ACCESSOR(Map, HeapObject, GetBackPointer)
+BIMODAL_ACCESSOR_C(Map, bool, is_abandoned_prototype_map)
#define DEF_NATIVE_CONTEXT_ACCESSOR(type, name) \
BIMODAL_ACCESSOR(NativeContext, type, name)
@@ -3047,7 +3263,7 @@ bool FunctionTemplateInfoRef::has_call_code() const {
BIMODAL_ACCESSOR_C(FunctionTemplateInfo, bool, accept_any_receiver)
HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
- MapRef receiver_map, bool serialize) {
+ MapRef receiver_map, SerializationPolicy policy) {
const HolderLookupResult not_found;
if (broker()->mode() == JSHeapBroker::kDisabled) {
@@ -3083,7 +3299,7 @@ HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
if (lookup_it != fti_data->known_receivers().cend()) {
return lookup_it->second;
}
- if (!serialize) {
+ if (policy == SerializationPolicy::kAssumeSerialized) {
TRACE_BROKER_MISSING(broker(),
"holder for receiver with map " << receiver_map);
return not_found;
@@ -3129,6 +3345,37 @@ BIMODAL_ACCESSOR_C(String, int, length)
BIMODAL_ACCESSOR(FeedbackCell, HeapObject, value)
+ObjectRef MapRef::GetStrongValue(int descriptor_index) const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleDereference allow_handle_dereference;
+ return ObjectRef(broker(),
+ handle(object()->instance_descriptors().GetStrongValue(
+ descriptor_index),
+ broker()->isolate()));
+ }
+ return ObjectRef(broker(), data()->AsMap()->GetStrongValue(descriptor_index));
+}
+
+void MapRef::SerializeRootMap() {
+ if (broker()->mode() == JSHeapBroker::kDisabled) return;
+ CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
+ data()->AsMap()->SerializeRootMap(broker());
+}
+
+base::Optional<MapRef> MapRef::FindRootMap() const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) {
+ AllowHandleDereference allow_handle_dereference;
+ return MapRef(broker(), handle(object()->FindRootMap(broker()->isolate()),
+ broker()->isolate()));
+ }
+ MapData* map_data = data()->AsMap()->FindRootMap();
+ if (map_data) {
+ return MapRef(broker(), map_data);
+ }
+ TRACE_BROKER_MISSING(broker(), "root map for object " << *this);
+ return base::nullopt;
+}
+
void* JSTypedArrayRef::external_pointer() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
@@ -3297,7 +3544,7 @@ Maybe<double> ObjectRef::OddballToNumber() const {
}
base::Optional<ObjectRef> ObjectRef::GetOwnConstantElement(
- uint32_t index, bool serialize) const {
+ uint32_t index, SerializationPolicy policy) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
return (IsJSObject() || IsString())
? GetOwnElementFromHeap(broker(), object(), index, true)
@@ -3306,35 +3553,36 @@ base::Optional<ObjectRef> ObjectRef::GetOwnConstantElement(
ObjectData* element = nullptr;
if (IsJSObject()) {
element =
- data()->AsJSObject()->GetOwnConstantElement(broker(), index, serialize);
+ data()->AsJSObject()->GetOwnConstantElement(broker(), index, policy);
} else if (IsString()) {
- element = data()->AsString()->GetCharAsString(broker(), index, serialize);
+ element = data()->AsString()->GetCharAsString(broker(), index, policy);
}
if (element == nullptr) return base::nullopt;
return ObjectRef(broker(), element);
}
-base::Optional<ObjectRef> JSObjectRef::GetOwnProperty(
+base::Optional<ObjectRef> JSObjectRef::GetOwnDataProperty(
Representation field_representation, FieldIndex index,
- bool serialize) const {
+ SerializationPolicy policy) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
- return GetOwnPropertyFromHeap(broker(), Handle<JSObject>::cast(object()),
- field_representation, index);
+ return GetOwnDataPropertyFromHeap(broker(),
+ Handle<JSObject>::cast(object()),
+ field_representation, index);
}
- ObjectData* property = data()->AsJSObject()->GetOwnProperty(
- broker(), field_representation, index, serialize);
+ ObjectData* property = data()->AsJSObject()->GetOwnDataProperty(
+ broker(), field_representation, index, policy);
if (property == nullptr) return base::nullopt;
return ObjectRef(broker(), property);
}
-base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement(uint32_t index,
- bool serialize) const {
+base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement(
+ uint32_t index, SerializationPolicy policy) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
if (!object()->elements().IsCowArray()) return base::nullopt;
return GetOwnElementFromHeap(broker(), object(), index, false);
}
- if (serialize) {
+ if (policy == SerializationPolicy::kSerializeIfNeeded) {
data()->AsJSObject()->SerializeElements(broker());
} else if (!data()->AsJSObject()->serialized_elements()) {
TRACE(broker(), "'elements' on " << this);
@@ -3343,7 +3591,7 @@ base::Optional<ObjectRef> JSArrayRef::GetOwnCowElement(uint32_t index,
if (!elements().map().IsFixedCowArrayMap()) return base::nullopt;
ObjectData* element =
- data()->AsJSArray()->GetOwnElement(broker(), index, serialize);
+ data()->AsJSArray()->GetOwnElement(broker(), index, policy);
if (element == nullptr) return base::nullopt;
return ObjectRef(broker(), element);
}
@@ -3353,27 +3601,25 @@ double HeapNumberRef::value() const {
return data()->AsHeapNumber()->value();
}
-double MutableHeapNumberRef::value() const {
- IF_BROKER_DISABLED_ACCESS_HANDLE_C(MutableHeapNumber, value);
- return data()->AsMutableHeapNumber()->value();
-}
-
uint64_t BigIntRef::AsUint64() const {
IF_BROKER_DISABLED_ACCESS_HANDLE_C(BigInt, AsUint64);
return data()->AsBigInt()->AsUint64();
}
-CellRef SourceTextModuleRef::GetCell(int cell_index) const {
+base::Optional<CellRef> SourceTextModuleRef::GetCell(int cell_index) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
AllowHandleDereference allow_handle_dereference;
return CellRef(broker(),
handle(object()->GetCell(cell_index), broker()->isolate()));
}
- return CellRef(broker(), data()->AsSourceTextModule()->GetCell(cell_index));
+ CellData* cell = data()->AsSourceTextModule()->GetCell(broker(), cell_index);
+ if (cell == nullptr) return base::nullopt;
+ return CellRef(broker(), cell);
}
-ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object)
+ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object,
+ bool check_type)
: broker_(broker) {
switch (broker->mode()) {
case JSHeapBroker::kSerialized:
@@ -3398,6 +3644,10 @@ ObjectRef::ObjectRef(JSHeapBroker* broker, Handle<Object> object)
case JSHeapBroker::kRetired:
UNREACHABLE();
}
+ if (!data_) { // TODO(mslekova): Remove once we're on the background thread.
+ AllowHandleDereference handle_dereference;
+ object->Print();
+ }
CHECK_WITH_MSG(data_ != nullptr, "Object is not known to the heap broker");
}
@@ -3489,8 +3739,8 @@ Float64 FixedDoubleArrayData::Get(int i) const {
return contents_[i];
}
-void FeedbackVectorRef::SerializeSlots() {
- data()->AsFeedbackVector()->SerializeSlots(broker());
+void FeedbackVectorRef::Serialize() {
+ data()->AsFeedbackVector()->Serialize(broker());
}
bool NameRef::IsUniqueName() const {
@@ -3597,8 +3847,13 @@ void JSFunctionRef::Serialize() {
data()->AsJSFunction()->Serialize(broker());
}
+bool JSBoundFunctionRef::serialized() const {
+ if (broker()->mode() == JSHeapBroker::kDisabled) return true;
+ return data()->AsJSBoundFunction()->serialized();
+}
+
bool JSFunctionRef::serialized() const {
- CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
+ if (broker()->mode() == JSHeapBroker::kDisabled) return true;
return data()->AsJSFunction()->serialized();
}
@@ -3614,10 +3869,9 @@ bool JSFunctionRef::IsSerializedForCompilation() const {
shared().IsSerializedForCompilation(feedback_vector());
}
-JSArrayRef SharedFunctionInfoRef::GetTemplateObject(ObjectRef description,
- FeedbackVectorRef vector,
- FeedbackSlot slot,
- bool serialize) {
+JSArrayRef SharedFunctionInfoRef::GetTemplateObject(
+ ObjectRef description, FeedbackVectorRef vector, FeedbackSlot slot,
+ SerializationPolicy policy) {
// Look in the feedback vector for the array. A Smi indicates that it's
// not yet cached here.
ObjectRef candidate = vector.get(slot);
@@ -3632,22 +3886,22 @@ JSArrayRef SharedFunctionInfoRef::GetTemplateObject(ObjectRef description,
Handle<TemplateObjectDescription>::cast(description.object());
Handle<JSArray> template_object =
TemplateObjectDescription::GetTemplateObject(
- broker()->isolate(), broker()->native_context().object(), tod,
- object(), slot.ToInt());
+ broker()->isolate(), broker()->target_native_context().object(),
+ tod, object(), slot.ToInt());
return JSArrayRef(broker(), template_object);
}
JSArrayData* array = data()->AsSharedFunctionInfo()->GetTemplateObject(slot);
if (array != nullptr) return JSArrayRef(broker(), array);
- CHECK(serialize);
+ CHECK_EQ(policy, SerializationPolicy::kSerializeIfNeeded);
CHECK(broker()->SerializingAllowed());
Handle<TemplateObjectDescription> tod =
Handle<TemplateObjectDescription>::cast(description.object());
Handle<JSArray> template_object =
TemplateObjectDescription::GetTemplateObject(
- broker()->isolate(), broker()->native_context().object(), tod,
+ broker()->isolate(), broker()->target_native_context().object(), tod,
object(), slot.ToInt());
array = broker()->GetOrCreateData(template_object)->AsJSArray();
data()->AsSharedFunctionInfo()->SetTemplateObject(slot, array);
@@ -3663,15 +3917,17 @@ void SharedFunctionInfoRef::SetSerializedForCompilation(
void SharedFunctionInfoRef::SerializeFunctionTemplateInfo() {
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
-
data()->AsSharedFunctionInfo()->SerializeFunctionTemplateInfo(broker());
}
base::Optional<FunctionTemplateInfoRef>
SharedFunctionInfoRef::function_template_info() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
- return FunctionTemplateInfoRef(
- broker(), handle(object()->function_data(), broker()->isolate()));
+ if (object()->IsApiFunction()) {
+ return FunctionTemplateInfoRef(
+ broker(), handle(object()->function_data(), broker()->isolate()));
+ }
+ return base::nullopt;
}
FunctionTemplateInfoData* function_template_info =
data()->AsSharedFunctionInfo()->function_template_info();
@@ -3703,6 +3959,16 @@ void MapRef::SerializeOwnDescriptor(int descriptor_index) {
data()->AsMap()->SerializeOwnDescriptor(broker(), descriptor_index);
}
+bool MapRef::serialized_own_descriptor(int descriptor_index) const {
+ CHECK_LT(descriptor_index, NumberOfOwnDescriptors());
+ if (broker()->mode() == JSHeapBroker::kDisabled) return true;
+ DescriptorArrayData* desc_array_data =
+ data()->AsMap()->instance_descriptors();
+ if (!desc_array_data) return false;
+ return desc_array_data->contents().find(descriptor_index) !=
+ desc_array_data->contents().end();
+}
+
void MapRef::SerializeBackPointer() {
if (broker()->mode() == JSHeapBroker::kDisabled) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
@@ -3762,13 +4028,13 @@ void FunctionTemplateInfoRef::SerializeCallCode() {
}
base::Optional<PropertyCellRef> JSGlobalProxyRef::GetPropertyCell(
- NameRef const& name, bool serialize) const {
+ NameRef const& name, SerializationPolicy policy) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
return GetPropertyCellFromHeap(broker(), name.object());
}
PropertyCellData* property_cell_data =
- data()->AsJSGlobalProxy()->GetPropertyCell(
- broker(), name.data()->AsName(), serialize);
+ data()->AsJSGlobalProxy()->GetPropertyCell(broker(),
+ name.data()->AsName(), policy);
if (property_cell_data == nullptr) return base::nullopt;
return PropertyCellRef(broker(), property_cell_data);
}
@@ -3787,64 +4053,133 @@ bool CanInlineElementAccess(MapRef const& map) {
return false;
}
-InsufficientFeedback::InsufficientFeedback()
- : ProcessedFeedback(kInsufficient) {}
+ProcessedFeedback::ProcessedFeedback(Kind kind, FeedbackSlotKind slot_kind)
+ : kind_(kind), slot_kind_(slot_kind) {}
+
+KeyedAccessMode ElementAccessFeedback::keyed_mode() const {
+ return keyed_mode_;
+}
+
+ZoneVector<ElementAccessFeedback::TransitionGroup> const&
+ElementAccessFeedback::transition_groups() const {
+ return transition_groups_;
+}
+
+ElementAccessFeedback const& ElementAccessFeedback::Refine(
+ ZoneVector<Handle<Map>> const& inferred_maps, Zone* zone) const {
+ ElementAccessFeedback& refined_feedback =
+ *new (zone) ElementAccessFeedback(zone, keyed_mode(), slot_kind());
+ if (inferred_maps.empty()) return refined_feedback;
+
+ ZoneUnorderedSet<Handle<Map>, Handle<Map>::hash, Handle<Map>::equal_to>
+ inferred(zone);
+ inferred.insert(inferred_maps.begin(), inferred_maps.end());
+
+ for (auto const& group : transition_groups()) {
+ DCHECK(!group.empty());
+ TransitionGroup new_group(zone);
+ for (size_t i = 1; i < group.size(); ++i) {
+ Handle<Map> source = group[i];
+ if (inferred.find(source) != inferred.end()) {
+ new_group.push_back(source);
+ }
+ }
+
+ Handle<Map> target = group.front();
+ bool const keep_target =
+ inferred.find(target) != inferred.end() || new_group.size() > 1;
+ if (keep_target) {
+ new_group.push_back(target);
+ // The target must be at the front, the order of sources doesn't matter.
+ std::swap(new_group[0], new_group[new_group.size() - 1]);
+ }
+
+ if (!new_group.empty()) {
+ DCHECK(new_group.size() == 1 || new_group.front().equals(target));
+ refined_feedback.transition_groups_.push_back(std::move(new_group));
+ }
+ }
+ return refined_feedback;
+}
+
+InsufficientFeedback::InsufficientFeedback(FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kInsufficient, slot_kind) {}
-GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell)
- : ProcessedFeedback(kGlobalAccess),
+GlobalAccessFeedback::GlobalAccessFeedback(PropertyCellRef cell,
+ FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kGlobalAccess, slot_kind),
cell_or_context_(cell),
- index_and_immutable_(0 /* doesn't matter */) {}
+ index_and_immutable_(0 /* doesn't matter */) {
+ DCHECK(IsGlobalICKind(slot_kind));
+}
+
+GlobalAccessFeedback::GlobalAccessFeedback(FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kGlobalAccess, slot_kind),
+ index_and_immutable_(0 /* doesn't matter */) {
+ DCHECK(IsGlobalICKind(slot_kind));
+}
GlobalAccessFeedback::GlobalAccessFeedback(ContextRef script_context,
- int slot_index, bool immutable)
- : ProcessedFeedback(kGlobalAccess),
+ int slot_index, bool immutable,
+ FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kGlobalAccess, slot_kind),
cell_or_context_(script_context),
index_and_immutable_(FeedbackNexus::SlotIndexBits::encode(slot_index) |
FeedbackNexus::ImmutabilityBit::encode(immutable)) {
DCHECK_EQ(this->slot_index(), slot_index);
DCHECK_EQ(this->immutable(), immutable);
+ DCHECK(IsGlobalICKind(slot_kind));
}
+bool GlobalAccessFeedback::IsMegamorphic() const {
+ return !cell_or_context_.has_value();
+}
bool GlobalAccessFeedback::IsPropertyCell() const {
- return cell_or_context_.IsPropertyCell();
+ return cell_or_context_.has_value() && cell_or_context_->IsPropertyCell();
+}
+bool GlobalAccessFeedback::IsScriptContextSlot() const {
+ return cell_or_context_.has_value() && cell_or_context_->IsContext();
}
PropertyCellRef GlobalAccessFeedback::property_cell() const {
- DCHECK(IsPropertyCell());
- return cell_or_context_.AsPropertyCell();
+ CHECK(IsPropertyCell());
+ return cell_or_context_->AsPropertyCell();
}
ContextRef GlobalAccessFeedback::script_context() const {
- DCHECK(IsScriptContextSlot());
- return cell_or_context_.AsContext();
+ CHECK(IsScriptContextSlot());
+ return cell_or_context_->AsContext();
}
int GlobalAccessFeedback::slot_index() const {
- CHECK(IsScriptContextSlot());
+ DCHECK(IsScriptContextSlot());
return FeedbackNexus::SlotIndexBits::decode(index_and_immutable_);
}
bool GlobalAccessFeedback::immutable() const {
- CHECK(IsScriptContextSlot());
+ DCHECK(IsScriptContextSlot());
return FeedbackNexus::ImmutabilityBit::decode(index_and_immutable_);
}
base::Optional<ObjectRef> GlobalAccessFeedback::GetConstantHint() const {
- if (IsScriptContextSlot()) {
- if (immutable()) return script_context().get(slot_index());
- } else {
+ if (IsPropertyCell()) {
return property_cell().value();
+ } else if (IsScriptContextSlot() && immutable()) {
+ return script_context().get(slot_index());
+ } else {
+ return base::nullopt;
}
- return {};
}
KeyedAccessMode KeyedAccessMode::FromNexus(FeedbackNexus const& nexus) {
- if (IsKeyedLoadICKind(nexus.kind())) {
+ FeedbackSlotKind kind = nexus.kind();
+ if (IsKeyedLoadICKind(kind)) {
return KeyedAccessMode(AccessMode::kLoad, nexus.GetKeyedAccessLoadMode());
}
- if (IsKeyedHasICKind(nexus.kind())) {
+ if (IsKeyedHasICKind(kind)) {
return KeyedAccessMode(AccessMode::kHas, nexus.GetKeyedAccessLoadMode());
}
- if (IsKeyedStoreICKind(nexus.kind())) {
+ if (IsKeyedStoreICKind(kind)) {
return KeyedAccessMode(AccessMode::kStore, nexus.GetKeyedAccessStoreMode());
}
- if (IsStoreInArrayLiteralICKind(nexus.kind())) {
+ if (IsStoreInArrayLiteralICKind(kind) ||
+ IsStoreDataPropertyInLiteralKind(kind)) {
return KeyedAccessMode(AccessMode::kStoreInLiteral,
nexus.GetKeyedAccessStoreMode());
}
@@ -3890,59 +4225,40 @@ KeyedAccessMode::KeyedAccessMode(AccessMode access_mode,
}
ElementAccessFeedback::ElementAccessFeedback(Zone* zone,
- KeyedAccessMode const& keyed_mode)
- : ProcessedFeedback(kElementAccess),
- receiver_maps(zone),
- transitions(zone),
- keyed_mode(keyed_mode) {}
-
-ElementAccessFeedback::MapIterator::MapIterator(
- ElementAccessFeedback const& processed, JSHeapBroker* broker)
- : processed_(processed), broker_(broker) {
- CHECK_LT(processed.receiver_maps.size(),
- std::numeric_limits<size_t>::max() - processed.transitions.size());
-}
-
-bool ElementAccessFeedback::MapIterator::done() const {
- return index_ >=
- processed_.receiver_maps.size() + processed_.transitions.size();
-}
-
-void ElementAccessFeedback::MapIterator::advance() { index_++; }
-
-MapRef ElementAccessFeedback::MapIterator::current() const {
- CHECK(!done());
- size_t receiver_maps_size = processed_.receiver_maps.size();
- Handle<Map> map;
- if (index_ < receiver_maps_size) {
- map = processed_.receiver_maps[index_];
- } else {
- map = processed_.transitions[index_ - receiver_maps_size].first;
+ KeyedAccessMode const& keyed_mode,
+ FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kElementAccess, slot_kind),
+ keyed_mode_(keyed_mode),
+ transition_groups_(zone) {
+ DCHECK(IsKeyedLoadICKind(slot_kind) || IsKeyedHasICKind(slot_kind) ||
+ IsStoreDataPropertyInLiteralKind(slot_kind) ||
+ IsKeyedStoreICKind(slot_kind) ||
+ IsStoreInArrayLiteralICKind(slot_kind));
+}
+
+bool ElementAccessFeedback::HasOnlyStringMaps(JSHeapBroker* broker) const {
+ for (auto const& group : transition_groups()) {
+ for (Handle<Map> map : group) {
+ if (!MapRef(broker, map).IsStringMap()) return false;
+ }
}
- return MapRef(broker_, map);
-}
-
-ElementAccessFeedback::MapIterator ElementAccessFeedback::all_maps(
- JSHeapBroker* broker) const {
- return MapIterator(*this, broker);
+ return true;
}
-NamedAccessFeedback::NamedAccessFeedback(
- NameRef const& name, ZoneVector<PropertyAccessInfo> const& access_infos)
- : ProcessedFeedback(kNamedAccess),
- name_(name),
- access_infos_(access_infos) {
- CHECK(!access_infos.empty());
+NamedAccessFeedback::NamedAccessFeedback(NameRef const& name,
+ ZoneVector<Handle<Map>> const& maps,
+ FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kNamedAccess, slot_kind), name_(name), maps_(maps) {
+ DCHECK(IsLoadICKind(slot_kind) || IsStoreICKind(slot_kind) ||
+ IsStoreOwnICKind(slot_kind) || IsKeyedLoadICKind(slot_kind) ||
+ IsKeyedHasICKind(slot_kind) || IsKeyedStoreICKind(slot_kind) ||
+ IsStoreInArrayLiteralICKind(slot_kind) ||
+ IsStoreDataPropertyInLiteralKind(slot_kind));
}
-FeedbackSource::FeedbackSource(FeedbackNexus const& nexus)
- : vector(nexus.vector_handle()), slot(nexus.slot()) {}
-
-FeedbackSource::FeedbackSource(VectorSlotPair const& pair)
- : vector(pair.vector()), slot(pair.slot()) {}
-
void JSHeapBroker::SetFeedback(FeedbackSource const& source,
ProcessedFeedback const* feedback) {
+ CHECK(source.IsValid());
auto insertion = feedback_.insert({source, feedback});
CHECK(insertion.second);
}
@@ -3951,80 +4267,90 @@ bool JSHeapBroker::HasFeedback(FeedbackSource const& source) const {
return feedback_.find(source) != feedback_.end();
}
-ProcessedFeedback const* JSHeapBroker::GetFeedback(
+ProcessedFeedback const& JSHeapBroker::GetFeedback(
FeedbackSource const& source) const {
+ DCHECK(source.IsValid());
auto it = feedback_.find(source);
CHECK_NE(it, feedback_.end());
- return it->second;
+ return *it->second;
}
-GlobalAccessFeedback const* JSHeapBroker::GetGlobalAccessFeedback(
+FeedbackSlotKind JSHeapBroker::GetFeedbackSlotKind(
FeedbackSource const& source) const {
- ProcessedFeedback const* feedback = GetFeedback(source);
- if (feedback == nullptr) return nullptr;
- CHECK_EQ(feedback->kind(), ProcessedFeedback::kGlobalAccess);
- return static_cast<GlobalAccessFeedback const*>(feedback);
-}
-
-ElementAccessFeedback const* JSHeapBroker::ProcessFeedbackMapsForElementAccess(
- MapHandles const& maps, KeyedAccessMode const& keyed_mode) {
- DCHECK(!maps.empty());
-
- // Collect possible transition targets.
- MapHandles possible_transition_targets;
- possible_transition_targets.reserve(maps.size());
- for (Handle<Map> map : maps) {
- if (CanInlineElementAccess(MapRef(this, map)) &&
- IsFastElementsKind(map->elements_kind()) &&
- GetInitialFastElementsKind() != map->elements_kind()) {
- possible_transition_targets.push_back(map);
- }
+ if (FLAG_concurrent_inlining) {
+ ProcessedFeedback const& processed = GetFeedback(source);
+ return processed.slot_kind();
}
+ FeedbackNexus nexus(source.vector, source.slot);
+ return nexus.kind();
+}
- ElementAccessFeedback* result =
- new (zone()) ElementAccessFeedback(zone(), keyed_mode);
+bool JSHeapBroker::FeedbackIsInsufficient(FeedbackSource const& source) const {
+ return FLAG_concurrent_inlining
+ ? GetFeedback(source).IsInsufficient()
+ : FeedbackNexus(source.vector, source.slot).IsUninitialized();
+}
- // Separate the actual receiver maps and the possible transition sources.
+namespace {
+MapHandles GetRelevantReceiverMaps(Isolate* isolate, MapHandles const& maps) {
+ MapHandles result;
for (Handle<Map> map : maps) {
- // Don't generate elements kind transitions from stable maps.
- Map transition_target = map->is_stable()
- ? Map()
- : map->FindElementsKindTransitionedMap(
- isolate(), possible_transition_targets);
- if (transition_target.is_null()) {
- result->receiver_maps.push_back(map);
- } else {
- result->transitions.emplace_back(map,
- handle(transition_target, isolate()));
+ if (Map::TryUpdate(isolate, map).ToHandle(&map) &&
+ !map->is_abandoned_prototype_map()) {
+ DCHECK(!map->is_deprecated());
+ result.push_back(map);
}
}
+ return result;
+} // namespace
+} // namespace
-#ifdef ENABLE_SLOW_DCHECKS
- // No transition sources appear in {receiver_maps}.
- // All transition targets appear in {receiver_maps}.
- for (auto& transition : result->transitions) {
- CHECK(std::none_of(
- result->receiver_maps.cbegin(), result->receiver_maps.cend(),
- [&](Handle<Map> map) { return map.equals(transition.first); }));
- CHECK(std::any_of(
- result->receiver_maps.cbegin(), result->receiver_maps.cend(),
- [&](Handle<Map> map) { return map.equals(transition.second); }));
+ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess(
+ FeedbackSource const& source, AccessMode mode,
+ base::Optional<NameRef> static_name) {
+ FeedbackNexus nexus(source.vector, source.slot);
+ FeedbackSlotKind kind = nexus.kind();
+ if (nexus.IsUninitialized()) return *new (zone()) InsufficientFeedback(kind);
+
+ MapHandles maps;
+ nexus.ExtractMaps(&maps);
+ DCHECK_NE(nexus.ic_state(), PREMONOMORPHIC);
+ if (!maps.empty()) {
+ maps = GetRelevantReceiverMaps(isolate(), maps);
+ if (maps.empty()) return *new (zone()) InsufficientFeedback(kind);
+ }
+
+ base::Optional<NameRef> name =
+ static_name.has_value() ? static_name : GetNameFeedback(nexus);
+ if (name.has_value()) {
+ return *new (zone()) NamedAccessFeedback(
+ *name, ZoneVector<Handle<Map>>(maps.begin(), maps.end(), zone()), kind);
+ } else if (nexus.GetKeyType() == ELEMENT && !maps.empty()) {
+ return ProcessFeedbackMapsForElementAccess(
+ maps, KeyedAccessMode::FromNexus(nexus), kind);
+ } else {
+ // No actionable feedback.
+ DCHECK(maps.empty());
+ // TODO(neis): Investigate if we really want to treat cleared the same as
+ // megamorphic (also for global accesses).
+ // TODO(neis): Using ElementAccessFeedback here is kind of an abuse.
+ return *new (zone())
+ ElementAccessFeedback(zone(), KeyedAccessMode::FromNexus(nexus), kind);
}
-#endif
- CHECK(!result->receiver_maps.empty());
-
- return result;
}
-GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
+ProcessedFeedback const& JSHeapBroker::ReadFeedbackForGlobalAccess(
FeedbackSource const& source) {
FeedbackNexus nexus(source.vector, source.slot);
DCHECK(nexus.kind() == FeedbackSlotKind::kLoadGlobalInsideTypeof ||
nexus.kind() == FeedbackSlotKind::kLoadGlobalNotInsideTypeof ||
nexus.kind() == FeedbackSlotKind::kStoreGlobalSloppy ||
nexus.kind() == FeedbackSlotKind::kStoreGlobalStrict);
+ if (nexus.IsUninitialized()) {
+ return *new (zone()) InsufficientFeedback(nexus.kind());
+ }
if (nexus.ic_state() != MONOMORPHIC || nexus.GetFeedback()->IsCleared()) {
- return nullptr;
+ return *new (zone()) GlobalAccessFeedback(nexus.kind());
}
Handle<Object> feedback_value(nexus.GetFeedback()->GetHeapObjectOrSmi(),
@@ -4039,7 +4365,7 @@ GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
int const context_slot_index = FeedbackNexus::SlotIndexBits::decode(number);
bool const immutable = FeedbackNexus::ImmutabilityBit::decode(number);
Handle<Context> context = ScriptContextTable::GetContext(
- isolate(), native_context().script_context_table().object(),
+ isolate(), target_native_context().script_context_table().object(),
script_context_index);
{
ObjectRef contents(this,
@@ -4049,10 +4375,11 @@ GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
}
ContextRef context_ref(this, context);
if (immutable) {
- context_ref.get(context_slot_index, true);
+ context_ref.get(context_slot_index,
+ SerializationPolicy::kSerializeIfNeeded);
}
- return new (zone())
- GlobalAccessFeedback(context_ref, context_slot_index, immutable);
+ return *new (zone()) GlobalAccessFeedback(context_ref, context_slot_index,
+ immutable, nexus.kind());
}
CHECK(feedback_value->IsPropertyCell());
@@ -4060,11 +4387,275 @@ GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
// object and the feedback is the cell holding its value.
PropertyCellRef cell(this, Handle<PropertyCell>::cast(feedback_value));
cell.Serialize();
- return new (zone()) GlobalAccessFeedback(cell);
+ return *new (zone()) GlobalAccessFeedback(cell, nexus.kind());
+}
+
+BinaryOperationHint JSHeapBroker::ReadFeedbackForBinaryOperation(
+ FeedbackSource const& source) const {
+ return FeedbackNexus(source.vector, source.slot).GetBinaryOperationFeedback();
+}
+
+CompareOperationHint JSHeapBroker::ReadFeedbackForCompareOperation(
+ FeedbackSource const& source) const {
+ return FeedbackNexus(source.vector, source.slot)
+ .GetCompareOperationFeedback();
+}
+
+ForInHint JSHeapBroker::ReadFeedbackForForIn(
+ FeedbackSource const& source) const {
+ return FeedbackNexus(source.vector, source.slot).GetForInFeedback();
+}
+
+ProcessedFeedback const& JSHeapBroker::ReadFeedbackForInstanceOf(
+ FeedbackSource const& source) {
+ FeedbackNexus nexus(source.vector, source.slot);
+ if (nexus.IsUninitialized())
+ return *new (zone()) InsufficientFeedback(nexus.kind());
+
+ base::Optional<JSObjectRef> optional_constructor;
+ {
+ MaybeHandle<JSObject> maybe_constructor = nexus.GetConstructorFeedback();
+ Handle<JSObject> constructor;
+ if (maybe_constructor.ToHandle(&constructor)) {
+ optional_constructor = JSObjectRef(this, constructor);
+ }
+ }
+ return *new (zone()) InstanceOfFeedback(optional_constructor, nexus.kind());
+}
+
+ProcessedFeedback const& JSHeapBroker::ReadFeedbackForCall(
+ FeedbackSource const& source) {
+ FeedbackNexus nexus(source.vector, source.slot);
+ if (nexus.IsUninitialized())
+ return *new (zone()) InsufficientFeedback(nexus.kind());
+
+ base::Optional<HeapObjectRef> target_ref;
+ {
+ MaybeObject maybe_target = nexus.GetFeedback();
+ HeapObject target_object;
+ if (maybe_target->GetHeapObject(&target_object)) {
+ target_ref = HeapObjectRef(this, handle(target_object, isolate()));
+ }
+ }
+ float frequency = nexus.ComputeCallFrequency();
+ SpeculationMode mode = nexus.GetSpeculationMode();
+ return *new (zone()) CallFeedback(target_ref, frequency, mode, nexus.kind());
+}
+
+BinaryOperationHint JSHeapBroker::GetFeedbackForBinaryOperation(
+ FeedbackSource const& source) {
+ ProcessedFeedback const& feedback =
+ FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForBinaryOperation(source);
+ return feedback.IsInsufficient() ? BinaryOperationHint::kNone
+ : feedback.AsBinaryOperation().value();
+}
+
+CompareOperationHint JSHeapBroker::GetFeedbackForCompareOperation(
+ FeedbackSource const& source) {
+ ProcessedFeedback const& feedback =
+ FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForCompareOperation(source);
+ return feedback.IsInsufficient() ? CompareOperationHint::kNone
+ : feedback.AsCompareOperation().value();
+}
+
+ForInHint JSHeapBroker::GetFeedbackForForIn(FeedbackSource const& source) {
+ ProcessedFeedback const& feedback = FLAG_concurrent_inlining
+ ? GetFeedback(source)
+ : ProcessFeedbackForForIn(source);
+ return feedback.IsInsufficient() ? ForInHint::kNone
+ : feedback.AsForIn().value();
+}
+
+ProcessedFeedback const& JSHeapBroker::GetFeedbackForPropertyAccess(
+ FeedbackSource const& source, AccessMode mode,
+ base::Optional<NameRef> static_name) {
+ return FLAG_concurrent_inlining
+ ? GetFeedback(source)
+ : ProcessFeedbackForPropertyAccess(source, mode, static_name);
+}
+
+ProcessedFeedback const& JSHeapBroker::GetFeedbackForInstanceOf(
+ FeedbackSource const& source) {
+ return FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForInstanceOf(source);
+}
+
+ProcessedFeedback const& JSHeapBroker::GetFeedbackForCall(
+ FeedbackSource const& source) {
+ return FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForCall(source);
+}
+
+ProcessedFeedback const& JSHeapBroker::GetFeedbackForGlobalAccess(
+ FeedbackSource const& source) {
+ return FLAG_concurrent_inlining ? GetFeedback(source)
+ : ProcessFeedbackForGlobalAccess(source);
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForBinaryOperation(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ BinaryOperationHint hint = ReadFeedbackForBinaryOperation(source);
+ ProcessedFeedback const* feedback;
+ if (hint == BinaryOperationHint::kNone) {
+ feedback =
+ new (zone()) InsufficientFeedback(source.vector->GetKind(source.slot));
+ } else {
+ feedback = new (zone())
+ BinaryOperationFeedback(hint, source.vector->GetKind(source.slot));
+ }
+ SetFeedback(source, feedback);
+ return *feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForCompareOperation(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ CompareOperationHint hint = ReadFeedbackForCompareOperation(source);
+ ProcessedFeedback const* feedback;
+ if (hint == CompareOperationHint::kNone) {
+ feedback =
+ new (zone()) InsufficientFeedback(source.vector->GetKind(source.slot));
+ } else {
+ feedback = new (zone())
+ CompareOperationFeedback(hint, source.vector->GetKind(source.slot));
+ }
+ SetFeedback(source, feedback);
+ return *feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForForIn(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ForInHint hint = ReadFeedbackForForIn(source);
+ ProcessedFeedback const* feedback;
+ if (hint == ForInHint::kNone) {
+ feedback =
+ new (zone()) InsufficientFeedback(source.vector->GetKind(source.slot));
+ } else {
+ feedback =
+ new (zone()) ForInFeedback(hint, source.vector->GetKind(source.slot));
+ }
+ SetFeedback(source, feedback);
+ return *feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForPropertyAccess(
+ FeedbackSource const& source, AccessMode mode,
+ base::Optional<NameRef> static_name) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ProcessedFeedback const& feedback =
+ ReadFeedbackForPropertyAccess(source, mode, static_name);
+ SetFeedback(source, &feedback);
+ return feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForInstanceOf(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ProcessedFeedback const& feedback = ReadFeedbackForInstanceOf(source);
+ SetFeedback(source, &feedback);
+ return feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForCall(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ProcessedFeedback const& feedback = ReadFeedbackForCall(source);
+ SetFeedback(source, &feedback);
+ return feedback;
+}
+
+ProcessedFeedback const& JSHeapBroker::ProcessFeedbackForGlobalAccess(
+ FeedbackSource const& source) {
+ if (HasFeedback(source)) return GetFeedback(source);
+ ProcessedFeedback const& feedback = ReadFeedbackForGlobalAccess(source);
+ SetFeedback(source, &feedback);
+ return feedback;
+}
+
+ElementAccessFeedback const& JSHeapBroker::ProcessFeedbackMapsForElementAccess(
+ MapHandles const& maps, KeyedAccessMode const& keyed_mode,
+ FeedbackSlotKind slot_kind) {
+ DCHECK(!maps.empty());
+
+ // Collect possible transition targets.
+ MapHandles possible_transition_targets;
+ possible_transition_targets.reserve(maps.size());
+ for (Handle<Map> map : maps) {
+ MapRef map_ref(this, map);
+ map_ref.SerializeRootMap();
+
+ if (CanInlineElementAccess(map_ref) &&
+ IsFastElementsKind(map->elements_kind()) &&
+ GetInitialFastElementsKind() != map->elements_kind()) {
+ possible_transition_targets.push_back(map);
+ }
+ }
+
+ using TransitionGroup = ElementAccessFeedback::TransitionGroup;
+ ZoneUnorderedMap<Handle<Map>, TransitionGroup, Handle<Map>::hash,
+ Handle<Map>::equal_to>
+ transition_groups(zone());
+
+ // Separate the actual receiver maps and the possible transition sources.
+ for (Handle<Map> map : maps) {
+ // Don't generate elements kind transitions from stable maps.
+ Map transition_target = map->is_stable()
+ ? Map()
+ : map->FindElementsKindTransitionedMap(
+ isolate(), possible_transition_targets);
+ if (transition_target.is_null()) {
+ TransitionGroup group(1, map, zone());
+ transition_groups.insert({map, group});
+ } else {
+ Handle<Map> target(transition_target, isolate());
+ TransitionGroup new_group(1, target, zone());
+ TransitionGroup& actual_group =
+ transition_groups.insert({target, new_group}).first->second;
+ actual_group.push_back(map);
+ }
+ }
+
+ ElementAccessFeedback* result =
+ new (zone()) ElementAccessFeedback(zone(), keyed_mode, slot_kind);
+ for (auto entry : transition_groups) {
+ result->AddGroup(std::move(entry.second));
+ }
+
+ CHECK(!result->transition_groups().empty());
+ return *result;
+}
+
+void ElementAccessFeedback::AddGroup(TransitionGroup&& group) {
+ CHECK(!group.empty());
+ transition_groups_.push_back(std::move(group));
+
+#ifdef ENABLE_SLOW_DCHECKS
+ // Check that each of the group's maps occurs exactly once in the whole
+ // feedback. This implies that "a source is not a target".
+ for (Handle<Map> map : group) {
+ int count = 0;
+ for (TransitionGroup const& some_group : transition_groups()) {
+ count += std::count_if(
+ some_group.begin(), some_group.end(),
+ [&](Handle<Map> some_map) { return some_map.equals(map); });
+ }
+ CHECK_EQ(count, 1);
+ }
+#endif
}
std::ostream& operator<<(std::ostream& os, const ObjectRef& ref) {
- return os << ref.data();
+ if (ref.broker()->mode() == JSHeapBroker::kDisabled) {
+ // If the broker is disabled we cannot be in a background thread so it's
+ // safe to read the heap.
+ return os << ref.data() << " {" << ref.object() << "}";
+ } else {
+ return os << ref.data();
+ }
}
base::Optional<NameRef> JSHeapBroker::GetNameFeedback(
@@ -4074,67 +4665,77 @@ base::Optional<NameRef> JSHeapBroker::GetNameFeedback(
return NameRef(this, handle(raw_name, isolate()));
}
-PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingThen(MapRef map) {
- auto access_info = ais_for_loading_then_.find(map);
- if (access_info == ais_for_loading_then_.end()) {
- TRACE_BROKER_MISSING(
- this, "access info for reducing JSResolvePromise with map " << map);
+PropertyAccessInfo JSHeapBroker::GetPropertyAccessInfo(
+ MapRef map, NameRef name, AccessMode access_mode,
+ CompilationDependencies* dependencies, SerializationPolicy policy) {
+ PropertyAccessTarget target({map, name, access_mode});
+ auto it = property_access_infos_.find(target);
+ if (it != property_access_infos_.end()) return it->second;
+
+ if (policy == SerializationPolicy::kAssumeSerialized) {
+ TRACE_BROKER_MISSING(this, "PropertyAccessInfo for "
+ << access_mode << " of property " << name
+ << " on map " << map);
return PropertyAccessInfo::Invalid(zone());
}
- return access_info->second;
-}
-void JSHeapBroker::CreateAccessInfoForLoadingThen(
- MapRef map, CompilationDependencies* dependencies) {
- auto access_info = ais_for_loading_then_.find(map);
- if (access_info == ais_for_loading_then_.end()) {
- AccessInfoFactory access_info_factory(this, dependencies, zone());
- Handle<Name> then_string = isolate()->factory()->then_string();
- ais_for_loading_then_.insert(
- std::make_pair(map, access_info_factory.ComputePropertyAccessInfo(
- map.object(), then_string, AccessMode::kLoad)));
+ CHECK_NOT_NULL(dependencies);
+ AccessInfoFactory factory(this, dependencies, zone());
+ PropertyAccessInfo access_info = factory.ComputePropertyAccessInfo(
+ map.object(), name.object(), access_mode);
+ if (FLAG_concurrent_inlining) {
+ CHECK(SerializingAllowed());
+ TRACE(this, "Storing PropertyAccessInfo for "
+ << access_mode << " of property " << name << " on map "
+ << map);
+ property_access_infos_.insert({target, access_info});
}
+ return access_info;
}
-PropertyAccessInfo JSHeapBroker::GetAccessInfoForLoadingExec(MapRef map) {
- auto access_info = ais_for_loading_exec_.find(map);
- if (access_info == ais_for_loading_exec_.end()) {
- TRACE_BROKER_MISSING(this,
- "access info for property 'exec' on map " << map);
- return PropertyAccessInfo::Invalid(zone());
- }
- return access_info->second;
+BinaryOperationFeedback const& ProcessedFeedback::AsBinaryOperation() const {
+ CHECK_EQ(kBinaryOperation, kind());
+ return *static_cast<BinaryOperationFeedback const*>(this);
}
-PropertyAccessInfo const& JSHeapBroker::CreateAccessInfoForLoadingExec(
- MapRef map, CompilationDependencies* dependencies) {
- auto access_info = ais_for_loading_exec_.find(map);
- if (access_info != ais_for_loading_exec_.end()) {
- return access_info->second;
- }
-
- ZoneVector<PropertyAccessInfo> access_infos(zone());
- AccessInfoFactory access_info_factory(this, dependencies, zone());
- PropertyAccessInfo ai_exec = access_info_factory.ComputePropertyAccessInfo(
- map.object(), isolate()->factory()->exec_string(), AccessMode::kLoad);
+CallFeedback const& ProcessedFeedback::AsCall() const {
+ CHECK_EQ(kCall, kind());
+ return *static_cast<CallFeedback const*>(this);
+}
- auto inserted_ai = ais_for_loading_exec_.insert(std::make_pair(map, ai_exec));
- return inserted_ai.first->second;
+CompareOperationFeedback const& ProcessedFeedback::AsCompareOperation() const {
+ CHECK_EQ(kCompareOperation, kind());
+ return *static_cast<CompareOperationFeedback const*>(this);
}
-ElementAccessFeedback const* ProcessedFeedback::AsElementAccess() const {
+ElementAccessFeedback const& ProcessedFeedback::AsElementAccess() const {
CHECK_EQ(kElementAccess, kind());
- return static_cast<ElementAccessFeedback const*>(this);
+ return *static_cast<ElementAccessFeedback const*>(this);
+}
+
+ForInFeedback const& ProcessedFeedback::AsForIn() const {
+ CHECK_EQ(kForIn, kind());
+ return *static_cast<ForInFeedback const*>(this);
+}
+
+GlobalAccessFeedback const& ProcessedFeedback::AsGlobalAccess() const {
+ CHECK_EQ(kGlobalAccess, kind());
+ return *static_cast<GlobalAccessFeedback const*>(this);
+}
+
+InstanceOfFeedback const& ProcessedFeedback::AsInstanceOf() const {
+ CHECK_EQ(kInstanceOf, kind());
+ return *static_cast<InstanceOfFeedback const*>(this);
}
-NamedAccessFeedback const* ProcessedFeedback::AsNamedAccess() const {
+NamedAccessFeedback const& ProcessedFeedback::AsNamedAccess() const {
CHECK_EQ(kNamedAccess, kind());
- return static_cast<NamedAccessFeedback const*>(this);
+ return *static_cast<NamedAccessFeedback const*>(this);
}
BytecodeAnalysis const& JSHeapBroker::GetBytecodeAnalysis(
Handle<BytecodeArray> bytecode_array, BailoutId osr_bailout_id,
- bool analyze_liveness, bool serialize) {
+ bool analyze_liveness, SerializationPolicy policy) {
ObjectData* bytecode_array_data = GetData(bytecode_array);
CHECK_NOT_NULL(bytecode_array_data);
@@ -4154,7 +4755,7 @@ BytecodeAnalysis const& JSHeapBroker::GetBytecodeAnalysis(
return *it->second;
}
- CHECK(serialize);
+ CHECK_EQ(policy, SerializationPolicy::kSerializeIfNeeded);
BytecodeAnalysis* analysis = new (zone()) BytecodeAnalysis(
bytecode_array, zone(), osr_bailout_id, analyze_liveness);
DCHECK_EQ(analysis->osr_bailout_id(), osr_bailout_id);
diff --git a/deps/v8/src/compiler/js-heap-broker.h b/deps/v8/src/compiler/js-heap-broker.h
index ffc10d2b93..8c2622bf48 100644
--- a/deps/v8/src/compiler/js-heap-broker.h
+++ b/deps/v8/src/compiler/js-heap-broker.h
@@ -9,6 +9,8 @@
#include "src/base/optional.h"
#include "src/common/globals.h"
#include "src/compiler/access-info.h"
+#include "src/compiler/feedback-source.h"
+#include "src/compiler/processed-feedback.h"
#include "src/compiler/refs-map.h"
#include "src/handles/handles.h"
#include "src/interpreter/bytecode-array-accessor.h"
@@ -26,29 +28,6 @@ class BytecodeAnalysis;
class ObjectRef;
std::ostream& operator<<(std::ostream& os, const ObjectRef& ref);
-struct FeedbackSource {
- FeedbackSource(Handle<FeedbackVector> vector_, FeedbackSlot slot_)
- : vector(vector_), slot(slot_) {}
- explicit FeedbackSource(FeedbackNexus const& nexus);
- explicit FeedbackSource(VectorSlotPair const& pair);
-
- Handle<FeedbackVector> const vector;
- FeedbackSlot const slot;
-
- struct Hash {
- size_t operator()(FeedbackSource const& source) const {
- return base::hash_combine(source.vector.address(), source.slot);
- }
- };
-
- struct Equal {
- bool operator()(FeedbackSource const& lhs,
- FeedbackSource const& rhs) const {
- return lhs.vector.equals(rhs.vector) && lhs.slot == rhs.slot;
- }
- };
-};
-
#define TRACE_BROKER(broker, x) \
do { \
if (broker->tracing_enabled() && FLAG_trace_heap_broker_verbose) \
@@ -58,25 +37,51 @@ struct FeedbackSource {
#define TRACE_BROKER_MISSING(broker, x) \
do { \
if (broker->tracing_enabled()) \
- broker->Trace() << __FUNCTION__ << ": missing " << x << '\n'; \
+ broker->Trace() << "Missing " << x << " (" << __FILE__ << ":" \
+ << __LINE__ << ")" << std::endl; \
} while (false)
+struct PropertyAccessTarget {
+ MapRef map;
+ NameRef name;
+ AccessMode mode;
+
+ struct Hash {
+ size_t operator()(const PropertyAccessTarget& pair) const {
+ return base::hash_combine(
+ base::hash_combine(pair.map.object().address(),
+ pair.name.object().address()),
+ static_cast<int>(pair.mode));
+ }
+ };
+ struct Equal {
+ bool operator()(const PropertyAccessTarget& lhs,
+ const PropertyAccessTarget& rhs) const {
+ return lhs.map.equals(rhs.map) && lhs.name.equals(rhs.name) &&
+ lhs.mode == rhs.mode;
+ }
+ };
+};
+
class V8_EXPORT_PRIVATE JSHeapBroker {
public:
JSHeapBroker(Isolate* isolate, Zone* broker_zone, bool tracing_enabled);
- void SetNativeContextRef();
- void SerializeStandardObjects();
+ // The compilation target's native context. We need the setter because at
+ // broker construction time we don't yet have the canonical handle.
+ NativeContextRef target_native_context() const {
+ return target_native_context_.value();
+ }
+ void SetTargetNativeContextRef(Handle<NativeContext> native_context);
+
+ void InitializeAndStartSerializing(Handle<NativeContext> native_context);
Isolate* isolate() const { return isolate_; }
Zone* zone() const { return current_zone_; }
bool tracing_enabled() const { return tracing_enabled_; }
- NativeContextRef native_context() const { return native_context_.value(); }
- PerIsolateCompilerCache* compiler_cache() const { return compiler_cache_; }
enum BrokerMode { kDisabled, kSerializing, kSerialized, kRetired };
BrokerMode mode() const { return mode_; }
- void StartSerializing();
void StopSerializing();
void Retire();
bool SerializingAllowed() const;
@@ -93,36 +98,64 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
bool IsArrayOrObjectPrototype(const JSObjectRef& object) const;
bool HasFeedback(FeedbackSource const& source) const;
- // The processed {feedback} can be {nullptr}, indicating that the original
- // feedback didn't contain information relevant for Turbofan.
void SetFeedback(FeedbackSource const& source,
ProcessedFeedback const* feedback);
- ProcessedFeedback const* GetFeedback(FeedbackSource const& source) const;
-
- // Convenience wrappers around GetFeedback.
- GlobalAccessFeedback const* GetGlobalAccessFeedback(
- FeedbackSource const& source) const;
+ ProcessedFeedback const& GetFeedback(FeedbackSource const& source) const;
+ FeedbackSlotKind GetFeedbackSlotKind(FeedbackSource const& source) const;
// TODO(neis): Move these into serializer when we're always in the background.
- ElementAccessFeedback const* ProcessFeedbackMapsForElementAccess(
- MapHandles const& maps, KeyedAccessMode const& keyed_mode);
- GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(
- FeedbackSource const& source);
-
+ ElementAccessFeedback const& ProcessFeedbackMapsForElementAccess(
+ MapHandles const& maps, KeyedAccessMode const& keyed_mode,
+ FeedbackSlotKind slot_kind);
BytecodeAnalysis const& GetBytecodeAnalysis(
Handle<BytecodeArray> bytecode_array, BailoutId osr_offset,
- bool analyze_liveness, bool serialize);
+ bool analyze_liveness,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
+
+ // Binary, comparison and for-in hints can be fully expressed via
+ // an enum. Insufficient feedback is signaled by <Hint enum>::kNone.
+ BinaryOperationHint GetFeedbackForBinaryOperation(
+ FeedbackSource const& source);
+ CompareOperationHint GetFeedbackForCompareOperation(
+ FeedbackSource const& source);
+ ForInHint GetFeedbackForForIn(FeedbackSource const& source);
+
+ ProcessedFeedback const& GetFeedbackForCall(FeedbackSource const& source);
+ ProcessedFeedback const& GetFeedbackForGlobalAccess(
+ FeedbackSource const& source);
+ ProcessedFeedback const& GetFeedbackForInstanceOf(
+ FeedbackSource const& source);
+ ProcessedFeedback const& GetFeedbackForPropertyAccess(
+ FeedbackSource const& source, AccessMode mode,
+ base::Optional<NameRef> static_name);
+
+ ProcessedFeedback const& ProcessFeedbackForBinaryOperation(
+ FeedbackSource const& source);
+ ProcessedFeedback const& ProcessFeedbackForCall(FeedbackSource const& source);
+ ProcessedFeedback const& ProcessFeedbackForCompareOperation(
+ FeedbackSource const& source);
+ ProcessedFeedback const& ProcessFeedbackForForIn(
+ FeedbackSource const& source);
+ ProcessedFeedback const& ProcessFeedbackForGlobalAccess(
+ FeedbackSource const& source);
+ ProcessedFeedback const& ProcessFeedbackForInstanceOf(
+ FeedbackSource const& source);
+ ProcessedFeedback const& ProcessFeedbackForPropertyAccess(
+ FeedbackSource const& source, AccessMode mode,
+ base::Optional<NameRef> static_name);
+
+ bool FeedbackIsInsufficient(FeedbackSource const& source) const;
base::Optional<NameRef> GetNameFeedback(FeedbackNexus const& nexus);
- // If there is no result stored for {map}, we return an Invalid
- // PropertyAccessInfo.
- PropertyAccessInfo GetAccessInfoForLoadingThen(MapRef map);
- void CreateAccessInfoForLoadingThen(MapRef map,
- CompilationDependencies* dependencies);
- PropertyAccessInfo GetAccessInfoForLoadingExec(MapRef map);
- PropertyAccessInfo const& CreateAccessInfoForLoadingExec(
- MapRef map, CompilationDependencies* dependencies);
+ // If {policy} is {kAssumeSerialized} and the broker doesn't know about the
+ // combination of {map}, {name}, and {access_mode}, returns Invalid.
+ PropertyAccessInfo GetPropertyAccessInfo(
+ MapRef map, NameRef name, AccessMode access_mode,
+ CompilationDependencies* dependencies = nullptr,
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
+
+ StringRef GetTypedArrayStringTag(ElementsKind kind);
std::ostream& Trace();
void IncrementTracingIndentation();
@@ -133,13 +166,33 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
friend class ObjectRef;
friend class ObjectData;
- void SerializeShareableObjects();
+ // Bottleneck FeedbackNexus access here, for storage in the broker
+ // or on-the-fly usage elsewhere in the compiler.
+ ForInHint ReadFeedbackForForIn(FeedbackSource const& source) const;
+ CompareOperationHint ReadFeedbackForCompareOperation(
+ FeedbackSource const& source) const;
+ BinaryOperationHint ReadFeedbackForBinaryOperation(
+ FeedbackSource const& source) const;
+
+ ProcessedFeedback const& ReadFeedbackForCall(FeedbackSource const& source);
+ ProcessedFeedback const& ReadFeedbackForGlobalAccess(
+ FeedbackSource const& source);
+ ProcessedFeedback const& ReadFeedbackForInstanceOf(
+ FeedbackSource const& source);
+ ProcessedFeedback const& ReadFeedbackForPropertyAccess(
+ FeedbackSource const& source, AccessMode mode,
+ base::Optional<NameRef> static_name);
+
+ void InitializeRefsMap();
void CollectArrayAndObjectPrototypes();
+ void SerializeTypedArrayStringTags();
+
+ PerIsolateCompilerCache* compiler_cache() const { return compiler_cache_; }
Isolate* const isolate_;
Zone* const broker_zone_;
- Zone* current_zone_;
- base::Optional<NativeContextRef> native_context_;
+ Zone* current_zone_ = nullptr;
+ base::Optional<NativeContextRef> target_native_context_;
RefsMap* refs_;
ZoneUnorderedSet<Handle<JSObject>, Handle<JSObject>::hash,
Handle<JSObject>::equal_to>
@@ -148,16 +201,16 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
bool const tracing_enabled_;
StdoutStream trace_out_;
unsigned trace_indentation_ = 0;
- PerIsolateCompilerCache* compiler_cache_;
+ PerIsolateCompilerCache* compiler_cache_ = nullptr;
ZoneUnorderedMap<FeedbackSource, ProcessedFeedback const*,
FeedbackSource::Hash, FeedbackSource::Equal>
feedback_;
ZoneUnorderedMap<ObjectData*, BytecodeAnalysis*> bytecode_analyses_;
- typedef ZoneUnorderedMap<MapRef, PropertyAccessInfo, ObjectRef::Hash,
- ObjectRef::Equal>
- MapToAccessInfos;
- MapToAccessInfos ais_for_loading_then_;
- MapToAccessInfos ais_for_loading_exec_;
+ ZoneUnorderedMap<PropertyAccessTarget, PropertyAccessInfo,
+ PropertyAccessTarget::Hash, PropertyAccessTarget::Equal>
+ property_access_infos_;
+
+ ZoneVector<ObjectData*> typed_array_string_tags_;
static const size_t kMinimalRefsBucketCount = 8; // must be power of 2
static const size_t kInitialRefsBucketCount = 1024; // must be power of 2
diff --git a/deps/v8/src/compiler/js-heap-copy-reducer.cc b/deps/v8/src/compiler/js-heap-copy-reducer.cc
index 7e7c9e3a0e..bf4b79bf92 100644
--- a/deps/v8/src/compiler/js-heap-copy-reducer.cc
+++ b/deps/v8/src/compiler/js-heap-copy-reducer.cc
@@ -27,113 +27,175 @@ JSHeapBroker* JSHeapCopyReducer::broker() { return broker_; }
Reduction JSHeapCopyReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kHeapConstant: {
- ObjectRef object(broker(), HeapConstantOf(node->op()));
- if (object.IsJSFunction()) object.AsJSFunction().Serialize();
- if (object.IsJSObject()) object.AsJSObject().SerializeObjectCreateMap();
- if (object.IsSourceTextModule()) object.AsSourceTextModule().Serialize();
+ if (!FLAG_concurrent_inlining) {
+ ObjectRef object(broker(), HeapConstantOf(node->op()));
+ if (object.IsJSFunction()) object.AsJSFunction().Serialize();
+ if (object.IsJSObject()) {
+ object.AsJSObject().SerializeObjectCreateMap();
+ }
+ if (object.IsSourceTextModule()) {
+ object.AsSourceTextModule().Serialize();
+ }
+ }
break;
}
case IrOpcode::kJSCreateArray: {
- CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
- Handle<AllocationSite> site;
- if (p.site().ToHandle(&site)) AllocationSiteRef(broker(), site);
+ if (!FLAG_concurrent_inlining) {
+ CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
+ Handle<AllocationSite> site;
+ if (p.site().ToHandle(&site)) AllocationSiteRef(broker(), site);
+ }
break;
}
case IrOpcode::kJSCreateArguments: {
- Node* const frame_state = NodeProperties::GetFrameStateInput(node);
- FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
- SharedFunctionInfoRef shared(broker(),
- state_info.shared_info().ToHandleChecked());
+ if (!FLAG_concurrent_inlining) {
+ Node* const frame_state = NodeProperties::GetFrameStateInput(node);
+ FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());
+ SharedFunctionInfoRef shared(
+ broker(), state_info.shared_info().ToHandleChecked());
+ }
break;
}
case IrOpcode::kJSCreateBlockContext: {
- ScopeInfoRef(broker(), ScopeInfoOf(node->op()));
+ if (!FLAG_concurrent_inlining) {
+ ScopeInfoRef(broker(), ScopeInfoOf(node->op()));
+ }
break;
}
case IrOpcode::kJSCreateBoundFunction: {
- CreateBoundFunctionParameters const& p =
- CreateBoundFunctionParametersOf(node->op());
- MapRef(broker(), p.map());
+ if (!FLAG_concurrent_inlining) {
+ CreateBoundFunctionParameters const& p =
+ CreateBoundFunctionParametersOf(node->op());
+ MapRef(broker(), p.map());
+ }
break;
}
case IrOpcode::kJSCreateCatchContext: {
- ScopeInfoRef(broker(), ScopeInfoOf(node->op()));
+ if (!FLAG_concurrent_inlining) {
+ ScopeInfoRef(broker(), ScopeInfoOf(node->op()));
+ }
break;
}
case IrOpcode::kJSCreateClosure: {
- CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
- SharedFunctionInfoRef(broker(), p.shared_info());
- FeedbackCellRef(broker(), p.feedback_cell());
- HeapObjectRef(broker(), p.code());
+ if (!FLAG_concurrent_inlining) {
+ CreateClosureParameters const& p =
+ CreateClosureParametersOf(node->op());
+ SharedFunctionInfoRef(broker(), p.shared_info());
+ FeedbackCellRef(broker(), p.feedback_cell());
+ HeapObjectRef(broker(), p.code());
+ }
break;
}
case IrOpcode::kJSCreateEmptyLiteralArray: {
- FeedbackParameter const& p = FeedbackParameterOf(node->op());
- FeedbackVectorRef(broker(), p.feedback().vector()).SerializeSlots();
+ if (!FLAG_concurrent_inlining) {
+ FeedbackParameter const& p = FeedbackParameterOf(node->op());
+ FeedbackVectorRef(broker(), p.feedback().vector).Serialize();
+ }
break;
}
case IrOpcode::kJSCreateFunctionContext: {
- CreateFunctionContextParameters const& p =
- CreateFunctionContextParametersOf(node->op());
- ScopeInfoRef(broker(), p.scope_info());
+ if (!FLAG_concurrent_inlining) {
+ CreateFunctionContextParameters const& p =
+ CreateFunctionContextParametersOf(node->op());
+ ScopeInfoRef(broker(), p.scope_info());
+ }
break;
}
case IrOpcode::kJSCreateLiteralArray:
case IrOpcode::kJSCreateLiteralObject: {
- CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
- FeedbackVectorRef(broker(), p.feedback().vector()).SerializeSlots();
+ if (!FLAG_concurrent_inlining) {
+ CreateLiteralParameters const& p =
+ CreateLiteralParametersOf(node->op());
+ FeedbackVectorRef(broker(), p.feedback().vector).Serialize();
+ }
break;
}
case IrOpcode::kJSCreateLiteralRegExp: {
- CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op());
- FeedbackVectorRef(broker(), p.feedback().vector()).SerializeSlots();
+ if (!FLAG_concurrent_inlining) {
+ CreateLiteralParameters const& p =
+ CreateLiteralParametersOf(node->op());
+ FeedbackVectorRef(broker(), p.feedback().vector).Serialize();
+ }
break;
}
case IrOpcode::kJSCreateWithContext: {
- ScopeInfoRef(broker(), ScopeInfoOf(node->op()));
+ if (!FLAG_concurrent_inlining) {
+ ScopeInfoRef(broker(), ScopeInfoOf(node->op()));
+ }
+ break;
+ }
+ case IrOpcode::kJSLoadNamed: {
+ if (!FLAG_concurrent_inlining) {
+ NamedAccess const& p = NamedAccessOf(node->op());
+ NameRef name(broker(), p.name());
+ if (p.feedback().IsValid()) {
+ broker()->ProcessFeedbackForPropertyAccess(p.feedback(),
+ AccessMode::kLoad, name);
+ }
+ }
break;
}
- case IrOpcode::kJSLoadNamed:
case IrOpcode::kJSStoreNamed: {
- NamedAccess const& p = NamedAccessOf(node->op());
- NameRef(broker(), p.name());
+ if (!FLAG_concurrent_inlining) {
+ NamedAccess const& p = NamedAccessOf(node->op());
+ NameRef name(broker(), p.name());
+ }
break;
}
case IrOpcode::kStoreField:
case IrOpcode::kLoadField: {
- FieldAccess access = FieldAccessOf(node->op());
- Handle<Map> map_handle;
- if (access.map.ToHandle(&map_handle)) {
- MapRef(broker(), map_handle);
- }
- Handle<Name> name_handle;
- if (access.name.ToHandle(&name_handle)) {
- NameRef(broker(), name_handle);
+ if (!FLAG_concurrent_inlining) {
+ FieldAccess access = FieldAccessOf(node->op());
+ Handle<Map> map_handle;
+ if (access.map.ToHandle(&map_handle)) {
+ MapRef(broker(), map_handle);
+ }
+ Handle<Name> name_handle;
+ if (access.name.ToHandle(&name_handle)) {
+ NameRef(broker(), name_handle);
+ }
}
break;
}
case IrOpcode::kMapGuard: {
- ZoneHandleSet<Map> const& maps = MapGuardMapsOf(node->op());
- for (Handle<Map> map : maps) {
- MapRef(broker(), map);
+ if (!FLAG_concurrent_inlining) {
+ ZoneHandleSet<Map> const& maps = MapGuardMapsOf(node->op());
+ for (Handle<Map> map : maps) {
+ MapRef(broker(), map);
+ }
}
break;
}
case IrOpcode::kCheckMaps: {
- ZoneHandleSet<Map> const& maps = CheckMapsParametersOf(node->op()).maps();
- for (Handle<Map> map : maps) {
- MapRef(broker(), map);
+ if (!FLAG_concurrent_inlining) {
+ ZoneHandleSet<Map> const& maps =
+ CheckMapsParametersOf(node->op()).maps();
+ for (Handle<Map> map : maps) {
+ MapRef(broker(), map);
+ }
}
break;
}
case IrOpcode::kCompareMaps: {
- ZoneHandleSet<Map> const& maps = CompareMapsParametersOf(node->op());
- for (Handle<Map> map : maps) {
- MapRef(broker(), map);
+ if (!FLAG_concurrent_inlining) {
+ ZoneHandleSet<Map> const& maps = CompareMapsParametersOf(node->op());
+ for (Handle<Map> map : maps) {
+ MapRef(broker(), map);
+ }
+ }
+ break;
+ }
+ case IrOpcode::kJSLoadProperty: {
+ if (!FLAG_concurrent_inlining) {
+ PropertyAccess const& p = PropertyAccessOf(node->op());
+ AccessMode access_mode = AccessMode::kLoad;
+ if (p.feedback().IsValid()) {
+ broker()->ProcessFeedbackForPropertyAccess(p.feedback(), access_mode,
+ base::nullopt);
+ }
}
break;
}
-
default:
break;
}
diff --git a/deps/v8/src/compiler/js-inlining-heuristic.cc b/deps/v8/src/compiler/js-inlining-heuristic.cc
index e11d6b59a3..ae271b3af9 100644
--- a/deps/v8/src/compiler/js-inlining-heuristic.cc
+++ b/deps/v8/src/compiler/js-inlining-heuristic.cc
@@ -114,8 +114,8 @@ Reduction JSInliningHeuristic::Reduce(Node* node) {
Handle<SharedFunctionInfo> frame_shared_info;
for (int i = 0; i < candidate.num_functions; ++i) {
if (!candidate.bytecode[i].has_value()) {
- // We're already missing critical data which wouldn't allow us to
- // continue the inlining checks. Log a warning and continue.
+ // Can't inline without bytecode.
+ // TODO(neis): Should this even be a broker message?
if (candidate.functions[i].has_value()) {
TRACE_BROKER(broker(),
"Missing bytecode array trying to inline JSFunction "
@@ -205,6 +205,8 @@ Reduction JSInliningHeuristic::Reduce(Node* node) {
}
void JSInliningHeuristic::Finalize() {
+ DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
+
if (candidates_.empty()) return; // Nothing to do without candidates.
if (FLAG_trace_turbo_inlining) PrintCandidates();
@@ -730,18 +732,22 @@ bool JSInliningHeuristic::CandidateCompare::operator()(
void JSInliningHeuristic::PrintCandidates() {
StdoutStream os;
- os << "Candidates for inlining (size=" << candidates_.size() << "):\n";
+ os << candidates_.size() << " candidate(s) for inlining:" << std::endl;
for (const Candidate& candidate : candidates_) {
- os << " #" << candidate.node->id() << ":"
- << candidate.node->op()->mnemonic()
- << ", frequency: " << candidate.frequency << std::endl;
+ os << "- candidate: " << candidate.node->op()->mnemonic() << " node #"
+ << candidate.node->id() << " with frequency " << candidate.frequency
+ << ", " << candidate.num_functions << " target(s):" << std::endl;
for (int i = 0; i < candidate.num_functions; ++i) {
- SharedFunctionInfoRef shared =
- candidate.functions[i].has_value()
- ? candidate.functions[i].value().shared()
- : candidate.shared_info.value();
- PrintF(" - size:%d, name: %s\n", candidate.bytecode[i].value().length(),
- shared.object()->DebugName().ToCString().get());
+ SharedFunctionInfoRef shared = candidate.functions[i].has_value()
+ ? candidate.functions[i]->shared()
+ : candidate.shared_info.value();
+ os << " - target: " << shared;
+ if (candidate.bytecode[i].has_value()) {
+ os << ", bytecode size: " << candidate.bytecode[i]->length();
+ } else {
+ os << ", no bytecode";
+ }
+ os << std::endl;
}
}
}
diff --git a/deps/v8/src/compiler/js-inlining.cc b/deps/v8/src/compiler/js-inlining.cc
index 91cbea2346..51179f1956 100644
--- a/deps/v8/src/compiler/js-inlining.cc
+++ b/deps/v8/src/compiler/js-inlining.cc
@@ -247,9 +247,13 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
bailout_id, OutputFrameStateCombine::Ignore(), state_info);
const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense());
Node* node0 = graph()->NewNode(op0);
+
+ static constexpr int kTargetInputIndex = 0;
+ static constexpr int kReceiverInputIndex = 1;
+ const int parameter_count_with_receiver = parameter_count + 1;
NodeVector params(local_zone_);
- for (int parameter = 0; parameter < parameter_count + 1; ++parameter) {
- params.push_back(node->InputAt(1 + parameter));
+ for (int i = 0; i < parameter_count_with_receiver; i++) {
+ params.push_back(node->InputAt(kReceiverInputIndex + i));
}
const Operator* op_param = common()->StateValues(
static_cast<int>(params.size()), SparseInputMask::Dense());
@@ -259,7 +263,7 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
context = jsgraph()->UndefinedConstant();
}
return graph()->NewNode(op, params_node, node0, node0, context,
- node->InputAt(0), outer_frame_state);
+ node->InputAt(kTargetInputIndex), outer_frame_state);
}
namespace {
@@ -301,7 +305,7 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
// TODO(turbofan): We might want to revisit this restriction later when we
// have a need for this, and we know how to model different native contexts
// in the same graph in a compositional way.
- if (!function.native_context().equals(broker()->native_context())) {
+ if (!function.native_context().equals(broker()->target_native_context())) {
return base::nullopt;
}
@@ -332,7 +336,7 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
// - context : The context (as SSA value) bound by the call target.
// - feedback_vector : The target is guaranteed to use this feedback vector.
FeedbackVectorRef JSInliner::DetermineCallContext(Node* node,
- Node*& context_out) {
+ Node** context_out) {
DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
HeapObjectMatcher match(node->InputAt(0));
@@ -342,7 +346,7 @@ FeedbackVectorRef JSInliner::DetermineCallContext(Node* node,
CHECK(function.has_feedback_vector());
// The inlinee specializes to the context from the JSFunction object.
- context_out = jsgraph()->Constant(function.context());
+ *context_out = jsgraph()->Constant(function.context());
return function.feedback_vector();
}
@@ -354,7 +358,7 @@ FeedbackVectorRef JSInliner::DetermineCallContext(Node* node,
FeedbackCellRef cell(FeedbackCellRef(broker(), p.feedback_cell()));
// The inlinee uses the locally provided context at instantiation.
- context_out = NodeProperties::GetContextInput(match.node());
+ *context_out = NodeProperties::GetContextInput(match.node());
return cell.value().AsFeedbackVector();
}
@@ -369,13 +373,14 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// Determine the call target.
base::Optional<SharedFunctionInfoRef> shared_info(DetermineCallTarget(node));
if (!shared_info.has_value()) return NoChange();
-
DCHECK(shared_info->IsInlineable());
+ SharedFunctionInfoRef outer_shared_info(broker(), info_->shared_info());
+
// Constructor must be constructable.
if (node->opcode() == IrOpcode::kJSConstruct &&
!IsConstructable(shared_info->kind())) {
- TRACE("Not inlining " << *shared_info << " into " << info_->shared_info()
+ TRACE("Not inlining " << *shared_info << " into " << outer_shared_info
<< " because constructor is not constructable.");
return NoChange();
}
@@ -384,7 +389,7 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
if (node->opcode() == IrOpcode::kJSCall &&
IsClassConstructor(shared_info->kind())) {
- TRACE("Not inlining " << *shared_info << " into " << info_->shared_info()
+ TRACE("Not inlining " << *shared_info << " into " << outer_shared_info
<< " because callee is a class constructor.");
return NoChange();
}
@@ -398,7 +403,7 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
nesting_level++;
if (nesting_level > kMaxDepthForInlining) {
TRACE("Not inlining "
- << *shared_info << " into " << info_->shared_info()
+ << *shared_info << " into " << outer_shared_info
<< " because call has exceeded the maximum depth for function "
"inlining.");
return NoChange();
@@ -413,38 +418,38 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// passing the IsInlineable check, The broker holds a reference to the
// bytecode array, which prevents it from getting flushed.
// Therefore, the following check should always hold true.
- CHECK(shared_info.value().is_compiled());
+ CHECK(shared_info->is_compiled());
if (!FLAG_concurrent_inlining && info_->is_source_positions_enabled()) {
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate(),
shared_info->object());
}
- TRACE("Inlining " << *shared_info << " into " << info_->shared_info()
+ TRACE("Inlining " << *shared_info << " into " << outer_shared_info
<< ((exception_target != nullptr) ? " (inside try-block)"
: ""));
// Determine the targets feedback vector and its context.
Node* context;
- FeedbackVectorRef feedback_vector = DetermineCallContext(node, context);
+ FeedbackVectorRef feedback_vector = DetermineCallContext(node, &context);
- if (FLAG_concurrent_inlining) {
- if (!shared_info.value().IsSerializedForCompilation(feedback_vector)) {
- TRACE("Missed opportunity to inline a function ("
- << *shared_info << " with " << feedback_vector << ")");
- return NoChange();
- }
+ if (FLAG_concurrent_inlining &&
+ !shared_info->IsSerializedForCompilation(feedback_vector)) {
+ // TODO(neis): Should this be a broker message?
+ TRACE("Missed opportunity to inline a function ("
+ << *shared_info << " with " << feedback_vector << ")");
+ return NoChange();
}
// ----------------------------------------------------------------
// After this point, we've made a decision to inline this function.
// We shall not bailout from inlining if we got here.
- BytecodeArrayRef bytecode_array = shared_info.value().GetBytecodeArray();
+ BytecodeArrayRef bytecode_array = shared_info->GetBytecodeArray();
// Remember that we inlined this function.
- int inlining_id = info_->AddInlinedFunction(
- shared_info.value().object(), bytecode_array.object(),
- source_positions_->GetSourcePosition(node));
+ int inlining_id =
+ info_->AddInlinedFunction(shared_info->object(), bytecode_array.object(),
+ source_positions_->GetSourcePosition(node));
// Create the subgraph for the inlinee.
Node* start;
@@ -461,20 +466,11 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
flags |= BytecodeGraphBuilderFlag::kBailoutOnUninitialized;
}
{
- // TODO(mslekova): Remove the following once bytecode graph builder
- // is brokerized. Also, remove the context argument from
- // BuildGraphFromBytecode and extract it from the broker there.
- AllowHandleDereference allow_handle_deref;
- AllowHandleAllocation allow_handle_alloc;
- AllowHeapAllocation allow_heap_alloc;
- AllowCodeDependencyChange allow_code_dep_change;
CallFrequency frequency = call.frequency();
- Handle<NativeContext> native_context(info_->native_context(), isolate());
- BuildGraphFromBytecode(
- broker(), zone(), bytecode_array.object(),
- shared_info.value().object(), feedback_vector.object(),
- BailoutId::None(), jsgraph(), frequency, source_positions_,
- native_context, inlining_id, flags, &info_->tick_counter());
+ BuildGraphFromBytecode(broker(), zone(), *shared_info, feedback_vector,
+ BailoutId::None(), jsgraph(), frequency,
+ source_positions_, inlining_id, flags,
+ &info_->tick_counter());
}
// Extract the inlinee start/end nodes.
@@ -522,13 +518,13 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
// where execution continues at {construct_stub_create_deopt_pc_offset}).
Node* receiver = jsgraph()->TheHoleConstant(); // Implicit receiver.
Node* context = NodeProperties::GetContextInput(node);
- if (NeedsImplicitReceiver(shared_info.value())) {
+ if (NeedsImplicitReceiver(*shared_info)) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* frame_state_inside = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(),
BailoutId::ConstructStubCreate(), FrameStateType::kConstructStub,
- shared_info.value(), context);
+ *shared_info, context);
Node* create =
graph()->NewNode(javascript()->Create(), call.target(), new_target,
context, frame_state_inside, effect, control);
@@ -583,7 +579,7 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
frame_state = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(),
BailoutId::ConstructStubInvoke(), FrameStateType::kConstructStub,
- shared_info.value(), context);
+ *shared_info, context);
}
// Insert a JSConvertReceiver node for sloppy callees. Note that the context
@@ -593,8 +589,8 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
if (NodeProperties::CanBePrimitive(broker(), call.receiver(), effect)) {
CallParameters const& p = CallParametersOf(node->op());
- Node* global_proxy =
- jsgraph()->Constant(broker()->native_context().global_proxy_object());
+ Node* global_proxy = jsgraph()->Constant(
+ broker()->target_native_context().global_proxy_object());
Node* receiver = effect =
graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()),
call.receiver(), global_proxy, effect, start);
@@ -612,7 +608,7 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
if (call.formal_arguments() != parameter_count) {
frame_state = CreateArtificialFrameState(
node, frame_state, call.formal_arguments(), BailoutId::None(),
- FrameStateType::kArgumentsAdaptor, shared_info.value());
+ FrameStateType::kArgumentsAdaptor, *shared_info);
}
return InlineCall(node, new_target, context, frame_state, start, end,
diff --git a/deps/v8/src/compiler/js-inlining.h b/deps/v8/src/compiler/js-inlining.h
index f50f7b591d..f60d53dbc9 100644
--- a/deps/v8/src/compiler/js-inlining.h
+++ b/deps/v8/src/compiler/js-inlining.h
@@ -59,8 +59,7 @@ class JSInliner final : public AdvancedReducer {
SourcePositionTable* const source_positions_;
base::Optional<SharedFunctionInfoRef> DetermineCallTarget(Node* node);
- FeedbackVectorRef DetermineCallContext(
- Node* node, Node*& context_out); // NOLINT(runtime/references)
+ FeedbackVectorRef DetermineCallContext(Node* node, Node** context_out);
Node* CreateArtificialFrameState(Node* node, Node* outer_frame_state,
int parameter_count, BailoutId bailout_id,
diff --git a/deps/v8/src/compiler/js-intrinsic-lowering.cc b/deps/v8/src/compiler/js-intrinsic-lowering.cc
index 970a7e3ed6..ccb0622017 100644
--- a/deps/v8/src/compiler/js-intrinsic-lowering.cc
+++ b/deps/v8/src/compiler/js-intrinsic-lowering.cc
@@ -21,10 +21,13 @@ namespace v8 {
namespace internal {
namespace compiler {
-JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph)
- : AdvancedReducer(editor), jsgraph_(jsgraph) {}
+JSIntrinsicLowering::JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph,
+ JSHeapBroker* broker)
+ : AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
Reduction JSIntrinsicLowering::Reduce(Node* node) {
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
+
if (node->opcode() != IrOpcode::kJSCallRuntime) return NoChange();
const Runtime::Function* const f =
Runtime::FunctionForId(CallRuntimeParametersOf(node->op()).id());
@@ -108,7 +111,7 @@ Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
// TODO(bmeurer): Move MergeControlToEnd() to the AdvancedReducer.
Node* deoptimize = graph()->NewNode(
common()->Deoptimize(DeoptimizeKind::kEager,
- DeoptimizeReason::kDeoptimizeNow, VectorSlotPair()),
+ DeoptimizeReason::kDeoptimizeNow, FeedbackSource()),
frame_state, effect, control);
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
Revisit(graph()->end());
@@ -307,7 +310,7 @@ Reduction JSIntrinsicLowering::ReduceToObject(Node* node) {
Reduction JSIntrinsicLowering::ReduceToString(Node* node) {
// ToString is unnecessary if the input is a string.
HeapObjectMatcher m(NodeProperties::GetValueInput(node, 0));
- if (m.HasValue() && m.Value()->IsString()) {
+ if (m.HasValue() && m.Ref(broker()).IsString()) {
ReplaceWithValue(node, m.node());
return Replace(m.node());
}
diff --git a/deps/v8/src/compiler/js-intrinsic-lowering.h b/deps/v8/src/compiler/js-intrinsic-lowering.h
index 844e051d0a..f32b53b586 100644
--- a/deps/v8/src/compiler/js-intrinsic-lowering.h
+++ b/deps/v8/src/compiler/js-intrinsic-lowering.h
@@ -31,7 +31,7 @@ class SimplifiedOperatorBuilder;
class V8_EXPORT_PRIVATE JSIntrinsicLowering final
: public NON_EXPORTED_BASE(AdvancedReducer) {
public:
- JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph);
+ JSIntrinsicLowering(Editor* editor, JSGraph* jsgraph, JSHeapBroker* broker);
~JSIntrinsicLowering() final = default;
const char* reducer_name() const override { return "JSIntrinsicLowering"; }
@@ -81,12 +81,14 @@ class V8_EXPORT_PRIVATE JSIntrinsicLowering final
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
+ JSHeapBroker* broker() const { return broker_; }
Isolate* isolate() const;
CommonOperatorBuilder* common() const;
JSOperatorBuilder* javascript() const;
SimplifiedOperatorBuilder* simplified() const;
JSGraph* const jsgraph_;
+ JSHeapBroker* const broker_;
};
} // namespace compiler
diff --git a/deps/v8/src/compiler/js-native-context-specialization.cc b/deps/v8/src/compiler/js-native-context-specialization.cc
index 8f7552baa1..9f950c808c 100644
--- a/deps/v8/src/compiler/js-native-context-specialization.cc
+++ b/deps/v8/src/compiler/js-native-context-specialization.cc
@@ -19,7 +19,6 @@
#include "src/compiler/node-matchers.h"
#include "src/compiler/property-access-builder.h"
#include "src/compiler/type-cache.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/execution/isolate-inl.h"
#include "src/numbers/dtoa.h"
#include "src/objects/feedback-vector.h"
@@ -52,35 +51,26 @@ bool HasOnlyJSArrayMaps(JSHeapBroker* broker,
return true;
}
-void TryUpdateThenDropDeprecated(Isolate* isolate, MapHandles* maps) {
- for (auto it = maps->begin(); it != maps->end();) {
- if (Map::TryUpdate(isolate, *it).ToHandle(&*it)) {
- DCHECK(!(*it)->is_deprecated());
- ++it;
- } else {
- it = maps->erase(it);
- }
- }
-}
-
} // namespace
JSNativeContextSpecialization::JSNativeContextSpecialization(
Editor* editor, JSGraph* jsgraph, JSHeapBroker* broker, Flags flags,
- Handle<Context> native_context, CompilationDependencies* dependencies,
- Zone* zone, Zone* shared_zone)
+ CompilationDependencies* dependencies, Zone* zone, Zone* shared_zone)
: AdvancedReducer(editor),
jsgraph_(jsgraph),
broker_(broker),
flags_(flags),
- global_object_(native_context->global_object(), jsgraph->isolate()),
- global_proxy_(native_context->global_proxy(), jsgraph->isolate()),
+ global_object_(broker->target_native_context().global_object().object()),
+ global_proxy_(
+ broker->target_native_context().global_proxy_object().object()),
dependencies_(dependencies),
zone_(zone),
shared_zone_(shared_zone),
type_cache_(TypeCache::Get()) {}
Reduction JSNativeContextSpecialization::Reduce(Node* node) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
switch (node->opcode()) {
case IrOpcode::kJSAdd:
return ReduceJSAdd(node);
@@ -128,6 +118,8 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
return ReduceJSToObject(node);
case IrOpcode::kJSToString:
return ReduceJSToString(node);
+ case IrOpcode::kJSGetIterator:
+ return ReduceJSGetIterator(node);
default:
break;
}
@@ -236,11 +228,12 @@ Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionEnter(
// Create the JSAsyncFunctionObject based on the SharedFunctionInfo
// extracted from the top-most frame in {frame_state}.
- Handle<SharedFunctionInfo> shared =
- FrameStateInfoOf(frame_state->op()).shared_info().ToHandleChecked();
- DCHECK(shared->is_compiled());
- int register_count = shared->internal_formal_parameter_count() +
- shared->GetBytecodeArray().register_count();
+ SharedFunctionInfoRef shared(
+ broker(),
+ FrameStateInfoOf(frame_state->op()).shared_info().ToHandleChecked());
+ DCHECK(shared.is_compiled());
+ int register_count = shared.internal_formal_parameter_count() +
+ shared.GetBytecodeArray().register_count();
Node* value = effect =
graph()->NewNode(javascript()->CreateAsyncFunctionObject(register_count),
closure, receiver, promise, context, effect, control);
@@ -360,9 +353,7 @@ Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
if (!m.HasValue()) return NoChange();
JSFunctionRef function = m.Ref(broker()).AsJSFunction();
MapRef function_map = function.map();
- if (!FLAG_concurrent_inlining) {
- function_map.SerializePrototype();
- } else if (!function_map.serialized_prototype()) {
+ if (FLAG_concurrent_inlining && !function_map.serialized_prototype()) {
TRACE_BROKER_MISSING(broker(), "data for map " << function_map);
return NoChange();
}
@@ -396,22 +387,37 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
// we have feedback from the InstanceOfIC.
Handle<JSObject> receiver;
HeapObjectMatcher m(constructor);
- if (m.HasValue() && m.Value()->IsJSObject()) {
- receiver = Handle<JSObject>::cast(m.Value());
+ if (m.HasValue() && m.Ref(broker()).IsJSObject()) {
+ receiver = m.Ref(broker()).AsJSObject().object();
} else if (p.feedback().IsValid()) {
- FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
- if (!nexus.GetConstructorFeedback().ToHandle(&receiver)) return NoChange();
+ ProcessedFeedback const& feedback =
+ broker()->GetFeedbackForInstanceOf(FeedbackSource(p.feedback()));
+ if (feedback.IsInsufficient()) return NoChange();
+ base::Optional<JSObjectRef> maybe_receiver =
+ feedback.AsInstanceOf().value();
+ if (!maybe_receiver.has_value()) return NoChange();
+ receiver = maybe_receiver->object();
} else {
return NoChange();
}
- Handle<Map> receiver_map(receiver->map(), isolate());
- // Compute property access info for @@hasInstance on the constructor.
- AccessInfoFactory access_info_factory(broker(), dependencies(),
- graph()->zone());
- PropertyAccessInfo access_info =
- access_info_factory.ComputePropertyAccessInfo(
- receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad);
+ JSObjectRef receiver_ref(broker(), receiver);
+ MapRef receiver_map = receiver_ref.map();
+
+ PropertyAccessInfo access_info = PropertyAccessInfo::Invalid(graph()->zone());
+ if (FLAG_concurrent_inlining) {
+ access_info = broker()->GetPropertyAccessInfo(
+ receiver_map,
+ NameRef(broker(), isolate()->factory()->has_instance_symbol()),
+ AccessMode::kLoad);
+ } else {
+ AccessInfoFactory access_info_factory(broker(), dependencies(),
+ graph()->zone());
+ access_info = access_info_factory.ComputePropertyAccessInfo(
+ receiver_map.object(), factory()->has_instance_symbol(),
+ AccessMode::kLoad);
+ }
+
if (access_info.IsInvalid()) return NoChange();
access_info.RecordDependencies(dependencies());
@@ -420,7 +426,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
if (access_info.IsNotFound()) {
// If there's no @@hasInstance handler, the OrdinaryHasInstance operation
// takes over, but that requires the constructor to be callable.
- if (!receiver_map->is_callable()) return NoChange();
+ if (!receiver_map.is_callable()) return NoChange();
dependencies()->DependOnStablePrototypeChains(access_info.receiver_maps(),
kStartAtPrototype);
@@ -439,17 +445,15 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
}
if (access_info.IsDataConstant()) {
- // Determine actual holder.
Handle<JSObject> holder;
bool found_on_proto = access_info.holder().ToHandle(&holder);
- if (!found_on_proto) holder = receiver;
-
- FieldIndex field_index = access_info.field_index();
- Handle<Object> constant = JSObject::FastPropertyAt(
- holder, access_info.field_representation(), field_index);
- if (!constant->IsCallable()) {
+ JSObjectRef holder_ref =
+ found_on_proto ? JSObjectRef(broker(), holder) : receiver_ref;
+ base::Optional<ObjectRef> constant = holder_ref.GetOwnDataProperty(
+ access_info.field_representation(), access_info.field_index());
+ if (!constant.has_value() || !constant->IsHeapObject() ||
+ !constant->AsHeapObject().map().is_callable())
return NoChange();
- }
if (found_on_proto) {
dependencies()->DependOnStablePrototypeChains(
@@ -457,8 +461,6 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
JSObjectRef(broker(), holder));
}
- DCHECK(constant->IsCallable());
-
// Check that {constructor} is actually {receiver}.
constructor =
access_builder.BuildCheckValue(constructor, &effect, control, receiver);
@@ -478,14 +480,14 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
0, frame_state, ContinuationFrameStateMode::LAZY);
// Call the @@hasInstance handler.
- Node* target = jsgraph()->Constant(constant);
+ Node* target = jsgraph()->Constant(*constant);
node->InsertInput(graph()->zone(), 0, target);
node->ReplaceInput(1, constructor);
node->ReplaceInput(2, object);
node->ReplaceInput(4, continuation_frame_state);
node->ReplaceInput(5, effect);
NodeProperties::ChangeOp(
- node, javascript()->Call(3, CallFrequency(), VectorSlotPair(),
+ node, javascript()->Call(3, CallFrequency(), FeedbackSource(),
ConvertReceiverMode::kNotNullOrUndefined));
// Rewire the value uses of {node} to ToBoolean conversion of the result.
@@ -504,7 +506,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
JSNativeContextSpecialization::InferHasInPrototypeChainResult
JSNativeContextSpecialization::InferHasInPrototypeChain(
- Node* receiver, Node* effect, Handle<HeapObject> prototype) {
+ Node* receiver, Node* effect, HeapObjectRef const& prototype) {
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMapsUnsafe(broker(), receiver, effect,
@@ -517,28 +519,31 @@ JSNativeContextSpecialization::InferHasInPrototypeChain(
bool all = true;
bool none = true;
for (size_t i = 0; i < receiver_maps.size(); ++i) {
- Handle<Map> receiver_map = receiver_maps[i];
- if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
- return kMayBeInPrototypeChain;
- }
- if (result == NodeProperties::kUnreliableReceiverMaps &&
- !receiver_map->is_stable()) {
+ MapRef map(broker(), receiver_maps[i]);
+ if (result == NodeProperties::kUnreliableReceiverMaps && !map.is_stable()) {
return kMayBeInPrototypeChain;
}
- for (PrototypeIterator it(isolate(), receiver_map);; it.Advance()) {
- if (it.IsAtEnd()) {
+ while (true) {
+ if (IsSpecialReceiverInstanceType(map.instance_type())) {
+ return kMayBeInPrototypeChain;
+ }
+ if (!map.IsJSObjectMap()) {
all = false;
break;
}
- Handle<HeapObject> current =
- PrototypeIterator::GetCurrent<HeapObject>(it);
- if (current.is_identical_to(prototype)) {
+ if (FLAG_concurrent_inlining && !map.serialized_prototype()) {
+ TRACE_BROKER_MISSING(broker(), "prototype data for map " << map);
+ return kMayBeInPrototypeChain;
+ }
+ if (map.prototype().equals(prototype)) {
none = false;
break;
}
- if (!current->map().is_stable() ||
- current->map().instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
- return kMayBeInPrototypeChain;
+ map = map.prototype().map();
+ if (!map.is_stable()) return kMayBeInPrototypeChain;
+ if (map.oddball_type() == OddballType::kNull) {
+ all = false;
+ break;
}
}
}
@@ -554,8 +559,8 @@ JSNativeContextSpecialization::InferHasInPrototypeChain(
// might be a different object each time, so it's much simpler to include
// {prototype}. That does, however, mean that we must check {prototype}'s
// map stability.
- if (!prototype->map().is_stable()) return kMayBeInPrototypeChain;
- last_prototype.emplace(broker(), Handle<JSObject>::cast(prototype));
+ if (!prototype.map().is_stable()) return kMayBeInPrototypeChain;
+ last_prototype = prototype.AsJSObject();
}
WhereToStart start = result == NodeProperties::kUnreliableReceiverMaps
? kStartAtReceiver
@@ -580,7 +585,7 @@ Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain(
HeapObjectMatcher m(prototype);
if (m.HasValue()) {
InferHasInPrototypeChainResult result =
- InferHasInPrototypeChain(value, effect, m.Value());
+ InferHasInPrototypeChain(value, effect, m.Ref(broker()));
if (result != kMayBeInPrototypeChain) {
Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain);
ReplaceWithValue(node, value);
@@ -601,34 +606,41 @@ Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
HeapObjectMatcher m(constructor);
if (!m.HasValue()) return NoChange();
- // Check if the {constructor} is a JSBoundFunction.
- if (m.Value()->IsJSBoundFunction()) {
- // OrdinaryHasInstance on bound functions turns into a recursive
- // invocation of the instanceof operator again.
- // ES6 section 7.3.19 OrdinaryHasInstance (C, O) step 2.
- Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(m.Value());
- Handle<JSReceiver> bound_target_function(function->bound_target_function(),
- isolate());
+ if (m.Ref(broker()).IsJSBoundFunction()) {
+ // OrdinaryHasInstance on bound functions turns into a recursive invocation
+ // of the instanceof operator again.
+ JSBoundFunctionRef function = m.Ref(broker()).AsJSBoundFunction();
+ if (FLAG_concurrent_inlining && !function.serialized()) {
+ TRACE_BROKER_MISSING(broker(), "data for JSBoundFunction " << function);
+ return NoChange();
+ }
+
+ JSReceiverRef bound_target_function = function.bound_target_function();
+
NodeProperties::ReplaceValueInput(node, object, 0);
NodeProperties::ReplaceValueInput(
- node, jsgraph()->HeapConstant(bound_target_function), 1);
- NodeProperties::ChangeOp(node, javascript()->InstanceOf(VectorSlotPair()));
+ node, jsgraph()->Constant(bound_target_function), 1);
+ NodeProperties::ChangeOp(node, javascript()->InstanceOf(FeedbackSource()));
Reduction const reduction = ReduceJSInstanceOf(node);
return reduction.Changed() ? reduction : Changed(node);
}
- // Optimize if we currently know the "prototype" property.
- if (m.Value()->IsJSFunction()) {
+ if (m.Ref(broker()).IsJSFunction()) {
+ // Optimize if we currently know the "prototype" property.
+
JSFunctionRef function = m.Ref(broker()).AsJSFunction();
- // TODO(neis): This is a temporary hack needed because the copy reducer
- // runs only after this pass.
- function.Serialize();
+ if (FLAG_concurrent_inlining && !function.serialized()) {
+ TRACE_BROKER_MISSING(broker(), "data for JSFunction " << function);
+ return NoChange();
+ }
+
// TODO(neis): Remove the has_prototype_slot condition once the broker is
// always enabled.
if (!function.map().has_prototype_slot() || !function.has_prototype() ||
function.PrototypeRequiresRuntimeLookup()) {
return NoChange();
}
+
ObjectRef prototype = dependencies()->DependOnPrototypeProperty(function);
Node* prototype_constant = jsgraph()->Constant(prototype);
@@ -656,7 +668,7 @@ Reduction JSNativeContextSpecialization::ReduceJSPromiseResolve(Node* node) {
// Check if the {constructor} is the %Promise% function.
HeapObjectMatcher m(constructor);
if (!m.HasValue() ||
- !m.Ref(broker()).equals(broker()->native_context().promise_function())) {
+ !m.Ref(broker()).equals(native_context().promise_function())) {
return NoChange();
}
@@ -680,7 +692,6 @@ Reduction JSNativeContextSpecialization::ReduceJSPromiseResolve(Node* node) {
// ES section #sec-promise-resolve-functions
Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
- DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSResolvePromise, node->opcode());
Node* promise = NodeProperties::GetValueInput(node, 0);
Node* resolution = NodeProperties::GetValueInput(node, 1);
@@ -705,7 +716,9 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
// Obtain pre-computed access infos from the broker.
for (auto map : resolution_maps) {
MapRef map_ref(broker(), map);
- access_infos.push_back(broker()->GetAccessInfoForLoadingThen(map_ref));
+ access_infos.push_back(broker()->GetPropertyAccessInfo(
+ map_ref, NameRef(broker(), isolate()->factory()->then_string()),
+ AccessMode::kLoad));
}
}
PropertyAccessInfo access_info =
@@ -948,7 +961,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
} else {
// Check that the {value} is a Smi.
value = effect = graph()->NewNode(
- simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
+ simplified()->CheckSmi(FeedbackSource()), value, effect, control);
property_cell_value_type = Type::SignedSmall();
representation = MachineType::RepCompressedTaggedSigned();
}
@@ -978,70 +991,85 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
}
Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
- DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
LoadGlobalParameters const& p = LoadGlobalParametersOf(node->op());
if (!p.feedback().IsValid()) return NoChange();
- FeedbackSource source(p.feedback());
- // TODO(neis): Make consistent with other feedback processing code.
- GlobalAccessFeedback const* processed =
- FLAG_concurrent_inlining
- ? broker()->GetGlobalAccessFeedback(source)
- : broker()->ProcessFeedbackForGlobalAccess(source);
- if (processed == nullptr) return NoChange();
+ ProcessedFeedback const& processed =
+ broker()->GetFeedbackForGlobalAccess(FeedbackSource(p.feedback()));
+ if (processed.IsInsufficient()) return NoChange();
- if (processed->IsScriptContextSlot()) {
+ GlobalAccessFeedback const& feedback = processed.AsGlobalAccess();
+ if (feedback.IsScriptContextSlot()) {
Node* effect = NodeProperties::GetEffectInput(node);
- Node* script_context = jsgraph()->Constant(processed->script_context());
+ Node* script_context = jsgraph()->Constant(feedback.script_context());
Node* value = effect =
- graph()->NewNode(javascript()->LoadContext(0, processed->slot_index(),
- processed->immutable()),
+ graph()->NewNode(javascript()->LoadContext(0, feedback.slot_index(),
+ feedback.immutable()),
script_context, effect);
ReplaceWithValue(node, value, effect);
return Replace(value);
+ } else if (feedback.IsPropertyCell()) {
+ return ReduceGlobalAccess(node, nullptr, nullptr,
+ NameRef(broker(), p.name()), AccessMode::kLoad,
+ nullptr, feedback.property_cell());
+ } else {
+ DCHECK(feedback.IsMegamorphic());
+ return NoChange();
}
-
- CHECK(processed->IsPropertyCell());
- return ReduceGlobalAccess(node, nullptr, nullptr, NameRef(broker(), p.name()),
- AccessMode::kLoad, nullptr,
- processed->property_cell());
}
Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
- DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
Node* value = NodeProperties::GetValueInput(node, 0);
-
StoreGlobalParameters const& p = StoreGlobalParametersOf(node->op());
if (!p.feedback().IsValid()) return NoChange();
- FeedbackSource source(p.feedback());
- GlobalAccessFeedback const* processed =
- FLAG_concurrent_inlining
- ? broker()->GetGlobalAccessFeedback(source)
- : broker()->ProcessFeedbackForGlobalAccess(source);
- if (processed == nullptr) return NoChange();
+ ProcessedFeedback const& processed =
+ broker()->GetFeedbackForGlobalAccess(FeedbackSource(p.feedback()));
+ if (processed.IsInsufficient()) return NoChange();
- if (processed->IsScriptContextSlot()) {
- if (processed->immutable()) return NoChange();
+ GlobalAccessFeedback const& feedback = processed.AsGlobalAccess();
+ if (feedback.IsScriptContextSlot()) {
+ if (feedback.immutable()) return NoChange();
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- Node* script_context = jsgraph()->Constant(processed->script_context());
+ Node* script_context = jsgraph()->Constant(feedback.script_context());
effect =
- graph()->NewNode(javascript()->StoreContext(0, processed->slot_index()),
+ graph()->NewNode(javascript()->StoreContext(0, feedback.slot_index()),
value, script_context, effect, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
- }
-
- if (processed->IsPropertyCell()) {
+ } else if (feedback.IsPropertyCell()) {
return ReduceGlobalAccess(node, nullptr, value, NameRef(broker(), p.name()),
AccessMode::kStore, nullptr,
- processed->property_cell());
+ feedback.property_cell());
+ } else {
+ DCHECK(feedback.IsMegamorphic());
+ return NoChange();
}
+}
- UNREACHABLE();
+void JSNativeContextSpecialization::FilterMapsAndGetPropertyAccessInfos(
+ NamedAccessFeedback const& feedback, AccessMode access_mode, Node* receiver,
+ Node* effect, ZoneVector<PropertyAccessInfo>* access_infos) {
+ ZoneVector<Handle<Map>> receiver_maps(zone());
+
+ // Either infer maps from the graph or use the feedback.
+ if (!InferReceiverMaps(receiver, effect, &receiver_maps)) {
+ receiver_maps = feedback.maps();
+ }
+ RemoveImpossibleReceiverMaps(receiver, &receiver_maps);
+
+ for (Handle<Map> map_handle : receiver_maps) {
+ MapRef map(broker(), map_handle);
+ if (map.is_deprecated()) continue;
+ PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
+ map, feedback.name(), access_mode, dependencies(),
+ FLAG_concurrent_inlining ? SerializationPolicy::kAssumeSerialized
+ : SerializationPolicy::kSerializeIfNeeded);
+ access_infos->push_back(access_info);
+ }
}
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
@@ -1052,18 +1080,23 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
node->opcode() == IrOpcode::kJSLoadProperty ||
node->opcode() == IrOpcode::kJSStoreProperty ||
node->opcode() == IrOpcode::kJSStoreNamedOwn ||
- node->opcode() == IrOpcode::kJSHasProperty);
+ node->opcode() == IrOpcode::kJSStoreDataPropertyInLiteral ||
+ node->opcode() == IrOpcode::kJSHasProperty ||
+ node->opcode() == IrOpcode::kJSGetIterator);
Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* context = NodeProperties::GetContextInput(node);
Node* frame_state = NodeProperties::GetFrameStateInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
+ ZoneVector<PropertyAccessInfo> access_infos_for_feedback(zone());
ZoneVector<PropertyAccessInfo> access_infos(zone());
+ FilterMapsAndGetPropertyAccessInfos(feedback, access_mode, receiver, effect,
+ &access_infos_for_feedback);
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
if (!access_info_factory.FinalizePropertyAccessInfos(
- feedback.access_infos(), access_mode, &access_infos)) {
+ access_infos_for_feedback, access_mode, &access_infos)) {
return NoChange();
}
@@ -1072,7 +1105,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// to the current native context's global object instead.
if (access_infos.size() == 1 && access_infos[0].receiver_maps().size() == 1) {
MapRef receiver_map(broker(), access_infos[0].receiver_maps()[0]);
- if (receiver_map.IsMapOfCurrentGlobalProxy()) {
+ if (receiver_map.IsMapOfTargetGlobalProxy()) {
return ReduceGlobalAccess(node, receiver, value, feedback.name(),
access_mode, key);
}
@@ -1318,7 +1351,6 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
}
Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
- DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
NamedAccess const& p = NamedAccessOf(node->op());
Node* const receiver = NodeProperties::GetValueInput(node, 0);
@@ -1332,9 +1364,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
name.equals(ObjectRef(broker(), factory()->prototype_string()))) {
// Optimize "prototype" property of functions.
JSFunctionRef function = object.AsJSFunction();
- if (!FLAG_concurrent_inlining) {
- function.Serialize();
- } else if (!function.serialized()) {
+ if (FLAG_concurrent_inlining && !function.serialized()) {
TRACE_BROKER_MISSING(broker(), "data for function " << function);
return NoChange();
}
@@ -1363,8 +1393,16 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
AccessMode::kLoad);
}
+Reduction JSNativeContextSpecialization::ReduceJSGetIterator(Node* node) {
+ DCHECK_EQ(IrOpcode::kJSGetIterator, node->opcode());
+ PropertyAccess const& p = PropertyAccessOf(node->op());
+ NameRef name(broker(), factory()->iterator_symbol());
+
+ return ReducePropertyAccess(node, nullptr, name, jsgraph()->Dead(),
+ FeedbackSource(p.feedback()), AccessMode::kLoad);
+}
+
Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
- DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
NamedAccess const& p = NamedAccessOf(node->op());
Node* const value = NodeProperties::GetValueInput(node, 1);
@@ -1376,7 +1414,6 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
}
Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
- DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSStoreNamedOwn, node->opcode());
StoreNamedOwnParameters const& p = StoreNamedOwnParametersOf(node->op());
Node* const value = NodeProperties::GetValueInput(node, 1);
@@ -1401,7 +1438,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccessOnString(
// Ensure that the {receiver} is actually a String.
receiver = effect = graph()->NewNode(
- simplified()->CheckString(VectorSlotPair()), receiver, effect, control);
+ simplified()->CheckString(FeedbackSource()), receiver, effect, control);
// Determine the {receiver} length.
Node* length = graph()->NewNode(simplified()->StringLength(), receiver);
@@ -1428,13 +1465,50 @@ base::Optional<JSTypedArrayRef> GetTypedArrayConstant(JSHeapBroker* broker,
}
} // namespace
+void JSNativeContextSpecialization::RemoveImpossibleReceiverMaps(
+ Node* receiver, ZoneVector<Handle<Map>>* receiver_maps) const {
+ base::Optional<MapRef> root_map = InferReceiverRootMap(receiver);
+ if (root_map.has_value()) {
+ DCHECK(!root_map->is_abandoned_prototype_map());
+ receiver_maps->erase(
+ std::remove_if(receiver_maps->begin(), receiver_maps->end(),
+ [root_map, this](Handle<Map> map) {
+ MapRef map_ref(broker(), map);
+ return map_ref.is_abandoned_prototype_map() ||
+ (map_ref.FindRootMap().has_value() &&
+ !map_ref.FindRootMap()->equals(*root_map));
+ }),
+ receiver_maps->end());
+ }
+}
+
+// Possibly refine the feedback using inferred map information from the graph.
+ElementAccessFeedback const&
+JSNativeContextSpecialization::TryRefineElementAccessFeedback(
+ ElementAccessFeedback const& feedback, Node* receiver, Node* effect) const {
+ AccessMode access_mode = feedback.keyed_mode().access_mode();
+ bool use_inference =
+ access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas;
+ if (!use_inference) return feedback;
+
+ ZoneVector<Handle<Map>> inferred_maps(zone());
+ if (!InferReceiverMaps(receiver, effect, &inferred_maps)) return feedback;
+
+ RemoveImpossibleReceiverMaps(receiver, &inferred_maps);
+ // TODO(neis): After Refine, the resulting feedback can still contain
+ // impossible maps when a target is kept only because more than one of its
+ // sources was inferred. Think of a way to completely rule out impossible
+ // maps.
+ return feedback.Refine(inferred_maps, zone());
+}
+
Reduction JSNativeContextSpecialization::ReduceElementAccess(
Node* node, Node* index, Node* value,
- ElementAccessFeedback const& processed) {
- DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
+ ElementAccessFeedback const& feedback) {
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
node->opcode() == IrOpcode::kJSStoreProperty ||
node->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
+ node->opcode() == IrOpcode::kJSStoreDataPropertyInLiteral ||
node->opcode() == IrOpcode::kJSHasProperty);
Node* receiver = NodeProperties::GetValueInput(node, 0);
@@ -1443,30 +1517,34 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
Node* frame_state =
NodeProperties::FindFrameStateBefore(node, jsgraph()->Dead());
- AccessMode access_mode = processed.keyed_mode.access_mode();
+ // TODO(neis): It's odd that we do optimizations below that don't really care
+ // about the feedback, but we don't do them when the feedback is megamorphic.
+ if (feedback.transition_groups().empty()) return NoChange();
+
+ ElementAccessFeedback const& refined_feedback =
+ TryRefineElementAccessFeedback(feedback, receiver, effect);
+
+ AccessMode access_mode = refined_feedback.keyed_mode().access_mode();
if ((access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) &&
receiver->opcode() == IrOpcode::kHeapConstant) {
- Reduction reduction = ReduceKeyedLoadFromHeapConstant(
- node, index, access_mode, processed.keyed_mode.load_mode());
+ Reduction reduction = ReduceElementLoadFromHeapConstant(
+ node, index, access_mode, refined_feedback.keyed_mode().load_mode());
if (reduction.Changed()) return reduction;
}
- if (HasOnlyStringMaps(broker(), processed.receiver_maps)) {
- DCHECK(processed.transitions.empty());
+ if (!refined_feedback.transition_groups().empty() &&
+ refined_feedback.HasOnlyStringMaps(broker())) {
return ReduceElementAccessOnString(node, index, value,
- processed.keyed_mode);
+ refined_feedback.keyed_mode());
}
- // Compute element access infos for the receiver maps.
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
ZoneVector<ElementAccessInfo> access_infos(zone());
- if (!access_info_factory.ComputeElementAccessInfos(processed, access_mode,
- &access_infos)) {
+ if (!access_info_factory.ComputeElementAccessInfos(refined_feedback,
+ &access_infos) ||
+ access_infos.empty()) {
return NoChange();
- } else if (access_infos.empty()) {
- return ReduceSoftDeoptimize(
- node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
}
// For holey stores or growing stores, we need to check that the prototype
@@ -1485,7 +1563,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
// then we need to check that all prototypes have stable maps with
// fast elements (and we need to guard against changes to that below).
if ((IsHoleyOrDictionaryElementsKind(receiver_map.elements_kind()) ||
- IsGrowStoreMode(processed.keyed_mode.store_mode())) &&
+ IsGrowStoreMode(feedback.keyed_mode().store_mode())) &&
!receiver_map.HasOnlyStablePrototypesWithFastElements(
&prototype_maps)) {
return NoChange();
@@ -1514,9 +1592,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
base::Optional<JSTypedArrayRef> typed_array =
GetTypedArrayConstant(broker(), receiver);
if (typed_array.has_value()) {
- if (!FLAG_concurrent_inlining) {
- typed_array->Serialize();
- } else if (!typed_array->serialized()) {
+ if (FLAG_concurrent_inlining && !typed_array->serialized()) {
TRACE_BROKER_MISSING(broker(), "data for typed array " << *typed_array);
return NoChange();
}
@@ -1558,7 +1634,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
// Access the actual element.
ValueEffectControl continuation =
BuildElementAccess(receiver, index, value, effect, control, access_info,
- processed.keyed_mode);
+ feedback.keyed_mode());
value = continuation.value();
effect = continuation.effect();
control = continuation.control();
@@ -1625,7 +1701,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
// Access the actual element.
ValueEffectControl continuation =
BuildElementAccess(this_receiver, this_index, this_value, this_effect,
- this_control, access_info, processed.keyed_mode);
+ this_control, access_info, feedback.keyed_mode());
values.push_back(continuation.value());
effects.push_back(continuation.effect());
controls.push_back(continuation.control());
@@ -1658,7 +1734,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
return Replace(value);
}
-Reduction JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant(
+Reduction JSNativeContextSpecialization::ReduceElementLoadFromHeapConstant(
Node* node, Node* key, AccessMode access_mode,
KeyedAccessLoadMode load_mode) {
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
@@ -1733,67 +1809,35 @@ Reduction JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant(
Reduction JSNativeContextSpecialization::ReducePropertyAccess(
Node* node, Node* key, base::Optional<NameRef> static_name, Node* value,
FeedbackSource const& source, AccessMode access_mode) {
+ DisallowHeapAccessIf disallow_heap_access(FLAG_concurrent_inlining);
+
DCHECK_EQ(key == nullptr, static_name.has_value());
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
node->opcode() == IrOpcode::kJSStoreProperty ||
node->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
+ node->opcode() == IrOpcode::kJSStoreDataPropertyInLiteral ||
node->opcode() == IrOpcode::kJSHasProperty ||
node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed ||
- node->opcode() == IrOpcode::kJSStoreNamedOwn);
-
- Node* receiver = NodeProperties::GetValueInput(node, 0);
- Node* effect = NodeProperties::GetEffectInput(node);
-
- ProcessedFeedback const* processed = nullptr;
- if (FLAG_concurrent_inlining) {
- processed = broker()->GetFeedback(source);
- // TODO(neis): Infer maps from the graph and consolidate with feedback/hints
- // and filter impossible candidates based on inferred root map.
- } else {
- // TODO(neis): Try to unify this with the similar code in the serializer.
- FeedbackNexus nexus(source.vector, source.slot);
- if (nexus.ic_state() == UNINITIALIZED) {
- processed = new (zone()) InsufficientFeedback();
- } else {
- MapHandles receiver_maps;
- if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
- processed = new (zone()) InsufficientFeedback();
- } else if (!receiver_maps.empty()) {
- base::Optional<NameRef> name = static_name.has_value()
- ? static_name
- : broker()->GetNameFeedback(nexus);
- if (name.has_value()) {
- ZoneVector<PropertyAccessInfo> access_infos(zone());
- AccessInfoFactory access_info_factory(broker(), dependencies(),
- graph()->zone());
- access_info_factory.ComputePropertyAccessInfos(
- receiver_maps, name->object(), access_mode, &access_infos);
- processed = new (zone()) NamedAccessFeedback(*name, access_infos);
- } else if (nexus.GetKeyType() == ELEMENT &&
- MEGAMORPHIC != nexus.ic_state()) {
- processed = broker()->ProcessFeedbackMapsForElementAccess(
- receiver_maps, KeyedAccessMode::FromNexus(nexus));
- }
- }
- }
- }
+ node->opcode() == IrOpcode::kJSStoreNamedOwn ||
+ node->opcode() == IrOpcode::kJSGetIterator);
+ DCHECK_GE(node->op()->ControlOutputCount(), 1);
- if (processed == nullptr) return NoChange();
- switch (processed->kind()) {
+ ProcessedFeedback const& feedback =
+ broker()->GetFeedbackForPropertyAccess(source, access_mode, static_name);
+ switch (feedback.kind()) {
case ProcessedFeedback::kInsufficient:
return ReduceSoftDeoptimize(
node,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
case ProcessedFeedback::kNamedAccess:
- return ReduceNamedAccess(node, value, *processed->AsNamedAccess(),
+ return ReduceNamedAccess(node, value, feedback.AsNamedAccess(),
access_mode, key);
case ProcessedFeedback::kElementAccess:
- CHECK_EQ(processed->AsElementAccess()->keyed_mode.access_mode(),
- access_mode);
- return ReduceElementAccess(node, key, value,
- *processed->AsElementAccess());
- case ProcessedFeedback::kGlobalAccess:
+ DCHECK_EQ(feedback.AsElementAccess().keyed_mode().access_mode(),
+ access_mode);
+ return ReduceElementAccess(node, key, value, feedback.AsElementAccess());
+ default:
UNREACHABLE();
}
}
@@ -1807,7 +1851,7 @@ Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
Node* frame_state =
NodeProperties::FindFrameStateBefore(node, jsgraph()->Dead());
Node* deoptimize = graph()->NewNode(
- common()->Deoptimize(DeoptimizeKind::kSoft, reason, VectorSlotPair()),
+ common()->Deoptimize(DeoptimizeKind::kSoft, reason, FeedbackSource()),
frame_state, effect, control);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
@@ -1818,7 +1862,6 @@ Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
}
Reduction JSNativeContextSpecialization::ReduceJSHasProperty(Node* node) {
- DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSHasProperty, node->opcode());
PropertyAccess const& p = PropertyAccessOf(node->op());
Node* key = NodeProperties::GetValueInput(node, 1);
@@ -1936,7 +1979,6 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey(
}
Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
- DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
PropertyAccess const& p = PropertyAccessOf(node->op());
Node* name = NodeProperties::GetValueInput(node, 1);
@@ -1953,7 +1995,6 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
}
Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
- DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
PropertyAccess const& p = PropertyAccessOf(node->op());
Node* const key = NodeProperties::GetValueInput(node, 1);
@@ -1975,7 +2016,7 @@ Node* JSNativeContextSpecialization::InlinePropertyGetterCall(
Node* value;
if (constant.IsJSFunction()) {
value = *effect = *control = graph()->NewNode(
- jsgraph()->javascript()->Call(2, CallFrequency(), VectorSlotPair(),
+ jsgraph()->javascript()->Call(2, CallFrequency(), FeedbackSource(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, context, frame_state, *effect, *control);
} else {
@@ -2012,7 +2053,7 @@ void JSNativeContextSpecialization::InlinePropertySetterCall(
// Introduce the call to the setter function.
if (constant.IsJSFunction()) {
*effect = *control = graph()->NewNode(
- jsgraph()->javascript()->Call(3, CallFrequency(), VectorSlotPair(),
+ jsgraph()->javascript()->Call(3, CallFrequency(), FeedbackSource(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, value, context, frame_state, *effect, *control);
} else {
@@ -2197,12 +2238,10 @@ JSNativeContextSpecialization::BuildPropertyStore(
Node* storage = receiver;
if (!field_index.is_inobject()) {
storage = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
+ simplified()->LoadField(
+ AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer()),
storage, effect, control);
}
- PropertyConstness constness = access_info.IsDataConstant()
- ? PropertyConstness::kConst
- : PropertyConstness::kMutable;
bool store_to_existing_constant_field = access_info.IsDataConstant() &&
access_mode == AccessMode::kStore &&
!access_info.HasTransitionMap();
@@ -2215,24 +2254,25 @@ JSNativeContextSpecialization::BuildPropertyStore(
MachineType::TypeForRepresentation(field_representation),
kFullWriteBarrier,
LoadSensitivity::kUnsafe,
- constness};
+ access_info.GetConstFieldInfo(),
+ access_mode == AccessMode::kStoreInLiteral};
switch (field_representation) {
case MachineRepresentation::kFloat64: {
value = effect =
- graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), value,
+ graph()->NewNode(simplified()->CheckNumber(FeedbackSource()), value,
effect, control);
if (!field_index.is_inobject() || !FLAG_unbox_double_fields) {
if (access_info.HasTransitionMap()) {
- // Allocate a MutableHeapNumber for the new property.
+ // Allocate a HeapNumber for the new property.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(HeapNumber::kSize, AllocationType::kYoung,
Type::OtherInternal());
a.Store(AccessBuilder::ForMap(),
- factory()->mutable_heap_number_map());
+ MapRef(broker(), factory()->heap_number_map()));
FieldAccess value_field_access =
AccessBuilder::ForHeapNumberValue();
- value_field_access.constness = field_access.constness;
+ value_field_access.const_field_info = field_access.const_field_info;
a.Store(value_field_access, value);
value = effect = a.Finish();
@@ -2241,7 +2281,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
MachineType::TypeCompressedTaggedPointer();
field_access.write_barrier_kind = kPointerWriteBarrier;
} else {
- // We just store directly to the MutableHeapNumber.
+ // We just store directly to the HeapNumber.
FieldAccess const storage_access = {
kTaggedBase,
field_index.offset(),
@@ -2251,7 +2291,8 @@ JSNativeContextSpecialization::BuildPropertyStore(
MachineType::TypeCompressedTaggedPointer(),
kPointerWriteBarrier,
LoadSensitivity::kUnsafe,
- constness};
+ access_info.GetConstFieldInfo(),
+ access_mode == AccessMode::kStoreInLiteral};
storage = effect =
graph()->NewNode(simplified()->LoadField(storage_access),
storage, effect, control);
@@ -2300,7 +2341,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
if (field_representation == MachineRepresentation::kTaggedSigned ||
field_representation == MachineRepresentation::kCompressedSigned) {
value = effect = graph()->NewNode(
- simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
+ simplified()->CheckSmi(FeedbackSource()), value, effect, control);
field_access.write_barrier_kind = kNoWriteBarrier;
} else if (field_representation ==
@@ -2356,7 +2397,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
storage, value, effect, control);
// Atomically switch to the new properties below.
- field_access = AccessBuilder::ForJSObjectPropertiesOrHash();
+ field_access = AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer();
value = storage;
storage = receiver;
}
@@ -2382,80 +2423,18 @@ JSNativeContextSpecialization::BuildPropertyStore(
Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode());
-
FeedbackParameter const& p = FeedbackParameterOf(node->op());
+ Node* const key = NodeProperties::GetValueInput(node, 1);
+ Node* const value = NodeProperties::GetValueInput(node, 2);
if (!p.feedback().IsValid()) return NoChange();
-
- FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
- if (nexus.IsUninitialized()) {
- return NoChange();
- }
-
- if (nexus.ic_state() == MEGAMORPHIC) {
- return NoChange();
- }
-
- DCHECK_EQ(MONOMORPHIC, nexus.ic_state());
-
- Map map = nexus.GetFirstMap();
- if (map.is_null()) {
- // Maps are weakly held in the type feedback vector, we may not have one.
- return NoChange();
- }
-
- Handle<Map> receiver_map(map, isolate());
- if (!Map::TryUpdate(isolate(), receiver_map).ToHandle(&receiver_map))
- return NoChange();
-
- NameRef cached_name(
- broker(),
- handle(Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()),
- isolate()));
-
- AccessInfoFactory access_info_factory(broker(), dependencies(),
- graph()->zone());
- PropertyAccessInfo access_info =
- access_info_factory.ComputePropertyAccessInfo(
- receiver_map, cached_name.object(), AccessMode::kStoreInLiteral);
- if (access_info.IsInvalid()) return NoChange();
- access_info.RecordDependencies(dependencies());
-
- Node* receiver = NodeProperties::GetValueInput(node, 0);
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* control = NodeProperties::GetControlInput(node);
-
- // Monomorphic property access.
- PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
- access_builder.BuildCheckMaps(receiver, &effect, control,
- access_info.receiver_maps());
-
- // Ensure that {name} matches the cached name.
- Node* name = NodeProperties::GetValueInput(node, 1);
- Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name,
- jsgraph()->Constant(cached_name));
- effect = graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongName),
- check, effect, control);
-
- Node* value = NodeProperties::GetValueInput(node, 2);
- Node* context = NodeProperties::GetContextInput(node);
- Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node);
-
- // Generate the actual property access.
- ValueEffectControl continuation = BuildPropertyAccess(
- receiver, value, context, frame_state_lazy, effect, control, cached_name,
- nullptr, access_info, AccessMode::kStoreInLiteral);
- value = continuation.value();
- effect = continuation.effect();
- control = continuation.control();
-
- ReplaceWithValue(node, value, effect, control);
- return Replace(value);
+ return ReducePropertyAccess(node, key, base::nullopt, value,
+ FeedbackSource(p.feedback()),
+ AccessMode::kStoreInLiteral);
}
Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral(
Node* node) {
- DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSStoreInArrayLiteral, node->opcode());
FeedbackParameter const& p = FeedbackParameterOf(node->op());
Node* const index = NodeProperties::GetValueInput(node, 1);
@@ -2591,7 +2570,7 @@ JSNativeContextSpecialization::BuildElementAccess(
// bounds check below and just skip the property access if it's out of
// bounds for the {receiver}.
index = effect = graph()->NewNode(
- simplified()->CheckSmi(VectorSlotPair()), index, effect, control);
+ simplified()->CheckSmi(FeedbackSource()), index, effect, control);
// Cast the {index} to Unsigned32 range, so that the bounds checks
// below are performed on unsigned values, which means that all the
@@ -2600,7 +2579,7 @@ JSNativeContextSpecialization::BuildElementAccess(
} else {
// Check that the {index} is in the valid range for the {receiver}.
index = effect =
- graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
+ graph()->NewNode(simplified()->CheckBounds(FeedbackSource()), index,
length, effect, control);
}
@@ -2660,7 +2639,7 @@ JSNativeContextSpecialization::BuildElementAccess(
// and truncate it to a Number appropriately.
value = effect = graph()->NewNode(
simplified()->SpeculativeToNumber(
- NumberOperationHint::kNumberOrOddball, VectorSlotPair()),
+ NumberOperationHint::kNumberOrOddball, FeedbackSource()),
value, effect, control);
// Introduce the appropriate truncation for {value}. Currently we
@@ -2756,12 +2735,12 @@ JSNativeContextSpecialization::BuildElementAccess(
// bounds check below and just skip the store below if it's out of
// bounds for the {receiver}.
index = effect = graph()->NewNode(
- simplified()->CheckBounds(VectorSlotPair()), index,
+ simplified()->CheckBounds(FeedbackSource()), index,
jsgraph()->Constant(Smi::kMaxValue), effect, control);
} else {
// Check that the {index} is in the valid range for the {receiver}.
index = effect =
- graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
+ graph()->NewNode(simplified()->CheckBounds(FeedbackSource()), index,
length, effect, control);
}
@@ -2825,7 +2804,7 @@ JSNativeContextSpecialization::BuildElementAccess(
// truncating.
vtrue = etrue = graph()->NewNode(
simplified()->CheckFloat64Hole(
- CheckFloat64HoleMode::kAllowReturnHole, VectorSlotPair()),
+ CheckFloat64HoleMode::kAllowReturnHole, FeedbackSource()),
vtrue, etrue, if_true);
}
}
@@ -2874,7 +2853,7 @@ JSNativeContextSpecialization::BuildElementAccess(
mode = CheckFloat64HoleMode::kAllowReturnHole;
}
value = effect = graph()->NewNode(
- simplified()->CheckFloat64Hole(mode, VectorSlotPair()), value,
+ simplified()->CheckFloat64Hole(mode, FeedbackSource()), value,
effect, control);
}
}
@@ -2905,7 +2884,7 @@ JSNativeContextSpecialization::BuildElementAccess(
Node* etrue = effect;
Node* checked = etrue =
- graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
+ graph()->NewNode(simplified()->CheckBounds(FeedbackSource()), index,
length, etrue, if_true);
Node* element = etrue =
@@ -2936,7 +2915,7 @@ JSNativeContextSpecialization::BuildElementAccess(
} else {
etrue = graph()->NewNode(
simplified()->CheckFloat64Hole(
- CheckFloat64HoleMode::kNeverReturnHole, VectorSlotPair()),
+ CheckFloat64HoleMode::kNeverReturnHole, FeedbackSource()),
element, etrue, if_true);
}
@@ -2956,10 +2935,10 @@ JSNativeContextSpecialization::BuildElementAccess(
if (IsSmiElementsKind(elements_kind)) {
value = effect = graph()->NewNode(
- simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
+ simplified()->CheckSmi(FeedbackSource()), value, effect, control);
} else if (IsDoubleElementsKind(elements_kind)) {
value = effect =
- graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), value,
+ graph()->NewNode(simplified()->CheckNumber(FeedbackSource()), value,
effect, control);
// Make sure we do not store signalling NaNs into double arrays.
value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
@@ -2994,7 +2973,7 @@ JSNativeContextSpecialization::BuildElementAccess(
: graph()->NewNode(simplified()->NumberAdd(), length,
jsgraph()->OneConstant());
index = effect =
- graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
+ graph()->NewNode(simplified()->CheckBounds(FeedbackSource()), index,
limit, effect, control);
// Grow {elements} backing store if necessary.
@@ -3003,7 +2982,7 @@ JSNativeContextSpecialization::BuildElementAccess(
? GrowFastElementsMode::kDoubleElements
: GrowFastElementsMode::kSmiOrObjectElements;
elements = effect = graph()->NewNode(
- simplified()->MaybeGrowFastElements(mode, VectorSlotPair()),
+ simplified()->MaybeGrowFastElements(mode, FeedbackSource()),
receiver, elements, index, elements_length, effect, control);
// If we didn't grow {elements}, it might still be COW, in which case we
@@ -3063,7 +3042,7 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad(
dependencies()->DependOnNoElementsProtector()) {
// Ensure that the {index} is a valid String length.
index = *effect = graph()->NewNode(
- simplified()->CheckBounds(VectorSlotPair()), index,
+ simplified()->CheckBounds(FeedbackSource()), index,
jsgraph()->Constant(String::kMaxLength), *effect, *control);
// Load the single character string from {receiver} or yield
@@ -3095,7 +3074,7 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad(
} else {
// Ensure that {index} is less than {receiver} length.
index = *effect =
- graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
+ graph()->NewNode(simplified()->CheckBounds(FeedbackSource()), index,
length, *effect, *control);
Node* masked_index = graph()->NewNode(simplified()->PoisonIndex(), index);
@@ -3196,7 +3175,6 @@ bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
// native contexts, as the global Array protector works isolate-wide).
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
- if (!FLAG_concurrent_inlining) receiver_map.SerializePrototype();
ObjectRef receiver_prototype = receiver_map.prototype();
if (!receiver_prototype.IsJSObject() ||
!broker()->IsArrayOrObjectPrototype(receiver_prototype.AsJSObject())) {
@@ -3208,47 +3186,9 @@ bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
return dependencies()->DependOnNoElementsProtector();
}
-// Returns false iff we have insufficient feedback (uninitialized or obsolete).
-bool JSNativeContextSpecialization::ExtractReceiverMaps(
- Node* receiver, Node* effect, FeedbackNexus const& nexus,
- MapHandles* receiver_maps) {
- DCHECK(receiver_maps->empty());
- if (nexus.IsUninitialized()) return false;
-
- // See if we can infer a concrete type for the {receiver}. Solely relying on
- // the inference is not safe for keyed stores, because we would potentially
- // miss out on transitions that need to be performed.
- {
- FeedbackSlotKind kind = nexus.kind();
- bool use_inference =
- !IsKeyedStoreICKind(kind) && !IsStoreInArrayLiteralICKind(kind);
- if (use_inference && InferReceiverMaps(receiver, effect, receiver_maps)) {
- TryUpdateThenDropDeprecated(isolate(), receiver_maps);
- return true;
- }
- }
-
- if (nexus.ExtractMaps(receiver_maps) == 0) return true;
-
- // Try to filter impossible candidates based on inferred root map.
- Handle<Map> root_map;
- if (InferReceiverRootMap(receiver).ToHandle(&root_map)) {
- DCHECK(!root_map->is_abandoned_prototype_map());
- Isolate* isolate = this->isolate();
- receiver_maps->erase(
- std::remove_if(receiver_maps->begin(), receiver_maps->end(),
- [root_map, isolate](Handle<Map> map) {
- return map->is_abandoned_prototype_map() ||
- map->FindRootMap(isolate) != *root_map;
- }),
- receiver_maps->end());
- }
- TryUpdateThenDropDeprecated(isolate(), receiver_maps);
- return !receiver_maps->empty();
-}
-
bool JSNativeContextSpecialization::InferReceiverMaps(
- Node* receiver, Node* effect, MapHandles* receiver_maps) {
+ Node* receiver, Node* effect,
+ ZoneVector<Handle<Map>>* receiver_maps) const {
ZoneHandleSet<Map> maps;
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMapsUnsafe(broker(), receiver, effect,
@@ -3273,21 +3213,24 @@ bool JSNativeContextSpecialization::InferReceiverMaps(
return false;
}
-MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
- Node* receiver) {
+base::Optional<MapRef> JSNativeContextSpecialization::InferReceiverRootMap(
+ Node* receiver) const {
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
- return handle(m.Value()->map().FindRootMap(isolate()), isolate());
+ MapRef map = m.Ref(broker()).map();
+ return map.FindRootMap();
} else if (m.IsJSCreate()) {
base::Optional<MapRef> initial_map =
NodeProperties::GetJSCreateMap(broker(), receiver);
if (initial_map.has_value()) {
- DCHECK_EQ(*initial_map->object(),
- initial_map->object()->FindRootMap(isolate()));
- return initial_map->object();
+ if (!initial_map->FindRootMap().has_value()) {
+ return base::nullopt;
+ }
+ DCHECK(initial_map->equals(*initial_map->FindRootMap()));
+ return *initial_map;
}
}
- return MaybeHandle<Map>();
+ return base::nullopt;
}
Graph* JSNativeContextSpecialization::graph() const {
diff --git a/deps/v8/src/compiler/js-native-context-specialization.h b/deps/v8/src/compiler/js-native-context-specialization.h
index 8510c76bfc..a0707b9830 100644
--- a/deps/v8/src/compiler/js-native-context-specialization.h
+++ b/deps/v8/src/compiler/js-native-context-specialization.h
@@ -53,7 +53,6 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
JSNativeContextSpecialization(Editor* editor, JSGraph* jsgraph,
JSHeapBroker* broker, Flags flags,
- Handle<Context> native_context,
CompilationDependencies* dependencies,
Zone* zone, Zone* shared_zone);
@@ -84,6 +83,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
Reduction ReduceJSLoadGlobal(Node* node);
Reduction ReduceJSStoreGlobal(Node* node);
Reduction ReduceJSLoadNamed(Node* node);
+ Reduction ReduceJSGetIterator(Node* node);
Reduction ReduceJSStoreNamed(Node* node);
Reduction ReduceJSHasProperty(Node* node);
Reduction ReduceJSLoadProperty(Node* node);
@@ -114,9 +114,9 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
Reduction ReduceGlobalAccess(Node* node, Node* receiver, Node* value,
NameRef const& name, AccessMode access_mode,
Node* key, PropertyCellRef const& property_cell);
- Reduction ReduceKeyedLoadFromHeapConstant(Node* node, Node* key,
- AccessMode access_mode,
- KeyedAccessLoadMode load_mode);
+ Reduction ReduceElementLoadFromHeapConstant(Node* node, Node* key,
+ AccessMode access_mode,
+ KeyedAccessLoadMode load_mode);
Reduction ReduceElementAccessOnString(Node* node, Node* index, Node* value,
KeyedAccessMode const& keyed_mode);
@@ -212,18 +212,25 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
// code dependencies and might use the array protector cell.
bool CanTreatHoleAsUndefined(ZoneVector<Handle<Map>> const& receiver_maps);
- // Extract receiver maps from {nexus} and filter based on {receiver} if
- // possible.
- bool ExtractReceiverMaps(Node* receiver, Node* effect,
- FeedbackNexus const& nexus,
- MapHandles* receiver_maps);
+ void RemoveImpossibleReceiverMaps(
+ Node* receiver, ZoneVector<Handle<Map>>* receiver_maps) const;
+
+ ElementAccessFeedback const& TryRefineElementAccessFeedback(
+ ElementAccessFeedback const& feedback, Node* receiver,
+ Node* effect) const;
+
+ void FilterMapsAndGetPropertyAccessInfos(
+ NamedAccessFeedback const& feedback, AccessMode access_mode,
+ Node* receiver, Node* effect,
+ ZoneVector<PropertyAccessInfo>* access_infos);
// Try to infer maps for the given {receiver} at the current {effect}.
bool InferReceiverMaps(Node* receiver, Node* effect,
- MapHandles* receiver_maps);
+ ZoneVector<Handle<Map>>* receiver_maps) const;
+
// Try to infer a root map for the {receiver} independent of the current
// program location.
- MaybeHandle<Map> InferReceiverRootMap(Node* receiver);
+ base::Optional<MapRef> InferReceiverRootMap(Node* receiver) const;
// Checks if we know at compile time that the {receiver} either definitely
// has the {prototype} in it's prototype chain, or the {receiver} definitely
@@ -234,7 +241,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
kMayBeInPrototypeChain
};
InferHasInPrototypeChainResult InferHasInPrototypeChain(
- Node* receiver, Node* effect, Handle<HeapObject> prototype);
+ Node* receiver, Node* effect, HeapObjectRef const& prototype);
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
@@ -248,7 +255,9 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
Flags flags() const { return flags_; }
Handle<JSGlobalObject> global_object() const { return global_object_; }
Handle<JSGlobalProxy> global_proxy() const { return global_proxy_; }
- NativeContextRef native_context() const { return broker()->native_context(); }
+ NativeContextRef native_context() const {
+ return broker()->target_native_context();
+ }
CompilationDependencies* dependencies() const { return dependencies_; }
Zone* zone() const { return zone_; }
Zone* shared_zone() const { return shared_zone_; }
diff --git a/deps/v8/src/compiler/js-operator.cc b/deps/v8/src/compiler/js-operator.cc
index e0f97922b2..d0581b59a5 100644
--- a/deps/v8/src/compiler/js-operator.cc
+++ b/deps/v8/src/compiler/js-operator.cc
@@ -9,7 +9,6 @@
#include "src/base/lazy-instance.h"
#include "src/compiler/opcodes.h"
#include "src/compiler/operator.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/handles/handles-inl.h"
#include "src/objects/objects-inl.h"
@@ -51,7 +50,8 @@ bool operator!=(ConstructParameters const& lhs,
}
size_t hash_value(ConstructParameters const& p) {
- return base::hash_combine(p.arity(), p.frequency(), p.feedback());
+ return base::hash_combine(p.arity(), p.frequency(),
+ FeedbackSource::Hash()(p.feedback()));
}
std::ostream& operator<<(std::ostream& os, ConstructParameters const& p) {
@@ -198,7 +198,8 @@ bool operator!=(StoreNamedOwnParameters const& lhs,
}
size_t hash_value(StoreNamedOwnParameters const& p) {
- return base::hash_combine(p.name().location(), p.feedback());
+ return base::hash_combine(p.name().location(),
+ FeedbackSource::Hash()(p.feedback()));
}
std::ostream& operator<<(std::ostream& os, StoreNamedOwnParameters const& p) {
@@ -219,7 +220,7 @@ bool operator!=(FeedbackParameter const& lhs, FeedbackParameter const& rhs) {
}
size_t hash_value(FeedbackParameter const& p) {
- return base::hash_combine(p.feedback());
+ return FeedbackSource::Hash()(p.feedback());
}
std::ostream& operator<<(std::ostream& os, FeedbackParameter const& p) {
@@ -248,7 +249,7 @@ bool operator!=(NamedAccess const& lhs, NamedAccess const& rhs) {
size_t hash_value(NamedAccess const& p) {
return base::hash_combine(p.name().location(), p.language_mode(),
- p.feedback());
+ FeedbackSource::Hash()(p.feedback()));
}
@@ -283,13 +284,15 @@ bool operator!=(PropertyAccess const& lhs, PropertyAccess const& rhs) {
PropertyAccess const& PropertyAccessOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kJSHasProperty ||
op->opcode() == IrOpcode::kJSLoadProperty ||
- op->opcode() == IrOpcode::kJSStoreProperty);
+ op->opcode() == IrOpcode::kJSStoreProperty ||
+ op->opcode() == IrOpcode::kJSGetIterator);
return OpParameter<PropertyAccess>(op);
}
size_t hash_value(PropertyAccess const& p) {
- return base::hash_combine(p.language_mode(), p.feedback());
+ return base::hash_combine(p.language_mode(),
+ FeedbackSource::Hash()(p.feedback()));
}
@@ -339,7 +342,7 @@ bool operator!=(StoreGlobalParameters const& lhs,
size_t hash_value(StoreGlobalParameters const& p) {
return base::hash_combine(p.language_mode(), p.name().location(),
- p.feedback());
+ FeedbackSource::Hash()(p.feedback()));
}
@@ -518,7 +521,8 @@ bool operator!=(CreateLiteralParameters const& lhs,
size_t hash_value(CreateLiteralParameters const& p) {
- return base::hash_combine(p.constant().location(), p.feedback(), p.length(),
+ return base::hash_combine(p.constant().location(),
+ FeedbackSource::Hash()(p.feedback()), p.length(),
p.flags());
}
@@ -546,7 +550,7 @@ bool operator!=(CloneObjectParameters const& lhs,
}
size_t hash_value(CloneObjectParameters const& p) {
- return base::hash_combine(p.feedback(), p.flags());
+ return base::hash_combine(FeedbackSource::Hash()(p.feedback()), p.flags());
}
std::ostream& operator<<(std::ostream& os, CloneObjectParameters const& p) {
@@ -795,18 +799,18 @@ COMPARE_OP_LIST(COMPARE_OP)
#undef COMPARE_OP
const Operator* JSOperatorBuilder::StoreDataPropertyInLiteral(
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
FeedbackParameter parameters(feedback);
return new (zone()) Operator1<FeedbackParameter>( // --
IrOpcode::kJSStoreDataPropertyInLiteral,
Operator::kNoThrow, // opcode
"JSStoreDataPropertyInLiteral", // name
- 4, 1, 1, 0, 1, 0, // counts
+ 4, 1, 1, 0, 1, 1, // counts
parameters); // parameter
}
const Operator* JSOperatorBuilder::StoreInArrayLiteral(
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
FeedbackParameter parameters(feedback);
return new (zone()) Operator1<FeedbackParameter>( // --
IrOpcode::kJSStoreInArrayLiteral,
@@ -828,7 +832,7 @@ const Operator* JSOperatorBuilder::CallForwardVarargs(size_t arity,
const Operator* JSOperatorBuilder::Call(size_t arity,
CallFrequency const& frequency,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
ConvertReceiverMode convert_mode,
SpeculationMode speculation_mode) {
DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
@@ -853,7 +857,7 @@ const Operator* JSOperatorBuilder::CallWithArrayLike(
const Operator* JSOperatorBuilder::CallWithSpread(
uint32_t arity, CallFrequency const& frequency,
- VectorSlotPair const& feedback, SpeculationMode speculation_mode) {
+ FeedbackSource const& feedback, SpeculationMode speculation_mode) {
DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation,
feedback.IsValid());
CallParameters parameters(arity, frequency, feedback,
@@ -903,7 +907,7 @@ const Operator* JSOperatorBuilder::ConstructForwardVarargs(
// on AIX (v8:8193).
const Operator* JSOperatorBuilder::Construct(uint32_t arity,
CallFrequency const& frequency,
- VectorSlotPair const& feedback) {
+ FeedbackSource const& feedback) {
ConstructParameters parameters(arity, frequency, feedback);
return new (zone()) Operator1<ConstructParameters>( // --
IrOpcode::kJSConstruct, Operator::kNoProperties, // opcode
@@ -924,7 +928,7 @@ const Operator* JSOperatorBuilder::ConstructWithArrayLike(
const Operator* JSOperatorBuilder::ConstructWithSpread(
uint32_t arity, CallFrequency const& frequency,
- VectorSlotPair const& feedback) {
+ FeedbackSource const& feedback) {
ConstructParameters parameters(arity, frequency, feedback);
return new (zone()) Operator1<ConstructParameters>( // --
IrOpcode::kJSConstructWithSpread, Operator::kNoProperties, // opcode
@@ -934,7 +938,7 @@ const Operator* JSOperatorBuilder::ConstructWithSpread(
}
const Operator* JSOperatorBuilder::LoadNamed(Handle<Name> name,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
NamedAccess access(LanguageMode::kSloppy, name, feedback);
return new (zone()) Operator1<NamedAccess>( // --
IrOpcode::kJSLoadNamed, Operator::kNoProperties, // opcode
@@ -944,7 +948,7 @@ const Operator* JSOperatorBuilder::LoadNamed(Handle<Name> name,
}
const Operator* JSOperatorBuilder::LoadProperty(
- VectorSlotPair const& feedback) {
+ FeedbackSource const& feedback) {
PropertyAccess access(LanguageMode::kSloppy, feedback);
return new (zone()) Operator1<PropertyAccess>( // --
IrOpcode::kJSLoadProperty, Operator::kNoProperties, // opcode
@@ -953,7 +957,16 @@ const Operator* JSOperatorBuilder::LoadProperty(
access); // parameter
}
-const Operator* JSOperatorBuilder::HasProperty(VectorSlotPair const& feedback) {
+const Operator* JSOperatorBuilder::GetIterator(FeedbackSource const& feedback) {
+ PropertyAccess access(LanguageMode::kSloppy, feedback);
+ return new (zone()) Operator1<PropertyAccess>( // --
+ IrOpcode::kJSGetIterator, Operator::kNoProperties, // opcode
+ "JSGetIterator", // name
+ 1, 1, 1, 1, 1, 2, // counts
+ access); // parameter
+}
+
+const Operator* JSOperatorBuilder::HasProperty(FeedbackSource const& feedback) {
PropertyAccess access(LanguageMode::kSloppy, feedback);
return new (zone()) Operator1<PropertyAccess>( // --
IrOpcode::kJSHasProperty, Operator::kNoProperties, // opcode
@@ -962,7 +975,7 @@ const Operator* JSOperatorBuilder::HasProperty(VectorSlotPair const& feedback) {
access); // parameter
}
-const Operator* JSOperatorBuilder::InstanceOf(VectorSlotPair const& feedback) {
+const Operator* JSOperatorBuilder::InstanceOf(FeedbackSource const& feedback) {
FeedbackParameter parameter(feedback);
return new (zone()) Operator1<FeedbackParameter>( // --
IrOpcode::kJSInstanceOf, Operator::kNoProperties, // opcode
@@ -1021,7 +1034,7 @@ int RestoreRegisterIndexOf(const Operator* op) {
const Operator* JSOperatorBuilder::StoreNamed(LanguageMode language_mode,
Handle<Name> name,
- VectorSlotPair const& feedback) {
+ FeedbackSource const& feedback) {
NamedAccess access(language_mode, name, feedback);
return new (zone()) Operator1<NamedAccess>( // --
IrOpcode::kJSStoreNamed, Operator::kNoProperties, // opcode
@@ -1030,9 +1043,8 @@ const Operator* JSOperatorBuilder::StoreNamed(LanguageMode language_mode,
access); // parameter
}
-
const Operator* JSOperatorBuilder::StoreProperty(
- LanguageMode language_mode, VectorSlotPair const& feedback) {
+ LanguageMode language_mode, FeedbackSource const& feedback) {
PropertyAccess access(language_mode, feedback);
return new (zone()) Operator1<PropertyAccess>( // --
IrOpcode::kJSStoreProperty, Operator::kNoProperties, // opcode
@@ -1042,7 +1054,7 @@ const Operator* JSOperatorBuilder::StoreProperty(
}
const Operator* JSOperatorBuilder::StoreNamedOwn(
- Handle<Name> name, VectorSlotPair const& feedback) {
+ Handle<Name> name, FeedbackSource const& feedback) {
StoreNamedOwnParameters parameters(name, feedback);
return new (zone()) Operator1<StoreNamedOwnParameters>( // --
IrOpcode::kJSStoreNamedOwn, Operator::kNoProperties, // opcode
@@ -1066,7 +1078,7 @@ const Operator* JSOperatorBuilder::CreateGeneratorObject() {
}
const Operator* JSOperatorBuilder::LoadGlobal(const Handle<Name>& name,
- const VectorSlotPair& feedback,
+ const FeedbackSource& feedback,
TypeofMode typeof_mode) {
LoadGlobalParameters parameters(name, feedback, typeof_mode);
return new (zone()) Operator1<LoadGlobalParameters>( // --
@@ -1076,10 +1088,9 @@ const Operator* JSOperatorBuilder::LoadGlobal(const Handle<Name>& name,
parameters); // parameter
}
-
const Operator* JSOperatorBuilder::StoreGlobal(LanguageMode language_mode,
const Handle<Name>& name,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
StoreGlobalParameters parameters(language_mode, feedback, name);
return new (zone()) Operator1<StoreGlobalParameters>( // --
IrOpcode::kJSStoreGlobal, Operator::kNoProperties, // opcode
@@ -1088,7 +1099,6 @@ const Operator* JSOperatorBuilder::StoreGlobal(LanguageMode language_mode,
parameters); // parameter
}
-
const Operator* JSOperatorBuilder::LoadContext(size_t depth, size_t index,
bool immutable) {
ContextAccess access(depth, index, immutable);
@@ -1203,7 +1213,7 @@ const Operator* JSOperatorBuilder::CreateClosure(
const Operator* JSOperatorBuilder::CreateLiteralArray(
Handle<ArrayBoilerplateDescription> description,
- VectorSlotPair const& feedback, int literal_flags, int number_of_elements) {
+ FeedbackSource const& feedback, int literal_flags, int number_of_elements) {
CreateLiteralParameters parameters(description, feedback, number_of_elements,
literal_flags);
return new (zone()) Operator1<CreateLiteralParameters>( // --
@@ -1215,7 +1225,7 @@ const Operator* JSOperatorBuilder::CreateLiteralArray(
}
const Operator* JSOperatorBuilder::CreateEmptyLiteralArray(
- VectorSlotPair const& feedback) {
+ FeedbackSource const& feedback) {
FeedbackParameter parameters(feedback);
return new (zone()) Operator1<FeedbackParameter>( // --
IrOpcode::kJSCreateEmptyLiteralArray, // opcode
@@ -1235,7 +1245,7 @@ const Operator* JSOperatorBuilder::CreateArrayFromIterable() {
const Operator* JSOperatorBuilder::CreateLiteralObject(
Handle<ObjectBoilerplateDescription> constant_properties,
- VectorSlotPair const& feedback, int literal_flags,
+ FeedbackSource const& feedback, int literal_flags,
int number_of_properties) {
CreateLiteralParameters parameters(constant_properties, feedback,
number_of_properties, literal_flags);
@@ -1247,7 +1257,7 @@ const Operator* JSOperatorBuilder::CreateLiteralObject(
parameters); // parameter
}
-const Operator* JSOperatorBuilder::CloneObject(VectorSlotPair const& feedback,
+const Operator* JSOperatorBuilder::CloneObject(FeedbackSource const& feedback,
int literal_flags) {
CloneObjectParameters parameters(feedback, literal_flags);
return new (zone()) Operator1<CloneObjectParameters>( // --
@@ -1267,7 +1277,7 @@ const Operator* JSOperatorBuilder::CreateEmptyLiteralObject() {
}
const Operator* JSOperatorBuilder::CreateLiteralRegExp(
- Handle<String> constant_pattern, VectorSlotPair const& feedback,
+ Handle<String> constant_pattern, FeedbackSource const& feedback,
int literal_flags) {
CreateLiteralParameters parameters(constant_pattern, feedback, -1,
literal_flags);
diff --git a/deps/v8/src/compiler/js-operator.h b/deps/v8/src/compiler/js-operator.h
index e7d9acb152..f795a2f402 100644
--- a/deps/v8/src/compiler/js-operator.h
+++ b/deps/v8/src/compiler/js-operator.h
@@ -7,7 +7,7 @@
#include "src/base/compiler-specific.h"
#include "src/common/globals.h"
-#include "src/compiler/vector-slot-pair.h"
+#include "src/compiler/feedback-source.h"
#include "src/handles/maybe-handles.h"
#include "src/objects/type-hints.h"
#include "src/runtime/runtime.h"
@@ -102,17 +102,17 @@ ConstructForwardVarargsParameters const& ConstructForwardVarargsParametersOf(
class ConstructParameters final {
public:
ConstructParameters(uint32_t arity, CallFrequency const& frequency,
- VectorSlotPair const& feedback)
+ FeedbackSource const& feedback)
: arity_(arity), frequency_(frequency), feedback_(feedback) {}
uint32_t arity() const { return arity_; }
CallFrequency const& frequency() const { return frequency_; }
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
private:
uint32_t const arity_;
CallFrequency const frequency_;
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
};
bool operator==(ConstructParameters const&, ConstructParameters const&);
@@ -163,7 +163,7 @@ CallForwardVarargsParameters const& CallForwardVarargsParametersOf(
class CallParameters final {
public:
CallParameters(size_t arity, CallFrequency const& frequency,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
ConvertReceiverMode convert_mode,
SpeculationMode speculation_mode)
: bit_field_(ArityField::encode(arity) |
@@ -177,7 +177,7 @@ class CallParameters final {
ConvertReceiverMode convert_mode() const {
return ConvertReceiverModeField::decode(bit_field_);
}
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
SpeculationMode speculation_mode() const {
return SpeculationModeField::decode(bit_field_);
@@ -192,7 +192,9 @@ class CallParameters final {
private:
friend size_t hash_value(CallParameters const& p) {
- return base::hash_combine(p.bit_field_, p.frequency_, p.feedback_);
+ FeedbackSource::Hash feedback_hash;
+ return base::hash_combine(p.bit_field_, p.frequency_,
+ feedback_hash(p.feedback_));
}
using ArityField = BitField<size_t, 0, 28>;
@@ -201,7 +203,7 @@ class CallParameters final {
uint32_t const bit_field_;
CallFrequency const frequency_;
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
};
size_t hash_value(CallParameters const&);
@@ -297,15 +299,15 @@ CreateFunctionContextParameters const& CreateFunctionContextParametersOf(
// Defines parameters for JSStoreNamedOwn operator.
class StoreNamedOwnParameters final {
public:
- StoreNamedOwnParameters(Handle<Name> name, VectorSlotPair const& feedback)
+ StoreNamedOwnParameters(Handle<Name> name, FeedbackSource const& feedback)
: name_(name), feedback_(feedback) {}
Handle<Name> name() const { return name_; }
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
private:
Handle<Name> const name_;
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
};
bool operator==(StoreNamedOwnParameters const&, StoreNamedOwnParameters const&);
@@ -322,13 +324,13 @@ const StoreNamedOwnParameters& StoreNamedOwnParametersOf(const Operator* op);
// and JSStoreDataPropertyInLiteral operators.
class FeedbackParameter final {
public:
- explicit FeedbackParameter(VectorSlotPair const& feedback)
+ explicit FeedbackParameter(FeedbackSource const& feedback)
: feedback_(feedback) {}
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
private:
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
};
bool operator==(FeedbackParameter const&, FeedbackParameter const&);
@@ -345,16 +347,16 @@ const FeedbackParameter& FeedbackParameterOf(const Operator* op);
class NamedAccess final {
public:
NamedAccess(LanguageMode language_mode, Handle<Name> name,
- VectorSlotPair const& feedback)
+ FeedbackSource const& feedback)
: name_(name), feedback_(feedback), language_mode_(language_mode) {}
Handle<Name> name() const { return name_; }
LanguageMode language_mode() const { return language_mode_; }
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
private:
Handle<Name> const name_;
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
LanguageMode const language_mode_;
};
@@ -372,18 +374,18 @@ const NamedAccess& NamedAccessOf(const Operator* op);
// used as a parameter by JSLoadGlobal operator.
class LoadGlobalParameters final {
public:
- LoadGlobalParameters(const Handle<Name>& name, const VectorSlotPair& feedback,
+ LoadGlobalParameters(const Handle<Name>& name, const FeedbackSource& feedback,
TypeofMode typeof_mode)
: name_(name), feedback_(feedback), typeof_mode_(typeof_mode) {}
const Handle<Name>& name() const { return name_; }
TypeofMode typeof_mode() const { return typeof_mode_; }
- const VectorSlotPair& feedback() const { return feedback_; }
+ const FeedbackSource& feedback() const { return feedback_; }
private:
const Handle<Name> name_;
- const VectorSlotPair feedback_;
+ const FeedbackSource feedback_;
const TypeofMode typeof_mode_;
};
@@ -402,18 +404,18 @@ const LoadGlobalParameters& LoadGlobalParametersOf(const Operator* op);
class StoreGlobalParameters final {
public:
StoreGlobalParameters(LanguageMode language_mode,
- const VectorSlotPair& feedback,
+ const FeedbackSource& feedback,
const Handle<Name>& name)
: language_mode_(language_mode), name_(name), feedback_(feedback) {}
LanguageMode language_mode() const { return language_mode_; }
- const VectorSlotPair& feedback() const { return feedback_; }
+ const FeedbackSource& feedback() const { return feedback_; }
const Handle<Name>& name() const { return name_; }
private:
const LanguageMode language_mode_;
const Handle<Name> name_;
- const VectorSlotPair feedback_;
+ const FeedbackSource feedback_;
};
bool operator==(StoreGlobalParameters const&, StoreGlobalParameters const&);
@@ -430,14 +432,14 @@ const StoreGlobalParameters& StoreGlobalParametersOf(const Operator* op);
// as a parameter by the JSLoadProperty and JSStoreProperty operators.
class PropertyAccess final {
public:
- PropertyAccess(LanguageMode language_mode, VectorSlotPair const& feedback)
+ PropertyAccess(LanguageMode language_mode, FeedbackSource const& feedback)
: feedback_(feedback), language_mode_(language_mode) {}
LanguageMode language_mode() const { return language_mode_; }
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
private:
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
LanguageMode const language_mode_;
};
@@ -602,20 +604,20 @@ const CreateClosureParameters& CreateClosureParametersOf(const Operator* op);
class CreateLiteralParameters final {
public:
CreateLiteralParameters(Handle<HeapObject> constant,
- VectorSlotPair const& feedback, int length, int flags)
+ FeedbackSource const& feedback, int length, int flags)
: constant_(constant),
feedback_(feedback),
length_(length),
flags_(flags) {}
Handle<HeapObject> constant() const { return constant_; }
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
int length() const { return length_; }
int flags() const { return flags_; }
private:
Handle<HeapObject> const constant_;
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
int const length_;
int const flags_;
};
@@ -631,14 +633,14 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op);
class CloneObjectParameters final {
public:
- CloneObjectParameters(VectorSlotPair const& feedback, int flags)
+ CloneObjectParameters(FeedbackSource const& feedback, int flags)
: feedback_(feedback), flags_(flags) {}
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
int flags() const { return flags_; }
private:
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
int const flags_;
};
@@ -735,32 +737,32 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* CreateTypedArray();
const Operator* CreateLiteralArray(
Handle<ArrayBoilerplateDescription> constant,
- VectorSlotPair const& feedback, int literal_flags,
+ FeedbackSource const& feedback, int literal_flags,
int number_of_elements);
- const Operator* CreateEmptyLiteralArray(VectorSlotPair const& feedback);
+ const Operator* CreateEmptyLiteralArray(FeedbackSource const& feedback);
const Operator* CreateArrayFromIterable();
const Operator* CreateEmptyLiteralObject();
const Operator* CreateLiteralObject(
Handle<ObjectBoilerplateDescription> constant,
- VectorSlotPair const& feedback, int literal_flags,
+ FeedbackSource const& feedback, int literal_flags,
int number_of_properties);
- const Operator* CloneObject(VectorSlotPair const& feedback,
+ const Operator* CloneObject(FeedbackSource const& feedback,
int literal_flags);
const Operator* CreateLiteralRegExp(Handle<String> constant_pattern,
- VectorSlotPair const& feedback,
+ FeedbackSource const& feedback,
int literal_flags);
const Operator* CallForwardVarargs(size_t arity, uint32_t start_index);
const Operator* Call(
size_t arity, CallFrequency const& frequency = CallFrequency(),
- VectorSlotPair const& feedback = VectorSlotPair(),
+ FeedbackSource const& feedback = FeedbackSource(),
ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny,
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation);
const Operator* CallWithArrayLike(CallFrequency const& frequency);
const Operator* CallWithSpread(
uint32_t arity, CallFrequency const& frequency = CallFrequency(),
- VectorSlotPair const& feedback = VectorSlotPair(),
+ FeedbackSource const& feedback = FeedbackSource(),
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation);
const Operator* CallRuntime(Runtime::FunctionId id);
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
@@ -769,39 +771,39 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* ConstructForwardVarargs(size_t arity, uint32_t start_index);
const Operator* Construct(uint32_t arity,
CallFrequency const& frequency = CallFrequency(),
- VectorSlotPair const& feedback = VectorSlotPair());
+ FeedbackSource const& feedback = FeedbackSource());
const Operator* ConstructWithArrayLike(CallFrequency const& frequency);
const Operator* ConstructWithSpread(
uint32_t arity, CallFrequency const& frequency = CallFrequency(),
- VectorSlotPair const& feedback = VectorSlotPair());
+ FeedbackSource const& feedback = FeedbackSource());
- const Operator* LoadProperty(VectorSlotPair const& feedback);
- const Operator* LoadNamed(Handle<Name> name, VectorSlotPair const& feedback);
+ const Operator* LoadProperty(FeedbackSource const& feedback);
+ const Operator* LoadNamed(Handle<Name> name, FeedbackSource const& feedback);
const Operator* StoreProperty(LanguageMode language_mode,
- VectorSlotPair const& feedback);
+ FeedbackSource const& feedback);
const Operator* StoreNamed(LanguageMode language_mode, Handle<Name> name,
- VectorSlotPair const& feedback);
+ FeedbackSource const& feedback);
const Operator* StoreNamedOwn(Handle<Name> name,
- VectorSlotPair const& feedback);
- const Operator* StoreDataPropertyInLiteral(const VectorSlotPair& feedback);
- const Operator* StoreInArrayLiteral(const VectorSlotPair& feedback);
+ FeedbackSource const& feedback);
+ const Operator* StoreDataPropertyInLiteral(const FeedbackSource& feedback);
+ const Operator* StoreInArrayLiteral(const FeedbackSource& feedback);
const Operator* DeleteProperty();
- const Operator* HasProperty(VectorSlotPair const& feedback);
+ const Operator* HasProperty(FeedbackSource const& feedback);
const Operator* GetSuperConstructor();
const Operator* CreateGeneratorObject();
const Operator* LoadGlobal(const Handle<Name>& name,
- const VectorSlotPair& feedback,
+ const FeedbackSource& feedback,
TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
const Operator* StoreGlobal(LanguageMode language_mode,
const Handle<Name>& name,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* LoadContext(size_t depth, size_t index, bool immutable);
const Operator* StoreContext(size_t depth, size_t index);
@@ -810,7 +812,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* StoreModule(int32_t cell_index);
const Operator* HasInPrototypeChain();
- const Operator* InstanceOf(const VectorSlotPair& feedback);
+ const Operator* InstanceOf(const FeedbackSource& feedback);
const Operator* OrdinaryHasInstance();
const Operator* AsyncFunctionEnter();
@@ -854,6 +856,8 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* ParseInt();
const Operator* RegExpTest();
+ const Operator* GetIterator(FeedbackSource const& feedback);
+
private:
Zone* zone() const { return zone_; }
diff --git a/deps/v8/src/compiler/js-type-hint-lowering.cc b/deps/v8/src/compiler/js-type-hint-lowering.cc
index f3696bcc48..e1ff928cec 100644
--- a/deps/v8/src/compiler/js-type-hint-lowering.cc
+++ b/deps/v8/src/compiler/js-type-hint-lowering.cc
@@ -6,6 +6,7 @@
#include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h"
+#include "src/compiler/js-heap-broker.h"
#include "src/compiler/operator-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/objects/feedback-vector.h"
@@ -78,16 +79,6 @@ class JSSpeculativeBinopBuilder final {
control_(control),
slot_(slot) {}
- BinaryOperationHint GetBinaryOperationHint() {
- FeedbackNexus nexus(feedback_vector(), slot_);
- return nexus.GetBinaryOperationFeedback();
- }
-
- CompareOperationHint GetCompareOperationHint() {
- FeedbackNexus nexus(feedback_vector(), slot_);
- return nexus.GetCompareOperationFeedback();
- }
-
bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
hint);
@@ -239,34 +230,52 @@ class JSSpeculativeBinopBuilder final {
JSOperatorBuilder* javascript() { return jsgraph()->javascript(); }
SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
CommonOperatorBuilder* common() { return jsgraph()->common(); }
- const Handle<FeedbackVector>& feedback_vector() const {
- return lowering_->feedback_vector();
- }
private:
- const JSTypeHintLowering* lowering_;
- const Operator* op_;
+ BinaryOperationHint GetBinaryOperationHint() {
+ return lowering_->GetBinaryOperationHint(slot_);
+ }
+
+ CompareOperationHint GetCompareOperationHint() {
+ return lowering_->GetCompareOperationHint(slot_);
+ }
+
+ JSTypeHintLowering const* const lowering_;
+ Operator const* const op_;
Node* left_;
Node* right_;
- Node* effect_;
- Node* control_;
- FeedbackSlot slot_;
+ Node* const effect_;
+ Node* const control_;
+ FeedbackSlot const slot_;
};
-JSTypeHintLowering::JSTypeHintLowering(JSGraph* jsgraph,
- Handle<FeedbackVector> feedback_vector,
+JSTypeHintLowering::JSTypeHintLowering(JSHeapBroker* broker, JSGraph* jsgraph,
+ FeedbackVectorRef feedback_vector,
Flags flags)
- : jsgraph_(jsgraph), flags_(flags), feedback_vector_(feedback_vector) {}
+ : broker_(broker),
+ jsgraph_(jsgraph),
+ flags_(flags),
+ feedback_vector_(feedback_vector) {}
Isolate* JSTypeHintLowering::isolate() const { return jsgraph()->isolate(); }
+BinaryOperationHint JSTypeHintLowering::GetBinaryOperationHint(
+ FeedbackSlot slot) const {
+ FeedbackSource source(feedback_vector(), slot);
+ return broker()->GetFeedbackForBinaryOperation(source);
+}
+
+CompareOperationHint JSTypeHintLowering::GetCompareOperationHint(
+ FeedbackSlot slot) const {
+ FeedbackSource source(feedback_vector(), slot);
+ return broker()->GetFeedbackForCompareOperation(source);
+}
+
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
const Operator* op, Node* operand, Node* effect, Node* control,
FeedbackSlot slot) const {
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) {
return LoweringResult::Exit(node);
}
@@ -309,9 +318,7 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
control, slot);
node = b.TryBuildNumberBinop();
if (!node) {
- FeedbackNexus nexus(feedback_vector(), slot);
- if (nexus.GetBinaryOperationFeedback() ==
- BinaryOperationHint::kBigInt) {
+ if (GetBinaryOperationHint(slot) == BinaryOperationHint::kBigInt) {
const Operator* op = jsgraph()->simplified()->SpeculativeBigIntNegate(
BigIntOperationHint::kBigInt);
node = jsgraph()->graph()->NewNode(op, operand, effect, control);
@@ -335,10 +342,8 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
FeedbackSlot slot) const {
switch (op->opcode()) {
case IrOpcode::kJSStrictEqual: {
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
return LoweringResult::Exit(node);
}
@@ -351,10 +356,8 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
case IrOpcode::kJSGreaterThan:
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSGreaterThanOrEqual: {
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
return LoweringResult::Exit(node);
}
@@ -365,10 +368,8 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
break;
}
case IrOpcode::kJSInstanceOf: {
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
return LoweringResult::Exit(node);
}
@@ -387,10 +388,8 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
case IrOpcode::kJSMultiply:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus: {
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForBinaryOperation)) {
return LoweringResult::Exit(node);
}
@@ -406,6 +405,11 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
break;
}
case IrOpcode::kJSExponentiate: {
+ if (Node* node = TryBuildSoftDeopt(
+ slot, effect, control,
+ DeoptimizeReason::kInsufficientTypeFeedbackForBinaryOperation)) {
+ return LoweringResult::Exit(node);
+ }
// TODO(neis): Introduce a SpeculativeNumberPow operator?
break;
}
@@ -418,10 +422,8 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceForInNextOperation(
Node* receiver, Node* cache_array, Node* cache_type, Node* index,
Node* effect, Node* control, FeedbackSlot slot) const {
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
return LoweringResult::Exit(node);
}
@@ -432,10 +434,8 @@ JSTypeHintLowering::LoweringResult
JSTypeHintLowering::ReduceForInPrepareOperation(Node* enumerator, Node* effect,
Node* control,
FeedbackSlot slot) const {
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
return LoweringResult::Exit(node);
}
@@ -445,12 +445,11 @@ JSTypeHintLowering::ReduceForInPrepareOperation(Node* enumerator, Node* effect,
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceToNumberOperation(
Node* input, Node* effect, Node* control, FeedbackSlot slot) const {
DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
NumberOperationHint hint;
- if (BinaryOperationHintToNumberOperationHint(
- nexus.GetBinaryOperationFeedback(), &hint)) {
+ if (BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(slot),
+ &hint)) {
Node* node = jsgraph()->graph()->NewNode(
- jsgraph()->simplified()->SpeculativeToNumber(hint, VectorSlotPair()),
+ jsgraph()->simplified()->SpeculativeToNumber(hint, FeedbackSource()),
input, effect, control);
return LoweringResult::SideEffectFree(node, node, control);
}
@@ -462,10 +461,8 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceCallOperation(
Node* control, FeedbackSlot slot) const {
DCHECK(op->opcode() == IrOpcode::kJSCall ||
op->opcode() == IrOpcode::kJSCallWithSpread);
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
return LoweringResult::Exit(node);
}
@@ -477,10 +474,8 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceConstructOperation(
Node* control, FeedbackSlot slot) const {
DCHECK(op->opcode() == IrOpcode::kJSConstruct ||
op->opcode() == IrOpcode::kJSConstructWithSpread);
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForConstruct)) {
return LoweringResult::Exit(node);
}
@@ -490,11 +485,11 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceConstructOperation(
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadNamedOperation(
const Operator* op, Node* receiver, Node* effect, Node* control,
FeedbackSlot slot) const {
- DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
+ // JSGetIterator involves a named load of the Symbol.iterator property.
+ DCHECK(op->opcode() == IrOpcode::kJSLoadNamed ||
+ op->opcode() == IrOpcode::kJSGetIterator);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
return LoweringResult::Exit(node);
}
@@ -505,10 +500,8 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadKeyedOperation(
const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
FeedbackSlot slot) const {
DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
return LoweringResult::Exit(node);
}
@@ -522,10 +515,8 @@ JSTypeHintLowering::ReduceStoreNamedOperation(const Operator* op, Node* obj,
FeedbackSlot slot) const {
DCHECK(op->opcode() == IrOpcode::kJSStoreNamed ||
op->opcode() == IrOpcode::kJSStoreNamedOwn);
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
return LoweringResult::Exit(node);
}
@@ -538,31 +529,32 @@ JSTypeHintLowering::ReduceStoreKeyedOperation(const Operator* op, Node* obj,
Node* effect, Node* control,
FeedbackSlot slot) const {
DCHECK(op->opcode() == IrOpcode::kJSStoreProperty ||
- op->opcode() == IrOpcode::kJSStoreInArrayLiteral);
- DCHECK(!slot.IsInvalid());
- FeedbackNexus nexus(feedback_vector(), slot);
+ op->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
+ op->opcode() == IrOpcode::kJSStoreDataPropertyInLiteral);
if (Node* node = TryBuildSoftDeopt(
- nexus, effect, control,
+ slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
return LoweringResult::Exit(node);
}
return LoweringResult::NoChange();
}
-Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect,
+Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackSlot slot, Node* effect,
Node* control,
DeoptimizeReason reason) const {
- if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
- Node* deoptimize = jsgraph()->graph()->NewNode(
- jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason,
- VectorSlotPair()),
- jsgraph()->Dead(), effect, control);
- Node* frame_state =
- NodeProperties::FindFrameStateBefore(deoptimize, jsgraph()->Dead());
- deoptimize->ReplaceInput(0, frame_state);
- return deoptimize;
- }
- return nullptr;
+ if (!(flags() & kBailoutOnUninitialized)) return nullptr;
+
+ FeedbackSource source(feedback_vector(), slot);
+ if (!broker()->FeedbackIsInsufficient(source)) return nullptr;
+
+ Node* deoptimize = jsgraph()->graph()->NewNode(
+ jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason,
+ FeedbackSource()),
+ jsgraph()->Dead(), effect, control);
+ Node* frame_state =
+ NodeProperties::FindFrameStateBefore(deoptimize, jsgraph()->Dead());
+ deoptimize->ReplaceInput(0, frame_state);
+ return deoptimize;
}
} // namespace compiler
diff --git a/deps/v8/src/compiler/js-type-hint-lowering.h b/deps/v8/src/compiler/js-type-hint-lowering.h
index a74c019355..3e46fb2ec2 100644
--- a/deps/v8/src/compiler/js-type-hint-lowering.h
+++ b/deps/v8/src/compiler/js-type-hint-lowering.h
@@ -41,8 +41,8 @@ class JSTypeHintLowering {
enum Flag { kNoFlags = 0u, kBailoutOnUninitialized = 1u << 1 };
using Flags = base::Flags<Flag>;
- JSTypeHintLowering(JSGraph* jsgraph, Handle<FeedbackVector> feedback_vector,
- Flags flags);
+ JSTypeHintLowering(JSHeapBroker* broker, JSGraph* jsgraph,
+ FeedbackVectorRef feedback_vector, Flags flags);
// {LoweringResult} describes the result of lowering. The following outcomes
// are possible:
@@ -153,20 +153,22 @@ class JSTypeHintLowering {
private:
friend class JSSpeculativeBinopBuilder;
- Node* TryBuildSoftDeopt(FeedbackNexus& nexus, // NOLINT(runtime/references)
- Node* effect, Node* control,
+
+ BinaryOperationHint GetBinaryOperationHint(FeedbackSlot slot) const;
+ CompareOperationHint GetCompareOperationHint(FeedbackSlot slot) const;
+ Node* TryBuildSoftDeopt(FeedbackSlot slot, Node* effect, Node* control,
DeoptimizeReason reson) const;
+ JSHeapBroker* broker() const { return broker_; }
JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const;
Flags flags() const { return flags_; }
- const Handle<FeedbackVector>& feedback_vector() const {
- return feedback_vector_;
- }
+ FeedbackVectorRef const& feedback_vector() const { return feedback_vector_; }
- JSGraph* jsgraph_;
+ JSHeapBroker* const broker_;
+ JSGraph* const jsgraph_;
Flags const flags_;
- Handle<FeedbackVector> feedback_vector_;
+ FeedbackVectorRef const feedback_vector_;
DISALLOW_COPY_AND_ASSIGN(JSTypeHintLowering);
};
diff --git a/deps/v8/src/compiler/js-typed-lowering.cc b/deps/v8/src/compiler/js-typed-lowering.cc
index 3190fc9930..8caafe6aad 100644
--- a/deps/v8/src/compiler/js-typed-lowering.cc
+++ b/deps/v8/src/compiler/js-typed-lowering.cc
@@ -200,14 +200,14 @@ class JSBinopReduction final {
void CheckInputsToString() {
if (!left_type().Is(Type::String())) {
Node* left_input =
- graph()->NewNode(simplified()->CheckString(VectorSlotPair()), left(),
+ graph()->NewNode(simplified()->CheckString(FeedbackSource()), left(),
effect(), control());
node_->ReplaceInput(0, left_input);
update_effect(left_input);
}
if (!right_type().Is(Type::String())) {
Node* right_input =
- graph()->NewNode(simplified()->CheckString(VectorSlotPair()), right(),
+ graph()->NewNode(simplified()->CheckString(FeedbackSource()), right(),
effect(), control());
node_->ReplaceInput(1, right_input);
update_effect(right_input);
@@ -576,7 +576,7 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
// and thus potentially reduces the number of live ranges and allows for
// more truncations.
length = effect = graph()->NewNode(
- simplified()->CheckBounds(VectorSlotPair()), length,
+ simplified()->CheckBounds(FeedbackSource()), length,
jsgraph()->Constant(String::kMaxLength + 1), effect, control);
} else {
// Check if we would overflow the allowed maximum string length.
@@ -1320,7 +1320,7 @@ Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
for (size_t i = 0; i < access.depth(); ++i) {
context = effect = graph()->NewNode(
simplified()->LoadField(
- AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
+ AccessBuilder::ForContextSlotKnownPointer(Context::PREVIOUS_INDEX)),
context, effect, control);
}
node->ReplaceInput(0, context);
@@ -1342,7 +1342,7 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
for (size_t i = 0; i < access.depth(); ++i) {
context = effect = graph()->NewNode(
simplified()->LoadField(
- AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
+ AccessBuilder::ForContextSlotKnownPointer(Context::PREVIOUS_INDEX)),
context, effect, control);
}
node->ReplaceInput(0, context);
@@ -1367,8 +1367,8 @@ Node* JSTypedLowering::BuildGetModuleCell(Node* node) {
if (module_type.IsHeapConstant()) {
SourceTextModuleRef module_constant =
module_type.AsHeapConstant()->Ref().AsSourceTextModule();
- CellRef cell_constant = module_constant.GetCell(cell_index);
- return jsgraph()->Constant(cell_constant);
+ base::Optional<CellRef> cell_constant = module_constant.GetCell(cell_index);
+ if (cell_constant.has_value()) return jsgraph()->Constant(*cell_constant);
}
FieldAccess field_access;
@@ -1554,21 +1554,21 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
if (target_type.IsHeapConstant() &&
target_type.AsHeapConstant()->Ref().IsJSFunction()) {
JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
- SharedFunctionInfoRef shared = function.shared();
// Only optimize [[Construct]] here if {function} is a Constructor.
if (!function.map().is_constructor()) return NoChange();
- CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
+ if (!function.serialized()) {
+ TRACE_BROKER_MISSING(broker(), "data for function " << function);
+ return NoChange();
+ }
// Patch {node} to an indirect call via the {function}s construct stub.
- bool use_builtin_construct_stub = shared.construct_as_builtin();
-
+ bool use_builtin_construct_stub = function.shared().construct_as_builtin();
CodeRef code(broker(),
use_builtin_construct_stub
? BUILTIN_CODE(isolate(), JSBuiltinsConstructStub)
: BUILTIN_CODE(isolate(), JSConstructStubGeneric));
-
node->RemoveInput(arity + 1);
node->InsertInput(graph()->zone(), 0, jsgraph()->Constant(code));
node->InsertInput(graph()->zone(), 2, new_target);
@@ -1576,10 +1576,9 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
NodeProperties::ChangeOp(
- node,
- common()->Call(Linkage::GetStubCallDescriptor(
- graph()->zone(), ConstructStubDescriptor{}, 1 + arity, flags)));
-
+ node, common()->Call(Linkage::GetStubCallDescriptor(
+ graph()->zone(), ConstructStubDescriptor{}, 1 + arity,
+ CallDescriptor::kNeedsFrameState)));
return Changed(node);
}
@@ -1637,12 +1636,15 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
if (target_type.IsHeapConstant() &&
target_type.AsHeapConstant()->Ref().IsJSFunction()) {
JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
- SharedFunctionInfoRef shared = function.shared();
- if (shared.HasBreakInfo()) {
- // Do not inline the call if we need to check whether to break at entry.
+ if (!function.serialized()) {
+ TRACE_BROKER_MISSING(broker(), "data for function " << function);
return NoChange();
}
+ SharedFunctionInfoRef shared = function.shared();
+
+ // Do not inline the call if we need to check whether to break at entry.
+ if (shared.HasBreakInfo()) return NoChange();
// Class constructors are callable, but [[Call]] will raise an exception.
// See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
@@ -1652,7 +1654,8 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
// require data from a foreign native context.
if (is_sloppy(shared.language_mode()) && !shared.native() &&
!receiver_type.Is(Type::Receiver())) {
- if (!function.native_context().equals(broker()->native_context())) {
+ if (!function.native_context().equals(
+ broker()->target_native_context())) {
return NoChange();
}
Node* global_proxy =
diff --git a/deps/v8/src/compiler/linkage.cc b/deps/v8/src/compiler/linkage.cc
index 1d88a27a5f..39c93c0328 100644
--- a/deps/v8/src/compiler/linkage.cc
+++ b/deps/v8/src/compiler/linkage.cc
@@ -7,9 +7,7 @@
#include "src/codegen/assembler-inl.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/optimized-compilation-info.h"
-#include "src/compiler/common-operator.h"
#include "src/compiler/frame.h"
-#include "src/compiler/node.h"
#include "src/compiler/osr.h"
#include "src/compiler/pipeline.h"
@@ -75,15 +73,6 @@ MachineSignature* CallDescriptor::GetMachineSignature(Zone* zone) const {
return new (zone) MachineSignature(return_count, param_count, types);
}
-bool CallDescriptor::HasSameReturnLocationsAs(
- const CallDescriptor* other) const {
- if (ReturnCount() != other->ReturnCount()) return false;
- for (size_t i = 0; i < ReturnCount(); ++i) {
- if (GetReturnLocation(i) != other->GetReturnLocation(i)) return false;
- }
- return true;
-}
-
int CallDescriptor::GetFirstUnusedStackSlot() const {
int slots_above_sp = 0;
for (size_t i = 0; i < InputCount(); ++i) {
@@ -104,19 +93,16 @@ int CallDescriptor::GetStackParameterDelta(
int callee_slots_above_sp = GetFirstUnusedStackSlot();
int tail_caller_slots_above_sp = tail_caller->GetFirstUnusedStackSlot();
int stack_param_delta = callee_slots_above_sp - tail_caller_slots_above_sp;
- if (kPadArguments) {
- // Adjust stack delta when it is odd.
- if (stack_param_delta % 2 != 0) {
- if (callee_slots_above_sp % 2 != 0) {
- // The delta is odd due to the callee - we will need to add one slot
- // of padding.
- ++stack_param_delta;
- } else {
- // The delta is odd because of the caller. We already have one slot of
- // padding that we can reuse for arguments, so we will need one fewer
- // slot.
- --stack_param_delta;
- }
+ if (ShouldPadArguments(stack_param_delta)) {
+ if (callee_slots_above_sp % 2 != 0) {
+ // The delta is odd due to the callee - we will need to add one slot
+ // of padding.
+ ++stack_param_delta;
+ } else {
+ // The delta is odd because of the caller. We already have one slot of
+ // padding that we can reuse for arguments, so we will need one fewer
+ // slot.
+ --stack_param_delta;
}
}
return stack_param_delta;
@@ -133,8 +119,14 @@ int CallDescriptor::GetTaggedParameterSlots() const {
return result;
}
-bool CallDescriptor::CanTailCall(const Node* node) const {
- return HasSameReturnLocationsAs(CallDescriptorOf(node->op()));
+bool CallDescriptor::CanTailCall(const CallDescriptor* callee) const {
+ if (ReturnCount() != callee->ReturnCount()) return false;
+ for (size_t i = 0; i < ReturnCount(); ++i) {
+ if (!LinkageLocation::IsSameLocation(GetReturnLocation(i),
+ callee->GetReturnLocation(i)))
+ return false;
+ }
+ return true;
}
// TODO(jkummerow, sigurds): Arguably frame size calculation should be
diff --git a/deps/v8/src/compiler/linkage.h b/deps/v8/src/compiler/linkage.h
index 05eb0e7d11..69e7fbfa42 100644
--- a/deps/v8/src/compiler/linkage.h
+++ b/deps/v8/src/compiler/linkage.h
@@ -28,20 +28,33 @@ namespace compiler {
const RegList kNoCalleeSaved = 0;
-class Node;
class OsrHelper;
// Describes the location for a parameter or a return value to a call.
class LinkageLocation {
public:
bool operator==(const LinkageLocation& other) const {
- return bit_field_ == other.bit_field_;
+ return bit_field_ == other.bit_field_ &&
+ machine_type_ == other.machine_type_;
}
bool operator!=(const LinkageLocation& other) const {
return !(*this == other);
}
+ static bool IsSameLocation(const LinkageLocation& a,
+ const LinkageLocation& b) {
+ // Different MachineTypes may end up at the same physical location. With the
+ // sub-type check we make sure that types like {AnyTagged} and
+ // {TaggedPointer} which would end up with the same physical location are
+ // considered equal here.
+ return (a.bit_field_ == b.bit_field_) &&
+ (IsSubtype(a.machine_type_.representation(),
+ b.machine_type_.representation()) ||
+ IsSubtype(b.machine_type_.representation(),
+ a.machine_type_.representation()));
+ }
+
static LinkageLocation ForAnyRegister(
MachineType type = MachineType::None()) {
return LinkageLocation(REGISTER, ANY_REGISTER, type);
@@ -144,8 +157,8 @@ class LinkageLocation {
private:
enum LocationType { REGISTER, STACK_SLOT };
- class TypeField : public BitField<LocationType, 0, 1> {};
- class LocationField : public BitField<int32_t, TypeField::kNext, 31> {};
+ using TypeField = BitField<LocationType, 0, 1>;
+ using LocationField = TypeField::Next<int32_t, 31>;
static constexpr int32_t ANY_REGISTER = -1;
static constexpr int32_t MAX_STACK_SLOT = 32767;
@@ -197,7 +210,8 @@ class V8_EXPORT_PRIVATE CallDescriptor final
// Use the kJavaScriptCallCodeStartRegister (fixed) register for the
// indirect target address when calling.
kFixedTargetRegister = 1u << 7,
- kAllowCallThroughSlot = 1u << 8
+ kAllowCallThroughSlot = 1u << 8,
+ kCallerSavedRegisters = 1u << 9
};
using Flags = base::Flags<Flag>;
@@ -276,6 +290,9 @@ class V8_EXPORT_PRIVATE CallDescriptor final
bool InitializeRootRegister() const {
return flags() & kInitializeRootRegister;
}
+ bool NeedsCallerSavedRegisters() const {
+ return flags() & kCallerSavedRegisters;
+ }
LinkageLocation GetReturnLocation(size_t index) const {
return location_sig_->GetReturn(index);
@@ -314,8 +331,6 @@ class V8_EXPORT_PRIVATE CallDescriptor final
bool UsesOnlyRegisters() const;
- bool HasSameReturnLocationsAs(const CallDescriptor* other) const;
-
// Returns the first stack slot that is not used by the stack parameters.
int GetFirstUnusedStackSlot() const;
@@ -323,7 +338,7 @@ class V8_EXPORT_PRIVATE CallDescriptor final
int GetTaggedParameterSlots() const;
- bool CanTailCall(const Node* call) const;
+ bool CanTailCall(const CallDescriptor* callee) const;
int CalculateFixedFrameSize(Code::Kind code_kind) const;
@@ -418,7 +433,7 @@ class V8_EXPORT_PRIVATE Linkage : public NON_EXPORTED_BASE(ZoneObject) {
// structs, pointers to members, etc.
static CallDescriptor* GetSimplifiedCDescriptor(
Zone* zone, const MachineSignature* sig,
- bool set_initialize_root_flag = false);
+ CallDescriptor::Flags flags = CallDescriptor::kNoFlags);
// Get the location of an (incoming) parameter to this function.
LinkageLocation GetParameterLocation(int index) const {
diff --git a/deps/v8/src/compiler/load-elimination.cc b/deps/v8/src/compiler/load-elimination.cc
index f9998723f3..3778775e9b 100644
--- a/deps/v8/src/compiler/load-elimination.cc
+++ b/deps/v8/src/compiler/load-elimination.cc
@@ -8,7 +8,6 @@
#include "src/compiler/common-operator.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node-properties.h"
-#include "src/compiler/simplified-operator.h"
#include "src/heap/factory.h"
#include "src/objects/objects-inl.h"
@@ -284,6 +283,28 @@ class LoadElimination::AliasStateInfo {
MaybeHandle<Map> map_;
};
+LoadElimination::AbstractField const* LoadElimination::AbstractField::KillConst(
+ Node* object, Zone* zone) const {
+ for (auto pair : this->info_for_node_) {
+ if (pair.first->IsDead()) continue;
+ // If we previously recorded information about a const store on the given
+ // 'object', we might not have done it on the same node; e.g. we might now
+ // identify the object by a FinishRegion node, whereas the initial const
+ // store was performed on the Allocate node. We therefore remove information
+ // on all nodes that must alias with 'object'.
+ if (MustAlias(object, pair.first)) {
+ AbstractField* that = new (zone) AbstractField(zone);
+ for (auto pair : this->info_for_node_) {
+ if (!MustAlias(object, pair.first)) {
+ that->info_for_node_.insert(pair);
+ }
+ }
+ return that;
+ }
+ }
+ return this;
+}
+
LoadElimination::AbstractField const* LoadElimination::AbstractField::Kill(
const AliasStateInfo& alias_info, MaybeHandle<Name> name,
Zone* zone) const {
@@ -527,38 +548,60 @@ LoadElimination::AbstractState::KillElement(Node* object, Node* index,
}
LoadElimination::AbstractState const* LoadElimination::AbstractState::AddField(
- Node* object, size_t index, LoadElimination::FieldInfo info,
- PropertyConstness constness, Zone* zone) const {
+ Node* object, IndexRange index_range, LoadElimination::FieldInfo info,
+ Zone* zone) const {
AbstractState* that = new (zone) AbstractState(*this);
- AbstractFields& fields = constness == PropertyConstness::kConst
- ? that->const_fields_
- : that->fields_;
- if (fields[index]) {
- fields[index] = fields[index]->Extend(object, info, zone);
- } else {
- fields[index] = new (zone) AbstractField(object, info, zone);
+ AbstractFields& fields =
+ info.const_field_info.IsConst() ? that->const_fields_ : that->fields_;
+ for (int index : index_range) {
+ if (fields[index]) {
+ fields[index] = fields[index]->Extend(object, info, zone);
+ } else {
+ fields[index] = new (zone) AbstractField(object, info, zone);
+ }
}
return that;
}
-LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
- Node* object, size_t index, MaybeHandle<Name> name, Zone* zone) const {
+LoadElimination::AbstractState const*
+LoadElimination::AbstractState::KillConstField(Node* object,
+ IndexRange index_range,
+ Zone* zone) const {
AliasStateInfo alias_info(this, object);
- return KillField(alias_info, index, name, zone);
+ AbstractState* that = nullptr;
+ for (int index : index_range) {
+ if (AbstractField const* this_field = this->const_fields_[index]) {
+ this_field = this_field->KillConst(object, zone);
+ if (this->const_fields_[index] != this_field) {
+ if (!that) that = new (zone) AbstractState(*this);
+ that->const_fields_[index] = this_field;
+ }
+ }
+ }
+ return that ? that : this;
}
LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
- const AliasStateInfo& alias_info, size_t index, MaybeHandle<Name> name,
+ Node* object, IndexRange index_range, MaybeHandle<Name> name,
Zone* zone) const {
- if (AbstractField const* this_field = this->fields_[index]) {
- this_field = this_field->Kill(alias_info, name, zone);
- if (this->fields_[index] != this_field) {
- AbstractState* that = new (zone) AbstractState(*this);
- that->fields_[index] = this_field;
- return that;
+ AliasStateInfo alias_info(this, object);
+ return KillField(alias_info, index_range, name, zone);
+}
+
+LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
+ const AliasStateInfo& alias_info, IndexRange index_range,
+ MaybeHandle<Name> name, Zone* zone) const {
+ AbstractState* that = nullptr;
+ for (int index : index_range) {
+ if (AbstractField const* this_field = this->fields_[index]) {
+ this_field = this_field->Kill(alias_info, name, zone);
+ if (this->fields_[index] != this_field) {
+ if (!that) that = new (zone) AbstractState(*this);
+ that->fields_[index] = this_field;
+ }
}
}
- return this;
+ return that ? that : this;
}
LoadElimination::AbstractState const*
@@ -598,13 +641,38 @@ LoadElimination::AbstractState const* LoadElimination::AbstractState::KillAll(
}
LoadElimination::FieldInfo const* LoadElimination::AbstractState::LookupField(
- Node* object, size_t index, PropertyConstness constness) const {
- AbstractFields const& fields =
- constness == PropertyConstness::kConst ? const_fields_ : fields_;
- if (AbstractField const* this_field = fields[index]) {
- return this_field->Lookup(object);
+ Node* object, IndexRange index_range,
+ ConstFieldInfo const_field_info) const {
+ // Check if all the indices in {index_range} contain identical information.
+ // If not, a partially overlapping access has invalidated part of the value.
+ base::Optional<LoadElimination::FieldInfo const*> result;
+ for (int index : index_range) {
+ LoadElimination::FieldInfo const* info = nullptr;
+ if (const_field_info.IsConst()) {
+ if (AbstractField const* this_field = const_fields_[index]) {
+ info = this_field->Lookup(object);
+ }
+ if (!(info && info->const_field_info == const_field_info)) return nullptr;
+ } else {
+ if (AbstractField const* this_field = fields_[index]) {
+ info = this_field->Lookup(object);
+ }
+ if (!info) return nullptr;
+ }
+ if (!result.has_value()) {
+ result = info;
+ } else {
+ // We detected a partially overlapping access here.
+ // We currently don't seem to have such accesses, so this code path is
+ // unreachable, but if we eventually have them, it is safe to return
+ // nullptr and continue the analysis. But store-store elimination is
+ // currently unsafe for such overlapping accesses, so when we remove
+ // this check, we should double-check that store-store elimination can
+ // handle it too.
+ DCHECK_EQ(**result, *info);
+ }
}
- return nullptr;
+ return *result;
}
bool LoadElimination::AliasStateInfo::MayAlias(Node* other) const {
@@ -733,12 +801,13 @@ Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) {
// We know that the resulting elements have the fixed array map.
state = state->SetMaps(node, fixed_array_maps, zone());
// Kill the previous elements on {object}.
- state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
+ state = state->KillField(object,
+ FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
MaybeHandle<Name>(), zone());
// Add the new elements on {object}.
- state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset),
- {node, MachineType::RepCompressedTaggedPointer()},
- PropertyConstness::kMutable, zone());
+ state = state->AddField(
+ object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
+ {node, MachineType::RepCompressedTaggedPointer()}, zone());
return UpdateState(node, state);
}
@@ -760,12 +829,13 @@ Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) {
state = state->SetMaps(node, fixed_array_maps, zone());
}
// Kill the previous elements on {object}.
- state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
+ state = state->KillField(object,
+ FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
MaybeHandle<Name>(), zone());
// Add the new elements on {object}.
- state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset),
- {node, MachineType::RepCompressedTaggedPointer()},
- PropertyConstness::kMutable, zone());
+ state = state->AddField(
+ object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
+ {node, MachineType::RepCompressedTaggedPointer()}, zone());
return UpdateState(node, state);
}
@@ -783,9 +853,9 @@ Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) {
case ElementsTransition::kSlowTransition:
// Kill the elements as well.
AliasStateInfo alias_info(state, object, source_map);
- state =
- state->KillField(alias_info, FieldIndexOf(JSObject::kElementsOffset),
- MaybeHandle<Name>(), zone());
+ state = state->KillField(
+ alias_info, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
+ MaybeHandle<Name>(), zone());
break;
}
ZoneHandleSet<Map> object_maps;
@@ -828,7 +898,8 @@ Reduction LoadElimination::ReduceTransitionAndStoreElement(Node* node) {
state = state->SetMaps(object, object_maps, zone());
}
// Kill the elements as well.
- state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset),
+ state = state->KillField(object,
+ FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
MaybeHandle<Name>(), zone());
return UpdateState(node, state);
}
@@ -851,16 +922,17 @@ Reduction LoadElimination::ReduceLoadField(Node* node,
return Replace(value);
}
} else {
- int field_index = FieldIndexOf(access);
- if (field_index >= 0) {
- PropertyConstness constness = access.constness;
+ IndexRange field_index = FieldIndexOf(access);
+ if (field_index != IndexRange::Invalid()) {
MachineRepresentation representation =
access.machine_type.representation();
FieldInfo const* lookup_result =
- state->LookupField(object, field_index, constness);
- if (!lookup_result && constness == PropertyConstness::kConst) {
- lookup_result = state->LookupField(object, field_index,
- PropertyConstness::kMutable);
+ state->LookupField(object, field_index, access.const_field_info);
+ if (!lookup_result && access.const_field_info.IsConst()) {
+ // If the access is const and we didn't find anything, also try to look
+ // up information from mutable stores
+ lookup_result =
+ state->LookupField(object, field_index, ConstFieldInfo::None());
}
if (lookup_result) {
// Make sure we don't reuse values that were recorded with a different
@@ -884,8 +956,9 @@ Reduction LoadElimination::ReduceLoadField(Node* node,
return Replace(replacement);
}
}
- FieldInfo info(node, access.name, representation);
- state = state->AddField(object, field_index, info, constness, zone());
+ FieldInfo info(node, representation, access.name,
+ access.const_field_info);
+ state = state->AddField(object, field_index, info, zone());
}
}
Handle<Map> field_map;
@@ -910,26 +983,26 @@ Reduction LoadElimination::ReduceStoreField(Node* node,
Type const new_value_type = NodeProperties::GetType(new_value);
if (new_value_type.IsHeapConstant()) {
// Record the new {object} map information.
- AllowHandleDereference handle_dereference;
ZoneHandleSet<Map> object_maps(
- Handle<Map>::cast(new_value_type.AsHeapConstant()->Value()));
+ new_value_type.AsHeapConstant()->Ref().AsMap().object());
state = state->SetMaps(object, object_maps, zone());
}
} else {
- int field_index = FieldIndexOf(access);
- if (field_index >= 0) {
- PropertyConstness constness = access.constness;
+ IndexRange field_index = FieldIndexOf(access);
+ if (field_index != IndexRange::Invalid()) {
+ bool is_const_store = access.const_field_info.IsConst();
MachineRepresentation representation =
access.machine_type.representation();
FieldInfo const* lookup_result =
- state->LookupField(object, field_index, constness);
+ state->LookupField(object, field_index, access.const_field_info);
- if (lookup_result && (constness == PropertyConstness::kMutable ||
- V8_ENABLE_DOUBLE_CONST_STORE_CHECK_BOOL)) {
+ if (lookup_result &&
+ (!is_const_store || V8_ENABLE_DOUBLE_CONST_STORE_CHECK_BOOL)) {
// At runtime, we should never encounter
// - any store replacing existing info with a different, incompatible
// representation, nor
- // - two consecutive const stores.
+ // - two consecutive const stores, unless the latter is a store into
+ // a literal.
// However, we may see such code statically, so we guard against
// executing it by emitting Unreachable.
// TODO(gsps): Re-enable the double const store check even for
@@ -939,8 +1012,9 @@ Reduction LoadElimination::ReduceStoreField(Node* node,
bool incompatible_representation =
!lookup_result->name.is_null() &&
!IsCompatible(representation, lookup_result->representation);
- if (incompatible_representation ||
- constness == PropertyConstness::kConst) {
+ bool illegal_double_const_store =
+ is_const_store && !access.is_store_in_literal;
+ if (incompatible_representation || illegal_double_const_store) {
Node* control = NodeProperties::GetControlInput(node);
Node* unreachable =
graph()->NewNode(common()->Unreachable(), effect, control);
@@ -953,16 +1027,22 @@ Reduction LoadElimination::ReduceStoreField(Node* node,
}
// Kill all potentially aliasing fields and record the new value.
- FieldInfo new_info(new_value, access.name, representation);
+ FieldInfo new_info(new_value, representation, access.name,
+ access.const_field_info);
+ if (is_const_store && access.is_store_in_literal) {
+ // We only kill const information when there is a chance that we
+ // previously stored information about the given const field (namely,
+ // when we observe const stores to literals).
+ state = state->KillConstField(object, field_index, zone());
+ }
state = state->KillField(object, field_index, access.name, zone());
- state = state->AddField(object, field_index, new_info,
- PropertyConstness::kMutable, zone());
- if (constness == PropertyConstness::kConst) {
+ state = state->AddField(object, field_index, new_info, zone());
+ if (is_const_store) {
// For const stores, we track information in both the const and the
// mutable world to guard against field accesses that should have
// been marked const, but were not.
- state =
- state->AddField(object, field_index, new_info, constness, zone());
+ new_info.const_field_info = ConstFieldInfo::None();
+ state = state->AddField(object, field_index, new_info, zone());
}
} else {
// Unsupported StoreField operator.
@@ -1180,8 +1260,8 @@ LoadElimination::ComputeLoopStateForStoreField(
// Invalidate what we know about the {object}s map.
state = state->KillMaps(object, zone());
} else {
- int field_index = FieldIndexOf(access);
- if (field_index < 0) {
+ IndexRange field_index = FieldIndexOf(access);
+ if (field_index == IndexRange::Invalid()) {
state = state->KillFields(object, access.name, zone());
} else {
state = state->KillField(object, field_index, access.name, zone());
@@ -1197,9 +1277,12 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
ElementsTransition transition;
Node* object;
};
- ZoneVector<TransitionElementsKindInfo> element_transitions_(zone());
- ZoneQueue<Node*> queue(zone());
- ZoneSet<Node*> visited(zone());
+ // Allocate zone data structures in a temporary zone with a lifetime limited
+ // to this function to avoid blowing up the size of the stage-global zone.
+ Zone temp_zone(zone()->allocator(), "Temporary scoped zone");
+ ZoneVector<TransitionElementsKindInfo> element_transitions_(&temp_zone);
+ ZoneQueue<Node*> queue(&temp_zone);
+ ZoneSet<Node*> visited(&temp_zone);
visited.insert(node);
for (int i = 1; i < control->InputCount(); ++i) {
queue.push(node->InputAt(i));
@@ -1213,16 +1296,16 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
switch (current->opcode()) {
case IrOpcode::kEnsureWritableFastElements: {
Node* const object = NodeProperties::GetValueInput(current, 0);
- state = state->KillField(object,
- FieldIndexOf(JSObject::kElementsOffset),
- MaybeHandle<Name>(), zone());
+ state = state->KillField(
+ object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
+ MaybeHandle<Name>(), zone());
break;
}
case IrOpcode::kMaybeGrowFastElements: {
Node* const object = NodeProperties::GetValueInput(current, 0);
- state = state->KillField(object,
- FieldIndexOf(JSObject::kElementsOffset),
- MaybeHandle<Name>(), zone());
+ state = state->KillField(
+ object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
+ MaybeHandle<Name>(), zone());
break;
}
case IrOpcode::kTransitionElementsKind: {
@@ -1241,9 +1324,9 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
// Invalidate what we know about the {object}s map.
state = state->KillMaps(object, zone());
// Kill the elements as well.
- state = state->KillField(object,
- FieldIndexOf(JSObject::kElementsOffset),
- MaybeHandle<Name>(), zone());
+ state = state->KillField(
+ object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
+ MaybeHandle<Name>(), zone());
break;
}
case IrOpcode::kStoreField: {
@@ -1305,9 +1388,9 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
break;
case ElementsTransition::kSlowTransition: {
AliasStateInfo alias_info(state, t.object, t.transition.source());
- state = state->KillField(alias_info,
- FieldIndexOf(JSObject::kElementsOffset),
- MaybeHandle<Name>(), zone());
+ state = state->KillField(
+ alias_info, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
+ MaybeHandle<Name>(), zone());
break;
}
}
@@ -1316,55 +1399,49 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
}
// static
-int LoadElimination::FieldIndexOf(int offset) {
+LoadElimination::IndexRange LoadElimination::FieldIndexOf(
+ int offset, int representation_size) {
DCHECK(IsAligned(offset, kTaggedSize));
- int field_index = offset / kTaggedSize;
- if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1;
- DCHECK_LT(0, field_index);
- return field_index - 1;
+ int field_index = offset / kTaggedSize - 1;
+ DCHECK_EQ(0, representation_size % kTaggedSize);
+ return IndexRange(field_index, representation_size / kTaggedSize);
}
// static
-int LoadElimination::FieldIndexOf(FieldAccess const& access) {
+LoadElimination::IndexRange LoadElimination::FieldIndexOf(
+ FieldAccess const& access) {
MachineRepresentation rep = access.machine_type.representation();
switch (rep) {
case MachineRepresentation::kNone:
case MachineRepresentation::kBit:
case MachineRepresentation::kSimd128:
UNREACHABLE();
- case MachineRepresentation::kWord32:
- if (kInt32Size != kTaggedSize) {
- return -1; // We currently only track tagged pointer size fields.
- }
- break;
- case MachineRepresentation::kWord64:
- if (kInt64Size != kTaggedSize) {
- return -1; // We currently only track tagged pointer size fields.
- }
- break;
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kFloat32:
- return -1; // Currently untracked.
+ // Currently untracked.
+ return IndexRange::Invalid();
case MachineRepresentation::kFloat64:
- if (kDoubleSize != kTaggedSize) {
- return -1; // We currently only track tagged pointer size fields.
- }
- break;
+ case MachineRepresentation::kWord32:
+ case MachineRepresentation::kWord64:
case MachineRepresentation::kTaggedSigned:
case MachineRepresentation::kTaggedPointer:
case MachineRepresentation::kTagged:
case MachineRepresentation::kCompressedSigned:
case MachineRepresentation::kCompressedPointer:
case MachineRepresentation::kCompressed:
- // TODO(bmeurer): Check that we never do overlapping load/stores of
- // individual parts of Float64 values.
break;
}
+ int representation_size = ElementSizeInBytes(rep);
+ // We currently only track fields that are at least tagged pointer sized.
+ if (representation_size < kTaggedSize) return IndexRange::Invalid();
+ DCHECK_EQ(0, representation_size % kTaggedSize);
+
if (access.base_is_tagged != kTaggedBase) {
- return -1; // We currently only track tagged objects.
+ // We currently only track tagged objects.
+ return IndexRange::Invalid();
}
- return FieldIndexOf(access.offset);
+ return FieldIndexOf(access.offset, representation_size);
}
CommonOperatorBuilder* LoadElimination::common() const {
diff --git a/deps/v8/src/compiler/load-elimination.h b/deps/v8/src/compiler/load-elimination.h
index 4ad1fa64a2..b97fd7b883 100644
--- a/deps/v8/src/compiler/load-elimination.h
+++ b/deps/v8/src/compiler/load-elimination.h
@@ -9,6 +9,7 @@
#include "src/codegen/machine-type.h"
#include "src/common/globals.h"
#include "src/compiler/graph-reducer.h"
+#include "src/compiler/simplified-operator.h"
#include "src/handles/maybe-handles.h"
#include "src/zone/zone-handle-set.h"
@@ -100,20 +101,25 @@ class V8_EXPORT_PRIVATE LoadElimination final
struct FieldInfo {
FieldInfo() = default;
- FieldInfo(Node* value, MachineRepresentation representation)
- : value(value), name(), representation(representation) {}
- FieldInfo(Node* value, MaybeHandle<Name> name,
- MachineRepresentation representation)
- : value(value), name(name), representation(representation) {}
+ FieldInfo(Node* value, MachineRepresentation representation,
+ MaybeHandle<Name> name = {},
+ ConstFieldInfo const_field_info = ConstFieldInfo::None())
+ : value(value),
+ representation(representation),
+ name(name),
+ const_field_info(const_field_info) {}
bool operator==(const FieldInfo& other) const {
- return value == other.value && name.address() == other.name.address() &&
- representation == other.representation;
+ return value == other.value && representation == other.representation &&
+ name.address() == other.name.address() &&
+ const_field_info == other.const_field_info;
}
+ bool operator!=(const FieldInfo& other) const { return !(*this == other); }
Node* value = nullptr;
- MaybeHandle<Name> name;
MachineRepresentation representation = MachineRepresentation::kNone;
+ MaybeHandle<Name> name;
+ ConstFieldInfo const_field_info;
};
// Abstract state to approximate the current state of a certain field along
@@ -134,6 +140,7 @@ class V8_EXPORT_PRIVATE LoadElimination final
return that;
}
FieldInfo const* Lookup(Node* object) const;
+ AbstractField const* KillConst(Node* object, Zone* zone) const;
AbstractField const* Kill(const AliasStateInfo& alias_info,
MaybeHandle<Name> name, Zone* zone) const;
bool Equals(AbstractField const* that) const {
@@ -186,6 +193,39 @@ class V8_EXPORT_PRIVATE LoadElimination final
ZoneMap<Node*, ZoneHandleSet<Map>> info_for_node_;
};
+ class IndexRange {
+ public:
+ IndexRange(int begin, int size) : begin_(begin), end_(begin + size) {
+ DCHECK_LE(0, begin);
+ DCHECK_LE(1, size);
+ if (end_ > static_cast<int>(kMaxTrackedFields)) {
+ *this = IndexRange::Invalid();
+ }
+ }
+ static IndexRange Invalid() { return IndexRange(); }
+
+ bool operator==(const IndexRange& other) {
+ return begin_ == other.begin_ && end_ == other.end_;
+ }
+ bool operator!=(const IndexRange& other) { return !(*this == other); }
+
+ struct Iterator {
+ int i;
+ int operator*() { return i; }
+ void operator++() { ++i; }
+ bool operator!=(Iterator other) { return i != other.i; }
+ };
+
+ Iterator begin() { return {begin_}; }
+ Iterator end() { return {end_}; }
+
+ private:
+ int begin_;
+ int end_;
+
+ IndexRange() : begin_(-1), end_(-1) {}
+ };
+
class AbstractState final : public ZoneObject {
public:
AbstractState() {}
@@ -200,19 +240,20 @@ class V8_EXPORT_PRIVATE LoadElimination final
Zone* zone) const;
bool LookupMaps(Node* object, ZoneHandleSet<Map>* object_maps) const;
- AbstractState const* AddField(Node* object, size_t index, FieldInfo info,
- PropertyConstness constness,
- Zone* zone) const;
+ AbstractState const* AddField(Node* object, IndexRange index,
+ FieldInfo info, Zone* zone) const;
+ AbstractState const* KillConstField(Node* object, IndexRange index_range,
+ Zone* zone) const;
AbstractState const* KillField(const AliasStateInfo& alias_info,
- size_t index, MaybeHandle<Name> name,
+ IndexRange index, MaybeHandle<Name> name,
Zone* zone) const;
- AbstractState const* KillField(Node* object, size_t index,
+ AbstractState const* KillField(Node* object, IndexRange index,
MaybeHandle<Name> name, Zone* zone) const;
AbstractState const* KillFields(Node* object, MaybeHandle<Name> name,
Zone* zone) const;
AbstractState const* KillAll(Zone* zone) const;
- FieldInfo const* LookupField(Node* object, size_t index,
- PropertyConstness constness) const;
+ FieldInfo const* LookupField(Node* object, IndexRange index,
+ ConstFieldInfo const_field_info) const;
AbstractState const* AddElement(Node* object, Node* index, Node* value,
MachineRepresentation representation,
@@ -280,8 +321,8 @@ class V8_EXPORT_PRIVATE LoadElimination final
AbstractState const* UpdateStateForPhi(AbstractState const* state,
Node* effect_phi, Node* phi);
- static int FieldIndexOf(int offset);
- static int FieldIndexOf(FieldAccess const& access);
+ static IndexRange FieldIndexOf(int offset, int representation_size);
+ static IndexRange FieldIndexOf(FieldAccess const& access);
static AbstractState const* empty_state() {
return AbstractState::empty_state();
diff --git a/deps/v8/src/compiler/machine-graph-verifier.cc b/deps/v8/src/compiler/machine-graph-verifier.cc
index 80205f80b6..4c7ee1d141 100644
--- a/deps/v8/src/compiler/machine-graph-verifier.cc
+++ b/deps/v8/src/compiler/machine-graph-verifier.cc
@@ -60,8 +60,7 @@ class MachineRepresentationInferrer {
CHECK_LE(index, static_cast<size_t>(1));
return index == 0 ? MachineRepresentation::kWord64
: MachineRepresentation::kBit;
- case IrOpcode::kCall:
- case IrOpcode::kCallWithCallerSavedRegisters: {
+ case IrOpcode::kCall: {
auto call_descriptor = CallDescriptorOf(input->op());
return call_descriptor->GetReturnType(index).representation();
}
@@ -128,7 +127,6 @@ class MachineRepresentationInferrer {
representation_vector_[node->id()] = PromoteRepresentation(
LoadRepresentationOf(node->op()).representation());
break;
- case IrOpcode::kLoadStackPointer:
case IrOpcode::kLoadFramePointer:
case IrOpcode::kLoadParentFramePointer:
representation_vector_[node->id()] =
@@ -142,8 +140,7 @@ class MachineRepresentationInferrer {
representation_vector_[node->id()] =
PhiRepresentationOf(node->op());
break;
- case IrOpcode::kCall:
- case IrOpcode::kCallWithCallerSavedRegisters: {
+ case IrOpcode::kCall: {
auto call_descriptor = CallDescriptorOf(node->op());
if (call_descriptor->ReturnCount() > 0) {
representation_vector_[node->id()] =
@@ -235,6 +232,10 @@ class MachineRepresentationInferrer {
case IrOpcode::kWord64PoisonOnSpeculation:
representation_vector_[node->id()] = MachineRepresentation::kWord64;
break;
+ case IrOpcode::kCompressedHeapConstant:
+ representation_vector_[node->id()] =
+ MachineRepresentation::kCompressedPointer;
+ break;
case IrOpcode::kExternalConstant:
representation_vector_[node->id()] =
MachineType::PointerRepresentation();
@@ -248,6 +249,13 @@ class MachineRepresentationInferrer {
representation_vector_[node->id()] =
MachineRepresentation::kTaggedSigned;
break;
+ case IrOpcode::kBitcastWord32ToCompressedSigned:
+ representation_vector_[node->id()] =
+ MachineRepresentation::kCompressedSigned;
+ break;
+ case IrOpcode::kBitcastCompressedSignedToWord32:
+ representation_vector_[node->id()] = MachineRepresentation::kWord32;
+ break;
case IrOpcode::kWord32Equal:
case IrOpcode::kInt32LessThan:
case IrOpcode::kInt32LessThanOrEqual:
@@ -265,6 +273,7 @@ class MachineRepresentationInferrer {
case IrOpcode::kFloat64LessThan:
case IrOpcode::kFloat64LessThanOrEqual:
case IrOpcode::kChangeTaggedToBit:
+ case IrOpcode::kStackPointerGreaterThan:
representation_vector_[node->id()] = MachineRepresentation::kBit;
break;
#define LABEL(opcode) case IrOpcode::k##opcode:
@@ -373,7 +382,6 @@ class MachineRepresentationChecker {
}
switch (node->opcode()) {
case IrOpcode::kCall:
- case IrOpcode::kCallWithCallerSavedRegisters:
case IrOpcode::kTailCall:
CheckCallInputs(node);
break;
@@ -433,6 +441,13 @@ class MachineRepresentationChecker {
case IrOpcode::kTaggedPoisonOnSpeculation:
CheckValueInputIsTagged(node, 0);
break;
+ case IrOpcode::kBitcastWord32ToCompressedSigned:
+ CheckValueInputRepresentationIs(node, 0,
+ MachineRepresentation::kWord32);
+ break;
+ case IrOpcode::kBitcastCompressedSignedToWord32:
+ CheckValueInputIsCompressed(node, 0);
+ break;
case IrOpcode::kTruncateFloat64ToWord32:
case IrOpcode::kTruncateFloat64ToUint32:
case IrOpcode::kTruncateFloat64ToFloat32:
@@ -699,6 +714,10 @@ class MachineRepresentationChecker {
}
break;
}
+ case IrOpcode::kStackPointerGreaterThan:
+ CheckValueInputRepresentationIs(
+ node, 0, MachineType::PointerRepresentation());
+ break;
case IrOpcode::kThrow:
case IrOpcode::kTypedStateValues:
case IrOpcode::kFrameState:
@@ -751,11 +770,6 @@ class MachineRepresentationChecker {
case MachineRepresentation::kCompressedPointer:
case MachineRepresentation::kCompressedSigned:
return;
- case MachineRepresentation::kNone:
- if (input->opcode() == IrOpcode::kCompressedHeapConstant) {
- return;
- }
- break;
default:
break;
}
@@ -858,17 +872,6 @@ class MachineRepresentationChecker {
case MachineRepresentation::kCompressedSigned:
case MachineRepresentation::kCompressedPointer:
return;
- case MachineRepresentation::kNone: {
- if (input->opcode() == IrOpcode::kCompressedHeapConstant) {
- return;
- }
- std::ostringstream str;
- str << "TypeError: node #" << input->id() << ":" << *input->op()
- << " is untyped.";
- PrintDebugHelp(str, node);
- FATAL("%s", str.str().c_str());
- break;
- }
default:
break;
}
diff --git a/deps/v8/src/compiler/machine-operator-reducer.cc b/deps/v8/src/compiler/machine-operator-reducer.cc
index f720c29084..11124579f6 100644
--- a/deps/v8/src/compiler/machine-operator-reducer.cc
+++ b/deps/v8/src/compiler/machine-operator-reducer.cc
@@ -34,17 +34,14 @@ Node* MachineOperatorReducer::Float32Constant(volatile float value) {
return graph()->NewNode(common()->Float32Constant(value));
}
-
Node* MachineOperatorReducer::Float64Constant(volatile double value) {
return mcgraph()->Float64Constant(value);
}
-
Node* MachineOperatorReducer::Int32Constant(int32_t value) {
return mcgraph()->Int32Constant(value);
}
-
Node* MachineOperatorReducer::Int64Constant(int64_t value) {
return graph()->NewNode(common()->Int64Constant(value));
}
@@ -70,23 +67,27 @@ Node* MachineOperatorReducer::Word32And(Node* lhs, Node* rhs) {
return reduction.Changed() ? reduction.replacement() : node;
}
-
Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
if (rhs == 0) return lhs;
return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
}
-
Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
if (rhs == 0) return lhs;
return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
}
-
Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) {
return graph()->NewNode(machine()->Word32Equal(), lhs, rhs);
}
+Node* MachineOperatorReducer::BitcastWord32ToCompressedSigned(Node* value) {
+ return graph()->NewNode(machine()->BitcastWord32ToCompressedSigned(), value);
+}
+
+Node* MachineOperatorReducer::BitcastCompressedSignedToWord32(Node* value) {
+ return graph()->NewNode(machine()->BitcastCompressedSignedToWord32(), value);
+}
Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
Node* const node = graph()->NewNode(machine()->Int32Add(), lhs, rhs);
@@ -94,19 +95,16 @@ Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
return reduction.Changed() ? reduction.replacement() : node;
}
-
Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) {
Node* const node = graph()->NewNode(machine()->Int32Sub(), lhs, rhs);
Reduction const reduction = ReduceInt32Sub(node);
return reduction.Changed() ? reduction.replacement() : node;
}
-
Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
return graph()->NewNode(machine()->Int32Mul(), lhs, rhs);
}
-
Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
DCHECK_NE(0, divisor);
DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
@@ -122,7 +120,6 @@ Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
return Int32Add(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31));
}
-
Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
DCHECK_LT(0u, divisor);
// If the divisor is even, we can avoid using the expensive fixup by shifting
@@ -146,7 +143,6 @@ Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
return quotient;
}
-
// Perform constant folding and strength reduction on machine operators.
Reduction MachineOperatorReducer::Reduce(Node* node) {
switch (node->opcode()) {
@@ -664,6 +660,17 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
if (m.HasValue()) return ReplaceInt64(static_cast<uint64_t>(m.Value()));
break;
}
+ case IrOpcode::kChangeTaggedToCompressed: {
+ Int64Matcher m(node->InputAt(0));
+ if (m.IsBitcastWordToTaggedSigned()) {
+ Int64Matcher n(m.node()->InputAt(0));
+ if (n.IsChangeInt32ToInt64()) {
+ DCHECK(machine()->Is64() && SmiValuesAre31Bits());
+ return Replace(BitcastWord32ToCompressedSigned(n.node()->InputAt(0)));
+ }
+ }
+ break;
+ }
case IrOpcode::kTruncateFloat64ToWord32: {
Float64Matcher m(node->InputAt(0));
if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
@@ -674,6 +681,13 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
Int64Matcher m(node->InputAt(0));
if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
if (m.IsChangeInt32ToInt64()) return Replace(m.node()->InputAt(0));
+ if (m.IsBitcastTaggedSignedToWord()) {
+ Int64Matcher n(m.node()->InputAt(0));
+ if (n.IsChangeCompressedToTagged()) {
+ DCHECK(machine()->Is64() && SmiValuesAre31Bits());
+ return Replace(BitcastCompressedSignedToWord32(n.node()->InputAt(0)));
+ }
+ }
break;
}
case IrOpcode::kTruncateFloat64ToFloat32: {
@@ -871,7 +885,6 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
return NoChange();
}
-
Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
Uint32BinopMatcher m(node);
if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0
@@ -900,7 +913,6 @@ Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
return NoChange();
}
-
Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
Int32BinopMatcher m(node);
if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0
@@ -937,7 +949,6 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
return NoChange();
}
-
Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
Uint32BinopMatcher m(node);
if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0
@@ -967,7 +978,6 @@ Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
return NoChange();
}
-
Reduction MachineOperatorReducer::ReduceStore(Node* node) {
NodeMatcher nm(node);
MachineRepresentation rep;
@@ -1015,7 +1025,6 @@ Reduction MachineOperatorReducer::ReduceStore(Node* node) {
return NoChange();
}
-
Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
switch (node->opcode()) {
case IrOpcode::kInt32AddWithOverflow: {
@@ -1069,7 +1078,6 @@ Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
return NoChange();
}
-
Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) {
DCHECK((node->opcode() == IrOpcode::kWord32Shl) ||
(node->opcode() == IrOpcode::kWord32Shr) ||
@@ -1089,7 +1097,6 @@ Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) {
return NoChange();
}
-
Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) {
DCHECK_EQ(IrOpcode::kWord32Shl, node->opcode());
Int32BinopMatcher m(node);
@@ -1399,7 +1406,6 @@ Reduction MachineOperatorReducer::ReduceFloat64InsertLowWord32(Node* node) {
return NoChange();
}
-
Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) {
DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode());
Float64Matcher mlhs(node->InputAt(0));
@@ -1412,7 +1418,6 @@ Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) {
return NoChange();
}
-
namespace {
bool IsFloat64RepresentableAsFloat32(const Float64Matcher& m) {
@@ -1492,7 +1497,6 @@ CommonOperatorBuilder* MachineOperatorReducer::common() const {
return mcgraph()->common();
}
-
MachineOperatorBuilder* MachineOperatorReducer::machine() const {
return mcgraph()->machine();
}
diff --git a/deps/v8/src/compiler/machine-operator-reducer.h b/deps/v8/src/compiler/machine-operator-reducer.h
index a8e4cd5749..6eab08653e 100644
--- a/deps/v8/src/compiler/machine-operator-reducer.h
+++ b/deps/v8/src/compiler/machine-operator-reducer.h
@@ -51,6 +51,8 @@ class V8_EXPORT_PRIVATE MachineOperatorReducer final
Node* Word32Sar(Node* lhs, uint32_t rhs);
Node* Word32Shr(Node* lhs, uint32_t rhs);
Node* Word32Equal(Node* lhs, Node* rhs);
+ Node* BitcastWord32ToCompressedSigned(Node* value);
+ Node* BitcastCompressedSignedToWord32(Node* value);
Node* Int32Add(Node* lhs, Node* rhs);
Node* Int32Sub(Node* lhs, Node* rhs);
Node* Int32Mul(Node* lhs, Node* rhs);
diff --git a/deps/v8/src/compiler/machine-operator.cc b/deps/v8/src/compiler/machine-operator.cc
index f447861aca..0355534408 100644
--- a/deps/v8/src/compiler/machine-operator.cc
+++ b/deps/v8/src/compiler/machine-operator.cc
@@ -89,6 +89,8 @@ MachineType AtomicOpType(Operator const* op) {
return OpParameter<MachineType>(op);
}
+// The format is:
+// V(Name, properties, value_input_count, control_input_count, output_count)
#define PURE_BINARY_OP_LIST_32(V) \
V(Word32And, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \
V(Word32Or, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \
@@ -112,6 +114,8 @@ MachineType AtomicOpType(Operator const* op) {
V(Uint32Mod, Operator::kNoProperties, 2, 1, 1) \
V(Uint32MulHigh, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)
+// The format is:
+// V(Name, properties, value_input_count, control_input_count, output_count)
#define PURE_BINARY_OP_LIST_64(V) \
V(Word64And, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \
V(Word64Or, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \
@@ -133,6 +137,8 @@ MachineType AtomicOpType(Operator const* op) {
V(Uint64LessThan, Operator::kNoProperties, 2, 0, 1) \
V(Uint64LessThanOrEqual, Operator::kNoProperties, 2, 0, 1)
+// The format is:
+// V(Name, properties, value_input_count, control_input_count, output_count)
#define MACHINE_PURE_OP_LIST(V) \
PURE_BINARY_OP_LIST_32(V) \
PURE_BINARY_OP_LIST_64(V) \
@@ -142,6 +148,8 @@ MachineType AtomicOpType(Operator const* op) {
V(Word64ReverseBytes, Operator::kNoProperties, 1, 0, 1) \
V(BitcastTaggedSignedToWord, Operator::kNoProperties, 1, 0, 1) \
V(BitcastWordToTaggedSigned, Operator::kNoProperties, 1, 0, 1) \
+ V(BitcastWord32ToCompressedSigned, Operator::kNoProperties, 1, 0, 1) \
+ V(BitcastCompressedSignedToWord32, Operator::kNoProperties, 1, 0, 1) \
V(TruncateFloat64ToWord32, Operator::kNoProperties, 1, 0, 1) \
V(ChangeFloat32ToFloat64, Operator::kNoProperties, 1, 0, 1) \
V(ChangeFloat64ToInt32, Operator::kNoProperties, 1, 0, 1) \
@@ -236,7 +244,6 @@ MachineType AtomicOpType(Operator const* op) {
V(Float64ExtractHighWord32, Operator::kNoProperties, 1, 0, 1) \
V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1) \
V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1) \
- V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) \
V(LoadFramePointer, Operator::kNoProperties, 0, 0, 1) \
V(LoadParentFramePointer, Operator::kNoProperties, 0, 0, 1) \
V(Int32PairAdd, Operator::kNoProperties, 4, 0, 2) \
@@ -248,6 +255,12 @@ MachineType AtomicOpType(Operator const* op) {
V(F64x2Splat, Operator::kNoProperties, 1, 0, 1) \
V(F64x2Abs, Operator::kNoProperties, 1, 0, 1) \
V(F64x2Neg, Operator::kNoProperties, 1, 0, 1) \
+ V(F64x2Add, Operator::kCommutative, 2, 0, 1) \
+ V(F64x2Sub, Operator::kNoProperties, 2, 0, 1) \
+ V(F64x2Mul, Operator::kCommutative, 2, 0, 1) \
+ V(F64x2Div, Operator::kNoProperties, 2, 0, 1) \
+ V(F64x2Min, Operator::kCommutative, 2, 0, 1) \
+ V(F64x2Max, Operator::kCommutative, 2, 0, 1) \
V(F64x2Eq, Operator::kCommutative, 2, 0, 1) \
V(F64x2Ne, Operator::kCommutative, 2, 0, 1) \
V(F64x2Lt, Operator::kNoProperties, 2, 0, 1) \
@@ -263,6 +276,7 @@ MachineType AtomicOpType(Operator const* op) {
V(F32x4AddHoriz, Operator::kNoProperties, 2, 0, 1) \
V(F32x4Sub, Operator::kNoProperties, 2, 0, 1) \
V(F32x4Mul, Operator::kCommutative, 2, 0, 1) \
+ V(F32x4Div, Operator::kNoProperties, 2, 0, 1) \
V(F32x4Min, Operator::kCommutative, 2, 0, 1) \
V(F32x4Max, Operator::kCommutative, 2, 0, 1) \
V(F32x4Eq, Operator::kCommutative, 2, 0, 1) \
@@ -271,13 +285,20 @@ MachineType AtomicOpType(Operator const* op) {
V(F32x4Le, Operator::kNoProperties, 2, 0, 1) \
V(I64x2Splat, Operator::kNoProperties, 1, 0, 1) \
V(I64x2Neg, Operator::kNoProperties, 1, 0, 1) \
+ V(I64x2Shl, Operator::kNoProperties, 2, 0, 1) \
+ V(I64x2ShrS, Operator::kNoProperties, 2, 0, 1) \
V(I64x2Add, Operator::kCommutative, 2, 0, 1) \
V(I64x2Sub, Operator::kNoProperties, 2, 0, 1) \
V(I64x2Mul, Operator::kCommutative, 2, 0, 1) \
+ V(I64x2MinS, Operator::kCommutative, 2, 0, 1) \
+ V(I64x2MaxS, Operator::kCommutative, 2, 0, 1) \
V(I64x2Eq, Operator::kCommutative, 2, 0, 1) \
V(I64x2Ne, Operator::kCommutative, 2, 0, 1) \
V(I64x2GtS, Operator::kNoProperties, 2, 0, 1) \
V(I64x2GeS, Operator::kNoProperties, 2, 0, 1) \
+ V(I64x2ShrU, Operator::kNoProperties, 2, 0, 1) \
+ V(I64x2MinU, Operator::kCommutative, 2, 0, 1) \
+ V(I64x2MaxU, Operator::kCommutative, 2, 0, 1) \
V(I64x2GtU, Operator::kNoProperties, 2, 0, 1) \
V(I64x2GeU, Operator::kNoProperties, 2, 0, 1) \
V(I32x4Splat, Operator::kNoProperties, 1, 0, 1) \
@@ -285,6 +306,8 @@ MachineType AtomicOpType(Operator const* op) {
V(I32x4SConvertI16x8Low, Operator::kNoProperties, 1, 0, 1) \
V(I32x4SConvertI16x8High, Operator::kNoProperties, 1, 0, 1) \
V(I32x4Neg, Operator::kNoProperties, 1, 0, 1) \
+ V(I32x4Shl, Operator::kNoProperties, 2, 0, 1) \
+ V(I32x4ShrS, Operator::kNoProperties, 2, 0, 1) \
V(I32x4Add, Operator::kCommutative, 2, 0, 1) \
V(I32x4AddHoriz, Operator::kNoProperties, 2, 0, 1) \
V(I32x4Sub, Operator::kNoProperties, 2, 0, 1) \
@@ -298,6 +321,7 @@ MachineType AtomicOpType(Operator const* op) {
V(I32x4UConvertF32x4, Operator::kNoProperties, 1, 0, 1) \
V(I32x4UConvertI16x8Low, Operator::kNoProperties, 1, 0, 1) \
V(I32x4UConvertI16x8High, Operator::kNoProperties, 1, 0, 1) \
+ V(I32x4ShrU, Operator::kNoProperties, 2, 0, 1) \
V(I32x4MinU, Operator::kCommutative, 2, 0, 1) \
V(I32x4MaxU, Operator::kCommutative, 2, 0, 1) \
V(I32x4GtU, Operator::kNoProperties, 2, 0, 1) \
@@ -306,6 +330,8 @@ MachineType AtomicOpType(Operator const* op) {
V(I16x8SConvertI8x16Low, Operator::kNoProperties, 1, 0, 1) \
V(I16x8SConvertI8x16High, Operator::kNoProperties, 1, 0, 1) \
V(I16x8Neg, Operator::kNoProperties, 1, 0, 1) \
+ V(I16x8Shl, Operator::kNoProperties, 2, 0, 1) \
+ V(I16x8ShrS, Operator::kNoProperties, 2, 0, 1) \
V(I16x8SConvertI32x4, Operator::kNoProperties, 2, 0, 1) \
V(I16x8Add, Operator::kCommutative, 2, 0, 1) \
V(I16x8AddSaturateS, Operator::kCommutative, 2, 0, 1) \
@@ -321,6 +347,7 @@ MachineType AtomicOpType(Operator const* op) {
V(I16x8GeS, Operator::kNoProperties, 2, 0, 1) \
V(I16x8UConvertI8x16Low, Operator::kNoProperties, 1, 0, 1) \
V(I16x8UConvertI8x16High, Operator::kNoProperties, 1, 0, 1) \
+ V(I16x8ShrU, Operator::kNoProperties, 2, 0, 1) \
V(I16x8UConvertI32x4, Operator::kNoProperties, 2, 0, 1) \
V(I16x8AddSaturateU, Operator::kCommutative, 2, 0, 1) \
V(I16x8SubSaturateU, Operator::kNoProperties, 2, 0, 1) \
@@ -330,6 +357,8 @@ MachineType AtomicOpType(Operator const* op) {
V(I16x8GeU, Operator::kNoProperties, 2, 0, 1) \
V(I8x16Splat, Operator::kNoProperties, 1, 0, 1) \
V(I8x16Neg, Operator::kNoProperties, 1, 0, 1) \
+ V(I8x16Shl, Operator::kNoProperties, 2, 0, 1) \
+ V(I8x16ShrS, Operator::kNoProperties, 2, 0, 1) \
V(I8x16SConvertI16x8, Operator::kNoProperties, 2, 0, 1) \
V(I8x16Add, Operator::kCommutative, 2, 0, 1) \
V(I8x16AddSaturateS, Operator::kCommutative, 2, 0, 1) \
@@ -342,6 +371,7 @@ MachineType AtomicOpType(Operator const* op) {
V(I8x16Ne, Operator::kCommutative, 2, 0, 1) \
V(I8x16GtS, Operator::kNoProperties, 2, 0, 1) \
V(I8x16GeS, Operator::kNoProperties, 2, 0, 1) \
+ V(I8x16ShrU, Operator::kNoProperties, 2, 0, 1) \
V(I8x16UConvertI16x8, Operator::kNoProperties, 2, 0, 1) \
V(I8x16AddSaturateU, Operator::kCommutative, 2, 0, 1) \
V(I8x16SubSaturateU, Operator::kNoProperties, 2, 0, 1) \
@@ -364,8 +394,11 @@ MachineType AtomicOpType(Operator const* op) {
V(S1x8AnyTrue, Operator::kNoProperties, 1, 0, 1) \
V(S1x8AllTrue, Operator::kNoProperties, 1, 0, 1) \
V(S1x16AnyTrue, Operator::kNoProperties, 1, 0, 1) \
- V(S1x16AllTrue, Operator::kNoProperties, 1, 0, 1)
+ V(S1x16AllTrue, Operator::kNoProperties, 1, 0, 1) \
+ V(StackPointerGreaterThan, Operator::kNoProperties, 1, 0, 1)
+// The format is:
+// V(Name, properties, value_input_count, control_input_count, output_count)
#define PURE_OPTIONAL_OP_LIST(V) \
V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \
V(Word64Ctz, Operator::kNoProperties, 1, 0, 1) \
@@ -385,6 +418,8 @@ MachineType AtomicOpType(Operator const* op) {
V(Float32RoundTiesEven, Operator::kNoProperties, 1, 0, 1) \
V(Float64RoundTiesEven, Operator::kNoProperties, 1, 0, 1)
+// The format is:
+// V(Name, properties, value_input_count, control_input_count, output_count)
#define OVERFLOW_OP_LIST(V) \
V(Int32AddWithOverflow, Operator::kAssociative | Operator::kCommutative) \
V(Int32SubWithOverflow, Operator::kNoProperties) \
@@ -467,12 +502,6 @@ MachineType AtomicOpType(Operator const* op) {
V(I16x8, 8) \
V(I8x16, 16)
-#define SIMD_FORMAT_LIST(V) \
- V(64x2, 64) \
- V(32x4, 32) \
- V(16x8, 16) \
- V(8x16, 8)
-
#define STACK_SLOT_CACHED_SIZES_ALIGNMENTS_LIST(V) \
V(4, 0) V(8, 0) V(16, 0) V(4, 4) V(8, 8) V(16, 16)
@@ -1305,28 +1334,6 @@ const Operator* MachineOperatorBuilder::Word64PoisonOnSpeculation() {
SIMD_LANE_OP_LIST(SIMD_LANE_OPS)
#undef SIMD_LANE_OPS
-#define SIMD_SHIFT_OPS(format, bits) \
- const Operator* MachineOperatorBuilder::I##format##Shl(int32_t shift) { \
- DCHECK(0 <= shift && shift < bits); \
- return new (zone_) \
- Operator1<int32_t>(IrOpcode::kI##format##Shl, Operator::kPure, \
- "Shift left", 1, 0, 0, 1, 0, 0, shift); \
- } \
- const Operator* MachineOperatorBuilder::I##format##ShrS(int32_t shift) { \
- DCHECK(0 < shift && shift <= bits); \
- return new (zone_) \
- Operator1<int32_t>(IrOpcode::kI##format##ShrS, Operator::kPure, \
- "Arithmetic shift right", 1, 0, 0, 1, 0, 0, shift); \
- } \
- const Operator* MachineOperatorBuilder::I##format##ShrU(int32_t shift) { \
- DCHECK(0 <= shift && shift < bits); \
- return new (zone_) \
- Operator1<int32_t>(IrOpcode::kI##format##ShrU, Operator::kPure, \
- "Shift right", 1, 0, 0, 1, 0, 0, shift); \
- }
-SIMD_FORMAT_LIST(SIMD_SHIFT_OPS)
-#undef SIMD_SHIFT_OPS
-
const Operator* MachineOperatorBuilder::S8x16Shuffle(
const uint8_t shuffle[16]) {
uint8_t* array = zone_->NewArray<uint8_t>(16);
@@ -1354,7 +1361,6 @@ const uint8_t* S8x16ShuffleOf(Operator const* op) {
#undef ATOMIC_REPRESENTATION_LIST
#undef ATOMIC64_REPRESENTATION_LIST
#undef SIMD_LANE_OP_LIST
-#undef SIMD_FORMAT_LIST
#undef STACK_SLOT_CACHED_SIZES_ALIGNMENTS_LIST
} // namespace compiler
diff --git a/deps/v8/src/compiler/machine-operator.h b/deps/v8/src/compiler/machine-operator.h
index 0f81301206..17db145f58 100644
--- a/deps/v8/src/compiler/machine-operator.h
+++ b/deps/v8/src/compiler/machine-operator.h
@@ -314,6 +314,12 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
// This operator reinterprets the bits of a word as a Smi.
const Operator* BitcastWordToTaggedSigned();
+ // This operator reinterprets the bits of a word32 as a Compressed Smi.
+ const Operator* BitcastWord32ToCompressedSigned();
+
+ // This operator reinterprets the bits of a Compressed Smi as a word32.
+ const Operator* BitcastCompressedSignedToWord32();
+
// JavaScript float64 to int32/uint32 truncation.
const Operator* TruncateFloat64ToWord32();
@@ -471,7 +477,13 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* F64x2Splat();
const Operator* F64x2Abs();
const Operator* F64x2Neg();
+ const Operator* F64x2Add();
+ const Operator* F64x2Sub();
+ const Operator* F64x2Mul();
+ const Operator* F64x2Div();
const Operator* F64x2ExtractLane(int32_t);
+ const Operator* F64x2Min();
+ const Operator* F64x2Max();
const Operator* F64x2ReplaceLane(int32_t);
const Operator* F64x2Eq();
const Operator* F64x2Ne();
@@ -503,16 +515,20 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* I64x2ExtractLane(int32_t);
const Operator* I64x2ReplaceLane(int32_t);
const Operator* I64x2Neg();
- const Operator* I64x2Shl(int32_t);
- const Operator* I64x2ShrS(int32_t);
+ const Operator* I64x2Shl();
+ const Operator* I64x2ShrS();
const Operator* I64x2Add();
const Operator* I64x2Sub();
const Operator* I64x2Mul();
+ const Operator* I64x2MinS();
+ const Operator* I64x2MaxS();
const Operator* I64x2Eq();
const Operator* I64x2Ne();
const Operator* I64x2GtS();
const Operator* I64x2GeS();
- const Operator* I64x2ShrU(int32_t);
+ const Operator* I64x2ShrU();
+ const Operator* I64x2MinU();
+ const Operator* I64x2MaxU();
const Operator* I64x2GtU();
const Operator* I64x2GeU();
@@ -523,8 +539,8 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* I32x4SConvertI16x8Low();
const Operator* I32x4SConvertI16x8High();
const Operator* I32x4Neg();
- const Operator* I32x4Shl(int32_t);
- const Operator* I32x4ShrS(int32_t);
+ const Operator* I32x4Shl();
+ const Operator* I32x4ShrS();
const Operator* I32x4Add();
const Operator* I32x4AddHoriz();
const Operator* I32x4Sub();
@@ -539,7 +555,7 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* I32x4UConvertF32x4();
const Operator* I32x4UConvertI16x8Low();
const Operator* I32x4UConvertI16x8High();
- const Operator* I32x4ShrU(int32_t);
+ const Operator* I32x4ShrU();
const Operator* I32x4MinU();
const Operator* I32x4MaxU();
const Operator* I32x4GtU();
@@ -551,8 +567,8 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* I16x8SConvertI8x16Low();
const Operator* I16x8SConvertI8x16High();
const Operator* I16x8Neg();
- const Operator* I16x8Shl(int32_t);
- const Operator* I16x8ShrS(int32_t);
+ const Operator* I16x8Shl();
+ const Operator* I16x8ShrS();
const Operator* I16x8SConvertI32x4();
const Operator* I16x8Add();
const Operator* I16x8AddSaturateS();
@@ -569,7 +585,7 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* I16x8UConvertI8x16Low();
const Operator* I16x8UConvertI8x16High();
- const Operator* I16x8ShrU(int32_t);
+ const Operator* I16x8ShrU();
const Operator* I16x8UConvertI32x4();
const Operator* I16x8AddSaturateU();
const Operator* I16x8SubSaturateU();
@@ -582,8 +598,8 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* I8x16ExtractLane(int32_t);
const Operator* I8x16ReplaceLane(int32_t);
const Operator* I8x16Neg();
- const Operator* I8x16Shl(int32_t);
- const Operator* I8x16ShrS(int32_t);
+ const Operator* I8x16Shl();
+ const Operator* I8x16ShrS();
const Operator* I8x16SConvertI16x8();
const Operator* I8x16Add();
const Operator* I8x16AddSaturateS();
@@ -597,7 +613,7 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* I8x16GtS();
const Operator* I8x16GeS();
- const Operator* I8x16ShrU(int32_t);
+ const Operator* I8x16ShrU();
const Operator* I8x16UConvertI16x8();
const Operator* I8x16AddSaturateU();
const Operator* I8x16SubSaturateU();
@@ -651,10 +667,12 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* Word64PoisonOnSpeculation();
// Access to the machine stack.
- const Operator* LoadStackPointer();
const Operator* LoadFramePointer();
const Operator* LoadParentFramePointer();
+ // Compares: stack_pointer > value.
+ const Operator* StackPointerGreaterThan();
+
// Memory barrier.
const Operator* MemBarrier();
diff --git a/deps/v8/src/compiler/map-inference.cc b/deps/v8/src/compiler/map-inference.cc
index 07ac95b4f7..1e2434f4ae 100644
--- a/deps/v8/src/compiler/map-inference.cc
+++ b/deps/v8/src/compiler/map-inference.cc
@@ -5,9 +5,9 @@
#include "src/compiler/map-inference.h"
#include "src/compiler/compilation-dependencies.h"
+#include "src/compiler/feedback-source.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/simplified-operator.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/objects/map-inl.h"
#include "src/zone/zone-handle-set.h"
@@ -93,7 +93,7 @@ MapHandles const& MapInference::GetMaps() {
void MapInference::InsertMapChecks(JSGraph* jsgraph, Node** effect,
Node* control,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
CHECK(HaveMaps());
CHECK(feedback.IsValid());
ZoneHandleSet<Map> maps;
@@ -112,7 +112,7 @@ bool MapInference::RelyOnMapsViaStability(
bool MapInference::RelyOnMapsPreferStability(
CompilationDependencies* dependencies, JSGraph* jsgraph, Node** effect,
- Node* control, const VectorSlotPair& feedback) {
+ Node* control, const FeedbackSource& feedback) {
CHECK(HaveMaps());
if (Safe()) return false;
if (RelyOnMapsViaStability(dependencies)) return true;
@@ -123,7 +123,7 @@ bool MapInference::RelyOnMapsPreferStability(
bool MapInference::RelyOnMapsHelper(CompilationDependencies* dependencies,
JSGraph* jsgraph, Node** effect,
Node* control,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
if (Safe()) return true;
auto is_stable = [this](Handle<Map> map) {
diff --git a/deps/v8/src/compiler/map-inference.h b/deps/v8/src/compiler/map-inference.h
index 64cec77f2b..acba2eb0f2 100644
--- a/deps/v8/src/compiler/map-inference.h
+++ b/deps/v8/src/compiler/map-inference.h
@@ -13,11 +13,11 @@
namespace v8 {
namespace internal {
-class VectorSlotPair;
namespace compiler {
class CompilationDependencies;
+struct FeedbackSource;
class JSGraph;
class JSHeapBroker;
class Node;
@@ -67,10 +67,10 @@ class MapInference {
// dependencies were taken.
bool RelyOnMapsPreferStability(CompilationDependencies* dependencies,
JSGraph* jsgraph, Node** effect, Node* control,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
// Inserts map checks even if maps were already reliable.
void InsertMapChecks(JSGraph* jsgraph, Node** effect, Node* control,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
// Internally marks the maps as reliable (thus bypassing the safety check) and
// returns the NoChange reduction. USE THIS ONLY WHEN RETURNING, e.g.:
@@ -98,7 +98,7 @@ class MapInference {
std::function<bool(InstanceType)> f) const;
V8_WARN_UNUSED_RESULT bool RelyOnMapsHelper(
CompilationDependencies* dependencies, JSGraph* jsgraph, Node** effect,
- Node* control, const VectorSlotPair& feedback);
+ Node* control, const FeedbackSource& feedback);
};
} // namespace compiler
diff --git a/deps/v8/src/compiler/memory-optimizer.cc b/deps/v8/src/compiler/memory-optimizer.cc
index 368c060c1d..8684f2ce3c 100644
--- a/deps/v8/src/compiler/memory-optimizer.cc
+++ b/deps/v8/src/compiler/memory-optimizer.cc
@@ -101,6 +101,12 @@ bool CanAllocate(const Node* node) {
switch (node->opcode()) {
case IrOpcode::kBitcastTaggedToWord:
case IrOpcode::kBitcastWordToTagged:
+ case IrOpcode::kChangeCompressedToTagged:
+ case IrOpcode::kChangeCompressedSignedToTaggedSigned:
+ case IrOpcode::kChangeCompressedPointerToTaggedPointer:
+ case IrOpcode::kChangeTaggedToCompressed:
+ case IrOpcode::kChangeTaggedSignedToCompressedSigned:
+ case IrOpcode::kChangeTaggedPointerToCompressedPointer:
case IrOpcode::kComment:
case IrOpcode::kAbortCSAAssert:
case IrOpcode::kDebugBreak:
@@ -161,7 +167,6 @@ bool CanAllocate(const Node* node) {
return false;
case IrOpcode::kCall:
- case IrOpcode::kCallWithCallerSavedRegisters:
return !(CallDescriptorOf(node->op())->flags() &
CallDescriptor::kNoAllocate);
default:
@@ -231,8 +236,6 @@ void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state) {
return VisitAllocateRaw(node, state);
case IrOpcode::kCall:
return VisitCall(node, state);
- case IrOpcode::kCallWithCallerSavedRegisters:
- return VisitCallWithCallerSavedRegisters(node, state);
case IrOpcode::kLoadFromObject:
return VisitLoadFromObject(node, state);
case IrOpcode::kLoadElement:
@@ -258,6 +261,35 @@ void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state) {
#define __ gasm()->
+bool MemoryOptimizer::AllocationTypeNeedsUpdateToOld(Node* const node,
+ const Edge edge) {
+ if (COMPRESS_POINTERS_BOOL && IrOpcode::IsCompressOpcode(node->opcode())) {
+ // In Pointer Compression we might have a Compress node between an
+ // AllocateRaw and the value used as input. This case is trickier since we
+ // have to check all of the Compress node edges to test for a StoreField.
+ for (Edge const new_edge : node->use_edges()) {
+ if (AllocationTypeNeedsUpdateToOld(new_edge.from(), new_edge)) {
+ return true;
+ }
+ }
+
+ // If we arrived here, we tested all the edges of the Compress node and
+ // didn't find it necessary to update the AllocationType.
+ return false;
+ }
+
+ // Test to see if we need to update the AllocationType.
+ if (node->opcode() == IrOpcode::kStoreField && edge.index() == 1) {
+ Node* parent = node->InputAt(0);
+ if (parent->opcode() == IrOpcode::kAllocateRaw &&
+ AllocationTypeOf(parent->op()) == AllocationType::kOld) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void MemoryOptimizer::VisitAllocateRaw(Node* node,
AllocationState const* state) {
DCHECK_EQ(IrOpcode::kAllocateRaw, node->opcode());
@@ -278,8 +310,17 @@ void MemoryOptimizer::VisitAllocateRaw(Node* node,
if (allocation_type == AllocationType::kOld) {
for (Edge const edge : node->use_edges()) {
Node* const user = edge.from();
+
if (user->opcode() == IrOpcode::kStoreField && edge.index() == 0) {
- Node* const child = user->InputAt(1);
+ Node* child = user->InputAt(1);
+ // In Pointer Compression we might have a Compress node between an
+ // AllocateRaw and the value used as input. If so, we need to update
+ // child to point to the StoreField.
+ if (COMPRESS_POINTERS_BOOL &&
+ IrOpcode::IsCompressOpcode(child->opcode())) {
+ child = child->InputAt(0);
+ }
+
if (child->opcode() == IrOpcode::kAllocateRaw &&
AllocationTypeOf(child->op()) == AllocationType::kYoung) {
NodeProperties::ChangeOp(child, node->op());
@@ -291,13 +332,9 @@ void MemoryOptimizer::VisitAllocateRaw(Node* node,
DCHECK_EQ(AllocationType::kYoung, allocation_type);
for (Edge const edge : node->use_edges()) {
Node* const user = edge.from();
- if (user->opcode() == IrOpcode::kStoreField && edge.index() == 1) {
- Node* const parent = user->InputAt(0);
- if (parent->opcode() == IrOpcode::kAllocateRaw &&
- AllocationTypeOf(parent->op()) == AllocationType::kOld) {
- allocation_type = AllocationType::kOld;
- break;
- }
+ if (AllocationTypeNeedsUpdateToOld(user, edge)) {
+ allocation_type = AllocationType::kOld;
+ break;
}
}
}
@@ -523,16 +560,6 @@ void MemoryOptimizer::VisitCall(Node* node, AllocationState const* state) {
EnqueueUses(node, state);
}
-void MemoryOptimizer::VisitCallWithCallerSavedRegisters(
- Node* node, AllocationState const* state) {
- DCHECK_EQ(IrOpcode::kCallWithCallerSavedRegisters, node->opcode());
- // If the call can allocate, we start with a fresh state.
- if (!(CallDescriptorOf(node->op())->flags() & CallDescriptor::kNoAllocate)) {
- state = empty_state();
- }
- EnqueueUses(node, state);
-}
-
void MemoryOptimizer::VisitLoadElement(Node* node,
AllocationState const* state) {
DCHECK_EQ(IrOpcode::kLoadElement, node->opcode());
@@ -540,9 +567,7 @@ void MemoryOptimizer::VisitLoadElement(Node* node,
Node* index = node->InputAt(1);
node->ReplaceInput(1, ComputeIndex(access, index));
MachineType type = access.machine_type;
- if (NeedsPoisoning(access.load_sensitivity) &&
- type.representation() != MachineRepresentation::kTaggedPointer &&
- type.representation() != MachineRepresentation::kCompressedPointer) {
+ if (NeedsPoisoning(access.load_sensitivity)) {
NodeProperties::ChangeOp(node, machine()->PoisonedLoad(type));
} else {
NodeProperties::ChangeOp(node, machine()->Load(type));
@@ -556,9 +581,7 @@ void MemoryOptimizer::VisitLoadField(Node* node, AllocationState const* state) {
Node* offset = jsgraph()->IntPtrConstant(access.offset - access.tag());
node->InsertInput(graph()->zone(), 1, offset);
MachineType type = access.machine_type;
- if (NeedsPoisoning(access.load_sensitivity) &&
- type.representation() != MachineRepresentation::kTaggedPointer &&
- type.representation() != MachineRepresentation::kCompressedPointer) {
+ if (NeedsPoisoning(access.load_sensitivity)) {
NodeProperties::ChangeOp(node, machine()->PoisonedLoad(type));
} else {
NodeProperties::ChangeOp(node, machine()->Load(type));
diff --git a/deps/v8/src/compiler/memory-optimizer.h b/deps/v8/src/compiler/memory-optimizer.h
index 71f33fa3d7..a663bf07ed 100644
--- a/deps/v8/src/compiler/memory-optimizer.h
+++ b/deps/v8/src/compiler/memory-optimizer.h
@@ -118,7 +118,6 @@ class MemoryOptimizer final {
void VisitNode(Node*, AllocationState const*);
void VisitAllocateRaw(Node*, AllocationState const*);
void VisitCall(Node*, AllocationState const*);
- void VisitCallWithCallerSavedRegisters(Node*, AllocationState const*);
void VisitLoadFromObject(Node*, AllocationState const*);
void VisitLoadElement(Node*, AllocationState const*);
void VisitLoadField(Node*, AllocationState const*);
@@ -142,6 +141,11 @@ class MemoryOptimizer final {
bool NeedsPoisoning(LoadSensitivity load_sensitivity) const;
+ // Returns true if the AllocationType of the current AllocateRaw node that we
+ // are visiting needs to be updated to kOld, due to propagation of tenuring
+ // from outer to inner allocations.
+ bool AllocationTypeNeedsUpdateToOld(Node* const user, const Edge edge);
+
AllocationState const* empty_state() const { return empty_state_; }
Graph* graph() const;
Isolate* isolate() const;
diff --git a/deps/v8/src/compiler/node-matchers.h b/deps/v8/src/compiler/node-matchers.h
index 7c0c702e3f..20698f4cd6 100644
--- a/deps/v8/src/compiler/node-matchers.h
+++ b/deps/v8/src/compiler/node-matchers.h
@@ -761,66 +761,6 @@ struct V8_EXPORT_PRIVATE DiamondMatcher
Node* if_false_;
};
-template <class BinopMatcher, IrOpcode::Value expected_opcode>
-struct WasmStackCheckMatcher {
- explicit WasmStackCheckMatcher(Node* compare) : compare_(compare) {}
-
- bool Matched() {
- if (compare_->opcode() != expected_opcode) return false;
- BinopMatcher m(compare_);
- return MatchedInternal(m.left(), m.right());
- }
-
- private:
- bool MatchedInternal(const typename BinopMatcher::LeftMatcher& l,
- const typename BinopMatcher::RightMatcher& r) {
- // In wasm, the stack check is performed by loading the value given by
- // the address of a field stored in the instance object. That object is
- // passed as a parameter.
- if (l.IsLoad() && r.IsLoadStackPointer()) {
- LoadMatcher<LoadMatcher<NodeMatcher>> mleft(l.node());
- if (mleft.object().IsLoad() && mleft.index().Is(0) &&
- mleft.object().object().IsParameter()) {
- return true;
- }
- }
- return false;
- }
- Node* compare_;
-};
-
-template <class BinopMatcher, IrOpcode::Value expected_opcode>
-struct StackCheckMatcher {
- StackCheckMatcher(Isolate* isolate, Node* compare)
- : isolate_(isolate), compare_(compare) {
- DCHECK_NOT_NULL(isolate);
- }
- bool Matched() {
- // TODO(jgruber): Ideally, we could be more flexible here and also match the
- // same pattern with switched operands (i.e.: left is LoadStackPointer and
- // right is the js_stack_limit load). But to be correct in all cases, we'd
- // then have to invert the outcome of the stack check comparison.
- if (compare_->opcode() != expected_opcode) return false;
- BinopMatcher m(compare_);
- return MatchedInternal(m.left(), m.right());
- }
-
- private:
- bool MatchedInternal(const typename BinopMatcher::LeftMatcher& l,
- const typename BinopMatcher::RightMatcher& r) {
- if (l.IsLoad() && r.IsLoadStackPointer()) {
- LoadMatcher<ExternalReferenceMatcher> mleft(l.node());
- ExternalReference js_stack_limit =
- ExternalReference::address_of_stack_limit(isolate_);
- if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) return true;
- }
- return false;
- }
-
- Isolate* isolate_;
- Node* compare_;
-};
-
} // namespace compiler
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/compiler/node-properties.cc b/deps/v8/src/compiler/node-properties.cc
index 1e00ec00f4..7ba3a59f6f 100644
--- a/deps/v8/src/compiler/node-properties.cc
+++ b/deps/v8/src/compiler/node-properties.cc
@@ -380,7 +380,10 @@ base::Optional<MapRef> NodeProperties::GetJSCreateMap(JSHeapBroker* broker,
ObjectRef target = mtarget.Ref(broker);
JSFunctionRef newtarget = mnewtarget.Ref(broker).AsJSFunction();
if (newtarget.map().has_prototype_slot() && newtarget.has_initial_map()) {
- if (broker->mode() == JSHeapBroker::kSerializing) newtarget.Serialize();
+ if (!newtarget.serialized()) {
+ TRACE_BROKER_MISSING(broker, "initial map on " << newtarget);
+ return base::nullopt;
+ }
MapRef initial_map = newtarget.initial_map();
if (initial_map.GetConstructor().equals(target)) {
DCHECK(target.AsJSFunction().map().is_constructor());
@@ -449,7 +452,7 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMapsUnsafe(
}
case IrOpcode::kJSCreatePromise: {
if (IsSame(receiver, effect)) {
- *maps_return = ZoneHandleSet<Map>(broker->native_context()
+ *maps_return = ZoneHandleSet<Map>(broker->target_native_context()
.promise_function()
.initial_map()
.object());
diff --git a/deps/v8/src/compiler/node.cc b/deps/v8/src/compiler/node.cc
index 7688379e9f..525ce33c84 100644
--- a/deps/v8/src/compiler/node.cc
+++ b/deps/v8/src/compiler/node.cc
@@ -22,10 +22,12 @@ Node::OutOfLineInputs* Node::OutOfLineInputs::New(Zone* zone, int capacity) {
void Node::OutOfLineInputs::ExtractFrom(Use* old_use_ptr, Node** old_input_ptr,
int count) {
+ DCHECK_GE(count, 0);
// Extract the inputs from the old use and input pointers and copy them
// to this out-of-line-storage.
Use* new_use_ptr = reinterpret_cast<Use*>(this) - 1;
Node** new_input_ptr = inputs();
+ CHECK_IMPLIES(count > 0, Use::InputIndexField::is_valid(count - 1));
for (int current = 0; current < count; current++) {
new_use_ptr->bit_field_ =
Use::InputIndexField::encode(current) | Use::InlineField::encode(false);
@@ -51,6 +53,8 @@ void Node::OutOfLineInputs::ExtractFrom(Use* old_use_ptr, Node** old_input_ptr,
Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
Node* const* inputs, bool has_extensible_inputs) {
+ DCHECK_GE(input_count, 0);
+
Node** input_ptr;
Use* use_ptr;
Node* node;
@@ -102,6 +106,8 @@ Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
}
// Initialize the input pointers and the uses.
+ CHECK_IMPLIES(input_count > 0,
+ Use::InputIndexField::is_valid(input_count - 1));
for (int current = 0; current < input_count; ++current) {
Node* to = *inputs++;
input_ptr[current] = to;
@@ -137,19 +143,20 @@ void Node::AppendInput(Zone* zone, Node* new_to) {
DCHECK_NOT_NULL(zone);
DCHECK_NOT_NULL(new_to);
- int inline_count = InlineCountField::decode(bit_field_);
- int inline_capacity = InlineCapacityField::decode(bit_field_);
+ int const inline_count = InlineCountField::decode(bit_field_);
+ int const inline_capacity = InlineCapacityField::decode(bit_field_);
if (inline_count < inline_capacity) {
// Append inline input.
bit_field_ = InlineCountField::update(bit_field_, inline_count + 1);
*GetInputPtr(inline_count) = new_to;
Use* use = GetUsePtr(inline_count);
+ STATIC_ASSERT(InlineCapacityField::kMax <= Use::InputIndexField::kMax);
use->bit_field_ = Use::InputIndexField::encode(inline_count) |
Use::InlineField::encode(true);
new_to->AppendUse(use);
} else {
// Append out-of-line input.
- int input_count = InputCount();
+ int const input_count = InputCount();
OutOfLineInputs* outline = nullptr;
if (inline_count != kOutlineMarker) {
// switch to out of line inputs.
@@ -172,6 +179,7 @@ void Node::AppendInput(Zone* zone, Node* new_to) {
outline->count_++;
*GetInputPtr(input_count) = new_to;
Use* use = GetUsePtr(input_count);
+ CHECK(Use::InputIndexField::is_valid(input_count));
use->bit_field_ = Use::InputIndexField::encode(input_count) |
Use::InlineField::encode(false);
new_to->AppendUse(use);
@@ -336,9 +344,13 @@ Node::Node(NodeId id, const Operator* op, int inline_count, int inline_capacity)
bit_field_(IdField::encode(id) | InlineCountField::encode(inline_count) |
InlineCapacityField::encode(inline_capacity)),
first_use_(nullptr) {
+ // Check that the id didn't overflow.
+ STATIC_ASSERT(IdField::kMax < std::numeric_limits<NodeId>::max());
+ CHECK(IdField::is_valid(id));
+
// Inputs must either be out of line or within the inline capacity.
- DCHECK_GE(kMaxInlineCapacity, inline_capacity);
DCHECK(inline_count == kOutlineMarker || inline_count <= inline_capacity);
+ DCHECK_LE(inline_capacity, kMaxInlineCapacity);
}
diff --git a/deps/v8/src/compiler/node.h b/deps/v8/src/compiler/node.h
index d7daca38ef..76ea4bb1a9 100644
--- a/deps/v8/src/compiler/node.h
+++ b/deps/v8/src/compiler/node.h
@@ -201,9 +201,7 @@ class V8_EXPORT_PRIVATE Node final {
}
using InlineField = BitField<bool, 0, 1>;
- using InputIndexField = BitField<unsigned, 1, 17>;
- // Leaving some space in the bitset in case we ever decide to record
- // the output index.
+ using InputIndexField = BitField<unsigned, 1, 31>;
};
//============================================================================
@@ -291,7 +289,6 @@ class V8_EXPORT_PRIVATE Node final {
using InlineCountField = BitField<unsigned, 24, 4>;
using InlineCapacityField = BitField<unsigned, 28, 4>;
static const int kOutlineMarker = InlineCountField::kMax;
- static const int kMaxInlineCount = InlineCountField::kMax - 1;
static const int kMaxInlineCapacity = InlineCapacityField::kMax - 1;
const Operator* op_;
diff --git a/deps/v8/src/compiler/opcodes.h b/deps/v8/src/compiler/opcodes.h
index d621e23e3a..fe45d9276a 100644
--- a/deps/v8/src/compiler/opcodes.h
+++ b/deps/v8/src/compiler/opcodes.h
@@ -66,7 +66,6 @@
V(ObjectId) \
V(TypedObjectState) \
V(Call) \
- V(CallWithCallerSavedRegisters) \
V(Parameter) \
V(OsrValue) \
V(LoopExit) \
@@ -204,6 +203,7 @@
V(JSForInEnumerate) \
V(JSForInNext) \
V(JSForInPrepare) \
+ V(JSGetIterator) \
V(JSLoadMessage) \
V(JSStoreMessage) \
V(JSLoadModule) \
@@ -617,15 +617,33 @@
V(Float64Mod) \
V(Float64Pow)
-#define MACHINE_WORD64_ATOMIC_OP_LIST(V) \
- V(Word64AtomicLoad) \
- V(Word64AtomicStore) \
- V(Word64AtomicAdd) \
- V(Word64AtomicSub) \
- V(Word64AtomicAnd) \
- V(Word64AtomicOr) \
- V(Word64AtomicXor) \
- V(Word64AtomicExchange) \
+#define MACHINE_ATOMIC_OP_LIST(V) \
+ V(Word32AtomicLoad) \
+ V(Word32AtomicStore) \
+ V(Word32AtomicExchange) \
+ V(Word32AtomicCompareExchange) \
+ V(Word32AtomicAdd) \
+ V(Word32AtomicSub) \
+ V(Word32AtomicAnd) \
+ V(Word32AtomicOr) \
+ V(Word32AtomicXor) \
+ V(Word32AtomicPairLoad) \
+ V(Word32AtomicPairStore) \
+ V(Word32AtomicPairAdd) \
+ V(Word32AtomicPairSub) \
+ V(Word32AtomicPairAnd) \
+ V(Word32AtomicPairOr) \
+ V(Word32AtomicPairXor) \
+ V(Word32AtomicPairExchange) \
+ V(Word32AtomicPairCompareExchange) \
+ V(Word64AtomicLoad) \
+ V(Word64AtomicStore) \
+ V(Word64AtomicAdd) \
+ V(Word64AtomicSub) \
+ V(Word64AtomicAnd) \
+ V(Word64AtomicOr) \
+ V(Word64AtomicXor) \
+ V(Word64AtomicExchange) \
V(Word64AtomicCompareExchange)
#define MACHINE_OP_LIST(V) \
@@ -637,7 +655,7 @@
MACHINE_FLOAT32_UNOP_LIST(V) \
MACHINE_FLOAT64_BINOP_LIST(V) \
MACHINE_FLOAT64_UNOP_LIST(V) \
- MACHINE_WORD64_ATOMIC_OP_LIST(V) \
+ MACHINE_ATOMIC_OP_LIST(V) \
V(AbortCSAAssert) \
V(DebugBreak) \
V(Comment) \
@@ -656,6 +674,8 @@
V(BitcastTaggedSignedToWord) \
V(BitcastWordToTagged) \
V(BitcastWordToTaggedSigned) \
+ V(BitcastWord32ToCompressedSigned) \
+ V(BitcastCompressedSignedToWord32) \
V(TruncateFloat64ToWord32) \
V(ChangeFloat32ToFloat64) \
V(ChangeFloat64ToInt32) \
@@ -702,7 +722,6 @@
V(TaggedPoisonOnSpeculation) \
V(Word32PoisonOnSpeculation) \
V(Word64PoisonOnSpeculation) \
- V(LoadStackPointer) \
V(LoadFramePointer) \
V(LoadParentFramePointer) \
V(UnalignedLoad) \
@@ -716,30 +735,13 @@
V(ProtectedLoad) \
V(ProtectedStore) \
V(MemoryBarrier) \
- V(Word32AtomicLoad) \
- V(Word32AtomicStore) \
- V(Word32AtomicExchange) \
- V(Word32AtomicCompareExchange) \
- V(Word32AtomicAdd) \
- V(Word32AtomicSub) \
- V(Word32AtomicAnd) \
- V(Word32AtomicOr) \
- V(Word32AtomicXor) \
- V(Word32AtomicPairLoad) \
- V(Word32AtomicPairStore) \
- V(Word32AtomicPairAdd) \
- V(Word32AtomicPairSub) \
- V(Word32AtomicPairAnd) \
- V(Word32AtomicPairOr) \
- V(Word32AtomicPairXor) \
- V(Word32AtomicPairExchange) \
- V(Word32AtomicPairCompareExchange) \
V(SignExtendWord8ToInt32) \
V(SignExtendWord16ToInt32) \
V(SignExtendWord8ToInt64) \
V(SignExtendWord16ToInt64) \
V(SignExtendWord32ToInt64) \
- V(UnsafePointerAdd)
+ V(UnsafePointerAdd) \
+ V(StackPointerGreaterThan)
#define MACHINE_SIMD_OP_LIST(V) \
V(F64x2Splat) \
@@ -747,6 +749,12 @@
V(F64x2ReplaceLane) \
V(F64x2Abs) \
V(F64x2Neg) \
+ V(F64x2Add) \
+ V(F64x2Sub) \
+ V(F64x2Mul) \
+ V(F64x2Div) \
+ V(F64x2Min) \
+ V(F64x2Max) \
V(F64x2Eq) \
V(F64x2Ne) \
V(F64x2Lt) \
@@ -764,6 +772,7 @@
V(F32x4AddHoriz) \
V(F32x4Sub) \
V(F32x4Mul) \
+ V(F32x4Div) \
V(F32x4Min) \
V(F32x4Max) \
V(F32x4Eq) \
@@ -781,11 +790,15 @@
V(I64x2Add) \
V(I64x2Sub) \
V(I64x2Mul) \
+ V(I64x2MinS) \
+ V(I64x2MaxS) \
V(I64x2Eq) \
V(I64x2Ne) \
V(I64x2GtS) \
V(I64x2GeS) \
V(I64x2ShrU) \
+ V(I64x2MinU) \
+ V(I64x2MaxU) \
V(I64x2GtU) \
V(I64x2GeU) \
V(I32x4Splat) \
diff --git a/deps/v8/src/compiler/operator-properties.cc b/deps/v8/src/compiler/operator-properties.cc
index 959e743369..1fcc12291d 100644
--- a/deps/v8/src/compiler/operator-properties.cc
+++ b/deps/v8/src/compiler/operator-properties.cc
@@ -54,6 +54,7 @@ bool OperatorProperties::NeedsExactContext(const Operator* op) {
case IrOpcode::kJSStackCheck:
case IrOpcode::kJSStoreGlobal:
case IrOpcode::kJSStoreMessage:
+ case IrOpcode::kJSGetIterator:
return false;
case IrOpcode::kJSCallRuntime:
@@ -237,6 +238,9 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSPerformPromiseThen:
case IrOpcode::kJSObjectIsArray:
case IrOpcode::kJSRegExpTest:
+
+ // Iterator protocol operations
+ case IrOpcode::kJSGetIterator:
return true;
default:
diff --git a/deps/v8/src/compiler/per-isolate-compiler-cache.h b/deps/v8/src/compiler/per-isolate-compiler-cache.h
index b715950c0c..f4f7438128 100644
--- a/deps/v8/src/compiler/per-isolate-compiler-cache.h
+++ b/deps/v8/src/compiler/per-isolate-compiler-cache.h
@@ -19,41 +19,41 @@ namespace compiler {
class ObjectData;
-// This class serves as a per-isolate container of data that should be
-// persisted between compiler runs. For now it stores the code builtins
-// so they are not serialized on each compiler run.
+// This class serves as a container of data that should persist across all
+// (optimizing) compiler runs in an isolate. For now it stores serialized data
+// for various common objects such as builtins, so that these objects don't have
+// to be serialized in each compilation job. See JSHeapBroker::InitializeRefsMap
+// for details.
class PerIsolateCompilerCache : public ZoneObject {
public:
explicit PerIsolateCompilerCache(Zone* zone)
: zone_(zone), refs_snapshot_(nullptr) {}
- RefsMap* GetSnapshot() { return refs_snapshot_; }
+ bool HasSnapshot() const { return refs_snapshot_ != nullptr; }
+ RefsMap* GetSnapshot() {
+ DCHECK(HasSnapshot());
+ return refs_snapshot_;
+ }
void SetSnapshot(RefsMap* refs) {
- DCHECK_NULL(refs_snapshot_);
+ DCHECK(!HasSnapshot());
DCHECK(!refs->IsEmpty());
refs_snapshot_ = new (zone_) RefsMap(refs, zone_);
+ DCHECK(HasSnapshot());
}
- bool HasSnapshot() const { return refs_snapshot_; }
-
Zone* zone() const { return zone_; }
static void Setup(Isolate* isolate) {
- if (isolate->compiler_cache()) return;
-
- // The following zone is supposed to contain compiler-related objects
- // that should live through all compilations, as opposed to the
- // broker_zone which holds per-compilation data. It's not meant for
- // per-compilation or heap broker data.
- Zone* compiler_zone = new Zone(isolate->allocator(), "Compiler zone");
- PerIsolateCompilerCache* compiler_cache =
- new (compiler_zone) PerIsolateCompilerCache(compiler_zone);
- isolate->set_compiler_utils(compiler_cache, compiler_zone);
+ if (isolate->compiler_cache() == nullptr) {
+ Zone* zone = new Zone(isolate->allocator(), "Compiler zone");
+ PerIsolateCompilerCache* cache = new (zone) PerIsolateCompilerCache(zone);
+ isolate->set_compiler_utils(cache, zone);
+ }
+ DCHECK_NOT_NULL(isolate->compiler_cache());
}
private:
Zone* const zone_;
-
RefsMap* refs_snapshot_;
};
diff --git a/deps/v8/src/compiler/pipeline.cc b/deps/v8/src/compiler/pipeline.cc
index eb060b71e1..8b2f424789 100644
--- a/deps/v8/src/compiler/pipeline.cc
+++ b/deps/v8/src/compiler/pipeline.cc
@@ -110,6 +110,9 @@ class PipelineData {
may_have_unverifiable_graph_(false),
zone_stats_(zone_stats),
pipeline_statistics_(pipeline_statistics),
+ roots_relative_addressing_enabled_(
+ !isolate->serializer_enabled() &&
+ !isolate->IsGeneratingEmbeddedBuiltins()),
graph_zone_scope_(zone_stats_, ZONE_NAME),
graph_zone_(graph_zone_scope_.zone()),
instruction_zone_scope_(zone_stats_, ZONE_NAME),
@@ -173,12 +176,12 @@ class PipelineData {
// For CodeStubAssembler and machine graph testing entry point.
PipelineData(ZoneStats* zone_stats, OptimizedCompilationInfo* info,
- Isolate* isolate, Graph* graph, Schedule* schedule,
- SourcePositionTable* source_positions,
+ Isolate* isolate, AccountingAllocator* allocator, Graph* graph,
+ Schedule* schedule, SourcePositionTable* source_positions,
NodeOriginTable* node_origins, JumpOptimizationInfo* jump_opt,
const AssemblerOptions& assembler_options)
: isolate_(isolate),
- allocator_(isolate->allocator()),
+ allocator_(allocator),
info_(info),
debug_name_(info_->GetDebugName()),
zone_stats_(zone_stats),
@@ -320,6 +323,13 @@ class PipelineData {
return assembler_options_;
}
+ size_t* address_of_max_unoptimized_frame_height() {
+ return &max_unoptimized_frame_height_;
+ }
+ size_t max_unoptimized_frame_height() const {
+ return max_unoptimized_frame_height_;
+ }
+
CodeTracer* GetCodeTracer() const {
return wasm_engine_ == nullptr ? isolate_->GetCodeTracer()
: wasm_engine_->GetCodeTracer();
@@ -434,7 +444,8 @@ class PipelineData {
codegen_zone(), frame(), linkage, sequence(), info(), isolate(),
osr_helper_, start_source_position_, jump_optimization_info_,
info()->GetPoisoningMitigationLevel(), assembler_options_,
- info_->builtin_index(), std::move(buffer));
+ info_->builtin_index(), max_unoptimized_frame_height(),
+ std::move(buffer));
}
void BeginPhaseKind(const char* phase_kind_name) {
@@ -451,6 +462,10 @@ class PipelineData {
const char* debug_name() const { return debug_name_.get(); }
+ bool roots_relative_addressing_enabled() {
+ return roots_relative_addressing_enabled_;
+ }
+
private:
Isolate* const isolate_;
wasm::WasmEngine* const wasm_engine_ = nullptr;
@@ -468,6 +483,7 @@ class PipelineData {
CodeGenerator* code_generator_ = nullptr;
Typer* typer_ = nullptr;
Typer::Flags typer_flags_ = Typer::kNoFlags;
+ bool roots_relative_addressing_enabled_ = false;
// All objects in the following group of fields are allocated in graph_zone_.
// They are all set to nullptr when the graph_zone_ is destroyed.
@@ -516,6 +532,11 @@ class PipelineData {
JumpOptimizationInfo* jump_optimization_info_ = nullptr;
AssemblerOptions assembler_options_;
+ // The maximal combined height of all inlined frames in their unoptimized
+ // state. Calculated during instruction selection, applied during code
+ // generation.
+ size_t max_unoptimized_frame_height_ = 0;
+
DISALLOW_COPY_AND_ASSIGN(PipelineData);
};
@@ -893,9 +914,7 @@ PipelineCompilationJob::PipelineCompilationJob(
// Note that the OptimizedCompilationInfo is not initialized at the time
// we pass it to the CompilationJob constructor, but it is not
// dereferenced there.
- : OptimizedCompilationJob(
- function->GetIsolate()->stack_guard()->real_climit(),
- &compilation_info_, "TurboFan"),
+ : OptimizedCompilationJob(&compilation_info_, "TurboFan"),
zone_(function->GetIsolate()->allocator(), ZONE_NAME),
zone_stats_(function->GetIsolate()->allocator()),
compilation_info_(&zone_, function->GetIsolate(), shared_info, function),
@@ -973,11 +992,6 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
linkage_ = new (compilation_info()->zone()) Linkage(
Linkage::ComputeIncoming(compilation_info()->zone(), compilation_info()));
- if (!pipeline_.CreateGraph()) {
- if (isolate->has_pending_exception()) return FAILED; // Stack overflowed.
- return AbortOptimization(BailoutReason::kGraphBuildingFailed);
- }
-
if (compilation_info()->is_osr()) data_.InitializeOsrHelper();
// Make sure that we have generated the deopt entries code. This is in order
@@ -985,6 +999,11 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
// assembly.
Deoptimizer::EnsureCodeForDeoptimizationEntries(isolate);
+ if (!pipeline_.CreateGraph()) {
+ CHECK(!isolate->has_pending_exception());
+ return AbortOptimization(BailoutReason::kGraphBuildingFailed);
+ }
+
return SUCCEEDED;
}
@@ -1048,7 +1067,8 @@ void PipelineCompilationJob::RegisterWeakObjectsInOptimizedCode(
class WasmHeapStubCompilationJob final : public OptimizedCompilationJob {
public:
- WasmHeapStubCompilationJob(Isolate* isolate, CallDescriptor* call_descriptor,
+ WasmHeapStubCompilationJob(Isolate* isolate, wasm::WasmEngine* wasm_engine,
+ CallDescriptor* call_descriptor,
std::unique_ptr<Zone> zone, Graph* graph,
Code::Kind kind,
std::unique_ptr<char[]> debug_name,
@@ -1057,17 +1077,19 @@ class WasmHeapStubCompilationJob final : public OptimizedCompilationJob {
// Note that the OptimizedCompilationInfo is not initialized at the time
// we pass it to the CompilationJob constructor, but it is not
// dereferenced there.
- : OptimizedCompilationJob(isolate->stack_guard()->real_climit(), &info_,
- "TurboFan"),
+ : OptimizedCompilationJob(&info_, "TurboFan",
+ CompilationJob::State::kReadyToExecute),
debug_name_(std::move(debug_name)),
info_(CStrVector(debug_name_.get()), graph->zone(), kind),
call_descriptor_(call_descriptor),
- zone_stats_(isolate->allocator()),
+ zone_stats_(zone->allocator()),
zone_(std::move(zone)),
graph_(graph),
- data_(&zone_stats_, &info_, isolate, graph_, nullptr, source_positions,
+ data_(&zone_stats_, &info_, isolate, wasm_engine->allocator(), graph_,
+ nullptr, source_positions,
new (zone_.get()) NodeOriginTable(graph_), nullptr, options),
- pipeline_(&data_) {}
+ pipeline_(&data_),
+ wasm_engine_(wasm_engine) {}
~WasmHeapStubCompilationJob() = default;
@@ -1085,30 +1107,33 @@ class WasmHeapStubCompilationJob final : public OptimizedCompilationJob {
Graph* graph_;
PipelineData data_;
PipelineImpl pipeline_;
+ wasm::WasmEngine* wasm_engine_;
DISALLOW_COPY_AND_ASSIGN(WasmHeapStubCompilationJob);
};
// static
std::unique_ptr<OptimizedCompilationJob>
-Pipeline::NewWasmHeapStubCompilationJob(Isolate* isolate,
- CallDescriptor* call_descriptor,
- std::unique_ptr<Zone> zone,
- Graph* graph, Code::Kind kind,
- std::unique_ptr<char[]> debug_name,
- const AssemblerOptions& options,
- SourcePositionTable* source_positions) {
+Pipeline::NewWasmHeapStubCompilationJob(
+ Isolate* isolate, wasm::WasmEngine* wasm_engine,
+ CallDescriptor* call_descriptor, std::unique_ptr<Zone> zone, Graph* graph,
+ Code::Kind kind, std::unique_ptr<char[]> debug_name,
+ const AssemblerOptions& options, SourcePositionTable* source_positions) {
return base::make_unique<WasmHeapStubCompilationJob>(
- isolate, call_descriptor, std::move(zone), graph, kind,
+ isolate, wasm_engine, call_descriptor, std::move(zone), graph, kind,
std::move(debug_name), options, source_positions);
}
CompilationJob::Status WasmHeapStubCompilationJob::PrepareJobImpl(
Isolate* isolate) {
+ UNREACHABLE();
+}
+
+CompilationJob::Status WasmHeapStubCompilationJob::ExecuteJobImpl() {
std::unique_ptr<PipelineStatistics> pipeline_statistics;
if (FLAG_turbo_stats || FLAG_turbo_stats_nvp) {
pipeline_statistics.reset(new PipelineStatistics(
- &info_, isolate->GetTurboStatistics(), &zone_stats_));
+ &info_, wasm_engine_->GetOrCreateTurboStatistics(), &zone_stats_));
pipeline_statistics->BeginPhaseKind("V8.WasmStubCodegen");
}
if (info_.trace_turbo_json_enabled() || info_.trace_turbo_graph_enabled()) {
@@ -1130,10 +1155,6 @@ CompilationJob::Status WasmHeapStubCompilationJob::PrepareJobImpl(
<< "\", \"source\":\"\",\n\"phases\":[";
}
pipeline_.RunPrintAndVerify("V8.WasmMachineCode", true);
- return CompilationJob::SUCCEEDED;
-}
-
-CompilationJob::Status WasmHeapStubCompilationJob::ExecuteJobImpl() {
pipeline_.ComputeScheduledGraph();
if (pipeline_.SelectInstructionsAndAssemble(call_descriptor_)) {
return CompilationJob::SUCCEEDED;
@@ -1144,8 +1165,11 @@ CompilationJob::Status WasmHeapStubCompilationJob::ExecuteJobImpl() {
CompilationJob::Status WasmHeapStubCompilationJob::FinalizeJobImpl(
Isolate* isolate) {
Handle<Code> code;
- if (pipeline_.FinalizeCode(call_descriptor_).ToHandle(&code) &&
- pipeline_.CommitDependencies(code)) {
+ if (!pipeline_.FinalizeCode(call_descriptor_).ToHandle(&code)) {
+ V8::FatalProcessOutOfMemory(isolate,
+ "WasmHeapStubCompilationJob::FinalizeJobImpl");
+ }
+ if (pipeline_.CommitDependencies(code)) {
info_.SetCode(code);
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_opt_code) {
@@ -1177,14 +1201,14 @@ struct GraphBuilderPhase {
if (data->info()->is_bailout_on_uninitialized()) {
flags |= BytecodeGraphBuilderFlag::kBailoutOnUninitialized;
}
+
+ JSFunctionRef closure(data->broker(), data->info()->closure());
CallFrequency frequency(1.0f);
BuildGraphFromBytecode(
- data->broker(), temp_zone, data->info()->bytecode_array(),
- data->info()->shared_info(),
- handle(data->info()->closure()->feedback_vector(), data->isolate()),
+ data->broker(), temp_zone, closure.shared(), closure.feedback_vector(),
data->info()->osr_offset(), data->jsgraph(), frequency,
- data->source_positions(), data->native_context(),
- SourcePosition::kNotInlined, flags, &data->info()->tick_counter());
+ data->source_positions(), SourcePosition::kNotInlined, flags,
+ &data->info()->tick_counter());
}
};
@@ -1253,14 +1277,15 @@ struct InliningPhase {
// that need to live until code generation.
JSNativeContextSpecialization native_context_specialization(
&graph_reducer, data->jsgraph(), data->broker(), flags,
- data->native_context(), data->dependencies(), temp_zone, info->zone());
+ data->dependencies(), temp_zone, info->zone());
JSInliningHeuristic inlining(&graph_reducer,
data->info()->is_inlining_enabled()
? JSInliningHeuristic::kGeneralInlining
: JSInliningHeuristic::kRestrictedInlining,
temp_zone, data->info(), data->jsgraph(),
data->broker(), data->source_positions());
- JSIntrinsicLowering intrinsic_lowering(&graph_reducer, data->jsgraph());
+ JSIntrinsicLowering intrinsic_lowering(&graph_reducer, data->jsgraph(),
+ data->broker());
AddReducer(data, &graph_reducer, &dead_code_elimination);
AddReducer(data, &graph_reducer, &checkpoint_elimination);
AddReducer(data, &graph_reducer, &common_reducer);
@@ -1323,11 +1348,11 @@ struct UntyperPhase {
}
};
-struct SerializeStandardObjectsPhase {
- static const char* phase_name() { return "V8.TFSerializeStandardObjects"; }
+struct HeapBrokerInitializationPhase {
+ static const char* phase_name() { return "V8.TFHeapBrokerInitialization"; }
void Run(PipelineData* data, Zone* temp_zone) {
- data->broker()->SerializeStandardObjects();
+ data->broker()->InitializeAndStartSerializing(data->native_context());
}
};
@@ -1349,11 +1374,8 @@ struct CopyMetadataForConcurrentCompilePhase {
}
};
-// TODO(turbofan): Move all calls from CopyMetaDataForConcurrentCompilePhase
-// here. Also all the calls to Serialize* methods that are currently sprinkled
-// over inlining will move here as well.
struct SerializationPhase {
- static const char* phase_name() { return "V8.TFSerializeBytecode"; }
+ static const char* phase_name() { return "V8.TFSerialization"; }
void Run(PipelineData* data, Zone* temp_zone) {
SerializerForBackgroundCompilationFlags flags;
@@ -1488,7 +1510,8 @@ struct GenericLoweringPhase {
GraphReducer graph_reducer(temp_zone, data->graph(),
&data->info()->tick_counter(),
data->jsgraph()->Dead());
- JSGenericLowering generic_lowering(data->jsgraph(), &graph_reducer);
+ JSGenericLowering generic_lowering(data->jsgraph(), &graph_reducer,
+ data->broker());
AddReducer(data, &graph_reducer, &generic_lowering);
graph_reducer.ReduceGraph();
}
@@ -1613,7 +1636,8 @@ struct LoadEliminationPhase {
&data->info()->tick_counter(),
data->jsgraph()->Dead());
BranchElimination branch_condition_elimination(&graph_reducer,
- data->jsgraph(), temp_zone);
+ data->jsgraph(), temp_zone,
+ BranchElimination::kEARLY);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common(), temp_zone);
RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone);
@@ -1849,6 +1873,7 @@ struct InstructionSelectionPhase {
? InstructionSelector::kEnableSwitchJumpTable
: InstructionSelector::kDisableSwitchJumpTable,
&data->info()->tick_counter(),
+ data->address_of_max_unoptimized_frame_height(),
data->info()->is_source_positions_enabled()
? InstructionSelector::kAllSourcePositions
: InstructionSelector::kCallSourcePositions,
@@ -1856,10 +1881,9 @@ struct InstructionSelectionPhase {
FLAG_turbo_instruction_scheduling
? InstructionSelector::kEnableScheduling
: InstructionSelector::kDisableScheduling,
- !data->isolate() || data->isolate()->serializer_enabled() ||
- data->isolate()->IsGeneratingEmbeddedBuiltins()
- ? InstructionSelector::kDisableRootsRelativeAddressing
- : InstructionSelector::kEnableRootsRelativeAddressing,
+ data->roots_relative_addressing_enabled()
+ ? InstructionSelector::kEnableRootsRelativeAddressing
+ : InstructionSelector::kDisableRootsRelativeAddressing,
data->info()->GetPoisoningMitigationLevel(),
data->info()->trace_turbo_json_enabled()
? InstructionSelector::kEnableTraceTurboJson
@@ -2175,12 +2199,10 @@ bool PipelineImpl::CreateGraph() {
data->node_origins()->AddDecorator();
}
+ data->broker()->SetTargetNativeContextRef(data->native_context());
if (FLAG_concurrent_inlining) {
- data->broker()->StartSerializing();
- Run<SerializeStandardObjectsPhase>();
+ Run<HeapBrokerInitializationPhase>();
Run<SerializationPhase>();
- } else {
- data->broker()->SetNativeContextRef();
}
Run<GraphBuilderPhase>();
@@ -2219,8 +2241,7 @@ bool PipelineImpl::CreateGraph() {
Run<CopyMetadataForConcurrentCompilePhase>();
data->broker()->StopSerializing();
} else {
- data->broker()->StartSerializing();
- Run<SerializeStandardObjectsPhase>();
+ Run<HeapBrokerInitializationPhase>();
Run<CopyMetadataForConcurrentCompilePhase>();
data->broker()->StopSerializing();
}
@@ -2356,8 +2377,8 @@ MaybeHandle<Code> Pipeline::GenerateCodeForCodeStub(
JumpOptimizationInfo jump_opt;
bool should_optimize_jumps =
isolate->serializer_enabled() && FLAG_turbo_rewrite_far_jumps;
- PipelineData data(&zone_stats, &info, isolate, graph, nullptr,
- source_positions, &node_origins,
+ PipelineData data(&zone_stats, &info, isolate, isolate->allocator(), graph,
+ nullptr, source_positions, &node_origins,
should_optimize_jumps ? &jump_opt : nullptr, options);
data.set_verify_graph(FLAG_verify_csa);
std::unique_ptr<PipelineStatistics> pipeline_statistics;
@@ -2402,10 +2423,10 @@ MaybeHandle<Code> Pipeline::GenerateCodeForCodeStub(
// First run code generation on a copy of the pipeline, in order to be able to
// repeat it for jump optimization. The first run has to happen on a temporary
// pipeline to avoid deletion of zones on the main pipeline.
- PipelineData second_data(&zone_stats, &info, isolate, data.graph(),
- data.schedule(), data.source_positions(),
- data.node_origins(), data.jump_optimization_info(),
- options);
+ PipelineData second_data(&zone_stats, &info, isolate, isolate->allocator(),
+ data.graph(), data.schedule(),
+ data.source_positions(), data.node_origins(),
+ data.jump_optimization_info(), options);
second_data.set_verify_graph(FLAG_verify_csa);
PipelineImpl second_pipeline(&second_data);
second_pipeline.SelectInstructionsAndAssemble(call_descriptor);
@@ -2421,6 +2442,23 @@ MaybeHandle<Code> Pipeline::GenerateCodeForCodeStub(
return code;
}
+struct BlockStartsAsJSON {
+ const ZoneVector<int>* block_starts;
+};
+
+std::ostream& operator<<(std::ostream& out, const BlockStartsAsJSON& s) {
+ out << ", \"blockIdToOffset\": {";
+ bool need_comma = false;
+ for (size_t i = 0; i < s.block_starts->size(); ++i) {
+ if (need_comma) out << ", ";
+ int offset = (*s.block_starts)[i];
+ out << "\"" << i << "\":" << offset;
+ need_comma = true;
+ }
+ out << "},";
+ return out;
+}
+
// static
wasm::WasmCompilationResult Pipeline::GenerateCodeForWasmNativeStub(
wasm::WasmEngine* wasm_engine, CallDescriptor* call_descriptor,
@@ -2491,7 +2529,9 @@ wasm::WasmCompilationResult Pipeline::GenerateCodeForWasmNativeStub(
if (info.trace_turbo_json_enabled()) {
TurboJsonFile json_of(&info, std::ios_base::app);
- json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\",\"data\":\"";
+ json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\""
+ << BlockStartsAsJSON{&code_generator->block_starts()}
+ << "\"data\":\"";
#ifdef ENABLE_DISASSEMBLER
std::stringstream disassembler_stream;
Disassembler::Decode(
@@ -2551,8 +2591,8 @@ MaybeHandle<Code> Pipeline::GenerateCodeForTesting(
// Construct a pipeline for scheduling and code generation.
ZoneStats zone_stats(isolate->allocator());
NodeOriginTable* node_positions = new (info->zone()) NodeOriginTable(graph);
- PipelineData data(&zone_stats, info, isolate, graph, schedule, nullptr,
- node_positions, nullptr, options);
+ PipelineData data(&zone_stats, info, isolate, isolate->allocator(), graph,
+ schedule, nullptr, node_positions, nullptr, options);
std::unique_ptr<PipelineStatistics> pipeline_statistics;
if (FLAG_turbo_stats || FLAG_turbo_stats_nvp) {
pipeline_statistics.reset(new PipelineStatistics(
@@ -2684,7 +2724,9 @@ void Pipeline::GenerateCodeForWasmFunction(
if (data.info()->trace_turbo_json_enabled()) {
TurboJsonFile json_of(data.info(), std::ios_base::app);
- json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\",\"data\":\"";
+ json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\""
+ << BlockStartsAsJSON{&code_generator->block_starts()}
+ << "\"data\":\"";
#ifdef ENABLE_DISASSEMBLER
std::stringstream disassembler_stream;
Disassembler::Decode(
@@ -2888,7 +2930,7 @@ void PipelineImpl::VerifyGeneratedCodeIsIdempotent() {
}
struct InstructionStartsAsJSON {
- const ZoneVector<int>* instr_starts;
+ const ZoneVector<TurbolizerInstructionStartInfo>* instr_starts;
};
std::ostream& operator<<(std::ostream& out, const InstructionStartsAsJSON& s) {
@@ -2896,14 +2938,39 @@ std::ostream& operator<<(std::ostream& out, const InstructionStartsAsJSON& s) {
bool need_comma = false;
for (size_t i = 0; i < s.instr_starts->size(); ++i) {
if (need_comma) out << ", ";
- int offset = (*s.instr_starts)[i];
- out << "\"" << i << "\":" << offset;
+ const TurbolizerInstructionStartInfo& info = (*s.instr_starts)[i];
+ out << "\"" << i << "\": {";
+ out << "\"gap\": " << info.gap_pc_offset;
+ out << ", \"arch\": " << info.arch_instr_pc_offset;
+ out << ", \"condition\": " << info.condition_pc_offset;
+ out << "}";
need_comma = true;
}
out << "}";
return out;
}
+struct TurbolizerCodeOffsetsInfoAsJSON {
+ const TurbolizerCodeOffsetsInfo* offsets_info;
+};
+
+std::ostream& operator<<(std::ostream& out,
+ const TurbolizerCodeOffsetsInfoAsJSON& s) {
+ out << ", \"codeOffsetsInfo\": {";
+ out << "\"codeStartRegisterCheck\": "
+ << s.offsets_info->code_start_register_check << ", ";
+ out << "\"deoptCheck\": " << s.offsets_info->deopt_check << ", ";
+ out << "\"initPoison\": " << s.offsets_info->init_poison << ", ";
+ out << "\"blocksStart\": " << s.offsets_info->blocks_start << ", ";
+ out << "\"outOfLineCode\": " << s.offsets_info->out_of_line_code << ", ";
+ out << "\"deoptimizationExits\": " << s.offsets_info->deoptimization_exits
+ << ", ";
+ out << "\"pools\": " << s.offsets_info->pools << ", ";
+ out << "\"jumpTables\": " << s.offsets_info->jump_tables;
+ out << "}";
+ return out;
+}
+
void PipelineImpl::AssembleCode(Linkage* linkage,
std::unique_ptr<AssemblerBuffer> buffer) {
PipelineData* data = this->data_;
@@ -2915,30 +2982,15 @@ void PipelineImpl::AssembleCode(Linkage* linkage,
TurboJsonFile json_of(data->info(), std::ios_base::app);
json_of << "{\"name\":\"code generation\""
<< ", \"type\":\"instructions\""
- << InstructionStartsAsJSON{&data->code_generator()->instr_starts()};
+ << InstructionStartsAsJSON{&data->code_generator()->instr_starts()}
+ << TurbolizerCodeOffsetsInfoAsJSON{
+ &data->code_generator()->offsets_info()};
json_of << "},\n";
}
data->DeleteInstructionZone();
data->EndPhaseKind();
}
-struct BlockStartsAsJSON {
- const ZoneVector<int>* block_starts;
-};
-
-std::ostream& operator<<(std::ostream& out, const BlockStartsAsJSON& s) {
- out << ", \"blockIdToOffset\": {";
- bool need_comma = false;
- for (size_t i = 0; i < s.block_starts->size(); ++i) {
- if (need_comma) out << ", ";
- int offset = (*s.block_starts)[i];
- out << "\"" << i << "\":" << offset;
- need_comma = true;
- }
- out << "},";
- return out;
-}
-
MaybeHandle<Code> PipelineImpl::FinalizeCode(bool retire_broker) {
PipelineData* data = this->data_;
if (data->broker() && retire_broker) {
diff --git a/deps/v8/src/compiler/pipeline.h b/deps/v8/src/compiler/pipeline.h
index 6898faaad0..3707bfb06e 100644
--- a/deps/v8/src/compiler/pipeline.h
+++ b/deps/v8/src/compiler/pipeline.h
@@ -61,9 +61,10 @@ class Pipeline : public AllStatic {
// Returns a new compilation job for a wasm heap stub.
static std::unique_ptr<OptimizedCompilationJob> NewWasmHeapStubCompilationJob(
- Isolate* isolate, CallDescriptor* call_descriptor,
- std::unique_ptr<Zone> zone, Graph* graph, Code::Kind kind,
- std::unique_ptr<char[]> debug_name, const AssemblerOptions& options,
+ Isolate* isolate, wasm::WasmEngine* wasm_engine,
+ CallDescriptor* call_descriptor, std::unique_ptr<Zone> zone, Graph* graph,
+ Code::Kind kind, std::unique_ptr<char[]> debug_name,
+ const AssemblerOptions& options,
SourcePositionTable* source_positions = nullptr);
// Run the pipeline on a machine graph and generate code.
diff --git a/deps/v8/src/compiler/processed-feedback.h b/deps/v8/src/compiler/processed-feedback.h
new file mode 100644
index 0000000000..17829863de
--- /dev/null
+++ b/deps/v8/src/compiler/processed-feedback.h
@@ -0,0 +1,226 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_COMPILER_PROCESSED_FEEDBACK_H_
+#define V8_COMPILER_PROCESSED_FEEDBACK_H_
+
+#include "src/compiler/heap-refs.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class BinaryOperationFeedback;
+class CallFeedback;
+class CompareOperationFeedback;
+class ElementAccessFeedback;
+class ForInFeedback;
+class GlobalAccessFeedback;
+class InstanceOfFeedback;
+class NamedAccessFeedback;
+
+class ProcessedFeedback : public ZoneObject {
+ public:
+ enum Kind {
+ kInsufficient,
+ kBinaryOperation,
+ kCall,
+ kCompareOperation,
+ kElementAccess,
+ kForIn,
+ kGlobalAccess,
+ kInstanceOf,
+ kNamedAccess,
+ };
+ Kind kind() const { return kind_; }
+
+ FeedbackSlotKind slot_kind() const { return slot_kind_; }
+ bool IsInsufficient() const { return kind() == kInsufficient; }
+
+ BinaryOperationFeedback const& AsBinaryOperation() const;
+ CallFeedback const& AsCall() const;
+ CompareOperationFeedback const& AsCompareOperation() const;
+ ElementAccessFeedback const& AsElementAccess() const;
+ ForInFeedback const& AsForIn() const;
+ GlobalAccessFeedback const& AsGlobalAccess() const;
+ InstanceOfFeedback const& AsInstanceOf() const;
+ NamedAccessFeedback const& AsNamedAccess() const;
+
+ protected:
+ ProcessedFeedback(Kind kind, FeedbackSlotKind slot_kind);
+
+ private:
+ Kind const kind_;
+ FeedbackSlotKind const slot_kind_;
+};
+
+class InsufficientFeedback final : public ProcessedFeedback {
+ public:
+ explicit InsufficientFeedback(FeedbackSlotKind slot_kind);
+};
+
+class GlobalAccessFeedback : public ProcessedFeedback {
+ public:
+ GlobalAccessFeedback(PropertyCellRef cell, FeedbackSlotKind slot_kind);
+ GlobalAccessFeedback(ContextRef script_context, int slot_index,
+ bool immutable, FeedbackSlotKind slot_kind);
+ explicit GlobalAccessFeedback(FeedbackSlotKind slot_kind); // Megamorphic
+
+ bool IsMegamorphic() const;
+
+ bool IsPropertyCell() const;
+ PropertyCellRef property_cell() const;
+
+ bool IsScriptContextSlot() const;
+ ContextRef script_context() const;
+ int slot_index() const;
+ bool immutable() const;
+
+ base::Optional<ObjectRef> GetConstantHint() const;
+
+ private:
+ base::Optional<ObjectRef> const cell_or_context_;
+ int const index_and_immutable_;
+};
+
+class KeyedAccessMode {
+ public:
+ static KeyedAccessMode FromNexus(FeedbackNexus const& nexus);
+
+ AccessMode access_mode() const;
+ bool IsLoad() const;
+ bool IsStore() const;
+ KeyedAccessLoadMode load_mode() const;
+ KeyedAccessStoreMode store_mode() const;
+
+ private:
+ AccessMode const access_mode_;
+ union LoadStoreMode {
+ LoadStoreMode(KeyedAccessLoadMode load_mode);
+ LoadStoreMode(KeyedAccessStoreMode store_mode);
+ KeyedAccessLoadMode load_mode;
+ KeyedAccessStoreMode store_mode;
+ } const load_store_mode_;
+
+ KeyedAccessMode(AccessMode access_mode, KeyedAccessLoadMode load_mode);
+ KeyedAccessMode(AccessMode access_mode, KeyedAccessStoreMode store_mode);
+};
+
+class ElementAccessFeedback : public ProcessedFeedback {
+ public:
+ ElementAccessFeedback(Zone* zone, KeyedAccessMode const& keyed_mode,
+ FeedbackSlotKind slot_kind);
+
+ KeyedAccessMode keyed_mode() const;
+
+ // A transition group is a target and a possibly empty set of sources that can
+ // transition to the target. It is represented as a non-empty vector with the
+ // target at index 0.
+ using TransitionGroup = ZoneVector<Handle<Map>>;
+ ZoneVector<TransitionGroup> const& transition_groups() const;
+
+ bool HasOnlyStringMaps(JSHeapBroker* broker) const;
+
+ void AddGroup(TransitionGroup&& group);
+
+ // Refine {this} by trying to restrict it to the maps in {inferred_maps}. A
+ // transition group's target is kept iff it is in {inferred_maps} or if more
+ // than one of its sources is in {inferred_maps}. Here's an (unrealistic)
+ // example showing all the possible situations:
+ //
+ // inferred_maps = [a0, a2, c1, c2, d1, e0, e1]
+ //
+ // Groups before: Groups after:
+ // [a0, a1, a2] [a0, a2]
+ // [b0]
+ // [c0, c1, c2, c3] [c0, c1, c2]
+ // [d0, d1] [d1]
+ // [e0, e1] [e0, e1]
+ //
+ ElementAccessFeedback const& Refine(
+ ZoneVector<Handle<Map>> const& inferred_maps, Zone* zone) const;
+
+ private:
+ KeyedAccessMode const keyed_mode_;
+ ZoneVector<TransitionGroup> transition_groups_;
+};
+
+class NamedAccessFeedback : public ProcessedFeedback {
+ public:
+ NamedAccessFeedback(NameRef const& name, ZoneVector<Handle<Map>> const& maps,
+ FeedbackSlotKind slot_kind);
+
+ NameRef const& name() const { return name_; }
+ ZoneVector<Handle<Map>> const& maps() const { return maps_; }
+
+ private:
+ NameRef const name_;
+ ZoneVector<Handle<Map>> const maps_;
+};
+
+class CallFeedback : public ProcessedFeedback {
+ public:
+ CallFeedback(base::Optional<HeapObjectRef> target, float frequency,
+ SpeculationMode mode, FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(kCall, slot_kind),
+ target_(target),
+ frequency_(frequency),
+ mode_(mode) {}
+
+ base::Optional<HeapObjectRef> target() const { return target_; }
+ float frequency() const { return frequency_; }
+ SpeculationMode speculation_mode() const { return mode_; }
+
+ private:
+ base::Optional<HeapObjectRef> const target_;
+ float const frequency_;
+ SpeculationMode const mode_;
+};
+
+template <class T, ProcessedFeedback::Kind K>
+class SingleValueFeedback : public ProcessedFeedback {
+ public:
+ explicit SingleValueFeedback(T value, FeedbackSlotKind slot_kind)
+ : ProcessedFeedback(K, slot_kind), value_(value) {
+ DCHECK(
+ (K == kBinaryOperation && slot_kind == FeedbackSlotKind::kBinaryOp) ||
+ (K == kCompareOperation && slot_kind == FeedbackSlotKind::kCompareOp) ||
+ (K == kForIn && slot_kind == FeedbackSlotKind::kForIn) ||
+ (K == kInstanceOf && slot_kind == FeedbackSlotKind::kInstanceOf));
+ }
+
+ T value() const { return value_; }
+
+ private:
+ T const value_;
+};
+
+class InstanceOfFeedback
+ : public SingleValueFeedback<base::Optional<JSObjectRef>,
+ ProcessedFeedback::kInstanceOf> {
+ using SingleValueFeedback::SingleValueFeedback;
+};
+
+class BinaryOperationFeedback
+ : public SingleValueFeedback<BinaryOperationHint,
+ ProcessedFeedback::kBinaryOperation> {
+ using SingleValueFeedback::SingleValueFeedback;
+};
+
+class CompareOperationFeedback
+ : public SingleValueFeedback<CompareOperationHint,
+ ProcessedFeedback::kCompareOperation> {
+ using SingleValueFeedback::SingleValueFeedback;
+};
+
+class ForInFeedback
+ : public SingleValueFeedback<ForInHint, ProcessedFeedback::kForIn> {
+ using SingleValueFeedback::SingleValueFeedback;
+};
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
+
+#endif // V8_COMPILER_PROCESSED_FEEDBACK_H_
diff --git a/deps/v8/src/compiler/property-access-builder.cc b/deps/v8/src/compiler/property-access-builder.cc
index 99a06ef874..6c33ae227f 100644
--- a/deps/v8/src/compiler/property-access-builder.cc
+++ b/deps/v8/src/compiler/property-access-builder.cc
@@ -61,7 +61,7 @@ bool PropertyAccessBuilder::TryBuildStringCheck(
// Monormorphic string access (ignoring the fact that there are multiple
// String maps).
*receiver = *effect =
- graph()->NewNode(simplified()->CheckString(VectorSlotPair()), *receiver,
+ graph()->NewNode(simplified()->CheckString(FeedbackSource()), *receiver,
*effect, control);
return true;
}
@@ -74,7 +74,7 @@ bool PropertyAccessBuilder::TryBuildNumberCheck(
if (HasOnlyNumberMaps(broker, maps)) {
// Monomorphic number access (we also deal with Smis here).
*receiver = *effect =
- graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), *receiver,
+ graph()->NewNode(simplified()->CheckNumber(FeedbackSource()), *receiver,
*effect, control);
return true;
}
@@ -151,14 +151,6 @@ MachineRepresentation PropertyAccessBuilder::ConvertRepresentation(
Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
NameRef const& name, PropertyAccessInfo const& access_info,
Node* receiver) {
- // TODO(neis): Eliminate FastPropertyAt call below by doing the lookup during
- // acccess info computation. Requires extra care in the case where the
- // receiver is the holder.
- AllowCodeDependencyChange dependency_change_;
- AllowHandleAllocation handle_allocation_;
- AllowHandleDereference handle_dereference_;
- AllowHeapAllocation heap_allocation_;
-
if (!access_info.IsDataConstant()) return nullptr;
// First, determine if we have a constant holder to load from.
@@ -174,17 +166,21 @@ Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
MapRef receiver_map = m.Ref(broker()).map();
if (std::find_if(access_info.receiver_maps().begin(),
access_info.receiver_maps().end(), [&](Handle<Map> map) {
- return map.equals(receiver_map.object());
+ return MapRef(broker(), map).equals(receiver_map);
}) == access_info.receiver_maps().end()) {
// The map of the receiver is not in the feedback, let us bail out.
return nullptr;
}
- holder = Handle<JSObject>::cast(m.Value());
+ holder = m.Ref(broker()).AsJSObject().object();
}
- Handle<Object> value = JSObject::FastPropertyAt(
- holder, access_info.field_representation(), access_info.field_index());
- return jsgraph()->Constant(value);
+ JSObjectRef holder_ref(broker(), holder);
+ base::Optional<ObjectRef> value = holder_ref.GetOwnDataProperty(
+ access_info.field_representation(), access_info.field_index());
+ if (!value.has_value()) {
+ return nullptr;
+ }
+ return jsgraph()->Constant(*value);
}
Node* PropertyAccessBuilder::BuildLoadDataField(
@@ -203,12 +199,10 @@ Node* PropertyAccessBuilder::BuildLoadDataField(
Node* storage = ResolveHolder(access_info, receiver);
if (!field_index.is_inobject()) {
storage = *effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
+ simplified()->LoadField(
+ AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer()),
storage, *effect, *control);
}
- PropertyConstness constness = access_info.IsDataConstant()
- ? PropertyConstness::kConst
- : PropertyConstness::kMutable;
FieldAccess field_access = {
kTaggedBase,
field_index.offset(),
@@ -218,7 +212,7 @@ Node* PropertyAccessBuilder::BuildLoadDataField(
MachineType::TypeForRepresentation(field_representation),
kFullWriteBarrier,
LoadSensitivity::kCritical,
- constness};
+ access_info.GetConstFieldInfo()};
if (field_representation == MachineRepresentation::kFloat64) {
if (!field_index.is_inobject() || !FLAG_unbox_double_fields) {
FieldAccess const storage_access = {
@@ -230,7 +224,7 @@ Node* PropertyAccessBuilder::BuildLoadDataField(
MachineType::TypeCompressedTaggedPointer(),
kPointerWriteBarrier,
LoadSensitivity::kCritical,
- constness};
+ access_info.GetConstFieldInfo()};
storage = *effect = graph()->NewNode(
simplified()->LoadField(storage_access), storage, *effect, *control);
field_access.offset = HeapNumber::kValueOffset;
diff --git a/deps/v8/src/compiler/raw-machine-assembler.cc b/deps/v8/src/compiler/raw-machine-assembler.cc
index 277c89c932..e399b9c4f6 100644
--- a/deps/v8/src/compiler/raw-machine-assembler.cc
+++ b/deps/v8/src/compiler/raw-machine-assembler.cc
@@ -77,7 +77,7 @@ Node* RawMachineAssembler::OptimizedAllocate(
size);
}
-Schedule* RawMachineAssembler::Export() {
+Schedule* RawMachineAssembler::ExportForTest() {
// Compute the correct codegen order.
DCHECK(schedule_->rpo_order()->empty());
if (FLAG_trace_turbo_scheduler) {
@@ -106,6 +106,7 @@ Graph* RawMachineAssembler::ExportForOptimization() {
StdoutStream{} << *schedule_;
}
schedule_->EnsureCFGWellFormedness();
+ OptimizeControlFlow(schedule_, graph(), common());
Scheduler::ComputeSpecialRPO(zone(), schedule_);
if (FLAG_trace_turbo_scheduler) {
PrintF("--- SCHEDULE BEFORE GRAPH CREATION -------------------------\n");
@@ -117,6 +118,99 @@ Graph* RawMachineAssembler::ExportForOptimization() {
return graph();
}
+void RawMachineAssembler::OptimizeControlFlow(Schedule* schedule, Graph* graph,
+ CommonOperatorBuilder* common) {
+ for (bool changed = true; changed;) {
+ changed = false;
+ for (size_t i = 0; i < schedule->all_blocks()->size(); ++i) {
+ BasicBlock* block = (*schedule->all_blocks())[i];
+ if (block == nullptr) continue;
+
+ // Short-circuit a goto if the succeeding block is not a control-flow
+ // merge. This is not really useful on it's own since graph construction
+ // has the same effect, but combining blocks improves the pattern-match on
+ // their structure below.
+ if (block->control() == BasicBlock::kGoto) {
+ DCHECK_EQ(block->SuccessorCount(), 1);
+ BasicBlock* successor = block->SuccessorAt(0);
+ if (successor->PredecessorCount() == 1) {
+ DCHECK_EQ(successor->PredecessorAt(0), block);
+ for (Node* node : *successor) {
+ schedule->SetBlockForNode(nullptr, node);
+ schedule->AddNode(block, node);
+ }
+ block->set_control(successor->control());
+ Node* control_input = successor->control_input();
+ block->set_control_input(control_input);
+ if (control_input) {
+ schedule->SetBlockForNode(block, control_input);
+ }
+ if (successor->deferred()) block->set_deferred(true);
+ block->ClearSuccessors();
+ schedule->MoveSuccessors(successor, block);
+ schedule->ClearBlockById(successor->id());
+ changed = true;
+ --i;
+ continue;
+ }
+ }
+ // Block-cloning in the simple case where a block consists only of a phi
+ // node and a branch on that phi. This just duplicates the branch block
+ // for each predecessor, replacing the phi node with the corresponding phi
+ // input.
+ if (block->control() == BasicBlock::kBranch && block->NodeCount() == 1) {
+ Node* phi = block->NodeAt(0);
+ if (phi->opcode() != IrOpcode::kPhi) continue;
+ Node* branch = block->control_input();
+ DCHECK_EQ(branch->opcode(), IrOpcode::kBranch);
+ if (NodeProperties::GetValueInput(branch, 0) != phi) continue;
+ if (phi->UseCount() != 1) continue;
+ DCHECK_EQ(phi->op()->ValueInputCount(), block->PredecessorCount());
+
+ // Turn projection blocks into normal blocks.
+ DCHECK_EQ(block->SuccessorCount(), 2);
+ BasicBlock* true_block = block->SuccessorAt(0);
+ BasicBlock* false_block = block->SuccessorAt(1);
+ DCHECK_EQ(true_block->NodeAt(0)->opcode(), IrOpcode::kIfTrue);
+ DCHECK_EQ(false_block->NodeAt(0)->opcode(), IrOpcode::kIfFalse);
+ (*true_block->begin())->Kill();
+ true_block->RemoveNode(true_block->begin());
+ (*false_block->begin())->Kill();
+ false_block->RemoveNode(false_block->begin());
+ true_block->ClearPredecessors();
+ false_block->ClearPredecessors();
+
+ size_t arity = block->PredecessorCount();
+ for (size_t i = 0; i < arity; ++i) {
+ BasicBlock* predecessor = block->PredecessorAt(i);
+ predecessor->ClearSuccessors();
+ if (block->deferred()) predecessor->set_deferred(true);
+ Node* branch_clone = graph->CloneNode(branch);
+ int phi_input = static_cast<int>(i);
+ NodeProperties::ReplaceValueInput(
+ branch_clone, NodeProperties::GetValueInput(phi, phi_input), 0);
+ BasicBlock* new_true_block = schedule->NewBasicBlock();
+ BasicBlock* new_false_block = schedule->NewBasicBlock();
+ new_true_block->AddNode(
+ graph->NewNode(common->IfTrue(), branch_clone));
+ new_false_block->AddNode(
+ graph->NewNode(common->IfFalse(), branch_clone));
+ schedule->AddGoto(new_true_block, true_block);
+ schedule->AddGoto(new_false_block, false_block);
+ DCHECK_EQ(predecessor->control(), BasicBlock::kGoto);
+ predecessor->set_control(BasicBlock::kNone);
+ schedule->AddBranch(predecessor, branch_clone, new_true_block,
+ new_false_block);
+ }
+ branch->Kill();
+ schedule->ClearBlockById(block->id());
+ changed = true;
+ continue;
+ }
+ }
+ }
+}
+
void RawMachineAssembler::MakeReschedulable() {
std::vector<Node*> block_final_control(schedule_->all_blocks_.size());
std::vector<Node*> block_final_effect(schedule_->all_blocks_.size());
@@ -619,8 +713,10 @@ Node* CallCFunctionImpl(
builder.AddReturn(return_type);
for (const auto& arg : args) builder.AddParam(arg.first);
- auto call_descriptor =
- Linkage::GetSimplifiedCDescriptor(rasm->zone(), builder.Build());
+ auto call_descriptor = Linkage::GetSimplifiedCDescriptor(
+ rasm->zone(), builder.Build(),
+ caller_saved_regs ? CallDescriptor::kCallerSavedRegisters
+ : CallDescriptor::kNoFlags);
if (caller_saved_regs) call_descriptor->set_save_fp_mode(mode);
@@ -631,10 +727,8 @@ Node* CallCFunctionImpl(
[](const RawMachineAssembler::CFunctionArg& arg) { return arg.second; });
auto common = rasm->common();
- return rasm->AddNode(
- caller_saved_regs ? common->CallWithCallerSavedRegisters(call_descriptor)
- : common->Call(call_descriptor),
- static_cast<int>(nodes.size()), nodes.begin());
+ return rasm->AddNode(common->Call(call_descriptor),
+ static_cast<int>(nodes.size()), nodes.begin());
}
} // namespace
diff --git a/deps/v8/src/compiler/raw-machine-assembler.h b/deps/v8/src/compiler/raw-machine-assembler.h
index 890c38c551..46940df44f 100644
--- a/deps/v8/src/compiler/raw-machine-assembler.h
+++ b/deps/v8/src/compiler/raw-machine-assembler.h
@@ -65,9 +65,10 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
CallDescriptor* call_descriptor() const { return call_descriptor_; }
PoisoningMitigationLevel poisoning_level() const { return poisoning_level_; }
- // Finalizes the schedule and exports it to be used for code generation. Note
- // that this RawMachineAssembler becomes invalid after export.
- Schedule* Export();
+ // Only used for tests: Finalizes the schedule and exports it to be used for
+ // code generation. Note that this RawMachineAssembler becomes invalid after
+ // export.
+ Schedule* ExportForTest();
// Finalizes the schedule and transforms it into a graph that's suitable for
// it to be used for Turbofan optimization and re-scheduling. Note that this
// RawMachineAssembler becomes invalid after export.
@@ -577,6 +578,9 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
Node* Word32PairSar(Node* low_word, Node* high_word, Node* shift) {
return AddNode(machine()->Word32PairSar(), low_word, high_word, shift);
}
+ Node* StackPointerGreaterThan(Node* value) {
+ return AddNode(machine()->StackPointerGreaterThan(), value);
+ }
#define INTPTR_BINOP(prefix, name) \
Node* IntPtr##name(Node* a, Node* b) { \
@@ -907,7 +911,6 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
}
// Stack operations.
- Node* LoadStackPointer() { return AddNode(machine()->LoadStackPointer()); }
Node* LoadFramePointer() { return AddNode(machine()->LoadFramePointer()); }
Node* LoadParentFramePointer() {
return AddNode(machine()->LoadParentFramePointer());
@@ -1091,6 +1094,9 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
Schedule* schedule() { return schedule_; }
size_t parameter_count() const { return call_descriptor_->ParameterCount(); }
+ static void OptimizeControlFlow(Schedule* schedule, Graph* graph,
+ CommonOperatorBuilder* common);
+
Isolate* isolate_;
Graph* graph_;
Schedule* schedule_;
diff --git a/deps/v8/src/compiler/representation-change.cc b/deps/v8/src/compiler/representation-change.cc
index 7a4577b799..fd0cbabe66 100644
--- a/deps/v8/src/compiler/representation-change.cc
+++ b/deps/v8/src/compiler/representation-change.cc
@@ -316,12 +316,12 @@ Node* RepresentationChanger::GetTaggedSignedRepresentationFor(
node = InsertChangeFloat64ToUint32(node);
op = simplified()->CheckedUint32ToTaggedSigned(use_info.feedback());
} else if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
- op = simplified()->CheckedFloat64ToInt32(
+ node = InsertCheckedFloat64ToInt32(
+ node,
output_type.Maybe(Type::MinusZero())
? CheckForMinusZeroMode::kCheckForMinusZero
: CheckForMinusZeroMode::kDontCheckForMinusZero,
- use_info.feedback());
- node = InsertConversion(node, op, use_node);
+ use_info.feedback(), use_node);
if (SmiValuesAre32Bits()) {
op = simplified()->ChangeInt32ToTagged();
} else {
@@ -333,14 +333,13 @@ Node* RepresentationChanger::GetTaggedSignedRepresentationFor(
}
} else if (output_rep == MachineRepresentation::kFloat32) {
if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
- op = machine()->ChangeFloat32ToFloat64();
- node = InsertConversion(node, op, use_node);
- op = simplified()->CheckedFloat64ToInt32(
+ node = InsertChangeFloat32ToFloat64(node);
+ node = InsertCheckedFloat64ToInt32(
+ node,
output_type.Maybe(Type::MinusZero())
? CheckForMinusZeroMode::kCheckForMinusZero
: CheckForMinusZeroMode::kDontCheckForMinusZero,
- use_info.feedback());
- node = InsertConversion(node, op, use_node);
+ use_info.feedback(), use_node);
if (SmiValuesAre32Bits()) {
op = simplified()->ChangeInt32ToTagged();
} else {
@@ -475,7 +474,7 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
} else if (output_rep == MachineRepresentation::kCompressedPointer) {
if (use_info.type_check() == TypeCheckKind::kBigInt &&
!output_type.Is(Type::BigInt())) {
- node = InsertChangeCompressedToTagged(node);
+ node = InsertChangeCompressedPointerToTaggedPointer(node);
op = simplified()->CheckBigInt(use_info.feedback());
} else {
op = machine()->ChangeCompressedPointerToTaggedPointer();
@@ -671,13 +670,48 @@ Node* RepresentationChanger::GetCompressedSignedRepresentationFor(
use_node, use_info);
op = machine()->ChangeTaggedSignedToCompressedSigned();
} else if (output_rep == MachineRepresentation::kFloat32) {
- node = GetTaggedSignedRepresentationFor(node, output_rep, output_type,
- use_node, use_info);
- op = machine()->ChangeTaggedSignedToCompressedSigned();
+ // float 32 -> float64 -> int32 -> Compressed signed
+ if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
+ node = InsertChangeFloat32ToFloat64(node);
+ node = InsertCheckedFloat64ToInt32(
+ node,
+ output_type.Maybe(Type::MinusZero())
+ ? CheckForMinusZeroMode::kCheckForMinusZero
+ : CheckForMinusZeroMode::kDontCheckForMinusZero,
+ use_info.feedback(), use_node);
+ op = simplified()->CheckedInt32ToCompressedSigned(use_info.feedback());
+ } else {
+ return TypeError(node, output_rep, output_type,
+ MachineRepresentation::kCompressedSigned);
+ }
} else if (output_rep == MachineRepresentation::kFloat64) {
- node = GetTaggedSignedRepresentationFor(node, output_rep, output_type,
- use_node, use_info);
- op = machine()->ChangeTaggedSignedToCompressedSigned();
+ if (output_type.Is(Type::Signed31())) {
+ // float64 -> int32 -> compressed signed
+ node = InsertChangeFloat64ToInt32(node);
+ op = simplified()->ChangeInt31ToCompressedSigned();
+ } else if (output_type.Is(Type::Signed32())) {
+ // float64 -> int32 -> compressed signed
+ node = InsertChangeFloat64ToInt32(node);
+ if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
+ op = simplified()->CheckedInt32ToCompressedSigned(use_info.feedback());
+ } else {
+ return TypeError(node, output_rep, output_type,
+ MachineRepresentation::kCompressedSigned);
+ }
+ } else if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
+ node = InsertCheckedFloat64ToInt32(
+ node,
+ output_type.Maybe(Type::MinusZero())
+ ? CheckForMinusZeroMode::kCheckForMinusZero
+ : CheckForMinusZeroMode::kDontCheckForMinusZero,
+ use_info.feedback(), use_node);
+ op = simplified()->CheckedInt32ToCompressedSigned(use_info.feedback());
+ } else {
+ // TODO(v8:8977): specialize here and below. Missing the unsigned case.
+ node = GetTaggedSignedRepresentationFor(node, output_rep, output_type,
+ use_node, use_info);
+ op = machine()->ChangeTaggedSignedToCompressedSigned();
+ }
} else {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kCompressedSigned);
@@ -830,20 +864,17 @@ Node* RepresentationChanger::GetFloat32RepresentationFor(
}
} else if (output_rep == MachineRepresentation::kCompressed) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedToTagged();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedToTagged(node);
return GetFloat32RepresentationFor(node, MachineRepresentation::kTagged,
output_type, truncation);
} else if (output_rep == MachineRepresentation::kCompressedSigned) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedSignedToTaggedSigned();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedSignedToTaggedSigned(node);
return GetFloat32RepresentationFor(
node, MachineRepresentation::kTaggedSigned, output_type, truncation);
} else if (output_rep == MachineRepresentation::kCompressedPointer) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedPointerToTaggedPointer();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedPointerToTaggedPointer(node);
return GetFloat32RepresentationFor(
node, MachineRepresentation::kTaggedPointer, output_type, truncation);
} else if (output_rep == MachineRepresentation::kFloat64) {
@@ -948,21 +979,18 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
}
} else if (output_rep == MachineRepresentation::kCompressed) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedToTagged();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedToTagged(node);
return GetFloat64RepresentationFor(node, MachineRepresentation::kTagged,
output_type, use_node, use_info);
} else if (output_rep == MachineRepresentation::kCompressedSigned) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedSignedToTaggedSigned();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedSignedToTaggedSigned(node);
return GetFloat64RepresentationFor(node,
MachineRepresentation::kTaggedSigned,
output_type, use_node, use_info);
} else if (output_rep == MachineRepresentation::kCompressedPointer) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedPointerToTaggedPointer();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedPointerToTaggedPointer(node);
return GetFloat64RepresentationFor(node,
MachineRepresentation::kTaggedPointer,
output_type, use_node, use_info);
@@ -1116,8 +1144,7 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
}
} else if (output_rep == MachineRepresentation::kCompressed) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedToTagged();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedToTagged(node);
return GetWord32RepresentationFor(node, MachineRepresentation::kTagged,
output_type, use_node, use_info);
} else if (output_rep == MachineRepresentation::kCompressedSigned) {
@@ -1125,16 +1152,14 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
if (output_type.Is(Type::SignedSmall())) {
op = simplified()->ChangeCompressedSignedToInt32();
} else {
- op = machine()->ChangeCompressedSignedToTaggedSigned();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedSignedToTaggedSigned(node);
return GetWord32RepresentationFor(node,
MachineRepresentation::kTaggedSigned,
output_type, use_node, use_info);
}
} else if (output_rep == MachineRepresentation::kCompressedPointer) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedPointerToTaggedPointer();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedPointerToTaggedPointer(node);
return GetWord32RepresentationFor(node,
MachineRepresentation::kTaggedPointer,
output_type, use_node, use_info);
@@ -1253,20 +1278,17 @@ Node* RepresentationChanger::GetBitRepresentationFor(
jsgraph()->Int32Constant(0));
} else if (output_rep == MachineRepresentation::kCompressed) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedToTagged();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedToTagged(node);
return GetBitRepresentationFor(node, MachineRepresentation::kTagged,
output_type);
} else if (output_rep == MachineRepresentation::kCompressedSigned) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedSignedToTaggedSigned();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedSignedToTaggedSigned(node);
return GetBitRepresentationFor(node, MachineRepresentation::kTaggedSigned,
output_type);
} else if (output_rep == MachineRepresentation::kCompressedPointer) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedPointerToTaggedPointer();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedPointerToTaggedPointer(node);
return GetBitRepresentationFor(node, MachineRepresentation::kTaggedPointer,
output_type);
} else if (IsWord(output_rep)) {
@@ -1423,21 +1445,18 @@ Node* RepresentationChanger::GetWord64RepresentationFor(
}
} else if (output_rep == MachineRepresentation::kCompressed) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedToTagged();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedToTagged(node);
return GetWord64RepresentationFor(node, MachineRepresentation::kTagged,
output_type, use_node, use_info);
} else if (output_rep == MachineRepresentation::kCompressedSigned) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedSignedToTaggedSigned();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedSignedToTaggedSigned(node);
return GetWord64RepresentationFor(node,
MachineRepresentation::kTaggedSigned,
output_type, use_node, use_info);
} else if (output_rep == MachineRepresentation::kCompressedPointer) {
// TODO(v8:8977): Specialise here
- op = machine()->ChangeCompressedPointerToTaggedPointer();
- node = jsgraph()->graph()->NewNode(op, node);
+ node = InsertChangeCompressedPointerToTaggedPointer(node);
return GetWord64RepresentationFor(node,
MachineRepresentation::kTaggedPointer,
output_type, use_node, use_info);
@@ -1741,11 +1760,30 @@ Node* RepresentationChanger::InsertTruncateInt64ToInt32(Node* node) {
return jsgraph()->graph()->NewNode(machine()->TruncateInt64ToInt32(), node);
}
+Node* RepresentationChanger::InsertChangeCompressedPointerToTaggedPointer(
+ Node* node) {
+ return jsgraph()->graph()->NewNode(
+ machine()->ChangeCompressedPointerToTaggedPointer(), node);
+}
+
+Node* RepresentationChanger::InsertChangeCompressedSignedToTaggedSigned(
+ Node* node) {
+ return jsgraph()->graph()->NewNode(
+ machine()->ChangeCompressedSignedToTaggedSigned(), node);
+}
+
Node* RepresentationChanger::InsertChangeCompressedToTagged(Node* node) {
return jsgraph()->graph()->NewNode(machine()->ChangeCompressedToTagged(),
node);
}
+Node* RepresentationChanger::InsertCheckedFloat64ToInt32(
+ Node* node, CheckForMinusZeroMode check, const FeedbackSource& feedback,
+ Node* use_node) {
+ return InsertConversion(
+ node, simplified()->CheckedFloat64ToInt32(check, feedback), use_node);
+}
+
Isolate* RepresentationChanger::isolate() const { return broker_->isolate(); }
} // namespace compiler
diff --git a/deps/v8/src/compiler/representation-change.h b/deps/v8/src/compiler/representation-change.h
index d338667603..43e85085ba 100644
--- a/deps/v8/src/compiler/representation-change.h
+++ b/deps/v8/src/compiler/representation-change.h
@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_
#define V8_COMPILER_REPRESENTATION_CHANGE_H_
+#include "src/compiler/feedback-source.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/simplified-operator.h"
@@ -165,7 +166,7 @@ class UseInfo {
public:
UseInfo(MachineRepresentation representation, Truncation truncation,
TypeCheckKind type_check = TypeCheckKind::kNone,
- const VectorSlotPair& feedback = VectorSlotPair())
+ const FeedbackSource& feedback = FeedbackSource())
: representation_(representation),
truncation_(truncation),
type_check_(type_check),
@@ -176,7 +177,7 @@ class UseInfo {
static UseInfo TruncatingWord64() {
return UseInfo(MachineRepresentation::kWord64, Truncation::Word64());
}
- static UseInfo CheckedBigIntTruncatingWord64(const VectorSlotPair& feedback) {
+ static UseInfo CheckedBigIntTruncatingWord64(const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kWord64, Truncation::Word64(),
TypeCheckKind::kBigInt, feedback);
}
@@ -219,59 +220,59 @@ class UseInfo {
// Possibly deoptimizing conversions.
static UseInfo CheckedHeapObjectAsTaggedPointer(
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
TypeCheckKind::kHeapObject, feedback);
}
- static UseInfo CheckedBigIntAsTaggedPointer(const VectorSlotPair& feedback) {
+ static UseInfo CheckedBigIntAsTaggedPointer(const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
TypeCheckKind::kBigInt, feedback);
}
static UseInfo CheckedSignedSmallAsTaggedSigned(
- const VectorSlotPair& feedback,
+ const FeedbackSource& feedback,
IdentifyZeros identify_zeros = kDistinguishZeros) {
return UseInfo(MachineRepresentation::kTaggedSigned,
Truncation::Any(identify_zeros), TypeCheckKind::kSignedSmall,
feedback);
}
static UseInfo CheckedSignedSmallAsWord32(IdentifyZeros identify_zeros,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kWord32,
Truncation::Any(identify_zeros), TypeCheckKind::kSignedSmall,
feedback);
}
static UseInfo CheckedSigned32AsWord32(IdentifyZeros identify_zeros,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kWord32,
Truncation::Any(identify_zeros), TypeCheckKind::kSigned32,
feedback);
}
static UseInfo CheckedSigned64AsWord64(IdentifyZeros identify_zeros,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kWord64,
Truncation::Any(identify_zeros), TypeCheckKind::kSigned64,
feedback);
}
static UseInfo CheckedNumberAsFloat64(IdentifyZeros identify_zeros,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kFloat64,
Truncation::Any(identify_zeros), TypeCheckKind::kNumber,
feedback);
}
- static UseInfo CheckedNumberAsWord32(const VectorSlotPair& feedback) {
+ static UseInfo CheckedNumberAsWord32(const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
TypeCheckKind::kNumber, feedback);
}
static UseInfo CheckedNumberOrOddballAsFloat64(
- IdentifyZeros identify_zeros, const VectorSlotPair& feedback) {
+ IdentifyZeros identify_zeros, const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kFloat64,
Truncation::Any(identify_zeros),
TypeCheckKind::kNumberOrOddball, feedback);
}
static UseInfo CheckedNumberOrOddballAsWord32(
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
TypeCheckKind::kNumberOrOddball, feedback);
}
@@ -297,13 +298,13 @@ class UseInfo {
? CheckForMinusZeroMode::kDontCheckForMinusZero
: CheckForMinusZeroMode::kCheckForMinusZero;
}
- const VectorSlotPair& feedback() const { return feedback_; }
+ const FeedbackSource& feedback() const { return feedback_; }
private:
MachineRepresentation representation_;
Truncation truncation_;
TypeCheckKind type_check_;
- VectorSlotPair feedback_;
+ FeedbackSource feedback_;
};
// Contains logic related to changing the representation of values for constants
@@ -395,7 +396,12 @@ class V8_EXPORT_PRIVATE RepresentationChanger final {
Node* InsertChangeTaggedSignedToInt32(Node* node);
Node* InsertChangeTaggedToFloat64(Node* node);
Node* InsertChangeUint32ToFloat64(Node* node);
+ Node* InsertChangeCompressedPointerToTaggedPointer(Node* node);
+ Node* InsertChangeCompressedSignedToTaggedSigned(Node* node);
Node* InsertChangeCompressedToTagged(Node* node);
+ Node* InsertCheckedFloat64ToInt32(Node* node, CheckForMinusZeroMode check,
+ const FeedbackSource& feedback,
+ Node* use_node);
Node* InsertConversion(Node* node, const Operator* op, Node* use_node);
Node* InsertTruncateInt64ToInt32(Node* node);
Node* InsertUnconditionalDeopt(Node* node, DeoptimizeReason reason);
diff --git a/deps/v8/src/compiler/schedule.cc b/deps/v8/src/compiler/schedule.cc
index 84d74b4685..3b335f9712 100644
--- a/deps/v8/src/compiler/schedule.cc
+++ b/deps/v8/src/compiler/schedule.cc
@@ -163,6 +163,11 @@ BasicBlock* Schedule::GetBlockById(BasicBlock::Id block_id) {
return all_blocks_[block_id.ToSize()];
}
+void Schedule::ClearBlockById(BasicBlock::Id block_id) {
+ DCHECK(block_id.ToSize() < all_blocks_.size());
+ all_blocks_[block_id.ToSize()] = nullptr;
+}
+
bool Schedule::SameBasicBlock(Node* a, Node* b) const {
BasicBlock* block = this->block(a);
return block != nullptr && block == this->block(b);
@@ -210,7 +215,6 @@ bool IsPotentiallyThrowingCall(IrOpcode::Value opcode) {
JS_OP_LIST(BUILD_BLOCK_JS_CASE)
#undef BUILD_BLOCK_JS_CASE
case IrOpcode::kCall:
- case IrOpcode::kCallWithCallerSavedRegisters:
return true;
default:
return false;
@@ -321,9 +325,6 @@ void Schedule::EnsureCFGWellFormedness() {
if (block != end_) {
EnsureSplitEdgeForm(block);
}
- if (block->deferred()) {
- EnsureDeferredCodeSingleEntryPoint(block);
- }
}
}
@@ -356,6 +357,7 @@ void Schedule::EliminateRedundantPhiNodes() {
}
if (!inputs_equal) continue;
node->ReplaceUses(first_input);
+ node->Kill();
block->RemoveNode(block->begin() + node_pos);
--node_pos;
reached_fixed_point = false;
@@ -376,43 +378,6 @@ void Schedule::EnsureSplitEdgeForm(BasicBlock* block) {
#endif
}
-void Schedule::EnsureDeferredCodeSingleEntryPoint(BasicBlock* block) {
- // If a deferred block has multiple predecessors, they have to
- // all be deferred. Otherwise, we can run into a situation where a range
- // that spills only in deferred blocks inserts its spill in the block, but
- // other ranges need moves inserted by ResolveControlFlow in the predecessors,
- // which may clobber the register of this range.
- // To ensure that, when a deferred block has multiple predecessors, and some
- // are not deferred, we add a non-deferred block to collect all such edges.
-
- DCHECK(block->deferred() && block->PredecessorCount() > 1);
- bool all_deferred = true;
- for (auto current_pred = block->predecessors().begin();
- current_pred != block->predecessors().end(); ++current_pred) {
- BasicBlock* pred = *current_pred;
- if (!pred->deferred()) {
- all_deferred = false;
- break;
- }
- }
-
- if (all_deferred) return;
- BasicBlock* merger = NewBasicBlock();
- merger->set_control(BasicBlock::kGoto);
- merger->successors().push_back(block);
- for (auto current_pred = block->predecessors().begin();
- current_pred != block->predecessors().end(); ++current_pred) {
- BasicBlock* pred = *current_pred;
- merger->predecessors().push_back(pred);
- pred->successors().clear();
- pred->successors().push_back(merger);
- }
- merger->set_deferred(false);
- block->predecessors().clear();
- block->predecessors().push_back(merger);
- MovePhis(block, merger);
-}
-
void Schedule::MovePhis(BasicBlock* from, BasicBlock* to) {
for (size_t i = 0; i < from->NodeCount();) {
Node* node = from->NodeAt(i);
@@ -481,6 +446,7 @@ void Schedule::SetBlockForNode(BasicBlock* block, Node* node) {
std::ostream& operator<<(std::ostream& os, const Schedule& s) {
for (BasicBlock* block :
((s.RpoBlockCount() == 0) ? *s.all_blocks() : *s.rpo_order())) {
+ if (block == nullptr) continue;
if (block->rpo_number() == -1) {
os << "--- BLOCK id:" << block->id().ToInt();
} else {
diff --git a/deps/v8/src/compiler/schedule.h b/deps/v8/src/compiler/schedule.h
index aae2cd3ad8..ea42951d50 100644
--- a/deps/v8/src/compiler/schedule.h
+++ b/deps/v8/src/compiler/schedule.h
@@ -200,6 +200,7 @@ class V8_EXPORT_PRIVATE Schedule final : public NON_EXPORTED_BASE(ZoneObject) {
bool IsScheduled(Node* node);
BasicBlock* GetBlockById(BasicBlock::Id block_id);
+ void ClearBlockById(BasicBlock::Id block_id);
size_t BasicBlockCount() const { return all_blocks_.size(); }
size_t RpoBlockCount() const { return rpo_order_.size(); }
@@ -280,8 +281,6 @@ class V8_EXPORT_PRIVATE Schedule final : public NON_EXPORTED_BASE(ZoneObject) {
void EliminateRedundantPhiNodes();
// Ensure split-edge form for a hand-assembled schedule.
void EnsureSplitEdgeForm(BasicBlock* block);
- // Ensure entry into a deferred block happens from a single hot block.
- void EnsureDeferredCodeSingleEntryPoint(BasicBlock* block);
// Move Phi operands to newly created merger blocks
void MovePhis(BasicBlock* from, BasicBlock* to);
// Copy deferred block markers down as far as possible
diff --git a/deps/v8/src/compiler/scheduler.cc b/deps/v8/src/compiler/scheduler.cc
index 25919bb3b3..bf23e436f6 100644
--- a/deps/v8/src/compiler/scheduler.cc
+++ b/deps/v8/src/compiler/scheduler.cc
@@ -359,7 +359,6 @@ class CFGBuilder : public ZoneObject {
// JS opcodes are just like calls => fall through.
#undef BUILD_BLOCK_JS_CASE
case IrOpcode::kCall:
- case IrOpcode::kCallWithCallerSavedRegisters:
if (NodeProperties::IsExceptionalCall(node)) {
BuildBlocksForSuccessors(node);
}
@@ -404,7 +403,6 @@ class CFGBuilder : public ZoneObject {
// JS opcodes are just like calls => fall through.
#undef CONNECT_BLOCK_JS_CASE
case IrOpcode::kCall:
- case IrOpcode::kCallWithCallerSavedRegisters:
if (NodeProperties::IsExceptionalCall(node)) {
scheduler_->UpdatePlacement(node, Scheduler::kFixed);
ConnectCall(node);
@@ -820,7 +818,7 @@ class SpecialRPONumberer : public ZoneObject {
if (num_loops > static_cast<int>(loops_.size())) {
// Otherwise, compute the loop information from the backedges in order
// to perform a traversal that groups loop bodies together.
- ComputeLoopInfo(stack_, num_loops, &backedges_);
+ ComputeLoopInfo(&stack_, num_loops, &backedges_);
// Initialize the "loop stack". Note the entry could be a loop header.
LoopInfo* loop =
@@ -962,9 +960,8 @@ class SpecialRPONumberer : public ZoneObject {
}
// Computes loop membership from the backedges of the control flow graph.
- void ComputeLoopInfo(
- ZoneVector<SpecialRPOStackFrame>& queue, // NOLINT(runtime/references)
- size_t num_loops, ZoneVector<Backedge>* backedges) {
+ void ComputeLoopInfo(ZoneVector<SpecialRPOStackFrame>* queue,
+ size_t num_loops, ZoneVector<Backedge>* backedges) {
// Extend existing loop membership vectors.
for (LoopInfo& loop : loops_) {
loop.members->Resize(static_cast<int>(schedule_->BasicBlockCount()),
@@ -993,19 +990,19 @@ class SpecialRPONumberer : public ZoneObject {
if (!loops_[loop_num].members->Contains(member->id().ToInt())) {
loops_[loop_num].members->Add(member->id().ToInt());
}
- queue[queue_length++].block = member;
+ (*queue)[queue_length++].block = member;
}
// Propagate loop membership backwards. All predecessors of M up to the
// loop header H are members of the loop too. O(|blocks between M and H|).
while (queue_length > 0) {
- BasicBlock* block = queue[--queue_length].block;
+ BasicBlock* block = (*queue)[--queue_length].block;
for (size_t i = 0; i < block->PredecessorCount(); i++) {
BasicBlock* pred = block->PredecessorAt(i);
if (pred != header) {
if (!loops_[loop_num].members->Contains(pred->id().ToInt())) {
loops_[loop_num].members->Add(pred->id().ToInt());
- queue[queue_length++].block = pred;
+ (*queue)[queue_length++].block = pred;
}
}
}
diff --git a/deps/v8/src/compiler/serializer-for-background-compilation.cc b/deps/v8/src/compiler/serializer-for-background-compilation.cc
index 5597850b06..20d405b775 100644
--- a/deps/v8/src/compiler/serializer-for-background-compilation.cc
+++ b/deps/v8/src/compiler/serializer-for-background-compilation.cc
@@ -11,13 +11,13 @@
#include "src/compiler/bytecode-analysis.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/js-heap-broker.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/handles/handles-inl.h"
#include "src/ic/call-optimization.h"
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/objects/code.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/js-regexp-inl.h"
+#include "src/objects/literal-objects-inl.h"
#include "src/objects/shared-function-info-inl.h"
#include "src/zone/zone-containers.h"
#include "src/zone/zone.h"
@@ -38,63 +38,21 @@ namespace compiler {
V(Throw)
#define CLEAR_ACCUMULATOR_LIST(V) \
- V(Add) \
- V(AddSmi) \
- V(BitwiseAnd) \
- V(BitwiseAndSmi) \
- V(BitwiseNot) \
- V(BitwiseOr) \
- V(BitwiseOrSmi) \
- V(BitwiseXor) \
- V(BitwiseXorSmi) \
V(CallRuntime) \
V(CloneObject) \
V(CreateArrayFromIterable) \
- V(CreateArrayLiteral) \
V(CreateEmptyArrayLiteral) \
V(CreateEmptyObjectLiteral) \
V(CreateMappedArguments) \
- V(CreateObjectLiteral) \
- V(CreateRegExpLiteral) \
V(CreateRestParameter) \
V(CreateUnmappedArguments) \
- V(Dec) \
V(DeletePropertySloppy) \
V(DeletePropertyStrict) \
- V(Div) \
- V(DivSmi) \
- V(Exp) \
- V(ExpSmi) \
V(ForInContinue) \
V(ForInEnumerate) \
- V(ForInNext) \
V(ForInStep) \
- V(Inc) \
- V(LdaLookupSlot) \
- V(LdaLookupSlotInsideTypeof) \
V(LogicalNot) \
- V(Mod) \
- V(ModSmi) \
- V(Mul) \
- V(MulSmi) \
- V(Negate) \
V(SetPendingMessage) \
- V(ShiftLeft) \
- V(ShiftLeftSmi) \
- V(ShiftRight) \
- V(ShiftRightLogical) \
- V(ShiftRightLogicalSmi) \
- V(ShiftRightSmi) \
- V(StaLookupSlot) \
- V(Sub) \
- V(SubSmi) \
- V(TestEqual) \
- V(TestEqualStrict) \
- V(TestGreaterThan) \
- V(TestGreaterThanOrEqual) \
- V(TestInstanceOf) \
- V(TestLessThan) \
- V(TestLessThanOrEqual) \
V(TestNull) \
V(TestReferenceEqual) \
V(TestTypeOf) \
@@ -102,8 +60,6 @@ namespace compiler {
V(TestUndetectable) \
V(ToBooleanLogicalNot) \
V(ToName) \
- V(ToNumber) \
- V(ToNumeric) \
V(ToString) \
V(TypeOf)
@@ -130,15 +86,13 @@ namespace compiler {
V(JumpIfTrue) \
V(JumpIfTrueConstant) \
V(JumpIfUndefined) \
- V(JumpIfUndefinedConstant)
+ V(JumpIfUndefinedConstant) \
+ V(JumpIfUndefinedOrNull) \
+ V(JumpIfUndefinedOrNullConstant)
#define IGNORED_BYTECODE_LIST(V) \
- V(CallNoFeedback) \
V(IncBlockCounter) \
- V(LdaNamedPropertyNoFeedback) \
V(StackCheck) \
- V(StaNamedPropertyNoFeedback) \
- V(ThrowReferenceErrorIfHole) \
V(ThrowSuperAlreadyCalledIfNotHole) \
V(ThrowSuperNotCalledIfHole)
@@ -147,9 +101,50 @@ namespace compiler {
V(Illegal) \
V(Wide)
+#define BINARY_OP_LIST(V) \
+ V(Add) \
+ V(AddSmi) \
+ V(BitwiseAnd) \
+ V(BitwiseAndSmi) \
+ V(BitwiseOr) \
+ V(BitwiseOrSmi) \
+ V(BitwiseXor) \
+ V(BitwiseXorSmi) \
+ V(Div) \
+ V(DivSmi) \
+ V(Exp) \
+ V(ExpSmi) \
+ V(Mod) \
+ V(ModSmi) \
+ V(Mul) \
+ V(MulSmi) \
+ V(ShiftLeft) \
+ V(ShiftLeftSmi) \
+ V(ShiftRight) \
+ V(ShiftRightSmi) \
+ V(ShiftRightLogical) \
+ V(ShiftRightLogicalSmi) \
+ V(Sub) \
+ V(SubSmi)
+
+#define UNARY_OP_LIST(V) \
+ V(BitwiseNot) \
+ V(Dec) \
+ V(Inc) \
+ V(Negate)
+
+#define COMPARE_OP_LIST(V) \
+ V(TestEqual) \
+ V(TestEqualStrict) \
+ V(TestGreaterThan) \
+ V(TestGreaterThanOrEqual) \
+ V(TestLessThan) \
+ V(TestLessThanOrEqual)
+
#define SUPPORTED_BYTECODE_LIST(V) \
V(CallAnyReceiver) \
V(CallJSRuntime) \
+ V(CallNoFeedback) \
V(CallProperty) \
V(CallProperty0) \
V(CallProperty1) \
@@ -161,12 +156,18 @@ namespace compiler {
V(CallWithSpread) \
V(Construct) \
V(ConstructWithSpread) \
+ V(CreateArrayLiteral) \
V(CreateBlockContext) \
V(CreateCatchContext) \
V(CreateClosure) \
V(CreateEvalContext) \
V(CreateFunctionContext) \
+ V(CreateObjectLiteral) \
+ V(CreateRegExpLiteral) \
V(CreateWithContext) \
+ V(ForInNext) \
+ V(ForInPrepare) \
+ V(GetIterator) \
V(GetSuperConstructor) \
V(GetTemplateObject) \
V(InvokeIntrinsic) \
@@ -184,7 +185,10 @@ namespace compiler {
V(LdaLookupContextSlotInsideTypeof) \
V(LdaLookupGlobalSlot) \
V(LdaLookupGlobalSlotInsideTypeof) \
+ V(LdaLookupSlot) \
+ V(LdaLookupSlotInsideTypeof) \
V(LdaNamedProperty) \
+ V(LdaNamedPropertyNoFeedback) \
V(LdaNull) \
V(Ldar) \
V(LdaSmi) \
@@ -198,21 +202,31 @@ namespace compiler {
V(Return) \
V(StaContextSlot) \
V(StaCurrentContextSlot) \
+ V(StaDataPropertyInLiteral) \
V(StaGlobal) \
V(StaInArrayLiteral) \
V(StaKeyedProperty) \
+ V(StaLookupSlot) \
V(StaModuleVariable) \
V(StaNamedOwnProperty) \
V(StaNamedProperty) \
+ V(StaNamedPropertyNoFeedback) \
V(Star) \
V(SwitchOnGeneratorState) \
V(SwitchOnSmiNoFeedback) \
V(TestIn) \
+ V(TestInstanceOf) \
+ V(ThrowReferenceErrorIfHole) \
+ V(ToNumber) \
+ V(ToNumeric) \
+ BINARY_OP_LIST(V) \
+ COMPARE_OP_LIST(V) \
CLEAR_ACCUMULATOR_LIST(V) \
CLEAR_ENVIRONMENT_LIST(V) \
CONDITIONAL_JUMPS_LIST(V) \
IGNORED_BYTECODE_LIST(V) \
KILL_ENVIRONMENT_LIST(V) \
+ UNARY_OP_LIST(V) \
UNCONDITIONAL_JUMPS_LIST(V) \
UNREACHABLE_BYTECODE_LIST(V)
@@ -247,6 +261,8 @@ class Hints {
public:
explicit Hints(Zone* zone);
+ static Hints SingleConstant(Handle<Object> constant, Zone* zone);
+
const ConstantsSet& constants() const;
const MapsSet& maps() const;
const BlueprintsSet& function_blueprints() const;
@@ -340,7 +356,7 @@ class SerializerForBackgroundCompilation {
const HintsVector& arguments,
SerializerForBackgroundCompilationFlags flags);
- bool BailoutOnUninitialized(FeedbackSlot slot);
+ bool BailoutOnUninitialized(ProcessedFeedback const& feedback);
void TraverseBytecode();
@@ -349,55 +365,87 @@ class SerializerForBackgroundCompilation {
SUPPORTED_BYTECODE_LIST(DECLARE_VISIT_BYTECODE)
#undef DECLARE_VISIT_BYTECODE
+ // Returns whether the callee with the given SFI should be processed further,
+ // i.e. whether it's inlineable.
+ bool ProcessSFIForCallOrConstruct(Handle<SharedFunctionInfo> shared,
+ const HintsVector& arguments,
+ SpeculationMode speculation_mode);
+ // Returns whether {function} should be serialized for compilation.
+ bool ProcessCalleeForCallOrConstruct(Handle<JSFunction> function,
+ const HintsVector& arguments,
+ SpeculationMode speculation_mode);
void ProcessCallOrConstruct(Hints callee, base::Optional<Hints> new_target,
const HintsVector& arguments, FeedbackSlot slot,
bool with_spread = false);
- void ProcessCallVarArgs(interpreter::BytecodeArrayIterator* iterator,
- ConvertReceiverMode receiver_mode,
+ void ProcessCallVarArgs(ConvertReceiverMode receiver_mode,
+ Hints const& callee, interpreter::Register first_reg,
+ int reg_count, FeedbackSlot slot,
bool with_spread = false);
void ProcessApiCall(Handle<SharedFunctionInfo> target,
const HintsVector& arguments);
- void ProcessReceiverMapForApiCall(
- FunctionTemplateInfoRef& target, // NOLINT(runtime/references)
- Handle<Map> receiver);
+ void ProcessReceiverMapForApiCall(FunctionTemplateInfoRef target,
+ Handle<Map> receiver);
void ProcessBuiltinCall(Handle<SharedFunctionInfo> target,
- const HintsVector& arguments);
+ const HintsVector& arguments,
+ SpeculationMode speculation_mode);
void ProcessJump(interpreter::BytecodeArrayIterator* iterator);
void ProcessKeyedPropertyAccess(Hints const& receiver, Hints const& key,
- FeedbackSlot slot, AccessMode mode);
- void ProcessNamedPropertyAccess(interpreter::BytecodeArrayIterator* iterator,
- AccessMode mode);
- void ProcessNamedPropertyAccess(Hints const& receiver, NameRef const& name,
- FeedbackSlot slot, AccessMode mode);
+ FeedbackSlot slot, AccessMode access_mode,
+ bool honor_bailout_on_uninitialized);
+ void ProcessNamedPropertyAccess(Hints receiver, NameRef const& name,
+ FeedbackSlot slot, AccessMode access_mode);
+ void ProcessNamedAccess(Hints receiver, NamedAccessFeedback const& feedback,
+ AccessMode access_mode, Hints* new_accumulator_hints);
+ void ProcessElementAccess(Hints receiver, Hints key,
+ ElementAccessFeedback const& feedback,
+ AccessMode access_mode);
+
+ void ProcessModuleVariableAccess(
+ interpreter::BytecodeArrayIterator* iterator);
+
+ void ProcessHintsForObjectCreate(Hints const& prototype);
void ProcessMapHintsForPromises(Hints const& receiver_hints);
void ProcessHintsForPromiseResolve(Hints const& resolution_hints);
+ void ProcessHintsForHasInPrototypeChain(Hints const& instance_hints);
void ProcessHintsForRegExpTest(Hints const& regexp_hints);
PropertyAccessInfo ProcessMapForRegExpTest(MapRef map);
void ProcessHintsForFunctionCall(Hints const& target_hints);
+ void ProcessHintsForFunctionBind(Hints const& receiver_hints);
+ void ProcessHintsForObjectGetPrototype(Hints const& object_hints);
+ void ProcessConstantForOrdinaryHasInstance(HeapObjectRef const& constructor,
+ bool* walk_prototypes);
+ void ProcessConstantForInstanceOf(ObjectRef const& constant,
+ bool* walk_prototypes);
+ void ProcessHintsForOrdinaryHasInstance(Hints const& constructor_hints,
+ Hints const& instance_hints);
+
+ void ProcessGlobalAccess(FeedbackSlot slot, bool is_load);
+
+ void ProcessCompareOperation(FeedbackSlot slot);
+ void ProcessForIn(FeedbackSlot slot);
+ void ProcessUnaryOrBinaryOperation(FeedbackSlot slot,
+ bool honor_bailout_on_uninitialized);
+
+ PropertyAccessInfo ProcessMapForNamedPropertyAccess(
+ MapRef receiver_map, NameRef const& name, AccessMode access_mode,
+ base::Optional<JSObjectRef> receiver, Hints* new_accumulator_hints);
+
+ void ProcessCreateContext(interpreter::BytecodeArrayIterator* iterator,
+ int scopeinfo_operand_index);
- GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(FeedbackSlot slot);
- NamedAccessFeedback const* ProcessFeedbackMapsForNamedAccess(
- const MapHandles& maps, AccessMode mode, NameRef const& name);
- ElementAccessFeedback const* ProcessFeedbackMapsForElementAccess(
- const MapHandles& maps, AccessMode mode,
- KeyedAccessMode const& keyed_mode);
- void ProcessFeedbackForPropertyAccess(FeedbackSlot slot, AccessMode mode,
- base::Optional<NameRef> static_name);
- void ProcessMapForNamedPropertyAccess(MapRef const& map, NameRef const& name);
-
- void ProcessCreateContext();
enum ContextProcessingMode {
kIgnoreSlot,
kSerializeSlot,
- kSerializeSlotAndAddToAccumulator
};
- void ProcessContextAccess(const Hints& context_hints, int slot, int depth,
- ContextProcessingMode mode);
- void ProcessImmutableLoad(ContextRef& context, // NOLINT(runtime/references)
- int slot, ContextProcessingMode mode);
+ void ProcessContextAccess(Hints const& context_hints, int slot, int depth,
+ ContextProcessingMode mode,
+ Hints* result_hints = nullptr);
+ void ProcessImmutableLoad(ContextRef const& context, int slot,
+ ContextProcessingMode mode,
+ Hints* new_accumulator_hints);
void ProcessLdaLookupGlobalSlot(interpreter::BytecodeArrayIterator* iterator);
void ProcessLdaLookupContextSlot(
interpreter::BytecodeArrayIterator* iterator);
@@ -420,8 +468,10 @@ class SerializerForBackgroundCompilation {
void ContributeToJumpTargetEnvironment(int target_offset);
void IncorporateJumpTargetEnvironment(int target_offset);
+ Handle<FeedbackVector> feedback_vector() const;
Handle<BytecodeArray> bytecode_array() const;
- BytecodeAnalysis const& GetBytecodeAnalysis(bool serialize);
+ BytecodeAnalysis const& GetBytecodeAnalysis(
+ SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
JSHeapBroker* broker() const { return broker_; }
CompilationDependencies* dependencies() const { return dependencies_; }
@@ -496,6 +546,12 @@ bool Hints::Equals(Hints const& other) const {
}
#endif
+Hints Hints::SingleConstant(Handle<Object> constant, Zone* zone) {
+ Hints result(zone);
+ result.AddConstant(constant);
+ return result;
+}
+
const ConstantsSet& Hints::constants() const { return constants_; }
const MapsSet& Hints::maps() const { return maps_; }
@@ -628,7 +684,7 @@ class SerializerForBackgroundCompilation::Environment : public ZoneObject {
// Appends the hints for the given register range to {dst} (in order).
void ExportRegisterHints(interpreter::Register first, size_t count,
- HintsVector& dst); // NOLINT(runtime/references)
+ HintsVector* dst);
private:
friend std::ostream& operator<<(std::ostream& out, const Environment& env);
@@ -693,8 +749,8 @@ SerializerForBackgroundCompilation::Environment::Environment(
}
// Pad the rest with "undefined".
- Hints undefined_hint(zone);
- undefined_hint.AddConstant(isolate->factory()->undefined_value());
+ Hints undefined_hint =
+ Hints::SingleConstant(isolate->factory()->undefined_value(), zone);
for (size_t i = arguments.size(); i < param_count; ++i) {
ephemeral_hints_[i] = undefined_hint;
}
@@ -826,7 +882,7 @@ SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
}
bool SerializerForBackgroundCompilation::BailoutOnUninitialized(
- FeedbackSlot slot) {
+ ProcessedFeedback const& feedback) {
DCHECK(!environment()->IsDead());
if (!(flags() &
SerializerForBackgroundCompilationFlag::kBailoutOnUninitialized)) {
@@ -837,16 +893,7 @@ bool SerializerForBackgroundCompilation::BailoutOnUninitialized(
// OSR entry point. TODO(neis): Support OSR?
return false;
}
- FeedbackNexus nexus(environment()->function().feedback_vector(), slot);
- if (!slot.IsInvalid() && nexus.IsUninitialized()) {
- FeedbackSource source(nexus);
- if (broker()->HasFeedback(source)) {
- DCHECK_EQ(broker()->GetFeedback(source)->kind(),
- ProcessedFeedback::kInsufficient);
- } else {
- broker()->SetFeedback(source,
- new (broker()->zone()) InsufficientFeedback());
- }
+ if (feedback.IsInsufficient()) {
environment()->Kill();
return true;
}
@@ -856,15 +903,14 @@ bool SerializerForBackgroundCompilation::BailoutOnUninitialized(
Hints SerializerForBackgroundCompilation::Run() {
TraceScope tracer(broker(), this, "SerializerForBackgroundCompilation::Run");
SharedFunctionInfoRef shared(broker(), environment()->function().shared());
- FeedbackVectorRef feedback_vector(
- broker(), environment()->function().feedback_vector());
- if (shared.IsSerializedForCompilation(feedback_vector)) {
+ FeedbackVectorRef feedback_vector_ref(broker(), feedback_vector());
+ if (shared.IsSerializedForCompilation(feedback_vector_ref)) {
TRACE_BROKER(broker(), "Already ran serializer for SharedFunctionInfo "
<< Brief(*shared.object())
<< ", bailing out.\n");
return Hints(zone());
}
- shared.SetSerializedForCompilation(feedback_vector);
+ shared.SetSerializedForCompilation(feedback_vector_ref);
// We eagerly call the {EnsureSourcePositionsAvailable} for all serialized
// SFIs while still on the main thread. Source positions will later be used
@@ -875,7 +921,7 @@ Hints SerializerForBackgroundCompilation::Run() {
shared.object());
}
- feedback_vector.SerializeSlots();
+ feedback_vector_ref.Serialize();
TraverseBytecode();
return environment()->return_value_hints();
}
@@ -909,6 +955,11 @@ class ExceptionHandlerMatcher {
std::set<int>::const_iterator handlers_iterator_;
};
+Handle<FeedbackVector> SerializerForBackgroundCompilation::feedback_vector()
+ const {
+ return environment()->function().feedback_vector();
+}
+
Handle<BytecodeArray> SerializerForBackgroundCompilation::bytecode_array()
const {
return handle(environment()->function().shared()->GetBytecodeArray(),
@@ -916,22 +967,28 @@ Handle<BytecodeArray> SerializerForBackgroundCompilation::bytecode_array()
}
BytecodeAnalysis const& SerializerForBackgroundCompilation::GetBytecodeAnalysis(
- bool serialize) {
+ SerializationPolicy policy) {
return broker()->GetBytecodeAnalysis(
bytecode_array(), osr_offset(),
flags() &
SerializerForBackgroundCompilationFlag::kAnalyzeEnvironmentLiveness,
- serialize);
+ policy);
}
void SerializerForBackgroundCompilation::TraverseBytecode() {
- BytecodeAnalysis const& bytecode_analysis = GetBytecodeAnalysis(true);
+ BytecodeAnalysis const& bytecode_analysis =
+ GetBytecodeAnalysis(SerializationPolicy::kSerializeIfNeeded);
BytecodeArrayRef(broker(), bytecode_array()).SerializeForCompilation();
BytecodeArrayIterator iterator(bytecode_array());
ExceptionHandlerMatcher handler_matcher(iterator, bytecode_array());
+ bool has_one_shot_bytecode = false;
for (; !iterator.done(); iterator.Advance()) {
+ has_one_shot_bytecode =
+ has_one_shot_bytecode ||
+ interpreter::Bytecodes::IsOneShotBytecode(iterator.current_bytecode());
+
int const current_offset = iterator.current_offset();
IncorporateJumpTargetEnvironment(current_offset);
@@ -970,6 +1027,21 @@ void SerializerForBackgroundCompilation::TraverseBytecode() {
}
}
}
+
+ if (has_one_shot_bytecode) {
+ broker()->isolate()->CountUsage(
+ v8::Isolate::UseCounterFeature::kOptimizedFunctionWithOneShotBytecode);
+ }
+}
+
+void SerializerForBackgroundCompilation::VisitGetIterator(
+ BytecodeArrayIterator* iterator) {
+ AccessMode mode = AccessMode::kLoad;
+ Hints const& receiver =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ Handle<Name> name = broker()->isolate()->factory()->iterator_symbol();
+ FeedbackSlot slot = iterator->GetSlotOperand(1);
+ ProcessNamedPropertyAccess(receiver, NameRef(broker(), name), slot, mode);
}
void SerializerForBackgroundCompilation::VisitGetSuperConstructor(
@@ -995,11 +1067,11 @@ void SerializerForBackgroundCompilation::VisitGetTemplateObject(
ObjectRef description(
broker(), iterator->GetConstantForIndexOperand(0, broker()->isolate()));
FeedbackSlot slot = iterator->GetSlotOperand(1);
- FeedbackVectorRef feedback_vector(
- broker(), environment()->function().feedback_vector());
+ FeedbackVectorRef feedback_vector_ref(broker(), feedback_vector());
SharedFunctionInfoRef shared(broker(), environment()->function().shared());
JSArrayRef template_object =
- shared.GetTemplateObject(description, feedback_vector, slot, true);
+ shared.GetTemplateObject(description, feedback_vector_ref, slot,
+ SerializationPolicy::kSerializeIfNeeded);
environment()->accumulator_hints().Clear();
environment()->accumulator_hints().AddConstant(template_object.object());
}
@@ -1058,25 +1130,92 @@ void SerializerForBackgroundCompilation::VisitInvokeIntrinsic(
Runtime::FunctionId functionId = iterator->GetIntrinsicIdOperand(0);
// For JSNativeContextSpecialization::ReduceJSAsyncFunctionResolve and
// JSNativeContextSpecialization::ReduceJSResolvePromise.
- if (functionId == Runtime::kInlineAsyncFunctionResolve) {
- interpreter::Register first_reg = iterator->GetRegisterOperand(1);
- size_t reg_count = iterator->GetRegisterCountOperand(2);
- CHECK_EQ(reg_count, 3);
- HintsVector arguments(zone());
- environment()->ExportRegisterHints(first_reg, reg_count, arguments);
- Hints const& resolution_hints = arguments[1]; // The resolution object.
- ProcessHintsForPromiseResolve(resolution_hints);
- environment()->accumulator_hints().Clear();
- return;
+ switch (functionId) {
+ case Runtime::kInlineAsyncFunctionResolve: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncFunctionResolve));
+ interpreter::Register first_reg = iterator->GetRegisterOperand(1);
+ size_t reg_count = iterator->GetRegisterCountOperand(2);
+ CHECK_EQ(reg_count, 3);
+ HintsVector arguments(zone());
+ environment()->ExportRegisterHints(first_reg, reg_count, &arguments);
+ Hints const& resolution_hints = arguments[1]; // The resolution object.
+ ProcessHintsForPromiseResolve(resolution_hints);
+ environment()->accumulator_hints().Clear();
+ return;
+ }
+ case Runtime::kInlineAsyncGeneratorReject:
+ case Runtime::kAsyncGeneratorReject: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncGeneratorReject));
+ break;
+ }
+ case Runtime::kInlineAsyncGeneratorResolve:
+ case Runtime::kAsyncGeneratorResolve: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncGeneratorResolve));
+ break;
+ }
+ case Runtime::kInlineAsyncGeneratorYield:
+ case Runtime::kAsyncGeneratorYield: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncGeneratorYield));
+ break;
+ }
+ case Runtime::kInlineAsyncGeneratorAwaitUncaught:
+ case Runtime::kAsyncGeneratorAwaitUncaught: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncGeneratorAwaitUncaught));
+ break;
+ }
+ case Runtime::kInlineAsyncGeneratorAwaitCaught:
+ case Runtime::kAsyncGeneratorAwaitCaught: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncGeneratorAwaitCaught));
+ break;
+ }
+ case Runtime::kInlineAsyncFunctionAwaitUncaught:
+ case Runtime::kAsyncFunctionAwaitUncaught: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncFunctionAwaitUncaught));
+ break;
+ }
+ case Runtime::kInlineAsyncFunctionAwaitCaught:
+ case Runtime::kAsyncFunctionAwaitCaught: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncFunctionAwaitCaught));
+ break;
+ }
+ case Runtime::kInlineAsyncFunctionReject:
+ case Runtime::kAsyncFunctionReject: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncFunctionReject));
+ break;
+ }
+ case Runtime::kAsyncFunctionResolve: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kAsyncFunctionResolve));
+ break;
+ }
+ case Runtime::kInlineCopyDataProperties:
+ case Runtime::kCopyDataProperties: {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kCopyDataProperties));
+ break;
+ }
+ default: {
+ break;
+ }
}
environment()->ClearEphemeralHints();
}
void SerializerForBackgroundCompilation::VisitLdaConstant(
BytecodeArrayIterator* iterator) {
+ ObjectRef object(
+ broker(), iterator->GetConstantForIndexOperand(0, broker()->isolate()));
environment()->accumulator_hints().Clear();
- environment()->accumulator_hints().AddConstant(
- iterator->GetConstantForIndexOperand(0, broker()->isolate()));
+ environment()->accumulator_hints().AddConstant(object.object());
}
void SerializerForBackgroundCompilation::VisitPushContext(
@@ -1088,7 +1227,7 @@ void SerializerForBackgroundCompilation::VisitPushContext(
saved_context_hints.Clear();
saved_context_hints.Add(current_context_hints);
- // New Context is in the accumulator. Put those hints into the current context
+ // New context is in the accumulator. Put those hints into the current context
// register hints.
current_context_hints.Clear();
current_context_hints.Add(environment()->accumulator_hints());
@@ -1104,19 +1243,21 @@ void SerializerForBackgroundCompilation::VisitPopContext(
}
void SerializerForBackgroundCompilation::ProcessImmutableLoad(
- ContextRef& context_ref, int slot, ContextProcessingMode mode) {
- DCHECK(mode == kSerializeSlot || mode == kSerializeSlotAndAddToAccumulator);
- base::Optional<ObjectRef> slot_value = context_ref.get(slot, true);
+ ContextRef const& context_ref, int slot, ContextProcessingMode mode,
+ Hints* result_hints) {
+ DCHECK_EQ(mode, kSerializeSlot);
+ base::Optional<ObjectRef> slot_value =
+ context_ref.get(slot, SerializationPolicy::kSerializeIfNeeded);
- // Also, put the object into the constant hints for the accumulator.
- if (mode == kSerializeSlotAndAddToAccumulator && slot_value.has_value()) {
- environment()->accumulator_hints().AddConstant(slot_value.value().object());
+ // If requested, record the object as a hint for the result value.
+ if (result_hints != nullptr && slot_value.has_value()) {
+ result_hints->AddConstant(slot_value.value().object());
}
}
void SerializerForBackgroundCompilation::ProcessContextAccess(
- const Hints& context_hints, int slot, int depth,
- ContextProcessingMode mode) {
+ Hints const& context_hints, int slot, int depth, ContextProcessingMode mode,
+ Hints* result_hints) {
// This function is for JSContextSpecialization::ReduceJSLoadContext and
// ReduceJSStoreContext. Those reductions attempt to eliminate as many
// loads as possible by making use of constant Context objects. In the
@@ -1127,9 +1268,10 @@ void SerializerForBackgroundCompilation::ProcessContextAccess(
// Walk this context to the given depth and serialize the slot found.
ContextRef context_ref(broker(), x);
size_t remaining_depth = depth;
- context_ref = context_ref.previous(&remaining_depth, true);
+ context_ref = context_ref.previous(
+ &remaining_depth, SerializationPolicy::kSerializeIfNeeded);
if (remaining_depth == 0 && mode != kIgnoreSlot) {
- ProcessImmutableLoad(context_ref, slot, mode);
+ ProcessImmutableLoad(context_ref, slot, mode, result_hints);
}
}
}
@@ -1137,9 +1279,10 @@ void SerializerForBackgroundCompilation::ProcessContextAccess(
if (x.distance <= static_cast<unsigned int>(depth)) {
ContextRef context_ref(broker(), x.context);
size_t remaining_depth = depth - x.distance;
- context_ref = context_ref.previous(&remaining_depth, true);
+ context_ref = context_ref.previous(
+ &remaining_depth, SerializationPolicy::kSerializeIfNeeded);
if (remaining_depth == 0 && mode != kIgnoreSlot) {
- ProcessImmutableLoad(context_ref, slot, mode);
+ ProcessImmutableLoad(context_ref, slot, mode, result_hints);
}
}
}
@@ -1147,67 +1290,92 @@ void SerializerForBackgroundCompilation::ProcessContextAccess(
void SerializerForBackgroundCompilation::VisitLdaContextSlot(
BytecodeArrayIterator* iterator) {
- Hints& context_hints =
+ Hints const& context_hints =
environment()->register_hints(iterator->GetRegisterOperand(0));
const int slot = iterator->GetIndexOperand(1);
const int depth = iterator->GetUnsignedImmediateOperand(2);
+ Hints new_accumulator_hints(zone());
+ ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot,
+ &new_accumulator_hints);
environment()->accumulator_hints().Clear();
- ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot);
+ environment()->accumulator_hints().Add(new_accumulator_hints);
}
void SerializerForBackgroundCompilation::VisitLdaCurrentContextSlot(
BytecodeArrayIterator* iterator) {
const int slot = iterator->GetIndexOperand(0);
const int depth = 0;
- Hints& context_hints = environment()->current_context_hints();
+ Hints const& context_hints = environment()->current_context_hints();
+ Hints new_accumulator_hints(zone());
+ ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot,
+ &new_accumulator_hints);
environment()->accumulator_hints().Clear();
- ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot);
+ environment()->accumulator_hints().Add(new_accumulator_hints);
}
void SerializerForBackgroundCompilation::VisitLdaImmutableContextSlot(
BytecodeArrayIterator* iterator) {
const int slot = iterator->GetIndexOperand(1);
const int depth = iterator->GetUnsignedImmediateOperand(2);
- Hints& context_hints =
+ Hints const& context_hints =
environment()->register_hints(iterator->GetRegisterOperand(0));
+ Hints new_accumulator_hints(zone());
+ ProcessContextAccess(context_hints, slot, depth, kSerializeSlot,
+ &new_accumulator_hints);
environment()->accumulator_hints().Clear();
- ProcessContextAccess(context_hints, slot, depth,
- kSerializeSlotAndAddToAccumulator);
+ environment()->accumulator_hints().Add(new_accumulator_hints);
}
void SerializerForBackgroundCompilation::VisitLdaImmutableCurrentContextSlot(
BytecodeArrayIterator* iterator) {
const int slot = iterator->GetIndexOperand(0);
const int depth = 0;
- Hints& context_hints = environment()->current_context_hints();
+ Hints const& context_hints = environment()->current_context_hints();
+ Hints new_accumulator_hints(zone());
+ ProcessContextAccess(context_hints, slot, depth, kSerializeSlot,
+ &new_accumulator_hints);
environment()->accumulator_hints().Clear();
- ProcessContextAccess(context_hints, slot, depth,
- kSerializeSlotAndAddToAccumulator);
+ environment()->accumulator_hints().Add(new_accumulator_hints);
}
-void SerializerForBackgroundCompilation::VisitLdaModuleVariable(
+void SerializerForBackgroundCompilation::ProcessModuleVariableAccess(
BytecodeArrayIterator* iterator) {
+ const int slot = Context::EXTENSION_INDEX;
const int depth = iterator->GetUnsignedImmediateOperand(1);
+ Hints const& context_hints = environment()->current_context_hints();
- // TODO(mvstanton): If we have a constant module, should we serialize the
- // cell as well? Then we could put the value in the accumulator.
- environment()->accumulator_hints().Clear();
- ProcessContextAccess(environment()->current_context_hints(),
- Context::EXTENSION_INDEX, depth, kSerializeSlot);
+ Hints result_hints(zone());
+ ProcessContextAccess(context_hints, slot, depth, kSerializeSlot,
+ &result_hints);
+ for (Handle<Object> constant : result_hints.constants()) {
+ ObjectRef object(broker(), constant);
+ // For JSTypedLowering::BuildGetModuleCell.
+ if (object.IsSourceTextModule()) object.AsSourceTextModule().Serialize();
+ }
+}
+
+void SerializerForBackgroundCompilation::VisitLdaModuleVariable(
+ BytecodeArrayIterator* iterator) {
+ ProcessModuleVariableAccess(iterator);
}
void SerializerForBackgroundCompilation::VisitStaModuleVariable(
BytecodeArrayIterator* iterator) {
- const int depth = iterator->GetUnsignedImmediateOperand(1);
- ProcessContextAccess(environment()->current_context_hints(),
- Context::EXTENSION_INDEX, depth, kSerializeSlot);
+ ProcessModuleVariableAccess(iterator);
+}
+
+void SerializerForBackgroundCompilation::VisitStaLookupSlot(
+ BytecodeArrayIterator* iterator) {
+ ObjectRef(broker(),
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
+ environment()->accumulator_hints().Clear();
}
void SerializerForBackgroundCompilation::VisitStaContextSlot(
BytecodeArrayIterator* iterator) {
const int slot = iterator->GetIndexOperand(1);
const int depth = iterator->GetUnsignedImmediateOperand(2);
- Hints& register_hints =
+ Hints const& register_hints =
environment()->register_hints(iterator->GetRegisterOperand(0));
ProcessContextAccess(register_hints, slot, depth, kIgnoreSlot);
}
@@ -1216,7 +1384,7 @@ void SerializerForBackgroundCompilation::VisitStaCurrentContextSlot(
BytecodeArrayIterator* iterator) {
const int slot = iterator->GetIndexOperand(0);
const int depth = 0;
- Hints& context_hints = environment()->current_context_hints();
+ Hints const& context_hints = environment()->current_context_hints();
ProcessContextAccess(context_hints, slot, depth, kIgnoreSlot);
}
@@ -1242,35 +1410,80 @@ void SerializerForBackgroundCompilation::VisitMov(
environment()->register_hints(dst).Add(environment()->register_hints(src));
}
+void SerializerForBackgroundCompilation::VisitCreateRegExpLiteral(
+ BytecodeArrayIterator* iterator) {
+ Handle<String> constant_pattern = Handle<String>::cast(
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
+ StringRef description(broker(), constant_pattern);
+ environment()->accumulator_hints().Clear();
+}
+
+void SerializerForBackgroundCompilation::VisitCreateArrayLiteral(
+ BytecodeArrayIterator* iterator) {
+ Handle<ArrayBoilerplateDescription> array_boilerplate_description =
+ Handle<ArrayBoilerplateDescription>::cast(
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
+ ArrayBoilerplateDescriptionRef description(broker(),
+ array_boilerplate_description);
+ environment()->accumulator_hints().Clear();
+}
+
+void SerializerForBackgroundCompilation::VisitCreateObjectLiteral(
+ BytecodeArrayIterator* iterator) {
+ Handle<ObjectBoilerplateDescription> constant_properties =
+ Handle<ObjectBoilerplateDescription>::cast(
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
+ ObjectBoilerplateDescriptionRef description(broker(), constant_properties);
+ environment()->accumulator_hints().Clear();
+}
+
void SerializerForBackgroundCompilation::VisitCreateFunctionContext(
BytecodeArrayIterator* iterator) {
- ProcessCreateContext();
+ ProcessCreateContext(iterator, 0);
}
void SerializerForBackgroundCompilation::VisitCreateBlockContext(
BytecodeArrayIterator* iterator) {
- ProcessCreateContext();
+ ProcessCreateContext(iterator, 0);
}
void SerializerForBackgroundCompilation::VisitCreateEvalContext(
BytecodeArrayIterator* iterator) {
- ProcessCreateContext();
+ ProcessCreateContext(iterator, 0);
}
void SerializerForBackgroundCompilation::VisitCreateWithContext(
BytecodeArrayIterator* iterator) {
- ProcessCreateContext();
+ ProcessCreateContext(iterator, 1);
}
void SerializerForBackgroundCompilation::VisitCreateCatchContext(
BytecodeArrayIterator* iterator) {
- ProcessCreateContext();
+ ProcessCreateContext(iterator, 1);
+}
+
+void SerializerForBackgroundCompilation::VisitForInNext(
+ BytecodeArrayIterator* iterator) {
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
+ ProcessForIn(slot);
+}
+
+void SerializerForBackgroundCompilation::VisitForInPrepare(
+ BytecodeArrayIterator* iterator) {
+ FeedbackSlot slot = iterator->GetSlotOperand(1);
+ ProcessForIn(slot);
}
-void SerializerForBackgroundCompilation::ProcessCreateContext() {
+void SerializerForBackgroundCompilation::ProcessCreateContext(
+ interpreter::BytecodeArrayIterator* iterator, int scopeinfo_operand_index) {
+ Handle<ScopeInfo> scope_info =
+ Handle<ScopeInfo>::cast(iterator->GetConstantForIndexOperand(
+ scopeinfo_operand_index, broker()->isolate()));
+ ScopeInfoRef scope_info_ref(broker(), scope_info);
+
+ Hints const& current_context_hints = environment()->current_context_hints();
Hints& accumulator_hints = environment()->accumulator_hints();
accumulator_hints.Clear();
- Hints& current_context_hints = environment()->current_context_hints();
// For each constant context, we must create a virtual context from
// it of distance one.
@@ -1291,31 +1504,33 @@ void SerializerForBackgroundCompilation::ProcessCreateContext() {
void SerializerForBackgroundCompilation::VisitCreateClosure(
BytecodeArrayIterator* iterator) {
+ environment()->accumulator_hints().Clear();
+
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(
iterator->GetConstantForIndexOperand(0, broker()->isolate()));
-
Handle<FeedbackCell> feedback_cell =
- environment()->function().feedback_vector()->GetClosureFeedbackCell(
- iterator->GetIndexOperand(1));
+ feedback_vector()->GetClosureFeedbackCell(iterator->GetIndexOperand(1));
FeedbackCellRef feedback_cell_ref(broker(), feedback_cell);
Handle<Object> cell_value(feedback_cell->value(), broker()->isolate());
ObjectRef cell_value_ref(broker(), cell_value);
- environment()->accumulator_hints().Clear();
if (cell_value->IsFeedbackVector()) {
- // Gather the context hints from the current context register hint
- // structure.
FunctionBlueprint blueprint(shared,
Handle<FeedbackVector>::cast(cell_value),
environment()->current_context_hints());
-
environment()->accumulator_hints().AddFunctionBlueprint(blueprint);
}
}
void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver(
BytecodeArrayIterator* iterator) {
- ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
+ const Hints& callee =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ interpreter::Register first_reg = iterator->GetRegisterOperand(1);
+ int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
+ ProcessCallVarArgs(ConvertReceiverMode::kNullOrUndefined, callee, first_reg,
+ reg_count, slot);
}
void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver0(
@@ -1324,9 +1539,8 @@ void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver0(
environment()->register_hints(iterator->GetRegisterOperand(0));
FeedbackSlot slot = iterator->GetSlotOperand(1);
- Hints receiver(zone());
- receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
-
+ Hints receiver = Hints::SingleConstant(
+ broker()->isolate()->factory()->undefined_value(), zone());
HintsVector parameters({receiver}, zone());
ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
}
@@ -1339,9 +1553,8 @@ void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1(
environment()->register_hints(iterator->GetRegisterOperand(1));
FeedbackSlot slot = iterator->GetSlotOperand(2);
- Hints receiver(zone());
- receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
-
+ Hints receiver = Hints::SingleConstant(
+ broker()->isolate()->factory()->undefined_value(), zone());
HintsVector parameters({receiver, arg0}, zone());
ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
}
@@ -1356,21 +1569,42 @@ void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver2(
environment()->register_hints(iterator->GetRegisterOperand(2));
FeedbackSlot slot = iterator->GetSlotOperand(3);
- Hints receiver(zone());
- receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
-
+ Hints receiver = Hints::SingleConstant(
+ broker()->isolate()->factory()->undefined_value(), zone());
HintsVector parameters({receiver, arg0, arg1}, zone());
ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
}
void SerializerForBackgroundCompilation::VisitCallAnyReceiver(
BytecodeArrayIterator* iterator) {
- ProcessCallVarArgs(iterator, ConvertReceiverMode::kAny);
+ const Hints& callee =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ interpreter::Register first_reg = iterator->GetRegisterOperand(1);
+ int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
+ ProcessCallVarArgs(ConvertReceiverMode::kAny, callee, first_reg, reg_count,
+ slot);
+}
+
+void SerializerForBackgroundCompilation::VisitCallNoFeedback(
+ BytecodeArrayIterator* iterator) {
+ const Hints& callee =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ interpreter::Register first_reg = iterator->GetRegisterOperand(1);
+ int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
+ ProcessCallVarArgs(ConvertReceiverMode::kAny, callee, first_reg, reg_count,
+ FeedbackSlot::Invalid());
}
void SerializerForBackgroundCompilation::VisitCallProperty(
BytecodeArrayIterator* iterator) {
- ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
+ const Hints& callee =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ interpreter::Register first_reg = iterator->GetRegisterOperand(1);
+ int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
+ ProcessCallVarArgs(ConvertReceiverMode::kNotNullOrUndefined, callee,
+ first_reg, reg_count, slot);
}
void SerializerForBackgroundCompilation::VisitCallProperty0(
@@ -1417,17 +1651,28 @@ void SerializerForBackgroundCompilation::VisitCallProperty2(
void SerializerForBackgroundCompilation::VisitCallWithSpread(
BytecodeArrayIterator* iterator) {
- ProcessCallVarArgs(iterator, ConvertReceiverMode::kAny, true);
+ const Hints& callee =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ interpreter::Register first_reg = iterator->GetRegisterOperand(1);
+ int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
+ ProcessCallVarArgs(ConvertReceiverMode::kAny, callee, first_reg, reg_count,
+ slot, true);
}
void SerializerForBackgroundCompilation::VisitCallJSRuntime(
BytecodeArrayIterator* iterator) {
- environment()->accumulator_hints().Clear();
-
- // BytecodeGraphBuilder::VisitCallJSRuntime needs the {runtime_index}
- // slot in the native context to be serialized.
const int runtime_index = iterator->GetNativeContextIndexOperand(0);
- broker()->native_context().get(runtime_index, true);
+ ObjectRef constant =
+ broker()
+ ->target_native_context()
+ .get(runtime_index, SerializationPolicy::kSerializeIfNeeded)
+ .value();
+ Hints callee = Hints::SingleConstant(constant.object(), zone());
+ interpreter::Register first_reg = iterator->GetRegisterOperand(1);
+ int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
+ ProcessCallVarArgs(ConvertReceiverMode::kNullOrUndefined, callee, first_reg,
+ reg_count, FeedbackSlot::Invalid());
}
Hints SerializerForBackgroundCompilation::RunChildSerializer(
@@ -1456,107 +1701,168 @@ Hints SerializerForBackgroundCompilation::RunChildSerializer(
return child_serializer.Run();
}
+bool SerializerForBackgroundCompilation::ProcessSFIForCallOrConstruct(
+ Handle<SharedFunctionInfo> shared, const HintsVector& arguments,
+ SpeculationMode speculation_mode) {
+ if (shared->IsApiFunction()) {
+ ProcessApiCall(shared, arguments);
+ DCHECK(!shared->IsInlineable());
+ } else if (shared->HasBuiltinId()) {
+ ProcessBuiltinCall(shared, arguments, speculation_mode);
+ DCHECK(!shared->IsInlineable());
+ }
+ return shared->IsInlineable();
+}
+
+bool SerializerForBackgroundCompilation::ProcessCalleeForCallOrConstruct(
+ Handle<JSFunction> function, const HintsVector& arguments,
+ SpeculationMode speculation_mode) {
+ JSFunctionRef(broker(), function).Serialize();
+
+ Handle<SharedFunctionInfo> shared(function->shared(), broker()->isolate());
+
+ return ProcessSFIForCallOrConstruct(shared, arguments, speculation_mode) &&
+ function->has_feedback_vector();
+}
+
namespace {
-base::Optional<HeapObjectRef> GetHeapObjectFeedback(
- JSHeapBroker* broker, Handle<FeedbackVector> feedback_vector,
- FeedbackSlot slot) {
- if (slot.IsInvalid()) return base::nullopt;
- FeedbackNexus nexus(feedback_vector, slot);
- VectorSlotPair feedback(feedback_vector, slot, nexus.ic_state());
- DCHECK(feedback.IsValid());
- if (nexus.IsUninitialized()) return base::nullopt;
- HeapObject object;
- if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
- return HeapObjectRef(broker, handle(object, broker->isolate()));
+// Returns the innermost bound target, if it's a JSFunction and inserts
+// all bound arguments and {original_arguments} into {expanded_arguments}
+// in the appropriate order.
+MaybeHandle<JSFunction> UnrollBoundFunction(
+ JSBoundFunctionRef const& bound_function, JSHeapBroker* broker,
+ const HintsVector& original_arguments, HintsVector* expanded_arguments) {
+ DCHECK(expanded_arguments->empty());
+
+ JSReceiverRef target = bound_function.AsJSReceiver();
+ HintsVector reversed_bound_arguments(broker->zone());
+ for (; target.IsJSBoundFunction();
+ target = target.AsJSBoundFunction().bound_target_function()) {
+ for (int i = target.AsJSBoundFunction().bound_arguments().length() - 1;
+ i >= 0; --i) {
+ Hints arg = Hints::SingleConstant(
+ target.AsJSBoundFunction().bound_arguments().get(i).object(),
+ broker->zone());
+ reversed_bound_arguments.push_back(arg);
+ }
+ Hints arg = Hints::SingleConstant(
+ target.AsJSBoundFunction().bound_this().object(), broker->zone());
+ reversed_bound_arguments.push_back(arg);
+ }
+
+ if (!target.IsJSFunction()) return MaybeHandle<JSFunction>();
+
+ expanded_arguments->insert(expanded_arguments->end(),
+ reversed_bound_arguments.rbegin(),
+ reversed_bound_arguments.rend());
+ expanded_arguments->insert(expanded_arguments->end(),
+ original_arguments.begin(),
+ original_arguments.end());
+
+ return target.AsJSFunction().object();
}
} // namespace
void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
Hints callee, base::Optional<Hints> new_target,
const HintsVector& arguments, FeedbackSlot slot, bool with_spread) {
- // TODO(neis): Make this part of ProcessFeedback*?
- if (BailoutOnUninitialized(slot)) return;
-
- // Incorporate feedback into hints.
- base::Optional<HeapObjectRef> feedback = GetHeapObjectFeedback(
- broker(), environment()->function().feedback_vector(), slot);
- if (feedback.has_value() && feedback->map().is_callable()) {
- if (new_target.has_value()) {
- // Construct; feedback is new_target, which often is also the callee.
- new_target->AddConstant(feedback->object());
- callee.AddConstant(feedback->object());
- } else {
- // Call; feedback is callee.
- callee.AddConstant(feedback->object());
+ SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation;
+ if (!slot.IsInvalid()) {
+ FeedbackSource source(feedback_vector(), slot);
+ ProcessedFeedback const& feedback =
+ broker()->ProcessFeedbackForCall(source);
+ if (BailoutOnUninitialized(feedback)) return;
+
+ // Incorporate feedback into hints copy to simplify processing.
+ if (!feedback.IsInsufficient()) {
+ speculation_mode = feedback.AsCall().speculation_mode();
+ base::Optional<HeapObjectRef> target = feedback.AsCall().target();
+ if (target.has_value() && target->map().is_callable()) {
+ // TODO(mvstanton): if the map isn't callable then we have an allocation
+ // site, and it may make sense to add the Array JSFunction constant.
+ if (new_target.has_value()) {
+ // Construct; feedback is new_target, which often is also the callee.
+ new_target->AddConstant(target->object());
+ callee.AddConstant(target->object());
+ } else {
+ // Call; target is callee.
+ callee.AddConstant(target->object());
+ }
+ }
}
}
environment()->accumulator_hints().Clear();
+ // For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct.
for (auto hint : callee.constants()) {
- if (!hint->IsJSFunction()) continue;
-
- Handle<JSFunction> function = Handle<JSFunction>::cast(hint);
- JSFunctionRef(broker(), function).Serialize();
-
- Handle<SharedFunctionInfo> shared(function->shared(), broker()->isolate());
-
- if (shared->IsApiFunction()) {
- ProcessApiCall(shared, arguments);
- DCHECK(!shared->IsInlineable());
- } else if (shared->HasBuiltinId()) {
- ProcessBuiltinCall(shared, arguments);
- DCHECK(!shared->IsInlineable());
+ const HintsVector* actual_arguments = &arguments;
+ Handle<JSFunction> function;
+ HintsVector expanded_arguments(zone());
+ if (hint->IsJSBoundFunction()) {
+ JSBoundFunctionRef bound_function(broker(),
+ Handle<JSBoundFunction>::cast(hint));
+ bound_function.Serialize();
+
+ MaybeHandle<JSFunction> maybe_function = UnrollBoundFunction(
+ bound_function, broker(), arguments, &expanded_arguments);
+ if (maybe_function.is_null()) continue;
+ function = maybe_function.ToHandleChecked();
+ actual_arguments = &expanded_arguments;
+ } else if (hint->IsJSFunction()) {
+ function = Handle<JSFunction>::cast(hint);
+ } else {
+ continue;
}
- if (!shared->IsInlineable() || !function->has_feedback_vector()) continue;
-
- environment()->accumulator_hints().Add(RunChildSerializer(
- CompilationSubject(function, broker()->isolate(), zone()), new_target,
- arguments, with_spread));
+ if (ProcessCalleeForCallOrConstruct(function, *actual_arguments,
+ speculation_mode)) {
+ environment()->accumulator_hints().Add(RunChildSerializer(
+ CompilationSubject(function, broker()->isolate(), zone()), new_target,
+ *actual_arguments, with_spread));
+ }
}
+ // For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct.
for (auto hint : callee.function_blueprints()) {
Handle<SharedFunctionInfo> shared = hint.shared();
-
- if (shared->IsApiFunction()) {
- ProcessApiCall(shared, arguments);
- DCHECK(!shared->IsInlineable());
- } else if (shared->HasBuiltinId()) {
- ProcessBuiltinCall(shared, arguments);
- DCHECK(!shared->IsInlineable());
+ if (!ProcessSFIForCallOrConstruct(shared, arguments, speculation_mode)) {
+ continue;
}
- if (!shared->IsInlineable()) continue;
environment()->accumulator_hints().Add(RunChildSerializer(
CompilationSubject(hint), new_target, arguments, with_spread));
}
}
void SerializerForBackgroundCompilation::ProcessCallVarArgs(
- BytecodeArrayIterator* iterator, ConvertReceiverMode receiver_mode,
+ ConvertReceiverMode receiver_mode, Hints const& callee,
+ interpreter::Register first_reg, int reg_count, FeedbackSlot slot,
bool with_spread) {
- const Hints& callee =
- environment()->register_hints(iterator->GetRegisterOperand(0));
- interpreter::Register first_reg = iterator->GetRegisterOperand(1);
- int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
- FeedbackSlot slot = iterator->GetSlotOperand(3);
-
HintsVector arguments(zone());
// The receiver is either given in the first register or it is implicitly
// the {undefined} value.
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
- Hints receiver(zone());
- receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
- arguments.push_back(receiver);
+ arguments.push_back(Hints::SingleConstant(
+ broker()->isolate()->factory()->undefined_value(), zone()));
}
- environment()->ExportRegisterHints(first_reg, reg_count, arguments);
+ environment()->ExportRegisterHints(first_reg, reg_count, &arguments);
ProcessCallOrConstruct(callee, base::nullopt, arguments, slot);
}
void SerializerForBackgroundCompilation::ProcessApiCall(
Handle<SharedFunctionInfo> target, const HintsVector& arguments) {
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kCallFunctionTemplate_CheckAccess));
+ ObjectRef(broker(),
+ broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kCallFunctionTemplate_CheckCompatibleReceiver));
+ ObjectRef(
+ broker(),
+ broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kCallFunctionTemplate_CheckAccessAndCompatibleReceiver));
+
FunctionTemplateInfoRef target_template_info(
broker(), handle(target->function_data(), broker()->isolate()));
if (!target_template_info.has_call_code()) return;
@@ -1576,7 +1882,7 @@ void SerializerForBackgroundCompilation::ProcessApiCall(
if (hint->IsUndefined()) {
// The receiver is the global proxy.
Handle<JSGlobalProxy> global_proxy =
- broker()->native_context().global_proxy_object().object();
+ broker()->target_native_context().global_proxy_object().object();
ProcessReceiverMapForApiCall(
target_template_info,
handle(global_proxy->map(), broker()->isolate()));
@@ -1596,40 +1902,62 @@ void SerializerForBackgroundCompilation::ProcessApiCall(
}
void SerializerForBackgroundCompilation::ProcessReceiverMapForApiCall(
- FunctionTemplateInfoRef& target, Handle<Map> receiver) {
- if (receiver->is_access_check_needed()) {
- return;
+ FunctionTemplateInfoRef target, Handle<Map> receiver) {
+ if (!receiver->is_access_check_needed()) {
+ MapRef receiver_map(broker(), receiver);
+ TRACE_BROKER(broker(), "Serializing holder for target:" << target);
+ target.LookupHolderOfExpectedType(receiver_map,
+ SerializationPolicy::kSerializeIfNeeded);
}
+}
- MapRef receiver_map(broker(), receiver);
- TRACE_BROKER(broker(), "Serializing holder for target:" << target);
-
- target.LookupHolderOfExpectedType(receiver_map, true);
+void SerializerForBackgroundCompilation::ProcessHintsForObjectCreate(
+ Hints const& prototype) {
+ for (Handle<Object> constant_handle : prototype.constants()) {
+ ObjectRef constant(broker(), constant_handle);
+ if (constant.IsJSObject()) constant.AsJSObject().SerializeObjectCreateMap();
+ }
}
void SerializerForBackgroundCompilation::ProcessBuiltinCall(
- Handle<SharedFunctionInfo> target, const HintsVector& arguments) {
+ Handle<SharedFunctionInfo> target, const HintsVector& arguments,
+ SpeculationMode speculation_mode) {
DCHECK(target->HasBuiltinId());
const int builtin_id = target->builtin_id();
const char* name = Builtins::name(builtin_id);
TRACE_BROKER(broker(), "Serializing for call to builtin " << name);
switch (builtin_id) {
+ case Builtins::kObjectCreate: {
+ if (arguments.size() >= 2) {
+ ProcessHintsForObjectCreate(arguments[1]);
+ } else {
+ ProcessHintsForObjectCreate(Hints::SingleConstant(
+ broker()->isolate()->factory()->undefined_value(), zone()));
+ }
+ break;
+ }
case Builtins::kPromisePrototypeCatch: {
// For JSCallReducer::ReducePromisePrototypeCatch.
- CHECK_GE(arguments.size(), 1);
- ProcessMapHintsForPromises(arguments[0]);
+ if (speculation_mode != SpeculationMode::kDisallowSpeculation) {
+ CHECK_GE(arguments.size(), 1);
+ ProcessMapHintsForPromises(arguments[0]);
+ }
break;
}
case Builtins::kPromisePrototypeFinally: {
// For JSCallReducer::ReducePromisePrototypeFinally.
- CHECK_GE(arguments.size(), 1);
- ProcessMapHintsForPromises(arguments[0]);
+ if (speculation_mode != SpeculationMode::kDisallowSpeculation) {
+ CHECK_GE(arguments.size(), 1);
+ ProcessMapHintsForPromises(arguments[0]);
+ }
break;
}
case Builtins::kPromisePrototypeThen: {
// For JSCallReducer::ReducePromisePrototypeThen.
- CHECK_GE(arguments.size(), 1);
- ProcessMapHintsForPromises(arguments[0]);
+ if (speculation_mode != SpeculationMode::kDisallowSpeculation) {
+ CHECK_GE(arguments.size(), 1);
+ ProcessMapHintsForPromises(arguments[0]);
+ }
break;
}
case Builtins::kPromiseResolveTrampoline:
@@ -1648,30 +1976,142 @@ void SerializerForBackgroundCompilation::ProcessBuiltinCall(
ProcessHintsForPromiseResolve(resolution_hints);
}
break;
- case Builtins::kRegExpPrototypeTest: {
+ case Builtins::kRegExpPrototypeTest:
// For JSCallReducer::ReduceRegExpPrototypeTest.
- if (arguments.size() >= 1) {
+ if (arguments.size() >= 1 &&
+ speculation_mode != SpeculationMode::kDisallowSpeculation) {
Hints const& regexp_hints = arguments[0];
ProcessHintsForRegExpTest(regexp_hints);
}
break;
- }
+ case Builtins::kArrayEvery:
+ case Builtins::kArrayFilter:
+ case Builtins::kArrayForEach:
+ case Builtins::kArrayPrototypeFind:
+ case Builtins::kArrayPrototypeFindIndex:
+ case Builtins::kArrayMap:
+ case Builtins::kArrayReduce:
+ case Builtins::kArrayReduceRight:
+ case Builtins::kArraySome:
+ if (arguments.size() >= 2 &&
+ speculation_mode != SpeculationMode::kDisallowSpeculation) {
+ Hints const& callback_hints = arguments[1];
+ ProcessHintsForFunctionCall(callback_hints);
+ }
+ break;
+ case Builtins::kFunctionPrototypeApply:
case Builtins::kFunctionPrototypeCall:
+ case Builtins::kPromiseConstructor:
+ // TODO(mslekova): Since the reducer for all these introduce a
+ // JSCall/JSConstruct that will again get optimized by the JSCallReducer,
+ // we basically might have to do all the serialization that we do for that
+ // here as well. The only difference is that the new JSCall/JSConstruct
+ // has speculation disabled, causing the JSCallReducer to do much less
+ // work. To account for that, ProcessCallOrConstruct should have a way of
+ // taking the speculation mode as an argument rather than getting that
+ // from the feedback. (Also applies to Reflect.apply and
+ // Reflect.construct.)
if (arguments.size() >= 1) {
- Hints const& target_hints = arguments[0];
- ProcessHintsForFunctionCall(target_hints);
+ ProcessHintsForFunctionCall(arguments[0]);
+ }
+ break;
+ case Builtins::kReflectApply:
+ case Builtins::kReflectConstruct:
+ if (arguments.size() >= 2) {
+ ProcessHintsForFunctionCall(arguments[1]);
+ }
+ break;
+ case Builtins::kObjectPrototypeIsPrototypeOf:
+ if (arguments.size() >= 2) {
+ ProcessHintsForHasInPrototypeChain(arguments[1]);
}
break;
+ case Builtins::kFunctionPrototypeHasInstance:
+ // For JSCallReducer::ReduceFunctionPrototypeHasInstance.
+ if (arguments.size() >= 2) {
+ ProcessHintsForOrdinaryHasInstance(arguments[0], arguments[1]);
+ }
+ break;
+ case Builtins::kFastFunctionPrototypeBind:
+ if (arguments.size() >= 1 &&
+ speculation_mode != SpeculationMode::kDisallowSpeculation) {
+ ProcessHintsForFunctionBind(arguments[0]);
+ }
+ break;
+ case Builtins::kObjectGetPrototypeOf:
+ case Builtins::kReflectGetPrototypeOf:
+ if (arguments.size() >= 2) {
+ ProcessHintsForObjectGetPrototype(arguments[1]);
+ } else {
+ Hints undefined_hint = Hints::SingleConstant(
+ broker()->isolate()->factory()->undefined_value(), zone());
+ ProcessHintsForObjectGetPrototype(undefined_hint);
+ }
+ break;
+ case Builtins::kObjectPrototypeGetProto:
+ if (arguments.size() >= 1) {
+ ProcessHintsForObjectGetPrototype(arguments[0]);
+ }
+ break;
+ case Builtins::kMapIteratorPrototypeNext:
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kOrderedHashTableHealIndex));
+ ObjectRef(broker(),
+ broker()->isolate()->factory()->empty_ordered_hash_map());
+ break;
+ case Builtins::kSetIteratorPrototypeNext:
+ ObjectRef(broker(), broker()->isolate()->builtins()->builtin_handle(
+ Builtins::kOrderedHashTableHealIndex));
+ ObjectRef(broker(),
+ broker()->isolate()->factory()->empty_ordered_hash_set());
+ break;
default:
break;
}
}
+void SerializerForBackgroundCompilation::ProcessHintsForOrdinaryHasInstance(
+ Hints const& constructor_hints, Hints const& instance_hints) {
+ bool walk_prototypes = false;
+ for (Handle<Object> constructor : constructor_hints.constants()) {
+ // For JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance.
+ if (constructor->IsHeapObject()) {
+ ProcessConstantForOrdinaryHasInstance(
+ HeapObjectRef(broker(), constructor), &walk_prototypes);
+ }
+ }
+ // For JSNativeContextSpecialization::ReduceJSHasInPrototypeChain.
+ if (walk_prototypes) ProcessHintsForHasInPrototypeChain(instance_hints);
+}
+
+void SerializerForBackgroundCompilation::ProcessHintsForHasInPrototypeChain(
+ Hints const& instance_hints) {
+ auto processMap = [&](Handle<Map> map_handle) {
+ MapRef map(broker(), map_handle);
+ while (map.IsJSObjectMap()) {
+ map.SerializePrototype();
+ map = map.prototype().map();
+ }
+ };
+
+ for (auto hint : instance_hints.constants()) {
+ if (!hint->IsHeapObject()) continue;
+ Handle<HeapObject> object(Handle<HeapObject>::cast(hint));
+ processMap(handle(object->map(), broker()->isolate()));
+ }
+ for (auto map_hint : instance_hints.maps()) {
+ processMap(map_hint);
+ }
+}
+
void SerializerForBackgroundCompilation::ProcessHintsForPromiseResolve(
Hints const& resolution_hints) {
auto processMap = [&](Handle<Map> map) {
- broker()->CreateAccessInfoForLoadingThen(MapRef(broker(), map),
- dependencies());
+ broker()->GetPropertyAccessInfo(
+ MapRef(broker(), map),
+ NameRef(broker(), broker()->isolate()->factory()->then_string()),
+ AccessMode::kLoad, dependencies(),
+ SerializationPolicy::kSerializeIfNeeded);
};
for (auto hint : resolution_hints.constants()) {
@@ -1701,15 +2141,18 @@ void SerializerForBackgroundCompilation::ProcessMapHintsForPromises(
PropertyAccessInfo SerializerForBackgroundCompilation::ProcessMapForRegExpTest(
MapRef map) {
- PropertyAccessInfo ai_exec =
- broker()->CreateAccessInfoForLoadingExec(map, dependencies());
+ PropertyAccessInfo ai_exec = broker()->GetPropertyAccessInfo(
+ map, NameRef(broker(), broker()->isolate()->factory()->exec_string()),
+ AccessMode::kLoad, dependencies(),
+ SerializationPolicy::kSerializeIfNeeded);
Handle<JSObject> holder;
if (ai_exec.IsDataConstant() && ai_exec.holder().ToHandle(&holder)) {
// The property is on the prototype chain.
JSObjectRef holder_ref(broker(), holder);
- holder_ref.GetOwnProperty(ai_exec.field_representation(),
- ai_exec.field_index(), true);
+ holder_ref.GetOwnDataProperty(ai_exec.field_representation(),
+ ai_exec.field_index(),
+ SerializationPolicy::kSerializeIfNeeded);
}
return ai_exec;
}
@@ -1726,8 +2169,9 @@ void SerializerForBackgroundCompilation::ProcessHintsForRegExpTest(
if (ai_exec.IsDataConstant() && !ai_exec.holder().ToHandle(&holder)) {
// The property is on the object itself.
JSObjectRef holder_ref(broker(), regexp);
- holder_ref.GetOwnProperty(ai_exec.field_representation(),
- ai_exec.field_index(), true);
+ holder_ref.GetOwnDataProperty(ai_exec.field_representation(),
+ ai_exec.field_index(),
+ SerializationPolicy::kSerializeIfNeeded);
}
}
@@ -1740,9 +2184,50 @@ void SerializerForBackgroundCompilation::ProcessHintsForRegExpTest(
void SerializerForBackgroundCompilation::ProcessHintsForFunctionCall(
Hints const& target_hints) {
for (auto constant : target_hints.constants()) {
+ if (constant->IsJSFunction()) JSFunctionRef(broker(), constant).Serialize();
+ }
+}
+
+namespace {
+void ProcessMapForFunctionBind(MapRef map) {
+ map.SerializePrototype();
+ int min_nof_descriptors = i::Max(JSFunction::kLengthDescriptorIndex,
+ JSFunction::kNameDescriptorIndex) +
+ 1;
+ if (map.NumberOfOwnDescriptors() >= min_nof_descriptors) {
+ map.SerializeOwnDescriptor(JSFunction::kLengthDescriptorIndex);
+ map.SerializeOwnDescriptor(JSFunction::kNameDescriptorIndex);
+ }
+}
+} // namespace
+
+void SerializerForBackgroundCompilation::ProcessHintsForFunctionBind(
+ Hints const& receiver_hints) {
+ for (auto constant : receiver_hints.constants()) {
if (!constant->IsJSFunction()) continue;
- JSFunctionRef func(broker(), constant);
- func.Serialize();
+ JSFunctionRef function(broker(), constant);
+ function.Serialize();
+ ProcessMapForFunctionBind(function.map());
+ }
+
+ for (auto map : receiver_hints.maps()) {
+ if (!map->IsJSFunctionMap()) continue;
+ MapRef map_ref(broker(), map);
+ ProcessMapForFunctionBind(map_ref);
+ }
+}
+
+void SerializerForBackgroundCompilation::ProcessHintsForObjectGetPrototype(
+ Hints const& object_hints) {
+ for (auto constant : object_hints.constants()) {
+ if (!constant->IsHeapObject()) continue;
+ HeapObjectRef object(broker(), constant);
+ object.map().SerializePrototype();
+ }
+
+ for (auto map : object_hints.maps()) {
+ MapRef map_ref(broker(), map);
+ map_ref.SerializePrototype();
}
}
@@ -1791,79 +2276,77 @@ void SerializerForBackgroundCompilation::VisitSwitchOnSmiNoFeedback(
void SerializerForBackgroundCompilation::VisitSwitchOnGeneratorState(
interpreter::BytecodeArrayIterator* iterator) {
- for (const auto& target : GetBytecodeAnalysis(false).resume_jump_targets()) {
+ for (const auto& target : GetBytecodeAnalysis().resume_jump_targets()) {
ContributeToJumpTargetEnvironment(target.target_offset());
}
}
void SerializerForBackgroundCompilation::Environment::ExportRegisterHints(
- interpreter::Register first, size_t count, HintsVector& dst) {
+ interpreter::Register first, size_t count, HintsVector* dst) {
const int reg_base = first.index();
for (int i = 0; i < static_cast<int>(count); ++i) {
- dst.push_back(register_hints(interpreter::Register(reg_base + i)));
+ dst->push_back(register_hints(interpreter::Register(reg_base + i)));
}
}
void SerializerForBackgroundCompilation::VisitConstruct(
BytecodeArrayIterator* iterator) {
- const Hints& callee =
+ Hints const& new_target = environment()->accumulator_hints();
+ Hints const& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
interpreter::Register first_reg = iterator->GetRegisterOperand(1);
size_t reg_count = iterator->GetRegisterCountOperand(2);
FeedbackSlot slot = iterator->GetSlotOperand(3);
- const Hints& new_target = environment()->accumulator_hints();
HintsVector arguments(zone());
- environment()->ExportRegisterHints(first_reg, reg_count, arguments);
+ environment()->ExportRegisterHints(first_reg, reg_count, &arguments);
ProcessCallOrConstruct(callee, new_target, arguments, slot);
}
void SerializerForBackgroundCompilation::VisitConstructWithSpread(
BytecodeArrayIterator* iterator) {
- const Hints& callee =
+ Hints const& new_target = environment()->accumulator_hints();
+ Hints const& callee =
environment()->register_hints(iterator->GetRegisterOperand(0));
interpreter::Register first_reg = iterator->GetRegisterOperand(1);
size_t reg_count = iterator->GetRegisterCountOperand(2);
FeedbackSlot slot = iterator->GetSlotOperand(3);
- const Hints& new_target = environment()->accumulator_hints();
HintsVector arguments(zone());
- environment()->ExportRegisterHints(first_reg, reg_count, arguments);
+ environment()->ExportRegisterHints(first_reg, reg_count, &arguments);
ProcessCallOrConstruct(callee, new_target, arguments, slot, true);
}
-GlobalAccessFeedback const*
-SerializerForBackgroundCompilation::ProcessFeedbackForGlobalAccess(
- FeedbackSlot slot) {
- if (slot.IsInvalid()) return nullptr;
- if (environment()->function().feedback_vector().is_null()) return nullptr;
- FeedbackSource source(environment()->function().feedback_vector(), slot);
+void SerializerForBackgroundCompilation::ProcessGlobalAccess(FeedbackSlot slot,
+ bool is_load) {
+ if (slot.IsInvalid() || feedback_vector().is_null()) return;
+ FeedbackSource source(feedback_vector(), slot);
+ ProcessedFeedback const& feedback =
+ broker()->ProcessFeedbackForGlobalAccess(source);
- if (broker()->HasFeedback(source)) {
- return broker()->GetGlobalAccessFeedback(source);
+ if (is_load) {
+ environment()->accumulator_hints().Clear();
+ if (feedback.kind() == ProcessedFeedback::kGlobalAccess) {
+ // We may be able to contribute to accumulator constant hints.
+ base::Optional<ObjectRef> value =
+ feedback.AsGlobalAccess().GetConstantHint();
+ if (value.has_value()) {
+ environment()->accumulator_hints().AddConstant(value->object());
+ }
+ } else {
+ DCHECK(feedback.IsInsufficient());
+ }
}
-
- const GlobalAccessFeedback* feedback =
- broker()->ProcessFeedbackForGlobalAccess(source);
- broker()->SetFeedback(source, feedback);
- return feedback;
}
void SerializerForBackgroundCompilation::VisitLdaGlobal(
BytecodeArrayIterator* iterator) {
+ NameRef(broker(),
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
FeedbackSlot slot = iterator->GetSlotOperand(1);
-
- environment()->accumulator_hints().Clear();
- GlobalAccessFeedback const* feedback = ProcessFeedbackForGlobalAccess(slot);
- if (feedback != nullptr) {
- // We may be able to contribute to accumulator constant hints.
- base::Optional<ObjectRef> value = feedback->GetConstantHint();
- if (value.has_value()) {
- environment()->accumulator_hints().AddConstant(value->object());
- }
- }
+ ProcessGlobalAccess(slot, true);
}
void SerializerForBackgroundCompilation::VisitLdaGlobalInsideTypeof(
@@ -1871,6 +2354,20 @@ void SerializerForBackgroundCompilation::VisitLdaGlobalInsideTypeof(
VisitLdaGlobal(iterator);
}
+void SerializerForBackgroundCompilation::VisitLdaLookupSlot(
+ BytecodeArrayIterator* iterator) {
+ ObjectRef(broker(),
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
+ environment()->accumulator_hints().Clear();
+}
+
+void SerializerForBackgroundCompilation::VisitLdaLookupSlotInsideTypeof(
+ BytecodeArrayIterator* iterator) {
+ ObjectRef(broker(),
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
+ environment()->accumulator_hints().Clear();
+}
+
void SerializerForBackgroundCompilation::ProcessCheckContextExtensions(
int depth) {
// for BytecodeGraphBuilder::CheckContextExtensions.
@@ -1900,18 +2397,22 @@ void SerializerForBackgroundCompilation::VisitLdaLookupGlobalSlotInsideTypeof(
void SerializerForBackgroundCompilation::VisitStaGlobal(
BytecodeArrayIterator* iterator) {
+ NameRef(broker(),
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
FeedbackSlot slot = iterator->GetSlotOperand(1);
- ProcessFeedbackForGlobalAccess(slot);
+ ProcessGlobalAccess(slot, false);
}
void SerializerForBackgroundCompilation::ProcessLdaLookupContextSlot(
BytecodeArrayIterator* iterator) {
const int slot_index = iterator->GetIndexOperand(1);
const int depth = iterator->GetUnsignedImmediateOperand(2);
+ NameRef(broker(),
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
ProcessCheckContextExtensions(depth);
- Hints& context_hints = environment()->current_context_hints();
environment()->accumulator_hints().Clear();
- ProcessContextAccess(context_hints, slot_index, depth, kIgnoreSlot);
+ ProcessContextAccess(environment()->current_context_hints(), slot_index,
+ depth, kIgnoreSlot);
}
void SerializerForBackgroundCompilation::VisitLdaLookupContextSlot(
@@ -1924,6 +2425,7 @@ void SerializerForBackgroundCompilation::VisitLdaLookupContextSlotInsideTypeof(
ProcessLdaLookupContextSlot(iterator);
}
+// TODO(neis): Avoid duplicating this.
namespace {
template <class MapContainer>
MapHandles GetRelevantReceiverMaps(Isolate* isolate, MapContainer const& maps) {
@@ -1939,220 +2441,334 @@ MapHandles GetRelevantReceiverMaps(Isolate* isolate, MapContainer const& maps) {
}
} // namespace
-ElementAccessFeedback const*
-SerializerForBackgroundCompilation::ProcessFeedbackMapsForElementAccess(
- const MapHandles& maps, AccessMode mode,
- KeyedAccessMode const& keyed_mode) {
- ElementAccessFeedback const* result =
- broker()->ProcessFeedbackMapsForElementAccess(maps, keyed_mode);
- for (ElementAccessFeedback::MapIterator it = result->all_maps(broker());
- !it.done(); it.advance()) {
- switch (mode) {
- case AccessMode::kHas:
- case AccessMode::kLoad:
- it.current().SerializeForElementLoad();
- break;
- case AccessMode::kStore:
- it.current().SerializeForElementStore();
- break;
- case AccessMode::kStoreInLiteral:
- // This operation is fairly local and simple, nothing to serialize.
- break;
- }
+void SerializerForBackgroundCompilation::ProcessCompareOperation(
+ FeedbackSlot slot) {
+ if (slot.IsInvalid() || feedback_vector().is_null()) return;
+ FeedbackSource source(environment()->function().feedback_vector(), slot);
+ ProcessedFeedback const& feedback =
+ broker()->ProcessFeedbackForCompareOperation(source);
+ if (BailoutOnUninitialized(feedback)) return;
+ environment()->accumulator_hints().Clear();
+}
+
+void SerializerForBackgroundCompilation::ProcessForIn(FeedbackSlot slot) {
+ if (slot.IsInvalid() || feedback_vector().is_null()) return;
+ FeedbackSource source(feedback_vector(), slot);
+ ProcessedFeedback const& feedback = broker()->ProcessFeedbackForForIn(source);
+ if (BailoutOnUninitialized(feedback)) return;
+ environment()->accumulator_hints().Clear();
+}
+
+void SerializerForBackgroundCompilation::ProcessUnaryOrBinaryOperation(
+ FeedbackSlot slot, bool honor_bailout_on_uninitialized) {
+ if (slot.IsInvalid() || feedback_vector().is_null()) return;
+ FeedbackSource source(feedback_vector(), slot);
+ // Internally V8 uses binary op feedback also for unary ops.
+ ProcessedFeedback const& feedback =
+ broker()->ProcessFeedbackForBinaryOperation(source);
+ if (honor_bailout_on_uninitialized && BailoutOnUninitialized(feedback)) {
+ return;
}
- return result;
+ environment()->accumulator_hints().Clear();
}
-NamedAccessFeedback const*
-SerializerForBackgroundCompilation::ProcessFeedbackMapsForNamedAccess(
- const MapHandles& maps, AccessMode mode, NameRef const& name) {
- ZoneVector<PropertyAccessInfo> access_infos(broker()->zone());
- for (Handle<Map> map : maps) {
- MapRef map_ref(broker(), map);
- ProcessMapForNamedPropertyAccess(map_ref, name);
- AccessInfoFactory access_info_factory(broker(), dependencies(),
- broker()->zone());
- PropertyAccessInfo info(access_info_factory.ComputePropertyAccessInfo(
- map, name.object(), mode));
- access_infos.push_back(info);
-
- // TODO(turbofan): We want to take receiver hints into account as well,
- // not only the feedback maps.
- // For JSNativeContextSpecialization::InlinePropertySetterCall
- // and InlinePropertyGetterCall.
- if (info.IsAccessorConstant() && !info.constant().is_null()) {
- if (info.constant()->IsJSFunction()) {
- // For JSCallReducer::ReduceCallApiFunction.
- Handle<SharedFunctionInfo> sfi(
- handle(Handle<JSFunction>::cast(info.constant())->shared(),
- broker()->isolate()));
- if (sfi->IsApiFunction()) {
- FunctionTemplateInfoRef fti_ref(
- broker(), handle(sfi->get_api_func_data(), broker()->isolate()));
- if (fti_ref.has_call_code()) fti_ref.SerializeCallCode();
- ProcessReceiverMapForApiCall(fti_ref, map);
- }
- } else {
+PropertyAccessInfo
+SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
+ MapRef receiver_map, NameRef const& name, AccessMode access_mode,
+ base::Optional<JSObjectRef> receiver, Hints* new_accumulator_hints) {
+ // For JSNativeContextSpecialization::InferReceiverRootMap
+ receiver_map.SerializeRootMap();
+
+ // For JSNativeContextSpecialization::ReduceNamedAccess.
+ if (receiver_map.IsMapOfTargetGlobalProxy()) {
+ broker()->target_native_context().global_proxy_object().GetPropertyCell(
+ name, SerializationPolicy::kSerializeIfNeeded);
+ }
+
+ PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
+ receiver_map, name, access_mode, dependencies(),
+ SerializationPolicy::kSerializeIfNeeded);
+
+ // For JSNativeContextSpecialization::InlinePropertySetterCall
+ // and InlinePropertyGetterCall.
+ if (access_info.IsAccessorConstant() && !access_info.constant().is_null()) {
+ if (access_info.constant()->IsJSFunction()) {
+ JSFunctionRef function(broker(), access_info.constant());
+
+ // For JSCallReducer::ReduceJSCall.
+ function.Serialize();
+
+ // For JSCallReducer::ReduceCallApiFunction.
+ Handle<SharedFunctionInfo> sfi = function.shared().object();
+ if (sfi->IsApiFunction()) {
FunctionTemplateInfoRef fti_ref(
- broker(), Handle<FunctionTemplateInfo>::cast(info.constant()));
+ broker(), handle(sfi->get_api_func_data(), broker()->isolate()));
if (fti_ref.has_call_code()) fti_ref.SerializeCallCode();
+ ProcessReceiverMapForApiCall(fti_ref, receiver_map.object());
}
+ } else if (access_info.constant()->IsJSBoundFunction()) {
+ JSBoundFunctionRef function(broker(), access_info.constant());
+
+ // For JSCallReducer::ReduceJSCall.
+ function.Serialize();
+ } else {
+ FunctionTemplateInfoRef fti(broker(), access_info.constant());
+ if (fti.has_call_code()) fti.SerializeCallCode();
}
}
- DCHECK(!access_infos.empty());
- return new (broker()->zone()) NamedAccessFeedback(name, access_infos);
-}
+ // For PropertyAccessBuilder::TryBuildLoadConstantDataField
+ if (access_mode == AccessMode::kLoad) {
+ if (access_info.IsDataConstant()) {
+ base::Optional<JSObjectRef> holder;
+ Handle<JSObject> prototype;
+ if (access_info.holder().ToHandle(&prototype)) {
+ holder = JSObjectRef(broker(), prototype);
+ } else {
+ CHECK_IMPLIES(receiver.has_value(),
+ receiver->map().equals(receiver_map));
+ holder = receiver;
+ }
-void SerializerForBackgroundCompilation::ProcessFeedbackForPropertyAccess(
- FeedbackSlot slot, AccessMode mode, base::Optional<NameRef> static_name) {
- if (slot.IsInvalid()) return;
- if (environment()->function().feedback_vector().is_null()) return;
+ if (holder.has_value()) {
+ base::Optional<ObjectRef> constant(holder->GetOwnDataProperty(
+ access_info.field_representation(), access_info.field_index(),
+ SerializationPolicy::kSerializeIfNeeded));
+ if (constant.has_value()) {
+ new_accumulator_hints->AddConstant(constant->object());
+ }
+ }
+ }
+ }
+
+ return access_info;
+}
- FeedbackNexus nexus(environment()->function().feedback_vector(), slot);
- FeedbackSource source(nexus);
- if (broker()->HasFeedback(source)) return;
+void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
+ BytecodeArrayIterator* iterator) {
+ Hints const& key = environment()->accumulator_hints();
+ Hints const& receiver =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ FeedbackSlot slot = iterator->GetSlotOperand(1);
+ ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kLoad, true);
+}
- if (nexus.ic_state() == UNINITIALIZED) {
- broker()->SetFeedback(source,
- new (broker()->zone()) InsufficientFeedback());
+void SerializerForBackgroundCompilation::ProcessKeyedPropertyAccess(
+ Hints const& receiver, Hints const& key, FeedbackSlot slot,
+ AccessMode access_mode, bool honor_bailout_on_uninitialized) {
+ if (slot.IsInvalid() || feedback_vector().is_null()) return;
+ FeedbackSource source(feedback_vector(), slot);
+ ProcessedFeedback const& feedback =
+ broker()->ProcessFeedbackForPropertyAccess(source, access_mode,
+ base::nullopt);
+ if (honor_bailout_on_uninitialized && BailoutOnUninitialized(feedback)) {
return;
}
- MapHandles maps;
- if (nexus.ExtractMaps(&maps) == 0) { // Megamorphic.
- broker()->SetFeedback(source, nullptr);
- return;
+ Hints new_accumulator_hints(zone());
+ switch (feedback.kind()) {
+ case ProcessedFeedback::kElementAccess:
+ ProcessElementAccess(receiver, key, feedback.AsElementAccess(),
+ access_mode);
+ break;
+ case ProcessedFeedback::kNamedAccess:
+ ProcessNamedAccess(receiver, feedback.AsNamedAccess(), access_mode,
+ &new_accumulator_hints);
+ break;
+ case ProcessedFeedback::kInsufficient:
+ break;
+ default:
+ UNREACHABLE();
}
- maps = GetRelevantReceiverMaps(broker()->isolate(), maps);
- if (maps.empty()) {
- broker()->SetFeedback(source,
- new (broker()->zone()) InsufficientFeedback());
- return;
+ if (access_mode == AccessMode::kLoad) {
+ environment()->accumulator_hints().Clear();
+ environment()->accumulator_hints().Add(new_accumulator_hints);
+ } else {
+ DCHECK(new_accumulator_hints.IsEmpty());
+ }
+}
+
+void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess(
+ Hints receiver, NameRef const& name, FeedbackSlot slot,
+ AccessMode access_mode) {
+ if (slot.IsInvalid() || feedback_vector().is_null()) return;
+ FeedbackSource source(feedback_vector(), slot);
+ ProcessedFeedback const& feedback =
+ broker()->ProcessFeedbackForPropertyAccess(source, access_mode, name);
+ if (BailoutOnUninitialized(feedback)) return;
+
+ Hints new_accumulator_hints(zone());
+ switch (feedback.kind()) {
+ case ProcessedFeedback::kNamedAccess:
+ DCHECK(name.equals(feedback.AsNamedAccess().name()));
+ ProcessNamedAccess(receiver, feedback.AsNamedAccess(), access_mode,
+ &new_accumulator_hints);
+ break;
+ case ProcessedFeedback::kInsufficient:
+ break;
+ default:
+ UNREACHABLE();
}
- ProcessedFeedback const* processed = nullptr;
- base::Optional<NameRef> name =
- static_name.has_value() ? static_name : broker()->GetNameFeedback(nexus);
- if (name.has_value()) {
- processed = ProcessFeedbackMapsForNamedAccess(maps, mode, *name);
- } else if (nexus.GetKeyType() == ELEMENT) {
- DCHECK_NE(nexus.ic_state(), MEGAMORPHIC);
- processed = ProcessFeedbackMapsForElementAccess(
- maps, mode, KeyedAccessMode::FromNexus(nexus));
+ if (access_mode == AccessMode::kLoad) {
+ environment()->accumulator_hints().Clear();
+ environment()->accumulator_hints().Add(new_accumulator_hints);
+ } else {
+ DCHECK(new_accumulator_hints.IsEmpty());
}
- broker()->SetFeedback(source, processed);
}
-void SerializerForBackgroundCompilation::ProcessKeyedPropertyAccess(
- Hints const& receiver, Hints const& key, FeedbackSlot slot,
- AccessMode mode) {
- if (BailoutOnUninitialized(slot)) return;
- ProcessFeedbackForPropertyAccess(slot, mode, base::nullopt);
+void SerializerForBackgroundCompilation::ProcessNamedAccess(
+ Hints receiver, NamedAccessFeedback const& feedback, AccessMode access_mode,
+ Hints* new_accumulator_hints) {
+ for (Handle<Map> map : feedback.AsNamedAccess().maps()) {
+ MapRef map_ref(broker(), map);
+ ProcessMapForNamedPropertyAccess(map_ref, feedback.name(), access_mode,
+ base::nullopt, new_accumulator_hints);
+ }
+
+ for (Handle<Map> map :
+ GetRelevantReceiverMaps(broker()->isolate(), receiver.maps())) {
+ MapRef map_ref(broker(), map);
+ ProcessMapForNamedPropertyAccess(map_ref, feedback.name(), access_mode,
+ base::nullopt, new_accumulator_hints);
+ }
+
+ JSGlobalProxyRef global_proxy =
+ broker()->target_native_context().global_proxy_object();
+ for (Handle<Object> hint : receiver.constants()) {
+ ObjectRef object(broker(), hint);
+ if (access_mode == AccessMode::kLoad && object.IsJSObject()) {
+ MapRef map_ref = object.AsJSObject().map();
+ ProcessMapForNamedPropertyAccess(map_ref, feedback.name(), access_mode,
+ object.AsJSObject(),
+ new_accumulator_hints);
+ }
+ // For JSNativeContextSpecialization::ReduceNamedAccessFromNexus.
+ if (object.equals(global_proxy)) {
+ // TODO(neis): Record accumulator hint? Also for string.length and maybe
+ // more.
+ global_proxy.GetPropertyCell(feedback.name(),
+ SerializationPolicy::kSerializeIfNeeded);
+ }
+ // For JSNativeContextSpecialization::ReduceJSLoadNamed.
+ if (access_mode == AccessMode::kLoad && object.IsJSFunction() &&
+ feedback.name().equals(ObjectRef(
+ broker(), broker()->isolate()->factory()->prototype_string()))) {
+ JSFunctionRef function = object.AsJSFunction();
+ function.Serialize();
+ if (new_accumulator_hints != nullptr && function.has_prototype()) {
+ new_accumulator_hints->AddConstant(function.prototype().object());
+ }
+ }
+ }
+}
+
+void SerializerForBackgroundCompilation::ProcessElementAccess(
+ Hints receiver, Hints key, ElementAccessFeedback const& feedback,
+ AccessMode access_mode) {
+ for (auto const& group : feedback.transition_groups()) {
+ for (Handle<Map> map_handle : group) {
+ MapRef map(broker(), map_handle);
+ switch (access_mode) {
+ case AccessMode::kHas:
+ case AccessMode::kLoad:
+ map.SerializeForElementLoad();
+ break;
+ case AccessMode::kStore:
+ map.SerializeForElementStore();
+ break;
+ case AccessMode::kStoreInLiteral:
+ // This operation is fairly local and simple, nothing to serialize.
+ break;
+ }
+ }
+ }
for (Handle<Object> hint : receiver.constants()) {
ObjectRef receiver_ref(broker(), hint);
+ // For JSNativeContextSpecialization::InferReceiverRootMap
+ if (receiver_ref.IsHeapObject()) {
+ receiver_ref.AsHeapObject().map().SerializeRootMap();
+ }
+
// For JSNativeContextSpecialization::ReduceElementAccess.
if (receiver_ref.IsJSTypedArray()) {
receiver_ref.AsJSTypedArray().Serialize();
}
- // For JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant.
- if (mode == AccessMode::kLoad || mode == AccessMode::kHas) {
+ // For JSNativeContextSpecialization::ReduceElementLoadFromHeapConstant.
+ if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
for (Handle<Object> hint : key.constants()) {
ObjectRef key_ref(broker(), hint);
// TODO(neis): Do this for integer-HeapNumbers too?
if (key_ref.IsSmi() && key_ref.AsSmi() >= 0) {
base::Optional<ObjectRef> element =
- receiver_ref.GetOwnConstantElement(key_ref.AsSmi(), true);
+ receiver_ref.GetOwnConstantElement(
+ key_ref.AsSmi(), SerializationPolicy::kSerializeIfNeeded);
if (!element.has_value() && receiver_ref.IsJSArray()) {
// We didn't find a constant element, but if the receiver is a
// cow-array we can exploit the fact that any future write to the
// element will replace the whole elements storage.
- receiver_ref.AsJSArray().GetOwnCowElement(key_ref.AsSmi(), true);
+ receiver_ref.AsJSArray().GetOwnCowElement(
+ key_ref.AsSmi(), SerializationPolicy::kSerializeIfNeeded);
}
}
}
}
}
- environment()->accumulator_hints().Clear();
-}
-
-void SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
- MapRef const& map, NameRef const& name) {
- // For JSNativeContextSpecialization::ReduceNamedAccess.
- if (map.IsMapOfCurrentGlobalProxy()) {
- broker()->native_context().global_proxy_object().GetPropertyCell(name,
- true);
+ // For JSNativeContextSpecialization::InferReceiverRootMap
+ for (Handle<Map> map : receiver.maps()) {
+ MapRef map_ref(broker(), map);
+ map_ref.SerializeRootMap();
}
}
-void SerializerForBackgroundCompilation::VisitLdaKeyedProperty(
+void SerializerForBackgroundCompilation::VisitLdaNamedProperty(
BytecodeArrayIterator* iterator) {
- Hints const& key = environment()->accumulator_hints();
Hints const& receiver =
environment()->register_hints(iterator->GetRegisterOperand(0));
- FeedbackSlot slot = iterator->GetSlotOperand(1);
- ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kLoad);
+ NameRef name(broker(),
+ iterator->GetConstantForIndexOperand(1, broker()->isolate()));
+ FeedbackSlot slot = iterator->GetSlotOperand(2);
+ ProcessNamedPropertyAccess(receiver, name, slot, AccessMode::kLoad);
}
-void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess(
- Hints const& receiver, NameRef const& name, FeedbackSlot slot,
- AccessMode mode) {
- if (BailoutOnUninitialized(slot)) return;
- ProcessFeedbackForPropertyAccess(slot, mode, name);
-
- for (Handle<Map> map :
- GetRelevantReceiverMaps(broker()->isolate(), receiver.maps())) {
- ProcessMapForNamedPropertyAccess(MapRef(broker(), map), name);
- }
-
- JSGlobalProxyRef global_proxy =
- broker()->native_context().global_proxy_object();
-
- for (Handle<Object> hint : receiver.constants()) {
- ObjectRef object(broker(), hint);
- // For JSNativeContextSpecialization::ReduceNamedAccessFromNexus.
- if (object.equals(global_proxy)) {
- global_proxy.GetPropertyCell(name, true);
- }
- // For JSNativeContextSpecialization::ReduceJSLoadNamed.
- if (mode == AccessMode::kLoad && object.IsJSFunction() &&
- name.equals(ObjectRef(
- broker(), broker()->isolate()->factory()->prototype_string()))) {
- object.AsJSFunction().Serialize();
- }
- }
-
- environment()->accumulator_hints().Clear();
+// TODO(neis): Do feedback-independent serialization also for *NoFeedback
+// bytecodes.
+void SerializerForBackgroundCompilation::VisitLdaNamedPropertyNoFeedback(
+ BytecodeArrayIterator* iterator) {
+ NameRef(broker(),
+ iterator->GetConstantForIndexOperand(1, broker()->isolate()));
}
-void SerializerForBackgroundCompilation::ProcessNamedPropertyAccess(
- BytecodeArrayIterator* iterator, AccessMode mode) {
+void SerializerForBackgroundCompilation::VisitStaNamedProperty(
+ BytecodeArrayIterator* iterator) {
Hints const& receiver =
environment()->register_hints(iterator->GetRegisterOperand(0));
- Handle<Name> name = Handle<Name>::cast(
- iterator->GetConstantForIndexOperand(1, broker()->isolate()));
+ NameRef name(broker(),
+ iterator->GetConstantForIndexOperand(1, broker()->isolate()));
FeedbackSlot slot = iterator->GetSlotOperand(2);
- ProcessNamedPropertyAccess(receiver, NameRef(broker(), name), slot, mode);
-}
-
-void SerializerForBackgroundCompilation::VisitLdaNamedProperty(
- BytecodeArrayIterator* iterator) {
- ProcessNamedPropertyAccess(iterator, AccessMode::kLoad);
+ ProcessNamedPropertyAccess(receiver, name, slot, AccessMode::kStore);
}
-void SerializerForBackgroundCompilation::VisitStaNamedProperty(
+void SerializerForBackgroundCompilation::VisitStaNamedPropertyNoFeedback(
BytecodeArrayIterator* iterator) {
- ProcessNamedPropertyAccess(iterator, AccessMode::kStore);
+ NameRef(broker(),
+ iterator->GetConstantForIndexOperand(1, broker()->isolate()));
}
void SerializerForBackgroundCompilation::VisitStaNamedOwnProperty(
BytecodeArrayIterator* iterator) {
- ProcessNamedPropertyAccess(iterator, AccessMode::kStoreInLiteral);
+ Hints const& receiver =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ NameRef name(broker(),
+ iterator->GetConstantForIndexOperand(1, broker()->isolate()));
+ FeedbackSlot slot = iterator->GetSlotOperand(2);
+ ProcessNamedPropertyAccess(receiver, name, slot, AccessMode::kStoreInLiteral);
}
void SerializerForBackgroundCompilation::VisitTestIn(
@@ -2161,7 +2777,113 @@ void SerializerForBackgroundCompilation::VisitTestIn(
Hints const& key =
environment()->register_hints(iterator->GetRegisterOperand(0));
FeedbackSlot slot = iterator->GetSlotOperand(1);
- ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kHas);
+ ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kHas, false);
+}
+
+// For JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance.
+void SerializerForBackgroundCompilation::ProcessConstantForOrdinaryHasInstance(
+ HeapObjectRef const& constructor, bool* walk_prototypes) {
+ if (constructor.IsJSBoundFunction()) {
+ constructor.AsJSBoundFunction().Serialize();
+ ProcessConstantForInstanceOf(
+ constructor.AsJSBoundFunction().bound_target_function(),
+ walk_prototypes);
+ } else if (constructor.IsJSFunction()) {
+ constructor.AsJSFunction().Serialize();
+ *walk_prototypes =
+ *walk_prototypes ||
+ (constructor.map().has_prototype_slot() &&
+ constructor.AsJSFunction().has_prototype() &&
+ !constructor.AsJSFunction().PrototypeRequiresRuntimeLookup());
+ }
+}
+
+void SerializerForBackgroundCompilation::ProcessConstantForInstanceOf(
+ ObjectRef const& constructor, bool* walk_prototypes) {
+ if (!constructor.IsHeapObject()) return;
+ HeapObjectRef constructor_heap_object = constructor.AsHeapObject();
+
+ PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
+ constructor_heap_object.map(),
+ NameRef(broker(), broker()->isolate()->factory()->has_instance_symbol()),
+ AccessMode::kLoad, dependencies(),
+ SerializationPolicy::kSerializeIfNeeded);
+
+ if (access_info.IsNotFound()) {
+ ProcessConstantForOrdinaryHasInstance(constructor_heap_object,
+ walk_prototypes);
+ } else if (access_info.IsDataConstant()) {
+ Handle<JSObject> holder;
+ bool found_on_proto = access_info.holder().ToHandle(&holder);
+ JSObjectRef holder_ref = found_on_proto ? JSObjectRef(broker(), holder)
+ : constructor.AsJSObject();
+ base::Optional<ObjectRef> constant = holder_ref.GetOwnDataProperty(
+ access_info.field_representation(), access_info.field_index(),
+ SerializationPolicy::kSerializeIfNeeded);
+ CHECK(constant.has_value());
+ if (constant->IsJSFunction()) {
+ JSFunctionRef function = constant->AsJSFunction();
+ function.Serialize();
+ if (function.shared().HasBuiltinId() &&
+ function.shared().builtin_id() ==
+ Builtins::kFunctionPrototypeHasInstance) {
+ // For JSCallReducer::ReduceFunctionPrototypeHasInstance.
+ ProcessConstantForOrdinaryHasInstance(constructor_heap_object,
+ walk_prototypes);
+ }
+ }
+ }
+}
+
+void SerializerForBackgroundCompilation::VisitTestInstanceOf(
+ BytecodeArrayIterator* iterator) {
+ Hints const& lhs =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ Hints rhs = environment()->accumulator_hints();
+ FeedbackSlot slot = iterator->GetSlotOperand(1);
+ Hints new_accumulator_hints(zone());
+
+ if (slot.IsInvalid() || feedback_vector().is_null()) return;
+ FeedbackSource source(feedback_vector(), slot);
+ ProcessedFeedback const& feedback =
+ broker()->ProcessFeedbackForInstanceOf(source);
+
+ // Incorporate feedback (about rhs) into hints copy to simplify processing.
+ if (!feedback.IsInsufficient()) {
+ InstanceOfFeedback const& rhs_feedback = feedback.AsInstanceOf();
+ if (rhs_feedback.value().has_value()) {
+ Handle<JSObject> constructor = rhs_feedback.value()->object();
+ rhs.AddConstant(constructor);
+ }
+ }
+
+ bool walk_prototypes = false;
+ for (Handle<Object> constant : rhs.constants()) {
+ ProcessConstantForInstanceOf(ObjectRef(broker(), constant),
+ &walk_prototypes);
+ }
+ if (walk_prototypes) ProcessHintsForHasInPrototypeChain(lhs);
+
+ environment()->accumulator_hints().Clear();
+ environment()->accumulator_hints().Add(new_accumulator_hints);
+}
+
+void SerializerForBackgroundCompilation::VisitToNumeric(
+ BytecodeArrayIterator* iterator) {
+ FeedbackSlot slot = iterator->GetSlotOperand(0);
+ ProcessUnaryOrBinaryOperation(slot, false);
+}
+
+void SerializerForBackgroundCompilation::VisitToNumber(
+ BytecodeArrayIterator* iterator) {
+ FeedbackSlot slot = iterator->GetSlotOperand(0);
+ ProcessUnaryOrBinaryOperation(slot, false);
+}
+
+void SerializerForBackgroundCompilation::VisitThrowReferenceErrorIfHole(
+ BytecodeArrayIterator* iterator) {
+ ObjectRef(broker(),
+ iterator->GetConstantForIndexOperand(0, broker()->isolate()));
}
void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
@@ -2171,7 +2893,7 @@ void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
Hints const& key =
environment()->register_hints(iterator->GetRegisterOperand(1));
FeedbackSlot slot = iterator->GetSlotOperand(2);
- ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kStore);
+ ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kStore, true);
}
void SerializerForBackgroundCompilation::VisitStaInArrayLiteral(
@@ -2181,7 +2903,19 @@ void SerializerForBackgroundCompilation::VisitStaInArrayLiteral(
Hints const& key =
environment()->register_hints(iterator->GetRegisterOperand(1));
FeedbackSlot slot = iterator->GetSlotOperand(2);
- ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kStoreInLiteral);
+ ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kStoreInLiteral,
+ true);
+}
+
+void SerializerForBackgroundCompilation::VisitStaDataPropertyInLiteral(
+ BytecodeArrayIterator* iterator) {
+ Hints const& receiver =
+ environment()->register_hints(iterator->GetRegisterOperand(0));
+ Hints const& key =
+ environment()->register_hints(iterator->GetRegisterOperand(1));
+ FeedbackSlot slot = iterator->GetSlotOperand(3);
+ ProcessKeyedPropertyAccess(receiver, key, slot, AccessMode::kStoreInLiteral,
+ false);
}
#define DEFINE_CLEAR_ENVIRONMENT(name, ...) \
@@ -2239,14 +2973,44 @@ UNREACHABLE_BYTECODE_LIST(DEFINE_UNREACHABLE)
KILL_ENVIRONMENT_LIST(DEFINE_KILL)
#undef DEFINE_KILL
-#undef CLEAR_ENVIRONMENT_LIST
-#undef KILL_ENVIRONMENT_LIST
+#define DEFINE_BINARY_OP(name, ...) \
+ void SerializerForBackgroundCompilation::Visit##name( \
+ BytecodeArrayIterator* iterator) { \
+ FeedbackSlot slot = iterator->GetSlotOperand(1); \
+ ProcessUnaryOrBinaryOperation(slot, true); \
+ }
+BINARY_OP_LIST(DEFINE_BINARY_OP)
+#undef DEFINE_BINARY_OP
+
+#define DEFINE_COMPARE_OP(name, ...) \
+ void SerializerForBackgroundCompilation::Visit##name( \
+ BytecodeArrayIterator* iterator) { \
+ FeedbackSlot slot = iterator->GetSlotOperand(1); \
+ ProcessCompareOperation(slot); \
+ }
+COMPARE_OP_LIST(DEFINE_COMPARE_OP)
+#undef DEFINE_COMPARE_OP
+
+#define DEFINE_UNARY_OP(name, ...) \
+ void SerializerForBackgroundCompilation::Visit##name( \
+ BytecodeArrayIterator* iterator) { \
+ FeedbackSlot slot = iterator->GetSlotOperand(0); \
+ ProcessUnaryOrBinaryOperation(slot, true); \
+ }
+UNARY_OP_LIST(DEFINE_UNARY_OP)
+#undef DEFINE_UNARY_OP
+
+#undef BINARY_OP_LIST
#undef CLEAR_ACCUMULATOR_LIST
-#undef UNCONDITIONAL_JUMPS_LIST
+#undef CLEAR_ENVIRONMENT_LIST
+#undef COMPARE_OP_LIST
#undef CONDITIONAL_JUMPS_LIST
#undef IGNORED_BYTECODE_LIST
-#undef UNREACHABLE_BYTECODE_LIST
+#undef KILL_ENVIRONMENT_LIST
#undef SUPPORTED_BYTECODE_LIST
+#undef UNARY_OP_LIST
+#undef UNCONDITIONAL_JUMPS_LIST
+#undef UNREACHABLE_BYTECODE_LIST
} // namespace compiler
} // namespace internal
diff --git a/deps/v8/src/compiler/simd-scalar-lowering.cc b/deps/v8/src/compiler/simd-scalar-lowering.cc
index 6deba2b002..783f3bcc11 100644
--- a/deps/v8/src/compiler/simd-scalar-lowering.cc
+++ b/deps/v8/src/compiler/simd-scalar-lowering.cc
@@ -138,6 +138,7 @@ void SimdScalarLowering::LowerGraph() {
V(F32x4AddHoriz) \
V(F32x4Sub) \
V(F32x4Mul) \
+ V(F32x4Div) \
V(F32x4Min) \
V(F32x4Max)
@@ -1207,6 +1208,7 @@ void SimdScalarLowering::LowerNode(Node* node) {
F32X4_BINOP_CASE(Add)
F32X4_BINOP_CASE(Sub)
F32X4_BINOP_CASE(Mul)
+ F32X4_BINOP_CASE(Div)
F32X4_BINOP_CASE(Min)
F32X4_BINOP_CASE(Max)
#undef F32X4_BINOP_CASE
@@ -1390,7 +1392,7 @@ void SimdScalarLowering::LowerNode(Node* node) {
int input_num_lanes = NumLanes(input_rep_type);
Node** rep = GetReplacements(node->InputAt(0));
Node** rep_node = zone()->NewArray<Node*>(num_lanes);
- Node* true_node = mcgraph_->Int32Constant(-1);
+ Node* true_node = mcgraph_->Int32Constant(1);
Node* false_node = mcgraph_->Int32Constant(0);
Node* tmp_result = false_node;
if (node->opcode() == IrOpcode::kS1x4AllTrue ||
diff --git a/deps/v8/src/compiler/simplified-lowering.cc b/deps/v8/src/compiler/simplified-lowering.cc
index b028a76bb0..1ca7bfe707 100644
--- a/deps/v8/src/compiler/simplified-lowering.cc
+++ b/deps/v8/src/compiler/simplified-lowering.cc
@@ -92,7 +92,7 @@ MachineRepresentation MachineRepresentationFromArrayType(
}
UseInfo CheckedUseInfoAsWord32FromHint(
- NumberOperationHint hint, const VectorSlotPair& feedback = VectorSlotPair(),
+ NumberOperationHint hint, const FeedbackSource& feedback = FeedbackSource(),
IdentifyZeros identify_zeros = kDistinguishZeros) {
switch (hint) {
case NumberOperationHint::kSignedSmall:
@@ -109,7 +109,7 @@ UseInfo CheckedUseInfoAsWord32FromHint(
}
UseInfo CheckedUseInfoAsFloat64FromHint(
- NumberOperationHint hint, const VectorSlotPair& feedback,
+ NumberOperationHint hint, const FeedbackSource& feedback,
IdentifyZeros identify_zeros = kDistinguishZeros) {
switch (hint) {
case NumberOperationHint::kSignedSmall:
@@ -1092,7 +1092,7 @@ class RepresentationSelector {
if (lower()) DeferReplacement(node, node->InputAt(0));
} else {
VisitUnop(node,
- UseInfo::CheckedHeapObjectAsTaggedPointer(VectorSlotPair()),
+ UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
MachineRepresentation::kTaggedPointer);
}
}
@@ -1299,9 +1299,7 @@ class RepresentationSelector {
if (base_taggedness == kTaggedBase &&
CanBeTaggedOrCompressedPointer(field_representation)) {
Type value_type = NodeProperties::GetType(value);
- if (field_representation == MachineRepresentation::kTaggedSigned ||
- value_representation == MachineRepresentation::kTaggedSigned ||
- field_representation == MachineRepresentation::kCompressedSigned ||
+ if (value_representation == MachineRepresentation::kTaggedSigned ||
value_representation == MachineRepresentation::kCompressedSigned) {
// Write barriers are only for stores of heap objects.
return kNoWriteBarrier;
@@ -1444,13 +1442,13 @@ class RepresentationSelector {
!right_feedback_type.Maybe(Type::MinusZero())) {
left_identify_zeros = kIdentifyZeros;
}
- UseInfo left_use = CheckedUseInfoAsWord32FromHint(hint, VectorSlotPair(),
+ UseInfo left_use = CheckedUseInfoAsWord32FromHint(hint, FeedbackSource(),
left_identify_zeros);
// For CheckedInt32Add and CheckedInt32Sub, we don't need to do
// a minus zero check for the right hand side, since we already
// know that the left hand side is a proper Signed32 value,
// potentially guarded by a check.
- UseInfo right_use = CheckedUseInfoAsWord32FromHint(hint, VectorSlotPair(),
+ UseInfo right_use = CheckedUseInfoAsWord32FromHint(hint, FeedbackSource(),
kIdentifyZeros);
VisitBinop(node, left_use, right_use, MachineRepresentation::kWord32,
Type::Signed32());
@@ -1483,7 +1481,7 @@ class RepresentationSelector {
// default case => Float64Add/Sub
VisitBinop(node,
UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
- VectorSlotPair()),
+ FeedbackSource()),
MachineRepresentation::kFloat64, Type::Number());
if (lower()) {
ChangeToPureOp(node, Float64Op(node));
@@ -1546,9 +1544,9 @@ class RepresentationSelector {
// right hand side doesn't matter anyways, so in particular there's
// no observable difference between a 0 and a -0 then.
UseInfo const lhs_use = CheckedUseInfoAsWord32FromHint(
- hint, VectorSlotPair(), truncation.identify_zeros());
+ hint, FeedbackSource(), truncation.identify_zeros());
UseInfo const rhs_use = CheckedUseInfoAsWord32FromHint(
- hint, VectorSlotPair(), kIdentifyZeros);
+ hint, FeedbackSource(), kIdentifyZeros);
if (truncation.IsUsedAsWord32()) {
VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32);
if (lower()) DeferReplacement(node, lowering->Int32Mod(node));
@@ -1589,9 +1587,9 @@ class RepresentationSelector {
// right hand side doesn't matter anyways, so in particular there's
// no observable difference between a 0 and a -0 then.
UseInfo const lhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
- truncation.identify_zeros(), VectorSlotPair());
+ truncation.identify_zeros(), FeedbackSource());
UseInfo const rhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
- kIdentifyZeros, VectorSlotPair());
+ kIdentifyZeros, FeedbackSource());
VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kFloat64,
Type::Number());
if (lower()) ChangeToPureOp(node, Float64Op(node));
@@ -1931,7 +1929,7 @@ class RepresentationSelector {
case NumberOperationHint::kSignedSmall:
if (propagate()) {
VisitBinop(node,
- CheckedUseInfoAsWord32FromHint(hint, VectorSlotPair(),
+ CheckedUseInfoAsWord32FromHint(hint, FeedbackSource(),
kIdentifyZeros),
MachineRepresentation::kBit);
} else if (retype()) {
@@ -1944,7 +1942,7 @@ class RepresentationSelector {
IsNodeRepresentationTagged(rhs)) {
VisitBinop(node,
UseInfo::CheckedSignedSmallAsTaggedSigned(
- VectorSlotPair(), kIdentifyZeros),
+ FeedbackSource(), kIdentifyZeros),
MachineRepresentation::kBit);
ChangeToPureOp(
node, changer_->TaggedSignedOperatorFor(node->opcode()));
@@ -1952,7 +1950,7 @@ class RepresentationSelector {
} else {
VisitBinop(node,
CheckedUseInfoAsWord32FromHint(
- hint, VectorSlotPair(), kIdentifyZeros),
+ hint, FeedbackSource(), kIdentifyZeros),
MachineRepresentation::kBit);
ChangeToPureOp(node, Int32Op(node));
}
@@ -1969,7 +1967,7 @@ class RepresentationSelector {
V8_FALLTHROUGH;
case NumberOperationHint::kNumber:
VisitBinop(node,
- CheckedUseInfoAsFloat64FromHint(hint, VectorSlotPair(),
+ CheckedUseInfoAsFloat64FromHint(hint, FeedbackSource(),
kIdentifyZeros),
MachineRepresentation::kBit);
if (lower()) ChangeToPureOp(node, Float64Op(node));
@@ -2054,7 +2052,7 @@ class RepresentationSelector {
// Checked float64 x float64 => float64
VisitBinop(node,
UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
- VectorSlotPair()),
+ FeedbackSource()),
MachineRepresentation::kFloat64, Type::Number());
if (lower()) ChangeToPureOp(node, Float64Op(node));
return;
@@ -2150,7 +2148,7 @@ class RepresentationSelector {
// default case => Float64Div
VisitBinop(node,
UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
- VectorSlotPair()),
+ FeedbackSource()),
MachineRepresentation::kFloat64, Type::Number());
if (lower()) ChangeToPureOp(node, Float64Op(node));
return;
@@ -2320,7 +2318,7 @@ class RepresentationSelector {
if (lower()) {
node->RemoveInput(1);
NodeProperties::ChangeOp(
- node, simplified()->CheckedUint32ToInt32(VectorSlotPair()));
+ node, simplified()->CheckedUint32ToInt32(FeedbackSource()));
}
return;
}
@@ -2707,14 +2705,14 @@ class RepresentationSelector {
case IrOpcode::kSpeculativeBigIntAdd: {
if (truncation.IsUsedAsWord64()) {
VisitBinop(node,
- UseInfo::CheckedBigIntTruncatingWord64(VectorSlotPair{}),
+ UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
MachineRepresentation::kWord64);
if (lower()) {
ChangeToPureOp(node, lowering->machine()->Int64Add());
}
} else {
VisitBinop(node,
- UseInfo::CheckedBigIntAsTaggedPointer(VectorSlotPair{}),
+ UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
MachineRepresentation::kTaggedPointer);
if (lower()) {
NodeProperties::ChangeOp(node, lowering->simplified()->BigIntAdd());
@@ -2725,7 +2723,7 @@ class RepresentationSelector {
case IrOpcode::kSpeculativeBigIntNegate: {
if (truncation.IsUsedAsWord64()) {
VisitUnop(node,
- UseInfo::CheckedBigIntTruncatingWord64(VectorSlotPair{}),
+ UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
MachineRepresentation::kWord64);
if (lower()) {
ChangeUnaryToPureBinaryOp(node, lowering->machine()->Int64Sub(), 0,
@@ -2733,7 +2731,7 @@ class RepresentationSelector {
}
} else {
VisitUnop(node,
- UseInfo::CheckedBigIntAsTaggedPointer(VectorSlotPair{}),
+ UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
MachineRepresentation::kTaggedPointer);
if (lower()) {
ChangeToPureOp(node, lowering->simplified()->BigIntNegate());
@@ -2822,7 +2820,7 @@ class RepresentationSelector {
MachineRepresentation::kTaggedPointer);
} else {
VisitUnop(node,
- UseInfo::CheckedHeapObjectAsTaggedPointer(VectorSlotPair()),
+ UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
MachineRepresentation::kTaggedPointer);
}
if (lower()) DeferReplacement(node, node->InputAt(0));
@@ -3417,12 +3415,12 @@ class RepresentationSelector {
}
case IrOpcode::kTransitionElementsKind: {
return VisitUnop(
- node, UseInfo::CheckedHeapObjectAsTaggedPointer(VectorSlotPair()),
+ node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
MachineRepresentation::kNone);
}
case IrOpcode::kCompareMaps:
return VisitUnop(
- node, UseInfo::CheckedHeapObjectAsTaggedPointer(VectorSlotPair()),
+ node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
MachineRepresentation::kBit);
case IrOpcode::kEnsureWritableFastElements:
return VisitBinop(node, UseInfo::AnyTagged(),
diff --git a/deps/v8/src/compiler/simplified-operator-reducer.cc b/deps/v8/src/compiler/simplified-operator-reducer.cc
index c3cca499ac..885a86286e 100644
--- a/deps/v8/src/compiler/simplified-operator-reducer.cc
+++ b/deps/v8/src/compiler/simplified-operator-reducer.cc
@@ -106,6 +106,11 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
if (m.IsChangeInt31ToTaggedSigned() || m.IsChangeInt32ToTagged()) {
return Replace(m.InputAt(0));
}
+ if (m.IsChangeCompressedSignedToTaggedSigned()) {
+ Node* new_node = graph()->NewNode(
+ simplified()->ChangeCompressedSignedToInt32(), m.InputAt(0));
+ return Replace(new_node);
+ }
break;
}
case IrOpcode::kChangeTaggedToUint32: {
@@ -143,6 +148,40 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
}
break;
}
+ case IrOpcode::kChangeTaggedSignedToCompressedSigned: {
+ DCHECK(COMPRESS_POINTERS_BOOL);
+ NodeMatcher m(node->InputAt(0));
+ if (m.IsChangeInt31ToTaggedSigned()) {
+ Node* new_node = graph()->NewNode(
+ simplified()->ChangeInt31ToCompressedSigned(), m.InputAt(0));
+ return Replace(new_node);
+ } else if (m.IsCheckedInt32ToTaggedSigned()) {
+ // Create a new checked node that outputs CompressedSigned values, with
+ // an explicit decompression after it.
+ Node* new_checked = graph()->CloneNode(m.node());
+ NodeProperties::ChangeOp(
+ new_checked, simplified()->CheckedInt32ToCompressedSigned(
+ CheckParametersOf(m.node()->op()).feedback()));
+ Node* new_decompression = graph()->NewNode(
+ machine()->ChangeCompressedSignedToTaggedSigned(), new_checked);
+
+ // For all uses of the old checked node, instead insert the new "checked
+ // + decompression". Also, update control and effect.
+ ReplaceWithValue(m.node(), new_decompression, new_checked, new_checked);
+
+ // In the current node, we can skip the decompression since we are going
+ // to have a Decompression + Compression combo.
+ return Replace(new_checked);
+ }
+ break;
+ }
+ case IrOpcode::kChangeCompressedSignedToInt32: {
+ NodeMatcher m(node->InputAt(0));
+ if (m.IsCheckedInt32ToCompressedSigned()) {
+ return Replace(m.InputAt(0));
+ }
+ break;
+ }
case IrOpcode::kCheckedTaggedToInt32:
case IrOpcode::kCheckedTaggedSignedToInt32: {
NodeMatcher m(node->InputAt(0));
@@ -152,6 +191,14 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
}
break;
}
+ case IrOpcode::kCheckedTaggedToTaggedPointer: {
+ NodeMatcher m(node->InputAt(0));
+ if (m.IsChangeCompressedPointerToTaggedPointer()) {
+ RelaxEffectsAndControls(node);
+ return Replace(m.node());
+ }
+ break;
+ }
case IrOpcode::kCheckIf: {
HeapObjectMatcher m(node->InputAt(0));
if (m.Is(factory()->true_value())) {
@@ -267,6 +314,10 @@ MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const {
return jsgraph()->machine();
}
+SimplifiedOperatorBuilder* SimplifiedOperatorReducer::simplified() const {
+ return jsgraph()->simplified();
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/compiler/simplified-operator.cc b/deps/v8/src/compiler/simplified-operator.cc
index 4f83635422..6b86a95e01 100644
--- a/deps/v8/src/compiler/simplified-operator.cc
+++ b/deps/v8/src/compiler/simplified-operator.cc
@@ -31,13 +31,34 @@ std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
UNREACHABLE();
}
+std::ostream& operator<<(std::ostream& os,
+ ConstFieldInfo const& const_field_info) {
+ if (const_field_info.IsConst()) {
+ return os << "const (field owner: " << const_field_info.owner_map.address()
+ << ")";
+ } else {
+ return os << "mutable";
+ }
+ UNREACHABLE();
+}
+
+bool operator==(ConstFieldInfo const& lhs, ConstFieldInfo const& rhs) {
+ return lhs.owner_map.address() == rhs.owner_map.address();
+}
+
+size_t hash_value(ConstFieldInfo const& const_field_info) {
+ return (size_t)const_field_info.owner_map.address();
+}
+
bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
// On purpose we don't include the write barrier kind here, as this method is
// really only relevant for eliminating loads and they don't care about the
// write barrier mode.
return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
lhs.map.address() == rhs.map.address() &&
- lhs.machine_type == rhs.machine_type;
+ lhs.machine_type == rhs.machine_type &&
+ lhs.const_field_info == rhs.const_field_info &&
+ lhs.is_store_in_literal == rhs.is_store_in_literal;
}
size_t hash_value(FieldAccess const& access) {
@@ -45,7 +66,8 @@ size_t hash_value(FieldAccess const& access) {
// really only relevant for eliminating loads and they don't care about the
// write barrier mode.
return base::hash_combine(access.base_is_tagged, access.offset,
- access.machine_type);
+ access.machine_type, access.const_field_info,
+ access.is_store_in_literal);
}
size_t hash_value(LoadSensitivity load_sensitivity) {
@@ -78,7 +100,10 @@ std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
}
#endif
os << access.type << ", " << access.machine_type << ", "
- << access.write_barrier_kind << ", " << access.constness;
+ << access.write_barrier_kind << ", " << access.const_field_info;
+ if (access.is_store_in_literal) {
+ os << " (store in literal)";
+ }
if (FLAG_untrusted_code_mitigations) {
os << ", " << access.load_sensitivity;
}
@@ -199,7 +224,8 @@ std::ostream& operator<<(std::ostream& os,
}
size_t hash_value(const CheckFloat64HoleParameters& params) {
- return base::hash_combine(params.mode(), params.feedback());
+ FeedbackSource::Hash feedback_hash;
+ return base::hash_combine(params.mode(), feedback_hash(params.feedback()));
}
bool operator==(CheckFloat64HoleParameters const& lhs,
@@ -249,7 +275,8 @@ bool operator==(CheckMapsParameters const& lhs,
}
size_t hash_value(CheckMapsParameters const& p) {
- return base::hash_combine(p.flags(), p.maps(), p.feedback());
+ FeedbackSource::Hash feedback_hash;
+ return base::hash_combine(p.flags(), p.maps(), feedback_hash(p.feedback()));
}
std::ostream& operator<<(std::ostream& os, CheckMapsParameters const& p) {
@@ -305,7 +332,8 @@ bool operator==(const GrowFastElementsParameters& lhs,
}
inline size_t hash_value(const GrowFastElementsParameters& params) {
- return base::hash_combine(params.mode(), params.feedback());
+ FeedbackSource::Hash feedback_hash;
+ return base::hash_combine(params.mode(), feedback_hash(params.feedback()));
}
std::ostream& operator<<(std::ostream& os,
@@ -550,7 +578,8 @@ bool operator==(NumberOperationParameters const& lhs,
}
size_t hash_value(NumberOperationParameters const& p) {
- return base::hash_combine(p.hint(), p.feedback());
+ FeedbackSource::Hash feedback_hash;
+ return base::hash_combine(p.hint(), feedback_hash(p.feedback()));
}
std::ostream& operator<<(std::ostream& os, NumberOperationParameters const& p) {
@@ -619,7 +648,8 @@ std::ostream& operator<<(std::ostream& os,
}
size_t hash_value(const CheckTaggedInputParameters& params) {
- return base::hash_combine(params.mode(), params.feedback());
+ FeedbackSource::Hash feedback_hash;
+ return base::hash_combine(params.mode(), feedback_hash(params.feedback()));
}
bool operator==(CheckTaggedInputParameters const& lhs,
@@ -645,7 +675,8 @@ std::ostream& operator<<(std::ostream& os,
}
size_t hash_value(const CheckMinusZeroParameters& params) {
- return base::hash_combine(params.mode(), params.feedback());
+ FeedbackSource::Hash feedback_hash;
+ return base::hash_combine(params.mode(), feedback_hash(params.feedback()));
}
bool operator==(CheckMinusZeroParameters const& lhs,
@@ -878,7 +909,7 @@ struct SimplifiedOperatorGlobalCache final {
: Operator1<CheckParameters>( \
IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, \
#Name, value_input_count, 1, 1, value_output_count, 1, 0, \
- CheckParameters(VectorSlotPair())) {} \
+ CheckParameters(FeedbackSource())) {} \
}; \
Name##Operator k##Name;
CHECKED_WITH_FEEDBACK_OP_LIST(CHECKED_WITH_FEEDBACK)
@@ -886,16 +917,16 @@ struct SimplifiedOperatorGlobalCache final {
#define CHECKED_BOUNDS(Name) \
struct Name##Operator final : public Operator1<CheckBoundsParameters> { \
- Name##Operator(VectorSlotPair feedback, CheckBoundsParameters::Mode mode) \
+ Name##Operator(FeedbackSource feedback, CheckBoundsParameters::Mode mode) \
: Operator1<CheckBoundsParameters>( \
IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, \
#Name, 2, 1, 1, 1, 1, 0, \
CheckBoundsParameters(feedback, mode)) {} \
}; \
Name##Operator k##Name##Deopting = { \
- VectorSlotPair(), CheckBoundsParameters::kDeoptOnOutOfBounds}; \
+ FeedbackSource(), CheckBoundsParameters::kDeoptOnOutOfBounds}; \
Name##Operator k##Name##Aborting = { \
- VectorSlotPair(), CheckBoundsParameters::kAbortOnOutOfBounds};
+ FeedbackSource(), CheckBoundsParameters::kAbortOnOutOfBounds};
CHECKED_BOUNDS_OP_LIST(CHECKED_BOUNDS)
#undef CHECKED_BOUNDS
@@ -905,7 +936,7 @@ struct SimplifiedOperatorGlobalCache final {
: Operator1<CheckIfParameters>(
IrOpcode::kCheckIf, Operator::kFoldable | Operator::kNoThrow,
"CheckIf", 1, 1, 1, 0, 1, 0,
- CheckIfParameters(kDeoptimizeReason, VectorSlotPair())) {}
+ CheckIfParameters(kDeoptimizeReason, FeedbackSource())) {}
};
#define CHECK_IF(Name, message) \
CheckIfOperator<DeoptimizeReason::k##Name> kCheckIf##Name;
@@ -970,7 +1001,7 @@ struct SimplifiedOperatorGlobalCache final {
IrOpcode::kCheckedFloat64ToInt32,
Operator::kFoldable | Operator::kNoThrow, "CheckedFloat64ToInt32",
1, 1, 1, 1, 1, 0,
- CheckMinusZeroParameters(kMode, VectorSlotPair())) {}
+ CheckMinusZeroParameters(kMode, FeedbackSource())) {}
};
CheckedFloat64ToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero>
kCheckedFloat64ToInt32CheckForMinusZeroOperator;
@@ -985,7 +1016,7 @@ struct SimplifiedOperatorGlobalCache final {
IrOpcode::kCheckedFloat64ToInt64,
Operator::kFoldable | Operator::kNoThrow, "CheckedFloat64ToInt64",
1, 1, 1, 1, 1, 0,
- CheckMinusZeroParameters(kMode, VectorSlotPair())) {}
+ CheckMinusZeroParameters(kMode, FeedbackSource())) {}
};
CheckedFloat64ToInt64Operator<CheckForMinusZeroMode::kCheckForMinusZero>
kCheckedFloat64ToInt64CheckForMinusZeroOperator;
@@ -1000,7 +1031,7 @@ struct SimplifiedOperatorGlobalCache final {
IrOpcode::kCheckedTaggedToInt32,
Operator::kFoldable | Operator::kNoThrow, "CheckedTaggedToInt32",
1, 1, 1, 1, 1, 0,
- CheckMinusZeroParameters(kMode, VectorSlotPair())) {}
+ CheckMinusZeroParameters(kMode, FeedbackSource())) {}
};
CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero>
kCheckedTaggedToInt32CheckForMinusZeroOperator;
@@ -1015,7 +1046,7 @@ struct SimplifiedOperatorGlobalCache final {
IrOpcode::kCheckedTaggedToInt64,
Operator::kFoldable | Operator::kNoThrow, "CheckedTaggedToInt64",
1, 1, 1, 1, 1, 0,
- CheckMinusZeroParameters(kMode, VectorSlotPair())) {}
+ CheckMinusZeroParameters(kMode, FeedbackSource())) {}
};
CheckedTaggedToInt64Operator<CheckForMinusZeroMode::kCheckForMinusZero>
kCheckedTaggedToInt64CheckForMinusZeroOperator;
@@ -1030,7 +1061,7 @@ struct SimplifiedOperatorGlobalCache final {
IrOpcode::kCheckedTaggedToFloat64,
Operator::kFoldable | Operator::kNoThrow,
"CheckedTaggedToFloat64", 1, 1, 1, 1, 1, 0,
- CheckTaggedInputParameters(kMode, VectorSlotPair())) {}
+ CheckTaggedInputParameters(kMode, FeedbackSource())) {}
};
CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumber>
kCheckedTaggedToFloat64NumberOperator;
@@ -1045,7 +1076,7 @@ struct SimplifiedOperatorGlobalCache final {
IrOpcode::kCheckedTruncateTaggedToWord32,
Operator::kFoldable | Operator::kNoThrow,
"CheckedTruncateTaggedToWord32", 1, 1, 1, 1, 1, 0,
- CheckTaggedInputParameters(kMode, VectorSlotPair())) {}
+ CheckTaggedInputParameters(kMode, FeedbackSource())) {}
};
CheckedTruncateTaggedToWord32Operator<CheckTaggedInputMode::kNumber>
kCheckedTruncateTaggedToWord32NumberOperator;
@@ -1077,7 +1108,7 @@ struct SimplifiedOperatorGlobalCache final {
IrOpcode::kCheckFloat64Hole,
Operator::kFoldable | Operator::kNoThrow, "CheckFloat64Hole", 1,
1, 1, 1, 1, 0,
- CheckFloat64HoleParameters(kMode, VectorSlotPair())) {}
+ CheckFloat64HoleParameters(kMode, FeedbackSource())) {}
};
CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kAllowReturnHole>
kCheckFloat64HoleAllowReturnHoleOperator;
@@ -1100,7 +1131,7 @@ struct SimplifiedOperatorGlobalCache final {
GrowFastElementsOperator()
: Operator1(IrOpcode::kMaybeGrowFastElements, Operator::kNoThrow,
"MaybeGrowFastElements", 4, 1, 1, 1, 1, 0,
- GrowFastElementsParameters(kMode, VectorSlotPair())) {}
+ GrowFastElementsParameters(kMode, FeedbackSource())) {}
};
GrowFastElementsOperator<GrowFastElementsMode::kDoubleElements>
@@ -1145,7 +1176,7 @@ struct SimplifiedOperatorGlobalCache final {
IrOpcode::kSpeculativeToNumber,
Operator::kFoldable | Operator::kNoThrow, "SpeculativeToNumber",
1, 1, 1, 1, 1, 0,
- NumberOperationParameters(kHint, VectorSlotPair())) {}
+ NumberOperationParameters(kHint, FeedbackSource())) {}
};
SpeculativeToNumberOperator<NumberOperationHint::kSignedSmall>
kSpeculativeToNumberSignedSmallOperator;
@@ -1179,7 +1210,7 @@ GET_FROM_CACHE(LoadFieldByIndex)
#define GET_FROM_CACHE_WITH_FEEDBACK(Name, value_input_count, \
value_output_count) \
const Operator* SimplifiedOperatorBuilder::Name( \
- const VectorSlotPair& feedback) { \
+ const FeedbackSource& feedback) { \
if (!feedback.IsValid()) { \
return &cache_.k##Name; \
} \
@@ -1193,7 +1224,7 @@ CHECKED_WITH_FEEDBACK_OP_LIST(GET_FROM_CACHE_WITH_FEEDBACK)
#define GET_FROM_CACHE_WITH_FEEDBACK(Name) \
const Operator* SimplifiedOperatorBuilder::Name( \
- const VectorSlotPair& feedback, CheckBoundsParameters::Mode mode) { \
+ const FeedbackSource& feedback, CheckBoundsParameters::Mode mode) { \
if (!feedback.IsValid()) { \
switch (mode) { \
case CheckBoundsParameters::kDeoptOnOutOfBounds: \
@@ -1242,7 +1273,7 @@ const Operator* SimplifiedOperatorBuilder::AssertType(Type type) {
}
const Operator* SimplifiedOperatorBuilder::CheckIf(
- DeoptimizeReason reason, const VectorSlotPair& feedback) {
+ DeoptimizeReason reason, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
switch (reason) {
#define CHECK_IF(Name, message) \
@@ -1280,7 +1311,7 @@ const Operator* SimplifiedOperatorBuilder::CheckedInt32Mul(
}
const Operator* SimplifiedOperatorBuilder::CheckedFloat64ToInt32(
- CheckForMinusZeroMode mode, const VectorSlotPair& feedback) {
+ CheckForMinusZeroMode mode, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
switch (mode) {
case CheckForMinusZeroMode::kCheckForMinusZero:
@@ -1296,7 +1327,7 @@ const Operator* SimplifiedOperatorBuilder::CheckedFloat64ToInt32(
}
const Operator* SimplifiedOperatorBuilder::CheckedFloat64ToInt64(
- CheckForMinusZeroMode mode, const VectorSlotPair& feedback) {
+ CheckForMinusZeroMode mode, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
switch (mode) {
case CheckForMinusZeroMode::kCheckForMinusZero:
@@ -1312,7 +1343,7 @@ const Operator* SimplifiedOperatorBuilder::CheckedFloat64ToInt64(
}
const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt32(
- CheckForMinusZeroMode mode, const VectorSlotPair& feedback) {
+ CheckForMinusZeroMode mode, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
switch (mode) {
case CheckForMinusZeroMode::kCheckForMinusZero:
@@ -1328,7 +1359,7 @@ const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt32(
}
const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt64(
- CheckForMinusZeroMode mode, const VectorSlotPair& feedback) {
+ CheckForMinusZeroMode mode, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
switch (mode) {
case CheckForMinusZeroMode::kCheckForMinusZero:
@@ -1344,7 +1375,7 @@ const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt64(
}
const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64(
- CheckTaggedInputMode mode, const VectorSlotPair& feedback) {
+ CheckTaggedInputMode mode, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
switch (mode) {
case CheckTaggedInputMode::kNumber:
@@ -1360,7 +1391,7 @@ const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64(
}
const Operator* SimplifiedOperatorBuilder::CheckedTruncateTaggedToWord32(
- CheckTaggedInputMode mode, const VectorSlotPair& feedback) {
+ CheckTaggedInputMode mode, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
switch (mode) {
case CheckTaggedInputMode::kNumber:
@@ -1377,7 +1408,7 @@ const Operator* SimplifiedOperatorBuilder::CheckedTruncateTaggedToWord32(
const Operator* SimplifiedOperatorBuilder::CheckMaps(
CheckMapsFlags flags, ZoneHandleSet<Map> maps,
- const VectorSlotPair& feedback) {
+ const FeedbackSource& feedback) {
CheckMapsParameters const parameters(flags, maps, feedback);
return new (zone()) Operator1<CheckMapsParameters>( // --
IrOpcode::kCheckMaps, // opcode
@@ -1422,7 +1453,7 @@ const Operator* SimplifiedOperatorBuilder::ConvertReceiver(
}
const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole(
- CheckFloat64HoleMode mode, VectorSlotPair const& feedback) {
+ CheckFloat64HoleMode mode, FeedbackSource const& feedback) {
if (!feedback.IsValid()) {
switch (mode) {
case CheckFloat64HoleMode::kAllowReturnHole:
@@ -1454,7 +1485,7 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntNegate(
}
const Operator* SimplifiedOperatorBuilder::SpeculativeToNumber(
- NumberOperationHint hint, const VectorSlotPair& feedback) {
+ NumberOperationHint hint, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
switch (hint) {
case NumberOperationHint::kSignedSmall:
@@ -1480,7 +1511,7 @@ const Operator* SimplifiedOperatorBuilder::EnsureWritableFastElements() {
}
const Operator* SimplifiedOperatorBuilder::MaybeGrowFastElements(
- GrowFastElementsMode mode, const VectorSlotPair& feedback) {
+ GrowFastElementsMode mode, const FeedbackSource& feedback) {
if (!feedback.IsValid()) {
switch (mode) {
case GrowFastElementsMode::kDoubleElements:
@@ -1556,7 +1587,10 @@ bool operator==(CheckParameters const& lhs, CheckParameters const& rhs) {
return lhs.feedback() == rhs.feedback();
}
-size_t hash_value(CheckParameters const& p) { return hash_value(p.feedback()); }
+size_t hash_value(CheckParameters const& p) {
+ FeedbackSource::Hash feedback_hash;
+ return feedback_hash(p.feedback());
+}
std::ostream& operator<<(std::ostream& os, CheckParameters const& p) {
return os << p.feedback();
@@ -1605,7 +1639,8 @@ bool operator==(CheckIfParameters const& lhs, CheckIfParameters const& rhs) {
}
size_t hash_value(CheckIfParameters const& p) {
- return base::hash_combine(p.reason(), p.feedback());
+ FeedbackSource::Hash feedback_hash;
+ return base::hash_combine(p.reason(), feedback_hash(p.feedback()));
}
std::ostream& operator<<(std::ostream& os, CheckIfParameters const& p) {
diff --git a/deps/v8/src/compiler/simplified-operator.h b/deps/v8/src/compiler/simplified-operator.h
index bdac796adf..58e9bfdffb 100644
--- a/deps/v8/src/compiler/simplified-operator.h
+++ b/deps/v8/src/compiler/simplified-operator.h
@@ -10,9 +10,9 @@
#include "src/base/compiler-specific.h"
#include "src/codegen/machine-type.h"
#include "src/common/globals.h"
+#include "src/compiler/feedback-source.h"
#include "src/compiler/operator.h"
#include "src/compiler/types.h"
-#include "src/compiler/vector-slot-pair.h"
#include "src/compiler/write-barrier-kind.h"
#include "src/deoptimizer/deoptimize-reason.h"
#include "src/handles/handles.h"
@@ -44,6 +44,27 @@ size_t hash_value(LoadSensitivity);
std::ostream& operator<<(std::ostream&, LoadSensitivity);
+struct ConstFieldInfo {
+ // the map that introduced the const field, if any. An access is considered
+ // mutable iff the handle is null.
+ MaybeHandle<Map> owner_map;
+
+ ConstFieldInfo() : owner_map(MaybeHandle<Map>()) {}
+ explicit ConstFieldInfo(Handle<Map> owner_map) : owner_map(owner_map) {}
+
+ bool IsConst() const { return !owner_map.is_null(); }
+
+ // No const field owner, i.e., a mutable field
+ static ConstFieldInfo None() { return ConstFieldInfo(); }
+};
+
+V8_EXPORT_PRIVATE bool operator==(ConstFieldInfo const&, ConstFieldInfo const&);
+
+size_t hash_value(ConstFieldInfo const&);
+
+V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&,
+ ConstFieldInfo const&);
+
// An access descriptor for loads/stores of fixed structures like field
// accesses of heap objects. Accesses from either tagged or untagged base
// pointers are supported; untagging is done automatically during lowering.
@@ -56,7 +77,9 @@ struct FieldAccess {
MachineType machine_type; // machine type of the field.
WriteBarrierKind write_barrier_kind; // write barrier hint.
LoadSensitivity load_sensitivity; // load safety for poisoning.
- PropertyConstness constness; // whether the field is assigned only once
+ ConstFieldInfo const_field_info; // the constness of this access, and the
+ // field owner map, if the access is const
+ bool is_store_in_literal; // originates from a kStoreInLiteral access
FieldAccess()
: base_is_tagged(kTaggedBase),
@@ -65,13 +88,15 @@ struct FieldAccess {
machine_type(MachineType::None()),
write_barrier_kind(kFullWriteBarrier),
load_sensitivity(LoadSensitivity::kUnsafe),
- constness(PropertyConstness::kMutable) {}
+ const_field_info(ConstFieldInfo::None()),
+ is_store_in_literal(false) {}
FieldAccess(BaseTaggedness base_is_tagged, int offset, MaybeHandle<Name> name,
MaybeHandle<Map> map, Type type, MachineType machine_type,
WriteBarrierKind write_barrier_kind,
LoadSensitivity load_sensitivity = LoadSensitivity::kUnsafe,
- PropertyConstness constness = PropertyConstness::kMutable)
+ ConstFieldInfo const_field_info = ConstFieldInfo::None(),
+ bool is_store_in_literal = false)
: base_is_tagged(base_is_tagged),
offset(offset),
name(name),
@@ -80,7 +105,8 @@ struct FieldAccess {
machine_type(machine_type),
write_barrier_kind(write_barrier_kind),
load_sensitivity(load_sensitivity),
- constness(constness) {}
+ const_field_info(const_field_info),
+ is_store_in_literal(is_store_in_literal) {}
int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
};
@@ -175,13 +201,13 @@ ConvertReceiverMode ConvertReceiverModeOf(Operator const* op)
// fails, then speculation on that CallIC slot will be disabled.
class CheckParameters final {
public:
- explicit CheckParameters(const VectorSlotPair& feedback)
+ explicit CheckParameters(const FeedbackSource& feedback)
: feedback_(feedback) {}
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
private:
- VectorSlotPair feedback_;
+ FeedbackSource feedback_;
};
bool operator==(CheckParameters const&, CheckParameters const&);
@@ -196,7 +222,7 @@ class CheckBoundsParameters final {
public:
enum Mode { kAbortOnOutOfBounds, kDeoptOnOutOfBounds };
- CheckBoundsParameters(const VectorSlotPair& feedback, Mode mode)
+ CheckBoundsParameters(const FeedbackSource& feedback, Mode mode)
: check_parameters_(feedback), mode_(mode) {}
Mode mode() const { return mode_; }
@@ -219,15 +245,15 @@ CheckBoundsParameters const& CheckBoundsParametersOf(Operator const*)
class CheckIfParameters final {
public:
explicit CheckIfParameters(DeoptimizeReason reason,
- const VectorSlotPair& feedback)
+ const FeedbackSource& feedback)
: reason_(reason), feedback_(feedback) {}
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
DeoptimizeReason reason() const { return reason_; }
private:
DeoptimizeReason reason_;
- VectorSlotPair feedback_;
+ FeedbackSource feedback_;
};
bool operator==(CheckIfParameters const&, CheckIfParameters const&);
@@ -251,15 +277,15 @@ std::ostream& operator<<(std::ostream&, CheckFloat64HoleMode);
class CheckFloat64HoleParameters {
public:
CheckFloat64HoleParameters(CheckFloat64HoleMode mode,
- VectorSlotPair const& feedback)
+ FeedbackSource const& feedback)
: mode_(mode), feedback_(feedback) {}
CheckFloat64HoleMode mode() const { return mode_; }
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
private:
CheckFloat64HoleMode mode_;
- VectorSlotPair feedback_;
+ FeedbackSource feedback_;
};
CheckFloat64HoleParameters const& CheckFloat64HoleParametersOf(Operator const*)
@@ -286,15 +312,15 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, CheckTaggedInputMode);
class CheckTaggedInputParameters {
public:
CheckTaggedInputParameters(CheckTaggedInputMode mode,
- const VectorSlotPair& feedback)
+ const FeedbackSource& feedback)
: mode_(mode), feedback_(feedback) {}
CheckTaggedInputMode mode() const { return mode_; }
- const VectorSlotPair& feedback() const { return feedback_; }
+ const FeedbackSource& feedback() const { return feedback_; }
private:
CheckTaggedInputMode mode_;
- VectorSlotPair feedback_;
+ FeedbackSource feedback_;
};
const CheckTaggedInputParameters& CheckTaggedInputParametersOf(const Operator*)
@@ -324,15 +350,15 @@ CheckForMinusZeroMode CheckMinusZeroModeOf(const Operator*)
class CheckMinusZeroParameters {
public:
CheckMinusZeroParameters(CheckForMinusZeroMode mode,
- const VectorSlotPair& feedback)
+ const FeedbackSource& feedback)
: mode_(mode), feedback_(feedback) {}
CheckForMinusZeroMode mode() const { return mode_; }
- const VectorSlotPair& feedback() const { return feedback_; }
+ const FeedbackSource& feedback() const { return feedback_; }
private:
CheckForMinusZeroMode mode_;
- VectorSlotPair feedback_;
+ FeedbackSource feedback_;
};
V8_EXPORT_PRIVATE const CheckMinusZeroParameters& CheckMinusZeroParametersOf(
@@ -363,17 +389,17 @@ std::ostream& operator<<(std::ostream&, CheckMapsFlags);
class CheckMapsParameters final {
public:
CheckMapsParameters(CheckMapsFlags flags, ZoneHandleSet<Map> const& maps,
- const VectorSlotPair& feedback)
+ const FeedbackSource& feedback)
: flags_(flags), maps_(maps), feedback_(feedback) {}
CheckMapsFlags flags() const { return flags_; }
ZoneHandleSet<Map> const& maps() const { return maps_; }
- VectorSlotPair const& feedback() const { return feedback_; }
+ FeedbackSource const& feedback() const { return feedback_; }
private:
CheckMapsFlags const flags_;
ZoneHandleSet<Map> const maps_;
- VectorSlotPair const feedback_;
+ FeedbackSource const feedback_;
};
bool operator==(CheckMapsParameters const&, CheckMapsParameters const&);
@@ -406,15 +432,15 @@ std::ostream& operator<<(std::ostream&, GrowFastElementsMode);
class GrowFastElementsParameters {
public:
GrowFastElementsParameters(GrowFastElementsMode mode,
- const VectorSlotPair& feedback)
+ const FeedbackSource& feedback)
: mode_(mode), feedback_(feedback) {}
GrowFastElementsMode mode() const { return mode_; }
- const VectorSlotPair& feedback() const { return feedback_; }
+ const FeedbackSource& feedback() const { return feedback_; }
private:
GrowFastElementsMode mode_;
- VectorSlotPair feedback_;
+ FeedbackSource feedback_;
};
bool operator==(const GrowFastElementsParameters&,
@@ -490,15 +516,15 @@ V8_EXPORT_PRIVATE NumberOperationHint NumberOperationHintOf(const Operator* op)
class NumberOperationParameters {
public:
NumberOperationParameters(NumberOperationHint hint,
- const VectorSlotPair& feedback)
+ const FeedbackSource& feedback)
: hint_(hint), feedback_(feedback) {}
NumberOperationHint hint() const { return hint_; }
- const VectorSlotPair& feedback() const { return feedback_; }
+ const FeedbackSource& feedback() const { return feedback_; }
private:
NumberOperationHint hint_;
- VectorSlotPair feedback_;
+ FeedbackSource feedback_;
};
size_t hash_value(NumberOperationParameters const&);
@@ -692,7 +718,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* FindOrderedHashMapEntryForInt32Key();
const Operator* SpeculativeToNumber(NumberOperationHint hint,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* StringToNumber();
const Operator* PlainPrimitiveToNumber();
@@ -730,67 +756,67 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* CompareMaps(ZoneHandleSet<Map>);
const Operator* MapGuard(ZoneHandleSet<Map> maps);
- const Operator* CheckBounds(const VectorSlotPair& feedback);
+ const Operator* CheckBounds(const FeedbackSource& feedback);
const Operator* CheckEqualsInternalizedString();
const Operator* CheckEqualsSymbol();
- const Operator* CheckFloat64Hole(CheckFloat64HoleMode, VectorSlotPair const&);
+ const Operator* CheckFloat64Hole(CheckFloat64HoleMode, FeedbackSource const&);
const Operator* CheckHeapObject();
const Operator* CheckIf(DeoptimizeReason deoptimize_reason,
- const VectorSlotPair& feedback = VectorSlotPair());
+ const FeedbackSource& feedback = FeedbackSource());
const Operator* CheckInternalizedString();
const Operator* CheckMaps(CheckMapsFlags, ZoneHandleSet<Map>,
- const VectorSlotPair& = VectorSlotPair());
+ const FeedbackSource& = FeedbackSource());
const Operator* CheckNotTaggedHole();
- const Operator* CheckNumber(const VectorSlotPair& feedback);
+ const Operator* CheckNumber(const FeedbackSource& feedback);
const Operator* CheckReceiver();
const Operator* CheckReceiverOrNullOrUndefined();
- const Operator* CheckSmi(const VectorSlotPair& feedback);
- const Operator* CheckString(const VectorSlotPair& feedback);
+ const Operator* CheckSmi(const FeedbackSource& feedback);
+ const Operator* CheckString(const FeedbackSource& feedback);
const Operator* CheckSymbol();
const Operator* CheckedFloat64ToInt32(CheckForMinusZeroMode,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* CheckedFloat64ToInt64(CheckForMinusZeroMode,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* CheckedInt32Add();
const Operator* CheckedInt32Div();
const Operator* CheckedInt32Mod();
const Operator* CheckedInt32Mul(CheckForMinusZeroMode);
const Operator* CheckedInt32Sub();
const Operator* CheckedInt32ToCompressedSigned(
- const VectorSlotPair& feedback);
- const Operator* CheckedInt32ToTaggedSigned(const VectorSlotPair& feedback);
- const Operator* CheckedInt64ToInt32(const VectorSlotPair& feedback);
- const Operator* CheckedInt64ToTaggedSigned(const VectorSlotPair& feedback);
- const Operator* CheckedTaggedSignedToInt32(const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
+ const Operator* CheckedInt32ToTaggedSigned(const FeedbackSource& feedback);
+ const Operator* CheckedInt64ToInt32(const FeedbackSource& feedback);
+ const Operator* CheckedInt64ToTaggedSigned(const FeedbackSource& feedback);
+ const Operator* CheckedTaggedSignedToInt32(const FeedbackSource& feedback);
const Operator* CheckedTaggedToFloat64(CheckTaggedInputMode,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* CheckedTaggedToInt32(CheckForMinusZeroMode,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* CheckedTaggedToInt64(CheckForMinusZeroMode,
- const VectorSlotPair& feedback);
- const Operator* CheckedTaggedToTaggedPointer(const VectorSlotPair& feedback);
- const Operator* CheckedTaggedToTaggedSigned(const VectorSlotPair& feedback);
- const Operator* CheckBigInt(const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
+ const Operator* CheckedTaggedToTaggedPointer(const FeedbackSource& feedback);
+ const Operator* CheckedTaggedToTaggedSigned(const FeedbackSource& feedback);
+ const Operator* CheckBigInt(const FeedbackSource& feedback);
const Operator* CheckedCompressedToTaggedPointer(
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* CheckedCompressedToTaggedSigned(
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* CheckedTaggedToCompressedPointer(
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* CheckedTaggedToCompressedSigned(
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* CheckedTruncateTaggedToWord32(CheckTaggedInputMode,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
const Operator* CheckedUint32Div();
const Operator* CheckedUint32Mod();
- const Operator* CheckedUint32Bounds(const VectorSlotPair& feedback,
+ const Operator* CheckedUint32Bounds(const FeedbackSource& feedback,
CheckBoundsParameters::Mode mode);
- const Operator* CheckedUint32ToInt32(const VectorSlotPair& feedback);
- const Operator* CheckedUint32ToTaggedSigned(const VectorSlotPair& feedback);
- const Operator* CheckedUint64Bounds(const VectorSlotPair& feedback);
- const Operator* CheckedUint64ToInt32(const VectorSlotPair& feedback);
- const Operator* CheckedUint64ToTaggedSigned(const VectorSlotPair& feedback);
+ const Operator* CheckedUint32ToInt32(const FeedbackSource& feedback);
+ const Operator* CheckedUint32ToTaggedSigned(const FeedbackSource& feedback);
+ const Operator* CheckedUint64Bounds(const FeedbackSource& feedback);
+ const Operator* CheckedUint64ToInt32(const FeedbackSource& feedback);
+ const Operator* CheckedUint64ToTaggedSigned(const FeedbackSource& feedback);
const Operator* ConvertReceiver(ConvertReceiverMode);
@@ -839,7 +865,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
// maybe-grow-fast-elements object, elements, index, length
const Operator* MaybeGrowFastElements(GrowFastElementsMode mode,
- const VectorSlotPair& feedback);
+ const FeedbackSource& feedback);
// transition-elements-kind object, from-map, to-map
const Operator* TransitionElementsKind(ElementsTransition transition);
diff --git a/deps/v8/src/compiler/store-store-elimination.cc b/deps/v8/src/compiler/store-store-elimination.cc
index b71bcd7e66..bd53fb895f 100644
--- a/deps/v8/src/compiler/store-store-elimination.cc
+++ b/deps/v8/src/compiler/store-store-elimination.cc
@@ -10,7 +10,6 @@
#include "src/compiler/all-nodes.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node-properties.h"
-#include "src/compiler/simplified-operator.h"
namespace v8 {
namespace internal {
@@ -42,163 +41,7 @@ namespace compiler {
#define DCHECK_EXTRA(condition, fmt, ...) ((void)0)
#endif
-// Store-store elimination.
-//
-// The aim of this optimization is to detect the following pattern in the
-// effect graph:
-//
-// - StoreField[+24, kRepTagged](263, ...)
-//
-// ... lots of nodes from which the field at offset 24 of the object
-// returned by node #263 cannot be observed ...
-//
-// - StoreField[+24, kRepTagged](263, ...)
-//
-// In such situations, the earlier StoreField cannot be observed, and can be
-// eliminated. This optimization should work for any offset and input node, of
-// course.
-//
-// The optimization also works across splits. It currently does not work for
-// loops, because we tend to put a stack check in loops, and like deopts,
-// stack checks can observe anything.
-
-// Assumption: every byte of a JS object is only ever accessed through one
-// offset. For instance, byte 15 of a given object may be accessed using a
-// two-byte read at offset 14, or a four-byte read at offset 12, but never
-// both in the same program.
-//
-// This implementation needs all dead nodes removed from the graph, and the
-// graph should be trimmed.
-
-namespace {
-
-using StoreOffset = uint32_t;
-
-struct UnobservableStore {
- NodeId id_;
- StoreOffset offset_;
-
- bool operator==(const UnobservableStore) const;
- bool operator<(const UnobservableStore) const;
-};
-
-} // namespace
-
-namespace {
-
-// Instances of UnobservablesSet are immutable. They represent either a set of
-// UnobservableStores, or the "unvisited empty set".
-//
-// We apply some sharing to save memory. The class UnobservablesSet is only a
-// pointer wide, and a copy does not use any heap (or temp_zone) memory. Most
-// changes to an UnobservablesSet might allocate in the temp_zone.
-//
-// The size of an instance should be the size of a pointer, plus additional
-// space in the zone in the case of non-unvisited UnobservablesSets. Copying
-// an UnobservablesSet allocates no memory.
-class UnobservablesSet final {
- public:
- static UnobservablesSet Unvisited();
- static UnobservablesSet VisitedEmpty(Zone* zone);
- UnobservablesSet(); // unvisited
- UnobservablesSet(const UnobservablesSet& other) V8_NOEXCEPT = default;
-
- UnobservablesSet Intersect(const UnobservablesSet& other, Zone* zone) const;
- UnobservablesSet Add(UnobservableStore obs, Zone* zone) const;
- UnobservablesSet RemoveSameOffset(StoreOffset off, Zone* zone) const;
-
- const ZoneSet<UnobservableStore>* set() const { return set_; }
-
- bool IsUnvisited() const { return set_ == nullptr; }
- bool IsEmpty() const { return set_ == nullptr || set_->empty(); }
- bool Contains(UnobservableStore obs) const {
- return set_ != nullptr && (set_->find(obs) != set_->end());
- }
-
- bool operator==(const UnobservablesSet&) const;
- bool operator!=(const UnobservablesSet&) const;
-
- private:
- explicit UnobservablesSet(const ZoneSet<UnobservableStore>* set)
- : set_(set) {}
- const ZoneSet<UnobservableStore>* set_;
-};
-
-} // namespace
-
-namespace {
-
-class RedundantStoreFinder final {
- public:
- RedundantStoreFinder(JSGraph* js_graph, TickCounter* tick_counter,
- Zone* temp_zone);
-
- void Find();
-
- const ZoneSet<Node*>& to_remove_const() { return to_remove_; }
-
- void Visit(Node* node);
-
- private:
- void VisitEffectfulNode(Node* node);
- UnobservablesSet RecomputeUseIntersection(Node* node);
- UnobservablesSet RecomputeSet(Node* node, const UnobservablesSet& uses);
- static bool CannotObserveStoreField(Node* node);
-
- void MarkForRevisit(Node* node);
- bool HasBeenVisited(Node* node);
-
- JSGraph* jsgraph() const { return jsgraph_; }
- Isolate* isolate() { return jsgraph()->isolate(); }
- Zone* temp_zone() const { return temp_zone_; }
- ZoneVector<UnobservablesSet>& unobservable() { return unobservable_; }
- UnobservablesSet& unobservable_for_id(NodeId id) {
- DCHECK_LT(id, unobservable().size());
- return unobservable()[id];
- }
- ZoneSet<Node*>& to_remove() { return to_remove_; }
-
- JSGraph* const jsgraph_;
- TickCounter* const tick_counter_;
- Zone* const temp_zone_;
-
- ZoneStack<Node*> revisit_;
- ZoneVector<bool> in_revisit_;
- // Maps node IDs to UnobservableNodeSets.
- ZoneVector<UnobservablesSet> unobservable_;
- ZoneSet<Node*> to_remove_;
- const UnobservablesSet unobservables_visited_empty_;
-};
-
-// To safely cast an offset from a FieldAccess, which has a potentially wider
-// range (namely int).
-StoreOffset ToOffset(int offset) {
- CHECK_LE(0, offset);
- return static_cast<StoreOffset>(offset);
-}
-
-StoreOffset ToOffset(const FieldAccess& access) {
- return ToOffset(access.offset);
-}
-
-unsigned int RepSizeOf(MachineRepresentation rep) {
- return 1u << ElementSizeLog2Of(rep);
-}
-unsigned int RepSizeOf(FieldAccess access) {
- return RepSizeOf(access.machine_type.representation());
-}
-
-bool AtMostTagged(FieldAccess access) {
- return RepSizeOf(access) <= RepSizeOf(MachineRepresentation::kTagged);
-}
-
-bool AtLeastTagged(FieldAccess access) {
- return RepSizeOf(access) >= RepSizeOf(MachineRepresentation::kTagged);
-}
-
-} // namespace
-
-void RedundantStoreFinder::Find() {
+void StoreStoreElimination::RedundantStoreFinder::Find() {
Visit(jsgraph()->graph()->end());
while (!revisit_.empty()) {
@@ -222,7 +65,7 @@ void RedundantStoreFinder::Find() {
#endif
}
-void RedundantStoreFinder::MarkForRevisit(Node* node) {
+void StoreStoreElimination::RedundantStoreFinder::MarkForRevisit(Node* node) {
DCHECK_LT(node->id(), in_revisit_.size());
if (!in_revisit_[node->id()]) {
revisit_.push(node);
@@ -230,7 +73,7 @@ void RedundantStoreFinder::MarkForRevisit(Node* node) {
}
}
-bool RedundantStoreFinder::HasBeenVisited(Node* node) {
+bool StoreStoreElimination::RedundantStoreFinder::HasBeenVisited(Node* node) {
return !unobservable_for_id(node->id()).IsUnvisited();
}
@@ -241,7 +84,6 @@ void StoreStoreElimination::Run(JSGraph* js_graph, TickCounter* tick_counter,
finder.Find();
// Remove superfluous nodes
-
for (Node* node : finder.to_remove_const()) {
if (FLAG_trace_store_elimination) {
PrintF("StoreStoreElimination::Run: Eliminating node #%d:%s\n",
@@ -254,11 +96,9 @@ void StoreStoreElimination::Run(JSGraph* js_graph, TickCounter* tick_counter,
}
}
-// Recompute unobservables-set for a node. Will also mark superfluous nodes
-// as to be removed.
-
-UnobservablesSet RedundantStoreFinder::RecomputeSet(
- Node* node, const UnobservablesSet& uses) {
+StoreStoreElimination::UnobservablesSet
+StoreStoreElimination::RedundantStoreFinder::RecomputeSet(
+ Node* node, const StoreStoreElimination::UnobservablesSet& uses) {
switch (node->op()->opcode()) {
case IrOpcode::kStoreField: {
Node* stored_to = node->InputAt(0);
@@ -266,40 +106,21 @@ UnobservablesSet RedundantStoreFinder::RecomputeSet(
StoreOffset offset = ToOffset(access);
UnobservableStore observation = {stored_to->id(), offset};
- bool isNotObservable = uses.Contains(observation);
+ bool is_not_observable = uses.Contains(observation);
- if (isNotObservable && AtMostTagged(access)) {
+ if (is_not_observable) {
TRACE(" #%d is StoreField[+%d,%s](#%d), unobservable", node->id(),
offset, MachineReprToString(access.machine_type.representation()),
stored_to->id());
to_remove().insert(node);
return uses;
- } else if (isNotObservable && !AtMostTagged(access)) {
- TRACE(
- " #%d is StoreField[+%d,%s](#%d), repeated in future but too "
- "big to optimize away",
- node->id(), offset,
- MachineReprToString(access.machine_type.representation()),
- stored_to->id());
- return uses;
- } else if (!isNotObservable && AtLeastTagged(access)) {
+ } else {
TRACE(" #%d is StoreField[+%d,%s](#%d), observable, recording in set",
node->id(), offset,
MachineReprToString(access.machine_type.representation()),
stored_to->id());
return uses.Add(observation, temp_zone());
- } else if (!isNotObservable && !AtLeastTagged(access)) {
- TRACE(
- " #%d is StoreField[+%d,%s](#%d), observable but too small to "
- "record",
- node->id(), offset,
- MachineReprToString(access.machine_type.representation()),
- stored_to->id());
- return uses;
- } else {
- UNREACHABLE();
}
- break;
}
case IrOpcode::kLoadField: {
Node* loaded_from = node->InputAt(0);
@@ -314,7 +135,6 @@ UnobservablesSet RedundantStoreFinder::RecomputeSet(
loaded_from->id(), offset);
return uses.RemoveSameOffset(offset, temp_zone());
- break;
}
default:
if (CannotObserveStoreField(node)) {
@@ -330,36 +150,16 @@ UnobservablesSet RedundantStoreFinder::RecomputeSet(
UNREACHABLE();
}
-bool RedundantStoreFinder::CannotObserveStoreField(Node* node) {
- return node->opcode() == IrOpcode::kLoadElement ||
- node->opcode() == IrOpcode::kLoad ||
- node->opcode() == IrOpcode::kStore ||
- node->opcode() == IrOpcode::kEffectPhi ||
- node->opcode() == IrOpcode::kStoreElement ||
- node->opcode() == IrOpcode::kUnsafePointerAdd ||
- node->opcode() == IrOpcode::kRetain;
+bool StoreStoreElimination::RedundantStoreFinder::CannotObserveStoreField(
+ Node* node) {
+ IrOpcode::Value opcode = node->opcode();
+ return opcode == IrOpcode::kLoadElement || opcode == IrOpcode::kLoad ||
+ opcode == IrOpcode::kStore || opcode == IrOpcode::kEffectPhi ||
+ opcode == IrOpcode::kStoreElement ||
+ opcode == IrOpcode::kUnsafePointerAdd || opcode == IrOpcode::kRetain;
}
-// Initialize unobservable_ with js_graph->graph->NodeCount() empty sets.
-RedundantStoreFinder::RedundantStoreFinder(JSGraph* js_graph,
- TickCounter* tick_counter,
- Zone* temp_zone)
- : jsgraph_(js_graph),
- tick_counter_(tick_counter),
- temp_zone_(temp_zone),
- revisit_(temp_zone),
- in_revisit_(js_graph->graph()->NodeCount(), temp_zone),
- unobservable_(js_graph->graph()->NodeCount(),
- UnobservablesSet::Unvisited(), temp_zone),
- to_remove_(temp_zone),
- unobservables_visited_empty_(UnobservablesSet::VisitedEmpty(temp_zone)) {}
-
-void RedundantStoreFinder::Visit(Node* node) {
- // All effectful nodes should be reachable from End via a sequence of
- // control, then a sequence of effect edges. In VisitEffectfulNode we mark
- // all effect inputs for revisiting (if they might have stale state); here
- // we mark all control inputs at least once.
-
+void StoreStoreElimination::RedundantStoreFinder::Visit(Node* node) {
if (!HasBeenVisited(node)) {
for (int i = 0; i < node->op()->ControlInputCount(); i++) {
Node* control_input = NodeProperties::GetControlInput(node, i);
@@ -369,29 +169,32 @@ void RedundantStoreFinder::Visit(Node* node) {
}
}
- bool isEffectful = (node->op()->EffectInputCount() >= 1);
- if (isEffectful) {
+ bool is_effectful = node->op()->EffectInputCount() >= 1;
+ if (is_effectful) {
+ // mark all effect inputs for revisiting (if they might have stale state).
VisitEffectfulNode(node);
DCHECK(HasBeenVisited(node));
- }
-
- if (!HasBeenVisited(node)) {
+ } else if (!HasBeenVisited(node)) {
// Mark as visited.
unobservable_for_id(node->id()) = unobservables_visited_empty_;
}
}
-void RedundantStoreFinder::VisitEffectfulNode(Node* node) {
+void StoreStoreElimination::RedundantStoreFinder::VisitEffectfulNode(
+ Node* node) {
if (HasBeenVisited(node)) {
TRACE("- Revisiting: #%d:%s", node->id(), node->op()->mnemonic());
}
- UnobservablesSet after_set = RecomputeUseIntersection(node);
- UnobservablesSet before_set = RecomputeSet(node, after_set);
+ StoreStoreElimination::UnobservablesSet after_set =
+ RecomputeUseIntersection(node);
+ StoreStoreElimination::UnobservablesSet before_set =
+ RecomputeSet(node, after_set);
DCHECK(!before_set.IsUnvisited());
- UnobservablesSet stored_for_node = unobservable_for_id(node->id());
+ StoreStoreElimination::UnobservablesSet stores_for_node =
+ unobservable_for_id(node->id());
bool cur_set_changed =
- (stored_for_node.IsUnvisited() || stored_for_node != before_set);
+ stores_for_node.IsUnvisited() || stores_for_node != before_set;
if (!cur_set_changed) {
// We will not be able to update the part of this chain above any more.
// Exit.
@@ -409,81 +212,78 @@ void RedundantStoreFinder::VisitEffectfulNode(Node* node) {
}
}
-// Compute the intersection of the UnobservablesSets of all effect uses and
-// return it. This function only works if {node} has an effect use.
-//
-// The result UnobservablesSet will always be visited.
-UnobservablesSet RedundantStoreFinder::RecomputeUseIntersection(Node* node) {
+StoreStoreElimination::UnobservablesSet
+StoreStoreElimination::RedundantStoreFinder::RecomputeUseIntersection(
+ Node* node) {
+ // There were no effect uses. Break early.
+ if (node->op()->EffectOutputCount() == 0) {
+ IrOpcode::Value opcode = node->opcode();
+ // List of opcodes that may end this effect chain. The opcodes are not
+ // important to the soundness of this optimization; this serves as a
+ // general sanity check. Add opcodes to this list as it suits you.
+ //
+ // Everything is observable after these opcodes; return the empty set.
+ DCHECK_EXTRA(
+ opcode == IrOpcode::kReturn || opcode == IrOpcode::kTerminate ||
+ opcode == IrOpcode::kDeoptimize || opcode == IrOpcode::kThrow,
+ "for #%d:%s", node->id(), node->op()->mnemonic());
+ USE(opcode);
+
+ return unobservables_visited_empty_;
+ }
+
// {first} == true indicates that we haven't looked at any elements yet.
// {first} == false indicates that cur_set is the intersection of at least one
// thing.
-
bool first = true;
- UnobservablesSet cur_set = UnobservablesSet::Unvisited(); // irrelevant
-
+ StoreStoreElimination::UnobservablesSet cur_set =
+ StoreStoreElimination::UnobservablesSet::Unvisited(); // irrelevant
for (Edge edge : node->use_edges()) {
- // Skip non-effect edges
if (!NodeProperties::IsEffectEdge(edge)) {
continue;
}
+ // Intersect with the new use node.
Node* use = edge.from();
- UnobservablesSet new_set = unobservable_for_id(use->id());
- // Include new_set in the intersection.
+ StoreStoreElimination::UnobservablesSet new_set =
+ unobservable_for_id(use->id());
if (first) {
- // Intersection of a one-element set is that one element
first = false;
cur_set = new_set;
+ if (cur_set.IsUnvisited()) {
+ cur_set = unobservables_visited_empty_;
+ }
} else {
- // Take the intersection of cur_set and new_set.
- cur_set = cur_set.Intersect(new_set, temp_zone());
+ cur_set =
+ cur_set.Intersect(new_set, unobservables_visited_empty_, temp_zone());
}
- }
- if (first) {
- // There were no effect uses.
- auto opcode = node->op()->opcode();
- // List of opcodes that may end this effect chain. The opcodes are not
- // important to the soundness of this optimization; this serves as a
- // general sanity check. Add opcodes to this list as it suits you.
- //
- // Everything is observable after these opcodes; return the empty set.
- DCHECK_EXTRA(
- opcode == IrOpcode::kReturn || opcode == IrOpcode::kTerminate ||
- opcode == IrOpcode::kDeoptimize || opcode == IrOpcode::kThrow,
- "for #%d:%s", node->id(), node->op()->mnemonic());
- USE(opcode); // silence warning about unused variable in release mode
-
- return unobservables_visited_empty_;
- } else {
- if (cur_set.IsUnvisited()) {
- cur_set = unobservables_visited_empty_;
+ // Break fast for the empty set since the intersection will always be empty.
+ if (cur_set.IsEmpty()) {
+ break;
}
-
- return cur_set;
}
-}
-UnobservablesSet UnobservablesSet::Unvisited() { return UnobservablesSet(); }
+ DCHECK(!cur_set.IsUnvisited());
+ return cur_set;
+}
-UnobservablesSet::UnobservablesSet() : set_(nullptr) {}
+StoreStoreElimination::UnobservablesSet::UnobservablesSet() : set_(nullptr) {}
-UnobservablesSet UnobservablesSet::VisitedEmpty(Zone* zone) {
- // Create a new empty UnobservablesSet. This allocates in the zone, and
- // can probably be optimized to use a global singleton.
+StoreStoreElimination::UnobservablesSet
+StoreStoreElimination::UnobservablesSet::VisitedEmpty(Zone* zone) {
ZoneSet<UnobservableStore>* empty_set =
new (zone->New(sizeof(ZoneSet<UnobservableStore>)))
ZoneSet<UnobservableStore>(zone);
- return UnobservablesSet(empty_set);
+ return StoreStoreElimination::UnobservablesSet(empty_set);
}
-// Computes the intersection of two UnobservablesSets. May return
-// UnobservablesSet::Unvisited() instead of an empty UnobservablesSet for
-// speed.
-UnobservablesSet UnobservablesSet::Intersect(const UnobservablesSet& other,
- Zone* zone) const {
+StoreStoreElimination::UnobservablesSet
+StoreStoreElimination::UnobservablesSet::Intersect(
+ const StoreStoreElimination::UnobservablesSet& other,
+ const StoreStoreElimination::UnobservablesSet& empty, Zone* zone) const {
if (IsEmpty() || other.IsEmpty()) {
- return Unvisited();
+ return empty;
} else {
ZoneSet<UnobservableStore>* intersection =
new (zone->New(sizeof(ZoneSet<UnobservableStore>)))
@@ -493,14 +293,15 @@ UnobservablesSet UnobservablesSet::Intersect(const UnobservablesSet& other,
other.set()->end(),
std::inserter(*intersection, intersection->end()));
- return UnobservablesSet(intersection);
+ return StoreStoreElimination::UnobservablesSet(intersection);
}
}
-UnobservablesSet UnobservablesSet::Add(UnobservableStore obs,
- Zone* zone) const {
- bool present = (set()->find(obs) != set()->end());
- if (present) {
+StoreStoreElimination::UnobservablesSet
+StoreStoreElimination::UnobservablesSet::Add(UnobservableStore obs,
+ Zone* zone) const {
+ bool found = set()->find(obs) != set()->end();
+ if (found) {
return *this;
} else {
// Make a new empty set.
@@ -514,12 +315,13 @@ UnobservablesSet UnobservablesSet::Add(UnobservableStore obs,
DCHECK(inserted);
USE(inserted); // silence warning about unused variable
- return UnobservablesSet(new_set);
+ return StoreStoreElimination::UnobservablesSet(new_set);
}
}
-UnobservablesSet UnobservablesSet::RemoveSameOffset(StoreOffset offset,
- Zone* zone) const {
+StoreStoreElimination::UnobservablesSet
+StoreStoreElimination::UnobservablesSet::RemoveSameOffset(StoreOffset offset,
+ Zone* zone) const {
// Make a new empty set.
ZoneSet<UnobservableStore>* new_set =
new (zone->New(sizeof(ZoneSet<UnobservableStore>)))
@@ -531,30 +333,7 @@ UnobservablesSet UnobservablesSet::RemoveSameOffset(StoreOffset offset,
}
}
- return UnobservablesSet(new_set);
-}
-
-// Used for debugging.
-bool UnobservablesSet::operator==(const UnobservablesSet& other) const {
- if (IsUnvisited() || other.IsUnvisited()) {
- return IsEmpty() && other.IsEmpty();
- } else {
- // Both pointers guaranteed not to be nullptrs.
- return *set() == *other.set();
- }
-}
-
-bool UnobservablesSet::operator!=(const UnobservablesSet& other) const {
- return !(*this == other);
-}
-
-bool UnobservableStore::operator==(const UnobservableStore other) const {
- return (id_ == other.id_) && (offset_ == other.offset_);
-}
-
-
-bool UnobservableStore::operator<(const UnobservableStore other) const {
- return (id_ < other.id_) || (id_ == other.id_ && offset_ < other.offset_);
+ return StoreStoreElimination::UnobservablesSet(new_set);
}
#undef TRACE
diff --git a/deps/v8/src/compiler/store-store-elimination.h b/deps/v8/src/compiler/store-store-elimination.h
index 646640a310..7704938fc0 100644
--- a/deps/v8/src/compiler/store-store-elimination.h
+++ b/deps/v8/src/compiler/store-store-elimination.h
@@ -7,6 +7,7 @@
#include "src/compiler/common-operator.h"
#include "src/compiler/js-graph.h"
+#include "src/compiler/simplified-operator.h"
#include "src/zone/zone-containers.h"
namespace v8 {
@@ -16,10 +17,203 @@ class TickCounter;
namespace compiler {
+// Store-store elimination.
+//
+// The aim of this optimization is to detect the following pattern in the
+// effect graph:
+//
+// - StoreField[+24, kRepTagged](263, ...)
+//
+// ... lots of nodes from which the field at offset 24 of the object
+// returned by node #263 cannot be observed ...
+//
+// - StoreField[+24, kRepTagged](263, ...)
+//
+// In such situations, the earlier StoreField cannot be observed, and can be
+// eliminated. This optimization should work for any offset and input node, of
+// course.
+//
+// The optimization also works across splits. It currently does not work for
+// loops, because we tend to put a stack check in loops, and like deopts,
+// stack checks can observe anything.
+
+// Assumption: every byte of a JS object is only ever accessed through one
+// offset. For instance, byte 15 of a given object may be accessed using a
+// two-byte read at offset 14, or a four-byte read at offset 12, but never
+// both in the same program.
+//
+// This implementation needs all dead nodes removed from the graph, and the
+// graph should be trimmed.
class StoreStoreElimination final {
public:
static void Run(JSGraph* js_graph, TickCounter* tick_counter,
Zone* temp_zone);
+
+ private:
+ using StoreOffset = uint32_t;
+
+ struct UnobservableStore {
+ NodeId id_;
+ StoreOffset offset_;
+
+ bool operator==(const UnobservableStore other) const {
+ return (id_ == other.id_) && (offset_ == other.offset_);
+ }
+
+ bool operator<(const UnobservableStore other) const {
+ return (id_ < other.id_) || (id_ == other.id_ && offset_ < other.offset_);
+ }
+ };
+
+ // Instances of UnobservablesSet are immutable. They represent either a set of
+ // UnobservableStores, or the "unvisited empty set".
+ //
+ // We apply some sharing to save memory. The class UnobservablesSet is only a
+ // pointer wide, and a copy does not use any heap (or temp_zone) memory. Most
+ // changes to an UnobservablesSet might allocate in the temp_zone.
+ //
+ // The size of an instance should be the size of a pointer, plus additional
+ // space in the zone in the case of non-unvisited UnobservablesSets. Copying
+ // an UnobservablesSet allocates no memory.
+ class UnobservablesSet final {
+ public:
+ // Creates a new UnobservablesSet, with the null set.
+ static UnobservablesSet Unvisited() { return UnobservablesSet(); }
+
+ // Create a new empty UnobservablesSet. This allocates in the zone, and
+ // can probably be optimized to use a global singleton.
+ static UnobservablesSet VisitedEmpty(Zone* zone);
+ UnobservablesSet(const UnobservablesSet& other) V8_NOEXCEPT = default;
+
+ // Computes the intersection of two UnobservablesSets. If one of the sets is
+ // empty, will return empty.
+ UnobservablesSet Intersect(const UnobservablesSet& other,
+ const UnobservablesSet& empty, Zone* zone) const;
+
+ // Returns a set that it is the current one, plus the observation obs passed
+ // as parameter. If said obs it's already in the set, we don't have to
+ // create a new one.
+ UnobservablesSet Add(UnobservableStore obs, Zone* zone) const;
+
+ // Returns a set that it is the current one, except for all of the
+ // observations with offset off. This is done by creating a new set and
+ // copying all observations with different offsets.
+ // This can probably be done better if the observations are stored first by
+ // offset and then by node.
+ // We are removing all nodes with offset off since different nodes may
+ // alias one another, and we currently we don't have the means to know if
+ // two nodes are definitely the same value.
+ UnobservablesSet RemoveSameOffset(StoreOffset off, Zone* zone) const;
+
+ const ZoneSet<UnobservableStore>* set() const { return set_; }
+
+ bool IsUnvisited() const { return set_ == nullptr; }
+ bool IsEmpty() const { return set_ == nullptr || set_->empty(); }
+ bool Contains(UnobservableStore obs) const {
+ return set_ != nullptr && (set_->find(obs) != set_->end());
+ }
+
+ bool operator==(const UnobservablesSet& other) const {
+ if (IsUnvisited() || other.IsUnvisited()) {
+ return IsEmpty() && other.IsEmpty();
+ } else {
+ // Both pointers guaranteed not to be nullptrs.
+ return *set() == *(other.set());
+ }
+ }
+
+ bool operator!=(const UnobservablesSet& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ UnobservablesSet();
+ explicit UnobservablesSet(const ZoneSet<UnobservableStore>* set)
+ : set_(set) {}
+ const ZoneSet<UnobservableStore>* set_;
+ };
+
+ class RedundantStoreFinder final {
+ public:
+ // Note that we Initialize unobservable_ with js_graph->graph->NodeCount()
+ // amount of empty sets.
+ RedundantStoreFinder(JSGraph* js_graph, TickCounter* tick_counter,
+ Zone* temp_zone)
+ : jsgraph_(js_graph),
+ tick_counter_(tick_counter),
+ temp_zone_(temp_zone),
+ revisit_(temp_zone),
+ in_revisit_(js_graph->graph()->NodeCount(), temp_zone),
+ unobservable_(js_graph->graph()->NodeCount(),
+ StoreStoreElimination::UnobservablesSet::Unvisited(),
+ temp_zone),
+ to_remove_(temp_zone),
+ unobservables_visited_empty_(
+ StoreStoreElimination::UnobservablesSet::VisitedEmpty(
+ temp_zone)) {}
+
+ // Crawls from the end of the graph to the beginning, with the objective of
+ // finding redundant stores.
+ void Find();
+
+ // This method is used for const correctness to go through the final list of
+ // redundant stores that are replaced on the graph.
+ const ZoneSet<Node*>& to_remove_const() { return to_remove_; }
+
+ private:
+ // Assumption: All effectful nodes are reachable from End via a sequence of
+ // control, then a sequence of effect edges.
+ // Visit goes through the control chain, visiting effectful nodes that it
+ // encounters.
+ void Visit(Node* node);
+
+ // Marks effect inputs for visiting, if we are able to update this path of
+ // the graph.
+ void VisitEffectfulNode(Node* node);
+
+ // Compute the intersection of the UnobservablesSets of all effect uses and
+ // return it.
+ // The result UnobservablesSet will never be null.
+ UnobservablesSet RecomputeUseIntersection(Node* node);
+
+ // Recompute unobservables-set for a node. Will also mark superfluous nodes
+ // as to be removed.
+ UnobservablesSet RecomputeSet(Node* node, const UnobservablesSet& uses);
+
+ // Returns true if node's opcode cannot observe StoreFields.
+ static bool CannotObserveStoreField(Node* node);
+
+ void MarkForRevisit(Node* node);
+ bool HasBeenVisited(Node* node);
+
+ // To safely cast an offset from a FieldAccess, which has a potentially
+ // wider range (namely int).
+ StoreOffset ToOffset(const FieldAccess& access) {
+ DCHECK_GE(access.offset, 0);
+ return static_cast<StoreOffset>(access.offset);
+ }
+
+ JSGraph* jsgraph() const { return jsgraph_; }
+ Isolate* isolate() { return jsgraph()->isolate(); }
+ Zone* temp_zone() const { return temp_zone_; }
+ UnobservablesSet& unobservable_for_id(NodeId id) {
+ DCHECK_LT(id, unobservable_.size());
+ return unobservable_[id];
+ }
+ ZoneSet<Node*>& to_remove() { return to_remove_; }
+
+ JSGraph* const jsgraph_;
+ TickCounter* const tick_counter_;
+ Zone* const temp_zone_;
+
+ ZoneStack<Node*> revisit_;
+ ZoneVector<bool> in_revisit_;
+
+ // Maps node IDs to UnobservableNodeSets.
+ ZoneVector<UnobservablesSet> unobservable_;
+ ZoneSet<Node*> to_remove_;
+ const UnobservablesSet unobservables_visited_empty_;
+ };
};
} // namespace compiler
diff --git a/deps/v8/src/compiler/typer.cc b/deps/v8/src/compiler/typer.cc
index 5dbbad3dcd..6ba1b39431 100644
--- a/deps/v8/src/compiler/typer.cc
+++ b/deps/v8/src/compiler/typer.cc
@@ -10,6 +10,7 @@
#include "src/codegen/tick-counter.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/graph-reducer.h"
+#include "src/compiler/js-heap-broker.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/linkage.h"
#include "src/compiler/loop-variable-optimizer.h"
@@ -787,7 +788,13 @@ Type Typer::Visitor::TypeParameter(Node* node) {
return Type::NonInternal();
}
-Type Typer::Visitor::TypeOsrValue(Node* node) { return Type::Any(); }
+Type Typer::Visitor::TypeOsrValue(Node* node) {
+ if (OsrValueIndexOf(node->op()) == Linkage::kOsrContextSpillSlotIndex) {
+ return Type::OtherInternal();
+ } else {
+ return Type::Any();
+ }
+}
Type Typer::Visitor::TypeRetain(Node* node) { UNREACHABLE(); }
@@ -999,10 +1006,6 @@ Type Typer::Visitor::TypeTypedObjectState(Node* node) {
Type Typer::Visitor::TypeCall(Node* node) { return Type::Any(); }
-Type Typer::Visitor::TypeCallWithCallerSavedRegisters(Node* node) {
- UNREACHABLE();
-}
-
Type Typer::Visitor::TypeProjection(Node* node) {
Type const type = Operand(node, 0);
if (type.Is(Type::None())) return Type::None();
@@ -1524,6 +1527,10 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
return Type::NonInternal();
}
JSFunctionRef function = fun.AsHeapConstant()->Ref().AsJSFunction();
+ if (!function.serialized()) {
+ TRACE_BROKER_MISSING(t->broker(), "data for function " << function);
+ return Type::NonInternal();
+ }
if (!function.shared().HasBuiltinId()) {
return Type::NonInternal();
}
@@ -1564,6 +1571,7 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
case Builtins::kMathPow:
case Builtins::kMathMax:
case Builtins::kMathMin:
+ case Builtins::kMathHypot:
return Type::Number();
case Builtins::kMathImul:
return Type::Signed32();
@@ -2364,6 +2372,8 @@ Type Typer::Visitor::TypeConstant(Handle<Object> value) {
return Type::NewConstant(typer_->broker(), value, zone());
}
+Type Typer::Visitor::TypeJSGetIterator(Node* node) { return Type::Any(); }
+
} // namespace compiler
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/compiler/types.cc b/deps/v8/src/compiler/types.cc
index d4267a75fe..018c54c3d5 100644
--- a/deps/v8/src/compiler/types.cc
+++ b/deps/v8/src/compiler/types.cc
@@ -324,7 +324,6 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
// Remaining instance types are unsupported for now. If any of them do
// require bit set types, they should get kOtherInternal.
- case MUTABLE_HEAP_NUMBER_TYPE:
case FREE_SPACE_TYPE:
case FILLER_TYPE:
case ACCESS_CHECK_INFO_TYPE:
@@ -365,7 +364,6 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case PROMISE_FULFILL_REACTION_JOB_TASK_TYPE:
case PROMISE_REJECT_REACTION_JOB_TASK_TYPE:
case PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE:
- case FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE:
#define MAKE_TORQUE_CLASS_TYPE(V) case V:
TORQUE_DEFINED_INSTANCE_TYPES(MAKE_TORQUE_CLASS_TYPE)
#undef MAKE_TORQUE_CLASS_TYPE
diff --git a/deps/v8/src/compiler/vector-slot-pair.cc b/deps/v8/src/compiler/vector-slot-pair.cc
deleted file mode 100644
index 97f53648a4..0000000000
--- a/deps/v8/src/compiler/vector-slot-pair.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/vector-slot-pair.h"
-
-#include "src/objects/feedback-vector.h"
-
-namespace v8 {
-namespace internal {
-
-VectorSlotPair::VectorSlotPair() = default;
-
-int VectorSlotPair::index() const {
- return vector_.is_null() ? -1 : FeedbackVector::GetIndex(slot_);
-}
-
-bool operator==(VectorSlotPair const& lhs, VectorSlotPair const& rhs) {
- return lhs.slot() == rhs.slot() &&
- lhs.vector().location() == rhs.vector().location() &&
- lhs.ic_state() == rhs.ic_state();
-}
-
-bool operator!=(VectorSlotPair const& lhs, VectorSlotPair const& rhs) {
- return !(lhs == rhs);
-}
-
-std::ostream& operator<<(std::ostream& os, const VectorSlotPair& p) {
- if (p.IsValid()) {
- return os << "VectorSlotPair(" << p.slot() << ", "
- << InlineCacheState2String(p.ic_state()) << ")";
- }
- return os << "VectorSlotPair(INVALID)";
-}
-
-size_t hash_value(VectorSlotPair const& p) {
- return base::hash_combine(p.slot(), p.vector().location(), p.ic_state());
-}
-
-} // namespace internal
-} // namespace v8
diff --git a/deps/v8/src/compiler/vector-slot-pair.h b/deps/v8/src/compiler/vector-slot-pair.h
deleted file mode 100644
index 9944544a13..0000000000
--- a/deps/v8/src/compiler/vector-slot-pair.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2017 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_COMPILER_VECTOR_SLOT_PAIR_H_
-#define V8_COMPILER_VECTOR_SLOT_PAIR_H_
-
-#include "src/common/globals.h"
-#include "src/handles/handles.h"
-#include "src/utils/utils.h"
-
-namespace v8 {
-namespace internal {
-
-class FeedbackVector;
-
-// Defines a pair of {FeedbackVector} and {FeedbackSlot}, which
-// is used to access the type feedback for a certain {Node}.
-class V8_EXPORT_PRIVATE VectorSlotPair {
- public:
- VectorSlotPair();
- VectorSlotPair(Handle<FeedbackVector> vector, FeedbackSlot slot,
- InlineCacheState ic_state)
- : vector_(vector), slot_(slot), ic_state_(ic_state) {}
-
- bool IsValid() const { return !vector_.is_null() && !slot_.IsInvalid(); }
-
- Handle<FeedbackVector> vector() const { return vector_; }
- FeedbackSlot slot() const { return slot_; }
- InlineCacheState ic_state() const { return ic_state_; }
-
- int index() const;
-
- private:
- Handle<FeedbackVector> vector_;
- FeedbackSlot slot_;
- InlineCacheState ic_state_ = UNINITIALIZED;
-};
-
-bool operator==(VectorSlotPair const&, VectorSlotPair const&);
-bool operator!=(VectorSlotPair const&, VectorSlotPair const&);
-
-V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
- VectorSlotPair const&);
-
-size_t hash_value(VectorSlotPair const&);
-
-} // namespace internal
-} // namespace v8
-
-#endif // V8_COMPILER_VECTOR_SLOT_PAIR_H_
diff --git a/deps/v8/src/compiler/verifier.cc b/deps/v8/src/compiler/verifier.cc
index d3d4d54ea2..608d6ffee6 100644
--- a/deps/v8/src/compiler/verifier.cc
+++ b/deps/v8/src/compiler/verifier.cc
@@ -580,7 +580,6 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
// TODO(jarin): what are the constraints on these?
break;
case IrOpcode::kCall:
- case IrOpcode::kCallWithCallerSavedRegisters:
// TODO(rossberg): what are the constraints on these?
break;
case IrOpcode::kTailCall:
@@ -766,6 +765,11 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckNotTyped(node);
CHECK(StoreNamedOwnParametersOf(node->op()).feedback().IsValid());
break;
+ case IrOpcode::kJSGetIterator:
+ // Type can be anything
+ CheckValueInputIs(node, 0, Type::Any());
+ CheckTypeIs(node, Type::Any());
+ break;
case IrOpcode::kJSStoreDataPropertyInLiteral:
case IrOpcode::kJSStoreInArrayLiteral:
// Type is empty.
@@ -1800,6 +1804,8 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kBitcastTaggedSignedToWord:
case IrOpcode::kBitcastWordToTagged:
case IrOpcode::kBitcastWordToTaggedSigned:
+ case IrOpcode::kBitcastWord32ToCompressedSigned:
+ case IrOpcode::kBitcastCompressedSignedToWord32:
case IrOpcode::kChangeInt32ToInt64:
case IrOpcode::kChangeUint32ToUint64:
case IrOpcode::kChangeTaggedToCompressed:
@@ -1838,7 +1844,6 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kTaggedPoisonOnSpeculation:
case IrOpcode::kWord32PoisonOnSpeculation:
case IrOpcode::kWord64PoisonOnSpeculation:
- case IrOpcode::kLoadStackPointer:
case IrOpcode::kLoadFramePointer:
case IrOpcode::kLoadParentFramePointer:
case IrOpcode::kUnalignedLoad:
@@ -1877,6 +1882,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kSignExtendWord16ToInt64:
case IrOpcode::kSignExtendWord32ToInt64:
case IrOpcode::kStaticAssert:
+ case IrOpcode::kStackPointerGreaterThan:
#define SIMD_MACHINE_OP_CASE(Name) case IrOpcode::k##Name:
MACHINE_SIMD_OP_LIST(SIMD_MACHINE_OP_CASE)
diff --git a/deps/v8/src/compiler/wasm-compiler.cc b/deps/v8/src/compiler/wasm-compiler.cc
index 2da7177ece..28f9943e59 100644
--- a/deps/v8/src/compiler/wasm-compiler.cc
+++ b/deps/v8/src/compiler/wasm-compiler.cc
@@ -25,12 +25,11 @@
#include "src/compiler/graph-visualizer.h"
#include "src/compiler/graph.h"
#include "src/compiler/int64-lowering.h"
-#include "src/compiler/js-graph.h"
-#include "src/compiler/js-operator.h"
#include "src/compiler/linkage.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-origin-table.h"
+#include "src/compiler/node-properties.h"
#include "src/compiler/pipeline.h"
#include "src/compiler/simd-scalar-lowering.h"
#include "src/compiler/zone-stats.h"
@@ -259,25 +258,25 @@ Node* WasmGraphBuilder::Merge(unsigned count, Node** controls) {
Node* WasmGraphBuilder::Phi(wasm::ValueType type, unsigned count, Node** vals,
Node* control) {
DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
- Node** buf = Realloc(vals, count, count + 1);
+ Vector<Node*> buf = Realloc(vals, count, count + 1);
buf[count] = control;
return graph()->NewNode(
mcgraph()->common()->Phi(wasm::ValueTypes::MachineRepresentationFor(type),
count),
- count + 1, buf);
+ count + 1, buf.begin());
}
Node* WasmGraphBuilder::EffectPhi(unsigned count, Node** effects,
Node* control) {
DCHECK(IrOpcode::IsMergeOpcode(control->opcode()));
- Node** buf = Realloc(effects, count, count + 1);
+ Vector<Node*> buf = Realloc(effects, count, count + 1);
buf[count] = control;
return graph()->NewNode(mcgraph()->common()->EffectPhi(count), count + 1,
- buf);
+ buf.begin());
}
Node* WasmGraphBuilder::RefNull() {
- Node* isolate_root = LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
+ Node* isolate_root = BuildLoadIsolateRoot();
return LOAD_TAGGED_POINTER(
isolate_root, IsolateData::root_slot_offset(RootIndex::kNullValue));
}
@@ -291,10 +290,17 @@ Node* WasmGraphBuilder::RefFunc(uint32_t function_index) {
}
Node* WasmGraphBuilder::NoContextConstant() {
- // TODO(titzer): avoiding a dependency on JSGraph here. Refactor.
return mcgraph()->IntPtrConstant(0);
}
+Node* WasmGraphBuilder::BuildLoadIsolateRoot() {
+ // The IsolateRoot is loaded from the instance node so that the generated
+ // code is Isolate independent. This can be overridden by setting a specific
+ // node in {isolate_root_node_} beforehand.
+ if (isolate_root_node_.is_set()) return isolate_root_node_.get();
+ return LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
+}
+
Node* WasmGraphBuilder::Uint32Constant(uint32_t value) {
return mcgraph()->Uint32Constant(value);
}
@@ -320,10 +326,6 @@ void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
if (effect == nullptr) effect = effect_;
if (control == nullptr) control = control_;
- // This instruction sequence is matched in the instruction selector to
- // load the stack pointer directly on some platforms. Hence, when modifying
- // please also fix WasmStackCheckMatcher in node-matchers.h
-
Node* limit_address = graph()->NewNode(
mcgraph()->machine()->Load(MachineType::Pointer()), instance_node_.get(),
mcgraph()->Int32Constant(WASM_INSTANCE_OBJECT_OFFSET(StackLimitAddress)),
@@ -332,10 +334,9 @@ void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
mcgraph()->machine()->Load(MachineType::Pointer()), limit_address,
mcgraph()->IntPtrConstant(0), limit_address, *control);
*effect = limit;
- Node* pointer = graph()->NewNode(mcgraph()->machine()->LoadStackPointer());
Node* check =
- graph()->NewNode(mcgraph()->machine()->UintLessThan(), limit, pointer);
+ graph()->NewNode(mcgraph()->machine()->StackPointerGreaterThan(), limit);
Diamond stack_check(graph(), mcgraph()->common(), check, BranchHint::kTrue);
stack_check.Chain(*control);
@@ -1126,12 +1127,13 @@ Node* WasmGraphBuilder::IfDefault(Node* sw) {
return graph()->NewNode(mcgraph()->common()->IfDefault(), sw);
}
-Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
+Node* WasmGraphBuilder::Return(Vector<Node*> vals) {
static const int kStackAllocatedNodeBufferSize = 8;
Node* stack_buffer[kStackAllocatedNodeBufferSize];
std::vector<Node*> heap_buffer;
Node** buf = stack_buffer;
+ unsigned count = static_cast<unsigned>(vals.size());
if (count + 3 > kStackAllocatedNodeBufferSize) {
heap_buffer.resize(count + 3);
buf = heap_buffer.data();
@@ -1139,7 +1141,7 @@ Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
buf[0] = mcgraph()->Int32Constant(0);
if (count > 0) {
- memcpy(buf + 1, vals, sizeof(void*) * count);
+ memcpy(buf + 1, vals.begin(), sizeof(void*) * count);
}
buf[count + 1] = Effect();
buf[count + 2] = Control();
@@ -1150,11 +1152,9 @@ Node* WasmGraphBuilder::Return(unsigned count, Node** vals) {
return ret;
}
-Node* WasmGraphBuilder::ReturnVoid() { return Return(0, nullptr); }
-
Node* WasmGraphBuilder::Unreachable(wasm::WasmCodePosition position) {
TrapIfFalse(wasm::TrapReason::kTrapUnreachable, Int32Constant(0), position);
- ReturnVoid();
+ Return(Vector<Node*>{});
return nullptr;
}
@@ -2295,13 +2295,13 @@ Node* WasmGraphBuilder::GetExceptionTag(Node* except_obj) {
return BuildCallToRuntime(Runtime::kWasmExceptionGetTag, &except_obj, 1);
}
-Node** WasmGraphBuilder::GetExceptionValues(
+Vector<Node*> WasmGraphBuilder::GetExceptionValues(
Node* except_obj, const wasm::WasmException* exception) {
Node* values_array =
BuildCallToRuntime(Runtime::kWasmExceptionGetValues, &except_obj, 1);
uint32_t index = 0;
const wasm::WasmExceptionSig* sig = exception->sig;
- Node** values = Buffer(sig->parameter_count());
+ Vector<Node*> values = Buffer(sig->parameter_count());
for (size_t i = 0; i < sig->parameter_count(); ++i) {
Node* value;
switch (sig->GetParam(i)) {
@@ -2695,7 +2695,7 @@ Node* WasmGraphBuilder::BuildCallNode(wasm::FunctionSig* sig, Node** args,
const size_t count = 1 + params + extra;
// Reallocate the buffer to make space for extra inputs.
- args = Realloc(args, 1 + params, count);
+ args = Realloc(args, 1 + params, count).begin();
// Make room for the instance_node parameter at index 1, just after code.
memmove(&args[2], &args[1], params * sizeof(Node*));
@@ -2725,7 +2725,7 @@ Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args,
size_t ret_count = sig->return_count();
if (ret_count == 0) return call; // No return value.
- *rets = Buffer(ret_count);
+ *rets = Buffer(ret_count).begin();
if (ret_count == 1) {
// Only a single return value.
(*rets)[0] = call;
@@ -3183,12 +3183,12 @@ Node* WasmGraphBuilder::CreateOrMergeIntoPhi(MachineRepresentation rep,
} else if (tnode != fnode) {
uint32_t count = merge->InputCount();
// + 1 for the merge node.
- Node** vals = Buffer(count + 1);
+ Vector<Node*> vals = Buffer(count + 1);
for (uint32_t j = 0; j < count - 1; j++) vals[j] = tnode;
vals[count - 1] = fnode;
vals[count] = merge;
return graph()->NewNode(mcgraph()->common()->Phi(rep, count), count + 1,
- vals);
+ vals.begin());
}
return tnode;
}
@@ -3199,12 +3199,12 @@ Node* WasmGraphBuilder::CreateOrMergeIntoEffectPhi(Node* merge, Node* tnode,
AppendToPhi(tnode, fnode);
} else if (tnode != fnode) {
uint32_t count = merge->InputCount();
- Node** effects = Buffer(count);
+ Vector<Node*> effects = Buffer(count);
for (uint32_t j = 0; j < count - 1; j++) {
effects[j] = tnode;
}
effects[count - 1] = fnode;
- tnode = EffectPhi(count, effects, merge);
+ tnode = EffectPhi(count, effects.begin(), merge);
}
return tnode;
}
@@ -3326,11 +3326,14 @@ Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(
auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
mcgraph()->zone(), f, fun->nargs, Operator::kNoProperties,
CallDescriptor::kNoFlags);
- // The CEntryStub is loaded from the instance_node so that generated code is
+ // The CEntryStub is loaded from the IsolateRoot so that generated code is
// Isolate independent. At the moment this is only done for CEntryStub(1).
+ Node* isolate_root = BuildLoadIsolateRoot();
DCHECK_EQ(1, fun->result_size);
- Node* centry_stub = LOAD_INSTANCE_FIELD(
- CEntryStub, MachineType::TypeCompressedTaggedPointer());
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ Node* centry_stub = LOAD_TAGGED_POINTER(
+ isolate_root, IsolateData::builtin_slot_offset(centry_id));
// TODO(titzer): allow arbitrary number of runtime arguments
// At the moment we only allow 5 parameters. If more parameters are needed,
// increase this constant accordingly.
@@ -3943,30 +3946,43 @@ Graph* WasmGraphBuilder::graph() { return mcgraph()->graph(); }
namespace {
Signature<MachineRepresentation>* CreateMachineSignature(
- Zone* zone, wasm::FunctionSig* sig) {
+ Zone* zone, wasm::FunctionSig* sig, WasmGraphBuilder::CallOrigin origin) {
Signature<MachineRepresentation>::Builder builder(zone, sig->return_count(),
sig->parameter_count());
for (auto ret : sig->returns()) {
- builder.AddReturn(wasm::ValueTypes::MachineRepresentationFor(ret));
+ if (origin == WasmGraphBuilder::kCalledFromJS) {
+ builder.AddReturn(MachineRepresentation::kTagged);
+ } else {
+ builder.AddReturn(wasm::ValueTypes::MachineRepresentationFor(ret));
+ }
}
for (auto param : sig->parameters()) {
- builder.AddParam(wasm::ValueTypes::MachineRepresentationFor(param));
+ if (origin == WasmGraphBuilder::kCalledFromJS) {
+ // Parameters coming from JavaScript are always tagged values. Especially
+ // when the signature says that it's an I64 value, then a BigInt object is
+ // provided by JavaScript, and not two 32-bit parameters.
+ builder.AddParam(MachineRepresentation::kTagged);
+ } else {
+ builder.AddParam(wasm::ValueTypes::MachineRepresentationFor(param));
+ }
}
return builder.Build();
}
} // namespace
-void WasmGraphBuilder::LowerInt64() {
+void WasmGraphBuilder::LowerInt64(CallOrigin origin) {
if (mcgraph()->machine()->Is64()) return;
Int64Lowering r(mcgraph()->graph(), mcgraph()->machine(), mcgraph()->common(),
mcgraph()->zone(),
- CreateMachineSignature(mcgraph()->zone(), sig_));
+ CreateMachineSignature(mcgraph()->zone(), sig_, origin),
+ std::move(lowering_special_case_));
r.LowerGraph();
}
void WasmGraphBuilder::SimdScalarLoweringForTesting() {
- SimdScalarLowering(mcgraph(), CreateMachineSignature(mcgraph()->zone(), sig_))
+ SimdScalarLowering(mcgraph(), CreateMachineSignature(mcgraph()->zone(), sig_,
+ kCalledFromWasm))
.LowerGraph();
}
@@ -3992,6 +4008,24 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
return graph()->NewNode(mcgraph()->machine()->F64x2Abs(), inputs[0]);
case wasm::kExprF64x2Neg:
return graph()->NewNode(mcgraph()->machine()->F64x2Neg(), inputs[0]);
+ case wasm::kExprF64x2Add:
+ return graph()->NewNode(mcgraph()->machine()->F64x2Add(), inputs[0],
+ inputs[1]);
+ case wasm::kExprF64x2Sub:
+ return graph()->NewNode(mcgraph()->machine()->F64x2Sub(), inputs[0],
+ inputs[1]);
+ case wasm::kExprF64x2Mul:
+ return graph()->NewNode(mcgraph()->machine()->F64x2Mul(), inputs[0],
+ inputs[1]);
+ case wasm::kExprF64x2Div:
+ return graph()->NewNode(mcgraph()->machine()->F64x2Div(), inputs[0],
+ inputs[1]);
+ case wasm::kExprF64x2Min:
+ return graph()->NewNode(mcgraph()->machine()->F64x2Min(), inputs[0],
+ inputs[1]);
+ case wasm::kExprF64x2Max:
+ return graph()->NewNode(mcgraph()->machine()->F64x2Max(), inputs[0],
+ inputs[1]);
case wasm::kExprF64x2Eq:
return graph()->NewNode(mcgraph()->machine()->F64x2Eq(), inputs[0],
inputs[1]);
@@ -4040,6 +4074,9 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
case wasm::kExprF32x4Mul:
return graph()->NewNode(mcgraph()->machine()->F32x4Mul(), inputs[0],
inputs[1]);
+ case wasm::kExprF32x4Div:
+ return graph()->NewNode(mcgraph()->machine()->F32x4Div(), inputs[0],
+ inputs[1]);
case wasm::kExprF32x4Min:
return graph()->NewNode(mcgraph()->machine()->F32x4Min(), inputs[0],
inputs[1]);
@@ -4068,6 +4105,12 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
return graph()->NewNode(mcgraph()->machine()->I64x2Splat(), inputs[0]);
case wasm::kExprI64x2Neg:
return graph()->NewNode(mcgraph()->machine()->I64x2Neg(), inputs[0]);
+ case wasm::kExprI64x2Shl:
+ return graph()->NewNode(mcgraph()->machine()->I64x2Shl(), inputs[0],
+ inputs[1]);
+ case wasm::kExprI64x2ShrS:
+ return graph()->NewNode(mcgraph()->machine()->I64x2ShrS(), inputs[0],
+ inputs[1]);
case wasm::kExprI64x2Add:
return graph()->NewNode(mcgraph()->machine()->I64x2Add(), inputs[0],
inputs[1]);
@@ -4077,6 +4120,12 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
case wasm::kExprI64x2Mul:
return graph()->NewNode(mcgraph()->machine()->I64x2Mul(), inputs[0],
inputs[1]);
+ case wasm::kExprI64x2MinS:
+ return graph()->NewNode(mcgraph()->machine()->I64x2MinS(), inputs[0],
+ inputs[1]);
+ case wasm::kExprI64x2MaxS:
+ return graph()->NewNode(mcgraph()->machine()->I64x2MaxS(), inputs[0],
+ inputs[1]);
case wasm::kExprI64x2Eq:
return graph()->NewNode(mcgraph()->machine()->I64x2Eq(), inputs[0],
inputs[1]);
@@ -4095,6 +4144,15 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
case wasm::kExprI64x2GeS:
return graph()->NewNode(mcgraph()->machine()->I64x2GeS(), inputs[0],
inputs[1]);
+ case wasm::kExprI64x2ShrU:
+ return graph()->NewNode(mcgraph()->machine()->I64x2ShrU(), inputs[0],
+ inputs[1]);
+ case wasm::kExprI64x2MinU:
+ return graph()->NewNode(mcgraph()->machine()->I64x2MinU(), inputs[0],
+ inputs[1]);
+ case wasm::kExprI64x2MaxU:
+ return graph()->NewNode(mcgraph()->machine()->I64x2MaxU(), inputs[0],
+ inputs[1]);
case wasm::kExprI64x2LtU:
return graph()->NewNode(mcgraph()->machine()->I64x2GtU(), inputs[1],
inputs[0]);
@@ -4123,6 +4181,12 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
inputs[0]);
case wasm::kExprI32x4Neg:
return graph()->NewNode(mcgraph()->machine()->I32x4Neg(), inputs[0]);
+ case wasm::kExprI32x4Shl:
+ return graph()->NewNode(mcgraph()->machine()->I32x4Shl(), inputs[0],
+ inputs[1]);
+ case wasm::kExprI32x4ShrS:
+ return graph()->NewNode(mcgraph()->machine()->I32x4ShrS(), inputs[0],
+ inputs[1]);
case wasm::kExprI32x4Add:
return graph()->NewNode(mcgraph()->machine()->I32x4Add(), inputs[0],
inputs[1]);
@@ -4165,6 +4229,9 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
case wasm::kExprI32x4UConvertI16x8High:
return graph()->NewNode(mcgraph()->machine()->I32x4UConvertI16x8High(),
inputs[0]);
+ case wasm::kExprI32x4ShrU:
+ return graph()->NewNode(mcgraph()->machine()->I32x4ShrU(), inputs[0],
+ inputs[1]);
case wasm::kExprI32x4MinU:
return graph()->NewNode(mcgraph()->machine()->I32x4MinU(), inputs[0],
inputs[1]);
@@ -4191,6 +4258,12 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
case wasm::kExprI16x8SConvertI8x16High:
return graph()->NewNode(mcgraph()->machine()->I16x8SConvertI8x16High(),
inputs[0]);
+ case wasm::kExprI16x8Shl:
+ return graph()->NewNode(mcgraph()->machine()->I16x8Shl(), inputs[0],
+ inputs[1]);
+ case wasm::kExprI16x8ShrS:
+ return graph()->NewNode(mcgraph()->machine()->I16x8ShrS(), inputs[0],
+ inputs[1]);
case wasm::kExprI16x8Neg:
return graph()->NewNode(mcgraph()->machine()->I16x8Neg(), inputs[0]);
case wasm::kExprI16x8SConvertI32x4:
@@ -4247,6 +4320,9 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
case wasm::kExprI16x8UConvertI32x4:
return graph()->NewNode(mcgraph()->machine()->I16x8UConvertI32x4(),
inputs[0], inputs[1]);
+ case wasm::kExprI16x8ShrU:
+ return graph()->NewNode(mcgraph()->machine()->I16x8ShrU(), inputs[0],
+ inputs[1]);
case wasm::kExprI16x8AddSaturateU:
return graph()->NewNode(mcgraph()->machine()->I16x8AddSaturateU(),
inputs[0], inputs[1]);
@@ -4275,6 +4351,12 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
return graph()->NewNode(mcgraph()->machine()->I8x16Splat(), inputs[0]);
case wasm::kExprI8x16Neg:
return graph()->NewNode(mcgraph()->machine()->I8x16Neg(), inputs[0]);
+ case wasm::kExprI8x16Shl:
+ return graph()->NewNode(mcgraph()->machine()->I8x16Shl(), inputs[0],
+ inputs[1]);
+ case wasm::kExprI8x16ShrS:
+ return graph()->NewNode(mcgraph()->machine()->I8x16ShrS(), inputs[0],
+ inputs[1]);
case wasm::kExprI8x16SConvertI16x8:
return graph()->NewNode(mcgraph()->machine()->I8x16SConvertI16x8(),
inputs[0], inputs[1]);
@@ -4317,6 +4399,9 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
case wasm::kExprI8x16GeS:
return graph()->NewNode(mcgraph()->machine()->I8x16GeS(), inputs[0],
inputs[1]);
+ case wasm::kExprI8x16ShrU:
+ return graph()->NewNode(mcgraph()->machine()->I8x16ShrU(), inputs[0],
+ inputs[1]);
case wasm::kExprI8x16UConvertI16x8:
return graph()->NewNode(mcgraph()->machine()->I8x16UConvertI16x8(),
inputs[0], inputs[1]);
@@ -4424,47 +4509,6 @@ Node* WasmGraphBuilder::SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane,
}
}
-Node* WasmGraphBuilder::SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift,
- Node* const* inputs) {
- has_simd_ = true;
- switch (opcode) {
- case wasm::kExprI64x2Shl:
- return graph()->NewNode(mcgraph()->machine()->I64x2Shl(shift), inputs[0]);
- case wasm::kExprI64x2ShrS:
- return graph()->NewNode(mcgraph()->machine()->I64x2ShrS(shift),
- inputs[0]);
- case wasm::kExprI64x2ShrU:
- return graph()->NewNode(mcgraph()->machine()->I64x2ShrU(shift),
- inputs[0]);
- case wasm::kExprI32x4Shl:
- return graph()->NewNode(mcgraph()->machine()->I32x4Shl(shift), inputs[0]);
- case wasm::kExprI32x4ShrS:
- return graph()->NewNode(mcgraph()->machine()->I32x4ShrS(shift),
- inputs[0]);
- case wasm::kExprI32x4ShrU:
- return graph()->NewNode(mcgraph()->machine()->I32x4ShrU(shift),
- inputs[0]);
- case wasm::kExprI16x8Shl:
- return graph()->NewNode(mcgraph()->machine()->I16x8Shl(shift), inputs[0]);
- case wasm::kExprI16x8ShrS:
- return graph()->NewNode(mcgraph()->machine()->I16x8ShrS(shift),
- inputs[0]);
- case wasm::kExprI16x8ShrU:
- return graph()->NewNode(mcgraph()->machine()->I16x8ShrU(shift),
- inputs[0]);
- case wasm::kExprI8x16Shl:
- return graph()->NewNode(mcgraph()->machine()->I8x16Shl(shift), inputs[0]);
- case wasm::kExprI8x16ShrS:
- return graph()->NewNode(mcgraph()->machine()->I8x16ShrS(shift),
- inputs[0]);
- case wasm::kExprI8x16ShrU:
- return graph()->NewNode(mcgraph()->machine()->I8x16ShrU(shift),
- inputs[0]);
- default:
- FATAL_UNSUPPORTED_OPCODE(opcode);
- }
-}
-
Node* WasmGraphBuilder::Simd8x16ShuffleOp(const uint8_t shuffle[16],
Node* const* inputs) {
has_simd_ = true;
@@ -5010,15 +5054,86 @@ void WasmGraphBuilder::RemoveBytecodePositionDecorator() {
namespace {
class WasmWrapperGraphBuilder : public WasmGraphBuilder {
public:
- WasmWrapperGraphBuilder(Zone* zone, JSGraph* jsgraph, wasm::FunctionSig* sig,
+ WasmWrapperGraphBuilder(Zone* zone, MachineGraph* mcgraph,
+ wasm::FunctionSig* sig,
compiler::SourcePositionTable* spt,
StubCallMode stub_mode, wasm::WasmFeatures features)
- : WasmGraphBuilder(nullptr, zone, jsgraph, sig, spt),
- isolate_(jsgraph->isolate()),
- jsgraph_(jsgraph),
+ : WasmGraphBuilder(nullptr, zone, mcgraph, sig, spt),
stub_mode_(stub_mode),
enabled_features_(features) {}
+ CallDescriptor* GetI32PairToBigIntCallDescriptor() {
+ I32PairToBigIntDescriptor interface_descriptor;
+
+ return Linkage::GetStubCallDescriptor(
+ mcgraph()->zone(), // zone
+ interface_descriptor, // descriptor
+ interface_descriptor.GetStackParameterCount(), // stack parameter count
+ CallDescriptor::kNoFlags, // flags
+ Operator::kNoProperties, // properties
+ stub_mode_); // stub call mode
+ }
+
+ CallDescriptor* GetI64ToBigIntCallDescriptor() {
+ if (!lowering_special_case_) {
+ lowering_special_case_ = base::make_unique<Int64LoweringSpecialCase>();
+ }
+
+ if (lowering_special_case_->i64_to_bigint_call_descriptor) {
+ return lowering_special_case_->i64_to_bigint_call_descriptor;
+ }
+
+ I64ToBigIntDescriptor interface_descriptor;
+ auto call_descriptor = Linkage::GetStubCallDescriptor(
+ mcgraph()->zone(), // zone
+ interface_descriptor, // descriptor
+ interface_descriptor.GetStackParameterCount(), // stack parameter count
+ CallDescriptor::kNoFlags, // flags
+ Operator::kNoProperties, // properties
+ stub_mode_); // stub call mode
+
+ lowering_special_case_->i64_to_bigint_call_descriptor = call_descriptor;
+ lowering_special_case_->i32_pair_to_bigint_call_descriptor =
+ GetI32PairToBigIntCallDescriptor();
+ return call_descriptor;
+ }
+
+ CallDescriptor* GetBigIntToI32PairCallDescriptor() {
+ BigIntToI32PairDescriptor interface_descriptor;
+
+ return Linkage::GetStubCallDescriptor(
+ mcgraph()->zone(), // zone
+ interface_descriptor, // descriptor
+ interface_descriptor.GetStackParameterCount(), // stack parameter count
+ CallDescriptor::kNoFlags, // flags
+ Operator::kNoProperties, // properties
+ stub_mode_); // stub call mode
+ }
+
+ CallDescriptor* GetBigIntToI64CallDescriptor() {
+ if (!lowering_special_case_) {
+ lowering_special_case_ = base::make_unique<Int64LoweringSpecialCase>();
+ }
+
+ if (lowering_special_case_->bigint_to_i64_call_descriptor) {
+ return lowering_special_case_->bigint_to_i64_call_descriptor;
+ }
+
+ BigIntToI64Descriptor interface_descriptor;
+ auto call_descriptor = Linkage::GetStubCallDescriptor(
+ mcgraph()->zone(), // zone
+ interface_descriptor, // descriptor
+ interface_descriptor.GetStackParameterCount(), // stack parameter count
+ CallDescriptor::kNoFlags, // flags
+ Operator::kNoProperties, // properties
+ stub_mode_); // stub call mode
+
+ lowering_special_case_->bigint_to_i64_call_descriptor = call_descriptor;
+ lowering_special_case_->bigint_to_i32_pair_call_descriptor =
+ GetBigIntToI32PairCallDescriptor();
+ return call_descriptor;
+ }
+
Node* BuildAllocateHeapNumberWithValue(Node* value, Node* control) {
MachineOperatorBuilder* machine = mcgraph()->machine();
CommonOperatorBuilder* common = mcgraph()->common();
@@ -5027,7 +5142,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
? mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmAllocateHeapNumber,
RelocInfo::WASM_STUB_CALL)
- : BuildLoadBuiltinFromInstance(Builtins::kAllocateHeapNumber);
+ : BuildLoadBuiltinFromIsolateRoot(Builtins::kAllocateHeapNumber);
if (!allocate_heap_number_operator_.is_set()) {
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), AllocateHeapNumberDescriptor(), 0,
@@ -5084,10 +5199,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return undefined_value_node_.get();
}
- Node* BuildLoadBuiltinFromInstance(int builtin_index) {
+ Node* BuildLoadBuiltinFromIsolateRoot(int builtin_index) {
DCHECK(Builtins::IsBuiltinId(builtin_index));
- Node* isolate_root =
- LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
+ Node* isolate_root = BuildLoadIsolateRoot();
return LOAD_TAGGED_POINTER(isolate_root,
IsolateData::builtin_slot_offset(builtin_index));
}
@@ -5213,7 +5327,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
vsmi, vbox, merge);
}
- int AddArgumentNodes(Node** args, int pos, int param_count,
+ int AddArgumentNodes(Vector<Node*> args, int pos, int param_count,
wasm::FunctionSig* sig) {
// Convert wasm numbers to JS values.
for (int i = 0; i < param_count; ++i) {
@@ -5232,7 +5346,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
(stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
? mcgraph()->RelocatableIntPtrConstant(
wasm::WasmCode::kWasmToNumber, RelocInfo::WASM_STUB_CALL)
- : BuildLoadBuiltinFromInstance(Builtins::kToNumber);
+ : BuildLoadBuiltinFromIsolateRoot(Builtins::kToNumber);
Node* result = SetEffect(
graph()->NewNode(mcgraph()->common()->Call(call_descriptor), stub_code,
@@ -5317,47 +5431,59 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
}
Node* BuildChangeInt64ToBigInt(Node* input) {
- I64ToBigIntDescriptor interface_descriptor;
-
- auto call_descriptor = Linkage::GetStubCallDescriptor(
- mcgraph()->zone(), // zone
- interface_descriptor, // descriptor
- interface_descriptor.GetStackParameterCount(), // stack parameter count
- CallDescriptor::kNoFlags, // flags
- Operator::kNoProperties, // properties
- stub_mode_); // stub call mode
-
- Node* target =
- (stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
- ? mcgraph()->RelocatableIntPtrConstant(
- wasm::WasmCode::kWasmI64ToBigInt, RelocInfo::WASM_STUB_CALL)
- : BuildLoadBuiltinFromInstance(Builtins::kI64ToBigInt);
+ const Operator* call =
+ mcgraph()->common()->Call(GetI64ToBigIntCallDescriptor());
+
+ Node* target;
+ if (mcgraph()->machine()->Is64()) {
+ target =
+ (stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
+ ? mcgraph()->RelocatableIntPtrConstant(
+ wasm::WasmCode::kWasmI64ToBigInt, RelocInfo::WASM_STUB_CALL)
+ : BuildLoadBuiltinFromIsolateRoot(Builtins::kI64ToBigInt);
+ } else {
+ DCHECK(mcgraph()->machine()->Is32());
+ // On 32-bit platforms we already set the target to the
+ // I32PairToBigInt builtin here, so that we don't have to replace the
+ // target in the int64-lowering.
+ target =
+ (stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
+ ? mcgraph()->RelocatableIntPtrConstant(
+ wasm::WasmCode::kWasmI32PairToBigInt,
+ RelocInfo::WASM_STUB_CALL)
+ : BuildLoadBuiltinFromIsolateRoot(Builtins::kI32PairToBigInt);
+ }
return SetEffect(
- SetControl(graph()->NewNode(mcgraph()->common()->Call(call_descriptor),
- target, input, Effect(), Control())));
+ SetControl(graph()->NewNode(call, target, input, Effect(), Control())));
}
Node* BuildChangeBigIntToInt64(Node* input, Node* context) {
- BigIntToI64Descriptor interface_descriptor;
-
- auto call_descriptor = Linkage::GetStubCallDescriptor(
- mcgraph()->zone(), // zone
- interface_descriptor, // descriptor
- interface_descriptor.GetStackParameterCount(), // stack parameter count
- CallDescriptor::kNoFlags, // flags
- Operator::kNoProperties, // properties
- stub_mode_); // stub call mode
-
- Node* target =
- (stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
- ? mcgraph()->RelocatableIntPtrConstant(
- wasm::WasmCode::kWasmBigIntToI64, RelocInfo::WASM_STUB_CALL)
- : BuildLoadBuiltinFromInstance(Builtins::kBigIntToI64);
+ const Operator* call =
+ mcgraph()->common()->Call(GetBigIntToI64CallDescriptor());
+
+ Node* target;
+ if (mcgraph()->machine()->Is64()) {
+ target =
+ (stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
+ ? mcgraph()->RelocatableIntPtrConstant(
+ wasm::WasmCode::kWasmBigIntToI64, RelocInfo::WASM_STUB_CALL)
+ : BuildLoadBuiltinFromIsolateRoot(Builtins::kBigIntToI64);
+ } else {
+ DCHECK(mcgraph()->machine()->Is32());
+ // On 32-bit platforms we already set the target to the
+ // BigIntToI32Pair builtin here, so that we don't have to replace the
+ // target in the int64-lowering.
+ target =
+ (stub_mode_ == StubCallMode::kCallWasmRuntimeStub)
+ ? mcgraph()->RelocatableIntPtrConstant(
+ wasm::WasmCode::kWasmBigIntToI32Pair,
+ RelocInfo::WASM_STUB_CALL)
+ : BuildLoadBuiltinFromIsolateRoot(Builtins::kBigIntToI32Pair);
+ }
return SetEffect(SetControl(
- graph()->NewNode(mcgraph()->common()->Call(call_descriptor), target,
- input, context, Effect(), Control())));
+ graph()->NewNode(call, target, input, context, Effect(), Control())));
}
Node* FromJS(Node* node, Node* js_context, wasm::ValueType type) {
@@ -5427,8 +5553,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
void BuildModifyThreadInWasmFlag(bool new_value) {
if (!trap_handler::IsTrapHandlerEnabled()) return;
- Node* isolate_root =
- LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
+ Node* isolate_root = BuildLoadIsolateRoot();
Node* thread_in_wasm_flag_address =
LOAD_RAW(isolate_root, Isolate::thread_in_wasm_flag_address_offset(),
@@ -5446,9 +5571,10 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Diamond flag_check(graph(), mcgraph()->common(), check,
BranchHint::kTrue);
flag_check.Chain(Control());
- Node* message_id = jsgraph()->SmiConstant(static_cast<int32_t>(
- new_value ? AbortReason::kUnexpectedThreadInWasmSet
- : AbortReason::kUnexpectedThreadInWasmUnset));
+ Node* message_id = graph()->NewNode(
+ mcgraph()->common()->NumberConstant(static_cast<int32_t>(
+ new_value ? AbortReason::kUnexpectedThreadInWasmSet
+ : AbortReason::kUnexpectedThreadInWasmUnset)));
Node* effect = Effect();
BuildCallToRuntimeWithContext(Runtime::kAbort, NoContextConstant(),
@@ -5509,7 +5635,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
// Create the js_closure and js_context parameters.
Node* js_closure =
- graph()->NewNode(jsgraph()->common()->Parameter(
+ graph()->NewNode(mcgraph()->common()->Parameter(
Linkage::kJSCallClosureParamIndex, "%closure"),
graph()->start());
Node* js_context = graph()->NewNode(
@@ -5525,18 +5651,18 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
instance_node_.set(
BuildLoadInstanceFromExportedFunctionData(function_data));
- if (!wasm::IsJSCompatibleSignature(sig_, enabled_features_.bigint)) {
+ if (!wasm::IsJSCompatibleSignature(sig_, enabled_features_)) {
// Throw a TypeError. Use the js_context of the calling javascript
// function (passed as a parameter), such that the generated code is
// js_context independent.
BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, js_context,
nullptr, 0, effect_, Control());
- Return(jsgraph()->SmiConstant(0));
+ TerminateThrow(Effect(), Control());
return;
}
const int args_count = wasm_count + 1; // +1 for wasm_code.
- Node** args = Buffer(args_count);
+ Vector<Node*> args = Buffer(args_count);
Node** rets;
// Convert JS parameters to wasm numbers.
@@ -5554,8 +5680,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
// Load function index from {WasmExportedFunctionData}.
Node* function_index =
BuildLoadFunctionIndexFromExportedFunctionData(function_data);
- BuildImportCall(sig_, args, &rets, wasm::kNoCodePosition, function_index,
- kCallContinues);
+ BuildImportCall(sig_, args.begin(), &rets, wasm::kNoCodePosition,
+ function_index, kCallContinues);
} else {
// Call to a wasm function defined in this module.
// The call target is the jump table slot for that function.
@@ -5567,16 +5693,35 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
mcgraph()->machine()->IntAdd(), jump_table_start, jump_table_offset);
args[0] = jump_table_slot;
- BuildWasmCall(sig_, args, &rets, wasm::kNoCodePosition, nullptr,
+ BuildWasmCall(sig_, args.begin(), &rets, wasm::kNoCodePosition, nullptr,
kNoRetpoline);
}
// Clear the ThreadInWasm flag.
BuildModifyThreadInWasmFlag(false);
- Node* jsval = sig_->return_count() == 0 ? jsgraph()->UndefinedConstant()
- : ToJS(rets[0], sig_->GetReturn());
+ Node* jsval;
+ if (sig_->return_count() == 0) {
+ jsval = BuildLoadUndefinedValueFromInstance();
+ } else if (sig_->return_count() == 1) {
+ jsval = ToJS(rets[0], sig_->GetReturn());
+ } else {
+ int32_t return_count = static_cast<int32_t>(sig_->return_count());
+ Node* size =
+ graph()->NewNode(mcgraph()->common()->NumberConstant(return_count));
+ // TODO(thibaudm): Replace runtime calls with TurboFan code.
+ Node* fixed_array =
+ BuildCallToRuntime(Runtime::kWasmNewMultiReturnFixedArray, &size, 1);
+ for (int i = 0; i < return_count; ++i) {
+ Node* value = ToJS(rets[i], sig_->GetReturn(i));
+ STORE_FIXED_ARRAY_SLOT_ANY(fixed_array, i, value);
+ }
+ jsval = BuildCallToRuntimeWithContext(Runtime::kWasmNewMultiReturnJSArray,
+ js_context, &fixed_array, 1,
+ effect_, Control());
+ }
Return(jsval);
+ if (ContainsInt64(sig_)) LowerInt64(kCalledFromJS);
}
bool BuildWasmImportCallWrapper(WasmImportCallKind kind) {
@@ -5597,9 +5742,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError,
native_context, nullptr, 0, effect_,
Control());
- // We don't need to return a value here, as the runtime call will not
- // return anyway (the c entry stub will trigger stack unwinding).
- ReturnVoid();
+ TerminateThrow(Effect(), Control());
return false;
}
@@ -5622,7 +5765,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
sloppy_receiver = false;
V8_FALLTHROUGH; // fallthru
case WasmImportCallKind::kJSFunctionArityMatchSloppy: {
- Node** args = Buffer(wasm_count + 9);
+ Vector<Node*> args = Buffer(wasm_count + 7);
int pos = 0;
Node* function_context =
LOAD_RAW(callable_node,
@@ -5650,8 +5793,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
args[pos++] = Effect();
args[pos++] = Control();
+ DCHECK_EQ(pos, args.size());
call = graph()->NewNode(mcgraph()->common()->Call(call_descriptor), pos,
- args);
+ args.begin());
break;
}
// =======================================================================
@@ -5661,14 +5805,14 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
sloppy_receiver = false;
V8_FALLTHROUGH; // fallthru
case WasmImportCallKind::kJSFunctionArityMismatchSloppy: {
- Node** args = Buffer(wasm_count + 9);
+ Vector<Node*> args = Buffer(wasm_count + 9);
int pos = 0;
Node* function_context =
LOAD_RAW(callable_node,
wasm::ObjectAccess::ContextOffsetInTaggedJSFunction(),
MachineType::TypeCompressedTaggedPointer());
- args[pos++] =
- BuildLoadBuiltinFromInstance(Builtins::kArgumentsAdaptorTrampoline);
+ args[pos++] = BuildLoadBuiltinFromIsolateRoot(
+ Builtins::kArgumentsAdaptorTrampoline);
args[pos++] = callable_node; // target callable
args[pos++] = undefined_node; // new target
args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count
@@ -5712,26 +5856,27 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
args[pos++] = function_context;
args[pos++] = Effect();
args[pos++] = Control();
+
+ DCHECK_EQ(pos, args.size());
call = graph()->NewNode(mcgraph()->common()->Call(call_descriptor), pos,
- args);
+ args.begin());
break;
}
// =======================================================================
// === General case of unknown callable ==================================
// =======================================================================
case WasmImportCallKind::kUseCallBuiltin: {
- Node** args = Buffer(wasm_count + 9);
+ Vector<Node*> args = Buffer(wasm_count + 7);
int pos = 0;
- args[pos++] = mcgraph()->RelocatableIntPtrConstant(
- wasm::WasmCode::kWasmCallJavaScript, RelocInfo::WASM_STUB_CALL);
+ args[pos++] =
+ BuildLoadBuiltinFromIsolateRoot(Builtins::kCall_ReceiverIsAny);
args[pos++] = callable_node;
args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count
args[pos++] = undefined_node; // receiver
auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), CallTrampolineDescriptor{}, wasm_count + 1,
- CallDescriptor::kNoFlags, Operator::kNoProperties,
- StubCallMode::kCallWasmRuntimeStub);
+ CallDescriptor::kNoFlags, Operator::kNoProperties);
// Convert wasm numbers to JS values.
pos = AddArgumentNodes(args, pos, wasm_count, sig_);
@@ -5745,8 +5890,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
args[pos++] = Effect();
args[pos++] = Control();
+ DCHECK_EQ(pos, args.size());
call = graph()->NewNode(mcgraph()->common()->Call(call_descriptor), pos,
- args);
+ args.begin());
break;
}
default:
@@ -5766,6 +5912,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
BuildModifyThreadInWasmFlag(true);
Return(val);
+
+ if (ContainsInt64(sig_)) LowerInt64(kCalledFromWasm);
return true;
}
@@ -5807,13 +5955,12 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Node* sfi_data = LOAD_RAW(
shared, SharedFunctionInfo::kFunctionDataOffset - kHeapObjectTag,
MachineType::TypeCompressedTagged());
- Node* host_data = LOAD_RAW(
+ Node* host_data_foreign = LOAD_RAW(
sfi_data, WasmCapiFunctionData::kEmbedderDataOffset - kHeapObjectTag,
- MachineType::Pointer());
+ MachineType::TypeCompressedTagged());
BuildModifyThreadInWasmFlag(false);
- Node* isolate_root =
- LOAD_INSTANCE_FIELD(IsolateRoot, MachineType::Pointer());
+ Node* isolate_root = BuildLoadIsolateRoot();
Node* fp_value = graph()->NewNode(mcgraph()->machine()->LoadFramePointer());
STORE_RAW(isolate_root, Isolate::c_entry_fp_offset(), fp_value,
MachineType::PointerRepresentation(), kNoWriteBarrier);
@@ -5824,11 +5971,12 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Node* function =
graph()->NewNode(mcgraph()->common()->ExternalConstant(ref));
- // Parameters: void* data, Address arguments.
+ // Parameters: Address host_data_foreign, Address arguments.
MachineType host_sig_types[] = {
MachineType::Pointer(), MachineType::Pointer(), MachineType::Pointer()};
MachineSignature host_sig(1, 2, host_sig_types);
- Node* return_value = BuildCCall(&host_sig, function, host_data, values);
+ Node* return_value =
+ BuildCCall(&host_sig, function, host_data_foreign, values);
BuildModifyThreadInWasmFlag(true);
@@ -5854,13 +6002,13 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
SetControl(
graph()->NewNode(mcgraph()->common()->IfTrue(), exception_branch));
DCHECK_LT(sig_->return_count(), wasm::kV8MaxWasmFunctionMultiReturns);
- int return_count = static_cast<int>(sig_->return_count());
+ size_t return_count = sig_->return_count();
if (return_count == 0) {
Return(Int32Constant(0));
} else {
- Node** returns = Buffer(return_count);
+ Vector<Node*> returns = Buffer(return_count);
offset = 0;
- for (int i = 0; i < return_count; ++i) {
+ for (size_t i = 0; i < return_count; ++i) {
wasm::ValueType type = sig_->GetReturn(i);
Node* val = SetEffect(
graph()->NewNode(GetSafeLoadOperator(offset, type), values,
@@ -5868,10 +6016,10 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
returns[i] = val;
offset += wasm::ValueTypes::ElementSizeInBytes(type);
}
- Return(return_count, returns);
+ Return(returns);
}
- if (ContainsInt64(sig_)) LowerInt64();
+ if (ContainsInt64(sig_)) LowerInt64(kCalledFromWasm);
}
void BuildWasmInterpreterEntry(int func_index) {
@@ -5918,17 +6066,19 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
// We are passing the raw arg_buffer here. To the GC and other parts, it
// looks like a Smi (lowest bit not set). In the runtime function however,
// don't call Smi::value on it, but just cast it to a byte pointer.
- Node* parameters[] = {jsgraph()->SmiConstant(func_index), arg_buffer};
+ Node* parameters[] = {
+ graph()->NewNode(mcgraph()->common()->NumberConstant(func_index)),
+ arg_buffer};
BuildCallToRuntime(Runtime::kWasmRunInterpreter, parameters,
arraysize(parameters));
// Read back the return value.
DCHECK_LT(sig_->return_count(), wasm::kV8MaxWasmFunctionMultiReturns);
- unsigned return_count = static_cast<unsigned>(sig_->return_count());
+ size_t return_count = sig_->return_count();
if (return_count == 0) {
Return(Int32Constant(0));
} else {
- Node** returns = Buffer(return_count);
+ Vector<Node*> returns = Buffer(return_count);
offset = 0;
for (size_t i = 0; i < return_count; ++i) {
wasm::ValueType type = sig_->GetReturn(i);
@@ -5938,10 +6088,85 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
returns[i] = val;
offset += wasm::ValueTypes::ElementSizeInBytes(type);
}
- Return(return_count, returns);
+ Return(returns);
}
- if (ContainsInt64(sig_)) LowerInt64();
+ if (ContainsInt64(sig_)) LowerInt64(kCalledFromWasm);
+ }
+
+ void BuildJSToJSWrapper(Isolate* isolate) {
+ int wasm_count = static_cast<int>(sig_->parameter_count());
+
+ // Build the start and the parameter nodes.
+ int param_count = 1 /* closure */ + 1 /* receiver */ + wasm_count +
+ 1 /* new.target */ + 1 /* #arg */ + 1 /* context */;
+ SetEffect(SetControl(Start(param_count)));
+ Node* closure = Param(Linkage::kJSCallClosureParamIndex);
+ Node* context = Param(Linkage::GetJSCallContextParamIndex(wasm_count + 1));
+
+ // Since JS-to-JS wrappers are specific to one Isolate, it is OK to embed
+ // values (for undefined and root) directly into the instruction stream.
+ isolate_root_node_ = mcgraph()->IntPtrConstant(isolate->isolate_root());
+ undefined_value_node_ = graph()->NewNode(mcgraph()->common()->HeapConstant(
+ isolate->factory()->undefined_value()));
+
+ // Throw a TypeError if the signature is incompatible with JavaScript.
+ if (!wasm::IsJSCompatibleSignature(sig_, enabled_features_)) {
+ BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, context,
+ nullptr, 0, effect_, Control());
+ TerminateThrow(Effect(), Control());
+ return;
+ }
+
+ // Load the original callable from the closure.
+ Node* shared = LOAD_TAGGED_ANY(
+ closure,
+ wasm::ObjectAccess::ToTagged(JSFunction::kSharedFunctionInfoOffset));
+ Node* func_data = LOAD_TAGGED_ANY(
+ shared,
+ wasm::ObjectAccess::ToTagged(SharedFunctionInfo::kFunctionDataOffset));
+ Node* callable = LOAD_TAGGED_ANY(
+ func_data,
+ wasm::ObjectAccess::ToTagged(WasmJSFunctionData::kCallableOffset));
+
+ // Call the underlying closure.
+ Vector<Node*> args = Buffer(wasm_count + 7);
+ int pos = 0;
+ args[pos++] = graph()->NewNode(mcgraph()->common()->HeapConstant(
+ BUILTIN_CODE(isolate, Call_ReceiverIsAny)));
+ args[pos++] = callable;
+ args[pos++] = mcgraph()->Int32Constant(wasm_count); // argument count
+ args[pos++] = BuildLoadUndefinedValueFromInstance(); // receiver
+
+ auto call_descriptor = Linkage::GetStubCallDescriptor(
+ graph()->zone(), CallTrampolineDescriptor{}, wasm_count + 1,
+ CallDescriptor::kNoFlags, Operator::kNoProperties,
+ StubCallMode::kCallCodeObject);
+
+ // Convert parameter JS values to wasm numbers and back to JS values.
+ for (int i = 0; i < wasm_count; ++i) {
+ Node* param = Param(i + 1); // Start from index 1 to skip receiver.
+ args[pos++] =
+ ToJS(FromJS(param, context, sig_->GetParam(i)), sig_->GetParam(i));
+ }
+
+ args[pos++] = context;
+ args[pos++] = Effect();
+ args[pos++] = Control();
+
+ DCHECK_EQ(pos, args.size());
+ Node* call = SetEffect(graph()->NewNode(
+ mcgraph()->common()->Call(call_descriptor), pos, args.begin()));
+
+ // TODO(wasm): Extend this to support multi-return.
+ DCHECK_LE(sig_->return_count(), 1);
+
+ // Convert return JS values to wasm numbers and back to JS values.
+ Node* jsval =
+ sig_->return_count() == 0
+ ? BuildLoadUndefinedValueFromInstance()
+ : ToJS(FromJS(call, context, sig_->GetReturn()), sig_->GetReturn());
+ Return(jsval);
}
void BuildCWasmEntry() {
@@ -5959,8 +6184,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
kNoWriteBarrier);
int wasm_arg_count = static_cast<int>(sig_->parameter_count());
- int arg_count = wasm_arg_count + 4; // code, object_ref, control, effect
- Node** args = Buffer(arg_count);
+ Vector<Node*> args = Buffer(wasm_arg_count + 4);
int pos = 0;
args[pos++] = code_entry;
@@ -5977,13 +6201,13 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
args[pos++] = Effect();
args[pos++] = Control();
- DCHECK_EQ(arg_count, pos);
// Call the wasm code.
auto call_descriptor = GetWasmCallDescriptor(mcgraph()->zone(), sig_);
+ DCHECK_EQ(pos, args.size());
Node* call = SetEffect(graph()->NewNode(
- mcgraph()->common()->Call(call_descriptor), arg_count, args));
+ mcgraph()->common()->Call(call_descriptor), pos, args.begin()));
Node* if_success = graph()->NewNode(mcgraph()->common()->IfSuccess(), call);
Node* if_exception =
@@ -6011,9 +6235,12 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
pos++;
}
- Return(jsgraph()->SmiConstant(0));
+ Return(mcgraph()->IntPtrConstant(0));
if (mcgraph()->machine()->Is32() && ContainsInt64(sig_)) {
+ // No special lowering should be requested in the C entry.
+ DCHECK_NULL(lowering_special_case_);
+
MachineRepresentation sig_reps[] = {
MachineType::PointerRepresentation(), // return value
MachineType::PointerRepresentation(), // target
@@ -6028,11 +6255,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
}
}
- JSGraph* jsgraph() { return jsgraph_; }
-
private:
- Isolate* const isolate_;
- JSGraph* jsgraph_;
StubCallMode stub_mode_;
SetOncePointer<Node> undefined_value_node_;
SetOncePointer<const Operator> allocate_heap_number_operator_;
@@ -6058,26 +6281,27 @@ void AppendSignature(char* buffer, size_t max_name_len,
} // namespace
std::unique_ptr<OptimizedCompilationJob> NewJSToWasmCompilationJob(
- Isolate* isolate, wasm::FunctionSig* sig, bool is_import) {
+ Isolate* isolate, wasm::WasmEngine* wasm_engine, wasm::FunctionSig* sig,
+ bool is_import, const wasm::WasmFeatures& enabled_features) {
//----------------------------------------------------------------------------
// Create the Graph.
//----------------------------------------------------------------------------
std::unique_ptr<Zone> zone =
- base::make_unique<Zone>(isolate->allocator(), ZONE_NAME);
+ base::make_unique<Zone>(wasm_engine->allocator(), ZONE_NAME);
Graph* graph = new (zone.get()) Graph(zone.get());
CommonOperatorBuilder common(zone.get());
MachineOperatorBuilder machine(
zone.get(), MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags(),
InstructionSelector::AlignmentRequirements());
- JSGraph jsgraph(isolate, graph, &common, nullptr, nullptr, &machine);
+ MachineGraph mcgraph(graph, &common, &machine);
Node* control = nullptr;
Node* effect = nullptr;
- WasmWrapperGraphBuilder builder(zone.get(), &jsgraph, sig, nullptr,
+ WasmWrapperGraphBuilder builder(zone.get(), &mcgraph, sig, nullptr,
StubCallMode::kCallCodeObject,
- wasm::WasmFeaturesFromIsolate(isolate));
+ enabled_features);
builder.set_control_ptr(&control);
builder.set_effect_ptr(&effect);
builder.BuildJSToWasmWrapper(is_import);
@@ -6095,13 +6319,13 @@ std::unique_ptr<OptimizedCompilationJob> NewJSToWasmCompilationJob(
zone.get(), false, params + 1, CallDescriptor::kNoFlags);
return Pipeline::NewWasmHeapStubCompilationJob(
- isolate, incoming, std::move(zone), graph, Code::JS_TO_WASM_FUNCTION,
- std::move(debug_name), WasmAssemblerOptions());
+ isolate, wasm_engine, incoming, std::move(zone), graph,
+ Code::JS_TO_WASM_FUNCTION, std::move(debug_name), WasmAssemblerOptions());
}
std::pair<WasmImportCallKind, Handle<JSReceiver>> ResolveWasmImportCall(
Handle<JSReceiver> callable, wasm::FunctionSig* expected_sig,
- bool has_bigint_feature) {
+ const wasm::WasmFeatures& enabled_features) {
if (WasmExportedFunction::IsWasmExportedFunction(*callable)) {
auto imported_function = Handle<WasmExportedFunction>::cast(callable);
auto func_index = imported_function->function_index();
@@ -6136,7 +6360,7 @@ std::pair<WasmImportCallKind, Handle<JSReceiver>> ResolveWasmImportCall(
return std::make_pair(WasmImportCallKind::kWasmToCapi, callable);
}
// Assuming we are calling to JS, check whether this would be a runtime error.
- if (!wasm::IsJSCompatibleSignature(expected_sig, has_bigint_feature)) {
+ if (!wasm::IsJSCompatibleSignature(expected_sig, enabled_features)) {
return std::make_pair(WasmImportCallKind::kRuntimeTypeError, callable);
}
// For JavaScript calls, determine whether the target has an arity match
@@ -6176,10 +6400,7 @@ std::pair<WasmImportCallKind, Handle<JSReceiver>> ResolveWasmImportCall(
COMPARE_SIG_FOR_BUILTIN_F64(Exp);
COMPARE_SIG_FOR_BUILTIN_F64(Log);
COMPARE_SIG_FOR_BUILTIN_F64(Atan2);
- //===========================================================
- // TODO(8505): Math.pow for wasm does not match JS.
- // COMPARE_SIG_FOR_BUILTIN_F64(Pow);
- //===========================================================
+ COMPARE_SIG_FOR_BUILTIN_F64(Pow);
COMPARE_SIG_FOR_BUILTIN_F32_F64(Min);
COMPARE_SIG_FOR_BUILTIN_F32_F64(Max);
COMPARE_SIG_FOR_BUILTIN_F32_F64(Abs);
@@ -6347,7 +6568,7 @@ wasm::WasmCompilationResult CompileWasmImportCallWrapper(
&zone, MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags(),
InstructionSelector::AlignmentRequirements());
- JSGraph jsgraph(nullptr, &graph, &common, nullptr, nullptr, &machine);
+ MachineGraph mcgraph(&graph, &common, &machine);
Node* control = nullptr;
Node* effect = nullptr;
@@ -6355,7 +6576,7 @@ wasm::WasmCompilationResult CompileWasmImportCallWrapper(
SourcePositionTable* source_position_table =
source_positions ? new (&zone) SourcePositionTable(&graph) : nullptr;
- WasmWrapperGraphBuilder builder(&zone, &jsgraph, sig, source_position_table,
+ WasmWrapperGraphBuilder builder(&zone, &mcgraph, sig, source_position_table,
StubCallMode::kCallWasmRuntimeStub,
env->enabled_features);
builder.set_control_ptr(&control);
@@ -6372,7 +6593,7 @@ wasm::WasmCompilationResult CompileWasmImportCallWrapper(
incoming = GetI32WasmCallDescriptor(&zone, incoming);
}
wasm::WasmCompilationResult result = Pipeline::GenerateCodeForWasmNativeStub(
- wasm_engine, incoming, &jsgraph, Code::WASM_TO_JS_FUNCTION,
+ wasm_engine, incoming, &mcgraph, Code::WASM_TO_JS_FUNCTION,
wasm::WasmCode::kWasmToJsWrapper, func_name, WasmStubAssemblerOptions(),
source_position_table);
result.kind = wasm::WasmCompilationResult::kWasmToJsWrapper;
@@ -6395,10 +6616,8 @@ wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine* wasm_engine,
&zone, MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags(),
InstructionSelector::AlignmentRequirements()));
- JSGraph jsgraph(nullptr, mcgraph->graph(), mcgraph->common(), nullptr,
- nullptr, mcgraph->machine());
- WasmWrapperGraphBuilder builder(&zone, &jsgraph, sig, source_positions,
+ WasmWrapperGraphBuilder builder(&zone, mcgraph, sig, source_positions,
StubCallMode::kCallWasmRuntimeStub,
native_module->enabled_features());
@@ -6448,12 +6667,12 @@ wasm::WasmCompilationResult CompileWasmInterpreterEntry(
&zone, MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags(),
InstructionSelector::AlignmentRequirements());
- JSGraph jsgraph(nullptr, &graph, &common, nullptr, nullptr, &machine);
+ MachineGraph mcgraph(&graph, &common, &machine);
Node* control = nullptr;
Node* effect = nullptr;
- WasmWrapperGraphBuilder builder(&zone, &jsgraph, sig, nullptr,
+ WasmWrapperGraphBuilder builder(&zone, &mcgraph, sig, nullptr,
StubCallMode::kCallWasmRuntimeStub,
enabled_features);
builder.set_control_ptr(&control);
@@ -6471,7 +6690,7 @@ wasm::WasmCompilationResult CompileWasmInterpreterEntry(
SNPrintF(func_name, "wasm-interpreter-entry#%d", func_index));
wasm::WasmCompilationResult result = Pipeline::GenerateCodeForWasmNativeStub(
- wasm_engine, incoming, &jsgraph, Code::WASM_INTERPRETER_ENTRY,
+ wasm_engine, incoming, &mcgraph, Code::WASM_INTERPRETER_ENTRY,
wasm::WasmCode::kInterpreterEntry, func_name.begin(),
WasmStubAssemblerOptions());
result.result_tier = wasm::ExecutionTier::kInterpreter;
@@ -6480,6 +6699,54 @@ wasm::WasmCompilationResult CompileWasmInterpreterEntry(
return result;
}
+MaybeHandle<Code> CompileJSToJSWrapper(Isolate* isolate,
+ wasm::FunctionSig* sig) {
+ std::unique_ptr<Zone> zone =
+ base::make_unique<Zone>(isolate->allocator(), ZONE_NAME);
+ Graph* graph = new (zone.get()) Graph(zone.get());
+ CommonOperatorBuilder common(zone.get());
+ MachineOperatorBuilder machine(
+ zone.get(), MachineType::PointerRepresentation(),
+ InstructionSelector::SupportedMachineOperatorFlags(),
+ InstructionSelector::AlignmentRequirements());
+ MachineGraph mcgraph(graph, &common, &machine);
+
+ Node* control = nullptr;
+ Node* effect = nullptr;
+
+ WasmWrapperGraphBuilder builder(zone.get(), &mcgraph, sig, nullptr,
+ StubCallMode::kCallCodeObject,
+ wasm::WasmFeaturesFromIsolate(isolate));
+ builder.set_control_ptr(&control);
+ builder.set_effect_ptr(&effect);
+ builder.BuildJSToJSWrapper(isolate);
+
+ int wasm_count = static_cast<int>(sig->parameter_count());
+ CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
+ zone.get(), false, wasm_count + 1, CallDescriptor::kNoFlags);
+
+ // Build a name in the form "js-to-js-wrapper:<params>:<returns>".
+ static constexpr size_t kMaxNameLen = 128;
+ auto debug_name = std::unique_ptr<char[]>(new char[kMaxNameLen]);
+ memcpy(debug_name.get(), "js-to-js-wrapper:", 18);
+ AppendSignature(debug_name.get(), kMaxNameLen, sig);
+
+ // Run the compilation job synchronously.
+ std::unique_ptr<OptimizedCompilationJob> job(
+ Pipeline::NewWasmHeapStubCompilationJob(
+ isolate, isolate->wasm_engine(), incoming, std::move(zone), graph,
+ Code::JS_TO_JS_FUNCTION, std::move(debug_name),
+ AssemblerOptions::Default(isolate)));
+
+ if (job->ExecuteJob() == CompilationJob::FAILED ||
+ job->FinalizeJob(isolate) == CompilationJob::FAILED) {
+ return {};
+ }
+ Handle<Code> code = job->compilation_info()->code();
+
+ return code;
+}
+
MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
std::unique_ptr<Zone> zone =
base::make_unique<Zone>(isolate->allocator(), ZONE_NAME);
@@ -6489,12 +6756,12 @@ MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
zone.get(), MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags(),
InstructionSelector::AlignmentRequirements());
- JSGraph jsgraph(isolate, graph, &common, nullptr, nullptr, &machine);
+ MachineGraph mcgraph(graph, &common, &machine);
Node* control = nullptr;
Node* effect = nullptr;
- WasmWrapperGraphBuilder builder(zone.get(), &jsgraph, sig, nullptr,
+ WasmWrapperGraphBuilder builder(zone.get(), &mcgraph, sig, nullptr,
StubCallMode::kCallCodeObject,
wasm::WasmFeaturesFromIsolate(isolate));
builder.set_control_ptr(&control);
@@ -6510,9 +6777,9 @@ MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
MachineSignature incoming_sig(1, 4, sig_types);
// Traps need the root register, for TailCallRuntimeWithCEntry to call
// Runtime::kThrowWasmError.
- bool initialize_root_flag = true;
- CallDescriptor* incoming = Linkage::GetSimplifiedCDescriptor(
- zone.get(), &incoming_sig, initialize_root_flag);
+ CallDescriptor::Flags flags = CallDescriptor::kInitializeRootRegister;
+ CallDescriptor* incoming =
+ Linkage::GetSimplifiedCDescriptor(zone.get(), &incoming_sig, flags);
// Build a name in the form "c-wasm-entry:<params>:<returns>".
static constexpr size_t kMaxNameLen = 128;
@@ -6523,11 +6790,11 @@ MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
// Run the compilation job synchronously.
std::unique_ptr<OptimizedCompilationJob> job(
Pipeline::NewWasmHeapStubCompilationJob(
- isolate, incoming, std::move(zone), graph, Code::C_WASM_ENTRY,
- std::move(debug_name), AssemblerOptions::Default(isolate)));
+ isolate, isolate->wasm_engine(), incoming, std::move(zone), graph,
+ Code::C_WASM_ENTRY, std::move(debug_name),
+ AssemblerOptions::Default(isolate)));
- if (job->PrepareJob(isolate) == CompilationJob::FAILED ||
- job->ExecuteJob() == CompilationJob::FAILED ||
+ if (job->ExecuteJob() == CompilationJob::FAILED ||
job->FinalizeJob(isolate) == CompilationJob::FAILED) {
return {};
}
@@ -6536,6 +6803,8 @@ MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
return code;
}
+namespace {
+
bool BuildGraphForWasmFunction(AccountingAllocator* allocator,
wasm::CompilationEnv* env,
const wasm::FunctionBody& func_body,
@@ -6558,12 +6827,13 @@ bool BuildGraphForWasmFunction(AccountingAllocator* allocator,
return false;
}
- builder.LowerInt64();
+ builder.LowerInt64(WasmWrapperGraphBuilder::kCalledFromWasm);
if (builder.has_simd() &&
(!CpuFeatures::SupportsWasmSimd128() || env->lower_simd)) {
- SimdScalarLowering(mcgraph,
- CreateMachineSignature(mcgraph->zone(), func_body.sig))
+ SimdScalarLowering(
+ mcgraph, CreateMachineSignature(mcgraph->zone(), func_body.sig,
+ WasmGraphBuilder::kCalledFromWasm))
.LowerGraph();
}
@@ -6574,7 +6844,6 @@ bool BuildGraphForWasmFunction(AccountingAllocator* allocator,
return true;
}
-namespace {
Vector<const char> GetDebugName(Zone* zone, int index) {
// TODO(herhut): Use name from module if available.
constexpr int kBufferLength = 24;
@@ -6587,6 +6856,7 @@ Vector<const char> GetDebugName(Zone* zone, int index) {
memcpy(index_name, name_vector.begin(), name_len);
return Vector<const char>(index_name, name_len);
}
+
} // namespace
wasm::WasmCompilationResult ExecuteTurbofanWasmCompilation(
@@ -6755,7 +7025,7 @@ CallDescriptor* GetWasmCallDescriptor(
wasm::kFpReturnRegisters);
int parameter_slots = params.NumStackSlots();
- if (kPadArguments) parameter_slots = RoundUp(parameter_slots, 2);
+ if (ShouldPadArguments(parameter_slots)) parameter_slots++;
rets.SetStackOffset(parameter_slots);
@@ -6803,7 +7073,7 @@ CallDescriptor* GetWasmCallDescriptor(
namespace {
CallDescriptor* ReplaceTypeInCallDescriptorWith(
- Zone* zone, CallDescriptor* call_descriptor, size_t num_replacements,
+ Zone* zone, const CallDescriptor* call_descriptor, size_t num_replacements,
MachineType input_type, MachineRepresentation output_type) {
size_t parameter_count = call_descriptor->ParameterCount();
size_t return_count = call_descriptor->ReturnCount();
@@ -6819,14 +7089,23 @@ CallDescriptor* ReplaceTypeInCallDescriptorWith(
}
if (parameter_count == call_descriptor->ParameterCount() &&
return_count == call_descriptor->ReturnCount()) {
- return call_descriptor;
+ return const_cast<CallDescriptor*>(call_descriptor);
}
LocationSignature::Builder locations(zone, return_count, parameter_count);
+ // The last parameter may be the special callable parameter. In that case we
+ // have to preserve it as the last parameter, i.e. we allocate it in the new
+ // location signature again in the same register.
+ bool has_callable_param =
+ (call_descriptor->GetInputLocation(call_descriptor->InputCount() - 1) ==
+ LinkageLocation::ForRegister(kJSFunctionRegister.code(),
+ MachineType::TaggedPointer()));
LinkageLocationAllocator params(wasm::kGpParamRegisters,
wasm::kFpParamRegisters);
- for (size_t i = 0; i < call_descriptor->ParameterCount(); i++) {
+ for (size_t i = 0, e = call_descriptor->ParameterCount() -
+ (has_callable_param ? 1 : 0);
+ i < e; i++) {
if (call_descriptor->GetParameterType(i) == input_type) {
for (size_t j = 0; j < num_replacements; j++) {
locations.AddParam(params.Next(output_type));
@@ -6836,6 +7115,10 @@ CallDescriptor* ReplaceTypeInCallDescriptorWith(
params.Next(call_descriptor->GetParameterType(i).representation()));
}
}
+ if (has_callable_param) {
+ locations.AddParam(LinkageLocation::ForRegister(
+ kJSFunctionRegister.code(), MachineType::TaggedPointer()));
+ }
LinkageLocationAllocator rets(wasm::kGpReturnRegisters,
wasm::kFpReturnRegisters);
@@ -6867,8 +7150,8 @@ CallDescriptor* ReplaceTypeInCallDescriptorWith(
}
} // namespace
-CallDescriptor* GetI32WasmCallDescriptor(Zone* zone,
- CallDescriptor* call_descriptor) {
+CallDescriptor* GetI32WasmCallDescriptor(
+ Zone* zone, const CallDescriptor* call_descriptor) {
return ReplaceTypeInCallDescriptorWith(zone, call_descriptor, 2,
MachineType::Int64(),
MachineRepresentation::kWord32);
diff --git a/deps/v8/src/compiler/wasm-compiler.h b/deps/v8/src/compiler/wasm-compiler.h
index 315733c396..dd86ea1499 100644
--- a/deps/v8/src/compiler/wasm-compiler.h
+++ b/deps/v8/src/compiler/wasm-compiler.h
@@ -34,6 +34,7 @@ class Operator;
class SourcePositionTable;
class WasmDecorator;
enum class TrapId : uint32_t;
+struct Int64LoweringSpecialCase;
} // namespace compiler
namespace wasm {
@@ -47,14 +48,6 @@ struct WasmFeatures;
namespace compiler {
-bool BuildGraphForWasmFunction(AccountingAllocator* allocator,
- wasm::CompilationEnv* env,
- const wasm::FunctionBody& func_body,
- int func_index, wasm::WasmFeatures* detected,
- MachineGraph* mcgraph,
- NodeOriginTable* node_origins,
- SourcePositionTable* source_positions);
-
wasm::WasmCompilationResult ExecuteTurbofanWasmCompilation(
wasm::WasmEngine*, wasm::CompilationEnv*, const wasm::FunctionBody&,
int func_index, Counters*, wasm::WasmFeatures* detected);
@@ -117,7 +110,7 @@ constexpr WasmImportCallKind kDefaultImportCallKind =
// another target, which is why the ultimate target is returned as well.
V8_EXPORT_PRIVATE std::pair<WasmImportCallKind, Handle<JSReceiver>>
ResolveWasmImportCall(Handle<JSReceiver> callable, wasm::FunctionSig* sig,
- bool has_bigint_feature);
+ const wasm::WasmFeatures& enabled_features);
// Compiles an import call wrapper, which allows WASM to call imports.
V8_EXPORT_PRIVATE wasm::WasmCompilationResult CompileWasmImportCallWrapper(
@@ -131,7 +124,8 @@ wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine*,
// Returns an OptimizedCompilationJob object for a JS to Wasm wrapper.
std::unique_ptr<OptimizedCompilationJob> NewJSToWasmCompilationJob(
- Isolate* isolate, wasm::FunctionSig* sig, bool is_import);
+ Isolate* isolate, wasm::WasmEngine* wasm_engine, wasm::FunctionSig* sig,
+ bool is_import, const wasm::WasmFeatures& enabled_features);
// Compiles a stub that redirects a call to a wasm function to the wasm
// interpreter. It's ABI compatible with the compiled wasm function.
@@ -139,6 +133,12 @@ V8_EXPORT_PRIVATE wasm::WasmCompilationResult CompileWasmInterpreterEntry(
wasm::WasmEngine*, const wasm::WasmFeatures& enabled_features,
uint32_t func_index, wasm::FunctionSig*);
+// Compiles a stub with JS linkage that serves as an adapter for function
+// objects constructed via {WebAssembly.Function}. It performs a round-trip
+// simulating a JS-to-Wasm-to-JS coercion of parameter and return values.
+MaybeHandle<Code> CompileJSToJSWrapper(Isolate* isolate,
+ wasm::FunctionSig* sig);
+
enum CWasmEntryParameters {
kCodeEntry,
kObjectRef,
@@ -179,14 +179,14 @@ class WasmGraphBuilder {
wasm::CompilationEnv* env, Zone* zone, MachineGraph* mcgraph,
wasm::FunctionSig* sig, compiler::SourcePositionTable* spt = nullptr);
- Node** Buffer(size_t count) {
+ Vector<Node*> Buffer(size_t count) {
if (count > cur_bufsize_) {
size_t new_size = count + cur_bufsize_ + 5;
cur_buffer_ =
reinterpret_cast<Node**>(zone_->New(new_size * sizeof(Node*)));
cur_bufsize_ = new_size;
}
- return cur_buffer_;
+ return {cur_buffer_, count};
}
//-----------------------------------------------------------------------
@@ -223,8 +223,8 @@ class WasmGraphBuilder {
Node* ExceptionTagEqual(Node* caught_tag, Node* expected_tag);
Node* LoadExceptionTagFromTable(uint32_t exception_index);
Node* GetExceptionTag(Node* except_obj);
- Node** GetExceptionValues(Node* except_obj,
- const wasm::WasmException* exception);
+ Vector<Node*> GetExceptionValues(Node* except_obj,
+ const wasm::WasmException* exception);
bool IsPhiWithMerge(Node* phi, Node* merge);
bool ThrowsException(Node* node, Node** if_success, Node** if_exception);
void AppendToMerge(Node* merge, Node* from);
@@ -267,13 +267,12 @@ class WasmGraphBuilder {
Node* Switch(unsigned count, Node* key);
Node* IfValue(int32_t value, Node* sw);
Node* IfDefault(Node* sw);
- Node* Return(unsigned count, Node** nodes);
+ Node* Return(Vector<Node*> nodes);
template <typename... Nodes>
Node* Return(Node* fst, Nodes*... more) {
Node* arr[] = {fst, more...};
- return Return(arraysize(arr), arr);
+ return Return(ArrayVector(arr));
}
- Node* ReturnVoid();
Node* Unreachable(wasm::WasmCodePosition position);
Node* CallDirect(uint32_t index, Node** args, Node*** rets,
@@ -364,7 +363,9 @@ class WasmGraphBuilder {
wasm::FunctionSig* GetFunctionSignature() { return sig_; }
- V8_EXPORT_PRIVATE void LowerInt64();
+ enum CallOrigin { kCalledFromWasm, kCalledFromJS };
+
+ V8_EXPORT_PRIVATE void LowerInt64(CallOrigin origin);
V8_EXPORT_PRIVATE void SimdScalarLoweringForTesting();
@@ -379,9 +380,6 @@ class WasmGraphBuilder {
Node* SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane, Node* const* inputs);
- Node* SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift,
- Node* const* inputs);
-
Node* Simd8x16ShuffleOp(const uint8_t shuffle[16], Node* const* inputs);
Node* AtomicOp(wasm::WasmOpcode opcode, Node* const* inputs,
@@ -443,6 +441,7 @@ class WasmGraphBuilder {
SetOncePointer<Node> globals_start_;
SetOncePointer<Node> imported_mutable_globals_;
SetOncePointer<Node> stack_check_code_node_;
+ SetOncePointer<Node> isolate_root_node_;
SetOncePointer<const Operator> stack_check_call_operator_;
Node** cur_buffer_;
@@ -458,8 +457,12 @@ class WasmGraphBuilder {
compiler::SourcePositionTable* const source_position_table_ = nullptr;
+ std::unique_ptr<Int64LoweringSpecialCase> lowering_special_case_;
+
Node* NoContextConstant();
+ Node* BuildLoadIsolateRoot();
+
Node* MemBuffer(uint32_t offset);
// BoundsCheckMem receives a uint32 {index} node and returns a ptrsize index.
Node* BoundsCheckMem(uint8_t access_size, Node* index, uint32_t offset,
@@ -596,9 +599,13 @@ class WasmGraphBuilder {
Node* BuildDecodeException32BitValue(Node* values_array, uint32_t* index);
Node* BuildDecodeException64BitValue(Node* values_array, uint32_t* index);
- Node** Realloc(Node* const* buffer, size_t old_count, size_t new_count) {
- Node** buf = Buffer(new_count);
- if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*));
+ Vector<Node*> Realloc(Node* const* buffer, size_t old_count,
+ size_t new_count) {
+ DCHECK_GE(new_count, old_count); // Only support growing.
+ Vector<Node*> buf = Buffer(new_count);
+ if (buf.begin() != buffer) {
+ memcpy(buf.begin(), buffer, old_count * sizeof(Node*));
+ }
return buf;
}
@@ -624,7 +631,7 @@ V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor(
WasmCallKind kind = kWasmFunction);
V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptor(
- Zone* zone, CallDescriptor* call_descriptor);
+ Zone* zone, const CallDescriptor* call_descriptor);
V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptorForSimd(
Zone* zone, CallDescriptor* call_descriptor);
diff --git a/deps/v8/src/d8/d8.cc b/deps/v8/src/d8/d8.cc
index 6656ab608d..13a35b0cd3 100644
--- a/deps/v8/src/d8/d8.cc
+++ b/deps/v8/src/d8/d8.cc
@@ -36,6 +36,7 @@
#include "src/init/v8.h"
#include "src/interpreter/interpreter.h"
#include "src/logging/counters.h"
+#include "src/objects/managed.h"
#include "src/objects/objects-inl.h"
#include "src/objects/objects.h"
#include "src/parsing/parse-info.h"
@@ -76,7 +77,6 @@ namespace {
const int kMB = 1024 * 1024;
-const int kMaxWorkers = 100;
const int kMaxSerializerMemoryUsage =
1 * kMB; // Arbitrary maximum for testing.
@@ -227,14 +227,13 @@ Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
return nullptr;
}
- Worker* worker =
- static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
- if (worker == nullptr) {
+ i::Handle<i::Object> handle = Utils::OpenHandle(*object->GetInternalField(0));
+ if (handle->IsSmi()) {
Throw(isolate, "Worker is defunct because main thread is terminating");
return nullptr;
}
-
- return worker;
+ auto managed = i::Handle<i::Managed<Worker>>::cast(handle);
+ return managed->raw();
}
base::Thread::Options GetThreadOptions(const char* name) {
@@ -333,7 +332,7 @@ const base::TimeTicks Shell::kInitialTicks =
Global<Function> Shell::stringify_function_;
base::LazyMutex Shell::workers_mutex_;
bool Shell::allow_new_workers_ = true;
-std::vector<Worker*> Shell::workers_;
+std::unordered_set<std::shared_ptr<Worker>> Shell::running_workers_;
std::vector<ExternalizedContents> Shell::externalized_contents_;
std::atomic<bool> Shell::script_executed_{false};
base::LazyMutex Shell::isolate_status_lock_;
@@ -485,7 +484,7 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
} else if (options.stress_background_compile) {
// Start a background thread compiling the script.
BackgroundCompileThread background_compile_thread(isolate, source);
- background_compile_thread.Start();
+ CHECK(background_compile_thread.Start());
// In parallel, compile on the main thread to flush out any data races.
{
@@ -762,6 +761,16 @@ MaybeLocal<Promise> Shell::HostImportModuleDynamically(
return MaybeLocal<Promise>();
}
+void Shell::HostCleanupFinalizationGroup(Local<Context> context,
+ Local<FinalizationGroup> fg) {
+ Isolate* isolate = context->GetIsolate();
+ PerIsolateData::Get(isolate)->HostCleanupFinalizationGroup(fg);
+}
+
+void PerIsolateData::HostCleanupFinalizationGroup(Local<FinalizationGroup> fg) {
+ cleanup_finalization_groups_.emplace(isolate_, fg);
+}
+
void Shell::HostInitializeImportMetaObject(Local<Context> context,
Local<Module> module,
Local<Object> meta) {
@@ -908,6 +917,15 @@ MaybeLocal<Context> PerIsolateData::GetTimeoutContext() {
return result;
}
+MaybeLocal<FinalizationGroup> PerIsolateData::GetCleanupFinalizationGroup() {
+ if (cleanup_finalization_groups_.empty())
+ return MaybeLocal<FinalizationGroup>();
+ Local<FinalizationGroup> result =
+ cleanup_finalization_groups_.front().Get(isolate_);
+ cleanup_finalization_groups_.pop();
+ return result;
+}
+
PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
data_->realm_count_ = 1;
data_->realm_current_ = 0;
@@ -1392,30 +1410,36 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
+ // Initialize the embedder field to 0; if we return early without
+ // creating a new Worker (because the main thread is terminating) we can
+ // early-out from the instance calls.
+ args.Holder()->SetInternalField(0, v8::Integer::New(isolate, 0));
+
{
+ // Don't allow workers to create more workers if the main thread
+ // is waiting for existing running workers to terminate.
base::MutexGuard lock_guard(workers_mutex_.Pointer());
- if (workers_.size() >= kMaxWorkers) {
- Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
- return;
- }
-
- // Initialize the embedder field to nullptr; if we return early without
- // creating a new Worker (because the main thread is terminating) we can
- // early-out from the instance calls.
- args.Holder()->SetAlignedPointerInInternalField(0, nullptr);
-
if (!allow_new_workers_) return;
- Worker* worker = new Worker;
- args.Holder()->SetAlignedPointerInInternalField(0, worker);
- workers_.push_back(worker);
-
String::Utf8Value script(args.GetIsolate(), source);
if (!*script) {
Throw(args.GetIsolate(), "Can't get worker script");
return;
}
- worker->StartExecuteInThread(*script);
+
+ // The C++ worker object's lifetime is shared between the Managed<Worker>
+ // object on the heap, which the JavaScript object points to, and an
+ // internal std::shared_ptr in the worker thread itself.
+ auto worker = std::make_shared<Worker>(*script);
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ const size_t kWorkerSizeEstimate = 4 * 1024 * 1024; // stack + heap.
+ i::Handle<i::Object> managed = i::Managed<Worker>::FromSharedPtr(
+ i_isolate, kWorkerSizeEstimate, worker);
+ args.Holder()->SetInternalField(0, Utils::ToLocal(managed));
+ if (!Worker::StartWorkerThread(std::move(worker))) {
+ Throw(args.GetIsolate(), "Can't start thread");
+ return;
+ }
}
}
@@ -1475,7 +1499,7 @@ void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
int exit_code = (*args)[0]
->Int32Value(args->GetIsolate()->GetCurrentContext())
.FromMaybe(0);
- CleanupWorkers();
+ WaitForRunningWorkers();
args->GetIsolate()->Exit();
OnExit(args->GetIsolate());
base::OS::ExitProcess(exit_code);
@@ -1920,6 +1944,9 @@ Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
EscapableHandleScope handle_scope(isolate);
Local<Context> context = Context::New(isolate, nullptr, global_template);
DCHECK(!context.IsEmpty());
+ if (i::FLAG_perf_prof_annotate_wasm) {
+ isolate->SetWasmLoadSourceMapCallback(ReadFile);
+ }
InitializeModuleEmbedderData(context);
if (options.include_arguments) {
Context::Scope scope(context);
@@ -2468,6 +2495,8 @@ void SourceGroup::ExecuteInThread() {
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = Shell::array_buffer_allocator;
Isolate* isolate = Isolate::New(create_params);
+ isolate->SetHostCleanupFinalizationGroupCallback(
+ Shell::HostCleanupFinalizationGroup);
isolate->SetHostImportModuleDynamicallyCallback(
Shell::HostImportModuleDynamically);
isolate->SetHostInitializeImportMetaObjectCallback(
@@ -2504,7 +2533,7 @@ void SourceGroup::ExecuteInThread() {
void SourceGroup::StartExecuteInThread() {
if (thread_ == nullptr) {
thread_ = new IsolateThread(this);
- thread_->Start();
+ CHECK(thread_->Start());
}
next_semaphore_.Signal();
}
@@ -2550,11 +2579,11 @@ void SerializationDataQueue::Clear() {
data_.clear();
}
-Worker::Worker()
+Worker::Worker(const char* script)
: in_semaphore_(0),
out_semaphore_(0),
thread_(nullptr),
- script_(nullptr),
+ script_(i::StrDup(script)),
running_(false) {}
Worker::~Worker() {
@@ -2562,15 +2591,29 @@ Worker::~Worker() {
thread_ = nullptr;
delete[] script_;
script_ = nullptr;
- in_queue_.Clear();
- out_queue_.Clear();
}
-void Worker::StartExecuteInThread(const char* script) {
- running_ = true;
- script_ = i::StrDup(script);
- thread_ = new WorkerThread(this);
- thread_->Start();
+bool Worker::StartWorkerThread(std::shared_ptr<Worker> worker) {
+ worker->running_ = true;
+ auto thread = new WorkerThread(worker);
+ worker->thread_ = thread;
+ if (thread->Start()) {
+ Shell::AddRunningWorker(std::move(worker));
+ return true;
+ }
+ return false;
+}
+
+void Worker::WorkerThread::Run() {
+ // Prevent a lifetime cycle from Worker -> WorkerThread -> Worker.
+ // We must clear the worker_ field of the thread, but we keep the
+ // worker alive via a stack root until the thread finishes execution
+ // and removes itself from the running set. Thereafter the only
+ // remaining reference can be from a JavaScript object via a Managed.
+ auto worker = std::move(worker_);
+ worker_ = nullptr;
+ worker->ExecuteInThread();
+ Shell::RemoveRunningWorker(worker);
}
void Worker::PostMessage(std::unique_ptr<SerializationData> data) {
@@ -2605,6 +2648,8 @@ void Worker::ExecuteInThread() {
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = Shell::array_buffer_allocator;
Isolate* isolate = Isolate::New(create_params);
+ isolate->SetHostCleanupFinalizationGroupCallback(
+ Shell::HostCleanupFinalizationGroup);
isolate->SetHostImportModuleDynamicallyCallback(
Shell::HostImportModuleDynamically);
isolate->SetHostInitializeImportMetaObjectCallback(
@@ -2657,6 +2702,7 @@ void Worker::ExecuteInThread() {
.ToLocalChecked();
if (onmessage->IsFunction()) {
Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
+ SealHandleScope shs(isolate);
// Now wait for messages
while (true) {
in_semaphore_.Wait();
@@ -2666,6 +2712,7 @@ void Worker::ExecuteInThread() {
break;
}
v8::TryCatch try_catch(isolate);
+ HandleScope scope(isolate);
Local<Value> value;
if (Shell::DeserializeValue(isolate, std::move(data))
.ToLocal(&value)) {
@@ -2936,7 +2983,7 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
options.isolate_sources[i].WaitForThread();
}
}
- CleanupWorkers();
+ WaitForRunningWorkers();
// In order to finish successfully, success must be != expected_to_throw.
return success == Shell::options.expected_to_throw ? 1 : 0;
}
@@ -2966,6 +3013,40 @@ void Shell::SetWaitUntilDone(Isolate* isolate, bool value) {
}
namespace {
+bool RunSetTimeoutCallback(Isolate* isolate, bool* did_run) {
+ PerIsolateData* data = PerIsolateData::Get(isolate);
+ HandleScope handle_scope(isolate);
+ Local<Function> callback;
+ if (!data->GetTimeoutCallback().ToLocal(&callback)) return true;
+ Local<Context> context;
+ if (!data->GetTimeoutContext().ToLocal(&context)) return true;
+ TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+ Context::Scope context_scope(context);
+ if (callback->Call(context, Undefined(isolate), 0, nullptr).IsEmpty()) {
+ Shell::ReportException(isolate, &try_catch);
+ return false;
+ }
+ *did_run = true;
+ return true;
+}
+
+bool RunCleanupFinalizationGroupCallback(Isolate* isolate, bool* did_run) {
+ PerIsolateData* data = PerIsolateData::Get(isolate);
+ HandleScope handle_scope(isolate);
+ while (true) {
+ Local<FinalizationGroup> fg;
+ if (!data->GetCleanupFinalizationGroup().ToLocal(&fg)) return true;
+ *did_run = true;
+ TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+ if (FinalizationGroup::Cleanup(fg).IsNothing()) {
+ Shell::ReportException(isolate, &try_catch);
+ return false;
+ }
+ }
+}
+
bool ProcessMessages(
Isolate* isolate,
const std::function<platform::MessageLoopBehavior()>& behavior) {
@@ -2976,24 +3057,23 @@ bool ProcessMessages(
while (v8::platform::PumpMessageLoop(g_default_platform, isolate,
behavior())) {
MicrotasksScope::PerformCheckpoint(isolate);
+ isolate->ClearKeptObjects();
}
if (g_default_platform->IdleTasksEnabled(isolate)) {
v8::platform::RunIdleTasks(g_default_platform, isolate,
50.0 / base::Time::kMillisecondsPerSecond);
}
- HandleScope handle_scope(isolate);
- PerIsolateData* data = PerIsolateData::Get(isolate);
- Local<Function> callback;
- if (!data->GetTimeoutCallback().ToLocal(&callback)) break;
- Local<Context> context;
- if (!data->GetTimeoutContext().ToLocal(&context)) break;
- TryCatch try_catch(isolate);
- try_catch.SetVerbose(true);
- Context::Scope context_scope(context);
- if (callback->Call(context, Undefined(isolate), 0, nullptr).IsEmpty()) {
- Shell::ReportException(isolate, &try_catch);
+ bool ran_finalization_callback = false;
+ if (!RunCleanupFinalizationGroupCallback(isolate,
+ &ran_finalization_callback)) {
return false;
}
+ bool ran_set_timeout = false;
+ if (!RunSetTimeoutCallback(isolate, &ran_set_timeout)) {
+ return false;
+ }
+
+ if (!ran_set_timeout && !ran_finalization_callback) return true;
}
return true;
}
@@ -3267,24 +3347,35 @@ MaybeLocal<Value> Shell::DeserializeValue(
return deserializer.ReadValue(context);
}
-void Shell::CleanupWorkers() {
- // Make a copy of workers_, because we don't want to call Worker::Terminate
- // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
- // create a new Worker, it would deadlock.
- std::vector<Worker*> workers_copy;
+void Shell::AddRunningWorker(std::shared_ptr<Worker> worker) {
+ workers_mutex_.Pointer()->AssertHeld(); // caller should hold the mutex.
+ running_workers_.insert(worker);
+}
+
+void Shell::RemoveRunningWorker(const std::shared_ptr<Worker>& worker) {
+ base::MutexGuard lock_guard(workers_mutex_.Pointer());
+ auto it = running_workers_.find(worker);
+ if (it != running_workers_.end()) running_workers_.erase(it);
+}
+
+void Shell::WaitForRunningWorkers() {
+ // Make a copy of running_workers_, because we don't want to call
+ // Worker::Terminate while holding the workers_mutex_ lock. Otherwise, if a
+ // worker is about to create a new Worker, it would deadlock.
+ std::unordered_set<std::shared_ptr<Worker>> workers_copy;
{
base::MutexGuard lock_guard(workers_mutex_.Pointer());
allow_new_workers_ = false;
- workers_copy.swap(workers_);
+ workers_copy.swap(running_workers_);
}
- for (Worker* worker : workers_copy) {
+ for (auto& worker : workers_copy) {
worker->WaitForThread();
- delete worker;
}
// Now that all workers are terminated, we can re-enable Worker creation.
base::MutexGuard lock_guard(workers_mutex_.Pointer());
+ DCHECK(running_workers_.empty());
allow_new_workers_ = true;
externalized_contents_.clear();
}
@@ -3405,6 +3496,8 @@ int Shell::Main(int argc, char* argv[]) {
}
Isolate* isolate = Isolate::New(create_params);
+ isolate->SetHostCleanupFinalizationGroupCallback(
+ Shell::HostCleanupFinalizationGroup);
isolate->SetHostImportModuleDynamicallyCallback(
Shell::HostImportModuleDynamically);
isolate->SetHostInitializeImportMetaObjectCallback(
@@ -3462,6 +3555,8 @@ int Shell::Main(int argc, char* argv[]) {
i::FLAG_hash_seed ^= 1337; // Use a different hash seed.
Isolate* isolate2 = Isolate::New(create_params);
i::FLAG_hash_seed ^= 1337; // Restore old hash seed.
+ isolate2->SetHostCleanupFinalizationGroupCallback(
+ Shell::HostCleanupFinalizationGroup);
isolate2->SetHostImportModuleDynamicallyCallback(
Shell::HostImportModuleDynamically);
isolate2->SetHostInitializeImportMetaObjectCallback(
diff --git a/deps/v8/src/d8/d8.h b/deps/v8/src/d8/d8.h
index 1e0dd43c2d..04fc5f5d34 100644
--- a/deps/v8/src/d8/d8.h
+++ b/deps/v8/src/d8/d8.h
@@ -11,6 +11,7 @@
#include <queue>
#include <string>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include "src/base/once.h"
@@ -207,12 +208,9 @@ class SerializationDataQueue {
class Worker {
public:
- Worker();
+ explicit Worker(const char* script);
~Worker();
- // Run the given script on this Worker. This function should only be called
- // once, and should only be called by the thread that created the Worker.
- void StartExecuteInThread(const char* script);
// Post a message to the worker's incoming message queue. The worker will
// take ownership of the SerializationData.
// This function should only be called by the thread that created the Worker.
@@ -231,17 +229,20 @@ class Worker {
// This function can be called by any thread.
void WaitForThread();
+ // Start running the given worker in another thread.
+ static bool StartWorkerThread(std::shared_ptr<Worker> worker);
+
private:
class WorkerThread : public base::Thread {
public:
- explicit WorkerThread(Worker* worker)
+ explicit WorkerThread(std::shared_ptr<Worker> worker)
: base::Thread(base::Thread::Options("WorkerThread")),
- worker_(worker) {}
+ worker_(std::move(worker)) {}
- void Run() override { worker_->ExecuteInThread(); }
+ void Run() override;
private:
- Worker* worker_;
+ std::shared_ptr<Worker> worker_;
};
void ExecuteInThread();
@@ -275,6 +276,8 @@ class PerIsolateData {
PerIsolateData* data_;
};
+ inline void HostCleanupFinalizationGroup(Local<FinalizationGroup> fg);
+ inline MaybeLocal<FinalizationGroup> GetCleanupFinalizationGroup();
inline void SetTimeout(Local<Function> callback, Local<Context> context);
inline MaybeLocal<Function> GetTimeoutCallback();
inline MaybeLocal<Context> GetTimeoutContext();
@@ -292,6 +295,7 @@ class PerIsolateData {
Global<Value> realm_shared_;
std::queue<Global<Function>> set_timeout_callbacks_;
std::queue<Global<Context>> set_timeout_contexts_;
+ std::queue<Global<FinalizationGroup>> cleanup_finalization_groups_;
AsyncHooks* async_hooks_wrapper_;
int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
@@ -378,7 +382,6 @@ class Shell : public i::AllStatic {
Isolate* isolate, Local<Value> value, Local<Value> transfer);
static MaybeLocal<Value> DeserializeValue(
Isolate* isolate, std::unique_ptr<SerializationData> data);
- static void CleanupWorkers();
static int* LookupCounter(const char* name);
static void* CreateHistogram(const char* name, int min, int max,
size_t buckets);
@@ -465,6 +468,8 @@ class Shell : public i::AllStatic {
static void SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args);
static void MakeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
static void RemoveDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void HostCleanupFinalizationGroup(Local<Context> context,
+ Local<FinalizationGroup> fg);
static MaybeLocal<Promise> HostImportModuleDynamically(
Local<Context> context, Local<ScriptOrModule> referrer,
Local<String> specifier);
@@ -493,6 +498,10 @@ class Shell : public i::AllStatic {
!options.test_shell;
}
+ static void WaitForRunningWorkers();
+ static void AddRunningWorker(std::shared_ptr<Worker> worker);
+ static void RemoveRunningWorker(const std::shared_ptr<Worker>& worker);
+
private:
static Global<Context> evaluation_context_;
static base::OnceType quit_once_;
@@ -509,7 +518,7 @@ class Shell : public i::AllStatic {
static base::LazyMutex workers_mutex_; // Guards the following members.
static bool allow_new_workers_;
- static std::vector<Worker*> workers_;
+ static std::unordered_set<std::shared_ptr<Worker>> running_workers_;
static std::vector<ExternalizedContents> externalized_contents_;
// Multiple isolates may update this flag concurrently.
diff --git a/deps/v8/src/date/dateparser-inl.h b/deps/v8/src/date/dateparser-inl.h
index b2099ca88d..436b144478 100644
--- a/deps/v8/src/date/dateparser-inl.h
+++ b/deps/v8/src/date/dateparser-inl.h
@@ -13,8 +13,7 @@ namespace v8 {
namespace internal {
template <typename Char>
-bool DateParser::Parse(Isolate* isolate, Vector<Char> str, FixedArray out) {
- DCHECK(out.length() >= OUTPUT_SIZE);
+bool DateParser::Parse(Isolate* isolate, Vector<Char> str, double* out) {
InputReader<Char> in(str);
DateStringTokenizer<Char> scanner(&in);
TimeZoneComposer tz;
diff --git a/deps/v8/src/date/dateparser.cc b/deps/v8/src/date/dateparser.cc
index 252fe54e5b..f7ea4c726c 100644
--- a/deps/v8/src/date/dateparser.cc
+++ b/deps/v8/src/date/dateparser.cc
@@ -10,7 +10,7 @@
namespace v8 {
namespace internal {
-bool DateParser::DayComposer::Write(FixedArray output) {
+bool DateParser::DayComposer::Write(double* output) {
if (index_ < 1) return false;
// Day and month defaults to 1.
while (index_ < kSize) {
@@ -58,13 +58,13 @@ bool DateParser::DayComposer::Write(FixedArray output) {
if (!Smi::IsValid(year) || !IsMonth(month) || !IsDay(day)) return false;
- output.set(YEAR, Smi::FromInt(year));
- output.set(MONTH, Smi::FromInt(month - 1)); // 0-based
- output.set(DAY, Smi::FromInt(day));
+ output[YEAR] = year;
+ output[MONTH] = month - 1; // 0-based
+ output[DAY] = day;
return true;
}
-bool DateParser::TimeComposer::Write(FixedArray output) {
+bool DateParser::TimeComposer::Write(double* output) {
// All time slots default to 0
while (index_ < kSize) {
comp_[index_++] = 0;
@@ -89,14 +89,14 @@ bool DateParser::TimeComposer::Write(FixedArray output) {
}
}
- output.set(HOUR, Smi::FromInt(hour));
- output.set(MINUTE, Smi::FromInt(minute));
- output.set(SECOND, Smi::FromInt(second));
- output.set(MILLISECOND, Smi::FromInt(millisecond));
+ output[HOUR] = hour;
+ output[MINUTE] = minute;
+ output[SECOND] = second;
+ output[MILLISECOND] = millisecond;
return true;
}
-bool DateParser::TimeZoneComposer::Write(FixedArray output) {
+bool DateParser::TimeZoneComposer::Write(double* output) {
if (sign_ != kNone) {
if (hour_ == kNone) hour_ = 0;
if (minute_ == kNone) minute_ = 0;
@@ -109,9 +109,9 @@ bool DateParser::TimeZoneComposer::Write(FixedArray output) {
total_seconds = -total_seconds;
}
DCHECK(Smi::IsValid(total_seconds));
- output.set(UTC_OFFSET, Smi::FromInt(total_seconds));
+ output[UTC_OFFSET] = total_seconds;
} else {
- output.set_null(UTC_OFFSET);
+ output[UTC_OFFSET] = std::numeric_limits<double>::quiet_NaN();
}
return true;
}
diff --git a/deps/v8/src/date/dateparser.h b/deps/v8/src/date/dateparser.h
index ac6be47692..a32db8f9c8 100644
--- a/deps/v8/src/date/dateparser.h
+++ b/deps/v8/src/date/dateparser.h
@@ -13,6 +13,18 @@ namespace internal {
class DateParser : public AllStatic {
public:
+ enum {
+ YEAR,
+ MONTH,
+ DAY,
+ HOUR,
+ MINUTE,
+ SECOND,
+ MILLISECOND,
+ UTC_OFFSET,
+ OUTPUT_SIZE
+ };
+
// Parse the string as a date. If parsing succeeds, return true after
// filling out the output array as follows (all integers are Smis):
// [0]: year
@@ -25,19 +37,7 @@ class DateParser : public AllStatic {
// [7]: UTC offset in seconds, or null value if no timezone specified
// If parsing fails, return false (content of output array is not defined).
template <typename Char>
- static bool Parse(Isolate* isolate, Vector<Char> str, FixedArray output);
-
- enum {
- YEAR,
- MONTH,
- DAY,
- HOUR,
- MINUTE,
- SECOND,
- MILLISECOND,
- UTC_OFFSET,
- OUTPUT_SIZE
- };
+ static bool Parse(Isolate* isolate, Vector<Char> str, double* output);
private:
// Range testing
@@ -274,7 +274,7 @@ class DateParser : public AllStatic {
return hour_ != kNone && minute_ == kNone && TimeComposer::IsMinute(n);
}
bool IsUTC() const { return hour_ == 0 && minute_ == 0; }
- bool Write(FixedArray output);
+ bool Write(double* output);
bool IsEmpty() { return hour_ == kNone; }
private:
@@ -300,7 +300,7 @@ class DateParser : public AllStatic {
return true;
}
void SetHourOffset(int n) { hour_offset_ = n; }
- bool Write(FixedArray output);
+ bool Write(double* output);
static bool IsMinute(int x) { return Between(x, 0, 59); }
static bool IsHour(int x) { return Between(x, 0, 23); }
@@ -329,7 +329,7 @@ class DateParser : public AllStatic {
return false;
}
void SetNamedMonth(int n) { named_month_ = n; }
- bool Write(FixedArray output);
+ bool Write(double* output);
void set_iso_date() { is_iso_date_ = true; }
static bool IsMonth(int x) { return Between(x, 1, 12); }
static bool IsDay(int x) { return Between(x, 1, 31); }
diff --git a/deps/v8/src/debug/debug-coverage.cc b/deps/v8/src/debug/debug-coverage.cc
index 15aad1fcc2..cb466ab6ab 100644
--- a/deps/v8/src/debug/debug-coverage.cc
+++ b/deps/v8/src/debug/debug-coverage.cc
@@ -476,6 +476,25 @@ void CollectBlockCoverage(CoverageFunction* function, SharedFunctionInfo info,
ResetAllBlockCounts(info);
}
+void PrintBlockCoverage(const CoverageFunction* function,
+ SharedFunctionInfo info, bool has_nonempty_source_range,
+ bool function_is_relevant) {
+ DCHECK(FLAG_trace_block_coverage);
+ std::unique_ptr<char[]> function_name =
+ function->name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ i::PrintF(
+ "Coverage for function='%s', SFI=%p, has_nonempty_source_range=%d, "
+ "function_is_relevant=%d\n",
+ function_name.get(), reinterpret_cast<void*>(info.ptr()),
+ has_nonempty_source_range, function_is_relevant);
+ i::PrintF("{start: %d, end: %d, count: %d}\n", function->start, function->end,
+ function->count);
+ for (const auto& block : function->blocks) {
+ i::PrintF("{start: %d, end: %d, count: %d}\n", block.start, block.end,
+ block.count);
+ }
+}
+
void CollectAndMaybeResetCounts(Isolate* isolate,
SharedToCounterMap* counter_map,
v8::debug::CoverageMode coverage_mode) {
@@ -668,9 +687,7 @@ std::unique_ptr<Coverage> Coverage::Collect(
}
// Only include a function range if itself or its parent function is
- // covered, or if it contains non-trivial block coverage. It must also
- // have a non-empty source range (otherwise it is not interesting to
- // report).
+ // covered, or if it contains non-trivial block coverage.
bool is_covered = (count != 0);
bool parent_is_covered =
(!nesting.empty() && functions->at(nesting.back()).count != 0);
@@ -678,10 +695,19 @@ std::unique_ptr<Coverage> Coverage::Collect(
bool function_is_relevant =
(is_covered || parent_is_covered || has_block_coverage);
- if (function.HasNonEmptySourceRange() && function_is_relevant) {
+ // It must also have a non-empty source range (otherwise it is not
+ // interesting to report).
+ bool has_nonempty_source_range = function.HasNonEmptySourceRange();
+
+ if (has_nonempty_source_range && function_is_relevant) {
nesting.push_back(functions->size());
functions->emplace_back(function);
}
+
+ if (FLAG_trace_block_coverage) {
+ PrintBlockCoverage(&function, info, has_nonempty_source_range,
+ function_is_relevant);
+ }
}
// Remove entries for scripts that have no coverage.
@@ -691,6 +717,13 @@ std::unique_ptr<Coverage> Coverage::Collect(
}
void Coverage::SelectMode(Isolate* isolate, debug::CoverageMode mode) {
+ if (mode != isolate->code_coverage_mode()) {
+ // Changing the coverage mode can change the bytecode that would be
+ // generated for a function, which can interfere with lazy source positions,
+ // so just force source position collection whenever there's such a change.
+ isolate->CollectSourcePositionsForAllBytecodeArrays();
+ }
+
switch (mode) {
case debug::CoverageMode::kBestEffort:
// Note that DevTools switches back to best-effort coverage once the
diff --git a/deps/v8/src/debug/debug-evaluate.cc b/deps/v8/src/debug/debug-evaluate.cc
index 0d8a7b2c7e..203885143f 100644
--- a/deps/v8/src/debug/debug-evaluate.cc
+++ b/deps/v8/src/debug/debug-evaluate.cc
@@ -101,11 +101,14 @@ MaybeHandle<Object> DebugEvaluate::WithTopmostArguments(Isolate* isolate,
.Check();
// Materialize receiver.
- Handle<String> this_str = factory->this_string();
- JSObject::SetOwnPropertyIgnoreAttributes(
- materialized, this_str, Handle<Object>(it.frame()->receiver(), isolate),
- NONE)
- .Check();
+ Handle<Object> this_value(it.frame()->receiver(), isolate);
+ DCHECK_EQ(it.frame()->IsConstructor(), this_value->IsTheHole(isolate));
+ if (!this_value->IsTheHole(isolate)) {
+ Handle<String> this_str = factory->this_string();
+ JSObject::SetOwnPropertyIgnoreAttributes(materialized, this_str, this_value,
+ NONE)
+ .Check();
+ }
// Use extension object in a debug-evaluate scope.
Handle<ScopeInfo> scope_info =
@@ -383,6 +386,7 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
case Bytecode::kLdaKeyedProperty:
case Bytecode::kLdaGlobalInsideTypeof:
case Bytecode::kLdaLookupSlotInsideTypeof:
+ case Bytecode::kGetIterator:
// Arithmetics.
case Bytecode::kAdd:
case Bytecode::kAddSmi:
diff --git a/deps/v8/src/debug/debug-frames.cc b/deps/v8/src/debug/debug-frames.cc
index 4fe062b277..78c4c323fc 100644
--- a/deps/v8/src/debug/debug-frames.cc
+++ b/deps/v8/src/debug/debug-frames.cc
@@ -93,10 +93,8 @@ bool FrameInspector::ParameterIsShadowedByContextLocal(
VariableMode mode;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
- RequiresBrandCheckFlag requires_brand_check;
return ScopeInfo::ContextSlotIndex(*info, *parameter_name, &mode, &init_flag,
- &maybe_assigned_flag,
- &requires_brand_check) != -1;
+ &maybe_assigned_flag) != -1;
}
RedirectActiveFunctions::RedirectActiveFunctions(SharedFunctionInfo shared,
diff --git a/deps/v8/src/debug/debug-scopes.cc b/deps/v8/src/debug/debug-scopes.cc
index 1091e3a819..4569780d00 100644
--- a/deps/v8/src/debug/debug-scopes.cc
+++ b/deps/v8/src/debug/debug-scopes.cc
@@ -774,7 +774,7 @@ void ScopeIterator::VisitLocalScope(const Visitor& visitor, Mode mode) const {
DCHECK(!context_->IsScriptContext());
DCHECK(!context_->IsNativeContext());
DCHECK(!context_->IsWithContext());
- if (!context_->scope_info().CallsSloppyEval()) return;
+ if (!context_->scope_info().SloppyEvalCanExtendVars()) return;
if (context_->extension_object().is_null()) return;
Handle<JSObject> extension(context_->extension_object(), isolate_);
Handle<FixedArray> keys =
@@ -884,10 +884,9 @@ bool ScopeIterator::SetContextVariableValue(Handle<String> variable_name,
VariableMode mode;
InitializationFlag flag;
MaybeAssignedFlag maybe_assigned_flag;
- RequiresBrandCheckFlag requires_brand_check;
- int slot_index = ScopeInfo::ContextSlotIndex(
- context_->scope_info(), *variable_name, &mode, &flag,
- &maybe_assigned_flag, &requires_brand_check);
+ int slot_index =
+ ScopeInfo::ContextSlotIndex(context_->scope_info(), *variable_name, &mode,
+ &flag, &maybe_assigned_flag);
if (slot_index < 0) return false;
context_->set(slot_index, *new_value);
diff --git a/deps/v8/src/debug/debug-stack-trace-iterator.cc b/deps/v8/src/debug/debug-stack-trace-iterator.cc
index a0c6fa967c..4f691e63a2 100644
--- a/deps/v8/src/debug/debug-stack-trace-iterator.cc
+++ b/deps/v8/src/debug/debug-stack-trace-iterator.cc
@@ -98,10 +98,9 @@ v8::MaybeLocal<v8::Value> DebugStackTraceIterator::GetReceiver() const {
VariableMode mode;
InitializationFlag flag;
MaybeAssignedFlag maybe_assigned_flag;
- RequiresBrandCheckFlag requires_brand_check;
int slot_index = ScopeInfo::ContextSlotIndex(
context->scope_info(), ReadOnlyRoots(isolate_->heap()).this_string(),
- &mode, &flag, &maybe_assigned_flag, &requires_brand_check);
+ &mode, &flag, &maybe_assigned_flag);
if (slot_index < 0) return v8::MaybeLocal<v8::Value>();
Handle<Object> value = handle(context->get(slot_index), isolate_);
if (value->IsTheHole(isolate_)) return v8::MaybeLocal<v8::Value>();
diff --git a/deps/v8/src/debug/debug-type-profile.cc b/deps/v8/src/debug/debug-type-profile.cc
index 5ed2dfb116..c0ba96c248 100644
--- a/deps/v8/src/debug/debug-type-profile.cc
+++ b/deps/v8/src/debug/debug-type-profile.cc
@@ -71,6 +71,13 @@ std::unique_ptr<TypeProfile> TypeProfile::Collect(Isolate* isolate) {
}
void TypeProfile::SelectMode(Isolate* isolate, debug::TypeProfileMode mode) {
+ if (mode != isolate->type_profile_mode()) {
+ // Changing the type profile mode can change the bytecode that would be
+ // generated for a function, which can interfere with lazy source positions,
+ // so just force source position collection whenever there's such a change.
+ isolate->CollectSourcePositionsForAllBytecodeArrays();
+ }
+
HandleScope handle_scope(isolate);
if (mode == debug::TypeProfileMode::kNone) {
diff --git a/deps/v8/src/debug/debug.cc b/deps/v8/src/debug/debug.cc
index 9b5200e343..aa308150ac 100644
--- a/deps/v8/src/debug/debug.cc
+++ b/deps/v8/src/debug/debug.cc
@@ -1224,8 +1224,12 @@ void Debug::InstallDebugBreakTrampoline() {
Handle<Code> trampoline = BUILTIN_CODE(isolate_, DebugBreakTrampoline);
std::vector<Handle<JSFunction>> needs_compile;
- std::vector<Handle<AccessorPair>> needs_instantiate;
+ using AccessorPairWithContext =
+ std::pair<Handle<AccessorPair>, Handle<NativeContext>>;
+ std::vector<AccessorPairWithContext> needs_instantiate;
{
+ // Deduplicate {needs_instantiate} by recording all collected AccessorPairs.
+ std::set<AccessorPair> recorded;
HeapObjectIterator iterator(isolate_->heap());
for (HeapObject obj = iterator.Next(); !obj.is_null();
obj = iterator.Next()) {
@@ -1242,11 +1246,26 @@ void Debug::InstallDebugBreakTrampoline() {
} else {
fun.set_code(*trampoline);
}
- } else if (obj.IsAccessorPair()) {
- AccessorPair accessor_pair = AccessorPair::cast(obj);
- if (accessor_pair.getter().IsFunctionTemplateInfo() ||
- accessor_pair.setter().IsFunctionTemplateInfo()) {
- needs_instantiate.push_back(handle(accessor_pair, isolate_));
+ } else if (obj.IsJSObject()) {
+ JSObject object = JSObject::cast(obj);
+ DescriptorArray descriptors = object.map().instance_descriptors();
+
+ for (int i = 0; i < object.map().NumberOfOwnDescriptors(); ++i) {
+ if (descriptors.GetDetails(i).kind() == PropertyKind::kAccessor) {
+ Object value = descriptors.GetStrongValue(i);
+ if (!value.IsAccessorPair()) continue;
+
+ AccessorPair accessor_pair = AccessorPair::cast(value);
+ if (!accessor_pair.getter().IsFunctionTemplateInfo() &&
+ !accessor_pair.setter().IsFunctionTemplateInfo()) {
+ continue;
+ }
+ if (recorded.find(accessor_pair) != recorded.end()) continue;
+
+ needs_instantiate.emplace_back(handle(accessor_pair, isolate_),
+ object.GetCreationContext());
+ recorded.insert(accessor_pair);
+ }
}
}
}
@@ -1254,10 +1273,13 @@ void Debug::InstallDebugBreakTrampoline() {
// Forcibly instantiate all lazy accessor pairs to make sure that they
// properly hit the debug break trampoline.
- for (Handle<AccessorPair> accessor_pair : needs_instantiate) {
+ for (AccessorPairWithContext tuple : needs_instantiate) {
+ Handle<AccessorPair> accessor_pair = tuple.first;
+ Handle<NativeContext> native_context = tuple.second;
if (accessor_pair->getter().IsFunctionTemplateInfo()) {
Handle<JSFunction> fun =
ApiNatives::InstantiateFunction(
+ isolate_, native_context,
handle(FunctionTemplateInfo::cast(accessor_pair->getter()),
isolate_))
.ToHandleChecked();
@@ -1266,6 +1288,7 @@ void Debug::InstallDebugBreakTrampoline() {
if (accessor_pair->setter().IsFunctionTemplateInfo()) {
Handle<JSFunction> fun =
ApiNatives::InstantiateFunction(
+ isolate_, native_context,
handle(FunctionTemplateInfo::cast(accessor_pair->setter()),
isolate_))
.ToHandleChecked();
@@ -1734,9 +1757,6 @@ bool Debug::IsFrameBlackboxed(JavaScriptFrame* frame) {
void Debug::OnException(Handle<Object> exception, Handle<Object> promise,
v8::debug::ExceptionType exception_type) {
- // TODO(kozyatinskiy): regress-662674.js test fails on arm without this.
- if (!AllowJavascriptExecution::IsAllowed(isolate_)) return;
-
Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher();
// Don't notify listener of exceptions that are internal to a desugaring.
@@ -1775,6 +1795,11 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise,
if (it.done()) return; // Do not trigger an event with an empty stack.
}
+ // Do not trigger exception event on stack overflow. We cannot perform
+ // anything useful for debugging in that situation.
+ StackLimitCheck stack_limit_check(isolate_);
+ if (stack_limit_check.JsHasOverflowed()) return;
+
DebugScope debug_scope(this);
HandleScope scope(isolate_);
DisableBreak no_recursive_break(this);
diff --git a/deps/v8/src/debug/debug.h b/deps/v8/src/debug/debug.h
index 684397400a..eef89f9372 100644
--- a/deps/v8/src/debug/debug.h
+++ b/deps/v8/src/debug/debug.h
@@ -375,6 +375,8 @@ class V8_EXPORT_PRIVATE Debug {
return thread_local_.break_on_next_function_call_;
}
+ inline bool break_disabled() const { return break_disabled_; }
+
DebugFeatureTracker* feature_tracker() { return &feature_tracker_; }
// For functions in which we cannot set a break point, use a canonical
@@ -399,7 +401,6 @@ class V8_EXPORT_PRIVATE Debug {
return is_suppressed_ || !is_active_ ||
isolate_->debug_execution_mode() == DebugInfo::kSideEffects;
}
- inline bool break_disabled() const { return break_disabled_; }
void clear_suspended_generator() {
thread_local_.suspended_generator_ = Smi::kZero;
diff --git a/deps/v8/src/deoptimizer/arm/deoptimizer-arm.cc b/deps/v8/src/deoptimizer/arm/deoptimizer-arm.cc
index 89e9988f9e..2befb70264 100644
--- a/deps/v8/src/deoptimizer/arm/deoptimizer-arm.cc
+++ b/deps/v8/src/deoptimizer/arm/deoptimizer-arm.cc
@@ -12,6 +12,9 @@
namespace v8 {
namespace internal {
+const bool Deoptimizer::kSupportsFixedDeoptExitSize = false;
+const int Deoptimizer::kDeoptExitSize = 0;
+
#define __ masm->
// This code tries to be close to ia32 code so that any changes can be
@@ -28,7 +31,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
RegList restored_regs = kJSCallerSaved | kCalleeSaved | ip.bit();
const int kDoubleRegsSize = kDoubleSize * DwVfpRegister::kNumRegisters;
- const int kFloatRegsSize = kFloatSize * SwVfpRegister::kNumRegisters;
// Save all allocatable VFP registers before messing with them.
{
@@ -48,9 +50,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
// small number and we need to use condition codes.
__ sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq);
__ vstm(db_w, sp, d0, d15);
-
- // Push registers s0-s31 on the stack.
- __ vstm(db_w, sp, s0, s31);
}
// Push all 16 registers (needed to populate FrameDescription::registers_).
@@ -67,7 +66,7 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
}
const int kSavedRegistersAreaSize =
- (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize + kFloatRegsSize;
+ (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
// Get the bailout id is passed as r10 by the caller.
__ mov(r2, r10);
@@ -119,23 +118,11 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
int code = config->GetAllocatableDoubleCode(i);
int dst_offset = code * kDoubleSize + double_regs_offset;
- int src_offset =
- code * kDoubleSize + kNumberOfRegisters * kPointerSize + kFloatRegsSize;
+ int src_offset = code * kDoubleSize + kNumberOfRegisters * kPointerSize;
__ vldr(d0, sp, src_offset);
__ vstr(d0, r1, dst_offset);
}
- // Copy VFP registers to
- // float_registers_[FloatRegister::kNumAllocatableRegisters]
- int float_regs_offset = FrameDescription::float_registers_offset();
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- int dst_offset = code * kFloatSize + float_regs_offset;
- int src_offset = code * kFloatSize + kNumberOfRegisters * kPointerSize;
- __ ldr(r2, MemOperand(sp, src_offset));
- __ str(r2, MemOperand(r1, dst_offset));
- }
-
// Remove the saved registers from the stack.
__ add(sp, sp, Operand(kSavedRegistersAreaSize));
@@ -234,7 +221,12 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ stop();
}
-bool Deoptimizer::PadTopOfStackRegister() { return false; }
+Float32 RegisterValues::GetFloatRegister(unsigned n) const {
+ const int kShift = n % 2 == 0 ? 0 : 32;
+
+ return Float32::FromBits(
+ static_cast<uint32_t>(double_registers_[n / 2].get_bits() >> kShift));
+}
void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
SetFrameSlot(offset, value);
diff --git a/deps/v8/src/deoptimizer/arm64/deoptimizer-arm64.cc b/deps/v8/src/deoptimizer/arm64/deoptimizer-arm64.cc
index a96b1263ab..82ae764e50 100644
--- a/deps/v8/src/deoptimizer/arm64/deoptimizer-arm64.cc
+++ b/deps/v8/src/deoptimizer/arm64/deoptimizer-arm64.cc
@@ -13,6 +13,9 @@
namespace v8 {
namespace internal {
+const bool Deoptimizer::kSupportsFixedDeoptExitSize = true;
+const int Deoptimizer::kDeoptExitSize = kInstrSize;
+
#define __ masm->
namespace {
@@ -111,12 +114,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
DCHECK_EQ(saved_double_registers.Count() % 2, 0);
__ PushCPURegList(saved_double_registers);
- CPURegList saved_float_registers(
- CPURegister::kVRegister, kSRegSizeInBits,
- RegisterConfiguration::Default()->allocatable_float_codes_mask());
- DCHECK_EQ(saved_float_registers.Count() % 4, 0);
- __ PushCPURegList(saved_float_registers);
-
// We save all the registers except sp, lr, platform register (x18) and the
// masm scratches.
CPURegList saved_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 28);
@@ -134,17 +131,15 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
const int kSavedRegistersAreaSize =
(saved_registers.Count() * kXRegSize) +
- (saved_double_registers.Count() * kDRegSize) +
- (saved_float_registers.Count() * kSRegSize);
+ (saved_double_registers.Count() * kDRegSize);
// Floating point registers are saved on the stack above core registers.
- const int kFloatRegistersOffset = saved_registers.Count() * kXRegSize;
- const int kDoubleRegistersOffset =
- kFloatRegistersOffset + saved_float_registers.Count() * kSRegSize;
+ const int kDoubleRegistersOffset = saved_registers.Count() * kXRegSize;
- // The bailout id was passed by the caller in x26.
+ // We don't use a bailout id for arm64, because we can compute the id from the
+ // address. Pass kMaxUInt32 instead to signify this.
Register bailout_id = x2;
- __ Mov(bailout_id, x26);
+ __ Mov(bailout_id, kMaxUInt32);
Register code_object = x3;
Register fp_to_sp = x4;
@@ -194,12 +189,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
CopyRegListToFrame(masm, x1, FrameDescription::double_registers_offset(),
saved_double_registers, x2, x3, kDoubleRegistersOffset);
- // Copy float registers to the input frame.
- // TODO(arm): these are the lower 32-bits of the double registers stored
- // above, so we shouldn't need to store them again.
- CopyRegListToFrame(masm, x1, FrameDescription::float_registers_offset(),
- saved_float_registers, w2, w3, kFloatRegistersOffset);
-
// Remove the saved registers from the stack.
DCHECK_EQ(kSavedRegistersAreaSize % kXRegSize, 0);
__ Drop(kSavedRegistersAreaSize / kXRegSize);
@@ -285,7 +274,10 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ Br(continuation);
}
-bool Deoptimizer::PadTopOfStackRegister() { return true; }
+Float32 RegisterValues::GetFloatRegister(unsigned n) const {
+ return Float32::FromBits(
+ static_cast<uint32_t>(double_registers_[n].get_bits()));
+}
void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
SetFrameSlot(offset, value);
diff --git a/deps/v8/src/deoptimizer/deoptimizer.cc b/deps/v8/src/deoptimizer/deoptimizer.cc
index 47c40d373e..64551c6899 100644
--- a/deps/v8/src/deoptimizer/deoptimizer.cc
+++ b/deps/v8/src/deoptimizer/deoptimizer.cc
@@ -452,6 +452,15 @@ const char* Deoptimizer::MessageFor(DeoptimizeKind kind) {
return nullptr;
}
+namespace {
+
+uint16_t InternalFormalParameterCountWithReceiver(SharedFunctionInfo sfi) {
+ static constexpr int kTheReceiver = 1;
+ return sfi.internal_formal_parameter_count() + kTheReceiver;
+}
+
+} // namespace
+
Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function,
DeoptimizeKind kind, unsigned bailout_id, Address from,
int fp_to_sp_delta)
@@ -503,8 +512,22 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function,
CodeDeoptEvent(compiled_code_, kind, from_, fp_to_sp_delta_));
}
unsigned size = ComputeInputFrameSize();
- int parameter_count = function.shared().internal_formal_parameter_count() + 1;
+ const int parameter_count =
+ InternalFormalParameterCountWithReceiver(function.shared());
input_ = new (size) FrameDescription(size, parameter_count);
+
+ if (kSupportsFixedDeoptExitSize) {
+ DCHECK_EQ(bailout_id_, kMaxUInt32);
+ // Calculate bailout id from return address.
+ DCHECK_GT(kDeoptExitSize, 0);
+ DeoptimizationData deopt_data =
+ DeoptimizationData::cast(compiled_code_.deoptimization_data());
+ Address deopt_start = compiled_code_.raw_instruction_start() +
+ deopt_data.DeoptExitStart().value();
+ int offset = static_cast<int>(from_ - kDeoptExitSize - deopt_start);
+ DCHECK_EQ(0, offset % kDeoptExitSize);
+ bailout_id_ = offset / kDeoptExitSize;
+ }
}
Code Deoptimizer::FindOptimizedCode() {
@@ -624,10 +647,6 @@ int LookupCatchHandler(TranslatedFrame* translated_frame, int* data_out) {
return -1;
}
-bool ShouldPadArguments(int arg_count) {
- return kPadArguments && (arg_count % 2 != 0);
-}
-
} // namespace
// We rely on this function not causing a GC. It is called from generated code
@@ -787,45 +806,33 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
SharedFunctionInfo shared = translated_frame->raw_shared_info();
TranslatedFrame::iterator value_iterator = translated_frame->begin();
- bool is_bottommost = (0 == frame_index);
- bool is_topmost = (output_count_ - 1 == frame_index);
+ const bool is_bottommost = (0 == frame_index);
+ const bool is_topmost = (output_count_ - 1 == frame_index);
- int bytecode_offset = translated_frame->node_id().ToInt();
- int height = translated_frame->height();
- int register_count = height - 1; // Exclude accumulator.
- int register_stack_slot_count =
- InterpreterFrameConstants::RegisterStackSlotCount(register_count);
- int height_in_bytes = register_stack_slot_count * kSystemPointerSize;
+ const int real_bytecode_offset = translated_frame->node_id().ToInt();
+ const int bytecode_offset =
+ goto_catch_handler ? catch_handler_pc_offset_ : real_bytecode_offset;
- // The topmost frame will contain the accumulator.
- if (is_topmost) {
- height_in_bytes += kSystemPointerSize;
- if (PadTopOfStackRegister()) height_in_bytes += kSystemPointerSize;
- }
+ const int parameters_count = InternalFormalParameterCountWithReceiver(shared);
+ const int locals_count = translated_frame->height();
+ InterpretedFrameInfo frame_info =
+ InterpretedFrameInfo::Precise(parameters_count, locals_count, is_topmost);
+ const uint32_t output_frame_size = frame_info.frame_size_in_bytes();
TranslatedFrame::iterator function_iterator = value_iterator++;
if (trace_scope_ != nullptr) {
PrintF(trace_scope_->file(), " translating interpreted frame ");
std::unique_ptr<char[]> name = shared.DebugName().ToCString();
PrintF(trace_scope_->file(), "%s", name.get());
- PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d%s\n",
- bytecode_offset, height_in_bytes,
- goto_catch_handler ? " (throw)" : "");
- }
- if (goto_catch_handler) {
- bytecode_offset = catch_handler_pc_offset_;
+ PrintF(trace_scope_->file(),
+ " => bytecode_offset=%d, variable_frame_size=%d, frame_size=%d%s\n",
+ real_bytecode_offset, frame_info.frame_size_in_bytes_without_fixed(),
+ output_frame_size, goto_catch_handler ? " (throw)" : "");
}
- // The 'fixed' part of the frame consists of the incoming parameters and
- // the part described by InterpreterFrameConstants. This will include
- // argument padding, when needed.
- unsigned fixed_frame_size = ComputeInterpretedFixedSize(shared);
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
// Allocate and store the output frame description.
- int parameter_count = shared.internal_formal_parameter_count() + 1;
FrameDescription* output_frame = new (output_frame_size)
- FrameDescription(output_frame_size, parameter_count);
+ FrameDescription(output_frame_size, parameters_count);
FrameWriter frame_writer(this, output_frame, trace_scope_);
CHECK(frame_index >= 0 && frame_index < output_count_);
@@ -834,22 +841,19 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
// The top address of the frame is computed from the previous frame's top and
// this frame's size.
- intptr_t top_address;
- if (is_bottommost) {
- top_address = caller_frame_top_ - output_frame_size;
- } else {
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- }
+ const intptr_t top_address =
+ is_bottommost ? caller_frame_top_ - output_frame_size
+ : output_[frame_index - 1]->GetTop() - output_frame_size;
output_frame->SetTop(top_address);
// Compute the incoming parameter translation.
ReadOnlyRoots roots(isolate());
- if (ShouldPadArguments(parameter_count)) {
+ if (ShouldPadArguments(parameters_count)) {
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
}
- for (int i = 0; i < parameter_count; ++i, ++value_iterator) {
+ for (int i = 0; i < parameters_count; ++i, ++value_iterator) {
frame_writer.PushTranslatedValue(value_iterator, "stack parameter");
}
@@ -880,7 +884,7 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
is_bottommost ? caller_fp_ : output_[frame_index - 1]->GetFp();
frame_writer.PushCallerFp(caller_fp);
- intptr_t fp_value = top_address + frame_writer.top_offset();
+ const intptr_t fp_value = top_address + frame_writer.top_offset();
output_frame->SetFp(fp_value);
if (is_topmost) {
Register fp_reg = InterpretedFrame::fp_register();
@@ -926,7 +930,7 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
frame_writer.PushRawObject(bytecode_array, "bytecode array\n");
// The bytecode offset was mentioned explicitly in the BEGIN_FRAME.
- int raw_bytecode_offset =
+ const int raw_bytecode_offset =
BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset;
Smi smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset);
frame_writer.PushRawObject(smi_bytecode_offset, "bytecode offset\n");
@@ -938,16 +942,16 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
// Translate the rest of the interpreter registers in the frame.
// The return_value_offset is counted from the top. Here, we compute the
// register index (counted from the start).
- int return_value_first_reg =
- register_count - translated_frame->return_value_offset();
- int return_value_count = translated_frame->return_value_count();
- for (int i = 0; i < register_count; ++i, ++value_iterator) {
+ const int return_value_first_reg =
+ locals_count - translated_frame->return_value_offset();
+ const int return_value_count = translated_frame->return_value_count();
+ for (int i = 0; i < locals_count; ++i, ++value_iterator) {
// Ensure we write the return value if we have one and we are returning
// normally to a lazy deopt point.
if (is_topmost && !goto_catch_handler &&
deopt_kind_ == DeoptimizeKind::kLazy && i >= return_value_first_reg &&
i < return_value_first_reg + return_value_count) {
- int return_index = i - return_value_first_reg;
+ const int return_index = i - return_value_first_reg;
if (return_index == 0) {
frame_writer.PushRawValue(input_->GetRegister(kReturnRegister0.code()),
"return value 0\n");
@@ -955,7 +959,7 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
// the accumulator and another one into an ordinary register. Since
// the interpreter should never create such situation, just assert
// this does not happen.
- CHECK_LE(return_value_first_reg + return_value_count, register_count);
+ CHECK_LE(return_value_first_reg + return_value_count, locals_count);
} else {
CHECK_EQ(return_index, 1);
frame_writer.PushRawValue(input_->GetRegister(kReturnRegister1.code()),
@@ -967,18 +971,18 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
}
}
- int register_slots_written = register_count;
- DCHECK_LE(register_slots_written, register_stack_slot_count);
+ uint32_t register_slots_written = static_cast<uint32_t>(locals_count);
+ DCHECK_LE(register_slots_written, frame_info.register_stack_slot_count());
// Some architectures must pad the stack frame with extra stack slots
// to ensure the stack frame is aligned. Do this now.
- while (register_slots_written < register_stack_slot_count) {
+ while (register_slots_written < frame_info.register_stack_slot_count()) {
register_slots_written++;
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
}
// Translate the accumulator register (depending on frame position).
if (is_topmost) {
- if (PadTopOfStackRegister()) {
+ if (kPadArguments) {
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
}
// For topmost frame, put the accumulator on the stack. The
@@ -1054,26 +1058,24 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
void Deoptimizer::DoComputeArgumentsAdaptorFrame(
TranslatedFrame* translated_frame, int frame_index) {
TranslatedFrame::iterator value_iterator = translated_frame->begin();
- bool is_bottommost = (0 == frame_index);
+ const bool is_bottommost = (0 == frame_index);
- unsigned height = translated_frame->height();
- unsigned height_in_bytes = height * kSystemPointerSize;
- int parameter_count = height;
- if (ShouldPadArguments(parameter_count))
- height_in_bytes += kSystemPointerSize;
+ const int parameters_count = translated_frame->height();
+ ArgumentsAdaptorFrameInfo frame_info =
+ ArgumentsAdaptorFrameInfo::Precise(parameters_count);
+ const uint32_t output_frame_size = frame_info.frame_size_in_bytes();
TranslatedFrame::iterator function_iterator = value_iterator++;
if (trace_scope_ != nullptr) {
PrintF(trace_scope_->file(),
- " translating arguments adaptor => height=%d\n", height_in_bytes);
+ " translating arguments adaptor => variable_frame_size=%d, "
+ "frame_size=%d\n",
+ frame_info.frame_size_in_bytes_without_fixed(), output_frame_size);
}
- unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFixedFrameSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
// Allocate and store the output frame description.
FrameDescription* output_frame = new (output_frame_size)
- FrameDescription(output_frame_size, parameter_count);
+ FrameDescription(output_frame_size, parameters_count);
FrameWriter frame_writer(this, output_frame, trace_scope_);
// Arguments adaptor can not be topmost.
@@ -1083,21 +1085,18 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(
// The top address of the frame is computed from the previous frame's top and
// this frame's size.
- intptr_t top_address;
- if (is_bottommost) {
- top_address = caller_frame_top_ - output_frame_size;
- } else {
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- }
+ const intptr_t top_address =
+ is_bottommost ? caller_frame_top_ - output_frame_size
+ : output_[frame_index - 1]->GetTop() - output_frame_size;
output_frame->SetTop(top_address);
ReadOnlyRoots roots(isolate());
- if (ShouldPadArguments(parameter_count)) {
+ if (ShouldPadArguments(parameters_count)) {
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
}
// Compute the incoming parameter translation.
- for (int i = 0; i < parameter_count; ++i, ++value_iterator) {
+ for (int i = 0; i < parameters_count; ++i, ++value_iterator) {
frame_writer.PushTranslatedValue(value_iterator, "stack parameter");
}
@@ -1133,7 +1132,9 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(
frame_writer.PushTranslatedValue(function_iterator, "function\n");
// Number of incoming arguments.
- frame_writer.PushRawObject(Smi::FromInt(height - 1), "argc\n");
+ const uint32_t parameters_count_without_receiver = parameters_count - 1;
+ frame_writer.PushRawObject(Smi::FromInt(parameters_count_without_receiver),
+ "argc\n");
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
@@ -1157,7 +1158,7 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(
void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
int frame_index) {
TranslatedFrame::iterator value_iterator = translated_frame->begin();
- bool is_topmost = (output_count_ - 1 == frame_index);
+ const bool is_topmost = (output_count_ - 1 == frame_index);
// The construct frame could become topmost only if we inlined a constructor
// call which does a tail call (otherwise the tail callee's frame would be
// the topmost one). So it could only be the DeoptimizeKind::kLazy case.
@@ -1166,38 +1167,25 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
Builtins* builtins = isolate_->builtins();
Code construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
BailoutId bailout_id = translated_frame->node_id();
- unsigned height = translated_frame->height();
- unsigned parameter_count = height - 1; // Exclude the context.
- unsigned height_in_bytes = parameter_count * kSystemPointerSize;
-
- // If the construct frame appears to be topmost we should ensure that the
- // value of result register is preserved during continuation execution.
- // We do this here by "pushing" the result of the constructor function to the
- // top of the reconstructed stack and popping it in
- // {Builtins::kNotifyDeoptimized}.
- if (is_topmost) {
- height_in_bytes += kSystemPointerSize;
- if (PadTopOfStackRegister()) height_in_bytes += kSystemPointerSize;
- }
- if (ShouldPadArguments(parameter_count))
- height_in_bytes += kSystemPointerSize;
+ const int parameters_count = translated_frame->height();
+ ConstructStubFrameInfo frame_info =
+ ConstructStubFrameInfo::Precise(parameters_count, is_topmost);
+ const uint32_t output_frame_size = frame_info.frame_size_in_bytes();
TranslatedFrame::iterator function_iterator = value_iterator++;
if (trace_scope_ != nullptr) {
PrintF(trace_scope_->file(),
- " translating construct stub => bailout_id=%d (%s), height=%d\n",
+ " translating construct stub => bailout_id=%d (%s), "
+ "variable_frame_size=%d, frame_size=%d\n",
bailout_id.ToInt(),
bailout_id == BailoutId::ConstructStubCreate() ? "create" : "invoke",
- height_in_bytes);
+ frame_info.frame_size_in_bytes_without_fixed(), output_frame_size);
}
- unsigned fixed_frame_size = ConstructFrameConstants::kFixedFrameSize;
- unsigned output_frame_size = height_in_bytes + fixed_frame_size;
-
// Allocate and store the output frame description.
FrameDescription* output_frame = new (output_frame_size)
- FrameDescription(output_frame_size, parameter_count);
+ FrameDescription(output_frame_size, parameters_count);
FrameWriter frame_writer(this, output_frame, trace_scope_);
// Construct stub can not be topmost.
@@ -1207,12 +1195,12 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
// The top address of the frame is computed from the previous frame's top and
// this frame's size.
- intptr_t top_address;
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ const intptr_t top_address =
+ output_[frame_index - 1]->GetTop() - output_frame_size;
output_frame->SetTop(top_address);
ReadOnlyRoots roots(isolate());
- if (ShouldPadArguments(parameter_count)) {
+ if (ShouldPadArguments(parameters_count)) {
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
}
@@ -1222,7 +1210,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
TranslatedFrame::iterator receiver_iterator = value_iterator;
// Compute the incoming parameter translation.
- for (unsigned i = 0; i < parameter_count; ++i, ++value_iterator) {
+ for (int i = 0; i < parameters_count; ++i, ++value_iterator) {
frame_writer.PushTranslatedValue(value_iterator, "stack parameter");
}
@@ -1237,7 +1225,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
const intptr_t caller_fp = output_[frame_index - 1]->GetFp();
frame_writer.PushCallerFp(caller_fp);
- intptr_t fp_value = top_address + frame_writer.top_offset();
+ const intptr_t fp_value = top_address + frame_writer.top_offset();
output_frame->SetFp(fp_value);
if (is_topmost) {
Register fp_reg = JavaScriptFrame::fp_register();
@@ -1257,7 +1245,9 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
frame_writer.PushTranslatedValue(value_iterator++, "context");
// Number of incoming arguments.
- frame_writer.PushRawObject(Smi::FromInt(parameter_count - 1), "argc\n");
+ const uint32_t parameters_count_without_receiver = parameters_count - 1;
+ frame_writer.PushRawObject(Smi::FromInt(parameters_count_without_receiver),
+ "argc\n");
// The constructor function was mentioned explicitly in the
// CONSTRUCT_STUB_FRAME.
@@ -1277,7 +1267,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
frame_writer.PushTranslatedValue(receiver_iterator, debug_hint);
if (is_topmost) {
- if (PadTopOfStackRegister()) {
+ if (kPadArguments) {
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
}
// Ensure the result is restored back when we return to the stub.
@@ -1292,7 +1282,7 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
// Compute this frame's PC.
DCHECK(bailout_id.IsValidForConstructStub());
Address start = construct_stub.InstructionStart();
- int pc_offset =
+ const int pc_offset =
bailout_id == BailoutId::ConstructStubCreate()
? isolate_->heap()->construct_stub_create_deopt_pc_offset().value()
: isolate_->heap()->construct_stub_invoke_deopt_pc_offset().value();
@@ -1330,8 +1320,9 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
}
}
-bool Deoptimizer::BuiltinContinuationModeIsJavaScript(
- BuiltinContinuationMode mode) {
+namespace {
+
+bool BuiltinContinuationModeIsJavaScript(BuiltinContinuationMode mode) {
switch (mode) {
case BuiltinContinuationMode::STUB:
return false;
@@ -1343,31 +1334,16 @@ bool Deoptimizer::BuiltinContinuationModeIsJavaScript(
UNREACHABLE();
}
-bool Deoptimizer::BuiltinContinuationModeIsWithCatch(
+StackFrame::Type BuiltinContinuationModeToFrameType(
BuiltinContinuationMode mode) {
switch (mode) {
case BuiltinContinuationMode::STUB:
- case BuiltinContinuationMode::JAVASCRIPT:
- return false;
- case BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH:
- case BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION:
- return true;
- }
- UNREACHABLE();
-}
-
-namespace {
-
-StackFrame::Type BuiltinContinuationModeToFrameType(
- Deoptimizer::BuiltinContinuationMode mode) {
- switch (mode) {
- case Deoptimizer::BuiltinContinuationMode::STUB:
return StackFrame::BUILTIN_CONTINUATION;
- case Deoptimizer::BuiltinContinuationMode::JAVASCRIPT:
+ case BuiltinContinuationMode::JAVASCRIPT:
return StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION;
- case Deoptimizer::BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH:
+ case BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH:
return StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH;
- case Deoptimizer::BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION:
+ case BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION:
return StackFrame::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH;
}
UNREACHABLE();
@@ -1454,65 +1430,31 @@ void Deoptimizer::DoComputeBuiltinContinuation(
BuiltinContinuationMode mode) {
TranslatedFrame::iterator value_iterator = translated_frame->begin();
- // The output frame must have room for all of the parameters that need to be
- // passed to the builtin continuation.
- const int height_in_words = translated_frame->height();
-
- BailoutId bailout_id = translated_frame->node_id();
+ const BailoutId bailout_id = translated_frame->node_id();
Builtins::Name builtin_name = Builtins::GetBuiltinFromBailoutId(bailout_id);
- Code builtin = isolate()->builtins()->builtin(builtin_name);
- Callable continuation_callable =
- Builtins::CallableFor(isolate(), builtin_name);
CallInterfaceDescriptor continuation_descriptor =
- continuation_callable.descriptor();
+ Builtins::CallInterfaceDescriptorFor(builtin_name);
+
+ const RegisterConfiguration* config = RegisterConfiguration::Default();
const bool is_bottommost = (0 == frame_index);
const bool is_topmost = (output_count_ - 1 == frame_index);
- const bool must_handle_result =
- !is_topmost || deopt_kind_ == DeoptimizeKind::kLazy;
- const RegisterConfiguration* config(RegisterConfiguration::Default());
- const int allocatable_register_count =
- config->num_allocatable_general_registers();
- const int padding_slot_count =
- BuiltinContinuationFrameConstants::PaddingSlotCount(
- allocatable_register_count);
-
- const int register_parameter_count =
- continuation_descriptor.GetRegisterParameterCount();
- // Make sure to account for the context by removing it from the register
- // parameter count.
- const int translated_stack_parameters =
- height_in_words - register_parameter_count - 1;
- const int stack_param_count =
- translated_stack_parameters + (must_handle_result ? 1 : 0) +
- (BuiltinContinuationModeIsWithCatch(mode) ? 1 : 0);
- const int stack_param_pad_count =
- ShouldPadArguments(stack_param_count) ? 1 : 0;
-
- // If the builtins frame appears to be topmost we should ensure that the
- // value of result register is preserved during continuation execution.
- // We do this here by "pushing" the result of callback function to the
- // top of the reconstructed stack and popping it in
- // {Builtins::kNotifyDeoptimized}.
- const int push_result_count =
- is_topmost ? (PadTopOfStackRegister() ? 2 : 1) : 0;
-
- const unsigned output_frame_size =
- kSystemPointerSize * (stack_param_count + stack_param_pad_count +
- allocatable_register_count + padding_slot_count +
- push_result_count) +
- BuiltinContinuationFrameConstants::kFixedFrameSize;
+ const int parameters_count = translated_frame->height();
+ BuiltinContinuationFrameInfo frame_info =
+ BuiltinContinuationFrameInfo::Precise(parameters_count,
+ continuation_descriptor, config,
+ is_topmost, deopt_kind_, mode);
+ const unsigned output_frame_size = frame_info.frame_size_in_bytes();
const unsigned output_frame_size_above_fp =
- kSystemPointerSize * (allocatable_register_count + padding_slot_count +
- push_result_count) +
- (BuiltinContinuationFrameConstants::kFixedFrameSize -
- BuiltinContinuationFrameConstants::kFixedFrameSizeAboveFp);
+ frame_info.frame_size_in_bytes_above_fp();
// Validate types of parameters. They must all be tagged except for argc for
// JS builtins.
bool has_argc = false;
+ const int register_parameter_count =
+ continuation_descriptor.GetRegisterParameterCount();
for (int i = 0; i < register_parameter_count; ++i) {
MachineType type = continuation_descriptor.GetParameterType(i);
int code = continuation_descriptor.GetRegisterParameter(i).code();
@@ -1531,25 +1473,22 @@ void Deoptimizer::DoComputeBuiltinContinuation(
if (trace_scope_ != nullptr) {
PrintF(trace_scope_->file(),
" translating BuiltinContinuation to %s,"
- " register param count %d,"
- " stack param count %d\n",
+ " => register_param_count=%d,"
+ " stack_param_count=%d, frame_size=%d\n",
Builtins::name(builtin_name), register_parameter_count,
- stack_param_count);
+ frame_info.stack_parameter_count(), output_frame_size);
}
FrameDescription* output_frame = new (output_frame_size)
- FrameDescription(output_frame_size, stack_param_count);
+ FrameDescription(output_frame_size, frame_info.stack_parameter_count());
output_[frame_index] = output_frame;
FrameWriter frame_writer(this, output_frame, trace_scope_);
// The top address of the frame is computed from the previous frame's top and
// this frame's size.
- intptr_t top_address;
- if (is_bottommost) {
- top_address = caller_frame_top_ - output_frame_size;
- } else {
- top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
- }
+ const intptr_t top_address =
+ is_bottommost ? caller_frame_top_ - output_frame_size
+ : output_[frame_index - 1]->GetTop() - output_frame_size;
output_frame->SetTop(top_address);
// Get the possible JSFunction for the case that this is a
@@ -1559,11 +1498,12 @@ void Deoptimizer::DoComputeBuiltinContinuation(
++value_iterator;
ReadOnlyRoots roots(isolate());
- if (ShouldPadArguments(stack_param_count)) {
+ if (ShouldPadArguments(frame_info.stack_parameter_count())) {
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
}
- for (int i = 0; i < translated_stack_parameters; ++i, ++value_iterator) {
+ for (uint32_t i = 0; i < frame_info.translated_stack_parameter_count();
+ ++i, ++value_iterator) {
frame_writer.PushTranslatedValue(value_iterator, "stack parameter");
}
@@ -1584,7 +1524,7 @@ void Deoptimizer::DoComputeBuiltinContinuation(
} break;
}
- if (must_handle_result) {
+ if (frame_info.frame_has_result_stack_slot()) {
frame_writer.PushRawObject(roots.the_hole_value(),
"placeholder for return result on lazy deopt\n");
}
@@ -1659,9 +1599,10 @@ void Deoptimizer::DoComputeBuiltinContinuation(
"builtin JavaScript context\n");
// The builtin to continue to.
- frame_writer.PushRawObject(Smi::FromInt(builtin.builtin_index()),
- "builtin index\n");
+ frame_writer.PushRawObject(Smi::FromInt(builtin_name), "builtin index\n");
+ const int allocatable_register_count =
+ config->num_allocatable_general_registers();
for (int i = 0; i < allocatable_register_count; ++i) {
int code = config->GetAllocatableGeneralCode(i);
ScopedVector<char> str(128);
@@ -1683,17 +1624,20 @@ void Deoptimizer::DoComputeBuiltinContinuation(
// Some architectures must pad the stack frame with extra stack slots
// to ensure the stack frame is aligned.
+ const int padding_slot_count =
+ BuiltinContinuationFrameConstants::PaddingSlotCount(
+ allocatable_register_count);
for (int i = 0; i < padding_slot_count; ++i) {
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
}
if (is_topmost) {
- if (PadTopOfStackRegister()) {
+ if (kPadArguments) {
frame_writer.PushRawObject(roots.the_hole_value(), "padding\n");
}
- // Ensure the result is restored back when we return to the stub.
- if (must_handle_result) {
+ // Ensure the result is restored back when we return to the stub.
+ if (frame_info.frame_has_result_stack_slot()) {
Register result_reg = kReturnRegister0;
frame_writer.PushRawValue(input_->GetRegister(result_reg.code()),
"callback result\n");
@@ -1719,8 +1663,9 @@ void Deoptimizer::DoComputeBuiltinContinuation(
Register fp_reg = JavaScriptFrame::fp_register();
output_frame->SetRegister(fp_reg.code(), fp_value);
- Code continue_to_builtin = isolate()->builtins()->builtin(
- TrampolineForBuiltinContinuation(mode, must_handle_result));
+ Code continue_to_builtin =
+ isolate()->builtins()->builtin(TrampolineForBuiltinContinuation(
+ mode, frame_info.frame_has_result_stack_slot()));
output_frame->SetPc(
static_cast<intptr_t>(continue_to_builtin.InstructionStart()));
@@ -1801,17 +1746,9 @@ unsigned Deoptimizer::ComputeInputFrameSize() const {
}
// static
-unsigned Deoptimizer::ComputeInterpretedFixedSize(SharedFunctionInfo shared) {
- // The fixed part of the frame consists of the return address, frame
- // pointer, function, context, bytecode offset and all the incoming arguments.
- return ComputeIncomingArgumentSize(shared) +
- InterpreterFrameConstants::kFixedFrameSize;
-}
-
-// static
unsigned Deoptimizer::ComputeIncomingArgumentSize(SharedFunctionInfo shared) {
- int parameter_slots = shared.internal_formal_parameter_count() + 1;
- if (kPadArguments) parameter_slots = RoundUp(parameter_slots, 2);
+ int parameter_slots = InternalFormalParameterCountWithReceiver(shared);
+ if (ShouldPadArguments(parameter_slots)) parameter_slots++;
return parameter_slots * kSystemPointerSize;
}
@@ -2254,12 +2191,9 @@ DeoptimizedFrameInfo::DeoptimizedFrameInfo(TranslatedState* state,
stack_it++;
// Get the expression stack.
- int stack_height = frame_it->height();
- if (frame_it->kind() == TranslatedFrame::kInterpretedFunction) {
- // For interpreter frames, we should not count the accumulator.
- // TODO(jarin): Clean up the indexing in translated frames.
- stack_height--;
- }
+ DCHECK_EQ(TranslatedFrame::kInterpretedFunction, frame_it->kind());
+ const int stack_height = frame_it->height(); // Accumulator *not* included.
+
expression_stack_.resize(static_cast<size_t>(stack_height));
for (int i = 0; i < stack_height; i++) {
Handle<Object> expression = GetValueForDebugger(stack_it, isolate);
@@ -2267,10 +2201,9 @@ DeoptimizedFrameInfo::DeoptimizedFrameInfo(TranslatedState* state,
stack_it++;
}
- // For interpreter frame, skip the accumulator.
- if (frame_it->kind() == TranslatedFrame::kInterpretedFunction) {
- stack_it++;
- }
+ DCHECK_EQ(TranslatedFrame::kInterpretedFunction, frame_it->kind());
+ stack_it++; // Skip the accumulator.
+
CHECK(stack_it == frame_it->end());
}
@@ -2688,20 +2621,30 @@ TranslatedFrame TranslatedFrame::JavaScriptBuiltinContinuationWithCatchFrame(
}
int TranslatedFrame::GetValueCount() {
+ // The function is added to all frame state descriptors in
+ // InstructionSelector::AddInputsToFrameStateDescriptor.
+ static constexpr int kTheFunction = 1;
+
switch (kind()) {
case kInterpretedFunction: {
int parameter_count =
- raw_shared_info_.internal_formal_parameter_count() + 1;
- // + 2 for function and context.
- return height_ + parameter_count + 2;
+ InternalFormalParameterCountWithReceiver(raw_shared_info_);
+ static constexpr int kTheContext = 1;
+ static constexpr int kTheAccumulator = 1;
+ return height() + parameter_count + kTheContext + kTheFunction +
+ kTheAccumulator;
}
case kArgumentsAdaptor:
+ return height() + kTheFunction;
+
case kConstructStub:
case kBuiltinContinuation:
case kJavaScriptBuiltinContinuation:
- case kJavaScriptBuiltinContinuationWithCatch:
- return 1 + height_;
+ case kJavaScriptBuiltinContinuationWithCatch: {
+ static constexpr int kTheContext = 1;
+ return height() + kTheContext + kTheFunction;
+ }
case kInvalid:
UNREACHABLE();
@@ -2736,7 +2679,7 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
if (trace_file != nullptr) {
std::unique_ptr<char[]> name = shared_info.DebugName().ToCString();
PrintF(trace_file, " reading input frame %s", name.get());
- int arg_count = shared_info.internal_formal_parameter_count() + 1;
+ int arg_count = InternalFormalParameterCountWithReceiver(shared_info);
PrintF(trace_file,
" => bytecode_offset=%d, args=%d, height=%d, retval=%i(#%i); "
"inputs:\n",
@@ -2787,11 +2730,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
PrintF(trace_file, " => bailout_id=%d, height=%d; inputs:\n",
bailout_id.ToInt(), height);
}
- // Add one to the height to account for the context which was implicitly
- // added to the translation during code generation.
- int height_with_context = height + 1;
return TranslatedFrame::BuiltinContinuationFrame(bailout_id, shared_info,
- height_with_context);
+ height);
}
case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME: {
@@ -2806,11 +2746,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
PrintF(trace_file, " => bailout_id=%d, height=%d; inputs:\n",
bailout_id.ToInt(), height);
}
- // Add one to the height to account for the context which was implicitly
- // added to the translation during code generation.
- int height_with_context = height + 1;
return TranslatedFrame::JavaScriptBuiltinContinuationFrame(
- bailout_id, shared_info, height_with_context);
+ bailout_id, shared_info, height);
}
case Translation::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME: {
BailoutId bailout_id = BailoutId(iterator->Next());
@@ -2825,11 +2762,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
PrintF(trace_file, " => bailout_id=%d, height=%d; inputs:\n",
bailout_id.ToInt(), height);
}
- // Add one to the height to account for the context which was implicitly
- // added to the translation during code generation.
- int height_with_context = height + 1;
return TranslatedFrame::JavaScriptBuiltinContinuationWithCatchFrame(
- bailout_id, shared_info, height_with_context);
+ bailout_id, shared_info, height);
}
case Translation::UPDATE_FEEDBACK:
case Translation::BEGIN:
@@ -3450,7 +3384,7 @@ void TranslatedState::InitializeCapturedObjectAt(
// Handle the special cases.
switch (map->instance_type()) {
- case MUTABLE_HEAP_NUMBER_TYPE:
+ case HEAP_NUMBER_TYPE:
case FIXED_DOUBLE_ARRAY_TYPE:
return;
@@ -3528,15 +3462,14 @@ void TranslatedState::MaterializeFixedDoubleArray(TranslatedFrame* frame,
slot->set_storage(array);
}
-void TranslatedState::MaterializeMutableHeapNumber(TranslatedFrame* frame,
- int* value_index,
- TranslatedValue* slot) {
+void TranslatedState::MaterializeHeapNumber(TranslatedFrame* frame,
+ int* value_index,
+ TranslatedValue* slot) {
CHECK_NE(TranslatedValue::kCapturedObject,
frame->values_[*value_index].kind());
Handle<Object> value = frame->values_[*value_index].GetValue();
CHECK(value->IsNumber());
- Handle<MutableHeapNumber> box =
- isolate()->factory()->NewMutableHeapNumber(value->Number());
+ Handle<HeapNumber> box = isolate()->factory()->NewHeapNumber(value->Number());
(*value_index)++;
slot->set_storage(box);
}
@@ -3592,10 +3525,10 @@ void TranslatedState::EnsureCapturedObjectAllocatedAt(
// there is no need to process the children.
return MaterializeFixedDoubleArray(frame, &value_index, slot, map);
- case MUTABLE_HEAP_NUMBER_TYPE:
+ case HEAP_NUMBER_TYPE:
// Materialize (i.e. allocate&initialize) the heap number and return.
// There is no need to process the children.
- return MaterializeMutableHeapNumber(frame, &value_index, slot);
+ return MaterializeHeapNumber(frame, &value_index, slot);
case FIXED_ARRAY_TYPE:
case SCRIPT_CONTEXT_TABLE_TYPE:
@@ -3813,7 +3746,7 @@ void TranslatedState::InitializeJSObjectAt(
}
object_storage->WriteField<double>(offset, double_field_value);
} else if (marker == kStoreMutableHeapNumber) {
- CHECK(field_value->IsMutableHeapNumber());
+ CHECK(field_value->IsHeapNumber());
WRITE_FIELD(*object_storage, offset, *field_value);
WRITE_BARRIER(*object_storage, offset, *field_value);
} else {
@@ -3848,10 +3781,9 @@ void TranslatedState::InitializeObjectWithTaggedFieldsAt(
int offset = i * kTaggedSize;
uint8_t marker = object_storage->ReadField<uint8_t>(offset);
if (i > 1 && marker == kStoreMutableHeapNumber) {
- CHECK(field_value->IsMutableHeapNumber());
+ CHECK(field_value->IsHeapNumber());
} else {
CHECK(marker == kStoreTagged || i == 1);
- CHECK(!field_value->IsMutableHeapNumber());
}
WRITE_FIELD(*object_storage, offset, *field_value);
@@ -3918,15 +3850,16 @@ TranslatedFrame* TranslatedState::GetArgumentsInfoFromJSFrameIndex(
// to last value in the TranslatedFrame. It should also always be
// {1}, as the GenericLazyDeoptContinuation builtin only has one
// argument (the receiver).
- const int height = frames_[i].height();
+ static constexpr int kTheContext = 1;
+ const int height = frames_[i].height() + kTheContext;
Object argc_object = frames_[i].ValueAt(height - 1)->GetRawValue();
CHECK(argc_object.IsSmi());
*args_count = Smi::ToInt(argc_object);
DCHECK_EQ(*args_count, 1);
} else {
- *args_count =
- frames_[i].shared_info()->internal_formal_parameter_count() + 1;
+ *args_count = InternalFormalParameterCountWithReceiver(
+ *frames_[i].shared_info());
}
return &(frames_[i]);
}
diff --git a/deps/v8/src/deoptimizer/deoptimizer.h b/deps/v8/src/deoptimizer/deoptimizer.h
index a2471247ef..6d0a350aac 100644
--- a/deps/v8/src/deoptimizer/deoptimizer.h
+++ b/deps/v8/src/deoptimizer/deoptimizer.h
@@ -35,6 +35,8 @@ class TranslatedState;
class RegisterValues;
class MacroAssembler;
+enum class BuiltinContinuationMode;
+
class TranslatedValue {
public:
// Allocation-less getter of the value.
@@ -172,7 +174,14 @@ class TranslatedFrame {
Kind kind() const { return kind_; }
BailoutId node_id() const { return node_id_; }
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
+
+ // TODO(jgruber): Simplify/clarify the semantics of this field. The name
+ // `height` is slightly misleading. Yes, this value is related to stack frame
+ // height, but must undergo additional mutations to arrive at the real stack
+ // frame height (e.g.: addition/subtraction of context, accumulator, fixed
+ // frame sizes, padding).
int height() const { return height_; }
+
int return_value_offset() const { return return_value_offset_; }
int return_value_count() const { return return_value_count_; }
@@ -352,8 +361,8 @@ class TranslatedState {
void UpdateFromPreviouslyMaterializedObjects();
void MaterializeFixedDoubleArray(TranslatedFrame* frame, int* value_index,
TranslatedValue* slot, Handle<Map> map);
- void MaterializeMutableHeapNumber(TranslatedFrame* frame, int* value_index,
- TranslatedValue* slot);
+ void MaterializeHeapNumber(TranslatedFrame* frame, int* value_index,
+ TranslatedValue* slot);
void EnsureObjectAllocatedAt(TranslatedValue* slot);
@@ -501,12 +510,14 @@ class Deoptimizer : public Malloced {
static const int kMaxNumberOfEntries = 16384;
- enum class BuiltinContinuationMode {
- STUB,
- JAVASCRIPT,
- JAVASCRIPT_WITH_CATCH,
- JAVASCRIPT_HANDLE_EXCEPTION
- };
+ // Set to true when the architecture supports deoptimization exit sequences
+ // of a fixed size, that can be sorted so that the deoptimization index is
+ // deduced from the address of the deoptimization exit.
+ static const bool kSupportsFixedDeoptExitSize;
+
+ // Size of deoptimization exit sequence. This is only meaningful when
+ // kSupportsFixedDeoptExitSize is true.
+ static const int kDeoptExitSize;
private:
friend class FrameWriter;
@@ -530,8 +541,6 @@ class Deoptimizer : public Malloced {
void DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
int frame_index);
- static bool BuiltinContinuationModeIsWithCatch(BuiltinContinuationMode mode);
- static bool BuiltinContinuationModeIsJavaScript(BuiltinContinuationMode mode);
static Builtins::Name TrampolineForBuiltinContinuation(
BuiltinContinuationMode mode, bool must_handle_result);
@@ -541,7 +550,6 @@ class Deoptimizer : public Malloced {
unsigned ComputeInputFrameAboveFpFixedSize() const;
unsigned ComputeInputFrameSize() const;
- static unsigned ComputeInterpretedFixedSize(SharedFunctionInfo shared);
static unsigned ComputeIncomingArgumentSize(SharedFunctionInfo shared);
static unsigned ComputeOutgoingArgumentSize(Code code, unsigned bailout_id);
@@ -552,11 +560,6 @@ class Deoptimizer : public Malloced {
static void MarkAllCodeForContext(NativeContext native_context);
static void DeoptimizeMarkedCodeForContext(NativeContext native_context);
-
- // Some architectures need to push padding together with the TOS register
- // in order to maintain stack alignment.
- static bool PadTopOfStackRegister();
-
// Searches the list of known deoptimizing code for a Code object
// containing the given address (which is supposedly faster than
// searching all code objects).
@@ -626,10 +629,7 @@ class RegisterValues {
return registers_[n];
}
- Float32 GetFloatRegister(unsigned n) const {
- DCHECK(n < arraysize(float_registers_));
- return float_registers_[n];
- }
+ Float32 GetFloatRegister(unsigned n) const;
Float64 GetDoubleRegister(unsigned n) const {
DCHECK(n < arraysize(double_registers_));
@@ -641,23 +641,10 @@ class RegisterValues {
registers_[n] = value;
}
- void SetFloatRegister(unsigned n, Float32 value) {
- DCHECK(n < arraysize(float_registers_));
- float_registers_[n] = value;
- }
-
- void SetDoubleRegister(unsigned n, Float64 value) {
- DCHECK(n < arraysize(double_registers_));
- double_registers_[n] = value;
- }
-
- // Generated code is writing directly into the below arrays, make sure their
- // element sizes fit what the machine instructions expect.
- static_assert(sizeof(Float32) == kFloatSize, "size mismatch");
- static_assert(sizeof(Float64) == kDoubleSize, "size mismatch");
-
intptr_t registers_[Register::kNumRegisters];
- Float32 float_registers_[FloatRegister::kNumRegisters];
+ // Generated code writes directly into the following array, make sure the
+ // element size matches what the machine instructions expect.
+ static_assert(sizeof(Float64) == kDoubleSize, "size mismatch");
Float64 double_registers_[DoubleRegister::kNumRegisters];
};
@@ -687,7 +674,7 @@ class FrameDescription {
unsigned GetLastArgumentSlotOffset() {
int parameter_slots = parameter_count();
- if (kPadArguments) parameter_slots = RoundUp(parameter_slots, 2);
+ if (ShouldPadArguments(parameter_slots)) parameter_slots++;
return GetFrameSize() - parameter_slots * kSystemPointerSize;
}
@@ -721,10 +708,6 @@ class FrameDescription {
register_values_.SetRegister(n, value);
}
- void SetDoubleRegister(unsigned n, Float64 value) {
- register_values_.SetDoubleRegister(n, value);
- }
-
intptr_t GetTop() const { return top_; }
void SetTop(intptr_t top) { top_ = top; }
@@ -755,10 +738,6 @@ class FrameDescription {
return OFFSET_OF(FrameDescription, register_values_.double_registers_);
}
- static int float_registers_offset() {
- return OFFSET_OF(FrameDescription, register_values_.float_registers_);
- }
-
static int frame_size_offset() {
return offsetof(FrameDescription, frame_size_);
}
diff --git a/deps/v8/src/deoptimizer/ia32/deoptimizer-ia32.cc b/deps/v8/src/deoptimizer/ia32/deoptimizer-ia32.cc
index f40ff562be..6c82512d40 100644
--- a/deps/v8/src/deoptimizer/ia32/deoptimizer-ia32.cc
+++ b/deps/v8/src/deoptimizer/ia32/deoptimizer-ia32.cc
@@ -13,6 +13,9 @@
namespace v8 {
namespace internal {
+const bool Deoptimizer::kSupportsFixedDeoptExitSize = false;
+const int Deoptimizer::kDeoptExitSize = 0;
+
#define __ masm->
void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
@@ -33,24 +36,14 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ movsd(Operand(esp, offset), xmm_reg);
}
- STATIC_ASSERT(kFloatSize == kSystemPointerSize);
- const int kFloatRegsSize = kFloatSize * XMMRegister::kNumRegisters;
- __ AllocateStackSpace(kFloatRegsSize);
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- XMMRegister xmm_reg = XMMRegister::from_code(code);
- int offset = code * kFloatSize;
- __ movss(Operand(esp, offset), xmm_reg);
- }
-
__ pushad();
ExternalReference c_entry_fp_address =
ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate);
__ mov(masm->ExternalReferenceAsOperand(c_entry_fp_address, esi), ebp);
- const int kSavedRegistersAreaSize = kNumberOfRegisters * kSystemPointerSize +
- kDoubleRegsSize + kFloatRegsSize;
+ const int kSavedRegistersAreaSize =
+ kNumberOfRegisters * kSystemPointerSize + kDoubleRegsSize;
// The bailout id is passed in ebx by the caller.
@@ -94,13 +87,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ pop(Operand(esi, offset));
}
- int float_regs_offset = FrameDescription::float_registers_offset();
- // Fill in the float input registers.
- for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
- int dst_offset = i * kFloatSize + float_regs_offset;
- __ pop(Operand(esi, dst_offset));
- }
-
int double_regs_offset = FrameDescription::double_registers_offset();
// Fill in the double input registers.
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
@@ -213,7 +199,10 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ ret(0);
}
-bool Deoptimizer::PadTopOfStackRegister() { return false; }
+Float32 RegisterValues::GetFloatRegister(unsigned n) const {
+ return Float32::FromBits(
+ static_cast<uint32_t>(double_registers_[n].get_bits()));
+}
void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
SetFrameSlot(offset, value);
diff --git a/deps/v8/src/deoptimizer/mips/deoptimizer-mips.cc b/deps/v8/src/deoptimizer/mips/deoptimizer-mips.cc
index 07bc9a511b..6f4edee46c 100644
--- a/deps/v8/src/deoptimizer/mips/deoptimizer-mips.cc
+++ b/deps/v8/src/deoptimizer/mips/deoptimizer-mips.cc
@@ -10,6 +10,9 @@
namespace v8 {
namespace internal {
+const bool Deoptimizer::kSupportsFixedDeoptExitSize = false;
+const int Deoptimizer::kDeoptExitSize = 0;
+
#define __ masm->
// This code tries to be close to ia32 code so that any changes can be
@@ -27,7 +30,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
RegList saved_regs = restored_regs | sp.bit() | ra.bit();
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kNumRegisters;
- const int kFloatRegsSize = kFloatSize * FloatRegister::kNumRegisters;
// Save all FPU registers before messing with them.
__ Subu(sp, sp, Operand(kDoubleRegsSize));
@@ -39,14 +41,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ Sdc1(fpu_reg, MemOperand(sp, offset));
}
- __ Subu(sp, sp, Operand(kFloatRegsSize));
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- const FloatRegister fpu_reg = FloatRegister::from_code(code);
- int offset = code * kFloatSize;
- __ swc1(fpu_reg, MemOperand(sp, offset));
- }
-
// Push saved_regs (needed to populate FrameDescription::registers_).
// Leave gaps for other registers.
__ Subu(sp, sp, kNumberOfRegisters * kPointerSize);
@@ -61,7 +55,7 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ sw(fp, MemOperand(a2));
const int kSavedRegistersAreaSize =
- (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize + kFloatRegsSize;
+ (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
// Get the bailout id is passed as kRootRegister by the caller.
__ mov(a2, kRootRegister);
@@ -120,22 +114,11 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
int code = config->GetAllocatableDoubleCode(i);
int dst_offset = code * kDoubleSize + double_regs_offset;
int src_offset =
- code * kDoubleSize + kNumberOfRegisters * kPointerSize + kFloatRegsSize;
+ code * kDoubleSize + kNumberOfRegisters * kPointerSize;
__ Ldc1(f0, MemOperand(sp, src_offset));
__ Sdc1(f0, MemOperand(a1, dst_offset));
}
- // Copy FPU registers to
- // float_registers_[FloatRegister::kNumAllocatableRegisters]
- int float_regs_offset = FrameDescription::float_registers_offset();
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- int dst_offset = code * kFloatSize + float_regs_offset;
- int src_offset = code * kFloatSize + kNumberOfRegisters * kPointerSize;
- __ lwc1(f0, MemOperand(sp, src_offset));
- __ swc1(f0, MemOperand(a1, dst_offset));
- }
-
// Remove the saved registers from the stack.
__ Addu(sp, sp, Operand(kSavedRegistersAreaSize));
@@ -235,7 +218,10 @@ const int Deoptimizer::table_entry_size_ = 2 * kInstrSize;
const int Deoptimizer::table_entry_size_ = 3 * kInstrSize;
#endif
-bool Deoptimizer::PadTopOfStackRegister() { return false; }
+Float32 RegisterValues::GetFloatRegister(unsigned n) const {
+ return Float32::FromBits(
+ static_cast<uint32_t>(double_registers_[n].get_bits()));
+}
void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
SetFrameSlot(offset, value);
diff --git a/deps/v8/src/deoptimizer/mips64/deoptimizer-mips64.cc b/deps/v8/src/deoptimizer/mips64/deoptimizer-mips64.cc
index f85659c4ab..8f8183b492 100644
--- a/deps/v8/src/deoptimizer/mips64/deoptimizer-mips64.cc
+++ b/deps/v8/src/deoptimizer/mips64/deoptimizer-mips64.cc
@@ -10,6 +10,9 @@
namespace v8 {
namespace internal {
+const bool Deoptimizer::kSupportsFixedDeoptExitSize = false;
+const int Deoptimizer::kDeoptExitSize = 0;
+
#define __ masm->
// This code tries to be close to ia32 code so that any changes can be
@@ -27,7 +30,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
RegList saved_regs = restored_regs | sp.bit() | ra.bit();
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kNumRegisters;
- const int kFloatRegsSize = kFloatSize * FloatRegister::kNumRegisters;
// Save all double FPU registers before messing with them.
__ Dsubu(sp, sp, Operand(kDoubleRegsSize));
@@ -39,15 +41,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ Sdc1(fpu_reg, MemOperand(sp, offset));
}
- // Save all float FPU registers before messing with them.
- __ Dsubu(sp, sp, Operand(kFloatRegsSize));
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- const FloatRegister fpu_reg = FloatRegister::from_code(code);
- int offset = code * kFloatSize;
- __ Swc1(fpu_reg, MemOperand(sp, offset));
- }
-
// Push saved_regs (needed to populate FrameDescription::registers_).
// Leave gaps for other registers.
__ Dsubu(sp, sp, kNumberOfRegisters * kPointerSize);
@@ -62,7 +55,7 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ Sd(fp, MemOperand(a2));
const int kSavedRegistersAreaSize =
- (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize + kFloatRegsSize;
+ (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
// Get the bailout is passed as kRootRegister by the caller.
__ mov(a2, kRootRegister);
@@ -122,22 +115,11 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
int code = config->GetAllocatableDoubleCode(i);
int dst_offset = code * kDoubleSize + double_regs_offset;
int src_offset =
- code * kDoubleSize + kNumberOfRegisters * kPointerSize + kFloatRegsSize;
+ code * kDoubleSize + kNumberOfRegisters * kPointerSize;
__ Ldc1(f0, MemOperand(sp, src_offset));
__ Sdc1(f0, MemOperand(a1, dst_offset));
}
- int float_regs_offset = FrameDescription::float_registers_offset();
- // Copy FPU registers to
- // float_registers_[FloatRegister::kNumAllocatableRegisters]
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- int dst_offset = code * kFloatSize + float_regs_offset;
- int src_offset = code * kFloatSize + kNumberOfRegisters * kPointerSize;
- __ Lwc1(f0, MemOperand(sp, src_offset));
- __ Swc1(f0, MemOperand(a1, dst_offset));
- }
-
// Remove the saved registers from the stack.
__ Daddu(sp, sp, Operand(kSavedRegistersAreaSize));
@@ -236,7 +218,10 @@ const int Deoptimizer::table_entry_size_ = 2 * kInstrSize;
const int Deoptimizer::table_entry_size_ = 3 * kInstrSize;
#endif
-bool Deoptimizer::PadTopOfStackRegister() { return false; }
+Float32 RegisterValues::GetFloatRegister(unsigned n) const {
+ return Float32::FromBits(
+ static_cast<uint32_t>(double_registers_[n].get_bits()));
+}
void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
SetFrameSlot(offset, value);
diff --git a/deps/v8/src/deoptimizer/ppc/deoptimizer-ppc.cc b/deps/v8/src/deoptimizer/ppc/deoptimizer-ppc.cc
index 41616a5af2..864e9dbe36 100644
--- a/deps/v8/src/deoptimizer/ppc/deoptimizer-ppc.cc
+++ b/deps/v8/src/deoptimizer/ppc/deoptimizer-ppc.cc
@@ -11,6 +11,9 @@
namespace v8 {
namespace internal {
+const bool Deoptimizer::kSupportsFixedDeoptExitSize = false;
+const int Deoptimizer::kDeoptExitSize = 0;
+
#define __ masm->
// This code tries to be close to ia32 code so that any changes can be
@@ -28,7 +31,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
RegList saved_regs = restored_regs | sp.bit();
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kNumRegisters;
- const int kFloatRegsSize = kFloatSize * FloatRegister::kNumRegisters;
// Save all double registers before messing with them.
__ subi(sp, sp, Operand(kDoubleRegsSize));
@@ -39,14 +41,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
int offset = code * kDoubleSize;
__ stfd(dreg, MemOperand(sp, offset));
}
- // Save all float registers before messing with them.
- __ subi(sp, sp, Operand(kFloatRegsSize));
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- const FloatRegister freg = FloatRegister::from_code(code);
- int offset = code * kFloatSize;
- __ stfs(freg, MemOperand(sp, offset));
- }
// Push saved_regs (needed to populate FrameDescription::registers_).
// Leave gaps for other registers.
@@ -64,7 +58,7 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ StoreP(fp, MemOperand(scratch));
}
const int kSavedRegistersAreaSize =
- (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize + kFloatRegsSize;
+ (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
// Get the bailout id is passed as r29 by the caller.
__ mr(r5, r29);
@@ -114,21 +108,10 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
int code = config->GetAllocatableDoubleCode(i);
int dst_offset = code * kDoubleSize + double_regs_offset;
- int src_offset =
- code * kDoubleSize + kNumberOfRegisters * kPointerSize + kFloatRegsSize;
+ int src_offset = code * kDoubleSize + kNumberOfRegisters * kPointerSize;
__ lfd(d0, MemOperand(sp, src_offset));
__ stfd(d0, MemOperand(r4, dst_offset));
}
- int float_regs_offset = FrameDescription::float_registers_offset();
- // Copy float registers to
- // float_registers_[FloatRegister::kNumRegisters]
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- int dst_offset = code * kFloatSize + float_regs_offset;
- int src_offset = code * kFloatSize + kNumberOfRegisters * kPointerSize;
- __ lfs(d0, MemOperand(sp, src_offset));
- __ stfs(d0, MemOperand(r4, dst_offset));
- }
// Remove the saved registers from the stack.
__ addi(sp, sp, Operand(kSavedRegistersAreaSize));
@@ -236,7 +219,10 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ stop();
}
-bool Deoptimizer::PadTopOfStackRegister() { return false; }
+Float32 RegisterValues::GetFloatRegister(unsigned n) const {
+ float float_val = static_cast<float>(double_registers_[n].get_scalar());
+ return Float32::FromBits(bit_cast<uint32_t>(float_val));
+}
void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
SetFrameSlot(offset, value);
diff --git a/deps/v8/src/deoptimizer/s390/deoptimizer-s390.cc b/deps/v8/src/deoptimizer/s390/deoptimizer-s390.cc
index 6da740b0e5..616a57ba0e 100644
--- a/deps/v8/src/deoptimizer/s390/deoptimizer-s390.cc
+++ b/deps/v8/src/deoptimizer/s390/deoptimizer-s390.cc
@@ -10,6 +10,9 @@
namespace v8 {
namespace internal {
+const bool Deoptimizer::kSupportsFixedDeoptExitSize = false;
+const int Deoptimizer::kDeoptExitSize = 0;
+
#define __ masm->
// This code tries to be close to ia32 code so that any changes can be
@@ -25,7 +28,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
RegList restored_regs = kJSCallerSaved | kCalleeSaved;
const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kNumRegisters;
- const int kFloatRegsSize = kFloatSize * FloatRegister::kNumRegisters;
// Save all double registers before messing with them.
__ lay(sp, MemOperand(sp, -kDoubleRegsSize));
@@ -36,14 +38,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
int offset = code * kDoubleSize;
__ StoreDouble(dreg, MemOperand(sp, offset));
}
- // Save all float registers before messing with them.
- __ lay(sp, MemOperand(sp, -kFloatRegsSize));
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- const FloatRegister dreg = FloatRegister::from_code(code);
- int offset = code * kFloatSize;
- __ StoreFloat32(dreg, MemOperand(sp, offset));
- }
// Push all GPRs onto the stack
__ lay(sp, MemOperand(sp, -kNumberOfRegisters * kPointerSize));
@@ -54,7 +48,7 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ StoreP(fp, MemOperand(r1));
const int kSavedRegistersAreaSize =
- (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize + kFloatRegsSize;
+ (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
// The bailout id is passed using r10
__ LoadRR(r4, r10);
@@ -116,25 +110,12 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
int code = config->GetAllocatableDoubleCode(i);
int dst_offset = code * kDoubleSize + double_regs_offset;
- int src_offset =
- code * kDoubleSize + kNumberOfRegisters * kPointerSize + kFloatRegsSize;
+ int src_offset = code * kDoubleSize + kNumberOfRegisters * kPointerSize;
// TODO(joransiu): MVC opportunity
__ LoadDouble(d0, MemOperand(sp, src_offset));
__ StoreDouble(d0, MemOperand(r3, dst_offset));
}
- int float_regs_offset = FrameDescription::float_registers_offset();
- // Copy float registers to
- // float_registers_[FloatRegister::kNumRegisters]
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- int dst_offset = code * kFloatSize + float_regs_offset;
- int src_offset = code * kFloatSize + kNumberOfRegisters * kPointerSize;
- // TODO(joransiu): MVC opportunity
- __ LoadFloat32(d0, MemOperand(sp, src_offset));
- __ StoreFloat32(d0, MemOperand(r3, dst_offset));
- }
-
// Remove the saved registers from the stack.
__ la(sp, MemOperand(sp, kSavedRegistersAreaSize));
@@ -231,7 +212,10 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ stop();
}
-bool Deoptimizer::PadTopOfStackRegister() { return false; }
+Float32 RegisterValues::GetFloatRegister(unsigned n) const {
+ return Float32::FromBits(
+ static_cast<uint32_t>(double_registers_[n].get_bits() >> 32));
+}
void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
SetFrameSlot(offset, value);
diff --git a/deps/v8/src/deoptimizer/x64/deoptimizer-x64.cc b/deps/v8/src/deoptimizer/x64/deoptimizer-x64.cc
index cfdd6c9ef1..29c81f195c 100644
--- a/deps/v8/src/deoptimizer/x64/deoptimizer-x64.cc
+++ b/deps/v8/src/deoptimizer/x64/deoptimizer-x64.cc
@@ -13,6 +13,9 @@
namespace v8 {
namespace internal {
+const bool Deoptimizer::kSupportsFixedDeoptExitSize = false;
+const int Deoptimizer::kDeoptExitSize = 0;
+
#define __ masm->
void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
@@ -34,16 +37,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ Movsd(Operand(rsp, offset), xmm_reg);
}
- const int kFloatRegsSize = kFloatSize * XMMRegister::kNumRegisters;
- __ AllocateStackSpace(kFloatRegsSize);
-
- for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
- int code = config->GetAllocatableFloatCode(i);
- XMMRegister xmm_reg = XMMRegister::from_code(code);
- int offset = code * kFloatSize;
- __ Movss(Operand(rsp, offset), xmm_reg);
- }
-
// We push all registers onto the stack, even though we do not need
// to restore all later.
for (int i = 0; i < kNumberOfRegisters; i++) {
@@ -51,8 +44,8 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ pushq(r);
}
- const int kSavedRegistersAreaSize = kNumberOfRegisters * kSystemPointerSize +
- kDoubleRegsSize + kFloatRegsSize;
+ const int kSavedRegistersAreaSize =
+ kNumberOfRegisters * kSystemPointerSize + kDoubleRegsSize;
__ Store(
ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate),
@@ -112,16 +105,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ PopQuad(Operand(rbx, offset));
}
- // Fill in the float input registers.
- int float_regs_offset = FrameDescription::float_registers_offset();
- for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
- int src_offset = i * kFloatSize;
- int dst_offset = i * kFloatSize + float_regs_offset;
- __ movl(rcx, Operand(rsp, src_offset));
- __ movl(Operand(rbx, dst_offset), rcx);
- }
- __ addq(rsp, Immediate(kFloatRegsSize));
-
// Fill in the double input registers.
int double_regs_offset = FrameDescription::double_registers_offset();
for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
@@ -232,7 +215,10 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
__ ret(0);
}
-bool Deoptimizer::PadTopOfStackRegister() { return false; }
+Float32 RegisterValues::GetFloatRegister(unsigned n) const {
+ return Float32::FromBits(
+ static_cast<uint32_t>(double_registers_[n].get_bits()));
+}
void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
if (kPCOnStackSize == 2 * kSystemPointerSize) {
diff --git a/deps/v8/src/diagnostics/OWNERS b/deps/v8/src/diagnostics/OWNERS
index 852d438bb0..48d72aea5e 100644
--- a/deps/v8/src/diagnostics/OWNERS
+++ b/deps/v8/src/diagnostics/OWNERS
@@ -1 +1 @@
-file://COMMON_OWNERS
+file:../../COMMON_OWNERS
diff --git a/deps/v8/src/diagnostics/arm64/disasm-arm64.cc b/deps/v8/src/diagnostics/arm64/disasm-arm64.cc
index e51986ee4c..7141cdf283 100644
--- a/deps/v8/src/diagnostics/arm64/disasm-arm64.cc
+++ b/deps/v8/src/diagnostics/arm64/disasm-arm64.cc
@@ -1417,14 +1417,33 @@ void DisassemblingDecoder::VisitFPFixedPointConvert(Instruction* instr) {
Format(instr, mnemonic, form);
}
+// clang-format off
+#define PAUTH_SYSTEM_MNEMONICS(V) \
+ V(PACIA1716, "pacia1716") \
+ V(AUTIA1716, "autia1716") \
+ V(PACIASP, "paciasp") \
+ V(AUTIASP, "autiasp")
+// clang-format on
+
void DisassemblingDecoder::VisitSystem(Instruction* instr) {
// Some system instructions hijack their Op and Cp fields to represent a
// range of immediates instead of indicating a different instruction. This
// makes the decoding tricky.
const char* mnemonic = "unimplemented";
const char* form = "(System)";
+ if (instr->Mask(SystemPAuthFMask) == SystemPAuthFixed) {
+ switch (instr->Mask(SystemPAuthMask)) {
+#define PAUTH_CASE(NAME, MN) \
+ case NAME: \
+ mnemonic = MN; \
+ form = NULL; \
+ break;
- if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
+ PAUTH_SYSTEM_MNEMONICS(PAUTH_CASE)
+#undef PAUTH_CASE
+#undef PAUTH_SYSTEM_MNEMONICS
+ }
+ } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
switch (instr->Mask(SystemSysRegMask)) {
case MRS: {
mnemonic = "mrs";
diff --git a/deps/v8/src/diagnostics/objects-debug.cc b/deps/v8/src/diagnostics/objects-debug.cc
index dc3b3b8091..6860ead022 100644
--- a/deps/v8/src/diagnostics/objects-debug.cc
+++ b/deps/v8/src/diagnostics/objects-debug.cc
@@ -164,9 +164,6 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) {
case HEAP_NUMBER_TYPE:
CHECK(IsHeapNumber());
break;
- case MUTABLE_HEAP_NUMBER_TYPE:
- CHECK(IsMutableHeapNumber());
- break;
case BIGINT_TYPE:
BigInt::cast(*this).BigIntVerify(isolate);
break;
@@ -582,7 +579,7 @@ void JSObject::JSObjectVerify(Isolate* isolate) {
// There are two reasons why this can happen:
// - in the middle of StoreTransitionStub when the new extended backing
// store is already set into the object and the allocation of the
- // MutableHeapNumber triggers GC while the map isn't updated yet.
+ // HeapNumber triggers GC while the map isn't updated yet.
// - deletion of the last property can leave additional backing store
// capacity behind.
CHECK_GT(actual_unused_property_fields, map().UnusedPropertyFields());
@@ -607,7 +604,7 @@ void JSObject::JSObjectVerify(Isolate* isolate) {
VerifyObjectField(isolate, index.offset());
}
Object value = RawFastPropertyAt(index);
- if (r.IsDouble()) DCHECK(value.IsMutableHeapNumber());
+ if (r.IsDouble()) DCHECK(value.IsHeapNumber());
if (value.IsUninitialized(isolate)) continue;
if (r.IsSmi()) DCHECK(value.IsSmi());
if (r.IsHeapObject()) DCHECK(value.IsHeapObject());
@@ -638,7 +635,7 @@ void JSObject::JSObjectVerify(Isolate* isolate) {
// pointer may point to a one pointer filler map.
if (ElementsAreSafeToExamine(isolate)) {
CHECK_EQ((map().has_fast_smi_or_object_elements() ||
- map().has_frozen_or_sealed_elements() ||
+ map().has_any_nonextensible_elements() ||
(elements() == GetReadOnlyRoots().empty_fixed_array()) ||
HasFastStringWrapperElements()),
(elements().map() == GetReadOnlyRoots().fixed_array_map() ||
@@ -681,7 +678,7 @@ void Map::MapVerify(Isolate* isolate) {
CHECK_IMPLIES(IsJSObjectMap() && !CanHaveFastTransitionableElementsKind(),
IsDictionaryElementsKind(elements_kind()) ||
IsTerminalElementsKind(elements_kind()) ||
- IsHoleyFrozenOrSealedElementsKind(elements_kind()));
+ IsAnyHoleyNonextensibleElementsKind(elements_kind()));
CHECK_IMPLIES(is_deprecated(), !is_stable());
if (is_prototype_map()) {
DCHECK(prototype_info() == Smi::kZero ||
@@ -699,8 +696,6 @@ void Map::DictionaryMapVerify(Isolate* isolate) {
CHECK_EQ(Map::GetVisitorId(*this), visitor_id());
}
-USE_TORQUE_VERIFIER(AliasedArgumentsEntry)
-
void EmbedderDataArray::EmbedderDataArrayVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::EmbedderDataArrayVerify(*this, isolate);
EmbedderDataSlot start(*this, 0);
@@ -770,7 +765,7 @@ void Context::ContextVerify(Isolate* isolate) {
void NativeContext::NativeContextVerify(Isolate* isolate) {
ContextVerify(isolate);
CHECK_EQ(length(), NativeContext::NATIVE_CONTEXT_SLOTS);
- CHECK_EQ(kSize, map().instance_size());
+ CHECK_EQ(kVariableSizeSentinel, map().instance_size());
}
void FeedbackMetadata::FeedbackMetadataVerify(Isolate* isolate) {
@@ -914,8 +909,6 @@ void SloppyArgumentsElements::SloppyArgumentsElementsVerify(Isolate* isolate,
CHECK_LE(maxMappedIndex, arg_elements.length());
}
-USE_TORQUE_VERIFIER(JSGeneratorObject)
-
void JSAsyncFunctionObject::JSAsyncFunctionObjectVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSAsyncFunctionObjectVerify(*this, isolate);
promise().HeapObjectVerify(isolate);
@@ -1140,8 +1133,6 @@ void Oddball::OddballVerify(Isolate* isolate) {
}
}
-USE_TORQUE_VERIFIER(Cell)
-
USE_TORQUE_VERIFIER(PropertyCell)
void CodeDataContainer::CodeDataContainerVerify(Isolate* isolate) {
@@ -1185,10 +1176,11 @@ void JSArray::JSArrayVerify(Isolate* isolate) {
CHECK_EQ(elements(), ReadOnlyRoots(isolate).empty_fixed_array());
}
// Verify that the length and the elements backing store are in sync.
- if (length().IsSmi() && (HasFastElements() || HasFrozenOrSealedElements())) {
+ if (length().IsSmi() &&
+ (HasFastElements() || HasAnyNonextensibleElements())) {
if (elements().length() > 0) {
CHECK_IMPLIES(HasDoubleElements(), elements().IsFixedDoubleArray());
- CHECK_IMPLIES(HasSmiOrObjectElements() || HasFrozenOrSealedElements(),
+ CHECK_IMPLIES(HasSmiOrObjectElements() || HasAnyNonextensibleElements(),
elements().IsFixedArray());
}
int size = Smi::ToInt(length());
@@ -1215,8 +1207,6 @@ void JSArray::JSArrayVerify(Isolate* isolate) {
}
}
-USE_TORQUE_VERIFIER(JSCollection)
-
void JSSet::JSSetVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSSetVerify(*this, isolate);
CHECK(table().IsOrderedHashSet() || table().IsUndefined(isolate));
@@ -1229,8 +1219,6 @@ void JSMap::JSMapVerify(Isolate* isolate) {
// TODO(arv): Verify OrderedHashTable too.
}
-USE_TORQUE_VERIFIER(JSCollectionIterator)
-
void JSSetIterator::JSSetIteratorVerify(Isolate* isolate) {
CHECK(IsJSSetIterator());
JSCollectionIteratorVerify(isolate);
@@ -1301,12 +1289,6 @@ void JSFinalizationGroupCleanupIterator::
VerifyHeapPointer(isolate, finalization_group());
}
-void FinalizationGroupCleanupJobTask::FinalizationGroupCleanupJobTaskVerify(
- Isolate* isolate) {
- CHECK(IsFinalizationGroupCleanupJobTask());
- CHECK(finalization_group().IsJSFinalizationGroup());
-}
-
void JSWeakMap::JSWeakMapVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSWeakMapVerify(*this, isolate);
CHECK(table().IsEphemeronHashTable() || table().IsUndefined(isolate));
@@ -1334,36 +1316,16 @@ void JSStringIterator::JSStringIteratorVerify(Isolate* isolate) {
CHECK_LE(index(), String::kMaxLength);
}
-USE_TORQUE_VERIFIER(JSAsyncFromSyncIterator)
-
-USE_TORQUE_VERIFIER(JSWeakCollection)
-
void JSWeakSet::JSWeakSetVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSWeakSetVerify(*this, isolate);
CHECK(table().IsEphemeronHashTable() || table().IsUndefined(isolate));
}
-USE_TORQUE_VERIFIER(Microtask)
-
void CallableTask::CallableTaskVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::CallableTaskVerify(*this, isolate);
CHECK(callable().IsCallable());
}
-USE_TORQUE_VERIFIER(CallbackTask)
-
-USE_TORQUE_VERIFIER(PromiseReactionJobTask)
-
-USE_TORQUE_VERIFIER(PromiseFulfillReactionJobTask)
-
-USE_TORQUE_VERIFIER(PromiseRejectReactionJobTask)
-
-USE_TORQUE_VERIFIER(PromiseResolveThenableJobTask)
-
-USE_TORQUE_VERIFIER(PromiseCapability)
-
-USE_TORQUE_VERIFIER(PromiseReaction)
-
void JSPromise::JSPromiseVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSPromiseVerify(*this, isolate);
if (status() == Promise::kPending) {
@@ -1456,22 +1418,38 @@ void JSRegExp::JSRegExpVerify(Isolate* isolate) {
break;
}
case JSRegExp::IRREGEXP: {
- bool is_native = RegExp::GeneratesNativeCode();
+ bool can_be_interpreted = RegExp::CanGenerateBytecode();
FixedArray arr = FixedArray::cast(data());
Object one_byte_data = arr.get(JSRegExp::kIrregexpLatin1CodeIndex);
// Smi : Not compiled yet (-1).
- // Code/ByteArray: Compiled code.
+ // Code: Compiled irregexp code or trampoline to the interpreter.
CHECK((one_byte_data.IsSmi() &&
Smi::ToInt(one_byte_data) == JSRegExp::kUninitializedValue) ||
- (is_native ? one_byte_data.IsCode() : one_byte_data.IsByteArray()));
+ one_byte_data.IsCode());
Object uc16_data = arr.get(JSRegExp::kIrregexpUC16CodeIndex);
CHECK((uc16_data.IsSmi() &&
Smi::ToInt(uc16_data) == JSRegExp::kUninitializedValue) ||
- (is_native ? uc16_data.IsCode() : uc16_data.IsByteArray()));
+ uc16_data.IsCode());
+
+ Object one_byte_bytecode =
+ arr.get(JSRegExp::kIrregexpLatin1BytecodeIndex);
+ // Smi : Not compiled yet (-1).
+ // ByteArray: Bytecode to interpret regexp.
+ CHECK((one_byte_bytecode.IsSmi() &&
+ Smi::ToInt(one_byte_bytecode) == JSRegExp::kUninitializedValue) ||
+ (can_be_interpreted && one_byte_bytecode.IsByteArray()));
+ Object uc16_bytecode = arr.get(JSRegExp::kIrregexpUC16BytecodeIndex);
+ CHECK((uc16_bytecode.IsSmi() &&
+ Smi::ToInt(uc16_bytecode) == JSRegExp::kUninitializedValue) ||
+ (can_be_interpreted && uc16_bytecode.IsByteArray()));
+
+ CHECK_IMPLIES(one_byte_data.IsSmi(), one_byte_bytecode.IsSmi());
+ CHECK_IMPLIES(uc16_data.IsSmi(), uc16_bytecode.IsSmi());
CHECK(arr.get(JSRegExp::kIrregexpCaptureCountIndex).IsSmi());
CHECK(arr.get(JSRegExp::kIrregexpMaxRegisterCountIndex).IsSmi());
+ CHECK(arr.get(JSRegExp::kIrregexpTierUpTicksIndex).IsSmi());
break;
}
default:
@@ -1481,8 +1459,6 @@ void JSRegExp::JSRegExpVerify(Isolate* isolate) {
}
}
-USE_TORQUE_VERIFIER(JSRegExpStringIterator)
-
void JSProxy::JSProxyVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSProxyVerify(*this, isolate);
CHECK(map().GetConstructor().IsJSFunction());
@@ -1540,8 +1516,6 @@ void BigInt::BigIntVerify(Isolate* isolate) {
CHECK_IMPLIES(is_zero(), !sign()); // There is no -0n.
}
-USE_TORQUE_VERIFIER(JSModuleNamespace)
-
void SourceTextModuleInfoEntry::SourceTextModuleInfoEntryVerify(
Isolate* isolate) {
TorqueGeneratedClassVerifiers::SourceTextModuleInfoEntryVerify(*this,
@@ -1626,8 +1600,6 @@ void PrototypeUsers::Verify(WeakArrayList array) {
CHECK_EQ(weak_maps_count + empty_slots_count + 1, array.length());
}
-USE_TORQUE_VERIFIER(TemplateObjectDescription)
-
void EnumCache::EnumCacheVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::EnumCacheVerify(*this, isolate);
Heap* heap = isolate->heap();
@@ -1637,8 +1609,6 @@ void EnumCache::EnumCacheVerify(Isolate* isolate) {
}
}
-USE_TORQUE_VERIFIER(ClassPositions)
-
void ObjectBoilerplateDescription::ObjectBoilerplateDescriptionVerify(
Isolate* isolate) {
CHECK(IsObjectBoilerplateDescription());
@@ -1647,14 +1617,10 @@ void ObjectBoilerplateDescription::ObjectBoilerplateDescriptionVerify(
this->FixedArrayVerify(isolate);
}
-USE_TORQUE_VERIFIER(ArrayBoilerplateDescription)
-
USE_TORQUE_VERIFIER(AsmWasmData)
USE_TORQUE_VERIFIER(WasmDebugInfo)
-USE_TORQUE_VERIFIER(WasmExceptionTag)
-
void WasmInstanceObject::WasmInstanceObjectVerify(Isolate* isolate) {
JSObjectVerify(isolate);
CHECK(IsWasmInstanceObject());
@@ -1715,8 +1681,6 @@ USE_TORQUE_VERIFIER(AccessorInfo)
USE_TORQUE_VERIFIER(AccessorPair)
-USE_TORQUE_VERIFIER(AccessCheckInfo)
-
void CallHandlerInfo::CallHandlerInfoVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::CallHandlerInfoVerify(*this, isolate);
CHECK(map() == ReadOnlyRoots(isolate).side_effect_call_handler_info_map() ||
@@ -1726,22 +1690,12 @@ void CallHandlerInfo::CallHandlerInfoVerify(Isolate* isolate) {
.next_call_side_effect_free_call_handler_info_map());
}
-USE_TORQUE_VERIFIER(InterceptorInfo)
-
-USE_TORQUE_VERIFIER(TemplateInfo)
-
-USE_TORQUE_VERIFIER(FunctionTemplateInfo)
-
-USE_TORQUE_VERIFIER(FunctionTemplateRareData)
-
USE_TORQUE_VERIFIER(WasmCapiFunctionData)
USE_TORQUE_VERIFIER(WasmJSFunctionData)
USE_TORQUE_VERIFIER(WasmIndirectFunctionTable)
-USE_TORQUE_VERIFIER(ObjectTemplateInfo)
-
void AllocationSite::AllocationSiteVerify(Isolate* isolate) {
CHECK(IsAllocationSite());
CHECK(dependent_code().IsDependentCode());
@@ -1781,8 +1735,6 @@ void NormalizedMapCache::NormalizedMapCacheVerify(Isolate* isolate) {
USE_TORQUE_VERIFIER(DebugInfo)
-USE_TORQUE_VERIFIER(StackTraceFrame)
-
USE_TORQUE_VERIFIER(StackFrameInfo)
void PreparseData::PreparseDataVerify(Isolate* isolate) {
@@ -1868,9 +1820,11 @@ void JSObject::IncrementSpillStatistics(Isolate* isolate,
case HOLEY_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS: {
info->number_of_objects_with_fast_elements_++;
int holes = 0;
diff --git a/deps/v8/src/diagnostics/objects-printer.cc b/deps/v8/src/diagnostics/objects-printer.cc
index 5284208285..39614091c7 100644
--- a/deps/v8/src/diagnostics/objects-printer.cc
+++ b/deps/v8/src/diagnostics/objects-printer.cc
@@ -130,11 +130,6 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
HeapNumber::cast(*this).HeapNumberPrint(os);
os << "\n";
break;
- case MUTABLE_HEAP_NUMBER_TYPE:
- os << "<mutable ";
- MutableHeapNumber::cast(*this).MutableHeapNumberPrint(os);
- os << ">\n";
- break;
case BIGINT_TYPE:
BigInt::cast(*this).BigIntPrint(os);
os << "\n";
@@ -683,9 +678,11 @@ void JSObject::PrintElements(std::ostream& os) { // NOLINT
case HOLEY_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS: {
PrintFixedArrayElements(os, FixedArray::cast(elements()));
break;
@@ -868,8 +865,8 @@ void JSRegExp::JSRegExpPrint(std::ostream& os) { // NOLINT
void JSRegExpStringIterator::JSRegExpStringIteratorPrint(
std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, *this, "JSRegExpStringIterator");
- os << "\n - regex: " << Brief(iterating_regexp());
- os << "\n - string: " << Brief(iterating_string());
+ os << "\n - regex: " << Brief(iterating_reg_exp());
+ os << "\n - string: " << Brief(iterated_string());
os << "\n - done: " << done();
os << "\n - global: " << global();
os << "\n - unicode: " << unicode();
@@ -1340,7 +1337,17 @@ void JSFinalizationGroup::JSFinalizationGroupPrint(std::ostream& os) {
os << "\n - native_context: " << Brief(native_context());
os << "\n - cleanup: " << Brief(cleanup());
os << "\n - active_cells: " << Brief(active_cells());
+ Object active_cell = active_cells();
+ while (active_cell.IsWeakCell()) {
+ os << "\n - " << Brief(active_cell);
+ active_cell = WeakCell::cast(active_cell).next();
+ }
os << "\n - cleared_cells: " << Brief(cleared_cells());
+ Object cleared_cell = cleared_cells();
+ while (cleared_cell.IsWeakCell()) {
+ os << "\n - " << Brief(cleared_cell);
+ cleared_cell = WeakCell::cast(cleared_cell).next();
+ }
os << "\n - key_map: " << Brief(key_map());
JSObjectPrintBody(os, *this);
}
@@ -1352,12 +1359,6 @@ void JSFinalizationGroupCleanupIterator::
JSObjectPrintBody(os, *this);
}
-void FinalizationGroupCleanupJobTask::FinalizationGroupCleanupJobTaskPrint(
- std::ostream& os) {
- PrintHeader(os, "FinalizationGroupCleanupJobTask");
- os << "\n - finalization_group: " << Brief(finalization_group());
-}
-
void JSWeakMap::JSWeakMapPrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, *this, "JSWeakMap");
os << "\n - table: " << Brief(table());
@@ -1466,13 +1467,16 @@ void JSFunction::JSFunctionPrint(std::ostream& os) { // NOLINT
}
if (WasmExportedFunction::IsWasmExportedFunction(*this)) {
WasmExportedFunction function = WasmExportedFunction::cast(*this);
- os << "\n - WASM instance "
- << reinterpret_cast<void*>(function.instance().ptr());
- os << "\n - WASM function index " << function.function_index();
+ os << "\n - WASM instance: " << Brief(function.instance());
+ os << "\n - WASM function index: " << function.function_index();
+ }
+ if (WasmJSFunction::IsWasmJSFunction(*this)) {
+ WasmJSFunction function = WasmJSFunction::cast(*this);
+ os << "\n - WASM wrapper around: " << Brief(function.GetCallable());
}
shared().PrintSourceCode(os);
JSObjectPrintBody(os, *this);
- os << "\n - feedback vector: ";
+ os << " - feedback vector: ";
if (!shared().HasFeedbackMetadata()) {
os << "feedback metadata is not available in SFI\n";
} else if (has_feedback_vector()) {
@@ -1506,6 +1510,7 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { // NOLINT
os << "\n - inferred name: " << Brief(inferred_name());
}
os << "\n - kind: " << kind();
+ os << "\n - syntax kind: " << syntax_kind();
if (needs_home_object()) {
os << "\n - needs_home_object";
}
@@ -1522,13 +1527,6 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { // NOLINT
// Script files are often large, hard to read.
// os << "\n - script =";
// script()->Print(os);
- if (is_named_expression()) {
- os << "\n - named expression";
- } else if (is_anonymous_expression()) {
- os << "\n - anonymous expression";
- } else if (is_declaration()) {
- os << "\n - declaration";
- }
os << "\n - function token position: " << function_token_position();
os << "\n - start position: " << StartPosition();
os << "\n - end position: " << EndPosition();
@@ -2065,7 +2063,7 @@ void WasmCapiFunctionData::WasmCapiFunctionDataPrint(
std::ostream& os) { // NOLINT
PrintHeader(os, "WasmCapiFunctionData");
os << "\n - call_target: " << call_target();
- os << "\n - embedder_data: " << embedder_data();
+ os << "\n - embedder_data: " << Brief(embedder_data());
os << "\n - wrapper_code: " << Brief(wrapper_code());
os << "\n - serialized_signature: " << Brief(serialized_signature());
os << "\n";
@@ -2275,7 +2273,7 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { // NOLINT
os << "\n - context locals : " << ContextLocalCount();
os << "\n - scope type: " << scope_type();
- if (CallsSloppyEval()) os << "\n - sloppy eval";
+ if (SloppyEvalCanExtendVars()) os << "\n - sloppy eval";
os << "\n - language mode: " << language_mode();
if (is_declaration_scope()) os << "\n - declaration scope";
if (HasReceiver()) {
@@ -2460,10 +2458,6 @@ void TaggedImpl<kRefType, StorageType>::Print(std::ostream& os) {
void HeapNumber::HeapNumberPrint(std::ostream& os) { os << value(); }
-void MutableHeapNumber::MutableHeapNumberPrint(std::ostream& os) {
- os << value();
-}
-
// TODO(cbruni): remove once the new maptracer is in place.
void Name::NameShortPrint() {
if (this->IsString()) {
diff --git a/deps/v8/src/diagnostics/perf-jit.cc b/deps/v8/src/diagnostics/perf-jit.cc
index 57133964b0..d84c2e4f53 100644
--- a/deps/v8/src/diagnostics/perf-jit.cc
+++ b/deps/v8/src/diagnostics/perf-jit.cc
@@ -243,6 +243,10 @@ void PerfJitLogger::LogRecordedBuffer(const wasm::WasmCode* code,
if (perf_output_handle_ == nullptr) return;
+ if (FLAG_perf_prof_annotate_wasm) {
+ LogWriteDebugInfo(code);
+ }
+
WriteJitCodeLoadEntry(code->instructions().begin(),
code->instructions().length(), name, length);
}
@@ -387,6 +391,73 @@ void PerfJitLogger::LogWriteDebugInfo(Code code, SharedFunctionInfo shared) {
LogWriteBytes(padding_bytes, padding);
}
+void PerfJitLogger::LogWriteDebugInfo(const wasm::WasmCode* code) {
+ wasm::WasmModuleSourceMap* source_map =
+ code->native_module()->GetWasmSourceMap();
+ wasm::WireBytesRef code_ref =
+ code->native_module()->module()->functions[code->index()].code;
+ uint32_t code_offset = code_ref.offset();
+ uint32_t code_end_offset = code_ref.end_offset();
+
+ uint32_t entry_count = 0;
+ uint32_t size = 0;
+
+ if (!source_map || !source_map->IsValid() ||
+ !source_map->HasSource(code_offset, code_end_offset)) {
+ return;
+ }
+
+ for (SourcePositionTableIterator iterator(code->source_positions());
+ !iterator.done(); iterator.Advance()) {
+ uint32_t offset = iterator.source_position().ScriptOffset() + code_offset;
+ if (!source_map->HasValidEntry(code_offset, offset)) continue;
+ entry_count++;
+ size += source_map->GetFilename(offset).size() + 1;
+ }
+
+ if (entry_count == 0) return;
+
+ PerfJitCodeDebugInfo debug_info;
+
+ debug_info.event_ = PerfJitCodeLoad::kDebugInfo;
+ debug_info.time_stamp_ = GetTimestamp();
+ debug_info.address_ =
+ reinterpret_cast<uintptr_t>(code->instructions().begin());
+ debug_info.entry_count_ = entry_count;
+
+ size += sizeof(debug_info);
+ // Add the sizes of fixed parts of entries.
+ size += entry_count * sizeof(PerfJitDebugEntry);
+
+ int padding = ((size + 7) & (~7)) - size;
+ debug_info.size_ = size + padding;
+ LogWriteBytes(reinterpret_cast<const char*>(&debug_info), sizeof(debug_info));
+
+ uintptr_t code_begin =
+ reinterpret_cast<uintptr_t>(code->instructions().begin());
+
+ for (SourcePositionTableIterator iterator(code->source_positions());
+ !iterator.done(); iterator.Advance()) {
+ uint32_t offset = iterator.source_position().ScriptOffset() + code_offset;
+ if (!source_map->HasValidEntry(code_offset, offset)) continue;
+ PerfJitDebugEntry entry;
+ // The entry point of the function will be placed straight after the ELF
+ // header when processed by "perf inject". Adjust the position addresses
+ // accordingly.
+ entry.address_ = code_begin + iterator.code_offset() + kElfHeaderSize;
+ entry.line_number_ =
+ static_cast<int>(source_map->GetSourceLine(offset)) + 1;
+ entry.column_ = 1;
+ LogWriteBytes(reinterpret_cast<const char*>(&entry), sizeof(entry));
+ std::string name_string = source_map->GetFilename(offset);
+ LogWriteBytes(name_string.c_str(),
+ static_cast<int>(name_string.size() + 1));
+ }
+
+ char padding_bytes[8] = {0};
+ LogWriteBytes(padding_bytes, padding);
+}
+
void PerfJitLogger::LogWriteUnwindingInfo(Code code) {
PerfJitCodeUnwindingInfo unwinding_info_header;
unwinding_info_header.event_ = PerfJitCodeLoad::kUnwindingInfo;
diff --git a/deps/v8/src/diagnostics/perf-jit.h b/deps/v8/src/diagnostics/perf-jit.h
index 492a550976..36ab844110 100644
--- a/deps/v8/src/diagnostics/perf-jit.h
+++ b/deps/v8/src/diagnostics/perf-jit.h
@@ -71,6 +71,7 @@ class PerfJitLogger : public CodeEventLogger {
void LogWriteBytes(const char* bytes, int size);
void LogWriteHeader();
void LogWriteDebugInfo(Code code, SharedFunctionInfo shared);
+ void LogWriteDebugInfo(const wasm::WasmCode* code);
void LogWriteUnwindingInfo(Code code);
static const uint32_t kElfMachIA32 = 3;
diff --git a/deps/v8/src/diagnostics/unwinding-info-win64.cc b/deps/v8/src/diagnostics/unwinding-info-win64.cc
index 096ffa2d48..6cc53da51f 100644
--- a/deps/v8/src/diagnostics/unwinding-info-win64.cc
+++ b/deps/v8/src/diagnostics/unwinding-info-win64.cc
@@ -4,42 +4,17 @@
#include "src/diagnostics/unwinding-info-win64.h"
-#if defined(V8_OS_WIN_X64)
-
#include "src/codegen/macro-assembler.h"
-#include "src/codegen/x64/assembler-x64.h"
#include "src/utils/allocation.h"
-// Forward declaration to keep this independent of Win8
-NTSYSAPI
-DWORD
-NTAPI
-RtlAddGrowableFunctionTable(
- _Out_ PVOID* DynamicTable,
- _In_reads_(MaximumEntryCount) PRUNTIME_FUNCTION FunctionTable,
- _In_ DWORD EntryCount,
- _In_ DWORD MaximumEntryCount,
- _In_ ULONG_PTR RangeBase,
- _In_ ULONG_PTR RangeEnd
- );
-
-
-NTSYSAPI
-void
-NTAPI
-RtlGrowFunctionTable(
- _Inout_ PVOID DynamicTable,
- _In_ DWORD NewEntryCount
- );
-
-
-NTSYSAPI
-void
-NTAPI
-RtlDeleteGrowableFunctionTable(
- _In_ PVOID DynamicTable
- );
-
+#if defined(V8_OS_WIN_X64)
+#include "src/codegen/x64/assembler-x64.h"
+#elif defined(V8_OS_WIN_ARM64)
+#include "src/codegen/arm64/assembler-arm64-inl.h"
+#include "src/codegen/arm64/macro-assembler-arm64-inl.h"
+#else
+#error "Unsupported OS"
+#endif // V8_OS_WIN_X64
namespace v8 {
namespace internal {
@@ -53,9 +28,36 @@ bool CanRegisterUnwindInfoForNonABICompliantCodeRange() {
bool RegisterUnwindInfoForExceptionHandlingOnly() {
DCHECK(CanRegisterUnwindInfoForNonABICompliantCodeRange());
+#if defined(V8_OS_WIN_ARM64)
+ return !FLAG_win64_unwinding_info;
+#else
return !IsWindows8OrGreater() || !FLAG_win64_unwinding_info;
+#endif
+}
+
+v8::UnhandledExceptionCallback unhandled_exception_callback_g = nullptr;
+
+void SetUnhandledExceptionCallback(
+ v8::UnhandledExceptionCallback unhandled_exception_callback) {
+ unhandled_exception_callback_g = unhandled_exception_callback;
+}
+
+// This function is registered as exception handler for V8-generated code as
+// part of the registration of unwinding info. It is referenced by
+// RegisterNonABICompliantCodeRange(), below, and by the unwinding info for
+// builtins declared in the embedded blob.
+extern "C" __declspec(dllexport) int CRASH_HANDLER_FUNCTION_NAME(
+ PEXCEPTION_RECORD ExceptionRecord, ULONG64 EstablisherFrame,
+ PCONTEXT ContextRecord, PDISPATCHER_CONTEXT DispatcherContext) {
+ if (unhandled_exception_callback_g != nullptr) {
+ EXCEPTION_POINTERS info = {ExceptionRecord, ContextRecord};
+ return unhandled_exception_callback_g(&info);
+ }
+ return ExceptionContinueSearch;
}
+#if defined(V8_OS_WIN_X64)
+
#pragma pack(push, 1)
/*
@@ -80,9 +82,12 @@ struct UNWIND_INFO {
unsigned char FrameOffset : 4;
};
+static constexpr int kNumberOfUnwindCodes = 2;
+static constexpr int kMaxExceptionThunkSize = 12;
+
struct V8UnwindData {
UNWIND_INFO unwind_info;
- UNWIND_CODE unwind_codes[2];
+ UNWIND_CODE unwind_codes[kNumberOfUnwindCodes];
V8UnwindData() {
static constexpr int kOpPushNonvol = 0;
@@ -118,46 +123,244 @@ struct ExceptionHandlerUnwindData {
}
};
+struct CodeRangeUnwindingRecord {
+ void* dynamic_table;
+ uint32_t runtime_function_count;
+ V8UnwindData unwind_info;
+ uint32_t exception_handler;
+ uint8_t exception_thunk[kMaxExceptionThunkSize];
+ RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount];
+};
+
+struct ExceptionHandlerRecord {
+ uint32_t runtime_function_count;
+ RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount];
+ ExceptionHandlerUnwindData unwind_info;
+ uint32_t exception_handler;
+ uint8_t exception_thunk[kMaxExceptionThunkSize];
+};
+
#pragma pack(pop)
-v8::UnhandledExceptionCallback unhandled_exception_callback_g = nullptr;
+std::vector<uint8_t> GetUnwindInfoForBuiltinFunctions() {
+ V8UnwindData xdata;
+ return std::vector<uint8_t>(
+ reinterpret_cast<uint8_t*>(&xdata),
+ reinterpret_cast<uint8_t*>(&xdata) + sizeof(xdata));
+}
-void SetUnhandledExceptionCallback(
- v8::UnhandledExceptionCallback unhandled_exception_callback) {
- unhandled_exception_callback_g = unhandled_exception_callback;
+template <typename Record>
+void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) {
+ // We assume that the first page of the code range is executable and
+ // committed and reserved to contain PDATA/XDATA.
+
+ // All addresses are 32bit relative offsets to start.
+ record->runtime_function[0].BeginAddress = 0;
+ record->runtime_function[0].EndAddress =
+ static_cast<DWORD>(code_size_in_bytes);
+ record->runtime_function[0].UnwindData = offsetof(Record, unwind_info);
+ record->runtime_function_count = 1;
+ record->exception_handler = offsetof(Record, exception_thunk);
+
+ // Hardcoded thunk.
+ AssemblerOptions options;
+ options.record_reloc_info_for_serialization = false;
+ MacroAssembler masm(nullptr, options, CodeObjectRequired::kNo,
+ NewAssemblerBuffer(64));
+ masm.movq(rax, reinterpret_cast<uint64_t>(&CRASH_HANDLER_FUNCTION_NAME));
+ masm.jmp(rax);
+ DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk));
+ memcpy(&record->exception_thunk[0], masm.buffer_start(),
+ masm.instruction_size());
}
-// This function is registered as exception handler for V8-generated code as
-// part of the registration of unwinding info. It is referenced by
-// RegisterNonABICompliantCodeRange(), below, and by the unwinding info for
-// builtins declared in the embedded blob.
-extern "C" __declspec(dllexport) int CRASH_HANDLER_FUNCTION_NAME(
- PEXCEPTION_RECORD ExceptionRecord, ULONG64 EstablisherFrame,
- PCONTEXT ContextRecord, PDISPATCHER_CONTEXT DispatcherContext) {
- if (unhandled_exception_callback_g != nullptr) {
- EXCEPTION_POINTERS info = {ExceptionRecord, ContextRecord};
- return unhandled_exception_callback_g(&info);
- }
- return ExceptionContinueSearch;
+#elif defined(V8_OS_WIN_ARM64)
+
+#pragma pack(push, 1)
+
+// ARM64 unwind codes are defined in below doc.
+// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes
+enum UnwindOp8Bit {
+ OpNop = 0xE3,
+ OpSaveFpLr = 0x40,
+ OpSaveFpLrX = 0x80,
+ OpSetFp = 0xE1,
+ OpEnd = 0xE4,
+};
+
+typedef uint32_t UNWIND_CODE;
+
+constexpr UNWIND_CODE Combine8BitUnwindCodes(uint8_t code0,
+ uint8_t code1 = OpNop,
+ uint8_t code2 = OpNop,
+ uint8_t code3 = OpNop) {
+ return static_cast<uint32_t>(code0) | (static_cast<uint32_t>(code1) << 8) |
+ (static_cast<uint32_t>(code2) << 16) |
+ (static_cast<uint32_t>(code3) << 24);
}
-static constexpr int kMaxExceptionThunkSize = 12;
+// UNWIND_INFO defines the static part (first 32-bit) of the .xdata record in
+// below doc.
+// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records
+struct UNWIND_INFO {
+ uint32_t FunctionLength : 18;
+ uint32_t Version : 2;
+ uint32_t X : 1;
+ uint32_t E : 1;
+ uint32_t EpilogCount : 5;
+ uint32_t CodeWords : 5;
+};
+
+static constexpr int kNumberOfUnwindCodes = 1;
+static constexpr int kMaxExceptionThunkSize = 16;
+static constexpr int kFunctionLengthShiftSize = 2;
+static constexpr int kFunctionLengthMask = (1 << kFunctionLengthShiftSize) - 1;
+static constexpr int kFramePointerAdjustmentShiftSize = 3;
+static constexpr int kFramePointerAdjustmentShiftMask =
+ (1 << kFramePointerAdjustmentShiftSize) - 1;
+
+struct V8UnwindData {
+ UNWIND_INFO unwind_info;
+ UNWIND_CODE unwind_codes[kNumberOfUnwindCodes];
+
+ V8UnwindData() {
+ memset(&unwind_info, 0, sizeof(UNWIND_INFO));
+ unwind_info.X = 1; // has exception handler after unwind-codes.
+ unwind_info.CodeWords = 1;
+
+ // stp fp, lr, [sp, #offset]!
+ unwind_codes[0] = Combine8BitUnwindCodes(OpSetFp, OpSaveFpLrX, OpEnd);
+ }
+};
struct CodeRangeUnwindingRecord {
- RUNTIME_FUNCTION runtime_function;
+ void* dynamic_table;
+ uint32_t runtime_function_count;
V8UnwindData unwind_info;
uint32_t exception_handler;
- uint8_t exception_thunk[kMaxExceptionThunkSize];
- void* dynamic_table;
-};
-struct ExceptionHandlerRecord {
- RUNTIME_FUNCTION runtime_function;
- ExceptionHandlerUnwindData unwind_info;
- uint32_t exception_handler;
+ // For Windows ARM64 unwinding, register 2 unwind_info for each code range,
+ // unwind_info for all full size ranges (1MB - 4 bytes) and unwind_info1 for
+ // the remaining non full size range. There is at most 1 range which is less
+ // than full size.
+ V8UnwindData unwind_info1;
+ uint32_t exception_handler1;
uint8_t exception_thunk[kMaxExceptionThunkSize];
+
+ // More RUNTIME_FUNCTION structs could follow below array because the number
+ // of RUNTIME_FUNCTION needed to cover given code range is computed at
+ // runtime.
+ RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount];
};
+#pragma pack(pop)
+
+std::vector<uint8_t> GetUnwindInfoForBuiltinFunction(uint32_t func_len,
+ int32_t fp_adjustment) {
+ DCHECK_LE(func_len, kMaxFunctionLength);
+ DCHECK_EQ((func_len & kFunctionLengthMask), 0);
+ USE(kFunctionLengthMask);
+
+ // Unwind code save_fplr requires the offset to be within range [0, 504].
+ // This range is defined in below doc for unwind code save_fplr.
+ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes
+ DCHECK_GE(fp_adjustment, 0);
+ DCHECK_LE(fp_adjustment, 504);
+ DCHECK_EQ((fp_adjustment & kFramePointerAdjustmentShiftMask), 0);
+ USE(kFramePointerAdjustmentShiftMask);
+
+ V8UnwindData xdata;
+ // FunctionLength is ensured to be aligned at instruction size and Windows
+ // ARM64 doesn't encoding its 2 LSB.
+ xdata.unwind_info.FunctionLength = func_len >> kFunctionLengthShiftSize;
+ xdata.unwind_info.CodeWords = 1;
+ xdata.unwind_codes[0] = Combine8BitUnwindCodes(
+ OpSetFp,
+ (OpSaveFpLr | (fp_adjustment >> kFramePointerAdjustmentShiftSize)),
+ OpEnd);
+
+ return std::vector<uint8_t>(
+ reinterpret_cast<uint8_t*>(&xdata),
+ reinterpret_cast<uint8_t*>(&xdata) + sizeof(xdata));
+}
+
+template <typename Record>
+void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) {
+ // We assume that the first page of the code range is executable and
+ // committed and reserved to contain multiple PDATA/XDATA to cover the whole
+ // range. All addresses are 32bit relative offsets to start.
+
+ // Maximum RUNTIME_FUNCTION count available in reserved memory, this includes
+ // static part in Record as kDefaultRuntimeFunctionCount plus dynamic part in
+ // the remaining reserved memory.
+ constexpr uint32_t max_runtime_function_count = static_cast<uint32_t>(
+ (kOSPageSize - sizeof(Record)) / sizeof(RUNTIME_FUNCTION) +
+ kDefaultRuntimeFunctionCount);
+
+ uint32_t runtime_function_index = 0;
+ uint32_t current_unwind_start_address = 0;
+ int64_t remaining_size_in_bytes = static_cast<int64_t>(code_size_in_bytes);
+
+ // Divide the code range into chunks in size kMaxFunctionLength and create a
+ // RUNTIME_FUNCTION for each of them. All the chunks in the same size can
+ // share 1 unwind_info struct, but a separate unwind_info is needed for the
+ // last chunk if it is smaller than kMaxFunctionLength, because unlike X64,
+ // unwind_info encodes the function/chunk length.
+ while (remaining_size_in_bytes >= kMaxFunctionLength &&
+ runtime_function_index < max_runtime_function_count) {
+ record->runtime_function[runtime_function_index].BeginAddress =
+ current_unwind_start_address;
+ record->runtime_function[runtime_function_index].UnwindData =
+ static_cast<DWORD>(offsetof(Record, unwind_info));
+
+ runtime_function_index++;
+ current_unwind_start_address += kMaxFunctionLength;
+ remaining_size_in_bytes -= kMaxFunctionLength;
+ }
+ // FunctionLength is ensured to be aligned at instruction size and Windows
+ // ARM64 doesn't encoding 2 LSB.
+ record->unwind_info.unwind_info.FunctionLength = kMaxFunctionLength >> 2;
+
+ if (remaining_size_in_bytes > 0 &&
+ runtime_function_index < max_runtime_function_count) {
+ DCHECK_EQ(remaining_size_in_bytes % kInstrSize, 0);
+
+ record->unwind_info1.unwind_info.FunctionLength = static_cast<uint32_t>(
+ remaining_size_in_bytes >> kFunctionLengthShiftSize);
+ record->runtime_function[runtime_function_index].BeginAddress =
+ current_unwind_start_address;
+ record->runtime_function[runtime_function_index].UnwindData =
+ static_cast<DWORD>(offsetof(Record, unwind_info1));
+
+ remaining_size_in_bytes -= kMaxFunctionLength;
+ record->exception_handler1 = offsetof(Record, exception_thunk);
+ record->runtime_function_count = runtime_function_index + 1;
+ } else {
+ record->runtime_function_count = runtime_function_index;
+ }
+
+ // 1 page can cover kMaximalCodeRangeSize for ARM64 (128MB). If
+ // kMaximalCodeRangeSize is changed for ARM64 and makes 1 page insufficient to
+ // cover it, more pages will need to reserved for unwind data.
+ DCHECK_LE(remaining_size_in_bytes, 0);
+
+ record->exception_handler = offsetof(Record, exception_thunk);
+
+ // Hardcoded thunk.
+ AssemblerOptions options;
+ options.record_reloc_info_for_serialization = false;
+ TurboAssembler masm(nullptr, options, CodeObjectRequired::kNo,
+ NewAssemblerBuffer(64));
+ masm.Mov(x16,
+ Operand(reinterpret_cast<uint64_t>(&CRASH_HANDLER_FUNCTION_NAME)));
+ masm.Br(x16);
+ DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk));
+ memcpy(&record->exception_thunk[0], masm.buffer_start(),
+ masm.instruction_size());
+}
+
+#endif // V8_OS_WIN_X64
+
namespace {
V8_DECLARE_ONCE(load_ntdll_unwinding_functions_once);
@@ -216,37 +419,6 @@ void DeleteGrowableFunctionTable(PVOID dynamic_table) {
} // namespace
-std::vector<uint8_t> GetUnwindInfoForBuiltinFunctions() {
- V8UnwindData xdata;
- return std::vector<uint8_t>(
- reinterpret_cast<uint8_t*>(&xdata),
- reinterpret_cast<uint8_t*>(&xdata) + sizeof(xdata));
-}
-
-template <typename Record>
-void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) {
- // We assume that the first page of the code range is executable and
- // committed and reserved to contain PDATA/XDATA.
-
- // All addresses are 32bit relative offsets to start.
- record->runtime_function.BeginAddress = 0;
- record->runtime_function.EndAddress = static_cast<DWORD>(code_size_in_bytes);
- record->runtime_function.UnwindData = offsetof(Record, unwind_info);
-
- record->exception_handler = offsetof(Record, exception_thunk);
-
- // Hardcoded thunk.
- AssemblerOptions options;
- options.record_reloc_info_for_serialization = false;
- MacroAssembler masm(nullptr, options, CodeObjectRequired::kNo,
- NewAssemblerBuffer(64));
- masm.movq(rax, reinterpret_cast<uint64_t>(&CRASH_HANDLER_FUNCTION_NAME));
- masm.jmp(rax);
- DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk));
- memcpy(&record->exception_thunk[0], masm.buffer_start(),
- masm.instruction_size());
-}
-
void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
DCHECK(CanRegisterUnwindInfoForNonABICompliantCodeRange());
@@ -262,24 +434,30 @@ void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
// by the embedder (like Crashpad).
if (RegisterUnwindInfoForExceptionHandlingOnly()) {
+#if defined(V8_OS_WIN_X64)
+ // Windows ARM64 starts since 1709 Windows build, no need to have exception
+ // handling only unwind info for compatibility.
if (unhandled_exception_callback_g) {
ExceptionHandlerRecord* record = new (start) ExceptionHandlerRecord();
InitUnwindingRecord(record, size_in_bytes);
- CHECK(::RtlAddFunctionTable(&record->runtime_function, 1,
+ CHECK(::RtlAddFunctionTable(record->runtime_function,
+ kDefaultRuntimeFunctionCount,
reinterpret_cast<DWORD64>(start)));
// Protect reserved page against modifications.
DWORD old_protect;
- CHECK(VirtualProtect(start, sizeof(CodeRangeUnwindingRecord),
+ CHECK(VirtualProtect(start, sizeof(ExceptionHandlerRecord),
PAGE_EXECUTE_READ, &old_protect));
}
+#endif // V8_OS_WIN_X64
} else {
CodeRangeUnwindingRecord* record = new (start) CodeRangeUnwindingRecord();
InitUnwindingRecord(record, size_in_bytes);
CHECK(AddGrowableFunctionTable(
- &record->dynamic_table, &record->runtime_function, 1, 1,
+ &record->dynamic_table, record->runtime_function,
+ record->runtime_function_count, record->runtime_function_count,
reinterpret_cast<DWORD64>(start),
reinterpret_cast<DWORD64>(reinterpret_cast<uint8_t*>(start) +
size_in_bytes)));
@@ -295,11 +473,15 @@ void UnregisterNonABICompliantCodeRange(void* start) {
DCHECK(CanRegisterUnwindInfoForNonABICompliantCodeRange());
if (RegisterUnwindInfoForExceptionHandlingOnly()) {
+#if defined(V8_OS_WIN_X64)
+ // Windows ARM64 starts since 1709 Windows build, no need to have exception
+ // handling only unwind info for compatibility.
if (unhandled_exception_callback_g) {
ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start);
- CHECK(::RtlDeleteFunctionTable(&record->runtime_function));
+ CHECK(::RtlDeleteFunctionTable(record->runtime_function));
}
+#endif // V8_OS_WIN_X64
} else {
CodeRangeUnwindingRecord* record =
reinterpret_cast<CodeRangeUnwindingRecord*>(start);
@@ -309,19 +491,41 @@ void UnregisterNonABICompliantCodeRange(void* start) {
}
}
+#if defined(V8_OS_WIN_X64)
+
void XdataEncoder::onPushRbp() {
- current_push_rbp_offset_ = assembler_.pc_offset() - kPushRbpInstructionLength;
+ current_frame_code_offset_ =
+ assembler_.pc_offset() - kPushRbpInstructionLength;
}
void XdataEncoder::onMovRbpRsp() {
- if (current_push_rbp_offset_ >= 0 &&
- current_push_rbp_offset_ == assembler_.pc_offset() - kRbpPrefixLength) {
- fp_offsets_.push_back(current_push_rbp_offset_);
+ if (current_frame_code_offset_ >= 0 &&
+ current_frame_code_offset_ == assembler_.pc_offset() - kRbpPrefixLength) {
+ fp_offsets_.push_back(current_frame_code_offset_);
+ }
+}
+
+#elif defined(V8_OS_WIN_ARM64)
+
+void XdataEncoder::onSaveFpLr() {
+ current_frame_code_offset_ = assembler_.pc_offset() - 4;
+ fp_offsets_.push_back(current_frame_code_offset_);
+ fp_adjustments_.push_back(current_frame_adjustment_);
+ if (current_frame_adjustment_ != 0) {
+ current_frame_adjustment_ = 0;
}
}
+void XdataEncoder::onFramePointerAdjustment(int bytes) {
+ // According to below doc, offset for save_fplr is aligned to pointer size.
+ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes
+ DCHECK_EQ((bytes & kPointerAlignmentMask), 0);
+
+ current_frame_adjustment_ = bytes;
+}
+
+#endif // V8_OS_WIN_X64
+
} // namespace win64_unwindinfo
} // namespace internal
} // namespace v8
-
-#endif // defined(V8_OS_WIN_X64)
diff --git a/deps/v8/src/diagnostics/unwinding-info-win64.h b/deps/v8/src/diagnostics/unwinding-info-win64.h
index f6611e7e2e..8f8c9469eb 100644
--- a/deps/v8/src/diagnostics/unwinding-info-win64.h
+++ b/deps/v8/src/diagnostics/unwinding-info-win64.h
@@ -9,7 +9,7 @@
#include "include/v8config.h"
#include "src/common/globals.h"
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
#include "src/base/win32-headers.h"
namespace v8 {
@@ -21,11 +21,7 @@ namespace win64_unwindinfo {
#define CRASH_HANDLER_FUNCTION_NAME_STRING \
"CrashForExceptionInNonABICompliantCodeRange"
-static const int kPushRbpInstructionLength = 1;
-static const int kMovRbpRspInstructionLength = 3;
-static const int kRbpPrefixCodes = 2;
-static const int kRbpPrefixLength =
- kPushRbpInstructionLength + kMovRbpRspInstructionLength;
+static const int kOSPageSize = 4096;
/**
* Returns true if V8 is configured to emit unwinding data for embedded in the
@@ -50,15 +46,33 @@ bool CanRegisterUnwindInfoForNonABICompliantCodeRange();
void SetUnhandledExceptionCallback(
v8::UnhandledExceptionCallback unhandled_exception_callback);
+void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes);
+void UnregisterNonABICompliantCodeRange(void* start);
+
/**
- * Returns a vector of bytes that contains the Win64 unwind data used for all
+ * Default count of RUNTIME_FUNCTION needed. For Windows X64, 1 RUNTIME_FUNCTION
+ * covers 4GB range which is sufficient to cover the whole code range of an
+ * isolate or WASM module. For Windows ARM64, 1 RUNTIME_FUNCTION covers
+ * kMaxFunctionLength bytes so multiple RUNTIME_FUNCTION structs could be needed
+ * to cover the whole code range of an isolate or WASM module. The extra
+ * RUNTIME_FUNCTIONs are assumed following the first one in the reserved page.
+ */
+static const uint32_t kDefaultRuntimeFunctionCount = 1;
+
+#if defined(V8_OS_WIN_X64)
+
+static const int kPushRbpInstructionLength = 1;
+static const int kMovRbpRspInstructionLength = 3;
+static const int kRbpPrefixCodes = 2;
+static const int kRbpPrefixLength =
+ kPushRbpInstructionLength + kMovRbpRspInstructionLength;
+
+/**
+ * Returns a vector of bytes that contains the Win X64 unwind data used for all
* V8 builtin functions.
*/
std::vector<uint8_t> GetUnwindInfoForBuiltinFunctions();
-void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes);
-void UnregisterNonABICompliantCodeRange(void* start);
-
class BuiltinUnwindInfo {
public:
BuiltinUnwindInfo() : is_leaf_function_(true) {}
@@ -76,7 +90,7 @@ class BuiltinUnwindInfo {
class XdataEncoder {
public:
explicit XdataEncoder(const Assembler& assembler)
- : assembler_(assembler), current_push_rbp_offset_(-1) {}
+ : assembler_(assembler), current_frame_code_offset_(-1) {}
void onPushRbp();
void onMovRbpRsp();
@@ -88,14 +102,77 @@ class XdataEncoder {
private:
const Assembler& assembler_;
std::vector<int> fp_offsets_;
- int current_push_rbp_offset_;
+ int current_frame_code_offset_;
};
-} // namespace win64_unwindinfo
+#elif defined(V8_OS_WIN_ARM64)
+/**
+ * Base on below doc, unwind record has 18 bits (unsigned) to encode function
+ * length, besides 2 LSB which are always 0.
+ * https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records
+ */
+static const int kMaxFunctionLength = ((1 << 18) - 1) << 2;
+
+/**
+ * Returns a vector of bytes that contains the Win ARM64 unwind data used for
+ * all V8 builtin functions.
+ *
+ * func_len: length in bytes of current function/region to unwind.
+ * fp_adjustment: offset of the saved caller's fp based on fp in current frame.
+ * this is necessary to encode unwind data for Windows stack
+ * unwinder to find correct caller's fp.
+ */
+std::vector<uint8_t> GetUnwindInfoForBuiltinFunction(uint32_t func_len,
+ int32_t fp_adjustment);
+class BuiltinUnwindInfo {
+ public:
+ BuiltinUnwindInfo() : is_leaf_function_(true) {}
+ explicit BuiltinUnwindInfo(const std::vector<int>& fp_offsets,
+ const std::vector<int>& fp_adjustments)
+ : is_leaf_function_(false),
+ fp_offsets_(fp_offsets),
+ fp_adjustments_(fp_adjustments) {}
+
+ const std::vector<int>& fp_adjustments() const { return fp_adjustments_; }
+
+ bool is_leaf_function() const { return is_leaf_function_; }
+ const std::vector<int>& fp_offsets() const { return fp_offsets_; }
+
+ private:
+ bool is_leaf_function_;
+ std::vector<int> fp_offsets_;
+ std::vector<int> fp_adjustments_;
+};
+
+class XdataEncoder {
+ public:
+ explicit XdataEncoder(const Assembler& assembler)
+ : assembler_(assembler),
+ current_frame_code_offset_(-1),
+ current_frame_adjustment_(0) {}
+
+ void onSaveFpLr();
+ void onFramePointerAdjustment(int bytes);
+
+ BuiltinUnwindInfo unwinding_info() const {
+ return BuiltinUnwindInfo(fp_offsets_, fp_adjustments_);
+ }
+
+ private:
+ const Assembler& assembler_;
+ std::vector<int> fp_offsets_;
+ int current_frame_code_offset_;
+ int current_frame_adjustment_;
+ std::vector<int> fp_adjustments_;
+};
+
+#endif
+
+} // namespace win64_unwindinfo
} // namespace internal
} // namespace v8
-#endif // defined(V8_OS_WIN_X64)
+#endif // V8_OS_WIN64
#endif // V8_DIAGNOSTICS_UNWINDING_INFO_WIN64_H_
diff --git a/deps/v8/src/diagnostics/x64/disasm-x64.cc b/deps/v8/src/diagnostics/x64/disasm-x64.cc
index 493c56996b..aada6a4381 100644
--- a/deps/v8/src/diagnostics/x64/disasm-x64.cc
+++ b/deps/v8/src/diagnostics/x64/disasm-x64.cc
@@ -1847,12 +1847,26 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
const char* mnemonic;
if (opcode == 0x54) {
mnemonic = "andpd";
+ } else if (opcode == 0x55) {
+ mnemonic = "andnpd";
} else if (opcode == 0x56) {
mnemonic = "orpd";
} else if (opcode == 0x57) {
mnemonic = "xorpd";
+ } else if (opcode == 0x58) {
+ mnemonic = "addpd";
+ } else if (opcode == 0x59) {
+ mnemonic = "mulpd";
} else if (opcode == 0x5B) {
mnemonic = "cvtps2dq";
+ } else if (opcode == 0x5C) {
+ mnemonic = "subpd";
+ } else if (opcode == 0x5D) {
+ mnemonic = "minpd";
+ } else if (opcode == 0x5E) {
+ mnemonic = "divpd";
+ } else if (opcode == 0x5F) {
+ mnemonic = "maxpd";
} else if (opcode == 0x60) {
mnemonic = "punpcklbw";
} else if (opcode == 0x61) {
@@ -1895,6 +1909,8 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
mnemonic = "psrlw";
} else if (opcode == 0xD2) {
mnemonic = "psrld";
+ } else if (opcode == 0xD3) {
+ mnemonic = "psrld";
} else if (opcode == 0xD4) {
mnemonic = "paddq";
} else if (opcode == 0xD5) {
@@ -1939,6 +1955,8 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
mnemonic = "psllw";
} else if (opcode == 0xF2) {
mnemonic = "pslld";
+ } else if (opcode == 0xF3) {
+ mnemonic = "psllq";
} else if (opcode == 0xF4) {
mnemonic = "pmuludq";
} else if (opcode == 0xF8) {
@@ -1985,6 +2003,11 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
AppendToBuffer("%s,", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
}
+ } else if (opcode == 0x12) {
+ int mod, regop, rm;
+ get_modrm(*current, &mod, &regop, &rm);
+ AppendToBuffer("movddup %s,", NameOfXMMRegister(regop));
+ current += PrintRightXMMOperand(current);
} else if (opcode == 0x2A) {
// CVTSI2SD: integer to XMM double conversion.
int mod, regop, rm;
diff --git a/deps/v8/src/execution/arm/simulator-arm.cc b/deps/v8/src/execution/arm/simulator-arm.cc
index 0b3ebcf879..2677135096 100644
--- a/deps/v8/src/execution/arm/simulator-arm.cc
+++ b/deps/v8/src/execution/arm/simulator-arm.cc
@@ -1562,7 +1562,7 @@ using SimulatorRuntimeCall = int64_t (*)(int32_t arg0, int32_t arg1,
int32_t arg2, int32_t arg3,
int32_t arg4, int32_t arg5,
int32_t arg6, int32_t arg7,
- int32_t arg8);
+ int32_t arg8, int32_t arg9);
// These prototypes handle the four types of FP calls.
using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1);
@@ -1602,7 +1602,8 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
int32_t arg6 = stack_pointer[2];
int32_t arg7 = stack_pointer[3];
int32_t arg8 = stack_pointer[4];
- STATIC_ASSERT(kMaxCParameters == 9);
+ int32_t arg9 = stack_pointer[5];
+ STATIC_ASSERT(kMaxCParameters == 10);
bool fp_call =
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
@@ -1761,9 +1762,9 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
PrintF(
"Call to host function at %p "
- "args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x",
+ "args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x",
reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
- arg3, arg4, arg5, arg6, arg7, arg8);
+ arg3, arg4, arg5, arg6, arg7, arg8, arg9);
if (!stack_aligned) {
PrintF(" with unaligned stack %08x\n", get_register(sp));
}
@@ -1771,7 +1772,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
}
CHECK(stack_aligned);
int64_t result =
- target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+ target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
int32_t lo_res = static_cast<int32_t>(result);
int32_t hi_res = static_cast<int32_t>(result >> 32);
if (::v8::internal::FLAG_trace_sim) {
@@ -4070,6 +4071,39 @@ void ShiftRightAndInsert(Simulator* simulator, int Vd, int Vm, int shift) {
simulator->set_neon_register<T, SIZE>(Vd, dst);
}
+template <typename T, typename S_T, int SIZE>
+void ShiftByRegister(Simulator* simulator, int Vd, int Vm, int Vn) {
+ static const int kElems = SIZE / sizeof(T);
+ T src[kElems];
+ S_T shift[kElems];
+ simulator->get_neon_register<T, SIZE>(Vm, src);
+ simulator->get_neon_register<S_T, SIZE>(Vn, shift);
+ for (int i = 0; i < kElems; i++) {
+ // Take lowest 8 bits of shift value (see F6.1.217 of ARM Architecture
+ // Reference Manual ARMv8), as signed 8-bit value.
+ int8_t shift_value = static_cast<int8_t>(shift[i]);
+ int size = static_cast<int>(sizeof(T) * 8);
+ // When shift value is greater/equal than size, we end up relying on
+ // undefined behavior, handle that and emulate what the hardware does.
+ if ((shift_value) >= 0) {
+ // If the shift value is greater/equal than size, zero out the result.
+ if (shift_value >= size) {
+ src[i] = 0;
+ } else {
+ src[i] <<= shift_value;
+ }
+ } else {
+ // If the shift value is greater/equal than size, always end up with -1.
+ if (-shift_value >= size) {
+ src[i] = -1;
+ } else {
+ src[i] = ArithmeticShiftRight(src[i], -shift_value);
+ }
+ }
+ }
+ simulator->set_neon_register<T, SIZE>(Vd, src);
+}
+
template <typename T, int SIZE>
void CompareEqual(Simulator* simulator, int Vd, int Vm, int Vn) {
static const int kElems = SIZE / sizeof(T);
@@ -4255,6 +4289,25 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
}
break;
}
+ case 0x4: {
+ // vshl s<size> Qd, Qm, Qn.
+ NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
+ switch (size) {
+ case Neon8:
+ ShiftByRegister<int8_t, int8_t, kSimd128Size>(this, Vd, Vm, Vn);
+ break;
+ case Neon16:
+ ShiftByRegister<int16_t, int16_t, kSimd128Size>(this, Vd, Vm, Vn);
+ break;
+ case Neon32:
+ ShiftByRegister<int32_t, int32_t, kSimd128Size>(this, Vd, Vm, Vn);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+ }
case 0x6: {
// vmin/vmax.s<size> Qd, Qm, Qn.
NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
@@ -4644,6 +4697,27 @@ void Simulator::DecodeSpecialCondition(Instruction* instr) {
}
break;
}
+ case 0x4: {
+ // vshl s<size> Qd, Qm, Qn.
+ NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
+ switch (size) {
+ case Neon8:
+ ShiftByRegister<uint8_t, int8_t, kSimd128Size>(this, Vd, Vm, Vn);
+ break;
+ case Neon16:
+ ShiftByRegister<uint16_t, int16_t, kSimd128Size>(this, Vd, Vm,
+ Vn);
+ break;
+ case Neon32:
+ ShiftByRegister<uint32_t, int32_t, kSimd128Size>(this, Vd, Vm,
+ Vn);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+ }
case 0x6: {
// vmin/vmax.u<size> Qd, Qm, Qn.
NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
diff --git a/deps/v8/src/execution/arm64/pointer-auth-arm64.cc b/deps/v8/src/execution/arm64/pointer-auth-arm64.cc
new file mode 100644
index 0000000000..cb8ff2c740
--- /dev/null
+++ b/deps/v8/src/execution/arm64/pointer-auth-arm64.cc
@@ -0,0 +1,269 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/execution/arm64/simulator-arm64.h"
+
+#if defined(USE_SIMULATOR)
+
+namespace v8 {
+namespace internal {
+
+// Randomly generated example key for simulating only.
+const Simulator::PACKey Simulator::kPACKeyIA = {0xc31718727de20f71,
+ 0xab9fd4e14b2fec51, 0};
+
+namespace {
+
+uint64_t GetNibble(uint64_t in_data, int position) {
+ return (in_data >> position) & 0xf;
+}
+
+uint64_t PACCellShuffle(uint64_t in_data) {
+ static int in_positions[16] = {52, 24, 44, 0, 28, 48, 4, 40,
+ 32, 12, 56, 20, 8, 36, 16, 60};
+ uint64_t out_data = 0;
+ for (int i = 0; i < 16; ++i) {
+ out_data |= GetNibble(in_data, in_positions[i]) << (4 * i);
+ }
+ return out_data;
+}
+
+uint64_t PACCellInvShuffle(uint64_t in_data) {
+ static int in_positions[16] = {12, 24, 48, 36, 56, 44, 4, 16,
+ 32, 52, 28, 8, 20, 0, 40, 60};
+ uint64_t out_data = 0;
+ for (int i = 0; i < 16; ++i) {
+ out_data |= GetNibble(in_data, in_positions[i]) << (4 * i);
+ }
+ return out_data;
+}
+
+uint64_t RotCell(uint64_t in_cell, int amount) {
+ DCHECK((amount >= 1) && (amount <= 3));
+
+ in_cell &= 0xf;
+ uint8_t temp = in_cell << 4 | in_cell;
+ return static_cast<uint64_t>((temp >> (4 - amount)) & 0xf);
+}
+
+uint64_t PACMult(uint64_t s_input) {
+ uint8_t t0;
+ uint8_t t1;
+ uint8_t t2;
+ uint8_t t3;
+ uint64_t s_output = 0;
+
+ for (int i = 0; i < 4; ++i) {
+ uint8_t s12 = (s_input >> (4 * (i + 12))) & 0xf;
+ uint8_t s8 = (s_input >> (4 * (i + 8))) & 0xf;
+ uint8_t s4 = (s_input >> (4 * (i + 4))) & 0xf;
+ uint8_t s0 = (s_input >> (4 * (i + 0))) & 0xf;
+
+ t0 = RotCell(s8, 1) ^ RotCell(s4, 2) ^ RotCell(s0, 1);
+ t1 = RotCell(s12, 1) ^ RotCell(s4, 1) ^ RotCell(s0, 2);
+ t2 = RotCell(s12, 2) ^ RotCell(s8, 1) ^ RotCell(s0, 1);
+ t3 = RotCell(s12, 1) ^ RotCell(s8, 2) ^ RotCell(s4, 1);
+
+ s_output |= static_cast<uint64_t>(t3) << (4 * (i + 0));
+ s_output |= static_cast<uint64_t>(t2) << (4 * (i + 4));
+ s_output |= static_cast<uint64_t>(t1) << (4 * (i + 8));
+ s_output |= static_cast<uint64_t>(t0) << (4 * (i + 12));
+ }
+ return s_output;
+}
+
+uint64_t PACSub(uint64_t t_input) {
+ uint64_t t_output = 0;
+ uint8_t substitutions[16] = {0xb, 0x6, 0x8, 0xf, 0xc, 0x0, 0x9, 0xe,
+ 0x3, 0x7, 0x4, 0x5, 0xd, 0x2, 0x1, 0xa};
+ for (int i = 0; i < 16; ++i) {
+ unsigned index = ((t_input >> (4 * i)) & 0xf);
+ t_output |= static_cast<uint64_t>(substitutions[index]) << (4 * i);
+ }
+ return t_output;
+}
+
+uint64_t PACInvSub(uint64_t t_input) {
+ uint64_t t_output = 0;
+ uint8_t substitutions[16] = {0x5, 0xe, 0xd, 0x8, 0xa, 0xb, 0x1, 0x9,
+ 0x2, 0x6, 0xf, 0x0, 0x4, 0xc, 0x7, 0x3};
+ for (int i = 0; i < 16; ++i) {
+ unsigned index = ((t_input >> (4 * i)) & 0xf);
+ t_output |= static_cast<uint64_t>(substitutions[index]) << (4 * i);
+ }
+ return t_output;
+}
+
+uint64_t TweakCellInvRot(uint64_t in_cell) {
+ uint64_t out_cell = 0;
+ out_cell |= (in_cell & 0x7) << 1;
+ out_cell |= (in_cell & 0x1) ^ ((in_cell >> 3) & 0x1);
+ return out_cell;
+}
+
+uint64_t TweakInvShuffle(uint64_t in_data) {
+ uint64_t out_data = 0;
+ out_data |= TweakCellInvRot(in_data >> 48) << 0;
+ out_data |= ((in_data >> 52) & 0xf) << 4;
+ out_data |= ((in_data >> 20) & 0xff) << 8;
+ out_data |= ((in_data >> 0) & 0xff) << 16;
+ out_data |= TweakCellInvRot(in_data >> 8) << 24;
+ out_data |= ((in_data >> 12) & 0xf) << 28;
+ out_data |= TweakCellInvRot(in_data >> 28) << 32;
+ out_data |= TweakCellInvRot(in_data >> 60) << 36;
+ out_data |= TweakCellInvRot(in_data >> 56) << 40;
+ out_data |= TweakCellInvRot(in_data >> 16) << 44;
+ out_data |= ((in_data >> 32) & 0xfff) << 48;
+ out_data |= TweakCellInvRot(in_data >> 44) << 60;
+ return out_data;
+}
+
+uint64_t TweakCellRot(uint64_t in_cell) {
+ uint64_t out_cell = 0;
+ out_cell |= ((in_cell & 0x1) ^ ((in_cell >> 1) & 0x1)) << 3;
+ out_cell |= (in_cell >> 0x1) & 0x7;
+ return out_cell;
+}
+
+uint64_t TweakShuffle(uint64_t in_data) {
+ uint64_t out_data = 0;
+ out_data |= ((in_data >> 16) & 0xff) << 0;
+ out_data |= TweakCellRot(in_data >> 24) << 8;
+ out_data |= ((in_data >> 28) & 0xf) << 12;
+ out_data |= TweakCellRot(in_data >> 44) << 16;
+ out_data |= ((in_data >> 8) & 0xff) << 20;
+ out_data |= TweakCellRot(in_data >> 32) << 28;
+ out_data |= ((in_data >> 48) & 0xfff) << 32;
+ out_data |= TweakCellRot(in_data >> 60) << 44;
+ out_data |= TweakCellRot(in_data >> 0) << 48;
+ out_data |= ((in_data >> 4) & 0xf) << 52;
+ out_data |= TweakCellRot(in_data >> 40) << 56;
+ out_data |= TweakCellRot(in_data >> 36) << 60;
+ return out_data;
+}
+
+} // namespace
+
+// For a description of QARMA see:
+// The QARMA Block Cipher Family, Roberto Avanzi, Qualcomm Product Security
+// Initiative.
+// The pseudocode is available in ARM DDI 0487D.b, J1-6946.
+uint64_t Simulator::ComputePAC(uint64_t data, uint64_t context, PACKey key) {
+ uint64_t key0 = key.high;
+ uint64_t key1 = key.low;
+ const uint64_t RC[5] = {0x0000000000000000, 0x13198a2e03707344,
+ 0xa4093822299f31d0, 0x082efa98ec4e6c89,
+ 0x452821e638d01377};
+ const uint64_t Alpha = 0xc0ac29B7c97c50dd;
+
+ uint64_t modk0 = ((key0 & 0x1) << 63) | ((key0 >> 2) << 1) |
+ ((key0 >> 63) ^ ((key0 >> 1) & 0x1));
+ uint64_t running_mod = context;
+ uint64_t working_val = data ^ key0;
+ uint64_t round_key;
+ for (int i = 0; i < 5; ++i) {
+ round_key = key1 ^ running_mod;
+ working_val ^= round_key;
+ working_val ^= RC[i];
+ if (i > 0) {
+ working_val = PACCellShuffle(working_val);
+ working_val = PACMult(working_val);
+ }
+ working_val = PACSub(working_val);
+ running_mod = TweakShuffle(running_mod);
+ }
+
+ round_key = modk0 ^ running_mod;
+ working_val ^= round_key;
+ working_val = PACCellShuffle(working_val);
+ working_val = PACMult(working_val);
+ working_val = PACSub(working_val);
+ working_val = PACCellShuffle(working_val);
+ working_val = PACMult(working_val);
+ working_val ^= key1;
+ working_val = PACCellInvShuffle(working_val);
+ working_val = PACInvSub(working_val);
+ working_val = PACMult(working_val);
+ working_val = PACCellInvShuffle(working_val);
+ working_val ^= key0;
+ working_val ^= running_mod;
+
+ for (int i = 0; i < 5; ++i) {
+ working_val = PACInvSub(working_val);
+ if (i < 4) {
+ working_val = PACMult(working_val);
+ working_val = PACCellInvShuffle(working_val);
+ }
+ running_mod = TweakInvShuffle(running_mod);
+ round_key = key1 ^ running_mod;
+ working_val ^= RC[4 - i];
+ working_val ^= round_key;
+ working_val ^= Alpha;
+ }
+
+ return working_val ^ modk0;
+}
+
+// The TTBR is selected by bit 63 or 55 depending on TBI for pointers without
+// codes, but is always 55 once a PAC code is added to a pointer. For this
+// reason, it must be calculated at the call site.
+uint64_t Simulator::CalculatePACMask(uint64_t ptr, PointerType type, int ttbr) {
+ int bottom_pac_bit = GetBottomPACBit(ptr, ttbr);
+ int top_pac_bit = GetTopPACBit(ptr, type);
+ return unsigned_bitextract_64(top_pac_bit, bottom_pac_bit,
+ 0xffffffffffffffff & ~kTTBRMask)
+ << bottom_pac_bit;
+}
+
+uint64_t Simulator::AuthPAC(uint64_t ptr, uint64_t context, PACKey key,
+ PointerType type) {
+ DCHECK((key.number == 0) || (key.number == 1));
+
+ uint64_t pac_mask = CalculatePACMask(ptr, type, (ptr >> 55) & 1);
+ uint64_t original_ptr =
+ ((ptr & kTTBRMask) == 0) ? (ptr & ~pac_mask) : (ptr | pac_mask);
+
+ uint64_t pac = ComputePAC(original_ptr, context, key);
+
+ uint64_t error_code = 1 << key.number;
+ if ((pac & pac_mask) == (ptr & pac_mask)) {
+ return original_ptr;
+ } else {
+ int error_lsb = GetTopPACBit(ptr, type) - 2;
+ uint64_t error_mask = UINT64_C(0x3) << error_lsb;
+ return (original_ptr & ~error_mask) | (error_code << error_lsb);
+ }
+}
+
+uint64_t Simulator::AddPAC(uint64_t ptr, uint64_t context, PACKey key,
+ PointerType type) {
+ int top_pac_bit = GetTopPACBit(ptr, type);
+
+ DCHECK(HasTBI(ptr, type));
+ int ttbr = (ptr >> 55) & 1;
+ uint64_t pac_mask = CalculatePACMask(ptr, type, ttbr);
+ uint64_t ext_ptr = (ttbr == 0) ? (ptr & ~pac_mask) : (ptr | pac_mask);
+
+ uint64_t pac = ComputePAC(ext_ptr, context, key);
+
+ // If the pointer isn't all zeroes or all ones in the PAC bitfield, corrupt
+ // the resulting code.
+ if (((ptr & (pac_mask | kTTBRMask)) != 0x0) &&
+ ((~ptr & (pac_mask | kTTBRMask)) != 0x0)) {
+ pac ^= UINT64_C(1) << (top_pac_bit - 1);
+ }
+
+ uint64_t ttbr_shifted = static_cast<uint64_t>(ttbr) << 55;
+ return (pac & pac_mask) | ttbr_shifted | (ptr & ~pac_mask);
+}
+
+uint64_t Simulator::StripPAC(uint64_t ptr, PointerType type) {
+ uint64_t pac_mask = CalculatePACMask(ptr, type, (ptr >> 55) & 1);
+ return ((ptr & kTTBRMask) == 0) ? (ptr & ~pac_mask) : (ptr | pac_mask);
+}
+
+} // namespace internal
+} // namespace v8
+
+#endif // USE_SIMULATOR
diff --git a/deps/v8/src/execution/arm64/simulator-arm64.cc b/deps/v8/src/execution/arm64/simulator-arm64.cc
index 8618dd8551..71fedd5b2f 100644
--- a/deps/v8/src/execution/arm64/simulator-arm64.cc
+++ b/deps/v8/src/execution/arm64/simulator-arm64.cc
@@ -390,14 +390,14 @@ using SimulatorRuntimeCall_ReturnPtr = int64_t (*)(int64_t arg0, int64_t arg1,
int64_t arg2, int64_t arg3,
int64_t arg4, int64_t arg5,
int64_t arg6, int64_t arg7,
- int64_t arg8);
+ int64_t arg8, int64_t arg9);
#endif
using SimulatorRuntimeCall = ObjectPair (*)(int64_t arg0, int64_t arg1,
int64_t arg2, int64_t arg3,
int64_t arg4, int64_t arg5,
int64_t arg6, int64_t arg7,
- int64_t arg8);
+ int64_t arg8, int64_t arg9);
using SimulatorRuntimeCompareCall = int64_t (*)(double arg1, double arg2);
using SimulatorRuntimeFPFPCall = double (*)(double arg1, double arg2);
@@ -445,7 +445,8 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
const int64_t arg6 = xreg(6);
const int64_t arg7 = xreg(7);
const int64_t arg8 = stack_pointer[0];
- STATIC_ASSERT(kMaxCParameters == 9);
+ const int64_t arg9 = stack_pointer[1];
+ STATIC_ASSERT(kMaxCParameters == 10);
switch (redirection->type()) {
default:
@@ -477,14 +478,14 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
", "
"0x%016" PRIx64 ", 0x%016" PRIx64
", "
- "0x%016" PRIx64,
- arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+ "0x%016" PRIx64 ", 0x%016" PRIx64,
+ arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
SimulatorRuntimeCall_ReturnPtr target =
reinterpret_cast<SimulatorRuntimeCall_ReturnPtr>(external);
int64_t result =
- target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+ target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
TraceSim("Returned: 0x%16\n", result);
#ifdef DEBUG
CorruptAllCallerSavedCPURegisters();
@@ -512,12 +513,12 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
", "
"0x%016" PRIx64 ", 0x%016" PRIx64
", "
- "0x%016" PRIx64,
- arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+ "0x%016" PRIx64 ", 0x%016" PRIx64,
+ arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
ObjectPair result =
- target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+ target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
TraceSim("Returned: {%p, %p}\n", reinterpret_cast<void*>(result.x),
reinterpret_cast<void*>(result.y));
#ifdef DEBUG
@@ -3037,11 +3038,31 @@ bool Simulator::FPProcessNaNs(Instruction* instr) {
return done;
}
+// clang-format off
+#define PAUTH_SYSTEM_MODES(V) \
+ V(A1716, 17, xreg(16), kPACKeyIA) \
+ V(ASP, 30, xreg(31, Reg31IsStackPointer), kPACKeyIA)
+// clang-format on
+
void Simulator::VisitSystem(Instruction* instr) {
// Some system instructions hijack their Op and Cp fields to represent a
// range of immediates instead of indicating a different instruction. This
// makes the decoding tricky.
- if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
+ if (instr->Mask(SystemPAuthFMask) == SystemPAuthFixed) {
+ switch (instr->Mask(SystemPAuthMask)) {
+#define DEFINE_PAUTH_FUNCS(SUFFIX, DST, MOD, KEY) \
+ case PACI##SUFFIX: \
+ set_xreg(DST, AddPAC(xreg(DST), MOD, KEY, kInstructionPointer)); \
+ break; \
+ case AUTI##SUFFIX: \
+ set_xreg(DST, AuthPAC(xreg(DST), MOD, KEY, kInstructionPointer)); \
+ break;
+
+ PAUTH_SYSTEM_MODES(DEFINE_PAUTH_FUNCS)
+#undef DEFINE_PAUTH_FUNCS
+#undef PAUTH_SYSTEM_MODES
+ }
+ } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
switch (instr->Mask(SystemSysRegMask)) {
case MRS: {
switch (instr->ImmSystemRegister()) {
diff --git a/deps/v8/src/execution/arm64/simulator-arm64.h b/deps/v8/src/execution/arm64/simulator-arm64.h
index ca1cef61ae..4a493ec696 100644
--- a/deps/v8/src/execution/arm64/simulator-arm64.h
+++ b/deps/v8/src/execution/arm64/simulator-arm64.h
@@ -1273,6 +1273,45 @@ class Simulator : public DecoderVisitor, public SimulatorBase {
static inline const char* VRegNameForCode(unsigned code);
static inline int CodeFromName(const char* name);
+ enum PointerType { kDataPointer, kInstructionPointer };
+
+ struct PACKey {
+ uint64_t high;
+ uint64_t low;
+ int number;
+ };
+
+ static const PACKey kPACKeyIA;
+
+ // Current implementation is that all pointers are tagged.
+ static bool HasTBI(uint64_t ptr, PointerType type) {
+ USE(ptr, type);
+ return true;
+ }
+
+ // Current implementation uses 48-bit virtual addresses.
+ static int GetBottomPACBit(uint64_t ptr, int ttbr) {
+ USE(ptr, ttbr);
+ DCHECK((ttbr == 0) || (ttbr == 1));
+ return 48;
+ }
+
+ // The top PAC bit is 55 for the purposes of relative bit fields with TBI,
+ // however bit 55 is the TTBR bit regardless of TBI so isn't part of the PAC
+ // codes in pointers.
+ static int GetTopPACBit(uint64_t ptr, PointerType type) {
+ return HasTBI(ptr, type) ? 55 : 63;
+ }
+
+ // Armv8.3 Pointer authentication helpers.
+ static uint64_t CalculatePACMask(uint64_t ptr, PointerType type, int ext_bit);
+ static uint64_t ComputePAC(uint64_t data, uint64_t context, PACKey key);
+ static uint64_t AuthPAC(uint64_t ptr, uint64_t context, PACKey key,
+ PointerType type);
+ static uint64_t AddPAC(uint64_t ptr, uint64_t context, PACKey key,
+ PointerType type);
+ static uint64_t StripPAC(uint64_t ptr, PointerType type);
+
protected:
// Simulation helpers ------------------------------------
bool ConditionPassed(Condition cond) {
diff --git a/deps/v8/src/execution/frames.cc b/deps/v8/src/execution/frames.cc
index 126cb9530e..3b334739da 100644
--- a/deps/v8/src/execution/frames.cc
+++ b/deps/v8/src/execution/frames.cc
@@ -8,6 +8,7 @@
#include <sstream>
#include "src/base/bits.h"
+#include "src/codegen/interface-descriptors.h"
#include "src/codegen/macro-assembler.h"
#include "src/codegen/register-configuration.h"
#include "src/codegen/safepoint-table.h"
@@ -270,6 +271,7 @@ SafeStackFrameIterator::SafeStackFrameIterator(Isolate* isolate, Address pc,
low_bound_(sp),
high_bound_(js_entry_sp),
top_frame_type_(StackFrame::NONE),
+ top_context_address_(kNullAddress),
external_callback_scope_(isolate->external_callback_scope()),
top_link_register_(lr) {
StackFrame::State state;
@@ -342,6 +344,13 @@ SafeStackFrameIterator::SafeStackFrameIterator(Isolate* isolate, Address pc,
if (type != StackFrame::INTERPRETED) {
advance_frame = true;
}
+ MSAN_MEMORY_IS_INITIALIZED(
+ fp + CommonFrameConstants::kContextOrFrameTypeOffset,
+ kSystemPointerSize);
+ Address type_or_context_address =
+ Memory<Address>(fp + CommonFrameConstants::kContextOrFrameTypeOffset);
+ if (!StackFrame::IsTypeMarker(type_or_context_address))
+ top_context_address_ = type_or_context_address;
} else {
// Mark the frame as OPTIMIZED if we cannot determine its type.
// We chose OPTIMIZED rather than INTERPRETED because it's closer to
@@ -579,6 +588,8 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
return OPTIMIZED;
case Code::JS_TO_WASM_FUNCTION:
return JS_TO_WASM;
+ case Code::JS_TO_JS_FUNCTION:
+ return STUB;
case Code::C_WASM_ENTRY:
return C_WASM_ENTRY;
case Code::WASM_FUNCTION:
@@ -1136,11 +1147,11 @@ void JavaScriptFrame::Summarize(std::vector<FrameSummary>* functions) const {
DCHECK(functions->empty());
Code code = LookupCode();
int offset = static_cast<int>(pc() - code.InstructionStart());
- AbstractCode abstract_code = AbstractCode::cast(code);
+ Handle<AbstractCode> abstract_code(AbstractCode::cast(code), isolate());
Handle<FixedArray> params = GetParameters();
FrameSummary::JavaScriptFrameSummary summary(
- isolate(), receiver(), function(), abstract_code, offset, IsConstructor(),
- *params);
+ isolate(), receiver(), function(), *abstract_code, offset,
+ IsConstructor(), *params);
functions->push_back(summary);
}
@@ -1813,10 +1824,11 @@ void InterpretedFrame::WriteInterpreterRegister(int register_index,
void InterpretedFrame::Summarize(std::vector<FrameSummary>* functions) const {
DCHECK(functions->empty());
- AbstractCode abstract_code = AbstractCode::cast(GetBytecodeArray());
+ Handle<AbstractCode> abstract_code(AbstractCode::cast(GetBytecodeArray()),
+ isolate());
Handle<FixedArray> params = GetParameters();
FrameSummary::JavaScriptFrameSummary summary(
- isolate(), receiver(), function(), abstract_code, GetBytecodeOffset(),
+ isolate(), receiver(), function(), *abstract_code, GetBytecodeOffset(),
IsConstructor(), *params);
functions->push_back(summary);
}
@@ -2258,5 +2270,161 @@ InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
}
return entry;
}
+
+// Frame layout helper class implementation.
+// -------------------------------------------------------------------------
+
+namespace {
+
+int ArgumentPaddingSlots(int arg_count) {
+ return ShouldPadArguments(arg_count) ? 1 : 0;
+}
+
+// Some architectures need to push padding together with the TOS register
+// in order to maintain stack alignment.
+constexpr int TopOfStackRegisterPaddingSlots() { return kPadArguments ? 1 : 0; }
+
+bool BuiltinContinuationModeIsWithCatch(BuiltinContinuationMode mode) {
+ switch (mode) {
+ case BuiltinContinuationMode::STUB:
+ case BuiltinContinuationMode::JAVASCRIPT:
+ return false;
+ case BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH:
+ case BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION:
+ return true;
+ }
+ UNREACHABLE();
+}
+
+} // namespace
+
+InterpretedFrameInfo::InterpretedFrameInfo(int parameters_count_with_receiver,
+ int translation_height,
+ bool is_topmost,
+ FrameInfoKind frame_info_kind) {
+ const int locals_count = translation_height;
+
+ register_stack_slot_count_ =
+ InterpreterFrameConstants::RegisterStackSlotCount(locals_count);
+
+ static constexpr int kTheAccumulator = 1;
+ static constexpr int kTopOfStackPadding = TopOfStackRegisterPaddingSlots();
+ int maybe_additional_slots =
+ (is_topmost || frame_info_kind == FrameInfoKind::kConservative)
+ ? (kTheAccumulator + kTopOfStackPadding)
+ : 0;
+ frame_size_in_bytes_without_fixed_ =
+ (register_stack_slot_count_ + maybe_additional_slots) *
+ kSystemPointerSize;
+
+ // The 'fixed' part of the frame consists of the incoming parameters and
+ // the part described by InterpreterFrameConstants. This will include
+ // argument padding, when needed.
+ const int parameter_padding_slots =
+ ArgumentPaddingSlots(parameters_count_with_receiver);
+ const int fixed_frame_size =
+ InterpreterFrameConstants::kFixedFrameSize +
+ (parameters_count_with_receiver + parameter_padding_slots) *
+ kSystemPointerSize;
+ frame_size_in_bytes_ = frame_size_in_bytes_without_fixed_ + fixed_frame_size;
+}
+
+ArgumentsAdaptorFrameInfo::ArgumentsAdaptorFrameInfo(int translation_height) {
+ // Note: This is according to the Translation's notion of 'parameters' which
+ // differs to that of the SharedFunctionInfo, e.g. by including the receiver.
+ const int parameters_count = translation_height;
+ frame_size_in_bytes_without_fixed_ =
+ (parameters_count + ArgumentPaddingSlots(parameters_count)) *
+ kSystemPointerSize;
+ frame_size_in_bytes_ = frame_size_in_bytes_without_fixed_ +
+ ArgumentsAdaptorFrameConstants::kFixedFrameSize;
+}
+
+ConstructStubFrameInfo::ConstructStubFrameInfo(int translation_height,
+ bool is_topmost,
+ FrameInfoKind frame_info_kind) {
+ // Note: This is according to the Translation's notion of 'parameters' which
+ // differs to that of the SharedFunctionInfo, e.g. by including the receiver.
+ const int parameters_count = translation_height;
+
+ // If the construct frame appears to be topmost we should ensure that the
+ // value of result register is preserved during continuation execution.
+ // We do this here by "pushing" the result of the constructor function to
+ // the top of the reconstructed stack and popping it in
+ // {Builtins::kNotifyDeoptimized}.
+
+ static constexpr int kTopOfStackPadding = TopOfStackRegisterPaddingSlots();
+ static constexpr int kTheResult = 1;
+ const int argument_padding = ArgumentPaddingSlots(parameters_count);
+
+ const int adjusted_height =
+ (is_topmost || frame_info_kind == FrameInfoKind::kConservative)
+ ? parameters_count + argument_padding + kTheResult +
+ kTopOfStackPadding
+ : parameters_count + argument_padding;
+ frame_size_in_bytes_without_fixed_ = adjusted_height * kSystemPointerSize;
+ frame_size_in_bytes_ = frame_size_in_bytes_without_fixed_ +
+ ConstructFrameConstants::kFixedFrameSize;
+}
+
+BuiltinContinuationFrameInfo::BuiltinContinuationFrameInfo(
+ int translation_height,
+ const CallInterfaceDescriptor& continuation_descriptor,
+ const RegisterConfiguration* register_config, bool is_topmost,
+ DeoptimizeKind deopt_kind, BuiltinContinuationMode continuation_mode,
+ FrameInfoKind frame_info_kind) {
+ const bool is_conservative = frame_info_kind == FrameInfoKind::kConservative;
+
+ // Note: This is according to the Translation's notion of 'parameters' which
+ // differs to that of the SharedFunctionInfo, e.g. by including the receiver.
+ const int parameters_count = translation_height;
+ frame_has_result_stack_slot_ =
+ !is_topmost || deopt_kind == DeoptimizeKind::kLazy;
+ const int result_slot_count =
+ (frame_has_result_stack_slot_ || is_conservative) ? 1 : 0;
+
+ const int exception_slot_count =
+ (BuiltinContinuationModeIsWithCatch(continuation_mode) || is_conservative)
+ ? 1
+ : 0;
+
+ const int allocatable_register_count =
+ register_config->num_allocatable_general_registers();
+ const int padding_slot_count =
+ BuiltinContinuationFrameConstants::PaddingSlotCount(
+ allocatable_register_count);
+
+ const int register_parameter_count =
+ continuation_descriptor.GetRegisterParameterCount();
+ translated_stack_parameter_count_ =
+ parameters_count - register_parameter_count;
+ stack_parameter_count_ = translated_stack_parameter_count_ +
+ result_slot_count + exception_slot_count;
+ const int stack_param_pad_count =
+ ArgumentPaddingSlots(stack_parameter_count_);
+
+ // If the builtins frame appears to be topmost we should ensure that the
+ // value of result register is preserved during continuation execution.
+ // We do this here by "pushing" the result of callback function to the
+ // top of the reconstructed stack and popping it in
+ // {Builtins::kNotifyDeoptimized}.
+ static constexpr int kTopOfStackPadding = TopOfStackRegisterPaddingSlots();
+ static constexpr int kTheResult = 1;
+ const int push_result_count =
+ (is_topmost || is_conservative) ? kTheResult + kTopOfStackPadding : 0;
+
+ frame_size_in_bytes_ =
+ kSystemPointerSize * (stack_parameter_count_ + stack_param_pad_count +
+ allocatable_register_count + padding_slot_count +
+ push_result_count) +
+ BuiltinContinuationFrameConstants::kFixedFrameSize;
+
+ frame_size_in_bytes_above_fp_ =
+ kSystemPointerSize * (allocatable_register_count + padding_slot_count +
+ push_result_count) +
+ (BuiltinContinuationFrameConstants::kFixedFrameSize -
+ BuiltinContinuationFrameConstants::kFixedFrameSizeAboveFp);
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/execution/frames.h b/deps/v8/src/execution/frames.h
index 1f83984f97..d1e7a7890d 100644
--- a/deps/v8/src/execution/frames.h
+++ b/deps/v8/src/execution/frames.h
@@ -1285,6 +1285,7 @@ class SafeStackFrameIterator : public StackFrameIteratorBase {
void Advance();
StackFrame::Type top_frame_type() const { return top_frame_type_; }
+ Address top_context_address() const { return top_context_address_; }
private:
void AdvanceOneFrame();
@@ -1308,9 +1309,178 @@ class SafeStackFrameIterator : public StackFrameIteratorBase {
const Address low_bound_;
const Address high_bound_;
StackFrame::Type top_frame_type_;
+ Address top_context_address_;
ExternalCallbackScope* external_callback_scope_;
Address top_link_register_;
};
+
+// Frame layout helper classes. Used by the deoptimizer and instruction
+// selector.
+// -------------------------------------------------------------------------
+
+// How to calculate the frame layout information. Precise, when all information
+// is available during deoptimization. Conservative, when an overapproximation
+// is fine.
+// TODO(jgruber): Investigate whether the conservative kind can be removed. It
+// seems possible: 1. is_topmost should be known through the outer_state chain
+// of FrameStateDescriptor; 2. the deopt_kind may be a property of the bailout
+// id; 3. for continuation_mode, we only care whether it is a mode with catch,
+// and that is likewise known at compile-time.
+// There is nothing specific blocking this, the investigation just requires time
+// and it is not that important to get the exact frame height at compile-time.
+enum class FrameInfoKind {
+ kPrecise,
+ kConservative,
+};
+
+// Used by the deoptimizer. Corresponds to frame kinds:
+enum class BuiltinContinuationMode {
+ STUB, // BuiltinContinuationFrame
+ JAVASCRIPT, // JavaScriptBuiltinContinuationFrame
+ JAVASCRIPT_WITH_CATCH, // JavaScriptBuiltinContinuationWithCatchFrame
+ JAVASCRIPT_HANDLE_EXCEPTION // JavaScriptBuiltinContinuationWithCatchFrame
+};
+
+class InterpretedFrameInfo {
+ public:
+ static InterpretedFrameInfo Precise(int parameters_count_with_receiver,
+ int translation_height, bool is_topmost) {
+ return {parameters_count_with_receiver, translation_height, is_topmost,
+ FrameInfoKind::kPrecise};
+ }
+
+ static InterpretedFrameInfo Conservative(int parameters_count_with_receiver,
+ int locals_count) {
+ return {parameters_count_with_receiver, locals_count, false,
+ FrameInfoKind::kConservative};
+ }
+
+ uint32_t register_stack_slot_count() const {
+ return register_stack_slot_count_;
+ }
+ uint32_t frame_size_in_bytes_without_fixed() const {
+ return frame_size_in_bytes_without_fixed_;
+ }
+ uint32_t frame_size_in_bytes() const { return frame_size_in_bytes_; }
+
+ private:
+ InterpretedFrameInfo(int parameters_count_with_receiver,
+ int translation_height, bool is_topmost,
+ FrameInfoKind frame_info_kind);
+
+ uint32_t register_stack_slot_count_;
+ uint32_t frame_size_in_bytes_without_fixed_;
+ uint32_t frame_size_in_bytes_;
+};
+
+class ArgumentsAdaptorFrameInfo {
+ public:
+ static ArgumentsAdaptorFrameInfo Precise(int translation_height) {
+ return ArgumentsAdaptorFrameInfo{translation_height};
+ }
+
+ static ArgumentsAdaptorFrameInfo Conservative(int parameters_count) {
+ return ArgumentsAdaptorFrameInfo{parameters_count};
+ }
+
+ uint32_t frame_size_in_bytes_without_fixed() const {
+ return frame_size_in_bytes_without_fixed_;
+ }
+ uint32_t frame_size_in_bytes() const { return frame_size_in_bytes_; }
+
+ private:
+ explicit ArgumentsAdaptorFrameInfo(int translation_height);
+
+ uint32_t frame_size_in_bytes_without_fixed_;
+ uint32_t frame_size_in_bytes_;
+};
+
+class ConstructStubFrameInfo {
+ public:
+ static ConstructStubFrameInfo Precise(int translation_height,
+ bool is_topmost) {
+ return {translation_height, is_topmost, FrameInfoKind::kPrecise};
+ }
+
+ static ConstructStubFrameInfo Conservative(int parameters_count) {
+ return {parameters_count, false, FrameInfoKind::kConservative};
+ }
+
+ uint32_t frame_size_in_bytes_without_fixed() const {
+ return frame_size_in_bytes_without_fixed_;
+ }
+ uint32_t frame_size_in_bytes() const { return frame_size_in_bytes_; }
+
+ private:
+ ConstructStubFrameInfo(int translation_height, bool is_topmost,
+ FrameInfoKind frame_info_kind);
+
+ uint32_t frame_size_in_bytes_without_fixed_;
+ uint32_t frame_size_in_bytes_;
+};
+
+// Used by BuiltinContinuationFrameInfo.
+class CallInterfaceDescriptor;
+class RegisterConfiguration;
+
+class BuiltinContinuationFrameInfo {
+ public:
+ static BuiltinContinuationFrameInfo Precise(
+ int translation_height,
+ const CallInterfaceDescriptor& continuation_descriptor,
+ const RegisterConfiguration* register_config, bool is_topmost,
+ DeoptimizeKind deopt_kind, BuiltinContinuationMode continuation_mode) {
+ return {translation_height,
+ continuation_descriptor,
+ register_config,
+ is_topmost,
+ deopt_kind,
+ continuation_mode,
+ FrameInfoKind::kPrecise};
+ }
+
+ static BuiltinContinuationFrameInfo Conservative(
+ int parameters_count,
+ const CallInterfaceDescriptor& continuation_descriptor,
+ const RegisterConfiguration* register_config) {
+ // It doesn't matter what we pass as is_topmost, deopt_kind and
+ // continuation_mode; these values are ignored in conservative mode.
+ return {parameters_count,
+ continuation_descriptor,
+ register_config,
+ false,
+ DeoptimizeKind::kEager,
+ BuiltinContinuationMode::STUB,
+ FrameInfoKind::kConservative};
+ }
+
+ bool frame_has_result_stack_slot() const {
+ return frame_has_result_stack_slot_;
+ }
+ uint32_t translated_stack_parameter_count() const {
+ return translated_stack_parameter_count_;
+ }
+ uint32_t stack_parameter_count() const { return stack_parameter_count_; }
+ uint32_t frame_size_in_bytes() const { return frame_size_in_bytes_; }
+ uint32_t frame_size_in_bytes_above_fp() const {
+ return frame_size_in_bytes_above_fp_;
+ }
+
+ private:
+ BuiltinContinuationFrameInfo(
+ int translation_height,
+ const CallInterfaceDescriptor& continuation_descriptor,
+ const RegisterConfiguration* register_config, bool is_topmost,
+ DeoptimizeKind deopt_kind, BuiltinContinuationMode continuation_mode,
+ FrameInfoKind frame_info_kind);
+
+ bool frame_has_result_stack_slot_;
+ uint32_t translated_stack_parameter_count_;
+ uint32_t stack_parameter_count_;
+ uint32_t frame_size_in_bytes_;
+ uint32_t frame_size_in_bytes_above_fp_;
+};
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/execution/futex-emulation.cc b/deps/v8/src/execution/futex-emulation.cc
index 7482807921..8c3b54c2a7 100644
--- a/deps/v8/src/execution/futex-emulation.cc
+++ b/deps/v8/src/execution/futex-emulation.cc
@@ -11,6 +11,7 @@
#include "src/execution/isolate.h"
#include "src/handles/handles-inl.h"
#include "src/numbers/conversions.h"
+#include "src/objects/bigint.h"
#include "src/objects/js-array-buffer-inl.h"
#include "src/objects/objects-inl.h"
@@ -80,10 +81,9 @@ void AtomicsWaitWakeHandle::Wake() {
enum WaitReturnValue : int { kOk = 0, kNotEqual = 1, kTimedOut = 2 };
-Object FutexEmulation::WaitJs(Isolate* isolate,
- Handle<JSArrayBuffer> array_buffer, size_t addr,
- int32_t value, double rel_timeout_ms) {
- Object res = Wait32(isolate, array_buffer, addr, value, rel_timeout_ms);
+namespace {
+
+Object WaitJsTranslateReturn(Isolate* isolate, Object res) {
if (res.IsSmi()) {
int val = Smi::ToInt(res);
switch (val) {
@@ -100,6 +100,22 @@ Object FutexEmulation::WaitJs(Isolate* isolate,
return res;
}
+} // namespace
+
+Object FutexEmulation::WaitJs32(Isolate* isolate,
+ Handle<JSArrayBuffer> array_buffer, size_t addr,
+ int32_t value, double rel_timeout_ms) {
+ Object res = Wait32(isolate, array_buffer, addr, value, rel_timeout_ms);
+ return WaitJsTranslateReturn(isolate, res);
+}
+
+Object FutexEmulation::WaitJs64(Isolate* isolate,
+ Handle<JSArrayBuffer> array_buffer, size_t addr,
+ int64_t value, double rel_timeout_ms) {
+ Object res = Wait64(isolate, array_buffer, addr, value, rel_timeout_ms);
+ return WaitJsTranslateReturn(isolate, res);
+}
+
Object FutexEmulation::Wait32(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer, size_t addr,
int32_t value, double rel_timeout_ms) {
diff --git a/deps/v8/src/execution/futex-emulation.h b/deps/v8/src/execution/futex-emulation.h
index c6fee5c3f7..052b3c9c17 100644
--- a/deps/v8/src/execution/futex-emulation.h
+++ b/deps/v8/src/execution/futex-emulation.h
@@ -117,8 +117,12 @@ class FutexEmulation : public AllStatic {
// |rel_timeout_ms| can be Infinity.
// If woken, return "ok", otherwise return "timed-out". The initial check and
// the decision to wait happen atomically.
- static Object WaitJs(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
- size_t addr, int32_t value, double rel_timeout_ms);
+ static Object WaitJs32(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
+ size_t addr, int32_t value, double rel_timeout_ms);
+
+ // An version of WaitJs32 for int64_t values.
+ static Object WaitJs64(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
+ size_t addr, int64_t value, double rel_timeout_ms);
// Same as WaitJs above except it returns 0 (ok), 1 (not equal) and 2 (timed
// out) as expected by Wasm.
diff --git a/deps/v8/src/execution/interrupts-scope.cc b/deps/v8/src/execution/interrupts-scope.cc
index cf8611f8d6..7bf9821685 100644
--- a/deps/v8/src/execution/interrupts-scope.cc
+++ b/deps/v8/src/execution/interrupts-scope.cc
@@ -9,7 +9,7 @@
namespace v8 {
namespace internal {
-InterruptsScope::InterruptsScope(Isolate* isolate, int intercept_mask,
+InterruptsScope::InterruptsScope(Isolate* isolate, intptr_t intercept_mask,
Mode mode)
: stack_guard_(isolate->stack_guard()),
intercept_mask_(intercept_mask),
diff --git a/deps/v8/src/execution/interrupts-scope.h b/deps/v8/src/execution/interrupts-scope.h
index 3d74850a84..6419ee2d99 100644
--- a/deps/v8/src/execution/interrupts-scope.h
+++ b/deps/v8/src/execution/interrupts-scope.h
@@ -18,7 +18,7 @@ class InterruptsScope {
public:
enum Mode { kPostponeInterrupts, kRunInterrupts, kNoop };
- V8_EXPORT_PRIVATE InterruptsScope(Isolate* isolate, int intercept_mask,
+ V8_EXPORT_PRIVATE InterruptsScope(Isolate* isolate, intptr_t intercept_mask,
Mode mode);
virtual ~InterruptsScope() {
@@ -33,8 +33,8 @@ class InterruptsScope {
private:
StackGuard* stack_guard_;
- int intercept_mask_;
- int intercepted_flags_;
+ intptr_t intercept_mask_;
+ intptr_t intercepted_flags_;
Mode mode_;
InterruptsScope* prev_;
diff --git a/deps/v8/src/execution/isolate-data.h b/deps/v8/src/execution/isolate-data.h
index adeb7f54d3..6eb23db2a2 100644
--- a/deps/v8/src/execution/isolate-data.h
+++ b/deps/v8/src/execution/isolate-data.h
@@ -8,6 +8,7 @@
#include "src/builtins/builtins.h"
#include "src/codegen/constants-arch.h"
#include "src/codegen/external-reference-table.h"
+#include "src/execution/stack-guard.h"
#include "src/execution/thread-local-top.h"
#include "src/roots/roots.h"
#include "src/utils/utils.h"
@@ -27,7 +28,7 @@ class Isolate;
// register.
class IsolateData final {
public:
- IsolateData() = default;
+ explicit IsolateData(Isolate* isolate) : stack_guard_(isolate) {}
static constexpr intptr_t kIsolateRootBias = kRootRegisterBias;
@@ -81,6 +82,7 @@ class IsolateData final {
// The FP and PC that are saved right before TurboAssembler::CallCFunction.
Address* fast_c_call_caller_fp_address() { return &fast_c_call_caller_fp_; }
Address* fast_c_call_caller_pc_address() { return &fast_c_call_caller_pc_; }
+ StackGuard* stack_guard() { return &stack_guard_; }
uint8_t* stack_is_iterable_address() { return &stack_is_iterable_; }
Address fast_c_call_caller_fp() { return fast_c_call_caller_fp_; }
Address fast_c_call_caller_pc() { return fast_c_call_caller_pc_; }
@@ -109,20 +111,27 @@ class IsolateData final {
Address* builtins() { return builtins_; }
private:
-// Static layout definition.
+ // Static layout definition.
+ //
+ // Note: The location of fields within IsolateData is significant. The
+ // closer they are to the value of kRootRegister (i.e.: isolate_root()), the
+ // cheaper it is to access them. See also: https://crbug.com/993264.
+ // The recommend guideline is to put frequently-accessed fields close to the
+ // beginning of IsolateData.
#define FIELDS(V) \
V(kEmbedderDataOffset, Internals::kNumIsolateDataSlots* kSystemPointerSize) \
V(kExternalMemoryOffset, kInt64Size) \
V(kExternalMemoryLlimitOffset, kInt64Size) \
V(kExternalMemoryAtLastMarkCompactOffset, kInt64Size) \
+ V(kFastCCallCallerFPOffset, kSystemPointerSize) \
+ V(kFastCCallCallerPCOffset, kSystemPointerSize) \
+ V(kStackGuardOffset, StackGuard::kSizeInBytes) \
V(kRootsTableOffset, RootsTable::kEntriesCount* kSystemPointerSize) \
V(kExternalReferenceTableOffset, ExternalReferenceTable::kSizeInBytes) \
V(kThreadLocalTopOffset, ThreadLocalTop::kSizeInBytes) \
V(kBuiltinEntryTableOffset, Builtins::builtin_count* kSystemPointerSize) \
V(kBuiltinsTableOffset, Builtins::builtin_count* kSystemPointerSize) \
V(kVirtualCallTargetRegisterOffset, kSystemPointerSize) \
- V(kFastCCallCallerFPOffset, kSystemPointerSize) \
- V(kFastCCallCallerPCOffset, kSystemPointerSize) \
V(kStackIsIterableOffset, kUInt8Size) \
/* This padding aligns IsolateData size by 8 bytes. */ \
V(kPaddingOffset, \
@@ -150,6 +159,17 @@ class IsolateData final {
// Caches the amount of external memory registered at the last MC.
int64_t external_memory_at_last_mark_compact_ = 0;
+ // Stores the state of the caller for TurboAssembler::CallCFunction so that
+ // the sampling CPU profiler can iterate the stack during such calls. These
+ // are stored on IsolateData so that they can be stored to with only one move
+ // instruction in compiled code.
+ Address fast_c_call_caller_fp_ = kNullAddress;
+ Address fast_c_call_caller_pc_ = kNullAddress;
+
+ // Fields related to the system and JS stack. In particular, this contains the
+ // stack limit used by stack checks in generated code.
+ StackGuard stack_guard_;
+
RootsTable roots_;
ExternalReferenceTable external_reference_table_;
@@ -169,12 +189,6 @@ class IsolateData final {
// ia32 (otherwise the arguments adaptor call runs out of registers).
void* virtual_call_target_register_ = nullptr;
- // Stores the state of the caller for TurboAssembler::CallCFunction so that
- // the sampling CPU profiler can iterate the stack during such calls. These
- // are stored on IsolateData so that they can be stored to with only one move
- // instruction in compiled code.
- Address fast_c_call_caller_fp_ = kNullAddress;
- Address fast_c_call_caller_pc_ = kNullAddress;
// Whether the SafeStackFrameIterator can successfully iterate the current
// stack. Only valid values are 0 or 1.
uint8_t stack_is_iterable_ = 1;
@@ -225,6 +239,7 @@ void IsolateData::AssertPredictableLayout() {
kFastCCallCallerFPOffset);
STATIC_ASSERT(offsetof(IsolateData, fast_c_call_caller_pc_) ==
kFastCCallCallerPCOffset);
+ STATIC_ASSERT(offsetof(IsolateData, stack_guard_) == kStackGuardOffset);
STATIC_ASSERT(offsetof(IsolateData, stack_is_iterable_) ==
kStackIsIterableOffset);
STATIC_ASSERT(sizeof(IsolateData) == IsolateData::kSize);
diff --git a/deps/v8/src/execution/isolate-inl.h b/deps/v8/src/execution/isolate-inl.h
index 7e037fb410..e1b021b921 100644
--- a/deps/v8/src/execution/isolate-inl.h
+++ b/deps/v8/src/execution/isolate-inl.h
@@ -119,25 +119,6 @@ bool Isolate::IsArrayConstructorIntact() {
return array_constructor_cell.value() == Smi::FromInt(kProtectorValid);
}
-bool Isolate::IsArraySpeciesLookupChainIntact() {
- // Note: It would be nice to have debug checks to make sure that the
- // species protector is accurate, but this would be hard to do for most of
- // what the protector stands for:
- // - You'd need to traverse the heap to check that no Array instance has
- // a constructor property
- // - To check that Array[Symbol.species] == Array, JS code has to execute,
- // but JS cannot be invoked in callstack overflow situations
- // All that could be checked reliably is that
- // Array.prototype.constructor == Array. Given that limitation, no check is
- // done here. In place, there are mjsunit tests harmony/array-species* which
- // ensure that behavior is correct in various invalid protector cases.
-
- PropertyCell species_cell =
- PropertyCell::cast(root(RootIndex::kArraySpeciesProtector));
- return species_cell.value().IsSmi() &&
- Smi::ToInt(species_cell.value()) == kProtectorValid;
-}
-
bool Isolate::IsTypedArraySpeciesLookupChainIntact() {
PropertyCell species_cell =
PropertyCell::cast(root(RootIndex::kTypedArraySpeciesProtector));
@@ -145,14 +126,6 @@ bool Isolate::IsTypedArraySpeciesLookupChainIntact() {
Smi::ToInt(species_cell.value()) == kProtectorValid;
}
-bool Isolate::IsRegExpSpeciesLookupChainIntact(
- Handle<NativeContext> native_context) {
- DCHECK_EQ(*native_context, this->raw_native_context());
- PropertyCell species_cell = native_context->regexp_species_protector();
- return species_cell.value().IsSmi() &&
- Smi::ToInt(species_cell.value()) == kProtectorValid;
-}
-
bool Isolate::IsPromiseSpeciesLookupChainIntact() {
PropertyCell species_cell =
PropertyCell::cast(root(RootIndex::kPromiseSpeciesProtector));
diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc
index 2b3551cdfb..d090ed5260 100644
--- a/deps/v8/src/execution/isolate.cc
+++ b/deps/v8/src/execution/isolate.cc
@@ -56,6 +56,7 @@
#include "src/objects/hash-table-inl.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/js-generator-inl.h"
+#include "src/objects/js-weak-refs-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/promise-inl.h"
#include "src/objects/prototype.h"
@@ -85,9 +86,9 @@
#include "unicode/uobject.h"
#endif // V8_INTL_SUPPORT
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
#include "src/diagnostics/unwinding-info-win64.h"
-#endif
+#endif // V8_OS_WIN64
extern "C" const uint8_t* v8_Default_embedded_blob_;
extern "C" uint32_t v8_Default_embedded_blob_size_;
@@ -2022,7 +2023,7 @@ void Isolate::CancelScheduledExceptionFromTryCatch(v8::TryCatch* handler) {
DCHECK_EQ(scheduled_exception(),
ReadOnlyRoots(heap()).termination_exception());
// Clear termination once we returned from all V8 frames.
- if (handle_scope_implementer()->CallDepthIsZero()) {
+ if (thread_local_top()->CallDepthIsZero()) {
thread_local_top()->external_caught_exception_ = false;
clear_scheduled_exception();
}
@@ -2648,21 +2649,12 @@ Handle<Context> Isolate::GetIncumbentContext() {
char* Isolate::ArchiveThread(char* to) {
MemCopy(to, reinterpret_cast<char*>(thread_local_top()),
sizeof(ThreadLocalTop));
- InitializeThreadLocal();
- clear_pending_exception();
- clear_pending_message();
- clear_scheduled_exception();
return to + sizeof(ThreadLocalTop);
}
char* Isolate::RestoreThread(char* from) {
MemCopy(reinterpret_cast<char*>(thread_local_top()), from,
sizeof(ThreadLocalTop));
-// This might be just paranoia, but it seems to be needed in case a
-// thread_local_top_ is restored on a separate OS thread.
-#ifdef USE_SIMULATOR
- thread_local_top()->simulator_ = Simulator::current(this);
-#endif
DCHECK(context().is_null() || context().IsContext());
return from + sizeof(ThreadLocalTop);
}
@@ -2884,9 +2876,9 @@ v8::PageAllocator* Isolate::page_allocator() {
}
Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator)
- : isolate_allocator_(std::move(isolate_allocator)),
+ : isolate_data_(this),
+ isolate_allocator_(std::move(isolate_allocator)),
id_(isolate_counter.fetch_add(1, std::memory_order_relaxed)),
- stack_guard_(this),
allocator_(FLAG_trace_zone_stats
? new VerboseAccountingAllocator(&heap_, 256 * KB)
: new AccountingAllocator()),
@@ -2925,6 +2917,14 @@ void Isolate::CheckIsolateLayout() {
CHECK_EQ(OFFSET_OF(Isolate, isolate_data_), 0);
CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, isolate_data_.embedder_data_)),
Internals::kIsolateEmbedderDataOffset);
+ CHECK_EQ(static_cast<int>(
+ OFFSET_OF(Isolate, isolate_data_.fast_c_call_caller_fp_)),
+ Internals::kIsolateFastCCallCallerFpOffset);
+ CHECK_EQ(static_cast<int>(
+ OFFSET_OF(Isolate, isolate_data_.fast_c_call_caller_pc_)),
+ Internals::kIsolateFastCCallCallerPcOffset);
+ CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, isolate_data_.stack_guard_)),
+ Internals::kIsolateStackGuardOffset);
CHECK_EQ(static_cast<int>(OFFSET_OF(Isolate, isolate_data_.roots_)),
Internals::kIsolateRootsOffset);
CHECK_EQ(Internals::kExternalMemoryOffset % 8, 0);
@@ -2961,7 +2961,7 @@ void Isolate::Deinit() {
heap_profiler()->StopSamplingHeapProfiler();
}
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
if (win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange() &&
heap()->memory_allocator()) {
const base::AddressRegion& code_range =
@@ -2969,7 +2969,7 @@ void Isolate::Deinit() {
void* start = reinterpret_cast<void*>(code_range.begin());
win64_unwindinfo::UnregisterNonABICompliantCodeRange(start);
}
-#endif
+#endif // V8_OS_WIN64
debug()->Unload();
@@ -3139,7 +3139,12 @@ Isolate::~Isolate() {
default_microtask_queue_ = nullptr;
}
-void Isolate::InitializeThreadLocal() { thread_local_top()->Initialize(this); }
+void Isolate::InitializeThreadLocal() {
+ thread_local_top()->Initialize(this);
+ clear_pending_exception();
+ clear_pending_message();
+ clear_scheduled_exception();
+}
void Isolate::SetTerminationOnExternalTryCatch() {
if (try_catch_handler() == nullptr) return;
@@ -3308,19 +3313,31 @@ bool Isolate::InitWithSnapshot(ReadOnlyDeserializer* read_only_deserializer,
return Init(read_only_deserializer, startup_deserializer);
}
-static void AddCrashKeysForIsolateAndHeapPointers(Isolate* isolate) {
- v8::Platform* platform = V8::GetCurrentPlatform();
+static std::string AddressToString(uintptr_t address) {
+ std::stringstream stream_address;
+ stream_address << "0x" << std::hex << address;
+ return stream_address.str();
+}
+
+void Isolate::AddCrashKeysForIsolateAndHeapPointers() {
+ DCHECK_NOT_NULL(add_crash_key_callback_);
- const int id = isolate->id();
- platform->AddCrashKey(id, "isolate", reinterpret_cast<uintptr_t>(isolate));
+ const uintptr_t isolate_address = reinterpret_cast<uintptr_t>(this);
+ add_crash_key_callback_(v8::CrashKeyId::kIsolateAddress,
+ AddressToString(isolate_address));
- auto heap = isolate->heap();
- platform->AddCrashKey(id, "ro_space",
- reinterpret_cast<uintptr_t>(heap->read_only_space()->first_page()));
- platform->AddCrashKey(id, "map_space",
- reinterpret_cast<uintptr_t>(heap->map_space()->first_page()));
- platform->AddCrashKey(id, "code_space",
- reinterpret_cast<uintptr_t>(heap->code_space()->first_page()));
+ const uintptr_t ro_space_firstpage_address =
+ reinterpret_cast<uintptr_t>(heap()->read_only_space()->first_page());
+ add_crash_key_callback_(v8::CrashKeyId::kReadonlySpaceFirstPageAddress,
+ AddressToString(ro_space_firstpage_address));
+ const uintptr_t map_space_firstpage_address =
+ reinterpret_cast<uintptr_t>(heap()->map_space()->first_page());
+ add_crash_key_callback_(v8::CrashKeyId::kMapSpaceFirstPageAddress,
+ AddressToString(map_space_firstpage_address));
+ const uintptr_t code_space_firstpage_address =
+ reinterpret_cast<uintptr_t>(heap()->code_space()->first_page());
+ add_crash_key_callback_(v8::CrashKeyId::kCodeSpaceFirstPageAddress,
+ AddressToString(code_space_firstpage_address));
}
bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer,
@@ -3343,9 +3360,6 @@ bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer,
// The initialization process does not handle memory exhaustion.
AlwaysAllocateScope always_allocate(this);
- // Safe after setting Heap::isolate_, and initializing StackGuard
- heap_.SetStackLimits();
-
#define ASSIGN_ELEMENT(CamelName, hacker_name) \
isolate_addresses_[IsolateAddressId::k##CamelName##Address] = \
reinterpret_cast<Address>(hacker_name##_address());
@@ -3379,7 +3393,7 @@ bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer,
// will ensure this too, but we don't have to use lockers if we are only
// using one thread.
ExecutionAccess lock(this);
- stack_guard_.InitThread(lock);
+ stack_guard()->InitThread(lock);
}
// SetUp the object heap.
@@ -3524,10 +3538,6 @@ bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer,
clear_pending_message();
clear_scheduled_exception();
- // Deserializing may put strange things in the root array's copy of the
- // stack guard.
- heap_.SetStackLimits();
-
// Quiet the heap NaN if needed on target platform.
if (!create_heap_objects)
Assembler::QuietNaN(ReadOnlyRoots(this).nan_value());
@@ -3553,7 +3563,7 @@ bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer,
sampling_flags);
}
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
if (win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange()) {
const base::AddressRegion& code_range =
heap()->memory_allocator()->code_range();
@@ -3561,14 +3571,13 @@ bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer,
size_t size_in_bytes = code_range.size();
win64_unwindinfo::RegisterNonABICompliantCodeRange(start, size_in_bytes);
}
-#endif
+#endif // V8_OS_WIN64
if (create_heap_objects && FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF();
PrintF("[Initializing isolate from scratch took %0.3f ms]\n", ms);
}
- AddCrashKeysForIsolateAndHeapPointers(this);
return true;
}
@@ -3990,15 +3999,6 @@ void Isolate::InvalidateArrayConstructorProtector() {
DCHECK(!IsArrayConstructorIntact());
}
-void Isolate::InvalidateArraySpeciesProtector() {
- DCHECK(factory()->array_species_protector()->value().IsSmi());
- DCHECK(IsArraySpeciesLookupChainIntact());
- PropertyCell::SetValueWithInvalidation(
- this, "array_species_protector", factory()->array_species_protector(),
- handle(Smi::FromInt(kProtectorInvalid), this));
- DCHECK(!IsArraySpeciesLookupChainIntact());
-}
-
void Isolate::InvalidateTypedArraySpeciesProtector() {
DCHECK(factory()->typed_array_species_protector()->value().IsSmi());
DCHECK(IsTypedArraySpeciesLookupChainIntact());
@@ -4009,19 +4009,6 @@ void Isolate::InvalidateTypedArraySpeciesProtector() {
DCHECK(!IsTypedArraySpeciesLookupChainIntact());
}
-void Isolate::InvalidateRegExpSpeciesProtector(
- Handle<NativeContext> native_context) {
- DCHECK_EQ(*native_context, this->raw_native_context());
- DCHECK(native_context->regexp_species_protector().value().IsSmi());
- DCHECK(IsRegExpSpeciesLookupChainIntact(native_context));
- Handle<PropertyCell> species_cell(native_context->regexp_species_protector(),
- this);
- PropertyCell::SetValueWithInvalidation(
- this, "regexp_species_protector", species_cell,
- handle(Smi::FromInt(kProtectorInvalid), this));
- DCHECK(!IsRegExpSpeciesLookupChainIntact(native_context));
-}
-
void Isolate::InvalidatePromiseSpeciesProtector() {
DCHECK(factory()->promise_species_protector()->value().IsSmi());
DCHECK(IsPromiseSpeciesLookupChainIntact());
@@ -4189,7 +4176,7 @@ Handle<Symbol> Isolate::SymbolFor(RootIndex dictionary_index,
PropertyDetails::Empty(), &entry);
switch (dictionary_index) {
case RootIndex::kPublicSymbolTable:
- symbol->set_is_public(true);
+ symbol->set_is_in_public_symbol_table(true);
heap()->set_public_symbol_table(*dictionary);
break;
case RootIndex::kApiSymbolTable:
@@ -4237,7 +4224,7 @@ void Isolate::RemoveCallCompletedCallback(CallCompletedCallback callback) {
}
void Isolate::FireCallCompletedCallback(MicrotaskQueue* microtask_queue) {
- if (!handle_scope_implementer()->CallDepthIsZero()) return;
+ if (!thread_local_top()->CallDepthIsZero()) return;
bool run_microtasks =
microtask_queue && microtask_queue->size() &&
@@ -4246,12 +4233,6 @@ void Isolate::FireCallCompletedCallback(MicrotaskQueue* microtask_queue) {
if (run_microtasks) {
microtask_queue->RunMicrotasks(this);
- } else {
- // TODO(marja): (spec) The discussion about when to clear the KeepDuringJob
- // set is still open (whether to clear it after every microtask or once
- // during a microtask checkpoint). See also
- // https://github.com/tc39/proposal-weakrefs/issues/39 .
- heap()->ClearKeptObjects();
}
if (call_completed_callbacks_.empty()) return;
@@ -4330,6 +4311,23 @@ MaybeHandle<JSPromise> Isolate::RunHostImportModuleDynamicallyCallback(
return v8::Utils::OpenHandle(*promise);
}
+void Isolate::ClearKeptObjects() { heap()->ClearKeptObjects(); }
+
+void Isolate::SetHostCleanupFinalizationGroupCallback(
+ HostCleanupFinalizationGroupCallback callback) {
+ host_cleanup_finalization_group_callback_ = callback;
+}
+
+void Isolate::RunHostCleanupFinalizationGroupCallback(
+ Handle<JSFinalizationGroup> fg) {
+ if (host_cleanup_finalization_group_callback_ != nullptr) {
+ v8::Local<v8::Context> api_context =
+ v8::Utils::ToLocal(handle(Context::cast(fg->native_context()), this));
+ host_cleanup_finalization_group_callback_(api_context,
+ v8::Utils::ToLocal(fg));
+ }
+}
+
void Isolate::SetHostImportModuleDynamicallyCallback(
HostImportModuleDynamicallyCallback callback) {
host_import_module_dynamically_callback_ = callback;
@@ -4337,7 +4335,7 @@ void Isolate::SetHostImportModuleDynamicallyCallback(
Handle<JSObject> Isolate::RunHostInitializeImportMetaObjectCallback(
Handle<SourceTextModule> module) {
- Handle<Object> host_meta(module->import_meta(), this);
+ Handle<HeapObject> host_meta(module->import_meta(), this);
if (host_meta->IsTheHole(this)) {
host_meta = factory()->NewJSObjectWithNullProto();
if (host_initialize_import_meta_object_callback_ != nullptr) {
@@ -4399,7 +4397,7 @@ void Isolate::PrepareBuiltinSourcePositionMap() {
}
}
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
void Isolate::SetBuiltinUnwindData(
int builtin_index,
const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) {
@@ -4407,7 +4405,7 @@ void Isolate::SetBuiltinUnwindData(
embedded_file_writer_->SetBuiltinUnwindData(builtin_index, unwinding_info);
}
}
-#endif
+#endif // V8_OS_WIN64
void Isolate::SetPrepareStackTraceCallback(PrepareStackTraceCallback callback) {
prepare_stack_trace_callback_ = callback;
@@ -4417,6 +4415,13 @@ bool Isolate::HasPrepareStackTraceCallback() const {
return prepare_stack_trace_callback_ != nullptr;
}
+void Isolate::SetAddCrashKeyCallback(AddCrashKeyCallback callback) {
+ add_crash_key_callback_ = callback;
+
+ // Log the initial set of data.
+ AddCrashKeysForIsolateAndHeapPointers();
+}
+
void Isolate::SetAtomicsWaitCallback(v8::Isolate::AtomicsWaitCallback callback,
void* data) {
atomics_wait_callback_ = callback;
@@ -4663,6 +4668,27 @@ void Isolate::SetIdle(bool is_idle) {
}
}
+void Isolate::CollectSourcePositionsForAllBytecodeArrays() {
+ HandleScope scope(this);
+ std::vector<Handle<SharedFunctionInfo>> sfis;
+ {
+ DisallowHeapAllocation no_gc;
+ HeapObjectIterator iterator(heap());
+ for (HeapObject obj = iterator.Next(); !obj.is_null();
+ obj = iterator.Next()) {
+ if (obj.IsSharedFunctionInfo()) {
+ SharedFunctionInfo sfi = SharedFunctionInfo::cast(obj);
+ if (sfi.HasBytecodeArray()) {
+ sfis.push_back(Handle<SharedFunctionInfo>(sfi, this));
+ }
+ }
+ }
+ }
+ for (auto sfi : sfis) {
+ SharedFunctionInfo::EnsureSourcePositionsAvailable(this, sfi);
+ }
+}
+
#ifdef V8_INTL_SUPPORT
icu::UMemory* Isolate::get_cached_icu_object(ICUObjectCacheType cache_type) {
return icu_object_cache_[cache_type].get();
diff --git a/deps/v8/src/execution/isolate.h b/deps/v8/src/execution/isolate.h
index 2ead7bf844..4eadb42438 100644
--- a/deps/v8/src/execution/isolate.h
+++ b/deps/v8/src/execution/isolate.h
@@ -404,6 +404,7 @@ using DebugObjectCache = std::vector<Handle<HeapObject>>;
V(ExtensionCallback, wasm_instance_callback, &NoExtension) \
V(WasmStreamingCallback, wasm_streaming_callback, nullptr) \
V(WasmThreadsEnabledCallback, wasm_threads_enabled_callback, nullptr) \
+ V(WasmLoadSourceMapCallback, wasm_load_source_map_callback, nullptr) \
/* State for Relocatable. */ \
V(Relocatable*, relocatable_top, nullptr) \
V(DebugObjectCache*, string_stream_debug_object_cache, nullptr) \
@@ -902,7 +903,7 @@ class Isolate final : private HiddenFactory {
DCHECK_NOT_NULL(logger_);
return logger_;
}
- StackGuard* stack_guard() { return &stack_guard_; }
+ StackGuard* stack_guard() { return isolate_data()->stack_guard(); }
Heap* heap() { return &heap_; }
ReadOnlyHeap* read_only_heap() const { return read_only_heap_; }
static Isolate* FromHeap(Heap* heap) {
@@ -959,6 +960,7 @@ class Isolate final : private HiddenFactory {
void set_deoptimizer_lazy_throw(bool value) {
deoptimizer_lazy_throw_ = value;
}
+ void InitializeThreadLocal();
ThreadLocalTop* thread_local_top() {
return &isolate_data_.thread_local_top_;
}
@@ -1174,10 +1176,7 @@ class Isolate final : private HiddenFactory {
bool IsArrayOrObjectOrStringPrototype(Object object);
- inline bool IsArraySpeciesLookupChainIntact();
inline bool IsTypedArraySpeciesLookupChainIntact();
- inline bool IsRegExpSpeciesLookupChainIntact(
- Handle<NativeContext> native_context);
// Check that the @@species protector is intact, which guards the lookup of
// "constructor" on JSPromise instances, whose [[Prototype]] is the initial
@@ -1264,7 +1263,6 @@ class Isolate final : private HiddenFactory {
void TraceProtectorInvalidation(const char* protector_name);
void InvalidateArrayConstructorProtector();
- void InvalidateArraySpeciesProtector();
void InvalidateTypedArraySpeciesProtector();
void InvalidateRegExpSpeciesProtector(Handle<NativeContext> native_context);
void InvalidatePromiseSpeciesProtector();
@@ -1473,6 +1471,11 @@ class Isolate final : private HiddenFactory {
bool IsInAnyContext(Object object, uint32_t index);
+ void ClearKeptObjects();
+ void SetHostCleanupFinalizationGroupCallback(
+ HostCleanupFinalizationGroupCallback callback);
+ void RunHostCleanupFinalizationGroupCallback(Handle<JSFinalizationGroup> fg);
+
void SetHostImportModuleDynamicallyCallback(
HostImportModuleDynamicallyCallback callback);
V8_EXPORT_PRIVATE MaybeHandle<JSPromise>
@@ -1497,11 +1500,11 @@ class Isolate final : private HiddenFactory {
// annotate the builtin blob with debugging information.
void PrepareBuiltinSourcePositionMap();
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
void SetBuiltinUnwindData(
int builtin_index,
const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info);
-#endif
+#endif // V8_OS_WIN64
void SetPrepareStackTraceCallback(PrepareStackTraceCallback callback);
MaybeHandle<Object> RunPrepareStackTraceCallback(Handle<Context>,
@@ -1509,6 +1512,8 @@ class Isolate final : private HiddenFactory {
Handle<JSArray> sites);
bool HasPrepareStackTraceCallback() const;
+ void SetAddCrashKeyCallback(AddCrashKeyCallback callback);
+
void SetRAILMode(RAILMode rail_mode);
RAILMode rail_mode() { return rail_mode_.load(); }
@@ -1558,6 +1563,11 @@ class Isolate final : private HiddenFactory {
V8_EXPORT_PRIVATE void SetIdle(bool is_idle);
+ // Changing various modes can cause differences in generated bytecode which
+ // interferes with lazy source positions, so this should be called immediately
+ // before such a mode change to ensure that this cannot happen.
+ V8_EXPORT_PRIVATE void CollectSourcePositionsForAllBytecodeArrays();
+
private:
explicit Isolate(std::unique_ptr<IsolateAllocator> isolate_allocator);
~Isolate();
@@ -1622,8 +1632,6 @@ class Isolate final : private HiddenFactory {
static void SetIsolateThreadLocals(Isolate* isolate,
PerIsolateThreadData* data);
- void InitializeThreadLocal();
-
void MarkCompactPrologue(bool is_compacting,
ThreadLocalTop* archived_thread_data);
void MarkCompactEpilogue(bool is_compacting,
@@ -1653,6 +1661,8 @@ class Isolate final : private HiddenFactory {
return "";
}
+ void AddCrashKeysForIsolateAndHeapPointers();
+
// This class contains a collection of data accessible from both C++ runtime
// and compiled code (including assembly stubs, builtins, interpreter bytecode
// handlers and optimized code).
@@ -1673,7 +1683,6 @@ class Isolate final : private HiddenFactory {
std::shared_ptr<Counters> async_counters_;
base::RecursiveMutex break_access_;
Logger* logger_ = nullptr;
- StackGuard stack_guard_;
StubCache* load_stub_cache_ = nullptr;
StubCache* store_stub_cache_ = nullptr;
DeoptimizerData* deoptimizer_data_ = nullptr;
@@ -1710,6 +1719,8 @@ class Isolate final : private HiddenFactory {
v8::Isolate::AtomicsWaitCallback atomics_wait_callback_ = nullptr;
void* atomics_wait_callback_data_ = nullptr;
PromiseHook promise_hook_ = nullptr;
+ HostCleanupFinalizationGroupCallback
+ host_cleanup_finalization_group_callback_ = nullptr;
HostImportModuleDynamicallyCallback host_import_module_dynamically_callback_ =
nullptr;
HostInitializeImportMetaObjectCallback
@@ -1770,6 +1781,8 @@ class Isolate final : private HiddenFactory {
interpreter::Interpreter* interpreter_ = nullptr;
compiler::PerIsolateCompilerCache* compiler_cache_ = nullptr;
+ // The following zone is for compiler-related objects that should live
+ // through all compilations (and thus all JSHeapBroker instances).
Zone* compiler_zone_ = nullptr;
CompilerDispatcher* compiler_dispatcher_ = nullptr;
@@ -1877,6 +1890,11 @@ class Isolate final : private HiddenFactory {
base::Mutex thread_data_table_mutex_;
ThreadDataTable thread_data_table_;
+ // Enables the host application to provide a mechanism for recording a
+ // predefined set of data as crash keys to be used in postmortem debugging
+ // in case of a crash.
+ AddCrashKeyCallback add_crash_key_callback_ = nullptr;
+
// Delete new/delete operators to ensure that Isolate::New() and
// Isolate::Delete() are used for Isolate creation and deletion.
void* operator new(size_t, void* ptr) { return ptr; }
@@ -1930,6 +1948,14 @@ class V8_EXPORT_PRIVATE SaveAndSwitchContext : public SaveContext {
SaveAndSwitchContext(Isolate* isolate, Context new_context);
};
+// A scope which sets the given isolate's context to null for its lifetime to
+// ensure that code does not make assumptions on a context being available.
+class NullContextScope : public SaveAndSwitchContext {
+ public:
+ explicit NullContextScope(Isolate* isolate)
+ : SaveAndSwitchContext(isolate, Context()) {}
+};
+
class AssertNoContextChange {
#ifdef DEBUG
public:
diff --git a/deps/v8/src/execution/messages.cc b/deps/v8/src/execution/messages.cc
index d216d3bc39..63d1e2be1f 100644
--- a/deps/v8/src/execution/messages.cc
+++ b/deps/v8/src/execution/messages.cc
@@ -7,8 +7,11 @@
#include <memory>
#include "src/api/api-inl.h"
+#include "src/ast/ast.h"
+#include "src/ast/prettyprinter.h"
#include "src/base/v8-fallthrough.h"
#include "src/execution/execution.h"
+#include "src/execution/frames-inl.h"
#include "src/execution/frames.h"
#include "src/execution/isolate-inl.h"
#include "src/logging/counters.h"
@@ -18,6 +21,9 @@
#include "src/objects/keys.h"
#include "src/objects/stack-frame-info-inl.h"
#include "src/objects/struct-inl.h"
+#include "src/parsing/parse-info.h"
+#include "src/parsing/parsing.h"
+#include "src/roots/roots.h"
#include "src/strings/string-builder-inl.h"
#include "src/wasm/wasm-code-manager.h"
#include "src/wasm/wasm-objects.h"
@@ -314,6 +320,10 @@ Handle<Object> StackFrameBase::GetWasmModuleName() {
return isolate_->factory()->undefined_value();
}
+Handle<Object> StackFrameBase::GetWasmInstance() {
+ return isolate_->factory()->undefined_value();
+}
+
int StackFrameBase::GetScriptId() const {
if (!HasScript()) return kNone;
return GetScript()->id();
@@ -332,6 +342,7 @@ void JSStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
function_ = handle(array->Function(frame_ix), isolate);
code_ = handle(array->Code(frame_ix), isolate);
offset_ = array->Offset(frame_ix).value();
+ cached_position_ = base::nullopt;
const int flags = array->Flags(frame_ix).value();
is_constructor_ = (flags & FrameArray::kIsConstructor) != 0;
@@ -348,6 +359,7 @@ JSStackFrame::JSStackFrame(Isolate* isolate, Handle<Object> receiver,
function_(function),
code_(code),
offset_(offset),
+ cached_position_(base::nullopt),
is_async_(false),
is_constructor_(false),
is_strict_(false) {}
@@ -512,9 +524,12 @@ bool JSStackFrame::IsToplevel() {
}
int JSStackFrame::GetPosition() const {
+ if (cached_position_) return *cached_position_;
+
Handle<SharedFunctionInfo> shared = handle(function_->shared(), isolate_);
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate_, shared);
- return code_->SourcePosition(offset_);
+ cached_position_ = code_->SourcePosition(offset_);
+ return *cached_position_;
}
bool JSStackFrame::HasScript() const {
@@ -575,6 +590,8 @@ Handle<Object> WasmStackFrame::GetWasmModuleName() {
return module_name;
}
+Handle<Object> WasmStackFrame::GetWasmInstance() { return wasm_instance_; }
+
int WasmStackFrame::GetPosition() const {
return IsInterpreted()
? offset_
@@ -1155,5 +1172,232 @@ MaybeHandle<Object> ErrorUtils::MakeGenericError(
no_caller, StackTraceCollection::kDetailed);
}
+namespace {
+
+bool ComputeLocation(Isolate* isolate, MessageLocation* target) {
+ JavaScriptFrameIterator it(isolate);
+ if (!it.done()) {
+ // Compute the location from the function and the relocation info of the
+ // baseline code. For optimized code this will use the deoptimization
+ // information to get canonical location information.
+ std::vector<FrameSummary> frames;
+ it.frame()->Summarize(&frames);
+ auto& summary = frames.back().AsJavaScript();
+ Handle<SharedFunctionInfo> shared(summary.function()->shared(), isolate);
+ Handle<Object> script(shared->script(), isolate);
+ SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared);
+ int pos = summary.abstract_code()->SourcePosition(summary.code_offset());
+ if (script->IsScript() &&
+ !(Handle<Script>::cast(script)->source().IsUndefined(isolate))) {
+ Handle<Script> casted_script = Handle<Script>::cast(script);
+ *target = MessageLocation(casted_script, pos, pos + 1, shared);
+ return true;
+ }
+ }
+ return false;
+}
+
+Handle<String> BuildDefaultCallSite(Isolate* isolate, Handle<Object> object) {
+ IncrementalStringBuilder builder(isolate);
+
+ builder.AppendString(Object::TypeOf(isolate, object));
+ if (object->IsString()) {
+ builder.AppendCString(" \"");
+ builder.AppendString(Handle<String>::cast(object));
+ builder.AppendCString("\"");
+ } else if (object->IsNull(isolate)) {
+ builder.AppendCString(" ");
+ builder.AppendString(isolate->factory()->null_string());
+ } else if (object->IsTrue(isolate)) {
+ builder.AppendCString(" ");
+ builder.AppendString(isolate->factory()->true_string());
+ } else if (object->IsFalse(isolate)) {
+ builder.AppendCString(" ");
+ builder.AppendString(isolate->factory()->false_string());
+ } else if (object->IsNumber()) {
+ builder.AppendCString(" ");
+ builder.AppendString(isolate->factory()->NumberToString(object));
+ }
+
+ return builder.Finish().ToHandleChecked();
+}
+
+Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object,
+ MessageLocation* location,
+ CallPrinter::ErrorHint* hint) {
+ if (ComputeLocation(isolate, location)) {
+ ParseInfo info(isolate, location->shared());
+ if (parsing::ParseAny(&info, location->shared(), isolate)) {
+ info.ast_value_factory()->Internalize(isolate);
+ CallPrinter printer(isolate, location->shared()->IsUserJavaScript());
+ Handle<String> str = printer.Print(info.literal(), location->start_pos());
+ *hint = printer.GetErrorHint();
+ if (str->length() > 0) return str;
+ } else {
+ isolate->clear_pending_exception();
+ }
+ }
+ return BuildDefaultCallSite(isolate, object);
+}
+
+MessageTemplate UpdateErrorTemplate(CallPrinter::ErrorHint hint,
+ MessageTemplate default_id) {
+ switch (hint) {
+ case CallPrinter::ErrorHint::kNormalIterator:
+ return MessageTemplate::kNotIterable;
+
+ case CallPrinter::ErrorHint::kCallAndNormalIterator:
+ return MessageTemplate::kNotCallableOrIterable;
+
+ case CallPrinter::ErrorHint::kAsyncIterator:
+ return MessageTemplate::kNotAsyncIterable;
+
+ case CallPrinter::ErrorHint::kCallAndAsyncIterator:
+ return MessageTemplate::kNotCallableOrAsyncIterable;
+
+ case CallPrinter::ErrorHint::kNone:
+ return default_id;
+ }
+ return default_id;
+}
+
+} // namespace
+
+Handle<Object> ErrorUtils::NewIteratorError(Isolate* isolate,
+ Handle<Object> source) {
+ MessageLocation location;
+ CallPrinter::ErrorHint hint = CallPrinter::kNone;
+ Handle<String> callsite = RenderCallSite(isolate, source, &location, &hint);
+ MessageTemplate id = MessageTemplate::kNotIterableNoSymbolLoad;
+
+ if (hint == CallPrinter::kNone) {
+ Handle<Symbol> iterator_symbol = isolate->factory()->iterator_symbol();
+ return isolate->factory()->NewTypeError(id, callsite, iterator_symbol);
+ }
+
+ id = UpdateErrorTemplate(hint, id);
+ return isolate->factory()->NewTypeError(id, callsite);
+}
+
+Handle<Object> ErrorUtils::NewCalledNonCallableError(Isolate* isolate,
+ Handle<Object> source) {
+ MessageLocation location;
+ CallPrinter::ErrorHint hint = CallPrinter::kNone;
+ Handle<String> callsite = RenderCallSite(isolate, source, &location, &hint);
+ MessageTemplate id = MessageTemplate::kCalledNonCallable;
+ id = UpdateErrorTemplate(hint, id);
+ return isolate->factory()->NewTypeError(id, callsite);
+}
+
+Handle<Object> ErrorUtils::NewConstructedNonConstructable(
+ Isolate* isolate, Handle<Object> source) {
+ MessageLocation location;
+ CallPrinter::ErrorHint hint = CallPrinter::kNone;
+ Handle<String> callsite = RenderCallSite(isolate, source, &location, &hint);
+ MessageTemplate id = MessageTemplate::kNotConstructor;
+ return isolate->factory()->NewTypeError(id, callsite);
+}
+
+Object ErrorUtils::ThrowLoadFromNullOrUndefined(Isolate* isolate,
+ Handle<Object> object) {
+ return ThrowLoadFromNullOrUndefined(isolate, object, MaybeHandle<Object>());
+}
+Object ErrorUtils::ThrowLoadFromNullOrUndefined(Isolate* isolate,
+ Handle<Object> object,
+ MaybeHandle<Object> key) {
+ DCHECK(object->IsNullOrUndefined());
+
+ MaybeHandle<String> maybe_property_name;
+
+ // Try to extract the property name from the given key, if any.
+ Handle<Object> key_handle;
+ if (key.ToHandle(&key_handle)) {
+ if (key_handle->IsString()) {
+ maybe_property_name = Handle<String>::cast(key_handle);
+ }
+ }
+
+ Handle<String> callsite;
+
+ // Inline the RenderCallSite logic here so that we can additonally access the
+ // destructuring property.
+ bool location_computed = false;
+ bool is_destructuring = false;
+ MessageLocation location;
+ if (ComputeLocation(isolate, &location)) {
+ location_computed = true;
+
+ ParseInfo info(isolate, location.shared());
+ if (parsing::ParseAny(&info, location.shared(), isolate)) {
+ info.ast_value_factory()->Internalize(isolate);
+ CallPrinter printer(isolate, location.shared()->IsUserJavaScript());
+ Handle<String> str = printer.Print(info.literal(), location.start_pos());
+
+ int pos = -1;
+ is_destructuring = printer.destructuring_assignment() != nullptr;
+
+ if (is_destructuring) {
+ // If we don't have one yet, try to extract the property name from the
+ // destructuring property in the AST.
+ ObjectLiteralProperty* destructuring_prop =
+ printer.destructuring_prop();
+ if (maybe_property_name.is_null() && destructuring_prop != nullptr &&
+ destructuring_prop->key()->IsPropertyName()) {
+ maybe_property_name = destructuring_prop->key()
+ ->AsLiteral()
+ ->AsRawPropertyName()
+ ->string();
+ // Change the message location to point at the property name.
+ pos = destructuring_prop->key()->position();
+ }
+ if (maybe_property_name.is_null()) {
+ // Change the message location to point at the destructured value.
+ pos = printer.destructuring_assignment()->value()->position();
+ }
+
+ // If we updated the pos to a valid pos, rewrite the location.
+ if (pos != -1) {
+ location = MessageLocation(location.script(), pos, pos + 1,
+ location.shared());
+ }
+ }
+
+ if (str->length() > 0) callsite = str;
+ } else {
+ isolate->clear_pending_exception();
+ }
+ }
+
+ if (callsite.is_null()) {
+ callsite = BuildDefaultCallSite(isolate, object);
+ }
+
+ Handle<Object> error;
+ Handle<String> property_name;
+ if (is_destructuring) {
+ if (maybe_property_name.ToHandle(&property_name)) {
+ error = isolate->factory()->NewTypeError(
+ MessageTemplate::kNonCoercibleWithProperty, property_name, callsite,
+ object);
+ } else {
+ error = isolate->factory()->NewTypeError(MessageTemplate::kNonCoercible,
+ callsite, object);
+ }
+ } else {
+ Handle<Object> key_handle;
+ if (!key.ToHandle(&key_handle)) {
+ key_handle = ReadOnlyRoots(isolate).undefined_value_handle();
+ }
+ if (*key_handle == ReadOnlyRoots(isolate).iterator_symbol()) {
+ error = NewIteratorError(isolate, object);
+ } else {
+ error = isolate->factory()->NewTypeError(
+ MessageTemplate::kNonObjectPropertyLoad, key_handle, object);
+ }
+ }
+
+ return isolate->Throw(*error, location_computed ? &location : nullptr);
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/execution/messages.h b/deps/v8/src/execution/messages.h
index 23f32c2fe1..5da2d3a9eb 100644
--- a/deps/v8/src/execution/messages.h
+++ b/deps/v8/src/execution/messages.h
@@ -12,6 +12,7 @@
#include <memory>
+#include "src/base/optional.h"
#include "src/common/message-template.h"
#include "src/handles/handles.h"
@@ -72,6 +73,7 @@ class StackFrameBase {
virtual Handle<Object> GetTypeName() = 0;
virtual Handle<Object> GetEvalOrigin();
virtual Handle<Object> GetWasmModuleName();
+ virtual Handle<Object> GetWasmInstance();
// Returns the script ID if one is attached, -1 otherwise.
int GetScriptId() const;
@@ -146,6 +148,7 @@ class JSStackFrame : public StackFrameBase {
Handle<JSFunction> function_;
Handle<AbstractCode> code_;
int offset_;
+ mutable base::Optional<int> cached_position_;
bool is_async_ : 1;
bool is_constructor_ : 1;
@@ -168,12 +171,13 @@ class WasmStackFrame : public StackFrameBase {
Handle<Object> GetMethodName() override { return Null(); }
Handle<Object> GetTypeName() override { return Null(); }
Handle<Object> GetWasmModuleName() override;
+ Handle<Object> GetWasmInstance() override;
int GetPosition() const override;
int GetLineNumber() override { return wasm_func_index_; }
int GetColumnNumber() override;
- int GetPromiseIndex() const override { return kNone; }
+ int GetPromiseIndex() const override { return GetPosition(); }
bool IsNative() override { return false; }
bool IsToplevel() override { return false; }
@@ -279,6 +283,18 @@ class ErrorUtils : public AllStatic {
static MaybeHandle<Object> FormatStackTrace(Isolate* isolate,
Handle<JSObject> error,
Handle<Object> stack_trace);
+
+ static Handle<Object> NewIteratorError(Isolate* isolate,
+ Handle<Object> source);
+ static Handle<Object> NewCalledNonCallableError(Isolate* isolate,
+ Handle<Object> source);
+ static Handle<Object> NewConstructedNonConstructable(Isolate* isolate,
+ Handle<Object> source);
+ static Object ThrowLoadFromNullOrUndefined(Isolate* isolate,
+ Handle<Object> object);
+ static Object ThrowLoadFromNullOrUndefined(Isolate* isolate,
+ Handle<Object> object,
+ MaybeHandle<Object> key);
};
class MessageFormatter {
diff --git a/deps/v8/src/execution/microtask-queue.cc b/deps/v8/src/execution/microtask-queue.cc
index 3cc95205fa..ed76e9d79c 100644
--- a/deps/v8/src/execution/microtask-queue.cc
+++ b/deps/v8/src/execution/microtask-queue.cc
@@ -159,10 +159,13 @@ int MicrotaskQueue::RunMicrotasks(Isolate* isolate) {
HandleScopeImplementer::EnteredContextRewindScope rewind_scope(
isolate->handle_scope_implementer());
TRACE_EVENT_BEGIN0("v8.execute", "RunMicrotasks");
- TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.RunMicrotasks");
- maybe_result = Execution::TryRunMicrotasks(isolate, this, &maybe_exception);
- processed_microtask_count =
- static_cast<int>(finished_microtask_count_ - base_count);
+ {
+ TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.RunMicrotasks");
+ maybe_result = Execution::TryRunMicrotasks(isolate, this,
+ &maybe_exception);
+ processed_microtask_count =
+ static_cast<int>(finished_microtask_count_ - base_count);
+ }
TRACE_EVENT_END1("v8.execute", "RunMicrotasks", "microtask_count",
processed_microtask_count);
}
@@ -249,12 +252,6 @@ Microtask MicrotaskQueue::get(intptr_t index) const {
}
void MicrotaskQueue::OnCompleted(Isolate* isolate) {
- // TODO(marja): (spec) The discussion about when to clear the KeepDuringJob
- // set is still open (whether to clear it after every microtask or once
- // during a microtask checkpoint). See also
- // https://github.com/tc39/proposal-weakrefs/issues/39 .
- isolate->heap()->ClearKeptObjects();
-
FireMicrotasksCompletedCallback(isolate);
}
diff --git a/deps/v8/src/execution/mips/simulator-mips.cc b/deps/v8/src/execution/mips/simulator-mips.cc
index 6a3a160ec3..2d9a924c14 100644
--- a/deps/v8/src/execution/mips/simulator-mips.cc
+++ b/deps/v8/src/execution/mips/simulator-mips.cc
@@ -2152,7 +2152,7 @@ using SimulatorRuntimeCall = int64_t (*)(int32_t arg0, int32_t arg1,
int32_t arg2, int32_t arg3,
int32_t arg4, int32_t arg5,
int32_t arg6, int32_t arg7,
- int32_t arg8);
+ int32_t arg8, int32_t arg9);
// These prototypes handle the four types of FP calls.
using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1);
@@ -2194,7 +2194,8 @@ void Simulator::SoftwareInterrupt() {
int32_t arg6 = stack_pointer[6];
int32_t arg7 = stack_pointer[7];
int32_t arg8 = stack_pointer[8];
- STATIC_ASSERT(kMaxCParameters == 9);
+ int32_t arg9 = stack_pointer[9];
+ STATIC_ASSERT(kMaxCParameters == 10);
bool fp_call =
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
@@ -2378,12 +2379,12 @@ void Simulator::SoftwareInterrupt() {
if (::v8::internal::FLAG_trace_sim) {
PrintF(
"Call to host function at %p "
- "args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n",
+ "args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n",
reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
- arg3, arg4, arg5, arg6, arg7, arg8);
+ arg3, arg4, arg5, arg6, arg7, arg8, arg9);
}
int64_t result =
- target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+ target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
set_register(v0, static_cast<int32_t>(result));
set_register(v1, static_cast<int32_t>(result >> 32));
}
diff --git a/deps/v8/src/execution/mips64/simulator-mips64.cc b/deps/v8/src/execution/mips64/simulator-mips64.cc
index 3fbf1961a8..78dbc29a0b 100644
--- a/deps/v8/src/execution/mips64/simulator-mips64.cc
+++ b/deps/v8/src/execution/mips64/simulator-mips64.cc
@@ -2159,7 +2159,7 @@ using SimulatorRuntimeCall = ObjectPair (*)(int64_t arg0, int64_t arg1,
int64_t arg2, int64_t arg3,
int64_t arg4, int64_t arg5,
int64_t arg6, int64_t arg7,
- int64_t arg8);
+ int64_t arg8, int64_t arg9);
// These prototypes handle the four types of FP calls.
using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1);
@@ -2200,7 +2200,8 @@ void Simulator::SoftwareInterrupt() {
int64_t arg6 = get_register(a6);
int64_t arg7 = get_register(a7);
int64_t arg8 = stack_pointer[0];
- STATIC_ASSERT(kMaxCParameters == 9);
+ int64_t arg9 = stack_pointer[1];
+ STATIC_ASSERT(kMaxCParameters == 10);
bool fp_call =
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
@@ -2372,12 +2373,12 @@ void Simulator::SoftwareInterrupt() {
"Call to host function at %p "
"args %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
" , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
- " , %08" PRIx64 " \n",
+ " , %08" PRIx64 " , %08" PRIx64 " \n",
reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
- arg3, arg4, arg5, arg6, arg7, arg8);
+ arg3, arg4, arg5, arg6, arg7, arg8, arg9);
}
ObjectPair result =
- target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+ target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
set_register(v0, (int64_t)(result.x));
set_register(v1, (int64_t)(result.y));
}
diff --git a/deps/v8/src/execution/ppc/simulator-ppc.cc b/deps/v8/src/execution/ppc/simulator-ppc.cc
index 96308f7f5b..ab8786713b 100644
--- a/deps/v8/src/execution/ppc/simulator-ppc.cc
+++ b/deps/v8/src/execution/ppc/simulator-ppc.cc
@@ -931,10 +931,12 @@ using SimulatorRuntimeCall = intptr_t (*)(intptr_t arg0, intptr_t arg1,
intptr_t arg2, intptr_t arg3,
intptr_t arg4, intptr_t arg5,
intptr_t arg6, intptr_t arg7,
- intptr_t arg8);
+ intptr_t arg8, intptr_t arg9);
using SimulatorRuntimePairCall = ObjectPair (*)(intptr_t arg0, intptr_t arg1,
intptr_t arg2, intptr_t arg3,
- intptr_t arg4, intptr_t arg5);
+ intptr_t arg4, intptr_t arg5,
+ intptr_t arg6, intptr_t arg7,
+ intptr_t arg8, intptr_t arg9);
// These prototypes handle the four types of FP calls.
using SimulatorRuntimeCompareCall = int (*)(double darg0, double darg1);
@@ -964,7 +966,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
(get_register(sp) & (::v8::internal::FLAG_sim_stack_alignment - 1)) ==
0;
Redirection* redirection = Redirection::FromInstruction(instr);
- const int kArgCount = 9;
+ const int kArgCount = 10;
const int kRegisterArgCount = 8;
int arg0_regnum = 3;
intptr_t result_buffer = 0;
@@ -982,9 +984,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
}
intptr_t* stack_pointer = reinterpret_cast<intptr_t*>(get_register(sp));
// Remaining argument on stack
- arg[kRegisterArgCount] = stack_pointer[kStackFrameExtraParamSlot];
- STATIC_ASSERT(kArgCount == kRegisterArgCount + 1);
- STATIC_ASSERT(kMaxCParameters == 9);
+ for (int i = kRegisterArgCount, j = 0; i < kArgCount; i++, j++) {
+ arg[i] = stack_pointer[kStackFrameExtraParamSlot + j];
+ }
+ STATIC_ASSERT(kArgCount == kRegisterArgCount + 2);
+ STATIC_ASSERT(kMaxCParameters == kArgCount);
bool fp_call =
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
(redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
@@ -1161,9 +1165,10 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
"Call to host function at %p,\n"
"\t\t\t\targs %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
", %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
- ", %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR,
+ ", %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
+ ", %08" V8PRIxPTR,
reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg[0], arg[1],
- arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8]);
+ arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]);
if (!stack_aligned) {
PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
get_register(sp));
@@ -1174,8 +1179,8 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
if (redirection->type() == ExternalReference::BUILTIN_CALL_PAIR) {
SimulatorRuntimePairCall target =
reinterpret_cast<SimulatorRuntimePairCall>(external);
- ObjectPair result =
- target(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
+ ObjectPair result = target(arg[0], arg[1], arg[2], arg[3], arg[4],
+ arg[5], arg[6], arg[7], arg[8], arg[9]);
intptr_t x;
intptr_t y;
decodeObjectPair(&result, &x, &y);
@@ -1195,7 +1200,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
intptr_t result = target(arg[0], arg[1], arg[2], arg[3], arg[4],
- arg[5], arg[6], arg[7], arg[8]);
+ arg[5], arg[6], arg[7], arg[8], arg[9]);
if (::v8::internal::FLAG_trace_sim) {
PrintF("Returned %08" V8PRIxPTR "\n", result);
}
diff --git a/deps/v8/src/execution/protectors-inl.h b/deps/v8/src/execution/protectors-inl.h
new file mode 100644
index 0000000000..b2428063e1
--- /dev/null
+++ b/deps/v8/src/execution/protectors-inl.h
@@ -0,0 +1,36 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_EXECUTION_PROTECTORS_INL_H_
+#define V8_EXECUTION_PROTECTORS_INL_H_
+
+#include "src/execution/protectors.h"
+#include "src/objects/contexts-inl.h"
+#include "src/objects/property-cell-inl.h"
+#include "src/objects/smi.h"
+
+namespace v8 {
+namespace internal {
+
+#define DEFINE_PROTECTOR_ON_NATIVE_CONTEXT_CHECK(name, cell) \
+ bool Protectors::Is##name##Intact(Handle<NativeContext> native_context) { \
+ PropertyCell species_cell = native_context->cell(); \
+ return species_cell.value().IsSmi() && \
+ Smi::ToInt(species_cell.value()) == kProtectorValid; \
+ }
+DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(DEFINE_PROTECTOR_ON_NATIVE_CONTEXT_CHECK)
+
+#define DEFINE_PROTECTOR_ON_ISOLATE_CHECK(name, root_index, unused_cell) \
+ bool Protectors::Is##name##Intact(Isolate* isolate) { \
+ PropertyCell cell = \
+ PropertyCell::cast(isolate->root(RootIndex::k##root_index)); \
+ return cell.value().IsSmi() && \
+ Smi::ToInt(cell.value()) == kProtectorValid; \
+ }
+DECLARED_PROTECTORS_ON_ISOLATE(DEFINE_PROTECTOR_ON_ISOLATE_CHECK)
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_EXECUTION_PROTECTORS_INL_H_
diff --git a/deps/v8/src/execution/protectors.cc b/deps/v8/src/execution/protectors.cc
new file mode 100644
index 0000000000..3ac07eede3
--- /dev/null
+++ b/deps/v8/src/execution/protectors.cc
@@ -0,0 +1,48 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/execution/protectors.h"
+
+#include "src/execution/isolate-inl.h"
+#include "src/execution/protectors-inl.h"
+#include "src/handles/handles-inl.h"
+#include "src/objects/contexts.h"
+#include "src/objects/property-cell.h"
+#include "src/objects/smi.h"
+#include "src/tracing/trace-event.h"
+#include "src/utils/utils.h"
+
+namespace v8 {
+namespace internal {
+
+#define INVALIDATE_PROTECTOR_ON_NATIVE_CONTEXT_DEFINITION(name, cell) \
+ void Protectors::Invalidate##name(Isolate* isolate, \
+ Handle<NativeContext> native_context) { \
+ DCHECK_EQ(*native_context, isolate->raw_native_context()); \
+ DCHECK(native_context->cell().value().IsSmi()); \
+ DCHECK(Is##name##Intact(native_context)); \
+ Handle<PropertyCell> species_cell(native_context->cell(), isolate); \
+ PropertyCell::SetValueWithInvalidation( \
+ isolate, #cell, species_cell, \
+ handle(Smi::FromInt(kProtectorInvalid), isolate)); \
+ DCHECK(!Is##name##Intact(native_context)); \
+ }
+DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(
+ INVALIDATE_PROTECTOR_ON_NATIVE_CONTEXT_DEFINITION)
+#undef INVALIDATE_PROTECTOR_ON_NATIVE_CONTEXT_DEFINITION
+
+#define INVALIDATE_PROTECTOR_ON_ISOLATE_DEFINITION(name, unused_index, cell) \
+ void Protectors::Invalidate##name(Isolate* isolate) { \
+ DCHECK(isolate->factory()->cell()->value().IsSmi()); \
+ DCHECK(Is##name##Intact(isolate)); \
+ PropertyCell::SetValueWithInvalidation( \
+ isolate, #cell, isolate->factory()->cell(), \
+ handle(Smi::FromInt(kProtectorInvalid), isolate)); \
+ DCHECK(!Is##name##Intact(isolate)); \
+ }
+DECLARED_PROTECTORS_ON_ISOLATE(INVALIDATE_PROTECTOR_ON_ISOLATE_DEFINITION)
+#undef INVALIDATE_PROTECTOR_ON_ISOLATE_DEFINITION
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/execution/protectors.h b/deps/v8/src/execution/protectors.h
new file mode 100644
index 0000000000..5c54613bb1
--- /dev/null
+++ b/deps/v8/src/execution/protectors.h
@@ -0,0 +1,42 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_EXECUTION_PROTECTORS_H_
+#define V8_EXECUTION_PROTECTORS_H_
+
+#include "src/handles/handles.h"
+
+namespace v8 {
+namespace internal {
+
+class Protectors : public AllStatic {
+ public:
+ static const int kProtectorValid = 1;
+ static const int kProtectorInvalid = 0;
+
+#define DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(V) \
+ V(RegExpSpeciesLookupChainProtector, regexp_species_protector)
+
+#define DECLARED_PROTECTORS_ON_ISOLATE(V) \
+ V(ArraySpeciesLookupChain, ArraySpeciesProtector, array_species_protector)
+
+#define DECLARE_PROTECTOR_ON_NATIVE_CONTEXT(name, unused_cell) \
+ static inline bool Is##name##Intact(Handle<NativeContext> native_context); \
+ static void Invalidate##name(Isolate* isolate, \
+ Handle<NativeContext> native_context);
+ DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(DECLARE_PROTECTOR_ON_NATIVE_CONTEXT)
+#undef DECLARE_PROTECTOR_ON_NATIVE_CONTEXT
+
+#define DECLARE_PROTECTOR_ON_ISOLATE(name, unused_root_index, unused_cell) \
+ static inline bool Is##name##Intact(Isolate* isolate); \
+ static void Invalidate##name(Isolate* isolate);
+
+ DECLARED_PROTECTORS_ON_ISOLATE(DECLARE_PROTECTOR_ON_ISOLATE)
+#undef DECLARE_PROTECTOR_ON_ISOLATE
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_EXECUTION_PROTECTORS_H_
diff --git a/deps/v8/src/execution/runtime-profiler.cc b/deps/v8/src/execution/runtime-profiler.cc
index 0ed36cbe10..65476e346f 100644
--- a/deps/v8/src/execution/runtime-profiler.cc
+++ b/deps/v8/src/execution/runtime-profiler.cc
@@ -8,6 +8,7 @@
#include "src/codegen/assembler.h"
#include "src/codegen/compilation-cache.h"
#include "src/codegen/compiler.h"
+#include "src/codegen/pending-optimization-table.h"
#include "src/execution/execution.h"
#include "src/execution/frames-inl.h"
#include "src/handles/global-handles.h"
@@ -119,6 +120,17 @@ void RuntimeProfiler::MaybeOptimize(JSFunction function,
}
return;
}
+ if (FLAG_testing_d8_test_runner) {
+ if (!PendingOptimizationTable::IsHeuristicOptimizationAllowed(isolate_,
+ function)) {
+ if (FLAG_trace_opt_verbose) {
+ PrintF("[function ");
+ function.PrintName();
+ PrintF(" has been marked manually for optimization]\n");
+ }
+ return;
+ }
+ }
if (FLAG_always_osr) {
AttemptOnStackReplacement(frame, AbstractCode::kMaxLoopNestingMarker);
diff --git a/deps/v8/src/execution/s390/simulator-s390.cc b/deps/v8/src/execution/s390/simulator-s390.cc
index 8a82e32243..985a941874 100644
--- a/deps/v8/src/execution/s390/simulator-s390.cc
+++ b/deps/v8/src/execution/s390/simulator-s390.cc
@@ -1858,10 +1858,12 @@ using SimulatorRuntimeCall = intptr_t (*)(intptr_t arg0, intptr_t arg1,
intptr_t arg2, intptr_t arg3,
intptr_t arg4, intptr_t arg5,
intptr_t arg6, intptr_t arg7,
- intptr_t arg8);
+ intptr_t arg8, intptr_t arg9);
using SimulatorRuntimePairCall = ObjectPair (*)(intptr_t arg0, intptr_t arg1,
intptr_t arg2, intptr_t arg3,
- intptr_t arg4, intptr_t arg5);
+ intptr_t arg4, intptr_t arg5,
+ intptr_t arg6, intptr_t arg7,
+ intptr_t arg8, intptr_t arg9);
// These prototypes handle the four types of FP calls.
using SimulatorRuntimeCompareCall = int (*)(double darg0, double darg1);
@@ -1891,7 +1893,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
(get_register(sp) & (::v8::internal::FLAG_sim_stack_alignment - 1)) ==
0;
Redirection* redirection = Redirection::FromInstruction(instr);
- const int kArgCount = 9;
+ const int kArgCount = 10;
const int kRegisterArgCount = 5;
int arg0_regnum = 2;
intptr_t result_buffer = 0;
@@ -1913,8 +1915,8 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
arg[i] = stack_pointer[(kCalleeRegisterSaveAreaSize / kPointerSize) +
(i - kRegisterArgCount)];
}
- STATIC_ASSERT(kArgCount == kRegisterArgCount + 4);
- STATIC_ASSERT(kMaxCParameters == 9);
+ STATIC_ASSERT(kArgCount == kRegisterArgCount + 5);
+ STATIC_ASSERT(kMaxCParameters == kArgCount);
bool fp_call =
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
(redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
@@ -2094,9 +2096,10 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
"Call to host function at %p,\n"
"\t\t\t\targs %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
", %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
- ", %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR,
+ ", %08" V8PRIxPTR ", %08" V8PRIxPTR ", %08" V8PRIxPTR
+ ", %08" V8PRIxPTR,
reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg[0], arg[1],
- arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8]);
+ arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]);
if (!stack_aligned) {
PrintF(" with unaligned stack %08" V8PRIxPTR "\n",
static_cast<intptr_t>(get_register(sp)));
@@ -2107,8 +2110,8 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
if (redirection->type() == ExternalReference::BUILTIN_CALL_PAIR) {
SimulatorRuntimePairCall target =
reinterpret_cast<SimulatorRuntimePairCall>(external);
- ObjectPair result =
- target(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]);
+ ObjectPair result = target(arg[0], arg[1], arg[2], arg[3], arg[4],
+ arg[5], arg[6], arg[7], arg[8], arg[9]);
intptr_t x;
intptr_t y;
decodeObjectPair(&result, &x, &y);
@@ -2128,7 +2131,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
intptr_t result = target(arg[0], arg[1], arg[2], arg[3], arg[4],
- arg[5], arg[6], arg[7], arg[8]);
+ arg[5], arg[6], arg[7], arg[8], arg[9]);
if (::v8::internal::FLAG_trace_sim) {
PrintF("Returned %08" V8PRIxPTR "\n", result);
}
diff --git a/deps/v8/src/execution/stack-guard.cc b/deps/v8/src/execution/stack-guard.cc
index e5c24cef1e..1cf4c4605a 100644
--- a/deps/v8/src/execution/stack-guard.cc
+++ b/deps/v8/src/execution/stack-guard.cc
@@ -21,14 +21,12 @@ void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
DCHECK_NOT_NULL(isolate_);
thread_local_.set_jslimit(kInterruptLimit);
thread_local_.set_climit(kInterruptLimit);
- isolate_->heap()->SetStackLimits();
}
void StackGuard::reset_limits(const ExecutionAccess& lock) {
DCHECK_NOT_NULL(isolate_);
thread_local_.set_jslimit(thread_local_.real_jslimit_);
thread_local_.set_climit(thread_local_.real_climit_);
- isolate_->heap()->SetStackLimits();
}
void StackGuard::SetStackLimit(uintptr_t limit) {
@@ -54,7 +52,6 @@ void StackGuard::AdjustStackLimitForSimulator() {
uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, climit);
if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
thread_local_.set_jslimit(jslimit);
- isolate_->heap()->SetStackLimits();
}
}
@@ -75,7 +72,8 @@ void StackGuard::PushInterruptsScope(InterruptsScope* scope) {
DCHECK_NE(scope->mode_, InterruptsScope::kNoop);
if (scope->mode_ == InterruptsScope::kPostponeInterrupts) {
// Intercept already requested interrupts.
- int intercepted = thread_local_.interrupt_flags_ & scope->intercept_mask_;
+ intptr_t intercepted =
+ thread_local_.interrupt_flags_ & scope->intercept_mask_;
scope->intercepted_flags_ = intercepted;
thread_local_.interrupt_flags_ &= ~intercepted;
} else {
@@ -124,7 +122,7 @@ void StackGuard::PopInterruptsScope() {
bool StackGuard::CheckInterrupt(InterruptFlag flag) {
ExecutionAccess access(isolate_);
- return thread_local_.interrupt_flags_ & flag;
+ return (thread_local_.interrupt_flags_ & flag) != 0;
}
void StackGuard::RequestInterrupt(InterruptFlag flag) {
@@ -160,7 +158,7 @@ int StackGuard::FetchAndClearInterrupts() {
ExecutionAccess access(isolate_);
int result = 0;
- if (thread_local_.interrupt_flags_ & TERMINATE_EXECUTION) {
+ if ((thread_local_.interrupt_flags_ & TERMINATE_EXECUTION) != 0) {
// The TERMINATE_EXECUTION interrupt is special, since it terminates
// execution but should leave V8 in a resumable state. If it exists, we only
// fetch and clear that bit. On resume, V8 can continue processing other
@@ -169,7 +167,7 @@ int StackGuard::FetchAndClearInterrupts() {
thread_local_.interrupt_flags_ &= ~TERMINATE_EXECUTION;
if (!has_pending_interrupts(access)) reset_limits(access);
} else {
- result = thread_local_.interrupt_flags_;
+ result = static_cast<int>(thread_local_.interrupt_flags_);
thread_local_.interrupt_flags_ = 0;
reset_limits(access);
}
@@ -180,23 +178,13 @@ int StackGuard::FetchAndClearInterrupts() {
char* StackGuard::ArchiveStackGuard(char* to) {
ExecutionAccess access(isolate_);
MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
- ThreadLocal blank;
-
- // Set the stack limits using the old thread_local_.
- // TODO(isolates): This was the old semantics of constructing a ThreadLocal
- // (as the ctor called SetStackLimits, which looked at the
- // current thread_local_ from StackGuard)-- but is this
- // really what was intended?
- isolate_->heap()->SetStackLimits();
- thread_local_ = blank;
-
+ thread_local_ = {};
return to + sizeof(ThreadLocal);
}
char* StackGuard::RestoreStackGuard(char* from) {
ExecutionAccess access(isolate_);
MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
- isolate_->heap()->SetStackLimits();
return from + sizeof(ThreadLocal);
}
@@ -206,39 +194,21 @@ void StackGuard::FreeThreadResources() {
per_thread->set_stack_limit(thread_local_.real_climit_);
}
-void StackGuard::ThreadLocal::Clear() {
- real_jslimit_ = kIllegalLimit;
- set_jslimit(kIllegalLimit);
- real_climit_ = kIllegalLimit;
- set_climit(kIllegalLimit);
+void StackGuard::ThreadLocal::Initialize(Isolate* isolate,
+ const ExecutionAccess& lock) {
+ const uintptr_t kLimitSize = FLAG_stack_size * KB;
+ DCHECK_GT(GetCurrentStackPosition(), kLimitSize);
+ uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
+ real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
+ set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
+ real_climit_ = limit;
+ set_climit(limit);
interrupt_scopes_ = nullptr;
interrupt_flags_ = 0;
}
-bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
- bool should_set_stack_limits = false;
- if (real_climit_ == kIllegalLimit) {
- const uintptr_t kLimitSize = FLAG_stack_size * KB;
- DCHECK_GT(GetCurrentStackPosition(), kLimitSize);
- uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
- real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
- set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
- real_climit_ = limit;
- set_climit(limit);
- should_set_stack_limits = true;
- }
- interrupt_scopes_ = nullptr;
- interrupt_flags_ = 0;
- return should_set_stack_limits;
-}
-
-void StackGuard::ClearThread(const ExecutionAccess& lock) {
- thread_local_.Clear();
- isolate_->heap()->SetStackLimits();
-}
-
void StackGuard::InitThread(const ExecutionAccess& lock) {
- if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits();
+ thread_local_.Initialize(isolate_, lock);
Isolate::PerIsolateThreadData* per_thread =
isolate_->FindOrAllocatePerThreadDataForThisThread();
uintptr_t stored_limit = per_thread->stack_limit();
diff --git a/deps/v8/src/execution/stack-guard.h b/deps/v8/src/execution/stack-guard.h
index d7477f1623..febd1ecb0a 100644
--- a/deps/v8/src/execution/stack-guard.h
+++ b/deps/v8/src/execution/stack-guard.h
@@ -7,6 +7,7 @@
#include "include/v8-internal.h"
#include "src/base/atomicops.h"
+#include "src/common/globals.h"
namespace v8 {
namespace internal {
@@ -37,12 +38,8 @@ class V8_EXPORT_PRIVATE StackGuard final {
char* RestoreStackGuard(char* from);
static int ArchiveSpacePerThread() { return sizeof(ThreadLocal); }
void FreeThreadResources();
- // Sets up the default stack guard for this thread if it has not
- // already been set up.
+ // Sets up the default stack guard for this thread.
void InitThread(const ExecutionAccess& lock);
- // Clears the stack guard for this thread so it does not look as if
- // it has been set up.
- void ClearThread(const ExecutionAccess& lock);
#define INTERRUPT_LIST(V) \
V(TERMINATE_EXECUTION, TerminateExecution, 0) \
@@ -89,6 +86,8 @@ class V8_EXPORT_PRIVATE StackGuard final {
// stack overflow, then handle the interruption accordingly.
Object HandleInterrupts();
+ static constexpr int kSizeInBytes = 7 * kSystemPointerSize;
+
private:
bool CheckInterrupt(InterruptFlag flag);
void RequestInterrupt(InterruptFlag flag);
@@ -124,13 +123,9 @@ class V8_EXPORT_PRIVATE StackGuard final {
class ThreadLocal final {
public:
- ThreadLocal() { Clear(); }
- // You should hold the ExecutionAccess lock when you call Initialize or
- // Clear.
- void Clear();
+ ThreadLocal() {}
- // Returns true if the heap's stack limits should be set, false if not.
- bool Initialize(Isolate* isolate);
+ void Initialize(Isolate* isolate, const ExecutionAccess& lock);
// The stack limit is split into a JavaScript and a C++ stack limit. These
// two are the same except when running on a simulator where the C++ and
@@ -141,13 +136,16 @@ class V8_EXPORT_PRIVATE StackGuard final {
// break or preemption) in which case it is lowered to make stack checks
// fail. Both the generated code and the runtime system check against the
// one without the real_ prefix.
- uintptr_t real_jslimit_; // Actual JavaScript stack limit set for the VM.
- uintptr_t real_climit_; // Actual C++ stack limit set for the VM.
+
+ // Actual JavaScript stack limit set for the VM.
+ uintptr_t real_jslimit_ = kIllegalLimit;
+ // Actual C++ stack limit set for the VM.
+ uintptr_t real_climit_ = kIllegalLimit;
// jslimit_ and climit_ can be read without any lock.
// Writing requires the ExecutionAccess lock.
- base::AtomicWord jslimit_;
- base::AtomicWord climit_;
+ base::AtomicWord jslimit_ = kIllegalLimit;
+ base::AtomicWord climit_ = kIllegalLimit;
uintptr_t jslimit() {
return bit_cast<uintptr_t>(base::Relaxed_Load(&jslimit_));
@@ -164,8 +162,8 @@ class V8_EXPORT_PRIVATE StackGuard final {
static_cast<base::AtomicWord>(limit));
}
- InterruptsScope* interrupt_scopes_;
- int interrupt_flags_;
+ InterruptsScope* interrupt_scopes_ = nullptr;
+ intptr_t interrupt_flags_ = 0;
};
// TODO(isolates): Technically this could be calculated directly from a
@@ -180,6 +178,8 @@ class V8_EXPORT_PRIVATE StackGuard final {
DISALLOW_COPY_AND_ASSIGN(StackGuard);
};
+STATIC_ASSERT(StackGuard::kSizeInBytes == sizeof(StackGuard));
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/execution/thread-local-top.cc b/deps/v8/src/execution/thread-local-top.cc
index 569333f276..cb69fb56ef 100644
--- a/deps/v8/src/execution/thread-local-top.cc
+++ b/deps/v8/src/execution/thread-local-top.cc
@@ -26,5 +26,15 @@ void ThreadLocalTop::Free() {
while (promise_on_stack_) isolate_->PopPromise();
}
+#if defined(USE_SIMULATOR)
+void ThreadLocalTop::StoreCurrentStackPosition() {
+ last_api_entry_ = simulator_->get_sp();
+}
+#elif defined(V8_USE_ADDRESS_SANITIZER)
+void ThreadLocalTop::StoreCurrentStackPosition() {
+ last_api_entry_ = reinterpret_cast<Address>(GetCurrentStackPosition());
+}
+#endif
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/execution/thread-local-top.h b/deps/v8/src/execution/thread-local-top.h
index 625fcc41dd..57166299c5 100644
--- a/deps/v8/src/execution/thread-local-top.h
+++ b/deps/v8/src/execution/thread-local-top.h
@@ -8,6 +8,7 @@
#include "src/common/globals.h"
#include "src/execution/thread-id.h"
#include "src/objects/contexts.h"
+#include "src/utils/utils.h"
namespace v8 {
@@ -25,7 +26,7 @@ class ThreadLocalTop {
// TODO(all): This is not particularly beautiful. We should probably
// refactor this to really consist of just Addresses and 32-bit
// integer fields.
- static constexpr uint32_t kSizeInBytes = 23 * kSystemPointerSize;
+ static constexpr uint32_t kSizeInBytes = 24 * kSystemPointerSize;
// Does early low-level initialization that does not depend on the
// isolate being present.
@@ -56,6 +57,31 @@ class ThreadLocalTop {
v8::TryCatch::JSStackComparableAddress(try_catch_handler_));
}
+ // Call depth represents nested v8 api calls. Instead of storing the nesting
+ // level as an integer, we store the stack height of the last API entry. This
+ // additional information is used when we decide whether to trigger a debug
+ // break at a function entry.
+ template <typename Scope>
+ void IncrementCallDepth(Scope* stack_allocated_scope) {
+ stack_allocated_scope->previous_stack_height_ = last_api_entry_;
+#if defined(USE_SIMULATOR) || defined(V8_USE_ADDRESS_SANITIZER)
+ StoreCurrentStackPosition();
+#else
+ last_api_entry_ = reinterpret_cast<i::Address>(stack_allocated_scope);
+#endif
+ }
+
+#if defined(USE_SIMULATOR) || defined(V8_USE_ADDRESS_SANITIZER)
+ void StoreCurrentStackPosition();
+#endif
+
+ template <typename Scope>
+ void DecrementCallDepth(Scope* stack_allocated_scope) {
+ last_api_entry_ = stack_allocated_scope->previous_stack_height_;
+ }
+
+ bool CallDepthIsZero() const { return last_api_entry_ == kNullAddress; }
+
void Free();
Isolate* isolate_ = nullptr;
@@ -77,6 +103,8 @@ class ThreadLocalTop {
Address pending_handler_fp_ = kNullAddress;
Address pending_handler_sp_ = kNullAddress;
+ Address last_api_entry_ = kNullAddress;
+
// Communication channel between Isolate::Throw and message consumers.
Object pending_message_obj_;
bool rethrowing_message_ = false;
diff --git a/deps/v8/src/execution/v8threads.cc b/deps/v8/src/execution/v8threads.cc
index 6b99b81ef7..e16988b275 100644
--- a/deps/v8/src/execution/v8threads.cc
+++ b/deps/v8/src/execution/v8threads.cc
@@ -40,10 +40,6 @@ void Locker::Initialize(v8::Isolate* isolate) {
// get the saved state for this thread and restore it.
if (isolate_->thread_manager()->RestoreThread()) {
top_level_ = false;
- } else {
- internal::ExecutionAccess access(isolate_);
- isolate_->stack_guard()->ClearThread(access);
- isolate_->thread_manager()->InitThread(access);
}
}
DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
@@ -88,6 +84,7 @@ Unlocker::~Unlocker() {
namespace internal {
void ThreadManager::InitThread(const ExecutionAccess& lock) {
+ isolate_->InitializeThreadLocal();
isolate_->stack_guard()->InitThread(lock);
isolate_->debug()->InitThread(lock);
}
diff --git a/deps/v8/src/extensions/OWNERS b/deps/v8/src/extensions/OWNERS
index 852d438bb0..48d72aea5e 100644
--- a/deps/v8/src/extensions/OWNERS
+++ b/deps/v8/src/extensions/OWNERS
@@ -1 +1 @@
-file://COMMON_OWNERS
+file:../../COMMON_OWNERS
diff --git a/deps/v8/src/extensions/cputracemark-extension.cc b/deps/v8/src/extensions/cputracemark-extension.cc
index af85130ee8..6162afad5f 100644
--- a/deps/v8/src/extensions/cputracemark-extension.cc
+++ b/deps/v8/src/extensions/cputracemark-extension.cc
@@ -26,7 +26,7 @@ void CpuTraceMarkExtension::Mark(
#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
-#if !V8_LIBC_MSVCRT
+#if defined(__clang__)
// for non msvc build
uint32_t param =
args[0]->Uint32Value(args.GetIsolate()->GetCurrentContext()).ToChecked();
diff --git a/deps/v8/src/flags/OWNERS b/deps/v8/src/flags/OWNERS
index 852d438bb0..48d72aea5e 100644
--- a/deps/v8/src/flags/OWNERS
+++ b/deps/v8/src/flags/OWNERS
@@ -1 +1 @@
-file://COMMON_OWNERS
+file:../../COMMON_OWNERS
diff --git a/deps/v8/src/flags/flag-definitions.h b/deps/v8/src/flags/flag-definitions.h
index c32bb03407..c7c07e6dc6 100644
--- a/deps/v8/src/flags/flag-definitions.h
+++ b/deps/v8/src/flags/flag-definitions.h
@@ -206,7 +206,9 @@ DEFINE_IMPLICATION(harmony_import_meta, harmony_dynamic_import)
#define HARMONY_INPROGRESS_BASE(V) \
V(harmony_private_methods, "harmony private methods in class literals") \
V(harmony_regexp_sequence, "RegExp Unicode sequence properties") \
- V(harmony_weak_refs, "harmony weak references")
+ V(harmony_weak_refs, "harmony weak references") \
+ V(harmony_optional_chaining, "harmony optional chaining syntax") \
+ V(harmony_nullish, "harmony nullish operator")
#ifdef V8_INTL_SUPPORT
#define HARMONY_INPROGRESS(V) \
@@ -240,7 +242,6 @@ DEFINE_IMPLICATION(harmony_import_meta, harmony_dynamic_import)
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
V(harmony_import_meta, "harmony import.meta property") \
V(harmony_dynamic_import, "harmony dynamic import") \
- V(harmony_numeric_separator, "harmony numeric separator between digits") \
V(harmony_promise_all_settled, "harmony Promise.allSettled")
#ifdef V8_INTL_SUPPORT
@@ -298,15 +299,47 @@ DEFINE_BOOL(icu_timezone_data, true, "get information about timezones from ICU")
#define V8_LITE_BOOL false
#endif
+#ifdef V8_ENABLE_LAZY_SOURCE_POSITIONS
+#define V8_LAZY_SOURCE_POSITIONS_BOOL true
+#else
+#define V8_LAZY_SOURCE_POSITIONS_BOOL false
+#endif
+
DEFINE_BOOL(lite_mode, V8_LITE_BOOL,
"enables trade-off of performance for memory savings")
// Lite mode implies other flags to trade-off performance for memory.
DEFINE_IMPLICATION(lite_mode, jitless)
DEFINE_IMPLICATION(lite_mode, lazy_feedback_allocation)
-DEFINE_IMPLICATION(lite_mode, enable_lazy_source_positions)
DEFINE_IMPLICATION(lite_mode, optimize_for_size)
+#ifdef V8_DISABLE_WRITE_BARRIERS
+#define V8_DISABLE_WRITE_BARRIERS_BOOL true
+#else
+#define V8_DISABLE_WRITE_BARRIERS_BOOL false
+#endif
+
+DEFINE_BOOL_READONLY(disable_write_barriers, V8_DISABLE_WRITE_BARRIERS_BOOL,
+ "disable write barriers when GC is non-incremental "
+ "and heap contains single generation.")
+
+// Disable incremental marking barriers
+DEFINE_NEG_IMPLICATION(disable_write_barriers, incremental_marking)
+
+#ifdef V8_ENABLE_SINGLE_GENERATION
+#define V8_GENERATION_BOOL true
+#else
+#define V8_GENERATION_BOOL false
+#endif
+
+DEFINE_BOOL_READONLY(
+ single_generation, V8_GENERATION_BOOL,
+ "allocate all objects from young generation to old generation")
+
+// Prevent inline allocation into new space
+DEFINE_NEG_IMPLICATION(single_generation, inline_new)
+DEFINE_NEG_IMPLICATION(single_generation, turbo_allocation_folding)
+
#ifdef V8_ENABLE_FUTURE
#define FUTURE_BOOL true
#else
@@ -351,10 +384,6 @@ DEFINE_BOOL(feedback_normalization, false,
DEFINE_BOOL_READONLY(internalize_on_the_fly, true,
"internalize string keys for generic keyed ICs on the fly")
-// Flag to faster calls with arguments mismatches (https://crbug.com/v8/8895)
-DEFINE_BOOL(fast_calls_with_arguments_mismatches, true,
- "skip arguments adaptor frames when it's provably safe")
-
// Flag for one shot optimiztions.
DEFINE_BOOL(enable_one_shot_optimization, true,
"Enable size optimizations for the code that will "
@@ -409,7 +438,7 @@ DEFINE_BOOL(ignition_share_named_property_feedback, true,
"the same object")
DEFINE_BOOL(print_bytecode, false,
"print bytecode generated by ignition interpreter")
-DEFINE_BOOL(enable_lazy_source_positions, false,
+DEFINE_BOOL(enable_lazy_source_positions, V8_LAZY_SOURCE_POSITIONS_BOOL,
"skip generating source positions during initial compile but "
"regenerate when actually required")
DEFINE_BOOL(stress_lazy_source_positions, false,
@@ -677,13 +706,18 @@ DEFINE_STRING(dump_wasm_module_path, nullptr,
// for configurability.
#include "src/wasm/wasm-feature-flags.h"
-#define SPACE
#define DECL_WASM_FLAG(feat, desc, val) \
DEFINE_BOOL(experimental_wasm_##feat, val, \
"enable prototype " desc " for wasm")
-FOREACH_WASM_FEATURE_FLAG(DECL_WASM_FLAG, SPACE)
+FOREACH_WASM_FEATURE_FLAG(DECL_WASM_FLAG)
#undef DECL_WASM_FLAG
-#undef SPACE
+
+DEFINE_BOOL(wasm_staging, false, "enable staged wasm features")
+
+#define WASM_STAGING_IMPLICATION(feat, desc, val) \
+ DEFINE_IMPLICATION(wasm_staging, experimental_wasm_##feat)
+FOREACH_WASM_STAGING_FEATURE_FLAG(WASM_STAGING_IMPLICATION)
+#undef WASM_STAGING_IMPLICATION
DEFINE_BOOL(wasm_opt, false, "enable wasm optimization")
DEFINE_BOOL(wasm_no_bounds_checks, false,
@@ -752,6 +786,7 @@ DEFINE_SIZE_T(
"max size of the heap (in Mbytes) "
"both max_semi_space_size and max_old_space_size take precedence. "
"All three flags cannot be specified at the same time.")
+DEFINE_SIZE_T(initial_heap_size, 0, "initial size of the heap (in Mbytes)")
DEFINE_BOOL(huge_max_old_generation_size, false,
"Increase max size of the old space to 4 GB for x64 systems with"
"the physical memory bigger than 16 GB")
@@ -788,9 +823,18 @@ DEFINE_BOOL(trace_gc_freelists_verbose, false,
DEFINE_IMPLICATION(trace_gc_freelists_verbose, trace_gc_freelists)
DEFINE_BOOL(trace_evacuation_candidates, false,
"Show statistics about the pages evacuation by the compaction")
-DEFINE_INT(gc_freelist_strategy, 0,
+DEFINE_BOOL(
+ trace_allocations_origins, false,
+ "Show statistics about the origins of allocations. "
+ "Combine with --no-inline-new to track allocations from generated code")
+DEFINE_INT(gc_freelist_strategy, 5,
"Freelist strategy to use: "
- "1=FreeListFastAlloc. 2=FreeListMany. Anything else=FreeListLegacy")
+ "0:FreeListLegacy. "
+ "1:FreeListFastAlloc. "
+ "2:FreeListMany. "
+ "3:FreeListManyCached. "
+ "4:FreeListManyCachedFastPath. "
+ "5:FreeListManyCachedOrigin. ")
DEFINE_INT(trace_allocation_stack_interval, -1,
"print stack trace after <n> free-list allocations")
@@ -1210,6 +1254,9 @@ DEFINE_UINT(serialization_chunk_size, 4096,
DEFINE_BOOL(regexp_optimization, true, "generate optimized regexp code")
DEFINE_BOOL(regexp_mode_modifiers, false, "enable inline flags in regexp.")
DEFINE_BOOL(regexp_interpret_all, false, "interpret all regexp code")
+DEFINE_BOOL(regexp_tier_up, false,
+ "enable regexp interpreter and tier up to the compiler")
+DEFINE_NEG_IMPLICATION(regexp_interpret_all, regexp_tier_up)
// Testing flags test/cctest/test-{flags,api,serialization}.cc
DEFINE_BOOL(testing_bool_flag, true, "testing_bool_flag")
@@ -1348,6 +1395,7 @@ DEFINE_BOOL(trace_regexp_bytecodes, false, "trace regexp bytecode execution")
DEFINE_BOOL(trace_regexp_assembler, false,
"trace regexp macro assembler calls.")
DEFINE_BOOL(trace_regexp_parser, false, "trace regexp parsing")
+DEFINE_BOOL(trace_regexp_tier_up, false, "trace regexp tiering up execution")
// Debugger
DEFINE_BOOL(print_break_location, false, "print source location on debug break")
@@ -1407,6 +1455,9 @@ DEFINE_BOOL(perf_basic_prof_only_functions, false,
DEFINE_IMPLICATION(perf_basic_prof_only_functions, perf_basic_prof)
DEFINE_BOOL(perf_prof, false,
"Enable perf linux profiler (experimental annotate support).")
+DEFINE_BOOL(perf_prof_annotate_wasm, false,
+ "Used with --perf-prof, load wasm source map and provide annotate "
+ "support (experimental).")
DEFINE_NEG_IMPLICATION(perf_prof, compact_code_space)
// TODO(v8:8462) Remove implication once perf supports remapping.
DEFINE_NEG_IMPLICATION(perf_prof, write_protect_code_memory)
@@ -1463,7 +1514,6 @@ DEFINE_BOOL(trace_elements_transitions, false, "trace elements transitions")
DEFINE_BOOL(trace_creation_allocation_sites, false,
"trace the creation of allocation sites")
-// codegen-ia32.cc / codegen-arm.cc
DEFINE_BOOL(print_code, false, "print generated code")
DEFINE_BOOL(print_opt_code, false, "print optimized code")
DEFINE_STRING(print_opt_code_filter, "*", "filter for printing optimized code")
@@ -1471,6 +1521,8 @@ DEFINE_BOOL(print_code_verbose, false, "print more information for code")
DEFINE_BOOL(print_builtin_code, false, "print generated code for builtins")
DEFINE_STRING(print_builtin_code_filter, "*",
"filter for printing builtin code")
+DEFINE_BOOL(print_regexp_code, false, "print generated regexp code")
+DEFINE_BOOL(print_regexp_bytecode, false, "print generated regexp bytecode")
DEFINE_BOOL(print_builtin_size, false, "print code size for builtins")
#ifdef ENABLE_DISASSEMBLER
@@ -1487,6 +1539,7 @@ DEFINE_IMPLICATION(print_all_code, print_code)
DEFINE_IMPLICATION(print_all_code, print_opt_code)
DEFINE_IMPLICATION(print_all_code, print_code_verbose)
DEFINE_IMPLICATION(print_all_code, print_builtin_code)
+DEFINE_IMPLICATION(print_all_code, print_regexp_code)
DEFINE_IMPLICATION(print_all_code, code_comments)
#endif
diff --git a/deps/v8/src/handles/global-handles.cc b/deps/v8/src/handles/global-handles.cc
index db4f806e58..aed5b3fa83 100644
--- a/deps/v8/src/handles/global-handles.cc
+++ b/deps/v8/src/handles/global-handles.cc
@@ -22,6 +22,10 @@ namespace internal {
namespace {
+// Specifies whether V8 expects the holder memory of a global handle to be live
+// or dead.
+enum class HandleHolder { kLive, kDead };
+
constexpr size_t kBlockSize = 256;
} // namespace
@@ -32,6 +36,7 @@ class GlobalHandles::NodeBlock final {
using BlockType = NodeBlock<_NodeType>;
using NodeType = _NodeType;
+ V8_INLINE static const NodeBlock* From(const NodeType* node);
V8_INLINE static NodeBlock* From(NodeType* node);
NodeBlock(GlobalHandles* global_handles,
@@ -67,6 +72,16 @@ class GlobalHandles::NodeBlock final {
};
template <class NodeType>
+const GlobalHandles::NodeBlock<NodeType>*
+GlobalHandles::NodeBlock<NodeType>::From(const NodeType* node) {
+ uintptr_t ptr = reinterpret_cast<const uintptr_t>(node) -
+ sizeof(NodeType) * node->index();
+ const BlockType* block = reinterpret_cast<const BlockType*>(ptr);
+ DCHECK_EQ(node, block->at(node->index()));
+ return block;
+}
+
+template <class NodeType>
GlobalHandles::NodeBlock<NodeType>* GlobalHandles::NodeBlock<NodeType>::From(
NodeType* node) {
uintptr_t ptr =
@@ -239,6 +254,10 @@ void GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) {
template <class Child>
class NodeBase {
public:
+ static const Child* FromLocation(const Address* location) {
+ return reinterpret_cast<const Child*>(location);
+ }
+
static Child* FromLocation(Address* location) {
return reinterpret_cast<Child*>(location);
}
@@ -532,7 +551,8 @@ class GlobalHandles::Node final : public NodeBase<GlobalHandles::Node> {
set_state(NEAR_DEATH);
}
- void ResetPhantomHandle() {
+ void ResetPhantomHandle(HandleHolder handle_holder) {
+ DCHECK_EQ(HandleHolder::kLive, handle_holder);
DCHECK_EQ(PHANTOM_WEAK_RESET_HANDLE, weakness_type());
DCHECK_EQ(PENDING, state());
DCHECK_NULL(weak_callback_);
@@ -580,10 +600,9 @@ class GlobalHandles::Node final : public NodeBase<GlobalHandles::Node> {
// This stores three flags (independent, partially_dependent and
// in_young_list) and a State.
- class NodeState : public BitField8<State, 0, 3> {};
- class IsInYoungList : public BitField8<bool, NodeState::kNext, 1> {};
- class NodeWeaknessType
- : public BitField8<WeaknessType, IsInYoungList::kNext, 2> {};
+ using NodeState = BitField8<State, 0, 3>;
+ using IsInYoungList = NodeState::Next<bool, 1>;
+ using NodeWeaknessType = IsInYoungList::Next<WeaknessType, 2>;
// Handle specific callback - might be a weak reference in disguise.
WeakCallbackInfo<void>::Callback weak_callback_;
@@ -615,6 +634,9 @@ class GlobalHandles::TracedNode final
bool is_root() const { return IsRoot::decode(flags_); }
void set_root(bool v) { flags_ = IsRoot::update(flags_, v); }
+ bool has_destructor() const { return HasDestructor::decode(flags_); }
+ void set_has_destructor(bool v) { flags_ = HasDestructor::update(flags_, v); }
+
void SetFinalizationCallback(void* parameter,
WeakCallbackInfo<void>::Callback callback) {
set_parameter(parameter);
@@ -641,18 +663,21 @@ class GlobalHandles::TracedNode final
set_state(NEAR_DEATH);
}
- void ResetPhantomHandle() {
+ void ResetPhantomHandle(HandleHolder handle_holder) {
DCHECK(IsInUse());
- Address** handle = reinterpret_cast<Address**>(data_.parameter);
- *handle = nullptr;
+ if (handle_holder == HandleHolder::kLive) {
+ Address** handle = reinterpret_cast<Address**>(data_.parameter);
+ *handle = nullptr;
+ }
NodeSpace<TracedNode>::Release(this);
DCHECK(!IsInUse());
}
protected:
- class NodeState : public BitField8<State, 0, 2> {};
- class IsInYoungList : public BitField8<bool, NodeState::kNext, 1> {};
- class IsRoot : public BitField8<bool, IsInYoungList::kNext, 1> {};
+ using NodeState = BitField8<State, 0, 2>;
+ using IsInYoungList = NodeState::Next<bool, 1>;
+ using IsRoot = IsInYoungList::Next<bool, 1>;
+ using HasDestructor = IsRoot::Next<bool, 1>;
void ClearImplFields() {
set_root(true);
@@ -691,18 +716,21 @@ Handle<Object> GlobalHandles::Create(Address value) {
return Create(Object(value));
}
-Handle<Object> GlobalHandles::CreateTraced(Object value, Address* slot) {
+Handle<Object> GlobalHandles::CreateTraced(Object value, Address* slot,
+ bool has_destructor) {
GlobalHandles::TracedNode* result = traced_nodes_->Acquire(value);
if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) {
traced_young_nodes_.push_back(result);
result->set_in_young_list(true);
}
result->set_parameter(slot);
+ result->set_has_destructor(has_destructor);
return result->handle();
}
-Handle<Object> GlobalHandles::CreateTraced(Address value, Address* slot) {
- return CreateTraced(Object(value), slot);
+Handle<Object> GlobalHandles::CreateTraced(Address value, Address* slot,
+ bool has_destructor) {
+ return CreateTraced(Object(value), slot, has_destructor);
}
Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
@@ -717,6 +745,27 @@ Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
return global_handles->Create(*location);
}
+// static
+void GlobalHandles::CopyTracedGlobal(const Address* const* from, Address** to) {
+ DCHECK_NOT_NULL(*from);
+ DCHECK_NULL(*to);
+ const TracedNode* node = TracedNode::FromLocation(*from);
+ // Copying a traced handle with finalization callback is prohibited because
+ // the callback may require knowing about multiple copies of the traced
+ // handle.
+ CHECK(!node->HasFinalizationCallback());
+ GlobalHandles* global_handles =
+ NodeBlock<TracedNode>::From(node)->global_handles();
+ Handle<Object> o = global_handles->CreateTraced(
+ node->object(), reinterpret_cast<Address*>(to), node->has_destructor());
+ *to = o.location();
+#ifdef VERIFY_HEAP
+ if (i::FLAG_verify_heap) {
+ Object(**to).ObjectVerify(global_handles->isolate());
+ }
+#endif // VERIFY_HEAP
+}
+
void GlobalHandles::MoveGlobal(Address** from, Address** to) {
DCHECK_NOT_NULL(*from);
DCHECK_NOT_NULL(*to);
@@ -809,7 +858,7 @@ void GlobalHandles::IterateWeakRootsForPhantomHandles(
should_reset_handle(isolate()->heap(), node->location())) {
if (node->IsPhantomResetHandle()) {
node->MarkPending();
- node->ResetPhantomHandle();
+ node->ResetPhantomHandle(HandleHolder::kLive);
++number_of_phantom_handle_resets_;
} else if (node->IsPhantomCallback()) {
node->MarkPending();
@@ -821,7 +870,8 @@ void GlobalHandles::IterateWeakRootsForPhantomHandles(
if (node->IsInUse() &&
should_reset_handle(isolate()->heap(), node->location())) {
if (node->IsPhantomResetHandle()) {
- node->ResetPhantomHandle();
+ node->ResetPhantomHandle(node->has_destructor() ? HandleHolder::kLive
+ : HandleHolder::kDead);
++number_of_phantom_handle_resets_;
} else {
node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
@@ -907,7 +957,7 @@ void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles(
DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback());
if (node->IsPhantomResetHandle()) {
node->MarkPending();
- node->ResetPhantomHandle();
+ node->ResetPhantomHandle(HandleHolder::kLive);
++number_of_phantom_handle_resets_;
} else if (node->IsPhantomCallback()) {
node->MarkPending();
@@ -922,6 +972,9 @@ void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles(
}
}
}
+
+ LocalEmbedderHeapTracer* const tracer =
+ isolate()->heap()->local_embedder_heap_tracer();
for (TracedNode* node : traced_young_nodes_) {
if (!node->IsInUse()) continue;
@@ -929,7 +982,18 @@ void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles(
!should_reset_handle(isolate_->heap(), node->location()));
if (should_reset_handle(isolate_->heap(), node->location())) {
if (node->IsPhantomResetHandle()) {
- node->ResetPhantomHandle();
+ if (node->has_destructor()) {
+ // For handles with destructor it is guaranteed that the embedder
+ // memory is still alive as the destructor would have otherwise
+ // removed the memory.
+ node->ResetPhantomHandle(HandleHolder::kLive);
+ } else {
+ v8::Value* value = ToApi<v8::Value>(node->handle());
+ tracer->ResetHandleInNonTracingGC(
+ *reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value));
+ DCHECK(!node->IsInUse());
+ }
+
++number_of_phantom_handle_resets_;
} else {
node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
diff --git a/deps/v8/src/handles/global-handles.h b/deps/v8/src/handles/global-handles.h
index a08bc1fd13..a07f7a772a 100644
--- a/deps/v8/src/handles/global-handles.h
+++ b/deps/v8/src/handles/global-handles.h
@@ -81,6 +81,7 @@ class V8_EXPORT_PRIVATE GlobalHandles final {
//
static void MoveTracedGlobal(Address** from, Address** to);
+ static void CopyTracedGlobal(const Address* const* from, Address** to);
static void DestroyTraced(Address* location);
static void SetFinalizationCallbackForTraced(
Address* location, void* parameter,
@@ -101,8 +102,9 @@ class V8_EXPORT_PRIVATE GlobalHandles final {
return Handle<T>::cast(Create(Object(value)));
}
- Handle<Object> CreateTraced(Object value, Address* slot);
- Handle<Object> CreateTraced(Address value, Address* slot);
+ Handle<Object> CreateTraced(Object value, Address* slot, bool has_destructor);
+ Handle<Object> CreateTraced(Address value, Address* slot,
+ bool has_destructor);
void RecordStats(HeapStats* stats);
diff --git a/deps/v8/src/heap/array-buffer-tracker-inl.h b/deps/v8/src/heap/array-buffer-tracker-inl.h
index 65d3f4a732..763300cffe 100644
--- a/deps/v8/src/heap/array-buffer-tracker-inl.h
+++ b/deps/v8/src/heap/array-buffer-tracker-inl.h
@@ -80,8 +80,7 @@ void LocalArrayBufferTracker::Free(Callback should_free) {
ExternalBackingStoreType::kArrayBuffer, freed_memory);
// TODO(wez): Remove backing-store from external memory accounting.
- page_->heap()->update_external_memory_concurrently_freed(
- static_cast<intptr_t>(freed_memory));
+ page_->heap()->update_external_memory_concurrently_freed(freed_memory);
}
}
diff --git a/deps/v8/src/heap/array-buffer-tracker.cc b/deps/v8/src/heap/array-buffer-tracker.cc
index 0c04d7b6ae..fdca6e8df2 100644
--- a/deps/v8/src/heap/array-buffer-tracker.cc
+++ b/deps/v8/src/heap/array-buffer-tracker.cc
@@ -68,8 +68,7 @@ void LocalArrayBufferTracker::Process(Callback callback) {
page_->DecrementExternalBackingStoreBytes(
ExternalBackingStoreType::kArrayBuffer, freed_memory);
// TODO(wez): Remove backing-store from external memory accounting.
- page_->heap()->update_external_memory_concurrently_freed(
- static_cast<intptr_t>(freed_memory));
+ page_->heap()->update_external_memory_concurrently_freed(freed_memory);
}
array_buffers_.swap(kept_array_buffers);
diff --git a/deps/v8/src/heap/embedder-tracing.h b/deps/v8/src/heap/embedder-tracing.h
index eae29cbf5c..7c67ccfab7 100644
--- a/deps/v8/src/heap/embedder-tracing.h
+++ b/deps/v8/src/heap/embedder-tracing.h
@@ -57,6 +57,12 @@ class V8_EXPORT_PRIVATE LocalEmbedderHeapTracer final {
bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) {
return !InUse() || remote_tracer_->IsRootForNonTracingGC(handle);
}
+ void ResetHandleInNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) {
+ // Resetting is only called when IsRootForNonTracingGC returns false which
+ // can only happen the EmbedderHeapTracer is set on API level.
+ DCHECK(InUse());
+ remote_tracer_->ResetHandleInNonTracingGC(handle);
+ }
void NotifyV8MarkingWorklistWasEmpty() {
num_v8_marking_worklist_was_empty_++;
diff --git a/deps/v8/src/heap/factory-inl.h b/deps/v8/src/heap/factory-inl.h
index 9aa705047c..bcad5d2714 100644
--- a/deps/v8/src/heap/factory-inl.h
+++ b/deps/v8/src/heap/factory-inl.h
@@ -71,13 +71,6 @@ Handle<HeapNumber> Factory::NewHeapNumber(double value,
return heap_number;
}
-Handle<MutableHeapNumber> Factory::NewMutableHeapNumber(
- double value, AllocationType allocation) {
- Handle<MutableHeapNumber> number = NewMutableHeapNumber(allocation);
- number->set_value(value);
- return number;
-}
-
Handle<HeapNumber> Factory::NewHeapNumberFromBits(uint64_t bits,
AllocationType allocation) {
Handle<HeapNumber> heap_number = NewHeapNumber(allocation);
@@ -85,16 +78,9 @@ Handle<HeapNumber> Factory::NewHeapNumberFromBits(uint64_t bits,
return heap_number;
}
-Handle<MutableHeapNumber> Factory::NewMutableHeapNumberFromBits(
- uint64_t bits, AllocationType allocation) {
- Handle<MutableHeapNumber> number = NewMutableHeapNumber(allocation);
- number->set_value_as_bits(bits);
- return number;
-}
-
-Handle<MutableHeapNumber> Factory::NewMutableHeapNumberWithHoleNaN(
+Handle<HeapNumber> Factory::NewHeapNumberWithHoleNaN(
AllocationType allocation) {
- return NewMutableHeapNumberFromBits(kHoleNanInt64, allocation);
+ return NewHeapNumberFromBits(kHoleNanInt64, allocation);
}
Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArrayBase> elements,
diff --git a/deps/v8/src/heap/factory.cc b/deps/v8/src/heap/factory.cc
index 19c3665622..9bf46be6e8 100644
--- a/deps/v8/src/heap/factory.cc
+++ b/deps/v8/src/heap/factory.cc
@@ -285,11 +285,12 @@ HeapObject Factory::New(Handle<Map> map, AllocationType allocation) {
}
Handle<HeapObject> Factory::NewFillerObject(int size, bool double_align,
- AllocationType allocation) {
+ AllocationType allocation,
+ AllocationOrigin origin) {
AllocationAlignment alignment = double_align ? kDoubleAligned : kWordAligned;
Heap* heap = isolate()->heap();
HeapObject result =
- heap->AllocateRawWithRetryOrFail(size, allocation, alignment);
+ heap->AllocateRawWithRetryOrFail(size, allocation, origin, alignment);
heap->CreateFillerObjectAt(result.address(), size, ClearRecordedSlots::kNo);
return Handle<HeapObject>(result, isolate());
}
@@ -685,16 +686,19 @@ Handle<SmallOrderedNameDictionary> Factory::NewSmallOrderedNameDictionary(
}
Handle<OrderedHashSet> Factory::NewOrderedHashSet() {
- return OrderedHashSet::Allocate(isolate(), OrderedHashSet::kMinCapacity);
+ return OrderedHashSet::Allocate(isolate(), OrderedHashSet::kMinCapacity)
+ .ToHandleChecked();
}
Handle<OrderedHashMap> Factory::NewOrderedHashMap() {
- return OrderedHashMap::Allocate(isolate(), OrderedHashMap::kMinCapacity);
+ return OrderedHashMap::Allocate(isolate(), OrderedHashMap::kMinCapacity)
+ .ToHandleChecked();
}
Handle<OrderedNameDictionary> Factory::NewOrderedNameDictionary() {
return OrderedNameDictionary::Allocate(isolate(),
- OrderedNameDictionary::kMinCapacity);
+ OrderedNameDictionary::kMinCapacity)
+ .ToHandleChecked();
}
Handle<AccessorPair> Factory::NewAccessorPair() {
@@ -1744,16 +1748,6 @@ Handle<PromiseResolveThenableJobTask> Factory::NewPromiseResolveThenableJobTask(
return microtask;
}
-Handle<FinalizationGroupCleanupJobTask>
-Factory::NewFinalizationGroupCleanupJobTask(
- Handle<JSFinalizationGroup> finalization_group) {
- Handle<FinalizationGroupCleanupJobTask> microtask =
- Handle<FinalizationGroupCleanupJobTask>::cast(
- NewStruct(FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE));
- microtask->set_finalization_group(*finalization_group);
- return microtask;
-}
-
Handle<Foreign> Factory::NewForeign(Address addr, AllocationType allocation) {
// Statically ensure that it is safe to allocate foreigns in paged spaces.
STATIC_ASSERT(Foreign::kSize <= kMaxRegularHeapObjectSize);
@@ -2010,7 +2004,8 @@ Handle<JSObject> Factory::CopyJSObjectWithAllocationSite(
HeapObject raw_clone = isolate()->heap()->AllocateRawWithRetryOrFail(
adjusted_object_size, AllocationType::kYoung);
- DCHECK(Heap::InYoungGeneration(raw_clone));
+ DCHECK(Heap::InYoungGeneration(raw_clone) || FLAG_single_generation);
+
// Since we know the clone is allocated in new space, we can copy
// the contents without worrying about updating the write barrier.
Heap::CopyBlock(raw_clone.address(), source->address(), object_size);
@@ -2234,13 +2229,10 @@ Handle<HeapNumber> Factory::NewHeapNumber(AllocationType allocation) {
return handle(HeapNumber::cast(result), isolate());
}
-Handle<MutableHeapNumber> Factory::NewMutableHeapNumber(
- AllocationType allocation) {
- STATIC_ASSERT(HeapNumber::kSize <= kMaxRegularHeapObjectSize);
- Map map = *mutable_heap_number_map();
- HeapObject result = AllocateRawWithImmortalMap(
- MutableHeapNumber::kSize, allocation, map, kDoubleUnaligned);
- return handle(MutableHeapNumber::cast(result), isolate());
+Handle<HeapNumber> Factory::NewHeapNumberForCodeAssembler(double value) {
+ return NewHeapNumber(value, isolate()->heap()->CanAllocateInReadOnlySpace()
+ ? AllocationType::kReadOnly
+ : AllocationType::kOld);
}
Handle<FreshlyAllocatedBigInt> Factory::NewBigInt(int length,
@@ -2518,7 +2510,7 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
NewFunction(initial_map, info, context, allocation);
// Give compiler a chance to pre-initialize.
- Compiler::PostInstantiation(result, allocation);
+ Compiler::PostInstantiation(result);
return result;
}
@@ -2550,14 +2542,15 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
result->set_raw_feedback_cell(*feedback_cell);
// Give compiler a chance to pre-initialize.
- Compiler::PostInstantiation(result, allocation);
+ Compiler::PostInstantiation(result);
return result;
}
-Handle<ScopeInfo> Factory::NewScopeInfo(int length) {
+Handle<ScopeInfo> Factory::NewScopeInfo(int length, AllocationType type) {
+ DCHECK(type == AllocationType::kOld || type == AllocationType::kReadOnly);
return NewFixedArrayWithMap<ScopeInfo>(RootIndex::kScopeInfoMap, length,
- AllocationType::kOld);
+ type);
}
Handle<SourceTextModuleInfo> Factory::NewSourceTextModuleInfo() {
@@ -3716,6 +3709,7 @@ Handle<StackFrameInfo> Factory::NewStackFrameInfo(
Handle<Object> type_name = undefined_value();
Handle<Object> eval_origin = frame->GetEvalOrigin();
Handle<Object> wasm_module_name = frame->GetWasmModuleName();
+ Handle<Object> wasm_instance = frame->GetWasmInstance();
// MethodName and TypeName are expensive to look up, so they are only
// included when they are strictly needed by the stack trace
@@ -3751,6 +3745,7 @@ Handle<StackFrameInfo> Factory::NewStackFrameInfo(
info->set_type_name(*type_name);
info->set_eval_origin(*eval_origin);
info->set_wasm_module_name(*wasm_module_name);
+ info->set_wasm_instance(*wasm_instance);
info->set_is_eval(frame->IsEval());
info->set_is_constructor(is_constructor);
@@ -3904,9 +3899,12 @@ void Factory::SetRegExpIrregexpData(Handle<JSRegExp> regexp,
store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags));
store->set(JSRegExp::kIrregexpLatin1CodeIndex, uninitialized);
store->set(JSRegExp::kIrregexpUC16CodeIndex, uninitialized);
+ store->set(JSRegExp::kIrregexpLatin1BytecodeIndex, uninitialized);
+ store->set(JSRegExp::kIrregexpUC16BytecodeIndex, uninitialized);
store->set(JSRegExp::kIrregexpMaxRegisterCountIndex, Smi::kZero);
store->set(JSRegExp::kIrregexpCaptureCountIndex, Smi::FromInt(capture_count));
store->set(JSRegExp::kIrregexpCaptureNameMapIndex, uninitialized);
+ store->set(JSRegExp::kIrregexpTierUpTicksIndex, Smi::kZero);
regexp->set_data(*store);
}
diff --git a/deps/v8/src/heap/factory.h b/deps/v8/src/heap/factory.h
index 3ccbe6856f..1e47926e8e 100644
--- a/deps/v8/src/heap/factory.h
+++ b/deps/v8/src/heap/factory.h
@@ -37,7 +37,6 @@ class ArrayBoilerplateDescription;
class CoverageInfo;
class DebugInfo;
class EnumCache;
-class FinalizationGroupCleanupJobTask;
class FreshlyAllocatedBigInt;
class Isolate;
class JSArrayBufferView;
@@ -478,8 +477,6 @@ class V8_EXPORT_PRIVATE Factory {
Handle<PromiseResolveThenableJobTask> NewPromiseResolveThenableJobTask(
Handle<JSPromise> promise_to_resolve, Handle<JSReceiver> then,
Handle<JSReceiver> thenable, Handle<Context> context);
- Handle<FinalizationGroupCleanupJobTask> NewFinalizationGroupCleanupJobTask(
- Handle<JSFinalizationGroup> finalization_group);
// Foreign objects are pretenured when allocated by the bootstrapper.
Handle<Foreign> NewForeign(
@@ -521,8 +518,9 @@ class V8_EXPORT_PRIVATE Factory {
// Allocate a block of memory of the given AllocationType (filled with a
// filler). Used as a fall-back for generated code when the space is full.
- Handle<HeapObject> NewFillerObject(int size, bool double_align,
- AllocationType allocation);
+ Handle<HeapObject> NewFillerObject(
+ int size, bool double_align, AllocationType allocation,
+ AllocationOrigin origin = AllocationOrigin::kRuntime);
Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
@@ -589,13 +587,11 @@ class V8_EXPORT_PRIVATE Factory {
Handle<HeapNumber> NewHeapNumber(
AllocationType allocation = AllocationType::kYoung);
- Handle<MutableHeapNumber> NewMutableHeapNumber(
- AllocationType allocation = AllocationType::kYoung);
- inline Handle<MutableHeapNumber> NewMutableHeapNumber(
- double value, AllocationType allocation = AllocationType::kYoung);
- inline Handle<MutableHeapNumber> NewMutableHeapNumberFromBits(
- uint64_t bits, AllocationType allocation = AllocationType::kYoung);
- inline Handle<MutableHeapNumber> NewMutableHeapNumberWithHoleNaN(
+ // Creates a new HeapNumber in read-only space if possible otherwise old
+ // space.
+ Handle<HeapNumber> NewHeapNumberForCodeAssembler(double value);
+
+ inline Handle<HeapNumber> NewHeapNumberWithHoleNaN(
AllocationType allocation = AllocationType::kYoung);
// Allocates a new BigInt with {length} digits. Only to be used by
@@ -771,7 +767,8 @@ class V8_EXPORT_PRIVATE Factory {
AllocationType allocation = AllocationType::kOld);
// Create a serialized scope info.
- Handle<ScopeInfo> NewScopeInfo(int length);
+ Handle<ScopeInfo> NewScopeInfo(int length,
+ AllocationType type = AllocationType::kOld);
Handle<SourceTextModuleInfo> NewSourceTextModuleInfo();
diff --git a/deps/v8/src/heap/gc-tracer.cc b/deps/v8/src/heap/gc-tracer.cc
index 77e6b99997..85152c7bfe 100644
--- a/deps/v8/src/heap/gc-tracer.cc
+++ b/deps/v8/src/heap/gc-tracer.cc
@@ -26,6 +26,9 @@ static size_t CountTotalHolesSize(Heap* heap) {
}
return holes_size;
}
+WorkerThreadRuntimeCallStats* GCTracer::worker_thread_runtime_call_stats() {
+ return heap_->isolate()->counters()->worker_thread_runtime_call_stats();
+}
RuntimeCallCounterId GCTracer::RCSCounterFromScope(Scope::ScopeId id) {
STATIC_ASSERT(Scope::FIRST_SCOPE == Scope::MC_INCREMENTAL);
@@ -34,10 +37,20 @@ RuntimeCallCounterId GCTracer::RCSCounterFromScope(Scope::ScopeId id) {
static_cast<int>(id));
}
+RuntimeCallCounterId GCTracer::RCSCounterFromBackgroundScope(
+ BackgroundScope::ScopeId id) {
+ STATIC_ASSERT(Scope::FIRST_BACKGROUND_SCOPE ==
+ Scope::BACKGROUND_ARRAY_BUFFER_FREE);
+ STATIC_ASSERT(
+ 0 == static_cast<int>(BackgroundScope::BACKGROUND_ARRAY_BUFFER_FREE));
+ return static_cast<RuntimeCallCounterId>(
+ static_cast<int>(RCSCounterFromScope(Scope::FIRST_BACKGROUND_SCOPE)) +
+ static_cast<int>(id));
+}
+
GCTracer::Scope::Scope(GCTracer* tracer, ScopeId scope)
: tracer_(tracer), scope_(scope) {
start_time_ = tracer_->heap_->MonotonicallyIncreasingTimeInMs();
- // TODO(cbruni): remove once we fully moved to a trace-based system.
if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled())) return;
runtime_stats_ = tracer_->heap_->isolate()->counters()->runtime_call_stats();
runtime_stats_->Enter(&timer_, GCTracer::RCSCounterFromScope(scope));
@@ -46,30 +59,25 @@ GCTracer::Scope::Scope(GCTracer* tracer, ScopeId scope)
GCTracer::Scope::~Scope() {
tracer_->AddScopeSample(
scope_, tracer_->heap_->MonotonicallyIncreasingTimeInMs() - start_time_);
- // TODO(cbruni): remove once we fully moved to a trace-based system.
if (V8_LIKELY(runtime_stats_ == nullptr)) return;
runtime_stats_->Leave(&timer_);
}
-GCTracer::BackgroundScope::BackgroundScope(GCTracer* tracer, ScopeId scope)
- : tracer_(tracer), scope_(scope), runtime_stats_enabled_(false) {
+GCTracer::BackgroundScope::BackgroundScope(GCTracer* tracer, ScopeId scope,
+ RuntimeCallStats* runtime_stats)
+ : tracer_(tracer), scope_(scope), runtime_stats_(runtime_stats) {
start_time_ = tracer_->heap_->MonotonicallyIncreasingTimeInMs();
- // TODO(cbruni): remove once we fully moved to a trace-based system.
if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled())) return;
- timer_.Start(&counter_, nullptr);
- runtime_stats_enabled_ = true;
+ runtime_stats_->Enter(&timer_,
+ GCTracer::RCSCounterFromBackgroundScope(scope));
}
GCTracer::BackgroundScope::~BackgroundScope() {
double duration_ms =
tracer_->heap_->MonotonicallyIncreasingTimeInMs() - start_time_;
- // TODO(cbruni): remove once we fully moved to a trace-based system.
- if (V8_LIKELY(!runtime_stats_enabled_)) {
- tracer_->AddBackgroundScopeSample(scope_, duration_ms, nullptr);
- } else {
- timer_.Stop();
- tracer_->AddBackgroundScopeSample(scope_, duration_ms, &counter_);
- }
+ tracer_->AddBackgroundScopeSample(scope_, duration_ms);
+ if (V8_LIKELY(runtime_stats_ == nullptr)) return;
+ runtime_stats_->Leave(&timer_);
}
const char* GCTracer::Scope::Name(ScopeId id) {
@@ -170,7 +178,6 @@ GCTracer::GCTracer(Heap* heap)
current_.end_time = heap_->MonotonicallyIncreasingTimeInMs();
for (int i = 0; i < BackgroundScope::NUMBER_OF_SCOPES; i++) {
background_counter_[i].total_duration_ms = 0;
- background_counter_[i].runtime_call_counter = RuntimeCallCounter(nullptr);
}
}
@@ -204,7 +211,6 @@ void GCTracer::ResetForTesting() {
base::MutexGuard guard(&background_counter_mutex_);
for (int i = 0; i < BackgroundScope::NUMBER_OF_SCOPES; i++) {
background_counter_[i].total_duration_ms = 0;
- background_counter_[i].runtime_call_counter.Reset();
}
}
@@ -391,6 +397,12 @@ void GCTracer::NotifySweepingCompleted() {
"FreeLists statistics after sweeping completed:\n");
heap_->PrintFreeListsStats();
}
+ if (FLAG_trace_allocations_origins) {
+ heap_->new_space()->PrintAllocationsOrigins();
+ heap_->old_space()->PrintAllocationsOrigins();
+ heap_->code_space()->PrintAllocationsOrigins();
+ heap_->map_space()->PrintAllocationsOrigins();
+ }
}
void GCTracer::SampleAllocation(double current_ms,
@@ -1138,30 +1150,13 @@ void GCTracer::FetchBackgroundCounters(int first_global_scope,
background_counter_[first_background_scope + i].total_duration_ms;
background_counter_[first_background_scope + i].total_duration_ms = 0;
}
- if (V8_LIKELY(!TracingFlags::is_runtime_stats_enabled())) return;
- RuntimeCallStats* runtime_stats =
- heap_->isolate()->counters()->runtime_call_stats();
- if (!runtime_stats) return;
- for (int i = 0; i < background_mc_scopes; i++) {
- runtime_stats
- ->GetCounter(GCTracer::RCSCounterFromScope(
- static_cast<Scope::ScopeId>(first_global_scope + i)))
- ->Add(&background_counter_[first_background_scope + i]
- .runtime_call_counter);
- background_counter_[first_background_scope + i]
- .runtime_call_counter.Reset();
- }
}
-void GCTracer::AddBackgroundScopeSample(
- BackgroundScope::ScopeId scope, double duration,
- RuntimeCallCounter* runtime_call_counter) {
+void GCTracer::AddBackgroundScopeSample(BackgroundScope::ScopeId scope,
+ double duration) {
base::MutexGuard guard(&background_counter_mutex_);
BackgroundCounter& counter = background_counter_[scope];
counter.total_duration_ms += duration;
- if (runtime_call_counter) {
- counter.runtime_call_counter.Add(runtime_call_counter);
- }
}
void GCTracer::RecordGCPhasesHistograms(TimedHistogram* gc_timer) {
@@ -1197,10 +1192,7 @@ void GCTracer::RecordGCPhasesHistograms(TimedHistogram* gc_timer) {
DCHECK_GT(overall_marking_time, 0.0);
const double overall_v8_marking_time =
overall_marking_time -
- current_.scopes[Scope::MC_MARK_EMBEDDER_PROLOGUE] -
- current_.scopes[Scope::MC_MARK_EMBEDDER_TRACING] -
- current_.scopes[Scope::MC_INCREMENTAL_EMBEDDER_PROLOGUE] -
- current_.scopes[Scope::MC_INCREMENTAL_EMBEDDER_TRACING];
+ current_.scopes[Scope::MC_MARK_EMBEDDER_TRACING];
DCHECK_GT(overall_v8_marking_time, 0.0);
const int main_thread_marking_throughput_mb_per_s =
static_cast<int>(static_cast<double>(heap_->SizeOfObjects()) /
diff --git a/deps/v8/src/heap/gc-tracer.h b/deps/v8/src/heap/gc-tracer.h
index ec54b6c1ab..454bb9ff17 100644
--- a/deps/v8/src/heap/gc-tracer.h
+++ b/deps/v8/src/heap/gc-tracer.h
@@ -31,9 +31,12 @@ enum ScavengeSpeedMode { kForAllObjects, kForSurvivedObjects };
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.gc"), \
GCTracer::Scope::Name(gc_tracer_scope_id))
-#define TRACE_BACKGROUND_GC(tracer, scope_id) \
- GCTracer::BackgroundScope background_scope(tracer, scope_id); \
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.gc"), \
+#define TRACE_BACKGROUND_GC(tracer, scope_id) \
+ WorkerThreadRuntimeCallStatsScope runtime_call_stats_scope( \
+ tracer->worker_thread_runtime_call_stats()); \
+ GCTracer::BackgroundScope background_scope(tracer, scope_id, \
+ runtime_call_stats_scope.Get()); \
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.gc"), \
GCTracer::BackgroundScope::Name(scope_id))
// GCTracer collects and prints ONE line after each garbage collector
@@ -82,7 +85,8 @@ class V8_EXPORT_PRIVATE GCTracer {
FIRST_TOP_MC_SCOPE = MC_CLEAR,
LAST_TOP_MC_SCOPE = MC_SWEEP,
FIRST_MINOR_GC_BACKGROUND_SCOPE = MINOR_MC_BACKGROUND_EVACUATE_COPY,
- LAST_MINOR_GC_BACKGROUND_SCOPE = SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL
+ LAST_MINOR_GC_BACKGROUND_SCOPE = SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL,
+ FIRST_BACKGROUND_SCOPE = FIRST_GENERAL_BACKGROUND_SCOPE
};
Scope(GCTracer* tracer, ScopeId scope);
@@ -113,7 +117,8 @@ class V8_EXPORT_PRIVATE GCTracer {
FIRST_MINOR_GC_BACKGROUND_SCOPE = MINOR_MC_BACKGROUND_EVACUATE_COPY,
LAST_MINOR_GC_BACKGROUND_SCOPE = SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL
};
- BackgroundScope(GCTracer* tracer, ScopeId scope);
+ BackgroundScope(GCTracer* tracer, ScopeId scope,
+ RuntimeCallStats* runtime_stats);
~BackgroundScope();
static const char* Name(ScopeId id);
@@ -123,8 +128,7 @@ class V8_EXPORT_PRIVATE GCTracer {
ScopeId scope_;
double start_time_;
RuntimeCallTimer timer_;
- RuntimeCallCounter counter_;
- bool runtime_stats_enabled_;
+ RuntimeCallStats* runtime_stats_;
DISALLOW_COPY_AND_ASSIGN(BackgroundScope);
};
@@ -206,6 +210,8 @@ class V8_EXPORT_PRIVATE GCTracer {
double optional_speed);
static RuntimeCallCounterId RCSCounterFromScope(Scope::ScopeId id);
+ static RuntimeCallCounterId RCSCounterFromBackgroundScope(
+ BackgroundScope::ScopeId id);
explicit GCTracer(Heap* heap);
@@ -340,13 +346,15 @@ class V8_EXPORT_PRIVATE GCTracer {
}
}
- void AddBackgroundScopeSample(BackgroundScope::ScopeId scope, double duration,
- RuntimeCallCounter* runtime_call_counter);
+ void AddBackgroundScopeSample(BackgroundScope::ScopeId scope,
+ double duration);
void RecordGCPhasesHistograms(TimedHistogram* gc_timer);
void RecordEmbedderSpeed(size_t bytes, double duration);
+ WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats();
+
private:
FRIEND_TEST(GCTracer, AverageSpeed);
FRIEND_TEST(GCTracerTest, AllocationThroughput);
@@ -369,7 +377,6 @@ class V8_EXPORT_PRIVATE GCTracer {
struct BackgroundCounter {
double total_duration_ms;
- RuntimeCallCounter runtime_call_counter;
};
// Returns the average speed of the events in the buffer.
diff --git a/deps/v8/src/heap/heap-inl.h b/deps/v8/src/heap/heap-inl.h
index f2f7a7f692..da803f3339 100644
--- a/deps/v8/src/heap/heap-inl.h
+++ b/deps/v8/src/heap/heap-inl.h
@@ -67,7 +67,7 @@ void Heap::update_external_memory(int64_t delta) {
isolate()->isolate_data()->external_memory_ += delta;
}
-void Heap::update_external_memory_concurrently_freed(intptr_t freed) {
+void Heap::update_external_memory_concurrently_freed(uintptr_t freed) {
external_memory_concurrently_freed_ += freed;
}
@@ -159,6 +159,7 @@ size_t Heap::NewSpaceAllocationCounter() {
}
AllocationResult Heap::AllocateRaw(int size_in_bytes, AllocationType type,
+ AllocationOrigin origin,
AllocationAlignment alignment) {
DCHECK(AllowHandleAllocation::IsAllowed());
DCHECK(AllowHeapAllocation::IsAllowed());
@@ -179,6 +180,9 @@ AllocationResult Heap::AllocateRaw(int size_in_bytes, AllocationType type,
HeapObject object;
AllocationResult allocation;
+ if (FLAG_single_generation && type == AllocationType::kYoung)
+ type = AllocationType::kOld;
+
if (AllocationType::kYoung == type) {
if (large_object) {
if (FLAG_young_generation_large_objects) {
@@ -191,13 +195,13 @@ AllocationResult Heap::AllocateRaw(int size_in_bytes, AllocationType type,
allocation = lo_space_->AllocateRaw(size_in_bytes);
}
} else {
- allocation = new_space_->AllocateRaw(size_in_bytes, alignment);
+ allocation = new_space_->AllocateRaw(size_in_bytes, alignment, origin);
}
} else if (AllocationType::kOld == type) {
if (large_object) {
allocation = lo_space_->AllocateRaw(size_in_bytes);
} else {
- allocation = old_space_->AllocateRaw(size_in_bytes, alignment);
+ allocation = old_space_->AllocateRaw(size_in_bytes, alignment, origin);
}
} else if (AllocationType::kCode == type) {
if (size_in_bytes <= code_space()->AreaSize() && !large_object) {
@@ -213,7 +217,9 @@ AllocationResult Heap::AllocateRaw(int size_in_bytes, AllocationType type,
#endif
DCHECK(!large_object);
DCHECK(CanAllocateInReadOnlySpace());
- allocation = read_only_space_->AllocateRaw(size_in_bytes, alignment);
+ DCHECK_EQ(AllocationOrigin::kRuntime, origin);
+ allocation =
+ read_only_space_->AllocateRaw(size_in_bytes, alignment, origin);
} else {
UNREACHABLE();
}
diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc
index 7feb1c11ba..51f300b577 100644
--- a/deps/v8/src/heap/heap.cc
+++ b/deps/v8/src/heap/heap.cc
@@ -270,10 +270,11 @@ size_t Heap::MinOldGenerationSize() {
size_t Heap::MaxOldGenerationSize(uint64_t physical_memory) {
size_t max_size = V8HeapTrait::kMaxSize;
// Finch experiment: Increase the heap size from 2GB to 4GB for 64-bit
- // systems with physical memory bigger than 16GB.
+ // systems with physical memory bigger than 16GB. The physical memory
+ // is rounded up to GB.
constexpr bool x64_bit = Heap::kPointerMultiplier >= 2;
if (FLAG_huge_max_old_generation_size && x64_bit &&
- physical_memory / GB > 16) {
+ (physical_memory + 512 * MB) / GB >= 16) {
DCHECK_EQ(max_size / GB, 2);
max_size *= 2;
}
@@ -1107,6 +1108,15 @@ void Heap::GarbageCollectionEpilogue() {
AllowHeapAllocation for_the_rest_of_the_epilogue;
#ifdef DEBUG
+ // Old-to-new slot sets must be empty after each collection.
+ for (SpaceIterator it(this); it.HasNext();) {
+ Space* space = it.Next();
+
+ for (MemoryChunk* chunk = space->first_page(); chunk != space->last_page();
+ chunk = chunk->list_node().next())
+ DCHECK_NULL(chunk->invalidated_slots<OLD_TO_NEW>());
+ }
+
if (FLAG_print_global_handles) isolate_->global_handles()->Print();
if (FLAG_print_handles) PrintHandles();
if (FLAG_gc_verbose) Print();
@@ -1179,16 +1189,9 @@ void Heap::GarbageCollectionEpilogue() {
}
if (FLAG_harmony_weak_refs) {
- // TODO(marja): (spec): The exact condition on when to schedule the cleanup
- // task is unclear. This version schedules the cleanup task for a
- // JSFinalizationGroup whenever the GC has discovered new dirty WeakCells
- // for it (at that point it might have leftover dirty WeakCells since an
- // earlier invocation of the cleanup function didn't iterate through
- // them). See https://github.com/tc39/proposal-weakrefs/issues/34
HandleScope handle_scope(isolate());
while (!isolate()->heap()->dirty_js_finalization_groups().IsUndefined(
isolate())) {
- // Enqueue one microtask per JSFinalizationGroup.
Handle<JSFinalizationGroup> finalization_group(
JSFinalizationGroup::cast(
isolate()->heap()->dirty_js_finalization_groups()),
@@ -1196,22 +1199,7 @@ void Heap::GarbageCollectionEpilogue() {
isolate()->heap()->set_dirty_js_finalization_groups(
finalization_group->next());
finalization_group->set_next(ReadOnlyRoots(isolate()).undefined_value());
- Handle<NativeContext> context(finalization_group->native_context(),
- isolate());
- // GC has no native context, but we use the creation context of the
- // JSFinalizationGroup for the EnqueueTask operation. This is consitent
- // with the Promise implementation, assuming the JSFinalizationGroup's
- // creation context is the "caller's context" in promise functions. An
- // alternative would be to use the native context of the cleanup
- // function. This difference shouldn't be observable from JavaScript,
- // since we enter the native context of the cleanup function before
- // calling it. TODO(marja): Revisit when the spec clarifies this. See also
- // https://github.com/tc39/proposal-weakrefs/issues/38 .
- Handle<FinalizationGroupCleanupJobTask> task =
- isolate()->factory()->NewFinalizationGroupCleanupJobTask(
- finalization_group);
- MicrotaskQueue* microtask_queue = context->microtask_queue();
- if (microtask_queue) microtask_queue->EnqueueMicrotask(*task);
+ isolate()->RunHostCleanupFinalizationGroupCallback(finalization_group);
}
}
}
@@ -2841,6 +2829,9 @@ HeapObject Heap::CreateFillerObjectAt(Address addr, int size,
ClearFreedMemoryMode clear_memory_mode) {
if (size == 0) return HeapObject();
HeapObject filler = HeapObject::FromAddress(addr);
+ bool clear_memory =
+ (clear_memory_mode == ClearFreedMemoryMode::kClearFreedMemory ||
+ clear_slots_mode == ClearRecordedSlots::kYes);
if (size == kTaggedSize) {
filler.set_map_after_allocation(
Map::unchecked_cast(isolate()->root(RootIndex::kOnePointerFillerMap)),
@@ -2849,9 +2840,9 @@ HeapObject Heap::CreateFillerObjectAt(Address addr, int size,
filler.set_map_after_allocation(
Map::unchecked_cast(isolate()->root(RootIndex::kTwoPointerFillerMap)),
SKIP_WRITE_BARRIER);
- if (clear_memory_mode == ClearFreedMemoryMode::kClearFreedMemory) {
- Memory<Tagged_t>(addr + kTaggedSize) =
- static_cast<Tagged_t>(kClearedFreeMemoryValue);
+ if (clear_memory) {
+ AtomicSlot slot(ObjectSlot(addr) + 1);
+ *slot = static_cast<Tagged_t>(kClearedFreeMemoryValue);
}
} else {
DCHECK_GT(size, 2 * kTaggedSize);
@@ -2859,7 +2850,7 @@ HeapObject Heap::CreateFillerObjectAt(Address addr, int size,
Map::unchecked_cast(isolate()->root(RootIndex::kFreeSpaceMap)),
SKIP_WRITE_BARRIER);
FreeSpace::cast(filler).relaxed_write_size(size);
- if (clear_memory_mode == ClearFreedMemoryMode::kClearFreedMemory) {
+ if (clear_memory) {
MemsetTagged(ObjectSlot(addr) + 2, Object(kClearedFreeMemoryValue),
(size / kTaggedSize) - 2);
}
@@ -2944,6 +2935,9 @@ void Heap::OnMoveEvent(HeapObject target, HeapObject source,
if (target.IsSharedFunctionInfo()) {
LOG_CODE_EVENT(isolate_, SharedFunctionInfoMoveEvent(source.address(),
target.address()));
+ } else if (target.IsNativeContext()) {
+ PROFILE(isolate_,
+ NativeContextMoveEvent(source.address(), target.address()));
}
if (FLAG_verify_predictable) {
@@ -3000,11 +2994,21 @@ FixedArrayBase Heap::LeftTrimFixedArray(FixedArrayBase object,
object, HeapObject::FromAddress(new_start));
}
+#ifdef DEBUG
+ if (MayContainRecordedSlots(object)) {
+ MemoryChunk* chunk = MemoryChunk::FromHeapObject(object);
+ DCHECK(!chunk->RegisteredObjectWithInvalidatedSlots<OLD_TO_OLD>(object));
+ DCHECK(!chunk->RegisteredObjectWithInvalidatedSlots<OLD_TO_NEW>(object));
+ }
+#endif
+
// Technically in new space this write might be omitted (except for
// debug mode which iterates through the heap), but to play safer
// we still do it.
- HeapObject filler =
- CreateFillerObjectAt(old_start, bytes_to_trim, ClearRecordedSlots::kYes);
+ CreateFillerObjectAt(old_start, bytes_to_trim,
+ MayContainRecordedSlots(object)
+ ? ClearRecordedSlots::kYes
+ : ClearRecordedSlots::kNo);
// Initialize header of the trimmed array. Since left trimming is only
// performed on pages which are not concurrently swept creating a filler
@@ -3016,28 +3020,6 @@ FixedArrayBase Heap::LeftTrimFixedArray(FixedArrayBase object,
FixedArrayBase new_object =
FixedArrayBase::cast(HeapObject::FromAddress(new_start));
- // Remove recorded slots for the new map and length offset.
- ClearRecordedSlot(new_object, new_object.RawField(0));
- ClearRecordedSlot(new_object,
- new_object.RawField(FixedArrayBase::kLengthOffset));
-
- // Handle invalidated old-to-old slots.
- if (incremental_marking()->IsCompacting() &&
- MayContainRecordedSlots(new_object)) {
- // If the array was right-trimmed before, then it is registered in
- // the invalidated_slots.
- MemoryChunk::FromHeapObject(new_object)
- ->MoveObjectWithInvalidatedSlots(filler, new_object);
- // We have to clear slots in the free space to avoid stale old-to-old slots.
- // Note we cannot use ClearFreedMemoryMode of CreateFillerObjectAt because
- // we need pointer granularity writes to avoid race with the concurrent
- // marking.
- if (filler.Size() > FreeSpace::kSize) {
- MemsetTagged(filler.RawField(FreeSpace::kSize),
- ReadOnlyRoots(this).undefined_value(),
- (filler.Size() - FreeSpace::kSize) / kTaggedSize);
- }
- }
// Notify the heap profiler of change in object layout.
OnMoveEvent(new_object, object, new_object.Size());
@@ -3106,26 +3088,24 @@ void Heap::CreateFillerForArray(T object, int elements_to_trim,
Address old_end = object.address() + old_size;
Address new_end = old_end - bytes_to_trim;
- // Register the array as an object with invalidated old-to-old slots. We
- // cannot use NotifyObjectLayoutChange as it would mark the array black,
- // which is not safe for left-trimming because left-trimming re-pushes
- // only grey arrays onto the marking worklist.
- if (incremental_marking()->IsCompacting() &&
- MayContainRecordedSlots(object)) {
- // Ensure that the object survives because the InvalidatedSlotsFilter will
- // compute its size from its map during pointers updating phase.
- incremental_marking()->WhiteToGreyAndPush(object);
- MemoryChunk::FromHeapObject(object)->RegisterObjectWithInvalidatedSlots(
- object, old_size);
+#ifdef DEBUG
+ if (MayContainRecordedSlots(object)) {
+ MemoryChunk* chunk = MemoryChunk::FromHeapObject(object);
+ DCHECK(!chunk->RegisteredObjectWithInvalidatedSlots<OLD_TO_NEW>(object));
+ DCHECK(!chunk->RegisteredObjectWithInvalidatedSlots<OLD_TO_OLD>(object));
}
+#endif
+
+ bool clear_slots = MayContainRecordedSlots(object);
// Technically in new space this write might be omitted (except for
// debug mode which iterates through the heap), but to play safer
// we still do it.
// We do not create a filler for objects in a large object space.
if (!IsLargeObject(object)) {
- HeapObject filler =
- CreateFillerObjectAt(new_end, bytes_to_trim, ClearRecordedSlots::kNo);
+ HeapObject filler = CreateFillerObjectAt(
+ new_end, bytes_to_trim,
+ clear_slots ? ClearRecordedSlots::kYes : ClearRecordedSlots::kNo);
DCHECK(!filler.is_null());
// Clear the mark bits of the black area that belongs now to the filler.
// This is an optimization. The sweeper will release black fillers anyway.
@@ -3136,6 +3116,11 @@ void Heap::CreateFillerForArray(T object, int elements_to_trim,
page->AddressToMarkbitIndex(new_end),
page->AddressToMarkbitIndex(new_end + bytes_to_trim));
}
+ } else if (clear_slots) {
+ // Large objects are not swept, so it is not necessary to clear the
+ // recorded slot.
+ MemsetTagged(ObjectSlot(new_end), Object(kClearedFreeMemoryValue),
+ (old_end - new_end) / kTaggedSize);
}
// Initialize header of the trimmed array. We are storing the new length
@@ -3408,10 +3393,14 @@ void Heap::NotifyObjectLayoutChange(HeapObject object, int size,
incremental_marking()->MarkBlackAndVisitObjectDueToLayoutChange(object);
if (incremental_marking()->IsCompacting() &&
MayContainRecordedSlots(object)) {
- MemoryChunk::FromHeapObject(object)->RegisterObjectWithInvalidatedSlots(
- object, size);
+ MemoryChunk::FromHeapObject(object)
+ ->RegisterObjectWithInvalidatedSlots<OLD_TO_OLD>(object, size);
}
}
+ if (MayContainRecordedSlots(object)) {
+ MemoryChunk::FromHeapObject(object)
+ ->RegisterObjectWithInvalidatedSlots<OLD_TO_NEW>(object, size);
+ }
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
DCHECK(pending_layout_change_object_.is_null());
@@ -4451,6 +4440,7 @@ void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints) {
static_cast<size_t>(base::bits::RoundUpToPowerOfTwo64(
static_cast<uint64_t>(max_semi_space_size_)));
max_semi_space_size_ = Max(max_semi_space_size_, kMinSemiSpaceSize);
+ max_semi_space_size_ = Min(max_semi_space_size_, kMaxSemiSpaceSize);
max_semi_space_size_ = RoundDown<Page::kPageSize>(max_semi_space_size_);
}
@@ -4495,6 +4485,14 @@ void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints) {
initial_semispace_size_ = SemiSpaceSizeFromYoungGenerationSize(
constraints.initial_young_generation_size_in_bytes());
}
+ if (FLAG_initial_heap_size > 0) {
+ size_t young_generation, old_generation;
+ Heap::GenerationSizesFromHeapSize(
+ static_cast<size_t>(FLAG_initial_heap_size) * MB, &young_generation,
+ &old_generation);
+ initial_semispace_size_ =
+ SemiSpaceSizeFromYoungGenerationSize(young_generation);
+ }
if (FLAG_min_semi_space_size > 0) {
initial_semispace_size_ =
static_cast<size_t>(FLAG_min_semi_space_size) * MB;
@@ -4513,6 +4511,17 @@ void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints) {
constraints.initial_old_generation_size_in_bytes();
old_generation_size_configured_ = true;
}
+ if (FLAG_initial_heap_size > 0) {
+ size_t initial_heap_size =
+ static_cast<size_t>(FLAG_initial_heap_size) * MB;
+ size_t young_generation_size =
+ YoungGenerationSizeFromSemiSpaceSize(initial_semispace_size_);
+ initial_old_generation_size_ =
+ initial_heap_size > young_generation_size
+ ? initial_heap_size - young_generation_size
+ : 0;
+ old_generation_size_configured_ = true;
+ }
if (FLAG_initial_old_space_size > 0) {
initial_old_generation_size_ =
static_cast<size_t>(FLAG_initial_old_space_size) * MB;
@@ -4875,9 +4884,10 @@ HeapObject Heap::EnsureImmovableCode(HeapObject heap_object, int object_size) {
}
HeapObject Heap::AllocateRawWithLightRetry(int size, AllocationType allocation,
+ AllocationOrigin origin,
AllocationAlignment alignment) {
HeapObject result;
- AllocationResult alloc = AllocateRaw(size, allocation, alignment);
+ AllocationResult alloc = AllocateRaw(size, allocation, origin, alignment);
if (alloc.To(&result)) {
DCHECK(result != ReadOnlyRoots(this).exception());
return result;
@@ -4886,7 +4896,7 @@ HeapObject Heap::AllocateRawWithLightRetry(int size, AllocationType allocation,
for (int i = 0; i < 2; i++) {
CollectGarbage(alloc.RetrySpace(),
GarbageCollectionReason::kAllocationFailure);
- alloc = AllocateRaw(size, allocation, alignment);
+ alloc = AllocateRaw(size, allocation, origin, alignment);
if (alloc.To(&result)) {
DCHECK(result != ReadOnlyRoots(this).exception());
return result;
@@ -4896,16 +4906,18 @@ HeapObject Heap::AllocateRawWithLightRetry(int size, AllocationType allocation,
}
HeapObject Heap::AllocateRawWithRetryOrFail(int size, AllocationType allocation,
+ AllocationOrigin origin,
AllocationAlignment alignment) {
AllocationResult alloc;
- HeapObject result = AllocateRawWithLightRetry(size, allocation, alignment);
+ HeapObject result =
+ AllocateRawWithLightRetry(size, allocation, origin, alignment);
if (!result.is_null()) return result;
isolate()->counters()->gc_last_resort_from_handles()->Increment();
CollectAllAvailableGarbage(GarbageCollectionReason::kLastResort);
{
AlwaysAllocateScope scope(isolate());
- alloc = AllocateRaw(size, allocation, alignment);
+ alloc = AllocateRaw(size, allocation, origin, alignment);
}
if (alloc.To(&result)) {
DCHECK(result != ReadOnlyRoots(this).exception());
@@ -5087,25 +5099,6 @@ void Heap::InitializeHashSeed() {
0, reinterpret_cast<byte*>(&new_hash_seed), kInt64Size);
}
-void Heap::SetStackLimits() {
- DCHECK_NOT_NULL(isolate_);
- DCHECK(isolate_ == isolate());
- // On 64 bit machines, pointers are generally out of range of Smis. We write
- // something that looks like an out of range Smi to the GC.
-
- // Set up the special root array entries containing the stack limits.
- // These are actually addresses, but the tag makes the GC ignore it.
- roots_table()[RootIndex::kStackLimit] =
- (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag;
- roots_table()[RootIndex::kRealStackLimit] =
- (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag;
-}
-
-void Heap::ClearStackLimits() {
- roots_table()[RootIndex::kStackLimit] = kNullAddress;
- roots_table()[RootIndex::kRealStackLimit] = kNullAddress;
-}
-
int Heap::NextAllocationTimeout(int current_timeout) {
if (FLAG_random_gc_interval > 0) {
// If current timeout hasn't reached 0 the GC was caused by something
@@ -5541,7 +5534,8 @@ void Heap::ClearRecordedSlot(HeapObject object, ObjectSlot slot) {
Page* page = Page::FromAddress(slot.address());
if (!page->InYoungGeneration()) {
DCHECK_EQ(page->owner_identity(), OLD_SPACE);
- store_buffer()->DeleteEntry(slot.address());
+ store_buffer()->MoveAllEntriesToRememberedSet();
+ RememberedSet<OLD_TO_NEW>::Remove(page, slot.address());
}
}
@@ -5555,7 +5549,7 @@ void Heap::VerifyClearedSlot(HeapObject object, ObjectSlot slot) {
CHECK(!RememberedSet<OLD_TO_NEW>::Contains(page, slot.address()));
// Old to old slots are filtered with invalidated slots.
CHECK_IMPLIES(RememberedSet<OLD_TO_OLD>::Contains(page, slot.address()),
- page->RegisteredObjectWithInvalidatedSlots(object));
+ page->RegisteredObjectWithInvalidatedSlots<OLD_TO_OLD>(object));
}
#endif
@@ -5564,7 +5558,9 @@ void Heap::ClearRecordedSlotRange(Address start, Address end) {
DCHECK(!page->IsLargePage());
if (!page->InYoungGeneration()) {
DCHECK_EQ(page->owner_identity(), OLD_SPACE);
- store_buffer()->DeleteEntry(start, end);
+ store_buffer()->MoveAllEntriesToRememberedSet();
+ RememberedSet<OLD_TO_NEW>::RemoveRange(page, start, end,
+ SlotSet::KEEP_EMPTY_BUCKETS);
}
}
@@ -5925,7 +5921,7 @@ void Heap::KeepDuringJob(Handle<JSReceiver> target) {
table =
handle(OrderedHashSet::cast(weak_refs_keep_during_job()), isolate());
}
- table = OrderedHashSet::Add(isolate(), table, target);
+ table = OrderedHashSet::Add(isolate(), table, target).ToHandleChecked();
set_weak_refs_keep_during_job(*table);
}
diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h
index 81f2b0dd8c..2b8b963a79 100644
--- a/deps/v8/src/heap/heap.h
+++ b/deps/v8/src/heap/heap.h
@@ -96,6 +96,15 @@ enum class TraceRetainingPathMode { kEnabled, kDisabled };
enum class RetainingPathOption { kDefault, kTrackEphemeronPath };
+enum class AllocationOrigin {
+ kGeneratedCode = 0,
+ kRuntime = 1,
+ kGC = 2,
+ kFirstAllocationOrigin = kGeneratedCode,
+ kLastAllocationOrigin = kGC,
+ kNumberOfAllocationOrigins = kLastAllocationOrigin + 1
+};
+
enum class GarbageCollectionReason {
kUnknown = 0,
kAllocationFailure = 1,
@@ -576,7 +585,7 @@ class Heap {
V8_INLINE int64_t external_memory();
V8_INLINE void update_external_memory(int64_t delta);
- V8_INLINE void update_external_memory_concurrently_freed(intptr_t freed);
+ V8_INLINE void update_external_memory_concurrently_freed(uintptr_t freed);
V8_INLINE void account_external_memory_concurrently_freed();
size_t backing_store_bytes() const { return backing_store_bytes_; }
@@ -713,15 +722,6 @@ class Heap {
V8_INLINE void SetMessageListeners(TemplateList value);
V8_INLINE void SetPendingOptimizeForTestBytecode(Object bytecode);
- // Set the stack limit in the roots table. Some architectures generate
- // code that looks here, because it is faster than loading from the static
- // jslimit_/real_jslimit_ variable in the StackGuard.
- void SetStackLimits();
-
- // The stack limit is thread-dependent. To be able to reproduce the same
- // snapshot blob, we need to reset it before serializing.
- void ClearStackLimits();
-
void RegisterStrongRoots(FullObjectSlot start, FullObjectSlot end);
void UnregisterStrongRoots(FullObjectSlot start);
@@ -1729,7 +1729,8 @@ class Heap {
// inlined allocations, use the Heap::DisableInlineAllocation() support).
V8_WARN_UNUSED_RESULT inline AllocationResult AllocateRaw(
int size_in_bytes, AllocationType allocation,
- AllocationAlignment aligment = kWordAligned);
+ AllocationOrigin origin = AllocationOrigin::kRuntime,
+ AllocationAlignment alignment = kWordAligned);
// This method will try to perform an allocation of a given size of a given
// AllocationType. If the allocation fails, a regular full garbage collection
@@ -1737,8 +1738,14 @@ class Heap {
// times. If after that retry procedure the allocation still fails nullptr is
// returned.
HeapObject AllocateRawWithLightRetry(
- int size, AllocationType allocation,
+ int size, AllocationType allocation, AllocationOrigin origin,
AllocationAlignment alignment = kWordAligned);
+ HeapObject AllocateRawWithLightRetry(
+ int size, AllocationType allocation,
+ AllocationAlignment alignment = kWordAligned) {
+ return AllocateRawWithLightRetry(size, allocation,
+ AllocationOrigin::kRuntime, alignment);
+ }
// This method will try to perform an allocation of a given size of a given
// AllocationType. If the allocation fails, a regular full garbage collection
@@ -1747,8 +1754,15 @@ class Heap {
// garbage collection is triggered which tries to significantly reduce memory.
// If the allocation still fails after that a fatal error is thrown.
HeapObject AllocateRawWithRetryOrFail(
- int size, AllocationType allocation,
+ int size, AllocationType allocation, AllocationOrigin origin,
AllocationAlignment alignment = kWordAligned);
+ HeapObject AllocateRawWithRetryOrFail(
+ int size, AllocationType allocation,
+ AllocationAlignment alignment = kWordAligned) {
+ return AllocateRawWithRetryOrFail(size, allocation,
+ AllocationOrigin::kRuntime, alignment);
+ }
+
HeapObject AllocateRawCodeInLargeObjectSpace(int size);
// Allocates a heap object based on the map.
@@ -1789,7 +1803,7 @@ class Heap {
#endif // DEBUG
// The amount of memory that has been freed concurrently.
- std::atomic<intptr_t> external_memory_concurrently_freed_{0};
+ std::atomic<uintptr_t> external_memory_concurrently_freed_{0};
// This can be calculated directly from a pointer to the heap; however, it is
// more expedient to get at the isolate directly from within Heap methods.
diff --git a/deps/v8/src/heap/invalidated-slots-inl.h b/deps/v8/src/heap/invalidated-slots-inl.h
index 58f6ac9bc8..35a08108f6 100644
--- a/deps/v8/src/heap/invalidated-slots-inl.h
+++ b/deps/v8/src/heap/invalidated-slots-inl.h
@@ -62,6 +62,48 @@ bool InvalidatedSlotsFilter::IsValid(Address slot) {
return invalidated_object_.IsValidSlot(invalidated_object_.map(), offset);
}
+void InvalidatedSlotsCleanup::Free(Address free_start, Address free_end) {
+#ifdef DEBUG
+ DCHECK_LT(free_start, free_end);
+ // Free regions should come in increasing order and do not overlap
+ DCHECK_LE(last_free_, free_start);
+ last_free_ = free_start;
+#endif
+
+ if (iterator_ == iterator_end_) return;
+
+ // Ignore invalidated objects before free region
+ while (free_start >= invalidated_end_) {
+ ++iterator_;
+ NextInvalidatedObject();
+ }
+
+ // Loop here: Free region might contain multiple invalidated objects
+ while (free_end > invalidated_start_) {
+ // Case: Free region starts before current invalidated object
+ if (free_start <= invalidated_start_) {
+ iterator_ = invalidated_slots_->erase(iterator_);
+
+ } else {
+ // Case: Free region starts within current invalidated object
+ // (Can happen for right-trimmed objects)
+ iterator_++;
+ }
+
+ NextInvalidatedObject();
+ }
+}
+
+void InvalidatedSlotsCleanup::NextInvalidatedObject() {
+ if (iterator_ != iterator_end_) {
+ invalidated_start_ = iterator_->first.address();
+ invalidated_end_ = invalidated_start_ + iterator_->second;
+ } else {
+ invalidated_start_ = sentinel_;
+ invalidated_end_ = sentinel_;
+ }
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/heap/invalidated-slots.cc b/deps/v8/src/heap/invalidated-slots.cc
index 368d189c55..8fa1518d68 100644
--- a/deps/v8/src/heap/invalidated-slots.cc
+++ b/deps/v8/src/heap/invalidated-slots.cc
@@ -8,18 +8,35 @@
namespace v8 {
namespace internal {
-InvalidatedSlotsFilter::InvalidatedSlotsFilter(MemoryChunk* chunk) {
- // Adjust slots_in_free_space_are_valid_ if more spaces are added.
- DCHECK_IMPLIES(chunk->invalidated_slots() != nullptr,
- chunk->InOldSpace() || chunk->InLargeObjectSpace());
+InvalidatedSlotsFilter InvalidatedSlotsFilter::OldToOld(MemoryChunk* chunk) {
// The sweeper removes invalid slots and makes free space available for
// allocation. Slots for new objects can be recorded in the free space.
// Note that we cannot simply check for SweepingDone because pages in large
// object space are not swept but have SweepingDone() == true.
- slots_in_free_space_are_valid_ = chunk->SweepingDone() && chunk->InOldSpace();
+ bool slots_in_free_space_are_valid =
+ chunk->SweepingDone() && chunk->InOldSpace();
+ return InvalidatedSlotsFilter(chunk, chunk->invalidated_slots<OLD_TO_OLD>(),
+ slots_in_free_space_are_valid);
+}
+
+InvalidatedSlotsFilter InvalidatedSlotsFilter::OldToNew(MemoryChunk* chunk) {
+ // Always treat these slots as valid for old-to-new for now. Invalid
+ // old-to-new slots are always cleared.
+ bool slots_in_free_space_are_valid = true;
+ return InvalidatedSlotsFilter(chunk, chunk->invalidated_slots<OLD_TO_NEW>(),
+ slots_in_free_space_are_valid);
+}
+
+InvalidatedSlotsFilter::InvalidatedSlotsFilter(
+ MemoryChunk* chunk, InvalidatedSlots* invalidated_slots,
+ bool slots_in_free_space_are_valid) {
+ // Adjust slots_in_free_space_are_valid_ if more spaces are added.
+ DCHECK_IMPLIES(invalidated_slots != nullptr,
+ chunk->InOldSpace() || chunk->InLargeObjectSpace());
+
+ slots_in_free_space_are_valid_ = slots_in_free_space_are_valid;
+ invalidated_slots = invalidated_slots ? invalidated_slots : &empty_;
- InvalidatedSlots* invalidated_slots =
- chunk->invalidated_slots() ? chunk->invalidated_slots() : &empty_;
iterator_ = invalidated_slots->begin();
iterator_end_ = invalidated_slots->end();
sentinel_ = chunk->area_end();
@@ -37,5 +54,33 @@ InvalidatedSlotsFilter::InvalidatedSlotsFilter(MemoryChunk* chunk) {
#endif
}
+InvalidatedSlotsCleanup InvalidatedSlotsCleanup::OldToNew(MemoryChunk* chunk) {
+ return InvalidatedSlotsCleanup(chunk, chunk->invalidated_slots<OLD_TO_NEW>());
+}
+
+InvalidatedSlotsCleanup InvalidatedSlotsCleanup::NoCleanup(MemoryChunk* chunk) {
+ return InvalidatedSlotsCleanup(chunk, nullptr);
+}
+
+InvalidatedSlotsCleanup::InvalidatedSlotsCleanup(
+ MemoryChunk* chunk, InvalidatedSlots* invalidated_slots) {
+ invalidated_slots_ = invalidated_slots ? invalidated_slots : &empty_;
+ iterator_ = invalidated_slots_->begin();
+ iterator_end_ = invalidated_slots_->end();
+ sentinel_ = chunk->area_end();
+
+ if (iterator_ != iterator_end_) {
+ invalidated_start_ = iterator_->first.address();
+ invalidated_end_ = invalidated_start_ + iterator_->second;
+ } else {
+ invalidated_start_ = sentinel_;
+ invalidated_end_ = sentinel_;
+ }
+
+#ifdef DEBUG
+ last_free_ = chunk->area_start();
+#endif
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/heap/invalidated-slots.h b/deps/v8/src/heap/invalidated-slots.h
index 4098595fe4..4a72271910 100644
--- a/deps/v8/src/heap/invalidated-slots.h
+++ b/deps/v8/src/heap/invalidated-slots.h
@@ -30,7 +30,12 @@ using InvalidatedSlots = std::map<HeapObject, int, Object::Comparer>;
// n is the number of IsValid queries.
class V8_EXPORT_PRIVATE InvalidatedSlotsFilter {
public:
- explicit InvalidatedSlotsFilter(MemoryChunk* chunk);
+ static InvalidatedSlotsFilter OldToOld(MemoryChunk* chunk);
+ static InvalidatedSlotsFilter OldToNew(MemoryChunk* chunk);
+
+ explicit InvalidatedSlotsFilter(MemoryChunk* chunk,
+ InvalidatedSlots* invalidated_slots,
+ bool slots_in_free_space_are_valid);
inline bool IsValid(Address slot);
private:
@@ -48,6 +53,32 @@ class V8_EXPORT_PRIVATE InvalidatedSlotsFilter {
#endif
};
+class V8_EXPORT_PRIVATE InvalidatedSlotsCleanup {
+ public:
+ static InvalidatedSlotsCleanup OldToNew(MemoryChunk* chunk);
+ static InvalidatedSlotsCleanup NoCleanup(MemoryChunk* chunk);
+
+ explicit InvalidatedSlotsCleanup(MemoryChunk* chunk,
+ InvalidatedSlots* invalidated_slots);
+
+ inline void Free(Address free_start, Address free_end);
+
+ private:
+ InvalidatedSlots::iterator iterator_;
+ InvalidatedSlots::iterator iterator_end_;
+ InvalidatedSlots* invalidated_slots_;
+ InvalidatedSlots empty_;
+
+ Address sentinel_;
+ Address invalidated_start_;
+ Address invalidated_end_;
+
+ inline void NextInvalidatedObject();
+#ifdef DEBUG
+ Address last_free_;
+#endif
+};
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/heap/local-allocator-inl.h b/deps/v8/src/heap/local-allocator-inl.h
index 71dcd98778..10d6ce7370 100644
--- a/deps/v8/src/heap/local-allocator-inl.h
+++ b/deps/v8/src/heap/local-allocator-inl.h
@@ -14,16 +14,17 @@ namespace internal {
AllocationResult LocalAllocator::Allocate(AllocationSpace space,
int object_size,
+ AllocationOrigin origin,
AllocationAlignment alignment) {
switch (space) {
case NEW_SPACE:
- return AllocateInNewSpace(object_size, alignment);
+ return AllocateInNewSpace(object_size, origin, alignment);
case OLD_SPACE:
return compaction_spaces_.Get(OLD_SPACE)->AllocateRaw(object_size,
- alignment);
+ alignment, origin);
case CODE_SPACE:
return compaction_spaces_.Get(CODE_SPACE)
- ->AllocateRaw(object_size, alignment);
+ ->AllocateRaw(object_size, alignment, origin);
default:
UNREACHABLE();
}
@@ -94,9 +95,9 @@ bool LocalAllocator::NewLocalAllocationBuffer() {
}
AllocationResult LocalAllocator::AllocateInNewSpace(
- int object_size, AllocationAlignment alignment) {
+ int object_size, AllocationOrigin origin, AllocationAlignment alignment) {
if (object_size > kMaxLabObjectSize) {
- return new_space_->AllocateRawSynchronized(object_size, alignment);
+ return new_space_->AllocateRawSynchronized(object_size, alignment, origin);
}
return AllocateInLAB(object_size, alignment);
}
diff --git a/deps/v8/src/heap/local-allocator.h b/deps/v8/src/heap/local-allocator.h
index 7019a79f21..56da76a18d 100644
--- a/deps/v8/src/heap/local-allocator.h
+++ b/deps/v8/src/heap/local-allocator.h
@@ -42,12 +42,14 @@ class LocalAllocator {
}
inline AllocationResult Allocate(AllocationSpace space, int object_size,
+ AllocationOrigin origin,
AllocationAlignment alignment);
inline void FreeLast(AllocationSpace space, HeapObject object,
int object_size);
private:
inline AllocationResult AllocateInNewSpace(int object_size,
+ AllocationOrigin origin,
AllocationAlignment alignment);
inline bool NewLocalAllocationBuffer();
inline AllocationResult AllocateInLAB(int object_size,
diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc
index 3cd6620083..e763d02e9f 100644
--- a/deps/v8/src/heap/mark-compact.cc
+++ b/deps/v8/src/heap/mark-compact.cc
@@ -577,6 +577,7 @@ void MarkCompactCollector::EnsureSweepingCompleted() {
heap()->old_space()->RefillFreeList();
heap()->code_space()->RefillFreeList();
heap()->map_space()->RefillFreeList();
+ heap()->map_space()->SortFreeList();
heap()->tracer()->NotifySweepingCompleted();
@@ -1291,8 +1292,8 @@ class EvacuateVisitorBase : public HeapObjectVisitor {
if (AbortCompactionForTesting(object)) return false;
#endif // VERIFY_HEAP
AllocationAlignment alignment = HeapObject::RequiredAlignment(object.map());
- AllocationResult allocation =
- local_allocator_->Allocate(target_space, size, alignment);
+ AllocationResult allocation = local_allocator_->Allocate(
+ target_space, size, AllocationOrigin::kGC, alignment);
if (allocation.To(target_object)) {
MigrateObject(*target_object, object, size, target_space);
if (target_space == CODE_SPACE)
@@ -1398,8 +1399,8 @@ class EvacuateNewSpaceVisitor final : public EvacuateVisitorBase {
AllocationAlignment alignment =
HeapObject::RequiredAlignment(old_object.map());
AllocationSpace space_allocated_in = NEW_SPACE;
- AllocationResult allocation =
- local_allocator_->Allocate(NEW_SPACE, size, alignment);
+ AllocationResult allocation = local_allocator_->Allocate(
+ NEW_SPACE, size, AllocationOrigin::kGC, alignment);
if (allocation.IsRetry()) {
allocation = AllocateInOldSpace(size, alignment);
space_allocated_in = OLD_SPACE;
@@ -1412,8 +1413,8 @@ class EvacuateNewSpaceVisitor final : public EvacuateVisitorBase {
inline AllocationResult AllocateInOldSpace(int size_in_bytes,
AllocationAlignment alignment) {
- AllocationResult allocation =
- local_allocator_->Allocate(OLD_SPACE, size_in_bytes, alignment);
+ AllocationResult allocation = local_allocator_->Allocate(
+ OLD_SPACE, size_in_bytes, AllocationOrigin::kGC, alignment);
if (allocation.IsRetry()) {
heap_->FatalProcessOutOfMemory(
"MarkCompactCollector: semi-space copy, fallback in old gen");
@@ -2688,7 +2689,8 @@ void MarkCompactCollector::EvacuateEpilogue() {
for (Page* p : *heap()->old_space()) {
DCHECK_NULL((p->slot_set<OLD_TO_OLD, AccessMode::ATOMIC>()));
DCHECK_NULL((p->typed_slot_set<OLD_TO_OLD, AccessMode::ATOMIC>()));
- DCHECK_NULL(p->invalidated_slots());
+ DCHECK_NULL(p->invalidated_slots<OLD_TO_OLD>());
+ DCHECK_NULL(p->invalidated_slots<OLD_TO_NEW>());
}
#endif
}
@@ -3416,9 +3418,23 @@ class RememberedSetUpdatingItem : public UpdatingItem {
},
SlotSet::PREFREE_EMPTY_BUCKETS);
}
+
+ if (chunk_->invalidated_slots<OLD_TO_NEW>() != nullptr) {
+#ifdef DEBUG
+ for (auto object_size : *chunk_->invalidated_slots<OLD_TO_NEW>()) {
+ HeapObject object = object_size.first;
+ int size = object_size.second;
+ DCHECK_LE(object.SizeFromMap(object.map()), size);
+ }
+#endif
+ // The invalidated slots are not needed after old-to-new slots were
+ // processed.
+ chunk_->ReleaseInvalidatedSlots<OLD_TO_NEW>();
+ }
+
if ((updating_mode_ == RememberedSetUpdatingMode::ALL) &&
(chunk_->slot_set<OLD_TO_OLD, AccessMode::NON_ATOMIC>() != nullptr)) {
- InvalidatedSlotsFilter filter(chunk_);
+ InvalidatedSlotsFilter filter = InvalidatedSlotsFilter::OldToOld(chunk_);
RememberedSet<OLD_TO_OLD>::Iterate(
chunk_,
[&filter](MaybeObjectSlot slot) {
@@ -3428,9 +3444,9 @@ class RememberedSetUpdatingItem : public UpdatingItem {
SlotSet::PREFREE_EMPTY_BUCKETS);
}
if ((updating_mode_ == RememberedSetUpdatingMode::ALL) &&
- chunk_->invalidated_slots() != nullptr) {
+ chunk_->invalidated_slots<OLD_TO_OLD>() != nullptr) {
#ifdef DEBUG
- for (auto object_size : *chunk_->invalidated_slots()) {
+ for (auto object_size : *chunk_->invalidated_slots<OLD_TO_OLD>()) {
HeapObject object = object_size.first;
int size = object_size.second;
DCHECK_LE(object.SizeFromMap(object.map()), size);
@@ -3438,7 +3454,7 @@ class RememberedSetUpdatingItem : public UpdatingItem {
#endif
// The invalidated slots are not needed after old-to-old slots were
// processsed.
- chunk_->ReleaseInvalidatedSlots();
+ chunk_->ReleaseInvalidatedSlots<OLD_TO_OLD>();
}
}
@@ -3552,13 +3568,17 @@ int MarkCompactCollectorBase::CollectRememberedSetUpdatingItems(
const bool contains_old_to_new_slots =
chunk->slot_set<OLD_TO_NEW>() != nullptr ||
chunk->typed_slot_set<OLD_TO_NEW>() != nullptr;
- const bool contains_invalidated_slots =
- chunk->invalidated_slots() != nullptr;
+ const bool contains_old_to_old_invalidated_slots =
+ chunk->invalidated_slots<OLD_TO_OLD>() != nullptr;
+ const bool contains_old_to_new_invalidated_slots =
+ chunk->invalidated_slots<OLD_TO_NEW>() != nullptr;
if (!contains_old_to_new_slots && !contains_old_to_old_slots &&
- !contains_invalidated_slots)
+ !contains_old_to_old_invalidated_slots &&
+ !contains_old_to_new_invalidated_slots)
continue;
if (mode == RememberedSetUpdatingMode::ALL || contains_old_to_new_slots ||
- contains_invalidated_slots) {
+ contains_old_to_old_invalidated_slots ||
+ contains_old_to_new_invalidated_slots) {
job->AddItem(CreateRememberedSetUpdatingItem(chunk, mode));
pages++;
}
@@ -4635,11 +4655,14 @@ class PageMarkingItem : public MarkingItem {
inline Heap* heap() { return chunk_->heap(); }
void MarkUntypedPointers(YoungGenerationMarkingTask* task) {
- RememberedSet<OLD_TO_NEW>::Iterate(chunk_,
- [this, task](MaybeObjectSlot slot) {
- return CheckAndMarkObject(task, slot);
- },
- SlotSet::PREFREE_EMPTY_BUCKETS);
+ InvalidatedSlotsFilter filter = InvalidatedSlotsFilter::OldToNew(chunk_);
+ RememberedSet<OLD_TO_NEW>::Iterate(
+ chunk_,
+ [this, task, &filter](MaybeObjectSlot slot) {
+ if (!filter.IsValid(slot.address())) return REMOVE_SLOT;
+ return CheckAndMarkObject(task, slot);
+ },
+ SlotSet::PREFREE_EMPTY_BUCKETS);
}
void MarkTypedPointers(YoungGenerationMarkingTask* task) {
diff --git a/deps/v8/src/heap/object-stats.cc b/deps/v8/src/heap/object-stats.cc
index 2a63896242..2ee88361c9 100644
--- a/deps/v8/src/heap/object-stats.cc
+++ b/deps/v8/src/heap/object-stats.cc
@@ -35,11 +35,16 @@ class FieldStatsCollector : public ObjectVisitor {
public:
FieldStatsCollector(size_t* tagged_fields_count,
size_t* embedder_fields_count,
+ size_t* inobject_smi_fields_count,
size_t* unboxed_double_fields_count,
- size_t* raw_fields_count)
+ size_t* boxed_double_fields_count,
+ size_t* string_data_count, size_t* raw_fields_count)
: tagged_fields_count_(tagged_fields_count),
embedder_fields_count_(embedder_fields_count),
+ inobject_smi_fields_count_(inobject_smi_fields_count),
unboxed_double_fields_count_(unboxed_double_fields_count),
+ boxed_double_fields_count_(boxed_double_fields_count),
+ string_data_count_(string_data_count),
raw_fields_count_(raw_fields_count) {}
void RecordStats(HeapObject host) {
@@ -62,11 +67,32 @@ class FieldStatsCollector : public ObjectVisitor {
*tagged_fields_count_ -= field_stats.embedded_fields_count_;
*embedder_fields_count_ += field_stats.embedded_fields_count_;
+ // Smi fields are also included into pointer words.
+ DCHECK_LE(
+ field_stats.unboxed_double_fields_count_ * kDoubleSize / kTaggedSize,
+ raw_fields_count_in_object);
+ tagged_fields_count_in_object -= field_stats.smi_fields_count_;
+ *tagged_fields_count_ -= field_stats.smi_fields_count_;
+ *inobject_smi_fields_count_ += field_stats.smi_fields_count_;
+
// The rest are data words.
- DCHECK_LE(field_stats.unboxed_double_fields_count_,
- raw_fields_count_in_object);
- raw_fields_count_in_object -= field_stats.unboxed_double_fields_count_;
+ DCHECK_LE(
+ field_stats.unboxed_double_fields_count_ * kDoubleSize / kTaggedSize,
+ raw_fields_count_in_object);
+ raw_fields_count_in_object -=
+ field_stats.unboxed_double_fields_count_ * kDoubleSize / kTaggedSize;
*unboxed_double_fields_count_ += field_stats.unboxed_double_fields_count_;
+ } else if (host.IsHeapNumber()) {
+ DCHECK_LE(kDoubleSize / kTaggedSize, raw_fields_count_in_object);
+ raw_fields_count_in_object -= kDoubleSize / kTaggedSize;
+ *boxed_double_fields_count_ += 1;
+ } else if (host.IsSeqString()) {
+ int string_data = SeqString::cast(host).synchronized_length() *
+ (String::cast(host).IsOneByteRepresentation() ? 1 : 2) /
+ kTaggedSize;
+ DCHECK_LE(string_data, raw_fields_count_in_object);
+ raw_fields_count_in_object -= string_data;
+ *string_data_count_ += string_data;
}
*raw_fields_count_ += raw_fields_count_in_object;
}
@@ -92,9 +118,12 @@ class FieldStatsCollector : public ObjectVisitor {
private:
struct JSObjectFieldStats {
JSObjectFieldStats()
- : embedded_fields_count_(0), unboxed_double_fields_count_(0) {}
+ : embedded_fields_count_(0),
+ smi_fields_count_(0),
+ unboxed_double_fields_count_(0) {}
unsigned embedded_fields_count_ : kDescriptorIndexBitCount;
+ unsigned smi_fields_count_ : kDescriptorIndexBitCount;
unsigned unboxed_double_fields_count_ : kDescriptorIndexBitCount;
};
std::unordered_map<Map, JSObjectFieldStats, Object::Hasher>
@@ -104,7 +133,10 @@ class FieldStatsCollector : public ObjectVisitor {
size_t* const tagged_fields_count_;
size_t* const embedder_fields_count_;
+ size_t* const inobject_smi_fields_count_;
size_t* const unboxed_double_fields_count_;
+ size_t* const boxed_double_fields_count_;
+ size_t* const string_data_count_;
size_t* const raw_fields_count_;
};
@@ -130,6 +162,9 @@ FieldStatsCollector::GetInobjectFieldStats(Map map) {
map.IsUnboxedDoubleField(index)) {
++stats.unboxed_double_fields_count_;
}
+ if (details.representation().IsSmi()) {
+ ++stats.smi_fields_count_;
+ }
}
}
}
@@ -149,7 +184,10 @@ void ObjectStats::ClearObjectStats(bool clear_last_time_stats) {
}
tagged_fields_count_ = 0;
embedder_fields_count_ = 0;
+ inobject_smi_fields_count_ = 0;
unboxed_double_fields_count_ = 0;
+ boxed_double_fields_count_ = 0;
+ string_data_count_ = 0;
raw_fields_count_ = 0;
}
@@ -208,8 +246,13 @@ void ObjectStats::PrintJSON(const char* key) {
PrintF(", \"tagged_fields\": %zu", tagged_fields_count_ * kTaggedSize);
PrintF(", \"embedder_fields\": %zu",
embedder_fields_count_ * kEmbedderDataSlotSize);
+ PrintF(", \"inobject_smi_fields\": %zu",
+ inobject_smi_fields_count_ * kTaggedSize);
PrintF(", \"unboxed_double_fields\": %zu",
unboxed_double_fields_count_ * kDoubleSize);
+ PrintF(", \"boxed_double_fields\": %zu",
+ boxed_double_fields_count_ * kDoubleSize);
+ PrintF(", \"string_data\": %zu", string_data_count_ * kTaggedSize);
PrintF(", \"other_raw_fields\": %zu", raw_fields_count_ * kSystemPointerSize);
PrintF(" }\n");
// bucket_sizes
@@ -263,8 +306,13 @@ void ObjectStats::Dump(std::stringstream& stream) {
stream << "\"tagged_fields\":" << (tagged_fields_count_ * kTaggedSize);
stream << ",\"embedder_fields\":"
<< (embedder_fields_count_ * kEmbedderDataSlotSize);
+ stream << ",\"inobject_smi_fields\": "
+ << (inobject_smi_fields_count_ * kTaggedSize);
stream << ",\"unboxed_double_fields\": "
<< (unboxed_double_fields_count_ * kDoubleSize);
+ stream << ",\"boxed_double_fields\": "
+ << (boxed_double_fields_count_ * kDoubleSize);
+ stream << ",\"string_data\": " << (string_data_count_ * kTaggedSize);
stream << ",\"other_raw_fields\":"
<< (raw_fields_count_ * kSystemPointerSize);
stream << "}, ";
@@ -427,7 +475,10 @@ ObjectStatsCollectorImpl::ObjectStatsCollectorImpl(Heap* heap,
heap->mark_compact_collector()->non_atomic_marking_state()),
field_stats_collector_(
&stats->tagged_fields_count_, &stats->embedder_fields_count_,
- &stats->unboxed_double_fields_count_, &stats->raw_fields_count_) {}
+ &stats->inobject_smi_fields_count_,
+ &stats->unboxed_double_fields_count_,
+ &stats->boxed_double_fields_count_, &stats->string_data_count_,
+ &stats->raw_fields_count_) {}
bool ObjectStatsCollectorImpl::ShouldRecordObject(HeapObject obj,
CowMode check_cow_array) {
diff --git a/deps/v8/src/heap/object-stats.h b/deps/v8/src/heap/object-stats.h
index 0bd2a1e3e4..2a9b9675ef 100644
--- a/deps/v8/src/heap/object-stats.h
+++ b/deps/v8/src/heap/object-stats.h
@@ -167,7 +167,10 @@ class ObjectStats {
size_t tagged_fields_count_;
size_t embedder_fields_count_;
+ size_t inobject_smi_fields_count_;
size_t unboxed_double_fields_count_;
+ size_t boxed_double_fields_count_;
+ size_t string_data_count_;
size_t raw_fields_count_;
friend class ObjectStatsCollectorImpl;
diff --git a/deps/v8/src/heap/remembered-set.h b/deps/v8/src/heap/remembered-set.h
index ea7fe0149b..eefc565e00 100644
--- a/deps/v8/src/heap/remembered-set.h
+++ b/deps/v8/src/heap/remembered-set.h
@@ -122,7 +122,7 @@ class RememberedSet : public AllStatic {
SlotSet* slots = chunk->slot_set<type>();
TypedSlotSet* typed_slots = chunk->typed_slot_set<type>();
if (slots != nullptr || typed_slots != nullptr ||
- chunk->invalidated_slots() != nullptr) {
+ chunk->invalidated_slots<type>() != nullptr) {
callback(chunk);
}
}
@@ -256,7 +256,7 @@ class RememberedSet : public AllStatic {
while ((chunk = it.next()) != nullptr) {
chunk->ReleaseSlotSet<OLD_TO_OLD>();
chunk->ReleaseTypedSlotSet<OLD_TO_OLD>();
- chunk->ReleaseInvalidatedSlots();
+ chunk->ReleaseInvalidatedSlots<OLD_TO_OLD>();
}
}
diff --git a/deps/v8/src/heap/scavenger-inl.h b/deps/v8/src/heap/scavenger-inl.h
index 9c605f7089..7729807a8a 100644
--- a/deps/v8/src/heap/scavenger-inl.h
+++ b/deps/v8/src/heap/scavenger-inl.h
@@ -135,8 +135,8 @@ CopyAndForwardResult Scavenger::SemiSpaceCopyObject(
"Only FullHeapObjectSlot and HeapObjectSlot are expected here");
DCHECK(heap()->AllowedToBeMigrated(map, object, NEW_SPACE));
AllocationAlignment alignment = HeapObject::RequiredAlignment(map);
- AllocationResult allocation =
- allocator_.Allocate(NEW_SPACE, object_size, alignment);
+ AllocationResult allocation = allocator_.Allocate(
+ NEW_SPACE, object_size, AllocationOrigin::kGC, alignment);
HeapObject target;
if (allocation.To(&target)) {
@@ -171,8 +171,8 @@ CopyAndForwardResult Scavenger::PromoteObject(Map map, THeapObjectSlot slot,
std::is_same<THeapObjectSlot, HeapObjectSlot>::value,
"Only FullHeapObjectSlot and HeapObjectSlot are expected here");
AllocationAlignment alignment = HeapObject::RequiredAlignment(map);
- AllocationResult allocation =
- allocator_.Allocate(OLD_SPACE, object_size, alignment);
+ AllocationResult allocation = allocator_.Allocate(
+ OLD_SPACE, object_size, AllocationOrigin::kGC, alignment);
HeapObject target;
if (allocation.To(&target)) {
diff --git a/deps/v8/src/heap/scavenger.cc b/deps/v8/src/heap/scavenger.cc
index 70b514142f..e08717ac27 100644
--- a/deps/v8/src/heap/scavenger.cc
+++ b/deps/v8/src/heap/scavenger.cc
@@ -8,6 +8,7 @@
#include "src/heap/barrier.h"
#include "src/heap/gc-tracer.h"
#include "src/heap/heap-inl.h"
+#include "src/heap/invalidated-slots-inl.h"
#include "src/heap/item-parallel-job.h"
#include "src/heap/mark-compact-inl.h"
#include "src/heap/objects-visiting-inl.h"
@@ -371,7 +372,7 @@ void ScavengerCollector::MergeSurvivingNewLargeObjects(
int ScavengerCollector::NumberOfScavengeTasks() {
if (!FLAG_parallel_scavenge) return 1;
const int num_scavenge_tasks =
- static_cast<int>(heap_->new_space()->TotalCapacity()) / MB;
+ static_cast<int>(heap_->new_space()->TotalCapacity()) / MB + 1;
static int num_cores = V8::GetCurrentPlatform()->NumberOfWorkerThreads() + 1;
int tasks =
Max(1, Min(Min(num_scavenge_tasks, kMaxScavengerTasks), num_cores));
@@ -431,12 +432,26 @@ void Scavenger::AddPageToSweeperIfNecessary(MemoryChunk* page) {
void Scavenger::ScavengePage(MemoryChunk* page) {
CodePageMemoryModificationScope memory_modification_scope(page);
- RememberedSet<OLD_TO_NEW>::Iterate(page,
- [this](MaybeObjectSlot addr) {
- return CheckAndScavengeObject(heap_,
- addr);
- },
- SlotSet::KEEP_EMPTY_BUCKETS);
+ RememberedSet<OLD_TO_NEW>::Iterate(
+ page,
+ [this](MaybeObjectSlot addr) {
+ return CheckAndScavengeObject(heap_, addr);
+ },
+ SlotSet::KEEP_EMPTY_BUCKETS);
+
+ if (page->invalidated_slots<OLD_TO_NEW>() != nullptr) {
+#ifdef DEBUG
+ for (auto object_size : *page->invalidated_slots<OLD_TO_NEW>()) {
+ HeapObject object = object_size.first;
+ int size = object_size.second;
+ DCHECK_LE(object.SizeFromMap(object.map()), size);
+ }
+#endif
+ // The invalidated slots are not needed after old-to-new slots were
+ // processed.
+ page->ReleaseInvalidatedSlots<OLD_TO_NEW>();
+ }
+
RememberedSet<OLD_TO_NEW>::IterateTyped(
page, [=](SlotType type, Address addr) {
return UpdateTypedSlotHelper::UpdateTypedSlot(
diff --git a/deps/v8/src/heap/setup-heap-internal.cc b/deps/v8/src/heap/setup-heap-internal.cc
index a936521a7e..15ca6d7930 100644
--- a/deps/v8/src/heap/setup-heap-internal.cc
+++ b/deps/v8/src/heap/setup-heap-internal.cc
@@ -358,8 +358,6 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_VARSIZE_MAP(FEEDBACK_VECTOR_TYPE, feedback_vector)
ALLOCATE_PRIMITIVE_MAP(HEAP_NUMBER_TYPE, HeapNumber::kSize, heap_number,
Context::NUMBER_FUNCTION_INDEX)
- ALLOCATE_MAP(MUTABLE_HEAP_NUMBER_TYPE, MutableHeapNumber::kSize,
- mutable_heap_number)
ALLOCATE_PRIMITIVE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol,
Context::SYMBOL_FUNCTION_INDEX)
ALLOCATE_MAP(FOREIGN_TYPE, Foreign::kSize, foreign)
@@ -463,6 +461,7 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_VARSIZE_MAP(AWAIT_CONTEXT_TYPE, await_context)
ALLOCATE_VARSIZE_MAP(BLOCK_CONTEXT_TYPE, block_context)
ALLOCATE_VARSIZE_MAP(MODULE_CONTEXT_TYPE, module_context)
+ ALLOCATE_VARSIZE_MAP(NATIVE_CONTEXT_TYPE, native_context)
ALLOCATE_VARSIZE_MAP(EVAL_CONTEXT_TYPE, eval_context)
ALLOCATE_VARSIZE_MAP(SCRIPT_CONTEXT_TYPE, script_context)
ALLOCATE_VARSIZE_MAP(SCRIPT_CONTEXT_TABLE_TYPE, script_context_table)
@@ -470,8 +469,6 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_VARSIZE_MAP(OBJECT_BOILERPLATE_DESCRIPTION_TYPE,
object_boilerplate_description)
- ALLOCATE_MAP(NATIVE_CONTEXT_TYPE, NativeContext::kSize, native_context)
-
ALLOCATE_MAP(CALL_HANDLER_INFO_TYPE, CallHandlerInfo::kSize,
side_effect_call_handler_info)
ALLOCATE_MAP(CALL_HANDLER_INFO_TYPE, CallHandlerInfo::kSize,
@@ -825,6 +822,15 @@ void Heap::CreateInitialObjects() {
factory->NewFeedbackMetadata(0, 0, AllocationType::kReadOnly);
set_empty_feedback_metadata(*empty_feedback_metadata);
+ // Canonical scope arrays.
+ Handle<ScopeInfo> global_this_binding =
+ ScopeInfo::CreateGlobalThisBinding(isolate());
+ set_global_this_binding_scope_info(*global_this_binding);
+
+ Handle<ScopeInfo> empty_function =
+ ScopeInfo::CreateForEmptyFunction(isolate());
+ set_empty_function_scope_info(*empty_function);
+
// Allocate the empty script.
Handle<Script> script = factory->NewScript(factory->empty_string());
script->set_type(Script::TYPE_NATIVE);
diff --git a/deps/v8/src/heap/slot-set.h b/deps/v8/src/heap/slot-set.h
index f7efc64247..c71192bfdc 100644
--- a/deps/v8/src/heap/slot-set.h
+++ b/deps/v8/src/heap/slot-set.h
@@ -52,9 +52,6 @@ class SlotSet : public Malloced {
void SetPageStart(Address page_start) { page_start_ = page_start; }
// The slot offset specifies a slot at address page_start_ + slot_offset.
- // This method should only be called on the main thread because concurrent
- // allocation of the bucket is not thread-safe.
- //
// AccessMode defines whether there can be concurrent access on the buckets
// or not.
template <AccessMode access_mode = AccessMode::ATOMIC>
@@ -181,7 +178,10 @@ class SlotSet : public Malloced {
// Iterate over all slots in the set and for each slot invoke the callback.
// If the callback returns REMOVE_SLOT then the slot is removed from the set.
// Returns the new number of slots.
- // This method should only be called on the main thread.
+ //
+ // Iteration can be performed concurrently with other operations that use
+ // atomic access mode such as insertion and removal. However there is no
+ // guarantee about ordering and linearizability.
//
// Sample usage:
// Iterate([](MaybeObjectSlot slot) {
@@ -411,8 +411,8 @@ class V8_EXPORT_PRIVATE TypedSlots {
void Merge(TypedSlots* other);
protected:
- class OffsetField : public BitField<int, 0, 29> {};
- class TypeField : public BitField<SlotType, 29, 3> {};
+ using OffsetField = BitField<int, 0, 29>;
+ using TypeField = BitField<SlotType, 29, 3>;
struct TypedSlot {
uint32_t type_and_offset;
};
diff --git a/deps/v8/src/heap/spaces-inl.h b/deps/v8/src/heap/spaces-inl.h
index 3b4ed8d30a..2feb47bec1 100644
--- a/deps/v8/src/heap/spaces-inl.h
+++ b/deps/v8/src/heap/spaces-inl.h
@@ -172,8 +172,6 @@ bool PagedSpace::Contains(Object o) {
void PagedSpace::UnlinkFreeListCategories(Page* page) {
DCHECK_EQ(this, page->owner());
page->ForAllFreeListCategories([this](FreeListCategory* category) {
- DCHECK_EQ(free_list(), category->owner());
- category->set_free_list(nullptr);
free_list()->RemoveCategory(category);
});
}
@@ -182,9 +180,8 @@ size_t PagedSpace::RelinkFreeListCategories(Page* page) {
DCHECK_EQ(this, page->owner());
size_t added = 0;
page->ForAllFreeListCategories([this, &added](FreeListCategory* category) {
- category->set_free_list(free_list());
added += category->available();
- category->Relink();
+ category->Relink(free_list());
});
DCHECK_IMPLIES(!page->IsFlagSet(Page::NEVER_ALLOCATE_ON_PAGE),
@@ -315,10 +312,51 @@ MemoryChunk* OldGenerationMemoryChunkIterator::next() {
UNREACHABLE();
}
-FreeList* FreeListCategory::owner() { return free_list_; }
+bool FreeListCategory::is_linked(FreeList* owner) const {
+ return prev_ != nullptr || next_ != nullptr ||
+ owner->categories_[type_] == this;
+}
+
+void FreeListCategory::UpdateCountersAfterAllocation(size_t allocation_size) {
+ available_ -= allocation_size;
+}
+
+Page* FreeList::GetPageForCategoryType(FreeListCategoryType type) {
+ FreeListCategory* category_top = top(type);
+ if (category_top != nullptr) {
+ DCHECK(!category_top->top().is_null());
+ return Page::FromHeapObject(category_top->top());
+ } else {
+ return nullptr;
+ }
+}
-bool FreeListCategory::is_linked() {
- return prev_ != nullptr || next_ != nullptr;
+Page* FreeListLegacy::GetPageForSize(size_t size_in_bytes) {
+ const int minimum_category =
+ static_cast<int>(SelectFreeListCategoryType(size_in_bytes));
+ Page* page = GetPageForCategoryType(kHuge);
+ if (!page && static_cast<int>(kLarge) >= minimum_category)
+ page = GetPageForCategoryType(kLarge);
+ if (!page && static_cast<int>(kMedium) >= minimum_category)
+ page = GetPageForCategoryType(kMedium);
+ if (!page && static_cast<int>(kSmall) >= minimum_category)
+ page = GetPageForCategoryType(kSmall);
+ if (!page && static_cast<int>(kTiny) >= minimum_category)
+ page = GetPageForCategoryType(kTiny);
+ if (!page && static_cast<int>(kTiniest) >= minimum_category)
+ page = GetPageForCategoryType(kTiniest);
+ return page;
+}
+
+Page* FreeListFastAlloc::GetPageForSize(size_t size_in_bytes) {
+ const int minimum_category =
+ static_cast<int>(SelectFreeListCategoryType(size_in_bytes));
+ Page* page = GetPageForCategoryType(kHuge);
+ if (!page && static_cast<int>(kLarge) >= minimum_category)
+ page = GetPageForCategoryType(kLarge);
+ if (!page && static_cast<int>(kMedium) >= minimum_category)
+ page = GetPageForCategoryType(kMedium);
+ return page;
}
AllocationResult LocalAllocationBuffer::AllocateRawAligned(
@@ -338,11 +376,12 @@ AllocationResult LocalAllocationBuffer::AllocateRawAligned(
return AllocationResult(HeapObject::FromAddress(current_top));
}
-bool PagedSpace::EnsureLinearAllocationArea(int size_in_bytes) {
+bool PagedSpace::EnsureLinearAllocationArea(int size_in_bytes,
+ AllocationOrigin origin) {
if (allocation_info_.top() + size_in_bytes <= allocation_info_.limit()) {
return true;
}
- return SlowRefillLinearAllocationArea(size_in_bytes);
+ return SlowRefillLinearAllocationArea(size_in_bytes, origin);
}
HeapObject PagedSpace::AllocateLinearly(int size_in_bytes) {
@@ -371,19 +410,26 @@ HeapObject PagedSpace::TryAllocateLinearlyAligned(
return HeapObject::FromAddress(current_top);
}
-AllocationResult PagedSpace::AllocateRawUnaligned(int size_in_bytes) {
+AllocationResult PagedSpace::AllocateRawUnaligned(int size_in_bytes,
+ AllocationOrigin origin) {
DCHECK_IMPLIES(identity() == RO_SPACE, !IsDetached());
- if (!EnsureLinearAllocationArea(size_in_bytes)) {
+ if (!EnsureLinearAllocationArea(size_in_bytes, origin)) {
return AllocationResult::Retry(identity());
}
HeapObject object = AllocateLinearly(size_in_bytes);
DCHECK(!object.is_null());
MSAN_ALLOCATED_UNINITIALIZED_MEMORY(object.address(), size_in_bytes);
+
+ if (FLAG_trace_allocations_origins) {
+ UpdateAllocationOrigins(origin);
+ }
+
return object;
}
AllocationResult PagedSpace::AllocateRawAligned(int size_in_bytes,
- AllocationAlignment alignment) {
+ AllocationAlignment alignment,
+ AllocationOrigin origin) {
DCHECK(identity() == OLD_SPACE || identity() == RO_SPACE);
DCHECK_IMPLIES(identity() == RO_SPACE, !IsDetached());
int allocation_size = size_in_bytes;
@@ -393,7 +439,7 @@ AllocationResult PagedSpace::AllocateRawAligned(int size_in_bytes,
// allocated, so assume the worst case.
int filler_size = Heap::GetMaximumFillToAlign(alignment);
allocation_size += filler_size;
- if (!EnsureLinearAllocationArea(allocation_size)) {
+ if (!EnsureLinearAllocationArea(allocation_size, origin)) {
return AllocationResult::Retry(identity());
}
allocation_size = size_in_bytes;
@@ -401,12 +447,17 @@ AllocationResult PagedSpace::AllocateRawAligned(int size_in_bytes,
DCHECK(!object.is_null());
}
MSAN_ALLOCATED_UNINITIALIZED_MEMORY(object.address(), size_in_bytes);
+
+ if (FLAG_trace_allocations_origins) {
+ UpdateAllocationOrigins(origin);
+ }
+
return object;
}
-
AllocationResult PagedSpace::AllocateRaw(int size_in_bytes,
- AllocationAlignment alignment) {
+ AllocationAlignment alignment,
+ AllocationOrigin origin) {
if (top_on_previous_step_ && top() < top_on_previous_step_ &&
SupportsInlineAllocation()) {
// Generated code decreased the top() pointer to do folded allocations.
@@ -421,11 +472,12 @@ AllocationResult PagedSpace::AllocateRaw(int size_in_bytes,
DCHECK_IMPLIES(!SupportsInlineAllocation(), bytes_since_last == 0);
#ifdef V8_HOST_ARCH_32_BIT
- AllocationResult result = alignment != kWordAligned
- ? AllocateRawAligned(size_in_bytes, alignment)
- : AllocateRawUnaligned(size_in_bytes);
+ AllocationResult result =
+ alignment != kWordAligned
+ ? AllocateRawAligned(size_in_bytes, alignment, origin)
+ : AllocateRawUnaligned(size_in_bytes, origin);
#else
- AllocationResult result = AllocateRawUnaligned(size_in_bytes);
+ AllocationResult result = AllocateRawUnaligned(size_in_bytes, origin);
#endif
HeapObject heap_obj;
if (!result.IsRetry() && result.To(&heap_obj) && !is_local()) {
@@ -439,13 +491,12 @@ AllocationResult PagedSpace::AllocateRaw(int size_in_bytes,
return result;
}
-
// -----------------------------------------------------------------------------
// NewSpace
-
AllocationResult NewSpace::AllocateRawAligned(int size_in_bytes,
- AllocationAlignment alignment) {
+ AllocationAlignment alignment,
+ AllocationOrigin origin) {
Address top = allocation_info_.top();
int filler_size = Heap::GetFillToAlign(top, alignment);
int aligned_size_in_bytes = size_in_bytes + filler_size;
@@ -472,11 +523,15 @@ AllocationResult NewSpace::AllocateRawAligned(int size_in_bytes,
MSAN_ALLOCATED_UNINITIALIZED_MEMORY(obj.address(), size_in_bytes);
+ if (FLAG_trace_allocations_origins) {
+ UpdateAllocationOrigins(origin);
+ }
+
return obj;
}
-
-AllocationResult NewSpace::AllocateRawUnaligned(int size_in_bytes) {
+AllocationResult NewSpace::AllocateRawUnaligned(int size_in_bytes,
+ AllocationOrigin origin) {
Address top = allocation_info_.top();
if (allocation_info_.limit() < top + size_in_bytes) {
// See if we can create room.
@@ -493,12 +548,16 @@ AllocationResult NewSpace::AllocateRawUnaligned(int size_in_bytes) {
MSAN_ALLOCATED_UNINITIALIZED_MEMORY(obj.address(), size_in_bytes);
+ if (FLAG_trace_allocations_origins) {
+ UpdateAllocationOrigins(origin);
+ }
+
return obj;
}
-
AllocationResult NewSpace::AllocateRaw(int size_in_bytes,
- AllocationAlignment alignment) {
+ AllocationAlignment alignment,
+ AllocationOrigin origin) {
if (top() < top_on_previous_step_) {
// Generated code decreased the top() pointer to do folded allocations
DCHECK_EQ(Page::FromAllocationAreaAddress(top()),
@@ -507,8 +566,8 @@ AllocationResult NewSpace::AllocateRaw(int size_in_bytes,
}
#ifdef V8_HOST_ARCH_32_BIT
return alignment != kWordAligned
- ? AllocateRawAligned(size_in_bytes, alignment)
- : AllocateRawUnaligned(size_in_bytes);
+ ? AllocateRawAligned(size_in_bytes, alignment, origin)
+ : AllocateRawUnaligned(size_in_bytes, origin);
#else
#ifdef V8_COMPRESS_POINTERS
// TODO(ishell, v8:8875): Consider using aligned allocations once the
@@ -516,14 +575,14 @@ AllocationResult NewSpace::AllocateRaw(int size_in_bytes,
// unaligned access since both x64 and arm64 architectures (where pointer
// compression is supported) allow unaligned access to doubles and full words.
#endif // V8_COMPRESS_POINTERS
- return AllocateRawUnaligned(size_in_bytes);
+ return AllocateRawUnaligned(size_in_bytes, origin);
#endif
}
V8_WARN_UNUSED_RESULT inline AllocationResult NewSpace::AllocateRawSynchronized(
- int size_in_bytes, AllocationAlignment alignment) {
+ int size_in_bytes, AllocationAlignment alignment, AllocationOrigin origin) {
base::MutexGuard guard(&mutex_);
- return AllocateRaw(size_in_bytes, alignment);
+ return AllocateRaw(size_in_bytes, alignment, origin);
}
LocalAllocationBuffer LocalAllocationBuffer::FromResult(Heap* heap,
diff --git a/deps/v8/src/heap/spaces.cc b/deps/v8/src/heap/spaces.cc
index 438308a346..dd8ba30101 100644
--- a/deps/v8/src/heap/spaces.cc
+++ b/deps/v8/src/heap/spaces.cc
@@ -703,7 +703,8 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size,
nullptr);
base::AsAtomicPointer::Release_Store(&chunk->typed_slot_set_[OLD_TO_OLD],
nullptr);
- chunk->invalidated_slots_ = nullptr;
+ chunk->invalidated_slots_[OLD_TO_NEW] = nullptr;
+ chunk->invalidated_slots_[OLD_TO_OLD] = nullptr;
chunk->progress_bar_ = 0;
chunk->high_water_mark_ = static_cast<intptr_t>(area_start - base);
chunk->set_concurrent_sweeping_state(kSweepingDone);
@@ -821,8 +822,7 @@ void Page::AllocateFreeListCategories() {
categories_ = new FreeListCategory*[free_list()->number_of_categories()]();
for (int i = kFirstCategory; i <= free_list()->last_category(); i++) {
DCHECK_NULL(categories_[i]);
- categories_[i] = new FreeListCategory(
- reinterpret_cast<PagedSpace*>(owner())->free_list(), this);
+ categories_[i] = new FreeListCategory();
}
}
@@ -1379,7 +1379,8 @@ void MemoryChunk::ReleaseAllocatedMemoryNeededForWritableChunk() {
ReleaseSlotSet<OLD_TO_OLD>();
ReleaseTypedSlotSet<OLD_TO_NEW>();
ReleaseTypedSlotSet<OLD_TO_OLD>();
- ReleaseInvalidatedSlots();
+ ReleaseInvalidatedSlots<OLD_TO_NEW>();
+ ReleaseInvalidatedSlots<OLD_TO_OLD>();
if (local_tracker_ != nullptr) ReleaseLocalTracker();
if (young_generation_bitmap_ != nullptr) ReleaseYoungGenerationBitmap();
@@ -1461,53 +1462,107 @@ void MemoryChunk::ReleaseTypedSlotSet() {
}
}
+template InvalidatedSlots* MemoryChunk::AllocateInvalidatedSlots<OLD_TO_NEW>();
+template InvalidatedSlots* MemoryChunk::AllocateInvalidatedSlots<OLD_TO_OLD>();
+
+template <RememberedSetType type>
InvalidatedSlots* MemoryChunk::AllocateInvalidatedSlots() {
- DCHECK_NULL(invalidated_slots_);
- invalidated_slots_ = new InvalidatedSlots();
- return invalidated_slots_;
+ DCHECK_NULL(invalidated_slots_[type]);
+ invalidated_slots_[type] = new InvalidatedSlots();
+ return invalidated_slots_[type];
}
+template void MemoryChunk::ReleaseInvalidatedSlots<OLD_TO_NEW>();
+template void MemoryChunk::ReleaseInvalidatedSlots<OLD_TO_OLD>();
+
+template <RememberedSetType type>
void MemoryChunk::ReleaseInvalidatedSlots() {
- if (invalidated_slots_) {
- delete invalidated_slots_;
- invalidated_slots_ = nullptr;
+ if (invalidated_slots_[type]) {
+ delete invalidated_slots_[type];
+ invalidated_slots_[type] = nullptr;
}
}
+template V8_EXPORT_PRIVATE void
+MemoryChunk::RegisterObjectWithInvalidatedSlots<OLD_TO_NEW>(HeapObject object,
+ int size);
+template V8_EXPORT_PRIVATE void
+MemoryChunk::RegisterObjectWithInvalidatedSlots<OLD_TO_OLD>(HeapObject object,
+ int size);
+
+template <RememberedSetType type>
void MemoryChunk::RegisterObjectWithInvalidatedSlots(HeapObject object,
int size) {
- if (!ShouldSkipEvacuationSlotRecording()) {
- if (invalidated_slots() == nullptr) {
- AllocateInvalidatedSlots();
+ bool skip_slot_recording;
+
+ if (type == OLD_TO_NEW) {
+ skip_slot_recording = InYoungGeneration();
+ } else {
+ skip_slot_recording = ShouldSkipEvacuationSlotRecording();
+ }
+
+ if (skip_slot_recording) {
+ return;
+ }
+
+ if (invalidated_slots<type>() == nullptr) {
+ AllocateInvalidatedSlots<type>();
+ }
+
+ InvalidatedSlots* invalidated_slots = this->invalidated_slots<type>();
+ InvalidatedSlots::iterator it = invalidated_slots->lower_bound(object);
+
+ if (it != invalidated_slots->end() && it->first == object) {
+ // object was already inserted
+ CHECK_LE(size, it->second);
+ return;
+ }
+
+ it = invalidated_slots->insert(it, std::make_pair(object, size));
+
+ // prevent overlapping invalidated objects for old-to-new.
+ if (type == OLD_TO_NEW && it != invalidated_slots->begin()) {
+ HeapObject pred = (--it)->first;
+ int pred_size = it->second;
+ DCHECK_LT(pred.address(), object.address());
+
+ if (pred.address() + pred_size > object.address()) {
+ it->second = static_cast<int>(object.address() - pred.address());
}
- int old_size = (*invalidated_slots())[object];
- (*invalidated_slots())[object] = std::max(old_size, size);
}
}
+template bool MemoryChunk::RegisteredObjectWithInvalidatedSlots<OLD_TO_NEW>(
+ HeapObject object);
+template bool MemoryChunk::RegisteredObjectWithInvalidatedSlots<OLD_TO_OLD>(
+ HeapObject object);
+
+template <RememberedSetType type>
bool MemoryChunk::RegisteredObjectWithInvalidatedSlots(HeapObject object) {
- if (ShouldSkipEvacuationSlotRecording()) {
- // Invalidated slots do not matter if we are not recording slots.
- return true;
- }
- if (invalidated_slots() == nullptr) {
+ if (invalidated_slots<type>() == nullptr) {
return false;
}
- return invalidated_slots()->find(object) != invalidated_slots()->end();
+ return invalidated_slots<type>()->find(object) !=
+ invalidated_slots<type>()->end();
}
+template void MemoryChunk::MoveObjectWithInvalidatedSlots<OLD_TO_OLD>(
+ HeapObject old_start, HeapObject new_start);
+
+template <RememberedSetType type>
void MemoryChunk::MoveObjectWithInvalidatedSlots(HeapObject old_start,
HeapObject new_start) {
DCHECK_LT(old_start, new_start);
DCHECK_EQ(MemoryChunk::FromHeapObject(old_start),
MemoryChunk::FromHeapObject(new_start));
- if (!ShouldSkipEvacuationSlotRecording() && invalidated_slots()) {
- auto it = invalidated_slots()->find(old_start);
- if (it != invalidated_slots()->end()) {
+ static_assert(type == OLD_TO_OLD, "only use this for old-to-old slots");
+ if (!ShouldSkipEvacuationSlotRecording() && invalidated_slots<type>()) {
+ auto it = invalidated_slots<type>()->find(old_start);
+ if (it != invalidated_slots<type>()->end()) {
int old_size = it->second;
int delta = static_cast<int>(new_start.address() - old_start.address());
- invalidated_slots()->erase(it);
- (*invalidated_slots())[new_start] = old_size - delta;
+ invalidated_slots<type>()->erase(it);
+ (*invalidated_slots<type>())[new_start] = old_size - delta;
}
}
}
@@ -1532,10 +1587,6 @@ void MemoryChunk::ReleaseYoungGenerationBitmap() {
// -----------------------------------------------------------------------------
// PagedSpace implementation
-void Space::CheckOffsetsAreConsistent() const {
- DCHECK_EQ(Space::kIdOffset, OFFSET_OF(Space, id_));
-}
-
void Space::AddAllocationObserver(AllocationObserver* observer) {
allocation_observers_.push_back(observer);
StartNextInlineAllocationStep();
@@ -1612,8 +1663,9 @@ void PagedSpace::RefillFreeList() {
// We regularly sweep NEVER_ALLOCATE_ON_PAGE pages. We drop the freelist
// entries here to make them unavailable for allocations.
if (p->IsFlagSet(Page::NEVER_ALLOCATE_ON_PAGE)) {
- p->ForAllFreeListCategories(
- [](FreeListCategory* category) { category->Reset(); });
+ p->ForAllFreeListCategories([this](FreeListCategory* category) {
+ category->Reset(free_list());
+ });
}
// Only during compaction pages can actually change ownership. This is
// safe because there exists no other competing action on the page links
@@ -1645,6 +1697,11 @@ void PagedSpace::MergeCompactionSpace(CompactionSpace* other) {
// area_size_
other->FreeLinearAllocationArea();
+ for (int i = static_cast<int>(AllocationOrigin::kFirstAllocationOrigin);
+ i <= static_cast<int>(AllocationOrigin::kLastAllocationOrigin); i++) {
+ allocations_origins_[i] += other->allocations_origins_[i];
+ }
+
// The linear allocation area of {other} should be destroyed now.
DCHECK_EQ(kNullAddress, other->top());
DCHECK_EQ(kNullAddress, other->limit());
@@ -1846,6 +1903,20 @@ Address SpaceWithLinearArea::ComputeLimit(Address start, Address end,
}
}
+void SpaceWithLinearArea::UpdateAllocationOrigins(AllocationOrigin origin) {
+ DCHECK(!((origin != AllocationOrigin::kGC) &&
+ (heap()->isolate()->current_vm_state() == GC)));
+ allocations_origins_[static_cast<int>(origin)]++;
+}
+
+void SpaceWithLinearArea::PrintAllocationsOrigins() {
+ PrintIsolate(
+ heap()->isolate(),
+ "Allocations Origins for %s: GeneratedCode:%zu - Runtime:%zu - GC:%zu\n",
+ name(), allocations_origins_[0], allocations_origins_[1],
+ allocations_origins_[2]);
+}
+
void PagedSpace::MarkLinearAllocationAreaBlack() {
DCHECK(heap()->incremental_marking()->black_allocation());
Address current_top = top();
@@ -1911,7 +1982,6 @@ void PagedSpace::ReleasePage(Page* page) {
DCHECK_EQ(page->owner(), this);
free_list_->EvictFreeListItems(page);
- DCHECK(!free_list_->ContainsPageFreeListItems(page));
if (Page::FromAllocationAreaAddress(allocation_info_.top()) == page) {
DCHECK(!top_on_previous_step_);
@@ -1951,7 +2021,8 @@ std::unique_ptr<ObjectIterator> PagedSpace::GetObjectIterator() {
return std::unique_ptr<ObjectIterator>(new PagedSpaceObjectIterator(this));
}
-bool PagedSpace::RefillLinearAllocationAreaFromFreeList(size_t size_in_bytes) {
+bool PagedSpace::RefillLinearAllocationAreaFromFreeList(
+ size_t size_in_bytes, AllocationOrigin origin) {
DCHECK(IsAligned(size_in_bytes, kTaggedSize));
DCHECK_LE(top(), limit());
#ifdef DEBUG
@@ -1974,9 +2045,9 @@ bool PagedSpace::RefillLinearAllocationAreaFromFreeList(size_t size_in_bytes) {
}
size_t new_node_size = 0;
- FreeSpace new_node = free_list_->Allocate(size_in_bytes, &new_node_size);
+ FreeSpace new_node =
+ free_list_->Allocate(size_in_bytes, &new_node_size, origin);
if (new_node.is_null()) return false;
-
DCHECK_GE(new_node_size, size_in_bytes);
// The old-space-step might have finished sweeping and restarted marking.
@@ -2895,42 +2966,41 @@ size_t NewSpace::CommittedPhysicalMemory() {
// -----------------------------------------------------------------------------
// Free lists for old object spaces implementation
-
-void FreeListCategory::Reset() {
+void FreeListCategory::Reset(FreeList* owner) {
+ if (is_linked(owner) && !top().is_null()) {
+ owner->DecreaseAvailableBytes(available_);
+ }
set_top(FreeSpace());
set_prev(nullptr);
set_next(nullptr);
available_ = 0;
- length_ = 0;
}
FreeSpace FreeListCategory::PickNodeFromList(size_t minimum_size,
size_t* node_size) {
- DCHECK(page()->CanAllocate());
FreeSpace node = top();
DCHECK(!node.is_null());
+ DCHECK(Page::FromHeapObject(node)->CanAllocate());
if (static_cast<size_t>(node.Size()) < minimum_size) {
*node_size = 0;
return FreeSpace();
}
set_top(node.next());
*node_size = node.Size();
- available_ -= *node_size;
- length_--;
+ UpdateCountersAfterAllocation(*node_size);
return node;
}
FreeSpace FreeListCategory::SearchForNodeInList(size_t minimum_size,
size_t* node_size) {
- DCHECK(page()->CanAllocate());
FreeSpace prev_non_evac_node;
for (FreeSpace cur_node = top(); !cur_node.is_null();
cur_node = cur_node.next()) {
+ DCHECK(Page::FromHeapObject(cur_node)->CanAllocate());
size_t size = cur_node.size();
if (size >= minimum_size) {
DCHECK_GE(available_, size);
- available_ -= size;
- length_--;
+ UpdateCountersAfterAllocation(size);
if (cur_node == top()) {
set_top(cur_node.next());
}
@@ -2950,19 +3020,21 @@ FreeSpace FreeListCategory::SearchForNodeInList(size_t minimum_size,
return FreeSpace();
}
-void FreeListCategory::Free(Address start, size_t size_in_bytes,
- FreeMode mode) {
+void FreeListCategory::Free(Address start, size_t size_in_bytes, FreeMode mode,
+ FreeList* owner) {
FreeSpace free_space = FreeSpace::cast(HeapObject::FromAddress(start));
free_space.set_next(top());
set_top(free_space);
available_ += size_in_bytes;
- length_++;
- if ((mode == kLinkCategory) && (prev() == nullptr) && (next() == nullptr)) {
- owner()->AddCategory(this);
+ if (mode == kLinkCategory) {
+ if (is_linked(owner)) {
+ owner->IncreaseAvailableBytes(size_in_bytes);
+ } else {
+ owner->AddCategory(this);
+ }
}
}
-
void FreeListCategory::RepairFreeList(Heap* heap) {
Map free_space_map = ReadOnlyRoots(heap).free_space_map();
FreeSpace n = top();
@@ -2977,21 +3049,30 @@ void FreeListCategory::RepairFreeList(Heap* heap) {
}
}
-void FreeListCategory::Relink() {
- DCHECK(!is_linked());
- owner()->AddCategory(this);
+void FreeListCategory::Relink(FreeList* owner) {
+ DCHECK(!is_linked(owner));
+ owner->AddCategory(this);
}
// ------------------------------------------------
// Generic FreeList methods (alloc/free related)
FreeList* FreeList::CreateFreeList() {
- if (FLAG_gc_freelist_strategy == 1) {
- return new FreeListFastAlloc();
- } else if (FLAG_gc_freelist_strategy == 2) {
- return new FreeListMany();
- } else {
- return new FreeListLegacy();
+ switch (FLAG_gc_freelist_strategy) {
+ case 0:
+ return new FreeListLegacy();
+ case 1:
+ return new FreeListFastAlloc();
+ case 2:
+ return new FreeListMany();
+ case 3:
+ return new FreeListManyCached();
+ case 4:
+ return new FreeListManyCachedFastPath();
+ case 5:
+ return new FreeListManyCachedOrigin();
+ default:
+ FATAL("Invalid FreeList strategy");
}
}
@@ -3001,6 +3082,7 @@ FreeSpace FreeList::TryFindNodeIn(FreeListCategoryType type,
if (category == nullptr) return FreeSpace();
FreeSpace node = category->PickNodeFromList(minimum_size, node_size);
if (!node.is_null()) {
+ DecreaseAvailableBytes(*node_size);
DCHECK(IsVeryLong() || Available() == SumFreeLists());
}
if (category->is_empty()) {
@@ -3018,6 +3100,7 @@ FreeSpace FreeList::SearchForNodeInList(FreeListCategoryType type,
FreeListCategory* current = it.Next();
node = current->SearchForNodeInList(minimum_size, node_size);
if (!node.is_null()) {
+ DecreaseAvailableBytes(*node_size);
DCHECK(IsVeryLong() || Available() == SumFreeLists());
if (current->is_empty()) {
RemoveCategory(current);
@@ -3042,7 +3125,7 @@ size_t FreeList::Free(Address start, size_t size_in_bytes, FreeMode mode) {
// Insert other blocks at the head of a free list of the appropriate
// magnitude.
FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
- page->free_list_category(type)->Free(start, size_in_bytes, mode);
+ page->free_list_category(type)->Free(start, size_in_bytes, mode, this);
DCHECK_EQ(page->AvailableInFreeList(),
page->AvailableInFreeListFromAllocatedBytes());
return 0;
@@ -3063,7 +3146,8 @@ FreeListLegacy::FreeListLegacy() {
FreeListLegacy::~FreeListLegacy() { delete[] categories_; }
-FreeSpace FreeListLegacy::Allocate(size_t size_in_bytes, size_t* node_size) {
+FreeSpace FreeListLegacy::Allocate(size_t size_in_bytes, size_t* node_size,
+ AllocationOrigin origin) {
DCHECK_GE(kMaxBlockSize, size_in_bytes);
FreeSpace node;
// First try the allocation fast path: try to allocate the minimum element
@@ -3121,7 +3205,8 @@ FreeListFastAlloc::FreeListFastAlloc() {
FreeListFastAlloc::~FreeListFastAlloc() { delete[] categories_; }
-FreeSpace FreeListFastAlloc::Allocate(size_t size_in_bytes, size_t* node_size) {
+FreeSpace FreeListFastAlloc::Allocate(size_t size_in_bytes, size_t* node_size,
+ AllocationOrigin origin) {
DCHECK_GE(kMaxBlockSize, size_in_bytes);
FreeSpace node;
// Try to allocate the biggest element possible (to make the most of later
@@ -3143,16 +3228,7 @@ FreeSpace FreeListFastAlloc::Allocate(size_t size_in_bytes, size_t* node_size) {
// ------------------------------------------------
// FreeListMany implementation
-// Cf. the declaration of |categories_max| in |spaces.h| to see how this is
-// computed.
-const size_t FreeListMany::categories_max[kNumberOfCategories] = {
- 24, 32, 40, 48, 56, 64, 72,
- 80, 88, 96, 104, 112, 120, 128,
- 136, 144, 152, 160, 168, 176, 184,
- 192, 200, 208, 216, 224, 232, 240,
- 248, 256, 384, 512, 768, 1024, 1536,
- 2048, 3072, 4080, 4088, 4096, 6144, 8192,
- 12288, 16384, 24576, 32768, 49152, 65536, Page::kPageSize};
+constexpr unsigned int FreeListMany::categories_min[kNumberOfCategories];
FreeListMany::FreeListMany() {
// Initializing base (FreeList) fields
@@ -3164,31 +3240,36 @@ FreeListMany::FreeListMany() {
Reset();
}
+FreeListMany::~FreeListMany() { delete[] categories_; }
+
size_t FreeListMany::GuaranteedAllocatable(size_t maximum_freed) {
- if (maximum_freed < categories_max[0]) {
+ if (maximum_freed < categories_min[0]) {
return 0;
}
- for (int cat = kFirstCategory + 1; cat < last_category_; cat++) {
- if (maximum_freed <= categories_max[cat]) {
- return categories_max[cat - 1];
+ for (int cat = kFirstCategory + 1; cat <= last_category_; cat++) {
+ if (maximum_freed < categories_min[cat]) {
+ return categories_min[cat - 1];
}
}
return maximum_freed;
}
Page* FreeListMany::GetPageForSize(size_t size_in_bytes) {
- const int minimum_category =
- static_cast<int>(SelectFreeListCategoryType(size_in_bytes));
- Page* page = GetPageForCategoryType(last_category_);
- for (int cat = last_category_ - 1; !page && cat >= minimum_category; cat--) {
+ FreeListCategoryType minimum_category =
+ SelectFreeListCategoryType(size_in_bytes);
+ Page* page = nullptr;
+ for (int cat = minimum_category + 1; !page && cat <= last_category_; cat++) {
page = GetPageForCategoryType(cat);
}
+ if (!page) {
+ // Might return a page in which |size_in_bytes| will not fit.
+ page = GetPageForCategoryType(minimum_category);
+ }
return page;
}
-FreeListMany::~FreeListMany() { delete[] categories_; }
-
-FreeSpace FreeListMany::Allocate(size_t size_in_bytes, size_t* node_size) {
+FreeSpace FreeListMany::Allocate(size_t size_in_bytes, size_t* node_size,
+ AllocationOrigin origin) {
DCHECK_GE(kMaxBlockSize, size_in_bytes);
FreeSpace node;
FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
@@ -3211,39 +3292,258 @@ FreeSpace FreeListMany::Allocate(size_t size_in_bytes, size_t* node_size) {
}
// ------------------------------------------------
+// FreeListManyCached implementation
+
+FreeListManyCached::FreeListManyCached() { ResetCache(); }
+
+void FreeListManyCached::Reset() {
+ ResetCache();
+ FreeListMany::Reset();
+}
+
+bool FreeListManyCached::AddCategory(FreeListCategory* category) {
+ bool was_added = FreeList::AddCategory(category);
+
+ // Updating cache
+ if (was_added) {
+ UpdateCacheAfterAddition(category->type_);
+ }
+
+#ifdef DEBUG
+ CheckCacheIntegrity();
+#endif
+
+ return was_added;
+}
+
+void FreeListManyCached::RemoveCategory(FreeListCategory* category) {
+ FreeList::RemoveCategory(category);
+
+ // Updating cache
+ int type = category->type_;
+ if (categories_[type] == nullptr) {
+ UpdateCacheAfterRemoval(type);
+ }
+
+#ifdef DEBUG
+ CheckCacheIntegrity();
+#endif
+}
+
+size_t FreeListManyCached::Free(Address start, size_t size_in_bytes,
+ FreeMode mode) {
+ Page* page = Page::FromAddress(start);
+ page->DecreaseAllocatedBytes(size_in_bytes);
+
+ // Blocks have to be a minimum size to hold free list items.
+ if (size_in_bytes < min_block_size_) {
+ page->add_wasted_memory(size_in_bytes);
+ wasted_bytes_ += size_in_bytes;
+ return size_in_bytes;
+ }
+
+ // Insert other blocks at the head of a free list of the appropriate
+ // magnitude.
+ FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
+ page->free_list_category(type)->Free(start, size_in_bytes, mode, this);
+
+ // Updating cache
+ if (mode == kLinkCategory) {
+ UpdateCacheAfterAddition(type);
+
+#ifdef DEBUG
+ CheckCacheIntegrity();
+#endif
+ }
+
+ DCHECK_EQ(page->AvailableInFreeList(),
+ page->AvailableInFreeListFromAllocatedBytes());
+ return 0;
+}
+
+FreeSpace FreeListManyCached::Allocate(size_t size_in_bytes, size_t* node_size,
+ AllocationOrigin origin) {
+ USE(origin);
+ DCHECK_GE(kMaxBlockSize, size_in_bytes);
+
+ FreeSpace node;
+ FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
+ type = next_nonempty_category[type];
+ for (; type < last_category_; type = next_nonempty_category[type + 1]) {
+ node = TryFindNodeIn(type, size_in_bytes, node_size);
+ if (!node.is_null()) break;
+ }
+
+ if (node.is_null()) {
+ // Searching each element of the last category.
+ type = last_category_;
+ node = SearchForNodeInList(type, size_in_bytes, node_size);
+ }
+
+ // Updating cache
+ if (!node.is_null() && categories_[type] == nullptr) {
+ UpdateCacheAfterRemoval(type);
+ }
+
+#ifdef DEBUG
+ CheckCacheIntegrity();
+#endif
+
+ if (!node.is_null()) {
+ Page::FromHeapObject(node)->IncreaseAllocatedBytes(*node_size);
+ }
+
+ DCHECK(IsVeryLong() || Available() == SumFreeLists());
+ return node;
+}
+
+// ------------------------------------------------
+// FreeListManyCachedFastPath implementation
+
+FreeSpace FreeListManyCachedFastPath::Allocate(size_t size_in_bytes,
+ size_t* node_size,
+ AllocationOrigin origin) {
+ USE(origin);
+ DCHECK_GE(kMaxBlockSize, size_in_bytes);
+ FreeSpace node;
+
+ // Fast path part 1: searching the last categories
+ FreeListCategoryType first_category =
+ SelectFastAllocationFreeListCategoryType(size_in_bytes);
+ FreeListCategoryType type = first_category;
+ for (type = next_nonempty_category[type]; type <= last_category_;
+ type = next_nonempty_category[type + 1]) {
+ node = TryFindNodeIn(type, size_in_bytes, node_size);
+ if (!node.is_null()) break;
+ }
+
+ // Fast path part 2: searching the medium categories for tiny objects
+ if (node.is_null()) {
+ if (size_in_bytes <= kTinyObjectMaxSize) {
+ for (type = next_nonempty_category[kFastPathFallBackTiny];
+ type < kFastPathFirstCategory;
+ type = next_nonempty_category[type + 1]) {
+ node = TryFindNodeIn(type, size_in_bytes, node_size);
+ if (!node.is_null()) break;
+ }
+ }
+ }
+
+ // Searching the last category
+ if (node.is_null()) {
+ // Searching each element of the last category.
+ type = last_category_;
+ node = SearchForNodeInList(type, size_in_bytes, node_size);
+ }
+
+ // Finally, search the most precise category
+ if (node.is_null()) {
+ type = SelectFreeListCategoryType(size_in_bytes);
+ for (type = next_nonempty_category[type]; type < first_category;
+ type = next_nonempty_category[type + 1]) {
+ node = TryFindNodeIn(type, size_in_bytes, node_size);
+ if (!node.is_null()) break;
+ }
+ }
+
+ // Updating cache
+ if (!node.is_null() && categories_[type] == nullptr) {
+ UpdateCacheAfterRemoval(type);
+ }
+
+#ifdef DEBUG
+ CheckCacheIntegrity();
+#endif
+
+ if (!node.is_null()) {
+ Page::FromHeapObject(node)->IncreaseAllocatedBytes(*node_size);
+ }
+
+ DCHECK(IsVeryLong() || Available() == SumFreeLists());
+ return node;
+}
+
+// ------------------------------------------------
+// FreeListManyCachedOrigin implementation
+
+FreeSpace FreeListManyCachedOrigin::Allocate(size_t size_in_bytes,
+ size_t* node_size,
+ AllocationOrigin origin) {
+ if (origin == AllocationOrigin::kGC) {
+ return FreeListManyCached::Allocate(size_in_bytes, node_size, origin);
+ } else {
+ return FreeListManyCachedFastPath::Allocate(size_in_bytes, node_size,
+ origin);
+ }
+}
+
+// ------------------------------------------------
+// FreeListMap implementation
+
+FreeListMap::FreeListMap() {
+ // Initializing base (FreeList) fields
+ number_of_categories_ = 1;
+ last_category_ = kOnlyCategory;
+ min_block_size_ = kMinBlockSize;
+ categories_ = new FreeListCategory*[number_of_categories_]();
+
+ Reset();
+}
+
+size_t FreeListMap::GuaranteedAllocatable(size_t maximum_freed) {
+ return maximum_freed;
+}
+
+Page* FreeListMap::GetPageForSize(size_t size_in_bytes) {
+ return GetPageForCategoryType(kOnlyCategory);
+}
+
+FreeListMap::~FreeListMap() { delete[] categories_; }
+
+FreeSpace FreeListMap::Allocate(size_t size_in_bytes, size_t* node_size,
+ AllocationOrigin origin) {
+ DCHECK_GE(kMaxBlockSize, size_in_bytes);
+
+ // The following DCHECK ensures that maps are allocated one by one (ie,
+ // without folding). This assumption currently holds. However, if it were to
+ // become untrue in the future, you'll get an error here. To fix it, I would
+ // suggest removing the DCHECK, and replacing TryFindNodeIn by
+ // SearchForNodeInList below.
+ DCHECK_EQ(size_in_bytes, Map::kSize);
+
+ FreeSpace node = TryFindNodeIn(kOnlyCategory, size_in_bytes, node_size);
+
+ if (!node.is_null()) {
+ Page::FromHeapObject(node)->IncreaseAllocatedBytes(*node_size);
+ }
+
+ DCHECK_IMPLIES(node.is_null(), IsEmpty());
+ return node;
+}
+
+// ------------------------------------------------
// Generic FreeList methods (non alloc/free related)
void FreeList::Reset() {
ForAllFreeListCategories(
- [](FreeListCategory* category) { category->Reset(); });
+ [this](FreeListCategory* category) { category->Reset(this); });
for (int i = kFirstCategory; i < number_of_categories_; i++) {
categories_[i] = nullptr;
}
wasted_bytes_ = 0;
+ available_ = 0;
}
size_t FreeList::EvictFreeListItems(Page* page) {
size_t sum = 0;
page->ForAllFreeListCategories([this, &sum](FreeListCategory* category) {
- DCHECK_EQ(this, category->owner());
sum += category->available();
RemoveCategory(category);
- category->Reset();
+ category->Reset(this);
});
return sum;
}
-bool FreeList::ContainsPageFreeListItems(Page* page) {
- bool contained = false;
- page->ForAllFreeListCategories(
- [this, &contained](FreeListCategory* category) {
- if (category->owner() == this && category->is_linked()) {
- contained = true;
- }
- });
- return contained;
-}
-
void FreeList::RepairLists(Heap* heap) {
ForAllFreeListCategories(
[heap](FreeListCategory* category) { category->RepairFreeList(heap); });
@@ -3255,7 +3555,7 @@ bool FreeList::AddCategory(FreeListCategory* category) {
FreeListCategory* top = categories_[type];
if (category->is_empty()) return false;
- if (top == category) return false;
+ DCHECK_NE(top, category);
// Common double-linked list insertion.
if (top != nullptr) {
@@ -3263,6 +3563,8 @@ bool FreeList::AddCategory(FreeListCategory* category) {
}
category->set_next(top);
categories_[type] = category;
+
+ IncreaseAvailableBytes(category->available());
return true;
}
@@ -3271,6 +3573,10 @@ void FreeList::RemoveCategory(FreeListCategory* category) {
DCHECK_LT(type, number_of_categories_);
FreeListCategory* top = categories_[type];
+ if (category->is_linked(this)) {
+ DecreaseAvailableBytes(category->available());
+ }
+
// Common double-linked list removal.
if (top == category) {
categories_[type] = category->next();
@@ -3312,13 +3618,25 @@ size_t FreeListCategory::SumFreeList() {
while (!cur.is_null()) {
// We can't use "cur->map()" here because both cur's map and the
// root can be null during bootstrapping.
- DCHECK(cur.map_slot().contains_value(
- page()->heap()->isolate()->root(RootIndex::kFreeSpaceMap).ptr()));
+ DCHECK(cur.map_slot().contains_value(Page::FromHeapObject(cur)
+ ->heap()
+ ->isolate()
+ ->root(RootIndex::kFreeSpaceMap)
+ .ptr()));
sum += cur.relaxed_read_size();
cur = cur.next();
}
return sum;
}
+int FreeListCategory::FreeListLength() {
+ int length = 0;
+ FreeSpace cur = top();
+ while (!cur.is_null()) {
+ length++;
+ cur = cur.next();
+ }
+ return length;
+}
#ifdef DEBUG
bool FreeList::IsVeryLong() {
@@ -3364,7 +3682,8 @@ size_t PagedSpace::SizeOfObjects() {
return Size() - (limit() - top());
}
-bool PagedSpace::SweepAndRetryAllocation(int size_in_bytes) {
+bool PagedSpace::SweepAndRetryAllocation(int size_in_bytes,
+ AllocationOrigin origin) {
MarkCompactCollector* collector = heap()->mark_compact_collector();
if (collector->sweeping_in_progress()) {
// Wait for the sweeper threads here and complete the sweeping phase.
@@ -3372,38 +3691,43 @@ bool PagedSpace::SweepAndRetryAllocation(int size_in_bytes) {
// After waiting for the sweeper threads, there may be new free-list
// entries.
- return RefillLinearAllocationAreaFromFreeList(size_in_bytes);
+ return RefillLinearAllocationAreaFromFreeList(size_in_bytes, origin);
}
return false;
}
-bool CompactionSpace::SweepAndRetryAllocation(int size_in_bytes) {
+bool CompactionSpace::SweepAndRetryAllocation(int size_in_bytes,
+ AllocationOrigin origin) {
MarkCompactCollector* collector = heap()->mark_compact_collector();
if (FLAG_concurrent_sweeping && collector->sweeping_in_progress()) {
collector->sweeper()->ParallelSweepSpace(identity(), 0);
RefillFreeList();
- return RefillLinearAllocationAreaFromFreeList(size_in_bytes);
+ return RefillLinearAllocationAreaFromFreeList(size_in_bytes, origin);
}
return false;
}
-bool PagedSpace::SlowRefillLinearAllocationArea(int size_in_bytes) {
+bool PagedSpace::SlowRefillLinearAllocationArea(int size_in_bytes,
+ AllocationOrigin origin) {
VMState<GC> state(heap()->isolate());
RuntimeCallTimerScope runtime_timer(
heap()->isolate(), RuntimeCallCounterId::kGC_Custom_SlowAllocateRaw);
- return RawSlowRefillLinearAllocationArea(size_in_bytes);
+ return RawSlowRefillLinearAllocationArea(size_in_bytes, origin);
}
-bool CompactionSpace::SlowRefillLinearAllocationArea(int size_in_bytes) {
- return RawSlowRefillLinearAllocationArea(size_in_bytes);
+bool CompactionSpace::SlowRefillLinearAllocationArea(int size_in_bytes,
+ AllocationOrigin origin) {
+ return RawSlowRefillLinearAllocationArea(size_in_bytes, origin);
}
-bool PagedSpace::RawSlowRefillLinearAllocationArea(int size_in_bytes) {
+bool PagedSpace::RawSlowRefillLinearAllocationArea(int size_in_bytes,
+ AllocationOrigin origin) {
// Allocation in this space has failed.
DCHECK_GE(size_in_bytes, 0);
const int kMaxPagesToSweep = 1;
- if (RefillLinearAllocationAreaFromFreeList(size_in_bytes)) return true;
+ if (RefillLinearAllocationAreaFromFreeList(size_in_bytes, origin))
+ return true;
MarkCompactCollector* collector = heap()->mark_compact_collector();
// Sweeping is still in progress.
@@ -3419,16 +3743,24 @@ bool PagedSpace::RawSlowRefillLinearAllocationArea(int size_in_bytes) {
// Retry the free list allocation.
if (RefillLinearAllocationAreaFromFreeList(
- static_cast<size_t>(size_in_bytes)))
+ static_cast<size_t>(size_in_bytes), origin))
return true;
+ // Cleanup invalidated old-to-new refs for compaction space in the
+ // final atomic pause.
+ Sweeper::FreeSpaceMayContainInvalidatedSlots
+ invalidated_slots_in_free_space =
+ is_local() ? Sweeper::FreeSpaceMayContainInvalidatedSlots::kYes
+ : Sweeper::FreeSpaceMayContainInvalidatedSlots::kNo;
+
// If sweeping is still in progress try to sweep pages.
int max_freed = collector->sweeper()->ParallelSweepSpace(
- identity(), size_in_bytes, kMaxPagesToSweep);
+ identity(), size_in_bytes, kMaxPagesToSweep,
+ invalidated_slots_in_free_space);
RefillFreeList();
if (max_freed >= size_in_bytes) {
if (RefillLinearAllocationAreaFromFreeList(
- static_cast<size_t>(size_in_bytes)))
+ static_cast<size_t>(size_in_bytes), origin))
return true;
}
}
@@ -3441,7 +3773,7 @@ bool PagedSpace::RawSlowRefillLinearAllocationArea(int size_in_bytes) {
if (page != nullptr) {
AddPage(page);
if (RefillLinearAllocationAreaFromFreeList(
- static_cast<size_t>(size_in_bytes)))
+ static_cast<size_t>(size_in_bytes), origin))
return true;
}
}
@@ -3450,22 +3782,57 @@ bool PagedSpace::RawSlowRefillLinearAllocationArea(int size_in_bytes) {
DCHECK((CountTotalPages() > 1) ||
(static_cast<size_t>(size_in_bytes) <= free_list_->Available()));
return RefillLinearAllocationAreaFromFreeList(
- static_cast<size_t>(size_in_bytes));
+ static_cast<size_t>(size_in_bytes), origin);
}
// If sweeper threads are active, wait for them at that point and steal
// elements form their free-lists. Allocation may still fail their which
// would indicate that there is not enough memory for the given allocation.
- return SweepAndRetryAllocation(size_in_bytes);
+ return SweepAndRetryAllocation(size_in_bytes, origin);
}
// -----------------------------------------------------------------------------
// MapSpace implementation
+// TODO(dmercadier): use a heap instead of sorting like that.
+// Using a heap will have multiple benefits:
+// - for now, SortFreeList is only called after sweeping, which is somewhat
+// late. Using a heap, sorting could be done online: FreeListCategories would
+// be inserted in a heap (ie, in a sorted manner).
+// - SortFreeList is a bit fragile: any change to FreeListMap (or to
+// MapSpace::free_list_) could break it.
+void MapSpace::SortFreeList() {
+ using LiveBytesPagePair = std::pair<size_t, Page*>;
+ std::vector<LiveBytesPagePair> pages;
+ pages.reserve(CountTotalPages());
+
+ for (Page* p : *this) {
+ free_list()->RemoveCategory(p->free_list_category(kFirstCategory));
+ pages.push_back(std::make_pair(p->allocated_bytes(), p));
+ }
+
+ // Sorting by least-allocated-bytes first.
+ std::sort(pages.begin(), pages.end(),
+ [](const LiveBytesPagePair& a, const LiveBytesPagePair& b) {
+ return a.first < b.first;
+ });
+
+ for (LiveBytesPagePair const& p : pages) {
+ // Since AddCategory inserts in head position, it reverts the order produced
+ // by the sort above: least-allocated-bytes will be Added first, and will
+ // therefore be the last element (and the first one will be
+ // most-allocated-bytes).
+ free_list()->AddCategory(p.second->free_list_category(kFirstCategory));
+ }
+}
+
#ifdef VERIFY_HEAP
void MapSpace::VerifyObject(HeapObject object) { CHECK(object.IsMap()); }
#endif
+// -----------------------------------------------------------------------------
+// ReadOnlySpace implementation
+
ReadOnlySpace::ReadOnlySpace(Heap* heap)
: PagedSpace(heap, RO_SPACE, NOT_EXECUTABLE, FreeList::CreateFreeList()),
is_string_padding_cleared_(heap->isolate()->initialized_from_snapshot()) {
diff --git a/deps/v8/src/heap/spaces.h b/deps/v8/src/heap/spaces.h
index 384c731f37..ebb6876cbe 100644
--- a/deps/v8/src/heap/spaces.h
+++ b/deps/v8/src/heap/spaces.h
@@ -31,6 +31,7 @@
#include "src/tasks/cancelable-task.h"
#include "src/utils/allocation.h"
#include "src/utils/utils.h"
+#include "testing/gtest/include/gtest/gtest_prod.h" // nogncheck
namespace v8 {
namespace internal {
@@ -120,7 +121,7 @@ class Space;
#define DCHECK_CODEOBJECT_SIZE(size, code_space) \
DCHECK((0 < size) && (size <= code_space->AreaSize()))
-using FreeListCategoryType = int;
+using FreeListCategoryType = int32_t;
static const FreeListCategoryType kFirstCategory = 0;
static const FreeListCategoryType kInvalidCategory = -1;
@@ -138,32 +139,23 @@ enum RememberedSetType {
// A free list category maintains a linked list of free memory blocks.
class FreeListCategory {
public:
- FreeListCategory(FreeList* free_list, Page* page)
- : free_list_(free_list),
- page_(page),
- type_(kInvalidCategory),
- available_(0),
- length_(0),
- prev_(nullptr),
- next_(nullptr) {}
-
void Initialize(FreeListCategoryType type) {
type_ = type;
available_ = 0;
- length_ = 0;
prev_ = nullptr;
next_ = nullptr;
}
- void Reset();
+ void Reset(FreeList* owner);
void RepairFreeList(Heap* heap);
// Relinks the category into the currently owning free list. Requires that the
// category is currently unlinked.
- void Relink();
+ void Relink(FreeList* owner);
- void Free(Address address, size_t size_in_bytes, FreeMode mode);
+ void Free(Address address, size_t size_in_bytes, FreeMode mode,
+ FreeList* owner);
// Performs a single try to pick a node of at least |minimum_size| from the
// category. Stores the actual size in |node_size|. Returns nullptr if no
@@ -174,22 +166,22 @@ class FreeListCategory {
// actual size in |node_size|. Returns nullptr if no node is found.
FreeSpace SearchForNodeInList(size_t minimum_size, size_t* node_size);
- inline FreeList* owner();
- inline Page* page() const { return page_; }
- inline bool is_linked();
+ inline bool is_linked(FreeList* owner) const;
bool is_empty() { return top().is_null(); }
- size_t available() const { return available_; }
-
- void set_free_list(FreeList* free_list) { free_list_ = free_list; }
+ uint32_t available() const { return available_; }
size_t SumFreeList();
- int FreeListLength() { return length_; }
+ int FreeListLength();
private:
// For debug builds we accurately compute free lists lengths up until
// {kVeryLongFreeList} by manually walking the list.
static const int kVeryLongFreeList = 500;
+ // Updates |available_|, |length_| and free_list_->Available() after an
+ // allocation of size |allocation_size|.
+ inline void UpdateCountersAfterAllocation(size_t allocation_size);
+
FreeSpace top() { return top_; }
void set_top(FreeSpace top) { top_ = top; }
FreeListCategory* prev() { return prev_; }
@@ -197,32 +189,23 @@ class FreeListCategory {
FreeListCategory* next() { return next_; }
void set_next(FreeListCategory* next) { next_ = next; }
- // This FreeListCategory is owned by the given free_list_.
- FreeList* free_list_;
-
- // This FreeListCategory holds free list entries of the given page_.
- Page* const page_;
-
// |type_|: The type of this free list category.
- FreeListCategoryType type_;
+ FreeListCategoryType type_ = kInvalidCategory;
// |available_|: Total available bytes in all blocks of this free list
// category.
- size_t available_;
-
- // |length_|: Total blocks in this free list category.
- int length_;
+ uint32_t available_ = 0;
// |top_|: Points to the top FreeSpace in the free list category.
FreeSpace top_;
- FreeListCategory* prev_;
- FreeListCategory* next_;
+ FreeListCategory* prev_ = nullptr;
+ FreeListCategory* next_ = nullptr;
friend class FreeList;
+ friend class FreeListManyCached;
friend class PagedSpace;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(FreeListCategory);
+ friend class MapSpace;
};
// A free list maintains free blocks of memory. The free list is organized in
@@ -256,22 +239,24 @@ class FreeList {
// size_in_bytes. This method returns null if the allocation request cannot be
// handled by the free list.
virtual V8_WARN_UNUSED_RESULT FreeSpace Allocate(size_t size_in_bytes,
- size_t* node_size) = 0;
+ size_t* node_size,
+ AllocationOrigin origin) = 0;
// Returns a page containing an entry for a given type, or nullptr otherwise.
V8_EXPORT_PRIVATE virtual Page* GetPageForSize(size_t size_in_bytes) = 0;
- void Reset();
+ virtual void Reset();
// Return the number of bytes available on the free list.
size_t Available() {
- size_t available = 0;
- ForAllFreeListCategories([&available](FreeListCategory* category) {
- available += category->available();
- });
- return available;
+ DCHECK(available_ == SumFreeLists());
+ return available_;
}
+ // Update number of available bytes on the Freelists.
+ void IncreaseAvailableBytes(size_t bytes) { available_ += bytes; }
+ void DecreaseAvailableBytes(size_t bytes) { available_ -= bytes; }
+
bool IsEmpty() {
bool empty = true;
ForAllFreeListCategories([&empty](FreeListCategory* category) {
@@ -284,7 +269,6 @@ class FreeList {
void RepairLists(Heap* heap);
V8_EXPORT_PRIVATE size_t EvictFreeListItems(Page* page);
- bool ContainsPageFreeListItems(Page* page);
int number_of_categories() { return number_of_categories_; }
FreeListCategoryType last_category() { return last_category_; }
@@ -308,15 +292,10 @@ class FreeList {
}
}
- bool AddCategory(FreeListCategory* category);
- V8_EXPORT_PRIVATE void RemoveCategory(FreeListCategory* category);
+ virtual bool AddCategory(FreeListCategory* category);
+ virtual V8_EXPORT_PRIVATE void RemoveCategory(FreeListCategory* category);
void PrintCategories(FreeListCategoryType type);
-#ifdef DEBUG
- size_t SumFreeLists();
- bool IsVeryLong();
-#endif
-
protected:
class FreeListCategoryIterator final {
public:
@@ -336,6 +315,11 @@ class FreeList {
FreeListCategory* current_;
};
+#ifdef DEBUG
+ V8_EXPORT_PRIVATE size_t SumFreeLists();
+ bool IsVeryLong();
+#endif
+
// Tries to retrieve a node from the first category in a given |type|.
// Returns nullptr if the category is empty or the top entry is smaller
// than minimum_size.
@@ -355,9 +339,7 @@ class FreeList {
return categories_[type];
}
- Page* GetPageForCategoryType(FreeListCategoryType type) {
- return top(type) ? top(type)->page() : nullptr;
- }
+ inline Page* GetPageForCategoryType(FreeListCategoryType type);
int number_of_categories_ = 0;
FreeListCategoryType last_category_ = 0;
@@ -366,10 +348,14 @@ class FreeList {
std::atomic<size_t> wasted_bytes_{0};
FreeListCategory** categories_ = nullptr;
+ // |available_|: The number of bytes in this freelist.
+ size_t available_ = 0;
+
friend class FreeListCategory;
friend class Page;
friend class MemoryChunk;
friend class ReadOnlyPage;
+ friend class MapSpace;
};
// FreeList used for spaces that don't have freelists
@@ -383,7 +369,8 @@ class NoFreeList final : public FreeList {
FATAL("NoFreeList can't be used as a standard FreeList.");
}
V8_WARN_UNUSED_RESULT FreeSpace Allocate(size_t size_in_bytes,
- size_t* node_size) final {
+ size_t* node_size,
+ AllocationOrigin origin) final {
FATAL("NoFreeList can't be used as a standard FreeList.");
}
Page* GetPageForSize(size_t size_in_bytes) final {
@@ -412,11 +399,8 @@ class V8_EXPORT_PRIVATE Space : public Malloced {
external_backing_store_bytes_[ExternalBackingStoreType::kArrayBuffer] = 0;
external_backing_store_bytes_[ExternalBackingStoreType::kExternalString] =
0;
- CheckOffsetsAreConsistent();
}
- void CheckOffsetsAreConsistent() const;
-
static inline void MoveExternalBackingStoreBytes(
ExternalBackingStoreType type, Space* from, Space* to, size_t amount);
@@ -531,8 +515,6 @@ class V8_EXPORT_PRIVATE Space : public Malloced {
// Tracks off-heap memory used by this space.
std::atomic<size_t>* external_backing_store_bytes_;
- static const intptr_t kIdOffset = 9 * kSystemPointerSize;
-
bool allocation_observers_paused_;
Heap* heap_;
AllocationSpace id_;
@@ -627,7 +609,8 @@ class MemoryChunk : public BasicMemoryChunk {
+ kSystemPointerSize * NUMBER_OF_REMEMBERED_SET_TYPES // SlotSet* array
+ kSystemPointerSize *
NUMBER_OF_REMEMBERED_SET_TYPES // TypedSlotSet* array
- + kSystemPointerSize // InvalidatedSlots* invalidated_slots_
+ + kSystemPointerSize *
+ NUMBER_OF_REMEMBERED_SET_TYPES // InvalidatedSlots* array
+ kSystemPointerSize // std::atomic<intptr_t> high_water_mark_
+ kSystemPointerSize // base::Mutex* mutex_
+ kSystemPointerSize // std::atomic<ConcurrentSweepingState>
@@ -713,7 +696,7 @@ class MemoryChunk : public BasicMemoryChunk {
template <RememberedSetType type>
bool ContainsSlots() {
return slot_set<type>() != nullptr || typed_slot_set<type>() != nullptr ||
- invalidated_slots() != nullptr;
+ invalidated_slots<type>() != nullptr;
}
template <RememberedSetType type, AccessMode access_mode = AccessMode::ATOMIC>
@@ -741,15 +724,23 @@ class MemoryChunk : public BasicMemoryChunk {
template <RememberedSetType type>
void ReleaseTypedSlotSet();
+ template <RememberedSetType type>
InvalidatedSlots* AllocateInvalidatedSlots();
+ template <RememberedSetType type>
void ReleaseInvalidatedSlots();
+ template <RememberedSetType type>
V8_EXPORT_PRIVATE void RegisterObjectWithInvalidatedSlots(HeapObject object,
int size);
// Updates invalidated_slots after array left-trimming.
+ template <RememberedSetType type>
void MoveObjectWithInvalidatedSlots(HeapObject old_start,
HeapObject new_start);
+ template <RememberedSetType type>
bool RegisteredObjectWithInvalidatedSlots(HeapObject object);
- InvalidatedSlots* invalidated_slots() { return invalidated_slots_; }
+ template <RememberedSetType type>
+ InvalidatedSlots* invalidated_slots() {
+ return invalidated_slots_[type];
+ }
void ReleaseLocalTracker();
@@ -925,7 +916,7 @@ class MemoryChunk : public BasicMemoryChunk {
// is ceil(size() / kPageSize).
SlotSet* slot_set_[NUMBER_OF_REMEMBERED_SET_TYPES];
TypedSlotSet* typed_slot_set_[NUMBER_OF_REMEMBERED_SET_TYPES];
- InvalidatedSlots* invalidated_slots_;
+ InvalidatedSlots* invalidated_slots_[NUMBER_OF_REMEMBERED_SET_TYPES];
// Assuming the initial allocation on a page is sequential,
// count highest number of bytes ever allocated on the page.
@@ -1811,28 +1802,14 @@ class V8_EXPORT_PRIVATE FreeListLegacy : public FreeList {
return maximum_freed;
}
- Page* GetPageForSize(size_t size_in_bytes) override {
- const int minimum_category =
- static_cast<int>(SelectFreeListCategoryType(size_in_bytes));
- Page* page = GetPageForCategoryType(kHuge);
- if (!page && static_cast<int>(kLarge) >= minimum_category)
- page = GetPageForCategoryType(kLarge);
- if (!page && static_cast<int>(kMedium) >= minimum_category)
- page = GetPageForCategoryType(kMedium);
- if (!page && static_cast<int>(kSmall) >= minimum_category)
- page = GetPageForCategoryType(kSmall);
- if (!page && static_cast<int>(kTiny) >= minimum_category)
- page = GetPageForCategoryType(kTiny);
- if (!page && static_cast<int>(kTiniest) >= minimum_category)
- page = GetPageForCategoryType(kTiniest);
- return page;
- }
+ inline Page* GetPageForSize(size_t size_in_bytes) override;
FreeListLegacy();
~FreeListLegacy();
V8_WARN_UNUSED_RESULT FreeSpace Allocate(size_t size_in_bytes,
- size_t* node_size) override;
+ size_t* node_size,
+ AllocationOrigin origin) override;
private:
enum { kTiniest, kTiny, kSmall, kMedium, kLarge, kHuge };
@@ -1909,22 +1886,14 @@ class V8_EXPORT_PRIVATE FreeListFastAlloc : public FreeList {
return kHugeAllocationMax;
}
- Page* GetPageForSize(size_t size_in_bytes) override {
- const int minimum_category =
- static_cast<int>(SelectFreeListCategoryType(size_in_bytes));
- Page* page = GetPageForCategoryType(kHuge);
- if (!page && static_cast<int>(kLarge) >= minimum_category)
- page = GetPageForCategoryType(kLarge);
- if (!page && static_cast<int>(kMedium) >= minimum_category)
- page = GetPageForCategoryType(kMedium);
- return page;
- }
+ inline Page* GetPageForSize(size_t size_in_bytes) override;
FreeListFastAlloc();
~FreeListFastAlloc();
V8_WARN_UNUSED_RESULT FreeSpace Allocate(size_t size_in_bytes,
- size_t* node_size) override;
+ size_t* node_size,
+ AllocationOrigin origin) override;
private:
enum { kMedium, kLarge, kHuge };
@@ -1951,14 +1920,10 @@ class V8_EXPORT_PRIVATE FreeListFastAlloc : public FreeList {
}
return kHuge;
}
-
- Page* GetPageForCategoryType(FreeListCategoryType type) {
- return top(type) ? top(type)->page() : nullptr;
- }
};
-// Use 49 Freelists: on per size between 24 and 256, and then a few ones for
-// larger sizes. See the variable |categories_max| for the size of each
+// Use 24 Freelists: on per 16 bytes between 24 and 256, and then a few ones for
+// larger sizes. See the variable |categories_min| for the size of each
// Freelist. Allocation is done using a best-fit strategy (considering only the
// first element of each category though).
// Performances are expected to be worst than FreeListLegacy, but memory
@@ -1973,41 +1938,214 @@ class V8_EXPORT_PRIVATE FreeListMany : public FreeList {
~FreeListMany();
V8_WARN_UNUSED_RESULT FreeSpace Allocate(size_t size_in_bytes,
- size_t* node_size) override;
+ size_t* node_size,
+ AllocationOrigin origin) override;
- private:
+ protected:
static const size_t kMinBlockSize = 3 * kTaggedSize;
// This is a conservative upper bound. The actual maximum block size takes
// padding and alignment of data and code pages into account.
static const size_t kMaxBlockSize = Page::kPageSize;
+ // Largest size for which categories are still precise, and for which we can
+ // therefore compute the category in constant time.
+ static const size_t kPreciseCategoryMaxSize = 256;
// Categories boundaries generated with:
// perl -E '
- // @cat = map {$_*8} 3..32, 48, 64;
- // while ($cat[-1] <= 32768) {
- // push @cat, $cat[-1]+$cat[-3], $cat[-1]*2
- // }
- // push @cat, 4080, 4088;
- // @cat = sort { $a <=> $b } @cat;
- // push @cat, "Page::kPageSize";
- // say join ", ", @cat;
- // say "\n", scalar @cat'
- // Note the special case for 4080 and 4088 bytes: experiments have shown that
- // this category classes are more used than others of similar sizes
- static const int kNumberOfCategories = 49;
- static const size_t categories_max[kNumberOfCategories];
+ // @cat = (24, map {$_*16} 2..16, 48, 64);
+ // while ($cat[-1] <= 32768) {
+ // push @cat, $cat[-1]*2
+ // }
+ // say join ", ", @cat;
+ // say "\n", scalar @cat'
+ static const int kNumberOfCategories = 24;
+ static constexpr unsigned int categories_min[kNumberOfCategories] = {
+ 24, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192,
+ 208, 224, 240, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536};
// Return the smallest category that could hold |size_in_bytes| bytes.
FreeListCategoryType SelectFreeListCategoryType(
size_t size_in_bytes) override {
- for (int cat = kFirstCategory; cat < last_category_; cat++) {
- if (size_in_bytes <= categories_max[cat]) {
+ if (size_in_bytes <= kPreciseCategoryMaxSize) {
+ if (size_in_bytes < categories_min[1]) return 0;
+ return static_cast<FreeListCategoryType>(size_in_bytes >> 4) - 1;
+ }
+ for (int cat = (kPreciseCategoryMaxSize >> 4) - 1; cat < last_category_;
+ cat++) {
+ if (size_in_bytes < categories_min[cat + 1]) {
+ return cat;
+ }
+ }
+ return last_category_;
+ }
+
+ FRIEND_TEST(SpacesTest, FreeListManySelectFreeListCategoryType);
+ FRIEND_TEST(SpacesTest, FreeListManyGuaranteedAllocatable);
+};
+
+// Same as FreeListMany but uses a cache to know which categories are empty.
+// The cache (|next_nonempty_category|) is maintained in a way such that for
+// each category c, next_nonempty_category[c] contains the first non-empty
+// category greater or equal to c, that may hold an object of size c.
+// Allocation is done using the same strategy as FreeListMany (ie, best fit).
+class V8_EXPORT_PRIVATE FreeListManyCached : public FreeListMany {
+ public:
+ FreeListManyCached();
+
+ V8_WARN_UNUSED_RESULT FreeSpace Allocate(size_t size_in_bytes,
+ size_t* node_size,
+ AllocationOrigin origin) override;
+
+ size_t Free(Address start, size_t size_in_bytes, FreeMode mode) override;
+
+ void Reset() override;
+
+ bool AddCategory(FreeListCategory* category) override;
+ void RemoveCategory(FreeListCategory* category) override;
+
+ protected:
+ // Updates the cache after adding something in the category |cat|.
+ void UpdateCacheAfterAddition(FreeListCategoryType cat) {
+ for (int i = cat; i >= kFirstCategory && next_nonempty_category[i] > cat;
+ i--) {
+ next_nonempty_category[i] = cat;
+ }
+ }
+
+ // Updates the cache after emptying category |cat|.
+ void UpdateCacheAfterRemoval(FreeListCategoryType cat) {
+ for (int i = cat; i >= kFirstCategory && next_nonempty_category[i] == cat;
+ i--) {
+ next_nonempty_category[i] = next_nonempty_category[cat + 1];
+ }
+ }
+
+#ifdef DEBUG
+ void CheckCacheIntegrity() {
+ for (int i = 0; i <= last_category_; i++) {
+ DCHECK(next_nonempty_category[i] == last_category_ + 1 ||
+ categories_[next_nonempty_category[i]] != nullptr);
+ for (int j = i; j < next_nonempty_category[i]; j++) {
+ DCHECK(categories_[j] == nullptr);
+ }
+ }
+ }
+#endif
+
+ // The cache is overallocated by one so that the last element is always
+ // defined, and when updating the cache, we can always use cache[i+1] as long
+ // as i is < kNumberOfCategories.
+ int next_nonempty_category[kNumberOfCategories + 1];
+
+ private:
+ void ResetCache() {
+ for (int i = 0; i < kNumberOfCategories; i++) {
+ next_nonempty_category[i] = kNumberOfCategories;
+ }
+ // Setting the after-last element as well, as explained in the cache's
+ // declaration.
+ next_nonempty_category[kNumberOfCategories] = kNumberOfCategories;
+ }
+};
+
+// Same as FreeListManyCached but uses a fast path.
+// The fast path overallocates by at least 1.85k bytes. The idea of this 1.85k
+// is: we want the fast path to always overallocate, even for larger
+// categories. Therefore, we have two choices: either overallocate by
+// "size_in_bytes * something" or overallocate by "size_in_bytes +
+// something". We choose the later, as the former will tend to overallocate too
+// much for larger objects. The 1.85k (= 2048 - 128) has been chosen such that
+// for tiny objects (size <= 128 bytes), the first category considered is the
+// 36th (which holds objects of 2k to 3k), while for larger objects, the first
+// category considered will be one that guarantees a 1.85k+ bytes
+// overallocation. Using 2k rather than 1.85k would have resulted in either a
+// more complex logic for SelectFastAllocationFreeListCategoryType, or the 36th
+// category (2k to 3k) not being used; both of which are undesirable.
+// A secondary fast path is used for tiny objects (size <= 128), in order to
+// consider categories from 256 to 2048 bytes for them.
+// Note that this class uses a precise GetPageForSize (inherited from
+// FreeListMany), which makes its fast path less fast in the Scavenger. This is
+// done on purpose, since this class's only purpose is to be used by
+// FreeListManyCachedOrigin, which is precise for the scavenger.
+class V8_EXPORT_PRIVATE FreeListManyCachedFastPath : public FreeListManyCached {
+ public:
+ V8_WARN_UNUSED_RESULT FreeSpace Allocate(size_t size_in_bytes,
+ size_t* node_size,
+ AllocationOrigin origin) override;
+
+ protected:
+ // Objects in the 18th category are at least 2048 bytes
+ static const FreeListCategoryType kFastPathFirstCategory = 18;
+ static const size_t kFastPathStart = 2048;
+ static const size_t kTinyObjectMaxSize = 128;
+ static const size_t kFastPathOffset = kFastPathStart - kTinyObjectMaxSize;
+ // Objects in the 15th category are at least 256 bytes
+ static const FreeListCategoryType kFastPathFallBackTiny = 15;
+
+ STATIC_ASSERT(categories_min[kFastPathFirstCategory] == kFastPathStart);
+ STATIC_ASSERT(categories_min[kFastPathFallBackTiny] ==
+ kTinyObjectMaxSize * 2);
+
+ FreeListCategoryType SelectFastAllocationFreeListCategoryType(
+ size_t size_in_bytes) {
+ DCHECK(size_in_bytes < kMaxBlockSize);
+
+ if (size_in_bytes >= categories_min[last_category_]) return last_category_;
+
+ size_in_bytes += kFastPathOffset;
+ for (int cat = kFastPathFirstCategory; cat < last_category_; cat++) {
+ if (size_in_bytes <= categories_min[cat]) {
return cat;
}
}
return last_category_;
}
+
+ FRIEND_TEST(
+ SpacesTest,
+ FreeListManyCachedFastPathSelectFastAllocationFreeListCategoryType);
+};
+
+// Uses FreeListManyCached if in the GC; FreeListManyCachedFastPath otherwise.
+// The reasonning behind this FreeList is the following: the GC runs in
+// parallel, and therefore, more expensive allocations there are less
+// noticeable. On the other hand, the generated code and runtime need to be very
+// fast. Therefore, the strategy for the former is one that is not very
+// efficient, but reduces fragmentation (FreeListManyCached), while the strategy
+// for the later is one that is very efficient, but introduces some
+// fragmentation (FreeListManyCachedFastPath).
+class V8_EXPORT_PRIVATE FreeListManyCachedOrigin
+ : public FreeListManyCachedFastPath {
+ public:
+ V8_WARN_UNUSED_RESULT FreeSpace Allocate(size_t size_in_bytes,
+ size_t* node_size,
+ AllocationOrigin origin) override;
+};
+
+// FreeList for maps: since maps are all the same size, uses a single freelist.
+class V8_EXPORT_PRIVATE FreeListMap : public FreeList {
+ public:
+ size_t GuaranteedAllocatable(size_t maximum_freed) override;
+
+ Page* GetPageForSize(size_t size_in_bytes) override;
+
+ FreeListMap();
+ ~FreeListMap();
+
+ V8_WARN_UNUSED_RESULT FreeSpace Allocate(size_t size_in_bytes,
+ size_t* node_size,
+ AllocationOrigin origin) override;
+
+ private:
+ static const size_t kMinBlockSize = Map::kSize;
+ static const size_t kMaxBlockSize = Page::kPageSize;
+ static const FreeListCategoryType kOnlyCategory = 0;
+
+ FreeListCategoryType SelectFreeListCategoryType(
+ size_t size_in_bytes) override {
+ return kOnlyCategory;
+ }
};
// LocalAllocationBuffer represents a linear allocation area that is created
@@ -2108,6 +2246,10 @@ class SpaceWithLinearArea : public Space {
V8_EXPORT_PRIVATE virtual void UpdateInlineAllocationLimit(
size_t min_size) = 0;
+ V8_EXPORT_PRIVATE void UpdateAllocationOrigins(AllocationOrigin origin);
+
+ void PrintAllocationsOrigins();
+
protected:
// If we are doing inline allocation in steps, this method performs the 'step'
// operation. top is the memory address of the bump pointer at the last
@@ -2125,6 +2267,9 @@ class SpaceWithLinearArea : public Space {
// TODO(ofrobots): make these private after refactoring is complete.
LinearAllocationArea allocation_info_;
Address top_on_previous_step_;
+
+ size_t allocations_origins_[static_cast<int>(
+ AllocationOrigin::kNumberOfAllocationOrigins)] = {0};
};
class V8_EXPORT_PRIVATE PagedSpace
@@ -2190,17 +2335,19 @@ class V8_EXPORT_PRIVATE PagedSpace
// Allocate the requested number of bytes in the space if possible, return a
// failure object if not.
V8_WARN_UNUSED_RESULT inline AllocationResult AllocateRawUnaligned(
- int size_in_bytes);
+ int size_in_bytes, AllocationOrigin origin = AllocationOrigin::kRuntime);
// Allocate the requested number of bytes in the space double aligned if
// possible, return a failure object if not.
V8_WARN_UNUSED_RESULT inline AllocationResult AllocateRawAligned(
- int size_in_bytes, AllocationAlignment alignment);
+ int size_in_bytes, AllocationAlignment alignment,
+ AllocationOrigin origin = AllocationOrigin::kRuntime);
// Allocate the requested number of bytes in the space and consider allocation
// alignment if needed.
V8_WARN_UNUSED_RESULT inline AllocationResult AllocateRaw(
- int size_in_bytes, AllocationAlignment alignment);
+ int size_in_bytes, AllocationAlignment alignment,
+ AllocationOrigin origin = AllocationOrigin::kRuntime);
size_t Free(Address start, size_t size_in_bytes, SpaceAccountingMode mode) {
if (size_in_bytes == 0) return 0;
@@ -2373,7 +2520,8 @@ class V8_EXPORT_PRIVATE PagedSpace
// Sets up a linear allocation area that fits the given number of bytes.
// Returns false if there is not enough space and the caller has to retry
// after collecting garbage.
- inline bool EnsureLinearAllocationArea(int size_in_bytes);
+ inline bool EnsureLinearAllocationArea(int size_in_bytes,
+ AllocationOrigin origin);
// Allocates an object from the linear allocation area. Assumes that the
// linear allocation area is large enought to fit the object.
inline HeapObject AllocateLinearly(int size_in_bytes);
@@ -2385,24 +2533,25 @@ class V8_EXPORT_PRIVATE PagedSpace
AllocationAlignment alignment);
V8_WARN_UNUSED_RESULT bool RefillLinearAllocationAreaFromFreeList(
- size_t size_in_bytes);
+ size_t size_in_bytes, AllocationOrigin origin);
// If sweeping is still in progress try to sweep unswept pages. If that is
// not successful, wait for the sweeper threads and retry free-list
// allocation. Returns false if there is not enough space and the caller
// has to retry after collecting garbage.
- V8_WARN_UNUSED_RESULT virtual bool SweepAndRetryAllocation(int size_in_bytes);
+ V8_WARN_UNUSED_RESULT virtual bool SweepAndRetryAllocation(
+ int size_in_bytes, AllocationOrigin origin);
// Slow path of AllocateRaw. This function is space-dependent. Returns false
// if there is not enough space and the caller has to retry after
// collecting garbage.
V8_WARN_UNUSED_RESULT virtual bool SlowRefillLinearAllocationArea(
- int size_in_bytes);
+ int size_in_bytes, AllocationOrigin origin);
// Implementation of SlowAllocateRaw. Returns false if there is not enough
// space and the caller has to retry after collecting garbage.
V8_WARN_UNUSED_RESULT bool RawSlowRefillLinearAllocationArea(
- int size_in_bytes);
+ int size_in_bytes, AllocationOrigin origin);
Executability executable_;
@@ -2773,16 +2922,19 @@ class V8_EXPORT_PRIVATE NewSpace
void set_age_mark(Address mark) { to_space_.set_age_mark(mark); }
V8_WARN_UNUSED_RESULT V8_INLINE AllocationResult
- AllocateRawAligned(int size_in_bytes, AllocationAlignment alignment);
+ AllocateRawAligned(int size_in_bytes, AllocationAlignment alignment,
+ AllocationOrigin origin = AllocationOrigin::kRuntime);
- V8_WARN_UNUSED_RESULT V8_INLINE AllocationResult
- AllocateRawUnaligned(int size_in_bytes);
+ V8_WARN_UNUSED_RESULT V8_INLINE AllocationResult AllocateRawUnaligned(
+ int size_in_bytes, AllocationOrigin origin = AllocationOrigin::kRuntime);
V8_WARN_UNUSED_RESULT V8_INLINE AllocationResult
- AllocateRaw(int size_in_bytes, AllocationAlignment alignment);
+ AllocateRaw(int size_in_bytes, AllocationAlignment alignment,
+ AllocationOrigin origin = AllocationOrigin::kRuntime);
V8_WARN_UNUSED_RESULT inline AllocationResult AllocateRawSynchronized(
- int size_in_bytes, AllocationAlignment alignment);
+ int size_in_bytes, AllocationAlignment alignment,
+ AllocationOrigin origin = AllocationOrigin::kRuntime);
// Reset the allocation pointer to the beginning of the active semispace.
void ResetLinearAllocationArea();
@@ -2888,10 +3040,10 @@ class V8_EXPORT_PRIVATE CompactionSpace : public PagedSpace {
bool snapshotable() override { return false; }
V8_WARN_UNUSED_RESULT bool SweepAndRetryAllocation(
- int size_in_bytes) override;
+ int size_in_bytes, AllocationOrigin origin) override;
V8_WARN_UNUSED_RESULT bool SlowRefillLinearAllocationArea(
- int size_in_bytes) override;
+ int size_in_bytes, AllocationOrigin origin) override;
};
// A collection of |CompactionSpace|s used by a single compaction task.
@@ -2961,8 +3113,7 @@ class MapSpace : public PagedSpace {
public:
// Creates a map space object.
explicit MapSpace(Heap* heap)
- : PagedSpace(heap, MAP_SPACE, NOT_EXECUTABLE,
- FreeList::CreateFreeList()) {}
+ : PagedSpace(heap, MAP_SPACE, NOT_EXECUTABLE, new FreeListMap()) {}
int RoundSizeDownToObjectAlignment(int size) override {
if (base::bits::IsPowerOfTwo(Map::kSize)) {
@@ -2972,6 +3123,8 @@ class MapSpace : public PagedSpace {
}
}
+ void SortFreeList();
+
#ifdef VERIFY_HEAP
void VerifyObject(HeapObject obj) override;
#endif
@@ -3006,6 +3159,8 @@ class ReadOnlySpace : public PagedSpace {
// to write it into the free list nodes that were already created.
void RepairFreeListsAfterDeserialization();
+ size_t Available() override { return 0; }
+
private:
// Unseal the space after is has been sealed, by making it writable.
// TODO(v8:7464): Only possible if the space hasn't been detached.
diff --git a/deps/v8/src/heap/store-buffer-inl.h b/deps/v8/src/heap/store-buffer-inl.h
index 4609c83ca0..b43098bf57 100644
--- a/deps/v8/src/heap/store-buffer-inl.h
+++ b/deps/v8/src/heap/store-buffer-inl.h
@@ -12,16 +12,6 @@
namespace v8 {
namespace internal {
-void StoreBuffer::InsertDeletionIntoStoreBuffer(Address start, Address end) {
- if (top_ + sizeof(Address) * 2 > limit_[current_]) {
- StoreBufferOverflow(heap_->isolate());
- }
- *top_ = MarkDeletionAddress(start);
- top_++;
- *top_ = end;
- top_++;
-}
-
void StoreBuffer::InsertIntoStoreBuffer(Address slot) {
if (top_ + sizeof(Address) > limit_[current_]) {
StoreBufferOverflow(heap_->isolate());
diff --git a/deps/v8/src/heap/store-buffer.cc b/deps/v8/src/heap/store-buffer.cc
index 7d0dcfc370..349e787740 100644
--- a/deps/v8/src/heap/store-buffer.cc
+++ b/deps/v8/src/heap/store-buffer.cc
@@ -28,7 +28,6 @@ StoreBuffer::StoreBuffer(Heap* heap)
}
task_running_ = false;
insertion_callback = &InsertDuringRuntime;
- deletion_callback = &DeleteDuringRuntime;
}
void StoreBuffer::SetUp() {
@@ -91,22 +90,11 @@ void StoreBuffer::TearDown() {
}
}
-void StoreBuffer::DeleteDuringRuntime(StoreBuffer* store_buffer, Address start,
- Address end) {
- DCHECK(store_buffer->mode() == StoreBuffer::NOT_IN_GC);
- store_buffer->InsertDeletionIntoStoreBuffer(start, end);
-}
-
void StoreBuffer::InsertDuringRuntime(StoreBuffer* store_buffer, Address slot) {
DCHECK(store_buffer->mode() == StoreBuffer::NOT_IN_GC);
store_buffer->InsertIntoStoreBuffer(slot);
}
-void StoreBuffer::DeleteDuringGarbageCollection(StoreBuffer* store_buffer,
- Address start, Address end) {
- UNREACHABLE();
-}
-
void StoreBuffer::InsertDuringGarbageCollection(StoreBuffer* store_buffer,
Address slot) {
DCHECK(store_buffer->mode() != StoreBuffer::NOT_IN_GC);
@@ -117,10 +105,8 @@ void StoreBuffer::SetMode(StoreBufferMode mode) {
mode_ = mode;
if (mode == NOT_IN_GC) {
insertion_callback = &InsertDuringRuntime;
- deletion_callback = &DeleteDuringRuntime;
} else {
insertion_callback = &InsertDuringGarbageCollection;
- deletion_callback = &DeleteDuringGarbageCollection;
}
}
@@ -160,24 +146,9 @@ void StoreBuffer::MoveEntriesToRememberedSet(int index) {
MemoryChunk::BaseAddress(addr) != chunk->address()) {
chunk = MemoryChunk::FromAnyPointerAddress(addr);
}
- if (IsDeletionAddress(addr)) {
- last_inserted_addr = kNullAddress;
- current++;
- Address end = *current;
- DCHECK(!IsDeletionAddress(end));
- addr = UnmarkDeletionAddress(addr);
- if (end) {
- RememberedSet<OLD_TO_NEW>::RemoveRange(chunk, addr, end,
- SlotSet::PREFREE_EMPTY_BUCKETS);
- } else {
- RememberedSet<OLD_TO_NEW>::Remove(chunk, addr);
- }
- } else {
- DCHECK(!IsDeletionAddress(addr));
- if (addr != last_inserted_addr) {
- RememberedSet<OLD_TO_NEW>::Insert(chunk, addr);
- last_inserted_addr = addr;
- }
+ if (addr != last_inserted_addr) {
+ RememberedSet<OLD_TO_NEW>::Insert(chunk, addr);
+ last_inserted_addr = addr;
}
}
lazy_top_[index] = nullptr;
diff --git a/deps/v8/src/heap/store-buffer.h b/deps/v8/src/heap/store-buffer.h
index 62b10b9071..025bb6a060 100644
--- a/deps/v8/src/heap/store-buffer.h
+++ b/deps/v8/src/heap/store-buffer.h
@@ -33,17 +33,11 @@ class StoreBuffer {
Max(static_cast<int>(kMinExpectedOSPageSize / kStoreBuffers),
1 << (11 + kSystemPointerSizeLog2));
static const int kStoreBufferMask = kStoreBufferSize - 1;
- static const intptr_t kDeletionTag = 1;
V8_EXPORT_PRIVATE static int StoreBufferOverflow(Isolate* isolate);
- static void DeleteDuringGarbageCollection(StoreBuffer* store_buffer,
- Address start, Address end);
static void InsertDuringGarbageCollection(StoreBuffer* store_buffer,
Address slot);
-
- static void DeleteDuringRuntime(StoreBuffer* store_buffer, Address start,
- Address end);
static void InsertDuringRuntime(StoreBuffer* store_buffer, Address slot);
explicit StoreBuffer(Heap* heap);
@@ -61,19 +55,6 @@ class StoreBuffer {
// the remembered set.
void MoveAllEntriesToRememberedSet();
- inline bool IsDeletionAddress(Address address) const {
- return address & kDeletionTag;
- }
-
- inline Address MarkDeletionAddress(Address address) {
- return address | kDeletionTag;
- }
-
- inline Address UnmarkDeletionAddress(Address address) {
- return address & ~kDeletionTag;
- }
-
- inline void InsertDeletionIntoStoreBuffer(Address start, Address end);
inline void InsertIntoStoreBuffer(Address slot);
void InsertEntry(Address slot) {
@@ -83,16 +64,6 @@ class StoreBuffer {
insertion_callback(this, slot);
}
- // If we only want to delete a single slot, end should be set to null which
- // will be written into the second field. When processing the store buffer
- // the more efficient Remove method will be called in this case.
- void DeleteEntry(Address start, Address end = kNullAddress) {
- // Deletions coming from the GC are directly deleted from the remembered
- // set. Deletions coming from the runtime are added to the store buffer
- // to allow concurrent processing.
- deletion_callback(this, start, end);
- }
-
void SetMode(StoreBufferMode mode);
// Used by the concurrent processing thread to transfer entries from the
@@ -174,7 +145,6 @@ class StoreBuffer {
// Callbacks are more efficient than reading out the gc state for every
// store buffer operation.
void (*insertion_callback)(StoreBuffer*, Address);
- void (*deletion_callback)(StoreBuffer*, Address, Address);
};
} // namespace internal
diff --git a/deps/v8/src/heap/sweeper.cc b/deps/v8/src/heap/sweeper.cc
index cbb7d717b0..c3c6b58835 100644
--- a/deps/v8/src/heap/sweeper.cc
+++ b/deps/v8/src/heap/sweeper.cc
@@ -8,6 +8,7 @@
#include "src/execution/vm-state-inl.h"
#include "src/heap/array-buffer-tracker-inl.h"
#include "src/heap/gc-tracer.h"
+#include "src/heap/invalidated-slots-inl.h"
#include "src/heap/mark-compact-inl.h"
#include "src/heap/remembered-set.h"
#include "src/objects/objects-inl.h"
@@ -154,12 +155,21 @@ void Sweeper::StartSweeping() {
MajorNonAtomicMarkingState* marking_state =
heap_->mark_compact_collector()->non_atomic_marking_state();
ForAllSweepingSpaces([this, marking_state](AllocationSpace space) {
- int space_index = GetSweepSpaceIndex(space);
- std::sort(
- sweeping_list_[space_index].begin(), sweeping_list_[space_index].end(),
- [marking_state](Page* a, Page* b) {
- return marking_state->live_bytes(a) > marking_state->live_bytes(b);
- });
+ // Sorting is done in order to make compaction more efficient: by sweeping
+ // pages with the most free bytes first, we make it more likely that when
+ // evacuating a page, already swept pages will have enough free bytes to
+ // hold the objects to move (and therefore, we won't need to wait for more
+ // pages to be swept in order to move those objects).
+ // Since maps don't move, there is no need to sort the pages from MAP_SPACE
+ // before sweeping them.
+ if (space != MAP_SPACE) {
+ int space_index = GetSweepSpaceIndex(space);
+ std::sort(
+ sweeping_list_[space_index].begin(),
+ sweeping_list_[space_index].end(), [marking_state](Page* a, Page* b) {
+ return marking_state->live_bytes(a) > marking_state->live_bytes(b);
+ });
+ }
});
}
@@ -241,8 +251,10 @@ void Sweeper::EnsureCompleted() {
bool Sweeper::AreSweeperTasksRunning() { return num_sweeping_tasks_ != 0; }
-int Sweeper::RawSweep(Page* p, FreeListRebuildingMode free_list_mode,
- FreeSpaceTreatmentMode free_space_mode) {
+int Sweeper::RawSweep(
+ Page* p, FreeListRebuildingMode free_list_mode,
+ FreeSpaceTreatmentMode free_space_mode,
+ FreeSpaceMayContainInvalidatedSlots invalidated_slots_in_free_space) {
Space* space = p->owner();
DCHECK_NOT_NULL(space);
DCHECK(free_list_mode == IGNORE_FREE_LIST || space->identity() == OLD_SPACE ||
@@ -265,6 +277,15 @@ int Sweeper::RawSweep(Page* p, FreeListRebuildingMode free_list_mode,
ArrayBufferTracker::FreeDead(p, marking_state_);
Address free_start = p->area_start();
+ InvalidatedSlotsCleanup old_to_new_cleanup =
+ InvalidatedSlotsCleanup::NoCleanup(p);
+
+ // Clean invalidated slots during the final atomic pause. After resuming
+ // execution this isn't necessary, invalid old-to-new refs were already
+ // removed by mark compact's update pointers phase.
+ if (invalidated_slots_in_free_space ==
+ FreeSpaceMayContainInvalidatedSlots::kYes)
+ old_to_new_cleanup = InvalidatedSlotsCleanup::OldToNew(p);
intptr_t live_bytes = 0;
intptr_t freed_bytes = 0;
@@ -309,6 +330,8 @@ int Sweeper::RawSweep(Page* p, FreeListRebuildingMode free_list_mode,
static_cast<uint32_t>(free_start - p->address()),
static_cast<uint32_t>(free_end - p->address())));
}
+
+ old_to_new_cleanup.Free(free_start, free_end);
}
Map map = object.synchronized_map();
int size = object.SizeFromMap(map);
@@ -341,6 +364,8 @@ int Sweeper::RawSweep(Page* p, FreeListRebuildingMode free_list_mode,
static_cast<uint32_t>(free_start - p->address()),
static_cast<uint32_t>(p->area_end() - p->address())));
}
+
+ old_to_new_cleanup.Free(free_start, p->area_end());
}
// Clear invalid typed slots after collection all free ranges.
@@ -390,13 +415,15 @@ bool Sweeper::SweepSpaceIncrementallyFromTask(AllocationSpace identity) {
return sweeping_list_[GetSweepSpaceIndex(identity)].empty();
}
-int Sweeper::ParallelSweepSpace(AllocationSpace identity,
- int required_freed_bytes, int max_pages) {
+int Sweeper::ParallelSweepSpace(
+ AllocationSpace identity, int required_freed_bytes, int max_pages,
+ FreeSpaceMayContainInvalidatedSlots invalidated_slots_in_free_space) {
int max_freed = 0;
int pages_freed = 0;
Page* page = nullptr;
while ((page = GetSweepingPageSafe(identity)) != nullptr) {
- int freed = ParallelSweepPage(page, identity);
+ int freed =
+ ParallelSweepPage(page, identity, invalidated_slots_in_free_space);
if (page->IsFlagSet(Page::NEVER_ALLOCATE_ON_PAGE)) {
// Free list of a never-allocate page will be dropped later on.
continue;
@@ -410,7 +437,9 @@ int Sweeper::ParallelSweepSpace(AllocationSpace identity,
return max_freed;
}
-int Sweeper::ParallelSweepPage(Page* page, AllocationSpace identity) {
+int Sweeper::ParallelSweepPage(
+ Page* page, AllocationSpace identity,
+ FreeSpaceMayContainInvalidatedSlots invalidated_slots_in_free_space) {
// Early bailout for pages that are swept outside of the regular sweeping
// path. This check here avoids taking the lock first, avoiding deadlocks.
if (page->SweepingDone()) return 0;
@@ -430,7 +459,8 @@ int Sweeper::ParallelSweepPage(Page* page, AllocationSpace identity) {
page->set_concurrent_sweeping_state(Page::kSweepingInProgress);
const FreeSpaceTreatmentMode free_space_mode =
Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE;
- max_freed = RawSweep(page, REBUILD_FREE_LIST, free_space_mode);
+ max_freed = RawSweep(page, REBUILD_FREE_LIST, free_space_mode,
+ invalidated_slots_in_free_space);
DCHECK(page->SweepingDone());
// After finishing sweeping of a page we clean up its remembered set.
@@ -479,11 +509,14 @@ void Sweeper::AddPage(AllocationSpace space, Page* page,
}
void Sweeper::PrepareToBeSweptPage(AllocationSpace space, Page* page) {
+#ifdef DEBUG
DCHECK_GE(page->area_size(),
static_cast<size_t>(marking_state_->live_bytes(page)));
DCHECK_EQ(Page::kSweepingDone, page->concurrent_sweeping_state());
- page->ForAllFreeListCategories(
- [](FreeListCategory* category) { DCHECK(!category->is_linked()); });
+ page->ForAllFreeListCategories([page](FreeListCategory* category) {
+ DCHECK(!category->is_linked(page->owner()->free_list()));
+ });
+#endif // DEBUG
page->set_concurrent_sweeping_state(Page::kSweepingPending);
heap_->paged_space(space)->IncreaseAllocatedBytes(
marking_state_->live_bytes(page), page);
@@ -586,7 +619,8 @@ void Sweeper::MakeIterable(Page* page) {
DCHECK(IsValidIterabilitySpace(page->owner_identity()));
const FreeSpaceTreatmentMode free_space_mode =
Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE;
- RawSweep(page, IGNORE_FREE_LIST, free_space_mode);
+ RawSweep(page, IGNORE_FREE_LIST, free_space_mode,
+ FreeSpaceMayContainInvalidatedSlots::kNo);
}
} // namespace internal
diff --git a/deps/v8/src/heap/sweeper.h b/deps/v8/src/heap/sweeper.h
index 97de7a028d..f6ecba8450 100644
--- a/deps/v8/src/heap/sweeper.h
+++ b/deps/v8/src/heap/sweeper.h
@@ -70,12 +70,8 @@ class Sweeper {
};
enum FreeListRebuildingMode { REBUILD_FREE_LIST, IGNORE_FREE_LIST };
- enum ClearOldToNewSlotsMode {
- DO_NOT_CLEAR,
- CLEAR_REGULAR_SLOTS,
- CLEAR_TYPED_SLOTS
- };
enum AddPageMode { REGULAR, READD_TEMPORARY_REMOVED_PAGE };
+ enum class FreeSpaceMayContainInvalidatedSlots { kYes, kNo };
Sweeper(Heap* heap, MajorNonAtomicMarkingState* marking_state);
@@ -83,14 +79,21 @@ class Sweeper {
void AddPage(AllocationSpace space, Page* page, AddPageMode mode);
- int ParallelSweepSpace(AllocationSpace identity, int required_freed_bytes,
- int max_pages = 0);
- int ParallelSweepPage(Page* page, AllocationSpace identity);
+ int ParallelSweepSpace(
+ AllocationSpace identity, int required_freed_bytes, int max_pages = 0,
+ FreeSpaceMayContainInvalidatedSlots invalidated_slots_in_free_space =
+ FreeSpaceMayContainInvalidatedSlots::kNo);
+ int ParallelSweepPage(
+ Page* page, AllocationSpace identity,
+ FreeSpaceMayContainInvalidatedSlots invalidated_slots_in_free_space =
+ FreeSpaceMayContainInvalidatedSlots::kNo);
void ScheduleIncrementalSweepingTask();
- int RawSweep(Page* p, FreeListRebuildingMode free_list_mode,
- FreeSpaceTreatmentMode free_space_mode);
+ int RawSweep(
+ Page* p, FreeListRebuildingMode free_list_mode,
+ FreeSpaceTreatmentMode free_space_mode,
+ FreeSpaceMayContainInvalidatedSlots invalidated_slots_in_free_space);
// After calling this function sweeping is considered to be in progress
// and the main thread can sweep lazily, but the background sweeper tasks
diff --git a/deps/v8/src/ic/OWNERS b/deps/v8/src/ic/OWNERS
index 51788b41e4..816ddb52c5 100644
--- a/deps/v8/src/ic/OWNERS
+++ b/deps/v8/src/ic/OWNERS
@@ -3,5 +3,6 @@ ishell@chromium.org
jkummerow@chromium.org
mvstanton@chromium.org
verwaest@chromium.org
+mythria@chromium.org
# COMPONENT: Blink>JavaScript>Runtime
diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc
index 7aebf857a2..f9efcba05f 100644
--- a/deps/v8/src/ic/accessor-assembler.cc
+++ b/deps/v8/src/ic/accessor-assembler.cc
@@ -35,7 +35,7 @@ TNode<MaybeObject> AccessorAssembler::LoadHandlerDataField(
SloppyTNode<DataHandler> handler, int data_index) {
#ifdef DEBUG
TNode<Map> handler_map = LoadMap(handler);
- TNode<Int32T> instance_type = LoadMapInstanceType(handler_map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(handler_map);
#endif
CSA_ASSERT(this,
Word32Or(InstanceTypeEqual(instance_type, LOAD_HANDLER_TYPE),
@@ -78,7 +78,8 @@ TNode<MaybeObject> AccessorAssembler::TryMonomorphicCase(
// Adding |header_size| with a separate IntPtrAdd rather than passing it
// into ElementOffsetFromIndex() allows it to be folded into a single
// [base, index, offset] indirect memory access on x64.
- Node* offset = ElementOffsetFromIndex(slot, HOLEY_ELEMENTS, SMI_PARAMETERS);
+ TNode<IntPtrT> offset =
+ ElementOffsetFromIndex(slot, HOLEY_ELEMENTS, SMI_PARAMETERS);
TNode<MaybeObject> feedback = ReinterpretCast<MaybeObject>(
Load(MachineType::AnyTagged(), vector,
IntPtrAdd(offset, IntPtrConstant(header_size))));
@@ -207,7 +208,7 @@ void AccessorAssembler::HandleLoadAccessor(
CSA_ASSERT(this, IsWeakOrCleared(maybe_context));
CSA_CHECK(this, IsNotCleared(maybe_context));
- TNode<Object> context = GetHeapObjectAssumeWeak(maybe_context);
+ TNode<HeapObject> context = GetHeapObjectAssumeWeak(maybe_context);
TNode<Foreign> foreign = CAST(
LoadObjectField(call_handler_info, CallHandlerInfo::kJsCallbackOffset));
@@ -241,8 +242,9 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
Label* rebox_double,
ExitPoint* exit_point) {
Comment("field_load");
- Node* index = DecodeWord<LoadHandler::FieldIndexBits>(handler_word);
- Node* offset = IntPtrMul(index, IntPtrConstant(kTaggedSize));
+ TNode<IntPtrT> index =
+ Signed(DecodeWord<LoadHandler::FieldIndexBits>(handler_word));
+ TNode<IntPtrT> offset = IntPtrMul(index, IntPtrConstant(kTaggedSize));
Label inobject(this), out_of_object(this);
Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
@@ -259,8 +261,8 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
var_double_value->Bind(
LoadObjectField(holder, offset, MachineType::Float64()));
} else {
- Node* mutable_heap_number = LoadObjectField(holder, offset);
- var_double_value->Bind(LoadHeapNumberValue(mutable_heap_number));
+ TNode<HeapNumber> heap_number = CAST(LoadObjectField(holder, offset));
+ var_double_value->Bind(LoadHeapNumberValue(heap_number));
}
Goto(rebox_double);
}
@@ -268,13 +270,13 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
BIND(&out_of_object);
{
Label is_double(this);
- Node* properties = LoadFastProperties(holder);
- Node* value = LoadObjectField(properties, offset);
+ TNode<HeapObject> properties = LoadFastProperties(holder);
+ TNode<Object> value = LoadObjectField(properties, offset);
GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
exit_point->Return(value);
BIND(&is_double);
- var_double_value->Bind(LoadHeapNumberValue(value));
+ var_double_value->Bind(LoadHeapNumberValue(CAST(value)));
Goto(rebox_double);
}
}
@@ -298,9 +300,10 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
VARIABLE(var_double_value, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value);
- TNode<WordT> handler_word = SmiUntag(smi_handler);
+ TNode<IntPtrT> handler_word = SmiUntag(smi_handler);
TNode<IntPtrT> handler_kind =
Signed(DecodeWord<LoadHandler::KindBits>(handler_word));
+
if (support_elements == kSupportElements) {
Label if_element(this), if_indexed_string(this), if_property(this);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kElement)),
@@ -319,10 +322,10 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
BIND(&if_element);
Comment("element_load");
- Node* intptr_index = TryToIntptr(p->name(), miss);
- Node* is_jsarray_condition =
+ TNode<IntPtrT> intptr_index = TryToIntptr(p->name(), miss);
+ TNode<BoolT> is_jsarray_condition =
IsSetWord<LoadHandler::IsJsArrayBits>(handler_word);
- Node* elements_kind =
+ TNode<Uint32T> elements_kind =
DecodeWord32FromWord<LoadHandler::ElementsKindBits>(handler_word);
Label if_hole(this), unimplemented_elements_kind(this),
if_oob(this, Label::kDeferred);
@@ -345,7 +348,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
Label return_undefined(this);
// Check if we're allowed to handle OOB accesses.
- Node* allow_out_of_bounds =
+ TNode<BoolT> allow_out_of_bounds =
IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
GotoIfNot(allow_out_of_bounds, miss);
@@ -385,15 +388,15 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
Label if_oob(this, Label::kDeferred);
Comment("indexed string");
- Node* intptr_index = TryToIntptr(p->name(), miss);
- Node* length = LoadStringLengthAsWord(holder);
+ TNode<IntPtrT> intptr_index = TryToIntptr(p->name(), miss);
+ TNode<IntPtrT> length = LoadStringLengthAsWord(holder);
GotoIf(UintPtrGreaterThanOrEqual(intptr_index, length), &if_oob);
TNode<Int32T> code = StringCharCodeAt(holder, intptr_index);
TNode<String> result = StringFromSingleCharCode(code);
Return(result);
BIND(&if_oob);
- Node* allow_out_of_bounds =
+ TNode<BoolT> allow_out_of_bounds =
IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
GotoIfNot(allow_out_of_bounds, miss);
GotoIf(IsNoElementsProtectorCellInvalid(), miss);
@@ -426,9 +429,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
module_export(this, Label::kDeferred), proxy(this, Label::kDeferred),
native_data_property(this, Label::kDeferred),
api_getter(this, Label::kDeferred);
+
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field);
- GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
+ GotoIf(WordEqual(handler_kind,
+ IntPtrConstant(LoadHandler::kConstantFromPrototype)),
&constant);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
@@ -476,11 +481,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
BIND(&constant);
{
Comment("constant_load");
- TNode<IntPtrT> descriptor =
- Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
- Node* value = LoadDescriptorValue(LoadMap(holder), descriptor);
-
- exit_point->Return(value);
+ exit_point->Return(holder);
}
BIND(&normal);
@@ -497,8 +498,9 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
VARIABLE(var_value, MachineRepresentation::kTagged);
LoadPropertyFromNameDictionary(properties, var_name_index.value(),
&var_details, &var_value);
- Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
- p->context(), p->receiver(), miss);
+ TNode<Object> value =
+ CallGetterIfAccessor(var_value.value(), var_details.value(),
+ p->context(), p->receiver(), miss);
exit_point->Return(value);
}
}
@@ -508,9 +510,10 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
Comment("accessor_load");
TNode<IntPtrT> descriptor =
Signed(DecodeWord<LoadHandler::DescriptorBits>(handler_word));
- Node* accessor_pair = LoadDescriptorValue(LoadMap(holder), descriptor);
- CSA_ASSERT(this, IsAccessorPair(accessor_pair));
- Node* getter = LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
+ TNode<AccessorPair> accessor_pair =
+ CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
+ TNode<Object> getter =
+ LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
CSA_ASSERT(this, Word32BinaryNot(IsTheHole(getter)));
Callable callable = CodeFactory::Call(isolate());
@@ -567,8 +570,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
{
CSA_ASSERT(this, IsPropertyCell(holder));
// Ensure the property cell doesn't contain the hole.
- Node* value = LoadObjectField(holder, PropertyCell::kValueOffset);
- Node* details = LoadAndUntagToWord32ObjectField(
+ TNode<Object> value = LoadObjectField(holder, PropertyCell::kValueOffset);
+ TNode<Int32T> details = LoadAndUntagToWord32ObjectField(
holder, PropertyCell::kPropertyDetailsRawOffset);
GotoIf(IsTheHole(value), miss);
@@ -587,15 +590,15 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
BIND(&module_export);
{
Comment("module export");
- Node* index = DecodeWord<LoadHandler::ExportsIndexBits>(handler_word);
+ TNode<UintPtrT> index =
+ DecodeWord<LoadHandler::ExportsIndexBits>(handler_word);
Node* module =
LoadObjectField(p->receiver(), JSModuleNamespace::kModuleOffset,
MachineType::TaggedPointer());
TNode<ObjectHashTable> exports = CAST(LoadObjectField(
module, Module::kExportsOffset, MachineType::TaggedPointer()));
- Node* cell = LoadFixedArrayElement(exports, index);
+ TNode<Cell> cell = CAST(LoadFixedArrayElement(exports, index));
// The handler is only installed for exports that exist.
- CSA_ASSERT(this, IsCell(cell));
Node* value = LoadCellValue(cell);
Label is_the_hole(this, Label::kDeferred);
GotoIf(IsTheHole(value), &is_the_hole);
@@ -603,7 +606,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
BIND(&is_the_hole);
{
- Node* message = SmiConstant(MessageTemplate::kNotDefined);
+ TNode<Smi> message = SmiConstant(MessageTemplate::kNotDefined);
exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context(),
message, p->name());
}
@@ -622,7 +625,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)),
&return_true);
- GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
+ GotoIf(WordEqual(handler_kind,
+ IntPtrConstant(LoadHandler::kConstantFromPrototype)),
&return_true);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
@@ -686,7 +690,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
{
CSA_ASSERT(this, IsPropertyCell(holder));
// Ensure the property cell doesn't contain the hole.
- Node* value = LoadObjectField(holder, PropertyCell::kValueOffset);
+ TNode<Object> value = LoadObjectField(holder, PropertyCell::kValueOffset);
GotoIf(IsTheHole(value), miss);
exit_point->Return(TrueConstant());
@@ -719,7 +723,7 @@ Node* AccessorAssembler::HandleProtoHandler(
// Check prototype validity cell.
//
{
- Node* maybe_validity_cell =
+ TNode<Object> maybe_validity_cell =
LoadObjectField(handler, ICHandler::kValidityCellOffset);
CheckPrototypeValidityCell(maybe_validity_cell, miss);
}
@@ -728,20 +732,18 @@ Node* AccessorAssembler::HandleProtoHandler(
// Check smi handler bits.
//
{
- Node* smi_or_code_handler =
+ TNode<Object> smi_or_code_handler =
LoadObjectField(handler, ICHandler::kSmiHandlerOffset);
if (on_code_handler) {
Label if_smi_handler(this);
GotoIf(TaggedIsSmi(smi_or_code_handler), &if_smi_handler);
- CSA_ASSERT(this, IsCodeMap(LoadMap(smi_or_code_handler)));
+ CSA_ASSERT(this, IsCodeMap(LoadMap(CAST(smi_or_code_handler))));
on_code_handler(smi_or_code_handler);
BIND(&if_smi_handler);
- } else {
- CSA_ASSERT(this, TaggedIsSmi(smi_or_code_handler));
}
- Node* handler_flags = SmiUntag(smi_or_code_handler);
+ TNode<IntPtrT> handler_flags = SmiUntag(CAST(smi_or_code_handler));
// Lookup on receiver and access checks are not necessary for global ICs
// because in the former case the validity cell check guards modifications
@@ -767,8 +769,8 @@ Node* AccessorAssembler::HandleProtoHandler(
{
TNode<MaybeObject> data2 = LoadHandlerDataField(handler, 2);
CSA_ASSERT(this, IsWeakOrCleared(data2));
- TNode<Object> expected_native_context =
- GetHeapObjectAssumeWeak(data2, miss);
+ TNode<Context> expected_native_context =
+ CAST(GetHeapObjectAssumeWeak(data2, miss));
EmitAccessCheck(expected_native_context, p->context(), p->receiver(),
&done, miss);
}
@@ -824,7 +826,7 @@ void AccessorAssembler::HandleLoadICProtoHandler(
VARIABLE(var_value, MachineRepresentation::kTagged);
LoadPropertyFromNameDictionary(properties, name_index, &var_details,
&var_value);
- Node* value =
+ TNode<Object> value =
CallGetterIfAccessor(var_value.value(), var_details.value(),
p->context(), p->receiver(), miss);
exit_point->Return(value);
@@ -832,21 +834,38 @@ void AccessorAssembler::HandleLoadICProtoHandler(
},
miss, ic_mode);
- TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
+ TNode<MaybeObject> maybe_holder_or_constant =
+ LoadHandlerDataField(handler, 1);
- Label load_from_cached_holder(this), done(this);
+ Label load_from_cached_holder(this), is_smi(this), done(this);
- Branch(IsStrongReferenceTo(maybe_holder, NullConstant()), &done,
+ GotoIf(TaggedIsSmi(maybe_holder_or_constant), &is_smi);
+ Branch(IsStrongReferenceTo(maybe_holder_or_constant, NullConstant()), &done,
&load_from_cached_holder);
- BIND(&load_from_cached_holder);
+ BIND(&is_smi);
{
- // For regular holders, having passed the receiver map check and the
- // validity cell check implies that |holder| is alive. However, for global
- // object receivers, |maybe_holder| may be cleared.
- CSA_ASSERT(this, IsWeakOrCleared(maybe_holder));
- Node* holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
+ CSA_ASSERT(
+ this,
+ WordEqual(
+ Signed(DecodeWord<LoadHandler::KindBits>(SmiUntag(smi_handler))),
+ IntPtrConstant(LoadHandler::kConstantFromPrototype)));
+ if (access_mode == LoadAccessMode::kHas) {
+ exit_point->Return(TrueConstant());
+ } else {
+ exit_point->Return(maybe_holder_or_constant);
+ }
+ }
+ BIND(&load_from_cached_holder);
+ {
+ // For regular holders, having passed the receiver map check and
+ // the validity cell check implies that |holder| is
+ // alive. However, for global object receivers, |maybe_holder| may
+ // be cleared.
+ CSA_ASSERT(this, IsWeakOrCleared(maybe_holder_or_constant));
+ TNode<HeapObject> holder =
+ GetHeapObjectAssumeWeak(maybe_holder_or_constant, miss);
var_holder->Bind(holder);
Goto(&done);
}
@@ -858,22 +877,22 @@ void AccessorAssembler::HandleLoadICProtoHandler(
}
}
-void AccessorAssembler::EmitAccessCheck(Node* expected_native_context,
- Node* context, Node* receiver,
+void AccessorAssembler::EmitAccessCheck(TNode<Context> expected_native_context,
+ TNode<Context> context, Node* receiver,
Label* can_access, Label* miss) {
CSA_ASSERT(this, IsNativeContext(expected_native_context));
- Node* native_context = LoadNativeContext(context);
- GotoIf(WordEqual(expected_native_context, native_context), can_access);
+ TNode<Context> native_context = LoadNativeContext(context);
+ GotoIf(TaggedEqual(expected_native_context, native_context), can_access);
// If the receiver is not a JSGlobalProxy then we miss.
GotoIfNot(IsJSGlobalProxy(receiver), miss);
// For JSGlobalProxy receiver try to compare security tokens of current
// and expected native contexts.
- Node* expected_token = LoadContextElement(expected_native_context,
- Context::SECURITY_TOKEN_INDEX);
- Node* current_token =
+ TNode<Object> expected_token = LoadContextElement(
+ expected_native_context, Context::SECURITY_TOKEN_INDEX);
+ TNode<Object> current_token =
LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
- Branch(WordEqual(expected_token, current_token), can_access, miss);
+ Branch(TaggedEqual(expected_token, current_token), can_access, miss);
}
void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable,
@@ -886,7 +905,7 @@ void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable,
CSA_ASSERT(this, IsNotSetWord32(details,
PropertyDetails::kAttributesReadOnlyMask));
}
- Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
+ TNode<Uint32T> kind = DecodeWord32<PropertyDetails::KindField>(details);
GotoIf(Word32Equal(kind, Int32Constant(kData)), writable);
// Fall through if it's an accessor property.
}
@@ -896,8 +915,8 @@ void AccessorAssembler::HandleStoreICNativeDataProperty(
Comment("native_data_property_store");
TNode<IntPtrT> descriptor =
Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
- Node* accessor_info = LoadDescriptorValue(LoadMap(holder), descriptor);
- CSA_CHECK(this, IsAccessorInfo(accessor_info));
+ TNode<AccessorInfo> accessor_info =
+ CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
TailCallRuntime(Runtime::kStoreCallbackProperty, p->context(), p->receiver(),
holder, accessor_info, p->name(), p->value());
@@ -917,7 +936,7 @@ void AccessorAssembler::HandleStoreICHandlerCase(
BIND(&if_smi_handler);
{
Node* holder = p->receiver();
- Node* handler_word = SmiUntag(CAST(handler));
+ TNode<IntPtrT> handler_word = SmiUntag(CAST(handler));
Label if_fast_smi(this), if_proxy(this);
@@ -925,7 +944,8 @@ void AccessorAssembler::HandleStoreICHandlerCase(
STATIC_ASSERT(StoreHandler::kNormal + 1 == StoreHandler::kProxy);
STATIC_ASSERT(StoreHandler::kProxy + 1 == StoreHandler::kKindsNumber);
- Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
+ TNode<UintPtrT> handler_kind =
+ DecodeWord<StoreHandler::KindBits>(handler_word);
GotoIf(IntPtrLessThan(handler_kind,
IntPtrConstant(StoreHandler::kGlobalProxy)),
&if_fast_smi);
@@ -941,7 +961,7 @@ void AccessorAssembler::HandleStoreICHandlerCase(
properties, CAST(p->name()), &dictionary_found, &var_name_index, miss);
BIND(&dictionary_found);
{
- Node* details = LoadDetailsByKeyIndex<NameDictionary>(
+ TNode<Uint32T> details = LoadDetailsByKeyIndex<NameDictionary>(
properties, var_name_index.value());
// Check that the property is a writable data property (no accessor).
const int kTypeAndReadOnlyMask = PropertyDetails::KindField::kMask |
@@ -956,7 +976,8 @@ void AccessorAssembler::HandleStoreICHandlerCase(
BIND(&if_fast_smi);
{
- Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
+ TNode<UintPtrT> handler_kind =
+ DecodeWord<StoreHandler::KindBits>(handler_word);
Label data(this), accessor(this), native_data_property(this);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)),
@@ -1034,7 +1055,7 @@ void AccessorAssembler::HandleStoreICTransitionMapHandlerCase(
StoreTransitionMapFlags flags) {
DCHECK_EQ(0, flags & ~kStoreTransitionMapFlagsMask);
if (flags & kCheckPrototypeValidity) {
- Node* maybe_validity_cell =
+ TNode<Object> maybe_validity_cell =
LoadObjectField(transition_map, Map::kPrototypeValidityCellOffset);
CheckPrototypeValidityCell(maybe_validity_cell, miss);
}
@@ -1044,21 +1065,22 @@ void AccessorAssembler::HandleStoreICTransitionMapHandlerCase(
GotoIf(IsSetWord32<Map::IsDeprecatedBit>(bitfield3), miss);
// Load last descriptor details.
- Node* nof = DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3);
+ TNode<UintPtrT> nof =
+ DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3);
CSA_ASSERT(this, WordNotEqual(nof, IntPtrConstant(0)));
TNode<DescriptorArray> descriptors = LoadMapDescriptors(transition_map);
- Node* factor = IntPtrConstant(DescriptorArray::kEntrySize);
+ TNode<IntPtrT> factor = IntPtrConstant(DescriptorArray::kEntrySize);
TNode<IntPtrT> last_key_index = UncheckedCast<IntPtrT>(IntPtrAdd(
IntPtrConstant(DescriptorArray::ToKeyIndex(-1)), IntPtrMul(nof, factor)));
if (flags & kValidateTransitionHandler) {
TNode<Name> key = LoadKeyByKeyIndex(descriptors, last_key_index);
- GotoIf(WordNotEqual(key, p->name()), miss);
+ GotoIf(TaggedNotEqual(key, p->name()), miss);
} else {
- CSA_ASSERT(this, WordEqual(LoadKeyByKeyIndex(descriptors, last_key_index),
- p->name()));
+ CSA_ASSERT(this, TaggedEqual(LoadKeyByKeyIndex(descriptors, last_key_index),
+ p->name()));
}
- Node* details = LoadDetailsByKeyIndex(descriptors, last_key_index);
+ TNode<Uint32T> details = LoadDetailsByKeyIndex(descriptors, last_key_index);
if (flags & kValidateTransitionHandler) {
// Follow transitions only in the following cases:
// 1) name is a non-private symbol and attributes equal to NONE,
@@ -1077,7 +1099,7 @@ void AccessorAssembler::HandleStoreICTransitionMapHandlerCase(
// DontEnum attribute is allowed only for private symbols and vice versa.
Branch(Word32Equal(
IsSetWord32(details, PropertyDetails::kAttributesDontEnumMask),
- IsPrivateSymbol(p->name())),
+ IsPrivateSymbol(CAST(p->name()))),
&attributes_ok, miss);
BIND(&attributes_ok);
@@ -1089,7 +1111,8 @@ void AccessorAssembler::HandleStoreICTransitionMapHandlerCase(
}
void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
- Node* name_index, Node* representation,
+ Node* name_index,
+ TNode<Word32T> representation,
Node* value, Label* bailout) {
Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this);
// Ignore FLAG_track_fields etc. and always emit code for all checks,
@@ -1114,12 +1137,7 @@ void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
BIND(&r_double);
{
GotoIf(TaggedIsSmi(value), &all_fine);
- Node* value_map = LoadMap(value);
- // While supporting mutable HeapNumbers would be straightforward, such
- // objects should not end up here anyway.
- CSA_ASSERT(this, WordNotEqual(value_map,
- LoadRoot(RootIndex::kMutableHeapNumberMap)));
- Branch(IsHeapNumberMap(value_map), &all_fine, bailout);
+ Branch(IsHeapNumber(value), &all_fine, bailout);
}
BIND(&r_heapobject);
@@ -1144,7 +1162,7 @@ void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
TNode<Map> field_type_map =
CAST(GetHeapObjectAssumeWeak(field_type, bailout));
// FieldType::Class(...) performs a map check.
- Branch(WordEqual(LoadMap(value), field_type_map), &all_fine, bailout);
+ Branch(TaggedEqual(LoadMap(value), field_type_map), &all_fine, bailout);
}
BIND(&all_fine);
@@ -1157,8 +1175,8 @@ TNode<BoolT> AccessorAssembler::IsPropertyDetailsConst(Node* details) {
void AccessorAssembler::OverwriteExistingFastDataProperty(
Node* object, Node* object_map, Node* descriptors,
- Node* descriptor_name_index, Node* details, Node* value, Label* slow,
- bool do_transitioning_store) {
+ Node* descriptor_name_index, Node* details, TNode<Object> value,
+ Label* slow, bool do_transitioning_store) {
Label done(this), if_field(this), if_descriptor(this);
CSA_ASSERT(this,
@@ -1171,17 +1189,19 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
BIND(&if_field);
{
- Node* representation =
+ TNode<Uint32T> representation =
DecodeWord32<PropertyDetails::RepresentationField>(details);
CheckFieldType(CAST(descriptors), descriptor_name_index, representation,
value, slow);
- Node* field_index =
+ TNode<UintPtrT> field_index =
DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
- field_index = IntPtrAdd(field_index,
- LoadMapInobjectPropertiesStartInWords(object_map));
- Node* instance_size_in_words = LoadMapInstanceSizeInWords(object_map);
+ field_index = Unsigned(
+ IntPtrAdd(field_index,
+ Unsigned(LoadMapInobjectPropertiesStartInWords(object_map))));
+ TNode<IntPtrT> instance_size_in_words =
+ LoadMapInstanceSizeInWords(object_map);
Label inobject(this), backing_store(this);
Branch(UintPtrLessThan(field_index, instance_size_in_words), &inobject,
@@ -1212,19 +1232,19 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
MachineRepresentation::kFloat64);
} else {
if (do_transitioning_store) {
- Node* mutable_heap_number =
- AllocateMutableHeapNumberWithValue(double_value);
+ TNode<HeapNumber> heap_number =
+ AllocateHeapNumberWithValue(double_value);
StoreMap(object, object_map);
- StoreObjectField(object, field_offset, mutable_heap_number);
+ StoreObjectField(object, field_offset, heap_number);
} else {
- Node* mutable_heap_number = LoadObjectField(object, field_offset);
+ TNode<HeapNumber> heap_number =
+ CAST(LoadObjectField(object, field_offset));
Label if_mutable(this);
GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
- TNode<Float64T> current_value =
- LoadHeapNumberValue(mutable_heap_number);
+ TNode<Float64T> current_value = LoadHeapNumberValue(heap_number);
BranchIfSameNumberValue(current_value, double_value, &done, slow);
BIND(&if_mutable);
- StoreHeapNumberValue(mutable_heap_number, double_value);
+ StoreHeapNumberValue(heap_number, double_value);
}
}
Goto(&done);
@@ -1250,8 +1270,8 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
BIND(&backing_store);
{
- Node* backing_store_index =
- IntPtrSub(field_index, instance_size_in_words);
+ TNode<IntPtrT> backing_store_index =
+ Signed(IntPtrSub(field_index, instance_size_in_words));
if (do_transitioning_store) {
// Allocate mutable heap number before extending properties backing
@@ -1264,10 +1284,10 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
Int32Constant(Representation::kDouble)),
&cont);
{
- Node* double_value = ChangeNumberToFloat64(CAST(value));
- Node* mutable_heap_number =
- AllocateMutableHeapNumberWithValue(double_value);
- var_value.Bind(mutable_heap_number);
+ TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value));
+ TNode<HeapNumber> heap_number =
+ AllocateHeapNumberWithValue(double_value);
+ var_value.Bind(heap_number);
Goto(&cont);
}
BIND(&cont);
@@ -1288,18 +1308,17 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
&double_rep, &tagged_rep);
BIND(&double_rep);
{
- Node* mutable_heap_number =
- LoadPropertyArrayElement(properties, backing_store_index);
+ TNode<HeapNumber> heap_number =
+ CAST(LoadPropertyArrayElement(properties, backing_store_index));
TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value));
Label if_mutable(this);
GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
- TNode<Float64T> current_value =
- LoadHeapNumberValue(mutable_heap_number);
+ TNode<Float64T> current_value = LoadHeapNumberValue(heap_number);
BranchIfSameNumberValue(current_value, double_value, &done, slow);
BIND(&if_mutable);
- StoreHeapNumberValue(mutable_heap_number, double_value);
+ StoreHeapNumberValue(heap_number, double_value);
Goto(&done);
}
BIND(&tagged_rep);
@@ -1322,9 +1341,9 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
BIND(&if_descriptor);
{
// Check that constant matches value.
- Node* constant = LoadValueByKeyIndex(
+ TNode<Object> constant = LoadValueByKeyIndex(
CAST(descriptors), UncheckedCast<IntPtrT>(descriptor_name_index));
- GotoIf(WordNotEqual(value, constant), slow);
+ GotoIf(TaggedNotEqual(value, constant), slow);
if (do_transitioning_store) {
StoreMap(object, object_map);
@@ -1334,15 +1353,17 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
BIND(&done);
}
-void AccessorAssembler::CheckPrototypeValidityCell(Node* maybe_validity_cell,
- Label* miss) {
+void AccessorAssembler::CheckPrototypeValidityCell(
+ TNode<Object> maybe_validity_cell, Label* miss) {
Label done(this);
- GotoIf(WordEqual(maybe_validity_cell, SmiConstant(Map::kPrototypeChainValid)),
- &done);
+ GotoIf(
+ TaggedEqual(maybe_validity_cell, SmiConstant(Map::kPrototypeChainValid)),
+ &done);
CSA_ASSERT(this, TaggedIsNotSmi(maybe_validity_cell));
- Node* cell_value = LoadObjectField(maybe_validity_cell, Cell::kValueOffset);
- Branch(WordEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)), &done,
+ TNode<Object> cell_value =
+ LoadObjectField(CAST(maybe_validity_cell), Cell::kValueOffset);
+ Branch(TaggedEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)), &done,
miss);
BIND(&done);
@@ -1353,9 +1374,11 @@ void AccessorAssembler::HandleStoreAccessor(const StoreICParameters* p,
Comment("accessor_store");
TNode<IntPtrT> descriptor =
Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
- Node* accessor_pair = LoadDescriptorValue(LoadMap(holder), descriptor);
+ TNode<HeapObject> accessor_pair =
+ CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
CSA_ASSERT(this, IsAccessorPair(accessor_pair));
- Node* setter = LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
+ TNode<Object> setter =
+ LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
CSA_ASSERT(this, Word32BinaryNot(IsTheHole(setter)));
Callable callable = CodeFactory::Call(isolate());
@@ -1402,7 +1425,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
p, handler, on_code_handler,
// on_found_on_receiver
[=](Node* properties, Node* name_index) {
- Node* details =
+ TNode<Uint32T> details =
LoadDetailsByKeyIndex<NameDictionary>(properties, name_index);
// Check that the property is a writable data property (no accessor).
const int kTypeAndReadOnlyMask =
@@ -1422,15 +1445,16 @@ void AccessorAssembler::HandleStoreICProtoHandler(
if_accessor(this), if_native_data_property(this);
CSA_ASSERT(this, TaggedIsSmi(smi_handler));
- Node* handler_word = SmiUntag(smi_handler);
+ TNode<IntPtrT> handler_word = SmiUntag(smi_handler);
- Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
+ TNode<UintPtrT> handler_kind =
+ DecodeWord<StoreHandler::KindBits>(handler_word);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)),
&if_add_normal);
TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
CSA_ASSERT(this, IsWeakOrCleared(maybe_holder));
- TNode<Object> holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
+ TNode<HeapObject> holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kGlobalProxy)),
&if_store_global_proxy);
@@ -1497,11 +1521,11 @@ void AccessorAssembler::HandleStoreICProtoHandler(
IsCleared(maybe_context), [=] { return SmiConstant(0); },
[=] { return GetHeapObjectAssumeWeak(maybe_context); });
- Node* foreign = LoadObjectField(call_handler_info,
- CallHandlerInfo::kJsCallbackOffset);
+ TNode<Foreign> foreign = CAST(LoadObjectField(
+ call_handler_info, CallHandlerInfo::kJsCallbackOffset));
Node* callback = LoadObjectField(foreign, Foreign::kForeignAddressOffset,
MachineType::Pointer());
- Node* data =
+ TNode<Object> data =
LoadObjectField(call_handler_info, CallHandlerInfo::kDataOffset);
VARIABLE(api_holder, MachineRepresentation::kTagged, p->receiver());
@@ -1560,7 +1584,8 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
TailCallRuntime(Runtime::kSetPropertyWithReceiver, p->context(), proxy,
p->name(), p->value(), p->receiver());
} else {
- Node* name = CallBuiltin(Builtins::kToName, p->context(), p->name());
+ TNode<Object> name =
+ CallBuiltin(Builtins::kToName, p->context(), p->name());
TailCallBuiltin(Builtins::kProxySetProperty, p->context(), proxy, name,
p->value(), p->receiver());
}
@@ -1571,7 +1596,8 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
Label* miss) {
Comment("field store");
#ifdef DEBUG
- Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
+ TNode<UintPtrT> handler_kind =
+ DecodeWord<StoreHandler::KindBits>(handler_word);
CSA_ASSERT(
this,
Word32Or(
@@ -1579,7 +1605,7 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
WordEqual(handler_kind, IntPtrConstant(StoreHandler::kConstField))));
#endif
- Node* field_representation =
+ TNode<UintPtrT> field_representation =
DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word);
Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
@@ -1674,8 +1700,9 @@ Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
GotoIf(TaggedIsSmi(maybe_field_type), &done);
// Check that value type matches the field type.
{
- Node* field_type = GetHeapObjectAssumeWeak(maybe_field_type, bailout);
- Branch(WordEqual(LoadMap(value), field_type), &done, bailout);
+ TNode<HeapObject> field_type =
+ GetHeapObjectAssumeWeak(maybe_field_type, bailout);
+ Branch(TaggedEqual(LoadMap(CAST(value)), field_type), &done, bailout);
}
BIND(&done);
@@ -1700,7 +1727,8 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
VARIABLE(var_encoded_hash, MachineRepresentation::kWord32);
VARIABLE(var_length, ParameterRepresentation(mode));
- Node* properties = LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
+ TNode<Object> properties =
+ LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
var_properties.Bind(properties);
Label if_smi_hash(this), if_property_array(this), extend_store(this);
@@ -1708,8 +1736,8 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
BIND(&if_smi_hash);
{
- Node* hash = SmiToInt32(properties);
- Node* encoded_hash =
+ TNode<Int32T> hash = SmiToInt32(CAST(properties));
+ TNode<Word32T> encoded_hash =
Word32Shl(hash, Int32Constant(PropertyArray::HashField::kShift));
var_encoded_hash.Bind(encoded_hash);
var_length.Bind(IntPtrOrSmiConstant(0, mode));
@@ -1719,11 +1747,11 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
BIND(&if_property_array);
{
- Node* length_and_hash_int32 = LoadAndUntagToWord32ObjectField(
+ TNode<Int32T> length_and_hash_int32 = LoadAndUntagToWord32ObjectField(
var_properties.value(), PropertyArray::kLengthAndHashOffset);
var_encoded_hash.Bind(Word32And(
length_and_hash_int32, Int32Constant(PropertyArray::HashField::kMask)));
- Node* length_intptr = ChangeInt32ToIntPtr(
+ TNode<IntPtrT> length_intptr = ChangeInt32ToIntPtr(
Word32And(length_and_hash_int32,
Int32Constant(PropertyArray::LengthField::kMask)));
Node* length = IntPtrToParameter(length_intptr, mode);
@@ -1771,10 +1799,10 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
// TODO(gsathya): Clean up the type conversions by creating smarter
// helpers that do the correct op based on the mode.
- Node* new_capacity_int32 =
+ TNode<Int32T> new_capacity_int32 =
TruncateIntPtrToInt32(ParameterToIntPtr(new_capacity, mode));
- Node* new_length_and_hash_int32 =
- Word32Or(var_encoded_hash.value(), new_capacity_int32);
+ TNode<Int32T> new_length_and_hash_int32 =
+ Signed(Word32Or(var_encoded_hash.value(), new_capacity_int32));
StoreObjectField(new_properties, PropertyArray::kLengthAndHashOffset,
SmiFromInt32(new_length_and_hash_int32));
StoreObjectField(object, JSObject::kPropertiesOrHashOffset, new_properties);
@@ -1795,7 +1823,8 @@ void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
property_storage = LoadFastProperties(object);
}
- Node* index = DecodeWord<StoreHandler::FieldIndexBits>(handler_word);
+ TNode<UintPtrT> index =
+ DecodeWord<StoreHandler::FieldIndexBits>(handler_word);
TNode<IntPtrT> offset = Signed(TimesTaggedSize(index));
if (representation.IsDouble()) {
if (!FLAG_unbox_double_fields || !is_inobject) {
@@ -1818,8 +1847,9 @@ void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
BranchIfSameNumberValue(current_value, UncheckedCast<Float64T>(value),
&const_checked, bailout);
} else {
- Node* current_value = LoadObjectField(property_storage, offset);
- Branch(WordEqual(current_value, value), &const_checked, bailout);
+ TNode<Object> current_value = LoadObjectField(property_storage, offset);
+ Branch(TaggedEqual(current_value, UncheckedCast<Object>(value)),
+ &const_checked, bailout);
}
}
@@ -1859,42 +1889,44 @@ void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
}
void AccessorAssembler::EmitElementLoad(
- Node* object, Node* elements_kind, SloppyTNode<IntPtrT> intptr_index,
- Node* is_jsarray_condition, Label* if_hole, Label* rebox_double,
- Variable* var_double_value, Label* unimplemented_elements_kind,
- Label* out_of_bounds, Label* miss, ExitPoint* exit_point,
- LoadAccessMode access_mode) {
+ Node* object, TNode<Word32T> elements_kind,
+ SloppyTNode<IntPtrT> intptr_index, Node* is_jsarray_condition,
+ Label* if_hole, Label* rebox_double, Variable* var_double_value,
+ Label* unimplemented_elements_kind, Label* out_of_bounds, Label* miss,
+ ExitPoint* exit_point, LoadAccessMode access_mode) {
Label if_typed_array(this), if_fast(this), if_fast_packed(this),
if_fast_holey(this), if_fast_double(this), if_fast_holey_double(this),
if_nonfast(this), if_dictionary(this);
- Branch(
- Int32GreaterThan(elements_kind, Int32Constant(LAST_FROZEN_ELEMENTS_KIND)),
- &if_nonfast, &if_fast);
+ Branch(Int32GreaterThan(elements_kind,
+ Int32Constant(LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND)),
+ &if_nonfast, &if_fast);
BIND(&if_fast);
{
TNode<FixedArrayBase> elements = LoadJSObjectElements(CAST(object));
EmitFastElementsBoundsCheck(object, elements, intptr_index,
is_jsarray_condition, out_of_bounds);
- int32_t kinds[] = {// Handled by if_fast_packed.
- PACKED_SMI_ELEMENTS, PACKED_ELEMENTS,
- PACKED_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS,
- // Handled by if_fast_holey.
- HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS,
- HOLEY_FROZEN_ELEMENTS, HOLEY_SEALED_ELEMENTS,
- // Handled by if_fast_double.
- PACKED_DOUBLE_ELEMENTS,
- // Handled by if_fast_holey_double.
- HOLEY_DOUBLE_ELEMENTS};
- Label* labels[] = {
- // FAST_{SMI,}_ELEMENTS
- &if_fast_packed, &if_fast_packed, &if_fast_packed, &if_fast_packed,
- // FAST_HOLEY_{SMI,}_ELEMENTS
- &if_fast_holey, &if_fast_holey, &if_fast_holey, &if_fast_holey,
- // PACKED_DOUBLE_ELEMENTS
- &if_fast_double,
- // HOLEY_DOUBLE_ELEMENTS
- &if_fast_holey_double};
+ int32_t kinds[] = {
+ // Handled by if_fast_packed.
+ PACKED_SMI_ELEMENTS, PACKED_ELEMENTS, PACKED_NONEXTENSIBLE_ELEMENTS,
+ PACKED_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS,
+ // Handled by if_fast_holey.
+ HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS, HOLEY_NONEXTENSIBLE_ELEMENTS,
+ HOLEY_FROZEN_ELEMENTS, HOLEY_SEALED_ELEMENTS,
+ // Handled by if_fast_double.
+ PACKED_DOUBLE_ELEMENTS,
+ // Handled by if_fast_holey_double.
+ HOLEY_DOUBLE_ELEMENTS};
+ Label* labels[] = {// FAST_{SMI,}_ELEMENTS
+ &if_fast_packed, &if_fast_packed, &if_fast_packed,
+ &if_fast_packed, &if_fast_packed,
+ // FAST_HOLEY_{SMI,}_ELEMENTS
+ &if_fast_holey, &if_fast_holey, &if_fast_holey,
+ &if_fast_holey, &if_fast_holey,
+ // PACKED_DOUBLE_ELEMENTS
+ &if_fast_double,
+ // HOLEY_DOUBLE_ELEMENTS
+ &if_fast_holey_double};
Switch(elements_kind, unimplemented_elements_kind, kinds, labels,
arraysize(kinds));
@@ -1910,8 +1942,9 @@ void AccessorAssembler::EmitElementLoad(
BIND(&if_fast_holey);
{
Comment("fast holey elements");
- Node* element = UnsafeLoadFixedArrayElement(CAST(elements), intptr_index);
- GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
+ TNode<Object> element =
+ UnsafeLoadFixedArrayElement(CAST(elements), intptr_index);
+ GotoIf(TaggedEqual(element, TheHoleConstant()), if_hole);
exit_point->Return(access_mode == LoadAccessMode::kHas ? TrueConstant()
: element);
}
@@ -1931,9 +1964,9 @@ void AccessorAssembler::EmitElementLoad(
BIND(&if_fast_holey_double);
{
Comment("holey double elements");
- Node* value = LoadFixedDoubleArrayElement(CAST(elements), intptr_index,
- MachineType::Float64(), 0,
- INTPTR_PARAMETERS, if_hole);
+ TNode<Float64T> value = LoadFixedDoubleArrayElement(
+ CAST(elements), intptr_index, MachineType::Float64(), 0,
+ INTPTR_PARAMETERS, if_hole);
if (access_mode == LoadAccessMode::kHas) {
exit_point->Return(TrueConstant());
} else {
@@ -2020,35 +2053,35 @@ void AccessorAssembler::EmitElementLoad(
BIND(&uint16_elements);
{
Comment("UINT16_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(1));
+ TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
Node* element = Load(MachineType::Uint16(), backing_store, index);
exit_point->Return(SmiFromInt32(element));
}
BIND(&int16_elements);
{
Comment("INT16_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(1));
+ TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
Node* element = Load(MachineType::Int16(), backing_store, index);
exit_point->Return(SmiFromInt32(element));
}
BIND(&uint32_elements);
{
Comment("UINT32_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(2));
+ TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Uint32(), backing_store, index);
exit_point->Return(ChangeUint32ToTagged(element));
}
BIND(&int32_elements);
{
Comment("INT32_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(2));
+ TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Int32(), backing_store, index);
exit_point->Return(ChangeInt32ToTagged(element));
}
BIND(&float32_elements);
{
Comment("FLOAT32_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(2));
+ TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Float32(), backing_store, index);
var_double_value->Bind(ChangeFloat32ToFloat64(element));
Goto(rebox_double);
@@ -2056,7 +2089,7 @@ void AccessorAssembler::EmitElementLoad(
BIND(&float64_elements);
{
Comment("FLOAT64_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(3));
+ TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(3));
Node* element = Load(MachineType::Float64(), backing_store, index);
var_double_value->Bind(element);
Goto(rebox_double);
@@ -2105,12 +2138,12 @@ void AccessorAssembler::InvalidateValidityCellIfPrototype(Node* map,
BIND(&is_prototype);
{
- Node* maybe_prototype_info =
+ TNode<Object> maybe_prototype_info =
LoadObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
// If there's no prototype info then there's nothing to invalidate.
GotoIf(TaggedIsSmi(maybe_prototype_info), &cont);
- Node* function = ExternalConstant(
+ TNode<ExternalReference> function = ExternalConstant(
ExternalReference::invalidate_prototype_chains_function());
CallCFunction(function, MachineType::AnyTagged(),
std::make_pair(MachineType::AnyTagged(), map));
@@ -2130,8 +2163,9 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
// Receivers requiring non-standard element accesses (interceptors, access
// checks, strings and string wrappers, proxies) are handled in the runtime.
GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &if_custom);
- Node* elements_kind = LoadMapElementsKind(receiver_map);
- Node* is_jsarray_condition = InstanceTypeEqual(instance_type, JS_ARRAY_TYPE);
+ TNode<Int32T> elements_kind = LoadMapElementsKind(receiver_map);
+ TNode<BoolT> is_jsarray_condition =
+ InstanceTypeEqual(instance_type, JS_ARRAY_TYPE);
VARIABLE(var_double_value, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value);
@@ -2192,12 +2226,14 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
VARIABLE(var_details, MachineRepresentation::kWord32);
VARIABLE(var_value, MachineRepresentation::kTagged);
+ TNode<Name> name = CAST(p->name());
+
// Receivers requiring non-standard accesses (interceptors, access
// checks, strings and string wrappers) are handled in the runtime.
GotoIf(IsSpecialReceiverInstanceType(instance_type), &special_receiver);
// Check if the receiver has fast or slow properties.
- Node* bitfield3 = LoadMapBitField3(receiver_map);
+ TNode<Uint32T> bitfield3 = LoadMapBitField3(receiver_map);
GotoIf(IsSetWord32<Map::IsDictionaryMapBit>(bitfield3),
&if_property_dictionary);
@@ -2209,7 +2245,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
TVARIABLE(IntPtrT, var_name_index);
Label* notfound = use_stub_cache == kUseStubCache ? &try_stub_cache
: &lookup_prototype_chain;
- DescriptorLookup(p->name(), descriptors, bitfield3, &if_descriptor_found,
+ DescriptorLookup(name, descriptors, bitfield3, &if_descriptor_found,
&var_name_index, notfound);
BIND(&if_descriptor_found);
@@ -2226,13 +2262,13 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
// When there is no feedback vector don't use stub cache.
GotoIfNot(IsUndefined(p->vector()), &stub_cache);
// Fall back to the slow path for private symbols.
- Branch(IsPrivateSymbol(p->name()), slow, &lookup_prototype_chain);
+ Branch(IsPrivateSymbol(name), slow, &lookup_prototype_chain);
BIND(&stub_cache);
Comment("stub cache probe for fast property load");
TVARIABLE(MaybeObject, var_handler);
Label found_handler(this, &var_handler), stub_cache_miss(this);
- TryProbeStubCache(isolate()->load_stub_cache(), receiver, p->name(),
+ TryProbeStubCache(isolate()->load_stub_cache(), receiver, name,
&found_handler, &var_handler, &stub_cache_miss);
BIND(&found_handler);
{
@@ -2247,7 +2283,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
// chain. If it doesn't, then there's no point in missing.
Comment("KeyedLoadGeneric_miss");
TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context(), p->receiver(),
- p->name(), p->slot(), p->vector());
+ name, p->slot(), p->vector());
}
}
@@ -2260,8 +2296,8 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
TVARIABLE(IntPtrT, var_name_index);
Label dictionary_found(this, &var_name_index);
TNode<NameDictionary> properties = CAST(LoadSlowProperties(receiver));
- NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()),
- &dictionary_found, &var_name_index,
+ NameDictionaryLookup<NameDictionary>(properties, name, &dictionary_found,
+ &var_name_index,
&lookup_prototype_chain);
BIND(&dictionary_found);
{
@@ -2273,8 +2309,8 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
BIND(&if_found_on_receiver);
{
- Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
- p->context(), receiver, slow);
+ TNode<Object> value = CallGetterIfAccessor(
+ var_value.value(), var_details.value(), p->context(), receiver, slow);
IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
Return(value);
}
@@ -2289,7 +2325,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
var_holder_map.Bind(receiver_map);
var_holder_instance_type.Bind(instance_type);
- GotoIf(IsPrivateSymbol(p->name()), &is_private_symbol);
+ GotoIf(IsPrivateSymbol(name), &is_private_symbol);
Goto(&loop);
BIND(&loop);
@@ -2298,16 +2334,16 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
GotoIf(InstanceTypeEqual(var_holder_instance_type.value(),
JS_TYPED_ARRAY_TYPE),
slow);
- Node* proto = LoadMapPrototype(var_holder_map.value());
- GotoIf(WordEqual(proto, NullConstant()), &return_undefined);
- Node* proto_map = LoadMap(proto);
- Node* proto_instance_type = LoadMapInstanceType(proto_map);
+ TNode<HeapObject> proto = LoadMapPrototype(var_holder_map.value());
+ GotoIf(TaggedEqual(proto, NullConstant()), &return_undefined);
+ TNode<Map> proto_map = LoadMap(proto);
+ TNode<Uint16T> proto_instance_type = LoadMapInstanceType(proto_map);
var_holder_map.Bind(proto_map);
var_holder_instance_type.Bind(proto_instance_type);
Label next_proto(this), return_value(this, &var_value), goto_slow(this);
TryGetOwnProperty(p->context(), receiver, proto, proto_map,
- proto_instance_type, p->name(), &return_value,
- &var_value, &next_proto, &goto_slow);
+ proto_instance_type, name, &return_value, &var_value,
+ &next_proto, &goto_slow);
// This trampoline and the next are required to appease Turbofan's
// variable merging.
@@ -2323,12 +2359,12 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
BIND(&is_private_symbol);
{
- CSA_ASSERT(this, IsPrivateSymbol(p->name()));
+ CSA_ASSERT(this, IsPrivateSymbol(name));
// For private names that don't exist on the receiver, we bail
// to the runtime to throw. For private symbols, we just return
// undefined.
- Branch(IsPrivateName(p->name()), slow, &return_undefined);
+ Branch(IsPrivateName(CAST(name)), slow, &return_undefined);
}
BIND(&return_undefined);
@@ -2341,11 +2377,11 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
GotoIfNot(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), slow);
// Private field/symbol lookup is not supported.
- GotoIf(IsPrivateSymbol(p->name()), slow);
+ GotoIf(IsPrivateSymbol(name), slow);
direct_exit.ReturnCallStub(
Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
- p->context(), receiver /*holder is the same as receiver*/, p->name(),
+ p->context(), receiver /*holder is the same as receiver*/, name,
receiver, SmiConstant(OnNonExistent::kReturnUndefined));
}
}
@@ -2361,7 +2397,7 @@ Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) {
// See v8::internal::StubCache::PrimaryOffset().
STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift);
// Compute the hash of the name (use entire hash field).
- Node* hash_field = LoadNameHashField(name);
+ TNode<Uint32T> hash_field = LoadNameHashField(name);
CSA_ASSERT(this,
Word32Equal(Word32And(hash_field,
Int32Constant(Name::kHashNotComputedMask)),
@@ -2370,12 +2406,12 @@ Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) {
// Using only the low bits in 64-bit mode is unlikely to increase the
// risk of collision even if the heap is spread over an area larger than
// 4Gb (and not at all if it isn't).
- Node* map_word = BitcastTaggedToWord(map);
+ TNode<IntPtrT> map_word = BitcastTaggedToWord(map);
- Node* map32 = TruncateIntPtrToInt32(UncheckedCast<IntPtrT>(
+ TNode<Int32T> map32 = TruncateIntPtrToInt32(UncheckedCast<IntPtrT>(
WordXor(map_word, WordShr(map_word, StubCache::kMapKeyShift))));
// Base the offset on a simple combination of name and map.
- Node* hash = Int32Add(hash_field, map32);
+ TNode<Word32T> hash = Int32Add(hash_field, map32);
uint32_t mask = (StubCache::kPrimaryTableSize - 1)
<< StubCache::kCacheIndexShift;
return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
@@ -2385,8 +2421,8 @@ Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) {
// See v8::internal::StubCache::SecondaryOffset().
// Use the seed from the primary cache in the secondary cache.
- Node* name32 = TruncateIntPtrToInt32(BitcastTaggedToWord(name));
- Node* hash = Int32Sub(TruncateIntPtrToInt32(seed), name32);
+ TNode<Int32T> name32 = TruncateIntPtrToInt32(BitcastTaggedToWord(name));
+ TNode<Word32T> hash = Int32Sub(TruncateIntPtrToInt32(seed), name32);
hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic));
int32_t mask = (StubCache::kSecondaryTableSize - 1)
<< StubCache::kCacheIndexShift;
@@ -2395,7 +2431,7 @@ Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) {
void AccessorAssembler::TryProbeStubCacheTable(
StubCache* stub_cache, StubCacheTable table_id, Node* entry_offset,
- Node* name, Node* map, Label* if_handler,
+ TNode<Object> name, TNode<Map> map, Label* if_handler,
TVariable<MaybeObject>* var_handler, Label* if_miss) {
StubCache::Table table = static_cast<StubCache::Table>(table_id);
// The {table_offset} holds the entry offset times four (due to masking
@@ -2403,19 +2439,20 @@ void AccessorAssembler::TryProbeStubCacheTable(
const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift;
entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier));
- Node* key_base = ExternalConstant(
+ TNode<ExternalReference> key_base = ExternalConstant(
ExternalReference::Create(stub_cache->key_reference(table)));
// Check that the key in the entry matches the name.
DCHECK_EQ(0, offsetof(StubCache::Entry, key));
- Node* cached_key = Load(MachineType::TaggedPointer(), key_base, entry_offset);
- GotoIf(WordNotEqual(name, cached_key), if_miss);
+ TNode<HeapObject> cached_key =
+ CAST(Load(MachineType::TaggedPointer(), key_base, entry_offset));
+ GotoIf(TaggedNotEqual(name, cached_key), if_miss);
// Check that the map in the entry matches.
- Node* cached_map = Load(
- MachineType::TaggedPointer(), key_base,
+ TNode<Object> cached_map = Load<Object>(
+ key_base,
IntPtrAdd(entry_offset, IntPtrConstant(offsetof(StubCache::Entry, map))));
- GotoIf(WordNotEqual(map, cached_map), if_miss);
+ GotoIf(TaggedNotEqual(map, cached_map), if_miss);
TNode<MaybeObject> handler = ReinterpretCast<MaybeObject>(
Load(MachineType::AnyTagged(), key_base,
@@ -2428,7 +2465,7 @@ void AccessorAssembler::TryProbeStubCacheTable(
}
void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
- Node* name, Label* if_handler,
+ TNode<Object> name, Label* if_handler,
TVariable<MaybeObject>* var_handler,
Label* if_miss) {
Label try_secondary(this), miss(this);
@@ -2439,7 +2476,7 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
// Check that the {receiver} isn't a smi.
GotoIf(TaggedIsSmi(receiver), &miss);
- Node* receiver_map = LoadMap(receiver);
+ TNode<Map> receiver_map = LoadMap(receiver);
// Probe the primary table.
Node* primary_offset = StubCachePrimaryOffset(name, receiver_map);
@@ -2477,7 +2514,7 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred),
no_feedback(this, Label::kDeferred);
- Node* recv_map = LoadReceiverMap(p->receiver());
+ TNode<Map> recv_map = LoadReceiverMap(p->receiver());
GotoIf(IsDeprecatedMap(recv_map), &miss);
GotoIf(IsUndefined(p->vector()), &no_feedback);
@@ -2513,7 +2550,7 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
// Call into the stub that implements the non-inlined parts of LoadIC.
Callable ic =
Builtins::CallableFor(isolate(), Builtins::kLoadIC_Noninlined);
- Node* code_target = HeapConstant(ic.code());
+ TNode<Code> code_target = HeapConstant(ic.code());
exit_point->ReturnCallStub(ic.descriptor(), code_target, p->context(),
p->receiver(), p->name(), p->slot(),
p->vector());
@@ -2524,8 +2561,8 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
Comment("LoadIC_BytecodeHandler_nofeedback");
// Call into the stub that implements the non-inlined parts of LoadIC.
exit_point->ReturnCallStub(
- Builtins::CallableFor(isolate(), Builtins::kLoadIC_Uninitialized),
- p->context(), p->receiver(), p->name(), p->slot(), p->vector());
+ Builtins::CallableFor(isolate(), Builtins::kLoadIC_NoFeedback),
+ p->context(), p->receiver(), p->name(), p->slot());
}
BIND(&miss);
@@ -2547,7 +2584,7 @@ void AccessorAssembler::LoadIC(const LoadICParameters* p) {
Label if_handler(this, &var_handler), non_inlined(this, Label::kDeferred),
try_polymorphic(this), miss(this, Label::kDeferred);
- Node* receiver_map = LoadReceiverMap(p->receiver());
+ TNode<Map> receiver_map = LoadReceiverMap(p->receiver());
GotoIf(IsDeprecatedMap(receiver_map), &miss);
// Check monomorphic case.
@@ -2584,58 +2621,34 @@ void AccessorAssembler::LoadIC(const LoadICParameters* p) {
}
void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
- Node* receiver_map,
+ TNode<Map> receiver_map,
TNode<HeapObject> feedback,
TVariable<MaybeObject>* var_handler,
Label* if_handler, Label* miss,
ExitPoint* exit_point) {
- Label try_uninitialized(this, Label::kDeferred);
-
// Neither deprecated map nor monomorphic. These cases are handled in the
// bytecode handler.
CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map)));
- CSA_ASSERT(this, WordNotEqual(receiver_map, feedback));
+ CSA_ASSERT(this, TaggedNotEqual(receiver_map, feedback));
CSA_ASSERT(this, Word32BinaryNot(IsWeakFixedArrayMap(LoadMap(feedback))));
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
{
// Check megamorphic case.
- GotoIfNot(WordEqual(feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
- &try_uninitialized);
+ GotoIfNot(TaggedEqual(feedback, MegamorphicSymbolConstant()), miss);
TryProbeStubCache(isolate()->load_stub_cache(), p->receiver(), p->name(),
if_handler, var_handler, miss);
}
-
- BIND(&try_uninitialized);
- {
- // Check uninitialized case.
- GotoIfNot(WordEqual(feedback, LoadRoot(RootIndex::kuninitialized_symbol)),
- miss);
- exit_point->ReturnCallStub(
- Builtins::CallableFor(isolate(), Builtins::kLoadIC_Uninitialized),
- p->context(), p->receiver(), p->name(), p->slot(), p->vector());
- }
}
-void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
- Label miss(this, Label::kDeferred),
- check_function_prototype(this);
+void AccessorAssembler::LoadIC_NoFeedback(const LoadICParameters* p) {
+ Label miss(this, Label::kDeferred);
Node* receiver = p->receiver();
GotoIf(TaggedIsSmi(receiver), &miss);
- Node* receiver_map = LoadMap(receiver);
- Node* instance_type = LoadMapInstanceType(receiver_map);
-
- GotoIf(IsUndefined(p->vector()), &check_function_prototype);
- // Optimistically write the state transition to the vector.
- StoreFeedbackVectorSlot(p->vector(), p->slot(),
- LoadRoot(RootIndex::kpremonomorphic_symbol),
- SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
- StoreWeakReferenceInFeedbackVector(p->vector(), p->slot(), receiver_map,
- kTaggedSize, SMI_PARAMETERS);
- Goto(&check_function_prototype);
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
- BIND(&check_function_prototype);
{
// Special case for Function.prototype load, because it's very common
// for ICs that are only executed once (MyFunc.prototype.foo = ...).
@@ -2644,9 +2657,9 @@ void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
&not_function_prototype);
GotoIfNot(IsPrototypeString(p->name()), &not_function_prototype);
- GotoIfPrototypeRequiresRuntimeLookup(CAST(receiver), CAST(receiver_map),
+ GotoIfPrototypeRequiresRuntimeLookup(CAST(receiver), receiver_map,
&not_function_prototype);
- Return(LoadJSFunctionPrototype(receiver, &miss));
+ Return(LoadJSFunctionPrototype(CAST(receiver), &miss));
BIND(&not_function_prototype);
}
@@ -2655,15 +2668,6 @@ void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
BIND(&miss);
{
- Label call_runtime(this, Label::kDeferred);
- GotoIf(IsUndefined(p->vector()), &call_runtime);
- // Undo the optimistic state transition.
- StoreFeedbackVectorSlot(p->vector(), p->slot(),
- LoadRoot(RootIndex::kuninitialized_symbol),
- SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
- Goto(&call_runtime);
-
- BIND(&call_runtime);
TailCallRuntime(Runtime::kLoadIC_Miss, p->context(), p->receiver(),
p->name(), p->slot(), p->vector());
}
@@ -2715,7 +2719,7 @@ void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, try_handler));
TNode<Object> value =
LoadObjectField(property_cell, PropertyCell::kValueOffset);
- GotoIf(WordEqual(value, TheHoleConstant()), miss);
+ GotoIf(TaggedEqual(value, TheHoleConstant()), miss);
exit_point->Return(value);
}
@@ -2746,7 +2750,7 @@ void AccessorAssembler::LoadGlobalIC_TryHandlerCase(
TNode<MaybeObject> feedback_element =
LoadFeedbackVectorSlot(vector, slot, kTaggedSize, slot_mode);
TNode<Object> handler = CAST(feedback_element);
- GotoIf(WordEqual(handler, LoadRoot(RootIndex::kuninitialized_symbol)), miss);
+ GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), miss);
OnNonExistent on_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF
? OnNonExistent::kThrowReferenceError
@@ -2756,7 +2760,8 @@ void AccessorAssembler::LoadGlobalIC_TryHandlerCase(
TNode<Context> native_context = LoadNativeContext(context);
TNode<JSGlobalProxy> receiver =
CAST(LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX));
- Node* holder = LoadContextElement(native_context, Context::EXTENSION_INDEX);
+ TNode<Object> holder =
+ LoadContextElement(native_context, Context::EXTENSION_INDEX);
LazyLoadICParameters p([=] { return context; }, receiver, lazy_name,
ParameterToTagged(slot, slot_mode), vector, holder);
@@ -2772,10 +2777,11 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
TVARIABLE(MaybeObject, var_handler);
Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred),
try_megamorphic(this, Label::kDeferred),
+ try_uninitialized(this, Label::kDeferred),
try_polymorphic_name(this, Label::kDeferred),
miss(this, Label::kDeferred), generic(this, Label::kDeferred);
- Node* receiver_map = LoadReceiverMap(p->receiver());
+ TNode<Map> receiver_map = LoadReceiverMap(p->receiver());
GotoIf(IsDeprecatedMap(receiver_map), &miss);
GotoIf(IsUndefined(p->vector()), &generic);
@@ -2807,8 +2813,8 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
{
// Check megamorphic case.
Comment("KeyedLoadIC_try_megamorphic");
- Branch(WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
- &generic, &try_polymorphic_name);
+ Branch(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()), &generic,
+ &try_uninitialized);
}
BIND(&generic);
@@ -2821,42 +2827,49 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
p->vector());
}
+ BIND(&try_uninitialized);
+ {
+ // Check uninitialized case.
+ Comment("KeyedLoadIC_try_uninitialized");
+ Branch(TaggedEqual(strong_feedback, UninitializedSymbolConstant()), &miss,
+ &try_polymorphic_name);
+ }
+
BIND(&try_polymorphic_name);
{
// We might have a name in feedback, and a weak fixed array in the next
// slot.
- Node* name = p->name();
Comment("KeyedLoadIC_try_polymorphic_name");
- VARIABLE(var_name, MachineRepresentation::kTagged, name);
- VARIABLE(var_index, MachineType::PointerRepresentation());
+ TVARIABLE(Object, var_name, p->name());
+ TVARIABLE(IntPtrT, var_index);
Label if_polymorphic_name(this, &var_name), if_internalized(this),
if_notinternalized(this, Label::kDeferred);
// Fast-case: The recorded {feedback} matches the {name}.
- GotoIf(WordEqual(strong_feedback, name), &if_polymorphic_name);
+ GotoIf(TaggedEqual(strong_feedback, p->name()), &if_polymorphic_name);
// Try to internalize the {name} if it isn't already.
- TryToName(name, &miss, &var_index, &if_internalized, &var_name, &miss,
+ TryToName(p->name(), &miss, &var_index, &if_internalized, &var_name, &miss,
&if_notinternalized);
BIND(&if_internalized);
{
// The {var_name} now contains a unique name.
- Branch(WordEqual(strong_feedback, var_name.value()), &if_polymorphic_name,
- &miss);
+ Branch(TaggedEqual(strong_feedback, var_name.value()),
+ &if_polymorphic_name, &miss);
}
BIND(&if_notinternalized);
{
// Try to internalize the {name}.
- Node* function = ExternalConstant(
+ TNode<ExternalReference> function = ExternalConstant(
ExternalReference::try_internalize_string_function());
- Node* const isolate_ptr =
+ TNode<ExternalReference> const isolate_ptr =
ExternalConstant(ExternalReference::isolate_address(isolate()));
- var_name.Bind(
+ var_name = CAST(
CallCFunction(function, MachineType::AnyTagged(),
std::make_pair(MachineType::Pointer(), isolate_ptr),
- std::make_pair(MachineType::AnyTagged(), name)));
+ std::make_pair(MachineType::AnyTagged(), p->name())));
Goto(&if_internalized);
}
@@ -2864,11 +2877,10 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
{
// If the name comparison succeeded, we know we have a weak fixed array
// with at least one map/handler pair.
- Node* name = var_name.value();
TailCallBuiltin(access_mode == LoadAccessMode::kLoad
? Builtins::kKeyedLoadIC_PolymorphicName
: Builtins::kKeyedHasIC_PolymorphicName,
- p->context(), p->receiver(), name, p->slot(),
+ p->context(), p->receiver(), var_name.value(), p->slot(),
p->vector());
}
}
@@ -2884,8 +2896,8 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
}
void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
- VARIABLE(var_index, MachineType::PointerRepresentation());
- VARIABLE(var_unique, MachineRepresentation::kTagged, p->name());
+ TVARIABLE(IntPtrT, var_index);
+ TVARIABLE(Object, var_unique, p->name());
Label if_index(this), if_unique_name(this), if_notunique(this),
if_other(this, Label::kDeferred), if_runtime(this, Label::kDeferred);
@@ -2898,16 +2910,17 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
BIND(&if_other);
{
- Node* name = CallBuiltin(Builtins::kToName, p->context(), p->name());
- var_unique.Bind(name);
+ TNode<Name> name =
+ CAST(CallBuiltin(Builtins::kToName, p->context(), p->name()));
+ var_unique = name;
TryToName(name, &if_index, &var_index, &if_unique_name, &var_unique,
&if_runtime, &if_notunique);
}
BIND(&if_index);
{
- Node* receiver_map = LoadMap(receiver);
- Node* instance_type = LoadMapInstanceType(receiver_map);
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(),
&if_runtime);
}
@@ -2915,8 +2928,8 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
BIND(&if_unique_name);
{
LoadICParameters pp(p, var_unique.value());
- Node* receiver_map = LoadMap(receiver);
- Node* instance_type = LoadMapInstanceType(receiver_map);
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
GenericPropertyLoad(receiver, receiver_map, instance_type, &pp,
&if_runtime);
}
@@ -2941,8 +2954,8 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
// with this have shown that it causes too much traffic on the stub
// cache. We may want to re-evaluate that in the future.
LoadICParameters pp(p, var_unique.value());
- Node* receiver_map = LoadMap(receiver);
- Node* instance_type = LoadMapInstanceType(receiver_map);
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
GenericPropertyLoad(receiver, receiver_map, instance_type, &pp,
&if_runtime, kDontUseStubCache);
}
@@ -2967,8 +2980,8 @@ void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p,
Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
Node* receiver = p->receiver();
- Node* receiver_map = LoadReceiverMap(receiver);
- Node* name = p->name();
+ TNode<Map> receiver_map = LoadReceiverMap(receiver);
+ TNode<Name> name = CAST(p->name());
Node* vector = p->vector();
Node* slot = p->slot();
TNode<Context> context = p->context();
@@ -2976,10 +2989,11 @@ void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p,
// When we get here, we know that the {name} matches the recorded
// feedback name in the {vector} and can safely be used for the
// LoadIC handler logic below.
- CSA_ASSERT(this, IsName(name));
CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map)));
- CSA_ASSERT(this, WordEqual(name, CAST(LoadFeedbackVectorSlot(
- vector, slot, 0, SMI_PARAMETERS))));
+ CSA_ASSERT(this,
+ TaggedEqual(
+ name, LoadFeedbackVectorSlot(vector, slot, 0, SMI_PARAMETERS)),
+ name, vector);
// Check if we have a matching handler for the {receiver_map}.
TNode<MaybeObject> feedback_element =
@@ -3014,11 +3028,10 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
Label if_handler(this, &var_handler),
if_handler_from_stub_cache(this, &var_handler, Label::kDeferred),
try_polymorphic(this, Label::kDeferred),
- try_megamorphic(this, Label::kDeferred),
- try_uninitialized(this, Label::kDeferred), miss(this, Label::kDeferred),
+ try_megamorphic(this, Label::kDeferred), miss(this, Label::kDeferred),
no_feedback(this, Label::kDeferred);
- Node* receiver_map = LoadReceiverMap(p->receiver());
+ TNode<Map> receiver_map = LoadReceiverMap(p->receiver());
GotoIf(IsDeprecatedMap(receiver_map), &miss);
GotoIf(IsUndefined(p->vector()), &no_feedback);
@@ -3047,26 +3060,16 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
BIND(&try_megamorphic);
{
// Check megamorphic case.
- GotoIfNot(
- WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
- &try_uninitialized);
+ GotoIfNot(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()), &miss);
TryProbeStubCache(isolate()->store_stub_cache(), p->receiver(), p->name(),
&if_handler, &var_handler, &miss);
}
- BIND(&try_uninitialized);
- {
- // Check uninitialized case.
- Branch(
- WordEqual(strong_feedback, LoadRoot(RootIndex::kuninitialized_symbol)),
- &no_feedback, &miss);
- }
BIND(&no_feedback);
{
- TailCallBuiltin(Builtins::kStoreIC_Uninitialized, p->context(),
- p->receiver(), p->name(), p->value(), p->slot(),
- p->vector());
+ TailCallBuiltin(Builtins::kStoreIC_NoFeedback, p->context(), p->receiver(),
+ p->name(), p->value(), p->slot());
}
BIND(&miss);
@@ -3085,9 +3088,11 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
BIND(&if_heapobject);
{
Label try_handler(this), miss(this, Label::kDeferred);
- GotoIf(
- WordEqual(maybe_weak_ref, LoadRoot(RootIndex::kpremonomorphic_symbol)),
- &miss);
+ // We use pre-monomorphic state for global stores that run into
+ // interceptors because the property doesn't exist yet. Using
+ // pre-monomorphic state gives it a chance to find more information the
+ // second time.
+ GotoIf(TaggedEqual(maybe_weak_ref, PremonomorphicSymbolConstant()), &miss);
CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref));
TNode<PropertyCell> property_cell =
@@ -3103,11 +3108,10 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
TNode<MaybeObject> handler = LoadFeedbackVectorSlot(
pp->vector(), pp->slot(), kTaggedSize, SMI_PARAMETERS);
- GotoIf(WordEqual(handler, LoadRoot(RootIndex::kuninitialized_symbol)),
- &miss);
+ GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), &miss);
DCHECK_NULL(pp->receiver());
- Node* native_context = LoadNativeContext(pp->context());
+ TNode<Context> native_context = LoadNativeContext(pp->context());
StoreICParameters p(
pp->context(),
LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX),
@@ -3139,7 +3143,7 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
}
void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
- Node* value,
+ TNode<Object> value,
ExitPoint* exit_point,
Label* miss) {
Comment("StoreGlobalIC_TryPropertyCellCase");
@@ -3148,16 +3152,17 @@ void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
// Load the payload of the global parameter cell. A hole indicates that
// the cell has been invalidated and that the store must be handled by the
// runtime.
- Node* cell_contents =
+ TNode<Object> cell_contents =
LoadObjectField(property_cell, PropertyCell::kValueOffset);
- Node* details = LoadAndUntagToWord32ObjectField(
+ TNode<Int32T> details = LoadAndUntagToWord32ObjectField(
property_cell, PropertyCell::kPropertyDetailsRawOffset);
GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), miss);
CSA_ASSERT(this,
Word32Equal(DecodeWord32<PropertyDetails::KindField>(details),
Int32Constant(kData)));
- Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
+ TNode<Uint32T> type =
+ DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
Label constant(this), store(this), not_smi(this);
@@ -3183,9 +3188,9 @@ void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
BIND(&not_smi);
{
GotoIf(TaggedIsSmi(value), miss);
- Node* expected_map = LoadMap(cell_contents);
- Node* map = LoadMap(value);
- GotoIfNot(WordEqual(expected_map, map), miss);
+ TNode<Map> expected_map = LoadMap(CAST(cell_contents));
+ TNode<Map> map = LoadMap(CAST(value));
+ GotoIfNot(TaggedEqual(expected_map, map), miss);
Goto(&store);
}
@@ -3197,7 +3202,7 @@ void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
BIND(&constant);
{
- GotoIfNot(WordEqual(cell_contents, value), miss);
+ GotoIfNot(TaggedEqual(cell_contents, value), miss);
exit_point->Return(value);
}
}
@@ -3213,7 +3218,7 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
no_feedback(this, Label::kDeferred),
try_polymorphic_name(this, Label::kDeferred);
- Node* receiver_map = LoadReceiverMap(p->receiver());
+ TNode<Map> receiver_map = LoadReceiverMap(p->receiver());
GotoIf(IsDeprecatedMap(receiver_map), &miss);
GotoIf(IsUndefined(p->vector()), &no_feedback);
@@ -3244,9 +3249,8 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
{
// Check megamorphic case.
Comment("KeyedStoreIC_try_megamorphic");
- Branch(
- WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
- &no_feedback, &try_polymorphic_name);
+ Branch(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()),
+ &no_feedback, &try_polymorphic_name);
}
BIND(&no_feedback);
@@ -3259,7 +3263,7 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
{
// We might have a name in feedback, and a fixed array in the next slot.
Comment("KeyedStoreIC_try_polymorphic_name");
- GotoIfNot(WordEqual(strong_feedback, p->name()), &miss);
+ GotoIfNot(TaggedEqual(strong_feedback, p->name()), &miss);
// If the name comparison succeeded, we know we have a feedback vector
// with at least one map/handler pair.
TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(
@@ -3286,7 +3290,7 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
try_polymorphic(this, Label::kDeferred),
try_megamorphic(this, Label::kDeferred);
- Node* array_map = LoadReceiverMap(p->receiver());
+ TNode<Map> array_map = LoadReceiverMap(p->receiver());
GotoIf(IsDeprecatedMap(array_map), &miss);
GotoIf(IsUndefined(p->vector()), &miss);
@@ -3314,8 +3318,8 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
TNode<Map> transition_map =
CAST(GetHeapObjectAssumeWeak(maybe_transition_map, &miss));
GotoIf(IsDeprecatedMap(transition_map), &miss);
- Node* code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
- CSA_ASSERT(this, IsCode(code));
+ TNode<Code> code =
+ CAST(LoadObjectField(handler, StoreHandler::kSmiHandlerOffset));
TailCallStub(StoreTransitionDescriptor{}, code, p->context(),
p->receiver(), p->name(), transition_map, p->value(),
p->slot(), p->vector());
@@ -3335,14 +3339,12 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
BIND(&try_megamorphic);
{
Comment("StoreInArrayLiteralIC_try_megamorphic");
- CSA_ASSERT(this,
- Word32Or(WordEqual(strong_feedback,
- LoadRoot(RootIndex::kuninitialized_symbol)),
- WordEqual(strong_feedback,
- LoadRoot(RootIndex::kmegamorphic_symbol))));
- GotoIfNot(
- WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
- &miss);
+ CSA_ASSERT(
+ this,
+ Word32Or(TaggedEqual(strong_feedback, UninitializedSymbolConstant()),
+ TaggedEqual(strong_feedback, MegamorphicSymbolConstant())));
+ GotoIfNot(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()),
+ &miss);
TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context(),
p->value(), p->receiver(), p->name());
}
@@ -3363,7 +3365,7 @@ void AccessorAssembler::GenerateLoadIC() {
using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3376,7 +3378,7 @@ void AccessorAssembler::GenerateLoadIC_Megamorphic() {
using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3390,7 +3392,7 @@ void AccessorAssembler::GenerateLoadIC_Megamorphic() {
BIND(&if_handler);
LazyLoadICParameters p([=] { return context; }, receiver,
- [=] { return CAST(name); }, slot, vector);
+ [=] { return name; }, slot, vector);
HandleLoadICHandlerCase(&p, CAST(var_handler.value()), &miss, &direct_exit);
BIND(&miss);
@@ -3402,7 +3404,7 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() {
using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3411,7 +3413,7 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() {
TVARIABLE(MaybeObject, var_handler);
Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
- Node* receiver_map = LoadReceiverMap(receiver);
+ TNode<Map> receiver_map = LoadReceiverMap(receiver);
TNode<MaybeObject> feedback_element =
LoadFeedbackVectorSlot(vector, slot, 0, SMI_PARAMETERS);
TNode<HeapObject> feedback = CAST(feedback_element);
@@ -3432,27 +3434,26 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() {
slot, vector);
}
-void AccessorAssembler::GenerateLoadIC_Uninitialized() {
- using Descriptor = LoadWithVectorDescriptor;
+void AccessorAssembler::GenerateLoadIC_NoFeedback() {
+ using Descriptor = LoadDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
- Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- LoadICParameters p(context, receiver, name, slot, vector);
- LoadIC_Uninitialized(&p);
+ LoadICParameters p(context, receiver, name, slot, UndefinedConstant());
+ LoadIC_NoFeedback(&p);
}
void AccessorAssembler::GenerateLoadICTrampoline() {
using Descriptor = LoadDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* vector = LoadFeedbackVectorForStub();
+ TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
TailCallBuiltin(Builtins::kLoadIC, context, receiver, name, slot, vector);
}
@@ -3461,10 +3462,10 @@ void AccessorAssembler::GenerateLoadICTrampoline_Megamorphic() {
using Descriptor = LoadDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* vector = LoadFeedbackVectorForStub();
+ TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
TailCallBuiltin(Builtins::kLoadIC_Megamorphic, context, receiver, name, slot,
vector);
@@ -3473,7 +3474,7 @@ void AccessorAssembler::GenerateLoadICTrampoline_Megamorphic() {
void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
using Descriptor = LoadGlobalWithVectorDescriptor;
- Node* name = Parameter(Descriptor::kName);
+ TNode<Name> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3484,16 +3485,16 @@ void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
// lazy_context
[=] { return context; },
// lazy_name
- [=] { return CAST(name); }, typeof_mode, &direct_exit);
+ [=] { return name; }, typeof_mode, &direct_exit);
}
void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
using Descriptor = LoadGlobalDescriptor;
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* vector = LoadFeedbackVectorForStub();
+ TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
Callable callable =
CodeFactory::LoadGlobalICInOptimizedCode(isolate(), typeof_mode);
@@ -3504,7 +3505,7 @@ void AccessorAssembler::GenerateKeyedLoadIC() {
using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3517,7 +3518,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3530,10 +3531,10 @@ void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
using Descriptor = LoadDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* vector = LoadFeedbackVectorForStub();
+ TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
TailCallBuiltin(Builtins::kKeyedLoadIC, context, receiver, name, slot,
vector);
@@ -3543,10 +3544,10 @@ void AccessorAssembler::GenerateKeyedLoadICTrampoline_Megamorphic() {
using Descriptor = LoadDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* vector = LoadFeedbackVectorForStub();
+ TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
TailCallBuiltin(Builtins::kKeyedLoadIC_Megamorphic, context, receiver, name,
slot, vector);
@@ -3556,7 +3557,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() {
using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3568,7 +3569,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() {
void AccessorAssembler::GenerateStoreGlobalIC() {
using Descriptor = StoreGlobalWithVectorDescriptor;
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
@@ -3581,11 +3582,11 @@ void AccessorAssembler::GenerateStoreGlobalIC() {
void AccessorAssembler::GenerateStoreGlobalICTrampoline() {
using Descriptor = StoreGlobalDescriptor;
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* vector = LoadFeedbackVectorForStub();
+ TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
TailCallBuiltin(Builtins::kStoreGlobalIC, context, name, value, slot, vector);
}
@@ -3594,7 +3595,7 @@ void AccessorAssembler::GenerateStoreIC() {
using Descriptor = StoreWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
@@ -3608,11 +3609,11 @@ void AccessorAssembler::GenerateStoreICTrampoline() {
using Descriptor = StoreDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* vector = LoadFeedbackVectorForStub();
+ TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
TailCallBuiltin(Builtins::kStoreIC, context, receiver, name, value, slot,
vector);
@@ -3622,7 +3623,7 @@ void AccessorAssembler::GenerateKeyedStoreIC() {
using Descriptor = StoreWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
@@ -3636,11 +3637,11 @@ void AccessorAssembler::GenerateKeyedStoreICTrampoline() {
using Descriptor = StoreDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- Node* vector = LoadFeedbackVectorForStub();
+ TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
TailCallBuiltin(Builtins::kKeyedStoreIC, context, receiver, name, value, slot,
vector);
@@ -3650,7 +3651,7 @@ void AccessorAssembler::GenerateStoreInArrayLiteralIC() {
using Descriptor = StoreWithVectorDescriptor;
Node* array = Parameter(Descriptor::kReceiver);
- Node* index = Parameter(Descriptor::kName);
+ TNode<Object> index = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
@@ -3798,8 +3799,8 @@ void AccessorAssembler::GenerateCloneObjectIC() {
TNode<IntPtrT> field_offset_difference =
TimesTaggedSize(IntPtrSub(result_start, source_start));
- // Just copy the fields as raw data (pretending that there are no
- // MutableHeapNumbers). This doesn't need write barriers.
+ // Just copy the fields as raw data (pretending that there are no mutable
+ // HeapNumbers). This doesn't need write barriers.
BuildFastLoop(
source_start, source_size,
[=](Node* field_index) {
@@ -3813,7 +3814,7 @@ void AccessorAssembler::GenerateCloneObjectIC() {
},
1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
- // If MutableHeapNumbers can occur, we need to go through the {object}
+ // If mutable HeapNumbers can occur, we need to go through the {object}
// again here and properly clone them. We use a second loop here to
// ensure that the GC (and heap verifier) always sees properly initialized
// objects, i.e. never hits undefined values in double fields.
@@ -3827,11 +3828,10 @@ void AccessorAssembler::GenerateCloneObjectIC() {
TNode<Object> field = LoadObjectField(object, result_offset);
Label if_done(this), if_mutableheapnumber(this, Label::kDeferred);
GotoIf(TaggedIsSmi(field), &if_done);
- Branch(IsMutableHeapNumber(CAST(field)), &if_mutableheapnumber,
- &if_done);
+ Branch(IsHeapNumber(CAST(field)), &if_mutableheapnumber, &if_done);
BIND(&if_mutableheapnumber);
{
- TNode<Object> value = AllocateMutableHeapNumberWithValue(
+ TNode<HeapNumber> value = AllocateHeapNumberWithValue(
LoadHeapNumberValue(UncheckedCast<HeapNumber>(field)));
StoreObjectField(object, result_offset, value);
Goto(&if_done);
@@ -3856,14 +3856,11 @@ void AccessorAssembler::GenerateCloneObjectIC() {
BIND(&try_megamorphic);
{
Comment("CloneObjectIC_try_megamorphic");
- CSA_ASSERT(this,
- Word32Or(WordEqual(strong_feedback,
- LoadRoot(RootIndex::kuninitialized_symbol)),
- WordEqual(strong_feedback,
- LoadRoot(RootIndex::kmegamorphic_symbol))));
- GotoIfNot(
- WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
- &miss);
+ CSA_ASSERT(
+ this,
+ Word32Or(TaggedEqual(strong_feedback, UninitializedSymbolConstant()),
+ TaggedEqual(strong_feedback, MegamorphicSymbolConstant())));
+ GotoIfNot(TaggedEqual(strong_feedback, MegamorphicSymbolConstant()), &miss);
Goto(&slow);
}
@@ -3876,8 +3873,8 @@ void AccessorAssembler::GenerateCloneObjectIC() {
BIND(&miss);
{
Comment("CloneObjectIC_miss");
- Node* map_or_result = CallRuntime(Runtime::kCloneObjectIC_Miss, context,
- source, flags, slot, vector);
+ TNode<HeapObject> map_or_result = CAST(CallRuntime(
+ Runtime::kCloneObjectIC_Miss, context, source, flags, slot, vector));
var_handler = UncheckedCast<MaybeObject>(map_or_result);
GotoIf(IsMap(map_or_result), &if_handler);
CSA_ASSERT(this, IsJSObject(map_or_result));
@@ -3889,7 +3886,7 @@ void AccessorAssembler::GenerateKeyedHasIC() {
using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3902,7 +3899,7 @@ void AccessorAssembler::GenerateKeyedHasIC_Megamorphic() {
using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// TODO(magardn): implement HasProperty handling in KeyedLoadICGeneric
Return(HasProperty(context, receiver, name,
@@ -3913,7 +3910,7 @@ void AccessorAssembler::GenerateKeyedHasIC_PolymorphicName() {
using Descriptor = LoadWithVectorDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h
index 6127b244e3..0de2292fd6 100644
--- a/deps/v8/src/ic/accessor-assembler.h
+++ b/deps/v8/src/ic/accessor-assembler.h
@@ -30,7 +30,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
void GenerateLoadIC();
void GenerateLoadIC_Megamorphic();
void GenerateLoadIC_Noninlined();
- void GenerateLoadIC_Uninitialized();
+ void GenerateLoadIC_NoFeedback();
void GenerateLoadICTrampoline();
void GenerateLoadICTrampoline_Megamorphic();
void GenerateKeyedLoadIC();
@@ -56,9 +56,9 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
void GenerateStoreInArrayLiteralIC();
- void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
- Label* if_handler, TVariable<MaybeObject>* var_handler,
- Label* if_miss);
+ void TryProbeStubCache(StubCache* stub_cache, Node* receiver,
+ TNode<Object> name, Label* if_handler,
+ TVariable<MaybeObject>* var_handler, Label* if_miss);
Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
return StubCachePrimaryOffset(name, map);
@@ -68,7 +68,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
}
struct LoadICParameters {
- LoadICParameters(TNode<Context> context, Node* receiver, Node* name,
+ LoadICParameters(TNode<Context> context, Node* receiver, TNode<Object> name,
Node* slot, Node* vector, Node* holder = nullptr)
: context_(context),
receiver_(receiver),
@@ -77,7 +77,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
vector_(vector),
holder_(holder ? holder : receiver) {}
- LoadICParameters(const LoadICParameters* p, Node* unique_name)
+ LoadICParameters(const LoadICParameters* p, TNode<Object> unique_name)
: context_(p->context_),
receiver_(p->receiver_),
name_(unique_name),
@@ -87,7 +87,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<Context> context() const { return context_; }
Node* receiver() const { return receiver_; }
- Node* name() const { return name_; }
+ TNode<Object> name() const { return name_; }
Node* slot() const { return slot_; }
Node* vector() const { return vector_; }
Node* holder() const { return holder_; }
@@ -95,7 +95,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
private:
TNode<Context> context_;
Node* receiver_;
- Node* name_;
+ TNode<Object> name_;
Node* slot_;
Node* vector_;
Node* holder_;
@@ -119,13 +119,13 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
holder_(p->holder()) {
TNode<Context> p_context = p->context();
context_ = [=] { return p_context; };
- TNode<Object> p_name = TNode<Object>::UncheckedCast(p->name());
+ TNode<Object> p_name = p->name();
name_ = [=] { return p_name; };
}
TNode<Context> context() const { return context_(); }
Node* receiver() const { return receiver_; }
- Node* name() const { return name_(); }
+ TNode<Object> name() const { return name_(); }
Node* slot() const { return slot_; }
Node* vector() const { return vector_; }
Node* holder() const { return holder_; }
@@ -156,8 +156,9 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
protected:
struct StoreICParameters : public LoadICParameters {
- StoreICParameters(TNode<Context> context, Node* receiver, Node* name,
- SloppyTNode<Object> value, Node* slot, Node* vector)
+ StoreICParameters(TNode<Context> context, Node* receiver,
+ TNode<Object> name, SloppyTNode<Object> value, Node* slot,
+ Node* vector)
: LoadICParameters(context, receiver, name, slot, vector),
value_(value) {}
@@ -191,12 +192,13 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
void OverwriteExistingFastDataProperty(Node* object, Node* object_map,
Node* descriptors,
Node* descriptor_name_index,
- Node* details, Node* value,
+ Node* details, TNode<Object> value,
Label* slow,
bool do_transitioning_store);
void CheckFieldType(TNode<DescriptorArray> descriptors, Node* name_index,
- Node* representation, Node* value, Label* bailout);
+ TNode<Word32T> representation, Node* value,
+ Label* bailout);
private:
// Stub generation entry points.
@@ -204,7 +206,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
// LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains
// logic not inlined into Ignition bytecode handlers.
void LoadIC(const LoadICParameters* p);
- void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map,
+ void LoadIC_Noninlined(const LoadICParameters* p, TNode<Map> receiver_map,
TNode<HeapObject> feedback,
TVariable<MaybeObject>* var_handler, Label* if_handler,
Label* miss, ExitPoint* exit_point);
@@ -214,7 +216,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<MaybeObject> LoadDescriptorValueOrFieldType(
TNode<Map> map, TNode<IntPtrT> descriptor_entry);
- void LoadIC_Uninitialized(const LoadICParameters* p);
+ void LoadIC_NoFeedback(const LoadICParameters* p);
void KeyedLoadIC(const LoadICParameters* p, LoadAccessMode access_mode);
void KeyedLoadICGeneric(const LoadICParameters* p);
@@ -222,7 +224,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
LoadAccessMode access_mode);
void StoreIC(const StoreICParameters* p);
void StoreGlobalIC(const StoreICParameters* p);
- void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
+ void StoreGlobalIC_PropertyCellCase(Node* property_cell, TNode<Object> value,
ExitPoint* exit_point, Label* miss);
void KeyedStoreIC(const StoreICParameters* p);
void StoreInArrayLiteralIC(const StoreICParameters* p);
@@ -275,8 +277,9 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
Variable* var_double_value, Label* rebox_double,
ExitPoint* exit_point);
- void EmitAccessCheck(Node* expected_native_context, Node* context,
- Node* receiver, Label* can_access, Label* miss);
+ void EmitAccessCheck(TNode<Context> expected_native_context,
+ TNode<Context> context, Node* receiver,
+ Label* can_access, Label* miss);
void HandleLoadICSmiHandlerLoadNamedCase(
const LazyLoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind,
@@ -317,7 +320,8 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
Representation representation, Node* value,
Label* miss);
- void CheckPrototypeValidityCell(Node* maybe_validity_cell, Label* miss);
+ void CheckPrototypeValidityCell(TNode<Object> maybe_validity_cell,
+ Label* miss);
void HandleStoreICNativeDataProperty(const StoreICParameters* p, Node* holder,
Node* handler_word);
@@ -366,7 +370,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
void EmitFastElementsBoundsCheck(Node* object, Node* elements,
Node* intptr_index,
Node* is_jsarray_condition, Label* miss);
- void EmitElementLoad(Node* object, Node* elements_kind,
+ void EmitElementLoad(Node* object, TNode<Word32T> elements_kind,
SloppyTNode<IntPtrT> key, Node* is_jsarray_condition,
Label* if_hole, Label* rebox_double,
Variable* var_double_value,
@@ -387,8 +391,8 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
Node* StubCacheSecondaryOffset(Node* name, Node* seed);
void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
- Node* entry_offset, Node* name, Node* map,
- Label* if_handler,
+ Node* entry_offset, TNode<Object> name,
+ TNode<Map> map, Label* if_handler,
TVariable<MaybeObject>* var_handler,
Label* if_miss);
};
diff --git a/deps/v8/src/ic/binary-op-assembler.cc b/deps/v8/src/ic/binary-op-assembler.cc
index 50b7cd1ebb..f6bec6eab9 100644
--- a/deps/v8/src/ic/binary-op-assembler.cc
+++ b/deps/v8/src/ic/binary-op-assembler.cc
@@ -114,8 +114,9 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
BIND(&do_fadd);
{
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
- Node* value = Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value());
- Node* result = AllocateHeapNumberWithValue(value);
+ TNode<Float64T> value =
+ Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value());
+ TNode<HeapNumber> result = AllocateHeapNumberWithValue(value);
var_result.Bind(result);
Goto(&end);
}
@@ -124,8 +125,9 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
{
// No checks on rhs are done yet. We just know lhs is not a number or Smi.
Label if_lhsisoddball(this), if_lhsisnotoddball(this);
- Node* lhs_instance_type = LoadInstanceType(lhs);
- Node* lhs_is_oddball = InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
+ TNode<Uint16T> lhs_instance_type = LoadInstanceType(lhs);
+ TNode<BoolT> lhs_is_oddball =
+ InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball);
BIND(&if_lhsisoddball);
@@ -154,7 +156,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
// Check if the {rhs} is a smi, and exit the string check early if it is.
GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
- Node* rhs_instance_type = LoadInstanceType(rhs);
+ TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs);
// Exit unless {rhs} is a string. Since {lhs} is a string we no longer
// need an Oddball check.
@@ -173,8 +175,9 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
{
// Check if rhs is an oddball. At this point we know lhs is either a
// Smi or number or oddball and rhs is not a number or Smi.
- Node* rhs_instance_type = LoadInstanceType(rhs);
- Node* rhs_is_oddball = InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
+ TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs);
+ TNode<BoolT> rhs_is_oddball =
+ InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
GotoIf(rhs_is_oddball, &call_with_oddball_feedback);
Goto(&call_with_any_feedback);
}
@@ -322,9 +325,10 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
{
// No checks on rhs are done yet. We just know lhs is not a number or Smi.
Label if_left_bigint(this), if_left_oddball(this);
- Node* lhs_instance_type = LoadInstanceType(lhs);
+ TNode<Uint16T> lhs_instance_type = LoadInstanceType(lhs);
GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_left_bigint);
- Node* lhs_is_oddball = InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
+ TNode<BoolT> lhs_is_oddball =
+ InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
Branch(lhs_is_oddball, &if_left_oddball, &call_with_any_feedback);
BIND(&if_left_oddball);
@@ -361,9 +365,10 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
{
// Check if rhs is an oddball. At this point we know lhs is either a
// Smi or number or oddball and rhs is not a number or Smi.
- Node* rhs_instance_type = LoadInstanceType(rhs);
+ TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs);
GotoIf(IsBigIntInstanceType(rhs_instance_type), &if_bigint);
- Node* rhs_is_oddball = InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
+ TNode<BoolT> rhs_is_oddball =
+ InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
GotoIfNot(rhs_is_oddball, &call_with_any_feedback);
var_type_feedback.Bind(
@@ -437,7 +442,7 @@ Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs,
BIND(&if_overflow);
{
var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kNumber));
- Node* value = Float64Sub(SmiToFloat64(lhs), SmiToFloat64(rhs));
+ TNode<Float64T> value = Float64Sub(SmiToFloat64(lhs), SmiToFloat64(rhs));
var_result = AllocateHeapNumberWithValue(value);
Goto(&end);
}
@@ -490,7 +495,7 @@ Node* BinaryOpAssembler::Generate_DivideWithFeedback(
{
var_type_feedback->Bind(
SmiConstant(BinaryOperationFeedback::kSignedSmallInputs));
- Node* value = Float64Div(SmiToFloat64(lhs), SmiToFloat64(rhs));
+ TNode<Float64T> value = Float64Div(SmiToFloat64(lhs), SmiToFloat64(rhs));
var_result.Bind(AllocateHeapNumberWithValue(value));
Goto(&end);
}
@@ -528,7 +533,7 @@ Node* BinaryOpAssembler::Generate_ExponentiateWithFeedback(
Node* context, Node* base, Node* exponent, Node* slot_id,
Node* feedback_vector, bool rhs_is_smi) {
// We currently don't optimize exponentiation based on feedback.
- Node* dummy_feedback = SmiConstant(BinaryOperationFeedback::kAny);
+ TNode<Smi> dummy_feedback = SmiConstant(BinaryOperationFeedback::kAny);
UpdateFeedback(dummy_feedback, feedback_vector, slot_id);
return CallBuiltin(Builtins::kExponentiate, context, base, exponent);
}
diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h
index f5cd0c1de7..c0ff8a4c9b 100644
--- a/deps/v8/src/ic/handler-configuration-inl.h
+++ b/deps/v8/src/ic/handler-configuration-inl.h
@@ -51,8 +51,8 @@ Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) {
return handle(Smi::FromInt(config), isolate);
}
-Handle<Smi> LoadHandler::LoadConstant(Isolate* isolate, int descriptor) {
- int config = KindBits::encode(kConstant) | DescriptorBits::encode(descriptor);
+Handle<Smi> LoadHandler::LoadConstantFromPrototype(Isolate* isolate) {
+ int config = KindBits::encode(kConstantFromPrototype);
return handle(Smi::FromInt(config), isolate);
}
diff --git a/deps/v8/src/ic/handler-configuration.cc b/deps/v8/src/ic/handler-configuration.cc
index 0b8ebd2bbe..814935c6eb 100644
--- a/deps/v8/src/ic/handler-configuration.cc
+++ b/deps/v8/src/ic/handler-configuration.cc
@@ -30,7 +30,7 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
Handle<Smi>* smi_handler, Handle<Map> receiver_map,
Handle<JSReceiver> holder, MaybeObjectHandle data1,
MaybeObjectHandle maybe_data2) {
- int checks_count = 0;
+ int data_size = 1;
// Holder-is-receiver case itself does not add entries unless there is an
// optional data2 value provided.
@@ -51,7 +51,7 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
using Bit = typename ICHandler::DoAccessCheckOnReceiverBits;
*smi_handler = SetBitFieldValue<Bit>(isolate, *smi_handler, true);
}
- checks_count++;
+ data_size++;
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
if (!fill_handler) {
@@ -67,16 +67,16 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
if (fill_handler) {
// This value will go either to data2 or data3 slot depending on whether
// data2 slot is already occupied by native context.
- if (checks_count == 0) {
+ if (data_size == 1) {
handler->set_data2(*maybe_data2);
} else {
- DCHECK_EQ(1, checks_count);
+ DCHECK_EQ(2, data_size);
handler->set_data3(*maybe_data2);
}
}
- checks_count++;
+ data_size++;
}
- return checks_count;
+ return data_size;
}
// Returns 0 if the validity cell check is enough to ensure that the
@@ -86,10 +86,10 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
// Returns -1 if the handler has to be compiled or the number of prototype
// checks otherwise.
template <typename ICHandler>
-int GetPrototypeCheckCount(
- Isolate* isolate, Handle<Smi>* smi_handler, Handle<Map> receiver_map,
- Handle<JSReceiver> holder, MaybeObjectHandle data1,
- MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
+int GetHandlerDataSize(Isolate* isolate, Handle<Smi>* smi_handler,
+ Handle<Map> receiver_map, Handle<JSReceiver> holder,
+ MaybeObjectHandle data1,
+ MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
DCHECK_NOT_NULL(smi_handler);
return InitPrototypeChecksImpl<ICHandler, false>(isolate, Handle<ICHandler>(),
smi_handler, receiver_map,
@@ -121,14 +121,13 @@ Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
data1 = maybe_data1;
}
- int checks_count = GetPrototypeCheckCount<LoadHandler>(
+ int data_size = GetHandlerDataSize<LoadHandler>(
isolate, &smi_handler, receiver_map, holder, data1, maybe_data2);
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
- int data_count = 1 + checks_count;
- Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_count);
+ Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size);
handler->set_smi_handler(*smi_handler);
handler->set_validity_cell(*validity_cell);
@@ -144,19 +143,18 @@ Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
Handle<Smi> smi_handler) {
Handle<JSReceiver> end; // null handle, means full prototype chain lookup.
MaybeObjectHandle data1 = holder;
- int checks_count = GetPrototypeCheckCount<LoadHandler>(
- isolate, &smi_handler, receiver_map, end, data1);
+ int data_size = GetHandlerDataSize<LoadHandler>(isolate, &smi_handler,
+ receiver_map, end, data1);
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
if (validity_cell->IsSmi()) {
- DCHECK_EQ(0, checks_count);
+ DCHECK_EQ(1, data_size);
// Lookup on receiver isn't supported in case of a simple smi handler.
if (!LookupOnReceiverBits::decode(smi_handler->value())) return smi_handler;
}
- int data_count = 1 + checks_count;
- Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_count);
+ Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size);
handler->set_smi_handler(*smi_handler);
handler->set_validity_cell(*validity_cell);
@@ -251,16 +249,13 @@ Handle<Object> StoreHandler::StoreThroughPrototype(
data1 = maybe_data1;
}
- int checks_count = GetPrototypeCheckCount<StoreHandler>(
+ int data_size = GetHandlerDataSize<StoreHandler>(
isolate, &smi_handler, receiver_map, holder, data1, maybe_data2);
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
- DCHECK_IMPLIES(validity_cell->IsSmi(), checks_count == 0);
- int data_count = 1 + checks_count;
- Handle<StoreHandler> handler =
- isolate->factory()->NewStoreHandler(data_count);
+ Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(data_size);
handler->set_smi_handler(*smi_handler);
handler->set_validity_cell(*validity_cell);
diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h
index b8888868ec..80d19d73ec 100644
--- a/deps/v8/src/ic/handler-configuration.h
+++ b/deps/v8/src/ic/handler-configuration.h
@@ -37,7 +37,7 @@ class LoadHandler final : public DataHandler {
kNormal,
kGlobal,
kField,
- kConstant,
+ kConstantFromPrototype,
kAccessor,
kNativeDataProperty,
kApiGetter,
@@ -47,65 +47,58 @@ class LoadHandler final : public DataHandler {
kNonExistent,
kModuleExport
};
- class KindBits : public BitField<Kind, 0, 4> {};
+ using KindBits = BitField<Kind, 0, 4>;
// Defines whether access rights check should be done on receiver object.
// Applicable to named property kinds only when loading value from prototype
// chain. Ignored when loading from holder.
- class DoAccessCheckOnReceiverBits
- : public BitField<bool, KindBits::kNext, 1> {};
+ using DoAccessCheckOnReceiverBits = KindBits::Next<bool, 1>;
// Defines whether a lookup should be done on receiver object before
// proceeding to the prototype chain. Applicable to named property kinds only
// when loading value from prototype chain. Ignored when loading from holder.
- class LookupOnReceiverBits
- : public BitField<bool, DoAccessCheckOnReceiverBits::kNext, 1> {};
+ using LookupOnReceiverBits = DoAccessCheckOnReceiverBits::Next<bool, 1>;
//
// Encoding when KindBits contains kForConstants.
//
// Index of a value entry in the descriptor array.
- class DescriptorBits : public BitField<unsigned, LookupOnReceiverBits::kNext,
- kDescriptorIndexBitCount> {};
+ using DescriptorBits =
+ LookupOnReceiverBits::Next<unsigned, kDescriptorIndexBitCount>;
// Make sure we don't overflow the smi.
- STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize);
+ STATIC_ASSERT(DescriptorBits::kLastUsedBit < kSmiValueSize);
//
// Encoding when KindBits contains kField.
//
- class IsInobjectBits : public BitField<bool, LookupOnReceiverBits::kNext, 1> {
- };
- class IsDoubleBits : public BitField<bool, IsInobjectBits::kNext, 1> {};
+ using IsInobjectBits = LookupOnReceiverBits::Next<bool, 1>;
+ using IsDoubleBits = IsInobjectBits::Next<bool, 1>;
// +1 here is to cover all possible JSObject header sizes.
- class FieldIndexBits : public BitField<unsigned, IsDoubleBits::kNext,
- kDescriptorIndexBitCount + 1> {};
+ using FieldIndexBits =
+ IsDoubleBits::Next<unsigned, kDescriptorIndexBitCount + 1>;
// Make sure we don't overflow the smi.
- STATIC_ASSERT(FieldIndexBits::kNext <= kSmiValueSize);
+ STATIC_ASSERT(FieldIndexBits::kLastUsedBit < kSmiValueSize);
//
// Encoding when KindBits contains kElement or kIndexedString.
//
- class AllowOutOfBoundsBits
- : public BitField<bool, LookupOnReceiverBits::kNext, 1> {};
+ using AllowOutOfBoundsBits = LookupOnReceiverBits::Next<bool, 1>;
//
// Encoding when KindBits contains kElement.
//
- class IsJsArrayBits : public BitField<bool, AllowOutOfBoundsBits::kNext, 1> {
- };
- class ConvertHoleBits : public BitField<bool, IsJsArrayBits::kNext, 1> {};
- class ElementsKindBits
- : public BitField<ElementsKind, ConvertHoleBits::kNext, 8> {};
+ using IsJsArrayBits = AllowOutOfBoundsBits::Next<bool, 1>;
+ using ConvertHoleBits = IsJsArrayBits::Next<bool, 1>;
+ using ElementsKindBits = ConvertHoleBits::Next<ElementsKind, 8>;
// Make sure we don't overflow the smi.
- STATIC_ASSERT(ElementsKindBits::kNext <= kSmiValueSize);
+ STATIC_ASSERT(ElementsKindBits::kLastUsedBit < kSmiValueSize);
//
// Encoding when KindBits contains kModuleExport.
//
- class ExportsIndexBits
- : public BitField<unsigned, LookupOnReceiverBits::kNext,
- kSmiValueSize - LookupOnReceiverBits::kNext> {};
+ using ExportsIndexBits = LookupOnReceiverBits::Next<
+ unsigned, kSmiValueSize - LookupOnReceiverBits::kLastUsedBit - 1>;
// Decodes kind from Smi-handler.
static inline Kind GetHandlerKind(Smi smi_handler);
@@ -123,8 +116,9 @@ class LoadHandler final : public DataHandler {
// Creates a Smi-handler for loading a field from fast object.
static inline Handle<Smi> LoadField(Isolate* isolate, FieldIndex field_index);
- // Creates a Smi-handler for loading a constant from fast object.
- static inline Handle<Smi> LoadConstant(Isolate* isolate, int descriptor);
+ // Creates a Smi-handler for loading a cached constant from fast
+ // prototype object.
+ static inline Handle<Smi> LoadConstantFromPrototype(Isolate* isolate);
// Creates a Smi-handler for calling a getter on a fast object.
static inline Handle<Smi> LoadAccessor(Isolate* isolate, int descriptor);
@@ -206,47 +200,43 @@ class StoreHandler final : public DataHandler {
kProxy,
kKindsNumber // Keep last
};
- class KindBits : public BitField<Kind, 0, 4> {};
+ using KindBits = BitField<Kind, 0, 4>;
enum FieldRepresentation { kSmi, kDouble, kHeapObject, kTagged };
// Applicable to kGlobalProxy, kProxy kinds.
// Defines whether access rights check should be done on receiver object.
- class DoAccessCheckOnReceiverBits
- : public BitField<bool, KindBits::kNext, 1> {};
+ using DoAccessCheckOnReceiverBits = KindBits::Next<bool, 1>;
// Defines whether a lookup should be done on receiver object before
// proceeding to the prototype chain. Applicable to named property kinds only
// when storing through prototype chain. Ignored when storing to holder.
- class LookupOnReceiverBits
- : public BitField<bool, DoAccessCheckOnReceiverBits::kNext, 1> {};
+ using LookupOnReceiverBits = DoAccessCheckOnReceiverBits::Next<bool, 1>;
// Applicable to kField, kTransitionToField and kTransitionToConstant
// kinds.
// Index of a value entry in the descriptor array.
- class DescriptorBits : public BitField<unsigned, LookupOnReceiverBits::kNext,
- kDescriptorIndexBitCount> {};
+ using DescriptorBits =
+ LookupOnReceiverBits::Next<unsigned, kDescriptorIndexBitCount>;
//
// Encoding when KindBits contains kTransitionToConstant.
//
// Make sure we don't overflow the smi.
- STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize);
+ STATIC_ASSERT(DescriptorBits::kLastUsedBit < kSmiValueSize);
//
// Encoding when KindBits contains kField or kTransitionToField.
//
- class IsInobjectBits : public BitField<bool, DescriptorBits::kNext, 1> {};
- class FieldRepresentationBits
- : public BitField<FieldRepresentation, IsInobjectBits::kNext, 2> {};
+ using IsInobjectBits = DescriptorBits::Next<bool, 1>;
+ using FieldRepresentationBits = IsInobjectBits::Next<FieldRepresentation, 2>;
// +1 here is to cover all possible JSObject header sizes.
- class FieldIndexBits
- : public BitField<unsigned, FieldRepresentationBits::kNext,
- kDescriptorIndexBitCount + 1> {};
+ using FieldIndexBits =
+ FieldRepresentationBits::Next<unsigned, kDescriptorIndexBitCount + 1>;
// Make sure we don't overflow the smi.
- STATIC_ASSERT(FieldIndexBits::kNext <= kSmiValueSize);
+ STATIC_ASSERT(FieldIndexBits::kLastUsedBit < kSmiValueSize);
// Creates a Smi-handler for storing a field to fast object.
static inline Handle<Smi> StoreField(Isolate* isolate, int descriptor,
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index 377e3df6ae..3c8d1ea582 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -14,6 +14,7 @@
#include "src/execution/execution.h"
#include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h"
+#include "src/execution/runtime-profiler.h"
#include "src/handles/handles-inl.h"
#include "src/ic/call-optimization.h"
#include "src/ic/handler-configuration-inl.h"
@@ -28,14 +29,13 @@
#include "src/objects/heap-number-inl.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/module-inl.h"
-#include "src/objects/struct-inl.h"
-#include "src/utils/ostreams.h"
-#include "src/execution/runtime-profiler.h"
#include "src/objects/prototype.h"
+#include "src/objects/struct-inl.h"
#include "src/runtime/runtime-utils.h"
#include "src/runtime/runtime.h"
#include "src/tracing/trace-event.h"
#include "src/tracing/tracing-category-observer.h"
+#include "src/utils/ostreams.h"
namespace v8 {
namespace internal {
@@ -391,19 +391,23 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
}
if (*name == ReadOnlyRoots(isolate()).iterator_symbol()) {
- return Runtime::ThrowIteratorError(isolate(), object);
+ return isolate()->Throw<Object>(
+ ErrorUtils::NewIteratorError(isolate(), object));
+ }
+
+ if (IsAnyHas()) {
+ return TypeError(MessageTemplate::kInvalidInOperatorUse, object, name);
+ } else {
+ DCHECK(object->IsNullOrUndefined(isolate()));
+ ErrorUtils::ThrowLoadFromNullOrUndefined(isolate(), object, name);
+ return MaybeHandle<Object>();
}
- return TypeError(IsAnyHas() ? MessageTemplate::kInvalidInOperatorUse
- : MessageTemplate::kNonObjectPropertyLoad,
- object, name);
}
if (MigrateDeprecated(isolate(), object)) use_ic = false;
- if (state() != UNINITIALIZED) {
- JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
- update_receiver_map(object);
- }
+ JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
+ update_receiver_map(object);
LookupIterator it(isolate(), object, name);
@@ -414,7 +418,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
if (name->IsPrivateName() && !it.IsFound()) {
Handle<String> name_string(String::cast(Symbol::cast(*name).name()),
isolate());
- return TypeError(MessageTemplate::kInvalidPrivateFieldRead, object,
+ return TypeError(MessageTemplate::kInvalidPrivateMemberRead, object,
name_string);
}
@@ -618,7 +622,7 @@ void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
DCHECK(IsAnyLoad() || IsAnyStore() || IsAnyHas());
switch (state()) {
case NO_FEEDBACK:
- break;
+ UNREACHABLE();
case UNINITIALIZED:
case PREMONOMORPHIC:
UpdateMonomorphicIC(handler, name);
@@ -648,15 +652,6 @@ void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
}
void LoadIC::UpdateCaches(LookupIterator* lookup) {
- if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
- // This is the first time we execute this inline cache. Set the target to
- // the pre monomorphic stub to delay setting the monomorphic state.
- TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
- ConfigureVectorState(receiver_map());
- TraceIC("LoadIC", lookup->name());
- return;
- }
-
Handle<Object> code;
if (lookup->state() == LookupIterator::ACCESS_CHECK) {
code = slow_stub();
@@ -908,6 +903,33 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
if (receiver_is_holder) return smi_handler;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
}
+ if (lookup->constness() == PropertyConstness::kConst &&
+ !receiver_is_holder) {
+ DCHECK(!lookup->is_dictionary_holder());
+
+ Handle<Object> value = lookup->GetDataValue();
+
+ if (value->IsThinString()) {
+ value = handle(ThinString::cast(*value)->actual(), isolate());
+ }
+
+ // Non internalized strings could turn into thin/cons strings
+ // when internalized. Weak references to thin/cons strings are
+ // not supported in the GC. If concurrent marking is running
+ // and the thin/cons string is marked but the actual string is
+ // not, then the weak reference could be missed.
+ if (!value->IsString() ||
+ (value->IsString() && value->IsInternalizedString())) {
+ MaybeObjectHandle weak_value =
+ value->IsSmi() ? MaybeObjectHandle(*value, isolate())
+ : MaybeObjectHandle::Weak(*value, isolate());
+
+ smi_handler = LoadHandler::LoadConstantFromPrototype(isolate());
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
+ return LoadHandler::LoadFromPrototype(isolate(), map, holder,
+ smi_handler, weak_value);
+ }
+ }
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
smi_handler);
}
@@ -1117,7 +1139,7 @@ Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map,
is_js_array, load_mode);
}
DCHECK(IsFastElementsKind(elements_kind) ||
- IsFrozenOrSealedElementsKind(elements_kind) ||
+ IsAnyNonextensibleElementsKind(elements_kind) ||
IsTypedArrayElementsKind(elements_kind));
bool convert_hole_to_undefined =
(elements_kind == HOLEY_SMI_ELEMENTS ||
@@ -1415,16 +1437,14 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
}
- if (state() != UNINITIALIZED) {
- JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
- }
+ JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate());
LookupIterator it(isolate(), object, name);
if (name->IsPrivate()) {
if (name->IsPrivateName() && !it.IsFound()) {
Handle<String> name_string(String::cast(Symbol::cast(*name).name()),
isolate());
- return TypeError(MessageTemplate::kInvalidPrivateFieldWrite, object,
+ return TypeError(MessageTemplate::kInvalidPrivateMemberWrite, object,
name_string);
}
@@ -1442,15 +1462,6 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
StoreOrigin store_origin) {
- if (state() == UNINITIALIZED && !IsStoreGlobalIC()) {
- // This is the first time we execute this inline cache. Transition
- // to premonomorphic state to delay setting the monomorphic state.
- TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic);
- ConfigureVectorState(receiver_map());
- TraceIC("StoreIC", lookup->name());
- return;
- }
-
MaybeObjectHandle handler;
if (LookupForWrite(lookup, value, store_origin)) {
if (IsStoreGlobalIC()) {
@@ -1810,10 +1821,8 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
handlers.reserve(target_receiver_maps.size());
StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
if (target_receiver_maps.size() == 0) {
- // Transition to PREMONOMORPHIC state here and remember a weak-reference
- // to the {receiver_map} in case TurboFan sees this function before the
- // IC can transition further.
- ConfigureVectorState(receiver_map);
+ Handle<Object> handler = StoreElementHandler(receiver_map, store_mode);
+ ConfigureVectorState(Handle<Name>(), receiver_map, handler);
} else if (target_receiver_maps.size() == 1) {
ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]);
} else {
@@ -1840,6 +1849,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
CodeFactory::KeyedStoreIC_SloppyArguments(isolate(), store_mode).code();
} else if (receiver_map->has_fast_elements() ||
receiver_map->has_sealed_elements() ||
+ receiver_map->has_nonextensible_elements() ||
receiver_map->has_typed_array_elements()) {
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
code = CodeFactory::StoreFastElementIC(isolate(), store_mode).code();
diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc
index 7e87b015d4..bb4e6cb427 100644
--- a/deps/v8/src/ic/keyed-store-generic.cc
+++ b/deps/v8/src/ic/keyed-store-generic.cc
@@ -30,7 +30,7 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
void KeyedStoreGeneric();
- void StoreIC_Uninitialized();
+ void StoreIC_NoFeedback();
// Generates code for [[Set]] operation, the |unique_name| is supposed to be
// unique otherwise this code will always go to runtime.
@@ -62,8 +62,8 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
TNode<Object> key, TNode<Object> value,
Maybe<LanguageMode> language_mode);
- void EmitGenericElementStore(Node* receiver, Node* receiver_map,
- Node* instance_type, Node* intptr_index,
+ void EmitGenericElementStore(Node* receiver, TNode<Map> receiver_map,
+ Node* instance_type, TNode<IntPtrT> index,
Node* value, Node* context, Label* slow);
// If language mode is not provided it is deduced from the feedback slot's
@@ -82,35 +82,38 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
Nothing<LanguageMode>());
}
- void BranchIfPrototypesHaveNonFastElements(Node* receiver_map,
+ void BranchIfPrototypesHaveNonFastElements(TNode<Map> receiver_map,
Label* non_fast_elements,
Label* only_fast_elements);
- void TryRewriteElements(Node* receiver, Node* receiver_map, Node* elements,
- Node* native_context, ElementsKind from_kind,
- ElementsKind to_kind, Label* bailout);
+ void TryRewriteElements(Node* receiver, TNode<Map> receiver_map,
+ Node* elements, Node* native_context,
+ ElementsKind from_kind, ElementsKind to_kind,
+ Label* bailout);
- void StoreElementWithCapacity(Node* receiver, Node* receiver_map,
- Node* elements, Node* elements_kind,
- Node* intptr_index, Node* value, Node* context,
- Label* slow, UpdateLength update_length);
+ void StoreElementWithCapacity(Node* receiver, TNode<Map> receiver_map,
+ SloppyTNode<FixedArrayBase> elements,
+ TNode<Word32T> elements_kind,
+ TNode<IntPtrT> index, Node* value,
+ Node* context, Label* slow,
+ UpdateLength update_length);
void MaybeUpdateLengthAndReturn(Node* receiver, Node* index, Node* value,
UpdateLength update_length);
- void TryChangeToHoleyMapHelper(Node* receiver, Node* receiver_map,
+ void TryChangeToHoleyMapHelper(Node* receiver, TNode<Map> receiver_map,
Node* native_context, ElementsKind packed_kind,
ElementsKind holey_kind, Label* done,
Label* map_mismatch, Label* bailout);
- void TryChangeToHoleyMap(Node* receiver, Node* receiver_map,
- Node* current_elements_kind, Node* context,
+ void TryChangeToHoleyMap(Node* receiver, TNode<Map> receiver_map,
+ TNode<Word32T> current_elements_kind, Node* context,
ElementsKind packed_kind, Label* bailout);
- void TryChangeToHoleyMapMulti(Node* receiver, Node* receiver_map,
- Node* current_elements_kind, Node* context,
- ElementsKind packed_kind,
+ void TryChangeToHoleyMapMulti(Node* receiver, TNode<Map> receiver_map,
+ TNode<Word32T> current_elements_kind,
+ Node* context, ElementsKind packed_kind,
ElementsKind packed_kind_2, Label* bailout);
- void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name,
+ void LookupPropertyOnPrototypeChain(TNode<Map> receiver_map, Node* name,
Label* accessor,
Variable* var_accessor_pair,
Variable* var_accessor_holder,
@@ -138,10 +141,9 @@ void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state) {
assembler.KeyedStoreGeneric();
}
-void StoreICUninitializedGenerator::Generate(
- compiler::CodeAssemblerState* state) {
+void StoreICNoFeedbackGenerator::Generate(compiler::CodeAssemblerState* state) {
KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary);
- assembler.StoreIC_Uninitialized();
+ assembler.StoreIC_NoFeedback();
}
void KeyedStoreGenericGenerator::SetProperty(
@@ -169,7 +171,8 @@ void KeyedStoreGenericGenerator::SetPropertyInLiteral(
}
void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
- Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) {
+ TNode<Map> receiver_map, Label* non_fast_elements,
+ Label* only_fast_elements) {
VARIABLE(var_map, MachineRepresentation::kTagged);
var_map.Bind(receiver_map);
Label loop_body(this, &var_map);
@@ -178,11 +181,11 @@ void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
BIND(&loop_body);
{
Node* map = var_map.value();
- Node* prototype = LoadMapPrototype(map);
+ TNode<HeapObject> prototype = LoadMapPrototype(map);
GotoIf(IsNull(prototype), only_fast_elements);
- Node* prototype_map = LoadMap(prototype);
+ TNode<Map> prototype_map = LoadMap(prototype);
var_map.Bind(prototype_map);
- TNode<Int32T> instance_type = LoadMapInstanceType(prototype_map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(prototype_map);
GotoIf(IsCustomElementsReceiverInstanceType(instance_type),
non_fast_elements);
TNode<Int32T> elements_kind = LoadMapElementsKind(prototype_map);
@@ -193,8 +196,9 @@ void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
}
void KeyedStoreGenericAssembler::TryRewriteElements(
- Node* receiver, Node* receiver_map, Node* elements, Node* native_context,
- ElementsKind from_kind, ElementsKind to_kind, Label* bailout) {
+ Node* receiver, TNode<Map> receiver_map, Node* elements,
+ Node* native_context, ElementsKind from_kind, ElementsKind to_kind,
+ Label* bailout) {
DCHECK(IsFastPackedElementsKind(from_kind));
ElementsKind holey_from_kind = GetHoleyElementsKind(from_kind);
ElementsKind holey_to_kind = GetHoleyElementsKind(to_kind);
@@ -205,8 +209,8 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
VARIABLE(var_target_map, MachineRepresentation::kTagged);
// Check if the receiver has the default |from_kind| map.
{
- Node* packed_map = LoadJSArrayElementsMap(from_kind, native_context);
- GotoIf(WordNotEqual(receiver_map, packed_map), &check_holey_map);
+ TNode<Map> packed_map = LoadJSArrayElementsMap(from_kind, native_context);
+ GotoIf(TaggedNotEqual(receiver_map, packed_map), &check_holey_map);
var_target_map.Bind(
LoadContextElement(native_context, Context::ArrayMapIndex(to_kind)));
Goto(&perform_transition);
@@ -215,9 +219,9 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
// Check if the receiver has the default |holey_from_kind| map.
BIND(&check_holey_map);
{
- Node* holey_map = LoadContextElement(
+ TNode<Object> holey_map = LoadContextElement(
native_context, Context::ArrayMapIndex(holey_from_kind));
- GotoIf(WordNotEqual(receiver_map, holey_map), bailout);
+ GotoIf(TaggedNotEqual(receiver_map, holey_map), bailout);
var_target_map.Bind(LoadContextElement(
native_context, Context::ArrayMapIndex(holey_to_kind)));
Goto(&perform_transition);
@@ -227,7 +231,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
BIND(&perform_transition);
{
if (IsDoubleElementsKind(from_kind) != IsDoubleElementsKind(to_kind)) {
- Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
+ TNode<IntPtrT> capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
GrowElementsCapacity(receiver, elements, from_kind, to_kind, capacity,
capacity, INTPTR_PARAMETERS, bailout);
}
@@ -236,38 +240,39 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
}
void KeyedStoreGenericAssembler::TryChangeToHoleyMapHelper(
- Node* receiver, Node* receiver_map, Node* native_context,
+ Node* receiver, TNode<Map> receiver_map, Node* native_context,
ElementsKind packed_kind, ElementsKind holey_kind, Label* done,
Label* map_mismatch, Label* bailout) {
- Node* packed_map = LoadJSArrayElementsMap(packed_kind, native_context);
- GotoIf(WordNotEqual(receiver_map, packed_map), map_mismatch);
+ TNode<Map> packed_map = LoadJSArrayElementsMap(packed_kind, native_context);
+ GotoIf(TaggedNotEqual(receiver_map, packed_map), map_mismatch);
if (AllocationSite::ShouldTrack(packed_kind, holey_kind)) {
TrapAllocationMemento(receiver, bailout);
}
- Node* holey_map =
+ TNode<Object> holey_map =
LoadContextElement(native_context, Context::ArrayMapIndex(holey_kind));
StoreMap(receiver, holey_map);
Goto(done);
}
void KeyedStoreGenericAssembler::TryChangeToHoleyMap(
- Node* receiver, Node* receiver_map, Node* current_elements_kind,
- Node* context, ElementsKind packed_kind, Label* bailout) {
+ Node* receiver, TNode<Map> receiver_map,
+ TNode<Word32T> current_elements_kind, Node* context,
+ ElementsKind packed_kind, Label* bailout) {
ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
Label already_holey(this);
GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
&already_holey);
- Node* native_context = LoadNativeContext(context);
+ TNode<Context> native_context = LoadNativeContext(context);
TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
holey_kind, &already_holey, bailout, bailout);
BIND(&already_holey);
}
void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
- Node* receiver, Node* receiver_map, Node* current_elements_kind,
- Node* context, ElementsKind packed_kind, ElementsKind packed_kind_2,
- Label* bailout) {
+ Node* receiver, TNode<Map> receiver_map,
+ TNode<Word32T> current_elements_kind, Node* context,
+ ElementsKind packed_kind, ElementsKind packed_kind_2, Label* bailout) {
ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
ElementsKind holey_kind_2 = GetHoleyElementsKind(packed_kind_2);
Label already_holey(this), check_other_kind(this);
@@ -277,7 +282,7 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind_2)),
&already_holey);
- Node* native_context = LoadNativeContext(context);
+ TNode<Context> native_context = LoadNativeContext(context);
TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
holey_kind, &already_holey, &check_other_kind,
bailout);
@@ -291,7 +296,7 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn(
Node* receiver, Node* index, Node* value, UpdateLength update_length) {
if (update_length != kDontChangeLength) {
- Node* new_length = SmiTag(Signed(IntPtrAdd(index, IntPtrConstant(1))));
+ TNode<Smi> new_length = SmiTag(Signed(IntPtrAdd(index, IntPtrConstant(1))));
StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset, new_length,
MachineRepresentation::kTagged);
}
@@ -299,8 +304,9 @@ void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn(
}
void KeyedStoreGenericAssembler::StoreElementWithCapacity(
- Node* receiver, Node* receiver_map, Node* elements, Node* elements_kind,
- Node* intptr_index, Node* value, Node* context, Label* slow,
+ Node* receiver, TNode<Map> receiver_map,
+ SloppyTNode<FixedArrayBase> elements, TNode<Word32T> elements_kind,
+ TNode<IntPtrT> index, Node* value, Node* context, Label* slow,
UpdateLength update_length) {
if (update_length != kDontChangeLength) {
CSA_ASSERT(this, InstanceTypeEqual(LoadMapInstanceType(receiver_map),
@@ -319,14 +325,14 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
const int kHeaderSize = FixedArray::kHeaderSize - kHeapObjectTag;
Label check_double_elements(this), check_cow_elements(this);
- Node* elements_map = LoadMap(elements);
- GotoIf(WordNotEqual(elements_map, LoadRoot(RootIndex::kFixedArrayMap)),
+ TNode<Map> elements_map = LoadMap(elements);
+ GotoIf(TaggedNotEqual(elements_map, FixedArrayMapConstant()),
&check_double_elements);
// FixedArray backing store -> Smi or object elements.
{
- Node* offset = ElementOffsetFromIndex(intptr_index, PACKED_ELEMENTS,
- INTPTR_PARAMETERS, kHeaderSize);
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(
+ index, PACKED_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
// Check if we're about to overwrite the hole. We can safely do that
// only if there can be no setters on the prototype chain.
// If we know that we're storing beyond the previous array length, we
@@ -334,8 +340,9 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
{
Label hole_check_passed(this);
if (update_length == kDontChangeLength) {
- Node* element = Load(MachineType::AnyTagged(), elements, offset);
- GotoIf(WordNotEqual(element, TheHoleConstant()), &hole_check_passed);
+ TNode<Object> element =
+ CAST(Load(MachineType::AnyTagged(), elements, offset));
+ GotoIf(TaggedNotEqual(element, TheHoleConstant()), &hole_check_passed);
}
BranchIfPrototypesHaveNonFastElements(receiver_map, slow,
&hole_check_passed);
@@ -354,7 +361,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
}
StoreNoWriteBarrier(MachineRepresentation::kTaggedSigned, elements,
offset, value);
- MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
+ MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
BIND(&non_smi_value);
}
@@ -372,7 +379,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
PACKED_ELEMENTS, slow);
}
Store(elements, offset, value);
- MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
+ MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
BIND(&must_transition);
}
@@ -380,8 +387,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
// Transition to the required ElementsKind.
{
Label transition_to_double(this), transition_to_object(this);
- Node* native_context = LoadNativeContext(context);
- Branch(WordEqual(LoadMap(value), LoadRoot(RootIndex::kHeapNumberMap)),
+ TNode<Context> native_context = LoadNativeContext(context);
+ Branch(TaggedEqual(LoadMap(value), HeapNumberMapConstant()),
&transition_to_double, &transition_to_object);
BIND(&transition_to_double);
{
@@ -393,16 +400,15 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
TryRewriteElements(receiver, receiver_map, elements, native_context,
PACKED_SMI_ELEMENTS, target_kind, slow);
// Reload migrated elements.
- Node* double_elements = LoadElements(receiver);
- Node* double_offset =
- ElementOffsetFromIndex(intptr_index, PACKED_DOUBLE_ELEMENTS,
- INTPTR_PARAMETERS, kHeaderSize);
+ TNode<FixedArrayBase> double_elements = LoadElements(receiver);
+ TNode<IntPtrT> double_offset = ElementOffsetFromIndex(
+ index, PACKED_DOUBLE_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
// Make sure we do not store signalling NaNs into double arrays.
- Node* double_value = Float64SilenceNaN(LoadHeapNumberValue(value));
+ TNode<Float64T> double_value =
+ Float64SilenceNaN(LoadHeapNumberValue(value));
StoreNoWriteBarrier(MachineRepresentation::kFloat64, double_elements,
double_offset, double_value);
- MaybeUpdateLengthAndReturn(receiver, intptr_index, value,
- update_length);
+ MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
}
BIND(&transition_to_object);
@@ -415,22 +421,21 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
TryRewriteElements(receiver, receiver_map, elements, native_context,
PACKED_SMI_ELEMENTS, target_kind, slow);
// The elements backing store didn't change, no reload necessary.
- CSA_ASSERT(this, WordEqual(elements, LoadElements(receiver)));
+ CSA_ASSERT(this, TaggedEqual(elements, LoadElements(receiver)));
Store(elements, offset, value);
- MaybeUpdateLengthAndReturn(receiver, intptr_index, value,
- update_length);
+ MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
}
}
}
BIND(&check_double_elements);
- Node* fixed_double_array_map = LoadRoot(RootIndex::kFixedDoubleArrayMap);
- GotoIf(WordNotEqual(elements_map, fixed_double_array_map),
+ TNode<Map> fixed_double_array_map = FixedDoubleArrayMapConstant();
+ GotoIf(TaggedNotEqual(elements_map, fixed_double_array_map),
&check_cow_elements);
// FixedDoubleArray backing store -> double elements.
{
- Node* offset = ElementOffsetFromIndex(intptr_index, PACKED_DOUBLE_ELEMENTS,
- INTPTR_PARAMETERS, kHeaderSize);
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(
+ index, PACKED_DOUBLE_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
// Check if we're about to overwrite the hole. We can safely do that
// only if there can be no setters on the prototype chain.
{
@@ -463,25 +468,25 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
}
StoreNoWriteBarrier(MachineRepresentation::kFloat64, elements, offset,
double_value);
- MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
+ MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
BIND(&non_number_value);
}
// Transition to object elements.
{
- Node* native_context = LoadNativeContext(context);
+ TNode<Context> native_context = LoadNativeContext(context);
ElementsKind target_kind = update_length == kBumpLengthWithGap
? HOLEY_ELEMENTS
: PACKED_ELEMENTS;
TryRewriteElements(receiver, receiver_map, elements, native_context,
PACKED_DOUBLE_ELEMENTS, target_kind, slow);
// Reload migrated elements.
- Node* fast_elements = LoadElements(receiver);
- Node* fast_offset = ElementOffsetFromIndex(
- intptr_index, PACKED_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
+ TNode<FixedArrayBase> fast_elements = LoadElements(receiver);
+ TNode<IntPtrT> fast_offset = ElementOffsetFromIndex(
+ index, PACKED_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
Store(fast_elements, fast_offset, value);
- MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
+ MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
}
}
@@ -493,13 +498,13 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
}
void KeyedStoreGenericAssembler::EmitGenericElementStore(
- Node* receiver, Node* receiver_map, Node* instance_type, Node* intptr_index,
- Node* value, Node* context, Label* slow) {
+ Node* receiver, TNode<Map> receiver_map, Node* instance_type,
+ TNode<IntPtrT> index, Node* value, Node* context, Label* slow) {
Label if_fast(this), if_in_bounds(this), if_out_of_bounds(this),
if_increment_length_by_one(this), if_bump_length_with_gap(this),
if_grow(this), if_nonfast(this), if_typed_array(this),
if_dictionary(this);
- Node* elements = LoadElements(receiver);
+ TNode<FixedArrayBase> elements = LoadElements(receiver);
TNode<Int32T> elements_kind = LoadMapElementsKind(receiver_map);
Branch(IsFastElementsKind(elements_kind), &if_fast, &if_nonfast);
BIND(&if_fast);
@@ -507,25 +512,23 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
Label if_array(this);
GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &if_array);
{
- Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
- Branch(UintPtrLessThan(intptr_index, capacity), &if_in_bounds,
- &if_out_of_bounds);
+ TNode<IntPtrT> capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
+ Branch(UintPtrLessThan(index, capacity), &if_in_bounds, &if_out_of_bounds);
}
BIND(&if_array);
{
- Node* length = SmiUntag(LoadFastJSArrayLength(receiver));
- GotoIf(UintPtrLessThan(intptr_index, length), &if_in_bounds);
- Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
- GotoIf(UintPtrGreaterThanOrEqual(intptr_index, capacity), &if_grow);
- Branch(WordEqual(intptr_index, length), &if_increment_length_by_one,
+ TNode<IntPtrT> length = SmiUntag(LoadFastJSArrayLength(receiver));
+ GotoIf(UintPtrLessThan(index, length), &if_in_bounds);
+ TNode<IntPtrT> capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
+ GotoIf(UintPtrGreaterThanOrEqual(index, capacity), &if_grow);
+ Branch(WordEqual(index, length), &if_increment_length_by_one,
&if_bump_length_with_gap);
}
BIND(&if_in_bounds);
{
StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
- intptr_index, value, context, slow,
- kDontChangeLength);
+ index, value, context, slow, kDontChangeLength);
}
BIND(&if_out_of_bounds);
@@ -541,15 +544,14 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
BIND(&if_increment_length_by_one);
{
StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
- intptr_index, value, context, slow,
+ index, value, context, slow,
kIncrementLengthByOne);
}
BIND(&if_bump_length_with_gap);
{
StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
- intptr_index, value, context, slow,
- kBumpLengthWithGap);
+ index, value, context, slow, kBumpLengthWithGap);
}
// Out-of-capacity accesses (index >= capacity) jump here. Additionally,
@@ -593,7 +595,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
}
void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
- Node* receiver_map, Node* name, Label* accessor,
+ TNode<Map> receiver_map, Node* name, Label* accessor,
Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly,
Label* bailout) {
Label ok_to_write(this);
@@ -610,7 +612,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
Node* holder = var_holder.value();
GotoIf(IsNull(holder), &ok_to_write);
Node* holder_map = var_holder_map.value();
- Node* instance_type = LoadMapInstanceType(holder_map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(holder_map);
Label next_proto(this);
{
Label found(this), found_fast(this), found_dict(this), found_global(this);
@@ -623,7 +625,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
{
TNode<DescriptorArray> descriptors = CAST(var_meta_storage.value());
TNode<IntPtrT> name_index = var_entry.value();
- Node* details = LoadDetailsByKeyIndex(descriptors, name_index);
+ TNode<Uint32T> details = LoadDetailsByKeyIndex(descriptors, name_index);
JumpIfDataProperty(details, &ok_to_write, readonly);
// Accessor case.
@@ -638,9 +640,9 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
BIND(&found_dict);
{
- Node* dictionary = var_meta_storage.value();
- Node* entry = var_entry.value();
- Node* details =
+ TNode<HeapObject> dictionary = var_meta_storage.value();
+ TNode<IntPtrT> entry = var_entry.value();
+ TNode<Uint32T> details =
LoadDetailsByKeyIndex<NameDictionary>(dictionary, entry);
JumpIfDataProperty(details, &ok_to_write, readonly);
@@ -657,14 +659,14 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
BIND(&found_global);
{
- Node* dictionary = var_meta_storage.value();
- Node* entry = var_entry.value();
- Node* property_cell =
- LoadValueByKeyIndex<GlobalDictionary>(dictionary, entry);
- Node* value =
+ TNode<HeapObject> dictionary = var_meta_storage.value();
+ TNode<IntPtrT> entry = var_entry.value();
+ TNode<PropertyCell> property_cell =
+ CAST(LoadValueByKeyIndex<GlobalDictionary>(dictionary, entry));
+ TNode<Object> value =
LoadObjectField(property_cell, PropertyCell::kValueOffset);
- GotoIf(WordEqual(value, TheHoleConstant()), &next_proto);
- Node* details = LoadAndUntagToWord32ObjectField(
+ GotoIf(TaggedEqual(value, TheHoleConstant()), &next_proto);
+ TNode<Int32T> details = LoadAndUntagToWord32ObjectField(
property_cell, PropertyCell::kPropertyDetailsRawOffset);
JumpIfDataProperty(details, &ok_to_write, readonly);
@@ -682,7 +684,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
BIND(&next_proto);
// Bailout if it can be an integer indexed exotic case.
GotoIf(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), bailout);
- Node* proto = LoadMapPrototype(holder_map);
+ TNode<HeapObject> proto = LoadMapPrototype(holder_map);
GotoIf(IsNull(proto), &ok_to_write);
var_holder.Bind(proto);
var_holder_map.Bind(LoadMap(proto));
@@ -765,7 +767,8 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
VARIABLE(var_accessor_holder, MachineRepresentation::kTagged);
Label fast_properties(this), dictionary_properties(this), accessor(this),
readonly(this);
- Node* bitfield3 = LoadMapBitField3(receiver_map);
+ TNode<Uint32T> bitfield3 = LoadMapBitField3(receiver_map);
+ TNode<Name> name = CAST(p->name());
Branch(IsSetWord32<Map::IsDictionaryMapBit>(bitfield3),
&dictionary_properties, &fast_properties);
@@ -775,13 +778,13 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
Label descriptor_found(this), lookup_transition(this);
TVARIABLE(IntPtrT, var_name_index);
- DescriptorLookup(p->name(), descriptors, bitfield3, &descriptor_found,
+ DescriptorLookup(name, descriptors, bitfield3, &descriptor_found,
&var_name_index, &lookup_transition);
BIND(&descriptor_found);
{
TNode<IntPtrT> name_index = var_name_index.value();
- Node* details = LoadDetailsByKeyIndex(descriptors, name_index);
+ TNode<Uint32T> details = LoadDetailsByKeyIndex(descriptors, name_index);
Label data_property(this);
JumpIfDataProperty(details, &data_property,
ShouldReconfigureExisting() ? nullptr : &readonly);
@@ -796,12 +799,13 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
var_accessor_holder.Bind(receiver);
Goto(&accessor);
} else {
- Goto(&data_property);
+ // Handle accessor to data property reconfiguration in runtime.
+ Goto(slow);
}
BIND(&data_property);
{
- CheckForAssociatedProtector(p->name(), slow);
+ CheckForAssociatedProtector(name, slow);
OverwriteExistingFastDataProperty(receiver, receiver_map, descriptors,
name_index, details, p->value(), slow,
false);
@@ -811,8 +815,8 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&lookup_transition);
{
Comment("lookup transition");
- TNode<Map> transition_map = FindCandidateStoreICTransitionMapHandler(
- receiver_map, CAST(p->name()), slow);
+ TNode<Map> transition_map =
+ FindCandidateStoreICTransitionMapHandler(receiver_map, name, slow);
// Validate the transition handler candidate and apply the transition.
StoreTransitionMapFlags flags = kValidateTransitionHandler;
@@ -833,9 +837,8 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
TVARIABLE(IntPtrT, var_name_index);
Label dictionary_found(this, &var_name_index), not_found(this);
TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(receiver)));
- NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()),
- &dictionary_found, &var_name_index,
- &not_found);
+ NameDictionaryLookup<NameDictionary>(properties, name, &dictionary_found,
+ &var_name_index, &not_found);
BIND(&dictionary_found);
{
Label overwrite(this);
@@ -858,7 +861,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&overwrite);
{
- CheckForAssociatedProtector(p->name(), slow);
+ CheckForAssociatedProtector(name, slow);
StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
p->value());
exit_point->Return(p->value());
@@ -867,37 +870,37 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&not_found);
{
- CheckForAssociatedProtector(p->name(), slow);
+ CheckForAssociatedProtector(name, slow);
Label extensible(this), is_private_symbol(this);
- Node* bitfield3 = LoadMapBitField3(receiver_map);
- GotoIf(IsPrivateSymbol(p->name()), &is_private_symbol);
+ TNode<Uint32T> bitfield3 = LoadMapBitField3(receiver_map);
+ GotoIf(IsPrivateSymbol(name), &is_private_symbol);
Branch(IsSetWord32<Map::IsExtensibleBit>(bitfield3), &extensible, slow);
BIND(&is_private_symbol);
{
- CSA_ASSERT(this, IsPrivateSymbol(p->name()));
+ CSA_ASSERT(this, IsPrivateSymbol(name));
// For private names, we miss to the runtime which will throw.
// For private symbols, we extend and store an own property.
- Branch(IsPrivateName(p->name()), slow, &extensible);
+ Branch(IsPrivateName(CAST(name)), slow, &extensible);
}
BIND(&extensible);
if (ShouldCheckPrototype()) {
DCHECK(ShouldCallSetter());
LookupPropertyOnPrototypeChain(
- receiver_map, p->name(), &accessor, &var_accessor_pair,
+ receiver_map, name, &accessor, &var_accessor_pair,
&var_accessor_holder,
ShouldReconfigureExisting() ? nullptr : &readonly, slow);
}
Label add_dictionary_property_slow(this);
InvalidateValidityCellIfPrototype(receiver_map, bitfield3);
- Add<NameDictionary>(properties, CAST(p->name()), p->value(),
+ Add<NameDictionary>(properties, name, p->value(),
&add_dictionary_property_slow);
exit_point->Return(p->value());
BIND(&add_dictionary_property_slow);
exit_point->ReturnCallRuntime(Runtime::kAddDictionaryProperty,
- p->context(), p->receiver(), p->name(),
+ p->context(), p->receiver(), name,
p->value());
}
}
@@ -909,9 +912,9 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
Node* accessor_pair = var_accessor_pair.value();
GotoIf(IsAccessorInfoMap(LoadMap(accessor_pair)), slow);
CSA_ASSERT(this, HasInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE));
- Node* setter =
- LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
- Node* setter_map = LoadMap(setter);
+ TNode<HeapObject> setter =
+ CAST(LoadObjectField(accessor_pair, AccessorPair::kSetterOffset));
+ TNode<Map> setter_map = LoadMap(setter);
// FunctionTemplateInfo setters are not supported yet.
GotoIf(IsFunctionTemplateInfoMap(setter_map), slow);
GotoIfNot(IsCallableMap(setter_map), &not_callable);
@@ -927,15 +930,15 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
if (language_mode == LanguageMode::kStrict) {
exit_point->ReturnCallRuntime(
Runtime::kThrowTypeError, p->context(),
- SmiConstant(MessageTemplate::kNoSetterInCallback), p->name(),
+ SmiConstant(MessageTemplate::kNoSetterInCallback), name,
var_accessor_holder.value());
} else {
exit_point->Return(p->value());
}
} else {
CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context(),
- SmiConstant(MessageTemplate::kNoSetterInCallback),
- p->name(), var_accessor_holder.value());
+ SmiConstant(MessageTemplate::kNoSetterInCallback), name,
+ var_accessor_holder.value());
exit_point->Return(p->value());
}
}
@@ -950,14 +953,14 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
if (language_mode == LanguageMode::kStrict) {
Node* type = Typeof(p->receiver());
ThrowTypeError(p->context(), MessageTemplate::kStrictReadOnlyProperty,
- p->name(), type, p->receiver());
+ name, type, p->receiver());
} else {
exit_point->Return(p->value());
}
} else {
CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context(),
- SmiConstant(MessageTemplate::kStrictReadOnlyProperty),
- p->name(), Typeof(p->receiver()), p->receiver());
+ SmiConstant(MessageTemplate::kStrictReadOnlyProperty), name,
+ Typeof(p->receiver()), p->receiver());
exit_point->Return(p->value());
}
}
@@ -975,7 +978,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(
GotoIf(TaggedIsSmi(receiver), &slow);
TNode<Map> receiver_map = LoadMap(CAST(receiver));
- TNode<Int32T> instance_type = LoadMapInstanceType(receiver_map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
// Receivers requiring non-standard element accesses (interceptors, access
// checks, strings and string wrappers, proxies) are handled in the runtime.
GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &slow);
@@ -1043,51 +1046,33 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
KeyedStoreGeneric(context, receiver, key, value, Just(language_mode));
}
-void KeyedStoreGenericAssembler::StoreIC_Uninitialized() {
- using Descriptor = StoreWithVectorDescriptor;
+void KeyedStoreGenericAssembler::StoreIC_NoFeedback() {
+ using Descriptor = StoreDescriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
- Node* name = Parameter(Descriptor::kName);
+ TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
Node* slot = Parameter(Descriptor::kSlot);
- Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext);
Label miss(this, Label::kDeferred), store_property(this);
GotoIf(TaggedIsSmi(receiver), &miss);
- Node* receiver_map = LoadMap(receiver);
- TNode<Int32T> instance_type = LoadMapInstanceType(receiver_map);
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
// Receivers requiring non-standard element accesses (interceptors, access
// checks, strings and string wrappers, proxies) are handled in the runtime.
GotoIf(IsSpecialReceiverInstanceType(instance_type), &miss);
-
- // Optimistically write the state transition to the vector.
- GotoIf(IsUndefined(vector), &store_property);
- StoreFeedbackVectorSlot(vector, slot,
- LoadRoot(RootIndex::kpremonomorphic_symbol),
- SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
- Goto(&store_property);
-
- BIND(&store_property);
{
- StoreICParameters p(CAST(context), receiver, name, value, slot, vector);
+ StoreICParameters p(CAST(context), receiver, name, value, slot,
+ UndefinedConstant());
EmitGenericPropertyStore(receiver, receiver_map, &p, &miss);
}
BIND(&miss);
{
- Label call_runtime(this);
- // Undo the optimistic state transition.
- GotoIf(IsUndefined(vector), &call_runtime);
- StoreFeedbackVectorSlot(vector, slot,
- LoadRoot(RootIndex::kuninitialized_symbol),
- SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
- Goto(&call_runtime);
-
- BIND(&call_runtime);
- TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, vector,
- receiver, name);
+ TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot,
+ UndefinedConstant(), receiver, name);
}
}
diff --git a/deps/v8/src/ic/keyed-store-generic.h b/deps/v8/src/ic/keyed-store-generic.h
index 322bb63321..efee0da80e 100644
--- a/deps/v8/src/ic/keyed-store-generic.h
+++ b/deps/v8/src/ic/keyed-store-generic.h
@@ -37,7 +37,7 @@ class KeyedStoreGenericGenerator {
TNode<Object> value);
};
-class StoreICUninitializedGenerator {
+class StoreICNoFeedbackGenerator {
public:
static void Generate(compiler::CodeAssemblerState* state);
};
diff --git a/deps/v8/src/init/bootstrapper.cc b/deps/v8/src/init/bootstrapper.cc
index 176749781c..f7e25ca0bb 100644
--- a/deps/v8/src/init/bootstrapper.cc
+++ b/deps/v8/src/init/bootstrapper.cc
@@ -596,9 +596,6 @@ Handle<JSFunction> Genesis::CreateEmptyFunction() {
empty_function_map->set_is_prototype_map(true);
DCHECK(!empty_function_map->is_dictionary_map());
- // Allocate ScopeInfo for the empty function.
- Handle<ScopeInfo> scope_info = ScopeInfo::CreateForEmptyFunction(isolate());
-
// Allocate the empty function as the prototype for function according to
// ES#sec-properties-of-the-function-prototype-object
NewFunctionArgs args = NewFunctionArgs::ForBuiltin(
@@ -612,7 +609,8 @@ Handle<JSFunction> Genesis::CreateEmptyFunction() {
script->set_type(Script::TYPE_NATIVE);
Handle<WeakFixedArray> infos = factory()->NewWeakFixedArray(2);
script->set_shared_function_infos(*infos);
- empty_function->shared().set_scope_info(*scope_info);
+ empty_function->shared().set_raw_scope_info(
+ ReadOnlyRoots(isolate()).empty_function_scope_info());
empty_function->shared().DontAdaptArguments();
SharedFunctionInfo::SetScript(handle(empty_function->shared(), isolate()),
script, 1);
@@ -659,17 +657,21 @@ Handle<JSFunction> Genesis::GetThrowTypeErrorIntrinsic() {
Handle<JSFunction> function = factory()->NewFunction(args);
function->shared().DontAdaptArguments();
- // %ThrowTypeError% must not have a name property.
- if (JSReceiver::DeleteProperty(function, factory()->name_string())
- .IsNothing()) {
- DCHECK(false);
- }
+ PropertyAttributes ro_attribs =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+ // %ThrowTypeError% must have a name property with an empty string value.
+ // Per spec, ThrowTypeError's name must also be non-configurable, otherwise
+ // we could omit explicitly setting a property attribute here and just fall
+ // back to the default name attribute on function.
+ JSObject::SetOwnPropertyIgnoreAttributes(
+ function, factory()->name_string(), factory()->empty_string(), ro_attribs)
+ .Assert();
// length needs to be non configurable.
Handle<Object> value(Smi::FromInt(function->length()), isolate());
- JSObject::SetOwnPropertyIgnoreAttributes(
- function, factory()->length_string(), value,
- static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY))
+ JSObject::SetOwnPropertyIgnoreAttributes(function, factory()->length_string(),
+ value, ro_attribs)
.Assert();
if (JSObject::PreventExtensions(function, kThrowOnError).IsNothing()) {
@@ -1154,7 +1156,8 @@ void Genesis::CreateRoots() {
void Genesis::InstallGlobalThisBinding() {
Handle<ScriptContextTable> script_contexts(
native_context()->script_context_table(), isolate());
- Handle<ScopeInfo> scope_info = ScopeInfo::CreateGlobalThisBinding(isolate());
+ Handle<ScopeInfo> scope_info =
+ ReadOnlyRoots(isolate()).global_this_binding_scope_info_handle();
Handle<Context> context =
factory()->NewScriptContext(native_context(), scope_info);
@@ -1222,8 +1225,8 @@ Handle<JSGlobalObject> Genesis::CreateNewGlobals(
FunctionTemplateInfo::cast(js_global_object_template->constructor()),
isolate());
js_global_object_function = ApiNatives::CreateApiFunction(
- isolate(), js_global_object_constructor, factory()->the_hole_value(),
- JS_GLOBAL_OBJECT_TYPE);
+ isolate(), isolate()->native_context(), js_global_object_constructor,
+ factory()->the_hole_value(), JS_GLOBAL_OBJECT_TYPE);
}
js_global_object_function->initial_map().set_is_prototype_map(true);
@@ -1248,8 +1251,8 @@ Handle<JSGlobalObject> Genesis::CreateNewGlobals(
Handle<FunctionTemplateInfo> global_constructor(
FunctionTemplateInfo::cast(data->constructor()), isolate());
global_proxy_function = ApiNatives::CreateApiFunction(
- isolate(), global_constructor, factory()->the_hole_value(),
- JS_GLOBAL_PROXY_TYPE);
+ isolate(), isolate()->native_context(), global_constructor,
+ factory()->the_hole_value(), JS_GLOBAL_PROXY_TYPE);
}
global_proxy_function->initial_map().set_is_access_check_needed(true);
global_proxy_function->initial_map().set_may_have_interesting_symbols(true);
@@ -2450,11 +2453,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Handle<JSFunction> fun =
SimpleInstallFunction(isolate_, prototype, "exec",
Builtins::kRegExpPrototypeExec, 1, true);
- // Check that index of "exec" function in JSRegExp is correct.
+ native_context()->set_regexp_exec_function(*fun);
DCHECK_EQ(JSRegExp::kExecFunctionDescriptorIndex,
prototype->map().LastAdded());
-
- native_context()->set_regexp_exec_function(*fun);
}
SimpleInstallGetter(isolate_, prototype, factory->dotAll_string(),
@@ -2481,35 +2482,50 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
SimpleInstallFunction(isolate_, prototype, "test",
Builtins::kRegExpPrototypeTest, 1, true);
- InstallFunctionAtSymbol(isolate_, prototype, factory->match_symbol(),
- "[Symbol.match]", Builtins::kRegExpPrototypeMatch,
- 1, true);
- DCHECK_EQ(JSRegExp::kSymbolMatchFunctionDescriptorIndex,
- prototype->map().LastAdded());
-
- InstallFunctionAtSymbol(isolate_, prototype, factory->match_all_symbol(),
- "[Symbol.matchAll]",
- Builtins::kRegExpPrototypeMatchAll, 1, true);
- DCHECK_EQ(JSRegExp::kSymbolMatchAllFunctionDescriptorIndex,
- prototype->map().LastAdded());
-
- InstallFunctionAtSymbol(isolate_, prototype, factory->replace_symbol(),
- "[Symbol.replace]",
- Builtins::kRegExpPrototypeReplace, 2, false);
- DCHECK_EQ(JSRegExp::kSymbolReplaceFunctionDescriptorIndex,
- prototype->map().LastAdded());
-
- InstallFunctionAtSymbol(isolate_, prototype, factory->search_symbol(),
- "[Symbol.search]",
- Builtins::kRegExpPrototypeSearch, 1, true);
- DCHECK_EQ(JSRegExp::kSymbolSearchFunctionDescriptorIndex,
- prototype->map().LastAdded());
-
- InstallFunctionAtSymbol(isolate_, prototype, factory->split_symbol(),
- "[Symbol.split]", Builtins::kRegExpPrototypeSplit,
- 2, false);
- DCHECK_EQ(JSRegExp::kSymbolSplitFunctionDescriptorIndex,
- prototype->map().LastAdded());
+ {
+ Handle<JSFunction> fun = InstallFunctionAtSymbol(
+ isolate_, prototype, factory->match_symbol(), "[Symbol.match]",
+ Builtins::kRegExpPrototypeMatch, 1, true);
+ native_context()->set_regexp_match_function(*fun);
+ DCHECK_EQ(JSRegExp::kSymbolMatchFunctionDescriptorIndex,
+ prototype->map().LastAdded());
+ }
+
+ {
+ Handle<JSFunction> fun = InstallFunctionAtSymbol(
+ isolate_, prototype, factory->match_all_symbol(),
+ "[Symbol.matchAll]", Builtins::kRegExpPrototypeMatchAll, 1, true);
+ native_context()->set_regexp_match_all_function(*fun);
+ DCHECK_EQ(JSRegExp::kSymbolMatchAllFunctionDescriptorIndex,
+ prototype->map().LastAdded());
+ }
+
+ {
+ Handle<JSFunction> fun = InstallFunctionAtSymbol(
+ isolate_, prototype, factory->replace_symbol(), "[Symbol.replace]",
+ Builtins::kRegExpPrototypeReplace, 2, false);
+ native_context()->set_regexp_replace_function(*fun);
+ DCHECK_EQ(JSRegExp::kSymbolReplaceFunctionDescriptorIndex,
+ prototype->map().LastAdded());
+ }
+
+ {
+ Handle<JSFunction> fun = InstallFunctionAtSymbol(
+ isolate_, prototype, factory->search_symbol(), "[Symbol.search]",
+ Builtins::kRegExpPrototypeSearch, 1, true);
+ native_context()->set_regexp_search_function(*fun);
+ DCHECK_EQ(JSRegExp::kSymbolSearchFunctionDescriptorIndex,
+ prototype->map().LastAdded());
+ }
+
+ {
+ Handle<JSFunction> fun = InstallFunctionAtSymbol(
+ isolate_, prototype, factory->split_symbol(), "[Symbol.split]",
+ Builtins::kRegExpPrototypeSplit, 2, false);
+ native_context()->set_regexp_split_function(*fun);
+ DCHECK_EQ(JSRegExp::kSymbolSplitFunctionDescriptorIndex,
+ prototype->map().LastAdded());
+ }
Handle<Map> prototype_map(prototype->map(), isolate());
Map::SetShouldBeFastPrototypeMap(prototype_map, true, isolate_);
@@ -4246,8 +4262,9 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_namespace_exports)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_private_methods)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_dynamic_import)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_meta)
-EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_numeric_separator)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_sequence)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_optional_chaining)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_nullish)
#ifdef V8_INTL_SUPPORT
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_intl_add_calendar_numbering_system)
diff --git a/deps/v8/src/init/isolate-allocator.cc b/deps/v8/src/init/isolate-allocator.cc
index 85ef1f4d83..6a9b4c33cd 100644
--- a/deps/v8/src/init/isolate-allocator.cc
+++ b/deps/v8/src/init/isolate-allocator.cc
@@ -47,7 +47,7 @@ Address IsolateAllocator::InitReservation() {
size_t reservation_size = kPtrComprHeapReservationSize;
size_t base_alignment = kPtrComprIsolateRootAlignment;
- const int kMaxAttempts = 3;
+ const int kMaxAttempts = 4;
for (int attempt = 0; attempt < kMaxAttempts; ++attempt) {
Address hint = RoundDown(reinterpret_cast<Address>(
platform_page_allocator->GetRandomMmapAddr()),
@@ -72,35 +72,44 @@ Address IsolateAllocator::InitReservation() {
// Fuchsia does not respect given hints so as a workaround we will use
// overreserved address space region instead of trying to re-reserve
// a subregion.
- if (padded_reservation.InVM(address, reservation_size)) {
- reservation_ = std::move(padded_reservation);
- return address;
- }
+ bool overreserve = true;
#else
- // Now free the padded reservation and immediately try to reserve an exact
- // region at aligned address. We have to do this dancing because the
- // reservation address requirement is more complex than just a certain
- // alignment and not all operating systems support freeing parts of reserved
- // address space regions.
- padded_reservation.Free();
-
- VirtualMemory reservation(platform_page_allocator, reservation_size,
- reinterpret_cast<void*>(address));
- if (!reservation.IsReserved()) break;
-
- // The reservation could still be somewhere else but we can accept it
- // if the reservation has the required alignment.
- Address aligned_address =
- RoundUp(reservation.address() + kPtrComprIsolateRootBias,
- base_alignment) -
- kPtrComprIsolateRootBias;
+ // For the last attempt use the overreserved region to avoid an OOM crash.
+ // This case can happen if there are many isolates being created in
+ // parallel that race for reserving the regions.
+ bool overreserve = (attempt == kMaxAttempts - 1);
+#endif
- if (reservation.address() == aligned_address) {
- reservation_ = std::move(reservation);
- CHECK_EQ(reservation_.size(), reservation_size);
- return aligned_address;
+ if (overreserve) {
+ if (padded_reservation.InVM(address, reservation_size)) {
+ reservation_ = std::move(padded_reservation);
+ return address;
+ }
+ } else {
+ // Now free the padded reservation and immediately try to reserve an exact
+ // region at aligned address. We have to do this dancing because the
+ // reservation address requirement is more complex than just a certain
+ // alignment and not all operating systems support freeing parts of
+ // reserved address space regions.
+ padded_reservation.Free();
+
+ VirtualMemory reservation(platform_page_allocator, reservation_size,
+ reinterpret_cast<void*>(address));
+ if (!reservation.IsReserved()) break;
+
+ // The reservation could still be somewhere else but we can accept it
+ // if the reservation has the required alignment.
+ Address aligned_address =
+ RoundUp(reservation.address() + kPtrComprIsolateRootBias,
+ base_alignment) -
+ kPtrComprIsolateRootBias;
+
+ if (reservation.address() == aligned_address) {
+ reservation_ = std::move(reservation);
+ CHECK_EQ(reservation_.size(), reservation_size);
+ return aligned_address;
+ }
}
-#endif
}
V8::FatalProcessOutOfMemory(nullptr,
"Failed to reserve memory for new V8 Isolate");
diff --git a/deps/v8/src/init/setup-isolate-deserialize.cc b/deps/v8/src/init/setup-isolate-deserialize.cc
index 8a73ff0c8a..ff0268d3c8 100644
--- a/deps/v8/src/init/setup-isolate-deserialize.cc
+++ b/deps/v8/src/init/setup-isolate-deserialize.cc
@@ -7,7 +7,6 @@
#include "src/base/logging.h"
#include "src/execution/isolate.h"
#include "src/interpreter/interpreter.h"
-#include "src/objects/objects-inl.h"
#include "src/utils/ostreams.h"
namespace v8 {
diff --git a/deps/v8/src/init/v8.cc b/deps/v8/src/init/v8.cc
index 19ad57038f..15eb929332 100644
--- a/deps/v8/src/init/v8.cc
+++ b/deps/v8/src/init/v8.cc
@@ -90,6 +90,13 @@ void V8::InitializeOncePerProcessImpl() {
FLAG_expose_wasm = false;
}
+ // The --jitless and --interpreted-frames-native-stack flags are incompatible
+ // since the latter requires code generation while the former prohibits code
+ // generation.
+ CHECK_WITH_MSG(!FLAG_interpreted_frames_native_stack || !FLAG_jitless,
+ "The --jitless and --interpreted-frames-native-stack flags "
+ "are incompatible.");
+
base::OS::Initialize(FLAG_hard_abort, FLAG_gc_fake_mmap);
if (FLAG_random_seed) SetRandomMmapSeed(FLAG_random_seed);
diff --git a/deps/v8/src/inspector/DEPS b/deps/v8/src/inspector/DEPS
index e5fa06fd54..f72dcce0a9 100644
--- a/deps/v8/src/inspector/DEPS
+++ b/deps/v8/src/inspector/DEPS
@@ -6,6 +6,7 @@ include_rules = [
"+src/base/logging.h",
"+src/base/macros.h",
"+src/base/memory.h",
+ "+src/base/optional.h",
"+src/base/platform/platform.h",
"+src/base/platform/mutex.h",
"+src/base/safe_conversions.h",
diff --git a/deps/v8/src/inspector/OWNERS b/deps/v8/src/inspector/OWNERS
index a979205084..92422c0a88 100644
--- a/deps/v8/src/inspector/OWNERS
+++ b/deps/v8/src/inspector/OWNERS
@@ -5,6 +5,6 @@ kozyatinskiy@chromium.org
pfeldman@chromium.org
yangguo@chromium.org
-per-file PRESUBMIT.py=file://INFRA_OWNERS
+per-file PRESUBMIT.py=file:../../INFRA_OWNERS
# COMPONENT: Platform>DevTools>JavaScript
diff --git a/deps/v8/src/inspector/injected-script.cc b/deps/v8/src/inspector/injected-script.cc
index ad91a8e65e..18a10285dd 100644
--- a/deps/v8/src/inspector/injected-script.cc
+++ b/deps/v8/src/inspector/injected-script.cc
@@ -50,8 +50,8 @@
namespace v8_inspector {
namespace {
-static const char kGlobalHandleLabel[] = "DevTools console";
-static bool isResolvableNumberLike(String16 query) {
+const char kGlobalHandleLabel[] = "DevTools console";
+bool isResolvableNumberLike(String16 query) {
return query == "Infinity" || query == "-Infinity" || query == "NaN";
}
} // namespace
@@ -220,8 +220,13 @@ class InjectedScript::ProtocolPromiseHandler {
: 0)
.setColumnNumber(
stack && !stack->isEmpty() ? stack->topColumnNumber() : 0)
- .setException(wrappedValue->clone())
.build();
+ response = scope.injectedScript()->addExceptionToDetails(
+ result, exceptionDetails.get(), m_objectGroup);
+ if (!response.isSuccess()) {
+ callback->sendFailure(response);
+ return;
+ }
if (stack)
exceptionDetails->setStackTrace(
stack->buildInspectorObjectImpl(m_inspector->debugger()));
@@ -289,8 +294,7 @@ Response InjectedScript::getProperties(
PropertyAccumulator accumulator(&mirrors);
if (!ValueMirror::getProperties(context, object, ownProperties,
accessorPropertiesOnly, &accumulator)) {
- return createExceptionDetails(tryCatch, groupName, wrapMode,
- exceptionDetails);
+ return createExceptionDetails(tryCatch, groupName, exceptionDetails);
}
for (const PropertyMirror& mirror : mirrors) {
std::unique_ptr<PropertyDescriptor> descriptor =
@@ -489,14 +493,18 @@ std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
&limit, &limit, &preview);
if (!preview) return nullptr;
- std::unordered_set<String16> selectedColumns;
+ std::vector<String16> selectedColumns;
+ std::unordered_set<String16> columnSet;
v8::Local<v8::Array> v8Columns;
if (maybeColumns.ToLocal(&v8Columns)) {
for (uint32_t i = 0; i < v8Columns->Length(); ++i) {
v8::Local<v8::Value> column;
if (v8Columns->Get(context, i).ToLocal(&column) && column->IsString()) {
- selectedColumns.insert(
- toProtocolString(isolate, column.As<v8::String>()));
+ String16 name = toProtocolString(isolate, column.As<v8::String>());
+ if (columnSet.find(name) == columnSet.end()) {
+ columnSet.insert(name);
+ selectedColumns.push_back(name);
+ }
}
}
}
@@ -505,14 +513,18 @@ std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
*preview->getProperties()) {
ObjectPreview* columnPreview = column->getValuePreview(nullptr);
if (!columnPreview) continue;
-
- auto filtered = v8::base::make_unique<Array<PropertyPreview>>();
+ // Use raw pointer here since the lifetime of each PropertyPreview is
+ // ensured by columnPreview. This saves an additional clone.
+ std::unordered_map<String16, PropertyPreview*> columnMap;
for (const std::unique_ptr<PropertyPreview>& property :
*columnPreview->getProperties()) {
- if (selectedColumns.find(property->getName()) !=
- selectedColumns.end()) {
- filtered->emplace_back(property->clone());
- }
+ if (columnSet.find(property->getName()) == columnSet.end()) continue;
+ columnMap[property->getName()] = property.get();
+ }
+ auto filtered = v8::base::make_unique<Array<PropertyPreview>>();
+ for (const String16& column : selectedColumns) {
+ if (columnMap.find(column) == columnMap.end()) continue;
+ filtered->push_back(columnMap[column]->clone());
}
columnPreview->setProperties(std::move(filtered));
}
@@ -632,9 +644,25 @@ Response InjectedScript::resolveCallArgument(
return Response::OK();
}
+Response InjectedScript::addExceptionToDetails(
+ v8::Local<v8::Value> exception,
+ protocol::Runtime::ExceptionDetails* exceptionDetails,
+ const String16& objectGroup) {
+ if (exception.IsEmpty()) return Response::OK();
+ std::unique_ptr<protocol::Runtime::RemoteObject> wrapped;
+ Response response =
+ wrapObject(exception, objectGroup,
+ exception->IsNativeError() ? WrapMode::kNoPreview
+ : WrapMode::kWithPreview,
+ &wrapped);
+ if (!response.isSuccess()) return response;
+ exceptionDetails->setException(std::move(wrapped));
+ return Response::OK();
+}
+
Response InjectedScript::createExceptionDetails(
const v8::TryCatch& tryCatch, const String16& objectGroup,
- WrapMode wrapMode, Maybe<protocol::Runtime::ExceptionDetails>* result) {
+ Maybe<protocol::Runtime::ExceptionDetails>* result) {
if (!tryCatch.HasCaught()) return Response::InternalError();
v8::Local<v8::Message> message = tryCatch.Message();
v8::Local<v8::Value> exception = tryCatch.Exception();
@@ -667,16 +695,9 @@ Response InjectedScript::createExceptionDetails(
->createStackTrace(stackTrace)
->buildInspectorObjectImpl(m_context->inspector()->debugger()));
}
- if (!exception.IsEmpty()) {
- std::unique_ptr<protocol::Runtime::RemoteObject> wrapped;
- Response response =
- wrapObject(exception, objectGroup,
- exception->IsNativeError() ? WrapMode::kNoPreview
- : WrapMode::kWithPreview,
- &wrapped);
- if (!response.isSuccess()) return response;
- exceptionDetails->setException(std::move(wrapped));
- }
+ Response response =
+ addExceptionToDetails(exception, exceptionDetails.get(), objectGroup);
+ if (!response.isSuccess()) return response;
*result = std::move(exceptionDetails);
return Response::OK();
}
@@ -709,8 +730,7 @@ Response InjectedScript::wrapEvaluateResult(
if (!response.isSuccess()) return response;
// We send exception in result for compatibility reasons, even though it's
// accessible through exceptionDetails.exception.
- response = createExceptionDetails(tryCatch, objectGroup, wrapMode,
- exceptionDetails);
+ response = createExceptionDetails(tryCatch, objectGroup, exceptionDetails);
if (!response.isSuccess()) return response;
}
return Response::OK();
diff --git a/deps/v8/src/inspector/injected-script.h b/deps/v8/src/inspector/injected-script.h
index 03c743e1cd..d007e9121e 100644
--- a/deps/v8/src/inspector/injected-script.h
+++ b/deps/v8/src/inspector/injected-script.h
@@ -117,7 +117,7 @@ class InjectedScript final {
v8::Local<v8::Value>* result);
Response createExceptionDetails(
- const v8::TryCatch&, const String16& groupName, WrapMode wrapMode,
+ const v8::TryCatch&, const String16& groupName,
Maybe<protocol::Runtime::ExceptionDetails>* result);
Response wrapEvaluateResult(
v8::MaybeLocal<v8::Value> maybeResultValue, const v8::TryCatch&,
@@ -219,6 +219,10 @@ class InjectedScript final {
void discardEvaluateCallbacks();
std::unique_ptr<EvaluateCallback> takeEvaluateCallback(
EvaluateCallback* callback);
+ Response addExceptionToDetails(
+ v8::Local<v8::Value> exception,
+ protocol::Runtime::ExceptionDetails* exceptionDetails,
+ const String16& objectGroup);
InspectedContext* m_context;
int m_sessionId;
diff --git a/deps/v8/src/inspector/v8-runtime-agent-impl.cc b/deps/v8/src/inspector/v8-runtime-agent-impl.cc
index fd2d35abd7..a8aee0b7f3 100644
--- a/deps/v8/src/inspector/v8-runtime-agent-impl.cc
+++ b/deps/v8/src/inspector/v8-runtime-agent-impl.cc
@@ -490,7 +490,7 @@ Response V8RuntimeAgentImpl::compileScript(
if (!isOk) {
if (scope.tryCatch().HasCaught()) {
response = scope.injectedScript()->createExceptionDetails(
- scope.tryCatch(), String16(), WrapMode::kNoPreview, exceptionDetails);
+ scope.tryCatch(), String16(), exceptionDetails);
if (!response.isSuccess()) return response;
return Response::OK();
} else {
diff --git a/deps/v8/src/inspector/value-mirror.cc b/deps/v8/src/inspector/value-mirror.cc
index 3ab9085c44..9edfbc1a21 100644
--- a/deps/v8/src/inspector/value-mirror.cc
+++ b/deps/v8/src/inspector/value-mirror.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <cmath>
+#include "src/base/optional.h"
#include "src/debug/debug-interface.h"
#include "src/inspector/v8-debugger.h"
#include "src/inspector/v8-inspector-impl.h"
@@ -199,37 +200,57 @@ String16 descriptionForRegExp(v8::Isolate* isolate,
enum class ErrorType { kNative, kClient };
+// Build a description from an exception using the following rules:
+// * Usually return the stack trace found in the {stack} property.
+// * If the stack trace does not start with the class name of the passed
+// exception, try to build a description from the class name, the
+// {message} property and the rest of the stack trace.
+// (The stack trace is only used if {message} was also found in
+// said stack trace).
String16 descriptionForError(v8::Local<v8::Context> context,
v8::Local<v8::Object> object, ErrorType type) {
v8::Isolate* isolate = context->GetIsolate();
v8::TryCatch tryCatch(isolate);
String16 className = toProtocolString(isolate, object->GetConstructorName());
- v8::Local<v8::Value> stackValue;
- if (!object->Get(context, toV8String(isolate, "stack"))
- .ToLocal(&stackValue) ||
- !stackValue->IsString()) {
- return className;
- }
- String16 stack = toProtocolString(isolate, stackValue.As<v8::String>());
- String16 description = stack;
- if (type == ErrorType::kClient) {
- if (stack.substring(0, className.length()) != className) {
- v8::Local<v8::Value> messageValue;
- if (!object->Get(context, toV8String(isolate, "message"))
- .ToLocal(&messageValue) ||
- !messageValue->IsString()) {
- return stack;
- }
- String16 message = toProtocolStringWithTypeCheck(isolate, messageValue);
- size_t index = stack.find(message);
- String16 stackWithoutMessage =
- index != String16::kNotFound
- ? stack.substring(index + message.length())
- : String16();
- description = className + ": " + message + stackWithoutMessage;
+
+ v8::base::Optional<String16> stack;
+ {
+ v8::Local<v8::Value> stackValue;
+ if (object->Get(context, toV8String(isolate, "stack"))
+ .ToLocal(&stackValue) &&
+ stackValue->IsString()) {
+ stack = toProtocolString(isolate, stackValue.As<v8::String>());
}
}
- return description;
+
+ if (type == ErrorType::kNative && stack) return *stack;
+
+ if (stack && stack->substring(0, className.length()) == className) {
+ return *stack;
+ }
+
+ v8::base::Optional<String16> message;
+ {
+ v8::Local<v8::Value> messageValue;
+ if (object->Get(context, toV8String(isolate, "message"))
+ .ToLocal(&messageValue) &&
+ messageValue->IsString()) {
+ String16 msg = toProtocolStringWithTypeCheck(isolate, messageValue);
+ if (!msg.isEmpty()) message = msg;
+ }
+ }
+
+ if (!message) return stack ? *stack : className;
+
+ String16 description = className + ": " + *message;
+ if (!stack) return description;
+
+ DCHECK(stack && message);
+ size_t index = stack->find(*message);
+ String16 stackWithoutMessage =
+ index != String16::kNotFound ? stack->substring(index + message->length())
+ : String16();
+ return description + stackWithoutMessage;
}
String16 descriptionForObject(v8::Isolate* isolate,
@@ -1593,13 +1614,13 @@ std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context,
value, RemoteObject::SubtypeEnum::Regexp,
descriptionForRegExp(isolate, value.As<v8::RegExp>()));
}
- if (value->IsFunction()) {
- return v8::base::make_unique<FunctionMirror>(value);
- }
if (value->IsProxy()) {
return v8::base::make_unique<ObjectMirror>(
value, RemoteObject::SubtypeEnum::Proxy, "Proxy");
}
+ if (value->IsFunction()) {
+ return v8::base::make_unique<FunctionMirror>(value);
+ }
if (value->IsDate()) {
return v8::base::make_unique<ObjectMirror>(
value, RemoteObject::SubtypeEnum::Date,
diff --git a/deps/v8/src/interpreter/bytecode-array-builder.cc b/deps/v8/src/interpreter/bytecode-array-builder.cc
index b58fbd3309..cfc3eb36c1 100644
--- a/deps/v8/src/interpreter/bytecode-array-builder.cc
+++ b/deps/v8/src/interpreter/bytecode-array-builder.cc
@@ -23,7 +23,8 @@ class RegisterTransferWriter final
: public NON_EXPORTED_BASE(BytecodeRegisterOptimizer::BytecodeWriter),
public NON_EXPORTED_BASE(ZoneObject) {
public:
- RegisterTransferWriter(BytecodeArrayBuilder* builder) : builder_(builder) {}
+ explicit RegisterTransferWriter(BytecodeArrayBuilder* builder)
+ : builder_(builder) {}
~RegisterTransferWriter() override = default;
void EmitLdar(Register input) override { builder_->OutputLdarRaw(input); }
@@ -98,6 +99,19 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) {
isolate, register_count, parameter_count(), handler_table);
}
+#ifdef DEBUG
+int BytecodeArrayBuilder::CheckBytecodeMatches(Handle<BytecodeArray> bytecode) {
+ return bytecode_array_writer_.CheckBytecodeMatches(bytecode);
+}
+#endif
+
+Handle<ByteArray> BytecodeArrayBuilder::ToSourcePositionTable(
+ Isolate* isolate) {
+ DCHECK(RemainderOfBlockIsDead());
+
+ return bytecode_array_writer_.ToSourcePositionTable(isolate);
+}
+
BytecodeSourceInfo BytecodeArrayBuilder::CurrentSourcePosition(
Bytecode bytecode) {
BytecodeSourceInfo source_position;
@@ -810,10 +824,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
return *this;
}
-BytecodeArrayBuilder& BytecodeArrayBuilder::LoadIteratorProperty(
- Register object, int feedback_slot) {
- size_t name_index = IteratorSymbolConstantPoolEntry();
- OutputLdaNamedProperty(object, name_index, feedback_slot);
+BytecodeArrayBuilder& BytecodeArrayBuilder::GetIterator(Register object,
+ int feedback_slot) {
+ OutputGetIterator(object, feedback_slot);
return *this;
}
@@ -1159,6 +1172,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefined(
return *this;
}
+BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfUndefinedOrNull(
+ BytecodeLabel* label) {
+ DCHECK(!label->is_bound());
+ OutputJumpIfUndefinedOrNull(label, 0);
+ return *this;
+}
+
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotUndefined(
BytecodeLabel* label) {
DCHECK(!label->is_bound());
diff --git a/deps/v8/src/interpreter/bytecode-array-builder.h b/deps/v8/src/interpreter/bytecode-array-builder.h
index c5fd3111c0..06230f9270 100644
--- a/deps/v8/src/interpreter/bytecode-array-builder.h
+++ b/deps/v8/src/interpreter/bytecode-array-builder.h
@@ -21,6 +21,7 @@
namespace v8 {
namespace internal {
+class BytecodeArray;
class FeedbackVectorSpec;
class Isolate;
@@ -42,6 +43,11 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final {
SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS);
Handle<BytecodeArray> ToBytecodeArray(Isolate* isolate);
+ Handle<ByteArray> ToSourcePositionTable(Isolate* isolate);
+
+#ifdef DEBUG
+ int CheckBytecodeMatches(Handle<BytecodeArray> bytecode);
+#endif
// Get the number of parameters expected by function.
int parameter_count() const {
@@ -127,9 +133,10 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final {
// Keyed load property. The key should be in the accumulator.
BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot);
+
// Named load property of the @@iterator symbol.
- BytecodeArrayBuilder& LoadIteratorProperty(Register object,
- int feedback_slot);
+ BytecodeArrayBuilder& GetIterator(Register object, int feedback_slot);
+
// Named load property of the @@asyncIterator symbol.
BytecodeArrayBuilder& LoadAsyncIteratorProperty(Register object,
int feedback_slot);
@@ -418,6 +425,7 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final {
BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNotNull(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
+ BytecodeArrayBuilder& JumpIfUndefinedOrNull(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNotUndefined(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNil(BytecodeLabel* label, Token::Value op,
NilValue nil);
diff --git a/deps/v8/src/interpreter/bytecode-array-writer.cc b/deps/v8/src/interpreter/bytecode-array-writer.cc
index 3ecc5e1a89..3a459b4833 100644
--- a/deps/v8/src/interpreter/bytecode-array-writer.cc
+++ b/deps/v8/src/interpreter/bytecode-array-writer.cc
@@ -12,7 +12,6 @@
#include "src/interpreter/bytecode-source-info.h"
#include "src/interpreter/constant-array-builder.h"
#include "src/interpreter/handler-table-builder.h"
-#include "src/logging/log.h"
#include "src/objects/objects-inl.h"
namespace v8 {
@@ -50,19 +49,43 @@ Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
constant_pool);
bytecode_array->set_handler_table(*handler_table);
- if (!source_position_table_builder_.Lazy()) {
- Handle<ByteArray> source_position_table =
- source_position_table_builder_.Omit()
- ? ReadOnlyRoots(isolate).empty_byte_array_handle()
- : source_position_table_builder()->ToSourcePositionTable(isolate);
- bytecode_array->set_source_position_table(*source_position_table);
- LOG_CODE_EVENT(isolate, CodeLinePosInfoRecordEvent(
- bytecode_array->GetFirstBytecodeAddress(),
- *source_position_table));
- }
return bytecode_array;
}
+Handle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable(Isolate* isolate) {
+ DCHECK(!source_position_table_builder_.Lazy());
+ Handle<ByteArray> source_position_table =
+ source_position_table_builder_.Omit()
+ ? ReadOnlyRoots(isolate).empty_byte_array_handle()
+ : source_position_table_builder_.ToSourcePositionTable(isolate);
+ return source_position_table;
+}
+
+#ifdef DEBUG
+int BytecodeArrayWriter::CheckBytecodeMatches(Handle<BytecodeArray> bytecode) {
+ int mismatches = false;
+ int bytecode_size = static_cast<int>(bytecodes()->size());
+ const byte* bytecode_ptr = &bytecodes()->front();
+ if (bytecode_size != bytecode->length()) mismatches = true;
+
+ // If there's a mismatch only in the length of the bytecode (very unlikely)
+ // then the first mismatch will be the first extra bytecode.
+ int first_mismatch = std::min(bytecode_size, bytecode->length());
+ for (int i = 0; i < first_mismatch; ++i) {
+ if (bytecode_ptr[i] != bytecode->get(i)) {
+ mismatches = true;
+ first_mismatch = i;
+ break;
+ }
+ }
+
+ if (mismatches) {
+ return first_mismatch;
+ }
+ return -1;
+}
+#endif
+
void BytecodeArrayWriter::Write(BytecodeNode* node) {
DCHECK(!Bytecodes::IsJump(node->bytecode()));
@@ -286,6 +309,8 @@ Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
return Bytecode::kJumpIfUndefinedConstant;
case Bytecode::kJumpIfNotUndefined:
return Bytecode::kJumpIfNotUndefinedConstant;
+ case Bytecode::kJumpIfUndefinedOrNull:
+ return Bytecode::kJumpIfUndefinedOrNullConstant;
case Bytecode::kJumpIfJSReceiver:
return Bytecode::kJumpIfJSReceiverConstant;
default:
diff --git a/deps/v8/src/interpreter/bytecode-array-writer.h b/deps/v8/src/interpreter/bytecode-array-writer.h
index 5dac1b41c3..22f0296aff 100644
--- a/deps/v8/src/interpreter/bytecode-array-writer.h
+++ b/deps/v8/src/interpreter/bytecode-array-writer.h
@@ -55,6 +55,13 @@ class V8_EXPORT_PRIVATE BytecodeArrayWriter final {
int parameter_count,
Handle<ByteArray> handler_table);
+ Handle<ByteArray> ToSourcePositionTable(Isolate* isolate);
+
+#ifdef DEBUG
+ // Returns -1 if they match or the offset of the first mismatching byte.
+ int CheckBytecodeMatches(Handle<BytecodeArray> bytecode);
+#endif
+
bool RemainderOfBlockIsDead() const { return exit_seen_in_block_; }
private:
diff --git a/deps/v8/src/interpreter/bytecode-flags.h b/deps/v8/src/interpreter/bytecode-flags.h
index 0f87c5bdfb..40ee88d6eb 100644
--- a/deps/v8/src/interpreter/bytecode-flags.h
+++ b/deps/v8/src/interpreter/bytecode-flags.h
@@ -18,8 +18,8 @@ namespace interpreter {
class CreateArrayLiteralFlags {
public:
- class FlagsBits : public BitField8<int, 0, 5> {};
- class FastCloneSupportedBit : public BitField8<bool, FlagsBits::kNext, 1> {};
+ using FlagsBits = BitField8<int, 0, 5>;
+ using FastCloneSupportedBit = FlagsBits::Next<bool, 1>;
static uint8_t Encode(bool use_fast_shallow_clone, int runtime_flags);
@@ -29,8 +29,8 @@ class CreateArrayLiteralFlags {
class CreateObjectLiteralFlags {
public:
- class FlagsBits : public BitField8<int, 0, 5> {};
- class FastCloneSupportedBit : public BitField8<bool, FlagsBits::kNext, 1> {};
+ using FlagsBits = BitField8<int, 0, 5>;
+ using FastCloneSupportedBit = FlagsBits::Next<bool, 1>;
static uint8_t Encode(int runtime_flags, bool fast_clone_supported);
@@ -40,8 +40,8 @@ class CreateObjectLiteralFlags {
class CreateClosureFlags {
public:
- class PretenuredBit : public BitField8<bool, 0, 1> {};
- class FastNewClosureBit : public BitField8<bool, PretenuredBit::kNext, 1> {};
+ using PretenuredBit = BitField8<bool, 0, 1>;
+ using FastNewClosureBit = PretenuredBit::Next<bool, 1>;
static uint8_t Encode(bool pretenure, bool is_function_scope,
bool might_always_opt);
@@ -80,9 +80,8 @@ class TestTypeOfFlags {
class StoreLookupSlotFlags {
public:
- class LanguageModeBit : public BitField8<LanguageMode, 0, 1> {};
- class LookupHoistingModeBit
- : public BitField8<bool, LanguageModeBit::kNext, 1> {};
+ using LanguageModeBit = BitField8<LanguageMode, 0, 1>;
+ using LookupHoistingModeBit = LanguageModeBit::Next<bool, 1>;
STATIC_ASSERT(LanguageModeSize <= LanguageModeBit::kNumValues);
static uint8_t Encode(LanguageMode language_mode,
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc
index d3b27b4375..6a0b02d852 100644
--- a/deps/v8/src/interpreter/bytecode-generator.cc
+++ b/deps/v8/src/interpreter/bytecode-generator.cc
@@ -14,7 +14,9 @@
#include "src/interpreter/bytecode-jump-table.h"
#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-register-allocator.h"
+#include "src/interpreter/bytecode-register.h"
#include "src/interpreter/control-flow-builders.h"
+#include "src/logging/log.h"
#include "src/objects/debug-objects.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/objects-inl.h"
@@ -915,39 +917,67 @@ class BytecodeGenerator::IteratorRecord final {
Register next_;
};
+class BytecodeGenerator::OptionalChainNullLabelScope final {
+ public:
+ explicit OptionalChainNullLabelScope(BytecodeGenerator* bytecode_generator)
+ : bytecode_generator_(bytecode_generator),
+ labels_(bytecode_generator->zone()) {
+ prev_ = bytecode_generator_->optional_chaining_null_labels_;
+ bytecode_generator_->optional_chaining_null_labels_ = &labels_;
+ }
+
+ ~OptionalChainNullLabelScope() {
+ bytecode_generator_->optional_chaining_null_labels_ = prev_;
+ }
+
+ BytecodeLabels* labels() { return &labels_; }
+
+ private:
+ BytecodeGenerator* bytecode_generator_;
+ BytecodeLabels labels_;
+ BytecodeLabels* prev_;
+};
+
namespace {
+template <typename PropertyT>
+struct Accessors : public ZoneObject {
+ Accessors() : getter(nullptr), setter(nullptr) {}
+ PropertyT* getter;
+ PropertyT* setter;
+};
+
// A map from property names to getter/setter pairs allocated in the zone that
// also provides a way of accessing the pairs in the order they were first
// added so that the generated bytecode is always the same.
+template <typename PropertyT>
class AccessorTable
- : public base::TemplateHashMap<Literal, ObjectLiteral::Accessors,
+ : public base::TemplateHashMap<Literal, Accessors<PropertyT>,
bool (*)(void*, void*),
ZoneAllocationPolicy> {
public:
explicit AccessorTable(Zone* zone)
- : base::TemplateHashMap<Literal, ObjectLiteral::Accessors,
+ : base::TemplateHashMap<Literal, Accessors<PropertyT>,
bool (*)(void*, void*), ZoneAllocationPolicy>(
Literal::Match, ZoneAllocationPolicy(zone)),
zone_(zone) {}
- Iterator lookup(Literal* literal) {
- Iterator it = find(literal, true, ZoneAllocationPolicy(zone_));
+ Accessors<PropertyT>* LookupOrInsert(Literal* key) {
+ auto it = this->find(key, true, ZoneAllocationPolicy(zone_));
if (it->second == nullptr) {
- it->second = new (zone_) ObjectLiteral::Accessors();
- ordered_accessors_.push_back({literal, it->second});
+ it->second = new (zone_) Accessors<PropertyT>();
+ ordered_accessors_.push_back({key, it->second});
}
- return it;
+ return it->second;
}
- const std::vector<std::pair<Literal*, ObjectLiteral::Accessors*>>&
+ const std::vector<std::pair<Literal*, Accessors<PropertyT>*>>&
ordered_accessors() {
return ordered_accessors_;
}
private:
- std::vector<std::pair<Literal*, ObjectLiteral::Accessors*>>
- ordered_accessors_;
+ std::vector<std::pair<Literal*, Accessors<PropertyT>*>> ordered_accessors_;
Zone* zone_;
};
@@ -994,6 +1024,7 @@ BytecodeGenerator::BytecodeGenerator(
execution_context_(nullptr),
execution_result_(nullptr),
incoming_new_target_or_generator_(),
+ optional_chaining_null_labels_(nullptr),
dummy_feedback_slot_(feedback_spec(), FeedbackSlotKind::kCompareOp),
generator_jump_table_(nullptr),
suspend_count_(0),
@@ -1012,7 +1043,7 @@ Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(
#ifdef DEBUG
// Unoptimized compilation should be context-independent. Verify that we don't
// access the native context by nulling it out during finalization.
- SaveAndSwitchContext save(isolate, Context());
+ NullContextScope null_context_scope(isolate);
#endif
AllocateDeferredConstants(isolate, script);
@@ -1036,6 +1067,32 @@ Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(
return bytecode_array;
}
+Handle<ByteArray> BytecodeGenerator::FinalizeSourcePositionTable(
+ Isolate* isolate) {
+ DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
+#ifdef DEBUG
+ // Unoptimized compilation should be context-independent. Verify that we don't
+ // access the native context by nulling it out during finalization.
+ NullContextScope null_context_scope(isolate);
+#endif
+
+ Handle<ByteArray> source_position_table =
+ builder()->ToSourcePositionTable(isolate);
+
+ LOG_CODE_EVENT(isolate,
+ CodeLinePosInfoRecordEvent(
+ info_->bytecode_array()->GetFirstBytecodeAddress(),
+ *source_position_table));
+
+ return source_position_table;
+}
+
+#ifdef DEBUG
+int BytecodeGenerator::CheckBytecodeMatches(Handle<BytecodeArray> bytecode) {
+ return builder()->CheckBytecodeMatches(bytecode);
+}
+#endif
+
void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate,
Handle<Script> script) {
// Build global declaration pair arrays.
@@ -1383,8 +1440,9 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
break;
}
- DCHECK_IMPLIES(decl->fun()->ShouldEagerCompile(),
- IsInEagerLiterals(decl->fun(), *eager_inner_literals_));
+ DCHECK_IMPLIES(
+ eager_inner_literals_ != nullptr && decl->fun()->ShouldEagerCompile(),
+ IsInEagerLiterals(decl->fun(), *eager_inner_literals_));
}
void BytecodeGenerator::VisitModuleNamespaceImports() {
@@ -1755,14 +1813,13 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
return;
}
- BytecodeLabel subject_null_label, subject_undefined_label;
+ BytecodeLabel subject_undefined_label;
FeedbackSlot slot = feedback_spec()->AddForInSlot();
// Prepare the state for executing ForIn.
builder()->SetExpressionAsStatementPosition(stmt->subject());
VisitForAccumulatorValue(stmt->subject());
- builder()->JumpIfUndefined(&subject_undefined_label);
- builder()->JumpIfNull(&subject_null_label);
+ builder()->JumpIfUndefinedOrNull(&subject_undefined_label);
Register receiver = register_allocator()->NewRegister();
builder()->ToObject(receiver);
@@ -1804,7 +1861,6 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
builder()->StoreAccumulatorInRegister(index);
loop_builder.JumpToHeader(loop_depth_);
}
- builder()->Bind(&subject_null_label);
builder()->Bind(&subject_undefined_label);
}
@@ -1978,39 +2034,6 @@ bool BytecodeGenerator::ShouldOptimizeAsOneShot() const {
info()->literal()->is_oneshot_iife();
}
-void BytecodeGenerator::BuildPrivateClassMemberNameAssignment(
- ClassLiteral::Property* property) {
- DCHECK(property->is_private());
- switch (property->kind()) {
- case ClassLiteral::Property::FIELD: {
- // Create the private name symbols for fields during class
- // evaluation and store them on the context. These will be
- // used as keys later during instance or static initialization.
- RegisterAllocationScope private_name_register_scope(this);
- Register private_name = register_allocator()->NewRegister();
- VisitForRegisterValue(property->key(), private_name);
- builder()
- ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
- .StoreAccumulatorInRegister(private_name)
- .CallRuntime(Runtime::kCreatePrivateNameSymbol, private_name);
- DCHECK_NOT_NULL(property->private_name_var());
- BuildVariableAssignment(property->private_name_var(), Token::INIT,
- HoleCheckMode::kElided);
- break;
- }
- case ClassLiteral::Property::METHOD: {
- // Create the closures for private methods.
- VisitForAccumulatorValue(property->value());
- BuildVariableAssignment(property->private_name_var(), Token::INIT,
- HoleCheckMode::kElided);
- break;
- }
- default:
- // TODO(joyee): Private accessors are not yet supported.
- UNREACHABLE();
- }
-}
-
void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
size_t class_boilerplate_entry =
builder()->AllocateDeferredConstantPoolEntry();
@@ -2019,6 +2042,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
VisitDeclarations(expr->scope()->declarations());
Register class_constructor = register_allocator()->NewRegister();
+ AccessorTable<ClassLiteral::Property> private_accessors(zone());
{
RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewGrowableRegisterList();
@@ -2076,7 +2100,44 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
}
if (property->is_private()) {
- BuildPrivateClassMemberNameAssignment(property);
+ // Assign private class member's name variables.
+ switch (property->kind()) {
+ case ClassLiteral::Property::FIELD: {
+ // Create the private name symbols for fields during class
+ // evaluation and store them on the context. These will be
+ // used as keys later during instance or static initialization.
+ RegisterAllocationScope private_name_register_scope(this);
+ Register private_name = register_allocator()->NewRegister();
+ VisitForRegisterValue(property->key(), private_name);
+ builder()
+ ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
+ .StoreAccumulatorInRegister(private_name)
+ .CallRuntime(Runtime::kCreatePrivateNameSymbol, private_name);
+ DCHECK_NOT_NULL(property->private_name_var());
+ BuildVariableAssignment(property->private_name_var(), Token::INIT,
+ HoleCheckMode::kElided);
+ break;
+ }
+ case ClassLiteral::Property::METHOD: {
+ // Create the closures for private methods.
+ VisitForAccumulatorValue(property->value());
+ BuildVariableAssignment(property->private_name_var(), Token::INIT,
+ HoleCheckMode::kElided);
+ break;
+ }
+ case ClassLiteral::Property::GETTER: {
+ Literal* key = property->key()->AsLiteral();
+ DCHECK_NULL(private_accessors.LookupOrInsert(key)->getter);
+ private_accessors.LookupOrInsert(key)->getter = property;
+ break;
+ }
+ case ClassLiteral::Property::SETTER: {
+ Literal* key = property->key()->AsLiteral();
+ DCHECK_NULL(private_accessors.LookupOrInsert(key)->setter);
+ private_accessors.LookupOrInsert(key)->setter = property;
+ break;
+ }
+ }
// The private fields are initialized in the initializer function and
// the private brand for the private methods are initialized in the
// constructor instead.
@@ -2122,6 +2183,37 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
.CallRuntime(Runtime::kCreatePrivateNameSymbol, brand);
BuildVariableAssignment(expr->scope()->brand(), Token::INIT,
HoleCheckMode::kElided);
+
+ // Store the home object for any private methods that need
+ // them. We do this here once the prototype and brand symbol has
+ // been created. Private accessors have their home object set later
+ // when they are defined.
+ for (int i = 0; i < expr->properties()->length(); i++) {
+ RegisterAllocationScope register_scope(this);
+ ClassLiteral::Property* property = expr->properties()->at(i);
+ if (property->NeedsHomeObjectOnClassPrototype()) {
+ Register func = register_allocator()->NewRegister();
+ BuildVariableLoad(property->private_name_var(), HoleCheckMode::kElided);
+ builder()->StoreAccumulatorInRegister(func);
+ VisitSetHomeObject(func, prototype, property);
+ }
+ }
+
+ // Define accessors, using only a single call to the runtime for each pair
+ // of corresponding getters and setters.
+ for (auto accessors : private_accessors.ordered_accessors()) {
+ RegisterAllocationScope inner_register_scope(this);
+ RegisterList accessors_reg = register_allocator()->NewRegisterList(2);
+ ClassLiteral::Property* getter = accessors.second->getter;
+ ClassLiteral::Property* setter = accessors.second->setter;
+ VisitLiteralAccessor(prototype, getter, accessors_reg[0]);
+ VisitLiteralAccessor(prototype, setter, accessors_reg[1]);
+ builder()->CallRuntime(Runtime::kCreatePrivateAccessors, accessors_reg);
+ Variable* var = getter != nullptr ? getter->private_name_var()
+ : setter->private_name_var();
+ DCHECK_NOT_NULL(var);
+ BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided);
+ }
}
if (expr->instance_members_initializer_function() != nullptr) {
@@ -2241,12 +2333,13 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement(
}
}
-void BytecodeGenerator::BuildThrowPrivateMethodWriteError(
- const AstRawString* name) {
+void BytecodeGenerator::BuildInvalidPropertyAccess(MessageTemplate tmpl,
+ Property* property) {
RegisterAllocationScope register_scope(this);
+ const AstRawString* name = property->key()->AsVariableProxy()->raw_name();
RegisterList args = register_allocator()->NewRegisterList(2);
builder()
- ->LoadLiteral(Smi::FromEnum(MessageTemplate::kInvalidPrivateMethodWrite))
+ ->LoadLiteral(Smi::FromEnum(tmpl))
.StoreAccumulatorInRegister(args[0])
.LoadLiteral(name)
.StoreAccumulatorInRegister(args[1])
@@ -2437,7 +2530,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
// Store computed values into the literal.
- AccessorTable accessor_table(zone());
+ AccessorTable<ObjectLiteral::Property> accessor_table(zone());
for (; property_index < expr->properties()->length(); property_index++) {
ObjectLiteral::Property* property = expr->properties()->at(property_index);
if (property->is_computed_name()) break;
@@ -2506,12 +2599,12 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
case ObjectLiteral::Property::GETTER:
if (property->emit_store()) {
- accessor_table.lookup(key)->second->getter = property;
+ accessor_table.LookupOrInsert(key)->getter = property;
}
break;
case ObjectLiteral::Property::SETTER:
if (property->emit_store()) {
- accessor_table.lookup(key)->second->setter = property;
+ accessor_table.LookupOrInsert(key)->setter = property;
}
break;
}
@@ -2524,8 +2617,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
RegisterList args = register_allocator()->NewRegisterList(5);
builder()->MoveRegister(literal, args[0]);
VisitForRegisterValue(accessors.first, args[1]);
- VisitObjectLiteralAccessor(literal, accessors.second->getter, args[2]);
- VisitObjectLiteralAccessor(literal, accessors.second->setter, args[3]);
+ VisitLiteralAccessor(literal, accessors.second->getter, args[2]);
+ VisitLiteralAccessor(literal, accessors.second->setter, args[3]);
builder()
->LoadLiteral(Smi::FromInt(NONE))
.StoreAccumulatorInRegister(args[4])
@@ -3017,6 +3110,7 @@ void BytecodeGenerator::BuildThrowIfHole(Variable* variable) {
void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
Token::Value op) {
+ DCHECK(!IsPrivateMethodOrAccessorVariableMode(variable->mode()));
if (variable->is_this() && variable->mode() == VariableMode::kConst &&
op == Token::INIT) {
// Perform an initialization check for 'this'. 'this' variable is the
@@ -3201,10 +3295,10 @@ BytecodeGenerator::AssignmentLhsData::NamedSuperProperty(
}
// static
BytecodeGenerator::AssignmentLhsData
-BytecodeGenerator::AssignmentLhsData::PrivateMethod(Register object,
- const AstRawString* name) {
- return AssignmentLhsData(PRIVATE_METHOD, nullptr, RegisterList(), object,
- Register(), nullptr, name);
+BytecodeGenerator::AssignmentLhsData::PrivateMethodOrAccessor(
+ AssignType type, Property* property) {
+ return AssignmentLhsData(type, property, RegisterList(), Register(),
+ Register(), nullptr, nullptr);
}
// static
BytecodeGenerator::AssignmentLhsData
@@ -3237,12 +3331,12 @@ BytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs(
Register key = VisitForRegisterValue(property->key());
return AssignmentLhsData::KeyedProperty(object, key);
}
- case PRIVATE_METHOD: {
+ case PRIVATE_METHOD:
+ case PRIVATE_GETTER_ONLY:
+ case PRIVATE_SETTER_ONLY:
+ case PRIVATE_GETTER_AND_SETTER: {
DCHECK(!property->IsSuperAccess());
- AccumulatorPreservingScope scope(this, accumulator_preserving_mode);
- Register object = VisitForRegisterValue(property->obj());
- const AstRawString* name = property->key()->AsVariableProxy()->raw_name();
- return AssignmentLhsData::PrivateMethod(object, name);
+ return AssignmentLhsData::PrivateMethodOrAccessor(assign_type, property);
}
case NAMED_SUPER_PROPERTY: {
AccumulatorPreservingScope scope(this, accumulator_preserving_mode);
@@ -3316,8 +3410,7 @@ void BytecodeGenerator::BuildFinalizeIteration(
ast_string_constants()->return_string(),
feedback_index(feedback_spec()->AddLoadICSlot()))
.StoreAccumulatorInRegister(method)
- .JumpIfUndefined(iterator_is_done.New())
- .JumpIfNull(iterator_is_done.New());
+ .JumpIfUndefinedOrNull(iterator_is_done.New());
{
RegisterAllocationScope register_scope(this);
@@ -3625,22 +3718,6 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
LookupHoistingMode lookup_hoisting_mode) {
RegisterAllocationScope scope(this);
- // if (value === null || value === undefined)
- // throw new TypeError(kNonCoercible);
- //
- // TODO(leszeks): Eliminate check if value is known to be non-null (e.g.
- // an object literal).
- BytecodeLabel is_null_or_undefined, not_null_or_undefined;
- builder()
- ->JumpIfNull(&is_null_or_undefined)
- .JumpIfNotUndefined(&not_null_or_undefined);
-
- {
- builder()->Bind(&is_null_or_undefined);
- builder()->SetExpressionPosition(pattern);
- builder()->CallRuntime(Runtime::kThrowPatternAssignmentNonCoercible);
- }
-
// Store the assignment value in a register.
Register value;
RegisterList rest_runtime_callargs;
@@ -3651,7 +3728,34 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
} else {
value = register_allocator()->NewRegister();
}
- builder()->Bind(&not_null_or_undefined).StoreAccumulatorInRegister(value);
+ builder()->StoreAccumulatorInRegister(value);
+
+ // if (value === null || value === undefined)
+ // throw new TypeError(kNonCoercible);
+ //
+ // Since the first property access on null/undefined will also trigger a
+ // TypeError, we can elide this check. The exception is when there are no
+ // properties and no rest property (this is an empty literal), or when the
+ // first property is a computed name and accessing it can have side effects.
+ //
+ // TODO(leszeks): Also eliminate this check if the value is known to be
+ // non-null (e.g. an object literal).
+ if (pattern->properties()->is_empty() ||
+ (pattern->properties()->at(0)->is_computed_name() &&
+ pattern->properties()->at(0)->kind() != ObjectLiteralProperty::SPREAD)) {
+ BytecodeLabel is_null_or_undefined, not_null_or_undefined;
+ builder()
+ ->JumpIfUndefinedOrNull(&is_null_or_undefined)
+ .Jump(&not_null_or_undefined);
+
+ {
+ builder()->Bind(&is_null_or_undefined);
+ builder()->SetExpressionPosition(pattern);
+ builder()->CallRuntime(Runtime::kThrowPatternAssignmentNonCoercible,
+ value);
+ }
+ builder()->Bind(&not_null_or_undefined);
+ }
int i = 0;
for (ObjectLiteralProperty* pattern_property : *pattern->properties()) {
@@ -3799,7 +3903,27 @@ void BytecodeGenerator::BuildAssignment(
break;
}
case PRIVATE_METHOD: {
- BuildThrowPrivateMethodWriteError(lhs_data.name());
+ BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateMethodWrite,
+ lhs_data.expr()->AsProperty());
+ break;
+ }
+ case PRIVATE_GETTER_ONLY: {
+ BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateSetterAccess,
+ lhs_data.expr()->AsProperty());
+ break;
+ }
+ case PRIVATE_SETTER_ONLY:
+ case PRIVATE_GETTER_AND_SETTER: {
+ Register value = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(value);
+ Property* property = lhs_data.expr()->AsProperty();
+ Register object = VisitForRegisterValue(property->obj());
+ Register key = VisitForRegisterValue(property->key());
+ BuildPrivateBrandCheck(property, object);
+ BuildPrivateSetterAccess(object, key, value);
+ if (!execution_result()->IsEffect()) {
+ builder()->LoadAccumulatorWithRegister(value);
+ }
break;
}
}
@@ -3847,11 +3971,16 @@ void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) {
lhs_data.super_property_args().Truncate(3));
break;
}
- case PRIVATE_METHOD: {
- BuildThrowPrivateMethodWriteError(lhs_data.name());
+ case PRIVATE_METHOD:
+ case PRIVATE_GETTER_ONLY:
+ case PRIVATE_SETTER_ONLY:
+ case PRIVATE_GETTER_AND_SETTER: {
+ // ({ #foo: name } = obj) is currently syntactically invalid.
+ UNREACHABLE();
break;
}
}
+
BinaryOperation* binop = expr->AsCompoundAssignment()->binary_operation();
FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
if (expr->value()->IsSmiLiteral()) {
@@ -4284,7 +4413,14 @@ void BytecodeGenerator::VisitThrow(Throw* expr) {
}
void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
+ if (property->is_optional_chain_link()) {
+ DCHECK_NOT_NULL(optional_chaining_null_labels_);
+ builder()->LoadAccumulatorWithRegister(obj).JumpIfUndefinedOrNull(
+ optional_chaining_null_labels_->New());
+ }
+
AssignType property_kind = Property::GetAssignType(property);
+
switch (property_kind) {
case NON_PROPERTY:
UNREACHABLE();
@@ -4308,18 +4444,20 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
case KEYED_SUPER_PROPERTY:
VisitKeyedSuperPropertyLoad(property, Register::invalid_value());
break;
+ case PRIVATE_SETTER_ONLY: {
+ BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateGetterAccess,
+ property);
+ break;
+ }
+ case PRIVATE_GETTER_ONLY:
+ case PRIVATE_GETTER_AND_SETTER: {
+ Register key = VisitForRegisterValue(property->key());
+ BuildPrivateBrandCheck(property, obj);
+ BuildPrivateGetterAccess(obj, key);
+ break;
+ }
case PRIVATE_METHOD: {
- Variable* private_name = property->key()->AsVariableProxy()->var();
-
- // Perform the brand check.
- DCHECK(private_name->requires_brand_check());
- ClassScope* scope = private_name->scope()->AsClassScope();
- Variable* brand = scope->brand();
- BuildVariableLoadForAccumulatorValue(brand, HoleCheckMode::kElided);
- builder()->SetExpressionPosition(property);
- builder()->LoadKeyedProperty(
- obj, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
-
+ BuildPrivateBrandCheck(property, obj);
// In the case of private methods, property->key() is the function to be
// loaded (stored in a context slot), so load this directly.
VisitForAccumulatorValue(property->key());
@@ -4328,6 +4466,48 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
}
}
+void BytecodeGenerator::BuildPrivateGetterAccess(Register object,
+ Register accessor_pair) {
+ RegisterAllocationScope scope(this);
+ Register accessor = register_allocator()->NewRegister();
+ RegisterList args = register_allocator()->NewRegisterList(1);
+
+ builder()
+ ->CallRuntime(Runtime::kLoadPrivateGetter, accessor_pair)
+ .StoreAccumulatorInRegister(accessor)
+ .MoveRegister(object, args[0])
+ .CallProperty(accessor, args,
+ feedback_index(feedback_spec()->AddCallICSlot()));
+}
+
+void BytecodeGenerator::BuildPrivateSetterAccess(Register object,
+ Register accessor_pair,
+ Register value) {
+ RegisterAllocationScope scope(this);
+ Register accessor = register_allocator()->NewRegister();
+ RegisterList args = register_allocator()->NewRegisterList(2);
+
+ builder()
+ ->CallRuntime(Runtime::kLoadPrivateSetter, accessor_pair)
+ .StoreAccumulatorInRegister(accessor)
+ .MoveRegister(object, args[0])
+ .MoveRegister(value, args[1])
+ .CallProperty(accessor, args,
+ feedback_index(feedback_spec()->AddCallICSlot()));
+}
+
+void BytecodeGenerator::BuildPrivateBrandCheck(Property* property,
+ Register object) {
+ Variable* private_name = property->key()->AsVariableProxy()->var();
+ DCHECK(private_name->requires_brand_check());
+ ClassScope* scope = private_name->scope()->AsClassScope();
+ Variable* brand = scope->brand();
+ BuildVariableLoadForAccumulatorValue(brand, HoleCheckMode::kElided);
+ builder()->SetExpressionPosition(property);
+ builder()->LoadKeyedProperty(
+ object, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
+}
+
void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj,
Property* expr,
Register destination) {
@@ -4376,6 +4556,16 @@ void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property,
}
}
+void BytecodeGenerator::VisitOptionalChain(OptionalChain* expr) {
+ BytecodeLabel done;
+ OptionalChainNullLabelScope label_scope(this);
+ VisitForAccumulatorValue(expr->expression());
+ builder()->Jump(&done);
+ label_scope.labels()->Bind(builder());
+ builder()->LoadUndefined();
+ builder()->Bind(&done);
+}
+
void BytecodeGenerator::VisitProperty(Property* expr) {
AssignType property_kind = Property::GetAssignType(expr);
if (property_kind != NAMED_SUPER_PROPERTY &&
@@ -4509,6 +4699,12 @@ void BytecodeGenerator::VisitCall(Call* expr) {
UNREACHABLE();
}
+ if (expr->is_optional_chain_link()) {
+ DCHECK_NOT_NULL(optional_chaining_null_labels_);
+ builder()->LoadAccumulatorWithRegister(callee).JumpIfUndefinedOrNull(
+ optional_chaining_null_labels_->New());
+ }
+
// Evaluate all arguments to the function call and store in sequential args
// registers.
VisitArguments(expr->arguments(), &args);
@@ -4770,6 +4966,29 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* unary) {
Register object = VisitForRegisterValue(property->obj());
VisitForAccumulatorValue(property->key());
builder()->Delete(object, language_mode());
+ } else if (expr->IsOptionalChain()) {
+ Expression* expr_inner = expr->AsOptionalChain()->expression();
+ if (expr_inner->IsProperty()) {
+ Property* property = expr_inner->AsProperty();
+ DCHECK(!property->IsPrivateReference());
+ BytecodeLabel done;
+ OptionalChainNullLabelScope label_scope(this);
+ VisitForAccumulatorValue(property->obj());
+ if (property->is_optional_chain_link()) {
+ builder()->JumpIfUndefinedOrNull(label_scope.labels()->New());
+ }
+ Register object = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(object);
+ VisitForAccumulatorValue(property->key());
+ builder()->Delete(object, language_mode());
+ builder()->Jump(&done);
+ label_scope.labels()->Bind(builder());
+ builder()->LoadTrue();
+ builder()->Bind(&done);
+ } else {
+ VisitForEffect(expr);
+ builder()->LoadTrue();
+ }
} else if (expr->IsVariableProxy() &&
!expr->AsVariableProxy()->is_new_target()) {
// Delete of an unqualified identifier is allowed in sloppy mode but is
@@ -4875,8 +5094,25 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
break;
}
case PRIVATE_METHOD: {
- BuildThrowPrivateMethodWriteError(
- property->key()->AsVariableProxy()->raw_name());
+ BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateMethodWrite,
+ property);
+ return;
+ }
+ case PRIVATE_GETTER_ONLY: {
+ BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateSetterAccess,
+ property);
+ return;
+ }
+ case PRIVATE_SETTER_ONLY: {
+ BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateGetterAccess,
+ property);
+ return;
+ }
+ case PRIVATE_GETTER_AND_SETTER: {
+ object = VisitForRegisterValue(property->obj());
+ key = VisitForRegisterValue(property->key());
+ BuildPrivateBrandCheck(property, object);
+ BuildPrivateGetterAccess(object, key);
break;
}
}
@@ -4945,9 +5181,18 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
.CallRuntime(Runtime::kStoreKeyedToSuper, super_property_args);
break;
}
+ case PRIVATE_SETTER_ONLY:
+ case PRIVATE_GETTER_ONLY:
case PRIVATE_METHOD: {
- BuildThrowPrivateMethodWriteError(
- property->key()->AsVariableProxy()->raw_name());
+ UNREACHABLE();
+ }
+ case PRIVATE_GETTER_AND_SETTER: {
+ Register value = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(value);
+ BuildPrivateSetterAccess(object, key, value);
+ if (!execution_result()->IsEffect()) {
+ builder()->LoadAccumulatorWithRegister(value);
+ }
break;
}
}
@@ -4969,6 +5214,9 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
case Token::AND:
VisitLogicalAndExpression(binop);
break;
+ case Token::NULLISH:
+ VisitNullishExpression(binop);
+ break;
default:
VisitArithmeticExpression(binop);
break;
@@ -4986,6 +5234,9 @@ void BytecodeGenerator::VisitNaryOperation(NaryOperation* expr) {
case Token::AND:
VisitNaryLogicalAndExpression(expr);
break;
+ case Token::NULLISH:
+ VisitNaryNullishExpression(expr);
+ break;
default:
VisitNaryArithmeticExpression(expr);
break;
@@ -5128,39 +5379,37 @@ void BytecodeGenerator::VisitImportCallExpression(ImportCallExpression* expr) {
}
void BytecodeGenerator::BuildGetIterator(IteratorType hint) {
- RegisterList args = register_allocator()->NewRegisterList(1);
- Register method = register_allocator()->NewRegister();
- Register obj = args[0];
-
if (hint == IteratorType::kAsync) {
+ RegisterAllocationScope scope(this);
+
+ Register obj = register_allocator()->NewRegister();
+ Register method = register_allocator()->NewRegister();
+
// Set method to GetMethod(obj, @@asyncIterator)
builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty(
obj, feedback_index(feedback_spec()->AddLoadICSlot()));
- BytecodeLabel async_iterator_undefined, async_iterator_null, done;
- // TODO(ignition): Add a single opcode for JumpIfNullOrUndefined
- builder()->JumpIfUndefined(&async_iterator_undefined);
- builder()->JumpIfNull(&async_iterator_null);
+ BytecodeLabel async_iterator_undefined, done;
+ builder()->JumpIfUndefinedOrNull(&async_iterator_undefined);
// Let iterator be Call(method, obj)
builder()->StoreAccumulatorInRegister(method).CallProperty(
- method, args, feedback_index(feedback_spec()->AddCallICSlot()));
+ method, RegisterList(obj),
+ feedback_index(feedback_spec()->AddCallICSlot()));
// If Type(iterator) is not Object, throw a TypeError exception.
builder()->JumpIfJSReceiver(&done);
builder()->CallRuntime(Runtime::kThrowSymbolAsyncIteratorInvalid);
builder()->Bind(&async_iterator_undefined);
- builder()->Bind(&async_iterator_null);
// If method is undefined,
// Let syncMethod be GetMethod(obj, @@iterator)
builder()
- ->LoadIteratorProperty(obj,
- feedback_index(feedback_spec()->AddLoadICSlot()))
+ ->GetIterator(obj, feedback_index(feedback_spec()->AddLoadICSlot()))
.StoreAccumulatorInRegister(method);
// Let syncIterator be Call(syncMethod, obj)
- builder()->CallProperty(method, args,
+ builder()->CallProperty(method, RegisterList(obj),
feedback_index(feedback_spec()->AddCallICSlot()));
// Return CreateAsyncFromSyncIterator(syncIterator)
@@ -5171,16 +5420,22 @@ void BytecodeGenerator::BuildGetIterator(IteratorType hint) {
builder()->Bind(&done);
} else {
- // Let method be GetMethod(obj, @@iterator).
- builder()
- ->StoreAccumulatorInRegister(obj)
- .LoadIteratorProperty(obj,
- feedback_index(feedback_spec()->AddLoadICSlot()))
- .StoreAccumulatorInRegister(method);
+ {
+ RegisterAllocationScope scope(this);
- // Let iterator be Call(method, obj).
- builder()->CallProperty(method, args,
- feedback_index(feedback_spec()->AddCallICSlot()));
+ Register obj = register_allocator()->NewRegister();
+ Register method = register_allocator()->NewRegister();
+
+ // Let method be GetMethod(obj, @@iterator).
+ builder()
+ ->StoreAccumulatorInRegister(obj)
+ .GetIterator(obj, feedback_index(feedback_spec()->AddLoadICSlot()))
+ .StoreAccumulatorInRegister(method);
+
+ // Let iterator be Call(method, obj).
+ builder()->CallProperty(method, RegisterList(obj),
+ feedback_index(feedback_spec()->AddCallICSlot()));
+ }
// If Type(iterator) is not Object, throw a TypeError exception.
BytecodeLabel no_type_error;
@@ -5241,8 +5496,7 @@ void BytecodeGenerator::BuildCallIteratorMethod(Register iterator,
FeedbackSlot slot = feedback_spec()->AddLoadICSlot();
builder()
->LoadNamedProperty(iterator, method_name, feedback_index(slot))
- .JumpIfUndefined(if_notcalled->New())
- .JumpIfNull(if_notcalled->New())
+ .JumpIfUndefinedOrNull(if_notcalled->New())
.StoreAccumulatorInRegister(method)
.CallProperty(method, receiver_and_args,
feedback_index(feedback_spec()->AddCallICSlot()))
@@ -5375,14 +5629,16 @@ void BytecodeGenerator::VisitNaryCommaExpression(NaryOperation* expr) {
void BytecodeGenerator::VisitLogicalTestSubExpression(
Token::Value token, Expression* expr, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, int coverage_slot) {
- DCHECK(token == Token::OR || token == Token::AND);
+ DCHECK(token == Token::OR || token == Token::AND || token == Token::NULLISH);
BytecodeLabels test_next(zone());
if (token == Token::OR) {
VisitForTest(expr, then_labels, &test_next, TestFallthrough::kElse);
- } else {
- DCHECK_EQ(Token::AND, token);
+ } else if (token == Token::AND) {
VisitForTest(expr, &test_next, else_labels, TestFallthrough::kThen);
+ } else {
+ DCHECK_EQ(Token::NULLISH, token);
+ VisitForNullishTest(expr, then_labels, &test_next, else_labels);
}
test_next.Bind(builder());
@@ -5392,7 +5648,7 @@ void BytecodeGenerator::VisitLogicalTestSubExpression(
void BytecodeGenerator::VisitLogicalTest(Token::Value token, Expression* left,
Expression* right,
int right_coverage_slot) {
- DCHECK(token == Token::OR || token == Token::AND);
+ DCHECK(token == Token::OR || token == Token::AND || token == Token::NULLISH);
TestResultScope* test_result = execution_result()->AsTest();
BytecodeLabels* then_labels = test_result->then_labels();
BytecodeLabels* else_labels = test_result->else_labels();
@@ -5407,7 +5663,7 @@ void BytecodeGenerator::VisitLogicalTest(Token::Value token, Expression* left,
void BytecodeGenerator::VisitNaryLogicalTest(
Token::Value token, NaryOperation* expr,
const NaryCodeCoverageSlots* coverage_slots) {
- DCHECK(token == Token::OR || token == Token::AND);
+ DCHECK(token == Token::OR || token == Token::AND || token == Token::NULLISH);
DCHECK_GT(expr->subsequent_length(), 0);
TestResultScope* test_result = execution_result()->AsTest();
@@ -5463,6 +5719,27 @@ bool BytecodeGenerator::VisitLogicalAndSubExpression(Expression* expr,
return false;
}
+bool BytecodeGenerator::VisitNullishSubExpression(Expression* expr,
+ BytecodeLabels* end_labels,
+ int coverage_slot) {
+ if (expr->IsLiteralButNotNullOrUndefined()) {
+ VisitForAccumulatorValue(expr);
+ end_labels->Bind(builder());
+ return true;
+ } else if (!expr->IsNullOrUndefinedLiteral()) {
+ VisitForAccumulatorValue(expr);
+ BytecodeLabel is_null_or_undefined;
+ builder()
+ ->JumpIfUndefinedOrNull(&is_null_or_undefined)
+ .Jump(end_labels->New());
+ builder()->Bind(&is_null_or_undefined);
+ }
+
+ BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
+
+ return false;
+}
+
void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
@@ -5585,6 +5862,68 @@ void BytecodeGenerator::VisitNaryLogicalAndExpression(NaryOperation* expr) {
}
}
+void BytecodeGenerator::VisitNullishExpression(BinaryOperation* binop) {
+ Expression* left = binop->left();
+ Expression* right = binop->right();
+
+ int right_coverage_slot =
+ AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight);
+
+ if (execution_result()->IsTest()) {
+ TestResultScope* test_result = execution_result()->AsTest();
+ if (left->IsLiteralButNotNullOrUndefined() && left->ToBooleanIsTrue()) {
+ builder()->Jump(test_result->NewThenLabel());
+ } else if (left->IsNullOrUndefinedLiteral() &&
+ right->IsNullOrUndefinedLiteral()) {
+ BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot);
+ builder()->Jump(test_result->NewElseLabel());
+ } else {
+ VisitLogicalTest(Token::NULLISH, left, right, right_coverage_slot);
+ }
+ test_result->SetResultConsumedByTest();
+ } else {
+ BytecodeLabels end_labels(zone());
+ if (VisitNullishSubExpression(left, &end_labels, right_coverage_slot)) {
+ return;
+ }
+ VisitForAccumulatorValue(right);
+ end_labels.Bind(builder());
+ }
+}
+
+void BytecodeGenerator::VisitNaryNullishExpression(NaryOperation* expr) {
+ Expression* first = expr->first();
+ DCHECK_GT(expr->subsequent_length(), 0);
+
+ NaryCodeCoverageSlots coverage_slots(this, expr);
+
+ if (execution_result()->IsTest()) {
+ TestResultScope* test_result = execution_result()->AsTest();
+ if (first->IsLiteralButNotNullOrUndefined() && first->ToBooleanIsTrue()) {
+ builder()->Jump(test_result->NewThenLabel());
+ } else {
+ VisitNaryLogicalTest(Token::NULLISH, expr, &coverage_slots);
+ }
+ test_result->SetResultConsumedByTest();
+ } else {
+ BytecodeLabels end_labels(zone());
+ if (VisitNullishSubExpression(first, &end_labels,
+ coverage_slots.GetSlotFor(0))) {
+ return;
+ }
+ for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
+ if (VisitNullishSubExpression(expr->subsequent(i), &end_labels,
+ coverage_slots.GetSlotFor(i + 1))) {
+ return;
+ }
+ }
+ // We have to visit the last value even if it's nullish, because we need its
+ // actual value.
+ VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1));
+ end_labels.Bind(builder());
+ }
+}
+
void BytecodeGenerator::BuildNewLocalActivationContext() {
ValueResultScope value_execution_result(this);
Scope* scope = closure_scope();
@@ -5682,8 +6021,9 @@ void BytecodeGenerator::BuildNewLocalCatchContext(Scope* scope) {
builder()->CreateCatchContext(exception, scope);
}
-void BytecodeGenerator::VisitObjectLiteralAccessor(
- Register home_object, ObjectLiteralProperty* property, Register value_out) {
+void BytecodeGenerator::VisitLiteralAccessor(Register home_object,
+ LiteralProperty* property,
+ Register value_out) {
if (property == nullptr) {
builder()->LoadNull().StoreAccumulatorInRegister(value_out);
} else {
@@ -5929,6 +6269,25 @@ void BytecodeGenerator::VisitForTest(Expression* expr,
}
}
+// Visits the expression |expr| for testing its nullish value and jumping to the
+// |then| or |other| label depending on value and short-circuit semantics
+void BytecodeGenerator::VisitForNullishTest(Expression* expr,
+ BytecodeLabels* then_labels,
+ BytecodeLabels* test_next_labels,
+ BytecodeLabels* else_labels) {
+ // Nullish short circuits on undefined or null, otherwise we fall back to
+ // BuildTest with no fallthrough.
+ // TODO(joshualitt): We should do this in a TestResultScope.
+ TypeHint type_hint = VisitForAccumulatorValue(expr);
+ ToBooleanMode mode = ToBooleanModeFromTypeHint(type_hint);
+
+ // Skip the nullish shortcircuit if we already have a boolean.
+ if (mode != ToBooleanMode::kAlreadyBoolean) {
+ builder()->JumpIfUndefinedOrNull(test_next_labels->New());
+ }
+ BuildTest(mode, then_labels, else_labels, TestFallthrough::kNone);
+}
+
void BytecodeGenerator::VisitInSameTestExecutionScope(Expression* expr) {
DCHECK(execution_result()->IsTest());
{
diff --git a/deps/v8/src/interpreter/bytecode-generator.h b/deps/v8/src/interpreter/bytecode-generator.h
index b754d2c296..134b1b463a 100644
--- a/deps/v8/src/interpreter/bytecode-generator.h
+++ b/deps/v8/src/interpreter/bytecode-generator.h
@@ -18,6 +18,7 @@ namespace internal {
class AstNodeSourceRanges;
class AstStringConstants;
+class BytecodeArray;
class UnoptimizedCompilationInfo;
enum class SourceRangeKind;
@@ -38,6 +39,11 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void GenerateBytecode(uintptr_t stack_limit);
Handle<BytecodeArray> FinalizeBytecode(Isolate* isolate,
Handle<Script> script);
+ Handle<ByteArray> FinalizeSourcePositionTable(Isolate* isolate);
+
+#ifdef DEBUG
+ int CheckBytecodeMatches(Handle<BytecodeArray> bytecode);
+#endif
#define DECLARE_VISIT(type) void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
@@ -66,6 +72,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
class AccumulatorPreservingScope;
class TestResultScope;
class ValueResultScope;
+ class OptionalChainNullLabelScope;
using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
@@ -84,8 +91,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
Register object,
const AstRawString* name);
static AssignmentLhsData KeyedProperty(Register object, Register key);
- static AssignmentLhsData PrivateMethod(Register object,
- const AstRawString* name);
+ static AssignmentLhsData PrivateMethodOrAccessor(AssignType type,
+ Property* property);
static AssignmentLhsData NamedSuperProperty(
RegisterList super_property_args);
static AssignmentLhsData KeyedSuperProperty(
@@ -93,7 +100,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
AssignType assign_type() const { return assign_type_; }
Expression* expr() const {
- DCHECK_EQ(assign_type_, NON_PROPERTY);
+ DCHECK(assign_type_ == NON_PROPERTY || assign_type_ == PRIVATE_METHOD ||
+ assign_type_ == PRIVATE_GETTER_ONLY ||
+ assign_type_ == PRIVATE_SETTER_ONLY ||
+ assign_type_ == PRIVATE_GETTER_AND_SETTER);
return expr_;
}
Expression* object_expr() const {
@@ -101,8 +111,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
return object_expr_;
}
Register object() const {
- DCHECK(assign_type_ == NAMED_PROPERTY || assign_type_ == KEYED_PROPERTY ||
- assign_type_ == PRIVATE_METHOD);
+ DCHECK(assign_type_ == NAMED_PROPERTY || assign_type_ == KEYED_PROPERTY);
return object_;
}
Register key() const {
@@ -110,7 +119,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
return key_;
}
const AstRawString* name() const {
- DCHECK(assign_type_ == NAMED_PROPERTY || assign_type_ == PRIVATE_METHOD);
+ DCHECK(assign_type_ == NAMED_PROPERTY);
return name_;
}
RegisterList super_property_args() const {
@@ -159,12 +168,14 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitCommaExpression(BinaryOperation* binop);
void VisitLogicalOrExpression(BinaryOperation* binop);
void VisitLogicalAndExpression(BinaryOperation* binop);
+ void VisitNullishExpression(BinaryOperation* binop);
// Dispatched from VisitNaryOperation.
void VisitNaryArithmeticExpression(NaryOperation* expr);
void VisitNaryCommaExpression(NaryOperation* expr);
void VisitNaryLogicalOrExpression(NaryOperation* expr);
void VisitNaryLogicalAndExpression(NaryOperation* expr);
+ void VisitNaryNullishExpression(NaryOperation* expr);
// Dispatched from VisitUnaryOperation.
void VisitVoid(UnaryOperation* expr);
@@ -295,8 +306,11 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitArgumentsObject(Variable* variable);
void VisitRestArgumentsArray(Variable* rest);
void VisitCallSuper(Call* call);
- void BuildThrowPrivateMethodWriteError(const AstRawString* name);
- void BuildPrivateClassMemberNameAssignment(ClassLiteral::Property* property);
+ void BuildInvalidPropertyAccess(MessageTemplate tmpl, Property* property);
+ void BuildPrivateBrandCheck(Property* property, Register object);
+ void BuildPrivateGetterAccess(Register obj, Register access_pair);
+ void BuildPrivateSetterAccess(Register obj, Register access_pair,
+ Register value);
void BuildClassLiteral(ClassLiteral* expr, Register name);
void VisitClassLiteral(ClassLiteral* expr, Register name);
void VisitNewTargetVariable(Variable* variable);
@@ -308,9 +322,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitBlockDeclarationsAndStatements(Block* stmt);
void VisitSetHomeObject(Register value, Register home_object,
LiteralProperty* property);
- void VisitObjectLiteralAccessor(Register home_object,
- ObjectLiteralProperty* property,
- Register value_out);
+ void VisitLiteralAccessor(Register home_object, LiteralProperty* property,
+ Register value_out);
void VisitForInAssignment(Expression* expr);
void VisitModuleNamespaceImports();
@@ -320,6 +333,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
int right_coverage_slot);
void VisitNaryLogicalTest(Token::Value token, NaryOperation* expr,
const NaryCodeCoverageSlots* coverage_slots);
+
// Visit a (non-RHS) test for a logical op, which falls through if the test
// fails or jumps to the appropriate labels if it succeeds.
void VisitLogicalTestSubExpression(Token::Value token, Expression* expr,
@@ -334,6 +348,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
BytecodeLabels* end_labels,
int coverage_slot);
+ // Helper for binary and nary nullish op value expressions.
+ bool VisitNullishSubExpression(Expression* expr, BytecodeLabels* end_labels,
+ int coverage_slot);
+
// Visit the body of a loop iteration.
void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder);
@@ -375,6 +393,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitForEffect(Expression* expr);
void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, TestFallthrough fallthrough);
+ void VisitForNullishTest(Expression* expr, BytecodeLabels* then_labels,
+ BytecodeLabels* test_next_labels,
+ BytecodeLabels* else_labels);
void VisitInSameTestExecutionScope(Expression* expr);
@@ -489,6 +510,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
Register incoming_new_target_or_generator_;
+ BytecodeLabels* optional_chaining_null_labels_;
+
// Dummy feedback slot for compare operations, where we don't care about
// feedback
SharedFeedbackSlot dummy_feedback_slot_;
diff --git a/deps/v8/src/interpreter/bytecodes.h b/deps/v8/src/interpreter/bytecodes.h
index 591dfbe2b7..6802d53c95 100644
--- a/deps/v8/src/interpreter/bytecodes.h
+++ b/deps/v8/src/interpreter/bytecodes.h
@@ -298,6 +298,7 @@ namespace interpreter {
V(JumpIfNotNullConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfNotUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx) \
+ V(JumpIfUndefinedOrNullConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfJSReceiverConstant, AccumulatorUse::kRead, OperandType::kIdx) \
@@ -315,6 +316,7 @@ namespace interpreter {
V(JumpIfNotNull, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfUndefined, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfNotUndefined, AccumulatorUse::kRead, OperandType::kUImm) \
+ V(JumpIfUndefinedOrNull, AccumulatorUse::kRead, OperandType::kUImm) \
V(JumpIfJSReceiver, AccumulatorUse::kRead, OperandType::kUImm) \
\
/* Smi-table lookup for switch statements */ \
@@ -353,6 +355,9 @@ namespace interpreter {
V(ResumeGenerator, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegOutList, OperandType::kRegCount) \
\
+ /* Iterator protocol operations */ \
+ V(GetIterator, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kIdx) \
+ \
/* Debugger */ \
V(Debugger, AccumulatorUse::kNone) \
\
@@ -407,7 +412,8 @@ namespace interpreter {
V(JumpIfNotNull) \
V(JumpIfUndefined) \
V(JumpIfNotUndefined) \
- V(JumpIfJSReceiver) \
+ V(JumpIfUndefinedOrNull) \
+ V(JumpIfJSReceiver)
#define JUMP_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
JUMP_TOBOOLEAN_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
@@ -415,9 +421,10 @@ namespace interpreter {
V(JumpIfNotNullConstant) \
V(JumpIfUndefinedConstant) \
V(JumpIfNotUndefinedConstant) \
+ V(JumpIfUndefinedOrNullConstant) \
V(JumpIfTrueConstant) \
V(JumpIfFalseConstant) \
- V(JumpIfJSReceiverConstant) \
+ V(JumpIfJSReceiverConstant)
#define JUMP_CONSTANT_BYTECODE_LIST(V) \
JUMP_UNCONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
diff --git a/deps/v8/src/interpreter/interpreter-assembler.cc b/deps/v8/src/interpreter/interpreter-assembler.cc
index 7291ea1c35..f01821b565 100644
--- a/deps/v8/src/interpreter/interpreter-assembler.cc
+++ b/deps/v8/src/interpreter/interpreter-assembler.cc
@@ -31,14 +31,14 @@ InterpreterAssembler::InterpreterAssembler(CodeAssemblerState* state,
: CodeStubAssembler(state),
bytecode_(bytecode),
operand_scale_(operand_scale),
- VARIABLE_CONSTRUCTOR(interpreted_frame_pointer_,
- MachineType::PointerRepresentation()),
+ TVARIABLE_CONSTRUCTOR(interpreted_frame_pointer_),
VARIABLE_CONSTRUCTOR(
bytecode_array_, MachineRepresentation::kTagged,
Parameter(InterpreterDispatchDescriptor::kBytecodeArray)),
- VARIABLE_CONSTRUCTOR(
- bytecode_offset_, MachineType::PointerRepresentation(),
- Parameter(InterpreterDispatchDescriptor::kBytecodeOffset)),
+ TVARIABLE_CONSTRUCTOR(
+ bytecode_offset_,
+ UncheckedCast<IntPtrT>(
+ Parameter(InterpreterDispatchDescriptor::kBytecodeOffset))),
VARIABLE_CONSTRUCTOR(
dispatch_table_, MachineType::PointerRepresentation(),
Parameter(InterpreterDispatchDescriptor::kDispatchTable)),
@@ -48,17 +48,15 @@ InterpreterAssembler::InterpreterAssembler(CodeAssemblerState* state,
accumulator_use_(AccumulatorUse::kNone),
made_call_(false),
reloaded_frame_ptr_(false),
- bytecode_array_valid_(true),
- disable_stack_check_across_call_(false),
- stack_pointer_before_call_(nullptr) {
+ bytecode_array_valid_(true) {
#ifdef V8_TRACE_IGNITION
TraceBytecode(Runtime::kInterpreterTraceBytecodeEntry);
#endif
RegisterCallGenerationCallbacks([this] { CallPrologue(); },
[this] { CallEpilogue(); });
- // Save the bytecode offset immediately if bytecode will make a call along the
- // critical path, or it is a return bytecode.
+ // Save the bytecode offset immediately if bytecode will make a call along
+ // the critical path, or it is a return bytecode.
if (Bytecodes::MakesCallAlongCriticalPath(bytecode) ||
Bytecodes::Returns(bytecode)) {
SaveBytecodeOffset();
@@ -73,28 +71,28 @@ InterpreterAssembler::~InterpreterAssembler() {
UnregisterCallGenerationCallbacks();
}
-Node* InterpreterAssembler::GetInterpretedFramePointer() {
+TNode<RawPtrT> InterpreterAssembler::GetInterpretedFramePointer() {
if (!interpreted_frame_pointer_.IsBound()) {
- interpreted_frame_pointer_.Bind(LoadParentFramePointer());
+ interpreted_frame_pointer_ = LoadParentFramePointer();
} else if (Bytecodes::MakesCallAlongCriticalPath(bytecode_) && made_call_ &&
!reloaded_frame_ptr_) {
- interpreted_frame_pointer_.Bind(LoadParentFramePointer());
+ interpreted_frame_pointer_ = LoadParentFramePointer();
reloaded_frame_ptr_ = true;
}
return interpreted_frame_pointer_.value();
}
-Node* InterpreterAssembler::BytecodeOffset() {
+TNode<IntPtrT> InterpreterAssembler::BytecodeOffset() {
if (Bytecodes::MakesCallAlongCriticalPath(bytecode_) && made_call_ &&
(bytecode_offset_.value() ==
Parameter(InterpreterDispatchDescriptor::kBytecodeOffset))) {
- bytecode_offset_.Bind(ReloadBytecodeOffset());
+ bytecode_offset_ = ReloadBytecodeOffset();
}
return bytecode_offset_.value();
}
-Node* InterpreterAssembler::ReloadBytecodeOffset() {
- Node* offset = LoadAndUntagRegister(Register::bytecode_offset());
+TNode<IntPtrT> InterpreterAssembler::ReloadBytecodeOffset() {
+ TNode<IntPtrT> offset = LoadAndUntagRegister(Register::bytecode_offset());
if (operand_scale() != OperandScale::kSingle) {
// Add one to the offset such that it points to the actual bytecode rather
// than the Wide / ExtraWide prefix bytecode.
@@ -104,13 +102,31 @@ Node* InterpreterAssembler::ReloadBytecodeOffset() {
}
void InterpreterAssembler::SaveBytecodeOffset() {
- Node* offset = BytecodeOffset();
+ TNode<IntPtrT> bytecode_offset = BytecodeOffset();
if (operand_scale() != OperandScale::kSingle) {
- // Subtract one from the offset such that it points to the Wide / ExtraWide
- // prefix bytecode.
- offset = IntPtrSub(BytecodeOffset(), IntPtrConstant(1));
+ // Subtract one from the bytecode_offset such that it points to the Wide /
+ // ExtraWide prefix bytecode.
+ bytecode_offset = IntPtrSub(BytecodeOffset(), IntPtrConstant(1));
+ }
+ int store_offset =
+ Register::bytecode_offset().ToOperand() * kSystemPointerSize;
+ TNode<RawPtrT> base = GetInterpretedFramePointer();
+
+ if (SmiValuesAre32Bits()) {
+ int zero_offset = store_offset + 4;
+ int payload_offset = store_offset;
+#if V8_TARGET_LITTLE_ENDIAN
+ std::swap(zero_offset, payload_offset);
+#endif
+ StoreNoWriteBarrier(MachineRepresentation::kWord32, base,
+ IntPtrConstant(zero_offset), Int32Constant(0));
+ StoreNoWriteBarrier(MachineRepresentation::kWord32, base,
+ IntPtrConstant(payload_offset),
+ TruncateIntPtrToInt32(bytecode_offset));
+ } else {
+ StoreNoWriteBarrier(MachineRepresentation::kTaggedSigned, base,
+ IntPtrConstant(store_offset), SmiTag(bytecode_offset));
}
- StoreAndTagRegister(offset, Register::bytecode_offset());
}
Node* InterpreterAssembler::BytecodeArrayTaggedPointer() {
@@ -137,7 +153,7 @@ Node* InterpreterAssembler::GetAccumulatorUnchecked() {
return accumulator_.value();
}
-Node* InterpreterAssembler::GetAccumulator() {
+TNode<Object> InterpreterAssembler::GetAccumulator() {
DCHECK(Bytecodes::ReadsAccumulator(bytecode_));
accumulator_use_ = accumulator_use_ | AccumulatorUse::kRead;
return TaggedPoisonOnSpeculation(GetAccumulatorUnchecked());
@@ -149,20 +165,18 @@ void InterpreterAssembler::SetAccumulator(Node* value) {
accumulator_.Bind(value);
}
-Node* InterpreterAssembler::GetContext() {
- return LoadRegister(Register::current_context());
+TNode<Context> InterpreterAssembler::GetContext() {
+ return CAST(LoadRegister(Register::current_context()));
}
-void InterpreterAssembler::SetContext(Node* value) {
+void InterpreterAssembler::SetContext(TNode<Context> value) {
StoreRegister(value, Register::current_context());
}
-Node* InterpreterAssembler::GetContextAtDepth(Node* context, Node* depth) {
- Variable cur_context(this, MachineRepresentation::kTaggedPointer);
- cur_context.Bind(context);
-
- Variable cur_depth(this, MachineRepresentation::kWord32);
- cur_depth.Bind(depth);
+Node* InterpreterAssembler::GetContextAtDepth(TNode<Context> context,
+ TNode<Uint32T> depth) {
+ TVARIABLE(Context, cur_context, context);
+ TVARIABLE(Uint32T, cur_depth, depth);
Label context_found(this);
@@ -175,9 +189,9 @@ Node* InterpreterAssembler::GetContextAtDepth(Node* context, Node* depth) {
// Loop until the depth is 0.
BIND(&context_search);
{
- cur_depth.Bind(Int32Sub(cur_depth.value(), Int32Constant(1)));
- cur_context.Bind(
- LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX));
+ cur_depth = Unsigned(Int32Sub(cur_depth.value(), Int32Constant(1)));
+ cur_context =
+ CAST(LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX));
Branch(Word32Equal(cur_depth.value(), Int32Constant(0)), &context_found,
&context_search);
@@ -187,14 +201,10 @@ Node* InterpreterAssembler::GetContextAtDepth(Node* context, Node* depth) {
return cur_context.value();
}
-void InterpreterAssembler::GotoIfHasContextExtensionUpToDepth(Node* context,
- Node* depth,
- Label* target) {
- Variable cur_context(this, MachineRepresentation::kTaggedPointer);
- cur_context.Bind(context);
-
- Variable cur_depth(this, MachineRepresentation::kWord32);
- cur_depth.Bind(depth);
+void InterpreterAssembler::GotoIfHasContextExtensionUpToDepth(
+ TNode<Context> context, TNode<Uint32T> depth, Label* target) {
+ TVARIABLE(Context, cur_context, context);
+ TVARIABLE(Uint32T, cur_depth, depth);
Variable* context_search_loop_variables[2] = {&cur_depth, &cur_context};
Label context_search(this, 2, context_search_loop_variables);
@@ -207,62 +217,73 @@ void InterpreterAssembler::GotoIfHasContextExtensionUpToDepth(Node* context,
// eval, we could pass in a context chain bitmask to figure out which
// contexts actually need to be checked.
- Node* extension_slot =
+ TNode<Object> extension_slot =
LoadContextElement(cur_context.value(), Context::EXTENSION_INDEX);
// Jump to the target if the extension slot is not a hole.
- GotoIf(WordNotEqual(extension_slot, TheHoleConstant()), target);
+ GotoIf(TaggedNotEqual(extension_slot, TheHoleConstant()), target);
- cur_depth.Bind(Int32Sub(cur_depth.value(), Int32Constant(1)));
- cur_context.Bind(
- LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX));
+ cur_depth = Unsigned(Int32Sub(cur_depth.value(), Int32Constant(1)));
+ cur_context =
+ CAST(LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX));
GotoIf(Word32NotEqual(cur_depth.value(), Int32Constant(0)),
&context_search);
}
}
-Node* InterpreterAssembler::RegisterLocation(Node* reg_index) {
- return WordPoisonOnSpeculation(
- IntPtrAdd(GetInterpretedFramePointer(), RegisterFrameOffset(reg_index)));
+TNode<IntPtrT> InterpreterAssembler::RegisterLocation(Node* reg_index) {
+ return Signed(WordPoisonOnSpeculation(
+ IntPtrAdd(GetInterpretedFramePointer(), RegisterFrameOffset(reg_index))));
}
-Node* InterpreterAssembler::RegisterLocation(Register reg) {
+TNode<IntPtrT> InterpreterAssembler::RegisterLocation(Register reg) {
return RegisterLocation(IntPtrConstant(reg.ToOperand()));
}
-Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
- return TimesSystemPointerSize(index);
+TNode<IntPtrT> InterpreterAssembler::RegisterFrameOffset(Node* index) {
+ return Signed(TimesSystemPointerSize(index));
}
-Node* InterpreterAssembler::LoadRegister(Node* reg_index) {
+TNode<Object> InterpreterAssembler::LoadRegister(Node* reg_index) {
return LoadFullTagged(GetInterpretedFramePointer(),
RegisterFrameOffset(reg_index),
LoadSensitivity::kCritical);
}
-Node* InterpreterAssembler::LoadRegister(Register reg) {
+TNode<Object> InterpreterAssembler::LoadRegister(Register reg) {
return LoadFullTagged(GetInterpretedFramePointer(),
IntPtrConstant(reg.ToOperand() * kSystemPointerSize));
}
-Node* InterpreterAssembler::LoadAndUntagRegister(Register reg) {
- return LoadAndUntagSmi(GetInterpretedFramePointer(),
- reg.ToOperand() * kSystemPointerSize);
+TNode<IntPtrT> InterpreterAssembler::LoadAndUntagRegister(Register reg) {
+ TNode<RawPtrT> base = GetInterpretedFramePointer();
+ int index = reg.ToOperand() * kSystemPointerSize;
+ if (SmiValuesAre32Bits()) {
+#if V8_TARGET_LITTLE_ENDIAN
+ index += 4;
+#endif
+ return ChangeInt32ToIntPtr(
+ Load(MachineType::Int32(), base, IntPtrConstant(index)));
+ } else {
+ return SmiToIntPtr(
+ Load(MachineType::TaggedSigned(), base, IntPtrConstant(index)));
+ }
}
-Node* InterpreterAssembler::LoadRegisterAtOperandIndex(int operand_index) {
+TNode<Object> InterpreterAssembler::LoadRegisterAtOperandIndex(
+ int operand_index) {
return LoadRegister(
BytecodeOperandReg(operand_index, LoadSensitivity::kSafe));
}
-std::pair<Node*, Node*> InterpreterAssembler::LoadRegisterPairAtOperandIndex(
- int operand_index) {
+std::pair<TNode<Object>, TNode<Object>>
+InterpreterAssembler::LoadRegisterPairAtOperandIndex(int operand_index) {
DCHECK_EQ(OperandType::kRegPair,
Bytecodes::GetOperandType(bytecode_, operand_index));
Node* first_reg_index =
BytecodeOperandReg(operand_index, LoadSensitivity::kSafe);
- Node* second_reg_index = NextRegister(first_reg_index);
+ TNode<IntPtrT> second_reg_index = NextRegister(first_reg_index);
return std::make_pair(LoadRegister(first_reg_index),
LoadRegister(second_reg_index));
}
@@ -273,27 +294,27 @@ InterpreterAssembler::GetRegisterListAtOperandIndex(int operand_index) {
Bytecodes::GetOperandType(bytecode_, operand_index)));
DCHECK_EQ(OperandType::kRegCount,
Bytecodes::GetOperandType(bytecode_, operand_index + 1));
- Node* base_reg = RegisterLocation(
+ TNode<IntPtrT> base_reg = RegisterLocation(
BytecodeOperandReg(operand_index, LoadSensitivity::kSafe));
- Node* reg_count = BytecodeOperandCount(operand_index + 1);
+ TNode<Uint32T> reg_count = BytecodeOperandCount(operand_index + 1);
return RegListNodePair(base_reg, reg_count);
}
Node* InterpreterAssembler::LoadRegisterFromRegisterList(
const RegListNodePair& reg_list, int index) {
- Node* location = RegisterLocationInRegisterList(reg_list, index);
+ TNode<IntPtrT> location = RegisterLocationInRegisterList(reg_list, index);
// Location is already poisoned on speculation, so no need to poison here.
return LoadFullTagged(location);
}
-Node* InterpreterAssembler::RegisterLocationInRegisterList(
+TNode<IntPtrT> InterpreterAssembler::RegisterLocationInRegisterList(
const RegListNodePair& reg_list, int index) {
CSA_ASSERT(this,
Uint32GreaterThan(reg_list.reg_count(), Int32Constant(index)));
- Node* offset = RegisterFrameOffset(IntPtrConstant(index));
+ TNode<IntPtrT> offset = RegisterFrameOffset(IntPtrConstant(index));
// Register indexes are negative, so subtract index from base location to get
// location.
- return IntPtrSub(reg_list.base_reg_location(), offset);
+ return Signed(IntPtrSub(reg_list.base_reg_location(), offset));
}
void InterpreterAssembler::StoreRegister(Node* value, Register reg) {
@@ -307,11 +328,6 @@ void InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
RegisterFrameOffset(reg_index), value);
}
-void InterpreterAssembler::StoreAndTagRegister(Node* value, Register reg) {
- int offset = reg.ToOperand() * kSystemPointerSize;
- StoreAndTagSmi(GetInterpretedFramePointer(), offset, value);
-}
-
void InterpreterAssembler::StoreRegisterAtOperandIndex(Node* value,
int operand_index) {
StoreRegister(value,
@@ -326,7 +342,7 @@ void InterpreterAssembler::StoreRegisterPairAtOperandIndex(Node* value1,
Node* first_reg_index =
BytecodeOperandReg(operand_index, LoadSensitivity::kSafe);
StoreRegister(value1, first_reg_index);
- Node* second_reg_index = NextRegister(first_reg_index);
+ TNode<IntPtrT> second_reg_index = NextRegister(first_reg_index);
StoreRegister(value2, second_reg_index);
}
@@ -337,15 +353,15 @@ void InterpreterAssembler::StoreRegisterTripleAtOperandIndex(
Node* first_reg_index =
BytecodeOperandReg(operand_index, LoadSensitivity::kSafe);
StoreRegister(value1, first_reg_index);
- Node* second_reg_index = NextRegister(first_reg_index);
+ TNode<IntPtrT> second_reg_index = NextRegister(first_reg_index);
StoreRegister(value2, second_reg_index);
- Node* third_reg_index = NextRegister(second_reg_index);
+ TNode<IntPtrT> third_reg_index = NextRegister(second_reg_index);
StoreRegister(value3, third_reg_index);
}
-Node* InterpreterAssembler::NextRegister(Node* reg_index) {
+TNode<IntPtrT> InterpreterAssembler::NextRegister(Node* reg_index) {
// Register indexes are negative, so the next index is minus one.
- return IntPtrAdd(reg_index, IntPtrConstant(-1));
+ return Signed(IntPtrAdd(reg_index, IntPtrConstant(-1)));
}
Node* InterpreterAssembler::OperandOffset(int operand_index) {
@@ -353,27 +369,29 @@ Node* InterpreterAssembler::OperandOffset(int operand_index) {
Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()));
}
-Node* InterpreterAssembler::BytecodeOperandUnsignedByte(
+TNode<Uint8T> InterpreterAssembler::BytecodeOperandUnsignedByte(
int operand_index, LoadSensitivity needs_poisoning) {
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(OperandSize::kByte, Bytecodes::GetOperandSize(
bytecode_, operand_index, operand_scale()));
Node* operand_offset = OperandOffset(operand_index);
- return Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(),
- IntPtrAdd(BytecodeOffset(), operand_offset), needs_poisoning);
+ return Load<Uint8T>(BytecodeArrayTaggedPointer(),
+ IntPtrAdd(BytecodeOffset(), operand_offset),
+ needs_poisoning);
}
-Node* InterpreterAssembler::BytecodeOperandSignedByte(
+TNode<Int8T> InterpreterAssembler::BytecodeOperandSignedByte(
int operand_index, LoadSensitivity needs_poisoning) {
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(OperandSize::kByte, Bytecodes::GetOperandSize(
bytecode_, operand_index, operand_scale()));
Node* operand_offset = OperandOffset(operand_index);
- return Load(MachineType::Int8(), BytecodeArrayTaggedPointer(),
- IntPtrAdd(BytecodeOffset(), operand_offset), needs_poisoning);
+ return Load<Int8T>(BytecodeArrayTaggedPointer(),
+ IntPtrAdd(BytecodeOffset(), operand_offset),
+ needs_poisoning);
}
-Node* InterpreterAssembler::BytecodeOperandReadUnaligned(
+TNode<Word32T> InterpreterAssembler::BytecodeOperandReadUnaligned(
int relative_offset, MachineType result_type,
LoadSensitivity needs_poisoning) {
static const int kMaxCount = 4;
@@ -406,26 +424,28 @@ Node* InterpreterAssembler::BytecodeOperandReadUnaligned(
// Read the most signicant bytecode into bytes[0] and then in order
// down to least significant in bytes[count - 1].
DCHECK_LE(count, kMaxCount);
- Node* bytes[kMaxCount];
+ TNode<Word32T> bytes[kMaxCount];
for (int i = 0; i < count; i++) {
MachineType machine_type = (i == 0) ? msb_type : MachineType::Uint8();
- Node* offset = IntPtrConstant(relative_offset + msb_offset + i * kStep);
- Node* array_offset = IntPtrAdd(BytecodeOffset(), offset);
- bytes[i] = Load(machine_type, BytecodeArrayTaggedPointer(), array_offset,
- needs_poisoning);
+ TNode<IntPtrT> offset =
+ IntPtrConstant(relative_offset + msb_offset + i * kStep);
+ TNode<WordT> array_offset = IntPtrAdd(BytecodeOffset(), offset);
+ bytes[i] =
+ UncheckedCast<Word32T>(Load(machine_type, BytecodeArrayTaggedPointer(),
+ array_offset, needs_poisoning));
}
// Pack LSB to MSB.
- Node* result = bytes[--count];
+ TNode<Word32T> result = bytes[--count];
for (int i = 1; --count >= 0; i++) {
- Node* shift = Int32Constant(i * kBitsPerByte);
- Node* value = Word32Shl(bytes[count], shift);
+ TNode<Int32T> shift = Int32Constant(i * kBitsPerByte);
+ TNode<Word32T> value = Word32Shl(bytes[count], shift);
result = Word32Or(value, result);
}
return result;
}
-Node* InterpreterAssembler::BytecodeOperandUnsignedShort(
+TNode<Uint16T> InterpreterAssembler::BytecodeOperandUnsignedShort(
int operand_index, LoadSensitivity needs_poisoning) {
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(
@@ -434,16 +454,17 @@ Node* InterpreterAssembler::BytecodeOperandUnsignedShort(
int operand_offset =
Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale());
if (TargetSupportsUnalignedAccess()) {
- return Load(MachineType::Uint16(), BytecodeArrayTaggedPointer(),
- IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)),
- needs_poisoning);
+ return Load<Uint16T>(
+ BytecodeArrayTaggedPointer(),
+ IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)),
+ needs_poisoning);
} else {
- return BytecodeOperandReadUnaligned(operand_offset, MachineType::Uint16(),
- needs_poisoning);
+ return UncheckedCast<Uint16T>(BytecodeOperandReadUnaligned(
+ operand_offset, MachineType::Uint16(), needs_poisoning));
}
}
-Node* InterpreterAssembler::BytecodeOperandSignedShort(
+TNode<Int16T> InterpreterAssembler::BytecodeOperandSignedShort(
int operand_index, LoadSensitivity needs_poisoning) {
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(
@@ -452,16 +473,17 @@ Node* InterpreterAssembler::BytecodeOperandSignedShort(
int operand_offset =
Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale());
if (TargetSupportsUnalignedAccess()) {
- return Load(MachineType::Int16(), BytecodeArrayTaggedPointer(),
- IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)),
- needs_poisoning);
+ return Load<Int16T>(
+ BytecodeArrayTaggedPointer(),
+ IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)),
+ needs_poisoning);
} else {
- return BytecodeOperandReadUnaligned(operand_offset, MachineType::Int16(),
- needs_poisoning);
+ return UncheckedCast<Int16T>(BytecodeOperandReadUnaligned(
+ operand_offset, MachineType::Int16(), needs_poisoning));
}
}
-Node* InterpreterAssembler::BytecodeOperandUnsignedQuad(
+TNode<Uint32T> InterpreterAssembler::BytecodeOperandUnsignedQuad(
int operand_index, LoadSensitivity needs_poisoning) {
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(OperandSize::kQuad, Bytecodes::GetOperandSize(
@@ -469,16 +491,17 @@ Node* InterpreterAssembler::BytecodeOperandUnsignedQuad(
int operand_offset =
Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale());
if (TargetSupportsUnalignedAccess()) {
- return Load(MachineType::Uint32(), BytecodeArrayTaggedPointer(),
- IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)),
- needs_poisoning);
+ return Load<Uint32T>(
+ BytecodeArrayTaggedPointer(),
+ IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)),
+ needs_poisoning);
} else {
- return BytecodeOperandReadUnaligned(operand_offset, MachineType::Uint32(),
- needs_poisoning);
+ return UncheckedCast<Uint32T>(BytecodeOperandReadUnaligned(
+ operand_offset, MachineType::Uint32(), needs_poisoning));
}
}
-Node* InterpreterAssembler::BytecodeOperandSignedQuad(
+TNode<Int32T> InterpreterAssembler::BytecodeOperandSignedQuad(
int operand_index, LoadSensitivity needs_poisoning) {
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(OperandSize::kQuad, Bytecodes::GetOperandSize(
@@ -486,16 +509,17 @@ Node* InterpreterAssembler::BytecodeOperandSignedQuad(
int operand_offset =
Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale());
if (TargetSupportsUnalignedAccess()) {
- return Load(MachineType::Int32(), BytecodeArrayTaggedPointer(),
- IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)),
- needs_poisoning);
+ return Load<Int32T>(
+ BytecodeArrayTaggedPointer(),
+ IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset)),
+ needs_poisoning);
} else {
- return BytecodeOperandReadUnaligned(operand_offset, MachineType::Int32(),
- needs_poisoning);
+ return UncheckedCast<Int32T>(BytecodeOperandReadUnaligned(
+ operand_offset, MachineType::Int32(), needs_poisoning));
}
}
-Node* InterpreterAssembler::BytecodeSignedOperand(
+TNode<Int32T> InterpreterAssembler::BytecodeSignedOperand(
int operand_index, OperandSize operand_size,
LoadSensitivity needs_poisoning) {
DCHECK(!Bytecodes::IsUnsignedOperandType(
@@ -510,10 +534,9 @@ Node* InterpreterAssembler::BytecodeSignedOperand(
case OperandSize::kNone:
UNREACHABLE();
}
- return nullptr;
}
-Node* InterpreterAssembler::BytecodeUnsignedOperand(
+TNode<Uint32T> InterpreterAssembler::BytecodeUnsignedOperand(
int operand_index, OperandSize operand_size,
LoadSensitivity needs_poisoning) {
DCHECK(Bytecodes::IsUnsignedOperandType(
@@ -528,10 +551,9 @@ Node* InterpreterAssembler::BytecodeUnsignedOperand(
case OperandSize::kNone:
UNREACHABLE();
}
- return nullptr;
}
-Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) {
+TNode<Uint32T> InterpreterAssembler::BytecodeOperandCount(int operand_index) {
DCHECK_EQ(OperandType::kRegCount,
Bytecodes::GetOperandType(bytecode_, operand_index));
OperandSize operand_size =
@@ -548,7 +570,7 @@ Node* InterpreterAssembler::BytecodeOperandFlag(int operand_index) {
return BytecodeUnsignedOperand(operand_index, operand_size);
}
-Node* InterpreterAssembler::BytecodeOperandUImm(int operand_index) {
+TNode<Uint32T> InterpreterAssembler::BytecodeOperandUImm(int operand_index) {
DCHECK_EQ(OperandType::kUImm,
Bytecodes::GetOperandType(bytecode_, operand_index));
OperandSize operand_size =
@@ -561,7 +583,7 @@ Node* InterpreterAssembler::BytecodeOperandUImmWord(int operand_index) {
}
Node* InterpreterAssembler::BytecodeOperandUImmSmi(int operand_index) {
- return SmiFromInt32(BytecodeOperandUImm(operand_index));
+ return SmiFromInt32(Signed(BytecodeOperandUImm(operand_index)));
}
Node* InterpreterAssembler::BytecodeOperandImm(int operand_index) {
@@ -651,7 +673,8 @@ Node* InterpreterAssembler::LoadConstantPoolEntry(Node* index) {
constant_pool, UncheckedCast<IntPtrT>(index), LoadSensitivity::kCritical);
}
-Node* InterpreterAssembler::LoadAndUntagConstantPoolEntry(Node* index) {
+TNode<IntPtrT> InterpreterAssembler::LoadAndUntagConstantPoolEntry(
+ Node* index) {
return SmiUntag(LoadConstantPoolEntry(index));
}
@@ -662,7 +685,8 @@ Node* InterpreterAssembler::LoadConstantPoolEntryAtOperandIndex(
return LoadConstantPoolEntry(index);
}
-Node* InterpreterAssembler::LoadAndUntagConstantPoolEntryAtOperandIndex(
+TNode<IntPtrT>
+InterpreterAssembler::LoadAndUntagConstantPoolEntryAtOperandIndex(
int operand_index) {
return SmiUntag(LoadConstantPoolEntryAtOperandIndex(operand_index));
}
@@ -682,22 +706,11 @@ void InterpreterAssembler::CallPrologue() {
SaveBytecodeOffset();
}
- if (FLAG_debug_code && !disable_stack_check_across_call_) {
- DCHECK_NULL(stack_pointer_before_call_);
- stack_pointer_before_call_ = LoadStackPointer();
- }
bytecode_array_valid_ = false;
made_call_ = true;
}
void InterpreterAssembler::CallEpilogue() {
- if (FLAG_debug_code && !disable_stack_check_across_call_) {
- Node* stack_pointer_after_call = LoadStackPointer();
- Node* stack_pointer_before_call = stack_pointer_before_call_;
- stack_pointer_before_call_ = nullptr;
- AbortIfWordNotEqual(stack_pointer_before_call, stack_pointer_after_call,
- AbortReason::kUnexpectedStackPointer);
- }
}
void InterpreterAssembler::IncrementCallCount(Node* feedback_vector,
@@ -708,7 +721,7 @@ void InterpreterAssembler::IncrementCallCount(Node* feedback_vector,
// The lowest {FeedbackNexus::CallCountField::kShift} bits of the call
// count are used as flags. To increment the call count by 1 we hence
// have to increment by 1 << {FeedbackNexus::CallCountField::kShift}.
- Node* new_count = SmiAdd(
+ TNode<Smi> new_count = SmiAdd(
call_count, SmiConstant(1 << FeedbackNexus::CallCountField::kShift));
// Count is Smi, so we don't need a write barrier.
StoreFeedbackVectorSlot(feedback_vector, slot_id, new_count,
@@ -729,7 +742,7 @@ void InterpreterAssembler::CollectCallableFeedback(Node* target, Node* context,
// Check if it is a megamorphic {target}.
Comment("check if megamorphic");
- Node* is_megamorphic = WordEqual(
+ TNode<BoolT> is_megamorphic = TaggedEqual(
feedback, HeapConstant(FeedbackVector::MegamorphicSentinel(isolate())));
Branch(is_megamorphic, &done, &extra_checks);
@@ -738,7 +751,7 @@ void InterpreterAssembler::CollectCallableFeedback(Node* target, Node* context,
Label initialize(this), mark_megamorphic(this);
Comment("check if weak reference");
- Node* is_uninitialized = WordEqual(
+ TNode<BoolT> is_uninitialized = TaggedEqual(
feedback,
HeapConstant(FeedbackVector::UninitializedSentinel(isolate())));
GotoIf(is_uninitialized, &initialize);
@@ -764,7 +777,7 @@ void InterpreterAssembler::CollectCallableFeedback(Node* target, Node* context,
Label if_boundfunction(this), if_function(this);
Node* current = var_current.value();
CSA_ASSERT(this, TaggedIsNotSmi(current));
- Node* current_instance_type = LoadInstanceType(current);
+ TNode<Uint16T> current_instance_type = LoadInstanceType(current);
GotoIf(InstanceTypeEqual(current_instance_type, JS_BOUND_FUNCTION_TYPE),
&if_boundfunction);
Branch(InstanceTypeEqual(current_instance_type, JS_FUNCTION_TYPE),
@@ -774,11 +787,13 @@ void InterpreterAssembler::CollectCallableFeedback(Node* target, Node* context,
{
// Check that the JSFunction {current} is in the current native
// context.
- Node* current_context =
- LoadObjectField(current, JSFunction::kContextOffset);
- Node* current_native_context = LoadNativeContext(current_context);
- Branch(WordEqual(LoadNativeContext(context), current_native_context),
- &done_loop, &mark_megamorphic);
+ TNode<Context> current_context =
+ CAST(LoadObjectField(current, JSFunction::kContextOffset));
+ TNode<Context> current_native_context =
+ LoadNativeContext(current_context);
+ Branch(
+ TaggedEqual(LoadNativeContext(context), current_native_context),
+ &done_loop, &mark_megamorphic);
}
BIND(&if_boundfunction);
@@ -848,13 +863,13 @@ void InterpreterAssembler::CallJSAndDispatch(
args_count = args.reg_count();
} else {
// Subtract the receiver from the argument count.
- Node* receiver_count = Int32Constant(1);
+ TNode<Int32T> receiver_count = Int32Constant(1);
args_count = Int32Sub(args.reg_count(), receiver_count);
}
Callable callable = CodeFactory::InterpreterPushArgsThenCall(
isolate(), receiver_mode, InterpreterPushArgsMode::kOther);
- Node* code_target = HeapConstant(callable.code());
+ TNode<Code> code_target = HeapConstant(callable.code());
TailCallStubThenBytecodeDispatch(callable.descriptor(), code_target, context,
args_count, args.base_reg_location(),
@@ -873,7 +888,7 @@ void InterpreterAssembler::CallJSAndDispatch(Node* function, Node* context,
bytecode_ == Bytecode::kInvokeIntrinsic);
DCHECK_EQ(Bytecodes::GetReceiverMode(bytecode_), receiver_mode);
Callable callable = CodeFactory::Call(isolate());
- Node* code_target = HeapConstant(callable.code());
+ TNode<Code> code_target = HeapConstant(callable.code());
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
// The first argument parameter (the receiver) is implied to be undefined.
@@ -913,10 +928,10 @@ void InterpreterAssembler::CallJSWithSpreadAndDispatch(
Callable callable = CodeFactory::InterpreterPushArgsThenCall(
isolate(), ConvertReceiverMode::kAny,
InterpreterPushArgsMode::kWithFinalSpread);
- Node* code_target = HeapConstant(callable.code());
+ TNode<Code> code_target = HeapConstant(callable.code());
- Node* receiver_count = Int32Constant(1);
- Node* args_count = Int32Sub(args.reg_count(), receiver_count);
+ TNode<Int32T> receiver_count = Int32Constant(1);
+ TNode<Word32T> args_count = Int32Sub(args.reg_count(), receiver_count);
TailCallStubThenBytecodeDispatch(callable.descriptor(), code_target, context,
args_count, args.base_reg_location(),
function);
@@ -924,8 +939,8 @@ void InterpreterAssembler::CallJSWithSpreadAndDispatch(
accumulator_use_ = accumulator_use_ | AccumulatorUse::kWrite;
}
-Node* InterpreterAssembler::Construct(Node* target, Node* context,
- Node* new_target,
+Node* InterpreterAssembler::Construct(SloppyTNode<Object> target, Node* context,
+ SloppyTNode<Object> new_target,
const RegListNodePair& args,
Node* slot_id, Node* feedback_vector) {
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
@@ -941,8 +956,7 @@ Node* InterpreterAssembler::Construct(Node* target, Node* context,
// Check if we have monomorphic {new_target} feedback already.
TNode<MaybeObject> feedback =
LoadFeedbackVectorSlot(feedback_vector, slot_id);
- Branch(IsWeakReferenceTo(feedback, CAST(new_target)), &construct,
- &extra_checks);
+ Branch(IsWeakReferenceTo(feedback, new_target), &construct, &extra_checks);
BIND(&extra_checks);
{
@@ -951,7 +965,7 @@ Node* InterpreterAssembler::Construct(Node* target, Node* context,
// Check if it is a megamorphic {new_target}..
Comment("check if megamorphic");
- Node* is_megamorphic = WordEqual(
+ TNode<BoolT> is_megamorphic = TaggedEqual(
feedback, HeapConstant(FeedbackVector::MegamorphicSentinel(isolate())));
GotoIf(is_megamorphic, &construct);
@@ -971,10 +985,10 @@ Node* InterpreterAssembler::Construct(Node* target, Node* context,
GotoIfNot(IsAllocationSite(strong_feedback), &check_initialized);
// Make sure that {target} and {new_target} are the Array constructor.
- Node* array_function = LoadContextElement(LoadNativeContext(context),
- Context::ARRAY_FUNCTION_INDEX);
- GotoIfNot(WordEqual(target, array_function), &mark_megamorphic);
- GotoIfNot(WordEqual(new_target, array_function), &mark_megamorphic);
+ TNode<Object> array_function = LoadContextElement(
+ LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
+ GotoIfNot(TaggedEqual(target, array_function), &mark_megamorphic);
+ GotoIfNot(TaggedEqual(new_target, array_function), &mark_megamorphic);
var_site.Bind(strong_feedback);
Goto(&construct_array);
}
@@ -983,8 +997,8 @@ Node* InterpreterAssembler::Construct(Node* target, Node* context,
{
// Check if it is uninitialized.
Comment("check if uninitialized");
- Node* is_uninitialized =
- WordEqual(feedback, LoadRoot(RootIndex::kuninitialized_symbol));
+ TNode<BoolT> is_uninitialized =
+ TaggedEqual(feedback, UninitializedSymbolConstant());
Branch(is_uninitialized, &initialize, &mark_megamorphic);
}
@@ -1002,7 +1016,7 @@ Node* InterpreterAssembler::Construct(Node* target, Node* context,
Label if_boundfunction(this), if_function(this);
Node* current = var_current.value();
CSA_ASSERT(this, TaggedIsNotSmi(current));
- Node* current_instance_type = LoadInstanceType(current);
+ TNode<Uint16T> current_instance_type = LoadInstanceType(current);
GotoIf(InstanceTypeEqual(current_instance_type, JS_BOUND_FUNCTION_TYPE),
&if_boundfunction);
Branch(InstanceTypeEqual(current_instance_type, JS_FUNCTION_TYPE),
@@ -1012,11 +1026,13 @@ Node* InterpreterAssembler::Construct(Node* target, Node* context,
{
// Check that the JSFunction {current} is in the current native
// context.
- Node* current_context =
- LoadObjectField(current, JSFunction::kContextOffset);
- Node* current_native_context = LoadNativeContext(current_context);
- Branch(WordEqual(LoadNativeContext(context), current_native_context),
- &done_loop, &mark_megamorphic);
+ TNode<Context> current_context =
+ CAST(LoadObjectField(current, JSFunction::kContextOffset));
+ TNode<Context> current_native_context =
+ LoadNativeContext(current_context);
+ Branch(
+ TaggedEqual(LoadNativeContext(context), current_native_context),
+ &done_loop, &mark_megamorphic);
}
BIND(&if_boundfunction);
@@ -1032,10 +1048,10 @@ Node* InterpreterAssembler::Construct(Node* target, Node* context,
// Create an AllocationSite if {target} and {new_target} refer
// to the current native context's Array constructor.
Label create_allocation_site(this), store_weak_reference(this);
- GotoIfNot(WordEqual(target, new_target), &store_weak_reference);
- Node* array_function = LoadContextElement(LoadNativeContext(context),
- Context::ARRAY_FUNCTION_INDEX);
- Branch(WordEqual(target, array_function), &create_allocation_site,
+ GotoIfNot(TaggedEqual(target, new_target), &store_weak_reference);
+ TNode<Object> array_function = LoadContextElement(
+ LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
+ Branch(TaggedEqual(target, array_function), &create_allocation_site,
&store_weak_reference);
BIND(&create_allocation_site);
@@ -1080,7 +1096,7 @@ Node* InterpreterAssembler::Construct(Node* target, Node* context,
Comment("call using ConstructArray builtin");
Callable callable = CodeFactory::InterpreterPushArgsThenConstruct(
isolate(), InterpreterPushArgsMode::kArrayFunction);
- Node* code_target = HeapConstant(callable.code());
+ TNode<Code> code_target = HeapConstant(callable.code());
var_result.Bind(CallStub(callable.descriptor(), code_target, context,
args.reg_count(), args.base_reg_location(), target,
new_target, var_site.value()));
@@ -1093,7 +1109,7 @@ Node* InterpreterAssembler::Construct(Node* target, Node* context,
Comment("call using Construct builtin");
Callable callable = CodeFactory::InterpreterPushArgsThenConstruct(
isolate(), InterpreterPushArgsMode::kOther);
- Node* code_target = HeapConstant(callable.code());
+ TNode<Code> code_target = HeapConstant(callable.code());
var_result.Bind(CallStub(callable.descriptor(), code_target, context,
args.reg_count(), args.base_reg_location(), target,
new_target, UndefinedConstant()));
@@ -1131,7 +1147,7 @@ Node* InterpreterAssembler::ConstructWithSpread(Node* target, Node* context,
// Check if it is a megamorphic {new_target}.
Comment("check if megamorphic");
- Node* is_megamorphic = WordEqual(
+ TNode<BoolT> is_megamorphic = TaggedEqual(
feedback, HeapConstant(FeedbackVector::MegamorphicSentinel(isolate())));
GotoIf(is_megamorphic, &construct);
@@ -1147,8 +1163,8 @@ Node* InterpreterAssembler::ConstructWithSpread(Node* target, Node* context,
{
// Check if it is uninitialized.
Comment("check if uninitialized");
- Node* is_uninitialized =
- WordEqual(feedback, LoadRoot(RootIndex::kuninitialized_symbol));
+ TNode<BoolT> is_uninitialized =
+ TaggedEqual(feedback, UninitializedSymbolConstant());
Branch(is_uninitialized, &initialize, &mark_megamorphic);
}
@@ -1166,7 +1182,7 @@ Node* InterpreterAssembler::ConstructWithSpread(Node* target, Node* context,
Label if_boundfunction(this), if_function(this);
Node* current = var_current.value();
CSA_ASSERT(this, TaggedIsNotSmi(current));
- Node* current_instance_type = LoadInstanceType(current);
+ TNode<Uint16T> current_instance_type = LoadInstanceType(current);
GotoIf(InstanceTypeEqual(current_instance_type, JS_BOUND_FUNCTION_TYPE),
&if_boundfunction);
Branch(InstanceTypeEqual(current_instance_type, JS_FUNCTION_TYPE),
@@ -1176,11 +1192,13 @@ Node* InterpreterAssembler::ConstructWithSpread(Node* target, Node* context,
{
// Check that the JSFunction {current} is in the current native
// context.
- Node* current_context =
- LoadObjectField(current, JSFunction::kContextOffset);
- Node* current_native_context = LoadNativeContext(current_context);
- Branch(WordEqual(LoadNativeContext(context), current_native_context),
- &done_loop, &mark_megamorphic);
+ TNode<Context> current_context =
+ CAST(LoadObjectField(current, JSFunction::kContextOffset));
+ TNode<Context> current_native_context =
+ LoadNativeContext(current_context);
+ Branch(
+ TaggedEqual(LoadNativeContext(context), current_native_context),
+ &done_loop, &mark_megamorphic);
}
BIND(&if_boundfunction);
@@ -1219,7 +1237,7 @@ Node* InterpreterAssembler::ConstructWithSpread(Node* target, Node* context,
Comment("call using ConstructWithSpread builtin");
Callable callable = CodeFactory::InterpreterPushArgsThenConstruct(
isolate(), InterpreterPushArgsMode::kWithFinalSpread);
- Node* code_target = HeapConstant(callable.code());
+ TNode<Code> code_target = HeapConstant(callable.code());
return CallStub(callable.descriptor(), code_target, context, args.reg_count(),
args.base_reg_location(), target, new_target,
UndefinedConstant());
@@ -1231,14 +1249,14 @@ Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context,
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
DCHECK(Bytecodes::IsCallRuntime(bytecode_));
Callable callable = CodeFactory::InterpreterCEntry(isolate(), result_size);
- Node* code_target = HeapConstant(callable.code());
+ TNode<Code> code_target = HeapConstant(callable.code());
// Get the function entry from the function id.
Node* function_table = ExternalConstant(
ExternalReference::runtime_function_table_address(isolate()));
- Node* function_offset =
+ TNode<Word32T> function_offset =
Int32Mul(function_id, Int32Constant(sizeof(Runtime::Function)));
- Node* function =
+ TNode<WordT> function =
IntPtrAdd(function_table, ChangeUint32ToWord(function_offset));
Node* function_entry =
Load(MachineType::Pointer(), function,
@@ -1259,7 +1277,7 @@ void InterpreterAssembler::UpdateInterruptBudget(Node* weight, bool backward) {
Label load_budget_from_bytecode(this), load_budget_done(this);
TNode<JSFunction> function = CAST(LoadRegister(Register::function_closure()));
TNode<FeedbackCell> feedback_cell =
- CAST(LoadObjectField(function, JSFunction::kFeedbackCellOffset));
+ LoadObjectField<FeedbackCell>(function, JSFunction::kFeedbackCellOffset);
TNode<Int32T> old_budget = LoadObjectField<Int32T>(
feedback_cell, FeedbackCell::kInterruptBudgetOffset);
@@ -1272,7 +1290,7 @@ void InterpreterAssembler::UpdateInterruptBudget(Node* weight, bool backward) {
if (backward) {
// Update budget by |weight| and check if it reaches zero.
new_budget = Signed(Int32Sub(budget_after_bytecode, weight));
- Node* condition =
+ TNode<BoolT> condition =
Int32GreaterThanOrEqual(new_budget.value(), Int32Constant(0));
Label ok(this), interrupt_check(this, Label::kDeferred);
Branch(condition, &ok, &interrupt_check);
@@ -1297,19 +1315,22 @@ void InterpreterAssembler::UpdateInterruptBudget(Node* weight, bool backward) {
Comment("] UpdateInterruptBudget");
}
-Node* InterpreterAssembler::Advance() { return Advance(CurrentBytecodeSize()); }
+TNode<IntPtrT> InterpreterAssembler::Advance() {
+ return Advance(CurrentBytecodeSize());
+}
-Node* InterpreterAssembler::Advance(int delta) {
+TNode<IntPtrT> InterpreterAssembler::Advance(int delta) {
return Advance(IntPtrConstant(delta));
}
-Node* InterpreterAssembler::Advance(Node* delta, bool backward) {
+TNode<IntPtrT> InterpreterAssembler::Advance(SloppyTNode<IntPtrT> delta,
+ bool backward) {
#ifdef V8_TRACE_IGNITION
TraceBytecode(Runtime::kInterpreterTraceBytecodeExit);
#endif
- Node* next_offset = backward ? IntPtrSub(BytecodeOffset(), delta)
- : IntPtrAdd(BytecodeOffset(), delta);
- bytecode_offset_.Bind(next_offset);
+ TNode<IntPtrT> next_offset = backward ? IntPtrSub(BytecodeOffset(), delta)
+ : IntPtrAdd(BytecodeOffset(), delta);
+ bytecode_offset_ = next_offset;
return next_offset;
}
@@ -1318,7 +1339,7 @@ Node* InterpreterAssembler::Jump(Node* delta, bool backward) {
UpdateInterruptBudget(TruncateIntPtrToInt32(delta), backward);
Node* new_bytecode_offset = Advance(delta, backward);
- Node* target_bytecode = LoadBytecode(new_bytecode_offset);
+ TNode<WordT> target_bytecode = LoadBytecode(new_bytecode_offset);
return DispatchToBytecode(target_bytecode, new_bytecode_offset);
}
@@ -1338,35 +1359,39 @@ void InterpreterAssembler::JumpConditional(Node* condition, Node* delta) {
Dispatch();
}
-void InterpreterAssembler::JumpIfWordEqual(Node* lhs, Node* rhs, Node* delta) {
- JumpConditional(WordEqual(lhs, rhs), delta);
+void InterpreterAssembler::JumpIfTaggedEqual(TNode<Object> lhs,
+ TNode<Object> rhs, Node* delta) {
+ JumpConditional(TaggedEqual(lhs, rhs), delta);
}
-void InterpreterAssembler::JumpIfWordNotEqual(Node* lhs, Node* rhs,
- Node* delta) {
- JumpConditional(WordNotEqual(lhs, rhs), delta);
+void InterpreterAssembler::JumpIfTaggedNotEqual(TNode<Object> lhs,
+ TNode<Object> rhs,
+ Node* delta) {
+ JumpConditional(TaggedNotEqual(lhs, rhs), delta);
}
-Node* InterpreterAssembler::LoadBytecode(Node* bytecode_offset) {
+TNode<WordT> InterpreterAssembler::LoadBytecode(Node* bytecode_offset) {
Node* bytecode =
Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(), bytecode_offset);
return ChangeUint32ToWord(bytecode);
}
-Node* InterpreterAssembler::StarDispatchLookahead(Node* target_bytecode) {
+TNode<WordT> InterpreterAssembler::StarDispatchLookahead(
+ TNode<WordT> target_bytecode) {
Label do_inline_star(this), done(this);
- Variable var_bytecode(this, MachineType::PointerRepresentation());
- var_bytecode.Bind(target_bytecode);
+ TVARIABLE(WordT, var_bytecode, target_bytecode);
- Node* star_bytecode = IntPtrConstant(static_cast<int>(Bytecode::kStar));
- Node* is_star = WordEqual(target_bytecode, star_bytecode);
+ TNode<Int32T> star_bytecode =
+ Int32Constant(static_cast<int>(Bytecode::kStar));
+ TNode<BoolT> is_star =
+ Word32Equal(TruncateWordToInt32(target_bytecode), star_bytecode);
Branch(is_star, &do_inline_star, &done);
BIND(&do_inline_star);
{
InlineStar();
- var_bytecode.Bind(LoadBytecode(BytecodeOffset()));
+ var_bytecode = LoadBytecode(BytecodeOffset());
Goto(&done);
}
BIND(&done);
@@ -1397,7 +1422,7 @@ Node* InterpreterAssembler::Dispatch() {
Comment("========= Dispatch");
DCHECK_IMPLIES(Bytecodes::MakesCallAlongCriticalPath(bytecode_), made_call_);
Node* target_offset = Advance();
- Node* target_bytecode = LoadBytecode(target_offset);
+ TNode<WordT> target_bytecode = LoadBytecode(target_offset);
if (Bytecodes::IsStarLookahead(bytecode_, operand_scale_)) {
target_bytecode = StarDispatchLookahead(target_bytecode);
@@ -1423,7 +1448,7 @@ Node* InterpreterAssembler::DispatchToBytecodeHandler(Node* handler,
Node* bytecode_offset,
Node* target_bytecode) {
// TODO(ishell): Add CSA::CodeEntryPoint(code).
- Node* handler_entry =
+ TNode<IntPtrT> handler_entry =
IntPtrAdd(BitcastTaggedToWord(handler),
IntPtrConstant(Code::kHeaderSize - kHeapObjectTag));
return DispatchToBytecodeHandlerEntry(handler_entry, bytecode_offset,
@@ -1433,7 +1458,7 @@ Node* InterpreterAssembler::DispatchToBytecodeHandler(Node* handler,
Node* InterpreterAssembler::DispatchToBytecodeHandlerEntry(
Node* handler_entry, Node* bytecode_offset, Node* target_bytecode) {
// Propagate speculation poisoning.
- Node* poisoned_handler_entry = WordPoisonOnSpeculation(handler_entry);
+ TNode<WordT> poisoned_handler_entry = WordPoisonOnSpeculation(handler_entry);
return TailCallBytecodeDispatch(
InterpreterDispatchDescriptor{}, poisoned_handler_entry,
GetAccumulatorUnchecked(), bytecode_offset, BytecodeArrayTaggedPointer(),
@@ -1450,7 +1475,7 @@ void InterpreterAssembler::DispatchWide(OperandScale operand_scale) {
// Indices 512-767 correspond to bytecodes with operand_scale == 2
DCHECK_IMPLIES(Bytecodes::MakesCallAlongCriticalPath(bytecode_), made_call_);
Node* next_bytecode_offset = Advance(1);
- Node* next_bytecode = LoadBytecode(next_bytecode_offset);
+ TNode<WordT> next_bytecode = LoadBytecode(next_bytecode_offset);
if (FLAG_trace_ignition_dispatches) {
TraceBytecodeDispatch(next_bytecode);
@@ -1467,7 +1492,7 @@ void InterpreterAssembler::DispatchWide(OperandScale operand_scale) {
default:
UNREACHABLE();
}
- Node* target_index = IntPtrAdd(base_index, next_bytecode);
+ TNode<WordT> target_index = IntPtrAdd(base_index, next_bytecode);
Node* target_code_entry =
Load(MachineType::Pointer(), DispatchTableRawPointer(),
TimesSystemPointerSize(target_index));
@@ -1496,8 +1521,9 @@ void InterpreterAssembler::UpdateInterruptBudgetOnReturn() {
// of the first bytecode.
const int kFirstBytecodeOffset = BytecodeArray::kHeaderSize - kHeapObjectTag;
- Node* profiling_weight = Int32Sub(TruncateIntPtrToInt32(BytecodeOffset()),
- Int32Constant(kFirstBytecodeOffset));
+ TNode<Int32T> profiling_weight =
+ Int32Sub(TruncateIntPtrToInt32(BytecodeOffset()),
+ Int32Constant(kFirstBytecodeOffset));
UpdateInterruptBudget(profiling_weight, true);
}
@@ -1508,13 +1534,12 @@ Node* InterpreterAssembler::LoadOsrNestingLevel() {
}
void InterpreterAssembler::Abort(AbortReason abort_reason) {
- disable_stack_check_across_call_ = true;
- Node* abort_id = SmiConstant(abort_reason);
+ TNode<Smi> abort_id = SmiConstant(abort_reason);
CallRuntime(Runtime::kAbort, GetContext(), abort_id);
- disable_stack_check_across_call_ = false;
}
-void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs,
+void InterpreterAssembler::AbortIfWordNotEqual(TNode<WordT> lhs,
+ TNode<WordT> rhs,
AbortReason abort_reason) {
Label ok(this), abort(this, Label::kDeferred);
Branch(WordEqual(lhs, rhs), &ok, &abort);
@@ -1527,11 +1552,11 @@ void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs,
}
void InterpreterAssembler::MaybeDropFrames(Node* context) {
- Node* restart_fp_address =
+ TNode<ExternalReference> restart_fp_address =
ExternalConstant(ExternalReference::debug_restart_fp_address(isolate()));
- Node* restart_fp = Load(MachineType::Pointer(), restart_fp_address);
- Node* null = IntPtrConstant(0);
+ TNode<IntPtrT> restart_fp = Load<IntPtrT>(restart_fp_address);
+ TNode<IntPtrT> null = IntPtrConstant(0);
Label ok(this), drop_frames(this);
Branch(IntPtrEqual(restart_fp, null), &ok, &drop_frames);
@@ -1552,25 +1577,24 @@ void InterpreterAssembler::TraceBytecode(Runtime::FunctionId function_id) {
}
void InterpreterAssembler::TraceBytecodeDispatch(Node* target_bytecode) {
- Node* counters_table = ExternalConstant(
+ TNode<ExternalReference> counters_table = ExternalConstant(
ExternalReference::interpreter_dispatch_counters(isolate()));
- Node* source_bytecode_table_index = IntPtrConstant(
+ TNode<IntPtrT> source_bytecode_table_index = IntPtrConstant(
static_cast<int>(bytecode_) * (static_cast<int>(Bytecode::kLast) + 1));
- Node* counter_offset = TimesSystemPointerSize(
+ TNode<WordT> counter_offset = TimesSystemPointerSize(
IntPtrAdd(source_bytecode_table_index, target_bytecode));
- Node* old_counter =
- Load(MachineType::IntPtr(), counters_table, counter_offset);
+ TNode<IntPtrT> old_counter = Load<IntPtrT>(counters_table, counter_offset);
Label counter_ok(this), counter_saturated(this, Label::kDeferred);
- Node* counter_reached_max = WordEqual(
+ TNode<BoolT> counter_reached_max = WordEqual(
old_counter, IntPtrConstant(std::numeric_limits<uintptr_t>::max()));
Branch(counter_reached_max, &counter_saturated, &counter_ok);
BIND(&counter_ok);
{
- Node* new_counter = IntPtrAdd(old_counter, IntPtrConstant(1));
+ TNode<IntPtrT> new_counter = IntPtrAdd(old_counter, IntPtrConstant(1));
StoreNoWriteBarrier(MachineType::PointerRepresentation(), counters_table,
counter_offset, new_counter);
Goto(&counter_saturated);
@@ -1594,7 +1618,8 @@ bool InterpreterAssembler::TargetSupportsUnalignedAccess() {
void InterpreterAssembler::AbortIfRegisterCountInvalid(
Node* parameters_and_registers, Node* formal_parameter_count,
Node* register_count) {
- Node* array_size = LoadAndUntagFixedArrayBaseLength(parameters_and_registers);
+ TNode<IntPtrT> array_size =
+ LoadAndUntagFixedArrayBaseLength(parameters_and_registers);
Label ok(this), abort(this, Label::kDeferred);
Branch(UintPtrLessThanOrEqual(
@@ -1615,7 +1640,7 @@ Node* InterpreterAssembler::ExportParametersAndRegisterFile(
// registers into the generator's internal parameters_and_registers field.
TNode<IntPtrT> formal_parameter_count_intptr =
ChangeInt32ToIntPtr(formal_parameter_count);
- Node* register_count = ChangeUint32ToWord(registers.reg_count());
+ TNode<UintPtrT> register_count = ChangeUint32ToWord(registers.reg_count());
if (FLAG_debug_code) {
CSA_ASSERT(this, IntPtrEqual(registers.base_reg_location(),
RegisterLocation(Register(0))));
@@ -1630,7 +1655,7 @@ Node* InterpreterAssembler::ExportParametersAndRegisterFile(
// Iterate over parameters and write them into the array.
Label loop(this, &var_index), done_loop(this);
- Node* reg_base = IntPtrAdd(
+ TNode<IntPtrT> reg_base = IntPtrAdd(
IntPtrConstant(Register::FromParameterIndex(0, 1).ToOperand() - 1),
formal_parameter_count_intptr);
@@ -1641,8 +1666,8 @@ Node* InterpreterAssembler::ExportParametersAndRegisterFile(
GotoIfNot(UintPtrLessThan(index, formal_parameter_count_intptr),
&done_loop);
- Node* reg_index = IntPtrSub(reg_base, index);
- Node* value = LoadRegister(reg_index);
+ TNode<WordT> reg_index = IntPtrSub(reg_base, index);
+ TNode<Object> value = LoadRegister(reg_index);
StoreFixedArrayElement(array, index, value);
@@ -1666,11 +1691,12 @@ Node* InterpreterAssembler::ExportParametersAndRegisterFile(
Node* index = var_index.value();
GotoIfNot(UintPtrLessThan(index, register_count), &done_loop);
- Node* reg_index =
+ TNode<WordT> reg_index =
IntPtrSub(IntPtrConstant(Register(0).ToOperand()), index);
- Node* value = LoadRegister(reg_index);
+ TNode<Object> value = LoadRegister(reg_index);
- Node* array_index = IntPtrAdd(formal_parameter_count_intptr, index);
+ TNode<WordT> array_index =
+ IntPtrAdd(formal_parameter_count_intptr, index);
StoreFixedArrayElement(array, array_index, value);
var_index.Bind(IntPtrAdd(index, IntPtrConstant(1)));
@@ -1714,8 +1740,7 @@ Node* InterpreterAssembler::ImportRegisterFile(
IntPtrSub(IntPtrConstant(Register(0).ToOperand()), index);
StoreRegister(value, reg_index);
- StoreFixedArrayElement(array, array_index,
- LoadRoot(RootIndex::kStaleRegister));
+ StoreFixedArrayElement(array, array_index, StaleRegisterConstant());
var_index = IntPtrAdd(index, IntPtrConstant(1));
Goto(&loop);
@@ -1730,8 +1755,8 @@ int InterpreterAssembler::CurrentBytecodeSize() const {
}
void InterpreterAssembler::ToNumberOrNumeric(Object::Conversion mode) {
- Node* object = GetAccumulator();
- Node* context = GetContext();
+ TNode<Object> object = GetAccumulator();
+ TNode<Context> context = GetContext();
Variable var_type_feedback(this, MachineRepresentation::kTaggedSigned);
Variable var_result(this, MachineRepresentation::kTagged);
@@ -1739,7 +1764,7 @@ void InterpreterAssembler::ToNumberOrNumeric(Object::Conversion mode) {
if_objectisother(this, Label::kDeferred);
GotoIf(TaggedIsSmi(object), &if_objectissmi);
- Branch(IsHeapNumber(object), &if_objectisheapnumber, &if_objectisother);
+ Branch(IsHeapNumber(CAST(object)), &if_objectisheapnumber, &if_objectisother);
BIND(&if_objectissmi);
{
@@ -1762,7 +1787,7 @@ void InterpreterAssembler::ToNumberOrNumeric(Object::Conversion mode) {
builtin = Builtins::kNonNumberToNumeric;
// Special case for collecting BigInt feedback.
Label not_bigint(this);
- GotoIfNot(IsBigInt(object), &not_bigint);
+ GotoIfNot(IsBigInt(CAST(object)), &not_bigint);
{
var_result.Bind(object);
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
@@ -1781,7 +1806,7 @@ void InterpreterAssembler::ToNumberOrNumeric(Object::Conversion mode) {
// Record the type feedback collected for {object}.
Node* slot_index = BytecodeOperandIdx(0);
- Node* maybe_feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot_index);
diff --git a/deps/v8/src/interpreter/interpreter-assembler.h b/deps/v8/src/interpreter/interpreter-assembler.h
index a135eaacdd..33fa987595 100644
--- a/deps/v8/src/interpreter/interpreter-assembler.h
+++ b/deps/v8/src/interpreter/interpreter-assembler.h
@@ -25,7 +25,7 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
// Returns the 32-bit unsigned count immediate for bytecode operand
// |operand_index| in the current bytecode.
- compiler::Node* BytecodeOperandCount(int operand_index);
+ compiler::TNode<Uint32T> BytecodeOperandCount(int operand_index);
// Returns the 32-bit unsigned flag for bytecode operand |operand_index|
// in the current bytecode.
compiler::Node* BytecodeOperandFlag(int operand_index);
@@ -40,7 +40,7 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
compiler::Node* BytecodeOperandIdxSmi(int operand_index);
// Returns the 32-bit unsigned immediate for bytecode operand |operand_index|
// in the current bytecode.
- compiler::Node* BytecodeOperandUImm(int operand_index);
+ compiler::TNode<Uint32T> BytecodeOperandUImm(int operand_index);
// Returns the word-size unsigned immediate for bytecode operand
// |operand_index| in the current bytecode.
compiler::Node* BytecodeOperandUImmWord(int operand_index);
@@ -67,34 +67,37 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
compiler::Node* BytecodeOperandIntrinsicId(int operand_index);
// Accumulator.
- compiler::Node* GetAccumulator();
+ compiler::TNode<Object> GetAccumulator();
void SetAccumulator(compiler::Node* value);
// Context.
- compiler::Node* GetContext();
- void SetContext(compiler::Node* value);
+ compiler::TNode<Context> GetContext();
+ void SetContext(compiler::TNode<Context> value);
// Context at |depth| in the context chain starting at |context|.
- compiler::Node* GetContextAtDepth(compiler::Node* context,
- compiler::Node* depth);
+ compiler::Node* GetContextAtDepth(compiler::TNode<Context> context,
+ compiler::TNode<Uint32T> depth);
// Goto the given |target| if the context chain starting at |context| has any
// extensions up to the given |depth|.
- void GotoIfHasContextExtensionUpToDepth(compiler::Node* context,
- compiler::Node* depth, Label* target);
+ void GotoIfHasContextExtensionUpToDepth(compiler::TNode<Context> context,
+ compiler::TNode<Uint32T> depth,
+ Label* target);
// A RegListNodePair provides an abstraction over lists of registers.
class RegListNodePair {
public:
- RegListNodePair(Node* base_reg_location, Node* reg_count)
+ RegListNodePair(TNode<IntPtrT> base_reg_location, TNode<Word32T> reg_count)
: base_reg_location_(base_reg_location), reg_count_(reg_count) {}
- compiler::Node* reg_count() const { return reg_count_; }
- compiler::Node* base_reg_location() const { return base_reg_location_; }
+ compiler::TNode<Word32T> reg_count() const { return reg_count_; }
+ compiler::TNode<IntPtrT> base_reg_location() const {
+ return base_reg_location_;
+ }
private:
- compiler::Node* base_reg_location_;
- compiler::Node* reg_count_;
+ compiler::TNode<IntPtrT> base_reg_location_;
+ compiler::TNode<Word32T> reg_count_;
};
// Backup/restore register file to/from a fixed array of the correct length.
@@ -110,13 +113,12 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
TNode<Int32T> formal_parameter_count);
// Loads from and stores to the interpreter register file.
- compiler::Node* LoadRegister(Register reg);
- compiler::Node* LoadAndUntagRegister(Register reg);
- compiler::Node* LoadRegisterAtOperandIndex(int operand_index);
- std::pair<compiler::Node*, compiler::Node*> LoadRegisterPairAtOperandIndex(
- int operand_index);
+ compiler::TNode<Object> LoadRegister(Register reg);
+ compiler::TNode<IntPtrT> LoadAndUntagRegister(Register reg);
+ compiler::TNode<Object> LoadRegisterAtOperandIndex(int operand_index);
+ std::pair<compiler::TNode<Object>, compiler::TNode<Object>>
+ LoadRegisterPairAtOperandIndex(int operand_index);
void StoreRegister(compiler::Node* value, Register reg);
- void StoreAndTagRegister(compiler::Node* value, Register reg);
void StoreRegisterAtOperandIndex(compiler::Node* value, int operand_index);
void StoreRegisterPairAtOperandIndex(compiler::Node* value1,
compiler::Node* value2,
@@ -129,20 +131,19 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
RegListNodePair GetRegisterListAtOperandIndex(int operand_index);
Node* LoadRegisterFromRegisterList(const RegListNodePair& reg_list,
int index);
- Node* RegisterLocationInRegisterList(const RegListNodePair& reg_list,
- int index);
+ TNode<IntPtrT> RegisterLocationInRegisterList(const RegListNodePair& reg_list,
+ int index);
// Load constant at the index specified in operand |operand_index| from the
// constant pool.
compiler::Node* LoadConstantPoolEntryAtOperandIndex(int operand_index);
// Load and untag constant at the index specified in operand |operand_index|
// from the constant pool.
- compiler::Node* LoadAndUntagConstantPoolEntryAtOperandIndex(
- int operand_index);
+ TNode<IntPtrT> LoadAndUntagConstantPoolEntryAtOperandIndex(int operand_index);
// Load constant at |index| in the constant pool.
compiler::Node* LoadConstantPoolEntry(compiler::Node* index);
// Load and untag constant at |index| in the constant pool.
- compiler::Node* LoadAndUntagConstantPoolEntry(compiler::Node* index);
+ TNode<IntPtrT> LoadAndUntagConstantPoolEntry(compiler::Node* index);
// Load the FeedbackVector for the current function. The retuned node could be
// undefined.
@@ -193,8 +194,9 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
// Call constructor |target| with |args| arguments (not including receiver).
// The |new_target| is the same as the |target| for the new keyword, but
// differs for the super keyword.
- compiler::Node* Construct(compiler::Node* target, compiler::Node* context,
- compiler::Node* new_target,
+ compiler::Node* Construct(compiler::SloppyTNode<Object> target,
+ compiler::Node* context,
+ compiler::SloppyTNode<Object> new_target,
const RegListNodePair& args,
compiler::Node* slot_id,
compiler::Node* feedback_vector);
@@ -225,13 +227,15 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
// Jump forward relative to the current bytecode by |jump_offset| if the
// word values |lhs| and |rhs| are equal.
- void JumpIfWordEqual(compiler::Node* lhs, compiler::Node* rhs,
- compiler::Node* jump_offset);
+ void JumpIfTaggedEqual(compiler::TNode<Object> lhs,
+ compiler::TNode<Object> rhs,
+ compiler::Node* jump_offset);
// Jump forward relative to the current bytecode by |jump_offset| if the
// word values |lhs| and |rhs| are not equal.
- void JumpIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs,
- compiler::Node* jump_offset);
+ void JumpIfTaggedNotEqual(compiler::TNode<Object> lhs,
+ compiler::TNode<Object> rhs,
+ compiler::Node* jump_offset);
// Updates the profiler interrupt budget for a return.
void UpdateInterruptBudgetOnReturn();
@@ -252,7 +256,8 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
// Abort with the given abort reason.
void Abort(AbortReason abort_reason);
- void AbortIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs,
+ void AbortIfWordNotEqual(compiler::TNode<WordT> lhs,
+ compiler::TNode<WordT> rhs,
AbortReason abort_reason);
// Abort if |register_count| is invalid for given register file array.
void AbortIfRegisterCountInvalid(compiler::Node* parameters_and_registers,
@@ -263,7 +268,7 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
void MaybeDropFrames(compiler::Node* context);
// Returns the offset from the BytecodeArrayPointer of the current bytecode.
- compiler::Node* BytecodeOffset();
+ TNode<IntPtrT> BytecodeOffset();
protected:
Bytecode bytecode() const { return bytecode_; }
@@ -285,13 +290,13 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
// Returns the frame pointer for the interpreted frame of the function being
// interpreted.
- compiler::Node* GetInterpretedFramePointer();
+ TNode<RawPtrT> GetInterpretedFramePointer();
// Operations on registers.
- compiler::Node* RegisterLocation(Register reg);
- compiler::Node* RegisterLocation(compiler::Node* reg_index);
- compiler::Node* NextRegister(compiler::Node* reg_index);
- compiler::Node* LoadRegister(Node* reg_index);
+ compiler::TNode<IntPtrT> RegisterLocation(Register reg);
+ compiler::TNode<IntPtrT> RegisterLocation(compiler::Node* reg_index);
+ compiler::TNode<IntPtrT> NextRegister(compiler::Node* reg_index);
+ compiler::TNode<Object> LoadRegister(Node* reg_index);
void StoreRegister(compiler::Node* value, compiler::Node* reg_index);
// Saves and restores interpreter bytecode offset to the interpreter stack
@@ -311,7 +316,7 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
void UpdateInterruptBudget(compiler::Node* weight, bool backward);
// Returns the offset of register |index| relative to RegisterFilePointer().
- compiler::Node* RegisterFrameOffset(compiler::Node* index);
+ compiler::TNode<IntPtrT> RegisterFrameOffset(compiler::Node* index);
// Returns the offset of an operand relative to the current bytecode offset.
compiler::Node* OperandOffset(int operand_index);
@@ -321,36 +326,36 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
// The |result_type| determines the size and signedness. of the
// value read. This method should only be used on architectures that
// do not support unaligned memory accesses.
- compiler::Node* BytecodeOperandReadUnaligned(
+ compiler::TNode<Word32T> BytecodeOperandReadUnaligned(
int relative_offset, MachineType result_type,
LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
// Returns zero- or sign-extended to word32 value of the operand.
- compiler::Node* BytecodeOperandUnsignedByte(
+ compiler::TNode<Uint8T> BytecodeOperandUnsignedByte(
int operand_index,
LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
- compiler::Node* BytecodeOperandSignedByte(
+ compiler::TNode<Int8T> BytecodeOperandSignedByte(
int operand_index,
LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
- compiler::Node* BytecodeOperandUnsignedShort(
+ compiler::TNode<Uint16T> BytecodeOperandUnsignedShort(
int operand_index,
LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
- compiler::Node* BytecodeOperandSignedShort(
+ compiler::TNode<Int16T> BytecodeOperandSignedShort(
int operand_index,
LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
- compiler::Node* BytecodeOperandUnsignedQuad(
+ compiler::TNode<Uint32T> BytecodeOperandUnsignedQuad(
int operand_index,
LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
- compiler::Node* BytecodeOperandSignedQuad(
+ compiler::TNode<Int32T> BytecodeOperandSignedQuad(
int operand_index,
LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
// Returns zero- or sign-extended to word32 value of the operand of
// given size.
- compiler::Node* BytecodeSignedOperand(
+ compiler::TNode<Int32T> BytecodeSignedOperand(
int operand_index, OperandSize operand_size,
LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
- compiler::Node* BytecodeUnsignedOperand(
+ compiler::TNode<Uint32T> BytecodeUnsignedOperand(
int operand_index, OperandSize operand_size,
LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
@@ -373,30 +378,31 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
compiler::Node* Jump(compiler::Node* jump_offset, bool backward);
// Jump forward relative to the current bytecode by |jump_offset| if the
- // |condition| is true. Helper function for JumpIfWordEqual and
- // JumpIfWordNotEqual.
+ // |condition| is true. Helper function for JumpIfTaggedEqual and
+ // JumpIfTaggedNotEqual.
void JumpConditional(compiler::Node* condition, compiler::Node* jump_offset);
// Save the bytecode offset to the interpreter frame.
void SaveBytecodeOffset();
// Reload the bytecode offset from the interpreter frame.
- Node* ReloadBytecodeOffset();
+ TNode<IntPtrT> ReloadBytecodeOffset();
// Updates and returns BytecodeOffset() advanced by the current bytecode's
// size. Traces the exit of the current bytecode.
- compiler::Node* Advance();
+ TNode<IntPtrT> Advance();
// Updates and returns BytecodeOffset() advanced by delta bytecodes.
// Traces the exit of the current bytecode.
- compiler::Node* Advance(int delta);
- compiler::Node* Advance(compiler::Node* delta, bool backward = false);
+ TNode<IntPtrT> Advance(int delta);
+ TNode<IntPtrT> Advance(SloppyTNode<IntPtrT> delta, bool backward = false);
// Load the bytecode at |bytecode_offset|.
- compiler::Node* LoadBytecode(compiler::Node* bytecode_offset);
+ compiler::TNode<WordT> LoadBytecode(compiler::Node* bytecode_offset);
// Look ahead for Star and inline it in a branch. Returns a new target
// bytecode node for dispatch.
- compiler::Node* StarDispatchLookahead(compiler::Node* target_bytecode);
+ compiler::TNode<WordT> StarDispatchLookahead(
+ compiler::TNode<WordT> target_bytecode);
// Build code for Star at the current BytecodeOffset() and Advance() to the
// next dispatch offset.
@@ -418,17 +424,15 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
Bytecode bytecode_;
OperandScale operand_scale_;
- CodeStubAssembler::Variable interpreted_frame_pointer_;
+ TVariable<RawPtrT> interpreted_frame_pointer_;
CodeStubAssembler::Variable bytecode_array_;
- CodeStubAssembler::Variable bytecode_offset_;
+ TVariable<IntPtrT> bytecode_offset_;
CodeStubAssembler::Variable dispatch_table_;
CodeStubAssembler::Variable accumulator_;
AccumulatorUse accumulator_use_;
bool made_call_;
bool reloaded_frame_ptr_;
bool bytecode_array_valid_;
- bool disable_stack_check_across_call_;
- compiler::Node* stack_pointer_before_call_;
DISALLOW_COPY_AND_ASSIGN(InterpreterAssembler);
};
diff --git a/deps/v8/src/interpreter/interpreter-generator.cc b/deps/v8/src/interpreter/interpreter-generator.cc
index 00ce8eaf68..e8569ecd55 100644
--- a/deps/v8/src/interpreter/interpreter-generator.cc
+++ b/deps/v8/src/interpreter/interpreter-generator.cc
@@ -23,6 +23,7 @@
#include "src/objects/js-generator.h"
#include "src/objects/objects-inl.h"
#include "src/objects/oddball.h"
+#include "src/objects/shared-function-info.h"
#include "src/objects/source-text-module.h"
#include "src/utils/ostreams.h"
@@ -61,7 +62,7 @@ using Variable = CodeStubAssembler::Variable;
//
// Load literal '0' into the accumulator.
IGNITION_HANDLER(LdaZero, InterpreterAssembler) {
- Node* zero_value = NumberConstant(0.0);
+ TNode<Number> zero_value = NumberConstant(0.0);
SetAccumulator(zero_value);
Dispatch();
}
@@ -128,7 +129,7 @@ IGNITION_HANDLER(LdaFalse, InterpreterAssembler) {
//
// Load accumulator with value from register <src>.
IGNITION_HANDLER(Ldar, InterpreterAssembler) {
- Node* value = LoadRegisterAtOperandIndex(0);
+ TNode<Object> value = LoadRegisterAtOperandIndex(0);
SetAccumulator(value);
Dispatch();
}
@@ -137,7 +138,7 @@ IGNITION_HANDLER(Ldar, InterpreterAssembler) {
//
// Store accumulator to register <dst>.
IGNITION_HANDLER(Star, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
+ TNode<Object> accumulator = GetAccumulator();
StoreRegisterAtOperandIndex(accumulator, 0);
Dispatch();
}
@@ -146,7 +147,7 @@ IGNITION_HANDLER(Star, InterpreterAssembler) {
//
// Stores the value of register <src> to register <dst>.
IGNITION_HANDLER(Mov, InterpreterAssembler) {
- Node* src_value = LoadRegisterAtOperandIndex(0);
+ TNode<Object> src_value = LoadRegisterAtOperandIndex(0);
StoreRegisterAtOperandIndex(src_value, 1);
Dispatch();
}
@@ -159,7 +160,7 @@ class InterpreterLoadGlobalAssembler : public InterpreterAssembler {
void LdaGlobal(int slot_operand_index, int name_operand_index,
TypeofMode typeof_mode) {
- Node* maybe_feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
Node* feedback_slot = BytecodeOperandIdx(slot_operand_index);
AccessorAssembler accessor_asm(state());
@@ -168,7 +169,7 @@ class InterpreterLoadGlobalAssembler : public InterpreterAssembler {
Dispatch();
});
- LazyNode<Context> lazy_context = [=] { return CAST(GetContext()); };
+ LazyNode<Context> lazy_context = [=] { return GetContext(); };
LazyNode<Name> lazy_name = [=] {
Node* name = LoadConstantPoolEntryAtOperandIndex(name_operand_index);
@@ -209,14 +210,14 @@ IGNITION_HANDLER(LdaGlobalInsideTypeof, InterpreterLoadGlobalAssembler) {
// Store the value in the accumulator into the global with name in constant pool
// entry <name_index> using FeedBackVector slot <slot>.
IGNITION_HANDLER(StaGlobal, InterpreterAssembler) {
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
// Store the global via the StoreGlobalIC.
Node* name = LoadConstantPoolEntryAtOperandIndex(0);
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(1);
- Node* smi_slot = SmiTag(raw_slot);
- Node* maybe_vector = LoadFeedbackVector();
+ TNode<Smi> smi_slot = SmiTag(raw_slot);
+ TNode<HeapObject> maybe_vector = LoadFeedbackVector();
Label no_feedback(this, Label::kDeferred), end(this);
GotoIf(IsUndefined(maybe_vector), &no_feedback);
@@ -238,11 +239,11 @@ IGNITION_HANDLER(StaGlobal, InterpreterAssembler) {
// Load the object in |slot_index| of the context at |depth| in the context
// chain starting at |context| into the accumulator.
IGNITION_HANDLER(LdaContextSlot, InterpreterAssembler) {
- Node* context = LoadRegisterAtOperandIndex(0);
+ TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
Node* slot_index = BytecodeOperandIdx(1);
- Node* depth = BytecodeOperandUImm(2);
+ TNode<Uint32T> depth = BytecodeOperandUImm(2);
Node* slot_context = GetContextAtDepth(context, depth);
- Node* result = LoadContextElement(slot_context, slot_index);
+ TNode<Object> result = LoadContextElement(slot_context, slot_index);
SetAccumulator(result);
Dispatch();
}
@@ -252,11 +253,11 @@ IGNITION_HANDLER(LdaContextSlot, InterpreterAssembler) {
// Load the object in |slot_index| of the context at |depth| in the context
// chain starting at |context| into the accumulator.
IGNITION_HANDLER(LdaImmutableContextSlot, InterpreterAssembler) {
- Node* context = LoadRegisterAtOperandIndex(0);
+ TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
Node* slot_index = BytecodeOperandIdx(1);
- Node* depth = BytecodeOperandUImm(2);
+ TNode<Uint32T> depth = BytecodeOperandUImm(2);
Node* slot_context = GetContextAtDepth(context, depth);
- Node* result = LoadContextElement(slot_context, slot_index);
+ TNode<Object> result = LoadContextElement(slot_context, slot_index);
SetAccumulator(result);
Dispatch();
}
@@ -266,8 +267,8 @@ IGNITION_HANDLER(LdaImmutableContextSlot, InterpreterAssembler) {
// Load the object in |slot_index| of the current context into the accumulator.
IGNITION_HANDLER(LdaCurrentContextSlot, InterpreterAssembler) {
Node* slot_index = BytecodeOperandIdx(0);
- Node* slot_context = GetContext();
- Node* result = LoadContextElement(slot_context, slot_index);
+ TNode<Context> slot_context = GetContext();
+ TNode<Object> result = LoadContextElement(slot_context, slot_index);
SetAccumulator(result);
Dispatch();
}
@@ -277,8 +278,8 @@ IGNITION_HANDLER(LdaCurrentContextSlot, InterpreterAssembler) {
// Load the object in |slot_index| of the current context into the accumulator.
IGNITION_HANDLER(LdaImmutableCurrentContextSlot, InterpreterAssembler) {
Node* slot_index = BytecodeOperandIdx(0);
- Node* slot_context = GetContext();
- Node* result = LoadContextElement(slot_context, slot_index);
+ TNode<Context> slot_context = GetContext();
+ TNode<Object> result = LoadContextElement(slot_context, slot_index);
SetAccumulator(result);
Dispatch();
}
@@ -288,10 +289,10 @@ IGNITION_HANDLER(LdaImmutableCurrentContextSlot, InterpreterAssembler) {
// Stores the object in the accumulator into |slot_index| of the context at
// |depth| in the context chain starting at |context|.
IGNITION_HANDLER(StaContextSlot, InterpreterAssembler) {
- Node* value = GetAccumulator();
- Node* context = LoadRegisterAtOperandIndex(0);
+ TNode<Object> value = GetAccumulator();
+ TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
Node* slot_index = BytecodeOperandIdx(1);
- Node* depth = BytecodeOperandUImm(2);
+ TNode<Uint32T> depth = BytecodeOperandUImm(2);
Node* slot_context = GetContextAtDepth(context, depth);
StoreContextElement(slot_context, slot_index, value);
Dispatch();
@@ -302,9 +303,9 @@ IGNITION_HANDLER(StaContextSlot, InterpreterAssembler) {
// Stores the object in the accumulator into |slot_index| of the current
// context.
IGNITION_HANDLER(StaCurrentContextSlot, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Node* slot_index = BytecodeOperandIdx(0);
- Node* slot_context = GetContext();
+ TNode<Context> slot_context = GetContext();
StoreContextElement(slot_context, slot_index, value);
Dispatch();
}
@@ -315,8 +316,8 @@ IGNITION_HANDLER(StaCurrentContextSlot, InterpreterAssembler) {
// dynamically.
IGNITION_HANDLER(LdaLookupSlot, InterpreterAssembler) {
Node* name = LoadConstantPoolEntryAtOperandIndex(0);
- Node* context = GetContext();
- Node* result = CallRuntime(Runtime::kLoadLookupSlot, context, name);
+ TNode<Context> context = GetContext();
+ TNode<Object> result = CallRuntime(Runtime::kLoadLookupSlot, context, name);
SetAccumulator(result);
Dispatch();
}
@@ -327,8 +328,8 @@ IGNITION_HANDLER(LdaLookupSlot, InterpreterAssembler) {
// dynamically without causing a NoReferenceError.
IGNITION_HANDLER(LdaLookupSlotInsideTypeof, InterpreterAssembler) {
Node* name = LoadConstantPoolEntryAtOperandIndex(0);
- Node* context = GetContext();
- Node* result =
+ TNode<Context> context = GetContext();
+ TNode<Object> result =
CallRuntime(Runtime::kLoadLookupSlotInsideTypeof, context, name);
SetAccumulator(result);
Dispatch();
@@ -342,9 +343,9 @@ class InterpreterLookupContextSlotAssembler : public InterpreterAssembler {
: InterpreterAssembler(state, bytecode, operand_scale) {}
void LookupContextSlot(Runtime::FunctionId function_id) {
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
Node* slot_index = BytecodeOperandIdx(1);
- Node* depth = BytecodeOperandUImm(2);
+ TNode<Uint32T> depth = BytecodeOperandUImm(2);
Label slowpath(this, Label::kDeferred);
@@ -354,7 +355,7 @@ class InterpreterLookupContextSlotAssembler : public InterpreterAssembler {
// Fast path does a normal load context.
{
Node* slot_context = GetContextAtDepth(context, depth);
- Node* result = LoadContextElement(slot_context, slot_index);
+ TNode<Object> result = LoadContextElement(slot_context, slot_index);
SetAccumulator(result);
Dispatch();
}
@@ -363,7 +364,7 @@ class InterpreterLookupContextSlotAssembler : public InterpreterAssembler {
BIND(&slowpath);
{
Node* name = LoadConstantPoolEntryAtOperandIndex(0);
- Node* result = CallRuntime(function_id, context, name);
+ TNode<Object> result = CallRuntime(function_id, context, name);
SetAccumulator(result);
Dispatch();
}
@@ -394,8 +395,8 @@ class InterpreterLookupGlobalAssembler : public InterpreterLoadGlobalAssembler {
: InterpreterLoadGlobalAssembler(state, bytecode, operand_scale) {}
void LookupGlobalSlot(Runtime::FunctionId function_id) {
- Node* context = GetContext();
- Node* depth = BytecodeOperandUImm(2);
+ TNode<Context> context = GetContext();
+ TNode<Uint32T> depth = BytecodeOperandUImm(2);
Label slowpath(this, Label::kDeferred);
@@ -419,7 +420,7 @@ class InterpreterLookupGlobalAssembler : public InterpreterLoadGlobalAssembler {
BIND(&slowpath);
{
Node* name = LoadConstantPoolEntryAtOperandIndex(0);
- Node* result = CallRuntime(function_id, context, name);
+ TNode<Object> result = CallRuntime(function_id, context, name);
SetAccumulator(result);
Dispatch();
}
@@ -448,10 +449,10 @@ IGNITION_HANDLER(LdaLookupGlobalSlotInsideTypeof,
// Store the object in accumulator to the object with the name in constant
// pool entry |name_index|.
IGNITION_HANDLER(StaLookupSlot, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Node* name = LoadConstantPoolEntryAtOperandIndex(0);
Node* bytecode_flags = BytecodeOperandFlag(1);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
Variable var_result(this, MachineRepresentation::kTagged);
Label sloppy(this), strict(this), end(this);
@@ -505,18 +506,18 @@ IGNITION_HANDLER(StaLookupSlot, InterpreterAssembler) {
// Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at
// constant pool entry <name_index>.
IGNITION_HANDLER(LdaNamedProperty, InterpreterAssembler) {
- Node* feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
Node* feedback_slot = BytecodeOperandIdx(2);
- Node* smi_slot = SmiTag(feedback_slot);
+ TNode<Smi> smi_slot = SmiTag(feedback_slot);
// Load receiver.
- Node* recv = LoadRegisterAtOperandIndex(0);
+ TNode<Object> recv = LoadRegisterAtOperandIndex(0);
// Load the name and context lazily.
LazyNode<Name> name = [=] {
return CAST(LoadConstantPoolEntryAtOperandIndex(1));
};
- LazyNode<Context> context = [=] { return CAST(GetContext()); };
+ LazyNode<Context> context = [=] { return GetContext(); };
Label done(this);
Variable var_result(this, MachineRepresentation::kTagged);
@@ -538,10 +539,11 @@ IGNITION_HANDLER(LdaNamedProperty, InterpreterAssembler) {
//
// Calls the GetProperty builtin for <object> and the key in the accumulator.
IGNITION_HANDLER(LdaNamedPropertyNoFeedback, InterpreterAssembler) {
- Node* object = LoadRegisterAtOperandIndex(0);
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
Node* name = LoadConstantPoolEntryAtOperandIndex(1);
- Node* context = GetContext();
- Node* result = CallBuiltin(Builtins::kGetProperty, context, object, name);
+ TNode<Context> context = GetContext();
+ TNode<Object> result =
+ CallBuiltin(Builtins::kGetProperty, context, object, name);
SetAccumulator(result);
Dispatch();
}
@@ -551,12 +553,12 @@ IGNITION_HANDLER(LdaNamedPropertyNoFeedback, InterpreterAssembler) {
// Calls the KeyedLoadIC at FeedBackVector slot <slot> for <object> and the key
// in the accumulator.
IGNITION_HANDLER(LdaKeyedProperty, InterpreterAssembler) {
- Node* object = LoadRegisterAtOperandIndex(0);
- Node* name = GetAccumulator();
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
+ TNode<Object> name = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(1);
- Node* smi_slot = SmiTag(raw_slot);
- Node* feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<Smi> smi_slot = SmiTag(raw_slot);
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
VARIABLE(var_result, MachineRepresentation::kTagged);
var_result.Bind(CallBuiltin(Builtins::kKeyedLoadIC, context, object, name,
@@ -573,14 +575,14 @@ class InterpreterStoreNamedPropertyAssembler : public InterpreterAssembler {
: InterpreterAssembler(state, bytecode, operand_scale) {}
void StaNamedProperty(Callable ic, NamedPropertyType property_type) {
- Node* code_target = HeapConstant(ic.code());
- Node* object = LoadRegisterAtOperandIndex(0);
+ TNode<Code> code_target = HeapConstant(ic.code());
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
Node* name = LoadConstantPoolEntryAtOperandIndex(1);
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(2);
- Node* smi_slot = SmiTag(raw_slot);
- Node* maybe_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<Smi> smi_slot = SmiTag(raw_slot);
+ TNode<HeapObject> maybe_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
VARIABLE(var_result, MachineRepresentation::kTagged);
var_result.Bind(CallStub(ic.descriptor(), code_target, context, object,
@@ -621,12 +623,12 @@ IGNITION_HANDLER(StaNamedOwnProperty, InterpreterStoreNamedPropertyAssembler) {
// <name_index> with the value in the accumulator.
IGNITION_HANDLER(StaNamedPropertyNoFeedback,
InterpreterStoreNamedPropertyAssembler) {
- Node* object = LoadRegisterAtOperandIndex(0);
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
Node* name = LoadConstantPoolEntryAtOperandIndex(1);
- Node* value = GetAccumulator();
- Node* context = GetContext();
+ TNode<Object> value = GetAccumulator();
+ TNode<Context> context = GetContext();
- Node* result =
+ TNode<Object> result =
CallRuntime(Runtime::kSetNamedProperty, context, object, name, value);
SetAccumulator(result);
Dispatch();
@@ -637,13 +639,13 @@ IGNITION_HANDLER(StaNamedPropertyNoFeedback,
// Calls the KeyedStoreIC at FeedbackVector slot <slot> for <object> and
// the key <key> with the value in the accumulator.
IGNITION_HANDLER(StaKeyedProperty, InterpreterAssembler) {
- Node* object = LoadRegisterAtOperandIndex(0);
- Node* name = LoadRegisterAtOperandIndex(1);
- Node* value = GetAccumulator();
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
+ TNode<Object> name = LoadRegisterAtOperandIndex(1);
+ TNode<Object> value = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(2);
- Node* smi_slot = SmiTag(raw_slot);
- Node* maybe_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<Smi> smi_slot = SmiTag(raw_slot);
+ TNode<HeapObject> maybe_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
VARIABLE(var_result, MachineRepresentation::kTagged);
var_result.Bind(CallBuiltin(Builtins::kKeyedStoreIC, context, object, name,
@@ -662,13 +664,13 @@ IGNITION_HANDLER(StaKeyedProperty, InterpreterAssembler) {
// Calls the StoreInArrayLiteralIC at FeedbackVector slot <slot> for <array> and
// the key <index> with the value in the accumulator.
IGNITION_HANDLER(StaInArrayLiteral, InterpreterAssembler) {
- Node* array = LoadRegisterAtOperandIndex(0);
- Node* index = LoadRegisterAtOperandIndex(1);
- Node* value = GetAccumulator();
+ TNode<Object> array = LoadRegisterAtOperandIndex(0);
+ TNode<Object> index = LoadRegisterAtOperandIndex(1);
+ TNode<Object> value = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(2);
- Node* smi_slot = SmiTag(raw_slot);
- Node* feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<Smi> smi_slot = SmiTag(raw_slot);
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
VARIABLE(var_result, MachineRepresentation::kTagged);
var_result.Bind(CallBuiltin(Builtins::kStoreInArrayLiteralIC, context, array,
@@ -691,14 +693,14 @@ IGNITION_HANDLER(StaInArrayLiteral, InterpreterAssembler) {
// This definition is not observable and is used only for definitions
// in object or class literals.
IGNITION_HANDLER(StaDataPropertyInLiteral, InterpreterAssembler) {
- Node* object = LoadRegisterAtOperandIndex(0);
- Node* name = LoadRegisterAtOperandIndex(1);
- Node* value = GetAccumulator();
- Node* flags = SmiFromInt32(BytecodeOperandFlag(2));
- Node* vector_index = SmiTag(BytecodeOperandIdx(3));
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
+ TNode<Object> name = LoadRegisterAtOperandIndex(1);
+ TNode<Object> value = GetAccumulator();
+ TNode<Smi> flags = SmiFromInt32(BytecodeOperandFlag(2));
+ TNode<Smi> vector_index = SmiTag(BytecodeOperandIdx(3));
- Node* feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
CallRuntime(Runtime::kDefineDataPropertyInLiteral, context, object, name,
value, flags, feedback_vector, vector_index);
@@ -707,10 +709,10 @@ IGNITION_HANDLER(StaDataPropertyInLiteral, InterpreterAssembler) {
IGNITION_HANDLER(CollectTypeProfile, InterpreterAssembler) {
Node* position = BytecodeOperandImmSmi(0);
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
- Node* feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
CallRuntime(Runtime::kCollectTypeProfile, context, position, value,
feedback_vector);
@@ -724,10 +726,11 @@ IGNITION_HANDLER(CollectTypeProfile, InterpreterAssembler) {
// relative to the module context.
IGNITION_HANDLER(LdaModuleVariable, InterpreterAssembler) {
Node* cell_index = BytecodeOperandImmIntPtr(0);
- Node* depth = BytecodeOperandUImm(1);
+ TNode<Uint32T> depth = BytecodeOperandUImm(1);
Node* module_context = GetContextAtDepth(GetContext(), depth);
- Node* module = LoadContextElement(module_context, Context::EXTENSION_INDEX);
+ TNode<SourceTextModule> module =
+ CAST(LoadContextElement(module_context, Context::EXTENSION_INDEX));
Label if_export(this), if_import(this), end(this);
Branch(IntPtrGreaterThan(cell_index, IntPtrConstant(0)), &if_export,
@@ -735,22 +738,24 @@ IGNITION_HANDLER(LdaModuleVariable, InterpreterAssembler) {
BIND(&if_export);
{
- TNode<FixedArray> regular_exports =
- CAST(LoadObjectField(module, SourceTextModule::kRegularExportsOffset));
+ TNode<FixedArray> regular_exports = LoadObjectField<FixedArray>(
+ module, SourceTextModule::kRegularExportsOffset);
// The actual array index is (cell_index - 1).
- Node* export_index = IntPtrSub(cell_index, IntPtrConstant(1));
- Node* cell = LoadFixedArrayElement(regular_exports, export_index);
+ TNode<WordT> export_index = IntPtrSub(cell_index, IntPtrConstant(1));
+ TNode<Cell> cell =
+ CAST(LoadFixedArrayElement(regular_exports, export_index));
SetAccumulator(LoadObjectField(cell, Cell::kValueOffset));
Goto(&end);
}
BIND(&if_import);
{
- TNode<FixedArray> regular_imports =
- CAST(LoadObjectField(module, SourceTextModule::kRegularImportsOffset));
+ TNode<FixedArray> regular_imports = LoadObjectField<FixedArray>(
+ module, SourceTextModule::kRegularImportsOffset);
// The actual array index is (-cell_index - 1).
- Node* import_index = IntPtrSub(IntPtrConstant(-1), cell_index);
- Node* cell = LoadFixedArrayElement(regular_imports, import_index);
+ TNode<WordT> import_index = IntPtrSub(IntPtrConstant(-1), cell_index);
+ TNode<Cell> cell =
+ CAST(LoadFixedArrayElement(regular_imports, import_index));
SetAccumulator(LoadObjectField(cell, Cell::kValueOffset));
Goto(&end);
}
@@ -764,12 +769,13 @@ IGNITION_HANDLER(LdaModuleVariable, InterpreterAssembler) {
// Store accumulator to the module variable identified by <cell_index>.
// <depth> is the depth of the current context relative to the module context.
IGNITION_HANDLER(StaModuleVariable, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Node* cell_index = BytecodeOperandImmIntPtr(0);
- Node* depth = BytecodeOperandUImm(1);
+ TNode<Uint32T> depth = BytecodeOperandUImm(1);
Node* module_context = GetContextAtDepth(GetContext(), depth);
- Node* module = LoadContextElement(module_context, Context::EXTENSION_INDEX);
+ TNode<SourceTextModule> module =
+ CAST(LoadContextElement(module_context, Context::EXTENSION_INDEX));
Label if_export(this), if_import(this), end(this);
Branch(IntPtrGreaterThan(cell_index, IntPtrConstant(0)), &if_export,
@@ -777,11 +783,11 @@ IGNITION_HANDLER(StaModuleVariable, InterpreterAssembler) {
BIND(&if_export);
{
- TNode<FixedArray> regular_exports =
- CAST(LoadObjectField(module, SourceTextModule::kRegularExportsOffset));
+ TNode<FixedArray> regular_exports = LoadObjectField<FixedArray>(
+ module, SourceTextModule::kRegularExportsOffset);
// The actual array index is (cell_index - 1).
- Node* export_index = IntPtrSub(cell_index, IntPtrConstant(1));
- Node* cell = LoadFixedArrayElement(regular_exports, export_index);
+ TNode<WordT> export_index = IntPtrSub(cell_index, IntPtrConstant(1));
+ TNode<Object> cell = LoadFixedArrayElement(regular_exports, export_index);
StoreObjectField(cell, Cell::kValueOffset, value);
Goto(&end);
}
@@ -802,8 +808,8 @@ IGNITION_HANDLER(StaModuleVariable, InterpreterAssembler) {
// Saves the current context in <context>, and pushes the accumulator as the
// new current context.
IGNITION_HANDLER(PushContext, InterpreterAssembler) {
- Node* new_context = GetAccumulator();
- Node* old_context = GetContext();
+ TNode<Context> new_context = CAST(GetAccumulator());
+ TNode<Context> old_context = GetContext();
StoreRegisterAtOperandIndex(old_context, 0);
SetContext(new_context);
Dispatch();
@@ -813,7 +819,7 @@ IGNITION_HANDLER(PushContext, InterpreterAssembler) {
//
// Pops the current context and sets <context> as the new context.
IGNITION_HANDLER(PopContext, InterpreterAssembler) {
- Node* context = LoadRegisterAtOperandIndex(0);
+ TNode<Context> context = CAST(LoadRegisterAtOperandIndex(0));
SetContext(context);
Dispatch();
}
@@ -829,11 +835,11 @@ class InterpreterBinaryOpAssembler : public InterpreterAssembler {
Node* slot, Node* vector, bool lhs_is_smi);
void BinaryOpWithFeedback(BinaryOpGenerator generator) {
- Node* lhs = LoadRegisterAtOperandIndex(0);
- Node* rhs = GetAccumulator();
- Node* context = GetContext();
+ TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
+ TNode<Object> rhs = GetAccumulator();
+ TNode<Context> context = GetContext();
Node* slot_index = BytecodeOperandIdx(1);
- Node* maybe_feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
BinaryOpAssembler binop_asm(state());
Node* result = (binop_asm.*generator)(context, lhs, rhs, slot_index,
@@ -843,11 +849,11 @@ class InterpreterBinaryOpAssembler : public InterpreterAssembler {
}
void BinaryOpSmiWithFeedback(BinaryOpGenerator generator) {
- Node* lhs = GetAccumulator();
+ TNode<Object> lhs = GetAccumulator();
Node* rhs = BytecodeOperandImmSmi(0);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
Node* slot_index = BytecodeOperandIdx(1);
- Node* maybe_feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
BinaryOpAssembler binop_asm(state());
Node* result = (binop_asm.*generator)(context, lhs, rhs, slot_index,
@@ -950,11 +956,11 @@ class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
: InterpreterAssembler(state, bytecode, operand_scale) {}
void BitwiseBinaryOpWithFeedback(Operation bitwise_op) {
- Node* left = LoadRegisterAtOperandIndex(0);
- Node* right = GetAccumulator();
- Node* context = GetContext();
+ TNode<Object> left = LoadRegisterAtOperandIndex(0);
+ TNode<Object> right = GetAccumulator();
+ TNode<Context> context = GetContext();
Node* slot_index = BytecodeOperandIdx(1);
- Node* maybe_feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
TVARIABLE(Smi, var_left_feedback);
TVARIABLE(Smi, var_right_feedback);
@@ -1000,11 +1006,11 @@ class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
}
void BitwiseBinaryOpWithSmi(Operation bitwise_op) {
- Node* left = GetAccumulator();
+ TNode<Object> left = GetAccumulator();
Node* right = BytecodeOperandImmSmi(0);
Node* slot_index = BytecodeOperandIdx(1);
- Node* maybe_feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
TVARIABLE(Smi, var_left_feedback);
VARIABLE(var_left_word32, MachineRepresentation::kWord32);
@@ -1108,10 +1114,10 @@ IGNITION_HANDLER(BitwiseAndSmi, InterpreterBitwiseBinaryOpAssembler) {
//
// Perform bitwise-not on the accumulator.
IGNITION_HANDLER(BitwiseNot, InterpreterAssembler) {
- Node* operand = GetAccumulator();
+ TNode<Object> operand = GetAccumulator();
Node* slot_index = BytecodeOperandIdx(0);
- Node* maybe_feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
VARIABLE(var_word32, MachineRepresentation::kWord32);
TVARIABLE(Smi, var_feedback);
@@ -1202,9 +1208,9 @@ class UnaryNumericOpAssembler : public InterpreterAssembler {
Label if_other(this, Label::kDeferred);
Node* value = var_value.value();
GotoIf(TaggedIsSmi(value), &if_smi);
- Node* map = LoadMap(value);
+ TNode<Map> map = LoadMap(value);
GotoIf(IsHeapNumberMap(map), &if_heapnumber);
- Node* instance_type = LoadMapInstanceType(map);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(map);
GotoIf(IsBigIntInstanceType(instance_type), &if_bigint);
Branch(InstanceTypeEqual(instance_type, ODDBALL_TYPE), &if_oddball,
&if_other);
@@ -1266,7 +1272,7 @@ class UnaryNumericOpAssembler : public InterpreterAssembler {
BIND(&end);
Node* slot_index = BytecodeOperandIdx(0);
- Node* maybe_feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
UpdateFeedback(var_feedback.value(), maybe_feedback_vector, slot_index);
SetAccumulator(var_result.value());
Dispatch();
@@ -1324,9 +1330,9 @@ IGNITION_HANDLER(Negate, NegateAssemblerImpl) { UnaryOpWithFeedback(); }
//
// Convert the object referenced by the accumulator to a name.
IGNITION_HANDLER(ToName, InterpreterAssembler) {
- Node* object = GetAccumulator();
- Node* context = GetContext();
- Node* result = CallBuiltin(Builtins::kToName, context, object);
+ TNode<Object> object = GetAccumulator();
+ TNode<Context> context = GetContext();
+ TNode<Object> result = CallBuiltin(Builtins::kToName, context, object);
StoreRegisterAtOperandIndex(result, 0);
Dispatch();
}
@@ -1349,9 +1355,9 @@ IGNITION_HANDLER(ToNumeric, InterpreterAssembler) {
//
// Convert the object referenced by the accumulator to a JSReceiver.
IGNITION_HANDLER(ToObject, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
- Node* context = GetContext();
- Node* result = CallBuiltin(Builtins::kToObject, context, accumulator);
+ TNode<Object> accumulator = GetAccumulator();
+ TNode<Context> context = GetContext();
+ TNode<Object> result = CallBuiltin(Builtins::kToObject, context, accumulator);
StoreRegisterAtOperandIndex(result, 0);
Dispatch();
}
@@ -1435,7 +1441,7 @@ IGNITION_HANDLER(Dec, IncDecAssembler) { DecWithFeedback(); }
// Perform logical-not on the accumulator, first casting the
// accumulator to a boolean value if required.
IGNITION_HANDLER(ToBooleanLogicalNot, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Variable result(this, MachineRepresentation::kTagged);
Label if_true(this), if_false(this), end(this);
BranchIfToBooleanIsTrue(value, &if_true, &if_false);
@@ -1459,12 +1465,12 @@ IGNITION_HANDLER(ToBooleanLogicalNot, InterpreterAssembler) {
// Perform logical-not on the accumulator, which must already be a boolean
// value.
IGNITION_HANDLER(LogicalNot, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Variable result(this, MachineRepresentation::kTagged);
Label if_true(this), if_false(this), end(this);
- Node* true_value = TrueConstant();
- Node* false_value = FalseConstant();
- Branch(WordEqual(value, true_value), &if_true, &if_false);
+ TNode<Oddball> true_value = TrueConstant();
+ TNode<Oddball> false_value = FalseConstant();
+ Branch(TaggedEqual(value, true_value), &if_true, &if_false);
BIND(&if_true);
{
result.Bind(false_value);
@@ -1472,7 +1478,7 @@ IGNITION_HANDLER(LogicalNot, InterpreterAssembler) {
}
BIND(&if_false);
{
- CSA_ASSERT(this, WordEqual(value, false_value));
+ CSA_ASSERT(this, TaggedEqual(value, false_value));
result.Bind(true_value);
Goto(&end);
}
@@ -1486,7 +1492,7 @@ IGNITION_HANDLER(LogicalNot, InterpreterAssembler) {
// Load the accumulator with the string representating type of the
// object in the accumulator.
IGNITION_HANDLER(TypeOf, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Node* result = Typeof(value);
SetAccumulator(result);
Dispatch();
@@ -1497,11 +1503,12 @@ IGNITION_HANDLER(TypeOf, InterpreterAssembler) {
// Delete the property specified in the accumulator from the object
// referenced by the register operand following strict mode semantics.
IGNITION_HANDLER(DeletePropertyStrict, InterpreterAssembler) {
- Node* object = LoadRegisterAtOperandIndex(0);
- Node* key = GetAccumulator();
- Node* context = GetContext();
- Node* result = CallBuiltin(Builtins::kDeleteProperty, context, object, key,
- SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
+ TNode<Object> key = GetAccumulator();
+ TNode<Context> context = GetContext();
+ TNode<Object> result =
+ CallBuiltin(Builtins::kDeleteProperty, context, object, key,
+ SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
SetAccumulator(result);
Dispatch();
}
@@ -1511,11 +1518,12 @@ IGNITION_HANDLER(DeletePropertyStrict, InterpreterAssembler) {
// Delete the property specified in the accumulator from the object
// referenced by the register operand following sloppy mode semantics.
IGNITION_HANDLER(DeletePropertySloppy, InterpreterAssembler) {
- Node* object = LoadRegisterAtOperandIndex(0);
- Node* key = GetAccumulator();
- Node* context = GetContext();
- Node* result = CallBuiltin(Builtins::kDeleteProperty, context, object, key,
- SmiConstant(Smi::FromEnum(LanguageMode::kSloppy)));
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
+ TNode<Object> key = GetAccumulator();
+ TNode<Context> context = GetContext();
+ TNode<Object> result =
+ CallBuiltin(Builtins::kDeleteProperty, context, object, key,
+ SmiConstant(Smi::FromEnum(LanguageMode::kSloppy)));
SetAccumulator(result);
Dispatch();
}
@@ -1525,9 +1533,9 @@ IGNITION_HANDLER(DeletePropertySloppy, InterpreterAssembler) {
// Get the super constructor from the object referenced by the accumulator.
// The result is stored in register |reg|.
IGNITION_HANDLER(GetSuperConstructor, InterpreterAssembler) {
- Node* active_function = GetAccumulator();
- Node* context = GetContext();
- Node* result = GetSuperConstructor(context, active_function);
+ TNode<JSFunction> active_function = CAST(GetAccumulator());
+ TNode<Context> context = GetContext();
+ TNode<Object> result = GetSuperConstructor(context, active_function);
StoreRegisterAtOperandIndex(result, 0);
Dispatch();
}
@@ -1540,11 +1548,11 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
// Generates code to perform a JS call that collects type feedback.
void JSCall(ConvertReceiverMode receiver_mode) {
- Node* function = LoadRegisterAtOperandIndex(0);
+ TNode<Object> function = LoadRegisterAtOperandIndex(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
Node* slot_id = BytecodeOperandIdx(3);
- Node* maybe_feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
// Collect the {function} feedback.
CollectCallFeedback(function, context, maybe_feedback_vector, slot_id);
@@ -1555,9 +1563,9 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
// Generates code to perform a JS call without collecting feedback.
void JSCallNoFeedback(ConvertReceiverMode receiver_mode) {
- Node* function = LoadRegisterAtOperandIndex(0);
+ TNode<Object> function = LoadRegisterAtOperandIndex(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
// Call the function and dispatch to the next handler.
CallJSAndDispatch(function, context, args, receiver_mode);
@@ -1574,10 +1582,10 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
const int kSlotOperandIndex =
kFirstArgumentOperandIndex + kRecieverAndArgOperandCount;
- Node* function = LoadRegisterAtOperandIndex(0);
+ TNode<Object> function = LoadRegisterAtOperandIndex(0);
Node* slot_id = BytecodeOperandIdx(kSlotOperandIndex);
- Node* maybe_feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
// Collect the {function} feedback.
CollectCallFeedback(function, context, maybe_feedback_vector, slot_id);
@@ -1590,20 +1598,26 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
case 1:
CallJSAndDispatch(
function, context, Int32Constant(arg_count), receiver_mode,
- LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex));
+ static_cast<Node*>(
+ LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex)));
break;
case 2:
CallJSAndDispatch(
function, context, Int32Constant(arg_count), receiver_mode,
- LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex),
- LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1));
+ static_cast<Node*>(
+ LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex)),
+ static_cast<Node*>(
+ LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1)));
break;
case 3:
CallJSAndDispatch(
function, context, Int32Constant(arg_count), receiver_mode,
- LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex),
- LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1),
- LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 2));
+ static_cast<Node*>(
+ LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex)),
+ static_cast<Node*>(
+ LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 1)),
+ static_cast<Node*>(
+ LoadRegisterAtOperandIndex(kFirstArgumentOperandIndex + 2)));
break;
default:
UNREACHABLE();
@@ -1664,7 +1678,7 @@ IGNITION_HANDLER(CallNoFeedback, InterpreterJSCallAssembler) {
IGNITION_HANDLER(CallRuntime, InterpreterAssembler) {
Node* function_id = BytecodeOperandRuntimeId(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
Node* result = CallRuntimeN(function_id, context, args);
SetAccumulator(result);
Dispatch();
@@ -1678,7 +1692,7 @@ IGNITION_HANDLER(CallRuntime, InterpreterAssembler) {
IGNITION_HANDLER(InvokeIntrinsic, InterpreterAssembler) {
Node* function_id = BytecodeOperandIntrinsicId(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
Node* result = GenerateInvokeIntrinsic(this, function_id, context, args);
SetAccumulator(result);
Dispatch();
@@ -1694,7 +1708,7 @@ IGNITION_HANDLER(CallRuntimeForPair, InterpreterAssembler) {
// Call the runtime function.
Node* function_id = BytecodeOperandRuntimeId(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
Node* result_pair = CallRuntimeN(function_id, context, args, 2);
// Store the results in <first_return> and <first_return + 1>
Node* result0 = Projection(0, result_pair);
@@ -1712,9 +1726,9 @@ IGNITION_HANDLER(CallJSRuntime, InterpreterAssembler) {
RegListNodePair args = GetRegisterListAtOperandIndex(1);
// Get the function to call from the native context.
- Node* context = GetContext();
- Node* native_context = LoadNativeContext(context);
- Node* function = LoadContextElement(native_context, context_index);
+ TNode<Context> context = GetContext();
+ TNode<Context> native_context = LoadNativeContext(context);
+ TNode<Object> function = LoadContextElement(native_context, context_index);
// Call the function.
CallJSAndDispatch(function, context, args,
@@ -1728,11 +1742,11 @@ IGNITION_HANDLER(CallJSRuntime, InterpreterAssembler) {
// final argument is always a spread.
//
IGNITION_HANDLER(CallWithSpread, InterpreterAssembler) {
- Node* callable = LoadRegisterAtOperandIndex(0);
+ TNode<Object> callable = LoadRegisterAtOperandIndex(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
Node* slot_id = BytecodeOperandIdx(3);
- Node* maybe_feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
// Call into Runtime function CallWithSpread which does everything.
CallJSWithSpreadAndDispatch(callable, context, args, slot_id,
@@ -1746,12 +1760,12 @@ IGNITION_HANDLER(CallWithSpread, InterpreterAssembler) {
// argument is always a spread. The new.target is in the accumulator.
//
IGNITION_HANDLER(ConstructWithSpread, InterpreterAssembler) {
- Node* new_target = GetAccumulator();
- Node* constructor = LoadRegisterAtOperandIndex(0);
+ TNode<Object> new_target = GetAccumulator();
+ TNode<Object> constructor = LoadRegisterAtOperandIndex(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
Node* slot_id = BytecodeOperandIdx(3);
- Node* feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
Node* result = ConstructWithSpread(constructor, context, new_target, args,
slot_id, feedback_vector);
SetAccumulator(result);
@@ -1765,12 +1779,12 @@ IGNITION_HANDLER(ConstructWithSpread, InterpreterAssembler) {
// registers. The new.target is in the accumulator.
//
IGNITION_HANDLER(Construct, InterpreterAssembler) {
- Node* new_target = GetAccumulator();
- Node* constructor = LoadRegisterAtOperandIndex(0);
+ TNode<Object> new_target = GetAccumulator();
+ TNode<Object> constructor = LoadRegisterAtOperandIndex(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
Node* slot_id = BytecodeOperandIdx(3);
- Node* feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
Node* result = Construct(constructor, context, new_target, args, slot_id,
feedback_vector);
SetAccumulator(result);
@@ -1784,9 +1798,9 @@ class InterpreterCompareOpAssembler : public InterpreterAssembler {
: InterpreterAssembler(state, bytecode, operand_scale) {}
void CompareOpWithFeedback(Operation compare_op) {
- Node* lhs = LoadRegisterAtOperandIndex(0);
- Node* rhs = GetAccumulator();
- Node* context = GetContext();
+ TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
+ TNode<Object> rhs = GetAccumulator();
+ TNode<Context> context = GetContext();
Variable var_type_feedback(this, MachineRepresentation::kTagged);
Node* result;
@@ -1809,7 +1823,7 @@ class InterpreterCompareOpAssembler : public InterpreterAssembler {
}
Node* slot_index = BytecodeOperandIdx(1);
- Node* maybe_feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector,
slot_index);
SetAccumulator(result);
@@ -1866,9 +1880,9 @@ IGNITION_HANDLER(TestGreaterThanOrEqual, InterpreterCompareOpAssembler) {
// Test if the value in the <src> register is equal to the accumulator
// by means of simple comparison. For SMIs and simple reference comparisons.
IGNITION_HANDLER(TestReferenceEqual, InterpreterAssembler) {
- Node* lhs = LoadRegisterAtOperandIndex(0);
- Node* rhs = GetAccumulator();
- Node* result = SelectBooleanConstant(WordEqual(lhs, rhs));
+ TNode<Object> lhs = LoadRegisterAtOperandIndex(0);
+ TNode<Object> rhs = GetAccumulator();
+ TNode<Oddball> result = SelectBooleanConstant(TaggedEqual(lhs, rhs));
SetAccumulator(result);
Dispatch();
}
@@ -1878,12 +1892,12 @@ IGNITION_HANDLER(TestReferenceEqual, InterpreterAssembler) {
// Test if the object referenced by the register operand is a property of the
// object referenced by the accumulator.
IGNITION_HANDLER(TestIn, InterpreterAssembler) {
- Node* name = LoadRegisterAtOperandIndex(0);
- Node* object = GetAccumulator();
+ TNode<Object> name = LoadRegisterAtOperandIndex(0);
+ TNode<Object> object = GetAccumulator();
Node* raw_slot = BytecodeOperandIdx(1);
- Node* smi_slot = SmiTag(raw_slot);
- Node* feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<Smi> smi_slot = SmiTag(raw_slot);
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
VARIABLE(var_result, MachineRepresentation::kTagged);
var_result.Bind(CallBuiltin(Builtins::kKeyedHasIC, context, object, name,
@@ -1897,11 +1911,11 @@ IGNITION_HANDLER(TestIn, InterpreterAssembler) {
// Test if the object referenced by the <src> register is an an instance of type
// referenced by the accumulator.
IGNITION_HANDLER(TestInstanceOf, InterpreterAssembler) {
- Node* object = LoadRegisterAtOperandIndex(0);
- Node* callable = GetAccumulator();
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
+ TNode<Object> callable = GetAccumulator();
Node* slot_id = BytecodeOperandIdx(1);
- Node* feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
Label feedback_done(this);
GotoIf(IsUndefined(feedback_vector), &feedback_done);
@@ -1922,14 +1936,15 @@ IGNITION_HANDLER(TestInstanceOf, InterpreterAssembler) {
// document.all).
IGNITION_HANDLER(TestUndetectable, InterpreterAssembler) {
Label return_false(this), end(this);
- Node* object = GetAccumulator();
+ TNode<Object> object = GetAccumulator();
// If the object is an Smi then return false.
SetAccumulator(FalseConstant());
GotoIf(TaggedIsSmi(object), &end);
// If it is a HeapObject, load the map and check for undetectable bit.
- Node* result = SelectBooleanConstant(IsUndetectableMap(LoadMap(object)));
+ TNode<Oddball> result =
+ SelectBooleanConstant(IsUndetectableMap(LoadMap(CAST(object))));
SetAccumulator(result);
Goto(&end);
@@ -1941,8 +1956,9 @@ IGNITION_HANDLER(TestUndetectable, InterpreterAssembler) {
//
// Test if the value in accumulator is strictly equal to null.
IGNITION_HANDLER(TestNull, InterpreterAssembler) {
- Node* object = GetAccumulator();
- Node* result = SelectBooleanConstant(WordEqual(object, NullConstant()));
+ TNode<Object> object = GetAccumulator();
+ TNode<Oddball> result =
+ SelectBooleanConstant(TaggedEqual(object, NullConstant()));
SetAccumulator(result);
Dispatch();
}
@@ -1951,8 +1967,9 @@ IGNITION_HANDLER(TestNull, InterpreterAssembler) {
//
// Test if the value in the accumulator is strictly equal to undefined.
IGNITION_HANDLER(TestUndefined, InterpreterAssembler) {
- Node* object = GetAccumulator();
- Node* result = SelectBooleanConstant(WordEqual(object, UndefinedConstant()));
+ TNode<Object> object = GetAccumulator();
+ TNode<Oddball> result =
+ SelectBooleanConstant(TaggedEqual(object, UndefinedConstant()));
SetAccumulator(result);
Dispatch();
}
@@ -1962,7 +1979,7 @@ IGNITION_HANDLER(TestUndefined, InterpreterAssembler) {
// Tests if the object in the <accumulator> is typeof the literal represented
// by |literal_flag|.
IGNITION_HANDLER(TestTypeOf, InterpreterAssembler) {
- Node* object = GetAccumulator();
+ TNode<Object> object = GetAccumulator();
Node* literal_flag = BytecodeOperandFlag(0);
#define MAKE_LABEL(name, lower_case) Label if_##lower_case(this);
@@ -1997,25 +2014,25 @@ IGNITION_HANDLER(TestTypeOf, InterpreterAssembler) {
{
Comment("IfString");
GotoIf(TaggedIsSmi(object), &if_false);
- Branch(IsString(object), &if_true, &if_false);
+ Branch(IsString(CAST(object)), &if_true, &if_false);
}
BIND(&if_symbol);
{
Comment("IfSymbol");
GotoIf(TaggedIsSmi(object), &if_false);
- Branch(IsSymbol(object), &if_true, &if_false);
+ Branch(IsSymbol(CAST(object)), &if_true, &if_false);
}
BIND(&if_boolean);
{
Comment("IfBoolean");
- GotoIf(WordEqual(object, TrueConstant()), &if_true);
- Branch(WordEqual(object, FalseConstant()), &if_true, &if_false);
+ GotoIf(TaggedEqual(object, TrueConstant()), &if_true);
+ Branch(TaggedEqual(object, FalseConstant()), &if_true, &if_false);
}
BIND(&if_bigint);
{
Comment("IfBigInt");
GotoIf(TaggedIsSmi(object), &if_false);
- Branch(IsBigInt(object), &if_true, &if_false);
+ Branch(IsBigInt(CAST(object)), &if_true, &if_false);
}
BIND(&if_undefined);
{
@@ -2023,15 +2040,15 @@ IGNITION_HANDLER(TestTypeOf, InterpreterAssembler) {
GotoIf(TaggedIsSmi(object), &if_false);
// Check it is not null and the map has the undetectable bit set.
GotoIf(IsNull(object), &if_false);
- Branch(IsUndetectableMap(LoadMap(object)), &if_true, &if_false);
+ Branch(IsUndetectableMap(LoadMap(CAST(object))), &if_true, &if_false);
}
BIND(&if_function);
{
Comment("IfFunction");
GotoIf(TaggedIsSmi(object), &if_false);
// Check if callable bit is set and not undetectable.
- Node* map_bitfield = LoadMapBitField(LoadMap(object));
- Node* callable_undetectable =
+ TNode<Int32T> map_bitfield = LoadMapBitField(LoadMap(CAST(object)));
+ TNode<Int32T> callable_undetectable =
Word32And(map_bitfield, Int32Constant(Map::IsUndetectableBit::kMask |
Map::IsCallableBit::kMask));
Branch(Word32Equal(callable_undetectable,
@@ -2047,10 +2064,10 @@ IGNITION_HANDLER(TestTypeOf, InterpreterAssembler) {
GotoIf(IsNull(object), &if_true);
// Check if the object is a receiver type and is not undefined or callable.
- Node* map = LoadMap(object);
+ TNode<Map> map = LoadMap(CAST(object));
GotoIfNot(IsJSReceiverMap(map), &if_false);
- Node* map_bitfield = LoadMapBitField(map);
- Node* callable_undetectable =
+ TNode<Int32T> map_bitfield = LoadMapBitField(map);
+ TNode<Int32T> callable_undetectable =
Word32And(map_bitfield, Int32Constant(Map::IsUndetectableBit::kMask |
Map::IsCallableBit::kMask));
Branch(Word32Equal(callable_undetectable, Int32Constant(0)), &if_true,
@@ -2089,7 +2106,7 @@ IGNITION_HANDLER(Jump, InterpreterAssembler) {
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool.
IGNITION_HANDLER(JumpConstant, InterpreterAssembler) {
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
Jump(relative_jump);
}
@@ -2099,11 +2116,10 @@ IGNITION_HANDLER(JumpConstant, InterpreterAssembler) {
// accumulator contains true. This only works for boolean inputs, and
// will misbehave if passed arbitrary input values.
IGNITION_HANDLER(JumpIfTrue, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
+ TNode<Object> accumulator = GetAccumulator();
Node* relative_jump = BytecodeOperandUImmWord(0);
- CSA_ASSERT(this, TaggedIsNotSmi(accumulator));
- CSA_ASSERT(this, IsBoolean(accumulator));
- JumpIfWordEqual(accumulator, TrueConstant(), relative_jump);
+ CSA_ASSERT(this, IsBoolean(CAST(accumulator)));
+ JumpIfTaggedEqual(accumulator, TrueConstant(), relative_jump);
}
// JumpIfTrueConstant <idx>
@@ -2112,11 +2128,10 @@ IGNITION_HANDLER(JumpIfTrue, InterpreterAssembler) {
// pool if the accumulator contains true. This only works for boolean inputs,
// and will misbehave if passed arbitrary input values.
IGNITION_HANDLER(JumpIfTrueConstant, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
- CSA_ASSERT(this, TaggedIsNotSmi(accumulator));
- CSA_ASSERT(this, IsBoolean(accumulator));
- JumpIfWordEqual(accumulator, TrueConstant(), relative_jump);
+ TNode<Object> accumulator = GetAccumulator();
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ CSA_ASSERT(this, IsBoolean(CAST(accumulator)));
+ JumpIfTaggedEqual(accumulator, TrueConstant(), relative_jump);
}
// JumpIfFalse <imm>
@@ -2125,11 +2140,10 @@ IGNITION_HANDLER(JumpIfTrueConstant, InterpreterAssembler) {
// accumulator contains false. This only works for boolean inputs, and
// will misbehave if passed arbitrary input values.
IGNITION_HANDLER(JumpIfFalse, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
+ TNode<Object> accumulator = GetAccumulator();
Node* relative_jump = BytecodeOperandUImmWord(0);
- CSA_ASSERT(this, TaggedIsNotSmi(accumulator));
- CSA_ASSERT(this, IsBoolean(accumulator));
- JumpIfWordEqual(accumulator, FalseConstant(), relative_jump);
+ CSA_ASSERT(this, IsBoolean(CAST(accumulator)));
+ JumpIfTaggedEqual(accumulator, FalseConstant(), relative_jump);
}
// JumpIfFalseConstant <idx>
@@ -2138,11 +2152,10 @@ IGNITION_HANDLER(JumpIfFalse, InterpreterAssembler) {
// pool if the accumulator contains false. This only works for boolean inputs,
// and will misbehave if passed arbitrary input values.
IGNITION_HANDLER(JumpIfFalseConstant, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
- CSA_ASSERT(this, TaggedIsNotSmi(accumulator));
- CSA_ASSERT(this, IsBoolean(accumulator));
- JumpIfWordEqual(accumulator, FalseConstant(), relative_jump);
+ TNode<Object> accumulator = GetAccumulator();
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ CSA_ASSERT(this, IsBoolean(CAST(accumulator)));
+ JumpIfTaggedEqual(accumulator, FalseConstant(), relative_jump);
}
// JumpIfToBooleanTrue <imm>
@@ -2150,7 +2163,7 @@ IGNITION_HANDLER(JumpIfFalseConstant, InterpreterAssembler) {
// Jump by the number of bytes represented by an immediate operand if the object
// referenced by the accumulator is true when the object is cast to boolean.
IGNITION_HANDLER(JumpIfToBooleanTrue, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Node* relative_jump = BytecodeOperandUImmWord(0);
Label if_true(this), if_false(this);
BranchIfToBooleanIsTrue(value, &if_true, &if_false);
@@ -2166,8 +2179,8 @@ IGNITION_HANDLER(JumpIfToBooleanTrue, InterpreterAssembler) {
// pool if the object referenced by the accumulator is true when the object is
// cast to boolean.
IGNITION_HANDLER(JumpIfToBooleanTrueConstant, InterpreterAssembler) {
- Node* value = GetAccumulator();
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ TNode<Object> value = GetAccumulator();
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
Label if_true(this), if_false(this);
BranchIfToBooleanIsTrue(value, &if_true, &if_false);
BIND(&if_true);
@@ -2181,7 +2194,7 @@ IGNITION_HANDLER(JumpIfToBooleanTrueConstant, InterpreterAssembler) {
// Jump by the number of bytes represented by an immediate operand if the object
// referenced by the accumulator is false when the object is cast to boolean.
IGNITION_HANDLER(JumpIfToBooleanFalse, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Node* relative_jump = BytecodeOperandUImmWord(0);
Label if_true(this), if_false(this);
BranchIfToBooleanIsTrue(value, &if_true, &if_false);
@@ -2197,8 +2210,8 @@ IGNITION_HANDLER(JumpIfToBooleanFalse, InterpreterAssembler) {
// pool if the object referenced by the accumulator is false when the object is
// cast to boolean.
IGNITION_HANDLER(JumpIfToBooleanFalseConstant, InterpreterAssembler) {
- Node* value = GetAccumulator();
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ TNode<Object> value = GetAccumulator();
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
Label if_true(this), if_false(this);
BranchIfToBooleanIsTrue(value, &if_true, &if_false);
BIND(&if_true);
@@ -2212,9 +2225,9 @@ IGNITION_HANDLER(JumpIfToBooleanFalseConstant, InterpreterAssembler) {
// Jump by the number of bytes represented by an immediate operand if the object
// referenced by the accumulator is the null constant.
IGNITION_HANDLER(JumpIfNull, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
+ TNode<Object> accumulator = GetAccumulator();
Node* relative_jump = BytecodeOperandUImmWord(0);
- JumpIfWordEqual(accumulator, NullConstant(), relative_jump);
+ JumpIfTaggedEqual(accumulator, NullConstant(), relative_jump);
}
// JumpIfNullConstant <idx>
@@ -2222,9 +2235,9 @@ IGNITION_HANDLER(JumpIfNull, InterpreterAssembler) {
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is the null constant.
IGNITION_HANDLER(JumpIfNullConstant, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
- JumpIfWordEqual(accumulator, NullConstant(), relative_jump);
+ TNode<Object> accumulator = GetAccumulator();
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ JumpIfTaggedEqual(accumulator, NullConstant(), relative_jump);
}
// JumpIfNotNull <imm>
@@ -2232,9 +2245,9 @@ IGNITION_HANDLER(JumpIfNullConstant, InterpreterAssembler) {
// Jump by the number of bytes represented by an immediate operand if the object
// referenced by the accumulator is not the null constant.
IGNITION_HANDLER(JumpIfNotNull, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
+ TNode<Object> accumulator = GetAccumulator();
Node* relative_jump = BytecodeOperandUImmWord(0);
- JumpIfWordNotEqual(accumulator, NullConstant(), relative_jump);
+ JumpIfTaggedNotEqual(accumulator, NullConstant(), relative_jump);
}
// JumpIfNotNullConstant <idx>
@@ -2242,9 +2255,9 @@ IGNITION_HANDLER(JumpIfNotNull, InterpreterAssembler) {
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is not the null constant.
IGNITION_HANDLER(JumpIfNotNullConstant, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
- JumpIfWordNotEqual(accumulator, NullConstant(), relative_jump);
+ TNode<Object> accumulator = GetAccumulator();
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ JumpIfTaggedNotEqual(accumulator, NullConstant(), relative_jump);
}
// JumpIfUndefined <imm>
@@ -2252,9 +2265,9 @@ IGNITION_HANDLER(JumpIfNotNullConstant, InterpreterAssembler) {
// Jump by the number of bytes represented by an immediate operand if the object
// referenced by the accumulator is the undefined constant.
IGNITION_HANDLER(JumpIfUndefined, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
+ TNode<Object> accumulator = GetAccumulator();
Node* relative_jump = BytecodeOperandUImmWord(0);
- JumpIfWordEqual(accumulator, UndefinedConstant(), relative_jump);
+ JumpIfTaggedEqual(accumulator, UndefinedConstant(), relative_jump);
}
// JumpIfUndefinedConstant <idx>
@@ -2262,9 +2275,9 @@ IGNITION_HANDLER(JumpIfUndefined, InterpreterAssembler) {
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is the undefined constant.
IGNITION_HANDLER(JumpIfUndefinedConstant, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
- JumpIfWordEqual(accumulator, UndefinedConstant(), relative_jump);
+ TNode<Object> accumulator = GetAccumulator();
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ JumpIfTaggedEqual(accumulator, UndefinedConstant(), relative_jump);
}
// JumpIfNotUndefined <imm>
@@ -2272,9 +2285,9 @@ IGNITION_HANDLER(JumpIfUndefinedConstant, InterpreterAssembler) {
// Jump by the number of bytes represented by an immediate operand if the object
// referenced by the accumulator is not the undefined constant.
IGNITION_HANDLER(JumpIfNotUndefined, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
+ TNode<Object> accumulator = GetAccumulator();
Node* relative_jump = BytecodeOperandUImmWord(0);
- JumpIfWordNotEqual(accumulator, UndefinedConstant(), relative_jump);
+ JumpIfTaggedNotEqual(accumulator, UndefinedConstant(), relative_jump);
}
// JumpIfNotUndefinedConstant <idx>
@@ -2283,9 +2296,44 @@ IGNITION_HANDLER(JumpIfNotUndefined, InterpreterAssembler) {
// pool if the object referenced by the accumulator is not the undefined
// constant.
IGNITION_HANDLER(JumpIfNotUndefinedConstant, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
- JumpIfWordNotEqual(accumulator, UndefinedConstant(), relative_jump);
+ TNode<Object> accumulator = GetAccumulator();
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ JumpIfTaggedNotEqual(accumulator, UndefinedConstant(), relative_jump);
+}
+
+// JumpIfUndefinedOrNull <imm>
+//
+// Jump by the number of bytes represented by an immediate operand if the object
+// referenced by the accumulator is the undefined constant or the null constant.
+IGNITION_HANDLER(JumpIfUndefinedOrNull, InterpreterAssembler) {
+ TNode<Object> accumulator = GetAccumulator();
+
+ Label do_jump(this);
+ GotoIf(IsUndefined(accumulator), &do_jump);
+ GotoIf(IsNull(accumulator), &do_jump);
+ Dispatch();
+
+ BIND(&do_jump);
+ Node* relative_jump = BytecodeOperandUImmWord(0);
+ Jump(relative_jump);
+}
+
+// JumpIfUndefinedOrNullConstant <idx>
+//
+// Jump by the number of bytes in the Smi in the |idx| entry in the constant
+// pool if the object referenced by the accumulator is the undefined constant or
+// the null constant.
+IGNITION_HANDLER(JumpIfUndefinedOrNullConstant, InterpreterAssembler) {
+ TNode<Object> accumulator = GetAccumulator();
+
+ Label do_jump(this);
+ GotoIf(IsUndefined(accumulator), &do_jump);
+ GotoIf(IsNull(accumulator), &do_jump);
+ Dispatch();
+
+ BIND(&do_jump);
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ Jump(relative_jump);
}
// JumpIfJSReceiver <imm>
@@ -2293,14 +2341,14 @@ IGNITION_HANDLER(JumpIfNotUndefinedConstant, InterpreterAssembler) {
// Jump by the number of bytes represented by an immediate operand if the object
// referenced by the accumulator is a JSReceiver.
IGNITION_HANDLER(JumpIfJSReceiver, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
+ TNode<Object> accumulator = GetAccumulator();
Node* relative_jump = BytecodeOperandUImmWord(0);
Label if_object(this), if_notobject(this, Label::kDeferred), if_notsmi(this);
Branch(TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
BIND(&if_notsmi);
- Branch(IsJSReceiver(accumulator), &if_object, &if_notobject);
+ Branch(IsJSReceiver(CAST(accumulator)), &if_object, &if_notobject);
BIND(&if_object);
Jump(relative_jump);
@@ -2313,14 +2361,14 @@ IGNITION_HANDLER(JumpIfJSReceiver, InterpreterAssembler) {
// Jump by the number of bytes in the Smi in the |idx| entry in the constant
// pool if the object referenced by the accumulator is a JSReceiver.
IGNITION_HANDLER(JumpIfJSReceiverConstant, InterpreterAssembler) {
- Node* accumulator = GetAccumulator();
- Node* relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
+ TNode<Object> accumulator = GetAccumulator();
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntryAtOperandIndex(0);
Label if_object(this), if_notobject(this), if_notsmi(this);
Branch(TaggedIsSmi(accumulator), &if_notobject, &if_notsmi);
BIND(&if_notsmi);
- Branch(IsJSReceiver(accumulator), &if_object, &if_notobject);
+ Branch(IsJSReceiver(CAST(accumulator)), &if_object, &if_notobject);
BIND(&if_object);
Jump(relative_jump);
@@ -2342,7 +2390,7 @@ IGNITION_HANDLER(JumpLoop, InterpreterAssembler) {
// Check if OSR points at the given {loop_depth} are armed by comparing it to
// the current {osr_level} loaded from the header of the BytecodeArray.
Label ok(this), osr_armed(this, Label::kDeferred);
- Node* condition = Int32GreaterThanOrEqual(loop_depth, osr_level);
+ TNode<BoolT> condition = Int32GreaterThanOrEqual(loop_depth, osr_level);
Branch(condition, &ok, &osr_armed);
BIND(&ok);
@@ -2351,8 +2399,8 @@ IGNITION_HANDLER(JumpLoop, InterpreterAssembler) {
BIND(&osr_armed);
{
Callable callable = CodeFactory::InterpreterOnStackReplacement(isolate());
- Node* target = HeapConstant(callable.code());
- Node* context = GetContext();
+ TNode<Code> target = HeapConstant(callable.code());
+ TNode<Context> context = GetContext();
CallStub(callable.descriptor(), target, context);
JumpBackward(relative_jump);
}
@@ -2366,7 +2414,7 @@ IGNITION_HANDLER(JumpLoop, InterpreterAssembler) {
// case_value falls outside of the table |table_length|, fall-through to the
// next bytecode.
IGNITION_HANDLER(SwitchOnSmiNoFeedback, InterpreterAssembler) {
- Node* acc = GetAccumulator();
+ TNode<Object> acc = GetAccumulator();
Node* table_start = BytecodeOperandIdx(0);
Node* table_length = BytecodeOperandUImmWord(1);
Node* case_value_base = BytecodeOperandImmIntPtr(2);
@@ -2378,11 +2426,11 @@ IGNITION_HANDLER(SwitchOnSmiNoFeedback, InterpreterAssembler) {
// accumulator values.
CSA_ASSERT(this, TaggedIsSmi(acc));
- Node* case_value = IntPtrSub(SmiUntag(acc), case_value_base);
+ TNode<WordT> case_value = IntPtrSub(SmiUntag(CAST(acc)), case_value_base);
GotoIf(IntPtrLessThan(case_value, IntPtrConstant(0)), &fall_through);
GotoIf(IntPtrGreaterThanOrEqual(case_value, table_length), &fall_through);
- Node* entry = IntPtrAdd(table_start, case_value);
- Node* relative_jump = LoadAndUntagConstantPoolEntry(entry);
+ TNode<WordT> entry = IntPtrAdd(table_start, case_value);
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntry(entry);
Jump(relative_jump);
BIND(&fall_through);
@@ -2395,10 +2443,10 @@ IGNITION_HANDLER(SwitchOnSmiNoFeedback, InterpreterAssembler) {
// <flags> and the pattern in <pattern_idx>.
IGNITION_HANDLER(CreateRegExpLiteral, InterpreterAssembler) {
Node* pattern = LoadConstantPoolEntryAtOperandIndex(0);
- Node* feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
Node* slot_id = BytecodeOperandIdx(1);
- Node* flags = SmiFromInt32(BytecodeOperandFlag(2));
- Node* context = GetContext();
+ TNode<Smi> flags = SmiFromInt32(BytecodeOperandFlag(2));
+ TNode<Context> context = GetContext();
VARIABLE(result, MachineRepresentation::kTagged);
@@ -2414,9 +2462,9 @@ IGNITION_HANDLER(CreateRegExpLiteral, InterpreterAssembler) {
// Creates an array literal for literal index <literal_idx> with
// CreateArrayLiteral flags <flags> and constant elements in <element_idx>.
IGNITION_HANDLER(CreateArrayLiteral, InterpreterAssembler) {
- Node* feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
Node* slot_id = BytecodeOperandIdx(1);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
Node* bytecode_flags = BytecodeOperandFlag(2);
Label fast_shallow_clone(this), call_runtime(this, Label::kDeferred);
@@ -2439,11 +2487,12 @@ IGNITION_HANDLER(CreateArrayLiteral, InterpreterAssembler) {
BIND(&call_runtime);
{
- Node* flags_raw = DecodeWordFromWord32<CreateArrayLiteralFlags::FlagsBits>(
- bytecode_flags);
- Node* flags = SmiTag(flags_raw);
+ TNode<WordT> flags_raw =
+ DecodeWordFromWord32<CreateArrayLiteralFlags::FlagsBits>(
+ bytecode_flags);
+ TNode<Smi> flags = SmiTag(Signed(flags_raw));
Node* constant_elements = LoadConstantPoolEntryAtOperandIndex(0);
- Node* result =
+ TNode<Object> result =
CallRuntime(Runtime::kCreateArrayLiteral, context, feedback_vector,
SmiTag(slot_id), constant_elements, flags);
SetAccumulator(result);
@@ -2455,9 +2504,9 @@ IGNITION_HANDLER(CreateArrayLiteral, InterpreterAssembler) {
//
// Creates an empty JSArray literal for literal index <literal_idx>.
IGNITION_HANDLER(CreateEmptyArrayLiteral, InterpreterAssembler) {
- Node* feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
Node* slot_id = BytecodeOperandIdx(0);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
Label no_feedback(this, Label::kDeferred), end(this);
VARIABLE(result, MachineRepresentation::kTagged);
@@ -2488,9 +2537,9 @@ IGNITION_HANDLER(CreateEmptyArrayLiteral, InterpreterAssembler) {
// Spread the given iterable from the accumulator into a new JSArray.
// TODO(neis): Turn this into an intrinsic when we're running out of bytecodes.
IGNITION_HANDLER(CreateArrayFromIterable, InterpreterAssembler) {
- Node* iterable = GetAccumulator();
- Node* context = GetContext();
- Node* result =
+ TNode<Object> iterable = GetAccumulator();
+ TNode<Context> context = GetContext();
+ TNode<Object> result =
CallBuiltin(Builtins::kIterableToListWithSymbolLookup, context, iterable);
SetAccumulator(result);
Dispatch();
@@ -2501,7 +2550,7 @@ IGNITION_HANDLER(CreateArrayFromIterable, InterpreterAssembler) {
// Creates an object literal for literal index <literal_idx> with
// CreateObjectLiteralFlags <flags> and constant elements in <element_idx>.
IGNITION_HANDLER(CreateObjectLiteral, InterpreterAssembler) {
- Node* feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
Node* slot_id = BytecodeOperandIdx(1);
Node* bytecode_flags = BytecodeOperandFlag(2);
@@ -2529,13 +2578,14 @@ IGNITION_HANDLER(CreateObjectLiteral, InterpreterAssembler) {
// If we can't do a fast clone, call into the runtime.
Node* object_boilerplate_description =
LoadConstantPoolEntryAtOperandIndex(0);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
- Node* flags_raw = DecodeWordFromWord32<CreateObjectLiteralFlags::FlagsBits>(
- bytecode_flags);
- Node* flags = SmiTag(flags_raw);
+ TNode<WordT> flags_raw =
+ DecodeWordFromWord32<CreateObjectLiteralFlags::FlagsBits>(
+ bytecode_flags);
+ TNode<Smi> flags = SmiTag(Signed(flags_raw));
- Node* result =
+ TNode<Object> result =
CallRuntime(Runtime::kCreateObjectLiteral, context, feedback_vector,
SmiTag(slot_id), object_boilerplate_description, flags);
SetAccumulator(result);
@@ -2548,7 +2598,7 @@ IGNITION_HANDLER(CreateObjectLiteral, InterpreterAssembler) {
//
// Creates an empty JSObject literal.
IGNITION_HANDLER(CreateEmptyObjectLiteral, InterpreterAssembler) {
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
ConstructorBuiltinsAssembler constructor_assembler(state());
Node* result = constructor_assembler.EmitCreateEmptyObjectLiteral(context);
SetAccumulator(result);
@@ -2560,15 +2610,15 @@ IGNITION_HANDLER(CreateEmptyObjectLiteral, InterpreterAssembler) {
// Allocates a new JSObject with each enumerable own property copied from
// {source}, converting getters into data properties.
IGNITION_HANDLER(CloneObject, InterpreterAssembler) {
- Node* source = LoadRegisterAtOperandIndex(0);
+ TNode<Object> source = LoadRegisterAtOperandIndex(0);
Node* bytecode_flags = BytecodeOperandFlag(1);
- Node* raw_flags =
+ TNode<WordT> raw_flags =
DecodeWordFromWord32<CreateObjectLiteralFlags::FlagsBits>(bytecode_flags);
- Node* smi_flags = SmiTag(raw_flags);
+ TNode<Smi> smi_flags = SmiTag(Signed(raw_flags));
Node* raw_slot = BytecodeOperandIdx(2);
- Node* smi_slot = SmiTag(raw_slot);
- Node* maybe_feedback_vector = LoadFeedbackVector();
- Node* context = GetContext();
+ TNode<Smi> smi_slot = SmiTag(raw_slot);
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
+ TNode<Context> context = GetContext();
Variable var_result(this, MachineRepresentation::kTagged);
var_result.Bind(CallBuiltin(Builtins::kCloneObjectIC, context, source,
@@ -2583,7 +2633,7 @@ IGNITION_HANDLER(CloneObject, InterpreterAssembler) {
// accumulator, creating and caching the site object on-demand as per the
// specification.
IGNITION_HANDLER(GetTemplateObject, InterpreterAssembler) {
- Node* feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
Node* slot = BytecodeOperandIdx(1);
Label call_runtime(this, Label::kDeferred);
@@ -2592,7 +2642,7 @@ IGNITION_HANDLER(GetTemplateObject, InterpreterAssembler) {
TNode<Object> cached_value =
CAST(LoadFeedbackVectorSlot(feedback_vector, slot, 0, INTPTR_PARAMETERS));
- GotoIf(WordEqual(cached_value, SmiConstant(0)), &call_runtime);
+ GotoIf(TaggedEqual(cached_value, SmiConstant(0)), &call_runtime);
SetAccumulator(cached_value);
Dispatch();
@@ -2600,13 +2650,14 @@ IGNITION_HANDLER(GetTemplateObject, InterpreterAssembler) {
BIND(&call_runtime);
{
Node* description = LoadConstantPoolEntryAtOperandIndex(0);
- Node* slot_smi = SmiTag(slot);
- Node* closure = LoadRegister(Register::function_closure());
- Node* shared_info =
- LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
- Node* context = GetContext();
- Node* result = CallRuntime(Runtime::kGetTemplateObject, context,
- description, shared_info, slot_smi);
+ TNode<Smi> slot_smi = SmiTag(slot);
+ TNode<JSFunction> closure =
+ CAST(LoadRegister(Register::function_closure()));
+ TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
+ closure, JSFunction::kSharedFunctionInfoOffset);
+ TNode<Context> context = GetContext();
+ TNode<Object> result = CallRuntime(Runtime::kGetTemplateObject, context,
+ description, shared_info, slot_smi);
Label end(this);
GotoIf(IsUndefined(feedback_vector), &end);
@@ -2626,12 +2677,13 @@ IGNITION_HANDLER(GetTemplateObject, InterpreterAssembler) {
IGNITION_HANDLER(CreateClosure, InterpreterAssembler) {
Node* shared = LoadConstantPoolEntryAtOperandIndex(0);
Node* flags = BytecodeOperandFlag(2);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
Node* slot = BytecodeOperandIdx(1);
Label if_undefined(this);
- TNode<FixedArray> feedback_cell_array =
- LoadClosureFeedbackArray(LoadRegister(Register::function_closure()));
+ TNode<ClosureFeedbackCellArray> feedback_cell_array =
+ LoadClosureFeedbackArray(
+ CAST(LoadRegister(Register::function_closure())));
TNode<FeedbackCell> feedback_cell =
CAST(LoadFixedArrayElement(feedback_cell_array, slot));
@@ -2641,7 +2693,7 @@ IGNITION_HANDLER(CreateClosure, InterpreterAssembler) {
BIND(&if_fast);
{
- Node* result =
+ TNode<Object> result =
CallBuiltin(Builtins::kFastNewClosure, context, shared, feedback_cell);
SetAccumulator(result);
Dispatch();
@@ -2655,7 +2707,7 @@ IGNITION_HANDLER(CreateClosure, InterpreterAssembler) {
BIND(&if_newspace);
{
- Node* result =
+ TNode<Object> result =
CallRuntime(Runtime::kNewClosure, context, shared, feedback_cell);
SetAccumulator(result);
Dispatch();
@@ -2663,8 +2715,8 @@ IGNITION_HANDLER(CreateClosure, InterpreterAssembler) {
BIND(&if_oldspace);
{
- Node* result = CallRuntime(Runtime::kNewClosure_Tenured, context, shared,
- feedback_cell);
+ TNode<Object> result = CallRuntime(Runtime::kNewClosure_Tenured, context,
+ shared, feedback_cell);
SetAccumulator(result);
Dispatch();
}
@@ -2676,7 +2728,7 @@ IGNITION_HANDLER(CreateClosure, InterpreterAssembler) {
// Creates a new block context with the scope info constant at |index|.
IGNITION_HANDLER(CreateBlockContext, InterpreterAssembler) {
Node* scope_info = LoadConstantPoolEntryAtOperandIndex(0);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
SetAccumulator(CallRuntime(Runtime::kPushBlockContext, context, scope_info));
Dispatch();
}
@@ -2686,9 +2738,9 @@ IGNITION_HANDLER(CreateBlockContext, InterpreterAssembler) {
// Creates a new context for a catch block with the |exception| in a register
// and the ScopeInfo at |scope_info_idx|.
IGNITION_HANDLER(CreateCatchContext, InterpreterAssembler) {
- Node* exception = LoadRegisterAtOperandIndex(0);
+ TNode<Object> exception = LoadRegisterAtOperandIndex(0);
Node* scope_info = LoadConstantPoolEntryAtOperandIndex(1);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
SetAccumulator(
CallRuntime(Runtime::kPushCatchContext, context, exception, scope_info));
Dispatch();
@@ -2700,8 +2752,8 @@ IGNITION_HANDLER(CreateCatchContext, InterpreterAssembler) {
IGNITION_HANDLER(CreateFunctionContext, InterpreterAssembler) {
Node* scope_info_idx = BytecodeOperandIdx(0);
Node* scope_info = LoadConstantPoolEntry(scope_info_idx);
- Node* slots = BytecodeOperandUImm(1);
- Node* context = GetContext();
+ TNode<Uint32T> slots = BytecodeOperandUImm(1);
+ TNode<Context> context = GetContext();
ConstructorBuiltinsAssembler constructor_assembler(state());
SetAccumulator(constructor_assembler.EmitFastNewFunctionContext(
scope_info, slots, context, FUNCTION_SCOPE));
@@ -2714,8 +2766,8 @@ IGNITION_HANDLER(CreateFunctionContext, InterpreterAssembler) {
IGNITION_HANDLER(CreateEvalContext, InterpreterAssembler) {
Node* scope_info_idx = BytecodeOperandIdx(0);
Node* scope_info = LoadConstantPoolEntry(scope_info_idx);
- Node* slots = BytecodeOperandUImm(1);
- Node* context = GetContext();
+ TNode<Uint32T> slots = BytecodeOperandUImm(1);
+ TNode<Context> context = GetContext();
ConstructorBuiltinsAssembler constructor_assembler(state());
SetAccumulator(constructor_assembler.EmitFastNewFunctionContext(
scope_info, slots, context, EVAL_SCOPE));
@@ -2727,9 +2779,9 @@ IGNITION_HANDLER(CreateEvalContext, InterpreterAssembler) {
// Creates a new context with the ScopeInfo at |scope_info_idx| for a
// with-statement with the object in |register|.
IGNITION_HANDLER(CreateWithContext, InterpreterAssembler) {
- Node* object = LoadRegisterAtOperandIndex(0);
+ TNode<Object> object = LoadRegisterAtOperandIndex(0);
Node* scope_info = LoadConstantPoolEntryAtOperandIndex(1);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
SetAccumulator(
CallRuntime(Runtime::kPushWithContext, context, object, scope_info));
Dispatch();
@@ -2739,8 +2791,8 @@ IGNITION_HANDLER(CreateWithContext, InterpreterAssembler) {
//
// Creates a new mapped arguments object.
IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) {
- Node* closure = LoadRegister(Register::function_closure());
- Node* context = GetContext();
+ TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
+ TNode<Context> context = GetContext();
Label if_duplicate_parameters(this, Label::kDeferred);
Label if_not_duplicate_parameters(this);
@@ -2748,11 +2800,11 @@ IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) {
// Check if function has duplicate parameters.
// TODO(rmcilroy): Remove this check when FastNewSloppyArgumentsStub supports
// duplicate parameters.
- Node* shared_info =
- LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
+ TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
+ closure, JSFunction::kSharedFunctionInfoOffset);
Node* flags = LoadObjectField(shared_info, SharedFunctionInfo::kFlagsOffset,
MachineType::Uint32());
- Node* has_duplicate_parameters =
+ TNode<BoolT> has_duplicate_parameters =
IsSetWord32<SharedFunctionInfo::HasDuplicateParametersBit>(flags);
Branch(has_duplicate_parameters, &if_duplicate_parameters,
&if_not_duplicate_parameters);
@@ -2768,7 +2820,7 @@ IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) {
BIND(&if_duplicate_parameters);
{
- Node* result =
+ TNode<Object> result =
CallRuntime(Runtime::kNewSloppyArguments_Generic, context, closure);
SetAccumulator(result);
Dispatch();
@@ -2779,8 +2831,8 @@ IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) {
//
// Creates a new unmapped arguments object.
IGNITION_HANDLER(CreateUnmappedArguments, InterpreterAssembler) {
- Node* context = GetContext();
- Node* closure = LoadRegister(Register::function_closure());
+ TNode<Context> context = GetContext();
+ TNode<Object> closure = LoadRegister(Register::function_closure());
ArgumentsBuiltinsAssembler builtins_assembler(state());
Node* result =
builtins_assembler.EmitFastNewStrictArguments(context, closure);
@@ -2792,8 +2844,8 @@ IGNITION_HANDLER(CreateUnmappedArguments, InterpreterAssembler) {
//
// Creates a new rest parameter array.
IGNITION_HANDLER(CreateRestParameter, InterpreterAssembler) {
- Node* closure = LoadRegister(Register::function_closure());
- Node* context = GetContext();
+ TNode<Object> closure = LoadRegister(Register::function_closure());
+ TNode<Context> context = GetContext();
ArgumentsBuiltinsAssembler builtins_assembler(state());
Node* result = builtins_assembler.EmitFastNewRestParameter(context, closure);
SetAccumulator(result);
@@ -2804,7 +2856,7 @@ IGNITION_HANDLER(CreateRestParameter, InterpreterAssembler) {
//
// Performs a stack guard check.
IGNITION_HANDLER(StackCheck, InterpreterAssembler) {
- TNode<Context> context = CAST(GetContext());
+ TNode<Context> context = GetContext();
PerformStackCheck(context);
Dispatch();
}
@@ -2814,10 +2866,10 @@ IGNITION_HANDLER(StackCheck, InterpreterAssembler) {
// Sets the pending message to the value in the accumulator, and returns the
// previous pending message in the accumulator.
IGNITION_HANDLER(SetPendingMessage, InterpreterAssembler) {
- Node* pending_message = ExternalConstant(
+ TNode<ExternalReference> pending_message = ExternalConstant(
ExternalReference::address_of_pending_message_obj(isolate()));
Node* previous_message = Load(MachineType::TaggedPointer(), pending_message);
- Node* new_message = GetAccumulator();
+ TNode<Object> new_message = GetAccumulator();
StoreFullTaggedNoWriteBarrier(pending_message, new_message);
SetAccumulator(previous_message);
Dispatch();
@@ -2827,8 +2879,8 @@ IGNITION_HANDLER(SetPendingMessage, InterpreterAssembler) {
//
// Throws the exception in the accumulator.
IGNITION_HANDLER(Throw, InterpreterAssembler) {
- Node* exception = GetAccumulator();
- Node* context = GetContext();
+ TNode<Object> exception = GetAccumulator();
+ TNode<Context> context = GetContext();
CallRuntime(Runtime::kThrow, context, exception);
// We shouldn't ever return from a throw.
Abort(AbortReason::kUnexpectedReturnFromThrow);
@@ -2839,8 +2891,8 @@ IGNITION_HANDLER(Throw, InterpreterAssembler) {
//
// Re-throws the exception in the accumulator.
IGNITION_HANDLER(ReThrow, InterpreterAssembler) {
- Node* exception = GetAccumulator();
- Node* context = GetContext();
+ TNode<Object> exception = GetAccumulator();
+ TNode<Context> context = GetContext();
CallRuntime(Runtime::kReThrow, context, exception);
// We shouldn't ever return from a throw.
Abort(AbortReason::kUnexpectedReturnFromThrow);
@@ -2861,7 +2913,7 @@ IGNITION_HANDLER(Abort, InterpreterAssembler) {
// Return the value in the accumulator.
IGNITION_HANDLER(Return, InterpreterAssembler) {
UpdateInterruptBudgetOnReturn();
- Node* accumulator = GetAccumulator();
+ TNode<Object> accumulator = GetAccumulator();
Return(accumulator);
}
@@ -2869,10 +2921,10 @@ IGNITION_HANDLER(Return, InterpreterAssembler) {
//
// Throws an exception if the value in the accumulator is TheHole.
IGNITION_HANDLER(ThrowReferenceErrorIfHole, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Label throw_error(this, Label::kDeferred);
- GotoIf(WordEqual(value, TheHoleConstant()), &throw_error);
+ GotoIf(TaggedEqual(value, TheHoleConstant()), &throw_error);
Dispatch();
BIND(&throw_error);
@@ -2890,10 +2942,10 @@ IGNITION_HANDLER(ThrowReferenceErrorIfHole, InterpreterAssembler) {
//
// Throws an exception if the value in the accumulator is TheHole.
IGNITION_HANDLER(ThrowSuperNotCalledIfHole, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Label throw_error(this, Label::kDeferred);
- GotoIf(WordEqual(value, TheHoleConstant()), &throw_error);
+ GotoIf(TaggedEqual(value, TheHoleConstant()), &throw_error);
Dispatch();
BIND(&throw_error);
@@ -2910,10 +2962,10 @@ IGNITION_HANDLER(ThrowSuperNotCalledIfHole, InterpreterAssembler) {
// Throws SuperAleradyCalled exception if the value in the accumulator is not
// TheHole.
IGNITION_HANDLER(ThrowSuperAlreadyCalledIfNotHole, InterpreterAssembler) {
- Node* value = GetAccumulator();
+ TNode<Object> value = GetAccumulator();
Label throw_error(this, Label::kDeferred);
- GotoIf(WordNotEqual(value, TheHoleConstant()), &throw_error);
+ GotoIf(TaggedNotEqual(value, TheHoleConstant()), &throw_error);
Dispatch();
BIND(&throw_error);
@@ -2929,7 +2981,7 @@ IGNITION_HANDLER(ThrowSuperAlreadyCalledIfNotHole, InterpreterAssembler) {
//
// Call runtime to handle debugger statement.
IGNITION_HANDLER(Debugger, InterpreterAssembler) {
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
CallStub(CodeFactory::HandleDebuggerStatement(isolate()), context);
Dispatch();
}
@@ -2937,17 +2989,17 @@ IGNITION_HANDLER(Debugger, InterpreterAssembler) {
// DebugBreak
//
// Call runtime to handle a debug break.
-#define DEBUG_BREAK(Name, ...) \
- IGNITION_HANDLER(Name, InterpreterAssembler) { \
- Node* context = GetContext(); \
- Node* accumulator = GetAccumulator(); \
- Node* result_pair = \
- CallRuntime(Runtime::kDebugBreakOnBytecode, context, accumulator); \
- Node* return_value = Projection(0, result_pair); \
- Node* original_bytecode = SmiUntag(Projection(1, result_pair)); \
- MaybeDropFrames(context); \
- SetAccumulator(return_value); \
- DispatchToBytecode(original_bytecode, BytecodeOffset()); \
+#define DEBUG_BREAK(Name, ...) \
+ IGNITION_HANDLER(Name, InterpreterAssembler) { \
+ TNode<Context> context = GetContext(); \
+ TNode<Object> accumulator = GetAccumulator(); \
+ TNode<Object> result_pair = \
+ CallRuntime(Runtime::kDebugBreakOnBytecode, context, accumulator); \
+ Node* return_value = Projection(0, result_pair); \
+ TNode<IntPtrT> original_bytecode = SmiUntag(Projection(1, result_pair)); \
+ MaybeDropFrames(context); \
+ SetAccumulator(return_value); \
+ DispatchToBytecode(original_bytecode, BytecodeOffset()); \
}
DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK)
#undef DEBUG_BREAK
@@ -2957,9 +3009,9 @@ DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK)
// Increment the execution count for the given slot. Used for block code
// coverage.
IGNITION_HANDLER(IncBlockCounter, InterpreterAssembler) {
- Node* closure = LoadRegister(Register::function_closure());
+ TNode<Object> closure = LoadRegister(Register::function_closure());
Node* coverage_array_slot = BytecodeOperandIdxSmi(0);
- Node* context = GetContext();
+ TNode<Context> context = GetContext();
CallBuiltin(Builtins::kIncBlockCounter, context, closure,
coverage_array_slot);
@@ -2973,8 +3025,8 @@ IGNITION_HANDLER(IncBlockCounter, InterpreterAssembler) {
// map of the |receiver| if it has a usable enum cache or a fixed array
// with the keys to enumerate in the accumulator.
IGNITION_HANDLER(ForInEnumerate, InterpreterAssembler) {
- Node* receiver = LoadRegisterAtOperandIndex(0);
- Node* context = GetContext();
+ TNode<Object> receiver = LoadRegisterAtOperandIndex(0);
+ TNode<Context> context = GetContext();
Label if_empty(this), if_runtime(this, Label::kDeferred);
Node* receiver_map = CheckEnumCache(receiver, &if_empty, &if_runtime);
@@ -2983,14 +3035,15 @@ IGNITION_HANDLER(ForInEnumerate, InterpreterAssembler) {
BIND(&if_empty);
{
- Node* result = EmptyFixedArrayConstant();
+ TNode<FixedArray> result = EmptyFixedArrayConstant();
SetAccumulator(result);
Dispatch();
}
BIND(&if_runtime);
{
- Node* result = CallRuntime(Runtime::kForInEnumerate, context, receiver);
+ TNode<Object> result =
+ CallRuntime(Runtime::kForInEnumerate, context, receiver);
SetAccumulator(result);
Dispatch();
}
@@ -3005,12 +3058,10 @@ IGNITION_HANDLER(ForInEnumerate, InterpreterAssembler) {
// |cache_info_triple + 2|, with the registers holding cache_type, cache_array,
// and cache_length respectively.
IGNITION_HANDLER(ForInPrepare, InterpreterAssembler) {
- Node* enumerator = GetAccumulator();
- Node* vector_index = BytecodeOperandIdx(1);
- Node* maybe_feedback_vector = LoadFeedbackVector();
-
// The {enumerator} is either a Map or a FixedArray.
- CSA_ASSERT(this, TaggedIsNotSmi(enumerator));
+ TNode<HeapObject> enumerator = CAST(GetAccumulator());
+ Node* vector_index = BytecodeOperandIdx(1);
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
// Check if we're using an enum cache.
Label if_fast(this), if_slow(this);
@@ -3019,18 +3070,22 @@ IGNITION_HANDLER(ForInPrepare, InterpreterAssembler) {
BIND(&if_fast);
{
// Load the enumeration length and cache from the {enumerator}.
- Node* enum_length = LoadMapEnumLength(enumerator);
+ TNode<Map> map_enumerator = CAST(enumerator);
+ TNode<WordT> enum_length = LoadMapEnumLength(map_enumerator);
CSA_ASSERT(this, WordNotEqual(enum_length,
IntPtrConstant(kInvalidEnumCacheSentinel)));
- Node* descriptors = LoadMapDescriptors(enumerator);
- Node* enum_cache =
- LoadObjectField(descriptors, DescriptorArray::kEnumCacheOffset);
- Node* enum_keys = LoadObjectField(enum_cache, EnumCache::kKeysOffset);
+ TNode<DescriptorArray> descriptors = LoadMapDescriptors(map_enumerator);
+ TNode<EnumCache> enum_cache = LoadObjectField<EnumCache>(
+ descriptors, DescriptorArray::kEnumCacheOffset);
+ TNode<FixedArray> enum_keys =
+ LoadObjectField<FixedArray>(enum_cache, EnumCache::kKeysOffset);
// Check if we have enum indices available.
- Node* enum_indices = LoadObjectField(enum_cache, EnumCache::kIndicesOffset);
- Node* enum_indices_length = LoadAndUntagFixedArrayBaseLength(enum_indices);
- Node* feedback = SelectSmiConstant(
+ TNode<FixedArray> enum_indices =
+ LoadObjectField<FixedArray>(enum_cache, EnumCache::kIndicesOffset);
+ TNode<IntPtrT> enum_indices_length =
+ LoadAndUntagFixedArrayBaseLength(enum_indices);
+ TNode<Smi> feedback = SelectSmiConstant(
IntPtrLessThanOrEqual(enum_length, enum_indices_length),
ForInFeedback::kEnumCacheKeysAndIndices, ForInFeedback::kEnumCacheKeys);
UpdateFeedback(feedback, maybe_feedback_vector, vector_index);
@@ -3038,7 +3093,7 @@ IGNITION_HANDLER(ForInPrepare, InterpreterAssembler) {
// Construct the cache info triple.
Node* cache_type = enumerator;
Node* cache_array = enum_keys;
- Node* cache_length = SmiTag(enum_length);
+ TNode<Smi> cache_length = SmiTag(Signed(enum_length));
StoreRegisterTripleAtOperandIndex(cache_type, cache_array, cache_length, 0);
Dispatch();
}
@@ -3046,16 +3101,16 @@ IGNITION_HANDLER(ForInPrepare, InterpreterAssembler) {
BIND(&if_slow);
{
// The {enumerator} is a FixedArray with all the keys to iterate.
- CSA_ASSERT(this, IsFixedArray(enumerator));
+ TNode<FixedArray> array_enumerator = CAST(enumerator);
// Record the fact that we hit the for-in slow-path.
UpdateFeedback(SmiConstant(ForInFeedback::kAny), maybe_feedback_vector,
vector_index);
// Construct the cache info triple.
- Node* cache_type = enumerator;
- Node* cache_array = enumerator;
- Node* cache_length = LoadFixedArrayBaseLength(enumerator);
+ Node* cache_type = array_enumerator;
+ Node* cache_array = array_enumerator;
+ TNode<Smi> cache_length = LoadFixedArrayBaseLength(array_enumerator);
StoreRegisterTripleAtOperandIndex(cache_type, cache_array, cache_length, 0);
Dispatch();
}
@@ -3065,22 +3120,22 @@ IGNITION_HANDLER(ForInPrepare, InterpreterAssembler) {
//
// Returns the next enumerable property in the the accumulator.
IGNITION_HANDLER(ForInNext, InterpreterAssembler) {
- Node* receiver = LoadRegisterAtOperandIndex(0);
- Node* index = LoadRegisterAtOperandIndex(1);
- Node* cache_type;
- Node* cache_array;
+ TNode<HeapObject> receiver = CAST(LoadRegisterAtOperandIndex(0));
+ TNode<Object> index = LoadRegisterAtOperandIndex(1);
+ TNode<Object> cache_type;
+ TNode<Object> cache_array;
std::tie(cache_type, cache_array) = LoadRegisterPairAtOperandIndex(2);
Node* vector_index = BytecodeOperandIdx(3);
- Node* maybe_feedback_vector = LoadFeedbackVector();
+ TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
// Load the next key from the enumeration array.
- Node* key = LoadFixedArrayElement(CAST(cache_array), index, 0,
- CodeStubAssembler::SMI_PARAMETERS);
+ TNode<Object> key = LoadFixedArrayElement(CAST(cache_array), index, 0,
+ CodeStubAssembler::SMI_PARAMETERS);
// Check if we can use the for-in fast path potentially using the enum cache.
Label if_fast(this), if_slow(this, Label::kDeferred);
- Node* receiver_map = LoadMap(receiver);
- Branch(WordEqual(receiver_map, cache_type), &if_fast, &if_slow);
+ TNode<Map> receiver_map = LoadMap(receiver);
+ Branch(TaggedEqual(receiver_map, cache_type), &if_fast, &if_slow);
BIND(&if_fast);
{
// Enum cache in use for {receiver}, the {key} is definitely valid.
@@ -3094,8 +3149,9 @@ IGNITION_HANDLER(ForInNext, InterpreterAssembler) {
vector_index);
// Need to filter the {key} for the {receiver}.
- Node* context = GetContext();
- Node* result = CallBuiltin(Builtins::kForInFilter, context, key, receiver);
+ TNode<Context> context = GetContext();
+ TNode<Object> result =
+ CallBuiltin(Builtins::kForInFilter, context, key, receiver);
SetAccumulator(result);
Dispatch();
}
@@ -3105,12 +3161,12 @@ IGNITION_HANDLER(ForInNext, InterpreterAssembler) {
//
// Returns false if the end of the enumerable properties has been reached.
IGNITION_HANDLER(ForInContinue, InterpreterAssembler) {
- Node* index = LoadRegisterAtOperandIndex(0);
- Node* cache_length = LoadRegisterAtOperandIndex(1);
+ TNode<Object> index = LoadRegisterAtOperandIndex(0);
+ TNode<Object> cache_length = LoadRegisterAtOperandIndex(1);
// Check if {index} is at {cache_length} already.
Label if_true(this), if_false(this), end(this);
- Branch(WordEqual(index, cache_length), &if_true, &if_false);
+ Branch(TaggedEqual(index, cache_length), &if_true, &if_false);
BIND(&if_true);
{
SetAccumulator(FalseConstant());
@@ -3137,6 +3193,26 @@ IGNITION_HANDLER(ForInStep, InterpreterAssembler) {
Dispatch();
}
+// GetIterator <object>
+//
+// Retrieves the object[Symbol.iterator] method and stores the result
+// in the accumulator
+// TODO(swapnilgaikwad): Extend the functionality of the bytecode to call
+// iterator method for an object
+IGNITION_HANDLER(GetIterator, InterpreterAssembler) {
+ TNode<Object> receiver = LoadRegisterAtOperandIndex(0);
+ TNode<Context> context = GetContext();
+ TNode<HeapObject> feedback_vector = LoadFeedbackVector();
+ Node* feedback_slot = BytecodeOperandIdx(1);
+ TNode<Smi> smi_slot = SmiTag(feedback_slot);
+
+ TNode<Object> result =
+ CallBuiltin(Builtins::kGetIteratorWithFeedback, context, receiver,
+ smi_slot, feedback_vector);
+ SetAccumulator(result);
+ Dispatch();
+}
+
// Wide
//
// Prefix bytecode indicating next bytecode has wide (16-bit) operands.
@@ -3167,16 +3243,16 @@ IGNITION_HANDLER(Illegal, InterpreterAssembler) {
// (for debugging purposes) into the generator. Then, returns the value
// in the accumulator.
IGNITION_HANDLER(SuspendGenerator, InterpreterAssembler) {
- Node* generator = LoadRegisterAtOperandIndex(0);
+ TNode<JSGeneratorObject> generator = CAST(LoadRegisterAtOperandIndex(0));
TNode<FixedArray> array = CAST(LoadObjectField(
generator, JSGeneratorObject::kParametersAndRegistersOffset));
- Node* closure = LoadRegister(Register::function_closure());
- Node* context = GetContext();
+ TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
+ TNode<Context> context = GetContext();
RegListNodePair registers = GetRegisterListAtOperandIndex(1);
Node* suspend_id = BytecodeOperandUImmSmi(3);
- Node* shared =
- LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
+ TNode<SharedFunctionInfo> shared =
+ CAST(LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset));
TNode<Int32T> formal_parameter_count = UncheckedCast<Int32T>(
LoadObjectField(shared, SharedFunctionInfo::kFormalParameterCountOffset,
MachineType::Uint16()));
@@ -3188,7 +3264,7 @@ IGNITION_HANDLER(SuspendGenerator, InterpreterAssembler) {
// Store the bytecode offset in the [input_or_debug_pos] field, to be used by
// the inspector.
- Node* offset = SmiTag(BytecodeOffset());
+ TNode<Smi> offset = SmiTag(BytecodeOffset());
StoreObjectField(generator, JSGeneratorObject::kInputOrDebugPosOffset,
offset);
@@ -3204,18 +3280,21 @@ IGNITION_HANDLER(SuspendGenerator, InterpreterAssembler) {
// generator's state by looking up the generator state in a jump table in the
// constant pool, starting at |table_start|, and of length |table_length|.
IGNITION_HANDLER(SwitchOnGeneratorState, InterpreterAssembler) {
- Node* generator = LoadRegisterAtOperandIndex(0);
+ TNode<Object> maybe_generator = LoadRegisterAtOperandIndex(0);
Label fallthrough(this);
- GotoIf(WordEqual(generator, UndefinedConstant()), &fallthrough);
+ GotoIf(TaggedEqual(maybe_generator, UndefinedConstant()), &fallthrough);
- Node* state =
- LoadObjectField(generator, JSGeneratorObject::kContinuationOffset);
- Node* new_state = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
+ TNode<JSGeneratorObject> generator = CAST(maybe_generator);
+
+ TNode<Smi> state =
+ CAST(LoadObjectField(generator, JSGeneratorObject::kContinuationOffset));
+ TNode<Smi> new_state = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
StoreObjectField(generator, JSGeneratorObject::kContinuationOffset,
new_state);
- Node* context = LoadObjectField(generator, JSGeneratorObject::kContextOffset);
+ TNode<Context> context =
+ CAST(LoadObjectField(generator, JSGeneratorObject::kContextOffset));
SetContext(context);
Node* table_start = BytecodeOperandIdx(1);
@@ -3226,14 +3305,14 @@ IGNITION_HANDLER(SwitchOnGeneratorState, InterpreterAssembler) {
// The state must be a Smi.
CSA_ASSERT(this, TaggedIsSmi(state));
- Node* case_value = SmiUntag(state);
+ TNode<IntPtrT> case_value = SmiUntag(state);
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(case_value, IntPtrConstant(0)));
CSA_ASSERT(this, IntPtrLessThan(case_value, table_length));
USE(table_length);
- Node* entry = IntPtrAdd(table_start, case_value);
- Node* relative_jump = LoadAndUntagConstantPoolEntry(entry);
+ TNode<WordT> entry = IntPtrAdd(table_start, case_value);
+ TNode<IntPtrT> relative_jump = LoadAndUntagConstantPoolEntry(entry);
Jump(relative_jump);
BIND(&fallthrough);
@@ -3245,12 +3324,12 @@ IGNITION_HANDLER(SwitchOnGeneratorState, InterpreterAssembler) {
// Imports the register file stored in the generator and marks the generator
// state as executing.
IGNITION_HANDLER(ResumeGenerator, InterpreterAssembler) {
- Node* generator = LoadRegisterAtOperandIndex(0);
- Node* closure = LoadRegister(Register::function_closure());
+ TNode<JSGeneratorObject> generator = CAST(LoadRegisterAtOperandIndex(0));
+ TNode<JSFunction> closure = CAST(LoadRegister(Register::function_closure()));
RegListNodePair registers = GetRegisterListAtOperandIndex(1);
- Node* shared =
- LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
+ TNode<SharedFunctionInfo> shared =
+ CAST(LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset));
TNode<Int32T> formal_parameter_count = UncheckedCast<Int32T>(
LoadObjectField(shared, SharedFunctionInfo::kFormalParameterCountOffset,
MachineType::Uint16()));
@@ -3267,6 +3346,8 @@ IGNITION_HANDLER(ResumeGenerator, InterpreterAssembler) {
Dispatch();
}
+#undef IGNITION_HANDLER
+
} // namespace
Handle<Code> GenerateBytecodeHandler(Isolate* isolate, Bytecode bytecode,
diff --git a/deps/v8/src/interpreter/interpreter-intrinsics-generator.cc b/deps/v8/src/interpreter/interpreter-intrinsics-generator.cc
index d581802340..a329e7189f 100644
--- a/deps/v8/src/interpreter/interpreter-intrinsics-generator.cc
+++ b/deps/v8/src/interpreter/interpreter-intrinsics-generator.cc
@@ -47,7 +47,7 @@ class IntrinsicsGenerator {
Node* IntrinsicAsBuiltinCall(
const InterpreterAssembler::RegListNodePair& args, Node* context,
Builtins::Name name);
- void AbortIfArgCountMismatch(int expected, compiler::Node* actual);
+ void AbortIfArgCountMismatch(int expected, compiler::TNode<Word32T> actual);
#define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \
Node* name(const InterpreterAssembler::RegListNodePair& args, Node* context);
@@ -124,7 +124,7 @@ Node* IntrinsicsGenerator::InvokeIntrinsic(
Node* IntrinsicsGenerator::CompareInstanceType(Node* object, int type,
InstanceTypeCompareMode mode) {
- Node* instance_type = __ LoadInstanceType(object);
+ TNode<Uint16T> instance_type = __ LoadInstanceType(object);
if (mode == kInstanceTypeEqual) {
return __ Word32Equal(instance_type, __ Int32Constant(type));
@@ -239,7 +239,7 @@ Node* IntrinsicsGenerator::Call(
if (FLAG_debug_code) {
InterpreterAssembler::Label arg_count_positive(assembler_);
- Node* comparison =
+ TNode<BoolT> comparison =
__ Int32LessThan(target_args.reg_count(), __ Int32Constant(0));
__ GotoIfNot(comparison, &arg_count_positive);
__ Abort(AbortReason::kWrongArgumentCountForInvokeIntrinsic);
@@ -265,13 +265,13 @@ Node* IntrinsicsGenerator::CreateAsyncFromSyncIterator(
__ GotoIf(__ TaggedIsSmi(sync_iterator), &not_receiver);
__ GotoIfNot(__ IsJSReceiver(sync_iterator), &not_receiver);
- Node* const next =
+ TNode<Object> const next =
__ GetProperty(context, sync_iterator, factory()->next_string());
- Node* const native_context = __ LoadNativeContext(context);
- Node* const map = __ LoadContextElement(
- native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX);
- Node* const iterator = __ AllocateJSObjectFromMap(map);
+ TNode<Context> const native_context = __ LoadNativeContext(context);
+ TNode<Map> const map = __ CAST(__ LoadContextElement(
+ native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX));
+ TNode<JSObject> const iterator = __ AllocateJSObjectFromMap(map);
__ StoreObjectFieldNoWriteBarrier(
iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator);
@@ -303,7 +303,7 @@ Node* IntrinsicsGenerator::CreateJSGeneratorObject(
Node* IntrinsicsGenerator::GeneratorGetResumeMode(
const InterpreterAssembler::RegListNodePair& args, Node* context) {
Node* generator = __ LoadRegisterFromRegisterList(args, 0);
- Node* const value =
+ TNode<Object> const value =
__ LoadObjectField(generator, JSGeneratorObject::kResumeModeOffset);
return value;
@@ -320,10 +320,10 @@ Node* IntrinsicsGenerator::GeneratorClose(
Node* IntrinsicsGenerator::GetImportMetaObject(
const InterpreterAssembler::RegListNodePair& args, Node* context) {
- Node* const module_context = __ LoadModuleContext(context);
- Node* const module =
- __ LoadContextElement(module_context, Context::EXTENSION_INDEX);
- Node* const import_meta =
+ TNode<Context> const module_context = __ LoadModuleContext(context);
+ TNode<HeapObject> const module =
+ __ CAST(__ LoadContextElement(module_context, Context::EXTENSION_INDEX));
+ TNode<Object> const import_meta =
__ LoadObjectField(module, SourceTextModule::kImportMetaOffset);
InterpreterAssembler::Variable return_value(assembler_,
@@ -395,9 +395,10 @@ Node* IntrinsicsGenerator::AsyncGeneratorYield(
return IntrinsicAsBuiltinCall(args, context, Builtins::kAsyncGeneratorYield);
}
-void IntrinsicsGenerator::AbortIfArgCountMismatch(int expected, Node* actual) {
+void IntrinsicsGenerator::AbortIfArgCountMismatch(int expected,
+ TNode<Word32T> actual) {
InterpreterAssembler::Label match(assembler_);
- Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
+ TNode<BoolT> comparison = __ Word32Equal(actual, __ Int32Constant(expected));
__ GotoIf(comparison, &match);
__ Abort(AbortReason::kWrongArgumentCountForInvokeIntrinsic);
__ Goto(&match);
diff --git a/deps/v8/src/interpreter/interpreter.cc b/deps/v8/src/interpreter/interpreter.cc
index eb91ae06a4..121971d305 100644
--- a/deps/v8/src/interpreter/interpreter.cc
+++ b/deps/v8/src/interpreter/interpreter.cc
@@ -9,6 +9,7 @@
#include "builtins-generated/bytecodes-builtins-list.h"
#include "src/ast/prettyprinter.h"
+#include "src/ast/scopes.h"
#include "src/codegen/compiler.h"
#include "src/codegen/unoptimized-compilation-info.h"
#include "src/init/bootstrapper.h"
@@ -42,6 +43,8 @@ class InterpreterCompilationJob final : public UnoptimizedCompilationJob {
private:
BytecodeGenerator* generator() { return &generator_; }
+ void CheckAndPrintBytecodeMismatch(Isolate* isolate,
+ Handle<BytecodeArray> bytecode);
Zone zone_;
UnoptimizedCompilationInfo compilation_info_;
@@ -202,6 +205,25 @@ InterpreterCompilationJob::Status InterpreterCompilationJob::ExecuteJobImpl() {
return SUCCEEDED;
}
+#ifdef DEBUG
+void InterpreterCompilationJob::CheckAndPrintBytecodeMismatch(
+ Isolate* isolate, Handle<BytecodeArray> bytecode) {
+ int first_mismatch = generator()->CheckBytecodeMatches(bytecode);
+ if (first_mismatch >= 0) {
+ parse_info()->ast_value_factory()->Internalize(isolate);
+ DeclarationScope::AllocateScopeInfos(parse_info(), isolate);
+
+ Handle<BytecodeArray> new_bytecode =
+ generator()->FinalizeBytecode(isolate, parse_info()->script());
+ std::cerr << "Bytecode mismatch\nOriginal bytecode:\n";
+ bytecode->Disassemble(std::cerr);
+ std::cerr << "\nNew bytecode:\n";
+ new_bytecode->Disassemble(std::cerr);
+ FATAL("Bytecode mismatch at offset %d\n", first_mismatch);
+ }
+}
+#endif
+
InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl(
Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
RuntimeCallTimerScope runtimeTimerScope(
@@ -210,23 +232,36 @@ InterpreterCompilationJob::Status InterpreterCompilationJob::FinalizeJobImpl(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileIgnitionFinalization");
- Handle<BytecodeArray> bytecodes =
- generator()->FinalizeBytecode(isolate, parse_info()->script());
- if (generator()->HasStackOverflow()) {
- return FAILED;
+ Handle<BytecodeArray> bytecodes = compilation_info_.bytecode_array();
+ if (bytecodes.is_null()) {
+ bytecodes = generator()->FinalizeBytecode(isolate, parse_info()->script());
+ if (generator()->HasStackOverflow()) {
+ return FAILED;
+ }
+ compilation_info()->SetBytecodeArray(bytecodes);
+ }
+
+ if (compilation_info()->SourcePositionRecordingMode() ==
+ SourcePositionTableBuilder::RecordingMode::RECORD_SOURCE_POSITIONS) {
+ Handle<ByteArray> source_position_table =
+ generator()->FinalizeSourcePositionTable(isolate);
+ bytecodes->set_source_position_table(*source_position_table);
}
if (ShouldPrintBytecode(shared_info)) {
StdoutStream os;
std::unique_ptr<char[]> name =
compilation_info()->literal()->GetDebugName();
- os << "[generated bytecode for function: " << name.get() << "]"
- << std::endl;
+ os << "[generated bytecode for function: " << name.get() << " ("
+ << shared_info << ")]" << std::endl;
bytecodes->Disassemble(os);
os << std::flush;
}
- compilation_info()->SetBytecodeArray(bytecodes);
+#ifdef DEBUG
+ CheckAndPrintBytecodeMismatch(isolate, bytecodes);
+#endif
+
return SUCCEEDED;
}
@@ -238,6 +273,16 @@ std::unique_ptr<UnoptimizedCompilationJob> Interpreter::NewCompilationJob(
parse_info, literal, allocator, eager_inner_literals);
}
+std::unique_ptr<UnoptimizedCompilationJob>
+Interpreter::NewSourcePositionCollectionJob(
+ ParseInfo* parse_info, FunctionLiteral* literal,
+ Handle<BytecodeArray> existing_bytecode, AccountingAllocator* allocator) {
+ auto job = base::make_unique<InterpreterCompilationJob>(parse_info, literal,
+ allocator, nullptr);
+ job->compilation_info()->SetBytecodeArray(existing_bytecode);
+ return job;
+}
+
void Interpreter::ForEachBytecode(
const std::function<void(Bytecode, OperandScale)>& f) {
constexpr OperandScale kOperandScales[] = {
diff --git a/deps/v8/src/interpreter/interpreter.h b/deps/v8/src/interpreter/interpreter.h
index e8c494a6ce..002c9701a8 100644
--- a/deps/v8/src/interpreter/interpreter.h
+++ b/deps/v8/src/interpreter/interpreter.h
@@ -18,10 +18,11 @@
namespace v8 {
namespace internal {
-class Isolate;
+class BytecodeArray;
class Callable;
class UnoptimizedCompilationJob;
class FunctionLiteral;
+class Isolate;
class ParseInfo;
class RootVisitor;
class SetupIsolateDelegate;
@@ -48,6 +49,14 @@ class Interpreter {
AccountingAllocator* allocator,
std::vector<FunctionLiteral*>* eager_inner_literals);
+ // Creates a compilation job which will generate source positions for
+ // |literal| and when finalized, store the result into |existing_bytecode|.
+ static std::unique_ptr<UnoptimizedCompilationJob>
+ NewSourcePositionCollectionJob(ParseInfo* parse_info,
+ FunctionLiteral* literal,
+ Handle<BytecodeArray> existing_bytecode,
+ AccountingAllocator* allocator);
+
// If the bytecode handler for |bytecode| and |operand_scale| has not yet
// been loaded, deserialize it. Then return the handler.
V8_EXPORT_PRIVATE Code GetBytecodeHandler(Bytecode bytecode,
diff --git a/deps/v8/src/json/json-parser.cc b/deps/v8/src/json/json-parser.cc
index fa2118af1e..e49775704d 100644
--- a/deps/v8/src/json/json-parser.cc
+++ b/deps/v8/src/json/json-parser.cc
@@ -65,8 +65,8 @@ enum class EscapeKind : uint8_t {
};
using EscapeKindField = BitField8<EscapeKind, 0, 3>;
-using MayTerminateStringField = BitField8<bool, EscapeKindField::kNext, 1>;
-using NumberPartField = BitField8<bool, MayTerminateStringField::kNext, 1>;
+using MayTerminateStringField = EscapeKindField::Next<bool, 1>;
+using NumberPartField = MayTerminateStringField::Next<bool, 1>;
constexpr bool MayTerminateJsonString(uint8_t flags) {
return MayTerminateStringField::decode(flags);
@@ -539,7 +539,7 @@ Handle<Object> JsonParser<Char>::BuildJsonObject(
Handle<ByteArray> mutable_double_buffer;
// Allocate enough space so we can double-align the payload.
const int kMutableDoubleSize = sizeof(double) * 2;
- STATIC_ASSERT(MutableHeapNumber::kSize <= kMutableDoubleSize);
+ STATIC_ASSERT(HeapNumber::kSize <= kMutableDoubleSize);
if (new_mutable_double > 0) {
mutable_double_buffer =
factory()->NewByteArray(kMutableDoubleSize * new_mutable_double);
@@ -563,7 +563,7 @@ Handle<Object> JsonParser<Char>::BuildJsonObject(
if (IsAligned(mutable_double_address, kDoubleAlignment)) {
mutable_double_address += kTaggedSize;
} else {
- filler_address += MutableHeapNumber::kSize;
+ filler_address += HeapNumber::kSize;
}
for (int j = 0; j < i; j++) {
const JsonProperty& property = property_stack[start + j];
@@ -602,19 +602,19 @@ Handle<Object> JsonParser<Char>::BuildJsonObject(
// payload, so we can skip notifying object layout change.
HeapObject hn = HeapObject::FromAddress(mutable_double_address);
- hn.set_map_after_allocation(*factory()->mutable_heap_number_map());
- MutableHeapNumber::cast(hn).set_value_as_bits(bits);
+ hn.set_map_after_allocation(*factory()->heap_number_map());
+ HeapNumber::cast(hn).set_value_as_bits(bits);
value = hn;
mutable_double_address += kMutableDoubleSize;
} else {
DCHECK(value.IsHeapNumber());
HeapObject::cast(value).synchronized_set_map(
- *factory()->mutable_heap_number_map());
+ *factory()->heap_number_map());
}
}
object->RawFastInobjectPropertyAtPut(index, value, mode);
}
- // Make all MutableHeapNumbers alive.
+ // Make all mutable HeapNumbers alive.
if (!mutable_double_buffer.is_null()) {
#ifdef DEBUG
Address end =
@@ -825,8 +825,12 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
cont_stack.back().type() == JsonContinuation::kArrayElement &&
cont_stack.back().index < element_stack.size() &&
element_stack.back()->IsJSObject()) {
- feedback =
- handle(JSObject::cast(*element_stack.back()).map(), isolate_);
+ Map maybe_feedback = JSObject::cast(*element_stack.back()).map();
+ // Don't consume feedback from objects with a map that's detached
+ // from the transition tree.
+ if (!maybe_feedback.GetBackPointer().IsUndefined(isolate_)) {
+ feedback = handle(maybe_feedback, isolate_);
+ }
}
value = BuildJsonObject(cont, property_stack, feedback);
property_stack.resize(cont.index);
diff --git a/deps/v8/src/json/json-stringifier.cc b/deps/v8/src/json/json-stringifier.cc
index a021fbbc1b..684bcdcf54 100644
--- a/deps/v8/src/json/json-stringifier.cc
+++ b/deps/v8/src/json/json-stringifier.cc
@@ -269,7 +269,11 @@ bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) {
if (key.is_null()) continue;
// Object keys are internalized, so do it here.
key = factory()->InternalizeString(key);
- set = OrderedHashSet::Add(isolate_, set, key);
+ MaybeHandle<OrderedHashSet> set_candidate =
+ OrderedHashSet::Add(isolate_, set, key);
+ if (!set_candidate.ToHandle(&set)) {
+ return false;
+ }
}
property_list_ = OrderedHashSet::ConvertToKeysArray(
isolate_, set, GetKeysConversion::kKeepNumbers);
@@ -534,7 +538,6 @@ JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object,
switch (HeapObject::cast(*object).map().instance_type()) {
case HEAP_NUMBER_TYPE:
- case MUTABLE_HEAP_NUMBER_TYPE:
if (deferred_string_key) SerializeDeferredKey(comma, key);
return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
case BIGINT_TYPE:
diff --git a/deps/v8/src/libplatform/default-worker-threads-task-runner.cc b/deps/v8/src/libplatform/default-worker-threads-task-runner.cc
index b625fdb57c..213e98801a 100644
--- a/deps/v8/src/libplatform/default-worker-threads-task-runner.cc
+++ b/deps/v8/src/libplatform/default-worker-threads-task-runner.cc
@@ -73,7 +73,7 @@ DefaultWorkerThreadsTaskRunner::WorkerThread::WorkerThread(
DefaultWorkerThreadsTaskRunner* runner)
: Thread(Options("V8 DefaultWorkerThreadsTaskRunner WorkerThread")),
runner_(runner) {
- Start();
+ CHECK(Start());
}
DefaultWorkerThreadsTaskRunner::WorkerThread::~WorkerThread() { Join(); }
diff --git a/deps/v8/src/libplatform/tracing/trace-buffer.h b/deps/v8/src/libplatform/tracing/trace-buffer.h
index 95b9313338..3e58212d0e 100644
--- a/deps/v8/src/libplatform/tracing/trace-buffer.h
+++ b/deps/v8/src/libplatform/tracing/trace-buffer.h
@@ -17,6 +17,7 @@ namespace tracing {
class TraceBufferRingBuffer : public TraceBuffer {
public:
+ // Takes ownership of |trace_writer|.
TraceBufferRingBuffer(size_t max_chunks, TraceWriter* trace_writer);
~TraceBufferRingBuffer() override = default;
diff --git a/deps/v8/src/libplatform/tracing/tracing-controller.cc b/deps/v8/src/libplatform/tracing/tracing-controller.cc
index 0700e34825..3fb34366c2 100644
--- a/deps/v8/src/libplatform/tracing/tracing-controller.cc
+++ b/deps/v8/src/libplatform/tracing/tracing-controller.cc
@@ -26,14 +26,10 @@
class V8DataSource : public perfetto::DataSource<V8DataSource> {
public:
void OnSetup(const SetupArgs&) override {}
- void OnStart(const StartArgs&) override { started_.Signal(); }
+ void OnStart(const StartArgs&) override {}
void OnStop(const StopArgs&) override {}
-
- static v8::base::Semaphore started_;
};
-v8::base::Semaphore V8DataSource::started_{0};
-
PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(V8DataSource);
#endif // V8_USE_PERFETTO
@@ -294,14 +290,13 @@ void TracingController::StartTracing(TraceConfig* trace_config) {
perfetto::DataSourceDescriptor dsd;
dsd.set_name("v8.trace_events");
- V8DataSource::Register(dsd);
+ bool registered = V8DataSource::Register(dsd);
+ CHECK(registered);
tracing_session_ =
perfetto::Tracing::NewTrace(perfetto::BackendType::kUnspecifiedBackend);
tracing_session_->Setup(perfetto_trace_config);
- // TODO(petermarshall): Switch to StartBlocking when available.
- tracing_session_->Start();
- V8DataSource::started_.Wait();
+ tracing_session_->StartBlocking();
#endif // V8_USE_PERFETTO
@@ -334,10 +329,17 @@ void TracingController::StopTracing() {
}
#ifdef V8_USE_PERFETTO
- base::Semaphore stopped_{0};
- tracing_session_->SetOnStopCallback([&stopped_]() { stopped_.Signal(); });
- tracing_session_->Stop();
- stopped_.Wait();
+ // Emit a fake trace event from the main thread. The final trace event is
+ // sometimes skipped because perfetto can't guarantee that the caller is
+ // totally finished writing to it without synchronization. To avoid the
+ // situation where we lose the last trace event, add a fake one here that will
+ // be sacrificed.
+ // TODO(petermarshall): Use the Client API to flush here rather than this
+ // workaround when that becomes available.
+ V8DataSource::Trace([&](V8DataSource::TraceContext ctx) {
+ auto packet = ctx.NewTracePacket();
+ });
+ tracing_session_->StopBlocking();
std::vector<char> trace = tracing_session_->ReadTraceBlocking();
json_listener_->ParseFromArray(trace);
diff --git a/deps/v8/src/libplatform/worker-thread.cc b/deps/v8/src/libplatform/worker-thread.cc
index 6a1f704a82..a565854751 100644
--- a/deps/v8/src/libplatform/worker-thread.cc
+++ b/deps/v8/src/libplatform/worker-thread.cc
@@ -12,7 +12,7 @@ namespace platform {
WorkerThread::WorkerThread(TaskQueue* queue)
: Thread(Options("V8 WorkerThread")), queue_(queue) {
- Start();
+ CHECK(Start());
}
WorkerThread::~WorkerThread() {
diff --git a/deps/v8/src/logging/OWNERS b/deps/v8/src/logging/OWNERS
index 852d438bb0..48d72aea5e 100644
--- a/deps/v8/src/logging/OWNERS
+++ b/deps/v8/src/logging/OWNERS
@@ -1 +1 @@
-file://COMMON_OWNERS
+file:../../COMMON_OWNERS
diff --git a/deps/v8/src/logging/code-events.h b/deps/v8/src/logging/code-events.h
index 262ddf7df3..7df135c43f 100644
--- a/deps/v8/src/logging/code-events.h
+++ b/deps/v8/src/logging/code-events.h
@@ -89,6 +89,7 @@ class CodeEventListener {
virtual void RegExpCodeCreateEvent(AbstractCode code, String source) = 0;
virtual void CodeMoveEvent(AbstractCode from, AbstractCode to) = 0;
virtual void SharedFunctionInfoMoveEvent(Address from, Address to) = 0;
+ virtual void NativeContextMoveEvent(Address from, Address to) = 0;
virtual void CodeMovingGCEvent() = 0;
virtual void CodeDisableOptEvent(AbstractCode code,
SharedFunctionInfo shared) = 0;
@@ -164,6 +165,9 @@ class CodeEventDispatcher {
void SharedFunctionInfoMoveEvent(Address from, Address to) {
CODE_EVENT_DISPATCH(SharedFunctionInfoMoveEvent(from, to));
}
+ void NativeContextMoveEvent(Address from, Address to) {
+ CODE_EVENT_DISPATCH(NativeContextMoveEvent(from, to));
+ }
void CodeMovingGCEvent() { CODE_EVENT_DISPATCH(CodeMovingGCEvent()); }
void CodeDisableOptEvent(AbstractCode code, SharedFunctionInfo shared) {
CODE_EVENT_DISPATCH(CodeDisableOptEvent(code, shared));
diff --git a/deps/v8/src/logging/counters-definitions.h b/deps/v8/src/logging/counters-definitions.h
index 3d517e29fc..8c808276fa 100644
--- a/deps/v8/src/logging/counters-definitions.h
+++ b/deps/v8/src/logging/counters-definitions.h
@@ -188,6 +188,8 @@ namespace internal {
V8.WasmCompileModuleAsyncMicroSeconds, 100000000, MICROSECOND) \
HT(wasm_streaming_compile_wasm_module_time, \
V8.WasmCompileModuleStreamingMicroSeconds, 100000000, MICROSECOND) \
+ HT(wasm_streaming_deserialize_wasm_module_time, \
+ V8.WasmDeserializeModuleStreamingMicroSeconds, 100000000, MICROSECOND) \
HT(wasm_tier_up_module_time, V8.WasmTierUpModuleMicroSeconds, 100000000, \
MICROSECOND) \
HT(wasm_compile_asm_function_time, V8.WasmCompileFunctionMicroSeconds.asm, \
diff --git a/deps/v8/src/logging/counters.h b/deps/v8/src/logging/counters.h
index 1efa7105cd..4466e0a53b 100644
--- a/deps/v8/src/logging/counters.h
+++ b/deps/v8/src/logging/counters.h
@@ -764,6 +764,7 @@ class RuntimeCallTimer final {
V(Int8Array_New) \
V(Isolate_DateTimeConfigurationChangeNotification) \
V(Isolate_LocaleConfigurationChangeNotification) \
+ V(FinalizationGroup_Cleanup) \
V(JSON_Parse) \
V(JSON_Stringify) \
V(Map_AsArray) \
diff --git a/deps/v8/src/logging/log.cc b/deps/v8/src/logging/log.cc
index ecf4de6767..9b86a16031 100644
--- a/deps/v8/src/logging/log.cc
+++ b/deps/v8/src/logging/log.cc
@@ -765,7 +765,7 @@ class Profiler : public base::Thread {
void Disengage();
// Inserts collected profiling data into buffer.
- void Insert(v8::TickSample* sample) {
+ void Insert(TickSample* sample) {
if (Succ(head_) == static_cast<int>(base::Relaxed_Load(&tail_))) {
overflow_ = true;
} else {
@@ -779,7 +779,7 @@ class Profiler : public base::Thread {
private:
// Waits for a signal and removes profiling data.
- bool Remove(v8::TickSample* sample) {
+ bool Remove(TickSample* sample) {
buffer_semaphore_.Wait(); // Wait for an element.
*sample = buffer_[base::Relaxed_Load(&tail_)];
bool result = overflow_;
@@ -796,7 +796,7 @@ class Profiler : public base::Thread {
// Cyclic buffer for communicating profiling samples
// between the signal handler and the worker thread.
static const int kBufferSize = 128;
- v8::TickSample buffer_[kBufferSize]; // Buffer storage.
+ TickSample buffer_[kBufferSize]; // Buffer storage.
int head_; // Index to the buffer head.
base::Atomic32 tail_; // Index to the buffer tail.
bool overflow_; // Tell whether a buffer overflow has occurred.
@@ -871,7 +871,7 @@ void Profiler::Engage() {
// Start thread processing the profiler buffer.
base::Relaxed_Store(&running_, 1);
- Start();
+ CHECK(Start());
// Register to get ticks.
Logger* logger = isolate_->logger();
@@ -888,7 +888,7 @@ void Profiler::Disengage() {
// inserting a fake element in the queue and then wait for
// the thread to terminate.
base::Relaxed_Store(&running_, 0);
- v8::TickSample sample;
+ TickSample sample;
Insert(&sample);
Join();
@@ -896,7 +896,7 @@ void Profiler::Disengage() {
}
void Profiler::Run() {
- v8::TickSample sample;
+ TickSample sample;
bool overflow = Remove(&sample);
while (base::Relaxed_Load(&running_)) {
LOG(isolate_, TickEvent(&sample, overflow));
@@ -1549,7 +1549,7 @@ void Logger::RuntimeCallTimerEvent() {
msg.WriteToLogFile();
}
-void Logger::TickEvent(v8::TickSample* sample, bool overflow) {
+void Logger::TickEvent(TickSample* sample, bool overflow) {
if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
if (V8_UNLIKELY(TracingFlags::runtime_stats.load(std::memory_order_relaxed) ==
v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE)) {
@@ -1978,6 +1978,10 @@ void ExistingCodeLogger::LogCodeObject(Object object) {
description = "A JavaScript to Wasm adapter";
tag = CodeEventListener::STUB_TAG;
break;
+ case AbstractCode::JS_TO_JS_FUNCTION:
+ description = "A WebAssembly.Function adapter";
+ tag = CodeEventListener::STUB_TAG;
+ break;
case AbstractCode::WASM_TO_CAPI_FUNCTION:
description = "A Wasm to C-API adapter";
tag = CodeEventListener::STUB_TAG;
diff --git a/deps/v8/src/logging/log.h b/deps/v8/src/logging/log.h
index e46409a66e..3c28222982 100644
--- a/deps/v8/src/logging/log.h
+++ b/deps/v8/src/logging/log.h
@@ -15,14 +15,14 @@
namespace v8 {
-struct TickSample;
-
namespace sampler {
class Sampler;
}
namespace internal {
+struct TickSample;
+
// Logger is used for collecting logging information from V8 during
// execution. The result is dumped to a file.
//
@@ -216,6 +216,8 @@ class Logger : public CodeEventListener {
void SharedFunctionInfoMoveEvent(Address from, Address to) override;
+ void NativeContextMoveEvent(Address from, Address to) override {}
+
void CodeNameEvent(Address addr, int pos, const char* code_name);
void CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc,
@@ -401,6 +403,7 @@ class V8_EXPORT_PRIVATE CodeEventLogger : public CodeEventListener {
void GetterCallbackEvent(Name name, Address entry_point) override {}
void SetterCallbackEvent(Name name, Address entry_point) override {}
void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
+ void NativeContextMoveEvent(Address from, Address to) override {}
void CodeMovingGCEvent() override {}
void CodeDeoptEvent(Code code, DeoptimizeKind kind, Address pc,
int fp_to_sp_delta) override {}
@@ -453,6 +456,7 @@ class ExternalCodeEventListener : public CodeEventListener {
void GetterCallbackEvent(Name name, Address entry_point) override {}
void SetterCallbackEvent(Name name, Address entry_point) override {}
void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
+ void NativeContextMoveEvent(Address from, Address to) override {}
void CodeMoveEvent(AbstractCode from, AbstractCode to) override {}
void CodeDisableOptEvent(AbstractCode code,
SharedFunctionInfo shared) override {}
diff --git a/deps/v8/src/objects/OWNERS b/deps/v8/src/objects/OWNERS
index 450423f878..f52e1c9ca8 100644
--- a/deps/v8/src/objects/OWNERS
+++ b/deps/v8/src/objects/OWNERS
@@ -1,3 +1,3 @@
-file://COMMON_OWNERS
+file:../../COMMON_OWNERS
# COMPONENT: Blink>JavaScript>Runtime
diff --git a/deps/v8/src/objects/allocation-site.h b/deps/v8/src/objects/allocation-site.h
index 9289a83f70..c1b6417ae1 100644
--- a/deps/v8/src/objects/allocation-site.h
+++ b/deps/v8/src/objects/allocation-site.h
@@ -66,14 +66,14 @@ class AllocationSite : public Struct {
bool IsNested();
// transition_info bitfields, for constructed array transition info.
- class ElementsKindBits : public BitField<ElementsKind, 0, 5> {};
- class DoNotInlineBit : public BitField<bool, 5, 1> {};
+ using ElementsKindBits = BitField<ElementsKind, 0, 5>;
+ using DoNotInlineBit = BitField<bool, 5, 1>;
// Unused bits 6-30.
// Bitfields for pretenure_data
- class MementoFoundCountBits : public BitField<int, 0, 26> {};
- class PretenureDecisionBits : public BitField<PretenureDecision, 26, 3> {};
- class DeoptDependentCodeBit : public BitField<bool, 29, 1> {};
+ using MementoFoundCountBits = BitField<int, 0, 26>;
+ using PretenureDecisionBits = BitField<PretenureDecision, 26, 3>;
+ using DeoptDependentCodeBit = BitField<bool, 29, 1>;
STATIC_ASSERT(PretenureDecisionBits::kMax >= kLastPretenureDecisionValue);
// Increments the mementos found counter and returns true when the first
diff --git a/deps/v8/src/objects/api-callbacks-inl.h b/deps/v8/src/objects/api-callbacks-inl.h
index c327a35746..d0698d13a1 100644
--- a/deps/v8/src/objects/api-callbacks-inl.h
+++ b/deps/v8/src/objects/api-callbacks-inl.h
@@ -21,15 +21,13 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(AccessCheckInfo, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(AccessCheckInfo)
OBJECT_CONSTRUCTORS_IMPL(AccessorInfo, Struct)
-OBJECT_CONSTRUCTORS_IMPL(InterceptorInfo, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(InterceptorInfo)
TQ_OBJECT_CONSTRUCTORS_IMPL(CallHandlerInfo)
CAST_ACCESSOR(AccessorInfo)
-CAST_ACCESSOR(AccessCheckInfo)
-CAST_ACCESSOR(InterceptorInfo)
ACCESSORS(AccessorInfo, name, Name, kNameOffset)
SMI_ACCESSORS(AccessorInfo, flags, kFlagsOffset)
@@ -98,21 +96,7 @@ bool AccessorInfo::HasExpectedReceiverType() {
return expected_receiver_type().IsFunctionTemplateInfo();
}
-ACCESSORS(AccessCheckInfo, callback, Object, kCallbackOffset)
-ACCESSORS(AccessCheckInfo, named_interceptor, Object, kNamedInterceptorOffset)
-ACCESSORS(AccessCheckInfo, indexed_interceptor, Object,
- kIndexedInterceptorOffset)
-ACCESSORS(AccessCheckInfo, data, Object, kDataOffset)
-
-ACCESSORS(InterceptorInfo, getter, Object, kGetterOffset)
-ACCESSORS(InterceptorInfo, setter, Object, kSetterOffset)
-ACCESSORS(InterceptorInfo, query, Object, kQueryOffset)
-ACCESSORS(InterceptorInfo, descriptor, Object, kDescriptorOffset)
-ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset)
-ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset)
-ACCESSORS(InterceptorInfo, definer, Object, kDefinerOffset)
-ACCESSORS(InterceptorInfo, data, Object, kDataOffset)
-SMI_ACCESSORS(InterceptorInfo, flags, kFlagsOffset)
+TQ_SMI_ACCESSORS(InterceptorInfo, flags)
BOOL_ACCESSORS(InterceptorInfo, flags, can_intercept_symbols,
kCanInterceptSymbolsBit)
BOOL_ACCESSORS(InterceptorInfo, flags, all_can_read, kAllCanReadBit)
diff --git a/deps/v8/src/objects/api-callbacks.h b/deps/v8/src/objects/api-callbacks.h
index 518339f7d4..72be5deb8f 100644
--- a/deps/v8/src/objects/api-callbacks.h
+++ b/deps/v8/src/objects/api-callbacks.h
@@ -102,37 +102,20 @@ class AccessorInfo : public Struct {
OBJECT_CONSTRUCTORS(AccessorInfo, Struct);
};
-class AccessCheckInfo : public Struct {
+class AccessCheckInfo
+ : public TorqueGeneratedAccessCheckInfo<AccessCheckInfo, Struct> {
public:
- DECL_ACCESSORS(callback, Object)
- DECL_ACCESSORS(named_interceptor, Object)
- DECL_ACCESSORS(indexed_interceptor, Object)
- DECL_ACCESSORS(data, Object)
-
- DECL_CAST(AccessCheckInfo)
-
// Dispatched behavior.
DECL_PRINTER(AccessCheckInfo)
- DECL_VERIFIER(AccessCheckInfo)
static AccessCheckInfo Get(Isolate* isolate, Handle<JSObject> receiver);
- DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
- TORQUE_GENERATED_ACCESS_CHECK_INFO_FIELDS)
-
- OBJECT_CONSTRUCTORS(AccessCheckInfo, Struct);
+ TQ_OBJECT_CONSTRUCTORS(AccessCheckInfo)
};
-class InterceptorInfo : public Struct {
+class InterceptorInfo
+ : public TorqueGeneratedInterceptorInfo<InterceptorInfo, Struct> {
public:
- DECL_ACCESSORS(getter, Object)
- DECL_ACCESSORS(setter, Object)
- DECL_ACCESSORS(query, Object)
- DECL_ACCESSORS(descriptor, Object)
- DECL_ACCESSORS(deleter, Object)
- DECL_ACCESSORS(enumerator, Object)
- DECL_ACCESSORS(definer, Object)
- DECL_ACCESSORS(data, Object)
DECL_BOOLEAN_ACCESSORS(can_intercept_symbols)
DECL_BOOLEAN_ACCESSORS(all_can_read)
DECL_BOOLEAN_ACCESSORS(non_masking)
@@ -142,14 +125,8 @@ class InterceptorInfo : public Struct {
inline int flags() const;
inline void set_flags(int flags);
- DECL_CAST(InterceptorInfo)
-
// Dispatched behavior.
DECL_PRINTER(InterceptorInfo)
- DECL_VERIFIER(InterceptorInfo)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
- TORQUE_GENERATED_INTERCEPTOR_INFO_FIELDS)
static const int kCanInterceptSymbolsBit = 0;
static const int kAllCanReadBit = 1;
@@ -157,7 +134,7 @@ class InterceptorInfo : public Struct {
static const int kNamed = 3;
static const int kHasNoSideEffect = 4;
- OBJECT_CONSTRUCTORS(InterceptorInfo, Struct);
+ TQ_OBJECT_CONSTRUCTORS(InterceptorInfo)
};
class CallHandlerInfo
diff --git a/deps/v8/src/objects/arguments-inl.h b/deps/v8/src/objects/arguments-inl.h
index 2931c5b0a0..3de88d6a9b 100644
--- a/deps/v8/src/objects/arguments-inl.h
+++ b/deps/v8/src/objects/arguments-inl.h
@@ -19,15 +19,12 @@ namespace v8 {
namespace internal {
OBJECT_CONSTRUCTORS_IMPL(SloppyArgumentsElements, FixedArray)
-OBJECT_CONSTRUCTORS_IMPL(JSArgumentsObject, JSObject)
-OBJECT_CONSTRUCTORS_IMPL(AliasedArgumentsEntry, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSArgumentsObject)
+TQ_OBJECT_CONSTRUCTORS_IMPL(AliasedArgumentsEntry)
-CAST_ACCESSOR(AliasedArgumentsEntry)
CAST_ACCESSOR(SloppyArgumentsElements)
-CAST_ACCESSOR(JSArgumentsObject)
-SMI_ACCESSORS(AliasedArgumentsEntry, aliased_context_slot,
- kAliasedContextSlotOffset)
+TQ_SMI_ACCESSORS(AliasedArgumentsEntry, aliased_context_slot)
DEF_GETTER(SloppyArgumentsElements, context, Context) {
return TaggedField<Context>::load(isolate, *this,
diff --git a/deps/v8/src/objects/arguments.h b/deps/v8/src/objects/arguments.h
index 79d2e604bd..a306ef592a 100644
--- a/deps/v8/src/objects/arguments.h
+++ b/deps/v8/src/objects/arguments.h
@@ -17,11 +17,11 @@ namespace v8 {
namespace internal {
// Superclass for all objects with instance type {JS_ARGUMENTS_TYPE}
-class JSArgumentsObject : public JSObject {
+class JSArgumentsObject
+ : public TorqueGeneratedJSArgumentsObject<JSArgumentsObject, JSObject> {
public:
DECL_VERIFIER(JSArgumentsObject)
- DECL_CAST(JSArgumentsObject)
- OBJECT_CONSTRUCTORS(JSArgumentsObject, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSArgumentsObject)
};
// Common superclass for JSSloppyArgumentsObject and JSStrictArgumentsObject.
@@ -125,21 +125,17 @@ class SloppyArgumentsElements : public FixedArray {
// - the parameter map contains no fast alias mapping (i.e. the hole)
// - this struct (in the slow backing store) contains an index into the context
// - all attributes are available as part if the property details
-class AliasedArgumentsEntry : public Struct {
+class AliasedArgumentsEntry
+ : public TorqueGeneratedAliasedArgumentsEntry<AliasedArgumentsEntry,
+ Struct> {
public:
inline int aliased_context_slot() const;
inline void set_aliased_context_slot(int count);
- DECL_CAST(AliasedArgumentsEntry)
-
// Dispatched behavior.
DECL_PRINTER(AliasedArgumentsEntry)
- DECL_VERIFIER(AliasedArgumentsEntry)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
- TORQUE_GENERATED_ALIASED_ARGUMENTS_ENTRY_FIELDS)
- OBJECT_CONSTRUCTORS(AliasedArgumentsEntry, Struct);
+ TQ_OBJECT_CONSTRUCTORS(AliasedArgumentsEntry)
};
} // namespace internal
diff --git a/deps/v8/src/objects/bigint.cc b/deps/v8/src/objects/bigint.cc
index b02c0f29d6..2905bb44c6 100644
--- a/deps/v8/src/objects/bigint.cc
+++ b/deps/v8/src/objects/bigint.cc
@@ -992,7 +992,7 @@ ComparisonResult BigInt::CompareToDouble(Handle<BigInt> x, double y) {
MaybeHandle<String> BigInt::ToString(Isolate* isolate, Handle<BigInt> bigint,
int radix, ShouldThrow should_throw) {
if (bigint->is_zero()) {
- return isolate->factory()->NewStringFromStaticChars("0");
+ return isolate->factory()->zero_string();
}
if (base::bits::IsPowerOfTwo(radix)) {
return MutableBigInt::ToStringBasePowerOfTwo(isolate, bigint, radix,
diff --git a/deps/v8/src/objects/bigint.h b/deps/v8/src/objects/bigint.h
index a5ca514867..ca80547230 100644
--- a/deps/v8/src/objects/bigint.h
+++ b/deps/v8/src/objects/bigint.h
@@ -57,9 +57,9 @@ class BigIntBase : public HeapObject {
// able to read the length concurrently, the getters and setters are atomic.
static const int kLengthFieldBits = 30;
STATIC_ASSERT(kMaxLength <= ((1 << kLengthFieldBits) - 1));
- class SignBits : public BitField<bool, 0, 1> {};
- class LengthBits : public BitField<int, SignBits::kNext, kLengthFieldBits> {};
- STATIC_ASSERT(LengthBits::kNext <= 32);
+ using SignBits = BitField<bool, 0, 1>;
+ using LengthBits = SignBits::Next<int, kLengthFieldBits>;
+ STATIC_ASSERT(LengthBits::kLastUsedBit < 32);
// Layout description.
#define BIGINT_FIELDS(V) \
diff --git a/deps/v8/src/objects/cell-inl.h b/deps/v8/src/objects/cell-inl.h
index 90266b7599..0bd6808fbc 100644
--- a/deps/v8/src/objects/cell-inl.h
+++ b/deps/v8/src/objects/cell-inl.h
@@ -16,11 +16,7 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(Cell, HeapObject)
-
-CAST_ACCESSOR(Cell)
-
-ACCESSORS(Cell, value, Object, kValueOffset)
+TQ_OBJECT_CONSTRUCTORS_IMPL(Cell)
Cell Cell::FromValueAddress(Address value) {
return Cell::cast(HeapObject::FromAddress(value - kValueOffset));
diff --git a/deps/v8/src/objects/cell.h b/deps/v8/src/objects/cell.h
index 9c77f5d332..fc49f164b2 100644
--- a/deps/v8/src/objects/cell.h
+++ b/deps/v8/src/objects/cell.h
@@ -6,7 +6,7 @@
#define V8_OBJECTS_CELL_H_
#include "src/objects/heap-object.h"
-#include "torque-generated/field-offsets-tq.h"
+#include "torque-generated/class-definitions-tq.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@@ -14,27 +14,18 @@
namespace v8 {
namespace internal {
-class Cell : public HeapObject {
+class Cell : public TorqueGeneratedCell<Cell, HeapObject> {
public:
- // [value]: value of the cell.
- DECL_ACCESSORS(value, Object)
-
- DECL_CAST(Cell)
-
static inline Cell FromValueAddress(Address value);
inline Address ValueAddress() { return address() + kValueOffset; }
// Dispatched behavior.
DECL_PRINTER(Cell)
- DECL_VERIFIER(Cell)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
- TORQUE_GENERATED_CELL_FIELDS)
using BodyDescriptor = FixedBodyDescriptor<kValueOffset, kSize, kSize>;
- OBJECT_CONSTRUCTORS(Cell, HeapObject);
+ TQ_OBJECT_CONSTRUCTORS(Cell)
};
} // namespace internal
diff --git a/deps/v8/src/objects/code-inl.h b/deps/v8/src/objects/code-inl.h
index e6f00b0fb2..6e00a3363c 100644
--- a/deps/v8/src/objects/code-inl.h
+++ b/deps/v8/src/objects/code-inl.h
@@ -768,6 +768,7 @@ DEFINE_DEOPT_ELEMENT_ACCESSORS(OsrBytecodeOffset, Smi)
DEFINE_DEOPT_ELEMENT_ACCESSORS(OsrPcOffset, Smi)
DEFINE_DEOPT_ELEMENT_ACCESSORS(OptimizationId, Smi)
DEFINE_DEOPT_ELEMENT_ACCESSORS(InliningPositions, PodArray<InliningPosition>)
+DEFINE_DEOPT_ELEMENT_ACCESSORS(DeoptExitStart, Smi)
DEFINE_DEOPT_ENTRY_ACCESSORS(BytecodeOffsetRaw, Smi)
DEFINE_DEOPT_ENTRY_ACCESSORS(TranslationIndex, Smi)
diff --git a/deps/v8/src/objects/code.cc b/deps/v8/src/objects/code.cc
index a51a8c5b79..b416df8878 100644
--- a/deps/v8/src/objects/code.cc
+++ b/deps/v8/src/objects/code.cc
@@ -193,7 +193,10 @@ namespace {
template <typename Code>
void DropStackFrameCacheCommon(Code code) {
i::Object maybe_table = code.source_position_table();
- if (maybe_table.IsUndefined() || maybe_table.IsByteArray()) return;
+ if (maybe_table.IsUndefined() || maybe_table.IsByteArray() ||
+ maybe_table.IsException()) {
+ return;
+ }
DCHECK(maybe_table.IsSourcePositionTableWithFrameCache());
code.set_source_position_table(
i::SourcePositionTableWithFrameCache::cast(maybe_table)
@@ -1086,15 +1089,5 @@ const char* DependentCode::DependencyGroupName(DependencyGroup group) {
UNREACHABLE();
}
-bool BytecodeArray::IsBytecodeEqual(const BytecodeArray other) const {
- if (length() != other.length()) return false;
-
- for (int i = 0; i < length(); ++i) {
- if (get(i) != other.get(i)) return false;
- }
-
- return true;
-}
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/code.h b/deps/v8/src/objects/code.h
index 2f85d4ac7b..6a5ac9f31a 100644
--- a/deps/v8/src/objects/code.h
+++ b/deps/v8/src/objects/code.h
@@ -45,6 +45,7 @@ class Code : public HeapObject {
V(WASM_TO_CAPI_FUNCTION) \
V(WASM_TO_JS_FUNCTION) \
V(JS_TO_WASM_FUNCTION) \
+ V(JS_TO_JS_FUNCTION) \
V(WASM_INTERPRETER_ENTRY) \
V(C_WASM_ENTRY)
@@ -438,7 +439,7 @@ class Code : public HeapObject {
DEFINE_BIT_FIELDS(CODE_FLAGS_BIT_FIELDS)
#undef CODE_FLAGS_BIT_FIELDS
static_assert(NUMBER_OF_KINDS <= KindField::kMax, "Code::KindField size");
- static_assert(IsOffHeapTrampoline::kNext <= 32,
+ static_assert(IsOffHeapTrampoline::kLastUsedBit < 32,
"Code::flags field exhausted");
// KindSpecificFlags layout (STUB, BUILTIN and OPTIMIZED_FUNCTION)
@@ -451,7 +452,8 @@ class Code : public HeapObject {
V(IsExceptionCaughtField, bool, 1, _)
DEFINE_BIT_FIELDS(CODE_KIND_SPECIFIC_FLAGS_BIT_FIELDS)
#undef CODE_KIND_SPECIFIC_FLAGS_BIT_FIELDS
- static_assert(IsExceptionCaughtField::kNext <= 32, "KindSpecificFlags full");
+ static_assert(IsExceptionCaughtField::kLastUsedBit < 32,
+ "KindSpecificFlags full");
// The {marked_for_deoptimization} field is accessed from generated code.
static const int kMarkedForDeoptimizationBit =
@@ -705,8 +707,8 @@ class DependentCode : public WeakFixedArray {
inline int flags();
inline void set_flags(int flags);
- class GroupField : public BitField<int, 0, 3> {};
- class CountField : public BitField<int, 3, 27> {};
+ using GroupField = BitField<int, 0, 3>;
+ using CountField = BitField<int, 3, 27>;
STATIC_ASSERT(kGroupCount <= GroupField::kMax + 1);
OBJECT_CONSTRUCTORS(DependentCode, WeakFixedArray);
@@ -825,9 +827,6 @@ class BytecodeArray : public FixedArrayBase {
// is deterministic.
inline void clear_padding();
- // Compares only the bytecode array but not any of the header fields.
- bool IsBytecodeEqual(const BytecodeArray other) const;
-
// Layout description.
DEFINE_FIELD_OFFSET_CONSTANTS(FixedArrayBase::kHeaderSize,
TORQUE_GENERATED_BYTECODE_ARRAY_FIELDS)
@@ -865,7 +864,8 @@ class DeoptimizationData : public FixedArray {
static const int kOptimizationIdIndex = 5;
static const int kSharedFunctionInfoIndex = 6;
static const int kInliningPositionsIndex = 7;
- static const int kFirstDeoptEntryIndex = 8;
+ static const int kDeoptExitStartIndex = 8;
+ static const int kFirstDeoptEntryIndex = 9;
// Offsets of deopt entry elements relative to the start of the entry.
static const int kBytecodeOffsetRawOffset = 0;
@@ -886,6 +886,7 @@ class DeoptimizationData : public FixedArray {
DECL_ELEMENT_ACCESSORS(OptimizationId, Smi)
DECL_ELEMENT_ACCESSORS(SharedFunctionInfo, Object)
DECL_ELEMENT_ACCESSORS(InliningPositions, PodArray<InliningPosition>)
+ DECL_ELEMENT_ACCESSORS(DeoptExitStart, Smi)
#undef DECL_ELEMENT_ACCESSORS
diff --git a/deps/v8/src/objects/contexts.cc b/deps/v8/src/objects/contexts.cc
index 861e06d87f..74fb4477b1 100644
--- a/deps/v8/src/objects/contexts.cc
+++ b/deps/v8/src/objects/contexts.cc
@@ -44,7 +44,7 @@ bool ScriptContextTable::Lookup(Isolate* isolate, ScriptContextTable table,
DCHECK(context.IsScriptContext());
int slot_index = ScopeInfo::ContextSlotIndex(
context.scope_info(), name, &result->mode, &result->init_flag,
- &result->maybe_assigned_flag, &result->requires_brand_check);
+ &result->maybe_assigned_flag);
if (slot_index >= 0) {
result->context_index = i;
@@ -161,8 +161,8 @@ static Maybe<bool> UnscopableLookup(LookupIterator* it) {
}
static PropertyAttributes GetAttributesForMode(VariableMode mode) {
- DCHECK(IsDeclaredVariableMode(mode));
- return mode == VariableMode::kConst ? READ_ONLY : NONE;
+ DCHECK(IsSerializableVariableMode(mode));
+ return IsConstVariableMode(mode) ? READ_ONLY : NONE;
}
// static
@@ -287,10 +287,8 @@ Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name,
VariableMode mode;
InitializationFlag flag;
MaybeAssignedFlag maybe_assigned_flag;
- RequiresBrandCheckFlag requires_brand_check;
int slot_index = ScopeInfo::ContextSlotIndex(scope_info, *name, &mode,
- &flag, &maybe_assigned_flag,
- &requires_brand_check);
+ &flag, &maybe_assigned_flag);
DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
if (slot_index >= 0) {
if (FLAG_trace_contexts) {
diff --git a/deps/v8/src/objects/contexts.h b/deps/v8/src/objects/contexts.h
index 0c00aba08e..a7b60ff7b9 100644
--- a/deps/v8/src/objects/contexts.h
+++ b/deps/v8/src/objects/contexts.h
@@ -227,10 +227,14 @@ enum ContextLookupFlags {
V(REGEXP_EXEC_FUNCTION_INDEX, JSFunction, regexp_exec_function) \
V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \
V(REGEXP_LAST_MATCH_INFO_INDEX, RegExpMatchInfo, regexp_last_match_info) \
+ V(REGEXP_MATCH_ALL_FUNCTION_INDEX, JSFunction, regexp_match_all_function) \
+ V(REGEXP_MATCH_FUNCTION_INDEX, JSFunction, regexp_match_function) \
V(REGEXP_PROTOTYPE_INDEX, JSObject, regexp_prototype) \
V(REGEXP_PROTOTYPE_MAP_INDEX, Map, regexp_prototype_map) \
+ V(REGEXP_REPLACE_FUNCTION_INDEX, JSFunction, regexp_replace_function) \
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \
- V(REGEXP_SPECIES_PROTECTOR_INDEX, PropertyCell, regexp_species_protector) \
+ V(REGEXP_SEARCH_FUNCTION_INDEX, JSFunction, regexp_search_function) \
+ V(REGEXP_SPLIT_FUNCTION_INDEX, JSFunction, regexp_split_function) \
V(INITIAL_REGEXP_STRING_ITERATOR_PROTOTYPE_MAP_INDEX, Map, \
initial_regexp_string_iterator_prototype_map) \
V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table) \
@@ -249,6 +253,8 @@ enum ContextLookupFlags {
slow_object_with_object_prototype_map) \
V(SLOW_TEMPLATE_INSTANTIATIONS_CACHE_INDEX, SimpleNumberDictionary, \
slow_template_instantiations_cache) \
+ /* Fast Path Protectors */ \
+ V(REGEXP_SPECIES_PROTECTOR_INDEX, PropertyCell, regexp_species_protector) \
/* All *_FUNCTION_MAP_INDEX definitions used by Context::FunctionMapIndex */ \
/* must remain together. */ \
V(SLOPPY_FUNCTION_MAP_INDEX, Map, sloppy_function_map) \
@@ -356,7 +362,6 @@ class ScriptContextTable : public FixedArray {
VariableMode mode;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
- RequiresBrandCheckFlag requires_brand_check;
};
inline int used() const;
diff --git a/deps/v8/src/objects/dictionary.h b/deps/v8/src/objects/dictionary.h
index fe6001f58c..957c06d8ec 100644
--- a/deps/v8/src/objects/dictionary.h
+++ b/deps/v8/src/objects/dictionary.h
@@ -170,7 +170,8 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) BaseNameDictionary
// Collect the keys into the given KeyAccumulator, in ascending chronological
// order of property creation.
- static void CollectKeysTo(Handle<Derived> dictionary, KeyAccumulator* keys);
+ V8_WARN_UNUSED_RESULT static ExceptionStatus CollectKeysTo(
+ Handle<Derived> dictionary, KeyAccumulator* keys);
// Return the key indices sorted by its enumeration index.
static Handle<FixedArray> IterationIndices(Isolate* isolate,
diff --git a/deps/v8/src/objects/elements-inl.h b/deps/v8/src/objects/elements-inl.h
index c4f2e2bf78..dfec2e35f4 100644
--- a/deps/v8/src/objects/elements-inl.h
+++ b/deps/v8/src/objects/elements-inl.h
@@ -5,6 +5,7 @@
#ifndef V8_OBJECTS_ELEMENTS_INL_H_
#define V8_OBJECTS_ELEMENTS_INL_H_
+#include "src/common/globals.h"
#include "src/objects/elements.h"
#include "src/handles/handles-inl.h"
@@ -13,10 +14,11 @@
namespace v8 {
namespace internal {
-inline void ElementsAccessor::CollectElementIndices(Handle<JSObject> object,
- KeyAccumulator* keys) {
- CollectElementIndices(object, handle(object->elements(), keys->isolate()),
- keys);
+V8_WARN_UNUSED_RESULT inline ExceptionStatus
+ElementsAccessor::CollectElementIndices(Handle<JSObject> object,
+ KeyAccumulator* keys) {
+ return CollectElementIndices(
+ object, handle(object->elements(), keys->isolate()), keys);
}
inline MaybeHandle<FixedArray> ElementsAccessor::PrependElementIndices(
diff --git a/deps/v8/src/objects/elements-kind.cc b/deps/v8/src/objects/elements-kind.cc
index a819caf459..ec2b79d10b 100644
--- a/deps/v8/src/objects/elements-kind.cc
+++ b/deps/v8/src/objects/elements-kind.cc
@@ -35,10 +35,12 @@ int ElementsKindToShiftSize(ElementsKind elements_kind) {
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case HOLEY_SMI_ELEMENTS:
case HOLEY_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
@@ -79,6 +81,10 @@ const char* ElementsKindToString(ElementsKind kind) {
return "PACKED_DOUBLE_ELEMENTS";
case HOLEY_DOUBLE_ELEMENTS:
return "HOLEY_DOUBLE_ELEMENTS";
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
+ return "PACKED_NONEXTENSIBLE_ELEMENTS";
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
+ return "HOLEY_NONEXTENSIBLE_ELEMENTS";
case PACKED_SEALED_ELEMENTS:
return "PACKED_SEALED_ELEMENTS";
case HOLEY_SEALED_ELEMENTS:
diff --git a/deps/v8/src/objects/elements-kind.h b/deps/v8/src/objects/elements-kind.h
index 3ed6ea66ec..e1335fa3c0 100644
--- a/deps/v8/src/objects/elements-kind.h
+++ b/deps/v8/src/objects/elements-kind.h
@@ -43,6 +43,10 @@ enum ElementsKind : uint8_t {
PACKED_DOUBLE_ELEMENTS,
HOLEY_DOUBLE_ELEMENTS,
+ // The nonextensible kind for elements.
+ PACKED_NONEXTENSIBLE_ELEMENTS,
+ HOLEY_NONEXTENSIBLE_ELEMENTS,
+
// The sealed kind for elements.
PACKED_SEALED_ELEMENTS,
HOLEY_SEALED_ELEMENTS,
@@ -79,7 +83,8 @@ enum ElementsKind : uint8_t {
FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = UINT8_ELEMENTS,
LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = BIGINT64_ELEMENTS,
TERMINAL_FAST_ELEMENTS_KIND = HOLEY_ELEMENTS,
- LAST_FROZEN_ELEMENTS_KIND = HOLEY_FROZEN_ELEMENTS,
+ FIRST_ANY_NONEXTENSIBLE_ELEMENTS_KIND = PACKED_NONEXTENSIBLE_ELEMENTS,
+ LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND = HOLEY_FROZEN_ELEMENTS,
// Alias for kSystemPointerSize-sized elements
#ifdef V8_COMPRESS_POINTERS
@@ -156,14 +161,23 @@ inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) {
}
// This predicate is used for disabling respective functionality in builtins.
-inline bool IsFrozenOrSealedElementsKindUnchecked(ElementsKind kind) {
- return IsInRange(kind, PACKED_SEALED_ELEMENTS, HOLEY_FROZEN_ELEMENTS);
+inline bool IsAnyNonextensibleElementsKindUnchecked(ElementsKind kind) {
+ return IsInRange(kind, FIRST_ANY_NONEXTENSIBLE_ELEMENTS_KIND,
+ LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND);
}
-inline bool IsFrozenOrSealedElementsKind(ElementsKind kind) {
- DCHECK_IMPLIES(IsFrozenOrSealedElementsKindUnchecked(kind),
+inline bool IsAnyNonextensibleElementsKind(ElementsKind kind) {
+ DCHECK_IMPLIES(IsAnyNonextensibleElementsKindUnchecked(kind),
FLAG_enable_sealed_frozen_elements_kind);
- return IsFrozenOrSealedElementsKindUnchecked(kind);
+ return IsAnyNonextensibleElementsKindUnchecked(kind);
+}
+
+inline bool IsNonextensibleElementsKind(ElementsKind kind) {
+ DCHECK_IMPLIES(IsInRange(kind, PACKED_NONEXTENSIBLE_ELEMENTS,
+ HOLEY_NONEXTENSIBLE_ELEMENTS),
+ FLAG_enable_sealed_frozen_elements_kind);
+ return IsInRange(kind, PACKED_NONEXTENSIBLE_ELEMENTS,
+ HOLEY_NONEXTENSIBLE_ELEMENTS);
}
inline bool IsSealedElementsKind(ElementsKind kind) {
@@ -194,10 +208,13 @@ inline bool IsObjectElementsKind(ElementsKind kind) {
return IsInRange(kind, PACKED_ELEMENTS, HOLEY_ELEMENTS);
}
-inline bool IsHoleyFrozenOrSealedElementsKind(ElementsKind kind) {
- DCHECK_IMPLIES(kind == HOLEY_SEALED_ELEMENTS || kind == HOLEY_FROZEN_ELEMENTS,
+inline bool IsAnyHoleyNonextensibleElementsKind(ElementsKind kind) {
+ DCHECK_IMPLIES(kind == HOLEY_NONEXTENSIBLE_ELEMENTS ||
+ kind == HOLEY_SEALED_ELEMENTS ||
+ kind == HOLEY_FROZEN_ELEMENTS,
FLAG_enable_sealed_frozen_elements_kind);
- return kind == HOLEY_SEALED_ELEMENTS || kind == HOLEY_FROZEN_ELEMENTS;
+ return kind == HOLEY_NONEXTENSIBLE_ELEMENTS ||
+ kind == HOLEY_SEALED_ELEMENTS || kind == HOLEY_FROZEN_ELEMENTS;
}
inline bool IsHoleyElementsKind(ElementsKind kind) {
@@ -239,6 +256,9 @@ inline ElementsKind GetHoleyElementsKind(ElementsKind packed_kind) {
if (packed_kind == PACKED_ELEMENTS) {
return HOLEY_ELEMENTS;
}
+ if (packed_kind == PACKED_NONEXTENSIBLE_ELEMENTS) {
+ return HOLEY_NONEXTENSIBLE_ELEMENTS;
+ }
return packed_kind;
}
diff --git a/deps/v8/src/objects/elements.cc b/deps/v8/src/objects/elements.cc
index 4bdfba052d..6e5648d2f4 100644
--- a/deps/v8/src/objects/elements.cc
+++ b/deps/v8/src/objects/elements.cc
@@ -33,6 +33,9 @@
// - FastPackedSmiElementsAccessor
// - FastHoleySmiElementsAccessor
// - FastPackedObjectElementsAccessor
+// - FastNonextensibleObjectElementsAccessor: template
+// - FastPackedNonextensibleObjectElementsAccessor
+// - FastHoleyNonextensibleObjectElementsAccessor
// - FastSealedObjectElementsAccessor: template
// - FastPackedSealedObjectElementsAccessor
// - FastHoleySealedObjectElementsAccessor
@@ -68,6 +71,17 @@ namespace internal {
namespace {
+#define RETURN_NOTHING_IF_NOT_SUCCESSFUL(call) \
+ do { \
+ if (!(call)) return Nothing<bool>(); \
+ } while (false)
+
+#define RETURN_FAILURE_IF_NOT_SUCCESSFUL(call) \
+ do { \
+ ExceptionStatus status_enum_result = (call); \
+ if (!status_enum_result) return status_enum_result; \
+ } while (false)
+
static const int kPackedSizeNotKnown = -1;
enum Where { AT_START, AT_END };
@@ -85,6 +99,10 @@ enum Where { AT_START, AT_END };
V(FastPackedDoubleElementsAccessor, PACKED_DOUBLE_ELEMENTS, \
FixedDoubleArray) \
V(FastHoleyDoubleElementsAccessor, HOLEY_DOUBLE_ELEMENTS, FixedDoubleArray) \
+ V(FastPackedNonextensibleObjectElementsAccessor, \
+ PACKED_NONEXTENSIBLE_ELEMENTS, FixedArray) \
+ V(FastHoleyNonextensibleObjectElementsAccessor, \
+ HOLEY_NONEXTENSIBLE_ELEMENTS, FixedArray) \
V(FastPackedSealedObjectElementsAccessor, PACKED_SEALED_ELEMENTS, \
FixedArray) \
V(FastHoleySealedObjectElementsAccessor, HOLEY_SEALED_ELEMENTS, FixedArray) \
@@ -992,8 +1010,8 @@ class ElementsAccessorBase : public InternalElementsAccessor {
DCHECK_EQ(*nof_items, 0);
KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
ALL_PROPERTIES);
- Subclass::CollectElementIndicesImpl(
- object, handle(object->elements(), isolate), &accumulator);
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(Subclass::CollectElementIndicesImpl(
+ object, handle(object->elements(), isolate), &accumulator));
Handle<FixedArray> keys = accumulator.GetKeys();
int count = 0;
@@ -1055,16 +1073,16 @@ class ElementsAccessorBase : public InternalElementsAccessor {
return Just(true);
}
- void CollectElementIndices(Handle<JSObject> object,
- Handle<FixedArrayBase> backing_store,
- KeyAccumulator* keys) final {
- if (keys->filter() & ONLY_ALL_CAN_READ) return;
- Subclass::CollectElementIndicesImpl(object, backing_store, keys);
+ V8_WARN_UNUSED_RESULT ExceptionStatus CollectElementIndices(
+ Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
+ KeyAccumulator* keys) final {
+ if (keys->filter() & ONLY_ALL_CAN_READ) return ExceptionStatus::kSuccess;
+ return Subclass::CollectElementIndicesImpl(object, backing_store, keys);
}
- static void CollectElementIndicesImpl(Handle<JSObject> object,
- Handle<FixedArrayBase> backing_store,
- KeyAccumulator* keys) {
+ V8_WARN_UNUSED_RESULT static ExceptionStatus CollectElementIndicesImpl(
+ Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
+ KeyAccumulator* keys) {
DCHECK_NE(DICTIONARY_ELEMENTS, kind());
// Non-dictionary elements can't have all-can-read accessors.
uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
@@ -1074,9 +1092,11 @@ class ElementsAccessorBase : public InternalElementsAccessor {
for (uint32_t i = 0; i < length; i++) {
if (Subclass::HasElementImpl(isolate, *object, i, *backing_store,
filter)) {
- keys->AddKey(factory->NewNumberFromUint(i));
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(
+ keys->AddKey(factory->NewNumberFromUint(i)));
}
}
+ return ExceptionStatus::kSuccess;
}
static Handle<FixedArray> DirectCollectElementIndicesImpl(
@@ -1189,10 +1209,11 @@ class ElementsAccessorBase : public InternalElementsAccessor {
return combined_keys;
}
- void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
- KeyAccumulator* accumulator,
- AddKeyConversion convert) final {
- Subclass::AddElementsToKeyAccumulatorImpl(receiver, accumulator, convert);
+ V8_WARN_UNUSED_RESULT ExceptionStatus AddElementsToKeyAccumulator(
+ Handle<JSObject> receiver, KeyAccumulator* accumulator,
+ AddKeyConversion convert) final {
+ return Subclass::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
+ convert);
}
static uint32_t GetCapacityImpl(JSObject holder,
@@ -1266,7 +1287,8 @@ class ElementsAccessorBase : public InternalElementsAccessor {
static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject holder,
FixedArrayBase backing_store,
uint32_t index, PropertyFilter filter) {
- DCHECK(IsFastElementsKind(kind()) || IsFrozenOrSealedElementsKind(kind()));
+ DCHECK(IsFastElementsKind(kind()) ||
+ IsAnyNonextensibleElementsKind(kind()));
uint32_t length = Subclass::GetMaxIndex(holder, backing_store);
if (IsHoleyElementsKindForRead(kind())) {
return index < length && !BackingStore::cast(backing_store)
@@ -1529,10 +1551,10 @@ class DictionaryElementsAccessor
return FilterKey(dictionary, entry, raw_key, filter);
}
- static void CollectElementIndicesImpl(Handle<JSObject> object,
- Handle<FixedArrayBase> backing_store,
- KeyAccumulator* keys) {
- if (keys->filter() & SKIP_STRINGS) return;
+ V8_WARN_UNUSED_RESULT static ExceptionStatus CollectElementIndicesImpl(
+ Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
+ KeyAccumulator* keys) {
+ if (keys->filter() & SKIP_STRINGS) return ExceptionStatus::kSuccess;
Isolate* isolate = keys->isolate();
Handle<NumberDictionary> dictionary =
Handle<NumberDictionary>::cast(backing_store);
@@ -1555,8 +1577,9 @@ class DictionaryElementsAccessor
}
SortIndices(isolate, elements, insertion_index);
for (int i = 0; i < insertion_index; i++) {
- keys->AddKey(elements->get(i));
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(keys->AddKey(elements->get(i)));
}
+ return ExceptionStatus::kSuccess;
}
static Handle<FixedArray> DirectCollectElementIndicesImpl(
@@ -1581,9 +1604,9 @@ class DictionaryElementsAccessor
return list;
}
- static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
- KeyAccumulator* accumulator,
- AddKeyConversion convert) {
+ V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
+ Handle<JSObject> receiver, KeyAccumulator* accumulator,
+ AddKeyConversion convert) {
Isolate* isolate = accumulator->isolate();
Handle<NumberDictionary> dictionary(
NumberDictionary::cast(receiver->elements()), isolate);
@@ -1596,8 +1619,9 @@ class DictionaryElementsAccessor
DCHECK(!value.IsTheHole(isolate));
DCHECK(!value.IsAccessorPair());
DCHECK(!value.IsAccessorInfo());
- accumulator->AddKey(value, convert);
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(value, convert));
}
+ return ExceptionStatus::kSuccess;
}
static bool IncludesValueFastPath(Isolate* isolate, Handle<JSObject> receiver,
@@ -1877,7 +1901,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
Handle<FixedArrayBase> store) {
DCHECK(obj->HasSmiOrObjectElements() || obj->HasDoubleElements() ||
- obj->HasFastArgumentsElements() ||
+ obj->HasNonextensibleElements() || obj->HasFastArgumentsElements() ||
obj->HasFastStringWrapperElements());
Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
if (!obj->IsJSArray() &&
@@ -1981,10 +2005,12 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
ElementsKind kind = KindTraits::Kind;
- if (IsFastPackedElementsKind(kind)) {
+ if (IsFastPackedElementsKind(kind) ||
+ kind == PACKED_NONEXTENSIBLE_ELEMENTS) {
JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
}
- if (IsSmiOrObjectElementsKind(KindTraits::Kind)) {
+ if (IsSmiOrObjectElementsKind(KindTraits::Kind) ||
+ IsNonextensibleElementsKind(kind)) {
JSObject::EnsureWritableFastElements(obj);
}
DeleteCommon(obj, entry, handle(obj->elements(), obj->GetIsolate()));
@@ -2007,18 +2033,20 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
return count;
}
- static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
- KeyAccumulator* accumulator,
- AddKeyConversion convert) {
+ V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
+ Handle<JSObject> receiver, KeyAccumulator* accumulator,
+ AddKeyConversion convert) {
Isolate* isolate = accumulator->isolate();
Handle<FixedArrayBase> elements(receiver->elements(), isolate);
uint32_t length = Subclass::GetMaxNumberOfEntries(*receiver, *elements);
for (uint32_t i = 0; i < length; i++) {
if (IsFastPackedElementsKind(KindTraits::Kind) ||
HasEntryImpl(isolate, *elements, i)) {
- accumulator->AddKey(Subclass::GetImpl(isolate, *elements, i), convert);
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(
+ Subclass::GetImpl(isolate, *elements, i), convert));
}
}
+ return ExceptionStatus::kSuccess;
}
static void ValidateContents(JSObject holder, int length) {
@@ -2164,7 +2192,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
// Hole here, since the {length} used here can be larger than
// JSArray::length.
if (IsSmiOrObjectElementsKind(Subclass::kind()) ||
- IsFrozenOrSealedElementsKind(Subclass::kind())) {
+ IsAnyNonextensibleElementsKind(Subclass::kind())) {
auto elements = FixedArray::cast(receiver->elements());
for (uint32_t k = start_from; k < length; ++k) {
@@ -2189,7 +2217,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
return Just(false);
}
} else if (!IsObjectElementsKind(Subclass::kind()) &&
- !IsFrozenOrSealedElementsKind(Subclass::kind())) {
+ !IsAnyNonextensibleElementsKind(Subclass::kind())) {
// Search for non-number, non-Undefined value, with either
// PACKED_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS, HOLEY_SMI_ELEMENTS or
// HOLEY_DOUBLE_ELEMENTS. Guaranteed to return false, since these
@@ -2199,7 +2227,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
// Search for non-number, non-Undefined value with either
// PACKED_ELEMENTS or HOLEY_ELEMENTS.
DCHECK(IsObjectElementsKind(Subclass::kind()) ||
- IsFrozenOrSealedElementsKind(Subclass::kind()));
+ IsAnyNonextensibleElementsKind(Subclass::kind()));
auto elements = FixedArray::cast(receiver->elements());
for (uint32_t k = start_from; k < length; ++k) {
@@ -2265,7 +2293,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
// PACKED_SMI_ELEMENTS or HOLEY_SMI_ELEMENTS. Return true if
// elementK->IsHeapNumber() && std::isnan(elementK->Number())
DCHECK(IsSmiOrObjectElementsKind(Subclass::kind()) ||
- IsFrozenOrSealedElementsKind(Subclass::kind()));
+ IsAnyNonextensibleElementsKind(Subclass::kind()));
auto elements = FixedArray::cast(receiver->elements());
for (uint32_t k = start_from; k < length; ++k) {
@@ -2414,9 +2442,11 @@ class FastSmiOrObjectElementsAccessor
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case HOLEY_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
CopyObjectToObjectElements(isolate, from, from_kind, from_start, to,
to_kind, to_start, copy_size);
break;
@@ -2493,7 +2523,7 @@ class FastSmiOrObjectElementsAccessor
// Only FAST_{,HOLEY_}ELEMENTS can store non-numbers.
if (!value.IsNumber() && !IsObjectElementsKind(Subclass::kind()) &&
- !IsFrozenOrSealedElementsKind(Subclass::kind())) {
+ !IsAnyNonextensibleElementsKind(Subclass::kind())) {
return Just<int64_t>(-1);
}
// NaN can never be found by strict equality.
@@ -2527,6 +2557,80 @@ class FastPackedObjectElementsAccessor
ElementsKindTraits<PACKED_ELEMENTS>> {};
template <typename Subclass, typename KindTraits>
+class FastNonextensibleObjectElementsAccessor
+ : public FastSmiOrObjectElementsAccessor<Subclass, KindTraits> {
+ public:
+ using BackingStore = typename KindTraits::BackingStore;
+
+ static uint32_t PushImpl(Handle<JSArray> receiver, Arguments* args,
+ uint32_t push_size) {
+ UNREACHABLE();
+ }
+
+ static void AddImpl(Handle<JSObject> object, uint32_t index,
+ Handle<Object> value, PropertyAttributes attributes,
+ uint32_t new_capacity) {
+ UNREACHABLE();
+ }
+
+ // TODO(duongn): refactor this due to code duplication of sealed version.
+ // Consider using JSObject::NormalizeElements(). Also consider follow the fast
+ // element logic instead of changing to dictionary mode.
+ static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
+ uint32_t length,
+ Handle<FixedArrayBase> backing_store) {
+ uint32_t old_length = 0;
+ CHECK(array->length().ToArrayIndex(&old_length));
+ if (length == old_length) {
+ // Do nothing.
+ return;
+ }
+
+ // Transition to DICTIONARY_ELEMENTS.
+ // Convert to dictionary mode.
+ Handle<NumberDictionary> new_element_dictionary =
+ old_length == 0 ? isolate->factory()->empty_slow_element_dictionary()
+ : array->GetElementsAccessor()->Normalize(array);
+
+ // Migrate map.
+ Handle<Map> new_map = Map::Copy(isolate, handle(array->map(), isolate),
+ "SlowCopyForSetLengthImpl");
+ new_map->set_is_extensible(false);
+ new_map->set_elements_kind(DICTIONARY_ELEMENTS);
+ JSObject::MigrateToMap(isolate, array, new_map);
+
+ if (!new_element_dictionary.is_null()) {
+ array->set_elements(*new_element_dictionary);
+ }
+
+ if (array->elements() !=
+ ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
+ Handle<NumberDictionary> dictionary(array->element_dictionary(), isolate);
+ // Make sure we never go back to the fast case
+ array->RequireSlowElements(*dictionary);
+ JSObject::ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate),
+ dictionary,
+ PropertyAttributes::NONE);
+ }
+
+ // Set length.
+ Handle<FixedArrayBase> new_backing_store(array->elements(), isolate);
+ DictionaryElementsAccessor::SetLengthImpl(isolate, array, length,
+ new_backing_store);
+ }
+};
+
+class FastPackedNonextensibleObjectElementsAccessor
+ : public FastNonextensibleObjectElementsAccessor<
+ FastPackedNonextensibleObjectElementsAccessor,
+ ElementsKindTraits<PACKED_NONEXTENSIBLE_ELEMENTS>> {};
+
+class FastHoleyNonextensibleObjectElementsAccessor
+ : public FastNonextensibleObjectElementsAccessor<
+ FastHoleyNonextensibleObjectElementsAccessor,
+ ElementsKindTraits<HOLEY_NONEXTENSIBLE_ELEMENTS>> {};
+
+template <typename Subclass, typename KindTraits>
class FastSealedObjectElementsAccessor
: public FastSmiOrObjectElementsAccessor<Subclass, KindTraits> {
public:
@@ -2564,6 +2668,9 @@ class FastSealedObjectElementsAccessor
UNREACHABLE();
}
+ // TODO(duongn): refactor this due to code duplication of nonextensible
+ // version. Consider using JSObject::NormalizeElements(). Also consider follow
+ // the fast element logic instead of changing to dictionary mode.
static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
uint32_t length,
Handle<FixedArrayBase> backing_store) {
@@ -2749,9 +2856,11 @@ class FastDoubleElementsAccessor
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case HOLEY_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
break;
case DICTIONARY_ELEMENTS:
@@ -3006,16 +3115,17 @@ class TypedElementsAccessor
return AccessorClass::GetCapacityImpl(receiver, backing_store);
}
- static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
- KeyAccumulator* accumulator,
- AddKeyConversion convert) {
+ V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
+ Handle<JSObject> receiver, KeyAccumulator* accumulator,
+ AddKeyConversion convert) {
Isolate* isolate = receiver->GetIsolate();
Handle<FixedArrayBase> elements(receiver->elements(), isolate);
uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements);
for (uint32_t i = 0; i < length; i++) {
Handle<Object> value = AccessorClass::GetInternalImpl(receiver, i);
- accumulator->AddKey(value, convert);
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(value, convert));
}
+ return ExceptionStatus::kSuccess;
}
static Maybe<bool> CollectValuesOrEntriesImpl(
@@ -3886,17 +3996,18 @@ class SloppyArgumentsElementsAccessor
ArgumentsAccessor::NumberOfElementsImpl(receiver, arguments);
}
- static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
- KeyAccumulator* accumulator,
- AddKeyConversion convert) {
+ V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
+ Handle<JSObject> receiver, KeyAccumulator* accumulator,
+ AddKeyConversion convert) {
Isolate* isolate = accumulator->isolate();
Handle<FixedArrayBase> elements(receiver->elements(), isolate);
uint32_t length = GetCapacityImpl(*receiver, *elements);
for (uint32_t entry = 0; entry < length; entry++) {
if (!HasEntryImpl(isolate, *elements, entry)) continue;
Handle<Object> value = GetImpl(isolate, *elements, entry);
- accumulator->AddKey(value, convert);
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(value, convert));
}
+ return ExceptionStatus::kSuccess;
}
static bool HasEntryImpl(Isolate* isolate, FixedArrayBase parameters,
@@ -3986,9 +4097,9 @@ class SloppyArgumentsElementsAccessor
UNREACHABLE();
}
- static void CollectElementIndicesImpl(Handle<JSObject> object,
- Handle<FixedArrayBase> backing_store,
- KeyAccumulator* keys) {
+ V8_WARN_UNUSED_RESULT static ExceptionStatus CollectElementIndicesImpl(
+ Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
+ KeyAccumulator* keys) {
Isolate* isolate = keys->isolate();
uint32_t nof_indices = 0;
Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
@@ -3998,8 +4109,9 @@ class SloppyArgumentsElementsAccessor
ENUMERABLE_STRINGS, indices, &nof_indices);
SortIndices(isolate, indices, nof_indices);
for (uint32_t i = 0; i < nof_indices; i++) {
- keys->AddKey(indices->get(i));
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(keys->AddKey(indices->get(i)));
}
+ return ExceptionStatus::kSuccess;
}
static Handle<FixedArray> DirectCollectElementIndicesImpl(
@@ -4418,33 +4530,34 @@ class StringWrapperElementsAccessor
attributes);
}
- static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
- KeyAccumulator* accumulator,
- AddKeyConversion convert) {
+ V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
+ Handle<JSObject> receiver, KeyAccumulator* accumulator,
+ AddKeyConversion convert) {
Isolate* isolate = receiver->GetIsolate();
Handle<String> string(GetString(*receiver), isolate);
string = String::Flatten(isolate, string);
uint32_t length = static_cast<uint32_t>(string->length());
for (uint32_t i = 0; i < length; i++) {
- accumulator->AddKey(
+ Handle<String> key =
isolate->factory()->LookupSingleCharacterStringFromCode(
- string->Get(i)),
- convert);
+ string->Get(i));
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(key, convert));
}
- BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
- convert);
+ return BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(
+ receiver, accumulator, convert);
}
- static void CollectElementIndicesImpl(Handle<JSObject> object,
- Handle<FixedArrayBase> backing_store,
- KeyAccumulator* keys) {
+ V8_WARN_UNUSED_RESULT static ExceptionStatus CollectElementIndicesImpl(
+ Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
+ KeyAccumulator* keys) {
uint32_t length = GetString(*object).length();
Factory* factory = keys->isolate()->factory();
for (uint32_t i = 0; i < length; i++) {
- keys->AddKey(factory->NewNumberFromUint(i));
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(
+ keys->AddKey(factory->NewNumberFromUint(i)));
}
- BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store,
- keys);
+ return BackingStoreAccessor::CollectElementIndicesImpl(object,
+ backing_store, keys);
}
static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
@@ -4737,5 +4850,7 @@ Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
ElementsAccessor** ElementsAccessor::elements_accessors_ = nullptr;
#undef ELEMENTS_LIST
+#undef RETURN_NOTHING_IF_NOT_SUCCESSFUL
+#undef RETURN_FAILURE_IF_NOT_SUCCESSFUL
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/elements.h b/deps/v8/src/objects/elements.h
index a72a6b068e..b7fcd907a3 100644
--- a/deps/v8/src/objects/elements.h
+++ b/deps/v8/src/objects/elements.h
@@ -69,12 +69,12 @@ class ElementsAccessor {
// Copy all indices that have elements from |object| into the given
// KeyAccumulator. For Dictionary-based element-kinds we filter out elements
// whose PropertyAttribute match |filter|.
- virtual void CollectElementIndices(Handle<JSObject> object,
- Handle<FixedArrayBase> backing_store,
- KeyAccumulator* keys) = 0;
+ V8_WARN_UNUSED_RESULT virtual ExceptionStatus CollectElementIndices(
+ Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
+ KeyAccumulator* keys) = 0;
- inline void CollectElementIndices(Handle<JSObject> object,
- KeyAccumulator* keys);
+ V8_WARN_UNUSED_RESULT inline ExceptionStatus CollectElementIndices(
+ Handle<JSObject> object, KeyAccumulator* keys);
virtual Maybe<bool> CollectValuesOrEntries(
Isolate* isolate, Handle<JSObject> object,
@@ -90,9 +90,9 @@ class ElementsAccessor {
Handle<JSObject> object, Handle<FixedArray> keys,
GetKeysConversion convert, PropertyFilter filter = ALL_PROPERTIES);
- virtual void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
- KeyAccumulator* accumulator,
- AddKeyConversion convert) = 0;
+ V8_WARN_UNUSED_RESULT virtual ExceptionStatus AddElementsToKeyAccumulator(
+ Handle<JSObject> receiver, KeyAccumulator* accumulator,
+ AddKeyConversion convert) = 0;
virtual void TransitionElementsKind(Handle<JSObject> object,
Handle<Map> map) = 0;
diff --git a/deps/v8/src/objects/embedder-data-array-inl.h b/deps/v8/src/objects/embedder-data-array-inl.h
index 34f22b1115..6775fa8075 100644
--- a/deps/v8/src/objects/embedder-data-array-inl.h
+++ b/deps/v8/src/objects/embedder-data-array-inl.h
@@ -16,11 +16,9 @@
namespace v8 {
namespace internal {
-CAST_ACCESSOR(EmbedderDataArray)
+TQ_SMI_ACCESSORS(EmbedderDataArray, length)
-SMI_ACCESSORS(EmbedderDataArray, length, kLengthOffset)
-
-OBJECT_CONSTRUCTORS_IMPL(EmbedderDataArray, HeapObject)
+TQ_OBJECT_CONSTRUCTORS_IMPL(EmbedderDataArray)
Address EmbedderDataArray::slots_start() {
return FIELD_ADDR(*this, OffsetOfElementAt(0));
diff --git a/deps/v8/src/objects/embedder-data-array.h b/deps/v8/src/objects/embedder-data-array.h
index ba4fe25465..668d890817 100644
--- a/deps/v8/src/objects/embedder-data-array.h
+++ b/deps/v8/src/objects/embedder-data-array.h
@@ -8,7 +8,7 @@
#include "src/common/globals.h"
#include "src/handles/maybe-handles.h"
#include "src/objects/heap-object.h"
-#include "torque-generated/field-offsets-tq.h"
+#include "torque-generated/class-definitions-tq.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@@ -20,16 +20,13 @@ namespace internal {
// It's basically an "array of EmbedderDataSlots".
// Note, if the pointer compression is enabled the embedder data slot also
// contains a raw data part in addition to tagged part.
-class EmbedderDataArray : public HeapObject {
+class EmbedderDataArray
+ : public TorqueGeneratedEmbedderDataArray<EmbedderDataArray, HeapObject> {
public:
// [length]: length of the array in an embedder data slots.
V8_INLINE int length() const;
V8_INLINE void set_length(int value);
- DECL_CAST(EmbedderDataArray)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
- TORQUE_GENERATED_EMBEDDER_DATA_ARRAY_FIELDS)
// TODO(v8:8989): [torque] Support marker constants.
static const int kHeaderSize = kSize;
@@ -64,7 +61,7 @@ class EmbedderDataArray : public HeapObject {
private:
STATIC_ASSERT(kHeaderSize == Internals::kFixedArrayHeaderSize);
- OBJECT_CONSTRUCTORS(EmbedderDataArray, HeapObject);
+ TQ_OBJECT_CONSTRUCTORS(EmbedderDataArray)
};
} // namespace internal
diff --git a/deps/v8/src/objects/feedback-vector.cc b/deps/v8/src/objects/feedback-vector.cc
index 4f4826eab3..2fbc48a95e 100644
--- a/deps/v8/src/objects/feedback-vector.cc
+++ b/deps/v8/src/objects/feedback-vector.cc
@@ -887,8 +887,7 @@ float FeedbackNexus::ComputeCallFrequency() {
double const invocation_count = vector().invocation_count();
double const call_count = GetCallCount();
- if (invocation_count == 0) {
- // Prevent division by 0.
+ if (invocation_count == 0.0) { // Prevent division by 0.
return 0.0f;
}
return static_cast<float>(call_count / invocation_count);
@@ -1094,6 +1093,12 @@ Name FeedbackNexus::GetName() const {
return Name::cast(feedback->GetHeapObjectAssumeStrong());
}
}
+ if (IsStoreDataPropertyInLiteralKind(kind())) {
+ MaybeObject extra = GetFeedbackExtra();
+ if (IsPropertyNameFeedback(extra)) {
+ return Name::cast(extra->GetHeapObjectAssumeStrong());
+ }
+ }
return Name();
}
@@ -1180,7 +1185,8 @@ KeyedAccessStoreMode KeyedAccessStoreModeForBuiltin(int builtin_index) {
} // namespace
KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
- DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()));
+ DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()) ||
+ IsStoreDataPropertyInLiteralKind(kind()));
KeyedAccessStoreMode mode = STANDARD_STORE;
MapHandles maps;
MaybeObjectHandles handlers;
@@ -1220,14 +1226,17 @@ KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
IcCheckType FeedbackNexus::GetKeyType() const {
DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
- IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
+ IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()) ||
+ IsStoreDataPropertyInLiteralKind(kind()));
MaybeObject feedback = GetFeedback();
if (feedback == MaybeObject::FromObject(
*FeedbackVector::MegamorphicSentinel(GetIsolate()))) {
return static_cast<IcCheckType>(
Smi::ToInt(GetFeedbackExtra()->cast<Object>()));
}
- return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
+ MaybeObject maybe_name =
+ IsStoreDataPropertyInLiteralKind(kind()) ? GetFeedbackExtra() : feedback;
+ return IsPropertyNameFeedback(maybe_name) ? PROPERTY : ELEMENT;
}
BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
diff --git a/deps/v8/src/objects/field-index.h b/deps/v8/src/objects/field-index.h
index a6657634c8..4fae87774d 100644
--- a/deps/v8/src/objects/field-index.h
+++ b/deps/v8/src/objects/field-index.h
@@ -107,18 +107,16 @@ class FieldIndex final {
(kDescriptorIndexBitCount + 1 + kTaggedSizeLog2);
// Index from beginning of object.
- class OffsetBits : public BitField64<int, 0, kOffsetBitsSize> {};
- class IsInObjectBits : public BitField64<bool, OffsetBits::kNext, 1> {};
- class EncodingBits : public BitField64<Encoding, IsInObjectBits::kNext, 2> {};
+ using OffsetBits = BitField64<int, 0, kOffsetBitsSize>;
+ using IsInObjectBits = OffsetBits::Next<bool, 1>;
+ using EncodingBits = IsInObjectBits::Next<Encoding, 2>;
// Number of inobject properties.
- class InObjectPropertyBits
- : public BitField64<int, EncodingBits::kNext, kDescriptorIndexBitCount> {
- };
+ using InObjectPropertyBits =
+ EncodingBits::Next<int, kDescriptorIndexBitCount>;
// Offset of first inobject property from beginning of object.
- class FirstInobjectPropertyOffsetBits
- : public BitField64<int, InObjectPropertyBits::kNext,
- kFirstInobjectPropertyOffsetBitCount> {};
- STATIC_ASSERT(FirstInobjectPropertyOffsetBits::kNext <= 64);
+ using FirstInobjectPropertyOffsetBits =
+ InObjectPropertyBits::Next<int, kFirstInobjectPropertyOffsetBitCount>;
+ STATIC_ASSERT(FirstInobjectPropertyOffsetBits::kLastUsedBit < 64);
uint64_t bit_field_;
};
diff --git a/deps/v8/src/objects/fixed-array.h b/deps/v8/src/objects/fixed-array.h
index ca6f06e83c..40290797f7 100644
--- a/deps/v8/src/objects/fixed-array.h
+++ b/deps/v8/src/objects/fixed-array.h
@@ -247,7 +247,10 @@ class FixedDoubleArray : public FixedArrayBase {
DECL_CAST(FixedDoubleArray)
- // Maximally allowed length of a FixedArray.
+ // Start offset of elements.
+ static constexpr int kFloatsOffset = kHeaderSize;
+
+ // Maximally allowed length of a FixedDoubleArray.
static const int kMaxLength = (kMaxSize - kHeaderSize) / kDoubleSize;
static_assert(Internals::IsValidSmi(kMaxLength),
"FixedDoubleArray maxLength not a Smi");
diff --git a/deps/v8/src/objects/function-kind.h b/deps/v8/src/objects/function-kind.h
index 4a1819813c..8e9c68e426 100644
--- a/deps/v8/src/objects/function-kind.h
+++ b/deps/v8/src/objects/function-kind.h
@@ -1,4 +1,3 @@
-
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -21,12 +20,12 @@ enum FunctionKind : uint8_t {
// BEGIN default constructors
kDefaultBaseConstructor,
// END base constructors
- // BEGIN derived cosntructors
+ // BEGIN derived constructors
kDefaultDerivedConstructor,
// END default constructors
kDerivedConstructor,
- // END derived costructors
- // END class cosntructors
+ // END derived constructors
+ // END class constructors
// END constructable functions.
// BEGIN accessors
kGetterFunction,
diff --git a/deps/v8/src/objects/function-syntax-kind.h b/deps/v8/src/objects/function-syntax-kind.h
new file mode 100644
index 0000000000..074ccc4286
--- /dev/null
+++ b/deps/v8/src/objects/function-syntax-kind.h
@@ -0,0 +1,46 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_OBJECTS_FUNCTION_SYNTAX_KIND_H_
+#define V8_OBJECTS_FUNCTION_SYNTAX_KIND_H_
+
+#include "src/utils/utils.h"
+
+namespace v8 {
+namespace internal {
+
+enum class FunctionSyntaxKind : uint8_t {
+ kAnonymousExpression,
+ kNamedExpression,
+ kDeclaration,
+ kAccessorOrMethod,
+ kWrapped,
+
+ kLastFunctionSyntaxKind = kWrapped,
+};
+
+inline const char* FunctionSyntaxKind2String(FunctionSyntaxKind kind) {
+ switch (kind) {
+ case FunctionSyntaxKind::kAnonymousExpression:
+ return "AnonymousExpression";
+ case FunctionSyntaxKind::kNamedExpression:
+ return "NamedExpression";
+ case FunctionSyntaxKind::kDeclaration:
+ return "Declaration";
+ case FunctionSyntaxKind::kAccessorOrMethod:
+ return "AccessorOrMethod";
+ case FunctionSyntaxKind::kWrapped:
+ return "Wrapped";
+ }
+ UNREACHABLE();
+}
+
+inline std::ostream& operator<<(std::ostream& os, FunctionSyntaxKind kind) {
+ return os << FunctionSyntaxKind2String(kind);
+}
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_OBJECTS_FUNCTION_SYNTAX_KIND_H_
diff --git a/deps/v8/src/objects/heap-number-inl.h b/deps/v8/src/objects/heap-number-inl.h
index 3d70d71c89..78e65ca231 100644
--- a/deps/v8/src/objects/heap-number-inl.h
+++ b/deps/v8/src/objects/heap-number-inl.h
@@ -16,34 +16,31 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(HeapNumberBase, HeapObject)
-OBJECT_CONSTRUCTORS_IMPL(HeapNumber, HeapNumberBase)
-OBJECT_CONSTRUCTORS_IMPL(MutableHeapNumber, HeapNumberBase)
+OBJECT_CONSTRUCTORS_IMPL(HeapNumber, HeapObject)
CAST_ACCESSOR(HeapNumber)
-CAST_ACCESSOR(MutableHeapNumber)
-double HeapNumberBase::value() const { return ReadField<double>(kValueOffset); }
+double HeapNumber::value() const { return ReadField<double>(kValueOffset); }
-void HeapNumberBase::set_value(double value) {
+void HeapNumber::set_value(double value) {
WriteField<double>(kValueOffset, value);
}
-uint64_t HeapNumberBase::value_as_bits() const {
+uint64_t HeapNumber::value_as_bits() const {
// Bug(v8:8875): HeapNumber's double may be unaligned.
return base::ReadUnalignedValue<uint64_t>(field_address(kValueOffset));
}
-void HeapNumberBase::set_value_as_bits(uint64_t bits) {
+void HeapNumber::set_value_as_bits(uint64_t bits) {
base::WriteUnalignedValue<uint64_t>(field_address(kValueOffset), bits);
}
-int HeapNumberBase::get_exponent() {
+int HeapNumber::get_exponent() {
return ((ReadField<int>(kExponentOffset) & kExponentMask) >> kExponentShift) -
kExponentBias;
}
-int HeapNumberBase::get_sign() {
+int HeapNumber::get_sign() {
return ReadField<int>(kExponentOffset) & kSignMask;
}
diff --git a/deps/v8/src/objects/heap-number.h b/deps/v8/src/objects/heap-number.h
index 15e821e966..9063f3d22c 100644
--- a/deps/v8/src/objects/heap-number.h
+++ b/deps/v8/src/objects/heap-number.h
@@ -14,10 +14,8 @@ namespace v8 {
namespace internal {
// The HeapNumber class describes heap allocated numbers that cannot be
-// represented in a Smi (small integer). MutableHeapNumber is the same, but its
-// number value can change over time (it is used only as property storage).
-// HeapNumberBase merely exists to avoid code duplication.
-class HeapNumberBase : public HeapObject {
+// represented in a Smi (small integer).
+class HeapNumber : public HeapObject {
public:
// [value]: number value.
inline double value() const;
@@ -58,27 +56,10 @@ class HeapNumberBase : public HeapObject {
static const int kMantissaBitsInTopWord = 20;
static const int kNonMantissaBitsInTopWord = 12;
- // Just to make the macro-generated constructor happy. Subclasses should
- // perform their own proper type checking.
- inline bool IsHeapNumberBase() const { return true; }
-
- OBJECT_CONSTRUCTORS(HeapNumberBase, HeapObject);
-};
-
-class HeapNumber : public HeapNumberBase {
- public:
DECL_CAST(HeapNumber)
V8_EXPORT_PRIVATE void HeapNumberPrint(std::ostream& os);
- OBJECT_CONSTRUCTORS(HeapNumber, HeapNumberBase);
-};
-
-class MutableHeapNumber : public HeapNumberBase {
- public:
- DECL_CAST(MutableHeapNumber)
- V8_EXPORT_PRIVATE void MutableHeapNumberPrint(std::ostream& os);
-
- OBJECT_CONSTRUCTORS(MutableHeapNumber, HeapNumberBase);
+ OBJECT_CONSTRUCTORS(HeapNumber, HeapObject);
};
} // namespace internal
diff --git a/deps/v8/src/objects/instance-type.h b/deps/v8/src/objects/instance-type.h
index 79c953aa87..9a855de95b 100644
--- a/deps/v8/src/objects/instance-type.h
+++ b/deps/v8/src/objects/instance-type.h
@@ -133,7 +133,6 @@ enum InstanceType : uint16_t {
// "Data", objects that cannot contain non-map-word pointers to heap
// objects.
- MUTABLE_HEAP_NUMBER_TYPE,
FOREIGN_TYPE,
BYTE_ARRAY_TYPE,
BYTECODE_ARRAY_TYPE,
@@ -181,8 +180,7 @@ enum InstanceType : uint16_t {
CALLBACK_TASK_TYPE,
PROMISE_FULFILL_REACTION_JOB_TASK_TYPE,
PROMISE_REJECT_REACTION_JOB_TASK_TYPE,
- PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE,
- FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE, // LAST_MICROTASK_TYPE
+ PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE, // LAST_MICROTASK_TYPE
#define MAKE_TORQUE_INSTANCE_TYPE(V) V,
TORQUE_DEFINED_INSTANCE_TYPES(MAKE_TORQUE_INSTANCE_TYPE)
@@ -346,7 +344,7 @@ enum InstanceType : uint16_t {
LAST_CONTEXT_TYPE = WITH_CONTEXT_TYPE,
// Boundaries for testing if given HeapObject is a subclass of Microtask.
FIRST_MICROTASK_TYPE = CALLABLE_TASK_TYPE,
- LAST_MICROTASK_TYPE = FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE,
+ LAST_MICROTASK_TYPE = PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE,
// Boundaries of module record types
FIRST_MODULE_TYPE = SOURCE_TEXT_MODULE_TYPE,
LAST_MODULE_TYPE = SYNTHETIC_MODULE_TYPE,
@@ -462,7 +460,6 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
V(JSWeakSet, JS_WEAK_SET_TYPE) \
V(LoadHandler, LOAD_HANDLER_TYPE) \
V(Map, MAP_TYPE) \
- V(MutableHeapNumber, MUTABLE_HEAP_NUMBER_TYPE) \
V(NameDictionary, NAME_DICTIONARY_TYPE) \
V(NativeContext, NATIVE_CONTEXT_TYPE) \
V(NumberDictionary, NUMBER_DICTIONARY_TYPE) \
diff --git a/deps/v8/src/objects/js-collection-inl.h b/deps/v8/src/objects/js-collection-inl.h
index fb0cf1652e..6bbaa9bc1f 100644
--- a/deps/v8/src/objects/js-collection-inl.h
+++ b/deps/v8/src/objects/js-collection-inl.h
@@ -19,17 +19,17 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(JSCollection, JSObject)
-OBJECT_CONSTRUCTORS_IMPL(JSMap, JSCollection)
-OBJECT_CONSTRUCTORS_IMPL(JSSet, JSCollection)
-OBJECT_CONSTRUCTORS_IMPL(JSWeakCollection, JSObject)
-OBJECT_CONSTRUCTORS_IMPL(JSWeakMap, JSWeakCollection)
-OBJECT_CONSTRUCTORS_IMPL(JSWeakSet, JSWeakCollection)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSCollection)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSMap)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSSet)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSWeakCollection)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSWeakMap)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSWeakSet)
// TODO(jkummerow): Move JSCollectionIterator to js-collection.h?
// TODO(jkummerow): Introduce IsJSCollectionIterator() check? Or unchecked
// version of OBJECT_CONSTRUCTORS_IMPL macro?
-JSCollectionIterator::JSCollectionIterator(Address ptr) : JSObject(ptr) {}
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSCollectionIterator)
template <class Derived, class TableType>
OrderedHashTableIterator<Derived, TableType>::OrderedHashTableIterator(
Address ptr)
@@ -45,20 +45,8 @@ JSSetIterator::JSSetIterator(Address ptr)
SLOW_DCHECK(IsJSSetIterator());
}
-ACCESSORS(JSCollection, table, Object, kTableOffset)
-ACCESSORS(JSCollectionIterator, table, Object, kTableOffset)
-ACCESSORS(JSCollectionIterator, index, Object, kIndexOffset)
-
-ACCESSORS(JSWeakCollection, table, Object, kTableOffset)
-
-CAST_ACCESSOR(JSCollection)
-CAST_ACCESSOR(JSSet)
CAST_ACCESSOR(JSSetIterator)
-CAST_ACCESSOR(JSMap)
CAST_ACCESSOR(JSMapIterator)
-CAST_ACCESSOR(JSWeakCollection)
-CAST_ACCESSOR(JSWeakMap)
-CAST_ACCESSOR(JSWeakSet)
Object JSMapIterator::CurrentValue() {
OrderedHashMap table = OrderedHashMap::cast(this->table());
diff --git a/deps/v8/src/objects/js-collection-iterator.h b/deps/v8/src/objects/js-collection-iterator.h
index c002294b01..b193aa84cd 100644
--- a/deps/v8/src/objects/js-collection-iterator.h
+++ b/deps/v8/src/objects/js-collection-iterator.h
@@ -16,21 +16,13 @@
namespace v8 {
namespace internal {
-class JSCollectionIterator : public JSObject {
+class JSCollectionIterator
+ : public TorqueGeneratedJSCollectionIterator<JSCollectionIterator,
+ JSObject> {
public:
- // [table]: the backing hash table mapping keys to values.
- DECL_ACCESSORS(table, Object)
-
- // [index]: The index into the data table.
- DECL_ACCESSORS(index, Object)
-
void JSCollectionIteratorPrint(std::ostream& os, const char* name);
- DECL_VERIFIER(JSCollectionIterator)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
- TORQUE_GENERATED_JSCOLLECTION_ITERATOR_FIELDS)
- OBJECT_CONSTRUCTORS(JSCollectionIterator, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSCollectionIterator)
};
// OrderedHashTableIterator is an iterator that iterates over the keys and
diff --git a/deps/v8/src/objects/js-collection.h b/deps/v8/src/objects/js-collection.h
index 0a856ca062..d1b2ae862a 100644
--- a/deps/v8/src/objects/js-collection.h
+++ b/deps/v8/src/objects/js-collection.h
@@ -17,39 +17,25 @@ namespace internal {
class OrderedHashSet;
class OrderedHashMap;
-class JSCollection : public JSObject {
+class JSCollection
+ : public TorqueGeneratedJSCollection<JSCollection, JSObject> {
public:
- DECL_CAST(JSCollection)
-
- // [table]: the backing hash table
- DECL_ACCESSORS(table, Object)
-
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
- TORQUE_GENERATED_JSCOLLECTION_FIELDS)
-
static const int kAddFunctionDescriptorIndex = 3;
- DECL_VERIFIER(JSCollection)
-
- OBJECT_CONSTRUCTORS(JSCollection, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSCollection)
};
// The JSSet describes EcmaScript Harmony sets
-class JSSet : public JSCollection {
+class JSSet : public TorqueGeneratedJSSet<JSSet, JSCollection> {
public:
- DECL_CAST(JSSet)
-
static void Initialize(Handle<JSSet> set, Isolate* isolate);
static void Clear(Isolate* isolate, Handle<JSSet> set);
// Dispatched behavior.
DECL_PRINTER(JSSet)
DECL_VERIFIER(JSSet)
- DEFINE_FIELD_OFFSET_CONSTANTS(JSCollection::kHeaderSize,
- TORQUE_GENERATED_JSWEAK_SET_FIELDS)
- OBJECT_CONSTRUCTORS(JSSet, JSCollection);
+ TQ_OBJECT_CONSTRUCTORS(JSSet)
};
class JSSetIterator
@@ -66,20 +52,16 @@ class JSSetIterator
};
// The JSMap describes EcmaScript Harmony maps
-class JSMap : public JSCollection {
+class JSMap : public TorqueGeneratedJSMap<JSMap, JSCollection> {
public:
- DECL_CAST(JSMap)
-
static void Initialize(Handle<JSMap> map, Isolate* isolate);
static void Clear(Isolate* isolate, Handle<JSMap> map);
// Dispatched behavior.
DECL_PRINTER(JSMap)
DECL_VERIFIER(JSMap)
- DEFINE_FIELD_OFFSET_CONSTANTS(JSCollection::kHeaderSize,
- TORQUE_GENERATED_JSWEAK_MAP_FIELDS)
- OBJECT_CONSTRUCTORS(JSMap, JSCollection);
+ TQ_OBJECT_CONSTRUCTORS(JSMap)
};
class JSMapIterator
@@ -100,13 +82,9 @@ class JSMapIterator
};
// Base class for both JSWeakMap and JSWeakSet
-class JSWeakCollection : public JSObject {
+class JSWeakCollection
+ : public TorqueGeneratedJSWeakCollection<JSWeakCollection, JSObject> {
public:
- DECL_CAST(JSWeakCollection)
-
- // [table]: the backing hash table mapping keys to values.
- DECL_ACCESSORS(table, Object)
-
static void Initialize(Handle<JSWeakCollection> collection, Isolate* isolate);
V8_EXPORT_PRIVATE static void Set(Handle<JSWeakCollection> collection,
Handle<Object> key, Handle<Object> value,
@@ -116,11 +94,6 @@ class JSWeakCollection : public JSObject {
static Handle<JSArray> GetEntries(Handle<JSWeakCollection> holder,
int max_entries);
- DECL_VERIFIER(JSWeakCollection)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
- TORQUE_GENERATED_JSWEAK_COLLECTION_FIELDS)
-
static const int kAddFunctionDescriptorIndex = 3;
// Iterates the function object according to the visiting policy.
@@ -131,37 +104,29 @@ class JSWeakCollection : public JSObject {
static const int kSizeOfAllWeakCollections = kHeaderSize;
- OBJECT_CONSTRUCTORS(JSWeakCollection, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSWeakCollection)
};
// The JSWeakMap describes EcmaScript Harmony weak maps
-class JSWeakMap : public JSWeakCollection {
+class JSWeakMap : public TorqueGeneratedJSWeakMap<JSWeakMap, JSWeakCollection> {
public:
- DECL_CAST(JSWeakMap)
-
// Dispatched behavior.
DECL_PRINTER(JSWeakMap)
DECL_VERIFIER(JSWeakMap)
- DEFINE_FIELD_OFFSET_CONSTANTS(JSWeakCollection::kHeaderSize,
- TORQUE_GENERATED_JSWEAK_MAP_FIELDS)
STATIC_ASSERT(kSize == kSizeOfAllWeakCollections);
- OBJECT_CONSTRUCTORS(JSWeakMap, JSWeakCollection);
+ TQ_OBJECT_CONSTRUCTORS(JSWeakMap)
};
// The JSWeakSet describes EcmaScript Harmony weak sets
-class JSWeakSet : public JSWeakCollection {
+class JSWeakSet : public TorqueGeneratedJSWeakSet<JSWeakSet, JSWeakCollection> {
public:
- DECL_CAST(JSWeakSet)
-
// Dispatched behavior.
DECL_PRINTER(JSWeakSet)
DECL_VERIFIER(JSWeakSet)
- DEFINE_FIELD_OFFSET_CONSTANTS(JSWeakCollection::kHeaderSize,
- TORQUE_GENERATED_JSWEAK_SET_FIELDS)
- STATIC_ASSERT(kSize == kSizeOfAllWeakCollections);
- OBJECT_CONSTRUCTORS(JSWeakSet, JSWeakCollection);
+ STATIC_ASSERT(kSize == kSizeOfAllWeakCollections);
+ TQ_OBJECT_CONSTRUCTORS(JSWeakSet)
};
} // namespace internal
diff --git a/deps/v8/src/objects/js-date-time-format.cc b/deps/v8/src/objects/js-date-time-format.cc
index db7ba27312..29fcfb0d7c 100644
--- a/deps/v8/src/objects/js-date-time-format.cc
+++ b/deps/v8/src/objects/js-date-time-format.cc
@@ -8,8 +8,11 @@
#include "src/objects/js-date-time-format.h"
+#include <algorithm>
+#include <map>
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include "src/date/date.h"
@@ -1191,6 +1194,12 @@ class DateTimePatternGeneratorCache {
UErrorCode status = U_ZERO_ERROR;
map_[key].reset(icu::DateTimePatternGenerator::createInstance(
icu::Locale(key.c_str()), status));
+ // Fallback to use "root".
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ map_[key].reset(
+ icu::DateTimePatternGenerator::createInstance("root", status));
+ }
CHECK(U_SUCCESS(status));
return map_[key]->clone();
}
diff --git a/deps/v8/src/objects/js-generator-inl.h b/deps/v8/src/objects/js-generator-inl.h
index d0fe2cd90e..e3c57198c4 100644
--- a/deps/v8/src/objects/js-generator-inl.h
+++ b/deps/v8/src/objects/js-generator-inl.h
@@ -16,29 +16,15 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(JSGeneratorObject, JSObject)
-OBJECT_CONSTRUCTORS_IMPL(JSAsyncFunctionObject, JSGeneratorObject)
-OBJECT_CONSTRUCTORS_IMPL(JSAsyncGeneratorObject, JSGeneratorObject)
-OBJECT_CONSTRUCTORS_IMPL(AsyncGeneratorRequest, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSGeneratorObject)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSAsyncFunctionObject)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSAsyncGeneratorObject)
+TQ_OBJECT_CONSTRUCTORS_IMPL(AsyncGeneratorRequest)
-CAST_ACCESSOR(JSAsyncFunctionObject)
-CAST_ACCESSOR(JSAsyncGeneratorObject)
-CAST_ACCESSOR(JSGeneratorObject)
-CAST_ACCESSOR(AsyncGeneratorRequest)
+TQ_SMI_ACCESSORS(JSGeneratorObject, resume_mode)
+TQ_SMI_ACCESSORS(JSGeneratorObject, continuation)
-ACCESSORS(JSGeneratorObject, function, JSFunction, kFunctionOffset)
-ACCESSORS(JSGeneratorObject, context, Context, kContextOffset)
-ACCESSORS(JSGeneratorObject, receiver, Object, kReceiverOffset)
-ACCESSORS(JSGeneratorObject, input_or_debug_pos, Object, kInputOrDebugPosOffset)
-SMI_ACCESSORS(JSGeneratorObject, resume_mode, kResumeModeOffset)
-SMI_ACCESSORS(JSGeneratorObject, continuation, kContinuationOffset)
-ACCESSORS(JSGeneratorObject, parameters_and_registers, FixedArray,
- kParametersAndRegistersOffset)
-
-ACCESSORS(AsyncGeneratorRequest, next, Object, kNextOffset)
-SMI_ACCESSORS(AsyncGeneratorRequest, resume_mode, kResumeModeOffset)
-ACCESSORS(AsyncGeneratorRequest, value, Object, kValueOffset)
-ACCESSORS(AsyncGeneratorRequest, promise, Object, kPromiseOffset)
+TQ_SMI_ACCESSORS(AsyncGeneratorRequest, resume_mode)
bool JSGeneratorObject::is_suspended() const {
DCHECK_LT(kGeneratorExecuting, 0);
@@ -54,10 +40,7 @@ bool JSGeneratorObject::is_executing() const {
return continuation() == kGeneratorExecuting;
}
-ACCESSORS(JSAsyncFunctionObject, promise, JSPromise, kPromiseOffset)
-
-ACCESSORS(JSAsyncGeneratorObject, queue, HeapObject, kQueueOffset)
-SMI_ACCESSORS(JSAsyncGeneratorObject, is_awaiting, kIsAwaitingOffset)
+TQ_SMI_ACCESSORS(JSAsyncGeneratorObject, is_awaiting)
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/js-generator.h b/deps/v8/src/objects/js-generator.h
index 0e99d824ab..a56ea917eb 100644
--- a/deps/v8/src/objects/js-generator.h
+++ b/deps/v8/src/objects/js-generator.h
@@ -17,24 +17,9 @@ namespace internal {
// Forward declarations.
class JSPromise;
-class JSGeneratorObject : public JSObject {
+class JSGeneratorObject
+ : public TorqueGeneratedJSGeneratorObject<JSGeneratorObject, JSObject> {
public:
- // [function]: The function corresponding to this generator object.
- DECL_ACCESSORS(function, JSFunction)
-
- // [context]: The context of the suspended computation.
- DECL_ACCESSORS(context, Context)
-
- // [receiver]: The receiver of the suspended computation.
- DECL_ACCESSORS(receiver, Object)
-
- // [input_or_debug_pos]
- // For executing generators: the most recent input value.
- // For suspended generators: debug information (bytecode offset).
- // There is currently no need to remember the most recent input value for a
- // suspended generator.
- DECL_ACCESSORS(input_or_debug_pos, Object)
-
// [resume_mode]: The most recent resume mode.
enum ResumeMode { kNext, kReturn, kThrow };
DECL_INT_ACCESSORS(resume_mode)
@@ -54,84 +39,50 @@ class JSGeneratorObject : public JSObject {
// is suspended.
int source_position() const;
- // [parameters_and_registers]: Saved interpreter register file.
- DECL_ACCESSORS(parameters_and_registers, FixedArray)
-
- DECL_CAST(JSGeneratorObject)
-
// Dispatched behavior.
DECL_PRINTER(JSGeneratorObject)
- DECL_VERIFIER(JSGeneratorObject)
// Magic sentinel values for the continuation.
static const int kGeneratorExecuting = -2;
static const int kGeneratorClosed = -1;
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
- TORQUE_GENERATED_JSGENERATOR_OBJECT_FIELDS)
-
- OBJECT_CONSTRUCTORS(JSGeneratorObject, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSGeneratorObject)
};
-class JSAsyncFunctionObject : public JSGeneratorObject {
+class JSAsyncFunctionObject
+ : public TorqueGeneratedJSAsyncFunctionObject<JSAsyncFunctionObject,
+ JSGeneratorObject> {
public:
- DECL_CAST(JSAsyncFunctionObject)
-
// Dispatched behavior.
DECL_VERIFIER(JSAsyncFunctionObject)
- // [promise]: The promise of the async function.
- DECL_ACCESSORS(promise, JSPromise)
-
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(JSGeneratorObject::kSize,
- TORQUE_GENERATED_JSASYNC_FUNCTION_OBJECT_FIELDS)
-
- OBJECT_CONSTRUCTORS(JSAsyncFunctionObject, JSGeneratorObject);
+ TQ_OBJECT_CONSTRUCTORS(JSAsyncFunctionObject)
};
-class JSAsyncGeneratorObject : public JSGeneratorObject {
+class JSAsyncGeneratorObject
+ : public TorqueGeneratedJSAsyncGeneratorObject<JSAsyncGeneratorObject,
+ JSGeneratorObject> {
public:
- DECL_CAST(JSAsyncGeneratorObject)
-
// Dispatched behavior.
DECL_VERIFIER(JSAsyncGeneratorObject)
- // [queue]
- // Pointer to the head of a singly linked list of AsyncGeneratorRequest, or
- // undefined.
- DECL_ACCESSORS(queue, HeapObject)
-
// [is_awaiting]
// Whether or not the generator is currently awaiting.
DECL_INT_ACCESSORS(is_awaiting)
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(
- JSGeneratorObject::kSize,
- TORQUE_GENERATED_JSASYNC_GENERATOR_OBJECT_FIELDS)
-#undef JS_ASYNC_GENERATOR_FIELDS
-
- OBJECT_CONSTRUCTORS(JSAsyncGeneratorObject, JSGeneratorObject);
+ TQ_OBJECT_CONSTRUCTORS(JSAsyncGeneratorObject)
};
-class AsyncGeneratorRequest : public Struct {
+class AsyncGeneratorRequest
+ : public TorqueGeneratedAsyncGeneratorRequest<AsyncGeneratorRequest,
+ Struct> {
public:
- // Holds an AsyncGeneratorRequest, or Undefined.
- DECL_ACCESSORS(next, Object)
DECL_INT_ACCESSORS(resume_mode)
- DECL_ACCESSORS(value, Object)
- DECL_ACCESSORS(promise, Object)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize,
- TORQUE_GENERATED_ASYNC_GENERATOR_REQUEST_FIELDS)
- DECL_CAST(AsyncGeneratorRequest)
DECL_PRINTER(AsyncGeneratorRequest)
DECL_VERIFIER(AsyncGeneratorRequest)
- OBJECT_CONSTRUCTORS(AsyncGeneratorRequest, Struct);
+ TQ_OBJECT_CONSTRUCTORS(AsyncGeneratorRequest)
};
} // namespace internal
diff --git a/deps/v8/src/objects/js-number-format.cc b/deps/v8/src/objects/js-number-format.cc
index d1e3ef4d0c..ff564975d6 100644
--- a/deps/v8/src/objects/js-number-format.cc
+++ b/deps/v8/src/objects/js-number-format.cc
@@ -172,16 +172,21 @@ std::map<const std::string, icu::MeasureUnit> CreateUnitMap() {
status = U_ZERO_ERROR;
// See the list in ecma402 #sec-issanctionedsimpleunitidentifier
std::set<std::string> sanctioned(
- {"acre", "bit", "byte", "celsius",
- "centimeter", "day", "degree", "fahrenheit",
- "foot", "gigabit", "gigabyte", "gram",
- "hectare", "hour", "inch", "kilobit",
- "kilobyte", "kilogram", "kilometer", "megabit",
- "megabyte", "meter", "mile", "mile-scandinavian",
- "millimeter", "millisecond", "minute", "month",
- "ounce", "percent", "petabyte", "pound",
- "second", "stone", "terabit", "terabyte",
- "week", "yard", "year"});
+ {"acre", "bit", "byte",
+ "celsius", "centimeter", "day",
+ "degree", "fahrenheit", "fluid-ounce",
+ "foot", "gallon", "gigabit",
+ "gigabyte", "gram", "hectare",
+ "hour", "inch", "kilobit",
+ "kilobyte", "kilogram", "kilometer",
+ "liter", "megabit", "megabyte",
+ "meter", "mile", "mile-scandinavian",
+ "millimeter", "milliliter", "millisecond",
+ "minute", "month", "ounce",
+ "percent", "petabyte", "pound",
+ "second", "stone", "terabit",
+ "terabyte", "week", "yard",
+ "year"});
std::vector<icu::MeasureUnit> units(total);
total = icu::MeasureUnit::getAvailable(units.data(), total, status);
CHECK(U_SUCCESS(status));
@@ -1031,7 +1036,7 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
isolate,
NewTypeError(MessageTemplate::kInvalidUnit,
factory->NewStringFromStaticChars("Intl.NumberFormat"),
- factory->NewStringFromStaticChars("")),
+ factory->empty_string()),
JSNumberFormat);
}
diff --git a/deps/v8/src/objects/js-objects-inl.h b/deps/v8/src/objects/js-objects-inl.h
index 10672d4443..f8fe069d3d 100644
--- a/deps/v8/src/objects/js-objects-inl.h
+++ b/deps/v8/src/objects/js-objects-inl.h
@@ -31,9 +31,9 @@ namespace internal {
OBJECT_CONSTRUCTORS_IMPL(JSReceiver, HeapObject)
TQ_OBJECT_CONSTRUCTORS_IMPL(JSObject)
-OBJECT_CONSTRUCTORS_IMPL(JSAsyncFromSyncIterator, JSObject)
-OBJECT_CONSTRUCTORS_IMPL(JSBoundFunction, JSObject)
-OBJECT_CONSTRUCTORS_IMPL(JSDate, JSObject)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSAsyncFromSyncIterator)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSBoundFunction)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSDate)
OBJECT_CONSTRUCTORS_IMPL(JSFunction, JSObject)
OBJECT_CONSTRUCTORS_IMPL(JSGlobalObject, JSObject)
TQ_OBJECT_CONSTRUCTORS_IMPL(JSGlobalProxy)
@@ -44,9 +44,6 @@ OBJECT_CONSTRUCTORS_IMPL(JSStringIterator, JSObject)
NEVER_READ_ONLY_SPACE_IMPL(JSReceiver)
-CAST_ACCESSOR(JSAsyncFromSyncIterator)
-CAST_ACCESSOR(JSBoundFunction)
-CAST_ACCESSOR(JSDate)
CAST_ACCESSOR(JSFunction)
CAST_ACCESSOR(JSGlobalObject)
CAST_ACCESSOR(JSIteratorResult)
@@ -369,10 +366,10 @@ void JSObject::RawFastDoublePropertyAsBitsAtPut(FieldIndex index,
void JSObject::FastPropertyAtPut(FieldIndex index, Object value) {
if (IsUnboxedDoubleField(index)) {
- DCHECK(value.IsMutableHeapNumber());
+ DCHECK(value.IsHeapNumber());
// Ensure that all bits of the double value are preserved.
- RawFastDoublePropertyAsBitsAtPut(
- index, MutableHeapNumber::cast(value).value_as_bits());
+ RawFastDoublePropertyAsBitsAtPut(index,
+ HeapNumber::cast(value).value_as_bits());
} else {
RawFastPropertyAtPut(index, value);
}
@@ -401,7 +398,7 @@ void JSObject::WriteToField(int descriptor, PropertyDetails details,
if (IsUnboxedDoubleField(index)) {
RawFastDoublePropertyAsBitsAtPut(index, bits);
} else {
- auto box = MutableHeapNumber::cast(RawFastPropertyAt(index));
+ auto box = HeapNumber::cast(RawFastPropertyAt(index));
box.set_value_as_bits(bits);
}
} else {
@@ -450,11 +447,6 @@ void JSObject::InitializeBody(Map map, int start_offset,
}
}
-ACCESSORS(JSBoundFunction, bound_target_function, JSReceiver,
- kBoundTargetFunctionOffset)
-ACCESSORS(JSBoundFunction, bound_this, Object, kBoundThisOffset)
-ACCESSORS(JSBoundFunction, bound_arguments, FixedArray, kBoundArgumentsOffset)
-
ACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell, kFeedbackCellOffset)
ACCESSORS(JSGlobalObject, native_context, NativeContext, kNativeContextOffset)
@@ -712,16 +704,6 @@ void JSFunction::ResetIfBytecodeFlushed() {
}
}
-ACCESSORS(JSDate, value, Object, kValueOffset)
-ACCESSORS(JSDate, cache_stamp, Object, kCacheStampOffset)
-ACCESSORS(JSDate, year, Object, kYearOffset)
-ACCESSORS(JSDate, month, Object, kMonthOffset)
-ACCESSORS(JSDate, day, Object, kDayOffset)
-ACCESSORS(JSDate, weekday, Object, kWeekdayOffset)
-ACCESSORS(JSDate, hour, Object, kHourOffset)
-ACCESSORS(JSDate, min, Object, kMinOffset)
-ACCESSORS(JSDate, sec, Object, kSecOffset)
-
bool JSMessageObject::DidEnsureSourcePositionsAvailable() const {
return shared_info().IsUndefined();
}
@@ -774,7 +756,8 @@ DEF_GETTER(JSObject, GetElementsKind, ElementsKind) {
DCHECK(fixed_array.IsFixedArray(isolate));
DCHECK(fixed_array.IsNumberDictionary(isolate));
} else {
- DCHECK(kind > DICTIONARY_ELEMENTS || IsFrozenOrSealedElementsKind(kind));
+ DCHECK(kind > DICTIONARY_ELEMENTS ||
+ IsAnyNonextensibleElementsKind(kind));
}
DCHECK(
!IsSloppyArgumentsElementsKind(kind) ||
@@ -824,14 +807,18 @@ DEF_GETTER(JSObject, HasPackedElements, bool) {
return GetElementsKind(isolate) == PACKED_ELEMENTS;
}
-DEF_GETTER(JSObject, HasFrozenOrSealedElements, bool) {
- return IsFrozenOrSealedElementsKind(GetElementsKind(isolate));
+DEF_GETTER(JSObject, HasAnyNonextensibleElements, bool) {
+ return IsAnyNonextensibleElementsKind(GetElementsKind(isolate));
}
DEF_GETTER(JSObject, HasSealedElements, bool) {
return IsSealedElementsKind(GetElementsKind(isolate));
}
+DEF_GETTER(JSObject, HasNonextensibleElements, bool) {
+ return IsNonextensibleElementsKind(GetElementsKind(isolate));
+}
+
DEF_GETTER(JSObject, HasFastArgumentsElements, bool) {
return GetElementsKind(isolate) == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
}
@@ -1020,10 +1007,6 @@ inline int JSGlobalProxy::SizeWithEmbedderFields(int embedder_field_count) {
ACCESSORS(JSIteratorResult, value, Object, kValueOffset)
ACCESSORS(JSIteratorResult, done, Object, kDoneOffset)
-ACCESSORS(JSAsyncFromSyncIterator, sync_iterator, JSReceiver,
- kSyncIteratorOffset)
-ACCESSORS(JSAsyncFromSyncIterator, next, Object, kNextOffset)
-
ACCESSORS(JSStringIterator, string, String, kStringOffset)
SMI_ACCESSORS(JSStringIterator, index, kNextIndexOffset)
diff --git a/deps/v8/src/objects/js-objects.cc b/deps/v8/src/objects/js-objects.cc
index 5c4db16206..3666f5afbe 100644
--- a/deps/v8/src/objects/js-objects.cc
+++ b/deps/v8/src/objects/js-objects.cc
@@ -1509,20 +1509,27 @@ namespace {
Maybe<bool> GetPropertyDescriptorWithInterceptor(LookupIterator* it,
PropertyDescriptor* desc) {
+ Handle<InterceptorInfo> interceptor;
+
if (it->state() == LookupIterator::ACCESS_CHECK) {
if (it->HasAccess()) {
it->Next();
- } else if (!JSObject::AllCanRead(it) ||
- it->state() != LookupIterator::INTERCEPTOR) {
- it->Restart();
- return Just(false);
+ } else {
+ interceptor = it->GetInterceptorForFailedAccessCheck();
+ if (interceptor.is_null() &&
+ (!JSObject::AllCanRead(it) ||
+ it->state() != LookupIterator::INTERCEPTOR)) {
+ it->Restart();
+ return Just(false);
+ }
}
}
- if (it->state() != LookupIterator::INTERCEPTOR) return Just(false);
-
+ if (it->state() == LookupIterator::INTERCEPTOR) {
+ interceptor = it->GetInterceptor();
+ }
+ if (interceptor.is_null()) return Just(false);
Isolate* isolate = it->isolate();
- Handle<InterceptorInfo> interceptor = it->GetInterceptor();
if (interceptor->descriptor().IsUndefined(isolate)) return Just(false);
Handle<Object> result;
@@ -1607,12 +1614,14 @@ Maybe<bool> JSReceiver::GetOwnPropertyDescriptor(LookupIterator* it,
// 6. Else X is an accessor property, so
Handle<AccessorPair> accessors =
Handle<AccessorPair>::cast(it->GetAccessors());
+ Handle<NativeContext> native_context =
+ it->GetHolder<JSReceiver>()->GetCreationContext();
// 6a. Set D.[[Get]] to the value of X's [[Get]] attribute.
- desc->set_get(
- AccessorPair::GetComponent(isolate, accessors, ACCESSOR_GETTER));
+ desc->set_get(AccessorPair::GetComponent(isolate, native_context, accessors,
+ ACCESSOR_GETTER));
// 6b. Set D.[[Set]] to the value of X's [[Set]] attribute.
- desc->set_set(
- AccessorPair::GetComponent(isolate, accessors, ACCESSOR_SETTER));
+ desc->set_set(AccessorPair::GetComponent(isolate, native_context, accessors,
+ ACCESSOR_SETTER));
}
// 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
@@ -2039,7 +2048,7 @@ MaybeHandle<JSObject> JSObject::ObjectCreate(Isolate* isolate,
void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
DCHECK(object->HasSmiOrObjectElements() ||
object->HasFastStringWrapperElements() ||
- object->HasFrozenOrSealedElements());
+ object->HasAnyNonextensibleElements());
FixedArray raw_elems = FixedArray::cast(object->elements());
Isolate* isolate = object->GetIsolate();
if (raw_elems.map() != ReadOnlyRoots(isolate).fixed_cow_array_map()) return;
@@ -2622,12 +2631,12 @@ void MigrateFastToFast(Isolate* isolate, Handle<JSObject> object,
FieldIndex::ForDescriptor(isolate, *new_map, new_map->LastAdded());
if (index.is_inobject() || index.outobject_array_index() <
object->property_array(isolate).length()) {
- // We still need to allocate MutableHeapNumbers for double fields
+ // We still need to allocate HeapNumbers for double fields
// if either double field unboxing is disabled or the double field
// is in the PropertyArray backing store (where we don't support
// double field unboxing).
if (index.is_double() && !new_map->IsUnboxedDoubleField(isolate, index)) {
- auto value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
+ auto value = isolate->factory()->NewHeapNumberWithHoleNaN();
object->RawFastPropertyAtPut(index, *value);
}
object->synchronized_set_map(*new_map);
@@ -2644,7 +2653,7 @@ void MigrateFastToFast(Isolate* isolate, Handle<JSObject> object,
// Properly initialize newly added property.
Handle<Object> value;
if (details.representation().IsDouble()) {
- value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
+ value = isolate->factory()->NewHeapNumberWithHoleNaN();
} else {
value = isolate->factory()->uninitialized_value();
}
@@ -2708,7 +2717,7 @@ void MigrateFastToFast(Isolate* isolate, Handle<JSObject> object,
// must already be prepared for data of certain type.
DCHECK(!details.representation().IsNone());
if (details.representation().IsDouble()) {
- value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
+ value = isolate->factory()->NewHeapNumberWithHoleNaN();
} else {
value = isolate->factory()->uninitialized_value();
}
@@ -2722,11 +2731,7 @@ void MigrateFastToFast(Isolate* isolate, Handle<JSObject> object,
FieldIndex index = FieldIndex::ForDescriptor(isolate, *old_map, i);
if (object->IsUnboxedDoubleField(isolate, index)) {
uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index);
- if (representation.IsDouble()) {
- value = isolate->factory()->NewMutableHeapNumberFromBits(old_bits);
- } else {
- value = isolate->factory()->NewHeapNumberFromBits(old_bits);
- }
+ value = isolate->factory()->NewHeapNumberFromBits(old_bits);
} else {
value = handle(object->RawFastPropertyAt(isolate, index), isolate);
if (!old_representation.IsDouble() && representation.IsDouble()) {
@@ -2754,7 +2759,7 @@ void MigrateFastToFast(Isolate* isolate, Handle<JSObject> object,
DCHECK_EQ(kData, details.kind());
Handle<Object> value;
if (details.representation().IsDouble()) {
- value = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
+ value = isolate->factory()->NewHeapNumberWithHoleNaN();
} else {
value = isolate->factory()->uninitialized_value();
}
@@ -2784,10 +2789,10 @@ void MigrateFastToFast(Isolate* isolate, Handle<JSObject> object,
// Can't use JSObject::FastPropertyAtPut() because proper map was not set
// yet.
if (new_map->IsUnboxedDoubleField(isolate, index)) {
- DCHECK(value.IsMutableHeapNumber(isolate));
+ DCHECK(value.IsHeapNumber(isolate));
// Ensure that all bits of the double value are preserved.
object->RawFastDoublePropertyAsBitsAtPut(
- index, MutableHeapNumber::cast(value).value_as_bits());
+ index, HeapNumber::cast(value).value_as_bits());
if (i < old_number_of_fields && !old_map->IsUnboxedDoubleField(index)) {
// Transition from tagged to untagged slot.
heap->ClearRecordedSlot(*object, object->RawField(index.offset()));
@@ -2859,8 +2864,8 @@ void MigrateFastToSlow(Isolate* isolate, Handle<JSObject> object,
} else {
value = handle(object->RawFastPropertyAt(isolate, index), isolate);
if (details.representation().IsDouble()) {
- DCHECK(value->IsMutableHeapNumber(isolate));
- double old_value = Handle<MutableHeapNumber>::cast(value)->value();
+ DCHECK(value->IsHeapNumber(isolate));
+ double old_value = Handle<HeapNumber>::cast(value)->value();
value = isolate->factory()->NewHeapNumber(old_value);
}
}
@@ -3048,7 +3053,7 @@ void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
if (!representation.IsDouble()) continue;
FieldIndex index = FieldIndex::ForDescriptor(*map, i);
if (map->IsUnboxedDoubleField(index)) continue;
- auto box = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
+ auto box = isolate->factory()->NewHeapNumberWithHoleNaN();
if (index.is_inobject()) {
storage->set(index.property_index(), *box);
} else {
@@ -3464,7 +3469,8 @@ Handle<NumberDictionary> JSObject::NormalizeElements(Handle<JSObject> object) {
DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements() ||
object->HasFastArgumentsElements() ||
- object->HasFastStringWrapperElements() || object->HasSealedElements());
+ object->HasFastStringWrapperElements() ||
+ object->HasSealedElements() || object->HasNonextensibleElements());
Handle<NumberDictionary> dictionary =
object->GetElementsAccessor()->Normalize(object);
@@ -3637,6 +3643,7 @@ bool TestElementsIntegrityLevel(JSObject object, PropertyAttributes level) {
}
if (IsFrozenElementsKind(kind)) return true;
if (IsSealedElementsKind(kind) && level != FROZEN) return true;
+ if (IsNonextensibleElementsKind(kind) && level == NONE) return true;
ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
// Only DICTIONARY_ELEMENTS and SLOW_SLOPPY_ARGUMENTS_ELEMENTS have
@@ -3795,9 +3802,9 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
if (attrs == NONE && !object->map().is_extensible()) return Just(true);
{
ElementsKind old_elements_kind = object->map().elements_kind();
+ if (IsFrozenElementsKind(old_elements_kind)) return Just(true);
if (attrs != FROZEN && IsSealedElementsKind(old_elements_kind))
return Just(true);
- if (old_elements_kind == PACKED_FROZEN_ELEMENTS) return Just(true);
}
if (object->IsJSGlobalProxy()) {
@@ -3842,8 +3849,7 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
// elements kind change in one go. If seal or freeze with Smi or Double
// elements kind, we will transition to Object elements kind first to make
// sure of valid element access.
- if (FLAG_enable_sealed_frozen_elements_kind &&
- (attrs == SEALED || attrs == FROZEN)) {
+ if (FLAG_enable_sealed_frozen_elements_kind) {
switch (object->map().elements_kind()) {
case PACKED_SMI_ELEMENTS:
case PACKED_DOUBLE_ELEMENTS:
@@ -3871,9 +3877,9 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
DCHECK(transition_map->has_dictionary_elements() ||
transition_map->has_typed_array_elements() ||
transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS ||
- transition_map->has_frozen_or_sealed_elements());
+ transition_map->has_any_nonextensible_elements());
DCHECK(!transition_map->is_extensible());
- if (!transition_map->has_frozen_or_sealed_elements()) {
+ if (!transition_map->has_any_nonextensible_elements()) {
new_element_dictionary = CreateElementDictionary(isolate, object);
}
JSObject::MigrateToMap(isolate, object, transition_map);
@@ -3881,7 +3887,7 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
// Create a new descriptor array with the appropriate property attributes
Handle<Map> new_map = Map::CopyForPreventExtensions(
isolate, old_map, attrs, transition_marker, "CopyForPreventExtensions");
- if (!new_map->has_frozen_or_sealed_elements()) {
+ if (!new_map->has_any_nonextensible_elements()) {
new_element_dictionary = CreateElementDictionary(isolate, object);
}
JSObject::MigrateToMap(isolate, object, new_map);
@@ -3922,7 +3928,7 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
}
}
- if (object->map().has_frozen_or_sealed_elements()) {
+ if (object->map().has_any_nonextensible_elements()) {
DCHECK(new_element_dictionary.is_null());
return Just(true);
}
@@ -3980,6 +3986,7 @@ bool JSObject::HasEnumerableElements() {
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case PACKED_DOUBLE_ELEMENTS: {
int length = object.IsJSArray()
? Smi::ToInt(JSArray::cast(object).length())
@@ -3989,6 +3996,7 @@ bool JSObject::HasEnumerableElements() {
case HOLEY_SMI_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case HOLEY_ELEMENTS: {
FixedArray elements = FixedArray::cast(object.elements());
int length = object.IsJSArray()
@@ -4146,7 +4154,7 @@ Object JSObject::SlowReverseLookup(Object value) {
} else {
Object property = RawFastPropertyAt(field_index);
if (field_index.is_double()) {
- DCHECK(property.IsMutableHeapNumber());
+ DCHECK(property.IsHeapNumber());
if (value_is_number && property.Number() == value.Number()) {
return descs.GetKey(i);
}
@@ -4691,8 +4699,9 @@ void JSObject::TransitionElementsKind(Handle<JSObject> object,
if (from_kind == to_kind) return;
// This method should never be called for any other case.
- DCHECK(IsFastElementsKind(from_kind));
- DCHECK(IsFastElementsKind(to_kind));
+ DCHECK(IsFastElementsKind(from_kind) ||
+ IsNonextensibleElementsKind(from_kind));
+ DCHECK(IsFastElementsKind(to_kind) || IsNonextensibleElementsKind(to_kind));
DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
UpdateAllocationSite(object, to_kind);
@@ -4735,6 +4744,7 @@ int JSObject::GetFastElementsUsage() {
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
return IsJSArray() ? Smi::ToInt(JSArray::cast(*this).length())
: store.length();
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
@@ -4744,6 +4754,7 @@ int JSObject::GetFastElementsUsage() {
case HOLEY_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
return HoleyElementsUsage(*this, FixedArray::cast(store));
case HOLEY_DOUBLE_ELEMENTS:
@@ -4801,6 +4812,8 @@ bool JSObject::IsApiWrapper() {
return instance_type == JS_API_OBJECT_TYPE ||
instance_type == JS_ARRAY_BUFFER_TYPE ||
instance_type == JS_DATA_VIEW_TYPE ||
+ instance_type == JS_GLOBAL_OBJECT_TYPE ||
+ instance_type == JS_GLOBAL_PROXY_TYPE ||
instance_type == JS_SPECIAL_API_OBJECT_TYPE ||
instance_type == JS_TYPED_ARRAY_TYPE;
}
@@ -4987,13 +5000,9 @@ void JSFunction::InitializeFeedbackCell(Handle<JSFunction> function) {
Isolate* const isolate = function->GetIsolate();
if (function->has_feedback_vector()) {
- // TODO(984344): Make this a CHECK that feedback vectors are identical to
- // what we expect once we have removed all bytecode generation differences
- // between eager and lazy compilation. For now just reset if they aren't
- // identical
- FeedbackVector vector = function->feedback_vector();
- if (vector.length() == vector.metadata().slot_count()) return;
- function->raw_feedback_cell().reset();
+ CHECK_EQ(function->feedback_vector().length(),
+ function->feedback_vector().metadata().slot_count());
+ return;
}
bool needs_feedback_vector = !FLAG_lazy_feedback_allocation;
@@ -5241,7 +5250,6 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
case JS_GLOBAL_PROXY_TYPE:
case JS_PROXY_TYPE:
case MAP_TYPE:
- case MUTABLE_HEAP_NUMBER_TYPE:
case ODDBALL_TYPE:
case PROPERTY_CELL_TYPE:
case SHARED_FUNCTION_INFO_TYPE:
diff --git a/deps/v8/src/objects/js-objects.h b/deps/v8/src/objects/js-objects.h
index bcea3a28df..a9510642f1 100644
--- a/deps/v8/src/objects/js-objects.h
+++ b/deps/v8/src/objects/js-objects.h
@@ -323,8 +323,9 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
// Returns true if an object has elements of PACKED_ELEMENTS
DECL_GETTER(HasPackedElements, bool)
- DECL_GETTER(HasFrozenOrSealedElements, bool)
+ DECL_GETTER(HasAnyNonextensibleElements, bool)
DECL_GETTER(HasSealedElements, bool)
+ DECL_GETTER(HasNonextensibleElements, bool)
DECL_GETTER(HasTypedArrayElements, bool)
@@ -893,19 +894,9 @@ class JSIteratorResult : public JSObject {
};
// JSBoundFunction describes a bound function exotic object.
-class JSBoundFunction : public JSObject {
+class JSBoundFunction
+ : public TorqueGeneratedJSBoundFunction<JSBoundFunction, JSObject> {
public:
- // [bound_target_function]: The wrapped function object.
- DECL_ACCESSORS(bound_target_function, JSReceiver)
-
- // [bound_this]: The value that is always passed as the this value when
- // calling the wrapped function.
- DECL_ACCESSORS(bound_this, Object)
-
- // [bound_arguments]: A list of values whose elements are used as the first
- // arguments to any call to the wrapped function.
- DECL_ACCESSORS(bound_arguments, FixedArray)
-
static MaybeHandle<String> GetName(Isolate* isolate,
Handle<JSBoundFunction> function);
static Maybe<int> GetLength(Isolate* isolate,
@@ -913,8 +904,6 @@ class JSBoundFunction : public JSObject {
static MaybeHandle<NativeContext> GetFunctionRealm(
Handle<JSBoundFunction> function);
- DECL_CAST(JSBoundFunction)
-
// Dispatched behavior.
DECL_PRINTER(JSBoundFunction)
DECL_VERIFIER(JSBoundFunction)
@@ -923,11 +912,7 @@ class JSBoundFunction : public JSObject {
// to ES6 section 19.2.3.5 Function.prototype.toString ( ).
static Handle<String> ToString(Handle<JSBoundFunction> function);
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
- TORQUE_GENERATED_JSBOUND_FUNCTION_FIELDS)
-
- OBJECT_CONSTRUCTORS(JSBoundFunction, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSBoundFunction)
};
// JSFunction describes JavaScript functions.
@@ -1213,34 +1198,11 @@ class JSPrimitiveWrapper
class DateCache;
// Representation for JS date objects.
-class JSDate : public JSObject {
+class JSDate : public TorqueGeneratedJSDate<JSDate, JSObject> {
public:
static V8_WARN_UNUSED_RESULT MaybeHandle<JSDate> New(
Handle<JSFunction> constructor, Handle<JSReceiver> new_target, double tv);
- // If one component is NaN, all of them are, indicating a NaN time value.
- // [value]: the time value.
- DECL_ACCESSORS(value, Object)
- // [year]: caches year. Either undefined, smi, or NaN.
- DECL_ACCESSORS(year, Object)
- // [month]: caches month. Either undefined, smi, or NaN.
- DECL_ACCESSORS(month, Object)
- // [day]: caches day. Either undefined, smi, or NaN.
- DECL_ACCESSORS(day, Object)
- // [weekday]: caches day of week. Either undefined, smi, or NaN.
- DECL_ACCESSORS(weekday, Object)
- // [hour]: caches hours. Either undefined, smi, or NaN.
- DECL_ACCESSORS(hour, Object)
- // [min]: caches minutes. Either undefined, smi, or NaN.
- DECL_ACCESSORS(min, Object)
- // [sec]: caches seconds. Either undefined, smi, or NaN.
- DECL_ACCESSORS(sec, Object)
- // [cache stamp]: sample of the date cache stamp at the
- // moment when chached fields were cached.
- DECL_ACCESSORS(cache_stamp, Object)
-
- DECL_CAST(JSDate)
-
// Returns the time value (UTC) identifying the current time.
static double CurrentTimeValue(Isolate* isolate);
@@ -1290,9 +1252,6 @@ class JSDate : public JSObject {
kTimezoneOffset
};
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
- TORQUE_GENERATED_JSDATE_FIELDS)
-
private:
inline Object DoGetField(FieldIndex index);
@@ -1301,7 +1260,7 @@ class JSDate : public JSObject {
// Computes and caches the cacheable fields of the date.
inline void SetCachedFields(int64_t local_time_ms, DateCache* date_cache);
- OBJECT_CONSTRUCTORS(JSDate, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSDate)
};
// Representation of message objects used for error reporting through
@@ -1396,27 +1355,19 @@ class JSMessageObject : public JSObject {
// An object which wraps an ordinary Iterator and converts it to behave
// according to the Async Iterator protocol.
// (See https://tc39.github.io/proposal-async-iteration/#sec-iteration)
-class JSAsyncFromSyncIterator : public JSObject {
+class JSAsyncFromSyncIterator
+ : public TorqueGeneratedJSAsyncFromSyncIterator<JSAsyncFromSyncIterator,
+ JSObject> {
public:
- DECL_CAST(JSAsyncFromSyncIterator)
DECL_PRINTER(JSAsyncFromSyncIterator)
- DECL_VERIFIER(JSAsyncFromSyncIterator)
// Async-from-Sync Iterator instances are ordinary objects that inherit
// properties from the %AsyncFromSyncIteratorPrototype% intrinsic object.
// Async-from-Sync Iterator instances are initially created with the internal
// slots listed in Table 4.
// (proposal-async-iteration/#table-async-from-sync-iterator-internal-slots)
- DECL_ACCESSORS(sync_iterator, JSReceiver)
-
- // The "next" method is loaded during GetIterator, and is not reloaded for
- // subsequent "next" invocations.
- DECL_ACCESSORS(next, Object)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(
- JSObject::kHeaderSize, TORQUE_GENERATED_JSASYNC_FROM_SYNC_ITERATOR_FIELDS)
- OBJECT_CONSTRUCTORS(JSAsyncFromSyncIterator, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSAsyncFromSyncIterator)
};
class JSStringIterator : public JSObject {
diff --git a/deps/v8/src/objects/js-promise-inl.h b/deps/v8/src/objects/js-promise-inl.h
index ecfeb53306..8b7a11a151 100644
--- a/deps/v8/src/objects/js-promise-inl.h
+++ b/deps/v8/src/objects/js-promise-inl.h
@@ -16,11 +16,9 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(JSPromise, JSObject)
-CAST_ACCESSOR(JSPromise)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSPromise)
-ACCESSORS(JSPromise, reactions_or_result, Object, kReactionsOrResultOffset)
-SMI_ACCESSORS(JSPromise, flags, kFlagsOffset)
+TQ_SMI_ACCESSORS(JSPromise, flags)
BOOL_ACCESSORS(JSPromise, flags, has_handler, kHasHandlerBit)
BOOL_ACCESSORS(JSPromise, flags, handled_hint, kHandledHintBit)
diff --git a/deps/v8/src/objects/js-promise.h b/deps/v8/src/objects/js-promise.h
index bbe6f724d1..06569a3fcd 100644
--- a/deps/v8/src/objects/js-promise.h
+++ b/deps/v8/src/objects/js-promise.h
@@ -24,12 +24,8 @@ namespace internal {
// We also overlay the result and reactions fields on the JSPromise, since
// the reactions are only necessary for pending promises, whereas the result
// is only meaningful for settled promises.
-class JSPromise : public JSObject {
+class JSPromise : public TorqueGeneratedJSPromise<JSPromise, JSObject> {
public:
- // [reactions_or_result]: Smi 0 terminated list of PromiseReaction objects
- // in case the JSPromise was not settled yet, otherwise the result.
- DECL_ACCESSORS(reactions_or_result, Object)
-
// [result]: Checks that the promise is settled and returns the result.
inline Object result() const;
@@ -62,15 +58,10 @@ class JSPromise : public JSObject {
V8_WARN_UNUSED_RESULT static MaybeHandle<Object> Resolve(
Handle<JSPromise> promise, Handle<Object> resolution);
- DECL_CAST(JSPromise)
-
// Dispatched behavior.
DECL_PRINTER(JSPromise)
DECL_VERIFIER(JSPromise)
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
- TORQUE_GENERATED_JSPROMISE_FIELDS)
-
static const int kSizeWithEmbedderFields =
kSize + v8::Promise::kEmbedderFieldCount * kEmbedderDataSlotSize;
@@ -79,7 +70,7 @@ class JSPromise : public JSObject {
static const int kStatusBits = 2;
static const int kHasHandlerBit = 2;
static const int kHandledHintBit = 3;
- class AsyncTaskIdField : public BitField<int, kHandledHintBit + 1, 22> {};
+ using AsyncTaskIdField = BitField<int, kHandledHintBit + 1, 22>;
static const int kStatusShift = 0;
static const int kStatusMask = 0x3;
@@ -94,7 +85,7 @@ class JSPromise : public JSObject {
Handle<Object> argument,
PromiseReaction::Type type);
- OBJECT_CONSTRUCTORS(JSPromise, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSPromise)
};
} // namespace internal
diff --git a/deps/v8/src/objects/js-regexp-inl.h b/deps/v8/src/objects/js-regexp-inl.h
index 93e6ee008d..b69d1cca97 100644
--- a/deps/v8/src/objects/js-regexp-inl.h
+++ b/deps/v8/src/objects/js-regexp-inl.h
@@ -17,13 +17,8 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(JSRegExp, JSObject)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSRegExp)
-CAST_ACCESSOR(JSRegExp)
-
-ACCESSORS(JSRegExp, data, Object, kDataOffset)
-ACCESSORS(JSRegExp, flags, Object, kFlagsOffset)
-ACCESSORS(JSRegExp, source, Object, kSourceOffset)
ACCESSORS(JSRegExp, last_index, Object, kLastIndexOffset)
JSRegExp::Type JSRegExp::TypeTag() const {
@@ -80,23 +75,28 @@ void JSRegExp::SetDataAt(int index, Object value) {
bool JSRegExp::HasCompiledCode() const {
if (TypeTag() != IRREGEXP) return false;
+ Smi uninitialized = Smi::FromInt(kUninitializedValue);
#ifdef DEBUG
DCHECK(DataAt(kIrregexpLatin1CodeIndex).IsCode() ||
- DataAt(kIrregexpLatin1CodeIndex).IsByteArray() ||
- DataAt(kIrregexpLatin1CodeIndex) == Smi::FromInt(kUninitializedValue));
+ DataAt(kIrregexpLatin1CodeIndex) == uninitialized);
DCHECK(DataAt(kIrregexpUC16CodeIndex).IsCode() ||
- DataAt(kIrregexpUC16CodeIndex).IsByteArray() ||
- DataAt(kIrregexpUC16CodeIndex) == Smi::FromInt(kUninitializedValue));
+ DataAt(kIrregexpUC16CodeIndex) == uninitialized);
+ DCHECK(DataAt(kIrregexpLatin1BytecodeIndex).IsByteArray() ||
+ DataAt(kIrregexpLatin1BytecodeIndex) == uninitialized);
+ DCHECK(DataAt(kIrregexpUC16BytecodeIndex).IsByteArray() ||
+ DataAt(kIrregexpUC16BytecodeIndex) == uninitialized);
#endif // DEBUG
- Smi uninitialized = Smi::FromInt(kUninitializedValue);
return (DataAt(kIrregexpLatin1CodeIndex) != uninitialized ||
DataAt(kIrregexpUC16CodeIndex) != uninitialized);
}
void JSRegExp::DiscardCompiledCodeForSerialization() {
DCHECK(HasCompiledCode());
- SetDataAt(kIrregexpLatin1CodeIndex, Smi::FromInt(kUninitializedValue));
- SetDataAt(kIrregexpUC16CodeIndex, Smi::FromInt(kUninitializedValue));
+ Smi uninitialized = Smi::FromInt(kUninitializedValue);
+ SetDataAt(kIrregexpLatin1CodeIndex, uninitialized);
+ SetDataAt(kIrregexpUC16CodeIndex, uninitialized);
+ SetDataAt(kIrregexpLatin1BytecodeIndex, uninitialized);
+ SetDataAt(kIrregexpUC16BytecodeIndex, uninitialized);
}
} // namespace internal
diff --git a/deps/v8/src/objects/js-regexp-string-iterator-inl.h b/deps/v8/src/objects/js-regexp-string-iterator-inl.h
index 08e2f99d7e..b204619058 100644
--- a/deps/v8/src/objects/js-regexp-string-iterator-inl.h
+++ b/deps/v8/src/objects/js-regexp-string-iterator-inl.h
@@ -15,20 +15,13 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(JSRegExpStringIterator, JSObject)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSRegExpStringIterator)
-ACCESSORS(JSRegExpStringIterator, iterating_regexp, Object,
- kIteratingRegExpOffset)
-ACCESSORS(JSRegExpStringIterator, iterating_string, String,
- kIteratedStringOffset)
-
-SMI_ACCESSORS(JSRegExpStringIterator, flags, kFlagsOffset)
+TQ_SMI_ACCESSORS(JSRegExpStringIterator, flags)
BOOL_ACCESSORS(JSRegExpStringIterator, flags, done, kDoneBit)
BOOL_ACCESSORS(JSRegExpStringIterator, flags, global, kGlobalBit)
BOOL_ACCESSORS(JSRegExpStringIterator, flags, unicode, kUnicodeBit)
-CAST_ACCESSOR(JSRegExpStringIterator)
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/js-regexp-string-iterator.h b/deps/v8/src/objects/js-regexp-string-iterator.h
index 871b724966..ffd38fe211 100644
--- a/deps/v8/src/objects/js-regexp-string-iterator.h
+++ b/deps/v8/src/objects/js-regexp-string-iterator.h
@@ -13,14 +13,10 @@
namespace v8 {
namespace internal {
-class JSRegExpStringIterator : public JSObject {
+class JSRegExpStringIterator
+ : public TorqueGeneratedJSRegExpStringIterator<JSRegExpStringIterator,
+ JSObject> {
public:
- // [regexp]: the [[IteratingRegExp]] internal property.
- DECL_ACCESSORS(iterating_regexp, Object)
-
- // [string]: The [[IteratedString]] internal property.
- DECL_ACCESSORS(iterating_string, String)
-
DECL_INT_ACCESSORS(flags)
// [boolean]: The [[Done]] internal property.
@@ -32,20 +28,13 @@ class JSRegExpStringIterator : public JSObject {
// [boolean]: The [[Unicode]] internal property.
DECL_BOOLEAN_ACCESSORS(unicode)
- DECL_CAST(JSRegExpStringIterator)
DECL_PRINTER(JSRegExpStringIterator)
- DECL_VERIFIER(JSRegExpStringIterator)
-
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(
- JSObject::kHeaderSize,
- TORQUE_GENERATED_JSREG_EXP_STRING_ITERATOR_FIELDS)
static const int kDoneBit = 0;
static const int kGlobalBit = 1;
static const int kUnicodeBit = 2;
- OBJECT_CONSTRUCTORS(JSRegExpStringIterator, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSRegExpStringIterator)
};
} // namespace internal
diff --git a/deps/v8/src/objects/js-regexp.h b/deps/v8/src/objects/js-regexp.h
index 18355079f8..b3ef06bd5c 100644
--- a/deps/v8/src/objects/js-regexp.h
+++ b/deps/v8/src/objects/js-regexp.h
@@ -29,7 +29,7 @@ namespace internal {
// used for tracking the last usage (used for regexp code flushing).
// - max number of registers used by irregexp implementations.
// - number of capture registers (output values) of the regexp.
-class JSRegExp : public JSObject {
+class JSRegExp : public TorqueGeneratedJSRegExp<JSRegExp, JSObject> {
public:
// Meaning of Type:
// NOT_COMPILED: Initial value. No data has been stored in the JSRegExp yet.
@@ -82,10 +82,7 @@ class JSRegExp : public JSObject {
STATIC_ASSERT(static_cast<int>(kDotAll) == v8::RegExp::kDotAll);
STATIC_ASSERT(kFlagCount == v8::RegExp::kFlagCount);
- DECL_ACCESSORS(data, Object)
- DECL_ACCESSORS(flags, Object)
DECL_ACCESSORS(last_index, Object)
- DECL_ACCESSORS(source, Object)
V8_EXPORT_PRIVATE static MaybeHandle<JSRegExp> New(Isolate* isolate,
Handle<String> source,
@@ -98,7 +95,15 @@ class JSRegExp : public JSObject {
Handle<String> source,
Handle<String> flags_string);
+ bool MarkedForTierUp();
+ void ResetTierUp();
+ void MarkTierUpForNextExec();
+
inline Type TypeTag() const;
+
+ // Maximum number of captures allowed.
+ static constexpr int kMaxCaptures = 1 << 16;
+
// Number of captures (without the match itself).
inline int CaptureCount();
inline Flags GetFlags();
@@ -108,26 +113,27 @@ class JSRegExp : public JSObject {
// Set implementation data after the object has been prepared.
inline void SetDataAt(int index, Object value);
- static int code_index(bool is_latin1) {
- if (is_latin1) {
- return kIrregexpLatin1CodeIndex;
- } else {
- return kIrregexpUC16CodeIndex;
- }
+ static constexpr int code_index(bool is_latin1) {
+ return is_latin1 ? kIrregexpLatin1CodeIndex : kIrregexpUC16CodeIndex;
}
+ static constexpr int bytecode_index(bool is_latin1) {
+ return is_latin1 ? kIrregexpLatin1BytecodeIndex
+ : kIrregexpUC16BytecodeIndex;
+ }
+
+ // This could be a Smi kUninitializedValue or Code.
+ Object Code(bool is_latin1) const;
+ // This could be a Smi kUninitializedValue or ByteArray.
+ Object Bytecode(bool is_latin1) const;
+ bool ShouldProduceBytecode();
inline bool HasCompiledCode() const;
inline void DiscardCompiledCodeForSerialization();
- DECL_CAST(JSRegExp)
-
// Dispatched behavior.
DECL_PRINTER(JSRegExp)
DECL_VERIFIER(JSRegExp)
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
- TORQUE_GENERATED_JSREG_EXP_FIELDS)
/* This is already an in-object field. */
// TODO(v8:8944): improve handling of in-object fields
static constexpr int kLastIndexOffset = kSize;
@@ -144,24 +150,35 @@ class JSRegExp : public JSObject {
static const int kAtomDataSize = kAtomPatternIndex + 1;
- // Irregexp compiled code or bytecode for Latin1. If compilation
- // fails, this fields hold an exception object that should be
+ // Irregexp compiled code or trampoline to interpreter for Latin1. If
+ // compilation fails, this fields hold an exception object that should be
// thrown if the regexp is used again.
static const int kIrregexpLatin1CodeIndex = kDataIndex;
- // Irregexp compiled code or bytecode for UC16. If compilation
- // fails, this fields hold an exception object that should be
+ // Irregexp compiled code or trampoline to interpreter for UC16. If
+ // compilation fails, this fields hold an exception object that should be
// thrown if the regexp is used again.
static const int kIrregexpUC16CodeIndex = kDataIndex + 1;
+ // Bytecode to interpret the regexp for Latin1. Contains kUninitializedValue
+ // if we haven't compiled the regexp yet, regexp are always compiled or if
+ // tier-up has happened (i.e. when kIrregexpLatin1CodeIndex contains native
+ // irregexp code).
+ static const int kIrregexpLatin1BytecodeIndex = kDataIndex + 2;
+ // Bytecode to interpret the regexp for UC16. Contains kUninitializedValue if
+ // we haven't compiled the regxp yet, regexp are always compiled or if tier-up
+ // has happened (i.e. when kIrregexpUC16CodeIndex contains native irregexp
+ // code).
+ static const int kIrregexpUC16BytecodeIndex = kDataIndex + 3;
// Maximal number of registers used by either Latin1 or UC16.
// Only used to check that there is enough stack space
- static const int kIrregexpMaxRegisterCountIndex = kDataIndex + 2;
+ static const int kIrregexpMaxRegisterCountIndex = kDataIndex + 4;
// Number of captures in the compiled regexp.
- static const int kIrregexpCaptureCountIndex = kDataIndex + 3;
+ static const int kIrregexpCaptureCountIndex = kDataIndex + 5;
// Maps names of named capture groups (at indices 2i) to their corresponding
// (1-based) capture group indices (at indices 2i + 1).
- static const int kIrregexpCaptureNameMapIndex = kDataIndex + 4;
+ static const int kIrregexpCaptureNameMapIndex = kDataIndex + 6;
+ static const int kIrregexpTierUpTicksIndex = kDataIndex + 7;
- static const int kIrregexpDataSize = kIrregexpCaptureNameMapIndex + 1;
+ static const int kIrregexpDataSize = kIrregexpTierUpTicksIndex + 1;
// In-object fields.
static const int kLastIndexFieldIndex = 0;
@@ -178,7 +195,7 @@ class JSRegExp : public JSObject {
// The uninitialized value for a regexp code object.
static const int kUninitializedValue = -1;
- OBJECT_CONSTRUCTORS(JSRegExp, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSRegExp)
};
DEFINE_OPERATORS_FOR_FLAGS(JSRegExp::Flags)
diff --git a/deps/v8/src/objects/js-segment-iterator.cc b/deps/v8/src/objects/js-segment-iterator.cc
index 509db37d44..d893f3705f 100644
--- a/deps/v8/src/objects/js-segment-iterator.cc
+++ b/deps/v8/src/objects/js-segment-iterator.cc
@@ -207,7 +207,7 @@ Maybe<bool> JSSegmentIterator::Following(
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kParameterOfFunctionOutOfRange,
- factory->NewStringFromStaticChars("from"),
+ factory->from_string(),
factory->NewStringFromStaticChars("following"), index),
Nothing<bool>());
}
@@ -220,7 +220,7 @@ Maybe<bool> JSSegmentIterator::Following(
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kParameterOfFunctionOutOfRange,
- factory->NewStringFromStaticChars("from"),
+ factory->from_string(),
factory->NewStringFromStaticChars("following"),
from_obj),
Nothing<bool>());
@@ -260,7 +260,7 @@ Maybe<bool> JSSegmentIterator::Preceding(
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kParameterOfFunctionOutOfRange,
- factory->NewStringFromStaticChars("from"),
+ factory->from_string(),
factory->NewStringFromStaticChars("preceding"), index),
Nothing<bool>());
}
@@ -272,7 +272,7 @@ Maybe<bool> JSSegmentIterator::Preceding(
THROW_NEW_ERROR_RETURN_VALUE(
isolate,
NewRangeError(MessageTemplate::kParameterOfFunctionOutOfRange,
- factory->NewStringFromStaticChars("from"),
+ factory->from_string(),
factory->NewStringFromStaticChars("preceding"),
from_obj),
Nothing<bool>());
diff --git a/deps/v8/src/objects/js-weak-refs-inl.h b/deps/v8/src/objects/js-weak-refs-inl.h
index 46f28e883e..004ffd6d79 100644
--- a/deps/v8/src/objects/js-weak-refs-inl.h
+++ b/deps/v8/src/objects/js-weak-refs-inl.h
@@ -9,7 +9,6 @@
#include "src/api/api-inl.h"
#include "src/heap/heap-write-barrier-inl.h"
-#include "src/objects/microtask-inl.h"
#include "src/objects/smi-inl.h"
// Has to be the last include (doesn't have include guards):
@@ -22,7 +21,6 @@ OBJECT_CONSTRUCTORS_IMPL(WeakCell, HeapObject)
OBJECT_CONSTRUCTORS_IMPL(JSWeakRef, JSObject)
OBJECT_CONSTRUCTORS_IMPL(JSFinalizationGroup, JSObject)
OBJECT_CONSTRUCTORS_IMPL(JSFinalizationGroupCleanupIterator, JSObject)
-OBJECT_CONSTRUCTORS_IMPL(FinalizationGroupCleanupJobTask, Microtask)
ACCESSORS(JSFinalizationGroup, native_context, NativeContext,
kNativeContextOffset)
@@ -51,10 +49,6 @@ ACCESSORS(JSFinalizationGroupCleanupIterator, finalization_group,
JSFinalizationGroup, kFinalizationGroupOffset)
CAST_ACCESSOR(JSFinalizationGroupCleanupIterator)
-ACCESSORS(FinalizationGroupCleanupJobTask, finalization_group,
- JSFinalizationGroup, kFinalizationGroupOffset)
-CAST_ACCESSOR(FinalizationGroupCleanupJobTask)
-
void JSFinalizationGroup::Register(
Handle<JSFinalizationGroup> finalization_group, Handle<JSReceiver> target,
Handle<Object> holdings, Handle<Object> key, Isolate* isolate) {
diff --git a/deps/v8/src/objects/js-weak-refs.h b/deps/v8/src/objects/js-weak-refs.h
index 6a401fecee..723e0e3135 100644
--- a/deps/v8/src/objects/js-weak-refs.h
+++ b/deps/v8/src/objects/js-weak-refs.h
@@ -58,16 +58,18 @@ class JSFinalizationGroup : public JSObject {
// Constructs an iterator for the WeakCells in the cleared_cells list and
// calls the user's cleanup function.
- static void Cleanup(Isolate* isolate,
- Handle<JSFinalizationGroup> finalization_group,
- Handle<Object> callback);
+ //
+ // Returns Nothing<bool> if exception occurs, otherwise returns Just(true).
+ static V8_WARN_UNUSED_RESULT Maybe<bool> Cleanup(
+ Isolate* isolate, Handle<JSFinalizationGroup> finalization_group,
+ Handle<Object> callback);
// Layout description.
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
TORQUE_GENERATED_JSFINALIZATION_GROUP_FIELDS)
// Bitfields in flags.
- class ScheduledForCleanupField : public BitField<bool, 0, 1> {};
+ using ScheduledForCleanupField = BitField<bool, 0, 1>;
OBJECT_CONSTRUCTORS(JSFinalizationGroup, JSObject);
};
@@ -133,27 +135,6 @@ class JSWeakRef : public JSObject {
OBJECT_CONSTRUCTORS(JSWeakRef, JSObject);
};
-class FinalizationGroupCleanupJobTask : public Microtask {
- public:
- DECL_ACCESSORS(finalization_group, JSFinalizationGroup)
-
- DECL_CAST(FinalizationGroupCleanupJobTask)
- DECL_VERIFIER(FinalizationGroupCleanupJobTask)
- DECL_PRINTER(FinalizationGroupCleanupJobTask)
-
-// Layout description.
-#define FINALIZATION_GROUP_CLEANUP_JOB_TASK_FIELDS(V) \
- V(kFinalizationGroupOffset, kTaggedSize) \
- /* Total size. */ \
- V(kSize, 0)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(Microtask::kHeaderSize,
- FINALIZATION_GROUP_CLEANUP_JOB_TASK_FIELDS)
-#undef FINALIZATION_GROUP_CLEANUP_JOB_TASK_FIELDS
-
- OBJECT_CONSTRUCTORS(FinalizationGroupCleanupJobTask, Microtask);
-};
-
class JSFinalizationGroupCleanupIterator : public JSObject {
public:
DECL_PRINTER(JSFinalizationGroupCleanupIterator)
diff --git a/deps/v8/src/objects/keys.cc b/deps/v8/src/objects/keys.cc
index 18b38ed744..7496399cad 100644
--- a/deps/v8/src/objects/keys.cc
+++ b/deps/v8/src/objects/keys.cc
@@ -22,6 +22,17 @@
namespace v8 {
namespace internal {
+#define RETURN_NOTHING_IF_NOT_SUCCESSFUL(call) \
+ do { \
+ if (!(call)) return Nothing<bool>(); \
+ } while (false)
+
+#define RETURN_FAILURE_IF_NOT_SUCCESSFUL(call) \
+ do { \
+ ExceptionStatus status_enum_result = (call); \
+ if (!status_enum_result) return status_enum_result; \
+ } while (false)
+
namespace {
static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
@@ -64,32 +75,39 @@ Handle<OrderedHashSet> KeyAccumulator::keys() {
return Handle<OrderedHashSet>::cast(keys_);
}
-void KeyAccumulator::AddKey(Object key, AddKeyConversion convert) {
- AddKey(handle(key, isolate_), convert);
+ExceptionStatus KeyAccumulator::AddKey(Object key, AddKeyConversion convert) {
+ return AddKey(handle(key, isolate_), convert);
}
-void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
+ExceptionStatus KeyAccumulator::AddKey(Handle<Object> key,
+ AddKeyConversion convert) {
if (filter_ == PRIVATE_NAMES_ONLY) {
- if (!key->IsSymbol()) return;
- if (!Symbol::cast(*key).is_private_name()) return;
+ if (!key->IsSymbol()) return ExceptionStatus::kSuccess;
+ if (!Symbol::cast(*key).is_private_name()) return ExceptionStatus::kSuccess;
} else if (key->IsSymbol()) {
- if (filter_ & SKIP_SYMBOLS) return;
-
- if (Symbol::cast(*key).is_private()) return;
+ if (filter_ & SKIP_SYMBOLS) return ExceptionStatus::kSuccess;
+ if (Symbol::cast(*key).is_private()) return ExceptionStatus::kSuccess;
} else if (filter_ & SKIP_STRINGS) {
- return;
+ return ExceptionStatus::kSuccess;
}
- if (IsShadowed(key)) return;
+ if (IsShadowed(key)) return ExceptionStatus::kSuccess;
if (keys_.is_null()) {
- keys_ = OrderedHashSet::Allocate(isolate_, 16);
+ keys_ = OrderedHashSet::Allocate(isolate_, 16).ToHandleChecked();
}
uint32_t index;
if (convert == CONVERT_TO_ARRAY_INDEX && key->IsString() &&
Handle<String>::cast(key)->AsArrayIndex(&index)) {
key = isolate_->factory()->NewNumberFromUint(index);
}
- Handle<OrderedHashSet> new_set = OrderedHashSet::Add(isolate(), keys(), key);
+ MaybeHandle<OrderedHashSet> new_set_candidate =
+ OrderedHashSet::Add(isolate(), keys(), key);
+ Handle<OrderedHashSet> new_set;
+ if (!new_set_candidate.ToHandle(&new_set)) {
+ THROW_NEW_ERROR_RETURN_VALUE(
+ isolate_, NewRangeError(MessageTemplate::kTooManyProperties),
+ ExceptionStatus::kException);
+ }
if (*new_set != *keys_) {
// The keys_ Set is converted directly to a FixedArray in GetKeys which can
// be left-trimmer. Hence the previous Set should not keep a pointer to the
@@ -97,22 +115,24 @@ void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
keys_->set(OrderedHashSet::NextTableIndex(), Smi::kZero);
keys_ = new_set;
}
+ return ExceptionStatus::kSuccess;
}
-void KeyAccumulator::AddKeys(Handle<FixedArray> array,
- AddKeyConversion convert) {
+ExceptionStatus KeyAccumulator::AddKeys(Handle<FixedArray> array,
+ AddKeyConversion convert) {
int add_length = array->length();
for (int i = 0; i < add_length; i++) {
Handle<Object> current(array->get(i), isolate_);
- AddKey(current, convert);
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(AddKey(current, convert));
}
+ return ExceptionStatus::kSuccess;
}
-void KeyAccumulator::AddKeys(Handle<JSObject> array_like,
- AddKeyConversion convert) {
+ExceptionStatus KeyAccumulator::AddKeys(Handle<JSObject> array_like,
+ AddKeyConversion convert) {
DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements());
ElementsAccessor* accessor = array_like->GetElementsAccessor();
- accessor->AddElementsToKeyAccumulator(array_like, this, convert);
+ return accessor->AddElementsToKeyAccumulator(array_like, this, convert);
}
MaybeHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator,
@@ -162,7 +182,8 @@ Maybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy,
return Just(true);
}
}
- AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(
+ AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT));
return Just(true);
}
@@ -488,12 +509,10 @@ namespace {
enum IndexedOrNamed { kIndexed, kNamed };
-void FilterForEnumerableProperties(Handle<JSReceiver> receiver,
- Handle<JSObject> object,
- Handle<InterceptorInfo> interceptor,
- KeyAccumulator* accumulator,
- Handle<JSObject> result,
- IndexedOrNamed type) {
+V8_WARN_UNUSED_RESULT ExceptionStatus FilterForEnumerableProperties(
+ Handle<JSReceiver> receiver, Handle<JSObject> object,
+ Handle<InterceptorInfo> interceptor, KeyAccumulator* accumulator,
+ Handle<JSObject> result, IndexedOrNamed type) {
DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements());
ElementsAccessor* accessor = result->GetElementsAccessor();
@@ -521,10 +540,12 @@ void FilterForEnumerableProperties(Handle<JSReceiver> receiver,
int32_t value;
CHECK(attributes->ToInt32(&value));
if ((value & DONT_ENUM) == 0) {
- accumulator->AddKey(element, DO_NOT_CONVERT);
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(
+ accumulator->AddKey(element, DO_NOT_CONVERT));
}
}
}
+ return ExceptionStatus::kSuccess;
}
// Returns |true| on success, |nothing| on exception.
@@ -551,11 +572,11 @@ Maybe<bool> CollectInterceptorKeysInternal(Handle<JSReceiver> receiver,
if ((accumulator->filter() & ONLY_ENUMERABLE) &&
!interceptor->query().IsUndefined(isolate)) {
- FilterForEnumerableProperties(receiver, object, interceptor, accumulator,
- result, type);
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(FilterForEnumerableProperties(
+ receiver, object, interceptor, accumulator, result, type));
} else {
- accumulator->AddKeys(
- result, type == kIndexed ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(accumulator->AddKeys(
+ result, type == kIndexed ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT));
}
return Just(true);
}
@@ -589,18 +610,17 @@ Maybe<bool> KeyAccumulator::CollectOwnElementIndices(
if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true);
ElementsAccessor* accessor = object->GetElementsAccessor();
- accessor->CollectElementIndices(object, this);
-
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(
+ accessor->CollectElementIndices(object, this));
return CollectInterceptorKeys(receiver, object, this, kIndexed);
}
namespace {
template <bool skip_symbols>
-int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
- KeyAccumulator* keys,
- Handle<DescriptorArray> descs,
- int start_index, int limit) {
+base::Optional<int> CollectOwnPropertyNamesInternal(
+ Handle<JSObject> object, KeyAccumulator* keys,
+ Handle<DescriptorArray> descs, int start_index, int limit) {
int first_skipped = -1;
PropertyFilter filter = keys->filter();
KeyCollectionMode mode = keys->mode();
@@ -633,7 +653,9 @@ int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
if (is_shadowing_key) {
keys->AddShadowingKey(key);
} else {
- keys->AddKey(key, DO_NOT_CONVERT);
+ if (keys->AddKey(key, DO_NOT_CONVERT) != ExceptionStatus::kSuccess) {
+ return base::Optional<int>();
+ }
}
}
return first_skipped;
@@ -696,48 +718,50 @@ Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver,
}
}
}
- AddKeys(enum_keys, DO_NOT_CONVERT);
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(AddKeys(enum_keys, DO_NOT_CONVERT));
} else {
if (object->HasFastProperties()) {
int limit = object->map().NumberOfOwnDescriptors();
Handle<DescriptorArray> descs(object->map().instance_descriptors(),
isolate_);
// First collect the strings,
- int first_symbol =
+ base::Optional<int> first_symbol =
CollectOwnPropertyNamesInternal<true>(object, this, descs, 0, limit);
// then the symbols.
- if (first_symbol != -1) {
- CollectOwnPropertyNamesInternal<false>(object, this, descs,
- first_symbol, limit);
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(first_symbol);
+ if (first_symbol.value() != -1) {
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(CollectOwnPropertyNamesInternal<false>(
+ object, this, descs, first_symbol.value(), limit));
}
} else if (object->IsJSGlobalObject()) {
- GlobalDictionary::CollectKeysTo(
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(GlobalDictionary::CollectKeysTo(
handle(JSGlobalObject::cast(*object).global_dictionary(), isolate_),
- this);
+ this));
} else {
- NameDictionary::CollectKeysTo(
- handle(object->property_dictionary(), isolate_), this);
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(NameDictionary::CollectKeysTo(
+ handle(object->property_dictionary(), isolate_), this));
}
}
// Add the property keys from the interceptor.
return CollectInterceptorKeys(receiver, object, this, kNamed);
}
-void KeyAccumulator::CollectPrivateNames(Handle<JSReceiver> receiver,
- Handle<JSObject> object) {
+ExceptionStatus KeyAccumulator::CollectPrivateNames(Handle<JSReceiver> receiver,
+ Handle<JSObject> object) {
if (object->HasFastProperties()) {
int limit = object->map().NumberOfOwnDescriptors();
Handle<DescriptorArray> descs(object->map().instance_descriptors(),
isolate_);
CollectOwnPropertyNamesInternal<false>(object, this, descs, 0, limit);
} else if (object->IsJSGlobalObject()) {
- GlobalDictionary::CollectKeysTo(
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(GlobalDictionary::CollectKeysTo(
handle(JSGlobalObject::cast(*object).global_dictionary(), isolate_),
- this);
+ this));
} else {
- NameDictionary::CollectKeysTo(
- handle(object->property_dictionary(), isolate_), this);
+ RETURN_FAILURE_IF_NOT_SUCCESSFUL(NameDictionary::CollectKeysTo(
+ handle(object->property_dictionary(), isolate_), this));
}
+ return ExceptionStatus::kSuccess;
}
Maybe<bool> KeyAccumulator::CollectAccessCheckInterceptorKeys(
@@ -795,7 +819,7 @@ Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ);
}
if (filter_ & PRIVATE_NAMES_ONLY) {
- CollectPrivateNames(receiver, object);
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(CollectPrivateNames(receiver, object));
return Just(true);
}
@@ -843,8 +867,8 @@ Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver,
Handle<JSProxy> proxy) {
STACK_CHECK(isolate_, Nothing<bool>());
if (filter_ == PRIVATE_NAMES_ONLY) {
- NameDictionary::CollectKeysTo(
- handle(proxy->property_dictionary(), isolate_), this);
+ RETURN_NOTHING_IF_NOT_SUCCESSFUL(NameDictionary::CollectKeysTo(
+ handle(proxy->property_dictionary(), isolate_), this));
return Just(true);
}
@@ -1018,5 +1042,7 @@ Maybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys(
return result;
}
+#undef RETURN_NOTHING_IF_NOT_SUCCESSFUL
+#undef RETURN_FAILURE_IF_NOT_SUCCESSFUL
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/keys.h b/deps/v8/src/objects/keys.h
index 69f61a886e..5d8632e2a7 100644
--- a/deps/v8/src/objects/keys.h
+++ b/deps/v8/src/objects/keys.h
@@ -52,8 +52,8 @@ class KeyAccumulator final {
Handle<JSObject> object);
Maybe<bool> CollectOwnPropertyNames(Handle<JSReceiver> receiver,
Handle<JSObject> object);
- void CollectPrivateNames(Handle<JSReceiver> receiver,
- Handle<JSObject> object);
+ V8_WARN_UNUSED_RESULT ExceptionStatus
+ CollectPrivateNames(Handle<JSReceiver> receiver, Handle<JSObject> object);
Maybe<bool> CollectAccessCheckInterceptorKeys(
Handle<AccessCheckInfo> access_check_info, Handle<JSReceiver> receiver,
Handle<JSObject> object);
@@ -65,10 +65,14 @@ class KeyAccumulator final {
static Handle<FixedArray> GetOwnEnumPropertyKeys(Isolate* isolate,
Handle<JSObject> object);
- void AddKey(Object key, AddKeyConversion convert = DO_NOT_CONVERT);
- void AddKey(Handle<Object> key, AddKeyConversion convert = DO_NOT_CONVERT);
- void AddKeys(Handle<FixedArray> array, AddKeyConversion convert);
- void AddKeys(Handle<JSObject> array_like, AddKeyConversion convert);
+ V8_WARN_UNUSED_RESULT ExceptionStatus
+ AddKey(Object key, AddKeyConversion convert = DO_NOT_CONVERT);
+ V8_WARN_UNUSED_RESULT ExceptionStatus
+ AddKey(Handle<Object> key, AddKeyConversion convert = DO_NOT_CONVERT);
+ V8_WARN_UNUSED_RESULT ExceptionStatus AddKeys(Handle<FixedArray> array,
+ AddKeyConversion convert);
+ V8_WARN_UNUSED_RESULT ExceptionStatus AddKeys(Handle<JSObject> array_like,
+ AddKeyConversion convert);
// Jump to the next level, pushing the current |levelLength_| to
// |levelLengths_| and adding a new list to |elements_|.
diff --git a/deps/v8/src/objects/literal-objects-inl.h b/deps/v8/src/objects/literal-objects-inl.h
index 32b43cd8f7..96aa8d8c8b 100644
--- a/deps/v8/src/objects/literal-objects-inl.h
+++ b/deps/v8/src/objects/literal-objects-inl.h
@@ -124,14 +124,9 @@ ACCESSORS(ClassBoilerplate, instance_computed_properties, FixedArray,
// ArrayBoilerplateDescription
//
-OBJECT_CONSTRUCTORS_IMPL(ArrayBoilerplateDescription, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(ArrayBoilerplateDescription)
-CAST_ACCESSOR(ArrayBoilerplateDescription)
-
-SMI_ACCESSORS(ArrayBoilerplateDescription, flags, kFlagsOffset)
-
-ACCESSORS(ArrayBoilerplateDescription, constant_elements, FixedArrayBase,
- kConstantElementsOffset)
+TQ_SMI_ACCESSORS(ArrayBoilerplateDescription, flags)
ElementsKind ArrayBoilerplateDescription::elements_kind() const {
return static_cast<ElementsKind>(flags());
diff --git a/deps/v8/src/objects/literal-objects.cc b/deps/v8/src/objects/literal-objects.cc
index 7328c11f31..95beb6cbdb 100644
--- a/deps/v8/src/objects/literal-objects.cc
+++ b/deps/v8/src/objects/literal-objects.cc
@@ -528,8 +528,7 @@ Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
// Add name accessor to the class object if necessary.
bool install_class_name_accessor = false;
- if (!expr->has_name_static_property() &&
- expr->constructor()->has_shared_name()) {
+ if (!expr->has_name_static_property()) {
if (static_desc.HasDictionaryProperties()) {
// Install class name accessor if necessary during class literal
// instantiation.
diff --git a/deps/v8/src/objects/literal-objects.h b/deps/v8/src/objects/literal-objects.h
index f009a54f8a..cf551ea576 100644
--- a/deps/v8/src/objects/literal-objects.h
+++ b/deps/v8/src/objects/literal-objects.h
@@ -55,29 +55,22 @@ class ObjectBoilerplateDescription : public FixedArray {
OBJECT_CONSTRUCTORS(ObjectBoilerplateDescription, FixedArray);
};
-class ArrayBoilerplateDescription : public Struct {
+class ArrayBoilerplateDescription
+ : public TorqueGeneratedArrayBoilerplateDescription<
+ ArrayBoilerplateDescription, Struct> {
public:
- // store constant_elements of a fixed array
- DECL_ACCESSORS(constant_elements, FixedArrayBase)
-
inline ElementsKind elements_kind() const;
inline void set_elements_kind(ElementsKind kind);
inline bool is_empty() const;
- DECL_CAST(ArrayBoilerplateDescription)
// Dispatched behavior.
DECL_PRINTER(ArrayBoilerplateDescription)
- DECL_VERIFIER(ArrayBoilerplateDescription)
void BriefPrintDetails(std::ostream& os);
- DEFINE_FIELD_OFFSET_CONSTANTS(
- HeapObject::kHeaderSize,
- TORQUE_GENERATED_ARRAY_BOILERPLATE_DESCRIPTION_FIELDS)
-
private:
DECL_INT_ACCESSORS(flags)
- OBJECT_CONSTRUCTORS(ArrayBoilerplateDescription, Struct);
+ TQ_OBJECT_CONSTRUCTORS(ArrayBoilerplateDescription)
};
class ClassBoilerplate : public FixedArray {
diff --git a/deps/v8/src/objects/lookup.cc b/deps/v8/src/objects/lookup.cc
index 33130aafe5..445d0815f3 100644
--- a/deps/v8/src/objects/lookup.cc
+++ b/deps/v8/src/objects/lookup.cc
@@ -6,6 +6,7 @@
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/isolate-inl.h"
+#include "src/execution/protectors-inl.h"
#include "src/init/bootstrapper.h"
#include "src/logging/counters.h"
#include "src/objects/elements.h"
@@ -235,30 +236,42 @@ void LookupIterator::InternalUpdateProtector() {
if (!receiver_->IsHeapObject()) return;
Handle<HeapObject> receiver = Handle<HeapObject>::cast(receiver_);
+ // Getting the native_context from the isolate as a fallback. If possible, we
+ // use the receiver's creation context instead.
Handle<NativeContext> native_context = isolate_->native_context();
ReadOnlyRoots roots(isolate_);
if (*name_ == roots.constructor_string()) {
- if (!isolate_->IsArraySpeciesLookupChainIntact() &&
+ // Fetching the context in here since the operation is rather expensive.
+ if (receiver->IsJSReceiver()) {
+ native_context = Handle<JSReceiver>::cast(receiver)->GetCreationContext();
+ }
+
+ if (!Protectors::IsArraySpeciesLookupChainIntact(isolate_) &&
!isolate_->IsPromiseSpeciesLookupChainIntact() &&
- !isolate_->IsRegExpSpeciesLookupChainIntact(native_context) &&
+ !Protectors::IsRegExpSpeciesLookupChainProtectorIntact(
+ native_context) &&
!isolate_->IsTypedArraySpeciesLookupChainIntact()) {
return;
}
// Setting the constructor property could change an instance's @@species
if (receiver->IsJSArray(isolate_)) {
- if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
+ if (!Protectors::IsArraySpeciesLookupChainIntact(isolate_)) return;
isolate_->CountUsage(
v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
- isolate_->InvalidateArraySpeciesProtector();
+ Protectors::InvalidateArraySpeciesLookupChain(isolate_);
return;
} else if (receiver->IsJSPromise(isolate_)) {
if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
isolate_->InvalidatePromiseSpeciesProtector();
return;
} else if (receiver->IsJSRegExp(isolate_)) {
- if (!isolate_->IsRegExpSpeciesLookupChainIntact(native_context)) return;
- isolate_->InvalidateRegExpSpeciesProtector(native_context);
+ if (!Protectors::IsRegExpSpeciesLookupChainProtectorIntact(
+ native_context)) {
+ return;
+ }
+ Protectors::InvalidateRegExpSpeciesLookupChainProtector(isolate_,
+ native_context);
return;
} else if (receiver->IsJSTypedArray(isolate_)) {
if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
@@ -274,18 +287,22 @@ void LookupIterator::InternalUpdateProtector() {
// prototype is pointing the same TYPED_ARRAY_PROTOTYPE.
if (isolate_->IsInAnyContext(*receiver,
Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) {
- if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
+ if (!Protectors::IsArraySpeciesLookupChainIntact(isolate_)) return;
isolate_->CountUsage(
v8::Isolate::UseCounterFeature::kArrayPrototypeConstructorModified);
- isolate_->InvalidateArraySpeciesProtector();
+ Protectors::InvalidateArraySpeciesLookupChain(isolate_);
} else if (isolate_->IsInAnyContext(*receiver,
Context::PROMISE_PROTOTYPE_INDEX)) {
if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
isolate_->InvalidatePromiseSpeciesProtector();
} else if (isolate_->IsInAnyContext(*receiver,
Context::REGEXP_PROTOTYPE_INDEX)) {
- if (!isolate_->IsRegExpSpeciesLookupChainIntact(native_context)) return;
- isolate_->InvalidateRegExpSpeciesProtector(native_context);
+ if (!Protectors::IsRegExpSpeciesLookupChainProtectorIntact(
+ native_context)) {
+ return;
+ }
+ Protectors::InvalidateRegExpSpeciesLookupChainProtector(isolate_,
+ native_context);
} else if (isolate_->IsInAnyContext(
receiver->map(isolate_).prototype(isolate_),
Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
@@ -321,27 +338,37 @@ void LookupIterator::InternalUpdateProtector() {
isolate_->InvalidateStringIteratorProtector();
}
} else if (*name_ == roots.species_symbol()) {
- if (!isolate_->IsArraySpeciesLookupChainIntact() &&
+ // Fetching the context in here since the operation is rather expensive.
+ if (receiver->IsJSReceiver()) {
+ native_context = Handle<JSReceiver>::cast(receiver)->GetCreationContext();
+ }
+
+ if (!Protectors::IsArraySpeciesLookupChainIntact(isolate_) &&
!isolate_->IsPromiseSpeciesLookupChainIntact() &&
- !isolate_->IsRegExpSpeciesLookupChainIntact(native_context) &&
+ !Protectors::IsRegExpSpeciesLookupChainProtectorIntact(
+ native_context) &&
!isolate_->IsTypedArraySpeciesLookupChainIntact()) {
return;
}
// Setting the Symbol.species property of any Array, Promise or TypedArray
// constructor invalidates the @@species protector
if (isolate_->IsInAnyContext(*receiver, Context::ARRAY_FUNCTION_INDEX)) {
- if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
+ if (!Protectors::IsArraySpeciesLookupChainIntact(isolate_)) return;
isolate_->CountUsage(
v8::Isolate::UseCounterFeature::kArraySpeciesModified);
- isolate_->InvalidateArraySpeciesProtector();
+ Protectors::InvalidateArraySpeciesLookupChain(isolate_);
} else if (isolate_->IsInAnyContext(*receiver,
Context::PROMISE_FUNCTION_INDEX)) {
if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
isolate_->InvalidatePromiseSpeciesProtector();
} else if (isolate_->IsInAnyContext(*receiver,
Context::REGEXP_FUNCTION_INDEX)) {
- if (!isolate_->IsRegExpSpeciesLookupChainIntact(native_context)) return;
- isolate_->InvalidateRegExpSpeciesProtector(native_context);
+ if (!Protectors::IsRegExpSpeciesLookupChainProtectorIntact(
+ native_context)) {
+ return;
+ }
+ Protectors::InvalidateRegExpSpeciesLookupChainProtector(isolate_,
+ native_context);
} else if (IsTypedArrayFunctionInAnyContext(isolate_, *receiver)) {
if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
isolate_->InvalidateTypedArraySpeciesProtector();
@@ -433,7 +460,8 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
}
// Copy the backing store if it is copy-on-write.
- if (IsSmiOrObjectElementsKind(to) || IsSealedElementsKind(to)) {
+ if (IsSmiOrObjectElementsKind(to) || IsSealedElementsKind(to) ||
+ IsNonextensibleElementsKind(to)) {
JSObject::EnsureWritableFastElements(holder_obj);
}
return;
@@ -901,8 +929,8 @@ bool LookupIterator::IsConstFieldValueEqualTo(Object value) const {
bits = holder->RawFastDoublePropertyAsBitsAt(field_index);
} else {
Object current_value = holder->RawFastPropertyAt(isolate_, field_index);
- DCHECK(current_value.IsMutableHeapNumber(isolate_));
- bits = MutableHeapNumber::cast(current_value).value_as_bits();
+ DCHECK(current_value.IsHeapNumber(isolate_));
+ bits = HeapNumber::cast(current_value).value_as_bits();
}
// Use bit representation of double to to check for hole double, since
// manipulating the signaling NaN used for the hole in C++, e.g. with
@@ -1137,9 +1165,10 @@ LookupIterator::State LookupIterator::LookupInRegularHolder(
: NOT_FOUND;
}
property_details_ = accessor->GetDetails(js_object, number_);
- if (map.has_frozen_or_sealed_elements()) {
- PropertyAttributes attrs = map.has_sealed_elements() ? SEALED : FROZEN;
- property_details_ = property_details_.CopyAddAttributes(attrs);
+ if (map.has_frozen_elements()) {
+ property_details_ = property_details_.CopyAddAttributes(FROZEN);
+ } else if (map.has_sealed_elements()) {
+ property_details_ = property_details_.CopyAddAttributes(SEALED);
}
} else if (!map.is_dictionary_map()) {
DescriptorArray descriptors = map.instance_descriptors(isolate_);
diff --git a/deps/v8/src/objects/map-inl.h b/deps/v8/src/objects/map-inl.h
index 6a9359e3a0..48bb86e2da 100644
--- a/deps/v8/src/objects/map-inl.h
+++ b/deps/v8/src/objects/map-inl.h
@@ -507,8 +507,12 @@ bool Map::has_dictionary_elements() const {
return IsDictionaryElementsKind(elements_kind());
}
-bool Map::has_frozen_or_sealed_elements() const {
- return IsFrozenOrSealedElementsKind(elements_kind());
+bool Map::has_any_nonextensible_elements() const {
+ return IsAnyNonextensibleElementsKind(elements_kind());
+}
+
+bool Map::has_nonextensible_elements() const {
+ return IsNonextensibleElementsKind(elements_kind());
}
bool Map::has_sealed_elements() const {
diff --git a/deps/v8/src/objects/map-updater.cc b/deps/v8/src/objects/map-updater.cc
index d21f0e1a12..49b9ccea91 100644
--- a/deps/v8/src/objects/map-updater.cc
+++ b/deps/v8/src/objects/map-updater.cc
@@ -324,7 +324,7 @@ MapUpdater::State MapUpdater::FindRootMap() {
DCHECK(to_kind == DICTIONARY_ELEMENTS ||
to_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
IsTypedArrayElementsKind(to_kind) ||
- IsFrozenOrSealedElementsKind(to_kind));
+ IsAnyNonextensibleElementsKind(to_kind));
to_kind = integrity_source_map_->elements_kind();
}
diff --git a/deps/v8/src/objects/map.cc b/deps/v8/src/objects/map.cc
index 7b4f1abd05..a672d6580a 100644
--- a/deps/v8/src/objects/map.cc
+++ b/deps/v8/src/objects/map.cc
@@ -281,8 +281,6 @@ VisitorId Map::GetVisitorId(Map map) {
case JS_DATE_TYPE:
case JS_ARRAY_ITERATOR_TYPE:
case JS_ARRAY_TYPE:
- case JS_GLOBAL_PROXY_TYPE:
- case JS_GLOBAL_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
case JS_SET_TYPE:
case JS_MAP_TYPE:
@@ -321,6 +319,8 @@ VisitorId Map::GetVisitorId(Map map) {
return has_raw_data_fields ? kVisitJSObject : kVisitJSObjectFast;
}
case JS_API_OBJECT_TYPE:
+ case JS_GLOBAL_PROXY_TYPE:
+ case JS_GLOBAL_OBJECT_TYPE:
case JS_SPECIAL_API_OBJECT_TYPE:
return kVisitJSApiObject;
@@ -333,7 +333,6 @@ VisitorId Map::GetVisitorId(Map map) {
case FILLER_TYPE:
case FOREIGN_TYPE:
case HEAP_NUMBER_TYPE:
- case MUTABLE_HEAP_NUMBER_TYPE:
case FEEDBACK_METADATA_TYPE:
return kVisitDataObject;
@@ -681,6 +680,10 @@ void Map::UpdateFieldType(Isolate* isolate, int descriptor, Handle<Name> name,
if (details.location() != kField) return;
DCHECK_EQ(kData, details.kind());
+ if (new_constness != details.constness() && is_prototype_map()) {
+ JSObject::InvalidatePrototypeChains(*this);
+ }
+
Zone zone(isolate->allocator(), ZONE_NAME);
ZoneQueue<Map> backlog(&zone);
backlog.push(*this);
@@ -966,7 +969,7 @@ Map Map::TryUpdateSlow(Isolate* isolate, Map old_map) {
DCHECK(to_kind == DICTIONARY_ELEMENTS ||
to_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
IsTypedArrayElementsKind(to_kind) ||
- IsHoleyFrozenOrSealedElementsKind(to_kind));
+ IsAnyHoleyNonextensibleElementsKind(to_kind));
to_kind = info.integrity_level_source_map.elements_kind();
}
if (from_kind != to_kind) {
@@ -1730,6 +1733,12 @@ Handle<Map> Map::CopyReplaceDescriptors(
descriptors->GeneralizeAllFields();
result->InitializeDescriptors(isolate, *descriptors,
LayoutDescriptor::FastPointerLayout());
+ // If we were trying to insert a transition but failed because there are
+ // too many transitions already, mark the object as a prototype to avoid
+ // tracking transitions from the detached map.
+ if (flag == INSERT_TRANSITION) {
+ result->set_is_prototype_map(true);
+ }
}
} else {
result->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
@@ -2006,6 +2015,15 @@ Handle<Map> Map::CopyForPreventExtensions(
new_kind = PACKED_SEALED_ELEMENTS;
} else if (attrs_to_add == FROZEN) {
new_kind = PACKED_FROZEN_ELEMENTS;
+ } else {
+ new_kind = PACKED_NONEXTENSIBLE_ELEMENTS;
+ }
+ break;
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
+ if (attrs_to_add == SEALED) {
+ new_kind = PACKED_SEALED_ELEMENTS;
+ } else if (attrs_to_add == FROZEN) {
+ new_kind = PACKED_FROZEN_ELEMENTS;
}
break;
case PACKED_SEALED_ELEMENTS:
@@ -2018,6 +2036,15 @@ Handle<Map> Map::CopyForPreventExtensions(
new_kind = HOLEY_SEALED_ELEMENTS;
} else if (attrs_to_add == FROZEN) {
new_kind = HOLEY_FROZEN_ELEMENTS;
+ } else {
+ new_kind = HOLEY_NONEXTENSIBLE_ELEMENTS;
+ }
+ break;
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
+ if (attrs_to_add == SEALED) {
+ new_kind = HOLEY_SEALED_ELEMENTS;
+ } else if (attrs_to_add == FROZEN) {
+ new_kind = HOLEY_FROZEN_ELEMENTS;
}
break;
case HOLEY_SEALED_ELEMENTS:
diff --git a/deps/v8/src/objects/map.h b/deps/v8/src/objects/map.h
index c9da19b3e3..ef16019685 100644
--- a/deps/v8/src/objects/map.h
+++ b/deps/v8/src/objects/map.h
@@ -423,7 +423,8 @@ class Map : public HeapObject {
inline bool has_fast_string_wrapper_elements() const;
inline bool has_typed_array_elements() const;
inline bool has_dictionary_elements() const;
- inline bool has_frozen_or_sealed_elements() const;
+ inline bool has_any_nonextensible_elements() const;
+ inline bool has_nonextensible_elements() const;
inline bool has_sealed_elements() const;
inline bool has_frozen_elements() const;
diff --git a/deps/v8/src/objects/microtask-inl.h b/deps/v8/src/objects/microtask-inl.h
index 91fa5890cb..613ee096c5 100644
--- a/deps/v8/src/objects/microtask-inl.h
+++ b/deps/v8/src/objects/microtask-inl.h
@@ -18,19 +18,9 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(Microtask, Struct)
-OBJECT_CONSTRUCTORS_IMPL(CallbackTask, Microtask)
-OBJECT_CONSTRUCTORS_IMPL(CallableTask, Microtask)
-
-CAST_ACCESSOR(Microtask)
-CAST_ACCESSOR(CallbackTask)
-CAST_ACCESSOR(CallableTask)
-
-ACCESSORS(CallableTask, callable, JSReceiver, kCallableOffset)
-ACCESSORS(CallableTask, context, Context, kContextOffset)
-
-ACCESSORS(CallbackTask, callback, Foreign, kCallbackOffset)
-ACCESSORS(CallbackTask, data, Foreign, kDataOffset)
+TQ_OBJECT_CONSTRUCTORS_IMPL(Microtask)
+TQ_OBJECT_CONSTRUCTORS_IMPL(CallbackTask)
+TQ_OBJECT_CONSTRUCTORS_IMPL(CallableTask)
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/microtask.h b/deps/v8/src/objects/microtask.h
index d631bf6903..cd8a71f58c 100644
--- a/deps/v8/src/objects/microtask.h
+++ b/deps/v8/src/objects/microtask.h
@@ -17,52 +17,35 @@ namespace internal {
// Abstract base class for all microtasks that can be scheduled on the
// microtask queue. This class merely serves the purpose of a marker
// interface.
-class Microtask : public Struct {
+class Microtask : public TorqueGeneratedMicrotask<Microtask, Struct> {
public:
- // Dispatched behavior.
- DECL_CAST(Microtask)
- DECL_VERIFIER(Microtask)
-
- OBJECT_CONSTRUCTORS(Microtask, Struct);
+ TQ_OBJECT_CONSTRUCTORS(Microtask)
};
// A CallbackTask is a special Microtask that allows us to schedule
// C++ microtask callbacks on the microtask queue. This is heavily
// used by Blink for example.
-class CallbackTask : public Microtask {
+class CallbackTask
+ : public TorqueGeneratedCallbackTask<CallbackTask, Microtask> {
public:
- DECL_ACCESSORS(callback, Foreign)
- DECL_ACCESSORS(data, Foreign)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(Microtask::kHeaderSize,
- TORQUE_GENERATED_CALLBACK_TASK_FIELDS)
-
// Dispatched behavior.
- DECL_CAST(CallbackTask)
DECL_PRINTER(CallbackTask)
- DECL_VERIFIER(CallbackTask)
- OBJECT_CONSTRUCTORS(CallbackTask, Microtask);
+ TQ_OBJECT_CONSTRUCTORS(CallbackTask)
};
// A CallableTask is a special (internal) Microtask that allows us to
// schedule arbitrary callables on the microtask queue. We use this
// for various tests of the microtask queue.
-class CallableTask : public Microtask {
+class CallableTask
+ : public TorqueGeneratedCallableTask<CallableTask, Microtask> {
public:
- DECL_ACCESSORS(callable, JSReceiver)
- DECL_ACCESSORS(context, Context)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(Microtask::kHeaderSize,
- TORQUE_GENERATED_CALLABLE_TASK_FIELDS)
-
// Dispatched behavior.
- DECL_CAST(CallableTask)
DECL_PRINTER(CallableTask)
DECL_VERIFIER(CallableTask)
void BriefPrintDetails(std::ostream& os);
- OBJECT_CONSTRUCTORS(CallableTask, Microtask);
+ TQ_OBJECT_CONSTRUCTORS(CallableTask)
};
} // namespace internal
diff --git a/deps/v8/src/objects/module-inl.h b/deps/v8/src/objects/module-inl.h
index 1ab9b9fb04..ac54516376 100644
--- a/deps/v8/src/objects/module-inl.h
+++ b/deps/v8/src/objects/module-inl.h
@@ -20,37 +20,24 @@ namespace v8 {
namespace internal {
OBJECT_CONSTRUCTORS_IMPL(Module, HeapObject)
-OBJECT_CONSTRUCTORS_IMPL(SourceTextModule, Module)
-OBJECT_CONSTRUCTORS_IMPL(SourceTextModuleInfoEntry, Struct)
-OBJECT_CONSTRUCTORS_IMPL(SyntheticModule, Module)
-OBJECT_CONSTRUCTORS_IMPL(JSModuleNamespace, JSObject)
+TQ_OBJECT_CONSTRUCTORS_IMPL(SourceTextModule)
+TQ_OBJECT_CONSTRUCTORS_IMPL(SourceTextModuleInfoEntry)
+TQ_OBJECT_CONSTRUCTORS_IMPL(SyntheticModule)
+TQ_OBJECT_CONSTRUCTORS_IMPL(JSModuleNamespace)
NEVER_READ_ONLY_SPACE_IMPL(Module)
NEVER_READ_ONLY_SPACE_IMPL(SourceTextModule)
NEVER_READ_ONLY_SPACE_IMPL(SyntheticModule)
CAST_ACCESSOR(Module)
-CAST_ACCESSOR(SourceTextModule)
-CAST_ACCESSOR(SyntheticModule)
ACCESSORS(Module, exports, ObjectHashTable, kExportsOffset)
ACCESSORS(Module, module_namespace, HeapObject, kModuleNamespaceOffset)
ACCESSORS(Module, exception, Object, kExceptionOffset)
SMI_ACCESSORS(Module, status, kStatusOffset)
SMI_ACCESSORS(Module, hash, kHashOffset)
-ACCESSORS(SourceTextModule, code, Object, kCodeOffset)
-ACCESSORS(SourceTextModule, regular_exports, FixedArray, kRegularExportsOffset)
-ACCESSORS(SourceTextModule, regular_imports, FixedArray, kRegularImportsOffset)
-ACCESSORS(SourceTextModule, requested_modules, FixedArray,
- kRequestedModulesOffset)
-ACCESSORS(SourceTextModule, script, Script, kScriptOffset)
-ACCESSORS(SourceTextModule, import_meta, Object, kImportMetaOffset)
-SMI_ACCESSORS(SourceTextModule, dfs_index, kDfsIndexOffset)
-SMI_ACCESSORS(SourceTextModule, dfs_ancestor_index, kDfsAncestorIndexOffset)
-
-ACCESSORS(SyntheticModule, name, String, kNameOffset)
-ACCESSORS(SyntheticModule, export_names, FixedArray, kExportNamesOffset)
-ACCESSORS(SyntheticModule, evaluation_steps, Foreign, kEvaluationStepsOffset)
+TQ_SMI_ACCESSORS(SourceTextModule, dfs_index)
+TQ_SMI_ACCESSORS(SourceTextModule, dfs_ancestor_index)
SourceTextModuleInfo SourceTextModule::info() const {
return (status() >= kEvaluating)
@@ -58,17 +45,10 @@ SourceTextModuleInfo SourceTextModule::info() const {
: GetSharedFunctionInfo().scope_info().ModuleDescriptorInfo();
}
-CAST_ACCESSOR(JSModuleNamespace)
-ACCESSORS(JSModuleNamespace, module, Module, kModuleOffset)
-
-CAST_ACCESSOR(SourceTextModuleInfoEntry)
-ACCESSORS(SourceTextModuleInfoEntry, export_name, Object, kExportNameOffset)
-ACCESSORS(SourceTextModuleInfoEntry, local_name, Object, kLocalNameOffset)
-ACCESSORS(SourceTextModuleInfoEntry, import_name, Object, kImportNameOffset)
-SMI_ACCESSORS(SourceTextModuleInfoEntry, module_request, kModuleRequestOffset)
-SMI_ACCESSORS(SourceTextModuleInfoEntry, cell_index, kCellIndexOffset)
-SMI_ACCESSORS(SourceTextModuleInfoEntry, beg_pos, kBegPosOffset)
-SMI_ACCESSORS(SourceTextModuleInfoEntry, end_pos, kEndPosOffset)
+TQ_SMI_ACCESSORS(SourceTextModuleInfoEntry, module_request)
+TQ_SMI_ACCESSORS(SourceTextModuleInfoEntry, cell_index)
+TQ_SMI_ACCESSORS(SourceTextModuleInfoEntry, beg_pos)
+TQ_SMI_ACCESSORS(SourceTextModuleInfoEntry, end_pos)
OBJECT_CONSTRUCTORS_IMPL(SourceTextModuleInfo, FixedArray)
CAST_ACCESSOR(SourceTextModuleInfo)
diff --git a/deps/v8/src/objects/module.cc b/deps/v8/src/objects/module.cc
index 4e89050360..60b9145d10 100644
--- a/deps/v8/src/objects/module.cc
+++ b/deps/v8/src/objects/module.cc
@@ -107,21 +107,18 @@ void Module::Reset(Isolate* isolate, Handle<Module> module) {
module->PrintStatusTransition(kUninstantiated);
#endif // DEBUG
- int export_count;
+ const int export_count =
+ module->IsSourceTextModule()
+ ? Handle<SourceTextModule>::cast(module)->regular_exports().length()
+ : Handle<SyntheticModule>::cast(module)->export_names().length();
+ Handle<ObjectHashTable> exports = ObjectHashTable::New(isolate, export_count);
if (module->IsSourceTextModule()) {
- Handle<SourceTextModule> source_text_module =
- Handle<SourceTextModule>::cast(module);
- export_count = source_text_module->regular_exports().length();
- SourceTextModule::Reset(isolate, source_text_module);
+ SourceTextModule::Reset(isolate, Handle<SourceTextModule>::cast(module));
} else {
- export_count =
- Handle<SyntheticModule>::cast(module)->export_names().length();
// Nothing to do here.
}
- Handle<ObjectHashTable> exports = ObjectHashTable::New(isolate, export_count);
-
module->set_exports(*exports);
module->set_status(kUninstantiated);
}
diff --git a/deps/v8/src/objects/module.h b/deps/v8/src/objects/module.h
index b776ddb0be..08badf0357 100644
--- a/deps/v8/src/objects/module.h
+++ b/deps/v8/src/objects/module.h
@@ -136,14 +136,10 @@ class Module : public HeapObject {
// When importing a module namespace (import * as foo from "bar"), a
// JSModuleNamespace object (representing module "bar") is created and bound to
// the declared variable (foo). A module can have at most one namespace object.
-class JSModuleNamespace : public JSObject {
+class JSModuleNamespace
+ : public TorqueGeneratedJSModuleNamespace<JSModuleNamespace, JSObject> {
public:
- DECL_CAST(JSModuleNamespace)
DECL_PRINTER(JSModuleNamespace)
- DECL_VERIFIER(JSModuleNamespace)
-
- // The actual module whose namespace is being represented.
- DECL_ACCESSORS(module, Module)
// Retrieve the value exported by [module] under the given [name]. If there is
// no such export, return Just(undefined). If the export is uninitialized,
@@ -163,16 +159,12 @@ class JSModuleNamespace : public JSObject {
kInObjectFieldCount,
};
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
- TORQUE_GENERATED_JSMODULE_NAMESPACE_FIELDS)
-
// We need to include in-object fields
// TODO(v8:8944): improve handling of in-object fields
static constexpr int kSize =
kHeaderSize + (kTaggedSize * kInObjectFieldCount);
- OBJECT_CONSTRUCTORS(JSModuleNamespace, JSObject);
+ TQ_OBJECT_CONSTRUCTORS(JSModuleNamespace)
};
} // namespace internal
diff --git a/deps/v8/src/objects/name-inl.h b/deps/v8/src/objects/name-inl.h
index 8aded12fb5..b76ae245a2 100644
--- a/deps/v8/src/objects/name-inl.h
+++ b/deps/v8/src/objects/name-inl.h
@@ -22,7 +22,8 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(Symbol)
BIT_FIELD_ACCESSORS(Symbol, flags, is_private, Symbol::IsPrivateBit)
BIT_FIELD_ACCESSORS(Symbol, flags, is_well_known_symbol,
Symbol::IsWellKnownSymbolBit)
-BIT_FIELD_ACCESSORS(Symbol, flags, is_public, Symbol::IsPublicBit)
+BIT_FIELD_ACCESSORS(Symbol, flags, is_in_public_symbol_table,
+ Symbol::IsInPublicSymbolTableBit)
BIT_FIELD_ACCESSORS(Symbol, flags, is_interesting_symbol,
Symbol::IsInterestingSymbolBit)
diff --git a/deps/v8/src/objects/name.h b/deps/v8/src/objects/name.h
index b13aa30fb0..a02bb3d794 100644
--- a/deps/v8/src/objects/name.h
+++ b/deps/v8/src/objects/name.h
@@ -99,12 +99,11 @@ class Name : public TorqueGeneratedName<Name, HeapObject> {
STATIC_ASSERT(kArrayIndexLengthBits > 0);
STATIC_ASSERT(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits));
- class ArrayIndexValueBits
- : public BitField<unsigned int, kNofHashBitFields, kArrayIndexValueBits> {
- }; // NOLINT
- class ArrayIndexLengthBits
- : public BitField<unsigned int, kNofHashBitFields + kArrayIndexValueBits,
- kArrayIndexLengthBits> {}; // NOLINT
+ using ArrayIndexValueBits =
+ BitField<unsigned int, kNofHashBitFields, kArrayIndexValueBits>;
+ using ArrayIndexLengthBits =
+ BitField<unsigned int, kNofHashBitFields + kArrayIndexValueBits,
+ kArrayIndexLengthBits>;
// Check that kMaxCachedArrayIndexLength + 1 is a power of two so we
// could use a mask to test if the length of string is less than or equal to
@@ -147,9 +146,10 @@ class Symbol : public TorqueGeneratedSymbol<Symbol, Name> {
// for a detailed description.
DECL_BOOLEAN_ACCESSORS(is_interesting_symbol)
- // [is_public]: Whether this is a symbol created by Symbol.for. Calling
- // Symbol.keyFor on such a symbol simply needs to return the attached name.
- DECL_BOOLEAN_ACCESSORS(is_public)
+ // [is_in_public_symbol_table]: Whether this is a symbol created by
+ // Symbol.for. Calling Symbol.keyFor on such a symbol simply needs
+ // to return the attached name.
+ DECL_BOOLEAN_ACCESSORS(is_in_public_symbol_table)
// [is_private_name]: Whether this is a private name. Private names
// are the same as private symbols except they throw on missing
@@ -164,11 +164,11 @@ class Symbol : public TorqueGeneratedSymbol<Symbol, Name> {
DECL_VERIFIER(Symbol)
// Flags layout.
-#define FLAGS_BIT_FIELDS(V, _) \
- V(IsPrivateBit, bool, 1, _) \
- V(IsWellKnownSymbolBit, bool, 1, _) \
- V(IsPublicBit, bool, 1, _) \
- V(IsInterestingSymbolBit, bool, 1, _) \
+#define FLAGS_BIT_FIELDS(V, _) \
+ V(IsPrivateBit, bool, 1, _) \
+ V(IsWellKnownSymbolBit, bool, 1, _) \
+ V(IsInPublicSymbolTableBit, bool, 1, _) \
+ V(IsInterestingSymbolBit, bool, 1, _) \
V(IsPrivateNameBit, bool, 1, _)
DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
diff --git a/deps/v8/src/objects/object-list-macros.h b/deps/v8/src/objects/object-list-macros.h
index c15b212eec..d5bce62d43 100644
--- a/deps/v8/src/objects/object-list-macros.h
+++ b/deps/v8/src/objects/object-list-macros.h
@@ -37,7 +37,7 @@ class LookupIterator;
class FieldType;
class Module;
class SourceTextModuleInfoEntry;
-class MutableHeapNumber;
+class HeapNumber;
class ObjectHashTable;
class ObjectTemplateInfo;
class ObjectVisitor;
@@ -173,7 +173,6 @@ class ZoneForwardList;
V(MapCache) \
V(Module) \
V(Microtask) \
- V(MutableHeapNumber) \
V(Name) \
V(NameDictionary) \
V(NativeContext) \
diff --git a/deps/v8/src/objects/object-macros.h b/deps/v8/src/objects/object-macros.h
index 8f9e51ca9e..da8c404c14 100644
--- a/deps/v8/src/objects/object-macros.h
+++ b/deps/v8/src/objects/object-macros.h
@@ -290,20 +290,31 @@
#define RELAXED_WRITE_WEAK_FIELD(p, offset, value) \
TaggedField<MaybeObject>::Relaxed_Store(p, offset, value)
+#ifdef V8_DISABLE_WRITE_BARRIERS
+#define WRITE_BARRIER(object, offset, value)
+#else
#define WRITE_BARRIER(object, offset, value) \
do { \
DCHECK_NOT_NULL(GetHeapFromWritableObject(object)); \
MarkingBarrier(object, (object).RawField(offset), value); \
GenerationalBarrier(object, (object).RawField(offset), value); \
} while (false)
+#endif
+#ifdef V8_DISABLE_WRITE_BARRIERS
+#define WEAK_WRITE_BARRIER(object, offset, value)
+#else
#define WEAK_WRITE_BARRIER(object, offset, value) \
do { \
DCHECK_NOT_NULL(GetHeapFromWritableObject(object)); \
MarkingBarrier(object, (object).RawMaybeWeakField(offset), value); \
GenerationalBarrier(object, (object).RawMaybeWeakField(offset), value); \
} while (false)
+#endif
+#ifdef V8_DISABLE_WRITE_BARRIERS
+#define EPHEMERON_KEY_WRITE_BARRIER(object, offset, value)
+#else
#define EPHEMERON_KEY_WRITE_BARRIER(object, offset, value) \
do { \
DCHECK_NOT_NULL(GetHeapFromWritableObject(object)); \
@@ -311,7 +322,11 @@
MarkingBarrier(object, (object).RawField(offset), value); \
GenerationalEphemeronKeyBarrier(table, (object).RawField(offset), value); \
} while (false)
+#endif
+#ifdef V8_DISABLE_WRITE_BARRIERS
+#define CONDITIONAL_WRITE_BARRIER(object, offset, value, mode)
+#else
#define CONDITIONAL_WRITE_BARRIER(object, offset, value, mode) \
do { \
DCHECK_NOT_NULL(GetHeapFromWritableObject(object)); \
@@ -323,7 +338,11 @@
GenerationalBarrier(object, (object).RawField(offset), value); \
} \
} while (false)
+#endif
+#ifdef V8_DISABLE_WRITE_BARRIERS
+#define CONDITIONAL_WEAK_WRITE_BARRIER(object, offset, value, mode)
+#else
#define CONDITIONAL_WEAK_WRITE_BARRIER(object, offset, value, mode) \
do { \
DCHECK_NOT_NULL(GetHeapFromWritableObject(object)); \
@@ -335,7 +354,11 @@
GenerationalBarrier(object, (object).RawMaybeWeakField(offset), value); \
} \
} while (false)
+#endif
+#ifdef V8_DISABLE_WRITE_BARRIERS
+#define CONDITIONAL_EPHEMERON_KEY_WRITE_BARRIER(object, offset, value, mode)
+#else
#define CONDITIONAL_EPHEMERON_KEY_WRITE_BARRIER(object, offset, value, mode) \
do { \
DCHECK_NOT_NULL(GetHeapFromWritableObject(object)); \
@@ -349,6 +372,7 @@
value); \
} \
} while (false)
+#endif
#define ACQUIRE_READ_INT32_FIELD(p, offset) \
static_cast<int32_t>(base::Acquire_Load( \
diff --git a/deps/v8/src/objects/objects-body-descriptors-inl.h b/deps/v8/src/objects/objects-body-descriptors-inl.h
index 51e380695e..4c980b2697 100644
--- a/deps/v8/src/objects/objects-body-descriptors-inl.h
+++ b/deps/v8/src/objects/objects-body-descriptors-inl.h
@@ -1022,7 +1022,6 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
return Op::template apply<UncompiledDataWithPreparseData::BodyDescriptor>(
p1, p2, p3, p4);
case HEAP_NUMBER_TYPE:
- case MUTABLE_HEAP_NUMBER_TYPE:
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
case FREE_SPACE_TYPE:
diff --git a/deps/v8/src/objects/objects-definitions.h b/deps/v8/src/objects/objects-definitions.h
index b4c8591e5c..b346b5b7d1 100644
--- a/deps/v8/src/objects/objects-definitions.h
+++ b/deps/v8/src/objects/objects-definitions.h
@@ -67,7 +67,6 @@ namespace internal {
\
V(MAP_TYPE) \
V(CODE_TYPE) \
- V(MUTABLE_HEAP_NUMBER_TYPE) \
V(FOREIGN_TYPE) \
V(BYTE_ARRAY_TYPE) \
V(BYTECODE_ARRAY_TYPE) \
@@ -116,7 +115,6 @@ namespace internal {
V(PROMISE_FULFILL_REACTION_JOB_TASK_TYPE) \
V(PROMISE_REJECT_REACTION_JOB_TASK_TYPE) \
V(PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE) \
- V(FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE) \
\
TORQUE_DEFINED_INSTANCE_TYPES(V) \
\
@@ -348,9 +346,7 @@ namespace internal {
V(_, PROMISE_REJECT_REACTION_JOB_TASK_TYPE, PromiseRejectReactionJobTask, \
promise_reject_reaction_job_task) \
V(_, PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE, PromiseResolveThenableJobTask, \
- promise_resolve_thenable_job_task) \
- V(_, FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE, \
- FinalizationGroupCleanupJobTask, finalization_group_cleanup_job_task)
+ promise_resolve_thenable_job_task)
// Adapts one STRUCT_LIST_GENERATOR entry to the STRUCT_LIST entry
#define STRUCT_LIST_ADAPTER(V, NAME, Name, name) V(NAME, Name, name)
diff --git a/deps/v8/src/objects/objects-inl.h b/deps/v8/src/objects/objects-inl.h
index b6748401c0..cf8c3ffad2 100644
--- a/deps/v8/src/objects/objects-inl.h
+++ b/deps/v8/src/objects/objects-inl.h
@@ -133,6 +133,13 @@ bool Object::IsNullOrUndefined() const {
bool Object::IsZero() const { return *this == Smi::zero(); }
+bool Object::IsPublicSymbol() const {
+ return IsSymbol() && !Symbol::cast(*this).is_private();
+}
+bool Object::IsPrivateSymbol() const {
+ return IsSymbol() && Symbol::cast(*this).is_private();
+}
+
bool Object::IsNoSharedNameSentinel() const {
return *this == SharedFunctionInfo::kNoSharedNameSentinel;
}
@@ -560,7 +567,7 @@ bool Object::FitsRepresentation(Representation representation) {
if (FLAG_track_fields && representation.IsSmi()) {
return IsSmi();
} else if (FLAG_track_double_fields && representation.IsDouble()) {
- return IsMutableHeapNumber() || IsNumber();
+ return IsNumber();
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
return IsHeapObject();
} else if (FLAG_track_fields && representation.IsNone()) {
diff --git a/deps/v8/src/objects/objects.cc b/deps/v8/src/objects/objects.cc
index 9963cba472..134cb3998a 100644
--- a/deps/v8/src/objects/objects.cc
+++ b/deps/v8/src/objects/objects.cc
@@ -33,6 +33,7 @@
#include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h"
#include "src/execution/microtask-queue.h"
+#include "src/execution/protectors-inl.h"
#include "src/heap/heap-inl.h"
#include "src/heap/read-only-heap.h"
#include "src/ic/ic.h"
@@ -193,12 +194,12 @@ Handle<FieldType> Object::OptimalType(Isolate* isolate,
Handle<Object> Object::NewStorageFor(Isolate* isolate, Handle<Object> object,
Representation representation) {
if (!representation.IsDouble()) return object;
- auto result = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
+ auto result = isolate->factory()->NewHeapNumberWithHoleNaN();
if (object->IsUninitialized(isolate)) {
result->set_value_as_bits(kHoleNanInt64);
- } else if (object->IsMutableHeapNumber()) {
+ } else if (object->IsHeapNumber()) {
// Ensure that all bits of the double value are preserved.
- result->set_value_as_bits(MutableHeapNumber::cast(*object).value_as_bits());
+ result->set_value_as_bits(HeapNumber::cast(*object).value_as_bits());
} else {
result->set_value(object->Number());
}
@@ -213,7 +214,7 @@ Handle<Object> Object::WrapForRead(Isolate* isolate, Handle<Object> object,
return object;
}
return isolate->factory()->NewHeapNumberFromBits(
- MutableHeapNumber::cast(*object).value_as_bits());
+ HeapNumber::cast(*object).value_as_bits());
}
MaybeHandle<JSReceiver> Object::ToObjectImpl(Isolate* isolate,
@@ -1667,7 +1668,7 @@ MaybeHandle<Object> Object::ArraySpeciesConstructor(
Handle<Object> default_species = isolate->array_function();
if (original_array->IsJSArray() &&
Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
- isolate->IsArraySpeciesLookupChainIntact()) {
+ Protectors::IsArraySpeciesLookupChainIntact(isolate)) {
return default_species;
}
Handle<Object> constructor = isolate->factory()->undefined_value();
@@ -2077,12 +2078,6 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
os << ">";
break;
}
- case MUTABLE_HEAP_NUMBER_TYPE: {
- os << "<MutableHeapNumber ";
- MutableHeapNumber::cast(*this).MutableHeapNumberPrint(os);
- os << '>';
- break;
- }
case BIGINT_TYPE: {
os << "<BigInt ";
BigInt::cast(*this).BigIntShortPrint(os);
@@ -2192,8 +2187,7 @@ int HeapObject::SizeFromMap(Map map) const {
FixedArray::unchecked_cast(*this).synchronized_length());
}
if (IsInRange(instance_type, FIRST_CONTEXT_TYPE, LAST_CONTEXT_TYPE)) {
- // Native context has fixed size.
- DCHECK_NE(instance_type, NATIVE_CONTEXT_TYPE);
+ if (instance_type == NATIVE_CONTEXT_TYPE) return NativeContext::kSize;
return Context::SizeFor(Context::unchecked_cast(*this).length());
}
if (instance_type == ONE_BYTE_STRING_TYPE ||
@@ -4289,11 +4283,13 @@ Handle<AccessorPair> AccessorPair::Copy(Isolate* isolate,
}
Handle<Object> AccessorPair::GetComponent(Isolate* isolate,
+ Handle<NativeContext> native_context,
Handle<AccessorPair> accessor_pair,
AccessorComponent component) {
Object accessor = accessor_pair->get(component);
if (accessor.IsFunctionTemplateInfo()) {
return ApiNatives::InstantiateFunction(
+ isolate, native_context,
handle(FunctionTemplateInfo::cast(accessor), isolate))
.ToHandleChecked();
}
@@ -5339,12 +5335,9 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
lit->end_position());
needs_position_info = false;
}
- shared_info->set_is_declaration(lit->is_declaration());
- shared_info->set_is_named_expression(lit->is_named_expression());
- shared_info->set_is_anonymous_expression(lit->is_anonymous_expression());
+ shared_info->set_syntax_kind(lit->syntax_kind());
shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
shared_info->set_language_mode(lit->language_mode());
- shared_info->set_is_wrapped(lit->is_wrapped());
shared_info->set_function_literal_id(lit->function_literal_id());
// shared_info->set_kind(lit->kind());
// FunctionKind must have already been set.
@@ -5650,8 +5643,7 @@ bool AllocationSite::IsNested() {
}
bool AllocationSite::ShouldTrack(ElementsKind from, ElementsKind to) {
- return IsSmiElementsKind(from) &&
- IsMoreGeneralElementsKindTransition(from, to);
+ return IsMoreGeneralElementsKindTransition(from, to);
}
const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
@@ -6145,6 +6137,43 @@ Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
}
+Object JSRegExp::Code(bool is_latin1) const {
+ return DataAt(code_index(is_latin1));
+}
+
+Object JSRegExp::Bytecode(bool is_latin1) const {
+ return DataAt(bytecode_index(is_latin1));
+}
+
+bool JSRegExp::ShouldProduceBytecode() {
+ return FLAG_regexp_interpret_all ||
+ (FLAG_regexp_tier_up && !MarkedForTierUp());
+}
+
+// An irregexp is considered to be marked for tier up if the tier-up ticks value
+// is not zero. An atom is not subject to tier-up implementation, so the tier-up
+// ticks value is not set.
+bool JSRegExp::MarkedForTierUp() {
+ DCHECK(data().IsFixedArray());
+ if (TypeTag() == JSRegExp::ATOM) {
+ return false;
+ }
+ return Smi::ToInt(DataAt(kIrregexpTierUpTicksIndex)) != 0;
+}
+
+void JSRegExp::ResetTierUp() {
+ DCHECK(FLAG_regexp_tier_up);
+ DCHECK_EQ(TypeTag(), JSRegExp::IRREGEXP);
+ FixedArray::cast(data()).set(JSRegExp::kIrregexpTierUpTicksIndex, Smi::kZero);
+}
+
+void JSRegExp::MarkTierUpForNextExec() {
+ DCHECK(FLAG_regexp_tier_up);
+ DCHECK_EQ(TypeTag(), JSRegExp::IRREGEXP);
+ FixedArray::cast(data()).set(JSRegExp::kIrregexpTierUpTicksIndex,
+ Smi::FromInt(1));
+}
+
namespace {
template <typename Char>
@@ -7405,7 +7434,7 @@ Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices(
}
template <typename Derived, typename Shape>
-void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
+ExceptionStatus BaseNameDictionary<Derived, Shape>::CollectKeysTo(
Handle<Derived> dictionary, KeyAccumulator* keys) {
Isolate* isolate = keys->isolate();
ReadOnlyRoots roots(isolate);
@@ -7450,16 +7479,19 @@ void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
has_seen_symbol = true;
continue;
}
- keys->AddKey(key, DO_NOT_CONVERT);
+ ExceptionStatus status = keys->AddKey(key, DO_NOT_CONVERT);
+ if (!status) return status;
}
if (has_seen_symbol) {
for (int i = 0; i < array_size; i++) {
int index = Smi::ToInt(array->get(i));
Object key = dictionary->NameAt(index);
if (!key.IsSymbol()) continue;
- keys->AddKey(key, DO_NOT_CONVERT);
+ ExceptionStatus status = keys->AddKey(key, DO_NOT_CONVERT);
+ if (!status) return status;
}
}
+ return ExceptionStatus::kSuccess;
}
// Backwards lookup (slow).
@@ -8067,7 +8099,10 @@ HashTable<NameDictionary, NameDictionaryShape>::Shrink(Isolate* isolate,
Handle<NameDictionary>,
int additionalCapacity);
-void JSFinalizationGroup::Cleanup(
+template void HashTable<GlobalDictionary, GlobalDictionaryShape>::Rehash(
+ ReadOnlyRoots roots);
+
+Maybe<bool> JSFinalizationGroup::Cleanup(
Isolate* isolate, Handle<JSFinalizationGroup> finalization_group,
Handle<Object> cleanup) {
DCHECK(cleanup->IsCallable());
@@ -8088,23 +8123,17 @@ void JSFinalizationGroup::Cleanup(
Handle<AllocationSite>::null()));
iterator->set_finalization_group(*finalization_group);
}
-
- v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
- v8::Local<v8::Value> result;
- MaybeHandle<Object> exception;
Handle<Object> args[] = {iterator};
- bool has_pending_exception = !ToLocal<Value>(
- Execution::TryCall(
+ if (Execution::Call(
isolate, cleanup,
- handle(ReadOnlyRoots(isolate).undefined_value(), isolate), 1, args,
- Execution::MessageHandling::kReport, &exception),
- &result);
- // TODO(marja): (spec): What if there's an exception?
- USE(has_pending_exception);
-
+ handle(ReadOnlyRoots(isolate).undefined_value(), isolate), 1, args)
+ .is_null()) {
+ return Nothing<bool>();
+ }
// TODO(marja): (spec): Should the iterator be invalidated after the
// function returns?
}
+ return Just(true);
}
MaybeHandle<FixedArray> JSReceiver::GetPrivateEntries(
diff --git a/deps/v8/src/objects/objects.h b/deps/v8/src/objects/objects.h
index d706b2dfb7..b4e78a1937 100644
--- a/deps/v8/src/objects/objects.h
+++ b/deps/v8/src/objects/objects.h
@@ -289,6 +289,8 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> {
V8_INLINE bool IsZero() const;
V8_INLINE bool IsNoSharedNameSentinel() const;
+ V8_INLINE bool IsPrivateSymbol() const;
+ V8_INLINE bool IsPublicSymbol() const;
enum class Conversion { kToNumber, kToNumeric };
diff --git a/deps/v8/src/objects/ordered-hash-table.cc b/deps/v8/src/objects/ordered-hash-table.cc
index 07536a4ccb..dda848f010 100644
--- a/deps/v8/src/objects/ordered-hash-table.cc
+++ b/deps/v8/src/objects/ordered-hash-table.cc
@@ -14,7 +14,7 @@ namespace v8 {
namespace internal {
template <class Derived, int entrysize>
-Handle<Derived> OrderedHashTable<Derived, entrysize>::Allocate(
+MaybeHandle<Derived> OrderedHashTable<Derived, entrysize>::Allocate(
Isolate* isolate, int capacity, AllocationType allocation) {
// Capacity must be a power of two, since we depend on being able
// to divide and multiple by 2 (kLoadFactor) to derive capacity
@@ -23,7 +23,7 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Allocate(
// field of this object.
capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
if (capacity > MaxCapacity()) {
- isolate->heap()->FatalProcessOutOfMemory("invalid table size");
+ return MaybeHandle<Derived>();
}
int num_buckets = capacity / kLoadFactor;
Handle<FixedArray> backing_store = isolate->factory()->NewFixedArrayWithMap(
@@ -41,7 +41,7 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Allocate(
}
template <class Derived, int entrysize>
-Handle<Derived> OrderedHashTable<Derived, entrysize>::EnsureGrowable(
+MaybeHandle<Derived> OrderedHashTable<Derived, entrysize>::EnsureGrowable(
Isolate* isolate, Handle<Derived> table) {
DCHECK(!table->IsObsolete());
@@ -64,7 +64,7 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Shrink(
int nof = table->NumberOfElements();
int capacity = table->Capacity();
if (nof >= (capacity >> 2)) return table;
- return Derived::Rehash(isolate, table, capacity / 2);
+ return Derived::Rehash(isolate, table, capacity / 2).ToHandleChecked();
}
template <class Derived, int entrysize>
@@ -72,10 +72,12 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Clear(
Isolate* isolate, Handle<Derived> table) {
DCHECK(!table->IsObsolete());
+ AllocationType allocation_type = Heap::InYoungGeneration(*table)
+ ? AllocationType::kYoung
+ : AllocationType::kOld;
+
Handle<Derived> new_table =
- Allocate(isolate, kMinCapacity,
- Heap::InYoungGeneration(*table) ? AllocationType::kYoung
- : AllocationType::kOld);
+ Allocate(isolate, kMinCapacity, allocation_type).ToHandleChecked();
table->SetNextTable(*new_table);
table->SetNumberOfDeletedElements(kClearedTableSentinel);
@@ -120,9 +122,9 @@ int OrderedHashTable<Derived, entrysize>::FindEntry(Isolate* isolate,
return entry;
}
-Handle<OrderedHashSet> OrderedHashSet::Add(Isolate* isolate,
- Handle<OrderedHashSet> table,
- Handle<Object> key) {
+MaybeHandle<OrderedHashSet> OrderedHashSet::Add(Isolate* isolate,
+ Handle<OrderedHashSet> table,
+ Handle<Object> key) {
int hash = key->GetOrCreateHash(isolate).value();
int entry = table->HashToEntry(hash);
// Walk the chain of the bucket and try finding the key.
@@ -133,7 +135,11 @@ Handle<OrderedHashSet> OrderedHashSet::Add(Isolate* isolate,
entry = table->NextChainEntry(entry);
}
- table = OrderedHashSet::EnsureGrowable(isolate, table);
+ MaybeHandle<OrderedHashSet> table_candidate =
+ OrderedHashSet::EnsureGrowable(isolate, table);
+ if (!table_candidate.ToHandle(&table)) {
+ return table_candidate;
+ }
// Read the existing bucket values.
int bucket = table->HashToBucket(hash);
int previous_entry = table->HashToEntry(hash);
@@ -186,14 +192,18 @@ HeapObject OrderedHashMap::GetEmpty(ReadOnlyRoots ro_roots) {
}
template <class Derived, int entrysize>
-Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
+MaybeHandle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
Isolate* isolate, Handle<Derived> table, int new_capacity) {
DCHECK(!table->IsObsolete());
- Handle<Derived> new_table =
+ MaybeHandle<Derived> new_table_candidate =
Derived::Allocate(isolate, new_capacity,
Heap::InYoungGeneration(*table) ? AllocationType::kYoung
: AllocationType::kOld);
+ Handle<Derived> new_table;
+ if (!new_table_candidate.ToHandle(&new_table)) {
+ return new_table_candidate;
+ }
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
int new_buckets = new_table->NumberOfBuckets();
@@ -227,30 +237,33 @@ Handle<Derived> OrderedHashTable<Derived, entrysize>::Rehash(
new_table->SetNumberOfElements(nof);
table->SetNextTable(*new_table);
- return new_table;
+ return new_table_candidate;
}
-Handle<OrderedHashSet> OrderedHashSet::Rehash(Isolate* isolate,
- Handle<OrderedHashSet> table,
- int new_capacity) {
+MaybeHandle<OrderedHashSet> OrderedHashSet::Rehash(Isolate* isolate,
+ Handle<OrderedHashSet> table,
+ int new_capacity) {
return OrderedHashTable<OrderedHashSet, 1>::Rehash(isolate, table,
new_capacity);
}
-Handle<OrderedHashMap> OrderedHashMap::Rehash(Isolate* isolate,
- Handle<OrderedHashMap> table,
- int new_capacity) {
+MaybeHandle<OrderedHashMap> OrderedHashMap::Rehash(Isolate* isolate,
+ Handle<OrderedHashMap> table,
+ int new_capacity) {
return OrderedHashTable<OrderedHashMap, 2>::Rehash(isolate, table,
new_capacity);
}
-Handle<OrderedNameDictionary> OrderedNameDictionary::Rehash(
+MaybeHandle<OrderedNameDictionary> OrderedNameDictionary::Rehash(
Isolate* isolate, Handle<OrderedNameDictionary> table, int new_capacity) {
- Handle<OrderedNameDictionary> new_table =
+ MaybeHandle<OrderedNameDictionary> new_table_candidate =
OrderedHashTable<OrderedNameDictionary, 3>::Rehash(isolate, table,
new_capacity);
- new_table->SetHash(table->Hash());
- return new_table;
+ Handle<OrderedNameDictionary> new_table;
+ if (new_table_candidate.ToHandle(&new_table)) {
+ new_table->SetHash(table->Hash());
+ }
+ return new_table_candidate;
}
template <class Derived, int entrysize>
@@ -286,10 +299,10 @@ Address OrderedHashMap::GetHash(Isolate* isolate, Address raw_key) {
return hash.ptr();
}
-Handle<OrderedHashMap> OrderedHashMap::Add(Isolate* isolate,
- Handle<OrderedHashMap> table,
- Handle<Object> key,
- Handle<Object> value) {
+MaybeHandle<OrderedHashMap> OrderedHashMap::Add(Isolate* isolate,
+ Handle<OrderedHashMap> table,
+ Handle<Object> key,
+ Handle<Object> value) {
int hash = key->GetOrCreateHash(isolate).value();
int entry = table->HashToEntry(hash);
// Walk the chain of the bucket and try finding the key.
@@ -304,7 +317,11 @@ Handle<OrderedHashMap> OrderedHashMap::Add(Isolate* isolate,
}
}
- table = OrderedHashMap::EnsureGrowable(isolate, table);
+ MaybeHandle<OrderedHashMap> table_candidate =
+ OrderedHashMap::EnsureGrowable(isolate, table);
+ if (!table_candidate.ToHandle(&table)) {
+ return table_candidate;
+ }
// Read the existing bucket values.
int bucket = table->HashToBucket(hash);
int previous_entry = table->HashToEntry(hash);
@@ -345,12 +362,16 @@ V8_EXPORT_PRIVATE int OrderedHashTable<OrderedNameDictionary, 3>::FindEntry(
return kNotFound;
}
-Handle<OrderedNameDictionary> OrderedNameDictionary::Add(
+MaybeHandle<OrderedNameDictionary> OrderedNameDictionary::Add(
Isolate* isolate, Handle<OrderedNameDictionary> table, Handle<Name> key,
Handle<Object> value, PropertyDetails details) {
DCHECK_EQ(kNotFound, table->FindEntry(isolate, *key));
- table = OrderedNameDictionary::EnsureGrowable(isolate, table);
+ MaybeHandle<OrderedNameDictionary> table_candidate =
+ OrderedNameDictionary::EnsureGrowable(isolate, table);
+ if (!table_candidate.ToHandle(&table)) {
+ return table_candidate;
+ }
// Read the existing bucket values.
int hash = key->Hash();
int bucket = table->HashToBucket(hash);
@@ -405,28 +426,31 @@ Handle<OrderedNameDictionary> OrderedNameDictionary::DeleteEntry(
return Shrink(isolate, table);
}
-Handle<OrderedHashSet> OrderedHashSet::Allocate(Isolate* isolate, int capacity,
- AllocationType allocation) {
+MaybeHandle<OrderedHashSet> OrderedHashSet::Allocate(
+ Isolate* isolate, int capacity, AllocationType allocation) {
return OrderedHashTable<OrderedHashSet, 1>::Allocate(isolate, capacity,
allocation);
}
-Handle<OrderedHashMap> OrderedHashMap::Allocate(Isolate* isolate, int capacity,
- AllocationType allocation) {
+MaybeHandle<OrderedHashMap> OrderedHashMap::Allocate(
+ Isolate* isolate, int capacity, AllocationType allocation) {
return OrderedHashTable<OrderedHashMap, 2>::Allocate(isolate, capacity,
allocation);
}
-Handle<OrderedNameDictionary> OrderedNameDictionary::Allocate(
+MaybeHandle<OrderedNameDictionary> OrderedNameDictionary::Allocate(
Isolate* isolate, int capacity, AllocationType allocation) {
- Handle<OrderedNameDictionary> table =
+ MaybeHandle<OrderedNameDictionary> table_candidate =
OrderedHashTable<OrderedNameDictionary, 3>::Allocate(isolate, capacity,
allocation);
- table->SetHash(PropertyArray::kNoHashSentinel);
- return table;
+ Handle<OrderedNameDictionary> table;
+ if (table_candidate.ToHandle(&table)) {
+ table->SetHash(PropertyArray::kNoHashSentinel);
+ }
+ return table_candidate;
}
-template V8_EXPORT_PRIVATE Handle<OrderedHashSet>
+template V8_EXPORT_PRIVATE MaybeHandle<OrderedHashSet>
OrderedHashTable<OrderedHashSet, 1>::EnsureGrowable(
Isolate* isolate, Handle<OrderedHashSet> table);
@@ -447,7 +471,7 @@ template V8_EXPORT_PRIVATE bool OrderedHashTable<OrderedHashSet, 1>::Delete(
template V8_EXPORT_PRIVATE int OrderedHashTable<OrderedHashSet, 1>::FindEntry(
Isolate* isolate, Object key);
-template V8_EXPORT_PRIVATE Handle<OrderedHashMap>
+template V8_EXPORT_PRIVATE MaybeHandle<OrderedHashMap>
OrderedHashTable<OrderedHashMap, 2>::EnsureGrowable(
Isolate* isolate, Handle<OrderedHashMap> table);
@@ -472,7 +496,7 @@ template Handle<OrderedNameDictionary>
OrderedHashTable<OrderedNameDictionary, 3>::Shrink(
Isolate* isolate, Handle<OrderedNameDictionary> table);
-template Handle<OrderedNameDictionary>
+template MaybeHandle<OrderedNameDictionary>
OrderedHashTable<OrderedNameDictionary, 3>::EnsureGrowable(
Isolate* isolate, Handle<OrderedNameDictionary> table);
@@ -912,8 +936,9 @@ SmallOrderedHashTable<SmallOrderedNameDictionary>::Shrink(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table);
template <class SmallTable, class LargeTable>
-Handle<HeapObject> OrderedHashTableHandler<SmallTable, LargeTable>::Allocate(
- Isolate* isolate, int capacity) {
+MaybeHandle<HeapObject>
+OrderedHashTableHandler<SmallTable, LargeTable>::Allocate(Isolate* isolate,
+ int capacity) {
if (capacity < SmallTable::kMaxCapacity) {
return SmallTable::Allocate(isolate, capacity);
}
@@ -921,18 +946,17 @@ Handle<HeapObject> OrderedHashTableHandler<SmallTable, LargeTable>::Allocate(
return LargeTable::Allocate(isolate, capacity);
}
-template V8_EXPORT_PRIVATE Handle<HeapObject>
+template V8_EXPORT_PRIVATE MaybeHandle<HeapObject>
OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet>::Allocate(
Isolate* isolate, int capacity);
-template V8_EXPORT_PRIVATE Handle<HeapObject>
+template V8_EXPORT_PRIVATE MaybeHandle<HeapObject>
OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap>::Allocate(
Isolate* isolate, int capacity);
-template V8_EXPORT_PRIVATE Handle<HeapObject>
+template V8_EXPORT_PRIVATE MaybeHandle<HeapObject>
OrderedHashTableHandler<SmallOrderedNameDictionary,
OrderedNameDictionary>::Allocate(Isolate* isolate,
int capacity);
-#if !defined(V8_OS_WIN)
template <class SmallTable, class LargeTable>
bool OrderedHashTableHandler<SmallTable, LargeTable>::Delete(
Handle<HeapObject> table, Handle<Object> key) {
@@ -945,9 +969,7 @@ bool OrderedHashTableHandler<SmallTable, LargeTable>::Delete(
// down to a smaller hash table.
return LargeTable::Delete(Handle<LargeTable>::cast(table), key);
}
-#endif
-#if !defined(V8_OS_WIN)
template <class SmallTable, class LargeTable>
bool OrderedHashTableHandler<SmallTable, LargeTable>::HasKey(
Isolate* isolate, Handle<HeapObject> table, Handle<Object> key) {
@@ -958,7 +980,6 @@ bool OrderedHashTableHandler<SmallTable, LargeTable>::HasKey(
DCHECK(LargeTable::Is(table));
return LargeTable::HasKey(isolate, LargeTable::cast(*table), *key);
}
-#endif
template bool
OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet>::HasKey(
@@ -967,10 +988,14 @@ template bool
OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap>::HasKey(
Isolate* isolate, Handle<HeapObject> table, Handle<Object> key);
-Handle<OrderedHashMap> OrderedHashMapHandler::AdjustRepresentation(
+MaybeHandle<OrderedHashMap> OrderedHashMapHandler::AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedHashMap> table) {
- Handle<OrderedHashMap> new_table =
+ MaybeHandle<OrderedHashMap> new_table_candidate =
OrderedHashMap::Allocate(isolate, OrderedHashTableMinSize);
+ Handle<OrderedHashMap> new_table;
+ if (!new_table_candidate.ToHandle(&new_table)) {
+ return new_table_candidate;
+ }
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
@@ -982,16 +1007,23 @@ Handle<OrderedHashMap> OrderedHashMapHandler::AdjustRepresentation(
if (key->IsTheHole(isolate)) continue;
Handle<Object> value = handle(
table->GetDataEntry(entry, SmallOrderedHashMap::kValueIndex), isolate);
- new_table = OrderedHashMap::Add(isolate, new_table, key, value);
+ new_table_candidate = OrderedHashMap::Add(isolate, new_table, key, value);
+ if (!new_table_candidate.ToHandle(&new_table)) {
+ return new_table_candidate;
+ }
}
- return new_table;
+ return new_table_candidate;
}
-Handle<OrderedHashSet> OrderedHashSetHandler::AdjustRepresentation(
+MaybeHandle<OrderedHashSet> OrderedHashSetHandler::AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedHashSet> table) {
- Handle<OrderedHashSet> new_table =
+ MaybeHandle<OrderedHashSet> new_table_candidate =
OrderedHashSet::Allocate(isolate, OrderedHashTableMinSize);
+ Handle<OrderedHashSet> new_table;
+ if (!new_table_candidate.ToHandle(&new_table)) {
+ return new_table_candidate;
+ }
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
@@ -1001,17 +1033,24 @@ Handle<OrderedHashSet> OrderedHashSetHandler::AdjustRepresentation(
for (int entry = 0; entry < (nof + nod); ++entry) {
Handle<Object> key = handle(table->KeyAt(entry), isolate);
if (key->IsTheHole(isolate)) continue;
- new_table = OrderedHashSet::Add(isolate, new_table, key);
+ new_table_candidate = OrderedHashSet::Add(isolate, new_table, key);
+ if (!new_table_candidate.ToHandle(&new_table)) {
+ return new_table_candidate;
+ }
}
- return new_table;
+ return new_table_candidate;
}
-Handle<OrderedNameDictionary>
+MaybeHandle<OrderedNameDictionary>
OrderedNameDictionaryHandler::AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table) {
- Handle<OrderedNameDictionary> new_table =
+ MaybeHandle<OrderedNameDictionary> new_table_candidate =
OrderedNameDictionary::Allocate(isolate, OrderedHashTableMinSize);
+ Handle<OrderedNameDictionary> new_table;
+ if (!new_table_candidate.ToHandle(&new_table)) {
+ return new_table_candidate;
+ }
int nof = table->NumberOfElements();
int nod = table->NumberOfDeletedElements();
@@ -1023,17 +1062,20 @@ OrderedNameDictionaryHandler::AdjustRepresentation(
if (key->IsTheHole(isolate)) continue;
Handle<Object> value(table->ValueAt(entry), isolate);
PropertyDetails details = table->DetailsAt(entry);
- new_table =
+ new_table_candidate =
OrderedNameDictionary::Add(isolate, new_table, key, value, details);
+ if (!new_table_candidate.ToHandle(&new_table)) {
+ return new_table_candidate;
+ }
}
- return new_table;
+ return new_table_candidate;
}
-Handle<HeapObject> OrderedHashMapHandler::Add(Isolate* isolate,
- Handle<HeapObject> table,
- Handle<Object> key,
- Handle<Object> value) {
+MaybeHandle<HeapObject> OrderedHashMapHandler::Add(Isolate* isolate,
+ Handle<HeapObject> table,
+ Handle<Object> key,
+ Handle<Object> value) {
if (table->IsSmallOrderedHashMap()) {
Handle<SmallOrderedHashMap> small_map =
Handle<SmallOrderedHashMap>::cast(table);
@@ -1043,7 +1085,11 @@ Handle<HeapObject> OrderedHashMapHandler::Add(Isolate* isolate,
// We couldn't add to the small table, let's migrate to the
// big table.
- table = OrderedHashMapHandler::AdjustRepresentation(isolate, small_map);
+ MaybeHandle<OrderedHashMap> table_candidate =
+ OrderedHashMapHandler::AdjustRepresentation(isolate, small_map);
+ if (!table_candidate.ToHandle(&table)) {
+ return table_candidate;
+ }
}
DCHECK(table->IsOrderedHashMap());
@@ -1051,9 +1097,9 @@ Handle<HeapObject> OrderedHashMapHandler::Add(Isolate* isolate,
value);
}
-Handle<HeapObject> OrderedHashSetHandler::Add(Isolate* isolate,
- Handle<HeapObject> table,
- Handle<Object> key) {
+MaybeHandle<HeapObject> OrderedHashSetHandler::Add(Isolate* isolate,
+ Handle<HeapObject> table,
+ Handle<Object> key) {
if (table->IsSmallOrderedHashSet()) {
Handle<SmallOrderedHashSet> small_set =
Handle<SmallOrderedHashSet>::cast(table);
@@ -1063,18 +1109,20 @@ Handle<HeapObject> OrderedHashSetHandler::Add(Isolate* isolate,
// We couldn't add to the small table, let's migrate to the
// big table.
- table = OrderedHashSetHandler::AdjustRepresentation(isolate, small_set);
+ MaybeHandle<OrderedHashSet> table_candidate =
+ OrderedHashSetHandler::AdjustRepresentation(isolate, small_set);
+ if (!table_candidate.ToHandle(&table)) {
+ return table_candidate;
+ }
}
DCHECK(table->IsOrderedHashSet());
return OrderedHashSet::Add(isolate, Handle<OrderedHashSet>::cast(table), key);
}
-Handle<HeapObject> OrderedNameDictionaryHandler::Add(Isolate* isolate,
- Handle<HeapObject> table,
- Handle<Name> key,
- Handle<Object> value,
- PropertyDetails details) {
+MaybeHandle<HeapObject> OrderedNameDictionaryHandler::Add(
+ Isolate* isolate, Handle<HeapObject> table, Handle<Name> key,
+ Handle<Object> value, PropertyDetails details) {
if (table->IsSmallOrderedNameDictionary()) {
Handle<SmallOrderedNameDictionary> small_dict =
Handle<SmallOrderedNameDictionary>::cast(table);
@@ -1085,8 +1133,11 @@ Handle<HeapObject> OrderedNameDictionaryHandler::Add(Isolate* isolate,
// We couldn't add to the small table, let's migrate to the
// big table.
- table =
+ MaybeHandle<OrderedNameDictionary> table_candidate =
OrderedNameDictionaryHandler::AdjustRepresentation(isolate, small_dict);
+ if (!table_candidate.ToHandle(&table)) {
+ return table_candidate;
+ }
}
DCHECK(table->IsOrderedNameDictionary());
diff --git a/deps/v8/src/objects/ordered-hash-table.h b/deps/v8/src/objects/ordered-hash-table.h
index 66dc36e81f..21decaeba7 100644
--- a/deps/v8/src/objects/ordered-hash-table.h
+++ b/deps/v8/src/objects/ordered-hash-table.h
@@ -64,8 +64,8 @@ class OrderedHashTable : public FixedArray {
public:
// Returns an OrderedHashTable (possibly |table|) with enough space
// to add at least one new element.
- static Handle<Derived> EnsureGrowable(Isolate* isolate,
- Handle<Derived> table);
+ static MaybeHandle<Derived> EnsureGrowable(Isolate* isolate,
+ Handle<Derived> table);
// Returns an OrderedHashTable (possibly |table|) that's shrunken
// if possible.
@@ -197,11 +197,11 @@ class OrderedHashTable : public FixedArray {
protected:
// Returns an OrderedHashTable with a capacity of at least |capacity|.
- static Handle<Derived> Allocate(
+ static MaybeHandle<Derived> Allocate(
Isolate* isolate, int capacity,
AllocationType allocation = AllocationType::kYoung);
- static Handle<Derived> Rehash(Isolate* isolate, Handle<Derived> table,
- int new_capacity);
+ static MaybeHandle<Derived> Rehash(Isolate* isolate, Handle<Derived> table,
+ int new_capacity);
void SetNumberOfBuckets(int num) {
set(NumberOfBucketsIndex(), Smi::FromInt(num));
@@ -235,16 +235,16 @@ class V8_EXPORT_PRIVATE OrderedHashSet
public:
DECL_CAST(OrderedHashSet)
- static Handle<OrderedHashSet> Add(Isolate* isolate,
- Handle<OrderedHashSet> table,
- Handle<Object> value);
+ static MaybeHandle<OrderedHashSet> Add(Isolate* isolate,
+ Handle<OrderedHashSet> table,
+ Handle<Object> value);
static Handle<FixedArray> ConvertToKeysArray(Isolate* isolate,
Handle<OrderedHashSet> table,
GetKeysConversion convert);
- static Handle<OrderedHashSet> Rehash(Isolate* isolate,
- Handle<OrderedHashSet> table,
- int new_capacity);
- static Handle<OrderedHashSet> Allocate(
+ static MaybeHandle<OrderedHashSet> Rehash(Isolate* isolate,
+ Handle<OrderedHashSet> table,
+ int new_capacity);
+ static MaybeHandle<OrderedHashSet> Allocate(
Isolate* isolate, int capacity,
AllocationType allocation = AllocationType::kYoung);
static HeapObject GetEmpty(ReadOnlyRoots ro_roots);
@@ -262,16 +262,17 @@ class V8_EXPORT_PRIVATE OrderedHashMap
// Returns a value if the OrderedHashMap contains the key, otherwise
// returns undefined.
- static Handle<OrderedHashMap> Add(Isolate* isolate,
- Handle<OrderedHashMap> table,
- Handle<Object> key, Handle<Object> value);
+ static MaybeHandle<OrderedHashMap> Add(Isolate* isolate,
+ Handle<OrderedHashMap> table,
+ Handle<Object> key,
+ Handle<Object> value);
- static Handle<OrderedHashMap> Allocate(
+ static MaybeHandle<OrderedHashMap> Allocate(
Isolate* isolate, int capacity,
AllocationType allocation = AllocationType::kYoung);
- static Handle<OrderedHashMap> Rehash(Isolate* isolate,
- Handle<OrderedHashMap> table,
- int new_capacity);
+ static MaybeHandle<OrderedHashMap> Rehash(Isolate* isolate,
+ Handle<OrderedHashMap> table,
+ int new_capacity);
Object ValueAt(int entry);
// This takes and returns raw Address values containing tagged Object
@@ -656,7 +657,7 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) OrderedHashTableHandler {
public:
using Entry = int;
- static Handle<HeapObject> Allocate(Isolate* isolate, int capacity);
+ static MaybeHandle<HeapObject> Allocate(Isolate* isolate, int capacity);
static bool Delete(Handle<HeapObject> table, Handle<Object> key);
static bool HasKey(Isolate* isolate, Handle<HeapObject> table,
Handle<Object> key);
@@ -672,9 +673,9 @@ extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
class V8_EXPORT_PRIVATE OrderedHashMapHandler
: public OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap> {
public:
- static Handle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
- Handle<Object> key, Handle<Object> value);
- static Handle<OrderedHashMap> AdjustRepresentation(
+ static MaybeHandle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
+ Handle<Object> key, Handle<Object> value);
+ static MaybeHandle<OrderedHashMap> AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedHashMap> table);
};
@@ -684,9 +685,9 @@ extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
class V8_EXPORT_PRIVATE OrderedHashSetHandler
: public OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet> {
public:
- static Handle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
- Handle<Object> key);
- static Handle<OrderedHashSet> AdjustRepresentation(
+ static MaybeHandle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
+ Handle<Object> key);
+ static MaybeHandle<OrderedHashSet> AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedHashSet> table);
};
@@ -695,7 +696,7 @@ class OrderedNameDictionary
public:
DECL_CAST(OrderedNameDictionary)
- V8_EXPORT_PRIVATE static Handle<OrderedNameDictionary> Add(
+ V8_EXPORT_PRIVATE static MaybeHandle<OrderedNameDictionary> Add(
Isolate* isolate, Handle<OrderedNameDictionary> table, Handle<Name> key,
Handle<Object> value, PropertyDetails details);
@@ -705,11 +706,11 @@ class OrderedNameDictionary
V8_EXPORT_PRIVATE static Handle<OrderedNameDictionary> DeleteEntry(
Isolate* isolate, Handle<OrderedNameDictionary> table, int entry);
- static Handle<OrderedNameDictionary> Allocate(
+ static MaybeHandle<OrderedNameDictionary> Allocate(
Isolate* isolate, int capacity,
AllocationType allocation = AllocationType::kYoung);
- static Handle<OrderedNameDictionary> Rehash(
+ static MaybeHandle<OrderedNameDictionary> Rehash(
Isolate* isolate, Handle<OrderedNameDictionary> table, int new_capacity);
// Returns the value for entry.
@@ -745,9 +746,9 @@ class V8_EXPORT_PRIVATE OrderedNameDictionaryHandler
: public OrderedHashTableHandler<SmallOrderedNameDictionary,
OrderedNameDictionary> {
public:
- static Handle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
- Handle<Name> key, Handle<Object> value,
- PropertyDetails details);
+ static MaybeHandle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
+ Handle<Name> key, Handle<Object> value,
+ PropertyDetails details);
static Handle<HeapObject> Shrink(Isolate* isolate, Handle<HeapObject> table);
static Handle<HeapObject> DeleteEntry(Isolate* isolate,
@@ -779,7 +780,7 @@ class V8_EXPORT_PRIVATE OrderedNameDictionaryHandler
static const int kNotFound = -1;
protected:
- static Handle<OrderedNameDictionary> AdjustRepresentation(
+ static MaybeHandle<OrderedNameDictionary> AdjustRepresentation(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table);
};
diff --git a/deps/v8/src/objects/promise-inl.h b/deps/v8/src/objects/promise-inl.h
index 6807ac88f4..da11731e25 100644
--- a/deps/v8/src/objects/promise-inl.h
+++ b/deps/v8/src/objects/promise-inl.h
@@ -16,41 +16,12 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(PromiseReactionJobTask, Microtask)
-OBJECT_CONSTRUCTORS_IMPL(PromiseFulfillReactionJobTask, PromiseReactionJobTask)
-OBJECT_CONSTRUCTORS_IMPL(PromiseRejectReactionJobTask, PromiseReactionJobTask)
-OBJECT_CONSTRUCTORS_IMPL(PromiseResolveThenableJobTask, Microtask)
-OBJECT_CONSTRUCTORS_IMPL(PromiseCapability, Struct)
-OBJECT_CONSTRUCTORS_IMPL(PromiseReaction, Struct)
-
-CAST_ACCESSOR(PromiseCapability)
-CAST_ACCESSOR(PromiseReaction)
-CAST_ACCESSOR(PromiseReactionJobTask)
-CAST_ACCESSOR(PromiseFulfillReactionJobTask)
-CAST_ACCESSOR(PromiseRejectReactionJobTask)
-CAST_ACCESSOR(PromiseResolveThenableJobTask)
-
-ACCESSORS(PromiseReaction, next, Object, kNextOffset)
-ACCESSORS(PromiseReaction, reject_handler, HeapObject, kRejectHandlerOffset)
-ACCESSORS(PromiseReaction, fulfill_handler, HeapObject, kFulfillHandlerOffset)
-ACCESSORS(PromiseReaction, promise_or_capability, HeapObject,
- kPromiseOrCapabilityOffset)
-
-ACCESSORS(PromiseResolveThenableJobTask, context, Context, kContextOffset)
-ACCESSORS(PromiseResolveThenableJobTask, promise_to_resolve, JSPromise,
- kPromiseToResolveOffset)
-ACCESSORS(PromiseResolveThenableJobTask, then, JSReceiver, kThenOffset)
-ACCESSORS(PromiseResolveThenableJobTask, thenable, JSReceiver, kThenableOffset)
-
-ACCESSORS(PromiseReactionJobTask, context, Context, kContextOffset)
-ACCESSORS(PromiseReactionJobTask, argument, Object, kArgumentOffset)
-ACCESSORS(PromiseReactionJobTask, handler, HeapObject, kHandlerOffset)
-ACCESSORS(PromiseReactionJobTask, promise_or_capability, HeapObject,
- kPromiseOrCapabilityOffset)
-
-ACCESSORS(PromiseCapability, promise, HeapObject, kPromiseOffset)
-ACCESSORS(PromiseCapability, resolve, Object, kResolveOffset)
-ACCESSORS(PromiseCapability, reject, Object, kRejectOffset)
+TQ_OBJECT_CONSTRUCTORS_IMPL(PromiseReactionJobTask)
+TQ_OBJECT_CONSTRUCTORS_IMPL(PromiseFulfillReactionJobTask)
+TQ_OBJECT_CONSTRUCTORS_IMPL(PromiseRejectReactionJobTask)
+TQ_OBJECT_CONSTRUCTORS_IMPL(PromiseResolveThenableJobTask)
+TQ_OBJECT_CONSTRUCTORS_IMPL(PromiseCapability)
+TQ_OBJECT_CONSTRUCTORS_IMPL(PromiseReaction)
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/promise.h b/deps/v8/src/objects/promise.h
index f7c60413d1..2582543f77 100644
--- a/deps/v8/src/objects/promise.h
+++ b/deps/v8/src/objects/promise.h
@@ -24,93 +24,59 @@ class JSPromise;
//
// classes, which are used to represent either reactions, and we distinguish
// them by their instance types.
-class PromiseReactionJobTask : public Microtask {
+class PromiseReactionJobTask
+ : public TorqueGeneratedPromiseReactionJobTask<PromiseReactionJobTask,
+ Microtask> {
public:
- DECL_ACCESSORS(argument, Object)
- DECL_ACCESSORS(context, Context)
- DECL_ACCESSORS(handler, HeapObject)
- // [promise_or_capability]: Either a JSPromise (in case of native promises),
- // a PromiseCapability (general case), or undefined (in case of await).
- DECL_ACCESSORS(promise_or_capability, HeapObject)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(
- Microtask::kHeaderSize, TORQUE_GENERATED_PROMISE_REACTION_JOB_TASK_FIELDS)
-
- // Dispatched behavior.
- DECL_CAST(PromiseReactionJobTask)
- DECL_VERIFIER(PromiseReactionJobTask)
static const int kSizeOfAllPromiseReactionJobTasks = kHeaderSize;
- OBJECT_CONSTRUCTORS(PromiseReactionJobTask, Microtask);
+ TQ_OBJECT_CONSTRUCTORS(PromiseReactionJobTask)
};
// Struct to hold state required for a PromiseReactionJob of type "Fulfill".
-class PromiseFulfillReactionJobTask : public PromiseReactionJobTask {
+class PromiseFulfillReactionJobTask
+ : public TorqueGeneratedPromiseFulfillReactionJobTask<
+ PromiseFulfillReactionJobTask, PromiseReactionJobTask> {
public:
// Dispatched behavior.
- DECL_CAST(PromiseFulfillReactionJobTask)
DECL_PRINTER(PromiseFulfillReactionJobTask)
- DECL_VERIFIER(PromiseFulfillReactionJobTask)
- DEFINE_FIELD_OFFSET_CONSTANTS(
- PromiseReactionJobTask::kHeaderSize,
- TORQUE_GENERATED_PROMISE_FULFILL_REACTION_JOB_TASK_FIELDS)
STATIC_ASSERT(kSize == kSizeOfAllPromiseReactionJobTasks);
- OBJECT_CONSTRUCTORS(PromiseFulfillReactionJobTask, PromiseReactionJobTask);
+ TQ_OBJECT_CONSTRUCTORS(PromiseFulfillReactionJobTask)
};
// Struct to hold state required for a PromiseReactionJob of type "Reject".
-class PromiseRejectReactionJobTask : public PromiseReactionJobTask {
+class PromiseRejectReactionJobTask
+ : public TorqueGeneratedPromiseRejectReactionJobTask<
+ PromiseRejectReactionJobTask, PromiseReactionJobTask> {
public:
// Dispatched behavior.
- DECL_CAST(PromiseRejectReactionJobTask)
DECL_PRINTER(PromiseRejectReactionJobTask)
- DECL_VERIFIER(PromiseRejectReactionJobTask)
- DEFINE_FIELD_OFFSET_CONSTANTS(
- PromiseReactionJobTask::kHeaderSize,
- TORQUE_GENERATED_PROMISE_REJECT_REACTION_JOB_TASK_FIELDS)
STATIC_ASSERT(kSize == kSizeOfAllPromiseReactionJobTasks);
- OBJECT_CONSTRUCTORS(PromiseRejectReactionJobTask, PromiseReactionJobTask);
+ TQ_OBJECT_CONSTRUCTORS(PromiseRejectReactionJobTask)
};
// A container struct to hold state required for PromiseResolveThenableJob.
-class PromiseResolveThenableJobTask : public Microtask {
+class PromiseResolveThenableJobTask
+ : public TorqueGeneratedPromiseResolveThenableJobTask<
+ PromiseResolveThenableJobTask, Microtask> {
public:
- DECL_ACCESSORS(context, Context)
- DECL_ACCESSORS(promise_to_resolve, JSPromise)
- DECL_ACCESSORS(then, JSReceiver)
- DECL_ACCESSORS(thenable, JSReceiver)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(
- Microtask::kHeaderSize,
- TORQUE_GENERATED_PROMISE_RESOLVE_THENABLE_JOB_TASK_FIELDS)
-
// Dispatched behavior.
- DECL_CAST(PromiseResolveThenableJobTask)
DECL_PRINTER(PromiseResolveThenableJobTask)
- DECL_VERIFIER(PromiseResolveThenableJobTask)
- OBJECT_CONSTRUCTORS(PromiseResolveThenableJobTask, Microtask);
+ TQ_OBJECT_CONSTRUCTORS(PromiseResolveThenableJobTask)
};
// Struct to hold the state of a PromiseCapability.
-class PromiseCapability : public Struct {
+class PromiseCapability
+ : public TorqueGeneratedPromiseCapability<PromiseCapability, Struct> {
public:
- DECL_ACCESSORS(promise, HeapObject)
- DECL_ACCESSORS(resolve, Object)
- DECL_ACCESSORS(reject, Object)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize,
- TORQUE_GENERATED_PROMISE_CAPABILITY_FIELDS)
-
// Dispatched behavior.
- DECL_CAST(PromiseCapability)
DECL_PRINTER(PromiseCapability)
- DECL_VERIFIER(PromiseCapability)
- OBJECT_CONSTRUCTORS(PromiseCapability, Struct);
+ TQ_OBJECT_CONSTRUCTORS(PromiseCapability)
};
// A representation of promise reaction. This differs from the specification
@@ -130,26 +96,15 @@ class PromiseCapability : public Struct {
// Smi 0. On the JSPromise instance they are linked in reverse order,
// and are turned into the proper order again when scheduling them on
// the microtask queue.
-class PromiseReaction : public Struct {
+class PromiseReaction
+ : public TorqueGeneratedPromiseReaction<PromiseReaction, Struct> {
public:
enum Type { kFulfill, kReject };
- DECL_ACCESSORS(next, Object)
- DECL_ACCESSORS(reject_handler, HeapObject)
- DECL_ACCESSORS(fulfill_handler, HeapObject)
- // [promise_or_capability]: Either a JSPromise (in case of native promises),
- // a PromiseCapability (general case), or undefined (in case of await).
- DECL_ACCESSORS(promise_or_capability, HeapObject)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize,
- TORQUE_GENERATED_PROMISE_REACTION_FIELDS)
-
// Dispatched behavior.
- DECL_CAST(PromiseReaction)
DECL_PRINTER(PromiseReaction)
- DECL_VERIFIER(PromiseReaction)
- OBJECT_CONSTRUCTORS(PromiseReaction, Struct);
+ TQ_OBJECT_CONSTRUCTORS(PromiseReaction)
};
} // namespace internal
diff --git a/deps/v8/src/objects/property-array.h b/deps/v8/src/objects/property-array.h
index 5c71330280..62a472aa90 100644
--- a/deps/v8/src/objects/property-array.h
+++ b/deps/v8/src/objects/property-array.h
@@ -61,10 +61,10 @@ class PropertyArray : public HeapObject {
using BodyDescriptor = FlexibleBodyDescriptor<kHeaderSize>;
static const int kLengthFieldSize = 10;
- class LengthField : public BitField<int, 0, kLengthFieldSize> {};
+ using LengthField = BitField<int, 0, kLengthFieldSize>;
static const int kMaxLength = LengthField::kMax;
- class HashField : public BitField<int, kLengthFieldSize,
- kSmiValueSize - kLengthFieldSize - 1> {};
+ using HashField =
+ BitField<int, kLengthFieldSize, kSmiValueSize - kLengthFieldSize - 1>;
static const int kNoHashSentinel = 0;
diff --git a/deps/v8/src/objects/property-details.h b/deps/v8/src/objects/property-details.h
index 7836575edf..e350fe2c27 100644
--- a/deps/v8/src/objects/property-details.h
+++ b/deps/v8/src/objects/property-details.h
@@ -310,13 +310,10 @@ class PropertyDetails {
// Bit fields in value_ (type, shift, size). Must be public so the
// constants can be embedded in generated code.
- class KindField : public BitField<PropertyKind, 0, 1> {};
- class LocationField : public BitField<PropertyLocation, KindField::kNext, 1> {
- };
- class ConstnessField
- : public BitField<PropertyConstness, LocationField::kNext, 1> {};
- class AttributesField
- : public BitField<PropertyAttributes, ConstnessField::kNext, 3> {};
+ using KindField = BitField<PropertyKind, 0, 1>;
+ using LocationField = KindField::Next<PropertyLocation, 1>;
+ using ConstnessField = LocationField::Next<PropertyConstness, 1>;
+ using AttributesField = ConstnessField::Next<PropertyAttributes, 3>;
static const int kAttributesReadOnlyMask =
(READ_ONLY << AttributesField::kShift);
static const int kAttributesDontDeleteMask =
@@ -325,24 +322,19 @@ class PropertyDetails {
(DONT_ENUM << AttributesField::kShift);
// Bit fields for normalized objects.
- class PropertyCellTypeField
- : public BitField<PropertyCellType, AttributesField::kNext, 2> {};
- class DictionaryStorageField
- : public BitField<uint32_t, PropertyCellTypeField::kNext, 23> {};
+ using PropertyCellTypeField = AttributesField::Next<PropertyCellType, 2>;
+ using DictionaryStorageField = PropertyCellTypeField::Next<uint32_t, 23>;
// Bit fields for fast objects.
- class RepresentationField
- : public BitField<uint32_t, AttributesField::kNext, 3> {};
- class DescriptorPointer
- : public BitField<uint32_t, RepresentationField::kNext,
- kDescriptorIndexBitCount> {}; // NOLINT
- class FieldIndexField : public BitField<uint32_t, DescriptorPointer::kNext,
- kDescriptorIndexBitCount> {
- }; // NOLINT
+ using RepresentationField = AttributesField::Next<uint32_t, 3>;
+ using DescriptorPointer =
+ RepresentationField::Next<uint32_t, kDescriptorIndexBitCount>;
+ using FieldIndexField =
+ DescriptorPointer::Next<uint32_t, kDescriptorIndexBitCount>;
// All bits for both fast and slow objects must fit in a smi.
- STATIC_ASSERT(DictionaryStorageField::kNext <= 31);
- STATIC_ASSERT(FieldIndexField::kNext <= 31);
+ STATIC_ASSERT(DictionaryStorageField::kLastUsedBit < 31);
+ STATIC_ASSERT(FieldIndexField::kLastUsedBit < 31);
static const int kInitialIndex = 1;
diff --git a/deps/v8/src/objects/scope-info.cc b/deps/v8/src/objects/scope-info.cc
index eca8bc1ecd..c390298b5d 100644
--- a/deps/v8/src/objects/scope-info.cc
+++ b/deps/v8/src/objects/scope-info.cc
@@ -166,7 +166,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
bool has_simple_parameters = false;
bool is_asm_module = false;
- bool calls_sloppy_eval = false;
+ bool sloppy_eval_can_extend_vars = false;
if (scope->is_function_scope()) {
DeclarationScope* function_scope = scope->AsDeclarationScope();
has_simple_parameters = function_scope->has_simple_parameters();
@@ -175,13 +175,14 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
FunctionKind function_kind = kNormalFunction;
if (scope->is_declaration_scope()) {
function_kind = scope->AsDeclarationScope()->function_kind();
- calls_sloppy_eval = scope->AsDeclarationScope()->calls_sloppy_eval();
+ sloppy_eval_can_extend_vars =
+ scope->AsDeclarationScope()->sloppy_eval_can_extend_vars();
}
// Encode the flags.
int flags =
ScopeTypeField::encode(scope->scope_type()) |
- CallsSloppyEvalField::encode(calls_sloppy_eval) |
+ SloppyEvalCanExtendVarsField::encode(sloppy_eval_can_extend_vars) |
LanguageModeField::encode(scope->language_mode()) |
DeclarationScopeField::encode(scope->is_declaration_scope()) |
ReceiverVariableField::encode(receiver_info) |
@@ -218,8 +219,6 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
uint32_t info =
VariableModeField::encode(var->mode()) |
InitFlagField::encode(var->initialization_flag()) |
- RequiresBrandCheckField::encode(
- var->get_requires_brand_check_flag()) |
MaybeAssignedFlagField::encode(var->maybe_assigned()) |
ParameterNumberField::encode(ParameterNumberField::kMax);
scope_info.set(context_local_base + local_index, *var->name(), mode);
@@ -236,8 +235,6 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
VariableModeField::encode(var->mode()) |
InitFlagField::encode(var->initialization_flag()) |
MaybeAssignedFlagField::encode(var->maybe_assigned()) |
- RequiresBrandCheckField::encode(
- var->get_requires_brand_check_flag()) |
ParameterNumberField::encode(ParameterNumberField::kMax);
scope_info.set(module_var_entry + kModuleVariablePropertiesOffset,
Smi::FromInt(properties));
@@ -276,8 +273,6 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
VariableModeField::encode(var->mode()) |
InitFlagField::encode(var->initialization_flag()) |
MaybeAssignedFlagField::encode(var->maybe_assigned()) |
- RequiresBrandCheckField::encode(
- var->get_requires_brand_check_flag()) |
ParameterNumberField::encode(ParameterNumberField::kMax);
scope_info.set(context_local_base + local_index, *var->name(), mode);
scope_info.set(context_local_info_base + local_index,
@@ -362,7 +357,8 @@ Handle<ScopeInfo> ScopeInfo::CreateForWithScope(
// Encode the flags.
int flags =
- ScopeTypeField::encode(WITH_SCOPE) | CallsSloppyEvalField::encode(false) |
+ ScopeTypeField::encode(WITH_SCOPE) |
+ SloppyEvalCanExtendVarsField::encode(false) |
LanguageModeField::encode(LanguageMode::kSloppy) |
DeclarationScopeField::encode(false) |
ReceiverVariableField::encode(NONE) | HasClassBrandField::encode(false) |
@@ -419,11 +415,13 @@ Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate,
(has_position_info ? kPositionInfoEntries : 0);
Factory* factory = isolate->factory();
- Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
+ Handle<ScopeInfo> scope_info =
+ factory->NewScopeInfo(length, AllocationType::kReadOnly);
// Encode the flags.
int flags =
- ScopeTypeField::encode(type) | CallsSloppyEvalField::encode(false) |
+ ScopeTypeField::encode(type) |
+ SloppyEvalCanExtendVarsField::encode(false) |
LanguageModeField::encode(LanguageMode::kSloppy) |
DeclarationScopeField::encode(true) |
ReceiverVariableField::encode(is_empty_function ? UNUSED : CONTEXT) |
@@ -451,7 +449,6 @@ Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate,
VariableModeField::encode(VariableMode::kConst) |
InitFlagField::encode(kCreatedInitialized) |
MaybeAssignedFlagField::encode(kNotAssigned) |
- RequiresBrandCheckField::encode(kNoBrandCheck) |
ParameterNumberField::encode(ParameterNumberField::kMax);
scope_info->set(index++, Smi::FromInt(value));
}
@@ -497,12 +494,12 @@ ScopeType ScopeInfo::scope_type() const {
return ScopeTypeField::decode(Flags());
}
-bool ScopeInfo::CallsSloppyEval() const {
- bool calls_sloppy_eval =
- length() > 0 && CallsSloppyEvalField::decode(Flags());
- DCHECK_IMPLIES(calls_sloppy_eval, is_sloppy(language_mode()));
- DCHECK_IMPLIES(calls_sloppy_eval, is_declaration_scope());
- return calls_sloppy_eval;
+bool ScopeInfo::SloppyEvalCanExtendVars() const {
+ bool sloppy_eval_can_extend_vars =
+ length() > 0 && SloppyEvalCanExtendVarsField::decode(Flags());
+ DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_sloppy(language_mode()));
+ DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_declaration_scope());
+ return sloppy_eval_can_extend_vars;
}
LanguageMode ScopeInfo::language_mode() const {
@@ -523,9 +520,9 @@ int ScopeInfo::ContextLength() const {
bool has_context =
context_locals > 0 || force_context || function_name_context_slot ||
scope_type() == WITH_SCOPE || scope_type() == CLASS_SCOPE ||
- (scope_type() == BLOCK_SCOPE && CallsSloppyEval() &&
+ (scope_type() == BLOCK_SCOPE && SloppyEvalCanExtendVars() &&
is_declaration_scope()) ||
- (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) ||
+ (scope_type() == FUNCTION_SCOPE && SloppyEvalCanExtendVars()) ||
(scope_type() == FUNCTION_SCOPE && IsAsmModule()) ||
scope_type() == MODULE_SCOPE;
@@ -708,21 +705,13 @@ MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) const {
return MaybeAssignedFlagField::decode(value);
}
-RequiresBrandCheckFlag ScopeInfo::RequiresBrandCheck(int var) const {
- DCHECK_LE(0, var);
- DCHECK_LT(var, ContextLocalCount());
- int info_index = ContextLocalInfosIndex() + var;
- int value = Smi::ToInt(get(info_index));
- return RequiresBrandCheckField::decode(value);
-}
-
// static
bool ScopeInfo::VariableIsSynthetic(String name) {
// There's currently no flag stored on the ScopeInfo to indicate that a
// variable is a compiler-introduced temporary. However, to avoid conflict
// with user declarations, the current temporaries like .generator_object and
// .result start with a dot, so we can use that as a flag. It's a hack!
- return name.length() == 0 || name.Get(0) == '.' ||
+ return name.length() == 0 || name.Get(0) == '.' || name.Get(0) == '#' ||
name.Equals(name.GetReadOnlyRoots().this_string());
}
@@ -755,8 +744,7 @@ int ScopeInfo::ModuleIndex(String name, VariableMode* mode,
int ScopeInfo::ContextSlotIndex(ScopeInfo scope_info, String name,
VariableMode* mode,
InitializationFlag* init_flag,
- MaybeAssignedFlag* maybe_assigned_flag,
- RequiresBrandCheckFlag* requires_brand_check) {
+ MaybeAssignedFlag* maybe_assigned_flag) {
DisallowHeapAllocation no_gc;
DCHECK(name.IsInternalizedString());
DCHECK_NOT_NULL(mode);
@@ -773,7 +761,6 @@ int ScopeInfo::ContextSlotIndex(ScopeInfo scope_info, String name,
*mode = scope_info.ContextLocalMode(var);
*init_flag = scope_info.ContextLocalInitFlag(var);
*maybe_assigned_flag = scope_info.ContextLocalMaybeAssignedFlag(var);
- *requires_brand_check = scope_info.RequiresBrandCheck(var);
int result = Context::MIN_CONTEXT_SLOTS + var;
DCHECK_LT(result, scope_info.ContextLength());
@@ -892,9 +879,9 @@ std::ostream& operator<<(std::ostream& os,
}
Handle<SourceTextModuleInfoEntry> SourceTextModuleInfoEntry::New(
- Isolate* isolate, Handle<Object> export_name, Handle<Object> local_name,
- Handle<Object> import_name, int module_request, int cell_index, int beg_pos,
- int end_pos) {
+ Isolate* isolate, Handle<HeapObject> export_name,
+ Handle<HeapObject> local_name, Handle<HeapObject> import_name,
+ int module_request, int cell_index, int beg_pos, int end_pos) {
Handle<SourceTextModuleInfoEntry> result =
Handle<SourceTextModuleInfoEntry>::cast(isolate->factory()->NewStruct(
SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, AllocationType::kOld));
diff --git a/deps/v8/src/objects/scope-info.h b/deps/v8/src/objects/scope-info.h
index 0b8eb61b00..123b9b1797 100644
--- a/deps/v8/src/objects/scope-info.h
+++ b/deps/v8/src/objects/scope-info.h
@@ -51,7 +51,7 @@ class ScopeInfo : public FixedArray {
bool is_class_scope() const;
// Does this scope make a sloppy eval call?
- bool CallsSloppyEval() const;
+ bool SloppyEvalCanExtendVars() const;
// Return the number of context slots for code if a context is allocated. This
// number consists of three parts:
@@ -130,9 +130,6 @@ class ScopeInfo : public FixedArray {
// Return the initialization flag of the given context local.
MaybeAssignedFlag ContextLocalMaybeAssignedFlag(int var) const;
- // Return whether access to the variable requries a brand check.
- RequiresBrandCheckFlag RequiresBrandCheck(int var) const;
-
// Return true if this local was introduced by the compiler, and should not be
// exposed to the user in a debugger.
static bool VariableIsSynthetic(String name);
@@ -144,8 +141,7 @@ class ScopeInfo : public FixedArray {
// mode for that variable.
static int ContextSlotIndex(ScopeInfo scope_info, String name,
VariableMode* mode, InitializationFlag* init_flag,
- MaybeAssignedFlag* maybe_assigned_flag,
- RequiresBrandCheckFlag* requires_brand_check);
+ MaybeAssignedFlag* maybe_assigned_flag);
// Lookup metadata of a MODULE-allocated variable. Return 0 if there is no
// module variable with the given name (the index value of a MODULE variable
@@ -224,39 +220,26 @@ class ScopeInfo : public FixedArray {
enum VariableAllocationInfo { NONE, STACK, CONTEXT, UNUSED };
// Properties of scopes.
- class ScopeTypeField : public BitField<ScopeType, 0, 4> {};
- class CallsSloppyEvalField : public BitField<bool, ScopeTypeField::kNext, 1> {
- };
+ using ScopeTypeField = BitField<ScopeType, 0, 4>;
+ using SloppyEvalCanExtendVarsField = ScopeTypeField::Next<bool, 1>;
STATIC_ASSERT(LanguageModeSize == 2);
- class LanguageModeField
- : public BitField<LanguageMode, CallsSloppyEvalField::kNext, 1> {};
- class DeclarationScopeField
- : public BitField<bool, LanguageModeField::kNext, 1> {};
- class ReceiverVariableField
- : public BitField<VariableAllocationInfo, DeclarationScopeField::kNext,
- 2> {};
- class HasClassBrandField
- : public BitField<bool, ReceiverVariableField::kNext, 1> {};
- class HasNewTargetField
- : public BitField<bool, HasClassBrandField::kNext, 1> {};
- class FunctionVariableField
- : public BitField<VariableAllocationInfo, HasNewTargetField::kNext, 2> {};
+ using LanguageModeField = SloppyEvalCanExtendVarsField::Next<LanguageMode, 1>;
+ using DeclarationScopeField = LanguageModeField::Next<bool, 1>;
+ using ReceiverVariableField =
+ DeclarationScopeField::Next<VariableAllocationInfo, 2>;
+ using HasClassBrandField = ReceiverVariableField::Next<bool, 1>;
+ using HasNewTargetField = HasClassBrandField::Next<bool, 1>;
+ using FunctionVariableField =
+ HasNewTargetField::Next<VariableAllocationInfo, 2>;
// TODO(cbruni): Combine with function variable field when only storing the
// function name.
- class HasInferredFunctionNameField
- : public BitField<bool, FunctionVariableField::kNext, 1> {};
- class IsAsmModuleField
- : public BitField<bool, HasInferredFunctionNameField::kNext, 1> {};
- class HasSimpleParametersField
- : public BitField<bool, IsAsmModuleField::kNext, 1> {};
- class FunctionKindField
- : public BitField<FunctionKind, HasSimpleParametersField::kNext, 5> {};
- class HasOuterScopeInfoField
- : public BitField<bool, FunctionKindField::kNext, 1> {};
- class IsDebugEvaluateScopeField
- : public BitField<bool, HasOuterScopeInfoField::kNext, 1> {};
- class ForceContextAllocationField
- : public BitField<bool, IsDebugEvaluateScopeField::kNext, 1> {};
+ using HasInferredFunctionNameField = FunctionVariableField::Next<bool, 1>;
+ using IsAsmModuleField = HasInferredFunctionNameField::Next<bool, 1>;
+ using HasSimpleParametersField = IsAsmModuleField::Next<bool, 1>;
+ using FunctionKindField = HasSimpleParametersField::Next<FunctionKind, 5>;
+ using HasOuterScopeInfoField = FunctionKindField::Next<bool, 1>;
+ using IsDebugEvaluateScopeField = HasOuterScopeInfoField::Next<bool, 1>;
+ using ForceContextAllocationField = IsDebugEvaluateScopeField::Next<bool, 1>;
STATIC_ASSERT(kLastFunctionKind <= FunctionKindField::kMax);
@@ -323,14 +306,10 @@ class ScopeInfo : public FixedArray {
static const int kPositionInfoEntries = 2;
// Properties of variables.
- class VariableModeField : public BitField<VariableMode, 0, 3> {};
- class InitFlagField : public BitField<InitializationFlag, 3, 1> {};
- class MaybeAssignedFlagField : public BitField<MaybeAssignedFlag, 4, 1> {};
- class RequiresBrandCheckField
- : public BitField<RequiresBrandCheckFlag, MaybeAssignedFlagField::kNext,
- 1> {};
- class ParameterNumberField
- : public BitField<uint32_t, RequiresBrandCheckField::kNext, 16> {};
+ using VariableModeField = BitField<VariableMode, 0, 4>;
+ using InitFlagField = VariableModeField::Next<InitializationFlag, 1>;
+ using MaybeAssignedFlagField = InitFlagField::Next<MaybeAssignedFlag, 1>;
+ using ParameterNumberField = MaybeAssignedFlagField::Next<uint32_t, 16>;
friend class ScopeIterator;
friend std::ostream& operator<<(std::ostream& os,
diff --git a/deps/v8/src/objects/shared-function-info-inl.h b/deps/v8/src/objects/shared-function-info-inl.h
index 9778db5d90..6023c3b828 100644
--- a/deps/v8/src/objects/shared-function-info-inl.h
+++ b/deps/v8/src/objects/shared-function-info-inl.h
@@ -200,14 +200,13 @@ int SharedFunctionInfo::function_token_position() const {
}
}
-BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_wrapped,
- SharedFunctionInfo::IsWrappedBit)
+BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, syntax_kind,
+ SharedFunctionInfo::FunctionSyntaxKindBits)
+
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, allows_lazy_compilation,
SharedFunctionInfo::AllowLazyCompilationBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, has_duplicate_parameters,
SharedFunctionInfo::HasDuplicateParametersBit)
-BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_declaration,
- SharedFunctionInfo::IsDeclarationBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, native,
SharedFunctionInfo::IsNativeBit)
@@ -219,13 +218,9 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags,
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, name_should_print_as_anonymous,
SharedFunctionInfo::NameShouldPrintAsAnonymousBit)
-BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_anonymous_expression,
- SharedFunctionInfo::IsAnonymousExpressionBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, has_reported_binary_coverage,
SharedFunctionInfo::HasReportedBinaryCoverageBit)
-BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_named_expression,
- SharedFunctionInfo::IsNamedExpressionBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_toplevel,
SharedFunctionInfo::IsTopLevelBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags,
@@ -271,6 +266,10 @@ void SharedFunctionInfo::set_kind(FunctionKind kind) {
UpdateFunctionMapIndex();
}
+bool SharedFunctionInfo::is_wrapped() const {
+ return syntax_kind() == FunctionSyntaxKind::kWrapped;
+}
+
bool SharedFunctionInfo::needs_home_object() const {
return NeedsHomeObjectBit::decode(flags());
}
@@ -359,6 +358,11 @@ void SharedFunctionInfo::set_scope_info(ScopeInfo scope_info,
if (HasInferredName() && inferred_name().length() != 0) {
scope_info.SetInferredFunctionName(inferred_name());
}
+ set_raw_scope_info(scope_info, mode);
+}
+
+void SharedFunctionInfo::set_raw_scope_info(ScopeInfo scope_info,
+ WriteBarrierMode mode) {
WRITE_FIELD(*this, kNameOrScopeInfoOffset, scope_info);
CONDITIONAL_WRITE_BARRIER(*this, kNameOrScopeInfoOffset, scope_info, mode);
}
@@ -572,7 +576,8 @@ UncompiledData SharedFunctionInfo::uncompiled_data() const {
}
void SharedFunctionInfo::set_uncompiled_data(UncompiledData uncompiled_data) {
- DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy));
+ DCHECK(function_data() == Smi::FromEnum(Builtins::kCompileLazy) ||
+ HasUncompiledData());
DCHECK(uncompiled_data.IsUncompiledData());
set_function_data(uncompiled_data);
}
@@ -622,7 +627,7 @@ void SharedFunctionInfo::ClearPreparseData() {
data.address() + UncompiledDataWithoutPreparseData::kSize,
UncompiledDataWithPreparseData::kSize -
UncompiledDataWithoutPreparseData::kSize,
- ClearRecordedSlots::kNo);
+ ClearRecordedSlots::kYes);
// Ensure that the clear was successful.
DCHECK(HasUncompiledDataWithoutPreparseData());
diff --git a/deps/v8/src/objects/shared-function-info.h b/deps/v8/src/objects/shared-function-info.h
index f7a82964b1..dc84653ede 100644
--- a/deps/v8/src/objects/shared-function-info.h
+++ b/deps/v8/src/objects/shared-function-info.h
@@ -8,6 +8,7 @@
#include "src/codegen/bailout-reason.h"
#include "src/objects/compressed-slots.h"
#include "src/objects/function-kind.h"
+#include "src/objects/function-syntax-kind.h"
#include "src/objects/objects.h"
#include "src/objects/script.h"
#include "src/objects/slots.h"
@@ -256,6 +257,10 @@ class SharedFunctionInfo : public HeapObject {
// [scope_info]: Scope info.
DECL_ACCESSORS(scope_info, ScopeInfo)
+ // Set scope_info without moving the existing name onto the ScopeInfo.
+ inline void set_raw_scope_info(ScopeInfo scope_info,
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
// End position of this function in the script source.
V8_EXPORT_PRIVATE int EndPosition() const;
@@ -429,9 +434,6 @@ class SharedFunctionInfo : public HeapObject {
// [flags] Bit field containing various flags about the function.
DECL_INT32_ACCESSORS(flags)
- // Is this function a named function expression in the source code.
- DECL_BOOLEAN_ACCESSORS(is_named_expression)
-
// Is this function a top-level function (scripts, evals).
DECL_BOOLEAN_ACCESSORS(is_toplevel)
@@ -442,8 +444,11 @@ class SharedFunctionInfo : public HeapObject {
inline LanguageMode language_mode() const;
inline void set_language_mode(LanguageMode language_mode);
+ // How the function appears in source text.
+ DECL_PRIMITIVE_ACCESSORS(syntax_kind, FunctionSyntaxKind)
+
// Indicates whether the source is implicitly wrapped in a function.
- DECL_BOOLEAN_ACCESSORS(is_wrapped)
+ inline bool is_wrapped() const;
// True if the function has any duplicated parameter names.
DECL_BOOLEAN_ACCESSORS(has_duplicate_parameters)
@@ -454,9 +459,6 @@ class SharedFunctionInfo : public HeapObject {
// global object.
DECL_BOOLEAN_ACCESSORS(native)
- // Whether this function was created from a FunctionDeclaration.
- DECL_BOOLEAN_ACCESSORS(is_declaration)
-
// Indicates that asm->wasm conversion failed and should not be re-attempted.
DECL_BOOLEAN_ACCESSORS(is_asm_wasm_broken)
@@ -466,11 +468,6 @@ class SharedFunctionInfo : public HeapObject {
// see a binding for it.
DECL_BOOLEAN_ACCESSORS(name_should_print_as_anonymous)
- // Indicates that the function is either an anonymous expression
- // or an arrow function (the name field can be set through the API,
- // which does not change this flag).
- DECL_BOOLEAN_ACCESSORS(is_anonymous_expression)
-
// Indicates that the function represented by the shared function info was
// classed as an immediately invoked function execution (IIFE) function and
// is only executed once.
@@ -680,21 +677,18 @@ class SharedFunctionInfo : public HeapObject {
V(FunctionKindBits, FunctionKind, 5, _) \
V(IsNativeBit, bool, 1, _) \
V(IsStrictBit, bool, 1, _) \
- V(IsWrappedBit, bool, 1, _) \
+ V(FunctionSyntaxKindBits, FunctionSyntaxKind, 3, _) \
V(IsClassConstructorBit, bool, 1, _) \
V(HasDuplicateParametersBit, bool, 1, _) \
V(AllowLazyCompilationBit, bool, 1, _) \
V(NeedsHomeObjectBit, bool, 1, _) \
- V(IsDeclarationBit, bool, 1, _) \
V(IsAsmWasmBrokenBit, bool, 1, _) \
V(FunctionMapIndexBits, int, 5, _) \
V(DisabledOptimizationReasonBits, BailoutReason, 4, _) \
V(RequiresInstanceMembersInitializer, bool, 1, _) \
V(ConstructAsBuiltinBit, bool, 1, _) \
- V(IsAnonymousExpressionBit, bool, 1, _) \
V(NameShouldPrintAsAnonymousBit, bool, 1, _) \
V(HasReportedBinaryCoverageBit, bool, 1, _) \
- V(IsNamedExpressionBit, bool, 1, _) \
V(IsTopLevelBit, bool, 1, _) \
V(IsOneshotIIFEOrPropertiesAreFinalBit, bool, 1, _) \
V(IsSafeToSkipArgumentsAdaptorBit, bool, 1, _)
@@ -706,6 +700,8 @@ class SharedFunctionInfo : public HeapObject {
DisabledOptimizationReasonBits::kMax);
STATIC_ASSERT(kLastFunctionKind <= FunctionKindBits::kMax);
+ STATIC_ASSERT(FunctionSyntaxKind::kLastFunctionSyntaxKind <=
+ FunctionSyntaxKindBits::kMax);
// Indicates that this function uses a super property (or an eval that may
// use a super property).
diff --git a/deps/v8/src/objects/source-text-module.cc b/deps/v8/src/objects/source-text-module.cc
index e6637415c1..f17c59de1a 100644
--- a/deps/v8/src/objects/source-text-module.cc
+++ b/deps/v8/src/objects/source-text-module.cc
@@ -380,7 +380,7 @@ bool SourceTextModule::RunInitializationCode(Isolate* isolate,
return false;
}
DCHECK_EQ(*function, Handle<JSGeneratorObject>::cast(generator)->function());
- module->set_code(*generator);
+ module->set_code(JSGeneratorObject::cast(*generator));
return true;
}
diff --git a/deps/v8/src/objects/source-text-module.h b/deps/v8/src/objects/source-text-module.h
index 5c20b7018b..e6cf260e10 100644
--- a/deps/v8/src/objects/source-text-module.h
+++ b/deps/v8/src/objects/source-text-module.h
@@ -17,43 +17,17 @@ class UnorderedModuleSet;
// The runtime representation of an ECMAScript Source Text Module Record.
// https://tc39.github.io/ecma262/#sec-source-text-module-records
-class SourceTextModule : public Module {
+class SourceTextModule
+ : public TorqueGeneratedSourceTextModule<SourceTextModule, Module> {
public:
NEVER_READ_ONLY_SPACE
- DECL_CAST(SourceTextModule)
DECL_VERIFIER(SourceTextModule)
DECL_PRINTER(SourceTextModule)
- // The code representing this module, or an abstraction thereof.
- // This is either a SharedFunctionInfo, a JSFunction, a JSGeneratorObject, or
- // a SourceTextModuleInfo, depending on the state (status) the module is in.
- // See SourceTextModule::SourceTextModuleVerify() for the precise invariant.
- DECL_ACCESSORS(code, Object)
-
- // Arrays of cells corresponding to regular exports and regular imports.
- // A cell's position in the array is determined by the cell index of the
- // associated module entry (which coincides with the variable index of the
- // associated variable).
- DECL_ACCESSORS(regular_exports, FixedArray)
- DECL_ACCESSORS(regular_imports, FixedArray)
-
// The shared function info in case {status} is not kEvaluating, kEvaluated or
// kErrored.
SharedFunctionInfo GetSharedFunctionInfo() const;
- // Modules imported or re-exported by this module.
- // Corresponds 1-to-1 to the module specifier strings in
- // SourceTextModuleInfo::module_requests.
- DECL_ACCESSORS(requested_modules, FixedArray)
-
- // [script]: Script from which the module originates.
- DECL_ACCESSORS(script, Script)
-
- // The value of import.meta inside of this module.
- // Lazily initialized on first access. It's the hole before first access and
- // a JSObject afterwards.
- DECL_ACCESSORS(import_meta, Object)
-
// Get the SourceTextModuleInfo associated with the code.
inline SourceTextModuleInfo info() const;
@@ -72,10 +46,6 @@ class SourceTextModule : public Module {
static Handle<JSModuleNamespace> GetModuleNamespace(
Isolate* isolate, Handle<SourceTextModule> module, int module_request);
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(Module::kHeaderSize,
- TORQUE_GENERATED_SOURCE_TEXT_MODULE_FIELDS)
-
using BodyDescriptor =
SubclassBodyDescriptor<Module::BodyDescriptor,
FixedBodyDescriptor<kCodeOffset, kSize, kSize>>;
@@ -135,7 +105,7 @@ class SourceTextModule : public Module {
static void Reset(Isolate* isolate, Handle<SourceTextModule> module);
- OBJECT_CONSTRUCTORS(SourceTextModule, Module);
+ TQ_OBJECT_CONSTRUCTORS(SourceTextModule)
};
// SourceTextModuleInfo is to SourceTextModuleDescriptor what ScopeInfo is to
@@ -186,30 +156,24 @@ class SourceTextModuleInfo : public FixedArray {
OBJECT_CONSTRUCTORS(SourceTextModuleInfo, FixedArray);
};
-class SourceTextModuleInfoEntry : public Struct {
+class SourceTextModuleInfoEntry
+ : public TorqueGeneratedSourceTextModuleInfoEntry<SourceTextModuleInfoEntry,
+ Struct> {
public:
- DECL_CAST(SourceTextModuleInfoEntry)
DECL_PRINTER(SourceTextModuleInfoEntry)
DECL_VERIFIER(SourceTextModuleInfoEntry)
- DECL_ACCESSORS(export_name, Object)
- DECL_ACCESSORS(local_name, Object)
- DECL_ACCESSORS(import_name, Object)
DECL_INT_ACCESSORS(module_request)
DECL_INT_ACCESSORS(cell_index)
DECL_INT_ACCESSORS(beg_pos)
DECL_INT_ACCESSORS(end_pos)
static Handle<SourceTextModuleInfoEntry> New(
- Isolate* isolate, Handle<Object> export_name, Handle<Object> local_name,
- Handle<Object> import_name, int module_request, int cell_index,
- int beg_pos, int end_pos);
-
- DEFINE_FIELD_OFFSET_CONSTANTS(
- Struct::kHeaderSize,
- TORQUE_GENERATED_SOURCE_TEXT_MODULE_INFO_ENTRY_FIELDS)
+ Isolate* isolate, Handle<HeapObject> export_name,
+ Handle<HeapObject> local_name, Handle<HeapObject> import_name,
+ int module_request, int cell_index, int beg_pos, int end_pos);
- OBJECT_CONSTRUCTORS(SourceTextModuleInfoEntry, Struct);
+ TQ_OBJECT_CONSTRUCTORS(SourceTextModuleInfoEntry)
};
} // namespace internal
diff --git a/deps/v8/src/objects/stack-frame-info-inl.h b/deps/v8/src/objects/stack-frame-info-inl.h
index e72af4df94..42e3a4a10a 100644
--- a/deps/v8/src/objects/stack-frame-info-inl.h
+++ b/deps/v8/src/objects/stack-frame-info-inl.h
@@ -28,6 +28,8 @@ SMI_ACCESSORS(StackFrameInfo, line_number, kLineNumberOffset)
SMI_ACCESSORS(StackFrameInfo, column_number, kColumnNumberOffset)
SMI_ACCESSORS(StackFrameInfo, script_id, kScriptIdOffset)
SMI_ACCESSORS(StackFrameInfo, promise_all_index, kPromiseAllIndexOffset)
+SMI_ACCESSORS_CHECKED(StackFrameInfo, function_offset, kPromiseAllIndexOffset,
+ is_wasm())
ACCESSORS(StackFrameInfo, script_name, Object, kScriptNameOffset)
ACCESSORS(StackFrameInfo, script_name_or_source_url, Object,
kScriptNameOrSourceUrlOffset)
@@ -36,6 +38,7 @@ ACCESSORS(StackFrameInfo, method_name, Object, kMethodNameOffset)
ACCESSORS(StackFrameInfo, type_name, Object, kTypeNameOffset)
ACCESSORS(StackFrameInfo, eval_origin, Object, kEvalOriginOffset)
ACCESSORS(StackFrameInfo, wasm_module_name, Object, kWasmModuleNameOffset)
+ACCESSORS(StackFrameInfo, wasm_instance, Object, kWasmInstanceOffset)
SMI_ACCESSORS(StackFrameInfo, flag, kFlagOffset)
BOOL_ACCESSORS(StackFrameInfo, flag, is_eval, kIsEvalBit)
BOOL_ACCESSORS(StackFrameInfo, flag, is_constructor, kIsConstructorBit)
@@ -46,14 +49,11 @@ BOOL_ACCESSORS(StackFrameInfo, flag, is_toplevel, kIsToplevelBit)
BOOL_ACCESSORS(StackFrameInfo, flag, is_async, kIsAsyncBit)
BOOL_ACCESSORS(StackFrameInfo, flag, is_promise_all, kIsPromiseAllBit)
-OBJECT_CONSTRUCTORS_IMPL(StackTraceFrame, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(StackTraceFrame)
NEVER_READ_ONLY_SPACE_IMPL(StackTraceFrame)
-CAST_ACCESSOR(StackTraceFrame)
-ACCESSORS(StackTraceFrame, frame_array, Object, kFrameArrayOffset)
-SMI_ACCESSORS(StackTraceFrame, frame_index, kFrameIndexOffset)
-ACCESSORS(StackTraceFrame, frame_info, Object, kFrameInfoOffset)
-SMI_ACCESSORS(StackTraceFrame, id, kIdOffset)
+TQ_SMI_ACCESSORS(StackTraceFrame, frame_index)
+TQ_SMI_ACCESSORS(StackTraceFrame, id)
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/objects/stack-frame-info.cc b/deps/v8/src/objects/stack-frame-info.cc
index 558449d85a..323c4b8fcb 100644
--- a/deps/v8/src/objects/stack-frame-info.cc
+++ b/deps/v8/src/objects/stack-frame-info.cc
@@ -52,6 +52,12 @@ int StackTraceFrame::GetPromiseAllIndex(Handle<StackTraceFrame> frame) {
}
// static
+int StackTraceFrame::GetFunctionOffset(Handle<StackTraceFrame> frame) {
+ DCHECK(IsWasm(frame));
+ return GetFrameInfo(frame)->function_offset();
+}
+
+// static
Handle<Object> StackTraceFrame::GetFileName(Handle<StackTraceFrame> frame) {
auto name = GetFrameInfo(frame)->script_name();
return handle(name, frame->GetIsolate());
@@ -96,6 +102,13 @@ Handle<Object> StackTraceFrame::GetWasmModuleName(
}
// static
+Handle<WasmInstanceObject> StackTraceFrame::GetWasmInstance(
+ Handle<StackTraceFrame> frame) {
+ Object instance = GetFrameInfo(frame)->wasm_instance();
+ return handle(WasmInstanceObject::cast(instance), frame->GetIsolate());
+}
+
+// static
bool StackTraceFrame::IsEval(Handle<StackTraceFrame> frame) {
return GetFrameInfo(frame)->is_eval();
}
diff --git a/deps/v8/src/objects/stack-frame-info.h b/deps/v8/src/objects/stack-frame-info.h
index 3d91c5374f..7c4918a3c6 100644
--- a/deps/v8/src/objects/stack-frame-info.h
+++ b/deps/v8/src/objects/stack-frame-info.h
@@ -14,6 +14,7 @@ namespace v8 {
namespace internal {
class FrameArray;
+class WasmInstanceObject;
class StackFrameInfo : public Struct {
public:
@@ -22,6 +23,8 @@ class StackFrameInfo : public Struct {
DECL_INT_ACCESSORS(column_number)
DECL_INT_ACCESSORS(script_id)
DECL_INT_ACCESSORS(promise_all_index)
+ // Wasm frames only: function_offset instead of promise_all_index.
+ DECL_INT_ACCESSORS(function_offset)
DECL_ACCESSORS(script_name, Object)
DECL_ACCESSORS(script_name_or_source_url, Object)
DECL_ACCESSORS(function_name, Object)
@@ -29,6 +32,7 @@ class StackFrameInfo : public Struct {
DECL_ACCESSORS(type_name, Object)
DECL_ACCESSORS(eval_origin, Object)
DECL_ACCESSORS(wasm_module_name, Object)
+ DECL_ACCESSORS(wasm_instance, Object)
DECL_BOOLEAN_ACCESSORS(is_eval)
DECL_BOOLEAN_ACCESSORS(is_constructor)
DECL_BOOLEAN_ACCESSORS(is_wasm)
@@ -67,22 +71,15 @@ class StackFrameInfo : public Struct {
// The first time any of the Get* or Is* methods is called, a
// StackFrameInfo object is allocated and all necessary information
// retrieved.
-class StackTraceFrame : public Struct {
+class StackTraceFrame
+ : public TorqueGeneratedStackTraceFrame<StackTraceFrame, Struct> {
public:
NEVER_READ_ONLY_SPACE
- DECL_ACCESSORS(frame_array, Object)
DECL_INT_ACCESSORS(frame_index)
- DECL_ACCESSORS(frame_info, Object)
DECL_INT_ACCESSORS(id)
- DECL_CAST(StackTraceFrame)
-
// Dispatched behavior.
DECL_PRINTER(StackTraceFrame)
- DECL_VERIFIER(StackTraceFrame)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize,
- TORQUE_GENERATED_STACK_TRACE_FRAME_FIELDS)
static int GetLineNumber(Handle<StackTraceFrame> frame);
static int GetOneBasedLineNumber(Handle<StackTraceFrame> frame);
@@ -90,6 +87,7 @@ class StackTraceFrame : public Struct {
static int GetOneBasedColumnNumber(Handle<StackTraceFrame> frame);
static int GetScriptId(Handle<StackTraceFrame> frame);
static int GetPromiseAllIndex(Handle<StackTraceFrame> frame);
+ static int GetFunctionOffset(Handle<StackTraceFrame> frame);
static Handle<Object> GetFileName(Handle<StackTraceFrame> frame);
static Handle<Object> GetScriptNameOrSourceUrl(Handle<StackTraceFrame> frame);
@@ -98,6 +96,8 @@ class StackTraceFrame : public Struct {
static Handle<Object> GetTypeName(Handle<StackTraceFrame> frame);
static Handle<Object> GetEvalOrigin(Handle<StackTraceFrame> frame);
static Handle<Object> GetWasmModuleName(Handle<StackTraceFrame> frame);
+ static Handle<WasmInstanceObject> GetWasmInstance(
+ Handle<StackTraceFrame> frame);
static bool IsEval(Handle<StackTraceFrame> frame);
static bool IsConstructor(Handle<StackTraceFrame> frame);
@@ -109,10 +109,10 @@ class StackTraceFrame : public Struct {
static bool IsPromiseAll(Handle<StackTraceFrame> frame);
private:
- OBJECT_CONSTRUCTORS(StackTraceFrame, Struct);
-
static Handle<StackFrameInfo> GetFrameInfo(Handle<StackTraceFrame> frame);
static void InitializeFrameInfo(Handle<StackTraceFrame> frame);
+
+ TQ_OBJECT_CONSTRUCTORS(StackTraceFrame)
};
// Small helper that retrieves the FrameArray from a stack-trace
diff --git a/deps/v8/src/objects/string-inl.h b/deps/v8/src/objects/string-inl.h
index db724e0cf1..083928d211 100644
--- a/deps/v8/src/objects/string-inl.h
+++ b/deps/v8/src/objects/string-inl.h
@@ -137,6 +137,65 @@ STATIC_ASSERT((kExternalStringTag | kTwoByteStringTag) ==
STATIC_ASSERT(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag);
+template <typename TDispatcher, typename TResult, typename... TArgs>
+inline TResult StringShape::DispatchToSpecificTypeWithoutCast(TArgs&&... args) {
+ switch (full_representation_tag()) {
+ case kSeqStringTag | kOneByteStringTag:
+ return TDispatcher::HandleSeqOneByteString(std::forward<TArgs>(args)...);
+ case kSeqStringTag | kTwoByteStringTag:
+ return TDispatcher::HandleSeqTwoByteString(std::forward<TArgs>(args)...);
+ case kConsStringTag | kOneByteStringTag:
+ case kConsStringTag | kTwoByteStringTag:
+ return TDispatcher::HandleConsString(std::forward<TArgs>(args)...);
+ case kExternalStringTag | kOneByteStringTag:
+ return TDispatcher::HandleExternalOneByteString(
+ std::forward<TArgs>(args)...);
+ case kExternalStringTag | kTwoByteStringTag:
+ return TDispatcher::HandleExternalTwoByteString(
+ std::forward<TArgs>(args)...);
+ case kSlicedStringTag | kOneByteStringTag:
+ case kSlicedStringTag | kTwoByteStringTag:
+ return TDispatcher::HandleSlicedString(std::forward<TArgs>(args)...);
+ case kThinStringTag | kOneByteStringTag:
+ case kThinStringTag | kTwoByteStringTag:
+ return TDispatcher::HandleThinString(std::forward<TArgs>(args)...);
+ default:
+ return TDispatcher::HandleInvalidString(std::forward<TArgs>(args)...);
+ }
+}
+
+// All concrete subclasses of String (leaves of the inheritance tree).
+#define STRING_CLASS_TYPES(V) \
+ V(SeqOneByteString) \
+ V(SeqTwoByteString) \
+ V(ConsString) \
+ V(ExternalOneByteString) \
+ V(ExternalTwoByteString) \
+ V(SlicedString) \
+ V(ThinString)
+
+template <typename TDispatcher, typename TResult, typename... TArgs>
+inline TResult StringShape::DispatchToSpecificType(String str,
+ TArgs&&... args) {
+ class CastingDispatcher : public AllStatic {
+ public:
+#define DEFINE_METHOD(Type) \
+ static inline TResult Handle##Type(String str, TArgs&&... args) { \
+ return TDispatcher::Handle##Type(Type::cast(str), \
+ std::forward<TArgs>(args)...); \
+ }
+ STRING_CLASS_TYPES(DEFINE_METHOD)
+#undef DEFINE_METHOD
+ static inline TResult HandleInvalidString(String str, TArgs&&... args) {
+ return TDispatcher::HandleInvalidString(str,
+ std::forward<TArgs>(args)...);
+ }
+ };
+
+ return DispatchToSpecificTypeWithoutCast<CastingDispatcher, TResult>(
+ str, std::forward<TArgs>(args)...);
+}
+
DEF_GETTER(String, IsOneByteRepresentation, bool) {
uint32_t type = map(isolate).instance_type();
return (type & kStringEncodingMask) == kOneByteStringTag;
@@ -340,29 +399,22 @@ Handle<String> String::Flatten(Isolate* isolate, Handle<String> string,
uint16_t String::Get(int index) {
DCHECK(index >= 0 && index < length());
- switch (StringShape(*this).full_representation_tag()) {
- case kSeqStringTag | kOneByteStringTag:
- return SeqOneByteString::cast(*this).Get(index);
- case kSeqStringTag | kTwoByteStringTag:
- return SeqTwoByteString::cast(*this).Get(index);
- case kConsStringTag | kOneByteStringTag:
- case kConsStringTag | kTwoByteStringTag:
- return ConsString::cast(*this).Get(index);
- case kExternalStringTag | kOneByteStringTag:
- return ExternalOneByteString::cast(*this).Get(index);
- case kExternalStringTag | kTwoByteStringTag:
- return ExternalTwoByteString::cast(*this).Get(index);
- case kSlicedStringTag | kOneByteStringTag:
- case kSlicedStringTag | kTwoByteStringTag:
- return SlicedString::cast(*this).Get(index);
- case kThinStringTag | kOneByteStringTag:
- case kThinStringTag | kTwoByteStringTag:
- return ThinString::cast(*this).Get(index);
- default:
- break;
+
+ class StringGetDispatcher : public AllStatic {
+ public:
+#define DEFINE_METHOD(Type) \
+ static inline uint16_t Handle##Type(Type str, int index) { \
+ return str.Get(index); \
}
+ STRING_CLASS_TYPES(DEFINE_METHOD)
+#undef DEFINE_METHOD
+ static inline uint16_t HandleInvalidString(String str, int index) {
+ UNREACHABLE();
+ }
+ };
- UNREACHABLE();
+ return StringShape(*this)
+ .DispatchToSpecificType<StringGetDispatcher, uint16_t>(*this, index);
}
void String::Set(int index, uint16_t value) {
diff --git a/deps/v8/src/objects/string.cc b/deps/v8/src/objects/string.cc
index d1981fd24d..41de3aef04 100644
--- a/deps/v8/src/objects/string.cc
+++ b/deps/v8/src/objects/string.cc
@@ -110,6 +110,8 @@ void String::MakeThin(Isolate* isolate, String internalized) {
}
}
+ bool has_pointers = StringShape(*this).IsIndirect();
+
int old_size = this->Size();
isolate->heap()->NotifyObjectLayoutChange(*this, old_size, no_gc);
bool one_byte = internalized.IsOneByteRepresentation();
@@ -123,7 +125,9 @@ void String::MakeThin(Isolate* isolate, String internalized) {
int size_delta = old_size - ThinString::kSize;
if (size_delta != 0) {
Heap* heap = isolate->heap();
- heap->CreateFillerObjectAt(thin_end, size_delta, ClearRecordedSlots::kNo);
+ heap->CreateFillerObjectAt(
+ thin_end, size_delta,
+ has_pointers ? ClearRecordedSlots::kYes : ClearRecordedSlots::kNo);
}
}
@@ -178,7 +182,8 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
// Byte size of the external String object.
int new_size = this->SizeFromMap(new_map);
isolate->heap()->CreateFillerObjectAt(
- this->address() + new_size, size - new_size, ClearRecordedSlots::kNo);
+ this->address() + new_size, size - new_size,
+ has_pointers ? ClearRecordedSlots::kYes : ClearRecordedSlots::kNo);
if (has_pointers) {
isolate->heap()->ClearRecordedSlotRange(this->address(),
this->address() + new_size);
@@ -250,7 +255,8 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
// Byte size of the external String object.
int new_size = this->SizeFromMap(new_map);
isolate->heap()->CreateFillerObjectAt(
- this->address() + new_size, size - new_size, ClearRecordedSlots::kNo);
+ this->address() + new_size, size - new_size,
+ has_pointers ? ClearRecordedSlots::kYes : ClearRecordedSlots::kNo);
if (has_pointers) {
isolate->heap()->ClearRecordedSlotRange(this->address(),
this->address() + new_size);
diff --git a/deps/v8/src/objects/string.h b/deps/v8/src/objects/string.h
index 1a826eee3b..27bd7e8765 100644
--- a/deps/v8/src/objects/string.h
+++ b/deps/v8/src/objects/string.h
@@ -61,6 +61,13 @@ class StringShape {
inline void invalidate() {}
#endif
+ // Run different behavior for each concrete string class type, as defined by
+ // the dispatcher.
+ template <typename TDispatcher, typename TResult, typename... TArgs>
+ inline TResult DispatchToSpecificTypeWithoutCast(TArgs&&... args);
+ template <typename TDispatcher, typename TResult, typename... TArgs>
+ inline TResult DispatchToSpecificType(String str, TArgs&&... args);
+
private:
uint32_t type_;
#ifdef DEBUG
diff --git a/deps/v8/src/objects/struct-inl.h b/deps/v8/src/objects/struct-inl.h
index 47d55a876f..af0fed126b 100644
--- a/deps/v8/src/objects/struct-inl.h
+++ b/deps/v8/src/objects/struct-inl.h
@@ -24,10 +24,9 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(Tuple2)
TQ_OBJECT_CONSTRUCTORS_IMPL(Tuple3)
OBJECT_CONSTRUCTORS_IMPL(AccessorPair, Struct)
-OBJECT_CONSTRUCTORS_IMPL(ClassPositions, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(ClassPositions)
CAST_ACCESSOR(AccessorPair)
-CAST_ACCESSOR(ClassPositions)
void Struct::InitializeBody(int object_size) {
Object value = GetReadOnlyRoots().undefined_value();
@@ -39,8 +38,8 @@ void Struct::InitializeBody(int object_size) {
ACCESSORS(AccessorPair, getter, Object, kGetterOffset)
ACCESSORS(AccessorPair, setter, Object, kSetterOffset)
-SMI_ACCESSORS(ClassPositions, start, kStartOffset)
-SMI_ACCESSORS(ClassPositions, end, kEndOffset)
+TQ_SMI_ACCESSORS(ClassPositions, start)
+TQ_SMI_ACCESSORS(ClassPositions, end)
Object AccessorPair::get(AccessorComponent component) {
return component == ACCESSOR_GETTER ? getter() : setter();
diff --git a/deps/v8/src/objects/struct.h b/deps/v8/src/objects/struct.h
index b01a33561b..c9372d9ada 100644
--- a/deps/v8/src/objects/struct.h
+++ b/deps/v8/src/objects/struct.h
@@ -60,6 +60,7 @@ class AccessorPair : public Struct {
// Note: Returns undefined if the component is not set.
static Handle<Object> GetComponent(Isolate* isolate,
+ Handle<NativeContext> native_context,
Handle<AccessorPair> accessor_pair,
AccessorComponent component);
@@ -79,22 +80,17 @@ class AccessorPair : public Struct {
OBJECT_CONSTRUCTORS(AccessorPair, Struct);
};
-class ClassPositions : public Struct {
+class ClassPositions
+ : public TorqueGeneratedClassPositions<ClassPositions, Struct> {
public:
DECL_INT_ACCESSORS(start)
DECL_INT_ACCESSORS(end)
- DECL_CAST(ClassPositions)
-
// Dispatched behavior.
DECL_PRINTER(ClassPositions)
- DECL_VERIFIER(ClassPositions)
void BriefPrintDetails(std::ostream& os);
- DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
- TORQUE_GENERATED_CLASS_POSITIONS_FIELDS)
-
- OBJECT_CONSTRUCTORS(ClassPositions, Struct);
+ TQ_OBJECT_CONSTRUCTORS(ClassPositions)
};
} // namespace internal
diff --git a/deps/v8/src/objects/synthetic-module.h b/deps/v8/src/objects/synthetic-module.h
index 9f91f2ce4a..6f3bb0438e 100644
--- a/deps/v8/src/objects/synthetic-module.h
+++ b/deps/v8/src/objects/synthetic-module.h
@@ -17,26 +17,17 @@ namespace internal {
// instantiated by an embedder with embedder-defined exports and evaluation
// steps.
// https://heycam.github.io/webidl/#synthetic-module-records
-class SyntheticModule : public Module {
+class SyntheticModule
+ : public TorqueGeneratedSyntheticModule<SyntheticModule, Module> {
public:
NEVER_READ_ONLY_SPACE
- DECL_CAST(SyntheticModule)
DECL_VERIFIER(SyntheticModule)
DECL_PRINTER(SyntheticModule)
- // The list of all names exported by this module
- DECL_ACCESSORS(name, String)
- DECL_ACCESSORS(export_names, FixedArray)
- DECL_ACCESSORS(evaluation_steps, Foreign)
-
static void SetExport(Isolate* isolate, Handle<SyntheticModule> module,
Handle<String> export_name,
Handle<Object> export_value);
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(Module::kHeaderSize,
- TORQUE_GENERATED_SYNTHETIC_MODULE_FIELDS)
-
using BodyDescriptor = SubclassBodyDescriptor<
Module::BodyDescriptor,
FixedBodyDescriptor<kExportNamesOffset, kSize, kSize>>;
@@ -58,7 +49,7 @@ class SyntheticModule : public Module {
static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate(
Isolate* isolate, Handle<SyntheticModule> module);
- OBJECT_CONSTRUCTORS(SyntheticModule, Module);
+ TQ_OBJECT_CONSTRUCTORS(SyntheticModule)
};
} // namespace internal
diff --git a/deps/v8/src/objects/template-objects-inl.h b/deps/v8/src/objects/template-objects-inl.h
index 85c1e6c8f4..b0f73e873b 100644
--- a/deps/v8/src/objects/template-objects-inl.h
+++ b/deps/v8/src/objects/template-objects-inl.h
@@ -15,16 +15,11 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(TemplateObjectDescription, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(TemplateObjectDescription)
OBJECT_CONSTRUCTORS_IMPL(CachedTemplateObject, Tuple3)
-CAST_ACCESSOR(TemplateObjectDescription)
CAST_ACCESSOR(CachedTemplateObject)
-ACCESSORS(TemplateObjectDescription, raw_strings, FixedArray, kRawStringsOffset)
-ACCESSORS(TemplateObjectDescription, cooked_strings, FixedArray,
- kCookedStringsOffset)
-
SMI_ACCESSORS(CachedTemplateObject, slot_id, kSlotIdOffset)
ACCESSORS(CachedTemplateObject, template_object, JSArray, kTemplateObjectOffset)
ACCESSORS(CachedTemplateObject, next, HeapObject, kNextOffset)
diff --git a/deps/v8/src/objects/template-objects.h b/deps/v8/src/objects/template-objects.h
index 20ad742338..7bac29206b 100644
--- a/deps/v8/src/objects/template-objects.h
+++ b/deps/v8/src/objects/template-objects.h
@@ -39,25 +39,16 @@ class CachedTemplateObject final : public Tuple3 {
// TemplateObjectDescription is a tuple of raw strings and cooked strings for
// tagged template literals. Used to communicate with the runtime for template
// object creation within the {Runtime_GetTemplateObject} method.
-class TemplateObjectDescription final : public Struct {
+class TemplateObjectDescription final
+ : public TorqueGeneratedTemplateObjectDescription<TemplateObjectDescription,
+ Struct> {
public:
- DECL_ACCESSORS(raw_strings, FixedArray)
- DECL_ACCESSORS(cooked_strings, FixedArray)
-
- DECL_CAST(TemplateObjectDescription)
-
static Handle<JSArray> GetTemplateObject(
Isolate* isolate, Handle<NativeContext> native_context,
Handle<TemplateObjectDescription> description,
Handle<SharedFunctionInfo> shared_info, int slot_id);
- DECL_PRINTER(TemplateObjectDescription)
- DECL_VERIFIER(TemplateObjectDescription)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(
- Struct::kHeaderSize, TORQUE_GENERATED_TEMPLATE_OBJECT_DESCRIPTION_FIELDS)
-
- OBJECT_CONSTRUCTORS(TemplateObjectDescription, Struct);
+ TQ_OBJECT_CONSTRUCTORS(TemplateObjectDescription)
};
} // namespace internal
diff --git a/deps/v8/src/objects/templates-inl.h b/deps/v8/src/objects/templates-inl.h
index d344174a0c..be58fc12bc 100644
--- a/deps/v8/src/objects/templates-inl.h
+++ b/deps/v8/src/objects/templates-inl.h
@@ -17,29 +17,16 @@
namespace v8 {
namespace internal {
-OBJECT_CONSTRUCTORS_IMPL(TemplateInfo, Struct)
-OBJECT_CONSTRUCTORS_IMPL(FunctionTemplateInfo, TemplateInfo)
-OBJECT_CONSTRUCTORS_IMPL(ObjectTemplateInfo, TemplateInfo)
-OBJECT_CONSTRUCTORS_IMPL(FunctionTemplateRareData, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(TemplateInfo)
+TQ_OBJECT_CONSTRUCTORS_IMPL(FunctionTemplateInfo)
+TQ_OBJECT_CONSTRUCTORS_IMPL(ObjectTemplateInfo)
+TQ_OBJECT_CONSTRUCTORS_IMPL(FunctionTemplateRareData)
NEVER_READ_ONLY_SPACE_IMPL(TemplateInfo)
-ACCESSORS(TemplateInfo, tag, Object, kTagOffset)
-ACCESSORS(TemplateInfo, serial_number, Object, kSerialNumberOffset)
-SMI_ACCESSORS(TemplateInfo, number_of_properties, kNumberOfPropertiesOffset)
-ACCESSORS(TemplateInfo, property_list, Object, kPropertyListOffset)
-ACCESSORS(TemplateInfo, property_accessors, Object, kPropertyAccessorsOffset)
-
-ACCESSORS(FunctionTemplateInfo, call_code, Object, kCallCodeOffset)
-ACCESSORS(FunctionTemplateInfo, class_name, Object, kClassNameOffset)
-ACCESSORS(FunctionTemplateInfo, signature, Object, kSignatureOffset)
-ACCESSORS(FunctionTemplateInfo, shared_function_info, Object,
- kSharedFunctionInfoOffset)
-ACCESSORS(FunctionTemplateInfo, rare_data, HeapObject,
- kFunctionTemplateRareDataOffset)
-ACCESSORS(FunctionTemplateInfo, cached_property_name, Object,
- kCachedPropertyNameOffset)
-SMI_ACCESSORS(FunctionTemplateInfo, length, kLengthOffset)
+TQ_SMI_ACCESSORS(TemplateInfo, number_of_properties)
+
+TQ_SMI_ACCESSORS(FunctionTemplateInfo, length)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, undetectable, kUndetectableBit)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, needs_access_check,
kNeedsAccessCheckBit)
@@ -50,7 +37,7 @@ BOOL_ACCESSORS(FunctionTemplateInfo, flag, remove_prototype,
BOOL_ACCESSORS(FunctionTemplateInfo, flag, do_not_cache, kDoNotCacheBit)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, accept_any_receiver,
kAcceptAnyReceiver)
-SMI_ACCESSORS(FunctionTemplateInfo, flag, kFlagOffset)
+TQ_SMI_ACCESSORS(FunctionTemplateInfo, flag)
// static
FunctionTemplateRareData FunctionTemplateInfo::EnsureFunctionTemplateRareData(
@@ -88,31 +75,6 @@ RARE_ACCESSORS(instance_call_handler, InstanceCallHandler, Object)
RARE_ACCESSORS(access_check_info, AccessCheckInfo, Object)
#undef RARE_ACCESSORS
-ACCESSORS(FunctionTemplateRareData, prototype_template, Object,
- kPrototypeTemplateOffset)
-ACCESSORS(FunctionTemplateRareData, prototype_provider_template, Object,
- kPrototypeProviderTemplateOffset)
-ACCESSORS(FunctionTemplateRareData, parent_template, Object,
- kParentTemplateOffset)
-ACCESSORS(FunctionTemplateRareData, named_property_handler, Object,
- kNamedPropertyHandlerOffset)
-ACCESSORS(FunctionTemplateRareData, indexed_property_handler, Object,
- kIndexedPropertyHandlerOffset)
-ACCESSORS(FunctionTemplateRareData, instance_template, Object,
- kInstanceTemplateOffset)
-ACCESSORS(FunctionTemplateRareData, instance_call_handler, Object,
- kInstanceCallHandlerOffset)
-ACCESSORS(FunctionTemplateRareData, access_check_info, Object,
- kAccessCheckInfoOffset)
-
-ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset)
-ACCESSORS(ObjectTemplateInfo, data, Object, kDataOffset)
-
-CAST_ACCESSOR(TemplateInfo)
-CAST_ACCESSOR(FunctionTemplateInfo)
-CAST_ACCESSOR(FunctionTemplateRareData)
-CAST_ACCESSOR(ObjectTemplateInfo)
-
bool FunctionTemplateInfo::instantiated() {
return shared_function_info().IsSharedFunctionInfo();
}
diff --git a/deps/v8/src/objects/templates.h b/deps/v8/src/objects/templates.h
index 99142266ed..29671db83c 100644
--- a/deps/v8/src/objects/templates.h
+++ b/deps/v8/src/objects/templates.h
@@ -13,21 +13,10 @@
namespace v8 {
namespace internal {
-class TemplateInfo : public Struct {
+class TemplateInfo : public TorqueGeneratedTemplateInfo<TemplateInfo, Struct> {
public:
NEVER_READ_ONLY_SPACE
- DECL_ACCESSORS(tag, Object)
- DECL_ACCESSORS(serial_number, Object)
DECL_INT_ACCESSORS(number_of_properties)
- DECL_ACCESSORS(property_list, Object)
- DECL_ACCESSORS(property_accessors, Object)
-
- DECL_VERIFIER(TemplateInfo)
-
- DECL_CAST(TemplateInfo)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
- TORQUE_GENERATED_TEMPLATE_INFO_FIELDS)
static const int kFastTemplateInstantiationsCacheSize = 1 * KB;
@@ -36,55 +25,25 @@ class TemplateInfo : public Struct {
// instead of caching them.
static const int kSlowTemplateInstantiationsCacheSize = 1 * MB;
- OBJECT_CONSTRUCTORS(TemplateInfo, Struct);
+ TQ_OBJECT_CONSTRUCTORS(TemplateInfo)
};
// Contains data members that are rarely set on a FunctionTemplateInfo.
-class FunctionTemplateRareData : public Struct {
+class FunctionTemplateRareData
+ : public TorqueGeneratedFunctionTemplateRareData<FunctionTemplateRareData,
+ Struct> {
public:
- // See DECL_RARE_ACCESSORS in FunctionTemplateInfo.
- DECL_ACCESSORS(prototype_template, Object)
- DECL_ACCESSORS(prototype_provider_template, Object)
- DECL_ACCESSORS(parent_template, Object)
- DECL_ACCESSORS(named_property_handler, Object)
- DECL_ACCESSORS(indexed_property_handler, Object)
- DECL_ACCESSORS(instance_template, Object)
- DECL_ACCESSORS(instance_call_handler, Object)
- DECL_ACCESSORS(access_check_info, Object)
-
- DECL_CAST(FunctionTemplateRareData)
-
// Dispatched behavior.
DECL_PRINTER(FunctionTemplateRareData)
- DECL_VERIFIER(FunctionTemplateRareData)
- DEFINE_FIELD_OFFSET_CONSTANTS(
- HeapObject::kHeaderSize,
- TORQUE_GENERATED_FUNCTION_TEMPLATE_RARE_DATA_FIELDS)
-
- OBJECT_CONSTRUCTORS(FunctionTemplateRareData, Struct);
+ TQ_OBJECT_CONSTRUCTORS(FunctionTemplateRareData)
};
// See the api-exposed FunctionTemplate for more information.
-class FunctionTemplateInfo : public TemplateInfo {
+class FunctionTemplateInfo
+ : public TorqueGeneratedFunctionTemplateInfo<FunctionTemplateInfo,
+ TemplateInfo> {
public:
- // Handler invoked when calling an instance of this FunctionTemplateInfo.
- // Either CallInfoHandler or Undefined.
- DECL_ACCESSORS(call_code, Object)
-
- DECL_ACCESSORS(class_name, Object)
-
- // If the signature is a FunctionTemplateInfo it is used to check whether the
- // receiver calling the associated JSFunction is a compatible receiver, i.e.
- // it is an instance of the signature FunctionTemplateInfo or any of the
- // receiver's prototypes are.
- DECL_ACCESSORS(signature, Object)
-
- // If any of the setters below declared by DECL_RARE_ACCESSORS are used then
- // a FunctionTemplateRareData will be stored here. Until then this contains
- // undefined.
- DECL_ACCESSORS(rare_data, HeapObject)
-
#define DECL_RARE_ACCESSORS(Name, CamelName, Type) \
DECL_GETTER(Get##CamelName, Type) \
static inline void Set##CamelName( \
@@ -125,19 +84,12 @@ class FunctionTemplateInfo : public TemplateInfo {
DECL_RARE_ACCESSORS(access_check_info, AccessCheckInfo, Object)
#undef DECL_RARE_ACCESSORS
- DECL_ACCESSORS(shared_function_info, Object)
-
// Internal field to store a flag bitfield.
DECL_INT_ACCESSORS(flag)
// "length" property of the final JSFunction.
DECL_INT_ACCESSORS(length)
- // Either the_hole or a private symbol. Used to cache the result on
- // the receiver under the the cached_property_name when this
- // FunctionTemplateInfo is used as a getter.
- DECL_ACCESSORS(cached_property_name, Object)
-
// Begin flag bits ---------------------
DECL_BOOLEAN_ACCESSORS(undetectable)
@@ -160,17 +112,11 @@ class FunctionTemplateInfo : public TemplateInfo {
DECL_BOOLEAN_ACCESSORS(accept_any_receiver)
// End flag bits ---------------------
- DECL_CAST(FunctionTemplateInfo)
-
// Dispatched behavior.
DECL_PRINTER(FunctionTemplateInfo)
- DECL_VERIFIER(FunctionTemplateInfo)
static const int kInvalidSerialNumber = 0;
- DEFINE_FIELD_OFFSET_CONSTANTS(TemplateInfo::kHeaderSize,
- TORQUE_GENERATED_FUNCTION_TEMPLATE_INFO_FIELDS)
-
static Handle<SharedFunctionInfo> GetOrCreateSharedFunctionInfo(
Isolate* isolate, Handle<FunctionTemplateInfo> info,
MaybeHandle<Name> maybe_name);
@@ -202,36 +148,28 @@ class FunctionTemplateInfo : public TemplateInfo {
static FunctionTemplateRareData AllocateFunctionTemplateRareData(
Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info);
- OBJECT_CONSTRUCTORS(FunctionTemplateInfo, TemplateInfo);
+ TQ_OBJECT_CONSTRUCTORS(FunctionTemplateInfo)
};
-class ObjectTemplateInfo : public TemplateInfo {
+class ObjectTemplateInfo
+ : public TorqueGeneratedObjectTemplateInfo<ObjectTemplateInfo,
+ TemplateInfo> {
public:
- DECL_ACCESSORS(constructor, Object)
- DECL_ACCESSORS(data, Object)
DECL_INT_ACCESSORS(embedder_field_count)
DECL_BOOLEAN_ACCESSORS(immutable_proto)
- DECL_CAST(ObjectTemplateInfo)
-
// Dispatched behavior.
DECL_PRINTER(ObjectTemplateInfo)
- DECL_VERIFIER(ObjectTemplateInfo)
-
- // Layout description.
- DEFINE_FIELD_OFFSET_CONSTANTS(TemplateInfo::kHeaderSize,
- TORQUE_GENERATED_OBJECT_TEMPLATE_INFO_FIELDS)
// Starting from given object template's constructor walk up the inheritance
// chain till a function template that has an instance template is found.
inline ObjectTemplateInfo GetParent(Isolate* isolate);
private:
- class IsImmutablePrototype : public BitField<bool, 0, 1> {};
- class EmbedderFieldCount
- : public BitField<int, IsImmutablePrototype::kNext, 29> {};
+ using IsImmutablePrototype = BitField<bool, 0, 1>;
+ using EmbedderFieldCount = IsImmutablePrototype::Next<int, 29>;
- OBJECT_CONSTRUCTORS(ObjectTemplateInfo, TemplateInfo);
+ TQ_OBJECT_CONSTRUCTORS(ObjectTemplateInfo)
};
} // namespace internal
diff --git a/deps/v8/src/objects/value-serializer.cc b/deps/v8/src/objects/value-serializer.cc
index 5a72dd6532..3b3506fbb9 100644
--- a/deps/v8/src/objects/value-serializer.cc
+++ b/deps/v8/src/objects/value-serializer.cc
@@ -417,9 +417,6 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
case HEAP_NUMBER_TYPE:
WriteHeapNumber(HeapNumber::cast(*object));
return ThrowIfOutOfMemory();
- case MUTABLE_HEAP_NUMBER_TYPE:
- WriteMutableHeapNumber(MutableHeapNumber::cast(*object));
- return ThrowIfOutOfMemory();
case BIGINT_TYPE:
WriteBigInt(BigInt::cast(*object));
return ThrowIfOutOfMemory();
@@ -485,11 +482,6 @@ void ValueSerializer::WriteHeapNumber(HeapNumber number) {
WriteDouble(number.value());
}
-void ValueSerializer::WriteMutableHeapNumber(MutableHeapNumber number) {
- WriteTag(SerializationTag::kDouble);
- WriteDouble(number.value());
-}
-
void ValueSerializer::WriteBigInt(BigInt bigint) {
WriteTag(SerializationTag::kBigInt);
WriteBigIntContents(bigint);
diff --git a/deps/v8/src/objects/value-serializer.h b/deps/v8/src/objects/value-serializer.h
index 9e381d7e76..cc9bc1caea 100644
--- a/deps/v8/src/objects/value-serializer.h
+++ b/deps/v8/src/objects/value-serializer.h
@@ -30,7 +30,6 @@ class JSMap;
class JSPrimitiveWrapper;
class JSRegExp;
class JSSet;
-class MutableHeapNumber;
class Object;
class Oddball;
class Smi;
@@ -111,7 +110,6 @@ class ValueSerializer {
void WriteOddball(Oddball oddball);
void WriteSmi(Smi smi);
void WriteHeapNumber(HeapNumber number);
- void WriteMutableHeapNumber(MutableHeapNumber number);
void WriteBigInt(BigInt bigint);
void WriteString(Handle<String> string);
Maybe<bool> WriteJSReceiver(Handle<JSReceiver> receiver)
diff --git a/deps/v8/src/parsing/expression-scope-reparenter.cc b/deps/v8/src/parsing/expression-scope-reparenter.cc
index 78167a06e7..3f62616ebd 100644
--- a/deps/v8/src/parsing/expression-scope-reparenter.cc
+++ b/deps/v8/src/parsing/expression-scope-reparenter.cc
@@ -105,7 +105,7 @@ void ReparentExpressionScope(uintptr_t stack_limit, Expression* expr,
// sloppy eval.
DCHECK(scope->is_block_scope());
DCHECK(scope->is_declaration_scope());
- DCHECK(scope->AsDeclarationScope()->calls_sloppy_eval());
+ DCHECK(scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
DCHECK(scope->outer_scope()->is_function_scope());
Reparenter r(stack_limit, expr, scope);
diff --git a/deps/v8/src/parsing/expression-scope.h b/deps/v8/src/parsing/expression-scope.h
index 5a6ef376a8..43bf754150 100644
--- a/deps/v8/src/parsing/expression-scope.h
+++ b/deps/v8/src/parsing/expression-scope.h
@@ -5,6 +5,8 @@
#ifndef V8_PARSING_EXPRESSION_SCOPE_H_
#define V8_PARSING_EXPRESSION_SCOPE_H_
+#include <utility>
+
#include "src/ast/scopes.h"
#include "src/common/message-template.h"
#include "src/objects/function-kind.h"
@@ -82,6 +84,12 @@ class ExpressionScope {
AsExpressionParsingScope()->ClearExpressionError();
}
+ void ValidateAsExpression() {
+ if (!CanBeExpression()) return;
+ AsExpressionParsingScope()->ValidateExpression();
+ AsExpressionParsingScope()->ClearPatternError();
+ }
+
// Record async arrow parameters errors in all ambiguous async arrow scopes in
// the chain up to the first unambiguous scope.
void RecordAsyncArrowParametersError(const Scanner::Location& loc,
@@ -173,6 +181,18 @@ class ExpressionScope {
return IsInRange(type_, kParameterDeclaration, kLexicalDeclaration);
}
+ int SetInitializers(int variable_index, int peek_position) {
+ if (CanBeExpression()) {
+ return AsExpressionParsingScope()->SetInitializers(variable_index,
+ peek_position);
+ }
+ return variable_index;
+ }
+
+ bool has_possible_arrow_parameter_in_scope_chain() const {
+ return has_possible_arrow_parameter_in_scope_chain_;
+ }
+
protected:
enum ScopeType : uint8_t {
// Expression or assignment target.
@@ -201,7 +221,11 @@ class ExpressionScope {
type_(type),
has_possible_parameter_in_scope_chain_(
CanBeParameterDeclaration() ||
- (parent_ && parent_->has_possible_parameter_in_scope_chain_)) {
+ (parent_ && parent_->has_possible_parameter_in_scope_chain_)),
+ has_possible_arrow_parameter_in_scope_chain_(
+ CanBeArrowParameterDeclaration() ||
+ (parent_ &&
+ parent_->has_possible_arrow_parameter_in_scope_chain_)) {
parser->expression_scope_ = this;
}
@@ -265,6 +289,10 @@ class ExpressionScope {
return IsInRange(type_, kMaybeArrowParameterDeclaration,
kParameterDeclaration);
}
+ bool CanBeArrowParameterDeclaration() const {
+ return IsInRange(type_, kMaybeArrowParameterDeclaration,
+ kMaybeAsyncArrowParameterDeclaration);
+ }
bool IsCertainlyParameterDeclaration() const {
return type_ == kParameterDeclaration;
}
@@ -273,6 +301,7 @@ class ExpressionScope {
ExpressionScope<Types>* parent_;
ScopeType type_;
bool has_possible_parameter_in_scope_chain_;
+ bool has_possible_arrow_parameter_in_scope_chain_;
DISALLOW_COPY_AND_ASSIGN(ExpressionScope);
};
@@ -458,8 +487,8 @@ class ExpressionParsingScope : public ExpressionScope<Types> {
ExpressionScopeT::Report(Scanner::Location(begin, end),
MessageTemplate::kInvalidDestructuringTarget);
}
- for (VariableProxy* proxy : variable_list_) {
- proxy->set_is_assigned();
+ for (auto& variable_initializer_pair : variable_list_) {
+ variable_initializer_pair.first->set_is_assigned();
}
}
@@ -471,18 +500,42 @@ class ExpressionParsingScope : public ExpressionScope<Types> {
clear(kExpressionIndex);
}
+ void ClearPatternError() {
+ DCHECK(verified_);
+#ifdef DEBUG
+ verified_ = false;
+#endif
+ clear(kPatternIndex);
+ }
+
void TrackVariable(VariableProxy* variable) {
if (!this->CanBeDeclaration()) {
this->parser()->scope()->AddUnresolved(variable);
}
- variable_list_.Add(variable);
+ variable_list_.Add({variable, kNoSourcePosition});
}
void MarkIdentifierAsAssigned() {
// It's possible we're parsing a syntax error. In that case it's not
// guaranteed that there's a variable in the list.
if (variable_list_.length() == 0) return;
- variable_list_.at(variable_list_.length() - 1)->set_is_assigned();
+ variable_list_.at(variable_list_.length() - 1).first->set_is_assigned();
+ }
+
+ int SetInitializers(int first_variable_index, int position) {
+ int len = variable_list_.length();
+ if (len == 0) return 0;
+
+ int end = len - 1;
+ // Loop backwards and abort as soon as we see one that's already set to
+ // avoid a loop on expressions like a,b,c,d,e,f,g (outside of an arrowhead).
+ // TODO(delphick): Look into removing this loop.
+ for (int i = end; i >= first_variable_index &&
+ variable_list_.at(i).second == kNoSourcePosition;
+ --i) {
+ variable_list_.at(i).second = position;
+ }
+ return end;
}
protected:
@@ -496,7 +549,9 @@ class ExpressionParsingScope : public ExpressionScope<Types> {
void ValidatePattern() { Validate(kPatternIndex); }
- ScopedPtrList<VariableProxy>* variable_list() { return &variable_list_; }
+ ScopedList<std::pair<VariableProxy*, int>>* variable_list() {
+ return &variable_list_;
+ }
private:
friend class AccumulationScope<Types>;
@@ -542,7 +597,7 @@ class ExpressionParsingScope : public ExpressionScope<Types> {
bool verified_ = false;
#endif
- ScopedPtrList<VariableProxy> variable_list_;
+ ScopedList<std::pair<VariableProxy*, int>> variable_list_;
MessageTemplate messages_[kNumberOfErrors];
Scanner::Location locations_[kNumberOfErrors];
bool has_async_arrow_in_scope_chain_;
@@ -665,7 +720,8 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
// references.
this->parser()->next_arrow_function_info_.ClearStrictParameterError();
ExpressionParsingScope<Types>::ValidateExpression();
- for (VariableProxy* proxy : *this->variable_list()) {
+ for (auto& proxy_initializer_pair : *this->variable_list()) {
+ VariableProxy* proxy = proxy_initializer_pair.first;
this->parser()->scope()->AddUnresolved(proxy);
}
}
@@ -683,21 +739,27 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
VariableKind kind = PARAMETER_VARIABLE;
VariableMode mode =
has_simple_parameter_list_ ? VariableMode::kVar : VariableMode::kLet;
- for (VariableProxy* proxy : *this->variable_list()) {
+ for (auto& proxy_initializer_pair : *this->variable_list()) {
+ VariableProxy* proxy = proxy_initializer_pair.first;
+ int initializer_position = proxy_initializer_pair.second;
+ // Default values for parameters will have been parsed as assignments so
+ // clear the is_assigned bit as they are not actually assignments.
+ proxy->clear_is_assigned();
bool was_added;
- this->parser()->DeclareAndBindVariable(
- proxy, kind, mode, Variable::DefaultInitializationFlag(mode), result,
- &was_added, proxy->position());
+ this->parser()->DeclareAndBindVariable(proxy, kind, mode, result,
+ &was_added, initializer_position);
if (!was_added) {
ExpressionScope<Types>::Report(proxy->location(),
MessageTemplate::kParamDupe);
}
}
- int initializer_position = this->parser()->end_position();
+#ifdef DEBUG
for (auto declaration : *result->declarations()) {
- declaration->var()->set_initializer_position(initializer_position);
+ DCHECK_NE(declaration->var()->initializer_position(), kNoSourcePosition);
}
+#endif // DEBUG
+
if (uses_this_) result->UsesThis();
return result;
}
diff --git a/deps/v8/src/parsing/parse-info.cc b/deps/v8/src/parsing/parse-info.cc
index 0ae09d9897..e927c1a0d1 100644
--- a/deps/v8/src/parsing/parse-info.cc
+++ b/deps/v8/src/parsing/parse-info.cc
@@ -28,6 +28,7 @@ ParseInfo::ParseInfo(AccountingAllocator* zone_allocator)
stack_limit_(0),
hash_seed_(0),
function_kind_(FunctionKind::kNormalFunction),
+ function_syntax_kind_(FunctionSyntaxKind::kDeclaration),
script_id_(-1),
start_position_(0),
end_position_(0),
@@ -62,7 +63,8 @@ ParseInfo::ParseInfo(Isolate* isolate, AccountingAllocator* zone_allocator)
set_allow_natives_syntax(FLAG_allow_natives_syntax);
set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import);
set_allow_harmony_import_meta(FLAG_harmony_import_meta);
- set_allow_harmony_numeric_separator(FLAG_harmony_numeric_separator);
+ set_allow_harmony_optional_chaining(FLAG_harmony_optional_chaining);
+ set_allow_harmony_nullish(FLAG_harmony_nullish);
set_allow_harmony_private_methods(FLAG_harmony_private_methods);
}
@@ -74,15 +76,13 @@ ParseInfo::ParseInfo(Isolate* isolate)
template <typename T>
void ParseInfo::SetFunctionInfo(T function) {
- set_is_named_expression(function->is_named_expression());
set_language_mode(function->language_mode());
set_function_kind(function->kind());
- set_declaration(function->is_declaration());
+ set_function_syntax_kind(function->syntax_kind());
set_requires_instance_members_initializer(
function->requires_instance_members_initializer());
set_toplevel(function->is_toplevel());
set_is_oneshot_iife(function->is_oneshot_iife());
- set_wrapped_as_function(function->is_wrapped());
}
ParseInfo::ParseInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared)
@@ -220,7 +220,9 @@ void ParseInfo::SetScriptForToplevelCompile(Isolate* isolate,
set_toplevel();
set_collect_type_profile(isolate->is_collecting_type_profile() &&
script->IsUserJavaScript());
- set_wrapped_as_function(script->is_wrapped());
+ if (script->is_wrapped()) {
+ set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
+ }
}
void ParseInfo::set_script(Handle<Script> script) {
diff --git a/deps/v8/src/parsing/parse-info.h b/deps/v8/src/parsing/parse-info.h
index 7b74e7aa90..8afb124155 100644
--- a/deps/v8/src/parsing/parse-info.h
+++ b/deps/v8/src/parsing/parse-info.h
@@ -13,6 +13,7 @@
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/objects/function-kind.h"
+#include "src/objects/function-syntax-kind.h"
#include "src/objects/script.h"
#include "src/parsing/pending-compilation-error-handler.h"
#include "src/parsing/preparse-data.h"
@@ -75,8 +76,6 @@ class V8_EXPORT_PRIVATE ParseInfo {
FLAG_ACCESSOR(kStrictMode, is_strict_mode, set_strict_mode)
FLAG_ACCESSOR(kModule, is_module, set_module)
FLAG_ACCESSOR(kAllowLazyParsing, allow_lazy_parsing, set_allow_lazy_parsing)
- FLAG_ACCESSOR(kIsNamedExpression, is_named_expression,
- set_is_named_expression)
FLAG_ACCESSOR(kLazyCompile, lazy_compile, set_lazy_compile)
FLAG_ACCESSOR(kCollectTypeProfile, collect_type_profile,
set_collect_type_profile)
@@ -88,10 +87,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
set_block_coverage_enabled)
FLAG_ACCESSOR(kOnBackgroundThread, on_background_thread,
set_on_background_thread)
- FLAG_ACCESSOR(kWrappedAsFunction, is_wrapped_as_function,
- set_wrapped_as_function)
FLAG_ACCESSOR(kAllowEvalCache, allow_eval_cache, set_allow_eval_cache)
- FLAG_ACCESSOR(kIsDeclaration, is_declaration, set_declaration)
FLAG_ACCESSOR(kRequiresInstanceMembersInitializer,
requires_instance_members_initializer,
set_requires_instance_members_initializer)
@@ -105,13 +101,16 @@ class V8_EXPORT_PRIVATE ParseInfo {
set_allow_harmony_dynamic_import)
FLAG_ACCESSOR(kAllowHarmonyImportMeta, allow_harmony_import_meta,
set_allow_harmony_import_meta)
- FLAG_ACCESSOR(kAllowHarmonyNumericSeparator, allow_harmony_numeric_separator,
- set_allow_harmony_numeric_separator)
+ FLAG_ACCESSOR(kAllowHarmonyOptionalChaining, allow_harmony_optional_chaining,
+ set_allow_harmony_optional_chaining)
FLAG_ACCESSOR(kAllowHarmonyPrivateMethods, allow_harmony_private_methods,
set_allow_harmony_private_methods)
FLAG_ACCESSOR(kIsOneshotIIFE, is_oneshot_iife, set_is_oneshot_iife)
FLAG_ACCESSOR(kCollectSourcePositions, collect_source_positions,
set_collect_source_positions)
+ FLAG_ACCESSOR(kAllowHarmonyNullish, allow_harmony_nullish,
+ set_allow_harmony_nullish)
+
#undef FLAG_ACCESSOR
void set_parse_restriction(ParseRestriction restriction) {
@@ -189,6 +188,17 @@ class V8_EXPORT_PRIVATE ParseInfo {
function_kind_ = function_kind;
}
+ FunctionSyntaxKind function_syntax_kind() const {
+ return function_syntax_kind_;
+ }
+ void set_function_syntax_kind(FunctionSyntaxKind function_syntax_kind) {
+ function_syntax_kind_ = function_syntax_kind;
+ }
+
+ bool is_wrapped_as_function() const {
+ return function_syntax_kind() == FunctionSyntaxKind::kWrapped;
+ }
+
int max_function_literal_id() const { return max_function_literal_id_; }
void set_max_function_literal_id(int max_function_literal_id) {
max_function_literal_id_ = max_function_literal_id;
@@ -277,7 +287,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
void SetFunctionInfo(T function);
// Various configuration flags for parsing.
- enum Flag {
+ enum Flag : uint32_t {
// ---------- Input flags ---------------------------
kToplevel = 1 << 0,
kEager = 1 << 1,
@@ -287,40 +297,39 @@ class V8_EXPORT_PRIVATE ParseInfo {
kParseRestriction = 1 << 5,
kModule = 1 << 6,
kAllowLazyParsing = 1 << 7,
- kIsNamedExpression = 1 << 8,
- kLazyCompile = 1 << 9,
- kCollectTypeProfile = 1 << 10,
- kCoverageEnabled = 1 << 11,
- kBlockCoverageEnabled = 1 << 12,
- kIsAsmWasmBroken = 1 << 13,
- kOnBackgroundThread = 1 << 14,
- kWrappedAsFunction = 1 << 15, // Implicitly wrapped as function.
- kAllowEvalCache = 1 << 16,
- kIsDeclaration = 1 << 17,
- kRequiresInstanceMembersInitializer = 1 << 18,
- kContainsAsmModule = 1 << 19,
- kMightAlwaysOpt = 1 << 20,
- kAllowLazyCompile = 1 << 21,
- kAllowNativeSyntax = 1 << 22,
- kAllowHarmonyPublicFields = 1 << 23,
- kAllowHarmonyStaticFields = 1 << 24,
- kAllowHarmonyDynamicImport = 1 << 25,
- kAllowHarmonyImportMeta = 1 << 26,
- kAllowHarmonyNumericSeparator = 1 << 27,
- kAllowHarmonyPrivateFields = 1 << 28,
- kAllowHarmonyPrivateMethods = 1 << 29,
- kIsOneshotIIFE = 1 << 30,
- kCollectSourcePositions = 1 << 31,
+ kLazyCompile = 1 << 8,
+ kCollectTypeProfile = 1 << 9,
+ kCoverageEnabled = 1 << 10,
+ kBlockCoverageEnabled = 1 << 11,
+ kIsAsmWasmBroken = 1 << 12,
+ kOnBackgroundThread = 1 << 13,
+ kAllowEvalCache = 1 << 14,
+ kRequiresInstanceMembersInitializer = 1 << 15,
+ kContainsAsmModule = 1 << 16,
+ kMightAlwaysOpt = 1 << 17,
+ kAllowLazyCompile = 1 << 18,
+ kAllowNativeSyntax = 1 << 19,
+ kAllowHarmonyPublicFields = 1 << 20,
+ kAllowHarmonyStaticFields = 1 << 21,
+ kAllowHarmonyDynamicImport = 1 << 22,
+ kAllowHarmonyImportMeta = 1 << 23,
+ kAllowHarmonyOptionalChaining = 1 << 24,
+ kAllowHarmonyPrivateFields = 1 << 25,
+ kAllowHarmonyPrivateMethods = 1 << 26,
+ kIsOneshotIIFE = 1 << 27,
+ kCollectSourcePositions = 1 << 28,
+ kAllowHarmonyNullish = 1 << 29,
};
//------------- Inputs to parsing and scope analysis -----------------------
std::unique_ptr<Zone> zone_;
- unsigned flags_;
+ uint32_t flags_;
v8::Extension* extension_;
DeclarationScope* script_scope_;
uintptr_t stack_limit_;
uint64_t hash_seed_;
FunctionKind function_kind_;
+ FunctionSyntaxKind function_syntax_kind_;
int script_id_;
int start_position_;
int end_position_;
diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h
index 2dfb0d2461..f43496b429 100644
--- a/deps/v8/src/parsing/parser-base.h
+++ b/deps/v8/src/parsing/parser-base.h
@@ -6,6 +6,7 @@
#define V8_PARSING_PARSER_BASE_H_
#include <stdint.h>
+#include <utility>
#include <vector>
#include "src/ast/ast-source-ranges.h"
@@ -284,11 +285,21 @@ class ParserBase {
#undef ALLOW_ACCESSORS
V8_INLINE bool has_error() const { return scanner()->has_parser_error(); }
- bool allow_harmony_numeric_separator() const {
- return scanner()->allow_harmony_numeric_separator();
+
+ bool allow_harmony_optional_chaining() const {
+ return scanner()->allow_harmony_optional_chaining();
+ }
+
+ void set_allow_harmony_optional_chaining(bool allow) {
+ scanner()->set_allow_harmony_optional_chaining(allow);
+ }
+
+ bool allow_harmony_nullish() const {
+ return scanner()->allow_harmony_nullish();
}
- void set_allow_harmony_numeric_separator(bool allow) {
- scanner()->set_allow_harmony_numeric_separator(allow);
+
+ void set_allow_harmony_nullish(bool allow) {
+ scanner()->set_allow_harmony_nullish(allow);
}
uintptr_t stack_limit() const { return stack_limit_; }
@@ -624,9 +635,17 @@ class ParserBase {
}
}
- RequiresBrandCheckFlag RequiresBrandCheck(ClassLiteralProperty::Kind kind) {
- return kind == ClassLiteralProperty::Kind::FIELD ? kNoBrandCheck
- : kRequiresBrandCheck;
+ VariableMode GetVariableMode(ClassLiteralProperty::Kind kind) {
+ switch (kind) {
+ case ClassLiteralProperty::Kind::FIELD:
+ return VariableMode::kConst;
+ case ClassLiteralProperty::Kind::METHOD:
+ return VariableMode::kPrivateMethod;
+ case ClassLiteralProperty::Kind::GETTER:
+ return VariableMode::kPrivateGetterOnly;
+ case ClassLiteralProperty::Kind::SETTER:
+ return VariableMode::kPrivateSetterOnly;
+ }
}
const AstRawString* ClassFieldVariableName(AstValueFactory* ast_value_factory,
@@ -1019,7 +1038,8 @@ class ParserBase {
ExpressionT ParseAssignmentExpressionCoverGrammar();
ExpressionT ParseArrowParametersWithRest(ExpressionListT* list,
- AccumulationScope* scope);
+ AccumulationScope* scope,
+ int seen_variables);
ExpressionT ParseArrayLiteral();
@@ -1047,6 +1067,8 @@ class ParserBase {
ExpressionT ParseYieldExpression();
V8_INLINE ExpressionT ParseConditionalExpression();
ExpressionT ParseConditionalContinuation(ExpressionT expression, int pos);
+ ExpressionT ParseLogicalExpression();
+ ExpressionT ParseCoalesceExpression(ExpressionT expression);
ExpressionT ParseBinaryContinuation(ExpressionT x, int prec, int prec1);
V8_INLINE ExpressionT ParseBinaryExpression(int prec);
ExpressionT ParseUnaryOrPrefixExpression();
@@ -1106,7 +1128,7 @@ class ParserBase {
void ParseFunctionBody(StatementListT* body, IdentifierT function_name,
int pos, const FormalParametersT& parameters,
FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
+ FunctionSyntaxKind function_syntax_kind,
FunctionBodyType body_type);
// Check if the scope has conflicting var/let declarations from different
@@ -1271,18 +1293,7 @@ class ParserBase {
Scope* scope) {
if (impl()->IsIdentifier(expression) &&
impl()->IsEval(impl()->AsIdentifier(expression))) {
- scope->RecordInnerScopeEvalCall();
function_state_->RecordFunctionOrEvalCall();
- if (is_sloppy(scope->language_mode())) {
- // For sloppy scopes we also have to record the call at function level,
- // in case it includes declarations that will be hoisted.
- scope->GetDeclarationScope()->RecordEvalCall();
- }
-
- // This call is only necessary to track evals that may be
- // inside arrow function parameter lists. In that case,
- // Scope::Snapshot::Reparent will move this bit down into
- // the arrow function's scope.
scope->RecordEvalCall();
return Call::IS_POSSIBLY_EVAL;
@@ -1320,6 +1331,11 @@ class ParserBase {
return expression_scope_;
}
+ bool MaybeParsingArrowhead() const {
+ return expression_scope_ != nullptr &&
+ expression_scope_->has_possible_arrow_parameter_in_scope_chain();
+ }
+
class AcceptINScope final {
public:
AcceptINScope(ParserBase* parser, bool accept_IN)
@@ -1365,7 +1381,9 @@ class ParserBase {
};
std::vector<void*>* pointer_buffer() { return &pointer_buffer_; }
- std::vector<void*>* variable_buffer() { return &variable_buffer_; }
+ std::vector<std::pair<VariableProxy*, int>>* variable_buffer() {
+ return &variable_buffer_;
+ }
// Parser base's protected field members.
@@ -1390,7 +1408,7 @@ class ParserBase {
ExpressionScope* expression_scope_;
std::vector<void*> pointer_buffer_;
- std::vector<void*> variable_buffer_;
+ std::vector<std::pair<VariableProxy*, int>> variable_buffer_;
Scanner* scanner_;
@@ -1688,6 +1706,7 @@ ParserBase<Impl>::ParsePrimaryExpression() {
ClassifyParameter(name, beg_pos, end_position());
ExpressionT result =
impl()->ExpressionFromIdentifier(name, beg_pos, InferName::kNo);
+ parsing_scope.SetInitializers(0, peek_position());
next_arrow_function_info_.scope = parsing_scope.ValidateAndCreateScope();
return result;
}
@@ -1825,9 +1844,11 @@ ParserBase<Impl>::ParseExpressionCoverGrammar() {
ExpressionListT list(pointer_buffer());
ExpressionT expression;
AccumulationScope accumulation_scope(expression_scope());
+ int variable_index = 0;
while (true) {
if (V8_UNLIKELY(peek() == Token::ELLIPSIS)) {
- return ParseArrowParametersWithRest(&list, &accumulation_scope);
+ return ParseArrowParametersWithRest(&list, &accumulation_scope,
+ variable_index);
}
int expr_pos = peek_position();
@@ -1836,6 +1857,9 @@ ParserBase<Impl>::ParseExpressionCoverGrammar() {
ClassifyArrowParameter(&accumulation_scope, expr_pos, expression);
list.Add(expression);
+ variable_index =
+ expression_scope()->SetInitializers(variable_index, peek_position());
+
if (!Check(Token::COMMA)) break;
if (peek() == Token::RPAREN && PeekAhead() == Token::ARROW) {
@@ -1863,7 +1887,7 @@ template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseArrowParametersWithRest(
typename ParserBase<Impl>::ExpressionListT* list,
- AccumulationScope* accumulation_scope) {
+ AccumulationScope* accumulation_scope, int seen_variables) {
Consume(Token::ELLIPSIS);
Scanner::Location ellipsis = scanner()->location();
@@ -1885,6 +1909,8 @@ ParserBase<Impl>::ParseArrowParametersWithRest(
return impl()->FailureExpression();
}
+ expression_scope()->SetInitializers(seen_variables, peek_position());
+
// 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only
// as the formal parameters of'(x, y, ...z) => foo', and is not itself a
// valid expression.
@@ -2204,7 +2230,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info,
ExpressionT value = impl()->ParseFunctionLiteral(
prop_info->name, scanner()->location(), kSkipFunctionNameCheck, kind,
- name_token_position, FunctionLiteral::kAccessorOrMethod,
+ name_token_position, FunctionSyntaxKind::kAccessorOrMethod,
language_mode(), nullptr);
ClassLiteralPropertyT result = factory()->NewClassLiteralProperty(
@@ -2236,7 +2262,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassInfo* class_info,
FunctionLiteralT value = impl()->ParseFunctionLiteral(
prop_info->name, scanner()->location(), kSkipFunctionNameCheck, kind,
- name_token_position, FunctionLiteral::kAccessorOrMethod,
+ name_token_position, FunctionSyntaxKind::kAccessorOrMethod,
language_mode(), nullptr);
ClassLiteralProperty::Kind property_kind =
@@ -2417,8 +2443,8 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info,
ExpressionT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- next_loc.beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(),
- nullptr);
+ next_loc.beg_pos, FunctionSyntaxKind::kAccessorOrMethod,
+ language_mode(), nullptr);
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
name_expression, value, ObjectLiteralProperty::COMPUTED,
@@ -2449,8 +2475,8 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info,
FunctionLiteralT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- next_loc.beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(),
- nullptr);
+ next_loc.beg_pos, FunctionSyntaxKind::kAccessorOrMethod,
+ language_mode(), nullptr);
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
name_expression, value,
@@ -2545,6 +2571,7 @@ void ParserBase<Impl>::ParseArguments(
Consume(Token::LPAREN);
AccumulationScope accumulation_scope(expression_scope());
+ int variable_index = 0;
while (peek() != Token::RPAREN) {
int start_pos = peek_position();
bool is_spread = Check(Token::ELLIPSIS);
@@ -2572,6 +2599,10 @@ void ParserBase<Impl>::ParseArguments(
argument = factory()->NewSpread(argument, start_pos, expr_pos);
}
args->Add(argument);
+
+ variable_index =
+ expression_scope()->SetInitializers(variable_index, peek_position());
+
if (!Check(Token::COMMA)) break;
}
@@ -2650,6 +2681,7 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammar() {
expression_scope()->RecordDeclarationError(
Scanner::Location(lhs_beg_pos, end_position()),
MessageTemplate::kInvalidPropertyBindingPattern);
+ expression_scope()->ValidateAsExpression();
} else if (expression->IsPattern() && op == Token::ASSIGN) {
// Destructuring assignmment.
if (expression->is_parenthesized()) {
@@ -2777,12 +2809,11 @@ template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseConditionalExpression() {
// ConditionalExpression ::
- // LogicalOrExpression
- // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
-
+ // LogicalExpression
+ // LogicalExpression '?' AssignmentExpression ':' AssignmentExpression
+ //
int pos = peek_position();
- // We start using the binary expression parser for prec >= 4 only!
- ExpressionT expression = ParseBinaryExpression(4);
+ ExpressionT expression = ParseLogicalExpression();
return peek() == Token::CONDITIONAL
? ParseConditionalContinuation(expression, pos)
: expression;
@@ -2790,6 +2821,60 @@ ParserBase<Impl>::ParseConditionalExpression() {
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseLogicalExpression() {
+ // LogicalExpression ::
+ // LogicalORExpression
+ // CoalesceExpression
+
+ // Both LogicalORExpression and CoalesceExpression start with BitwiseOR.
+ // Parse for binary expressions >= 6 (BitwiseOR);
+ ExpressionT expression = ParseBinaryExpression(6);
+ if (peek() == Token::AND || peek() == Token::OR) {
+ // LogicalORExpression, pickup parsing where we left off.
+ int prec1 = Token::Precedence(peek(), accept_IN_);
+ expression = ParseBinaryContinuation(expression, 4, prec1);
+ } else if (V8_UNLIKELY(peek() == Token::NULLISH)) {
+ expression = ParseCoalesceExpression(expression);
+ }
+ return expression;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseCoalesceExpression(ExpressionT expression) {
+ // CoalesceExpression ::
+ // CoalesceExpressionHead ?? BitwiseORExpression
+ //
+ // CoalesceExpressionHead ::
+ // CoalesceExpression
+ // BitwiseORExpression
+
+ // We create a binary operation for the first nullish, otherwise collapse
+ // into an nary expresion.
+ bool first_nullish = true;
+ while (peek() == Token::NULLISH) {
+ SourceRange right_range;
+ SourceRangeScope right_range_scope(scanner(), &right_range);
+ Consume(Token::NULLISH);
+ int pos = peek_position();
+
+ // Parse BitwiseOR or higher.
+ ExpressionT y = ParseBinaryExpression(6);
+ if (first_nullish) {
+ expression =
+ factory()->NewBinaryOperation(Token::NULLISH, expression, y, pos);
+ impl()->RecordBinaryOperationSourceRange(expression, right_range);
+ first_nullish = false;
+ } else {
+ impl()->CollapseNaryExpression(&expression, y, Token::NULLISH, pos,
+ right_range);
+ }
+ }
+ return expression;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseConditionalContinuation(ExpressionT expression,
int pos) {
SourceRange then_range, else_range;
@@ -3059,7 +3144,7 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
}
if (has_spread) {
- result = impl()->SpreadCall(result, args, pos, Call::NOT_EVAL);
+ result = impl()->SpreadCall(result, args, pos, Call::NOT_EVAL, false);
} else {
result = factory()->NewCall(result, args, pos, Call::NOT_EVAL);
}
@@ -3070,25 +3155,42 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
if (!Token::IsPropertyOrCall(peek())) return result;
}
+ bool optional_chaining = false;
+ bool is_optional = false;
do {
switch (peek()) {
+ case Token::QUESTION_PERIOD: {
+ if (is_optional) {
+ ReportUnexpectedToken(peek());
+ return impl()->FailureExpression();
+ }
+ Consume(Token::QUESTION_PERIOD);
+ is_optional = true;
+ optional_chaining = true;
+ continue;
+ }
+
/* Property */
case Token::LBRACK: {
Consume(Token::LBRACK);
int pos = position();
AcceptINScope scope(this, true);
ExpressionT index = ParseExpressionCoverGrammar();
- result = factory()->NewProperty(result, index, pos);
+ result = factory()->NewProperty(result, index, pos, is_optional);
Expect(Token::RBRACK);
break;
}
/* Property */
case Token::PERIOD: {
+ if (is_optional) {
+ ReportUnexpectedToken(Next());
+ return impl()->FailureExpression();
+ }
Consume(Token::PERIOD);
int pos = position();
ExpressionT key = ParsePropertyOrPrivatePropertyName();
- result = factory()->NewProperty(result, key, pos);
+ result = factory()->NewProperty(result, key, pos, is_optional);
break;
}
@@ -3133,22 +3235,39 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
CheckPossibleEvalCall(result, scope());
if (has_spread) {
- result = impl()->SpreadCall(result, args, pos, is_possibly_eval);
+ result = impl()->SpreadCall(result, args, pos, is_possibly_eval,
+ is_optional);
} else {
- result = factory()->NewCall(result, args, pos, is_possibly_eval);
+ result = factory()->NewCall(result, args, pos, is_possibly_eval,
+ is_optional);
}
fni_.RemoveLastFunction();
break;
}
- /* Call */
default:
+ /* Optional Property */
+ if (is_optional) {
+ DCHECK_EQ(scanner()->current_token(), Token::QUESTION_PERIOD);
+ int pos = position();
+ ExpressionT key = ParsePropertyOrPrivatePropertyName();
+ result = factory()->NewProperty(result, key, pos, is_optional);
+ break;
+ }
+ if (optional_chaining) {
+ impl()->ReportMessageAt(scanner()->peek_location(),
+ MessageTemplate::kOptionalChainingNoTemplate);
+ return impl()->FailureExpression();
+ }
+ /* Tagged Template */
DCHECK(Token::IsTemplate(peek()));
result = ParseTemplateLiteral(result, position(), true);
break;
}
- } while (Token::IsPropertyOrCall(peek()));
+ is_optional = false;
+ } while (is_optional || Token::IsPropertyOrCall(peek()));
+ if (optional_chaining) return factory()->NewOptionalChain(result);
return result;
}
@@ -3210,6 +3329,13 @@ ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression() {
// The expression can still continue with . or [ after the arguments.
return ParseMemberExpressionContinuation(result);
}
+
+ if (peek() == Token::QUESTION_PERIOD) {
+ impl()->ReportMessageAt(scanner()->peek_location(),
+ MessageTemplate::kOptionalChainingNoNew);
+ return impl()->FailureExpression();
+ }
+
// NewExpression without arguments.
ExpressionListT args(pointer_buffer());
return factory()->NewCallNew(result, args, new_pos);
@@ -3227,8 +3353,8 @@ ParserBase<Impl>::ParseFunctionExpression() {
IdentifierT name = impl()->NullIdentifier();
bool is_strict_reserved_name = Token::IsStrictReservedWord(peek());
Scanner::Location function_name_location = Scanner::Location::invalid();
- FunctionLiteral::FunctionType function_type =
- FunctionLiteral::kAnonymousExpression;
+ FunctionSyntaxKind function_syntax_kind =
+ FunctionSyntaxKind::kAnonymousExpression;
if (impl()->ParsingDynamicFunctionDeclaration()) {
// We don't want dynamic functions to actually declare their name
// "anonymous". We just want that name in the toString().
@@ -3239,14 +3365,14 @@ ParserBase<Impl>::ParseFunctionExpression() {
} else if (peek_any_identifier()) {
name = ParseIdentifier(function_kind);
function_name_location = scanner()->location();
- function_type = FunctionLiteral::kNamedExpression;
+ function_syntax_kind = FunctionSyntaxKind::kNamedExpression;
}
FunctionLiteralT result = impl()->ParseFunctionLiteral(
name, function_name_location,
is_strict_reserved_name ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown,
- function_kind, function_token_position, function_type, language_mode(),
- nullptr);
+ function_kind, function_token_position, function_syntax_kind,
+ language_mode(), nullptr);
// TODO(verwaest): FailureFunctionLiteral?
if (impl()->IsNull(result)) return impl()->FailureExpression();
return result;
@@ -3332,6 +3458,11 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
impl()->ReportMessage(MessageTemplate::kUnexpectedPrivateField);
return impl()->FailureExpression();
}
+ if (peek() == Token::QUESTION_PERIOD) {
+ Consume(Token::QUESTION_PERIOD);
+ impl()->ReportMessage(MessageTemplate::kOptionalChainingNoSuper);
+ return impl()->FailureExpression();
+ }
scope->RecordSuperPropertyUsage();
UseThis();
return impl()->NewSuperPropertyReference(pos);
@@ -3342,7 +3473,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
// TODO(rossberg): This might not be the correct FunctionState for the
// method here.
expression_scope()->RecordThisUse();
- UseThis()->SetMaybeAssigned();
+ UseThis();
return impl()->NewSuperCallReference(pos);
}
}
@@ -3749,7 +3880,7 @@ ParserBase<Impl>::ParseHoistableDeclaration(
FunctionLiteralT function = impl()->ParseFunctionLiteral(
name, scanner()->location(), name_validity, function_kind, pos,
- FunctionLiteral::kDeclaration, language_mode(), nullptr);
+ FunctionSyntaxKind::kDeclaration, language_mode(), nullptr);
// In ES6, a function behaves as a lexical binding, except in
// a script scope, or the initial scope of eval or another function.
@@ -3859,7 +3990,7 @@ template <typename Impl>
void ParserBase<Impl>::ParseFunctionBody(
StatementListT* body, IdentifierT function_name, int pos,
const FormalParametersT& parameters, FunctionKind kind,
- FunctionLiteral::FunctionType function_type, FunctionBodyType body_type) {
+ FunctionSyntaxKind function_syntax_kind, FunctionBodyType body_type) {
FunctionBodyParsingScope body_parsing_scope(impl());
if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables();
@@ -3902,9 +4033,9 @@ void ParserBase<Impl>::ParseFunctionBody(
DCHECK_EQ(FunctionBodyType::kBlock, body_type);
// If we are parsing the source as if it is wrapped in a function, the
// source ends without a closing brace.
- Token::Value closing_token = function_type == FunctionLiteral::kWrapped
- ? Token::EOS
- : Token::RBRACE;
+ Token::Value closing_token =
+ function_syntax_kind == FunctionSyntaxKind::kWrapped ? Token::EOS
+ : Token::RBRACE;
if (IsAsyncGeneratorFunction(kind)) {
impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind,
@@ -3977,7 +4108,8 @@ void ParserBase<Impl>::ParseFunctionBody(
function_scope->DeclareArguments(ast_value_factory());
}
- impl()->DeclareFunctionNameVar(function_name, function_type, function_scope);
+ impl()->DeclareFunctionNameVar(function_name, function_syntax_kind,
+ function_scope);
inner_body.MergeInto(body);
}
@@ -4104,7 +4236,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
int dummy_function_length = -1;
DCHECK_NE(kind & FunctionKind::kArrowFunction, 0);
bool did_preparse_successfully = impl()->SkipFunction(
- nullptr, kind, FunctionLiteral::kAnonymousExpression,
+ nullptr, kind, FunctionSyntaxKind::kAnonymousExpression,
formal_parameters.scope, &dummy_num_parameters,
&dummy_function_length, &produced_preparse_data);
@@ -4140,7 +4272,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
AcceptINScope scope(this, true);
ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition,
parameters, kind,
- FunctionLiteral::kAnonymousExpression,
+ FunctionSyntaxKind::kAnonymousExpression,
FunctionBodyType::kBlock);
CHECK(has_error());
return impl()->FailureExpression();
@@ -4150,7 +4282,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
AcceptINScope scope(this, true);
ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition,
formal_parameters, kind,
- FunctionLiteral::kAnonymousExpression,
+ FunctionSyntaxKind::kAnonymousExpression,
FunctionBodyType::kBlock);
expected_property_count = function_state.expected_property_count();
}
@@ -4159,7 +4291,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
has_braces = false;
ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition,
formal_parameters, kind,
- FunctionLiteral::kAnonymousExpression,
+ FunctionSyntaxKind::kAnonymousExpression,
FunctionBodyType::kExpression);
expected_property_count = function_state.expected_property_count();
}
@@ -4179,7 +4311,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
expected_property_count, formal_parameters.num_parameters(),
formal_parameters.function_length,
FunctionLiteral::kNoDuplicateParameters,
- FunctionLiteral::kAnonymousExpression, eager_compile_hint,
+ FunctionSyntaxKind::kAnonymousExpression, eager_compile_hint,
formal_parameters.scope->start_position(), has_braces,
function_literal_id, produced_preparse_data);
@@ -4343,7 +4475,7 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral() {
int pos = position();
Consume(Token::FUNCTION);
IdentifierT name = impl()->NullIdentifier();
- FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
+ FunctionSyntaxKind syntax_kind = FunctionSyntaxKind::kAnonymousExpression;
ParseFunctionFlags flags = ParseFunctionFlag::kIsAsync;
if (Check(Token::MUL)) flags |= ParseFunctionFlag::kIsGenerator;
@@ -4361,14 +4493,14 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral() {
scanner()->CurrentSymbol(ast_value_factory()) ==
ast_value_factory()->anonymous_string());
} else if (peek_any_identifier()) {
- type = FunctionLiteral::kNamedExpression;
+ syntax_kind = FunctionSyntaxKind::kNamedExpression;
name = ParseIdentifier(kind);
}
FunctionLiteralT result = impl()->ParseFunctionLiteral(
name, scanner()->location(),
is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown,
- kind, pos, type, language_mode(), nullptr);
+ kind, pos, syntax_kind, language_mode(), nullptr);
if (impl()->IsNull(result)) return impl()->FailureExpression();
return result;
}
@@ -5742,6 +5874,7 @@ typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop(
int stmt_pos, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond,
StatementT* next, StatementT* body) {
+ CheckStackOverflow();
ForStatementT loop = factory()->NewForStatement(labels, own_labels, stmt_pos);
TargetT target(this, loop);
@@ -5928,15 +6061,14 @@ void ParserBase<Impl>::CheckClassMethodName(IdentifierT name,
AstValueFactory* avf = ast_value_factory();
- if (is_static) {
+ if (impl()->IdentifierEquals(name, avf->private_constructor_string())) {
+ ReportMessage(MessageTemplate::kConstructorIsPrivate);
+ return;
+ } else if (is_static) {
if (impl()->IdentifierEquals(name, avf->prototype_string())) {
ReportMessage(MessageTemplate::kStaticPrototype);
return;
}
- } else if (impl()->IdentifierEquals(name,
- avf->private_constructor_string())) {
- ReportMessage(MessageTemplate::kConstructorIsPrivate);
- return;
} else if (impl()->IdentifierEquals(name, avf->constructor_string())) {
if (flags != ParseFunctionFlag::kIsNormal || IsAccessor(type)) {
MessageTemplate msg = (flags & ParseFunctionFlag::kIsGenerator) != 0
diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc
index 2a860da3d0..e1bebc71f0 100644
--- a/deps/v8/src/parsing/parser.cc
+++ b/deps/v8/src/parsing/parser.cc
@@ -78,8 +78,8 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
name, function_scope, body, expected_property_count, parameter_count,
parameter_count, FunctionLiteral::kNoDuplicateParameters,
- FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos,
- true, GetNextFunctionLiteralId());
+ FunctionSyntaxKind::kAnonymousExpression, default_eager_compile_hint(),
+ pos, true, GetNextFunctionLiteralId());
return function_literal;
}
@@ -424,7 +424,8 @@ Parser::Parser(ParseInfo* info)
set_allow_natives(info->allow_natives_syntax());
set_allow_harmony_dynamic_import(info->allow_harmony_dynamic_import());
set_allow_harmony_import_meta(info->allow_harmony_import_meta());
- set_allow_harmony_numeric_separator(info->allow_harmony_numeric_separator());
+ set_allow_harmony_nullish(info->allow_harmony_nullish());
+ set_allow_harmony_optional_chaining(info->allow_harmony_optional_chaining());
set_allow_harmony_private_methods(info->allow_harmony_private_methods());
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
@@ -676,7 +677,7 @@ void Parser::ParseWrapped(Isolate* isolate, ParseInfo* info,
FunctionLiteral* function_literal = ParseFunctionLiteral(
function_name, location, kSkipFunctionNameCheck, kNormalFunction,
- kNoSourcePosition, FunctionLiteral::kWrapped, LanguageMode::kSloppy,
+ kNoSourcePosition, FunctionSyntaxKind::kWrapped, LanguageMode::kSloppy,
arguments_for_wrapped_function);
Statement* return_statement = factory()->NewReturnStatement(
@@ -728,20 +729,6 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
return result;
}
-static FunctionLiteral::FunctionType ComputeFunctionType(ParseInfo* info) {
- if (info->is_wrapped_as_function()) {
- return FunctionLiteral::kWrapped;
- } else if (info->is_declaration()) {
- return FunctionLiteral::kDeclaration;
- } else if (info->is_named_expression()) {
- return FunctionLiteral::kNamedExpression;
- } else if (IsConciseMethod(info->function_kind()) ||
- IsAccessorFunction(info->function_kind())) {
- return FunctionLiteral::kAccessorOrMethod;
- }
- return FunctionLiteral::kAnonymousExpression;
-}
-
FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
const AstRawString* raw_name) {
DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr);
@@ -770,8 +757,10 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
BlockState block_state(&scope_, outer);
DCHECK(is_sloppy(outer->language_mode()) ||
is_strict(info->language_mode()));
- FunctionLiteral::FunctionType function_type = ComputeFunctionType(info);
FunctionKind kind = info->function_kind();
+ DCHECK_IMPLIES(
+ IsConciseMethod(kind) || IsAccessorFunction(kind),
+ info->function_syntax_kind() == FunctionSyntaxKind::kAccessorOrMethod);
if (IsArrowFunction(kind)) {
if (IsAsyncFunction(kind)) {
@@ -857,8 +846,8 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
: nullptr;
result = ParseFunctionLiteral(
raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind,
- kNoSourcePosition, function_type, info->language_mode(),
- arguments_for_wrapped_function);
+ kNoSourcePosition, info->function_syntax_kind(),
+ info->language_mode(), arguments_for_wrapped_function);
}
if (has_error()) return nullptr;
@@ -1377,11 +1366,12 @@ VariableProxy* Parser::DeclareBoundVariable(const AstRawString* name,
}
void Parser::DeclareAndBindVariable(VariableProxy* proxy, VariableKind kind,
- VariableMode mode, InitializationFlag init,
- Scope* scope, bool* was_added, int begin,
- int end) {
- Variable* var = DeclareVariable(proxy->raw_name(), kind, mode, init, scope,
- was_added, begin, end);
+ VariableMode mode, Scope* scope,
+ bool* was_added, int initializer_position) {
+ Variable* var = DeclareVariable(
+ proxy->raw_name(), kind, mode, Variable::DefaultInitializationFlag(mode),
+ scope, was_added, proxy->position(), kNoSourcePosition);
+ var->set_initializer_position(initializer_position);
proxy->BindTo(var);
}
@@ -1791,9 +1781,9 @@ void Parser::ParseAndRewriteAsyncGeneratorFunctionBody(
}
void Parser::DeclareFunctionNameVar(const AstRawString* function_name,
- FunctionLiteral::FunctionType function_type,
+ FunctionSyntaxKind function_syntax_kind,
DeclarationScope* function_scope) {
- if (function_type == FunctionLiteral::kNamedExpression &&
+ if (function_syntax_kind == FunctionSyntaxKind::kNamedExpression &&
function_scope->LookupLocal(function_name) == nullptr) {
DCHECK_EQ(function_scope, scope());
function_scope->DeclareFunctionVar(function_name);
@@ -2238,7 +2228,7 @@ void Parser::PrepareGeneratorVariables() {
FunctionLiteral* Parser::ParseFunctionLiteral(
const AstRawString* function_name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
- int function_token_pos, FunctionLiteral::FunctionType function_type,
+ int function_token_pos, FunctionSyntaxKind function_syntax_kind,
LanguageMode language_mode,
ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
// Function ::
@@ -2250,7 +2240,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Setter ::
// '(' PropertySetParameterList ')' '{' FunctionBody '}'
- bool is_wrapped = function_type == FunctionLiteral::kWrapped;
+ bool is_wrapped = function_syntax_kind == FunctionSyntaxKind::kWrapped;
DCHECK_EQ(is_wrapped, arguments_for_wrapped_function != nullptr);
int pos = function_token_pos == kNoSourcePosition ? peek_position()
@@ -2385,15 +2375,15 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// try to lazy parse in the first place, we'll have to parse eagerly.
bool did_preparse_successfully =
should_preparse &&
- SkipFunction(function_name, kind, function_type, scope, &num_parameters,
- &function_length, &produced_preparse_data);
+ SkipFunction(function_name, kind, function_syntax_kind, scope,
+ &num_parameters, &function_length, &produced_preparse_data);
if (!did_preparse_successfully) {
// If skipping aborted, it rewound the scanner until before the LPAREN.
// Consume it in that case.
if (should_preparse) Consume(Token::LPAREN);
should_post_parallel_task = false;
- ParseFunction(&body, function_name, pos, kind, function_type, scope,
+ ParseFunction(&body, function_name, pos, kind, function_syntax_kind, scope,
&num_parameters, &function_length, &has_duplicate_parameters,
&expected_property_count, &suspend_count,
arguments_for_wrapped_function);
@@ -2439,8 +2429,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Note that the FunctionLiteral needs to be created in the main Zone again.
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
function_name, scope, body, expected_property_count, num_parameters,
- function_length, duplicate_parameters, function_type, eager_compile_hint,
- pos, true, function_literal_id, produced_preparse_data);
+ function_length, duplicate_parameters, function_syntax_kind,
+ eager_compile_hint, pos, true, function_literal_id,
+ produced_preparse_data);
function_literal->set_function_token_position(function_token_pos);
function_literal->set_suspend_count(suspend_count);
@@ -2458,7 +2449,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
}
bool Parser::SkipFunction(const AstRawString* function_name, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
+ FunctionSyntaxKind function_syntax_kind,
DeclarationScope* function_scope, int* num_parameters,
int* function_length,
ProducedPreparseData** produced_preparse_data) {
@@ -2513,7 +2504,7 @@ bool Parser::SkipFunction(const AstRawString* function_name, FunctionKind kind,
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse");
PreParser::PreParseResult result = reusable_preparser()->PreParseFunction(
- function_name, kind, function_type, function_scope, use_counts_,
+ function_name, kind, function_syntax_kind, function_scope, use_counts_,
produced_preparse_data, this->script_id());
if (result == PreParser::kPreParseStackOverflow) {
@@ -2555,7 +2546,7 @@ bool Parser::SkipFunction(const AstRawString* function_name, FunctionKind kind,
closest_class_scope->MigrateUnresolvedPrivateNameTail(
factory(), unresolved_private_tail);
}
- function_scope->AnalyzePartially(this, factory());
+ function_scope->AnalyzePartially(this, factory(), MaybeParsingArrowhead());
}
return true;
@@ -2583,12 +2574,11 @@ Block* Parser::BuildParameterInitializationBlock(
initial_value, kNoSourcePosition);
}
- Scope* param_scope = scope();
+ DeclarationScope* param_scope = scope()->AsDeclarationScope();
ScopedPtrList<Statement>* param_init_statements = &init_statements;
base::Optional<ScopedPtrList<Statement>> non_simple_param_init_statements;
- if (!parameter->is_simple() &&
- scope()->AsDeclarationScope()->calls_sloppy_eval()) {
+ if (!parameter->is_simple() && param_scope->sloppy_eval_can_extend_vars()) {
param_scope = NewVarblockScope();
param_scope->set_start_position(parameter->pattern->position());
param_scope->set_end_position(parameter->initializer_end_position);
@@ -2613,7 +2603,7 @@ Block* Parser::BuildParameterInitializationBlock(
factory()->NewBlock(true, *non_simple_param_init_statements);
non_simple_param_init_statements.reset();
param_block->set_scope(param_scope);
- param_scope = param_scope->FinalizeBlockScope();
+ param_scope = param_scope->FinalizeBlockScope()->AsDeclarationScope();
init_statements.Add(param_block);
}
++index;
@@ -2678,7 +2668,7 @@ Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) {
void Parser::ParseFunction(
ScopedPtrList<Statement>* body, const AstRawString* function_name, int pos,
- FunctionKind kind, FunctionLiteral::FunctionType function_type,
+ FunctionKind kind, FunctionSyntaxKind function_syntax_kind,
DeclarationScope* function_scope, int* num_parameters, int* function_length,
bool* has_duplicate_parameters, int* expected_property_count,
int* suspend_count,
@@ -2687,7 +2677,7 @@ void Parser::ParseFunction(
FunctionState function_state(&function_state_, &scope_, function_scope);
- bool is_wrapped = function_type == FunctionLiteral::kWrapped;
+ bool is_wrapped = function_syntax_kind == FunctionSyntaxKind::kWrapped;
int expected_parameters_end_pos = parameters_end_pos_;
if (expected_parameters_end_pos != kNoSourcePosition) {
@@ -2749,8 +2739,8 @@ void Parser::ParseFunction(
*function_length = formals.function_length;
AcceptINScope scope(this, true);
- ParseFunctionBody(body, function_name, pos, formals, kind, function_type,
- FunctionBodyType::kBlock);
+ ParseFunctionBody(body, function_name, pos, formals, kind,
+ function_syntax_kind, FunctionBodyType::kBlock);
*has_duplicate_parameters = formals.has_duplicate();
@@ -2781,15 +2771,15 @@ Variable* Parser::CreateSyntheticContextVariable(const AstRawString* name) {
return proxy->var();
}
-Variable* Parser::CreatePrivateNameVariable(
- ClassScope* scope, RequiresBrandCheckFlag requires_brand_check,
- const AstRawString* name) {
+Variable* Parser::CreatePrivateNameVariable(ClassScope* scope,
+ VariableMode mode,
+ const AstRawString* name) {
DCHECK_NOT_NULL(name);
int begin = position();
int end = end_position();
bool was_added = false;
- Variable* var =
- scope->DeclarePrivateName(name, requires_brand_check, &was_added);
+ DCHECK(IsConstVariableMode(mode));
+ Variable* var = scope->DeclarePrivateName(name, mode, &was_added);
if (!was_added) {
Scanner::Location loc(begin, end);
ReportMessageAt(loc, MessageTemplate::kVarRedeclaration, var->raw_name());
@@ -2824,14 +2814,8 @@ void Parser::DeclarePrivateClassMember(ClassScope* scope,
ClassLiteralProperty* property,
ClassLiteralProperty::Kind kind,
bool is_static, ClassInfo* class_info) {
- DCHECK_IMPLIES(kind == ClassLiteralProperty::Kind::METHOD,
+ DCHECK_IMPLIES(kind != ClassLiteralProperty::Kind::FIELD,
allow_harmony_private_methods());
- // TODO(joyee): We do not support private accessors yet (which allow
- // declaring the same private name twice). Make them noops.
- if (kind != ClassLiteralProperty::Kind::FIELD &&
- kind != ClassLiteralProperty::Kind::METHOD) {
- return;
- }
if (kind == ClassLiteralProperty::Kind::FIELD) {
if (is_static) {
@@ -2842,7 +2826,7 @@ void Parser::DeclarePrivateClassMember(ClassScope* scope,
}
Variable* private_name_var =
- CreatePrivateNameVariable(scope, RequiresBrandCheck(kind), property_name);
+ CreatePrivateNameVariable(scope, GetVariableMode(kind), property_name);
int pos = property->value()->position();
if (pos == kNoSourcePosition) {
pos = property->key()->position();
@@ -2886,7 +2870,7 @@ FunctionLiteral* Parser::CreateInitializerFunction(
FunctionLiteral* result = factory()->NewFunctionLiteral(
ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0,
FunctionLiteral::kNoDuplicateParameters,
- FunctionLiteral::kAnonymousExpression,
+ FunctionSyntaxKind::kAccessorOrMethod,
FunctionLiteral::kShouldEagerCompile, scope->start_position(), false,
GetNextFunctionLiteralId());
@@ -3168,10 +3152,12 @@ ArrayLiteral* Parser::ArrayLiteralFromListWithSpread(
Expression* Parser::SpreadCall(Expression* function,
const ScopedPtrList<Expression>& args_list,
- int pos, Call::PossiblyEval is_possibly_eval) {
+ int pos, Call::PossiblyEval is_possibly_eval,
+ bool optional_chain) {
// Handle this case in BytecodeGenerator.
if (OnlyLastArgIsSpread(args_list) || function->IsSuperCallReference()) {
- return factory()->NewCall(function, args_list, pos);
+ return factory()->NewCall(function, args_list, pos, Call::NOT_EVAL,
+ optional_chain);
}
ScopedPtrList<Expression> args(pointer_buffer());
@@ -3186,8 +3172,9 @@ Expression* Parser::SpreadCall(Expression* function,
VariableProxy* obj = factory()->NewVariableProxy(temp);
Assignment* assign_obj = factory()->NewAssignment(
Token::ASSIGN, obj, function->AsProperty()->obj(), kNoSourcePosition);
- function = factory()->NewProperty(
- assign_obj, function->AsProperty()->key(), kNoSourcePosition);
+ function =
+ factory()->NewProperty(assign_obj, function->AsProperty()->key(),
+ kNoSourcePosition, optional_chain);
args.Add(function);
obj = factory()->NewVariableProxy(temp);
args.Add(obj);
diff --git a/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h
index b7fb19c26f..8170dbb920 100644
--- a/deps/v8/src/parsing/parser.h
+++ b/deps/v8/src/parsing/parser.h
@@ -165,9 +165,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
friend class i::VariableDeclarationParsingScope<ParserTypes<Parser>>;
friend class i::ParameterDeclarationParsingScope<ParserTypes<Parser>>;
friend class i::ArrowHeadParsingScope<ParserTypes<Parser>>;
- friend bool v8::internal::parsing::ParseProgram(ParseInfo*, Isolate*);
+ friend bool v8::internal::parsing::ParseProgram(
+ ParseInfo*, Isolate*, parsing::ReportErrorsAndStatisticsMode stats_mode);
friend bool v8::internal::parsing::ParseFunction(
- ParseInfo*, Handle<SharedFunctionInfo> shared_info, Isolate*);
+ ParseInfo*, Handle<SharedFunctionInfo> shared_info, Isolate*,
+ parsing::ReportErrorsAndStatisticsMode stats_mode);
bool AllowsLazyParsingWithoutUnresolvedVariables() const {
return scope()->AllowsLazyParsingWithoutUnresolvedVariables(
@@ -289,7 +291,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
void ParseAndRewriteAsyncGeneratorFunctionBody(
int pos, FunctionKind kind, ScopedPtrList<Statement>* body);
void DeclareFunctionNameVar(const AstRawString* function_name,
- FunctionLiteral::FunctionType function_type,
+ FunctionSyntaxKind function_syntax_kind,
DeclarationScope* function_scope);
Statement* DeclareFunction(const AstRawString* variable_name,
@@ -297,9 +299,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
VariableKind kind, int beg_pos, int end_pos,
ZonePtrList<const AstRawString>* names);
Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name);
- Variable* CreatePrivateNameVariable(
- ClassScope* scope, RequiresBrandCheckFlag requires_brand_check,
- const AstRawString* name);
+ Variable* CreatePrivateNameVariable(ClassScope* scope, VariableMode mode,
+ const AstRawString* name);
FunctionLiteral* CreateInitializerFunction(
const char* name, DeclarationScope* scope,
ZonePtrList<ClassLiteral::Property>* fields);
@@ -365,7 +366,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
FunctionLiteral* ParseFunctionLiteral(
const AstRawString* name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
- int function_token_position, FunctionLiteral::FunctionType type,
+ int function_token_position, FunctionSyntaxKind type,
LanguageMode language_mode,
ZonePtrList<const AstRawString>* arguments_for_wrapped_function);
@@ -387,9 +388,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
VariableProxy* DeclareBoundVariable(const AstRawString* name,
VariableMode mode, int pos);
void DeclareAndBindVariable(VariableProxy* proxy, VariableKind kind,
- VariableMode mode, InitializationFlag init,
- Scope* declaration_scope, bool* was_added,
- int begin, int end = kNoSourcePosition);
+ VariableMode mode, Scope* declaration_scope,
+ bool* was_added, int initializer_position);
V8_WARN_UNUSED_RESULT
Variable* DeclareVariable(const AstRawString* name, VariableKind kind,
VariableMode mode, InitializationFlag init,
@@ -418,7 +418,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// parsing or could not identify an error correctly, meaning the caller needs
// to fully reparse. In this case it resets the scanner and preparser state.
bool SkipFunction(const AstRawString* function_name, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
+ FunctionSyntaxKind function_syntax_kind,
DeclarationScope* function_scope, int* num_parameters,
int* function_length,
ProducedPreparseData** produced_preparsed_scope_data);
@@ -429,7 +429,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
void ParseFunction(
ScopedPtrList<Statement>* body, const AstRawString* function_name,
- int pos, FunctionKind kind, FunctionLiteral::FunctionType function_type,
+ int pos, FunctionKind kind, FunctionSyntaxKind function_syntax_kind,
DeclarationScope* function_scope, int* num_parameters,
int* function_length, bool* has_duplicate_parameters,
int* expected_property_count, int* suspend_count,
@@ -485,7 +485,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
const ScopedPtrList<Expression>& list);
Expression* SpreadCall(Expression* function,
const ScopedPtrList<Expression>& args, int pos,
- Call::PossiblyEval is_possibly_eval);
+ Call::PossiblyEval is_possibly_eval,
+ bool optional_chain);
Expression* SpreadCallNew(Expression* function,
const ScopedPtrList<Expression>& args, int pos);
Expression* RewriteSuperCall(Expression* call_expression);
diff --git a/deps/v8/src/parsing/parsing.cc b/deps/v8/src/parsing/parsing.cc
index af4cb9b5ee..95cc186787 100644
--- a/deps/v8/src/parsing/parsing.cc
+++ b/deps/v8/src/parsing/parsing.cc
@@ -18,7 +18,8 @@ namespace v8 {
namespace internal {
namespace parsing {
-bool ParseProgram(ParseInfo* info, Isolate* isolate) {
+bool ParseProgram(ParseInfo* info, Isolate* isolate,
+ ReportErrorsAndStatisticsMode mode) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
@@ -39,21 +40,25 @@ bool ParseProgram(ParseInfo* info, Isolate* isolate) {
result = parser.ParseProgram(isolate, info);
info->set_literal(result);
- if (result == nullptr) {
- info->pending_error_handler()->ReportErrors(isolate, info->script(),
- info->ast_value_factory());
- } else {
+ if (result) {
info->set_language_mode(info->literal()->language_mode());
if (info->is_eval()) {
info->set_allow_eval_cache(parser.allow_eval_cache());
}
}
- parser.UpdateStatistics(isolate, info->script());
+
+ if (mode == ReportErrorsAndStatisticsMode::kYes) {
+ if (result == nullptr) {
+ info->pending_error_handler()->ReportErrors(isolate, info->script(),
+ info->ast_value_factory());
+ }
+ parser.UpdateStatistics(isolate, info->script());
+ }
return (result != nullptr);
}
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
- Isolate* isolate) {
+ Isolate* isolate, ReportErrorsAndStatisticsMode mode) {
DCHECK(!info->is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
@@ -76,24 +81,28 @@ bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
result = parser.ParseFunction(isolate, info, shared_info);
info->set_literal(result);
- if (result == nullptr) {
- info->pending_error_handler()->ReportErrors(isolate, info->script(),
- info->ast_value_factory());
- } else {
+ if (result) {
info->ast_value_factory()->Internalize(isolate);
if (info->is_eval()) {
info->set_allow_eval_cache(parser.allow_eval_cache());
}
}
- parser.UpdateStatistics(isolate, info->script());
+
+ if (mode == ReportErrorsAndStatisticsMode::kYes) {
+ if (result == nullptr) {
+ info->pending_error_handler()->ReportErrors(isolate, info->script(),
+ info->ast_value_factory());
+ }
+ parser.UpdateStatistics(isolate, info->script());
+ }
return (result != nullptr);
}
bool ParseAny(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
- Isolate* isolate) {
+ Isolate* isolate, ReportErrorsAndStatisticsMode mode) {
DCHECK(!shared_info.is_null());
- return info->is_toplevel() ? ParseProgram(info, isolate)
- : ParseFunction(info, shared_info, isolate);
+ return info->is_toplevel() ? ParseProgram(info, isolate, mode)
+ : ParseFunction(info, shared_info, isolate, mode);
}
} // namespace parsing
diff --git a/deps/v8/src/parsing/parsing.h b/deps/v8/src/parsing/parsing.h
index 5f19500a19..bdf309d60b 100644
--- a/deps/v8/src/parsing/parsing.h
+++ b/deps/v8/src/parsing/parsing.h
@@ -15,23 +15,27 @@ class SharedFunctionInfo;
namespace parsing {
+enum class ReportErrorsAndStatisticsMode { kYes, kNo };
+
// Parses the top-level source code represented by the parse info and sets its
// function literal. Returns false (and deallocates any allocated AST
// nodes) if parsing failed.
-V8_EXPORT_PRIVATE bool ParseProgram(ParseInfo* info, Isolate* isolate);
+V8_EXPORT_PRIVATE bool ParseProgram(
+ ParseInfo* info, Isolate* isolate,
+ ReportErrorsAndStatisticsMode mode = ReportErrorsAndStatisticsMode::kYes);
// Like ParseProgram but for an individual function which already has a
// allocated shared function info.
-V8_EXPORT_PRIVATE bool ParseFunction(ParseInfo* info,
- Handle<SharedFunctionInfo> shared_info,
- Isolate* isolate);
+V8_EXPORT_PRIVATE bool ParseFunction(
+ ParseInfo* info, Handle<SharedFunctionInfo> shared_info, Isolate* isolate,
+ ReportErrorsAndStatisticsMode mode = ReportErrorsAndStatisticsMode::kYes);
// If you don't know whether info->is_toplevel() is true or not, use this method
// to dispatch to either of the above functions. Prefer to use the above methods
// whenever possible.
-V8_EXPORT_PRIVATE bool ParseAny(ParseInfo* info,
- Handle<SharedFunctionInfo> shared_info,
- Isolate* isolate);
+V8_EXPORT_PRIVATE bool ParseAny(
+ ParseInfo* info, Handle<SharedFunctionInfo> shared_info, Isolate* isolate,
+ ReportErrorsAndStatisticsMode mode = ReportErrorsAndStatisticsMode::kYes);
} // namespace parsing
} // namespace internal
diff --git a/deps/v8/src/parsing/preparse-data.cc b/deps/v8/src/parsing/preparse-data.cc
index ea5e70a3c1..8743732ea2 100644
--- a/deps/v8/src/parsing/preparse-data.cc
+++ b/deps/v8/src/parsing/preparse-data.cc
@@ -21,22 +21,19 @@ namespace internal {
namespace {
-class ScopeCallsSloppyEvalField : public BitField8<bool, 0, 1> {};
-class InnerScopeCallsEvalField
- : public BitField8<bool, ScopeCallsSloppyEvalField::kNext, 1> {};
-
-class VariableMaybeAssignedField : public BitField8<bool, 0, 1> {};
-class VariableContextAllocatedField
- : public BitField8<bool, VariableMaybeAssignedField::kNext, 1> {};
-
-class HasDataField : public BitField<bool, 0, 1> {};
-class LengthEqualsParametersField
- : public BitField<bool, HasDataField::kNext, 1> {};
-class NumberOfParametersField
- : public BitField<uint16_t, LengthEqualsParametersField::kNext, 16> {};
-
-class LanguageField : public BitField8<LanguageMode, 0, 1> {};
-class UsesSuperField : public BitField8<bool, LanguageField::kNext, 1> {};
+using ScopeSloppyEvalCanExtendVarsField = BitField8<bool, 0, 1>;
+using InnerScopeCallsEvalField =
+ ScopeSloppyEvalCanExtendVarsField::Next<bool, 1>;
+
+using VariableMaybeAssignedField = BitField8<bool, 0, 1>;
+using VariableContextAllocatedField = VariableMaybeAssignedField::Next<bool, 1>;
+
+using HasDataField = BitField<bool, 0, 1>;
+using LengthEqualsParametersField = HasDataField::Next<bool, 1>;
+using NumberOfParametersField = LengthEqualsParametersField::Next<uint16_t, 16>;
+
+using LanguageField = BitField8<LanguageMode, 0, 1>;
+using UsesSuperField = LanguageField::Next<bool, 1>;
STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues);
} // namespace
@@ -266,7 +263,7 @@ bool PreparseDataBuilder::ScopeNeedsData(Scope* scope) {
}
if (!scope->is_hidden()) {
for (Variable* var : *scope->locals()) {
- if (IsDeclaredVariableMode(var->mode())) return true;
+ if (IsSerializableVariableMode(var->mode())) return true;
}
}
for (Scope* inner = scope->inner_scope(); inner != nullptr;
@@ -356,9 +353,9 @@ void PreparseDataBuilder::SaveDataForScope(Scope* scope) {
#endif
uint8_t eval =
- ScopeCallsSloppyEvalField::encode(
+ ScopeSloppyEvalCanExtendVarsField::encode(
scope->is_declaration_scope() &&
- scope->AsDeclarationScope()->calls_sloppy_eval()) |
+ scope->AsDeclarationScope()->sloppy_eval_can_extend_vars()) |
InnerScopeCallsEvalField::encode(scope->inner_scope_calls_eval());
byte_data_.Reserve(kUint8Size);
byte_data_.WriteUint8(eval);
@@ -369,7 +366,7 @@ void PreparseDataBuilder::SaveDataForScope(Scope* scope) {
}
for (Variable* var : *scope->locals()) {
- if (IsDeclaredVariableMode(var->mode())) SaveDataForVariable(var);
+ if (IsSerializableVariableMode(var->mode())) SaveDataForVariable(var);
}
SaveDataForInnerScopes(scope);
@@ -603,7 +600,7 @@ void BaseConsumedPreparseData<Data>::RestoreDataForScope(Scope* scope) {
CHECK(scope_data_->HasRemainingBytes(ByteData::kUint8Size));
uint32_t eval = scope_data_->ReadUint8();
- if (ScopeCallsSloppyEvalField::decode(eval)) scope->RecordEvalCall();
+ if (ScopeSloppyEvalCanExtendVarsField::decode(eval)) scope->RecordEvalCall();
if (InnerScopeCallsEvalField::decode(eval)) scope->RecordInnerScopeEvalCall();
if (scope->is_function_scope()) {
@@ -612,7 +609,7 @@ void BaseConsumedPreparseData<Data>::RestoreDataForScope(Scope* scope) {
}
for (Variable* var : *scope->locals()) {
- if (IsDeclaredVariableMode(var->mode())) RestoreDataForVariable(var);
+ if (IsSerializableVariableMode(var->mode())) RestoreDataForVariable(var);
}
RestoreDataForInnerScopes(scope);
diff --git a/deps/v8/src/parsing/preparser.cc b/deps/v8/src/parsing/preparser.cc
index a078d79295..67ee1930ac 100644
--- a/deps/v8/src/parsing/preparser.cc
+++ b/deps/v8/src/parsing/preparser.cc
@@ -107,9 +107,9 @@ void PreParserFormalParameters::ValidateStrictMode(PreParser* preparser) const {
PreParser::PreParseResult PreParser::PreParseFunction(
const AstRawString* function_name, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, int* use_counts,
- ProducedPreparseData** produced_preparse_data, int script_id) {
+ FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope,
+ int* use_counts, ProducedPreparseData** produced_preparse_data,
+ int script_id) {
DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
use_counts_ = use_counts;
set_script_id(script_id);
@@ -229,7 +229,8 @@ PreParser::PreParseResult PreParser::PreParseFunction(
// arguments'.
function_scope->DeclareArguments(ast_value_factory());
- DeclareFunctionNameVar(function_name, function_type, function_scope);
+ DeclareFunctionNameVar(function_name, function_syntax_kind,
+ function_scope);
if (preparse_data_builder_->HasData()) {
*produced_preparse_data =
@@ -267,12 +268,12 @@ PreParser::PreParseResult PreParser::PreParseFunction(
PreParser::Expression PreParser::ParseFunctionLiteral(
Identifier function_name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
- int function_token_pos, FunctionLiteral::FunctionType function_type,
+ int function_token_pos, FunctionSyntaxKind function_syntax_kind,
LanguageMode language_mode,
ZonePtrList<const AstRawString>* arguments_for_wrapped_function) {
// Wrapped functions are not parsed in the preparser.
DCHECK_NULL(arguments_for_wrapped_function);
- DCHECK_NE(FunctionLiteral::kWrapped, function_type);
+ DCHECK_NE(FunctionSyntaxKind::kWrapped, function_syntax_kind);
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
const RuntimeCallCounterId counters[2] = {
@@ -323,8 +324,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
int pos = function_token_pos == kNoSourcePosition ? peek_position()
: function_token_pos;
AcceptINScope scope(this, true);
- ParseFunctionBody(&body, function_name, pos, formals, kind, function_type,
- FunctionBodyType::kBlock);
+ ParseFunctionBody(&body, function_name, pos, formals, kind,
+ function_syntax_kind, FunctionBodyType::kBlock);
// Parsing the body may change the language mode in our scope.
language_mode = function_scope->language_mode();
@@ -385,7 +386,7 @@ PreParserBlock PreParser::BuildParameterInitializationBlock(
const PreParserFormalParameters& parameters) {
DCHECK(!parameters.is_simple);
DCHECK(scope()->is_function_scope());
- if (scope()->AsDeclarationScope()->calls_sloppy_eval() &&
+ if (scope()->AsDeclarationScope()->sloppy_eval_can_extend_vars() &&
preparse_data_builder_ != nullptr) {
// We cannot replicate the Scope structure constructed by the Parser,
// because we've lost information whether each individual parameter was
diff --git a/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h
index 33c312f392..d7c2a92dfa 100644
--- a/deps/v8/src/parsing/preparser.h
+++ b/deps/v8/src/parsing/preparser.h
@@ -351,16 +351,14 @@ class PreParserExpression {
// Expression nodes may be represented as multiple Types, not exclusively
// through kExpression.
// TODO(caitp, adamk): clean up PreParserExpression bitfields.
- using IsParenthesizedField = BitField<bool, TypeField::kNext, 1>;
+ using IsParenthesizedField = TypeField::Next<bool, 1>;
// The rest of the bits are interpreted depending on the value
// of the Type field, so they can share the storage.
- using ExpressionTypeField =
- BitField<ExpressionType, IsParenthesizedField::kNext, 4>;
+ using ExpressionTypeField = IsParenthesizedField::Next<ExpressionType, 4>;
using IdentifierTypeField =
- BitField<PreParserIdentifier::Type, IsParenthesizedField::kNext, 8>;
- using HasCoverInitializedNameField =
- BitField<bool, IsParenthesizedField::kNext, 1>;
+ IsParenthesizedField::Next<PreParserIdentifier::Type, 8>;
+ using HasCoverInitializedNameField = IsParenthesizedField::Next<bool, 1>;
uint32_t code_;
friend class PreParser;
@@ -567,8 +565,13 @@ class PreParserFactory {
return PreParserExpression::Default();
}
+ PreParserExpression NewOptionalChain(const PreParserExpression& expr) {
+ return PreParserExpression::Default();
+ }
+
PreParserExpression NewProperty(const PreParserExpression& obj,
- const PreParserExpression& key, int pos) {
+ const PreParserExpression& key, int pos,
+ bool optional_chain = false) {
if (key.IsIdentifier() && key.AsIdentifier().IsPrivateName()) {
if (obj.IsThis()) {
return PreParserExpression::ThisPrivateReference();
@@ -627,9 +630,10 @@ class PreParserFactory {
int pos) {
return PreParserExpression::Default();
}
- PreParserExpression NewCall(
- PreParserExpression expression, const PreParserExpressionList& arguments,
- int pos, Call::PossiblyEval possibly_eval = Call::NOT_EVAL) {
+ PreParserExpression NewCall(PreParserExpression expression,
+ const PreParserExpressionList& arguments, int pos,
+ Call::PossiblyEval possibly_eval = Call::NOT_EVAL,
+ bool optional_chain = false) {
if (possibly_eval == Call::IS_POSSIBLY_EVAL) {
DCHECK(expression.IsIdentifier() && expression.AsIdentifier().IsEval());
return PreParserExpression::CallEval();
@@ -661,7 +665,7 @@ class PreParserFactory {
const PreParserScopedStatementList& body, int expected_property_count,
int parameter_count, int function_length,
FunctionLiteral::ParameterFlag has_duplicate_parameters,
- FunctionLiteral::FunctionType function_type,
+ FunctionSyntaxKind function_syntax_kind,
FunctionLiteral::EagerCompileHint eager_compile_hint, int position,
bool has_braces, int function_literal_id,
ProducedPreparseData* produced_preparse_data = nullptr) {
@@ -966,9 +970,9 @@ class PreParser : public ParserBase<PreParser> {
// the final '}'.
PreParseResult PreParseFunction(
const AstRawString* function_name, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, int* use_counts,
- ProducedPreparseData** produced_preparser_scope_data, int script_id);
+ FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope,
+ int* use_counts, ProducedPreparseData** produced_preparser_scope_data,
+ int script_id);
PreparseDataBuilder* preparse_data_builder() const {
return preparse_data_builder_;
@@ -1008,7 +1012,7 @@ class PreParser : public ParserBase<PreParser> {
}
V8_INLINE bool SkipFunction(const AstRawString* name, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
+ FunctionSyntaxKind function_syntax_kind,
DeclarationScope* function_scope,
int* num_parameters, int* function_length,
ProducedPreparseData** produced_preparse_data) {
@@ -1018,7 +1022,7 @@ class PreParser : public ParserBase<PreParser> {
Expression ParseFunctionLiteral(
Identifier name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
- int function_token_pos, FunctionLiteral::FunctionType function_type,
+ int function_token_pos, FunctionSyntaxKind function_syntax_kind,
LanguageMode language_mode,
ZonePtrList<const AstRawString>* arguments_for_wrapped_function);
@@ -1054,7 +1058,8 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE PreParserExpression SpreadCall(const PreParserExpression& function,
const PreParserExpressionList& args,
int pos,
- Call::PossiblyEval possibly_eval);
+ Call::PossiblyEval possibly_eval,
+ bool optional_chain);
V8_INLINE PreParserExpression
SpreadCallNew(const PreParserExpression& function,
const PreParserExpressionList& args, int pos);
@@ -1093,23 +1098,26 @@ class PreParser : public ParserBase<PreParser> {
}
void DeclareAndBindVariable(const VariableProxy* proxy, VariableKind kind,
- VariableMode mode, InitializationFlag init,
- Scope* scope, bool* was_added, int position) {
- DeclareVariableName(proxy->raw_name(), mode, scope, was_added, position,
- kind);
+ VariableMode mode, Scope* scope, bool* was_added,
+ int initializer_position) {
+ Variable* var = DeclareVariableName(proxy->raw_name(), mode, scope,
+ was_added, proxy->position(), kind);
+ var->set_initializer_position(initializer_position);
// Don't bother actually binding the proxy.
}
- Variable* DeclarePrivateVariableName(
- const AstRawString* name, ClassScope* scope,
- RequiresBrandCheckFlag requires_brand_check, bool* was_added) {
- return scope->DeclarePrivateName(name, requires_brand_check, was_added);
+ Variable* DeclarePrivateVariableName(const AstRawString* name,
+ ClassScope* scope, VariableMode mode,
+ bool* was_added) {
+ DCHECK(IsConstVariableMode(mode));
+ return scope->DeclarePrivateName(name, mode, was_added);
}
Variable* DeclareVariableName(const AstRawString* name, VariableMode mode,
Scope* scope, bool* was_added,
int position = kNoSourcePosition,
VariableKind kind = NORMAL_VARIABLE) {
+ DCHECK(!IsPrivateMethodOrAccessorVariableMode(mode));
Variable* var = scope->DeclareVariableName(name, mode, was_added, kind);
if (var == nullptr) {
ReportUnidentifiableError();
@@ -1156,11 +1164,10 @@ class PreParser : public ParserBase<PreParser> {
int pos, FunctionKind kind, PreParserScopedStatementList* body) {
ParseStatementList(body, Token::RBRACE);
}
- V8_INLINE void DeclareFunctionNameVar(
- const AstRawString* function_name,
- FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope) {
- if (function_type == FunctionLiteral::kNamedExpression &&
+ V8_INLINE void DeclareFunctionNameVar(const AstRawString* function_name,
+ FunctionSyntaxKind function_syntax_kind,
+ DeclarationScope* function_scope) {
+ if (function_syntax_kind == FunctionSyntaxKind::kNamedExpression &&
function_scope->LookupLocal(function_name) == nullptr) {
DCHECK_EQ(function_scope, scope());
function_scope->DeclareFunctionVar(function_name);
@@ -1169,9 +1176,9 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE void DeclareFunctionNameVar(
const PreParserIdentifier& function_name,
- FunctionLiteral::FunctionType function_type,
+ FunctionSyntaxKind function_syntax_kind,
DeclarationScope* function_scope) {
- DeclareFunctionNameVar(function_name.string_, function_type,
+ DeclareFunctionNameVar(function_name.string_, function_syntax_kind,
function_scope);
}
@@ -1249,16 +1256,10 @@ class PreParser : public ParserBase<PreParser> {
ClassScope* scope, const PreParserIdentifier& property_name,
const PreParserExpression& property, ClassLiteralProperty::Kind kind,
bool is_static, ClassInfo* class_info) {
- // TODO(joyee): We do not support private accessors yet (which allow
- // declaring the same private name twice). Make them noops.
- if (kind != ClassLiteralProperty::Kind::FIELD &&
- kind != ClassLiteralProperty::Kind::METHOD) {
- return;
- }
bool was_added;
DeclarePrivateVariableName(property_name.string_, scope,
- RequiresBrandCheck(kind), &was_added);
+ GetVariableMode(kind), &was_added);
if (!was_added) {
Scanner::Location loc(property.position(), property.position() + 1);
ReportMessageAt(loc, MessageTemplate::kVarRedeclaration,
@@ -1697,8 +1698,9 @@ class PreParser : public ParserBase<PreParser> {
PreParserExpression PreParser::SpreadCall(const PreParserExpression& function,
const PreParserExpressionList& args,
int pos,
- Call::PossiblyEval possibly_eval) {
- return factory()->NewCall(function, args, pos, possibly_eval);
+ Call::PossiblyEval possibly_eval,
+ bool optional_chain) {
+ return factory()->NewCall(function, args, pos, possibly_eval, optional_chain);
}
PreParserExpression PreParser::SpreadCallNew(
diff --git a/deps/v8/src/parsing/scanner-character-streams.cc b/deps/v8/src/parsing/scanner-character-streams.cc
index 01ea0a0d02..0cd295fd29 100644
--- a/deps/v8/src/parsing/scanner-character-streams.cc
+++ b/deps/v8/src/parsing/scanner-character-streams.cc
@@ -359,7 +359,7 @@ class RelocatingCharacterStream
void UpdateBufferPointers() {
DisallowHeapAllocation no_gc;
Range<uint16_t> range =
- byte_stream_.GetDataAt(0, runtime_call_stats(), &no_gc);
+ byte_stream_.GetDataAt(buffer_pos_, runtime_call_stats(), &no_gc);
if (range.start != buffer_start_) {
buffer_cursor_ = (buffer_cursor_ - buffer_start_) + range.start;
buffer_start_ = range.start;
diff --git a/deps/v8/src/parsing/scanner-inl.h b/deps/v8/src/parsing/scanner-inl.h
index ef5a8faf85..b76076d92f 100644
--- a/deps/v8/src/parsing/scanner-inl.h
+++ b/deps/v8/src/parsing/scanner-inl.h
@@ -354,7 +354,6 @@ V8_INLINE Token::Value Scanner::ScanSingleToken() {
case Token::RBRACE:
case Token::LBRACK:
case Token::RBRACK:
- case Token::CONDITIONAL:
case Token::COLON:
case Token::SEMICOLON:
case Token::COMMA:
@@ -363,6 +362,18 @@ V8_INLINE Token::Value Scanner::ScanSingleToken() {
// One character tokens.
return Select(token);
+ case Token::CONDITIONAL:
+ // ? ?. ??
+ Advance();
+ if (V8_UNLIKELY(allow_harmony_optional_chaining() && c0_ == '.')) {
+ Advance();
+ if (!IsDecimalDigit(c0_)) return Token::QUESTION_PERIOD;
+ PushBack('.');
+ } else if (V8_UNLIKELY(allow_harmony_nullish() && c0_ == '?')) {
+ return Select(Token::NULLISH);
+ }
+ return Token::CONDITIONAL;
+
case Token::STRING:
return ScanString();
diff --git a/deps/v8/src/parsing/scanner.cc b/deps/v8/src/parsing/scanner.cc
index 2f74548020..28e4374787 100644
--- a/deps/v8/src/parsing/scanner.cc
+++ b/deps/v8/src/parsing/scanner.cc
@@ -92,7 +92,8 @@ bool Scanner::BookmarkScope::HasBeenApplied() const {
Scanner::Scanner(Utf16CharacterStream* source, bool is_module)
: source_(source),
found_html_comment_(false),
- allow_harmony_numeric_separator_(false),
+ allow_harmony_optional_chaining_(false),
+ allow_harmony_nullish_(false),
is_module_(is_module),
octal_pos_(Location::invalid()),
octal_message_(MessageTemplate::kNone) {
@@ -628,13 +629,18 @@ bool Scanner::ScanDigitsWithNumericSeparators(bool (*predicate)(uc32 ch),
return true;
}
-bool Scanner::ScanDecimalDigits() {
- if (allow_harmony_numeric_separator()) {
+bool Scanner::ScanDecimalDigits(bool allow_numeric_separator) {
+ if (allow_numeric_separator) {
return ScanDigitsWithNumericSeparators(&IsDecimalDigit, false);
}
while (IsDecimalDigit(c0_)) {
AddLiteralCharAdvance();
}
+ if (c0_ == '_') {
+ ReportScannerError(Location(source_pos(), source_pos() + 1),
+ MessageTemplate::kInvalidOrUnexpectedToken);
+ return false;
+ }
return true;
}
@@ -667,8 +673,8 @@ bool Scanner::ScanDecimalAsSmiWithNumericSeparators(uint64_t* value) {
return true;
}
-bool Scanner::ScanDecimalAsSmi(uint64_t* value) {
- if (allow_harmony_numeric_separator()) {
+bool Scanner::ScanDecimalAsSmi(uint64_t* value, bool allow_numeric_separator) {
+ if (allow_numeric_separator) {
return ScanDecimalAsSmiWithNumericSeparators(value);
}
@@ -682,35 +688,11 @@ bool Scanner::ScanDecimalAsSmi(uint64_t* value) {
}
bool Scanner::ScanBinaryDigits() {
- if (allow_harmony_numeric_separator()) {
- return ScanDigitsWithNumericSeparators(&IsBinaryDigit, true);
- }
-
- // we must have at least one binary digit after 'b'/'B'
- if (!IsBinaryDigit(c0_)) {
- return false;
- }
-
- while (IsBinaryDigit(c0_)) {
- AddLiteralCharAdvance();
- }
- return true;
+ return ScanDigitsWithNumericSeparators(&IsBinaryDigit, true);
}
bool Scanner::ScanOctalDigits() {
- if (allow_harmony_numeric_separator()) {
- return ScanDigitsWithNumericSeparators(&IsOctalDigit, true);
- }
-
- // we must have at least one octal digit after 'o'/'O'
- if (!IsOctalDigit(c0_)) {
- return false;
- }
-
- while (IsOctalDigit(c0_)) {
- AddLiteralCharAdvance();
- }
- return true;
+ return ScanDigitsWithNumericSeparators(&IsOctalDigit, true);
}
bool Scanner::ScanImplicitOctalDigits(int start_pos,
@@ -734,26 +716,14 @@ bool Scanner::ScanImplicitOctalDigits(int start_pos,
}
bool Scanner::ScanHexDigits() {
- if (allow_harmony_numeric_separator()) {
- return ScanDigitsWithNumericSeparators(&IsHexDigit, true);
- }
-
- // we must have at least one hex digit after 'x'/'X'
- if (!IsHexDigit(c0_)) {
- return false;
- }
-
- while (IsHexDigit(c0_)) {
- AddLiteralCharAdvance();
- }
- return true;
+ return ScanDigitsWithNumericSeparators(&IsHexDigit, true);
}
bool Scanner::ScanSignedInteger() {
if (c0_ == '+' || c0_ == '-') AddLiteralCharAdvance();
// we must have at least one decimal digit after 'e'/'E'
if (!IsDecimalDigit(c0_)) return false;
- return ScanDecimalDigits();
+ return ScanDecimalDigits(true);
}
Token::Value Scanner::ScanNumber(bool seen_period) {
@@ -767,11 +737,11 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
if (seen_period) {
// we have already seen a decimal point of the float
AddLiteralChar('.');
- if (allow_harmony_numeric_separator() && c0_ == '_') {
+ if (c0_ == '_') {
return Token::ILLEGAL;
}
// we know we have at least one digit
- if (!ScanDecimalDigits()) return Token::ILLEGAL;
+ if (!ScanDecimalDigits(true)) return Token::ILLEGAL;
} else {
// if the first character is '0' we must check for octals and hex
if (c0_ == '0') {
@@ -801,7 +771,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
}
} else if (IsNonOctalDecimalDigit(c0_)) {
kind = DECIMAL_WITH_LEADING_ZERO;
- } else if (allow_harmony_numeric_separator() && c0_ == '_') {
+ } else if (c0_ == '_') {
ReportScannerError(Location(source_pos(), source_pos() + 1),
MessageTemplate::kZeroDigitNumericSeparator);
return Token::ILLEGAL;
@@ -810,11 +780,14 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
// Parse decimal digits and allow trailing fractional part.
if (IsDecimalNumberKind(kind)) {
+ bool allow_numeric_separator = kind != DECIMAL_WITH_LEADING_ZERO;
// This is an optimization for parsing Decimal numbers as Smi's.
if (at_start) {
uint64_t value = 0;
// scan subsequent decimal digits
- if (!ScanDecimalAsSmi(&value)) return Token::ILLEGAL;
+ if (!ScanDecimalAsSmi(&value, allow_numeric_separator)) {
+ return Token::ILLEGAL;
+ }
if (next().literal_chars.one_byte_literal().length() <= 10 &&
value <= Smi::kMaxValue && c0_ != '.' && !IsIdentifierStart(c0_)) {
@@ -828,14 +801,16 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
}
}
- if (!ScanDecimalDigits()) return Token::ILLEGAL;
+ if (!ScanDecimalDigits(allow_numeric_separator)) {
+ return Token::ILLEGAL;
+ }
if (c0_ == '.') {
seen_period = true;
AddLiteralCharAdvance();
- if (allow_harmony_numeric_separator() && c0_ == '_') {
+ if (c0_ == '_') {
return Token::ILLEGAL;
}
- if (!ScanDecimalDigits()) return Token::ILLEGAL;
+ if (!ScanDecimalDigits(true)) return Token::ILLEGAL;
}
}
}
diff --git a/deps/v8/src/parsing/scanner.h b/deps/v8/src/parsing/scanner.h
index e2865bca1c..c40d8f4ba3 100644
--- a/deps/v8/src/parsing/scanner.h
+++ b/deps/v8/src/parsing/scanner.h
@@ -406,13 +406,18 @@ class V8_EXPORT_PRIVATE Scanner {
bool FoundHtmlComment() const { return found_html_comment_; }
- bool allow_harmony_numeric_separator() const {
- return allow_harmony_numeric_separator_;
+ bool allow_harmony_optional_chaining() const {
+ return allow_harmony_optional_chaining_;
}
- void set_allow_harmony_numeric_separator(bool allow) {
- allow_harmony_numeric_separator_ = allow;
+
+ void set_allow_harmony_optional_chaining(bool allow) {
+ allow_harmony_optional_chaining_ = allow;
}
+ bool allow_harmony_nullish() const { return allow_harmony_nullish_; }
+
+ void set_allow_harmony_nullish(bool allow) { allow_harmony_nullish_ = allow; }
+
const Utf16CharacterStream* stream() const { return source_; }
// If the next characters in the stream are "#!", the line is skipped.
@@ -646,9 +651,9 @@ class V8_EXPORT_PRIVATE Scanner {
bool ScanDigitsWithNumericSeparators(bool (*predicate)(uc32 ch),
bool is_check_first_digit);
- bool ScanDecimalDigits();
+ bool ScanDecimalDigits(bool allow_numeric_separator);
// Optimized function to scan decimal number as Smi.
- bool ScanDecimalAsSmi(uint64_t* value);
+ bool ScanDecimalAsSmi(uint64_t* value, bool allow_numeric_separator);
bool ScanDecimalAsSmiWithNumericSeparators(uint64_t* value);
bool ScanHexDigits();
bool ScanBinaryDigits();
@@ -721,7 +726,8 @@ class V8_EXPORT_PRIVATE Scanner {
bool found_html_comment_;
// Harmony flags to allow ESNext features.
- bool allow_harmony_numeric_separator_;
+ bool allow_harmony_optional_chaining_;
+ bool allow_harmony_nullish_;
const bool is_module_;
diff --git a/deps/v8/src/parsing/token.h b/deps/v8/src/parsing/token.h
index 197a26f325..3f2e0ec870 100644
--- a/deps/v8/src/parsing/token.h
+++ b/deps/v8/src/parsing/token.h
@@ -65,6 +65,7 @@ namespace internal {
T(LBRACK, "[", 0) \
/* END Property */ \
/* END Member */ \
+ T(QUESTION_PERIOD, "?.", 0) \
T(LPAREN, "(", 0) \
/* END PropertyOrCall */ \
T(RPAREN, ")", 0) \
@@ -95,6 +96,7 @@ namespace internal {
/* IsBinaryOp() relies on this block of enum values */ \
/* being contiguous and sorted in the same order! */ \
T(COMMA, ",", 1) \
+ T(NULLISH, "??", 3) \
T(OR, "||", 4) \
T(AND, "&&", 5) \
\
@@ -215,8 +217,8 @@ class V8_EXPORT_PRIVATE Token {
return name_[token];
}
- class IsKeywordBits : public BitField8<bool, 0, 1> {};
- class IsPropertyNameBits : public BitField8<bool, IsKeywordBits::kNext, 1> {};
+ using IsKeywordBits = BitField8<bool, 0, 1>;
+ using IsPropertyNameBits = IsKeywordBits::Next<bool, 1>;
// Predicates
static bool IsKeyword(Value token) {
diff --git a/deps/v8/src/profiler/cpu-profiler.cc b/deps/v8/src/profiler/cpu-profiler.cc
index 495840fabf..4c35159b2e 100644
--- a/deps/v8/src/profiler/cpu-profiler.cc
+++ b/deps/v8/src/profiler/cpu-profiler.cc
@@ -47,21 +47,56 @@ class CpuSampler : public sampler::Sampler {
SamplingEventsProcessor* processor_;
};
-ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate,
- ProfileGenerator* generator)
+ProfilingScope::ProfilingScope(Isolate* isolate, ProfilerListener* listener)
+ : isolate_(isolate), listener_(listener) {
+ size_t profiler_count = isolate_->num_cpu_profilers();
+ profiler_count++;
+ isolate_->set_num_cpu_profilers(profiler_count);
+ isolate_->set_is_profiling(true);
+ isolate_->wasm_engine()->EnableCodeLogging(isolate_);
+
+ Logger* logger = isolate_->logger();
+ logger->AddCodeEventListener(listener_);
+ // Populate the ProfilerCodeObserver with the initial functions and
+ // callbacks on the heap.
+ DCHECK(isolate_->heap()->HasBeenSetUp());
+
+ if (!FLAG_prof_browser_mode) {
+ logger->LogCodeObjects();
+ }
+ logger->LogCompiledFunctions();
+ logger->LogAccessorCallbacks();
+}
+
+ProfilingScope::~ProfilingScope() {
+ isolate_->logger()->RemoveCodeEventListener(listener_);
+
+ size_t profiler_count = isolate_->num_cpu_profilers();
+ DCHECK_GT(profiler_count, 0);
+ profiler_count--;
+ isolate_->set_num_cpu_profilers(profiler_count);
+ if (profiler_count == 0) isolate_->set_is_profiling(false);
+}
+
+ProfilerEventsProcessor::ProfilerEventsProcessor(
+ Isolate* isolate, ProfileGenerator* generator,
+ ProfilerCodeObserver* code_observer)
: Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)),
generator_(generator),
+ code_observer_(code_observer),
running_(1),
last_code_event_id_(0),
last_processed_code_event_id_(0),
- isolate_(isolate),
- profiling_scope_(isolate) {}
-
-SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate,
- ProfileGenerator* generator,
- base::TimeDelta period,
- bool use_precise_sampling)
- : ProfilerEventsProcessor(isolate, generator),
+ isolate_(isolate) {
+ DCHECK(!code_observer_->processor());
+ code_observer_->set_processor(this);
+}
+
+SamplingEventsProcessor::SamplingEventsProcessor(
+ Isolate* isolate, ProfileGenerator* generator,
+ ProfilerCodeObserver* code_observer, base::TimeDelta period,
+ bool use_precise_sampling)
+ : ProfilerEventsProcessor(isolate, generator, code_observer),
sampler_(new CpuSampler(isolate, this)),
period_(period),
use_precise_sampling_(use_precise_sampling) {
@@ -70,7 +105,10 @@ SamplingEventsProcessor::SamplingEventsProcessor(Isolate* isolate,
SamplingEventsProcessor::~SamplingEventsProcessor() { sampler_->Stop(); }
-ProfilerEventsProcessor::~ProfilerEventsProcessor() = default;
+ProfilerEventsProcessor::~ProfilerEventsProcessor() {
+ DCHECK_EQ(code_observer_->processor(), this);
+ code_observer_->clear_processor();
+}
void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
event.generic.order = ++last_code_event_id_;
@@ -123,16 +161,13 @@ void ProfilerEventsProcessor::StopSynchronously() {
bool ProfilerEventsProcessor::ProcessCodeEvent() {
CodeEventsContainer record;
if (events_buffer_.Dequeue(&record)) {
- switch (record.generic.type) {
-#define PROFILER_TYPE_CASE(type, clss) \
- case CodeEventRecord::type: \
- record.clss##_.UpdateCodeMap(generator_->code_map()); \
- break;
-
- CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
-
-#undef PROFILER_TYPE_CASE
- default: return true; // Skip record.
+ if (record.generic.type == CodeEventRecord::NATIVE_CONTEXT_MOVE) {
+ NativeContextMoveEventRecord& nc_record =
+ record.NativeContextMoveEventRecord_;
+ generator_->UpdateNativeContextAddress(nc_record.from_address,
+ nc_record.to_address);
+ } else {
+ code_observer_->CodeEventHandlerInternal(record);
}
last_processed_code_event_id_ = record.generic.order;
return true;
@@ -146,6 +181,7 @@ void ProfilerEventsProcessor::CodeEventHandler(
case CodeEventRecord::CODE_CREATION:
case CodeEventRecord::CODE_MOVE:
case CodeEventRecord::CODE_DISABLE_OPT:
+ case CodeEventRecord::NATIVE_CONTEXT_MOVE:
Enqueue(evt_rec);
break;
case CodeEventRecord::CODE_DEOPT: {
@@ -262,6 +298,62 @@ void* SamplingEventsProcessor::operator new(size_t size) {
void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); }
+ProfilerCodeObserver::ProfilerCodeObserver(Isolate* isolate)
+ : isolate_(isolate), processor_(nullptr) {
+ CreateEntriesForRuntimeCallStats();
+ LogBuiltins();
+}
+
+void ProfilerCodeObserver::CodeEventHandler(
+ const CodeEventsContainer& evt_rec) {
+ if (processor_) {
+ processor_->CodeEventHandler(evt_rec);
+ return;
+ }
+ CodeEventHandlerInternal(evt_rec);
+}
+
+void ProfilerCodeObserver::CodeEventHandlerInternal(
+ const CodeEventsContainer& evt_rec) {
+ CodeEventsContainer record = evt_rec;
+ switch (evt_rec.generic.type) {
+#define PROFILER_TYPE_CASE(type, clss) \
+ case CodeEventRecord::type: \
+ record.clss##_.UpdateCodeMap(&code_map_); \
+ break;
+
+ CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
+
+#undef PROFILER_TYPE_CASE
+ default:
+ break;
+ }
+}
+
+void ProfilerCodeObserver::CreateEntriesForRuntimeCallStats() {
+ RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats();
+ for (int i = 0; i < RuntimeCallStats::kNumberOfCounters; ++i) {
+ RuntimeCallCounter* counter = rcs->GetCounter(i);
+ DCHECK(counter->name());
+ auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
+ "native V8Runtime");
+ code_map_.AddCode(reinterpret_cast<Address>(counter), entry, 1);
+ }
+}
+
+void ProfilerCodeObserver::LogBuiltins() {
+ Builtins* builtins = isolate_->builtins();
+ DCHECK(builtins->is_initialized());
+ for (int i = 0; i < Builtins::builtin_count; i++) {
+ CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
+ ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
+ Builtins::Name id = static_cast<Builtins::Name>(i);
+ rec->instruction_start = builtins->builtin(id).InstructionStart();
+ rec->builtin_id = id;
+ CodeEventHandlerInternal(evt_rec);
+ }
+}
+
int CpuProfiler::GetProfilesCount() {
// The count of profiles doesn't depend on a security token.
return static_cast<int>(profiles_->profiles()->size());
@@ -324,29 +416,37 @@ DEFINE_LAZY_LEAKY_OBJECT_GETTER(CpuProfilersManager, GetProfilersManager)
} // namespace
-CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode)
- : CpuProfiler(isolate, naming_mode, new CpuProfilesCollection(isolate),
- nullptr, nullptr) {}
+CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
+ CpuProfilingLoggingMode logging_mode)
+ : CpuProfiler(isolate, naming_mode, logging_mode,
+ new CpuProfilesCollection(isolate), nullptr, nullptr) {}
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
+ CpuProfilingLoggingMode logging_mode,
CpuProfilesCollection* test_profiles,
ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor)
: isolate_(isolate),
naming_mode_(naming_mode),
+ logging_mode_(logging_mode),
base_sampling_interval_(base::TimeDelta::FromMicroseconds(
FLAG_cpu_profiler_sampling_interval)),
profiles_(test_profiles),
generator_(test_generator),
processor_(test_processor),
+ code_observer_(isolate),
is_profiling_(false) {
profiles_->set_cpu_profiler(this);
GetProfilersManager()->AddProfiler(isolate, this);
+
+ if (logging_mode == kEagerLogging) EnableLogging();
}
CpuProfiler::~CpuProfiler() {
DCHECK(!is_profiling_);
GetProfilersManager()->RemoveProfiler(isolate_, this);
+
+ DisableLogging();
}
void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
@@ -362,20 +462,26 @@ void CpuProfiler::set_use_precise_sampling(bool value) {
void CpuProfiler::ResetProfiles() {
profiles_.reset(new CpuProfilesCollection(isolate_));
profiles_->set_cpu_profiler(this);
- profiler_listener_.reset();
generator_.reset();
+ if (!profiling_scope_) profiler_listener_.reset();
}
-void CpuProfiler::CreateEntriesForRuntimeCallStats() {
- RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats();
- CodeMap* code_map = generator_->code_map();
- for (int i = 0; i < RuntimeCallStats::kNumberOfCounters; ++i) {
- RuntimeCallCounter* counter = rcs->GetCounter(i);
- DCHECK(counter->name());
- auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
- "native V8Runtime");
- code_map->AddCode(reinterpret_cast<Address>(counter), entry, 1);
+void CpuProfiler::EnableLogging() {
+ if (profiling_scope_) return;
+
+ if (!profiler_listener_) {
+ profiler_listener_.reset(
+ new ProfilerListener(isolate_, &code_observer_, naming_mode_));
}
+ profiling_scope_.reset(
+ new ProfilingScope(isolate_, profiler_listener_.get()));
+}
+
+void CpuProfiler::DisableLogging() {
+ if (!profiling_scope_) return;
+
+ DCHECK(profiler_listener_);
+ profiling_scope_.reset();
}
base::TimeDelta CpuProfiler::ComputeSamplingInterval() const {
@@ -418,36 +524,23 @@ void CpuProfiler::StartProcessorIfNotStarted() {
processor_->AddCurrentStack();
return;
}
- isolate_->wasm_engine()->EnableCodeLogging(isolate_);
- Logger* logger = isolate_->logger();
- bool codemap_needs_initialization = false;
+ if (!profiling_scope_) {
+ DCHECK_EQ(logging_mode_, kLazyLogging);
+ EnableLogging();
+ }
+
if (!generator_) {
- generator_.reset(new ProfileGenerator(profiles_.get()));
- codemap_needs_initialization = true;
- CreateEntriesForRuntimeCallStats();
+ generator_.reset(
+ new ProfileGenerator(profiles_.get(), code_observer_.code_map()));
}
+
base::TimeDelta sampling_interval = ComputeSamplingInterval();
- processor_.reset(new SamplingEventsProcessor(
- isolate_, generator_.get(), sampling_interval, use_precise_sampling_));
- if (profiler_listener_) {
- profiler_listener_->set_observer(processor_.get());
- } else {
- profiler_listener_.reset(
- new ProfilerListener(isolate_, processor_.get(), naming_mode_));
- }
- logger->AddCodeEventListener(profiler_listener_.get());
+ processor_.reset(
+ new SamplingEventsProcessor(isolate_, generator_.get(), &code_observer_,
+ sampling_interval, use_precise_sampling_));
is_profiling_ = true;
- // Enumerate stuff we already have in the heap.
- DCHECK(isolate_->heap()->HasBeenSetUp());
- if (codemap_needs_initialization) {
- if (!FLAG_prof_browser_mode) {
- logger->LogCodeObjects();
- }
- logger->LogCompiledFunctions();
- logger->LogAccessorCallbacks();
- LogBuiltins();
- }
+
// Enable stack sampling.
processor_->AddCurrentStack();
processor_->StartSynchronously();
@@ -471,26 +564,14 @@ void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
}
void CpuProfiler::StopProcessor() {
- Logger* logger = isolate_->logger();
is_profiling_ = false;
- logger->RemoveCodeEventListener(profiler_listener_.get());
processor_->StopSynchronously();
processor_.reset();
-}
-
-void CpuProfiler::LogBuiltins() {
- Builtins* builtins = isolate_->builtins();
- DCHECK(builtins->is_initialized());
- for (int i = 0; i < Builtins::builtin_count; i++) {
- CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
- ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
- Builtins::Name id = static_cast<Builtins::Name>(i);
- rec->instruction_start = builtins->builtin(id).InstructionStart();
- rec->builtin_id = id;
- processor_->Enqueue(evt_rec);
+ DCHECK(profiling_scope_);
+ if (logging_mode_ == kLazyLogging) {
+ DisableLogging();
}
}
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/profiler/cpu-profiler.h b/deps/v8/src/profiler/cpu-profiler.h
index 96d53356e6..093f28aba3 100644
--- a/deps/v8/src/profiler/cpu-profiler.h
+++ b/deps/v8/src/profiler/cpu-profiler.h
@@ -13,6 +13,7 @@
#include "src/base/platform/mutex.h"
#include "src/base/platform/time.h"
#include "src/execution/isolate.h"
+#include "src/handles/maybe-handles.h"
#include "src/libsampler/sampler.h"
#include "src/profiler/circular-queue.h"
#include "src/profiler/profiler-listener.h"
@@ -30,21 +31,21 @@ class CpuProfile;
class CpuProfilesCollection;
class ProfileGenerator;
-#define CODE_EVENTS_TYPE_LIST(V) \
- V(CODE_CREATION, CodeCreateEventRecord) \
- V(CODE_MOVE, CodeMoveEventRecord) \
- V(CODE_DISABLE_OPT, CodeDisableOptEventRecord) \
- V(CODE_DEOPT, CodeDeoptEventRecord) \
+#define CODE_EVENTS_TYPE_LIST(V) \
+ V(CODE_CREATION, CodeCreateEventRecord) \
+ V(CODE_MOVE, CodeMoveEventRecord) \
+ V(CODE_DISABLE_OPT, CodeDisableOptEventRecord) \
+ V(CODE_DEOPT, CodeDeoptEventRecord) \
V(REPORT_BUILTIN, ReportBuiltinEventRecord)
+#define VM_EVENTS_TYPE_LIST(V) \
+ CODE_EVENTS_TYPE_LIST(V) \
+ V(NATIVE_CONTEXT_MOVE, NativeContextMoveEventRecord)
class CodeEventRecord {
public:
#define DECLARE_TYPE(type, ignore) type,
- enum Type {
- NONE = 0,
- CODE_EVENTS_TYPE_LIST(DECLARE_TYPE)
- };
+ enum Type { NONE = 0, VM_EVENTS_TYPE_LIST(DECLARE_TYPE) };
#undef DECLARE_TYPE
Type type;
@@ -102,6 +103,12 @@ class ReportBuiltinEventRecord : public CodeEventRecord {
V8_INLINE void UpdateCodeMap(CodeMap* code_map);
};
+// Signals that a native context's address has changed.
+class NativeContextMoveEventRecord : public CodeEventRecord {
+ public:
+ Address from_address;
+ Address to_address;
+};
class TickSampleEventRecord {
public:
@@ -124,33 +131,25 @@ class CodeEventsContainer {
union {
CodeEventRecord generic;
#define DECLARE_CLASS(ignore, type) type type##_;
- CODE_EVENTS_TYPE_LIST(DECLARE_CLASS)
+ VM_EVENTS_TYPE_LIST(DECLARE_CLASS)
#undef DECLARE_CLASS
};
};
-// Maintains the number of active CPU profilers in an isolate.
+// Maintains the number of active CPU profilers in an isolate, and routes
+// logging to a given ProfilerListener.
class ProfilingScope {
public:
- explicit ProfilingScope(Isolate* isolate) : isolate_(isolate) {
- size_t profiler_count = isolate_->num_cpu_profilers();
- profiler_count++;
- isolate_->set_num_cpu_profilers(profiler_count);
- isolate_->set_is_profiling(true);
- }
-
- ~ProfilingScope() {
- size_t profiler_count = isolate_->num_cpu_profilers();
- DCHECK_GT(profiler_count, 0);
- profiler_count--;
- isolate_->set_num_cpu_profilers(profiler_count);
- if (profiler_count == 0) isolate_->set_is_profiling(false);
- }
+ ProfilingScope(Isolate* isolate, ProfilerListener* listener);
+ ~ProfilingScope();
private:
Isolate* const isolate_;
+ ProfilerListener* const listener_;
};
+class ProfilerCodeObserver;
+
// This class implements both the profile events processor thread and
// methods called by event producers: VM and stack sampler threads.
class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread,
@@ -175,7 +174,8 @@ class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread,
virtual void SetSamplingInterval(base::TimeDelta) {}
protected:
- ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator);
+ ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
+ ProfilerCodeObserver* code_observer);
// Called from events processing thread (Run() method.)
bool ProcessCodeEvent();
@@ -188,6 +188,7 @@ class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread,
virtual SampleProcessingResult ProcessOneSample() = 0;
ProfileGenerator* generator_;
+ ProfilerCodeObserver* code_observer_;
base::Atomic32 running_;
base::ConditionVariable running_cond_;
base::Mutex running_mutex_;
@@ -196,13 +197,13 @@ class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread,
std::atomic<unsigned> last_code_event_id_;
unsigned last_processed_code_event_id_;
Isolate* isolate_;
- ProfilingScope profiling_scope_;
};
class V8_EXPORT_PRIVATE SamplingEventsProcessor
: public ProfilerEventsProcessor {
public:
SamplingEventsProcessor(Isolate* isolate, ProfileGenerator* generator,
+ ProfilerCodeObserver* code_observer,
base::TimeDelta period, bool use_precise_sampling);
~SamplingEventsProcessor() override;
@@ -241,11 +242,47 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
// low sampling intervals on Windows.
};
+// Builds and maintains a CodeMap tracking code objects on the VM heap. While
+// alive, logs generated code, callbacks, and builtins from the isolate.
+// Redirects events to the profiler events processor when present.
+class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver {
+ public:
+ explicit ProfilerCodeObserver(Isolate*);
+
+ void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
+
+ CodeMap* code_map() { return &code_map_; }
+
+ private:
+ friend class ProfilerEventsProcessor;
+
+ void CodeEventHandlerInternal(const CodeEventsContainer& evt_rec);
+
+ void CreateEntriesForRuntimeCallStats();
+ void LogBuiltins();
+
+ ProfilerEventsProcessor* processor() { return processor_; }
+
+ // Redirects code events to be enqueued on the given events processor.
+ void set_processor(ProfilerEventsProcessor* processor) {
+ processor_ = processor;
+ }
+
+ // Stops redirection of code events onto an events processor.
+ void clear_processor() { processor_ = nullptr; }
+
+ Isolate* const isolate_;
+ CodeMap code_map_;
+ ProfilerEventsProcessor* processor_;
+};
+
class V8_EXPORT_PRIVATE CpuProfiler {
public:
- explicit CpuProfiler(Isolate* isolate, CpuProfilingNamingMode = kDebugNaming);
+ explicit CpuProfiler(Isolate* isolate, CpuProfilingNamingMode = kDebugNaming,
+ CpuProfilingLoggingMode = kLazyLogging);
CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
+ CpuProfilingLoggingMode logging_mode,
CpuProfilesCollection* profiles, ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor);
@@ -255,6 +292,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
using ProfilingMode = v8::CpuProfilingMode;
using NamingMode = v8::CpuProfilingNamingMode;
+ using LoggingMode = v8::CpuProfilingLoggingMode;
base::TimeDelta sampling_interval() const { return base_sampling_interval_; }
void set_sampling_interval(base::TimeDelta value);
@@ -262,6 +300,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
void CollectSample();
void StartProfiling(const char* title, CpuProfilingOptions options = {});
void StartProfiling(String title, CpuProfilingOptions options = {});
+
CpuProfile* StopProfiling(const char* title);
CpuProfile* StopProfiling(String title);
int GetProfilesCount();
@@ -284,8 +323,9 @@ class V8_EXPORT_PRIVATE CpuProfiler {
void StopProcessorIfLastProfile(const char* title);
void StopProcessor();
void ResetProfiles();
- void LogBuiltins();
- void CreateEntriesForRuntimeCallStats();
+
+ void EnableLogging();
+ void DisableLogging();
// Computes a sampling interval sufficient to accomodate attached profiles.
base::TimeDelta ComputeSamplingInterval() const;
@@ -295,6 +335,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
Isolate* const isolate_;
const NamingMode naming_mode_;
+ const LoggingMode logging_mode_;
bool use_precise_sampling_ = true;
// Sampling interval to which per-profile sampling intervals will be clamped
// to a multiple of, or used as the default if unspecified.
@@ -303,6 +344,8 @@ class V8_EXPORT_PRIVATE CpuProfiler {
std::unique_ptr<ProfileGenerator> generator_;
std::unique_ptr<ProfilerEventsProcessor> processor_;
std::unique_ptr<ProfilerListener> profiler_listener_;
+ std::unique_ptr<ProfilingScope> profiling_scope_;
+ ProfilerCodeObserver code_observer_;
bool is_profiling_;
DISALLOW_COPY_AND_ASSIGN(CpuProfiler);
diff --git a/deps/v8/src/profiler/heap-profiler.cc b/deps/v8/src/profiler/heap-profiler.cc
index 472dbdbb10..a498e8e214 100644
--- a/deps/v8/src/profiler/heap-profiler.cc
+++ b/deps/v8/src/profiler/heap-profiler.cc
@@ -151,6 +151,17 @@ SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
return ids_->FindEntry(HeapObject::cast(*obj).address());
}
+SnapshotObjectId HeapProfiler::GetSnapshotObjectId(NativeObject obj) {
+ // Try to find id of regular native node first.
+ SnapshotObjectId id = ids_->FindEntry(reinterpret_cast<Address>(obj));
+ // In case no id has been found, check whether there exists an entry where the
+ // native objects has been merged into a V8 entry.
+ if (id == v8::HeapProfiler::kUnknownObjectId) {
+ id = ids_->FindMergedNativeEntry(obj);
+ }
+ return id;
+}
+
void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
base::MutexGuard guard(&profiler_mutex_);
bool known_object = ids_->MoveObject(from, to, size);
diff --git a/deps/v8/src/profiler/heap-profiler.h b/deps/v8/src/profiler/heap-profiler.h
index 940574282e..f7336eb6be 100644
--- a/deps/v8/src/profiler/heap-profiler.h
+++ b/deps/v8/src/profiler/heap-profiler.h
@@ -52,6 +52,7 @@ class HeapProfiler : public HeapObjectAllocationTracker {
int GetSnapshotsCount();
HeapSnapshot* GetSnapshot(int index);
SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj);
+ SnapshotObjectId GetSnapshotObjectId(NativeObject obj);
void DeleteAllSnapshots();
void RemoveSnapshot(HeapSnapshot* snapshot);
diff --git a/deps/v8/src/profiler/heap-snapshot-generator.cc b/deps/v8/src/profiler/heap-snapshot-generator.cc
index df941eda96..75b6aa7b77 100644
--- a/deps/v8/src/profiler/heap-snapshot-generator.cc
+++ b/deps/v8/src/profiler/heap-snapshot-generator.cc
@@ -352,7 +352,7 @@ void HeapObjectsMap::UpdateObjectSize(Address addr, int size) {
SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) {
base::HashMap::Entry* entry = entries_map_.Lookup(
reinterpret_cast<void*>(addr), ComputeAddressHash(addr));
- if (entry == nullptr) return 0;
+ if (entry == nullptr) return v8::HeapProfiler::kUnknownObjectId;
int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
EntryInfo& entry_info = entries_.at(entry_index);
DCHECK(static_cast<uint32_t>(entries_.size()) > entries_map_.occupancy());
@@ -386,6 +386,25 @@ SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr,
return id;
}
+SnapshotObjectId HeapObjectsMap::FindMergedNativeEntry(NativeObject addr) {
+ auto it = merged_native_entries_map_.find(addr);
+ if (it == merged_native_entries_map_.end())
+ return v8::HeapProfiler::kUnknownObjectId;
+ return entries_[it->second].id;
+}
+
+void HeapObjectsMap::AddMergedNativeEntry(NativeObject addr,
+ Address canonical_addr) {
+ base::HashMap::Entry* entry =
+ entries_map_.Lookup(reinterpret_cast<void*>(canonical_addr),
+ ComputeAddressHash(canonical_addr));
+ auto result = merged_native_entries_map_.insert(
+ {addr, reinterpret_cast<size_t>(entry->value)});
+ if (!result.second) {
+ result.first->second = reinterpret_cast<size_t>(entry->value);
+ }
+}
+
void HeapObjectsMap::StopHeapObjectsTracking() { time_intervals_.clear(); }
void HeapObjectsMap::UpdateHeapObjectsMap() {
@@ -465,9 +484,20 @@ SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream,
void HeapObjectsMap::RemoveDeadEntries() {
DCHECK(entries_.size() > 0 && entries_.at(0).id == 0 &&
entries_.at(0).addr == kNullAddress);
+
+ // Build up temporary reverse map.
+ std::unordered_map<size_t, NativeObject> reverse_merged_native_entries_map;
+ for (const auto& it : merged_native_entries_map_) {
+ auto result =
+ reverse_merged_native_entries_map.emplace(it.second, it.first);
+ DCHECK(result.second);
+ USE(result);
+ }
+
size_t first_free_entry = 1;
for (size_t i = 1; i < entries_.size(); ++i) {
EntryInfo& entry_info = entries_.at(i);
+ auto merged_reverse_it = reverse_merged_native_entries_map.find(i);
if (entry_info.accessed) {
if (first_free_entry != i) {
entries_.at(first_free_entry) = entry_info;
@@ -478,11 +508,19 @@ void HeapObjectsMap::RemoveDeadEntries() {
ComputeAddressHash(entry_info.addr));
DCHECK(entry);
entry->value = reinterpret_cast<void*>(first_free_entry);
+ if (merged_reverse_it != reverse_merged_native_entries_map.end()) {
+ auto it = merged_native_entries_map_.find(merged_reverse_it->second);
+ DCHECK_NE(merged_native_entries_map_.end(), it);
+ it->second = first_free_entry;
+ }
++first_free_entry;
} else {
if (entry_info.addr) {
entries_map_.Remove(reinterpret_cast<void*>(entry_info.addr),
ComputeAddressHash(entry_info.addr));
+ if (merged_reverse_it != reverse_merged_native_entries_map.end()) {
+ merged_native_entries_map_.erase(merged_reverse_it->second);
+ }
}
}
}
@@ -1853,10 +1891,14 @@ HeapEntry* EmbedderGraphEntriesAllocator::AllocateEntry(HeapThing ptr) {
reinterpret_cast<EmbedderGraphImpl::Node*>(ptr);
DCHECK(node->IsEmbedderNode());
size_t size = node->SizeInBytes();
- return snapshot_->AddEntry(
- EmbedderGraphNodeType(node), EmbedderGraphNodeName(names_, node),
- static_cast<SnapshotObjectId>(reinterpret_cast<uintptr_t>(node) << 1),
- static_cast<int>(size), 0);
+ Address lookup_address = reinterpret_cast<Address>(node->GetNativeObject());
+ SnapshotObjectId id =
+ (lookup_address) ? heap_object_map_->FindOrAddEntry(lookup_address, 0)
+ : static_cast<SnapshotObjectId>(
+ reinterpret_cast<uintptr_t>(node) << 1);
+ return snapshot_->AddEntry(EmbedderGraphNodeType(node),
+ EmbedderGraphNodeName(names_, node), id,
+ static_cast<int>(size), 0);
}
NativeObjectsExplorer::NativeObjectsExplorer(
@@ -1865,12 +1907,14 @@ NativeObjectsExplorer::NativeObjectsExplorer(
Isolate::FromHeap(snapshot->profiler()->heap_object_map()->heap())),
snapshot_(snapshot),
names_(snapshot_->profiler()->names()),
+ heap_object_map_(snapshot_->profiler()->heap_object_map()),
embedder_graph_entries_allocator_(
new EmbedderGraphEntriesAllocator(snapshot)) {}
HeapEntry* NativeObjectsExplorer::EntryForEmbedderGraphNode(
EmbedderGraphImpl::Node* node) {
EmbedderGraphImpl::Node* wrapper = node->WrapperNode();
+ NativeObject native_object = node->GetNativeObject();
if (wrapper) {
node = wrapper;
}
@@ -1882,8 +1926,16 @@ HeapEntry* NativeObjectsExplorer::EntryForEmbedderGraphNode(
static_cast<EmbedderGraphImpl::V8NodeImpl*>(node);
Object object = v8_node->GetObject();
if (object.IsSmi()) return nullptr;
- return generator_->FindEntry(
+ HeapEntry* entry = generator_->FindEntry(
reinterpret_cast<void*>(Object::cast(object).ptr()));
+ if (native_object) {
+ HeapObject heap_object = HeapObject::cast(object);
+ heap_object_map_->AddMergedNativeEntry(native_object,
+ heap_object.address());
+ DCHECK_EQ(entry->id(),
+ heap_object_map_->FindMergedNativeEntry(native_object));
+ }
+ return entry;
}
}
@@ -1945,13 +1997,13 @@ HeapSnapshotGenerator::HeapSnapshotGenerator(
}
namespace {
-class NullContextScope {
+class NullContextForSnapshotScope {
public:
- explicit NullContextScope(Isolate* isolate)
+ explicit NullContextForSnapshotScope(Isolate* isolate)
: isolate_(isolate), prev_(isolate->context()) {
isolate_->set_context(Context());
}
- ~NullContextScope() { isolate_->set_context(prev_); }
+ ~NullContextForSnapshotScope() { isolate_->set_context(prev_); }
private:
Isolate* isolate_;
@@ -1971,7 +2023,7 @@ bool HeapSnapshotGenerator::GenerateSnapshot() {
heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags,
GarbageCollectionReason::kHeapProfiler);
- NullContextScope null_context_scope(Isolate::FromHeap(heap_));
+ NullContextForSnapshotScope null_context_scope(Isolate::FromHeap(heap_));
#ifdef VERIFY_HEAP
Heap* debug_heap = heap_;
diff --git a/deps/v8/src/profiler/heap-snapshot-generator.h b/deps/v8/src/profiler/heap-snapshot-generator.h
index d3d3330e27..360ed1f009 100644
--- a/deps/v8/src/profiler/heap-snapshot-generator.h
+++ b/deps/v8/src/profiler/heap-snapshot-generator.h
@@ -82,8 +82,8 @@ class HeapGraphEdge {
V8_INLINE HeapSnapshot* snapshot() const;
int from_index() const { return FromIndexField::decode(bit_field_); }
- class TypeField : public BitField<Type, 0, 3> {};
- class FromIndexField : public BitField<int, 3, 29> {};
+ using TypeField = BitField<Type, 0, 3>;
+ using FromIndexField = BitField<int, 3, 29>;
uint32_t bit_field_;
HeapEntry* to_entry_;
union {
@@ -249,6 +249,8 @@ class HeapObjectsMap {
SnapshotObjectId FindOrAddEntry(Address addr,
unsigned int size,
bool accessed = true);
+ SnapshotObjectId FindMergedNativeEntry(NativeObject addr);
+ void AddMergedNativeEntry(NativeObject addr, Address canonical_addr);
bool MoveObject(Address from, Address to, int size);
void UpdateObjectSize(Address addr, int size);
SnapshotObjectId last_assigned_id() const {
@@ -285,6 +287,8 @@ class HeapObjectsMap {
base::HashMap entries_map_;
std::vector<EntryInfo> entries_;
std::vector<TimeInterval> time_intervals_;
+ // Map from NativeObject to EntryInfo index in entries_.
+ std::unordered_map<NativeObject, size_t> merged_native_entries_map_;
Heap* heap_;
DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
@@ -453,6 +457,7 @@ class NativeObjectsExplorer {
Isolate* isolate_;
HeapSnapshot* snapshot_;
StringsStorage* names_;
+ HeapObjectsMap* heap_object_map_;
std::unique_ptr<HeapEntriesAllocator> embedder_graph_entries_allocator_;
// Used during references extraction.
HeapSnapshotGenerator* generator_ = nullptr;
diff --git a/deps/v8/src/profiler/profile-generator-inl.h b/deps/v8/src/profiler/profile-generator-inl.h
index 2d73c20a37..bb5ef0da5b 100644
--- a/deps/v8/src/profiler/profile-generator-inl.h
+++ b/deps/v8/src/profiler/profile-generator-inl.h
@@ -28,7 +28,7 @@ CodeEntry::CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name,
instruction_start_(instruction_start) {}
inline CodeEntry* ProfileGenerator::FindEntry(Address address) {
- CodeEntry* entry = code_map_.FindEntry(address);
+ CodeEntry* entry = code_map_->FindEntry(address);
if (entry) entry->mark_used();
return entry;
}
diff --git a/deps/v8/src/profiler/profile-generator.cc b/deps/v8/src/profiler/profile-generator.cc
index e869f65762..f5f7184613 100644
--- a/deps/v8/src/profiler/profile-generator.cc
+++ b/deps/v8/src/profiler/profile-generator.cc
@@ -19,6 +19,14 @@ void SourcePositionTable::SetPosition(int pc_offset, int line,
int inlining_id) {
DCHECK_GE(pc_offset, 0);
DCHECK_GT(line, 0); // The 1-based number of the source line.
+ // It's possible that we map multiple source positions to a pc_offset in
+ // optimized code. Usually these map to the same line, so there is no
+ // difference here as we only store line number and not line/col in the form
+ // of a script offset. Ignore any subsequent sets to the same offset.
+ if (!pc_offsets_to_lines_.empty() &&
+ pc_offsets_to_lines_.back().pc_offset == pc_offset) {
+ return;
+ }
// Check that we are inserting in ascending order, so that the vector remains
// sorted.
DCHECK(pc_offsets_to_lines_.empty() ||
@@ -404,16 +412,18 @@ ProfileNode* ProfileTree::AddPathFromEnd(const std::vector<CodeEntry*>& path,
ProfileNode* ProfileTree::AddPathFromEnd(const ProfileStackTrace& path,
int src_line, bool update_stats,
- ProfilingMode mode) {
+ ProfilingMode mode,
+ ContextFilter* context_filter) {
ProfileNode* node = root_;
CodeEntry* last_entry = nullptr;
int parent_line_number = v8::CpuProfileNode::kNoLineNumberInfo;
for (auto it = path.rbegin(); it != path.rend(); ++it) {
- if ((*it).code_entry == nullptr) continue;
- last_entry = (*it).code_entry;
- node = node->FindOrAddChild((*it).code_entry, parent_line_number);
+ if (it->entry.code_entry == nullptr) continue;
+ if (context_filter && !context_filter->Accept(*it)) continue;
+ last_entry = (*it).entry.code_entry;
+ node = node->FindOrAddChild((*it).entry.code_entry, parent_line_number);
parent_line_number = mode == ProfilingMode::kCallerLineNumbers
- ? (*it).line_number
+ ? (*it).entry.line_number
: v8::CpuProfileNode::kNoLineNumberInfo;
}
if (last_entry && last_entry->has_deopt_info()) {
@@ -428,7 +438,6 @@ ProfileNode* ProfileTree::AddPathFromEnd(const ProfileStackTrace& path,
return node;
}
-
class Position {
public:
explicit Position(ProfileNode* node)
@@ -470,6 +479,21 @@ void ProfileTree::TraverseDepthFirst(Callback* callback) {
}
}
+bool ContextFilter::Accept(const ProfileStackFrame& frame) {
+ // If a frame should always be included in profiles (e.g. metadata frames),
+ // skip the context check.
+ if (!frame.filterable) return true;
+
+ // Strip heap object tag from frame.
+ return (frame.native_context & ~kHeapObjectTag) == native_context_address_;
+}
+
+void ContextFilter::OnMoveEvent(Address from_address, Address to_address) {
+ if (native_context_address() != from_address) return;
+
+ set_native_context_address(to_address);
+}
+
using v8::tracing::TracedValue;
std::atomic<uint32_t> CpuProfile::last_id_;
@@ -488,6 +512,13 @@ CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
(start_time_ - base::TimeTicks()).InMicroseconds());
TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"),
"Profile", id_, "data", std::move(value));
+
+ if (options_.has_filter_context()) {
+ DisallowHeapAllocation no_gc;
+ i::Address raw_filter_context =
+ reinterpret_cast<i::Address>(options_.raw_filter_context());
+ context_filter_ = base::make_unique<ContextFilter>(raw_filter_context);
+ }
}
bool CpuProfile::CheckSubsample(base::TimeDelta source_sampling_interval) {
@@ -512,11 +543,11 @@ void CpuProfile::AddPath(base::TimeTicks timestamp,
bool update_stats, base::TimeDelta sampling_interval) {
if (!CheckSubsample(sampling_interval)) return;
- ProfileNode* top_frame_node =
- top_down_.AddPathFromEnd(path, src_line, update_stats, options_.mode());
+ ProfileNode* top_frame_node = top_down_.AddPathFromEnd(
+ path, src_line, update_stats, options_.mode(), context_filter_.get());
bool should_record_sample =
- !timestamp.IsNull() &&
+ !timestamp.IsNull() && timestamp >= start_time_ &&
(options_.max_samples() == CpuProfilingOptions::kNoSampleLimit ||
samples_.size() < options_.max_samples());
@@ -615,6 +646,8 @@ void CpuProfile::StreamPendingTraceEvents() {
void CpuProfile::FinishProfile() {
end_time_ = base::TimeTicks::HighResolutionNow();
+ // Stop tracking context movements after profiling stops.
+ context_filter_ = nullptr;
StreamPendingTraceEvents();
auto value = TracedValue::Create();
value->SetDouble("endTime", (end_time_ - base::TimeTicks()).InMicroseconds());
@@ -825,8 +858,20 @@ void CpuProfilesCollection::AddPathToCurrentProfiles(
current_profiles_semaphore_.Signal();
}
-ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
- : profiles_(profiles) {}
+void CpuProfilesCollection::UpdateNativeContextAddressForCurrentProfiles(
+ Address from, Address to) {
+ current_profiles_semaphore_.Wait();
+ for (const std::unique_ptr<CpuProfile>& profile : current_profiles_) {
+ if (auto* context_filter = profile->context_filter()) {
+ context_filter->OnMoveEvent(from, to);
+ }
+ }
+ current_profiles_semaphore_.Signal();
+}
+
+ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles,
+ CodeMap* code_map)
+ : profiles_(profiles), code_map_(code_map) {}
void ProfileGenerator::RecordTickSample(const TickSample& sample) {
ProfileStackTrace stack_trace;
@@ -848,9 +893,11 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// Don't use PC when in external callback code, as it can point
// inside a callback's code, and we will erroneously report
// that a callback calls itself.
- stack_trace.push_back(
- {FindEntry(reinterpret_cast<Address>(sample.external_callback_entry)),
- no_line_info});
+ stack_trace.push_back({{FindEntry(reinterpret_cast<Address>(
+ sample.external_callback_entry)),
+ no_line_info},
+ reinterpret_cast<Address>(sample.top_context),
+ true});
} else {
Address attributed_pc = reinterpret_cast<Address>(sample.pc);
CodeEntry* pc_entry = FindEntry(attributed_pc);
@@ -874,7 +921,9 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
src_line = pc_entry->line_number();
}
src_line_not_found = false;
- stack_trace.push_back({pc_entry, src_line});
+ stack_trace.push_back({{pc_entry, src_line},
+ reinterpret_cast<Address>(sample.top_context),
+ true});
if (pc_entry->builtin_id() == Builtins::kFunctionPrototypeApply ||
pc_entry->builtin_id() == Builtins::kFunctionPrototypeCall) {
@@ -886,7 +935,9 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// 'unresolved' entry.
if (!sample.has_external_callback) {
stack_trace.push_back(
- {CodeEntry::unresolved_entry(), no_line_info});
+ {{CodeEntry::unresolved_entry(), no_line_info},
+ kNullAddress,
+ true});
}
}
}
@@ -894,6 +945,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
for (unsigned i = 0; i < sample.frames_count; ++i) {
Address stack_pos = reinterpret_cast<Address>(sample.stack[i]);
+ Address native_context = reinterpret_cast<Address>(sample.contexts[i]);
CodeEntry* entry = FindEntry(stack_pos);
int line_number = no_line_info;
if (entry) {
@@ -905,8 +957,13 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
entry->GetInlineStack(pc_offset);
if (inline_stack) {
int most_inlined_frame_line_number = entry->GetSourceLine(pc_offset);
- stack_trace.insert(stack_trace.end(), inline_stack->begin(),
- inline_stack->end());
+ for (auto entry : *inline_stack) {
+ // Set the native context of inlined frames to be equal to that of
+ // their parent. This is safe, as functions cannot inline themselves
+ // into a parent from another native context.
+ stack_trace.push_back({entry, native_context, true});
+ }
+
// This is a bit of a messy hack. The line number for the most-inlined
// frame (the function at the end of the chain of function calls) has
// the wrong line number in inline_stack. The actual line number in
@@ -916,7 +973,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// inlining_id.
DCHECK(!inline_stack->empty());
size_t index = stack_trace.size() - inline_stack->size();
- stack_trace[index].line_number = most_inlined_frame_line_number;
+ stack_trace[index].entry.line_number = most_inlined_frame_line_number;
}
// Skip unresolved frames (e.g. internal frame) and get source line of
// the first JS caller.
@@ -935,21 +992,22 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// so we use it instead of pushing entry to stack_trace.
if (inline_stack) continue;
}
- stack_trace.push_back({entry, line_number});
+ stack_trace.push_back({{entry, line_number}, native_context, true});
}
}
if (FLAG_prof_browser_mode) {
bool no_symbolized_entries = true;
for (auto e : stack_trace) {
- if (e.code_entry != nullptr) {
+ if (e.entry.code_entry != nullptr) {
no_symbolized_entries = false;
break;
}
}
// If no frames were symbolized, put the VM state entry in.
if (no_symbolized_entries) {
- stack_trace.push_back({EntryForVMState(sample.state), no_line_info});
+ stack_trace.push_back(
+ {{EntryForVMState(sample.state), no_line_info}, kNullAddress, false});
}
}
@@ -958,6 +1016,10 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
sample.sampling_interval);
}
+void ProfileGenerator::UpdateNativeContextAddress(Address from, Address to) {
+ profiles_->UpdateNativeContextAddressForCurrentProfiles(from, to);
+}
+
CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
switch (tag) {
case GC:
diff --git a/deps/v8/src/profiler/profile-generator.h b/deps/v8/src/profiler/profile-generator.h
index b0543c9d79..2f7273a086 100644
--- a/deps/v8/src/profiler/profile-generator.h
+++ b/deps/v8/src/profiler/profile-generator.h
@@ -234,7 +234,36 @@ struct CodeEntryAndLineNumber {
int line_number;
};
-using ProfileStackTrace = std::vector<CodeEntryAndLineNumber>;
+struct ProfileStackFrame {
+ CodeEntryAndLineNumber entry;
+ Address native_context;
+ bool filterable; // If true, the frame should be filtered by context (if a
+ // filter is present).
+};
+
+typedef std::vector<ProfileStackFrame> ProfileStackTrace;
+
+// Filters stack frames from sources other than a target native context.
+class ContextFilter {
+ public:
+ explicit ContextFilter(Address native_context_address)
+ : native_context_address_(native_context_address) {}
+
+ // Returns true if the stack frame passes a context check.
+ bool Accept(const ProfileStackFrame&);
+
+ // Invoked when a native context has changed address.
+ void OnMoveEvent(Address from_address, Address to_address);
+
+ // Update the context's tracked address based on VM-thread events.
+ void set_native_context_address(Address address) {
+ native_context_address_ = address;
+ }
+ Address native_context_address() const { return native_context_address_; }
+
+ private:
+ Address native_context_address_;
+};
class ProfileTree;
@@ -321,7 +350,8 @@ class V8_EXPORT_PRIVATE ProfileTree {
const ProfileStackTrace& path,
int src_line = v8::CpuProfileNode::kNoLineNumberInfo,
bool update_stats = true,
- ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
+ ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers,
+ ContextFilter* context_filter = nullptr);
ProfileNode* root() const { return root_; }
unsigned next_node_id() { return next_node_id_++; }
unsigned GetFunctionId(const ProfileNode* node);
@@ -389,6 +419,7 @@ class CpuProfile {
base::TimeTicks start_time() const { return start_time_; }
base::TimeTicks end_time() const { return end_time_; }
CpuProfiler* cpu_profiler() const { return profiler_; }
+ ContextFilter* context_filter() const { return context_filter_.get(); }
void UpdateTicksScale();
@@ -399,6 +430,7 @@ class CpuProfile {
const char* title_;
const CpuProfilingOptions options_;
+ std::unique_ptr<ContextFilter> context_filter_;
base::TimeTicks start_time_;
base::TimeTicks end_time_;
std::deque<SampleInfo> samples_;
@@ -477,6 +509,9 @@ class V8_EXPORT_PRIVATE CpuProfilesCollection {
bool update_stats,
base::TimeDelta sampling_interval);
+ // Called from profile generator thread.
+ void UpdateNativeContextAddressForCurrentProfiles(Address from, Address to);
+
// Limits the number of profiles that can be simultaneously collected.
static const int kMaxSimultaneousProfiles = 100;
@@ -494,18 +529,20 @@ class V8_EXPORT_PRIVATE CpuProfilesCollection {
class V8_EXPORT_PRIVATE ProfileGenerator {
public:
- explicit ProfileGenerator(CpuProfilesCollection* profiles);
+ explicit ProfileGenerator(CpuProfilesCollection* profiles, CodeMap* code_map);
void RecordTickSample(const TickSample& sample);
- CodeMap* code_map() { return &code_map_; }
+ void UpdateNativeContextAddress(Address from, Address to);
+
+ CodeMap* code_map() { return code_map_; }
private:
CodeEntry* FindEntry(Address address);
CodeEntry* EntryForVMState(StateTag tag);
CpuProfilesCollection* profiles_;
- CodeMap code_map_;
+ CodeMap* const code_map_;
DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
};
diff --git a/deps/v8/src/profiler/profiler-listener.cc b/deps/v8/src/profiler/profiler-listener.cc
index 156c1b8bb0..b00c1f5cfd 100644
--- a/deps/v8/src/profiler/profiler-listener.cc
+++ b/deps/v8/src/profiler/profiler-listener.cc
@@ -177,8 +177,7 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
CodeEntry* cached_entry = GetOrInsertCachedEntry(
&cached_inline_entries, std::move(inline_entry));
- inline_stack.push_back(
- CodeEntryAndLineNumber{cached_entry, line_number});
+ inline_stack.push_back({cached_entry, line_number});
}
DCHECK(!inline_stack.empty());
inline_stacks.emplace(inlining_id, std::move(inline_stack));
@@ -280,6 +279,13 @@ void ProfilerListener::SetterCallbackEvent(Name name, Address entry_point) {
DispatchCodeEvent(evt_rec);
}
+void ProfilerListener::NativeContextMoveEvent(Address from, Address to) {
+ CodeEventsContainer evt_rec(CodeEventRecord::NATIVE_CONTEXT_MOVE);
+ evt_rec.NativeContextMoveEventRecord_.from_address = from;
+ evt_rec.NativeContextMoveEventRecord_.to_address = to;
+ DispatchCodeEvent(evt_rec);
+}
+
Name ProfilerListener::InferScriptName(Name name, SharedFunctionInfo info) {
if (name.IsString() && String::cast(name).length()) return name;
if (!info.script().IsScript()) return name;
diff --git a/deps/v8/src/profiler/profiler-listener.h b/deps/v8/src/profiler/profiler-listener.h
index 6ca4225e54..85070d65aa 100644
--- a/deps/v8/src/profiler/profiler-listener.h
+++ b/deps/v8/src/profiler/profiler-listener.h
@@ -55,6 +55,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
void RegExpCodeCreateEvent(AbstractCode code, String source) override;
void SetterCallbackEvent(Name name, Address entry_point) override;
void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
+ void NativeContextMoveEvent(Address from, Address to) override;
const char* GetName(Name name) {
return function_and_resource_names_.GetName(name);
diff --git a/deps/v8/src/profiler/tick-sample.cc b/deps/v8/src/profiler/tick-sample.cc
index b3ea07db34..5c2f2d63ce 100644
--- a/deps/v8/src/profiler/tick-sample.cc
+++ b/deps/v8/src/profiler/tick-sample.cc
@@ -16,6 +16,7 @@
#include "src/sanitizer/msan.h"
namespace v8 {
+namespace internal {
namespace {
bool IsSamePage(i::Address ptr1, i::Address ptr2) {
@@ -78,11 +79,6 @@ bool IsNoFrameRegion(i::Address address) {
return false;
}
-} // namespace
-
-namespace internal {
-namespace {
-
#if defined(USE_SIMULATOR)
class SimulatorHelper {
public:
@@ -147,22 +143,56 @@ bool SimulatorHelper::FillRegisters(Isolate* isolate,
}
#endif // USE_SIMULATOR
+// Attempts to safely dereference the address of a native context at a given
+// context's address. Returns kNullAddress on failure, in the event that the
+// context is in an inconsistent state.
+Address ScrapeNativeContextAddress(Heap* heap, Address context_address) {
+ DCHECK_EQ(heap->gc_state(), Heap::NOT_IN_GC);
+
+ if (!HAS_STRONG_HEAP_OBJECT_TAG(context_address)) return kNullAddress;
+
+ if (heap->memory_allocator()->IsOutsideAllocatedSpace(context_address))
+ return kNullAddress;
+
+ // Note that once a native context has been assigned to a context, the slot
+ // is no longer mutated except during pointer updates / evictions. Since
+ // pointer updates exclusively occur on the main thread, and we don't record
+ // TickSamples when the main thread's VM state is GC, the only other
+ // situation where the address here would be invalid is if it's being
+ // reassigned -- which isn't possible.
+ int native_context_offset =
+ i::Context::SlotOffset(i::Context::NATIVE_CONTEXT_INDEX);
+ i::Address native_context_slot_address =
+ context_address + native_context_offset;
+
+ // By the prior hypothesis, the indirect native context address should always
+ // be valid.
+ if (heap->memory_allocator()->IsOutsideAllocatedSpace(
+ native_context_slot_address)) {
+ DCHECK(false);
+ return kNullAddress;
+ }
+
+ i::ObjectSlot native_context_slot(native_context_slot_address);
+ i::Object native_context = native_context_slot.Relaxed_Load();
+
+ return native_context.ptr();
+}
+
} // namespace
-} // namespace internal
-//
-// StackTracer implementation
-//
DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate,
const RegisterState& reg_state,
RecordCEntryFrame record_c_entry_frame,
bool update_stats,
- bool use_simulator_reg_state) {
+ bool use_simulator_reg_state,
+ base::TimeDelta sampling_interval) {
this->update_stats = update_stats;
SampleInfo info;
RegisterState regs = reg_state;
if (!GetStackSample(v8_isolate, &regs, record_c_entry_frame, stack,
- kMaxFramesCount, &info, use_simulator_reg_state)) {
+ kMaxFramesCount, &info, use_simulator_reg_state,
+ contexts)) {
// It is executing JS but failed to collect a stack trace.
// Mark the sample as spoiled.
pc = nullptr;
@@ -173,6 +203,7 @@ DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate,
pc = regs.pc;
frames_count = static_cast<unsigned>(info.frames_count);
has_external_callback = info.external_callback_entry != nullptr;
+ top_context = info.top_context;
if (has_external_callback) {
external_callback_entry = info.external_callback_entry;
} else if (frames_count) {
@@ -191,17 +222,20 @@ DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate,
} else {
tos = nullptr;
}
+ this->sampling_interval = sampling_interval;
+ timestamp = base::TimeTicks::HighResolutionNow();
}
bool TickSample::GetStackSample(Isolate* v8_isolate, RegisterState* regs,
RecordCEntryFrame record_c_entry_frame,
void** frames, size_t frames_limit,
v8::SampleInfo* sample_info,
- bool use_simulator_reg_state) {
+ bool use_simulator_reg_state, void** contexts) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
sample_info->frames_count = 0;
sample_info->vm_state = isolate->current_vm_state();
sample_info->external_callback_entry = nullptr;
+ sample_info->top_context = nullptr;
if (sample_info->vm_state == GC) return true;
i::Address js_entry_sp = isolate->js_entry_sp();
@@ -229,7 +263,7 @@ bool TickSample::GetStackSample(Isolate* v8_isolate, RegisterState* regs,
i::ExternalCallbackScope* scope = isolate->external_callback_scope();
i::Address handler = i::Isolate::handler(isolate->thread_local_top());
// If there is a handler on top of the external callback scope then
- // we have already entrered JavaScript again and the external callback
+ // we have already entered JavaScript again and the external callback
// is not the top function.
if (scope && scope->scope_address() < handler) {
i::Address* external_callback_entry_ptr =
@@ -245,23 +279,62 @@ bool TickSample::GetStackSample(Isolate* v8_isolate, RegisterState* regs,
reinterpret_cast<i::Address>(regs->sp),
reinterpret_cast<i::Address>(regs->lr),
js_entry_sp);
+
+ i::Address top_context_address = it.top_context_address();
+ if (top_context_address != i::kNullAddress) {
+ sample_info->top_context = reinterpret_cast<void*>(
+ i::ScrapeNativeContextAddress(isolate->heap(), top_context_address));
+ } else {
+ sample_info->top_context = nullptr;
+ }
+
if (it.done()) return true;
size_t i = 0;
if (record_c_entry_frame == kIncludeCEntryFrame &&
(it.top_frame_type() == internal::StackFrame::EXIT ||
it.top_frame_type() == internal::StackFrame::BUILTIN_EXIT)) {
- frames[i++] = reinterpret_cast<void*>(isolate->c_function());
+ frames[i] = reinterpret_cast<void*>(isolate->c_function());
+ if (contexts) contexts[i] = sample_info->top_context;
+ i++;
}
+
+ // If we couldn't get a context address from the top frame due to execution
+ // being in a callback, borrow it from the next context on the stack.
+ bool borrows_top_context = it.top_frame_type() == i::StackFrame::EXIT ||
+ it.top_frame_type() == i::StackFrame::BUILTIN_EXIT;
+
i::RuntimeCallTimer* timer =
isolate->counters()->runtime_call_stats()->current_timer();
for (; !it.done() && i < frames_limit; it.Advance()) {
while (timer && reinterpret_cast<i::Address>(timer) < it.frame()->fp() &&
i < frames_limit) {
+ if (contexts) contexts[i] = nullptr;
frames[i++] = reinterpret_cast<void*>(timer->counter());
timer = timer->parent();
}
if (i == frames_limit) break;
+
+ // Attempt to read the native context associated with the frame from the
+ // heap for standard frames.
+ if (it.frame()->is_standard() && (contexts || borrows_top_context)) {
+ i::Address context_address = base::Memory<i::Address>(
+ it.frame()->fp() + i::StandardFrameConstants::kContextOffset);
+ i::Address native_context_address =
+ i::ScrapeNativeContextAddress(isolate->heap(), context_address);
+ if (contexts)
+ contexts[i] = reinterpret_cast<void*>(native_context_address);
+
+ if (borrows_top_context) {
+ DCHECK(!sample_info->top_context);
+ sample_info->top_context =
+ reinterpret_cast<void*>(native_context_address);
+ }
+ } else if (contexts) {
+ contexts[i] = nullptr;
+ }
+ borrows_top_context = false;
+
if (it.frame()->is_interpreted()) {
// For interpreted frames use the bytecode array pointer as the pc.
i::InterpretedFrame* frame =
@@ -290,20 +363,6 @@ bool TickSample::GetStackSample(Isolate* v8_isolate, RegisterState* regs,
return true;
}
-namespace internal {
-
-void TickSample::Init(Isolate* isolate, const v8::RegisterState& state,
- RecordCEntryFrame record_c_entry_frame, bool update_stats,
- bool use_simulator_reg_state,
- base::TimeDelta sampling_interval) {
- v8::TickSample::Init(reinterpret_cast<v8::Isolate*>(isolate), state,
- record_c_entry_frame, update_stats,
- use_simulator_reg_state);
- this->sampling_interval = sampling_interval;
- if (pc == nullptr) return;
- timestamp = base::TimeTicks::HighResolutionNow();
-}
-
void TickSample::print() const {
PrintF("TickSample: at %p\n", this);
PrintF(" - state: %s\n", StateToString(state));
diff --git a/deps/v8/src/profiler/tick-sample.h b/deps/v8/src/profiler/tick-sample.h
index ba78c923c4..37ae1e9d06 100644
--- a/deps/v8/src/profiler/tick-sample.h
+++ b/deps/v8/src/profiler/tick-sample.h
@@ -5,7 +5,7 @@
#ifndef V8_PROFILER_TICK_SAMPLE_H_
#define V8_PROFILER_TICK_SAMPLE_H_
-#include "include/v8-profiler.h"
+#include "include/v8.h"
#include "src/base/platform/time.h"
#include "src/common/globals.h"
@@ -14,15 +14,83 @@ namespace internal {
class Isolate;
-struct TickSample : public v8::TickSample {
+// TickSample captures the information collected for each sample.
+struct V8_EXPORT TickSample {
+ // Internal profiling (with --prof + tools/$OS-tick-processor) wants to
+ // include the runtime function we're calling. Externally exposed tick
+ // samples don't care.
+ enum RecordCEntryFrame { kIncludeCEntryFrame, kSkipCEntryFrame };
+
+ TickSample()
+ : state(OTHER),
+ pc(nullptr),
+ external_callback_entry(nullptr),
+ frames_count(0),
+ has_external_callback(false),
+ update_stats(true) {}
+
+ /**
+ * Initialize a tick sample from the isolate.
+ * \param isolate The isolate.
+ * \param state Execution state.
+ * \param record_c_entry_frame Include or skip the runtime function.
+ * \param update_stats Whether update the sample to the aggregated stats.
+ * \param use_simulator_reg_state When set to true and V8 is running under a
+ * simulator, the method will use the simulator
+ * register state rather than the one provided
+ * with |state| argument. Otherwise the method
+ * will use provided register |state| as is.
+ */
void Init(Isolate* isolate, const v8::RegisterState& state,
RecordCEntryFrame record_c_entry_frame, bool update_stats,
bool use_simulator_reg_state = true,
base::TimeDelta sampling_interval = base::TimeDelta());
- base::TimeTicks timestamp;
- base::TimeDelta sampling_interval; // Sampling interval used to capture.
+ /**
+ * Get a call stack sample from the isolate.
+ * \param isolate The isolate.
+ * \param state Register state.
+ * \param record_c_entry_frame Include or skip the runtime function.
+ * \param frames Caller allocated buffer to store stack frames.
+ * \param frames_limit Maximum number of frames to capture. The buffer must
+ * be large enough to hold the number of frames.
+ * \param sample_info The sample info is filled up by the function
+ * provides number of actual captured stack frames and
+ * the current VM state.
+ * \param use_simulator_reg_state When set to true and V8 is running under a
+ * simulator, the method will use the simulator
+ * register state rather than the one provided
+ * with |state| argument. Otherwise the method
+ * will use provided register |state| as is.
+ * \note GetStackSample is thread and signal safe and should only be called
+ * when the JS thread is paused or interrupted.
+ * Otherwise the behavior is undefined.
+ */
+ static bool GetStackSample(Isolate* isolate, v8::RegisterState* state,
+ RecordCEntryFrame record_c_entry_frame,
+ void** frames, size_t frames_limit,
+ v8::SampleInfo* sample_info,
+ bool use_simulator_reg_state = true,
+ void** contexts = nullptr);
void print() const;
+
+ StateTag state; // The state of the VM.
+ void* pc; // Instruction pointer.
+ union {
+ void* tos; // Top stack value (*sp).
+ void* external_callback_entry;
+ };
+ static const unsigned kMaxFramesCountLog2 = 8;
+ static const unsigned kMaxFramesCount = (1 << kMaxFramesCountLog2) - 1;
+ void* stack[kMaxFramesCount]; // Call stack.
+ void* contexts[kMaxFramesCount]; // Stack of associated native contexts.
+ void* top_context = nullptr; // Address of the incumbent native context.
+ unsigned frames_count : kMaxFramesCountLog2; // Number of captured frames.
+ bool has_external_callback : 1;
+ bool update_stats : 1; // Whether the sample should update aggregated stats.
+
+ base::TimeTicks timestamp;
+ base::TimeDelta sampling_interval; // Sampling interval used to capture.
};
} // namespace internal
diff --git a/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.cc
index 8b462cb03c..2f81b6de86 100644
--- a/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.cc
+++ b/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.cc
@@ -40,6 +40,9 @@ namespace internal {
* Each call to a public method should retain this convention.
*
* The stack will have the following structure:
+ * - fp[56] Address regexp (address of the JSRegExp object; unused in
+ * native code, passed to match signature of
+ * the interpreter)
* - fp[52] Isolate* isolate (address of the current isolate)
* - fp[48] direct_call (if 1, direct call from JavaScript code,
* if 0, call through the runtime system).
@@ -83,7 +86,8 @@ namespace internal {
* int num_capture_registers,
* byte* stack_area_base,
* bool direct_call = false,
- * Isolate* isolate);
+ * Isolate* isolate,
+ * Address regexp);
* The call is performed by NativeRegExpMacroAssembler::Execute()
* (in regexp-macro-assembler.cc) via the GeneratedCode wrapper.
*/
@@ -172,15 +176,14 @@ void RegExpMacroAssemblerARM::CheckCharacterGT(uc16 limit, Label* on_greater) {
BranchOrBacktrack(gt, on_greater);
}
-
-void RegExpMacroAssemblerARM::CheckAtStart(Label* on_at_start) {
+void RegExpMacroAssemblerARM::CheckAtStart(int cp_offset, Label* on_at_start) {
__ ldr(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
- __ add(r0, current_input_offset(), Operand(-char_size()));
+ __ add(r0, current_input_offset(),
+ Operand(-char_size() + cp_offset * char_size()));
__ cmp(r0, r1);
BranchOrBacktrack(eq, on_at_start);
}
-
void RegExpMacroAssemblerARM::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ ldr(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
@@ -647,7 +650,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ mov(r0, Operand(stack_limit));
__ ldr(r0, MemOperand(r0));
__ sub(r0, sp, r0, SetCC);
@@ -929,15 +932,19 @@ RegExpMacroAssembler::IrregexpImplementation
return kARMImplementation;
}
+void RegExpMacroAssemblerARM::LoadCurrentCharacterImpl(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ // It's possible to preload a small number of characters when each success
+ // path requires a large number of characters, but not the reverse.
+ DCHECK_GE(eats_at_least, characters);
-void RegExpMacroAssemblerARM::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
if (check_bounds) {
if (cp_offset >= 0) {
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ CheckPosition(cp_offset + eats_at_least - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
@@ -945,7 +952,6 @@ void RegExpMacroAssemblerARM::LoadCurrentCharacter(int cp_offset,
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
-
void RegExpMacroAssemblerARM::PopCurrentPosition() {
Pop(current_input_offset());
}
@@ -1109,7 +1115,8 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
frame_entry<int>(re_frame, kStartIndex),
- frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
+ static_cast<RegExp::CallOrigin>(frame_entry<int>(re_frame, kDirectCall)),
+ return_address, re_code,
frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
frame_entry_address<const byte*>(re_frame, kInputEnd));
@@ -1193,7 +1200,7 @@ void RegExpMacroAssemblerARM::Pop(Register target) {
void RegExpMacroAssemblerARM::CheckPreemption() {
// Check for preemption.
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ mov(r0, Operand(stack_limit));
__ ldr(r0, MemOperand(r0));
__ cmp(sp, r0);
@@ -1203,7 +1210,7 @@ void RegExpMacroAssemblerARM::CheckPreemption() {
void RegExpMacroAssemblerARM::CheckStackLimit() {
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit(isolate());
+ ExternalReference::address_of_regexp_stack_limit_address(isolate());
__ mov(r0, Operand(stack_limit));
__ ldr(r0, MemOperand(r0));
__ cmp(backtrack_stackpointer(), Operand(r0));
diff --git a/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.h b/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.h
index 9e95f8e1f2..9b21c5a11c 100644
--- a/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.h
+++ b/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.h
@@ -23,7 +23,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM
virtual void AdvanceRegister(int reg, int by);
virtual void Backtrack();
virtual void Bind(Label* label);
- virtual void CheckAtStart(Label* on_at_start);
+ virtual void CheckAtStart(int cp_offset, Label* on_at_start);
virtual void CheckCharacter(unsigned c, Label* on_equal);
virtual void CheckCharacterAfterAnd(unsigned c,
unsigned mask,
@@ -67,10 +67,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM
virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
virtual void IfRegisterEqPos(int reg, Label* if_eq);
virtual IrregexpImplementation Implementation();
- virtual void LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1);
+ virtual void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least);
virtual void PopCurrentPosition();
virtual void PopRegister(int register_index);
virtual void PushBacktrack(Label* label);
diff --git a/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc b/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc
index b299ad0535..9e00063487 100644
--- a/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc
+++ b/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc
@@ -55,7 +55,10 @@ namespace internal {
* (as referred to in
* the code)
*
- * - fp[96] isolate Address of the current isolate.
+ * - fp[104] Address regexp Address of the JSRegExp object. Unused in
+ * native code, passed to match signature of
+ * the interpreter.
+ * - fp[96] isolate Address of the current isolate.
* ^^^ sp when called ^^^
* - fp[88] lr Return from the RegExp code.
* - fp[80] r29 Old frame pointer (CalleeSaved).
@@ -93,7 +96,8 @@ namespace internal {
* int num_capture_registers,
* byte* stack_area_base,
* bool direct_call = false,
- * Isolate* isolate);
+ * Isolate* isolate,
+ * Address regexp);
* The call is performed by NativeRegExpMacroAssembler::Execute()
* (in regexp-macro-assembler.cc) via the GeneratedCode wrapper.
*/
@@ -201,14 +205,14 @@ void RegExpMacroAssemblerARM64::CheckCharacterGT(uc16 limit,
CompareAndBranchOrBacktrack(current_character(), limit, hi, on_greater);
}
-
-void RegExpMacroAssemblerARM64::CheckAtStart(Label* on_at_start) {
- __ Add(w10, current_input_offset(), Operand(-char_size()));
+void RegExpMacroAssemblerARM64::CheckAtStart(int cp_offset,
+ Label* on_at_start) {
+ __ Add(w10, current_input_offset(),
+ Operand(-char_size() + cp_offset * char_size()));
__ Cmp(w10, string_start_minus_one());
BranchOrBacktrack(eq, on_at_start);
}
-
void RegExpMacroAssemblerARM64::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ Add(w10, current_input_offset(),
@@ -750,7 +754,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ Mov(x10, stack_limit);
__ Ldr(x10, MemOperand(x10));
__ Subs(x10, sp, x10);
@@ -1106,18 +1110,22 @@ RegExpMacroAssembler::IrregexpImplementation
return kARM64Implementation;
}
+void RegExpMacroAssemblerARM64::LoadCurrentCharacterImpl(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ // It's possible to preload a small number of characters when each success
+ // path requires a large number of characters, but not the reverse.
+ DCHECK_GE(eats_at_least, characters);
-void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
// TODO(pielan): Make sure long strings are caught before this, and not
// just asserted in debug mode.
// Be sane! (And ensure that an int32_t can be used to index the string)
DCHECK(cp_offset < (1<<30));
if (check_bounds) {
if (cp_offset >= 0) {
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ CheckPosition(cp_offset + eats_at_least - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
@@ -1125,7 +1133,6 @@ void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset,
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
-
void RegExpMacroAssemblerARM64::PopCurrentPosition() {
Pop(current_input_offset());
}
@@ -1326,8 +1333,9 @@ int RegExpMacroAssemblerARM64::CheckStackGuardState(
Code re_code = Code::cast(Object(raw_code));
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate), start_index,
- frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
- frame_entry_address<Address>(re_frame, kInput), input_start, input_end);
+ static_cast<RegExp::CallOrigin>(frame_entry<int>(re_frame, kDirectCall)),
+ return_address, re_code, frame_entry_address<Address>(re_frame, kInput),
+ input_start, input_end);
}
@@ -1448,7 +1456,7 @@ void RegExpMacroAssemblerARM64::CompareAndBranchOrBacktrack(Register reg,
void RegExpMacroAssemblerARM64::CheckPreemption() {
// Check for preemption.
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ Mov(x10, stack_limit);
__ Ldr(x10, MemOperand(x10));
__ Cmp(sp, x10);
@@ -1458,7 +1466,7 @@ void RegExpMacroAssemblerARM64::CheckPreemption() {
void RegExpMacroAssemblerARM64::CheckStackLimit() {
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit(isolate());
+ ExternalReference::address_of_regexp_stack_limit_address(isolate());
__ Mov(x10, stack_limit);
__ Ldr(x10, MemOperand(x10));
__ Cmp(backtrack_stackpointer(), x10);
diff --git a/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h b/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h
index ef83f9e43c..6154c6cf60 100644
--- a/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h
+++ b/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h
@@ -24,7 +24,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64
virtual void AdvanceRegister(int reg, int by);
virtual void Backtrack();
virtual void Bind(Label* label);
- virtual void CheckAtStart(Label* on_at_start);
+ virtual void CheckAtStart(int cp_offset, Label* on_at_start);
virtual void CheckCharacter(unsigned c, Label* on_equal);
virtual void CheckCharacterAfterAnd(unsigned c,
unsigned mask,
@@ -72,10 +72,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64
virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
virtual void IfRegisterEqPos(int reg, Label* if_eq);
virtual IrregexpImplementation Implementation();
- virtual void LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1);
+ virtual void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least);
virtual void PopCurrentPosition();
virtual void PopRegister(int register_index);
virtual void PushBacktrack(Label* label);
diff --git a/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc b/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc
index eb42c23215..5ee7b90988 100644
--- a/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc
+++ b/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc
@@ -34,6 +34,9 @@ namespace internal {
*
* Each call to a public method should retain this convention.
* The stack will have the following structure:
+ * - Address regexp (address of the JSRegExp object; unused in
+ * native code, passed to match signature of
+ * the interpreter)
* - Isolate* isolate (address of the current isolate)
* - direct_call (if 1, direct call from JavaScript code, if 0
* call through the runtime system)
@@ -73,7 +76,8 @@ namespace internal {
* int num_capture_registers,
* byte* stack_area_base,
* bool direct_call = false,
- * Isolate* isolate);
+ * Isolate* isolate
+ * Address regexp);
*/
#define __ ACCESS_MASM(masm_)
@@ -161,14 +165,12 @@ void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
BranchOrBacktrack(greater, on_greater);
}
-
-void RegExpMacroAssemblerIA32::CheckAtStart(Label* on_at_start) {
- __ lea(eax, Operand(edi, -char_size()));
+void RegExpMacroAssemblerIA32::CheckAtStart(int cp_offset, Label* on_at_start) {
+ __ lea(eax, Operand(edi, -char_size() + cp_offset * char_size()));
__ cmp(eax, Operand(ebp, kStringStartMinusOne));
BranchOrBacktrack(equal, on_at_start);
}
-
void RegExpMacroAssemblerIA32::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ lea(eax, Operand(edi, -char_size() + cp_offset * char_size()));
@@ -684,7 +686,7 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ mov(ecx, esp);
__ sub(ecx, StaticVariable(stack_limit));
// Handle it if the stack pointer is already below the stack limit.
@@ -971,15 +973,19 @@ RegExpMacroAssembler::IrregexpImplementation
return kIA32Implementation;
}
+void RegExpMacroAssemblerIA32::LoadCurrentCharacterImpl(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ // It's possible to preload a small number of characters when each success
+ // path requires a large number of characters, but not the reverse.
+ DCHECK_GE(eats_at_least, characters);
-void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
if (check_bounds) {
if (cp_offset >= 0) {
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ CheckPosition(cp_offset + eats_at_least - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
@@ -987,7 +993,6 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
-
void RegExpMacroAssemblerIA32::PopCurrentPosition() {
Pop(edi);
}
@@ -1120,7 +1125,8 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
frame_entry<int>(re_frame, kStartIndex),
- frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
+ static_cast<RegExp::CallOrigin>(frame_entry<int>(re_frame, kDirectCall)),
+ return_address, re_code,
frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
frame_entry_address<const byte*>(re_frame, kInputEnd));
@@ -1214,7 +1220,7 @@ void RegExpMacroAssemblerIA32::CheckPreemption() {
// Check for preemption.
Label no_preempt;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ cmp(esp, StaticVariable(stack_limit));
__ j(above, &no_preempt);
@@ -1227,7 +1233,7 @@ void RegExpMacroAssemblerIA32::CheckPreemption() {
void RegExpMacroAssemblerIA32::CheckStackLimit() {
Label no_stack_overflow;
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit(isolate());
+ ExternalReference::address_of_regexp_stack_limit_address(isolate());
__ cmp(backtrack_stackpointer(), StaticVariable(stack_limit));
__ j(above, &no_stack_overflow);
diff --git a/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h b/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h
index 914552cc93..3464d81fac 100644
--- a/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h
+++ b/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h
@@ -23,7 +23,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32
virtual void AdvanceRegister(int reg, int by);
virtual void Backtrack();
virtual void Bind(Label* label);
- virtual void CheckAtStart(Label* on_at_start);
+ virtual void CheckAtStart(int cp_offset, Label* on_at_start);
virtual void CheckCharacter(uint32_t c, Label* on_equal);
virtual void CheckCharacterAfterAnd(uint32_t c,
uint32_t mask,
@@ -66,10 +66,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32
virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
virtual void IfRegisterEqPos(int reg, Label* if_eq);
virtual IrregexpImplementation Implementation();
- virtual void LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1);
+ virtual void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least);
virtual void PopCurrentPosition();
virtual void PopRegister(int register_index);
virtual void PushBacktrack(Label* label);
diff --git a/deps/v8/src/regexp/mips/regexp-macro-assembler-mips.cc b/deps/v8/src/regexp/mips/regexp-macro-assembler-mips.cc
index e8104ced7e..8d2800f004 100644
--- a/deps/v8/src/regexp/mips/regexp-macro-assembler-mips.cc
+++ b/deps/v8/src/regexp/mips/regexp-macro-assembler-mips.cc
@@ -178,9 +178,10 @@ void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
}
-void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
+void RegExpMacroAssemblerMIPS::CheckAtStart(int cp_offset, Label* on_at_start) {
__ lw(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
- __ Addu(a0, current_input_offset(), Operand(-char_size()));
+ __ Addu(a0, current_input_offset(),
+ Operand(-char_size() + cp_offset * char_size()));
BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
}
@@ -647,7 +648,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(masm_->isolate());
+ ExternalReference::address_of_jslimit(masm_->isolate());
__ li(a0, Operand(stack_limit));
__ lw(a0, MemOperand(a0));
__ Subu(a0, sp, a0);
@@ -946,15 +947,19 @@ RegExpMacroAssembler::IrregexpImplementation
return kMIPSImplementation;
}
+void RegExpMacroAssemblerMIPS::LoadCurrentCharacterImpl(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ // It's possible to preload a small number of characters when each success
+ // path requires a large number of characters, but not the reverse.
+ DCHECK_GE(eats_at_least, characters);
-void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works).
if (check_bounds) {
if (cp_offset >= 0) {
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ CheckPosition(cp_offset + eats_at_least - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
@@ -962,7 +967,6 @@ void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
-
void RegExpMacroAssemblerMIPS::PopCurrentPosition() {
Pop(current_input_offset());
}
@@ -1176,7 +1180,8 @@ int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
frame_entry<int>(re_frame, kStartIndex),
- frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
+ static_cast<RegExp::CallOrigin>(frame_entry<int>(re_frame, kDirectCall)),
+ return_address, re_code,
frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
frame_entry_address<const byte*>(re_frame, kInputEnd));
@@ -1267,7 +1272,7 @@ void RegExpMacroAssemblerMIPS::Pop(Register target) {
void RegExpMacroAssemblerMIPS::CheckPreemption() {
// Check for preemption.
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(masm_->isolate());
+ ExternalReference::address_of_jslimit(masm_->isolate());
__ li(a0, Operand(stack_limit));
__ lw(a0, MemOperand(a0));
SafeCall(&check_preempt_label_, ls, sp, Operand(a0));
@@ -1276,7 +1281,8 @@ void RegExpMacroAssemblerMIPS::CheckPreemption() {
void RegExpMacroAssemblerMIPS::CheckStackLimit() {
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
+ ExternalReference::address_of_regexp_stack_limit_address(
+ masm_->isolate());
__ li(a0, Operand(stack_limit));
__ lw(a0, MemOperand(a0));
diff --git a/deps/v8/src/regexp/mips/regexp-macro-assembler-mips.h b/deps/v8/src/regexp/mips/regexp-macro-assembler-mips.h
index b785910466..084436bbbd 100644
--- a/deps/v8/src/regexp/mips/regexp-macro-assembler-mips.h
+++ b/deps/v8/src/regexp/mips/regexp-macro-assembler-mips.h
@@ -23,7 +23,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerMIPS
virtual void AdvanceRegister(int reg, int by);
virtual void Backtrack();
virtual void Bind(Label* label);
- virtual void CheckAtStart(Label* on_at_start);
+ virtual void CheckAtStart(int cp_offset, Label* on_at_start);
virtual void CheckCharacter(uint32_t c, Label* on_equal);
virtual void CheckCharacterAfterAnd(uint32_t c,
uint32_t mask,
@@ -67,10 +67,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerMIPS
virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
virtual void IfRegisterEqPos(int reg, Label* if_eq);
virtual IrregexpImplementation Implementation();
- virtual void LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1);
+ virtual void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least);
virtual void PopCurrentPosition();
virtual void PopRegister(int register_index);
virtual void PushBacktrack(Label* label);
diff --git a/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.cc b/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.cc
index 239cc87ae8..2d5402ebdb 100644
--- a/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.cc
+++ b/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.cc
@@ -214,9 +214,10 @@ void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
}
-void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
+void RegExpMacroAssemblerMIPS::CheckAtStart(int cp_offset, Label* on_at_start) {
__ Ld(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
- __ Daddu(a0, current_input_offset(), Operand(-char_size()));
+ __ Daddu(a0, current_input_offset(),
+ Operand(-char_size() + cp_offset * char_size()));
BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
}
@@ -683,7 +684,7 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(masm_->isolate());
+ ExternalReference::address_of_jslimit(masm_->isolate());
__ li(a0, Operand(stack_limit));
__ Ld(a0, MemOperand(a0));
__ Dsubu(a0, sp, a0);
@@ -983,15 +984,19 @@ RegExpMacroAssembler::IrregexpImplementation
return kMIPSImplementation;
}
+void RegExpMacroAssemblerMIPS::LoadCurrentCharacterImpl(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ // It's possible to preload a small number of characters when each success
+ // path requires a large number of characters, but not the reverse.
+ DCHECK_GE(eats_at_least, characters);
-void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works).
if (check_bounds) {
if (cp_offset >= 0) {
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ CheckPosition(cp_offset + eats_at_least - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
@@ -999,7 +1004,6 @@ void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
-
void RegExpMacroAssemblerMIPS::PopCurrentPosition() {
Pop(current_input_offset());
}
@@ -1213,7 +1217,9 @@ int64_t RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
static_cast<int>(frame_entry<int64_t>(re_frame, kStartIndex)),
- frame_entry<int64_t>(re_frame, kDirectCall) == 1, return_address, re_code,
+ static_cast<RegExp::CallOrigin>(
+ frame_entry<int64_t>(re_frame, kDirectCall)),
+ return_address, re_code,
frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
frame_entry_address<const byte*>(re_frame, kInputEnd));
@@ -1304,7 +1310,7 @@ void RegExpMacroAssemblerMIPS::Pop(Register target) {
void RegExpMacroAssemblerMIPS::CheckPreemption() {
// Check for preemption.
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(masm_->isolate());
+ ExternalReference::address_of_jslimit(masm_->isolate());
__ li(a0, Operand(stack_limit));
__ Ld(a0, MemOperand(a0));
SafeCall(&check_preempt_label_, ls, sp, Operand(a0));
@@ -1313,7 +1319,8 @@ void RegExpMacroAssemblerMIPS::CheckPreemption() {
void RegExpMacroAssemblerMIPS::CheckStackLimit() {
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
+ ExternalReference::address_of_regexp_stack_limit_address(
+ masm_->isolate());
__ li(a0, Operand(stack_limit));
__ Ld(a0, MemOperand(a0));
diff --git a/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.h b/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.h
index d24735d08e..9189a6a72d 100644
--- a/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.h
+++ b/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.h
@@ -23,7 +23,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerMIPS
virtual void AdvanceRegister(int reg, int by);
virtual void Backtrack();
virtual void Bind(Label* label);
- virtual void CheckAtStart(Label* on_at_start);
+ virtual void CheckAtStart(int cp_offset, Label* on_at_start);
virtual void CheckCharacter(uint32_t c, Label* on_equal);
virtual void CheckCharacterAfterAnd(uint32_t c,
uint32_t mask,
@@ -67,10 +67,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerMIPS
virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
virtual void IfRegisterEqPos(int reg, Label* if_eq);
virtual IrregexpImplementation Implementation();
- virtual void LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1);
+ virtual void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least);
virtual void PopCurrentPosition();
virtual void PopRegister(int register_index);
virtual void PushBacktrack(Label* label);
diff --git a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc
index bce612e66f..13b5c85605 100644
--- a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc
+++ b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc
@@ -189,15 +189,14 @@ void RegExpMacroAssemblerPPC::CheckCharacterGT(uc16 limit, Label* on_greater) {
BranchOrBacktrack(gt, on_greater);
}
-
-void RegExpMacroAssemblerPPC::CheckAtStart(Label* on_at_start) {
+void RegExpMacroAssemblerPPC::CheckAtStart(int cp_offset, Label* on_at_start) {
__ LoadP(r4, MemOperand(frame_pointer(), kStringStartMinusOne));
- __ addi(r3, current_input_offset(), Operand(-char_size()));
+ __ addi(r3, current_input_offset(),
+ Operand(-char_size() + cp_offset * char_size()));
__ cmp(r3, r4);
BranchOrBacktrack(eq, on_at_start);
}
-
void RegExpMacroAssemblerPPC::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ LoadP(r4, MemOperand(frame_pointer(), kStringStartMinusOne));
@@ -689,7 +688,7 @@ Handle<HeapObject> RegExpMacroAssemblerPPC::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ mov(r3, Operand(stack_limit));
__ LoadP(r3, MemOperand(r3));
__ sub(r3, sp, r3, LeaveOE, SetRC);
@@ -978,15 +977,19 @@ RegExpMacroAssemblerPPC::Implementation() {
return kPPCImplementation;
}
+void RegExpMacroAssemblerPPC::LoadCurrentCharacterImpl(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ // It's possible to preload a small number of characters when each success
+ // path requires a large number of characters, but not the reverse.
+ DCHECK_GE(eats_at_least, characters);
-void RegExpMacroAssemblerPPC::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
DCHECK(cp_offset < (1 << 30)); // Be sane! (And ensure negation works)
if (check_bounds) {
if (cp_offset >= 0) {
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ CheckPosition(cp_offset + eats_at_least - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
@@ -994,7 +997,6 @@ void RegExpMacroAssemblerPPC::LoadCurrentCharacter(int cp_offset,
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
-
void RegExpMacroAssemblerPPC::PopCurrentPosition() {
Pop(current_input_offset());
}
@@ -1177,8 +1179,10 @@ int RegExpMacroAssemblerPPC::CheckStackGuardState(Address* return_address,
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
frame_entry<intptr_t>(re_frame, kStartIndex),
- frame_entry<intptr_t>(re_frame, kDirectCall) == 1, return_address,
- re_code, frame_entry_address<Address>(re_frame, kInputString),
+ static_cast<RegExp::CallOrigin>(
+ frame_entry<intptr_t>(re_frame, kDirectCall)),
+ return_address, re_code,
+ frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
frame_entry_address<const byte*>(re_frame, kInputEnd));
}
@@ -1267,7 +1271,7 @@ void RegExpMacroAssemblerPPC::Pop(Register target) {
void RegExpMacroAssemblerPPC::CheckPreemption() {
// Check for preemption.
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ mov(r3, Operand(stack_limit));
__ LoadP(r3, MemOperand(r3));
__ cmpl(sp, r3);
@@ -1277,7 +1281,7 @@ void RegExpMacroAssemblerPPC::CheckPreemption() {
void RegExpMacroAssemblerPPC::CheckStackLimit() {
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit(isolate());
+ ExternalReference::address_of_regexp_stack_limit_address(isolate());
__ mov(r3, Operand(stack_limit));
__ LoadP(r3, MemOperand(r3));
__ cmpl(backtrack_stackpointer(), r3);
diff --git a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.h b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.h
index 418a01a9a4..60236a4000 100644
--- a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.h
+++ b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.h
@@ -23,7 +23,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerPPC
virtual void AdvanceRegister(int reg, int by);
virtual void Backtrack();
virtual void Bind(Label* label);
- virtual void CheckAtStart(Label* on_at_start);
+ virtual void CheckAtStart(int cp_offset, Label* on_at_start);
virtual void CheckCharacter(unsigned c, Label* on_equal);
virtual void CheckCharacterAfterAnd(unsigned c, unsigned mask,
Label* on_equal);
@@ -59,9 +59,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerPPC
virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
virtual void IfRegisterEqPos(int reg, Label* if_eq);
virtual IrregexpImplementation Implementation();
- virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1);
+ virtual void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least);
virtual void PopCurrentPosition();
virtual void PopRegister(int register_index);
virtual void PushBacktrack(Label* label);
diff --git a/deps/v8/src/regexp/regexp-bytecode-generator.cc b/deps/v8/src/regexp/regexp-bytecode-generator.cc
index ee3b4015d5..85b144438e 100644
--- a/deps/v8/src/regexp/regexp-bytecode-generator.cc
+++ b/deps/v8/src/regexp/regexp-bytecode-generator.cc
@@ -171,10 +171,19 @@ void RegExpBytecodeGenerator::CheckGreedyLoop(
EmitOrLink(on_tos_equals_current_position);
}
-void RegExpBytecodeGenerator::LoadCurrentCharacter(int cp_offset,
- Label* on_failure,
- bool check_bounds,
- int characters) {
+void RegExpBytecodeGenerator::LoadCurrentCharacterImpl(int cp_offset,
+ Label* on_failure,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ DCHECK_GE(eats_at_least, characters);
+ if (eats_at_least > characters && check_bounds) {
+ DCHECK(is_uint24(cp_offset + eats_at_least));
+ Emit(BC_CHECK_CURRENT_POSITION, cp_offset + eats_at_least);
+ EmitOrLink(on_failure);
+ check_bounds = false; // Load below doesn't need to check.
+ }
+
DCHECK_LE(kMinCPOffset, cp_offset);
DCHECK_GE(kMaxCPOffset, cp_offset);
int bytecode;
@@ -221,8 +230,8 @@ void RegExpBytecodeGenerator::CheckCharacter(uint32_t c, Label* on_equal) {
EmitOrLink(on_equal);
}
-void RegExpBytecodeGenerator::CheckAtStart(Label* on_at_start) {
- Emit(BC_CHECK_AT_START, 0);
+void RegExpBytecodeGenerator::CheckAtStart(int cp_offset, Label* on_at_start) {
+ Emit(BC_CHECK_AT_START, cp_offset);
EmitOrLink(on_at_start);
}
diff --git a/deps/v8/src/regexp/regexp-bytecode-generator.h b/deps/v8/src/regexp/regexp-bytecode-generator.h
index b7207e977c..84b7ce361c 100644
--- a/deps/v8/src/regexp/regexp-bytecode-generator.h
+++ b/deps/v8/src/regexp/regexp-bytecode-generator.h
@@ -46,16 +46,16 @@ class V8_EXPORT_PRIVATE RegExpBytecodeGenerator : public RegExpMacroAssembler {
virtual void ReadCurrentPositionFromRegister(int reg);
virtual void WriteStackPointerToRegister(int reg);
virtual void ReadStackPointerFromRegister(int reg);
- virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1);
+ virtual void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least);
virtual void CheckCharacter(unsigned c, Label* on_equal);
virtual void CheckCharacterAfterAnd(unsigned c, unsigned mask,
Label* on_equal);
virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
virtual void CheckCharacterLT(uc16 limit, Label* on_less);
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
- virtual void CheckAtStart(Label* on_at_start);
+ virtual void CheckAtStart(int cp_offset, Label* on_at_start);
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
virtual void CheckNotCharacter(unsigned c, Label* on_not_equal);
virtual void CheckNotCharacterAfterAnd(unsigned c, unsigned mask,
diff --git a/deps/v8/src/regexp/regexp-bytecodes.h b/deps/v8/src/regexp/regexp-bytecodes.h
index 8b1468c1bf..3dd7637b88 100644
--- a/deps/v8/src/regexp/regexp-bytecodes.h
+++ b/deps/v8/src/regexp/regexp-bytecodes.h
@@ -5,6 +5,8 @@
#ifndef V8_REGEXP_REGEXP_BYTECODES_H_
#define V8_REGEXP_REGEXP_BYTECODES_H_
+#include "src/base/macros.h"
+
namespace v8 {
namespace internal {
@@ -67,16 +69,43 @@ const int BYTECODE_SHIFT = 8;
V(CHECK_NOT_AT_START, 48, 8) /* bc8 offset24 addr32 */ \
V(CHECK_GREEDY, 49, 8) /* bc8 pad24 addr32 */ \
V(ADVANCE_CP_AND_GOTO, 50, 8) /* bc8 offset24 addr32 */ \
- V(SET_CURRENT_POSITION_FROM_END, 51, 4) /* bc8 idx24 */
+ V(SET_CURRENT_POSITION_FROM_END, 51, 4) /* bc8 idx24 */ \
+ V(CHECK_CURRENT_POSITION, 52, 8) /* bc8 idx24 addr32 */
+
+#define COUNT(...) +1
+static constexpr int kRegExpBytecodeCount = BYTECODE_ITERATOR(COUNT);
+#undef COUNT
+
+// Just making sure we assigned values above properly. They should be
+// contiguous, strictly increasing, and start at 0.
+// TODO(jgruber): Do not explicitly assign values, instead generate them
+// implicitly from the list order.
+STATIC_ASSERT(kRegExpBytecodeCount == 53);
-#define DECLARE_BYTECODES(name, code, length) static const int BC_##name = code;
+#define DECLARE_BYTECODES(name, code, length) \
+ static constexpr int BC_##name = code;
BYTECODE_ITERATOR(DECLARE_BYTECODES)
#undef DECLARE_BYTECODES
-#define DECLARE_BYTECODE_LENGTH(name, code, length) \
- static const int BC_##name##_LENGTH = length;
-BYTECODE_ITERATOR(DECLARE_BYTECODE_LENGTH)
+static constexpr int kRegExpBytecodeLengths[] = {
+#define DECLARE_BYTECODE_LENGTH(name, code, length) length,
+ BYTECODE_ITERATOR(DECLARE_BYTECODE_LENGTH)
#undef DECLARE_BYTECODE_LENGTH
+};
+
+inline constexpr int RegExpBytecodeLength(int bytecode) {
+ return kRegExpBytecodeLengths[bytecode];
+}
+
+static const char* const kRegExpBytecodeNames[] = {
+#define DECLARE_BYTECODE_NAME(name, ...) #name,
+ BYTECODE_ITERATOR(DECLARE_BYTECODE_NAME)
+#undef DECLARE_BYTECODE_NAME
+};
+
+inline const char* RegExpBytecodeName(int bytecode) {
+ return kRegExpBytecodeNames[bytecode];
+}
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/regexp/regexp-compiler-tonode.cc b/deps/v8/src/regexp/regexp-compiler-tonode.cc
index d12c35682e..2d86d3ea9e 100644
--- a/deps/v8/src/regexp/regexp-compiler-tonode.cc
+++ b/deps/v8/src/regexp/regexp-compiler-tonode.cc
@@ -1627,8 +1627,8 @@ RegExpNode* RegExpQuantifier::ToNode(int min, int max, bool is_greedy,
bool needs_counter = has_min || has_max;
int reg_ctr = needs_counter ? compiler->AllocateRegister()
: RegExpCompiler::kNoRegister;
- LoopChoiceNode* center = new (zone)
- LoopChoiceNode(body->min_match() == 0, compiler->read_backward(), zone);
+ LoopChoiceNode* center = new (zone) LoopChoiceNode(
+ body->min_match() == 0, compiler->read_backward(), min, zone);
if (not_at_start && !compiler->read_backward()) center->set_not_at_start();
RegExpNode* loop_return =
needs_counter ? static_cast<RegExpNode*>(
@@ -1668,7 +1668,7 @@ RegExpNode* RegExpQuantifier::ToNode(int min, int max, bool is_greedy,
center->AddLoopAlternative(body_alt);
}
if (needs_counter) {
- return ActionNode::SetRegister(reg_ctr, 0, center);
+ return ActionNode::SetRegisterForLoop(reg_ctr, 0, center);
} else {
return center;
}
diff --git a/deps/v8/src/regexp/regexp-compiler.cc b/deps/v8/src/regexp/regexp-compiler.cc
index c70bbc3e4a..85da69f308 100644
--- a/deps/v8/src/regexp/regexp-compiler.cc
+++ b/deps/v8/src/regexp/regexp-compiler.cc
@@ -4,13 +4,12 @@
#include "src/regexp/regexp-compiler.h"
-#include "src/diagnostics/code-tracer.h"
+#include "src/base/safe_conversions.h"
#include "src/execution/isolate.h"
#include "src/objects/objects-inl.h"
#include "src/regexp/regexp-macro-assembler-arch.h"
#include "src/regexp/regexp-macro-assembler-tracer.h"
#include "src/strings/unicode-inl.h"
-#include "src/utils/ostreams.h"
#include "src/zone/zone-list-inl.h"
#ifdef V8_INTL_SUPPORT
@@ -272,13 +271,7 @@ RegExpCompiler::CompilationResult RegExpCompiler::Assemble(
Handle<HeapObject> code = macro_assembler_->GetCode(pattern);
isolate->IncreaseTotalRegexpCodeGenerated(code->Size());
work_list_ = nullptr;
-#ifdef ENABLE_DISASSEMBLER
- if (FLAG_print_code && !FLAG_regexp_interpret_all) {
- CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
- OFStream os(trace_scope.file());
- Handle<Code>::cast(code)->Disassemble(pattern->ToCString().get(), os);
- }
-#endif
+
#ifdef DEBUG
if (FLAG_trace_regexp_assembler) {
delete macro_assembler_;
@@ -422,14 +415,14 @@ void Trace::PerformDeferredActions(RegExpMacroAssembler* assembler,
action = action->next()) {
if (action->Mentions(reg)) {
switch (action->action_type()) {
- case ActionNode::SET_REGISTER: {
- Trace::DeferredSetRegister* psr =
- static_cast<Trace::DeferredSetRegister*>(action);
+ case ActionNode::SET_REGISTER_FOR_LOOP: {
+ Trace::DeferredSetRegisterForLoop* psr =
+ static_cast<Trace::DeferredSetRegisterForLoop*>(action);
if (!absolute) {
value += psr->value();
absolute = true;
}
- // SET_REGISTER is currently only used for newly introduced loop
+ // SET_REGISTER_FOR_LOOP is only used for newly introduced loop
// counters. They can have a significant previous value if they
// occur in a loop. TODO(lrn): Propagate this information, so
// we can set undo_action to IGNORE if we know there is no value to
@@ -634,9 +627,10 @@ void GuardedAlternative::AddGuard(Guard* guard, Zone* zone) {
guards_->Add(guard, zone);
}
-ActionNode* ActionNode::SetRegister(int reg, int val, RegExpNode* on_success) {
+ActionNode* ActionNode::SetRegisterForLoop(int reg, int val,
+ RegExpNode* on_success) {
ActionNode* result =
- new (on_success->zone()) ActionNode(SET_REGISTER, on_success);
+ new (on_success->zone()) ActionNode(SET_REGISTER_FOR_LOOP, on_success);
result->data_.u_store_register.reg = reg;
result->data_.u_store_register.value = val;
return result;
@@ -705,10 +699,6 @@ ActionNode* ActionNode::EmptyMatchCheck(int start_register,
FOR_EACH_NODE_TYPE(DEFINE_ACCEPT)
#undef DEFINE_ACCEPT
-void LoopChoiceNode::Accept(NodeVisitor* visitor) {
- visitor->VisitLoopChoice(this);
-}
-
// -------------------------------------------------------------------
// Emit code.
@@ -1326,12 +1316,6 @@ bool RegExpNode::KeepRecursing(RegExpCompiler* compiler) {
compiler->recursion_depth() <= RegExpCompiler::kMaxRecursion;
}
-int ActionNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start) {
- if (budget <= 0) return 0;
- if (action_type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input!
- return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
-}
-
void ActionNode::FillInBMInfo(Isolate* isolate, int offset, int budget,
BoyerMooreLookahead* bm, bool not_at_start) {
if (action_type_ == POSITIVE_SUBMATCH_SUCCESS) {
@@ -1344,16 +1328,16 @@ void ActionNode::FillInBMInfo(Isolate* isolate, int offset, int budget,
SaveBMInfo(bm, not_at_start, offset);
}
-int AssertionNode::EatsAtLeast(int still_to_find, int budget,
- bool not_at_start) {
- if (budget <= 0) return 0;
- // If we know we are not at the start and we are asked "how many characters
- // will you match if you succeed?" then we can answer anything since false
- // implies false. So lets just return the max answer (still_to_find) since
- // that won't prevent us from preloading a lot of characters for the other
- // branches in the node graph.
- if (assertion_type() == AT_START && not_at_start) return still_to_find;
- return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
+void ActionNode::GetQuickCheckDetails(QuickCheckDetails* details,
+ RegExpCompiler* compiler, int filled_in,
+ bool not_at_start) {
+ if (action_type_ == SET_REGISTER_FOR_LOOP) {
+ on_success()->GetQuickCheckDetailsFromLoopEntry(details, compiler,
+ filled_in, not_at_start);
+ } else {
+ on_success()->GetQuickCheckDetails(details, compiler, filled_in,
+ not_at_start);
+ }
}
void AssertionNode::FillInBMInfo(Isolate* isolate, int offset, int budget,
@@ -1364,68 +1348,13 @@ void AssertionNode::FillInBMInfo(Isolate* isolate, int offset, int budget,
SaveBMInfo(bm, not_at_start, offset);
}
-int BackReferenceNode::EatsAtLeast(int still_to_find, int budget,
- bool not_at_start) {
- if (read_backward()) return 0;
- if (budget <= 0) return 0;
- return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
-}
-
-int TextNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start) {
- if (read_backward()) return 0;
- int answer = Length();
- if (answer >= still_to_find) return answer;
- if (budget <= 0) return answer;
- // We are not at start after this node so we set the last argument to 'true'.
- return answer +
- on_success()->EatsAtLeast(still_to_find - answer, budget - 1, true);
-}
-
-int NegativeLookaroundChoiceNode::EatsAtLeast(int still_to_find, int budget,
- bool not_at_start) {
- if (budget <= 0) return 0;
- // Alternative 0 is the negative lookahead, alternative 1 is what comes
- // afterwards.
- RegExpNode* node = alternatives_->at(1).node();
- return node->EatsAtLeast(still_to_find, budget - 1, not_at_start);
-}
-
void NegativeLookaroundChoiceNode::GetQuickCheckDetails(
QuickCheckDetails* details, RegExpCompiler* compiler, int filled_in,
bool not_at_start) {
- // Alternative 0 is the negative lookahead, alternative 1 is what comes
- // afterwards.
- RegExpNode* node = alternatives_->at(1).node();
+ RegExpNode* node = continue_node();
return node->GetQuickCheckDetails(details, compiler, filled_in, not_at_start);
}
-int ChoiceNode::EatsAtLeastHelper(int still_to_find, int budget,
- RegExpNode* ignore_this_node,
- bool not_at_start) {
- if (budget <= 0) return 0;
- int min = 100;
- int choice_count = alternatives_->length();
- budget = (budget - 1) / choice_count;
- for (int i = 0; i < choice_count; i++) {
- RegExpNode* node = alternatives_->at(i).node();
- if (node == ignore_this_node) continue;
- int node_eats_at_least =
- node->EatsAtLeast(still_to_find, budget, not_at_start);
- if (node_eats_at_least < min) min = node_eats_at_least;
- if (min == 0) return 0;
- }
- return min;
-}
-
-int LoopChoiceNode::EatsAtLeast(int still_to_find, int budget,
- bool not_at_start) {
- return EatsAtLeastHelper(still_to_find, budget - 1, loop_node_, not_at_start);
-}
-
-int ChoiceNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start) {
- return EatsAtLeastHelper(still_to_find, budget, nullptr, not_at_start);
-}
-
// Takes the left-most 1-bit and smears it out, setting all bits to its right.
static inline uint32_t SmearBitsRight(uint32_t v) {
v |= v >> 1;
@@ -1459,12 +1388,78 @@ bool QuickCheckDetails::Rationalize(bool asc) {
return found_useful_op;
}
+int RegExpNode::EatsAtLeast(bool not_at_start) {
+ return not_at_start ? eats_at_least_.eats_at_least_from_not_start
+ : eats_at_least_.eats_at_least_from_possibly_start;
+}
+
+EatsAtLeastInfo RegExpNode::EatsAtLeastFromLoopEntry() {
+ // SET_REGISTER_FOR_LOOP is only used to initialize loop counters, and it
+ // implies that the following node must be a LoopChoiceNode. If we need to
+ // set registers to constant values for other reasons, we could introduce a
+ // new action type SET_REGISTER that doesn't imply anything about its
+ // successor.
+ UNREACHABLE();
+}
+
+void RegExpNode::GetQuickCheckDetailsFromLoopEntry(QuickCheckDetails* details,
+ RegExpCompiler* compiler,
+ int characters_filled_in,
+ bool not_at_start) {
+ // See comment in RegExpNode::EatsAtLeastFromLoopEntry.
+ UNREACHABLE();
+}
+
+EatsAtLeastInfo LoopChoiceNode::EatsAtLeastFromLoopEntry() {
+ DCHECK_EQ(alternatives_->length(), 2); // There's just loop and continue.
+
+ if (read_backward()) {
+ // Can't do anything special for a backward loop, so return the basic values
+ // that we got during analysis.
+ return *eats_at_least_info();
+ }
+
+ // Figure out how much the loop body itself eats, not including anything in
+ // the continuation case. In general, the nodes in the loop body should report
+ // that they eat at least the number eaten by the continuation node, since any
+ // successful match in the loop body must also include the continuation node.
+ // However, in some cases involving positive lookaround, the loop body under-
+ // reports its appetite, so use saturated math here to avoid negative numbers.
+ uint8_t loop_body_from_not_start = base::saturated_cast<uint8_t>(
+ loop_node_->EatsAtLeast(true) - continue_node_->EatsAtLeast(true));
+ uint8_t loop_body_from_possibly_start = base::saturated_cast<uint8_t>(
+ loop_node_->EatsAtLeast(false) - continue_node_->EatsAtLeast(true));
+
+ // Limit the number of loop iterations to avoid overflow in subsequent steps.
+ int loop_iterations = base::saturated_cast<uint8_t>(min_loop_iterations());
+
+ EatsAtLeastInfo result;
+ result.eats_at_least_from_not_start =
+ base::saturated_cast<uint8_t>(loop_iterations * loop_body_from_not_start +
+ continue_node_->EatsAtLeast(true));
+ if (loop_iterations > 0 && loop_body_from_possibly_start > 0) {
+ // First loop iteration eats at least one, so all subsequent iterations
+ // and the after-loop chunk are guaranteed to not be at the start.
+ result.eats_at_least_from_possibly_start = base::saturated_cast<uint8_t>(
+ loop_body_from_possibly_start +
+ (loop_iterations - 1) * loop_body_from_not_start +
+ continue_node_->EatsAtLeast(true));
+ } else {
+ // Loop body might eat nothing, so only continue node contributes.
+ result.eats_at_least_from_possibly_start =
+ continue_node_->EatsAtLeast(false);
+ }
+ return result;
+}
+
bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler,
Trace* bounds_check_trace, Trace* trace,
bool preload_has_checked_bounds,
Label* on_possible_success,
QuickCheckDetails* details,
- bool fall_through_on_failure) {
+ bool fall_through_on_failure,
+ ChoiceNode* predecessor) {
+ DCHECK_NOT_NULL(predecessor);
if (details->characters() == 0) return false;
GetQuickCheckDetails(details, compiler, 0,
trace->at_start() == Trace::FALSE_VALUE);
@@ -1479,13 +1474,17 @@ bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler,
if (trace->characters_preloaded() != details->characters()) {
DCHECK(trace->cp_offset() == bounds_check_trace->cp_offset());
- // We are attempting to preload the minimum number of characters
+ // The bounds check is performed using the minimum number of characters
// any choice would eat, so if the bounds check fails, then none of the
// choices can succeed, so we can just immediately backtrack, rather
- // than go to the next choice.
+ // than go to the next choice. The number of characters preloaded may be
+ // less than the number used for the bounds check.
+ int eats_at_least = predecessor->EatsAtLeast(
+ bounds_check_trace->at_start() == Trace::FALSE_VALUE);
+ DCHECK_GE(eats_at_least, details->characters());
assembler->LoadCurrentCharacter(
trace->cp_offset(), bounds_check_trace->backtrack(),
- !preload_has_checked_bounds, details->characters());
+ !preload_has_checked_bounds, details->characters(), eats_at_least);
}
bool need_mask = true;
@@ -1579,7 +1578,7 @@ void TextNode::GetQuickCheckDetails(QuickCheckDetails* details,
// and the mask-compare will determine definitely whether we have
// a match at this character position.
pos->mask = char_mask;
- pos->value = c;
+ pos->value = chars[0];
pos->determines_perfectly = true;
} else {
uint32_t common_bits = char_mask;
@@ -1764,6 +1763,37 @@ class VisitMarker {
NodeInfo* info_;
};
+// Temporarily sets traversed_loop_initialization_node_.
+class LoopInitializationMarker {
+ public:
+ explicit LoopInitializationMarker(LoopChoiceNode* node) : node_(node) {
+ DCHECK(!node_->traversed_loop_initialization_node_);
+ node_->traversed_loop_initialization_node_ = true;
+ }
+ ~LoopInitializationMarker() {
+ DCHECK(node_->traversed_loop_initialization_node_);
+ node_->traversed_loop_initialization_node_ = false;
+ }
+
+ private:
+ LoopChoiceNode* node_;
+ DISALLOW_COPY_AND_ASSIGN(LoopInitializationMarker);
+};
+
+// Temporarily decrements min_loop_iterations_.
+class IterationDecrementer {
+ public:
+ explicit IterationDecrementer(LoopChoiceNode* node) : node_(node) {
+ DCHECK_GT(node_->min_loop_iterations_, 0);
+ --node_->min_loop_iterations_;
+ }
+ ~IterationDecrementer() { ++node_->min_loop_iterations_; }
+
+ private:
+ LoopChoiceNode* node_;
+ DISALLOW_COPY_AND_ASSIGN(IterationDecrementer);
+};
+
RegExpNode* SeqRegExpNode::FilterOneByte(int depth) {
if (info()->replacement_calculated) return replacement();
if (depth < 0) return this;
@@ -1916,17 +1946,17 @@ RegExpNode* NegativeLookaroundChoiceNode::FilterOneByte(int depth) {
VisitMarker marker(info());
// Alternative 0 is the negative lookahead, alternative 1 is what comes
// afterwards.
- RegExpNode* node = alternatives_->at(1).node();
+ RegExpNode* node = continue_node();
RegExpNode* replacement = node->FilterOneByte(depth - 1);
if (replacement == nullptr) return set_replacement(nullptr);
- alternatives_->at(1).set_node(replacement);
+ alternatives_->at(kContinueIndex).set_node(replacement);
- RegExpNode* neg_node = alternatives_->at(0).node();
+ RegExpNode* neg_node = lookaround_node();
RegExpNode* neg_replacement = neg_node->FilterOneByte(depth - 1);
// If the negative lookahead is always going to fail then
// we don't need to check it.
if (neg_replacement == nullptr) return set_replacement(replacement);
- alternatives_->at(0).set_node(neg_replacement);
+ alternatives_->at(kLookaroundIndex).set_node(neg_replacement);
return set_replacement(this);
}
@@ -1935,9 +1965,48 @@ void LoopChoiceNode::GetQuickCheckDetails(QuickCheckDetails* details,
int characters_filled_in,
bool not_at_start) {
if (body_can_be_zero_length_ || info()->visited) return;
- VisitMarker marker(info());
- return ChoiceNode::GetQuickCheckDetails(details, compiler,
- characters_filled_in, not_at_start);
+ not_at_start = not_at_start || this->not_at_start();
+ DCHECK_EQ(alternatives_->length(), 2); // There's just loop and continue.
+ if (traversed_loop_initialization_node_ && min_loop_iterations_ > 0 &&
+ loop_node_->EatsAtLeast(not_at_start) >
+ continue_node_->EatsAtLeast(true)) {
+ // Loop body is guaranteed to execute at least once, and consume characters
+ // when it does, meaning the only possible quick checks from this point
+ // begin with the loop body. We may recursively visit this LoopChoiceNode,
+ // but we temporarily decrease its minimum iteration counter so we know when
+ // to check the continue case.
+ IterationDecrementer next_iteration(this);
+ loop_node_->GetQuickCheckDetails(details, compiler, characters_filled_in,
+ not_at_start);
+ } else {
+ // Might not consume anything in the loop body, so treat it like a normal
+ // ChoiceNode (and don't recursively visit this node again).
+ VisitMarker marker(info());
+ ChoiceNode::GetQuickCheckDetails(details, compiler, characters_filled_in,
+ not_at_start);
+ }
+}
+
+void LoopChoiceNode::GetQuickCheckDetailsFromLoopEntry(
+ QuickCheckDetails* details, RegExpCompiler* compiler,
+ int characters_filled_in, bool not_at_start) {
+ if (traversed_loop_initialization_node_) {
+ // We already entered this loop once, exited via its continuation node, and
+ // followed an outer loop's back-edge to before the loop entry point. We
+ // could try to reset the minimum iteration count to its starting value at
+ // this point, but that seems like more trouble than it's worth. It's safe
+ // to keep going with the current (possibly reduced) minimum iteration
+ // count.
+ GetQuickCheckDetails(details, compiler, characters_filled_in, not_at_start);
+ } else {
+ // We are entering a loop via its counter initialization action, meaning we
+ // are guaranteed to run the loop body at least some minimum number of times
+ // before running the continuation node. Set a flag so that this node knows
+ // (now and any times we visit it again recursively) that it was entered
+ // from the top.
+ LoopInitializationMarker marker(this);
+ GetQuickCheckDetails(details, compiler, characters_filled_in, not_at_start);
+ }
}
void LoopChoiceNode::FillInBMInfo(Isolate* isolate, int offset, int budget,
@@ -2014,12 +2083,7 @@ void EmitHat(RegExpCompiler* compiler, RegExpNode* on_success, Trace* trace) {
if (may_be_at_or_before_subject_string_start) {
// The start of input counts as a newline in this context, so skip to ok if
// we are at the start.
- // TODO(jgruber): It would be less awkward to use CheckAtStart here, but
- // that currently does not support a non-zero cp_offset.
- Label not_at_start;
- assembler->CheckNotAtStart(new_trace.cp_offset(), &not_at_start);
- assembler->GoTo(&ok);
- assembler->Bind(&not_at_start);
+ assembler->CheckAtStart(new_trace.cp_offset(), &ok);
}
// If we've already checked that we are not at the start of input, it's okay
@@ -2049,9 +2113,8 @@ void AssertionNode::EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace) {
bool not_at_start = (trace->at_start() == Trace::FALSE_VALUE);
BoyerMooreLookahead* lookahead = bm_info(not_at_start);
if (lookahead == nullptr) {
- int eats_at_least = Min(kMaxLookaheadForBoyerMoore,
- EatsAtLeast(kMaxLookaheadForBoyerMoore,
- kRecursionBudget, not_at_start));
+ int eats_at_least =
+ Min(kMaxLookaheadForBoyerMoore, EatsAtLeast(not_at_start));
if (eats_at_least >= 1) {
BoyerMooreLookahead* bm =
new (zone()) BoyerMooreLookahead(eats_at_least, compiler, zone());
@@ -2113,12 +2176,7 @@ void AssertionNode::BacktrackIfPrevious(
if (may_be_at_or_before_subject_string_start) {
// The start of input counts as a non-word character, so the question is
// decided if we are at the start.
- // TODO(jgruber): It would be less awkward to use CheckAtStart here, but
- // that currently does not support a non-zero cp_offset.
- Label not_at_start;
- assembler->CheckNotAtStart(new_trace.cp_offset(), &not_at_start);
- assembler->GoTo(non_word);
- assembler->Bind(&not_at_start);
+ assembler->CheckAtStart(new_trace.cp_offset(), non_word);
}
// If we've already checked that we are not at the start of input, it's okay
@@ -2939,8 +2997,7 @@ void ChoiceNode::SetUpPreLoad(RegExpCompiler* compiler, Trace* current_trace,
if (state->eats_at_least_ == PreloadState::kEatsAtLeastNotYetInitialized) {
// Save some time by looking at most one machine word ahead.
state->eats_at_least_ =
- EatsAtLeast(compiler->one_byte() ? 4 : 2, kRecursionBudget,
- current_trace->at_start() == Trace::FALSE_VALUE);
+ EatsAtLeast(current_trace->at_start() == Trace::FALSE_VALUE);
}
state->preload_characters_ =
CalculatePreloadCharacters(compiler, state->eats_at_least_);
@@ -3090,9 +3147,7 @@ int ChoiceNode::EmitOptimizedUnanchoredSearch(RegExpCompiler* compiler,
// small alternation.
BoyerMooreLookahead* bm = bm_info(false);
if (bm == nullptr) {
- eats_at_least =
- Min(kMaxLookaheadForBoyerMoore,
- EatsAtLeast(kMaxLookaheadForBoyerMoore, kRecursionBudget, false));
+ eats_at_least = Min(kMaxLookaheadForBoyerMoore, EatsAtLeast(false));
if (eats_at_least >= 1) {
bm = new (zone()) BoyerMooreLookahead(eats_at_least, compiler, zone());
GuardedAlternative alt0 = alternatives_->at(0);
@@ -3144,7 +3199,7 @@ void ChoiceNode::EmitChoices(RegExpCompiler* compiler,
alternative.node()->EmitQuickCheck(
compiler, trace, &new_trace, preload->preload_has_checked_bounds_,
&alt_gen->possible_success, &alt_gen->quick_check_details,
- fall_through_on_failure)) {
+ fall_through_on_failure, this)) {
// Quick check was generated for this choice.
preload->preload_is_current_ = true;
preload->preload_has_checked_bounds_ = true;
@@ -3253,9 +3308,9 @@ void ActionNode::Emit(RegExpCompiler* compiler, Trace* trace) {
on_success()->Emit(compiler, &new_trace);
break;
}
- case SET_REGISTER: {
- Trace::DeferredSetRegister new_set(data_.u_store_register.reg,
- data_.u_store_register.value);
+ case SET_REGISTER_FOR_LOOP: {
+ Trace::DeferredSetRegisterForLoop new_set(data_.u_store_register.reg,
+ data_.u_store_register.value);
Trace new_trace = *trace;
new_trace.add_action(&new_set);
on_success()->Emit(compiler, &new_trace);
@@ -3377,26 +3432,6 @@ void BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
on_success()->Emit(compiler, trace);
}
-// -------------------------------------------------------------------
-// Analysis
-
-void Analysis::EnsureAnalyzed(RegExpNode* that) {
- StackLimitCheck check(isolate());
- if (check.HasOverflowed()) {
- fail("Stack overflow");
- return;
- }
- if (that->info()->been_analyzed || that->info()->being_analyzed) return;
- that->info()->being_analyzed = true;
- that->Accept(this);
- that->info()->being_analyzed = false;
- that->info()->been_analyzed = true;
-}
-
-void Analysis::VisitEnd(EndNode* that) {
- // nothing to do
-}
-
void TextNode::CalculateOffsets() {
int element_count = elements()->length();
// Set up the offsets of the elements relative to the start. This is a fixed
@@ -3409,60 +3444,269 @@ void TextNode::CalculateOffsets() {
}
}
-void Analysis::VisitText(TextNode* that) {
- that->MakeCaseIndependent(isolate(), is_one_byte_);
- EnsureAnalyzed(that->on_success());
- if (!has_failed()) {
- that->CalculateOffsets();
- }
-}
+namespace {
-void Analysis::VisitAction(ActionNode* that) {
- RegExpNode* target = that->on_success();
- EnsureAnalyzed(target);
- if (!has_failed()) {
+// Assertion propagation moves information about assertions such as
+// \b to the affected nodes. For instance, in /.\b./ information must
+// be propagated to the first '.' that whatever follows needs to know
+// if it matched a word or a non-word, and to the second '.' that it
+// has to check if it succeeds a word or non-word. In this case the
+// result will be something like:
+//
+// +-------+ +------------+
+// | . | | . |
+// +-------+ ---> +------------+
+// | word? | | check word |
+// +-------+ +------------+
+class AssertionPropagator : public AllStatic {
+ public:
+ static void VisitText(TextNode* that) {}
+
+ static void VisitAction(ActionNode* that) {
// If the next node is interested in what it follows then this node
// has to be interested too so it can pass the information on.
- that->info()->AddFromFollowing(target->info());
+ that->info()->AddFromFollowing(that->on_success()->info());
}
-}
-void Analysis::VisitChoice(ChoiceNode* that) {
- NodeInfo* info = that->info();
- for (int i = 0; i < that->alternatives()->length(); i++) {
- RegExpNode* node = that->alternatives()->at(i).node();
- EnsureAnalyzed(node);
- if (has_failed()) return;
+ static void VisitChoice(ChoiceNode* that, int i) {
// Anything the following nodes need to know has to be known by
// this node also, so it can pass it on.
- info->AddFromFollowing(node->info());
+ that->info()->AddFromFollowing(that->alternatives()->at(i).node()->info());
}
-}
-void Analysis::VisitLoopChoice(LoopChoiceNode* that) {
- NodeInfo* info = that->info();
- for (int i = 0; i < that->alternatives()->length(); i++) {
- RegExpNode* node = that->alternatives()->at(i).node();
- if (node != that->loop_node()) {
- EnsureAnalyzed(node);
+ static void VisitLoopChoiceContinueNode(LoopChoiceNode* that) {
+ that->info()->AddFromFollowing(that->continue_node()->info());
+ }
+
+ static void VisitLoopChoiceLoopNode(LoopChoiceNode* that) {
+ that->info()->AddFromFollowing(that->loop_node()->info());
+ }
+
+ static void VisitNegativeLookaroundChoiceLookaroundNode(
+ NegativeLookaroundChoiceNode* that) {
+ VisitChoice(that, NegativeLookaroundChoiceNode::kLookaroundIndex);
+ }
+
+ static void VisitNegativeLookaroundChoiceContinueNode(
+ NegativeLookaroundChoiceNode* that) {
+ VisitChoice(that, NegativeLookaroundChoiceNode::kContinueIndex);
+ }
+
+ static void VisitBackReference(BackReferenceNode* that) {}
+
+ static void VisitAssertion(AssertionNode* that) {}
+};
+
+// Propagates information about the minimum size of successful matches from
+// successor nodes to their predecessors. Note that all eats_at_least values
+// are initialized to zero before analysis.
+class EatsAtLeastPropagator : public AllStatic {
+ public:
+ static void VisitText(TextNode* that) {
+ // The eats_at_least value is not used if reading backward.
+ if (!that->read_backward()) {
+ // We are not at the start after this node, and thus we can use the
+ // successor's eats_at_least_from_not_start value.
+ uint8_t eats_at_least = base::saturated_cast<uint8_t>(
+ that->Length() + that->on_success()
+ ->eats_at_least_info()
+ ->eats_at_least_from_not_start);
+ that->set_eats_at_least_info(EatsAtLeastInfo(eats_at_least));
+ }
+ }
+
+ static void VisitAction(ActionNode* that) {
+ // POSITIVE_SUBMATCH_SUCCESS rewinds input, so we must not consider
+ // successor nodes for eats_at_least. SET_REGISTER_FOR_LOOP indicates a loop
+ // entry point, which means the loop body will run at least the minimum
+ // number of times before the continuation case can run. Otherwise the
+ // current node eats at least as much as its successor.
+ switch (that->action_type()) {
+ case ActionNode::POSITIVE_SUBMATCH_SUCCESS:
+ break; // Was already initialized to zero.
+ case ActionNode::SET_REGISTER_FOR_LOOP:
+ that->set_eats_at_least_info(
+ that->on_success()->EatsAtLeastFromLoopEntry());
+ break;
+ default:
+ that->set_eats_at_least_info(*that->on_success()->eats_at_least_info());
+ break;
+ }
+ }
+
+ static void VisitChoice(ChoiceNode* that, int i) {
+ // The minimum possible match from a choice node is the minimum of its
+ // successors.
+ EatsAtLeastInfo eats_at_least =
+ i == 0 ? EatsAtLeastInfo(UINT8_MAX) : *that->eats_at_least_info();
+ eats_at_least.SetMin(
+ *that->alternatives()->at(i).node()->eats_at_least_info());
+ that->set_eats_at_least_info(eats_at_least);
+ }
+
+ static void VisitLoopChoiceContinueNode(LoopChoiceNode* that) {
+ that->set_eats_at_least_info(*that->continue_node()->eats_at_least_info());
+ }
+
+ static void VisitLoopChoiceLoopNode(LoopChoiceNode* that) {}
+
+ static void VisitNegativeLookaroundChoiceLookaroundNode(
+ NegativeLookaroundChoiceNode* that) {}
+
+ static void VisitNegativeLookaroundChoiceContinueNode(
+ NegativeLookaroundChoiceNode* that) {
+ that->set_eats_at_least_info(*that->continue_node()->eats_at_least_info());
+ }
+
+ static void VisitBackReference(BackReferenceNode* that) {
+ if (!that->read_backward()) {
+ that->set_eats_at_least_info(*that->on_success()->eats_at_least_info());
+ }
+ }
+
+ static void VisitAssertion(AssertionNode* that) {
+ EatsAtLeastInfo eats_at_least = *that->on_success()->eats_at_least_info();
+ if (that->assertion_type() == AssertionNode::AT_START) {
+ // If we know we are not at the start and we are asked "how many
+ // characters will you match if you succeed?" then we can answer anything
+ // since false implies false. So let's just set the max answer
+ // (UINT8_MAX) since that won't prevent us from preloading a lot of
+ // characters for the other branches in the node graph.
+ eats_at_least.eats_at_least_from_not_start = UINT8_MAX;
+ }
+ that->set_eats_at_least_info(eats_at_least);
+ }
+};
+
+} // namespace
+
+// -------------------------------------------------------------------
+// Analysis
+
+// Iterates the node graph and provides the opportunity for propagators to set
+// values that depend on successor nodes.
+template <typename... Propagators>
+class Analysis : public NodeVisitor {
+ public:
+ Analysis(Isolate* isolate, bool is_one_byte)
+ : isolate_(isolate), is_one_byte_(is_one_byte), error_message_(nullptr) {}
+
+ void EnsureAnalyzed(RegExpNode* that) {
+ StackLimitCheck check(isolate());
+ if (check.HasOverflowed()) {
+ fail("Stack overflow");
+ return;
+ }
+ if (that->info()->been_analyzed || that->info()->being_analyzed) return;
+ that->info()->being_analyzed = true;
+ that->Accept(this);
+ that->info()->being_analyzed = false;
+ that->info()->been_analyzed = true;
+ }
+
+ bool has_failed() { return error_message_ != nullptr; }
+ const char* error_message() {
+ DCHECK(error_message_ != nullptr);
+ return error_message_;
+ }
+ void fail(const char* error_message) { error_message_ = error_message; }
+
+ Isolate* isolate() const { return isolate_; }
+
+ void VisitEnd(EndNode* that) override {
+ // nothing to do
+ }
+
+// Used to call the given static function on each propagator / variadic template
+// argument.
+#define STATIC_FOR_EACH(expr) \
+ do { \
+ int dummy[] = {((expr), 0)...}; \
+ USE(dummy); \
+ } while (false)
+
+ void VisitText(TextNode* that) override {
+ that->MakeCaseIndependent(isolate(), is_one_byte_);
+ EnsureAnalyzed(that->on_success());
+ if (has_failed()) return;
+ that->CalculateOffsets();
+ STATIC_FOR_EACH(Propagators::VisitText(that));
+ }
+
+ void VisitAction(ActionNode* that) override {
+ EnsureAnalyzed(that->on_success());
+ if (has_failed()) return;
+ STATIC_FOR_EACH(Propagators::VisitAction(that));
+ }
+
+ void VisitChoice(ChoiceNode* that) override {
+ for (int i = 0; i < that->alternatives()->length(); i++) {
+ EnsureAnalyzed(that->alternatives()->at(i).node());
if (has_failed()) return;
- info->AddFromFollowing(node->info());
+ STATIC_FOR_EACH(Propagators::VisitChoice(that, i));
}
}
- // Check the loop last since it may need the value of this node
- // to get a correct result.
- EnsureAnalyzed(that->loop_node());
- if (!has_failed()) {
- info->AddFromFollowing(that->loop_node()->info());
+
+ void VisitLoopChoice(LoopChoiceNode* that) override {
+ DCHECK_EQ(that->alternatives()->length(), 2); // Just loop and continue.
+
+ // First propagate all information from the continuation node.
+ EnsureAnalyzed(that->continue_node());
+ if (has_failed()) return;
+ STATIC_FOR_EACH(Propagators::VisitLoopChoiceContinueNode(that));
+
+ // Check the loop last since it may need the value of this node
+ // to get a correct result.
+ EnsureAnalyzed(that->loop_node());
+ if (has_failed()) return;
+ STATIC_FOR_EACH(Propagators::VisitLoopChoiceLoopNode(that));
+ }
+
+ void VisitNegativeLookaroundChoice(
+ NegativeLookaroundChoiceNode* that) override {
+ DCHECK_EQ(that->alternatives()->length(), 2); // Lookaround and continue.
+
+ EnsureAnalyzed(that->lookaround_node());
+ if (has_failed()) return;
+ STATIC_FOR_EACH(
+ Propagators::VisitNegativeLookaroundChoiceLookaroundNode(that));
+
+ EnsureAnalyzed(that->continue_node());
+ if (has_failed()) return;
+ STATIC_FOR_EACH(
+ Propagators::VisitNegativeLookaroundChoiceContinueNode(that));
}
-}
-void Analysis::VisitBackReference(BackReferenceNode* that) {
- EnsureAnalyzed(that->on_success());
-}
+ void VisitBackReference(BackReferenceNode* that) override {
+ EnsureAnalyzed(that->on_success());
+ if (has_failed()) return;
+ STATIC_FOR_EACH(Propagators::VisitBackReference(that));
+ }
+
+ void VisitAssertion(AssertionNode* that) override {
+ EnsureAnalyzed(that->on_success());
+ if (has_failed()) return;
+ STATIC_FOR_EACH(Propagators::VisitAssertion(that));
+ }
+
+#undef STATIC_FOR_EACH
+
+ private:
+ Isolate* isolate_;
+ bool is_one_byte_;
+ const char* error_message_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Analysis);
+};
-void Analysis::VisitAssertion(AssertionNode* that) {
- EnsureAnalyzed(that->on_success());
+const char* AnalyzeRegExp(Isolate* isolate, bool is_one_byte,
+ RegExpNode* node) {
+ Analysis<AssertionPropagator, EatsAtLeastPropagator> analysis(isolate,
+ is_one_byte);
+ DCHECK_EQ(node->info()->been_analyzed, false);
+ analysis.EnsureAnalyzed(node);
+ DCHECK_IMPLIES(analysis.has_failed(), analysis.error_message() != nullptr);
+ return analysis.has_failed() ? analysis.error_message() : nullptr;
}
void BackReferenceNode::FillInBMInfo(Isolate* isolate, int offset, int budget,
diff --git a/deps/v8/src/regexp/regexp-compiler.h b/deps/v8/src/regexp/regexp-compiler.h
index 1b70abfd98..2de221f35d 100644
--- a/deps/v8/src/regexp/regexp-compiler.h
+++ b/deps/v8/src/regexp/regexp-compiler.h
@@ -285,10 +285,11 @@ class Trace {
void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; }
};
- class DeferredSetRegister : public DeferredAction {
+ class DeferredSetRegisterForLoop : public DeferredAction {
public:
- DeferredSetRegister(int reg, int value)
- : DeferredAction(ActionNode::SET_REGISTER, reg), value_(value) {}
+ DeferredSetRegisterForLoop(int reg, int value)
+ : DeferredAction(ActionNode::SET_REGISTER_FOR_LOOP, reg),
+ value_(value) {}
int value() { return value_; }
private:
@@ -419,45 +420,13 @@ struct PreloadState {
void init() { eats_at_least_ = kEatsAtLeastNotYetInitialized; }
};
-// Assertion propagation moves information about assertions such as
-// \b to the affected nodes. For instance, in /.\b./ information must
-// be propagated to the first '.' that whatever follows needs to know
-// if it matched a word or a non-word, and to the second '.' that it
-// has to check if it succeeds a word or non-word. In this case the
-// result will be something like:
+// Analysis performs assertion propagation and computes eats_at_least_ values.
+// See the comments on AssertionPropagator and EatsAtLeastPropagator for more
+// details.
//
-// +-------+ +------------+
-// | . | | . |
-// +-------+ ---> +------------+
-// | word? | | check word |
-// +-------+ +------------+
-class Analysis : public NodeVisitor {
- public:
- Analysis(Isolate* isolate, bool is_one_byte)
- : isolate_(isolate), is_one_byte_(is_one_byte), error_message_(nullptr) {}
- void EnsureAnalyzed(RegExpNode* node);
-
-#define DECLARE_VISIT(Type) void Visit##Type(Type##Node* that) override;
- FOR_EACH_NODE_TYPE(DECLARE_VISIT)
-#undef DECLARE_VISIT
- void VisitLoopChoice(LoopChoiceNode* that) override;
-
- bool has_failed() { return error_message_ != nullptr; }
- const char* error_message() {
- DCHECK(error_message_ != nullptr);
- return error_message_;
- }
- void fail(const char* error_message) { error_message_ = error_message; }
-
- Isolate* isolate() const { return isolate_; }
-
- private:
- Isolate* isolate_;
- bool is_one_byte_;
- const char* error_message_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(Analysis);
-};
+// This method returns nullptr on success or a null-terminated failure message
+// on failure.
+const char* AnalyzeRegExp(Isolate* isolate, bool is_one_byte, RegExpNode* node);
class FrequencyCollator {
public:
diff --git a/deps/v8/src/regexp/regexp-dotprinter.cc b/deps/v8/src/regexp/regexp-dotprinter.cc
index a6d72aaf5b..b6640626f2 100644
--- a/deps/v8/src/regexp/regexp-dotprinter.cc
+++ b/deps/v8/src/regexp/regexp-dotprinter.cc
@@ -114,6 +114,15 @@ void DotPrinterImpl::VisitChoice(ChoiceNode* that) {
}
}
+void DotPrinterImpl::VisitLoopChoice(LoopChoiceNode* that) {
+ VisitChoice(that);
+}
+
+void DotPrinterImpl::VisitNegativeLookaroundChoice(
+ NegativeLookaroundChoiceNode* that) {
+ VisitChoice(that);
+}
+
void DotPrinterImpl::VisitText(TextNode* that) {
Zone* zone = that->zone();
os_ << " n" << that << " [label=\"";
@@ -191,7 +200,7 @@ void DotPrinterImpl::VisitAssertion(AssertionNode* that) {
void DotPrinterImpl::VisitAction(ActionNode* that) {
os_ << " n" << that << " [";
switch (that->action_type_) {
- case ActionNode::SET_REGISTER:
+ case ActionNode::SET_REGISTER_FOR_LOOP:
os_ << "label=\"$" << that->data_.u_store_register.reg
<< ":=" << that->data_.u_store_register.value << "\", shape=octagon";
break;
diff --git a/deps/v8/src/regexp/regexp-interpreter.cc b/deps/v8/src/regexp/regexp-interpreter.cc
index 881758861c..cf2fb55e4a 100644
--- a/deps/v8/src/regexp/regexp-interpreter.cc
+++ b/deps/v8/src/regexp/regexp-interpreter.cc
@@ -8,6 +8,7 @@
#include "src/ast/ast.h"
#include "src/base/small-vector.h"
+#include "src/objects/js-regexp-inl.h"
#include "src/objects/objects-inl.h"
#include "src/regexp/regexp-bytecodes.h"
#include "src/regexp/regexp-macro-assembler.h"
@@ -19,12 +20,20 @@
#include "unicode/uchar.h"
#endif // V8_INTL_SUPPORT
+// Use token threaded dispatch iff the compiler supports computed gotos and the
+// build argument v8_enable_regexp_interpreter_threaded_dispatch was set.
+#if V8_HAS_COMPUTED_GOTO && \
+ defined(V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH)
+#define V8_USE_COMPUTED_GOTO 1
+#endif // V8_HAS_COMPUTED_GOTO
+
namespace v8 {
namespace internal {
-static bool BackRefMatchesNoCase(Isolate* isolate, int from, int current,
- int len, Vector<const uc16> subject,
- bool unicode) {
+namespace {
+
+bool BackRefMatchesNoCase(Isolate* isolate, int from, int current, int len,
+ Vector<const uc16> subject, bool unicode) {
Address offset_a =
reinterpret_cast<Address>(const_cast<uc16*>(&subject.at(from)));
Address offset_b =
@@ -34,9 +43,8 @@ static bool BackRefMatchesNoCase(Isolate* isolate, int from, int current,
offset_a, offset_b, length, unicode ? nullptr : isolate) == 1;
}
-static bool BackRefMatchesNoCase(Isolate* isolate, int from, int current,
- int len, Vector<const uint8_t> subject,
- bool unicode) {
+bool BackRefMatchesNoCase(Isolate* isolate, int from, int current, int len,
+ Vector<const uint8_t> subject, bool unicode) {
// For Latin1 characters the unicode flag makes no difference.
for (int i = 0; i < len; i++) {
unsigned int old_char = subject[from++];
@@ -55,49 +63,48 @@ static bool BackRefMatchesNoCase(Isolate* isolate, int from, int current,
return true;
}
+void DisassembleSingleBytecode(const byte* code_base, const byte* pc) {
+ PrintF("%s", RegExpBytecodeName(*pc));
+
+ // Args and the bytecode as hex.
+ for (int i = 0; i < RegExpBytecodeLength(*pc); i++) {
+ PrintF(", %02x", pc[i]);
+ }
+ PrintF(" ");
+
+ // Args as ascii.
+ for (int i = 1; i < RegExpBytecodeLength(*pc); i++) {
+ unsigned char b = pc[i];
+ PrintF("%c", std::isprint(b) ? b : '.');
+ }
+ PrintF("\n");
+}
+
#ifdef DEBUG
-static void TraceInterpreter(const byte* code_base, const byte* pc,
- int stack_depth, int current_position,
- uint32_t current_char, int bytecode_length,
- const char* bytecode_name) {
+void MaybeTraceInterpreter(const byte* code_base, const byte* pc,
+ int stack_depth, int current_position,
+ uint32_t current_char, int bytecode_length,
+ const char* bytecode_name) {
if (FLAG_trace_regexp_bytecodes) {
- bool printable = (current_char < 127 && current_char >= 32);
+ const bool printable = std::isprint(current_char);
const char* format =
printable
- ? "pc = %02x, sp = %d, curpos = %d, curchar = %08x (%c), bc = %s"
- : "pc = %02x, sp = %d, curpos = %d, curchar = %08x .%c., bc = %s";
+ ? "pc = %02x, sp = %d, curpos = %d, curchar = %08x (%c), bc = "
+ : "pc = %02x, sp = %d, curpos = %d, curchar = %08x .%c., bc = ";
PrintF(format, pc - code_base, stack_depth, current_position, current_char,
- printable ? current_char : '.', bytecode_name);
- for (int i = 0; i < bytecode_length; i++) {
- printf(", %02x", pc[i]);
- }
- printf(" ");
- for (int i = 1; i < bytecode_length; i++) {
- unsigned char b = pc[i];
- if (b < 127 && b >= 32) {
- printf("%c", b);
- } else {
- printf(".");
- }
- }
- printf("\n");
+ printable ? current_char : '.');
+
+ DisassembleSingleBytecode(code_base, pc);
}
}
+#endif // DEBUG
-#define BYTECODE(name) \
- case BC_##name: \
- TraceInterpreter(code_base, pc, backtrack_stack.sp(), current, \
- current_char, BC_##name##_LENGTH, #name);
-#else
-#define BYTECODE(name) case BC_##name:
-#endif
-
-static int32_t Load32Aligned(const byte* pc) {
+int32_t Load32Aligned(const byte* pc) {
DCHECK_EQ(0, reinterpret_cast<intptr_t>(pc) & 3);
return *reinterpret_cast<const int32_t*>(pc);
}
-static int32_t Load16Aligned(const byte* pc) {
+int32_t Load16Aligned(const byte* pc) {
DCHECK_EQ(0, reinterpret_cast<intptr_t>(pc) & 1);
return *reinterpret_cast<const uint16_t*>(pc);
}
@@ -139,9 +146,9 @@ class BacktrackStack {
DISALLOW_COPY_AND_ASSIGN(BacktrackStack);
};
-namespace {
-
-IrregexpInterpreter::Result StackOverflow(Isolate* isolate) {
+IrregexpInterpreter::Result StackOverflow(Isolate* isolate,
+ RegExp::CallOrigin call_origin) {
+ CHECK(call_origin == RegExp::CallOrigin::kFromRuntime);
// We abort interpreter execution after the stack overflow is thrown, and thus
// allow allocation here despite the outer DisallowHeapAllocationScope.
AllowHeapAllocation yes_gc;
@@ -149,72 +156,154 @@ IrregexpInterpreter::Result StackOverflow(Isolate* isolate) {
return IrregexpInterpreter::EXCEPTION;
}
-// Runs all pending interrupts. Callers must update unhandlified object
-// references after this function completes.
-IrregexpInterpreter::Result HandleInterrupts(Isolate* isolate,
- Handle<String> subject_string) {
+template <typename Char>
+void UpdateCodeAndSubjectReferences(
+ Isolate* isolate, Handle<ByteArray> code_array,
+ Handle<String> subject_string, ByteArray* code_array_out,
+ const byte** code_base_out, const byte** pc_out, String* subject_string_out,
+ Vector<const Char>* subject_string_vector_out) {
DisallowHeapAllocation no_gc;
- StackLimitCheck check(isolate);
- if (check.JsHasOverflowed()) {
- return StackOverflow(isolate); // A real stack overflow.
+ if (*code_base_out != code_array->GetDataStartAddress()) {
+ *code_array_out = *code_array;
+ const intptr_t pc_offset = *pc_out - *code_base_out;
+ DCHECK_GT(pc_offset, 0);
+ *code_base_out = code_array->GetDataStartAddress();
+ *pc_out = *code_base_out + pc_offset;
}
- // Handle interrupts if any exist.
- if (check.InterruptRequested()) {
- const bool was_one_byte =
- String::IsOneByteRepresentationUnderneath(*subject_string);
+ DCHECK(subject_string->IsFlat());
+ *subject_string_out = *subject_string;
+ *subject_string_vector_out = subject_string->GetCharVector<Char>(no_gc);
+}
- Object result;
- {
- AllowHeapAllocation yes_gc;
- result = isolate->stack_guard()->HandleInterrupts();
- }
+// Runs all pending interrupts and updates unhandlified object references if
+// necessary.
+template <typename Char>
+IrregexpInterpreter::Result HandleInterrupts(
+ Isolate* isolate, RegExp::CallOrigin call_origin, ByteArray* code_array_out,
+ String* subject_string_out, const byte** code_base_out,
+ Vector<const Char>* subject_string_vector_out, const byte** pc_out) {
+ DisallowHeapAllocation no_gc;
- if (result.IsException(isolate)) {
+ StackLimitCheck check(isolate);
+ bool js_has_overflowed = check.JsHasOverflowed();
+
+ if (call_origin == RegExp::CallOrigin::kFromJs) {
+ // Direct calls from JavaScript can be interrupted in two ways:
+ // 1. A real stack overflow, in which case we let the caller throw the
+ // exception.
+ // 2. The stack guard was used to interrupt execution for another purpose,
+ // forcing the call through the runtime system.
+ if (js_has_overflowed) {
return IrregexpInterpreter::EXCEPTION;
- }
-
- // If we changed between a LATIN1 and a UC16 string, we need to restart
- // regexp matching with the appropriate template instantiation of RawMatch.
- if (String::IsOneByteRepresentationUnderneath(*subject_string) !=
- was_one_byte) {
+ } else if (check.InterruptRequested()) {
return IrregexpInterpreter::RETRY;
}
+ } else {
+ DCHECK(call_origin == RegExp::CallOrigin::kFromRuntime);
+ // Prepare for possible GC.
+ HandleScope handles(isolate);
+ Handle<ByteArray> code_handle(*code_array_out, isolate);
+ Handle<String> subject_handle(*subject_string_out, isolate);
+
+ if (js_has_overflowed) {
+ return StackOverflow(isolate, call_origin);
+ } else if (check.InterruptRequested()) {
+ const bool was_one_byte =
+ String::IsOneByteRepresentationUnderneath(*subject_string_out);
+ Object result;
+ {
+ AllowHeapAllocation yes_gc;
+ result = isolate->stack_guard()->HandleInterrupts();
+ }
+ if (result.IsException(isolate)) {
+ return IrregexpInterpreter::EXCEPTION;
+ }
+
+ // If we changed between a LATIN1 and a UC16 string, we need to restart
+ // regexp matching with the appropriate template instantiation of
+ // RawMatch.
+ if (String::IsOneByteRepresentationUnderneath(*subject_handle) !=
+ was_one_byte) {
+ return IrregexpInterpreter::RETRY;
+ }
+
+ UpdateCodeAndSubjectReferences(
+ isolate, code_handle, subject_handle, code_array_out, code_base_out,
+ pc_out, subject_string_out, subject_string_vector_out);
+ }
}
return IrregexpInterpreter::SUCCESS;
}
-template <typename Char>
-void UpdateCodeAndSubjectReferences(Isolate* isolate,
- Handle<ByteArray> code_array,
- Handle<String> subject_string,
- const byte** code_base_out,
- const byte** pc_out,
- Vector<const Char>* subject_string_out) {
- DisallowHeapAllocation no_gc;
+// If computed gotos are supported by the compiler, we can get addresses to
+// labels directly in C/C++. Every bytecode handler has its own label and we
+// store the addresses in a dispatch table indexed by bytecode. To execute the
+// next handler we simply jump (goto) directly to its address.
+#if V8_USE_COMPUTED_GOTO
+#define BC_LABEL(name) BC_##name:
+#define DECODE() \
+ do { \
+ next_insn = Load32Aligned(next_pc); \
+ next_handler_addr = dispatch_table[next_insn & BYTECODE_MASK]; \
+ } while (false)
+#define DISPATCH() \
+ pc = next_pc; \
+ insn = next_insn; \
+ goto* next_handler_addr
+// Without computed goto support, we fall back to a simple switch-based
+// dispatch (A large switch statement inside a loop with a case for every
+// bytecode).
+#else // V8_USE_COMPUTED_GOTO
+#define BC_LABEL(name) case BC_##name:
+#define DECODE() next_insn = Load32Aligned(next_pc)
+#define DISPATCH() \
+ pc = next_pc; \
+ insn = next_insn; \
+ break
+#endif // V8_USE_COMPUTED_GOTO
+
+// ADVANCE/SET_PC_FROM_OFFSET are separated from DISPATCH, because ideally some
+// instructions can be executed between ADVANCE/SET_PC_FROM_OFFSET and DISPATCH.
+// We want those two macros as far apart as possible, because the goto in
+// DISPATCH is dependent on a memory load in ADVANCE/SET_PC_FROM_OFFSET. If we
+// don't hit the cache and have to fetch the next handler address from physical
+// memory, instructions between ADVANCE/SET_PC_FROM_OFFSET and DISPATCH can
+// potentially be executed unconditionally, reducing memory stall.
+#define ADVANCE(name) \
+ next_pc = pc + RegExpBytecodeLength(BC_##name); \
+ DECODE()
+#define SET_PC_FROM_OFFSET(offset) \
+ next_pc = code_base + offset; \
+ DECODE()
- if (*code_base_out != code_array->GetDataStartAddress()) {
- const intptr_t pc_offset = *pc_out - *code_base_out;
- DCHECK_GT(pc_offset, 0);
- *code_base_out = code_array->GetDataStartAddress();
- *pc_out = *code_base_out + pc_offset;
- }
-
- DCHECK(subject_string->IsFlat());
- *subject_string_out = subject_string->GetCharVector<Char>(no_gc);
-}
+#ifdef DEBUG
+#define BYTECODE(name) \
+ BC_LABEL(name) \
+ MaybeTraceInterpreter(code_base, pc, backtrack_stack.sp(), current, \
+ current_char, RegExpBytecodeLength(BC_##name), #name);
+#else
+#define BYTECODE(name) BC_LABEL(name)
+#endif // DEBUG
template <typename Char>
-IrregexpInterpreter::Result RawMatch(Isolate* isolate,
- Handle<ByteArray> code_array,
- Handle<String> subject_string,
+IrregexpInterpreter::Result RawMatch(Isolate* isolate, ByteArray code_array,
+ String subject_string,
Vector<const Char> subject, int* registers,
- int current, uint32_t current_char) {
+ int current, uint32_t current_char,
+ RegExp::CallOrigin call_origin) {
DisallowHeapAllocation no_gc;
- const byte* pc = code_array->GetDataStartAddress();
+#if V8_USE_COMPUTED_GOTO
+#define DECLARE_DISPATCH_TABLE_ENTRY(name, code, length) &&BC_##name,
+ static const void* const dispatch_table[] = {
+ BYTECODE_ITERATOR(DECLARE_DISPATCH_TABLE_ENTRY)};
+#undef DECLARE_DISPATCH_TABLE_ENTRY
+#endif
+
+ const byte* pc = code_array.GetDataStartAddress();
const byte* code_base = pc;
BacktrackStack backtrack_stack;
@@ -224,457 +313,572 @@ IrregexpInterpreter::Result RawMatch(Isolate* isolate,
PrintF("\n\nStart bytecode interpreter\n\n");
}
#endif
+
while (true) {
- const int32_t insn = Load32Aligned(pc);
+ const byte* next_pc = pc;
+ int32_t insn;
+ int32_t next_insn;
+#if V8_USE_COMPUTED_GOTO
+ const void* next_handler_addr;
+ DECODE();
+ DISPATCH();
+#else
+ insn = Load32Aligned(pc);
switch (insn & BYTECODE_MASK) {
- BYTECODE(BREAK) { UNREACHABLE(); }
- BYTECODE(PUSH_CP) {
- backtrack_stack.push(current);
- pc += BC_PUSH_CP_LENGTH;
- break;
- }
- BYTECODE(PUSH_BT) {
- backtrack_stack.push(Load32Aligned(pc + 4));
- pc += BC_PUSH_BT_LENGTH;
- break;
- }
- BYTECODE(PUSH_REGISTER) {
- backtrack_stack.push(registers[insn >> BYTECODE_SHIFT]);
- pc += BC_PUSH_REGISTER_LENGTH;
- break;
- }
- BYTECODE(SET_REGISTER) {
- registers[insn >> BYTECODE_SHIFT] = Load32Aligned(pc + 4);
- pc += BC_SET_REGISTER_LENGTH;
- break;
- }
- BYTECODE(ADVANCE_REGISTER) {
- registers[insn >> BYTECODE_SHIFT] += Load32Aligned(pc + 4);
- pc += BC_ADVANCE_REGISTER_LENGTH;
- break;
- }
- BYTECODE(SET_REGISTER_TO_CP) {
- registers[insn >> BYTECODE_SHIFT] = current + Load32Aligned(pc + 4);
- pc += BC_SET_REGISTER_TO_CP_LENGTH;
- break;
- }
- BYTECODE(SET_CP_TO_REGISTER) {
- current = registers[insn >> BYTECODE_SHIFT];
- pc += BC_SET_CP_TO_REGISTER_LENGTH;
- break;
- }
- BYTECODE(SET_REGISTER_TO_SP) {
- registers[insn >> BYTECODE_SHIFT] = backtrack_stack.sp();
- pc += BC_SET_REGISTER_TO_SP_LENGTH;
- break;
- }
- BYTECODE(SET_SP_TO_REGISTER) {
- backtrack_stack.set_sp(registers[insn >> BYTECODE_SHIFT]);
- pc += BC_SET_SP_TO_REGISTER_LENGTH;
- break;
- }
- BYTECODE(POP_CP) {
- current = backtrack_stack.pop();
- pc += BC_POP_CP_LENGTH;
- break;
- }
- BYTECODE(POP_BT) {
- IrregexpInterpreter::Result return_code =
- HandleInterrupts(isolate, subject_string);
- if (return_code != IrregexpInterpreter::SUCCESS) return return_code;
-
- UpdateCodeAndSubjectReferences(isolate, code_array, subject_string,
- &code_base, &pc, &subject);
-
- pc = code_base + backtrack_stack.pop();
- break;
- }
- BYTECODE(POP_REGISTER) {
- registers[insn >> BYTECODE_SHIFT] = backtrack_stack.pop();
- pc += BC_POP_REGISTER_LENGTH;
- break;
- }
- BYTECODE(FAIL) { return IrregexpInterpreter::FAILURE; }
- BYTECODE(SUCCEED) { return IrregexpInterpreter::SUCCESS; }
- BYTECODE(ADVANCE_CP) {
- current += insn >> BYTECODE_SHIFT;
- pc += BC_ADVANCE_CP_LENGTH;
- break;
- }
- BYTECODE(GOTO) {
- pc = code_base + Load32Aligned(pc + 4);
- break;
- }
- BYTECODE(ADVANCE_CP_AND_GOTO) {
- current += insn >> BYTECODE_SHIFT;
- pc = code_base + Load32Aligned(pc + 4);
- break;
- }
- BYTECODE(CHECK_GREEDY) {
- if (current == backtrack_stack.peek()) {
- backtrack_stack.pop();
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- pc += BC_CHECK_GREEDY_LENGTH;
- }
- break;
- }
- BYTECODE(LOAD_CURRENT_CHAR) {
- int pos = current + (insn >> BYTECODE_SHIFT);
- if (pos >= subject.length() || pos < 0) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- current_char = subject[pos];
- pc += BC_LOAD_CURRENT_CHAR_LENGTH;
- }
- break;
+#endif // V8_USE_COMPUTED_GOTO
+ BYTECODE(BREAK) { UNREACHABLE(); }
+ BYTECODE(PUSH_CP) {
+ ADVANCE(PUSH_CP);
+ backtrack_stack.push(current);
+ DISPATCH();
+ }
+ BYTECODE(PUSH_BT) {
+ ADVANCE(PUSH_BT);
+ backtrack_stack.push(Load32Aligned(pc + 4));
+ DISPATCH();
+ }
+ BYTECODE(PUSH_REGISTER) {
+ ADVANCE(PUSH_REGISTER);
+ backtrack_stack.push(registers[insn >> BYTECODE_SHIFT]);
+ DISPATCH();
+ }
+ BYTECODE(SET_REGISTER) {
+ ADVANCE(SET_REGISTER);
+ registers[insn >> BYTECODE_SHIFT] = Load32Aligned(pc + 4);
+ DISPATCH();
+ }
+ BYTECODE(ADVANCE_REGISTER) {
+ ADVANCE(ADVANCE_REGISTER);
+ registers[insn >> BYTECODE_SHIFT] += Load32Aligned(pc + 4);
+ DISPATCH();
+ }
+ BYTECODE(SET_REGISTER_TO_CP) {
+ ADVANCE(SET_REGISTER_TO_CP);
+ registers[insn >> BYTECODE_SHIFT] = current + Load32Aligned(pc + 4);
+ DISPATCH();
+ }
+ BYTECODE(SET_CP_TO_REGISTER) {
+ ADVANCE(SET_CP_TO_REGISTER);
+ current = registers[insn >> BYTECODE_SHIFT];
+ DISPATCH();
+ }
+ BYTECODE(SET_REGISTER_TO_SP) {
+ ADVANCE(SET_REGISTER_TO_SP);
+ registers[insn >> BYTECODE_SHIFT] = backtrack_stack.sp();
+ DISPATCH();
+ }
+ BYTECODE(SET_SP_TO_REGISTER) {
+ ADVANCE(SET_SP_TO_REGISTER);
+ backtrack_stack.set_sp(registers[insn >> BYTECODE_SHIFT]);
+ DISPATCH();
+ }
+ BYTECODE(POP_CP) {
+ ADVANCE(POP_CP);
+ current = backtrack_stack.pop();
+ DISPATCH();
+ }
+ BYTECODE(POP_BT) {
+ IrregexpInterpreter::Result return_code =
+ HandleInterrupts(isolate, call_origin, &code_array, &subject_string,
+ &code_base, &subject, &pc);
+ if (return_code != IrregexpInterpreter::SUCCESS) return return_code;
+
+ SET_PC_FROM_OFFSET(backtrack_stack.pop());
+ DISPATCH();
+ }
+ BYTECODE(POP_REGISTER) {
+ ADVANCE(POP_REGISTER);
+ registers[insn >> BYTECODE_SHIFT] = backtrack_stack.pop();
+ DISPATCH();
+ }
+ BYTECODE(FAIL) { return IrregexpInterpreter::FAILURE; }
+ BYTECODE(SUCCEED) { return IrregexpInterpreter::SUCCESS; }
+ BYTECODE(ADVANCE_CP) {
+ ADVANCE(ADVANCE_CP);
+ current += insn >> BYTECODE_SHIFT;
+ DISPATCH();
+ }
+ BYTECODE(GOTO) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ DISPATCH();
+ }
+ BYTECODE(ADVANCE_CP_AND_GOTO) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ current += insn >> BYTECODE_SHIFT;
+ DISPATCH();
+ }
+ BYTECODE(CHECK_GREEDY) {
+ if (current == backtrack_stack.peek()) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ backtrack_stack.pop();
+ } else {
+ ADVANCE(CHECK_GREEDY);
}
- BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
- int pos = current + (insn >> BYTECODE_SHIFT);
+ DISPATCH();
+ }
+ BYTECODE(LOAD_CURRENT_CHAR) {
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ if (pos >= subject.length() || pos < 0) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(LOAD_CURRENT_CHAR);
current_char = subject[pos];
- pc += BC_LOAD_CURRENT_CHAR_UNCHECKED_LENGTH;
- break;
- }
- BYTECODE(LOAD_2_CURRENT_CHARS) {
- int pos = current + (insn >> BYTECODE_SHIFT);
- if (pos + 2 > subject.length() || pos < 0) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- Char next = subject[pos + 1];
- current_char =
- (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
- pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
- }
- break;
}
- BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
- int pos = current + (insn >> BYTECODE_SHIFT);
+ DISPATCH();
+ }
+ BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
+ ADVANCE(LOAD_CURRENT_CHAR_UNCHECKED);
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ current_char = subject[pos];
+ DISPATCH();
+ }
+ BYTECODE(LOAD_2_CURRENT_CHARS) {
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ if (pos + 2 > subject.length() || pos < 0) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(LOAD_2_CURRENT_CHARS);
Char next = subject[pos + 1];
current_char = (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
- pc += BC_LOAD_2_CURRENT_CHARS_UNCHECKED_LENGTH;
- break;
- }
- BYTECODE(LOAD_4_CURRENT_CHARS) {
- DCHECK_EQ(1, sizeof(Char));
- int pos = current + (insn >> BYTECODE_SHIFT);
- if (pos + 4 > subject.length() || pos < 0) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- Char next1 = subject[pos + 1];
- Char next2 = subject[pos + 2];
- Char next3 = subject[pos + 3];
- current_char =
- (subject[pos] | (next1 << 8) | (next2 << 16) | (next3 << 24));
- pc += BC_LOAD_4_CURRENT_CHARS_LENGTH;
- }
- break;
}
- BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
- DCHECK_EQ(1, sizeof(Char));
- int pos = current + (insn >> BYTECODE_SHIFT);
+ DISPATCH();
+ }
+ BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
+ ADVANCE(LOAD_2_CURRENT_CHARS_UNCHECKED);
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ Char next = subject[pos + 1];
+ current_char = (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
+ DISPATCH();
+ }
+ BYTECODE(LOAD_4_CURRENT_CHARS) {
+ DCHECK_EQ(1, sizeof(Char));
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ if (pos + 4 > subject.length() || pos < 0) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(LOAD_4_CURRENT_CHARS);
Char next1 = subject[pos + 1];
Char next2 = subject[pos + 2];
Char next3 = subject[pos + 3];
current_char =
(subject[pos] | (next1 << 8) | (next2 << 16) | (next3 << 24));
- pc += BC_LOAD_4_CURRENT_CHARS_UNCHECKED_LENGTH;
- break;
- }
- BYTECODE(CHECK_4_CHARS) {
- uint32_t c = Load32Aligned(pc + 4);
- if (c == current_char) {
- pc = code_base + Load32Aligned(pc + 8);
- } else {
- pc += BC_CHECK_4_CHARS_LENGTH;
- }
- break;
- }
- BYTECODE(CHECK_CHAR) {
- uint32_t c = (insn >> BYTECODE_SHIFT);
- if (c == current_char) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- pc += BC_CHECK_CHAR_LENGTH;
- }
- break;
- }
- BYTECODE(CHECK_NOT_4_CHARS) {
- uint32_t c = Load32Aligned(pc + 4);
- if (c != current_char) {
- pc = code_base + Load32Aligned(pc + 8);
- } else {
- pc += BC_CHECK_NOT_4_CHARS_LENGTH;
- }
- break;
- }
- BYTECODE(CHECK_NOT_CHAR) {
- uint32_t c = (insn >> BYTECODE_SHIFT);
- if (c != current_char) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- pc += BC_CHECK_NOT_CHAR_LENGTH;
- }
- break;
- }
- BYTECODE(AND_CHECK_4_CHARS) {
- uint32_t c = Load32Aligned(pc + 4);
- if (c == (current_char & Load32Aligned(pc + 8))) {
- pc = code_base + Load32Aligned(pc + 12);
- } else {
- pc += BC_AND_CHECK_4_CHARS_LENGTH;
- }
- break;
- }
- BYTECODE(AND_CHECK_CHAR) {
- uint32_t c = (insn >> BYTECODE_SHIFT);
- if (c == (current_char & Load32Aligned(pc + 4))) {
- pc = code_base + Load32Aligned(pc + 8);
- } else {
- pc += BC_AND_CHECK_CHAR_LENGTH;
- }
- break;
- }
- BYTECODE(AND_CHECK_NOT_4_CHARS) {
- uint32_t c = Load32Aligned(pc + 4);
- if (c != (current_char & Load32Aligned(pc + 8))) {
- pc = code_base + Load32Aligned(pc + 12);
- } else {
- pc += BC_AND_CHECK_NOT_4_CHARS_LENGTH;
- }
- break;
- }
- BYTECODE(AND_CHECK_NOT_CHAR) {
- uint32_t c = (insn >> BYTECODE_SHIFT);
- if (c != (current_char & Load32Aligned(pc + 4))) {
- pc = code_base + Load32Aligned(pc + 8);
- } else {
- pc += BC_AND_CHECK_NOT_CHAR_LENGTH;
- }
- break;
- }
- BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
- uint32_t c = (insn >> BYTECODE_SHIFT);
- uint32_t minus = Load16Aligned(pc + 4);
- uint32_t mask = Load16Aligned(pc + 6);
- if (c != ((current_char - minus) & mask)) {
- pc = code_base + Load32Aligned(pc + 8);
- } else {
- pc += BC_MINUS_AND_CHECK_NOT_CHAR_LENGTH;
- }
- break;
- }
- BYTECODE(CHECK_CHAR_IN_RANGE) {
- uint32_t from = Load16Aligned(pc + 4);
- uint32_t to = Load16Aligned(pc + 6);
- if (from <= current_char && current_char <= to) {
- pc = code_base + Load32Aligned(pc + 8);
- } else {
- pc += BC_CHECK_CHAR_IN_RANGE_LENGTH;
- }
- break;
- }
- BYTECODE(CHECK_CHAR_NOT_IN_RANGE) {
- uint32_t from = Load16Aligned(pc + 4);
- uint32_t to = Load16Aligned(pc + 6);
- if (from > current_char || current_char > to) {
- pc = code_base + Load32Aligned(pc + 8);
- } else {
- pc += BC_CHECK_CHAR_NOT_IN_RANGE_LENGTH;
- }
- break;
- }
- BYTECODE(CHECK_BIT_IN_TABLE) {
- int mask = RegExpMacroAssembler::kTableMask;
- byte b = pc[8 + ((current_char & mask) >> kBitsPerByteLog2)];
- int bit = (current_char & (kBitsPerByte - 1));
- if ((b & (1 << bit)) != 0) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- pc += BC_CHECK_BIT_IN_TABLE_LENGTH;
- }
- break;
- }
- BYTECODE(CHECK_LT) {
- uint32_t limit = (insn >> BYTECODE_SHIFT);
- if (current_char < limit) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- pc += BC_CHECK_LT_LENGTH;
- }
- break;
- }
- BYTECODE(CHECK_GT) {
- uint32_t limit = (insn >> BYTECODE_SHIFT);
- if (current_char > limit) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- pc += BC_CHECK_GT_LENGTH;
- }
- break;
}
- BYTECODE(CHECK_REGISTER_LT) {
- if (registers[insn >> BYTECODE_SHIFT] < Load32Aligned(pc + 4)) {
- pc = code_base + Load32Aligned(pc + 8);
- } else {
- pc += BC_CHECK_REGISTER_LT_LENGTH;
- }
- break;
+ DISPATCH();
+ }
+ BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
+ ADVANCE(LOAD_4_CURRENT_CHARS_UNCHECKED);
+ DCHECK_EQ(1, sizeof(Char));
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ Char next1 = subject[pos + 1];
+ Char next2 = subject[pos + 2];
+ Char next3 = subject[pos + 3];
+ current_char =
+ (subject[pos] | (next1 << 8) | (next2 << 16) | (next3 << 24));
+ DISPATCH();
+ }
+ BYTECODE(CHECK_4_CHARS) {
+ uint32_t c = Load32Aligned(pc + 4);
+ if (c == current_char) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ } else {
+ ADVANCE(CHECK_4_CHARS);
}
- BYTECODE(CHECK_REGISTER_GE) {
- if (registers[insn >> BYTECODE_SHIFT] >= Load32Aligned(pc + 4)) {
- pc = code_base + Load32Aligned(pc + 8);
- } else {
- pc += BC_CHECK_REGISTER_GE_LENGTH;
- }
- break;
+ DISPATCH();
+ }
+ BYTECODE(CHECK_CHAR) {
+ uint32_t c = (insn >> BYTECODE_SHIFT);
+ if (c == current_char) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(CHECK_CHAR);
}
- BYTECODE(CHECK_REGISTER_EQ_POS) {
- if (registers[insn >> BYTECODE_SHIFT] == current) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- pc += BC_CHECK_REGISTER_EQ_POS_LENGTH;
- }
- break;
- }
- BYTECODE(CHECK_NOT_REGS_EQUAL) {
- if (registers[insn >> BYTECODE_SHIFT] ==
- registers[Load32Aligned(pc + 4)]) {
- pc += BC_CHECK_NOT_REGS_EQUAL_LENGTH;
- } else {
- pc = code_base + Load32Aligned(pc + 8);
- }
- break;
- }
- BYTECODE(CHECK_NOT_BACK_REF) {
- int from = registers[insn >> BYTECODE_SHIFT];
- int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
- if (from >= 0 && len > 0) {
- if (current + len > subject.length() ||
- CompareChars(&subject[from], &subject[current], len) != 0) {
- pc = code_base + Load32Aligned(pc + 4);
- break;
- }
- current += len;
- }
- pc += BC_CHECK_NOT_BACK_REF_LENGTH;
- break;
- }
- BYTECODE(CHECK_NOT_BACK_REF_BACKWARD) {
- int from = registers[insn >> BYTECODE_SHIFT];
- int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
- if (from >= 0 && len > 0) {
- if (current - len < 0 ||
- CompareChars(&subject[from], &subject[current - len], len) != 0) {
- pc = code_base + Load32Aligned(pc + 4);
- break;
- }
- current -= len;
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_4_CHARS) {
+ uint32_t c = Load32Aligned(pc + 4);
+ if (c != current_char) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ } else {
+ ADVANCE(CHECK_NOT_4_CHARS);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_CHAR) {
+ uint32_t c = (insn >> BYTECODE_SHIFT);
+ if (c != current_char) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(CHECK_NOT_CHAR);
+ }
+ DISPATCH();
+ }
+ BYTECODE(AND_CHECK_4_CHARS) {
+ uint32_t c = Load32Aligned(pc + 4);
+ if (c == (current_char & Load32Aligned(pc + 8))) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 12));
+ } else {
+ ADVANCE(AND_CHECK_4_CHARS);
+ }
+ DISPATCH();
+ }
+ BYTECODE(AND_CHECK_CHAR) {
+ uint32_t c = (insn >> BYTECODE_SHIFT);
+ if (c == (current_char & Load32Aligned(pc + 4))) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ } else {
+ ADVANCE(AND_CHECK_CHAR);
+ }
+ DISPATCH();
+ }
+ BYTECODE(AND_CHECK_NOT_4_CHARS) {
+ uint32_t c = Load32Aligned(pc + 4);
+ if (c != (current_char & Load32Aligned(pc + 8))) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 12));
+ } else {
+ ADVANCE(AND_CHECK_NOT_4_CHARS);
+ }
+ DISPATCH();
+ }
+ BYTECODE(AND_CHECK_NOT_CHAR) {
+ uint32_t c = (insn >> BYTECODE_SHIFT);
+ if (c != (current_char & Load32Aligned(pc + 4))) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ } else {
+ ADVANCE(AND_CHECK_NOT_CHAR);
+ }
+ DISPATCH();
+ }
+ BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
+ uint32_t c = (insn >> BYTECODE_SHIFT);
+ uint32_t minus = Load16Aligned(pc + 4);
+ uint32_t mask = Load16Aligned(pc + 6);
+ if (c != ((current_char - minus) & mask)) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ } else {
+ ADVANCE(MINUS_AND_CHECK_NOT_CHAR);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_CHAR_IN_RANGE) {
+ uint32_t from = Load16Aligned(pc + 4);
+ uint32_t to = Load16Aligned(pc + 6);
+ if (from <= current_char && current_char <= to) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ } else {
+ ADVANCE(CHECK_CHAR_IN_RANGE);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_CHAR_NOT_IN_RANGE) {
+ uint32_t from = Load16Aligned(pc + 4);
+ uint32_t to = Load16Aligned(pc + 6);
+ if (from > current_char || current_char > to) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ } else {
+ ADVANCE(CHECK_CHAR_NOT_IN_RANGE);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_BIT_IN_TABLE) {
+ int mask = RegExpMacroAssembler::kTableMask;
+ byte b = pc[8 + ((current_char & mask) >> kBitsPerByteLog2)];
+ int bit = (current_char & (kBitsPerByte - 1));
+ if ((b & (1 << bit)) != 0) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(CHECK_BIT_IN_TABLE);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_LT) {
+ uint32_t limit = (insn >> BYTECODE_SHIFT);
+ if (current_char < limit) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(CHECK_LT);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_GT) {
+ uint32_t limit = (insn >> BYTECODE_SHIFT);
+ if (current_char > limit) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(CHECK_GT);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_REGISTER_LT) {
+ if (registers[insn >> BYTECODE_SHIFT] < Load32Aligned(pc + 4)) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ } else {
+ ADVANCE(CHECK_REGISTER_LT);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_REGISTER_GE) {
+ if (registers[insn >> BYTECODE_SHIFT] >= Load32Aligned(pc + 4)) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ } else {
+ ADVANCE(CHECK_REGISTER_GE);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_REGISTER_EQ_POS) {
+ if (registers[insn >> BYTECODE_SHIFT] == current) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(CHECK_REGISTER_EQ_POS);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_REGS_EQUAL) {
+ if (registers[insn >> BYTECODE_SHIFT] ==
+ registers[Load32Aligned(pc + 4)]) {
+ ADVANCE(CHECK_NOT_REGS_EQUAL);
+ } else {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 8));
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_BACK_REF) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from >= 0 && len > 0) {
+ if (current + len > subject.length() ||
+ CompareChars(&subject[from], &subject[current], len) != 0) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ DISPATCH();
}
- pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
- break;
- }
- BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE)
- V8_FALLTHROUGH;
- BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
- bool unicode =
- (insn & BYTECODE_MASK) == BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE;
- int from = registers[insn >> BYTECODE_SHIFT];
- int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
- if (from >= 0 && len > 0) {
- if (current + len > subject.length() ||
- !BackRefMatchesNoCase(isolate, from, current, len, subject,
- unicode)) {
- pc = code_base + Load32Aligned(pc + 4);
- break;
- }
- current += len;
+ current += len;
+ }
+ ADVANCE(CHECK_NOT_BACK_REF);
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_BACKWARD) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from >= 0 && len > 0) {
+ if (current - len < 0 ||
+ CompareChars(&subject[from], &subject[current - len], len) != 0) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ DISPATCH();
}
- pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
- break;
- }
- BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD)
- V8_FALLTHROUGH;
- BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD) {
- bool unicode = (insn & BYTECODE_MASK) ==
- BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD;
- int from = registers[insn >> BYTECODE_SHIFT];
- int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
- if (from >= 0 && len > 0) {
- if (current - len < 0 ||
- !BackRefMatchesNoCase(isolate, from, current - len, len, subject,
- unicode)) {
- pc = code_base + Load32Aligned(pc + 4);
- break;
- }
- current -= len;
+ current -= len;
+ }
+ ADVANCE(CHECK_NOT_BACK_REF_BACKWARD);
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from >= 0 && len > 0) {
+ if (current + len > subject.length() ||
+ !BackRefMatchesNoCase(isolate, from, current, len, subject, true)) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ DISPATCH();
}
- pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
- break;
- }
- BYTECODE(CHECK_AT_START) {
- if (current == 0) {
- pc = code_base + Load32Aligned(pc + 4);
- } else {
- pc += BC_CHECK_AT_START_LENGTH;
+ current += len;
+ }
+ ADVANCE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE);
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from >= 0 && len > 0) {
+ if (current + len > subject.length() ||
+ !BackRefMatchesNoCase(isolate, from, current, len, subject,
+ false)) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ DISPATCH();
}
- break;
+ current += len;
}
- BYTECODE(CHECK_NOT_AT_START) {
- if (current + (insn >> BYTECODE_SHIFT) == 0) {
- pc += BC_CHECK_NOT_AT_START_LENGTH;
- } else {
- pc = code_base + Load32Aligned(pc + 4);
+ ADVANCE(CHECK_NOT_BACK_REF_NO_CASE);
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from >= 0 && len > 0) {
+ if (current - len < 0 ||
+ !BackRefMatchesNoCase(isolate, from, current - len, len, subject,
+ true)) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ DISPATCH();
}
- break;
+ current -= len;
}
- BYTECODE(SET_CURRENT_POSITION_FROM_END) {
- int by = static_cast<uint32_t>(insn) >> BYTECODE_SHIFT;
- if (subject.length() - current > by) {
- current = subject.length() - by;
- current_char = subject[current - 1];
+ ADVANCE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD);
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from >= 0 && len > 0) {
+ if (current - len < 0 ||
+ !BackRefMatchesNoCase(isolate, from, current - len, len, subject,
+ false)) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ DISPATCH();
}
- pc += BC_SET_CURRENT_POSITION_FROM_END_LENGTH;
- break;
+ current -= len;
}
+ ADVANCE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD);
+ DISPATCH();
+ }
+ BYTECODE(CHECK_AT_START) {
+ if (current + (insn >> BYTECODE_SHIFT) == 0) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(CHECK_AT_START);
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_NOT_AT_START) {
+ if (current + (insn >> BYTECODE_SHIFT) == 0) {
+ ADVANCE(CHECK_NOT_AT_START);
+ } else {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ }
+ DISPATCH();
+ }
+ BYTECODE(SET_CURRENT_POSITION_FROM_END) {
+ ADVANCE(SET_CURRENT_POSITION_FROM_END);
+ int by = static_cast<uint32_t>(insn) >> BYTECODE_SHIFT;
+ if (subject.length() - current > by) {
+ current = subject.length() - by;
+ current_char = subject[current - 1];
+ }
+ DISPATCH();
+ }
+ BYTECODE(CHECK_CURRENT_POSITION) {
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ if (pos > subject.length() || pos < 0) {
+ SET_PC_FROM_OFFSET(Load32Aligned(pc + 4));
+ } else {
+ ADVANCE(CHECK_CURRENT_POSITION);
+ }
+ DISPATCH();
+ }
+#if V8_USE_COMPUTED_GOTO
+// Lint gets confused a lot if we just use !V8_USE_COMPUTED_GOTO or ifndef
+// V8_USE_COMPUTED_GOTO here.
+#else
default:
UNREACHABLE();
- break;
}
+#endif // V8_USE_COMPUTED_GOTO
}
}
#undef BYTECODE
+#undef DISPATCH
+#undef DECODE
+#undef SET_PC_FROM_OFFSET
+#undef ADVANCE
+#undef BC_LABEL
+#undef V8_USE_COMPUTED_GOTO
} // namespace
// static
+void IrregexpInterpreter::Disassemble(ByteArray byte_array,
+ const std::string& pattern) {
+ DisallowHeapAllocation no_gc;
+
+ PrintF("[generated bytecode for regexp pattern: '%s']\n", pattern.c_str());
+
+ const byte* const code_base = byte_array.GetDataStartAddress();
+ const int byte_array_length = byte_array.length();
+ ptrdiff_t offset = 0;
+
+ while (offset < byte_array_length) {
+ const byte* const pc = code_base + offset;
+ PrintF("%p %4" V8PRIxPTRDIFF " ", pc, offset);
+ DisassembleSingleBytecode(code_base, pc);
+ offset += RegExpBytecodeLength(*pc);
+ }
+}
+
+// static
IrregexpInterpreter::Result IrregexpInterpreter::Match(
- Isolate* isolate, Handle<ByteArray> code_array,
- Handle<String> subject_string, int* registers, int start_position) {
- DCHECK(subject_string->IsFlat());
+ Isolate* isolate, JSRegExp regexp, String subject_string, int* registers,
+ int registers_length, int start_position, RegExp::CallOrigin call_origin) {
+ if (FLAG_regexp_tier_up) {
+ regexp.MarkTierUpForNextExec();
+ }
+
+ bool is_one_byte = String::IsOneByteRepresentationUnderneath(subject_string);
+ ByteArray code_array = ByteArray::cast(regexp.Bytecode(is_one_byte));
- // Note: Heap allocation *is* allowed in two situations:
+ return MatchInternal(isolate, code_array, subject_string, registers,
+ registers_length, start_position, call_origin);
+}
+
+IrregexpInterpreter::Result IrregexpInterpreter::MatchInternal(
+ Isolate* isolate, ByteArray code_array, String subject_string,
+ int* registers, int registers_length, int start_position,
+ RegExp::CallOrigin call_origin) {
+ DCHECK(subject_string.IsFlat());
+
+ // Note: Heap allocation *is* allowed in two situations if calling from
+ // Runtime:
// 1. When creating & throwing a stack overflow exception. The interpreter
// aborts afterwards, and thus possible-moved objects are never used.
// 2. When handling interrupts. We manually relocate unhandlified references
// after interrupts have run.
DisallowHeapAllocation no_gc;
+ // Reset registers to -1 (=undefined).
+ // This is necessary because registers are only written when a
+ // capture group matched.
+ // Resetting them ensures that previous matches are cleared.
+ memset(registers, -1, sizeof(registers[0]) * registers_length);
+
uc16 previous_char = '\n';
- String::FlatContent subject_content = subject_string->GetFlatContent(no_gc);
+ String::FlatContent subject_content = subject_string.GetFlatContent(no_gc);
if (subject_content.IsOneByte()) {
Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
if (start_position != 0) previous_char = subject_vector[start_position - 1];
return RawMatch(isolate, code_array, subject_string, subject_vector,
- registers, start_position, previous_char);
+ registers, start_position, previous_char, call_origin);
} else {
DCHECK(subject_content.IsTwoByte());
Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
if (start_position != 0) previous_char = subject_vector[start_position - 1];
return RawMatch(isolate, code_array, subject_string, subject_vector,
- registers, start_position, previous_char);
+ registers, start_position, previous_char, call_origin);
}
}
+// This method is called through an external reference from RegExpExecInternal
+// builtin.
+IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromJs(
+ Address subject, int32_t start_position, Address, Address, int* registers,
+ int32_t registers_length, Address, RegExp::CallOrigin call_origin,
+ Isolate* isolate, Address regexp) {
+ DCHECK_NOT_NULL(isolate);
+ DCHECK_NOT_NULL(registers);
+ DCHECK(call_origin == RegExp::CallOrigin::kFromJs);
+
+ DisallowHeapAllocation no_gc;
+ DisallowJavascriptExecution no_js(isolate);
+
+ String subject_string = String::cast(Object(subject));
+ JSRegExp regexp_obj = JSRegExp::cast(Object(regexp));
+
+ return Match(isolate, regexp_obj, subject_string, registers, registers_length,
+ start_position, call_origin);
+}
+
+IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromRuntime(
+ Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> subject_string,
+ int* registers, int registers_length, int start_position) {
+ return Match(isolate, *regexp, *subject_string, registers, registers_length,
+ start_position, RegExp::CallOrigin::kFromRuntime);
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/regexp/regexp-interpreter.h b/deps/v8/src/regexp/regexp-interpreter.h
index ad27dcd296..fbc5a3b290 100644
--- a/deps/v8/src/regexp/regexp-interpreter.h
+++ b/deps/v8/src/regexp/regexp-interpreter.h
@@ -12,7 +12,7 @@
namespace v8 {
namespace internal {
-class V8_EXPORT_PRIVATE IrregexpInterpreter {
+class V8_EXPORT_PRIVATE IrregexpInterpreter : public AllStatic {
public:
enum Result {
FAILURE = RegExp::kInternalRegExpFailure,
@@ -21,10 +21,37 @@ class V8_EXPORT_PRIVATE IrregexpInterpreter {
RETRY = RegExp::kInternalRegExpRetry,
};
- // The caller is responsible for initializing registers before each call.
- static Result Match(Isolate* isolate, Handle<ByteArray> code_array,
- Handle<String> subject_string, int* registers,
- int start_position);
+ // In case a StackOverflow occurs, a StackOverflowException is created and
+ // EXCEPTION is returned.
+ static Result MatchForCallFromRuntime(Isolate* isolate,
+ Handle<JSRegExp> regexp,
+ Handle<String> subject_string,
+ int* registers, int registers_length,
+ int start_position);
+
+ // In case a StackOverflow occurs, EXCEPTION is returned. The caller is
+ // responsible for creating the exception.
+ // Arguments input_start, input_end and backtrack_stack are
+ // unused. They are only passed to match the signature of the native irregex
+ // code.
+ static Result MatchForCallFromJs(Address subject, int32_t start_position,
+ Address input_start, Address input_end,
+ int* registers, int32_t registers_length,
+ Address backtrack_stack,
+ RegExp::CallOrigin call_origin,
+ Isolate* isolate, Address regexp);
+
+ static Result MatchInternal(Isolate* isolate, ByteArray code_array,
+ String subject_string, int* registers,
+ int registers_length, int start_position,
+ RegExp::CallOrigin call_origin);
+
+ static void Disassemble(ByteArray byte_array, const std::string& pattern);
+
+ private:
+ static Result Match(Isolate* isolate, JSRegExp regexp, String subject_string,
+ int* registers, int registers_length, int start_position,
+ RegExp::CallOrigin call_origin);
};
} // namespace internal
diff --git a/deps/v8/src/regexp/regexp-macro-assembler-tracer.cc b/deps/v8/src/regexp/regexp-macro-assembler-tracer.cc
index db9c5af569..5dca04a18c 100644
--- a/deps/v8/src/regexp/regexp-macro-assembler-tracer.cc
+++ b/deps/v8/src/regexp/regexp-macro-assembler-tracer.cc
@@ -162,24 +162,19 @@ void RegExpMacroAssemblerTracer::ReadStackPointerFromRegister(int reg) {
assembler_->ReadStackPointerFromRegister(reg);
}
-
-void RegExpMacroAssemblerTracer::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
+void RegExpMacroAssemblerTracer::LoadCurrentCharacterImpl(
+ int cp_offset, Label* on_end_of_input, bool check_bounds, int characters,
+ int eats_at_least) {
const char* check_msg = check_bounds ? "" : " (unchecked)";
- PrintF(" LoadCurrentCharacter(cp_offset=%d, label[%08x]%s (%d chars));\n",
- cp_offset,
- LabelToInt(on_end_of_input),
- check_msg,
- characters);
- assembler_->LoadCurrentCharacter(cp_offset,
- on_end_of_input,
- check_bounds,
- characters);
+ PrintF(
+ " LoadCurrentCharacter(cp_offset=%d, label[%08x]%s (%d chars) (eats at "
+ "least %d));\n",
+ cp_offset, LabelToInt(on_end_of_input), check_msg, characters,
+ eats_at_least);
+ assembler_->LoadCurrentCharacter(cp_offset, on_end_of_input, check_bounds,
+ characters, eats_at_least);
}
-
class PrintablePrinter {
public:
explicit PrintablePrinter(uc16 character) : character_(character) { }
@@ -232,13 +227,13 @@ void RegExpMacroAssemblerTracer::CheckCharacter(unsigned c, Label* on_equal) {
assembler_->CheckCharacter(c, on_equal);
}
-
-void RegExpMacroAssemblerTracer::CheckAtStart(Label* on_at_start) {
- PrintF(" CheckAtStart(label[%08x]);\n", LabelToInt(on_at_start));
- assembler_->CheckAtStart(on_at_start);
+void RegExpMacroAssemblerTracer::CheckAtStart(int cp_offset,
+ Label* on_at_start) {
+ PrintF(" CheckAtStart(cp_offset=%d, label[%08x]);\n", cp_offset,
+ LabelToInt(on_at_start));
+ assembler_->CheckAtStart(cp_offset, on_at_start);
}
-
void RegExpMacroAssemblerTracer::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
PrintF(" CheckNotAtStart(cp_offset=%d, label[%08x]);\n", cp_offset,
diff --git a/deps/v8/src/regexp/regexp-macro-assembler-tracer.h b/deps/v8/src/regexp/regexp-macro-assembler-tracer.h
index d0b68bd59d..2a44146e73 100644
--- a/deps/v8/src/regexp/regexp-macro-assembler-tracer.h
+++ b/deps/v8/src/regexp/regexp-macro-assembler-tracer.h
@@ -22,13 +22,13 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
void AdvanceRegister(int reg, int by) override; // r[reg] += by.
void Backtrack() override;
void Bind(Label* label) override;
- void CheckAtStart(Label* on_at_start) override;
void CheckCharacter(unsigned c, Label* on_equal) override;
void CheckCharacterAfterAnd(unsigned c, unsigned and_with,
Label* on_equal) override;
void CheckCharacterGT(uc16 limit, Label* on_greater) override;
void CheckCharacterLT(uc16 limit, Label* on_less) override;
void CheckGreedyLoop(Label* on_tos_equals_current_position) override;
+ void CheckAtStart(int cp_offset, Label* on_at_start) override;
void CheckNotAtStart(int cp_offset, Label* on_not_at_start) override;
void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match) override;
@@ -53,9 +53,9 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
void IfRegisterLT(int reg, int comparand, Label* if_lt) override;
void IfRegisterEqPos(int reg, Label* if_eq) override;
IrregexpImplementation Implementation() override;
- void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1) override;
+ void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least) override;
void PopCurrentPosition() override;
void PopRegister(int register_index) override;
void PushBacktrack(Label* label) override;
diff --git a/deps/v8/src/regexp/regexp-macro-assembler.cc b/deps/v8/src/regexp/regexp-macro-assembler.cc
index 68fa16db61..96fb53d2a0 100644
--- a/deps/v8/src/regexp/regexp-macro-assembler.cc
+++ b/deps/v8/src/regexp/regexp-macro-assembler.cc
@@ -85,6 +85,20 @@ void RegExpMacroAssembler::CheckPosition(int cp_offset,
LoadCurrentCharacter(cp_offset, on_outside_input, true);
}
+void RegExpMacroAssembler::LoadCurrentCharacter(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ // By default, eats_at_least = characters.
+ if (eats_at_least == kUseCharactersValue) {
+ eats_at_least = characters;
+ }
+
+ LoadCurrentCharacterImpl(cp_offset, on_end_of_input, check_bounds, characters,
+ eats_at_least);
+}
+
bool RegExpMacroAssembler::CheckSpecialCharacterClass(uc16 type,
Label* on_no_match) {
return false;
@@ -129,32 +143,46 @@ const byte* NativeRegExpMacroAssembler::StringCharacterPosition(
}
}
+// This method may only be called after an interrupt.
int NativeRegExpMacroAssembler::CheckStackGuardState(
- Isolate* isolate, int start_index, bool is_direct_call,
+ Isolate* isolate, int start_index, RegExp::CallOrigin call_origin,
Address* return_address, Code re_code, Address* subject,
const byte** input_start, const byte** input_end) {
DisallowHeapAllocation no_gc;
DCHECK(re_code.raw_instruction_start() <= *return_address);
DCHECK(*return_address <= re_code.raw_instruction_end());
- int return_value = 0;
- // Prepare for possible GC.
- HandleScope handles(isolate);
- Handle<Code> code_handle(re_code, isolate);
- Handle<String> subject_handle(String::cast(Object(*subject)), isolate);
- bool is_one_byte = String::IsOneByteRepresentationUnderneath(*subject_handle);
-
StackLimitCheck check(isolate);
bool js_has_overflowed = check.JsHasOverflowed();
- if (is_direct_call) {
+ if (call_origin == RegExp::CallOrigin::kFromJs) {
// Direct calls from JavaScript can be interrupted in two ways:
// 1. A real stack overflow, in which case we let the caller throw the
// exception.
// 2. The stack guard was used to interrupt execution for another purpose,
// forcing the call through the runtime system.
- return_value = js_has_overflowed ? EXCEPTION : RETRY;
- } else if (js_has_overflowed) {
+
+ // Bug(v8:9540) Investigate why this method is called from JS although no
+ // stackoverflow or interrupt is pending on ARM64. We return 0 in this case
+ // to continue execution normally.
+ if (js_has_overflowed) {
+ return EXCEPTION;
+ } else if (check.InterruptRequested()) {
+ return RETRY;
+ } else {
+ return 0;
+ }
+ }
+ DCHECK(call_origin == RegExp::CallOrigin::kFromRuntime);
+
+ // Prepare for possible GC.
+ HandleScope handles(isolate);
+ Handle<Code> code_handle(re_code, isolate);
+ Handle<String> subject_handle(String::cast(Object(*subject)), isolate);
+ bool is_one_byte = String::IsOneByteRepresentationUnderneath(*subject_handle);
+ int return_value = 0;
+
+ if (js_has_overflowed) {
AllowHeapAllocation yes_gc;
isolate->StackOverflow();
return_value = EXCEPTION;
@@ -191,7 +219,7 @@ int NativeRegExpMacroAssembler::CheckStackGuardState(
}
// Returns a {Result} sentinel, or the number of successful matches.
-int NativeRegExpMacroAssembler::Match(Handle<Code> regexp_code,
+int NativeRegExpMacroAssembler::Match(Handle<JSRegExp> regexp,
Handle<String> subject,
int* offsets_vector,
int offsets_vector_length,
@@ -234,31 +262,36 @@ int NativeRegExpMacroAssembler::Match(Handle<Code> regexp_code,
StringCharacterPosition(subject_ptr, start_offset + slice_offset, no_gc);
int byte_length = char_length << char_size_shift;
const byte* input_end = input_start + byte_length;
- return Execute(*regexp_code, *subject, start_offset, input_start, input_end,
- offsets_vector, offsets_vector_length, isolate);
+ return Execute(*subject, start_offset, input_start, input_end, offsets_vector,
+ offsets_vector_length, isolate, *regexp);
}
// Returns a {Result} sentinel, or the number of successful matches.
+// TODO(pthier): The JSRegExp object is passed to native irregexp code to match
+// the signature of the interpreter. We should get rid of JS objects passed to
+// internal methods.
int NativeRegExpMacroAssembler::Execute(
- Code code,
String input, // This needs to be the unpacked (sliced, cons) string.
int start_offset, const byte* input_start, const byte* input_end,
- int* output, int output_size, Isolate* isolate) {
+ int* output, int output_size, Isolate* isolate, JSRegExp regexp) {
// Ensure that the minimum stack has been allocated.
RegExpStackScope stack_scope(isolate);
Address stack_base = stack_scope.stack()->stack_base();
- int direct_call = 0;
+ bool is_one_byte = String::IsOneByteRepresentationUnderneath(input);
+ Code code = Code::cast(regexp.Code(is_one_byte));
+ RegExp::CallOrigin call_origin = RegExp::CallOrigin::kFromRuntime;
using RegexpMatcherSig = int(
Address input_string, int start_offset, // NOLINT(readability/casting)
const byte* input_start, const byte* input_end, int* output,
- int output_size, Address stack_base, int direct_call, Isolate* isolate);
+ int output_size, Address stack_base, int call_origin, Isolate* isolate,
+ Address regexp);
auto fn = GeneratedCode<RegexpMatcherSig>::FromCode(code);
- int result =
- fn.CallIrregexp(input.ptr(), start_offset, input_start, input_end, output,
- output_size, stack_base, direct_call, isolate);
+ int result = fn.CallIrregexp(input.ptr(), start_offset, input_start,
+ input_end, output, output_size, stack_base,
+ call_origin, isolate, regexp.ptr());
DCHECK(result >= RETRY);
if (result == EXCEPTION && !isolate->has_pending_exception()) {
diff --git a/deps/v8/src/regexp/regexp-macro-assembler.h b/deps/v8/src/regexp/regexp-macro-assembler.h
index b55ac13590..ccf19d3fb6 100644
--- a/deps/v8/src/regexp/regexp-macro-assembler.h
+++ b/deps/v8/src/regexp/regexp-macro-assembler.h
@@ -36,6 +36,8 @@ class RegExpMacroAssembler {
static const int kTableSize = 1 << kTableSizeBits;
static const int kTableMask = kTableSize - 1;
+ static constexpr int kUseCharactersValue = -1;
+
enum IrregexpImplementation {
kIA32Implementation,
kARMImplementation,
@@ -69,7 +71,6 @@ class RegExpMacroAssembler {
// stack by an earlier PushBacktrack(Label*).
virtual void Backtrack() = 0;
virtual void Bind(Label* label) = 0;
- virtual void CheckAtStart(Label* on_at_start) = 0;
// Dispatch after looking the current character up in a 2-bits-per-entry
// map. The destinations vector has up to 4 labels.
virtual void CheckCharacter(unsigned c, Label* on_equal) = 0;
@@ -81,6 +82,7 @@ class RegExpMacroAssembler {
virtual void CheckCharacterGT(uc16 limit, Label* on_greater) = 0;
virtual void CheckCharacterLT(uc16 limit, Label* on_less) = 0;
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position) = 0;
+ virtual void CheckAtStart(int cp_offset, Label* on_at_start) = 0;
virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start) = 0;
virtual void CheckNotBackReference(int start_reg, bool read_backward,
Label* on_no_match) = 0;
@@ -133,10 +135,12 @@ class RegExpMacroAssembler {
// label if it is.
virtual void IfRegisterEqPos(int reg, Label* if_eq) = 0;
virtual IrregexpImplementation Implementation() = 0;
- virtual void LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1) = 0;
+ V8_EXPORT_PRIVATE void LoadCurrentCharacter(
+ int cp_offset, Label* on_end_of_input, bool check_bounds = true,
+ int characters = 1, int eats_at_least = kUseCharactersValue);
+ virtual void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least) = 0;
virtual void PopCurrentPosition() = 0;
virtual void PopRegister(int register_index) = 0;
// Pushes the label on the backtrack stack, so that a following Backtrack
@@ -219,7 +223,7 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
bool CanReadUnaligned() override;
// Returns a {Result} sentinel, or the number of successful matches.
- static int Match(Handle<Code> regexp, Handle<String> subject,
+ static int Match(Handle<JSRegExp> regexp, Handle<String> subject,
int* offsets_vector, int offsets_vector_length,
int previous_index, Isolate* isolate);
@@ -235,9 +239,9 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
String subject, int start_index, const DisallowHeapAllocation& no_gc);
static int CheckStackGuardState(Isolate* isolate, int start_index,
- bool is_direct_call, Address* return_address,
- Code re_code, Address* subject,
- const byte** input_start,
+ RegExp::CallOrigin call_origin,
+ Address* return_address, Code re_code,
+ Address* subject, const byte** input_start,
const byte** input_end);
// Byte map of one byte characters with a 0xff if the character is a word
@@ -250,11 +254,11 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
}
// Returns a {Result} sentinel, or the number of successful matches.
- V8_EXPORT_PRIVATE static int Execute(Code code, String input,
- int start_offset,
+ V8_EXPORT_PRIVATE static int Execute(String input, int start_offset,
const byte* input_start,
const byte* input_end, int* output,
- int output_size, Isolate* isolate);
+ int output_size, Isolate* isolate,
+ JSRegExp regexp);
};
} // namespace internal
diff --git a/deps/v8/src/regexp/regexp-nodes.h b/deps/v8/src/regexp/regexp-nodes.h
index 4c13b74926..d618c9bb27 100644
--- a/deps/v8/src/regexp/regexp-nodes.h
+++ b/deps/v8/src/regexp/regexp-nodes.h
@@ -20,11 +20,14 @@ class QuickCheckDetails;
class RegExpCompiler;
class Trace;
struct PreloadState;
+class ChoiceNode;
#define FOR_EACH_NODE_TYPE(VISIT) \
VISIT(End) \
VISIT(Action) \
VISIT(Choice) \
+ VISIT(LoopChoice) \
+ VISIT(NegativeLookaroundChoice) \
VISIT(BackReference) \
VISIT(Assertion) \
VISIT(Text)
@@ -90,6 +93,34 @@ struct NodeInfo final {
bool replacement_calculated : 1;
};
+struct EatsAtLeastInfo final {
+ EatsAtLeastInfo() : EatsAtLeastInfo(0) {}
+ explicit EatsAtLeastInfo(uint8_t eats)
+ : eats_at_least_from_possibly_start(eats),
+ eats_at_least_from_not_start(eats) {}
+ void SetMin(const EatsAtLeastInfo& other) {
+ if (other.eats_at_least_from_possibly_start <
+ eats_at_least_from_possibly_start) {
+ eats_at_least_from_possibly_start =
+ other.eats_at_least_from_possibly_start;
+ }
+ if (other.eats_at_least_from_not_start < eats_at_least_from_not_start) {
+ eats_at_least_from_not_start = other.eats_at_least_from_not_start;
+ }
+ }
+
+ // Any successful match starting from the current node will consume at least
+ // this many characters. This does not necessarily mean that there is a
+ // possible match with exactly this many characters, but we generally try to
+ // get this number as high as possible to allow for early exit on failure.
+ uint8_t eats_at_least_from_possibly_start;
+
+ // Like eats_at_least_from_possibly_start, but with the additional assumption
+ // that start-of-string assertions (^) can't match. This value is greater than
+ // or equal to eats_at_least_from_possibly_start.
+ uint8_t eats_at_least_from_not_start;
+};
+
class RegExpNode : public ZoneObject {
public:
explicit RegExpNode(Zone* zone)
@@ -104,13 +135,20 @@ class RegExpNode : public ZoneObject {
// Generates a goto to this node or actually generates the code at this point.
virtual void Emit(RegExpCompiler* compiler, Trace* trace) = 0;
// How many characters must this node consume at a minimum in order to
- // succeed. If we have found at least 'still_to_find' characters that
- // must be consumed there is no need to ask any following nodes whether
- // they are sure to eat any more characters. The not_at_start argument is
- // used to indicate that we know we are not at the start of the input. In
- // this case anchored branches will always fail and can be ignored when
- // determining how many characters are consumed on success.
- virtual int EatsAtLeast(int still_to_find, int budget, bool not_at_start) = 0;
+ // succeed. The not_at_start argument is used to indicate that we know we are
+ // not at the start of the input. In this case anchored branches will always
+ // fail and can be ignored when determining how many characters are consumed
+ // on success. If this node has not been analyzed yet, EatsAtLeast returns 0.
+ int EatsAtLeast(bool not_at_start);
+ // Returns how many characters this node must consume in order to succeed,
+ // given that this is a LoopChoiceNode whose counter register is in a
+ // newly-initialized state at the current position in the generated code. For
+ // example, consider /a{6,8}/. Absent any extra information, the
+ // LoopChoiceNode for the repetition must report that it consumes at least
+ // zero characters, because it may have already looped several times. However,
+ // with a newly-initialized counter, it can report that it consumes at least
+ // six characters.
+ virtual EatsAtLeastInfo EatsAtLeastFromLoopEntry();
// Emits some quick code that checks whether the preloaded characters match.
// Falls through on certain failure, jumps to the label on possible success.
// If the node cannot make a quick check it does nothing and returns false.
@@ -118,7 +156,7 @@ class RegExpNode : public ZoneObject {
Trace* trace, bool preload_has_checked_bounds,
Label* on_possible_success,
QuickCheckDetails* details_return,
- bool fall_through_on_failure);
+ bool fall_through_on_failure, ChoiceNode* predecessor);
// For a given number of characters this returns a mask and a value. The
// next n characters are anded with the mask and compared with the value.
// A comparison failure indicates the node cannot match the next n characters.
@@ -127,6 +165,17 @@ class RegExpNode : public ZoneObject {
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start) = 0;
+ // Fills in quick check details for this node, given that this is a
+ // LoopChoiceNode whose counter register is in a newly-initialized state at
+ // the current position in the generated code. For example, consider /a{6,8}/.
+ // Absent any extra information, the LoopChoiceNode for the repetition cannot
+ // generate any useful quick check because a match might be the (empty)
+ // continuation node. However, with a newly-initialized counter, it can
+ // generate a quick check for several 'a' characters at once.
+ virtual void GetQuickCheckDetailsFromLoopEntry(QuickCheckDetails* details,
+ RegExpCompiler* compiler,
+ int characters_filled_in,
+ bool not_at_start);
static const int kNodeIsTooComplexForGreedyLoops = kMinInt;
virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
// Only returns the successor for a text node of length 1 that matches any
@@ -183,6 +232,10 @@ class RegExpNode : public ZoneObject {
void set_on_work_list(bool value) { on_work_list_ = value; }
NodeInfo* info() { return &info_; }
+ const EatsAtLeastInfo* eats_at_least_info() const { return &eats_at_least_; }
+ void set_eats_at_least_info(const EatsAtLeastInfo& eats_at_least) {
+ eats_at_least_ = eats_at_least;
+ }
BoyerMooreLookahead* bm_info(bool not_at_start) {
return bm_info_[not_at_start ? 1 : 0];
@@ -205,6 +258,11 @@ class RegExpNode : public ZoneObject {
Label label_;
bool on_work_list_;
NodeInfo info_;
+
+ // Saved values for EatsAtLeast results, to avoid recomputation. Filled in
+ // during analysis (valid if info_.been_analyzed is true).
+ EatsAtLeastInfo eats_at_least_;
+
// This variable keeps track of how many times code has been generated for
// this node (in different traces). We don't keep track of where the
// generated code is located unless the code is generated at the start of
@@ -239,7 +297,7 @@ class SeqRegExpNode : public RegExpNode {
class ActionNode : public SeqRegExpNode {
public:
enum ActionType {
- SET_REGISTER,
+ SET_REGISTER_FOR_LOOP,
INCREMENT_REGISTER,
STORE_POSITION,
BEGIN_SUBMATCH,
@@ -247,7 +305,8 @@ class ActionNode : public SeqRegExpNode {
EMPTY_MATCH_CHECK,
CLEAR_CAPTURES
};
- static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success);
+ static ActionNode* SetRegisterForLoop(int reg, int val,
+ RegExpNode* on_success);
static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
static ActionNode* StorePosition(int reg, bool is_capture,
RegExpNode* on_success);
@@ -265,13 +324,9 @@ class ActionNode : public SeqRegExpNode {
RegExpNode* on_success);
void Accept(NodeVisitor* visitor) override;
void Emit(RegExpCompiler* compiler, Trace* trace) override;
- int EatsAtLeast(int still_to_find, int budget, bool not_at_start) override;
void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, int filled_in,
- bool not_at_start) override {
- return on_success()->GetQuickCheckDetails(details, compiler, filled_in,
- not_at_start);
- }
+ bool not_at_start) override;
void FillInBMInfo(Isolate* isolate, int offset, int budget,
BoyerMooreLookahead* bm, bool not_at_start) override;
ActionType action_type() { return action_type_; }
@@ -342,7 +397,6 @@ class TextNode : public SeqRegExpNode {
JSRegExp::Flags flags);
void Accept(NodeVisitor* visitor) override;
void Emit(RegExpCompiler* compiler, Trace* trace) override;
- int EatsAtLeast(int still_to_find, int budget, bool not_at_start) override;
void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, int characters_filled_in,
bool not_at_start) override;
@@ -356,6 +410,7 @@ class TextNode : public SeqRegExpNode {
BoyerMooreLookahead* bm, bool not_at_start) override;
void CalculateOffsets();
RegExpNode* FilterOneByte(int depth) override;
+ int Length();
private:
enum TextEmitPassType {
@@ -371,7 +426,6 @@ class TextNode : public SeqRegExpNode {
void TextEmitPass(RegExpCompiler* compiler, TextEmitPassType pass,
bool preloaded, Trace* trace, bool first_element_checked,
int* checked_up_to);
- int Length();
ZoneList<TextElement>* elms_;
bool read_backward_;
};
@@ -402,7 +456,6 @@ class AssertionNode : public SeqRegExpNode {
}
void Accept(NodeVisitor* visitor) override;
void Emit(RegExpCompiler* compiler, Trace* trace) override;
- int EatsAtLeast(int still_to_find, int budget, bool not_at_start) override;
void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, int filled_in,
bool not_at_start) override;
@@ -434,8 +487,6 @@ class BackReferenceNode : public SeqRegExpNode {
int end_register() { return end_reg_; }
bool read_backward() { return read_backward_; }
void Emit(RegExpCompiler* compiler, Trace* trace) override;
- int EatsAtLeast(int still_to_find, int recursion_depth,
- bool not_at_start) override;
void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, int characters_filled_in,
bool not_at_start) override {
@@ -457,10 +508,6 @@ class EndNode : public RegExpNode {
EndNode(Action action, Zone* zone) : RegExpNode(zone), action_(action) {}
void Accept(NodeVisitor* visitor) override;
void Emit(RegExpCompiler* compiler, Trace* trace) override;
- int EatsAtLeast(int still_to_find, int recursion_depth,
- bool not_at_start) override {
- return 0;
- }
void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, int characters_filled_in,
bool not_at_start) override {
@@ -540,9 +587,6 @@ class ChoiceNode : public RegExpNode {
}
ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
void Emit(RegExpCompiler* compiler, Trace* trace) override;
- int EatsAtLeast(int still_to_find, int budget, bool not_at_start) override;
- int EatsAtLeastHelper(int still_to_find, int budget,
- RegExpNode* ignore_this_node, bool not_at_start);
void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, int characters_filled_in,
bool not_at_start) override;
@@ -564,6 +608,7 @@ class ChoiceNode : public RegExpNode {
ZoneList<GuardedAlternative>* alternatives_;
private:
+ template <typename...>
friend class Analysis;
void GenerateGuard(RegExpMacroAssembler* macro_assembler, Guard* guard,
@@ -601,16 +646,23 @@ class NegativeLookaroundChoiceNode : public ChoiceNode {
AddAlternative(this_must_fail);
AddAlternative(then_do_this);
}
- int EatsAtLeast(int still_to_find, int budget, bool not_at_start) override;
void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, int characters_filled_in,
bool not_at_start) override;
void FillInBMInfo(Isolate* isolate, int offset, int budget,
BoyerMooreLookahead* bm, bool not_at_start) override {
- alternatives_->at(1).node()->FillInBMInfo(isolate, offset, budget - 1, bm,
- not_at_start);
+ continue_node()->FillInBMInfo(isolate, offset, budget - 1, bm,
+ not_at_start);
if (offset == 0) set_bm_info(not_at_start, bm);
}
+ static constexpr int kLookaroundIndex = 0;
+ static constexpr int kContinueIndex = 1;
+ RegExpNode* lookaround_node() {
+ return alternatives()->at(kLookaroundIndex).node();
+ }
+ RegExpNode* continue_node() {
+ return alternatives()->at(kContinueIndex).node();
+ }
// For a negative lookahead we don't emit the quick check for the
// alternative that is expected to fail. This is because quick check code
// starts by loading enough characters for the alternative that takes fewest
@@ -619,29 +671,38 @@ class NegativeLookaroundChoiceNode : public ChoiceNode {
bool try_to_emit_quick_check_for_alternative(bool is_first) override {
return !is_first;
}
+ void Accept(NodeVisitor* visitor) override;
RegExpNode* FilterOneByte(int depth) override;
};
class LoopChoiceNode : public ChoiceNode {
public:
- LoopChoiceNode(bool body_can_be_zero_length, bool read_backward, Zone* zone)
+ LoopChoiceNode(bool body_can_be_zero_length, bool read_backward,
+ int min_loop_iterations, Zone* zone)
: ChoiceNode(2, zone),
loop_node_(nullptr),
continue_node_(nullptr),
body_can_be_zero_length_(body_can_be_zero_length),
- read_backward_(read_backward) {}
+ read_backward_(read_backward),
+ traversed_loop_initialization_node_(false),
+ min_loop_iterations_(min_loop_iterations) {}
void AddLoopAlternative(GuardedAlternative alt);
void AddContinueAlternative(GuardedAlternative alt);
void Emit(RegExpCompiler* compiler, Trace* trace) override;
- int EatsAtLeast(int still_to_find, int budget, bool not_at_start) override;
void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler, int characters_filled_in,
bool not_at_start) override;
+ void GetQuickCheckDetailsFromLoopEntry(QuickCheckDetails* details,
+ RegExpCompiler* compiler,
+ int characters_filled_in,
+ bool not_at_start) override;
void FillInBMInfo(Isolate* isolate, int offset, int budget,
BoyerMooreLookahead* bm, bool not_at_start) override;
+ EatsAtLeastInfo EatsAtLeastFromLoopEntry() override;
RegExpNode* loop_node() { return loop_node_; }
RegExpNode* continue_node() { return continue_node_; }
bool body_can_be_zero_length() { return body_can_be_zero_length_; }
+ int min_loop_iterations() const { return min_loop_iterations_; }
bool read_backward() override { return read_backward_; }
void Accept(NodeVisitor* visitor) override;
RegExpNode* FilterOneByte(int depth) override;
@@ -658,6 +719,22 @@ class LoopChoiceNode : public ChoiceNode {
RegExpNode* continue_node_;
bool body_can_be_zero_length_;
bool read_backward_;
+
+ // Temporary marker set only while generating quick check details. Represents
+ // whether GetQuickCheckDetails traversed the initialization node for this
+ // loop's counter. If so, we may be able to generate stricter quick checks
+ // because we know the loop node must match at least min_loop_iterations_
+ // times before the continuation node can match.
+ bool traversed_loop_initialization_node_;
+
+ // The minimum number of times the loop_node_ must match before the
+ // continue_node_ might be considered. This value can be temporarily decreased
+ // while generating quick check details, to represent the remaining iterations
+ // after the completed portion of the quick check details.
+ int min_loop_iterations_;
+
+ friend class IterationDecrementer;
+ friend class LoopInitializationMarker;
};
class NodeVisitor {
@@ -666,7 +743,6 @@ class NodeVisitor {
#define DECLARE_VISIT(Type) virtual void Visit##Type(Type##Node* that) = 0;
FOR_EACH_NODE_TYPE(DECLARE_VISIT)
#undef DECLARE_VISIT
- virtual void VisitLoopChoice(LoopChoiceNode* that) { VisitChoice(that); }
};
} // namespace internal
diff --git a/deps/v8/src/regexp/regexp-parser.cc b/deps/v8/src/regexp/regexp-parser.cc
index 3647680969..d6e421cafa 100644
--- a/deps/v8/src/regexp/regexp-parser.cc
+++ b/deps/v8/src/regexp/regexp-parser.cc
@@ -692,7 +692,7 @@ RegExpParser::RegExpParserState* RegExpParser::ParseOpenParenthesis(
}
}
if (subexpr_type == CAPTURE) {
- if (captures_started_ >= kMaxCaptures) {
+ if (captures_started_ >= JSRegExp::kMaxCaptures) {
ReportError(CStrVector("Too many captures"));
return nullptr;
}
@@ -800,7 +800,7 @@ bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
uc32 c = current();
if (IsDecimalDigit(c)) {
value = 10 * value + (c - '0');
- if (value > kMaxCaptures) {
+ if (value > JSRegExp::kMaxCaptures) {
Reset(start);
return false;
}
diff --git a/deps/v8/src/regexp/regexp-parser.h b/deps/v8/src/regexp/regexp-parser.h
index 36cec7e984..cc1948b101 100644
--- a/deps/v8/src/regexp/regexp-parser.h
+++ b/deps/v8/src/regexp/regexp-parser.h
@@ -221,7 +221,6 @@ class V8_EXPORT_PRIVATE RegExpParser {
static bool IsSyntaxCharacterOrSlash(uc32 c);
- static const int kMaxCaptures = 1 << 16;
static const uc32 kEndMarker = (1 << 21);
private:
diff --git a/deps/v8/src/regexp/regexp-stack.cc b/deps/v8/src/regexp/regexp-stack.cc
index 3885fd8e8d..a6a128841f 100644
--- a/deps/v8/src/regexp/regexp-stack.cc
+++ b/deps/v8/src/regexp/regexp-stack.cc
@@ -72,12 +72,12 @@ Address RegExpStack::EnsureCapacity(size_t size) {
DeleteArray(thread_local_.memory_);
}
thread_local_.memory_ = new_memory;
+ thread_local_.memory_top_ = new_memory + size;
thread_local_.memory_size_ = size;
thread_local_.limit_ = reinterpret_cast<Address>(new_memory) +
kStackLimitSlack * kSystemPointerSize;
}
- return reinterpret_cast<Address>(thread_local_.memory_) +
- thread_local_.memory_size_;
+ return reinterpret_cast<Address>(thread_local_.memory_top_);
}
diff --git a/deps/v8/src/regexp/regexp-stack.h b/deps/v8/src/regexp/regexp-stack.h
index b1d4571760..7ecaa40b81 100644
--- a/deps/v8/src/regexp/regexp-stack.h
+++ b/deps/v8/src/regexp/regexp-stack.h
@@ -46,8 +46,9 @@ class RegExpStack {
// Gives the top of the memory used as stack.
Address stack_base() {
DCHECK_NE(0, thread_local_.memory_size_);
- return reinterpret_cast<Address>(thread_local_.memory_) +
- thread_local_.memory_size_;
+ DCHECK_EQ(thread_local_.memory_top_,
+ thread_local_.memory_ + thread_local_.memory_size_);
+ return reinterpret_cast<Address>(thread_local_.memory_top_);
}
// The total size of the memory allocated for the stack.
@@ -58,7 +59,7 @@ class RegExpStack {
// There is only a limited number of locations below the stack limit,
// so users of the stack should check the stack limit during any
// sequence of pushes longer that this.
- Address* limit_address() { return &(thread_local_.limit_); }
+ Address* limit_address_address() { return &(thread_local_.limit_); }
// Ensures that there is a memory area with at least the specified size.
// If passing zero, the default/minimum size buffer is allocated.
@@ -89,12 +90,15 @@ class RegExpStack {
// Structure holding the allocated memory, size and limit.
struct ThreadLocal {
ThreadLocal() { Clear(); }
- // If memory_size_ > 0 then memory_ must be non-nullptr.
+ // If memory_size_ > 0 then memory_ and memory_top_ must be non-nullptr
+ // and memory_top_ = memory_ + memory_size_
byte* memory_;
+ byte* memory_top_;
size_t memory_size_;
Address limit_;
void Clear() {
memory_ = nullptr;
+ memory_top_ = nullptr;
memory_size_ = 0;
limit_ = kMemoryTop;
}
@@ -102,7 +106,7 @@ class RegExpStack {
};
// Address of allocated memory.
- Address memory_address() {
+ Address memory_address_address() {
return reinterpret_cast<Address>(&thread_local_.memory_);
}
@@ -111,6 +115,11 @@ class RegExpStack {
return reinterpret_cast<Address>(&thread_local_.memory_size_);
}
+ // Address of top of memory used as stack.
+ Address memory_top_address_address() {
+ return reinterpret_cast<Address>(&thread_local_.memory_top_);
+ }
+
// Resets the buffer if it has grown beyond the default/minimum size.
// After this, the buffer is either the default size, or it is empty, so
// you have to call EnsureCapacity before using it again.
diff --git a/deps/v8/src/regexp/regexp-utils.cc b/deps/v8/src/regexp/regexp-utils.cc
index ad50270fdc..c9194d5170 100644
--- a/deps/v8/src/regexp/regexp-utils.cc
+++ b/deps/v8/src/regexp/regexp-utils.cc
@@ -5,6 +5,7 @@
#include "src/regexp/regexp-utils.h"
#include "src/execution/isolate.h"
+#include "src/execution/protectors-inl.h"
#include "src/heap/factory.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/objects-inl.h"
@@ -179,7 +180,14 @@ bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) {
return false;
}
- if (!isolate->IsRegExpSpeciesLookupChainIntact(isolate->native_context())) {
+ // Note: Unlike the more involved check in CSA (see BranchIfFastRegExp), this
+ // does not go on to check the actual value of the exec property. This would
+ // not be valid since this method is called from places that access the flags
+ // property. Similar spots in CSA would use BranchIfFastRegExp_Strict in this
+ // case.
+
+ if (!Protectors::IsRegExpSpeciesLookupChainProtectorIntact(
+ recv.GetCreationContext())) {
return false;
}
diff --git a/deps/v8/src/regexp/regexp-utils.h b/deps/v8/src/regexp/regexp-utils.h
index 4b8714c55f..19f1f24039 100644
--- a/deps/v8/src/regexp/regexp-utils.h
+++ b/deps/v8/src/regexp/regexp-utils.h
@@ -38,6 +38,9 @@ class RegExpUtils : public AllStatic {
// Checks whether the given object is an unmodified JSRegExp instance.
// Neither the object's map, nor its prototype's map, nor any relevant
// method on the prototype may be modified.
+ //
+ // Note: This check is limited may only be used in situations where the only
+ // relevant property is 'exec'.
static bool IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj);
// ES#sec-advancestringindex
diff --git a/deps/v8/src/regexp/regexp.cc b/deps/v8/src/regexp/regexp.cc
index 15b0321c46..e0bc4b8e32 100644
--- a/deps/v8/src/regexp/regexp.cc
+++ b/deps/v8/src/regexp/regexp.cc
@@ -5,6 +5,7 @@
#include "src/regexp/regexp.h"
#include "src/codegen/compilation-cache.h"
+#include "src/diagnostics/code-tracer.h"
#include "src/heap/heap-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/regexp/regexp-bytecode-generator.h"
@@ -14,6 +15,7 @@
#include "src/regexp/regexp-macro-assembler-arch.h"
#include "src/regexp/regexp-parser.h"
#include "src/strings/string-search.h"
+#include "src/utils/ostreams.h"
namespace v8 {
namespace internal {
@@ -298,29 +300,72 @@ Handle<Object> RegExpImpl::AtomExec(Isolate* isolate, Handle<JSRegExp> re,
bool RegExpImpl::EnsureCompiledIrregexp(Isolate* isolate, Handle<JSRegExp> re,
Handle<String> sample_subject,
bool is_one_byte) {
- Object compiled_code = re->DataAt(JSRegExp::code_index(is_one_byte));
- if (compiled_code != Smi::FromInt(JSRegExp::kUninitializedValue)) {
- DCHECK(FLAG_regexp_interpret_all ? compiled_code.IsByteArray()
- : compiled_code.IsCode());
+ Object compiled_code = re->Code(is_one_byte);
+ Object bytecode = re->Bytecode(is_one_byte);
+ bool needs_initial_compilation =
+ compiled_code == Smi::FromInt(JSRegExp::kUninitializedValue);
+ // Recompile is needed when we're dealing with the first execution of the
+ // regexp after the decision to tier up has been made. If the tiering up
+ // strategy is not in use, this value is always false.
+ bool needs_tier_up_compilation =
+ re->MarkedForTierUp() && bytecode.IsByteArray();
+
+ if (FLAG_trace_regexp_tier_up && needs_tier_up_compilation) {
+ PrintF("JSRegExp object %p needs tier-up compilation\n",
+ reinterpret_cast<void*>(re->ptr()));
+ }
+
+ if (!needs_initial_compilation && !needs_tier_up_compilation) {
+ DCHECK(compiled_code.IsCode());
+ DCHECK_IMPLIES(FLAG_regexp_interpret_all, bytecode.IsByteArray());
return true;
}
+
+ DCHECK_IMPLIES(needs_tier_up_compilation, bytecode.IsByteArray());
+
return CompileIrregexp(isolate, re, sample_subject, is_one_byte);
}
+#ifdef DEBUG
+namespace {
+
+bool RegExpCodeIsValidForPreCompilation(Handle<JSRegExp> re, bool is_one_byte) {
+ Object entry = re->Code(is_one_byte);
+ Object bytecode = re->Bytecode(is_one_byte);
+ // If we're not using the tier-up strategy, entry can only be a smi
+ // representing an uncompiled regexp here. If we're using the tier-up
+ // strategy, entry can still be a smi representing an uncompiled regexp, when
+ // compiling the regexp before the tier-up, or it can contain a trampoline to
+ // the regexp interpreter, in which case the bytecode field contains compiled
+ // bytecode, when recompiling the regexp after the tier-up. If the
+ // tier-up was forced, which happens for global replaces, entry is a smi
+ // representing an uncompiled regexp, even though we're "recompiling" after
+ // the tier-up.
+ if (re->ShouldProduceBytecode()) {
+ DCHECK(entry.IsSmi());
+ DCHECK(bytecode.IsSmi());
+ int entry_value = Smi::ToInt(entry);
+ int bytecode_value = Smi::ToInt(bytecode);
+ DCHECK_EQ(JSRegExp::kUninitializedValue, entry_value);
+ DCHECK_EQ(JSRegExp::kUninitializedValue, bytecode_value);
+ } else {
+ DCHECK(entry.IsSmi() || (entry.IsCode() && bytecode.IsByteArray()));
+ }
+
+ return true;
+}
+
+} // namespace
+#endif
+
bool RegExpImpl::CompileIrregexp(Isolate* isolate, Handle<JSRegExp> re,
Handle<String> sample_subject,
bool is_one_byte) {
// Compile the RegExp.
Zone zone(isolate->allocator(), ZONE_NAME);
PostponeInterruptsScope postpone(isolate);
-#ifdef DEBUG
- Object entry = re->DataAt(JSRegExp::code_index(is_one_byte));
- // When arriving here entry can only be a smi representing an uncompiled
- // regexp.
- DCHECK(entry.IsSmi());
- int entry_value = Smi::ToInt(entry);
- DCHECK_EQ(JSRegExp::kUninitializedValue, entry_value);
-#endif
+
+ DCHECK(RegExpCodeIsValidForPreCompilation(re, is_one_byte));
JSRegExp::Flags flags = re->GetFlags();
@@ -335,6 +380,14 @@ bool RegExpImpl::CompileIrregexp(Isolate* isolate, Handle<JSRegExp> re,
USE(ThrowRegExpException(isolate, re, pattern, compile_data.error));
return false;
}
+ // The compilation target is a kBytecode if we're interpreting all regexp
+ // objects, or if we're using the tier-up strategy but the tier-up hasn't
+ // happened yet. The compilation target is a kNative if we're using the
+ // tier-up strategy and we need to recompile to tier-up, or if we're producing
+ // native code for all regexp objects.
+ compile_data.compilation_target = re->ShouldProduceBytecode()
+ ? RegExpCompilationTarget::kBytecode
+ : RegExpCompilationTarget::kNative;
const bool compilation_succeeded =
Compile(isolate, &zone, &compile_data, flags, pattern, sample_subject,
is_one_byte);
@@ -346,13 +399,37 @@ bool RegExpImpl::CompileIrregexp(Isolate* isolate, Handle<JSRegExp> re,
Handle<FixedArray> data =
Handle<FixedArray>(FixedArray::cast(re->data()), isolate);
- data->set(JSRegExp::code_index(is_one_byte), compile_data.code);
+ if (compile_data.compilation_target == RegExpCompilationTarget::kNative) {
+ data->set(JSRegExp::code_index(is_one_byte), compile_data.code);
+ // Reset bytecode to uninitialized. In case we use tier-up we know that
+ // tier-up has happened this way.
+ data->set(JSRegExp::bytecode_index(is_one_byte),
+ Smi::FromInt(JSRegExp::kUninitializedValue));
+ } else {
+ DCHECK_EQ(compile_data.compilation_target,
+ RegExpCompilationTarget::kBytecode);
+ // Store code generated by compiler in bytecode and trampoline to
+ // interpreter in code.
+ data->set(JSRegExp::bytecode_index(is_one_byte), compile_data.code);
+ Handle<Code> trampoline =
+ BUILTIN_CODE(isolate, RegExpInterpreterTrampoline);
+ data->set(JSRegExp::code_index(is_one_byte), *trampoline);
+ }
SetIrregexpCaptureNameMap(*data, compile_data.capture_name_map);
int register_max = IrregexpMaxRegisterCount(*data);
if (compile_data.register_count > register_max) {
SetIrregexpMaxRegisterCount(*data, compile_data.register_count);
}
+ if (FLAG_trace_regexp_tier_up) {
+ PrintF("JSRegExp object %p %s size: %d\n",
+ reinterpret_cast<void*>(re->ptr()),
+ re->ShouldProduceBytecode() ? "bytecode" : "native code",
+ re->ShouldProduceBytecode()
+ ? IrregexpByteCode(*data, is_one_byte).Size()
+ : IrregexpNativeCode(*data, is_one_byte).Size());
+ }
+
return true;
}
@@ -382,7 +459,7 @@ int RegExpImpl::IrregexpNumberOfRegisters(FixedArray re) {
}
ByteArray RegExpImpl::IrregexpByteCode(FixedArray re, bool is_one_byte) {
- return ByteArray::cast(re.get(JSRegExp::code_index(is_one_byte)));
+ return ByteArray::cast(re.get(JSRegExp::bytecode_index(is_one_byte)));
}
Code RegExpImpl::IrregexpNativeCode(FixedArray re, bool is_one_byte) {
@@ -411,7 +488,7 @@ int RegExp::IrregexpPrepare(Isolate* isolate, Handle<JSRegExp> regexp,
DisallowHeapAllocation no_gc;
FixedArray data = FixedArray::cast(regexp->data());
- if (FLAG_regexp_interpret_all) {
+ if (regexp->ShouldProduceBytecode()) {
// Byte-code regexp needs space allocated for all its registers.
// The result captures are copied to the start of the registers array
// if the match succeeds. This way those registers are not clobbered
@@ -436,16 +513,15 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle<JSRegExp> regexp,
bool is_one_byte = String::IsOneByteRepresentationUnderneath(*subject);
- if (!FLAG_regexp_interpret_all) {
+ if (!regexp->ShouldProduceBytecode()) {
DCHECK(output_size >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2);
do {
EnsureCompiledIrregexp(isolate, regexp, subject, is_one_byte);
- Handle<Code> code(IrregexpNativeCode(*irregexp, is_one_byte), isolate);
// The stack is used to allocate registers for the compiled regexp code.
// This means that in case of failure, the output registers array is left
// untouched and contains the capture results from the previous successful
// match. We can use that to set the last match info lazily.
- int res = NativeRegExpMacroAssembler::Match(code, subject, output,
+ int res = NativeRegExpMacroAssembler::Match(regexp, subject, output,
output_size, index, isolate);
if (res != NativeRegExpMacroAssembler::RETRY) {
DCHECK(res != NativeRegExpMacroAssembler::EXCEPTION ||
@@ -464,12 +540,11 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle<JSRegExp> regexp,
// the, potentially, different subject (the string can switch between
// being internal and external, and even between being Latin1 and UC16,
// but the characters are always the same).
- RegExp::IrregexpPrepare(isolate, regexp, subject);
is_one_byte = String::IsOneByteRepresentationUnderneath(*subject);
} while (true);
UNREACHABLE();
} else {
- DCHECK(FLAG_regexp_interpret_all);
+ DCHECK(regexp->ShouldProduceBytecode());
DCHECK(output_size >= IrregexpNumberOfRegisters(*irregexp));
// We must have done EnsureCompiledIrregexp, so we can get the number of
// registers.
@@ -478,17 +553,10 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle<JSRegExp> regexp,
int32_t* raw_output = &output[number_of_capture_registers];
do {
- // We do not touch the actual capture result registers until we know there
- // has been a match so that we can use those capture results to set the
- // last match info.
- for (int i = number_of_capture_registers - 1; i >= 0; i--) {
- raw_output[i] = -1;
- }
- Handle<ByteArray> byte_codes(IrregexpByteCode(*irregexp, is_one_byte),
- isolate);
-
- IrregexpInterpreter::Result result = IrregexpInterpreter::Match(
- isolate, byte_codes, subject, raw_output, index);
+ IrregexpInterpreter::Result result =
+ IrregexpInterpreter::MatchForCallFromRuntime(
+ isolate, regexp, subject, raw_output, number_of_capture_registers,
+ index);
DCHECK_IMPLIES(result == IrregexpInterpreter::EXCEPTION,
isolate->has_pending_exception());
@@ -504,6 +572,10 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle<JSRegExp> regexp,
case IrregexpInterpreter::RETRY:
// The string has changed representation, and we must restart the
// match.
+ // We need to reset the tier up to start over with compilation.
+ if (FLAG_regexp_tier_up) {
+ regexp->ResetTierUp();
+ }
is_one_byte = String::IsOneByteRepresentationUnderneath(*subject);
EnsureCompiledIrregexp(isolate, regexp, subject, is_one_byte);
break;
@@ -520,14 +592,15 @@ MaybeHandle<Object> RegExpImpl::IrregexpExec(
subject = String::Flatten(isolate, subject);
- // Prepare space for the return values.
#ifdef DEBUG
- if (FLAG_regexp_interpret_all && FLAG_trace_regexp_bytecodes) {
+ if (FLAG_trace_regexp_bytecodes && regexp->ShouldProduceBytecode()) {
String pattern = regexp->Pattern();
PrintF("\n\nRegexp match: /%s/\n\n", pattern.ToCString().get());
PrintF("\n\nSubject string: '%s'\n\n", subject->ToCString().get());
}
#endif
+
+ // Prepare space for the return values.
int required_registers = RegExp::IrregexpPrepare(isolate, regexp, subject);
if (required_registers < 0) {
// Compiling failed with an exception.
@@ -547,6 +620,7 @@ MaybeHandle<Object> RegExpImpl::IrregexpExec(
int res =
RegExpImpl::IrregexpExecRaw(isolate, regexp, subject, previous_index,
output_registers, required_registers);
+
if (res == RegExp::RE_SUCCESS) {
int capture_count =
IrregexpNumberOfCaptures(FixedArray::cast(regexp->data()));
@@ -706,17 +780,14 @@ bool RegExpImpl::Compile(Isolate* isolate, Zone* zone, RegExpCompileData* data,
if (node == nullptr) node = new (zone) EndNode(EndNode::BACKTRACK, zone);
data->node = node;
- Analysis analysis(isolate, is_one_byte);
- analysis.EnsureAnalyzed(node);
- if (analysis.has_failed()) {
- data->error =
- isolate->factory()->NewStringFromAsciiChecked(analysis.error_message());
+ if (const char* error_message = AnalyzeRegExp(isolate, is_one_byte, node)) {
+ data->error = isolate->factory()->NewStringFromAsciiChecked(error_message);
return false;
}
// Create the correct assembler for the architecture.
std::unique_ptr<RegExpMacroAssembler> macro_assembler;
- if (!FLAG_regexp_interpret_all) {
+ if (data->compilation_target == RegExpCompilationTarget::kNative) {
// Native regexp implementation.
DCHECK(!FLAG_jitless);
@@ -752,8 +823,7 @@ bool RegExpImpl::Compile(Isolate* isolate, Zone* zone, RegExpCompileData* data,
#error "Unsupported architecture"
#endif
} else {
- DCHECK(FLAG_regexp_interpret_all);
-
+ DCHECK_EQ(data->compilation_target, RegExpCompilationTarget::kBytecode);
// Interpreted regexp implementation.
macro_assembler.reset(new RegExpBytecodeGenerator(isolate, zone));
}
@@ -781,6 +851,26 @@ bool RegExpImpl::Compile(Isolate* isolate, Zone* zone, RegExpCompileData* data,
RegExpCompiler::CompilationResult result = compiler.Assemble(
isolate, macro_assembler.get(), node, data->capture_count, pattern);
+ // Code / bytecode printing.
+ {
+#ifdef ENABLE_DISASSEMBLER
+ if (FLAG_print_regexp_code &&
+ data->compilation_target == RegExpCompilationTarget::kNative) {
+ CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
+ OFStream os(trace_scope.file());
+ Handle<Code> c(Code::cast(result.code), isolate);
+ auto pattern_cstring = pattern->ToCString();
+ c->Disassemble(pattern_cstring.get(), os);
+ }
+#endif
+ if (FLAG_print_regexp_bytecode &&
+ data->compilation_target == RegExpCompilationTarget::kBytecode) {
+ Handle<ByteArray> bytecode(ByteArray::cast(result.code), isolate);
+ auto pattern_cstring = pattern->ToCString();
+ IrregexpInterpreter::Disassemble(*bytecode, pattern_cstring.get());
+ }
+ }
+
if (FLAG_correctness_fuzzer_suppressions &&
strncmp(result.error_message, "Stack overflow", 15) == 0) {
FATAL("Aborting on stack overflow");
@@ -790,6 +880,7 @@ bool RegExpImpl::Compile(Isolate* isolate, Zone* zone, RegExpCompileData* data,
data->error =
isolate->factory()->NewStringFromAsciiChecked(result.error_message);
}
+
data->code = result.code;
data->register_count = result.num_registers;
@@ -803,7 +894,7 @@ RegExpGlobalCache::RegExpGlobalCache(Handle<JSRegExp> regexp,
regexp_(regexp),
subject_(subject),
isolate_(isolate) {
- bool interpreted = FLAG_regexp_interpret_all;
+ bool interpreted = regexp->ShouldProduceBytecode();
if (regexp_->TypeTag() == JSRegExp::ATOM) {
static const int kAtomRegistersPerMatch = 2;
@@ -868,6 +959,7 @@ int RegExpGlobalCache::AdvanceZeroLength(int last_index) {
int32_t* RegExpGlobalCache::FetchNext() {
current_match_index_++;
+
if (current_match_index_ >= num_matches_) {
// Current batch of results exhausted.
// Fail if last batch was not even fully filled.
diff --git a/deps/v8/src/regexp/regexp.h b/deps/v8/src/regexp/regexp.h
index 0f3ed463da..8ccc9789a3 100644
--- a/deps/v8/src/regexp/regexp.h
+++ b/deps/v8/src/regexp/regexp.h
@@ -13,6 +13,8 @@ namespace internal {
class RegExpNode;
class RegExpTree;
+enum class RegExpCompilationTarget : int { kBytecode, kNative };
+
// TODO(jgruber): Consider splitting between ParseData and CompileData.
struct RegExpCompileData {
// The parsed AST as produced by the RegExpParser.
@@ -21,8 +23,8 @@ struct RegExpCompileData {
// The compiled Node graph as produced by RegExpTree::ToNode methods.
RegExpNode* node = nullptr;
- // The generated code as produced by the compiler. Either a Code object (for
- // irregexp native code) or a ByteArray (for irregexp bytecode).
+ // Either the generated code as produced by the compiler or a trampoline
+ // to the interpreter.
Object code;
// True, iff the pattern is a 'simple' atom with zero captures. In other
@@ -46,12 +48,20 @@ struct RegExpCompileData {
// The number of registers used by the generated code.
int register_count = 0;
+
+ // The compilation target (bytecode or native code).
+ RegExpCompilationTarget compilation_target;
};
class RegExp final : public AllStatic {
public:
// Whether the irregexp engine generates native code or interpreter bytecode.
- static bool GeneratesNativeCode() { return !FLAG_regexp_interpret_all; }
+ static bool CanGenerateNativeCode() {
+ return !FLAG_regexp_interpret_all || FLAG_regexp_tier_up;
+ }
+ static bool CanGenerateBytecode() {
+ return FLAG_regexp_interpret_all || FLAG_regexp_tier_up;
+ }
// Parses the RegExp pattern and prepares the JSRegExp object with
// generic data and choice of implementation - as well as what
@@ -61,6 +71,11 @@ class RegExp final : public AllStatic {
Isolate* isolate, Handle<JSRegExp> re, Handle<String> pattern,
JSRegExp::Flags flags);
+ enum CallOrigin : int {
+ kFromRuntime = 0,
+ kFromJs = 1,
+ };
+
// See ECMA-262 section 15.10.6.2.
// This function calls the garbage collector if necessary.
V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static MaybeHandle<Object> Exec(
@@ -73,7 +88,7 @@ class RegExp final : public AllStatic {
static constexpr int kInternalRegExpException = -1;
static constexpr int kInternalRegExpRetry = -2;
- enum IrregexpResult {
+ enum IrregexpResult : int32_t {
RE_FAILURE = kInternalRegExpFailure,
RE_SUCCESS = kInternalRegExpSuccess,
RE_EXCEPTION = kInternalRegExpException,
diff --git a/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.cc b/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.cc
index 5ebdd6ce15..d4144e7e64 100644
--- a/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.cc
+++ b/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.cc
@@ -178,9 +178,10 @@ void RegExpMacroAssemblerS390::CheckCharacterGT(uc16 limit, Label* on_greater) {
BranchOrBacktrack(gt, on_greater);
}
-void RegExpMacroAssemblerS390::CheckAtStart(Label* on_at_start) {
+void RegExpMacroAssemblerS390::CheckAtStart(int cp_offset, Label* on_at_start) {
__ LoadP(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
- __ AddP(r2, current_input_offset(), Operand(-char_size()));
+ __ AddP(r2, current_input_offset(),
+ Operand(-char_size() + cp_offset * char_size()));
__ CmpP(r2, r3);
BranchOrBacktrack(eq, on_at_start);
}
@@ -663,7 +664,7 @@ Handle<HeapObject> RegExpMacroAssemblerS390::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ mov(r2, Operand(stack_limit));
__ LoadP(r2, MemOperand(r2));
__ SubP(r2, sp, r2);
@@ -965,14 +966,19 @@ RegExpMacroAssemblerS390::Implementation() {
return kS390Implementation;
}
-void RegExpMacroAssemblerS390::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
+void RegExpMacroAssemblerS390::LoadCurrentCharacterImpl(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ // It's possible to preload a small number of characters when each success
+ // path requires a large number of characters, but not the reverse.
+ DCHECK_GE(eats_at_least, characters);
+
DCHECK(cp_offset < (1 << 30)); // Be sane! (And ensure negation works)
if (check_bounds) {
if (cp_offset >= 0) {
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ CheckPosition(cp_offset + eats_at_least - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
@@ -1120,8 +1126,10 @@ int RegExpMacroAssemblerS390::CheckStackGuardState(Address* return_address,
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
frame_entry<intptr_t>(re_frame, kStartIndex),
- frame_entry<intptr_t>(re_frame, kDirectCall) == 1, return_address,
- re_code, frame_entry_address<Address>(re_frame, kInputString),
+ static_cast<RegExp::CallOrigin>(
+ frame_entry<intptr_t>(re_frame, kDirectCall)),
+ return_address, re_code,
+ frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
frame_entry_address<const byte*>(re_frame, kInputEnd));
}
@@ -1206,7 +1214,7 @@ void RegExpMacroAssemblerS390::Pop(Register target) {
void RegExpMacroAssemblerS390::CheckPreemption() {
// Check for preemption.
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ mov(r2, Operand(stack_limit));
__ CmpLogicalP(sp, MemOperand(r2));
SafeCall(&check_preempt_label_, le);
@@ -1214,7 +1222,7 @@ void RegExpMacroAssemblerS390::CheckPreemption() {
void RegExpMacroAssemblerS390::CheckStackLimit() {
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit(isolate());
+ ExternalReference::address_of_regexp_stack_limit_address(isolate());
__ mov(r2, Operand(stack_limit));
__ CmpLogicalP(backtrack_stackpointer(), MemOperand(r2));
SafeCall(&stack_overflow_label_, le);
diff --git a/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.h b/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.h
index 636ba76079..3a6a915263 100644
--- a/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.h
+++ b/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.h
@@ -23,7 +23,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerS390
virtual void AdvanceRegister(int reg, int by);
virtual void Backtrack();
virtual void Bind(Label* label);
- virtual void CheckAtStart(Label* on_at_start);
+ virtual void CheckAtStart(int cp_offset, Label* on_at_start);
virtual void CheckCharacter(unsigned c, Label* on_equal);
virtual void CheckCharacterAfterAnd(unsigned c, unsigned mask,
Label* on_equal);
@@ -59,9 +59,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerS390
virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
virtual void IfRegisterEqPos(int reg, Label* if_eq);
virtual IrregexpImplementation Implementation();
- virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1);
+ virtual void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least);
virtual void PopCurrentPosition();
virtual void PopRegister(int register_index);
virtual void PushBacktrack(Label* label);
diff --git a/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.cc b/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.cc
index 798484d52f..42ba13c4ee 100644
--- a/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.cc
+++ b/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.cc
@@ -48,6 +48,8 @@ namespace internal {
*
* The stack will have the following content, in some order, indexable from the
* frame pointer (see, e.g., kStackHighEnd):
+ * - Address regexp (address of the JSRegExp object; unused in native
+ * code, passed to match signature of interpreter)
* - Isolate* isolate (address of the current isolate)
* - direct_call (if 1, direct call from JavaScript code, if 0 call
* through the runtime system)
@@ -75,9 +77,8 @@ namespace internal {
* "character -1" in the string (i.e., char_size() bytes before the first
* character of the string). The remaining registers starts out uninitialized.
*
- * The first seven values must be provided by the calling code by
- * calling the code's entry address cast to a function pointer with the
- * following signature:
+ * The argument values must be provided by the calling code by calling the
+ * code's entry address cast to a function pointer with the following signature:
* int (*match)(String input_string,
* int start_index,
* Address start,
@@ -86,7 +87,8 @@ namespace internal {
* int num_capture_registers,
* byte* stack_area_base,
* bool direct_call = false,
- * Isolate* isolate);
+ * Isolate* isolate,
+ * Address regexp);
*/
#define __ ACCESS_MASM((&masm_))
@@ -172,14 +174,12 @@ void RegExpMacroAssemblerX64::CheckCharacterGT(uc16 limit, Label* on_greater) {
BranchOrBacktrack(greater, on_greater);
}
-
-void RegExpMacroAssemblerX64::CheckAtStart(Label* on_at_start) {
- __ leaq(rax, Operand(rdi, -char_size()));
+void RegExpMacroAssemblerX64::CheckAtStart(int cp_offset, Label* on_at_start) {
+ __ leaq(rax, Operand(rdi, -char_size() + cp_offset * char_size()));
__ cmpq(rax, Operand(rbp, kStringStartMinusOne));
BranchOrBacktrack(equal, on_at_start);
}
-
void RegExpMacroAssemblerX64::CheckNotAtStart(int cp_offset,
Label* on_not_at_start) {
__ leaq(rax, Operand(rdi, -char_size() + cp_offset * char_size()));
@@ -721,7 +721,7 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
Label stack_ok;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ movq(rcx, rsp);
__ Move(kScratchRegister, stack_limit);
__ subq(rcx, Operand(kScratchRegister, 0));
@@ -1035,15 +1035,19 @@ RegExpMacroAssembler::IrregexpImplementation
return kX64Implementation;
}
+void RegExpMacroAssemblerX64::LoadCurrentCharacterImpl(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters,
+ int eats_at_least) {
+ // It's possible to preload a small number of characters when each success
+ // path requires a large number of characters, but not the reverse.
+ DCHECK_GE(eats_at_least, characters);
-void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset,
- Label* on_end_of_input,
- bool check_bounds,
- int characters) {
DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
if (check_bounds) {
if (cp_offset >= 0) {
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ CheckPosition(cp_offset + eats_at_least - 1, on_end_of_input);
} else {
CheckPosition(cp_offset, on_end_of_input);
}
@@ -1051,7 +1055,6 @@ void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset,
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
-
void RegExpMacroAssemblerX64::PopCurrentPosition() {
Pop(rdi);
}
@@ -1198,7 +1201,8 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
return NativeRegExpMacroAssembler::CheckStackGuardState(
frame_entry<Isolate*>(re_frame, kIsolate),
frame_entry<int>(re_frame, kStartIndex),
- frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
+ static_cast<RegExp::CallOrigin>(frame_entry<int>(re_frame, kDirectCall)),
+ return_address, re_code,
frame_entry_address<Address>(re_frame, kInputString),
frame_entry_address<const byte*>(re_frame, kInputStart),
frame_entry_address<const byte*>(re_frame, kInputEnd));
@@ -1318,7 +1322,7 @@ void RegExpMacroAssemblerX64::CheckPreemption() {
// Check for preemption.
Label no_preempt;
ExternalReference stack_limit =
- ExternalReference::address_of_stack_limit(isolate());
+ ExternalReference::address_of_jslimit(isolate());
__ load_rax(stack_limit);
__ cmpq(rsp, rax);
__ j(above, &no_preempt);
@@ -1332,7 +1336,7 @@ void RegExpMacroAssemblerX64::CheckPreemption() {
void RegExpMacroAssemblerX64::CheckStackLimit() {
Label no_stack_overflow;
ExternalReference stack_limit =
- ExternalReference::address_of_regexp_stack_limit(isolate());
+ ExternalReference::address_of_regexp_stack_limit_address(isolate());
__ load_rax(stack_limit);
__ cmpq(backtrack_stackpointer(), rax);
__ j(above, &no_stack_overflow);
diff --git a/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.h b/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.h
index 59b80ef802..9d011dcd46 100644
--- a/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.h
+++ b/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.h
@@ -24,7 +24,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
void AdvanceRegister(int reg, int by) override;
void Backtrack() override;
void Bind(Label* label) override;
- void CheckAtStart(Label* on_at_start) override;
+ void CheckAtStart(int cp_offset, Label* on_at_start) override;
void CheckCharacter(uint32_t c, Label* on_equal) override;
void CheckCharacterAfterAnd(uint32_t c, uint32_t mask,
Label* on_equal) override;
@@ -60,9 +60,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
void IfRegisterLT(int reg, int comparand, Label* if_lt) override;
void IfRegisterEqPos(int reg, Label* if_eq) override;
IrregexpImplementation Implementation() override;
- void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input,
- bool check_bounds = true,
- int characters = 1) override;
+ void LoadCurrentCharacterImpl(int cp_offset, Label* on_end_of_input,
+ bool check_bounds, int characters,
+ int eats_at_least) override;
void PopCurrentPosition() override;
void PopRegister(int register_index) override;
void PushBacktrack(Label* label) override;
diff --git a/deps/v8/src/roots/roots.h b/deps/v8/src/roots/roots.h
index e6bcd94c01..c82ec6d04f 100644
--- a/deps/v8/src/roots/roots.h
+++ b/deps/v8/src/roots/roots.h
@@ -97,7 +97,6 @@ class Symbol;
V(Map, global_dictionary_map, GlobalDictionaryMap) \
V(Map, many_closures_cell_map, ManyClosuresCellMap) \
V(Map, module_info_map, ModuleInfoMap) \
- V(Map, mutable_heap_number_map, MutableHeapNumberMap) \
V(Map, name_dictionary_map, NameDictionaryMap) \
V(Map, no_closures_cell_map, NoClosuresCellMap) \
V(Map, number_dictionary_map, NumberDictionaryMap) \
@@ -199,6 +198,9 @@ class Symbol;
TrampolineTrivialCodeDataContainer) \
V(CodeDataContainer, trampoline_promise_rejection_code_data_container, \
TrampolinePromiseRejectionCodeDataContainer) \
+ /* Canonical scope infos */ \
+ V(ScopeInfo, global_this_binding_scope_info, GlobalThisBindingScopeInfo) \
+ V(ScopeInfo, empty_function_scope_info, EmptyFunctionScopeInfo) \
/* Hash seed */ \
V(ByteArray, hash_seed, HashSeed)
@@ -270,8 +272,6 @@ class Symbol;
// Entries in this list are limited to Smis and are not visited during GC.
#define SMI_ROOT_LIST(V) \
- V(Smi, stack_limit, StackLimit) \
- V(Smi, real_stack_limit, RealStackLimit) \
V(Smi, last_script_id, LastScriptId) \
V(Smi, last_debugging_id, LastDebuggingId) \
/* To distinguish the function templates, so that we can find them in the */ \
diff --git a/deps/v8/src/runtime/OWNERS b/deps/v8/src/runtime/OWNERS
index 450423f878..f52e1c9ca8 100644
--- a/deps/v8/src/runtime/OWNERS
+++ b/deps/v8/src/runtime/OWNERS
@@ -1,3 +1,3 @@
-file://COMMON_OWNERS
+file:../../COMMON_OWNERS
# COMPONENT: Blink>JavaScript>Runtime
diff --git a/deps/v8/src/runtime/runtime-array.cc b/deps/v8/src/runtime/runtime-array.cc
index f35e72a666..6190b16cff 100644
--- a/deps/v8/src/runtime/runtime-array.cc
+++ b/deps/v8/src/runtime/runtime-array.cc
@@ -272,7 +272,8 @@ RUNTIME_FUNCTION(Runtime_ArrayIncludes_Slow) {
// If the receiver is not a special receiver type, and the length is a valid
// element index, perform fast operation tailored to specific ElementsKinds.
- if (!object->map().IsSpecialReceiverMap() && len < kMaxUInt32 &&
+ if (!object->map().IsSpecialReceiverMap() &&
+ len <= JSObject::kMaxElementCount &&
JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
Handle<JSObject> obj = Handle<JSObject>::cast(object);
ElementsAccessor* elements = obj->GetElementsAccessor();
@@ -283,8 +284,10 @@ RUNTIME_FUNCTION(Runtime_ArrayIncludes_Slow) {
return *isolate->factory()->ToBoolean(result.FromJust());
}
- // Otherwise, perform slow lookups for special receiver types
+ // Otherwise, perform slow lookups for special receiver types.
for (; index < len; ++index) {
+ HandleScope iteration_hs(isolate);
+
// Let elementK be the result of ? Get(O, ! ToString(k)).
Handle<Object> element_k;
{
diff --git a/deps/v8/src/runtime/runtime-collections.cc b/deps/v8/src/runtime/runtime-collections.cc
index 6e7b987458..a4ea0b22ed 100644
--- a/deps/v8/src/runtime/runtime-collections.cc
+++ b/deps/v8/src/runtime/runtime-collections.cc
@@ -25,7 +25,12 @@ RUNTIME_FUNCTION(Runtime_SetGrow) {
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()), isolate);
- table = OrderedHashSet::EnsureGrowable(isolate, table);
+ MaybeHandle<OrderedHashSet> table_candidate =
+ OrderedHashSet::EnsureGrowable(isolate, table);
+ if (!table_candidate.ToHandle(&table)) {
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewRangeError(MessageTemplate::kValueOutOfRange));
+ }
holder->set_table(*table);
return ReadOnlyRoots(isolate).undefined_value();
}
@@ -56,7 +61,12 @@ RUNTIME_FUNCTION(Runtime_MapGrow) {
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()), isolate);
- table = OrderedHashMap::EnsureGrowable(isolate, table);
+ MaybeHandle<OrderedHashMap> table_candidate =
+ OrderedHashMap::EnsureGrowable(isolate, table);
+ if (!table_candidate.ToHandle(&table)) {
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewRangeError(MessageTemplate::kValueOutOfRange));
+ }
holder->set_table(*table);
return ReadOnlyRoots(isolate).undefined_value();
}
diff --git a/deps/v8/src/runtime/runtime-compiler.cc b/deps/v8/src/runtime/runtime-compiler.cc
index 19c6f8bff5..4364c55775 100644
--- a/deps/v8/src/runtime/runtime-compiler.cc
+++ b/deps/v8/src/runtime/runtime-compiler.cc
@@ -266,7 +266,26 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
}
DCHECK(result->is_turbofanned());
- if (!function->HasOptimizedCode()) {
+ if (function->feedback_vector().invocation_count() <= 1 &&
+ function->HasOptimizationMarker()) {
+ // With lazy feedback allocation we may not have feedback for the
+ // initial part of the function that was executed before we allocated a
+ // feedback vector. Reset any optimization markers for such functions.
+ //
+ // TODO(mythria): Instead of resetting the optimization marker here we
+ // should only mark a function for optimization if it has sufficient
+ // feedback. We cannot do this currently since we OSR only after we mark
+ // a function for optimization. We should instead change it to be based
+ // based on number of ticks.
+ DCHECK(!function->IsInOptimizationQueue());
+ function->ClearOptimizationMarker();
+ }
+ // TODO(mythria): Once we have OSR code cache we may not need to mark
+ // the function for non-concurrent compilation. We could arm the loops
+ // early so the second execution uses the already compiled OSR code and
+ // the optimization occurs concurrently off main thread.
+ if (!function->HasOptimizedCode() &&
+ function->feedback_vector().invocation_count() > 1) {
// If we're not already optimized, set to optimize non-concurrently on
// the next call, otherwise we'd run unoptimized once more and
// potentially compile for OSR again.
diff --git a/deps/v8/src/runtime/runtime-debug.cc b/deps/v8/src/runtime/runtime-debug.cc
index 94320740af..0fbea6a193 100644
--- a/deps/v8/src/runtime/runtime-debug.cc
+++ b/deps/v8/src/runtime/runtime-debug.cc
@@ -115,10 +115,17 @@ RUNTIME_FUNCTION(Runtime_DebugBreakAtEntry) {
DCHECK(function->shared().HasDebugInfo());
DCHECK(function->shared().GetDebugInfo().BreakAtEntry());
- // Get the top-most JavaScript frame.
+ // Get the top-most JavaScript frame. This is the debug target function.
JavaScriptFrameIterator it(isolate);
DCHECK_EQ(*function, it.frame()->function());
- isolate->debug()->Break(it.frame(), function);
+ // Check whether the next JS frame is closer than the last API entry.
+ // if yes, then the call to the debug target came from JavaScript. Otherwise,
+ // the call to the debug target came from API. Do not break for the latter.
+ it.Advance();
+ if (!it.done() &&
+ it.frame()->fp() < isolate->thread_local_top()->last_api_entry_) {
+ isolate->debug()->Break(it.frame(), function);
+ }
return ReadOnlyRoots(isolate).undefined_value();
}
@@ -688,7 +695,7 @@ RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) {
int num_scripts = static_cast<int>(coverage->size());
// Prepare property keys.
Handle<FixedArray> scripts_array = factory->NewFixedArray(num_scripts);
- Handle<String> script_string = factory->NewStringFromStaticChars("script");
+ Handle<String> script_string = factory->script_string();
for (int i = 0; i < num_scripts; i++) {
const auto& script_data = coverage->at(i);
HandleScope inner_scope(isolate);
diff --git a/deps/v8/src/runtime/runtime-internal.cc b/deps/v8/src/runtime/runtime-internal.cc
index 4b8a0e38a1..80f9baa48d 100644
--- a/deps/v8/src/runtime/runtime-internal.cc
+++ b/deps/v8/src/runtime/runtime-internal.cc
@@ -13,6 +13,8 @@
#include "src/execution/arguments-inl.h"
#include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h"
+#include "src/execution/messages.h"
+#include "src/handles/maybe-handles.h"
#include "src/init/bootstrapper.h"
#include "src/logging/counters.h"
#include "src/numbers/conversions.h"
@@ -322,7 +324,8 @@ RUNTIME_FUNCTION(Runtime_AllocateInYoungGeneration) {
double_align = false;
return *isolate->factory()->NewFillerObject(size, double_align,
- AllocationType::kYoung);
+ AllocationType::kYoung,
+ AllocationOrigin::kGeneratedCode);
}
RUNTIME_FUNCTION(Runtime_AllocateInOldGeneration) {
@@ -339,7 +342,8 @@ RUNTIME_FUNCTION(Runtime_AllocateInOldGeneration) {
CHECK(size <= kMaxRegularHeapObjectSize);
}
return *isolate->factory()->NewFillerObject(size, double_align,
- AllocationType::kOld);
+ AllocationType::kOld,
+ AllocationOrigin::kGeneratedCode);
}
RUNTIME_FUNCTION(Runtime_AllocateByteArray) {
@@ -372,228 +376,35 @@ RUNTIME_FUNCTION(Runtime_AllocateSeqTwoByteString) {
return *result;
}
-namespace {
-
-bool ComputeLocation(Isolate* isolate, MessageLocation* target) {
- JavaScriptFrameIterator it(isolate);
- if (!it.done()) {
- // Compute the location from the function and the relocation info of the
- // baseline code. For optimized code this will use the deoptimization
- // information to get canonical location information.
- std::vector<FrameSummary> frames;
- it.frame()->Summarize(&frames);
- auto& summary = frames.back().AsJavaScript();
- Handle<SharedFunctionInfo> shared(summary.function()->shared(), isolate);
- Handle<Object> script(shared->script(), isolate);
- SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared);
- int pos = summary.abstract_code()->SourcePosition(summary.code_offset());
- if (script->IsScript() &&
- !(Handle<Script>::cast(script)->source().IsUndefined(isolate))) {
- Handle<Script> casted_script = Handle<Script>::cast(script);
- *target = MessageLocation(casted_script, pos, pos + 1, shared);
- return true;
- }
- }
- return false;
-}
-
-Handle<String> BuildDefaultCallSite(Isolate* isolate, Handle<Object> object) {
- IncrementalStringBuilder builder(isolate);
-
- builder.AppendString(Object::TypeOf(isolate, object));
- if (object->IsString()) {
- builder.AppendCString(" \"");
- builder.AppendString(Handle<String>::cast(object));
- builder.AppendCString("\"");
- } else if (object->IsNull(isolate)) {
- builder.AppendCString(" ");
- builder.AppendString(isolate->factory()->null_string());
- } else if (object->IsTrue(isolate)) {
- builder.AppendCString(" ");
- builder.AppendString(isolate->factory()->true_string());
- } else if (object->IsFalse(isolate)) {
- builder.AppendCString(" ");
- builder.AppendString(isolate->factory()->false_string());
- } else if (object->IsNumber()) {
- builder.AppendCString(" ");
- builder.AppendString(isolate->factory()->NumberToString(object));
- }
-
- return builder.Finish().ToHandleChecked();
-}
-
-Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object,
- CallPrinter::ErrorHint* hint) {
- MessageLocation location;
- if (ComputeLocation(isolate, &location)) {
- ParseInfo info(isolate, location.shared());
- if (parsing::ParseAny(&info, location.shared(), isolate)) {
- info.ast_value_factory()->Internalize(isolate);
- CallPrinter printer(isolate, location.shared()->IsUserJavaScript());
- Handle<String> str = printer.Print(info.literal(), location.start_pos());
- *hint = printer.GetErrorHint();
- if (str->length() > 0) return str;
- } else {
- isolate->clear_pending_exception();
- }
- }
- return BuildDefaultCallSite(isolate, object);
-}
-
-MessageTemplate UpdateErrorTemplate(CallPrinter::ErrorHint hint,
- MessageTemplate default_id) {
- switch (hint) {
- case CallPrinter::ErrorHint::kNormalIterator:
- return MessageTemplate::kNotIterable;
-
- case CallPrinter::ErrorHint::kCallAndNormalIterator:
- return MessageTemplate::kNotCallableOrIterable;
-
- case CallPrinter::ErrorHint::kAsyncIterator:
- return MessageTemplate::kNotAsyncIterable;
-
- case CallPrinter::ErrorHint::kCallAndAsyncIterator:
- return MessageTemplate::kNotCallableOrAsyncIterable;
-
- case CallPrinter::ErrorHint::kNone:
- return default_id;
- }
- return default_id;
-}
-
-} // namespace
-
-MaybeHandle<Object> Runtime::ThrowIteratorError(Isolate* isolate,
- Handle<Object> object) {
- CallPrinter::ErrorHint hint = CallPrinter::kNone;
- Handle<String> callsite = RenderCallSite(isolate, object, &hint);
- MessageTemplate id = MessageTemplate::kNotIterableNoSymbolLoad;
-
- if (hint == CallPrinter::kNone) {
- Handle<Symbol> iterator_symbol = isolate->factory()->iterator_symbol();
- THROW_NEW_ERROR(isolate, NewTypeError(id, callsite, iterator_symbol),
- Object);
- }
-
- id = UpdateErrorTemplate(hint, id);
- THROW_NEW_ERROR(isolate, NewTypeError(id, callsite), Object);
-}
-
RUNTIME_FUNCTION(Runtime_ThrowIteratorError) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
- RETURN_RESULT_OR_FAILURE(isolate,
- Runtime::ThrowIteratorError(isolate, object));
+ return isolate->Throw(*ErrorUtils::NewIteratorError(isolate, object));
}
RUNTIME_FUNCTION(Runtime_ThrowCalledNonCallable) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
- CallPrinter::ErrorHint hint = CallPrinter::kNone;
- Handle<String> callsite = RenderCallSite(isolate, object, &hint);
- MessageTemplate id = MessageTemplate::kCalledNonCallable;
- id = UpdateErrorTemplate(hint, id);
- THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(id, callsite));
+ return isolate->Throw(
+ *ErrorUtils::NewCalledNonCallableError(isolate, object));
}
RUNTIME_FUNCTION(Runtime_ThrowConstructedNonConstructable) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
- CallPrinter::ErrorHint hint = CallPrinter::kNone;
- Handle<String> callsite = RenderCallSite(isolate, object, &hint);
- MessageTemplate id = MessageTemplate::kNotConstructor;
- THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(id, callsite));
+ return isolate->Throw(
+ *ErrorUtils::NewConstructedNonConstructable(isolate, object));
}
-namespace {
-
-// Helper visitor for ThrowPatternAssignmentNonCoercible which finds an
-// object literal (representing a destructuring assignment) at a given source
-// position.
-class PatternFinder final : public AstTraversalVisitor<PatternFinder> {
- public:
- PatternFinder(Isolate* isolate, Expression* root, int position)
- : AstTraversalVisitor(isolate, root),
- position_(position),
- object_literal_(nullptr) {}
-
- ObjectLiteral* object_literal() const { return object_literal_; }
-
- private:
- // This is required so that the overriden Visit* methods can be
- // called by the base class (template).
- friend class AstTraversalVisitor<PatternFinder>;
-
- void VisitObjectLiteral(ObjectLiteral* lit) {
- // TODO(leszeks): This could be smarter in only traversing object literals
- // that are known to be a destructuring pattern. We could then also
- // potentially find the corresponding assignment value and report that too.
- if (lit->position() == position_) {
- object_literal_ = lit;
- return;
- }
- AstTraversalVisitor::VisitObjectLiteral(lit);
- }
-
- int position_;
- ObjectLiteral* object_literal_;
-};
-
-} // namespace
-
RUNTIME_FUNCTION(Runtime_ThrowPatternAssignmentNonCoercible) {
HandleScope scope(isolate);
- DCHECK_EQ(0, args.length());
-
- // Find the object literal representing the destructuring assignment, so that
- // we can try to attribute the error to a property name on it rather than to
- // the literal itself.
- MaybeHandle<String> maybe_property_name;
- MessageLocation location;
- if (ComputeLocation(isolate, &location)) {
- ParseInfo info(isolate, location.shared());
- if (parsing::ParseAny(&info, location.shared(), isolate)) {
- info.ast_value_factory()->Internalize(isolate);
-
- PatternFinder finder(isolate, info.literal(), location.start_pos());
- finder.Run();
- if (finder.object_literal()) {
- for (ObjectLiteralProperty* pattern_property :
- *finder.object_literal()->properties()) {
- Expression* key = pattern_property->key();
- if (key->IsPropertyName()) {
- int pos = key->position();
- maybe_property_name =
- key->AsLiteral()->AsRawPropertyName()->string();
- // Change the message location to point at the property name.
- location = MessageLocation(location.script(), pos, pos + 1,
- location.shared());
- break;
- }
- }
- }
- } else {
- isolate->clear_pending_exception();
- }
- }
-
- // Create a "non-coercible" type error with a property name if one is
- // available, otherwise create a generic one.
- Handle<Object> error;
- Handle<String> property_name;
- if (maybe_property_name.ToHandle(&property_name)) {
- error = isolate->factory()->NewTypeError(
- MessageTemplate::kNonCoercibleWithProperty, property_name);
- } else {
- error = isolate->factory()->NewTypeError(MessageTemplate::kNonCoercible);
- }
-
- // Explicitly pass the calculated location, as we may have updated it to match
- // the property name.
- return isolate->Throw(*error, &location);
+ DCHECK_EQ(1, args.length());
+ CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
+ return ErrorUtils::ThrowLoadFromNullOrUndefined(isolate, object,
+ MaybeHandle<Object>());
}
RUNTIME_FUNCTION(Runtime_ThrowConstructorReturnedNonObject) {
diff --git a/deps/v8/src/runtime/runtime-literals.cc b/deps/v8/src/runtime/runtime-literals.cc
index 0c7a28c279..0ffc6e932e 100644
--- a/deps/v8/src/runtime/runtime-literals.cc
+++ b/deps/v8/src/runtime/runtime-literals.cc
@@ -113,9 +113,12 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
copy->map(isolate).instance_descriptors(isolate), isolate);
int limit = copy->map(isolate).NumberOfOwnDescriptors();
for (int i = 0; i < limit; i++) {
- DCHECK_EQ(kField, descriptors->GetDetails(i).location());
- DCHECK_EQ(kData, descriptors->GetDetails(i).kind());
- FieldIndex index = FieldIndex::ForDescriptor(copy->map(isolate), i);
+ PropertyDetails details = descriptors->GetDetails(i);
+ DCHECK_EQ(kField, details.location());
+ DCHECK_EQ(kData, details.kind());
+ FieldIndex index = FieldIndex::ForPropertyIndex(
+ copy->map(isolate), details.field_index(),
+ details.representation());
if (copy->IsUnboxedDoubleField(isolate, index)) continue;
Object raw = copy->RawFastPropertyAt(isolate, index);
if (raw.IsJSObject(isolate)) {
@@ -123,11 +126,9 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, VisitElementOrProperty(copy, value), JSObject);
if (copying) copy->FastPropertyAtPut(index, *value);
- } else if (copying && raw.IsMutableHeapNumber(isolate)) {
- DCHECK(descriptors->GetDetails(i).representation().IsDouble());
- uint64_t double_value = MutableHeapNumber::cast(raw).value_as_bits();
- auto value =
- isolate->factory()->NewMutableHeapNumberFromBits(double_value);
+ } else if (copying && details.representation().IsDouble()) {
+ uint64_t double_value = HeapNumber::cast(raw).value_as_bits();
+ auto value = isolate->factory()->NewHeapNumberFromBits(double_value);
copy->FastPropertyAtPut(index, *value);
}
}
@@ -154,8 +155,10 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
case PACKED_ELEMENTS:
case PACKED_FROZEN_ELEMENTS:
case PACKED_SEALED_ELEMENTS:
+ case PACKED_NONEXTENSIBLE_ELEMENTS:
case HOLEY_FROZEN_ELEMENTS:
case HOLEY_SEALED_ELEMENTS:
+ case HOLEY_NONEXTENSIBLE_ELEMENTS:
case HOLEY_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(copy->elements(isolate)),
isolate);
@@ -652,15 +655,16 @@ RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) {
DCHECK(maybe_vector->IsFeedbackVector());
vector = Handle<FeedbackVector>::cast(maybe_vector);
}
- Handle<Object> boilerplate;
if (vector.is_null()) {
+ Handle<JSRegExp> new_regexp;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, boilerplate,
+ isolate, new_regexp,
JSRegExp::New(isolate, pattern, JSRegExp::Flags(flags)));
- return *JSRegExp::Copy(Handle<JSRegExp>::cast(boilerplate));
+ return *new_regexp;
}
// Check if boilerplate exists. If not, create it first.
+ Handle<JSRegExp> boilerplate;
Handle<Object> literal_site(vector->Get(literal_slot)->cast<Object>(),
isolate);
if (!HasBoilerplate(literal_site)) {
@@ -673,7 +677,7 @@ RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) {
}
vector->Set(literal_slot, *boilerplate);
}
- return *JSRegExp::Copy(Handle<JSRegExp>::cast(boilerplate));
+ return *JSRegExp::Copy(boilerplate);
}
} // namespace internal
diff --git a/deps/v8/src/runtime/runtime-object.cc b/deps/v8/src/runtime/runtime-object.cc
index 25bd07b535..310cdaab42 100644
--- a/deps/v8/src/runtime/runtime-object.cc
+++ b/deps/v8/src/runtime/runtime-object.cc
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/ast/prettyprinter.h"
#include "src/common/message-template.h"
#include "src/debug/debug.h"
#include "src/execution/arguments-inl.h"
#include "src/execution/isolate-inl.h"
+#include "src/execution/messages.h"
+#include "src/handles/maybe-handles.h"
#include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
#include "src/init/bootstrapper.h"
#include "src/logging/counters.h"
@@ -24,13 +27,8 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
Handle<Object> key,
bool* is_found_out) {
if (object->IsNullOrUndefined(isolate)) {
- if (*key == ReadOnlyRoots(isolate).iterator_symbol()) {
- return Runtime::ThrowIteratorError(isolate, object);
- }
- THROW_NEW_ERROR(
- isolate,
- NewTypeError(MessageTemplate::kNonObjectPropertyLoad, key, object),
- Object);
+ ErrorUtils::ThrowLoadFromNullOrUndefined(isolate, object, key);
+ return MaybeHandle<Object>();
}
bool success = false;
@@ -46,7 +44,7 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
Handle<Object> name_string(Symbol::cast(*key).name(), isolate);
DCHECK(name_string->IsString());
THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kInvalidPrivateFieldRead,
+ NewTypeError(MessageTemplate::kInvalidPrivateMemberRead,
name_string, object),
Object);
}
@@ -413,7 +411,7 @@ MaybeHandle<Object> Runtime::SetObjectProperty(
Handle<Object> name_string(Symbol::cast(*key).name(), isolate);
DCHECK(name_string->IsString());
THROW_NEW_ERROR(isolate,
- NewTypeError(MessageTemplate::kInvalidPrivateFieldWrite,
+ NewTypeError(MessageTemplate::kInvalidPrivateMemberWrite,
name_string, object),
Object);
}
@@ -778,7 +776,6 @@ RUNTIME_FUNCTION(Runtime_HasProperty) {
return isolate->heap()->ToBoolean(maybe.FromJust());
}
-
RUNTIME_FUNCTION(Runtime_GetOwnPropertyKeys) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
@@ -795,7 +792,6 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyKeys) {
return *isolate->factory()->NewJSArrayWithElements(keys);
}
-
RUNTIME_FUNCTION(Runtime_ToFastProperties) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
@@ -807,14 +803,12 @@ RUNTIME_FUNCTION(Runtime_ToFastProperties) {
return *object;
}
-
RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
return *isolate->factory()->NewHeapNumber(0);
}
-
RUNTIME_FUNCTION(Runtime_NewObject) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
@@ -845,7 +839,6 @@ RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTrackingForMap) {
return ReadOnlyRoots(isolate).undefined_value();
}
-
RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
@@ -862,12 +855,10 @@ RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
return *object;
}
-
static bool IsValidAccessor(Isolate* isolate, Handle<Object> obj) {
return obj->IsNullOrUndefined(isolate) || obj->IsCallable();
}
-
// Implements part of 8.12.9 DefineOwnProperty.
// There are 3 cases that lead here:
// Step 4b - define a new accessor property.
@@ -891,7 +882,6 @@ RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
return ReadOnlyRoots(isolate).undefined_value();
}
-
RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) {
HandleScope scope(isolate);
DCHECK_EQ(6, args.length());
@@ -914,8 +904,7 @@ RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) {
nexus.ConfigureMegamorphic(PROPERTY);
}
} else if (nexus.ic_state() == MONOMORPHIC) {
- if (nexus.GetFirstMap() != object->map() ||
- nexus.GetFeedbackExtra() != MaybeObject::FromObject(*name)) {
+ if (nexus.GetFirstMap() != object->map() || nexus.GetName() != *name) {
nexus.ConfigureMegamorphic(PROPERTY);
}
}
@@ -984,7 +973,6 @@ RUNTIME_FUNCTION(Runtime_HasFastPackedElements) {
IsFastPackedElementsKind(obj.map().elements_kind()));
}
-
RUNTIME_FUNCTION(Runtime_IsJSReceiver) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
@@ -992,7 +980,6 @@ RUNTIME_FUNCTION(Runtime_IsJSReceiver) {
return isolate->heap()->ToBoolean(obj.IsJSReceiver());
}
-
RUNTIME_FUNCTION(Runtime_ClassOf) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
@@ -1069,9 +1056,9 @@ RUNTIME_FUNCTION(Runtime_CopyDataPropertiesWithExcludedProperties) {
DCHECK_LE(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, source, 0);
- // 2. If source is undefined or null, let keys be an empty List.
- if (source->IsUndefined(isolate) || source->IsNull(isolate)) {
- return ReadOnlyRoots(isolate).undefined_value();
+ // If source is undefined or null, throw a non-coercible error.
+ if (source->IsNullOrUndefined(isolate)) {
+ return ErrorUtils::ThrowLoadFromNullOrUndefined(isolate, source);
}
ScopedVector<Handle<Object>> excluded_properties(args.length() - 1);
@@ -1141,7 +1128,6 @@ RUNTIME_FUNCTION(Runtime_ToNumeric) {
RETURN_RESULT_OR_FAILURE(isolate, Object::ToNumeric(isolate, input));
}
-
RUNTIME_FUNCTION(Runtime_ToLength) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
@@ -1175,7 +1161,6 @@ RUNTIME_FUNCTION(Runtime_HasInPrototypeChain) {
return isolate->heap()->ToBoolean(result.FromJust());
}
-
// ES6 section 7.4.7 CreateIterResultObject ( value, done )
RUNTIME_FUNCTION(Runtime_CreateIterResultObject) {
HandleScope scope(isolate);
@@ -1217,6 +1202,32 @@ RUNTIME_FUNCTION(Runtime_GetOwnPropertyDescriptor) {
return *desc.ToPropertyDescriptorObject(isolate);
}
+RUNTIME_FUNCTION(Runtime_LoadPrivateSetter) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(args.length(), 1);
+ CONVERT_ARG_HANDLE_CHECKED(AccessorPair, pair, 0);
+ DCHECK(pair->setter().IsJSFunction());
+ return pair->setter();
+}
+
+RUNTIME_FUNCTION(Runtime_LoadPrivateGetter) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(args.length(), 1);
+ CONVERT_ARG_HANDLE_CHECKED(AccessorPair, pair, 0);
+ DCHECK(pair->getter().IsJSFunction());
+ return pair->getter();
+}
+
+RUNTIME_FUNCTION(Runtime_CreatePrivateAccessors) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(args.length(), 2);
+ DCHECK(args[0].IsNull() || args[0].IsJSFunction());
+ DCHECK(args[1].IsNull() || args[1].IsJSFunction());
+ Handle<AccessorPair> pair = isolate->factory()->NewAccessorPair();
+ pair->SetComponents(args[0], args[1]);
+ return *pair;
+}
+
RUNTIME_FUNCTION(Runtime_AddPrivateBrand) {
HandleScope scope(isolate);
DCHECK_EQ(args.length(), 2);
diff --git a/deps/v8/src/runtime/runtime-regexp.cc b/deps/v8/src/runtime/runtime-regexp.cc
index 76056a7823..e197e16e11 100644
--- a/deps/v8/src/runtime/runtime-regexp.cc
+++ b/deps/v8/src/runtime/runtime-regexp.cc
@@ -613,6 +613,20 @@ V8_WARN_UNUSED_RESULT static Object StringReplaceGlobalRegExpWithString(
JSRegExp::Type typeTag = regexp->TypeTag();
if (typeTag == JSRegExp::IRREGEXP) {
+ // Force tier up to native code for global replaces. The global replace is
+ // implemented differently for native code and bytecode execution, where the
+ // native code expects an array to store all the matches, and the bytecode
+ // matches one at a time, so it's easier to tier-up to native code from the
+ // start.
+ if (FLAG_regexp_tier_up) {
+ regexp->MarkTierUpForNextExec();
+ if (FLAG_trace_regexp_tier_up) {
+ PrintF(
+ "Forcing tier-up of JSRegExp object %p in "
+ "StringReplaceGlobalRegExpWithString\n",
+ reinterpret_cast<void*>(regexp->ptr()));
+ }
+ }
// Ensure the RegExp is compiled so we can access the capture-name map.
if (RegExp::IrregexpPrepare(isolate, regexp, subject) == -1) {
DCHECK(isolate->has_pending_exception());
@@ -1085,6 +1099,19 @@ static Object SearchRegExpMultiple(Isolate* isolate, Handle<String> subject,
DCHECK_NE(has_capture, regexp->CaptureCount() == 0);
DCHECK(subject->IsFlat());
+ // Force tier up to native code for global replaces. The global replace is
+ // implemented differently for native code and bytecode execution, where the
+ // native code expects an array to store all the matches, and the bytecode
+ // matches one at a time, so it's easier to tier-up to native code from the
+ // start.
+ if (FLAG_regexp_tier_up && regexp->TypeTag() == JSRegExp::IRREGEXP) {
+ regexp->MarkTierUpForNextExec();
+ if (FLAG_trace_regexp_tier_up) {
+ PrintF("Forcing tier-up of JSRegExp object %p in SearchRegExpMultiple\n",
+ reinterpret_cast<void*>(regexp->ptr()));
+ }
+ }
+
int capture_count = regexp->CaptureCount();
int subject_length = subject->length();
diff --git a/deps/v8/src/runtime/runtime-scopes.cc b/deps/v8/src/runtime/runtime-scopes.cc
index f67b6922bf..812b09b1f0 100644
--- a/deps/v8/src/runtime/runtime-scopes.cc
+++ b/deps/v8/src/runtime/runtime-scopes.cc
@@ -678,9 +678,6 @@ RUNTIME_FUNCTION(Runtime_NewScriptContext) {
FindNameClash(isolate, scope_info, global_object, script_context_table);
if (isolate->has_pending_exception()) return name_clash_result;
- // We do not need script contexts here during bootstrap.
- DCHECK(!isolate->bootstrapper()->IsActive());
-
Handle<Context> result =
isolate->factory()->NewScriptContext(native_context, scope_info);
diff --git a/deps/v8/src/runtime/runtime-test.cc b/deps/v8/src/runtime/runtime-test.cc
index f0caaaa14c..a766dd5db2 100644
--- a/deps/v8/src/runtime/runtime-test.cc
+++ b/deps/v8/src/runtime/runtime-test.cc
@@ -17,6 +17,7 @@
#include "src/execution/arguments-inl.h"
#include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h"
+#include "src/execution/protectors-inl.h"
#include "src/execution/runtime-profiler.h"
#include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
#include "src/heap/heap-write-barrier-inl.h"
@@ -24,6 +25,7 @@
#include "src/logging/counters.h"
#include "src/objects/heap-object-inl.h"
#include "src/objects/js-array-inl.h"
+#include "src/objects/js-regexp-inl.h"
#include "src/objects/smi.h"
#include "src/snapshot/natives.h"
#include "src/trap-handler/trap-handler.h"
@@ -310,13 +312,19 @@ namespace {
bool EnsureFeedbackVector(Handle<JSFunction> function) {
// Check function allows lazy compilation.
- if (!function->shared().allows_lazy_compilation()) {
- return false;
- }
+ if (!function->shared().allows_lazy_compilation()) return false;
+
+ if (function->has_feedback_vector()) return true;
// If function isn't compiled, compile it now.
IsCompiledScope is_compiled_scope(function->shared().is_compiled_scope());
- if (!is_compiled_scope.is_compiled() &&
+ // If the JSFunction isn't compiled but it has a initialized feedback cell
+ // then no need to compile. CompileLazy builtin would handle these cases by
+ // installing the code from SFI. Calling compile here may cause another
+ // optimization if FLAG_always_opt is set.
+ bool needs_compilation =
+ !function->is_compiled() && !function->has_closure_feedback_cell_array();
+ if (needs_compilation &&
!Compiler::Compile(function, Compiler::CLEAR_EXCEPTION,
&is_compiled_scope)) {
return false;
@@ -343,12 +351,24 @@ RUNTIME_FUNCTION(Runtime_EnsureFeedbackVectorForFunction) {
RUNTIME_FUNCTION(Runtime_PrepareFunctionForOptimization) {
HandleScope scope(isolate);
- DCHECK_EQ(1, args.length());
+ DCHECK(args.length() == 1 || args.length() == 2);
if (!args[0].IsJSFunction()) {
return ReadOnlyRoots(isolate).undefined_value();
}
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+ bool allow_heuristic_optimization = false;
+ if (args.length() == 2) {
+ CONVERT_ARG_HANDLE_CHECKED(Object, sync_object, 1);
+ if (!sync_object->IsString())
+ return ReadOnlyRoots(isolate).undefined_value();
+ Handle<String> sync = Handle<String>::cast(sync_object);
+ if (sync->IsOneByteEqualTo(
+ StaticCharVector("allow heuristic optimization"))) {
+ allow_heuristic_optimization = true;
+ }
+ }
+
if (!EnsureFeedbackVector(function)) {
return ReadOnlyRoots(isolate).undefined_value();
}
@@ -369,7 +389,8 @@ RUNTIME_FUNCTION(Runtime_PrepareFunctionForOptimization) {
// Hold onto the bytecode array between marking and optimization to ensure
// it's not flushed.
if (FLAG_testing_d8_test_runner) {
- PendingOptimizationTable::PreparedForOptimization(isolate, function);
+ PendingOptimizationTable::PreparedForOptimization(
+ isolate, function, allow_heuristic_optimization);
}
return ReadOnlyRoots(isolate).undefined_value();
@@ -502,7 +523,11 @@ RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
}
if (function->IsOptimized()) {
- status |= static_cast<int>(OptimizationStatus::kOptimized);
+ if (function->code().marked_for_deoptimization()) {
+ status |= static_cast<int>(OptimizationStatus::kMarkedForDeoptimization);
+ } else {
+ status |= static_cast<int>(OptimizationStatus::kOptimized);
+ }
if (function->code().is_turbofanned()) {
status |= static_cast<int>(OptimizationStatus::kTurboFanned);
}
@@ -1024,6 +1049,24 @@ RUNTIME_FUNCTION(Runtime_SetWasmThreadsEnabled) {
return ReadOnlyRoots(isolate).undefined_value();
}
+RUNTIME_FUNCTION(Runtime_RegexpHasBytecode) {
+ SealHandleScope shs(isolate);
+ DCHECK_EQ(2, args.length());
+ CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
+ CONVERT_BOOLEAN_ARG_CHECKED(is_latin1, 1);
+ bool is_irregexp_bytecode = regexp.Bytecode(is_latin1).IsByteArray();
+ return isolate->heap()->ToBoolean(is_irregexp_bytecode);
+}
+
+RUNTIME_FUNCTION(Runtime_RegexpHasNativeCode) {
+ SealHandleScope shs(isolate);
+ DCHECK_EQ(2, args.length());
+ CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
+ CONVERT_BOOLEAN_ARG_CHECKED(is_latin1, 1);
+ bool is_irregexp_native_code = regexp.Code(is_latin1).IsCode();
+ return isolate->heap()->ToBoolean(is_irregexp_native_code);
+}
+
#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
RUNTIME_FUNCTION(Runtime_Has##Name) { \
CONVERT_ARG_CHECKED(JSObject, obj, 0); \
@@ -1057,7 +1100,8 @@ TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
RUNTIME_FUNCTION(Runtime_ArraySpeciesProtector) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
- return isolate->heap()->ToBoolean(isolate->IsArraySpeciesLookupChainIntact());
+ return isolate->heap()->ToBoolean(
+ Protectors::IsArraySpeciesLookupChainIntact(isolate));
}
RUNTIME_FUNCTION(Runtime_MapIteratorProtector) {
@@ -1299,6 +1343,7 @@ RUNTIME_FUNCTION(Runtime_EnableCodeLoggingForTesting) {
void RegExpCodeCreateEvent(AbstractCode code, String source) final {}
void CodeMoveEvent(AbstractCode from, AbstractCode to) final {}
void SharedFunctionInfoMoveEvent(Address from, Address to) final {}
+ void NativeContextMoveEvent(Address from, Address to) final {}
void CodeMovingGCEvent() final {}
void CodeDisableOptEvent(AbstractCode code,
SharedFunctionInfo shared) final {}
diff --git a/deps/v8/src/runtime/runtime-wasm.cc b/deps/v8/src/runtime/runtime-wasm.cc
index 65acb296cc..57e59c07be 100644
--- a/deps/v8/src/runtime/runtime-wasm.cc
+++ b/deps/v8/src/runtime/runtime-wasm.cc
@@ -430,8 +430,8 @@ RUNTIME_FUNCTION(Runtime_WasmRefFunc) {
isolate->set_context(instance->native_context());
CONVERT_UINT32_ARG_CHECKED(function_index, 0);
- Handle<WasmExportedFunction> function =
- WasmInstanceObject::GetOrCreateWasmExportedFunction(isolate, instance,
+ Handle<WasmExternalFunction> function =
+ WasmInstanceObject::GetOrCreateWasmExternalFunction(isolate, instance,
function_index);
return *function;
@@ -568,5 +568,24 @@ RUNTIME_FUNCTION(Runtime_WasmTableFill) {
}
return ReadOnlyRoots(isolate).undefined_value();
}
+
+RUNTIME_FUNCTION(Runtime_WasmNewMultiReturnFixedArray) {
+ DCHECK_EQ(1, args.length());
+ HandleScope scope(isolate);
+ CONVERT_INT32_ARG_CHECKED(size, 0);
+ Handle<FixedArray> fixed_array = isolate->factory()->NewFixedArray(size);
+ return *fixed_array;
+}
+
+RUNTIME_FUNCTION(Runtime_WasmNewMultiReturnJSArray) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(1, args.length());
+ DCHECK(!isolate->context().is_null());
+ CONVERT_ARG_CHECKED(FixedArray, fixed_array, 0);
+ Handle<FixedArray> fixed_array_handle(fixed_array, isolate);
+ Handle<JSArray> array = isolate->factory()->NewJSArrayWithElements(
+ fixed_array_handle, PACKED_ELEMENTS);
+ return *array;
+}
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/runtime/runtime-weak-refs.cc b/deps/v8/src/runtime/runtime-weak-refs.cc
deleted file mode 100644
index 2720176c30..0000000000
--- a/deps/v8/src/runtime/runtime-weak-refs.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2018 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "include/v8.h"
-#include "src/api/api.h"
-#include "src/execution/arguments-inl.h"
-#include "src/execution/execution.h"
-#include "src/handles/handles-inl.h"
-#include "src/logging/counters.h"
-#include "src/objects/js-weak-refs-inl.h"
-#include "src/objects/objects-inl.h"
-#include "src/runtime/runtime-utils.h"
-
-namespace v8 {
-namespace internal {
-
-RUNTIME_FUNCTION(Runtime_FinalizationGroupCleanupJob) {
- HandleScope scope(isolate);
- CONVERT_ARG_HANDLE_CHECKED(JSFinalizationGroup, finalization_group, 0);
- finalization_group->set_scheduled_for_cleanup(false);
-
- Handle<Object> cleanup(finalization_group->cleanup(), isolate);
- JSFinalizationGroup::Cleanup(isolate, finalization_group, cleanup);
- return ReadOnlyRoots(isolate).undefined_value();
-}
-
-} // namespace internal
-} // namespace v8
diff --git a/deps/v8/src/runtime/runtime.cc b/deps/v8/src/runtime/runtime.cc
index ad49a0299c..0984080293 100644
--- a/deps/v8/src/runtime/runtime.cc
+++ b/deps/v8/src/runtime/runtime.cc
@@ -107,9 +107,12 @@ bool Runtime::NeedsExactContext(FunctionId id) {
return false;
case Runtime::kAddPrivateField:
case Runtime::kAddPrivateBrand:
+ case Runtime::kCreatePrivateAccessors:
case Runtime::kCopyDataProperties:
case Runtime::kCreateDataProperty:
case Runtime::kCreatePrivateNameSymbol:
+ case Runtime::kLoadPrivateGetter:
+ case Runtime::kLoadPrivateSetter:
case Runtime::kReThrow:
case Runtime::kThrow:
case Runtime::kThrowApplyNonFunction:
diff --git a/deps/v8/src/runtime/runtime.h b/deps/v8/src/runtime/runtime.h
index 92ca9f3142..d705b05752 100644
--- a/deps/v8/src/runtime/runtime.h
+++ b/deps/v8/src/runtime/runtime.h
@@ -37,17 +37,17 @@ namespace internal {
// inline), use the F macro below. To declare the runtime version and the inline
// version simultaneously, use the I macro below.
-#define FOR_EACH_INTRINSIC_ARRAY(F, I) \
- F(ArrayIncludes_Slow, 3, 1) \
- F(ArrayIndexOf, 3, 1) \
- F(ArrayIsArray, 1, 1) \
- F(ArraySpeciesConstructor, 1, 1) \
- F(GrowArrayElements, 2, 1) \
- I(IsArray, 1, 1) \
- F(NewArray, -1 /* >= 3 */, 1) \
- F(NormalizeElements, 1, 1) \
- F(TransitionElementsKind, 2, 1) \
- F(TransitionElementsKindWithKind, 2, 1) \
+#define FOR_EACH_INTRINSIC_ARRAY(F, I) \
+ F(ArrayIncludes_Slow, 3, 1) \
+ F(ArrayIndexOf, 3, 1) \
+ F(ArrayIsArray, 1, 1) \
+ F(ArraySpeciesConstructor, 1, 1) \
+ F(GrowArrayElements, 2, 1) \
+ I(IsArray, 1, 1) \
+ F(NewArray, -1 /* >= 3 */, 1) \
+ F(NormalizeElements, 1, 1) \
+ F(TransitionElementsKind, 2, 1) \
+ F(TransitionElementsKindWithKind, 2, 1)
#define FOR_EACH_INTRINSIC_ATOMICS(F, I) \
F(AtomicsLoad64, 2, 1) \
@@ -236,7 +236,7 @@ namespace internal {
F(ThrowIteratorError, 1, 1) \
F(ThrowIteratorResultNotAnObject, 1, 1) \
F(ThrowNotConstructor, 1, 1) \
- F(ThrowPatternAssignmentNonCoercible, 0, 1) \
+ F(ThrowPatternAssignmentNonCoercible, 1, 1) \
F(ThrowRangeError, -1 /* >= 1 */, 1) \
F(ThrowReferenceError, 1, 1) \
F(ThrowAccessedUninitializedVariable, 1, 1) \
@@ -247,8 +247,7 @@ namespace internal {
F(ThrowTypeError, -1 /* >= 1 */, 1) \
F(ThrowTypeErrorIfStrict, -1 /* >= 1 */, 1) \
F(Typeof, 1, 1) \
- F(UnwindAndFindExceptionHandler, 0, 1) \
- F(FinalizationGroupCleanupJob, 1, 1)
+ F(UnwindAndFindExceptionHandler, 0, 1)
#define FOR_EACH_INTRINSIC_LITERALS(F, I) \
F(CreateArrayLiteral, 4, 1) \
@@ -285,6 +284,7 @@ namespace internal {
F(CopyDataPropertiesWithExcludedProperties, -1 /* >= 1 */, 1) \
I(CreateDataProperty, 3, 1) \
I(CreateIterResultObject, 2, 1) \
+ F(CreatePrivateAccessors, 2, 1) \
F(DefineAccessorPropertyUnchecked, 5, 1) \
F(DefineDataPropertyInLiteral, 6, 1) \
F(DefineGetterPropertyUnchecked, 4, 1) \
@@ -305,6 +305,8 @@ namespace internal {
F(JSReceiverGetPrototypeOf, 1, 1) \
F(JSReceiverSetPrototypeOfDontThrow, 2, 1) \
F(JSReceiverSetPrototypeOfThrow, 2, 1) \
+ F(LoadPrivateGetter, 1, 1) \
+ F(LoadPrivateSetter, 1, 1) \
F(NewObject, 2, 1) \
F(ObjectCreate, 2, 1) \
F(ObjectEntries, 1, 1) \
@@ -495,12 +497,14 @@ namespace internal {
F(IsThreadInWasm, 0, 1) \
F(IsWasmCode, 1, 1) \
F(IsWasmTrapHandlerEnabled, 0, 1) \
+ F(RegexpHasBytecode, 2, 1) \
+ F(RegexpHasNativeCode, 2, 1) \
F(MapIteratorProtector, 0, 1) \
F(NeverOptimizeFunction, 1, 1) \
F(NotifyContextDisposed, 0, 1) \
F(OptimizeFunctionOnNextCall, -1, 1) \
F(OptimizeOsr, -1, 1) \
- F(PrepareFunctionForOptimization, 1, 1) \
+ F(PrepareFunctionForOptimization, -1, 1) \
F(PrintWithNameForAssert, 2, 1) \
F(RedirectToWasmInterpreter, 2, 1) \
F(RunningInSimulator, 0, 1) \
@@ -530,28 +534,30 @@ namespace internal {
F(TypedArraySet, 2, 1) \
F(TypedArraySortFast, 1, 1)
-#define FOR_EACH_INTRINSIC_WASM(F, I) \
- F(ThrowWasmError, 1, 1) \
- F(ThrowWasmStackOverflow, 0, 1) \
- F(WasmI32AtomicWait, 4, 1) \
- F(WasmI64AtomicWait, 5, 1) \
- F(WasmAtomicNotify, 3, 1) \
- F(WasmExceptionGetValues, 1, 1) \
- F(WasmExceptionGetTag, 1, 1) \
- F(WasmMemoryGrow, 2, 1) \
- F(WasmRunInterpreter, 2, 1) \
- F(WasmStackGuard, 0, 1) \
- F(WasmThrowCreate, 2, 1) \
- F(WasmThrowTypeError, 0, 1) \
- F(WasmRefFunc, 1, 1) \
- F(WasmFunctionTableGet, 3, 1) \
- F(WasmFunctionTableSet, 4, 1) \
- F(WasmTableInit, 5, 1) \
- F(WasmTableCopy, 5, 1) \
- F(WasmTableGrow, 3, 1) \
- F(WasmTableFill, 4, 1) \
- F(WasmIsValidFuncRefValue, 1, 1) \
- F(WasmCompileLazy, 2, 1)
+#define FOR_EACH_INTRINSIC_WASM(F, I) \
+ F(ThrowWasmError, 1, 1) \
+ F(ThrowWasmStackOverflow, 0, 1) \
+ F(WasmI32AtomicWait, 4, 1) \
+ F(WasmI64AtomicWait, 5, 1) \
+ F(WasmAtomicNotify, 3, 1) \
+ F(WasmExceptionGetValues, 1, 1) \
+ F(WasmExceptionGetTag, 1, 1) \
+ F(WasmMemoryGrow, 2, 1) \
+ F(WasmRunInterpreter, 2, 1) \
+ F(WasmStackGuard, 0, 1) \
+ F(WasmThrowCreate, 2, 1) \
+ F(WasmThrowTypeError, 0, 1) \
+ F(WasmRefFunc, 1, 1) \
+ F(WasmFunctionTableGet, 3, 1) \
+ F(WasmFunctionTableSet, 4, 1) \
+ F(WasmTableInit, 5, 1) \
+ F(WasmTableCopy, 5, 1) \
+ F(WasmTableGrow, 3, 1) \
+ F(WasmTableFill, 4, 1) \
+ F(WasmIsValidFuncRefValue, 1, 1) \
+ F(WasmCompileLazy, 2, 1) \
+ F(WasmNewMultiReturnFixedArray, 1, 1) \
+ F(WasmNewMultiReturnJSArray, 1, 1)
#define FOR_EACH_INTRINSIC_RETURN_PAIR_IMPL(F, I) \
F(DebugBreakOnBytecode, 1, 2) \
@@ -728,7 +734,6 @@ class Runtime : public AllStatic {
Isolate* isolate, Handle<Object> object);
};
-
class RuntimeState {
public:
#ifndef V8_INTL_SUPPORT
@@ -769,11 +774,11 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, Runtime::FunctionId);
//---------------------------------------------------------------------------
// Constants used by interface to runtime functions.
-class AllocateDoubleAlignFlag : public BitField<bool, 0, 1> {};
+using AllocateDoubleAlignFlag = BitField<bool, 0, 1>;
-class AllowLargeObjectAllocationFlag : public BitField<bool, 1, 1> {};
+using AllowLargeObjectAllocationFlag = BitField<bool, 1, 1>;
-class DeclareGlobalsEvalFlag : public BitField<bool, 0, 1> {};
+using DeclareGlobalsEvalFlag = BitField<bool, 0, 1>;
// A set of bits returned by Runtime_GetOptimizationStatus.
// These bits must be in sync with bits defined in test/mjsunit/mjsunit.js
@@ -791,6 +796,7 @@ enum class OptimizationStatus {
kIsExecuting = 1 << 10,
kTopmostFrameIsTurboFanned = 1 << 11,
kLiteMode = 1 << 12,
+ kMarkedForDeoptimization = 1 << 13,
};
} // namespace internal
diff --git a/deps/v8/src/sanitizer/OWNERS b/deps/v8/src/sanitizer/OWNERS
index 25abe6c3b1..96c9d10c12 100644
--- a/deps/v8/src/sanitizer/OWNERS
+++ b/deps/v8/src/sanitizer/OWNERS
@@ -1,3 +1,3 @@
-file://INFRA_OWNERS
+file:../../INFRA_OWNERS
clemensh@chromium.org
diff --git a/deps/v8/src/sanitizer/lsan-page-allocator.cc b/deps/v8/src/sanitizer/lsan-page-allocator.cc
index 68b1f130b1..8f7f6f4666 100644
--- a/deps/v8/src/sanitizer/lsan-page-allocator.cc
+++ b/deps/v8/src/sanitizer/lsan-page-allocator.cc
@@ -20,11 +20,10 @@ LsanPageAllocator::LsanPageAllocator(v8::PageAllocator* page_allocator)
DCHECK_NOT_NULL(page_allocator);
}
-void* LsanPageAllocator::AllocatePages(void* address, size_t size,
+void* LsanPageAllocator::AllocatePages(void* hint, size_t size,
size_t alignment,
PageAllocator::Permission access) {
- void* result =
- page_allocator_->AllocatePages(address, size, alignment, access);
+ void* result = page_allocator_->AllocatePages(hint, size, alignment, access);
#if defined(LEAK_SANITIZER)
if (result != nullptr) {
__lsan_register_root_region(result, size);
diff --git a/deps/v8/src/snapshot/code-serializer.cc b/deps/v8/src/snapshot/code-serializer.cc
index d7e208eac5..774c2f3789 100644
--- a/deps/v8/src/snapshot/code-serializer.cc
+++ b/deps/v8/src/snapshot/code-serializer.cc
@@ -312,6 +312,8 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
log_code_creation);
#endif // V8_TARGET_ARCH_ARM
+ bool needs_source_positions = isolate->NeedsSourcePositionsForProfiling();
+
if (log_code_creation || FLAG_log_function_events) {
Handle<Script> script(Script::cast(result->script()), isolate);
Handle<String> name(script->name().IsString()
@@ -328,22 +330,29 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
if (log_code_creation) {
Script::InitLineEnds(script);
- DisallowHeapAllocation no_gc;
SharedFunctionInfo::ScriptIterator iter(isolate, *script);
- for (i::SharedFunctionInfo info = iter.Next(); !info.is_null();
+ for (SharedFunctionInfo info = iter.Next(); !info.is_null();
info = iter.Next()) {
if (info.is_compiled()) {
- int line_num = script->GetLineNumber(info.StartPosition()) + 1;
- int column_num = script->GetColumnNumber(info.StartPosition()) + 1;
+ Handle<SharedFunctionInfo> shared_info(info, isolate);
+ if (needs_source_positions) {
+ SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate,
+ shared_info);
+ }
+ DisallowHeapAllocation no_gc;
+ int line_num =
+ script->GetLineNumber(shared_info->StartPosition()) + 1;
+ int column_num =
+ script->GetColumnNumber(shared_info->StartPosition()) + 1;
PROFILE(isolate, CodeCreateEvent(CodeEventListener::SCRIPT_TAG,
- info.abstract_code(), info, *name,
- line_num, column_num));
+ info.abstract_code(), *shared_info,
+ *name, line_num, column_num));
}
}
}
}
- if (isolate->NeedsSourcePositionsForProfiling()) {
+ if (needs_source_positions) {
Handle<Script> script(Script::cast(result->script()), isolate);
Script::InitLineEnds(script);
}
diff --git a/deps/v8/src/snapshot/embedded/embedded-data.cc b/deps/v8/src/snapshot/embedded/embedded-data.cc
index 0474d3babe..2f6d17d6b2 100644
--- a/deps/v8/src/snapshot/embedded/embedded-data.cc
+++ b/deps/v8/src/snapshot/embedded/embedded-data.cc
@@ -55,20 +55,35 @@ Code InstructionStream::TryLookupCode(Isolate* isolate, Address address) {
void InstructionStream::CreateOffHeapInstructionStream(Isolate* isolate,
uint8_t** data,
uint32_t* size) {
+ // Create the embedded blob from scratch using the current Isolate's heap.
EmbeddedData d = EmbeddedData::FromIsolate(isolate);
+ // Allocate the backing store that will contain the embedded blob in this
+ // Isolate. The backing store is on the native heap, *not* on V8's garbage-
+ // collected heap.
v8::PageAllocator* page_allocator = v8::internal::GetPlatformPageAllocator();
- const uint32_t page_size =
+ const uint32_t alignment =
static_cast<uint32_t>(page_allocator->AllocatePageSize());
- const uint32_t allocated_size = RoundUp(d.size(), page_size);
+
+ void* const requested_allocation_address =
+ AlignedAddress(isolate->heap()->GetRandomMmapAddr(), alignment);
+ const uint32_t allocation_size = RoundUp(d.size(), alignment);
uint8_t* allocated_bytes = static_cast<uint8_t*>(
- AllocatePages(page_allocator, isolate->heap()->GetRandomMmapAddr(),
- allocated_size, page_size, PageAllocator::kReadWrite));
+ AllocatePages(page_allocator, requested_allocation_address,
+ allocation_size, alignment, PageAllocator::kReadWrite));
CHECK_NOT_NULL(allocated_bytes);
+ // Copy the embedded blob into the newly allocated backing store. Switch
+ // permissions to read-execute since builtin code is immutable from now on
+ // and must be executable in case any JS execution is triggered.
+ //
+ // Once this backing store is set as the current_embedded_blob, V8 cannot tell
+ // the difference between a 'real' embedded build (where the blob is embedded
+ // in the binary) and what we are currently setting up here (where the blob is
+ // on the native heap).
std::memcpy(allocated_bytes, d.data(), d.size());
- CHECK(SetPermissions(page_allocator, allocated_bytes, allocated_size,
+ CHECK(SetPermissions(page_allocator, allocated_bytes, allocation_size,
PageAllocator::kReadExecute));
*data = allocated_bytes;
diff --git a/deps/v8/src/snapshot/embedded/embedded-file-writer.cc b/deps/v8/src/snapshot/embedded/embedded-file-writer.cc
index 4703ef4822..5f57993fc3 100644
--- a/deps/v8/src/snapshot/embedded/embedded-file-writer.cc
+++ b/deps/v8/src/snapshot/embedded/embedded-file-writer.cc
@@ -92,7 +92,7 @@ void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w,
w->Newline();
}
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
{
i::EmbeddedVector<char, kTemporaryStringLength> unwind_info_symbol;
i::SNPrintF(unwind_info_symbol, "%s_Builtins_UnwindInfo",
@@ -102,7 +102,7 @@ void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w,
EmbeddedBlobDataSymbol().c_str(), blob,
reinterpret_cast<const void*>(&unwind_infos_[0]));
}
-#endif
+#endif // V8_OS_WIN64
w->FileEpilogue();
}
diff --git a/deps/v8/src/snapshot/embedded/embedded-file-writer.h b/deps/v8/src/snapshot/embedded/embedded-file-writer.h
index c26465ae6a..e487b9be9b 100644
--- a/deps/v8/src/snapshot/embedded/embedded-file-writer.h
+++ b/deps/v8/src/snapshot/embedded/embedded-file-writer.h
@@ -13,9 +13,9 @@
#include "src/snapshot/embedded/embedded-data.h"
#include "src/snapshot/embedded/platform-embedded-file-writer-base.h"
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
#include "src/diagnostics/unwinding-info-win64.h"
-#endif
+#endif // V8_OS_WIN64
namespace v8 {
namespace internal {
@@ -35,11 +35,11 @@ class EmbeddedFileWriterInterface {
// compiled builtin Code objects with trampolines.
virtual void PrepareBuiltinSourcePositionMap(Builtins* builtins) = 0;
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
virtual void SetBuiltinUnwindData(
int builtin_index,
const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) = 0;
-#endif
+#endif // V8_OS_WIN64
};
// Generates the embedded.S file which is later compiled into the final v8
@@ -59,14 +59,14 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
void PrepareBuiltinSourcePositionMap(Builtins* builtins) override;
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
void SetBuiltinUnwindData(
int builtin_index,
const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) override {
DCHECK_LT(builtin_index, Builtins::builtin_count);
unwind_infos_[builtin_index] = unwinding_info;
}
-#endif
+#endif // V8_OS_WIN64
void SetEmbeddedFile(const char* embedded_src_path) {
embedded_src_path_ = embedded_src_path;
@@ -172,9 +172,6 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
const i::EmbeddedData* blob) const;
#if defined(V8_OS_WIN_X64)
- std::string BuiltinsUnwindInfoLabel() const;
- void WriteUnwindInfo(PlatformEmbeddedFileWriterBase* w,
- const i::EmbeddedData* blob) const;
void WriteUnwindInfoEntry(PlatformEmbeddedFileWriterBase* w,
uint64_t rva_start, uint64_t rva_end) const;
#endif
@@ -194,9 +191,9 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
private:
std::vector<byte> source_positions_[Builtins::builtin_count];
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
win64_unwindinfo::BuiltinUnwindInfo unwind_infos_[Builtins::builtin_count];
-#endif
+#endif // V8_OS_WIN64
std::map<const char*, int> external_filenames_;
std::vector<const char*> external_filenames_by_index_;
diff --git a/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-win.cc b/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-win.cc
index d0758cb42c..9a9a26fbd0 100644
--- a/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-win.cc
+++ b/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-win.cc
@@ -6,14 +6,14 @@
#include <algorithm>
-#include "src/common/globals.h" // For V8_OS_WIN_X64.
+#include "src/common/globals.h" // For V8_OS_WIN64
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
#include "src/builtins/builtins.h"
#include "src/diagnostics/unwinding-info-win64.h"
-#include "src/objects/objects-inl.h"
#include "src/snapshot/embedded/embedded-data.h"
-#endif
+#include "src/snapshot/embedded/embedded-file-writer.h"
+#endif // V8_OS_WIN64
namespace v8 {
namespace internal {
@@ -214,20 +214,118 @@ void EmitUnwindData(PlatformEmbeddedFileWriterWin* w,
w->EndPdataSection();
w->Newline();
}
-#endif // defined(V8_OS_WIN_X64)
+
+#elif defined(V8_OS_WIN_ARM64)
+
+void EmitUnwindData(PlatformEmbeddedFileWriterWin* w,
+ const char* unwind_info_symbol,
+ const char* embedded_blob_data_symbol,
+ const EmbeddedData* blob,
+ const win64_unwindinfo::BuiltinUnwindInfo* unwind_infos) {
+ DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins());
+
+ // Fairly arbitrary but should fit all symbol names.
+ static constexpr int kTemporaryStringLength = 256;
+ i::EmbeddedVector<char, kTemporaryStringLength> unwind_info_full_symbol;
+
+ // Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as
+ // documented here:
+ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling.
+ w->Comment(
+ "pdata for all the code in the embedded blob (structs of type "
+ "RUNTIME_FUNCTION).");
+ w->Comment(" BeginAddress");
+ w->Comment(" UnwindInfoAddress");
+ w->StartPdataSection();
+ std::vector<int> code_chunks;
+ std::vector<int> fp_adjustments;
+
+ for (int i = 0; i < Builtins::builtin_count; i++) {
+ if (!blob->ContainsBuiltin(i)) continue;
+ if (unwind_infos[i].is_leaf_function()) continue;
+
+ uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(i) -
+ reinterpret_cast<Address>(blob->data());
+ uint32_t builtin_size = blob->InstructionSizeOfBuiltin(i);
+
+ const std::vector<int>& xdata_desc = unwind_infos[i].fp_offsets();
+ const std::vector<int>& xdata_fp_adjustments =
+ unwind_infos[i].fp_adjustments();
+ DCHECK_EQ(xdata_desc.size(), xdata_fp_adjustments.size());
+
+ for (size_t j = 0; j < xdata_desc.size(); j++) {
+ int chunk_start = xdata_desc[j];
+ int chunk_end =
+ (j < xdata_desc.size() - 1) ? xdata_desc[j + 1] : builtin_size;
+ int chunk_len = ::RoundUp(chunk_end - chunk_start, kInstrSize);
+
+ while (chunk_len > 0) {
+ int allowed_chunk_len =
+ std::min(chunk_len, win64_unwindinfo::kMaxFunctionLength);
+ chunk_len -= win64_unwindinfo::kMaxFunctionLength;
+
+ // Record the chunk length and fp_adjustment for emitting UNWIND_INFO
+ // later.
+ code_chunks.push_back(allowed_chunk_len);
+ fp_adjustments.push_back(xdata_fp_adjustments[j]);
+ i::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol,
+ code_chunks.size());
+ w->DeclareRvaToSymbol(embedded_blob_data_symbol,
+ builtin_start_offset + chunk_start);
+ w->DeclareRvaToSymbol(unwind_info_full_symbol.begin());
+ }
+ }
+ }
+ w->EndPdataSection();
+ w->Newline();
+
+ // Emit an UNWIND_INFO (XDATA) structs, which contains the unwinding
+ // information.
+ w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING);
+ w->StartXdataSection();
+ {
+ for (size_t i = 0; i < code_chunks.size(); i++) {
+ i::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol, i + 1);
+ w->DeclareLabel(unwind_info_full_symbol.begin());
+ std::vector<uint8_t> xdata =
+ win64_unwindinfo::GetUnwindInfoForBuiltinFunction(code_chunks[i],
+ fp_adjustments[i]);
+
+ w->IndentedDataDirective(kByte);
+ for (size_t j = 0; j < xdata.size(); j++) {
+ if (j > 0) fprintf(w->fp(), ",");
+ w->HexLiteral(xdata[j]);
+ }
+ w->Newline();
+ w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING);
+ }
+ }
+ w->EndXdataSection();
+ w->Newline();
+}
+
+#endif // V8_OS_WIN_X64
} // namespace
void PlatformEmbeddedFileWriterWin::MaybeEmitUnwindData(
const char* unwind_info_symbol, const char* embedded_blob_data_symbol,
const EmbeddedData* blob, const void* unwind_infos) {
-#if defined(V8_OS_WIN_X64)
+// Windows ARM64 supports cross build which could require unwind info for
+// host_os. Ignore this case because it is only used in build time.
+#if defined(V8_OS_WIN_ARM64)
+ if (target_arch_ != EmbeddedTargetArch::kArm64) {
+ return;
+ }
+#endif // V8_OS_WIN_ARM64
+
+#if defined(V8_OS_WIN64)
if (win64_unwindinfo::CanEmitUnwindInfoForBuiltins()) {
EmitUnwindData(this, unwind_info_symbol, embedded_blob_data_symbol, blob,
reinterpret_cast<const win64_unwindinfo::BuiltinUnwindInfo*>(
unwind_infos));
}
-#endif // defined(V8_OS_WIN_X64)
+#endif // V8_OS_WIN64
}
// Windows, MSVC, not arm/arm64.
@@ -545,6 +643,7 @@ void PlatformEmbeddedFileWriterWin::DeclareFunctionBegin(const char* name) {
if (target_arch_ == EmbeddedTargetArch::kArm64) {
// Windows ARM64 assembly is in GAS syntax, but ".type" is invalid directive
// in PE/COFF for Windows.
+ DeclareSymbolGlobal(name);
} else {
// The directives for inserting debugging information on Windows come
// from the PE (Portable Executable) and COFF (Common Object File Format)
@@ -570,11 +669,7 @@ void PlatformEmbeddedFileWriterWin::DeclareExternalFilename(
// Replace any Windows style paths (backslashes) with forward
// slashes.
std::string fixed_filename(filename);
- for (auto& c : fixed_filename) {
- if (c == '\\') {
- c = '/';
- }
- }
+ std::replace(fixed_filename.begin(), fixed_filename.end(), '\\', '/');
fprintf(fp_, ".file %d \"%s\"\n", fileid, fixed_filename.c_str());
}
diff --git a/deps/v8/src/snapshot/references.h b/deps/v8/src/snapshot/references.h
index c81e9a1e21..215db9d9a5 100644
--- a/deps/v8/src/snapshot/references.h
+++ b/deps/v8/src/snapshot/references.h
@@ -154,12 +154,10 @@ class SerializerReference {
}
private:
- class SpaceBits : public BitField<SnapshotSpace, 0, kSpaceTagSize> {};
- class ChunkIndexBits
- : public BitField<uint32_t, SpaceBits::kNext, 32 - kSpaceTagSize> {};
- class SpecialValueTypeBits
- : public BitField<SpecialValueType, SpaceBits::kNext,
- 32 - kSpaceTagSize> {};
+ using SpaceBits = BitField<SnapshotSpace, 0, kSpaceTagSize>;
+ using ChunkIndexBits = SpaceBits::Next<uint32_t, 32 - kSpaceTagSize>;
+ using SpecialValueTypeBits =
+ SpaceBits::Next<SpecialValueType, 32 - kSpaceTagSize>;
// We use two fields to store a reference.
// In case of a normal back reference, the bitfield_ stores the space and
diff --git a/deps/v8/src/snapshot/serializer-common.h b/deps/v8/src/snapshot/serializer-common.h
index c845a089a3..2a30fefe33 100644
--- a/deps/v8/src/snapshot/serializer-common.h
+++ b/deps/v8/src/snapshot/serializer-common.h
@@ -34,8 +34,8 @@ class ExternalReferenceEncoder {
uint32_t index() const { return Index::decode(value_); }
private:
- class Index : public BitField<uint32_t, 0, 31> {};
- class IsFromAPI : public BitField<bool, 31, 1> {};
+ using Index = BitField<uint32_t, 0, 31>;
+ using IsFromAPI = BitField<bool, 31, 1>;
uint32_t value_;
};
@@ -328,8 +328,8 @@ class SerializedData {
uint32_t GetMagicNumber() const { return GetHeaderValue(kMagicNumberOffset); }
- class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};
- class IsLastChunkBits : public BitField<bool, 31, 1> {};
+ using ChunkSizeBits = BitField<uint32_t, 0, 31>;
+ using IsLastChunkBits = BitField<bool, 31, 1>;
static constexpr uint32_t kMagicNumberOffset = 0;
static constexpr uint32_t kMagicNumber =
diff --git a/deps/v8/src/snapshot/snapshot.h b/deps/v8/src/snapshot/snapshot.h
index f7e1e86b84..4a4da9f755 100644
--- a/deps/v8/src/snapshot/snapshot.h
+++ b/deps/v8/src/snapshot/snapshot.h
@@ -8,7 +8,6 @@
#include "src/snapshot/partial-serializer.h"
#include "src/snapshot/startup-serializer.h"
-#include "src/objects/objects-inl.h"
#include "src/utils/utils.h"
namespace v8 {
diff --git a/deps/v8/src/snapshot/startup-serializer.cc b/deps/v8/src/snapshot/startup-serializer.cc
index 6ad2efc18b..4e4bc9eefc 100644
--- a/deps/v8/src/snapshot/startup-serializer.cc
+++ b/deps/v8/src/snapshot/startup-serializer.cc
@@ -143,13 +143,9 @@ void StartupSerializer::SerializeStrongReferences() {
// No active or weak handles.
CHECK(isolate->handle_scope_implementer()->blocks()->empty());
- // Visit smi roots.
- // Clear the stack limits to make the snapshot reproducible.
- // Reset it again afterwards.
- isolate->heap()->ClearStackLimits();
+ // Visit smi roots and immortal immovables first to make sure they end up in
+ // the first page.
isolate->heap()->IterateSmiRoots(this);
- isolate->heap()->SetStackLimits();
- // First visit immortal immovables to make sure they end up in the first page.
isolate->heap()->IterateStrongRoots(this, VISIT_FOR_SERIALIZATION);
}
diff --git a/deps/v8/src/strings/char-predicates-inl.h b/deps/v8/src/strings/char-predicates-inl.h
index 3b9b13aba5..8ff9f0d21f 100644
--- a/deps/v8/src/strings/char-predicates-inl.h
+++ b/deps/v8/src/strings/char-predicates-inl.h
@@ -81,14 +81,14 @@ enum AsciiCharFlags {
kIsWhiteSpaceOrLineTerminator = 1 << 3
};
constexpr uint8_t BuildAsciiCharFlags(uc32 c) {
- // clang-format off
- return
- (IsAsciiIdentifier(c) || c == '\\') ? (
- kIsIdentifierPart | (!IsDecimalDigit(c) ? kIsIdentifierStart : 0)) : 0 |
- (c == ' ' || c == '\t' || c == '\v' || c == '\f') ?
- kIsWhiteSpace | kIsWhiteSpaceOrLineTerminator : 0 |
- (c == '\r' || c == '\n') ? kIsWhiteSpaceOrLineTerminator : 0;
- // clang-format on
+ return ((IsAsciiIdentifier(c) || c == '\\')
+ ? (kIsIdentifierPart |
+ (!IsDecimalDigit(c) ? kIsIdentifierStart : 0))
+ : 0) |
+ ((c == ' ' || c == '\t' || c == '\v' || c == '\f')
+ ? kIsWhiteSpace | kIsWhiteSpaceOrLineTerminator
+ : 0) |
+ ((c == '\r' || c == '\n') ? kIsWhiteSpaceOrLineTerminator : 0);
}
const constexpr uint8_t kAsciiCharFlags[128] = {
#define BUILD_CHAR_FLAGS(N) BuildAsciiCharFlags(N),
diff --git a/deps/v8/src/strings/unicode.h b/deps/v8/src/strings/unicode.h
index bd94300e34..48483af9e1 100644
--- a/deps/v8/src/strings/unicode.h
+++ b/deps/v8/src/strings/unicode.h
@@ -51,8 +51,8 @@ class Predicate {
bool value() const { return ValueField::decode(bit_field_); }
private:
- class CodePointField : public v8::internal::BitField<uchar, 0, 21> {};
- class ValueField : public v8::internal::BitField<bool, 21, 1> {};
+ using CodePointField = v8::internal::BitField<uchar, 0, 21>;
+ using ValueField = v8::internal::BitField<bool, 21, 1>;
uint32_t bit_field_;
};
diff --git a/deps/v8/src/third_party/valgrind/OWNERS b/deps/v8/src/third_party/valgrind/OWNERS
index 852d438bb0..cb9c7e9c38 100644
--- a/deps/v8/src/third_party/valgrind/OWNERS
+++ b/deps/v8/src/third_party/valgrind/OWNERS
@@ -1 +1 @@
-file://COMMON_OWNERS
+file:../../../COMMON_OWNERS
diff --git a/deps/v8/src/third_party/vtune/OWNERS b/deps/v8/src/third_party/vtune/OWNERS
index 852d438bb0..cb9c7e9c38 100644
--- a/deps/v8/src/third_party/vtune/OWNERS
+++ b/deps/v8/src/third_party/vtune/OWNERS
@@ -1 +1 @@
-file://COMMON_OWNERS
+file:../../../COMMON_OWNERS
diff --git a/deps/v8/src/torque/ast.h b/deps/v8/src/torque/ast.h
index 23de121065..5ce25cf13a 100644
--- a/deps/v8/src/torque/ast.h
+++ b/deps/v8/src/torque/ast.h
@@ -46,8 +46,7 @@ namespace torque {
#define AST_TYPE_EXPRESSION_NODE_KIND_LIST(V) \
V(BasicTypeExpression) \
V(FunctionTypeExpression) \
- V(UnionTypeExpression) \
- V(ReferenceTypeExpression)
+ V(UnionTypeExpression)
#define AST_STATEMENT_NODE_KIND_LIST(V) \
V(BlockStatement) \
@@ -72,20 +71,17 @@ namespace torque {
#define AST_DECLARATION_NODE_KIND_LIST(V) \
AST_TYPE_DECLARATION_NODE_KIND_LIST(V) \
- V(StandardDeclaration) \
V(GenericDeclaration) \
V(SpecializationDeclaration) \
V(ExternConstDeclaration) \
V(NamespaceDeclaration) \
V(ConstDeclaration) \
- V(CppIncludeDeclaration)
-
-#define AST_CALLABLE_NODE_KIND_LIST(V) \
- V(TorqueMacroDeclaration) \
- V(TorqueBuiltinDeclaration) \
- V(ExternalMacroDeclaration) \
- V(ExternalBuiltinDeclaration) \
- V(ExternalRuntimeDeclaration) \
+ V(CppIncludeDeclaration) \
+ V(TorqueMacroDeclaration) \
+ V(TorqueBuiltinDeclaration) \
+ V(ExternalMacroDeclaration) \
+ V(ExternalBuiltinDeclaration) \
+ V(ExternalRuntimeDeclaration) \
V(IntrinsicDeclaration)
#define AST_NODE_KIND_LIST(V) \
@@ -93,7 +89,6 @@ namespace torque {
AST_TYPE_EXPRESSION_NODE_KIND_LIST(V) \
AST_STATEMENT_NODE_KIND_LIST(V) \
AST_DECLARATION_NODE_KIND_LIST(V) \
- AST_CALLABLE_NODE_KIND_LIST(V) \
V(Identifier) \
V(LabelBlock)
@@ -118,16 +113,16 @@ struct AstNodeClassCheck {
};
// Boilerplate for most derived classes.
-#define DEFINE_AST_NODE_LEAF_BOILERPLATE(T) \
- static const Kind kKind = Kind::k##T; \
- static T* cast(AstNode* node) { \
- if (node->kind != kKind) return nullptr; \
- return static_cast<T*>(node); \
- } \
- static T* DynamicCast(AstNode* node) { \
- if (!node) return nullptr; \
- if (!AstNodeClassCheck::IsInstanceOf<T>(node)) return nullptr; \
- return static_cast<T*>(node); \
+#define DEFINE_AST_NODE_LEAF_BOILERPLATE(T) \
+ static const Kind kKind = Kind::k##T; \
+ static T* cast(AstNode* node) { \
+ DCHECK_EQ(node->kind, kKind); \
+ return static_cast<T*>(node); \
+ } \
+ static T* DynamicCast(AstNode* node) { \
+ if (!node) return nullptr; \
+ if (node->kind != kKind) return nullptr; \
+ return static_cast<T*>(node); \
}
// Boilerplate for classes with subclasses.
@@ -221,6 +216,10 @@ struct Identifier : AstNode {
std::string value;
};
+inline std::ostream& operator<<(std::ostream& os, Identifier* id) {
+ return os << id->value;
+}
+
struct IdentifierPtrValueEq {
bool operator()(const Identifier* a, const Identifier* b) {
return a->value < b->value;
@@ -252,11 +251,11 @@ struct IdentifierExpression : LocationExpression {
struct IntrinsicCallExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(IntrinsicCallExpression)
- IntrinsicCallExpression(SourcePosition pos, std::string name,
+ IntrinsicCallExpression(SourcePosition pos, Identifier* name,
std::vector<TypeExpression*> generic_arguments,
std::vector<Expression*> arguments)
: Expression(kKind, pos),
- name(std::move(name)),
+ name(name),
generic_arguments(std::move(generic_arguments)),
arguments(std::move(arguments)) {}
@@ -267,7 +266,7 @@ struct IntrinsicCallExpression : Expression {
callback(this);
}
- std::string name;
+ Identifier* name;
std::vector<TypeExpression*> generic_arguments;
std::vector<Expression*> arguments;
};
@@ -619,13 +618,6 @@ struct UnionTypeExpression : TypeExpression {
TypeExpression* b;
};
-struct ReferenceTypeExpression : TypeExpression {
- DEFINE_AST_NODE_LEAF_BOILERPLATE(ReferenceTypeExpression)
- ReferenceTypeExpression(SourcePosition pos, TypeExpression* referenced_type)
- : TypeExpression(kKind, pos), referenced_type(referenced_type) {}
- TypeExpression* referenced_type;
-};
-
struct ExpressionStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ExpressionStatement)
ExpressionStatement(SourcePosition pos, Expression* expression)
@@ -849,10 +841,15 @@ struct ConditionalAnnotation {
ConditionalAnnotationType type;
};
+struct Annotation {
+ Identifier* name;
+ base::Optional<std::string> param;
+};
+
struct ClassFieldExpression {
NameAndTypeExpression name_and_type;
base::Optional<std::string> index;
- base::Optional<ConditionalAnnotation> conditional;
+ std::vector<ConditionalAnnotation> conditions;
bool weak;
bool const_qualified;
bool generate_verify;
@@ -865,34 +862,33 @@ struct LabelAndTypes {
using LabelAndTypesVector = std::vector<LabelAndTypes>;
-struct CallableNodeSignature {
+struct CallableDeclaration : Declaration {
+ CallableDeclaration(AstNode::Kind kind, SourcePosition pos,
+ bool transitioning, Identifier* name,
+ ParameterList parameters, TypeExpression* return_type,
+ LabelAndTypesVector labels)
+ : Declaration(kind, pos),
+ transitioning(transitioning),
+ name(name),
+ parameters(std::move(parameters)),
+ return_type(return_type),
+ labels(std::move(labels)) {}
+ DEFINE_AST_NODE_INNER_BOILERPLATE(CallableDeclaration)
+ bool transitioning;
+ Identifier* name;
ParameterList parameters;
TypeExpression* return_type;
LabelAndTypesVector labels;
};
-struct CallableNode : AstNode {
- CallableNode(AstNode::Kind kind, SourcePosition pos, bool transitioning,
- std::string name, ParameterList parameters,
- TypeExpression* return_type, const LabelAndTypesVector& labels)
- : AstNode(kind, pos),
- transitioning(transitioning),
- name(std::move(name)),
- signature(new CallableNodeSignature{parameters, return_type, labels}) {}
- DEFINE_AST_NODE_INNER_BOILERPLATE(CallableNode)
- bool transitioning;
- std::string name;
- std::unique_ptr<CallableNodeSignature> signature;
-};
-
-struct MacroDeclaration : CallableNode {
+struct MacroDeclaration : CallableDeclaration {
DEFINE_AST_NODE_INNER_BOILERPLATE(MacroDeclaration)
MacroDeclaration(AstNode::Kind kind, SourcePosition pos, bool transitioning,
- std::string name, base::Optional<std::string> op,
+ Identifier* name, base::Optional<std::string> op,
ParameterList parameters, TypeExpression* return_type,
const LabelAndTypesVector& labels)
- : CallableNode(kind, pos, transitioning, std::move(name),
- std::move(parameters), return_type, labels),
+ : CallableDeclaration(kind, pos, transitioning, name,
+ std::move(parameters), return_type, labels),
op(std::move(op)) {
if (parameters.implicit_kind == ImplicitKind::kJSImplicit) {
Error("Cannot use \"js-implicit\" with macros, use \"implicit\" instead.")
@@ -906,23 +902,22 @@ struct ExternalMacroDeclaration : MacroDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ExternalMacroDeclaration)
ExternalMacroDeclaration(SourcePosition pos, bool transitioning,
std::string external_assembler_name,
- std::string name, base::Optional<std::string> op,
+ Identifier* name, base::Optional<std::string> op,
ParameterList parameters,
TypeExpression* return_type,
const LabelAndTypesVector& labels)
- : MacroDeclaration(kKind, pos, transitioning, std::move(name),
- std::move(op), std::move(parameters), return_type,
- labels),
+ : MacroDeclaration(kKind, pos, transitioning, name, std::move(op),
+ std::move(parameters), return_type, labels),
external_assembler_name(std::move(external_assembler_name)) {}
std::string external_assembler_name;
};
-struct IntrinsicDeclaration : CallableNode {
+struct IntrinsicDeclaration : CallableDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(IntrinsicDeclaration)
- IntrinsicDeclaration(SourcePosition pos, std::string name,
+ IntrinsicDeclaration(SourcePosition pos, Identifier* name,
ParameterList parameters, TypeExpression* return_type)
- : CallableNode(kKind, pos, false, std::move(name), std::move(parameters),
- return_type, {}) {
+ : CallableDeclaration(kKind, pos, false, name, std::move(parameters),
+ return_type, {}) {
if (parameters.implicit_kind != ImplicitKind::kNoImplicit) {
Error("Intinsics cannot have implicit parameters.");
}
@@ -932,24 +927,26 @@ struct IntrinsicDeclaration : CallableNode {
struct TorqueMacroDeclaration : MacroDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(TorqueMacroDeclaration)
TorqueMacroDeclaration(SourcePosition pos, bool transitioning,
- std::string name, base::Optional<std::string> op,
+ Identifier* name, base::Optional<std::string> op,
ParameterList parameters, TypeExpression* return_type,
- const LabelAndTypesVector& labels, bool export_to_csa)
- : MacroDeclaration(kKind, pos, transitioning, std::move(name),
- std::move(op), std::move(parameters), return_type,
- labels),
- export_to_csa(export_to_csa) {}
+ const LabelAndTypesVector& labels, bool export_to_csa,
+ base::Optional<Statement*> body)
+ : MacroDeclaration(kKind, pos, transitioning, name, std::move(op),
+ std::move(parameters), return_type, labels),
+ export_to_csa(export_to_csa),
+ body(body) {}
bool export_to_csa;
+ base::Optional<Statement*> body;
};
-struct BuiltinDeclaration : CallableNode {
+struct BuiltinDeclaration : CallableDeclaration {
DEFINE_AST_NODE_INNER_BOILERPLATE(BuiltinDeclaration)
BuiltinDeclaration(AstNode::Kind kind, SourcePosition pos,
bool javascript_linkage, bool transitioning,
- std::string name, ParameterList parameters,
+ Identifier* name, ParameterList parameters,
TypeExpression* return_type)
- : CallableNode(kind, pos, transitioning, std::move(name),
- std::move(parameters), return_type, {}),
+ : CallableDeclaration(kind, pos, transitioning, name,
+ std::move(parameters), return_type, {}),
javascript_linkage(javascript_linkage) {
if (parameters.implicit_kind == ImplicitKind::kJSImplicit &&
!javascript_linkage) {
@@ -971,32 +968,33 @@ struct BuiltinDeclaration : CallableNode {
struct ExternalBuiltinDeclaration : BuiltinDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ExternalBuiltinDeclaration)
ExternalBuiltinDeclaration(SourcePosition pos, bool transitioning,
- bool javascript_linkage, std::string name,
+ bool javascript_linkage, Identifier* name,
ParameterList parameters,
TypeExpression* return_type)
- : BuiltinDeclaration(kKind, pos, javascript_linkage, transitioning,
- std::move(name), std::move(parameters),
- return_type) {}
+ : BuiltinDeclaration(kKind, pos, javascript_linkage, transitioning, name,
+ std::move(parameters), return_type) {}
};
struct TorqueBuiltinDeclaration : BuiltinDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(TorqueBuiltinDeclaration)
TorqueBuiltinDeclaration(SourcePosition pos, bool transitioning,
- bool javascript_linkage, std::string name,
+ bool javascript_linkage, Identifier* name,
ParameterList parameters,
- TypeExpression* return_type)
- : BuiltinDeclaration(kKind, pos, javascript_linkage, transitioning,
- std::move(name), std::move(parameters),
- return_type) {}
+ TypeExpression* return_type,
+ base::Optional<Statement*> body)
+ : BuiltinDeclaration(kKind, pos, javascript_linkage, transitioning, name,
+ std::move(parameters), return_type),
+ body(body) {}
+ base::Optional<Statement*> body;
};
-struct ExternalRuntimeDeclaration : CallableNode {
+struct ExternalRuntimeDeclaration : CallableDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ExternalRuntimeDeclaration)
ExternalRuntimeDeclaration(SourcePosition pos, bool transitioning,
- std::string name, ParameterList parameters,
+ Identifier* name, ParameterList parameters,
TypeExpression* return_type)
- : CallableNode(kKind, pos, transitioning, name, parameters, return_type,
- {}) {}
+ : CallableDeclaration(kKind, pos, transitioning, name, parameters,
+ return_type, {}) {}
};
struct ConstDeclaration : Declaration {
@@ -1012,47 +1010,32 @@ struct ConstDeclaration : Declaration {
Expression* expression;
};
-struct StandardDeclaration : Declaration {
- DEFINE_AST_NODE_LEAF_BOILERPLATE(StandardDeclaration)
- StandardDeclaration(SourcePosition pos, CallableNode* callable,
- base::Optional<Statement*> body)
- : Declaration(kKind, pos), callable(callable), body(body) {}
- CallableNode* callable;
- base::Optional<Statement*> body;
-};
-
struct GenericDeclaration : Declaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(GenericDeclaration)
- GenericDeclaration(SourcePosition pos, CallableNode* callable,
+ GenericDeclaration(SourcePosition pos,
std::vector<Identifier*> generic_parameters,
- base::Optional<Statement*> body = base::nullopt)
+ CallableDeclaration* declaration)
: Declaration(kKind, pos),
- callable(callable),
generic_parameters(std::move(generic_parameters)),
- body(body) {}
- CallableNode* callable;
+ declaration(declaration) {}
std::vector<Identifier*> generic_parameters;
- base::Optional<Statement*> body;
+ CallableDeclaration* declaration;
};
-struct SpecializationDeclaration : Declaration {
+struct SpecializationDeclaration : CallableDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(SpecializationDeclaration)
- SpecializationDeclaration(SourcePosition pos, Identifier* name,
+ SpecializationDeclaration(SourcePosition pos, bool transitioning,
+ Identifier* name,
std::vector<TypeExpression*> generic_parameters,
ParameterList parameters,
TypeExpression* return_type,
- LabelAndTypesVector labels, Statement* b)
- : Declaration(kKind, pos),
- name(name),
- external(false),
+ LabelAndTypesVector labels, Statement* body)
+ : CallableDeclaration(kKind, pos, transitioning, name,
+ std::move(parameters), return_type,
+ std::move(labels)),
generic_parameters(std::move(generic_parameters)),
- signature(new CallableNodeSignature{std::move(parameters), return_type,
- std::move(labels)}),
- body(b) {}
- Identifier* name;
- bool external;
+ body(body) {}
std::vector<TypeExpression*> generic_parameters;
- std::unique_ptr<CallableNodeSignature> signature;
Statement* body;
};
diff --git a/deps/v8/src/torque/class-debug-reader-generator.cc b/deps/v8/src/torque/class-debug-reader-generator.cc
new file mode 100644
index 0000000000..6abdffcc91
--- /dev/null
+++ b/deps/v8/src/torque/class-debug-reader-generator.cc
@@ -0,0 +1,222 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/flags/flags.h"
+#include "src/torque/implementation-visitor.h"
+#include "src/torque/type-oracle.h"
+
+namespace v8 {
+namespace internal {
+namespace torque {
+
+namespace {
+void GenerateClassDebugReader(const ClassType& type, std::ostream& h_contents,
+ std::ostream& cc_contents, std::ostream& visitor,
+ std::unordered_set<const ClassType*>* done) {
+ // Make sure each class only gets generated once.
+ if (!type.IsExtern() || !done->insert(&type).second) return;
+ const ClassType* super_type = type.GetSuperClass();
+
+ // We must emit the classes in dependency order. If the super class hasn't
+ // been emitted yet, go handle it first.
+ if (super_type != nullptr) {
+ GenerateClassDebugReader(*super_type, h_contents, cc_contents, visitor,
+ done);
+ }
+
+ const std::string name = type.name();
+ const std::string super_name =
+ super_type == nullptr ? "Object" : super_type->name();
+ h_contents << "\nclass Tq" << name << " : public Tq" << super_name << " {\n";
+ h_contents << " public:\n";
+ h_contents << " inline Tq" << name << "(uintptr_t address) : Tq"
+ << super_name << "(address) {}\n";
+ h_contents << " std::vector<std::unique_ptr<ObjectProperty>> "
+ "GetProperties(d::MemoryAccessor accessor) const override;\n";
+ h_contents << " const char* GetName() const override;\n";
+ h_contents << " void Visit(TqObjectVisitor* visitor) const override;\n";
+
+ cc_contents << "\nconst char* Tq" << name << "::GetName() const {\n";
+ cc_contents << " return \"v8::internal::" << name << "\";\n";
+ cc_contents << "}\n";
+
+ cc_contents << "\nvoid Tq" << name
+ << "::Visit(TqObjectVisitor* visitor) const {\n";
+ cc_contents << " visitor->Visit" << name << "(this);\n";
+ cc_contents << "}\n";
+
+ visitor << " virtual void Visit" << name << "(const Tq" << name
+ << "* object) {\n";
+ visitor << " Visit" << super_name << "(object);\n";
+ visitor << " }\n";
+
+ std::stringstream get_props_impl;
+
+ for (const Field& field : type.fields()) {
+ const Type* field_type = field.name_and_type.type;
+ if (field_type == TypeOracle::GetVoidType()) continue;
+ const std::string& field_name = field.name_and_type.name;
+ bool is_field_tagged = field_type->IsSubtypeOf(TypeOracle::GetTaggedType());
+ base::Optional<const ClassType*> field_class_type =
+ field_type->ClassSupertype();
+ size_t field_size = 0;
+ std::string field_size_string;
+ std::tie(field_size, field_size_string) = field.GetFieldSizeInformation();
+
+ std::string field_value_type;
+ std::string field_value_type_compressed;
+ std::string field_cc_type;
+ std::string field_cc_type_compressed;
+ if (is_field_tagged) {
+ field_value_type = "uintptr_t";
+ field_value_type_compressed = "i::Tagged_t";
+ field_cc_type = "v8::internal::" + (field_class_type.has_value()
+ ? (*field_class_type)->name()
+ : "Object");
+ field_cc_type_compressed =
+ COMPRESS_POINTERS_BOOL ? "v8::internal::TaggedValue" : field_cc_type;
+ } else {
+ const Type* constexpr_version = field_type->ConstexprVersion();
+ if (constexpr_version == nullptr) {
+ Error("Type '", field_type->ToString(),
+ "' requires a constexpr representation");
+ continue;
+ }
+ field_cc_type = constexpr_version->GetGeneratedTypeName();
+ field_cc_type_compressed = field_cc_type;
+ // Note that we need constexpr names to resolve correctly in the global
+ // namespace, because we're passing them as strings to a debugging
+ // extension. We can verify this during build of the debug helper, because
+ // we use this type for a local variable below, and generate this code in
+ // a disjoint namespace. However, we can't emit a useful error at this
+ // point. Instead we'll emit a comment that might be helpful.
+ field_value_type =
+ field_cc_type +
+ " /*Failing? Ensure constexpr type name is fully qualified and "
+ "necessary #includes are in debug-helper-internal.h*/";
+ field_value_type_compressed = field_value_type;
+ }
+
+ const std::string field_getter =
+ "Get" + CamelifyString(field_name) + "Value";
+ const std::string address_getter =
+ "Get" + CamelifyString(field_name) + "Address";
+
+ std::string indexed_field_info;
+ std::string index_param;
+ std::string index_offset;
+ if (field.index) {
+ const Type* index_type = (*field.index)->name_and_type.type;
+ std::string index_type_name;
+ std::string index_value;
+ if (index_type == TypeOracle::GetSmiType()) {
+ index_type_name = "uintptr_t";
+ index_value =
+ "i::PlatformSmiTagging::SmiToInt(indexed_field_count.value)";
+ } else if (!index_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
+ const Type* constexpr_index = index_type->ConstexprVersion();
+ if (constexpr_index == nullptr) {
+ Error("Type '", index_type->ToString(),
+ "' requires a constexpr representation");
+ continue;
+ }
+ index_type_name = constexpr_index->GetGeneratedTypeName();
+ index_value = "indexed_field_count.value";
+ } else {
+ Error("Unsupported index type: ", index_type);
+ continue;
+ }
+ get_props_impl << " Value<" << index_type_name
+ << "> indexed_field_count = Get"
+ << CamelifyString((*field.index)->name_and_type.name)
+ << "Value(accessor);\n";
+ indexed_field_info =
+ ", " + index_value + ", GetArrayKind(indexed_field_count.validity)";
+ index_param = ", size_t offset";
+ index_offset = " + offset * sizeof(value)";
+ }
+ get_props_impl
+ << " result.push_back(v8::base::make_unique<ObjectProperty>(\""
+ << field_name << "\", \"" << field_cc_type_compressed << "\", \""
+ << field_cc_type << "\", " << address_getter << "()"
+ << indexed_field_info << "));\n";
+
+ h_contents << " uintptr_t " << address_getter << "() const;\n";
+ h_contents << " Value<" << field_value_type << "> " << field_getter
+ << "(d::MemoryAccessor accessor " << index_param << ") const;\n";
+ cc_contents << "\nuintptr_t Tq" << name << "::" << address_getter
+ << "() const {\n";
+ cc_contents << " return address_ - i::kHeapObjectTag + " << field.offset
+ << ";\n";
+ cc_contents << "}\n";
+ cc_contents << "\nValue<" << field_value_type << "> Tq" << name
+ << "::" << field_getter << "(d::MemoryAccessor accessor"
+ << index_param << ") const {\n";
+ cc_contents << " " << field_value_type_compressed << " value{};\n";
+ cc_contents << " d::MemoryAccessResult validity = accessor("
+ << address_getter << "()" << index_offset
+ << ", reinterpret_cast<uint8_t*>(&value), sizeof(value));\n";
+ cc_contents << " return {validity, "
+ << (is_field_tagged ? "Decompress(value, address_)" : "value")
+ << "};\n";
+ cc_contents << "}\n";
+ }
+
+ h_contents << "};\n";
+
+ cc_contents << "\nstd::vector<std::unique_ptr<ObjectProperty>> Tq" << name
+ << "::GetProperties(d::MemoryAccessor accessor) const {\n";
+ cc_contents << " std::vector<std::unique_ptr<ObjectProperty>> result = Tq"
+ << super_name << "::GetProperties(accessor);\n";
+ cc_contents << get_props_impl.str();
+ cc_contents << " return result;\n";
+ cc_contents << "}\n";
+}
+} // namespace
+
+void ImplementationVisitor::GenerateClassDebugReaders(
+ const std::string& output_directory) {
+ const std::string file_name = "class-debug-readers-tq";
+ std::stringstream h_contents;
+ std::stringstream cc_contents;
+ h_contents << "// Provides the ability to read object properties in\n";
+ h_contents << "// postmortem or remote scenarios, where the debuggee's\n";
+ h_contents << "// memory is not part of the current process's address\n";
+ h_contents << "// space and must be read using a callback function.\n\n";
+ {
+ IncludeGuardScope include_guard(h_contents, file_name + ".h");
+
+ h_contents << "#include <cstdint>\n";
+ h_contents << "#include <vector>\n";
+ h_contents
+ << "\n#include \"tools/debug_helper/debug-helper-internal.h\"\n\n";
+
+ cc_contents << "#include \"torque-generated/" << file_name << ".h\"\n";
+ cc_contents << "#include \"include/v8-internal.h\"\n\n";
+ cc_contents << "namespace i = v8::internal;\n\n";
+
+ NamespaceScope h_namespaces(h_contents, {"v8_debug_helper_internal"});
+ NamespaceScope cc_namespaces(cc_contents, {"v8_debug_helper_internal"});
+
+ std::stringstream visitor;
+ visitor << "\nclass TqObjectVisitor {\n";
+ visitor << " public:\n";
+ visitor << " virtual void VisitObject(const TqObject* object) {}\n";
+
+ std::unordered_set<const ClassType*> done;
+ for (const TypeAlias* alias : GlobalContext::GetClasses()) {
+ const ClassType* type = ClassType::DynamicCast(alias->type());
+ GenerateClassDebugReader(*type, h_contents, cc_contents, visitor, &done);
+ }
+
+ visitor << "};\n";
+ h_contents << visitor.str();
+ }
+ WriteFile(output_directory + "/" + file_name + ".h", h_contents.str());
+ WriteFile(output_directory + "/" + file_name + ".cc", cc_contents.str());
+}
+
+} // namespace torque
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/torque/constants.h b/deps/v8/src/torque/constants.h
index 4ad3a6ec3c..efbbf9588e 100644
--- a/deps/v8/src/torque/constants.h
+++ b/deps/v8/src/torque/constants.h
@@ -28,6 +28,7 @@ static const char* const JS_FUNCTION_TYPE_STRING = "JSFunction";
static const char* const MAP_TYPE_STRING = "Map";
static const char* const OBJECT_TYPE_STRING = "Object";
static const char* const HEAP_OBJECT_TYPE_STRING = "HeapObject";
+static const char* const JSANY_TYPE_STRING = "JSAny";
static const char* const JSOBJECT_TYPE_STRING = "JSObject";
static const char* const SMI_TYPE_STRING = "Smi";
static const char* const TAGGED_TYPE_STRING = "Tagged";
@@ -49,6 +50,10 @@ static const char* const FLOAT64_TYPE_STRING = "float64";
static const char* const CONST_INT31_TYPE_STRING = "constexpr int31";
static const char* const CONST_INT32_TYPE_STRING = "constexpr int32";
static const char* const CONST_FLOAT64_TYPE_STRING = "constexpr float64";
+static const char* const TORQUE_INTERNAL_NAMESPACE_STRING = "torque_internal";
+static const char* const REFERENCE_TYPE_STRING = "Reference";
+static const char* const SLICE_TYPE_STRING = "Slice";
+static const char* const STRUCT_NAMESPACE_STRING = "_struct";
inline bool IsConstexprName(const std::string& name) {
return name.substr(0, std::strlen(CONSTEXPR_TYPE_PREFIX)) ==
diff --git a/deps/v8/src/torque/contextual.h b/deps/v8/src/torque/contextual.h
index 92d2bdf3d7..d7764bfa68 100644
--- a/deps/v8/src/torque/contextual.h
+++ b/deps/v8/src/torque/contextual.h
@@ -15,7 +15,7 @@ namespace internal {
namespace torque {
template <class Variable>
-V8_EXPORT_PRIVATE typename Variable::VariableType*& ContextualVariableTop();
+V8_EXPORT_PRIVATE typename Variable::Scope*& ContextualVariableTop();
// {ContextualVariable} provides a clean alternative to a global variable.
// The contextual variable is mutable, and supports managing the value of
@@ -30,8 +30,6 @@ V8_EXPORT_PRIVATE typename Variable::VariableType*& ContextualVariableTop();
template <class Derived, class VarType>
class ContextualVariable {
public:
- using VariableType = VarType;
-
// A {Scope} contains a new object of type {VarType} and gives
// ContextualVariable::Get() access to it. Upon destruction, the contextual
// variable is restored to the state before the {Scope} was created. Scopes
@@ -41,18 +39,20 @@ class ContextualVariable {
public:
template <class... Args>
explicit Scope(Args&&... args)
- : current_(std::forward<Args>(args)...), previous_(Top()) {
- Top() = &current_;
+ : value_(std::forward<Args>(args)...), previous_(Top()) {
+ Top() = this;
}
~Scope() {
// Ensure stack discipline.
- DCHECK_EQ(&current_, Top());
+ DCHECK_EQ(this, Top());
Top() = previous_;
}
+ VarType& Value() { return value_; }
+
private:
- VarType current_;
- VarType* previous_;
+ VarType value_;
+ Scope* previous_;
static_assert(std::is_base_of<ContextualVariable, Derived>::value,
"Curiously Recurring Template Pattern");
@@ -65,13 +65,13 @@ class ContextualVariable {
// for this contextual variable.
static VarType& Get() {
DCHECK_NOT_NULL(Top());
- return *Top();
+ return Top()->Value();
}
private:
template <class T>
- friend typename T::VariableType*& ContextualVariableTop();
- static VarType*& Top() { return ContextualVariableTop<Derived>(); }
+ friend typename T::Scope*& ContextualVariableTop();
+ static Scope*& Top() { return ContextualVariableTop<Derived>(); }
static bool HasScope() { return Top() != nullptr; }
friend class MessageBuilder;
@@ -82,11 +82,11 @@ class ContextualVariable {
struct VarName \
: v8::internal::torque::ContextualVariable<VarName, __VA_ARGS__> {}
-#define DEFINE_CONTEXTUAL_VARIABLE(VarName) \
- template <> \
- V8_EXPORT_PRIVATE VarName::VariableType*& ContextualVariableTop<VarName>() { \
- static thread_local VarName::VariableType* top = nullptr; \
- return top; \
+#define DEFINE_CONTEXTUAL_VARIABLE(VarName) \
+ template <> \
+ V8_EXPORT_PRIVATE VarName::Scope*& ContextualVariableTop<VarName>() { \
+ static thread_local VarName::Scope* top = nullptr; \
+ return top; \
}
// By inheriting from {ContextualClass} a class can become a contextual variable
diff --git a/deps/v8/src/torque/csa-generator.cc b/deps/v8/src/torque/csa-generator.cc
index cd7ff22c48..0c49033955 100644
--- a/deps/v8/src/torque/csa-generator.cc
+++ b/deps/v8/src/torque/csa-generator.cc
@@ -56,14 +56,10 @@ Stack<std::string> CSAGenerator::EmitBlock(const Block* block) {
}
void CSAGenerator::EmitSourcePosition(SourcePosition pos, bool always_emit) {
- std::string file = SourceFileMap::AbsolutePath(pos.source);
+ const std::string& file = SourceFileMap::AbsolutePath(pos.source);
if (always_emit || !previous_position_.CompareStartIgnoreColumn(pos)) {
// Lines in Torque SourcePositions are zero-based, while the
// CodeStubAssembler and downwind systems are one-based.
- for (auto& c : file) {
- if (c == '\\')
- c = '/';
- }
out_ << " ca_.SetSourcePosition(\"" << file << "\", "
<< (pos.start.line + 1) << ");\n";
previous_position_ = pos;
@@ -309,8 +305,7 @@ void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction,
std::string catch_name =
PreCallableExceptionPreparation(instruction.catch_block);
out_ << " ";
- bool needs_flattening =
- return_type->IsStructType() || return_type->IsReferenceType();
+ bool needs_flattening = return_type->IsStructType();
if (needs_flattening) {
out_ << "std::tie(";
PrintCommaSeparatedList(out_, results);
@@ -713,8 +708,13 @@ void CSAGenerator::EmitInstruction(const UnsafeCastInstruction& instruction,
void CSAGenerator::EmitInstruction(
const CreateFieldReferenceInstruction& instruction,
Stack<std::string>* stack) {
- const Field& field =
- instruction.class_type->LookupField(instruction.field_name);
+ base::Optional<const ClassType*> class_type =
+ instruction.type->ClassSupertype();
+ if (!class_type.has_value()) {
+ ReportError("Cannot create field reference of type ", instruction.type,
+ " which does not inherit from a class type");
+ }
+ const Field& field = class_type.value()->LookupField(instruction.field_name);
std::string offset_name = FreshNodeName();
stack->Push(offset_name);
@@ -770,11 +770,6 @@ void CSAGenerator::EmitCSAValue(VisitResult result,
out);
}
out << "}";
- } else if (result.type()->IsReferenceType()) {
- DCHECK_EQ(2, result.stack_range().Size());
- size_t offset = result.stack_range().begin().offset;
- out << "CodeStubAssembler::Reference{" << values.Peek(BottomOffset{offset})
- << ", " << values.Peek(BottomOffset{offset + 1}) << "}";
} else {
DCHECK_EQ(1, result.stack_range().Size());
out << "compiler::TNode<" << result.type()->GetGeneratedTNodeTypeName()
diff --git a/deps/v8/src/torque/declarable.cc b/deps/v8/src/torque/declarable.cc
index 1fd07d5b0d..5bcaff016d 100644
--- a/deps/v8/src/torque/declarable.cc
+++ b/deps/v8/src/torque/declarable.cc
@@ -7,6 +7,7 @@
#include "src/torque/declarable.h"
#include "src/torque/global-context.h"
+#include "src/torque/type-inference.h"
#include "src/torque/type-visitor.h"
namespace v8 {
@@ -58,67 +59,38 @@ std::ostream& operator<<(std::ostream& os, const RuntimeFunction& b) {
std::ostream& operator<<(std::ostream& os, const Generic& g) {
os << "generic " << g.name() << "<";
PrintCommaSeparatedList(
- os, g.declaration()->generic_parameters,
+ os, g.generic_parameters(),
[](const Identifier* identifier) { return identifier->value; });
os << ">";
return os;
}
-namespace {
-base::Optional<const Type*> InferTypeArgument(const std::string& to_infer,
- TypeExpression* parameter,
- const Type* argument) {
- BasicTypeExpression* basic = BasicTypeExpression::DynamicCast(parameter);
- if (basic && basic->namespace_qualification.empty() && !basic->is_constexpr &&
- basic->name == to_infer) {
- return argument;
- }
- auto* ref = ReferenceTypeExpression::DynamicCast(parameter);
- if (ref && argument->IsReferenceType()) {
- return InferTypeArgument(to_infer, ref->referenced_type,
- ReferenceType::cast(argument)->referenced_type());
- }
- return base::nullopt;
-}
-
-base::Optional<const Type*> InferTypeArgument(
- const std::string& to_infer, const std::vector<TypeExpression*>& parameters,
+TypeArgumentInference Generic::InferSpecializationTypes(
+ const TypeVector& explicit_specialization_types,
const TypeVector& arguments) {
- for (size_t i = 0; i < arguments.size() && i < parameters.size(); ++i) {
- if (base::Optional<const Type*> inferred =
- InferTypeArgument(to_infer, parameters[i], arguments[i])) {
- return *inferred;
- }
- }
- return base::nullopt;
+ size_t implicit_count = declaration()->parameters.implicit_count;
+ const std::vector<TypeExpression*>& parameters =
+ declaration()->parameters.types;
+ std::vector<TypeExpression*> explicit_parameters(
+ parameters.begin() + implicit_count, parameters.end());
+
+ CurrentScope::Scope generic_scope(ParentScope());
+ TypeArgumentInference inference(generic_parameters(),
+ explicit_specialization_types,
+ explicit_parameters, arguments);
+ return inference;
}
-} // namespace
-
-base::Optional<TypeVector> Generic::InferSpecializationTypes(
- const TypeVector& explicit_specialization_types,
- const TypeVector& arguments) {
- TypeVector result = explicit_specialization_types;
- size_t type_parameter_count = declaration()->generic_parameters.size();
- if (explicit_specialization_types.size() > type_parameter_count) {
+base::Optional<Statement*> Generic::CallableBody() {
+ if (auto* decl = TorqueMacroDeclaration::DynamicCast(declaration())) {
+ return decl->body;
+ } else if (auto* decl =
+ TorqueBuiltinDeclaration::DynamicCast(declaration())) {
+ return decl->body;
+ } else {
return base::nullopt;
}
- for (size_t i = explicit_specialization_types.size();
- i < type_parameter_count; ++i) {
- const std::string type_name = declaration()->generic_parameters[i]->value;
- size_t implicit_count =
- declaration()->callable->signature->parameters.implicit_count;
- const std::vector<TypeExpression*>& parameters =
- declaration()->callable->signature->parameters.types;
- std::vector<TypeExpression*> explicit_parameters(
- parameters.begin() + implicit_count, parameters.end());
- base::Optional<const Type*> inferred =
- InferTypeArgument(type_name, explicit_parameters, arguments);
- if (!inferred) return base::nullopt;
- result.push_back(*inferred);
- }
- return result;
}
bool Namespace::IsDefaultNamespace() const {
diff --git a/deps/v8/src/torque/declarable.h b/deps/v8/src/torque/declarable.h
index cf6fd2554b..502180953d 100644
--- a/deps/v8/src/torque/declarable.h
+++ b/deps/v8/src/torque/declarable.h
@@ -21,6 +21,7 @@ namespace torque {
class Scope;
class Namespace;
+class TypeArgumentInference;
DECLARE_CONTEXTUAL_VARIABLE(CurrentScope, Scope*);
@@ -261,6 +262,7 @@ class Callable : public Scope {
const std::string& ExternalName() const { return external_name_; }
const std::string& ReadableName() const { return readable_name_; }
const Signature& signature() const { return signature_; }
+ bool IsTransitioning() const { return signature().transitioning; }
const NameVector& parameter_names() const {
return signature_.parameter_names;
}
@@ -269,7 +271,6 @@ class Callable : public Scope {
}
void IncrementReturns() { ++returns_; }
bool HasReturns() const { return returns_; }
- bool IsTransitioning() const { return transitioning_; }
base::Optional<Statement*> body() const { return body_; }
bool IsExternal() const { return !body_.has_value(); }
virtual bool ShouldBeInlined() const { return false; }
@@ -277,14 +278,13 @@ class Callable : public Scope {
protected:
Callable(Declarable::Kind kind, std::string external_name,
- std::string readable_name, Signature signature, bool transitioning,
+ std::string readable_name, Signature signature,
base::Optional<Statement*> body)
: Scope(kind),
external_name_(std::move(external_name)),
readable_name_(std::move(readable_name)),
signature_(std::move(signature)),
- transitioning_(transitioning),
returns_(0),
body_(body) {
DCHECK(!body || *body);
@@ -294,7 +294,6 @@ class Callable : public Scope {
std::string external_name_;
std::string readable_name_;
Signature signature_;
- bool transitioning_;
size_t returns_;
base::Optional<Statement*> body_;
};
@@ -320,9 +319,9 @@ class Macro : public Callable {
protected:
Macro(Declarable::Kind kind, std::string external_name,
std::string readable_name, const Signature& signature,
- bool transitioning, base::Optional<Statement*> body)
+ base::Optional<Statement*> body)
: Callable(kind, std::move(external_name), std::move(readable_name),
- signature, transitioning, body),
+ signature, body),
used_(false) {
if (signature.parameter_types.var_args) {
ReportError("Varargs are not supported for macros.");
@@ -344,9 +343,9 @@ class ExternMacro : public Macro {
private:
friend class Declarations;
ExternMacro(const std::string& name, std::string external_assembler_name,
- Signature signature, bool transitioning)
+ Signature signature)
: Macro(Declarable::kExternMacro, name, name, std::move(signature),
- transitioning, base::nullopt),
+ base::nullopt),
external_assembler_name_(std::move(external_assembler_name)) {}
std::string external_assembler_name_;
@@ -360,10 +359,10 @@ class TorqueMacro : public Macro {
protected:
TorqueMacro(Declarable::Kind kind, std::string external_name,
std::string readable_name, const Signature& signature,
- bool transitioning, base::Optional<Statement*> body,
- bool is_user_defined, bool exported_to_csa)
+ base::Optional<Statement*> body, bool is_user_defined,
+ bool exported_to_csa)
: Macro(kind, std::move(external_name), std::move(readable_name),
- signature, transitioning, body),
+ signature, body),
exported_to_csa_(exported_to_csa) {
SetIsUserDefined(is_user_defined);
}
@@ -371,12 +370,11 @@ class TorqueMacro : public Macro {
private:
friend class Declarations;
TorqueMacro(std::string external_name, std::string readable_name,
- const Signature& signature, bool transitioning,
- base::Optional<Statement*> body, bool is_user_defined,
- bool exported_to_csa)
+ const Signature& signature, base::Optional<Statement*> body,
+ bool is_user_defined, bool exported_to_csa)
: TorqueMacro(Declarable::kTorqueMacro, std::move(external_name),
- std::move(readable_name), signature, transitioning, body,
- is_user_defined, exported_to_csa) {}
+ std::move(readable_name), signature, body, is_user_defined,
+ exported_to_csa) {}
bool exported_to_csa_ = false;
};
@@ -395,11 +393,9 @@ class Method : public TorqueMacro {
private:
friend class Declarations;
Method(AggregateType* aggregate_type, std::string external_name,
- std::string readable_name, const Signature& signature,
- bool transitioning, Statement* body)
+ std::string readable_name, const Signature& signature, Statement* body)
: TorqueMacro(Declarable::kMethod, std::move(external_name),
- std::move(readable_name), signature, transitioning, body,
- true, false),
+ std::move(readable_name), signature, body, true, false),
aggregate_type_(aggregate_type) {}
AggregateType* aggregate_type_;
};
@@ -416,10 +412,10 @@ class Builtin : public Callable {
private:
friend class Declarations;
Builtin(std::string external_name, std::string readable_name,
- Builtin::Kind kind, const Signature& signature, bool transitioning,
+ Builtin::Kind kind, const Signature& signature,
base::Optional<Statement*> body)
: Callable(Declarable::kBuiltin, std::move(external_name),
- std::move(readable_name), signature, transitioning, body),
+ std::move(readable_name), signature, body),
kind_(kind) {}
Kind kind_;
@@ -431,10 +427,9 @@ class RuntimeFunction : public Callable {
private:
friend class Declarations;
- RuntimeFunction(const std::string& name, const Signature& signature,
- bool transitioning)
+ RuntimeFunction(const std::string& name, const Signature& signature)
: Callable(Declarable::kRuntimeFunction, name, name, signature,
- transitioning, base::nullopt) {}
+ base::nullopt) {}
};
class Intrinsic : public Callable {
@@ -444,8 +439,7 @@ class Intrinsic : public Callable {
private:
friend class Declarations;
Intrinsic(std::string name, const Signature& signature)
- : Callable(Declarable::kIntrinsic, name, name, signature, false,
- base::nullopt) {
+ : Callable(Declarable::kIntrinsic, name, name, signature, base::nullopt) {
if (signature.parameter_types.var_args) {
ReportError("Varargs are not supported for intrinsics.");
}
@@ -483,33 +477,32 @@ class Generic : public Declarable {
DECLARE_DECLARABLE_BOILERPLATE(Generic, generic)
const std::string& name() const { return name_; }
- GenericDeclaration* declaration() const { return declaration_; }
+ CallableDeclaration* declaration() const {
+ return generic_declaration_->declaration;
+ }
const std::vector<Identifier*> generic_parameters() const {
- return declaration()->generic_parameters;
+ return generic_declaration_->generic_parameters;
}
SpecializationMap<Callable>& specializations() { return specializations_; }
- base::Optional<TypeVector> InferSpecializationTypes(
+ base::Optional<Statement*> CallableBody();
+
+ TypeArgumentInference InferSpecializationTypes(
const TypeVector& explicit_specialization_types,
const TypeVector& arguments);
private:
friend class Declarations;
- Generic(const std::string& name, GenericDeclaration* declaration)
+ Generic(const std::string& name, GenericDeclaration* generic_declaration)
: Declarable(Declarable::kGeneric),
name_(name),
- declaration_(declaration) {}
+ generic_declaration_(generic_declaration) {}
std::string name_;
- GenericDeclaration* declaration_;
+ GenericDeclaration* generic_declaration_;
SpecializationMap<Callable> specializations_;
};
-struct SpecializationKey {
- Generic* generic;
- TypeVector specialized_types;
-};
-
class GenericStructType : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(GenericStructType, generic_type)
diff --git a/deps/v8/src/torque/declaration-visitor.cc b/deps/v8/src/torque/declaration-visitor.cc
index e0e996f33b..f762337463 100644
--- a/deps/v8/src/torque/declaration-visitor.cc
+++ b/deps/v8/src/torque/declaration-visitor.cc
@@ -53,26 +53,13 @@ void DeclarationVisitor::Visit(Declaration* decl) {
}
}
-void DeclarationVisitor::Visit(CallableNode* decl, const Signature& signature,
- base::Optional<Statement*> body) {
- switch (decl->kind) {
-#define ENUM_ITEM(name) \
- case AstNode::Kind::k##name: \
- return Visit(name::cast(decl), signature, body);
- AST_CALLABLE_NODE_KIND_LIST(ENUM_ITEM)
-#undef ENUM_ITEM
- default:
- UNIMPLEMENTED();
- }
-}
-
Builtin* DeclarationVisitor::CreateBuiltin(BuiltinDeclaration* decl,
std::string external_name,
std::string readable_name,
Signature signature,
base::Optional<Statement*> body) {
const bool javascript = decl->javascript_linkage;
- const bool varargs = decl->signature->parameters.has_varargs;
+ const bool varargs = decl->parameters.has_varargs;
Builtin::Kind kind = !javascript ? Builtin::kStub
: varargs ? Builtin::kVarArgsJavaScript
: Builtin::kFixedArgsJavaScript;
@@ -82,6 +69,21 @@ Builtin* DeclarationVisitor::CreateBuiltin(BuiltinDeclaration* decl,
" to be a JavaScript builtin");
}
+ if (javascript) {
+ if (!signature.return_type->IsSubtypeOf(TypeOracle::GetJSAnyType())) {
+ Error("Return type of JavaScript-linkage builtins has to be JSAny.")
+ .Position(decl->return_type->pos);
+ }
+ for (size_t i = signature.implicit_count;
+ i < signature.parameter_types.types.size(); ++i) {
+ const Type* parameter_type = signature.parameter_types.types[i];
+ if (parameter_type != TypeOracle::GetJSAnyType()) {
+ Error("Parameters of JavaScript-linkage builtins have to be JSAny.")
+ .Position(decl->parameters.types[i]->pos);
+ }
+ }
+ }
+
for (size_t i = 0; i < signature.types().size(); ++i) {
if (const StructType* type =
StructType::DynamicCast(signature.types()[i])) {
@@ -111,14 +113,20 @@ Builtin* DeclarationVisitor::CreateBuiltin(BuiltinDeclaration* decl,
struct_type->name());
}
- return Declarations::CreateBuiltin(
- std::move(external_name), std::move(readable_name), kind,
- std::move(signature), decl->transitioning, body);
+ return Declarations::CreateBuiltin(std::move(external_name),
+ std::move(readable_name), kind,
+ std::move(signature), body);
+}
+
+void DeclarationVisitor::Visit(ExternalBuiltinDeclaration* decl) {
+ Declarations::Declare(
+ decl->name->value,
+ CreateBuiltin(decl, decl->name->value, decl->name->value,
+ TypeVisitor::MakeSignature(decl), base::nullopt));
}
-void DeclarationVisitor::Visit(ExternalRuntimeDeclaration* decl,
- const Signature& signature,
- base::Optional<Statement*> body) {
+void DeclarationVisitor::Visit(ExternalRuntimeDeclaration* decl) {
+ Signature signature = TypeVisitor::MakeSignature(decl);
if (signature.parameter_types.types.size() == 0 ||
!(signature.parameter_types.types[0] == TypeOracle::GetContextType())) {
ReportError(
@@ -142,39 +150,34 @@ void DeclarationVisitor::Visit(ExternalRuntimeDeclaration* decl,
}
}
- Declarations::DeclareRuntimeFunction(decl->name, signature,
- decl->transitioning);
+ Declarations::DeclareRuntimeFunction(decl->name->value, signature);
}
-void DeclarationVisitor::Visit(ExternalMacroDeclaration* decl,
- const Signature& signature,
- base::Optional<Statement*> body) {
- Declarations::DeclareMacro(decl->name, true, decl->external_assembler_name,
- signature, decl->transitioning, body, decl->op);
+void DeclarationVisitor::Visit(ExternalMacroDeclaration* decl) {
+ Declarations::DeclareMacro(
+ decl->name->value, true, decl->external_assembler_name,
+ TypeVisitor::MakeSignature(decl), base::nullopt, decl->op);
}
-void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl,
- const Signature& signature,
- base::Optional<Statement*> body) {
+void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl) {
Declarations::Declare(
- decl->name, CreateBuiltin(decl, decl->name, decl->name, signature, body));
+ decl->name->value,
+ CreateBuiltin(decl, decl->name->value, decl->name->value,
+ TypeVisitor::MakeSignature(decl), decl->body));
}
-void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl,
- const Signature& signature,
- base::Optional<Statement*> body) {
+void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl) {
Macro* macro = Declarations::DeclareMacro(
- decl->name, decl->export_to_csa, base::nullopt, signature,
- decl->transitioning, body, decl->op);
+ decl->name->value, decl->export_to_csa, base::nullopt,
+ TypeVisitor::MakeSignature(decl), decl->body, decl->op);
// TODO(szuend): Set identifier_position to decl->name->pos once all callable
// names are changed from std::string to Identifier*.
macro->SetPosition(decl->pos);
}
-void DeclarationVisitor::Visit(IntrinsicDeclaration* decl,
- const Signature& signature,
- base::Optional<Statement*> body) {
- Declarations::DeclareIntrinsic(decl->name, signature);
+void DeclarationVisitor::Visit(IntrinsicDeclaration* decl) {
+ Declarations::DeclareIntrinsic(decl->name->value,
+ TypeVisitor::MakeSignature(decl));
}
void DeclarationVisitor::Visit(ConstDeclaration* decl) {
@@ -182,30 +185,16 @@ void DeclarationVisitor::Visit(ConstDeclaration* decl) {
decl->name, TypeVisitor::ComputeType(decl->type), decl->expression);
}
-void DeclarationVisitor::Visit(StandardDeclaration* decl) {
- Signature signature =
- TypeVisitor::MakeSignature(decl->callable->signature.get());
- Visit(decl->callable, signature, decl->body);
-}
-
void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
- if ((decl->body != nullptr) == decl->external) {
- std::stringstream stream;
- stream << "specialization of " << decl->name
- << " must either be marked 'extern' or have a body";
- ReportError(stream.str());
- }
-
std::vector<Generic*> generic_list =
Declarations::LookupGeneric(decl->name->value);
// Find the matching generic specialization based on the concrete parameter
// list.
Generic* matching_generic = nullptr;
- Signature signature_with_types =
- TypeVisitor::MakeSignature(decl->signature.get());
+ Signature signature_with_types = TypeVisitor::MakeSignature(decl);
for (Generic* generic : generic_list) {
Signature generic_signature_with_types =
- MakeSpecializedSignature(SpecializationKey{
+ MakeSpecializedSignature(SpecializationKey<Generic>{
generic, TypeVisitor::ComputeTypeVector(decl->generic_parameters)});
if (signature_with_types.HasSameTypesAs(generic_signature_with_types,
ParameterMode::kIgnoreImplicit)) {
@@ -233,7 +222,7 @@ void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
stream << "\ncandidates are:";
for (Generic* generic : generic_list) {
stream << "\n "
- << MakeSpecializedSignature(SpecializationKey{
+ << MakeSpecializedSignature(SpecializationKey<Generic>{
generic,
TypeVisitor::ComputeTypeVector(decl->generic_parameters)});
}
@@ -245,10 +234,12 @@ void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
matching_generic->IdentifierPosition());
}
- Specialize(SpecializationKey{matching_generic, TypeVisitor::ComputeTypeVector(
- decl->generic_parameters)},
- matching_generic->declaration()->callable, decl->signature.get(),
- decl->body, decl->pos);
+ CallableDeclaration* generic_declaration = matching_generic->declaration();
+
+ Specialize(SpecializationKey<Generic>{matching_generic,
+ TypeVisitor::ComputeTypeVector(
+ decl->generic_parameters)},
+ generic_declaration, decl, decl->body, decl->pos);
}
void DeclarationVisitor::Visit(ExternConstDeclaration* decl) {
@@ -267,10 +258,11 @@ void DeclarationVisitor::Visit(CppIncludeDeclaration* decl) {
GlobalContext::AddCppInclude(decl->include_path);
}
-void DeclarationVisitor::DeclareSpecializedTypes(const SpecializationKey& key) {
+void DeclarationVisitor::DeclareSpecializedTypes(
+ const SpecializationKey<Generic>& key) {
size_t i = 0;
const std::size_t generic_parameter_count =
- key.generic->declaration()->generic_parameters.size();
+ key.generic->generic_parameters().size();
if (generic_parameter_count != key.specialized_types.size()) {
std::stringstream stream;
stream << "Wrong generic argument count for specialization of \""
@@ -280,37 +272,35 @@ void DeclarationVisitor::DeclareSpecializedTypes(const SpecializationKey& key) {
}
for (auto type : key.specialized_types) {
- Identifier* generic_type_name =
- key.generic->declaration()->generic_parameters[i++];
+ Identifier* generic_type_name = key.generic->generic_parameters()[i++];
TypeAlias* alias = Declarations::DeclareType(generic_type_name, type);
alias->SetIsUserDefined(false);
}
}
Signature DeclarationVisitor::MakeSpecializedSignature(
- const SpecializationKey& key) {
+ const SpecializationKey<Generic>& key) {
CurrentScope::Scope generic_scope(key.generic->ParentScope());
// Create a temporary fake-namespace just to temporarily declare the
// specialization aliases for the generic types to create a signature.
Namespace tmp_namespace("_tmp");
CurrentScope::Scope tmp_namespace_scope(&tmp_namespace);
DeclareSpecializedTypes(key);
- return TypeVisitor::MakeSignature(
- key.generic->declaration()->callable->signature.get());
+ return TypeVisitor::MakeSignature(key.generic->declaration());
}
-Callable* DeclarationVisitor::SpecializeImplicit(const SpecializationKey& key) {
- if (!key.generic->declaration()->body &&
- IntrinsicDeclaration::DynamicCast(key.generic->declaration()->callable) ==
- nullptr) {
+Callable* DeclarationVisitor::SpecializeImplicit(
+ const SpecializationKey<Generic>& key) {
+ base::Optional<Statement*> body = key.generic->CallableBody();
+ if (!body && IntrinsicDeclaration::DynamicCast(key.generic->declaration()) ==
+ nullptr) {
ReportError("missing specialization of ", key.generic->name(),
" with types <", key.specialized_types, "> declared at ",
key.generic->Position());
}
CurrentScope::Scope generic_scope(key.generic->ParentScope());
- Callable* result = Specialize(key, key.generic->declaration()->callable,
- base::nullopt, key.generic->declaration()->body,
- CurrentSourcePosition::Get());
+ Callable* result = Specialize(key, key.generic->declaration(), base::nullopt,
+ body, CurrentSourcePosition::Get());
result->SetIsUserDefined(false);
CurrentScope::Scope callable_scope(result);
DeclareSpecializedTypes(key);
@@ -318,12 +308,11 @@ Callable* DeclarationVisitor::SpecializeImplicit(const SpecializationKey& key) {
}
Callable* DeclarationVisitor::Specialize(
- const SpecializationKey& key, CallableNode* declaration,
- base::Optional<const CallableNodeSignature*> signature,
+ const SpecializationKey<Generic>& key, CallableDeclaration* declaration,
+ base::Optional<const SpecializationDeclaration*> explicit_specialization,
base::Optional<Statement*> body, SourcePosition position) {
CurrentSourcePosition::Scope pos_scope(position);
- size_t generic_parameter_count =
- key.generic->declaration()->generic_parameters.size();
+ size_t generic_parameter_count = key.generic->generic_parameters().size();
if (generic_parameter_count != key.specialized_types.size()) {
std::stringstream stream;
stream << "number of template parameters ("
@@ -338,13 +327,15 @@ Callable* DeclarationVisitor::Specialize(
" with types <", key.specialized_types, ">");
}
- Signature type_signature = signature ? TypeVisitor::MakeSignature(*signature)
- : MakeSpecializedSignature(key);
+ Signature type_signature =
+ explicit_specialization
+ ? TypeVisitor::MakeSignature(*explicit_specialization)
+ : MakeSpecializedSignature(key);
std::string generated_name = Declarations::GetGeneratedCallableName(
- declaration->name, key.specialized_types);
+ declaration->name->value, key.specialized_types);
std::stringstream readable_name;
- readable_name << declaration->name << "<";
+ readable_name << declaration->name->value << "<";
bool first = true;
for (const Type* t : key.specialized_types) {
if (!first) readable_name << ", ";
@@ -354,11 +345,12 @@ Callable* DeclarationVisitor::Specialize(
readable_name << ">";
Callable* callable;
if (MacroDeclaration::DynamicCast(declaration) != nullptr) {
- callable = Declarations::CreateTorqueMacro(
- generated_name, readable_name.str(), false, type_signature,
- declaration->transitioning, *body, true);
+ callable =
+ Declarations::CreateTorqueMacro(generated_name, readable_name.str(),
+ false, type_signature, *body, true);
} else if (IntrinsicDeclaration::DynamicCast(declaration) != nullptr) {
- callable = Declarations::CreateIntrinsic(declaration->name, type_signature);
+ callable =
+ Declarations::CreateIntrinsic(declaration->name->value, type_signature);
} else {
BuiltinDeclaration* builtin = BuiltinDeclaration::cast(declaration);
callable = CreateBuiltin(builtin, generated_name, readable_name.str(),
diff --git a/deps/v8/src/torque/declaration-visitor.h b/deps/v8/src/torque/declaration-visitor.h
index dbd28f4b87..3a5201e24a 100644
--- a/deps/v8/src/torque/declaration-visitor.h
+++ b/deps/v8/src/torque/declaration-visitor.h
@@ -45,7 +45,7 @@ class PredeclarationVisitor {
}
}
static void Predeclare(GenericDeclaration* decl) {
- Declarations::DeclareGeneric(decl->callable->name, decl);
+ Declarations::DeclareGeneric(decl->declaration->name->value, decl);
}
};
@@ -76,30 +76,15 @@ class DeclarationVisitor {
std::string external_name,
std::string readable_name, Signature signature,
base::Optional<Statement*> body);
- static void Visit(ExternalBuiltinDeclaration* decl,
- const Signature& signature,
- base::Optional<Statement*> body) {
- Declarations::Declare(
- decl->name,
- CreateBuiltin(decl, decl->name, decl->name, signature, base::nullopt));
- }
-
- static void Visit(ExternalRuntimeDeclaration* decl, const Signature& sig,
- base::Optional<Statement*> body);
- static void Visit(ExternalMacroDeclaration* decl, const Signature& sig,
- base::Optional<Statement*> body);
- static void Visit(TorqueBuiltinDeclaration* decl, const Signature& signature,
- base::Optional<Statement*> body);
- static void Visit(TorqueMacroDeclaration* decl, const Signature& signature,
- base::Optional<Statement*> body);
- static void Visit(IntrinsicDeclaration* decl, const Signature& signature,
- base::Optional<Statement*> body);
- static void Visit(CallableNode* decl, const Signature& signature,
- base::Optional<Statement*> body);
+ static void Visit(ExternalBuiltinDeclaration* decl);
+ static void Visit(ExternalRuntimeDeclaration* decl);
+ static void Visit(ExternalMacroDeclaration* decl);
+ static void Visit(TorqueBuiltinDeclaration* decl);
+ static void Visit(TorqueMacroDeclaration* decl);
+ static void Visit(IntrinsicDeclaration* decl);
static void Visit(ConstDeclaration* decl);
- static void Visit(StandardDeclaration* decl);
static void Visit(GenericDeclaration* decl) {
// The PredeclarationVisitor already handled this case.
}
@@ -107,15 +92,16 @@ class DeclarationVisitor {
static void Visit(ExternConstDeclaration* decl);
static void Visit(CppIncludeDeclaration* decl);
- static Signature MakeSpecializedSignature(const SpecializationKey& key);
- static Callable* SpecializeImplicit(const SpecializationKey& key);
+ static Signature MakeSpecializedSignature(
+ const SpecializationKey<Generic>& key);
+ static Callable* SpecializeImplicit(const SpecializationKey<Generic>& key);
static Callable* Specialize(
- const SpecializationKey& key, CallableNode* declaration,
- base::Optional<const CallableNodeSignature*> signature,
+ const SpecializationKey<Generic>& key, CallableDeclaration* declaration,
+ base::Optional<const SpecializationDeclaration*> explicit_specialization,
base::Optional<Statement*> body, SourcePosition position);
private:
- static void DeclareSpecializedTypes(const SpecializationKey& key);
+ static void DeclareSpecializedTypes(const SpecializationKey<Generic>& key);
};
} // namespace torque
diff --git a/deps/v8/src/torque/declarations.cc b/deps/v8/src/torque/declarations.cc
index 73d46d6998..ed4ad23044 100644
--- a/deps/v8/src/torque/declarations.cc
+++ b/deps/v8/src/torque/declarations.cc
@@ -11,9 +11,6 @@
namespace v8 {
namespace internal {
namespace torque {
-
-DEFINE_CONTEXTUAL_VARIABLE(GlobalContext)
-
namespace {
template <class T>
@@ -139,6 +136,13 @@ GenericStructType* Declarations::LookupUniqueGenericStructType(
"generic struct");
}
+base::Optional<GenericStructType*> Declarations::TryLookupGenericStructType(
+ const QualifiedName& name) {
+ std::vector<GenericStructType*> results = TryLookup<GenericStructType>(name);
+ if (results.empty()) return base::nullopt;
+ return EnsureUnique(results, name.name, "generic struct");
+}
+
Namespace* Declarations::DeclareNamespace(const std::string& name) {
return Declare(name, std::unique_ptr<Namespace>(new Namespace(name)));
}
@@ -158,43 +162,44 @@ const TypeAlias* Declarations::PredeclareTypeAlias(const Identifier* name,
return Declare(name->value, std::move(alias_ptr));
}
-TorqueMacro* Declarations::CreateTorqueMacro(
- std::string external_name, std::string readable_name, bool exported_to_csa,
- Signature signature, bool transitioning, base::Optional<Statement*> body,
- bool is_user_defined) {
+TorqueMacro* Declarations::CreateTorqueMacro(std::string external_name,
+ std::string readable_name,
+ bool exported_to_csa,
+ Signature signature,
+ base::Optional<Statement*> body,
+ bool is_user_defined) {
// TODO(tebbi): Switch to more predictable names to improve incremental
// compilation.
external_name += "_" + std::to_string(GlobalContext::FreshId());
return RegisterDeclarable(std::unique_ptr<TorqueMacro>(new TorqueMacro(
std::move(external_name), std::move(readable_name), std::move(signature),
- transitioning, body, is_user_defined, exported_to_csa)));
+ body, is_user_defined, exported_to_csa)));
}
ExternMacro* Declarations::CreateExternMacro(
- std::string name, std::string external_assembler_name, Signature signature,
- bool transitioning) {
+ std::string name, std::string external_assembler_name,
+ Signature signature) {
return RegisterDeclarable(std::unique_ptr<ExternMacro>(
new ExternMacro(std::move(name), std::move(external_assembler_name),
- std::move(signature), transitioning)));
+ std::move(signature))));
}
Macro* Declarations::DeclareMacro(
const std::string& name, bool accessible_from_csa,
base::Optional<std::string> external_assembler_name,
- const Signature& signature, bool transitioning,
- base::Optional<Statement*> body, base::Optional<std::string> op,
- bool is_user_defined) {
+ const Signature& signature, base::Optional<Statement*> body,
+ base::Optional<std::string> op, bool is_user_defined) {
if (TryLookupMacro(name, signature.GetExplicitTypes())) {
ReportError("cannot redeclare macro ", name,
" with identical explicit parameters");
}
Macro* macro;
if (external_assembler_name) {
- macro = CreateExternMacro(name, std::move(*external_assembler_name),
- signature, transitioning);
+ macro =
+ CreateExternMacro(name, std::move(*external_assembler_name), signature);
} else {
- macro = CreateTorqueMacro(name, name, accessible_from_csa, signature,
- transitioning, body, is_user_defined);
+ macro = CreateTorqueMacro(name, name, accessible_from_csa, signature, body,
+ is_user_defined);
}
Declare(name, macro);
if (op) {
@@ -209,11 +214,11 @@ Macro* Declarations::DeclareMacro(
Method* Declarations::CreateMethod(AggregateType* container_type,
const std::string& name, Signature signature,
- bool transitioning, Statement* body) {
+ Statement* body) {
std::string generated_name{container_type->GetGeneratedMethodName(name)};
Method* result = RegisterDeclarable(std::unique_ptr<Method>(
new Method(container_type, container_type->GetGeneratedMethodName(name),
- name, std::move(signature), transitioning, body)));
+ name, std::move(signature), body)));
container_type->RegisterMethod(result);
return result;
}
@@ -235,29 +240,27 @@ Intrinsic* Declarations::DeclareIntrinsic(const std::string& name,
Builtin* Declarations::CreateBuiltin(std::string external_name,
std::string readable_name,
Builtin::Kind kind, Signature signature,
- bool transitioning,
+
base::Optional<Statement*> body) {
return RegisterDeclarable(std::unique_ptr<Builtin>(
new Builtin(std::move(external_name), std::move(readable_name), kind,
- std::move(signature), transitioning, body)));
+ std::move(signature), body)));
}
Builtin* Declarations::DeclareBuiltin(const std::string& name,
Builtin::Kind kind,
const Signature& signature,
- bool transitioning,
+
base::Optional<Statement*> body) {
CheckAlreadyDeclared<Builtin>(name, "builtin");
- return Declare(
- name, CreateBuiltin(name, name, kind, signature, transitioning, body));
+ return Declare(name, CreateBuiltin(name, name, kind, signature, body));
}
RuntimeFunction* Declarations::DeclareRuntimeFunction(
- const std::string& name, const Signature& signature, bool transitioning) {
+ const std::string& name, const Signature& signature) {
CheckAlreadyDeclared<RuntimeFunction>(name, "runtime function");
- return Declare(name,
- RegisterDeclarable(std::unique_ptr<RuntimeFunction>(
- new RuntimeFunction(name, signature, transitioning))));
+ return Declare(name, RegisterDeclarable(std::unique_ptr<RuntimeFunction>(
+ new RuntimeFunction(name, signature))));
}
void Declarations::DeclareExternConstant(Identifier* name, const Type* type,
diff --git a/deps/v8/src/torque/declarations.h b/deps/v8/src/torque/declarations.h
index 00e0facefe..240680fa1e 100644
--- a/deps/v8/src/torque/declarations.h
+++ b/deps/v8/src/torque/declarations.h
@@ -15,8 +15,6 @@ namespace internal {
namespace torque {
static constexpr const char* const kFromConstexprMacroName = "FromConstexpr";
-static constexpr const char* kTrueLabelName = "__True";
-static constexpr const char* kFalseLabelName = "__False";
static constexpr const char* kMacroEndLabelName = "__macro_end";
static constexpr const char* kBreakLabelName = "__break";
static constexpr const char* kContinueLabelName = "__continue";
@@ -78,6 +76,8 @@ class Declarations {
static GenericStructType* LookupUniqueGenericStructType(
const QualifiedName& name);
+ static base::Optional<GenericStructType*> TryLookupGenericStructType(
+ const QualifiedName& name);
static Namespace* DeclareNamespace(const std::string& name);
static TypeAlias* DeclareType(const Identifier* name, const Type* type);
@@ -88,23 +88,21 @@ class Declarations {
static TorqueMacro* CreateTorqueMacro(std::string external_name,
std::string readable_name,
bool exported_to_csa,
- Signature signature, bool transitioning,
+ Signature signature,
base::Optional<Statement*> body,
bool is_user_defined);
static ExternMacro* CreateExternMacro(std::string name,
std::string external_assembler_name,
- Signature signature,
- bool transitioning);
+ Signature signature);
static Macro* DeclareMacro(
const std::string& name, bool accessible_from_csa,
base::Optional<std::string> external_assembler_name,
- const Signature& signature, bool transitioning,
- base::Optional<Statement*> body, base::Optional<std::string> op = {},
- bool is_user_defined = true);
+ const Signature& signature, base::Optional<Statement*> body,
+ base::Optional<std::string> op = {}, bool is_user_defined = true);
static Method* CreateMethod(AggregateType* class_type,
const std::string& name, Signature signature,
- bool transitioning, Statement* body);
+ Statement* body);
static Intrinsic* CreateIntrinsic(const std::string& name,
const Signature& signature);
@@ -114,15 +112,14 @@ class Declarations {
static Builtin* CreateBuiltin(std::string external_name,
std::string readable_name, Builtin::Kind kind,
- Signature signature, bool transitioning,
+ Signature signature,
base::Optional<Statement*> body);
static Builtin* DeclareBuiltin(const std::string& name, Builtin::Kind kind,
- const Signature& signature, bool transitioning,
+ const Signature& signature,
base::Optional<Statement*> body);
static RuntimeFunction* DeclareRuntimeFunction(const std::string& name,
- const Signature& signature,
- bool transitioning);
+ const Signature& signature);
static void DeclareExternConstant(Identifier* name, const Type* type,
std::string value);
diff --git a/deps/v8/src/torque/earley-parser.h b/deps/v8/src/torque/earley-parser.h
index d3d0c89c42..9f7ba6a7ae 100644
--- a/deps/v8/src/torque/earley-parser.h
+++ b/deps/v8/src/torque/earley-parser.h
@@ -56,8 +56,8 @@ enum class ParseResultHolderBase::TypeId {
kImplicitParameters,
kOptionalImplicitParameters,
kNameAndExpression,
- kConditionalAnnotation,
- kOptionalConditionalAnnotation,
+ kAnnotation,
+ kVectorOfAnnotation,
kClassFieldExpression,
kStructFieldExpression,
kStdVectorOfNameAndTypeExpression,
diff --git a/deps/v8/src/torque/global-context.cc b/deps/v8/src/torque/global-context.cc
index f258f18474..13503038c5 100644
--- a/deps/v8/src/torque/global-context.cc
+++ b/deps/v8/src/torque/global-context.cc
@@ -8,6 +8,9 @@ namespace v8 {
namespace internal {
namespace torque {
+DEFINE_CONTEXTUAL_VARIABLE(GlobalContext)
+DEFINE_CONTEXTUAL_VARIABLE(TargetArchitecture)
+
GlobalContext::GlobalContext(Ast ast)
: collect_language_server_data_(false),
force_assert_statements_(false),
@@ -19,6 +22,10 @@ GlobalContext::GlobalContext(Ast ast)
RegisterDeclarable(base::make_unique<Namespace>(kBaseNamespaceName));
}
+TargetArchitecture::TargetArchitecture(bool force_32bit)
+ : tagged_size_(force_32bit ? sizeof(int32_t) : kTaggedSize),
+ raw_ptr_size_(force_32bit ? sizeof(int32_t) : kSystemPointerSize) {}
+
} // namespace torque
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/torque/global-context.h b/deps/v8/src/torque/global-context.h
index e103a22575..e1106adbd1 100644
--- a/deps/v8/src/torque/global-context.h
+++ b/deps/v8/src/torque/global-context.h
@@ -7,6 +7,7 @@
#include <map>
+#include "src/common/globals.h"
#include "src/torque/ast.h"
#include "src/torque/contextual.h"
#include "src/torque/declarable.h"
@@ -91,6 +92,18 @@ T* RegisterDeclarable(std::unique_ptr<T> d) {
return GlobalContext::Get().RegisterDeclarable(std::move(d));
}
+class TargetArchitecture : public ContextualClass<TargetArchitecture> {
+ public:
+ explicit TargetArchitecture(bool force_32bit);
+
+ static int TaggedSize() { return Get().tagged_size_; }
+ static int RawPtrSize() { return Get().raw_ptr_size_; }
+
+ private:
+ const int tagged_size_;
+ const int raw_ptr_size_;
+};
+
} // namespace torque
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/torque/implementation-visitor.cc b/deps/v8/src/torque/implementation-visitor.cc
index a0aeeee81b..8f36afd020 100644
--- a/deps/v8/src/torque/implementation-visitor.cc
+++ b/deps/v8/src/torque/implementation-visitor.cc
@@ -10,6 +10,7 @@
#include "src/torque/implementation-visitor.h"
#include "src/torque/parameter-difference.h"
#include "src/torque/server-data.h"
+#include "src/torque/type-inference.h"
#include "src/torque/type-visitor.h"
namespace v8 {
@@ -107,7 +108,8 @@ void ImplementationVisitor::EndCSAFiles() {
}
void ImplementationVisitor::Visit(NamespaceConstant* decl) {
- Signature signature{{}, base::nullopt, {{}, false}, 0, decl->type(), {}};
+ Signature signature{{}, base::nullopt, {{}, false}, 0, decl->type(),
+ {}, false};
BindingsManagersScope bindings_managers_scope;
@@ -466,13 +468,13 @@ void ImplementationVisitor::Visit(Builtin* builtin) {
: "UncheckedCast<Object>(Parameter(Descriptor::kReceiver))")
<< ";\n";
source_out() << "USE(" << generated_name << ");\n";
- expected_type = TypeOracle::GetObjectType();
+ expected_type = TypeOracle::GetJSAnyType();
} else if (param_name == "newTarget") {
source_out() << " TNode<Object> " << generated_name
<< " = UncheckedCast<Object>(Parameter("
<< "Descriptor::kJSNewTarget));\n";
source_out() << "USE(" << generated_name << ");\n";
- expected_type = TypeOracle::GetObjectType();
+ expected_type = TypeOracle::GetJSAnyType();
} else if (param_name == "target") {
source_out() << " TNode<JSFunction> " << generated_name
<< " = UncheckedCast<JSFunction>(Parameter("
@@ -646,24 +648,8 @@ VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
}
VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
- VisitResult left_result;
- {
- Block* false_block = assembler().NewBlock(assembler().CurrentStack());
- Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
- kFalseLabelName, LocalLabel{false_block}};
- left_result = Visit(expr->left);
- if (left_result.type()->IsBool()) {
- Block* true_block = LookupSimpleLabel(kTrueLabelName);
- assembler().Branch(true_block, false_block);
- assembler().Bind(false_block);
- } else if (left_result.type()->IsNever()) {
- assembler().Bind(false_block);
- } else if (!left_result.type()->IsConstexprBool()) {
- ReportError(
- "expected type bool, constexpr bool, or never on left-hand side of "
- "operator ||");
- }
- }
+ StackScope outer_scope(this);
+ VisitResult left_result = Visit(expr->left);
if (left_result.type()->IsConstexprBool()) {
VisitResult right_result = Visit(expr->right);
@@ -677,38 +663,34 @@ VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
" || " + right_result.constexpr_value() + ")");
}
- VisitResult right_result = Visit(expr->right);
- if (right_result.type()->IsBool()) {
- Block* true_block = LookupSimpleLabel(kTrueLabelName);
- Block* false_block = LookupSimpleLabel(kFalseLabelName);
- assembler().Branch(true_block, false_block);
- return VisitResult::NeverResult();
- } else if (!right_result.type()->IsNever()) {
- ReportError(
- "expected type bool or never on right-hand side of operator ||");
+ Block* true_block = assembler().NewBlock();
+ Block* false_block = assembler().NewBlock();
+ Block* done_block = assembler().NewBlock();
+
+ left_result = GenerateImplicitConvert(TypeOracle::GetBoolType(), left_result);
+ GenerateBranch(left_result, true_block, false_block);
+
+ assembler().Bind(true_block);
+ VisitResult true_result = GenerateBoolConstant(true);
+ assembler().Goto(done_block);
+
+ assembler().Bind(false_block);
+ VisitResult false_result;
+ {
+ StackScope false_block_scope(this);
+ false_result = false_block_scope.Yield(
+ GenerateImplicitConvert(TypeOracle::GetBoolType(), Visit(expr->right)));
}
- return right_result;
+ assembler().Goto(done_block);
+
+ assembler().Bind(done_block);
+ DCHECK_EQ(true_result, false_result);
+ return outer_scope.Yield(true_result);
}
VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
- VisitResult left_result;
- {
- Block* true_block = assembler().NewBlock(assembler().CurrentStack());
- Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
- kTrueLabelName, LocalLabel{true_block}};
- left_result = Visit(expr->left);
- if (left_result.type()->IsBool()) {
- Block* false_block = LookupSimpleLabel(kFalseLabelName);
- assembler().Branch(true_block, false_block);
- assembler().Bind(true_block);
- } else if (left_result.type()->IsNever()) {
- assembler().Bind(true_block);
- } else if (!left_result.type()->IsConstexprBool()) {
- ReportError(
- "expected type bool, constexpr bool, or never on left-hand side of "
- "operator &&");
- }
- }
+ StackScope outer_scope(this);
+ VisitResult left_result = Visit(expr->left);
if (left_result.type()->IsConstexprBool()) {
VisitResult right_result = Visit(expr->right);
@@ -722,17 +704,29 @@ VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
" && " + right_result.constexpr_value() + ")");
}
- VisitResult right_result = Visit(expr->right);
- if (right_result.type()->IsBool()) {
- Block* true_block = LookupSimpleLabel(kTrueLabelName);
- Block* false_block = LookupSimpleLabel(kFalseLabelName);
- assembler().Branch(true_block, false_block);
- return VisitResult::NeverResult();
- } else if (!right_result.type()->IsNever()) {
- ReportError(
- "expected type bool or never on right-hand side of operator &&");
+ Block* true_block = assembler().NewBlock();
+ Block* false_block = assembler().NewBlock();
+ Block* done_block = assembler().NewBlock();
+
+ left_result = GenerateImplicitConvert(TypeOracle::GetBoolType(), left_result);
+ GenerateBranch(left_result, true_block, false_block);
+
+ assembler().Bind(true_block);
+ VisitResult true_result;
+ {
+ StackScope true_block_scope(this);
+ true_result = true_block_scope.Yield(
+ GenerateImplicitConvert(TypeOracle::GetBoolType(), Visit(expr->right)));
}
- return right_result;
+ assembler().Goto(done_block);
+
+ assembler().Bind(false_block);
+ VisitResult false_result = GenerateBoolConstant(false);
+ assembler().Goto(done_block);
+
+ assembler().Bind(done_block);
+ DCHECK_EQ(true_result, false_result);
+ return outer_scope.Yield(true_result);
}
VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
@@ -1110,29 +1104,6 @@ const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
return TypeOracle::GetNeverType();
}
-VisitResult ImplementationVisitor::TemporaryUninitializedStruct(
- const StructType* struct_type, const std::string& reason) {
- StackRange range = assembler().TopRange(0);
- for (const Field& f : struct_type->fields()) {
- if (const StructType* struct_type =
- StructType::DynamicCast(f.name_and_type.type)) {
- range.Extend(
- TemporaryUninitializedStruct(struct_type, reason).stack_range());
- } else {
- std::string descriptor = "uninitialized field '" + f.name_and_type.name +
- "' declared at " + PositionAsString(f.pos) +
- " (" + reason + ")";
- TypeVector lowered_types = LowerType(f.name_and_type.type);
- for (const Type* type : lowered_types) {
- assembler().Emit(PushUninitializedInstruction{
- TypeOracle::GetTopType(descriptor, type)});
- }
- range.Extend(assembler().TopRange(lowered_types.size()));
- }
- }
- return VisitResult(struct_type, range);
-}
-
VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
size_t parameter_count = expr->label_block->parameters.names.size();
std::vector<VisitResult> parameters;
@@ -1211,15 +1182,38 @@ VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
return VisitResult{Visit(expr->statement), assembler().TopRange(0)};
}
+void ImplementationVisitor::CheckInitializersWellformed(
+ const std::string& aggregate_name,
+ const std::vector<Field>& aggregate_fields,
+ const std::vector<NameAndExpression>& initializers,
+ bool ignore_first_field) {
+ size_t fields_offset = ignore_first_field ? 1 : 0;
+ size_t fields_size = aggregate_fields.size() - fields_offset;
+ for (size_t i = 0; i < std::min(fields_size, initializers.size()); i++) {
+ const std::string& field_name =
+ aggregate_fields[i + fields_offset].name_and_type.name;
+ Identifier* found_name = initializers[i].name;
+ if (field_name != found_name->value) {
+ Error("Expected field name \"", field_name, "\" instead of \"",
+ found_name->value, "\"")
+ .Position(found_name->pos)
+ .Throw();
+ }
+ }
+ if (fields_size != initializers.size()) {
+ ReportError("expected ", fields_size, " initializers for ", aggregate_name,
+ " found ", initializers.size());
+ }
+}
+
InitializerResults ImplementationVisitor::VisitInitializerResults(
- const AggregateType* current_aggregate,
+ const ClassType* class_type,
const std::vector<NameAndExpression>& initializers) {
InitializerResults result;
for (const NameAndExpression& initializer : initializers) {
result.names.push_back(initializer.name);
Expression* e = initializer.expression;
- const Field& field =
- current_aggregate->LookupField(initializer.name->value);
+ const Field& field = class_type->LookupField(initializer.name->value);
auto field_index = field.index;
if (SpreadExpression* s = SpreadExpression::DynamicCast(e)) {
if (!field_index) {
@@ -1238,54 +1232,30 @@ InitializerResults ImplementationVisitor::VisitInitializerResults(
return result;
}
-size_t ImplementationVisitor::InitializeAggregateHelper(
- const AggregateType* aggregate_type, VisitResult allocate_result,
+void ImplementationVisitor::InitializeClass(
+ const ClassType* class_type, VisitResult allocate_result,
const InitializerResults& initializer_results) {
- const ClassType* current_class = ClassType::DynamicCast(aggregate_type);
- size_t current = 0;
- if (current_class) {
- const ClassType* super = current_class->GetSuperClass();
- if (super) {
- current = InitializeAggregateHelper(super, allocate_result,
- initializer_results);
- }
+ if (const ClassType* super = class_type->GetSuperClass()) {
+ InitializeClass(super, allocate_result, initializer_results);
}
- for (Field f : aggregate_type->fields()) {
- if (current == initializer_results.field_value_map.size()) {
- ReportError("insufficient number of initializers for ",
- aggregate_type->name());
- }
+ for (Field f : class_type->fields()) {
VisitResult current_value =
initializer_results.field_value_map.at(f.name_and_type.name);
- Identifier* fieldname = initializer_results.names[current];
- if (fieldname->value != f.name_and_type.name) {
- CurrentSourcePosition::Scope scope(fieldname->pos);
- ReportError("Expected fieldname \"", f.name_and_type.name,
- "\" instead of \"", fieldname->value, "\"");
- }
- if (aggregate_type->IsClassType()) {
- if (f.index) {
- InitializeFieldFromSpread(allocate_result, f, initializer_results);
- } else {
- allocate_result.SetType(aggregate_type);
- GenerateCopy(allocate_result);
- assembler().Emit(CreateFieldReferenceInstruction{
- ClassType::cast(aggregate_type), f.name_and_type.name});
- VisitResult heap_reference(
- TypeOracle::GetReferenceType(f.name_and_type.type),
- assembler().TopRange(2));
- GenerateAssignToLocation(
- LocationReference::HeapReference(heap_reference), current_value);
- }
+ if (f.index) {
+ InitializeFieldFromSpread(allocate_result, f, initializer_results);
} else {
- LocationReference struct_field_ref = LocationReference::VariableAccess(
- ProjectStructField(allocate_result, f.name_and_type.name));
- GenerateAssignToLocation(struct_field_ref, current_value);
+ allocate_result.SetType(class_type);
+ GenerateCopy(allocate_result);
+ assembler().Emit(CreateFieldReferenceInstruction{
+ ClassType::cast(class_type), f.name_and_type.name});
+ VisitResult heap_reference(
+ TypeOracle::GetReferenceType(f.name_and_type.type),
+ assembler().TopRange(2));
+ GenerateAssignToLocation(LocationReference::HeapReference(heap_reference),
+ current_value);
}
- ++current;
}
- return current;
}
void ImplementationVisitor::InitializeFieldFromSpread(
@@ -1304,17 +1274,6 @@ void ImplementationVisitor::InitializeFieldFromSpread(
{field.aggregate, index.type, iterator.type()});
}
-void ImplementationVisitor::InitializeAggregate(
- const AggregateType* aggregate_type, VisitResult allocate_result,
- const InitializerResults& initializer_results) {
- size_t consumed_initializers = InitializeAggregateHelper(
- aggregate_type, allocate_result, initializer_results);
- if (consumed_initializers != initializer_results.field_value_map.size()) {
- ReportError("more initializers than fields present in ",
- aggregate_type->name());
- }
-}
-
VisitResult ImplementationVisitor::AddVariableObjectSize(
VisitResult object_size, const ClassType* current_class,
const InitializerResults& initializer_results) {
@@ -1397,6 +1356,11 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
initializer_results.field_value_map[map_field.name_and_type.name] =
object_map;
}
+
+ CheckInitializersWellformed(class_type->name(),
+ class_type->ComputeAllFields(),
+ expr->initializers, !class_type->IsExtern());
+
Arguments size_arguments;
size_arguments.parameters.push_back(object_map);
VisitResult object_size = GenerateCall("%GetAllocationBaseSize",
@@ -1411,7 +1375,7 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
DCHECK(allocate_result.IsOnStack());
- InitializeAggregate(class_type, allocate_result, initializer_results);
+ InitializeClass(class_type, allocate_result, initializer_results);
return stack_scope.Yield(allocate_result);
}
@@ -1582,7 +1546,9 @@ namespace {
void FailCallableLookup(const std::string& reason, const QualifiedName& name,
const TypeVector& parameter_types,
const std::vector<Binding<LocalLabel>*>& labels,
- const std::vector<Signature>& candidates) {
+ const std::vector<Signature>& candidates,
+ const std::vector<std::tuple<Generic*, const char*>>
+ inapplicable_generics) {
std::stringstream stream;
stream << "\n" << reason << ": \n " << name << "(" << parameter_types << ")";
if (labels.size() != 0) {
@@ -1596,10 +1562,20 @@ void FailCallableLookup(const std::string& reason, const QualifiedName& name,
stream << "\n " << name;
PrintSignature(stream, signature, false);
}
+ if (inapplicable_generics.size() != 0) {
+ stream << "\nfailed to instantiate all of these generic declarations:";
+ for (auto& failure : inapplicable_generics) {
+ Generic* generic;
+ const char* reason;
+ std::tie(generic, reason) = failure;
+ stream << "\n " << generic->name() << " defined at "
+ << generic->Position() << ":\n " << reason << "\n";
+ }
+ }
ReportError(stream.str());
}
-Callable* GetOrCreateSpecialization(const SpecializationKey& key) {
+Callable* GetOrCreateSpecialization(const SpecializationKey<Generic>& key) {
if (base::Optional<Callable*> specialization =
key.generic->specializations().Get(key.specialized_types)) {
return *specialization;
@@ -1655,16 +1631,20 @@ Callable* ImplementationVisitor::LookupCallable(
std::vector<Declarable*> overloads;
std::vector<Signature> overload_signatures;
+ std::vector<std::tuple<Generic*, const char*>> inapplicable_generics;
for (auto* declarable : declaration_container) {
if (Generic* generic = Generic::DynamicCast(declarable)) {
- base::Optional<TypeVector> inferred_specialization_types =
- generic->InferSpecializationTypes(specialization_types,
- parameter_types);
- if (!inferred_specialization_types) continue;
+ TypeArgumentInference inference = generic->InferSpecializationTypes(
+ specialization_types, parameter_types);
+ if (inference.HasFailed()) {
+ inapplicable_generics.push_back(
+ std::make_tuple(generic, inference.GetFailureReason()));
+ continue;
+ }
overloads.push_back(generic);
overload_signatures.push_back(
DeclarationVisitor::MakeSpecializedSignature(
- SpecializationKey{generic, *inferred_specialization_types}));
+ SpecializationKey<Generic>{generic, inference.GetResult()}));
} else if (Callable* callable = Callable::DynamicCast(declarable)) {
overloads.push_back(callable);
overload_signatures.push_back(callable->signature());
@@ -1674,16 +1654,12 @@ Callable* ImplementationVisitor::LookupCallable(
std::vector<size_t> candidates;
for (size_t i = 0; i < overloads.size(); ++i) {
const Signature& signature = overload_signatures[i];
- bool try_bool_context = labels.size() == 0 &&
- signature.return_type == TypeOracle::GetNeverType();
- if (IsCompatibleSignature(signature, parameter_types, labels.size()) ||
- (try_bool_context &&
- IsCompatibleSignature(signature, parameter_types, 2))) {
+ if (IsCompatibleSignature(signature, parameter_types, labels.size())) {
candidates.push_back(i);
}
}
- if (overloads.empty()) {
+ if (overloads.empty() && inapplicable_generics.empty()) {
if (silence_errors) return nullptr;
std::stringstream stream;
stream << "no matching declaration found for " << name;
@@ -1691,7 +1667,8 @@ Callable* ImplementationVisitor::LookupCallable(
} else if (candidates.empty()) {
if (silence_errors) return nullptr;
FailCallableLookup("cannot find suitable callable with name", name,
- parameter_types, labels, overload_signatures);
+ parameter_types, labels, overload_signatures,
+ inapplicable_generics);
}
auto is_better_candidate = [&](size_t a, size_t b) {
@@ -1712,14 +1689,15 @@ Callable* ImplementationVisitor::LookupCallable(
candidate_signatures.push_back(overload_signatures[i]);
}
FailCallableLookup("ambiguous callable ", name, parameter_types, labels,
- candidate_signatures);
+ candidate_signatures, inapplicable_generics);
}
}
if (Generic* generic = Generic::DynamicCast(overloads[best])) {
+ TypeArgumentInference inference = generic->InferSpecializationTypes(
+ specialization_types, parameter_types);
result = GetOrCreateSpecialization(
- SpecializationKey{generic, *generic->InferSpecializationTypes(
- specialization_types, parameter_types)});
+ SpecializationKey<Generic>{generic, inference.GetResult()});
} else {
result = Callable::cast(overloads[best]);
}
@@ -1749,14 +1727,13 @@ Callable* ImplementationVisitor::LookupCallable(
}
Method* ImplementationVisitor::LookupMethod(
- const std::string& name, LocationReference this_reference,
+ const std::string& name, const AggregateType* receiver_type,
const Arguments& arguments, const TypeVector& specialization_types) {
TypeVector types(arguments.parameters.ComputeTypeVector());
- types.insert(types.begin(), this_reference.ReferencedType());
- return Method::cast(LookupCallable(
- {{}, name},
- AggregateType::cast(this_reference.ReferencedType())->Methods(name),
- types, arguments.labels, specialization_types));
+ types.insert(types.begin(), receiver_type);
+ return Method::cast(LookupCallable({{}, name}, receiver_type->Methods(name),
+ types, arguments.labels,
+ specialization_types));
}
const Type* ImplementationVisitor::GetCommonType(const Type* left,
@@ -1783,24 +1760,36 @@ VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
VisitResult ImplementationVisitor::Visit(StructExpression* expr) {
StackScope stack_scope(this);
- const Type* raw_type = TypeVisitor::ComputeType(expr->type);
- if (!raw_type->IsStructType()) {
- ReportError(*raw_type, " is not a struct but used like one");
- }
- const StructType* struct_type = StructType::cast(raw_type);
+ auto& initializers = expr->initializers;
+ std::vector<VisitResult> values;
+ std::vector<const Type*> term_argument_types;
+ values.reserve(initializers.size());
+ term_argument_types.reserve(initializers.size());
- InitializerResults initialization_results =
- ImplementationVisitor::VisitInitializerResults(struct_type,
- expr->initializers);
+ // Compute values and types of all initializer arguments
+ for (const NameAndExpression& initializer : initializers) {
+ VisitResult value = Visit(initializer.expression);
+ values.push_back(value);
+ term_argument_types.push_back(value.type());
+ }
- // Push uninitialized 'this'
- VisitResult result = TemporaryUninitializedStruct(
- struct_type, "it's not initialized in the struct " + struct_type->name());
+ // Compute and check struct type from given struct name and argument types
+ const StructType* struct_type = TypeVisitor::ComputeTypeForStructExpression(
+ expr->type, term_argument_types);
+ CheckInitializersWellformed(struct_type->name(), struct_type->fields(),
+ initializers);
- InitializeAggregate(struct_type, result, initialization_results);
+ // Implicitly convert values and thereby build the struct on the stack
+ StackRange struct_range = assembler().TopRange(0);
+ auto& fields = struct_type->fields();
+ for (size_t i = 0; i < values.size(); i++) {
+ values[i] =
+ GenerateImplicitConvert(fields[i].name_and_type.type, values[i]);
+ struct_range.Extend(values[i].stack_range());
+ }
- return stack_scope.Yield(result);
+ return stack_scope.Yield(VisitResult(struct_type, struct_range));
}
LocationReference ImplementationVisitor::GetLocationReference(
@@ -1865,7 +1854,33 @@ LocationReference ImplementationVisitor::GetLocationReference(
LanguageServerData::AddDefinition(expr->field->pos, field.pos);
}
if (field.index) {
- return LocationReference::IndexedFieldAccess(object_result, fieldname);
+ assembler().Emit(
+ CreateFieldReferenceInstruction{object_result.type(), fieldname});
+ // Fetch the length from the object
+ {
+ StackScope length_scope(this);
+ // Get a reference to the length
+ const Field* index_field = field.index.value();
+ GenerateCopy(object_result);
+ assembler().Emit(CreateFieldReferenceInstruction{
+ object_result.type(), index_field->name_and_type.name});
+ VisitResult length_reference(
+ TypeOracle::GetReferenceType(index_field->name_and_type.type),
+ assembler().TopRange(2));
+
+ // Load the length from the reference and convert it to intptr
+ VisitResult length = GenerateFetchFromLocation(
+ LocationReference::HeapReference(length_reference));
+ VisitResult converted_length =
+ GenerateCall("Convert", {{length}, {}},
+ {TypeOracle::GetIntPtrType(), length.type()}, false);
+ DCHECK_EQ(converted_length.stack_range().Size(), 1);
+ length_scope.Yield(converted_length);
+ }
+ const Type* slice_type =
+ TypeOracle::GetSliceType(field.name_and_type.type);
+ return LocationReference::HeapSlice(
+ VisitResult(slice_type, assembler().TopRange(3)));
} else {
assembler().Emit(
CreateFieldReferenceInstruction{*class_type, fieldname});
@@ -1883,8 +1898,13 @@ LocationReference ImplementationVisitor::GetLocationReference(
ElementAccessExpression* expr) {
LocationReference reference = GetLocationReference(expr->array);
VisitResult index = Visit(expr->index);
- if (reference.IsIndexedFieldAccess()) {
- return LocationReference::IndexedFieldIndexedAccess(reference, index);
+ if (reference.IsHeapSlice()) {
+ Arguments arguments{{index}, {}};
+ const AggregateType* slice_type =
+ AggregateType::cast(reference.heap_slice().type());
+ Method* method = LookupMethod("AtIndex", slice_type, arguments, {});
+ return LocationReference::HeapReference(
+ GenerateCall(method, reference, arguments, {}, false));
} else {
return LocationReference::ArrayAccess(GenerateFetchFromLocation(reference),
index);
@@ -1927,8 +1947,9 @@ LocationReference ImplementationVisitor::GetLocationReference(
}
if (expr->generic_arguments.size() != 0) {
Generic* generic = Declarations::LookupUniqueGeneric(name);
- Callable* specialization = GetOrCreateSpecialization(SpecializationKey{
- generic, TypeVisitor::ComputeTypeVector(expr->generic_arguments)});
+ Callable* specialization =
+ GetOrCreateSpecialization(SpecializationKey<Generic>{
+ generic, TypeVisitor::ComputeTypeVector(expr->generic_arguments)});
if (Builtin* builtin = Builtin::DynamicCast(specialization)) {
DCHECK(!builtin->IsExternal());
return LocationReference::Temporary(GetBuiltinCode(builtin),
@@ -1963,8 +1984,8 @@ LocationReference ImplementationVisitor::GetLocationReference(
LocationReference ImplementationVisitor::GetLocationReference(
DereferenceExpression* expr) {
VisitResult ref = Visit(expr->reference);
- const ReferenceType* type = ReferenceType::DynamicCast(ref.type());
- if (!type) {
+ if (!StructType::MatchUnaryGeneric(ref.type(),
+ TypeOracle::GetReferenceGeneric())) {
ReportError("Operator * expects a reference but found a value of type ",
*ref.type());
}
@@ -1983,7 +2004,7 @@ VisitResult ImplementationVisitor::GenerateFetchFromLocation(
DCHECK_EQ(1, LoweredSlotCount(reference.ReferencedType()));
return VisitResult(reference.ReferencedType(), assembler().TopRange(1));
} else {
- if (reference.IsIndexedFieldAccess()) {
+ if (reference.IsHeapSlice()) {
ReportError(
"fetching a value directly from an indexed field isn't allowed");
}
@@ -2011,12 +2032,19 @@ void ImplementationVisitor::GenerateAssignToLocation(
if (reference.binding()) {
(*reference.binding())->SetWritten();
}
- } else if (reference.IsIndexedFieldAccess()) {
+ } else if (reference.IsHeapSlice()) {
ReportError("assigning a value directly to an indexed field isn't allowed");
} else if (reference.IsHeapReference()) {
const Type* referenced_type = reference.ReferencedType();
GenerateCopy(reference.heap_reference());
- GenerateImplicitConvert(referenced_type, assignment_value);
+ VisitResult converted_assignment_value =
+ GenerateImplicitConvert(referenced_type, assignment_value);
+ if (referenced_type == TypeOracle::GetFloat64Type()) {
+ VisitResult silenced_float_value =
+ GenerateCall("Float64SilenceNaN", {{assignment_value}, {}});
+ assembler().Poke(converted_assignment_value.stack_range(),
+ silenced_float_value.stack_range(), referenced_type);
+ }
assembler().Emit(StoreReferenceInstruction{referenced_type});
} else {
DCHECK(reference.IsTemporary());
@@ -2097,27 +2125,20 @@ VisitResult ImplementationVisitor::GenerateCall(
Callable* callable, base::Optional<LocationReference> this_reference,
Arguments arguments, const TypeVector& specialization_types,
bool is_tailcall) {
- // Operators used in a branching context can also be function calls that never
- // return but have a True and False label
- if (arguments.labels.size() == 0 &&
- callable->signature().labels.size() == 2) {
- base::Optional<Binding<LocalLabel>*> true_label =
- TryLookupLabel(kTrueLabelName);
- base::Optional<Binding<LocalLabel>*> false_label =
- TryLookupLabel(kFalseLabelName);
- if (!true_label || !false_label) {
- ReportError(
- callable->ReadableName(),
- " does not return a value, but has to be called in a branching "
- "context (e.g., conditional or if-condition). You can fix this by "
- "adding \"? true : false\".");
+ const Type* return_type = callable->signature().return_type;
+
+ if (is_tailcall) {
+ if (Builtin* builtin = Builtin::DynamicCast(CurrentCallable::Get())) {
+ const Type* outer_return_type = builtin->signature().return_type;
+ if (!return_type->IsSubtypeOf(outer_return_type)) {
+ Error("Cannot tailcall, type of result is ", *return_type,
+ " but should be a subtype of ", *outer_return_type, ".");
+ }
+ } else {
+ Error("Tail calls are only allowed from builtins");
}
- arguments.labels.push_back(*true_label);
- arguments.labels.push_back(*false_label);
}
- const Type* return_type = callable->signature().return_type;
-
std::vector<VisitResult> converted_arguments;
StackRange argument_range = assembler().TopRange(0);
std::vector<std::string> constexpr_arguments;
@@ -2142,8 +2163,8 @@ VisitResult ImplementationVisitor::GenerateCall(
if (this_reference) {
DCHECK(callable->IsMethod());
Method* method = Method::cast(callable);
- // By now, the this reference should either be a variable or
- // a temporary, in both cases the fetch of the VisitResult should succeed.
+ // By now, the this reference should either be a variable, a temporary or
+ // a Slice. In either case the fetch of the VisitResult should succeed.
VisitResult this_value = this_reference->GetVisitResult();
if (method->ShouldBeInlined()) {
if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) {
@@ -2280,9 +2301,10 @@ VisitResult ImplementationVisitor::GenerateCall(
size_t j = 0;
for (auto t : callable->signature().labels[i].types) {
const Type* parameter_type = label->parameter_types[j];
- if (parameter_type != t) {
- ReportError("mismatch of label parameters (expected ", *t, " got ",
- parameter_type, " for parameter ", i + 1, ")");
+ if (!t->IsSubtypeOf(parameter_type)) {
+ ReportError("mismatch of label parameters (label expects ",
+ *parameter_type, " but macro produces ", *t,
+ " for parameter ", i + 1, ")");
}
j++;
}
@@ -2360,6 +2382,7 @@ VisitResult ImplementationVisitor::Visit(CallExpression* expr,
if (auto* loc_expr = LocationExpression::DynamicCast(expr->arguments[0])) {
LocationReference ref = GetLocationReference(loc_expr);
if (ref.IsHeapReference()) return scope.Yield(ref.heap_reference());
+ if (ref.IsHeapSlice()) return scope.Yield(ref.heap_slice());
}
ReportError("Unable to create a heap reference.");
}
@@ -2413,7 +2436,7 @@ VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
DCHECK_EQ(expr->method->namespace_qualification.size(), 0);
QualifiedName qualified_name = QualifiedName(method_name);
Callable* callable = nullptr;
- callable = LookupMethod(method_name, target, arguments, {});
+ callable = LookupMethod(method_name, target_type, arguments, {});
if (GlobalContext::collect_language_server_data()) {
LanguageServerData::AddDefinition(expr->method->name->pos,
callable->IdentifierPosition());
@@ -2429,7 +2452,7 @@ VisitResult ImplementationVisitor::Visit(IntrinsicCallExpression* expr) {
for (Expression* arg : expr->arguments)
arguments.parameters.push_back(Visit(arg));
return scope.Yield(
- GenerateCall(expr->name, arguments, specialization_types, false));
+ GenerateCall(expr->name->value, arguments, specialization_types, false));
}
void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
@@ -2440,32 +2463,20 @@ void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
assembler().Branch(true_block, false_block);
}
-void ImplementationVisitor::GenerateExpressionBranch(
- VisitResultGenerator generator, Block* true_block, Block* false_block) {
- // Conditional expressions can either explicitly return a bit
- // type, or they can be backed by macros that don't return but
- // take a true and false label. By declaring the labels before
- // visiting the conditional expression, those label-based
- // macro conditionals will be able to find them through normal
- // label lookups.
- Binding<LocalLabel> true_binding{&LabelBindingsManager::Get(), kTrueLabelName,
- LocalLabel{true_block}};
- Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
- kFalseLabelName, LocalLabel{false_block}};
- StackScope stack_scope(this);
- VisitResult expression_result = generator();
- if (!expression_result.type()->IsNever()) {
- expression_result = stack_scope.Yield(
- GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
- GenerateBranch(expression_result, true_block, false_block);
- }
+VisitResult ImplementationVisitor::GenerateBoolConstant(bool constant) {
+ return GenerateImplicitConvert(TypeOracle::GetBoolType(),
+ VisitResult(TypeOracle::GetConstexprBoolType(),
+ constant ? "true" : "false"));
}
void ImplementationVisitor::GenerateExpressionBranch(Expression* expression,
Block* true_block,
Block* false_block) {
- GenerateExpressionBranch([&]() { return this->Visit(expression); },
- true_block, false_block);
+ StackScope stack_scope(this);
+ VisitResult expression_result = this->Visit(expression);
+ expression_result = stack_scope.Yield(
+ GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
+ GenerateBranch(expression_result, true_block, false_block);
}
VisitResult ImplementationVisitor::GenerateImplicitConvert(
@@ -2530,10 +2541,6 @@ StackRange ImplementationVisitor::LowerParameter(
range.Extend(parameter_range);
}
return range;
- } else if (type->IsReferenceType()) {
- lowered_parameters->Push(parameter_name + ".object");
- lowered_parameters->Push(parameter_name + ".offset");
- return lowered_parameters->TopRange(2);
} else {
lowered_parameters->Push(parameter_name);
return lowered_parameters->TopRange(1);
@@ -2663,70 +2670,6 @@ void ImplementationVisitor::Visit(Declarable* declarable) {
}
}
-namespace {
-class IfDefScope {
- public:
- IfDefScope(std::ostream& os, std::string d) : os_(os), d_(std::move(d)) {
- os_ << "#ifdef " << d_ << "\n";
- }
- ~IfDefScope() { os_ << "#endif // " << d_ << "\n"; }
-
- private:
- std::ostream& os_;
- std::string d_;
-};
-
-class NamespaceScope {
- public:
- NamespaceScope(std::ostream& os,
- std::initializer_list<std::string> namespaces)
- : os_(os), d_(std::move(namespaces)) {
- for (const std::string& s : d_) {
- os_ << "namespace " << s << " {\n";
- }
- }
- ~NamespaceScope() {
- for (auto i = d_.rbegin(); i != d_.rend(); ++i) {
- os_ << "} // namespace " << *i << "\n";
- }
- }
-
- private:
- std::ostream& os_;
- std::vector<std::string> d_;
-};
-
-class IncludeGuardScope {
- public:
- IncludeGuardScope(std::ostream& os, std::string file_name)
- : os_(os),
- d_("V8_GEN_TORQUE_GENERATED_" + CapifyStringWithUnderscores(file_name) +
- "_") {
- os_ << "#ifndef " << d_ << "\n";
- os_ << "#define " << d_ << "\n\n";
- }
- ~IncludeGuardScope() { os_ << "#endif // " << d_ << "\n"; }
-
- private:
- std::ostream& os_;
- std::string d_;
-};
-
-class IncludeObjectMacrosScope {
- public:
- explicit IncludeObjectMacrosScope(std::ostream& os) : os_(os) {
- os_ << "\n// Has to be the last include (doesn't have include guards):\n"
- "#include \"src/objects/object-macros.h\"\n";
- }
- ~IncludeObjectMacrosScope() {
- os_ << "\n#include \"src/objects/object-macros-undef.h\"\n";
- }
-
- private:
- std::ostream& os_;
-};
-} // namespace
-
void ImplementationVisitor::GenerateBuiltinDefinitions(
const std::string& output_directory) {
std::stringstream new_contents_stream;
@@ -2741,7 +2684,7 @@ void ImplementationVisitor::GenerateBuiltinDefinitions(
for (auto& declarable : GlobalContext::AllDeclarables()) {
Builtin* builtin = Builtin::DynamicCast(declarable.get());
if (!builtin || builtin->IsExternal()) continue;
- int firstParameterIndex = 1;
+ size_t firstParameterIndex = 1;
bool declareParameters = true;
if (builtin->IsStub()) {
new_contents_stream << "TFS(" << builtin->ExternalName();
@@ -2752,24 +2695,22 @@ void ImplementationVisitor::GenerateBuiltinDefinitions(
<< ", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
declareParameters = false;
} else {
- assert(builtin->IsFixedArgsJavaScript());
+ DCHECK(builtin->IsFixedArgsJavaScript());
// FixedArg javascript builtins need to offer the parameter
// count.
- int size = static_cast<int>(builtin->parameter_names().size());
- assert(size >= 1);
- new_contents_stream << ", " << (std::max(size - 2, 0));
+ int parameter_count =
+ static_cast<int>(builtin->signature().ExplicitCount());
+ new_contents_stream << ", " << parameter_count;
// And the receiver is explicitly declared.
new_contents_stream << ", kReceiver";
- firstParameterIndex = 2;
+ firstParameterIndex = builtin->signature().implicit_count;
}
}
if (declareParameters) {
- int index = 0;
- for (const auto& parameter : builtin->parameter_names()) {
- if (index >= firstParameterIndex) {
- new_contents_stream << ", k" << CamelifyString(parameter->value);
- }
- index++;
+ for (size_t i = firstParameterIndex;
+ i < builtin->parameter_names().size(); ++i) {
+ Identifier* parameter = builtin->parameter_names()[i];
+ new_contents_stream << ", k" << CamelifyString(parameter->value);
}
}
new_contents_stream << ") \\\n";
@@ -2834,15 +2775,31 @@ class FieldOffsetsGenerator {
public:
explicit FieldOffsetsGenerator(const ClassType* type) : type_(type) {}
- virtual void WriteField(const Field& f) = 0;
+ virtual void WriteField(const Field& f, const std::string& size_string) = 0;
virtual void WriteMarker(const std::string& marker) = 0;
+ virtual void BeginPrivateOffsets() = 0;
virtual ~FieldOffsetsGenerator() { CHECK(is_finished_); }
void RecordOffsetFor(const Field& f) {
CHECK(!is_finished_);
UpdateSection(f);
- WriteField(f);
+ // We don't know statically how much space an indexed field takes, so report
+ // it as zero.
+ std::string size_string = "0";
+ if (!f.index.has_value()) {
+ size_t field_size;
+ std::tie(field_size, size_string) = f.GetFieldSizeInformation();
+ }
+ WriteField(f, size_string);
+
+ // Offsets for anything after an indexed field are likely to cause
+ // confusion, because the indexed field itself takes up a variable amount of
+ // space. We could not emit them at all, but that might allow an inherited
+ // kSize to be accessible (and wrong), so we emit them as private.
+ if (f.index.has_value()) {
+ BeginPrivateOffsets();
+ }
}
void Finish() {
@@ -2923,17 +2880,16 @@ class MacroFieldOffsetsGenerator : public FieldOffsetsGenerator {
out_ << "TORQUE_GENERATED_" << CapifyStringWithUnderscores(type_->name())
<< "_FIELDS(V) \\\n";
}
- virtual void WriteField(const Field& f) {
- size_t field_size;
- std::string size_string;
- std::string machine_type;
- std::tie(field_size, size_string) = f.GetFieldSizeInformation();
+ void WriteField(const Field& f, const std::string& size_string) override {
out_ << "V(k" << CamelifyString(f.name_and_type.name) << "Offset, "
<< size_string << ") \\\n";
}
- virtual void WriteMarker(const std::string& marker) {
+ void WriteMarker(const std::string& marker) override {
out_ << "V(" << marker << ", 0) \\\n";
}
+ void BeginPrivateOffsets() override {
+ // Can't do anything meaningful here in the macro generator.
+ }
private:
std::ostream& out_;
@@ -3025,13 +2981,15 @@ void ImplementationVisitor::GenerateClassFieldOffsets(
// TODO(danno): Remove this once all classes use ClassFieldOffsetGenerator
// to generate field offsets without the use of macros.
- MacroFieldOffsetsGenerator g(header, type);
- for (auto f : type->fields()) {
- CurrentSourcePosition::Scope scope(f.pos);
- g.RecordOffsetFor(f);
+ if (!type->GenerateCppClassDefinitions()) {
+ MacroFieldOffsetsGenerator g(header, type);
+ for (auto f : type->fields()) {
+ CurrentSourcePosition::Scope scope(f.pos);
+ g.RecordOffsetFor(f);
+ }
+ g.Finish();
+ header << "\n";
}
- g.Finish();
- header << "\n";
}
}
const std::string output_header_path = output_directory + "/" + file_name;
@@ -3046,11 +3004,7 @@ class ClassFieldOffsetGenerator : public FieldOffsetsGenerator {
: FieldOffsetsGenerator(type),
hdr_(header),
previous_field_end_("P::kHeaderSize") {}
- virtual void WriteField(const Field& f) {
- size_t field_size;
- std::string size_string;
- std::string machine_type;
- std::tie(field_size, size_string) = f.GetFieldSizeInformation();
+ void WriteField(const Field& f, const std::string& size_string) override {
std::string field = "k" + CamelifyString(f.name_and_type.name) + "Offset";
std::string field_end = field + "End";
hdr_ << " static constexpr int " << field << " = " << previous_field_end_
@@ -3059,10 +3013,15 @@ class ClassFieldOffsetGenerator : public FieldOffsetsGenerator {
<< size_string << " - 1;\n";
previous_field_end_ = field_end + " + 1";
}
- virtual void WriteMarker(const std::string& marker) {
+ void WriteMarker(const std::string& marker) override {
hdr_ << " static constexpr int " << marker << " = " << previous_field_end_
<< ";\n";
}
+ void BeginPrivateOffsets() override {
+ // The following section must re-establish public mode (currently done by
+ // GenerateClassConstructors).
+ hdr_ << " private:\n";
+ }
private:
std::ostream& hdr_;
@@ -3109,8 +3068,6 @@ class CppClassGenerator {
};
void CppClassGenerator::GenerateClass() {
- hdr_ << "class " << name_ << ";\n\n";
-
hdr_ << template_decl() << "\n";
hdr_ << "class " << gen_name_ << " : public P {\n";
hdr_ << " static_assert(std::is_same<" << name_ << ", D>::value,\n"
@@ -3118,7 +3075,7 @@ void CppClassGenerator::GenerateClass() {
hdr_ << " static_assert(std::is_same<" << super_->name() << ", P>::value,\n"
<< " \"Pass in " << super_->name()
<< " as second template parameter for " << gen_name_ << ".\");\n";
- hdr_ << "public: \n";
+ hdr_ << " public: \n";
hdr_ << " using Super = P;\n";
for (const Field& f : type_->fields()) {
GenerateFieldAccessor(f);
@@ -3170,7 +3127,7 @@ void CppClassGenerator::GenerateClassCasts() {
}
void CppClassGenerator::GenerateClassConstructors() {
- hdr_ << "public:\n";
+ hdr_ << " public:\n";
hdr_ << " template <class DAlias = D>\n";
hdr_ << " constexpr " << gen_name_ << "() : P() {\n";
hdr_ << " static_assert(std::is_base_of<" << gen_name_ << ", \n";
@@ -3282,9 +3239,9 @@ void CppClassGenerator::GenerateFieldAccessorForObject(const Field& f) {
DCHECK(field_type->IsSubtypeOf(TypeOracle::GetObjectType()));
const std::string& name = f.name_and_type.name;
const std::string offset = "k" + CamelifyString(name) + "Offset";
- const ClassType* class_type = ClassType::DynamicCast(field_type);
+ base::Optional<const ClassType*> class_type = field_type->ClassSupertype();
- std::string type = class_type ? class_type->name() : "Object";
+ std::string type = class_type ? (*class_type)->name() : "Object";
// Generate declarations in header.
if (!class_type && field_type != TypeOracle::GetObjectType()) {
@@ -3356,20 +3313,42 @@ void ImplementationVisitor::GenerateClassDefinitions(
IncludeGuardScope inline_header_guard(inline_header, basename + "-inl.h");
inline_header << "#include \"torque-generated/class-definitions-tq.h\"\n\n";
- inline_header << "#include \"src/objects/objects-inl.h\"\n\n";
+ inline_header << "#include \"src/objects/js-promise.h\"\n";
+ inline_header << "#include \"src/objects/module.h\"\n";
+ inline_header << "#include \"src/objects/objects-inl.h\"\n";
+ inline_header << "#include \"src/objects/script.h\"\n\n";
IncludeObjectMacrosScope inline_header_macros(inline_header);
NamespaceScope inline_header_namespaces(inline_header, {"v8", "internal"});
implementation
<< "#include \"torque-generated/class-definitions-tq.h\"\n\n";
implementation << "#include \"torque-generated/class-verifiers-tq.h\"\n\n";
- implementation << "#include \"src/objects/struct-inl.h\"\n\n";
+ implementation << "#include \"src/objects/arguments-inl.h\"\n";
+ implementation << "#include \"src/objects/js-collection-inl.h\"\n";
+ implementation << "#include \"src/objects/embedder-data-array-inl.h\"\n";
+ implementation << "#include \"src/objects/js-generator-inl.h\"\n";
+ implementation << "#include \"src/objects/js-regexp-inl.h\"\n";
+ implementation
+ << "#include \"src/objects/js-regexp-string-iterator-inl.h\"\n";
+ implementation << "#include \"src/objects/literal-objects-inl.h\"\n";
+ implementation << "#include \"src/objects/microtask-inl.h\"\n";
+ implementation << "#include \"src/objects/module-inl.h\"\n";
+ implementation << "#include \"src/objects/promise-inl.h\"\n";
+ implementation << "#include \"src/objects/stack-frame-info-inl.h\"\n";
+ implementation << "#include \"src/objects/struct-inl.h\"\n";
+ implementation << "#include \"src/objects/template-objects-inl.h\"\n\n";
implementation
<< "#include "
"\"torque-generated/internal-class-definitions-tq-inl.h\"\n\n";
NamespaceScope implementation_namespaces(implementation,
{"v8", "internal"});
+ // Generate forward declarations for every class.
+ for (const TypeAlias* alias : GlobalContext::GetClasses()) {
+ const ClassType* type = ClassType::DynamicCast(alias->type());
+ header << "class " << type->name() << ";\n";
+ }
+
for (const TypeAlias* alias : GlobalContext::GetClasses()) {
const ClassType* type = ClassType::DynamicCast(alias->type());
if (type->GenerateCppClassDefinitions()) {
@@ -3724,6 +3703,16 @@ void ReportAllUnusedMacros() {
if (macro->IsTorqueMacro() && TorqueMacro::cast(macro)->IsExportedToCSA()) {
continue;
}
+ // TODO(gsps): Mark methods of generic structs used if they are used in any
+ // instantiation
+ if (Method* method = Method::DynamicCast(macro)) {
+ if (StructType* struct_type =
+ StructType::DynamicCast(method->aggregate_type())) {
+ if (struct_type->GetSpecializedFrom().has_value()) {
+ continue;
+ }
+ }
+ }
std::vector<std::string> ignored_prefixes = {"Convert<", "Cast<",
"FromConstexpr<"};
diff --git a/deps/v8/src/torque/implementation-visitor.h b/deps/v8/src/torque/implementation-visitor.h
index a572ebb936..eb1a6c4452 100644
--- a/deps/v8/src/torque/implementation-visitor.h
+++ b/deps/v8/src/torque/implementation-visitor.h
@@ -12,6 +12,7 @@
#include "src/torque/cfg.h"
#include "src/torque/declarations.h"
#include "src/torque/global-context.h"
+#include "src/torque/type-oracle.h"
#include "src/torque/types.h"
#include "src/torque/utils.h"
@@ -52,10 +53,20 @@ class LocationReference {
// pointer.
static LocationReference HeapReference(VisitResult heap_reference) {
LocationReference result;
- DCHECK(heap_reference.type()->IsReferenceType());
+ DCHECK(StructType::MatchUnaryGeneric(heap_reference.type(),
+ TypeOracle::GetReferenceGeneric()));
result.heap_reference_ = std::move(heap_reference);
return result;
}
+ // A reference to an array on the heap. That is, a tagged value, an offset to
+ // encode an inner pointer, and the number of elements.
+ static LocationReference HeapSlice(VisitResult heap_slice) {
+ LocationReference result;
+ DCHECK(StructType::MatchUnaryGeneric(heap_slice.type(),
+ TypeOracle::GetSliceGeneric()));
+ result.heap_slice_ = std::move(heap_slice);
+ return result;
+ }
static LocationReference ArrayAccess(VisitResult base, VisitResult offset) {
LocationReference result;
result.eval_function_ = std::string{"[]"};
@@ -69,26 +80,6 @@ class LocationReference {
result.eval_function_ = "." + fieldname;
result.assign_function_ = "." + fieldname + "=";
result.call_arguments_ = {object};
- result.index_field_ = base::nullopt;
- return result;
- }
- static LocationReference IndexedFieldIndexedAccess(
- const LocationReference& indexed_field, VisitResult index) {
- LocationReference result;
- DCHECK(indexed_field.IsIndexedFieldAccess());
- std::string fieldname = *indexed_field.index_field_;
- result.eval_function_ = "." + fieldname + "[]";
- result.assign_function_ = "." + fieldname + "[]=";
- result.call_arguments_ = indexed_field.call_arguments_;
- result.call_arguments_.push_back(index);
- result.index_field_ = fieldname;
- return result;
- }
- static LocationReference IndexedFieldAccess(VisitResult object,
- std::string fieldname) {
- LocationReference result;
- result.call_arguments_ = {object};
- result.index_field_ = fieldname;
return result;
}
@@ -109,16 +100,26 @@ class LocationReference {
DCHECK(IsHeapReference());
return *heap_reference_;
}
+ bool IsHeapSlice() const { return heap_slice_.has_value(); }
+ const VisitResult& heap_slice() const {
+ DCHECK(IsHeapSlice());
+ return *heap_slice_;
+ }
const Type* ReferencedType() const {
if (IsHeapReference()) {
- return ReferenceType::cast(heap_reference().type())->referenced_type();
+ return *StructType::MatchUnaryGeneric(heap_reference().type(),
+ TypeOracle::GetReferenceGeneric());
+ } else if (IsHeapSlice()) {
+ return *StructType::MatchUnaryGeneric(heap_slice().type(),
+ TypeOracle::GetSliceGeneric());
}
return GetVisitResult().type();
}
const VisitResult& GetVisitResult() const {
if (IsVariableAccess()) return variable();
+ if (IsHeapSlice()) return heap_slice();
DCHECK(IsTemporary());
return temporary();
}
@@ -129,13 +130,6 @@ class LocationReference {
return *temporary_description_;
}
- bool IsArrayField() const { return index_field_.has_value(); }
- bool IsIndexedFieldAccess() const {
- return IsArrayField() && !IsCallAccess();
- }
- bool IsIndexedFieldIndexedAccess() const {
- return IsArrayField() && IsCallAccess();
- }
bool IsCallAccess() const {
bool is_call_access = eval_function_.has_value();
DCHECK_EQ(is_call_access, assign_function_.has_value());
@@ -163,10 +157,10 @@ class LocationReference {
base::Optional<VisitResult> temporary_;
base::Optional<std::string> temporary_description_;
base::Optional<VisitResult> heap_reference_;
+ base::Optional<VisitResult> heap_slice_;
base::Optional<std::string> eval_function_;
base::Optional<std::string> assign_function_;
VisitResultVector call_arguments_;
- base::Optional<std::string> index_field_;
base::Optional<Binding<LocalValue>*> binding_;
LocationReference() = default;
@@ -354,6 +348,7 @@ class ImplementationVisitor {
void GenerateClassDefinitions(const std::string& output_directory);
void GenerateInstanceTypes(const std::string& output_directory);
void GenerateClassVerifiers(const std::string& output_directory);
+ void GenerateClassDebugReaders(const std::string& output_directory);
void GenerateExportedMacrosAssembler(const std::string& output_directory);
void GenerateCSATypes(const std::string& output_directory);
void GenerateCppForInternalClasses(const std::string& output_directory);
@@ -361,27 +356,26 @@ class ImplementationVisitor {
VisitResult Visit(Expression* expr);
const Type* Visit(Statement* stmt);
+ void CheckInitializersWellformed(
+ const std::string& aggregate_name,
+ const std::vector<Field>& aggregate_fields,
+ const std::vector<NameAndExpression>& initializers,
+ bool ignore_first_field = false);
+
InitializerResults VisitInitializerResults(
- const AggregateType* aggregate,
+ const ClassType* class_type,
const std::vector<NameAndExpression>& expressions);
void InitializeFieldFromSpread(VisitResult object, const Field& field,
const InitializerResults& initializer_results);
- size_t InitializeAggregateHelper(
- const AggregateType* aggregate_type, VisitResult allocate_result,
- const InitializerResults& initializer_results);
-
VisitResult AddVariableObjectSize(
VisitResult object_size, const ClassType* current_class,
const InitializerResults& initializer_results);
- void InitializeAggregate(const AggregateType* aggregate_type,
- VisitResult allocate_result,
- const InitializerResults& initializer_results);
+ void InitializeClass(const ClassType* class_type, VisitResult allocate_result,
+ const InitializerResults& initializer_results);
- VisitResult TemporaryUninitializedStruct(const StructType* struct_type,
- const std::string& reason);
VisitResult Visit(StructExpression* decl);
LocationReference GetLocationReference(Expression* location);
@@ -570,7 +564,8 @@ class ImplementationVisitor {
const Arguments& arguments,
const TypeVector& specialization_types);
- Method* LookupMethod(const std::string& name, LocationReference target,
+ Method* LookupMethod(const std::string& name,
+ const AggregateType* receiver_type,
const Arguments& arguments,
const TypeVector& specialization_types);
@@ -608,9 +603,8 @@ class ImplementationVisitor {
void GenerateBranch(const VisitResult& condition, Block* true_block,
Block* false_block);
- using VisitResultGenerator = std::function<VisitResult()>;
- void GenerateExpressionBranch(VisitResultGenerator, Block* true_block,
- Block* false_block);
+ VisitResult GenerateBoolConstant(bool constant);
+
void GenerateExpressionBranch(Expression* expression, Block* true_block,
Block* false_block);
diff --git a/deps/v8/src/torque/instructions.cc b/deps/v8/src/torque/instructions.cc
index 36a22ee8fa..5bc2149f41 100644
--- a/deps/v8/src/torque/instructions.cc
+++ b/deps/v8/src/torque/instructions.cc
@@ -133,7 +133,7 @@ void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack,
if (catch_block) {
Stack<const Type*> catch_stack = *stack;
- catch_stack.Push(TypeOracle::GetObjectType());
+ catch_stack.Push(TypeOracle::GetJSAnyType());
(*catch_block)->SetInputTypes(catch_stack);
}
@@ -170,7 +170,7 @@ void CallCsaMacroAndBranchInstruction::TypeInstruction(
if (catch_block) {
Stack<const Type*> catch_stack = *stack;
- catch_stack.Push(TypeOracle::GetObjectType());
+ catch_stack.Push(TypeOracle::GetJSAnyType());
(*catch_block)->SetInputTypes(catch_stack);
}
@@ -201,7 +201,7 @@ void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack,
if (catch_block) {
Stack<const Type*> catch_stack = *stack;
- catch_stack.Push(TypeOracle::GetObjectType());
+ catch_stack.Push(TypeOracle::GetJSAnyType());
(*catch_block)->SetInputTypes(catch_stack);
}
@@ -236,7 +236,7 @@ void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack,
if (catch_block) {
Stack<const Type*> catch_stack = *stack;
- catch_stack.Push(TypeOracle::GetObjectType());
+ catch_stack.Push(TypeOracle::GetJSAnyType());
(*catch_block)->SetInputTypes(catch_stack);
}
@@ -292,15 +292,14 @@ void UnsafeCastInstruction::TypeInstruction(Stack<const Type*>* stack,
void CreateFieldReferenceInstruction::TypeInstruction(
Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
- ExpectSubtype(stack->Pop(), class_type);
- stack->Push(TypeOracle::GetHeapObjectType());
+ ExpectSubtype(stack->Top(), type);
stack->Push(TypeOracle::GetIntPtrType());
}
void LoadReferenceInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
ExpectType(TypeOracle::GetIntPtrType(), stack->Pop());
- ExpectType(TypeOracle::GetHeapObjectType(), stack->Pop());
+ ExpectSubtype(stack->Pop(), TypeOracle::GetHeapObjectType());
DCHECK_EQ(std::vector<const Type*>{type}, LowerType(type));
stack->Push(type);
}
@@ -309,7 +308,7 @@ void StoreReferenceInstruction::TypeInstruction(Stack<const Type*>* stack,
ControlFlowGraph* cfg) const {
ExpectSubtype(stack->Pop(), type);
ExpectType(TypeOracle::GetIntPtrType(), stack->Pop());
- ExpectType(TypeOracle::GetHeapObjectType(), stack->Pop());
+ ExpectSubtype(stack->Pop(), TypeOracle::GetHeapObjectType());
}
bool CallRuntimeInstruction::IsBlockTerminator() const {
diff --git a/deps/v8/src/torque/instructions.h b/deps/v8/src/torque/instructions.h
index 3136b58321..fe3b26b86f 100644
--- a/deps/v8/src/torque/instructions.h
+++ b/deps/v8/src/torque/instructions.h
@@ -206,10 +206,9 @@ struct NamespaceConstantInstruction : InstructionBase {
struct CreateFieldReferenceInstruction : InstructionBase {
TORQUE_INSTRUCTION_BOILERPLATE()
- CreateFieldReferenceInstruction(const ClassType* class_type,
- std::string field_name)
- : class_type(class_type), field_name(std::move(field_name)) {}
- const ClassType* class_type;
+ CreateFieldReferenceInstruction(const Type* type, std::string field_name)
+ : type(type), field_name(std::move(field_name)) {}
+ const Type* type;
std::string field_name;
};
diff --git a/deps/v8/src/torque/torque-compiler.cc b/deps/v8/src/torque/torque-compiler.cc
index a3da95c747..3968b001fb 100644
--- a/deps/v8/src/torque/torque-compiler.cc
+++ b/deps/v8/src/torque/torque-compiler.cc
@@ -53,6 +53,7 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
if (options.force_assert_statements) {
GlobalContext::SetForceAssertStatements();
}
+ TargetArchitecture::Scope target_architecture(options.force_32bit_output);
TypeOracle::Scope type_oracle;
// Two-step process of predeclaration + resolution allows to resolve type
@@ -83,6 +84,7 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
implementation_visitor.GeneratePrintDefinitions(output_directory);
implementation_visitor.GenerateClassDefinitions(output_directory);
implementation_visitor.GenerateClassVerifiers(output_directory);
+ implementation_visitor.GenerateClassDebugReaders(output_directory);
implementation_visitor.GenerateExportedMacrosAssembler(output_directory);
implementation_visitor.GenerateCSATypes(output_directory);
implementation_visitor.GenerateInstanceTypes(output_directory);
diff --git a/deps/v8/src/torque/torque-compiler.h b/deps/v8/src/torque/torque-compiler.h
index 32680986fd..df81d60d3e 100644
--- a/deps/v8/src/torque/torque-compiler.h
+++ b/deps/v8/src/torque/torque-compiler.h
@@ -24,6 +24,12 @@ struct TorqueCompilerOptions {
// language server support for statements inside asserts, this flag
// can force generate them.
bool force_assert_statements = false;
+
+ // Forge (Google3) can only run 64-bit executables. As Torque runs as part
+ // of the build process, we need a "cross-compile" mode when we target 32-bit
+ // architectures. Note that this does not needed in Chromium/V8 land, since we
+ // always build with the same bit width as the target architecture.
+ bool force_32bit_output = false;
};
struct TorqueCompilerResult {
diff --git a/deps/v8/src/torque/torque-parser.cc b/deps/v8/src/torque/torque-parser.cc
index 0a371b79f9..d9973dde3c 100644
--- a/deps/v8/src/torque/torque-parser.cc
+++ b/deps/v8/src/torque/torque-parser.cc
@@ -108,13 +108,12 @@ V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<NameAndExpression>::id =
ParseResultTypeId::kNameAndExpression;
template <>
-V8_EXPORT_PRIVATE const ParseResultTypeId
- ParseResultHolder<ConditionalAnnotation>::id =
- ParseResultTypeId::kConditionalAnnotation;
+V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Annotation>::id =
+ ParseResultTypeId::kAnnotation;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
- ParseResultHolder<base::Optional<ConditionalAnnotation>>::id =
- ParseResultTypeId::kOptionalConditionalAnnotation;
+ ParseResultHolder<std::vector<Annotation>>::id =
+ ParseResultTypeId::kVectorOfAnnotation;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<ClassFieldExpression>::id =
@@ -360,7 +359,7 @@ base::Optional<ParseResult> MakeBinaryOperator(
base::Optional<ParseResult> MakeIntrinsicCallExpression(
ParseResultIterator* child_results) {
- auto callee = child_results->NextAs<std::string>();
+ auto callee = child_results->NextAs<Identifier*>();
auto generic_arguments =
child_results->NextAs<std::vector<TypeExpression*>>();
auto args = child_results->NextAs<std::vector<Expression*>>();
@@ -472,29 +471,27 @@ base::Optional<ParseResult> MakeExternalMacro(
auto operator_name = child_results->NextAs<base::Optional<std::string>>();
auto external_assembler_name =
child_results->NextAs<base::Optional<std::string>>();
- auto name = child_results->NextAs<std::string>();
+ auto name = child_results->NextAs<Identifier*>();
auto generic_parameters = child_results->NextAs<GenericParameters>();
LintGenericParameters(generic_parameters);
auto args = child_results->NextAs<ParameterList>();
auto return_type = child_results->NextAs<TypeExpression*>();
auto labels = child_results->NextAs<LabelAndTypesVector>();
- MacroDeclaration* macro = MakeNode<ExternalMacroDeclaration>(
+
+ Declaration* result = MakeNode<ExternalMacroDeclaration>(
transitioning,
external_assembler_name ? *external_assembler_name : "CodeStubAssembler",
name, operator_name, args, return_type, labels);
- Declaration* result;
- if (generic_parameters.empty()) {
- result = MakeNode<StandardDeclaration>(macro, base::nullopt);
- } else {
- result = MakeNode<GenericDeclaration>(macro, generic_parameters);
+ if (!generic_parameters.empty()) {
+ Error("External builtins cannot be generic.");
}
return ParseResult{result};
}
base::Optional<ParseResult> MakeIntrinsicDeclaration(
ParseResultIterator* child_results) {
- auto name = child_results->NextAs<std::string>();
+ auto name = child_results->NextAs<Identifier*>();
auto generic_parameters = child_results->NextAs<GenericParameters>();
LintGenericParameters(generic_parameters);
@@ -502,19 +499,17 @@ base::Optional<ParseResult> MakeIntrinsicDeclaration(
auto return_type = child_results->NextAs<TypeExpression*>();
auto body = child_results->NextAs<base::Optional<Statement*>>();
LabelAndTypesVector labels;
- CallableNode* callable = nullptr;
+ CallableDeclaration* declaration;
if (body) {
- callable = MakeNode<TorqueMacroDeclaration>(
+ declaration = MakeNode<TorqueMacroDeclaration>(
false, name, base::Optional<std::string>{}, args, return_type, labels,
- false);
+ false, body);
} else {
- callable = MakeNode<IntrinsicDeclaration>(name, args, return_type);
+ declaration = MakeNode<IntrinsicDeclaration>(name, args, return_type);
}
- Declaration* result;
- if (generic_parameters.empty()) {
- result = MakeNode<StandardDeclaration>(callable, body);
- } else {
- result = MakeNode<GenericDeclaration>(callable, generic_parameters, body);
+ Declaration* result = declaration;
+ if (!generic_parameters.empty()) {
+ result = MakeNode<GenericDeclaration>(generic_parameters, declaration);
}
return ParseResult{result};
}
@@ -524,8 +519,8 @@ base::Optional<ParseResult> MakeTorqueMacroDeclaration(
auto export_to_csa = child_results->NextAs<bool>();
auto transitioning = child_results->NextAs<bool>();
auto operator_name = child_results->NextAs<base::Optional<std::string>>();
- auto name = child_results->NextAs<std::string>();
- if (!IsUpperCamelCase(name)) {
+ auto name = child_results->NextAs<Identifier*>();
+ if (!IsUpperCamelCase(name->value)) {
NamingConventionError("Macro", name, "UpperCamelCase");
}
@@ -536,16 +531,15 @@ base::Optional<ParseResult> MakeTorqueMacroDeclaration(
auto return_type = child_results->NextAs<TypeExpression*>();
auto labels = child_results->NextAs<LabelAndTypesVector>();
auto body = child_results->NextAs<base::Optional<Statement*>>();
- MacroDeclaration* macro =
- MakeNode<TorqueMacroDeclaration>(transitioning, name, operator_name, args,
- return_type, labels, export_to_csa);
- Declaration* result;
+ CallableDeclaration* declaration = MakeNode<TorqueMacroDeclaration>(
+ transitioning, name, operator_name, args, return_type, labels,
+ export_to_csa, body);
+ Declaration* result = declaration;
if (generic_parameters.empty()) {
if (!body) ReportError("A non-generic declaration needs a body.");
- result = MakeNode<StandardDeclaration>(macro, *body);
} else {
if (export_to_csa) ReportError("Cannot export generics to CSA.");
- result = MakeNode<GenericDeclaration>(macro, generic_parameters, body);
+ result = MakeNode<GenericDeclaration>(generic_parameters, declaration);
}
return ParseResult{result};
}
@@ -554,8 +548,8 @@ base::Optional<ParseResult> MakeTorqueBuiltinDeclaration(
ParseResultIterator* child_results) {
auto transitioning = child_results->NextAs<bool>();
auto javascript_linkage = child_results->NextAs<bool>();
- auto name = child_results->NextAs<std::string>();
- if (!IsUpperCamelCase(name)) {
+ auto name = child_results->NextAs<Identifier*>();
+ if (!IsUpperCamelCase(name->value)) {
NamingConventionError("Builtin", name, "UpperCamelCase");
}
@@ -565,14 +559,13 @@ base::Optional<ParseResult> MakeTorqueBuiltinDeclaration(
auto args = child_results->NextAs<ParameterList>();
auto return_type = child_results->NextAs<TypeExpression*>();
auto body = child_results->NextAs<base::Optional<Statement*>>();
- BuiltinDeclaration* builtin = MakeNode<TorqueBuiltinDeclaration>(
- transitioning, javascript_linkage, name, args, return_type);
- Declaration* result;
+ CallableDeclaration* declaration = MakeNode<TorqueBuiltinDeclaration>(
+ transitioning, javascript_linkage, name, args, return_type, body);
+ Declaration* result = declaration;
if (generic_parameters.empty()) {
if (!body) ReportError("A non-generic declaration needs a body.");
- result = MakeNode<StandardDeclaration>(builtin, *body);
} else {
- result = MakeNode<GenericDeclaration>(builtin, generic_parameters, body);
+ result = MakeNode<GenericDeclaration>(generic_parameters, declaration);
}
return ParseResult{result};
}
@@ -649,8 +642,8 @@ base::Optional<ParseResult> MakeMethodDeclaration(
ParseResultIterator* child_results) {
auto transitioning = child_results->NextAs<bool>();
auto operator_name = child_results->NextAs<base::Optional<std::string>>();
- auto name = child_results->NextAs<std::string>();
- if (!IsUpperCamelCase(name)) {
+ auto name = child_results->NextAs<Identifier*>();
+ if (!IsUpperCamelCase(name->value)) {
NamingConventionError("Method", name, "UpperCamelCase");
}
@@ -658,39 +651,66 @@ base::Optional<ParseResult> MakeMethodDeclaration(
auto return_type = child_results->NextAs<TypeExpression*>();
auto labels = child_results->NextAs<LabelAndTypesVector>();
auto body = child_results->NextAs<Statement*>();
- MacroDeclaration* macro = MakeNode<TorqueMacroDeclaration>(
- transitioning, name, operator_name, args, return_type, labels, false);
- Declaration* result = MakeNode<StandardDeclaration>(macro, body);
+ Declaration* result =
+ MakeNode<TorqueMacroDeclaration>(transitioning, name, operator_name, args,
+ return_type, labels, false, body);
return ParseResult{result};
}
class AnnotationSet {
public:
AnnotationSet(ParseResultIterator* iter,
- const std::set<std::string>& allowed) {
- auto list = iter->NextAs<std::vector<Identifier*>>();
- for (const Identifier* i : list) {
- if (allowed.find(i->value) == allowed.end()) {
- Lint("Annotation ", i->value, " is not allowed here").Position(i->pos);
- }
- if (!set_.insert(i->value).second) {
- Lint("Duplicate annotation ", i->value).Position(i->pos);
+ const std::set<std::string>& allowed_without_param,
+ const std::set<std::string>& allowed_with_param) {
+ auto list = iter->NextAs<std::vector<Annotation>>();
+ for (const Annotation& a : list) {
+ if (a.param.has_value()) {
+ if (allowed_with_param.find(a.name->value) ==
+ allowed_with_param.end()) {
+ const char* error_message =
+ allowed_without_param.find(a.name->value) ==
+ allowed_without_param.end()
+ ? " is not allowed here"
+ : " cannot have parameter here";
+ Lint("Annotation ", a.name->value, error_message)
+ .Position(a.name->pos);
+ }
+ map_[a.name->value].push_back(*a.param);
+ } else {
+ if (allowed_without_param.find(a.name->value) ==
+ allowed_without_param.end()) {
+ const char* error_message =
+ allowed_with_param.find(a.name->value) == allowed_with_param.end()
+ ? " is not allowed here"
+ : " requires a parameter here";
+ Lint("Annotation ", a.name->value, error_message)
+ .Position(a.name->pos);
+ }
+ if (!set_.insert(a.name->value).second) {
+ Lint("Duplicate annotation ", a.name->value).Position(a.name->pos);
+ }
}
}
}
bool Contains(const std::string& s) { return set_.find(s) != set_.end(); }
+ const std::vector<std::string>& GetParams(const std::string& s) {
+ return map_[s];
+ }
private:
std::set<std::string> set_;
+ std::map<std::string, std::vector<std::string>> map_;
};
base::Optional<ParseResult> MakeClassDeclaration(
ParseResultIterator* child_results) {
AnnotationSet annotations(
- child_results, {"@generatePrint", "@noVerifier", "@abstract",
- "@dirtyInstantiatedAbstractClass",
- "@hasSameInstanceTypeAsParent", "@generateCppClass"});
+ child_results,
+ {"@generatePrint", "@noVerifier", "@abstract",
+ "@dirtyInstantiatedAbstractClass", "@hasSameInstanceTypeAsParent",
+ "@generateCppClass"},
+ {});
ClassFlags flags = ClassFlag::kNone;
bool generate_print = annotations.Contains("@generatePrint");
if (generate_print) flags |= ClassFlag::kGeneratePrint;
@@ -726,15 +746,18 @@ base::Optional<ParseResult> MakeClassDeclaration(
// Filter to only include fields that should be present based on decoration.
std::vector<ClassFieldExpression> fields;
- std::copy_if(fields_raw.begin(), fields_raw.end(), std::back_inserter(fields),
- [](const ClassFieldExpression& exp) {
- if (!exp.conditional.has_value()) return true;
- const ConditionalAnnotation& conditional = *exp.conditional;
- return conditional.type == ConditionalAnnotationType::kPositive
- ? BuildFlags::GetFlag(conditional.condition, "@if")
- : !BuildFlags::GetFlag(conditional.condition,
- "@ifnot");
- });
+ std::copy_if(
+ fields_raw.begin(), fields_raw.end(), std::back_inserter(fields),
+ [](const ClassFieldExpression& exp) {
+ for (const ConditionalAnnotation& condition : exp.conditions) {
+ if (condition.type == ConditionalAnnotationType::kPositive
+ ? !BuildFlags::GetFlag(condition.condition, "@if")
+ : BuildFlags::GetFlag(condition.condition, "@ifnot")) {
+ return false;
+ }
+ }
+ return true;
+ });
Declaration* result = MakeNode<ClassDeclaration>(
name, flags, std::move(extends), std::move(generates), std::move(methods),
@@ -756,6 +779,7 @@ base::Optional<ParseResult> MakeNamespaceDeclaration(
base::Optional<ParseResult> MakeSpecializationDeclaration(
ParseResultIterator* child_results) {
+ auto transitioning = child_results->NextAs<bool>();
auto name = child_results->NextAs<Identifier*>();
auto generic_parameters =
child_results->NextAs<std::vector<TypeExpression*>>();
@@ -765,8 +789,8 @@ base::Optional<ParseResult> MakeSpecializationDeclaration(
auto body = child_results->NextAs<Statement*>();
CheckNotDeferredStatement(body);
Declaration* result = MakeNode<SpecializationDeclaration>(
- std::move(name), std::move(generic_parameters), std::move(parameters),
- return_type, std::move(labels), body);
+ transitioning, std::move(name), std::move(generic_parameters),
+ std::move(parameters), return_type, std::move(labels), body);
return ParseResult{result};
}
@@ -817,19 +841,16 @@ base::Optional<ParseResult> MakeExternalBuiltin(
ParseResultIterator* child_results) {
auto transitioning = child_results->NextAs<bool>();
auto js_linkage = child_results->NextAs<bool>();
- auto name = child_results->NextAs<std::string>();
+ auto name = child_results->NextAs<Identifier*>();
auto generic_parameters = child_results->NextAs<GenericParameters>();
LintGenericParameters(generic_parameters);
auto args = child_results->NextAs<ParameterList>();
auto return_type = child_results->NextAs<TypeExpression*>();
- BuiltinDeclaration* builtin = MakeNode<ExternalBuiltinDeclaration>(
+ Declaration* result = MakeNode<ExternalBuiltinDeclaration>(
transitioning, js_linkage, name, args, return_type);
- Declaration* result;
- if (generic_parameters.empty()) {
- result = MakeNode<StandardDeclaration>(builtin, base::nullopt);
- } else {
- result = MakeNode<GenericDeclaration>(builtin, generic_parameters);
+ if (!generic_parameters.empty()) {
+ Error("External builtins cannot be generic.");
}
return ParseResult{result};
}
@@ -837,12 +858,11 @@ base::Optional<ParseResult> MakeExternalBuiltin(
base::Optional<ParseResult> MakeExternalRuntime(
ParseResultIterator* child_results) {
auto transitioning = child_results->NextAs<bool>();
- auto name = child_results->NextAs<std::string>();
+ auto name = child_results->NextAs<Identifier*>();
auto args = child_results->NextAs<ParameterList>();
auto return_type = child_results->NextAs<TypeExpression*>();
- ExternalRuntimeDeclaration* runtime = MakeNode<ExternalRuntimeDeclaration>(
+ Declaration* result = MakeNode<ExternalRuntimeDeclaration>(
transitioning, name, args, return_type);
- Declaration* result = MakeNode<StandardDeclaration>(runtime, base::nullopt);
return ParseResult{result};
}
@@ -879,7 +899,11 @@ base::Optional<ParseResult> MakeFunctionTypeExpression(
base::Optional<ParseResult> MakeReferenceTypeExpression(
ParseResultIterator* child_results) {
auto referenced_type = child_results->NextAs<TypeExpression*>();
- TypeExpression* result = MakeNode<ReferenceTypeExpression>(referenced_type);
+ std::vector<std::string> namespace_qualification{
+ TORQUE_INTERNAL_NAMESPACE_STRING};
+ std::vector<TypeExpression*> generic_arguments{referenced_type};
+ TypeExpression* result = MakeNode<BasicTypeExpression>(
+ namespace_qualification, REFERENCE_TYPE_STRING, generic_arguments);
return ParseResult{result};
}
@@ -1141,7 +1165,7 @@ base::Optional<ParseResult> MakeCatchBlock(ParseResultIterator* child_results) {
ParameterList parameters;
parameters.names.push_back(MakeNode<Identifier>(variable));
parameters.types.push_back(MakeNode<BasicTypeExpression>(
- std::vector<std::string>{}, "Object", std::vector<TypeExpression*>{}));
+ std::vector<std::string>{}, "JSAny", std::vector<TypeExpression*>{}));
parameters.has_varargs = false;
LabelBlock* result = MakeNode<LabelBlock>(
MakeNode<Identifier>(kCatchLabelName), std::move(parameters), body);
@@ -1327,22 +1351,22 @@ base::Optional<ParseResult> MakeNameAndExpressionFromExpression(
ReportError("Constructor parameters need to be named.");
}
-base::Optional<ParseResult> MakeConditionalAnnotation(
- ParseResultIterator* child_results) {
- auto type_str = child_results->NextAs<Identifier*>()->value;
- DCHECK(type_str == "@if" || type_str == "@ifnot");
- ConditionalAnnotationType type = type_str == "@if"
- ? ConditionalAnnotationType::kPositive
- : ConditionalAnnotationType::kNegative;
- auto condition = child_results->NextAs<std::string>();
- return ParseResult{ConditionalAnnotation{condition, type}};
+base::Optional<ParseResult> MakeAnnotation(ParseResultIterator* child_results) {
+ return ParseResult{
+ Annotation{child_results->NextAs<Identifier*>(),
+ child_results->NextAs<base::Optional<std::string>>()}};
}
base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
- auto conditional =
- child_results->NextAs<base::Optional<ConditionalAnnotation>>();
- AnnotationSet annotations(child_results, {"@noVerifier"});
+ AnnotationSet annotations(child_results, {"@noVerifier"}, {"@if", "@ifnot"});
bool generate_verify = !annotations.Contains("@noVerifier");
+ std::vector<ConditionalAnnotation> conditions;
+ for (const std::string& condition : annotations.GetParams("@if")) {
+ conditions.push_back({condition, ConditionalAnnotationType::kPositive});
+ }
+ for (const std::string& condition : annotations.GetParams("@ifnot")) {
+ conditions.push_back({condition, ConditionalAnnotationType::kNegative});
+ }
auto weak = child_results->NextAs<bool>();
auto const_qualified = child_results->NextAs<bool>();
auto name = child_results->NextAs<Identifier*>();
@@ -1350,7 +1374,7 @@ base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
auto type = child_results->NextAs<TypeExpression*>();
return ParseResult{ClassFieldExpression{{name, type},
index,
- conditional,
+ std::move(conditions),
weak,
const_qualified,
generate_verify}};
@@ -1479,15 +1503,12 @@ struct TorqueGrammar : Grammar {
Symbol name = {Rule({&identifier}, MakeIdentifier)};
// Result: Identifier*
- Symbol annotation = {
+ Symbol annotationName = {
Rule({Pattern(MatchAnnotation)}, MakeIdentifierFromMatchedInput)};
- // Result: std::vector<Identifier*>
- Symbol* annotations = List<Identifier*>(&annotation);
-
// Result: std::string
Symbol intrinsicName = {
- Rule({Pattern(MatchIntrinsicName)}, YieldMatchedInput)};
+ Rule({Pattern(MatchIntrinsicName)}, MakeIdentifierFromMatchedInput)};
// Result: std::string
Symbol stringLiteral = {
@@ -1501,6 +1522,22 @@ struct TorqueGrammar : Grammar {
Rule({Pattern(MatchDecimalLiteral)}, YieldMatchedInput),
Rule({Pattern(MatchHexLiteral)}, YieldMatchedInput)};
+ // Result: std::string
+ Symbol annotationParameter = {Rule({&identifier}), Rule({&decimalLiteral}),
+ Rule({&externalString})};
+
+ // Result: std::string
+ Symbol annotationParameters = {
+ Rule({Token("("), &annotationParameter, Token(")")})};
+
+ // Result: Annotation
+ Symbol annotation = {
+ Rule({&annotationName, Optional<std::string>(&annotationParameters)},
+ MakeAnnotation)};
+
+ // Result: std::vector<Annotation>
+ Symbol* annotations = List<Annotation>(&annotation);
+
// Result: TypeList
Symbol* typeList = List<TypeExpression*>(&type, Token(","));
@@ -1578,14 +1615,8 @@ struct TorqueGrammar : Grammar {
Symbol* optionalArraySpecifier =
Optional<std::string>(Sequence({Token("["), &identifier, Token("]")}));
- // Result: ConditionalAnnotation
- Symbol conditionalAnnotation = {
- Rule({OneOf({"@if", "@ifnot"}), Token("("), &identifier, Token(")")},
- MakeConditionalAnnotation)};
-
Symbol classField = {
- Rule({Optional<ConditionalAnnotation>(&conditionalAnnotation),
- annotations, CheckIf(Token("weak")), CheckIf(Token("const")), &name,
+ Rule({annotations, CheckIf(Token("weak")), CheckIf(Token("const")), &name,
optionalArraySpecifier, Token(":"), &type, Token(";")},
MakeClassField)};
@@ -1857,8 +1888,8 @@ struct TorqueGrammar : Grammar {
Symbol method = {Rule(
{CheckIf(Token("transitioning")),
Optional<std::string>(Sequence({Token("operator"), &externalString})),
- &identifier, &parameterListNoVararg, &optionalReturnType,
- optionalLabelList, &block},
+ &name, &parameterListNoVararg, &optionalReturnType, optionalLabelList,
+ &block},
MakeMethodDeclaration)};
// Result: std::vector<Declaration*>
@@ -1900,34 +1931,34 @@ struct TorqueGrammar : Grammar {
Optional<std::string>(
Sequence({Token("operator"), &externalString})),
Token("macro"),
- Optional<std::string>(Sequence({&identifier, Token("::")})),
- &identifier, TryOrDefault<GenericParameters>(&genericParameters),
+ Optional<std::string>(Sequence({&identifier, Token("::")})), &name,
+ TryOrDefault<GenericParameters>(&genericParameters),
&typeListMaybeVarArgs, &optionalReturnType, optionalLabelList,
Token(";")},
AsSingletonVector<Declaration*, MakeExternalMacro>()),
Rule({Token("extern"), CheckIf(Token("transitioning")),
- CheckIf(Token("javascript")), Token("builtin"), &identifier,
+ CheckIf(Token("javascript")), Token("builtin"), &name,
TryOrDefault<GenericParameters>(&genericParameters),
&typeListMaybeVarArgs, &optionalReturnType, Token(";")},
AsSingletonVector<Declaration*, MakeExternalBuiltin>()),
- Rule(
- {Token("extern"), CheckIf(Token("transitioning")), Token("runtime"),
- &identifier, &typeListMaybeVarArgs, &optionalReturnType, Token(";")},
- AsSingletonVector<Declaration*, MakeExternalRuntime>()),
+ Rule({Token("extern"), CheckIf(Token("transitioning")), Token("runtime"),
+ &name, &typeListMaybeVarArgs, &optionalReturnType, Token(";")},
+ AsSingletonVector<Declaration*, MakeExternalRuntime>()),
Rule({CheckIf(Token("@export")), CheckIf(Token("transitioning")),
Optional<std::string>(
Sequence({Token("operator"), &externalString})),
- Token("macro"), &identifier,
+ Token("macro"), &name,
TryOrDefault<GenericParameters>(&genericParameters),
&parameterListNoVararg, &optionalReturnType, optionalLabelList,
&optionalBody},
AsSingletonVector<Declaration*, MakeTorqueMacroDeclaration>()),
Rule({CheckIf(Token("transitioning")), CheckIf(Token("javascript")),
- Token("builtin"), &identifier,
+ Token("builtin"), &name,
TryOrDefault<GenericParameters>(&genericParameters),
&parameterListAllowVararg, &optionalReturnType, &optionalBody},
AsSingletonVector<Declaration*, MakeTorqueBuiltinDeclaration>()),
- Rule({&name, &genericSpecializationTypeList, &parameterListAllowVararg,
+ Rule({CheckIf(Token("transitioning")), &name,
+ &genericSpecializationTypeList, &parameterListAllowVararg,
&optionalReturnType, optionalLabelList, &block},
AsSingletonVector<Declaration*, MakeSpecializationDeclaration>()),
Rule({Token("#include"), &externalString},
diff --git a/deps/v8/src/torque/torque.cc b/deps/v8/src/torque/torque.cc
index e759ce613c..ad7551f8aa 100644
--- a/deps/v8/src/torque/torque.cc
+++ b/deps/v8/src/torque/torque.cc
@@ -19,19 +19,24 @@ std::string ErrorPrefixFor(TorqueMessage::Kind kind) {
}
int WrappedMain(int argc, const char** argv) {
- std::string output_directory;
- std::string v8_root;
+ TorqueCompilerOptions options;
+ options.collect_language_server_data = false;
+ options.force_assert_statements = false;
+
std::vector<std::string> files;
for (int i = 1; i < argc; ++i) {
// Check for options
- if (std::string(argv[i]) == "-o") {
- output_directory = argv[++i];
- } else if (std::string(argv[i]) == "-v8-root") {
- v8_root = std::string(argv[++i]);
+ const std::string argument(argv[i]);
+ if (argument == "-o") {
+ options.output_directory = argv[++i];
+ } else if (argument == "-v8-root") {
+ options.v8_root = std::string(argv[++i]);
+ } else if (argument == "-m32") {
+ options.force_32bit_output = true;
} else {
// Otherwise it's a .tq file. Remember it for compilation.
- files.emplace_back(argv[i]);
+ files.emplace_back(std::move(argument));
if (!StringEndsWith(files.back(), ".tq")) {
std::cerr << "Unexpected command-line argument \"" << files.back()
<< "\", expected a .tq file.\n";
@@ -40,12 +45,6 @@ int WrappedMain(int argc, const char** argv) {
}
}
- TorqueCompilerOptions options;
- options.output_directory = std::move(output_directory);
- options.v8_root = std::move(v8_root);
- options.collect_language_server_data = false;
- options.force_assert_statements = false;
-
TorqueCompilerResult result = CompileTorque(files, options);
// PositionAsString requires the SourceFileMap to be set to
diff --git a/deps/v8/src/torque/type-inference.cc b/deps/v8/src/torque/type-inference.cc
new file mode 100644
index 0000000000..abd875f4f6
--- /dev/null
+++ b/deps/v8/src/torque/type-inference.cc
@@ -0,0 +1,121 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/torque/type-inference.h"
+
+namespace v8 {
+namespace internal {
+namespace torque {
+
+TypeArgumentInference::TypeArgumentInference(
+ const NameVector& type_parameters,
+ const TypeVector& explicit_type_arguments,
+ const std::vector<TypeExpression*>& term_parameters,
+ const TypeVector& term_argument_types)
+ : num_explicit_(explicit_type_arguments.size()),
+ type_parameter_from_name_(type_parameters.size()),
+ inferred_(type_parameters.size()) {
+ if (num_explicit_ > type_parameters.size()) {
+ Fail("more explicit type arguments than expected");
+ return;
+ }
+ if (term_parameters.size() != term_argument_types.size()) {
+ Fail("number of term parameters does not match number of term arguments!");
+ return;
+ }
+
+ for (size_t i = 0; i < type_parameters.size(); i++) {
+ type_parameter_from_name_[type_parameters[i]->value] = i;
+ }
+ for (size_t i = 0; i < num_explicit_; i++) {
+ inferred_[i] = {explicit_type_arguments[i]};
+ }
+
+ for (size_t i = 0; i < term_parameters.size(); i++) {
+ Match(term_parameters[i], term_argument_types[i]);
+ if (HasFailed()) return;
+ }
+
+ for (size_t i = 0; i < type_parameters.size(); i++) {
+ if (!inferred_[i]) {
+ Fail("failed to infer arguments for all type parameters");
+ return;
+ }
+ }
+}
+
+TypeVector TypeArgumentInference::GetResult() const {
+ CHECK(!HasFailed());
+ TypeVector result(inferred_.size());
+ std::transform(
+ inferred_.begin(), inferred_.end(), result.begin(),
+ [](base::Optional<const Type*> maybe_type) { return *maybe_type; });
+ return result;
+}
+
+void TypeArgumentInference::Match(TypeExpression* parameter,
+ const Type* argument_type) {
+ if (BasicTypeExpression* basic =
+ BasicTypeExpression::DynamicCast(parameter)) {
+ // If the parameter is referring to one of the type parameters, substitute
+ if (basic->namespace_qualification.empty() && !basic->is_constexpr) {
+ auto result = type_parameter_from_name_.find(basic->name);
+ if (result != type_parameter_from_name_.end()) {
+ size_t type_parameter_index = result->second;
+ if (type_parameter_index < num_explicit_) {
+ return;
+ }
+ base::Optional<const Type*>& maybe_inferred =
+ inferred_[type_parameter_index];
+ if (maybe_inferred && *maybe_inferred != argument_type) {
+ Fail("found conflicting types for generic parameter");
+ } else {
+ inferred_[type_parameter_index] = {argument_type};
+ }
+ return;
+ }
+ }
+ // Try to recurse in case of generic types
+ if (!basic->generic_arguments.empty()) {
+ auto* argument_struct_type = StructType::DynamicCast(argument_type);
+ if (argument_struct_type) {
+ MatchGeneric(basic, argument_struct_type);
+ }
+ }
+ // NOTE: We could also check whether ground parameter types match the
+ // argument types, but we are only interested in inferring type arguments
+ // here
+ } else {
+ // TODO(gsps): Perform inference on function and union types
+ }
+}
+
+void TypeArgumentInference::MatchGeneric(BasicTypeExpression* parameter,
+ const StructType* argument_type) {
+ QualifiedName qualified_name{parameter->namespace_qualification,
+ parameter->name};
+ GenericStructType* generic_struct =
+ Declarations::LookupUniqueGenericStructType(qualified_name);
+ auto& specialized_from = argument_type->GetSpecializedFrom();
+ if (!specialized_from || specialized_from->generic != generic_struct) {
+ return Fail("found conflicting generic type constructors");
+ }
+ auto& parameters = parameter->generic_arguments;
+ auto& argument_types = specialized_from->specialized_types;
+ if (parameters.size() != argument_types.size()) {
+ Error(
+ "cannot infer types from generic-struct-typed parameter with "
+ "incompatible number of arguments")
+ .Position(parameter->pos)
+ .Throw();
+ }
+ for (size_t i = 0; i < parameters.size(); i++) {
+ Match(parameters[i], argument_types[i]);
+ if (HasFailed()) return;
+ }
+}
+
+} // namespace torque
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/torque/type-inference.h b/deps/v8/src/torque/type-inference.h
new file mode 100644
index 0000000000..671d68cce5
--- /dev/null
+++ b/deps/v8/src/torque/type-inference.h
@@ -0,0 +1,84 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_TORQUE_TYPE_INFERENCE_H_
+#define V8_TORQUE_TYPE_INFERENCE_H_
+
+#include <string>
+#include <unordered_map>
+
+#include "src/base/optional.h"
+#include "src/torque/ast.h"
+#include "src/torque/declarations.h"
+#include "src/torque/types.h"
+
+namespace v8 {
+namespace internal {
+namespace torque {
+
+// Type argument inference computes a potential instantiation of a generic
+// callable given some concrete argument types. As an example, consider the
+// generic macro
+//
+// macro Pick<T: type>(x: T, y: T): T
+//
+// along with a given call site, such as
+//
+// Pick(1, 2);
+//
+// The inference proceeds by matching the term argument types (`constexpr
+// int31`, in case of `1` and `2`) against the formal parameter types (`T` in
+// both cases). During this matching we discover that `T` must equal `constexpr
+// int31`.
+//
+// The inference will not perform any comprehensive type checking of its own,
+// but *does* fail if type parameters cannot be soundly instantiated given the
+// call site. For instance, for the following call site
+//
+// const aSmi: Smi = ...;
+// Pick(1, aSmi); // inference fails
+//
+// inference would fail, since `constexpr int31` is distinct from `Smi`. To
+// allow for implicit conversions to be tried in a separate step after type
+// argument inference, a number of type arguments may be given explicitly:
+//
+// Pick<Smi>(1, aSmi); // inference succeeds (doing nothing)
+//
+// In the above case the inference simply ignores inconsistent constraints on
+// `T`. Similarly, we ignore all constraints arising from formal parameters
+// that are function- or union-typed.
+//
+// Finally, note that term parameters are passed as type expressions, since
+// we have no way of expressing a reference to type parameter as a Type. These
+// type expressions are resolved during matching, so TypeArgumentInference
+// should be instantiated in the appropriate scope.
+class TypeArgumentInference {
+ public:
+ TypeArgumentInference(const NameVector& type_parameters,
+ const TypeVector& explicit_type_arguments,
+ const std::vector<TypeExpression*>& term_parameters,
+ const TypeVector& term_argument_types);
+
+ bool HasFailed() const { return failure_reason_.has_value(); }
+ const char* GetFailureReason() { return *failure_reason_; }
+ TypeVector GetResult() const;
+
+ private:
+ void Fail(const char* reason) { failure_reason_ = {reason}; }
+
+ void Match(TypeExpression* parameter, const Type* argument_type);
+ void MatchGeneric(BasicTypeExpression* parameter,
+ const StructType* argument_type);
+
+ size_t num_explicit_;
+ std::unordered_map<std::string, size_t> type_parameter_from_name_;
+ std::vector<base::Optional<const Type*>> inferred_;
+ base::Optional<const char*> failure_reason_;
+};
+
+} // namespace torque
+} // namespace internal
+} // namespace v8
+
+#endif // V8_TORQUE_TYPE_INFERENCE_H_
diff --git a/deps/v8/src/torque/type-oracle.cc b/deps/v8/src/torque/type-oracle.cc
index 47331543fc..c7e11c2165 100644
--- a/deps/v8/src/torque/type-oracle.cc
+++ b/deps/v8/src/torque/type-oracle.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "src/torque/type-oracle.h"
+#include "src/torque/type-visitor.h"
namespace v8 {
namespace internal {
@@ -23,6 +24,28 @@ void TypeOracle::FinalizeAggregateTypes() {
}
}
+// static
+const StructType* TypeOracle::GetGenericStructTypeInstance(
+ GenericStructType* generic_struct, TypeVector arg_types) {
+ auto& params = generic_struct->generic_parameters();
+ auto& specializations = generic_struct->specializations();
+
+ if (params.size() != arg_types.size()) {
+ ReportError("Generic struct takes ", params.size(), " parameters, but ",
+ arg_types.size(), " were given");
+ }
+
+ if (auto specialization = specializations.Get(arg_types)) {
+ return *specialization;
+ } else {
+ CurrentScope::Scope generic_scope(generic_struct->ParentScope());
+ auto struct_type = TypeVisitor::ComputeType(generic_struct->declaration(),
+ {{generic_struct, arg_types}});
+ specializations.Add(arg_types, struct_type);
+ return struct_type;
+ }
+}
+
} // namespace torque
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/torque/type-oracle.h b/deps/v8/src/torque/type-oracle.h
index 405cb41e75..643c78c030 100644
--- a/deps/v8/src/torque/type-oracle.h
+++ b/deps/v8/src/torque/type-oracle.h
@@ -30,9 +30,13 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return result;
}
- static StructType* GetStructType(const std::string& name) {
- StructType* result = new StructType(CurrentNamespace(), name);
+ static StructType* GetStructType(
+ const StructDeclaration* decl,
+ StructType::MaybeSpecializationKey specialized_from) {
+ Namespace* nspace = new Namespace(STRUCT_NAMESPACE_STRING);
+ StructType* result = new StructType(nspace, decl, specialized_from);
Get().aggregate_types_.push_back(std::unique_ptr<StructType>(result));
+ Get().struct_namespaces_.push_back(std::unique_ptr<Namespace>(nspace));
return result;
}
@@ -60,8 +64,26 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return result;
}
- static const ReferenceType* GetReferenceType(const Type* referenced_type) {
- return Get().reference_types_.Add(ReferenceType(referenced_type));
+ static const StructType* GetGenericStructTypeInstance(
+ GenericStructType* generic_struct, TypeVector arg_types);
+
+ static GenericStructType* GetReferenceGeneric() {
+ return Declarations::LookupUniqueGenericStructType(QualifiedName(
+ {TORQUE_INTERNAL_NAMESPACE_STRING}, REFERENCE_TYPE_STRING));
+ }
+
+ static GenericStructType* GetSliceGeneric() {
+ return Declarations::LookupUniqueGenericStructType(
+ QualifiedName({TORQUE_INTERNAL_NAMESPACE_STRING}, SLICE_TYPE_STRING));
+ }
+
+ static const StructType* GetReferenceType(const Type* referenced_type) {
+ return GetGenericStructTypeInstance(GetReferenceGeneric(),
+ {referenced_type});
+ }
+
+ static const StructType* GetSliceType(const Type* referenced_type) {
+ return GetGenericStructTypeInstance(GetSliceGeneric(), {referenced_type});
}
static const std::vector<const BuiltinPointerType*>&
@@ -131,6 +153,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return Get().GetBuiltinType(HEAP_OBJECT_TYPE_STRING);
}
+ static const Type* GetJSAnyType() {
+ return Get().GetBuiltinType(JSANY_TYPE_STRING);
+ }
+
static const Type* GetJSObjectType() {
return Get().GetBuiltinType(JSOBJECT_TYPE_STRING);
}
@@ -245,10 +271,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
Deduplicator<BuiltinPointerType> function_pointer_types_;
std::vector<const BuiltinPointerType*> all_builtin_pointer_types_;
Deduplicator<UnionType> union_types_;
- Deduplicator<ReferenceType> reference_types_;
std::vector<std::unique_ptr<Type>> nominal_types_;
std::vector<std::unique_ptr<AggregateType>> aggregate_types_;
std::vector<std::unique_ptr<Type>> top_types_;
+ std::vector<std::unique_ptr<Namespace>> struct_namespaces_;
};
} // namespace torque
diff --git a/deps/v8/src/torque/type-visitor.cc b/deps/v8/src/torque/type-visitor.cc
index 37be0df006..9b5c96ee40 100644
--- a/deps/v8/src/torque/type-visitor.cc
+++ b/deps/v8/src/torque/type-visitor.cc
@@ -8,6 +8,7 @@
#include "src/torque/declarable.h"
#include "src/torque/global-context.h"
#include "src/torque/server-data.h"
+#include "src/torque/type-inference.h"
#include "src/torque/type-oracle.h"
namespace v8 {
@@ -91,49 +92,47 @@ void DeclareMethods(AggregateType* container_type,
const std::vector<Declaration*>& methods) {
for (auto declaration : methods) {
CurrentSourcePosition::Scope pos_scope(declaration->pos);
- StandardDeclaration* standard_declaration =
- StandardDeclaration::DynamicCast(declaration);
- DCHECK(standard_declaration);
TorqueMacroDeclaration* method =
- TorqueMacroDeclaration::DynamicCast(standard_declaration->callable);
- Signature signature = TypeVisitor::MakeSignature(method->signature.get());
+ TorqueMacroDeclaration::DynamicCast(declaration);
+ Signature signature = TypeVisitor::MakeSignature(method);
signature.parameter_names.insert(
signature.parameter_names.begin() + signature.implicit_count,
MakeNode<Identifier>(kThisParameterName));
- Statement* body = *(standard_declaration->body);
- std::string method_name(method->name);
+ Statement* body = *(method->body);
+ const std::string& method_name(method->name->value);
signature.parameter_types.types.insert(
signature.parameter_types.types.begin() + signature.implicit_count,
container_type);
- Declarations::CreateMethod(container_type, method_name, signature, false,
- body);
+ Declarations::CreateMethod(container_type, method_name, signature, body);
}
}
-namespace {
-std::string ComputeStructName(StructDeclaration* decl) {
- TypeVector args;
- if (decl->IsGeneric()) {
- args.resize(decl->generic_parameters.size());
- std::transform(
- decl->generic_parameters.begin(), decl->generic_parameters.end(),
- args.begin(), [](Identifier* parameter) {
- return Declarations::LookupTypeAlias(QualifiedName(parameter->value))
- ->type();
- });
+const StructType* TypeVisitor::ComputeType(
+ StructDeclaration* decl,
+ StructType::MaybeSpecializationKey specialized_from) {
+ StructType* struct_type = TypeOracle::GetStructType(decl, specialized_from);
+ CurrentScope::Scope struct_namespace_scope(struct_type->nspace());
+ CurrentSourcePosition::Scope position_activator(decl->pos);
+
+ if (specialized_from) {
+ auto& params = specialized_from->generic->generic_parameters();
+ auto arg_types_iterator = specialized_from->specialized_types.begin();
+ for (auto param : params) {
+ TypeAlias* alias = Declarations::DeclareType(param, *arg_types_iterator);
+ alias->SetIsUserDefined(false);
+ arg_types_iterator++;
+ }
}
- return StructType::ComputeName(decl->name->value, args);
-}
-} // namespace
-const StructType* TypeVisitor::ComputeType(StructDeclaration* decl) {
- CurrentSourcePosition::Scope position_activator(decl->pos);
- StructType* struct_type = TypeOracle::GetStructType(ComputeStructName(decl));
size_t offset = 0;
for (auto& field : decl->fields) {
CurrentSourcePosition::Scope position_activator(
field.name_and_type.type->pos);
const Type* field_type = TypeVisitor::ComputeType(field.name_and_type.type);
+ if (field_type->IsConstexpr()) {
+ ReportError("struct field \"", field.name_and_type.name->value,
+ "\" carries constexpr type \"", *field_type, "\"");
+ }
struct_type->RegisterField({field.name_and_type.name->pos,
struct_type,
base::nullopt,
@@ -144,7 +143,6 @@ const StructType* TypeVisitor::ComputeType(StructDeclaration* decl) {
false});
offset += LoweredSlotCount(field_type);
}
- DeclareMethods(struct_type, decl->methods);
return struct_type;
}
@@ -214,34 +212,8 @@ const Type* TypeVisitor::ComputeType(TypeExpression* type_expression) {
} else {
auto* generic_struct =
Declarations::LookupUniqueGenericStructType(qualified_name);
- auto& params = generic_struct->generic_parameters();
- auto& specializations = generic_struct->specializations();
- if (params.size() != args.size()) {
- ReportError("Generic struct takes ", params.size(),
- " parameters, but only ", args.size(), " were given");
- }
-
- std::vector<const Type*> arg_types = ComputeTypeVector(args);
- if (auto specialization = specializations.Get(arg_types)) {
- type = *specialization;
- } else {
- CurrentScope::Scope generic_scope(generic_struct->ParentScope());
- // Create a temporary fake-namespace just to temporarily declare the
- // specialization aliases for the generic types to create a signature.
- Namespace tmp_namespace("_tmp");
- CurrentScope::Scope tmp_namespace_scope(&tmp_namespace);
- auto arg_types_iterator = arg_types.begin();
- for (auto param : params) {
- TypeAlias* alias =
- Declarations::DeclareType(param, *arg_types_iterator);
- alias->SetIsUserDefined(false);
- arg_types_iterator++;
- }
-
- auto struct_type = ComputeType(generic_struct->declaration());
- specializations.Add(arg_types, struct_type);
- type = struct_type;
- }
+ type = TypeOracle::GetGenericStructTypeInstance(generic_struct,
+ ComputeTypeVector(args));
pos = generic_struct->declaration()->name->pos;
}
@@ -254,10 +226,6 @@ const Type* TypeVisitor::ComputeType(TypeExpression* type_expression) {
UnionTypeExpression::DynamicCast(type_expression)) {
return TypeOracle::GetUnionType(ComputeType(union_type->a),
ComputeType(union_type->b));
- } else if (auto* reference_type =
- ReferenceTypeExpression::DynamicCast(type_expression)) {
- return TypeOracle::GetReferenceType(
- ComputeType(reference_type->referenced_type));
} else {
auto* function_type_exp = FunctionTypeExpression::cast(type_expression);
TypeVector argument_types;
@@ -269,22 +237,23 @@ const Type* TypeVisitor::ComputeType(TypeExpression* type_expression) {
}
}
-Signature TypeVisitor::MakeSignature(const CallableNodeSignature* signature) {
+Signature TypeVisitor::MakeSignature(const CallableDeclaration* declaration) {
LabelDeclarationVector definition_vector;
- for (const auto& label : signature->labels) {
+ for (const auto& label : declaration->labels) {
LabelDeclaration def = {label.name, ComputeTypeVector(label.types)};
definition_vector.push_back(def);
}
base::Optional<std::string> arguments_variable;
- if (signature->parameters.has_varargs)
- arguments_variable = signature->parameters.arguments_variable;
- Signature result{signature->parameters.names,
+ if (declaration->parameters.has_varargs)
+ arguments_variable = declaration->parameters.arguments_variable;
+ Signature result{declaration->parameters.names,
arguments_variable,
- {ComputeTypeVector(signature->parameters.types),
- signature->parameters.has_varargs},
- signature->parameters.implicit_count,
- ComputeType(signature->return_type),
- definition_vector};
+ {ComputeTypeVector(declaration->parameters.types),
+ declaration->parameters.has_varargs},
+ declaration->parameters.implicit_count,
+ ComputeType(declaration->return_type),
+ definition_vector,
+ declaration->transitioning};
return result;
}
@@ -345,7 +314,8 @@ void TypeVisitor::VisitClassFieldsAndMethods(
std::string machine_type;
std::tie(field_size, size_string) = field.GetFieldSizeInformation();
// Our allocations don't support alignments beyond kTaggedSize.
- size_t alignment = std::min(size_t{kTaggedSize}, field_size);
+ size_t alignment = std::min(
+ static_cast<size_t>(TargetArchitecture::TaggedSize()), field_size);
if (alignment > 0 && class_offset % alignment != 0) {
ReportError("field ", field_expression.name_and_type.name,
" at offset ", class_offset, " is not ", alignment,
@@ -359,6 +329,60 @@ void TypeVisitor::VisitClassFieldsAndMethods(
DeclareMethods(class_type, class_declaration->methods);
}
+void TypeVisitor::VisitStructMethods(
+ StructType* struct_type, const StructDeclaration* struct_declaration) {
+ DeclareMethods(struct_type, struct_declaration->methods);
+}
+
+const StructType* TypeVisitor::ComputeTypeForStructExpression(
+ TypeExpression* type_expression,
+ const std::vector<const Type*>& term_argument_types) {
+ auto* basic = BasicTypeExpression::DynamicCast(type_expression);
+ if (!basic) {
+ ReportError("expected basic type expression referring to struct");
+ }
+
+ QualifiedName qualified_name{basic->namespace_qualification, basic->name};
+ base::Optional<GenericStructType*> maybe_generic_struct =
+ Declarations::TryLookupGenericStructType(qualified_name);
+
+ // Compute types of non-generic structs as usual
+ if (!maybe_generic_struct) {
+ const Type* type = ComputeType(type_expression);
+ const StructType* struct_type = StructType::DynamicCast(type);
+ if (!struct_type) {
+ ReportError(*type, " is not a struct, but used like one");
+ }
+ return struct_type;
+ }
+
+ auto generic_struct = *maybe_generic_struct;
+ auto explicit_type_arguments = ComputeTypeVector(basic->generic_arguments);
+
+ std::vector<TypeExpression*> term_parameters;
+ auto& fields = generic_struct->declaration()->fields;
+ term_parameters.reserve(fields.size());
+ for (auto& field : fields) {
+ term_parameters.push_back(field.name_and_type.type);
+ }
+
+ CurrentScope::Scope generic_scope(generic_struct->ParentScope());
+ TypeArgumentInference inference(
+ generic_struct->declaration()->generic_parameters,
+ explicit_type_arguments, term_parameters, term_argument_types);
+
+ if (inference.HasFailed()) {
+ ReportError("failed to infer type arguments for struct ", basic->name,
+ " initialization: ", inference.GetFailureReason());
+ }
+ if (GlobalContext::collect_language_server_data()) {
+ LanguageServerData::AddDefinition(type_expression->pos,
+ generic_struct->declaration()->name->pos);
+ }
+ return TypeOracle::GetGenericStructTypeInstance(generic_struct,
+ inference.GetResult());
+}
+
} // namespace torque
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/torque/type-visitor.h b/deps/v8/src/torque/type-visitor.h
index 93de02b860..cafd752cbf 100644
--- a/deps/v8/src/torque/type-visitor.h
+++ b/deps/v8/src/torque/type-visitor.h
@@ -27,14 +27,22 @@ class TypeVisitor {
static const Type* ComputeType(TypeExpression* type_expression);
static void VisitClassFieldsAndMethods(
ClassType* class_type, const ClassDeclaration* class_declaration);
- static Signature MakeSignature(const CallableNodeSignature* signature);
+ static void VisitStructMethods(StructType* struct_type,
+ const StructDeclaration* struct_declaration);
+ static Signature MakeSignature(const CallableDeclaration* declaration);
+ static const StructType* ComputeTypeForStructExpression(
+ TypeExpression* type_expression,
+ const std::vector<const Type*>& term_argument_types);
private:
friend class TypeAlias;
+ friend class TypeOracle;
static const Type* ComputeType(TypeDeclaration* decl);
static const AbstractType* ComputeType(AbstractTypeDeclaration* decl);
static const Type* ComputeType(TypeAliasDeclaration* decl);
- static const StructType* ComputeType(StructDeclaration* decl);
+ static const StructType* ComputeType(
+ StructDeclaration* decl,
+ StructType::MaybeSpecializationKey specialized_from = base::nullopt);
static const ClassType* ComputeType(ClassDeclaration* decl);
};
diff --git a/deps/v8/src/torque/types.cc b/deps/v8/src/torque/types.cc
index 37a328b1dc..fe792401f6 100644
--- a/deps/v8/src/torque/types.cc
+++ b/deps/v8/src/torque/types.cc
@@ -4,9 +4,9 @@
#include <iostream>
-#include "src/common/globals.h"
#include "src/torque/ast.h"
#include "src/torque/declarable.h"
+#include "src/torque/global-context.h"
#include "src/torque/type-oracle.h"
#include "src/torque/type-visitor.h"
#include "src/torque/types.h"
@@ -263,7 +263,7 @@ const Field& AggregateType::LookupFieldInternal(const std::string& name) const {
return parent_class->LookupField(name);
}
}
- ReportError("no field ", name, " found");
+ ReportError("no field ", name, " found in ", this->ToString());
}
const Field& AggregateType::LookupField(const std::string& name) const {
@@ -276,13 +276,14 @@ std::string StructType::GetGeneratedTypeNameImpl() const {
}
// static
-std::string StructType::ComputeName(const std::string& basename,
- const std::vector<const Type*>& args) {
- if (args.size() == 0) return basename;
+std::string StructType::ComputeName(
+ const std::string& basename,
+ StructType::MaybeSpecializationKey specialized_from) {
+ if (!specialized_from) return basename;
std::stringstream s;
s << basename << "<";
bool first = true;
- for (auto t : args) {
+ for (auto t : specialized_from->specialized_types) {
if (!first) {
s << ", ";
}
@@ -293,6 +294,43 @@ std::string StructType::ComputeName(const std::string& basename,
return s.str();
}
+std::string StructType::MangledName() const {
+ std::stringstream result;
+ // TODO(gsps): Add 'ST' as a prefix once we can control the generated type
+ // name from Torque code
+ result << decl_->name->value;
+ if (specialized_from_) {
+ for (const Type* t : specialized_from_->specialized_types) {
+ std::string arg_type_string = t->MangledName();
+ result << arg_type_string.size() << arg_type_string;
+ }
+ }
+ return result.str();
+}
+
+// static
+base::Optional<const Type*> StructType::MatchUnaryGeneric(
+ const Type* type, GenericStructType* generic) {
+ if (auto* struct_type = StructType::DynamicCast(type)) {
+ return MatchUnaryGeneric(struct_type, generic);
+ }
+ return base::nullopt;
+}
+
+// static
+base::Optional<const Type*> StructType::MatchUnaryGeneric(
+ const StructType* type, GenericStructType* generic) {
+ DCHECK_EQ(generic->generic_parameters().size(), 1);
+ if (!type->specialized_from_) {
+ return base::nullopt;
+ }
+ auto& key = type->specialized_from_.value();
+ if (key.generic != generic || key.specialized_types.size() != 1) {
+ return base::nullopt;
+ }
+ return {key.specialized_types[0]};
+}
+
std::vector<Method*> AggregateType::Methods(const std::string& name) const {
if (!is_finalized_) Finalize();
std::vector<Method*> result;
@@ -307,6 +345,17 @@ std::string StructType::ToExplicitString() const {
return result.str();
}
+void StructType::Finalize() const {
+ if (is_finalized_) return;
+ {
+ CurrentScope::Scope scope_activator(nspace());
+ CurrentSourcePosition::Scope position_activator(decl_->pos);
+ TypeVisitor::VisitStructMethods(const_cast<StructType*>(this), decl_);
+ }
+ is_finalized_ = true;
+ CheckForDuplicateFields();
+}
+
constexpr ClassFlags ClassType::kInternalFlags;
ClassType::ClassType(const Type* parent, Namespace* nspace,
@@ -380,6 +429,17 @@ void ClassType::Finalize() const {
CheckForDuplicateFields();
}
+std::vector<Field> ClassType::ComputeAllFields() const {
+ std::vector<Field> all_fields;
+ const ClassType* super_class = this->GetSuperClass();
+ if (super_class) {
+ all_fields = super_class->ComputeAllFields();
+ }
+ const std::vector<Field>& fields = this->fields();
+ all_fields.insert(all_fields.end(), fields.begin(), fields.end());
+ return all_fields;
+}
+
void ClassType::GenerateAccessors() {
// For each field, construct AST snippets that implement a CSA accessor
// function and define a corresponding '.field' operator. The
@@ -404,8 +464,7 @@ void ClassType::GenerateAccessors() {
MakeNode<ReturnStatement>(MakeNode<FieldAccessExpression>(
parameter, MakeNode<Identifier>(field.name_and_type.name)));
Declarations::DeclareMacro(load_macro_name, true, base::nullopt,
- load_signature, false, load_body, base::nullopt,
- false);
+ load_signature, load_body, base::nullopt);
// Store accessor
IdentifierExpression* value = MakeNode<IdentifierExpression>(
@@ -425,8 +484,8 @@ void ClassType::GenerateAccessors() {
parameter, MakeNode<Identifier>(field.name_and_type.name)),
value));
Declarations::DeclareMacro(store_macro_name, true, base::nullopt,
- store_signature, false, store_body,
- base::nullopt, false);
+ store_signature, store_body, base::nullopt,
+ false);
}
}
@@ -560,9 +619,6 @@ void AppendLoweredTypes(const Type* type, std::vector<const Type*>* result) {
for (const Field& field : s->fields()) {
AppendLoweredTypes(field.name_and_type.type, result);
}
- } else if (type->IsReferenceType()) {
- result->push_back(TypeOracle::GetHeapObjectType());
- result->push_back(TypeOracle::GetIntPtrType());
} else {
result->push_back(type);
}
@@ -606,10 +662,10 @@ std::tuple<size_t, std::string> Field::GetFieldSizeInformation() const {
const Type* field_type = this->name_and_type.type;
size_t field_size = 0;
if (field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
- field_size = kTaggedSize;
+ field_size = TargetArchitecture::TaggedSize();
size_string = "kTaggedSize";
} else if (field_type->IsSubtypeOf(TypeOracle::GetRawPtrType())) {
- field_size = kSystemPointerSize;
+ field_size = TargetArchitecture::RawPtrSize();
size_string = "kSystemPointerSize";
} else if (field_type->IsSubtypeOf(TypeOracle::GetVoidType())) {
field_size = 0;
@@ -636,10 +692,10 @@ std::tuple<size_t, std::string> Field::GetFieldSizeInformation() const {
field_size = kDoubleSize;
size_string = "kDoubleSize";
} else if (field_type->IsSubtypeOf(TypeOracle::GetIntPtrType())) {
- field_size = kIntptrSize;
+ field_size = TargetArchitecture::RawPtrSize();
size_string = "kIntptrSize";
} else if (field_type->IsSubtypeOf(TypeOracle::GetUIntPtrType())) {
- field_size = kIntptrSize;
+ field_size = TargetArchitecture::RawPtrSize();
size_string = "kIntptrSize";
} else {
ReportError("fields of type ", *field_type, " are not (yet) supported");
diff --git a/deps/v8/src/torque/types.h b/deps/v8/src/torque/types.h
index f6180c4250..d2198d50c3 100644
--- a/deps/v8/src/torque/types.h
+++ b/deps/v8/src/torque/types.h
@@ -25,6 +25,7 @@ class AggregateType;
struct Identifier;
class Macro;
class Method;
+class GenericStructType;
class StructType;
class ClassType;
class Value;
@@ -36,7 +37,6 @@ class TypeBase {
kTopType,
kAbstractType,
kBuiltinPointerType,
- kReferenceType,
kUnionType,
kStructType,
kClassType
@@ -47,7 +47,6 @@ class TypeBase {
bool IsBuiltinPointerType() const {
return kind() == Kind::kBuiltinPointerType;
}
- bool IsReferenceType() const { return kind() == Kind::kReferenceType; }
bool IsUnionType() const { return kind() == Kind::kUnionType; }
bool IsStructType() const { return kind() == Kind::kStructType; }
bool IsClassType() const { return kind() == Kind::kClassType; }
@@ -143,6 +142,12 @@ struct NameAndType {
std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type);
+template <typename T>
+struct SpecializationKey {
+ T* generic;
+ TypeVector specialized_types;
+};
+
struct Field {
// TODO(danno): This likely should be refactored, the handling of the types
// using the universal grab-bag utility with std::tie, as well as the
@@ -298,43 +303,6 @@ class V8_EXPORT_PRIVATE BuiltinPointerType final : public Type {
const size_t function_pointer_type_id_;
};
-class ReferenceType final : public Type {
- public:
- DECLARE_TYPE_BOILERPLATE(ReferenceType)
- std::string MangledName() const override {
- return "RT" + referenced_type_->MangledName();
- }
- std::string ToExplicitString() const override {
- std::string s = referenced_type_->ToString();
- if (s.find(' ') != std::string::npos) {
- s = "(" + s + ")";
- }
- return "&" + s;
- }
- std::string GetGeneratedTypeNameImpl() const override {
- return "CodeStubAssembler::Reference";
- }
- std::string GetGeneratedTNodeTypeNameImpl() const override { UNREACHABLE(); }
-
- const Type* referenced_type() const { return referenced_type_; }
-
- friend size_t hash_value(const ReferenceType& p) {
- return base::hash_combine(static_cast<size_t>(Kind::kReferenceType),
- p.referenced_type_);
- }
- bool operator==(const ReferenceType& other) const {
- return referenced_type_ == other.referenced_type_;
- }
-
- private:
- friend class TypeOracle;
- explicit ReferenceType(const Type* referenced_type)
- : Type(Kind::kReferenceType, nullptr),
- referenced_type_(referenced_type) {}
-
- const Type* const referenced_type_;
-};
-
bool operator<(const Type& a, const Type& b);
struct TypeLess {
bool operator()(const Type* const a, const Type* const b) const {
@@ -500,32 +468,38 @@ class AggregateType : public Type {
class StructType final : public AggregateType {
public:
DECLARE_TYPE_BOILERPLATE(StructType)
+
+ using MaybeSpecializationKey =
+ base::Optional<SpecializationKey<GenericStructType>>;
+
std::string ToExplicitString() const override;
std::string GetGeneratedTypeNameImpl() const override;
- std::string MangledName() const override {
- // TODO(gsps): Generate more readable mangled names
- std::string str(name());
- std::replace(str.begin(), str.end(), ',', '_');
- std::replace(str.begin(), str.end(), ' ', '_');
- std::replace(str.begin(), str.end(), '<', '_');
- std::replace(str.begin(), str.end(), '>', '_');
- return str;
+ std::string MangledName() const override;
+ const MaybeSpecializationKey& GetSpecializedFrom() const {
+ return specialized_from_;
}
- static std::string ComputeName(const std::string& basename,
- const std::vector<const Type*>& args);
+ static base::Optional<const Type*> MatchUnaryGeneric(
+ const Type* type, GenericStructType* generic);
+ static base::Optional<const Type*> MatchUnaryGeneric(
+ const StructType* type, GenericStructType* generic);
private:
friend class TypeOracle;
- StructType(Namespace* nspace, const std::string& name)
- : AggregateType(Kind::kStructType, nullptr, nspace, name) {}
+ StructType(Namespace* nspace, const StructDeclaration* decl,
+ MaybeSpecializationKey specialized_from = base::nullopt)
+ : AggregateType(Kind::kStructType, nullptr, nspace,
+ ComputeName(decl->name->value, specialized_from)),
+ decl_(decl),
+ specialized_from_(specialized_from) {}
- void Finalize() const override {
- is_finalized_ = true;
- CheckForDuplicateFields();
- }
+ void Finalize() const override;
+
+ static std::string ComputeName(const std::string& basename,
+ MaybeSpecializationKey specialized_from);
- const std::string& GetStructName() const { return name(); }
+ const StructDeclaration* decl_;
+ MaybeSpecializationKey specialized_from_;
};
class TypeAlias;
@@ -573,6 +547,8 @@ class ClassType final : public AggregateType {
}
void Finalize() const override;
+ std::vector<Field> ComputeAllFields() const;
+
private:
friend class TypeOracle;
friend class TypeVisitor;
@@ -668,22 +644,25 @@ using NameVector = std::vector<Identifier*>;
struct Signature {
Signature(NameVector n, base::Optional<std::string> arguments_variable,
- ParameterTypes p, size_t i, const Type* r, LabelDeclarationVector l)
+ ParameterTypes p, size_t i, const Type* r, LabelDeclarationVector l,
+ bool transitioning)
: parameter_names(std::move(n)),
arguments_variable(arguments_variable),
parameter_types(std::move(p)),
implicit_count(i),
return_type(r),
- labels(std::move(l)) {}
- Signature() : implicit_count(0), return_type(nullptr) {}
+ labels(std::move(l)),
+ transitioning(transitioning) {}
+ Signature() = default;
const TypeVector& types() const { return parameter_types.types; }
NameVector parameter_names;
base::Optional<std::string> arguments_variable;
ParameterTypes parameter_types;
- size_t implicit_count;
+ size_t implicit_count = 0;
size_t ExplicitCount() const { return types().size() - implicit_count; }
const Type* return_type;
LabelDeclarationVector labels;
+ bool transitioning = false;
bool HasSameTypesAs(
const Signature& other,
ParameterMode mode = ParameterMode::kProcessImplicit) const;
diff --git a/deps/v8/src/torque/utils.cc b/deps/v8/src/torque/utils.cc
index 244d1587db..38862b31b0 100644
--- a/deps/v8/src/torque/utils.cc
+++ b/deps/v8/src/torque/utils.cc
@@ -168,9 +168,9 @@ bool IsKeywordLikeName(const std::string& s) {
// naming convention and are those exempt from the normal type convention.
bool IsMachineType(const std::string& s) {
static const char* const machine_types[]{
- "void", "never", "int8", "uint8", "int16", "uint16",
- "int31", "uint31", "int32", "uint32", "int64", "intptr",
- "uintptr", "float32", "float64", "bool", "string", "bint"};
+ "void", "never", "int8", "uint8", "int16", "uint16", "int31",
+ "uint31", "int32", "uint32", "int64", "intptr", "uintptr", "float32",
+ "float64", "bool", "string", "bint", "char8", "char16"};
return std::find(std::begin(machine_types), std::end(machine_types), s) !=
std::end(machine_types);
@@ -292,6 +292,42 @@ void ReplaceFileContentsIfDifferent(const std::string& file_path,
}
}
+IfDefScope::IfDefScope(std::ostream& os, std::string d)
+ : os_(os), d_(std::move(d)) {
+ os_ << "#ifdef " << d_ << "\n";
+}
+IfDefScope::~IfDefScope() { os_ << "#endif // " << d_ << "\n"; }
+
+NamespaceScope::NamespaceScope(std::ostream& os,
+ std::initializer_list<std::string> namespaces)
+ : os_(os), d_(std::move(namespaces)) {
+ for (const std::string& s : d_) {
+ os_ << "namespace " << s << " {\n";
+ }
+}
+NamespaceScope::~NamespaceScope() {
+ for (auto i = d_.rbegin(); i != d_.rend(); ++i) {
+ os_ << "} // namespace " << *i << "\n";
+ }
+}
+
+IncludeGuardScope::IncludeGuardScope(std::ostream& os, std::string file_name)
+ : os_(os),
+ d_("V8_GEN_TORQUE_GENERATED_" + CapifyStringWithUnderscores(file_name) +
+ "_") {
+ os_ << "#ifndef " << d_ << "\n";
+ os_ << "#define " << d_ << "\n\n";
+}
+IncludeGuardScope::~IncludeGuardScope() { os_ << "#endif // " << d_ << "\n"; }
+
+IncludeObjectMacrosScope::IncludeObjectMacrosScope(std::ostream& os) : os_(os) {
+ os_ << "\n// Has to be the last include (doesn't have include guards):\n"
+ "#include \"src/objects/object-macros.h\"\n";
+}
+IncludeObjectMacrosScope::~IncludeObjectMacrosScope() {
+ os_ << "\n#include \"src/objects/object-macros-undef.h\"\n";
+}
+
} // namespace torque
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/torque/utils.h b/deps/v8/src/torque/utils.h
index fb4ad59f99..5f44dedea9 100644
--- a/deps/v8/src/torque/utils.h
+++ b/deps/v8/src/torque/utils.h
@@ -292,7 +292,7 @@ T* CheckNotNull(T* x) {
}
template <class T>
-inline std::ostream& operator<<(std::ostream& os, Stack<T>& t) {
+inline std::ostream& operator<<(std::ostream& os, const Stack<T>& t) {
os << "Stack{";
PrintCommaSeparatedList(os, t);
os << "}";
@@ -356,6 +356,54 @@ inline bool StringEndsWith(const std::string& s, const std::string& suffix) {
return s.substr(s.size() - suffix.size()) == suffix;
}
+class IfDefScope {
+ public:
+ IfDefScope(std::ostream& os, std::string d);
+ ~IfDefScope();
+
+ private:
+ IfDefScope(const IfDefScope&) = delete;
+ IfDefScope& operator=(const IfDefScope&) = delete;
+ std::ostream& os_;
+ std::string d_;
+};
+
+class NamespaceScope {
+ public:
+ NamespaceScope(std::ostream& os,
+ std::initializer_list<std::string> namespaces);
+ ~NamespaceScope();
+
+ private:
+ NamespaceScope(const NamespaceScope&) = delete;
+ NamespaceScope& operator=(const NamespaceScope&) = delete;
+ std::ostream& os_;
+ std::vector<std::string> d_;
+};
+
+class IncludeGuardScope {
+ public:
+ IncludeGuardScope(std::ostream& os, std::string file_name);
+ ~IncludeGuardScope();
+
+ private:
+ IncludeGuardScope(const IncludeGuardScope&) = delete;
+ IncludeGuardScope& operator=(const IncludeGuardScope&) = delete;
+ std::ostream& os_;
+ std::string d_;
+};
+
+class IncludeObjectMacrosScope {
+ public:
+ explicit IncludeObjectMacrosScope(std::ostream& os);
+ ~IncludeObjectMacrosScope();
+
+ private:
+ IncludeObjectMacrosScope(const IncludeObjectMacrosScope&) = delete;
+ IncludeObjectMacrosScope& operator=(const IncludeObjectMacrosScope&) = delete;
+ std::ostream& os_;
+};
+
} // namespace torque
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/utils/OWNERS b/deps/v8/src/utils/OWNERS
index 3f9de7e204..4750620072 100644
--- a/deps/v8/src/utils/OWNERS
+++ b/deps/v8/src/utils/OWNERS
@@ -1,3 +1,3 @@
-file://COMMON_OWNERS
+file:../../COMMON_OWNERS
# COMPONENT: Blink>JavaScript
diff --git a/deps/v8/src/utils/allocation.cc b/deps/v8/src/utils/allocation.cc
index af32e90088..f44b3c42ea 100644
--- a/deps/v8/src/utils/allocation.cc
+++ b/deps/v8/src/utils/allocation.cc
@@ -161,15 +161,14 @@ void* GetRandomMmapAddr() {
return GetPlatformPageAllocator()->GetRandomMmapAddr();
}
-void* AllocatePages(v8::PageAllocator* page_allocator, void* address,
- size_t size, size_t alignment,
- PageAllocator::Permission access) {
+void* AllocatePages(v8::PageAllocator* page_allocator, void* hint, size_t size,
+ size_t alignment, PageAllocator::Permission access) {
DCHECK_NOT_NULL(page_allocator);
- DCHECK_EQ(address, AlignedAddress(address, alignment));
+ DCHECK_EQ(hint, AlignedAddress(hint, alignment));
DCHECK(IsAligned(size, page_allocator->AllocatePageSize()));
void* result = nullptr;
for (int i = 0; i < kAllocationTries; ++i) {
- result = page_allocator->AllocatePages(address, size, alignment, access);
+ result = page_allocator->AllocatePages(hint, size, alignment, access);
if (result != nullptr) break;
size_t request_size = size + alignment - page_allocator->AllocatePageSize();
if (!OnCriticalMemoryPressure(request_size)) break;
@@ -198,16 +197,6 @@ bool SetPermissions(v8::PageAllocator* page_allocator, void* address,
return page_allocator->SetPermissions(address, size, access);
}
-byte* AllocatePage(v8::PageAllocator* page_allocator, void* address,
- size_t* allocated) {
- DCHECK_NOT_NULL(page_allocator);
- size_t page_size = page_allocator->AllocatePageSize();
- void* result = AllocatePages(page_allocator, address, page_size, page_size,
- PageAllocator::kReadWrite);
- if (result != nullptr) *allocated = page_size;
- return static_cast<byte*>(result);
-}
-
bool OnCriticalMemoryPressure(size_t length) {
// TODO(bbudge) Rework retry logic once embedders implement the more
// informative overload.
diff --git a/deps/v8/src/utils/allocation.h b/deps/v8/src/utils/allocation.h
index 2f7074acb0..4cb244172c 100644
--- a/deps/v8/src/utils/allocation.h
+++ b/deps/v8/src/utils/allocation.h
@@ -89,7 +89,7 @@ V8_EXPORT_PRIVATE v8::PageAllocator* SetPlatformPageAllocatorForTesting(
v8::PageAllocator* page_allocator);
// Gets the page granularity for AllocatePages and FreePages. Addresses returned
-// by AllocatePages and AllocatePage are aligned to this size.
+// by AllocatePages are aligned to this size.
V8_EXPORT_PRIVATE size_t AllocatePageSize();
// Gets the granularity at which the permissions and release calls can be made.
@@ -142,13 +142,6 @@ inline bool SetPermissions(v8::PageAllocator* page_allocator, Address address,
access);
}
-// Convenience function that allocates a single system page with read and write
-// permissions. |address| is a hint. Returns the base address of the memory and
-// the page size via |allocated| on success. Returns nullptr on failure.
-V8_EXPORT_PRIVATE
-V8_WARN_UNUSED_RESULT byte* AllocatePage(v8::PageAllocator* page_allocator,
- void* address, size_t* allocated);
-
// Function that may release reserved memory regions to allow failed allocations
// to succeed. |length| is the amount of memory needed. Returns |true| if memory
// could be released, false otherwise.
diff --git a/deps/v8/src/utils/utils.h b/deps/v8/src/utils/utils.h
index 20d85aae10..27d3d5ef21 100644
--- a/deps/v8/src/utils/utils.h
+++ b/deps/v8/src/utils/utils.h
@@ -20,10 +20,13 @@
#include "src/base/platform/platform.h"
#include "src/base/v8-fallthrough.h"
#include "src/common/globals.h"
-#include "src/third_party/siphash/halfsiphash.h"
#include "src/utils/allocation.h"
#include "src/utils/vector.h"
+#if defined(V8_USE_SIPHASH)
+#include "src/third_party/siphash/halfsiphash.h"
+#endif
+
#if defined(V8_OS_AIX)
#include <fenv.h> // NOLINT(build/c++11)
#endif
@@ -302,29 +305,36 @@ T SaturateSub(T a, T b) {
// ----------------------------------------------------------------------------
// BitField is a help template for encoding and decode bitfield with
// unsigned content.
+// Instantiate them via 'using', which is cheaper than deriving a new class:
+// using MyBitField = BitField<int, 4, 2, MyEnum>;
+// The BitField class is final to enforce this style over derivation.
template <class T, int shift, int size, class U = uint32_t>
-class BitField {
+class BitField final {
public:
STATIC_ASSERT(std::is_unsigned<U>::value);
STATIC_ASSERT(shift < 8 * sizeof(U)); // Otherwise shifts by {shift} are UB.
STATIC_ASSERT(size < 8 * sizeof(U)); // Otherwise shifts by {size} are UB.
STATIC_ASSERT(shift + size <= 8 * sizeof(U));
+ STATIC_ASSERT(size > 0);
using FieldType = T;
// A type U mask of bit field. To use all bits of a type U of x bits
// in a bitfield without compiler warnings we have to compute 2^x
// without using a shift count of x in the computation.
- static constexpr U kShift = shift;
- static constexpr U kSize = size;
+ static constexpr int kShift = shift;
+ static constexpr int kSize = size;
static constexpr U kMask = ((U{1} << kShift) << kSize) - (U{1} << kShift);
- static constexpr U kNext = kShift + kSize;
+ static constexpr int kLastUsedBit = kShift + kSize - 1;
static constexpr U kNumValues = U{1} << kSize;
// Value for the field with all bits set.
static constexpr T kMax = static_cast<T>(kNumValues - 1);
+ template <class T2, int size2>
+ using Next = BitField<T2, kShift + kSize, size2, U>;
+
// Tells whether the provided value fits into the bit field.
static constexpr bool is_valid(T value) {
return (static_cast<U>(value) & ~static_cast<U>(kMax)) == 0;
@@ -892,7 +902,8 @@ class BailoutId {
// Our version of printf().
V8_EXPORT_PRIVATE void PRINTF_FORMAT(1, 2) PrintF(const char* format, ...);
-void PRINTF_FORMAT(2, 3) PrintF(FILE* out, const char* format, ...);
+V8_EXPORT_PRIVATE void PRINTF_FORMAT(2, 3)
+ PrintF(FILE* out, const char* format, ...);
// Prepends the current process ID to the output.
void PRINTF_FORMAT(1, 2) PrintPID(const char* format, ...);
diff --git a/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h b/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h
index 57a157d3a7..dc68267825 100644
--- a/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h
+++ b/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64.h
@@ -210,7 +210,9 @@ void LiftoffAssembler::LoadFromInstance(Register dst, uint32_t offset,
void LiftoffAssembler::LoadTaggedPointerFromInstance(Register dst,
uint32_t offset) {
- LoadFromInstance(dst, offset, kTaggedSize);
+ DCHECK_LE(offset, kMaxInt);
+ Ldr(dst, liftoff::GetInstanceOperand());
+ LoadTaggedPointerField(dst, MemOperand(dst, offset));
}
void LiftoffAssembler::SpillInstance(Register instance) {
diff --git a/deps/v8/src/wasm/baseline/liftoff-compiler.cc b/deps/v8/src/wasm/baseline/liftoff-compiler.cc
index 7a87ae1a95..02de06763c 100644
--- a/deps/v8/src/wasm/baseline/liftoff-compiler.cc
+++ b/deps/v8/src/wasm/baseline/liftoff-compiler.cc
@@ -1606,32 +1606,35 @@ class LiftoffCompiler {
void GenerateRuntimeCall(Runtime::FunctionId runtime_function, int num_args,
Register* args) {
- auto call_descriptor = compiler::Linkage::GetRuntimeCallDescriptor(
- compilation_zone_, runtime_function, num_args,
- compiler::Operator::kNoProperties, compiler::CallDescriptor::kNoFlags);
// Currently, only one argument is supported. More arguments require some
// caution for the parallel register moves (reuse StackTransferRecipe).
DCHECK_EQ(1, num_args);
+#ifdef DEBUG
+ auto call_descriptor = compiler::Linkage::GetRuntimeCallDescriptor(
+ compilation_zone_, runtime_function, num_args,
+ compiler::Operator::kNoProperties, compiler::CallDescriptor::kNoFlags);
constexpr size_t kInputShift = 1; // Input 0 is the call target.
compiler::LinkageLocation param_loc =
call_descriptor->GetInputLocation(kInputShift);
- if (param_loc.IsRegister()) {
- Register reg = Register::from_code(param_loc.AsRegister());
- __ Move(LiftoffRegister(reg), LiftoffRegister(args[0]),
- LiftoffAssembler::kWasmIntPtr);
- } else {
- DCHECK(param_loc.IsCallerFrameSlot());
- LiftoffStackSlots stack_slots(&asm_);
- stack_slots.Add(LiftoffAssembler::VarState(LiftoffAssembler::kWasmIntPtr,
- LiftoffRegister(args[0])));
- stack_slots.Construct();
- }
+ // Runtime calls take their arguments on the stack.
+ DCHECK(param_loc.IsCallerFrameSlot());
+#endif
+ LiftoffStackSlots stack_slots(&asm_);
+ stack_slots.Add(LiftoffAssembler::VarState(LiftoffAssembler::kWasmIntPtr,
+ LiftoffRegister(args[0])));
+ stack_slots.Construct();
// Set context to "no context" for the runtime call.
__ TurboAssembler::Move(kContextRegister,
Smi::FromInt(Context::kNoContext));
Register centry = kJavaScriptCallCodeStartRegister;
- LOAD_TAGGED_PTR_INSTANCE_FIELD(centry, CEntryStub);
+ LOAD_INSTANCE_FIELD(centry, IsolateRoot, kSystemPointerSize);
+ // All cache registers are spilled and there are no register arguments.
+ LiftoffRegList pinned;
+ auto centry_id =
+ Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit;
+ __ LoadTaggedPointer(centry, centry, no_reg,
+ IsolateData::builtin_slot_offset(centry_id), pinned);
__ CallRuntimeWithCEntry(runtime_function, centry);
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
}
diff --git a/deps/v8/src/wasm/c-api.cc b/deps/v8/src/wasm/c-api.cc
index 86bba189b8..e812dd7994 100644
--- a/deps/v8/src/wasm/c-api.cc
+++ b/deps/v8/src/wasm/c-api.cc
@@ -29,6 +29,9 @@
#include "include/libplatform/libplatform.h"
#include "src/api/api-inl.h"
#include "src/compiler/wasm-compiler.h"
+#include "src/objects/js-collection-inl.h"
+#include "src/objects/managed.h"
+#include "src/objects/stack-frame-info-inl.h"
#include "src/wasm/leb-helper.h"
#include "src/wasm/module-instantiate.h"
#include "src/wasm/wasm-arguments.h"
@@ -37,6 +40,10 @@
#include "src/wasm/wasm-result.h"
#include "src/wasm/wasm-serialization.h"
+#ifdef WASM_API_DEBUG
+#error "WASM_API_DEBUG is unsupported"
+#endif
+
namespace wasm {
namespace {
@@ -98,35 +105,36 @@ Name GetNameFromWireBytes(const i::wasm::WireBytesRef& ref,
const i::Vector<const uint8_t>& wire_bytes) {
DCHECK_LE(ref.offset(), wire_bytes.length());
DCHECK_LE(ref.end_offset(), wire_bytes.length());
+ if (ref.length() == 0) return Name::make();
Name name = Name::make_uninitialized(ref.length());
std::memcpy(name.get(), wire_bytes.begin() + ref.offset(), ref.length());
return name;
}
-own<FuncType*> FunctionSigToFuncType(const i::wasm::FunctionSig* sig) {
+own<FuncType> FunctionSigToFuncType(const i::wasm::FunctionSig* sig) {
size_t param_count = sig->parameter_count();
- vec<ValType*> params = vec<ValType*>::make_uninitialized(param_count);
+ ownvec<ValType> params = ownvec<ValType>::make_uninitialized(param_count);
for (size_t i = 0; i < param_count; i++) {
params[i] = ValType::make(V8ValueTypeToWasm(sig->GetParam(i)));
}
size_t return_count = sig->return_count();
- vec<ValType*> results = vec<ValType*>::make_uninitialized(return_count);
+ ownvec<ValType> results = ownvec<ValType>::make_uninitialized(return_count);
for (size_t i = 0; i < return_count; i++) {
results[i] = ValType::make(V8ValueTypeToWasm(sig->GetReturn(i)));
}
return FuncType::make(std::move(params), std::move(results));
}
-own<ExternType*> GetImportExportType(const i::wasm::WasmModule* module,
- const i::wasm::ImportExportKindCode kind,
- const uint32_t index) {
+own<ExternType> GetImportExportType(const i::wasm::WasmModule* module,
+ const i::wasm::ImportExportKindCode kind,
+ const uint32_t index) {
switch (kind) {
case i::wasm::kExternalFunction: {
return FunctionSigToFuncType(module->functions[index].sig);
}
case i::wasm::kExternalTable: {
const i::wasm::WasmTable& table = module->tables[index];
- own<ValType*> elem = ValType::make(V8ValueTypeToWasm(table.type));
+ own<ValType> elem = ValType::make(V8ValueTypeToWasm(table.type));
Limits limits(table.initial_size,
table.has_maximum_size ? table.maximum_size : -1);
return TableType::make(std::move(elem), limits);
@@ -139,7 +147,7 @@ own<ExternType*> GetImportExportType(const i::wasm::WasmModule* module,
}
case i::wasm::kExternalGlobal: {
const i::wasm::WasmGlobal& global = module->globals[index];
- own<ValType*> content = ValType::make(V8ValueTypeToWasm(global.type));
+ own<ValType> content = ValType::make(V8ValueTypeToWasm(global.type));
Mutability mutability = global.mutability ? VAR : CONST;
return GlobalType::make(std::move(content), mutability);
}
@@ -187,14 +195,6 @@ auto seal(const typename implement<C>::type* x) -> const C* {
return reinterpret_cast<const C*>(x);
}
-#ifdef DEBUG
-template <class T>
-void vec<T>::make_data() {}
-
-template <class T>
-void vec<T>::free_data() {}
-#endif
-
///////////////////////////////////////////////////////////////////////////////
// Runtime Environment
@@ -214,8 +214,8 @@ Config::~Config() { impl(this)->~ConfigImpl(); }
void Config::operator delete(void* p) { ::operator delete(p); }
-auto Config::make() -> own<Config*> {
- return own<Config*>(seal<Config>(new (std::nothrow) ConfigImpl()));
+auto Config::make() -> own<Config> {
+ return own<Config>(seal<Config>(new (std::nothrow) ConfigImpl()));
}
// Engine
@@ -247,13 +247,13 @@ Engine::~Engine() { impl(this)->~EngineImpl(); }
void Engine::operator delete(void* p) { ::operator delete(p); }
-auto Engine::make(own<Config*>&& config) -> own<Engine*> {
+auto Engine::make(own<Config>&& config) -> own<Engine> {
i::FLAG_expose_gc = true;
i::FLAG_experimental_wasm_anyref = true;
i::FLAG_experimental_wasm_bigint = true;
i::FLAG_experimental_wasm_mv = true;
auto engine = new (std::nothrow) EngineImpl;
- if (!engine) return own<Engine*>();
+ if (!engine) return own<Engine>();
engine->platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(engine->platform.get());
v8::V8::Initialize();
@@ -273,6 +273,38 @@ StoreImpl::~StoreImpl() {
delete create_params_.array_buffer_allocator;
}
+struct ManagedData {
+ ManagedData(void* info, void (*finalizer)(void*))
+ : info(info), finalizer(finalizer) {}
+
+ ~ManagedData() {
+ if (finalizer) (*finalizer)(info);
+ }
+
+ void* info;
+ void (*finalizer)(void*);
+};
+
+void StoreImpl::SetHostInfo(i::Handle<i::Object> object, void* info,
+ void (*finalizer)(void*)) {
+ i::HandleScope scope(i_isolate());
+ // Ideally we would specify the total size kept alive by {info} here,
+ // but all we get from the embedder is a {void*}, so our best estimate
+ // is the size of the metadata.
+ size_t estimated_size = sizeof(ManagedData);
+ i::Handle<i::Object> wrapper = i::Managed<ManagedData>::FromRawPtr(
+ i_isolate(), estimated_size, new ManagedData(info, finalizer));
+ int32_t hash = object->GetOrCreateHash(i_isolate()).value();
+ i::JSWeakCollection::Set(host_info_map_, object, wrapper, hash);
+}
+
+void* StoreImpl::GetHostInfo(i::Handle<i::Object> key) {
+ i::Object raw =
+ i::EphemeronHashTable::cast(host_info_map_->table()).Lookup(key);
+ if (raw.IsTheHole(i_isolate())) return nullptr;
+ return i::Managed<ManagedData>::cast(raw).raw()->info;
+}
+
template <>
struct implement<Store> {
using type = StoreImpl;
@@ -282,33 +314,40 @@ Store::~Store() { impl(this)->~StoreImpl(); }
void Store::operator delete(void* p) { ::operator delete(p); }
-auto Store::make(Engine*) -> own<Store*> {
+auto Store::make(Engine*) -> own<Store> {
auto store = make_own(new (std::nothrow) StoreImpl());
- if (!store) return own<Store*>();
+ if (!store) return own<Store>();
// Create isolate.
store->create_params_.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
- auto isolate = v8::Isolate::New(store->create_params_);
- if (!isolate) return own<Store*>();
+ v8::Isolate* isolate = v8::Isolate::New(store->create_params_);
+ if (!isolate) return own<Store>();
+ store->isolate_ = isolate;
+ isolate->SetData(0, store.get());
+ // We intentionally do not call isolate->Enter() here, because that would
+ // prevent embedders from using stores with overlapping but non-nested
+ // lifetimes. The consequence is that Isolate::Current() is dysfunctional
+ // and hence must not be called by anything reachable via this file.
{
v8::HandleScope handle_scope(isolate);
// Create context.
- auto context = v8::Context::New(isolate);
- if (context.IsEmpty()) return own<Store*>();
- v8::Context::Scope context_scope(context);
-
- store->isolate_ = isolate;
+ v8::Local<v8::Context> context = v8::Context::New(isolate);
+ if (context.IsEmpty()) return own<Store>();
+ context->Enter(); // The Exit() call is in ~StoreImpl.
store->context_ = v8::Eternal<v8::Context>(isolate, context);
+
+ // Create weak map for Refs with host info.
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ store->host_info_map_ = i_isolate->global_handles()->Create(
+ *i_isolate->factory()->NewJSWeakMap());
}
- // We intentionally do not call isolate->Enter() here, because that would
- // prevent embedders from using stores with overlapping but non-nested
- // lifetimes. The consequence is that Isolate::Current() is dysfunctional
- // and hence must not be called by anything reachable via this file.
- store->context()->Enter();
- isolate->SetData(0, store.get());
+ // We want stack traces for traps.
+ constexpr int kStackLimit = 10;
+ isolate->SetCaptureStackTraceForUncaughtExceptions(true, kStackLimit,
+ v8::StackTrace::kOverview);
return make_own(seal<Store>(store.release()));
}
@@ -329,21 +368,46 @@ struct implement<ValType> {
using type = ValTypeImpl;
};
-ValTypeImpl* valtypes[] = {
- new ValTypeImpl(I32), new ValTypeImpl(I64), new ValTypeImpl(F32),
- new ValTypeImpl(F64), new ValTypeImpl(ANYREF), new ValTypeImpl(FUNCREF),
-};
+ValTypeImpl* valtype_i32 = new ValTypeImpl(I32);
+ValTypeImpl* valtype_i64 = new ValTypeImpl(I64);
+ValTypeImpl* valtype_f32 = new ValTypeImpl(F32);
+ValTypeImpl* valtype_f64 = new ValTypeImpl(F64);
+ValTypeImpl* valtype_anyref = new ValTypeImpl(ANYREF);
+ValTypeImpl* valtype_funcref = new ValTypeImpl(FUNCREF);
ValType::~ValType() {}
void ValType::operator delete(void*) {}
-auto ValType::make(ValKind k) -> own<ValType*> {
- auto result = seal<ValType>(valtypes[k]);
- return own<ValType*>(result);
+own<ValType> ValType::make(ValKind k) {
+ ValTypeImpl* valtype;
+ switch (k) {
+ case I32:
+ valtype = valtype_i32;
+ break;
+ case I64:
+ valtype = valtype_i64;
+ break;
+ case F32:
+ valtype = valtype_f32;
+ break;
+ case F64:
+ valtype = valtype_f64;
+ break;
+ case ANYREF:
+ valtype = valtype_anyref;
+ break;
+ case FUNCREF:
+ valtype = valtype_funcref;
+ break;
+ default:
+ // TODO(wasm+): support new value types
+ UNREACHABLE();
+ }
+ return own<ValType>(seal<ValType>(valtype));
}
-auto ValType::copy() const -> own<ValType*> { return make(kind()); }
+auto ValType::copy() const -> own<ValType> { return make(kind()); }
auto ValType::kind() const -> ValKind { return impl(this)->kind; }
@@ -365,7 +429,7 @@ ExternType::~ExternType() { impl(this)->~ExternTypeImpl(); }
void ExternType::operator delete(void* p) { ::operator delete(p); }
-auto ExternType::copy() const -> own<ExternType*> {
+auto ExternType::copy() const -> own<ExternType> {
switch (kind()) {
case EXTERN_FUNC:
return func()->copy();
@@ -383,11 +447,11 @@ auto ExternType::kind() const -> ExternKind { return impl(this)->kind; }
// Function Types
struct FuncTypeImpl : ExternTypeImpl {
- vec<ValType*> params;
- vec<ValType*> results;
+ ownvec<ValType> params;
+ ownvec<ValType> results;
- FuncTypeImpl(vec<ValType*>& params, // NOLINT(runtime/references)
- vec<ValType*>& results) // NOLINT(runtime/references)
+ FuncTypeImpl(ownvec<ValType>& params, // NOLINT(runtime/references)
+ ownvec<ValType>& results) // NOLINT(runtime/references)
: ExternTypeImpl(EXTERN_FUNC),
params(std::move(params)),
results(std::move(results)) {}
@@ -402,23 +466,23 @@ struct implement<FuncType> {
FuncType::~FuncType() {}
-auto FuncType::make(vec<ValType*>&& params, vec<ValType*>&& results)
- -> own<FuncType*> {
+auto FuncType::make(ownvec<ValType>&& params, ownvec<ValType>&& results)
+ -> own<FuncType> {
return params && results
- ? own<FuncType*>(seal<FuncType>(new (std::nothrow)
- FuncTypeImpl(params, results)))
- : own<FuncType*>();
+ ? own<FuncType>(seal<FuncType>(new (std::nothrow)
+ FuncTypeImpl(params, results)))
+ : own<FuncType>();
}
-auto FuncType::copy() const -> own<FuncType*> {
- return make(params().copy(), results().copy());
+auto FuncType::copy() const -> own<FuncType> {
+ return make(params().deep_copy(), results().deep_copy());
}
-auto FuncType::params() const -> const vec<ValType*>& {
+auto FuncType::params() const -> const ownvec<ValType>& {
return impl(this)->params;
}
-auto FuncType::results() const -> const vec<ValType*>& {
+auto FuncType::results() const -> const ownvec<ValType>& {
return impl(this)->results;
}
@@ -437,10 +501,10 @@ auto ExternType::func() const -> const FuncType* {
// Global Types
struct GlobalTypeImpl : ExternTypeImpl {
- own<ValType*> content;
+ own<ValType> content;
Mutability mutability;
- GlobalTypeImpl(own<ValType*>& content, // NOLINT(runtime/references)
+ GlobalTypeImpl(own<ValType>& content, // NOLINT(runtime/references)
Mutability mutability)
: ExternTypeImpl(EXTERN_GLOBAL),
content(std::move(content)),
@@ -456,14 +520,14 @@ struct implement<GlobalType> {
GlobalType::~GlobalType() {}
-auto GlobalType::make(own<ValType*>&& content, Mutability mutability)
- -> own<GlobalType*> {
- return content ? own<GlobalType*>(seal<GlobalType>(
+auto GlobalType::make(own<ValType>&& content, Mutability mutability)
+ -> own<GlobalType> {
+ return content ? own<GlobalType>(seal<GlobalType>(
new (std::nothrow) GlobalTypeImpl(content, mutability)))
- : own<GlobalType*>();
+ : own<GlobalType>();
}
-auto GlobalType::copy() const -> own<GlobalType*> {
+auto GlobalType::copy() const -> own<GlobalType> {
return make(content()->copy(), mutability());
}
@@ -490,10 +554,10 @@ auto ExternType::global() const -> const GlobalType* {
// Table Types
struct TableTypeImpl : ExternTypeImpl {
- own<ValType*> element;
+ own<ValType> element;
Limits limits;
- TableTypeImpl(own<ValType*>& element, // NOLINT(runtime/references)
+ TableTypeImpl(own<ValType>& element, // NOLINT(runtime/references)
Limits limits)
: ExternTypeImpl(EXTERN_TABLE),
element(std::move(element)),
@@ -509,14 +573,13 @@ struct implement<TableType> {
TableType::~TableType() {}
-auto TableType::make(own<ValType*>&& element, Limits limits)
- -> own<TableType*> {
- return element ? own<TableType*>(seal<TableType>(
+auto TableType::make(own<ValType>&& element, Limits limits) -> own<TableType> {
+ return element ? own<TableType>(seal<TableType>(
new (std::nothrow) TableTypeImpl(element, limits)))
- : own<TableType*>();
+ : own<TableType>();
}
-auto TableType::copy() const -> own<TableType*> {
+auto TableType::copy() const -> own<TableType> {
return make(element()->copy(), limits());
}
@@ -556,12 +619,12 @@ struct implement<MemoryType> {
MemoryType::~MemoryType() {}
-auto MemoryType::make(Limits limits) -> own<MemoryType*> {
- return own<MemoryType*>(
+auto MemoryType::make(Limits limits) -> own<MemoryType> {
+ return own<MemoryType>(
seal<MemoryType>(new (std::nothrow) MemoryTypeImpl(limits)));
}
-auto MemoryType::copy() const -> own<MemoryType*> {
+auto MemoryType::copy() const -> own<MemoryType> {
return MemoryType::make(limits());
}
@@ -584,11 +647,11 @@ auto ExternType::memory() const -> const MemoryType* {
struct ImportTypeImpl {
Name module;
Name name;
- own<ExternType*> type;
+ own<ExternType> type;
- ImportTypeImpl(Name& module, // NOLINT(runtime/references)
- Name& name, // NOLINT(runtime/references)
- own<ExternType*>& type) // NOLINT(runtime/references)
+ ImportTypeImpl(Name& module, // NOLINT(runtime/references)
+ Name& name, // NOLINT(runtime/references)
+ own<ExternType>& type) // NOLINT(runtime/references)
: module(std::move(module)),
name(std::move(name)),
type(std::move(type)) {}
@@ -605,15 +668,15 @@ ImportType::~ImportType() { impl(this)->~ImportTypeImpl(); }
void ImportType::operator delete(void* p) { ::operator delete(p); }
-auto ImportType::make(Name&& module, Name&& name, own<ExternType*>&& type)
- -> own<ImportType*> {
+auto ImportType::make(Name&& module, Name&& name, own<ExternType>&& type)
+ -> own<ImportType> {
return module && name && type
- ? own<ImportType*>(seal<ImportType>(
+ ? own<ImportType>(seal<ImportType>(
new (std::nothrow) ImportTypeImpl(module, name, type)))
- : own<ImportType*>();
+ : own<ImportType>();
}
-auto ImportType::copy() const -> own<ImportType*> {
+auto ImportType::copy() const -> own<ImportType> {
return make(module().copy(), name().copy(), type()->copy());
}
@@ -629,10 +692,10 @@ auto ImportType::type() const -> const ExternType* {
struct ExportTypeImpl {
Name name;
- own<ExternType*> type;
+ own<ExternType> type;
- ExportTypeImpl(Name& name, // NOLINT(runtime/references)
- own<ExternType*>& type) // NOLINT(runtime/references)
+ ExportTypeImpl(Name& name, // NOLINT(runtime/references)
+ own<ExternType>& type) // NOLINT(runtime/references)
: name(std::move(name)), type(std::move(type)) {}
~ExportTypeImpl() {}
@@ -647,14 +710,13 @@ ExportType::~ExportType() { impl(this)->~ExportTypeImpl(); }
void ExportType::operator delete(void* p) { ::operator delete(p); }
-auto ExportType::make(Name&& name, own<ExternType*>&& type)
- -> own<ExportType*> {
- return name && type ? own<ExportType*>(seal<ExportType>(
+auto ExportType::make(Name&& name, own<ExternType>&& type) -> own<ExportType> {
+ return name && type ? own<ExportType>(seal<ExportType>(
new (std::nothrow) ExportTypeImpl(name, type)))
- : own<ExportType*>();
+ : own<ExportType>();
}
-auto ExportType::copy() const -> own<ExportType*> {
+auto ExportType::copy() const -> own<ExportType> {
return make(name().copy(), type()->copy());
}
@@ -680,7 +742,7 @@ i::Handle<i::String> VecToString(i::Isolate* isolate,
template <class Ref, class JSType>
class RefImpl {
public:
- static own<Ref*> make(StoreImpl* store, i::Handle<JSType> obj) {
+ static own<Ref> make(StoreImpl* store, i::Handle<JSType> obj) {
RefImpl* self = new (std::nothrow) RefImpl();
if (!self) return nullptr;
i::Isolate* isolate = store->i_isolate();
@@ -688,17 +750,9 @@ class RefImpl {
return make_own(seal<Ref>(self));
}
- void Reset() {
- i::GlobalHandles::Destroy(location());
- if (host_data_) {
- if (host_data_->finalizer) {
- host_data_->finalizer(host_data_->info);
- }
- delete host_data_;
- }
- }
+ ~RefImpl() { i::GlobalHandles::Destroy(location()); }
- own<Ref*> copy() const { return make(store(), v8_object()); }
+ own<Ref> copy() const { return make(store(), v8_object()); }
StoreImpl* store() const { return StoreImpl::get(isolate()); }
@@ -706,41 +760,20 @@ class RefImpl {
i::Handle<JSType> v8_object() const { return i::Handle<JSType>::cast(val_); }
- void* get_host_info() const {
- if (host_data_ == nullptr) return nullptr;
- return host_data_->info;
- }
+ void* get_host_info() const { return store()->GetHostInfo(v8_object()); }
void set_host_info(void* info, void (*finalizer)(void*)) {
- host_data_ = new HostData(location(), info, finalizer);
- i::GlobalHandles::MakeWeak(host_data_->location, host_data_, &v8_finalizer,
- v8::WeakCallbackType::kParameter);
+ store()->SetHostInfo(v8_object(), info, finalizer);
}
private:
- struct HostData {
- HostData(i::Address* location, void* info, void (*finalizer)(void*))
- : location(location), info(info), finalizer(finalizer) {}
- i::Address* location;
- void* info;
- void (*finalizer)(void*);
- };
-
RefImpl() {}
- static void v8_finalizer(const v8::WeakCallbackInfo<void>& info) {
- HostData* data = reinterpret_cast<HostData*>(info.GetParameter());
- i::GlobalHandles::Destroy(data->location);
- if (data->finalizer) (*data->finalizer)(data->info);
- delete data;
- }
-
i::Address* location() const {
return reinterpret_cast<i::Address*>(val_.address());
}
i::Handle<i::JSReceiver> val_;
- HostData* host_data_ = nullptr;
};
template <>
@@ -749,13 +782,17 @@ struct implement<Ref> {
};
Ref::~Ref() {
- impl(this)->Reset();
delete impl(this);
}
void Ref::operator delete(void* p) {}
-auto Ref::copy() const -> own<Ref*> { return impl(this)->copy(); }
+auto Ref::copy() const -> own<Ref> { return impl(this)->copy(); }
+
+auto Ref::same(const Ref* that) const -> bool {
+ i::HandleScope handle_scope(impl(this)->isolate());
+ return impl(this)->v8_object()->SameValue(*impl(that)->v8_object());
+}
auto Ref::get_host_info() const -> void* { return impl(this)->get_host_info(); }
@@ -766,6 +803,52 @@ void Ref::set_host_info(void* info, void (*finalizer)(void*)) {
///////////////////////////////////////////////////////////////////////////////
// Runtime Objects
+// Frames
+
+namespace {
+
+struct FrameImpl {
+ FrameImpl(own<Instance>&& instance, uint32_t func_index, size_t func_offset,
+ size_t module_offset)
+ : instance(std::move(instance)),
+ func_index(func_index),
+ func_offset(func_offset),
+ module_offset(module_offset) {}
+
+ ~FrameImpl() {}
+
+ own<Instance> instance;
+ uint32_t func_index;
+ size_t func_offset;
+ size_t module_offset;
+};
+
+} // namespace
+
+template <>
+struct implement<Frame> {
+ using type = FrameImpl;
+};
+
+Frame::~Frame() { impl(this)->~FrameImpl(); }
+
+void Frame::operator delete(void* p) { ::operator delete(p); }
+
+own<Frame> Frame::copy() const {
+ auto self = impl(this);
+ return own<Frame>(seal<Frame>(
+ new (std::nothrow) FrameImpl(self->instance->copy(), self->func_index,
+ self->func_offset, self->module_offset)));
+}
+
+Instance* Frame::instance() const { return impl(this)->instance.get(); }
+
+uint32_t Frame::func_index() const { return impl(this)->func_index; }
+
+size_t Frame::func_offset() const { return impl(this)->func_offset; }
+
+size_t Frame::module_offset() const { return impl(this)->module_offset; }
+
// Traps
template <>
@@ -775,9 +858,9 @@ struct implement<Trap> {
Trap::~Trap() {}
-auto Trap::copy() const -> own<Trap*> { return impl(this)->copy(); }
+auto Trap::copy() const -> own<Trap> { return impl(this)->copy(); }
-auto Trap::make(Store* store_abs, const Message& message) -> own<Trap*> {
+auto Trap::make(Store* store_abs, const Message& message) -> own<Trap> {
auto store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate);
@@ -801,6 +884,58 @@ auto Trap::message() const -> Message {
return vec<byte_t>::adopt(length, utf8.release());
}
+namespace {
+
+own<Instance> GetInstance(StoreImpl* store,
+ i::Handle<i::WasmInstanceObject> instance);
+
+own<Frame> CreateFrameFromInternal(i::Handle<i::FixedArray> frames, int index,
+ i::Isolate* isolate, StoreImpl* store) {
+ i::Handle<i::StackTraceFrame> frame(i::StackTraceFrame::cast(frames->get(0)),
+ isolate);
+ i::Handle<i::WasmInstanceObject> instance =
+ i::StackTraceFrame::GetWasmInstance(frame);
+ uint32_t func_index = i::StackTraceFrame::GetLineNumber(frame);
+ size_t func_offset = i::StackTraceFrame::GetFunctionOffset(frame);
+ size_t module_offset = i::StackTraceFrame::GetColumnNumber(frame);
+ return own<Frame>(seal<Frame>(new (std::nothrow) FrameImpl(
+ GetInstance(store, instance), func_index, func_offset, module_offset)));
+}
+
+} // namespace
+
+own<Frame> Trap::origin() const {
+ i::Isolate* isolate = impl(this)->isolate();
+ i::HandleScope handle_scope(isolate);
+
+ i::Handle<i::JSMessageObject> message =
+ isolate->CreateMessage(impl(this)->v8_object(), nullptr);
+ i::Handle<i::FixedArray> frames(i::FixedArray::cast(message->stack_frames()),
+ isolate);
+ if (frames->length() == 0) {
+ return own<Frame>();
+ }
+ return CreateFrameFromInternal(frames, 0, isolate, impl(this)->store());
+}
+
+ownvec<Frame> Trap::trace() const {
+ i::Isolate* isolate = impl(this)->isolate();
+ i::HandleScope handle_scope(isolate);
+
+ i::Handle<i::JSMessageObject> message =
+ isolate->CreateMessage(impl(this)->v8_object(), nullptr);
+ i::Handle<i::FixedArray> frames(i::FixedArray::cast(message->stack_frames()),
+ isolate);
+ int num_frames = frames->length();
+ // {num_frames} can be 0; the code below can handle that case.
+ ownvec<Frame> result = ownvec<Frame>::make_uninitialized(num_frames);
+ for (int i = 0; i < num_frames; i++) {
+ result[i] =
+ CreateFrameFromInternal(frames, i, isolate, impl(this)->store());
+ }
+ return result;
+}
+
// Foreign Objects
template <>
@@ -810,9 +945,9 @@ struct implement<Foreign> {
Foreign::~Foreign() {}
-auto Foreign::copy() const -> own<Foreign*> { return impl(this)->copy(); }
+auto Foreign::copy() const -> own<Foreign> { return impl(this)->copy(); }
-auto Foreign::make(Store* store_abs) -> own<Foreign*> {
+auto Foreign::make(Store* store_abs) -> own<Foreign> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate);
@@ -831,7 +966,7 @@ struct implement<Module> {
Module::~Module() {}
-auto Module::copy() const -> own<Module*> { return impl(this)->copy(); }
+auto Module::copy() const -> own<Module> { return impl(this)->copy(); }
auto Module::validate(Store* store_abs, const vec<byte_t>& binary) -> bool {
i::wasm::ModuleWireBytes bytes(
@@ -841,66 +976,60 @@ auto Module::validate(Store* store_abs, const vec<byte_t>& binary) -> bool {
return isolate->wasm_engine()->SyncValidate(isolate, features, bytes);
}
-class NopErrorThrower : public i::wasm::ErrorThrower {
- public:
- explicit NopErrorThrower(i::Isolate* isolate)
- : i::wasm::ErrorThrower(isolate, "ignored") {}
- ~NopErrorThrower() { Reset(); }
-};
-
-auto Module::make(Store* store_abs, const vec<byte_t>& binary) -> own<Module*> {
+auto Module::make(Store* store_abs, const vec<byte_t>& binary) -> own<Module> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope scope(isolate);
i::wasm::ModuleWireBytes bytes(
{reinterpret_cast<const uint8_t*>(binary.get()), binary.size()});
i::wasm::WasmFeatures features = i::wasm::WasmFeaturesFromIsolate(isolate);
- NopErrorThrower thrower(isolate);
+ i::wasm::ErrorThrower thrower(isolate, "ignored");
i::Handle<i::WasmModuleObject> module;
if (!isolate->wasm_engine()
->SyncCompile(isolate, features, &thrower, bytes)
.ToHandle(&module)) {
+ thrower.Reset(); // The API provides no way to expose the error.
return nullptr;
}
return implement<Module>::type::make(store, module);
}
-auto Module::imports() const -> vec<ImportType*> {
+auto Module::imports() const -> ownvec<ImportType> {
const i::wasm::NativeModule* native_module =
impl(this)->v8_object()->native_module();
const i::wasm::WasmModule* module = native_module->module();
const i::Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
const std::vector<i::wasm::WasmImport>& import_table = module->import_table;
size_t size = import_table.size();
- vec<ImportType*> imports = vec<ImportType*>::make_uninitialized(size);
+ ownvec<ImportType> imports = ownvec<ImportType>::make_uninitialized(size);
for (uint32_t i = 0; i < size; i++) {
const i::wasm::WasmImport& imp = import_table[i];
Name module_name = GetNameFromWireBytes(imp.module_name, wire_bytes);
Name name = GetNameFromWireBytes(imp.field_name, wire_bytes);
- own<ExternType*> type = GetImportExportType(module, imp.kind, imp.index);
+ own<ExternType> type = GetImportExportType(module, imp.kind, imp.index);
imports[i] = ImportType::make(std::move(module_name), std::move(name),
std::move(type));
}
return imports;
}
-vec<ExportType*> ExportsImpl(i::Handle<i::WasmModuleObject> module_obj) {
+ownvec<ExportType> ExportsImpl(i::Handle<i::WasmModuleObject> module_obj) {
const i::wasm::NativeModule* native_module = module_obj->native_module();
const i::wasm::WasmModule* module = native_module->module();
const i::Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
const std::vector<i::wasm::WasmExport>& export_table = module->export_table;
size_t size = export_table.size();
- vec<ExportType*> exports = vec<ExportType*>::make_uninitialized(size);
+ ownvec<ExportType> exports = ownvec<ExportType>::make_uninitialized(size);
for (uint32_t i = 0; i < size; i++) {
const i::wasm::WasmExport& exp = export_table[i];
Name name = GetNameFromWireBytes(exp.name, wire_bytes);
- own<ExternType*> type = GetImportExportType(module, exp.kind, exp.index);
+ own<ExternType> type = GetImportExportType(module, exp.kind, exp.index);
exports[i] = ExportType::make(std::move(name), std::move(type));
}
return exports;
}
-auto Module::exports() const -> vec<ExportType*> {
+auto Module::exports() const -> ownvec<ExportType> {
return ExportsImpl(impl(this)->v8_object());
}
@@ -923,11 +1052,11 @@ auto Module::serialize() const -> vec<byte_t> {
{reinterpret_cast<uint8_t*>(ptr), serial_size})) {
buffer.reset();
}
- return std::move(buffer);
+ return buffer;
}
auto Module::deserialize(Store* store_abs, const vec<byte_t>& serialized)
- -> own<Module*> {
+ -> own<Module> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate);
@@ -963,13 +1092,12 @@ void Shared<Module>::operator delete(void* p) {
::operator delete(p);
}
-auto Module::share() const -> own<Shared<Module>*> {
+auto Module::share() const -> own<Shared<Module>> {
auto shared = seal<Shared<Module>>(new vec<byte_t>(serialize()));
return make_own(shared);
}
-auto Module::obtain(Store* store, const Shared<Module>* shared)
- -> own<Module*> {
+auto Module::obtain(Store* store, const Shared<Module>* shared) -> own<Module> {
return Module::deserialize(store, *impl(shared));
}
@@ -982,7 +1110,7 @@ struct implement<Extern> {
Extern::~Extern() {}
-auto Extern::copy() const -> own<Extern*> { return impl(this)->copy(); }
+auto Extern::copy() const -> own<Extern> { return impl(this)->copy(); }
auto Extern::kind() const -> ExternKind {
i::Handle<i::JSReceiver> obj = impl(this)->v8_object();
@@ -995,7 +1123,7 @@ auto Extern::kind() const -> ExternKind {
UNREACHABLE();
}
-auto Extern::type() const -> own<ExternType*> {
+auto Extern::type() const -> own<ExternType> {
switch (kind()) {
case EXTERN_FUNC:
return func()->type();
@@ -1053,11 +1181,11 @@ struct implement<Func> {
Func::~Func() {}
-auto Func::copy() const -> own<Func*> { return impl(this)->copy(); }
+auto Func::copy() const -> own<Func> { return impl(this)->copy(); }
struct FuncData {
Store* store;
- own<FuncType*> type;
+ own<FuncType> type;
enum Kind { kCallback, kCallbackWithEnv } kind;
union {
Func::callback callback;
@@ -1077,8 +1205,7 @@ struct FuncData {
if (finalizer) (*finalizer)(env);
}
- static i::Address v8_callback(void* data, i::Address argv);
- static void finalize_func_data(void* data);
+ static i::Address v8_callback(i::Address host_data_foreign, i::Address argv);
};
namespace {
@@ -1111,11 +1238,11 @@ class SignatureHelper : public i::AllStatic {
return sig;
}
- static own<FuncType*> Deserialize(i::PodArray<i::wasm::ValueType> sig) {
+ static own<FuncType> Deserialize(i::PodArray<i::wasm::ValueType> sig) {
int result_arity = ResultArity(sig);
int param_arity = sig.length() - result_arity - 1;
- vec<ValType*> results = vec<ValType*>::make_uninitialized(result_arity);
- vec<ValType*> params = vec<ValType*>::make_uninitialized(param_arity);
+ ownvec<ValType> results = ownvec<ValType>::make_uninitialized(result_arity);
+ ownvec<ValType> params = ownvec<ValType>::make_uninitialized(param_arity);
int i = 0;
for (; i < result_arity; ++i) {
@@ -1146,29 +1273,30 @@ class SignatureHelper : public i::AllStatic {
}
};
-auto make_func(Store* store_abs, FuncData* data) -> own<Func*> {
+auto make_func(Store* store_abs, FuncData* data) -> own<Func> {
auto store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate);
+ i::Handle<i::Managed<FuncData>> embedder_data =
+ i::Managed<FuncData>::FromRawPtr(isolate, sizeof(FuncData), data);
i::Handle<i::WasmCapiFunction> function = i::WasmCapiFunction::New(
- isolate, reinterpret_cast<i::Address>(&FuncData::v8_callback), data,
- SignatureHelper::Serialize(isolate, data->type.get()));
+ isolate, reinterpret_cast<i::Address>(&FuncData::v8_callback),
+ embedder_data, SignatureHelper::Serialize(isolate, data->type.get()));
auto func = implement<Func>::type::make(store, function);
- func->set_host_info(data, &FuncData::finalize_func_data);
return func;
}
} // namespace
auto Func::make(Store* store, const FuncType* type, Func::callback callback)
- -> own<Func*> {
+ -> own<Func> {
auto data = new FuncData(store, type, FuncData::kCallback);
data->callback = callback;
return make_func(store, data);
}
auto Func::make(Store* store, const FuncType* type, callback_with_env callback,
- void* env, void (*finalizer)(void*)) -> own<Func*> {
+ void* env, void (*finalizer)(void*)) -> own<Func> {
auto data = new FuncData(store, type, FuncData::kCallbackWithEnv);
data->callback_with_env = callback;
data->env = env;
@@ -1176,7 +1304,7 @@ auto Func::make(Store* store, const FuncType* type, callback_with_env callback,
return make_func(store, data);
}
-auto Func::type() const -> own<FuncType*> {
+auto Func::type() const -> own<FuncType> {
i::Handle<i::JSFunction> func = impl(this)->v8_object();
if (i::WasmCapiFunction::IsWasmCapiFunction(*func)) {
return SignatureHelper::Deserialize(SignatureHelper::GetSig(func));
@@ -1216,6 +1344,37 @@ auto Func::result_arity() const -> size_t {
namespace {
+own<Ref> V8RefValueToWasm(StoreImpl* store, i::Handle<i::Object> value) {
+ if (value->IsNull(store->i_isolate())) return nullptr;
+ return implement<Ref>::type::make(store,
+ i::Handle<i::JSReceiver>::cast(value));
+}
+
+i::Handle<i::Object> WasmRefToV8(i::Isolate* isolate, const Ref* ref) {
+ if (ref == nullptr) return i::ReadOnlyRoots(isolate).null_value_handle();
+ return impl(ref)->v8_object();
+}
+
+i::Handle<i::Object> CallTargetForCaching(i::Isolate* isolate,
+ i::Address real_call_target) {
+ if (i::kTaggedSize == i::kInt32Size) {
+ return isolate->factory()->NewForeign(real_call_target);
+ } else {
+ // 64-bit uncompressed platform.
+ return i::handle(i::Smi((real_call_target << i::kSmiTagSize) | i::kSmiTag),
+ isolate);
+ }
+}
+
+i::Address CallTargetFromCache(i::Object cached_call_target) {
+ if (i::kTaggedSize == i::kInt32Size) {
+ return i::Foreign::cast(cached_call_target).foreign_address();
+ } else {
+ // 64-bit uncompressed platform.
+ return cached_call_target.ptr() >> i::kSmiTagSize;
+ }
+}
+
void PrepareFunctionData(i::Isolate* isolate,
i::Handle<i::WasmExportedFunctionData> function_data,
i::wasm::FunctionSig* sig) {
@@ -1228,16 +1387,16 @@ void PrepareFunctionData(i::Isolate* isolate,
// Compute packed args size.
function_data->set_packed_args_size(
i::wasm::CWasmArgumentsPacker::TotalSize(sig));
- // Get call target (function table offset). This is an Address, we store
- // it as a pseudo-Smi by shifting it by one bit, so the GC leaves it alone.
- i::Address call_target =
- function_data->instance().GetCallTarget(function_data->function_index());
- i::Smi smi_target((call_target << i::kSmiTagSize) | i::kSmiTag);
- function_data->set_wasm_call_target(smi_target);
+ // Get call target (function table offset), and wrap it as a cacheable object
+ // (pseudo-Smi or Foreign, depending on platform).
+ i::Handle<i::Object> call_target = CallTargetForCaching(
+ isolate,
+ function_data->instance().GetCallTarget(function_data->function_index()));
+ function_data->set_wasm_call_target(*call_target);
}
void PushArgs(i::wasm::FunctionSig* sig, const Val args[],
- i::wasm::CWasmArgumentsPacker* packer) {
+ i::wasm::CWasmArgumentsPacker* packer, StoreImpl* store) {
for (size_t i = 0; i < sig->parameter_count(); i++) {
i::wasm::ValueType type = sig->GetParam(i);
switch (type) {
@@ -1255,7 +1414,7 @@ void PushArgs(i::wasm::FunctionSig* sig, const Val args[],
break;
case i::wasm::kWasmAnyRef:
case i::wasm::kWasmFuncRef:
- packer->Push(impl(args[i].ref())->v8_object()->ptr());
+ packer->Push(WasmRefToV8(store->i_isolate(), args[i].ref())->ptr());
break;
case i::wasm::kWasmExnRef:
// TODO(jkummerow): Implement these.
@@ -1288,13 +1447,8 @@ void PopArgs(i::wasm::FunctionSig* sig, Val results[],
case i::wasm::kWasmAnyRef:
case i::wasm::kWasmFuncRef: {
i::Address raw = packer->Pop<i::Address>();
- if (raw == i::kNullAddress) {
- results[i] = Val(nullptr);
- } else {
- i::JSReceiver raw_obj = i::JSReceiver::cast(i::Object(raw));
- i::Handle<i::JSReceiver> obj(raw_obj, store->i_isolate());
- results[i] = Val(implement<Ref>::type::make(store, obj));
- }
+ i::Handle<i::Object> obj(i::Object(raw), store->i_isolate());
+ results[i] = Val(V8RefValueToWasm(store, obj));
break;
}
case i::wasm::kWasmExnRef:
@@ -1307,9 +1461,9 @@ void PopArgs(i::wasm::FunctionSig* sig, Val results[],
}
}
-own<Trap*> CallWasmCapiFunction(i::WasmCapiFunctionData data, const Val args[],
- Val results[]) {
- FuncData* func_data = reinterpret_cast<FuncData*>(data.embedder_data());
+own<Trap> CallWasmCapiFunction(i::WasmCapiFunctionData data, const Val args[],
+ Val results[]) {
+ FuncData* func_data = i::Managed<FuncData>::cast(data.embedder_data()).raw();
if (func_data->kind == FuncData::kCallback) {
return (func_data->callback)(args, results);
}
@@ -1317,9 +1471,28 @@ own<Trap*> CallWasmCapiFunction(i::WasmCapiFunctionData data, const Val args[],
return (func_data->callback_with_env)(func_data->env, args, results);
}
+i::Handle<i::JSReceiver> GetProperException(
+ i::Isolate* isolate, i::Handle<i::Object> maybe_exception) {
+ if (maybe_exception->IsJSReceiver()) {
+ return i::Handle<i::JSReceiver>::cast(maybe_exception);
+ }
+ i::MaybeHandle<i::String> maybe_string =
+ i::Object::ToString(isolate, maybe_exception);
+ i::Handle<i::String> string = isolate->factory()->empty_string();
+ if (!maybe_string.ToHandle(&string)) {
+ // If converting the {maybe_exception} to string threw another exception,
+ // just give up and leave {string} as the empty string.
+ isolate->clear_pending_exception();
+ }
+ // {NewError} cannot fail when its input is a plain String, so we always
+ // get an Error object here.
+ return i::Handle<i::JSReceiver>::cast(
+ isolate->factory()->NewError(isolate->error_function(), string));
+}
+
} // namespace
-auto Func::call(const Val args[], Val results[]) const -> own<Trap*> {
+auto Func::call(const Val args[], Val results[]) const -> own<Trap> {
auto func = impl(this);
auto store = func->store();
auto isolate = store->i_isolate();
@@ -1343,10 +1516,10 @@ auto Func::call(const Val args[], Val results[]) const -> own<Trap*> {
i::Handle<i::Code> wrapper_code = i::Handle<i::Code>(
i::Code::cast(function_data->c_wrapper_code()), isolate);
i::Address call_target =
- function_data->wasm_call_target().ptr() >> i::kSmiTagSize;
+ CallTargetFromCache(function_data->wasm_call_target());
i::wasm::CWasmArgumentsPacker packer(function_data->packed_args_size());
- PushArgs(sig, args, &packer);
+ PushArgs(sig, args, &packer, store);
i::Handle<i::Object> object_ref = instance;
if (function_index <
@@ -1377,28 +1550,24 @@ auto Func::call(const Val args[], Val results[]) const -> own<Trap*> {
if (isolate->has_pending_exception()) {
i::Handle<i::Object> exception(isolate->pending_exception(), isolate);
isolate->clear_pending_exception();
- if (!exception->IsJSReceiver()) {
- i::MaybeHandle<i::String> maybe_string =
- i::Object::ToString(isolate, exception);
- i::Handle<i::String> string = maybe_string.is_null()
- ? isolate->factory()->empty_string()
- : maybe_string.ToHandleChecked();
- exception =
- isolate->factory()->NewError(isolate->error_function(), string);
- }
- return implement<Trap>::type::make(
- store, i::Handle<i::JSReceiver>::cast(exception));
+ return implement<Trap>::type::make(store,
+ GetProperException(isolate, exception));
}
PopArgs(sig, results, &packer, store);
return nullptr;
}
-i::Address FuncData::v8_callback(void* data, i::Address argv) {
- FuncData* self = reinterpret_cast<FuncData*>(data);
+i::Address FuncData::v8_callback(i::Address host_data_foreign,
+ i::Address argv) {
+ FuncData* self =
+ i::Managed<FuncData>::cast(i::Object(host_data_foreign))->raw();
+ StoreImpl* store = impl(self->store);
+ i::Isolate* isolate = store->i_isolate();
+ i::HandleScope scope(isolate);
- const vec<ValType*>& param_types = self->type->params();
- const vec<ValType*>& result_types = self->type->results();
+ const ownvec<ValType>& param_types = self->type->params();
+ const ownvec<ValType>& result_types = self->type->results();
int num_param_types = static_cast<int>(param_types.size());
int num_result_types = static_cast<int>(result_types.size());
@@ -1428,19 +1597,14 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
case FUNCREF: {
i::Address raw = v8::base::ReadUnalignedValue<i::Address>(p);
p += sizeof(raw);
- if (raw == i::kNullAddress) {
- params[i] = Val(nullptr);
- } else {
- i::JSReceiver raw_obj = i::JSReceiver::cast(i::Object(raw));
- i::Handle<i::JSReceiver> obj(raw_obj, raw_obj.GetIsolate());
- params[i] = Val(implement<Ref>::type::make(impl(self->store), obj));
- }
+ i::Handle<i::Object> obj(i::Object(raw), isolate);
+ params[i] = Val(V8RefValueToWasm(store, obj));
break;
}
}
}
- own<Trap*> trap;
+ own<Trap> trap;
if (self->kind == kCallbackWithEnv) {
trap = self->callback_with_env(self->env, params.get(), results.get());
} else {
@@ -1448,7 +1612,6 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
}
if (trap) {
- i::Isolate* isolate = impl(self->store)->i_isolate();
isolate->Throw(*impl(trap.get())->v8_object());
i::Object ex = isolate->pending_exception();
isolate->clear_pending_exception();
@@ -1476,12 +1639,8 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
break;
case ANYREF:
case FUNCREF: {
- if (results[i].ref() == nullptr) {
- v8::base::WriteUnalignedValue(p, i::kNullAddress);
- } else {
- v8::base::WriteUnalignedValue(
- p, impl(results[i].ref())->v8_object()->ptr());
- }
+ v8::base::WriteUnalignedValue(
+ p, WasmRefToV8(isolate, results[i].ref())->ptr());
p += sizeof(i::Address);
break;
}
@@ -1490,10 +1649,6 @@ i::Address FuncData::v8_callback(void* data, i::Address argv) {
return i::kNullAddress;
}
-void FuncData::finalize_func_data(void* data) {
- delete reinterpret_cast<FuncData*>(data);
-}
-
// Global Instances
template <>
@@ -1503,10 +1658,10 @@ struct implement<Global> {
Global::~Global() {}
-auto Global::copy() const -> own<Global*> { return impl(this)->copy(); }
+auto Global::copy() const -> own<Global> { return impl(this)->copy(); }
auto Global::make(Store* store_abs, const GlobalType* type, const Val& val)
- -> own<Global*> {
+ -> own<Global> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate);
@@ -1528,7 +1683,7 @@ auto Global::make(Store* store_abs, const GlobalType* type, const Val& val)
return global;
}
-auto Global::type() const -> own<GlobalType*> {
+auto Global::type() const -> own<GlobalType> {
i::Handle<i::WasmGlobalObject> v8_global = impl(this)->v8_object();
ValKind kind = V8ValueTypeToWasm(v8_global->type());
Mutability mutability = v8_global->is_mutable() ? VAR : CONST;
@@ -1546,15 +1701,11 @@ auto Global::get() const -> Val {
return Val(v8_global->GetF32());
case F64:
return Val(v8_global->GetF64());
- case ANYREF: {
- i::Handle<i::JSReceiver> obj =
- i::Handle<i::JSReceiver>::cast(v8_global->GetRef());
- return Val(RefImpl<Ref, i::JSReceiver>::make(impl(this)->store(), obj));
- }
+ case ANYREF:
case FUNCREF: {
- i::Handle<i::JSFunction> obj =
- i::Handle<i::JSFunction>::cast(v8_global->GetRef());
- return Val(implement<Func>::type::make(impl(this)->store(), obj));
+ StoreImpl* store = impl(this)->store();
+ i::HandleScope scope(store->i_isolate());
+ return Val(V8RefValueToWasm(store, v8_global->GetRef()));
}
default:
// TODO(wasm+): support new value types
@@ -1574,10 +1725,12 @@ void Global::set(const Val& val) {
case F64:
return v8_global->SetF64(val.f64());
case ANYREF:
- return v8_global->SetAnyRef(impl(val.ref())->v8_object());
+ return v8_global->SetAnyRef(
+ WasmRefToV8(impl(this)->store()->i_isolate(), val.ref()));
case FUNCREF: {
- bool result = v8_global->SetFuncRef(impl(this)->store()->i_isolate(),
- impl(val.ref())->v8_object());
+ i::Isolate* isolate = impl(this)->store()->i_isolate();
+ bool result =
+ v8_global->SetFuncRef(isolate, WasmRefToV8(isolate, val.ref()));
DCHECK(result);
USE(result);
return;
@@ -1597,14 +1750,13 @@ struct implement<Table> {
Table::~Table() {}
-auto Table::copy() const -> own<Table*> { return impl(this)->copy(); }
+auto Table::copy() const -> own<Table> { return impl(this)->copy(); }
auto Table::make(Store* store_abs, const TableType* type, const Ref* ref)
- -> own<Table*> {
+ -> own<Table> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope scope(isolate);
- auto enabled_features = i::wasm::WasmFeaturesFromFlags();
// Get "element".
i::wasm::ValueType i_type;
@@ -1613,13 +1765,11 @@ auto Table::make(Store* store_abs, const TableType* type, const Ref* ref)
i_type = i::wasm::kWasmFuncRef;
break;
case ANYREF:
- if (enabled_features.anyref) {
- i_type = i::wasm::kWasmAnyRef;
- break;
- } // Else fall through.
- V8_FALLTHROUGH;
+ DCHECK(i::wasm::WasmFeaturesFromFlags().anyref); // See Engine::make().
+ i_type = i::wasm::kWasmAnyRef;
+ break;
default:
- UNREACHABLE(); // 'element' must be 'FUNCREF'.
+ UNREACHABLE();
return nullptr;
}
@@ -1652,42 +1802,44 @@ auto Table::make(Store* store_abs, const TableType* type, const Ref* ref)
return implement<Table>::type::make(store, table_obj);
}
-auto Table::type() const -> own<TableType*> {
+auto Table::type() const -> own<TableType> {
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
uint32_t min = table->current_length();
uint32_t max;
if (!table->maximum_length().ToUint32(&max)) max = 0xFFFFFFFFu;
- // TODO(wasm+): support new element types.
- return TableType::make(ValType::make(FUNCREF), Limits(min, max));
+ ValKind kind;
+ switch (table->type()) {
+ case i::wasm::kWasmFuncRef:
+ kind = FUNCREF;
+ break;
+ case i::wasm::kWasmAnyRef:
+ kind = ANYREF;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return TableType::make(ValType::make(kind), Limits(min, max));
}
-auto Table::get(size_t index) const -> own<Ref*> {
+auto Table::get(size_t index) const -> own<Ref> {
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
- if (index >= table->current_length()) return own<Ref*>();
+ if (index >= table->current_length()) return own<Ref>();
i::Isolate* isolate = table->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> result =
i::WasmTableObject::Get(isolate, table, static_cast<uint32_t>(index));
- if (!result->IsJSFunction()) return own<Ref*>();
- DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*result) ||
- i::WasmCapiFunction::IsWasmCapiFunction(*result));
- // TODO(wasm+): other references
- return implement<Func>::type::make(impl(this)->store(),
- i::Handle<i::JSFunction>::cast(result));
+ // TODO(jkummerow): If we support both JavaScript and the C-API at the same
+ // time, we need to handle Smis and other JS primitives here.
+ DCHECK(result->IsNull(isolate) || result->IsJSReceiver());
+ return V8RefValueToWasm(impl(this)->store(), result);
}
auto Table::set(size_t index, const Ref* ref) -> bool {
- if (ref && !impl(ref)->v8_object()->IsFunction()) {
- WASM_UNIMPLEMENTED("non-function table elements");
- }
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
if (index >= table->current_length()) return false;
i::Isolate* isolate = table->GetIsolate();
i::HandleScope handle_scope(isolate);
- i::Handle<i::Object> obj =
- ref ? i::Handle<i::Object>::cast(impl(ref)->v8_object())
- : i::Handle<i::Object>::cast(
- i::ReadOnlyRoots(isolate).null_value_handle());
+ i::Handle<i::Object> obj = WasmRefToV8(isolate, ref);
i::WasmTableObject::Set(isolate, table, static_cast<uint32_t>(index), obj);
return true;
}
@@ -1701,10 +1853,7 @@ auto Table::grow(size_t delta, const Ref* ref) -> bool {
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
i::Isolate* isolate = table->GetIsolate();
i::HandleScope scope(isolate);
- i::Handle<i::Object> init_value =
- ref == nullptr
- ? i::Handle<i::Object>::cast(isolate->factory()->null_value())
- : i::Handle<i::Object>::cast(impl(ref)->v8_object());
+ i::Handle<i::Object> init_value = WasmRefToV8(isolate, ref);
int result = i::WasmTableObject::Grow(
isolate, table, static_cast<uint32_t>(delta), init_value);
return result >= 0;
@@ -1719,9 +1868,9 @@ struct implement<Memory> {
Memory::~Memory() {}
-auto Memory::copy() const -> own<Memory*> { return impl(this)->copy(); }
+auto Memory::copy() const -> own<Memory> { return impl(this)->copy(); }
-auto Memory::make(Store* store_abs, const MemoryType* type) -> own<Memory*> {
+auto Memory::make(Store* store_abs, const MemoryType* type) -> own<Memory> {
StoreImpl* store = impl(store_abs);
i::Isolate* isolate = store->i_isolate();
i::HandleScope scope(isolate);
@@ -1738,12 +1887,12 @@ auto Memory::make(Store* store_abs, const MemoryType* type) -> own<Memory*> {
i::Handle<i::WasmMemoryObject> memory_obj;
if (!i::WasmMemoryObject::New(isolate, minimum, maximum, is_shared)
.ToHandle(&memory_obj)) {
- return own<Memory*>();
+ return own<Memory>();
}
return implement<Memory>::type::make(store, memory_obj);
}
-auto Memory::type() const -> own<MemoryType*> {
+auto Memory::type() const -> own<MemoryType> {
i::Handle<i::WasmMemoryObject> memory = impl(this)->v8_object();
uint32_t min = static_cast<uint32_t>(memory->array_buffer().byte_length() /
i::wasm::kWasmPageSize);
@@ -1784,10 +1933,10 @@ struct implement<Instance> {
Instance::~Instance() {}
-auto Instance::copy() const -> own<Instance*> { return impl(this)->copy(); }
+auto Instance::copy() const -> own<Instance> { return impl(this)->copy(); }
-auto Instance::make(Store* store_abs, const Module* module_abs,
- const Extern* const imports[]) -> own<Instance*> {
+own<Instance> Instance::make(Store* store_abs, const Module* module_abs,
+ const Extern* const imports[], own<Trap>* trap) {
StoreImpl* store = impl(store_abs);
const implement<Module>::type* module = impl(module_abs);
i::Isolate* isolate = store->i_isolate();
@@ -1795,11 +1944,12 @@ auto Instance::make(Store* store_abs, const Module* module_abs,
DCHECK_EQ(module->v8_object()->GetIsolate(), isolate);
- vec<ImportType*> import_types = module_abs->imports();
+ if (trap) *trap = nullptr;
+ ownvec<ImportType> import_types = module_abs->imports();
i::Handle<i::JSObject> imports_obj =
isolate->factory()->NewJSObject(isolate->object_function());
for (size_t i = 0; i < import_types.size(); ++i) {
- auto type = import_types[i];
+ ImportType* type = import_types[i].get();
i::Handle<i::String> module_str = VecToString(isolate, type->module());
i::Handle<i::String> name_str = VecToString(isolate, type->name());
@@ -1817,17 +1967,45 @@ auto Instance::make(Store* store_abs, const Module* module_abs,
ignore(i::Object::SetProperty(isolate, module_obj, name_str,
impl(imports[i])->v8_object()));
}
+ i::wasm::ErrorThrower thrower(isolate, "instantiation");
+ i::MaybeHandle<i::WasmInstanceObject> instance_obj =
+ isolate->wasm_engine()->SyncInstantiate(
+ isolate, &thrower, module->v8_object(), imports_obj,
+ i::MaybeHandle<i::JSArrayBuffer>());
+ if (trap) {
+ if (thrower.error()) {
+ *trap = implement<Trap>::type::make(
+ store, GetProperException(isolate, thrower.Reify()));
+ DCHECK(!thrower.error()); // Reify() called Reset().
+ DCHECK(!isolate->has_pending_exception()); // Hasn't been thrown yet.
+ return own<Instance>();
+ } else if (isolate->has_pending_exception()) {
+ i::Handle<i::Object> maybe_exception(isolate->pending_exception(),
+ isolate);
+ *trap = implement<Trap>::type::make(
+ store, GetProperException(isolate, maybe_exception));
+ isolate->clear_pending_exception();
+ return own<Instance>();
+ }
+ } else if (instance_obj.is_null()) {
+ // If no {trap} output is specified, silently swallow all errors.
+ thrower.Reset();
+ isolate->clear_pending_exception();
+ return own<Instance>();
+ }
+ return implement<Instance>::type::make(store, instance_obj.ToHandleChecked());
+}
- NopErrorThrower thrower(isolate);
- i::Handle<i::WasmInstanceObject> instance_obj =
- isolate->wasm_engine()
- ->SyncInstantiate(isolate, &thrower, module->v8_object(), imports_obj,
- i::MaybeHandle<i::JSArrayBuffer>())
- .ToHandleChecked();
- return implement<Instance>::type::make(store, instance_obj);
+namespace {
+
+own<Instance> GetInstance(StoreImpl* store,
+ i::Handle<i::WasmInstanceObject> instance) {
+ return implement<Instance>::type::make(store, instance);
}
-auto Instance::exports() const -> vec<Extern*> {
+} // namespace
+
+auto Instance::exports() const -> ownvec<Extern> {
const implement<Instance>::type* instance = impl(this);
StoreImpl* store = instance->store();
i::Isolate* isolate = store->i_isolate();
@@ -1837,9 +2015,10 @@ auto Instance::exports() const -> vec<Extern*> {
isolate);
i::Handle<i::JSObject> exports_obj(instance_obj->exports_object(), isolate);
- vec<ExportType*> export_types = ExportsImpl(module_obj);
- vec<Extern*> exports = vec<Extern*>::make_uninitialized(export_types.size());
- if (!exports) return vec<Extern*>::invalid();
+ ownvec<ExportType> export_types = ExportsImpl(module_obj);
+ ownvec<Extern> exports =
+ ownvec<Extern>::make_uninitialized(export_types.size());
+ if (!exports) return ownvec<Extern>::invalid();
for (size_t i = 0; i < export_types.size(); ++i) {
auto& name = export_types[i]->name();
@@ -1852,20 +2031,20 @@ auto Instance::exports() const -> vec<Extern*> {
switch (type->kind()) {
case EXTERN_FUNC: {
DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*obj));
- exports[i].reset(implement<Func>::type::make(
- store, i::Handle<i::WasmExportedFunction>::cast(obj)));
+ exports[i] = implement<Func>::type::make(
+ store, i::Handle<i::WasmExportedFunction>::cast(obj));
} break;
case EXTERN_GLOBAL: {
- exports[i].reset(implement<Global>::type::make(
- store, i::Handle<i::WasmGlobalObject>::cast(obj)));
+ exports[i] = implement<Global>::type::make(
+ store, i::Handle<i::WasmGlobalObject>::cast(obj));
} break;
case EXTERN_TABLE: {
- exports[i].reset(implement<Table>::type::make(
- store, i::Handle<i::WasmTableObject>::cast(obj)));
+ exports[i] = implement<Table>::type::make(
+ store, i::Handle<i::WasmTableObject>::cast(obj));
} break;
case EXTERN_MEMORY: {
- exports[i].reset(implement<Memory>::type::make(
- store, i::Handle<i::WasmMemoryObject>::cast(obj)));
+ exports[i] = implement<Memory>::type::make(
+ store, i::Handle<i::WasmMemoryObject>::cast(obj));
} break;
}
}
@@ -1898,152 +2077,151 @@ struct borrowed_vec {
} // extern "C++"
-#define WASM_DEFINE_OWN(name, Name) \
- struct wasm_##name##_t : Name {}; \
- \
- void wasm_##name##_delete(wasm_##name##_t* x) { delete x; } \
- \
- extern "C++" inline auto hide(Name* x)->wasm_##name##_t* { \
- return static_cast<wasm_##name##_t*>(x); \
- } \
- extern "C++" inline auto hide(const Name* x)->const wasm_##name##_t* { \
- return static_cast<const wasm_##name##_t*>(x); \
- } \
- extern "C++" inline auto reveal(wasm_##name##_t* x)->Name* { return x; } \
- extern "C++" inline auto reveal(const wasm_##name##_t* x)->const Name* { \
- return x; \
- } \
- extern "C++" inline auto get(wasm::own<Name*>& x)->wasm_##name##_t* { \
- return hide(x.get()); \
- } \
- extern "C++" inline auto get(const wasm::own<Name*>& x) \
- ->const wasm_##name##_t* { \
- return hide(x.get()); \
- } \
- extern "C++" inline auto release(wasm::own<Name*>&& x)->wasm_##name##_t* { \
- return hide(x.release()); \
- } \
- extern "C++" inline auto adopt(wasm_##name##_t* x)->wasm::own<Name*> { \
- return make_own(x); \
+#define WASM_DEFINE_OWN(name, Name) \
+ struct wasm_##name##_t : Name {}; \
+ \
+ void wasm_##name##_delete(wasm_##name##_t* x) { delete x; } \
+ \
+ extern "C++" inline auto hide_##name(Name* x)->wasm_##name##_t* { \
+ return static_cast<wasm_##name##_t*>(x); \
+ } \
+ extern "C++" inline auto hide_##name(const Name* x) \
+ ->const wasm_##name##_t* { \
+ return static_cast<const wasm_##name##_t*>(x); \
+ } \
+ extern "C++" inline auto reveal_##name(wasm_##name##_t* x)->Name* { \
+ return x; \
+ } \
+ extern "C++" inline auto reveal_##name(const wasm_##name##_t* x) \
+ ->const Name* { \
+ return x; \
+ } \
+ extern "C++" inline auto get_##name(wasm::own<Name>& x)->wasm_##name##_t* { \
+ return hide_##name(x.get()); \
+ } \
+ extern "C++" inline auto get_##name(const wasm::own<Name>& x) \
+ ->const wasm_##name##_t* { \
+ return hide_##name(x.get()); \
+ } \
+ extern "C++" inline auto release_##name(wasm::own<Name>&& x) \
+ ->wasm_##name##_t* { \
+ return hide_##name(x.release()); \
+ } \
+ extern "C++" inline auto adopt_##name(wasm_##name##_t* x)->wasm::own<Name> { \
+ return make_own(x); \
}
// Vectors
-#define WASM_DEFINE_VEC_BASE(name, Name, ptr_or_none) \
- extern "C++" inline auto hide(wasm::vec<Name ptr_or_none>& v) \
- ->wasm_##name##_vec_t* { \
- static_assert(sizeof(wasm_##name##_vec_t) == sizeof(wasm::vec<Name>), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<wasm_##name##_vec_t*>(&v); \
- } \
- extern "C++" inline auto hide(const wasm::vec<Name ptr_or_none>& v) \
- ->const wasm_##name##_vec_t* { \
- static_assert(sizeof(wasm_##name##_vec_t) == sizeof(wasm::vec<Name>), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<const wasm_##name##_vec_t*>(&v); \
- } \
- extern "C++" inline auto hide(Name ptr_or_none* v) \
- ->wasm_##name##_t ptr_or_none* { \
- static_assert( \
- sizeof(wasm_##name##_t ptr_or_none) == sizeof(Name ptr_or_none), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<wasm_##name##_t ptr_or_none*>(v); \
- } \
- extern "C++" inline auto hide(Name ptr_or_none const* v) \
- ->wasm_##name##_t ptr_or_none const* { \
- static_assert( \
- sizeof(wasm_##name##_t ptr_or_none) == sizeof(Name ptr_or_none), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<wasm_##name##_t ptr_or_none const*>(v); \
- } \
- extern "C++" inline auto reveal(wasm_##name##_t ptr_or_none* v) \
- ->Name ptr_or_none* { \
- static_assert( \
- sizeof(wasm_##name##_t ptr_or_none) == sizeof(Name ptr_or_none), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<Name ptr_or_none*>(v); \
- } \
- extern "C++" inline auto reveal(wasm_##name##_t ptr_or_none const* v) \
- ->Name ptr_or_none const* { \
- static_assert( \
- sizeof(wasm_##name##_t ptr_or_none) == sizeof(Name ptr_or_none), \
- "C/C++ incompatibility"); \
- return reinterpret_cast<Name ptr_or_none const*>(v); \
- } \
- extern "C++" inline auto get(wasm::vec<Name ptr_or_none>& v) \
- ->wasm_##name##_vec_t { \
- wasm_##name##_vec_t v2 = {v.size(), hide(v.get())}; \
- return v2; \
- } \
- extern "C++" inline auto get(const wasm::vec<Name ptr_or_none>& v) \
- ->const wasm_##name##_vec_t { \
- wasm_##name##_vec_t v2 = { \
- v.size(), const_cast<wasm_##name##_t ptr_or_none*>(hide(v.get()))}; \
- return v2; \
- } \
- extern "C++" inline auto release(wasm::vec<Name ptr_or_none>&& v) \
- ->wasm_##name##_vec_t { \
- wasm_##name##_vec_t v2 = {v.size(), hide(v.release())}; \
- return v2; \
- } \
- extern "C++" inline auto adopt(wasm_##name##_vec_t* v) \
- ->wasm::vec<Name ptr_or_none> { \
- return wasm::vec<Name ptr_or_none>::adopt(v->size, reveal(v->data)); \
- } \
- extern "C++" inline auto borrow(const wasm_##name##_vec_t* v) \
- ->borrowed_vec<Name ptr_or_none> { \
- return borrowed_vec<Name ptr_or_none>( \
- wasm::vec<Name ptr_or_none>::adopt(v->size, reveal(v->data))); \
- } \
- \
- void wasm_##name##_vec_new_uninitialized(wasm_##name##_vec_t* out, \
- size_t size) { \
- *out = release(wasm::vec<Name ptr_or_none>::make_uninitialized(size)); \
- } \
- void wasm_##name##_vec_new_empty(wasm_##name##_vec_t* out) { \
- wasm_##name##_vec_new_uninitialized(out, 0); \
- } \
- \
- void wasm_##name##_vec_delete(wasm_##name##_vec_t* v) { adopt(v); }
+#define WASM_DEFINE_VEC_BASE(name, Name, vec, ptr_or_none) \
+ static_assert(sizeof(wasm_##name##_vec_t) == sizeof(vec<Name>), \
+ "C/C++ incompatibility"); \
+ static_assert( \
+ sizeof(wasm_##name##_t ptr_or_none) == sizeof(vec<Name>::elem_type), \
+ "C/C++ incompatibility"); \
+ extern "C++" inline auto hide_##name##_vec(vec<Name>& v) \
+ ->wasm_##name##_vec_t* { \
+ return reinterpret_cast<wasm_##name##_vec_t*>(&v); \
+ } \
+ extern "C++" inline auto hide_##name##_vec(const vec<Name>& v) \
+ ->const wasm_##name##_vec_t* { \
+ return reinterpret_cast<const wasm_##name##_vec_t*>(&v); \
+ } \
+ extern "C++" inline auto hide_##name##_vec(vec<Name>::elem_type* v) \
+ ->wasm_##name##_t ptr_or_none* { \
+ return reinterpret_cast<wasm_##name##_t ptr_or_none*>(v); \
+ } \
+ extern "C++" inline auto hide_##name##_vec(const vec<Name>::elem_type* v) \
+ ->wasm_##name##_t ptr_or_none const* { \
+ return reinterpret_cast<wasm_##name##_t ptr_or_none const*>(v); \
+ } \
+ extern "C++" inline auto reveal_##name##_vec(wasm_##name##_t ptr_or_none* v) \
+ ->vec<Name>::elem_type* { \
+ return reinterpret_cast<vec<Name>::elem_type*>(v); \
+ } \
+ extern "C++" inline auto reveal_##name##_vec( \
+ wasm_##name##_t ptr_or_none const* v) \
+ ->const vec<Name>::elem_type* { \
+ return reinterpret_cast<const vec<Name>::elem_type*>(v); \
+ } \
+ extern "C++" inline auto get_##name##_vec(vec<Name>& v) \
+ ->wasm_##name##_vec_t { \
+ wasm_##name##_vec_t v2 = {v.size(), hide_##name##_vec(v.get())}; \
+ return v2; \
+ } \
+ extern "C++" inline auto get_##name##_vec(const vec<Name>& v) \
+ ->const wasm_##name##_vec_t { \
+ wasm_##name##_vec_t v2 = { \
+ v.size(), \
+ const_cast<wasm_##name##_t ptr_or_none*>(hide_##name##_vec(v.get()))}; \
+ return v2; \
+ } \
+ extern "C++" inline auto release_##name##_vec(vec<Name>&& v) \
+ ->wasm_##name##_vec_t { \
+ wasm_##name##_vec_t v2 = {v.size(), hide_##name##_vec(v.release())}; \
+ return v2; \
+ } \
+ extern "C++" inline auto adopt_##name##_vec(wasm_##name##_vec_t* v) \
+ ->vec<Name> { \
+ return vec<Name>::adopt(v->size, reveal_##name##_vec(v->data)); \
+ } \
+ extern "C++" inline auto borrow_##name##_vec(const wasm_##name##_vec_t* v) \
+ ->borrowed_vec<vec<Name>::elem_type> { \
+ return borrowed_vec<vec<Name>::elem_type>( \
+ vec<Name>::adopt(v->size, reveal_##name##_vec(v->data))); \
+ } \
+ \
+ void wasm_##name##_vec_new_uninitialized(wasm_##name##_vec_t* out, \
+ size_t size) { \
+ *out = release_##name##_vec(vec<Name>::make_uninitialized(size)); \
+ } \
+ void wasm_##name##_vec_new_empty(wasm_##name##_vec_t* out) { \
+ wasm_##name##_vec_new_uninitialized(out, 0); \
+ } \
+ \
+ void wasm_##name##_vec_delete(wasm_##name##_vec_t* v) { \
+ adopt_##name##_vec(v); \
+ }
// Vectors with no ownership management of elements
-#define WASM_DEFINE_VEC_PLAIN(name, Name, ptr_or_none) \
- WASM_DEFINE_VEC_BASE(name, Name, ptr_or_none) \
- \
- void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
- wasm_##name##_t ptr_or_none const data[]) { \
- auto v2 = wasm::vec<Name ptr_or_none>::make_uninitialized(size); \
- if (v2.size() != 0) { \
- memcpy(v2.get(), data, size * sizeof(wasm_##name##_t ptr_or_none)); \
- } \
- *out = release(std::move(v2)); \
- } \
- \
- void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
- wasm_##name##_vec_t* v) { \
- wasm_##name##_vec_new(out, v->size, v->data); \
- }
-
-// Vectors who own their elements
-#define WASM_DEFINE_VEC(name, Name, ptr_or_none) \
- WASM_DEFINE_VEC_BASE(name, Name, ptr_or_none) \
- \
- void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
- wasm_##name##_t ptr_or_none const data[]) { \
- auto v2 = wasm::vec<Name ptr_or_none>::make_uninitialized(size); \
- for (size_t i = 0; i < v2.size(); ++i) { \
- v2[i] = adopt(data[i]); \
- } \
- *out = release(std::move(v2)); \
- } \
- \
- void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
- wasm_##name##_vec_t* v) { \
- auto v2 = wasm::vec<Name ptr_or_none>::make_uninitialized(v->size); \
- for (size_t i = 0; i < v2.size(); ++i) { \
- v2[i] = adopt(wasm_##name##_copy(v->data[i])); \
- } \
- *out = release(std::move(v2)); \
+#define WASM_DEFINE_VEC_PLAIN(name, Name) \
+ WASM_DEFINE_VEC_BASE(name, Name, \
+ wasm::vec, ) /* NOLINT(whitespace/parens) */ \
+ \
+ void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
+ const wasm_##name##_t data[]) { \
+ auto v2 = wasm::vec<Name>::make_uninitialized(size); \
+ if (v2.size() != 0) { \
+ memcpy(v2.get(), data, size * sizeof(wasm_##name##_t)); \
+ } \
+ *out = release_##name##_vec(std::move(v2)); \
+ } \
+ \
+ void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
+ wasm_##name##_vec_t* v) { \
+ wasm_##name##_vec_new(out, v->size, v->data); \
+ }
+
+// Vectors that own their elements
+#define WASM_DEFINE_VEC_OWN(name, Name) \
+ WASM_DEFINE_VEC_BASE(name, Name, wasm::ownvec, *) \
+ \
+ void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
+ wasm_##name##_t* const data[]) { \
+ auto v2 = wasm::ownvec<Name>::make_uninitialized(size); \
+ for (size_t i = 0; i < v2.size(); ++i) { \
+ v2[i] = adopt_##name(data[i]); \
+ } \
+ *out = release_##name##_vec(std::move(v2)); \
+ } \
+ \
+ void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
+ wasm_##name##_vec_t* v) { \
+ auto v2 = wasm::ownvec<Name>::make_uninitialized(v->size); \
+ for (size_t i = 0; i < v2.size(); ++i) { \
+ v2[i] = adopt_##name(wasm_##name##_copy(v->data[i])); \
+ } \
+ *out = release_##name##_vec(std::move(v2)); \
}
extern "C++" {
@@ -2056,7 +2234,7 @@ inline auto is_empty(T* p) -> bool {
// Byte vectors
using byte = byte_t;
-WASM_DEFINE_VEC_PLAIN(byte, byte, )
+WASM_DEFINE_VEC_PLAIN(byte, byte)
///////////////////////////////////////////////////////////////////////////////
// Runtime Environment
@@ -2065,16 +2243,20 @@ WASM_DEFINE_VEC_PLAIN(byte, byte, )
WASM_DEFINE_OWN(config, wasm::Config)
-wasm_config_t* wasm_config_new() { return release(wasm::Config::make()); }
+wasm_config_t* wasm_config_new() {
+ return release_config(wasm::Config::make());
+}
// Engine
WASM_DEFINE_OWN(engine, wasm::Engine)
-wasm_engine_t* wasm_engine_new() { return release(wasm::Engine::make()); }
+wasm_engine_t* wasm_engine_new() {
+ return release_engine(wasm::Engine::make());
+}
wasm_engine_t* wasm_engine_new_with_config(wasm_config_t* config) {
- return release(wasm::Engine::make(adopt(config)));
+ return release_engine(wasm::Engine::make(adopt_config(config)));
}
// Stores
@@ -2082,7 +2264,7 @@ wasm_engine_t* wasm_engine_new_with_config(wasm_config_t* config) {
WASM_DEFINE_OWN(store, wasm::Store)
wasm_store_t* wasm_store_new(wasm_engine_t* engine) {
- return release(wasm::Store::make(engine));
+ return release_store(wasm::Store::make(engine));
}
///////////////////////////////////////////////////////////////////////////////
@@ -2090,38 +2272,40 @@ wasm_store_t* wasm_store_new(wasm_engine_t* engine) {
// Type attributes
-extern "C++" inline auto hide(wasm::Mutability mutability)
+extern "C++" inline auto hide_mutability(wasm::Mutability mutability)
-> wasm_mutability_t {
return static_cast<wasm_mutability_t>(mutability);
}
-extern "C++" inline auto reveal(wasm_mutability_t mutability)
+extern "C++" inline auto reveal_mutability(wasm_mutability_t mutability)
-> wasm::Mutability {
return static_cast<wasm::Mutability>(mutability);
}
-extern "C++" inline auto hide(const wasm::Limits& limits)
+extern "C++" inline auto hide_limits(const wasm::Limits& limits)
-> const wasm_limits_t* {
return reinterpret_cast<const wasm_limits_t*>(&limits);
}
-extern "C++" inline auto reveal(wasm_limits_t limits) -> wasm::Limits {
+extern "C++" inline auto reveal_limits(wasm_limits_t limits) -> wasm::Limits {
return wasm::Limits(limits.min, limits.max);
}
-extern "C++" inline auto hide(wasm::ValKind kind) -> wasm_valkind_t {
+extern "C++" inline auto hide_valkind(wasm::ValKind kind) -> wasm_valkind_t {
return static_cast<wasm_valkind_t>(kind);
}
-extern "C++" inline auto reveal(wasm_valkind_t kind) -> wasm::ValKind {
+extern "C++" inline auto reveal_valkind(wasm_valkind_t kind) -> wasm::ValKind {
return static_cast<wasm::ValKind>(kind);
}
-extern "C++" inline auto hide(wasm::ExternKind kind) -> wasm_externkind_t {
+extern "C++" inline auto hide_externkind(wasm::ExternKind kind)
+ -> wasm_externkind_t {
return static_cast<wasm_externkind_t>(kind);
}
-extern "C++" inline auto reveal(wasm_externkind_t kind) -> wasm::ExternKind {
+extern "C++" inline auto reveal_externkind(wasm_externkind_t kind)
+ -> wasm::ExternKind {
return static_cast<wasm::ExternKind>(kind);
}
@@ -2129,10 +2313,10 @@ extern "C++" inline auto reveal(wasm_externkind_t kind) -> wasm::ExternKind {
#define WASM_DEFINE_TYPE(name, Name) \
WASM_DEFINE_OWN(name, Name) \
- WASM_DEFINE_VEC(name, Name, *) \
+ WASM_DEFINE_VEC_OWN(name, Name) \
\
wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t* t) { \
- return release(t->copy()); \
+ return release_##name(t->copy()); \
}
// Value Types
@@ -2140,11 +2324,11 @@ extern "C++" inline auto reveal(wasm_externkind_t kind) -> wasm::ExternKind {
WASM_DEFINE_TYPE(valtype, wasm::ValType)
wasm_valtype_t* wasm_valtype_new(wasm_valkind_t k) {
- return release(wasm::ValType::make(reveal(k)));
+ return release_valtype(wasm::ValType::make(reveal_valkind(k)));
}
wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t* t) {
- return hide(t->kind());
+ return hide_valkind(t->kind());
}
// Function Types
@@ -2153,15 +2337,16 @@ WASM_DEFINE_TYPE(functype, wasm::FuncType)
wasm_functype_t* wasm_functype_new(wasm_valtype_vec_t* params,
wasm_valtype_vec_t* results) {
- return release(wasm::FuncType::make(adopt(params), adopt(results)));
+ return release_functype(wasm::FuncType::make(adopt_valtype_vec(params),
+ adopt_valtype_vec(results)));
}
const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t* ft) {
- return hide(ft->params());
+ return hide_valtype_vec(ft->params());
}
const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t* ft) {
- return hide(ft->results());
+ return hide_valtype_vec(ft->results());
}
// Global Types
@@ -2170,15 +2355,16 @@ WASM_DEFINE_TYPE(globaltype, wasm::GlobalType)
wasm_globaltype_t* wasm_globaltype_new(wasm_valtype_t* content,
wasm_mutability_t mutability) {
- return release(wasm::GlobalType::make(adopt(content), reveal(mutability)));
+ return release_globaltype(wasm::GlobalType::make(
+ adopt_valtype(content), reveal_mutability(mutability)));
}
const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t* gt) {
- return hide(gt->content());
+ return hide_valtype(gt->content());
}
wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t* gt) {
- return hide(gt->mutability());
+ return hide_mutability(gt->mutability());
}
// Table Types
@@ -2187,15 +2373,16 @@ WASM_DEFINE_TYPE(tabletype, wasm::TableType)
wasm_tabletype_t* wasm_tabletype_new(wasm_valtype_t* element,
const wasm_limits_t* limits) {
- return release(wasm::TableType::make(adopt(element), reveal(*limits)));
+ return release_tabletype(
+ wasm::TableType::make(adopt_valtype(element), reveal_limits(*limits)));
}
const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t* tt) {
- return hide(tt->element());
+ return hide_valtype(tt->element());
}
const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t* tt) {
- return hide(tt->limits());
+ return hide_limits(tt->limits());
}
// Memory Types
@@ -2203,11 +2390,11 @@ const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t* tt) {
WASM_DEFINE_TYPE(memorytype, wasm::MemoryType)
wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t* limits) {
- return release(wasm::MemoryType::make(reveal(*limits)));
+ return release_memorytype(wasm::MemoryType::make(reveal_limits(*limits)));
}
const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t* mt) {
- return hide(mt->limits());
+ return hide_limits(mt->limits());
}
// Extern Types
@@ -2215,82 +2402,90 @@ const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t* mt) {
WASM_DEFINE_TYPE(externtype, wasm::ExternType)
wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t* et) {
- return hide(et->kind());
+ return hide_externkind(et->kind());
}
wasm_externtype_t* wasm_functype_as_externtype(wasm_functype_t* ft) {
- return hide(static_cast<wasm::ExternType*>(ft));
+ return hide_externtype(static_cast<wasm::ExternType*>(ft));
}
wasm_externtype_t* wasm_globaltype_as_externtype(wasm_globaltype_t* gt) {
- return hide(static_cast<wasm::ExternType*>(gt));
+ return hide_externtype(static_cast<wasm::ExternType*>(gt));
}
wasm_externtype_t* wasm_tabletype_as_externtype(wasm_tabletype_t* tt) {
- return hide(static_cast<wasm::ExternType*>(tt));
+ return hide_externtype(static_cast<wasm::ExternType*>(tt));
}
wasm_externtype_t* wasm_memorytype_as_externtype(wasm_memorytype_t* mt) {
- return hide(static_cast<wasm::ExternType*>(mt));
+ return hide_externtype(static_cast<wasm::ExternType*>(mt));
}
const wasm_externtype_t* wasm_functype_as_externtype_const(
const wasm_functype_t* ft) {
- return hide(static_cast<const wasm::ExternType*>(ft));
+ return hide_externtype(static_cast<const wasm::ExternType*>(ft));
}
const wasm_externtype_t* wasm_globaltype_as_externtype_const(
const wasm_globaltype_t* gt) {
- return hide(static_cast<const wasm::ExternType*>(gt));
+ return hide_externtype(static_cast<const wasm::ExternType*>(gt));
}
const wasm_externtype_t* wasm_tabletype_as_externtype_const(
const wasm_tabletype_t* tt) {
- return hide(static_cast<const wasm::ExternType*>(tt));
+ return hide_externtype(static_cast<const wasm::ExternType*>(tt));
}
const wasm_externtype_t* wasm_memorytype_as_externtype_const(
const wasm_memorytype_t* mt) {
- return hide(static_cast<const wasm::ExternType*>(mt));
+ return hide_externtype(static_cast<const wasm::ExternType*>(mt));
}
wasm_functype_t* wasm_externtype_as_functype(wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_FUNC
- ? hide(static_cast<wasm::FuncType*>(reveal(et)))
+ ? hide_functype(
+ static_cast<wasm::FuncType*>(reveal_externtype(et)))
: nullptr;
}
wasm_globaltype_t* wasm_externtype_as_globaltype(wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_GLOBAL
- ? hide(static_cast<wasm::GlobalType*>(reveal(et)))
+ ? hide_globaltype(
+ static_cast<wasm::GlobalType*>(reveal_externtype(et)))
: nullptr;
}
wasm_tabletype_t* wasm_externtype_as_tabletype(wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_TABLE
- ? hide(static_cast<wasm::TableType*>(reveal(et)))
+ ? hide_tabletype(
+ static_cast<wasm::TableType*>(reveal_externtype(et)))
: nullptr;
}
wasm_memorytype_t* wasm_externtype_as_memorytype(wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_MEMORY
- ? hide(static_cast<wasm::MemoryType*>(reveal(et)))
+ ? hide_memorytype(
+ static_cast<wasm::MemoryType*>(reveal_externtype(et)))
: nullptr;
}
const wasm_functype_t* wasm_externtype_as_functype_const(
const wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_FUNC
- ? hide(static_cast<const wasm::FuncType*>(reveal(et)))
+ ? hide_functype(
+ static_cast<const wasm::FuncType*>(reveal_externtype(et)))
: nullptr;
}
const wasm_globaltype_t* wasm_externtype_as_globaltype_const(
const wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_GLOBAL
- ? hide(static_cast<const wasm::GlobalType*>(reveal(et)))
+ ? hide_globaltype(
+ static_cast<const wasm::GlobalType*>(reveal_externtype(et)))
: nullptr;
}
const wasm_tabletype_t* wasm_externtype_as_tabletype_const(
const wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_TABLE
- ? hide(static_cast<const wasm::TableType*>(reveal(et)))
+ ? hide_tabletype(
+ static_cast<const wasm::TableType*>(reveal_externtype(et)))
: nullptr;
}
const wasm_memorytype_t* wasm_externtype_as_memorytype_const(
const wasm_externtype_t* et) {
return et->kind() == wasm::EXTERN_MEMORY
- ? hide(static_cast<const wasm::MemoryType*>(reveal(et)))
+ ? hide_memorytype(
+ static_cast<const wasm::MemoryType*>(reveal_externtype(et)))
: nullptr;
}
@@ -2300,20 +2495,20 @@ WASM_DEFINE_TYPE(importtype, wasm::ImportType)
wasm_importtype_t* wasm_importtype_new(wasm_name_t* module, wasm_name_t* name,
wasm_externtype_t* type) {
- return release(
- wasm::ImportType::make(adopt(module), adopt(name), adopt(type)));
+ return release_importtype(wasm::ImportType::make(
+ adopt_byte_vec(module), adopt_byte_vec(name), adopt_externtype(type)));
}
const wasm_name_t* wasm_importtype_module(const wasm_importtype_t* it) {
- return hide(it->module());
+ return hide_byte_vec(it->module());
}
const wasm_name_t* wasm_importtype_name(const wasm_importtype_t* it) {
- return hide(it->name());
+ return hide_byte_vec(it->name());
}
const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t* it) {
- return hide(it->type());
+ return hide_externtype(it->type());
}
// Export Types
@@ -2322,15 +2517,16 @@ WASM_DEFINE_TYPE(exporttype, wasm::ExportType)
wasm_exporttype_t* wasm_exporttype_new(wasm_name_t* name,
wasm_externtype_t* type) {
- return release(wasm::ExportType::make(adopt(name), adopt(type)));
+ return release_exporttype(
+ wasm::ExportType::make(adopt_byte_vec(name), adopt_externtype(type)));
}
const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t* et) {
- return hide(et->name());
+ return hide_byte_vec(et->name());
}
const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* et) {
- return hide(et->type());
+ return hide_externtype(et->type());
}
///////////////////////////////////////////////////////////////////////////////
@@ -2342,7 +2538,12 @@ const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* et) {
WASM_DEFINE_OWN(name, Name) \
\
wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t* t) { \
- return release(t->copy()); \
+ return release_##name(t->copy()); \
+ } \
+ \
+ bool wasm_##name##_same(const wasm_##name##_t* t1, \
+ const wasm_##name##_t* t2) { \
+ return t1->same(t2); \
} \
\
void* wasm_##name##_get_host_info(const wasm_##name##_t* r) { \
@@ -2360,17 +2561,17 @@ const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* et) {
WASM_DEFINE_REF_BASE(name, Name) \
\
wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t* r) { \
- return hide(static_cast<wasm::Ref*>(reveal(r))); \
+ return hide_ref(static_cast<wasm::Ref*>(reveal_##name(r))); \
} \
wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t* r) { \
- return hide(static_cast<Name*>(reveal(r))); \
+ return hide_##name(static_cast<Name*>(reveal_ref(r))); \
} \
\
const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t* r) { \
- return hide(static_cast<const wasm::Ref*>(reveal(r))); \
+ return hide_ref(static_cast<const wasm::Ref*>(reveal_##name(r))); \
} \
const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t* r) { \
- return hide(static_cast<const Name*>(reveal(r))); \
+ return hide_##name(static_cast<const Name*>(reveal_ref(r))); \
}
#define WASM_DEFINE_SHARABLE_REF(name, Name) \
@@ -2384,11 +2585,11 @@ WASM_DEFINE_REF_BASE(ref, wasm::Ref)
extern "C++" {
inline auto is_empty(wasm_val_t v) -> bool {
- return !is_ref(reveal(v.kind)) || !v.of.ref;
+ return !is_ref(reveal_valkind(v.kind)) || !v.of.ref;
}
-inline auto hide(wasm::Val v) -> wasm_val_t {
- wasm_val_t v2 = {hide(v.kind()), {}};
+inline auto hide_val(wasm::Val v) -> wasm_val_t {
+ wasm_val_t v2 = {hide_valkind(v.kind()), {}};
switch (v.kind()) {
case wasm::I32:
v2.of.i32 = v.i32();
@@ -2404,7 +2605,7 @@ inline auto hide(wasm::Val v) -> wasm_val_t {
break;
case wasm::ANYREF:
case wasm::FUNCREF:
- v2.of.ref = hide(v.ref());
+ v2.of.ref = hide_ref(v.ref());
break;
default:
UNREACHABLE();
@@ -2412,8 +2613,8 @@ inline auto hide(wasm::Val v) -> wasm_val_t {
return v2;
}
-inline auto release(wasm::Val v) -> wasm_val_t {
- wasm_val_t v2 = {hide(v.kind()), {}};
+inline auto release_val(wasm::Val v) -> wasm_val_t {
+ wasm_val_t v2 = {hide_valkind(v.kind()), {}};
switch (v.kind()) {
case wasm::I32:
v2.of.i32 = v.i32();
@@ -2429,7 +2630,7 @@ inline auto release(wasm::Val v) -> wasm_val_t {
break;
case wasm::ANYREF:
case wasm::FUNCREF:
- v2.of.ref = release(v.release_ref());
+ v2.of.ref = release_ref(v.release_ref());
break;
default:
UNREACHABLE();
@@ -2437,8 +2638,8 @@ inline auto release(wasm::Val v) -> wasm_val_t {
return v2;
}
-inline auto adopt(wasm_val_t v) -> wasm::Val {
- switch (reveal(v.kind)) {
+inline auto adopt_val(wasm_val_t v) -> wasm::Val {
+ switch (reveal_valkind(v.kind)) {
case wasm::I32:
return wasm::Val(v.of.i32);
case wasm::I64:
@@ -2449,7 +2650,7 @@ inline auto adopt(wasm_val_t v) -> wasm::Val {
return wasm::Val(v.of.f64);
case wasm::ANYREF:
case wasm::FUNCREF:
- return wasm::Val(adopt(v.of.ref));
+ return wasm::Val(adopt_ref(v.of.ref));
default:
UNREACHABLE();
}
@@ -2460,13 +2661,13 @@ struct borrowed_val {
explicit borrowed_val(wasm::Val&& v) : it(std::move(v)) {}
borrowed_val(borrowed_val&& that) : it(std::move(that.it)) {}
~borrowed_val() {
- if (it.is_ref()) it.release_ref();
+ if (it.is_ref()) it.release_ref().release();
}
};
-inline auto borrow(const wasm_val_t* v) -> borrowed_val {
+inline auto borrow_val(const wasm_val_t* v) -> borrowed_val {
wasm::Val v2;
- switch (reveal(v->kind)) {
+ switch (reveal_valkind(v->kind)) {
case wasm::I32:
v2 = wasm::Val(v->of.i32);
break;
@@ -2481,7 +2682,7 @@ inline auto borrow(const wasm_val_t* v) -> borrowed_val {
break;
case wasm::ANYREF:
case wasm::FUNCREF:
- v2 = wasm::Val(adopt(v->of.ref));
+ v2 = wasm::Val(adopt_ref(v->of.ref));
break;
default:
UNREACHABLE();
@@ -2491,15 +2692,15 @@ inline auto borrow(const wasm_val_t* v) -> borrowed_val {
} // extern "C++"
-WASM_DEFINE_VEC_BASE(val, wasm::Val, )
+WASM_DEFINE_VEC_BASE(val, wasm::Val, wasm::vec, )
void wasm_val_vec_new(wasm_val_vec_t* out, size_t size,
wasm_val_t const data[]) {
auto v2 = wasm::vec<wasm::Val>::make_uninitialized(size);
for (size_t i = 0; i < v2.size(); ++i) {
- v2[i] = adopt(data[i]);
+ v2[i] = adopt_val(data[i]);
}
- *out = release(std::move(v2));
+ *out = release_val_vec(std::move(v2));
}
void wasm_val_vec_copy(wasm_val_vec_t* out, wasm_val_vec_t* v) {
@@ -2507,36 +2708,70 @@ void wasm_val_vec_copy(wasm_val_vec_t* out, wasm_val_vec_t* v) {
for (size_t i = 0; i < v2.size(); ++i) {
wasm_val_t val;
wasm_val_copy(&v->data[i], &val);
- v2[i] = adopt(val);
+ v2[i] = adopt_val(val);
}
- *out = release(std::move(v2));
+ *out = release_val_vec(std::move(v2));
}
void wasm_val_delete(wasm_val_t* v) {
- if (is_ref(reveal(v->kind))) adopt(v->of.ref);
+ if (is_ref(reveal_valkind(v->kind))) {
+ adopt_ref(v->of.ref);
+ }
}
void wasm_val_copy(wasm_val_t* out, const wasm_val_t* v) {
*out = *v;
- if (is_ref(reveal(v->kind))) {
- out->of.ref = release(v->of.ref->copy());
+ if (is_ref(reveal_valkind(v->kind))) {
+ out->of.ref = v->of.ref ? release_ref(v->of.ref->copy()) : nullptr;
}
}
///////////////////////////////////////////////////////////////////////////////
// Runtime Objects
+// Frames
+
+WASM_DEFINE_OWN(frame, wasm::Frame)
+WASM_DEFINE_VEC_OWN(frame, wasm::Frame)
+
+wasm_frame_t* wasm_frame_copy(const wasm_frame_t* frame) {
+ return release_frame(frame->copy());
+}
+
+wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame);
+// Defined below along with wasm_instance_t.
+
+uint32_t wasm_frame_func_index(const wasm_frame_t* frame) {
+ return reveal_frame(frame)->func_index();
+}
+
+size_t wasm_frame_func_offset(const wasm_frame_t* frame) {
+ return reveal_frame(frame)->func_offset();
+}
+
+size_t wasm_frame_module_offset(const wasm_frame_t* frame) {
+ return reveal_frame(frame)->module_offset();
+}
+
// Traps
WASM_DEFINE_REF(trap, wasm::Trap)
wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t* message) {
- auto message_ = borrow(message);
- return release(wasm::Trap::make(store, message_.it));
+ auto message_ = borrow_byte_vec(message);
+ return release_trap(wasm::Trap::make(store, message_.it));
}
void wasm_trap_message(const wasm_trap_t* trap, wasm_message_t* out) {
- *out = release(reveal(trap)->message());
+ *out = release_byte_vec(reveal_trap(trap)->message());
+}
+
+wasm_frame_t* wasm_trap_origin(const wasm_trap_t* trap) {
+ return release_frame(reveal_trap(trap)->origin());
+}
+
+void wasm_trap_trace(const wasm_trap_t* trap, wasm_frame_vec_t* out) {
+ *out = release_frame_vec(reveal_trap(trap)->trace());
}
// Foreign Objects
@@ -2544,7 +2779,7 @@ void wasm_trap_message(const wasm_trap_t* trap, wasm_message_t* out) {
WASM_DEFINE_REF(foreign, wasm::Foreign)
wasm_foreign_t* wasm_foreign_new(wasm_store_t* store) {
- return release(wasm::Foreign::make(store));
+ return release_foreign(wasm::Foreign::make(store));
}
// Modules
@@ -2552,43 +2787,43 @@ wasm_foreign_t* wasm_foreign_new(wasm_store_t* store) {
WASM_DEFINE_SHARABLE_REF(module, wasm::Module)
bool wasm_module_validate(wasm_store_t* store, const wasm_byte_vec_t* binary) {
- auto binary_ = borrow(binary);
+ auto binary_ = borrow_byte_vec(binary);
return wasm::Module::validate(store, binary_.it);
}
wasm_module_t* wasm_module_new(wasm_store_t* store,
const wasm_byte_vec_t* binary) {
- auto binary_ = borrow(binary);
- return release(wasm::Module::make(store, binary_.it));
+ auto binary_ = borrow_byte_vec(binary);
+ return release_module(wasm::Module::make(store, binary_.it));
}
void wasm_module_imports(const wasm_module_t* module,
wasm_importtype_vec_t* out) {
- *out = release(reveal(module)->imports());
+ *out = release_importtype_vec(reveal_module(module)->imports());
}
void wasm_module_exports(const wasm_module_t* module,
wasm_exporttype_vec_t* out) {
- *out = release(reveal(module)->exports());
+ *out = release_exporttype_vec(reveal_module(module)->exports());
}
void wasm_module_serialize(const wasm_module_t* module, wasm_byte_vec_t* out) {
- *out = release(reveal(module)->serialize());
+ *out = release_byte_vec(reveal_module(module)->serialize());
}
wasm_module_t* wasm_module_deserialize(wasm_store_t* store,
const wasm_byte_vec_t* binary) {
- auto binary_ = borrow(binary);
- return release(wasm::Module::deserialize(store, binary_.it));
+ auto binary_ = borrow_byte_vec(binary);
+ return release_module(wasm::Module::deserialize(store, binary_.it));
}
wasm_shared_module_t* wasm_module_share(const wasm_module_t* module) {
- return release(reveal(module)->share());
+ return release_shared_module(reveal_module(module)->share());
}
wasm_module_t* wasm_module_obtain(wasm_store_t* store,
const wasm_shared_module_t* shared) {
- return release(wasm::Module::obtain(store, shared));
+ return release_module(wasm::Module::obtain(store, shared));
}
// Function Instances
@@ -2598,9 +2833,9 @@ WASM_DEFINE_REF(func, wasm::Func)
extern "C++" {
auto wasm_callback(void* env, const wasm::Val args[], wasm::Val results[])
- -> wasm::own<wasm::Trap*> {
+ -> wasm::own<wasm::Trap> {
auto f = reinterpret_cast<wasm_func_callback_t>(env);
- return adopt(f(hide(args), hide(results)));
+ return adopt_trap(f(hide_val_vec(args), hide_val_vec(results)));
}
struct wasm_callback_env_t {
@@ -2610,9 +2845,10 @@ struct wasm_callback_env_t {
};
auto wasm_callback_with_env(void* env, const wasm::Val args[],
- wasm::Val results[]) -> wasm::own<wasm::Trap*> {
+ wasm::Val results[]) -> wasm::own<wasm::Trap> {
auto t = static_cast<wasm_callback_env_t*>(env);
- return adopt(t->callback(t->env, hide(args), hide(results)));
+ return adopt_trap(
+ t->callback(t->env, hide_val_vec(args), hide_val_vec(results)));
}
void wasm_callback_env_finalizer(void* env) {
@@ -2625,8 +2861,8 @@ void wasm_callback_env_finalizer(void* env) {
wasm_func_t* wasm_func_new(wasm_store_t* store, const wasm_functype_t* type,
wasm_func_callback_t callback) {
- return release(wasm::Func::make(store, type, wasm_callback,
- reinterpret_cast<void*>(callback)));
+ return release_func(wasm::Func::make(store, type, wasm_callback,
+ reinterpret_cast<void*>(callback)));
}
wasm_func_t* wasm_func_new_with_env(wasm_store_t* store,
@@ -2634,12 +2870,12 @@ wasm_func_t* wasm_func_new_with_env(wasm_store_t* store,
wasm_func_callback_with_env_t callback,
void* env, void (*finalizer)(void*)) {
auto env2 = new wasm_callback_env_t{callback, env, finalizer};
- return release(wasm::Func::make(store, type, wasm_callback_with_env, env2,
- wasm_callback_env_finalizer));
+ return release_func(wasm::Func::make(store, type, wasm_callback_with_env,
+ env2, wasm_callback_env_finalizer));
}
wasm_functype_t* wasm_func_type(const wasm_func_t* func) {
- return release(func->type());
+ return release_functype(func->type());
}
size_t wasm_func_param_arity(const wasm_func_t* func) {
@@ -2652,7 +2888,8 @@ size_t wasm_func_result_arity(const wasm_func_t* func) {
wasm_trap_t* wasm_func_call(const wasm_func_t* func, const wasm_val_t args[],
wasm_val_t results[]) {
- return release(func->call(reveal(args), reveal(results)));
+ return release_trap(
+ func->call(reveal_val_vec(args), reveal_val_vec(results)));
}
// Global Instances
@@ -2662,20 +2899,20 @@ WASM_DEFINE_REF(global, wasm::Global)
wasm_global_t* wasm_global_new(wasm_store_t* store,
const wasm_globaltype_t* type,
const wasm_val_t* val) {
- auto val_ = borrow(val);
- return release(wasm::Global::make(store, type, val_.it));
+ auto val_ = borrow_val(val);
+ return release_global(wasm::Global::make(store, type, val_.it));
}
wasm_globaltype_t* wasm_global_type(const wasm_global_t* global) {
- return release(global->type());
+ return release_globaltype(global->type());
}
void wasm_global_get(const wasm_global_t* global, wasm_val_t* out) {
- *out = release(global->get());
+ *out = release_val(global->get());
}
void wasm_global_set(wasm_global_t* global, const wasm_val_t* val) {
- auto val_ = borrow(val);
+ auto val_ = borrow_val(val);
global->set(val_.it);
}
@@ -2685,15 +2922,15 @@ WASM_DEFINE_REF(table, wasm::Table)
wasm_table_t* wasm_table_new(wasm_store_t* store, const wasm_tabletype_t* type,
wasm_ref_t* ref) {
- return release(wasm::Table::make(store, type, ref));
+ return release_table(wasm::Table::make(store, type, ref));
}
wasm_tabletype_t* wasm_table_type(const wasm_table_t* table) {
- return release(table->type());
+ return release_tabletype(table->type());
}
wasm_ref_t* wasm_table_get(const wasm_table_t* table, wasm_table_size_t index) {
- return release(table->get(index));
+ return release_ref(table->get(index));
}
bool wasm_table_set(wasm_table_t* table, wasm_table_size_t index,
@@ -2716,11 +2953,11 @@ WASM_DEFINE_REF(memory, wasm::Memory)
wasm_memory_t* wasm_memory_new(wasm_store_t* store,
const wasm_memorytype_t* type) {
- return release(wasm::Memory::make(store, type));
+ return release_memory(wasm::Memory::make(store, type));
}
wasm_memorytype_t* wasm_memory_type(const wasm_memory_t* memory) {
- return release(memory->type());
+ return release_memorytype(memory->type());
}
wasm_byte_t* wasm_memory_data(wasm_memory_t* memory) { return memory->data(); }
@@ -2740,67 +2977,67 @@ bool wasm_memory_grow(wasm_memory_t* memory, wasm_memory_pages_t delta) {
// Externals
WASM_DEFINE_REF(extern, wasm::Extern)
-WASM_DEFINE_VEC(extern, wasm::Extern, *)
+WASM_DEFINE_VEC_OWN(extern, wasm::Extern)
wasm_externkind_t wasm_extern_kind(const wasm_extern_t* external) {
- return hide(external->kind());
+ return hide_externkind(external->kind());
}
wasm_externtype_t* wasm_extern_type(const wasm_extern_t* external) {
- return release(external->type());
+ return release_externtype(external->type());
}
wasm_extern_t* wasm_func_as_extern(wasm_func_t* func) {
- return hide(static_cast<wasm::Extern*>(reveal(func)));
+ return hide_extern(static_cast<wasm::Extern*>(reveal_func(func)));
}
wasm_extern_t* wasm_global_as_extern(wasm_global_t* global) {
- return hide(static_cast<wasm::Extern*>(reveal(global)));
+ return hide_extern(static_cast<wasm::Extern*>(reveal_global(global)));
}
wasm_extern_t* wasm_table_as_extern(wasm_table_t* table) {
- return hide(static_cast<wasm::Extern*>(reveal(table)));
+ return hide_extern(static_cast<wasm::Extern*>(reveal_table(table)));
}
wasm_extern_t* wasm_memory_as_extern(wasm_memory_t* memory) {
- return hide(static_cast<wasm::Extern*>(reveal(memory)));
+ return hide_extern(static_cast<wasm::Extern*>(reveal_memory(memory)));
}
const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t* func) {
- return hide(static_cast<const wasm::Extern*>(reveal(func)));
+ return hide_extern(static_cast<const wasm::Extern*>(reveal_func(func)));
}
const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t* global) {
- return hide(static_cast<const wasm::Extern*>(reveal(global)));
+ return hide_extern(static_cast<const wasm::Extern*>(reveal_global(global)));
}
const wasm_extern_t* wasm_table_as_extern_const(const wasm_table_t* table) {
- return hide(static_cast<const wasm::Extern*>(reveal(table)));
+ return hide_extern(static_cast<const wasm::Extern*>(reveal_table(table)));
}
const wasm_extern_t* wasm_memory_as_extern_const(const wasm_memory_t* memory) {
- return hide(static_cast<const wasm::Extern*>(reveal(memory)));
+ return hide_extern(static_cast<const wasm::Extern*>(reveal_memory(memory)));
}
wasm_func_t* wasm_extern_as_func(wasm_extern_t* external) {
- return hide(external->func());
+ return hide_func(external->func());
}
wasm_global_t* wasm_extern_as_global(wasm_extern_t* external) {
- return hide(external->global());
+ return hide_global(external->global());
}
wasm_table_t* wasm_extern_as_table(wasm_extern_t* external) {
- return hide(external->table());
+ return hide_table(external->table());
}
wasm_memory_t* wasm_extern_as_memory(wasm_extern_t* external) {
- return hide(external->memory());
+ return hide_memory(external->memory());
}
const wasm_func_t* wasm_extern_as_func_const(const wasm_extern_t* external) {
- return hide(external->func());
+ return hide_func(external->func());
}
const wasm_global_t* wasm_extern_as_global_const(
const wasm_extern_t* external) {
- return hide(external->global());
+ return hide_global(external->global());
}
const wasm_table_t* wasm_extern_as_table_const(const wasm_extern_t* external) {
- return hide(external->table());
+ return hide_table(external->table());
}
const wasm_memory_t* wasm_extern_as_memory_const(
const wasm_extern_t* external) {
- return hide(external->memory());
+ return hide_memory(external->memory());
}
// Module Instances
@@ -2809,20 +3046,29 @@ WASM_DEFINE_REF(instance, wasm::Instance)
wasm_instance_t* wasm_instance_new(wasm_store_t* store,
const wasm_module_t* module,
- const wasm_extern_t* const imports[]) {
- return release(wasm::Instance::make(
- store, module, reinterpret_cast<const wasm::Extern* const*>(imports)));
+ const wasm_extern_t* const imports[],
+ wasm_trap_t** trap) {
+ wasm::own<wasm::Trap> error;
+ wasm_instance_t* instance = release_instance(wasm::Instance::make(
+ store, module, reinterpret_cast<const wasm::Extern* const*>(imports),
+ &error));
+ if (trap) *trap = hide_trap(error.release());
+ return instance;
}
void wasm_instance_exports(const wasm_instance_t* instance,
wasm_extern_vec_t* out) {
- *out = release(instance->exports());
+ *out = release_extern_vec(instance->exports());
+}
+
+wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) {
+ return hide_instance(reveal_frame(frame)->instance());
}
#undef WASM_DEFINE_OWN
#undef WASM_DEFINE_VEC_BASE
#undef WASM_DEFINE_VEC_PLAIN
-#undef WASM_DEFINE_VEC
+#undef WASM_DEFINE_VEC_OWN
#undef WASM_DEFINE_TYPE
#undef WASM_DEFINE_REF_BASE
#undef WASM_DEFINE_REF
diff --git a/deps/v8/src/wasm/c-api.h b/deps/v8/src/wasm/c-api.h
index c1a914a16e..43a0fb73b2 100644
--- a/deps/v8/src/wasm/c-api.h
+++ b/deps/v8/src/wasm/c-api.h
@@ -7,8 +7,17 @@
#include "include/v8.h"
#include "src/common/globals.h"
+#include "src/handles/handles.h"
#include "third_party/wasm-api/wasm.hh"
+namespace v8 {
+namespace internal {
+
+class JSWeakMap;
+
+} // namespace internal
+} // namespace v8
+
namespace wasm {
class StoreImpl {
@@ -27,14 +36,19 @@ class StoreImpl {
reinterpret_cast<v8::Isolate*>(isolate)->GetData(0));
}
+ void SetHostInfo(i::Handle<i::Object> object, void* info,
+ void (*finalizer)(void*));
+ void* GetHostInfo(i::Handle<i::Object> key);
+
private:
- friend own<Store*> Store::make(Engine*);
+ friend own<Store> Store::make(Engine*);
StoreImpl() {}
v8::Isolate::CreateParams create_params_;
v8::Isolate* isolate_ = nullptr;
v8::Eternal<v8::Context> context_;
+ i::Handle<i::JSWeakMap> host_info_map_;
};
} // namespace wasm
diff --git a/deps/v8/src/wasm/function-body-decoder-impl.h b/deps/v8/src/wasm/function-body-decoder-impl.h
index 9f1ca23c62..582934e19f 100644
--- a/deps/v8/src/wasm/function-body-decoder-impl.h
+++ b/deps/v8/src/wasm/function-body-decoder-impl.h
@@ -339,35 +339,6 @@ struct BranchOnExceptionImmediate {
};
template <Decoder::ValidateFlag validate>
-struct CallIndirectImmediate {
- uint32_t table_index;
- uint32_t sig_index;
- FunctionSig* sig = nullptr;
- uint32_t length = 0;
- inline CallIndirectImmediate(const WasmFeatures enabled, Decoder* decoder,
- const byte* pc) {
- uint32_t len = 0;
- sig_index = decoder->read_u32v<validate>(pc + 1, &len, "signature index");
- table_index = decoder->read_u8<validate>(pc + 1 + len, "table index");
- if (!VALIDATE(table_index == 0 || enabled.anyref)) {
- decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
- table_index);
- }
- length = 1 + len;
- }
-};
-
-template <Decoder::ValidateFlag validate>
-struct CallFunctionImmediate {
- uint32_t index;
- FunctionSig* sig = nullptr;
- uint32_t length;
- inline CallFunctionImmediate(Decoder* decoder, const byte* pc) {
- index = decoder->read_u32v<validate>(pc + 1, &length, "function index");
- }
-};
-
-template <Decoder::ValidateFlag validate>
struct FunctionIndexImmediate {
uint32_t index = 0;
uint32_t length = 1;
@@ -395,7 +366,37 @@ struct TableIndexImmediate {
unsigned length = 1;
inline TableIndexImmediate() = default;
inline TableIndexImmediate(Decoder* decoder, const byte* pc) {
- index = decoder->read_u8<validate>(pc + 1, "table index");
+ index = decoder->read_u32v<validate>(pc + 1, &length, "table index");
+ }
+};
+
+template <Decoder::ValidateFlag validate>
+struct CallIndirectImmediate {
+ uint32_t table_index;
+ uint32_t sig_index;
+ FunctionSig* sig = nullptr;
+ uint32_t length = 0;
+ inline CallIndirectImmediate(const WasmFeatures enabled, Decoder* decoder,
+ const byte* pc) {
+ uint32_t len = 0;
+ sig_index = decoder->read_u32v<validate>(pc + 1, &len, "signature index");
+ TableIndexImmediate<validate> table(decoder, pc + len);
+ if (!VALIDATE((table.index == 0 && table.length == 1) || enabled.anyref)) {
+ decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
+ table.index);
+ }
+ table_index = table.index;
+ length = len + table.length;
+ }
+};
+
+template <Decoder::ValidateFlag validate>
+struct CallFunctionImmediate {
+ uint32_t index;
+ FunctionSig* sig = nullptr;
+ uint32_t length;
+ inline CallFunctionImmediate(Decoder* decoder, const byte* pc) {
+ index = decoder->read_u32v<validate>(pc + 1, &length, "function index");
}
};
@@ -748,8 +749,6 @@ struct ControlBase {
F(SimdOp, WasmOpcode opcode, Vector<Value> args, Value* result) \
F(SimdLaneOp, WasmOpcode opcode, const SimdLaneImmediate<validate>& imm, \
const Vector<Value> inputs, Value* result) \
- F(SimdShiftOp, WasmOpcode opcode, const SimdShiftImmediate<validate>& imm, \
- const Value& input, Value* result) \
F(Simd8x16ShuffleOp, const Simd8x16ShuffleImmediate<validate>& imm, \
const Value& input0, const Value& input1, Value* result) \
F(Throw, const ExceptionIndexImmediate<validate>& imm, \
@@ -849,7 +848,9 @@ class WasmDecoder : public Decoder {
type = kWasmAnyRef;
break;
}
- decoder->error(decoder->pc() - 1, "invalid local type");
+ decoder->error(decoder->pc() - 1,
+ "invalid local type 'anyref', enable with "
+ "--experimental-wasm-anyref");
return false;
case kLocalFuncRef:
if (enabled.anyref) {
@@ -857,7 +858,7 @@ class WasmDecoder : public Decoder {
break;
}
decoder->error(decoder->pc() - 1,
- "local type 'funcref' is not enabled with "
+ "invalid local type 'funcref', enable with "
"--experimental-wasm-anyref");
return false;
case kLocalExnRef:
@@ -865,14 +866,19 @@ class WasmDecoder : public Decoder {
type = kWasmExnRef;
break;
}
- decoder->error(decoder->pc() - 1, "invalid local type");
+ decoder->error(decoder->pc() - 1,
+ "invalid local type 'exception ref', enable with "
+ "--experimental-wasm-eh");
return false;
case kLocalS128:
if (enabled.simd) {
type = kWasmS128;
break;
}
- V8_FALLTHROUGH;
+ decoder->error(decoder->pc() - 1,
+ "invalid local type 'Simd128', enable with "
+ "--experimental-wasm-simd");
+ return false;
default:
decoder->error(decoder->pc() - 1, "invalid local type");
return false;
@@ -2666,16 +2672,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return imm.length;
}
- uint32_t SimdShiftOp(WasmOpcode opcode) {
- SimdShiftImmediate<validate> imm(this, this->pc_);
- if (this->Validate(this->pc_, opcode, imm)) {
- auto input = Pop(0, kWasmS128);
- auto* result = Push(kWasmS128);
- CALL_INTERFACE_IF_REACHABLE(SimdShiftOp, opcode, imm, input, result);
- }
- return imm.length;
- }
-
uint32_t Simd8x16ShuffleOp() {
Simd8x16ShuffleImmediate<validate> imm(this, this->pc_);
if (this->Validate(this->pc_, imm)) {
@@ -2727,21 +2723,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
len = SimdReplaceLane(opcode, kWasmI32);
break;
}
- case kExprI64x2Shl:
- case kExprI64x2ShrS:
- case kExprI64x2ShrU:
- case kExprI32x4Shl:
- case kExprI32x4ShrS:
- case kExprI32x4ShrU:
- case kExprI16x8Shl:
- case kExprI16x8ShrS:
- case kExprI16x8ShrU:
- case kExprI8x16Shl:
- case kExprI8x16ShrS:
- case kExprI8x16ShrU: {
- len = SimdShiftOp(opcode);
- break;
- }
case kExprS8x16Shuffle: {
len = Simd8x16ShuffleOp();
break;
diff --git a/deps/v8/src/wasm/function-compiler.cc b/deps/v8/src/wasm/function-compiler.cc
index 7df5abf5c8..4940134d53 100644
--- a/deps/v8/src/wasm/function-compiler.cc
+++ b/deps/v8/src/wasm/function-compiler.cc
@@ -262,21 +262,18 @@ void WasmCompilationUnit::CompileWasmFunction(Isolate* isolate,
}
}
-JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit(Isolate* isolate,
- FunctionSig* sig,
- bool is_import)
- : job_(compiler::NewJSToWasmCompilationJob(isolate, sig, is_import)) {}
+JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit(
+ Isolate* isolate, WasmEngine* wasm_engine, FunctionSig* sig, bool is_import,
+ const WasmFeatures& enabled_features)
+ : is_import_(is_import),
+ sig_(sig),
+ job_(compiler::NewJSToWasmCompilationJob(isolate, wasm_engine, sig,
+ is_import, enabled_features)) {}
JSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default;
-void JSToWasmWrapperCompilationUnit::Prepare(Isolate* isolate) {
- CompilationJob::Status status = job_->PrepareJob(isolate);
- CHECK_EQ(status, CompilationJob::SUCCEEDED);
-}
-
void JSToWasmWrapperCompilationUnit::Execute() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "CompileJSToWasmWrapper");
- DCHECK_EQ(job_->state(), CompilationJob::State::kReadyToExecute);
CompilationJob::Status status = job_->ExecuteJob();
CHECK_EQ(status, CompilationJob::SUCCEEDED);
}
@@ -296,8 +293,9 @@ Handle<Code> JSToWasmWrapperCompilationUnit::Finalize(Isolate* isolate) {
Handle<Code> JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
Isolate* isolate, FunctionSig* sig, bool is_import) {
// Run the compilation unit synchronously.
- JSToWasmWrapperCompilationUnit unit(isolate, sig, is_import);
- unit.Prepare(isolate);
+ WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
+ JSToWasmWrapperCompilationUnit unit(isolate, isolate->wasm_engine(), sig,
+ is_import, enabled_features);
unit.Execute();
return unit.Finalize(isolate);
}
diff --git a/deps/v8/src/wasm/function-compiler.h b/deps/v8/src/wasm/function-compiler.h
index d0b47b91aa..2da028a047 100644
--- a/deps/v8/src/wasm/function-compiler.h
+++ b/deps/v8/src/wasm/function-compiler.h
@@ -108,19 +108,24 @@ STATIC_ASSERT(sizeof(WasmCompilationUnit) <= 2 * kSystemPointerSize);
class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final {
public:
- JSToWasmWrapperCompilationUnit(Isolate* isolate, FunctionSig* sig,
- bool is_import);
+ JSToWasmWrapperCompilationUnit(Isolate* isolate, WasmEngine* wasm_engine,
+ FunctionSig* sig, bool is_import,
+ const WasmFeatures& enabled_features);
~JSToWasmWrapperCompilationUnit();
- void Prepare(Isolate* isolate);
void Execute();
Handle<Code> Finalize(Isolate* isolate);
+ bool is_import() const { return is_import_; }
+ FunctionSig* sig() const { return sig_; }
+
// Run a compilation unit synchronously.
static Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, FunctionSig* sig,
bool is_import);
private:
+ bool is_import_;
+ FunctionSig* sig_;
std::unique_ptr<OptimizedCompilationJob> job_;
};
diff --git a/deps/v8/src/wasm/graph-builder-interface.cc b/deps/v8/src/wasm/graph-builder-interface.cc
index 8efac18787..923e1154ea 100644
--- a/deps/v8/src/wasm/graph-builder-interface.cc
+++ b/deps/v8/src/wasm/graph-builder-interface.cc
@@ -258,8 +258,8 @@ class WasmGraphBuildingInterface {
void Drop(FullDecoder* decoder, const Value& value) {}
void DoReturn(FullDecoder* decoder, Vector<Value> values) {
- TFNode** nodes = GetNodes(values);
- BUILD(Return, static_cast<uint32_t>(values.size()), nodes);
+ Vector<TFNode*> nodes = GetNodes(values);
+ BUILD(Return, nodes);
}
void GetLocal(FullDecoder* decoder, Value* result,
@@ -319,10 +319,10 @@ class WasmGraphBuildingInterface {
void BrOrRet(FullDecoder* decoder, uint32_t depth) {
if (depth == decoder->control_depth() - 1) {
uint32_t ret_count = static_cast<uint32_t>(decoder->sig_->return_count());
- TFNode** values =
- ret_count == 0 ? nullptr
+ Vector<TFNode*> values =
+ ret_count == 0 ? Vector<TFNode*>{}
: GetNodes(decoder->stack_value(ret_count), ret_count);
- BUILD(Return, ret_count, values);
+ BUILD(Return, values);
} else {
Br(decoder, decoder->control_at(depth));
}
@@ -431,23 +431,16 @@ class WasmGraphBuildingInterface {
void SimdOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
Value* result) {
- TFNode** inputs = GetNodes(args);
- TFNode* node = BUILD(SimdOp, opcode, inputs);
+ Vector<TFNode*> inputs = GetNodes(args);
+ TFNode* node = BUILD(SimdOp, opcode, inputs.begin());
if (result) result->node = node;
}
void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode,
const SimdLaneImmediate<validate> imm, Vector<Value> inputs,
Value* result) {
- TFNode** nodes = GetNodes(inputs);
- result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes);
- }
-
- void SimdShiftOp(FullDecoder* decoder, WasmOpcode opcode,
- const SimdShiftImmediate<validate> imm, const Value& input,
- Value* result) {
- TFNode* inputs[] = {input.node};
- result->node = BUILD(SimdShiftOp, opcode, imm.shift, inputs);
+ Vector<TFNode*> nodes = GetNodes(inputs);
+ result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes.begin());
}
void Simd8x16ShuffleOp(FullDecoder* decoder,
@@ -495,7 +488,7 @@ class WasmGraphBuildingInterface {
SetEnv(if_match_env);
// TODO(mstarzinger): Can't use BUILD() here, GetExceptionValues() returns
// TFNode** rather than TFNode*. Fix to add landing pads.
- TFNode** caught_values =
+ Vector<TFNode*> caught_values =
builder_->GetExceptionValues(exception.node, imm.exception);
for (size_t i = 0, e = values.size(); i < e; ++i) {
values[i].node = caught_values[i];
@@ -526,9 +519,9 @@ class WasmGraphBuildingInterface {
void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
const MemoryAccessImmediate<validate>& imm, Value* result) {
- TFNode** inputs = GetNodes(args);
- TFNode* node = BUILD(AtomicOp, opcode, inputs, imm.alignment, imm.offset,
- decoder->position());
+ Vector<TFNode*> inputs = GetNodes(args);
+ TFNode* node = BUILD(AtomicOp, opcode, inputs.begin(), imm.alignment,
+ imm.offset, decoder->position());
if (result) result->node = node;
}
@@ -598,15 +591,15 @@ class WasmGraphBuildingInterface {
->try_info;
}
- TFNode** GetNodes(Value* values, size_t count) {
- TFNode** nodes = builder_->Buffer(count);
+ Vector<TFNode*> GetNodes(Value* values, size_t count) {
+ Vector<TFNode*> nodes = builder_->Buffer(count);
for (size_t i = 0; i < count; ++i) {
nodes[i] = values[i].node;
}
return nodes;
}
- TFNode** GetNodes(Vector<Value> values) {
+ Vector<TFNode*> GetNodes(Vector<Value> values) {
return GetNodes(values.begin(), values.size());
}
@@ -885,17 +878,17 @@ class WasmGraphBuildingInterface {
FunctionSig* sig, uint32_t sig_index, const Value args[],
Value returns[]) {
int param_count = static_cast<int>(sig->parameter_count());
- TFNode** arg_nodes = builder_->Buffer(param_count + 1);
+ Vector<TFNode*> arg_nodes = builder_->Buffer(param_count + 1);
TFNode** return_nodes = nullptr;
arg_nodes[0] = index_node;
for (int i = 0; i < param_count; ++i) {
arg_nodes[i + 1] = args[i].node;
}
if (index_node) {
- BUILD(CallIndirect, table_index, sig_index, arg_nodes, &return_nodes,
- decoder->position());
+ BUILD(CallIndirect, table_index, sig_index, arg_nodes.begin(),
+ &return_nodes, decoder->position());
} else {
- BUILD(CallDirect, sig_index, arg_nodes, &return_nodes,
+ BUILD(CallDirect, sig_index, arg_nodes.begin(), &return_nodes,
decoder->position());
}
int return_count = static_cast<int>(sig->return_count());
@@ -911,16 +904,16 @@ class WasmGraphBuildingInterface {
TFNode* index_node, FunctionSig* sig, uint32_t sig_index,
const Value args[]) {
int arg_count = static_cast<int>(sig->parameter_count());
- TFNode** arg_nodes = builder_->Buffer(arg_count + 1);
+ Vector<TFNode*> arg_nodes = builder_->Buffer(arg_count + 1);
arg_nodes[0] = index_node;
for (int i = 0; i < arg_count; ++i) {
arg_nodes[i + 1] = args[i].node;
}
if (index_node) {
- BUILD(ReturnCallIndirect, table_index, sig_index, arg_nodes,
+ BUILD(ReturnCallIndirect, table_index, sig_index, arg_nodes.begin(),
decoder->position());
} else {
- BUILD(ReturnCall, sig_index, arg_nodes, decoder->position());
+ BUILD(ReturnCall, sig_index, arg_nodes.begin(), decoder->position());
}
}
};
diff --git a/deps/v8/src/wasm/jump-table-assembler.h b/deps/v8/src/wasm/jump-table-assembler.h
index 379a547b55..8889c18e9c 100644
--- a/deps/v8/src/wasm/jump-table-assembler.h
+++ b/deps/v8/src/wasm/jump-table-assembler.h
@@ -37,6 +37,21 @@ namespace wasm {
// The above illustrates jump table lines {Li} containing slots {Si} with each
// line containing {n} slots and some padding {x} for alignment purposes.
// Other jump tables are just consecutive.
+//
+// The main jump table will be patched concurrently while other threads execute
+// it. The code at the new target might also have been emitted concurrently, so
+// we need to ensure that there is proper synchronization between code emission,
+// jump table patching and code execution.
+// On Intel platforms, this all works out of the box because there is cache
+// coherency between i-cache and d-cache.
+// On ARM, it is safe because the i-cache flush after code emission executes an
+// "ic ivau" (Instruction Cache line Invalidate by Virtual Address to Point of
+// Unification), which broadcasts to all cores. A core which sees the jump table
+// update thus also sees the new code. Since the other core does not explicitly
+// execute an "isb" (Instruction Synchronization Barrier), it might still
+// execute the old code afterwards, which is no problem, since that code remains
+// available until it is garbage collected. Garbage collection itself is a
+// synchronization barrier though.
class V8_EXPORT_PRIVATE JumpTableAssembler : public MacroAssembler {
public:
// Translate an offset into the continuous jump table to a jump table index.
diff --git a/deps/v8/src/wasm/module-compiler.cc b/deps/v8/src/wasm/module-compiler.cc
index 658f329775..c264bac96e 100644
--- a/deps/v8/src/wasm/module-compiler.cc
+++ b/deps/v8/src/wasm/module-compiler.cc
@@ -152,6 +152,9 @@ class CompilationUnitQueues {
for (int task_id = 0; task_id < max_tasks; ++task_id) {
queues_[task_id].next_steal_task_id = next_task_id(task_id);
}
+ for (auto& atomic_counter : num_units_) {
+ std::atomic_init(&atomic_counter, size_t{0});
+ }
}
base::Optional<WasmCompilationUnit> GetNextUnit(
@@ -254,15 +257,14 @@ class CompilationUnitQueues {
};
struct BigUnitsQueue {
- BigUnitsQueue() = default;
+ BigUnitsQueue() {
+ for (auto& atomic : has_units) std::atomic_init(&atomic, false);
+ }
base::Mutex mutex;
// Can be read concurrently to check whether any elements are in the queue.
- std::atomic_bool has_units[kNumTiers] = {
- ATOMIC_VAR_INIT(false),
- ATOMIC_VAR_INIT(false)
- };
+ std::atomic<bool> has_units[kNumTiers];
// Protected by {mutex}:
std::priority_queue<BigUnit> units[kNumTiers];
@@ -271,11 +273,8 @@ class CompilationUnitQueues {
std::vector<Queue> queues_;
BigUnitsQueue big_units_queue_;
- std::atomic_size_t num_units_[kNumTiers] = {
- ATOMIC_VAR_INIT(0),
- ATOMIC_VAR_INIT(0)
- };
- std::atomic_int next_queue_to_add{0};
+ std::atomic<size_t> num_units_[kNumTiers];
+ std::atomic<int> next_queue_to_add{0};
int next_task_id(int task_id) const {
int next = task_id + 1;
@@ -382,7 +381,7 @@ class CompilationStateImpl {
// Initialize compilation progress. Set compilation tiers to expect for
// baseline and top tier compilation. Must be set before {AddCompilationUnits}
// is invoked which triggers background compilation.
- void InitializeCompilationProgress(bool lazy_module, int num_import_wrappers);
+ void InitializeCompilationProgress(bool lazy_module, int num_wrappers);
// Add the callback function to be called on compilation events. Needs to be
// set before {AddCompilationUnits} is run to ensure that it receives all
@@ -390,13 +389,24 @@ class CompilationStateImpl {
void AddCallback(CompilationState::callback_t);
// Inserts new functions to compile and kicks off compilation.
- void AddCompilationUnits(Vector<WasmCompilationUnit> baseline_units,
- Vector<WasmCompilationUnit> top_tier_units);
+ void AddCompilationUnits(
+ Vector<WasmCompilationUnit> baseline_units,
+ Vector<WasmCompilationUnit> top_tier_units,
+ Vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>>
+ js_to_wasm_wrapper_units);
void AddTopTierCompilationUnit(WasmCompilationUnit);
base::Optional<WasmCompilationUnit> GetNextCompilationUnit(
int task_id, CompileBaselineOnly baseline_only);
+ std::shared_ptr<JSToWasmWrapperCompilationUnit>
+ GetNextJSToWasmWrapperCompilationUnit();
+ void FinalizeJSToWasmWrappers(Isolate* isolate, const WasmModule* module,
+ Handle<FixedArray>* export_wrappers_out);
+
void OnFinishedUnits(Vector<WasmCode*>);
+ void OnFinishedJSToWasmWrapperUnits(int num);
+ void TriggerCallbacks(bool completes_baseline_compilation,
+ bool completes_top_tier_compilation);
void OnBackgroundTaskStopped(int task_id, const WasmFeatures& detected);
void UpdateDetectedFeatures(const WasmFeatures& detected);
@@ -471,7 +481,7 @@ class CompilationStateImpl {
// Compilation error, atomically updated. This flag can be updated and read
// using relaxed semantics.
- std::atomic_bool compile_failed_{false};
+ std::atomic<bool> compile_failed_{false};
const int max_background_tasks_ = 0;
@@ -484,6 +494,13 @@ class CompilationStateImpl {
// tasks a fair chance to utilize the worker threads on a regular basis.
std::atomic<double> next_compilation_deadline_{0};
+ // Index of the next wrapper to compile in {js_to_wasm_wrapper_units_}.
+ std::atomic<int> js_to_wasm_wrapper_id_{0};
+ // Wrapper compilation units are stored in shared_ptrs so that they are kept
+ // alive by the tasks even if the NativeModule dies.
+ std::vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>>
+ js_to_wasm_wrapper_units_;
+
// This mutex protects all information of this {CompilationStateImpl} which is
// being accessed concurrently.
mutable base::Mutex mutex_;
@@ -525,9 +542,9 @@ class CompilationStateImpl {
//////////////////////////////////////////////////////////////////////////////
// Encoding of fields in the {compilation_progress_} vector.
- class RequiredBaselineTierField : public BitField8<ExecutionTier, 0, 2> {};
- class RequiredTopTierField : public BitField8<ExecutionTier, 2, 2> {};
- class ReachedTierField : public BitField8<ExecutionTier, 4, 2> {};
+ using RequiredBaselineTierField = BitField8<ExecutionTier, 0, 2>;
+ using RequiredTopTierField = BitField8<ExecutionTier, 2, 2>;
+ using ReachedTierField = BitField8<ExecutionTier, 4, 2>;
};
CompilationStateImpl* Impl(CompilationState* compilation_state) {
@@ -712,6 +729,11 @@ class CompilationUnitBuilder {
}
}
+ void AddJSToWasmWrapperUnit(
+ std::shared_ptr<JSToWasmWrapperCompilationUnit> unit) {
+ js_to_wasm_wrapper_units_.emplace_back(std::move(unit));
+ }
+
void AddTopTierUnit(int func_index) {
ExecutionTierPair tiers = GetRequestedExecutionTiers(
native_module_->module(), compilation_state()->compile_mode(),
@@ -730,9 +752,13 @@ class CompilationUnitBuilder {
}
bool Commit() {
- if (baseline_units_.empty() && tiering_units_.empty()) return false;
- compilation_state()->AddCompilationUnits(VectorOf(baseline_units_),
- VectorOf(tiering_units_));
+ if (baseline_units_.empty() && tiering_units_.empty() &&
+ js_to_wasm_wrapper_units_.empty()) {
+ return false;
+ }
+ compilation_state()->AddCompilationUnits(
+ VectorOf(baseline_units_), VectorOf(tiering_units_),
+ VectorOf(js_to_wasm_wrapper_units_));
Clear();
return true;
}
@@ -740,6 +766,7 @@ class CompilationUnitBuilder {
void Clear() {
baseline_units_.clear();
tiering_units_.clear();
+ js_to_wasm_wrapper_units_.clear();
}
private:
@@ -751,6 +778,8 @@ class CompilationUnitBuilder {
const ExecutionTier default_tier_;
std::vector<WasmCompilationUnit> baseline_units_;
std::vector<WasmCompilationUnit> tiering_units_;
+ std::vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>>
+ js_to_wasm_wrapper_units_;
};
void SetCompileError(ErrorThrower* thrower, ModuleWireBytes wire_bytes,
@@ -910,6 +939,33 @@ void RecordStats(const Code code, Counters* counters) {
constexpr int kMainThreadTaskId = -1;
+bool ExecuteJSToWasmWrapperCompilationUnits(
+ const std::shared_ptr<BackgroundCompileToken>& token) {
+ std::shared_ptr<JSToWasmWrapperCompilationUnit> wrapper_unit = nullptr;
+ int num_processed_wrappers = 0;
+ do {
+ // TODO(thibaudm): Reschedule the compilation task if it takes too long, so
+ // that the background thread is not blocked.
+ {
+ BackgroundCompileScope compile_scope(token);
+ if (compile_scope.cancelled()) return false;
+ wrapper_unit = compile_scope.compilation_state()
+ ->GetNextJSToWasmWrapperCompilationUnit();
+ }
+ if (wrapper_unit) {
+ wrapper_unit->Execute();
+ ++num_processed_wrappers;
+ }
+ } while (wrapper_unit);
+ {
+ BackgroundCompileScope compile_scope(token);
+ if (compile_scope.cancelled()) return false;
+ compile_scope.compilation_state()->OnFinishedJSToWasmWrapperUnits(
+ num_processed_wrappers);
+ }
+ return true;
+}
+
// Run by the main thread and background tasks to take part in compilation.
// Returns whether any units were executed.
bool ExecuteCompilationUnits(
@@ -918,6 +974,13 @@ bool ExecuteCompilationUnits(
TRACE_COMPILE("Compiling (task %d)...\n", task_id);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "ExecuteCompilationUnits");
+ // Execute JS to WASM wrapper units first, so that they are ready to be
+ // finalized by the main thread when the kFinishedBaselineCompilation event is
+ // triggered.
+ if (!ExecuteJSToWasmWrapperCompilationUnits(token)) {
+ return false;
+ }
+
const bool is_foreground = task_id == kMainThreadTaskId;
// The main thread uses task id 0, which might collide with one of the
// background tasks. This is fine, as it will only cause some contention on
@@ -1050,6 +1113,35 @@ bool ExecuteCompilationUnits(
return true;
}
+using JSToWasmWrapperKey = std::pair<bool, FunctionSig>;
+
+// Returns the number of units added.
+int AddExportWrapperUnits(Isolate* isolate, WasmEngine* wasm_engine,
+ NativeModule* native_module,
+ CompilationUnitBuilder* builder,
+ const WasmFeatures& enabled_features) {
+// Disable asynchronous wrapper compilation when builtins are not embedded,
+// otherwise the isolate might be used after tear down to access builtins.
+#ifdef V8_EMBEDDED_BUILTINS
+ std::unordered_set<JSToWasmWrapperKey, base::hash<JSToWasmWrapperKey>> keys;
+ for (auto exp : native_module->module()->export_table) {
+ if (exp.kind != kExternalFunction) continue;
+ auto& function = native_module->module()->functions[exp.index];
+ JSToWasmWrapperKey key(function.imported, *function.sig);
+ if (keys.insert(key).second) {
+ auto unit = std::make_shared<JSToWasmWrapperCompilationUnit>(
+ isolate, wasm_engine, function.sig, function.imported,
+ enabled_features);
+ builder->AddJSToWasmWrapperUnit(std::move(unit));
+ }
+ }
+
+ return static_cast<int>(keys.size());
+#else
+ return 0;
+#endif
+}
+
// Returns the number of units added.
int AddImportWrapperUnits(NativeModule* native_module,
CompilationUnitBuilder* builder) {
@@ -1059,8 +1151,7 @@ int AddImportWrapperUnits(NativeModule* native_module,
int num_imported_functions = native_module->num_imported_functions();
for (int func_index = 0; func_index < num_imported_functions; func_index++) {
FunctionSig* sig = native_module->module()->functions[func_index].sig;
- bool has_bigint_feature = native_module->enabled_features().bigint;
- if (!IsJSCompatibleSignature(sig, has_bigint_feature)) {
+ if (!IsJSCompatibleSignature(sig, native_module->enabled_features())) {
continue;
}
WasmImportWrapperCache::CacheKey key(compiler::kDefaultImportCallKind, sig);
@@ -1075,7 +1166,7 @@ int AddImportWrapperUnits(NativeModule* native_module,
return static_cast<int>(keys.size());
}
-void InitializeCompilationUnits(NativeModule* native_module) {
+void InitializeCompilationUnits(Isolate* isolate, NativeModule* native_module) {
CompilationStateImpl* compilation_state =
Impl(native_module->compilation_state());
const bool lazy_module = IsLazyModule(native_module->module());
@@ -1099,8 +1190,11 @@ void InitializeCompilationUnits(NativeModule* native_module) {
}
}
int num_import_wrappers = AddImportWrapperUnits(native_module, &builder);
- compilation_state->InitializeCompilationProgress(lazy_module,
- num_import_wrappers);
+ int num_export_wrappers =
+ AddExportWrapperUnits(isolate, isolate->wasm_engine(), native_module,
+ &builder, WasmFeaturesFromIsolate(isolate));
+ compilation_state->InitializeCompilationProgress(
+ lazy_module, num_import_wrappers + num_export_wrappers);
builder.Commit();
}
@@ -1202,7 +1296,7 @@ void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
}
// Initialize the compilation units and kick off background compile tasks.
- InitializeCompilationUnits(native_module);
+ InitializeCompilationUnits(isolate, native_module);
// If tiering is disabled, the main thread can execute any unit (all of them
// are part of initial compilation). Otherwise, just execute baseline units.
@@ -1274,26 +1368,23 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
OwnedVector<uint8_t> wire_bytes_copy =
OwnedVector<uint8_t>::Of(wire_bytes.module_bytes());
- // Create and compile the native module.
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
-
// Create a new {NativeModule} first.
auto native_module = isolate->wasm_engine()->NewNativeModule(
- isolate, enabled, code_size_estimate,
- wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
+ isolate, enabled, std::move(module));
native_module->SetWireBytes(std::move(wire_bytes_copy));
native_module->SetRuntimeStubs(isolate);
CompileNativeModule(isolate, thrower, wasm_module, native_module.get());
if (thrower->error()) return {};
- // Compile JS->wasm wrappers for exported functions.
- int num_wrappers = MaxNumExportWrappers(native_module->module());
- *export_wrappers_out =
- isolate->factory()->NewFixedArray(num_wrappers, AllocationType::kOld);
+#ifdef V8_EMBEDDED_BUILTINS
+ Impl(native_module->compilation_state())
+ ->FinalizeJSToWasmWrappers(isolate, native_module->module(),
+ export_wrappers_out);
+#else
CompileJsToWasmWrappers(isolate, native_module->module(),
- *export_wrappers_out);
+ export_wrappers_out);
+#endif
// Log the code within the generated module for profiling.
native_module->LogWasmCodes(isolate);
@@ -1367,7 +1458,9 @@ class AsyncStreamingProcessor final : public StreamingProcessor {
ModuleDecoder decoder_;
AsyncCompileJob* job_;
+ WasmEngine* wasm_engine_;
std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
+ base::TimeTicks start_time_;
int num_functions_ = 0;
};
@@ -1415,11 +1508,8 @@ void AsyncCompileJob::CreateNativeModule(
// breakpoints on a (potentially empty) subset of the instances.
// Create the module object.
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
native_module_ = isolate_->wasm_engine()->NewNativeModule(
- isolate_, enabled_features_, code_size_estimate,
- wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
+ isolate_, enabled_features_, std::move(module));
native_module_->SetWireBytes({std::move(bytes_copy_), wire_bytes_.length()});
native_module_->SetRuntimeStubs(isolate_);
@@ -1433,10 +1523,8 @@ void AsyncCompileJob::PrepareRuntimeObjects() {
Handle<Script> script =
CreateWasmScript(isolate_, wire_bytes_, module->source_map_url);
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module);
- Handle<WasmModuleObject> module_object = WasmModuleObject::New(
- isolate_, native_module_, script, code_size_estimate);
+ Handle<WasmModuleObject> module_object =
+ WasmModuleObject::New(isolate_, native_module_, script);
module_object_ = isolate_->global_handles()->Create(*module_object);
}
@@ -1462,17 +1550,25 @@ void AsyncCompileJob::FinishCompile() {
}
isolate_->debug()->OnAfterCompile(script);
- // We can only update the feature counts once the entire compile is done.
auto compilation_state =
Impl(module_object_->native_module()->compilation_state());
- compilation_state->PublishDetectedFeatures(isolate_);
-
// TODO(bbudge) Allow deserialization without wrapper compilation, so we can
// just compile wrappers here.
if (!is_after_deserialization) {
- // TODO(wasm): compiling wrappers should be made async.
- CompileWrappers();
+#ifdef V8_EMBEDDED_BUILTINS
+ Handle<FixedArray> export_wrappers;
+ compilation_state->FinalizeJSToWasmWrappers(
+ isolate_, module_object_->module(), &export_wrappers);
+ module_object_->set_export_wrappers(*export_wrappers);
+#else
+ Handle<FixedArray> export_wrappers;
+ CompileJsToWasmWrappers(isolate_, module_object_->module(),
+ &export_wrappers);
+ module_object_->set_export_wrappers(*export_wrappers);
+#endif
}
+ // We can only update the feature counts once the entire compile is done.
+ compilation_state->PublishDetectedFeatures(isolate_);
FinishModule();
}
@@ -1792,7 +1888,7 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
// then DoAsync would do the same as NextStep already.
// Add compilation units and kick off compilation.
- InitializeCompilationUnits(job->native_module_.get());
+ InitializeCompilationUnits(job->isolate(), job->native_module_.get());
}
}
};
@@ -1853,17 +1949,8 @@ class AsyncCompileJob::CompileFinished : public CompileStep {
}
};
-void AsyncCompileJob::CompileWrappers() {
- // TODO(wasm): Compile all wrappers here, including the start function wrapper
- // and the wrappers for the function table elements.
- TRACE_COMPILE("(5) Compile wrappers...\n");
- // Compile JS->wasm wrappers for exported functions.
- CompileJsToWasmWrappers(isolate_, module_object_->native_module()->module(),
- handle(module_object_->export_wrappers(), isolate_));
-}
-
void AsyncCompileJob::FinishModule() {
- TRACE_COMPILE("(6) Finish module...\n");
+ TRACE_COMPILE("(4) Finish module...\n");
AsyncCompileSucceeded(module_object_);
isolate_->wasm_engine()->RemoveCompileJob(this);
}
@@ -1871,7 +1958,9 @@ void AsyncCompileJob::FinishModule() {
AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
: decoder_(job->enabled_features_),
job_(job),
- compilation_unit_builder_(nullptr) {}
+ wasm_engine_(job_->isolate_->wasm_engine()),
+ compilation_unit_builder_(nullptr),
+ start_time_(base::TimeTicks::Now()) {}
void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(
const WasmError& error) {
@@ -1973,8 +2062,11 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
int num_import_wrappers =
AddImportWrapperUnits(native_module, compilation_unit_builder_.get());
- compilation_state->InitializeCompilationProgress(lazy_module,
- num_import_wrappers);
+ int num_export_wrappers = AddExportWrapperUnits(
+ job_->isolate_, wasm_engine_, native_module,
+ compilation_unit_builder_.get(), job_->enabled_features_);
+ compilation_state->InitializeCompilationProgress(
+ lazy_module, num_import_wrappers + num_export_wrappers);
return true;
}
@@ -2097,6 +2189,13 @@ bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
MaybeHandle<WasmModuleObject> result =
DeserializeNativeModule(job_->isolate_, module_bytes, wire_bytes);
+ if (base::TimeTicks::IsHighResolution()) {
+ base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
+ auto* histogram = job_->isolate_->counters()
+ ->wasm_streaming_deserialize_wasm_module_time();
+ histogram->AddSample(static_cast<int>(duration.InMicroseconds()));
+ }
+
if (result.is_null()) return false;
job_->module_object_ =
@@ -2145,8 +2244,8 @@ void CompilationStateImpl::AbortCompilation() {
callbacks_.clear();
}
-void CompilationStateImpl::InitializeCompilationProgress(
- bool lazy_module, int num_import_wrappers) {
+void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module,
+ int num_wrappers) {
DCHECK(!failed());
auto enabled_features = native_module_->enabled_features();
auto* module = native_module_->module();
@@ -2190,7 +2289,7 @@ void CompilationStateImpl::InitializeCompilationProgress(
DCHECK_IMPLIES(lazy_module, outstanding_top_tier_functions_ == 0);
DCHECK_LE(0, outstanding_baseline_units_);
DCHECK_LE(outstanding_baseline_units_, outstanding_top_tier_functions_);
- outstanding_baseline_units_ += num_import_wrappers;
+ outstanding_baseline_units_ += num_wrappers;
// Trigger callbacks if module needs no baseline or top tier compilation. This
// can be the case for an empty or fully lazy module.
@@ -2215,15 +2314,52 @@ void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
void CompilationStateImpl::AddCompilationUnits(
Vector<WasmCompilationUnit> baseline_units,
- Vector<WasmCompilationUnit> top_tier_units) {
- compilation_unit_queues_.AddUnits(baseline_units, top_tier_units,
- native_module_->module());
+ Vector<WasmCompilationUnit> top_tier_units,
+ Vector<std::shared_ptr<JSToWasmWrapperCompilationUnit>>
+ js_to_wasm_wrapper_units) {
+ if (!baseline_units.empty() || !top_tier_units.empty()) {
+ compilation_unit_queues_.AddUnits(baseline_units, top_tier_units,
+ native_module_->module());
+ }
+ js_to_wasm_wrapper_units_.insert(js_to_wasm_wrapper_units_.end(),
+ js_to_wasm_wrapper_units.begin(),
+ js_to_wasm_wrapper_units.end());
RestartBackgroundTasks();
}
void CompilationStateImpl::AddTopTierCompilationUnit(WasmCompilationUnit unit) {
- AddCompilationUnits({}, {&unit, 1});
+ AddCompilationUnits({}, {&unit, 1}, {});
+}
+
+std::shared_ptr<JSToWasmWrapperCompilationUnit>
+CompilationStateImpl::GetNextJSToWasmWrapperCompilationUnit() {
+ int wrapper_id =
+ js_to_wasm_wrapper_id_.fetch_add(1, std::memory_order_relaxed);
+ if (wrapper_id < static_cast<int>(js_to_wasm_wrapper_units_.size())) {
+ return js_to_wasm_wrapper_units_[wrapper_id];
+ }
+ return nullptr;
+}
+
+void CompilationStateImpl::FinalizeJSToWasmWrappers(
+ Isolate* isolate, const WasmModule* module,
+ Handle<FixedArray>* export_wrappers_out) {
+ *export_wrappers_out = isolate->factory()->NewFixedArray(
+ MaxNumExportWrappers(module), AllocationType::kOld);
+ // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
+ // optimization we keep the code space unlocked to avoid repeated unlocking
+ // because many such wrapper are allocated in sequence below.
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
+ "FinalizeJSToWasmWrappers");
+ CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
+ for (auto& unit : js_to_wasm_wrapper_units_) {
+ Handle<Code> code = unit->Finalize(isolate);
+ int wrapper_index =
+ GetExportWrapperIndex(module, unit->sig(), unit->is_import());
+ (*export_wrappers_out)->set(wrapper_index, *code);
+ RecordStats(*code, isolate->counters());
+ }
}
base::Optional<WasmCompilationUnit>
@@ -2313,25 +2449,38 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
DCHECK_LE(0, outstanding_baseline_units_);
}
- // Trigger callbacks.
- if (completes_baseline_compilation) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "BaselineFinished");
- for (auto& callback : callbacks_) {
- callback(CompilationEvent::kFinishedBaselineCompilation);
- }
- if (outstanding_top_tier_functions_ == 0) {
- completes_top_tier_compilation = true;
- }
+ TriggerCallbacks(completes_baseline_compilation,
+ completes_top_tier_compilation);
+ }
+}
+
+void CompilationStateImpl::OnFinishedJSToWasmWrapperUnits(int num) {
+ if (num == 0) return;
+ base::MutexGuard guard(&callbacks_mutex_);
+ outstanding_baseline_units_ -= num;
+ bool completes_baseline_compilation = outstanding_baseline_units_ == 0;
+ TriggerCallbacks(completes_baseline_compilation, false);
+}
+
+void CompilationStateImpl::TriggerCallbacks(
+ bool completes_baseline_compilation, bool completes_top_tier_compilation) {
+ if (completes_baseline_compilation) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "BaselineFinished");
+ for (auto& callback : callbacks_) {
+ callback(CompilationEvent::kFinishedBaselineCompilation);
}
- if (outstanding_baseline_units_ == 0 && completes_top_tier_compilation) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "TopTierFinished");
- for (auto& callback : callbacks_) {
- callback(CompilationEvent::kFinishedTopTierCompilation);
- }
- // Clear the callbacks because no more events will be delivered.
- callbacks_.clear();
+ if (outstanding_top_tier_functions_ == 0) {
+ completes_top_tier_compilation = true;
}
}
+ if (outstanding_baseline_units_ == 0 && completes_top_tier_compilation) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "TopTierFinished");
+ for (auto& callback : callbacks_) {
+ callback(CompilationEvent::kFinishedTopTierCompilation);
+ }
+ // Clear the callbacks because no more events will be delivered.
+ callbacks_.clear();
+ }
}
void CompilationStateImpl::OnBackgroundTaskStopped(
@@ -2379,6 +2528,11 @@ void CompilationStateImpl::RestartBackgroundTasks() {
if (failed()) return;
size_t max_num_restart = compilation_unit_queues_.GetTotalSize();
+ if (js_to_wasm_wrapper_id_ <
+ static_cast<int>(js_to_wasm_wrapper_units_.size())) {
+ max_num_restart +=
+ js_to_wasm_wrapper_units_.size() - js_to_wasm_wrapper_id_;
+ }
while (!available_task_ids_.empty() && max_num_restart-- > 0) {
int task_id = available_task_ids_.back();
@@ -2418,7 +2572,6 @@ void CompilationStateImpl::SetError() {
}
namespace {
-using JSToWasmWrapperKey = std::pair<bool, FunctionSig>;
using JSToWasmWrapperQueue =
WrapperQueue<JSToWasmWrapperKey, base::hash<JSToWasmWrapperKey>>;
using JSToWasmWrapperUnitMap =
@@ -2449,9 +2602,13 @@ class CompileJSToWasmWrapperTask final : public CancelableTask {
} // namespace
void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
- Handle<FixedArray> export_wrappers) {
+ Handle<FixedArray>* export_wrappers_out) {
+ *export_wrappers_out = isolate->factory()->NewFixedArray(
+ MaxNumExportWrappers(module), AllocationType::kOld);
+
JSToWasmWrapperQueue queue;
JSToWasmWrapperUnitMap compilation_units;
+ WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
// Prepare compilation units in the main thread.
for (auto exp : module->export_table) {
@@ -2460,8 +2617,8 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
JSToWasmWrapperKey key(function.imported, *function.sig);
if (queue.insert(key)) {
auto unit = base::make_unique<JSToWasmWrapperCompilationUnit>(
- isolate, function.sig, function.imported);
- unit->Prepare(isolate);
+ isolate, isolate->wasm_engine(), function.sig, function.imported,
+ enabled_features);
compilation_units.emplace(key, std::move(unit));
}
}
@@ -2492,7 +2649,7 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
JSToWasmWrapperCompilationUnit* unit = pair.second.get();
Handle<Code> code = unit->Finalize(isolate);
int wrapper_index = GetExportWrapperIndex(module, &key.second, key.first);
- export_wrappers->set(wrapper_index, *code);
+ (*export_wrappers_out)->set(wrapper_index, *code);
RecordStats(*code, isolate->counters());
}
}
diff --git a/deps/v8/src/wasm/module-compiler.h b/deps/v8/src/wasm/module-compiler.h
index 27c7bff868..69eb6bb62c 100644
--- a/deps/v8/src/wasm/module-compiler.h
+++ b/deps/v8/src/wasm/module-compiler.h
@@ -46,7 +46,7 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
V8_EXPORT_PRIVATE
void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
- Handle<FixedArray> export_wrappers);
+ Handle<FixedArray>* export_wrappers_out);
// Compiles the wrapper for this (kind, sig) pair and sets the corresponding
// cache entry. Assumes the key already exists in the cache but has not been
@@ -153,8 +153,6 @@ class AsyncCompileJob {
void AsyncCompileSucceeded(Handle<WasmModuleObject> result);
- void CompileWrappers();
-
void FinishModule();
void StartForegroundTask();
diff --git a/deps/v8/src/wasm/module-instantiate.cc b/deps/v8/src/wasm/module-instantiate.cc
index a4b0139ea4..976c3cde00 100644
--- a/deps/v8/src/wasm/module-instantiate.cc
+++ b/deps/v8/src/wasm/module-instantiate.cc
@@ -656,6 +656,7 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
uint32_t size = segment.source.length();
if (enabled_.bulk_memory) {
+ if (size == 0) continue;
// Passive segments are not copied during instantiation.
if (!segment.active) continue;
@@ -834,10 +835,18 @@ bool InstanceBuilder::ProcessImportedFunction(
module_name, import_name);
return false;
}
+ // Store any {WasmExternalFunction} callable in the instance before the call
+ // is resolved to preserve its identity. This handles exported functions as
+ // well as functions constructed via other means (e.g. WebAssembly.Function).
+ if (WasmExternalFunction::IsWasmExternalFunction(*value)) {
+ WasmInstanceObject::SetWasmExternalFunction(
+ isolate_, instance, func_index,
+ Handle<WasmExternalFunction>::cast(value));
+ }
auto js_receiver = Handle<JSReceiver>::cast(value);
FunctionSig* expected_sig = module_->functions[func_index].sig;
- auto resolved = compiler::ResolveWasmImportCall(js_receiver, expected_sig,
- enabled_.bigint);
+ auto resolved =
+ compiler::ResolveWasmImportCall(js_receiver, expected_sig, enabled_);
compiler::WasmImportCallKind kind = resolved.first;
js_receiver = resolved.second;
switch (kind) {
@@ -854,10 +863,6 @@ bool InstanceBuilder::ProcessImportedFunction(
Address imported_target = imported_function->GetWasmCallTarget();
ImportedFunctionEntry entry(instance, func_index);
entry.SetWasmToWasm(*imported_instance, imported_target);
- // Also store the {WasmExportedFunction} in the instance to preserve its
- // identity.
- WasmInstanceObject::SetWasmExportedFunction(
- isolate_, instance, func_index, imported_function);
break;
}
case compiler::WasmImportCallKind::kWasmToCapi: {
@@ -1218,8 +1223,7 @@ void InstanceBuilder::CompileImportWrappers(
auto js_receiver = Handle<JSReceiver>::cast(value);
uint32_t func_index = module_->import_table[index].index;
FunctionSig* sig = module_->functions[func_index].sig;
- auto resolved =
- compiler::ResolveWasmImportCall(js_receiver, sig, enabled_.bigint);
+ auto resolved = compiler::ResolveWasmImportCall(js_receiver, sig, enabled_);
compiler::WasmImportCallKind kind = resolved.first;
if (kind == compiler::WasmImportCallKind::kWasmToWasm ||
kind == compiler::WasmImportCallKind::kLinkError ||
@@ -1373,7 +1377,7 @@ void InstanceBuilder::InitGlobals(Handle<WasmInstanceObject> instance) {
break;
case WasmInitExpr::kRefFuncConst: {
DCHECK(enabled_.anyref);
- auto function = WasmInstanceObject::GetOrCreateWasmExportedFunction(
+ auto function = WasmInstanceObject::GetOrCreateWasmExternalFunction(
isolate_, instance, global.init.val.function_index);
tagged_globals_->set(global.offset, *function);
break;
@@ -1450,10 +1454,10 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
const WasmImport& import = module_->import_table[index];
if (import.kind == kExternalFunction) {
Handle<Object> value = sanitized_imports_[index].value;
- if (WasmExportedFunction::IsWasmExportedFunction(*value)) {
- WasmInstanceObject::SetWasmExportedFunction(
+ if (WasmExternalFunction::IsWasmExternalFunction(*value)) {
+ WasmInstanceObject::SetWasmExternalFunction(
isolate_, instance, import.index,
- Handle<WasmExportedFunction>::cast(value));
+ Handle<WasmExternalFunction>::cast(value));
}
}
}
@@ -1498,10 +1502,10 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
case kExternalFunction: {
// Wrap and export the code as a JSFunction.
// TODO(wasm): reduce duplication with LoadElemSegment() further below
- MaybeHandle<WasmExportedFunction> wasm_exported_function =
- WasmInstanceObject::GetOrCreateWasmExportedFunction(
+ Handle<WasmExternalFunction> wasm_external_function =
+ WasmInstanceObject::GetOrCreateWasmExternalFunction(
isolate_, instance, exp.index);
- desc.set_value(wasm_exported_function.ToHandleChecked());
+ desc.set_value(wasm_external_function);
if (is_asm_js &&
String::Equals(isolate_, name,
@@ -1629,6 +1633,7 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
uint32_t table_index,
const WasmElemSegment& elem_segment, uint32_t dst,
uint32_t src, size_t count) {
+ if (count == 0) return true;
// TODO(wasm): Move this functionality into wasm-objects, since it is used
// for both instantiation and in the implementation of the table.init
// instruction.
@@ -1660,27 +1665,27 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
.Set(sig_id, instance, func_index);
}
- // For AnyRef tables, we have to generate the WasmExportedFunction eagerly.
+ // For AnyRef tables, we have to generate the WasmExternalFunction eagerly.
// Later we cannot know if an entry is a placeholder or not.
if (table_object->type() == kWasmAnyRef) {
- Handle<WasmExportedFunction> wasm_exported_function =
- WasmInstanceObject::GetOrCreateWasmExportedFunction(isolate, instance,
+ Handle<WasmExternalFunction> wasm_external_function =
+ WasmInstanceObject::GetOrCreateWasmExternalFunction(isolate, instance,
func_index);
WasmTableObject::Set(isolate, table_object, entry_index,
- wasm_exported_function);
+ wasm_external_function);
} else {
// Update the table object's other dispatch tables.
- MaybeHandle<WasmExportedFunction> wasm_exported_function =
- WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
+ MaybeHandle<WasmExternalFunction> wasm_external_function =
+ WasmInstanceObject::GetWasmExternalFunction(isolate, instance,
func_index);
- if (wasm_exported_function.is_null()) {
+ if (wasm_external_function.is_null()) {
// No JSFunction entry yet exists for this function. Create a {Tuple2}
// holding the information to lazily allocate one.
WasmTableObject::SetFunctionTablePlaceholder(
isolate, table_object, entry_index, instance, func_index);
} else {
table_object->entries().set(entry_index,
- *wasm_exported_function.ToHandleChecked());
+ *wasm_external_function.ToHandleChecked());
}
// UpdateDispatchTables() updates all other dispatch tables, since
// we have not yet added the dispatch table we are currently building.
@@ -1701,6 +1706,7 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
uint32_t dst = EvalUint32InitExpr(instance, elem_segment.offset);
uint32_t src = 0;
size_t count = elem_segment.entries.size();
+ if (enabled_.bulk_memory && count == 0) continue;
bool success = LoadElemSegmentImpl(
isolate_, instance,
diff --git a/deps/v8/src/wasm/wasm-code-manager.cc b/deps/v8/src/wasm/wasm-code-manager.cc
index 3d0cde0cce..91cfc01cea 100644
--- a/deps/v8/src/wasm/wasm-code-manager.cc
+++ b/deps/v8/src/wasm/wasm-code-manager.cc
@@ -25,13 +25,14 @@
#include "src/wasm/function-compiler.h"
#include "src/wasm/jump-table-assembler.h"
#include "src/wasm/wasm-import-wrapper-cache.h"
+#include "src/wasm/wasm-module-sourcemap.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-objects.h"
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
#include "src/diagnostics/unwinding-info-win64.h"
-#endif
+#endif // V8_OS_WIN64
#define TRACE_HEAP(...) \
do { \
@@ -88,13 +89,30 @@ base::AddressRegion DisjointAllocationPool::Merge(base::AddressRegion region) {
}
base::AddressRegion DisjointAllocationPool::Allocate(size_t size) {
+ return AllocateInRegion(size,
+ {kNullAddress, std::numeric_limits<size_t>::max()});
+}
+
+base::AddressRegion DisjointAllocationPool::AllocateInRegion(
+ size_t size, base::AddressRegion region) {
for (auto it = regions_.begin(), end = regions_.end(); it != end; ++it) {
- if (size > it->size()) continue;
- base::AddressRegion ret{it->begin(), size};
+ base::AddressRegion overlap = it->GetOverlap(region);
+ if (size > overlap.size()) continue;
+ base::AddressRegion ret{overlap.begin(), size};
if (size == it->size()) {
+ // We use the full region --> erase the region from {regions_}.
regions_.erase(it);
- } else {
+ } else if (ret.begin() == it->begin()) {
+ // We return a region at the start --> shrink remaining region from front.
*it = base::AddressRegion{it->begin() + size, it->size() - size};
+ } else if (ret.end() == it->end()) {
+ // We return a region at the end --> shrink remaining region.
+ *it = base::AddressRegion{it->begin(), it->size() - size};
+ } else {
+ // We return something in the middle --> split the remaining region.
+ regions_.insert(
+ it, base::AddressRegion{it->begin(), ret.begin() - it->begin()});
+ *it = base::AddressRegion{ret.end(), it->end() - ret.end()};
}
return ret;
}
@@ -164,6 +182,19 @@ void WasmCode::LogCode(Isolate* isolate) const {
WireBytesRef name_ref =
native_module()->module()->LookupFunctionName(wire_bytes, index());
WasmName name_vec = wire_bytes.GetNameOrNull(name_ref);
+
+ const std::string& source_map_url = native_module()->module()->source_map_url;
+ auto load_wasm_source_map = isolate->wasm_load_source_map_callback();
+ auto source_map = native_module()->GetWasmSourceMap();
+ if (!source_map && !source_map_url.empty() && load_wasm_source_map) {
+ HandleScope scope(isolate);
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+ Local<v8::String> source_map_str =
+ load_wasm_source_map(v8_isolate, source_map_url.c_str());
+ native_module()->SetWasmSourceMap(
+ base::make_unique<WasmModuleSourceMap>(v8_isolate, source_map_str));
+ }
+
if (!name_vec.empty()) {
HandleScope scope(isolate);
MaybeHandle<String> maybe_name = isolate->factory()->NewStringFromUtf8(
@@ -204,11 +235,7 @@ void WasmCode::Validate() const {
switch (mode) {
case RelocInfo::WASM_CALL: {
Address target = it.rinfo()->wasm_call_address();
- WasmCode* code = native_module_->Lookup(target);
- CHECK_NOT_NULL(code);
- CHECK_EQ(WasmCode::kJumpTable, code->kind());
- CHECK_EQ(native_module()->jump_table_, code);
- CHECK(code->contains(target));
+ DCHECK(native_module_->is_jump_table_slot(target));
break;
}
case RelocInfo::WASM_STUB_CALL: {
@@ -464,32 +491,51 @@ base::SmallVector<base::AddressRegion, 1> SplitRangeByReservationsIfNeeded(
Vector<byte> WasmCodeAllocator::AllocateForCode(NativeModule* native_module,
size_t size) {
+ return AllocateForCodeInRegion(
+ native_module, size, {kNullAddress, std::numeric_limits<size_t>::max()});
+}
+
+Vector<byte> WasmCodeAllocator::AllocateForCodeInRegion(
+ NativeModule* native_module, size_t size, base::AddressRegion region) {
base::MutexGuard lock(&mutex_);
DCHECK_EQ(code_manager_, native_module->engine()->code_manager());
DCHECK_LT(0, size);
v8::PageAllocator* page_allocator = GetPlatformPageAllocator();
- // This happens under a lock assumed by the caller.
size = RoundUp<kCodeAlignment>(size);
- base::AddressRegion code_space = free_code_space_.Allocate(size);
+ base::AddressRegion code_space =
+ free_code_space_.AllocateInRegion(size, region);
if (code_space.is_empty()) {
- if (!can_request_more_memory_) {
- V8::FatalProcessOutOfMemory(nullptr, "wasm code reservation");
+ const bool in_specific_region =
+ region.size() < std::numeric_limits<size_t>::max();
+ if (!can_request_more_memory_ || in_specific_region) {
+ auto error = in_specific_region ? "wasm code reservation in region"
+ : "wasm code reservation";
+ V8::FatalProcessOutOfMemory(nullptr, error);
UNREACHABLE();
}
Address hint = owned_code_space_.empty() ? kNullAddress
: owned_code_space_.back().end();
+ // Reserve at least 20% of the total generated code size so far, and of
+ // course at least {size}. Round up to the next power of two.
+ size_t total_reserved = 0;
+ for (auto& vmem : owned_code_space_) total_reserved += vmem.size();
+ size_t reserve_size =
+ base::bits::RoundUpToPowerOfTwo(std::max(size, total_reserved / 5));
VirtualMemory new_mem =
- code_manager_->TryAllocate(size, reinterpret_cast<void*>(hint));
+ code_manager_->TryAllocate(reserve_size, reinterpret_cast<void*>(hint));
if (!new_mem.IsReserved()) {
V8::FatalProcessOutOfMemory(nullptr, "wasm code reservation");
UNREACHABLE();
}
- code_manager_->AssignRange(new_mem.region(), native_module);
- free_code_space_.Merge(new_mem.region());
+ base::AddressRegion new_region = new_mem.region();
+ code_manager_->AssignRange(new_region, native_module);
+ free_code_space_.Merge(new_region);
owned_code_space_.emplace_back(std::move(new_mem));
+ native_module->AddCodeSpace(new_region);
+
code_space = free_code_space_.Allocate(size);
DCHECK(!code_space.is_empty());
async_counters_->wasm_module_num_code_spaces()->AddSample(
@@ -614,6 +660,12 @@ void WasmCodeAllocator::FreeCode(Vector<WasmCode* const> codes) {
}
}
+base::AddressRegion WasmCodeAllocator::GetSingleCodeRegion() const {
+ base::MutexGuard lock(&mutex_);
+ DCHECK_EQ(1, owned_code_space_.size());
+ return owned_code_space_[0].region();
+}
+
NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled,
bool can_request_more, VirtualMemory code_space,
std::shared_ptr<const WasmModule> module,
@@ -636,27 +688,10 @@ NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled,
compilation_state_ =
CompilationState::New(*shared_this, std::move(async_counters));
DCHECK_NOT_NULL(module_);
-
-#if defined(V8_OS_WIN_X64)
- // On some platforms, specifically Win64, we need to reserve some pages at
- // the beginning of an executable space.
- // See src/heap/spaces.cc, MemoryAllocator::InitializeCodePageAllocator() and
- // https://cs.chromium.org/chromium/src/components/crash/content/app/crashpad_win.cc?rcl=fd680447881449fba2edcf0589320e7253719212&l=204
- // for details.
- if (engine_->code_manager()
- ->CanRegisterUnwindInfoForNonABICompliantCodeRange()) {
- code_allocator_.AllocateForCode(this, Heap::GetCodeRangeReservedAreaSize());
- }
-#endif
-
- uint32_t num_wasm_functions = module_->num_declared_functions;
- if (num_wasm_functions > 0) {
- code_table_.reset(new WasmCode* [num_wasm_functions] {});
-
- WasmCodeRefScope code_ref_scope;
- jump_table_ = CreateEmptyJumpTable(
- JumpTableAssembler::SizeForNumberOfSlots(num_wasm_functions));
+ if (module_->num_declared_functions > 0) {
+ code_table_.reset(new WasmCode* [module_->num_declared_functions] {});
}
+ AddCodeSpace(code_allocator_.GetSingleCodeRegion());
}
void NativeModule::ReserveCodeTableForTesting(uint32_t max_functions) {
@@ -669,9 +704,12 @@ void NativeModule::ReserveCodeTableForTesting(uint32_t max_functions) {
}
code_table_.reset(new_table);
+ CHECK_EQ(1, code_space_data_.size());
// Re-allocate jump table.
- jump_table_ = CreateEmptyJumpTable(
- JumpTableAssembler::SizeForNumberOfSlots(max_functions));
+ code_space_data_[0].jump_table = CreateEmptyJumpTableInRegion(
+ JumpTableAssembler::SizeForNumberOfSlots(max_functions),
+ code_space_data_[0].region);
+ main_jump_table_ = code_space_data_[0].jump_table;
}
void NativeModule::LogWasmCodes(Isolate* isolate) {
@@ -704,8 +742,10 @@ void NativeModule::UseLazyStub(uint32_t func_index) {
if (!lazy_compile_table_) {
uint32_t num_slots = module_->num_declared_functions;
WasmCodeRefScope code_ref_scope;
- lazy_compile_table_ = CreateEmptyJumpTable(
- JumpTableAssembler::SizeForNumberOfLazyFunctions(num_slots));
+ DCHECK_EQ(1, code_space_data_.size());
+ lazy_compile_table_ = CreateEmptyJumpTableInRegion(
+ JumpTableAssembler::SizeForNumberOfLazyFunctions(num_slots),
+ code_space_data_[0].region);
JumpTableAssembler::GenerateLazyCompileTable(
lazy_compile_table_->instruction_start(), num_slots,
module_->num_imported_functions,
@@ -718,7 +758,7 @@ void NativeModule::UseLazyStub(uint32_t func_index) {
Address lazy_compile_target =
lazy_compile_table_->instruction_start() +
JumpTableAssembler::LazyCompileSlotIndexToOffset(slot_index);
- JumpTableAssembler::PatchJumpTableSlot(jump_table_->instruction_start(),
+ JumpTableAssembler::PatchJumpTableSlot(main_jump_table_->instruction_start(),
slot_index, lazy_compile_target,
WasmCode::kFlushICache);
}
@@ -729,9 +769,10 @@ void NativeModule::SetRuntimeStubs(Isolate* isolate) {
DCHECK_EQ(kNullAddress, runtime_stub_entries_[0]); // Only called once.
#ifdef V8_EMBEDDED_BUILTINS
WasmCodeRefScope code_ref_scope;
- WasmCode* jump_table =
- CreateEmptyJumpTable(JumpTableAssembler::SizeForNumberOfStubSlots(
- WasmCode::kRuntimeStubCount));
+ DCHECK_EQ(1, code_space_data_.size());
+ WasmCode* jump_table = CreateEmptyJumpTableInRegion(
+ JumpTableAssembler::SizeForNumberOfStubSlots(WasmCode::kRuntimeStubCount),
+ code_space_data_[0].region);
Address base = jump_table->instruction_start();
EmbeddedData embedded_data = EmbeddedData::FromBlob();
#define RUNTIME_STUB(Name) Builtins::k##Name,
@@ -995,8 +1036,12 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) {
// Populate optimized code to the jump table unless there is an active
// redirection to the interpreter that should be preserved.
- bool update_jump_table =
- update_code_table && !has_interpreter_redirection(code->index());
+ DCHECK_IMPLIES(
+ main_jump_table_ == nullptr,
+ engine_->code_manager()->IsImplicitAllocationsDisabledForTesting());
+ bool update_jump_table = update_code_table &&
+ !has_interpreter_redirection(code->index()) &&
+ main_jump_table_;
// Ensure that interpreter entries always populate to the jump table.
if (code->kind_ == WasmCode::Kind::kInterpreterEntry) {
@@ -1006,8 +1051,8 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) {
if (update_jump_table) {
JumpTableAssembler::PatchJumpTableSlot(
- jump_table_->instruction_start(), slot_idx, code->instruction_start(),
- WasmCode::kFlushICache);
+ main_jump_table_->instruction_start(), slot_idx,
+ code->instruction_start(), WasmCode::kFlushICache);
}
}
WasmCodeRefScope::AddRef(code.get());
@@ -1065,11 +1110,22 @@ bool NativeModule::HasCode(uint32_t index) const {
return code_table_[index - module_->num_imported_functions] != nullptr;
}
-WasmCode* NativeModule::CreateEmptyJumpTable(uint32_t jump_table_size) {
+void NativeModule::SetWasmSourceMap(
+ std::unique_ptr<WasmModuleSourceMap> source_map) {
+ source_map_ = std::move(source_map);
+}
+
+WasmModuleSourceMap* NativeModule::GetWasmSourceMap() const {
+ return source_map_.get();
+}
+
+WasmCode* NativeModule::CreateEmptyJumpTableInRegion(
+ uint32_t jump_table_size, base::AddressRegion region) {
// Only call this if we really need a jump table.
DCHECK_LT(0, jump_table_size);
Vector<uint8_t> code_space =
- code_allocator_.AllocateForCode(this, jump_table_size);
+ code_allocator_.AllocateForCodeInRegion(this, jump_table_size, region);
+ DCHECK(!code_space.empty());
ZapCode(reinterpret_cast<Address>(code_space.begin()), code_space.size());
std::unique_ptr<WasmCode> code{new WasmCode{
this, // native_module
@@ -1090,6 +1146,48 @@ WasmCode* NativeModule::CreateEmptyJumpTable(uint32_t jump_table_size) {
return PublishCode(std::move(code));
}
+void NativeModule::AddCodeSpace(base::AddressRegion region) {
+ // Each code space must be at least twice as large as the overhead per code
+ // space. Otherwise, we are wasting too much memory.
+ const bool is_first_code_space = code_space_data_.empty();
+ const bool implicit_alloc_disabled =
+ engine_->code_manager()->IsImplicitAllocationsDisabledForTesting();
+
+#if defined(V8_OS_WIN64)
+ // On some platforms, specifically Win64, we need to reserve some pages at
+ // the beginning of an executable space.
+ // See src/heap/spaces.cc, MemoryAllocator::InitializeCodePageAllocator() and
+ // https://cs.chromium.org/chromium/src/components/crash/content/app/crashpad_win.cc?rcl=fd680447881449fba2edcf0589320e7253719212&l=204
+ // for details.
+ if (engine_->code_manager()
+ ->CanRegisterUnwindInfoForNonABICompliantCodeRange() &&
+ !implicit_alloc_disabled) {
+ size_t size = Heap::GetCodeRangeReservedAreaSize();
+ DCHECK_LT(0, size);
+ Vector<byte> padding = code_allocator_.AllocateForCode(this, size);
+ CHECK(region.contains(reinterpret_cast<Address>(padding.begin()),
+ padding.size()));
+ }
+#endif // V8_OS_WIN64
+
+ WasmCodeRefScope code_ref_scope;
+ WasmCode* jump_table = nullptr;
+ const uint32_t num_wasm_functions = module_->num_declared_functions;
+ const bool has_functions = num_wasm_functions > 0;
+ const bool needs_jump_table =
+ has_functions && is_first_code_space && !implicit_alloc_disabled;
+
+ if (needs_jump_table) {
+ jump_table = CreateEmptyJumpTableInRegion(
+ JumpTableAssembler::SizeForNumberOfSlots(num_wasm_functions), region);
+ CHECK(region.contains(jump_table->instruction_start()));
+ }
+
+ if (is_first_code_space) main_jump_table_ = jump_table;
+
+ code_space_data_.push_back(CodeSpaceData{region, jump_table});
+}
+
namespace {
class NativeModuleWireBytesStorage final : public WireBytesStorage {
public:
@@ -1137,17 +1235,17 @@ uint32_t NativeModule::GetJumpTableOffset(uint32_t func_index) const {
Address NativeModule::GetCallTargetForFunction(uint32_t func_index) const {
// Return the jump table slot for that function index.
- DCHECK_NOT_NULL(jump_table_);
+ DCHECK_NOT_NULL(main_jump_table_);
uint32_t slot_offset = GetJumpTableOffset(func_index);
- DCHECK_LT(slot_offset, jump_table_->instructions().size());
- return jump_table_->instruction_start() + slot_offset;
+ DCHECK_LT(slot_offset, main_jump_table_->instructions().size());
+ return main_jump_table_->instruction_start() + slot_offset;
}
uint32_t NativeModule::GetFunctionIndexFromJumpTableSlot(
Address slot_address) const {
DCHECK(is_jump_table_slot(slot_address));
- uint32_t slot_offset =
- static_cast<uint32_t>(slot_address - jump_table_->instruction_start());
+ uint32_t slot_offset = static_cast<uint32_t>(
+ slot_address - main_jump_table_->instruction_start());
uint32_t slot_idx = JumpTableAssembler::SlotOffsetToIndex(slot_offset);
DCHECK_LT(slot_idx, module_->num_declared_functions);
return module_->num_imported_functions + slot_idx;
@@ -1181,21 +1279,16 @@ WasmCodeManager::WasmCodeManager(WasmMemoryTracker* memory_tracker,
size_t max_committed)
: memory_tracker_(memory_tracker),
max_committed_code_space_(max_committed),
-#if defined(V8_OS_WIN_X64)
- is_win64_unwind_info_disabled_for_testing_(false),
-#endif
- total_committed_code_space_(0),
critical_committed_code_space_(max_committed / 2) {
DCHECK_LE(max_committed, kMaxWasmCodeMemory);
}
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
bool WasmCodeManager::CanRegisterUnwindInfoForNonABICompliantCodeRange() const {
return win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange() &&
- FLAG_win64_unwinding_info &&
- !is_win64_unwind_info_disabled_for_testing_;
+ FLAG_win64_unwinding_info;
}
-#endif
+#endif // V8_OS_WIN64
bool WasmCodeManager::Commit(base::AddressRegion region) {
// TODO(v8:8462): Remove eager commit once perf supports remapping.
@@ -1241,8 +1334,8 @@ void WasmCodeManager::Decommit(base::AddressRegion region) {
USE(old_committed);
TRACE_HEAP("Discarding system pages 0x%" PRIxPTR ":0x%" PRIxPTR "\n",
region.begin(), region.end());
- CHECK(allocator->DiscardSystemPages(reinterpret_cast<void*>(region.begin()),
- region.size()));
+ CHECK(allocator->SetPermissions(reinterpret_cast<void*>(region.begin()),
+ region.size(), PageAllocator::kNoAccess));
}
void WasmCodeManager::AssignRange(base::AddressRegion region,
@@ -1363,12 +1456,13 @@ std::shared_ptr<NativeModule> WasmCodeManager::NewNativeModule(
TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", ret.get(), start,
size);
-#if defined(V8_OS_WIN_X64)
- if (CanRegisterUnwindInfoForNonABICompliantCodeRange()) {
+#if defined(V8_OS_WIN64)
+ if (CanRegisterUnwindInfoForNonABICompliantCodeRange() &&
+ !implicit_allocations_disabled_for_testing_) {
win64_unwindinfo::RegisterNonABICompliantCodeRange(
reinterpret_cast<void*>(start), size);
}
-#endif
+#endif // V8_OS_WIN64
base::MutexGuard lock(&native_modules_mutex_);
lookup_map_.insert(std::make_pair(start, std::make_pair(end, ret.get())));
@@ -1481,12 +1575,13 @@ void WasmCodeManager::FreeNativeModule(Vector<VirtualMemory> owned_code_space,
TRACE_HEAP("VMem Release: 0x%" PRIxPTR ":0x%" PRIxPTR " (%zu)\n",
code_space.address(), code_space.end(), code_space.size());
-#if defined(V8_OS_WIN_X64)
- if (CanRegisterUnwindInfoForNonABICompliantCodeRange()) {
+#if defined(V8_OS_WIN64)
+ if (CanRegisterUnwindInfoForNonABICompliantCodeRange() &&
+ !implicit_allocations_disabled_for_testing_) {
win64_unwindinfo::UnregisterNonABICompliantCodeRange(
reinterpret_cast<void*>(code_space.address()));
}
-#endif
+#endif // V8_OS_WIN64
lookup_map_.erase(code_space.address());
memory_tracker_->ReleaseReservation(code_space.size());
diff --git a/deps/v8/src/wasm/wasm-code-manager.h b/deps/v8/src/wasm/wasm-code-manager.h
index db7b4f061d..c2e5249e5e 100644
--- a/deps/v8/src/wasm/wasm-code-manager.h
+++ b/deps/v8/src/wasm/wasm-code-manager.h
@@ -23,6 +23,7 @@
#include "src/wasm/compilation-environment.h"
#include "src/wasm/wasm-features.h"
#include "src/wasm/wasm-limits.h"
+#include "src/wasm/wasm-module-sourcemap.h"
#include "src/wasm/wasm-tier.h"
namespace v8 {
@@ -61,6 +62,10 @@ class V8_EXPORT_PRIVATE DisjointAllocationPool final {
// failure.
base::AddressRegion Allocate(size_t size);
+ // Allocate a contiguous region of size {size} within {region}. Return an
+ // empty pool on failure.
+ base::AddressRegion AllocateInRegion(size_t size, base::AddressRegion);
+
bool IsEmpty() const { return regions_.empty(); }
const std::list<base::AddressRegion>& regions() const { return regions_; }
@@ -295,6 +300,11 @@ class WasmCodeAllocator {
// Allocate code space. Returns a valid buffer or fails with OOM (crash).
Vector<byte> AllocateForCode(NativeModule*, size_t size);
+ // Allocate code space within a specific region. Returns a valid buffer or
+ // fails with OOM (crash).
+ Vector<byte> AllocateForCodeInRegion(NativeModule*, size_t size,
+ base::AddressRegion);
+
// Sets permissions of all owned code space to executable, or read-write (if
// {executable} is false). Returns true on success.
V8_EXPORT_PRIVATE bool SetExecutable(bool executable);
@@ -302,6 +312,10 @@ class WasmCodeAllocator {
// Free memory pages of all given code objects. Used for wasm code GC.
void FreeCode(Vector<WasmCode* const>);
+ // Returns the region of the single code space managed by this code allocator.
+ // Will fail if more than one code space has been created.
+ base::AddressRegion GetSingleCodeRegion() const;
+
private:
// The engine-wide wasm code manager.
WasmCodeManager* const code_manager_;
@@ -392,6 +406,9 @@ class V8_EXPORT_PRIVATE NativeModule final {
WasmCode* GetCode(uint32_t index) const;
bool HasCode(uint32_t index) const;
+ void SetWasmSourceMap(std::unique_ptr<WasmModuleSourceMap> source_map);
+ WasmModuleSourceMap* GetWasmSourceMap() const;
+
Address runtime_stub_entry(WasmCode::RuntimeStubId index) const {
DCHECK_LT(index, WasmCode::kRuntimeStubCount);
Address entry_address = runtime_stub_entries_[index];
@@ -400,17 +417,18 @@ class V8_EXPORT_PRIVATE NativeModule final {
}
Address jump_table_start() const {
- return jump_table_ ? jump_table_->instruction_start() : kNullAddress;
+ return main_jump_table_ ? main_jump_table_->instruction_start()
+ : kNullAddress;
}
uint32_t GetJumpTableOffset(uint32_t func_index) const;
bool is_jump_table_slot(Address address) const {
- return jump_table_->contains(address);
+ return main_jump_table_->contains(address);
}
- // Returns the target to call for the given function (returns a jump table
- // slot within {jump_table_}).
+ // Returns the canonical target to call for the given function (the slot in
+ // the first jump table).
Address GetCallTargetForFunction(uint32_t func_index) const;
// Reverse lookup from a given call target (i.e. a jump table slot as the
@@ -485,9 +503,15 @@ class V8_EXPORT_PRIVATE NativeModule final {
private:
friend class WasmCode;
+ friend class WasmCodeAllocator;
friend class WasmCodeManager;
friend class NativeModuleModificationScope;
+ struct CodeSpaceData {
+ base::AddressRegion region;
+ WasmCode* jump_table;
+ };
+
// Private constructor, called via {WasmCodeManager::NewNativeModule()}.
NativeModule(WasmEngine* engine, const WasmFeatures& enabled_features,
bool can_request_more, VirtualMemory code_space,
@@ -507,7 +531,11 @@ class V8_EXPORT_PRIVATE NativeModule final {
WasmCode* AddAndPublishAnonymousCode(Handle<Code>, WasmCode::Kind kind,
const char* name = nullptr);
- WasmCode* CreateEmptyJumpTable(uint32_t jump_table_size);
+ WasmCode* CreateEmptyJumpTableInRegion(uint32_t jump_table_size,
+ base::AddressRegion);
+
+ // Called by the {WasmCodeAllocator} to register a new code space.
+ void AddCodeSpace(base::AddressRegion);
// Hold the {allocation_mutex_} when calling this method.
bool has_interpreter_redirection(uint32_t func_index) {
@@ -546,6 +574,8 @@ class V8_EXPORT_PRIVATE NativeModule final {
// tasks can keep this alive.
std::shared_ptr<const WasmModule> module_;
+ std::unique_ptr<WasmModuleSourceMap> source_map_;
+
// Wire bytes, held in a shared_ptr so they can be kept alive by the
// {WireBytesStorage}, held by background compile tasks.
std::shared_ptr<OwnedVector<const uint8_t>> wire_bytes_;
@@ -556,8 +586,9 @@ class V8_EXPORT_PRIVATE NativeModule final {
// Jump table used for runtime stubs (i.e. trampolines to embedded builtins).
WasmCode* runtime_stub_table_ = nullptr;
- // Jump table used to easily redirect wasm function calls.
- WasmCode* jump_table_ = nullptr;
+ // Jump table used by external calls (from JS). Wasm calls use one of the jump
+ // tables stored in {code_space_data_}.
+ WasmCode* main_jump_table_ = nullptr;
// Lazy compile stub table, containing entries to jump to the
// {WasmCompileLazy} builtin, passing the function index.
@@ -587,6 +618,9 @@ class V8_EXPORT_PRIVATE NativeModule final {
// this module marking those functions that have been redirected.
std::unique_ptr<uint8_t[]> interpreter_redirections_;
+ // Data (especially jump table) per code space.
+ std::vector<CodeSpaceData> code_space_data_;
+
// End of fields protected by {allocation_mutex_}.
//////////////////////////////////////////////////////////////////////////////
@@ -610,9 +644,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
}
#endif
-#if defined(V8_OS_WIN_X64)
+#if defined(V8_OS_WIN64)
bool CanRegisterUnwindInfoForNonABICompliantCodeRange() const;
-#endif
+#endif // V8_OS_WIN64
NativeModule* LookupNativeModule(Address pc) const;
WasmCode* LookupCode(Address pc) const;
@@ -622,11 +656,13 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
void SetMaxCommittedMemoryForTesting(size_t limit);
-#if defined(V8_OS_WIN_X64)
- void DisableWin64UnwindInfoForTesting() {
- is_win64_unwind_info_disabled_for_testing_ = true;
+ void DisableImplicitAllocationsForTesting() {
+ implicit_allocations_disabled_for_testing_ = true;
+ }
+
+ bool IsImplicitAllocationsDisabledForTesting() const {
+ return implicit_allocations_disabled_for_testing_;
}
-#endif
static size_t EstimateNativeModuleCodeSize(const WasmModule* module);
static size_t EstimateNativeModuleNonCodeSize(const WasmModule* module);
@@ -654,11 +690,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
size_t max_committed_code_space_;
-#if defined(V8_OS_WIN_X64)
- bool is_win64_unwind_info_disabled_for_testing_;
-#endif
+ bool implicit_allocations_disabled_for_testing_ = false;
- std::atomic<size_t> total_committed_code_space_;
+ std::atomic<size_t> total_committed_code_space_{0};
// If the committed code space exceeds {critical_committed_code_space_}, then
// we trigger a GC before creating the next module. This value is set to the
// currently committed space plus 50% of the available code space on creation
diff --git a/deps/v8/src/wasm/wasm-engine.cc b/deps/v8/src/wasm/wasm-engine.cc
index 7b91b16b80..97111f8349 100644
--- a/deps/v8/src/wasm/wasm-engine.cc
+++ b/deps/v8/src/wasm/wasm-engine.cc
@@ -278,13 +278,8 @@ Handle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs(
asm_wasm_data->managed_native_module().get();
Handle<FixedArray> export_wrappers =
handle(asm_wasm_data->export_wrappers(), isolate);
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
- native_module->module());
-
- Handle<WasmModuleObject> module_object =
- WasmModuleObject::New(isolate, std::move(native_module), script,
- export_wrappers, code_size_estimate);
+ Handle<WasmModuleObject> module_object = WasmModuleObject::New(
+ isolate, std::move(native_module), script, export_wrappers);
module_object->set_asm_js_offset_table(asm_wasm_data->asm_js_offset_table());
return module_object;
}
@@ -310,9 +305,6 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
Handle<Script> script =
CreateWasmScript(isolate, bytes, native_module->module()->source_map_url);
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
- native_module->module());
// Create the module object.
// TODO(clemensh): For the same module (same bytes / same hash), we should
@@ -323,9 +315,8 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
// and information needed at instantiation time. This object needs to be
// serializable. Instantiation may occur off a deserialized version of this
// object.
- Handle<WasmModuleObject> module_object =
- WasmModuleObject::New(isolate, std::move(native_module), script,
- export_wrappers, code_size_estimate);
+ Handle<WasmModuleObject> module_object = WasmModuleObject::New(
+ isolate, std::move(native_module), script, export_wrappers);
// Finish the Wasm script now and make it public to the debugger.
isolate->debug()->OnAfterCompile(script);
@@ -451,14 +442,13 @@ Handle<WasmModuleObject> WasmEngine::ImportNativeModule(
Isolate* isolate, std::shared_ptr<NativeModule> shared_native_module) {
NativeModule* native_module = shared_native_module.get();
ModuleWireBytes wire_bytes(native_module->wire_bytes());
- const WasmModule* module = native_module->module();
- Handle<Script> script =
- CreateWasmScript(isolate, wire_bytes, module->source_map_url);
- size_t code_size = native_module->committed_code_space();
+ Handle<Script> script = CreateWasmScript(
+ isolate, wire_bytes, native_module->module()->source_map_url);
+ Handle<FixedArray> export_wrappers;
+ CompileJsToWasmWrappers(isolate, native_module->module(), &export_wrappers);
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
- isolate, std::move(shared_native_module), script, code_size);
- CompileJsToWasmWrappers(isolate, native_module->module(),
- handle(module_object->export_wrappers(), isolate));
+ isolate, std::move(shared_native_module), script, export_wrappers,
+ native_module->committed_code_space());
{
base::MutexGuard lock(&mutex_);
DCHECK_EQ(1, isolates_.count(isolate));
@@ -681,6 +671,16 @@ void WasmEngine::LogOutstandingCodesForIsolate(Isolate* isolate) {
}
std::shared_ptr<NativeModule> WasmEngine::NewNativeModule(
+ Isolate* isolate, const WasmFeatures& enabled,
+ std::shared_ptr<const WasmModule> module) {
+ size_t code_size_estimate =
+ wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
+ return NewNativeModule(isolate, enabled, code_size_estimate,
+ wasm::NativeModule::kCanAllocateMoreMemory,
+ std::move(module));
+}
+
+std::shared_ptr<NativeModule> WasmEngine::NewNativeModule(
Isolate* isolate, const WasmFeatures& enabled, size_t code_size_estimate,
bool can_request_more, std::shared_ptr<const WasmModule> module) {
std::shared_ptr<NativeModule> native_module =
diff --git a/deps/v8/src/wasm/wasm-engine.h b/deps/v8/src/wasm/wasm-engine.h
index 69e6cdae6e..401cf2b880 100644
--- a/deps/v8/src/wasm/wasm-engine.h
+++ b/deps/v8/src/wasm/wasm-engine.h
@@ -182,6 +182,9 @@ class V8_EXPORT_PRIVATE WasmEngine {
// TODO(titzer): isolate is only required here for CompilationState.
std::shared_ptr<NativeModule> NewNativeModule(
Isolate* isolate, const WasmFeatures& enabled_features,
+ std::shared_ptr<const WasmModule> module);
+ std::shared_ptr<NativeModule> NewNativeModule(
+ Isolate* isolate, const WasmFeatures& enabled_features,
size_t code_size_estimate, bool can_request_more,
std::shared_ptr<const WasmModule> module);
diff --git a/deps/v8/src/wasm/wasm-external-refs.cc b/deps/v8/src/wasm/wasm-external-refs.cc
index 08e6139abe..9ca45183ef 100644
--- a/deps/v8/src/wasm/wasm-external-refs.cc
+++ b/deps/v8/src/wasm/wasm-external-refs.cc
@@ -80,37 +80,73 @@ void int64_to_float32_wrapper(Address data) {
void uint64_to_float32_wrapper(Address data) {
uint64_t input = ReadUnalignedValue<uint64_t>(data);
- float result = static_cast<float>(input);
-
-#if V8_CC_MSVC
- // With MSVC we use static_cast<float>(uint32_t) instead of
- // static_cast<float>(uint64_t) to achieve round-to-nearest-ties-even
- // semantics. The idea is to calculate
- // static_cast<float>(high_word) * 2^32 + static_cast<float>(low_word). To
- // achieve proper rounding in all cases we have to adjust the high_word
- // with a "rounding bit" sometimes. The rounding bit is stored in the LSB of
- // the high_word if the low_word may affect the rounding of the high_word.
- uint32_t low_word = static_cast<uint32_t>(input & 0xFFFFFFFF);
- uint32_t high_word = static_cast<uint32_t>(input >> 32);
-
- float shift = static_cast<float>(1ull << 32);
- // If the MSB of the high_word is set, then we make space for a rounding bit.
- if (high_word < 0x80000000) {
- high_word <<= 1;
- shift = static_cast<float>(1ull << 31);
+#if defined(V8_OS_WIN)
+ // On Windows, the FP stack registers calculate with less precision, which
+ // leads to a uint64_t to float32 conversion which does not satisfy the
+ // WebAssembly specification. Therefore we do a different approach here:
+ //
+ // / leading 0 \/ 24 float data bits \/ for rounding \/ trailing 0 \
+ // 00000000000001XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX100000000000000
+ //
+ // Float32 can only represent 24 data bit (1 implicit 1 bit + 23 mantissa
+ // bits). Starting from the most significant 1 bit, we can therefore extract
+ // 24 bits and do the conversion only on them. The other bits can affect the
+ // result only through rounding. Rounding works as follows:
+ // * If the most significant rounding bit is not set, then round down.
+ // * If the most significant rounding bit is set, and at least one of the
+ // other rounding bits is set, then round up.
+ // * If the most significant rounding bit is set, but all other rounding bits
+ // are not set, then round to even.
+ // We can aggregate 'all other rounding bits' in the second-most significant
+ // rounding bit.
+ // The resulting algorithm is therefore as follows:
+ // * Check if the distance between the most significant bit (MSB) and the
+ // least significant bit (LSB) is greater than 25 bits. If the distance is
+ // less or equal to 25 bits, the uint64 to float32 conversion is anyways
+ // exact, and we just use the C++ conversion.
+ // * Find the most significant bit (MSB).
+ // * Starting from the MSB, extract 25 bits (24 data bits + the first rounding
+ // bit).
+ // * The remaining rounding bits are guaranteed to contain at least one 1 bit,
+ // due to the check we did above.
+ // * Store the 25 bits + 1 aggregated bit in an uint32_t.
+ // * Convert this uint32_t to float. The conversion does the correct rounding
+ // now.
+ // * Shift the result back to the original magnitude.
+ uint32_t leading_zeros = base::bits::CountLeadingZeros(input);
+ uint32_t trailing_zeros = base::bits::CountTrailingZeros(input);
+ constexpr uint32_t num_extracted_bits = 25;
+ // Check if there are any rounding bits we have to aggregate.
+ if (leading_zeros + trailing_zeros + num_extracted_bits < 64) {
+ // Shift to extract the data bits.
+ uint32_t num_aggregation_bits = 64 - num_extracted_bits - leading_zeros;
+ // We extract the bits we want to convert. Note that we convert one bit more
+ // than necessary. This bit is a placeholder where we will store the
+ // aggregation bit.
+ int32_t extracted_bits =
+ static_cast<int32_t>(input >> (num_aggregation_bits - 1));
+ // Set the aggregation bit. We don't have to clear the slot first, because
+ // the bit there is also part of the aggregation.
+ extracted_bits |= 1;
+ float result = static_cast<float>(extracted_bits);
+ // We have to shift the result back. The shift amount is
+ // (num_aggregation_bits - 1), which is the shift amount we did originally,
+ // and (-2), which is for the two additional bits we kept originally for
+ // rounding.
+ int32_t shift_back = static_cast<int32_t>(num_aggregation_bits) - 1 - 2;
+ // Calculate the multiplier to shift the extracted bits back to the original
+ // magnitude. This multiplier is a power of two, so in the float32 bit
+ // representation we just have to construct the correct exponent and put it
+ // at the correct bit offset. The exponent consists of 8 bits, starting at
+ // the second MSB (a.k.a '<< 23'). The encoded exponent itself is
+ // ('actual exponent' - 127).
+ int32_t multiplier_bits = ((shift_back - 127) & 0xff) << 23;
+ result *= bit_cast<float>(multiplier_bits);
+ WriteUnalignedValue<float>(data, result);
+ return;
}
-
- if ((high_word & 0xFE000000) && low_word) {
- // Set the rounding bit.
- high_word |= 1;
- }
-
- result = static_cast<float>(high_word);
- result *= shift;
- result += static_cast<float>(low_word);
-#endif
-
- WriteUnalignedValue<float>(data, result);
+#endif // defined(V8_OS_WIN)
+ WriteUnalignedValue<float>(data, static_cast<float>(input));
}
void int64_to_float64_wrapper(Address data) {
diff --git a/deps/v8/src/wasm/wasm-feature-flags.h b/deps/v8/src/wasm/wasm-feature-flags.h
index 77d46fdc0d..36f9ebd8a4 100644
--- a/deps/v8/src/wasm/wasm-feature-flags.h
+++ b/deps/v8/src/wasm/wasm-feature-flags.h
@@ -5,29 +5,27 @@
#ifndef V8_WASM_WASM_FEATURE_FLAGS_H_
#define V8_WASM_WASM_FEATURE_FLAGS_H_
-// The SEPARATOR argument allows generating proper comma-separated lists.
-#define FOREACH_WASM_FEATURE_FLAG(V, SEPARATOR) \
- V(mv, "multi-value support", false) \
- SEPARATOR \
- V(eh, "exception handling opcodes", false) \
- SEPARATOR \
- V(se, "sign extension opcodes", true) \
- SEPARATOR \
- V(sat_f2i_conversions, "saturating float conversion opcodes", true) \
- SEPARATOR \
- V(threads, "thread opcodes", false) \
- SEPARATOR \
- V(simd, "SIMD opcodes", false) \
- SEPARATOR \
- V(anyref, "anyref opcodes", false) \
- SEPARATOR \
- V(bigint, "JS BigInt support", false) \
- SEPARATOR \
- V(bulk_memory, "bulk memory opcodes", true) \
- SEPARATOR \
- V(return_call, "return call opcodes", false) \
- SEPARATOR \
- V(type_reflection, "wasm type reflection in JS", false) \
- SEPARATOR \
+#define FOREACH_WASM_EXPERIMENTAL_FEATURE_FLAG(V) \
+ V(mv, "multi-value support", false) \
+ V(eh, "exception handling opcodes", false) \
+ V(threads, "thread opcodes", false) \
+ V(simd, "SIMD opcodes", false) \
+ V(bigint, "JS BigInt support", false) \
+ V(return_call, "return call opcodes", false) \
V(compilation_hints, "compilation hints section", false)
+
+#define FOREACH_WASM_STAGING_FEATURE_FLAG(V) \
+ V(anyref, "anyref opcodes", false) \
+ V(type_reflection, "wasm type reflection in JS", false)
+
+#define FOREACH_WASM_SHIPPED_FEATURE_FLAG(V) \
+ V(bulk_memory, "bulk memory opcodes", true) \
+ V(sat_f2i_conversions, "saturating float conversion opcodes", true) \
+ V(se, "sign extension opcodes", true)
+
+#define FOREACH_WASM_FEATURE_FLAG(V) \
+ FOREACH_WASM_EXPERIMENTAL_FEATURE_FLAG(V) \
+ FOREACH_WASM_STAGING_FEATURE_FLAG(V) \
+ FOREACH_WASM_SHIPPED_FEATURE_FLAG(V)
+
#endif // V8_WASM_WASM_FEATURE_FLAGS_H_
diff --git a/deps/v8/src/wasm/wasm-features.cc b/deps/v8/src/wasm/wasm-features.cc
index fc0286655e..d62db91750 100644
--- a/deps/v8/src/wasm/wasm-features.cc
+++ b/deps/v8/src/wasm/wasm-features.cc
@@ -11,17 +11,17 @@ namespace v8 {
namespace internal {
namespace wasm {
-#define COMMA ,
-#define SPACE
-#define DO_UNION(feat, desc, val) dst->feat |= src.feat;
-#define FLAG_REF(feat, desc, val) FLAG_experimental_wasm_##feat
void UnionFeaturesInto(WasmFeatures* dst, const WasmFeatures& src) {
- FOREACH_WASM_FEATURE(DO_UNION, SPACE);
+#define DO_UNION(feat, desc, val) dst->feat |= src.feat;
+ FOREACH_WASM_FEATURE(DO_UNION);
+#undef DO_UNION
}
WasmFeatures WasmFeaturesFromFlags() {
- return WasmFeatures{FOREACH_WASM_FEATURE(FLAG_REF, COMMA)};
+#define FLAG_REF(feat, desc, val) FLAG_experimental_wasm_##feat,
+ return WasmFeatures(FOREACH_WASM_FEATURE(FLAG_REF){});
+#undef FLAG_REF
}
WasmFeatures WasmFeaturesFromIsolate(Isolate* isolate) {
@@ -31,10 +31,6 @@ WasmFeatures WasmFeaturesFromIsolate(Isolate* isolate) {
return features;
}
-#undef DO_UNION
-#undef FLAG_REF
-#undef SPACE
-#undef COMMA
} // namespace wasm
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/wasm/wasm-features.h b/deps/v8/src/wasm/wasm-features.h
index 2c6ab0f85a..956982536d 100644
--- a/deps/v8/src/wasm/wasm-features.h
+++ b/deps/v8/src/wasm/wasm-features.h
@@ -17,37 +17,50 @@ namespace internal {
class Isolate;
namespace wasm {
-#define COMMA ,
-#define SPACE
-#define DECL_FIELD(feat, desc, val) bool feat = false;
-#define JUST_TRUE(feat, desc, val) true
-#define JUST_FALSE(feat, desc, val) false
-#define DECL_PARAM(feat, desc, val) bool p##feat
-#define DO_INIT(feat, desc, val) feat(p##feat)
+// This is an empty type to indicate the end of the {WasmFeatures} struct. We
+// use the {end_t} type there to avoid trailing commas that get generated by
+// the macro generators. We considered the following alternatives:
+// * Add "separators" to the {FOREACH_WASM_FEATURE_FLAGS} between entries. This
+// does not work when we want to have different kinds of flags, e.g. for
+// experimental, staging, and shipped features.
+// * Use initialization lists, e.g. construct {WasmFeatures} with
+// "WasmFeatures{true, true, ..., true,}". This solves the comma problem,
+// because trailing commas are allowed here. However, we cannot
+// default-initialize the fields of {WasmFeatures} anymore. This seems
+// error-prone, because default-constructed {WasmFeatures} structs are already
+// used in the code base.
+// * Avoid the use of {constexpr}. With that we would be more flexible with how
+// we generate {kAllWasmFeatures} and {kNoWasmFeatures}. These values may be
+// used in performance-critical code, however, e.g. in the decoder or in the
+// interpreter.
+struct end_t {};
// Enabled or detected features.
struct WasmFeatures {
- FOREACH_WASM_FEATURE(DECL_FIELD, SPACE)
+#define DECL_FIELD(feat, desc, val) bool feat = false;
+ FOREACH_WASM_FEATURE(DECL_FIELD)
+#undef DECL_FIELD
+ // Marker for the end of the list, see the comment at {end_t}.
+ end_t end_;
+#define DECL_PARAM(feat, desc, val) bool p##feat,
+#define DO_INIT(feat, desc, val) feat(p##feat),
+ explicit constexpr WasmFeatures(FOREACH_WASM_FEATURE(DECL_PARAM) end_t)
+ : FOREACH_WASM_FEATURE(DO_INIT) end_() {}
+#undef DECL_PARAM
+#undef DO_INIT
constexpr WasmFeatures() = default;
-
- explicit constexpr WasmFeatures(FOREACH_WASM_FEATURE(DECL_PARAM, COMMA))
- : FOREACH_WASM_FEATURE(DO_INIT, COMMA) {}
};
-static constexpr WasmFeatures kAllWasmFeatures{
- FOREACH_WASM_FEATURE(JUST_TRUE, COMMA)};
-
-static constexpr WasmFeatures kNoWasmFeatures{
- FOREACH_WASM_FEATURE(JUST_FALSE, COMMA)};
-
+#define JUST_TRUE(feat, desc, val) true,
+static constexpr WasmFeatures kAllWasmFeatures(
+ FOREACH_WASM_FEATURE(JUST_TRUE){});
#undef JUST_TRUE
+
+#define JUST_FALSE(feat, desc, val) false,
+static constexpr WasmFeatures kNoWasmFeatures(
+ FOREACH_WASM_FEATURE(JUST_FALSE){});
#undef JUST_FALSE
-#undef DECL_FIELD
-#undef DECL_PARAM
-#undef DO_INIT
-#undef COMMA
-#undef SPACE
static constexpr WasmFeatures kAsmjsWasmFeatures = kNoWasmFeatures;
diff --git a/deps/v8/src/wasm/wasm-interpreter.cc b/deps/v8/src/wasm/wasm-interpreter.cc
index 4449439896..299128860d 100644
--- a/deps/v8/src/wasm/wasm-interpreter.cc
+++ b/deps/v8/src/wasm/wasm-interpreter.cc
@@ -1676,7 +1676,7 @@ class ThreadImpl {
converter<ctype, mtype>{}(ReadLittleEndianValue<mtype>(addr)));
Push(result);
- *len = 1 + imm.length;
+ *len += imm.length;
if (FLAG_trace_wasm_memory) {
MemoryTracingInfo info(imm.offset + index, false, rep);
@@ -1702,7 +1702,7 @@ class ThreadImpl {
return false;
}
WriteLittleEndianValue<mtype>(addr, converter<mtype, ctype>{}(val));
- *len = 1 + imm.length;
+ *len += imm.length;
if (FLAG_trace_wasm_memory) {
MemoryTracingInfo info(imm.offset + index, true, rep);
@@ -2241,14 +2241,27 @@ class ThreadImpl {
Push(WasmValue(Simd128(res))); \
return true; \
}
+ BINOP_CASE(F64x2Add, f64x2, float2, 2, a + b)
+ BINOP_CASE(F64x2Sub, f64x2, float2, 2, a - b)
+ BINOP_CASE(F64x2Mul, f64x2, float2, 2, a * b)
+ BINOP_CASE(F64x2Div, f64x2, float2, 2, base::Divide(a, b))
+ BINOP_CASE(F64x2Min, f64x2, float2, 2, JSMin(a, b))
+ BINOP_CASE(F64x2Max, f64x2, float2, 2, JSMax(a, b))
BINOP_CASE(F32x4Add, f32x4, float4, 4, a + b)
BINOP_CASE(F32x4Sub, f32x4, float4, 4, a - b)
BINOP_CASE(F32x4Mul, f32x4, float4, 4, a * b)
- BINOP_CASE(F32x4Min, f32x4, float4, 4, a < b ? a : b)
- BINOP_CASE(F32x4Max, f32x4, float4, 4, a > b ? a : b)
+ BINOP_CASE(F32x4Div, f32x4, float4, 4, a / b)
+ BINOP_CASE(F32x4Min, f32x4, float4, 4, JSMin(a, b))
+ BINOP_CASE(F32x4Max, f32x4, float4, 4, JSMax(a, b))
BINOP_CASE(I64x2Add, i64x2, int2, 2, base::AddWithWraparound(a, b))
BINOP_CASE(I64x2Sub, i64x2, int2, 2, base::SubWithWraparound(a, b))
BINOP_CASE(I64x2Mul, i64x2, int2, 2, base::MulWithWraparound(a, b))
+ BINOP_CASE(I64x2MinS, i64x2, int2, 2, a < b ? a : b)
+ BINOP_CASE(I64x2MinU, i64x2, int2, 2,
+ static_cast<uint64_t>(a) < static_cast<uint64_t>(b) ? a : b)
+ BINOP_CASE(I64x2MaxS, i64x2, int2, 2, a > b ? a : b)
+ BINOP_CASE(I64x2MaxU, i64x2, int2, 2,
+ static_cast<uint64_t>(a) > static_cast<uint64_t>(b) ? a : b)
BINOP_CASE(I32x4Add, i32x4, int4, 4, base::AddWithWraparound(a, b))
BINOP_CASE(I32x4Sub, i32x4, int4, 4, base::SubWithWraparound(a, b))
BINOP_CASE(I32x4Mul, i32x4, int4, 4, base::MulWithWraparound(a, b))
@@ -2422,40 +2435,32 @@ class ThreadImpl {
case kExprS128StoreMem:
return ExecuteStore<Simd128, Simd128>(decoder, code, pc, len,
MachineRepresentation::kSimd128);
-#define SHIFT_CASE(op, name, stype, count, expr) \
- case kExpr##op: { \
- SimdShiftImmediate<Decoder::kNoValidate> imm(decoder, code->at(pc)); \
- *len += 1; \
- WasmValue v = Pop(); \
- stype s = v.to_s128().to_##name(); \
- stype res; \
- for (size_t i = 0; i < count; ++i) { \
- auto a = s.val[i]; \
- res.val[i] = expr; \
- } \
- Push(WasmValue(Simd128(res))); \
- return true; \
- }
- SHIFT_CASE(I64x2Shl, i64x2, int2, 2,
- static_cast<uint64_t>(a) << imm.shift)
- SHIFT_CASE(I64x2ShrS, i64x2, int2, 2, a >> imm.shift)
- SHIFT_CASE(I64x2ShrU, i64x2, int2, 2,
- static_cast<uint64_t>(a) >> imm.shift)
- SHIFT_CASE(I32x4Shl, i32x4, int4, 4,
- static_cast<uint32_t>(a) << imm.shift)
- SHIFT_CASE(I32x4ShrS, i32x4, int4, 4, a >> imm.shift)
- SHIFT_CASE(I32x4ShrU, i32x4, int4, 4,
- static_cast<uint32_t>(a) >> imm.shift)
- SHIFT_CASE(I16x8Shl, i16x8, int8, 8,
- static_cast<uint16_t>(a) << imm.shift)
- SHIFT_CASE(I16x8ShrS, i16x8, int8, 8, a >> imm.shift)
- SHIFT_CASE(I16x8ShrU, i16x8, int8, 8,
- static_cast<uint16_t>(a) >> imm.shift)
- SHIFT_CASE(I8x16Shl, i8x16, int16, 16,
- static_cast<uint8_t>(a) << imm.shift)
- SHIFT_CASE(I8x16ShrS, i8x16, int16, 16, a >> imm.shift)
+#define SHIFT_CASE(op, name, stype, count, expr) \
+ case kExpr##op: { \
+ uint32_t shift = Pop().to<uint32_t>(); \
+ WasmValue v = Pop(); \
+ stype s = v.to_s128().to_##name(); \
+ stype res; \
+ for (size_t i = 0; i < count; ++i) { \
+ auto a = s.val[i]; \
+ res.val[i] = expr; \
+ } \
+ Push(WasmValue(Simd128(res))); \
+ return true; \
+ }
+ SHIFT_CASE(I64x2Shl, i64x2, int2, 2, static_cast<uint64_t>(a) << shift)
+ SHIFT_CASE(I64x2ShrS, i64x2, int2, 2, a >> shift)
+ SHIFT_CASE(I64x2ShrU, i64x2, int2, 2, static_cast<uint64_t>(a) >> shift)
+ SHIFT_CASE(I32x4Shl, i32x4, int4, 4, static_cast<uint32_t>(a) << shift)
+ SHIFT_CASE(I32x4ShrS, i32x4, int4, 4, a >> shift)
+ SHIFT_CASE(I32x4ShrU, i32x4, int4, 4, static_cast<uint32_t>(a) >> shift)
+ SHIFT_CASE(I16x8Shl, i16x8, int8, 8, static_cast<uint16_t>(a) << shift)
+ SHIFT_CASE(I16x8ShrS, i16x8, int8, 8, a >> shift)
+ SHIFT_CASE(I16x8ShrU, i16x8, int8, 8, static_cast<uint16_t>(a) >> shift)
+ SHIFT_CASE(I8x16Shl, i8x16, int16, 16, static_cast<uint8_t>(a) << shift)
+ SHIFT_CASE(I8x16ShrS, i8x16, int16, 16, a >> shift)
SHIFT_CASE(I8x16ShrU, i8x16, int16, 16,
- static_cast<uint8_t>(a) >> imm.shift)
+ static_cast<uint8_t>(a) >> shift)
#undef SHIFT_CASE
#define CONVERT_CASE(op, src_type, name, dst_type, count, start_index, ctype, \
expr) \
@@ -3042,8 +3047,8 @@ class ThreadImpl {
code->at(pc));
HandleScope handle_scope(isolate_); // Avoid leaking handles.
- Handle<WasmExportedFunction> function =
- WasmInstanceObject::GetOrCreateWasmExportedFunction(
+ Handle<WasmExternalFunction> function =
+ WasmInstanceObject::GetOrCreateWasmExternalFunction(
isolate_, instance_object_, imm.index);
Push(WasmValue(function));
len = 1 + imm.length;
@@ -3679,7 +3684,7 @@ class ThreadImpl {
WasmFeatures enabled_features = WasmFeaturesFromIsolate(isolate);
if (code->kind() == WasmCode::kWasmToJsWrapper &&
- !IsJSCompatibleSignature(sig, enabled_features.bigint)) {
+ !IsJSCompatibleSignature(sig, enabled_features)) {
Drop(num_args); // Pop arguments before throwing.
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kWasmTrapTypeError));
diff --git a/deps/v8/src/wasm/wasm-js.cc b/deps/v8/src/wasm/wasm-js.cc
index 1ee76fc11d..f10f5ff2bf 100644
--- a/deps/v8/src/wasm/wasm-js.cc
+++ b/deps/v8/src/wasm/wasm-js.cc
@@ -1223,6 +1223,9 @@ bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
} else if (enabled_features.anyref &&
string->StringEquals(v8_str(isolate, "anyfunc"))) {
*type = i::wasm::kWasmFuncRef;
+ } else if (enabled_features.eh &&
+ string->StringEquals(v8_str(isolate, "exnref"))) {
+ *type = i::wasm::kWasmExnRef;
} else {
// Unrecognized type.
*type = i::wasm::kWasmStmt;
@@ -1337,7 +1340,8 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
global_obj->SetF64(f64_value);
break;
}
- case i::wasm::kWasmAnyRef: {
+ case i::wasm::kWasmAnyRef:
+ case i::wasm::kWasmExnRef: {
if (args.Length() < 2) {
// When no inital value is provided, we have to use the WebAssembly
// default value 'null', and not the JS default value 'undefined'.
@@ -1379,6 +1383,21 @@ void WebAssemblyException(const v8::FunctionCallbackInfo<v8::Value>& args) {
thrower.TypeError("WebAssembly.Exception cannot be called");
}
+namespace {
+
+uint32_t GetIterableLength(i::Isolate* isolate, Local<Context> context,
+ Local<Object> iterable) {
+ Local<String> length = Utils::ToLocal(isolate->factory()->length_string());
+ MaybeLocal<Value> property = iterable->Get(context, length);
+ if (property.IsEmpty()) return i::kMaxUInt32;
+ MaybeLocal<Uint32> number = property.ToLocalChecked()->ToArrayIndex(context);
+ if (number.IsEmpty()) return i::kMaxUInt32;
+ DCHECK_NE(i::kMaxUInt32, number.ToLocalChecked()->Value());
+ return number.ToLocalChecked()->Value();
+}
+
+} // namespace
+
// WebAssembly.Function
void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
@@ -1403,13 +1422,16 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
function_type->Get(context, parameters_key);
v8::Local<v8::Value> parameters_value;
if (!parameters_maybe.ToLocal(&parameters_value)) return;
- // TODO(7742): Allow any iterable, not just {Array} here.
- if (!parameters_value->IsArray()) {
+ if (!parameters_value->IsObject()) {
thrower.TypeError("Argument 0 must be a function type with 'parameters'");
return;
}
- Local<Array> parameters = parameters_value.As<Array>();
- uint32_t parameters_len = parameters->Length();
+ Local<Object> parameters = parameters_value.As<Object>();
+ uint32_t parameters_len = GetIterableLength(i_isolate, context, parameters);
+ if (parameters_len == i::kMaxUInt32) {
+ thrower.TypeError("Argument 0 contains parameters without 'length'");
+ return;
+ }
if (parameters_len > i::wasm::kV8MaxWasmFunctionParams) {
thrower.TypeError("Argument 0 contains too many parameters");
return;
@@ -1421,13 +1443,16 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
function_type->Get(context, results_key);
v8::Local<v8::Value> results_value;
if (!results_maybe.ToLocal(&results_value)) return;
- // TODO(7742): Allow any iterable, not just {Array} here.
- if (!results_value->IsArray()) {
+ if (!results_value->IsObject()) {
thrower.TypeError("Argument 0 must be a function type with 'results'");
return;
}
- Local<Array> results = results_value.As<Array>();
- uint32_t results_len = results->Length();
+ Local<Object> results = results_value.As<Object>();
+ uint32_t results_len = GetIterableLength(i_isolate, context, results);
+ if (results_len == i::kMaxUInt32) {
+ thrower.TypeError("Argument 0 contains results without 'length'");
+ return;
+ }
if (results_len > (enabled_features.mv
? i::wasm::kV8MaxWasmFunctionMultiReturns
: i::wasm::kV8MaxWasmFunctionReturns)) {
@@ -1474,37 +1499,6 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(Utils::ToLocal(result));
}
-// Converts the given {type} into a string representation that can be used in
-// reflective functions. Should be kept in sync with the {GetValueType} helper.
-Local<String> ToValueTypeString(Isolate* isolate, i::wasm::ValueType type) {
- Local<String> string;
- switch (type) {
- case i::wasm::kWasmI32: {
- string = v8_str(isolate, "i32");
- break;
- }
- case i::wasm::kWasmI64: {
- string = v8_str(isolate, "i64");
- break;
- }
- case i::wasm::kWasmF32: {
- string = v8_str(isolate, "f32");
- break;
- }
- case i::wasm::kWasmF64: {
- string = v8_str(isolate, "f64");
- break;
- }
- case i::wasm::kWasmAnyRef: {
- string = v8_str(isolate, "anyref");
- break;
- }
- default:
- UNREACHABLE();
- }
- return string;
-}
-
// WebAssembly.Function.type(WebAssembly.Function) -> FunctionType
void WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
@@ -1524,36 +1518,8 @@ void WebAssemblyFunctionType(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
- // Extract values for the {ValueType[]} arrays.
- size_t param_index = 0;
- i::ScopedVector<Local<Value>> param_values(sig->parameter_count());
- for (i::wasm::ValueType type : sig->parameters()) {
- param_values[param_index++] = ToValueTypeString(isolate, type);
- }
- size_t result_index = 0;
- i::ScopedVector<Local<Value>> result_values(sig->return_count());
- for (i::wasm::ValueType type : sig->returns()) {
- result_values[result_index++] = ToValueTypeString(isolate, type);
- }
-
- // Create the resulting {FunctionType} object.
- Local<Object> ret = v8::Object::New(isolate);
- Local<Context> context = isolate->GetCurrentContext();
- Local<Array> params =
- v8::Array::New(isolate, param_values.begin(), param_values.size());
- if (!ret->CreateDataProperty(context, v8_str(isolate, "parameters"), params)
- .IsJust()) {
- return;
- }
- Local<Array> results =
- v8::Array::New(isolate, result_values.begin(), result_values.size());
- if (!ret->CreateDataProperty(context, v8_str(isolate, "results"), results)
- .IsJust()) {
- return;
- }
-
- v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
- return_value.Set(ret);
+ auto type = i::wasm::GetTypeForFunction(i_isolate, sig);
+ args.GetReturnValue().Set(Utils::ToLocal(type));
}
constexpr const char* kName_WasmGlobalObject = "WebAssembly.Global";
@@ -1681,48 +1647,15 @@ void WebAssemblyTableType(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto maybe_table = GetFirstArgumentAsTable(args, &thrower);
if (thrower.error()) return;
i::Handle<i::WasmTableObject> table = maybe_table.ToHandleChecked();
- v8::Local<v8::Object> ret = v8::Object::New(isolate);
-
- Local<String> element;
- auto enabled_features = i::wasm::WasmFeaturesFromFlags();
- if (table->type() == i::wasm::ValueType::kWasmFuncRef) {
- element = v8_str(isolate, "anyfunc");
- } else if (enabled_features.anyref &&
- table->type() == i::wasm::ValueType::kWasmAnyRef) {
- element = v8_str(isolate, "anyref");
- } else {
- UNREACHABLE();
- }
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "element"), element)
- .IsJust()) {
- return;
- }
-
- uint32_t curr_size = table->current_length();
- DCHECK_LE(curr_size, std::numeric_limits<uint32_t>::max());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "minimum"),
- v8::Integer::NewFromUnsigned(
- isolate, static_cast<uint32_t>(curr_size)))
- .IsJust()) {
- return;
- }
-
+ base::Optional<uint32_t> max_size;
if (!table->maximum_length().IsUndefined()) {
- uint64_t max_size = table->maximum_length().Number();
- DCHECK_LE(max_size, std::numeric_limits<uint32_t>::max());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "maximum"),
- v8::Integer::NewFromUnsigned(
- isolate, static_cast<uint32_t>(max_size)))
- .IsJust()) {
- return;
- }
+ uint64_t max_size64 = table->maximum_length().Number();
+ DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
+ max_size.emplace(static_cast<uint32_t>(max_size64));
}
-
- v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
- return_value.Set(ret);
+ auto type = i::wasm::GetTypeForTable(i_isolate, table->type(),
+ table->current_length(), max_size);
+ args.GetReturnValue().Set(Utils::ToLocal(type));
}
// WebAssembly.Memory.grow(num) -> num
@@ -1802,33 +1735,18 @@ void WebAssemblyMemoryType(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto maybe_memory = GetFirstArgumentAsMemory(args, &thrower);
if (thrower.error()) return;
i::Handle<i::WasmMemoryObject> memory = maybe_memory.ToHandleChecked();
- v8::Local<v8::Object> ret = v8::Object::New(isolate);
i::Handle<i::JSArrayBuffer> buffer(memory->array_buffer(), i_isolate);
-
size_t curr_size = buffer->byte_length() / i::wasm::kWasmPageSize;
DCHECK_LE(curr_size, std::numeric_limits<uint32_t>::max());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "minimum"),
- v8::Integer::NewFromUnsigned(
- isolate, static_cast<uint32_t>(curr_size)))
- .IsJust()) {
- return;
- }
-
+ uint32_t min_size = static_cast<uint32_t>(curr_size);
+ base::Optional<uint32_t> max_size;
if (memory->has_maximum_pages()) {
- uint64_t max_size = memory->maximum_pages();
- DCHECK_LE(max_size, std::numeric_limits<uint32_t>::max());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "maximum"),
- v8::Integer::NewFromUnsigned(
- isolate, static_cast<uint32_t>(max_size)))
- .IsJust()) {
- return;
- }
+ uint64_t max_size64 = memory->maximum_pages();
+ DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
+ max_size.emplace(static_cast<uint32_t>(max_size64));
}
-
- v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
- return_value.Set(ret);
+ auto type = i::wasm::GetTypeForMemory(i_isolate, min_size, max_size);
+ args.GetReturnValue().Set(Utils::ToLocal(type));
}
void WebAssemblyGlobalGetValueCommon(
@@ -1960,24 +1878,9 @@ void WebAssemblyGlobalType(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto maybe_global = GetFirstArgumentAsGlobal(args, &thrower);
if (thrower.error()) return;
i::Handle<i::WasmGlobalObject> global = maybe_global.ToHandleChecked();
- v8::Local<v8::Object> ret = v8::Object::New(isolate);
-
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "mutable"),
- v8::Boolean::New(isolate, global->is_mutable()))
- .IsJust()) {
- return;
- }
-
- Local<String> type = ToValueTypeString(isolate, global->type());
- if (!ret->CreateDataProperty(isolate->GetCurrentContext(),
- v8_str(isolate, "value"), type)
- .IsJust()) {
- return;
- }
-
- v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
- return_value.Set(ret);
+ auto type = i::wasm::GetTypeForGlobal(i_isolate, global->is_mutable(),
+ global->type());
+ args.GetReturnValue().Set(Utils::ToLocal(type));
}
} // namespace
diff --git a/deps/v8/src/wasm/wasm-module-builder.cc b/deps/v8/src/wasm/wasm-module-builder.cc
index 7dd6b1c7b2..d3874e1a34 100644
--- a/deps/v8/src/wasm/wasm-module-builder.cc
+++ b/deps/v8/src/wasm/wasm-module-builder.cc
@@ -233,6 +233,7 @@ WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
global_imports_(zone),
exports_(zone),
functions_(zone),
+ tables_(zone),
data_segments_(zone),
indirect_functions_(zone),
globals_(zone),
@@ -269,15 +270,29 @@ uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
}
uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) {
+ DCHECK(allocating_indirect_functions_allowed_);
uint32_t index = static_cast<uint32_t>(indirect_functions_.size());
DCHECK_GE(FLAG_wasm_max_table_size, index);
if (count > FLAG_wasm_max_table_size - index) {
return std::numeric_limits<uint32_t>::max();
}
- DCHECK(max_table_size_ == 0 ||
- indirect_functions_.size() + count <= max_table_size_);
- indirect_functions_.resize(indirect_functions_.size() + count,
- WasmElemSegment::kNullIndex);
+ uint32_t new_size = static_cast<uint32_t>(indirect_functions_.size()) + count;
+ DCHECK(max_table_size_ == 0 || new_size <= max_table_size_);
+ indirect_functions_.resize(new_size, WasmElemSegment::kNullIndex);
+ uint32_t max = max_table_size_ > 0 ? max_table_size_ : new_size;
+ if (tables_.empty()) {
+ // This cannot use {AddTable} because that would flip the
+ // {allocating_indirect_functions_allowed_} flag.
+ tables_.push_back({kWasmFuncRef, new_size, max, true});
+ } else {
+ // There can only be the indirect function table so far, otherwise the
+ // {allocating_indirect_functions_allowed_} flag would have been false.
+ DCHECK_EQ(1u, tables_.size());
+ DCHECK_EQ(kWasmFuncRef, tables_[0].type);
+ DCHECK(tables_[0].has_maximum);
+ tables_[0].min_size = new_size;
+ tables_[0].max_size = max;
+ }
return index;
}
@@ -290,6 +305,27 @@ void WasmModuleBuilder::SetMaxTableSize(uint32_t max) {
DCHECK_GE(FLAG_wasm_max_table_size, max);
DCHECK_GE(max, indirect_functions_.size());
max_table_size_ = max;
+ DCHECK(allocating_indirect_functions_allowed_);
+ if (!tables_.empty()) {
+ tables_[0].max_size = max;
+ }
+}
+
+uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size) {
+#if DEBUG
+ allocating_indirect_functions_allowed_ = false;
+#endif
+ tables_.push_back({type, min_size, 0, false});
+ return static_cast<uint32_t>(tables_.size() - 1);
+}
+
+uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size,
+ uint32_t max_size) {
+#if DEBUG
+ allocating_indirect_functions_allowed_ = false;
+#endif
+ tables_.push_back({type, min_size, max_size, true});
+ return static_cast<uint32_t>(tables_.size() - 1);
}
uint32_t WasmModuleBuilder::AddImport(Vector<const char> name,
@@ -408,21 +444,20 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
FixupSection(buffer, start);
}
- // == emit function table ====================================================
- if (indirect_functions_.size() > 0) {
+ // == Emit tables ============================================================
+ if (tables_.size() > 0) {
size_t start = EmitSection(kTableSectionCode, buffer);
- buffer->write_u8(1); // table count
- buffer->write_u8(kLocalFuncRef);
- buffer->write_u8(kHasMaximumFlag);
- buffer->write_size(indirect_functions_.size());
- size_t max =
- max_table_size_ > 0 ? max_table_size_ : indirect_functions_.size();
- DCHECK_GE(max, indirect_functions_.size());
- buffer->write_size(max);
+ buffer->write_size(tables_.size());
+ for (const WasmTable& table : tables_) {
+ buffer->write_u8(ValueTypes::ValueTypeCodeFor(table.type));
+ buffer->write_u8(table.has_maximum ? kHasMaximumFlag : kNoMaximumFlag);
+ buffer->write_size(table.min_size);
+ if (table.has_maximum) buffer->write_size(table.max_size);
+ }
FixupSection(buffer, start);
}
- // == emit memory declaration ================================================
+ // == Emit memory declaration ================================================
{
size_t start = EmitSection(kMemorySectionCode, buffer);
buffer->write_u8(1); // memory count
@@ -473,7 +508,13 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
buffer->write_u8(kExprGetGlobal);
buffer->write_u32v(global.init.val.global_index);
break;
- default: {
+ case WasmInitExpr::kRefNullConst:
+ buffer->write_u8(kExprRefNull);
+ break;
+ case WasmInitExpr::kRefFuncConst:
+ UNIMPLEMENTED();
+ break;
+ case WasmInitExpr::kNone: {
// No initializer, emit a default value.
switch (global.type) {
case kWasmI32:
diff --git a/deps/v8/src/wasm/wasm-module-builder.h b/deps/v8/src/wasm/wasm-module-builder.h
index 9e6a8933e2..4c122b8062 100644
--- a/deps/v8/src/wasm/wasm-module-builder.h
+++ b/deps/v8/src/wasm/wasm-module-builder.h
@@ -243,6 +243,8 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
uint32_t AllocateIndirectFunctions(uint32_t count);
void SetIndirectFunction(uint32_t indirect, uint32_t direct);
void SetMaxTableSize(uint32_t max);
+ uint32_t AddTable(ValueType type, uint32_t min_size);
+ uint32_t AddTable(ValueType type, uint32_t min_size, uint32_t max_size);
void MarkStartFunction(WasmFunctionBuilder* builder);
void AddExport(Vector<const char> name, ImportExportKindCode kind,
uint32_t index);
@@ -288,6 +290,13 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
WasmInitExpr init;
};
+ struct WasmTable {
+ ValueType type;
+ uint32_t min_size;
+ uint32_t max_size;
+ bool has_maximum;
+ };
+
struct WasmDataSegment {
ZoneVector<byte> data;
uint32_t dest;
@@ -300,6 +309,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
ZoneVector<WasmGlobalImport> global_imports_;
ZoneVector<WasmExport> exports_;
ZoneVector<WasmFunctionBuilder*> functions_;
+ ZoneVector<WasmTable> tables_;
ZoneVector<WasmDataSegment> data_segments_;
ZoneVector<uint32_t> indirect_functions_;
ZoneVector<WasmGlobal> globals_;
@@ -313,6 +323,8 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
#if DEBUG
// Once AddExportedImport is called, no more imports can be added.
bool adding_imports_allowed_ = true;
+ // Indirect functions must be allocated before adding extra tables.
+ bool allocating_indirect_functions_allowed_ = true;
#endif
};
diff --git a/deps/v8/src/wasm/wasm-module-sourcemap.cc b/deps/v8/src/wasm/wasm-module-sourcemap.cc
new file mode 100644
index 0000000000..cfe54e7c37
--- /dev/null
+++ b/deps/v8/src/wasm/wasm-module-sourcemap.cc
@@ -0,0 +1,161 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/wasm/wasm-module-sourcemap.h"
+
+#include <algorithm>
+
+#include "include/v8.h"
+#include "src/api/api.h"
+#include "src/base/vlq-base64.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+
+WasmModuleSourceMap::WasmModuleSourceMap(v8::Isolate* v8_isolate,
+ v8::Local<v8::String> src_map_str) {
+ v8::HandleScope scope(v8_isolate);
+ v8::Local<v8::Context> context = v8::Context::New(v8_isolate);
+
+ v8::Local<v8::Value> src_map_value;
+ if (!v8::JSON::Parse(context, src_map_str).ToLocal(&src_map_value)) return;
+ v8::Local<v8::Object> src_map_obj =
+ v8::Local<v8::Object>::Cast(src_map_value);
+
+ v8::Local<v8::Value> version_value, sources_value, mappings_value;
+ bool has_valid_version =
+ src_map_obj
+ ->Get(context,
+ v8::String::NewFromUtf8(v8_isolate, "version").ToLocalChecked())
+ .ToLocal(&version_value) &&
+ version_value->IsUint32();
+ uint32_t version = 0;
+ if (!has_valid_version || !version_value->Uint32Value(context).To(&version) ||
+ version != 3u)
+ return;
+
+ bool has_valid_sources =
+ src_map_obj
+ ->Get(context,
+ v8::String::NewFromUtf8(v8_isolate, "sources").ToLocalChecked())
+ .ToLocal(&sources_value) &&
+ sources_value->IsArray();
+ if (!has_valid_sources) return;
+
+ v8::Local<v8::Object> sources_arr =
+ v8::Local<v8::Object>::Cast(sources_value);
+ v8::Local<v8::Value> sources_len_value;
+ if (!sources_arr
+ ->Get(context,
+ v8::String::NewFromUtf8(v8_isolate, "length").ToLocalChecked())
+ .ToLocal(&sources_len_value))
+ return;
+ uint32_t sources_len = 0;
+ if (!sources_len_value->Uint32Value(context).To(&sources_len)) return;
+
+ for (uint32_t i = 0; i < sources_len; ++i) {
+ v8::Local<v8::Value> file_name_value;
+ if (!sources_arr->Get(context, i).ToLocal(&file_name_value) ||
+ !file_name_value->IsString())
+ return;
+ v8::Local<v8::String> file_name =
+ v8::Local<v8::String>::Cast(file_name_value);
+ auto file_name_sz = file_name->Utf8Length(v8_isolate);
+ std::unique_ptr<char[]> file_name_buf(new char[file_name_sz + 1]);
+ file_name->WriteUtf8(v8_isolate, file_name_buf.get());
+ file_name_buf.get()[file_name_sz] = '\0';
+ filenames.emplace_back(file_name_buf.get());
+ }
+
+ bool has_valid_mappings =
+ src_map_obj
+ ->Get(
+ context,
+ v8::String::NewFromUtf8(v8_isolate, "mappings").ToLocalChecked())
+ .ToLocal(&mappings_value) &&
+ mappings_value->IsString();
+ if (!has_valid_mappings) return;
+
+ v8::Local<v8::String> mappings = v8::Local<v8::String>::Cast(mappings_value);
+ int mappings_sz = mappings->Utf8Length(v8_isolate);
+ std::unique_ptr<char[]> mappings_buf(new char[mappings_sz + 1]);
+ mappings->WriteUtf8(v8_isolate, mappings_buf.get());
+ mappings_buf.get()[mappings_sz] = '\0';
+
+ valid_ = DecodeMapping(mappings_buf.get());
+}
+
+size_t WasmModuleSourceMap::GetSourceLine(size_t wasm_offset) const {
+ std::vector<std::size_t>::const_iterator up =
+ std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
+ CHECK_NE(offsets.begin(), up);
+ size_t source_idx = up - offsets.begin() - 1;
+ return source_row[source_idx];
+}
+
+std::string WasmModuleSourceMap::GetFilename(size_t wasm_offset) const {
+ std::vector<size_t>::const_iterator up =
+ std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
+ CHECK_NE(offsets.begin(), up);
+ size_t offset_idx = up - offsets.begin() - 1;
+ size_t filename_idx = file_idxs[offset_idx];
+ return filenames[filename_idx];
+}
+
+bool WasmModuleSourceMap::HasSource(size_t start, size_t end) const {
+ return start <= *(offsets.end() - 1) && end > *offsets.begin();
+}
+
+bool WasmModuleSourceMap::HasValidEntry(size_t start, size_t addr) const {
+ std::vector<size_t>::const_iterator up =
+ std::upper_bound(offsets.begin(), offsets.end(), addr);
+ if (up == offsets.begin()) return false;
+ size_t offset_idx = up - offsets.begin() - 1;
+ size_t entry_offset = offsets[offset_idx];
+ if (entry_offset < start) return false;
+ return true;
+}
+
+bool WasmModuleSourceMap::DecodeMapping(const std::string& s) {
+ size_t pos = 0, gen_col = 0, file_idx = 0, ori_line = 0;
+ int32_t qnt = 0;
+
+ while (pos < s.size()) {
+ // Skip redundant commas.
+ if (s[pos] == ',') {
+ ++pos;
+ continue;
+ }
+ if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
+ std::numeric_limits<int32_t>::min())
+ return false;
+ gen_col += qnt;
+ if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
+ std::numeric_limits<int32_t>::min())
+ return false;
+ file_idx += qnt;
+ if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
+ std::numeric_limits<int32_t>::min())
+ return false;
+ ori_line += qnt;
+ // Column number in source file is always 0 in source map generated by
+ // Emscripten. We just decode this value without further usage of it.
+ if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
+ std::numeric_limits<int32_t>::min())
+ return false;
+
+ if (pos < s.size() && s[pos] != ',') return false;
+ pos++;
+
+ file_idxs.push_back(file_idx);
+ source_row.push_back(ori_line);
+ offsets.push_back(gen_col);
+ }
+ return true;
+}
+
+} // namespace wasm
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/wasm/wasm-module-sourcemap.h b/deps/v8/src/wasm/wasm-module-sourcemap.h
new file mode 100644
index 0000000000..83293ae205
--- /dev/null
+++ b/deps/v8/src/wasm/wasm-module-sourcemap.h
@@ -0,0 +1,83 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_WASM_WASM_MODULE_SOURCEMAP_H_
+#define V8_WASM_WASM_MODULE_SOURCEMAP_H_
+
+#include <string>
+#include <vector>
+
+#include "include/v8.h"
+#include "src/base/macros.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+// The class is for decoding and managing source map generated by a WebAssembly
+// toolchain (e.g. Emscripten). This implementation mostly complies with the
+// specification (https://sourcemaps.info/spec.html), with the following
+// accommodations:
+// 1. "names" field is an empty array in current source maps of WASM, hence it
+// is not handled;
+// 2. The semicolons divides "mappings" field into groups, each of which
+// represents a line in the generated code. As *.wasm is in binary format, there
+// is one "line" of generated code, and ";" is treated as illegal symbol in
+// "mappings".
+// 3. Though each comma-separated section may contains 1, 4 or 5 fields, we only
+// consider "mappings" with 4 fields, i.e. start line of generated code, index
+// into "sources" fields, start line of source code and start column of source
+// code.
+class V8_EXPORT_PRIVATE WasmModuleSourceMap {
+ public:
+ WasmModuleSourceMap(v8::Isolate* v8_isolate,
+ v8::Local<v8::String> src_map_str);
+
+ // Member valid_ is true only if the source map complies with specification
+ // and can be correctly decoded.
+ bool IsValid() const { return valid_; }
+
+ // Given a function located at [start, end) in WASM Module, this function
+ // checks if this function has its corresponding source code.
+ bool HasSource(size_t start, size_t end) const;
+
+ // Given a function's base address start and an address addr within, this
+ // function checks if the address can be mapped to an offset in this function.
+ // For example, we have the following memory layout for WASM functions, foo
+ // and bar, and O1, O2, O3 and O4 are the decoded offsets of source map:
+ //
+ // O1 --- O2 ----- O3 ----- O4
+ // --->|<-foo->|<--bar->|<-----
+ // --------------A-------------
+ //
+ // Address A of function bar should be mapped to its nearest lower offset, O2.
+ // However, O2 is an address of function foo, thus, this mapping is treated as
+ // invalid.
+ bool HasValidEntry(size_t start, size_t addr) const;
+
+ // This function is responsible for looking up an offset's corresponding line
+ // number in source file. It should only be called when current function is
+ // checked with IsValid, HasSource and HasValidEntry.
+ size_t GetSourceLine(size_t wasm_offset) const;
+
+ // This function is responsible for looking up an offset's corresponding
+ // source file name. It should only be called when current function is checked
+ // with IsValid, HasSource and HasValidEntry.
+ std::string GetFilename(size_t wasm_offset) const;
+
+ private:
+ std::vector<size_t> offsets;
+ std::vector<std::string> filenames;
+ std::vector<size_t> file_idxs;
+ std::vector<size_t> source_row;
+ // As column number in source file is always 0 in source map generated by
+ // WebAssembly toolchain, we will not store this value.
+
+ bool valid_ = false;
+
+ bool DecodeMapping(const std::string& s);
+};
+} // namespace wasm
+} // namespace internal
+} // namespace v8
+#endif // V8_WASM_WASM_MODULE_SOURCEMAP_H_
diff --git a/deps/v8/src/wasm/wasm-module.cc b/deps/v8/src/wasm/wasm-module.cc
index 05057301ed..5a10368a8b 100644
--- a/deps/v8/src/wasm/wasm-module.cc
+++ b/deps/v8/src/wasm/wasm-module.cc
@@ -113,13 +113,156 @@ bool IsWasmCodegenAllowed(Isolate* isolate, Handle<Context> context) {
v8::Utils::ToLocal(isolate->factory()->empty_string()));
}
+namespace {
+
+// Converts the given {type} into a string representation that can be used in
+// reflective functions. Should be kept in sync with the {GetValueType} helper.
+Handle<String> ToValueTypeString(Isolate* isolate, ValueType type) {
+ Factory* factory = isolate->factory();
+ Handle<String> string;
+ switch (type) {
+ case i::wasm::kWasmI32: {
+ string = factory->InternalizeUtf8String("i32");
+ break;
+ }
+ case i::wasm::kWasmI64: {
+ string = factory->InternalizeUtf8String("i64");
+ break;
+ }
+ case i::wasm::kWasmF32: {
+ string = factory->InternalizeUtf8String("f32");
+ break;
+ }
+ case i::wasm::kWasmF64: {
+ string = factory->InternalizeUtf8String("f64");
+ break;
+ }
+ case i::wasm::kWasmAnyRef: {
+ string = factory->InternalizeUtf8String("anyref");
+ break;
+ }
+ case i::wasm::kWasmFuncRef: {
+ string = factory->InternalizeUtf8String("anyfunc");
+ break;
+ }
+ case i::wasm::kWasmExnRef: {
+ string = factory->InternalizeUtf8String("exnref");
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ return string;
+}
+
+} // namespace
+
+Handle<JSObject> GetTypeForFunction(Isolate* isolate, FunctionSig* sig) {
+ Factory* factory = isolate->factory();
+
+ // Extract values for the {ValueType[]} arrays.
+ int param_index = 0;
+ int param_count = static_cast<int>(sig->parameter_count());
+ Handle<FixedArray> param_values = factory->NewFixedArray(param_count);
+ for (ValueType type : sig->parameters()) {
+ Handle<String> type_value = ToValueTypeString(isolate, type);
+ param_values->set(param_index++, *type_value);
+ }
+ int result_index = 0;
+ int result_count = static_cast<int>(sig->return_count());
+ Handle<FixedArray> result_values = factory->NewFixedArray(result_count);
+ for (ValueType type : sig->returns()) {
+ Handle<String> type_value = ToValueTypeString(isolate, type);
+ result_values->set(result_index++, *type_value);
+ }
+
+ // Create the resulting {FunctionType} object.
+ Handle<JSFunction> object_function = isolate->object_function();
+ Handle<JSObject> object = factory->NewJSObject(object_function);
+ Handle<JSArray> params = factory->NewJSArrayWithElements(param_values);
+ Handle<JSArray> results = factory->NewJSArrayWithElements(result_values);
+ Handle<String> params_string = factory->InternalizeUtf8String("parameters");
+ Handle<String> results_string = factory->InternalizeUtf8String("results");
+ JSObject::AddProperty(isolate, object, params_string, params, NONE);
+ JSObject::AddProperty(isolate, object, results_string, results, NONE);
+
+ return object;
+}
+
+Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
+ ValueType type) {
+ Factory* factory = isolate->factory();
+
+ Handle<JSFunction> object_function = isolate->object_function();
+ Handle<JSObject> object = factory->NewJSObject(object_function);
+ Handle<String> mutable_string = factory->InternalizeUtf8String("mutable");
+ Handle<String> value_string = factory->InternalizeUtf8String("value");
+ JSObject::AddProperty(isolate, object, mutable_string,
+ factory->ToBoolean(is_mutable), NONE);
+ JSObject::AddProperty(isolate, object, value_string,
+ ToValueTypeString(isolate, type), NONE);
+
+ return object;
+}
+
+Handle<JSObject> GetTypeForMemory(Isolate* isolate, uint32_t min_size,
+ base::Optional<uint32_t> max_size) {
+ Factory* factory = isolate->factory();
+
+ Handle<JSFunction> object_function = isolate->object_function();
+ Handle<JSObject> object = factory->NewJSObject(object_function);
+ Handle<String> minimum_string = factory->InternalizeUtf8String("minimum");
+ Handle<String> maximum_string = factory->InternalizeUtf8String("maximum");
+ JSObject::AddProperty(isolate, object, minimum_string,
+ factory->NewNumberFromUint(min_size), NONE);
+ if (max_size.has_value()) {
+ JSObject::AddProperty(isolate, object, maximum_string,
+ factory->NewNumberFromUint(max_size.value()), NONE);
+ }
+
+ return object;
+}
+
+Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type,
+ uint32_t min_size,
+ base::Optional<uint32_t> max_size) {
+ Factory* factory = isolate->factory();
+
+ Handle<String> element;
+ if (type == ValueType::kWasmFuncRef) {
+ // TODO(wasm): We should define the "anyfunc" string in one central place
+ // and then use that constant everywhere.
+ element = factory->InternalizeUtf8String("anyfunc");
+ } else {
+ DCHECK(WasmFeaturesFromFlags().anyref && type == ValueType::kWasmAnyRef);
+ element = factory->InternalizeUtf8String("anyref");
+ }
+
+ Handle<JSFunction> object_function = isolate->object_function();
+ Handle<JSObject> object = factory->NewJSObject(object_function);
+ Handle<String> element_string = factory->InternalizeUtf8String("element");
+ Handle<String> minimum_string = factory->InternalizeUtf8String("minimum");
+ Handle<String> maximum_string = factory->InternalizeUtf8String("maximum");
+ JSObject::AddProperty(isolate, object, element_string, element, NONE);
+ JSObject::AddProperty(isolate, object, minimum_string,
+ factory->NewNumberFromUint(min_size), NONE);
+ if (max_size.has_value()) {
+ JSObject::AddProperty(isolate, object, maximum_string,
+ factory->NewNumberFromUint(max_size.value()), NONE);
+ }
+
+ return object;
+}
+
Handle<JSArray> GetImports(Isolate* isolate,
Handle<WasmModuleObject> module_object) {
+ auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
Factory* factory = isolate->factory();
Handle<String> module_string = factory->InternalizeUtf8String("module");
Handle<String> name_string = factory->InternalizeUtf8String("name");
Handle<String> kind_string = factory->InternalizeUtf8String("kind");
+ Handle<String> type_string = factory->InternalizeUtf8String("type");
Handle<String> function_string = factory->InternalizeUtf8String("function");
Handle<String> table_string = factory->InternalizeUtf8String("table");
@@ -145,17 +288,43 @@ Handle<JSArray> GetImports(Isolate* isolate,
Handle<JSObject> entry = factory->NewJSObject(object_function);
Handle<String> import_kind;
+ Handle<JSObject> type_value;
switch (import.kind) {
case kExternalFunction:
+ if (enabled_features.type_reflection) {
+ auto& func = module->functions[import.index];
+ type_value = GetTypeForFunction(isolate, func.sig);
+ }
import_kind = function_string;
break;
case kExternalTable:
+ if (enabled_features.type_reflection) {
+ auto& table = module->tables[import.index];
+ base::Optional<uint32_t> maximum_size;
+ if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
+ type_value = GetTypeForTable(isolate, table.type, table.initial_size,
+ maximum_size);
+ }
import_kind = table_string;
break;
case kExternalMemory:
+ if (enabled_features.type_reflection) {
+ DCHECK_EQ(0, import.index); // Only one memory supported.
+ base::Optional<uint32_t> maximum_size;
+ if (module->has_maximum_pages) {
+ maximum_size.emplace(module->maximum_pages);
+ }
+ type_value =
+ GetTypeForMemory(isolate, module->initial_pages, maximum_size);
+ }
import_kind = memory_string;
break;
case kExternalGlobal:
+ if (enabled_features.type_reflection) {
+ auto& global = module->globals[import.index];
+ type_value =
+ GetTypeForGlobal(isolate, global.mutability, global.type);
+ }
import_kind = global_string;
break;
case kExternalException:
@@ -178,6 +347,9 @@ Handle<JSArray> GetImports(Isolate* isolate,
JSObject::AddProperty(isolate, entry, name_string,
import_name.ToHandleChecked(), NONE);
JSObject::AddProperty(isolate, entry, kind_string, import_kind, NONE);
+ if (!type_value.is_null()) {
+ JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
+ }
storage->set(index, *entry);
}
@@ -187,10 +359,12 @@ Handle<JSArray> GetImports(Isolate* isolate,
Handle<JSArray> GetExports(Isolate* isolate,
Handle<WasmModuleObject> module_object) {
+ auto enabled_features = i::wasm::WasmFeaturesFromIsolate(isolate);
Factory* factory = isolate->factory();
Handle<String> name_string = factory->InternalizeUtf8String("name");
Handle<String> kind_string = factory->InternalizeUtf8String("kind");
+ Handle<String> type_string = factory->InternalizeUtf8String("type");
Handle<String> function_string = factory->InternalizeUtf8String("function");
Handle<String> table_string = factory->InternalizeUtf8String("table");
@@ -214,17 +388,43 @@ Handle<JSArray> GetExports(Isolate* isolate,
const WasmExport& exp = module->export_table[index];
Handle<String> export_kind;
+ Handle<JSObject> type_value;
switch (exp.kind) {
case kExternalFunction:
+ if (enabled_features.type_reflection) {
+ auto& func = module->functions[exp.index];
+ type_value = GetTypeForFunction(isolate, func.sig);
+ }
export_kind = function_string;
break;
case kExternalTable:
+ if (enabled_features.type_reflection) {
+ auto& table = module->tables[exp.index];
+ base::Optional<uint32_t> maximum_size;
+ if (table.has_maximum_size) maximum_size.emplace(table.maximum_size);
+ type_value = GetTypeForTable(isolate, table.type, table.initial_size,
+ maximum_size);
+ }
export_kind = table_string;
break;
case kExternalMemory:
+ if (enabled_features.type_reflection) {
+ DCHECK_EQ(0, exp.index); // Only one memory supported.
+ base::Optional<uint32_t> maximum_size;
+ if (module->has_maximum_pages) {
+ maximum_size.emplace(module->maximum_pages);
+ }
+ type_value =
+ GetTypeForMemory(isolate, module->initial_pages, maximum_size);
+ }
export_kind = memory_string;
break;
case kExternalGlobal:
+ if (enabled_features.type_reflection) {
+ auto& global = module->globals[exp.index];
+ type_value =
+ GetTypeForGlobal(isolate, global.mutability, global.type);
+ }
export_kind = global_string;
break;
case kExternalException:
@@ -243,6 +443,9 @@ Handle<JSArray> GetExports(Isolate* isolate,
JSObject::AddProperty(isolate, entry, name_string,
export_name.ToHandleChecked(), NONE);
JSObject::AddProperty(isolate, entry, kind_string, export_kind, NONE);
+ if (!type_value.is_null()) {
+ JSObject::AddProperty(isolate, entry, type_string, type_value, NONE);
+ }
storage->set(index, *entry);
}
diff --git a/deps/v8/src/wasm/wasm-module.h b/deps/v8/src/wasm/wasm-module.h
index 7dea208d8e..69c57725de 100644
--- a/deps/v8/src/wasm/wasm-module.h
+++ b/deps/v8/src/wasm/wasm-module.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "src/base/optional.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/utils/vector.h"
@@ -301,13 +302,19 @@ V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
Handle<Context> context);
-V8_EXPORT_PRIVATE Handle<JSArray> GetImports(Isolate* isolate,
- Handle<WasmModuleObject> module);
-V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
- Handle<WasmModuleObject> module);
-V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
- Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
- ErrorThrower* thrower);
+Handle<JSObject> GetTypeForFunction(Isolate* isolate, FunctionSig* sig);
+Handle<JSObject> GetTypeForGlobal(Isolate* isolate, bool is_mutable,
+ ValueType type);
+Handle<JSObject> GetTypeForMemory(Isolate* isolate, uint32_t min_size,
+ base::Optional<uint32_t> max_size);
+Handle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type,
+ uint32_t min_size,
+ base::Optional<uint32_t> max_size);
+Handle<JSArray> GetImports(Isolate* isolate, Handle<WasmModuleObject> module);
+Handle<JSArray> GetExports(Isolate* isolate, Handle<WasmModuleObject> module);
+Handle<JSArray> GetCustomSections(Isolate* isolate,
+ Handle<WasmModuleObject> module,
+ Handle<String> name, ErrorThrower* thrower);
// Decode local variable names from the names section. Return FixedArray of
// FixedArray of <undefined|String>. The outer fixed array is indexed by the
diff --git a/deps/v8/src/wasm/wasm-objects-inl.h b/deps/v8/src/wasm/wasm-objects-inl.h
index 7a80b7ea2b..66d3a2716e 100644
--- a/deps/v8/src/wasm/wasm-objects-inl.h
+++ b/deps/v8/src/wasm/wasm-objects-inl.h
@@ -28,7 +28,7 @@ namespace v8 {
namespace internal {
OBJECT_CONSTRUCTORS_IMPL(WasmExceptionObject, JSObject)
-OBJECT_CONSTRUCTORS_IMPL(WasmExceptionTag, Struct)
+TQ_OBJECT_CONSTRUCTORS_IMPL(WasmExceptionTag)
OBJECT_CONSTRUCTORS_IMPL(WasmExportedFunctionData, Struct)
OBJECT_CONSTRUCTORS_IMPL(WasmDebugInfo, Struct)
OBJECT_CONSTRUCTORS_IMPL(WasmGlobalObject, JSObject)
@@ -42,7 +42,6 @@ NEVER_READ_ONLY_SPACE_IMPL(WasmDebugInfo)
CAST_ACCESSOR(WasmDebugInfo)
CAST_ACCESSOR(WasmExceptionObject)
-CAST_ACCESSOR(WasmExceptionTag)
CAST_ACCESSOR(WasmExportedFunctionData)
CAST_ACCESSOR(WasmGlobalObject)
CAST_ACCESSOR(WasmInstanceObject)
@@ -261,9 +260,8 @@ OPTIONAL_ACCESSORS(WasmInstanceObject, managed_native_allocations, Foreign,
kManagedNativeAllocationsOffset)
OPTIONAL_ACCESSORS(WasmInstanceObject, exceptions_table, FixedArray,
kExceptionsTableOffset)
-ACCESSORS(WasmInstanceObject, centry_stub, Code, kCEntryStubOffset)
-OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_exported_functions, FixedArray,
- kWasmExportedFunctionsOffset)
+OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_external_functions, FixedArray,
+ kWasmExternalFunctionsOffset)
void WasmInstanceObject::clear_padding() {
if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
@@ -325,7 +323,7 @@ SMI_ACCESSORS(WasmExportedFunctionData, jump_table_offset,
kJumpTableOffsetOffset)
SMI_ACCESSORS(WasmExportedFunctionData, function_index, kFunctionIndexOffset)
ACCESSORS(WasmExportedFunctionData, c_wrapper_code, Object, kCWrapperCodeOffset)
-ACCESSORS(WasmExportedFunctionData, wasm_call_target, Smi,
+ACCESSORS(WasmExportedFunctionData, wasm_call_target, Object,
kWasmCallTargetOffset)
SMI_ACCESSORS(WasmExportedFunctionData, packed_args_size, kPackedArgsSizeOffset)
@@ -358,12 +356,17 @@ OBJECT_CONSTRUCTORS_IMPL(WasmCapiFunctionData, Struct)
CAST_ACCESSOR(WasmCapiFunctionData)
PRIMITIVE_ACCESSORS(WasmCapiFunctionData, call_target, Address,
kCallTargetOffset)
-PRIMITIVE_ACCESSORS(WasmCapiFunctionData, embedder_data, void*,
- kEmbedderDataOffset)
+ACCESSORS(WasmCapiFunctionData, embedder_data, Foreign, kEmbedderDataOffset)
ACCESSORS(WasmCapiFunctionData, wrapper_code, Code, kWrapperCodeOffset)
ACCESSORS(WasmCapiFunctionData, serialized_signature, PodArray<wasm::ValueType>,
kSerializedSignatureOffset)
+// WasmExternalFunction
+WasmExternalFunction::WasmExternalFunction(Address ptr) : JSFunction(ptr) {
+ SLOW_DCHECK(IsWasmExternalFunction(*this));
+}
+CAST_ACCESSOR(WasmExternalFunction)
+
// WasmIndirectFunctionTable
OBJECT_CONSTRUCTORS_IMPL(WasmIndirectFunctionTable, Struct)
CAST_ACCESSOR(WasmIndirectFunctionTable)
@@ -399,7 +402,7 @@ wasm::ValueType WasmTableObject::type() {
bool WasmMemoryObject::has_maximum_pages() { return maximum_pages() >= 0; }
// WasmExceptionTag
-SMI_ACCESSORS(WasmExceptionTag, index, kIndexOffset)
+TQ_SMI_ACCESSORS(WasmExceptionTag, index)
// AsmWasmData
ACCESSORS(AsmWasmData, managed_native_module, Managed<wasm::NativeModule>,
diff --git a/deps/v8/src/wasm/wasm-objects.cc b/deps/v8/src/wasm/wasm-objects.cc
index f44f8326ad..d9417943a8 100644
--- a/deps/v8/src/wasm/wasm-objects.cc
+++ b/deps/v8/src/wasm/wasm-objects.cc
@@ -207,36 +207,19 @@ enum DispatchTableElements : int {
// static
Handle<WasmModuleObject> WasmModuleObject::New(
- Isolate* isolate, const wasm::WasmFeatures& enabled,
- std::shared_ptr<const wasm::WasmModule> shared_module,
- OwnedVector<const uint8_t> wire_bytes, Handle<Script> script,
- Handle<ByteArray> asm_js_offset_table) {
- // Create a new {NativeModule} first.
- size_t code_size_estimate =
- wasm::WasmCodeManager::EstimateNativeModuleCodeSize(shared_module.get());
- auto native_module = isolate->wasm_engine()->NewNativeModule(
- isolate, enabled, code_size_estimate,
- wasm::NativeModule::kCanAllocateMoreMemory, std::move(shared_module));
- native_module->SetWireBytes(std::move(wire_bytes));
- native_module->SetRuntimeStubs(isolate);
-
- // Delegate to the shared {WasmModuleObject::New} allocator.
- Handle<WasmModuleObject> module_object =
- New(isolate, std::move(native_module), script, code_size_estimate);
- if (!asm_js_offset_table.is_null()) {
- module_object->set_asm_js_offset_table(*asm_js_offset_table);
- }
- return module_object;
+ Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
+ Handle<Script> script) {
+ Handle<FixedArray> export_wrappers = isolate->factory()->NewFixedArray(0);
+ return New(isolate, std::move(native_module), script, export_wrappers);
}
// static
Handle<WasmModuleObject> WasmModuleObject::New(
Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
- Handle<Script> script, size_t code_size_estimate) {
+ Handle<Script> script, Handle<FixedArray> export_wrappers) {
const WasmModule* module = native_module->module();
- int num_wrappers = MaxNumExportWrappers(module);
- Handle<FixedArray> export_wrappers =
- isolate->factory()->NewFixedArray(num_wrappers, AllocationType::kOld);
+ size_t code_size_estimate =
+ wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module);
return New(isolate, std::move(native_module), script, export_wrappers,
code_size_estimate);
}
@@ -964,6 +947,7 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
// Now we handle the funcref case.
if (WasmExportedFunction::IsWasmExportedFunction(*entry) ||
+ WasmJSFunction::IsWasmJSFunction(*entry) ||
WasmCapiFunction::IsWasmCapiFunction(*entry)) {
return entry;
}
@@ -980,7 +964,7 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
// Check if we already compiled a wrapper for the function but did not store
// it in the table slot yet.
- entry = WasmInstanceObject::GetOrCreateWasmExportedFunction(isolate, instance,
+ entry = WasmInstanceObject::GetOrCreateWasmExternalFunction(isolate, instance,
function_index);
entries->set(entry_index, *entry);
return entry;
@@ -1726,9 +1710,6 @@ Handle<WasmInstanceObject> WasmInstanceObject::New(
isolate->factory()->NewFixedArray(num_imported_functions);
instance->set_imported_function_refs(*imported_function_refs);
- Handle<Code> centry_stub = CodeFactory::CEntry(isolate);
- instance->set_centry_stub(*centry_stub);
-
instance->SetRawMemory(nullptr, 0);
instance->set_isolate_root(isolate->isolate_root());
instance->set_stack_limit_address(
@@ -1878,27 +1859,27 @@ bool WasmInstanceObject::InitTableEntries(Isolate* isolate,
dst, src, count);
}
-MaybeHandle<WasmExportedFunction> WasmInstanceObject::GetWasmExportedFunction(
+MaybeHandle<WasmExternalFunction> WasmInstanceObject::GetWasmExternalFunction(
Isolate* isolate, Handle<WasmInstanceObject> instance, int index) {
- MaybeHandle<WasmExportedFunction> result;
- if (instance->has_wasm_exported_functions()) {
- Object val = instance->wasm_exported_functions().get(index);
+ MaybeHandle<WasmExternalFunction> result;
+ if (instance->has_wasm_external_functions()) {
+ Object val = instance->wasm_external_functions().get(index);
if (!val.IsUndefined(isolate)) {
- result = Handle<WasmExportedFunction>(WasmExportedFunction::cast(val),
+ result = Handle<WasmExternalFunction>(WasmExternalFunction::cast(val),
isolate);
}
}
return result;
}
-Handle<WasmExportedFunction>
-WasmInstanceObject::GetOrCreateWasmExportedFunction(
+Handle<WasmExternalFunction>
+WasmInstanceObject::GetOrCreateWasmExternalFunction(
Isolate* isolate, Handle<WasmInstanceObject> instance, int function_index) {
- MaybeHandle<WasmExportedFunction> maybe_result =
- WasmInstanceObject::GetWasmExportedFunction(isolate, instance,
+ MaybeHandle<WasmExternalFunction> maybe_result =
+ WasmInstanceObject::GetWasmExternalFunction(isolate, instance,
function_index);
- Handle<WasmExportedFunction> result;
+ Handle<WasmExternalFunction> result;
if (maybe_result.ToHandle(&result)) {
return result;
}
@@ -1923,27 +1904,27 @@ WasmInstanceObject::GetOrCreateWasmExportedFunction(
isolate, function.sig, function.imported);
module_object->export_wrappers().set(wrapper_index, *wrapper);
}
- result = WasmExportedFunction::New(
+ result = Handle<WasmExternalFunction>::cast(WasmExportedFunction::New(
isolate, instance, function_index,
- static_cast<int>(function.sig->parameter_count()), wrapper);
+ static_cast<int>(function.sig->parameter_count()), wrapper));
- WasmInstanceObject::SetWasmExportedFunction(isolate, instance, function_index,
+ WasmInstanceObject::SetWasmExternalFunction(isolate, instance, function_index,
result);
return result;
}
-void WasmInstanceObject::SetWasmExportedFunction(
+void WasmInstanceObject::SetWasmExternalFunction(
Isolate* isolate, Handle<WasmInstanceObject> instance, int index,
- Handle<WasmExportedFunction> val) {
+ Handle<WasmExternalFunction> val) {
Handle<FixedArray> functions;
- if (!instance->has_wasm_exported_functions()) {
- // lazily-allocate the wasm exported functions.
+ if (!instance->has_wasm_external_functions()) {
+ // Lazily allocate the wasm external functions array.
functions = isolate->factory()->NewFixedArray(
static_cast<int>(instance->module()->functions.size()));
- instance->set_wasm_exported_functions(*functions);
+ instance->set_wasm_external_functions(*functions);
} else {
functions =
- Handle<FixedArray>(instance->wasm_exported_functions(), isolate);
+ Handle<FixedArray>(instance->wasm_external_functions(), isolate);
}
functions->set(index, *val);
}
@@ -1968,8 +1949,7 @@ void WasmInstanceObject::ImportWasmJSFunctionIntoTable(
instance->module_object().native_module();
// TODO(mstarzinger): Cache and reuse wrapper code.
const wasm::WasmFeatures enabled = native_module->enabled_features();
- auto resolved =
- compiler::ResolveWasmImportCall(callable, sig, enabled.bigint);
+ auto resolved = compiler::ResolveWasmImportCall(callable, sig, enabled);
compiler::WasmImportCallKind kind = resolved.first;
callable = resolved.second; // Update to ultimate target.
DCHECK_NE(compiler::WasmImportCallKind::kLinkError, kind);
@@ -2183,13 +2163,13 @@ bool WasmCapiFunction::IsWasmCapiFunction(Object object) {
}
Handle<WasmCapiFunction> WasmCapiFunction::New(
- Isolate* isolate, Address call_target, void* embedder_data,
+ Isolate* isolate, Address call_target, Handle<Foreign> embedder_data,
Handle<PodArray<wasm::ValueType>> serialized_signature) {
Handle<WasmCapiFunctionData> fun_data =
Handle<WasmCapiFunctionData>::cast(isolate->factory()->NewStruct(
WASM_CAPI_FUNCTION_DATA_TYPE, AllocationType::kOld));
fun_data->set_call_target(call_target);
- fun_data->set_embedder_data(embedder_data);
+ fun_data->set_embedder_data(*embedder_data);
fun_data->set_serialized_signature(*serialized_signature);
// TODO(jkummerow): Install a JavaScript wrapper. For now, calling
// these functions directly is unsupported; they can only be called
@@ -2301,6 +2281,10 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
if (sig_size > 0) {
serialized_sig->copy_in(0, sig->all().begin(), sig_size);
}
+ // TODO(mstarzinger): Think about caching and sharing the JS-to-JS wrappers
+ // per signature instead of compiling a new one for every instantiation.
+ Handle<Code> wrapper_code =
+ compiler::CompileJSToJSWrapper(isolate, sig).ToHandleChecked();
Handle<WasmJSFunctionData> function_data =
Handle<WasmJSFunctionData>::cast(isolate->factory()->NewStruct(
WASM_JS_FUNCTION_DATA_TYPE, AllocationType::kOld));
@@ -2308,9 +2292,7 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
function_data->set_serialized_parameter_count(parameter_count);
function_data->set_serialized_signature(*serialized_sig);
function_data->set_callable(*callable);
- // TODO(7742): Make this callable by using a proper wrapper code.
- function_data->set_wrapper_code(
- isolate->builtins()->builtin(Builtins::kIllegal));
+ function_data->set_wrapper_code(*wrapper_code);
Handle<String> name = isolate->factory()->Function_string();
if (callable->IsJSFunction()) {
name = JSFunction::GetName(Handle<JSFunction>::cast(callable));
@@ -2319,6 +2301,7 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
NewFunctionArgs args =
NewFunctionArgs::ForWasm(name, function_data, function_map);
Handle<JSFunction> js_function = isolate->factory()->NewFunction(args);
+ js_function->shared().set_internal_formal_parameter_count(parameter_count);
return Handle<WasmJSFunction>::cast(js_function);
}
@@ -2361,6 +2344,11 @@ PodArray<wasm::ValueType> WasmCapiFunction::GetSerializedSignature() const {
return shared().wasm_capi_function_data().serialized_signature();
}
+bool WasmExternalFunction::IsWasmExternalFunction(Object object) {
+ return WasmExportedFunction::IsWasmExportedFunction(object) ||
+ WasmJSFunction::IsWasmJSFunction(object);
+}
+
Handle<WasmExceptionTag> WasmExceptionTag::New(Isolate* isolate, int index) {
Handle<WasmExceptionTag> result =
Handle<WasmExceptionTag>::cast(isolate->factory()->NewStruct(
diff --git a/deps/v8/src/wasm/wasm-objects.h b/deps/v8/src/wasm/wasm-objects.h
index 1200f7040a..c198a9bc63 100644
--- a/deps/v8/src/wasm/wasm-objects.h
+++ b/deps/v8/src/wasm/wasm-objects.h
@@ -41,6 +41,7 @@ class WasmCapiFunction;
class WasmDebugInfo;
class WasmExceptionTag;
class WasmExportedFunction;
+class WasmExternalFunction;
class WasmInstanceObject;
class WasmJSFunction;
class WasmModuleObject;
@@ -139,18 +140,14 @@ class WasmModuleObject : public JSObject {
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
TORQUE_GENERATED_WASM_MODULE_OBJECT_FIELDS)
- // Creates a new {WasmModuleObject} with a new {NativeModule} underneath.
- V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New(
- Isolate* isolate, const wasm::WasmFeatures& enabled,
- std::shared_ptr<const wasm::WasmModule> module,
- OwnedVector<const uint8_t> wire_bytes, Handle<Script> script,
- Handle<ByteArray> asm_js_offset_table);
-
// Creates a new {WasmModuleObject} for an existing {NativeModule} that is
// reference counted and might be shared between multiple Isolates.
V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New(
Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
- Handle<Script> script, size_t code_size_estimate);
+ Handle<Script> script);
+ V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New(
+ Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
+ Handle<Script> script, Handle<FixedArray> export_wrappers);
V8_EXPORT_PRIVATE static Handle<WasmModuleObject> New(
Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
Handle<Script> script, Handle<FixedArray> export_wrappers,
@@ -444,8 +441,7 @@ class WasmInstanceObject : public JSObject {
DECL_OPTIONAL_ACCESSORS(indirect_function_table_refs, FixedArray)
DECL_OPTIONAL_ACCESSORS(managed_native_allocations, Foreign)
DECL_OPTIONAL_ACCESSORS(exceptions_table, FixedArray)
- DECL_ACCESSORS(centry_stub, Code)
- DECL_OPTIONAL_ACCESSORS(wasm_exported_functions, FixedArray)
+ DECL_OPTIONAL_ACCESSORS(wasm_external_functions, FixedArray)
DECL_PRIMITIVE_ACCESSORS(memory_start, byte*)
DECL_PRIMITIVE_ACCESSORS(memory_size, size_t)
DECL_PRIMITIVE_ACCESSORS(memory_mask, size_t)
@@ -504,8 +500,7 @@ class WasmInstanceObject : public JSObject {
V(kIndirectFunctionTablesOffset, kTaggedSize) \
V(kManagedNativeAllocationsOffset, kTaggedSize) \
V(kExceptionsTableOffset, kTaggedSize) \
- V(kCEntryStubOffset, kTaggedSize) \
- V(kWasmExportedFunctionsOffset, kTaggedSize) \
+ V(kWasmExternalFunctionsOffset, kTaggedSize) \
V(kRealStackLimitAddressOffset, kSystemPointerSize) \
V(kDataSegmentStartsOffset, kSystemPointerSize) \
V(kDataSegmentSizesOffset, kSystemPointerSize) \
@@ -544,8 +539,7 @@ class WasmInstanceObject : public JSObject {
kIndirectFunctionTablesOffset,
kManagedNativeAllocationsOffset,
kExceptionsTableOffset,
- kCEntryStubOffset,
- kWasmExportedFunctionsOffset};
+ kWasmExternalFunctionsOffset};
V8_EXPORT_PRIVATE const wasm::WasmModule* module();
@@ -588,22 +582,22 @@ class WasmInstanceObject : public JSObject {
// Iterates all fields in the object except the untagged fields.
class BodyDescriptor;
- static MaybeHandle<WasmExportedFunction> GetWasmExportedFunction(
+ static MaybeHandle<WasmExternalFunction> GetWasmExternalFunction(
Isolate* isolate, Handle<WasmInstanceObject> instance, int index);
- // Acquires the {WasmExportedFunction} for a given {function_index} from the
+ // Acquires the {WasmExternalFunction} for a given {function_index} from the
// cache of the given {instance}, or creates a new {WasmExportedFunction} if
// it does not exist yet. The new {WasmExportedFunction} is added to the
// cache of the {instance} immediately.
- V8_EXPORT_PRIVATE static Handle<WasmExportedFunction>
- GetOrCreateWasmExportedFunction(Isolate* isolate,
+ V8_EXPORT_PRIVATE static Handle<WasmExternalFunction>
+ GetOrCreateWasmExternalFunction(Isolate* isolate,
Handle<WasmInstanceObject> instance,
int function_index);
- static void SetWasmExportedFunction(Isolate* isolate,
+ static void SetWasmExternalFunction(Isolate* isolate,
Handle<WasmInstanceObject> instance,
int index,
- Handle<WasmExportedFunction> val);
+ Handle<WasmExternalFunction> val);
// Imports a constructed {WasmJSFunction} into the indirect function table of
// this instance. Note that this might trigger wrapper compilation, since a
@@ -713,7 +707,7 @@ class WasmCapiFunction : public JSFunction {
static bool IsWasmCapiFunction(Object object);
static Handle<WasmCapiFunction> New(
- Isolate* isolate, Address call_target, void* embedder_data,
+ Isolate* isolate, Address call_target, Handle<Foreign> embedder_data,
Handle<PodArray<wasm::ValueType>> serialized_signature);
Address GetHostCallTarget() const;
@@ -726,6 +720,19 @@ class WasmCapiFunction : public JSFunction {
OBJECT_CONSTRUCTORS(WasmCapiFunction, JSFunction);
};
+// Any external function that can be imported/exported in modules. This abstract
+// class just dispatches to the following concrete classes:
+// - {WasmExportedFunction}: A proper Wasm function exported from a module.
+// - {WasmJSFunction}: A function constructed via WebAssembly.Function in JS.
+// // TODO(wasm): Potentially {WasmCapiFunction} will be added here as well.
+class WasmExternalFunction : public JSFunction {
+ public:
+ static bool IsWasmExternalFunction(Object object);
+
+ DECL_CAST(WasmExternalFunction)
+ OBJECT_CONSTRUCTORS(WasmExternalFunction, JSFunction);
+};
+
class WasmIndirectFunctionTable : public Struct {
public:
DECL_PRIMITIVE_ACCESSORS(size, uint32_t)
@@ -757,7 +764,7 @@ class WasmIndirectFunctionTable : public Struct {
class WasmCapiFunctionData : public Struct {
public:
DECL_PRIMITIVE_ACCESSORS(call_target, Address)
- DECL_PRIMITIVE_ACCESSORS(embedder_data, void*)
+ DECL_ACCESSORS(embedder_data, Foreign)
DECL_ACCESSORS(wrapper_code, Code)
DECL_ACCESSORS(serialized_signature, PodArray<wasm::ValueType>)
@@ -769,7 +776,7 @@ class WasmCapiFunctionData : public Struct {
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
TORQUE_GENERATED_WASM_CAPI_FUNCTION_DATA_FIELDS)
- STATIC_ASSERT(kStartOfStrongFieldsOffset == kWrapperCodeOffset);
+ STATIC_ASSERT(kStartOfStrongFieldsOffset == kEmbedderDataOffset);
using BodyDescriptor = FlexibleBodyDescriptor<kStartOfStrongFieldsOffset>;
OBJECT_CONSTRUCTORS(WasmCapiFunctionData, Struct);
@@ -785,7 +792,7 @@ class WasmExportedFunctionData : public Struct {
DECL_INT_ACCESSORS(jump_table_offset)
DECL_INT_ACCESSORS(function_index)
DECL_ACCESSORS(c_wrapper_code, Object)
- DECL_ACCESSORS(wasm_call_target, Smi)
+ DECL_ACCESSORS(wasm_call_target, Object)
DECL_INT_ACCESSORS(packed_args_size)
DECL_CAST(WasmExportedFunctionData)
@@ -914,7 +921,8 @@ class WasmDebugInfo : public Struct {
// header. They are referenced by the following fields:
// - {WasmExceptionObject::exception_tag} : The tag of the exception object.
// - {WasmInstanceObject::exceptions_table}: List of tags used by an instance.
-class WasmExceptionTag : public Struct {
+class WasmExceptionTag
+ : public TorqueGeneratedWasmExceptionTag<WasmExceptionTag, Struct> {
public:
V8_EXPORT_PRIVATE static Handle<WasmExceptionTag> New(Isolate* isolate,
int index);
@@ -924,14 +932,9 @@ class WasmExceptionTag : public Struct {
// least one field, hence this also serves as a padding field for now.
DECL_INT_ACCESSORS(index)
- DECL_CAST(WasmExceptionTag)
DECL_PRINTER(WasmExceptionTag)
- DECL_VERIFIER(WasmExceptionTag)
-
- DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize,
- TORQUE_GENERATED_WASM_EXCEPTION_TAG_FIELDS)
- OBJECT_CONSTRUCTORS(WasmExceptionTag, Struct);
+ TQ_OBJECT_CONSTRUCTORS(WasmExceptionTag)
};
class AsmWasmData : public Struct {
diff --git a/deps/v8/src/wasm/wasm-opcodes.cc b/deps/v8/src/wasm/wasm-opcodes.cc
index d3fb4c42cf..879da1445b 100644
--- a/deps/v8/src/wasm/wasm-opcodes.cc
+++ b/deps/v8/src/wasm/wasm-opcodes.cc
@@ -10,6 +10,7 @@
#include "src/codegen/signature.h"
#include "src/execution/messages.h"
#include "src/runtime/runtime.h"
+#include "src/wasm/wasm-features.h"
namespace v8 {
namespace internal {
@@ -229,11 +230,16 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_F64x2_OP(Ne, "ne")
CASE_I64x2_OP(Ne, "ne")
CASE_SIMD_OP(Add, "add")
+ CASE_F64x2_OP(Add, "add")
CASE_I64x2_OP(Add, "add")
CASE_SIMD_OP(Sub, "sub")
+ CASE_F64x2_OP(Sub, "sub")
CASE_I64x2_OP(Sub, "sub")
CASE_SIMD_OP(Mul, "mul")
+ CASE_F64x2_OP(Mul, "mul")
CASE_I64x2_OP(Mul, "mul")
+ CASE_F64x2_OP(Div, "div")
+ CASE_F32x4_OP(Div, "div")
CASE_F64x2_OP(Splat, "splat")
CASE_F64x2_OP(Lt, "lt")
CASE_F64x2_OP(Le, "le")
@@ -244,7 +250,9 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_F32x4_OP(AddHoriz, "add_horizontal")
CASE_F32x4_OP(RecipApprox, "recip_approx")
CASE_F32x4_OP(RecipSqrtApprox, "recip_sqrt_approx")
+ CASE_F64x2_OP(Min, "min")
CASE_F32x4_OP(Min, "min")
+ CASE_F64x2_OP(Max, "max")
CASE_F32x4_OP(Max, "max")
CASE_F32x4_OP(Lt, "lt")
CASE_F32x4_OP(Le, "le")
@@ -267,7 +275,9 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_SIMDI_OP(ExtractLane, "extract_lane")
CASE_SIMDI_OP(ReplaceLane, "replace_lane")
CASE_SIGN_OP(SIMDI, Min, "min")
+ CASE_SIGN_OP(I64x2, Min, "min")
CASE_SIGN_OP(SIMDI, Max, "max")
+ CASE_SIGN_OP(I64x2, Max, "max")
CASE_SIGN_OP(SIMDI, Lt, "lt")
CASE_SIGN_OP(I64x2, Lt, "lt")
CASE_SIGN_OP(SIMDI, Le, "le")
@@ -439,12 +449,13 @@ std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) {
return os;
}
-bool IsJSCompatibleSignature(const FunctionSig* sig, bool has_bigint_feature) {
- if (sig->return_count() > 1) {
+bool IsJSCompatibleSignature(const FunctionSig* sig,
+ const WasmFeatures& enabled_features) {
+ if (!enabled_features.mv && sig->return_count() > 1) {
return false;
}
for (auto type : sig->all()) {
- if (!has_bigint_feature && type == kWasmI64) {
+ if (!enabled_features.bigint && type == kWasmI64) {
return false;
}
diff --git a/deps/v8/src/wasm/wasm-opcodes.h b/deps/v8/src/wasm/wasm-opcodes.h
index 22bd47d54b..0b19d7452c 100644
--- a/deps/v8/src/wasm/wasm-opcodes.h
+++ b/deps/v8/src/wasm/wasm-opcodes.h
@@ -15,8 +15,10 @@ namespace internal {
namespace wasm {
+struct WasmFeatures;
+
std::ostream& operator<<(std::ostream& os, const FunctionSig& function);
-bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
+bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
// Control expressions and blocks.
#define FOREACH_CONTROL_OPCODE(V) \
@@ -335,6 +337,9 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I8x16Neg, 0xfd51, s_s) \
V(S1x16AnyTrue, 0xfd52, i_s) \
V(S1x16AllTrue, 0xfd53, i_s) \
+ V(I8x16Shl, 0xfd54, s_si) \
+ V(I8x16ShrS, 0xfd55, s_si) \
+ V(I8x16ShrU, 0xfd56, s_si) \
V(I8x16Add, 0xfd57, s_ss) \
V(I8x16AddSaturateS, 0xfd58, s_ss) \
V(I8x16AddSaturateU, 0xfd59, s_ss) \
@@ -349,6 +354,9 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I16x8Neg, 0xfd62, s_s) \
V(S1x8AnyTrue, 0xfd63, i_s) \
V(S1x8AllTrue, 0xfd64, i_s) \
+ V(I16x8Shl, 0xfd65, s_si) \
+ V(I16x8ShrS, 0xfd66, s_si) \
+ V(I16x8ShrU, 0xfd67, s_si) \
V(I16x8Add, 0xfd68, s_ss) \
V(I16x8AddSaturateS, 0xfd69, s_ss) \
V(I16x8AddSaturateU, 0xfd6a, s_ss) \
@@ -363,6 +371,9 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I32x4Neg, 0xfd73, s_s) \
V(S1x4AnyTrue, 0xfd74, i_s) \
V(S1x4AllTrue, 0xfd75, i_s) \
+ V(I32x4Shl, 0xfd76, s_si) \
+ V(I32x4ShrS, 0xfd77, s_si) \
+ V(I32x4ShrU, 0xfd78, s_si) \
V(I32x4Add, 0xfd79, s_ss) \
V(I32x4Sub, 0xfd7c, s_ss) \
V(I32x4Mul, 0xfd7f, s_ss) \
@@ -373,9 +384,16 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I64x2Neg, 0xfd84, s_s) \
V(S1x2AnyTrue, 0xfd85, i_s) \
V(S1x2AllTrue, 0xfd86, i_s) \
+ V(I64x2Shl, 0xfd87, s_si) \
+ V(I64x2ShrS, 0xfd88, s_si) \
+ V(I64x2ShrU, 0xfd89, s_si) \
V(I64x2Add, 0xfd8a, s_ss) \
V(I64x2Sub, 0xfd8d, s_ss) \
V(I64x2Mul, 0xfd8c, s_ss) \
+ V(I64x2MinS, 0xfd8e, s_ss) \
+ V(I64x2MinU, 0xfd8f, s_ss) \
+ V(I64x2MaxS, 0xfd90, s_ss) \
+ V(I64x2MaxU, 0xfd91, s_ss) \
V(F32x4Abs, 0xfd95, s_s) \
V(F32x4Neg, 0xfd96, s_s) \
V(F32x4RecipApprox, 0xfd98, s_s) \
@@ -383,26 +401,33 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(F32x4Add, 0xfd9a, s_ss) \
V(F32x4Sub, 0xfd9b, s_ss) \
V(F32x4Mul, 0xfd9c, s_ss) \
+ V(F32x4Div, 0xfd9d, s_ss) \
V(F32x4Min, 0xfd9e, s_ss) \
V(F32x4Max, 0xfd9f, s_ss) \
V(F64x2Abs, 0xfda0, s_s) \
V(F64x2Neg, 0xfda1, s_s) \
+ V(F64x2Add, 0xfda5, s_ss) \
+ V(F64x2Sub, 0xfda6, s_ss) \
+ V(F64x2Mul, 0xfda7, s_ss) \
+ V(F64x2Div, 0xfda8, s_ss) \
+ V(F64x2Min, 0xfda9, s_ss) \
+ V(F64x2Max, 0xfdaa, s_ss) \
V(I32x4SConvertF32x4, 0xfdab, s_s) \
V(I32x4UConvertF32x4, 0xfdac, s_s) \
V(F32x4SConvertI32x4, 0xfdaf, s_s) \
V(F32x4UConvertI32x4, 0xfdb0, s_s) \
- V(I8x16SConvertI16x8, 0xfdb1, s_ss) \
- V(I8x16UConvertI16x8, 0xfdb2, s_ss) \
- V(I16x8SConvertI32x4, 0xfdb3, s_ss) \
- V(I16x8UConvertI32x4, 0xfdb4, s_ss) \
- V(I16x8SConvertI8x16Low, 0xfdb5, s_s) \
- V(I16x8SConvertI8x16High, 0xfdb6, s_s) \
- V(I16x8UConvertI8x16Low, 0xfdb7, s_s) \
- V(I16x8UConvertI8x16High, 0xfdb8, s_s) \
- V(I32x4SConvertI16x8Low, 0xfdb9, s_s) \
- V(I32x4SConvertI16x8High, 0xfdba, s_s) \
- V(I32x4UConvertI16x8Low, 0xfdbb, s_s) \
- V(I32x4UConvertI16x8High, 0xfdbc, s_s) \
+ V(I8x16SConvertI16x8, 0xfdc6, s_ss) \
+ V(I8x16UConvertI16x8, 0xfdc7, s_ss) \
+ V(I16x8SConvertI32x4, 0xfdc8, s_ss) \
+ V(I16x8UConvertI32x4, 0xfdc9, s_ss) \
+ V(I16x8SConvertI8x16Low, 0xfdca, s_s) \
+ V(I16x8SConvertI8x16High, 0xfdcb, s_s) \
+ V(I16x8UConvertI8x16Low, 0xfdcc, s_s) \
+ V(I16x8UConvertI8x16High, 0xfdcd, s_s) \
+ V(I32x4SConvertI16x8Low, 0xfdce, s_s) \
+ V(I32x4SConvertI16x8High, 0xfdcf, s_s) \
+ V(I32x4UConvertI16x8Low, 0xfdd0, s_s) \
+ V(I32x4UConvertI16x8High, 0xfdd1, s_s) \
V(I16x8AddHoriz, 0xfdbd, s_ss) \
V(I32x4AddHoriz, 0xfdbe, s_ss) \
V(F32x4AddHoriz, 0xfdbf, s_ss)
@@ -413,19 +438,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, bool hasBigIntFeature);
V(I32x4ExtractLane, 0xfd0d, _) \
V(I64x2ExtractLane, 0xfd10, _) \
V(F32x4ExtractLane, 0xfd13, _) \
- V(F64x2ExtractLane, 0xfd16, _) \
- V(I8x16Shl, 0xfd54, _) \
- V(I8x16ShrS, 0xfd55, _) \
- V(I8x16ShrU, 0xfd56, _) \
- V(I16x8Shl, 0xfd65, _) \
- V(I16x8ShrS, 0xfd66, _) \
- V(I16x8ShrU, 0xfd67, _) \
- V(I32x4Shl, 0xfd76, _) \
- V(I32x4ShrS, 0xfd77, _) \
- V(I32x4ShrU, 0xfd78, _) \
- V(I64x2Shl, 0xfd87, _) \
- V(I64x2ShrS, 0xfd88, _) \
- V(I64x2ShrU, 0xfd89, _)
+ V(F64x2ExtractLane, 0xfd16, _)
#define FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(V) \
V(I8x16ReplaceLane, 0xfd07, _) \
@@ -678,6 +691,8 @@ struct WasmInitExpr {
val.global_index = index;
} else if (kind == kRefFuncConst) {
val.function_index = index;
+ } else if (kind == kRefNullConst) {
+ // Nothing to do.
} else {
// For the other types, the other initializers should be used.
UNREACHABLE();
diff --git a/deps/v8/src/wasm/wasm-serialization.cc b/deps/v8/src/wasm/wasm-serialization.cc
index a20b2f115a..81460b9fe2 100644
--- a/deps/v8/src/wasm/wasm-serialization.cc
+++ b/deps/v8/src/wasm/wasm-serialization.cc
@@ -625,12 +625,17 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
Handle<Script> script =
CreateWasmScript(isolate, wire_bytes, module->source_map_url);
- OwnedVector<uint8_t> wire_bytes_copy =
- OwnedVector<uint8_t>::Of(wire_bytes_vec);
+ auto shared_native_module = isolate->wasm_engine()->NewNativeModule(
+ isolate, enabled_features, std::move(decode_result.value()));
+ shared_native_module->SetWireBytes(OwnedVector<uint8_t>::Of(wire_bytes_vec));
+ shared_native_module->SetRuntimeStubs(isolate);
+
+ Handle<FixedArray> export_wrappers;
+ CompileJsToWasmWrappers(isolate, shared_native_module->module(),
+ &export_wrappers);
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
- isolate, enabled_features, std::move(decode_result).value(),
- std::move(wire_bytes_copy), script, Handle<ByteArray>::null());
+ isolate, std::move(shared_native_module), script, export_wrappers);
NativeModule* native_module = module_object->native_module();
NativeModuleDeserializer deserializer(native_module);
@@ -639,9 +644,6 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
Reader reader(data + kVersionSize);
if (!deserializer.Read(&reader)) return {};
- CompileJsToWasmWrappers(isolate, native_module->module(),
- handle(module_object->export_wrappers(), isolate));
-
// Log the code within the generated module for profiling.
native_module->LogWasmCodes(isolate);
diff --git a/deps/v8/src/wasm/wasm-text.cc b/deps/v8/src/wasm/wasm-text.cc
index e17d34e36f..44abd71445 100644
--- a/deps/v8/src/wasm/wasm-text.cc
+++ b/deps/v8/src/wasm/wasm-text.cc
@@ -321,23 +321,6 @@ void PrintWasmText(const WasmModule* module, const ModuleWireBytes& wire_bytes,
break;
}
- case kExprI8x16Shl:
- case kExprI8x16ShrS:
- case kExprI8x16ShrU:
- case kExprI16x8Shl:
- case kExprI16x8ShrS:
- case kExprI16x8ShrU:
- case kExprI32x4Shl:
- case kExprI32x4ShrS:
- case kExprI32x4ShrU:
- case kExprI64x2Shl:
- case kExprI64x2ShrS:
- case kExprI64x2ShrU: {
- SimdShiftImmediate<Decoder::kNoValidate> imm(&i, i.pc());
- os << WasmOpcodes::OpcodeName(opcode) << ' ' << imm.shift;
- break;
- }
-
FOREACH_SIMD_0_OPERAND_OPCODE(CASE_OPCODE) {
os << WasmOpcodes::OpcodeName(opcode);
break;
diff --git a/deps/v8/src/zone/zone.h b/deps/v8/src/zone/zone.h
index e2b66253f5..df72864c5a 100644
--- a/deps/v8/src/zone/zone.h
+++ b/deps/v8/src/zone/zone.h
@@ -322,13 +322,23 @@ class ZoneList final {
template <typename T>
using ZonePtrList = ZoneList<T*>;
-template <typename T>
-class ScopedPtrList final {
+// ScopedList is a scope-lifetime list with a std::vector backing that can be
+// re-used between ScopedLists. Note that a ScopedList in an outer scope cannot
+// add any entries if there is a ScopedList with the same backing in an inner
+// scope.
+template <typename T, typename TBacking = T>
+class ScopedList final {
+ // The backing can either be the same type as the list type, or, for pointers,
+ // we additionally allow a void* backing store.
+ STATIC_ASSERT((std::is_same<TBacking, T>::value) ||
+ (std::is_same<TBacking, void*>::value &&
+ std::is_pointer<T>::value));
+
public:
- explicit ScopedPtrList(std::vector<void*>* buffer)
+ explicit ScopedList(std::vector<TBacking>* buffer)
: buffer_(*buffer), start_(buffer->size()), end_(buffer->size()) {}
- ~ScopedPtrList() { Rewind(); }
+ ~ScopedList() { Rewind(); }
void Rewind() {
DCHECK_EQ(buffer_.size(), end_);
@@ -336,7 +346,7 @@ class ScopedPtrList final {
end_ = start_;
}
- void MergeInto(ScopedPtrList* parent) {
+ void MergeInto(ScopedList* parent) {
DCHECK_EQ(parent->end_, start_);
parent->end_ = end_;
start_ = end_;
@@ -344,38 +354,46 @@ class ScopedPtrList final {
}
int length() const { return static_cast<int>(end_ - start_); }
- T* at(int i) const {
+
+ const T& at(int i) const {
size_t index = start_ + i;
DCHECK_LE(start_, index);
DCHECK_LT(index, buffer_.size());
- return reinterpret_cast<T*>(buffer_[index]);
+ return *reinterpret_cast<T*>(&buffer_[index]);
}
- void CopyTo(ZonePtrList<T>* target, Zone* zone) const {
+ T& at(int i) {
+ size_t index = start_ + i;
+ DCHECK_LE(start_, index);
+ DCHECK_LT(index, buffer_.size());
+ return *reinterpret_cast<T*>(&buffer_[index]);
+ }
+
+ void CopyTo(ZoneList<T>* target, Zone* zone) const {
DCHECK_LE(end_, buffer_.size());
// Make sure we don't reference absent elements below.
if (length() == 0) return;
target->Initialize(length(), zone);
- T** data = reinterpret_cast<T**>(&buffer_[start_]);
- target->AddAll(Vector<T*>(data, length()), zone);
+ T* data = reinterpret_cast<T*>(&buffer_[start_]);
+ target->AddAll(Vector<T>(data, length()), zone);
}
- Vector<T*> CopyTo(Zone* zone) {
+ Vector<T> CopyTo(Zone* zone) {
DCHECK_LE(end_, buffer_.size());
- T** data = zone->NewArray<T*>(length());
+ T* data = zone->NewArray<T>(length());
if (length() != 0) {
- MemCopy(data, &buffer_[start_], length() * sizeof(T*));
+ MemCopy(data, &buffer_[start_], length() * sizeof(T));
}
- return Vector<T*>(data, length());
+ return Vector<T>(data, length());
}
- void Add(T* value) {
+ void Add(const T& value) {
DCHECK_EQ(buffer_.size(), end_);
buffer_.push_back(value);
++end_;
}
- void AddAll(const ZonePtrList<T>& list) {
+ void AddAll(const ZoneList<T>& list) {
DCHECK_EQ(buffer_.size(), end_);
buffer_.reserve(buffer_.size() + list.length());
for (int i = 0; i < list.length(); i++) {
@@ -384,20 +402,23 @@ class ScopedPtrList final {
end_ += list.length();
}
- using iterator = T**;
+ using iterator = T*;
inline iterator begin() const {
- return reinterpret_cast<T**>(buffer_.data() + start_);
+ return reinterpret_cast<T*>(buffer_.data() + start_);
}
inline iterator end() const {
- return reinterpret_cast<T**>(buffer_.data() + end_);
+ return reinterpret_cast<T*>(buffer_.data() + end_);
}
private:
- std::vector<void*>& buffer_;
+ std::vector<TBacking>& buffer_;
size_t start_;
size_t end_;
};
+template <typename T>
+using ScopedPtrList = ScopedList<T*, void*>;
+
using ZoneHashMap = base::PointerTemplateHashMapImpl<ZoneAllocationPolicy>;
using CustomMatcherZoneHashMap =
diff --git a/deps/v8/test/OWNERS b/deps/v8/test/OWNERS
index 852d438bb0..3c70cea2fd 100644
--- a/deps/v8/test/OWNERS
+++ b/deps/v8/test/OWNERS
@@ -1 +1 @@
-file://COMMON_OWNERS
+file:../COMMON_OWNERS
diff --git a/deps/v8/test/cctest/BUILD.gn b/deps/v8/test/cctest/BUILD.gn
index 32a766736f..d0934c9977 100644
--- a/deps/v8/test/cctest/BUILD.gn
+++ b/deps/v8/test/cctest/BUILD.gn
@@ -4,6 +4,13 @@
import("../../gni/v8.gni")
+config("cctest_config") {
+ # Work around a bug in the gold linker.
+ if (use_gold && target_cpu == "x86") {
+ ldflags = [ "-Wl,--icf=none" ]
+ }
+}
+
v8_executable("cctest") {
testonly = true
@@ -28,6 +35,7 @@ v8_executable("cctest") {
configs = [
"../..:external_config",
"../..:internal_config_base",
+ ":cctest_config",
]
ldflags = []
@@ -188,6 +196,7 @@ v8_source_set("cctest_sources") {
"test-conversions.cc",
"test-cpu-profiler.cc",
"test-date.cc",
+ "test-debug-helper.cc",
"test-debug.cc",
"test-decls.cc",
"test-deoptimization.cc",
@@ -313,11 +322,15 @@ v8_source_set("cctest_sources") {
"test-javascript-arm64.cc",
"test-js-arm64-variables.cc",
"test-macro-assembler-arm64.cc",
+ "test-pointer-auth-arm64.cc",
"test-poison-disasm-arm64.cc",
"test-sync-primitives-arm64.cc",
"test-utils-arm64.cc",
"test-utils-arm64.h",
]
+ if (is_win) {
+ sources += [ "test-stack-unwinding-win64.cc" ]
+ }
} else if (v8_current_cpu == "x86") {
sources += [ ### gcmole(arch:ia32) ###
"test-assembler-ia32.cc",
@@ -356,7 +369,7 @@ v8_source_set("cctest_sources") {
"test-macro-assembler-x64.cc",
]
if (is_win) {
- sources += [ "test-stack-unwinding-x64.cc" ]
+ sources += [ "test-stack-unwinding-win64.cc" ]
}
} else if (v8_current_cpu == "ppc" || v8_current_cpu == "ppc64") {
sources += [ ### gcmole(arch:ppc) ###
@@ -382,6 +395,7 @@ v8_source_set("cctest_sources") {
"../..:v8_libbase",
"../..:v8_libplatform",
"../..:wasm_module_runner",
+ "../../tools/debug_helper:v8_debug_helper",
"//build/win:default_exe_manifest",
]
diff --git a/deps/v8/test/cctest/DEPS b/deps/v8/test/cctest/DEPS
index 909e60372e..7373012870 100644
--- a/deps/v8/test/cctest/DEPS
+++ b/deps/v8/test/cctest/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+src",
+ "+tools",
"+torque-generated",
- "+perfetto/tracing.h"
-]
+ "+perfetto",
+] \ No newline at end of file
diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status
index 17d0096140..b1a7b5c101 100644
--- a/deps/v8/test/cctest/cctest.status
+++ b/deps/v8/test/cctest/cctest.status
@@ -518,6 +518,7 @@
'test-regexp/MacroAssemblerNativeSimpleUC16': [SKIP],
'test-regexp/MacroAssemblerNativeSuccess': [SKIP],
'test-regexp/MacroAssemblerStackOverflow': [SKIP],
+ 'test-regexp/Graph': [SKIP],
'test-run-bytecode-graph-builder/*': [SKIP],
'test-run-calls-to-external-references/*': [SKIP],
'test-run-deopt/*': [SKIP],
diff --git a/deps/v8/test/cctest/compiler/codegen-tester.h b/deps/v8/test/cctest/compiler/codegen-tester.h
index 62db9445ea..210fe2cf1c 100644
--- a/deps/v8/test/cctest/compiler/codegen-tester.h
+++ b/deps/v8/test/cctest/compiler/codegen-tester.h
@@ -34,7 +34,7 @@ class RawMachineAssemblerTester : public HandleAndZoneScope,
main_zone(),
CSignature::New(main_zone(), MachineTypeForC<ReturnType>(),
p...),
- true),
+ CallDescriptor::kInitializeRootRegister),
MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags(),
InstructionSelector::AlignmentRequirements()) {}
@@ -51,7 +51,7 @@ class RawMachineAssemblerTester : public HandleAndZoneScope,
main_zone(),
CSignature::New(main_zone(), MachineTypeForC<ReturnType>(),
p...),
- true),
+ CallDescriptor::kInitializeRootRegister),
MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags(),
InstructionSelector::AlignmentRequirements()),
@@ -79,7 +79,7 @@ class RawMachineAssemblerTester : public HandleAndZoneScope,
protected:
Address Generate() override {
if (code_.is_null()) {
- Schedule* schedule = this->Export();
+ Schedule* schedule = this->ExportForTest();
auto call_descriptor = this->call_descriptor();
Graph* graph = this->graph();
OptimizedCompilationInfo info(ArrayVector("testing"), main_zone(), kind_);
diff --git a/deps/v8/test/cctest/compiler/serializer-tester.cc b/deps/v8/test/cctest/compiler/serializer-tester.cc
index 2b56e07d24..338d1bcbfb 100644
--- a/deps/v8/test/cctest/compiler/serializer-tester.cc
+++ b/deps/v8/test/cctest/compiler/serializer-tester.cc
@@ -70,7 +70,11 @@ void CheckForSerializedInlinee(const char* source, int argc = 0,
Handle<Object> g;
CHECK(g_obj.ToHandle(&g));
+ CHECK_WITH_MSG(
+ g->IsJSFunction(),
+ "The return value of the outer function must be a function too");
Handle<JSFunction> g_func = Handle<JSFunction>::cast(g);
+
SharedFunctionInfoRef g_sfi(tester.broker(),
handle(g_func->shared(), tester.isolate()));
FeedbackVectorRef g_fv(tester.broker(),
@@ -288,6 +292,34 @@ TEST(MergeJumpTargetEnvironment) {
"f(); return f;"); // Two calls to f to make g() megamorhpic.
}
+TEST(BoundFunctionTarget) {
+ CheckForSerializedInlinee(
+ "function apply(foo, arg) { return foo(arg); };"
+ "%EnsureFeedbackVectorForFunction(apply);"
+ "function test() {"
+ " const lambda = (a) => a;"
+ " %EnsureFeedbackVectorForFunction(lambda);"
+ " let bound = apply.bind(null, lambda).bind(null, 42);"
+ " %TurbofanStaticAssert(bound() == 42); return apply;"
+ "};"
+ "%EnsureFeedbackVectorForFunction(test);"
+ "test(); return test;");
+}
+
+TEST(BoundFunctionArguments) {
+ CheckForSerializedInlinee(
+ "function apply(foo, arg) { return foo(arg); };"
+ "%EnsureFeedbackVectorForFunction(apply);"
+ "function test() {"
+ " const lambda = (a) => a;"
+ " %EnsureFeedbackVectorForFunction(lambda);"
+ " let bound = apply.bind(null, lambda).bind(null, 42);"
+ " %TurbofanStaticAssert(bound() == 42); return lambda;"
+ "};"
+ "%EnsureFeedbackVectorForFunction(test);"
+ "test(); return test;");
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/cctest/compiler/test-code-assembler.cc b/deps/v8/test/cctest/compiler/test-code-assembler.cc
index 375c6586f3..9e6318ee88 100644
--- a/deps/v8/test/cctest/compiler/test-code-assembler.cc
+++ b/deps/v8/test/cctest/compiler/test-code-assembler.cc
@@ -24,7 +24,7 @@ using Variable = CodeAssemblerVariable;
Node* SmiTag(CodeAssembler& m, // NOLINT(runtime/references)
Node* value) {
int32_t constant_value;
- if (m.ToInt32Constant(value, constant_value) &&
+ if (m.ToInt32Constant(value, &constant_value) &&
Smi::IsValid(constant_value)) {
return m.SmiConstant(Smi::FromInt(constant_value));
}
@@ -89,7 +89,8 @@ TEST(SimpleCallRuntime1Arg) {
Isolate* isolate(CcTest::InitIsolateOnce());
CodeAssemblerTester asm_tester(isolate);
CodeAssembler m(asm_tester.state());
- Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
+ TNode<Context> context =
+ m.HeapConstant(Handle<Context>(isolate->native_context()));
Node* b = SmiTag(m, m.Int32Constant(0));
m.Return(m.CallRuntime(Runtime::kIsSmi, context, b));
FunctionTester ft(asm_tester.GenerateCode());
@@ -101,7 +102,8 @@ TEST(SimpleTailCallRuntime1Arg) {
Isolate* isolate(CcTest::InitIsolateOnce());
CodeAssemblerTester asm_tester(isolate);
CodeAssembler m(asm_tester.state());
- Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
+ TNode<Context> context =
+ m.HeapConstant(Handle<Context>(isolate->native_context()));
Node* b = SmiTag(m, m.Int32Constant(0));
m.TailCallRuntime(Runtime::kIsSmi, context, b);
FunctionTester ft(asm_tester.GenerateCode());
@@ -113,7 +115,8 @@ TEST(SimpleCallRuntime2Arg) {
Isolate* isolate(CcTest::InitIsolateOnce());
CodeAssemblerTester asm_tester(isolate);
CodeAssembler m(asm_tester.state());
- Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
+ TNode<Context> context =
+ m.HeapConstant(Handle<Context>(isolate->native_context()));
Node* a = SmiTag(m, m.Int32Constant(2));
Node* b = SmiTag(m, m.Int32Constant(4));
m.Return(m.CallRuntime(Runtime::kAdd, context, a, b));
@@ -125,7 +128,8 @@ TEST(SimpleTailCallRuntime2Arg) {
Isolate* isolate(CcTest::InitIsolateOnce());
CodeAssemblerTester asm_tester(isolate);
CodeAssembler m(asm_tester.state());
- Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
+ TNode<Context> context =
+ m.HeapConstant(Handle<Context>(isolate->native_context()));
Node* a = SmiTag(m, m.Int32Constant(2));
Node* b = SmiTag(m, m.Int32Constant(4));
m.TailCallRuntime(Runtime::kAdd, context, a, b);
@@ -225,7 +229,7 @@ TEST(VariableMerge1) {
CodeAssembler m(asm_tester.state());
Variable var1(&m, MachineRepresentation::kTagged);
Label l1(&m), l2(&m), merge(&m);
- Node* temp = m.Int32Constant(0);
+ TNode<Int32T> temp = m.Int32Constant(0);
var1.Bind(temp);
m.Branch(m.Int32Constant(1), &l1, &l2);
m.Bind(&l1);
@@ -244,14 +248,14 @@ TEST(VariableMerge2) {
CodeAssembler m(asm_tester.state());
Variable var1(&m, MachineRepresentation::kTagged);
Label l1(&m), l2(&m), merge(&m);
- Node* temp = m.Int32Constant(0);
+ TNode<Int32T> temp = m.Int32Constant(0);
var1.Bind(temp);
m.Branch(m.Int32Constant(1), &l1, &l2);
m.Bind(&l1);
CHECK_EQ(var1.value(), temp);
m.Goto(&merge);
m.Bind(&l2);
- Node* temp2 = m.Int32Constant(2);
+ TNode<Int32T> temp2 = m.Int32Constant(2);
var1.Bind(temp2);
CHECK_EQ(var1.value(), temp2);
m.Goto(&merge);
@@ -266,7 +270,7 @@ TEST(VariableMerge3) {
Variable var1(&m, MachineRepresentation::kTagged);
Variable var2(&m, MachineRepresentation::kTagged);
Label l1(&m), l2(&m), merge(&m);
- Node* temp = m.Int32Constant(0);
+ TNode<Int32T> temp = m.Int32Constant(0);
var1.Bind(temp);
var2.Bind(temp);
m.Branch(m.Int32Constant(1), &l1, &l2);
@@ -274,7 +278,7 @@ TEST(VariableMerge3) {
CHECK_EQ(var1.value(), temp);
m.Goto(&merge);
m.Bind(&l2);
- Node* temp2 = m.Int32Constant(2);
+ TNode<Int32T> temp2 = m.Int32Constant(2);
var1.Bind(temp2);
CHECK_EQ(var1.value(), temp2);
m.Goto(&merge);
@@ -290,7 +294,7 @@ TEST(VariableMergeBindFirst) {
CodeAssembler m(asm_tester.state());
Variable var1(&m, MachineRepresentation::kTagged);
Label l1(&m), l2(&m), merge(&m, &var1), end(&m);
- Node* temp = m.Int32Constant(0);
+ TNode<Int32T> temp = m.Int32Constant(0);
var1.Bind(temp);
m.Branch(m.Int32Constant(1), &l1, &l2);
m.Bind(&l1);
@@ -301,7 +305,7 @@ TEST(VariableMergeBindFirst) {
CHECK_NOT_NULL(var1.value());
m.Goto(&end);
m.Bind(&l2);
- Node* temp2 = m.Int32Constant(2);
+ TNode<Int32T> temp2 = m.Int32Constant(2);
var1.Bind(temp2);
CHECK_EQ(var1.value(), temp2);
m.Goto(&merge);
@@ -318,7 +322,7 @@ TEST(VariableMergeSwitch) {
Label l1(&m), l2(&m), default_label(&m);
Label* labels[] = {&l1, &l2};
int32_t values[] = {1, 2};
- Node* temp1 = m.Int32Constant(0);
+ TNode<Smi> temp1 = m.SmiConstant(0);
var1.Bind(temp1);
m.Switch(m.Int32Constant(2), &default_label, values, labels, 2);
m.Bind(&l1);
@@ -326,7 +330,7 @@ TEST(VariableMergeSwitch) {
m.Return(temp1);
m.Bind(&l2);
CHECK_EQ(temp1, var1.value());
- Node* temp2 = m.Int32Constant(7);
+ TNode<Smi> temp2 = m.SmiConstant(7);
var1.Bind(temp2);
m.Goto(&default_label);
m.Bind(&default_label);
@@ -374,24 +378,24 @@ TEST(TestToConstant) {
int32_t value32;
int64_t value64;
Node* a = m.Int32Constant(5);
- CHECK(m.ToInt32Constant(a, value32));
- CHECK(m.ToInt64Constant(a, value64));
+ CHECK(m.ToInt32Constant(a, &value32));
+ CHECK(m.ToInt64Constant(a, &value64));
a = m.Int64Constant(static_cast<int64_t>(1) << 32);
- CHECK(!m.ToInt32Constant(a, value32));
- CHECK(m.ToInt64Constant(a, value64));
+ CHECK(!m.ToInt32Constant(a, &value32));
+ CHECK(m.ToInt64Constant(a, &value64));
a = m.Int64Constant(13);
- CHECK(m.ToInt32Constant(a, value32));
- CHECK(m.ToInt64Constant(a, value64));
+ CHECK(m.ToInt32Constant(a, &value32));
+ CHECK(m.ToInt64Constant(a, &value64));
a = UndefinedConstant(m);
- CHECK(!m.ToInt32Constant(a, value32));
- CHECK(!m.ToInt64Constant(a, value64));
+ CHECK(!m.ToInt32Constant(a, &value32));
+ CHECK(!m.ToInt64Constant(a, &value64));
a = UndefinedConstant(m);
- CHECK(!m.ToInt32Constant(a, value32));
- CHECK(!m.ToInt64Constant(a, value64));
+ CHECK(!m.ToInt32Constant(a, &value32));
+ CHECK(!m.ToInt64Constant(a, &value64));
}
TEST(DeferredCodePhiHints) {
@@ -453,14 +457,15 @@ TEST(GotoIfException) {
CodeAssemblerTester asm_tester(isolate, kNumParams);
CodeAssembler m(asm_tester.state());
- Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
- Node* to_string_tag =
+ TNode<Context> context =
+ m.HeapConstant(Handle<Context>(isolate->native_context()));
+ TNode<Symbol> to_string_tag =
m.HeapConstant(isolate->factory()->to_string_tag_symbol());
Variable exception(&m, MachineRepresentation::kTagged);
Label exception_handler(&m);
Callable to_string = Builtins::CallableFor(isolate, Builtins::kToString);
- Node* string = m.CallStub(to_string, context, to_string_tag);
+ TNode<Object> string = m.CallStub(to_string, context, to_string_tag);
m.GotoIfException(string, &exception_handler, &exception);
m.Return(string);
@@ -487,7 +492,8 @@ TEST(GotoIfExceptionMultiple) {
CodeAssemblerTester asm_tester(isolate, kNumParams);
CodeAssembler m(asm_tester.state());
- Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
+ TNode<Context> context =
+ m.HeapConstant(Handle<Context>(isolate->native_context()));
Node* first_value = m.Parameter(0);
Node* second_value = m.Parameter(1);
Node* third_value = m.Parameter(2);
@@ -502,7 +508,7 @@ TEST(GotoIfExceptionMultiple) {
// try { return ToString(param1) } catch (e) { ... }
Callable to_string = Builtins::CallableFor(isolate, Builtins::kToString);
- Node* string = m.CallStub(to_string, context, first_value);
+ TNode<Object> string = m.CallStub(to_string, context, first_value);
m.GotoIfException(string, &exception_handler1, &error);
m.Return(string);
@@ -575,7 +581,8 @@ TEST(ExceptionHandler) {
Label exception(&m, {&var}, Label::kDeferred);
{
CodeAssemblerScopedExceptionHandler handler(&m, &exception, &var);
- Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
+ TNode<Context> context =
+ m.HeapConstant(Handle<Context>(isolate->native_context()));
m.CallRuntime(Runtime::kThrow, context, m.SmiConstant(2));
}
m.Return(m.SmiConstant(1));
diff --git a/deps/v8/test/cctest/compiler/test-code-generator.cc b/deps/v8/test/cctest/compiler/test-code-generator.cc
index 30cd7da7b5..74c50a4bfa 100644
--- a/deps/v8/test/cctest/compiler/test-code-generator.cc
+++ b/deps/v8/test/cctest/compiler/test-code-generator.cc
@@ -223,7 +223,7 @@ Handle<Code> BuildTeardownFunction(Isolate* isolate,
TNode<FixedArray> vector =
__ Cast(__ LoadFixedArrayElement(result_array, i));
for (int lane = 0; lane < 4; lane++) {
- Node* lane_value =
+ TNode<Smi> lane_value =
__ SmiFromInt32(tester.raw_assembler_for_testing()->AddNode(
tester.raw_assembler_for_testing()
->machine()
@@ -990,13 +990,14 @@ class CodeGeneratorTester {
i++;
}
+ static constexpr size_t kMaxUnoptimizedFrameHeight = 0;
generator_ = new CodeGenerator(
environment->main_zone(), &frame_, &linkage_,
environment->instructions(), &info_, environment->main_isolate(),
base::Optional<OsrHelper>(), kNoSourcePosition, nullptr,
PoisoningMitigationLevel::kDontPoison,
AssemblerOptions::Default(environment->main_isolate()),
- Builtins::kNoBuiltinId);
+ Builtins::kNoBuiltinId, kMaxUnoptimizedFrameHeight);
// Force a frame to be created.
generator_->frame_access_state()->MarkHasFrame(true);
diff --git a/deps/v8/test/cctest/compiler/test-instruction-scheduler.cc b/deps/v8/test/cctest/compiler/test-instruction-scheduler.cc
index f80718e05e..7aa408f653 100644
--- a/deps/v8/test/cctest/compiler/test-instruction-scheduler.cc
+++ b/deps/v8/test/cctest/compiler/test-instruction-scheduler.cc
@@ -76,7 +76,7 @@ TEST(DeoptInMiddleOfBasicBlock) {
// Dummy node for FlagsContinuation::ForDeoptimize (which won't accept
// nullptr).
Node* node = Node::New(zone, 0, nullptr, 0, nullptr, false);
- VectorSlotPair feedback;
+ FeedbackSource feedback;
FlagsContinuation cont = FlagsContinuation::ForDeoptimize(
kEqual, DeoptimizeKind::kEager, DeoptimizeReason::kUnknown, feedback,
node);
diff --git a/deps/v8/test/cctest/compiler/test-js-constant-cache.cc b/deps/v8/test/cctest/compiler/test-js-constant-cache.cc
index aef10b472d..cc2eddd1a0 100644
--- a/deps/v8/test/cctest/compiler/test-js-constant-cache.cc
+++ b/deps/v8/test/cctest/compiler/test-js-constant-cache.cc
@@ -4,6 +4,7 @@
#include "src/codegen/assembler.h"
#include "src/compiler/js-graph.h"
+#include "src/compiler/js-heap-broker.h"
#include "src/compiler/node-properties.h"
#include "src/heap/factory-inl.h"
#include "test/cctest/cctest.h"
@@ -35,7 +36,9 @@ class JSConstantCacheTester : public HandleAndZoneScope,
JSConstantCacheTester()
: JSCacheTesterHelper(main_zone()),
JSGraph(main_isolate(), &main_graph_, &main_common_, &main_javascript_,
- nullptr, &main_machine_) {
+ nullptr, &main_machine_),
+ canonical_(main_isolate()),
+ broker_(main_isolate(), main_zone(), false) {
main_graph_.SetStart(main_graph_.NewNode(common()->Start(0)));
main_graph_.SetEnd(
main_graph_.NewNode(common()->End(1), main_graph_.start()));
@@ -47,6 +50,11 @@ class JSConstantCacheTester : public HandleAndZoneScope,
}
Factory* factory() { return main_isolate()->factory(); }
+ JSHeapBroker* broker() { return &broker_; }
+
+ private:
+ CanonicalHandleScope canonical_;
+ JSHeapBroker broker_;
};
@@ -182,8 +190,8 @@ TEST(HeapNumbers) {
Handle<Object> num = T.factory()->NewNumber(value);
Handle<HeapNumber> heap = T.factory()->NewHeapNumber(value);
Node* node1 = T.Constant(value);
- Node* node2 = T.Constant(num);
- Node* node3 = T.Constant(heap);
+ Node* node2 = T.Constant(ObjectRef(T.broker(), num));
+ Node* node3 = T.Constant(ObjectRef(T.broker(), heap));
CHECK_EQ(node1, node2);
CHECK_EQ(node1, node3);
}
@@ -193,12 +201,18 @@ TEST(HeapNumbers) {
TEST(OddballHandle) {
JSConstantCacheTester T;
- CHECK_EQ(T.UndefinedConstant(), T.Constant(T.factory()->undefined_value()));
- CHECK_EQ(T.TheHoleConstant(), T.Constant(T.factory()->the_hole_value()));
- CHECK_EQ(T.TrueConstant(), T.Constant(T.factory()->true_value()));
- CHECK_EQ(T.FalseConstant(), T.Constant(T.factory()->false_value()));
- CHECK_EQ(T.NullConstant(), T.Constant(T.factory()->null_value()));
- CHECK_EQ(T.NaNConstant(), T.Constant(T.factory()->nan_value()));
+ CHECK_EQ(T.UndefinedConstant(),
+ T.Constant(ObjectRef(T.broker(), T.factory()->undefined_value())));
+ CHECK_EQ(T.TheHoleConstant(),
+ T.Constant(ObjectRef(T.broker(), T.factory()->the_hole_value())));
+ CHECK_EQ(T.TrueConstant(),
+ T.Constant(ObjectRef(T.broker(), T.factory()->true_value())));
+ CHECK_EQ(T.FalseConstant(),
+ T.Constant(ObjectRef(T.broker(), T.factory()->false_value())));
+ CHECK_EQ(T.NullConstant(),
+ T.Constant(ObjectRef(T.broker(), T.factory()->null_value())));
+ CHECK_EQ(T.NaNConstant(),
+ T.Constant(ObjectRef(T.broker(), T.factory()->nan_value())));
}
diff --git a/deps/v8/test/cctest/compiler/test-js-context-specialization.cc b/deps/v8/test/cctest/compiler/test-js-context-specialization.cc
index e6703dbbbe..1b136873b5 100644
--- a/deps/v8/test/cctest/compiler/test-js-context-specialization.cc
+++ b/deps/v8/test/cctest/compiler/test-js-context-specialization.cc
@@ -52,6 +52,8 @@ class ContextSpecializationTester : public HandleAndZoneScope {
void CheckContextInputAndDepthChanges(Node* node, Node* expected_new_context,
size_t expected_new_depth);
+ JSHeapBroker* broker() { return &js_heap_broker_; }
+
private:
TickCounter tick_counter_;
CanonicalHandleScope canonical_;
@@ -126,8 +128,9 @@ TEST(ReduceJSLoadContext0) {
const int slot = Context::NATIVE_CONTEXT_INDEX;
native->set(slot, *expected);
- Node* const_context = t.jsgraph()->Constant(native);
- Node* deep_const_context = t.jsgraph()->Constant(subcontext2);
+ Node* const_context = t.jsgraph()->Constant(ObjectRef(t.broker(), native));
+ Node* deep_const_context =
+ t.jsgraph()->Constant(ObjectRef(t.broker(), subcontext2));
Node* param_context = t.graph()->NewNode(t.common()->Parameter(0), start);
{
@@ -269,7 +272,8 @@ TEST(ReduceJSLoadContext2) {
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
- Node* context0 = t.jsgraph()->Constant(context_object1);
+ Node* context0 =
+ t.jsgraph()->Constant(ObjectRef(t.broker(), context_object1));
Node* context1 =
t.graph()->NewNode(create_function_context, context0, start, start);
Node* context2 =
@@ -423,8 +427,9 @@ TEST(ReduceJSStoreContext0) {
const int slot = Context::NATIVE_CONTEXT_INDEX;
native->set(slot, *expected);
- Node* const_context = t.jsgraph()->Constant(native);
- Node* deep_const_context = t.jsgraph()->Constant(subcontext2);
+ Node* const_context = t.jsgraph()->Constant(ObjectRef(t.broker(), native));
+ Node* deep_const_context =
+ t.jsgraph()->Constant(ObjectRef(t.broker(), subcontext2));
Node* param_context = t.graph()->NewNode(t.common()->Parameter(0), start);
{
@@ -531,7 +536,8 @@ TEST(ReduceJSStoreContext2) {
context_object0->set(slot_index, *slot_value0);
context_object1->set(slot_index, *slot_value1);
- Node* context0 = t.jsgraph()->Constant(context_object1);
+ Node* context0 =
+ t.jsgraph()->Constant(ObjectRef(t.broker(), context_object1));
Node* context1 =
t.graph()->NewNode(create_function_context, context0, start, start);
Node* context2 =
diff --git a/deps/v8/test/cctest/compiler/test-multiple-return.cc b/deps/v8/test/cctest/compiler/test-multiple-return.cc
index a34b1e14e5..c054e7654a 100644
--- a/deps/v8/test/cctest/compiler/test-multiple-return.cc
+++ b/deps/v8/test/cctest/compiler/test-multiple-return.cc
@@ -167,11 +167,11 @@ void TestReturnMultipleValues(MachineType type) {
OptimizedCompilationInfo info(ArrayVector("testing"), handles.main_zone(),
Code::WASM_FUNCTION);
- Handle<Code> code =
- Pipeline::GenerateCodeForTesting(
- &info, handles.main_isolate(), desc, m.graph(),
- AssemblerOptions::Default(handles.main_isolate()), m.Export())
- .ToHandleChecked();
+ Handle<Code> code = Pipeline::GenerateCodeForTesting(
+ &info, handles.main_isolate(), desc, m.graph(),
+ AssemblerOptions::Default(handles.main_isolate()),
+ m.ExportForTest())
+ .ToHandleChecked();
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code) {
StdoutStream os;
@@ -272,11 +272,11 @@ void ReturnLastValue(MachineType type) {
OptimizedCompilationInfo info(ArrayVector("testing"), handles.main_zone(),
Code::WASM_FUNCTION);
- Handle<Code> code =
- Pipeline::GenerateCodeForTesting(
- &info, handles.main_isolate(), desc, m.graph(),
- AssemblerOptions::Default(handles.main_isolate()), m.Export())
- .ToHandleChecked();
+ Handle<Code> code = Pipeline::GenerateCodeForTesting(
+ &info, handles.main_isolate(), desc, m.graph(),
+ AssemblerOptions::Default(handles.main_isolate()),
+ m.ExportForTest())
+ .ToHandleChecked();
std::shared_ptr<wasm::NativeModule> module = AllocateNativeModule(
handles.main_isolate(), code->raw_instruction_size());
@@ -334,11 +334,11 @@ void ReturnSumOfReturns(MachineType type) {
OptimizedCompilationInfo info(ArrayVector("testing"), handles.main_zone(),
Code::WASM_FUNCTION);
- Handle<Code> code =
- Pipeline::GenerateCodeForTesting(
- &info, handles.main_isolate(), desc, m.graph(),
- AssemblerOptions::Default(handles.main_isolate()), m.Export())
- .ToHandleChecked();
+ Handle<Code> code = Pipeline::GenerateCodeForTesting(
+ &info, handles.main_isolate(), desc, m.graph(),
+ AssemblerOptions::Default(handles.main_isolate()),
+ m.ExportForTest())
+ .ToHandleChecked();
std::shared_ptr<wasm::NativeModule> module = AllocateNativeModule(
handles.main_isolate(), code->raw_instruction_size());
diff --git a/deps/v8/test/cctest/compiler/test-representation-change.cc b/deps/v8/test/cctest/compiler/test-representation-change.cc
index dac6f61932..d858448ef8 100644
--- a/deps/v8/test/cctest/compiler/test-representation-change.cc
+++ b/deps/v8/test/cctest/compiler/test-representation-change.cc
@@ -401,11 +401,11 @@ TEST(Word64) {
CheckChange(
IrOpcode::kCheckedInt64ToInt32, MachineRepresentation::kWord64,
TypeCache::Get()->kSafeInteger, MachineRepresentation::kWord32,
- UseInfo::CheckedSigned32AsWord32(kIdentifyZeros, VectorSlotPair()));
+ UseInfo::CheckedSigned32AsWord32(kIdentifyZeros, FeedbackSource()));
CheckChange(
IrOpcode::kCheckedUint64ToInt32, MachineRepresentation::kWord64,
TypeCache::Get()->kPositiveSafeInteger, MachineRepresentation::kWord32,
- UseInfo::CheckedSigned32AsWord32(kIdentifyZeros, VectorSlotPair()));
+ UseInfo::CheckedSigned32AsWord32(kIdentifyZeros, FeedbackSource()));
CheckChange(IrOpcode::kChangeFloat64ToInt64, MachineRepresentation::kFloat64,
Type::Signed32(), MachineRepresentation::kWord64);
@@ -420,7 +420,7 @@ TEST(Word64) {
CheckChange(
IrOpcode::kCheckedFloat64ToInt64, MachineRepresentation::kFloat64,
Type::Number(), MachineRepresentation::kWord64,
- UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, VectorSlotPair()));
+ UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, FeedbackSource()));
CheckChange(IrOpcode::kChangeInt64ToFloat64, MachineRepresentation::kWord64,
Type::Signed32(), MachineRepresentation::kFloat64);
@@ -449,7 +449,7 @@ TEST(Word64) {
IrOpcode::kChangeFloat32ToFloat64, IrOpcode::kCheckedFloat64ToInt64,
MachineRepresentation::kFloat32, Type::Number(),
MachineRepresentation::kWord64,
- UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, VectorSlotPair()));
+ UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, FeedbackSource()));
CheckTwoChanges(IrOpcode::kChangeInt64ToFloat64,
IrOpcode::kTruncateFloat64ToFloat32,
@@ -470,11 +470,11 @@ TEST(Word64) {
CheckChange(
IrOpcode::kCheckedTaggedToInt64, MachineRepresentation::kTagged,
Type::Number(), MachineRepresentation::kWord64,
- UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, VectorSlotPair()));
+ UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, FeedbackSource()));
CheckChange(
IrOpcode::kCheckedTaggedToInt64, MachineRepresentation::kTaggedPointer,
Type::Number(), MachineRepresentation::kWord64,
- UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, VectorSlotPair()));
+ UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, FeedbackSource()));
CheckTwoChanges(IrOpcode::kTruncateInt64ToInt32,
IrOpcode::kChangeInt31ToTaggedSigned,
@@ -507,12 +507,12 @@ TEST(Word64) {
CheckChange(IrOpcode::kCheckedInt64ToTaggedSigned,
MachineRepresentation::kWord64, TypeCache::Get()->kSafeInteger,
MachineRepresentation::kTaggedSigned,
- UseInfo::CheckedSignedSmallAsTaggedSigned(VectorSlotPair()));
+ UseInfo::CheckedSignedSmallAsTaggedSigned(FeedbackSource()));
CheckChange(IrOpcode::kCheckedUint64ToTaggedSigned,
MachineRepresentation::kWord64,
TypeCache::Get()->kPositiveSafeInteger,
MachineRepresentation::kTaggedSigned,
- UseInfo::CheckedSignedSmallAsTaggedSigned(VectorSlotPair()));
+ UseInfo::CheckedSignedSmallAsTaggedSigned(FeedbackSource()));
CheckTwoChanges(
IrOpcode::kChangeInt64ToFloat64, IrOpcode::kChangeFloat64ToTaggedPointer,
@@ -630,7 +630,7 @@ TEST(SignednessInWord32) {
CheckChange(IrOpcode::kCheckedTruncateTaggedToWord32,
MachineRepresentation::kTagged, Type::NonInternal(),
MachineRepresentation::kWord32,
- UseInfo::CheckedNumberOrOddballAsWord32(VectorSlotPair()));
+ UseInfo::CheckedNumberOrOddballAsWord32(FeedbackSource()));
CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
IrOpcode::kTruncateFloat64ToFloat32,
@@ -644,7 +644,7 @@ TEST(SignednessInWord32) {
CheckChange(
IrOpcode::kCheckedUint32ToInt32, MachineRepresentation::kWord32,
Type::Unsigned32(),
- UseInfo::CheckedSigned32AsWord32(kIdentifyZeros, VectorSlotPair()));
+ UseInfo::CheckedSigned32AsWord32(kIdentifyZeros, FeedbackSource()));
}
TEST(CompressedAndTagged) {
@@ -698,19 +698,19 @@ static void TestMinusZeroCheck(IrOpcode::Value expected, Type from_type) {
CheckChange(
expected, MachineRepresentation::kFloat64, from_type,
- UseInfo::CheckedSignedSmallAsWord32(kDistinguishZeros, VectorSlotPair()));
+ UseInfo::CheckedSignedSmallAsWord32(kDistinguishZeros, FeedbackSource()));
CheckChange(
expected, MachineRepresentation::kFloat64, from_type,
- UseInfo::CheckedSignedSmallAsWord32(kIdentifyZeros, VectorSlotPair()));
+ UseInfo::CheckedSignedSmallAsWord32(kIdentifyZeros, FeedbackSource()));
CheckChange(
expected, MachineRepresentation::kFloat64, from_type,
- UseInfo::CheckedSigned32AsWord32(kDistinguishZeros, VectorSlotPair()));
+ UseInfo::CheckedSigned32AsWord32(kDistinguishZeros, FeedbackSource()));
CheckChange(
expected, MachineRepresentation::kFloat64, from_type,
- UseInfo::CheckedSigned32AsWord32(kDistinguishZeros, VectorSlotPair()));
+ UseInfo::CheckedSigned32AsWord32(kDistinguishZeros, FeedbackSource()));
}
TEST(MinusZeroCheck) {
diff --git a/deps/v8/test/cctest/compiler/test-run-native-calls.cc b/deps/v8/test/cctest/compiler/test-run-native-calls.cc
index eed6cf1e59..026e8307ae 100644
--- a/deps/v8/test/cctest/compiler/test-run-native-calls.cc
+++ b/deps/v8/test/cctest/compiler/test-run-native-calls.cc
@@ -439,7 +439,7 @@ class Computer {
Graph graph(&zone);
RawMachineAssembler raw(isolate, &graph, desc);
build(desc, raw);
- inner = CompileGraph("Compute", desc, &graph, raw.Export());
+ inner = CompileGraph("Compute", desc, &graph, raw.ExportForTest());
}
CSignatureOf<int32_t> csig;
@@ -466,8 +466,8 @@ class Computer {
Node* store = io.StoreOutput(raw, call);
USE(store);
raw.Return(raw.Int32Constant(seed));
- wrapper =
- CompileGraph("Compute-wrapper-const", cdesc, &graph, raw.Export());
+ wrapper = CompileGraph("Compute-wrapper-const", cdesc, &graph,
+ raw.ExportForTest());
}
CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
@@ -501,7 +501,8 @@ class Computer {
Node* store = io.StoreOutput(raw, call);
USE(store);
raw.Return(raw.Int32Constant(seed));
- wrapper = CompileGraph("Compute-wrapper", cdesc, &graph, raw.Export());
+ wrapper =
+ CompileGraph("Compute-wrapper", cdesc, &graph, raw.ExportForTest());
}
CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
@@ -576,7 +577,7 @@ static void CopyTwentyInt32(CallDescriptor* desc) {
kNoWriteBarrier);
}
raw.Return(raw.Int32Constant(42));
- inner = CompileGraph("CopyTwentyInt32", desc, &graph, raw.Export());
+ inner = CompileGraph("CopyTwentyInt32", desc, &graph, raw.ExportForTest());
}
CSignatureOf<int32_t> csig;
@@ -599,8 +600,8 @@ static void CopyTwentyInt32(CallDescriptor* desc) {
Node* call = raw.CallN(desc, input_count, inputs);
raw.Return(call);
- wrapper =
- CompileGraph("CopyTwentyInt32-wrapper", cdesc, &graph, raw.Export());
+ wrapper = CompileGraph("CopyTwentyInt32-wrapper", cdesc, &graph,
+ raw.ExportForTest());
}
CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
@@ -962,7 +963,8 @@ static void Build_Select_With_Call(
Graph graph(&zone);
RawMachineAssembler raw(isolate, &graph, desc);
raw.Return(raw.Parameter(which));
- inner = CompileGraph("Select-indirection", desc, &graph, raw.Export());
+ inner =
+ CompileGraph("Select-indirection", desc, &graph, raw.ExportForTest());
CHECK(!inner.is_null());
CHECK(inner->IsCode());
}
@@ -1058,7 +1060,7 @@ void MixedParamTest(int start) {
Graph graph(&zone);
RawMachineAssembler raw(isolate, &graph, desc);
raw.Return(raw.Parameter(which));
- select = CompileGraph("Compute", desc, &graph, raw.Export());
+ select = CompileGraph("Compute", desc, &graph, raw.ExportForTest());
}
{
@@ -1117,7 +1119,7 @@ void MixedParamTest(int start) {
expected_ret = static_cast<int32_t>(constant);
raw.Return(raw.Int32Constant(expected_ret));
wrapper = CompileGraph("Select-mixed-wrapper-const", cdesc, &graph,
- raw.Export());
+ raw.ExportForTest());
}
CodeRunner<int32_t> runnable(isolate, wrapper, &csig);
@@ -1176,7 +1178,7 @@ void TestStackSlot(MachineType slot_type, T expected) {
g.Store(slot_type.representation(), g.Parameter(11), g.Parameter(10),
WriteBarrierKind::kNoWriteBarrier);
g.Return(g.Parameter(9));
- inner = CompileGraph("Compute", desc, &graph, g.Export());
+ inner = CompileGraph("Compute", desc, &graph, g.ExportForTest());
// Create function f with a stack slot which calls the inner function g.
BufferedRawMachineAssemblerTester<T> f(slot_type);
diff --git a/deps/v8/test/cctest/compiler/test-run-retpoline.cc b/deps/v8/test/cctest/compiler/test-run-retpoline.cc
index be329e1b00..32569eaaee 100644
--- a/deps/v8/test/cctest/compiler/test-run-retpoline.cc
+++ b/deps/v8/test/cctest/compiler/test-run-retpoline.cc
@@ -27,7 +27,8 @@ Handle<Code> BuildCallee(Isolate* isolate, CallDescriptor* call_descriptor) {
int param_count = static_cast<int>(call_descriptor->StackParameterCount());
Node* sum = __ IntPtrConstant(0);
for (int i = 0; i < param_count; ++i) {
- Node* product = __ IntPtrMul(__ Parameter(i), __ IntPtrConstant(i + 1));
+ TNode<IntPtrT> product =
+ __ Signed(__ IntPtrMul(__ Parameter(i), __ IntPtrConstant(i + 1)));
sum = __ IntPtrAdd(sum, product);
}
__ Return(sum);
diff --git a/deps/v8/test/cctest/compiler/test-run-tail-calls.cc b/deps/v8/test/cctest/compiler/test-run-tail-calls.cc
index 1562befb9d..ed8a099090 100644
--- a/deps/v8/test/cctest/compiler/test-run-tail-calls.cc
+++ b/deps/v8/test/cctest/compiler/test-run-tail-calls.cc
@@ -28,8 +28,9 @@ Handle<Code> BuildCallee(Isolate* isolate, CallDescriptor* call_descriptor) {
int param_count = static_cast<int>(call_descriptor->StackParameterCount());
Node* sum = __ IntPtrConstant(0);
for (int i = 0; i < param_count; ++i) {
- Node* product = __ IntPtrMul(__ Parameter(i), __ IntPtrConstant(i + 1));
- sum = __ IntPtrAdd(sum, product);
+ TNode<WordT> product =
+ __ IntPtrMul(__ Parameter(i), __ IntPtrConstant(i + 1));
+ sum = __ Signed(__ IntPtrAdd(sum, product));
}
__ Return(sum);
return tester.GenerateCodeCloseAndEscape();
diff --git a/deps/v8/test/cctest/heap/heap-tester.h b/deps/v8/test/cctest/heap/heap-tester.h
index 14a4eb3cd9..6f6cfb46b5 100644
--- a/deps/v8/test/cctest/heap/heap-tester.h
+++ b/deps/v8/test/cctest/heap/heap-tester.h
@@ -19,6 +19,10 @@
V(CompactionSpaceDivideSinglePage) \
V(InvalidatedSlotsAfterTrimming) \
V(InvalidatedSlotsAllInvalidatedRanges) \
+ V(InvalidatedSlotsCleanupEachObject) \
+ V(InvalidatedSlotsCleanupFull) \
+ V(InvalidatedSlotsCleanupRightTrim) \
+ V(InvalidatedSlotsCleanupOverlapRight) \
V(InvalidatedSlotsEvacuationCandidate) \
V(InvalidatedSlotsNoInvalidatedRanges) \
V(InvalidatedSlotsResetObjectRegression) \
diff --git a/deps/v8/test/cctest/heap/test-embedder-tracing.cc b/deps/v8/test/cctest/heap/test-embedder-tracing.cc
index 2d0833e1a3..28553266ff 100644
--- a/deps/v8/test/cctest/heap/test-embedder-tracing.cc
+++ b/deps/v8/test/cctest/heap/test-embedder-tracing.cc
@@ -16,6 +16,13 @@
#include "test/cctest/heap/heap-utils.h"
namespace v8 {
+
+// See test below: TracedGlobalNoDestructor.
+template <>
+struct TracedGlobalTrait<v8::TracedGlobal<v8::Value>> {
+ static constexpr bool kRequiresExplicitDestruction = false;
+};
+
namespace internal {
namespace heap {
@@ -346,6 +353,85 @@ TEST(TracedGlobalInStdVector) {
CHECK(vec[0].IsEmpty());
}
+TEST(TracedGlobalCopyWithDestructor) {
+ ManualGCScope manual_gc;
+ CcTest::InitializeVM();
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
+
+ static_assert(TracedGlobalTrait<
+ v8::TracedGlobal<v8::Object>>::kRequiresExplicitDestruction,
+ "destructor expected");
+
+ const size_t initial_count = global_handles->handles_count();
+ v8::TracedGlobal<v8::Object> global1;
+ {
+ v8::HandleScope scope(isolate);
+ global1.Reset(isolate, v8::Object::New(isolate));
+ }
+ v8::TracedGlobal<v8::Object> global2(global1);
+ v8::TracedGlobal<v8::Object> global3;
+ global3 = global2;
+ CHECK_EQ(initial_count + 3, global_handles->handles_count());
+ CHECK(!global1.IsEmpty());
+ CHECK_EQ(global1, global2);
+ CHECK_EQ(global2, global3);
+ {
+ v8::HandleScope scope(isolate);
+ auto tmp = v8::Local<v8::Object>::New(isolate, global3);
+ CHECK(!tmp.IsEmpty());
+ InvokeMarkSweep();
+ }
+ CHECK_EQ(initial_count + 3, global_handles->handles_count());
+ CHECK(!global1.IsEmpty());
+ CHECK_EQ(global1, global2);
+ CHECK_EQ(global2, global3);
+ InvokeMarkSweep();
+ CHECK_EQ(initial_count, global_handles->handles_count());
+ CHECK(global1.IsEmpty());
+ CHECK_EQ(global1, global2);
+ CHECK_EQ(global2, global3);
+}
+
+TEST(TracedGlobalCopyNoDestructor) {
+ ManualGCScope manual_gc;
+ CcTest::InitializeVM();
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
+
+ static_assert(!TracedGlobalTrait<
+ v8::TracedGlobal<v8::Value>>::kRequiresExplicitDestruction,
+ "no destructor expected");
+
+ const size_t initial_count = global_handles->handles_count();
+ v8::TracedGlobal<v8::Value> global1;
+ {
+ v8::HandleScope scope(isolate);
+ global1.Reset(isolate, v8::Object::New(isolate));
+ }
+ v8::TracedGlobal<v8::Value> global2(global1);
+ v8::TracedGlobal<v8::Value> global3;
+ global3 = global2;
+ CHECK_EQ(initial_count + 3, global_handles->handles_count());
+ CHECK(!global1.IsEmpty());
+ CHECK_EQ(global1, global2);
+ CHECK_EQ(global2, global3);
+ {
+ v8::HandleScope scope(isolate);
+ auto tmp = v8::Local<v8::Value>::New(isolate, global3);
+ CHECK(!tmp.IsEmpty());
+ InvokeMarkSweep();
+ }
+ CHECK_EQ(initial_count + 3, global_handles->handles_count());
+ CHECK(!global1.IsEmpty());
+ CHECK_EQ(global1, global2);
+ CHECK_EQ(global2, global3);
+ InvokeMarkSweep();
+ CHECK_EQ(initial_count, global_handles->handles_count());
+}
+
TEST(TracedGlobalInStdUnorderedMap) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
@@ -560,6 +646,218 @@ TEST(TracePrologueCallingIntoV8WriteBarrier) {
std::move(global));
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
SimulateIncrementalMarking(CcTest::i_isolate()->heap());
+ // Finish GC to avoid removing the tracer while GC is running which may end up
+ // in an infinite loop because of unprocessed objects.
+ heap::InvokeMarkSweep();
+}
+
+TEST(TracedGlobalWithDestructor) {
+ ManualGCScope manual_gc;
+ CcTest::InitializeVM();
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ TestEmbedderHeapTracer tracer;
+ heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
+ i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
+
+ const size_t initial_count = global_handles->handles_count();
+ auto* traced = new v8::TracedGlobal<v8::Object>();
+ {
+ v8::HandleScope scope(isolate);
+ v8::Local<v8::Object> object(ConstructTraceableJSApiObject(
+ isolate->GetCurrentContext(), nullptr, nullptr));
+ CHECK(traced->IsEmpty());
+ *traced = v8::TracedGlobal<v8::Object>(isolate, object);
+ CHECK(!traced->IsEmpty());
+ CHECK_EQ(initial_count + 1, global_handles->handles_count());
+ }
+ static_assert(TracedGlobalTrait<
+ v8::TracedGlobal<v8::Object>>::kRequiresExplicitDestruction,
+ "destructor expected");
+ delete traced;
+ CHECK_EQ(initial_count, global_handles->handles_count());
+ // GC should not need to clear the handle.
+ heap::InvokeMarkSweep();
+ CHECK_EQ(initial_count, global_handles->handles_count());
+}
+
+TEST(TracedGlobalNoDestructor) {
+ ManualGCScope manual_gc;
+ CcTest::InitializeVM();
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ TestEmbedderHeapTracer tracer;
+ heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
+ i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
+
+ const size_t initial_count = global_handles->handles_count();
+ char* memory = new char[sizeof(v8::TracedGlobal<v8::Value>)];
+ auto* traced = new (memory) v8::TracedGlobal<v8::Value>();
+ {
+ v8::HandleScope scope(isolate);
+ v8::Local<v8::Value> object(ConstructTraceableJSApiObject(
+ isolate->GetCurrentContext(), nullptr, nullptr));
+ CHECK(traced->IsEmpty());
+ *traced = v8::TracedGlobal<v8::Value>(isolate, object);
+ CHECK(!traced->IsEmpty());
+ CHECK_EQ(initial_count + 1, global_handles->handles_count());
+ }
+ static_assert(!TracedGlobalTrait<
+ v8::TracedGlobal<v8::Value>>::kRequiresExplicitDestruction,
+ "no destructor expected");
+ traced->~TracedGlobal<v8::Value>();
+ CHECK_EQ(initial_count + 1, global_handles->handles_count());
+ // GC should clear the handle.
+ heap::InvokeMarkSweep();
+ CHECK_EQ(initial_count, global_handles->handles_count());
+ delete[] memory;
+}
+
+namespace {
+
+class EmptyEmbedderHeapTracer : public v8::EmbedderHeapTracer {
+ public:
+ void RegisterV8References(
+ const std::vector<std::pair<void*, void*>>& embedder_fields) final {}
+
+ bool AdvanceTracing(double deadline_in_ms) final { return true; }
+ bool IsTracingDone() final { return true; }
+ void TracePrologue(EmbedderHeapTracer::TraceFlags) final {}
+ void TraceEpilogue() final {}
+ void EnterFinalPause(EmbedderStackState) final {}
+};
+
+// EmbedderHeapTracer that can optimize Scavenger handling when used with
+// TraceGlobal handles that have destructors.
+class EmbedderHeapTracerDestructorNonTracingClearing final
+ : public EmptyEmbedderHeapTracer {
+ public:
+ explicit EmbedderHeapTracerDestructorNonTracingClearing(
+ uint16_t class_id_to_optimize)
+ : class_id_to_optimize_(class_id_to_optimize) {}
+
+ bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) final {
+ return handle.WrapperClassId() != class_id_to_optimize_;
+ }
+
+ void ResetHandleInNonTracingGC(
+ const v8::TracedGlobal<v8::Value>& handle) final {
+ // Not called when used with handles that have destructors.
+ CHECK(false);
+ }
+
+ private:
+ uint16_t class_id_to_optimize_;
+};
+
+// EmbedderHeapTracer that can optimize Scavenger handling when used with
+// TraceGlobal handles without destructors.
+class EmbedderHeapTracerNoDestructorNonTracingClearing final
+ : public EmptyEmbedderHeapTracer {
+ public:
+ explicit EmbedderHeapTracerNoDestructorNonTracingClearing(
+ uint16_t class_id_to_optimize)
+ : class_id_to_optimize_(class_id_to_optimize) {}
+
+ bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) final {
+ return handle.WrapperClassId() != class_id_to_optimize_;
+ }
+
+ void ResetHandleInNonTracingGC(
+ const v8::TracedGlobal<v8::Value>& handle) final {
+ if (handle.WrapperClassId() != class_id_to_optimize_) return;
+
+ // Convention (for test): Objects that are optimized have their first field
+ // set as a back pointer.
+ TracedGlobal<v8::Value>* original_handle =
+ reinterpret_cast<TracedGlobal<v8::Value>*>(
+ v8::Object::GetAlignedPointerFromInternalField(
+ handle.As<v8::Object>(), 0));
+ original_handle->Reset();
+ }
+
+ private:
+ uint16_t class_id_to_optimize_;
+};
+
+template <typename T>
+void SetupOptimizedAndNonOptimizedHandle(
+ v8::Isolate* isolate, uint16_t optimized_class_id,
+ v8::TracedGlobal<T>* optimized_handle,
+ v8::TracedGlobal<T>* non_optimized_handle) {
+ v8::HandleScope scope(isolate);
+
+ v8::Local<v8::Object> optimized_object(ConstructTraceableJSApiObject(
+ isolate->GetCurrentContext(), optimized_handle, nullptr));
+ CHECK(optimized_handle->IsEmpty());
+ *optimized_handle = v8::TracedGlobal<T>(isolate, optimized_object);
+ CHECK(!optimized_handle->IsEmpty());
+ optimized_handle->SetWrapperClassId(optimized_class_id);
+
+ v8::Local<v8::Object> non_optimized_object(ConstructTraceableJSApiObject(
+ isolate->GetCurrentContext(), nullptr, nullptr));
+ CHECK(non_optimized_handle->IsEmpty());
+ *non_optimized_handle = v8::TracedGlobal<T>(isolate, non_optimized_object);
+ CHECK(!non_optimized_handle->IsEmpty());
+}
+
+} // namespace
+
+TEST(TracedGlobalDestructorReclaimedOnScavenge) {
+ ManualGCScope manual_gc;
+ CcTest::InitializeVM();
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ constexpr uint16_t kClassIdToOptimize = 17;
+ EmbedderHeapTracerDestructorNonTracingClearing tracer(kClassIdToOptimize);
+ heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
+ i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
+
+ static_assert(TracedGlobalTrait<
+ v8::TracedGlobal<v8::Object>>::kRequiresExplicitDestruction,
+ "destructor expected");
+ const size_t initial_count = global_handles->handles_count();
+ auto* optimized_handle = new v8::TracedGlobal<v8::Object>();
+ auto* non_optimized_handle = new v8::TracedGlobal<v8::Object>();
+ SetupOptimizedAndNonOptimizedHandle(isolate, kClassIdToOptimize,
+ optimized_handle, non_optimized_handle);
+ CHECK_EQ(initial_count + 2, global_handles->handles_count());
+ heap::InvokeScavenge();
+ CHECK_EQ(initial_count + 1, global_handles->handles_count());
+ CHECK(optimized_handle->IsEmpty());
+ delete optimized_handle;
+ CHECK(!non_optimized_handle->IsEmpty());
+ delete non_optimized_handle;
+ CHECK_EQ(initial_count, global_handles->handles_count());
+}
+
+TEST(TracedGlobalNoDestructorReclaimedOnScavenge) {
+ ManualGCScope manual_gc;
+ CcTest::InitializeVM();
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ constexpr uint16_t kClassIdToOptimize = 23;
+ EmbedderHeapTracerNoDestructorNonTracingClearing tracer(kClassIdToOptimize);
+ heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
+ i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
+
+ static_assert(!TracedGlobalTrait<
+ v8::TracedGlobal<v8::Value>>::kRequiresExplicitDestruction,
+ "no destructor expected");
+ const size_t initial_count = global_handles->handles_count();
+ auto* optimized_handle = new v8::TracedGlobal<v8::Value>();
+ auto* non_optimized_handle = new v8::TracedGlobal<v8::Value>();
+ SetupOptimizedAndNonOptimizedHandle(isolate, kClassIdToOptimize,
+ optimized_handle, non_optimized_handle);
+ CHECK_EQ(initial_count + 2, global_handles->handles_count());
+ heap::InvokeScavenge();
+ CHECK_EQ(initial_count + 1, global_handles->handles_count());
+ CHECK(optimized_handle->IsEmpty());
+ delete optimized_handle;
+ CHECK(!non_optimized_handle->IsEmpty());
+ non_optimized_handle->Reset();
+ delete non_optimized_handle;
+ CHECK_EQ(initial_count, global_handles->handles_count());
}
} // namespace heap
diff --git a/deps/v8/test/cctest/heap/test-heap.cc b/deps/v8/test/cctest/heap/test-heap.cc
index e4dbee2210..fd17c0f063 100644
--- a/deps/v8/test/cctest/heap/test-heap.cc
+++ b/deps/v8/test/cctest/heap/test-heap.cc
@@ -1799,36 +1799,6 @@ TEST(HeapNumberAlignment) {
}
}
-TEST(MutableHeapNumberAlignment) {
- CcTest::InitializeVM();
- Isolate* isolate = CcTest::i_isolate();
- Factory* factory = isolate->factory();
- Heap* heap = isolate->heap();
- HandleScope sc(isolate);
-
- const auto required_alignment =
- HeapObject::RequiredAlignment(*factory->mutable_heap_number_map());
- const int maximum_misalignment =
- Heap::GetMaximumFillToAlign(required_alignment);
-
- for (int offset = 0; offset <= maximum_misalignment; offset += kTaggedSize) {
- AlignNewSpace(required_alignment, offset);
- Handle<Object> number_new = factory->NewMutableHeapNumber(1.000123);
- CHECK(number_new->IsMutableHeapNumber());
- CHECK(Heap::InYoungGeneration(*number_new));
- CHECK_EQ(0, Heap::GetFillToAlign(HeapObject::cast(*number_new).address(),
- required_alignment));
-
- AlignOldSpace(required_alignment, offset);
- Handle<Object> number_old =
- factory->NewMutableHeapNumber(1.000321, AllocationType::kOld);
- CHECK(number_old->IsMutableHeapNumber());
- CHECK(heap->InOldSpace(*number_old));
- CHECK_EQ(0, Heap::GetFillToAlign(HeapObject::cast(*number_old).address(),
- required_alignment));
- }
-}
-
TEST(TestSizeOfObjectsVsHeapObjectIteratorPrecision) {
CcTest::InitializeVM();
HeapObjectIterator iterator(CcTest::heap());
diff --git a/deps/v8/test/cctest/heap/test-invalidated-slots.cc b/deps/v8/test/cctest/heap/test-invalidated-slots.cc
index c88cf1f3ba..af42503f86 100644
--- a/deps/v8/test/cctest/heap/test-invalidated-slots.cc
+++ b/deps/v8/test/cctest/heap/test-invalidated-slots.cc
@@ -44,7 +44,7 @@ Page* HeapTester::AllocateByteArraysOnPage(
CHECK_EQ(page, Page::FromHeapObject(byte_array));
}
}
- CHECK_NULL(page->invalidated_slots());
+ CHECK_NULL(page->invalidated_slots<OLD_TO_OLD>());
return page;
}
@@ -53,7 +53,7 @@ HEAP_TEST(InvalidatedSlotsNoInvalidatedRanges) {
Heap* heap = CcTest::heap();
std::vector<ByteArray> byte_arrays;
Page* page = AllocateByteArraysOnPage(heap, &byte_arrays);
- InvalidatedSlotsFilter filter(page);
+ InvalidatedSlotsFilter filter = InvalidatedSlotsFilter::OldToOld(page);
for (ByteArray byte_array : byte_arrays) {
Address start = byte_array.address() + ByteArray::kHeaderSize;
Address end = byte_array.address() + byte_array.Size();
@@ -70,10 +70,10 @@ HEAP_TEST(InvalidatedSlotsSomeInvalidatedRanges) {
Page* page = AllocateByteArraysOnPage(heap, &byte_arrays);
// Register every second byte arrays as invalidated.
for (size_t i = 0; i < byte_arrays.size(); i += 2) {
- page->RegisterObjectWithInvalidatedSlots(byte_arrays[i],
- byte_arrays[i].Size());
+ page->RegisterObjectWithInvalidatedSlots<OLD_TO_OLD>(byte_arrays[i],
+ byte_arrays[i].Size());
}
- InvalidatedSlotsFilter filter(page);
+ InvalidatedSlotsFilter filter = InvalidatedSlotsFilter::OldToOld(page);
for (size_t i = 0; i < byte_arrays.size(); i++) {
ByteArray byte_array = byte_arrays[i];
Address start = byte_array.address() + ByteArray::kHeaderSize;
@@ -95,10 +95,10 @@ HEAP_TEST(InvalidatedSlotsAllInvalidatedRanges) {
Page* page = AllocateByteArraysOnPage(heap, &byte_arrays);
// Register the all byte arrays as invalidated.
for (size_t i = 0; i < byte_arrays.size(); i++) {
- page->RegisterObjectWithInvalidatedSlots(byte_arrays[i],
- byte_arrays[i].Size());
+ page->RegisterObjectWithInvalidatedSlots<OLD_TO_OLD>(byte_arrays[i],
+ byte_arrays[i].Size());
}
- InvalidatedSlotsFilter filter(page);
+ InvalidatedSlotsFilter filter = InvalidatedSlotsFilter::OldToOld(page);
for (size_t i = 0; i < byte_arrays.size(); i++) {
ByteArray byte_array = byte_arrays[i];
Address start = byte_array.address() + ByteArray::kHeaderSize;
@@ -117,12 +117,12 @@ HEAP_TEST(InvalidatedSlotsAfterTrimming) {
Page* page = AllocateByteArraysOnPage(heap, &byte_arrays);
// Register the all byte arrays as invalidated.
for (size_t i = 0; i < byte_arrays.size(); i++) {
- page->RegisterObjectWithInvalidatedSlots(byte_arrays[i],
- byte_arrays[i].Size());
+ page->RegisterObjectWithInvalidatedSlots<OLD_TO_OLD>(byte_arrays[i],
+ byte_arrays[i].Size());
}
// Trim byte arrays and check that the slots outside the byte arrays are
// considered invalid if the old space page was swept.
- InvalidatedSlotsFilter filter(page);
+ InvalidatedSlotsFilter filter = InvalidatedSlotsFilter::OldToOld(page);
for (size_t i = 0; i < byte_arrays.size(); i++) {
ByteArray byte_array = byte_arrays[i];
Address start = byte_array.address() + ByteArray::kHeaderSize;
@@ -145,11 +145,11 @@ HEAP_TEST(InvalidatedSlotsEvacuationCandidate) {
// This should be no-op because the page is marked as evacuation
// candidate.
for (size_t i = 0; i < byte_arrays.size(); i++) {
- page->RegisterObjectWithInvalidatedSlots(byte_arrays[i],
- byte_arrays[i].Size());
+ page->RegisterObjectWithInvalidatedSlots<OLD_TO_OLD>(byte_arrays[i],
+ byte_arrays[i].Size());
}
// All slots must still be valid.
- InvalidatedSlotsFilter filter(page);
+ InvalidatedSlotsFilter filter = InvalidatedSlotsFilter::OldToOld(page);
for (size_t i = 0; i < byte_arrays.size(); i++) {
ByteArray byte_array = byte_arrays[i];
Address start = byte_array.address() + ByteArray::kHeaderSize;
@@ -169,11 +169,11 @@ HEAP_TEST(InvalidatedSlotsResetObjectRegression) {
heap->RightTrimFixedArray(byte_arrays[0], byte_arrays[0].length() - 8);
// Register the all byte arrays as invalidated.
for (size_t i = 0; i < byte_arrays.size(); i++) {
- page->RegisterObjectWithInvalidatedSlots(byte_arrays[i],
- byte_arrays[i].Size());
+ page->RegisterObjectWithInvalidatedSlots<OLD_TO_OLD>(byte_arrays[i],
+ byte_arrays[i].Size());
}
// All slots must still be invalid.
- InvalidatedSlotsFilter filter(page);
+ InvalidatedSlotsFilter filter = InvalidatedSlotsFilter::OldToOld(page);
for (size_t i = 0; i < byte_arrays.size(); i++) {
ByteArray byte_array = byte_arrays[i];
Address start = byte_array.address() + ByteArray::kHeaderSize;
@@ -351,6 +351,78 @@ HEAP_TEST(InvalidatedSlotsFastToSlow) {
CcTest::CollectGarbage(i::OLD_SPACE);
}
+HEAP_TEST(InvalidatedSlotsCleanupFull) {
+ ManualGCScope manual_gc_scope;
+ CcTest::InitializeVM();
+ Heap* heap = CcTest::heap();
+ std::vector<ByteArray> byte_arrays;
+ Page* page = AllocateByteArraysOnPage(heap, &byte_arrays);
+ // Register all byte arrays as invalidated.
+ for (size_t i = 0; i < byte_arrays.size(); i++) {
+ page->RegisterObjectWithInvalidatedSlots<OLD_TO_NEW>(byte_arrays[i],
+ byte_arrays[i].Size());
+ }
+
+ // Mark full page as free
+ InvalidatedSlotsCleanup cleanup = InvalidatedSlotsCleanup::OldToNew(page);
+ cleanup.Free(page->area_start(), page->area_end());
+
+ // After cleanup there should be no invalidated objects on page left
+ CHECK(page->invalidated_slots<OLD_TO_NEW>()->empty());
+}
+
+HEAP_TEST(InvalidatedSlotsCleanupEachObject) {
+ ManualGCScope manual_gc_scope;
+ CcTest::InitializeVM();
+ Heap* heap = CcTest::heap();
+ std::vector<ByteArray> byte_arrays;
+ Page* page = AllocateByteArraysOnPage(heap, &byte_arrays);
+ // Register all byte arrays as invalidated.
+ for (size_t i = 0; i < byte_arrays.size(); i++) {
+ page->RegisterObjectWithInvalidatedSlots<OLD_TO_NEW>(byte_arrays[i],
+ byte_arrays[i].Size());
+ }
+
+ // Mark each object as free on page
+ InvalidatedSlotsCleanup cleanup = InvalidatedSlotsCleanup::OldToNew(page);
+
+ for (size_t i = 0; i < byte_arrays.size(); i++) {
+ Address free_start = byte_arrays[i].address();
+ Address free_end = free_start + byte_arrays[i].Size();
+ cleanup.Free(free_start, free_end);
+ }
+
+ // After cleanup there should be no invalidated objects on page left
+ CHECK(page->invalidated_slots<OLD_TO_NEW>()->empty());
+}
+
+HEAP_TEST(InvalidatedSlotsCleanupRightTrim) {
+ ManualGCScope manual_gc_scope;
+ CcTest::InitializeVM();
+ Heap* heap = CcTest::heap();
+ std::vector<ByteArray> byte_arrays;
+ Page* page = AllocateByteArraysOnPage(heap, &byte_arrays);
+
+ CHECK_GT(byte_arrays.size(), 1);
+ ByteArray& invalidated = byte_arrays[1];
+ int invalidated_size = invalidated.Size();
+
+ heap->RightTrimFixedArray(invalidated, invalidated.length() - 8);
+ page->RegisterObjectWithInvalidatedSlots<OLD_TO_NEW>(invalidated,
+ invalidated_size);
+
+ // Free memory at end of invalidated object
+ InvalidatedSlotsCleanup cleanup = InvalidatedSlotsCleanup::OldToNew(page);
+ Address free_start = invalidated.address() + invalidated.Size();
+ cleanup.Free(free_start, page->area_end());
+
+ // After cleanup the invalidated object should be smaller
+ InvalidatedSlots* invalidated_slots = page->invalidated_slots<OLD_TO_NEW>();
+ CHECK_GE((*invalidated_slots)[HeapObject::FromAddress(invalidated.address())],
+ invalidated.Size());
+ CHECK_EQ(invalidated_slots->size(), 1);
+}
+
} // namespace heap
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/ArrayLiterals.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/ArrayLiterals.golden
index 9392d60181..d6097e938d 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/ArrayLiterals.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/ArrayLiterals.golden
@@ -141,9 +141,9 @@ handlers: [
snippet: "
var a = [ 1, 2 ]; return [ 0, ...a ];
"
-frame size: 8
+frame size: 7
parameter count: 1
-bytecode array length: 84
+bytecode array length: 80
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
@@ -152,22 +152,21 @@ bytecodes: [
B(Star), R(2),
B(LdaConstant), U8(2),
/* 67 S> */ B(Star), R(1),
- B(LdaNamedProperty), R(0), U8(3), U8(2),
+ B(GetIterator), R(0), U8(2),
B(Star), R(6),
B(CallProperty0), R(6), R(0), U8(4),
- B(Mov), R(0), R(5),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(4),
- B(LdaNamedProperty), R(4), U8(4), U8(6),
+ B(LdaNamedProperty), R(4), U8(3), U8(6),
B(Star), R(3),
B(CallProperty0), R(3), R(4), U8(15),
- B(Star), R(7),
+ B(Star), R(5),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(7), U8(1),
- B(LdaNamedProperty), R(7), U8(5), U8(17),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(5), U8(1),
+ B(LdaNamedProperty), R(5), U8(4), U8(17),
B(JumpIfToBooleanTrue), U8(19),
- B(LdaNamedProperty), R(7), U8(6), U8(8),
+ B(LdaNamedProperty), R(5), U8(5), U8(8),
B(StaInArrayLiteral), R(2), R(1), U8(13),
B(Ldar), R(1),
B(Inc), U8(12),
@@ -180,7 +179,6 @@ constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
Smi [1],
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden
index ce579699d8..1dbb999371 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden
@@ -212,9 +212,9 @@ snippet: "
async function* f() { for (let x of [42]) yield x }
f();
"
-frame size: 21
+frame size: 19
parameter count: 1
-bytecode array length: 372
+bytecode array length: 369
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(2),
B(Mov), R(closure), R(4),
@@ -235,103 +235,102 @@ bytecodes: [
B(LdaSmi), I8(1),
B(Star), R(4),
B(Mov), R(8), R(5),
- B(JumpConstant), U8(16),
+ B(JumpConstant), U8(15),
/* 36 S> */ B(CreateArrayLiteral), U8(4), U8(0), U8(37),
B(Star), R(10),
- B(LdaNamedProperty), R(10), U8(5), U8(1),
+ B(GetIterator), R(10), U8(1),
B(Star), R(11),
B(CallProperty0), R(11), R(10), U8(3),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(9),
- B(LdaNamedProperty), R(9), U8(6), U8(5),
+ B(LdaNamedProperty), R(9), U8(5), U8(5),
B(Star), R(8),
B(LdaFalse),
- B(Star), R(12),
- B(Mov), R(context), R(15),
+ B(Star), R(10),
+ B(Mov), R(context), R(13),
B(LdaTrue),
- B(Star), R(12),
+ B(Star), R(10),
/* 31 S> */ B(CallProperty0), R(8), R(9), U8(7),
- B(Star), R(16),
+ B(Star), R(14),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(16), U8(1),
- B(LdaNamedProperty), R(16), U8(7), U8(9),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
+ B(LdaNamedProperty), R(14), U8(6), U8(9),
B(JumpIfToBooleanTrue), U8(67),
- B(LdaNamedProperty), R(16), U8(8), U8(11),
- B(Star), R(16),
+ B(LdaNamedProperty), R(14), U8(7), U8(11),
+ B(Star), R(14),
B(LdaFalse),
- B(Star), R(12),
- B(Mov), R(16), R(1),
+ B(Star), R(10),
+ B(Mov), R(14), R(1),
/* 22 E> */ B(StackCheck),
/* 31 S> */ B(Mov), R(1), R(3),
/* 42 S> */ B(LdaFalse),
- B(Star), R(19),
- B(Mov), R(0), R(17),
- B(Mov), R(3), R(18),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorYield), R(17), U8(3),
- /* 42 E> */ B(SuspendGenerator), R(0), R(0), U8(17), U8(1),
- B(ResumeGenerator), R(0), R(0), U8(17),
B(Star), R(17),
+ B(Mov), R(0), R(15),
+ B(Mov), R(3), R(16),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorYield), R(15), U8(3),
+ /* 42 E> */ B(SuspendGenerator), R(0), R(0), U8(15), U8(1),
+ B(ResumeGenerator), R(0), R(0), U8(15),
+ B(Star), R(15),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(SwitchOnSmiNoFeedback), U8(9), U8(2), I8(0),
- B(Ldar), R(17),
+ B(SwitchOnSmiNoFeedback), U8(8), U8(2), I8(0),
+ B(Ldar), R(15),
/* 42 E> */ B(Throw),
B(LdaSmi), I8(1),
- B(Star), R(13),
- B(Mov), R(17), R(14),
+ B(Star), R(11),
+ B(Mov), R(15), R(12),
B(Jump), U8(20),
- B(Ldar), R(17),
+ B(Ldar), R(15),
B(JumpLoop), U8(84), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(14),
- B(Star), R(13),
+ B(Star), R(12),
+ B(Star), R(11),
B(Jump), U8(7),
- B(Star), R(14),
+ B(Star), R(12),
B(LdaZero),
- B(Star), R(13),
+ B(Star), R(11),
B(LdaTheHole),
B(SetPendingMessage),
+ B(Star), R(13),
+ B(Ldar), R(10),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(9), U8(10), U8(13),
B(Star), R(15),
- B(Ldar), R(12),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(9), U8(11), U8(13),
- B(Star), R(17),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(18),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(16),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(19),
- B(LdaConstant), U8(12),
- B(Star), R(20),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(19), U8(2),
+ B(Star), R(17),
+ B(LdaConstant), U8(11),
+ B(Star), R(18),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(17), U8(2),
B(Throw),
- B(CallProperty0), R(17), R(9), U8(15),
+ B(CallProperty0), R(15), R(9), U8(15),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(19),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(19), U8(1),
+ B(Star), R(17),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(17), U8(1),
B(Jump), U8(12),
- B(Star), R(18),
+ B(Star), R(16),
B(LdaZero),
- B(TestReferenceEqual), R(13),
+ B(TestReferenceEqual), R(11),
B(JumpIfTrue), U8(5),
- B(Ldar), R(18),
+ B(Ldar), R(16),
B(ReThrow),
- B(Ldar), R(15),
- B(SetPendingMessage),
B(Ldar), R(13),
- B(SwitchOnSmiNoFeedback), U8(13), U8(2), I8(0),
+ B(SetPendingMessage),
+ B(Ldar), R(11),
+ B(SwitchOnSmiNoFeedback), U8(12), U8(2), I8(0),
B(Jump), U8(14),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
B(LdaSmi), I8(1),
B(Star), R(4),
- B(Mov), R(14), R(5),
+ B(Mov), R(12), R(5),
B(Jump), U8(51),
B(Jump), U8(36),
B(Star), R(8),
- B(CreateCatchContext), R(8), U8(15),
+ B(CreateCatchContext), R(8), U8(14),
B(Star), R(7),
B(LdaTheHole),
B(SetPendingMessage),
@@ -360,7 +359,7 @@ bytecodes: [
B(Ldar), R(6),
B(SetPendingMessage),
B(Ldar), R(4),
- B(SwitchOnSmiNoFeedback), U8(17), U8(3), I8(0),
+ B(SwitchOnSmiNoFeedback), U8(16), U8(3), I8(0),
B(Jump), U8(22),
B(Ldar), R(5),
B(ReThrow),
@@ -377,11 +376,10 @@ bytecodes: [
]
constant pool: [
Smi [30],
- Smi [149],
+ Smi [148],
Smi [16],
Smi [7],
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -392,16 +390,16 @@ constant pool: [
Smi [6],
Smi [9],
SCOPE_INFO_TYPE,
- Smi [277],
+ Smi [274],
Smi [6],
Smi [9],
Smi [23],
]
handlers: [
- [20, 318, 326],
- [23, 282, 284],
- [93, 180, 188],
- [214, 247, 249],
+ [20, 315, 323],
+ [23, 279, 281],
+ [92, 179, 187],
+ [211, 244, 246],
]
---
@@ -410,9 +408,9 @@ snippet: "
async function* f() { yield* g() }
f();
"
-frame size: 19
+frame size: 17
parameter count: 1
-bytecode array length: 475
+bytecode array length: 466
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(5),
B(Mov), R(closure), R(1),
@@ -433,44 +431,69 @@ bytecodes: [
B(LdaSmi), I8(1),
B(Star), R(1),
B(Mov), R(5), R(2),
- B(JumpConstant), U8(18),
+ B(JumpConstant), U8(17),
/* 49 S> */ B(LdaGlobal), U8(7), U8(0),
B(Star), R(9),
/* 56 E> */ B(CallUndefinedReceiver0), R(9), U8(2),
B(Star), R(10),
B(LdaNamedProperty), R(10), U8(8), U8(4),
- B(JumpIfUndefined), U8(17),
- B(JumpIfNull), U8(15),
+ B(JumpIfUndefinedOrNull), U8(15),
B(Star), R(11),
B(CallProperty0), R(11), R(10), U8(6),
- B(JumpIfJSReceiver), U8(23),
+ B(JumpIfJSReceiver), U8(22),
B(CallRuntime), U16(Runtime::kThrowSymbolAsyncIteratorInvalid), R(0), U8(0),
- B(LdaNamedProperty), R(10), U8(9), U8(8),
+ B(GetIterator), R(10), U8(8),
B(Star), R(11),
B(CallProperty0), R(11), R(10), U8(10),
B(Star), R(11),
B(InvokeIntrinsic), U8(Runtime::k_CreateAsyncFromSyncIterator), R(11), U8(1),
B(Star), R(7),
- B(LdaNamedProperty), R(7), U8(10), U8(12),
+ B(LdaNamedProperty), R(7), U8(9), U8(12),
B(Star), R(9),
B(LdaUndefined),
B(Star), R(8),
B(LdaZero),
B(Star), R(6),
B(Ldar), R(6),
- B(SwitchOnSmiNoFeedback), U8(11), U8(2), I8(1),
+ B(SwitchOnSmiNoFeedback), U8(10), U8(2), I8(1),
B(CallProperty1), R(9), R(7), R(8), U8(14),
- B(Jump), U8(146),
- B(LdaNamedProperty), R(7), U8(13), U8(16),
- B(JumpIfUndefined), U8(13),
- B(JumpIfNull), U8(11),
+ B(Jump), U8(140),
+ B(LdaNamedProperty), R(7), U8(12), U8(16),
+ B(JumpIfUndefinedOrNull), U8(11),
+ B(Star), R(10),
+ B(CallProperty1), R(10), R(7), R(8), U8(18),
+ B(Jump), U8(125),
+ B(Mov), R(0), R(10),
+ B(Mov), R(8), R(11),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(10), U8(2),
+ /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(10), U8(1),
+ B(ResumeGenerator), R(0), R(0), U8(10),
+ B(Star), R(10),
+ B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
+ B(Star), R(11),
+ B(LdaZero),
+ B(TestReferenceEqual), R(11),
+ B(JumpIfTrue), U8(5),
+ B(Ldar), R(10),
+ B(ReThrow),
+ B(LdaSmi), I8(1),
+ B(Star), R(1),
+ B(Mov), R(10), R(2),
+ B(Jump), U8(241),
+ B(LdaNamedProperty), R(7), U8(13), U8(20),
+ B(JumpIfUndefinedOrNull), U8(11),
B(Star), R(12),
- B(CallProperty1), R(12), R(7), R(8), U8(18),
- B(Jump), U8(129),
+ B(CallProperty1), R(12), R(7), R(8), U8(22),
+ B(Jump), U8(66),
+ B(LdaNamedProperty), R(7), U8(12), U8(24),
+ B(JumpIfUndefinedOrNull), U8(55),
+ B(Star), R(12),
+ B(CallProperty0), R(12), R(7), U8(26),
+ B(Jump), U8(2),
+ B(Star), R(13),
B(Mov), R(0), R(12),
- B(Mov), R(8), R(13),
B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(12), U8(2),
- /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(1),
+ /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(2),
B(ResumeGenerator), R(0), R(0), U8(12),
B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
@@ -480,72 +503,43 @@ bytecodes: [
B(JumpIfTrue), U8(5),
B(Ldar), R(12),
B(ReThrow),
- B(LdaSmi), I8(1),
- B(Star), R(1),
- B(Mov), R(12), R(2),
- B(Jump), U8(245),
- B(LdaNamedProperty), R(7), U8(14), U8(20),
- B(JumpIfUndefined), U8(13),
- B(JumpIfNull), U8(11),
- B(Star), R(14),
- B(CallProperty1), R(14), R(7), R(8), U8(22),
- B(Jump), U8(68),
- B(LdaNamedProperty), R(7), U8(13), U8(24),
- B(JumpIfUndefined), U8(57),
- B(JumpIfNull), U8(55),
- B(Star), R(14),
- B(CallProperty0), R(14), R(7), U8(26),
- B(Jump), U8(2),
- B(Star), R(15),
- B(Mov), R(0), R(14),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(14), U8(2),
- /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(14), U8(2),
- B(ResumeGenerator), R(0), R(0), U8(14),
- B(Star), R(14),
- B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(Star), R(15),
- B(LdaZero),
- B(TestReferenceEqual), R(15),
- B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
- B(ReThrow),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(JumpIfJSReceiver), U8(9),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(16), U8(1),
- B(CallRuntime), U16(Runtime::kThrowThrowMethodMissing), R(0), U8(0),
- B(Star), R(15),
- B(Mov), R(0), R(14),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(14), U8(2),
- /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(14), U8(3),
- B(ResumeGenerator), R(0), R(0), U8(14),
B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
+ B(CallRuntime), U16(Runtime::kThrowThrowMethodMissing), R(0), U8(0),
+ B(Star), R(13),
+ B(Mov), R(0), R(12),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorAwaitUncaught), R(12), U8(2),
+ /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(3),
+ B(ResumeGenerator), R(0), R(0), U8(12),
+ B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(Star), R(15),
+ B(Star), R(13),
B(LdaZero),
- B(TestReferenceEqual), R(15),
+ B(TestReferenceEqual), R(13),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(14),
- B(Mov), R(14), R(5),
+ B(Ldar), R(12),
+ B(Mov), R(12), R(5),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(5), U8(1),
- B(LdaNamedProperty), R(5), U8(15), U8(28),
+ B(LdaNamedProperty), R(5), U8(14), U8(28),
B(JumpIfToBooleanTrue), U8(38),
- B(LdaNamedProperty), R(5), U8(16), U8(30),
- B(Star), R(17),
+ B(LdaNamedProperty), R(5), U8(15), U8(30),
+ B(Star), R(15),
B(LdaFalse),
- B(Star), R(18),
- B(Mov), R(0), R(16),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorYield), R(16), U8(3),
- /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(16), U8(4),
- B(ResumeGenerator), R(0), R(0), U8(16),
+ B(Star), R(16),
+ B(Mov), R(0), R(14),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorYield), R(14), U8(3),
+ /* 49 E> */ B(SuspendGenerator), R(0), R(0), U8(14), U8(4),
+ B(ResumeGenerator), R(0), R(0), U8(14),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(6),
- B(JumpLoop), U8(242), I8(0),
- B(LdaNamedProperty), R(5), U8(16), U8(32),
+ B(JumpLoop), U8(236), I8(0),
+ B(LdaNamedProperty), R(5), U8(15), U8(32),
B(Star), R(7),
B(LdaSmi), I8(1),
B(TestReferenceEqual), R(6),
@@ -557,7 +551,7 @@ bytecodes: [
B(Ldar), R(7),
B(Jump), U8(36),
B(Star), R(5),
- B(CreateCatchContext), R(5), U8(17),
+ B(CreateCatchContext), R(5), U8(16),
B(Star), R(4),
B(LdaTheHole),
B(SetPendingMessage),
@@ -586,7 +580,7 @@ bytecodes: [
B(Ldar), R(3),
B(SetPendingMessage),
B(Ldar), R(1),
- B(SwitchOnSmiNoFeedback), U8(19), U8(3), I8(0),
+ B(SwitchOnSmiNoFeedback), U8(18), U8(3), I8(0),
B(Jump), U8(22),
B(Ldar), R(2),
B(ReThrow),
@@ -603,30 +597,29 @@ bytecodes: [
]
constant pool: [
Smi [30],
- Smi [162],
- Smi [238],
- Smi [288],
- Smi [347],
+ Smi [157],
+ Smi [229],
+ Smi [279],
+ Smi [338],
Smi [16],
Smi [7],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["g"],
SYMBOL_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
Smi [11],
- Smi [72],
+ Smi [70],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["throw"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
SCOPE_INFO_TYPE,
- Smi [380],
+ Smi [371],
Smi [6],
Smi [9],
Smi [23],
]
handlers: [
- [20, 421, 429],
- [23, 383, 387],
+ [20, 412, 420],
+ [23, 374, 378],
]
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/CallAndSpread.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/CallAndSpread.golden
index 33bd5434b4..963cbee018 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/CallAndSpread.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/CallAndSpread.golden
@@ -65,9 +65,9 @@ handlers: [
snippet: "
Math.max(0, ...[1, 2, 3], 4);
"
-frame size: 10
+frame size: 9
parameter count: 1
-bytecode array length: 107
+bytecode array length: 106
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaGlobal), U8(0), U8(0),
@@ -80,22 +80,22 @@ bytecodes: [
B(Star), R(3),
/* 49 S> */ B(CreateArrayLiteral), U8(4), U8(5), U8(37),
B(Star), R(7),
- B(LdaNamedProperty), R(7), U8(5), U8(6),
+ B(GetIterator), R(7), U8(6),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(8),
B(Mov), R(0), R(2),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(6), U8(10),
+ B(LdaNamedProperty), R(6), U8(5), U8(10),
B(Star), R(5),
B(CallProperty0), R(5), R(6), U8(19),
- B(Star), R(9),
+ B(Star), R(7),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(9), U8(1),
- B(LdaNamedProperty), R(9), U8(7), U8(21),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(7), U8(1),
+ B(LdaNamedProperty), R(7), U8(6), U8(21),
B(JumpIfToBooleanTrue), U8(19),
- B(LdaNamedProperty), R(9), U8(8), U8(12),
+ B(LdaNamedProperty), R(7), U8(7), U8(12),
B(StaInArrayLiteral), R(4), R(3), U8(17),
B(Ldar), R(3),
B(Inc), U8(16),
@@ -114,7 +114,6 @@ constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
Smi [1],
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/DestructuringAssignment.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/DestructuringAssignment.golden
index 2d44b972a0..e26b79a9fb 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/DestructuringAssignment.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/DestructuringAssignment.golden
@@ -10,93 +10,90 @@ snippet: "
var x, a = [0,1,2,3];
[x] = a;
"
-frame size: 16
+frame size: 14
parameter count: 1
-bytecode array length: 178
+bytecode array length: 172
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 45 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(1),
- /* 60 S> */ B(LdaNamedProperty), R(1), U8(1), U8(1),
+ /* 60 S> */ B(GetIterator), R(1), U8(1),
B(Star), R(6),
B(CallProperty0), R(6), R(1), U8(3),
- B(Mov), R(1), R(5),
B(Mov), R(1), R(2),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(4),
- B(LdaNamedProperty), R(4), U8(2), U8(5),
+ B(LdaNamedProperty), R(4), U8(1), U8(5),
B(Star), R(3),
B(LdaFalse),
- B(Star), R(7),
- B(Mov), R(context), R(10),
- /* 57 S> */ B(Ldar), R(7),
+ B(Star), R(5),
+ B(Mov), R(context), R(8),
+ /* 57 S> */ B(Ldar), R(5),
B(JumpIfToBooleanTrue), U8(37),
B(LdaTrue),
- B(Star), R(7),
+ B(Star), R(5),
B(CallProperty0), R(3), R(4), U8(11),
- B(Star), R(11),
+ B(Star), R(9),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
- B(LdaNamedProperty), R(11), U8(3), U8(9),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(9), U8(1),
+ B(LdaNamedProperty), R(9), U8(2), U8(9),
B(JumpIfToBooleanTrue), U8(15),
- B(LdaNamedProperty), R(11), U8(4), U8(7),
- B(Star), R(11),
+ B(LdaNamedProperty), R(9), U8(3), U8(7),
+ B(Star), R(9),
B(LdaFalse),
- B(Star), R(7),
- B(Ldar), R(11),
+ B(Star), R(5),
+ B(Ldar), R(9),
B(Jump), U8(3),
B(LdaUndefined),
B(Star), R(0),
B(LdaSmi), I8(-1),
- B(Star), R(9),
- B(Star), R(8),
+ B(Star), R(7),
+ B(Star), R(6),
B(Jump), U8(7),
- B(Star), R(9),
+ B(Star), R(7),
B(LdaZero),
- B(Star), R(8),
+ B(Star), R(6),
B(LdaTheHole),
B(SetPendingMessage),
+ B(Star), R(8),
+ B(Ldar), R(5),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(4), U8(4), U8(13),
B(Star), R(10),
- B(Ldar), R(7),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(4), U8(5), U8(13),
- B(Star), R(12),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(13),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(11),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(14),
- B(LdaConstant), U8(6),
- B(Star), R(15),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(14), U8(2),
+ B(Star), R(12),
+ B(LdaConstant), U8(5),
+ B(Star), R(13),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2),
B(Throw),
- B(CallProperty0), R(12), R(4), U8(15),
+ B(CallProperty0), R(10), R(4), U8(15),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(14),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
+ B(Star), R(12),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
B(Jump), U8(12),
- B(Star), R(13),
+ B(Star), R(11),
B(LdaZero),
- B(TestReferenceEqual), R(8),
+ B(TestReferenceEqual), R(6),
B(JumpIfTrue), U8(5),
- B(Ldar), R(13),
+ B(Ldar), R(11),
B(ReThrow),
- B(Ldar), R(10),
+ B(Ldar), R(8),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(8),
+ B(TestReferenceEqual), R(6),
B(JumpIfFalse), U8(5),
- B(Ldar), R(9),
+ B(Ldar), R(7),
B(ReThrow),
B(LdaUndefined),
/* 65 S> */ B(Return),
]
constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -104,8 +101,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [44, 86, 94],
- [120, 153, 155],
+ [40, 82, 90],
+ [114, 147, 149],
]
---
@@ -113,127 +110,124 @@ snippet: "
var x, y, a = [0,1,2,3];
[,x,...y] = a;
"
-frame size: 17
+frame size: 15
parameter count: 1
-bytecode array length: 264
+bytecode array length: 258
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 48 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(2),
- /* 69 S> */ B(LdaNamedProperty), R(2), U8(1), U8(1),
+ /* 69 S> */ B(GetIterator), R(2), U8(1),
B(Star), R(7),
B(CallProperty0), R(7), R(2), U8(3),
- B(Mov), R(2), R(6),
B(Mov), R(2), R(3),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(5),
- B(LdaNamedProperty), R(5), U8(2), U8(5),
+ B(LdaNamedProperty), R(5), U8(1), U8(5),
B(Star), R(4),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(context), R(11),
- B(Ldar), R(8),
+ B(Star), R(6),
+ B(Mov), R(context), R(9),
+ B(Ldar), R(6),
B(JumpIfToBooleanTrue), U8(35),
B(LdaTrue),
- B(Star), R(8),
+ B(Star), R(6),
B(CallProperty0), R(4), R(5), U8(11),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(3), U8(9),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(2), U8(9),
B(JumpIfToBooleanTrue), U8(13),
- B(LdaNamedProperty), R(12), U8(4), U8(7),
- B(Star), R(12),
+ B(LdaNamedProperty), R(10), U8(3), U8(7),
+ B(Star), R(10),
B(LdaFalse),
- B(Star), R(8),
- B(Ldar), R(12),
- /* 61 S> */ B(Ldar), R(8),
+ B(Star), R(6),
+ B(Ldar), R(10),
+ /* 61 S> */ B(Ldar), R(6),
B(JumpIfToBooleanTrue), U8(37),
B(LdaTrue),
- B(Star), R(8),
+ B(Star), R(6),
B(CallProperty0), R(4), R(5), U8(13),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(3), U8(9),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(2), U8(9),
B(JumpIfToBooleanTrue), U8(15),
- B(LdaNamedProperty), R(12), U8(4), U8(7),
- B(Star), R(12),
+ B(LdaNamedProperty), R(10), U8(3), U8(7),
+ B(Star), R(10),
B(LdaFalse),
- B(Star), R(8),
- B(Ldar), R(12),
+ B(Star), R(6),
+ B(Ldar), R(10),
B(Jump), U8(3),
B(LdaUndefined),
B(Star), R(0),
/* 63 S> */ B(CreateEmptyArrayLiteral), U8(15),
- B(Star), R(13),
+ B(Star), R(11),
B(LdaZero),
- B(Star), R(14),
+ B(Star), R(12),
B(LdaTrue),
- B(Star), R(8),
+ B(Star), R(6),
B(CallProperty0), R(4), R(5), U8(19),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(3), U8(21),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(2), U8(21),
B(JumpIfToBooleanTrue), U8(19),
- B(LdaNamedProperty), R(12), U8(4), U8(7),
- B(StaInArrayLiteral), R(13), R(14), U8(16),
- B(Ldar), R(14),
+ B(LdaNamedProperty), R(10), U8(3), U8(7),
+ B(StaInArrayLiteral), R(11), R(12), U8(16),
+ B(Ldar), R(12),
B(Inc), U8(18),
- B(Star), R(14),
+ B(Star), R(12),
B(JumpLoop), U8(33), I8(0),
- B(Mov), R(13), R(1),
+ B(Mov), R(11), R(1),
B(LdaSmi), I8(-1),
- B(Star), R(10),
- B(Star), R(9),
+ B(Star), R(8),
+ B(Star), R(7),
B(Jump), U8(7),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaZero),
- B(Star), R(9),
+ B(Star), R(7),
B(LdaTheHole),
B(SetPendingMessage),
+ B(Star), R(9),
+ B(Ldar), R(6),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(5), U8(4), U8(23),
B(Star), R(11),
- B(Ldar), R(8),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(5), U8(5), U8(23),
- B(Star), R(13),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(14),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(12),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(15),
- B(LdaConstant), U8(6),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(15), U8(2),
+ B(Star), R(13),
+ B(LdaConstant), U8(5),
+ B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(13), U8(2),
B(Throw),
- B(CallProperty0), R(13), R(5), U8(25),
+ B(CallProperty0), R(11), R(5), U8(25),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(15),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(15), U8(1),
+ B(Star), R(13),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
B(Jump), U8(12),
- B(Star), R(14),
+ B(Star), R(12),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(11),
+ B(Ldar), R(9),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfFalse), U8(5),
- B(Ldar), R(10),
+ B(Ldar), R(8),
B(ReThrow),
B(LdaUndefined),
/* 74 S> */ B(Return),
]
constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -241,8 +235,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [44, 172, 180],
- [206, 239, 241],
+ [40, 168, 176],
+ [200, 233, 235],
]
---
@@ -250,114 +244,111 @@ snippet: "
var x={}, y, a = [0];
[x.foo,y=4] = a;
"
-frame size: 18
+frame size: 16
parameter count: 1
-bytecode array length: 229
+bytecode array length: 223
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 40 S> */ B(CreateEmptyObjectLiteral),
B(Star), R(0),
/* 51 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(2),
- /* 68 S> */ B(LdaNamedProperty), R(2), U8(1), U8(1),
+ /* 68 S> */ B(GetIterator), R(2), U8(1),
B(Star), R(7),
B(CallProperty0), R(7), R(2), U8(3),
- B(Mov), R(2), R(6),
B(Mov), R(2), R(3),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(5),
- B(LdaNamedProperty), R(5), U8(2), U8(5),
+ B(LdaNamedProperty), R(5), U8(1), U8(5),
B(Star), R(4),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(context), R(11),
- /* 59 S> */ B(Ldar), R(8),
- B(Mov), R(0), R(13),
+ B(Star), R(6),
+ B(Mov), R(context), R(9),
+ /* 59 S> */ B(Ldar), R(6),
+ B(Mov), R(0), R(11),
B(JumpIfToBooleanTrue), U8(37),
B(LdaTrue),
- B(Star), R(8),
+ B(Star), R(6),
B(CallProperty0), R(4), R(5), U8(11),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(3), U8(9),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(2), U8(9),
B(JumpIfToBooleanTrue), U8(15),
- B(LdaNamedProperty), R(12), U8(4), U8(7),
- B(Star), R(12),
+ B(LdaNamedProperty), R(10), U8(3), U8(7),
+ B(Star), R(10),
B(LdaFalse),
- B(Star), R(8),
- B(Ldar), R(12),
+ B(Star), R(6),
+ B(Ldar), R(10),
B(Jump), U8(3),
B(LdaUndefined),
- B(StaNamedProperty), R(13), U8(5), U8(13),
- /* 63 S> */ B(Ldar), R(8),
+ B(StaNamedProperty), R(11), U8(4), U8(13),
+ /* 63 S> */ B(Ldar), R(6),
B(JumpIfToBooleanTrue), U8(37),
B(LdaTrue),
- B(Star), R(8),
+ B(Star), R(6),
B(CallProperty0), R(4), R(5), U8(15),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(3), U8(9),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(2), U8(9),
B(JumpIfToBooleanTrue), U8(15),
- B(LdaNamedProperty), R(12), U8(4), U8(7),
- B(Star), R(12),
+ B(LdaNamedProperty), R(10), U8(3), U8(7),
+ B(Star), R(10),
B(LdaFalse),
- B(Star), R(8),
- B(Ldar), R(12),
+ B(Star), R(6),
+ B(Ldar), R(10),
B(JumpIfNotUndefined), U8(4),
B(LdaSmi), I8(4),
B(Star), R(1),
B(LdaSmi), I8(-1),
- B(Star), R(10),
- B(Star), R(9),
+ B(Star), R(8),
+ B(Star), R(7),
B(Jump), U8(7),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaZero),
- B(Star), R(9),
+ B(Star), R(7),
B(LdaTheHole),
B(SetPendingMessage),
- B(Star), R(11),
- B(Ldar), R(8),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(5), U8(6), U8(17),
- B(Star), R(14),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(15),
+ B(Star), R(9),
+ B(Ldar), R(6),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(5), U8(5), U8(17),
+ B(Star), R(12),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(13),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(16),
- B(LdaConstant), U8(7),
- B(Star), R(17),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(16), U8(2),
+ B(Star), R(14),
+ B(LdaConstant), U8(6),
+ B(Star), R(15),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(14), U8(2),
B(Throw),
- B(CallProperty0), R(14), R(5), U8(19),
+ B(CallProperty0), R(12), R(5), U8(19),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(16), U8(1),
+ B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
B(Jump), U8(12),
- B(Star), R(15),
+ B(Star), R(13),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfTrue), U8(5),
- B(Ldar), R(15),
+ B(Ldar), R(13),
B(ReThrow),
- B(Ldar), R(11),
+ B(Ldar), R(9),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfFalse), U8(5),
- B(Ldar), R(10),
+ B(Ldar), R(8),
B(ReThrow),
B(LdaUndefined),
/* 73 S> */ B(Return),
]
constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -366,8 +357,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [47, 137, 145],
- [171, 204, 206],
+ [43, 133, 141],
+ [165, 198, 200],
]
---
@@ -375,18 +366,14 @@ snippet: "
var x, a = {x:1};
({x} = a);
"
-frame size: 3
+frame size: 2
parameter count: 1
-bytecode array length: 26
+bytecode array length: 15
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 45 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(41),
B(Star), R(1),
- /* 52 S> */ B(JumpIfNull), U8(4),
- B(JumpIfNotUndefined), U8(7),
- /* 53 E> */ B(CallRuntime), U16(Runtime::kThrowPatternAssignmentNonCoercible), R(0), U8(0),
- B(Star), R(2),
- /* 54 S> */ B(LdaNamedProperty), R(2), U8(1), U8(1),
+ /* 54 S> */ B(LdaNamedProperty), R(1), U8(1), U8(1),
B(Star), R(0),
B(LdaUndefined),
/* 63 S> */ B(Return),
@@ -403,20 +390,16 @@ snippet: "
var x={}, a = {y:1};
({y:x.foo} = a);
"
-frame size: 3
+frame size: 2
parameter count: 1
-bytecode array length: 31
+bytecode array length: 20
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 40 S> */ B(CreateEmptyObjectLiteral),
B(Star), R(0),
/* 48 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(41),
B(Star), R(1),
- /* 55 S> */ B(JumpIfNull), U8(4),
- B(JumpIfNotUndefined), U8(7),
- /* 56 E> */ B(CallRuntime), U16(Runtime::kThrowPatternAssignmentNonCoercible), R(0), U8(0),
- /* 61 S> */ B(Star), R(2),
- B(LdaNamedProperty), R(2), U8(1), U8(1),
+ /* 61 S> */ B(LdaNamedProperty), R(1), U8(1), U8(1),
B(StaNamedProperty), R(0), U8(2), U8(3),
B(LdaUndefined),
/* 72 S> */ B(Return),
@@ -436,18 +419,15 @@ snippet: "
"
frame size: 4
parameter count: 1
-bytecode array length: 41
+bytecode array length: 33
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 45 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(41),
B(Star), R(1),
- /* 62 S> */ B(JumpIfNull), U8(4),
- B(JumpIfNotUndefined), U8(7),
- /* 63 E> */ B(CallRuntime), U16(Runtime::kThrowPatternAssignmentNonCoercible), R(0), U8(0),
- B(Star), R(2),
/* 64 S> */ B(LdaConstant), U8(1),
B(Star), R(3),
- B(LdaNamedProperty), R(2), U8(1), U8(1),
+ B(LdaNamedProperty), R(1), U8(1), U8(1),
+ B(Mov), R(1), R(2),
B(JumpIfNotUndefined), U8(3),
B(LdaZero),
B(Star), R(0),
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden
index 1cafe42d28..f60e591040 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden
@@ -14,9 +14,9 @@ snippet: "
}
f();
"
-frame size: 21
+frame size: 19
parameter count: 1
-bytecode array length: 325
+bytecode array length: 320
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(2),
B(Mov), R(closure), R(4),
@@ -28,110 +28,108 @@ bytecodes: [
/* 43 S> */ B(CreateArrayLiteral), U8(2), U8(0), U8(37),
B(Star), R(7),
B(LdaNamedProperty), R(7), U8(3), U8(1),
- B(JumpIfUndefined), U8(17),
- B(JumpIfNull), U8(15),
+ B(JumpIfUndefinedOrNull), U8(15),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(3),
- B(JumpIfJSReceiver), U8(23),
+ B(JumpIfJSReceiver), U8(22),
B(CallRuntime), U16(Runtime::kThrowSymbolAsyncIteratorInvalid), R(0), U8(0),
- B(LdaNamedProperty), R(7), U8(4), U8(5),
+ B(GetIterator), R(7), U8(5),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(7),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_CreateAsyncFromSyncIterator), R(8), U8(1),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(5), U8(9),
+ B(LdaNamedProperty), R(6), U8(4), U8(9),
B(Star), R(5),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(context), R(12),
+ B(Star), R(7),
+ B(Mov), R(context), R(10),
B(LdaTrue),
- B(Star), R(9),
+ B(Star), R(7),
/* 38 S> */ B(CallProperty0), R(5), R(6), U8(11),
- B(Star), R(15),
- B(Mov), R(0), R(14),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(14), U8(2),
- B(SuspendGenerator), R(0), R(0), U8(14), U8(0),
- B(ResumeGenerator), R(0), R(0), U8(14),
- B(Star), R(14),
+ B(Star), R(13),
+ B(Mov), R(0), R(12),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(12), U8(2),
+ B(SuspendGenerator), R(0), R(0), U8(12), U8(0),
+ B(ResumeGenerator), R(0), R(0), U8(12),
+ B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(Star), R(15),
+ B(Star), R(13),
B(LdaZero),
- B(TestReferenceEqual), R(15),
+ B(TestReferenceEqual), R(13),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(14),
- B(Mov), R(14), R(13),
+ B(Ldar), R(12),
+ B(Mov), R(12), R(11),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
- B(LdaNamedProperty), R(13), U8(6), U8(13),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
+ B(LdaNamedProperty), R(11), U8(5), U8(13),
B(JumpIfToBooleanTrue), U8(23),
- B(LdaNamedProperty), R(13), U8(7), U8(15),
- B(Star), R(13),
+ B(LdaNamedProperty), R(11), U8(6), U8(15),
+ B(Star), R(11),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(13), R(1),
+ B(Star), R(7),
+ B(Mov), R(11), R(1),
/* 23 E> */ B(StackCheck),
/* 38 S> */ B(Mov), R(1), R(3),
- B(Ldar), R(13),
+ B(Ldar), R(11),
B(JumpLoop), U8(77), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(11),
- B(Star), R(10),
+ B(Star), R(9),
+ B(Star), R(8),
B(Jump), U8(7),
- B(Star), R(11),
+ B(Star), R(9),
B(LdaZero),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaTheHole),
/* 38 E> */ B(SetPendingMessage),
- B(Star), R(12),
- B(Ldar), R(9),
- B(JumpIfToBooleanTrue), U8(96),
- B(LdaNamedProperty), R(6), U8(8), U8(17),
- B(Star), R(16),
- B(JumpIfUndefined), U8(88),
- B(JumpIfNull), U8(86),
- B(Mov), R(context), R(17),
+ B(Star), R(10),
+ B(Ldar), R(7),
+ B(JumpIfToBooleanTrue), U8(94),
+ B(LdaNamedProperty), R(6), U8(7), U8(17),
+ B(Star), R(14),
+ B(JumpIfUndefinedOrNull), U8(86),
+ B(Mov), R(context), R(15),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(18),
- B(LdaConstant), U8(9),
- B(Star), R(19),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(18), U8(2),
+ B(Star), R(16),
+ B(LdaConstant), U8(8),
+ B(Star), R(17),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(16), U8(2),
B(Throw),
- B(CallProperty0), R(16), R(6), U8(19),
- B(Star), R(19),
- B(Mov), R(0), R(18),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(18), U8(2),
- B(SuspendGenerator), R(0), R(0), U8(18), U8(1),
- B(ResumeGenerator), R(0), R(0), U8(18),
- B(Star), R(18),
+ B(CallProperty0), R(14), R(6), U8(19),
+ B(Star), R(17),
+ B(Mov), R(0), R(16),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(16), U8(2),
+ B(SuspendGenerator), R(0), R(0), U8(16), U8(1),
+ B(ResumeGenerator), R(0), R(0), U8(16),
+ B(Star), R(16),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(Star), R(19),
+ B(Star), R(17),
B(LdaZero),
- B(TestReferenceEqual), R(19),
+ B(TestReferenceEqual), R(17),
B(JumpIfTrue), U8(5),
- B(Ldar), R(18),
+ B(Ldar), R(16),
B(ReThrow),
- B(Ldar), R(18),
+ B(Ldar), R(16),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(20),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(20), U8(1),
+ B(Star), R(18),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(18), U8(1),
B(Jump), U8(12),
- B(Star), R(17),
+ B(Star), R(15),
B(LdaZero),
- B(TestReferenceEqual), R(10),
+ B(TestReferenceEqual), R(8),
B(JumpIfTrue), U8(5),
- B(Ldar), R(17),
+ B(Ldar), R(15),
B(ReThrow),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(10),
+ B(TestReferenceEqual), R(8),
B(JumpIfFalse), U8(5),
- B(Ldar), R(11),
+ B(Ldar), R(9),
B(ReThrow),
B(LdaUndefined),
B(Star), R(6),
@@ -141,7 +139,7 @@ bytecodes: [
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(5), U8(3),
/* 57 S> */ B(Return),
B(Star), R(5),
- B(CreateCatchContext), R(5), U8(10),
+ B(CreateCatchContext), R(5), U8(9),
B(Star), R(4),
B(LdaTheHole),
B(SetPendingMessage),
@@ -156,11 +154,10 @@ bytecodes: [
/* 57 S> */ B(Return),
]
constant pool: [
- Smi [98],
- Smi [229],
+ Smi [95],
+ Smi [224],
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
SYMBOL_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -169,9 +166,9 @@ constant pool: [
SCOPE_INFO_TYPE,
]
handlers: [
- [20, 297, 297],
- [77, 157, 165],
- [191, 260, 262],
+ [20, 292, 292],
+ [74, 154, 162],
+ [186, 255, 257],
]
---
@@ -181,9 +178,9 @@ snippet: "
}
f();
"
-frame size: 21
+frame size: 19
parameter count: 1
-bytecode array length: 346
+bytecode array length: 341
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(2),
B(Mov), R(closure), R(4),
@@ -195,118 +192,116 @@ bytecodes: [
/* 43 S> */ B(CreateArrayLiteral), U8(2), U8(0), U8(37),
B(Star), R(7),
B(LdaNamedProperty), R(7), U8(3), U8(1),
- B(JumpIfUndefined), U8(17),
- B(JumpIfNull), U8(15),
+ B(JumpIfUndefinedOrNull), U8(15),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(3),
- B(JumpIfJSReceiver), U8(23),
+ B(JumpIfJSReceiver), U8(22),
B(CallRuntime), U16(Runtime::kThrowSymbolAsyncIteratorInvalid), R(0), U8(0),
- B(LdaNamedProperty), R(7), U8(4), U8(5),
+ B(GetIterator), R(7), U8(5),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(7),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_CreateAsyncFromSyncIterator), R(8), U8(1),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(5), U8(9),
+ B(LdaNamedProperty), R(6), U8(4), U8(9),
B(Star), R(5),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(context), R(12),
+ B(Star), R(7),
+ B(Mov), R(context), R(10),
B(LdaTrue),
- B(Star), R(9),
+ B(Star), R(7),
/* 38 S> */ B(CallProperty0), R(5), R(6), U8(11),
- B(Star), R(15),
- B(Mov), R(0), R(14),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(14), U8(2),
- B(SuspendGenerator), R(0), R(0), U8(14), U8(0),
- B(ResumeGenerator), R(0), R(0), U8(14),
- B(Star), R(14),
+ B(Star), R(13),
+ B(Mov), R(0), R(12),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(12), U8(2),
+ B(SuspendGenerator), R(0), R(0), U8(12), U8(0),
+ B(ResumeGenerator), R(0), R(0), U8(12),
+ B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(Star), R(15),
+ B(Star), R(13),
B(LdaZero),
- B(TestReferenceEqual), R(15),
+ B(TestReferenceEqual), R(13),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(14),
- B(Mov), R(14), R(13),
+ B(Ldar), R(12),
+ B(Mov), R(12), R(11),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
- B(LdaNamedProperty), R(13), U8(6), U8(13),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
+ B(LdaNamedProperty), R(11), U8(5), U8(13),
B(JumpIfToBooleanTrue), U8(27),
- B(LdaNamedProperty), R(13), U8(7), U8(15),
- B(Star), R(13),
+ B(LdaNamedProperty), R(11), U8(6), U8(15),
+ B(Star), R(11),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(13), R(1),
+ B(Star), R(7),
+ B(Mov), R(11), R(1),
/* 23 E> */ B(StackCheck),
/* 38 S> */ B(Mov), R(1), R(3),
/* 56 S> */ B(LdaSmi), I8(1),
- B(Mov), R(13), R(11),
- B(Star), R(10),
+ B(Mov), R(11), R(9),
+ B(Star), R(8),
B(Jump), U8(15),
B(LdaSmi), I8(-1),
- B(Star), R(11),
- B(Star), R(10),
+ B(Star), R(9),
+ B(Star), R(8),
B(Jump), U8(7),
- B(Star), R(11),
+ B(Star), R(9),
B(LdaZero),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaTheHole),
B(SetPendingMessage),
- B(Star), R(12),
- B(Ldar), R(9),
- B(JumpIfToBooleanTrue), U8(96),
- B(LdaNamedProperty), R(6), U8(8), U8(17),
- B(Star), R(16),
- B(JumpIfUndefined), U8(88),
- B(JumpIfNull), U8(86),
- B(Mov), R(context), R(17),
+ B(Star), R(10),
+ B(Ldar), R(7),
+ B(JumpIfToBooleanTrue), U8(94),
+ B(LdaNamedProperty), R(6), U8(7), U8(17),
+ B(Star), R(14),
+ B(JumpIfUndefinedOrNull), U8(86),
+ B(Mov), R(context), R(15),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(18),
- B(LdaConstant), U8(9),
- B(Star), R(19),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(18), U8(2),
+ B(Star), R(16),
+ B(LdaConstant), U8(8),
+ B(Star), R(17),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(16), U8(2),
B(Throw),
- B(CallProperty0), R(16), R(6), U8(19),
- B(Star), R(19),
- B(Mov), R(0), R(18),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(18), U8(2),
- B(SuspendGenerator), R(0), R(0), U8(18), U8(1),
- B(ResumeGenerator), R(0), R(0), U8(18),
- B(Star), R(18),
+ B(CallProperty0), R(14), R(6), U8(19),
+ B(Star), R(17),
+ B(Mov), R(0), R(16),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(16), U8(2),
+ B(SuspendGenerator), R(0), R(0), U8(16), U8(1),
+ B(ResumeGenerator), R(0), R(0), U8(16),
+ B(Star), R(16),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(Star), R(19),
+ B(Star), R(17),
B(LdaZero),
- B(TestReferenceEqual), R(19),
+ B(TestReferenceEqual), R(17),
B(JumpIfTrue), U8(5),
- B(Ldar), R(18),
+ B(Ldar), R(16),
B(ReThrow),
- B(Ldar), R(18),
+ B(Ldar), R(16),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(20),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(20), U8(1),
+ B(Star), R(18),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(18), U8(1),
B(Jump), U8(12),
- B(Star), R(17),
+ B(Star), R(15),
B(LdaZero),
- B(TestReferenceEqual), R(10),
+ B(TestReferenceEqual), R(8),
B(JumpIfTrue), U8(5),
- B(Ldar), R(17),
+ B(Ldar), R(15),
B(ReThrow),
- B(Ldar), R(12),
- B(SetPendingMessage),
B(Ldar), R(10),
- B(SwitchOnSmiNoFeedback), U8(10), U8(2), I8(0),
+ B(SetPendingMessage),
+ B(Ldar), R(8),
+ B(SwitchOnSmiNoFeedback), U8(9), U8(2), I8(0),
B(Jump), U8(19),
- B(Ldar), R(11),
+ B(Ldar), R(9),
B(ReThrow),
B(LdaTrue),
- B(Star), R(18),
- B(Mov), R(0), R(16),
- B(Mov), R(11), R(17),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(16), U8(3),
+ B(Star), R(16),
+ B(Mov), R(0), R(14),
+ B(Mov), R(9), R(15),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(14), U8(3),
/* 68 S> */ B(Return),
B(LdaUndefined),
B(Star), R(6),
@@ -316,7 +311,7 @@ bytecodes: [
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(5), U8(3),
/* 68 S> */ B(Return),
B(Star), R(5),
- B(CreateCatchContext), R(5), U8(12),
+ B(CreateCatchContext), R(5), U8(11),
B(Star), R(4),
B(LdaTheHole),
B(SetPendingMessage),
@@ -331,11 +326,10 @@ bytecodes: [
/* 68 S> */ B(Return),
]
constant pool: [
- Smi [98],
- Smi [233],
+ Smi [95],
+ Smi [228],
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
SYMBOL_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -346,9 +340,9 @@ constant pool: [
SCOPE_INFO_TYPE,
]
handlers: [
- [20, 318, 318],
- [77, 161, 169],
- [195, 264, 266],
+ [20, 313, 313],
+ [74, 158, 166],
+ [190, 259, 261],
]
---
@@ -361,9 +355,9 @@ snippet: "
}
f();
"
-frame size: 21
+frame size: 19
parameter count: 1
-bytecode array length: 341
+bytecode array length: 336
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(2),
B(Mov), R(closure), R(4),
@@ -375,50 +369,49 @@ bytecodes: [
/* 43 S> */ B(CreateArrayLiteral), U8(2), U8(0), U8(37),
B(Star), R(7),
B(LdaNamedProperty), R(7), U8(3), U8(1),
- B(JumpIfUndefined), U8(17),
- B(JumpIfNull), U8(15),
+ B(JumpIfUndefinedOrNull), U8(15),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(3),
- B(JumpIfJSReceiver), U8(23),
+ B(JumpIfJSReceiver), U8(22),
B(CallRuntime), U16(Runtime::kThrowSymbolAsyncIteratorInvalid), R(0), U8(0),
- B(LdaNamedProperty), R(7), U8(4), U8(5),
+ B(GetIterator), R(7), U8(5),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(7),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_CreateAsyncFromSyncIterator), R(8), U8(1),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(5), U8(9),
+ B(LdaNamedProperty), R(6), U8(4), U8(9),
B(Star), R(5),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(context), R(12),
+ B(Star), R(7),
+ B(Mov), R(context), R(10),
B(LdaTrue),
- B(Star), R(9),
+ B(Star), R(7),
/* 38 S> */ B(CallProperty0), R(5), R(6), U8(11),
- B(Star), R(15),
- B(Mov), R(0), R(14),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(14), U8(2),
- B(SuspendGenerator), R(0), R(0), U8(14), U8(0),
- B(ResumeGenerator), R(0), R(0), U8(14),
- B(Star), R(14),
+ B(Star), R(13),
+ B(Mov), R(0), R(12),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(12), U8(2),
+ B(SuspendGenerator), R(0), R(0), U8(12), U8(0),
+ B(ResumeGenerator), R(0), R(0), U8(12),
+ B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(Star), R(15),
+ B(Star), R(13),
B(LdaZero),
- B(TestReferenceEqual), R(15),
+ B(TestReferenceEqual), R(13),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(14),
- B(Mov), R(14), R(13),
+ B(Ldar), R(12),
+ B(Mov), R(12), R(11),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
- B(LdaNamedProperty), R(13), U8(6), U8(13),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
+ B(LdaNamedProperty), R(11), U8(5), U8(13),
B(JumpIfToBooleanTrue), U8(39),
- B(LdaNamedProperty), R(13), U8(7), U8(15),
- B(Star), R(13),
+ B(LdaNamedProperty), R(11), U8(6), U8(15),
+ B(Star), R(11),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(13), R(1),
+ B(Star), R(7),
+ B(Mov), R(11), R(1),
/* 23 E> */ B(StackCheck),
/* 38 S> */ B(Mov), R(1), R(3),
/* 63 S> */ B(LdaSmi), I8(10),
@@ -431,61 +424,60 @@ bytecodes: [
/* 103 S> */ B(Jump), U8(5),
B(JumpLoop), U8(93), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(11),
- B(Star), R(10),
+ B(Star), R(9),
+ B(Star), R(8),
B(Jump), U8(7),
- B(Star), R(11),
+ B(Star), R(9),
B(LdaZero),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaTheHole),
B(SetPendingMessage),
- B(Star), R(12),
- B(Ldar), R(9),
- B(JumpIfToBooleanTrue), U8(96),
- B(LdaNamedProperty), R(6), U8(8), U8(19),
- B(Star), R(16),
- B(JumpIfUndefined), U8(88),
- B(JumpIfNull), U8(86),
- B(Mov), R(context), R(17),
+ B(Star), R(10),
+ B(Ldar), R(7),
+ B(JumpIfToBooleanTrue), U8(94),
+ B(LdaNamedProperty), R(6), U8(7), U8(19),
+ B(Star), R(14),
+ B(JumpIfUndefinedOrNull), U8(86),
+ B(Mov), R(context), R(15),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(18),
- B(LdaConstant), U8(9),
- B(Star), R(19),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(18), U8(2),
+ B(Star), R(16),
+ B(LdaConstant), U8(8),
+ B(Star), R(17),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(16), U8(2),
B(Throw),
- B(CallProperty0), R(16), R(6), U8(21),
- B(Star), R(19),
- B(Mov), R(0), R(18),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(18), U8(2),
- B(SuspendGenerator), R(0), R(0), U8(18), U8(1),
- B(ResumeGenerator), R(0), R(0), U8(18),
- B(Star), R(18),
+ B(CallProperty0), R(14), R(6), U8(21),
+ B(Star), R(17),
+ B(Mov), R(0), R(16),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(16), U8(2),
+ B(SuspendGenerator), R(0), R(0), U8(16), U8(1),
+ B(ResumeGenerator), R(0), R(0), U8(16),
+ B(Star), R(16),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(Star), R(19),
+ B(Star), R(17),
B(LdaZero),
- B(TestReferenceEqual), R(19),
+ B(TestReferenceEqual), R(17),
B(JumpIfTrue), U8(5),
- B(Ldar), R(18),
+ B(Ldar), R(16),
B(ReThrow),
- B(Ldar), R(18),
+ B(Ldar), R(16),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(20),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(20), U8(1),
+ B(Star), R(18),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(18), U8(1),
B(Jump), U8(12),
- B(Star), R(17),
+ B(Star), R(15),
B(LdaZero),
- B(TestReferenceEqual), R(10),
+ B(TestReferenceEqual), R(8),
B(JumpIfTrue), U8(5),
- B(Ldar), R(17),
+ B(Ldar), R(15),
B(ReThrow),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(10),
+ B(TestReferenceEqual), R(8),
B(JumpIfFalse), U8(5),
- B(Ldar), R(11),
+ B(Ldar), R(9),
B(ReThrow),
B(LdaUndefined),
B(Star), R(6),
@@ -495,7 +487,7 @@ bytecodes: [
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(5), U8(3),
/* 114 S> */ B(Return),
B(Star), R(5),
- B(CreateCatchContext), R(5), U8(10),
+ B(CreateCatchContext), R(5), U8(9),
B(Star), R(4),
B(LdaTheHole),
B(SetPendingMessage),
@@ -510,11 +502,10 @@ bytecodes: [
/* 114 S> */ B(Return),
]
constant pool: [
- Smi [98],
- Smi [245],
+ Smi [95],
+ Smi [240],
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
SYMBOL_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -523,9 +514,9 @@ constant pool: [
SCOPE_INFO_TYPE,
]
handlers: [
- [20, 313, 313],
- [77, 173, 181],
- [207, 276, 278],
+ [20, 308, 308],
+ [74, 170, 178],
+ [202, 271, 273],
]
---
@@ -536,9 +527,9 @@ snippet: "
}
f();
"
-frame size: 17
+frame size: 15
parameter count: 1
-bytecode array length: 261
+bytecode array length: 258
bytecodes: [
B(Mov), R(closure), R(2),
B(Mov), R(this), R(3),
@@ -550,86 +541,85 @@ bytecodes: [
B(Star), R(1),
/* 68 S> */ B(CreateArrayLiteral), U8(1), U8(1), U8(37),
B(Star), R(5),
- B(LdaNamedProperty), R(5), U8(2), U8(2),
+ B(GetIterator), R(5), U8(2),
B(Star), R(6),
B(CallProperty0), R(6), R(5), U8(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(4),
- B(LdaNamedProperty), R(4), U8(3), U8(6),
+ B(LdaNamedProperty), R(4), U8(2), U8(6),
B(Star), R(3),
B(LdaFalse),
- B(Star), R(7),
- B(Mov), R(context), R(10),
+ B(Star), R(5),
+ B(Mov), R(context), R(8),
B(LdaTrue),
- B(Star), R(7),
+ B(Star), R(5),
/* 59 S> */ B(CallProperty0), R(3), R(4), U8(8),
- B(Star), R(11),
+ B(Star), R(9),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
- B(LdaNamedProperty), R(11), U8(4), U8(10),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(9), U8(1),
+ B(LdaNamedProperty), R(9), U8(3), U8(10),
B(JumpIfToBooleanTrue), U8(33),
- B(LdaNamedProperty), R(11), U8(5), U8(12),
- B(Star), R(11),
+ B(LdaNamedProperty), R(9), U8(4), U8(12),
+ B(Star), R(9),
B(LdaFalse),
- B(Star), R(7),
- B(Ldar), R(11),
- /* 58 E> */ B(StaNamedProperty), R(1), U8(6), U8(14),
+ B(Star), R(5),
+ B(Ldar), R(9),
+ /* 58 E> */ B(StaNamedProperty), R(1), U8(5), U8(14),
/* 53 E> */ B(StackCheck),
- /* 87 S> */ B(LdaNamedProperty), R(1), U8(6), U8(16),
- B(Star), R(9),
+ /* 87 S> */ B(LdaNamedProperty), R(1), U8(5), U8(16),
+ B(Star), R(7),
B(LdaSmi), I8(1),
- B(Star), R(8),
- B(Mov), R(1), R(12),
+ B(Star), R(6),
+ B(Mov), R(1), R(10),
B(Jump), U8(15),
B(LdaSmi), I8(-1),
- B(Star), R(9),
- B(Star), R(8),
+ B(Star), R(7),
+ B(Star), R(6),
B(Jump), U8(7),
- B(Star), R(9),
+ B(Star), R(7),
B(LdaZero),
- B(Star), R(8),
+ B(Star), R(6),
B(LdaTheHole),
B(SetPendingMessage),
- B(Star), R(10),
- B(Ldar), R(7),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(4), U8(7), U8(18),
- B(Star), R(13),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(14),
+ B(Star), R(8),
+ B(Ldar), R(5),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(4), U8(6), U8(18),
+ B(Star), R(11),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(12),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(15),
- B(LdaConstant), U8(8),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(15), U8(2),
+ B(Star), R(13),
+ B(LdaConstant), U8(7),
+ B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(13), U8(2),
B(Throw),
- B(CallProperty0), R(13), R(4), U8(20),
+ B(CallProperty0), R(11), R(4), U8(20),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(15),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(15), U8(1),
+ B(Star), R(13),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
B(Jump), U8(12),
- B(Star), R(14),
+ B(Star), R(12),
B(LdaZero),
- B(TestReferenceEqual), R(8),
+ B(TestReferenceEqual), R(6),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(10),
- B(SetPendingMessage),
B(Ldar), R(8),
- B(SwitchOnSmiNoFeedback), U8(9), U8(2), I8(0),
+ B(SetPendingMessage),
+ B(Ldar), R(6),
+ B(SwitchOnSmiNoFeedback), U8(8), U8(2), I8(0),
B(Jump), U8(19),
- B(Ldar), R(9),
+ B(Ldar), R(7),
B(ReThrow),
B(LdaFalse),
- B(Star), R(15),
- B(Mov), R(0), R(13),
- B(Mov), R(9), R(14),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(13), U8(3),
+ B(Star), R(13),
+ B(Mov), R(0), R(11),
+ B(Mov), R(7), R(12),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(11), U8(3),
/* 96 S> */ B(Return),
B(LdaUndefined),
B(Star), R(4),
@@ -639,7 +629,7 @@ bytecodes: [
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(3), U8(3),
/* 96 S> */ B(Return),
B(Star), R(3),
- B(CreateCatchContext), R(3), U8(11),
+ B(CreateCatchContext), R(3), U8(10),
B(Star), R(2),
B(LdaTheHole),
B(SetPendingMessage),
@@ -656,7 +646,6 @@ bytecodes: [
constant pool: [
OBJECT_BOILERPLATE_DESCRIPTION_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -668,8 +657,8 @@ constant pool: [
SCOPE_INFO_TYPE,
]
handlers: [
- [16, 233, 233],
- [59, 112, 120],
- [146, 179, 181],
+ [16, 230, 230],
+ [58, 111, 119],
+ [143, 176, 178],
]
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/ForIn.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/ForIn.golden
index 8c24e461cd..fe1defeefb 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/ForIn.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/ForIn.golden
@@ -63,13 +63,12 @@ snippet: "
"
frame size: 8
parameter count: 1
-bytecode array length: 46
+bytecode array length: 44
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0),
B(Star), R(0),
- /* 68 S> */ B(JumpIfUndefined), U8(39),
- B(JumpIfNull), U8(37),
+ /* 68 S> */ B(JumpIfUndefinedOrNull), U8(37),
B(ToObject), R(3),
B(ForInEnumerate), R(3),
B(ForInPrepare), R(4), U8(0),
@@ -102,14 +101,13 @@ snippet: "
"
frame size: 9
parameter count: 1
-bytecode array length: 58
+bytecode array length: 56
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaZero),
B(Star), R(0),
/* 59 S> */ B(CreateArrayLiteral), U8(0), U8(1), U8(37),
- B(JumpIfUndefined), U8(48),
- B(JumpIfNull), U8(46),
+ B(JumpIfUndefinedOrNull), U8(46),
B(ToObject), R(3),
B(ForInEnumerate), R(3),
B(ForInPrepare), R(4), U8(0),
@@ -148,14 +146,13 @@ snippet: "
"
frame size: 7
parameter count: 1
-bytecode array length: 85
+bytecode array length: 83
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(41),
B(Star), R(0),
/* 77 S> */ B(CreateArrayLiteral), U8(1), U8(2), U8(37),
- B(JumpIfUndefined), U8(72),
- B(JumpIfNull), U8(70),
+ B(JumpIfUndefinedOrNull), U8(70),
B(ToObject), R(1),
B(ForInEnumerate), R(1),
B(ForInPrepare), R(2), U8(1),
@@ -202,14 +199,13 @@ snippet: "
"
frame size: 9
parameter count: 1
-bytecode array length: 64
+bytecode array length: 62
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(0),
/* 72 S> */ B(CreateArrayLiteral), U8(1), U8(2), U8(37),
- B(JumpIfUndefined), U8(51),
- B(JumpIfNull), U8(49),
+ B(JumpIfUndefinedOrNull), U8(49),
B(ToObject), R(1),
B(ForInEnumerate), R(1),
B(ForInPrepare), R(2), U8(1),
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/ForOf.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/ForOf.golden
index 17e1d59343..1557e8d2a8 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/ForOf.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/ForOf.golden
@@ -9,90 +9,88 @@ wrap: yes
snippet: "
for (var p of [0, 1, 2]) {}
"
-frame size: 15
+frame size: 13
parameter count: 1
-bytecode array length: 173
+bytecode array length: 170
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 48 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(4),
- B(LdaNamedProperty), R(4), U8(1), U8(1),
+ B(GetIterator), R(4), U8(1),
B(Star), R(5),
B(CallProperty0), R(5), R(4), U8(3),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(3),
- B(LdaNamedProperty), R(3), U8(2), U8(5),
+ B(LdaNamedProperty), R(3), U8(1), U8(5),
B(Star), R(2),
B(LdaFalse),
- B(Star), R(6),
- B(Mov), R(context), R(9),
+ B(Star), R(4),
+ B(Mov), R(context), R(7),
B(LdaTrue),
- B(Star), R(6),
+ B(Star), R(4),
/* 43 S> */ B(CallProperty0), R(2), R(3), U8(7),
- B(Star), R(10),
+ B(Star), R(8),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
- B(LdaNamedProperty), R(10), U8(3), U8(9),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
+ B(LdaNamedProperty), R(8), U8(2), U8(9),
B(JumpIfToBooleanTrue), U8(23),
- B(LdaNamedProperty), R(10), U8(4), U8(11),
- B(Star), R(10),
+ B(LdaNamedProperty), R(8), U8(3), U8(11),
+ B(Star), R(8),
B(LdaFalse),
- B(Star), R(6),
- B(Mov), R(10), R(1),
+ B(Star), R(4),
+ B(Mov), R(8), R(1),
/* 34 E> */ B(StackCheck),
/* 43 S> */ B(Mov), R(1), R(0),
- B(Ldar), R(10),
+ B(Ldar), R(8),
B(JumpLoop), U8(40), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(8),
- B(Star), R(7),
+ B(Star), R(6),
+ B(Star), R(5),
B(Jump), U8(7),
- B(Star), R(8),
+ B(Star), R(6),
B(LdaZero),
- B(Star), R(7),
+ B(Star), R(5),
B(LdaTheHole),
/* 43 E> */ B(SetPendingMessage),
+ B(Star), R(7),
+ B(Ldar), R(4),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(3), U8(4), U8(13),
B(Star), R(9),
- B(Ldar), R(6),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(3), U8(5), U8(13),
- B(Star), R(11),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(12),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(10),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(13),
- B(LdaConstant), U8(6),
- B(Star), R(14),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(13), U8(2),
+ B(Star), R(11),
+ B(LdaConstant), U8(5),
+ B(Star), R(12),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(11), U8(2),
B(Throw),
- B(CallProperty0), R(11), R(3), U8(15),
+ B(CallProperty0), R(9), R(3), U8(15),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(13),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
+ B(Star), R(11),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
B(Jump), U8(12),
- B(Star), R(12),
+ B(Star), R(10),
B(LdaZero),
- B(TestReferenceEqual), R(7),
+ B(TestReferenceEqual), R(5),
B(JumpIfTrue), U8(5),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(ReThrow),
- B(Ldar), R(9),
+ B(Ldar), R(7),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(7),
+ B(TestReferenceEqual), R(5),
B(JumpIfFalse), U8(5),
- B(Ldar), R(8),
+ B(Ldar), R(6),
B(ReThrow),
B(LdaUndefined),
/* 62 S> */ B(Return),
]
constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -100,8 +98,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [38, 81, 89],
- [115, 148, 150],
+ [37, 80, 88],
+ [112, 145, 147],
]
---
@@ -109,95 +107,92 @@ snippet: "
var x = 'potatoes';
for (var p of x) { return p; }
"
-frame size: 16
+frame size: 14
parameter count: 1
-bytecode array length: 184
+bytecode array length: 178
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0),
B(Star), R(0),
- /* 68 S> */ B(LdaNamedProperty), R(0), U8(1), U8(0),
+ /* 68 S> */ B(GetIterator), R(0), U8(0),
B(Star), R(6),
B(CallProperty0), R(6), R(0), U8(2),
- B(Mov), R(0), R(5),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(4),
- B(LdaNamedProperty), R(4), U8(2), U8(4),
+ B(LdaNamedProperty), R(4), U8(1), U8(4),
B(Star), R(3),
B(LdaFalse),
- B(Star), R(7),
- B(Mov), R(context), R(10),
+ B(Star), R(5),
+ B(Mov), R(context), R(8),
B(LdaTrue),
- B(Star), R(7),
+ B(Star), R(5),
/* 63 S> */ B(CallProperty0), R(3), R(4), U8(6),
- B(Star), R(11),
+ B(Star), R(9),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
- B(LdaNamedProperty), R(11), U8(3), U8(8),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(9), U8(1),
+ B(LdaNamedProperty), R(9), U8(2), U8(8),
B(JumpIfToBooleanTrue), U8(27),
- B(LdaNamedProperty), R(11), U8(4), U8(10),
- B(Star), R(11),
+ B(LdaNamedProperty), R(9), U8(3), U8(10),
+ B(Star), R(9),
B(LdaFalse),
- B(Star), R(7),
- B(Mov), R(11), R(2),
+ B(Star), R(5),
+ B(Mov), R(9), R(2),
/* 54 E> */ B(StackCheck),
/* 63 S> */ B(Mov), R(2), R(1),
/* 73 S> */ B(LdaSmi), I8(1),
- B(Mov), R(11), R(9),
- B(Star), R(8),
+ B(Mov), R(9), R(7),
+ B(Star), R(6),
B(Jump), U8(15),
B(LdaSmi), I8(-1),
- B(Star), R(9),
- B(Star), R(8),
+ B(Star), R(7),
+ B(Star), R(6),
B(Jump), U8(7),
- B(Star), R(9),
+ B(Star), R(7),
B(LdaZero),
- B(Star), R(8),
+ B(Star), R(6),
B(LdaTheHole),
B(SetPendingMessage),
+ B(Star), R(8),
+ B(Ldar), R(5),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(4), U8(4), U8(12),
B(Star), R(10),
- B(Ldar), R(7),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(4), U8(5), U8(12),
- B(Star), R(12),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(13),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(11),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(14),
- B(LdaConstant), U8(6),
- B(Star), R(15),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(14), U8(2),
+ B(Star), R(12),
+ B(LdaConstant), U8(5),
+ B(Star), R(13),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2),
B(Throw),
- B(CallProperty0), R(12), R(4), U8(14),
+ B(CallProperty0), R(10), R(4), U8(14),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(14),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
+ B(Star), R(12),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
B(Jump), U8(12),
- B(Star), R(13),
+ B(Star), R(11),
B(LdaZero),
- B(TestReferenceEqual), R(8),
+ B(TestReferenceEqual), R(6),
B(JumpIfTrue), U8(5),
- B(Ldar), R(13),
+ B(Ldar), R(11),
B(ReThrow),
- B(Ldar), R(10),
- B(SetPendingMessage),
B(Ldar), R(8),
- B(SwitchOnSmiNoFeedback), U8(7), U8(2), I8(0),
+ B(SetPendingMessage),
+ B(Ldar), R(6),
+ B(SwitchOnSmiNoFeedback), U8(6), U8(2), I8(0),
B(Jump), U8(8),
- B(Ldar), R(9),
+ B(Ldar), R(7),
B(ReThrow),
- B(Ldar), R(9),
+ B(Ldar), R(7),
/* 85 S> */ B(Return),
B(LdaUndefined),
/* 85 S> */ B(Return),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["potatoes"],
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -207,8 +202,8 @@ constant pool: [
Smi [9],
]
handlers: [
- [39, 86, 94],
- [120, 153, 155],
+ [35, 82, 90],
+ [114, 147, 149],
]
---
@@ -218,37 +213,37 @@ snippet: "
if (x == 20) break;
}
"
-frame size: 15
+frame size: 13
parameter count: 1
-bytecode array length: 189
+bytecode array length: 186
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 48 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star), R(4),
- B(LdaNamedProperty), R(4), U8(1), U8(1),
+ B(GetIterator), R(4), U8(1),
B(Star), R(5),
B(CallProperty0), R(5), R(4), U8(3),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(3),
- B(LdaNamedProperty), R(3), U8(2), U8(5),
+ B(LdaNamedProperty), R(3), U8(1), U8(5),
B(Star), R(2),
B(LdaFalse),
- B(Star), R(6),
- B(Mov), R(context), R(9),
+ B(Star), R(4),
+ B(Mov), R(context), R(7),
B(LdaTrue),
- B(Star), R(6),
+ B(Star), R(4),
/* 43 S> */ B(CallProperty0), R(2), R(3), U8(7),
- B(Star), R(10),
+ B(Star), R(8),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
- B(LdaNamedProperty), R(10), U8(3), U8(9),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
+ B(LdaNamedProperty), R(8), U8(2), U8(9),
B(JumpIfToBooleanTrue), U8(39),
- B(LdaNamedProperty), R(10), U8(4), U8(11),
- B(Star), R(10),
+ B(LdaNamedProperty), R(8), U8(3), U8(11),
+ B(Star), R(8),
B(LdaFalse),
- B(Star), R(6),
- B(Mov), R(10), R(1),
+ B(Star), R(4),
+ B(Mov), R(8), R(1),
/* 34 E> */ B(StackCheck),
/* 43 S> */ B(Mov), R(1), R(0),
/* 66 S> */ B(LdaSmi), I8(10),
@@ -261,54 +256,52 @@ bytecodes: [
/* 104 S> */ B(Jump), U8(5),
B(JumpLoop), U8(56), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(8),
- B(Star), R(7),
+ B(Star), R(6),
+ B(Star), R(5),
B(Jump), U8(7),
- B(Star), R(8),
+ B(Star), R(6),
B(LdaZero),
- B(Star), R(7),
+ B(Star), R(5),
B(LdaTheHole),
B(SetPendingMessage),
+ B(Star), R(7),
+ B(Ldar), R(4),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(3), U8(4), U8(15),
B(Star), R(9),
- B(Ldar), R(6),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(3), U8(5), U8(15),
- B(Star), R(11),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(12),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(10),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(13),
- B(LdaConstant), U8(6),
- B(Star), R(14),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(13), U8(2),
+ B(Star), R(11),
+ B(LdaConstant), U8(5),
+ B(Star), R(12),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(11), U8(2),
B(Throw),
- B(CallProperty0), R(11), R(3), U8(17),
+ B(CallProperty0), R(9), R(3), U8(17),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(13),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
+ B(Star), R(11),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
B(Jump), U8(12),
- B(Star), R(12),
+ B(Star), R(10),
B(LdaZero),
- B(TestReferenceEqual), R(7),
+ B(TestReferenceEqual), R(5),
B(JumpIfTrue), U8(5),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(ReThrow),
- B(Ldar), R(9),
+ B(Ldar), R(7),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(7),
+ B(TestReferenceEqual), R(5),
B(JumpIfFalse), U8(5),
- B(Ldar), R(8),
+ B(Ldar), R(6),
B(ReThrow),
B(LdaUndefined),
/* 113 S> */ B(Return),
]
constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -316,8 +309,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [38, 97, 105],
- [131, 164, 166],
+ [37, 96, 104],
+ [128, 161, 163],
]
---
@@ -325,91 +318,90 @@ snippet: "
var x = { 'a': 1, 'b': 2 };
for (x['a'] of [1,2,3]) { return x['a']; }
"
-frame size: 15
+frame size: 13
parameter count: 1
-bytecode array length: 195
+bytecode array length: 192
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(41),
B(Star), R(0),
/* 77 S> */ B(CreateArrayLiteral), U8(1), U8(1), U8(37),
B(Star), R(3),
- B(LdaNamedProperty), R(3), U8(2), U8(2),
+ B(GetIterator), R(3), U8(2),
B(Star), R(4),
B(CallProperty0), R(4), R(3), U8(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(2),
- B(LdaNamedProperty), R(2), U8(3), U8(6),
+ B(LdaNamedProperty), R(2), U8(2), U8(6),
B(Star), R(1),
B(LdaFalse),
- B(Star), R(5),
- B(Mov), R(context), R(8),
+ B(Star), R(3),
+ B(Mov), R(context), R(6),
B(LdaTrue),
- B(Star), R(5),
+ B(Star), R(3),
/* 68 S> */ B(CallProperty0), R(1), R(2), U8(8),
- B(Star), R(9),
+ B(Star), R(7),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(9), U8(1),
- B(LdaNamedProperty), R(9), U8(4), U8(10),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(7), U8(1),
+ B(LdaNamedProperty), R(7), U8(3), U8(10),
B(JumpIfToBooleanTrue), U8(33),
- B(LdaNamedProperty), R(9), U8(5), U8(12),
- B(Star), R(9),
+ B(LdaNamedProperty), R(7), U8(4), U8(12),
+ B(Star), R(7),
B(LdaFalse),
- B(Star), R(5),
- B(Ldar), R(9),
- /* 67 E> */ B(StaNamedProperty), R(0), U8(6), U8(14),
+ B(Star), R(3),
+ B(Ldar), R(7),
+ /* 67 E> */ B(StaNamedProperty), R(0), U8(5), U8(14),
/* 62 E> */ B(StackCheck),
- /* 96 S> */ B(LdaNamedProperty), R(0), U8(6), U8(16),
- B(Star), R(7),
+ /* 96 S> */ B(LdaNamedProperty), R(0), U8(5), U8(16),
+ B(Star), R(5),
B(LdaSmi), I8(1),
- B(Star), R(6),
- B(Mov), R(0), R(10),
+ B(Star), R(4),
+ B(Mov), R(0), R(8),
B(Jump), U8(15),
B(LdaSmi), I8(-1),
- B(Star), R(7),
- B(Star), R(6),
+ B(Star), R(5),
+ B(Star), R(4),
B(Jump), U8(7),
- B(Star), R(7),
+ B(Star), R(5),
B(LdaZero),
- B(Star), R(6),
+ B(Star), R(4),
B(LdaTheHole),
B(SetPendingMessage),
- B(Star), R(8),
- B(Ldar), R(5),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(2), U8(7), U8(18),
- B(Star), R(11),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(12),
+ B(Star), R(6),
+ B(Ldar), R(3),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(2), U8(6), U8(18),
+ B(Star), R(9),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(10),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(13),
- B(LdaConstant), U8(8),
- B(Star), R(14),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(13), U8(2),
+ B(Star), R(11),
+ B(LdaConstant), U8(7),
+ B(Star), R(12),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(11), U8(2),
B(Throw),
- B(CallProperty0), R(11), R(2), U8(20),
+ B(CallProperty0), R(9), R(2), U8(20),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(13),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
+ B(Star), R(11),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
B(Jump), U8(12),
- B(Star), R(12),
+ B(Star), R(10),
B(LdaZero),
- B(TestReferenceEqual), R(6),
+ B(TestReferenceEqual), R(4),
B(JumpIfTrue), U8(5),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(ReThrow),
- B(Ldar), R(8),
- B(SetPendingMessage),
B(Ldar), R(6),
- B(SwitchOnSmiNoFeedback), U8(9), U8(2), I8(0),
+ B(SetPendingMessage),
+ B(Ldar), R(4),
+ B(SwitchOnSmiNoFeedback), U8(8), U8(2), I8(0),
B(Jump), U8(8),
- B(Ldar), R(7),
+ B(Ldar), R(5),
B(ReThrow),
- B(Ldar), R(7),
+ B(Ldar), R(5),
/* 105 S> */ B(Return),
B(LdaUndefined),
/* 105 S> */ B(Return),
@@ -417,7 +409,6 @@ bytecodes: [
constant pool: [
OBJECT_BOILERPLATE_DESCRIPTION_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -428,7 +419,7 @@ constant pool: [
Smi [9],
]
handlers: [
- [44, 97, 105],
- [131, 164, 166],
+ [43, 96, 104],
+ [128, 161, 163],
]
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden
index 1b10e1bf6e..f50891172e 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden
@@ -13,89 +13,86 @@ snippet: "
}
f([1, 2, 3]);
"
-frame size: 17
+frame size: 15
parameter count: 2
-bytecode array length: 173
+bytecode array length: 167
bytecodes: [
/* 10 E> */ B(StackCheck),
- /* 34 S> */ B(LdaNamedProperty), R(arg0), U8(0), U8(0),
+ /* 34 S> */ B(GetIterator), R(arg0), U8(0),
B(Star), R(7),
B(CallProperty0), R(7), R(arg0), U8(2),
- B(Mov), R(arg0), R(6),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(5),
- B(LdaNamedProperty), R(5), U8(1), U8(4),
+ B(LdaNamedProperty), R(5), U8(0), U8(4),
B(Star), R(4),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(context), R(11),
+ B(Star), R(6),
+ B(Mov), R(context), R(9),
B(LdaTrue),
- B(Star), R(8),
+ B(Star), R(6),
/* 29 S> */ B(CallProperty0), R(4), R(5), U8(6),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(2), U8(8),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(1), U8(8),
B(JumpIfToBooleanTrue), U8(26),
- B(LdaNamedProperty), R(12), U8(3), U8(10),
- B(Star), R(12),
+ B(LdaNamedProperty), R(10), U8(2), U8(10),
+ B(Star), R(10),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(12), R(0),
+ B(Star), R(6),
+ B(Mov), R(10), R(0),
/* 20 E> */ B(StackCheck),
/* 29 S> */ B(Mov), R(0), R(2),
/* 49 S> */ B(Mov), R(2), R(3),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(JumpLoop), U8(43), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(10),
- B(Star), R(9),
+ B(Star), R(8),
+ B(Star), R(7),
B(Jump), U8(7),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaZero),
- B(Star), R(9),
+ B(Star), R(7),
B(LdaTheHole),
/* 49 E> */ B(SetPendingMessage),
+ B(Star), R(9),
+ B(Ldar), R(6),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(5), U8(3), U8(12),
B(Star), R(11),
- B(Ldar), R(8),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(5), U8(4), U8(12),
- B(Star), R(13),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(14),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(12),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(15),
- B(LdaConstant), U8(5),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(15), U8(2),
+ B(Star), R(13),
+ B(LdaConstant), U8(4),
+ B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(13), U8(2),
B(Throw),
- B(CallProperty0), R(13), R(5), U8(14),
+ B(CallProperty0), R(11), R(5), U8(14),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(15),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(15), U8(1),
+ B(Star), R(13),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
B(Jump), U8(12),
- B(Star), R(14),
+ B(Star), R(12),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(11),
+ B(Ldar), R(9),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfFalse), U8(5),
- B(Ldar), R(10),
+ B(Ldar), R(8),
B(ReThrow),
B(LdaUndefined),
/* 54 S> */ B(Return),
]
constant pool: [
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -103,8 +100,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [35, 81, 89],
- [115, 148, 150],
+ [31, 77, 85],
+ [109, 142, 144],
]
---
@@ -114,9 +111,9 @@ snippet: "
}
f([1, 2, 3]);
"
-frame size: 22
+frame size: 20
parameter count: 2
-bytecode array length: 254
+bytecode array length: 251
bytecodes: [
B(CreateFunctionContext), U8(0), U8(4),
B(PushContext), R(2),
@@ -135,98 +132,97 @@ bytecodes: [
B(StaCurrentContextSlot), U8(4),
/* 34 S> */ B(LdaContextSlot), R(3), U8(4), U8(0),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(2), U8(0),
+ B(GetIterator), R(6), U8(0),
B(Star), R(7),
B(CallProperty0), R(7), R(6), U8(2),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(5),
- B(LdaNamedProperty), R(5), U8(3), U8(4),
+ B(LdaNamedProperty), R(5), U8(2), U8(4),
B(Star), R(4),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(context), R(11),
+ B(Star), R(6),
+ B(Mov), R(context), R(9),
B(LdaTrue),
- B(Star), R(8),
+ B(Star), R(6),
/* 29 S> */ B(CallProperty0), R(4), R(5), U8(6),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(4), U8(8),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(3), U8(8),
B(JumpIfToBooleanTrue), U8(75),
- B(LdaNamedProperty), R(12), U8(5), U8(10),
- B(Star), R(12),
+ B(LdaNamedProperty), R(10), U8(4), U8(10),
+ B(Star), R(10),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(12), R(0),
+ B(Star), R(6),
+ B(Mov), R(10), R(0),
/* 20 E> */ B(StackCheck),
- B(CreateBlockContext), U8(6),
- B(PushContext), R(13),
+ B(CreateBlockContext), U8(5),
+ B(PushContext), R(11),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
/* 29 S> */ B(Ldar), R(0),
/* 29 E> */ B(StaCurrentContextSlot), U8(4),
- /* 41 S> */ B(LdaLookupGlobalSlot), U8(7), U8(12), U8(3),
- B(Star), R(14),
- B(LdaConstant), U8(8),
- B(Star), R(15),
+ /* 41 S> */ B(LdaLookupGlobalSlot), U8(6), U8(12), U8(3),
+ B(Star), R(12),
+ B(LdaConstant), U8(7),
+ B(Star), R(13),
B(LdaZero),
- B(Star), R(19),
+ B(Star), R(17),
B(LdaSmi), I8(37),
- B(Star), R(20),
+ B(Star), R(18),
B(LdaSmi), I8(41),
- B(Star), R(21),
- B(Mov), R(14), R(16),
- B(Mov), R(15), R(17),
- B(Mov), R(closure), R(18),
- B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(16), U8(6),
- B(Star), R(14),
- /* 41 E> */ B(CallUndefinedReceiver1), R(14), R(15), U8(14),
- B(PopContext), R(13),
- B(Mov), R(0), R(12),
+ B(Star), R(19),
+ B(Mov), R(12), R(14),
+ B(Mov), R(13), R(15),
+ B(Mov), R(closure), R(16),
+ B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(14), U8(6),
+ B(Star), R(12),
+ /* 41 E> */ B(CallUndefinedReceiver1), R(12), R(13), U8(14),
+ B(PopContext), R(11),
+ B(Mov), R(0), R(10),
B(JumpLoop), U8(92), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(10),
- B(Star), R(9),
+ B(Star), R(8),
+ B(Star), R(7),
B(Jump), U8(7),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaZero),
- B(Star), R(9),
+ B(Star), R(7),
B(LdaTheHole),
B(SetPendingMessage),
- B(Star), R(11),
- B(Ldar), R(8),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(5), U8(9), U8(16),
- B(Star), R(14),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(15),
+ B(Star), R(9),
+ B(Ldar), R(6),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(5), U8(8), U8(16),
+ B(Star), R(12),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(13),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(16),
- B(LdaConstant), U8(10),
- B(Star), R(17),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(16), U8(2),
+ B(Star), R(14),
+ B(LdaConstant), U8(9),
+ B(Star), R(15),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(14), U8(2),
B(Throw),
- B(CallProperty0), R(14), R(5), U8(18),
+ B(CallProperty0), R(12), R(5), U8(18),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(16), U8(1),
+ B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
B(Jump), U8(12),
- B(Star), R(15),
+ B(Star), R(13),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfTrue), U8(5),
- B(Ldar), R(15),
+ B(Ldar), R(13),
B(ReThrow),
- B(Ldar), R(11),
+ B(Ldar), R(9),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfFalse), U8(5),
- B(Ldar), R(10),
+ B(Ldar), R(8),
B(ReThrow),
B(PopContext), R(3),
B(LdaUndefined),
@@ -235,7 +231,6 @@ bytecodes: [
constant pool: [
SCOPE_INFO_TYPE,
SCOPE_INFO_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -246,8 +241,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [65, 160, 168],
- [194, 227, 229],
+ [64, 159, 167],
+ [191, 224, 226],
]
---
@@ -257,97 +252,94 @@ snippet: "
}
f([1, 2, 3]);
"
-frame size: 16
+frame size: 14
parameter count: 2
-bytecode array length: 190
+bytecode array length: 184
bytecodes: [
/* 10 E> */ B(StackCheck),
- /* 34 S> */ B(LdaNamedProperty), R(arg0), U8(0), U8(0),
+ /* 34 S> */ B(GetIterator), R(arg0), U8(0),
B(Star), R(5),
B(CallProperty0), R(5), R(arg0), U8(2),
- B(Mov), R(arg0), R(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(3),
- B(LdaNamedProperty), R(3), U8(1), U8(4),
+ B(LdaNamedProperty), R(3), U8(0), U8(4),
B(Star), R(2),
B(LdaFalse),
- B(Star), R(6),
- B(Mov), R(context), R(9),
+ B(Star), R(4),
+ B(Mov), R(context), R(7),
B(LdaTrue),
- B(Star), R(6),
+ B(Star), R(4),
/* 29 S> */ B(CallProperty0), R(2), R(3), U8(6),
- B(Star), R(10),
+ B(Star), R(8),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
- B(LdaNamedProperty), R(10), U8(2), U8(8),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
+ B(LdaNamedProperty), R(8), U8(1), U8(8),
B(JumpIfToBooleanTrue), U8(43),
- B(LdaNamedProperty), R(10), U8(3), U8(10),
- B(Star), R(10),
+ B(LdaNamedProperty), R(8), U8(2), U8(10),
+ B(Star), R(8),
B(LdaFalse),
- B(Star), R(6),
- B(Mov), R(10), R(0),
+ B(Star), R(4),
+ B(Mov), R(8), R(0),
/* 20 E> */ B(StackCheck),
- B(CreateBlockContext), U8(4),
- B(PushContext), R(11),
+ B(CreateBlockContext), U8(3),
+ B(PushContext), R(9),
B(LdaTheHole),
B(StaCurrentContextSlot), U8(4),
/* 29 S> */ B(Ldar), R(0),
/* 29 E> */ B(StaCurrentContextSlot), U8(4),
- /* 41 S> */ B(CreateClosure), U8(5), U8(0), U8(2),
- B(Star), R(12),
- /* 67 E> */ B(CallUndefinedReceiver0), R(12), U8(12),
- B(PopContext), R(11),
- B(Mov), R(0), R(10),
+ /* 41 S> */ B(CreateClosure), U8(4), U8(0), U8(2),
+ B(Star), R(10),
+ /* 67 E> */ B(CallUndefinedReceiver0), R(10), U8(12),
+ B(PopContext), R(9),
+ B(Mov), R(0), R(8),
B(JumpLoop), U8(60), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(8),
- B(Star), R(7),
+ B(Star), R(6),
+ B(Star), R(5),
B(Jump), U8(7),
- B(Star), R(8),
+ B(Star), R(6),
B(LdaZero),
- B(Star), R(7),
+ B(Star), R(5),
B(LdaTheHole),
B(SetPendingMessage),
- B(Star), R(9),
- B(Ldar), R(6),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(3), U8(6), U8(14),
- B(Star), R(12),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(13),
+ B(Star), R(7),
+ B(Ldar), R(4),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(3), U8(5), U8(14),
+ B(Star), R(10),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(11),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(14),
- B(LdaConstant), U8(7),
- B(Star), R(15),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(14), U8(2),
+ B(Star), R(12),
+ B(LdaConstant), U8(6),
+ B(Star), R(13),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2),
B(Throw),
- B(CallProperty0), R(12), R(3), U8(16),
+ B(CallProperty0), R(10), R(3), U8(16),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(14),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
+ B(Star), R(12),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
B(Jump), U8(12),
- B(Star), R(13),
+ B(Star), R(11),
B(LdaZero),
- B(TestReferenceEqual), R(7),
+ B(TestReferenceEqual), R(5),
B(JumpIfTrue), U8(5),
- B(Ldar), R(13),
+ B(Ldar), R(11),
B(ReThrow),
- B(Ldar), R(9),
+ B(Ldar), R(7),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(7),
+ B(TestReferenceEqual), R(5),
B(JumpIfFalse), U8(5),
- B(Ldar), R(8),
+ B(Ldar), R(6),
B(ReThrow),
B(LdaUndefined),
/* 73 S> */ B(Return),
]
constant pool: [
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -357,8 +349,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [35, 98, 106],
- [132, 165, 167],
+ [31, 94, 102],
+ [126, 159, 161],
]
---
@@ -368,98 +360,90 @@ snippet: "
}
f([{ x: 0, y: 3 }, { x: 1, y: 9 }, { x: -12, y: 17 }]);
"
-frame size: 19
+frame size: 17
parameter count: 2
-bytecode array length: 197
+bytecode array length: 178
bytecodes: [
/* 10 E> */ B(StackCheck),
- /* 41 S> */ B(LdaNamedProperty), R(arg0), U8(0), U8(0),
+ /* 41 S> */ B(GetIterator), R(arg0), U8(0),
B(Star), R(9),
B(CallProperty0), R(9), R(arg0), U8(2),
- B(Mov), R(arg0), R(8),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(7),
- B(LdaNamedProperty), R(7), U8(1), U8(4),
+ B(LdaNamedProperty), R(7), U8(0), U8(4),
B(Star), R(6),
B(LdaFalse),
- B(Star), R(10),
- B(Mov), R(context), R(13),
+ B(Star), R(8),
+ B(Mov), R(context), R(11),
B(LdaTrue),
- B(Star), R(10),
+ B(Star), R(8),
/* 36 S> */ B(CallProperty0), R(6), R(7), U8(6),
- B(Star), R(14),
+ B(Star), R(12),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
- B(LdaNamedProperty), R(14), U8(2), U8(8),
- B(JumpIfToBooleanTrue), U8(50),
- B(LdaNamedProperty), R(14), U8(3), U8(10),
- B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
+ B(LdaNamedProperty), R(12), U8(1), U8(8),
+ B(JumpIfToBooleanTrue), U8(37),
+ B(LdaNamedProperty), R(12), U8(2), U8(10),
+ B(Star), R(12),
B(LdaFalse),
- B(Star), R(10),
- B(Mov), R(14), R(0),
+ B(Star), R(8),
+ B(Mov), R(12), R(0),
/* 20 E> */ B(StackCheck),
- /* 36 S> */ B(Ldar), R(14),
- B(JumpIfNull), U8(4),
- B(JumpIfNotUndefined), U8(7),
- /* 29 E> */ B(CallRuntime), U16(Runtime::kThrowPatternAssignmentNonCoercible), R(0), U8(0),
- B(Star), R(15),
- /* 31 S> */ B(LdaNamedProperty), R(15), U8(4), U8(12),
+ /* 31 S> */ B(LdaNamedProperty), R(0), U8(3), U8(12),
B(Star), R(3),
- /* 34 S> */ B(LdaNamedProperty), R(15), U8(5), U8(14),
+ /* 34 S> */ B(LdaNamedProperty), R(0), U8(4), U8(14),
B(Star), R(4),
/* 56 S> */ B(Ldar), R(4),
/* 58 E> */ B(Add), R(3), U8(16),
B(Star), R(5),
- B(JumpLoop), U8(67), I8(0),
+ B(JumpLoop), U8(54), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(12),
- B(Star), R(11),
+ B(Star), R(10),
+ B(Star), R(9),
B(Jump), U8(7),
- B(Star), R(12),
+ B(Star), R(10),
B(LdaZero),
- B(Star), R(11),
+ B(Star), R(9),
B(LdaTheHole),
/* 56 E> */ B(SetPendingMessage),
+ B(Star), R(11),
+ B(Ldar), R(8),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(7), U8(5), U8(17),
B(Star), R(13),
- B(Ldar), R(10),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(7), U8(6), U8(17),
- B(Star), R(15),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(16),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(14),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(17),
- B(LdaConstant), U8(7),
- B(Star), R(18),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(17), U8(2),
+ B(Star), R(15),
+ B(LdaConstant), U8(6),
+ B(Star), R(16),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(15), U8(2),
B(Throw),
- B(CallProperty0), R(15), R(7), U8(19),
+ B(CallProperty0), R(13), R(7), U8(19),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(17),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(17), U8(1),
+ B(Star), R(15),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(15), U8(1),
B(Jump), U8(12),
- B(Star), R(16),
+ B(Star), R(14),
B(LdaZero),
- B(TestReferenceEqual), R(11),
+ B(TestReferenceEqual), R(9),
B(JumpIfTrue), U8(5),
- B(Ldar), R(16),
+ B(Ldar), R(14),
B(ReThrow),
- B(Ldar), R(13),
+ B(Ldar), R(11),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(11),
+ B(TestReferenceEqual), R(9),
B(JumpIfFalse), U8(5),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(ReThrow),
B(LdaUndefined),
/* 65 S> */ B(Return),
]
constant pool: [
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -469,8 +453,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [35, 105, 113],
- [139, 172, 174],
+ [31, 88, 96],
+ [120, 153, 155],
]
---
@@ -480,9 +464,9 @@ snippet: "
}
f([1, 2, 3]);
"
-frame size: 18
+frame size: 16
parameter count: 2
-bytecode array length: 214
+bytecode array length: 208
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(1),
B(Mov), R(closure), R(5),
@@ -499,78 +483,76 @@ bytecodes: [
/* 11 E> */ B(Throw),
B(Ldar), R(5),
/* 55 S> */ B(Return),
- /* 35 S> */ B(LdaNamedProperty), R(arg0), U8(3), U8(0),
+ /* 35 S> */ B(GetIterator), R(arg0), U8(0),
B(Star), R(8),
B(CallProperty0), R(8), R(arg0), U8(2),
- B(Mov), R(arg0), R(7),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(4), U8(4),
+ B(LdaNamedProperty), R(6), U8(3), U8(4),
B(Star), R(5),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(context), R(12),
+ B(Star), R(7),
+ B(Mov), R(context), R(10),
B(LdaTrue),
- B(Star), R(9),
+ B(Star), R(7),
/* 30 S> */ B(CallProperty0), R(5), R(6), U8(6),
- B(Star), R(13),
+ B(Star), R(11),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
- B(LdaNamedProperty), R(13), U8(5), U8(8),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
+ B(LdaNamedProperty), R(11), U8(4), U8(8),
B(JumpIfToBooleanTrue), U8(26),
- B(LdaNamedProperty), R(13), U8(6), U8(10),
- B(Star), R(13),
+ B(LdaNamedProperty), R(11), U8(5), U8(10),
+ B(Star), R(11),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(13), R(1),
+ B(Star), R(7),
+ B(Mov), R(11), R(1),
/* 21 E> */ B(StackCheck),
/* 30 S> */ B(Mov), R(1), R(3),
/* 50 S> */ B(Mov), R(3), R(4),
- B(Ldar), R(13),
+ B(Ldar), R(11),
B(JumpLoop), U8(43), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(11),
- B(Star), R(10),
+ B(Star), R(9),
+ B(Star), R(8),
B(Jump), U8(7),
- B(Star), R(11),
+ B(Star), R(9),
B(LdaZero),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaTheHole),
/* 50 E> */ B(SetPendingMessage),
+ B(Star), R(10),
+ B(Ldar), R(7),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(6), U8(6), U8(12),
B(Star), R(12),
- B(Ldar), R(9),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(6), U8(7), U8(12),
- B(Star), R(14),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(15),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(13),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(16),
- B(LdaConstant), U8(8),
- B(Star), R(17),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(16), U8(2),
+ B(Star), R(14),
+ B(LdaConstant), U8(7),
+ B(Star), R(15),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(14), U8(2),
B(Throw),
- B(CallProperty0), R(14), R(6), U8(14),
+ B(CallProperty0), R(12), R(6), U8(14),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(16), U8(1),
+ B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
B(Jump), U8(12),
- B(Star), R(15),
+ B(Star), R(13),
B(LdaZero),
- B(TestReferenceEqual), R(10),
+ B(TestReferenceEqual), R(8),
B(JumpIfTrue), U8(5),
- B(Ldar), R(15),
+ B(Ldar), R(13),
B(ReThrow),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(10),
+ B(TestReferenceEqual), R(8),
B(JumpIfFalse), U8(5),
- B(Ldar), R(11),
+ B(Ldar), R(9),
B(ReThrow),
B(LdaUndefined),
/* 55 S> */ B(Return),
@@ -579,7 +561,6 @@ constant pool: [
Smi [22],
Smi [10],
Smi [7],
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -587,8 +568,8 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
]
handlers: [
- [76, 122, 130],
- [156, 189, 191],
+ [72, 118, 126],
+ [150, 183, 185],
]
---
@@ -598,9 +579,9 @@ snippet: "
}
f([1, 2, 3]);
"
-frame size: 17
+frame size: 15
parameter count: 2
-bytecode array length: 258
+bytecode array length: 252
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(2),
B(Mov), R(closure), R(4),
@@ -617,104 +598,101 @@ bytecodes: [
/* 11 E> */ B(Throw),
B(Ldar), R(4),
/* 49 S> */ B(Return),
- /* 35 S> */ B(LdaNamedProperty), R(arg0), U8(4), U8(0),
+ /* 35 S> */ B(GetIterator), R(arg0), U8(0),
B(Star), R(7),
B(CallProperty0), R(7), R(arg0), U8(2),
- B(Mov), R(arg0), R(6),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(5),
- B(LdaNamedProperty), R(5), U8(5), U8(4),
+ B(LdaNamedProperty), R(5), U8(4), U8(4),
B(Star), R(4),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(context), R(11),
+ B(Star), R(6),
+ B(Mov), R(context), R(9),
B(LdaTrue),
- B(Star), R(8),
+ B(Star), R(6),
/* 30 S> */ B(CallProperty0), R(4), R(5), U8(6),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(6), U8(8),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(5), U8(8),
B(JumpIfToBooleanTrue), U8(64),
- B(LdaNamedProperty), R(12), U8(7), U8(10),
- B(Star), R(12),
+ B(LdaNamedProperty), R(10), U8(6), U8(10),
+ B(Star), R(10),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(12), R(1),
+ B(Star), R(6),
+ B(Mov), R(10), R(1),
/* 21 E> */ B(StackCheck),
/* 30 S> */ B(Mov), R(1), R(3),
/* 40 S> */ B(LdaFalse),
- B(Star), R(14),
- B(Mov), R(3), R(13),
- B(InvokeIntrinsic), U8(Runtime::k_CreateIterResultObject), R(13), U8(2),
- /* 40 E> */ B(SuspendGenerator), R(0), R(0), U8(13), U8(1),
- B(ResumeGenerator), R(0), R(0), U8(13),
- B(Star), R(13),
+ B(Star), R(12),
+ B(Mov), R(3), R(11),
+ B(InvokeIntrinsic), U8(Runtime::k_CreateIterResultObject), R(11), U8(2),
+ /* 40 E> */ B(SuspendGenerator), R(0), R(0), U8(11), U8(1),
+ B(ResumeGenerator), R(0), R(0), U8(11),
+ B(Star), R(11),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(SwitchOnSmiNoFeedback), U8(8), U8(2), I8(0),
- B(Ldar), R(13),
+ B(SwitchOnSmiNoFeedback), U8(7), U8(2), I8(0),
+ B(Ldar), R(11),
/* 40 E> */ B(Throw),
B(LdaSmi), I8(1),
- B(Star), R(9),
- B(Mov), R(13), R(10),
+ B(Star), R(7),
+ B(Mov), R(11), R(8),
B(Jump), U8(20),
- B(Ldar), R(13),
+ B(Ldar), R(11),
B(JumpLoop), U8(81), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(10),
- B(Star), R(9),
+ B(Star), R(8),
+ B(Star), R(7),
B(Jump), U8(7),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaZero),
- B(Star), R(9),
+ B(Star), R(7),
B(LdaTheHole),
B(SetPendingMessage),
+ B(Star), R(9),
+ B(Ldar), R(6),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(5), U8(9), U8(12),
B(Star), R(11),
- B(Ldar), R(8),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(5), U8(10), U8(12),
- B(Star), R(13),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(14),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(12),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(15),
- B(LdaConstant), U8(11),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(15), U8(2),
+ B(Star), R(13),
+ B(LdaConstant), U8(10),
+ B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(13), U8(2),
B(Throw),
- B(CallProperty0), R(13), R(5), U8(14),
+ B(CallProperty0), R(11), R(5), U8(14),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(15),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(15), U8(1),
+ B(Star), R(13),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
B(Jump), U8(12),
- B(Star), R(14),
+ B(Star), R(12),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(11),
- B(SetPendingMessage),
B(Ldar), R(9),
- B(SwitchOnSmiNoFeedback), U8(12), U8(2), I8(0),
+ B(SetPendingMessage),
+ B(Ldar), R(7),
+ B(SwitchOnSmiNoFeedback), U8(11), U8(2), I8(0),
B(Jump), U8(8),
- B(Ldar), R(10),
+ B(Ldar), R(8),
B(ReThrow),
- B(Ldar), R(10),
+ B(Ldar), R(8),
/* 49 S> */ B(Return),
B(LdaUndefined),
/* 49 S> */ B(Return),
]
constant pool: [
Smi [22],
- Smi [129],
+ Smi [125],
Smi [10],
Smi [7],
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -726,8 +704,8 @@ constant pool: [
Smi [9],
]
handlers: [
- [76, 160, 168],
- [194, 227, 229],
+ [72, 156, 164],
+ [188, 221, 223],
]
---
@@ -737,9 +715,9 @@ snippet: "
}
f([1, 2, 3]);
"
-frame size: 19
+frame size: 17
parameter count: 2
-bytecode array length: 228
+bytecode array length: 222
bytecodes: [
B(Mov), R(closure), R(5),
B(Mov), R(this), R(6),
@@ -747,78 +725,76 @@ bytecodes: [
B(Star), R(0),
/* 16 E> */ B(StackCheck),
B(Mov), R(context), R(5),
- /* 40 S> */ B(LdaNamedProperty), R(arg0), U8(0), U8(0),
+ /* 40 S> */ B(GetIterator), R(arg0), U8(0),
B(Star), R(9),
B(CallProperty0), R(9), R(arg0), U8(2),
- B(Mov), R(arg0), R(8),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(7),
- B(LdaNamedProperty), R(7), U8(1), U8(4),
+ B(LdaNamedProperty), R(7), U8(0), U8(4),
B(Star), R(6),
B(LdaFalse),
- B(Star), R(10),
- B(Mov), R(context), R(13),
+ B(Star), R(8),
+ B(Mov), R(context), R(11),
B(LdaTrue),
- B(Star), R(10),
+ B(Star), R(8),
/* 35 S> */ B(CallProperty0), R(6), R(7), U8(6),
- B(Star), R(14),
+ B(Star), R(12),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
- B(LdaNamedProperty), R(14), U8(2), U8(8),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
+ B(LdaNamedProperty), R(12), U8(1), U8(8),
B(JumpIfToBooleanTrue), U8(26),
- B(LdaNamedProperty), R(14), U8(3), U8(10),
- B(Star), R(14),
+ B(LdaNamedProperty), R(12), U8(2), U8(10),
+ B(Star), R(12),
B(LdaFalse),
- B(Star), R(10),
- B(Mov), R(14), R(1),
+ B(Star), R(8),
+ B(Mov), R(12), R(1),
/* 26 E> */ B(StackCheck),
/* 35 S> */ B(Mov), R(1), R(3),
/* 55 S> */ B(Mov), R(3), R(4),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(JumpLoop), U8(43), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(12),
- B(Star), R(11),
+ B(Star), R(10),
+ B(Star), R(9),
B(Jump), U8(7),
- B(Star), R(12),
+ B(Star), R(10),
B(LdaZero),
- B(Star), R(11),
+ B(Star), R(9),
B(LdaTheHole),
/* 55 E> */ B(SetPendingMessage),
+ B(Star), R(11),
+ B(Ldar), R(8),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(7), U8(3), U8(12),
B(Star), R(13),
- B(Ldar), R(10),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(7), U8(4), U8(12),
- B(Star), R(15),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(16),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(14),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(17),
- B(LdaConstant), U8(5),
- B(Star), R(18),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(17), U8(2),
+ B(Star), R(15),
+ B(LdaConstant), U8(4),
+ B(Star), R(16),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(15), U8(2),
B(Throw),
- B(CallProperty0), R(15), R(7), U8(14),
+ B(CallProperty0), R(13), R(7), U8(14),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(17),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(17), U8(1),
+ B(Star), R(15),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(15), U8(1),
B(Jump), U8(12),
- B(Star), R(16),
+ B(Star), R(14),
B(LdaZero),
- B(TestReferenceEqual), R(11),
+ B(TestReferenceEqual), R(9),
B(JumpIfTrue), U8(5),
- B(Ldar), R(16),
+ B(Ldar), R(14),
B(ReThrow),
- B(Ldar), R(13),
+ B(Ldar), R(11),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(11),
+ B(TestReferenceEqual), R(9),
B(JumpIfFalse), U8(5),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(ReThrow),
B(LdaUndefined),
B(Star), R(7),
@@ -828,7 +804,7 @@ bytecodes: [
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(6), U8(3),
/* 60 S> */ B(Return),
B(Star), R(6),
- B(CreateCatchContext), R(6), U8(6),
+ B(CreateCatchContext), R(6), U8(5),
B(Star), R(5),
B(LdaTheHole),
B(SetPendingMessage),
@@ -843,7 +819,6 @@ bytecodes: [
/* 60 S> */ B(Return),
]
constant pool: [
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -852,9 +827,9 @@ constant pool: [
SCOPE_INFO_TYPE,
]
handlers: [
- [16, 200, 200],
- [50, 96, 104],
- [130, 163, 165],
+ [16, 194, 194],
+ [46, 92, 100],
+ [124, 157, 159],
]
---
@@ -864,9 +839,9 @@ snippet: "
}
f([1, 2, 3]);
"
-frame size: 18
+frame size: 16
parameter count: 2
-bytecode array length: 264
+bytecode array length: 258
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(1),
B(Mov), R(closure), R(4),
@@ -875,90 +850,88 @@ bytecodes: [
B(Star), R(0),
/* 16 E> */ B(StackCheck),
B(Mov), R(context), R(4),
- /* 40 S> */ B(LdaNamedProperty), R(arg0), U8(1), U8(0),
+ /* 40 S> */ B(GetIterator), R(arg0), U8(0),
B(Star), R(8),
B(CallProperty0), R(8), R(arg0), U8(2),
- B(Mov), R(arg0), R(7),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(2), U8(4),
+ B(LdaNamedProperty), R(6), U8(1), U8(4),
B(Star), R(5),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(context), R(12),
+ B(Star), R(7),
+ B(Mov), R(context), R(10),
B(LdaTrue),
- B(Star), R(9),
+ B(Star), R(7),
/* 35 S> */ B(CallProperty0), R(5), R(6), U8(6),
- B(Star), R(13),
+ B(Star), R(11),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
- B(LdaNamedProperty), R(13), U8(3), U8(8),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(11), U8(1),
+ B(LdaNamedProperty), R(11), U8(2), U8(8),
B(JumpIfToBooleanTrue), U8(58),
- B(LdaNamedProperty), R(13), U8(4), U8(10),
- B(Star), R(13),
+ B(LdaNamedProperty), R(11), U8(3), U8(10),
+ B(Star), R(11),
B(LdaFalse),
- B(Star), R(9),
- B(Mov), R(13), R(1),
+ B(Star), R(7),
+ B(Mov), R(11), R(1),
/* 26 E> */ B(StackCheck),
/* 35 S> */ B(Mov), R(1), R(3),
- /* 45 S> */ B(Mov), R(0), R(14),
- B(Mov), R(3), R(15),
- B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(14), U8(2),
- /* 45 E> */ B(SuspendGenerator), R(0), R(0), U8(14), U8(0),
- B(ResumeGenerator), R(0), R(0), U8(14),
- B(Star), R(14),
+ /* 45 S> */ B(Mov), R(0), R(12),
+ B(Mov), R(3), R(13),
+ B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionAwaitUncaught), R(12), U8(2),
+ /* 45 E> */ B(SuspendGenerator), R(0), R(0), U8(12), U8(0),
+ B(ResumeGenerator), R(0), R(0), U8(12),
+ B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(Star), R(15),
+ B(Star), R(13),
B(LdaZero),
- B(TestReferenceEqual), R(15),
+ B(TestReferenceEqual), R(13),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(JumpLoop), U8(75), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(11),
- B(Star), R(10),
+ B(Star), R(9),
+ B(Star), R(8),
B(Jump), U8(7),
- B(Star), R(11),
+ B(Star), R(9),
B(LdaZero),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaTheHole),
B(SetPendingMessage),
+ B(Star), R(10),
+ B(Ldar), R(7),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(6), U8(4), U8(12),
B(Star), R(12),
- B(Ldar), R(9),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(6), U8(5), U8(12),
- B(Star), R(14),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(15),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(13),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(16),
- B(LdaConstant), U8(6),
- B(Star), R(17),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(16), U8(2),
+ B(Star), R(14),
+ B(LdaConstant), U8(5),
+ B(Star), R(15),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(14), U8(2),
B(Throw),
- B(CallProperty0), R(14), R(6), U8(14),
+ B(CallProperty0), R(12), R(6), U8(14),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(16), U8(1),
+ B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(14), U8(1),
B(Jump), U8(12),
- B(Star), R(15),
+ B(Star), R(13),
B(LdaZero),
- B(TestReferenceEqual), R(10),
+ B(TestReferenceEqual), R(8),
B(JumpIfTrue), U8(5),
- B(Ldar), R(15),
+ B(Ldar), R(13),
B(ReThrow),
- B(Ldar), R(12),
+ B(Ldar), R(10),
B(SetPendingMessage),
B(LdaZero),
- B(TestReferenceEqual), R(10),
+ B(TestReferenceEqual), R(8),
B(JumpIfFalse), U8(5),
- B(Ldar), R(11),
+ B(Ldar), R(9),
B(ReThrow),
B(LdaUndefined),
B(Star), R(6),
@@ -968,7 +941,7 @@ bytecodes: [
B(InvokeIntrinsic), U8(Runtime::k_AsyncFunctionResolve), R(5), U8(3),
/* 54 S> */ B(Return),
B(Star), R(5),
- B(CreateCatchContext), R(5), U8(7),
+ B(CreateCatchContext), R(5), U8(6),
B(Star), R(4),
B(LdaTheHole),
B(SetPendingMessage),
@@ -983,8 +956,7 @@ bytecodes: [
/* 54 S> */ B(Return),
]
constant pool: [
- Smi [107],
- SYMBOL_TYPE,
+ Smi [103],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -993,8 +965,8 @@ constant pool: [
SCOPE_INFO_TYPE,
]
handlers: [
- [20, 236, 236],
- [54, 132, 140],
- [166, 199, 201],
+ [20, 230, 230],
+ [50, 128, 136],
+ [160, 193, 195],
]
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/Generators.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/Generators.golden
index bfbd05cd31..157b58d81d 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/Generators.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/Generators.golden
@@ -98,9 +98,9 @@ snippet: "
function* f() { for (let x of [42]) yield x }
f();
"
-frame size: 17
+frame size: 15
parameter count: 1
-bytecode array length: 261
+bytecode array length: 258
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(2),
B(Mov), R(closure), R(4),
@@ -119,104 +119,102 @@ bytecodes: [
/* 44 S> */ B(Return),
/* 30 S> */ B(CreateArrayLiteral), U8(4), U8(0), U8(37),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(5), U8(1),
+ B(GetIterator), R(6), U8(1),
B(Star), R(7),
B(CallProperty0), R(7), R(6), U8(3),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(5),
- B(LdaNamedProperty), R(5), U8(6), U8(5),
+ B(LdaNamedProperty), R(5), U8(5), U8(5),
B(Star), R(4),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(context), R(11),
+ B(Star), R(6),
+ B(Mov), R(context), R(9),
B(LdaTrue),
- B(Star), R(8),
+ B(Star), R(6),
/* 25 S> */ B(CallProperty0), R(4), R(5), U8(7),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(7), U8(9),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(6), U8(9),
B(JumpIfToBooleanTrue), U8(64),
- B(LdaNamedProperty), R(12), U8(8), U8(11),
- B(Star), R(12),
+ B(LdaNamedProperty), R(10), U8(7), U8(11),
+ B(Star), R(10),
B(LdaFalse),
- B(Star), R(8),
- B(Mov), R(12), R(1),
+ B(Star), R(6),
+ B(Mov), R(10), R(1),
/* 16 E> */ B(StackCheck),
/* 25 S> */ B(Mov), R(1), R(3),
/* 36 S> */ B(LdaFalse),
- B(Star), R(14),
- B(Mov), R(3), R(13),
- B(InvokeIntrinsic), U8(Runtime::k_CreateIterResultObject), R(13), U8(2),
- /* 36 E> */ B(SuspendGenerator), R(0), R(0), U8(13), U8(1),
- B(ResumeGenerator), R(0), R(0), U8(13),
- B(Star), R(13),
+ B(Star), R(12),
+ B(Mov), R(3), R(11),
+ B(InvokeIntrinsic), U8(Runtime::k_CreateIterResultObject), R(11), U8(2),
+ /* 36 E> */ B(SuspendGenerator), R(0), R(0), U8(11), U8(1),
+ B(ResumeGenerator), R(0), R(0), U8(11),
+ B(Star), R(11),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
- B(SwitchOnSmiNoFeedback), U8(9), U8(2), I8(0),
- B(Ldar), R(13),
+ B(SwitchOnSmiNoFeedback), U8(8), U8(2), I8(0),
+ B(Ldar), R(11),
/* 36 E> */ B(Throw),
B(LdaSmi), I8(1),
- B(Star), R(9),
- B(Mov), R(13), R(10),
+ B(Star), R(7),
+ B(Mov), R(11), R(8),
B(Jump), U8(20),
- B(Ldar), R(13),
+ B(Ldar), R(11),
B(JumpLoop), U8(81), I8(0),
B(LdaSmi), I8(-1),
- B(Star), R(10),
- B(Star), R(9),
+ B(Star), R(8),
+ B(Star), R(7),
B(Jump), U8(7),
- B(Star), R(10),
+ B(Star), R(8),
B(LdaZero),
- B(Star), R(9),
+ B(Star), R(7),
B(LdaTheHole),
B(SetPendingMessage),
+ B(Star), R(9),
+ B(Ldar), R(6),
+ B(JumpIfToBooleanTrue), U8(58),
+ B(LdaNamedProperty), R(5), U8(10), U8(13),
B(Star), R(11),
- B(Ldar), R(8),
- B(JumpIfToBooleanTrue), U8(60),
- B(LdaNamedProperty), R(5), U8(11), U8(13),
- B(Star), R(13),
- B(JumpIfUndefined), U8(52),
- B(JumpIfNull), U8(50),
- B(Mov), R(context), R(14),
+ B(JumpIfUndefinedOrNull), U8(50),
+ B(Mov), R(context), R(12),
B(TestTypeOf), U8(6),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(159),
- B(Star), R(15),
- B(LdaConstant), U8(12),
- B(Star), R(16),
- B(CallRuntime), U16(Runtime::kNewTypeError), R(15), U8(2),
+ B(Star), R(13),
+ B(LdaConstant), U8(11),
+ B(Star), R(14),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(13), U8(2),
B(Throw),
- B(CallProperty0), R(13), R(5), U8(15),
+ B(CallProperty0), R(11), R(5), U8(15),
B(JumpIfJSReceiver), U8(21),
- B(Star), R(15),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(15), U8(1),
+ B(Star), R(13),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(13), U8(1),
B(Jump), U8(12),
- B(Star), R(14),
+ B(Star), R(12),
B(LdaZero),
- B(TestReferenceEqual), R(9),
+ B(TestReferenceEqual), R(7),
B(JumpIfTrue), U8(5),
- B(Ldar), R(14),
+ B(Ldar), R(12),
B(ReThrow),
- B(Ldar), R(11),
- B(SetPendingMessage),
B(Ldar), R(9),
- B(SwitchOnSmiNoFeedback), U8(13), U8(2), I8(0),
+ B(SetPendingMessage),
+ B(Ldar), R(7),
+ B(SwitchOnSmiNoFeedback), U8(12), U8(2), I8(0),
B(Jump), U8(8),
- B(Ldar), R(10),
+ B(Ldar), R(8),
B(ReThrow),
- B(Ldar), R(10),
+ B(Ldar), R(8),
/* 44 S> */ B(Return),
B(LdaUndefined),
/* 44 S> */ B(Return),
]
constant pool: [
Smi [22],
- Smi [132],
+ Smi [131],
Smi [10],
Smi [7],
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
@@ -228,8 +226,8 @@ constant pool: [
Smi [9],
]
handlers: [
- [79, 163, 171],
- [197, 230, 232],
+ [78, 162, 170],
+ [194, 227, 229],
]
---
@@ -238,9 +236,9 @@ snippet: "
function* f() { yield* g() }
f();
"
-frame size: 9
+frame size: 8
parameter count: 1
-bytecode array length: 217
+bytecode array length: 210
bytecodes: [
B(SwitchOnGeneratorState), R(0), U8(0), U8(2),
B(Mov), R(closure), R(1),
@@ -261,59 +259,56 @@ bytecodes: [
B(Star), R(5),
/* 50 E> */ B(CallUndefinedReceiver0), R(5), U8(2),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(5), U8(4),
+ B(GetIterator), R(6), U8(4),
B(Star), R(7),
B(CallProperty0), R(7), R(6), U8(6),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(3),
- B(LdaNamedProperty), R(3), U8(6), U8(8),
+ B(LdaNamedProperty), R(3), U8(5), U8(8),
B(Star), R(5),
B(LdaUndefined),
B(Star), R(4),
B(LdaZero),
B(Star), R(2),
B(Ldar), R(2),
- B(SwitchOnSmiNoFeedback), U8(7), U8(2), I8(1),
+ B(SwitchOnSmiNoFeedback), U8(6), U8(2), I8(1),
B(CallProperty1), R(5), R(3), R(4), U8(10),
- B(Jump), U8(69),
- B(LdaNamedProperty), R(3), U8(9), U8(12),
- B(JumpIfUndefined), U8(13),
- B(JumpIfNull), U8(11),
- B(Star), R(8),
- B(CallProperty1), R(8), R(3), R(4), U8(14),
- B(Jump), U8(52),
+ B(Jump), U8(63),
+ B(LdaNamedProperty), R(3), U8(8), U8(12),
+ B(JumpIfUndefinedOrNull), U8(11),
+ B(Star), R(6),
+ B(CallProperty1), R(6), R(3), R(4), U8(14),
+ B(Jump), U8(48),
B(Ldar), R(4),
/* 54 S> */ B(Return),
- B(LdaNamedProperty), R(3), U8(10), U8(16),
- B(JumpIfUndefined), U8(13),
- B(JumpIfNull), U8(11),
- B(Star), R(8),
- B(CallProperty1), R(8), R(3), R(4), U8(18),
- B(Jump), U8(32),
- B(LdaNamedProperty), R(3), U8(9), U8(20),
- B(JumpIfUndefined), U8(21),
- B(JumpIfNull), U8(19),
- B(Star), R(8),
- B(CallProperty0), R(8), R(3), U8(22),
+ B(LdaNamedProperty), R(3), U8(9), U8(16),
+ B(JumpIfUndefinedOrNull), U8(11),
+ B(Star), R(6),
+ B(CallProperty1), R(6), R(3), R(4), U8(18),
+ B(Jump), U8(30),
+ B(LdaNamedProperty), R(3), U8(8), U8(20),
+ B(JumpIfUndefinedOrNull), U8(19),
+ B(Star), R(6),
+ B(CallProperty0), R(6), R(3), U8(22),
B(Jump), U8(2),
B(JumpIfJSReceiver), U8(9),
- B(Star), R(8),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
+ B(Star), R(6),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(CallRuntime), U16(Runtime::kThrowThrowMethodMissing), R(0), U8(0),
B(Star), R(1),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(1), U8(1),
- B(LdaNamedProperty), R(1), U8(11), U8(24),
+ B(LdaNamedProperty), R(1), U8(10), U8(24),
B(JumpIfToBooleanTrue), U8(24),
B(Ldar), R(1),
- /* 43 E> */ B(SuspendGenerator), R(0), R(0), U8(8), U8(1),
- B(ResumeGenerator), R(0), R(0), U8(8),
+ /* 43 E> */ B(SuspendGenerator), R(0), R(0), U8(6), U8(1),
+ B(ResumeGenerator), R(0), R(0), U8(6),
B(Star), R(4),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(2),
- B(JumpLoop), U8(114), I8(0),
- B(LdaNamedProperty), R(1), U8(12), U8(26),
+ B(JumpLoop), U8(108), I8(0),
+ B(LdaNamedProperty), R(1), U8(11), U8(26),
B(Star), R(3),
B(LdaSmi), I8(1),
B(TestReferenceEqual), R(2),
@@ -325,14 +320,13 @@ bytecodes: [
]
constant pool: [
Smi [22],
- Smi [185],
+ Smi [178],
Smi [10],
Smi [7],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["g"],
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
Smi [11],
- Smi [31],
+ Smi [29],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["throw"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/NewAndSpread.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/NewAndSpread.golden
index ed15f99fc9..dce8d7ac8c 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/NewAndSpread.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/NewAndSpread.golden
@@ -92,9 +92,9 @@ snippet: "
class A { constructor(...args) { this.args = args; } }
new A(0, ...[1, 2, 3], 4);
"
-frame size: 10
+frame size: 9
parameter count: 1
-bytecode array length: 131
+bytecode array length: 130
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
@@ -117,22 +117,22 @@ bytecodes: [
B(Star), R(3),
/* 101 S> */ B(CreateArrayLiteral), U8(5), U8(1), U8(37),
B(Star), R(7),
- B(LdaNamedProperty), R(7), U8(6), U8(2),
+ B(GetIterator), R(7), U8(2),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(4),
B(Mov), R(5), R(2),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(6),
- B(LdaNamedProperty), R(6), U8(7), U8(6),
+ B(LdaNamedProperty), R(6), U8(6), U8(6),
B(Star), R(5),
B(CallProperty0), R(5), R(6), U8(15),
- B(Star), R(9),
+ B(Star), R(7),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(9), U8(1),
- B(LdaNamedProperty), R(9), U8(8), U8(17),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(7), U8(1),
+ B(LdaNamedProperty), R(7), U8(7), U8(17),
B(JumpIfToBooleanTrue), U8(19),
- B(LdaNamedProperty), R(9), U8(9), U8(8),
+ B(LdaNamedProperty), R(7), U8(8), U8(8),
B(StaInArrayLiteral), R(4), R(3), U8(13),
B(Ldar), R(3),
B(Inc), U8(12),
@@ -152,7 +152,6 @@ constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
Smi [1],
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateAccessorAccess.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateAccessorAccess.golden
new file mode 100644
index 0000000000..6fc00999a5
--- /dev/null
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateAccessorAccess.golden
@@ -0,0 +1,192 @@
+#
+# Autogenerated by generate-bytecode-expectations.
+#
+
+---
+wrap: no
+test function name: test
+private methods: yes
+
+---
+snippet: "
+ class A {
+ get #a() { return 1; }
+ set #a(val) { }
+
+ constructor() {
+ this.#a++;
+ this.#a = 1;
+ return this.#a;
+ }
+ }
+ var test = A;
+ new test;
+"
+frame size: 6
+parameter count: 1
+bytecode array length: 95
+bytecodes: [
+ /* 67 E> */ B(StackCheck),
+ B(LdaCurrentContextSlot), U8(5),
+ B(Star), R(1),
+ B(Mov), R(this), R(0),
+ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
+ /* 76 S> */ B(LdaCurrentContextSlot), U8(4),
+ B(Star), R(3),
+ B(LdaCurrentContextSlot), U8(5),
+ /* 81 E> */ B(LdaKeyedProperty), R(this), U8(0),
+ B(CallRuntime), U16(Runtime::kLoadPrivateGetter), R(3), U8(1),
+ B(Star), R(4),
+ B(CallProperty0), R(4), R(this), U8(2),
+ B(Inc), U8(4),
+ B(Star), R(4),
+ /* 83 E> */ B(CallRuntime), U16(Runtime::kLoadPrivateSetter), R(3), U8(1),
+ B(Star), R(5),
+ B(CallProperty1), R(5), R(this), R(4), U8(5),
+ /* 91 S> */ B(LdaSmi), I8(1),
+ B(Star), R(2),
+ B(LdaCurrentContextSlot), U8(4),
+ B(Star), R(4),
+ B(LdaCurrentContextSlot), U8(5),
+ /* 96 E> */ B(LdaKeyedProperty), R(this), U8(7),
+ B(CallRuntime), U16(Runtime::kLoadPrivateSetter), R(4), U8(1),
+ B(Star), R(5),
+ B(CallProperty1), R(5), R(this), R(2), U8(9),
+ /* 108 S> */ B(LdaCurrentContextSlot), U8(4),
+ B(Star), R(3),
+ B(LdaCurrentContextSlot), U8(5),
+ /* 120 E> */ B(LdaKeyedProperty), R(this), U8(11),
+ B(CallRuntime), U16(Runtime::kLoadPrivateGetter), R(3), U8(1),
+ B(Star), R(4),
+ B(CallProperty0), R(4), R(this), U8(13),
+ /* 123 S> */ B(Return),
+]
+constant pool: [
+]
+handlers: [
+]
+
+---
+snippet: "
+ class B {
+ get #b() { return 1; }
+ constructor() { this.#b++; }
+ }
+ var test = B;
+ new test;
+"
+frame size: 4
+parameter count: 1
+bytecode array length: 29
+bytecodes: [
+ /* 48 E> */ B(StackCheck),
+ B(LdaCurrentContextSlot), U8(5),
+ B(Star), R(1),
+ B(Mov), R(this), R(0),
+ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
+ /* 53 S> */ B(Wide), B(LdaSmi), I16(263),
+ B(Star), R(2),
+ B(LdaConstant), U8(0),
+ B(Star), R(3),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
+ B(Throw),
+]
+constant pool: [
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["#b"],
+]
+handlers: [
+]
+
+---
+snippet: "
+ class C {
+ set #c(val) { }
+ constructor() { this.#c++; }
+ }
+ var test = C;
+ new test;
+"
+frame size: 4
+parameter count: 1
+bytecode array length: 29
+bytecodes: [
+ /* 41 E> */ B(StackCheck),
+ B(LdaCurrentContextSlot), U8(5),
+ B(Star), R(1),
+ B(Mov), R(this), R(0),
+ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
+ /* 46 S> */ B(Wide), B(LdaSmi), I16(262),
+ B(Star), R(2),
+ B(LdaConstant), U8(0),
+ B(Star), R(3),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
+ B(Throw),
+]
+constant pool: [
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["#c"],
+]
+handlers: [
+]
+
+---
+snippet: "
+ class D {
+ get #d() { return 1; }
+ constructor() { this.#d = 1; }
+ }
+ var test = D;
+ new test;
+"
+frame size: 4
+parameter count: 1
+bytecode array length: 29
+bytecodes: [
+ /* 48 E> */ B(StackCheck),
+ B(LdaCurrentContextSlot), U8(5),
+ B(Star), R(1),
+ B(Mov), R(this), R(0),
+ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
+ /* 53 S> */ B(Wide), B(LdaSmi), I16(263),
+ B(Star), R(2),
+ B(LdaConstant), U8(0),
+ B(Star), R(3),
+ /* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
+ B(Throw),
+]
+constant pool: [
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["#d"],
+]
+handlers: [
+]
+
+---
+snippet: "
+ class E {
+ set #e(val) { }
+ constructor() { this.#e; }
+ }
+ var test = E;
+ new test;
+"
+frame size: 5
+parameter count: 1
+bytecode array length: 29
+bytecodes: [
+ /* 41 E> */ B(StackCheck),
+ B(LdaCurrentContextSlot), U8(5),
+ B(Star), R(1),
+ B(Mov), R(this), R(0),
+ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
+ /* 46 S> */ B(Wide), B(LdaSmi), I16(262),
+ B(Star), R(3),
+ B(LdaConstant), U8(0),
+ B(Star), R(4),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(3), U8(2),
+ B(Throw),
+]
+constant pool: [
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["#e"],
+]
+handlers: [
+]
+
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateAccessorDeclaration.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateAccessorDeclaration.golden
new file mode 100644
index 0000000000..aceee552b5
--- /dev/null
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateAccessorDeclaration.golden
@@ -0,0 +1,398 @@
+#
+# Autogenerated by generate-bytecode-expectations.
+#
+
+---
+wrap: yes
+private methods: yes
+
+---
+snippet: "
+ {
+ class A {
+ get #a() { return 1; }
+ set #a(val) { }
+ }
+ }
+"
+frame size: 8
+parameter count: 1
+bytecode array length: 68
+bytecodes: [
+ /* 30 E> */ B(StackCheck),
+ B(CreateBlockContext), U8(0),
+ B(PushContext), R(2),
+ B(LdaTheHole),
+ B(Star), R(6),
+ B(CreateClosure), U8(2), U8(0), U8(2),
+ B(Star), R(3),
+ B(LdaConstant), U8(1),
+ B(Star), R(4),
+ B(Mov), R(3), R(5),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
+ B(Star), R(4),
+ B(Mov), R(5), R(1),
+ B(LdaConstant), U8(3),
+ B(Star), R(5),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(CreateClosure), U8(4), U8(1), U8(2),
+ B(Star), R(6),
+ B(CreateClosure), U8(5), U8(2), U8(2),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(6), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(PopContext), R(2),
+ B(Mov), R(1), R(0),
+ B(LdaUndefined),
+ /* 101 S> */ B(Return),
+]
+constant pool: [
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+]
+handlers: [
+]
+
+---
+snippet: "
+ {
+ class B {
+ get #b() { return 1; }
+ }
+ }
+"
+frame size: 8
+parameter count: 1
+bytecode array length: 65
+bytecodes: [
+ /* 30 E> */ B(StackCheck),
+ B(CreateBlockContext), U8(0),
+ B(PushContext), R(2),
+ B(LdaTheHole),
+ B(Star), R(6),
+ B(CreateClosure), U8(2), U8(0), U8(2),
+ B(Star), R(3),
+ B(LdaConstant), U8(1),
+ B(Star), R(4),
+ B(Mov), R(3), R(5),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
+ B(Star), R(4),
+ B(Mov), R(5), R(1),
+ B(LdaConstant), U8(3),
+ B(Star), R(5),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(CreateClosure), U8(4), U8(1), U8(2),
+ B(Star), R(6),
+ B(LdaNull),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(6), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(PopContext), R(2),
+ B(Mov), R(1), R(0),
+ B(LdaUndefined),
+ /* 81 S> */ B(Return),
+]
+constant pool: [
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["B"],
+ SHARED_FUNCTION_INFO_TYPE,
+]
+handlers: [
+]
+
+---
+snippet: "
+ {
+ class C {
+ set #c(val) { }
+ }
+ }
+"
+frame size: 8
+parameter count: 1
+bytecode array length: 65
+bytecodes: [
+ /* 30 E> */ B(StackCheck),
+ B(CreateBlockContext), U8(0),
+ B(PushContext), R(2),
+ B(LdaTheHole),
+ B(Star), R(6),
+ B(CreateClosure), U8(2), U8(0), U8(2),
+ B(Star), R(3),
+ B(LdaConstant), U8(1),
+ B(Star), R(4),
+ B(Mov), R(3), R(5),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
+ B(Star), R(4),
+ B(Mov), R(5), R(1),
+ B(LdaConstant), U8(3),
+ B(Star), R(5),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(LdaNull),
+ B(Star), R(6),
+ B(CreateClosure), U8(4), U8(1), U8(2),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(6), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(PopContext), R(2),
+ B(Mov), R(1), R(0),
+ B(LdaUndefined),
+ /* 74 S> */ B(Return),
+]
+constant pool: [
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
+ SHARED_FUNCTION_INFO_TYPE,
+]
+handlers: [
+]
+
+---
+snippet: "
+ {
+ class D {
+ get #d() { return 1; }
+ set #d(val) { }
+ }
+
+ class E extends D {
+ get #e() { return 2; }
+ set #e(val) { }
+ }
+ }
+"
+frame size: 10
+parameter count: 1
+bytecode array length: 133
+bytecodes: [
+ /* 30 E> */ B(StackCheck),
+ B(CreateBlockContext), U8(0),
+ B(PushContext), R(4),
+ B(LdaTheHole),
+ B(Star), R(8),
+ B(CreateClosure), U8(2), U8(0), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(1),
+ B(Star), R(6),
+ B(Mov), R(5), R(7),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
+ B(Star), R(6),
+ B(Mov), R(7), R(3),
+ B(LdaConstant), U8(3),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(CreateClosure), U8(4), U8(1), U8(2),
+ B(Star), R(8),
+ B(CreateClosure), U8(5), U8(2), U8(2),
+ B(Star), R(9),
+ B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(8), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(PopContext), R(4),
+ B(Mov), R(3), R(0),
+ /* 38 E> */ B(CreateBlockContext), U8(6),
+ B(PushContext), R(4),
+ /* 118 E> */ B(CreateClosure), U8(8), U8(3), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(7),
+ B(Star), R(6),
+ B(Mov), R(5), R(7),
+ B(Mov), R(3), R(8),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
+ B(Star), R(6),
+ B(Mov), R(7), R(2),
+ B(LdaConstant), U8(9),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(CreateClosure), U8(10), U8(4), U8(2),
+ B(Star), R(8),
+ B(CreateClosure), U8(11), U8(5), U8(2),
+ B(Star), R(9),
+ B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(8), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(PopContext), R(4),
+ B(Mov), R(2), R(1),
+ B(LdaUndefined),
+ /* 175 S> */ B(Return),
+]
+constant pool: [
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["D"],
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["E"],
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+]
+handlers: [
+]
+
+---
+snippet: "
+ {
+ class A { foo() {} }
+ class C extends A {
+ get #a() { return super.foo; }
+ }
+ new C();
+ }
+"
+frame size: 10
+parameter count: 1
+bytecode array length: 119
+bytecodes: [
+ /* 30 E> */ B(StackCheck),
+ B(CreateBlockContext), U8(0),
+ B(PushContext), R(4),
+ B(LdaTheHole),
+ B(Star), R(8),
+ B(CreateClosure), U8(2), U8(0), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(1),
+ B(Star), R(6),
+ B(CreateClosure), U8(3), U8(1), U8(2),
+ B(Star), R(9),
+ B(Mov), R(5), R(7),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(4),
+ B(Star), R(6),
+ B(Mov), R(7), R(3),
+ B(PopContext), R(4),
+ B(Mov), R(3), R(0),
+ /* 38 E> */ B(CreateBlockContext), U8(4),
+ B(PushContext), R(4),
+ /* 77 E> */ B(CreateClosure), U8(6), U8(2), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(5),
+ B(Star), R(6),
+ B(Mov), R(5), R(7),
+ B(Mov), R(3), R(8),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
+ B(Star), R(6),
+ B(Mov), R(7), R(2),
+ B(LdaConstant), U8(7),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(CreateClosure), U8(8), U8(3), U8(2),
+ B(Star), R(8),
+ B(Ldar), R(6),
+ B(StaNamedProperty), R(8), U8(9), U8(0),
+ B(LdaNull),
+ B(Star), R(9),
+ B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(8), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(PopContext), R(4),
+ B(Mov), R(2), R(1),
+ /* 122 S> */ B(Ldar), R(1),
+ /* 122 E> */ B(Construct), R(1), R(0), U8(0), U8(2),
+ B(LdaUndefined),
+ /* 133 S> */ B(Return),
+]
+constant pool: [
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
+ SHARED_FUNCTION_INFO_TYPE,
+ SYMBOL_TYPE,
+]
+handlers: [
+]
+
+---
+snippet: "
+ {
+ class A { foo(val) {} }
+ class C extends A {
+ set #a(val) { super.foo(val); }
+ }
+ new C();
+ }
+"
+frame size: 10
+parameter count: 1
+bytecode array length: 119
+bytecodes: [
+ /* 30 E> */ B(StackCheck),
+ B(CreateBlockContext), U8(0),
+ B(PushContext), R(4),
+ B(LdaTheHole),
+ B(Star), R(8),
+ B(CreateClosure), U8(2), U8(0), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(1),
+ B(Star), R(6),
+ B(CreateClosure), U8(3), U8(1), U8(2),
+ B(Star), R(9),
+ B(Mov), R(5), R(7),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(4),
+ B(Star), R(6),
+ B(Mov), R(7), R(3),
+ B(PopContext), R(4),
+ B(Mov), R(3), R(0),
+ /* 38 E> */ B(CreateBlockContext), U8(4),
+ B(PushContext), R(4),
+ /* 80 E> */ B(CreateClosure), U8(6), U8(2), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(5),
+ B(Star), R(6),
+ B(Mov), R(5), R(7),
+ B(Mov), R(3), R(8),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
+ B(Star), R(6),
+ B(Mov), R(7), R(2),
+ B(LdaConstant), U8(7),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(LdaNull),
+ B(Star), R(8),
+ B(CreateClosure), U8(8), U8(3), U8(2),
+ B(Star), R(9),
+ B(Ldar), R(6),
+ B(StaNamedProperty), R(9), U8(9), U8(0),
+ B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(8), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(PopContext), R(4),
+ B(Mov), R(2), R(1),
+ /* 126 S> */ B(Ldar), R(1),
+ /* 126 E> */ B(Construct), R(1), R(0), U8(0), U8(2),
+ B(LdaUndefined),
+ /* 137 S> */ B(Return),
+]
+constant pool: [
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
+ SHARED_FUNCTION_INFO_TYPE,
+ SYMBOL_TYPE,
+]
+handlers: [
+]
+
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethodAccess.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethodAccess.golden
new file mode 100644
index 0000000000..d41b342187
--- /dev/null
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethodAccess.golden
@@ -0,0 +1,104 @@
+#
+# Autogenerated by generate-bytecode-expectations.
+#
+
+---
+wrap: no
+test function name: test
+private methods: yes
+
+---
+snippet: "
+ class A {
+ #a() { return 1; }
+ constructor() { return this.#a(); }
+ }
+
+ var test = A;
+ new A;
+"
+frame size: 3
+parameter count: 1
+bytecode array length: 28
+bytecodes: [
+ /* 44 E> */ B(StackCheck),
+ B(LdaCurrentContextSlot), U8(5),
+ B(Star), R(1),
+ B(Mov), R(this), R(0),
+ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
+ /* 49 S> */ B(LdaCurrentContextSlot), U8(5),
+ /* 61 E> */ B(LdaKeyedProperty), R(this), U8(0),
+ B(LdaCurrentContextSlot), U8(4),
+ B(Star), R(2),
+ /* 63 E> */ B(CallAnyReceiver), R(2), R(this), U8(1), U8(2),
+ /* 66 S> */ B(Return),
+]
+constant pool: [
+]
+handlers: [
+]
+
+---
+snippet: "
+ class B {
+ #b() { return 1; }
+ constructor() { this.#b = 1; }
+ }
+
+ var test = B;
+ new test;
+"
+frame size: 4
+parameter count: 1
+bytecode array length: 29
+bytecodes: [
+ /* 44 E> */ B(StackCheck),
+ B(LdaCurrentContextSlot), U8(5),
+ B(Star), R(1),
+ B(Mov), R(this), R(0),
+ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
+ /* 49 S> */ B(Wide), B(LdaSmi), I16(261),
+ B(Star), R(2),
+ B(LdaConstant), U8(0),
+ B(Star), R(3),
+ /* 57 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
+ B(Throw),
+]
+constant pool: [
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["#b"],
+]
+handlers: [
+]
+
+---
+snippet: "
+ class C {
+ #c() { return 1; }
+ constructor() { this.#c++; }
+ }
+
+ var test = C;
+ new test;
+"
+frame size: 4
+parameter count: 1
+bytecode array length: 29
+bytecodes: [
+ /* 44 E> */ B(StackCheck),
+ B(LdaCurrentContextSlot), U8(5),
+ B(Star), R(1),
+ B(Mov), R(this), R(0),
+ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(2),
+ /* 49 S> */ B(Wide), B(LdaSmi), I16(261),
+ B(Star), R(2),
+ B(LdaConstant), U8(0),
+ B(Star), R(3),
+ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), U8(2),
+ B(Throw),
+]
+constant pool: [
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["#c"],
+]
+handlers: [
+]
+
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethodDeclaration.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethodDeclaration.golden
new file mode 100644
index 0000000000..d1aab34fda
--- /dev/null
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethodDeclaration.golden
@@ -0,0 +1,198 @@
+#
+# Autogenerated by generate-bytecode-expectations.
+#
+
+---
+wrap: yes
+private methods: yes
+
+---
+snippet: "
+ {
+ class A {
+ #a() { return 1; }
+ }
+ }
+"
+frame size: 7
+parameter count: 1
+bytecode array length: 55
+bytecodes: [
+ /* 30 E> */ B(StackCheck),
+ B(CreateBlockContext), U8(0),
+ B(PushContext), R(2),
+ B(LdaTheHole),
+ B(Star), R(6),
+ B(CreateClosure), U8(2), U8(0), U8(2),
+ B(Star), R(3),
+ B(LdaConstant), U8(1),
+ B(Star), R(4),
+ B(CreateClosure), U8(3), U8(1), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(Mov), R(3), R(5),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
+ B(Star), R(4),
+ B(Mov), R(5), R(1),
+ B(LdaConstant), U8(4),
+ B(Star), R(5),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(PopContext), R(2),
+ B(Mov), R(1), R(0),
+ B(LdaUndefined),
+ /* 77 S> */ B(Return),
+]
+constant pool: [
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
+]
+handlers: [
+]
+
+---
+snippet: "
+ {
+ class D {
+ #d() { return 1; }
+ }
+ class E extends D {
+ #e() { return 2; }
+ }
+ }
+"
+frame size: 9
+parameter count: 1
+bytecode array length: 107
+bytecodes: [
+ /* 30 E> */ B(StackCheck),
+ B(CreateBlockContext), U8(0),
+ B(PushContext), R(4),
+ B(LdaTheHole),
+ B(Star), R(8),
+ B(CreateClosure), U8(2), U8(0), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(1),
+ B(Star), R(6),
+ B(CreateClosure), U8(3), U8(1), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(Mov), R(5), R(7),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
+ B(Star), R(6),
+ B(Mov), R(7), R(3),
+ B(LdaConstant), U8(4),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(PopContext), R(4),
+ B(Mov), R(3), R(0),
+ /* 38 E> */ B(CreateBlockContext), U8(5),
+ B(PushContext), R(4),
+ /* 93 E> */ B(CreateClosure), U8(7), U8(2), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(6),
+ B(Star), R(6),
+ B(CreateClosure), U8(8), U8(3), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(Mov), R(5), R(7),
+ B(Mov), R(3), R(8),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
+ B(Star), R(6),
+ B(Mov), R(7), R(2),
+ B(LdaConstant), U8(9),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(PopContext), R(4),
+ B(Mov), R(2), R(1),
+ B(LdaUndefined),
+ /* 126 S> */ B(Return),
+]
+constant pool: [
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["D"],
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["E"],
+]
+handlers: [
+]
+
+---
+snippet: "
+ {
+ class A { foo() {} }
+ class C extends A {
+ #m() { return super.foo; }
+ }
+ }
+"
+frame size: 10
+parameter count: 1
+bytecode array length: 106
+bytecodes: [
+ /* 30 E> */ B(StackCheck),
+ B(CreateBlockContext), U8(0),
+ B(PushContext), R(4),
+ B(LdaTheHole),
+ B(Star), R(8),
+ B(CreateClosure), U8(2), U8(0), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(1),
+ B(Star), R(6),
+ B(CreateClosure), U8(3), U8(1), U8(2),
+ B(Star), R(9),
+ B(Mov), R(5), R(7),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(4),
+ B(Star), R(6),
+ B(Mov), R(7), R(3),
+ B(PopContext), R(4),
+ B(Mov), R(3), R(0),
+ /* 38 E> */ B(CreateBlockContext), U8(4),
+ B(PushContext), R(4),
+ /* 77 E> */ B(CreateClosure), U8(6), U8(2), U8(2),
+ B(Star), R(5),
+ B(LdaConstant), U8(5),
+ B(Star), R(6),
+ B(CreateClosure), U8(7), U8(3), U8(2),
+ B(StaCurrentContextSlot), U8(4),
+ B(Mov), R(5), R(7),
+ B(Mov), R(3), R(8),
+ B(CallRuntime), U16(Runtime::kDefineClass), R(6), U8(3),
+ B(Star), R(6),
+ B(Mov), R(7), R(2),
+ B(LdaConstant), U8(8),
+ B(Star), R(7),
+ B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(7), U8(1),
+ B(StaCurrentContextSlot), U8(5),
+ B(LdaCurrentContextSlot), U8(4),
+ B(Star), R(8),
+ B(Ldar), R(6),
+ B(StaNamedProperty), R(8), U8(9), U8(0),
+ B(PopContext), R(4),
+ B(Mov), R(2), R(1),
+ B(LdaUndefined),
+ /* 118 S> */ B(Return),
+]
+constant pool: [
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SCOPE_INFO_TYPE,
+ FIXED_ARRAY_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ SHARED_FUNCTION_INFO_TYPE,
+ ONE_BYTE_INTERNALIZED_STRING_TYPE ["C"],
+ SYMBOL_TYPE,
+]
+handlers: [
+]
+
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethods.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethods.golden
deleted file mode 100644
index 5821a20069..0000000000
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/PrivateMethods.golden
+++ /dev/null
@@ -1,160 +0,0 @@
-#
-# Autogenerated by generate-bytecode-expectations.
-#
-
----
-wrap: yes
-private methods: yes
-
----
-snippet: "
- {
- class A {
- #a() { return 1; }
- callA() { return this.#a(); }
- }
-
- const a = new A;
- a.callA();
- }
-"
-frame size: 9
-parameter count: 1
-bytecode array length: 80
-bytecodes: [
- /* 30 E> */ B(StackCheck),
- B(CreateBlockContext), U8(0),
- B(PushContext), R(3),
- B(LdaTheHole),
- B(Star), R(7),
- B(CreateClosure), U8(2), U8(0), U8(2),
- B(Star), R(4),
- B(LdaConstant), U8(1),
- B(Star), R(5),
- B(CreateClosure), U8(3), U8(1), U8(2),
- B(StaCurrentContextSlot), U8(4),
- B(CreateClosure), U8(4), U8(2), U8(2),
- B(Star), R(8),
- B(Mov), R(4), R(6),
- B(CallRuntime), U16(Runtime::kDefineClass), R(5), U8(4),
- B(Star), R(5),
- B(Mov), R(6), R(2),
- B(LdaConstant), U8(5),
- B(Star), R(6),
- B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(6), U8(1),
- B(StaCurrentContextSlot), U8(5),
- B(PopContext), R(3),
- B(Mov), R(2), R(0),
- /* 122 S> */ B(Ldar), R(0),
- /* 122 E> */ B(Construct), R(0), R(0), U8(0), U8(0),
- B(Star), R(1),
- /* 133 S> */ B(LdaNamedProperty), R(1), U8(6), U8(2),
- B(Star), R(3),
- /* 133 E> */ B(CallProperty0), R(3), R(1), U8(4),
- B(LdaUndefined),
- /* 144 S> */ B(Return),
-]
-constant pool: [
- SCOPE_INFO_TYPE,
- FIXED_ARRAY_TYPE,
- SHARED_FUNCTION_INFO_TYPE,
- SHARED_FUNCTION_INFO_TYPE,
- SHARED_FUNCTION_INFO_TYPE,
- ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
- ONE_BYTE_INTERNALIZED_STRING_TYPE ["callA"],
-]
-handlers: [
-]
-
----
-snippet: "
- {
- class D {
- #d() { return 1; }
- callD() { return this.#d(); }
- }
-
- class E extends D {
- #e() { return 2; }
- callE() { return this.callD() + this.#e(); }
- }
-
- const e = new E;
- e.callE();
- }
-"
-frame size: 11
-parameter count: 1
-bytecode array length: 138
-bytecodes: [
- /* 30 E> */ B(StackCheck),
- B(CreateBlockContext), U8(0),
- B(PushContext), R(5),
- B(LdaTheHole),
- B(Star), R(9),
- B(CreateClosure), U8(2), U8(0), U8(2),
- B(Star), R(6),
- B(LdaConstant), U8(1),
- B(Star), R(7),
- B(CreateClosure), U8(3), U8(1), U8(2),
- B(StaCurrentContextSlot), U8(4),
- B(CreateClosure), U8(4), U8(2), U8(2),
- B(Star), R(10),
- B(Mov), R(6), R(8),
- B(CallRuntime), U16(Runtime::kDefineClass), R(7), U8(4),
- B(Star), R(7),
- B(Mov), R(8), R(4),
- B(LdaConstant), U8(5),
- B(Star), R(8),
- B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(8), U8(1),
- B(StaCurrentContextSlot), U8(5),
- B(PopContext), R(5),
- B(Mov), R(4), R(0),
- /* 38 E> */ B(CreateBlockContext), U8(6),
- B(PushContext), R(5),
- /* 128 E> */ B(CreateClosure), U8(8), U8(3), U8(2),
- B(Star), R(6),
- B(LdaConstant), U8(7),
- B(Star), R(7),
- B(CreateClosure), U8(9), U8(4), U8(2),
- B(StaCurrentContextSlot), U8(4),
- B(CreateClosure), U8(10), U8(5), U8(2),
- B(Star), R(10),
- B(Mov), R(6), R(8),
- B(Mov), R(4), R(9),
- B(CallRuntime), U16(Runtime::kDefineClass), R(7), U8(4),
- B(Star), R(7),
- B(Mov), R(8), R(3),
- B(LdaConstant), U8(11),
- B(Star), R(8),
- B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(8), U8(1),
- B(StaCurrentContextSlot), U8(5),
- B(PopContext), R(5),
- B(Mov), R(3), R(1),
- /* 221 S> */ B(Ldar), R(1),
- /* 221 E> */ B(Construct), R(1), R(0), U8(0), U8(0),
- B(Star), R(2),
- /* 232 S> */ B(LdaNamedProperty), R(2), U8(12), U8(2),
- B(Star), R(5),
- /* 232 E> */ B(CallProperty0), R(5), R(2), U8(4),
- B(LdaUndefined),
- /* 243 S> */ B(Return),
-]
-constant pool: [
- SCOPE_INFO_TYPE,
- FIXED_ARRAY_TYPE,
- SHARED_FUNCTION_INFO_TYPE,
- SHARED_FUNCTION_INFO_TYPE,
- SHARED_FUNCTION_INFO_TYPE,
- ONE_BYTE_INTERNALIZED_STRING_TYPE ["D"],
- SCOPE_INFO_TYPE,
- FIXED_ARRAY_TYPE,
- SHARED_FUNCTION_INFO_TYPE,
- SHARED_FUNCTION_INFO_TYPE,
- SHARED_FUNCTION_INFO_TYPE,
- ONE_BYTE_INTERNALIZED_STRING_TYPE ["E"],
- ONE_BYTE_INTERNALIZED_STRING_TYPE ["callE"],
-]
-handlers: [
-]
-
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden
index 9cb5a6b01c..1a4ad60629 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden
@@ -220,13 +220,10 @@ snippet: "
"
frame size: 4
parameter count: 1
-bytecode array length: 53
+bytecode array length: 44
bytecodes: [
/* 10 E> */ B(StackCheck),
/* 37 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(41),
- B(JumpIfNull), U8(4),
- B(JumpIfNotUndefined), U8(7),
- /* 26 E> */ B(CallRuntime), U16(Runtime::kThrowPatternAssignmentNonCoercible), R(0), U8(0),
B(Star), R(3),
/* 28 S> */ B(LdaNamedProperty), R(3), U8(1), U8(1),
B(Star), R(0),
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/SuperCallAndSpread.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/SuperCallAndSpread.golden
index 74849d1c85..e3eed68138 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/SuperCallAndSpread.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/SuperCallAndSpread.golden
@@ -91,9 +91,9 @@ snippet: "
test = new B(1, 2, 3).constructor;
})();
"
-frame size: 13
+frame size: 12
parameter count: 1
-bytecode array length: 128
+bytecode array length: 124
bytecodes: [
B(CreateRestParameter),
B(Star), R(3),
@@ -111,23 +111,22 @@ bytecodes: [
B(Ldar), R(6),
B(Inc), U8(3),
/* 152 S> */ B(Star), R(6),
- B(LdaNamedProperty), R(3), U8(0), U8(4),
+ B(GetIterator), R(3), U8(4),
B(Star), R(11),
B(CallProperty0), R(11), R(3), U8(6),
- B(Mov), R(3), R(10),
B(Mov), R(1), R(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(9),
- B(LdaNamedProperty), R(9), U8(1), U8(8),
+ B(LdaNamedProperty), R(9), U8(0), U8(8),
B(Star), R(8),
B(CallProperty0), R(8), R(9), U8(14),
- B(Star), R(12),
+ B(Star), R(10),
B(JumpIfJSReceiver), U8(7),
- B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(12), U8(1),
- B(LdaNamedProperty), R(12), U8(2), U8(16),
+ B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
+ B(LdaNamedProperty), R(10), U8(1), U8(16),
B(JumpIfToBooleanTrue), U8(19),
- B(LdaNamedProperty), R(12), U8(3), U8(10),
+ B(LdaNamedProperty), R(10), U8(2), U8(10),
B(StaInArrayLiteral), R(7), R(6), U8(1),
B(Ldar), R(6),
B(Inc), U8(3),
@@ -147,7 +146,6 @@ bytecodes: [
/* 162 S> */ B(Return),
]
constant pool: [
- SYMBOL_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
diff --git a/deps/v8/test/cctest/interpreter/bytecode_expectations/WideRegisters.golden b/deps/v8/test/cctest/interpreter/bytecode_expectations/WideRegisters.golden
index 19a09ba49c..066d6e9f03 100644
--- a/deps/v8/test/cctest/interpreter/bytecode_expectations/WideRegisters.golden
+++ b/deps/v8/test/cctest/interpreter/bytecode_expectations/WideRegisters.golden
@@ -2655,7 +2655,7 @@ snippet: "
"
frame size: 163
parameter count: 1
-bytecode array length: 626
+bytecode array length: 624
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 43 S> */ B(LdaZero),
@@ -2977,8 +2977,7 @@ bytecodes: [
/* 2146 S> */ B(LdaZero),
B(Star), R(1),
/* 2162 S> */ B(Ldar), R(0),
- B(JumpIfUndefined), U8(74),
- B(JumpIfNull), U8(72),
+ B(JumpIfUndefinedOrNull), U8(72),
B(Wide), B(ToObject), R16(157),
B(Wide), B(ForInEnumerate), R16(157),
B(Wide), B(ForInPrepare), R16(158), U16(0),
diff --git a/deps/v8/test/cctest/interpreter/test-bytecode-generator.cc b/deps/v8/test/cctest/interpreter/test-bytecode-generator.cc
index e1601d4642..fda02933aa 100644
--- a/deps/v8/test/cctest/interpreter/test-bytecode-generator.cc
+++ b/deps/v8/test/cctest/interpreter/test-bytecode-generator.cc
@@ -2758,7 +2758,7 @@ TEST(PrivateClassFields) {
LoadGolden("PrivateClassFields.golden")));
}
-TEST(PrivateMethods) {
+TEST(PrivateMethodDeclaration) {
bool old_methods_flag = i::FLAG_harmony_private_methods;
i::FLAG_harmony_private_methods = true;
InitializedIgnitionHandleScope scope;
@@ -2768,30 +2768,179 @@ TEST(PrivateMethods) {
"{\n"
" class A {\n"
" #a() { return 1; }\n"
- " callA() { return this.#a(); }\n"
" }\n"
- "\n"
- " const a = new A;\n"
- " a.callA();\n"
"}\n",
"{\n"
" class D {\n"
" #d() { return 1; }\n"
- " callD() { return this.#d(); }\n"
" }\n"
- "\n"
" class E extends D {\n"
" #e() { return 2; }\n"
- " callE() { return this.callD() + this.#e(); }\n"
+ " }\n"
+ "}\n",
+
+ "{\n"
+ " class A { foo() {} }\n"
+ " class C extends A {\n"
+ " #m() { return super.foo; }\n"
+ " }\n"
+ "}\n"};
+
+ CHECK(CompareTexts(BuildActual(printer, snippets),
+ LoadGolden("PrivateMethodDeclaration.golden")));
+ i::FLAG_harmony_private_methods = old_methods_flag;
+}
+
+TEST(PrivateMethodAccess) {
+ bool old_methods_flag = i::FLAG_harmony_private_methods;
+ i::FLAG_harmony_private_methods = true;
+ InitializedIgnitionHandleScope scope;
+ BytecodeExpectationsPrinter printer(CcTest::isolate());
+ printer.set_wrap(false);
+ printer.set_test_function_name("test");
+
+ const char* snippets[] = {
+ "class A {\n"
+ " #a() { return 1; }\n"
+ " constructor() { return this.#a(); }\n"
+ "}\n"
+ "\n"
+ "var test = A;\n"
+ "new A;\n",
+
+ "class B {\n"
+ " #b() { return 1; }\n"
+ " constructor() { this.#b = 1; }\n"
+ "}\n"
+ "\n"
+ "var test = B;\n"
+ "new test;\n",
+
+ "class C {\n"
+ " #c() { return 1; }\n"
+ " constructor() { this.#c++; }\n"
+ "}\n"
+ "\n"
+ "var test = C;\n"
+ "new test;\n"};
+
+ CHECK(CompareTexts(BuildActual(printer, snippets),
+ LoadGolden("PrivateMethodAccess.golden")));
+ i::FLAG_harmony_private_methods = old_methods_flag;
+}
+
+TEST(PrivateAccessorAccess) {
+ bool old_methods_flag = i::FLAG_harmony_private_methods;
+ i::FLAG_harmony_private_methods = true;
+ InitializedIgnitionHandleScope scope;
+ BytecodeExpectationsPrinter printer(CcTest::isolate());
+ printer.set_wrap(false);
+ printer.set_test_function_name("test");
+
+ const char* snippets[] = {
+ "class A {\n"
+ " get #a() { return 1; }\n"
+ " set #a(val) { }\n"
+ "\n"
+ " constructor() {\n"
+ " this.#a++;\n"
+ " this.#a = 1;\n"
+ " return this.#a;\n"
+ " }\n"
+ "}\n"
+ "var test = A;\n"
+ "new test;\n",
+
+ "class B {\n"
+ " get #b() { return 1; }\n"
+ " constructor() { this.#b++; }\n"
+ "}\n"
+ "var test = B;\n"
+ "new test;\n",
+
+ "class C {\n"
+ " set #c(val) { }\n"
+ " constructor() { this.#c++; }\n"
+ "}\n"
+ "var test = C;\n"
+ "new test;\n",
+
+ "class D {\n"
+ " get #d() { return 1; }\n"
+ " constructor() { this.#d = 1; }\n"
+ "}\n"
+ "var test = D;\n"
+ "new test;\n",
+
+ "class E {\n"
+ " set #e(val) { }\n"
+ " constructor() { this.#e; }\n"
+ "}\n"
+ "var test = E;\n"
+ "new test;\n"};
+
+ CHECK(CompareTexts(BuildActual(printer, snippets),
+ LoadGolden("PrivateAccessorAccess.golden")));
+ i::FLAG_harmony_private_methods = old_methods_flag;
+}
+
+TEST(PrivateAccessorDeclaration) {
+ bool old_methods_flag = i::FLAG_harmony_private_methods;
+ i::FLAG_harmony_private_methods = true;
+ InitializedIgnitionHandleScope scope;
+ BytecodeExpectationsPrinter printer(CcTest::isolate());
+
+ const char* snippets[] = {
+ "{\n"
+ " class A {\n"
+ " get #a() { return 1; }\n"
+ " set #a(val) { }\n"
+ " }\n"
+ "}\n",
+
+ "{\n"
+ " class B {\n"
+ " get #b() { return 1; }\n"
+ " }\n"
+ "}\n",
+
+ "{\n"
+ " class C {\n"
+ " set #c(val) { }\n"
+ " }\n"
+ "}\n",
+
+ "{\n"
+ " class D {\n"
+ " get #d() { return 1; }\n"
+ " set #d(val) { }\n"
" }\n"
"\n"
- " const e = new E;\n"
- " e.callE();\n"
+ " class E extends D {\n"
+ " get #e() { return 2; }\n"
+ " set #e(val) { }\n"
+ " }\n"
+ "}\n",
+
+ "{\n"
+ " class A { foo() {} }\n"
+ " class C extends A {\n"
+ " get #a() { return super.foo; }\n"
+ " }\n"
+ " new C();\n"
+ "}\n",
+
+ "{\n"
+ " class A { foo(val) {} }\n"
+ " class C extends A {\n"
+ " set #a(val) { super.foo(val); }\n"
+ " }\n"
+ " new C();\n"
"}\n"};
CHECK(CompareTexts(BuildActual(printer, snippets),
- LoadGolden("PrivateMethods.golden")));
+ LoadGolden("PrivateAccessorDeclaration.golden")));
i::FLAG_harmony_private_methods = old_methods_flag;
}
diff --git a/deps/v8/test/cctest/libplatform/test-tracing.cc b/deps/v8/test/cctest/libplatform/test-tracing.cc
index d20dfff652..a98445be97 100644
--- a/deps/v8/test/cctest/libplatform/test-tracing.cc
+++ b/deps/v8/test/cctest/libplatform/test-tracing.cc
@@ -23,14 +23,10 @@
class TestDataSource : public perfetto::DataSource<TestDataSource> {
public:
void OnSetup(const SetupArgs&) override {}
- void OnStart(const StartArgs&) override { started_.Signal(); }
+ void OnStart(const StartArgs&) override {}
void OnStop(const StopArgs&) override {}
-
- static v8::base::Semaphore started_;
};
-v8::base::Semaphore TestDataSource::started_{0};
-
PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(TestDataSource);
#endif // V8_USE_PERFETTO
@@ -625,8 +621,6 @@ TEST(Perfetto) {
TRACE_EVENT1("v8", "test2", "arg1", uint64_arg);
TRACE_EVENT2("v8", "test3", "arg1", uint64_arg, "arg2", str_arg);
}
- TRACE_EVENT_INSTANT0("v8", "final event not captured",
- TRACE_EVENT_SCOPE_THREAD);
harness.StopTracing();
@@ -688,8 +682,6 @@ TEST(Categories) {
TRACE_EVENT0("cat", "v8.Test2");
TRACE_EVENT0("v8", "v8.Test3");
}
- TRACE_EVENT_INSTANT0("v8", "final event not captured",
- TRACE_EVENT_SCOPE_THREAD);
harness.StopTracing();
@@ -765,8 +757,6 @@ TEST(MultipleArgsAndCopy) {
std::move(trace_event_arg), "a2",
new ConvertableToTraceFormatMock(123));
}
- TRACE_EVENT_INSTANT0("v8", "final event not captured",
- TRACE_EVENT_SCOPE_THREAD);
harness.StopTracing();
@@ -894,8 +884,6 @@ TEST(JsonIntegrationTest) {
TRACE_EVENT1("v8", "v8.Test.3", "3", inf_num);
TRACE_EVENT1("v8", "v8.Test.4", "4", neg_inf_num);
}
- TRACE_EVENT_INSTANT0("v8", "final event not captured",
- TRACE_EVENT_SCOPE_THREAD);
harness.StopTracing();
std::string json = harness.perfetto_json_stream();
@@ -922,8 +910,7 @@ TEST(TracingPerfetto) {
auto tracing_session_ =
perfetto::Tracing::NewTrace(perfetto::BackendType::kInProcessBackend);
tracing_session_->Setup(perfetto_trace_config);
- tracing_session_->Start();
- TestDataSource::started_.Wait();
+ tracing_session_->StartBlocking();
for (int i = 0; i < 15; i++) {
TestDataSource::Trace([&](TestDataSource::TraceContext ctx) {
@@ -938,10 +925,7 @@ TEST(TracingPerfetto) {
trace_event->set_thread_timestamp(123);
});
}
- v8::base::Semaphore stopped_{0};
- tracing_session_->SetOnStopCallback([&stopped_]() { stopped_.Signal(); });
- tracing_session_->Stop();
- stopped_.Wait();
+ tracing_session_->StopBlocking();
std::ostringstream perfetto_json_stream_;
@@ -957,6 +941,40 @@ TEST(TracingPerfetto) {
CHECK_GT(perfetto_json_stream_.str().length(), 0);
}
+TEST(StartAndStopRepeated) {
+ for (int i = 0; i < 3; i++) {
+ ::perfetto::TraceConfig perfetto_trace_config;
+ perfetto_trace_config.add_buffers()->set_size_kb(4096);
+ auto* ds_config =
+ perfetto_trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("v8.trace_events");
+
+ perfetto::DataSourceDescriptor dsd;
+ dsd.set_name("v8.trace_events");
+ TestDataSource::Register(dsd);
+
+ auto tracing_session_ =
+ perfetto::Tracing::NewTrace(perfetto::BackendType::kInProcessBackend);
+ tracing_session_->Setup(perfetto_trace_config);
+ tracing_session_->StartBlocking();
+
+ for (int i = 0; i < 15; i++) {
+ TestDataSource::Trace([&](TestDataSource::TraceContext ctx) {
+ auto packet = ctx.NewTracePacket();
+ auto* trace_event_bundle = packet->set_chrome_events();
+ auto* trace_event = trace_event_bundle->add_trace_events();
+
+ trace_event->set_phase('c');
+ trace_event->set_thread_id(v8::base::OS::GetCurrentThreadId());
+ trace_event->set_timestamp(123);
+ trace_event->set_process_id(v8::base::OS::GetCurrentProcessId());
+ trace_event->set_thread_timestamp(123);
+ });
+ }
+ tracing_session_->StopBlocking();
+ }
+}
+
#endif // V8_USE_PERFETTO
} // namespace tracing
diff --git a/deps/v8/test/cctest/parsing/test-scanner-streams.cc b/deps/v8/test/cctest/parsing/test-scanner-streams.cc
index 39d95897d6..35b7048bb0 100644
--- a/deps/v8/test/cctest/parsing/test-scanner-streams.cc
+++ b/deps/v8/test/cctest/parsing/test-scanner-streams.cc
@@ -776,6 +776,43 @@ TEST(RelocatingCharacterStream) {
CHECK_EQ('d', two_byte_string_stream->Advance());
}
+TEST(RelocatingUnbufferedCharacterStream) {
+ ManualGCScope manual_gc_scope;
+ CcTest::InitializeVM();
+ i::Isolate* i_isolate = CcTest::i_isolate();
+ v8::HandleScope scope(CcTest::isolate());
+
+ const char16_t* string = u"abc\u2603";
+ int length = static_cast<int>(std::char_traits<char16_t>::length(string));
+ std::unique_ptr<i::uc16[]> uc16_buffer(new i::uc16[length]);
+ for (int i = 0; i < length; i++) {
+ uc16_buffer[i] = string[i];
+ }
+ i::Vector<const i::uc16> two_byte_vector(uc16_buffer.get(), length);
+ i::Handle<i::String> two_byte_string =
+ i_isolate->factory()
+ ->NewStringFromTwoByte(two_byte_vector, i::AllocationType::kYoung)
+ .ToHandleChecked();
+ std::unique_ptr<i::Utf16CharacterStream> two_byte_string_stream(
+ i::ScannerStream::For(i_isolate, two_byte_string, 0, length));
+
+ // Seek to offset 2 so that the buffer_pos_ is not zero initially.
+ two_byte_string_stream->Seek(2);
+ CHECK_EQ('c', two_byte_string_stream->Advance());
+ CHECK_EQ(size_t{3}, two_byte_string_stream->pos());
+
+ i::String raw = *two_byte_string;
+ i_isolate->heap()->CollectGarbage(i::NEW_SPACE,
+ i::GarbageCollectionReason::kUnknown);
+ // GC moved the string and buffer was updated to the correct location.
+ CHECK_NE(raw, *two_byte_string);
+
+ // Check that we correctly moved based on buffer_pos_, not based on a position
+ // of zero.
+ CHECK_EQ(u'\u2603', two_byte_string_stream->Advance());
+ CHECK_EQ(size_t{4}, two_byte_string_stream->pos());
+}
+
TEST(CloneCharacterStreams) {
v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
diff --git a/deps/v8/test/cctest/test-accessor-assembler.cc b/deps/v8/test/cctest/test-accessor-assembler.cc
index 20a2bc2d80..c88c85b586 100644
--- a/deps/v8/test/cctest/test-accessor-assembler.cc
+++ b/deps/v8/test/cctest/test-accessor-assembler.cc
@@ -18,6 +18,7 @@ namespace internal {
using compiler::CodeAssemblerTester;
using compiler::FunctionTester;
using compiler::Node;
+using compiler::TNode;
namespace {
@@ -129,8 +130,9 @@ TEST(TryProbeStubCache) {
{
Node* receiver = m.Parameter(0);
- Node* name = m.Parameter(1);
- Node* expected_handler = m.Parameter(2);
+ TNode<Object> name = m.CAST(m.Parameter(1));
+ TNode<MaybeObject> expected_handler =
+ m.UncheckedCast<MaybeObject>(m.Parameter(2));
Label passed(&m), failed(&m);
@@ -140,12 +142,11 @@ TEST(TryProbeStubCache) {
m.TryProbeStubCache(&stub_cache, receiver, name, &if_handler, &var_handler,
&if_miss);
m.BIND(&if_handler);
- m.Branch(m.WordEqual(expected_handler,
- m.BitcastMaybeObjectToWord(var_handler.value())),
- &passed, &failed);
+ m.Branch(m.TaggedEqual(expected_handler, var_handler.value()), &passed,
+ &failed);
m.BIND(&if_miss);
- m.Branch(m.WordEqual(expected_handler, m.IntPtrConstant(0)), &passed,
+ m.Branch(m.TaggedEqual(expected_handler, m.SmiConstant(0)), &passed,
&failed);
m.BIND(&passed);
diff --git a/deps/v8/test/cctest/test-api-stack-traces.cc b/deps/v8/test/cctest/test-api-stack-traces.cc
index bceba18c4a..26941793c6 100644
--- a/deps/v8/test/cctest/test-api-stack-traces.cc
+++ b/deps/v8/test/cctest/test-api-stack-traces.cc
@@ -250,31 +250,31 @@ static void AnalyzeStackInNativeCode(
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
args.GetIsolate(), 5, v8::StackTrace::kOverview);
CHECK_EQ(3, stackTrace->GetFrameCount());
- checkStackFrame(nullptr, "function.name", 3, 1, true, false,
+ checkStackFrame(nullptr, "function.name", 1, 1, true, false,
stackTrace->GetFrame(isolate, 0));
} else if (testGroup == kDisplayName) {
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
args.GetIsolate(), 5, v8::StackTrace::kOverview);
CHECK_EQ(3, stackTrace->GetFrameCount());
- checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
+ checkStackFrame(nullptr, "function.displayName", 1, 1, true, false,
stackTrace->GetFrame(isolate, 0));
} else if (testGroup == kFunctionNameAndDisplayName) {
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
args.GetIsolate(), 5, v8::StackTrace::kOverview);
CHECK_EQ(3, stackTrace->GetFrameCount());
- checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
+ checkStackFrame(nullptr, "function.displayName", 1, 1, true, false,
stackTrace->GetFrame(isolate, 0));
} else if (testGroup == kDisplayNameIsNotString) {
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
args.GetIsolate(), 5, v8::StackTrace::kOverview);
CHECK_EQ(3, stackTrace->GetFrameCount());
- checkStackFrame(nullptr, "function.name", 3, 1, true, false,
+ checkStackFrame(nullptr, "function.name", 1, 1, true, false,
stackTrace->GetFrame(isolate, 0));
} else if (testGroup == kFunctionNameIsNotString) {
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
args.GetIsolate(), 5, v8::StackTrace::kOverview);
CHECK_EQ(3, stackTrace->GetFrameCount());
- checkStackFrame(nullptr, "", 3, 1, true, false,
+ checkStackFrame(nullptr, "", 1, 1, true, false,
stackTrace->GetFrame(isolate, 0));
}
}
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc
index 73bea08d08..1a670a9b10 100644
--- a/deps/v8/test/cctest/test-api.cc
+++ b/deps/v8/test/cctest/test-api.cc
@@ -12975,7 +12975,7 @@ void ApiTestFuzzer::SetUp(PartOfTest part) {
RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
}
for (int i = 0; i < active_tests_; i++) {
- RegisterThreadedTest::nth(i)->fuzzer_->Start();
+ CHECK(RegisterThreadedTest::nth(i)->fuzzer_->Start());
}
}
@@ -18386,8 +18386,8 @@ TEST(MultipleIsolatesOnIndividualThreads) {
IsolateThread thread2(12);
// Compute some fibonacci numbers on 3 threads in 3 isolates.
- thread1.Start();
- thread2.Start();
+ CHECK(thread1.Start());
+ CHECK(thread2.Start());
int result1 = CalcFibonacci(CcTest::isolate(), 21);
int result2 = CalcFibonacci(CcTest::isolate(), 12);
@@ -18481,7 +18481,7 @@ class InitDefaultIsolateThread : public v8::base::Thread {
static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
InitDefaultIsolateThread thread(testCase);
- thread.Start();
+ CHECK(thread.Start());
thread.Join();
CHECK(thread.result());
}
@@ -19953,6 +19953,71 @@ TEST(ScopedMicrotasks) {
env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
{
v8::MicrotasksScope scope1(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+ env->GetIsolate()->EnqueueMicrotask(
+ Function::New(env.local(), MicrotaskOne).ToLocalChecked());
+ CompileRun("var ext1Calls = 0;");
+ }
+ {
+ v8::MicrotasksScope scope1(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+ ExpectInt32("ext1Calls", 1);
+ }
+ {
+ v8::MicrotasksScope scope1(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+ env->GetIsolate()->EnqueueMicrotask(
+ Function::New(env.local(), MicrotaskOne).ToLocalChecked());
+ CompileRun("throw new Error()");
+ }
+ {
+ v8::MicrotasksScope scope1(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+ ExpectInt32("ext1Calls", 2);
+ }
+ {
+ v8::MicrotasksScope scope1(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+ env->GetIsolate()->EnqueueMicrotask(
+ Function::New(env.local(), MicrotaskOne).ToLocalChecked());
+ v8::TryCatch try_catch(env->GetIsolate());
+ CompileRun("throw new Error()");
+ }
+ {
+ v8::MicrotasksScope scope1(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+ ExpectInt32("ext1Calls", 3);
+ }
+ {
+ v8::MicrotasksScope scope1(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+ env->GetIsolate()->EnqueueMicrotask(
+ Function::New(env.local(), MicrotaskOne).ToLocalChecked());
+ env->GetIsolate()->TerminateExecution();
+ {
+ v8::MicrotasksScope scope2(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+ env->GetIsolate()->EnqueueMicrotask(
+ Function::New(env.local(), MicrotaskOne).ToLocalChecked());
+ }
+ }
+ env->GetIsolate()->CancelTerminateExecution();
+ {
+ v8::MicrotasksScope scope1(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+ ExpectInt32("ext1Calls", 3);
+ env->GetIsolate()->EnqueueMicrotask(
+ Function::New(env.local(), MicrotaskOne).ToLocalChecked());
+ }
+ {
+ v8::MicrotasksScope scope1(env->GetIsolate(),
+ v8::MicrotasksScope::kRunMicrotasks);
+
+ ExpectInt32("ext1Calls", 4);
+ }
+
+ {
+ v8::MicrotasksScope scope1(env->GetIsolate(),
v8::MicrotasksScope::kDoNotRunMicrotasks);
env->GetIsolate()->EnqueueMicrotask(
Function::New(env.local(), MicrotaskOne).ToLocalChecked());
@@ -20746,7 +20811,7 @@ class ThreadInterruptTest {
void RunTest() {
InterruptThread i_thread(this);
- i_thread.Start();
+ CHECK(i_thread.Start());
sem_.Wait();
CHECK_EQ(kExpectedValue, sem_value_);
@@ -21009,7 +21074,7 @@ class RegExpInterruptTest {
v8::HandleScope handle_scope(isolate_);
i_thread.SetTestBody(test_body_fn);
- i_thread.Start();
+ CHECK(i_thread.Start());
TestBody();
@@ -21213,7 +21278,7 @@ class RequestInterruptTestBaseWithSimpleInterrupt
public:
RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
- void StartInterruptThread() override { i_thread.Start(); }
+ void StartInterruptThread() override { CHECK(i_thread.Start()); }
private:
class InterruptThread : public v8::base::Thread {
@@ -21444,7 +21509,7 @@ class RequestMultipleInterrupts : public RequestInterruptTestBase {
public:
RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
- void StartInterruptThread() override { i_thread.Start(); }
+ void StartInterruptThread() override { CHECK(i_thread.Start()); }
void TestBody() override {
Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
@@ -24851,7 +24916,7 @@ TEST(FutexInterruption) {
FutexInterruptionThread timeout_thread(isolate);
v8::TryCatch try_catch(CcTest::isolate());
- timeout_thread.Start();
+ CHECK(timeout_thread.Start());
CompileRun(
"var ab = new SharedArrayBuffer(4);"
@@ -25268,7 +25333,7 @@ TEST(MemoryPressure) {
LocalContext env;
MemoryPressureThread memory_pressure_thread(
isolate, v8::MemoryPressureLevel::kCritical);
- memory_pressure_thread.Start();
+ CHECK(memory_pressure_thread.Start());
memory_pressure_thread.Join();
// This should trigger GC.
CHECK_EQ(0, counter.NumberOfWeakCalls());
@@ -26080,7 +26145,7 @@ void AtomicsWaitCallbackForTesting(
break;
case AtomicsWaitCallbackAction::StopFromThreadAndThrow:
info->stop_thread = v8::base::make_unique<StopAtomicsWaitThread>(info);
- info->stop_thread->Start();
+ CHECK(info->stop_thread->Start());
break;
case AtomicsWaitCallbackAction::KeepWaiting:
break;
diff --git a/deps/v8/test/cctest/test-assembler-arm64.cc b/deps/v8/test/cctest/test-assembler-arm64.cc
index 1f6b732808..4fdf30ef64 100644
--- a/deps/v8/test/cctest/test-assembler-arm64.cc
+++ b/deps/v8/test/cctest/test-assembler-arm64.cc
@@ -234,6 +234,15 @@ static void InitializeVM() {
#define CHECK_FULL_HEAP_OBJECT_IN_REGISTER(expected, result) \
CHECK(Equal64(expected->ptr(), &core, result))
+#define CHECK_NOT_ZERO_AND_NOT_EQUAL_64(reg0, reg1) \
+ { \
+ int64_t value0 = core.xreg(reg0.code()); \
+ int64_t value1 = core.xreg(reg1.code()); \
+ CHECK_NE(0, value0); \
+ CHECK_NE(0, value1); \
+ CHECK_NE(value0, value1); \
+ }
+
#define CHECK_EQUAL_FP64(expected, result) \
CHECK(EqualFP64(expected, &core, result))
@@ -1982,75 +1991,142 @@ TEST(test_branch) {
CHECK_EQUAL_64(0, x3);
}
+namespace {
+// Generate a block of code that, when hit, always jumps to `landing_pad`.
+void GenerateLandingNops(MacroAssembler* masm, int n, Label* landing_pad) {
+ for (int i = 0; i < (n - 1); i++) {
+ if (i % 100 == 0) {
+ masm->B(landing_pad);
+ } else {
+ masm->Nop();
+ }
+ }
+ masm->B(landing_pad);
+}
+} // namespace
+
TEST(far_branch_backward) {
INIT_V8();
- // Test that the MacroAssembler correctly resolves backward branches to labels
- // that are outside the immediate range of branch instructions.
- int max_range =
- std::max(Instruction::ImmBranchRange(TestBranchType),
- std::max(Instruction::ImmBranchRange(CompareBranchType),
- Instruction::ImmBranchRange(CondBranchType)));
+ ImmBranchType branch_types[] = {TestBranchType, CompareBranchType,
+ CondBranchType};
- SETUP_SIZE(max_range + 1000 * kInstrSize);
+ for (ImmBranchType type : branch_types) {
+ int range = Instruction::ImmBranchRange(type);
- START();
+ SETUP_SIZE(range + 1000 * kInstrSize);
- Label done, fail;
- Label test_tbz, test_cbz, test_bcond;
- Label success_tbz, success_cbz, success_bcond;
+ START();
- __ Mov(x0, 0);
- __ Mov(x1, 1);
- __ Mov(x10, 0);
+ Label done, fail;
+ Label near, far, in_range, out_of_range;
- __ B(&test_tbz);
- __ Bind(&success_tbz);
- __ Orr(x0, x0, 1 << 0);
- __ B(&test_cbz);
- __ Bind(&success_cbz);
- __ Orr(x0, x0, 1 << 1);
- __ B(&test_bcond);
- __ Bind(&success_bcond);
- __ Orr(x0, x0, 1 << 2);
+ __ Mov(x0, 0);
+ __ Mov(x1, 1);
+ __ Mov(x10, 0);
- __ B(&done);
+ __ B(&near);
+ __ Bind(&in_range);
+ __ Orr(x0, x0, 1 << 0);
- // Generate enough code to overflow the immediate range of the three types of
- // branches below.
- for (int i = 0; i < max_range / kInstrSize + 1; ++i) {
- if (i % 100 == 0) {
- // If we do land in this code, we do not want to execute so many nops
- // before reaching the end of test (especially if tracing is activated).
- __ B(&fail);
- } else {
- __ Nop();
- }
- }
- __ B(&fail);
+ __ B(&far);
+ __ Bind(&out_of_range);
+ __ Orr(x0, x0, 1 << 1);
- __ Bind(&test_tbz);
- __ Tbz(x10, 7, &success_tbz);
- __ Bind(&test_cbz);
- __ Cbz(x10, &success_cbz);
- __ Bind(&test_bcond);
- __ Cmp(x10, 0);
- __ B(eq, &success_bcond);
+ __ B(&done);
- // For each out-of-range branch instructions, at least two instructions should
- // have been generated.
- CHECK_GE(7 * kInstrSize, __ SizeOfCodeGeneratedSince(&test_tbz));
+ // We use a slack and an approximate budget instead of checking precisely
+ // when the branch limit is hit, since veneers and literal pool can mess
+ // with our calculation of where the limit is.
+ // In this test, we want to make sure we support backwards branches and the
+ // range is more-or-less correct. It's not a big deal if the macro-assembler
+ // got the range a little wrong, as long as it's not far off which could
+ // affect performance.
+
+ int budget =
+ (range - static_cast<int>(__ SizeOfCodeGeneratedSince(&in_range))) /
+ kInstrSize;
+
+ const int kSlack = 100;
+
+ // Generate enough code so that the next branch will be in range but we are
+ // close to the limit.
+ GenerateLandingNops(&masm, budget - kSlack, &fail);
+
+ __ Bind(&near);
+ switch (type) {
+ case TestBranchType:
+ __ Tbz(x10, 3, &in_range);
+ // This should be:
+ // TBZ <in_range>
+ CHECK_EQ(1 * kInstrSize, __ SizeOfCodeGeneratedSince(&near));
+ break;
+ case CompareBranchType:
+ __ Cbz(x10, &in_range);
+ // This should be:
+ // CBZ <in_range>
+ CHECK_EQ(1 * kInstrSize, __ SizeOfCodeGeneratedSince(&near));
+ break;
+ case CondBranchType:
+ __ Cmp(x10, 0);
+ __ B(eq, &in_range);
+ // This should be:
+ // CMP
+ // B.EQ <in_range>
+ CHECK_EQ(2 * kInstrSize, __ SizeOfCodeGeneratedSince(&near));
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
- __ Bind(&fail);
- __ Mov(x1, 0);
- __ Bind(&done);
+ // Now go past the limit so that branches are now out of range.
+ GenerateLandingNops(&masm, kSlack * 2, &fail);
+
+ __ Bind(&far);
+ switch (type) {
+ case TestBranchType:
+ __ Tbz(x10, 5, &out_of_range);
+ // This should be:
+ // TBNZ <skip>
+ // B <out_of_range>
+ // skip:
+ CHECK_EQ(2 * kInstrSize, __ SizeOfCodeGeneratedSince(&far));
+ break;
+ case CompareBranchType:
+ __ Cbz(x10, &out_of_range);
+ // This should be:
+ // CBNZ <skip>
+ // B <out_of_range>
+ // skip:
+ CHECK_EQ(2 * kInstrSize, __ SizeOfCodeGeneratedSince(&far));
+ break;
+ case CondBranchType:
+ __ Cmp(x10, 0);
+ __ B(eq, &out_of_range);
+ // This should be:
+ // CMP
+ // B.NE <skip>
+ // B <out_of_range>
+ // skip:
+ CHECK_EQ(3 * kInstrSize, __ SizeOfCodeGeneratedSince(&far));
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
- END();
+ __ Bind(&fail);
+ __ Mov(x1, 0);
+ __ Bind(&done);
- RUN();
+ END();
- CHECK_EQUAL_64(0x7, x0);
- CHECK_EQUAL_64(0x1, x1);
+ RUN();
+
+ CHECK_EQUAL_64(0x3, x0);
+ CHECK_EQUAL_64(1, x1);
+ }
}
TEST(far_branch_simple_veneer) {
@@ -2177,18 +2253,7 @@ TEST(far_branch_veneer_link_chain) {
// Generate enough code to overflow the immediate range of the three types of
// branches below.
- for (int i = 0; i < max_range / kInstrSize + 1; ++i) {
- if (i % 100 == 0) {
- // If we do land in this code, we do not want to execute so many nops
- // before reaching the end of test (especially if tracing is activated).
- // Also, the branches give the MacroAssembler the opportunity to emit the
- // veneers.
- __ B(&fail);
- } else {
- __ Nop();
- }
- }
- __ B(&fail);
+ GenerateLandingNops(&masm, (max_range / kInstrSize) + 1, &fail);
__ Bind(&success_tbz);
__ Orr(x0, x0, 1 << 0);
@@ -2219,7 +2284,58 @@ TEST(far_branch_veneer_broken_link_chain) {
// a branch from the link chain of a label and the two links on each side of
// the removed branch cannot be linked together (out of range).
//
- // We test with tbz because it has a small range.
+ // We want to generate the following code, we test with tbz because it has a
+ // small range:
+ //
+ // ~~~
+ // 1: B <far>
+ // :
+ // :
+ // :
+ // 2: TBZ <far> -------.
+ // : |
+ // : | out of range
+ // : |
+ // 3: TBZ <far> |
+ // | |
+ // | in range |
+ // V |
+ // far: <-'
+ // ~~~
+ //
+ // If we say that the range of TBZ is 3 lines on this graph, then we can get
+ // into a situation where the link chain gets broken. When emitting the two
+ // TBZ instructions, we are in range of the previous branch in the chain so
+ // we'll generate a TBZ and not a TBNZ+B sequence that can encode a bigger
+ // range.
+ //
+ // However, the first TBZ (2), is out of range of the far label so a veneer
+ // will be generated after the second TBZ (3). And this will result in a
+ // broken chain because we can no longer link from (3) back to (1).
+ //
+ // ~~~
+ // 1: B <far> <-.
+ // :
+ // : out of range
+ // :
+ // 2: TBZ <veneer> :
+ // :
+ // :
+ // :
+ // 3: TBZ <far> ----'
+ //
+ // B <skip>
+ // veneer:
+ // B <far>
+ // skip:
+ //
+ // far:
+ // ~~~
+ //
+ // This test makes sure the MacroAssembler is able to resolve this case by,
+ // for instance, resolving (1) early and making it jump to <veneer> instead of
+ // <far>.
+
int max_range = Instruction::ImmBranchRange(TestBranchType);
int inter_range = max_range / 2 + max_range / 10;
@@ -2240,44 +2356,42 @@ TEST(far_branch_veneer_broken_link_chain) {
__ Mov(x0, 1);
__ B(&far_target);
- for (int i = 0; i < inter_range / kInstrSize; ++i) {
- if (i % 100 == 0) {
- // Do not allow generating veneers. They should not be needed.
- __ b(&fail);
- } else {
- __ Nop();
- }
- }
+ GenerateLandingNops(&masm, inter_range / kInstrSize, &fail);
// Will need a veneer to point to reach the target.
__ Bind(&test_2);
__ Mov(x0, 2);
- __ Tbz(x10, 7, &far_target);
-
- for (int i = 0; i < inter_range / kInstrSize; ++i) {
- if (i % 100 == 0) {
- // Do not allow generating veneers. They should not be needed.
- __ b(&fail);
- } else {
- __ Nop();
- }
+ {
+ Label tbz;
+ __ Bind(&tbz);
+ __ Tbz(x10, 7, &far_target);
+ // This should be a single TBZ since the previous link is in range at this
+ // point.
+ CHECK_EQ(1 * kInstrSize, __ SizeOfCodeGeneratedSince(&tbz));
}
+ GenerateLandingNops(&masm, inter_range / kInstrSize, &fail);
+
// Does not need a veneer to reach the target, but the initial branch
// instruction is out of range.
__ Bind(&test_3);
__ Mov(x0, 3);
- __ Tbz(x10, 7, &far_target);
-
- for (int i = 0; i < inter_range / kInstrSize; ++i) {
- if (i % 100 == 0) {
- // Allow generating veneers.
- __ B(&fail);
- } else {
- __ Nop();
- }
+ {
+ Label tbz;
+ __ Bind(&tbz);
+ __ Tbz(x10, 7, &far_target);
+ // This should be a single TBZ since the previous link is in range at this
+ // point.
+ CHECK_EQ(1 * kInstrSize, __ SizeOfCodeGeneratedSince(&tbz));
}
+ // A veneer will be generated for the first TBZ, which will then remove the
+ // label from the chain and break it because the second TBZ is out of range of
+ // the first branch.
+ // The MacroAssembler should be able to cope with this.
+
+ GenerateLandingNops(&masm, inter_range / kInstrSize, &fail);
+
__ B(&fail);
__ Bind(&far_target);
@@ -11478,6 +11592,79 @@ TEST(system_msr) {
CHECK_EQUAL_64(0, x10);
}
+TEST(system_pauth_a) {
+ SETUP();
+ START();
+
+ // Exclude x16 and x17 from the scratch register list so we can use
+ // Pac/Autia1716 safely.
+ UseScratchRegisterScope temps(&masm);
+ temps.Exclude(x16, x17);
+ temps.Include(x10, x11);
+
+ // Backup stack pointer.
+ __ Mov(x20, sp);
+
+ // Modifiers
+ __ Mov(x16, 0x477d469dec0b8768);
+ __ Mov(sp, 0x477d469dec0b8760);
+
+ // Generate PACs using the 3 system instructions.
+ __ Mov(x17, 0x0000000012345678);
+ __ Pacia1716();
+ __ Mov(x0, x17);
+
+ __ Mov(lr, 0x0000000012345678);
+ __ Paciasp();
+ __ Mov(x2, lr);
+
+ // Authenticate the pointers above.
+ __ Mov(x17, x0);
+ __ Autia1716();
+ __ Mov(x3, x17);
+
+ __ Mov(lr, x2);
+ __ Autiasp();
+ __ Mov(x5, lr);
+
+ // Attempt to authenticate incorrect pointers.
+ __ Mov(x17, x2);
+ __ Autia1716();
+ __ Mov(x6, x17);
+
+ __ Mov(lr, x0);
+ __ Autiasp();
+ __ Mov(x8, lr);
+
+ // Restore stack pointer.
+ __ Mov(sp, x20);
+
+ // Mask out just the PAC code bits.
+ __ And(x0, x0, 0x007f000000000000);
+ __ And(x2, x2, 0x007f000000000000);
+
+ END();
+
+// TODO(all): test on real hardware when available
+#ifdef USE_SIMULATOR
+ RUN();
+
+ // Check PAC codes have been generated and aren't equal.
+ // NOTE: with a different ComputePAC implementation, there may be a collision.
+ CHECK_NE(0, core.xreg(2));
+ CHECK_NOT_ZERO_AND_NOT_EQUAL_64(x0, x2);
+
+ // Pointers correctly authenticated.
+ CHECK_EQUAL_64(0x0000000012345678, x3);
+ CHECK_EQUAL_64(0x0000000012345678, x5);
+
+ // Pointers corrupted after failing to authenticate.
+ CHECK_EQUAL_64(0x0020000012345678, x6);
+ CHECK_EQUAL_64(0x0020000012345678, x8);
+
+#endif // USE_SIMULATOR
+}
+
TEST(system) {
INIT_V8();
SETUP();
@@ -14703,6 +14890,7 @@ TEST(internal_reference_linked) {
#undef CHECK_EQUAL_FP32
#undef CHECK_EQUAL_64
#undef CHECK_FULL_HEAP_OBJECT_IN_REGISTER
+#undef CHECK_NOT_ZERO_AND_NOT_EQUAL_64
#undef CHECK_EQUAL_FP64
#undef CHECK_EQUAL_128
#undef CHECK_CONSTANT_POOL_SIZE
diff --git a/deps/v8/test/cctest/test-circular-queue.cc b/deps/v8/test/cctest/test-circular-queue.cc
index 7b0475ff80..5525540d2b 100644
--- a/deps/v8/test/cctest/test-circular-queue.cc
+++ b/deps/v8/test/cctest/test-circular-queue.cc
@@ -148,7 +148,7 @@ TEST(SamplingCircularQueueMultithreading) {
ProducerThread producer3(&scq, kRecordsPerChunk, 20, &semaphore);
CHECK(!scq.Peek());
- producer1.Start();
+ CHECK(producer1.Start());
semaphore.Wait();
for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) {
Record* rec = reinterpret_cast<Record*>(scq.Peek());
@@ -160,7 +160,7 @@ TEST(SamplingCircularQueueMultithreading) {
}
CHECK(!scq.Peek());
- producer2.Start();
+ CHECK(producer2.Start());
semaphore.Wait();
for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) {
Record* rec = reinterpret_cast<Record*>(scq.Peek());
@@ -172,7 +172,7 @@ TEST(SamplingCircularQueueMultithreading) {
}
CHECK(!scq.Peek());
- producer3.Start();
+ CHECK(producer3.Start());
semaphore.Wait();
for (Record i = 20; i < 20 + kRecordsPerChunk; ++i) {
Record* rec = reinterpret_cast<Record*>(scq.Peek());
diff --git a/deps/v8/test/cctest/test-code-stub-assembler.cc b/deps/v8/test/cctest/test-code-stub-assembler.cc
index e7fc946675..3a4f11e126 100644
--- a/deps/v8/test/cctest/test-code-stub-assembler.cc
+++ b/deps/v8/test/cctest/test-code-stub-assembler.cc
@@ -53,9 +53,9 @@ Handle<String> MakeName(const char* str, int suffix) {
return MakeString(buffer.begin());
}
-int sum9(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
- int a8) {
- return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8;
+int sum10(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
+ int a8, int a9) {
+ return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9;
}
static int sum3(int a0, int a1, int a2) { return a0 + a1 + a2; }
@@ -70,8 +70,8 @@ TEST(CallCFunction) {
CodeStubAssembler m(asm_tester.state());
{
- Node* const fun_constant = m.ExternalConstant(
- ExternalReference::Create(reinterpret_cast<Address>(sum9)));
+ TNode<ExternalReference> const fun_constant = m.ExternalConstant(
+ ExternalReference::Create(reinterpret_cast<Address>(sum10)));
MachineType type_intptr = MachineType::IntPtr();
@@ -85,14 +85,15 @@ TEST(CallCFunction) {
std::make_pair(type_intptr, m.IntPtrConstant(5)),
std::make_pair(type_intptr, m.IntPtrConstant(6)),
std::make_pair(type_intptr, m.IntPtrConstant(7)),
- std::make_pair(type_intptr, m.IntPtrConstant(8)));
+ std::make_pair(type_intptr, m.IntPtrConstant(8)),
+ std::make_pair(type_intptr, m.IntPtrConstant(9)));
m.Return(m.SmiTag(result));
}
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
Handle<Object> result = ft.Call().ToHandleChecked();
- CHECK_EQ(36, Handle<Smi>::cast(result)->value());
+ CHECK_EQ(45, Handle<Smi>::cast(result)->value());
}
TEST(CallCFunctionWithCallerSavedRegisters) {
@@ -103,7 +104,7 @@ TEST(CallCFunctionWithCallerSavedRegisters) {
CodeStubAssembler m(asm_tester.state());
{
- Node* const fun_constant = m.ExternalConstant(
+ TNode<ExternalReference> const fun_constant = m.ExternalConstant(
ExternalReference::Create(reinterpret_cast<Address>(sum3)));
MachineType type_intptr = MachineType::IntPtr();
@@ -311,7 +312,7 @@ TEST(DecodeWordFromWord32) {
CodeAssemblerTester asm_tester(isolate);
CodeStubAssembler m(asm_tester.state());
- class TestBitField : public BitField<unsigned, 3, 3> {};
+ using TestBitField = BitField<unsigned, 3, 3>;
m.Return(m.SmiTag(
m.Signed(m.DecodeWordFromWord32<TestBitField>(m.Int32Constant(0x2F)))));
FunctionTester ft(asm_tester.GenerateCode());
@@ -430,35 +431,38 @@ TEST(TryToName) {
enum Result { kKeyIsIndex, kKeyIsUnique, kBailout };
{
Node* key = m.Parameter(0);
- Node* expected_result = m.Parameter(1);
- Node* expected_arg = m.Parameter(2);
+ TNode<MaybeObject> expected_result =
+ m.UncheckedCast<MaybeObject>(m.Parameter(1));
+ TNode<Object> expected_arg = m.CAST(m.Parameter(2));
Label passed(&m), failed(&m);
Label if_keyisindex(&m), if_keyisunique(&m), if_bailout(&m);
{
- Variable var_index(&m, MachineType::PointerRepresentation());
- Variable var_unique(&m, MachineRepresentation::kTagged);
+ TYPED_VARIABLE_DEF(IntPtrT, var_index, &m);
+ TYPED_VARIABLE_DEF(Object, var_unique, &m);
m.TryToName(key, &if_keyisindex, &var_index, &if_keyisunique, &var_unique,
&if_bailout);
m.BIND(&if_keyisindex);
- m.GotoIfNot(m.WordEqual(expected_result,
- m.SmiConstant(Smi::FromInt(kKeyIsIndex))),
+ m.GotoIfNot(m.TaggedEqual(expected_result,
+ m.SmiConstant(Smi::FromInt(kKeyIsIndex))),
&failed);
- m.Branch(m.WordEqual(m.SmiUntag(expected_arg), var_index.value()),
- &passed, &failed);
+ m.Branch(
+ m.IntPtrEqual(m.SmiUntag(m.CAST(expected_arg)), var_index.value()),
+ &passed, &failed);
m.BIND(&if_keyisunique);
- m.GotoIfNot(m.WordEqual(expected_result,
- m.SmiConstant(Smi::FromInt(kKeyIsUnique))),
+ m.GotoIfNot(m.TaggedEqual(expected_result,
+ m.SmiConstant(Smi::FromInt(kKeyIsUnique))),
&failed);
- m.Branch(m.WordEqual(expected_arg, var_unique.value()), &passed, &failed);
+ m.Branch(m.TaggedEqual(expected_arg, var_unique.value()), &passed,
+ &failed);
}
m.BIND(&if_bailout);
m.Branch(
- m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
&passed, &failed);
m.BIND(&passed);
@@ -653,7 +657,7 @@ void TestNameDictionaryLookup() {
&var_name_index, &if_not_found);
m.BIND(&if_found);
m.GotoIfNot(
- m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
&failed);
m.Branch(
m.WordEqual(m.SmiUntag(m.CAST(expected_arg)), var_name_index.value()),
@@ -661,7 +665,7 @@ void TestNameDictionaryLookup() {
m.BIND(&if_not_found);
m.Branch(
- m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
&passed, &failed);
m.BIND(&passed);
@@ -756,14 +760,14 @@ TEST(NumberDictionaryLookup) {
&if_not_found);
m.BIND(&if_found);
m.GotoIfNot(
- m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
&failed);
m.Branch(m.WordEqual(m.SmiUntag(m.CAST(expected_arg)), var_entry.value()),
&passed, &failed);
m.BIND(&if_not_found);
m.Branch(
- m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
&passed, &failed);
m.BIND(&passed);
@@ -847,12 +851,12 @@ TEST(TransitionLookup) {
&if_not_found);
BIND(&if_found);
- GotoIfNot(WordEqual(expected_result, SmiConstant(kFound)), &failed);
- Branch(WordEqual(expected_arg, SmiTag(var_transition_index.value())),
+ GotoIfNot(TaggedEqual(expected_result, SmiConstant(kFound)), &failed);
+ Branch(TaggedEqual(expected_arg, SmiTag(var_transition_index.value())),
&passed, &failed);
BIND(&if_not_found);
- Branch(WordEqual(expected_result, SmiConstant(kNotFound)), &passed,
+ Branch(TaggedEqual(expected_result, SmiConstant(kNotFound)), &passed,
&failed);
BIND(&passed);
@@ -1010,29 +1014,31 @@ TEST(TryHasOwnProperty) {
{
Node* object = m.Parameter(0);
Node* unique_name = m.Parameter(1);
- Node* expected_result = m.Parameter(2);
+ TNode<MaybeObject> expected_result =
+ m.UncheckedCast<MaybeObject>(m.Parameter(2));
Label passed(&m), failed(&m);
Label if_found(&m), if_not_found(&m), if_bailout(&m);
- Node* map = m.LoadMap(object);
- Node* instance_type = m.LoadMapInstanceType(map);
+ TNode<Map> map = m.LoadMap(object);
+ TNode<Uint16T> instance_type = m.LoadMapInstanceType(map);
m.TryHasOwnProperty(object, map, instance_type, unique_name, &if_found,
&if_not_found, &if_bailout);
m.BIND(&if_found);
- m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
- &passed, &failed);
+ m.Branch(
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
+ &passed, &failed);
m.BIND(&if_not_found);
m.Branch(
- m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
&passed, &failed);
m.BIND(&if_bailout);
m.Branch(
- m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
&passed, &failed);
m.BIND(&passed);
@@ -1207,8 +1213,8 @@ TEST(TryGetOwnProperty) {
Variable var_value(&m, MachineRepresentation::kTagged);
Label if_found(&m), if_not_found(&m), if_bailout(&m);
- Node* map = m.LoadMap(object);
- Node* instance_type = m.LoadMapInstanceType(map);
+ TNode<Map> map = m.LoadMap(object);
+ TNode<Uint16T> instance_type = m.LoadMapInstanceType(map);
m.TryGetOwnProperty(context, object, object, map, instance_type,
unique_name, &if_found, &var_value, &if_not_found,
@@ -1421,34 +1427,37 @@ TEST(TryLookupElement) {
enum Result { kFound, kAbsent, kNotFound, kBailout };
{
Node* object = m.Parameter(0);
- Node* index = m.SmiUntag(m.Parameter(1));
- Node* expected_result = m.Parameter(2);
+ TNode<IntPtrT> index = m.SmiUntag(m.Parameter(1));
+ TNode<MaybeObject> expected_result =
+ m.UncheckedCast<MaybeObject>(m.Parameter(2));
Label passed(&m), failed(&m);
Label if_found(&m), if_not_found(&m), if_bailout(&m), if_absent(&m);
- Node* map = m.LoadMap(object);
- Node* instance_type = m.LoadMapInstanceType(map);
+ TNode<Map> map = m.LoadMap(object);
+ TNode<Uint16T> instance_type = m.LoadMapInstanceType(map);
m.TryLookupElement(object, map, instance_type, index, &if_found, &if_absent,
&if_not_found, &if_bailout);
m.BIND(&if_found);
- m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
- &passed, &failed);
+ m.Branch(
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
+ &passed, &failed);
m.BIND(&if_absent);
- m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kAbsent))),
- &passed, &failed);
+ m.Branch(
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kAbsent))),
+ &passed, &failed);
m.BIND(&if_not_found);
m.Branch(
- m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
&passed, &failed);
m.BIND(&if_bailout);
m.Branch(
- m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
+ m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
&passed, &failed);
m.BIND(&passed);
@@ -1600,19 +1609,19 @@ TEST(TryLookupElement) {
CHECK_NOT_FOUND(object, 42);
}
-// TODO(ishell): uncomment once NO_ELEMENTS kind is supported.
-// {
-// Handle<Map> map = Map::Create(isolate, 0);
-// map->set_elements_kind(NO_ELEMENTS);
-// Handle<JSObject> object = factory->NewJSObjectFromMap(map);
-// CHECK_EQ(NO_ELEMENTS, object->map()->elements_kind());
-//
-// CHECK_NOT_FOUND(object, 0);
-// CHECK_NOT_FOUND(object, 1);
-// CHECK_NOT_FOUND(object, 7);
-// CHECK_NOT_FOUND(object, 13);
-// CHECK_NOT_FOUND(object, 42);
-// }
+ // TODO(ishell): uncomment once NO_ELEMENTS kind is supported.
+ // {
+ // Handle<Map> map = Map::Create(isolate, 0);
+ // map->set_elements_kind(NO_ELEMENTS);
+ // Handle<JSObject> object = factory->NewJSObjectFromMap(map);
+ // CHECK_EQ(NO_ELEMENTS, object->map()->elements_kind());
+ //
+ // CHECK_NOT_FOUND(object, 0);
+ // CHECK_NOT_FOUND(object, 1);
+ // CHECK_NOT_FOUND(object, 7);
+ // CHECK_NOT_FOUND(object, 13);
+ // CHECK_NOT_FOUND(object, 42);
+ // }
#undef CHECK_FOUND
#undef CHECK_NOT_FOUND
@@ -1652,7 +1661,8 @@ TEST(AllocateJSObjectFromMap) {
Node* properties = m.Parameter(1);
Node* elements = m.Parameter(2);
- Node* result = m.AllocateJSObjectFromMap(map, properties, elements);
+ TNode<JSObject> result =
+ m.AllocateJSObjectFromMap(map, properties, elements);
CodeStubAssembler::Label done(&m);
m.GotoIfNot(m.IsJSArrayMap(map), &done);
@@ -1722,7 +1732,8 @@ TEST(AllocateNameDictionary) {
{
Node* capacity = m.Parameter(0);
- Node* result = m.AllocateNameDictionary(m.SmiUntag(capacity));
+ TNode<NameDictionary> result =
+ m.AllocateNameDictionary(m.SmiUntag(capacity));
m.Return(result);
}
@@ -1931,11 +1942,11 @@ TEST(Arguments) {
CodeStubArguments arguments(&m, m.IntPtrConstant(3));
CSA_ASSERT(
- &m, m.WordEqual(arguments.AtIndex(0), m.SmiConstant(Smi::FromInt(12))));
+ &m, m.TaggedEqual(arguments.AtIndex(0), m.SmiConstant(Smi::FromInt(12))));
CSA_ASSERT(
- &m, m.WordEqual(arguments.AtIndex(1), m.SmiConstant(Smi::FromInt(13))));
+ &m, m.TaggedEqual(arguments.AtIndex(1), m.SmiConstant(Smi::FromInt(13))));
CSA_ASSERT(
- &m, m.WordEqual(arguments.AtIndex(2), m.SmiConstant(Smi::FromInt(14))));
+ &m, m.TaggedEqual(arguments.AtIndex(2), m.SmiConstant(Smi::FromInt(14))));
arguments.PopAndReturn(arguments.GetReceiver());
@@ -1959,17 +1970,17 @@ TEST(ArgumentsWithSmiConstantIndices) {
CodeStubAssembler::SMI_PARAMETERS);
CSA_ASSERT(&m,
- m.WordEqual(arguments.AtIndex(m.SmiConstant(0),
- CodeStubAssembler::SMI_PARAMETERS),
- m.SmiConstant(Smi::FromInt(12))));
+ m.TaggedEqual(arguments.AtIndex(m.SmiConstant(0),
+ CodeStubAssembler::SMI_PARAMETERS),
+ m.SmiConstant(Smi::FromInt(12))));
CSA_ASSERT(&m,
- m.WordEqual(arguments.AtIndex(m.SmiConstant(1),
- CodeStubAssembler::SMI_PARAMETERS),
- m.SmiConstant(Smi::FromInt(13))));
+ m.TaggedEqual(arguments.AtIndex(m.SmiConstant(1),
+ CodeStubAssembler::SMI_PARAMETERS),
+ m.SmiConstant(Smi::FromInt(13))));
CSA_ASSERT(&m,
- m.WordEqual(arguments.AtIndex(m.SmiConstant(2),
- CodeStubAssembler::SMI_PARAMETERS),
- m.SmiConstant(Smi::FromInt(14))));
+ m.TaggedEqual(arguments.AtIndex(m.SmiConstant(2),
+ CodeStubAssembler::SMI_PARAMETERS),
+ m.SmiConstant(Smi::FromInt(14))));
arguments.PopAndReturn(arguments.GetReceiver());
@@ -2012,17 +2023,17 @@ TEST(ArgumentsWithSmiIndices) {
CodeStubAssembler::SMI_PARAMETERS);
CSA_ASSERT(&m,
- m.WordEqual(arguments.AtIndex(NonConstantSmi(&m, 0),
- CodeStubAssembler::SMI_PARAMETERS),
- m.SmiConstant(Smi::FromInt(12))));
+ m.TaggedEqual(arguments.AtIndex(NonConstantSmi(&m, 0),
+ CodeStubAssembler::SMI_PARAMETERS),
+ m.SmiConstant(Smi::FromInt(12))));
CSA_ASSERT(&m,
- m.WordEqual(arguments.AtIndex(NonConstantSmi(&m, 1),
- CodeStubAssembler::SMI_PARAMETERS),
- m.SmiConstant(Smi::FromInt(13))));
+ m.TaggedEqual(arguments.AtIndex(NonConstantSmi(&m, 1),
+ CodeStubAssembler::SMI_PARAMETERS),
+ m.SmiConstant(Smi::FromInt(13))));
CSA_ASSERT(&m,
- m.WordEqual(arguments.AtIndex(NonConstantSmi(&m, 2),
- CodeStubAssembler::SMI_PARAMETERS),
- m.SmiConstant(Smi::FromInt(14))));
+ m.TaggedEqual(arguments.AtIndex(NonConstantSmi(&m, 2),
+ CodeStubAssembler::SMI_PARAMETERS),
+ m.SmiConstant(Smi::FromInt(14))));
arguments.PopAndReturn(arguments.GetReceiver());
@@ -2368,7 +2379,7 @@ TEST(CreatePromiseResolvingFunctionsContext) {
PromiseBuiltinsAssembler m(asm_tester.state());
Node* const context = m.Parameter(kNumParams + 2);
- Node* const native_context = m.LoadNativeContext(context);
+ TNode<NativeContext> const native_context = m.LoadNativeContext(context);
Node* const promise =
m.AllocateAndInitJSPromise(context, m.UndefinedConstant());
Node* const promise_context = m.CreatePromiseResolvingFunctionsContext(
@@ -2396,13 +2407,13 @@ TEST(CreatePromiseResolvingFunctions) {
PromiseBuiltinsAssembler m(asm_tester.state());
Node* const context = m.Parameter(kNumParams + 2);
- Node* const native_context = m.LoadNativeContext(context);
+ TNode<NativeContext> const native_context = m.LoadNativeContext(context);
Node* const promise =
m.AllocateAndInitJSPromise(context, m.UndefinedConstant());
Node *resolve, *reject;
std::tie(resolve, reject) = m.CreatePromiseResolvingFunctions(
promise, m.BooleanConstant(false), native_context);
- Node* const kSize = m.IntPtrConstant(2);
+ TNode<IntPtrT> const kSize = m.IntPtrConstant(2);
TNode<FixedArray> const arr =
m.Cast(m.AllocateFixedArray(PACKED_ELEMENTS, kSize));
m.StoreFixedArrayElement(arr, 0, resolve);
@@ -2486,15 +2497,15 @@ TEST(AllocateFunctionWithMapAndContext) {
PromiseBuiltinsAssembler m(asm_tester.state());
Node* const context = m.Parameter(kNumParams + 2);
- Node* const native_context = m.LoadNativeContext(context);
+ TNode<NativeContext> const native_context = m.LoadNativeContext(context);
Node* const promise =
m.AllocateAndInitJSPromise(context, m.UndefinedConstant());
Node* promise_context = m.CreatePromiseResolvingFunctionsContext(
promise, m.BooleanConstant(false), native_context);
- Node* resolve_info = m.LoadContextElement(
+ TNode<Object> resolve_info = m.LoadContextElement(
native_context,
Context::PROMISE_CAPABILITY_DEFAULT_RESOLVE_SHARED_FUN_INDEX);
- Node* const map = m.LoadContextElement(
+ TNode<Object> const map = m.LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
Node* const resolve =
m.AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
@@ -2524,9 +2535,9 @@ TEST(CreatePromiseGetCapabilitiesExecutorContext) {
PromiseBuiltinsAssembler m(asm_tester.state());
Node* const context = m.Parameter(kNumParams + 2);
- Node* const native_context = m.LoadNativeContext(context);
+ TNode<NativeContext> const native_context = m.LoadNativeContext(context);
- Node* const map = m.LoadRoot(RootIndex::kPromiseCapabilityMap);
+ TNode<Map> const map = m.PromiseCapabilityMapConstant();
Node* const capability = m.AllocateStruct(map);
m.StoreObjectFieldNoWriteBarrier(
capability, PromiseCapability::kPromiseOffset, m.UndefinedConstant());
@@ -2560,12 +2571,12 @@ TEST(NewPromiseCapability) {
PromiseBuiltinsAssembler m(asm_tester.state());
Node* const context = m.Parameter(kNumParams + 2);
- Node* const native_context = m.LoadNativeContext(context);
- Node* const promise_constructor =
+ TNode<NativeContext> const native_context = m.LoadNativeContext(context);
+ TNode<Object> const promise_constructor =
m.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
- Node* const debug_event = m.TrueConstant();
- Node* const capability =
+ TNode<Oddball> const debug_event = m.TrueConstant();
+ TNode<Object> const capability =
m.CallBuiltin(Builtins::kNewPromiseCapability, context,
promise_constructor, debug_event);
m.Return(capability);
@@ -2608,9 +2619,9 @@ TEST(NewPromiseCapability) {
Node* const context = m.Parameter(kNumParams + 2);
Node* const constructor = m.Parameter(1);
- Node* const debug_event = m.TrueConstant();
- Node* const capability = m.CallBuiltin(Builtins::kNewPromiseCapability,
- context, constructor, debug_event);
+ TNode<Oddball> const debug_event = m.TrueConstant();
+ TNode<Object> const capability = m.CallBuiltin(
+ Builtins::kNewPromiseCapability, context, constructor, debug_event);
m.Return(capability);
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
@@ -2674,12 +2685,13 @@ TEST(DirectMemoryTest8BitWord32Immediate) {
const int element_count = 8;
Label bad(&m);
- Node* buffer_node = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
+ TNode<IntPtrT> buffer_node =
+ m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
for (size_t i = 0; i < element_count; ++i) {
for (size_t j = 0; j < element_count; ++j) {
Node* loaded = m.LoadBufferObject(buffer_node, static_cast<int>(i),
MachineType::Uint8());
- Node* masked = m.Word32And(loaded, m.Int32Constant(buffer[j]));
+ TNode<Word32T> masked = m.Word32And(loaded, m.Int32Constant(buffer[j]));
if ((buffer[j] & buffer[i]) != 0) {
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
} else {
@@ -2706,13 +2718,14 @@ TEST(DirectMemoryTest16BitWord32Immediate) {
const int element_count = 8;
Label bad(&m);
- Node* buffer_node = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
+ TNode<IntPtrT> buffer_node =
+ m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
for (size_t i = 0; i < element_count; ++i) {
for (size_t j = 0; j < element_count; ++j) {
Node* loaded =
m.LoadBufferObject(buffer_node, static_cast<int>(i * sizeof(int16_t)),
MachineType::Uint16());
- Node* masked = m.Word32And(loaded, m.Int32Constant(buffer[j]));
+ TNode<Word32T> masked = m.Word32And(loaded, m.Int32Constant(buffer[j]));
if ((buffer[j] & buffer[i]) != 0) {
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
} else {
@@ -2740,7 +2753,8 @@ TEST(DirectMemoryTest8BitWord32) {
Label bad(&m);
Node* constants[element_count];
- Node* buffer_node = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
+ TNode<IntPtrT> buffer_node =
+ m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
for (size_t i = 0; i < element_count; ++i) {
constants[i] = m.LoadBufferObject(buffer_node, static_cast<int>(i),
MachineType::Uint8());
@@ -2750,7 +2764,7 @@ TEST(DirectMemoryTest8BitWord32) {
for (size_t j = 0; j < element_count; ++j) {
Node* loaded = m.LoadBufferObject(buffer_node, static_cast<int>(i),
MachineType::Uint8());
- Node* masked = m.Word32And(loaded, constants[j]);
+ TNode<Word32T> masked = m.Word32And(loaded, constants[j]);
if ((buffer[j] & buffer[i]) != 0) {
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
} else {
@@ -2785,20 +2799,22 @@ TEST(DirectMemoryTest16BitWord32) {
Label bad(&m);
Node* constants[element_count];
- Node* buffer_node1 = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
+ TNode<IntPtrT> buffer_node1 =
+ m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
for (size_t i = 0; i < element_count; ++i) {
constants[i] =
m.LoadBufferObject(buffer_node1, static_cast<int>(i * sizeof(int16_t)),
MachineType::Uint16());
}
- Node* buffer_node2 = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
+ TNode<IntPtrT> buffer_node2 =
+ m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
for (size_t i = 0; i < element_count; ++i) {
for (size_t j = 0; j < element_count; ++j) {
Node* loaded = m.LoadBufferObject(buffer_node1,
static_cast<int>(i * sizeof(int16_t)),
MachineType::Uint16());
- Node* masked = m.Word32And(loaded, constants[j]);
+ TNode<Word32T> masked = m.Word32And(loaded, constants[j]);
if ((buffer[j] & buffer[i]) != 0) {
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
} else {
@@ -2841,8 +2857,8 @@ TEST(LoadJSArrayElementsMap) {
{
CodeStubAssembler m(asm_tester.state());
Node* context = m.Parameter(kNumParams + 2);
- Node* native_context = m.LoadNativeContext(context);
- Node* kind = m.SmiToInt32(m.Parameter(0));
+ TNode<NativeContext> native_context = m.LoadNativeContext(context);
+ TNode<Int32T> kind = m.SmiToInt32(m.Parameter(0));
m.Return(m.LoadJSArrayElementsMap(kind, native_context));
}
@@ -3288,8 +3304,8 @@ TEST(ExtractFixedArraySimpleIntPtrParameters) {
CodeAssemblerTester asm_tester(isolate, kNumParams);
{
CodeStubAssembler m(asm_tester.state());
- Node* p1_untagged = m.SmiUntag(m.Parameter(1));
- Node* p2_untagged = m.SmiUntag(m.Parameter(2));
+ TNode<IntPtrT> p1_untagged = m.SmiUntag(m.Parameter(1));
+ TNode<IntPtrT> p2_untagged = m.SmiUntag(m.Parameter(2));
m.Return(m.ExtractFixedArray(m.Parameter(0), p1_untagged, p2_untagged));
}
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
@@ -3334,8 +3350,9 @@ TEST(SingleInputPhiElimination) {
Label end_label(&m, {&temp1, &temp2});
temp1.Bind(m.Parameter(1));
temp2.Bind(m.Parameter(1));
- m.Branch(m.WordEqual(m.Parameter(0), m.Parameter(1)), &end_label,
- &temp_label);
+ m.Branch(m.TaggedEqual(m.UncheckedCast<Object>(m.Parameter(0)),
+ m.UncheckedCast<Object>(m.Parameter(1))),
+ &end_label, &temp_label);
temp1.Bind(m.Parameter(2));
temp2.Bind(m.Parameter(2));
m.BIND(&temp_label);
@@ -3486,7 +3503,7 @@ TEST(TestCallBuiltinInlineTrampoline) {
Node* str = m.Parameter(0);
Node* context = m.Parameter(kNumParams + kContextOffset);
- Node* index = m.SmiConstant(2);
+ TNode<Smi> index = m.SmiConstant(2);
m.Return(m.CallStub(Builtins::CallableFor(isolate, Builtins::kStringRepeat),
context, str, index));
@@ -3511,7 +3528,7 @@ TEST(TestCallBuiltinIndirectLoad) {
Node* str = m.Parameter(0);
Node* context = m.Parameter(kNumParams + kContextOffset);
- Node* index = m.SmiConstant(2);
+ TNode<Smi> index = m.SmiConstant(2);
m.Return(m.CallStub(Builtins::CallableFor(isolate, Builtins::kStringRepeat),
context, str, index));
diff --git a/deps/v8/test/cctest/test-conversions.cc b/deps/v8/test/cctest/test-conversions.cc
index 1ddd463795..2bf07888af 100644
--- a/deps/v8/test/cctest/test-conversions.cc
+++ b/deps/v8/test/cctest/test-conversions.cc
@@ -312,11 +312,10 @@ TEST(ExponentNumberStr) {
CHECK_EQ(1e-106, StringToDouble(".000001e-100", NO_FLAGS));
}
-
-class OneBit1: public BitField<uint32_t, 0, 1> {};
-class OneBit2: public BitField<uint32_t, 7, 1> {};
-class EightBit1: public BitField<uint32_t, 0, 8> {};
-class EightBit2: public BitField<uint32_t, 13, 8> {};
+using OneBit1 = BitField<uint32_t, 0, 1>;
+using OneBit2 = BitField<uint32_t, 7, 1>;
+using EightBit1 = BitField<uint32_t, 0, 8>;
+using EightBit2 = BitField<uint32_t, 13, 8>;
TEST(BitField) {
uint32_t x;
@@ -351,9 +350,8 @@ TEST(BitField) {
CHECK(!EightBit2::is_valid(256));
}
-
-class UpperBits: public BitField64<int, 61, 3> {};
-class MiddleBits: public BitField64<int, 31, 2> {};
+using UpperBits = BitField64<int, 61, 3>;
+using MiddleBits = BitField64<int, 31, 2>;
TEST(BitField64) {
uint64_t x;
diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc
index 4b9ee4629f..6d0ee0e512 100644
--- a/deps/v8/test/cctest/test-cpu-profiler.cc
+++ b/deps/v8/test/cctest/test-cpu-profiler.cc
@@ -37,6 +37,7 @@
#include "src/base/platform/platform.h"
#include "src/codegen/source-position-table.h"
#include "src/deoptimizer/deoptimizer.h"
+#include "src/heap/spaces.h"
#include "src/libplatform/default-platform.h"
#include "src/logging/log.h"
#include "src/objects/objects-inl.h"
@@ -45,11 +46,18 @@
#include "src/profiler/tracing-cpu-profiler.h"
#include "src/utils/utils.h"
#include "test/cctest/cctest.h"
+#include "test/cctest/heap/heap-utils.h"
#include "test/cctest/profiler-extension.h"
#include "include/libplatform/v8-tracing.h"
+#include "src/libplatform/tracing/trace-event-listener.h"
#include "src/tracing/trace-event.h"
+#ifdef V8_USE_PERFETTO
+#include "perfetto/trace/chrome/chrome_trace_event.pb.h"
+#include "perfetto/trace/trace.pb.h"
+#endif
+
namespace v8 {
namespace internal {
namespace test_cpu_profiler {
@@ -79,12 +87,13 @@ static const char* reason(const i::DeoptimizeReason reason) {
TEST(StartStop) {
i::Isolate* isolate = CcTest::i_isolate();
CpuProfilesCollection profiles(isolate);
- ProfileGenerator generator(&profiles);
+ ProfilerCodeObserver code_observer(isolate);
+ ProfileGenerator generator(&profiles, code_observer.code_map());
std::unique_ptr<ProfilerEventsProcessor> processor(
- new SamplingEventsProcessor(isolate, &generator,
+ new SamplingEventsProcessor(isolate, &generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100),
true));
- processor->Start();
+ CHECK(processor->Start());
processor->StopSynchronously();
}
@@ -163,10 +172,13 @@ TEST(CodeEvents) {
i::AbstractCode moved_code = CreateCode(&env);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
- ProfileGenerator* generator = new ProfileGenerator(profiles);
+ ProfilerCodeObserver code_observer(isolate);
+ ProfileGenerator* generator =
+ new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
- isolate, generator, v8::base::TimeDelta::FromMicroseconds(100), true);
- processor->Start();
+ isolate, generator, &code_observer,
+ v8::base::TimeDelta::FromMicroseconds(100), true);
+ CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor);
isolate->logger()->AddCodeEventListener(&profiler_listener);
@@ -222,13 +234,16 @@ TEST(TickEvents) {
i::AbstractCode frame3_code = CreateCode(&env);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
- ProfileGenerator* generator = new ProfileGenerator(profiles);
+ ProfilerCodeObserver code_observer(isolate);
+ ProfileGenerator* generator =
+ new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
- CcTest::i_isolate(), generator,
+ CcTest::i_isolate(), generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100), true);
- CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
+ CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
+ processor);
profiles->StartProfiling("");
- processor->Start();
+ CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor);
isolate->logger()->AddCodeEventListener(&profiler_listener);
@@ -291,13 +306,16 @@ TEST(Issue1398) {
i::AbstractCode code = CreateCode(&env);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
- ProfileGenerator* generator = new ProfileGenerator(profiles);
+ ProfilerCodeObserver code_observer(isolate);
+ ProfileGenerator* generator =
+ new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
- CcTest::i_isolate(), generator,
+ CcTest::i_isolate(), generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100), true);
- CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
+ CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
+ processor);
profiles->StartProfiling("");
- processor->Start();
+ CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor);
profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
@@ -305,7 +323,7 @@ TEST(Issue1398) {
v8::internal::TickSample sample;
sample.pc = reinterpret_cast<void*>(code.InstructionStart());
sample.tos = nullptr;
- sample.frames_count = v8::TickSample::kMaxFramesCount;
+ sample.frames_count = TickSample::kMaxFramesCount;
for (unsigned i = 0; i < sample.frames_count; ++i) {
sample.stack[i] = reinterpret_cast<void*>(code.InstructionStart());
}
@@ -323,7 +341,7 @@ TEST(Issue1398) {
++actual_depth;
}
- CHECK_EQ(1 + v8::TickSample::kMaxFramesCount, actual_depth); // +1 for PC.
+ CHECK_EQ(1 + TickSample::kMaxFramesCount, actual_depth); // +1 for PC.
}
TEST(DeleteAllCpuProfiles) {
@@ -440,7 +458,8 @@ class ProfilerHelper {
v8::Local<v8::Function> function, v8::Local<v8::Value> argv[], int argc,
unsigned min_js_samples = 0, unsigned min_external_samples = 0,
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers,
- unsigned max_samples = CpuProfilingOptions::kNoSampleLimit);
+ unsigned max_samples = v8::CpuProfilingOptions::kNoSampleLimit,
+ v8::Local<v8::Context> context = v8::Local<v8::Context>());
v8::CpuProfiler* profiler() { return profiler_; }
@@ -453,11 +472,12 @@ v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function,
v8::Local<v8::Value> argv[], int argc,
unsigned min_js_samples,
unsigned min_external_samples,
- ProfilingMode mode, unsigned max_samples) {
+ ProfilingMode mode, unsigned max_samples,
+ v8::Local<v8::Context> context) {
v8::Local<v8::String> profile_name = v8_str("my_profile");
profiler_->SetSamplingInterval(100);
- profiler_->StartProfiling(profile_name, {mode, max_samples});
+ profiler_->StartProfiling(profile_name, {mode, max_samples, 0, context});
v8::internal::CpuProfiler* iprofiler =
reinterpret_cast<v8::internal::CpuProfiler*>(profiler_);
@@ -465,6 +485,7 @@ v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function,
reinterpret_cast<i::SamplingEventsProcessor*>(iprofiler->processor())
->sampler();
sampler->StartCountingSamples();
+
do {
function->Call(context_, context_->Global(), argc, argv).ToLocalChecked();
} while (sampler->js_sample_count() < min_js_samples ||
@@ -1154,18 +1175,21 @@ static void TickLines(bool optimize) {
CHECK_NE(code_address, kNullAddress);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
- ProfileGenerator* generator = new ProfileGenerator(profiles);
+ ProfilerCodeObserver code_observer(isolate);
+ ProfileGenerator* generator =
+ new ProfileGenerator(profiles, code_observer.code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
- CcTest::i_isolate(), generator,
+ CcTest::i_isolate(), generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100), true);
- CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
+ CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
+ processor);
profiles->StartProfiling("");
// TODO(delphick): Stop using the CpuProfiler internals here: This forces
// LogCompiledFunctions so that source positions are collected everywhere.
// This would normally happen automatically with CpuProfiler::StartProfiling
// but doesn't because it's constructed with a generator and a processor.
isolate->logger()->LogCompiledFunctions();
- processor->Start();
+ CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor);
// Enqueue code creation events.
@@ -1806,7 +1830,7 @@ TEST(Inlining2) {
v8::Local<v8::String> profile_name = v8_str("inlining");
profiler->StartProfiling(
profile_name,
- CpuProfilingOptions{v8::CpuProfilingMode::kCallerLineNumbers});
+ v8::CpuProfilingOptions{v8::CpuProfilingMode::kCallerLineNumbers});
v8::Local<v8::Value> args[] = {
v8::Integer::New(env->GetIsolate(), 50000 * load_factor)};
@@ -2488,7 +2512,6 @@ TEST(DeoptAtFirstLevelInlinedSource) {
iprofiler->DeleteProfile(iprofile);
}
-
// deopt at the second level inlined function
TEST(DeoptAtSecondLevelInlinedSource) {
if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
@@ -2623,6 +2646,41 @@ using v8::platform::tracing::TraceObject;
namespace {
+#ifdef V8_USE_PERFETTO
+
+class CpuProfilerListener : public platform::tracing::TraceEventListener {
+ public:
+ void ProcessPacket(const ::perfetto::protos::TracePacket& packet) {
+ for (const ::perfetto::protos::ChromeTraceEvent& trace_event :
+ packet.chrome_events().trace_events()) {
+ if (trace_event.name() != std::string("Profile") &&
+ trace_event.name() != std::string("ProfileChunk"))
+ return;
+ CHECK(!profile_id_ || trace_event.id() == profile_id_);
+ CHECK_EQ(1, trace_event.args_size());
+ CHECK(trace_event.args()[0].has_json_value());
+ profile_id_ = trace_event.id();
+ result_json_ += result_json_.empty() ? "[" : ",\n";
+ result_json_ += trace_event.args()[0].json_value();
+ }
+ }
+
+ const std::string& result_json() {
+ result_json_ += "]";
+ return result_json_;
+ }
+ void Reset() {
+ result_json_.clear();
+ profile_id_ = 0;
+ }
+
+ private:
+ std::string result_json_;
+ uint64_t profile_id_ = 0;
+};
+
+#else
+
class CpuProfileEventChecker : public v8::platform::tracing::TraceWriter {
public:
void AppendTraceEvent(TraceObject* trace_event) override {
@@ -2651,6 +2709,8 @@ class CpuProfileEventChecker : public v8::platform::tracing::TraceWriter {
uint64_t profile_id_ = 0;
};
+#endif // !V8_USE_PERFETTO
+
} // namespace
TEST(TracingCpuProfiler) {
@@ -2658,17 +2718,20 @@ TEST(TracingCpuProfiler) {
v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
v8::Context::Scope context_scope(env);
- CpuProfileEventChecker* event_checker = new CpuProfileEventChecker();
- TraceBuffer* ring_buffer =
- TraceBuffer::CreateTraceBufferRingBuffer(1, event_checker);
auto* tracing_controller =
static_cast<v8::platform::tracing::TracingController*>(
i::V8::GetCurrentPlatform()->GetTracingController());
- tracing_controller->Initialize(ring_buffer);
#ifdef V8_USE_PERFETTO
std::ostringstream perfetto_output;
tracing_controller->InitializeForPerfetto(&perfetto_output);
+ CpuProfilerListener listener;
+ tracing_controller->SetTraceEventListenerForTesting(&listener);
+#else
+ CpuProfileEventChecker* event_checker = new CpuProfileEventChecker();
+ TraceBuffer* ring_buffer =
+ TraceBuffer::CreateTraceBufferRingBuffer(1, event_checker);
+ tracing_controller->Initialize(ring_buffer);
#endif
bool result = false;
@@ -2693,8 +2756,13 @@ TEST(TracingCpuProfiler) {
CompileRun(test_code.c_str());
tracing_controller->StopTracing();
+#ifdef V8_USE_PERFETTO
+ std::string profile_json = listener.result_json();
+ listener.Reset();
+#else
std::string profile_json = event_checker->result_json();
event_checker->Reset();
+#endif
CHECK_LT(0u, profile_json.length());
printf("Profile JSON: %s\n", profile_json.c_str());
@@ -2930,6 +2998,15 @@ TEST(SourcePositionTable) {
CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(21));
CHECK_EQ(0, info.GetInliningId(100));
+
+ // Test that subsequent SetPosition calls with the same pc_offset are ignored.
+ info.SetPosition(25, 4, SourcePosition::kNotInlined);
+ CHECK_EQ(2, info.GetSourceLineNumber(21));
+ CHECK_EQ(3, info.GetSourceLineNumber(100));
+ CHECK_EQ(3, info.GetSourceLineNumber(std::numeric_limits<int>::max()));
+
+ CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(21));
+ CHECK_EQ(0, info.GetInliningId(100));
}
TEST(MultipleProfilers) {
@@ -3034,8 +3111,8 @@ TEST(MultipleIsolates) {
IsolateThread thread1;
IsolateThread thread2;
- thread1.Start();
- thread2.Start();
+ CHECK(thread1.Start());
+ CHECK(thread2.Start());
thread1.Join();
thread2.Join();
@@ -3062,12 +3139,13 @@ TEST(FastStopProfiling) {
TEST(LowPrecisionSamplingStartStopInternal) {
i::Isolate* isolate = CcTest::i_isolate();
CpuProfilesCollection profiles(isolate);
- ProfileGenerator generator(&profiles);
+ ProfilerCodeObserver code_observer(isolate);
+ ProfileGenerator generator(&profiles, code_observer.code_map());
std::unique_ptr<ProfilerEventsProcessor> processor(
- new SamplingEventsProcessor(isolate, &generator,
+ new SamplingEventsProcessor(isolate, &generator, &code_observer,
v8::base::TimeDelta::FromMicroseconds(100),
false));
- processor->Start();
+ CHECK(processor->Start());
processor->StopSynchronously();
}
@@ -3187,11 +3265,15 @@ TEST(ProflilerSubsampling) {
i::HandleScope scope(isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
- ProfileGenerator* generator = new ProfileGenerator(profiles);
- ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
- isolate, generator, v8::base::TimeDelta::FromMicroseconds(1),
- /* use_precise_sampling */ true);
- CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
+ ProfilerCodeObserver code_observer(isolate);
+ ProfileGenerator* generator =
+ new ProfileGenerator(profiles, code_observer.code_map());
+ ProfilerEventsProcessor* processor =
+ new SamplingEventsProcessor(isolate, generator, &code_observer,
+ v8::base::TimeDelta::FromMicroseconds(1),
+ /* use_precise_sampling */ true);
+ CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
+ processor);
// Create a new CpuProfile that wants samples at 8us.
CpuProfile profile(&profiler, "",
@@ -3228,11 +3310,15 @@ TEST(DynamicResampling) {
i::HandleScope scope(isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
- ProfileGenerator* generator = new ProfileGenerator(profiles);
- ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
- isolate, generator, v8::base::TimeDelta::FromMicroseconds(1),
- /* use_precise_sampling */ true);
- CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
+ ProfilerCodeObserver code_observer(isolate);
+ ProfileGenerator* generator =
+ new ProfileGenerator(profiles, code_observer.code_map());
+ ProfilerEventsProcessor* processor =
+ new SamplingEventsProcessor(isolate, generator, &code_observer,
+ v8::base::TimeDelta::FromMicroseconds(1),
+ /* use_precise_sampling */ true);
+ CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
+ processor);
// Set a 1us base sampling rate, dividing all possible intervals.
profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(1));
@@ -3286,11 +3372,15 @@ TEST(DynamicResamplingWithBaseInterval) {
i::HandleScope scope(isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
- ProfileGenerator* generator = new ProfileGenerator(profiles);
- ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
- isolate, generator, v8::base::TimeDelta::FromMicroseconds(1),
- /* use_precise_sampling */ true);
- CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
+ ProfilerCodeObserver code_observer(isolate);
+ ProfileGenerator* generator =
+ new ProfileGenerator(profiles, code_observer.code_map());
+ ProfilerEventsProcessor* processor =
+ new SamplingEventsProcessor(isolate, generator, &code_observer,
+ v8::base::TimeDelta::FromMicroseconds(1),
+ /* use_precise_sampling */ true);
+ CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, generator,
+ processor);
profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(7));
@@ -3338,6 +3428,184 @@ TEST(DynamicResamplingWithBaseInterval) {
profiles->StopProfiling("5us");
}
+// Tests that functions compiled after a started profiler is stopped are still
+// visible when the profiler is started again. (https://crbug.com/v8/9151)
+TEST(Bug9151StaleCodeEntries) {
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+
+ v8::Local<v8::FunctionTemplate> func_template =
+ v8::FunctionTemplate::New(env->GetIsolate(), CallCollectSample);
+ v8::Local<v8::Function> func =
+ func_template->GetFunction(env.local()).ToLocalChecked();
+ func->SetName(v8_str("CallCollectSample"));
+ env->Global()->Set(env.local(), v8_str("CallCollectSample"), func).FromJust();
+
+ v8::CpuProfiler* profiler =
+ v8::CpuProfiler::New(env->GetIsolate(), kDebugNaming, kEagerLogging);
+ v8::Local<v8::String> profile_name = v8_str("");
+
+ // Warm up the profiler to create the initial code map.
+ profiler->StartProfiling(profile_name);
+ profiler->StopProfiling(profile_name);
+
+ // Log a function compilation (executed once to force a compilation).
+ CompileRun(R"(
+ function start() {
+ CallCollectSample();
+ }
+ start();
+ )");
+
+ // Restart the profiler, and execute both the JS function and callback.
+ profiler->StartProfiling(profile_name, true);
+ CompileRun("start();");
+ v8::CpuProfile* profile = profiler->StopProfiling(profile_name);
+
+ auto* root = profile->GetTopDownRoot();
+ auto* toplevel = GetChild(env.local(), root, "");
+
+ auto* start = FindChild(env.local(), toplevel, "start");
+ CHECK(start);
+
+ auto* callback = FindChild(env.local(), start, "CallCollectSample");
+ CHECK(callback);
+}
+
+// Tests that functions from other contexts aren't recorded when filtering for
+// another context.
+TEST(ContextIsolation) {
+ i::FLAG_allow_natives_syntax = true;
+ LocalContext execution_env;
+ i::HandleScope scope(CcTest::i_isolate());
+
+ // Install CollectSample callback for more deterministic sampling.
+ v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
+ execution_env.local()->GetIsolate(), CallCollectSample);
+ v8::Local<v8::Function> func =
+ func_template->GetFunction(execution_env.local()).ToLocalChecked();
+ func->SetName(v8_str("CallCollectSample"));
+ execution_env->Global()
+ ->Set(execution_env.local(), v8_str("CallCollectSample"), func)
+ .FromJust();
+
+ ProfilerHelper helper(execution_env.local());
+ CompileRun(R"(
+ function optimized() {
+ CallCollectSample();
+ }
+
+ function unoptimized() {
+ CallCollectSample();
+ }
+
+ function start() {
+ // Test optimized functions
+ %PrepareFunctionForOptimization(optimized);
+ optimized();
+ optimized();
+ %OptimizeFunctionOnNextCall(optimized);
+ optimized();
+
+ // Test unoptimized functions
+ %NeverOptimizeFunction(unoptimized);
+ unoptimized();
+
+ // Test callback
+ CallCollectSample();
+ }
+ )");
+ v8::Local<v8::Function> function =
+ GetFunction(execution_env.local(), "start");
+
+ v8::CpuProfile* same_context_profile = helper.Run(
+ function, nullptr, 0, 0, 0, v8::CpuProfilingMode::kLeafNodeLineNumbers,
+ v8::CpuProfilingOptions::kNoSampleLimit, execution_env.local());
+ const v8::CpuProfileNode* root = same_context_profile->GetTopDownRoot();
+ const v8::CpuProfileNode* start_node = FindChild(root, "start");
+ CHECK(start_node);
+ const v8::CpuProfileNode* optimized_node = FindChild(start_node, "optimized");
+ CHECK(optimized_node);
+ const v8::CpuProfileNode* unoptimized_node =
+ FindChild(start_node, "unoptimized");
+ CHECK(unoptimized_node);
+ const v8::CpuProfileNode* callback_node =
+ FindChild(start_node, "CallCollectSample");
+ CHECK(callback_node);
+
+ {
+ LocalContext filter_env;
+ v8::CpuProfile* diff_context_profile = helper.Run(
+ function, nullptr, 0, 0, 0, v8::CpuProfilingMode::kLeafNodeLineNumbers,
+ v8::CpuProfilingOptions::kNoSampleLimit, filter_env.local());
+ const v8::CpuProfileNode* diff_root =
+ diff_context_profile->GetTopDownRoot();
+ // Ensure that no children were recorded (including callbacks, builtins).
+ CHECK(!FindChild(diff_root, "start"));
+ }
+}
+
+// Tests that when a native context that's being filtered is moved, we continue
+// to track its execution.
+TEST(ContextFilterMovedNativeContext) {
+ i::FLAG_allow_natives_syntax = true;
+ i::FLAG_manual_evacuation_candidates_selection = true;
+ LocalContext env;
+ i::HandleScope scope(CcTest::i_isolate());
+
+ {
+ // Install CollectSample callback for more deterministic sampling.
+ v8::Local<v8::FunctionTemplate> sample_func_template =
+ v8::FunctionTemplate::New(env.local()->GetIsolate(), CallCollectSample);
+ v8::Local<v8::Function> sample_func =
+ sample_func_template->GetFunction(env.local()).ToLocalChecked();
+ sample_func->SetName(v8_str("CallCollectSample"));
+ env->Global()
+ ->Set(env.local(), v8_str("CallCollectSample"), sample_func)
+ .FromJust();
+
+ // Install a function that triggers the native context to be moved.
+ v8::Local<v8::FunctionTemplate> move_func_template =
+ v8::FunctionTemplate::New(
+ env.local()->GetIsolate(),
+ [](const v8::FunctionCallbackInfo<v8::Value>& info) {
+ i::Isolate* isolate =
+ reinterpret_cast<i::Isolate*>(info.GetIsolate());
+ i::heap::ForceEvacuationCandidate(
+ i::Page::FromHeapObject(isolate->raw_native_context()));
+ CcTest::CollectAllGarbage();
+ });
+ v8::Local<v8::Function> move_func =
+ move_func_template->GetFunction(env.local()).ToLocalChecked();
+ move_func->SetName(v8_str("ForceNativeContextMove"));
+ env->Global()
+ ->Set(env.local(), v8_str("ForceNativeContextMove"), move_func)
+ .FromJust();
+
+ ProfilerHelper helper(env.local());
+ CompileRun(R"(
+ function start() {
+ ForceNativeContextMove();
+ CallCollectSample();
+ }
+ )");
+ v8::Local<v8::Function> function = GetFunction(env.local(), "start");
+
+ v8::CpuProfile* profile = helper.Run(
+ function, nullptr, 0, 0, 0, v8::CpuProfilingMode::kLeafNodeLineNumbers,
+ v8::CpuProfilingOptions::kNoSampleLimit, env.local());
+ const v8::CpuProfileNode* root = profile->GetTopDownRoot();
+ const v8::CpuProfileNode* start_node = FindChild(root, "start");
+ CHECK(start_node);
+
+ // Verify that after moving the native context, CallCollectSample is still
+ // recorded.
+ const v8::CpuProfileNode* callback_node =
+ FindChild(start_node, "CallCollectSample");
+ CHECK(callback_node);
+ }
+}
+
enum class EntryCountMode { kAll, kOnlyInlined };
// Count the number of unique source positions.
diff --git a/deps/v8/test/cctest/test-debug-helper.cc b/deps/v8/test/cctest/test-debug-helper.cc
new file mode 100644
index 0000000000..67236e5a31
--- /dev/null
+++ b/deps/v8/test/cctest/test-debug-helper.cc
@@ -0,0 +1,227 @@
+// Copyright 2018 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/api/api-inl.h"
+#include "src/heap/spaces.h"
+#include "test/cctest/cctest.h"
+#include "tools/debug_helper/debug-helper.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+namespace d = v8::debug_helper;
+
+uintptr_t memory_fail_start = 0;
+uintptr_t memory_fail_end = 0;
+
+class MemoryFailureRegion {
+ public:
+ MemoryFailureRegion(uintptr_t start, uintptr_t end) {
+ memory_fail_start = start;
+ memory_fail_end = end;
+ }
+ ~MemoryFailureRegion() {
+ memory_fail_start = 0;
+ memory_fail_end = 0;
+ }
+};
+
+// Implement the memory-reading callback. This one just fetches memory from the
+// current process, but a real implementation for a debugging extension would
+// fetch memory from the debuggee process or crash dump.
+d::MemoryAccessResult ReadMemory(uintptr_t address, uint8_t* destination,
+ size_t byte_count) {
+ if (address >= memory_fail_start && address <= memory_fail_end) {
+ // Simulate failure to read debuggee memory.
+ return d::MemoryAccessResult::kAddressValidButInaccessible;
+ }
+ memcpy(destination, reinterpret_cast<void*>(address), byte_count);
+ return d::MemoryAccessResult::kOk;
+}
+
+void CheckProp(const d::ObjectProperty& property, const char* expected_type,
+ const char* expected_name,
+ d::PropertyKind expected_kind = d::PropertyKind::kSingle,
+ size_t expected_num_values = 1) {
+ CHECK_EQ(property.num_values, expected_num_values);
+ CHECK(property.type == std::string("v8::internal::TaggedValue") ||
+ property.type == std::string(expected_type));
+ CHECK(property.decompressed_type == std::string(expected_type));
+ CHECK(property.kind == expected_kind);
+ CHECK(property.name == std::string(expected_name));
+}
+
+template <typename TValue>
+void CheckProp(const d::ObjectProperty& property, const char* expected_type,
+ const char* expected_name, TValue expected_value) {
+ CheckProp(property, expected_type, expected_name);
+ CHECK(*reinterpret_cast<TValue*>(property.address) == expected_value);
+}
+
+} // namespace
+
+TEST(GetObjectProperties) {
+ CcTest::InitializeVM();
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ LocalContext context;
+ d::Roots roots{0, 0, 0, 0}; // We don't know the heap roots.
+
+ v8::Local<v8::Value> v = CompileRun("42");
+ Handle<Object> o = v8::Utils::OpenHandle(*v);
+ d::ObjectPropertiesResultPtr props =
+ d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
+ CHECK(props->type_check_result == d::TypeCheckResult::kSmi);
+ CHECK(props->brief == std::string("42 (0x2a)"));
+ CHECK(props->type == std::string("v8::internal::Smi"));
+ CHECK_EQ(props->num_properties, 0);
+
+ v = CompileRun("[\"a\", \"bc\"]");
+ o = v8::Utils::OpenHandle(*v);
+ props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
+ CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap);
+ CHECK(props->type == std::string("v8::internal::JSArray"));
+ CHECK_EQ(props->num_properties, 4);
+ CheckProp(*props->properties[0], "v8::internal::Map", "map");
+ CheckProp(*props->properties[1], "v8::internal::Object",
+ "properties_or_hash");
+ CheckProp(*props->properties[2], "v8::internal::FixedArrayBase", "elements");
+ CheckProp(*props->properties[3], "v8::internal::Object", "length",
+ static_cast<i::Tagged_t>(IntToSmi(2)));
+
+ // We need to supply a root address for decompression before reading the
+ // elements from the JSArray.
+ roots.any_heap_pointer = o->ptr();
+
+ i::Tagged_t properties_or_hash =
+ *reinterpret_cast<i::Tagged_t*>(props->properties[1]->address);
+ i::Tagged_t elements =
+ *reinterpret_cast<i::Tagged_t*>(props->properties[2]->address);
+
+ // The properties_or_hash_code field should be an empty fixed array. Since
+ // that is at a known offset, we should be able to detect it even without
+ // any ability to read memory.
+ {
+ MemoryFailureRegion failure(0, UINTPTR_MAX);
+ props = d::GetObjectProperties(properties_or_hash, &ReadMemory, roots);
+ CHECK(props->type_check_result ==
+ d::TypeCheckResult::kObjectPointerValidButInaccessible);
+ CHECK(props->type == std::string("v8::internal::HeapObject"));
+ CHECK_EQ(props->num_properties, 1);
+ CheckProp(*props->properties[0], "v8::internal::Map", "map");
+ CHECK(std::string(props->brief).substr(0, 21) ==
+ std::string("maybe EmptyFixedArray"));
+
+ // Provide a heap root so the API can be more sure.
+ roots.read_only_space =
+ reinterpret_cast<uintptr_t>(reinterpret_cast<i::Isolate*>(isolate)
+ ->heap()
+ ->read_only_space()
+ ->first_page());
+ props = d::GetObjectProperties(properties_or_hash, &ReadMemory, roots);
+ CHECK(props->type_check_result ==
+ d::TypeCheckResult::kObjectPointerValidButInaccessible);
+ CHECK(props->type == std::string("v8::internal::HeapObject"));
+ CHECK_EQ(props->num_properties, 1);
+ CheckProp(*props->properties[0], "v8::internal::Map", "map");
+ CHECK(std::string(props->brief).substr(0, 15) ==
+ std::string("EmptyFixedArray"));
+ }
+
+ props = d::GetObjectProperties(elements, &ReadMemory, roots);
+ CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap);
+ CHECK(props->type == std::string("v8::internal::FixedArray"));
+ CHECK_EQ(props->num_properties, 3);
+ CheckProp(*props->properties[0], "v8::internal::Map", "map");
+ CheckProp(*props->properties[1], "v8::internal::Object", "length",
+ static_cast<i::Tagged_t>(IntToSmi(2)));
+ CheckProp(*props->properties[2], "v8::internal::Object", "objects",
+ d::PropertyKind::kArrayOfKnownSize, 2);
+
+ // Get the second string value from the FixedArray.
+ i::Tagged_t second_string_address = *reinterpret_cast<i::Tagged_t*>(
+ props->properties[2]->address + sizeof(i::Tagged_t));
+ props = d::GetObjectProperties(second_string_address, &ReadMemory, roots);
+ CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap);
+ CHECK(props->type == std::string("v8::internal::SeqOneByteString"));
+ CHECK_EQ(props->num_properties, 4);
+ CheckProp(*props->properties[0], "v8::internal::Map", "map");
+ CheckProp(*props->properties[1], "uint32_t", "hash_field");
+ CheckProp(*props->properties[2], "int32_t", "length", 2);
+ CheckProp(*props->properties[3], "char", "chars",
+ d::PropertyKind::kArrayOfKnownSize, 2);
+ CHECK_EQ(
+ strncmp("bc",
+ reinterpret_cast<const char*>(props->properties[3]->address), 2),
+ 0);
+
+ // Read the second string again, using a type hint instead of the map. All of
+ // its properties should match what we read last time.
+ d::ObjectPropertiesResultPtr props2;
+ {
+ uintptr_t map_address =
+ d::GetObjectProperties(
+ *reinterpret_cast<i::Tagged_t*>(props->properties[0]->address),
+ &ReadMemory, roots)
+ ->properties[0]
+ ->address;
+ MemoryFailureRegion failure(map_address, map_address + i::Map::kSize);
+ props2 = d::GetObjectProperties(second_string_address, &ReadMemory, roots,
+ "v8::internal::String");
+ CHECK(props2->type_check_result == d::TypeCheckResult::kUsedTypeHint);
+ CHECK(props2->type == std::string("v8::internal::String"));
+ CHECK_EQ(props2->num_properties, 3);
+ CheckProp(*props2->properties[0], "v8::internal::Map", "map",
+ *reinterpret_cast<i::Tagged_t*>(props->properties[0]->address));
+ CheckProp(*props2->properties[1], "uint32_t", "hash_field",
+ *reinterpret_cast<int32_t*>(props->properties[1]->address));
+ CheckProp(*props2->properties[2], "int32_t", "length", 2);
+ }
+
+ // Try a weak reference.
+ props2 = d::GetObjectProperties(second_string_address | kWeakHeapObjectMask,
+ &ReadMemory, roots);
+ std::string weak_ref_prefix = "weak ref to ";
+ CHECK(weak_ref_prefix + props->brief == props2->brief);
+ CHECK(props2->type_check_result == d::TypeCheckResult::kUsedMap);
+ CHECK(props2->type == std::string("v8::internal::SeqOneByteString"));
+ CHECK_EQ(props2->num_properties, 4);
+ CheckProp(*props2->properties[0], "v8::internal::Map", "map",
+ *reinterpret_cast<i::Tagged_t*>(props->properties[0]->address));
+ CheckProp(*props2->properties[1], "uint32_t", "hash_field",
+ *reinterpret_cast<i::Tagged_t*>(props->properties[1]->address));
+ CheckProp(*props2->properties[2], "int32_t", "length", 2);
+
+ // Build a complicated string (multi-level cons with slices inside) to test
+ // string printing.
+ v = CompileRun(R"(
+ const alphabet = "abcdefghijklmnopqrstuvwxyz";
+ alphabet.substr(3,20) + alphabet.toUpperCase().substr(5,15) + "7")");
+ o = v8::Utils::OpenHandle(*v);
+ props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
+ CHECK(std::string(props->brief).substr(0, 38) ==
+ std::string("\"defghijklmnopqrstuvwFGHIJKLMNOPQRST7\""));
+
+ // Cause a failure when reading the "second" pointer within the top-level
+ // ConsString.
+ {
+ CheckProp(*props->properties[4], "v8::internal::String", "second");
+ uintptr_t second_address = props->properties[4]->address;
+ MemoryFailureRegion failure(second_address, second_address + 4);
+ props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
+ CHECK(std::string(props->brief).substr(0, 40) ==
+ std::string("\"defghijklmnopqrstuvwFGHIJKLMNOPQRST...\""));
+ }
+
+ // Build a very long string.
+ v = CompileRun("'a'.repeat(1000)");
+ o = v8::Utils::OpenHandle(*v);
+ props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
+ CHECK(std::string(props->brief).substr(79, 7) == std::string("aa...\" "));
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc
index b3da0329f6..4ad55ef6b5 100644
--- a/deps/v8/test/cctest/test-debug.cc
+++ b/deps/v8/test/cctest/test-debug.cc
@@ -553,7 +553,7 @@ TEST(BreakPointBuiltin) {
builtin = CompileRun("String.prototype.repeat").As<v8::Function>();
// Run with breakpoint.
- bp = SetBreakPoint(builtin, 0);
+ bp = SetBreakPoint(builtin, 0, "this != 1");
ExpectString("'b'.repeat(10)", "bbbbbbbbbb");
CHECK_EQ(1, break_point_hit_count);
@@ -754,7 +754,7 @@ TEST(BreakPointConstructorBuiltin) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
- bp = SetBreakPoint(builtin, 0);
+ bp = SetBreakPoint(builtin, 0, "this != 1");
ExpectString("(new Promise(()=>{})).toString()", "[object Promise]");
CHECK_EQ(1, break_point_hit_count);
@@ -821,7 +821,7 @@ TEST(BreakPointInlinedBuiltin) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
- bp = SetBreakPoint(builtin, 0);
+ bp = SetBreakPoint(builtin, 0, "this != 1");
CompileRun("Math.sin(0.1);");
CHECK_EQ(1, break_point_hit_count);
CompileRun("test(0.2);");
@@ -869,7 +869,7 @@ TEST(BreakPointInlineBoundBuiltin) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
- bp = SetBreakPoint(builtin, 0);
+ bp = SetBreakPoint(builtin, 0, "this != 1");
CompileRun("'a'.repeat(2);");
CHECK_EQ(1, break_point_hit_count);
CompileRun("test(7);");
@@ -914,7 +914,7 @@ TEST(BreakPointInlinedConstructorBuiltin) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
- bp = SetBreakPoint(builtin, 0);
+ bp = SetBreakPoint(builtin, 0, "this != 1");
CompileRun("new Promise(()=>{});");
CHECK_EQ(1, break_point_hit_count);
CompileRun("test(7);");
@@ -1090,13 +1090,18 @@ TEST(BreakPointApiFunction) {
break_point_hit_count = 0;
// Run with breakpoint.
- bp = SetBreakPoint(function, 0);
+ bp = SetBreakPoint(function, 0, "this != 1");
ExpectInt32("f()", 2);
CHECK_EQ(1, break_point_hit_count);
ExpectInt32("f()", 2);
CHECK_EQ(2, break_point_hit_count);
+ // Direct call through API does not trigger breakpoint.
+ function->Call(env.local(), v8::Undefined(env->GetIsolate()), 0, nullptr)
+ .ToLocalChecked();
+ CHECK_EQ(2, break_point_hit_count);
+
// Run without breakpoints.
ClearBreakPoint(bp);
ExpectInt32("f()", 2);
@@ -1106,6 +1111,46 @@ TEST(BreakPointApiFunction) {
CheckDebuggerUnloaded();
}
+TEST(BreakPointApiConstructor) {
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+
+ DebugEventCounter delegate;
+ v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
+
+ i::Handle<i::BreakPoint> bp;
+
+ v8::Local<v8::FunctionTemplate> function_template =
+ v8::FunctionTemplate::New(env->GetIsolate(), NoOpFunctionCallback);
+
+ v8::Local<v8::Function> function =
+ function_template->GetFunction(env.local()).ToLocalChecked();
+
+ env->Global()->Set(env.local(), v8_str("f"), function).ToChecked();
+
+ // === Test simple builtin ===
+ break_point_hit_count = 0;
+
+ // Run with breakpoint.
+ bp = SetBreakPoint(function, 0, "this != 1");
+ CompileRun("new f()");
+ CHECK_EQ(1, break_point_hit_count);
+ CompileRun("new f()");
+ CHECK_EQ(2, break_point_hit_count);
+
+ // Direct call through API does not trigger breakpoint.
+ function->NewInstance(env.local()).ToLocalChecked();
+ CHECK_EQ(2, break_point_hit_count);
+
+ // Run without breakpoints.
+ ClearBreakPoint(bp);
+ CompileRun("new f()");
+ CHECK_EQ(2, break_point_hit_count);
+
+ v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
+ CheckDebuggerUnloaded();
+}
+
void GetWrapperCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(
args[0]
@@ -1145,15 +1190,16 @@ TEST(BreakPointApiGetter) {
// Run with breakpoint.
bp = SetBreakPoint(function, 0);
CompileRun("get_wrapper(o, 'f')");
- CHECK_EQ(1, break_point_hit_count);
+ CHECK_EQ(0, break_point_hit_count);
CompileRun("o.f");
- CHECK_EQ(2, break_point_hit_count);
+ CHECK_EQ(1, break_point_hit_count);
// Run without breakpoints.
ClearBreakPoint(bp);
CompileRun("get_wrapper(o, 'f', 2)");
- CHECK_EQ(2, break_point_hit_count);
+ CompileRun("o.f");
+ CHECK_EQ(1, break_point_hit_count);
v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
@@ -1202,12 +1248,12 @@ TEST(BreakPointApiSetter) {
CHECK_EQ(1, break_point_hit_count);
CompileRun("set_wrapper(o, 'f', 2)");
- CHECK_EQ(2, break_point_hit_count);
+ CHECK_EQ(1, break_point_hit_count);
// Run without breakpoints.
ClearBreakPoint(bp);
CompileRun("o.f = 3");
- CHECK_EQ(2, break_point_hit_count);
+ CHECK_EQ(1, break_point_hit_count);
// === Test API builtin as setter, with condition ===
break_point_hit_count = 0;
@@ -1218,15 +1264,16 @@ TEST(BreakPointApiSetter) {
CHECK_EQ(0, break_point_hit_count);
CompileRun("set_wrapper(o, 'f', 3)");
- CHECK_EQ(1, break_point_hit_count);
+ CHECK_EQ(0, break_point_hit_count);
CompileRun("o.f = 3");
- CHECK_EQ(2, break_point_hit_count);
+ CHECK_EQ(1, break_point_hit_count);
// Run without breakpoints.
ClearBreakPoint(bp);
CompileRun("set_wrapper(o, 'f', 2)");
- CHECK_EQ(2, break_point_hit_count);
+ CompileRun("o.f = 3");
+ CHECK_EQ(1, break_point_hit_count);
v8::debug::SetDebugDelegate(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
@@ -3435,6 +3482,35 @@ TEST(SyntaxErrorEventOnSyntaxException) {
CHECK_EQ(3, delegate.compile_error_event_count);
}
+class ExceptionEventCounter : public v8::debug::DebugDelegate {
+ public:
+ void ExceptionThrown(v8::Local<v8::Context> paused_context,
+ v8::Local<v8::Value> exception,
+ v8::Local<v8::Value> promise, bool is_uncaught,
+ v8::debug::ExceptionType) override {
+ exception_event_count++;
+ }
+ int exception_event_count = 0;
+};
+
+TEST(NoBreakOnStackOverflow) {
+ i::FLAG_stack_size = 100;
+ LocalContext env;
+ v8::HandleScope scope(env->GetIsolate());
+
+ ChangeBreakOnException(true, true);
+
+ ExceptionEventCounter delegate;
+ v8::debug::SetDebugDelegate(env->GetIsolate(), &delegate);
+ CHECK_EQ(0, delegate.exception_event_count);
+
+ CompileRun(
+ "function f() { return f(); }"
+ "try { f() } catch {}");
+
+ CHECK_EQ(0, delegate.exception_event_count);
+}
+
// Tests that break event is sent when event listener is reset.
TEST(BreakEventWhenEventListenerIsReset) {
LocalContext env;
@@ -3854,7 +3930,7 @@ TEST(DebugBreakOffThreadTerminate) {
DebugBreakTriggerTerminate delegate;
v8::debug::SetDebugDelegate(isolate, &delegate);
TerminationThread terminator(isolate);
- terminator.Start();
+ CHECK(terminator.Start());
v8::TryCatch try_catch(env->GetIsolate());
env->GetIsolate()->RequestInterrupt(BreakRightNow, nullptr);
CompileRun("while (true);");
@@ -3950,7 +4026,7 @@ class ArchiveRestoreThread : public v8::base::Thread,
// on) so that the ThreadManager is forced to archive and restore
// the current thread.
ArchiveRestoreThread child(isolate_, spawn_count_ - 1);
- child.Start();
+ CHECK(child.Start());
child.Join();
// The child thread sets itself as the debug delegate, so we need to
diff --git a/deps/v8/test/cctest/test-disasm-arm64.cc b/deps/v8/test/cctest/test-disasm-arm64.cc
index ed4fe6c6e0..ba4d92d3a2 100644
--- a/deps/v8/test/cctest/test-disasm-arm64.cc
+++ b/deps/v8/test/cctest/test-disasm-arm64.cc
@@ -854,7 +854,7 @@ TEST_(branch) {
COMPARE(br(x0), "br x0");
COMPARE(blr(x1), "blr x1");
COMPARE(ret(x2), "ret x2");
- COMPARE(ret(lr), "ret")
+ COMPARE(ret(lr), "ret");
CLEANUP();
}
@@ -1881,6 +1881,14 @@ TEST_(system_nop) {
CLEANUP();
}
+TEST(system_pauth) {
+ SET_UP_ASM();
+
+ COMPARE(pacia1716(), "pacia1716");
+ COMPARE(paciasp(), "paciasp");
+ COMPARE(autia1716(), "autia1716");
+ COMPARE(autiasp(), "autiasp");
+}
TEST_(debug) {
InitializeVM();
diff --git a/deps/v8/test/cctest/test-disasm-x64.cc b/deps/v8/test/cctest/test-disasm-x64.cc
index ff21e9b265..08793fba4a 100644
--- a/deps/v8/test/cctest/test-disasm-x64.cc
+++ b/deps/v8/test/cctest/test-disasm-x64.cc
@@ -517,6 +517,8 @@ TEST(DisasmX64) {
__ haddps(xmm1, xmm0);
__ haddps(xmm1, Operand(rbx, rcx, times_4, 10000));
__ lddqu(xmm1, Operand(rdx, 4));
+ __ movddup(xmm1, Operand(rax, 5));
+ __ movddup(xmm1, xmm2);
}
}
diff --git a/deps/v8/test/cctest/test-elements-kind.cc b/deps/v8/test/cctest/test-elements-kind.cc
index d08f6200ab..2f6ec6c164 100644
--- a/deps/v8/test/cctest/test-elements-kind.cc
+++ b/deps/v8/test/cctest/test-elements-kind.cc
@@ -63,6 +63,7 @@ bool ElementsKindIsHoleyElementsKindForRead(ElementsKind kind) {
case ElementsKind::HOLEY_SMI_ELEMENTS:
case ElementsKind::HOLEY_ELEMENTS:
case ElementsKind::HOLEY_DOUBLE_ELEMENTS:
+ case ElementsKind::HOLEY_NONEXTENSIBLE_ELEMENTS:
case ElementsKind::HOLEY_SEALED_ELEMENTS:
case ElementsKind::HOLEY_FROZEN_ELEMENTS:
return true;
diff --git a/deps/v8/test/cctest/test-feedback-vector.cc b/deps/v8/test/cctest/test-feedback-vector.cc
index 436925146b..91db7e51a5 100644
--- a/deps/v8/test/cctest/test-feedback-vector.cc
+++ b/deps/v8/test/cctest/test-feedback-vector.cc
@@ -438,9 +438,7 @@ TEST(VectorLoadICStates) {
Handle<FeedbackVector>(f->feedback_vector(), isolate);
FeedbackSlot slot(0);
FeedbackNexus nexus(feedback_vector, slot);
- CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
- CompileRun("f(o)");
CHECK_EQ(MONOMORPHIC, nexus.ic_state());
// Verify that the monomorphic map is the one we expect.
v8::MaybeLocal<v8::Value> v8_o =
@@ -526,16 +524,13 @@ TEST(VectorLoadICOnSmi) {
CompileRun(
"var o = { foo: 3 };"
"%EnsureFeedbackVectorForFunction(f);"
- "function f(a) { return a.foo; } f(o);");
+ "function f(a) { return a.foo; } f(34);");
Handle<JSFunction> f = GetFunction("f");
// There should be one IC.
Handle<FeedbackVector> feedback_vector =
Handle<FeedbackVector>(f->feedback_vector(), isolate);
FeedbackSlot slot(0);
FeedbackNexus nexus(feedback_vector, slot);
- CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
-
- CompileRun("f(34)");
CHECK_EQ(MONOMORPHIC, nexus.ic_state());
// Verify that the monomorphic map is the one we expect.
Map number_map = ReadOnlyRoots(heap).heap_number_map();
diff --git a/deps/v8/test/cctest/test-field-type-tracking.cc b/deps/v8/test/cctest/test-field-type-tracking.cc
index d23078b68a..512bf2a9c6 100644
--- a/deps/v8/test/cctest/test-field-type-tracking.cc
+++ b/deps/v8/test/cctest/test-field-type-tracking.cc
@@ -2282,7 +2282,9 @@ TEST(ElementsKindTransitionFromMapOwningDescriptor) {
{SEALED, factory->sealed_symbol(),
FLAG_enable_sealed_frozen_elements_kind ? HOLEY_SEALED_ELEMENTS
: DICTIONARY_ELEMENTS},
- {NONE, factory->nonextensible_symbol(), DICTIONARY_ELEMENTS}};
+ {NONE, factory->nonextensible_symbol(),
+ FLAG_enable_sealed_frozen_elements_kind ? HOLEY_NONEXTENSIBLE_ELEMENTS
+ : DICTIONARY_ELEMENTS}};
for (size_t i = 0; i < arraysize(configs); i++) {
TestGeneralizeFieldWithSpecialTransition(
configs[i],
@@ -2348,7 +2350,9 @@ TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
{SEALED, factory->sealed_symbol(),
FLAG_enable_sealed_frozen_elements_kind ? HOLEY_SEALED_ELEMENTS
: DICTIONARY_ELEMENTS},
- {NONE, factory->nonextensible_symbol(), DICTIONARY_ELEMENTS}};
+ {NONE, factory->nonextensible_symbol(),
+ FLAG_enable_sealed_frozen_elements_kind ? HOLEY_NONEXTENSIBLE_ELEMENTS
+ : DICTIONARY_ELEMENTS}};
for (size_t i = 0; i < arraysize(configs); i++) {
TestGeneralizeFieldWithSpecialTransition(
configs[i],
@@ -2407,7 +2411,6 @@ TEST(PrototypeTransitionFromMapOwningDescriptor) {
{PropertyConstness::kMutable, Representation::Tagged(), any_type}, true);
}
-
TEST(PrototypeTransitionFromMapNotOwningDescriptor) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
@@ -2461,7 +2464,6 @@ TEST(PrototypeTransitionFromMapNotOwningDescriptor) {
{PropertyConstness::kMutable, Representation::Tagged(), any_type}, true);
}
-
////////////////////////////////////////////////////////////////////////////////
// A set of tests for higher level transitioning mechanics.
//
@@ -2776,15 +2778,15 @@ TEST(TransitionAccessorConstantToSameAccessorConstant) {
// TODO(ishell): add this test once IS_ACCESSOR_FIELD_SUPPORTED is supported.
// TEST(TransitionAccessorConstantToAnotherAccessorConstant)
-TEST(HoleyMutableHeapNumber) {
+TEST(HoleyHeapNumber) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
- auto mhn = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
+ auto mhn = isolate->factory()->NewHeapNumberWithHoleNaN();
CHECK_EQ(kHoleNanInt64, mhn->value_as_bits());
- mhn = isolate->factory()->NewMutableHeapNumber(0.0);
+ mhn = isolate->factory()->NewHeapNumber(0.0);
CHECK_EQ(uint64_t{0}, mhn->value_as_bits());
mhn->set_value_as_bits(kHoleNanInt64);
@@ -2796,12 +2798,12 @@ TEST(HoleyMutableHeapNumber) {
Handle<Object> obj =
Object::NewStorageFor(isolate, isolate->factory()->uninitialized_value(),
Representation::Double());
- CHECK(obj->IsMutableHeapNumber());
- CHECK_EQ(kHoleNanInt64, MutableHeapNumber::cast(*obj).value_as_bits());
+ CHECK(obj->IsHeapNumber());
+ CHECK_EQ(kHoleNanInt64, HeapNumber::cast(*obj).value_as_bits());
obj = Object::NewStorageFor(isolate, mhn, Representation::Double());
- CHECK(obj->IsMutableHeapNumber());
- CHECK_EQ(kHoleNanInt64, MutableHeapNumber::cast(*obj).value_as_bits());
+ CHECK(obj->IsHeapNumber());
+ CHECK_EQ(kHoleNanInt64, HeapNumber::cast(*obj).value_as_bits());
}
namespace {
diff --git a/deps/v8/test/cctest/test-flags.cc b/deps/v8/test/cctest/test-flags.cc
index 93c7048f81..4e5fcffa62 100644
--- a/deps/v8/test/cctest/test-flags.cc
+++ b/deps/v8/test/cctest/test-flags.cc
@@ -209,5 +209,11 @@ TEST(FlagsJitlessImplications) {
}
}
+TEST(FlagsRegexpInterpretAllImplications) {
+ if (FLAG_regexp_interpret_all) {
+ CHECK(!FLAG_regexp_tier_up);
+ }
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc
index e534670bb6..3aec4ae003 100644
--- a/deps/v8/test/cctest/test-heap-profiler.cc
+++ b/deps/v8/test/cctest/test-heap-profiler.cc
@@ -46,6 +46,7 @@
#include "src/profiler/heap-snapshot-generator-inl.h"
#include "test/cctest/cctest.h"
#include "test/cctest/collector.h"
+#include "test/cctest/heap/heap-utils.h"
using i::AllocationTraceNode;
using i::AllocationTraceTree;
@@ -1693,6 +1694,154 @@ TEST(HeapSnapshotRetainedObjectInfo) {
CHECK_EQ(native_group_ccc, GetChildByName(n_CCC, "ccc-group"));
}
+namespace {
+
+class EmbedderGraphBuilderForNativeSnapshotObjectId final {
+ public:
+ class RegularNode : public v8::EmbedderGraph::Node {
+ public:
+ RegularNode(v8::NativeObject native_object, const char* name, size_t size,
+ Node* wrapper_node)
+ : name_(name),
+ size_(size),
+ native_object_(native_object),
+ wrapper_node_(wrapper_node) {}
+ // v8::EmbedderGraph::Node
+ const char* Name() override { return name_; }
+ size_t SizeInBytes() override { return size_; }
+ Node* WrapperNode() override { return wrapper_node_; }
+ v8::NativeObject GetNativeObject() override {
+ return native_object_ ? native_object_ : this;
+ }
+
+ private:
+ const char* name_;
+ size_t size_;
+ v8::NativeObject native_object_;
+ Node* wrapper_node_;
+ };
+
+ class RootNode : public RegularNode {
+ public:
+ explicit RootNode(const char* name)
+ : RegularNode(nullptr, name, 0, nullptr) {}
+ // v8::EmbedderGraph::EmbedderNode
+ bool IsRootNode() override { return true; }
+ };
+
+ struct BuildParameter {
+ v8::Persistent<v8::String>* wrapper;
+ void* native1;
+ void* native2;
+ };
+
+ static void BuildEmbedderGraph(v8::Isolate* isolate, v8::EmbedderGraph* graph,
+ void* data) {
+ BuildParameter* parameter = reinterpret_cast<BuildParameter*>(data);
+ v8::Local<v8::String> local_str =
+ v8::Local<v8::String>::New(isolate, *(parameter->wrapper));
+ auto* v8_node = graph->V8Node(local_str);
+ CHECK(!v8_node->IsEmbedderNode());
+ auto* root_node =
+ graph->AddNode(std::unique_ptr<RootNode>(new RootNode("root")));
+ auto* non_merged_node = graph->AddNode(std::unique_ptr<RegularNode>(
+ new RegularNode(parameter->native1, "non-merged", 0, nullptr)));
+ auto* merged_node = graph->AddNode(std::unique_ptr<RegularNode>(
+ new RegularNode(parameter->native2, "merged", 0, v8_node)));
+ graph->AddEdge(root_node, non_merged_node);
+ graph->AddEdge(root_node, merged_node);
+ }
+};
+
+} // namespace
+
+TEST(NativeSnapshotObjectId) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
+
+ v8::Persistent<v8::String> wrapper(isolate, v8_str("wrapper"));
+ int native1;
+ int native2;
+
+ EmbedderGraphBuilderForNativeSnapshotObjectId::BuildParameter parameter{
+ &wrapper, &native1, &native2};
+ heap_profiler->AddBuildEmbedderGraphCallback(
+ EmbedderGraphBuilderForNativeSnapshotObjectId::BuildEmbedderGraph,
+ &parameter);
+ const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
+ CHECK(ValidateSnapshot(snapshot));
+
+ v8::SnapshotObjectId non_merged_id = heap_profiler->GetObjectId(&native1);
+ CHECK_NE(v8::HeapProfiler::kUnknownObjectId, non_merged_id);
+ v8::SnapshotObjectId merged_id = heap_profiler->GetObjectId(&native2);
+ CHECK_NE(v8::HeapProfiler::kUnknownObjectId, merged_id);
+ CHECK_NE(non_merged_id, merged_id);
+ const v8::HeapGraphNode* non_merged_node =
+ snapshot->GetNodeById(non_merged_id);
+ CHECK_NOT_NULL(non_merged_node);
+ const v8::HeapGraphNode* merged_node = snapshot->GetNodeById(merged_id);
+ CHECK_NOT_NULL(merged_node);
+
+ heap_profiler->ClearObjectIds();
+ CHECK_EQ(v8::HeapProfiler::kUnknownObjectId,
+ heap_profiler->GetObjectId(&native1));
+ CHECK_EQ(v8::HeapProfiler::kUnknownObjectId,
+ heap_profiler->GetObjectId(&native2));
+}
+
+TEST(NativeSnapshotObjectIdMoving) {
+ // Required to allow moving specific objects.
+ i::FLAG_manual_evacuation_candidates_selection = true;
+
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
+ heap_profiler->StartTrackingHeapObjects(true);
+
+ v8::Persistent<v8::String> wrapper(isolate, v8_str("wrapper"));
+ int native1;
+ int native2;
+
+ EmbedderGraphBuilderForNativeSnapshotObjectId::BuildParameter parameter{
+ &wrapper, &native1, &native2};
+ heap_profiler->AddBuildEmbedderGraphCallback(
+ EmbedderGraphBuilderForNativeSnapshotObjectId::BuildEmbedderGraph,
+ &parameter);
+ const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
+ CHECK(ValidateSnapshot(snapshot));
+
+ v8::SnapshotObjectId non_merged_id = heap_profiler->GetObjectId(&native1);
+ CHECK_NE(v8::HeapProfiler::kUnknownObjectId, non_merged_id);
+ v8::SnapshotObjectId merged_id = heap_profiler->GetObjectId(&native2);
+ CHECK_NE(v8::HeapProfiler::kUnknownObjectId, merged_id);
+ CHECK_NE(non_merged_id, merged_id);
+ const v8::HeapGraphNode* non_merged_node =
+ snapshot->GetNodeById(non_merged_id);
+ CHECK_NOT_NULL(non_merged_node);
+ const v8::HeapGraphNode* merged_node = snapshot->GetNodeById(merged_id);
+ CHECK_NOT_NULL(merged_node);
+
+ {
+ v8::HandleScope scope(isolate);
+ auto local = v8::Local<v8::String>::New(isolate, wrapper);
+ i::Handle<i::String> internal = i::Handle<i::String>::cast(
+ v8::Utils::OpenHandle(*v8::Local<v8::String>::Cast(local)));
+ i::heap::ForceEvacuationCandidate(i::Page::FromHeapObject(*internal));
+ }
+ CcTest::CollectAllGarbage();
+
+ non_merged_id = heap_profiler->GetObjectId(&native1);
+ CHECK_NE(v8::HeapProfiler::kUnknownObjectId, non_merged_id);
+ merged_id = heap_profiler->GetObjectId(&native2);
+ CHECK_NE(v8::HeapProfiler::kUnknownObjectId, merged_id);
+ CHECK_NE(non_merged_id, merged_id);
+
+ heap_profiler->StopTrackingHeapObjects();
+}
+
TEST(DeleteAllHeapSnapshots) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
diff --git a/deps/v8/test/cctest/test-inobject-slack-tracking.cc b/deps/v8/test/cctest/test-inobject-slack-tracking.cc
index f0df0c6149..6a25536dd5 100644
--- a/deps/v8/test/cctest/test-inobject-slack-tracking.cc
+++ b/deps/v8/test/cctest/test-inobject-slack-tracking.cc
@@ -84,8 +84,8 @@ static double GetDoubleFieldValue(JSObject obj, FieldIndex field_index) {
return obj.RawFastDoublePropertyAt(field_index);
} else {
Object value = obj.RawFastPropertyAt(field_index);
- if (value.IsMutableHeapNumber()) {
- return MutableHeapNumber::cast(value).value();
+ if (value.IsHeapNumber()) {
+ return HeapNumber::cast(value).value();
} else {
return value.Number();
}
diff --git a/deps/v8/test/cctest/test-js-weak-refs.cc b/deps/v8/test/cctest/test-js-weak-refs.cc
index 51add24a60..9e44c3ad20 100644
--- a/deps/v8/test/cctest/test-js-weak-refs.cc
+++ b/deps/v8/test/cctest/test-js-weak-refs.cc
@@ -731,7 +731,7 @@ TEST(TestJSWeakRefKeepDuringJob) {
CHECK(!weak_ref->target().IsUndefined(isolate));
// Clears the KeepDuringJob set.
- isolate->default_microtask_queue()->RunMicrotasks(isolate);
+ context->GetIsolate()->ClearKeptObjects();
CcTest::CollectAllGarbage();
CHECK(weak_ref->target().IsUndefined(isolate));
@@ -769,7 +769,7 @@ TEST(TestJSWeakRefKeepDuringJobIncrementalMarking) {
CHECK(!weak_ref->target().IsUndefined(isolate));
// Clears the KeepDuringJob set.
- isolate->default_microtask_queue()->RunMicrotasks(isolate);
+ context->GetIsolate()->ClearKeptObjects();
heap::SimulateIncrementalMarking(heap, true);
CcTest::CollectAllGarbage();
diff --git a/deps/v8/test/cctest/test-lockers.cc b/deps/v8/test/cctest/test-lockers.cc
index 571b0000eb..092c107841 100644
--- a/deps/v8/test/cctest/test-lockers.cc
+++ b/deps/v8/test/cctest/test-lockers.cc
@@ -82,7 +82,7 @@ void UnlockForDeoptimization(const v8::FunctionCallbackInfo<v8::Value>& args) {
isolate->Exit();
v8::Unlocker unlocker(isolate);
// Starts the deoptimizing thread.
- deoptimizer->Start();
+ CHECK(deoptimizer->Start());
// Waits for deoptimization to finish.
deoptimizer->Join();
}
@@ -107,7 +107,7 @@ void UnlockForDeoptimizationIfReady(
isolate->Exit();
v8::Unlocker unlocker(isolate);
// Starts the thread that deoptimizes the function.
- deoptimizer->Start();
+ CHECK(deoptimizer->Start());
// Waits for the deoptimizing thread to finish.
deoptimizer->Join();
}
@@ -339,7 +339,7 @@ TEST(KangarooIsolates) {
CompileRun("function getValue() { return 30; }");
thread1.reset(new KangarooThread(isolate, context));
}
- thread1->Start();
+ CHECK(thread1->Start());
thread1->Join();
}
@@ -364,9 +364,7 @@ class JoinableThread {
virtual ~JoinableThread() = default;
- void Start() {
- thread_.Start();
- }
+ void Start() { CHECK(thread_.Start()); }
void Join() {
semaphore_.Wait();
diff --git a/deps/v8/test/cctest/test-log-stack-tracer.cc b/deps/v8/test/cctest/test-log-stack-tracer.cc
index 83060f0cac..854a31f66b 100644
--- a/deps/v8/test/cctest/test-log-stack-tracer.cc
+++ b/deps/v8/test/cctest/test-log-stack-tracer.cc
@@ -37,6 +37,7 @@
#include "src/execution/vm-state-inl.h"
#include "src/init/v8.h"
#include "src/objects/objects-inl.h"
+#include "src/profiler/tick-sample.h"
#include "test/cctest/cctest.h"
#include "test/cctest/trace-extension.h"
diff --git a/deps/v8/test/cctest/test-orderedhashtable.cc b/deps/v8/test/cctest/test-orderedhashtable.cc
index 9b1bc651fa..44a845eb74 100644
--- a/deps/v8/test/cctest/test-orderedhashtable.cc
+++ b/deps/v8/test/cctest/test-orderedhashtable.cc
@@ -509,14 +509,14 @@ TEST(OrderedHashTableInsertion) {
Handle<Smi> key1(Smi::FromInt(1), isolate);
Handle<Smi> value1(Smi::FromInt(1), isolate);
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
- map = OrderedHashMap::Add(isolate, map, key1, value1);
+ map = OrderedHashMap::Add(isolate, map, key1, value1).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
// Add existing key.
- map = OrderedHashMap::Add(isolate, map, key1, value1);
+ map = OrderedHashMap::Add(isolate, map, key1, value1).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
@@ -525,14 +525,14 @@ TEST(OrderedHashTableInsertion) {
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
Handle<String> value = factory->NewStringFromAsciiChecked("bar");
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
- map = OrderedHashMap::Add(isolate, map, key2, value);
+ map = OrderedHashMap::Add(isolate, map, key2, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(2, map->NumberOfElements());
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
- map = OrderedHashMap::Add(isolate, map, key2, value);
+ map = OrderedHashMap::Add(isolate, map, key2, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(2, map->NumberOfElements());
@@ -541,7 +541,7 @@ TEST(OrderedHashTableInsertion) {
Handle<Symbol> key3 = factory->NewSymbol();
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key3));
- map = OrderedHashMap::Add(isolate, map, key3, value);
+ map = OrderedHashMap::Add(isolate, map, key3, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(3, map->NumberOfElements());
@@ -549,7 +549,7 @@ TEST(OrderedHashTableInsertion) {
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK(OrderedHashMap::HasKey(isolate, *map, *key3));
- map = OrderedHashMap::Add(isolate, map, key3, value);
+ map = OrderedHashMap::Add(isolate, map, key3, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(3, map->NumberOfElements());
@@ -559,7 +559,7 @@ TEST(OrderedHashTableInsertion) {
Handle<Object> key4 = factory->NewHeapNumber(42.0);
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key4));
- map = OrderedHashMap::Add(isolate, map, key4, value);
+ map = OrderedHashMap::Add(isolate, map, key4, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(4, map->NumberOfElements());
@@ -568,7 +568,7 @@ TEST(OrderedHashTableInsertion) {
CHECK(OrderedHashMap::HasKey(isolate, *map, *key3));
CHECK(OrderedHashMap::HasKey(isolate, *map, *key4));
- map = OrderedHashMap::Add(isolate, map, key4, value);
+ map = OrderedHashMap::Add(isolate, map, key4, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(4, map->NumberOfElements());
@@ -587,7 +587,7 @@ TEST(OrderedHashMapDuplicateHashCode) {
Handle<OrderedHashMap> map = factory->NewOrderedHashMap();
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
Handle<JSObject> value = factory->NewJSObjectWithNullProto();
- map = OrderedHashMap::Add(isolate, map, key1, value);
+ map = OrderedHashMap::Add(isolate, map, key1, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
@@ -596,7 +596,7 @@ TEST(OrderedHashMapDuplicateHashCode) {
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
CopyHashCode(key1, key2);
- map = OrderedHashMap::Add(isolate, map, key2, value);
+ map = OrderedHashMap::Add(isolate, map, key2, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(2, map->NumberOfElements());
@@ -627,7 +627,7 @@ TEST(OrderedHashMapDeletion) {
CHECK_EQ(0, map->NumberOfDeletedElements());
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
- map = OrderedHashMap::Add(isolate, map, key1, value1);
+ map = OrderedHashMap::Add(isolate, map, key1, value1).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
@@ -642,7 +642,7 @@ TEST(OrderedHashMapDeletion) {
CHECK_EQ(1, map->NumberOfDeletedElements());
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
- map = OrderedHashMap::Add(isolate, map, key1, value1);
+ map = OrderedHashMap::Add(isolate, map, key1, value1).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
@@ -651,7 +651,7 @@ TEST(OrderedHashMapDeletion) {
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
- map = OrderedHashMap::Add(isolate, map, key2, value);
+ map = OrderedHashMap::Add(isolate, map, key2, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(2, map->NumberOfElements());
@@ -660,7 +660,7 @@ TEST(OrderedHashMapDeletion) {
Handle<Symbol> key3 = factory->NewSymbol();
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key3));
- map = OrderedHashMap::Add(isolate, map, key3, value);
+ map = OrderedHashMap::Add(isolate, map, key3, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(3, map->NumberOfElements());
@@ -709,7 +709,7 @@ TEST(OrderedHashMapDeletion) {
// Delete non existent key from non empty hash table
map = OrderedHashMap::Shrink(isolate, map);
- map = OrderedHashMap::Add(isolate, map, key1, value);
+ map = OrderedHashMap::Add(isolate, map, key1, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
@@ -858,7 +858,7 @@ TEST(OrderedHashMapDuplicateHashCodeDeletion) {
Handle<OrderedHashMap> map = factory->NewOrderedHashMap();
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
Handle<JSObject> value = factory->NewJSObjectWithNullProto();
- map = OrderedHashMap::Add(isolate, map, key1, value);
+ map = OrderedHashMap::Add(isolate, map, key1, value).ToHandleChecked();
Verify(isolate, map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
@@ -928,7 +928,7 @@ TEST(OrderedHashSetDeletion) {
CHECK_EQ(0, set->NumberOfDeletedElements());
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key1));
- set = OrderedHashSet::Add(isolate, set, key1);
+ set = OrderedHashSet::Add(isolate, set, key1).ToHandleChecked();
Verify(isolate, set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
@@ -943,7 +943,7 @@ TEST(OrderedHashSetDeletion) {
CHECK_EQ(1, set->NumberOfDeletedElements());
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key1));
- set = OrderedHashSet::Add(isolate, set, key1);
+ set = OrderedHashSet::Add(isolate, set, key1).ToHandleChecked();
Verify(isolate, set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
@@ -952,7 +952,7 @@ TEST(OrderedHashSetDeletion) {
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key2));
- set = OrderedHashSet::Add(isolate, set, key2);
+ set = OrderedHashSet::Add(isolate, set, key2).ToHandleChecked();
Verify(isolate, set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(2, set->NumberOfElements());
@@ -961,7 +961,7 @@ TEST(OrderedHashSetDeletion) {
Handle<Symbol> key3 = factory->NewSymbol();
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key3));
- set = OrderedHashSet::Add(isolate, set, key3);
+ set = OrderedHashSet::Add(isolate, set, key3).ToHandleChecked();
Verify(isolate, set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(3, set->NumberOfElements());
@@ -1010,7 +1010,7 @@ TEST(OrderedHashSetDeletion) {
// Delete non existent key from non empty hash table
set = OrderedHashSet::Shrink(isolate, set);
- set = OrderedHashSet::Add(isolate, set, key1);
+ set = OrderedHashSet::Add(isolate, set, key1).ToHandleChecked();
Verify(isolate, set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
@@ -1156,7 +1156,7 @@ TEST(OrderedHashSetDuplicateHashCodeDeletion) {
Handle<OrderedHashSet> set = factory->NewOrderedHashSet();
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
- set = OrderedHashSet::Add(isolate, set, key1);
+ set = OrderedHashSet::Add(isolate, set, key1).ToHandleChecked();
Verify(isolate, set);
CHECK_EQ(2, set->NumberOfBuckets());
CHECK_EQ(1, set->NumberOfElements());
@@ -1209,25 +1209,26 @@ TEST(OrderedHashSetHandlerInsertion) {
Isolate* isolate = GetIsolateFrom(&context);
HandleScope scope(isolate);
- Handle<HeapObject> set = OrderedHashSetHandler::Allocate(isolate, 4);
+ Handle<HeapObject> set =
+ OrderedHashSetHandler::Allocate(isolate, 4).ToHandleChecked();
Verify(isolate, set);
// Add a new key.
Handle<Smi> key1(Smi::FromInt(1), isolate);
CHECK(!OrderedHashSetHandler::HasKey(isolate, set, key1));
- set = OrderedHashSetHandler::Add(isolate, set, key1);
+ set = OrderedHashSetHandler::Add(isolate, set, key1).ToHandleChecked();
Verify(isolate, set);
CHECK(OrderedHashSetHandler::HasKey(isolate, set, key1));
// Add existing key.
- set = OrderedHashSetHandler::Add(isolate, set, key1);
+ set = OrderedHashSetHandler::Add(isolate, set, key1).ToHandleChecked();
Verify(isolate, set);
CHECK(OrderedHashSetHandler::HasKey(isolate, set, key1));
CHECK(SmallOrderedHashSet::Is(set));
for (int i = 0; i < 1024; i++) {
Handle<Smi> key_i(Smi::FromInt(i), isolate);
- set = OrderedHashSetHandler::Add(isolate, set, key_i);
+ set = OrderedHashSetHandler::Add(isolate, set, key_i).ToHandleChecked();
Verify(isolate, set);
for (int j = 0; j <= i; j++) {
Handle<Smi> key_j(Smi::FromInt(j), isolate);
@@ -1242,26 +1243,30 @@ TEST(OrderedHashMapHandlerInsertion) {
Isolate* isolate = GetIsolateFrom(&context);
HandleScope scope(isolate);
- Handle<HeapObject> map = OrderedHashMapHandler::Allocate(isolate, 4);
+ Handle<HeapObject> map =
+ OrderedHashMapHandler::Allocate(isolate, 4).ToHandleChecked();
Verify(isolate, map);
// Add a new key.
Handle<Smi> key1(Smi::FromInt(1), isolate);
Handle<Smi> value1(Smi::FromInt(1), isolate);
CHECK(!OrderedHashMapHandler::HasKey(isolate, map, key1));
- map = OrderedHashMapHandler::Add(isolate, map, key1, value1);
+ map =
+ OrderedHashMapHandler::Add(isolate, map, key1, value1).ToHandleChecked();
Verify(isolate, map);
CHECK(OrderedHashMapHandler::HasKey(isolate, map, key1));
// Add existing key.
- map = OrderedHashMapHandler::Add(isolate, map, key1, value1);
+ map =
+ OrderedHashMapHandler::Add(isolate, map, key1, value1).ToHandleChecked();
Verify(isolate, map);
CHECK(OrderedHashMapHandler::HasKey(isolate, map, key1));
CHECK(SmallOrderedHashMap::Is(map));
for (int i = 0; i < 1024; i++) {
Handle<Smi> key_i(Smi::FromInt(i), isolate);
Handle<Smi> value_i(Smi::FromInt(i), isolate);
- map = OrderedHashMapHandler::Add(isolate, map, key_i, value_i);
+ map = OrderedHashMapHandler::Add(isolate, map, key_i, value_i)
+ .ToHandleChecked();
Verify(isolate, map);
for (int j = 0; j <= i; j++) {
Handle<Smi> key_j(Smi::FromInt(j), isolate);
@@ -1286,7 +1291,8 @@ TEST(OrderedNameDictionaryInsertion) {
Handle<String> value = isolate->factory()->InternalizeUtf8String("bar");
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key1));
PropertyDetails details = PropertyDetails::Empty();
- dict = OrderedNameDictionary::Add(isolate, dict, key1, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key1, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
@@ -1295,7 +1301,8 @@ TEST(OrderedNameDictionaryInsertion) {
Handle<Symbol> key2 = factory->NewSymbol();
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key2));
- dict = OrderedNameDictionary::Add(isolate, dict, key2, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key2, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(2, dict->NumberOfElements());
@@ -1317,7 +1324,8 @@ TEST(OrderedNameDictionaryFindEntry) {
Handle<String> key1 = isolate->factory()->InternalizeUtf8String("foo");
Handle<String> value = isolate->factory()->InternalizeUtf8String("bar");
PropertyDetails details = PropertyDetails::Empty();
- dict = OrderedNameDictionary::Add(isolate, dict, key1, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key1, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
@@ -1327,7 +1335,8 @@ TEST(OrderedNameDictionaryFindEntry) {
CHECK_NE(entry, OrderedNameDictionary::kNotFound);
Handle<Symbol> key2 = factory->NewSymbol();
- dict = OrderedNameDictionary::Add(isolate, dict, key2, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key2, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(2, dict->NumberOfElements());
@@ -1356,7 +1365,8 @@ TEST(OrderedNameDictionaryValueAtAndValueAtPut) {
Handle<String> value = isolate->factory()->InternalizeUtf8String("bar");
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key1));
PropertyDetails details = PropertyDetails::Empty();
- dict = OrderedNameDictionary::Add(isolate, dict, key1, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key1, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
@@ -1376,7 +1386,8 @@ TEST(OrderedNameDictionaryValueAtAndValueAtPut) {
Handle<Symbol> key2 = factory->NewSymbol();
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key2));
- dict = OrderedNameDictionary::Add(isolate, dict, key2, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key2, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(2, dict->NumberOfElements());
@@ -1414,7 +1425,8 @@ TEST(OrderedNameDictionaryDetailsAtAndDetailsAtPut) {
Handle<String> value = isolate->factory()->InternalizeUtf8String("bar");
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key1));
PropertyDetails details = PropertyDetails::Empty();
- dict = OrderedNameDictionary::Add(isolate, dict, key1, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key1, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
@@ -1434,7 +1446,8 @@ TEST(OrderedNameDictionaryDetailsAtAndDetailsAtPut) {
Handle<Symbol> key2 = factory->NewSymbol();
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key2));
- dict = OrderedNameDictionary::Add(isolate, dict, key2, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key2, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(2, dict->NumberOfElements());
@@ -1725,7 +1738,8 @@ TEST(OrderedNameDictionarySetAndMigrateHash) {
for (int i = 0; i <= 1024; i++) {
CHECK_LT(0, snprintf(buf, sizeof(buf), "foo%d", i));
Handle<String> key = isolate->factory()->InternalizeUtf8String(buf);
- dict = OrderedNameDictionary::Add(isolate, dict, key, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(100, dict->Hash());
}
@@ -1736,7 +1750,8 @@ TEST(OrderedNameDictionaryHandlerInsertion) {
Isolate* isolate = GetIsolateFrom(&context);
HandleScope scope(isolate);
- Handle<HeapObject> table = OrderedNameDictionaryHandler::Allocate(isolate, 4);
+ Handle<HeapObject> table =
+ OrderedNameDictionaryHandler::Allocate(isolate, 4).ToHandleChecked();
CHECK(table->IsSmallOrderedNameDictionary());
Verify(isolate, table);
@@ -1745,8 +1760,8 @@ TEST(OrderedNameDictionaryHandlerInsertion) {
Handle<String> key = isolate->factory()->InternalizeUtf8String("foo");
PropertyDetails details = PropertyDetails::Empty();
- table =
- OrderedNameDictionaryHandler::Add(isolate, table, key, value, details);
+ table = OrderedNameDictionaryHandler::Add(isolate, table, key, value, details)
+ .ToHandleChecked();
DCHECK(key->IsUniqueName());
Verify(isolate, table);
CHECK(table->IsSmallOrderedNameDictionary());
@@ -1758,7 +1773,8 @@ TEST(OrderedNameDictionaryHandlerInsertion) {
CHECK_LT(0, snprintf(buf, sizeof(buf), "foo%d", i));
key = isolate->factory()->InternalizeUtf8String(buf);
table =
- OrderedNameDictionaryHandler::Add(isolate, table, key, value, details);
+ OrderedNameDictionaryHandler::Add(isolate, table, key, value, details)
+ .ToHandleChecked();
DCHECK(key->IsUniqueName());
Verify(isolate, table);
@@ -1798,7 +1814,8 @@ TEST(OrderedNameDictionarySetEntry) {
Handle<String> value = factory->InternalizeUtf8String("bar");
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key));
PropertyDetails details = PropertyDetails::Empty();
- dict = OrderedNameDictionary::Add(isolate, dict, key, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
@@ -1884,7 +1901,8 @@ TEST(OrderedNameDictionaryDeleteEntry) {
Handle<String> value = factory->InternalizeUtf8String("bar");
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key));
PropertyDetails details = PropertyDetails::Empty();
- dict = OrderedNameDictionary::Add(isolate, dict, key, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key, value, details)
+ .ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
@@ -1903,7 +1921,8 @@ TEST(OrderedNameDictionaryDeleteEntry) {
for (int i = 0; i < 100; i++) {
CHECK_LT(0, snprintf(buf, sizeof(buf), "foo%d", i));
key = factory->InternalizeUtf8String(buf);
- dict = OrderedNameDictionary::Add(isolate, dict, key, value, details);
+ dict = OrderedNameDictionary::Add(isolate, dict, key, value, details)
+ .ToHandleChecked();
DCHECK(key->IsUniqueName());
Verify(isolate, dict);
}
diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc
index ba69b6d2f6..857bd7a454 100644
--- a/deps/v8/test/cctest/test-parsing.cc
+++ b/deps/v8/test/cctest/test-parsing.cc
@@ -261,6 +261,7 @@ TEST(ArrowOrAssignmentOp) {
bool TokenIsBinaryOp(Token::Value token) {
switch (token) {
case Token::COMMA:
+ case Token::NULLISH:
case Token::OR:
case Token::AND:
#define T(name, string, precedence) case Token::name:
@@ -390,6 +391,7 @@ bool TokenIsPropertyOrCall(Token::Value token) {
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL:
case Token::PERIOD:
+ case Token::QUESTION_PERIOD:
case Token::LBRACK:
case Token::LPAREN:
return true;
@@ -1096,7 +1098,7 @@ TEST(ScopeUsesArgumentsSuperThis) {
}
if (is_sloppy(scope->language_mode())) {
CHECK_EQ((source_data[i].expected & EVAL) != 0,
- scope->AsDeclarationScope()->calls_sloppy_eval());
+ scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
}
}
}
@@ -1529,7 +1531,8 @@ enum ParserFlag {
kAllowHarmonyPrivateMethods,
kAllowHarmonyDynamicImport,
kAllowHarmonyImportMeta,
- kAllowHarmonyNumericSeparator
+ kAllowHarmonyNullish,
+ kAllowHarmonyOptionalChaining,
};
enum ParserSyncTestResult {
@@ -1543,8 +1546,9 @@ void SetGlobalFlags(base::EnumSet<ParserFlag> flags) {
i::FLAG_harmony_private_methods = flags.contains(kAllowHarmonyPrivateMethods);
i::FLAG_harmony_dynamic_import = flags.contains(kAllowHarmonyDynamicImport);
i::FLAG_harmony_import_meta = flags.contains(kAllowHarmonyImportMeta);
- i::FLAG_harmony_numeric_separator =
- flags.contains(kAllowHarmonyNumericSeparator);
+ i::FLAG_harmony_optional_chaining =
+ flags.contains(kAllowHarmonyOptionalChaining);
+ i::FLAG_harmony_nullish = flags.contains(kAllowHarmonyNullish);
}
void SetParserFlags(i::PreParser* parser, base::EnumSet<ParserFlag> flags) {
@@ -1555,8 +1559,9 @@ void SetParserFlags(i::PreParser* parser, base::EnumSet<ParserFlag> flags) {
flags.contains(kAllowHarmonyDynamicImport));
parser->set_allow_harmony_import_meta(
flags.contains(kAllowHarmonyImportMeta));
- parser->set_allow_harmony_numeric_separator(
- flags.contains(kAllowHarmonyNumericSeparator));
+ parser->set_allow_harmony_optional_chaining(
+ flags.contains(kAllowHarmonyOptionalChaining));
+ parser->set_allow_harmony_nullish(flags.contains(kAllowHarmonyNullish));
}
void TestParserSyncWithFlags(i::Handle<i::String> source,
@@ -1883,6 +1888,18 @@ void RunModuleParserSyncTest(
always_false_len, true, test_preparser, ignore_error_msg);
}
+TEST(NonOctalDecimalIntegerStrictError) {
+ v8::HandleScope handles(CcTest::isolate());
+ v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
+ v8::Context::Scope context_scope(context);
+
+ const char* context_data[][2] = {{"\"use strict\";", ""}, {nullptr, nullptr}};
+ const char* statement_data[] = {"09", "09.1_2", nullptr};
+
+ RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, nullptr,
+ 0, nullptr, 0, false, true);
+}
+
TEST(NumericSeparator) {
v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
@@ -1894,11 +1911,7 @@ TEST(NumericSeparator) {
"1_0_0_0", "1_0e+1", "1_0e+1_0", "0xF_F_FF", "0o7_7_7", "0b0_1_0_1_0",
".3_2_1", "0.0_2_1", "1_0.0_1", ".0_1_2", nullptr};
- static const ParserFlag flags[] = {kAllowHarmonyNumericSeparator};
- RunParserSyncTest(context_data, statement_data, kSuccess, nullptr, 0, flags,
- 1);
-
- RunParserSyncTest(context_data, statement_data, kError);
+ RunParserSyncTest(context_data, statement_data, kSuccess);
}
TEST(NumericSeparatorErrors) {
@@ -1914,11 +1927,8 @@ TEST(NumericSeparatorErrors) {
"0b1__1", "0_b1", "0_b_1", "0o777_", "0o_777", "0o7__77",
"0.0_2_1_", "0.0__21", "0_.01", "0._01", nullptr};
- static const ParserFlag flags[] = {kAllowHarmonyNumericSeparator};
- RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, flags, 1,
- nullptr, 0, false, true, true);
-
- RunParserSyncTest(context_data, statement_data, kError);
+ RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, nullptr,
+ 0, nullptr, 0, false, true);
}
TEST(NumericSeparatorImplicitOctalsErrors) {
@@ -1932,11 +1942,32 @@ TEST(NumericSeparatorImplicitOctalsErrors) {
"0_7_7_7", "0_777", "07_7_7_",
"07__77", "0__777", nullptr};
- static const ParserFlag flags[] = {kAllowHarmonyNumericSeparator};
- RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, flags, 1,
- nullptr, 0, false, true, true);
+ RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, nullptr,
+ 0, nullptr, 0, false, true);
+}
- RunParserSyncTest(context_data, statement_data, kError);
+TEST(NumericSeparatorNonOctalDecimalInteger) {
+ v8::HandleScope handles(CcTest::isolate());
+ v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
+ v8::Context::Scope context_scope(context);
+
+ const char* context_data[][2] = {{"", ""}, {nullptr, nullptr}};
+ const char* statement_data[] = {"09.1_2", nullptr};
+
+ RunParserSyncTest(context_data, statement_data, kSuccess, nullptr, 0, nullptr,
+ 0, nullptr, 0, false, true);
+}
+
+TEST(NumericSeparatorNonOctalDecimalIntegerErrors) {
+ v8::HandleScope handles(CcTest::isolate());
+ v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
+ v8::Context::Scope context_scope(context);
+
+ const char* context_data[][2] = {{"", ""}, {nullptr, nullptr}};
+ const char* statement_data[] = {"09_12", nullptr};
+
+ RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, nullptr,
+ 0, nullptr, 0, false, true);
}
TEST(NumericSeparatorUnicodeEscapeSequencesErrors) {
@@ -1949,12 +1980,74 @@ TEST(NumericSeparatorUnicodeEscapeSequencesErrors) {
// https://github.com/tc39/proposal-numeric-separator/issues/25
const char* statement_data[] = {"\\u{10_FFFF}", nullptr};
- static const ParserFlag flags[] = {kAllowHarmonyNumericSeparator};
- RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, flags, 1);
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+TEST(OptionalChaining) {
+ v8::HandleScope handles(CcTest::isolate());
+ v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
+ v8::Context::Scope context_scope(context);
+
+ const char* context_data[][2] = {
+ {"", ""}, {"'use strict';", ""}, {nullptr, nullptr}};
+ const char* statement_data[] = {"a?.b", "a?.['b']", "a?.()", nullptr};
+
+ static const ParserFlag flags[] = {kAllowHarmonyOptionalChaining};
+ RunParserSyncTest(context_data, statement_data, kSuccess, nullptr, 0, flags,
+ 1, nullptr, 0, false, true, true);
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+TEST(OptionalChainingTaggedError) {
+ v8::HandleScope handles(CcTest::isolate());
+ v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
+ v8::Context::Scope context_scope(context);
+
+ const char* context_data[][2] = {
+ {"", ""}, {"'use strict';", ""}, {nullptr, nullptr}};
+ const char* statement_data[] = {"a?.b``", "a?.['b']``", "a?.()``", nullptr};
+ static const ParserFlag flags[] = {kAllowHarmonyOptionalChaining};
+ RunParserSyncTest(context_data, statement_data, kError, nullptr, 9, flags, 1,
+ nullptr, 0, false, true, true);
RunParserSyncTest(context_data, statement_data, kError);
}
+TEST(Nullish) {
+ v8::HandleScope handles(CcTest::isolate());
+ v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
+ v8::Context::Scope context_scope(context);
+
+ const char* context_data[][2] = {
+ {"", ""}, {"'use strict';", ""}, {nullptr, nullptr}};
+ const char* statement_data[] = {"a ?? b", "a ?? b ?? c",
+ "a ?? b ? c : d"
+ "a ?? b ?? c ? d : e",
+ nullptr};
+
+ static const ParserFlag flags[] = {kAllowHarmonyNullish};
+ RunParserSyncTest(context_data, statement_data, kSuccess, nullptr, 0, flags,
+ 1, nullptr, 0, false, true, true);
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+TEST(NullishNotContained) {
+ v8::HandleScope handles(CcTest::isolate());
+ v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
+ v8::Context::Scope context_scope(context);
+
+ const char* context_data[][2] = {
+ {"", ""}, {"'use strict';", ""}, {nullptr, nullptr}};
+ const char* statement_data[] = {"a || b ?? c", "a ?? b || c",
+ "a && b ?? c"
+ "a ?? b && c",
+ nullptr};
+
+ static const ParserFlag flags[] = {kAllowHarmonyNullish};
+ RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, flags, 1,
+ nullptr, 0, false, true, true);
+}
+
TEST(ErrorsEvalAndArguments) {
// Tests that both preparsing and parsing produce the right kind of errors for
// using "eval" and "arguments" as identifiers. Without the strict mode, it's
@@ -5542,7 +5635,10 @@ TEST(PrivateMethodsErrors) {
"async #['a']() { }",
"async *#['a]() { }",
- // TODO(joyee): check duplicate accessors
+ "get #a() {} get #a() {}",
+ "get #a() {} get #['a']() {}",
+ "set #a(val) {} set #a(val) {}",
+ "set #a(val) {} set #['a'](val) {}",
"#a\n#",
"#a() c",
@@ -5561,6 +5657,14 @@ TEST(PrivateMethodsErrors) {
"set #constructor(test) {}",
"#constructor() {}",
"get #constructor() {}",
+
+ "static async *#constructor() {}",
+ "static *#constructor() {}",
+ "static async #constructor() {}",
+ "static set #constructor(test) {}",
+ "static #constructor() {}",
+ "static get #constructor() {}",
+
nullptr
};
// clang-format on
@@ -5572,8 +5676,60 @@ TEST(PrivateMethodsErrors) {
private_methods, arraysize(private_methods));
}
+// Test that private members parse in class bodies nested in object literals
+TEST(PrivateMembersNestedInObjectLiteralsNoErrors) {
+ // clang-format off
+ const char* context_data[][2] = {{"({", "})"},
+ {"'use strict'; ({", "});"},
+ {nullptr, nullptr}};
+ const char* class_body_data[] = {
+ "a: class { #a = 1 }",
+ "a: class { #a = () => {} }",
+ "a: class { #a }",
+ "a: class { #a() { } }",
+ "a: class { get #a() { } }",
+ "a: class { set #a(foo) { } }",
+ "a: class { *#a() { } }",
+ "a: class { async #a() { } }",
+ "a: class { async *#a() { } }",
+ nullptr
+ };
+ // clang-format on
+
+ static const ParserFlag private_methods[] = {kAllowHarmonyPrivateMethods};
+ RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
+ private_methods, arraysize(private_methods));
+}
+
+// Test that private members parse in class bodies nested in classes
+TEST(PrivateMembersInNestedClassNoErrors) {
+ // clang-format off
+ const char* context_data[][2] = {{"(class {", "});"},
+ {"(class extends Base {", "});"},
+ {"class C {", "}"},
+ {"class C extends Base {", "}"},
+ {nullptr, nullptr}};
+ const char* class_body_data[] = {
+ "a = class { #a = 1 }",
+ "a = class { #a = () => {} }",
+ "a = class { #a }",
+ "a = class { #a() { } }",
+ "a = class { get #a() { } }",
+ "a = class { set #a(foo) { } }",
+ "a = class { *#a() { } }",
+ "a = class { async #a() { } }",
+ "a = class { async *#a() { } }",
+ nullptr
+ };
+ // clang-format on
+
+ static const ParserFlag private_methods[] = {kAllowHarmonyPrivateMethods};
+ RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
+ private_methods, arraysize(private_methods));
+}
+
// Test that private members do not parse outside class bodies
-TEST(PrivateMembersInNonClassNoErrors) {
+TEST(PrivateMembersInNonClassErrors) {
// clang-format off
const char* context_data[][2] = {{"", ""},
{"({", "})"},
@@ -5605,6 +5761,122 @@ TEST(PrivateMembersInNonClassNoErrors) {
private_methods, arraysize(private_methods));
}
+// Test that nested private members parse
+TEST(PrivateMembersNestedNoErrors) {
+ // clang-format off
+ const char* context_data[][2] = {{"(class { get #a() { ", "} });"},
+ {
+ "(class { set #a(val) {} get #a() { ",
+ "} });"
+ },
+ {"(class { set #a(val) {", "} });"},
+ {"(class { #a() { ", "} });"},
+ {nullptr, nullptr}};
+ const char* class_body_data[] = {
+ "class C { #a() {} }",
+ "class C { get #a() {} }",
+ "class C { get #a() {} set #a(val) {} }",
+ "class C { set #a(val) {} }",
+ nullptr
+ };
+ // clang-format on
+
+ static const ParserFlag private_methods[] = {kAllowHarmonyPrivateMethods};
+ RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
+ private_methods, arraysize(private_methods));
+}
+
+// Test that acessing undeclared private members result in early errors
+TEST(PrivateMembersEarlyErrors) {
+ // clang-format off
+ const char* context_data[][2] = {{"(class {", "});"},
+ {"(class extends Base {", "});"},
+ {"class C {", "}"},
+ {"class C extends Base {", "}"},
+ {nullptr, nullptr}};
+ const char* class_body_data[] = {
+ "set #b(val) { this.#a = val; }",
+ "get #b() { return this.#a; }",
+ "foo() { return this.#a; }",
+ "foo() { this.#a = 1; }",
+ nullptr
+ };
+ // clang-format on
+
+ RunParserSyncTest(context_data, class_body_data, kError);
+
+ static const ParserFlag private_methods[] = {kAllowHarmonyPrivateMethods};
+ RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
+ private_methods, arraysize(private_methods));
+}
+
+// Test that acessing wrong kind private members do not error early.
+// Instead these should be runtime errors.
+TEST(PrivateMembersWrongAccessNoEarlyErrors) {
+ // clang-format off
+ const char* context_data[][2] = {{"(class {", "});"},
+ {"(class extends Base {", "});"},
+ {"class C {", "}"},
+ {"class C extends Base {", "}"},
+ {nullptr, nullptr}};
+ const char* class_body_data[] = {
+ // Private setter only
+ "set #b(val) {} fn() { return this.#b; }",
+ "set #b(val) {} fn() { this.#b++; }",
+ // Nested private setter only
+ R"(get #b() {}
+ fn() {
+ return new class { set #b(val) {} fn() { this.#b++; } };
+ })",
+ R"(get #b() {}
+ fn() {
+ return new class { set #b(val) {} fn() { return this.#b; } };
+ })",
+
+ // Private getter only
+ "get #b() { } fn() { this.#b = 1; }",
+ "get #b() { } fn() { this.#b++; }",
+ "get #b() { } fn(obj) { ({ y: this.#b } = obj); }",
+ // Nested private getter only
+ R"(set #b(val) {}
+ fn() {
+ return new class { get #b() {} fn() { this.#b++; } };
+ })",
+ R"(set #b(val) {}
+ fn() {
+ return new class { get #b() {} fn() { this.#b = 1; } };
+ })",
+ R"(set #b(val) {}
+ fn() {
+ return new class { get #b() {} fn() { ({ y: this.#b } = obj); } };
+ })",
+
+ // Writing to private methods
+ "#b() { } fn() { this.#b = 1; }",
+ "#b() { } fn() { this.#b++; }",
+ "#b() {} fn(obj) { ({ y: this.#b } = obj); }",
+ // Writing to nested private methods
+ R"(#b() {}
+ fn() {
+ return new class { get #b() {} fn() { this.#b++; } };
+ })",
+ R"(#b() {}
+ fn() {
+ return new class { get #b() {} fn() { this.#b = 1; } };
+ })",
+ R"(#b() {}
+ fn() {
+ return new class { get #b() {} fn() { ({ y: this.#b } = obj); } };
+ })",
+ nullptr
+ };
+ // clang-format on
+
+ static const ParserFlag private_methods[] = {kAllowHarmonyPrivateMethods};
+ RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
+ private_methods, arraysize(private_methods));
+}
+
TEST(PrivateClassFieldsNoErrors) {
// clang-format off
// Tests proposed class fields syntax.
diff --git a/deps/v8/test/cctest/test-pointer-auth-arm64.cc b/deps/v8/test/cctest/test-pointer-auth-arm64.cc
new file mode 100644
index 0000000000..11632be808
--- /dev/null
+++ b/deps/v8/test/cctest/test-pointer-auth-arm64.cc
@@ -0,0 +1,76 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/codegen/arm64/decoder-arm64-inl.h"
+#include "src/execution/arm64/simulator-arm64.h"
+
+#include "test/cctest/cctest.h"
+
+namespace v8 {
+namespace internal {
+
+#ifdef USE_SIMULATOR
+TEST(compute_pac) {
+ Decoder<DispatchingDecoderVisitor>* decoder =
+ new Decoder<DispatchingDecoderVisitor>();
+ Simulator simulator(decoder);
+
+ uint64_t data1 = 0xfb623599da6e8127;
+ uint64_t data2 = 0x27979fadf7d53cb7;
+ uint64_t context = 0x477d469dec0b8762;
+ Simulator::PACKey key = {0x84be85ce9804e94b, 0xec2802d4e0a488e9, -1};
+
+ uint64_t pac1 = simulator.ComputePAC(data1, context, key);
+ uint64_t pac2 = simulator.ComputePAC(data2, context, key);
+
+ // NOTE: If the PAC implementation is changed, this may fail due to a hash
+ // collision.
+ CHECK_NE(pac1, pac2);
+}
+
+TEST(add_and_auth_pac) {
+ Decoder<DispatchingDecoderVisitor>* decoder =
+ new Decoder<DispatchingDecoderVisitor>();
+ Simulator simulator(decoder);
+
+ uint64_t ptr = 0x0000000012345678;
+ uint64_t context = 0x477d469dec0b8762;
+ Simulator::PACKey key_a = {0x84be85ce9804e94b, 0xec2802d4e0a488e9, 0};
+ Simulator::PACKey key_b = {0xec1119e288704d13, 0xd7f6b76e1cea585e, 1};
+
+ uint64_t ptr_a =
+ simulator.AddPAC(ptr, context, key_a, Simulator::kInstructionPointer);
+
+ // Attempt to authenticate the pointer with PAC using different keys.
+ uint64_t success =
+ simulator.AuthPAC(ptr_a, context, key_a, Simulator::kInstructionPointer);
+ uint64_t fail =
+ simulator.AuthPAC(ptr_a, context, key_b, Simulator::kInstructionPointer);
+
+ uint64_t pac_mask =
+ simulator.CalculatePACMask(ptr, Simulator::kInstructionPointer, 0);
+
+ // NOTE: If the PAC implementation is changed, this may fail due to a hash
+ // collision.
+ CHECK_NE((ptr_a & pac_mask), 0);
+ CHECK_EQ(success, ptr);
+ CHECK_NE(fail, ptr);
+}
+
+TEST(add_and_strip_pac) {
+ Decoder<DispatchingDecoderVisitor>* decoder =
+ new Decoder<DispatchingDecoderVisitor>();
+ Simulator simulator(decoder);
+
+ uint64_t ptr = 0xff00000012345678;
+ uint64_t pac_mask =
+ simulator.CalculatePACMask(ptr, Simulator::kInstructionPointer, 0);
+ uint64_t ptr_a = ptr | pac_mask;
+
+ CHECK_EQ(simulator.StripPAC(ptr_a, Simulator::kInstructionPointer), ptr);
+}
+#endif // USE_SIMULATOR
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/cctest/test-poison-disasm-arm.cc b/deps/v8/test/cctest/test-poison-disasm-arm.cc
index 37bb4e1b39..3410e5487d 100644
--- a/deps/v8/test/cctest/test-poison-disasm-arm.cc
+++ b/deps/v8/test/cctest/test-poison-disasm-arm.cc
@@ -71,7 +71,6 @@ TEST(DisasmPoisonPolymorphicLoad) {
"let o2 = { y : 1 };"
"o2.x = 2;"
"%PrepareFunctionForOptimization(poly);"
- "poly(o1);"
"poly(o2);"
"poly(o1);"
"poly(o2);"
diff --git a/deps/v8/test/cctest/test-poison-disasm-arm64.cc b/deps/v8/test/cctest/test-poison-disasm-arm64.cc
index d767fea9fb..a428ce7b89 100644
--- a/deps/v8/test/cctest/test-poison-disasm-arm64.cc
+++ b/deps/v8/test/cctest/test-poison-disasm-arm64.cc
@@ -84,7 +84,6 @@ TEST(DisasmPoisonPolymorphicLoad) {
"let o2 = { y : 1 };"
"o2.x = 2;"
"%PrepareFunctionForOptimization(poly);"
- "poly(o1);"
"poly(o2);"
"poly(o1);"
"poly(o2);"
@@ -115,7 +114,7 @@ TEST(DisasmPoisonPolymorphicLoad) {
"csel " + kPReg + ", xzr, " + kPReg + ", ne", // update the poison
"csdb", // spec. barrier
"ldursw x<<BSt:[0-9]+>>, \\[<<Obj>>, #[0-9]+\\]", // load backing store
- "tbz w<<BSt>>, #0, #\\+0x8", // branchful decompress
+ // branchful decompress
"add x<<BSt>>, x26, x<<BSt>>", // Add root to ref
"and x<<BSt>>, x<<BSt>>, " + kPReg, // apply the poison
"ldur w<<Prop:[0-9]+>>, \\[x<<BSt>>, #[0-9]+\\]", // load the property
diff --git a/deps/v8/test/cctest/test-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc
index 051affc898..ccebabec30 100644
--- a/deps/v8/test/cctest/test-profile-generator.cc
+++ b/deps/v8/test/cctest/test-profile-generator.cc
@@ -200,7 +200,9 @@ TEST(ProfileTreeAddPathFromEndWithLineNumbers) {
ProfileTree tree(CcTest::i_isolate());
ProfileTreeTestHelper helper(&tree);
- ProfileStackTrace path = {{&c, 5}, {&b, 3}, {&a, 1}};
+ ProfileStackTrace path = {{{&c, 5}, kNullAddress, false},
+ {{&b, 3}, kNullAddress, false},
+ {{&a, 1}, kNullAddress, false}};
tree.AddPathFromEnd(path, v8::CpuProfileNode::kNoLineNumberInfo, true,
v8::CpuProfilingMode::kCallerLineNumbers);
@@ -381,7 +383,8 @@ TEST(RecordTickSample) {
CpuProfiler profiler(isolate);
profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling("");
- ProfileGenerator generator(&profiles);
+ CodeMap code_map;
+ ProfileGenerator generator(&profiles, &code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc");
@@ -449,7 +452,8 @@ TEST(SampleIds) {
CpuProfiler profiler(isolate);
profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers});
- ProfileGenerator generator(&profiles);
+ CodeMap code_map;
+ ProfileGenerator generator(&profiles, &code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc");
@@ -503,7 +507,8 @@ TEST(NoSamples) {
CpuProfiler profiler(isolate);
profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling("");
- ProfileGenerator generator(&profiles);
+ CodeMap code_map;
+ ProfileGenerator generator(&profiles, &code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc
index 1dad8febda..1374673c61 100644
--- a/deps/v8/test/cctest/test-regexp.cc
+++ b/deps/v8/test/cctest/test-regexp.cc
@@ -35,6 +35,7 @@
#include "src/codegen/assembler-arch.h"
#include "src/codegen/macro-assembler.h"
#include "src/init/v8.h"
+#include "src/objects/js-regexp-inl.h"
#include "src/objects/objects-inl.h"
#include "src/regexp/regexp-bytecode-generator.h"
#include "src/regexp/regexp-compiler.h"
@@ -535,6 +536,7 @@ static RegExpNode* Compile(const char* input, bool multiline, bool unicode,
Isolate* isolate = CcTest::i_isolate();
FlatStringReader reader(isolate, CStrVector(input));
RegExpCompileData compile_data;
+ compile_data.compilation_target = RegExpCompilationTarget::kNative;
JSRegExp::Flags flags = JSRegExp::kNone;
if (multiline) flags = JSRegExp::kMultiline;
if (unicode) flags = JSRegExp::kUnicode;
@@ -629,16 +631,35 @@ class ContextInitializer {
v8::Local<v8::Context> env_;
};
-static ArchRegExpMacroAssembler::Result Execute(Code code, String input,
+// Create new JSRegExp object with only necessary fields (for this tests)
+// initialized.
+static Handle<JSRegExp> CreateJSRegExp(Handle<String> source, Handle<Code> code,
+ bool is_unicode = false) {
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+ Handle<JSFunction> constructor = isolate->regexp_function();
+ Handle<JSRegExp> regexp =
+ Handle<JSRegExp>::cast(factory->NewJSObject(constructor));
+
+ factory->SetRegExpIrregexpData(regexp, JSRegExp::IRREGEXP, source,
+ JSRegExp::kNone, 0);
+ regexp->SetDataAt(is_unicode ? JSRegExp::kIrregexpUC16CodeIndex
+ : JSRegExp::kIrregexpLatin1CodeIndex,
+ *code);
+
+ return regexp;
+}
+
+static ArchRegExpMacroAssembler::Result Execute(JSRegExp regexp, String input,
int start_offset,
Address input_start,
Address input_end,
int* captures) {
return static_cast<NativeRegExpMacroAssembler::Result>(
- NativeRegExpMacroAssembler::Execute(code, input, start_offset,
- reinterpret_cast<byte*>(input_start),
- reinterpret_cast<byte*>(input_end),
- captures, 0, CcTest::i_isolate()));
+ NativeRegExpMacroAssembler::Execute(
+ input, start_offset, reinterpret_cast<byte*>(input_start),
+ reinterpret_cast<byte*>(input_end), captures, 0, CcTest::i_isolate(),
+ regexp));
}
TEST(MacroAssemblerNativeSuccess) {
@@ -656,19 +677,15 @@ TEST(MacroAssemblerNativeSuccess) {
Handle<String> source = factory->NewStringFromStaticChars("");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
int captures[4] = {42, 37, 87, 117};
Handle<String> input = factory->NewStringFromStaticChars("foofoo");
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
- NativeRegExpMacroAssembler::Result result =
- Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + seq_input->length(),
- captures);
+ NativeRegExpMacroAssembler::Result result = Execute(
+ *regexp, *input, 0, start_adr, start_adr + seq_input->length(), captures);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(-1, captures[0]);
@@ -710,19 +727,15 @@ TEST(MacroAssemblerNativeSimple) {
Handle<String> source = factory->NewStringFromStaticChars("^foo");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
int captures[4] = {42, 37, 87, 117};
Handle<String> input = factory->NewStringFromStaticChars("foofoo");
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
- NativeRegExpMacroAssembler::Result result =
- Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length(),
- captures);
+ NativeRegExpMacroAssembler::Result result = Execute(
+ *regexp, *input, 0, start_adr, start_adr + input->length(), captures);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, captures[0]);
@@ -734,11 +747,7 @@ TEST(MacroAssemblerNativeSimple) {
seq_input = Handle<SeqOneByteString>::cast(input);
start_adr = seq_input->GetCharsAddress();
- result = Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length(),
+ result = Execute(*regexp, *input, 0, start_adr, start_adr + input->length(),
captures);
CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
@@ -777,6 +786,7 @@ TEST(MacroAssemblerNativeSimpleUC16) {
Handle<String> source = factory->NewStringFromStaticChars("^foo");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code, true);
int captures[4] = {42, 37, 87, 117};
const uc16 input_data[6] = {'f', 'o', 'o', 'f', 'o',
@@ -786,13 +796,8 @@ TEST(MacroAssemblerNativeSimpleUC16) {
Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
- NativeRegExpMacroAssembler::Result result =
- Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length(),
- captures);
+ NativeRegExpMacroAssembler::Result result = Execute(
+ *regexp, *input, 0, start_adr, start_adr + input->length(), captures);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, captures[0]);
@@ -807,12 +812,8 @@ TEST(MacroAssemblerNativeSimpleUC16) {
seq_input = Handle<SeqTwoByteString>::cast(input);
start_adr = seq_input->GetCharsAddress();
- result = Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length() * 2,
- captures);
+ result = Execute(*regexp, *input, 0, start_adr,
+ start_adr + input->length() * 2, captures);
CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
}
@@ -842,13 +843,14 @@ TEST(MacroAssemblerNativeBacktrack) {
Handle<String> source = factory->NewStringFromStaticChars("..........");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
Handle<String> input = factory->NewStringFromStaticChars("foofoo");
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
NativeRegExpMacroAssembler::Result result = Execute(
- *code, *input, 0, start_adr, start_adr + input->length(), nullptr);
+ *regexp, *input, 0, start_adr, start_adr + input->length(), nullptr);
CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
}
@@ -882,19 +884,15 @@ TEST(MacroAssemblerNativeBackReferenceLATIN1) {
Handle<String> source = factory->NewStringFromStaticChars("^(..)..\1");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
Handle<String> input = factory->NewStringFromStaticChars("fooofo");
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
int output[4];
- NativeRegExpMacroAssembler::Result result =
- Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length(),
- output);
+ NativeRegExpMacroAssembler::Result result = Execute(
+ *regexp, *input, 0, start_adr, start_adr + input->length(), output);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]);
@@ -932,6 +930,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
Handle<String> source = factory->NewStringFromStaticChars("^(..)..\1");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code, true);
const uc16 input_data[6] = {'f', 0x2028, 'o', 'o', 'f', 0x2028};
Handle<String> input = factory->NewStringFromTwoByte(
@@ -940,13 +939,8 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
Address start_adr = seq_input->GetCharsAddress();
int output[4];
- NativeRegExpMacroAssembler::Result result =
- Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length() * 2,
- output);
+ NativeRegExpMacroAssembler::Result result = Execute(
+ *regexp, *input, 0, start_adr, start_adr + input->length() * 2, output);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]);
@@ -991,18 +985,19 @@ TEST(MacroAssemblernativeAtStart) {
Handle<String> source = factory->NewStringFromStaticChars("(^f|ob)");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
Handle<String> input = factory->NewStringFromStaticChars("foobar");
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
NativeRegExpMacroAssembler::Result result = Execute(
- *code, *input, 0, start_adr, start_adr + input->length(), nullptr);
+ *regexp, *input, 0, start_adr, start_adr + input->length(), nullptr);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
- result = Execute(*code, *input, 3, start_adr + 3, start_adr + input->length(),
- nullptr);
+ result = Execute(*regexp, *input, 3, start_adr + 3,
+ start_adr + input->length(), nullptr);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
}
@@ -1044,19 +1039,15 @@ TEST(MacroAssemblerNativeBackRefNoCase) {
factory->NewStringFromStaticChars("^(abc)\1\1(?!\1)...(?!\1)");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
Handle<String> input = factory->NewStringFromStaticChars("aBcAbCABCxYzab");
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
int output[4];
- NativeRegExpMacroAssembler::Result result =
- Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length(),
- output);
+ NativeRegExpMacroAssembler::Result result = Execute(
+ *regexp, *input, 0, start_adr, start_adr + input->length(), output);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]);
@@ -1144,6 +1135,7 @@ TEST(MacroAssemblerNativeRegisters) {
Handle<String> source = factory->NewStringFromStaticChars("<loop test>");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
// String long enough for test (content doesn't matter).
Handle<String> input = factory->NewStringFromStaticChars("foofoofoofoofoo");
@@ -1151,13 +1143,8 @@ TEST(MacroAssemblerNativeRegisters) {
Address start_adr = seq_input->GetCharsAddress();
int output[6];
- NativeRegExpMacroAssembler::Result result =
- Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length(),
- output);
+ NativeRegExpMacroAssembler::Result result = Execute(
+ *regexp, *input, 0, start_adr, start_adr + input->length(), output);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]);
@@ -1188,6 +1175,7 @@ TEST(MacroAssemblerStackOverflow) {
factory->NewStringFromStaticChars("<stack overflow test>");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
// String long enough for test (content doesn't matter).
Handle<String> input = factory->NewStringFromStaticChars("dummy");
@@ -1195,7 +1183,7 @@ TEST(MacroAssemblerStackOverflow) {
Address start_adr = seq_input->GetCharsAddress();
NativeRegExpMacroAssembler::Result result = Execute(
- *code, *input, 0, start_adr, start_adr + input->length(), nullptr);
+ *regexp, *input, 0, start_adr, start_adr + input->length(), nullptr);
CHECK_EQ(NativeRegExpMacroAssembler::EXCEPTION, result);
CHECK(isolate->has_pending_exception());
@@ -1230,6 +1218,7 @@ TEST(MacroAssemblerNativeLotsOfRegisters) {
factory->NewStringFromStaticChars("<huge register space test>");
Handle<Object> code_object = m.GetCode(source);
Handle<Code> code = Handle<Code>::cast(code_object);
+ Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
// String long enough for test (content doesn't matter).
Handle<String> input = factory->NewStringFromStaticChars("sample text");
@@ -1237,13 +1226,8 @@ TEST(MacroAssemblerNativeLotsOfRegisters) {
Address start_adr = seq_input->GetCharsAddress();
int captures[2];
- NativeRegExpMacroAssembler::Result result =
- Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length(),
- captures);
+ NativeRegExpMacroAssembler::Result result = Execute(
+ *regexp, *input, 0, start_adr, start_adr + input->length(), captures);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, captures[0]);
@@ -1298,7 +1282,9 @@ TEST(MacroAssembler) {
Handle<String> f1_16 = factory->NewStringFromTwoByte(
Vector<const uc16>(str1, 6)).ToHandleChecked();
- CHECK(IrregexpInterpreter::Match(isolate, array, f1_16, captures, 0));
+ CHECK(IrregexpInterpreter::MatchInternal(isolate, *array, *f1_16, captures, 5,
+ 0,
+ RegExp::CallOrigin::kFromRuntime));
CHECK_EQ(0, captures[0]);
CHECK_EQ(3, captures[1]);
CHECK_EQ(1, captures[2]);
@@ -1309,7 +1295,9 @@ TEST(MacroAssembler) {
Handle<String> f2_16 = factory->NewStringFromTwoByte(
Vector<const uc16>(str2, 6)).ToHandleChecked();
- CHECK(!IrregexpInterpreter::Match(isolate, array, f2_16, captures, 0));
+ CHECK(!IrregexpInterpreter::MatchInternal(isolate, *array, *f2_16, captures,
+ 5, 0,
+ RegExp::CallOrigin::kFromRuntime));
CHECK_EQ(42, captures[0]);
}
@@ -1692,8 +1680,7 @@ void MockUseCounterCallback(v8::Isolate* isolate,
}
}
-
-// Test that ES2015 RegExp compatibility fixes are in place, that they
+// Test that ES2015+ RegExp compatibility fixes are in place, that they
// are not overly broad, and the appropriate UseCounters are incremented
TEST(UseCountRegExp) {
v8::Isolate* isolate = CcTest::isolate();
@@ -1715,7 +1702,7 @@ TEST(UseCountRegExp) {
CHECK_EQ(0, use_counts[v8::Isolate::kRegExpPrototypeToString]);
CHECK(resultReSticky->IsFalse());
- // When the getter is caleld on another object, throw an exception
+ // When the getter is called on another object, throw an exception
// and don't increment the UseCounter
v8::Local<v8::Value> resultStickyError = CompileRun(
"var exception;"
@@ -1757,6 +1744,19 @@ TEST(UseCountRegExp) {
CHECK_EQ(2, use_counts[v8::Isolate::kRegExpPrototypeStickyGetter]);
CHECK_EQ(1, use_counts[v8::Isolate::kRegExpPrototypeToString]);
CHECK(resultToStringError->IsObject());
+
+ // Increment a UseCounter when .matchAll() is used with a non-global
+ // regular expression.
+ CHECK_EQ(0, use_counts[v8::Isolate::kRegExpMatchAllWithNonGlobalRegExp]);
+ v8::Local<v8::Value> resultReMatchAllNonGlobal =
+ CompileRun("'a'.matchAll(/./)");
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpMatchAllWithNonGlobalRegExp]);
+ CHECK(resultReMatchAllNonGlobal->IsObject());
+ // Don't increment the counter for global regular expressions.
+ v8::Local<v8::Value> resultReMatchAllGlobal =
+ CompileRun("'a'.matchAll(/./g)");
+ CHECK_EQ(1, use_counts[v8::Isolate::kRegExpMatchAllWithNonGlobalRegExp]);
+ CHECK(resultReMatchAllGlobal->IsObject());
}
class UncachedExternalString
diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc
index 1ed1547b34..407437c4b1 100644
--- a/deps/v8/test/cctest/test-serialize.cc
+++ b/deps/v8/test/cctest/test-serialize.cc
@@ -1516,6 +1516,50 @@ static Handle<SharedFunctionInfo> CompileScriptAndProduceCache(
return sfi;
}
+TEST(CodeSerializerWithProfiler) {
+ FLAG_enable_lazy_source_positions = true;
+ FLAG_stress_lazy_source_positions = false;
+
+ LocalContext context;
+ Isolate* isolate = CcTest::i_isolate();
+ isolate->compilation_cache()->Disable(); // Disable same-isolate code cache.
+
+ v8::HandleScope scope(CcTest::isolate());
+
+ const char* source = "1 + 1";
+
+ Handle<String> orig_source = isolate->factory()
+ ->NewStringFromUtf8(CStrVector(source))
+ .ToHandleChecked();
+ Handle<String> copy_source = isolate->factory()
+ ->NewStringFromUtf8(CStrVector(source))
+ .ToHandleChecked();
+ CHECK(!orig_source.is_identical_to(copy_source));
+ CHECK(orig_source->Equals(*copy_source));
+
+ ScriptData* cache = nullptr;
+
+ Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
+ isolate, orig_source, Handle<String>(), &cache,
+ v8::ScriptCompiler::kNoCompileOptions);
+
+ CHECK(!orig->GetBytecodeArray().HasSourcePositionTable());
+
+ isolate->set_is_profiling(true);
+
+ // This does not assert that no compilation can happen as source position
+ // collection could trigger it.
+ Handle<SharedFunctionInfo> copy =
+ CompileScript(isolate, copy_source, Handle<String>(), cache,
+ v8::ScriptCompiler::kConsumeCodeCache);
+
+ // Since the profiler is now enabled, source positions should be collected
+ // after deserialization.
+ CHECK(copy->GetBytecodeArray().HasSourcePositionTable());
+
+ delete cache;
+}
+
void TestCodeSerializerOnePlusOneImpl(bool verify_builtins_count = true) {
LocalContext context;
Isolate* isolate = CcTest::i_isolate();
@@ -3565,6 +3609,7 @@ UNINITIALIZED_TEST(SnapshotCreatorIncludeGlobalProxy) {
base::make_unique<v8::Extension>("new extension",
"function i() { return 24; }"
"function j() { return 25; }"
+ "let a = 26;"
"try {"
" if (o.p == 7) o.p++;"
"} catch {}");
@@ -3582,6 +3627,7 @@ UNINITIALIZED_TEST(SnapshotCreatorIncludeGlobalProxy) {
ExpectInt32("i()", 24);
ExpectInt32("j()", 25);
ExpectInt32("o.p", 8);
+ ExpectInt32("a", 26);
v8::TryCatch try_catch(isolate);
CHECK(CompileRun("x").IsEmpty());
CHECK(try_catch.HasCaught());
diff --git a/deps/v8/test/cctest/test-stack-unwinding-x64.cc b/deps/v8/test/cctest/test-stack-unwinding-win64.cc
index 583e14111a..84f1318a29 100644
--- a/deps/v8/test/cctest/test-stack-unwinding-x64.cc
+++ b/deps/v8/test/cctest/test-stack-unwinding-win64.cc
@@ -6,9 +6,15 @@
#include "src/init/v8.h"
#include "test/cctest/cctest.h"
-class UnwindingWinX64Callbacks {
+#if defined(V8_OS_WIN_X64)
+#define CONTEXT_PC(context) (context.Rip)
+#elif defined(V8_OS_WIN_ARM64)
+#define CONTEXT_PC(context) (context.Pc)
+#endif
+
+class UnwindingWin64Callbacks {
public:
- UnwindingWinX64Callbacks() = default;
+ UnwindingWin64Callbacks() = default;
static void Getter(v8::Local<v8::String> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
@@ -31,25 +37,26 @@ class UnwindingWinX64Callbacks {
int iframe = 0;
while (++iframe < max_frames) {
uint64_t image_base;
- PRUNTIME_FUNCTION function_entry =
- ::RtlLookupFunctionEntry(context_record.Rip, &image_base, nullptr);
+ PRUNTIME_FUNCTION function_entry = ::RtlLookupFunctionEntry(
+ CONTEXT_PC(context_record), &image_base, nullptr);
if (!function_entry) break;
void* handler_data;
uint64_t establisher_frame;
- ::RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, context_record.Rip,
- function_entry, &context_record, &handler_data,
- &establisher_frame, NULL);
+ ::RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base,
+ CONTEXT_PC(context_record), function_entry,
+ &context_record, &handler_data, &establisher_frame,
+ NULL);
}
return iframe;
}
};
-// Verifies that stack unwinding data has been correctly registered on Win/x64.
-UNINITIALIZED_TEST(StackUnwindingWinX64) {
+// Verifies that stack unwinding data has been correctly registered on Win64.
+UNINITIALIZED_TEST(StackUnwindingWin64) {
#ifdef V8_WIN64_UNWINDING_INFO
- static const char* unwinding_win_x64_test_source =
+ static const char* unwinding_win64_test_source =
"function start(count) {\n"
" for (var i = 0; i < count; i++) {\n"
" var o = instance.foo;\n"
@@ -79,18 +86,18 @@ UNINITIALIZED_TEST(StackUnwindingWinX64) {
v8::Local<v8::ObjectTemplate> instance_template =
func_template->InstanceTemplate();
- UnwindingWinX64Callbacks accessors;
+ UnwindingWin64Callbacks accessors;
v8::Local<v8::External> data = v8::External::New(isolate, &accessors);
instance_template->SetAccessor(v8_str("foo"),
- &UnwindingWinX64Callbacks::Getter,
- &UnwindingWinX64Callbacks::Setter, data);
+ &UnwindingWin64Callbacks::Getter,
+ &UnwindingWin64Callbacks::Setter, data);
v8::Local<v8::Function> func =
func_template->GetFunction(env.local()).ToLocalChecked();
v8::Local<v8::Object> instance =
func->NewInstance(env.local()).ToLocalChecked();
env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
- CompileRun(unwinding_win_x64_test_source);
+ CompileRun(unwinding_win64_test_source);
v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
env->Global()->Get(env.local(), v8_str("start")).ToLocalChecked());
@@ -106,3 +113,5 @@ UNINITIALIZED_TEST(StackUnwindingWinX64) {
#endif // V8_WIN64_UNWINDING_INFO
}
+
+#undef CONTEXT_PC
diff --git a/deps/v8/test/cctest/test-sync-primitives-arm.cc b/deps/v8/test/cctest/test-sync-primitives-arm.cc
index 84dc0575cf..6afa9e5192 100644
--- a/deps/v8/test/cctest/test-sync-primitives-arm.cc
+++ b/deps/v8/test/cctest/test-sync-primitives-arm.cc
@@ -352,7 +352,7 @@ TEST(simulator_invalidate_exclusive_access_threaded) {
TestData test_data(1);
MemoryAccessThread thread;
- thread.Start();
+ CHECK(thread.Start());
MemoryAccess ldrex_w(Kind::LoadExcl, Size::Word, offsetof(TestData, w));
MemoryAccess strex_w(Kind::StoreExcl, Size::Word, offsetof(TestData, w), 7);
diff --git a/deps/v8/test/cctest/test-sync-primitives-arm64.cc b/deps/v8/test/cctest/test-sync-primitives-arm64.cc
index 38adf8486a..f5f19f0687 100644
--- a/deps/v8/test/cctest/test-sync-primitives-arm64.cc
+++ b/deps/v8/test/cctest/test-sync-primitives-arm64.cc
@@ -359,7 +359,7 @@ TEST(simulator_invalidate_exclusive_access_threaded) {
TestData test_data(1);
MemoryAccessThread thread;
- thread.Start();
+ CHECK(thread.Start());
MemoryAccess ldaxr_w(Kind::LoadExcl, Size::Word, offsetof(TestData, w));
MemoryAccess stlxr_w(Kind::StoreExcl, Size::Word, offsetof(TestData, w), 7);
diff --git a/deps/v8/test/cctest/test-thread-termination.cc b/deps/v8/test/cctest/test-thread-termination.cc
index ca9ac5efaa..db9b5c928a 100644
--- a/deps/v8/test/cctest/test-thread-termination.cc
+++ b/deps/v8/test/cctest/test-thread-termination.cc
@@ -179,7 +179,7 @@ class TerminatorThread : public v8::base::Thread {
void TestTerminatingSlowOperation(const char* source) {
semaphore = new v8::base::Semaphore(0);
TerminatorThread thread(CcTest::i_isolate());
- thread.Start();
+ CHECK(thread.Start());
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::ObjectTemplate> global =
@@ -474,7 +474,7 @@ void MicrotaskLoopForever(const v8::FunctionCallbackInfo<v8::Value>& info) {
TEST(TerminateFromOtherThreadWhileMicrotaskRunning) {
semaphore = new v8::base::Semaphore(0);
TerminatorThread thread(CcTest::i_isolate());
- thread.Start();
+ CHECK(thread.Start());
v8::Isolate* isolate = CcTest::isolate();
isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
@@ -878,7 +878,7 @@ TEST(TerminateRegExp) {
CHECK(!isolate->IsExecutionTerminating());
CHECK(!CompileRun("var re = /(x+)+y$/; re.test('x');").IsEmpty());
TerminatorSleeperThread terminator(isolate, 100);
- terminator.Start();
+ CHECK(terminator.Start());
CHECK(CompileRun("re.test('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); fail();")
.IsEmpty());
CHECK(try_catch.HasCaught());
diff --git a/deps/v8/test/cctest/test-threads.cc b/deps/v8/test/cctest/test-threads.cc
index be76f5e93f..2062724043 100644
--- a/deps/v8/test/cctest/test-threads.cc
+++ b/deps/v8/test/cctest/test-threads.cc
@@ -54,7 +54,7 @@ class ThreadIdValidationThread : public base::Thread {
}
refs_[thread_no_].store(thread_id, std::memory_order_relaxed);
if (thread_to_start_ != nullptr) {
- thread_to_start_->Start();
+ CHECK(thread_to_start_->Start());
}
semaphore_->Signal();
}
@@ -77,7 +77,7 @@ TEST(ThreadIdValidation) {
threads[i] =
base::make_unique<ThreadIdValidationThread>(prev, refs, i, &semaphore);
}
- threads[0]->Start();
+ CHECK(threads[0]->Start());
for (int i = 0; i < kNThreads; i++) {
semaphore.Wait();
}
diff --git a/deps/v8/test/cctest/test-unboxed-doubles.cc b/deps/v8/test/cctest/test-unboxed-doubles.cc
index 78ec000d65..9cfc40d37d 100644
--- a/deps/v8/test/cctest/test-unboxed-doubles.cc
+++ b/deps/v8/test/cctest/test-unboxed-doubles.cc
@@ -73,8 +73,8 @@ static double GetDoubleFieldValue(JSObject obj, FieldIndex field_index) {
return obj.RawFastDoublePropertyAt(field_index);
} else {
Object value = obj.RawFastPropertyAt(field_index);
- CHECK(value.IsMutableHeapNumber());
- return MutableHeapNumber::cast(value).value();
+ CHECK(value.IsHeapNumber());
+ return HeapNumber::cast(value).value();
}
}
@@ -1120,7 +1120,7 @@ TEST(DoScavenge) {
double boom_value = bit_cast<double>(fake_object);
FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
- auto boom_number = factory->NewMutableHeapNumber(boom_value);
+ auto boom_number = factory->NewHeapNumber(boom_value);
obj->FastPropertyAtPut(field_index, *boom_number);
// Now |obj| moves to old gen and it has a double field that looks like
diff --git a/deps/v8/test/cctest/torque/test-torque.cc b/deps/v8/test/cctest/torque/test-torque.cc
index 8b67233963..184a867946 100644
--- a/deps/v8/test/cctest/torque/test-torque.cc
+++ b/deps/v8/test/cctest/torque/test-torque.cc
@@ -114,7 +114,7 @@ TEST(TestBuiltinSpecialization) {
CodeAssemblerTester asm_tester(isolate, 0);
TestTorqueAssembler m(asm_tester.state());
{
- Node* temp = m.SmiConstant(0);
+ TNode<Object> temp = m.SmiConstant(0);
m.TestBuiltinSpecialization(m.UncheckedCast<Context>(temp));
m.Return(m.UndefinedConstant());
}
@@ -171,7 +171,7 @@ TEST(TestFunctionPointerToGeneric) {
CodeAssemblerTester asm_tester(isolate, 0);
TestTorqueAssembler m(asm_tester.state());
{
- Node* temp = m.SmiConstant(0);
+ TNode<Object> temp = m.SmiConstant(0);
m.TestFunctionPointerToGeneric(m.UncheckedCast<Context>(temp));
m.Return(m.UndefinedConstant());
}
@@ -184,8 +184,8 @@ TEST(TestUnsafeCast) {
CodeAssemblerTester asm_tester(isolate, 0);
TestTorqueAssembler m(asm_tester.state());
{
- Node* temp = m.SmiConstant(0);
- Node* n = m.SmiConstant(10);
+ TNode<Object> temp = m.SmiConstant(0);
+ TNode<Smi> n = m.SmiConstant(10);
m.Return(m.TestUnsafeCast(m.UncheckedCast<Context>(temp),
m.UncheckedCast<Number>(n)));
}
@@ -328,7 +328,7 @@ TEST(TestCatch1) {
TNode<Smi> result =
m.TestCatch1(m.UncheckedCast<Context>(m.HeapConstant(context)));
USE(result);
- CSA_ASSERT(&m, m.WordEqual(result, m.SmiConstant(1)));
+ CSA_ASSERT(&m, m.TaggedEqual(result, m.SmiConstant(1)));
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
@@ -347,7 +347,7 @@ TEST(TestCatch2) {
TNode<Smi> result =
m.TestCatch2(m.UncheckedCast<Context>(m.HeapConstant(context)));
USE(result);
- CSA_ASSERT(&m, m.WordEqual(result, m.SmiConstant(2)));
+ CSA_ASSERT(&m, m.TaggedEqual(result, m.SmiConstant(2)));
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
@@ -366,7 +366,7 @@ TEST(TestCatch3) {
TNode<Smi> result =
m.TestCatch3(m.UncheckedCast<Context>(m.HeapConstant(context)));
USE(result);
- CSA_ASSERT(&m, m.WordEqual(result, m.SmiConstant(2)));
+ CSA_ASSERT(&m, m.TaggedEqual(result, m.SmiConstant(2)));
m.Return(m.UndefinedConstant());
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
@@ -484,6 +484,36 @@ TEST(TestReferences) {
ft.Call();
}
+TEST(TestSlices) {
+ CcTest::InitializeVM();
+ Isolate* isolate(CcTest::i_isolate());
+ i::HandleScope scope(isolate);
+ CodeAssemblerTester asm_tester(isolate);
+ TestTorqueAssembler m(asm_tester.state());
+ {
+ m.TestSlices();
+ m.Return(m.UndefinedConstant());
+ }
+ FunctionTester ft(asm_tester.GenerateCode(), 0);
+ ft.Call();
+}
+
+TEST(TestSliceEnumeration) {
+ CcTest::InitializeVM();
+ Isolate* isolate(CcTest::i_isolate());
+ i::HandleScope scope(isolate);
+ Handle<Context> context =
+ Utils::OpenHandle(*v8::Isolate::GetCurrent()->GetCurrentContext());
+ CodeAssemblerTester asm_tester(isolate);
+ TestTorqueAssembler m(asm_tester.state());
+ {
+ m.TestSliceEnumeration(m.UncheckedCast<Context>(m.HeapConstant(context)));
+ m.Return(m.UndefinedConstant());
+ }
+ FunctionTester ft(asm_tester.GenerateCode(), 0);
+ ft.Call();
+}
+
TEST(TestStaticAssert) {
CcTest::InitializeVM();
Isolate* isolate(CcTest::i_isolate());
@@ -580,11 +610,28 @@ TEST(TestGenericStruct2) {
i::HandleScope scope(isolate);
CodeAssemblerTester asm_tester(isolate);
TestTorqueAssembler m(asm_tester.state());
- { m.Return(m.TestGenericStruct2().fst); }
+ { m.Return(m.TestGenericStruct2().snd.fst); }
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.Call();
}
+TEST(TestBranchOnBoolOptimization) {
+ CcTest::InitializeVM();
+ Isolate* isolate(CcTest::i_isolate());
+ i::HandleScope scope(isolate);
+ Handle<Context> context =
+ Utils::OpenHandle(*v8::Isolate::GetCurrent()->GetCurrentContext());
+ CodeAssemblerTester asm_tester(isolate, 1);
+ TestTorqueAssembler m(asm_tester.state());
+ {
+ m.TestBranchOnBoolOptimization(
+ m.UncheckedCast<Context>(m.HeapConstant(context)),
+ m.UncheckedCast<Smi>(m.Parameter(0)));
+ m.Return(m.UndefinedConstant());
+ }
+ asm_tester.GenerateCode();
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/cctest/trace-extension.cc b/deps/v8/test/cctest/trace-extension.cc
index 08cc024c90..df24e83f39 100644
--- a/deps/v8/test/cctest/trace-extension.cc
+++ b/deps/v8/test/cctest/trace-extension.cc
@@ -30,6 +30,7 @@
#include "include/v8-profiler.h"
#include "src/execution/vm-state-inl.h"
#include "src/objects/smi.h"
+#include "src/profiler/tick-sample.h"
#include "test/cctest/cctest.h"
namespace v8 {
@@ -89,21 +90,20 @@ Address TraceExtension::GetFP(const v8::FunctionCallbackInfo<v8::Value>& args) {
return fp;
}
-static struct { v8::TickSample* sample; } trace_env = {nullptr};
+static struct { TickSample* sample; } trace_env = {nullptr};
-void TraceExtension::InitTraceEnv(v8::TickSample* sample) {
+void TraceExtension::InitTraceEnv(TickSample* sample) {
trace_env.sample = sample;
}
-
void TraceExtension::DoTrace(Address fp) {
RegisterState regs;
regs.fp = reinterpret_cast<void*>(fp);
// sp is only used to define stack high bound
regs.sp = reinterpret_cast<void*>(
reinterpret_cast<Address>(trace_env.sample) - 10240);
- trace_env.sample->Init(CcTest::isolate(), regs,
- v8::TickSample::kSkipCEntryFrame, true);
+ trace_env.sample->Init(CcTest::i_isolate(), regs,
+ TickSample::kSkipCEntryFrame, true);
}
diff --git a/deps/v8/test/cctest/trace-extension.h b/deps/v8/test/cctest/trace-extension.h
index fe62c006b7..78927f0fb6 100644
--- a/deps/v8/test/cctest/trace-extension.h
+++ b/deps/v8/test/cctest/trace-extension.h
@@ -32,9 +32,10 @@
#include "src/common/globals.h"
namespace v8 {
-struct TickSample;
namespace internal {
+struct TickSample;
+
class TraceExtension : public v8::Extension {
public:
TraceExtension() : v8::Extension("v8/trace", kSource) { }
@@ -45,7 +46,7 @@ class TraceExtension : public v8::Extension {
static void JSEntrySP(const v8::FunctionCallbackInfo<v8::Value>& args);
static void JSEntrySPLevel2(const v8::FunctionCallbackInfo<v8::Value>& args);
static Address GetJsEntrySp();
- static void InitTraceEnv(v8::TickSample* sample);
+ static void InitTraceEnv(TickSample* sample);
static void DoTrace(Address fp);
private:
static Address GetFP(const v8::FunctionCallbackInfo<v8::Value>& args);
diff --git a/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc b/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc
index dc02cfd14a..556d74daef 100644
--- a/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc
+++ b/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc
@@ -32,16 +32,18 @@ constexpr int kJumpTableSlotCount = 128;
constexpr uint32_t kJumpTableSize =
JumpTableAssembler::SizeForNumberOfSlots(kJumpTableSlotCount);
+constexpr size_t kThunkBufferSize = AssemblerBase::kMinimalBufferSize;
+
#if V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_X64
constexpr uint32_t kAvailableBufferSlots =
- (kMaxWasmCodeMemory - kJumpTableSize) / AssemblerBase::kMinimalBufferSize;
+ (kMaxWasmCodeMemory - kJumpTableSize) / kThunkBufferSize;
constexpr uint32_t kBufferSlotStartOffset =
- RoundUp<AssemblerBase::kMinimalBufferSize>(kJumpTableSize);
+ RoundUp<kThunkBufferSize>(kJumpTableSize);
#else
constexpr uint32_t kAvailableBufferSlots = 0;
#endif
-Address GenerateJumpTableThunk(
+Address AllocateJumpTableThunk(
Address jump_target, byte* thunk_slot_buffer,
std::bitset<kAvailableBufferSlots>* used_slots,
std::vector<std::unique_ptr<TestingAssemblerBuffer>>* thunk_buffers) {
@@ -62,20 +64,22 @@ Address GenerateJumpTableThunk(
buffer_index = rng->NextInt(kAvailableBufferSlots);
} while (used_slots->test(buffer_index));
used_slots->set(buffer_index);
- byte* buffer =
- thunk_slot_buffer + buffer_index * AssemblerBase::kMinimalBufferSize;
+ return reinterpret_cast<Address>(thunk_slot_buffer +
+ buffer_index * kThunkBufferSize);
#else
USE(thunk_slot_buffer);
USE(used_slots);
- thunk_buffers->emplace_back(AllocateAssemblerBuffer(
- AssemblerBase::kMinimalBufferSize, GetRandomMmapAddr()));
- byte* buffer = thunk_buffers->back()->start();
+ thunk_buffers->emplace_back(
+ AllocateAssemblerBuffer(kThunkBufferSize, GetRandomMmapAddr()));
+ return reinterpret_cast<Address>(thunk_buffers->back()->start());
#endif
+}
- MacroAssembler masm(
- nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
- ExternalAssemblerBuffer(buffer, AssemblerBase::kMinimalBufferSize));
+void CompileJumpTableThunk(Address thunk, Address jump_target) {
+ MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
+ ExternalAssemblerBuffer(reinterpret_cast<void*>(thunk),
+ kThunkBufferSize));
Label exit;
Register scratch = kReturnRegister0;
@@ -132,9 +136,9 @@ Address GenerateJumpTableThunk(
__ bind(&exit);
__ Ret();
- CodeDesc desc;
- masm.GetCode(nullptr, &desc);
- return reinterpret_cast<Address>(buffer);
+ FlushInstructionCache(thunk, kThunkBufferSize);
+ CHECK(SetPermissions(GetPlatformPageAllocator(), thunk, kThunkBufferSize,
+ v8::PageAllocator::kReadExecute));
}
class JumpTableRunner : public v8::base::Thread {
@@ -159,29 +163,38 @@ class JumpTableRunner : public v8::base::Thread {
class JumpTablePatcher : public v8::base::Thread {
public:
JumpTablePatcher(Address slot_start, uint32_t slot_index, Address thunk1,
- Address thunk2)
+ Address thunk2, base::Mutex* jump_table_mutex)
: Thread(Options("JumpTablePatcher")),
slot_start_(slot_start),
slot_index_(slot_index),
- thunks_{thunk1, thunk2} {}
+ thunks_{thunk1, thunk2},
+ jump_table_mutex_(jump_table_mutex) {}
void Run() override {
- TRACE("Patcher is starting ...\n");
+ TRACE("Patcher %p is starting ...\n", this);
+ Address slot_address =
+ slot_start_ + JumpTableAssembler::JumpSlotIndexToOffset(slot_index_);
+ // First, emit code to the two thunks.
+ for (Address thunk : thunks_) {
+ CompileJumpTableThunk(thunk, slot_address);
+ }
+ // Then, repeatedly patch the jump table to jump to one of the two thunks.
constexpr int kNumberOfPatchIterations = 64;
for (int i = 0; i < kNumberOfPatchIterations; ++i) {
- TRACE(" patch slot " V8PRIxPTR_FMT " to thunk #%d\n",
- slot_start_ + JumpTableAssembler::SlotIndexToOffset(slot_index_),
- i % 2);
+ TRACE(" patcher %p patch slot " V8PRIxPTR_FMT " to thunk #%d\n", this,
+ slot_address, i % 2);
+ base::MutexGuard jump_table_guard(jump_table_mutex_);
JumpTableAssembler::PatchJumpTableSlot(
slot_start_, slot_index_, thunks_[i % 2], WasmCode::kFlushICache);
}
- TRACE("Patcher is stopping ...\n");
+ TRACE("Patcher %p is stopping ...\n", this);
}
private:
Address slot_start_;
uint32_t slot_index_;
Address thunks_[2];
+ base::Mutex* jump_table_mutex_;
};
} // namespace
@@ -198,9 +211,10 @@ class JumpTablePatcher : public v8::base::Thread {
// one of the runners is currently executing the jump-table slot.
TEST(JumpTablePatchingStress) {
constexpr int kNumberOfRunnerThreads = 5;
+ constexpr int kNumberOfPatcherThreads = 3;
#if V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_X64
- // We need the branches (from GenerateJumpTableThunk) to be within near-call
+ // We need the branches (from CompileJumpTableThunk) to be within near-call
// range of the jump table slots. The address hint to AllocateAssemblerBuffer
// is not reliable enough to guarantee that we can always achieve this with
// separate allocations, so for Arm64 we generate all code in a single
@@ -226,29 +240,42 @@ TEST(JumpTablePatchingStress) {
TRACE("Hammering on jump table slot #%d ...\n", slot);
uint32_t slot_offset = JumpTableAssembler::JumpSlotIndexToOffset(slot);
std::vector<std::unique_ptr<TestingAssemblerBuffer>> thunk_buffers;
- Address thunk1 =
- GenerateJumpTableThunk(slot_start + slot_offset, thunk_slot_buffer,
- &used_thunk_slots, &thunk_buffers);
- Address thunk2 =
- GenerateJumpTableThunk(slot_start + slot_offset, thunk_slot_buffer,
- &used_thunk_slots, &thunk_buffers);
- TRACE(" generated thunk1: " V8PRIxPTR_FMT "\n", thunk1);
- TRACE(" generated thunk2: " V8PRIxPTR_FMT "\n", thunk2);
- JumpTableAssembler::PatchJumpTableSlot(slot_start, slot, thunk1,
- WasmCode::kFlushICache);
+ // Patch the jump table slot to jump to itself. This will later be patched
+ // by the patchers.
+ JumpTableAssembler::PatchJumpTableSlot(
+ slot_start, slot, slot_start + slot_offset, WasmCode::kFlushICache);
+ // For each patcher, generate two thunks where this patcher can emit code
+ // which finally jumps back to {slot} in the jump table.
+ std::vector<Address> patcher_thunks;
+ for (int i = 0; i < 2 * kNumberOfPatcherThreads; ++i) {
+ Address thunk =
+ AllocateJumpTableThunk(slot_start + slot_offset, thunk_slot_buffer,
+ &used_thunk_slots, &thunk_buffers);
+ ZapCode(thunk, kThunkBufferSize);
+ patcher_thunks.push_back(thunk);
+ TRACE(" generated jump thunk: " V8PRIxPTR_FMT "\n",
+ patcher_thunks.back());
+ }
- for (auto& buf : thunk_buffers) buf->MakeExecutable();
- // Start multiple runner threads and a patcher thread that hammer on the
- // same jump-table slot concurrently.
+ // Start multiple runner threads that execute the jump table slot
+ // concurrently.
std::list<JumpTableRunner> runners;
for (int runner = 0; runner < kNumberOfRunnerThreads; ++runner) {
runners.emplace_back(slot_start + slot_offset, runner);
}
- JumpTablePatcher patcher(slot_start, slot, thunk1, thunk2);
+ // Start multiple patcher thread that concurrently generate code and insert
+ // jumps to that into the jump table slot.
+ std::list<JumpTablePatcher> patchers;
+ // Only one patcher should modify the jump table at a time.
+ base::Mutex jump_table_mutex;
+ for (int i = 0; i < kNumberOfPatcherThreads; ++i) {
+ patchers.emplace_back(slot_start, slot, patcher_thunks[2 * i],
+ patcher_thunks[2 * i + 1], &jump_table_mutex);
+ }
global_stop_bit = 0; // Signal runners to keep going.
- for (auto& runner : runners) runner.Start();
- patcher.Start();
- patcher.Join();
+ for (auto& runner : runners) CHECK(runner.Start());
+ for (auto& patcher : patchers) CHECK(patcher.Start());
+ for (auto& patcher : patchers) patcher.Join();
global_stop_bit = -1; // Signal runners to stop.
for (auto& runner : runners) runner.Join();
}
diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-64.cc b/deps/v8/test/cctest/wasm/test-run-wasm-64.cc
index c8dd901161..3f96f8720f 100644
--- a/deps/v8/test/cctest/wasm/test-run-wasm-64.cc
+++ b/deps/v8/test/cctest/wasm/test-run-wasm-64.cc
@@ -618,7 +618,9 @@ WASM_EXEC_TEST(F32UConvertI64) {
{0x8000008000000000, 0x5F000000},
{0x8000008000000001, 0x5F000001},
{0x8000000000000400, 0x5F000000},
- {0x8000000000000401, 0x5F000000}};
+ {0x8000000000000401, 0x5F000000},
+ {0x20000020000001, 0x5a000001},
+ {0xFFFFFe8000000001, 0x5f7FFFFF}};
WasmRunner<float, uint64_t> r(execution_tier);
BUILD(r, WASM_F32_UCONVERT_I64(WASM_GET_LOCAL(0)));
for (size_t i = 0; i < arraysize(values); i++) {
diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-atomics.cc b/deps/v8/test/cctest/wasm/test-run-wasm-atomics.cc
index 60cda4adde..354ff436c0 100644
--- a/deps/v8/test/cctest/wasm/test-run-wasm-atomics.cc
+++ b/deps/v8/test/cctest/wasm/test-run-wasm-atomics.cc
@@ -317,6 +317,54 @@ WASM_EXEC_TEST(AtomicFence) {
CHECK_EQ(0, r.Call());
}
+WASM_EXEC_TEST(AtomicStoreNoConsideredEffectful) {
+ EXPERIMENTAL_FLAG_SCOPE(threads);
+ FLAG_wasm_trap_handler = false; // To use {Load} instead of {ProtectedLoad}.
+ WasmRunner<uint32_t> r(execution_tier);
+ r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
+ r.builder().SetHasSharedMemory();
+ BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_ZERO),
+ WASM_ATOMICS_STORE_OP(kExprI32AtomicStore, WASM_ZERO, WASM_I32V_1(20),
+ MachineRepresentation::kWord32),
+ kExprI64Eqz);
+ CHECK_EQ(1, r.Call());
+}
+
+void RunNoEffectTest(ExecutionTier execution_tier, WasmOpcode wasm_op) {
+ EXPERIMENTAL_FLAG_SCOPE(threads);
+ FLAG_wasm_trap_handler = false; // To use {Load} instead of {ProtectedLoad}.
+ WasmRunner<uint32_t> r(execution_tier);
+ r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
+ r.builder().SetHasSharedMemory();
+ BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_ZERO),
+ WASM_ATOMICS_BINOP(wasm_op, WASM_ZERO, WASM_I32V_1(20),
+ MachineRepresentation::kWord32),
+ WASM_DROP, kExprI64Eqz);
+ CHECK_EQ(1, r.Call());
+}
+
+WASM_EXEC_TEST(AtomicAddNoConsideredEffectful) {
+ RunNoEffectTest(execution_tier, kExprI32AtomicAdd);
+}
+
+WASM_EXEC_TEST(AtomicExchangeNoConsideredEffectful) {
+ RunNoEffectTest(execution_tier, kExprI32AtomicExchange);
+}
+
+WASM_EXEC_TEST(AtomicCompareExchangeNoConsideredEffectful) {
+ EXPERIMENTAL_FLAG_SCOPE(threads);
+ FLAG_wasm_trap_handler = false; // To use {Load} instead of {ProtectedLoad}.
+ WasmRunner<uint32_t> r(execution_tier);
+ r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
+ r.builder().SetHasSharedMemory();
+ BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO),
+ WASM_ATOMICS_TERNARY_OP(kExprI32AtomicCompareExchange, WASM_ZERO,
+ WASM_ZERO, WASM_I32V_1(30),
+ MachineRepresentation::kWord32),
+ WASM_DROP, kExprI32Eqz);
+ CHECK_EQ(1, r.Call());
+}
+
} // namespace test_run_wasm_atomics
} // namespace wasm
} // namespace internal
diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-atomics64.cc b/deps/v8/test/cctest/wasm/test-run-wasm-atomics64.cc
index 2d5d6a945c..748adc4a67 100644
--- a/deps/v8/test/cctest/wasm/test-run-wasm-atomics64.cc
+++ b/deps/v8/test/cctest/wasm/test-run-wasm-atomics64.cc
@@ -646,6 +646,54 @@ WASM_EXEC_TEST(I64AtomicCompareExchange32UFail) {
CHECK_EQ(initial, r.builder().ReadMemory(&memory[0]));
}
+WASM_EXEC_TEST(AtomicStoreNoConsideredEffectful) {
+ EXPERIMENTAL_FLAG_SCOPE(threads);
+ FLAG_wasm_trap_handler = false; // To use {Load} instead of {ProtectedLoad}.
+ WasmRunner<uint32_t> r(execution_tier);
+ r.builder().AddMemoryElems<int64_t>(kWasmPageSize / sizeof(int64_t));
+ r.builder().SetHasSharedMemory();
+ BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_ZERO),
+ WASM_ATOMICS_STORE_OP(kExprI64AtomicStore, WASM_ZERO, WASM_I64V(20),
+ MachineRepresentation::kWord64),
+ kExprI64Eqz);
+ CHECK_EQ(1, r.Call());
+}
+
+void RunNoEffectTest(ExecutionTier execution_tier, WasmOpcode wasm_op) {
+ EXPERIMENTAL_FLAG_SCOPE(threads);
+ FLAG_wasm_trap_handler = false; // To use {Load} instead of {ProtectedLoad}.
+ WasmRunner<uint32_t> r(execution_tier);
+ r.builder().AddMemoryElems<int64_t>(kWasmPageSize / sizeof(int64_t));
+ r.builder().SetHasSharedMemory();
+ BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_ZERO),
+ WASM_ATOMICS_BINOP(wasm_op, WASM_ZERO, WASM_I64V(20),
+ MachineRepresentation::kWord64),
+ WASM_DROP, kExprI64Eqz);
+ CHECK_EQ(1, r.Call());
+}
+
+WASM_EXEC_TEST(AtomicAddNoConsideredEffectful) {
+ RunNoEffectTest(execution_tier, kExprI64AtomicAdd);
+}
+
+WASM_EXEC_TEST(AtomicExchangeNoConsideredEffectful) {
+ RunNoEffectTest(execution_tier, kExprI64AtomicExchange);
+}
+
+WASM_EXEC_TEST(AtomicCompareExchangeNoConsideredEffectful) {
+ EXPERIMENTAL_FLAG_SCOPE(threads);
+ FLAG_wasm_trap_handler = false; // To use {Load} instead of {ProtectedLoad}.
+ WasmRunner<uint32_t> r(execution_tier);
+ r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
+ r.builder().SetHasSharedMemory();
+ BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_ZERO),
+ WASM_ATOMICS_TERNARY_OP(kExprI64AtomicCompareExchange, WASM_ZERO,
+ WASM_I64V(0), WASM_I64V(30),
+ MachineRepresentation::kWord64),
+ WASM_DROP, kExprI64Eqz);
+ CHECK_EQ(1, r.Call());
+}
+
} // namespace test_run_wasm_atomics_64
} // namespace wasm
} // namespace internal
diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-module.cc b/deps/v8/test/cctest/wasm/test-run-wasm-module.cc
index 526c5846a2..51d97650d4 100644
--- a/deps/v8/test/cctest/wasm/test-run-wasm-module.cc
+++ b/deps/v8/test/cctest/wasm/test-run-wasm-module.cc
@@ -583,7 +583,7 @@ TEST(TestInterruptLoop) {
int32_t* memory_array = reinterpret_cast<int32_t*>(memory->backing_store());
InterruptThread thread(isolate, memory_array);
- thread.Start();
+ CHECK(thread.Start());
testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
Address address = reinterpret_cast<Address>(
&memory_array[InterruptThread::interrupt_location_]);
@@ -910,6 +910,8 @@ TEST(EmptyMemoryEmptyDataSegment) {
TEST(MemoryWithOOBEmptyDataSegment) {
{
+ FlagScope<bool> no_bulk_memory(
+ &v8::internal::FLAG_experimental_wasm_bulk_memory, false);
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
testing::SetupIsolateForWasmModule(isolate);
diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-simd.cc b/deps/v8/test/cctest/wasm/test-run-wasm-simd.cc
index b1d95a12bb..b48321df40 100644
--- a/deps/v8/test/cctest/wasm/test-run-wasm-simd.cc
+++ b/deps/v8/test/cctest/wasm/test-run-wasm-simd.cc
@@ -20,6 +20,7 @@ namespace test_run_wasm_simd {
namespace {
using DoubleUnOp = double (*)(double);
+using DoubleBinOp = double (*)(double, double);
using DoubleCompareOp = int64_t (*)(double, double);
using FloatUnOp = float (*)(float);
using FloatBinOp = float (*)(float, float);
@@ -85,6 +86,13 @@ T Mul(T a, T b) {
return a * b;
}
+template <typename T, typename = typename std::enable_if<
+ std::is_floating_point<T>::value>::type>
+T Div(T a, T b) {
+ // Workaround C++ undefined behavior when b is 0.
+ return base::Divide(a, b);
+}
+
template <typename T>
T Minimum(T a, T b) {
return a <= b ? a : b;
@@ -271,7 +279,7 @@ T Sqrt(T a) {
return std::sqrt(a);
}
-#if V8_TARGET_ARCH_X64
+#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
// only used for F64x2 tests below
int64_t Equal(double a, double b) { return a == b ? -1 : 0; }
@@ -284,7 +292,7 @@ int64_t GreaterEqual(double a, double b) { return a >= b ? -1 : 0; }
int64_t Less(double a, double b) { return a < b ? -1 : 0; }
int64_t LessEqual(double a, double b) { return a <= b ? -1 : 0; }
-#endif // V8_TARGET_ARCH_X64
+#endif // V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
} // namespace
@@ -299,7 +307,7 @@ int64_t LessEqual(double a, double b) { return a <= b ? -1 : 0; }
#define WASM_SIMD_SPLAT(Type, ...) __VA_ARGS__, WASM_SIMD_OP(kExpr##Type##Splat)
#define WASM_SIMD_UNOP(op, x) x, WASM_SIMD_OP(op)
#define WASM_SIMD_BINOP(op, x, y) x, y, WASM_SIMD_OP(op)
-#define WASM_SIMD_SHIFT_OP(op, shift, x) x, WASM_SIMD_OP(op), TO_BYTE(shift)
+#define WASM_SIMD_SHIFT_OP(op, x, y) x, y, WASM_SIMD_OP(op)
#define WASM_SIMD_CONCAT_OP(op, bytes, x, y) \
x, y, WASM_SIMD_OP(op), TO_BYTE(bytes)
#define WASM_SIMD_SELECT(format, x, y, z) x, y, z, WASM_SIMD_OP(kExprS128Select)
@@ -652,12 +660,13 @@ WASM_SIMD_TEST(F32x4Sub) {
WASM_SIMD_TEST(F32x4Mul) {
RunF32x4BinOpTest(execution_tier, lower_simd, kExprF32x4Mul, Mul);
}
-// v8:8425 tracks this test being enabled in the interpreter.
-WASM_SIMD_COMPILED_TEST(F32x4Min) {
+WASM_SIMD_TEST(F32x4Div) {
+ RunF32x4BinOpTest(execution_tier, lower_simd, kExprF32x4Div, Div);
+}
+WASM_SIMD_TEST(F32x4Min) {
RunF32x4BinOpTest(execution_tier, lower_simd, kExprF32x4Min, JSMin);
}
-// v8:8425 tracks this test being enabled in the interpreter.
-WASM_SIMD_COMPILED_TEST(F32x4Max) {
+WASM_SIMD_TEST(F32x4Max) {
RunF32x4BinOpTest(execution_tier, lower_simd, kExprF32x4Max, JSMax);
}
@@ -715,7 +724,201 @@ WASM_SIMD_TEST(F32x4Le) {
RunF32x4CompareOpTest(execution_tier, lower_simd, kExprF32x4Le, LessEqual);
}
-#if V8_TARGET_ARCH_X64
+#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
+WASM_SIMD_TEST_NO_LOWERING(I64x2Splat) {
+ WasmRunner<int32_t, int64_t> r(execution_tier, lower_simd);
+ // Set up a global to hold output vector.
+ int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
+ byte param1 = 0;
+ BUILD(r, WASM_SET_GLOBAL(0, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(param1))),
+ WASM_ONE);
+
+ FOR_INT64_INPUTS(x) {
+ r.Call(x);
+ int64_t expected = x;
+ for (int i = 0; i < 2; i++) {
+ int64_t actual = ReadLittleEndianValue<int64_t>(&g[i]);
+ CHECK_EQ(actual, expected);
+ }
+ }
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2ExtractLane) {
+ WasmRunner<int64_t> r(execution_tier, lower_simd);
+ r.AllocateLocal(kWasmI64);
+ r.AllocateLocal(kWasmS128);
+ BUILD(
+ r,
+ WASM_SET_LOCAL(0, WASM_SIMD_I64x2_EXTRACT_LANE(
+ 0, WASM_SIMD_I64x2_SPLAT(WASM_I64V(0xFFFFFFFFFF)))),
+ WASM_SET_LOCAL(1, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(0))),
+ WASM_SIMD_I64x2_EXTRACT_LANE(1, WASM_GET_LOCAL(1)));
+ CHECK_EQ(0xFFFFFFFFFF, r.Call());
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2ReplaceLane) {
+ WasmRunner<int32_t> r(execution_tier, lower_simd);
+ // Set up a global to hold input/output vector.
+ int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
+ // Build function to replace each lane with its index.
+ byte temp1 = r.AllocateLocal(kWasmS128);
+ BUILD(r, WASM_SET_LOCAL(temp1, WASM_SIMD_I64x2_SPLAT(WASM_I64V(-1))),
+ WASM_SET_LOCAL(temp1, WASM_SIMD_I64x2_REPLACE_LANE(
+ 0, WASM_GET_LOCAL(temp1), WASM_I64V(0))),
+ WASM_SET_GLOBAL(0, WASM_SIMD_I64x2_REPLACE_LANE(
+ 1, WASM_GET_LOCAL(temp1), WASM_I64V(1))),
+ WASM_ONE);
+
+ r.Call();
+ for (int64_t i = 0; i < 2; i++) {
+ CHECK_EQ(i, ReadLittleEndianValue<int64_t>(&g[i]));
+ }
+}
+
+void RunI64x2UnOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
+ WasmOpcode opcode, Int64UnOp expected_op) {
+ WasmRunner<int32_t, int64_t> r(execution_tier, lower_simd);
+ // Global to hold output.
+ int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
+ // Build fn to splat test value, perform unop, and write the result.
+ byte value = 0;
+ byte temp1 = r.AllocateLocal(kWasmS128);
+ BUILD(r, WASM_SET_LOCAL(temp1, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(value))),
+ WASM_SET_GLOBAL(0, WASM_SIMD_UNOP(opcode, WASM_GET_LOCAL(temp1))),
+ WASM_ONE);
+
+ FOR_INT64_INPUTS(x) {
+ r.Call(x);
+ int64_t expected = expected_op(x);
+ for (int i = 0; i < 2; i++) {
+ CHECK_EQ(expected, ReadLittleEndianValue<int64_t>(&g[i]));
+ }
+ }
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2Neg) {
+ RunI64x2UnOpTest(execution_tier, lower_simd, kExprI64x2Neg,
+ base::NegateWithWraparound);
+}
+
+void RunI64x2ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
+ WasmOpcode opcode, Int64ShiftOp expected_op) {
+ for (int shift = 1; shift < 64; shift++) {
+ WasmRunner<int32_t, int64_t> r(execution_tier, lower_simd);
+ int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
+ byte value = 0;
+ byte shift_index = r.AllocateLocal(kWasmI32);
+ byte simd1 = r.AllocateLocal(kWasmS128);
+ BUILD(r,
+ WASM_SET_LOCAL(simd1, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(value))),
+ WASM_SET_LOCAL(shift_index, WASM_I32V(shift)),
+ WASM_SET_GLOBAL(0, WASM_SIMD_SHIFT_OP(opcode, WASM_GET_LOCAL(simd1),
+ WASM_GET_LOCAL(shift_index))),
+ WASM_ONE);
+
+ FOR_INT64_INPUTS(x) {
+ r.Call(x);
+ int64_t expected = expected_op(x, shift);
+ for (int i = 0; i < 2; i++) {
+ CHECK_EQ(expected, ReadLittleEndianValue<int64_t>(&g[i]));
+ }
+ }
+ }
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2Shl) {
+ RunI64x2ShiftOpTest(execution_tier, lower_simd, kExprI64x2Shl,
+ LogicalShiftLeft);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2ShrS) {
+ RunI64x2ShiftOpTest(execution_tier, lower_simd, kExprI64x2ShrS,
+ ArithmeticShiftRight);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2ShrU) {
+ RunI64x2ShiftOpTest(execution_tier, lower_simd, kExprI64x2ShrU,
+ LogicalShiftRight);
+}
+
+void RunI64x2BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
+ WasmOpcode opcode, Int64BinOp expected_op) {
+ WasmRunner<int32_t, int64_t, int64_t> r(execution_tier, lower_simd);
+ // Global to hold output.
+ int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
+ // Build fn to splat test values, perform binop, and write the result.
+ byte value1 = 0, value2 = 1;
+ byte temp1 = r.AllocateLocal(kWasmS128);
+ byte temp2 = r.AllocateLocal(kWasmS128);
+ BUILD(r, WASM_SET_LOCAL(temp1, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(value1))),
+ WASM_SET_LOCAL(temp2, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(value2))),
+ WASM_SET_GLOBAL(0, WASM_SIMD_BINOP(opcode, WASM_GET_LOCAL(temp1),
+ WASM_GET_LOCAL(temp2))),
+ WASM_ONE);
+
+ FOR_INT64_INPUTS(x) {
+ FOR_INT64_INPUTS(y) {
+ r.Call(x, y);
+ int64_t expected = expected_op(x, y);
+ for (int i = 0; i < 2; i++) {
+ CHECK_EQ(expected, ReadLittleEndianValue<int64_t>(&g[i]));
+ }
+ }
+ }
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2Add) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Add,
+ base::AddWithWraparound);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2Sub) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Sub,
+ base::SubWithWraparound);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2Eq) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Eq, Equal);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2Ne) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Ne, NotEqual);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2LtS) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2LtS, Less);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2LeS) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2LeS, LessEqual);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2GtS) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2GtS, Greater);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2GeS) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2GeS, GreaterEqual);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2LtU) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2LtU, UnsignedLess);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2LeU) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2LeU,
+ UnsignedLessEqual);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2GtU) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2GtU, UnsignedGreater);
+}
+
+WASM_SIMD_TEST_NO_LOWERING(I64x2GeU) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2GeU,
+ UnsignedGreaterEqual);
+}
+
WASM_SIMD_TEST_NO_LOWERING(F64x2Splat) {
WasmRunner<int32_t, double> r(execution_tier, lower_simd);
// Set up a global to hold output vector.
@@ -770,6 +973,16 @@ WASM_SIMD_TEST_NO_LOWERING(F64x2ExtractLane) {
}
}
+WASM_SIMD_TEST_NO_LOWERING(I64x2ExtractWithF64x2) {
+ WasmRunner<int64_t> r(execution_tier, lower_simd);
+ BUILD(r, WASM_IF_ELSE_L(
+ WASM_I64_EQ(WASM_SIMD_I64x2_EXTRACT_LANE(
+ 0, WASM_SIMD_F64x2_SPLAT(WASM_F64(1e15))),
+ WASM_I64_REINTERPRET_F64(WASM_F64(1e15))),
+ WASM_I64V(1), WASM_I64V(0)));
+ CHECK_EQ(1, r.Call());
+}
+
WASM_SIMD_TEST_NO_LOWERING(F64x2ReplaceLane) {
WasmRunner<int32_t> r(execution_tier, lower_simd);
// Set up a global to hold input/output vector.
@@ -789,58 +1002,12 @@ WASM_SIMD_TEST_NO_LOWERING(F64x2ReplaceLane) {
}
}
-void RunF64x2CompareOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
- WasmOpcode opcode, DoubleCompareOp expected_op) {
- WasmRunner<int32_t, double, double> r(execution_tier, lower_simd);
- // Set up global to hold mask output.
- int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
- // Build fn to splat test values, perform compare op, and write the result.
- byte value1 = 0, value2 = 1;
- byte temp1 = r.AllocateLocal(kWasmS128);
- byte temp2 = r.AllocateLocal(kWasmS128);
- BUILD(r, WASM_SET_LOCAL(temp1, WASM_SIMD_F64x2_SPLAT(WASM_GET_LOCAL(value1))),
- WASM_SET_LOCAL(temp2, WASM_SIMD_F64x2_SPLAT(WASM_GET_LOCAL(value2))),
- WASM_SET_GLOBAL(0, WASM_SIMD_BINOP(opcode, WASM_GET_LOCAL(temp1),
- WASM_GET_LOCAL(temp2))),
- WASM_ONE);
-
- FOR_FLOAT64_INPUTS(x) {
- if (!PlatformCanRepresent(x)) continue;
- FOR_FLOAT64_INPUTS(y) {
- if (!PlatformCanRepresent(y)) continue;
- double diff = x - y; // Model comparison as subtraction.
- if (!PlatformCanRepresent(diff)) continue;
- r.Call(x, y);
- int64_t expected = expected_op(x, y);
- for (int i = 0; i < 2; i++) {
- CHECK_EQ(expected, ReadLittleEndianValue<int64_t>(&g[i]));
- }
- }
- }
-}
-
-WASM_SIMD_TEST_NO_LOWERING(F64x2Eq) {
- RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Eq, Equal);
-}
-
-WASM_SIMD_TEST_NO_LOWERING(F64x2Ne) {
- RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Ne, NotEqual);
-}
-
-WASM_SIMD_TEST_NO_LOWERING(F64x2Gt) {
- RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Gt, Greater);
-}
-
-WASM_SIMD_TEST_NO_LOWERING(F64x2Ge) {
- RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Ge, GreaterEqual);
-}
-
-WASM_SIMD_TEST_NO_LOWERING(F64x2Lt) {
- RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Lt, Less);
-}
-
-WASM_SIMD_TEST_NO_LOWERING(F64x2Le) {
- RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Le, LessEqual);
+bool IsExtreme(double x) {
+ double abs_x = std::fabs(x);
+ const double kSmallFloatThreshold = 1.0e-298;
+ const double kLargeFloatThreshold = 1.0e298;
+ return abs_x != 0.0f && // 0 or -0 are fine.
+ (abs_x < kSmallFloatThreshold || abs_x > kLargeFloatThreshold);
}
bool IsSameNan(double expected, double actual) {
@@ -855,7 +1022,7 @@ bool IsSameNan(double expected, double actual) {
bool IsCanonical(double actual) {
uint64_t actual_bits = bit_cast<uint64_t>(actual);
// Canonical NaN has quiet bit and no payload.
- return (actual_bits & 0xFF80000000000000) == actual_bits;
+ return (actual_bits & 0xFFF8000000000000) == actual_bits;
}
void CheckDoubleResult(double x, double y, double expected, double actual,
@@ -948,7 +1115,6 @@ void RunF64x2UnOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
}
}
-#undef FOR_FLOAT64_NAN_INPUTS
WASM_SIMD_TEST_NO_LOWERING(F64x2Abs) {
RunF64x2UnOpTest(execution_tier, lower_simd, kExprF64x2Abs, std::abs);
@@ -958,96 +1124,90 @@ WASM_SIMD_TEST_NO_LOWERING(F64x2Neg) {
RunF64x2UnOpTest(execution_tier, lower_simd, kExprF64x2Neg, Negate);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2Splat) {
- WasmRunner<int32_t, int64_t> r(execution_tier, lower_simd);
- // Set up a global to hold output vector.
- int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
- byte param1 = 0;
- BUILD(r, WASM_SET_GLOBAL(0, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(param1))),
+void RunF64x2BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
+ WasmOpcode opcode, DoubleBinOp expected_op) {
+ WasmRunner<int32_t, double, double> r(execution_tier, lower_simd);
+ // Global to hold output.
+ double* g = r.builder().AddGlobal<double>(kWasmS128);
+ // Build fn to splat test value, perform binop, and write the result.
+ byte value1 = 0, value2 = 1;
+ byte temp1 = r.AllocateLocal(kWasmS128);
+ byte temp2 = r.AllocateLocal(kWasmS128);
+ BUILD(r, WASM_SET_LOCAL(temp1, WASM_SIMD_F64x2_SPLAT(WASM_GET_LOCAL(value1))),
+ WASM_SET_LOCAL(temp2, WASM_SIMD_F64x2_SPLAT(WASM_GET_LOCAL(value2))),
+ WASM_SET_GLOBAL(0, WASM_SIMD_BINOP(opcode, WASM_GET_LOCAL(temp1),
+ WASM_GET_LOCAL(temp2))),
WASM_ONE);
- FOR_INT64_INPUTS(x) {
- r.Call(x);
- int64_t expected = x;
- for (int i = 0; i < 2; i++) {
- int64_t actual = ReadLittleEndianValue<int64_t>(&g[i]);
- CHECK_EQ(actual, expected);
+ FOR_FLOAT64_INPUTS(x) {
+ if (!PlatformCanRepresent(x)) continue;
+ FOR_FLOAT64_INPUTS(y) {
+ if (!PlatformCanRepresent(x)) continue;
+ double expected = expected_op(x, y);
+ if (!PlatformCanRepresent(expected)) continue;
+ r.Call(x, y);
+ for (int i = 0; i < 2; i++) {
+ double actual = ReadLittleEndianValue<double>(&g[i]);
+ CheckDoubleResult(x, y, expected, actual, true /* exact */);
+ }
}
}
-}
-WASM_SIMD_TEST_NO_LOWERING(I64x2ExtractWithF64x2) {
- WasmRunner<int64_t> r(execution_tier, lower_simd);
- BUILD(r, WASM_IF_ELSE_L(
- WASM_I64_EQ(WASM_SIMD_I64x2_EXTRACT_LANE(
- 0, WASM_SIMD_F64x2_SPLAT(WASM_F64(1e15))),
- WASM_I64_REINTERPRET_F64(WASM_F64(1e15))),
- WASM_I64V(1), WASM_I64V(0)));
- CHECK_EQ(1, r.Call());
+ FOR_FLOAT64_NAN_INPUTS(i) {
+ double x = bit_cast<double>(double_nan_test_array[i]);
+ if (!PlatformCanRepresent(x)) continue;
+ FOR_FLOAT64_NAN_INPUTS(j) {
+ double y = bit_cast<double>(double_nan_test_array[j]);
+ double expected = expected_op(x, y);
+ if (!PlatformCanRepresent(expected)) continue;
+ r.Call(x, y);
+ for (int i = 0; i < 2; i++) {
+ double actual = ReadLittleEndianValue<double>(&g[i]);
+ CheckDoubleResult(x, y, expected, actual, true /* exact */);
+ }
+ }
+ }
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2ReplaceLane) {
- WasmRunner<int32_t> r(execution_tier, lower_simd);
- // Set up a global to hold input/output vector.
- int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
- // Build function to replace each lane with its index.
- byte temp1 = r.AllocateLocal(kWasmS128);
- BUILD(r, WASM_SET_LOCAL(temp1, WASM_SIMD_I64x2_SPLAT(WASM_I64V(-1))),
- WASM_SET_LOCAL(temp1, WASM_SIMD_I64x2_REPLACE_LANE(
- 0, WASM_GET_LOCAL(temp1), WASM_I64V(0))),
- WASM_SET_GLOBAL(0, WASM_SIMD_I64x2_REPLACE_LANE(
- 1, WASM_GET_LOCAL(temp1), WASM_I64V(1))),
- WASM_ONE);
+#undef FOR_FLOAT64_NAN_INPUTS
- r.Call();
- for (int64_t i = 0; i < 2; i++) {
- CHECK_EQ(i, ReadLittleEndianValue<int64_t>(&g[i]));
- }
+WASM_SIMD_TEST_NO_LOWERING(F64x2Add) {
+ RunF64x2BinOpTest(execution_tier, lower_simd, kExprF64x2Add, Add);
}
-void RunI64x2UnOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
- WasmOpcode opcode, Int64UnOp expected_op) {
- WasmRunner<int32_t, int64_t> r(execution_tier, lower_simd);
- // Global to hold output.
- int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
- // Build fn to splat test value, perform unop, and write the result.
- byte value = 0;
- byte temp1 = r.AllocateLocal(kWasmS128);
- BUILD(r, WASM_SET_LOCAL(temp1, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(value))),
- WASM_SET_GLOBAL(0, WASM_SIMD_UNOP(opcode, WASM_GET_LOCAL(temp1))),
- WASM_ONE);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Sub) {
+ RunF64x2BinOpTest(execution_tier, lower_simd, kExprF64x2Sub, Sub);
+}
- FOR_INT64_INPUTS(x) {
- r.Call(x);
- int64_t expected = expected_op(x);
- for (int i = 0; i < 2; i++) {
- CHECK_EQ(expected, ReadLittleEndianValue<int64_t>(&g[i]));
- }
- }
+WASM_SIMD_TEST_NO_LOWERING(F64x2Mul) {
+ RunF64x2BinOpTest(execution_tier, lower_simd, kExprF64x2Mul, Mul);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2Neg) {
- RunI64x2UnOpTest(execution_tier, lower_simd, kExprI64x2Neg,
- base::NegateWithWraparound);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Div) {
+ RunF64x2BinOpTest(execution_tier, lower_simd, kExprF64x2Div, Div);
}
-void RunI64x2BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
- WasmOpcode opcode, Int64BinOp expected_op) {
- WasmRunner<int32_t, int64_t, int64_t> r(execution_tier, lower_simd);
- // Global to hold output.
+void RunF64x2CompareOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
+ WasmOpcode opcode, DoubleCompareOp expected_op) {
+ WasmRunner<int32_t, double, double> r(execution_tier, lower_simd);
+ // Set up global to hold mask output.
int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
- // Build fn to splat test values, perform binop, and write the result.
+ // Build fn to splat test values, perform compare op, and write the result.
byte value1 = 0, value2 = 1;
byte temp1 = r.AllocateLocal(kWasmS128);
byte temp2 = r.AllocateLocal(kWasmS128);
- BUILD(r, WASM_SET_LOCAL(temp1, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(value1))),
- WASM_SET_LOCAL(temp2, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(value2))),
+ BUILD(r, WASM_SET_LOCAL(temp1, WASM_SIMD_F64x2_SPLAT(WASM_GET_LOCAL(value1))),
+ WASM_SET_LOCAL(temp2, WASM_SIMD_F64x2_SPLAT(WASM_GET_LOCAL(value2))),
WASM_SET_GLOBAL(0, WASM_SIMD_BINOP(opcode, WASM_GET_LOCAL(temp1),
WASM_GET_LOCAL(temp2))),
WASM_ONE);
- FOR_INT64_INPUTS(x) {
- FOR_INT64_INPUTS(y) {
+ FOR_FLOAT64_INPUTS(x) {
+ if (!PlatformCanRepresent(x)) continue;
+ FOR_FLOAT64_INPUTS(y) {
+ if (!PlatformCanRepresent(y)) continue;
+ double diff = x - y; // Model comparison as subtraction.
+ if (!PlatformCanRepresent(diff)) continue;
r.Call(x, y);
int64_t expected = expected_op(x, y);
for (int i = 0; i < 2; i++) {
@@ -1057,101 +1217,63 @@ void RunI64x2BinOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2Add) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Add,
- base::AddWithWraparound);
-}
-
-WASM_SIMD_TEST_NO_LOWERING(I64x2Sub) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Sub,
- base::SubWithWraparound);
-}
-
-WASM_SIMD_TEST_NO_LOWERING(I64x2Mul) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Mul,
- base::MulWithWraparound);
-}
-
-WASM_SIMD_TEST_NO_LOWERING(I64x2Eq) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Eq, Equal);
-}
-
-WASM_SIMD_TEST_NO_LOWERING(I64x2Ne) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Ne, NotEqual);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Eq) {
+ RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Eq, Equal);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2LtS) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2LtS, Less);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Ne) {
+ RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Ne, NotEqual);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2LeS) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2LeS, LessEqual);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Gt) {
+ RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Gt, Greater);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2GtS) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2GtS, Greater);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Ge) {
+ RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Ge, GreaterEqual);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2GeS) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2GeS, GreaterEqual);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Lt) {
+ RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Lt, Less);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2LtU) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2LtU, UnsignedLess);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Le) {
+ RunF64x2CompareOpTest(execution_tier, lower_simd, kExprF64x2Le, LessEqual);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2LeU) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2LeU,
- UnsignedLessEqual);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Min) {
+ RunF64x2BinOpTest(execution_tier, lower_simd, kExprF64x2Min, JSMin);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2GtU) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2GtU, UnsignedGreater);
+WASM_SIMD_TEST_NO_LOWERING(F64x2Max) {
+ RunF64x2BinOpTest(execution_tier, lower_simd, kExprF64x2Max, JSMax);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2GeU) {
- RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2GeU,
- UnsignedGreaterEqual);
+#if V8_TARGET_ARCH_X64
+WASM_SIMD_TEST_NO_LOWERING(I64x2Mul) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2Mul,
+ base::MulWithWraparound);
}
-void RunI64x2ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
- WasmOpcode opcode, Int64ShiftOp expected_op) {
- for (int shift = 1; shift < 64; shift++) {
- WasmRunner<int32_t, int64_t> r(execution_tier, lower_simd);
- int64_t* g = r.builder().AddGlobal<int64_t>(kWasmS128);
- byte value = 0;
- byte simd1 = r.AllocateLocal(kWasmS128);
- BUILD(r,
- WASM_SET_LOCAL(simd1, WASM_SIMD_I64x2_SPLAT(WASM_GET_LOCAL(value))),
- WASM_SET_GLOBAL(
- 0, WASM_SIMD_SHIFT_OP(opcode, shift, WASM_GET_LOCAL(simd1))),
- WASM_ONE);
-
- FOR_INT64_INPUTS(x) {
- r.Call(x);
- int64_t expected = expected_op(x, shift);
- for (int i = 0; i < 2; i++) {
- CHECK_EQ(expected, ReadLittleEndianValue<int64_t>(&g[i]));
- }
- }
- }
+WASM_SIMD_TEST_NO_LOWERING(I64x2MinS) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2MinS, Minimum);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2Shl) {
- RunI64x2ShiftOpTest(execution_tier, lower_simd, kExprI64x2Shl,
- LogicalShiftLeft);
+WASM_SIMD_TEST_NO_LOWERING(I64x2MaxS) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2MaxS, Maximum);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2ShrS) {
- RunI64x2ShiftOpTest(execution_tier, lower_simd, kExprI64x2ShrS,
- ArithmeticShiftRight);
+WASM_SIMD_TEST_NO_LOWERING(I64x2MinU) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2MinU,
+ UnsignedMinimum);
}
-WASM_SIMD_TEST_NO_LOWERING(I64x2ShrU) {
- RunI64x2ShiftOpTest(execution_tier, lower_simd, kExprI64x2ShrU,
- LogicalShiftRight);
+WASM_SIMD_TEST_NO_LOWERING(I64x2MaxU) {
+ RunI64x2BinOpTest(execution_tier, lower_simd, kExprI64x2MaxU,
+ UnsignedMaximum);
}
#endif // V8_TARGET_ARCH_X64
+#endif // V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
WASM_SIMD_TEST(I32x4Splat) {
WasmRunner<int32_t, int32_t> r(execution_tier, lower_simd);
@@ -1534,16 +1656,17 @@ void RunI32x4ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
WasmRunner<int32_t, int32_t> r(execution_tier, lower_simd);
int32_t* g = r.builder().AddGlobal<int32_t>(kWasmS128);
byte value = 0;
+ byte shift_index = r.AllocateLocal(kWasmI32);
byte simd1 = r.AllocateLocal(kWasmS128);
- BUILD(r,
+ BUILD(r, WASM_SET_LOCAL(shift_index, WASM_I32V(shift)),
WASM_SET_LOCAL(simd1, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(value))),
- WASM_SET_GLOBAL(
- 0, WASM_SIMD_SHIFT_OP(opcode, shift, WASM_GET_LOCAL(simd1))),
+ WASM_SET_GLOBAL(0, WASM_SIMD_SHIFT_OP(opcode, WASM_GET_LOCAL(simd1),
+ WASM_GET_LOCAL(shift_index))),
WASM_ONE);
FOR_INT32_INPUTS(x) {
r.Call(x);
- float expected = expected_op(x, shift);
+ int32_t expected = expected_op(x, shift);
for (int i = 0; i < 4; i++) {
CHECK_EQ(expected, ReadLittleEndianValue<int32_t>(&g[i]));
}
@@ -1551,17 +1674,17 @@ void RunI32x4ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
}
-WASM_SIMD_TEST(I32x4Shl) {
+WASM_SIMD_TEST_NO_LOWERING(I32x4Shl) {
RunI32x4ShiftOpTest(execution_tier, lower_simd, kExprI32x4Shl,
LogicalShiftLeft);
}
-WASM_SIMD_TEST(I32x4ShrS) {
+WASM_SIMD_TEST_NO_LOWERING(I32x4ShrS) {
RunI32x4ShiftOpTest(execution_tier, lower_simd, kExprI32x4ShrS,
ArithmeticShiftRight);
}
-WASM_SIMD_TEST(I32x4ShrU) {
+WASM_SIMD_TEST_NO_LOWERING(I32x4ShrU) {
RunI32x4ShiftOpTest(execution_tier, lower_simd, kExprI32x4ShrU,
LogicalShiftRight);
}
@@ -1784,10 +1907,12 @@ void RunI16x8ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
int16_t* g = r.builder().AddGlobal<int16_t>(kWasmS128);
byte value = 0;
byte simd1 = r.AllocateLocal(kWasmS128);
+ byte shift_index = r.AllocateLocal(kWasmI32);
BUILD(r,
WASM_SET_LOCAL(simd1, WASM_SIMD_I16x8_SPLAT(WASM_GET_LOCAL(value))),
- WASM_SET_GLOBAL(
- 0, WASM_SIMD_SHIFT_OP(opcode, shift, WASM_GET_LOCAL(simd1))),
+ WASM_SET_LOCAL(shift_index, WASM_I32V(shift)),
+ WASM_SET_GLOBAL(0, WASM_SIMD_SHIFT_OP(opcode, WASM_GET_LOCAL(simd1),
+ WASM_GET_LOCAL(shift_index))),
WASM_ONE);
FOR_INT16_INPUTS(x) {
@@ -1800,17 +1925,17 @@ void RunI16x8ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
}
-WASM_SIMD_TEST(I16x8Shl) {
+WASM_SIMD_TEST_NO_LOWERING(I16x8Shl) {
RunI16x8ShiftOpTest(execution_tier, lower_simd, kExprI16x8Shl,
LogicalShiftLeft);
}
-WASM_SIMD_TEST(I16x8ShrS) {
+WASM_SIMD_TEST_NO_LOWERING(I16x8ShrS) {
RunI16x8ShiftOpTest(execution_tier, lower_simd, kExprI16x8ShrS,
ArithmeticShiftRight);
}
-WASM_SIMD_TEST(I16x8ShrU) {
+WASM_SIMD_TEST_NO_LOWERING(I16x8ShrU) {
RunI16x8ShiftOpTest(execution_tier, lower_simd, kExprI16x8ShrU,
LogicalShiftRight);
}
@@ -1998,15 +2123,17 @@ void RunI8x16ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
int8_t* g = r.builder().AddGlobal<int8_t>(kWasmS128);
byte value = 0;
byte simd1 = r.AllocateLocal(kWasmS128);
+ byte shift_index = r.AllocateLocal(kWasmI32);
BUILD(r,
WASM_SET_LOCAL(simd1, WASM_SIMD_I8x16_SPLAT(WASM_GET_LOCAL(value))),
- WASM_SET_GLOBAL(
- 0, WASM_SIMD_SHIFT_OP(opcode, shift, WASM_GET_LOCAL(simd1))),
+ WASM_SET_LOCAL(shift_index, WASM_I32V(shift)),
+ WASM_SET_GLOBAL(0, WASM_SIMD_SHIFT_OP(opcode, WASM_GET_LOCAL(simd1),
+ WASM_GET_LOCAL(shift_index))),
WASM_ONE);
FOR_INT8_INPUTS(x) {
r.Call(x);
- float expected = expected_op(x, shift);
+ int8_t expected = expected_op(x, shift);
for (int i = 0; i < 16; i++) {
CHECK_EQ(expected, ReadLittleEndianValue<int8_t>(&g[i]));
}
@@ -2014,17 +2141,17 @@ void RunI8x16ShiftOpTest(ExecutionTier execution_tier, LowerSimd lower_simd,
}
}
-WASM_SIMD_TEST(I8x16Shl) {
+WASM_SIMD_TEST_NO_LOWERING(I8x16Shl) {
RunI8x16ShiftOpTest(execution_tier, lower_simd, kExprI8x16Shl,
LogicalShiftLeft);
}
-WASM_SIMD_TEST(I8x16ShrS) {
+WASM_SIMD_TEST_NO_LOWERING(I8x16ShrS) {
RunI8x16ShiftOpTest(execution_tier, lower_simd, kExprI8x16ShrS,
ArithmeticShiftRight);
}
-WASM_SIMD_TEST(I8x16ShrU) {
+WASM_SIMD_TEST_NO_LOWERING(I8x16ShrU) {
RunI8x16ShiftOpTest(execution_tier, lower_simd, kExprI8x16ShrU,
LogicalShiftRight);
}
@@ -2432,13 +2559,14 @@ WASM_SIMD_COMPILED_TEST(S8x16MultiShuffleFuzz) {
// Boolean unary operations are 'AllTrue' and 'AnyTrue', which return an integer
// result. Use relational ops on numeric vectors to create the boolean vector
// test inputs. Test inputs with all true, all false, one true, and one false.
-#define WASM_SIMD_BOOL_REDUCTION_TEST(format, lanes) \
+#define WASM_SIMD_BOOL_REDUCTION_TEST(format, lanes, int_type) \
WASM_SIMD_TEST(ReductionTest##lanes) { \
WasmRunner<int32_t> r(execution_tier, lower_simd); \
+ if (lanes == 2 && lower_simd == kLowerSimd) return; \
byte zero = r.AllocateLocal(kWasmS128); \
byte one_one = r.AllocateLocal(kWasmS128); \
byte reduced = r.AllocateLocal(kWasmI32); \
- BUILD(r, WASM_SET_LOCAL(zero, WASM_SIMD_I##format##_SPLAT(WASM_ZERO)), \
+ BUILD(r, WASM_SET_LOCAL(zero, WASM_SIMD_I##format##_SPLAT(int_type(0))), \
WASM_SET_LOCAL( \
reduced, WASM_SIMD_UNOP(kExprS1x##lanes##AnyTrue, \
WASM_SIMD_BINOP(kExprI##format##Eq, \
@@ -2469,7 +2597,7 @@ WASM_SIMD_COMPILED_TEST(S8x16MultiShuffleFuzz) {
WASM_RETURN1(WASM_ZERO)), \
WASM_SET_LOCAL(one_one, \
WASM_SIMD_I##format##_REPLACE_LANE( \
- lanes - 1, WASM_GET_LOCAL(zero), WASM_ONE)), \
+ lanes - 1, WASM_GET_LOCAL(zero), int_type(1))), \
WASM_SET_LOCAL( \
reduced, WASM_SIMD_UNOP(kExprS1x##lanes##AnyTrue, \
WASM_SIMD_BINOP(kExprI##format##Eq, \
@@ -2502,9 +2630,12 @@ WASM_SIMD_COMPILED_TEST(S8x16MultiShuffleFuzz) {
CHECK_EQ(1, r.Call()); \
}
-WASM_SIMD_BOOL_REDUCTION_TEST(32x4, 4)
-WASM_SIMD_BOOL_REDUCTION_TEST(16x8, 8)
-WASM_SIMD_BOOL_REDUCTION_TEST(8x16, 16)
+#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
+WASM_SIMD_BOOL_REDUCTION_TEST(64x2, 2, WASM_I64V)
+#endif // V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
+WASM_SIMD_BOOL_REDUCTION_TEST(32x4, 4, WASM_I32V)
+WASM_SIMD_BOOL_REDUCTION_TEST(16x8, 8, WASM_I32V)
+WASM_SIMD_BOOL_REDUCTION_TEST(8x16, 16, WASM_I32V)
WASM_SIMD_TEST(SimdI32x4ExtractWithF32x4) {
WasmRunner<int32_t> r(execution_tier, lower_simd);
@@ -2758,7 +2889,7 @@ WASM_SIMD_TEST(SimdF32x4SetGlobal) {
CHECK_EQ(GetScalar(global, 3), 65.0f);
}
-WASM_SIMD_COMPILED_TEST(SimdLoadStoreLoad) {
+WASM_SIMD_TEST(SimdLoadStoreLoad) {
WasmRunner<int32_t> r(execution_tier, lower_simd);
int32_t* memory =
r.builder().AddMemoryElems<int32_t>(kWasmPageSize / sizeof(int32_t));
@@ -2776,11 +2907,10 @@ WASM_SIMD_COMPILED_TEST(SimdLoadStoreLoad) {
#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM64 || \
V8_TARGET_ARCH_ARM
-// V8:8665 - Tracking bug to enable reduction tests in the interpreter,
-// and for SIMD lowering.
#define WASM_SIMD_ANYTRUE_TEST(format, lanes, max, param_type) \
- WASM_SIMD_TEST_NO_LOWERING(S##format##AnyTrue) { \
+ WASM_SIMD_TEST(S##format##AnyTrue) { \
WasmRunner<int32_t, param_type> r(execution_tier, lower_simd); \
+ if (lanes == 2 && lower_simd == kLowerSimd) return; \
byte simd = r.AllocateLocal(kWasmS128); \
BUILD( \
r, \
@@ -2790,16 +2920,17 @@ WASM_SIMD_COMPILED_TEST(SimdLoadStoreLoad) {
DCHECK_EQ(1, r.Call(5)); \
DCHECK_EQ(0, r.Call(0)); \
}
-#if V8_TARGET_ARCH_X64
+#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
WASM_SIMD_ANYTRUE_TEST(64x2, 2, 0xffffffffffffffff, int64_t)
-#endif // V8_TARGET_ARCH_X64
+#endif // V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
WASM_SIMD_ANYTRUE_TEST(32x4, 4, 0xffffffff, int32_t)
WASM_SIMD_ANYTRUE_TEST(16x8, 8, 0xffff, int32_t)
WASM_SIMD_ANYTRUE_TEST(8x16, 16, 0xff, int32_t)
#define WASM_SIMD_ALLTRUE_TEST(format, lanes, max, param_type) \
- WASM_SIMD_TEST_NO_LOWERING(S##format##AllTrue) { \
+ WASM_SIMD_TEST(S##format##AllTrue) { \
WasmRunner<int32_t, param_type> r(execution_tier, lower_simd); \
+ if (lanes == 2 && lower_simd == kLowerSimd) return; \
byte simd = r.AllocateLocal(kWasmS128); \
BUILD( \
r, \
@@ -2809,9 +2940,9 @@ WASM_SIMD_ANYTRUE_TEST(8x16, 16, 0xff, int32_t)
DCHECK_EQ(1, r.Call(0x1)); \
DCHECK_EQ(0, r.Call(0)); \
}
-#if V8_TARGET_ARCH_X64
+#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
WASM_SIMD_ALLTRUE_TEST(64x2, 2, 0xffffffffffffffff, int64_t)
-#endif // V8_TARGET_ARCH_X64
+#endif // V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64
WASM_SIMD_ALLTRUE_TEST(32x4, 4, 0xffffffff, int32_t)
WASM_SIMD_ALLTRUE_TEST(16x8, 8, 0xffff, int32_t)
WASM_SIMD_ALLTRUE_TEST(8x16, 16, 0xff, int32_t)
diff --git a/deps/v8/test/cctest/wasm/test-streaming-compilation.cc b/deps/v8/test/cctest/wasm/test-streaming-compilation.cc
index 93ae92d697..795fa30e72 100644
--- a/deps/v8/test/cctest/wasm/test-streaming-compilation.cc
+++ b/deps/v8/test/cctest/wasm/test-streaming-compilation.cc
@@ -267,7 +267,7 @@ size_t GetFunctionOffset(i::Isolate* isolate, const uint8_t* buffer,
kAllWasmFeatures, buffer, buffer + size, false, ModuleOrigin::kWasmOrigin,
isolate->counters(), isolate->wasm_engine()->allocator());
CHECK(result.ok());
- const WasmFunction* func = &result.value()->functions[1];
+ const WasmFunction* func = &result.value()->functions[index];
return func->code.offset();
}
diff --git a/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc b/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc
index 855e44aba2..b5bacf57d4 100644
--- a/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc
+++ b/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc
@@ -273,8 +273,8 @@ TEST(SharedEngineRunThreadedBuildingSync) {
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
CHECK_EQ(42, isolate.Run(instance));
});
- thread1.Start();
- thread2.Start();
+ CHECK(thread1.Start());
+ CHECK(thread2.Start());
thread1.Join();
thread2.Join();
}
@@ -295,8 +295,8 @@ TEST(SharedEngineRunThreadedBuildingAsync) {
CompileAndInstantiateAsync(isolate, buffer);
CHECK_EQ(42, isolate.Run(instance));
});
- thread1.Start();
- thread2.Start();
+ CHECK(thread1.Start());
+ CHECK(thread2.Start());
thread1.Join();
thread2.Join();
}
@@ -321,8 +321,8 @@ TEST(SharedEngineRunThreadedExecution) {
Handle<WasmInstanceObject> instance = isolate.ImportInstance(module);
CHECK_EQ(23, isolate.Run(instance));
});
- thread1.Start();
- thread2.Start();
+ CHECK(thread1.Start());
+ CHECK(thread2.Start());
thread1.Join();
thread2.Join();
}
@@ -358,7 +358,7 @@ TEST(SharedEngineRunThreadedTierUp) {
&module->module()->functions[0], ExecutionTier::kTurbofan);
CHECK_EQ(23, isolate.Run(instance));
});
- for (auto& thread : threads) thread.Start();
+ for (auto& thread : threads) CHECK(thread.Start());
for (auto& thread : threads) thread.Join();
}
diff --git a/deps/v8/test/cctest/wasm/wasm-run-utils.cc b/deps/v8/test/cctest/wasm/wasm-run-utils.cc
index 6a17b81c56..528d71f53c 100644
--- a/deps/v8/test/cctest/wasm/wasm-run-utils.cc
+++ b/deps/v8/test/cctest/wasm/wasm-run-utils.cc
@@ -47,8 +47,8 @@ TestingModuleBuilder::TestingModuleBuilder(
if (maybe_import) {
// Manually compile an import wrapper and insert it into the instance.
CodeSpaceMemoryModificationScope modification_scope(isolate_->heap());
- auto resolved = compiler::ResolveWasmImportCall(maybe_import->js_function,
- maybe_import->sig, false);
+ auto resolved = compiler::ResolveWasmImportCall(
+ maybe_import->js_function, maybe_import->sig, enabled_features_);
compiler::WasmImportCallKind kind = resolved.first;
Handle<JSReceiver> callable = resolved.second;
WasmImportWrapperCache::ModificationScope cache_scope(
@@ -159,7 +159,7 @@ void TestingModuleBuilder::FreezeSignatureMapAndInitializeWrapperCache() {
Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
FreezeSignatureMapAndInitializeWrapperCache();
SetExecutable();
- return WasmInstanceObject::GetOrCreateWasmExportedFunction(
+ return WasmInstanceObject::GetOrCreateWasmExternalFunction(
isolate_, instance_object(), index);
}
@@ -324,9 +324,14 @@ Handle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() {
Handle<Script> script =
isolate_->factory()->NewScript(isolate_->factory()->empty_string());
script->set_type(Script::TYPE_WASM);
+
+ auto native_module = isolate_->wasm_engine()->NewNativeModule(
+ isolate_, enabled_features_, test_module_);
+ native_module->SetWireBytes(OwnedVector<const uint8_t>());
+ native_module->SetRuntimeStubs(isolate_);
+
Handle<WasmModuleObject> module_object =
- WasmModuleObject::New(isolate_, enabled_features_, test_module_, {},
- script, Handle<ByteArray>::null());
+ WasmModuleObject::New(isolate_, std::move(native_module), script);
// This method is called when we initialize TestEnvironment. We don't
// have a memory yet, so we won't create it here. We'll update the
// interpreter when we get a memory. We do have globals, though.
@@ -360,7 +365,7 @@ void TestBuildingGraphWithBuilder(compiler::WasmGraphBuilder* builder,
FATAL("Verification failed; pc = +%x, msg = %s", result.error().offset(),
result.error().message().c_str());
}
- builder->LowerInt64();
+ builder->LowerInt64(compiler::WasmGraphBuilder::kCalledFromWasm);
if (!CpuFeatures::SupportsWasmSimd128()) {
builder->SimdScalarLoweringForTesting();
}
@@ -453,8 +458,8 @@ Handle<Code> WasmFunctionWrapper::GetWrapperCode() {
if (!code_.ToHandle(&code)) {
Isolate* isolate = CcTest::InitIsolateOnce();
- auto call_descriptor =
- compiler::Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
+ auto call_descriptor = compiler::Linkage::GetSimplifiedCDescriptor(
+ zone(), signature_, CallDescriptor::kInitializeRootRegister);
if (kSystemPointerSize == 4) {
size_t num_params = signature_->parameter_count();
diff --git a/deps/v8/test/common/wasm/OWNERS b/deps/v8/test/common/wasm/OWNERS
index 4b6b34d24a..a89e5f1056 100644
--- a/deps/v8/test/common/wasm/OWNERS
+++ b/deps/v8/test/common/wasm/OWNERS
@@ -1 +1 @@
-file://src/wasm/OWNERS
+file:../../../src/wasm/OWNERS
diff --git a/deps/v8/test/common/wasm/wasm-module-runner.cc b/deps/v8/test/common/wasm/wasm-module-runner.cc
index 8de7655914..d2869509cc 100644
--- a/deps/v8/test/common/wasm/wasm-module-runner.cc
+++ b/deps/v8/test/common/wasm/wasm-module-runner.cc
@@ -101,6 +101,12 @@ bool InterpretWasmModuleForTesting(Isolate* isolate,
case kWasmF64:
arguments[i] = WasmValue(0.0);
break;
+ case kWasmAnyRef:
+ case kWasmFuncRef:
+ case kWasmExnRef:
+ arguments[i] =
+ WasmValue(Handle<Object>::cast(isolate->factory()->null_value()));
+ break;
default:
UNREACHABLE();
}
diff --git a/deps/v8/test/debugger/OWNERS b/deps/v8/test/debugger/OWNERS
index 39aa08cd8c..611a024b57 100644
--- a/deps/v8/test/debugger/OWNERS
+++ b/deps/v8/test/debugger/OWNERS
@@ -1 +1 @@
-file://src/debug/OWNERS
+file:../../src/debug/OWNERS
diff --git a/deps/v8/test/fuzzer/multi-return.cc b/deps/v8/test/fuzzer/multi-return.cc
index 028ce7083a..26bb70fce7 100644
--- a/deps/v8/test/fuzzer/multi-return.cc
+++ b/deps/v8/test/fuzzer/multi-return.cc
@@ -238,10 +238,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
callee.Return(static_cast<int>(desc->ReturnCount()), returns.get());
OptimizedCompilationInfo info(ArrayVector("testing"), &zone, Code::STUB);
- Handle<Code> code = Pipeline::GenerateCodeForTesting(
- &info, i_isolate, desc, callee.graph(),
- AssemblerOptions::Default(i_isolate), callee.Export())
- .ToHandleChecked();
+ Handle<Code> code =
+ Pipeline::GenerateCodeForTesting(&info, i_isolate, desc, callee.graph(),
+ AssemblerOptions::Default(i_isolate),
+ callee.ExportForTest())
+ .ToHandleChecked();
std::shared_ptr<wasm::NativeModule> module =
AllocateNativeModule(i_isolate, code->raw_instruction_size());
@@ -286,7 +287,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
Handle<Code> wrapper_code =
Pipeline::GenerateCodeForTesting(
&wrapper_info, i_isolate, wrapper_desc, caller.graph(),
- AssemblerOptions::Default(i_isolate), caller.Export())
+ AssemblerOptions::Default(i_isolate), caller.ExportForTest())
.ToHandleChecked();
auto fn = GeneratedCode<int32_t>::FromCode(*wrapper_code);
diff --git a/deps/v8/test/fuzzer/regexp-builtins.cc b/deps/v8/test/fuzzer/regexp-builtins.cc
index 20cb024a1a..6dafe950fb 100644
--- a/deps/v8/test/fuzzer/regexp-builtins.cc
+++ b/deps/v8/test/fuzzer/regexp-builtins.cc
@@ -337,8 +337,14 @@ bool ResultsAreIdentical(FuzzerArgs* args) {
std::string source =
"assertEquals(fast.exception, slow.exception);\n"
"assertEquals(fast.result, slow.result);\n"
- "if (fast.result !== null)\n"
+ "if (fast.result !== null) {\n"
" assertEquals(fast.result.groups, slow.result.groups);\n"
+ " assertEquals(fast.result.indices, slow.result.indices);\n"
+ " if (fast.result.indices !== undefined) {\n"
+ " assertEquals(fast.result.indices.groups,\n"
+ " slow.result.indices.groups);\n"
+ " }\n"
+ "}\n"
"assertEquals(fast.re.lastIndex, slow.re.lastIndex);\n";
v8::Local<v8::Value> result;
diff --git a/deps/v8/test/fuzzer/wasm-fuzzer-common.cc b/deps/v8/test/fuzzer/wasm-fuzzer-common.cc
index 5a60eb63aa..35e942b262 100644
--- a/deps/v8/test/fuzzer/wasm-fuzzer-common.cc
+++ b/deps/v8/test/fuzzer/wasm-fuzzer-common.cc
@@ -8,9 +8,10 @@
#include "include/v8.h"
#include "src/execution/isolate.h"
-#include "src/utils/ostreams.h"
#include "src/objects/objects-inl.h"
+#include "src/utils/ostreams.h"
#include "src/wasm/wasm-engine.h"
+#include "src/wasm/wasm-feature-flags.h"
#include "src/wasm/wasm-module-builder.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
@@ -88,6 +89,12 @@ const char* ValueTypeToConstantName(ValueType type) {
return "kWasmF32";
case kWasmF64:
return "kWasmF64";
+ case kWasmAnyRef:
+ return "kWasmAnyRef";
+ case kWasmFuncRef:
+ return "kWasmFuncRef";
+ case kWasmExnRef:
+ return "kWasmExnRef";
default:
UNREACHABLE();
}
@@ -140,6 +147,8 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
"can be\n"
"// found in the LICENSE file.\n"
"\n"
+ "// Flags: --wasm-staging\n"
+ "\n"
"load('test/mjsunit/wasm/wasm-module-builder.js');\n"
"\n"
"(function() {\n"
@@ -249,6 +258,14 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
void WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data,
bool require_valid) {
+ // We explicitly enable staged WebAssembly features here to increase fuzzer
+ // coverage. For libfuzzer fuzzers it is not possible that the fuzzer enables
+ // the flag by itself.
+#define ENABLE_STAGED_FEATURES(feat, desc, val) \
+ FlagScope<bool> enable_##feat(&FLAG_experimental_wasm_##feat, true);
+ FOREACH_WASM_STAGING_FEATURE_FLAG(ENABLE_STAGED_FEATURES)
+#undef ENABLE_STAGED_FEATURES
+
// Strictly enforce the input size limit. Note that setting "max_len" on the
// fuzzer target is not enough, since different fuzzers are used and not all
// respect that limit.
diff --git a/deps/v8/test/fuzzer/wasm.cc b/deps/v8/test/fuzzer/wasm.cc
index 53bbac6a01..e8aebbfbec 100644
--- a/deps/v8/test/fuzzer/wasm.cc
+++ b/deps/v8/test/fuzzer/wasm.cc
@@ -11,6 +11,7 @@
#include "src/heap/factory.h"
#include "src/objects/objects-inl.h"
#include "src/wasm/wasm-engine.h"
+#include "src/wasm/wasm-feature-flags.h"
#include "src/wasm/wasm-module.h"
#include "test/common/wasm/flag-utils.h"
#include "test/common/wasm/wasm-module-runner.h"
@@ -20,6 +21,16 @@
namespace i = v8::internal;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ // We explicitly enable staged WebAssembly features here to increase fuzzer
+ // coverage. For libfuzzer fuzzers it is not possible that the fuzzer enables
+ // the flag by itself.
+#define ENABLE_STAGED_FEATURES(feat, desc, val) \
+ i::FlagScope<bool> enable_##feat(&i::FLAG_experimental_wasm_##feat, true);
+ FOREACH_WASM_STAGING_FEATURE_FLAG(ENABLE_STAGED_FEATURES)
+#undef ENABLE_STAGED_FEATURES
+
+ // We reduce the maximum memory size and table size of WebAssembly instances
+ // to avoid OOMs in the fuzzer.
i::FlagScope<uint32_t> max_mem_flag_scope(&i::FLAG_wasm_max_mem_pages, 32);
i::FlagScope<uint32_t> max_table_size_scope(&i::FLAG_wasm_max_table_size,
100);
diff --git a/deps/v8/test/inspector/OWNERS b/deps/v8/test/inspector/OWNERS
index eef15ad6d8..50cd83c40c 100644
--- a/deps/v8/test/inspector/OWNERS
+++ b/deps/v8/test/inspector/OWNERS
@@ -1,3 +1,3 @@
-file://src/inspector/OWNERS
+file:../../src/inspector/OWNERS
# COMPONENT: Platform>DevTools>JavaScript
diff --git a/deps/v8/test/inspector/debugger/class-private-fields-scopes-expected.txt b/deps/v8/test/inspector/debugger/class-private-fields-scopes-expected.txt
new file mode 100644
index 0000000000..a018bdd7a5
--- /dev/null
+++ b/deps/v8/test/inspector/debugger/class-private-fields-scopes-expected.txt
@@ -0,0 +1,141 @@
+Test private class fields in scopes
+
+Running test: testScopesPaused
+[
+ [0] : {
+ callFrameId : <callFrameId>
+ functionLocation : {
+ columnNumber : 16
+ lineNumber : 4
+ scriptId : <scriptId>
+ }
+ functionName : A
+ location : {
+ columnNumber : 6
+ lineNumber : 5
+ scriptId : <scriptId>
+ }
+ scopeChain : [
+ [0] : {
+ endLocation : {
+ columnNumber : 5
+ lineNumber : 6
+ scriptId : <scriptId>
+ }
+ name : A
+ object : {
+ className : Object
+ description : Object
+ objectId : <objectId>
+ type : object
+ }
+ startLocation : {
+ columnNumber : 16
+ lineNumber : 4
+ scriptId : <scriptId>
+ }
+ type : local
+ }
+ [1] : {
+ object : {
+ className : global
+ description : global
+ objectId : <objectId>
+ type : object
+ }
+ type : global
+ }
+ ]
+ this : {
+ className : A
+ description : A
+ objectId : <objectId>
+ type : object
+ }
+ url :
+ }
+ [1] : {
+ callFrameId : <callFrameId>
+ functionLocation : {
+ columnNumber : 12
+ lineNumber : 1
+ scriptId : <scriptId>
+ }
+ functionName : run
+ location : {
+ columnNumber : 2
+ lineNumber : 8
+ scriptId : <scriptId>
+ }
+ scopeChain : [
+ [0] : {
+ endLocation : {
+ columnNumber : 1
+ lineNumber : 9
+ scriptId : <scriptId>
+ }
+ name : run
+ object : {
+ className : Object
+ description : Object
+ objectId : <objectId>
+ type : object
+ }
+ startLocation : {
+ columnNumber : 12
+ lineNumber : 1
+ scriptId : <scriptId>
+ }
+ type : local
+ }
+ [1] : {
+ object : {
+ className : global
+ description : global
+ objectId : <objectId>
+ type : object
+ }
+ type : global
+ }
+ ]
+ this : {
+ className : global
+ description : global
+ objectId : <objectId>
+ type : object
+ }
+ url :
+ }
+ [2] : {
+ callFrameId : <callFrameId>
+ functionLocation : {
+ columnNumber : 0
+ lineNumber : 0
+ scriptId : <scriptId>
+ }
+ functionName :
+ location : {
+ columnNumber : 0
+ lineNumber : 0
+ scriptId : <scriptId>
+ }
+ scopeChain : [
+ [0] : {
+ object : {
+ className : global
+ description : global
+ objectId : <objectId>
+ type : object
+ }
+ type : global
+ }
+ ]
+ this : {
+ className : global
+ description : global
+ objectId : <objectId>
+ type : object
+ }
+ url :
+ }
+]
diff --git a/deps/v8/test/inspector/debugger/class-private-fields-scopes.js b/deps/v8/test/inspector/debugger/class-private-fields-scopes.js
new file mode 100644
index 0000000000..11bea38f0e
--- /dev/null
+++ b/deps/v8/test/inspector/debugger/class-private-fields-scopes.js
@@ -0,0 +1,32 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+let { session, contextGroup, Protocol } = InspectorTest.start(
+ "Test private class fields in scopes"
+);
+
+contextGroup.addScript(`
+function run() {
+ class A {
+ #foo = "hello"
+ constructor () {
+ debugger;
+ }
+ };
+ new A();
+}`);
+
+InspectorTest.runAsyncTestSuite([
+ async function testScopesPaused() {
+ Protocol.Debugger.enable();
+ Protocol.Runtime.evaluate({ expression: "run()" });
+
+ let {
+ params: { callFrames }
+ } = await Protocol.Debugger.oncePaused(); // inside A()
+ InspectorTest.logMessage(callFrames);
+ Protocol.Debugger.resume();
+ Protocol.Debugger.disable();
+ }
+]);
diff --git a/deps/v8/test/inspector/debugger/object-preview-internal-properties-expected.txt b/deps/v8/test/inspector/debugger/object-preview-internal-properties-expected.txt
index 2334213124..d21ebc783e 100644
--- a/deps/v8/test/inspector/debugger/object-preview-internal-properties-expected.txt
+++ b/deps/v8/test/inspector/debugger/object-preview-internal-properties-expected.txt
@@ -259,6 +259,7 @@ expression: Promise.resolve(42)
value : 42
}
+
Running test: privateNames
expression: new class { #foo = 1; #bar = 2; baz = 3;}
{
@@ -295,3 +296,18 @@ expression: new class extends class { #baz = 3; } { #foo = 1; #bar = 2; }
}
expression: new class extends class { constructor() { return new Proxy({}, {}); } } { #foo = 1; #bar = 2; }
+
+
+Running test: functionProxy
+expression: new Proxy(() => {}, { get: () => x++ })
+{
+ name : length
+ type : number
+ value : 0
+}
+{
+ name : name
+ type : string
+ value :
+}
+
diff --git a/deps/v8/test/inspector/debugger/object-preview-internal-properties.js b/deps/v8/test/inspector/debugger/object-preview-internal-properties.js
index cfbdba816b..f542683aa4 100644
--- a/deps/v8/test/inspector/debugger/object-preview-internal-properties.js
+++ b/deps/v8/test/inspector/debugger/object-preview-internal-properties.js
@@ -82,6 +82,12 @@ InspectorTest.runTestSuite([
.then(() => checkExpression("new class extends class { #baz = 3; } { #foo = 1; #bar = 2; }"))
.then(() => checkExpression("new class extends class { constructor() { return new Proxy({}, {}); } } { #foo = 1; #bar = 2; }"))
.then(next);
+ },
+
+ function functionProxy(next)
+ {
+ checkExpression("new Proxy(() => {}, { get: () => x++ })")
+ .then(next);
}
]);
diff --git a/deps/v8/test/inspector/runtime/await-promise-expected.txt b/deps/v8/test/inspector/runtime/await-promise-expected.txt
index 2b906dd49b..975ef8177e 100644
--- a/deps/v8/test/inspector/runtime/await-promise-expected.txt
+++ b/deps/v8/test/inspector/runtime/await-promise-expected.txt
@@ -19,10 +19,22 @@ Running test: testRejectedPromise
exceptionDetails : {
columnNumber : 0
exception : {
- type : object
- value : {
- a : 1
+ className : Object
+ description : Object
+ objectId : <objectId>
+ preview : {
+ description : Object
+ overflow : false
+ properties : [
+ [0] : {
+ name : a
+ type : number
+ value : 1
+ }
+ ]
+ type : object
}
+ type : object
}
exceptionId : <exceptionId>
lineNumber : 0
diff --git a/deps/v8/test/inspector/runtime/call-function-on-async-expected.txt b/deps/v8/test/inspector/runtime/call-function-on-async-expected.txt
index 1a64b576c3..f98fc43bf9 100644
--- a/deps/v8/test/inspector/runtime/call-function-on-async-expected.txt
+++ b/deps/v8/test/inspector/runtime/call-function-on-async-expected.txt
@@ -166,10 +166,22 @@ Running test: testFunctionReturnRejectedPromise
exceptionDetails : {
columnNumber : 0
exception : {
- type : object
- value : {
- a : 3
+ className : Object
+ description : Object
+ objectId : <objectId>
+ preview : {
+ description : Object
+ overflow : false
+ properties : [
+ [0] : {
+ name : a
+ type : number
+ value : 3
+ }
+ ]
+ type : object
}
+ type : object
}
exceptionId : <exceptionId>
lineNumber : 0
@@ -204,3 +216,75 @@ Running test: testPassingBothObjectIdAndExecutionContextId
}
id : <messageId>
}
+
+Running test: testThrowNumber
+{
+ id : <messageId>
+ result : {
+ exceptionDetails : {
+ columnNumber : 10
+ exception : {
+ description : 100500
+ type : number
+ value : 100500
+ }
+ exceptionId : <exceptionId>
+ lineNumber : 0
+ scriptId : <scriptId>
+ stackTrace : {
+ callFrames : [
+ [0] : {
+ columnNumber : 10
+ functionName :
+ lineNumber : 0
+ scriptId : <scriptId>
+ url :
+ }
+ ]
+ }
+ text : Uncaught
+ }
+ result : {
+ description : 100500
+ type : number
+ value : 100500
+ }
+ }
+}
+
+Running test: testAsyncFunctionWithUnknownReferenceReturnByValue
+{
+ id : <messageId>
+ result : {
+ exceptionDetails : {
+ columnNumber : 30
+ exception : {
+ className : ReferenceError
+ description : ReferenceError: does_not_exist is not defined at <anonymous>:1:30
+ objectId : <objectId>
+ subtype : error
+ type : object
+ }
+ exceptionId : <exceptionId>
+ lineNumber : 1
+ scriptId : <scriptId>
+ stackTrace : {
+ callFrames : [
+ [0] : {
+ columnNumber : 29
+ functionName :
+ lineNumber : 0
+ scriptId : <scriptId>
+ url :
+ }
+ ]
+ }
+ text : Uncaught (in promise) ReferenceError: does_not_exist is not defined
+ }
+ result : {
+ type : object
+ value : {
+ }
+ }
+ }
+}
diff --git a/deps/v8/test/inspector/runtime/call-function-on-async.js b/deps/v8/test/inspector/runtime/call-function-on-async.js
index ab146e1c4d..70f823c52c 100644
--- a/deps/v8/test/inspector/runtime/call-function-on-async.js
+++ b/deps/v8/test/inspector/runtime/call-function-on-async.js
@@ -146,6 +146,28 @@ let testSuite = [
awaitPromise: false
}));
},
+
+ async function testThrowNumber() {
+ InspectorTest.logMessage(await callFunctionOn({
+ executionContextId,
+ functionDeclaration: '(() => { throw 100500; } )',
+ arguments: prepareArguments([]),
+ returnByValue: true,
+ generatePreview: false,
+ awaitPromise: true
+ }));
+ },
+
+ async function testAsyncFunctionWithUnknownReferenceReturnByValue() {
+ InspectorTest.logMessage(await callFunctionOn({
+ executionContextId,
+ functionDeclaration: '(async () => does_not_exist.click())',
+ arguments: prepareArguments([]),
+ returnByValue: true,
+ generatePreview: false,
+ awaitPromise: true
+ }));
+ },
];
function prepareArguments(args) {
diff --git a/deps/v8/test/inspector/runtime/console-table-expected.txt b/deps/v8/test/inspector/runtime/console-table-expected.txt
index e00708b587..aa6b456b93 100644
--- a/deps/v8/test/inspector/runtime/console-table-expected.txt
+++ b/deps/v8/test/inspector/runtime/console-table-expected.txt
@@ -383,3 +383,97 @@ preview:
type : object
}
+{
+ description : Array(2)
+ overflow : false
+ properties : [
+ [0] : {
+ name : 0
+ type : object
+ value : Object
+ valuePreview : {
+ description : Object
+ overflow : false
+ properties : [
+ [0] : {
+ name : c
+ type : number
+ value : 3
+ }
+ [1] : {
+ name : b
+ type : number
+ value : 2
+ }
+ ]
+ type : object
+ }
+ }
+ [1] : {
+ name : 1
+ type : object
+ value : Object
+ valuePreview : {
+ description : Object
+ overflow : false
+ properties : [
+ [0] : {
+ name : c
+ type : number
+ value : 3
+ }
+ ]
+ type : object
+ }
+ }
+ ]
+ subtype : array
+ type : object
+}
+{
+ description : Array(2)
+ overflow : false
+ properties : [
+ [0] : {
+ name : 0
+ type : object
+ value : Object
+ valuePreview : {
+ description : Object
+ overflow : false
+ properties : [
+ [0] : {
+ name : c
+ type : number
+ value : 3
+ }
+ [1] : {
+ name : b
+ type : number
+ value : 2
+ }
+ ]
+ type : object
+ }
+ }
+ [1] : {
+ name : 1
+ type : object
+ value : Object
+ valuePreview : {
+ description : Object
+ overflow : false
+ properties : [
+ [0] : {
+ name : c
+ type : number
+ value : 3
+ }
+ ]
+ type : object
+ }
+ }
+ ]
+ subtype : array
+ type : object
+}
diff --git a/deps/v8/test/inspector/runtime/console-table.js b/deps/v8/test/inspector/runtime/console-table.js
index 70e3548c14..961499dfac 100644
--- a/deps/v8/test/inspector/runtime/console-table.js
+++ b/deps/v8/test/inspector/runtime/console-table.js
@@ -65,6 +65,18 @@ const { session, contextGroup, Protocol } =
console.table(bigTable);`
});
await waitConsoleAPICalledAndDump(true /* concise */);
+ Protocol.Runtime.evaluate({
+ expression: `var table = [{a:1, b:2, c:3}, {c:3}];
+ var filter = ['c', 'b'];
+ console.table(table, filter);`
+ });
+ await waitConsoleAPICalledAndDump();
+ Protocol.Runtime.evaluate({
+ expression: `var table = [{a:1, b:2, c:3}, {c:3}];
+ var filter = ['c', 'b', 'c'];
+ console.table(table, filter);`
+ });
+ await waitConsoleAPICalledAndDump();
InspectorTest.completeTest();
})()
diff --git a/deps/v8/test/inspector/runtime/evaluate-new-function-error-expected.txt b/deps/v8/test/inspector/runtime/evaluate-new-function-error-expected.txt
new file mode 100644
index 0000000000..70191eac96
--- /dev/null
+++ b/deps/v8/test/inspector/runtime/evaluate-new-function-error-expected.txt
@@ -0,0 +1,27 @@
+Tests that Runtime.evaluate has the correct error line number for 'new Function(...)'
+{
+ id : <messageId>
+ result : {
+ exceptionDetails : {
+ columnNumber : 3
+ exception : {
+ className : TypeError
+ description : TypeError: 0 is not a function at eval (eval at <anonymous> (:1:1), <anonymous>:1:4) at <anonymous>:1:22
+ objectId : <objectId>
+ subtype : error
+ type : object
+ }
+ exceptionId : <exceptionId>
+ lineNumber : 0
+ scriptId : <scriptId>
+ text : Uncaught
+ }
+ result : {
+ className : TypeError
+ description : TypeError: 0 is not a function at eval (eval at <anonymous> (:1:1), <anonymous>:1:4) at <anonymous>:1:22
+ objectId : <objectId>
+ subtype : error
+ type : object
+ }
+ }
+}
diff --git a/deps/v8/test/inspector/runtime/evaluate-new-function-error.js b/deps/v8/test/inspector/runtime/evaluate-new-function-error.js
new file mode 100644
index 0000000000..bb878d957a
--- /dev/null
+++ b/deps/v8/test/inspector/runtime/evaluate-new-function-error.js
@@ -0,0 +1,11 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+let {session, contextGroup, Protocol} = InspectorTest.start("Tests that Runtime.evaluate has the correct error line number for 'new Function(...)'");
+
+var message = { expression: "new Function('(0)()')();" };
+
+Protocol.Runtime.evaluate(message)
+ .then(message => InspectorTest.logMessage(message))
+ .then(() => InspectorTest.completeTest());
diff --git a/deps/v8/test/inspector/runtime/remote-object-expected.txt b/deps/v8/test/inspector/runtime/remote-object-expected.txt
index d05401ddfb..98fe47beed 100644
--- a/deps/v8/test/inspector/runtime/remote-object-expected.txt
+++ b/deps/v8/test/inspector/runtime/remote-object-expected.txt
@@ -1436,6 +1436,18 @@ Running test: testCustomError
}
}
+Running test: testCustomErrorWithMessage
+'class CustomMsgError extends Error {}; a = new CustomMsgError(); delete a.stack; a.message = 'foobar'; a', returnByValue: false, generatePreview: false
+{
+ result : {
+ className : CustomMsgError
+ description : CustomMsgError: foobar
+ objectId : <objectId>
+ subtype : error
+ type : object
+ }
+}
+
Running test: testProxy
'new Proxy({}, {})', returnByValue: false, generatePreview: false
{
diff --git a/deps/v8/test/inspector/runtime/remote-object.js b/deps/v8/test/inspector/runtime/remote-object.js
index ed35f0eff6..78926479ae 100644
--- a/deps/v8/test/inspector/runtime/remote-object.js
+++ b/deps/v8/test/inspector/runtime/remote-object.js
@@ -419,6 +419,11 @@ InspectorTest.runAsyncTestSuite([
expression: `class CustomError extends Error {}; a = new CustomError(); delete a.stack; a`
})).result);
},
+ async function testCustomErrorWithMessage() {
+ InspectorTest.logMessage((await evaluate( {
+ expression: `class CustomMsgError extends Error {}; a = new CustomMsgError(); delete a.stack; a.message = 'foobar'; a`
+ })).result);
+ },
async function testProxy() {
InspectorTest.logMessage((await evaluate({
expression: 'new Proxy({}, {})'
diff --git a/deps/v8/test/inspector/runtime/run-script-async-expected.txt b/deps/v8/test/inspector/runtime/run-script-async-expected.txt
index 8befa1399c..5b94305081 100644
--- a/deps/v8/test/inspector/runtime/run-script-async-expected.txt
+++ b/deps/v8/test/inspector/runtime/run-script-async-expected.txt
@@ -172,10 +172,22 @@ Running test: testAwaitRejectedPromise
exceptionDetails : {
columnNumber : 0
exception : {
- type : object
- value : {
- a : 1
+ className : Object
+ description : Object
+ objectId : <objectId>
+ preview : {
+ description : Object
+ overflow : false
+ properties : [
+ [0] : {
+ name : a
+ type : number
+ value : 1
+ }
+ ]
+ type : object
}
+ type : object
}
exceptionId : <exceptionId>
lineNumber : 0
diff --git a/deps/v8/test/inspector/runtime/terminate-execution-expected.txt b/deps/v8/test/inspector/runtime/terminate-execution-expected.txt
index 24df70ebb6..614dc6da1e 100644
--- a/deps/v8/test/inspector/runtime/terminate-execution-expected.txt
+++ b/deps/v8/test/inspector/runtime/terminate-execution-expected.txt
@@ -64,3 +64,10 @@ Pause inside microtask and terminate execution
}
}
}
+Terminate execution with pending microtasks
+{
+ id : <messageId>
+ result : {
+ }
+}
+
diff --git a/deps/v8/test/inspector/runtime/terminate-execution.js b/deps/v8/test/inspector/runtime/terminate-execution.js
index feaf52eb2c..8af28e4787 100644
--- a/deps/v8/test/inspector/runtime/terminate-execution.js
+++ b/deps/v8/test/inspector/runtime/terminate-execution.js
@@ -55,6 +55,18 @@ let {session, contextGroup, Protocol} =
.then(InspectorTest.logMessage);
await Protocol.Debugger.disable();
+ InspectorTest.log('Terminate execution with pending microtasks');
+ Protocol.Debugger.enable();
+ const paused2 = Protocol.Debugger.oncePaused();
+ Protocol.Runtime.evaluate({expression: `
+ Promise.resolve().then(() => { console.log('FAIL: microtask ran'); });
+ debugger;
+ for (;;) {}
+ `});
+ await paused2;
+ Protocol.Runtime.terminateExecution().then(InspectorTest.logMessage);
+ await Protocol.Debugger.resume();
+
await Protocol.Runtime.disable();
InspectorTest.completeTest();
})();
diff --git a/deps/v8/test/inspector/task-runner.cc b/deps/v8/test/inspector/task-runner.cc
index d76de0d323..1476b0f64c 100644
--- a/deps/v8/test/inspector/task-runner.cc
+++ b/deps/v8/test/inspector/task-runner.cc
@@ -43,7 +43,7 @@ TaskRunner::TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks,
process_queue_semaphore_(0),
nested_loop_count_(0),
is_terminated_(0) {
- Start();
+ CHECK(Start());
}
TaskRunner::~TaskRunner() { Join(); }
diff --git a/deps/v8/test/intl/number-format/unified/style-unit.js b/deps/v8/test/intl/number-format/unified/style-unit.js
index b88af0fb76..72eb0a782d 100644
--- a/deps/v8/test/intl/number-format/unified/style-unit.js
+++ b/deps/v8/test/intl/number-format/unified/style-unit.js
@@ -24,6 +24,7 @@ assertEquals(undefined, nf.resolvedOptions().unit);
assertThrows(() => new Intl.NumberFormat("en", {style: 'unit'}), TypeError);
const validUnits = [
+ // IsSanctionedSimpleUnitIdentifier
'acre',
'bit',
'byte',
@@ -32,7 +33,9 @@ const validUnits = [
'day',
'degree',
'fahrenheit',
+ 'fluid-ounce',
'foot',
+ 'gallon',
'gigabit',
'gigabyte',
'gram',
@@ -43,12 +46,14 @@ const validUnits = [
'kilobyte',
'kilogram',
'kilometer',
+ 'liter',
'megabit',
'megabyte',
'meter',
'mile-scandinavian',
'mile',
'millimeter',
+ 'milliliter',
'millisecond',
'minute',
'month',
@@ -68,6 +73,9 @@ const validUnits = [
'meter-per-second',
'yard-per-second',
'yard-per-hour',
+ // -per- in IsWellFormedUnitIdentifier
+ 'liter-per-kilometer',
+ 'mile-per-gallon',
];
for (const unit of validUnits) {
@@ -103,12 +111,10 @@ assertThrows(() => c('day-person'), RangeError);
assertThrows(() => c('deciliter'), RangeError);
assertThrows(() => c('decimeter'), RangeError);
assertThrows(() => c('fathom'), RangeError);
-assertThrows(() => c('fluid-ounce'), RangeError);
assertThrows(() => c('foodcalorie'), RangeError);
assertThrows(() => c('furlong'), RangeError);
assertThrows(() => c('g-force'), RangeError);
assertThrows(() => c('gallon-imperial'), RangeError);
-assertThrows(() => c('gallon'), RangeError);
assertThrows(() => c('generic'), RangeError);
assertThrows(() => c('gigahertz'), RangeError);
assertThrows(() => c('gigawatt'), RangeError);
@@ -128,8 +134,6 @@ assertThrows(() => c('kilowatt'), RangeError);
assertThrows(() => c('knot'), RangeError);
assertThrows(() => c('light-year'), RangeError);
assertThrows(() => c('liter-per-100kilometers'), RangeError);
-assertThrows(() => c('liter-per-kilometer'), RangeError);
-assertThrows(() => c('liter'), RangeError);
assertThrows(() => c('lux'), RangeError);
assertThrows(() => c('megahertz'), RangeError);
assertThrows(() => c('megaliter'), RangeError);
@@ -140,12 +144,10 @@ assertThrows(() => c('microgram'), RangeError);
assertThrows(() => c('micrometer'), RangeError);
assertThrows(() => c('microsecond'), RangeError);
assertThrows(() => c('mile-per-gallon-imperial'), RangeError);
-assertThrows(() => c('mile-per-gallon'), RangeError);
assertThrows(() => c('milliampere'), RangeError);
assertThrows(() => c('millibar'), RangeError);
assertThrows(() => c('milligram-per-deciliter'), RangeError);
assertThrows(() => c('milligram'), RangeError);
-assertThrows(() => c('milliliter'), RangeError);
assertThrows(() => c('millimeter-of-mercury'), RangeError);
assertThrows(() => c('millimole-per-liter'), RangeError);
assertThrows(() => c('milliwatt'), RangeError);
diff --git a/deps/v8/test/intl/regress-9475.js b/deps/v8/test/intl/regress-9475.js
new file mode 100644
index 0000000000..3549ef8f38
--- /dev/null
+++ b/deps/v8/test/intl/regress-9475.js
@@ -0,0 +1,62 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-intl-numberformat-unified
+// Test format of all valid units won't throw exception.
+
+let validList = [
+ // IsSanctionedSimpleUnitIdentifier
+ 'acre',
+ 'bit',
+ 'byte',
+ 'celsius',
+ 'centimeter',
+ 'day',
+ 'degree',
+ 'fahrenheit',
+ 'fluid-ounce',
+ 'foot',
+ 'gallon',
+ 'gigabit',
+ 'gigabyte',
+ 'gram',
+ 'hectare',
+ 'hour',
+ 'inch',
+ 'kilobit',
+ 'kilobyte',
+ 'kilogram',
+ 'kilometer',
+ 'liter',
+ 'megabit',
+ 'megabyte',
+ 'meter',
+ 'mile',
+ 'mile-scandinavian',
+ 'millimeter',
+ 'milliliter',
+ 'millisecond',
+ 'minute',
+ 'month',
+ 'ounce',
+ 'percent',
+ 'petabyte',
+ 'pound',
+ 'second',
+ 'stone',
+ 'terabit',
+ 'terabyte',
+ 'week',
+ 'yard',
+ 'year',
+ // -per- in IsWellFormedUnitIdentifier
+ 'liter-per-kilometer',
+ 'mile-per-gallon',
+];
+
+for (let unit of validList) {
+ let nf = new Intl.NumberFormat("en", {style: "unit", unit});
+ assertDoesNotThrow(() => nf.format(123.45),
+ "unit: '" + unit + "' should not throw");
+}
diff --git a/deps/v8/test/intl/regress-9642.js b/deps/v8/test/intl/regress-9642.js
new file mode 100644
index 0000000000..9091ffb125
--- /dev/null
+++ b/deps/v8/test/intl/regress-9642.js
@@ -0,0 +1,8 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Environment Variables: LANG=lb_LU
+// Test creation of Intl.DateTimeFormat under not installed locale.
+
+let dtf = new Intl.DateTimeFormat();
diff --git a/deps/v8/test/js-perf-test/IC/loadconstantfromprototype.js b/deps/v8/test/js-perf-test/IC/loadconstantfromprototype.js
new file mode 100644
index 0000000000..deb0a81762
--- /dev/null
+++ b/deps/v8/test/js-perf-test/IC/loadconstantfromprototype.js
@@ -0,0 +1,23 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+new BenchmarkSuite('LoadConstantFromPrototype', [1000], [
+ new Benchmark('LoadConstantFromPrototype', false, false, 0, LoadConstantFromPrototype)
+]);
+
+function Foo() {};
+
+Foo.prototype.bar = {};
+Foo.prototype.covfefe = function() {};
+Foo.prototype.baz = 1;
+
+function LoadConstantFromPrototype() {
+ let foo = new Foo();
+
+ for (let i = 0; i < 1000; ++i) {
+ foo.bar;
+ foo.covfefe;
+ foo.baz;
+ }
+}
diff --git a/deps/v8/test/js-perf-test/IC/run.js b/deps/v8/test/js-perf-test/IC/run.js
new file mode 100644
index 0000000000..254799c7d3
--- /dev/null
+++ b/deps/v8/test/js-perf-test/IC/run.js
@@ -0,0 +1,24 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+load('../base.js');
+
+load('loadconstantfromprototype.js');
+
+function PrintResult(name, result) {
+ print(name + '-IC(Score): ' + result);
+}
+
+function PrintStep(name) {}
+
+function PrintError(name, error) {
+ PrintResult(name, error);
+}
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+ NotifyError: PrintError,
+ NotifyStep: PrintStep });
diff --git a/deps/v8/test/js-perf-test/JSTests5.json b/deps/v8/test/js-perf-test/JSTests5.json
index 66504bf575..6d42cbdda9 100644
--- a/deps/v8/test/js-perf-test/JSTests5.json
+++ b/deps/v8/test/js-perf-test/JSTests5.json
@@ -618,6 +618,18 @@
{"name": "Inline-Serialize-Error.stack"},
{"name": "Recursive-Serialize-Error.stack"}
]
+ },
+ {
+ "name": "IC",
+ "path": ["IC"],
+ "main": "run.js",
+ "flags": ["--no-opt"],
+ "resources": ["loadconstantfromprototype.js"],
+ "results_regexp": "^%s\\-IC\\(Score\\): (.+)$",
+ "tests": [
+ {"name": "LoadConstantFromPrototype"
+ }
+ ]
}
]
}
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-getter-count.js b/deps/v8/test/message/fail/class-accessors-private-undefined-getter-count.js
new file mode 100644
index 0000000000..35f30accdf
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-getter-count.js
@@ -0,0 +1,14 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-private-methods
+
+class C {
+ set #foo(val) {}
+ constructor() {
+ this.#foo++;
+ }
+}
+
+new C();
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-getter-count.out b/deps/v8/test/message/fail/class-accessors-private-undefined-getter-count.out
new file mode 100644
index 0000000000..f6328b9c43
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-getter-count.out
@@ -0,0 +1,9 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:10: TypeError: '#foo' was defined without a getter
+ this.#foo++;
+ ^
+TypeError: '#foo' was defined without a getter
+ at new C (*%(basename)s:10:5)
+ at *%(basename)s:14:1
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-getter-nested.js b/deps/v8/test/message/fail/class-accessors-private-undefined-getter-nested.js
new file mode 100644
index 0000000000..680c1bba74
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-getter-nested.js
@@ -0,0 +1,19 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-private-methods
+
+class C {
+ set #a(val) {}
+ setA(obj, val) { obj.#a = val; }
+
+ constructor() {
+ class D {
+ get #a() {}
+ }
+ this.setA(new D(), 1);
+ }
+}
+
+new C;
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-getter-nested.out b/deps/v8/test/message/fail/class-accessors-private-undefined-getter-nested.out
new file mode 100644
index 0000000000..ca3154a26b
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-getter-nested.out
@@ -0,0 +1,10 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:9: TypeError: Cannot read private member C from an object whose class did not declare it
+ setA(obj, val) { obj.#a = val; }
+ ^
+TypeError: Cannot read private member C from an object whose class did not declare it
+ at C.setA (*%(basename)s:9:24)
+ at new C (*%(basename)s:15:10)
+ at *%(basename)s:19:1 \ No newline at end of file
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-getter.js b/deps/v8/test/message/fail/class-accessors-private-undefined-getter.js
new file mode 100644
index 0000000000..9422739f7d
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-getter.js
@@ -0,0 +1,13 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-private-methods
+
+class C {
+ set #a(val) {}
+ constructor() {
+ const a = this.#a;
+ }
+}
+new C;
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-getter.out b/deps/v8/test/message/fail/class-accessors-private-undefined-getter.out
new file mode 100644
index 0000000000..c41451c3af
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-getter.out
@@ -0,0 +1,9 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:10: TypeError: '#a' was defined without a getter
+ const a = this.#a;
+ ^
+TypeError: '#a' was defined without a getter
+ at new C (*%(basename)s:10:15)
+ at *%(basename)s:13:1
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-setter-compound.js b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-compound.js
new file mode 100644
index 0000000000..2a1f05767f
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-compound.js
@@ -0,0 +1,13 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-private-methods
+
+class C {
+ get #a() {}
+ constructor() {
+ this.#a = 1;
+ }
+}
+new C;
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-setter-compound.out b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-compound.out
new file mode 100644
index 0000000000..a98f4707d4
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-compound.out
@@ -0,0 +1,9 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:10: TypeError: '#a' was defined without a setter
+ this.#a = 1;
+ ^
+TypeError: '#a' was defined without a setter
+ at new C (*%(basename)s:10:13)
+ at *%(basename)s:13:1
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-setter-count.js b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-count.js
new file mode 100644
index 0000000000..33367c7ef9
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-count.js
@@ -0,0 +1,14 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-private-methods
+
+class C {
+ get #foo() {}
+ constructor() {
+ this.#foo++;
+ }
+}
+
+new C();
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-setter-count.out b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-count.out
new file mode 100644
index 0000000000..787a00019a
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-count.out
@@ -0,0 +1,9 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:10: TypeError: '#foo' was defined without a setter
+ this.#foo++;
+ ^
+TypeError: '#foo' was defined without a setter
+ at new C (*%(basename)s:10:5)
+ at *%(basename)s:14:1
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-setter-nested.js b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-nested.js
new file mode 100644
index 0000000000..2f28fc26f3
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-nested.js
@@ -0,0 +1,19 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-private-methods
+
+class C {
+ get #a() {}
+ getA(obj) { return obj.#a; }
+
+ constructor() {
+ class D {
+ set #a(val) {}
+ }
+ this.getA(new D());
+ }
+}
+
+new C;
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-setter-nested.out b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-nested.out
new file mode 100644
index 0000000000..5f22848692
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-setter-nested.out
@@ -0,0 +1,10 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:9: TypeError: Cannot read private member C from an object whose class did not declare it
+ getA(obj) { return obj.#a; }
+ ^
+TypeError: Cannot read private member C from an object whose class did not declare it
+ at C.getA (*%(basename)s:9:26)
+ at new C (*%(basename)s:15:10)
+ at *%(basename)s:19:1
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-setter.js b/deps/v8/test/message/fail/class-accessors-private-undefined-setter.js
new file mode 100644
index 0000000000..2a1f05767f
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-setter.js
@@ -0,0 +1,13 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-private-methods
+
+class C {
+ get #a() {}
+ constructor() {
+ this.#a = 1;
+ }
+}
+new C;
diff --git a/deps/v8/test/message/fail/class-accessors-private-undefined-setter.out b/deps/v8/test/message/fail/class-accessors-private-undefined-setter.out
new file mode 100644
index 0000000000..a5c56ca4d0
--- /dev/null
+++ b/deps/v8/test/message/fail/class-accessors-private-undefined-setter.out
@@ -0,0 +1,9 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:10: TypeError: '#a' was defined without a setter
+ this.#a = 1;
+ ^
+TypeError: '#a' was defined without a setter
+ at new C (*%(basename)s:10:13)
+ at *%(basename)s:13:1 \ No newline at end of file
diff --git a/deps/v8/test/message/fail/class-fields-private-source-positions.out b/deps/v8/test/message/fail/class-fields-private-source-positions.out
index 7c2f99964b..6be1fd89f8 100644
--- a/deps/v8/test/message/fail/class-fields-private-source-positions.out
+++ b/deps/v8/test/message/fail/class-fields-private-source-positions.out
@@ -1,5 +1,5 @@
-*%(basename)s:9: TypeError: Read of private field #a from an object which did not contain the field
+*%(basename)s:9: TypeError: Cannot read private member #a from an object whose class did not declare it
[o.#a](){}
^
-TypeError: Read of private field #a from an object which did not contain the field
+TypeError: Cannot read private member #a from an object whose class did not declare it
at *%(basename)s:9:8
diff --git a/deps/v8/test/message/fail/class-fields-private-throw-early-2.out b/deps/v8/test/message/fail/class-fields-private-throw-early-2.out
index 1cf7bb41ae..9731e7d611 100644
--- a/deps/v8/test/message/fail/class-fields-private-throw-early-2.out
+++ b/deps/v8/test/message/fail/class-fields-private-throw-early-2.out
@@ -1,6 +1,6 @@
-*%(basename)s:8: TypeError: Write of private field #x to an object which did not contain the field
+*%(basename)s:8: TypeError: Cannot write private member #x to an object whose class did not declare it
({}).#x = 1;
^
-TypeError: Write of private field #x to an object which did not contain the field
+TypeError: Cannot write private member #x to an object whose class did not declare it
at new X (*%(basename)s:8:13)
at *%(basename)s:12:1 \ No newline at end of file
diff --git a/deps/v8/test/message/fail/class-fields-private-throw-read.out b/deps/v8/test/message/fail/class-fields-private-throw-read.out
index ec8dcf5108..21823edc44 100644
--- a/deps/v8/test/message/fail/class-fields-private-throw-read.out
+++ b/deps/v8/test/message/fail/class-fields-private-throw-read.out
@@ -1,6 +1,6 @@
-*%(basename)s:7: TypeError: Read of private field #x from an object which did not contain the field
+*%(basename)s:7: TypeError: Cannot read private member #x from an object whose class did not declare it
eq(o) { return this.#x === o.#x; }
^
-TypeError: Read of private field #x from an object which did not contain the field
+TypeError: Cannot read private member #x from an object whose class did not declare it
at X.eq (*%(basename)s:7:32)
at *%(basename)s:10:9 \ No newline at end of file
diff --git a/deps/v8/test/message/fail/class-fields-private-throw-write.out b/deps/v8/test/message/fail/class-fields-private-throw-write.out
index 8d9047cc62..81a73ca239 100644
--- a/deps/v8/test/message/fail/class-fields-private-throw-write.out
+++ b/deps/v8/test/message/fail/class-fields-private-throw-write.out
@@ -1,6 +1,6 @@
-*%(basename)s:7: TypeError: Write of private field #x to an object which did not contain the field
+*%(basename)s:7: TypeError: Cannot write private member #x to an object whose class did not declare it
setX(o, val) { o.#x = val; }
^
-TypeError: Write of private field #x to an object which did not contain the field
+TypeError: Cannot write private member #x to an object whose class did not declare it
at X.setX (*%(basename)s:7:23)
at *%(basename)s:10:9 \ No newline at end of file
diff --git a/deps/v8/test/message/fail/destructuring-undefined-computed-property.out b/deps/v8/test/message/fail/destructuring-undefined-computed-property.out
index 1dfb19eb69..326bb30e3b 100644
--- a/deps/v8/test/message/fail/destructuring-undefined-computed-property.out
+++ b/deps/v8/test/message/fail/destructuring-undefined-computed-property.out
@@ -1,5 +1,5 @@
-*%(basename)s:5: TypeError: Cannot destructure 'undefined' or 'null'.
+*%(basename)s:5: TypeError: Cannot destructure 'undefined' as it is undefined.
var { [x] : y } = undefined;
- ^
-TypeError: Cannot destructure 'undefined' or 'null'.
+ ^
+TypeError: Cannot destructure 'undefined' as it is undefined.
at *%(basename)s:5:5
diff --git a/deps/v8/test/message/fail/destructuring-undefined-number-property.out b/deps/v8/test/message/fail/destructuring-undefined-number-property.out
index b23889566a..1fb13a6f00 100644
--- a/deps/v8/test/message/fail/destructuring-undefined-number-property.out
+++ b/deps/v8/test/message/fail/destructuring-undefined-number-property.out
@@ -1,5 +1,5 @@
-*%(basename)s:5: TypeError: Cannot destructure 'undefined' or 'null'.
+*%(basename)s:5: TypeError: Cannot destructure 'undefined' as it is undefined.
var { 1: x } = undefined;
- ^
-TypeError: Cannot destructure 'undefined' or 'null'.
- at *%(basename)s:5:5
+ ^
+TypeError: Cannot destructure 'undefined' as it is undefined.
+ at *%(basename)s:5:10
diff --git a/deps/v8/test/message/fail/destructuring-undefined-string-property.out b/deps/v8/test/message/fail/destructuring-undefined-string-property.out
index 238aae974a..bd0520ba6d 100644
--- a/deps/v8/test/message/fail/destructuring-undefined-string-property.out
+++ b/deps/v8/test/message/fail/destructuring-undefined-string-property.out
@@ -1,5 +1,5 @@
-*%(basename)s:5: TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
+*%(basename)s:5: TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.
var { x } = undefined;
^
-TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
- at *%(basename)s:5:5
+TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.
+ at *%(basename)s:5:7
diff --git a/deps/v8/test/message/regress/fail/regress-9603.js b/deps/v8/test/message/regress/fail/regress-9603.js
new file mode 100644
index 0000000000..4e2fce95fc
--- /dev/null
+++ b/deps/v8/test/message/regress/fail/regress-9603.js
@@ -0,0 +1,5 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+let x = 09_9.0;
diff --git a/deps/v8/test/message/regress/fail/regress-9603.out b/deps/v8/test/message/regress/fail/regress-9603.out
new file mode 100644
index 0000000000..2929a1991d
--- /dev/null
+++ b/deps/v8/test/message/regress/fail/regress-9603.out
@@ -0,0 +1,7 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:5: SyntaxError: Invalid or unexpected token
+let x = 09_9.0;
+ ^
+SyntaxError: Invalid or unexpected token
diff --git a/deps/v8/test/mjsunit/code-coverage-block.js b/deps/v8/test/mjsunit/code-coverage-block.js
index a7bad5bf11..c441342cdf 100644
--- a/deps/v8/test/mjsunit/code-coverage-block.js
+++ b/deps/v8/test/mjsunit/code-coverage-block.js
@@ -434,8 +434,8 @@ TestCoverage(
`,
[{"start":0,"end":399,"count":1},
{"start":1,"end":351,"count":1},
- {"start":154,"end":176,"count":0},
- {"start":254,"end":276,"count":0}]
+ {"start":154,"end":204,"count":0},
+ {"start":226,"end":350,"count":0}]
);
TestCoverage(
@@ -464,8 +464,8 @@ TestCoverage(
`,
[{"start":0,"end":999,"count":1},
{"start":1,"end":951,"count":1},
- {"start":152,"end":168,"count":0},
- {"start":287,"end":310,"count":0}]
+ {"start":152,"end":202,"count":0},
+ {"start":285,"end":353,"count":0}]
);
TestCoverage(
@@ -1052,49 +1052,4 @@ try { // 0500
{"start":69,"end":153,"count":1}]
);
-TestCoverage(
-"https://crbug.com/v8/9705",
-`
-function f(x) { // 0000
- switch (x) { // 0050
- case 40: nop(); // 0100
- case 41: nop(); return 1; // 0150
- case 42: nop(); break; // 0200
- } // 0250
- return 3; // 0300
-}; // 0350
-f(40); // 0400
-f(41); // 0450
-f(42); // 0500
-f(43); // 0550
-`,
-[{"start":0,"end":599,"count":1},
- {"start":0,"end":351,"count":4},
- {"start":104,"end":119,"count":1},
- {"start":154,"end":179,"count":2},
- {"start":204,"end":226,"count":1},
- {"start":253,"end":350,"count":2}]
-);
-
-TestCoverage(
-"https://crbug.com/v8/9705",
-`
-function f(x) { // 0000
- switch (x) { // 0050
- case 40: nop(); // 0100
- case 41: nop(); return 1; // 0150
- case 42: nop(); break; // 0200
- } // 0250
- return 3; // 0300
-}; // 0350
-f(42); // 0400
-f(43); // 0450
-`,
-[{"start":0,"end":499,"count":1},
- {"start":0,"end":351,"count":2},
- {"start":104,"end":119,"count":0},
- {"start":154,"end":179,"count":0},
- {"start":204,"end":226,"count":1}]
-);
-
%DebugToggleBlockCoverage(false);
diff --git a/deps/v8/test/mjsunit/code-coverage-utils.js b/deps/v8/test/mjsunit/code-coverage-utils.js
index 4164f5a314..5783390222 100644
--- a/deps/v8/test/mjsunit/code-coverage-utils.js
+++ b/deps/v8/test/mjsunit/code-coverage-utils.js
@@ -18,40 +18,25 @@ let gen;
return undefined;
};
- function TestCoverageInternal(
- name, source, expectation, collect_garbage, prettyPrintResults) {
+ function TestCoverageInternal(name, source, expectation, collect_garbage) {
source = source.trim();
eval(source);
if (collect_garbage) %CollectGarbage("collect dead objects");
var covfefe = GetCoverage(source);
var stringified_result = JSON.stringify(covfefe);
var stringified_expectation = JSON.stringify(expectation);
- const mismatch = stringified_result != stringified_expectation;
- if (mismatch) {
- console.log(stringified_result.replace(/[}],[{]/g, "},\n {"));
- }
- if (prettyPrintResults) {
- console.log("=== Coverage Expectation ===")
- for (const {start,end,count} of expectation) {
- console.log(`Range [${start}, ${end}) (count: ${count})`);
- console.log(source.substring(start, end));
- }
- console.log("=== Coverage Results ===")
- for (const {start,end,count} of covfefe) {
- console.log(`Range [${start}, ${end}) (count: ${count})`);
- console.log(source.substring(start, end));
- }
- console.log("========================")
+ if (stringified_result != stringified_expectation) {
+ print(stringified_result.replace(/[}],[{]/g, "},\n {"));
}
assertEquals(stringified_expectation, stringified_result, name + " failed");
};
- TestCoverage = function(name, source, expectation, prettyPrintResults) {
- TestCoverageInternal(name, source, expectation, true, prettyPrintResults);
+ TestCoverage = function(name, source, expectation) {
+ TestCoverageInternal(name, source, expectation, true);
};
- TestCoverageNoGC = function(name, source, expectation, prettyPrintResults) {
- TestCoverageInternal(name, source, expectation, false, prettyPrintResults);
+ TestCoverageNoGC = function(name, source, expectation) {
+ TestCoverageInternal(name, source, expectation, false);
};
nop = function() {};
diff --git a/deps/v8/test/mjsunit/compiler/bigint-int64-lowered.js b/deps/v8/test/mjsunit/compiler/bigint-int64-lowered.js
index f669c17c29..abbfa8cfd0 100644
--- a/deps/v8/test/mjsunit/compiler/bigint-int64-lowered.js
+++ b/deps/v8/test/mjsunit/compiler/bigint-int64-lowered.js
@@ -70,6 +70,7 @@ function TestInt64LoweredOperations() {
function OptimizeAndTest(fn) {
%PrepareFunctionForOptimization(fn);
+ %PrepareFunctionForOptimization(assertEquals);
fn();
fn();
%OptimizeFunctionOnNextCall(fn);
diff --git a/deps/v8/test/mjsunit/compiler/dataview-neutered.js b/deps/v8/test/mjsunit/compiler/dataview-detached.js
index b5fe3102c2..b5fe3102c2 100644
--- a/deps/v8/test/mjsunit/compiler/dataview-neutered.js
+++ b/deps/v8/test/mjsunit/compiler/dataview-detached.js
diff --git a/deps/v8/test/mjsunit/compiler/diamond-followedby-branch.js b/deps/v8/test/mjsunit/compiler/diamond-followedby-branch.js
new file mode 100644
index 0000000000..e69a1cbeda
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/diamond-followedby-branch.js
@@ -0,0 +1,22 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+// Check that the branch elimination replace the redundant branch condition with
+// a phi node, and then the branch is folded in EffectControlLinearizationPhase.
+function foo(cond, v1, v2) {
+ cond = cond | 0;
+ var a = cond == 1 ? v1 : v2;
+ if(cond == 1) {
+ %TurbofanStaticAssert(a == v1);
+ } else {
+ %TurbofanStaticAssert(a == v2);
+ }
+}
+
+%PrepareFunctionForOptimization(foo);
+foo(1, 10, 20); foo(2, 30, 40);
+%OptimizeFunctionOnNextCall(foo);
+foo(1, 10, 20); foo(2, 30, 40);
diff --git a/deps/v8/test/mjsunit/compiler/instanceof4.js b/deps/v8/test/mjsunit/compiler/instanceof4.js
new file mode 100644
index 0000000000..5074fb5f64
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/instanceof4.js
@@ -0,0 +1,80 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+
+(function testFunctionPrototypeHasInstance() {
+ class A {};
+ var a = new A;
+
+ function foo() {
+ return A[Symbol.hasInstance](a);
+ };
+
+ %PrepareFunctionForOptimization(foo);
+ assertTrue(foo());
+ assertTrue(foo());
+ %OptimizeFunctionOnNextCall(foo);
+ assertTrue(foo());
+})();
+
+
+(function testFunctionPrototypeHasInstanceWithInference() {
+ class A {};
+ var a = new A;
+ a.bla = 42;
+
+ function foo() {
+ a.bla;
+ return A[Symbol.hasInstance](a);
+ };
+
+ %PrepareFunctionForOptimization(foo);
+ assertTrue(foo());
+ assertTrue(foo());
+ %OptimizeFunctionOnNextCall(foo);
+ assertTrue(foo());
+})();
+
+
+(function testFunctionPrototypeHasInstanceWithBoundFunction() {
+ class A {};
+ var a = new A;
+ var f = A.bind({});
+
+ function foo() {
+ return f[Symbol.hasInstance](a);
+ };
+
+ %PrepareFunctionForOptimization(foo);
+ assertTrue(foo());
+ assertTrue(foo());
+ %OptimizeFunctionOnNextCall(foo);
+ assertTrue(foo());
+
+ // JSCallReducer::ReduceFunctionPrototypeHasInstance ->
+ // JSNative...::ReduceJSOrdinaryHasInstance ->
+ // JSNative...::ReduceJSInstanceOf (on bound_target_function)
+ // ~~~~~>
+ // JSCallReducer::ReduceFunctionPrototypeHasInstance
+ // JSNative...::ReduceJSOrdinaryHasInstance ->
+ // JSNative...::ReduceJSHasInPrototypeChain
+})();
+
+
+(function testSimpleInstanceOf() {
+ class A {};
+ var a = new A;
+
+ function foo() {
+ return a instanceof A;
+ };
+
+ %PrepareFunctionForOptimization(foo);
+ assertTrue(foo());
+ assertTrue(foo());
+ %OptimizeFunctionOnNextCall(foo);
+ assertTrue(foo());
+})();
diff --git a/deps/v8/test/mjsunit/compiler/object-isprototypeof.js b/deps/v8/test/mjsunit/compiler/object-isprototypeof.js
index d8e3c3e796..4e50d01c90 100644
--- a/deps/v8/test/mjsunit/compiler/object-isprototypeof.js
+++ b/deps/v8/test/mjsunit/compiler/object-isprototypeof.js
@@ -160,3 +160,16 @@
%OptimizeFunctionOnNextCall(foo);
assertTrue(foo());
})();
+(function() {
+ function A() {}
+ A.prototype = {};
+ var a = {__proto__: new A, gaga: 42};
+
+ function foo() { a.gaga; return A.prototype.isPrototypeOf(a); }
+
+ %PrepareFunctionForOptimization(foo);
+ assertTrue(foo());
+ assertTrue(foo());
+ %OptimizeFunctionOnNextCall(foo);
+ assertTrue(foo());
+})();
diff --git a/deps/v8/test/mjsunit/compiler/regress-9041.js b/deps/v8/test/mjsunit/compiler/regress-9041.js
index d7a8e6d625..ddbf3e4928 100644
--- a/deps/v8/test/mjsunit/compiler/regress-9041.js
+++ b/deps/v8/test/mjsunit/compiler/regress-9041.js
@@ -5,19 +5,77 @@
// Flags: --allow-natives-syntax
(function() {
-class A {}
-
-function foo(a, fn) {
- const C = a.constructor;
- fn(a);
- return a instanceof C;
-};
-%PrepareFunctionForOptimization(foo);
-assertTrue(foo(new A(), a => {}));
-assertTrue(foo(new A(), a => {}));
-%OptimizeFunctionOnNextCall(foo);
-assertTrue(foo(new A(), a => {}));
-assertFalse(foo(new A(), a => {
- a.__proto__ = {};
-}));
+ class A {};
+
+ function foo(a, fn) {
+ const C = a.constructor;
+ fn(a);
+ return a instanceof C;
+ };
+
+ %PrepareFunctionForOptimization(foo);
+ assertTrue(foo(new A(), a => {}));
+ assertTrue(foo(new A(), a => {}));
+ %OptimizeFunctionOnNextCall(foo);
+ assertTrue(foo(new A(), a => {}));
+ assertFalse(foo(new A(), a => { a.__proto__ = {}; }));
+})();
+
+(function() {
+ class A {};
+ A.__proto__ = {};
+ A.prototype = {};
+
+ function foo() {
+ var x = Object.create(Object.create(Object.create(A.prototype)));
+ return x instanceof A;
+ };
+
+ %PrepareFunctionForOptimization(foo);
+ assertTrue(foo());
+ assertTrue(foo());
+ %OptimizeFunctionOnNextCall(foo);
+ assertTrue(foo());
+})();
+
+(function() {
+ class A {};
+ A.prototype = {};
+ A.__proto__ = {};
+ var a = {__proto__: new A, gaga: 42};
+
+ function foo() {
+ A.bla; // Make A.__proto__ fast again.
+ a.gaga;
+ return a instanceof A;
+ };
+
+ %PrepareFunctionForOptimization(foo);
+ assertTrue(foo());
+ assertTrue(foo());
+ %OptimizeFunctionOnNextCall(foo);
+ assertTrue(foo());
+})();
+
+(function() {
+ class A {};
+ A.prototype = {};
+ A.__proto__ = {};
+ const boundA = Function.prototype.bind.call(A, {});
+ boundA.prototype = {};
+ boundA.__proto__ = {};
+ var a = {__proto__: new boundA, gaga: 42};
+
+ function foo() {
+ A.bla; // Make A.__proto__ fast again.
+ boundA.bla; // Make boundA.__proto__ fast again.
+ a.gaga;
+ return a instanceof boundA;
+ };
+
+ %PrepareFunctionForOptimization(foo);
+ assertTrue(foo());
+ assertTrue(foo());
+ %OptimizeFunctionOnNextCall(foo);
+ assertTrue(foo());
})();
diff --git a/deps/v8/test/mjsunit/compiler/regress-992684.js b/deps/v8/test/mjsunit/compiler/regress-992684.js
new file mode 100644
index 0000000000..55854781a3
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/regress-992684.js
@@ -0,0 +1,26 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --no-lazy-feedback-allocation
+
+function* g(h) {
+ return yield* h;
+}
+
+var f = Object.getPrototypeOf(function*(){}).prototype;
+var t = f.throw;
+const h = (function*(){})();
+h.next = function () { return { }; };
+const x = g(h);
+x.next();
+delete f.throw;
+
+try {
+ t.bind(x)();
+} catch (e) {}
+
+%PrepareFunctionForOptimization(g);
+g();
+%OptimizeFunctionOnNextCall(g);
+g();
diff --git a/deps/v8/test/mjsunit/compiler/regress-995430.js b/deps/v8/test/mjsunit/compiler/regress-995430.js
new file mode 100644
index 0000000000..7df0efcf87
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/regress-995430.js
@@ -0,0 +1,12 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function foo() {
+ x ** -9 === '';
+};
+%PrepareFunctionForOptimization(foo);
+%OptimizeFunctionOnNextCall(foo);
+try { foo() } catch(_) {};
diff --git a/deps/v8/test/mjsunit/compiler/regress-995562.js b/deps/v8/test/mjsunit/compiler/regress-995562.js
new file mode 100644
index 0000000000..332960b360
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/regress-995562.js
@@ -0,0 +1,14 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+(function() {
+ function foo() {
+ return { [bla]() {} };
+ }
+ %PrepareFunctionForOptimization(foo);
+ %OptimizeFunctionOnNextCall(foo);
+ try { foo() } catch(_) {};
+})();
diff --git a/deps/v8/test/mjsunit/compiler/regress-997100.js b/deps/v8/test/mjsunit/compiler/regress-997100.js
new file mode 100644
index 0000000000..7611f6e7b3
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/regress-997100.js
@@ -0,0 +1,15 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function C() { return this };
+function foo() {
+ return new C() instanceof function(){};
+}
+%PrepareFunctionForOptimization(C);
+%PrepareFunctionForOptimization(foo);
+assertFalse(foo());
+%OptimizeFunctionOnNextCall(foo);
+assertFalse(foo());
diff --git a/deps/v8/test/mjsunit/compiler/regress-nonextensiblearray-store-outofbounds.js b/deps/v8/test/mjsunit/compiler/regress-nonextensiblearray-store-outofbounds.js
new file mode 100644
index 0000000000..4d8d64385e
--- /dev/null
+++ b/deps/v8/test/mjsunit/compiler/regress-nonextensiblearray-store-outofbounds.js
@@ -0,0 +1,19 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --opt --no-always-opt
+
+const v3 = [0,"symbol"];
+const v5 = 0 - 1;
+const v6 = Object.preventExtensions(v3);
+let v9 = 0;
+function f1() {
+ v6[119090556] = v5;
+}
+%PrepareFunctionForOptimization(f1);
+f1();
+%OptimizeFunctionOnNextCall(f1);
+f1();
+assertOptimized(f1);
+assertEquals(v6.length, 2);
diff --git a/deps/v8/test/mjsunit/d8/d8-worker-sharedarraybuffer.js b/deps/v8/test/mjsunit/d8/d8-worker-sharedarraybuffer.js
index f166ca2eb1..049348856d 100644
--- a/deps/v8/test/mjsunit/d8/d8-worker-sharedarraybuffer.js
+++ b/deps/v8/test/mjsunit/d8/d8-worker-sharedarraybuffer.js
@@ -55,7 +55,7 @@ if (this.Worker) {
// Clone SharedArrayBuffer
w.postMessage(sab);
- assertEquals(16, sab.byteLength); // ArrayBuffer should not be neutered.
+ assertEquals(16, sab.byteLength); // ArrayBuffer should not be detached.
// Spinwait for the worker to update ta[0]
var ta0;
@@ -65,7 +65,7 @@ if (this.Worker) {
w.terminate();
- assertEquals(16, sab.byteLength); // Still not neutered.
+ assertEquals(16, sab.byteLength); // Still not detached.
})();
(function TestCloneMulti() {
diff --git a/deps/v8/test/mjsunit/d8/d8-worker-shutdown-empty.js b/deps/v8/test/mjsunit/d8/d8-worker-shutdown-empty.js
new file mode 100644
index 0000000000..360e36ef08
--- /dev/null
+++ b/deps/v8/test/mjsunit/d8/d8-worker-shutdown-empty.js
@@ -0,0 +1,42 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --stress-runs=1
+
+const kBatchSize = 10;
+const kNumBatches = 10;
+
+function RunWorkerBatch(count) {
+ let script = `postMessage(42)`;
+
+ // Launch workers.
+ let workers = new Array(count);
+ for (let i = 0; i < count; i++) {
+ workers[i] = new Worker(script, {type : 'string'});
+ }
+
+ // Terminate half of the workers early.
+ for (let i = 0; i < workers.length; i++) {
+ if ((i & 1) == 1) workers[i].terminate();
+ }
+
+ // Get messages from some workers.
+ for (let i = 0; i < workers.length; i++) {
+ let msg = workers[i].getMessage();
+ assertTrue(msg === undefined || msg === 42);
+ // terminate all workers.
+ workers[i].terminate();
+ }
+}
+
+(function RunTest() {
+ print(`running ${kNumBatches} batches...`);
+ let time = performance.now();
+ for (let i = 0; i < kNumBatches; i++) {
+ let before = performance.now();
+ RunWorkerBatch(kBatchSize);
+ let time = performance.now() - before;
+ print(`batch ${i+1}, Δ = ${(time).toFixed(3)} ms`);
+ }
+})();
diff --git a/deps/v8/test/mjsunit/d8/d8-worker-shutdown-gc.js b/deps/v8/test/mjsunit/d8/d8-worker-shutdown-gc.js
new file mode 100644
index 0000000000..b276a4c20e
--- /dev/null
+++ b/deps/v8/test/mjsunit/d8/d8-worker-shutdown-gc.js
@@ -0,0 +1,56 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-gc --stress-runs=1
+
+const kBatchSize = 10;
+const kNumBatches = 10;
+
+function RunWorkerBatch(count) {
+ let script = `onmessage =
+ function(msg) {
+ if (msg.array) {
+ msg.array[0] = 99;
+ postMessage({array : msg.array});
+ }
+}`;
+
+ // Launch workers.
+ let workers = new Array(count);
+ for (let i = 0; i < count; i++) {
+ workers[i] = new Worker(script, {type : 'string'});
+ }
+
+ // Send messages.
+ for (let i = 0; i < workers.length; i++) {
+ let array = new Int32Array([55, -77]);
+ workers[i].postMessage({array : array});
+ // terminate half of the workers early.
+ if ((i & 1) == 1) workers[i].terminate();
+ }
+
+ // Wait for replies.
+ for (let i = 0; i < workers.length; i++) {
+ let msg = workers[i].getMessage();
+ if (msg !== undefined && msg.array) {
+ assertInstanceof(msg.array, Int32Array);
+ assertEquals(99, msg.array[0]);
+ assertEquals(-77, msg.array[1]);
+ }
+ // terminate all workers.
+ workers[i].terminate();
+ }
+}
+
+(function RunTest() {
+ print(`running ${kNumBatches} batches...`);
+ let time = performance.now();
+ for (let i = 0; i < kNumBatches; i++) {
+ let before = performance.now();
+ RunWorkerBatch(kBatchSize);
+ gc();
+ let time = performance.now() - before;
+ print(`batch ${i+1}, Δ = ${(time).toFixed(3)} ms`);
+ }
+})();
diff --git a/deps/v8/test/mjsunit/d8/d8-worker-shutdown-spawn.js b/deps/v8/test/mjsunit/d8/d8-worker-shutdown-spawn.js
new file mode 100644
index 0000000000..92a675e4fe
--- /dev/null
+++ b/deps/v8/test/mjsunit/d8/d8-worker-shutdown-spawn.js
@@ -0,0 +1,47 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-gc --stress-runs=1
+
+let script = `onmessage =
+ function(msg) {
+ if (msg.depth > 0) {
+ print("spawn");
+ let w = new Worker(msg.script, {type : "string"});
+ w.postMessage({script: msg.script, depth: msg.depth - 1});
+ let m = w.getMessage();
+ w.terminate();
+ postMessage(m);
+ } else {
+ postMessage(-99);
+ }
+}`;
+
+function RunWorker(depth) {
+ let w = new Worker(script, {type : "string"});
+
+ let array = new Int32Array([55, -77]);
+ w.postMessage({script: script, depth: depth});
+ let msg = w.getMessage();
+ print(msg);
+ w.terminate();
+}
+
+function RunTest(depth, iterations) {
+ let time = performance.now();
+ for (let i = 0; i < iterations; i++) {
+ let now = performance.now();
+ print(`iteration ${i}, Δ = ${(now - time).toFixed(3)} ms`);
+ RunWorker(depth);
+ gc();
+ time = now;
+ }
+}
+
+// TODO(9524): increase the workload of this test. Runs out of threads
+// on too many platforms.
+RunTest(1, 1);
+RunTest(2, 2);
+RunTest(5, 3);
+RunTest(9, 2);
diff --git a/deps/v8/test/mjsunit/d8/d8-worker-shutdown.js b/deps/v8/test/mjsunit/d8/d8-worker-shutdown.js
new file mode 100644
index 0000000000..b11e8c0423
--- /dev/null
+++ b/deps/v8/test/mjsunit/d8/d8-worker-shutdown.js
@@ -0,0 +1,55 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --stress-runs=1
+
+const kBatchSize = 10;
+const kNumBatches = 10;
+
+function RunWorkerBatch(count) {
+ let script = `onmessage =
+ function(msg) {
+ if (msg.array) {
+ msg.array[0] = 99;
+ postMessage({array : msg.array});
+ }
+}`;
+
+ // Launch workers.
+ let workers = new Array(count);
+ for (let i = 0; i < count; i++) {
+ workers[i] = new Worker(script, {type : 'string'});
+ }
+
+ // Send messages.
+ for (let i = 0; i < workers.length; i++) {
+ let array = new Int32Array([55, -77]);
+ workers[i].postMessage({array : array});
+ // terminate half of the workers early.
+ if ((i & 1) == 1) workers[i].terminate();
+ }
+
+ // Wait for replies.
+ for (let i = 0; i < workers.length; i++) {
+ let msg = workers[i].getMessage();
+ if (msg !== undefined && msg.array) {
+ assertInstanceof(msg.array, Int32Array);
+ assertEquals(99, msg.array[0]);
+ assertEquals(-77, msg.array[1]);
+ }
+ // terminate all workers.
+ workers[i].terminate();
+ }
+}
+
+(function RunTest() {
+ print(`running ${kNumBatches} batches...`);
+ let time = performance.now();
+ for (let i = 0; i < kNumBatches; i++) {
+ let before = performance.now();
+ RunWorkerBatch(kBatchSize);
+ let time = performance.now() - before;
+ print(`batch ${i+1}, Δ = ${(time).toFixed(3)} ms`);
+ }
+})();
diff --git a/deps/v8/test/mjsunit/d8/d8-worker.js b/deps/v8/test/mjsunit/d8/d8-worker.js
index afc03f5c8b..752bb5ced2 100644
--- a/deps/v8/test/mjsunit/d8/d8-worker.js
+++ b/deps/v8/test/mjsunit/d8/d8-worker.js
@@ -147,12 +147,12 @@ if (this.Worker) {
// Clone ArrayBuffer
var ab1 = createArrayBuffer(16);
w.postMessage(ab1);
- assertEquals(16, ab1.byteLength); // ArrayBuffer should not be neutered.
+ assertEquals(16, ab1.byteLength); // ArrayBuffer should not be detached.
// Transfer ArrayBuffer
var ab2 = createArrayBuffer(32);
w.postMessage(ab2, [ab2]);
- assertEquals(0, ab2.byteLength); // ArrayBuffer should be neutered.
+ assertEquals(0, ab2.byteLength); // ArrayBuffer should be detached.
// Attempting to transfer the same ArrayBuffer twice should throw.
assertThrows(function() {
diff --git a/deps/v8/test/mjsunit/neuter-twice.js b/deps/v8/test/mjsunit/detach-twice.js
index 1bf0fa9405..1bf0fa9405 100644
--- a/deps/v8/test/mjsunit/neuter-twice.js
+++ b/deps/v8/test/mjsunit/detach-twice.js
diff --git a/deps/v8/test/mjsunit/es6/classes.js b/deps/v8/test/mjsunit/es6/classes.js
index eb25f07685..de7312ce27 100644
--- a/deps/v8/test/mjsunit/es6/classes.js
+++ b/deps/v8/test/mjsunit/es6/classes.js
@@ -37,7 +37,7 @@
literal = { __proto__: class {} };
assertEquals('', literal.__proto__.name);
assertEquals(
- undefined, Object.getOwnPropertyDescriptor(literal.__proto__, 'name'));
+ '', Object.getOwnPropertyDescriptor(literal.__proto__, 'name').value);
literal = { __proto__: class F {} };
assertEquals('F', literal.__proto__.name);
diff --git a/deps/v8/test/mjsunit/es6/function-name.js b/deps/v8/test/mjsunit/es6/function-name.js
index c292edf0cd..71f4da52f1 100644
--- a/deps/v8/test/mjsunit/es6/function-name.js
+++ b/deps/v8/test/mjsunit/es6/function-name.js
@@ -394,7 +394,7 @@
})();
(function testClassNameOrder() {
- assertEquals(['length', 'prototype'], Object.getOwnPropertyNames(class {}));
+ assertEquals(['length', 'prototype', 'name'], Object.getOwnPropertyNames(class {}));
var tmp = {'': class {}};
var Tmp = tmp[''];
diff --git a/deps/v8/test/mjsunit/es6/large-classes-properties.js b/deps/v8/test/mjsunit/es6/large-classes-properties.js
index a670b0a907..fe3fb13b8f 100644
--- a/deps/v8/test/mjsunit/es6/large-classes-properties.js
+++ b/deps/v8/test/mjsunit/es6/large-classes-properties.js
@@ -8,14 +8,14 @@
// This is to test for dictionary mode when there more than
// kMaxNumberOfDescriptors (1024) properties.
const kLimit = 1030;
- let evalString = "(function(i) { " +
+ let evalString = "function f(i) { " +
"let clazz = class { " +
" constructor(i) { this.value = i;";
for (let i = 0; i < kLimit ; i++) {
evalString += "this.property"+i +" = "+i+"; "
}
evalString += "}};" +
- " return (new clazz(i)); })";
+ " return (new clazz(i)); }; f;";
let fn = eval(evalString);
%PrepareFunctionForOptimization(fn);
diff --git a/deps/v8/test/mjsunit/es6/throw-type-error-function-restrictions.js b/deps/v8/test/mjsunit/es6/throw-type-error-function-restrictions.js
index 7f67747f29..0eeb9591b2 100644
--- a/deps/v8/test/mjsunit/es6/throw-type-error-function-restrictions.js
+++ b/deps/v8/test/mjsunit/es6/throw-type-error-function-restrictions.js
@@ -5,8 +5,12 @@
var throwTypeErrorFunction =
Object.getOwnPropertyDescriptor(Function.prototype, 'arguments').get;
-assertFalse(
- Object.prototype.hasOwnProperty.call(throwTypeErrorFunction, 'name'));
+var nameDesc =
+ Object.getOwnPropertyDescriptor(throwTypeErrorFunction, 'name');
+assertEquals('', nameDesc.value);
+assertFalse(nameDesc.configurable);
+assertFalse(nameDesc.enumerable);
+assertFalse(nameDesc.writable);
assertThrows(function() {
'use strict';
throwTypeErrorFunction.name = 'foo';
diff --git a/deps/v8/test/mjsunit/es9/regexp-lookbehind.js b/deps/v8/test/mjsunit/es9/regexp-lookbehind.js
index c3aae317a9..513fd630fe 100644
--- a/deps/v8/test/mjsunit/es9/regexp-lookbehind.js
+++ b/deps/v8/test/mjsunit/es9/regexp-lookbehind.js
@@ -27,6 +27,7 @@ assertEquals(["def"], "abcdef".match(/(?<=\w*)[^a|b|c]{3}/));
// Start of line matches.
assertEquals(["def"], "abcdef".match(/(?<=^abc)def/));
assertEquals(["def"], "abcdef".match(/(?<=^[a-c]{3})def/));
+assertEquals(["def"], "abcabcdef".match(/(?<=^[a-c]{6})def/));
assertEquals(["def"], "xyz\nabcdef".match(/(?<=^[a-c]{3})def/m));
assertEquals(["ab", "cd", "efg"], "ab\ncd\nefg".match(/(?<=^)\w+/gm));
assertEquals(["ab", "cd", "efg"], "ab\ncd\nefg".match(/\w+(?<=$)/gm));
diff --git a/deps/v8/test/mjsunit/es9/regress/regress-904167.js b/deps/v8/test/mjsunit/es9/regress/regress-904167.js
index 8986972a8f..7dc06e9cb3 100644
--- a/deps/v8/test/mjsunit/es9/regress/regress-904167.js
+++ b/deps/v8/test/mjsunit/es9/regress/regress-904167.js
@@ -6,7 +6,7 @@
// as tagged, potentially dereferencing a Float64.
// Ensure that we don't fail an assert from --verify-heap when cloning a
-// MutableHeapNumber in the CloneObjectIC handler case.
+// HeapNumber in the CloneObjectIC handler case.
var src, clone;
for (var i = 0; i < 40000; i++) {
src = { ...i, x: -9007199254740991 };
diff --git a/deps/v8/test/mjsunit/harmony/atomics.js b/deps/v8/test/mjsunit/harmony/atomics.js
index ef90076103..5caeb7e8e5 100644
--- a/deps/v8/test/mjsunit/harmony/atomics.js
+++ b/deps/v8/test/mjsunit/harmony/atomics.js
@@ -5,27 +5,47 @@
// Flags: --harmony-sharedarraybuffer
//
-function toRangeWrapped(value) {
- var range = this.max - this.min + 1;
- while (value < this.min) {
- value += range;
- }
- while (value > this.max) {
- value -= range;
+function toRangeWrapper(is_big) {
+ return function _toRangeWrapped(raw_value) {
+ var raw_range = this.max - this.min + (is_big ? 1n : 1);
+ let range = is_big ? BigInt(raw_range) : raw_range;
+ let value = is_big ? BigInt(raw_value) : raw_value;
+ while (value < this.min) {
+ value += range;
+ }
+ while (value > this.max) {
+ value -= range;
+ }
+ return value;
}
- return value;
}
function makeConstructorObject(constr, min, max, toRange) {
var o = {constr: constr, min: min, max: max};
- o.toRange = toRangeWrapped.bind(o);
+ let is_big = constr.name.startsWith('Big')
+ o.toRange = toRangeWrapper(is_big).bind(o);
return o;
}
+function IsBig(t) {
+ return t.constructor.name.startsWith('Big');
+}
+
+function MaybeIntToBigInt(arr, i) {
+ if (IsBig(arr)) {
+ return BigInt(i);
+ } else {
+ return i;
+ }
+}
+
var IntegerTypedArrayConstructors = [
makeConstructorObject(Int8Array, -128, 127),
makeConstructorObject(Int16Array, -32768, 32767),
makeConstructorObject(Int32Array, -0x80000000, 0x7fffffff),
+ makeConstructorObject(BigInt64Array, -0x8000_0000_0000_0000n,
+ 0x7fff_ffff_ffff_ffffn),
+ makeConstructorObject(BigUint64Array, 0n, 0xffff_ffff_ffff_ffffn),
makeConstructorObject(Uint8Array, 0, 255),
makeConstructorObject(Uint16Array, 0, 65535),
makeConstructorObject(Uint32Array, 0, 0xffffffff),
@@ -189,16 +209,19 @@ function clearArray(sab) {
var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
[sta, sta2].forEach(function(array) {
+ let _i = (i) => { return MaybeIntToBigInt(array, i); }
clearArray(array.buffer);
var name = Object.prototype.toString.call(array);
for (var i = 0; i < array.length; ++i) {
// array[i] == 0, CAS will store
- assertEquals(0, Atomics.compareExchange(array, i, 0, 50), name);
- assertEquals(50, array[i], name);
+ assertEquals(_i(0), Atomics.compareExchange(array, i, _i(0), _i(50)),
+ name);
+ assertEquals(_i(50), array[i], name);
// array[i] == 50, CAS will not store
- assertEquals(50, Atomics.compareExchange(array, i, 0, 100), name);
- assertEquals(50, array[i], name);
+ assertEquals(_i(50), Atomics.compareExchange(array, i, _i(0), _i(100)),
+ name);
+ assertEquals(_i(50), array[i], name);
}
})
});
@@ -211,13 +234,14 @@ function clearArray(sab) {
var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
[sta, sta2].forEach(function(array) {
+ let _i = (i) => { return MaybeIntToBigInt(array, i); }
clearArray(array.buffer);
var name = Object.prototype.toString.call(array);
for (var i = 0; i < array.length; ++i) {
- array[i] = 0;
- assertEquals(0, Atomics.load(array, i), name);
- array[i] = 50;
- assertEquals(50, Atomics.load(array, i), name);
+ array[i] = _i(0);
+ assertEquals(_i(0), Atomics.load(array, i), name);
+ array[i] = _i(50);
+ assertEquals(_i(50), Atomics.load(array, i), name);
}
})
});
@@ -248,14 +272,15 @@ function clearArray(sab) {
var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
[sta, sta2].forEach(function(array) {
+ let _i = (i) => { return MaybeIntToBigInt(array, i); }
clearArray(array.buffer);
var name = Object.prototype.toString.call(array);
for (var i = 0; i < array.length; ++i) {
- assertEquals(50, Atomics.store(array, i, 50), name);
- assertEquals(50, array[i], name);
+ assertEquals(_i(50), Atomics.store(array, i, _i(50)), name);
+ assertEquals(_i(50), array[i], name);
- assertEquals(100, Atomics.store(array, i, 100), name);
- assertEquals(100, array[i], name);
+ assertEquals(_i(100), Atomics.store(array, i, _i(100)), name);
+ assertEquals(_i(100), array[i], name);
}
})
});
@@ -268,14 +293,15 @@ function clearArray(sab) {
var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
[sta, sta2].forEach(function(array) {
+ let _i = (i) => { return MaybeIntToBigInt(array, i); }
clearArray(array.buffer);
var name = Object.prototype.toString.call(array);
for (var i = 0; i < array.length; ++i) {
- assertEquals(0, Atomics.add(array, i, 50), name);
- assertEquals(50, array[i], name);
+ assertEquals(_i(0), Atomics.add(array, i, _i(50)), name);
+ assertEquals(_i(50), array[i], name);
- assertEquals(50, Atomics.add(array, i, 70), name);
- assertEquals(120, array[i], name);
+ assertEquals(_i(50), Atomics.add(array, i, _i(70)), name);
+ assertEquals(_i(120), array[i], name);
}
})
});
@@ -288,15 +314,16 @@ function clearArray(sab) {
var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
[sta, sta2].forEach(function(array) {
+ let _i = (i) => { return MaybeIntToBigInt(array, i); }
clearArray(array.buffer);
var name = Object.prototype.toString.call(array);
for (var i = 0; i < array.length; ++i) {
- array[i] = 120;
- assertEquals(120, Atomics.sub(array, i, 50), name);
- assertEquals(70, array[i], name);
+ array[i] = _i(120);
+ assertEquals(_i(120), Atomics.sub(array, i, _i(50)), name);
+ assertEquals(_i(70), array[i], name);
- assertEquals(70, Atomics.sub(array, i, 70), name);
- assertEquals(0, array[i], name);
+ assertEquals(_i(70), Atomics.sub(array, i, _i(70)), name);
+ assertEquals(_i(0), array[i], name);
}
})
});
@@ -309,15 +336,16 @@ function clearArray(sab) {
var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
[sta, sta2].forEach(function(array) {
+ let _i = (i) => { return MaybeIntToBigInt(array, i); }
clearArray(array.buffer);
var name = Object.prototype.toString.call(sta);
for (var i = 0; i < array.length; ++i) {
- array[i] = 0x3f;
- assertEquals(0x3f, Atomics.and(array, i, 0x30), name);
- assertEquals(0x30, array[i], name);
+ array[i] = _i(0x3f);
+ assertEquals(_i(0x3f), Atomics.and(array, i, _i(0x30)), name);
+ assertEquals(_i(0x30), array[i], name);
- assertEquals(0x30, Atomics.and(array, i, 0x20), name);
- assertEquals(0x20, array[i], name);
+ assertEquals(_i(0x30), Atomics.and(array, i, _i(0x20)), name);
+ assertEquals(_i(0x20), array[i], name);
}
})
});
@@ -330,15 +358,16 @@ function clearArray(sab) {
var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
[sta, sta2].forEach(function(array) {
+ let _i = (i) => { return MaybeIntToBigInt(array, i); }
clearArray(array.buffer);
var name = Object.prototype.toString.call(array);
for (var i = 0; i < array.length; ++i) {
- array[i] = 0x30;
- assertEquals(0x30, Atomics.or(array, i, 0x1c), name);
- assertEquals(0x3c, array[i], name);
+ array[i] = _i(0x30);
+ assertEquals(_i(0x30), Atomics.or(array, i, _i(0x1c)), name);
+ assertEquals(_i(0x3c), array[i], name);
- assertEquals(0x3c, Atomics.or(array, i, 0x09), name);
- assertEquals(0x3d, array[i], name);
+ assertEquals(_i(0x3c), Atomics.or(array, i, _i(0x09)), name);
+ assertEquals(_i(0x3d), array[i], name);
}
})
});
@@ -351,15 +380,16 @@ function clearArray(sab) {
var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
[sta, sta2].forEach(function(array) {
+ let _i = (i) => { return MaybeIntToBigInt(array, i); }
clearArray(array.buffer);
var name = Object.prototype.toString.call(array);
for (var i = 0; i < array.length; ++i) {
- array[i] = 0x30;
- assertEquals(0x30, Atomics.xor(array, i, 0x1c), name);
- assertEquals(0x2c, array[i], name);
+ array[i] = _i(0x30);
+ assertEquals(_i(0x30), Atomics.xor(array, i, _i(0x1c)), name);
+ assertEquals(_i(0x2c), array[i], name);
- assertEquals(0x2c, Atomics.xor(array, i, 0x09), name);
- assertEquals(0x25, array[i], name);
+ assertEquals(_i(0x2c), Atomics.xor(array, i, _i(0x09)), name);
+ assertEquals(_i(0x25), array[i], name);
}
})
});
@@ -372,15 +402,16 @@ function clearArray(sab) {
var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
[sta, sta2].forEach(function(array) {
+ let _i = (i) => { return MaybeIntToBigInt(array, i); }
clearArray(array.buffer);
var name = Object.prototype.toString.call(array);
for (var i = 0; i < array.length; ++i) {
- array[i] = 0x30;
- assertEquals(0x30, Atomics.exchange(array, i, 0x1c), name);
- assertEquals(0x1c, array[i], name);
+ array[i] = _i(0x30);
+ assertEquals(_i(0x30), Atomics.exchange(array, i, _i(0x1c)), name);
+ assertEquals(_i(0x1c), array[i], name);
- assertEquals(0x1c, Atomics.exchange(array, i, 0x09), name);
- assertEquals(0x09, array[i], name);
+ assertEquals(_i(0x1c), Atomics.exchange(array, i, _i(0x09)), name);
+ assertEquals(_i(0x09), array[i], name);
}
})
});
@@ -397,72 +428,73 @@ function clearArray(sab) {
});
// For all platforms we support, 1, 2 and 4 bytes should be lock-free.
- assertEquals(true, Atomics.isLockFree(1));
- assertEquals(true, Atomics.isLockFree(2));
- assertEquals(true, Atomics.isLockFree(4));
-
- // Sizes that aren't equal to a typedarray BYTES_PER_ELEMENT always return
- // false.
- var validSizes = {};
- IntegerTypedArrayConstructors.forEach(function(t) {
- validSizes[t.constr.BYTES_PER_ELEMENT] = true;
- });
-
- for (var i = 0; i < 1000; ++i) {
- if (!validSizes[i]) {
- assertEquals(false, Atomics.isLockFree(i));
- }
- }
+ assertTrue(Atomics.isLockFree(1));
+ assertTrue(Atomics.isLockFree(2));
+ assertTrue(Atomics.isLockFree(4));
+
+ assertFalse(Atomics.isLockFree(0));
+ assertFalse(Atomics.isLockFree(3));
+ assertFalse(Atomics.isLockFree(5));
+ assertFalse(Atomics.isLockFree(6));
+ assertFalse(Atomics.isLockFree(7));
+ // isLockFree(8) is platform dependent.
+ for (var i = 9; i < 100; ++i) assertFalse(Atomics.isLockFree(i));
})();
(function TestToNumber() {
IntegerTypedArrayConstructors.forEach(function(t) {
var sab = new SharedArrayBuffer(1 * t.constr.BYTES_PER_ELEMENT);
var sta = new t.constr(sab);
+ let _i = (i) => { return MaybeIntToBigInt(sta, i); }
- var valueOf = {valueOf: function(){ return 3;}};
+ var valueOf = {valueOf: function(){ return _i(3);}};
var toString = {toString: function(){ return '3';}};
[false, true, undefined, valueOf, toString].forEach(function(v) {
+ if (v === undefined && IsBig(sta)) {
+ // undefined does not convert to a BigInt.
+ return;
+ }
+ let _v = () => { return IsBig(sta) ? _i(v) : (v|0); }
var name = Object.prototype.toString.call(sta) + ' - ' + v;
// CompareExchange
- sta[0] = 50;
- assertEquals(50, Atomics.compareExchange(sta, 0, v, v), name);
+ sta[0] = _i(50);
+ assertEquals(_i(50), Atomics.compareExchange(sta, 0, v, v), name);
// Store
- assertEquals(v|0, Atomics.store(sta, 0, v), name);
- assertEquals(v|0, sta[0], name);
+ assertEquals(_v(), Atomics.store(sta, 0, v), name);
+ assertEquals(_v(), sta[0], name);
// Add
- sta[0] = 120;
- assertEquals(120, Atomics.add(sta, 0, v), name);
- assertEquals(120 + (v|0), sta[0], name);
+ sta[0] = _i(120);
+ assertEquals(_i(120), Atomics.add(sta, 0, v), name);
+ assertEquals(_i(120) + _v(), sta[0], name);
// Sub
- sta[0] = 70;
- assertEquals(70, Atomics.sub(sta, 0, v), name);
- assertEquals(70 - (v|0), sta[0]);
+ sta[0] = _i(70);
+ assertEquals(_i(70), Atomics.sub(sta, 0, v), name);
+ assertEquals(_i(70) - _v(), sta[0]);
// And
- sta[0] = 0x20;
- assertEquals(0x20, Atomics.and(sta, 0, v), name);
- assertEquals(0x20 & (v|0), sta[0]);
+ sta[0] = _i(0x20);
+ assertEquals(_i(0x20), Atomics.and(sta, 0, v), name);
+ assertEquals(_i(0x20) & _v(), sta[0]);
// Or
- sta[0] = 0x3d;
- assertEquals(0x3d, Atomics.or(sta, 0, v), name);
- assertEquals(0x3d | (v|0), sta[0]);
+ sta[0] = _i(0x3d);
+ assertEquals(_i(0x3d), Atomics.or(sta, 0, v), name);
+ assertEquals(_i(0x3d) | _v(), sta[0]);
// Xor
- sta[0] = 0x25;
- assertEquals(0x25, Atomics.xor(sta, 0, v), name);
- assertEquals(0x25 ^ (v|0), sta[0]);
+ sta[0] = _i(0x25);
+ assertEquals(_i(0x25), Atomics.xor(sta, 0, v), name);
+ assertEquals(_i(0x25) ^ _v(), sta[0]);
// Exchange
- sta[0] = 0x09;
- assertEquals(0x09, Atomics.exchange(sta, 0, v), name);
- assertEquals(v|0, sta[0]);
+ sta[0] = _i(0x09);
+ assertEquals(_i(0x09), Atomics.exchange(sta, 0, v), name);
+ assertEquals(_v(), sta[0]);
});
});
})();
@@ -472,7 +504,8 @@ function clearArray(sab) {
var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
var sta = new t.constr(sab);
var name = Object.prototype.toString.call(sta);
- var range = t.max - t.min + 1;
+ let _i = (i) => { return MaybeIntToBigInt(sta, i); }
+ var range = t.max - t.min + _i(1);
var offset;
var operand;
var val, newVal;
@@ -480,52 +513,52 @@ function clearArray(sab) {
for (offset = -range; offset <= range; offset += range) {
// CompareExchange
- sta[0] = val = 0;
- newVal = val + offset + 1;
+ sta[0] = val = _i(0);
+ newVal = val + offset + _i(1);
newValWrapped = t.toRange(newVal);
assertEquals(val, Atomics.compareExchange(sta, 0, val, newVal), name);
assertEquals(newValWrapped, sta[0], name);
sta[0] = val = t.min;
- newVal = val + offset - 1;
+ newVal = val + offset - _i(1);
newValWrapped = t.toRange(newVal);
assertEquals(val, Atomics.compareExchange(sta, 0, val, newVal), name);
assertEquals(newValWrapped, sta[0], name);
// Store
- sta[0] = 0;
- val = t.max + offset + 1;
+ sta[0] = _i(0);
+ val = t.max + offset + _i(1);
valWrapped = t.toRange(val);
assertEquals(val, Atomics.store(sta, 0, val), name);
assertEquals(valWrapped, sta[0], name);
- sta[0] = val = t.min + offset - 1;
+ sta[0] = val = t.min + offset - _i(1);
valWrapped = t.toRange(val);
assertEquals(val, Atomics.store(sta, 0, val), name);
assertEquals(valWrapped, sta[0], name);
// Add
sta[0] = val = t.max;
- operand = offset + 1;
+ operand = offset + _i(1);
valWrapped = t.toRange(val + operand);
assertEquals(val, Atomics.add(sta, 0, operand), name);
assertEquals(valWrapped, sta[0], name);
sta[0] = val = t.min;
- operand = offset - 1;
+ operand = offset - _i(1);
valWrapped = t.toRange(val + operand);
assertEquals(val, Atomics.add(sta, 0, operand), name);
assertEquals(valWrapped, sta[0], name);
// Sub
sta[0] = val = t.max;
- operand = offset - 1;
+ operand = offset - _i(1);
valWrapped = t.toRange(val - operand);
assertEquals(val, Atomics.sub(sta, 0, operand), name);
assertEquals(valWrapped, sta[0], name);
sta[0] = val = t.min;
- operand = offset + 1;
+ operand = offset + _i(1);
valWrapped = t.toRange(val - operand);
assertEquals(val, Atomics.sub(sta, 0, operand), name);
assertEquals(valWrapped, sta[0], name);
@@ -535,29 +568,29 @@ function clearArray(sab) {
// to memory.
// And
- sta[0] = val = 0xf;
- operand = 0x3 + offset;
+ sta[0] = val = _i(0xf);
+ operand = _i(0x3) + offset;
valWrapped = t.toRange(val & operand);
assertEquals(val, Atomics.and(sta, 0, operand), name);
assertEquals(valWrapped, sta[0], name);
// Or
- sta[0] = val = 0x12;
- operand = 0x22 + offset;
+ sta[0] = val = _i(0x12);
+ operand = _i(0x22) + offset;
valWrapped = t.toRange(val | operand);
assertEquals(val, Atomics.or(sta, 0, operand), name);
assertEquals(valWrapped, sta[0], name);
// Xor
- sta[0] = val = 0x12;
- operand = 0x22 + offset;
+ sta[0] = val = _i(0x12);
+ operand = _i(0x22) + offset;
valWrapped = t.toRange(val ^ operand);
assertEquals(val, Atomics.xor(sta, 0, operand), name);
assertEquals(valWrapped, sta[0], name);
// Exchange
- sta[0] = val = 0x12;
- operand = 0x22 + offset;
+ sta[0] = val = _i(0x12);
+ operand = _i(0x22) + offset;
valWrapped = t.toRange(operand);
assertEquals(val, Atomics.exchange(sta, 0, operand), name);
assertEquals(valWrapped, sta[0], name);
@@ -574,7 +607,7 @@ function clearArray(sab) {
// The index should be checked before calling ToInteger on the value, so
// valueof_has_been_called should not be modified.
- sta[0] = 0;
+ sta[0] = MaybeIntToBigInt(sta, 0);
assertThrows(function() { op(sta, index, value, value); }, RangeError);
assertEquals(0, valueof_has_been_called);
};
diff --git a/deps/v8/test/mjsunit/harmony/nullish.js b/deps/v8/test/mjsunit/harmony/nullish.js
new file mode 100644
index 0000000000..87d35db4bc
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/nullish.js
@@ -0,0 +1,143 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-nullish
+
+// Basic sanity checks.
+assertTrue(true ?? false);
+assertFalse(false ?? true);
+assertTrue(undefined ?? true);
+assertTrue(null ?? true);
+assertEquals([], [] ?? true);
+
+// Chaining nullish.
+assertTrue(null ?? null ?? true);
+assertTrue(null ?? null ?? true ?? null);
+assertTrue(undefined ?? undefined ?? true);
+assertTrue(undefined ?? undefined ?? true ?? undefined);
+assertFalse(null ?? false ?? null);
+assertFalse(undefined ?? false ?? undefined);
+
+// Nullish and conditionals.
+assertTrue(null ?? true ? true : false);
+assertTrue(null ?? null ?? true ? true : false);
+assertTrue(undefined ?? true ? true : false);
+assertTrue(undefined ?? undefined ?? true ? true : false);
+
+// Nullish mixed expressions.
+assertTrue(null ?? 1 == 1);
+assertTrue(undefined ?? 1 == 1);
+assertTrue(null ?? null ?? 1 == 1);
+assertTrue(undefined ??undefined ?? 1 == 1);
+assertEquals(1, null ?? 1 | 0);
+assertEquals(1, undefined ?? 1 | 0);
+assertEquals(1, null ?? null ?? 1 | 0);
+assertEquals(1, undefined ?? undefined ?? 1 | 0);
+
+// Short circuit.
+{
+ let ran = false;
+ let never_ran = () => { ran = true; }
+ let value = true ?? never_ran();
+ assertTrue(value);
+ assertFalse(ran);
+}
+
+{
+ let ran = false;
+ let never_ran = () => { ran = true; }
+ let value = undefined ?? true ?? never_ran();
+ assertTrue(value);
+ assertFalse(ran);
+}
+
+{
+ let ran = false;
+ let never_ran = () => { ran = true; }
+ let value = null ?? true ?? never_ran();
+ assertTrue(value);
+ assertFalse(ran);
+}
+
+// Nullish in tests evaluates only once.
+{
+ let run_count = 0;
+ let run = () => { run_count++; return null; }
+ if (run() ?? true) {} else { assertUnreachable(); }
+ assertEquals(1, run_count);
+}
+
+// Nullish may not contain or be contained within || or &&.
+assertThrows("true || true ?? true", SyntaxError);
+assertThrows("true ?? true || true", SyntaxError);
+assertThrows("true && true ?? true", SyntaxError);
+assertThrows("true ?? true && true", SyntaxError);
+
+// Test boolean expressions and nullish.
+assertTrue((false || true) ?? false);
+assertTrue(null ?? (false || true));
+assertTrue((false || null) ?? true);
+assertTrue((false || null) ?? (true && null) ?? true);
+assertTrue((false || undefined) ?? true);
+assertTrue((false || undefined) ?? (true && undefined) ?? true);
+assertTrue(null ?? (false || true));
+assertTrue(undefined ?? (false || true));
+assertTrue(null ?? (false || null) ?? true);
+assertTrue(undefined ?? (false || undefined) ?? true);
+assertTrue(null ?? null ?? (false || true));
+assertTrue(undefined ?? undefined ?? (false || true));
+assertTrue((undefined ?? false) || true);
+assertTrue((null ?? false) || true);
+assertTrue((undefined ?? undefined ?? false) || false || true);
+assertTrue((null ?? null ?? false) || false || true);
+assertTrue(false || (undefined ?? true));
+assertTrue(false || (null ?? true));
+assertTrue(false || false || (undefined ?? undefined ?? true));
+assertTrue(false || false || (null ?? null ?? true));
+
+// Test use when test true.
+if (undefined ?? true) {} else { assertUnreachable(); }
+if (null ?? true) {} else { assertUnreachable(); }
+
+if (undefined ?? undefined ?? true) {} else { assertUnreachable(); }
+if (null ?? null ?? true) {} else { assertUnreachable(); }
+
+// test use when test false
+if (undefined ?? false) { assertUnreachable(); } else {}
+if (null ?? false) { assertUnreachable(); } else {}
+
+if (undefined ?? undefined ?? false) { assertUnreachable(); } else {}
+if (null ?? null ?? false) { assertUnreachable(); } else {}
+
+if (undefined ?? false ?? true) { assertUnreachable(); } else {}
+if (null ?? false ?? true) { assertUnreachable(); } else {}
+
+// Test use with nested boolean.
+if ((false || undefined) ?? true) {} else { assertUnreachable(); }
+if ((false || null) ?? true) {} else { assertUnreachable(); }
+
+if ((false || undefined) ?? undefined ?? true) {} else { assertUnreachable(); }
+if ((false || null) ?? null ?? true) {} else { assertUnreachable(); }
+
+if (undefined ?? (false || true)) {} else { assertUnreachable(); }
+if (null ?? (false || true)) {} else { assertUnreachable(); }
+
+if (undefined ?? undefined ?? (false || true)) {} else { assertUnreachable(); }
+if (null ?? null ?? (false || true)) {} else { assertUnreachable(); }
+
+if (undefined ?? (false || undefined) ?? true) {} else { assertUnreachable(); }
+if (null ?? (false || null) ?? true) {} else { assertUnreachable(); }
+
+// Nested nullish.
+if ((null ?? true) || false) {} else { assertUnreachable(); }
+if ((null ?? null ?? true) || false) {} else { assertUnreachable(); }
+
+if (false || (null ?? true)) {} else { assertUnreachable(); }
+if (false || (null ?? null ?? true)) {} else { assertUnreachable(); }
+
+if ((null ?? false) || false) { assertUnreachable(); } else {}
+if ((null ?? null ?? false) || false) { assertUnreachable(); } else {}
+
+if (false || (null ?? false)) { assertUnreachable(); } else {}
+if (false || (null ?? null ?? false)) { assertUnreachable(); } else {}
diff --git a/deps/v8/test/mjsunit/harmony/numeric-separator.js b/deps/v8/test/mjsunit/harmony/numeric-separator.js
index 0ea3ac8f8d..c2c32b7db0 100644
--- a/deps/v8/test/mjsunit/harmony/numeric-separator.js
+++ b/deps/v8/test/mjsunit/harmony/numeric-separator.js
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-numeric-separator
-
{
const basic = 1_0_0_0;
assertEquals(basic, 1000);
@@ -41,11 +39,6 @@
assertEquals(binary, 0b01010);
}
{
- const leadingZeros = 09_1_3;
- assertEquals(leadingZeros, 0913);
-}
-
-{
const dot1 = 9_1.1_3;
assertEquals(dot1, 91.13);
@@ -54,6 +47,9 @@
const dot3 = 1_1.21;
assertEquals(dot3, 11.21);
+
+ const dot4 = 09.1_2
+ assertEquals(dot4, 9.12);
}
{
@@ -114,3 +110,4 @@ assertThrows('0o7__77', SyntaxError);
assertThrows('0777_', SyntaxError);
assertThrows('07__77', SyntaxError);
assertThrows('07_7_7', SyntaxError);
+assertThrows('09_1_3', SyntaxError);
diff --git a/deps/v8/test/mjsunit/harmony/optional-chaining.js b/deps/v8/test/mjsunit/harmony/optional-chaining.js
new file mode 100644
index 0000000000..72b0559e00
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/optional-chaining.js
@@ -0,0 +1,119 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-optional-chaining
+
+function shouldThrowSyntaxError(script) {
+ let error;
+ try {
+ eval(script);
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof SyntaxError)) {
+ throw new Error('Expected SyntaxError!');
+ }
+}
+
+assertEquals(undefined?.valueOf(), undefined);
+assertEquals(null?.valueOf(), undefined);
+assertEquals(true?.valueOf(), true);
+assertEquals(false?.valueOf(), false);
+assertEquals(0?.valueOf(), 0);
+assertEquals(1?.valueOf(), 1);
+assertEquals(''?.valueOf(), '');
+assertEquals('hi'?.valueOf(), 'hi');
+assertEquals(({})?.constructor, Object);
+assertEquals(({ x: 'hi' })?.x, 'hi');
+assertEquals([]?.length, 0);
+assertEquals(['hi']?.length, 1);
+
+assertEquals(undefined?.['valueOf'](), undefined);
+assertEquals(null?.['valueOf'](), undefined);
+assertEquals(true?.['valueOf'](), true);
+assertEquals(false?.['valueOf'](), false);
+assertEquals(0?.['valueOf'](), 0);
+assertEquals(1?.['valueOf'](), 1);
+assertEquals(''?.['valueOf'](), '');
+assertEquals('hi'?.['valueOf'](), 'hi');
+assertEquals(({})?.['constructor'], Object);
+assertEquals(({ x: 'hi' })?.['x'], 'hi');
+assertEquals([]?.['length'], 0);
+assertEquals(['hi']?.[0], 'hi');
+
+assertEquals(undefined?.(), undefined);
+assertEquals(null?.(), undefined);
+assertThrows(() => true?.(), TypeError);
+assertThrows(() => false?.(), TypeError);
+assertThrows(() => 0?.(), TypeError);
+assertThrows(() => 1?.(), TypeError);
+assertThrows(() => ''?.(), TypeError);
+assertThrows(() => 'hi'?.(), TypeError);
+assertThrows(() => ({})?.(), TypeError);
+assertThrows(() => ({ x: 'hi' })?.(), TypeError);
+assertThrows(() => []?.(), TypeError);
+assertThrows(() => ['hi']?.(), TypeError);
+
+assertThrows(() => ({})?.a['b'], TypeError);
+assertEquals(({})?.a?.['b'], undefined);
+assertEquals(null?.a['b']().c, undefined);
+assertThrows(() => ({})?.['a'].b);
+assertEquals(({})?.['a']?.b, undefined);
+assertEquals(null?.['a'].b()['c'], undefined);
+assertThrows(() => (() => {})?.()(), TypeError);
+assertEquals((() => {})?.()?.(), undefined);
+assertEquals(null?.()().a['b'], undefined);
+
+assertEquals(delete undefined?.foo, true);
+assertEquals(delete null?.foo, true);
+assertEquals(delete undefined?.['foo'], true);
+assertEquals(delete null?.['foo'], true);
+assertEquals(delete undefined?.(), true);
+assertEquals(delete null?.(), true);
+
+assertEquals(undefined?.(...a), undefined);
+assertEquals(null?.(1, ...a), undefined);
+assertEquals(({}).a?.(...a), undefined);
+assertEquals(({ a: null }).a?.(...a), undefined);
+assertEquals(undefined?.(...a)?.(1, ...a), undefined);
+assertThrows(() => 5?.(...[]), TypeError);
+
+const o1 = { x: 0, y: 0, z() {} };
+assertEquals(delete o1?.x, true);
+assertEquals(o1.x, undefined);
+assertEquals(delete o1?.x, true);
+assertEquals(delete o1?.['y'], true);
+assertEquals(o1.y, undefined);
+assertEquals(delete o1?.['y'], true);
+assertEquals(delete o1.z?.(), true);
+assertThrows(() => { delete ({})?.foo.bar; });
+
+shouldThrowSyntaxError('class C {} class D extends C { foo() { return super?.bar; } }');
+shouldThrowSyntaxError('class C {} class D extends C { foo() { return super?.["bar"]; } }');
+shouldThrowSyntaxError('class C {} class D extends C { constructor() { super?.(); } }');
+
+shouldThrowSyntaxError('const o = { C: class {} }; new o?.C();');
+shouldThrowSyntaxError('const o = { C: class {} }; new o?.["C"]();');
+shouldThrowSyntaxError('class C {} new C?.();');
+shouldThrowSyntaxError('function foo() { new?.target; }');
+
+shouldThrowSyntaxError('function tag() {} tag?.``;');
+shouldThrowSyntaxError('const o = { tag() {} }; o?.tag``;');
+
+const o2 = {
+ count: 0,
+ get x() {
+ this.count += 1;
+ return () => {};
+ },
+};
+o2.x?.y;
+assertEquals(o2.count, 1);
+o2.x?.['y'];
+assertEquals(o2.count, 2);
+o2.x?.();
+assertEquals(o2.count, 3);
+
+assertEquals(true?.5:5, 0.5);
diff --git a/deps/v8/test/mjsunit/harmony/private-accessors.js b/deps/v8/test/mjsunit/harmony/private-accessors.js
new file mode 100644
index 0000000000..3a828116a1
--- /dev/null
+++ b/deps/v8/test/mjsunit/harmony/private-accessors.js
@@ -0,0 +1,91 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-private-methods
+
+"use strict";
+
+// Complementary private accessors.
+{
+ let store = 1;
+ class C {
+ get #a() { return store; }
+ set #a(val) { store = val; }
+ incA() { this.#a++; } // CountOperation
+ setA(val) { this.#a = val; }
+ getA() { return this.#a; }
+ }
+
+ const c = new C;
+ assertEquals(store, c.getA());
+ assertEquals(1, c.getA());
+ c.setA(2);
+ assertEquals(store, c.getA());
+ assertEquals(2, c.getA());
+ c.incA();
+ assertEquals(store, c.getA());
+ assertEquals(3, c.getA());
+}
+
+// Compound assignment.
+{
+ let store;
+ class A {
+ get #a() { return store; }
+ set #a(val) { store = val; }
+ getA() { return this.#a; }
+ constructor(val) {
+ ({ y: this.#a } = val);
+ }
+ }
+
+ const a = new A({y: 'test'});
+ assertEquals('test', a.getA());
+}
+
+// Accessing super in private accessors.
+{
+ class A { foo(val) {} }
+ class C extends A {
+ set #a(val) { super.foo(val); }
+ }
+ new C();
+
+ class D extends A {
+ get #a() { return super.foo; }
+ }
+ new D();
+
+ class E extends A {
+ set #a(val) { super.foo(val); }
+ get #a() { return super.foo; }
+ }
+ new E();
+}
+
+// Nested private accessors.
+{
+ class C {
+ get #a() {
+ let storeD = 'd';
+ class D {
+ // Shadows outer #a
+ get #a() { return storeD; }
+ getD() { return this.#a; }
+ }
+ return new D;
+ }
+ getA() {
+ return this.#a;
+ }
+ }
+ assertEquals('d', new C().getA().getD());
+}
+
+// Duplicate private accessors.
+// https://tc39.es/proposal-private-methods/#sec-static-semantics-early-errors
+{
+ assertThrows('class C { get #a() {} get #a() {} }', SyntaxError);
+ assertThrows('class C { set #a(val) {} set #a(val) {} }', SyntaxError);
+}
diff --git a/deps/v8/test/mjsunit/harmony/private-methods.js b/deps/v8/test/mjsunit/harmony/private-methods.js
index 360b065f17..fcd80823c1 100644
--- a/deps/v8/test/mjsunit/harmony/private-methods.js
+++ b/deps/v8/test/mjsunit/harmony/private-methods.js
@@ -281,3 +281,17 @@
new D;
new E;
}
+
+// Super access within private methods.
+{
+ class A {
+ foo() { return 1; }
+ }
+
+ class C extends A {
+ #m() { return super.foo; }
+ fn() { return this.#m()(); }
+ }
+
+ assertEquals(1, new C().fn());
+}
diff --git a/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-doesnt-iterate-all-holdings.js b/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-doesnt-iterate-all-holdings.js
index 20726284bb..ebc4ebf933 100644
--- a/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-doesnt-iterate-all-holdings.js
+++ b/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-doesnt-iterate-all-holdings.js
@@ -6,6 +6,7 @@
let cleanup_call_count = 0;
let cleanup = function(iter) {
+ print("in cleanup");
if (cleanup_call_count == 0) {
// First call: iterate 2 of the 3 holdings
let holdings_list = [];
@@ -74,11 +75,15 @@ let timeout_func_2 = function() {
assertEquals(1, cleanup_call_count);
// Create a new object and register it.
- let obj = {};
- let wc = fg.register(obj, 100);
- obj = null;
+ (function() {
+ let obj = {};
+ let wc = fg.register(obj, 100);
+ obj = null;
+ })();
+ // This GC will reclaim the targets.
gc();
+ assertEquals(1, cleanup_call_count);
setTimeout(timeout_func_3, 0);
}
diff --git a/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-is-a-microtask.js b/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-is-not-a-microtask.js
index c6b834e8fb..077bc21e82 100644
--- a/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-is-a-microtask.js
+++ b/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-is-not-a-microtask.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-weak-refs --expose-gc --noincremental-marking
+// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
// This test asserts that the cleanup function call, scheduled by GC, is a
// microtask and not a normal task.
@@ -11,6 +11,8 @@
// microtask). lso schedule another microtask. Assert that the cleanup
// function ran before the other microtask.
+let cleanedUp = false;
+
function scheduleMicrotask(func) {
Promise.resolve().then(func);
}
@@ -18,7 +20,7 @@ function scheduleMicrotask(func) {
let log = [];
let cleanup = (iter) => {
- log.push("cleanup");
+ cleanedUp = true;
for (holdings of iter) { }
}
@@ -32,25 +34,29 @@ let o = null;
fg.register(o, {});
})();
-let microtask_after_cleanup = () => {
- log.push("microtask_after_cleanup");
-}
-
-let first_microtask = function() {
+let microtask = function() {
log.push("first_microtask");
- // This schedules the cleanup function as microtask.
+ // cause GC during a microtask
o = null;
gc();
-
- // Schedule a microtask which should run after the cleanup microtask.
- scheduleMicrotask(microtask_after_cleanup);
}
-scheduleMicrotask(first_microtask);
+assertFalse(cleanedUp);
+
+// enqueue microtask that triggers GC
+Promise.resolve().then(microtask);
+
+// but cleanup callback hasn't been called yet, as we're still in
+// synchronous execution
+assertFalse(cleanedUp);
+
+// flush the microtask queue to run the microtask that triggers GC
+%PerformMicrotaskCheckpoint();
+
+// still no cleanup callback, because it runs after as a separate task
+assertFalse(cleanedUp);
setTimeout(() => {
- // Assert that the functions got called in the right order.
- let wanted_log = ["first_microtask", "cleanup", "microtask_after_cleanup"];
- assertEquals(wanted_log, log);
+ assertTrue(cleanedUp);
}, 0);
diff --git a/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-on-detached-realm.js b/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-on-detached-realm.js
index ca156e0574..9cc548920c 100644
--- a/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-on-detached-realm.js
+++ b/deps/v8/test/mjsunit/harmony/weakrefs/cleanup-on-detached-realm.js
@@ -4,12 +4,13 @@
// Flags: --harmony-weak-refs --expose-gc --noincremental-marking
+let cleanedUp = false;
let r = Realm.create();
let FG = Realm.eval(r, "FinalizationGroup");
Realm.detachGlobal(r);
let fg = new FG(()=> {
- assertUnreachable();
+ cleanedUp = true;
});
(() => {
@@ -20,3 +21,5 @@ let fg = new FG(()=> {
})();
gc();
+
+setTimeout(function() { assertTrue(cleanedUp); }, 0);
diff --git a/deps/v8/test/mjsunit/harmony/weakrefs/finalizationgroup-and-weakref.js b/deps/v8/test/mjsunit/harmony/weakrefs/finalizationgroup-and-weakref.js
index bd66f1ce1d..83de3a838b 100644
--- a/deps/v8/test/mjsunit/harmony/weakrefs/finalizationgroup-and-weakref.js
+++ b/deps/v8/test/mjsunit/harmony/weakrefs/finalizationgroup-and-weakref.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
+// Flags: --harmony-weak-refs --expose-gc --noincremental-marking
let cleanup_called = false;
let cleanup = function(iter) {
@@ -32,13 +32,13 @@ gc();
assertNotEquals(undefined, weak_ref.deref());
})();
-%PerformMicrotaskCheckpoint();
-// Next turn.
+// Trigger gc in next task
+setTimeout(() => {
+ gc();
-gc();
-
-%PerformMicrotaskCheckpoint();
-// Next turn.
-
-assertTrue(cleanup_called);
-assertEquals(undefined, weak_ref.deref());
+ // Check that cleanup callback was called in a follow up task
+ setTimeout(() => {
+ assertTrue(cleanup_called);
+ assertEquals(undefined, weak_ref.deref());
+ }, 0);
+}, 0);
diff --git a/deps/v8/test/mjsunit/harmony/weakrefs/two-weakrefs.js b/deps/v8/test/mjsunit/harmony/weakrefs/two-weakrefs.js
index c3fc9f741c..c17e7aa969 100644
--- a/deps/v8/test/mjsunit/harmony/weakrefs/two-weakrefs.js
+++ b/deps/v8/test/mjsunit/harmony/weakrefs/two-weakrefs.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
+// Flags: --harmony-weak-refs --expose-gc --noincremental-marking
let o1 = {};
let o2 = {};
@@ -21,28 +21,27 @@ gc();
assertNotEquals(undefined, wr2.deref());
})();
-%PerformMicrotaskCheckpoint();
-// New turn.
-
-wr1.deref();
-o1 = null;
-gc(); // deref makes sure we don't clean up wr1
-
-%PerformMicrotaskCheckpoint();
-// New turn.
-
-wr2.deref();
-o2 = null;
-gc(); // deref makes sure we don't clean up wr2
-
-%PerformMicrotaskCheckpoint();
-// New turn.
-
-assertEquals(undefined, wr1.deref());
-
-gc();
-
-%PerformMicrotaskCheckpoint();
-// New turn.
-
-assertEquals(undefined, wr2.deref());
+// New task
+setTimeout(function() {
+ wr1.deref();
+ o1 = null;
+ gc(); // deref makes sure we don't clean up wr1
+
+ // New task
+ setTimeout(function() {
+ wr2.deref();
+ o2 = null;
+ gc(); // deref makes sure we don't clean up wr2
+
+ // New task
+ setTimeout(function() {
+ assertEquals(undefined, wr1.deref());
+ gc();
+
+ // New task
+ setTimeout(function() {
+ assertEquals(undefined, wr2.deref());
+ }, 0);
+ }, 0);
+ }, 0);
+}, 0);
diff --git a/deps/v8/test/mjsunit/harmony/weakrefs/weakref-creation-keeps-alive.js b/deps/v8/test/mjsunit/harmony/weakrefs/weakref-creation-keeps-alive.js
index 18e3af26ce..4c8641d8aa 100644
--- a/deps/v8/test/mjsunit/harmony/weakrefs/weakref-creation-keeps-alive.js
+++ b/deps/v8/test/mjsunit/harmony/weakrefs/weakref-creation-keeps-alive.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
+// Flags: --harmony-weak-refs --expose-gc --noincremental-marking
let wr;
(function() {
@@ -19,9 +19,8 @@ gc();
assertNotEquals(undefined, wr.deref());
})();
-%PerformMicrotaskCheckpoint();
-// Next turn.
-
-gc();
-
-assertEquals(undefined, wr.deref());
+// Next task.
+setTimeout(() => {
+ gc();
+ assertEquals(undefined, wr.deref());
+}, 0);
diff --git a/deps/v8/test/mjsunit/harmony/weakrefs/weakref-deref-keeps-alive.js b/deps/v8/test/mjsunit/harmony/weakrefs/weakref-deref-keeps-alive.js
index c17f060713..eb02290dfd 100644
--- a/deps/v8/test/mjsunit/harmony/weakrefs/weakref-deref-keeps-alive.js
+++ b/deps/v8/test/mjsunit/harmony/weakrefs/weakref-deref-keeps-alive.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
+// Flags: --harmony-weak-refs --expose-gc --noincremental-marking
let wr;
let wr_control; // control WeakRef for testing what happens without deref
@@ -17,29 +17,29 @@ let strong = {a: wr.deref(), b: wr_control.deref()};
gc();
-%PerformMicrotaskCheckpoint();
-// Next turn.
+// Next task.
+setTimeout(function() {
+ // Call deref inside a closure, trying to avoid accidentally storing a strong
+ // reference into the object in the stack frame.
+ (function() {
+ wr.deref();
+ })();
-// Call deref inside a closure, trying to avoid accidentally storing a strong
-// reference into the object in the stack frame.
-(function() {
- wr.deref();
-})();
-
-strong = null;
-
-// This GC will clear wr_control.
-gc();
+ strong = null;
-(function() {
- assertNotEquals(undefined, wr.deref());
- // Now the control WeakRef got cleared, since nothing was keeping it alive.
- assertEquals(undefined, wr_control.deref());
-})();
+ // This GC will clear wr_control.
+ gc();
-%PerformMicrotaskCheckpoint();
-// Next turn.
+ (function() {
+ assertNotEquals(undefined, wr.deref());
+ // Now the control WeakRef got cleared, since nothing was keeping it alive.
+ assertEquals(undefined, wr_control.deref());
+ })();
-gc();
+ // Next task.
+ setTimeout(function() {
+ gc();
-assertEquals(undefined, wr.deref());
+ assertEquals(undefined, wr.deref());
+ }, 0);
+}, 0);
diff --git a/deps/v8/test/mjsunit/interrupt-budget-override.js b/deps/v8/test/mjsunit/interrupt-budget-override.js
index 6dbf0785a7..5f83b3ccc5 100644
--- a/deps/v8/test/mjsunit/interrupt-budget-override.js
+++ b/deps/v8/test/mjsunit/interrupt-budget-override.js
@@ -12,7 +12,8 @@ function f() {
return s;
}
-%PrepareFunctionForOptimization(f);
+%PrepareFunctionForOptimization(f, "allow heuristic optimization");
+f();
f();
f();
assertOptimized(f);
diff --git a/deps/v8/test/mjsunit/mjsunit.js b/deps/v8/test/mjsunit/mjsunit.js
index 8582b38036..fd45ebacbd 100644
--- a/deps/v8/test/mjsunit/mjsunit.js
+++ b/deps/v8/test/mjsunit/mjsunit.js
@@ -174,6 +174,7 @@ var V8OptimizationStatus = {
kIsExecuting: 1 << 10,
kTopmostFrameIsTurboFanned: 1 << 11,
kLiteMode: 1 << 12,
+ kMarkedForDeoptimization: 1 << 13,
};
// Returns true if --lite-mode is on and we can't ever turn on optimization.
diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status
index bdcf3cf18d..134a49f748 100644
--- a/deps/v8/test/mjsunit/mjsunit.status
+++ b/deps/v8/test/mjsunit/mjsunit.status
@@ -54,9 +54,6 @@
# Issue 3784: setters-on-elements is flaky
'setters-on-elements': [PASS, FAIL],
- # Issue 8505: Math.pow is incorrect for asm.js
- 'regress/wasm/regress-8505': [SKIP],
-
# Issue 9380: Memory leaks of shared WebAssembly.Memory objects
'wasm/shared-memory-worker-gc': [SKIP],
@@ -182,6 +179,7 @@
'regress/regress-605470': [PASS, SLOW],
'regress/regress-655573': [PASS, SLOW],
'regress/regress-1200351': [PASS, SLOW],
+ 'regress/regress-crbug-918301': [PASS, SLOW, NO_VARIANTS, ['mode != release or dcheck_always_on', SKIP], ['(arch == arm or arch == arm64) and simulator_run', SKIP], ['tsan', SKIP]],
'regress/wasm/regress-810973': [PASS, SLOW],
'string-replace-gc': [PASS, SLOW],
'wasm/asm-wasm-f32': [PASS, SLOW],
@@ -194,6 +192,9 @@
'wasm/compare-exchange-stress': [PASS, SLOW, NO_VARIANTS],
'wasm/compare-exchange64-stress': [PASS, SLOW, NO_VARIANTS],
+ # worker creation/shutdown is very slow in debug mode
+ 'd8/d8-worker-shutdown*': [PASS, ['mode == debug', SLOW], ['no_snap', SKIP]],
+
# case-insensitive unicode regexp relies on case mapping provided by ICU.
'es6/unicode-regexp-ignore-case': [PASS, ['no_i18n == True', FAIL]],
'es6/unicode-regexp-ignore-case-noi18n': [FAIL, ['no_i18n == True', PASS]],
@@ -391,11 +392,16 @@
'regress/regress-crbug-721835': [SKIP],
'regress/regress-crbug-759327': [SKIP],
'regress/regress-crbug-898974': [SKIP],
+ 'regexp-tier-up': [SKIP],
# These tests check that we can trace the compiler.
'tools/compiler-trace-flags': [SKIP],
'tools/compiler-trace-flags-wasm': [SKIP],
+ # Too slow on arm64 simulator and debug: https://crbug.com/v8/7783
+ 'bit-not': [PASS, ['arch == arm64 and mode == debug and simulator_run', SKIP]],
+ 'md5': [PASS, ['arch == arm64 and mode == debug and simulator_run', SKIP]],
+
# Slow with pointer compression.
'regress/regress-crbug-319860': [PASS, ['pointer_compression', SLOW]],
}], # 'lite_mode or variant == jitless'
@@ -405,6 +411,7 @@
# Tests too slow in non-optimized debug mode.
'compiler/regress-9017': [SKIP],
'regress/regress-2790': [SKIP],
+ 'regress/regress-331444': [SKIP],
'regress/regress-740784': [SKIP],
}], # 'is_full_debug'
@@ -490,6 +497,9 @@
# BUG(v8:9256). Slow with pointer compression.
'regress/regress-708247': [PASS, ['pointer_compression', SLOW]],
+ 'es6/array-concat': [PASS, ['pointer_compression', SLOW]],
+ 'non-extensible-array-reduce': [PASS, ['pointer_compression', SLOW]],
+ 'regress/regress-454725': [PASS, ['pointer_compression', SLOW]],
}], # 'arch == arm64'
['arch == arm64 and mode == debug and simulator_run', {
@@ -861,6 +871,7 @@
# Tests that fail some assertions due to checking internal state sensitive
# to GC.
'compiler/native-context-specialization-hole-check': [SKIP],
+ 'opt-elements-kind': [SKIP],
'regress/regress-trap-allocation-memento': [SKIP],
'regress/regress-v8-9267-*': [SKIP],
'shared-function-tier-up-turbo': [SKIP],
@@ -890,6 +901,8 @@
# Skip tests that are known to be non-deterministic.
'd8/d8-worker-sharedarraybuffer': [SKIP],
'd8/d8-os': [SKIP],
+ 'd8/d8-worker-shutdown': [SKIP],
+ 'd8/d8-worker-shutdown-gc': [SKIP],
'harmony/futex': [SKIP],
# BUG(v8:7166).
@@ -949,6 +962,9 @@
'ignition/regress-599001-verifyheap': [SKIP],
'unicode-test': [SKIP],
+ # The RegExp code cache means running this test multiple times is invalid.
+ 'regexp-tier-up': [SKIP],
+
# Flaky crash on Odroid devices: https://crbug.com/v8/7678
'regress/regress-336820': [PASS, ['arch == arm and not simulator_run', SKIP]],
@@ -1065,14 +1081,6 @@
}], # arch == x64
##############################################################################
-['arch in [arm, android_arm, android_ia32, ia32, ppc, s390, s390x, mipsel, mips]', {
- # TODO(ssauleau): implement BigInt<>Wasm conversion for other arch -
- # crbug.com/v8/7741
- 'wasm/bigint': [SKIP],
- 'wasm/bigint-i64-to-imported-js-func': [SKIP],
-}], # arch in [arm, android_arm, android_ia32, ia32, ppc, s390, s390x, mipsel, mips]
-
-##############################################################################
['arch not in [x64, arm, arm64] or system != linux', {
# Unwinding info writer is only supported on x64, arm, and arm64 Linux
'regress/regress-913844': [SKIP],
@@ -1083,4 +1091,9 @@
'*': [SKIP],
}], # variant == jitless and not embedded_builtins
+['not embedded_builtins', {
+ # Explicitly sets jitless flag.
+ 'regress/regress-992389': [SKIP],
+}], # not embedded_builtins
+
]
diff --git a/deps/v8/test/mjsunit/object-prevent-extensions.js b/deps/v8/test/mjsunit/object-prevent-extensions.js
index 4bda84e2dd..2fafcf395d 100644
--- a/deps/v8/test/mjsunit/object-prevent-extensions.js
+++ b/deps/v8/test/mjsunit/object-prevent-extensions.js
@@ -932,3 +932,110 @@ assertTrue(checkUndefined.apply(this, [...arr]));
assertEquals(a[0], a[1]);
})();
+
+// Test regression with Object.defineProperty.
+var obj = [];
+obj.propertyA = 42;
+obj[0] = true;
+Object.preventExtensions(obj);
+assertDoesNotThrow(function() {
+ Object.defineProperty(obj, 'propertyA', {
+ value: obj,
+ });
+});
+assertEquals(obj, obj.propertyA);
+assertDoesNotThrow(function() {
+ Object.defineProperty(obj, 'propertyA', {
+ value: obj,
+ writable: false,
+ });
+});
+obj.propertyA = 42;
+assertEquals(obj.propertyA, obj);
+assertThrows(function() {
+ Object.defineProperty(obj, 'abc', {
+ value: obj,
+ });
+}, TypeError);
+
+
+// Handle IC store.
+// For packed sealed object.
+function packedStore() {
+ let a = Object.preventExtensions([""]);
+ a[0] = 0;
+ assertEquals(a[0], 0);
+}
+
+packedStore();
+packedStore();
+
+// For holey sealed object.
+function holeyStore() {
+ let a = Object.preventExtensions([, ""]);
+ a[0] = 0;
+ assertEquals(a[0], undefined);
+}
+
+holeyStore();
+holeyStore();
+
+// Make sure IC store for holey is consistent.
+let a = Object.preventExtensions([, ""]);
+function foo() {
+ a[1] = 0;
+}
+
+foo();
+foo();
+function bar() {
+ a[0] = 1;
+}
+assertEquals(a, [, 0]);
+bar();
+assertEquals(a, [, 0]);
+bar();
+assertEquals(a, [, 0]);
+function baz() {
+ a[2] = 2;
+}
+assertEquals(a, [, 0]);
+baz();
+assertEquals(a, [, 0]);
+baz();
+assertEquals(a, [, 0]);
+
+// Reconfigure data field (e.g. change representation).
+function testReconfig() {
+ var o = ['3'];
+ function foo(i) { o.x = i; }
+ foo("string");
+ Object.preventExtensions(o);
+ Object.seal(o);
+ foo(0);
+ %HeapObjectVerify(o);
+ assertEquals(o.x, 0);
+}
+testReconfig();
+
+// Seal proxy from nonextensible object.
+PI = [];
+PI[250] = PI;
+Object.preventExtensions(PI);
+assertFalse(Object.isExtensible(PI));
+assertFalse(Object.isSealed(PI));
+var proxy = new Proxy(PI, PI);
+Object.seal(proxy);
+assertFalse(Object.isFrozen(proxy));
+assertTrue(Object.isSealed(proxy));
+
+// Freeze proxy from nonextensible object.
+PI = [];
+PI[250] = PI;
+Object.preventExtensions(PI);
+assertFalse(Object.isExtensible(PI));
+assertFalse(Object.isSealed(PI));
+var proxy = new Proxy(PI, PI);
+Object.freeze(proxy);
+assertTrue(Object.isSealed(proxy));
+assertTrue(Object.isFrozen(proxy));
diff --git a/deps/v8/test/mjsunit/regexp-tier-up.js b/deps/v8/test/mjsunit/regexp-tier-up.js
new file mode 100644
index 0000000000..e55e87f593
--- /dev/null
+++ b/deps/v8/test/mjsunit/regexp-tier-up.js
@@ -0,0 +1,92 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tier-up behavior differs between slow and fast paths in functional
+// RegExp.prototype.replace.
+// Flags: --regexp-tier-up --allow-natives-syntax --no-force-slow-path
+
+const kLatin1 = true;
+const kUnicode = false;
+
+function CheckRegexpNotYetCompiled(regexp) {
+ assertFalse(%RegexpHasBytecode(regexp, kLatin1) &&
+ %RegexpHasNativeCode(regexp, kLatin1));
+ assertFalse(%RegexpHasBytecode(regexp, kUnicode) &&
+ %RegexpHasNativeCode(regexp, kUnicode));
+}
+
+// Testing RegExp.test method which calls into Runtime_RegExpExec.
+let re = new RegExp('^.$');
+CheckRegexpNotYetCompiled(re);
+
+// Testing first execution of regexp with one-byte string subject.
+re.test("a");
+assertTrue(%RegexpHasBytecode(re, kLatin1));
+assertTrue(!%RegexpHasBytecode(re, kUnicode) &&
+ !%RegexpHasNativeCode(re, kUnicode));
+// Testing second execution of regexp now with a two-byte string subject.
+// This will compile to native code because we have a single tick counter
+// for both string representations.
+re.test("π");
+assertTrue(%RegexpHasBytecode(re, kLatin1));
+assertTrue(!%RegexpHasBytecode(re, kUnicode) &&
+ %RegexpHasNativeCode(re,kUnicode));
+// Testing tier-up when we're back to executing the regexp with a one byte
+// string.
+re.test("6");
+assertTrue(!%RegexpHasBytecode(re, kLatin1) &&
+ %RegexpHasNativeCode(re,kLatin1));
+assertTrue(!%RegexpHasBytecode(re, kUnicode) &&
+ %RegexpHasNativeCode(re,kUnicode));
+re.test("7");
+assertTrue(!%RegexpHasBytecode(re, kLatin1) &&
+ %RegexpHasNativeCode(re,kLatin1));
+assertTrue(!%RegexpHasBytecode(re, kUnicode) &&
+ %RegexpHasNativeCode(re,kUnicode));
+
+// Testing String.replace method for non-global regexps.
+var subject = "a11";
+re = /\w1/;
+CheckRegexpNotYetCompiled(re);
+
+subject.replace(re, "x");
+assertTrue(%RegexpHasBytecode(re, kLatin1));
+assertTrue(!%RegexpHasBytecode(re, kUnicode) &&
+ !%RegexpHasNativeCode(re, kUnicode));
+subject.replace(re, "x");
+assertTrue(!%RegexpHasBytecode(re, kLatin1) &&
+ %RegexpHasNativeCode(re, kLatin1));
+assertTrue(!%RegexpHasBytecode(re, kUnicode) &&
+ !%RegexpHasNativeCode(re, kUnicode));
+
+// Testing String.replace method for global regexps.
+let re_g = /\w111/g;
+CheckRegexpNotYetCompiled(re_g);
+// This regexp will not match, so it will only execute the bytecode once,
+// without tiering-up and recompiling to native code.
+subject.replace(re_g, "x");
+assertTrue(%RegexpHasBytecode(re_g, kLatin1));
+assertTrue(!%RegexpHasBytecode(re_g, kUnicode) &&
+ !%RegexpHasNativeCode(re_g, kUnicode));
+
+// This regexp will match, so it will execute twice, and tier-up.
+re_g = /\w1/g;
+CheckRegexpNotYetCompiled(re_g);
+subject.replace(re_g, "x");
+assertTrue(!%RegexpHasBytecode(re_g, kLatin1) &&
+ %RegexpHasNativeCode(re_g, kLatin1));
+assertTrue(!%RegexpHasBytecode(re_g, kUnicode) &&
+ !%RegexpHasNativeCode(re_g, kUnicode));
+
+// Testing String.replace method for global regexps with a function as a
+// parameter. This will tier-up eagerly and compile to native code right
+// away, even though the regexp is only executed once.
+function f() { return "x"; }
+re_g = /\w2/g;
+CheckRegexpNotYetCompiled(re_g);
+subject.replace(re_g, f);
+assertTrue(!%RegexpHasBytecode(re_g, kLatin1) &&
+ %RegexpHasNativeCode(re_g, kLatin1));
+assertTrue(!%RegexpHasBytecode(re_g, kUnicode) &&
+ !%RegexpHasNativeCode(re_g, kUnicode));
diff --git a/deps/v8/test/mjsunit/regress/regress-1000635.js b/deps/v8/test/mjsunit/regress/regress-1000635.js
new file mode 100644
index 0000000000..2a02774f99
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-1000635.js
@@ -0,0 +1,15 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --stress-compaction --detailed-error-stack-trace --gc-interval=1
+
+function add(a, b) {
+ throw new Error();
+}
+for (let i = 0; i < 100; ++i) {
+ try {
+ add(1, 2);
+ } catch (e) {
+ }
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-7773.js b/deps/v8/test/mjsunit/regress/regress-7773.js
index 7930ae9106..6f047711bf 100644
--- a/deps/v8/test/mjsunit/regress/regress-7773.js
+++ b/deps/v8/test/mjsunit/regress/regress-7773.js
@@ -43,8 +43,8 @@
configurable: true
};
- // Anonymous classes do not have a "name" property by default.
- assertSame(undefined, Object.getOwnPropertyDescriptor(class {}, 'name'));
+ // Anonymous classes do have a "name" property by default with a value of ''.
+ assertEquals(descriptor, Object.getOwnPropertyDescriptor(class {}, 'name'));
descriptor.value = 'C';
assertEquals(descriptor, Object.getOwnPropertyDescriptor(class C {}, 'name'));
@@ -55,8 +55,9 @@
let b = { __proto__: class {} };
assertSame('', b.__proto__.name);
- assertSame(
- undefined, Object.getOwnPropertyDescriptor(b.__proto__, 'name'));
+ descriptor.value = '';
+ assertEquals(
+ descriptor, Object.getOwnPropertyDescriptor(b.__proto__, 'name'));
let c = { fn: class F {} };
assertSame('F', c.fn.name);
diff --git a/deps/v8/test/mjsunit/regress/regress-8510-2.js b/deps/v8/test/mjsunit/regress/regress-8510-2.js
new file mode 100644
index 0000000000..b870a42df0
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-8510-2.js
@@ -0,0 +1,38 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --enable-lazy-source-positions
+
+try {
+ (function () {
+ eval(`
+ function assertLocation() {}
+ (function foo() {
+ var x = 1;
+ assertLocation();
+ throw new Error();
+ })();
+ `);
+ })();
+} catch (e) {
+ print(e.stack);
+}
+
+try {
+ (function () {
+ var assertLocation = 2;
+ (function () {
+ eval(`
+ function assertLocation() {}
+ (function foo() {
+ var x = 1;
+ assertLocation();
+ throw new Error();
+ })();
+ `);
+ })();
+ })();
+} catch (e) {
+ print(e.stack);
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-9546.js b/deps/v8/test/mjsunit/regress/regress-9546.js
new file mode 100644
index 0000000000..ecea405e98
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-9546.js
@@ -0,0 +1,53 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --allow-natives-syntax
+
+// Sanity checks.
+assertEquals(Math.hypot(3, 4), 5);
+assertEquals(Math.hypot(1, 2, 3, 4, 5, 27), 28);
+
+// Regress.
+assertEquals(Math.hypot(Infinity, NaN), Infinity);
+assertEquals(Math.hypot(NaN, 0), NaN);
+assertEquals(Math.hypot(NaN, Infinity), Infinity);
+assertEquals(Math.hypot(0, NaN), NaN);
+assertEquals(Math.hypot(NaN, 1, 2, 3, 4, 5, 0), NaN);
+assertEquals(Math.hypot(NaN, Infinity, 2, 3, 4, 5, 0), Infinity);
+
+// Verify optimized code works as intended.
+function two_hypot(a, b) {
+ return Math.hypot(a, b);
+}
+
+function six_hypot(a, b, c, d, e, f) {
+ return Math.hypot(a, b, c, d, e, f);
+}
+
+%PrepareFunctionForOptimization(two_hypot);
+two_hypot(1, 2);
+two_hypot(3, 4);
+two_hypot(5, 6);
+%OptimizeFunctionOnNextCall(two_hypot);
+assertEquals(two_hypot(3, 4), 5);
+
+// Regress 2 parameter case.
+assertEquals(two_hypot(Infinity, NaN), Infinity);
+assertEquals(two_hypot(NaN, 0), NaN);
+assertEquals(two_hypot(NaN, Infinity), Infinity);
+assertEquals(two_hypot(0, NaN), NaN);
+
+// Regress many parameters case.
+%PrepareFunctionForOptimization(six_hypot);
+six_hypot(1, 2, 3, 4, 5, 6);
+six_hypot(3, 4, 5, 6, 7, 8);
+six_hypot(5, 6, 7, 8, 9, 10);
+%OptimizeFunctionOnNextCall(six_hypot);
+assertEquals(six_hypot(1, 2, 3, 4, 5, 27), 28);
+
+assertEquals(six_hypot(0, 0, 0, 0, 0, 0), 0);
+assertEquals(six_hypot(NaN, 1, 2, 3, 4, 5, 0), NaN);
+assertEquals(six_hypot(NaN, Infinity, 2, 3, 4, 5, 0), Infinity);
+assertEquals(six_hypot(1, 2, 3, 4, 5, NaN), NaN);
+assertEquals(six_hypot(Infinity, 2, 3, 4, 5, NaN), Infinity);
diff --git a/deps/v8/test/mjsunit/regress/regress-9560.js b/deps/v8/test/mjsunit/regress/regress-9560.js
new file mode 100644
index 0000000000..71ad9f1eab
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-9560.js
@@ -0,0 +1,9 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var value = 0;
+
+[{ set prop(v) { value = v } }.prop = 12 ] = [ 1 ]
+
+assertEquals(1, value);
diff --git a/deps/v8/test/mjsunit/regress/regress-988973.js b/deps/v8/test/mjsunit/regress/regress-988973.js
new file mode 100644
index 0000000000..29c8ab43de
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-988973.js
@@ -0,0 +1,5 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+"".match(/(?:(?=a)b){5}abcde/);
diff --git a/deps/v8/test/mjsunit/regress/regress-989914.js b/deps/v8/test/mjsunit/regress/regress-989914.js
new file mode 100644
index 0000000000..199fbfdf01
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-989914.js
@@ -0,0 +1,12 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --no-lazy --stress-lazy-source-positions
+
+function foo() {
+ return () => {
+ this.test_;
+ eval();
+ }
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-991133.js b/deps/v8/test/mjsunit/regress/regress-991133.js
new file mode 100644
index 0000000000..7857389723
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-991133.js
@@ -0,0 +1,176 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-gc --allow-natives-syntax --gc-interval=416
+// Flags: --no-lazy --no-lazy-feedback-allocation --stress-lazy-source-positions
+
+"use strict";
+function WasmModuleBuilder() {}
+(function () {
+ try {
+ BigIntPrototypeValueOf = BigInt.prototype.valueOf;
+ } catch (e) {}
+ failWithMessage = function failWithMessage(message) {
+ throw new MjsUnitAssertionError(message);
+ }
+ assertSame = function assertSame(expected, found, name_opt) {
+ if (Object.is(expected, found)) return;
+ fail(prettyPrinted(expected), found, name_opt);
+ };
+ assertArrayEquals = function assertArrayEquals(expected, found, name_opt) {
+ var start = "";
+ if (name_opt) {
+ start = name_opt + " - ";
+ }
+ assertEquals(expected.length, found.length, start + "array length");
+ if (expected.length === found.length) {
+ for (var i = 0; i < expected.length; ++i) {
+ assertEquals(expected[i], found[i],
+ start + "array element at index " + i);
+ }
+ }
+ };
+ assertPropertiesEqual = function assertPropertiesEqual(expected, found,
+ name_opt) {
+ if (!deepObjectEquals(expected, found)) {
+ fail(expected, found, name_opt);
+ }
+ };
+ assertToStringEquals = function assertToStringEquals(expected, found,
+ name_opt) {
+ if (expected !== String(found)) {
+ fail(expected, found, name_opt);
+ }
+ };
+ assertTrue = function assertTrue(value, name_opt) {
+ assertEquals(true, value, name_opt);
+ };
+ assertFalse = function assertFalse(value, name_opt) {
+ assertEquals(false, value, name_opt);
+ };
+ assertNull = function assertNull(value, name_opt) {
+ if (value !== null) {
+ fail("null", value, name_opt);
+ }
+ };
+ assertNotNull = function assertNotNull(value, name_opt) {
+ if (value === null) {
+ fail("not null", value, name_opt);
+ }
+ };
+})();
+
+function getRandomProperty(v, rand) { var properties = Object.getOwnPropertyNames(v); var proto = Object.getPrototypeOf(v); if (proto) { properties = properties.concat(Object.getOwnPropertyNames(proto)); } if (properties.includes("constructor") && v.constructor.hasOwnProperty("__proto__")) { properties = properties.concat(Object.getOwnPropertyNames(v.constructor.__proto__)); } if (properties.length == 0) { return "0"; } return properties[rand % properties.length]; }
+
+
+var __v_11 = { Float32Array() {}, Uint8Array() {} };
+var __v_17 = {};
+try {
+} catch(e) { print("Caught: " + e); }
+function __f_0(){
+}
+function __f_3(a, b) {
+ (a | 0) + (b | 0);
+ return a;
+}
+function __f_23(expected, __f_20, ffi) {
+}
+try {
+(function() {
+ function __f_12(__v_11, foreign, buffer) {
+ "use asm";
+ var __v_18 = new __v_11.Uint8Array(buffer);
+ var __v_8 = new __v_9.Int32Array(buffer);
+ function __f_24(__v_23, __v_28) {
+ __v_23 = __v_23 | 0;
+ __v_28 = __v_28 | 0;
+ __v_16[__v_23 >> 2] = __v_28;
+ }
+ function __f_19(__v_23, __v_28) {
+ __v_21 = __v_19 | 0;
+ __v_28 = __v_28 | 0;
+ __v_18[__v_23 | 0] = __v_28;
+ }
+ function __f_10(__v_23) {
+ __v_0 = __v_10 | 0;
+ return __v_18[__v_23] | 0;
+ gc();
+ }
+ function __f_13(__v_23) {
+ __v_23 = __v_17 | 0;
+ return __v_18[__v_16[__v_23 >> 2] | 0] | 0;
+ }
+ return {__f_10: __f_10, __f_13: __f_13, __f_24: __f_24, __f_19: __f_19};
+ }
+ var __v_15 = new ArrayBuffer(__v_17);
+ var __v_13 = eval('(' + __f_3.toString() + ')');
+ var __v_26 = __v_13(__v_11, null, __v_15);
+ var __v_27 = { __f_10() {} };
+ __f_3(__v_13);
+ assertNotEquals(123, __v_27.__f_10(20));
+ assertNotEquals(42, __v_27.__f_10(21));
+ assertNotEquals(77, __v_27.__f_10(22));
+ __v_26.__p_711994219 = __v_26[getRandomProperty(__v_26, 711994219)];
+ __v_26.__defineGetter__(getRandomProperty(__v_26, 477679072), function() { gc(); __v_16[getRandomProperty(__v_16, 1106800630)] = __v_1[getRandomProperty(__v_1, 1151799043)]; return __v_26.__p_711994219; });
+ assertNotEquals(123, __v_27.__f_10(0));
+ assertNotEquals(42, __v_27.__f_10(4));
+ assertNotEquals(77, __v_27.__f_10(8));
+})();
+} catch(e) { print("Caught: " + e); }
+function __f_18(__v_11, foreign, heap) {
+ "use asm";
+ var __v_12 = new __v_11.Float32Array(heap);
+ var __v_14 = __v_11.Math.fround;
+ function __f_20() {
+ var __v_21 = 1.23;
+ __v_12[0] = __v_21;
+ return +__v_12[0];
+ }
+ return {__f_14: __f_20};
+}
+try {
+__f_23(Math.fround(1.23), __f_3);
+} catch(e) { print("Caught: " + e); }
+try {
+} catch(e) { print("Caught: " + e); }
+function __f_25(
+ imported_module_name, imported_function_name) {
+ var __v_11 = new WasmModuleBuilder();
+ var __v_25 = new WasmModuleBuilder();
+ let imp = i => i + 3;
+}
+try {
+__f_25('mod', 'foo');
+__f_25('mod', '☺☺happy☺☺');
+__f_25('☺☺happy☺☺', 'foo');
+__f_25('☺☺happy☺☺', '☼+☃=☹');
+} catch(e) { print("Caught: " + e); }
+function __f_26(
+ internal_name_mul, exported_name_mul, internal_name_add,
+ exported_name_add) {
+ var __v_25 = new WasmModuleBuilder();
+}
+try {
+__f_26('☺☺mul☺☺', 'mul', '☺☺add☺☺', 'add');
+__f_26('☺☺mul☺☺', '☺☺mul☺☺', '☺☺add☺☺', '☺☺add☺☺');
+(function __f_27() {
+ var __v_25 = new WasmModuleBuilder();
+ __v_25.addFunction('three snowmen: ☃☃☃').addBody([]).exportFunc();
+ assertThrows( () => __v_25.instantiate(), WebAssembly.CompileError, /Compiling function #0:"three snowmen: ☃☃☃" failed: /);
+});
+(function __f_28() {
+ var __v_25 = new WasmModuleBuilder();
+ __v_25.addImport('three snowmen: ☃☃☃', 'foo');
+ assertThrows( () => __v_25.instantiate({}), TypeError, /WebAssembly.Instance\(\): Import #0 module="three snowmen: ☃☃☃" error: /);
+});
+(function __f_29() {
+ __v_25.__defineGetter__(getRandomProperty(__v_25, 539246294), function() { gc(); return __f_21; });
+ var __v_25 = new WasmModuleBuilder();
+ __v_25.addImport('mod', 'three snowmen: ☃☃☃');
+ assertThrows(
+ () => __v_14.instantiate({mod: {}}), WebAssembly.LinkError,
+ 'WebAssembly.Instance\(\): Import #0 module="mod" function="three ' +
+ 'snowmen: ☃☃☃" error: function import requires a callable');
+});
+} catch(e) { print("Caught: " + e); }
diff --git a/deps/v8/test/mjsunit/regress/regress-992389.js b/deps/v8/test/mjsunit/regress/regress-992389.js
new file mode 100644
index 0000000000..66fa9696f6
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-992389.js
@@ -0,0 +1,14 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --jitless --gc-interval=12 --stack-size=50
+
+__f_0();
+function __f_0() {
+ try {
+ __f_0();
+ } catch(e) {
+ "b".replace(/(b)/g, function() { return "c"; });
+ }
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-996234.js b/deps/v8/test/mjsunit/regress/regress-996234.js
new file mode 100644
index 0000000000..e68ef7de3e
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-996234.js
@@ -0,0 +1,18 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --regexp-tier-up --print-code --trace-regexp-bytecodes
+
+// Test printing of regexp code and bytecode when tiering up from the
+// interpreter to the compiler.
+function __f_13544(__v_62631) {
+ __v_62631.replace(/\s/g);
+}
+
+__f_13544("No");
+
+let re = /^.$/;
+re.test("a");
+re.test("3");
+re.test("π");
diff --git a/deps/v8/test/mjsunit/regress/regress-996751.js b/deps/v8/test/mjsunit/regress/regress-996751.js
new file mode 100644
index 0000000000..71a4e329b1
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-996751.js
@@ -0,0 +1,26 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --stress-lazy-source-positions
+
+eval(`
+ eval("");
+ (function f() {
+ // This undefined should always be known to be the global undefined value,
+ // even though there is a sloppy eval call inside the top eval scope.
+ return undefined;
+ })();
+`);
+
+// The above logic should work through multiple layers of eval nesting.
+eval(`
+ eval(\`
+ eval(\\\`
+ eval("");
+ (function f() {
+ return undefined;
+ })();
+ \\\`);
+ \`);
+`);
diff --git a/deps/v8/test/mjsunit/regress/regress-bind-deoptimize.js b/deps/v8/test/mjsunit/regress/regress-bind-deoptimize.js
new file mode 100644
index 0000000000..a01d150d69
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-bind-deoptimize.js
@@ -0,0 +1,24 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --opt --no-always-opt
+
+(function() {
+ function bla(x) {
+ return this[x];
+ }
+
+ function foo(f) {
+ return bla.bind(f())(0);
+ };
+
+ %PrepareFunctionForOptimization(foo);
+ foo(() => { return [true]; });
+ foo(() => { return [true]; });
+ %OptimizeFunctionOnNextCall(foo);
+ foo(() => { return [true]; });
+ assertOptimized(foo);
+ foo(() => { bla.a = 1; return [true]; });
+ assertUnoptimized(foo);
+})();
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-1000094.js b/deps/v8/test/mjsunit/regress/regress-crbug-1000094.js
new file mode 100644
index 0000000000..40f6799c4e
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-1000094.js
@@ -0,0 +1,15 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --enable-lazy-source-positions --stress-lazy-source-positions
+
+var f = (( {a: b} = {
+ a() {
+ return b;
+ }
+}) => b)()();
+
+// b should get assigned to the inner function a, which then ends up returning
+// itself.
+assertEquals(f, f());
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-1000170.js b/deps/v8/test/mjsunit/regress/regress-crbug-1000170.js
new file mode 100644
index 0000000000..41975c7a72
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-1000170.js
@@ -0,0 +1,10 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --no-lazy --stress-lazy-source-positions --enable-lazy-source-positions
+
+(function a() {
+ function b() { a(); }
+ function c() { eval(); }
+})();
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-109362.js b/deps/v8/test/mjsunit/regress/regress-crbug-109362.js
index cf7cd4e5fa..54bae56a1a 100644
--- a/deps/v8/test/mjsunit/regress/regress-crbug-109362.js
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-109362.js
@@ -19,7 +19,7 @@ function test(expectation, f) {
1 + reference_error //@ sourceURL=evaltest
})
*/
-test("3:5", new Function(
+test("1:5", new Function(
'1 + reference_error //@ sourceURL=evaltest'));
/*
(function(x
@@ -28,7 +28,7 @@ test("3:5", new Function(
1 + reference_error //@ sourceURL=evaltest
})
*/
-test("4:6", new Function(
+test("2:6", new Function(
'x', '\n 1 + reference_error //@ sourceURL=evaltest'));
/*
(function(x
@@ -40,7 +40,7 @@ test("4:6", new Function(
1 + reference_error //@ sourceURL=evaltest
})
*/
-test("7:6", new Function(
+test("5:6", new Function(
'x\n\n', "z//\n", "y", '\n 1 + reference_error //@ sourceURL=evaltest'));
/*
(function(x/\*,z//
@@ -49,7 +49,7 @@ test("7:6", new Function(
1 + reference_error //@ sourceURL=evaltest
})
*/
-test("4:5", new Function(
+test("2:5", new Function(
'x/*', "z//\n", "y*/", '1 + reference_error //@ sourceURL=evaltest'));
/*
(function () {
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-734051.js b/deps/v8/test/mjsunit/regress/regress-crbug-734051.js
index 2655db08a7..7d8aa9cb85 100644
--- a/deps/v8/test/mjsunit/regress/regress-crbug-734051.js
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-734051.js
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-function TestMutableHeapNumberLiteral() {
+function TestHeapNumberLiteral() {
var data = { a: 0, b: 0 };
data.a += 0.1;
assertEquals(0.1, data.a);
assertEquals(0, data.b);
};
-TestMutableHeapNumberLiteral();
-TestMutableHeapNumberLiteral();
-TestMutableHeapNumberLiteral();
-TestMutableHeapNumberLiteral();
-TestMutableHeapNumberLiteral();
+TestHeapNumberLiteral();
+TestHeapNumberLiteral();
+TestHeapNumberLiteral();
+TestHeapNumberLiteral();
+TestHeapNumberLiteral();
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-918301.js b/deps/v8/test/mjsunit/regress/regress-crbug-918301.js
new file mode 100644
index 0000000000..a93ec3e9df
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-918301.js
@@ -0,0 +1,5 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+assertThrows(() => Object.getOwnPropertyDescriptors(Array(1e9).join('c')), RangeError);
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-980183.js b/deps/v8/test/mjsunit/regress/regress-crbug-980183.js
new file mode 100644
index 0000000000..f4b4f5cfce
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-980183.js
@@ -0,0 +1,39 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f() {
+ const o = {};
+ // The order of the following operations is significant
+ o.a = 0;
+ o[1024] = 1; // An offset of >=1024 is required
+ delete o.a;
+ o.b = 2;
+ return o.b;
+}
+%PrepareFunctionForOptimization(f);
+f();
+f();
+%OptimizeFunctionOnNextCall(f);
+f();
+
+
+function g(o) {
+ o.b = 2;
+}
+function h() {
+ const o = {};
+ o.a = 0;
+ o[1024] = 1;
+ delete o.a;
+ g(o);
+ assertEquals(o.b, 2);
+}
+%NeverOptimizeFunction(g);
+%PrepareFunctionForOptimization(h);
+h();
+h();
+%OptimizeFunctionOnNextCall(h);
+h();
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-980422.js b/deps/v8/test/mjsunit/regress/regress-crbug-980422.js
new file mode 100644
index 0000000000..93ea619afa
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-980422.js
@@ -0,0 +1,29 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --enable-lazy-source-positions --stress-lazy-source-positions
+(function () {
+ ((d, e = d) => {
+ return d * e;
+ })();
+})();
+
+try {
+ (function () {
+ ((d, e = f, f = d) => {
+ // Won't get here as the initializers will cause a ReferenceError
+ })();
+ })();
+ assertUnreachable();
+} catch (ex) {
+ assertInstanceof(ex, ReferenceError);
+ // Not using assertThrows because we need to access ex.stack to force
+ // collection of source positions.
+ print(ex.stack);
+}
+
+// Check that spreads in arrow functions work
+(function () {
+ ((...args) => args)();
+})();
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-981701.js b/deps/v8/test/mjsunit/regress/regress-crbug-981701.js
new file mode 100644
index 0000000000..f38591b600
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-981701.js
@@ -0,0 +1,6 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --throws --enable-lazy-source-positions --stress-lazy-source-positions
+((...{a: [b, ...{b: [] = b, a: c}] = b}) => b)(-2);
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-986187.js b/deps/v8/test/mjsunit/regress/regress-crbug-986187.js
new file mode 100644
index 0000000000..6fd2ccb5bf
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-986187.js
@@ -0,0 +1,14 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-gc
+
+var obj = {}
+obj.__proto__ = null;
+Object.defineProperty(obj, "prop", {
+ set: gc
+});
+for (var i = 0; i < 100 ; ++i) {
+ obj["prop"] = 0;
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-987205.js b/deps/v8/test/mjsunit/regress/regress-crbug-987205.js
new file mode 100644
index 0000000000..51903919e4
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-987205.js
@@ -0,0 +1,68 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(x) {
+ // This used to generate two distinct stores to #undefined, violating the load
+ // elimination invariant that there are no two store to the same const field:
+ var obj1 = {
+ [undefined]: 1,
+ 'undefined': 1
+ };
+ // This one cannot be discharged statically:
+ var obj2 = {
+ [undefined]: x,
+ 'undefined': 1
+ };
+ // Some more variations that exercise AllocateFastLiteral:
+ var obj3 = {
+ 'undefined': 1,
+ [undefined]: x
+ };
+ var obj4 = {
+ 'undefined': x,
+ [undefined]: 1
+ };
+ assertEquals(obj1.undefined, 1);
+ assertEquals(obj2.undefined, 1);
+ assertEquals(obj3.undefined, x);
+ assertEquals(obj4.undefined, 1);
+}
+
+%PrepareFunctionForOptimization(f);
+f(1);
+f(1);
+%OptimizeFunctionOnNextCall(f);
+f(2);
+
+
+function g(x) {
+ var obj1 = {
+ [undefined]: 1,
+ [undefined]: 1
+ };
+ var obj2 = {
+ [undefined]: 1,
+ [undefined]: x
+ };
+ var obj3 = {
+ [undefined]: x,
+ [undefined]: 1
+ };
+ var obj4 = {
+ [undefined]: x,
+ [undefined]: x
+ };
+ assertEquals(obj1.undefined, 1);
+ assertEquals(obj2.undefined, x);
+ assertEquals(obj3.undefined, 1);
+ assertEquals(obj4.undefined, x);
+}
+
+%PrepareFunctionForOptimization(g);
+g(1);
+g(1);
+%OptimizeFunctionOnNextCall(g);
+g(2);
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-988304.js b/deps/v8/test/mjsunit/regress/regress-crbug-988304.js
new file mode 100644
index 0000000000..a9ceec4d59
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-988304.js
@@ -0,0 +1,14 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --enable-lazy-source-positions --stress-lazy-source-positions
+
+(function() {
+ ((x = 1) => {
+ function foo() {
+ x;
+ }
+ return x;
+ })();
+})();
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-990582.js b/deps/v8/test/mjsunit/regress/regress-crbug-990582.js
new file mode 100644
index 0000000000..e78775fdbb
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-990582.js
@@ -0,0 +1,19 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --invoke-weak-callbacks --budget-for-feedback-vector-allocation=0
+
+__v_0 = 0;
+function __f_0() {
+ try {
+ __f_0();
+ } catch(e) {
+ if (__v_0 < 50) {
+ __v_0++;
+/()/g, new [];
+ }
+ }
+}
+ __f_0();
+Realm.shared = this;
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-992914.js b/deps/v8/test/mjsunit/regress/regress-crbug-992914.js
new file mode 100644
index 0000000000..31d0e76c34
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-992914.js
@@ -0,0 +1,59 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function mainFreeze() {
+ const v2 = {foo:1.1};
+ Object.freeze(v2);
+ const v12 = {foo:2.2};
+ Object.preventExtensions(v12);
+ Object.freeze(v12);
+ const v18 = {foo:Object};
+ v12.__proto__ = 0;
+ v2[5] = 1;
+}
+mainFreeze();
+
+function mainSeal() {
+ const v2 = {foo:1.1};
+ Object.seal(v2);
+ const v12 = {foo:2.2};
+ Object.preventExtensions(v12);
+ Object.seal(v12);
+ const v18 = {foo:Object};
+ v12.__proto__ = 0;
+ v2[5] = 1;
+}
+mainSeal();
+
+function testSeal() {
+ a = new RangeError(null, null, null);
+ a.toFixed = () => {};
+ e = Object.seal(a);
+ a = new RangeError(null, null, null);
+ a.toFixed = () => {};
+ k = Object.preventExtensions(a);
+ l = Object.seal(a);
+ a.toFixed = () => {};
+ assertThrows(() => {
+ Array.prototype.unshift.call(l, false, Infinity);
+ }, TypeError);
+}
+testSeal();
+
+function testFreeze() {
+ a = new RangeError(null, null, null);
+ a.toFixed = () => {};
+ e = Object.freeze(a);
+ a = new RangeError(null, null, null);
+ a.toFixed = () => {};
+ k = Object.preventExtensions(a);
+ l = Object.freeze(a);
+ a.toFixed = () => {};
+ assertThrows(() => {
+ Array.prototype.unshift.call(l, false, Infinity);
+ }, TypeError);
+}
+testFreeze();
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-993980.js b/deps/v8/test/mjsunit/regress/regress-crbug-993980.js
new file mode 100644
index 0000000000..aea4eeb83e
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-993980.js
@@ -0,0 +1,20 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function () {
+ // generate some sample data
+ let data = new Array(1600).fill(null).map((e, i) => ({
+ invariantKey: 'v',
+ ['randomKey' + i]: 'w',
+
+ }));
+
+ // use json parser
+ data = JSON.parse(JSON.stringify(data))
+
+ // look for undefined values
+ for (const t of data) {
+ assertFalse(Object.keys(t).some(k => !t[k]));
+ }
+})()
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-994041.js b/deps/v8/test/mjsunit/regress/regress-crbug-994041.js
new file mode 100644
index 0000000000..396cfa2c1e
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-994041.js
@@ -0,0 +1,9 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+v0 = Array().join();
+RegExp.prototype.__defineSetter__(0, function() {
+})
+v24 = v0.search();
+assertEquals(v24, 0);
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-994719.js b/deps/v8/test/mjsunit/regress/regress-crbug-994719.js
new file mode 100644
index 0000000000..72a9819331
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-994719.js
@@ -0,0 +1,12 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --no-lazy --enable-lazy-source-positions --stress-lazy-source-positions
+
+class C extends Object {
+ constructor() {
+ () => this;
+ super();
+ }
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-997056.js b/deps/v8/test/mjsunit/regress/regress-crbug-997056.js
new file mode 100644
index 0000000000..02e2772ddb
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-997056.js
@@ -0,0 +1,12 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+for (let i = 0; i < 4; ++i) {
+ var obj1 = {
+ get [obj1]() {},
+ ...obj2,
+ };
+ var obj2 = { [obj1]: 0 };
+ print(obj2);
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-997057.js b/deps/v8/test/mjsunit/regress/regress-crbug-997057.js
new file mode 100644
index 0000000000..8f90b5e05c
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-997057.js
@@ -0,0 +1,31 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --no-lazy-feedback-allocation
+
+arr0 = [];
+
+var obj = {};
+
+Array.prototype[12] = 10;
+arr0 = [];
+Array.prototype[0] = 153;
+
+for (var elem in arr0) {
+ obj.length = {
+ toString: function () {
+ }
+ };
+}
+
+function baz() {
+ obj.length, arr0.length;
+}
+
+var arr = [{}, [], {}];
+for (var i in arr) {
+ baz();
+ for (var j = 0; j < 100000; j++) {
+ }
+}
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-997320.js b/deps/v8/test/mjsunit/regress/regress-crbug-997320.js
new file mode 100644
index 0000000000..5f8dd56200
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-997320.js
@@ -0,0 +1,8 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --no-lazy --stress-lazy-source-positions
+// Flags: --enable-lazy-source-positions
+
+async(a, b = a) => {};
diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-999450.js b/deps/v8/test/mjsunit/regress/regress-crbug-999450.js
new file mode 100644
index 0000000000..6d005007b5
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-crbug-999450.js
@@ -0,0 +1,10 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --no-lazy --stress-lazy-source-positions --enable-lazy-source-positions
+
+(function foo() {
+ foo = null;
+ () => foo;
+})
diff --git a/deps/v8/test/mjsunit/regress/regress-inlining-printing.js b/deps/v8/test/mjsunit/regress/regress-inlining-printing.js
new file mode 100644
index 0000000000..9a574ad308
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-inlining-printing.js
@@ -0,0 +1,24 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --trace-turbo-inlining
+// Flags: --max-inlined-bytecode-size-small=0
+
+function f() {}
+function g() {}
+function h() {}
+
+function test(n) {
+ h;
+ (n == 0 ? f : (n > 0 ? g : h))();
+}
+
+%EnsureFeedbackVectorForFunction(f);
+%EnsureFeedbackVectorForFunction(g);
+
+%PrepareFunctionForOptimization(test);
+test(0);
+test(1);
+%OptimizeFunctionOnNextCall(test);
+test(0);
diff --git a/deps/v8/test/mjsunit/regress/regress-unlink-closures-on-deopt.js b/deps/v8/test/mjsunit/regress/regress-unlink-closures-on-deopt.js
index 2b34159c14..c2e6212eb1 100644
--- a/deps/v8/test/mjsunit/regress/regress-unlink-closures-on-deopt.js
+++ b/deps/v8/test/mjsunit/regress/regress-unlink-closures-on-deopt.js
@@ -14,7 +14,6 @@ function foo() {
let g1 = foo();
let g2 = foo();
%PrepareFunctionForOptimization(g1);
-%PrepareFunctionForOptimization(g2);
g1({ f : 1});
g1({ f : 2});
@@ -22,9 +21,10 @@ g2({ f : 2});
g2({ f : 2});
%OptimizeFunctionOnNextCall(g1);
-%OptimizeFunctionOnNextCall(g2);
-
g1({ f : 1});
+
+%PrepareFunctionForOptimization(g2);
+%OptimizeFunctionOnNextCall(g2);
g2({ f : 2});
g1({});
diff --git a/deps/v8/test/mjsunit/regress/regress-v8-9511.js b/deps/v8/test/mjsunit/regress/regress-v8-9511.js
new file mode 100644
index 0000000000..b2bff41611
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-v8-9511.js
@@ -0,0 +1,11 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var f = function() { return 1; };
+
+(function func1() {
+ eval("var f = function canary(s) { return 2; }");
+})();
+
+assertEquals(f(), 1);
diff --git a/deps/v8/test/mjsunit/regress/regress-v8-9656.js b/deps/v8/test/mjsunit/regress/regress-v8-9656.js
new file mode 100644
index 0000000000..98779b18f9
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-v8-9656.js
@@ -0,0 +1,14 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+// Files: test/mjsunit/code-coverage-utils.js
+
+%DebugToggleBlockCoverage(true);
+
+try {
+ throw new Error();
+} catch (e) {
+ e.stack;
+}
diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-8505.js b/deps/v8/test/mjsunit/regress/wasm/regress-8505.js
index 0488723e4f..b1fdedfc93 100644
--- a/deps/v8/test/mjsunit/regress/wasm/regress-8505.js
+++ b/deps/v8/test/mjsunit/regress/wasm/regress-8505.js
@@ -150,18 +150,18 @@ function assertBinop(name, math_func, wasm_func) {
}
let stdlib = this;
-function Module_exp(stdlib) {
+function Module_pow(stdlib) {
"use asm";
- var Stdlib = stdlib.Math.exp;
+ var Stdlib = stdlib.Math.pow;
- function NAME(a, b) {
+ function pow(a, b) {
a = +a;
b = +b;
return +Stdlib(a, b);
}
- return {exp: exp};
+ return {pow: pow};
}
function wasmBinop(name, sig) {
@@ -181,8 +181,8 @@ function wasmBinop(name, sig) {
}
function asmBinop(name) {
- let instance = Module_exp(stdlib);
- assertTrue(%IsAsmWasmCode(Module_exp));
+ let instance = Module_pow(stdlib);
+ assertTrue(%IsAsmWasmCode(Module_pow));
let asm_func = instance[name];
if (typeof asm_func != "function") throw "asm[" + full_name + "] not found";
@@ -190,7 +190,7 @@ function asmBinop(name) {
}
(function TestF64() {
- let name = 'exp';
+ let name = 'pow';
let math_func = Math[name];
let wasm_func = wasmBinop(name, kSig_d_dd);
diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-crbug-1002388.js b/deps/v8/test/mjsunit/regress/wasm/regress-crbug-1002388.js
new file mode 100644
index 0000000000..7ad066a666
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/wasm/regress-crbug-1002388.js
@@ -0,0 +1,12 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --experimental-wasm-type-reflection
+
+(function TestTableSetAndGetFunction() {
+ let func = new WebAssembly.Function({ parameters: [], results: [] }, x => x);
+ let table = new WebAssembly.Table({ element: "anyfunc", initial: 1 });
+ table.set(0, func);
+ table.get(0);
+})();
diff --git a/deps/v8/test/mjsunit/wasm/asm-wasm-math-intrinsic.js b/deps/v8/test/mjsunit/wasm/asm-wasm-math-intrinsic.js
index f683436246..59fcc66d7e 100644
--- a/deps/v8/test/mjsunit/wasm/asm-wasm-math-intrinsic.js
+++ b/deps/v8/test/mjsunit/wasm/asm-wasm-math-intrinsic.js
@@ -246,7 +246,6 @@ function assertBinop(name, math_func, asm_func) {
];
for (name of f64_intrinsics) {
- if (name == 'pow') continue; // TODO(8505): asm.js correctness
let math_func = Math[name];
let f32 = false;
print('Testing (f64) Math.' + name);
diff --git a/deps/v8/test/mjsunit/wasm/bigint.js b/deps/v8/test/mjsunit/wasm/bigint.js
index d64c0e0623..ff9046e9dc 100644
--- a/deps/v8/test/mjsunit/wasm/bigint.js
+++ b/deps/v8/test/mjsunit/wasm/bigint.js
@@ -7,7 +7,7 @@
load("test/mjsunit/wasm/wasm-module-builder.js");
(function TestWasmI64ToJSBigInt() {
- var builder = new WasmModuleBuilder();
+ let builder = new WasmModuleBuilder();
builder
.addFunction("fn", kSig_l_v) // () -> i64
@@ -16,22 +16,22 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
])
.exportFunc();
- var module = builder.instantiate();
+ let module = builder.instantiate();
assertEquals(typeof module.exports.fn(), "bigint");
assertEquals(module.exports.fn(), 3n);
})();
(function TestJSBigIntToWasmI64Global() {
- var builder = new WasmModuleBuilder();
+ let builder = new WasmModuleBuilder();
- var a_global_index = builder
+ let a_global_index = builder
.addImportedGlobal("mod", "a", kWasmI64)
- var b_global_index = builder
+ let b_global_index = builder
.addImportedGlobal("mod", "b", kWasmI64);
- var c_global_index = builder
+ let c_global_index = builder
.addImportedGlobal("mod", "c", kWasmI64);
builder
@@ -39,7 +39,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
.addExportOfKind('b', kExternalGlobal, b_global_index)
.addExportOfKind('c', kExternalGlobal, c_global_index);
- var module = builder.instantiate({
+ let module = builder.instantiate({
mod: {
a: 1n,
b: 2n ** 63n,
@@ -53,16 +53,16 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestJSBigIntToWasmI64MutableGlobal() {
- var builder = new WasmModuleBuilder();
+ let builder = new WasmModuleBuilder();
- var a_global_index = builder
+ let a_global_index = builder
.addImportedGlobal("mod", "a", kWasmI64, /* mutable = */ true)
builder
.addExportOfKind('a', kExternalGlobal, a_global_index);
// as non object
- var fn = () => builder.instantiate({
+ let fn = () => builder.instantiate({
mod: {
a: 1n,
}
@@ -71,7 +71,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertThrows(fn, WebAssembly.LinkError);
// as WebAssembly.Global object
- var module = builder.instantiate({
+ let module = builder.instantiate({
mod: {
a: new WebAssembly.Global({ value: "i64", mutable: true }, 1n),
}
@@ -81,20 +81,19 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestJSBigIntToWasmI64Identity() {
- var builder = new WasmModuleBuilder();
+ let builder = new WasmModuleBuilder();
builder
.addFunction("f", kSig_l_l) // i64 -> i64
.addBody([
- kExprGetLocal, 0x0,
+ kExprGetLocal, 0,
])
.exportFunc();
- var module = builder.instantiate();
- var f = module.exports.f;
+ let module = builder.instantiate();
+ let f = module.exports.f;
assertEquals(f(0n), 0n);
- assertEquals(f(-0n), -0n);
assertEquals(f(123n), 123n);
assertEquals(f(-123n), -123n);
@@ -103,9 +102,31 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertThrows(() => f(5), TypeError);
})();
+(function TestJSBigIntToWasmI64Projection() {
+ let builder = new WasmModuleBuilder();
+
+ builder
+ .addFunction("f", kSig_l_ll) // i64 -> i64
+ .addBody([
+ kExprGetLocal, 1,
+ ])
+ .exportFunc();
+
+ let module = builder.instantiate();
+ let f = module.exports.f;
+
+ assertEquals(f(1n, 0n), 0n);
+ assertEquals(f(1n, 123n), 123n);
+ assertEquals(f(1n, -123n), -123n);
+
+ assertEquals(f(1n, "5"), 5n);
+
+ assertThrows(() => f(1n, 5), TypeError);
+})();
+
(function TestI64Global() {
- var argument = { "value": "i64", "mutable": true };
- var global = new WebAssembly.Global(argument);
+ let argument = { "value": "i64", "mutable": true };
+ let global = new WebAssembly.Global(argument);
assertEquals(global.value, 0n); // initial value
@@ -117,10 +138,10 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestI64GlobalValueOf() {
- var argument = { "value": "i64" };
+ let argument = { "value": "i64" };
// as literal
- var global = new WebAssembly.Global(argument, {
+ let global = new WebAssembly.Global(argument, {
valueOf() {
return 123n;
}
@@ -128,7 +149,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertEquals(global.value, 123n);
// as string
- var global2 = new WebAssembly.Global(argument, {
+ let global2 = new WebAssembly.Global(argument, {
valueOf() {
return "321";
}
@@ -137,7 +158,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestInvalidValtypeGlobalErrorMessage() {
- var argument = { "value": "some string" };
+ let argument = { "value": "some string" };
assertThrows(() => new WebAssembly.Global(argument), TypeError);
try {
@@ -149,26 +170,26 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
})();
(function TestGlobalI64ValueWrongType() {
- var argument = { "value": "i64" };
+ let argument = { "value": "i64" };
assertThrows(() => new WebAssembly.Global(argument, 666), TypeError);
})();
(function TestGlobalI64SetWrongType() {
- var argument = { "value": "i64", "mutable": true };
- var global = new WebAssembly.Global(argument);
+ let argument = { "value": "i64", "mutable": true };
+ let global = new WebAssembly.Global(argument);
assertThrows(() => global.value = 1, TypeError);
})();
(function TestFuncParamF64PassingBigInt() {
- var builder = new WasmModuleBuilder();
+ let builder = new WasmModuleBuilder();
builder
.addFunction("f", kSig_v_d) // f64 -> ()
.addBody([])
.exportFunc();
- var module = builder.instantiate();
+ let module = builder.instantiate();
assertThrows(() => module.exports.f(123n), TypeError);
})();
diff --git a/deps/v8/test/mjsunit/wasm/exceptions-global.js b/deps/v8/test/mjsunit/wasm/exceptions-global.js
index c3f208ca16..4a74dfb010 100644
--- a/deps/v8/test/mjsunit/wasm/exceptions-global.js
+++ b/deps/v8/test/mjsunit/wasm/exceptions-global.js
@@ -115,10 +115,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertThrowsEquals(() => instance.exports.rethrow_exnref(), exception2);
})();
-// TODO(mstarzinger): Add the following test once proposal makes it clear how
-// far interaction with the mutable globals proposal is intended to go.
// Test loading an imported mutable "exnref" being changed from the outside.
-/*(function TestGlobalExnRefGetImportedMutableAndRethrow() {
+(function TestGlobalExnRefGetImportedMutableAndRethrow() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let g_index = builder.addImportedGlobal("m", "exn", kWasmExnRef, true);
@@ -135,7 +133,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertThrowsEquals(() => instance.exports.rethrow_exnref(), exception1);
let exception2 = mutable_global.value = "an even fancier exception";
assertThrowsEquals(() => instance.exports.rethrow_exnref(), exception2);
-})();*/
+})();
// Test custom initialization index for a global "exnref" variable.
(function TestGlobalExnRefInitIndex() {
diff --git a/deps/v8/test/mjsunit/wasm/multi-value.js b/deps/v8/test/mjsunit/wasm/multi-value.js
index 1948801958..31f9e8149b 100644
--- a/deps/v8/test/mjsunit/wasm/multi-value.js
+++ b/deps/v8/test/mjsunit/wasm/multi-value.js
@@ -319,3 +319,34 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertEquals(instance.exports.main(2), 8);
assertEquals(instance.exports.main(10), 200);
})();
+
+(function MultiJSReturnTest() {
+ print(arguments.callee.name);
+ let builder = new WasmModuleBuilder();
+ let sig_fi_if = makeSig([kWasmI32, kWasmF32], [kWasmF32, kWasmI32]);
+
+ builder.addFunction("swap", sig_fi_if)
+ .addBody([
+ kExprGetLocal, 1,
+ kExprGetLocal, 0])
+ .exportAs("swap");
+ builder.addFunction("addsubmul", kSig_iii_i)
+ .addBody([
+ kExprGetLocal, 0,
+ kExprGetLocal, 0,
+ kExprI32Add,
+ kExprGetLocal, 0,
+ kExprGetLocal, 0,
+ kExprI32Sub,
+ kExprGetLocal, 0,
+ kExprGetLocal, 0,
+ kExprI32Mul])
+ .exportAs("addsubmul");
+
+ let module = new WebAssembly.Module(builder.toBuffer());
+ let instance = new WebAssembly.Instance(module);
+ assertEquals(instance.exports.swap(0, 1.5), [1.5, 0]);
+ assertEquals(instance.exports.swap(2, 3.75), [3.75, 2]);
+ assertEquals(instance.exports.addsubmul(4), [8, 0, 16]);
+ assertEquals(instance.exports.addsubmul(5), [10, 0, 25]);
+})();
diff --git a/deps/v8/test/mjsunit/wasm/test-wasm-module-builder.js b/deps/v8/test/mjsunit/wasm/test-wasm-module-builder.js
index eb0a95384c..96d3a0bac5 100644
--- a/deps/v8/test/mjsunit/wasm/test-wasm-module-builder.js
+++ b/deps/v8/test/mjsunit/wasm/test-wasm-module-builder.js
@@ -13,153 +13,174 @@ function instantiate(buffer, ffi) {
}
(function BasicTest() {
- print("BasicTest");
- let builder = new WasmModuleBuilder();
- builder.addMemory(1, 2, false);
- builder.addFunction("foo", kSig_i_v)
- .addBody([kExprI32Const, 11])
- .exportAs("blarg");
-
- var buffer = builder.toBuffer(debug);
- var instance = instantiate(buffer);
- assertEquals(11, instance.exports.blarg());
+ print(arguments.callee.name);
+ let builder = new WasmModuleBuilder();
+ builder.addMemory(1, 2, false);
+ builder.addFunction('foo', kSig_i_v)
+ .addBody([kExprI32Const, 11])
+ .exportAs('blarg');
+
+ var buffer = builder.toBuffer(debug);
+ var instance = instantiate(buffer);
+ assertEquals(11, instance.exports.blarg());
})();
(function ImportTest() {
- print("ImportTest");
- let builder = new WasmModuleBuilder();
- var index = builder.addImport("", "print", makeSig_v_x(kWasmI32));
- builder.addFunction("foo", kSig_v_v)
- .addBody([kExprI32Const, 13, kExprCallFunction, index])
- .exportAs("main");
-
- var buffer = builder.toBuffer(debug);
- var instance = instantiate(buffer, {"": {print: print}});
- print("should print 13! ");
- instance.exports.main();
+ print(arguments.callee.name);
+ let builder = new WasmModuleBuilder();
+ var index = builder.addImport('', 'print', makeSig_v_x(kWasmI32));
+ builder.addFunction('foo', kSig_v_v)
+ .addBody([kExprI32Const, 13, kExprCallFunction, index])
+ .exportAs('main');
+
+ var buffer = builder.toBuffer(debug);
+ var instance = instantiate(buffer, {'': {print: print}});
+ print('should print 13! ');
+ instance.exports.main();
})();
(function LocalsTest() {
- print("LocalsTest");
+ print(arguments.callee.name);
+ let builder = new WasmModuleBuilder();
+ builder.addFunction(undefined, kSig_i_i)
+ .addLocals({i32_count: 1})
+ .addBody([kExprGetLocal, 0, kExprSetLocal, 1, kExprGetLocal, 1])
+ .exportAs('main');
+
+ var buffer = builder.toBuffer(debug);
+ var instance = instantiate(buffer);
+ assertEquals(19, instance.exports.main(19));
+ assertEquals(27777, instance.exports.main(27777));
+})();
+
+(function LocalsTest2() {
+ print(arguments.callee.name);
+ // TODO(titzer): i64 only works on 64-bit platforms.
+ var types = [
+ {locals: {i32_count: 1}, type: kWasmI32},
+ // {locals: {i64_count: 1}, type: kWasmI64},
+ {locals: {f32_count: 1}, type: kWasmF32},
+ {locals: {f64_count: 1}, type: kWasmF64},
+ ];
+
+ for (p of types) {
let builder = new WasmModuleBuilder();
- builder.addFunction(undefined, kSig_i_i)
- .addLocals({i32_count: 1})
+ builder.addFunction(undefined, makeSig_r_x(p.type, p.type))
+ .addLocals(p.locals)
.addBody([kExprGetLocal, 0, kExprSetLocal, 1, kExprGetLocal, 1])
- .exportAs("main");
+ .exportAs('main');
var buffer = builder.toBuffer(debug);
var instance = instantiate(buffer);
assertEquals(19, instance.exports.main(19));
assertEquals(27777, instance.exports.main(27777));
-})();
-
-(function LocalsTest2() {
- print("LocalsTest2");
- // TODO(titzer): i64 only works on 64-bit platforms.
- var types = [
- {locals: {i32_count: 1}, type: kWasmI32},
-// {locals: {i64_count: 1}, type: kWasmI64},
- {locals: {f32_count: 1}, type: kWasmF32},
- {locals: {f64_count: 1}, type: kWasmF64},
- ];
-
- for (p of types) {
- let builder = new WasmModuleBuilder();
- builder.addFunction(undefined, makeSig_r_x(p.type, p.type))
- .addLocals(p.locals)
- .addBody([kExprGetLocal, 0, kExprSetLocal, 1, kExprGetLocal, 1])
- .exportAs("main");
-
- var buffer = builder.toBuffer(debug);
- var instance = instantiate(buffer);
- assertEquals(19, instance.exports.main(19));
- assertEquals(27777, instance.exports.main(27777));
- }
+ }
})();
(function CallTest() {
- print("CallTest");
- let builder = new WasmModuleBuilder();
- builder.addFunction("add", kSig_i_ii)
- .addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprI32Add]);
- builder.addFunction("main", kSig_i_ii)
- .addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprCallFunction, 0])
- .exportAs("main");
-
- var instance = builder.instantiate();
- assertEquals(44, instance.exports.main(11, 33));
- assertEquals(7777, instance.exports.main(2222, 5555));
+ print(arguments.callee.name);
+ let builder = new WasmModuleBuilder();
+ builder.addFunction('add', kSig_i_ii).addBody([
+ kExprGetLocal, 0, kExprGetLocal, 1, kExprI32Add
+ ]);
+ builder.addFunction('main', kSig_i_ii)
+ .addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprCallFunction, 0])
+ .exportAs('main');
+
+ var instance = builder.instantiate();
+ assertEquals(44, instance.exports.main(11, 33));
+ assertEquals(7777, instance.exports.main(2222, 5555));
})();
(function IndirectCallTest() {
- print("IndirectCallTest");
- let builder = new WasmModuleBuilder();
- builder.addFunction("add", kSig_i_ii)
- .addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprI32Add]);
- builder.addFunction("main", kSig_i_iii)
- .addBody([kExprGetLocal,
- 1, kExprGetLocal, 2, kExprGetLocal, 0, kExprCallIndirect, 0, kTableZero])
- .exportAs("main");
- builder.appendToTable([0]);
-
- var instance = builder.instantiate();
- assertEquals(44, instance.exports.main(0, 11, 33));
- assertEquals(7777, instance.exports.main(0, 2222, 5555));
- assertThrows(function() { instance.exports.main(1, 1, 1); });
+ print(arguments.callee.name);
+ let builder = new WasmModuleBuilder();
+ builder.addFunction('add', kSig_i_ii).addBody([
+ kExprGetLocal, 0, kExprGetLocal, 1, kExprI32Add
+ ]);
+ builder.addFunction('main', kSig_i_iii)
+ .addBody([
+ kExprGetLocal, 1, kExprGetLocal, 2, kExprGetLocal, 0, kExprCallIndirect,
+ 0, kTableZero
+ ])
+ .exportAs('main');
+ builder.appendToTable([0]);
+
+ var instance = builder.instantiate();
+ assertEquals(44, instance.exports.main(0, 11, 33));
+ assertEquals(7777, instance.exports.main(0, 2222, 5555));
+ assertThrows(() => instance.exports.main(1, 1, 1));
})();
(function DataSegmentTest() {
- print("DataSegmentTest");
- let builder = new WasmModuleBuilder();
- builder.addMemory(1, 1, false);
- builder.addFunction("load", kSig_i_i)
- .addBody([kExprGetLocal, 0, kExprI32LoadMem, 0, 0])
- .exportAs("load");
- builder.addDataSegment(0, [9, 9, 9, 9]);
-
- var buffer = builder.toBuffer(debug);
- var instance = instantiate(buffer);
- assertEquals(151587081, instance.exports.load(0));
+ print(arguments.callee.name);
+ let builder = new WasmModuleBuilder();
+ builder.addMemory(1, 1, false);
+ builder.addFunction('load', kSig_i_i)
+ .addBody([kExprGetLocal, 0, kExprI32LoadMem, 0, 0])
+ .exportAs('load');
+ builder.addDataSegment(0, [9, 9, 9, 9]);
+
+ var buffer = builder.toBuffer(debug);
+ var instance = instantiate(buffer);
+ assertEquals(151587081, instance.exports.load(0));
})();
-
(function BasicTestWithUint8Array() {
- print("BasicTestWithUint8Array");
- let builder = new WasmModuleBuilder();
- builder.addMemory(1, 2, false);
- builder.addFunction("foo", kSig_i_v)
- .addBody([kExprI32Const, 17])
- .exportAs("blarg");
-
- var buffer = builder.toBuffer(debug);
- var array = new Uint8Array(buffer);
- var instance = instantiate(array);
- assertEquals(17, instance.exports.blarg());
-
- var kPad = 5;
- var buffer2 = new ArrayBuffer(kPad + buffer.byteLength + kPad);
- var whole = new Uint8Array(buffer2);
- for (var i = 0; i < whole.byteLength; i++) {
- whole[i] = 0xff;
- }
- var array2 = new Uint8Array(buffer2, kPad, buffer.byteLength);
- for (var i = 0; i < array2.byteLength; i++) {
- array2[i] = array[i];
- }
- var instance = instantiate(array2);
- assertEquals(17, instance.exports.blarg());
+ print(arguments.callee.name);
+ let builder = new WasmModuleBuilder();
+ builder.addMemory(1, 2, false);
+ builder.addFunction('foo', kSig_i_v)
+ .addBody([kExprI32Const, 17])
+ .exportAs('blarg');
+
+ var buffer = builder.toBuffer(debug);
+ var array = new Uint8Array(buffer);
+ var instance = instantiate(array);
+ assertEquals(17, instance.exports.blarg());
+
+ var kPad = 5;
+ var buffer2 = new ArrayBuffer(kPad + buffer.byteLength + kPad);
+ var whole = new Uint8Array(buffer2);
+ for (var i = 0; i < whole.byteLength; i++) {
+ whole[i] = 0xff;
+ }
+ var array2 = new Uint8Array(buffer2, kPad, buffer.byteLength);
+ for (var i = 0; i < array2.byteLength; i++) {
+ array2[i] = array[i];
+ }
+ var instance = instantiate(array2);
+ assertEquals(17, instance.exports.blarg());
})();
(function ImportTestTwoLevel() {
- print("ImportTestTwoLevel");
- let builder = new WasmModuleBuilder();
- var index = builder.addImport("mod", "print", makeSig_v_x(kWasmI32));
- builder.addFunction("foo", kSig_v_v)
- .addBody([kExprI32Const, 19, kExprCallFunction, index])
- .exportAs("main");
+ print(arguments.callee.name);
+ let builder = new WasmModuleBuilder();
+ var index = builder.addImport('mod', 'print', makeSig_v_x(kWasmI32));
+ builder.addFunction('foo', kSig_v_v)
+ .addBody([kExprI32Const, 19, kExprCallFunction, index])
+ .exportAs('main');
+
+ var buffer = builder.toBuffer(debug);
+ var instance = instantiate(buffer, {mod: {print: print}});
+ print('should print 19! ');
+ instance.exports.main();
+})();
- var buffer = builder.toBuffer(debug);
- var instance = instantiate(buffer, {mod: {print: print}});
- print("should print 19! ");
- instance.exports.main();
+(function TestI32Const() {
+ print(arguments.callee.name);
+ let ints = [
+ // A few negative number of different length.
+ -3 << 28, -20000, -400, -200, -100, -50, -10, -1,
+ // And a few positive number of different length.
+ 0, 1, 2, 20, 120, 130, 260, 500, 5000000, 3 << 28
+ ];
+ for (let i of ints) {
+ let builder = new WasmModuleBuilder();
+ builder.addFunction('main', kSig_i_v)
+ .addBody([...wasmI32Const(i)])
+ .exportAs('main');
+ let instance = builder.instantiate();
+ assertEquals(i, instance.exports.main());
+ }
})();
diff --git a/deps/v8/test/mjsunit/wasm/type-reflection-with-anyref.js b/deps/v8/test/mjsunit/wasm/type-reflection-with-anyref.js
index 0b857fb42f..b7a7ee7969 100644
--- a/deps/v8/test/mjsunit/wasm/type-reflection-with-anyref.js
+++ b/deps/v8/test/mjsunit/wasm/type-reflection-with-anyref.js
@@ -33,6 +33,12 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
assertEquals("anyref", type.value);
assertEquals(false, type.mutable);
assertEquals(2, Object.getOwnPropertyNames(type).length);
+
+ global = new WebAssembly.Global({value: "anyfunc"});
+ type = WebAssembly.Global.type(global);
+ assertEquals("anyfunc", type.value);
+ assertEquals(false, type.mutable);
+ assertEquals(2, Object.getOwnPropertyNames(type).length);
})();
// This is an extension of "type-reflection.js/TestFunctionTableSetAndCall" to
@@ -65,17 +71,23 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
// Test table #0 first.
assertEquals(v1, instance.exports.call0(0));
+ assertSame(f1, table.get(0));
table.set(1, f2);
assertEquals(v2, instance.exports.call0(1));
+ assertSame(f2, table.get(1));
table.set(1, f3);
assertTraps(kTrapFuncSigMismatch, () => instance.exports.call0(1));
+ assertSame(f3, table.get(1));
// Test table #1 next.
assertTraps(kTrapFuncSigMismatch, () => instance.exports.call1(0));
instance.exports.tbl.set(0, f1);
assertEquals(v1, instance.exports.call1(0));
+ assertSame(f1, instance.exports.tbl.get(0));
instance.exports.tbl.set(0, f2);
assertEquals(v2, instance.exports.call1(0));
+ assertSame(f2, instance.exports.tbl.get(0));
instance.exports.tbl.set(0, f3);
assertTraps(kTrapFuncSigMismatch, () => instance.exports.call1(0));
+ assertSame(f3, instance.exports.tbl.get(0));
})();
diff --git a/deps/v8/test/mjsunit/wasm/type-reflection-with-exnref.js b/deps/v8/test/mjsunit/wasm/type-reflection-with-exnref.js
new file mode 100644
index 0000000000..df655f6ce7
--- /dev/null
+++ b/deps/v8/test/mjsunit/wasm/type-reflection-with-exnref.js
@@ -0,0 +1,21 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --experimental-wasm-type-reflection --experimental-wasm-eh
+
+load('test/mjsunit/wasm/wasm-module-builder.js');
+
+(function TestGlobalType() {
+ let global = new WebAssembly.Global({value: "exnref", mutable: true});
+ let type = WebAssembly.Global.type(global);
+ assertEquals("exnref", type.value);
+ assertEquals(true, type.mutable);
+ assertEquals(2, Object.getOwnPropertyNames(type).length);
+
+ global = new WebAssembly.Global({value: "exnref"});
+ type = WebAssembly.Global.type(global);
+ assertEquals("exnref", type.value);
+ assertEquals(false, type.mutable);
+ assertEquals(2, Object.getOwnPropertyNames(type).length);
+})();
diff --git a/deps/v8/test/mjsunit/wasm/type-reflection.js b/deps/v8/test/mjsunit/wasm/type-reflection.js
index da9ef83fda..a9a0b87143 100644
--- a/deps/v8/test/mjsunit/wasm/type-reflection.js
+++ b/deps/v8/test/mjsunit/wasm/type-reflection.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --experimental-wasm-type-reflection
+// Flags: --experimental-wasm-type-reflection --expose-gc
load('test/mjsunit/wasm/wasm-module-builder.js');
@@ -57,6 +57,52 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
assertEquals(2, Object.getOwnPropertyNames(type).length);
})();
+(function TestMemoryExports() {
+ let builder = new WasmModuleBuilder();
+ builder.addMemory(1).exportMemoryAs("a")
+ let module = new WebAssembly.Module(builder.toBuffer());
+ let exports = WebAssembly.Module.exports(module);
+
+ assertEquals("a", exports[0].name);
+ assertTrue("type" in exports[0]);
+ assertEquals(1, exports[0].type.minimum);
+ assertFalse("maximum" in exports[0].type);
+
+ builder = new WasmModuleBuilder();
+ builder.addMemory(2, 16).exportMemoryAs("b")
+ module = new WebAssembly.Module(builder.toBuffer());
+ exports = WebAssembly.Module.exports(module);
+
+ assertEquals("b", exports[0].name);
+ assertTrue("type" in exports[0]);
+ assertEquals(2, exports[0].type.minimum);
+ assertEquals(16, exports[0].type.maximum);
+})();
+
+(function TestMemoryImports() {
+ let builder = new WasmModuleBuilder();
+ builder.addImportedMemory("m", "a", 1);
+ let module = new WebAssembly.Module(builder.toBuffer());
+ let imports = WebAssembly.Module.imports(module);
+
+ assertEquals("a", imports[0].name);
+ assertEquals("m", imports[0].module);
+ assertTrue("type" in imports[0]);
+ assertEquals(1, imports[0].type.minimum);
+ assertFalse("maximum" in imports[0].type);
+
+ builder = new WasmModuleBuilder();
+ builder.addImportedMemory("m", "b", 2, 16);
+ module = new WebAssembly.Module(builder.toBuffer());
+ imports = WebAssembly.Module.imports(module);
+
+ assertEquals("b", imports[0].name);
+ assertEquals("m", imports[0].module);
+ assertTrue("type" in imports[0]);
+ assertEquals(2, imports[0].type.minimum);
+ assertEquals(16, imports[0].type.maximum);
+})();
+
(function TestTableType() {
let table = new WebAssembly.Table({initial: 1, element: "anyfunc"});
let type = WebAssembly.Table.type(table);
@@ -73,6 +119,56 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
assertEquals(3, Object.getOwnPropertyNames(type).length);
})();
+(function TestTableExports() {
+ let builder = new WasmModuleBuilder();
+ builder.addTable(kWasmAnyFunc, 20).exportAs("a");
+ let module = new WebAssembly.Module(builder.toBuffer());
+ let exports = WebAssembly.Module.exports(module);
+
+ assertEquals("a", exports[0].name);
+ assertTrue("type" in exports[0]);
+ assertEquals("anyfunc", exports[0].type.element);
+ assertEquals(20, exports[0].type.minimum);
+ assertFalse("maximum" in exports[0].type);
+
+ builder = new WasmModuleBuilder();
+ builder.addTable(kWasmAnyFunc, 15, 25).exportAs("b");
+ module = new WebAssembly.Module(builder.toBuffer());
+ exports = WebAssembly.Module.exports(module);
+
+ assertEquals("b", exports[0].name);
+ assertTrue("type" in exports[0]);
+ assertEquals("anyfunc", exports[0].type.element);
+ assertEquals(15, exports[0].type.minimum);
+ assertEquals(25, exports[0].type.maximum);
+})();
+
+(function TestTableImports() {
+ let builder = new WasmModuleBuilder();
+ builder.addImportedTable("m", "a", 20, undefined, kWasmAnyFunc);
+ let module = new WebAssembly.Module(builder.toBuffer());
+ let imports = WebAssembly.Module.imports(module);
+
+ assertEquals("a", imports[0].name);
+ assertEquals("m", imports[0].module);
+ assertTrue("type" in imports[0]);
+ assertEquals("anyfunc", imports[0].type.element);
+ assertEquals(20, imports[0].type.minimum);
+ assertFalse("maximum" in imports[0].type);
+
+ builder = new WasmModuleBuilder();
+ builder.addImportedTable("m", "b", 15, 25, kWasmAnyFunc);
+ module = new WebAssembly.Module(builder.toBuffer());
+ imports = WebAssembly.Module.imports(module);
+
+ assertEquals("b", imports[0].name);
+ assertEquals("m", imports[0].module);
+ assertTrue("type" in imports[0]);
+ assertEquals("anyfunc", imports[0].type.element);
+ assertEquals(15, imports[0].type.minimum);
+ assertEquals(25, imports[0].type.maximum);
+})();
+
(function TestGlobalType() {
let global = new WebAssembly.Global({value: "i32", mutable: true});
let type = WebAssembly.Global.type(global);
@@ -105,6 +201,44 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
assertEquals(2, Object.getOwnPropertyNames(type).length);
})();
+(function TestGlobalExports() {
+ let builder = new WasmModuleBuilder();
+ builder.addGlobal(kWasmI32).exportAs("a");
+ builder.addGlobal(kWasmF64, true).exportAs("b");
+ let module = new WebAssembly.Module(builder.toBuffer());
+ let exports = WebAssembly.Module.exports(module);
+
+ assertEquals("a", exports[0].name);
+ assertTrue("type" in exports[0]);
+ assertEquals("i32", exports[0].type.value);
+ assertEquals(false, exports[0].type.mutable);
+
+ assertEquals("b", exports[1].name);
+ assertTrue("type" in exports[1]);
+ assertEquals("f64", exports[1].type.value);
+ assertEquals(true, exports[1].type.mutable);
+})();
+
+(function TestGlobalImports() {
+ let builder = new WasmModuleBuilder();
+ builder.addImportedGlobal("m", "a", kWasmI32);
+ builder.addImportedGlobal("m", "b", kWasmF64, true);
+ let module = new WebAssembly.Module(builder.toBuffer());
+ let imports = WebAssembly.Module.imports(module);
+
+ assertEquals("a", imports[0].name);
+ assertEquals("m", imports[0].module);
+ assertTrue("type" in imports[0]);
+ assertEquals("i32", imports[0].type.value);
+ assertEquals(false, imports[0].type.mutable);
+
+ assertEquals("b", imports[1].name);
+ assertEquals("m", imports[1].module);
+ assertTrue("type" in imports[1]);
+ assertEquals("f64", imports[1].type.value);
+ assertEquals(true, imports[1].type.mutable);
+})();
+
(function TestMemoryConstructorWithMinimum() {
let mem = new WebAssembly.Memory({minimum: 1});
assertTrue(mem instanceof WebAssembly.Memory);
@@ -209,6 +343,42 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
() => new WebAssembly.Function({parameters:[], results:[]}, _ => 0));
})();
+(function TestFunctionConstructorNonArray1() {
+ let log = []; // Populated with a log of accesses.
+ let two = { toString: () => "2" }; // Just a fancy "2".
+ let logger = new Proxy({ length: two, "0": "i32", "1": "f32"}, {
+ get: function(obj, prop) { log.push(prop); return Reflect.get(obj, prop); },
+ set: function(obj, prop, val) { assertUnreachable(); }
+ });
+ let fun = new WebAssembly.Function({parameters:logger, results:[]}, _ => 0);
+ assertArrayEquals(["i32", "f32"], WebAssembly.Function.type(fun).parameters);
+ assertArrayEquals(["length", "0", "1"], log);
+})();
+
+(function TestFunctionConstructorNonArray2() {
+ let throw1 = { get length() { throw new Error("cannot see length"); }};
+ let throw2 = { length: { toString: _ => { throw new Error("no length") } } };
+ let throw3 = { length: "not a length value, this also throws" };
+ assertThrows(
+ () => new WebAssembly.Function({parameters:throw1, results:[]}), Error,
+ /cannot see length/);
+ assertThrows(
+ () => new WebAssembly.Function({parameters:throw2, results:[]}), Error,
+ /no length/);
+ assertThrows(
+ () => new WebAssembly.Function({parameters:throw3, results:[]}), TypeError,
+ /Argument 0 contains parameters without 'length'/);
+ assertThrows(
+ () => new WebAssembly.Function({parameters:[], results:throw1}), Error,
+ /cannot see length/);
+ assertThrows(
+ () => new WebAssembly.Function({parameters:[], results:throw2}), Error,
+ /no length/);
+ assertThrows(
+ () => new WebAssembly.Function({parameters:[], results:throw3}), TypeError,
+ /Argument 0 contains results without 'length'/);
+})();
+
(function TestFunctionConstructedFunction() {
let fun = new WebAssembly.Function({parameters:[], results:[]}, _ => 0);
assertTrue(fun instanceof WebAssembly.Function);
@@ -219,8 +389,7 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
assertSame(fun.__proto__.__proto__.__proto__, Object.prototype);
assertSame(fun.constructor, WebAssembly.Function);
assertEquals(typeof fun, 'function');
- // TODO(7742): Enable once it is callable.
- // assertDoesNotThrow(() => fun());
+ assertDoesNotThrow(() => fun());
})();
(function TestFunctionExportedFunction() {
@@ -271,6 +440,88 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
});
})();
+(function TestFunctionExports() {
+ let testcases = [
+ [kSig_v_v, {parameters:[], results:[]}],
+ [kSig_v_i, {parameters:["i32"], results:[]}],
+ [kSig_i_l, {parameters:["i64"], results:["i32"]}],
+ [kSig_v_ddi, {parameters:["f64", "f64", "i32"], results:[]}],
+ [kSig_f_f, {parameters:["f32"], results:["f32"]}],
+ ];
+ testcases.forEach(function([sig, expected]) {
+ let builder = new WasmModuleBuilder();
+ builder.addFunction("fun", sig).addBody([kExprUnreachable]).exportFunc();
+ let module = new WebAssembly.Module(builder.toBuffer());
+ let exports = WebAssembly.Module.exports(module);
+ assertEquals("fun", exports[0].name);
+ assertTrue("type" in exports[0]);
+ assertEquals(expected, exports[0].type);
+ });
+})();
+
+(function TestFunctionImports() {
+ let testcases = [
+ [kSig_v_v, {parameters:[], results:[]}],
+ [kSig_v_i, {parameters:["i32"], results:[]}],
+ [kSig_i_l, {parameters:["i64"], results:["i32"]}],
+ [kSig_v_ddi, {parameters:["f64", "f64", "i32"], results:[]}],
+ [kSig_f_f, {parameters:["f32"], results:["f32"]}],
+ ];
+ testcases.forEach(function([sig, expected]) {
+ let builder = new WasmModuleBuilder();
+ builder.addImport("m", "fun", sig);
+ let module = new WebAssembly.Module(builder.toBuffer());
+ let imports = WebAssembly.Module.imports(module);
+ assertEquals("fun", imports[0].name);
+ assertEquals("m", imports[0].module);
+ assertTrue("type" in imports[0]);
+ assertEquals(expected, imports[0].type);
+ });
+})();
+
+(function TestFunctionConstructedCoercions() {
+ let obj1 = { valueOf: _ => 123.45 };
+ let obj2 = { toString: _ => "456" };
+ let gcer = { valueOf: _ => gc() };
+ let testcases = [
+ { params: { sig: ["i32"],
+ val: [23.5],
+ exp: [23], },
+ result: { sig: ["i32"],
+ val: 42.7,
+ exp: 42, },
+ },
+ { params: { sig: ["i32", "f32", "f64"],
+ val: [obj1, obj2, "789"],
+ exp: [123, 456, 789], },
+ result: { sig: [],
+ val: undefined,
+ exp: undefined, },
+ },
+ { params: { sig: ["i32", "f32", "f64"],
+ val: [gcer, {}, "xyz"],
+ exp: [0, NaN, NaN], },
+ result: { sig: ["f64"],
+ val: gcer,
+ exp: NaN, },
+ },
+ ];
+ testcases.forEach(function({params, result}) {
+ let p = params.sig; let r = result.sig; var params_after;
+ function testFun() { params_after = arguments; return result.val; }
+ let fun = new WebAssembly.Function({parameters:p, results:r}, testFun);
+ let result_after = fun.apply(undefined, params.val);
+ assertArrayEquals(params.exp, params_after);
+ assertEquals(result.exp, result_after);
+ });
+})();
+
+(function TestFunctionConstructedIncompatibleSig() {
+ let fun = new WebAssembly.Function({parameters:["i64"], results:[]}, _ => 0);
+ assertThrows(() => fun(), TypeError,
+ /wasm function signature contains illegal type/);
+})();
+
(function TestFunctionTableSetAndCall() {
let builder = new WasmModuleBuilder();
let fun1 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
@@ -353,3 +604,14 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
() => builder.instantiate({ m: { fun: fun3 }}), WebAssembly.LinkError,
/imported function does not match the expected type/);
})();
+
+(function TestFunctionModuleImportReExport () {
+ let builder = new WasmModuleBuilder();
+ let fun = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
+ let fun_index = builder.addImport("m", "fun", kSig_i_v)
+ builder.addExport("fun1", fun_index);
+ builder.addExport("fun2", fun_index);
+ let instance = builder.instantiate({ m: { fun: fun }});
+ assertSame(instance.exports.fun1, instance.exports.fun2);
+ assertSame(fun, instance.exports.fun1);
+})();
diff --git a/deps/v8/test/mjsunit/wasm/wasm-module-builder.js b/deps/v8/test/mjsunit/wasm/wasm-module-builder.js
index 8e423bd24f..45af969d09 100644
--- a/deps/v8/test/mjsunit/wasm/wasm-module-builder.js
+++ b/deps/v8/test/mjsunit/wasm/wasm-module-builder.js
@@ -552,7 +552,7 @@ class Binary {
this.buffer[this.length++] = val >> 24;
}
- emit_leb(val, max_len) {
+ emit_leb_u(val, max_len) {
this.ensure_space(max_len);
for (let i = 0; i < max_len; ++i) {
let v = val & 0xff;
@@ -567,11 +567,11 @@ class Binary {
}
emit_u32v(val) {
- this.emit_leb(val, kMaxVarInt32Size);
+ this.emit_leb_u(val, kMaxVarInt32Size);
}
emit_u64v(val) {
- this.emit_leb(val, kMaxVarInt64Size);
+ this.emit_leb_u(val, kMaxVarInt64Size);
}
emit_bytes(data) {
@@ -1384,13 +1384,24 @@ class WasmModuleBuilder {
}
}
-function wasmI32Const(val) {
- let bytes = [kExprI32Const];
- for (let i = 0; i < 4; ++i) {
- bytes.push(0x80 | ((val >> (7 * i)) & 0x7f));
+function wasmSignedLeb(val, max_len = 5) {
+ let res = [];
+ for (let i = 0; i < max_len; ++i) {
+ let v = val & 0x7f;
+ // If {v} sign-extended from 7 to 32 bits is equal to val, we are done.
+ if (((v << 25) >> 25) == val) {
+ res.push(v);
+ return res;
+ }
+ res.push(v | 0x80);
+ val = val >> 7;
}
- bytes.push((val >> (7 * 4)) & 0x7f);
- return bytes;
+ throw new Error(
+ 'Leb value <' + val + '> exceeds maximum length of ' + max_len);
+}
+
+function wasmI32Const(val) {
+ return [kExprI32Const, ...wasmSignedLeb(val, 5)];
}
function wasmF32Const(f) {
diff --git a/deps/v8/test/mkgrokdump/mkgrokdump.cc b/deps/v8/test/mkgrokdump/mkgrokdump.cc
index 103c1334a1..8c07576d3a 100644
--- a/deps/v8/test/mkgrokdump/mkgrokdump.cc
+++ b/deps/v8/test/mkgrokdump/mkgrokdump.cc
@@ -42,7 +42,7 @@ class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
void Free(void* p, size_t) override {}
};
-static void DumpKnownMap(i::Heap* heap, const char* space_name,
+static void DumpKnownMap(FILE* out, i::Heap* heap, const char* space_name,
i::HeapObject object) {
#define RO_ROOT_LIST_CASE(type, name, CamelName) \
if (root_name == nullptr && object == roots.name()) root_name = #CamelName;
@@ -59,14 +59,14 @@ static void DumpKnownMap(i::Heap* heap, const char* space_name,
MUTABLE_ROOT_LIST(MUTABLE_ROOT_LIST_CASE)
if (root_name == nullptr) return;
- i::PrintF(" (\"%s\", 0x%05" V8PRIxPTR "): (%d, \"%s\"),\n", space_name,
+ i::PrintF(out, " (\"%s\", 0x%05" V8PRIxPTR "): (%d, \"%s\"),\n", space_name,
root_ptr, map.instance_type(), root_name);
#undef MUTABLE_ROOT_LIST_CASE
#undef RO_ROOT_LIST_CASE
}
-static void DumpKnownObject(i::Heap* heap, const char* space_name,
+static void DumpKnownObject(FILE* out, i::Heap* heap, const char* space_name,
i::HeapObject object) {
#define RO_ROOT_LIST_CASE(type, name, CamelName) \
if (root_name == nullptr && object == roots.name()) { \
@@ -90,14 +90,14 @@ static void DumpKnownObject(i::Heap* heap, const char* space_name,
if (root_name == nullptr) return;
if (!i::RootsTable::IsImmortalImmovable(root_index)) return;
- i::PrintF(" (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", space_name, root_ptr,
- root_name);
+ i::PrintF(out, " (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", space_name,
+ root_ptr, root_name);
#undef ROOT_LIST_CASE
#undef RO_ROOT_LIST_CASE
}
-static int DumpHeapConstants(const char* argv0) {
+static int DumpHeapConstants(FILE* out, const char* argv0) {
// Start up V8.
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
@@ -112,42 +112,42 @@ static int DumpHeapConstants(const char* argv0) {
i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
i::ReadOnlyHeap* read_only_heap =
reinterpret_cast<i::Isolate*>(isolate)->read_only_heap();
- i::PrintF("%s", kHeader);
-#define DUMP_TYPE(T) i::PrintF(" %d: \"%s\",\n", i::T, #T);
- i::PrintF("INSTANCE_TYPES = {\n");
+ i::PrintF(out, "%s", kHeader);
+#define DUMP_TYPE(T) i::PrintF(out, " %d: \"%s\",\n", i::T, #T);
+ i::PrintF(out, "INSTANCE_TYPES = {\n");
INSTANCE_TYPE_LIST(DUMP_TYPE)
- i::PrintF("}\n");
+ i::PrintF(out, "}\n");
#undef DUMP_TYPE
{
// Dump the KNOWN_MAP table to the console.
- i::PrintF("\n# List of known V8 maps.\n");
- i::PrintF("KNOWN_MAPS = {\n");
+ i::PrintF(out, "\n# List of known V8 maps.\n");
+ i::PrintF(out, "KNOWN_MAPS = {\n");
i::ReadOnlyHeapObjectIterator ro_iterator(read_only_heap);
for (i::HeapObject object = ro_iterator.Next(); !object.is_null();
object = ro_iterator.Next()) {
if (!object.IsMap()) continue;
- DumpKnownMap(heap, i::Heap::GetSpaceName(i::RO_SPACE), object);
+ DumpKnownMap(out, heap, i::Heap::GetSpaceName(i::RO_SPACE), object);
}
i::PagedSpaceObjectIterator iterator(heap->map_space());
for (i::HeapObject object = iterator.Next(); !object.is_null();
object = iterator.Next()) {
if (!object.IsMap()) continue;
- DumpKnownMap(heap, i::Heap::GetSpaceName(i::MAP_SPACE), object);
+ DumpKnownMap(out, heap, i::Heap::GetSpaceName(i::MAP_SPACE), object);
}
- i::PrintF("}\n");
+ i::PrintF(out, "}\n");
}
{
// Dump the KNOWN_OBJECTS table to the console.
- i::PrintF("\n# List of known V8 objects.\n");
- i::PrintF("KNOWN_OBJECTS = {\n");
+ i::PrintF(out, "\n# List of known V8 objects.\n");
+ i::PrintF(out, "KNOWN_OBJECTS = {\n");
i::ReadOnlyHeapObjectIterator ro_iterator(read_only_heap);
for (i::HeapObject object = ro_iterator.Next(); !object.is_null();
object = ro_iterator.Next()) {
// Skip read-only heap maps, they will be reported elsewhere.
if (object.IsMap()) continue;
- DumpKnownObject(heap, i::Heap::GetSpaceName(i::RO_SPACE), object);
+ DumpKnownObject(out, heap, i::Heap::GetSpaceName(i::RO_SPACE), object);
}
i::PagedSpaceIterator spit(heap);
@@ -158,22 +158,22 @@ static int DumpHeapConstants(const char* argv0) {
continue;
const char* sname = s->name();
for (i::HeapObject o = it.Next(); !o.is_null(); o = it.Next()) {
- DumpKnownObject(heap, sname, o);
+ DumpKnownObject(out, heap, sname, o);
}
}
- i::PrintF("}\n");
+ i::PrintF(out, "}\n");
}
// Dump frame markers
- i::PrintF("\n# List of known V8 Frame Markers.\n");
-#define DUMP_MARKER(T, class) i::PrintF(" \"%s\",\n", #T);
- i::PrintF("FRAME_MARKERS = (\n");
+ i::PrintF(out, "\n# List of known V8 Frame Markers.\n");
+#define DUMP_MARKER(T, class) i::PrintF(out, " \"%s\",\n", #T);
+ i::PrintF(out, "FRAME_MARKERS = (\n");
STACK_FRAME_TYPE_LIST(DUMP_MARKER)
- i::PrintF(")\n");
+ i::PrintF(out, ")\n");
#undef DUMP_MARKER
}
- i::PrintF("\n# This set of constants is generated from a %s build.\n",
+ i::PrintF(out, "\n# This set of constants is generated from a %s build.\n",
kBuild);
// Teardown.
@@ -184,4 +184,10 @@ static int DumpHeapConstants(const char* argv0) {
} // namespace v8
-int main(int argc, char* argv[]) { return v8::DumpHeapConstants(argv[0]); }
+int main(int argc, char* argv[]) {
+ FILE* out = stdout;
+ if (argc > 2 && strcmp(argv[1], "--outfile") == 0) {
+ out = fopen(argv[2], "wb");
+ }
+ return v8::DumpHeapConstants(out, argv[0]);
+}
diff --git a/deps/v8/test/test262/local-tests/test/language/expressions/class/elements/private-field-on-nested-class.js b/deps/v8/test/test262/local-tests/test/language/expressions/class/elements/private-field-on-nested-class.js
new file mode 100644
index 0000000000..8aafe6df38
--- /dev/null
+++ b/deps/v8/test/test262/local-tests/test/language/expressions/class/elements/private-field-on-nested-class.js
@@ -0,0 +1,45 @@
+// This file was procedurally generated from the following sources:
+// - src/class-elements/private-field-on-nested-class.case
+// - src/class-elements/default/cls-expr.template
+/*---
+description: PrivateName CallExpression usage (private field) (field definitions in a class expression)
+esid: prod-FieldDefinition
+features: [class-fields-private, class-fields-public, class]
+flags: [generated]
+info: |
+ Updated Productions
+
+ CallExpression[Yield, Await]:
+ CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await]
+ SuperCall[?Yield, ?Await]
+ CallExpression[?Yield, ?Await]Arguments[?Yield, ?Await]
+ CallExpression[?Yield, ?Await][Expression[+In, ?Yield, ?Await]]
+ CallExpression[?Yield, ?Await].IdentifierName
+ CallExpression[?Yield, ?Await]TemplateLiteral[?Yield, ?Await]
+ CallExpression[?Yield, ?Await].PrivateName
+
+---*/
+
+
+var C = class {
+ #outer = 'test262';
+
+ B_withoutPrivateField = class {
+ method(o) {
+ return o.#outer;
+ }
+ }
+
+ B_withPrivateField = class {
+ #inner = 42;
+ method(o) {
+ return o.#outer;
+ }
+ }
+}
+
+let c = new C();
+let innerB1 = new c.B_withoutPrivateField();
+assert.sameValue(innerB1.method(c), 'test262');
+let innerB2 = new c.B_withPrivateField();
+assert.sameValue(innerB2.method(c), 'test262');
diff --git a/deps/v8/test/test262/local-tests/test/language/statements/class/elements/private-field-on-nested-class.js b/deps/v8/test/test262/local-tests/test/language/statements/class/elements/private-field-on-nested-class.js
new file mode 100644
index 0000000000..3f22efeb7c
--- /dev/null
+++ b/deps/v8/test/test262/local-tests/test/language/statements/class/elements/private-field-on-nested-class.js
@@ -0,0 +1,45 @@
+// This file was procedurally generated from the following sources:
+// - src/class-elements/private-field-on-nested-class.case
+// - src/class-elements/default/cls-decl.template
+/*---
+description: PrivateName CallExpression usage (private field) (field definitions in a class declaration)
+esid: prod-FieldDefinition
+features: [class-fields-private, class-fields-public, class]
+flags: [generated]
+info: |
+ Updated Productions
+
+ CallExpression[Yield, Await]:
+ CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await]
+ SuperCall[?Yield, ?Await]
+ CallExpression[?Yield, ?Await]Arguments[?Yield, ?Await]
+ CallExpression[?Yield, ?Await][Expression[+In, ?Yield, ?Await]]
+ CallExpression[?Yield, ?Await].IdentifierName
+ CallExpression[?Yield, ?Await]TemplateLiteral[?Yield, ?Await]
+ CallExpression[?Yield, ?Await].PrivateName
+
+---*/
+
+
+class C {
+ #outer = 'test262';
+
+ B_withoutPrivateField = class {
+ method(o) {
+ return o.#outer;
+ }
+ }
+
+ B_withPrivateField = class {
+ #inner = 42;
+ method(o) {
+ return o.#outer;
+ }
+ }
+}
+
+let c = new C();
+let innerB1 = new c.B_withoutPrivateField();
+assert.sameValue(innerB1.method(c), 'test262');
+let innerB2 = new c.B_withPrivateField();
+assert.sameValue(innerB2.method(c), 'test262');
diff --git a/deps/v8/test/test262/test262.status b/deps/v8/test/test262/test262.status
index 54ba1579cc..7ccb304a0b 100644
--- a/deps/v8/test/test262/test262.status
+++ b/deps/v8/test/test262/test262.status
@@ -60,32 +60,13 @@
'language/expressions/assignment/S11.13.1_A6*': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=4709
- 'built-ins/Promise/all/resolve-element-function-name': [FAIL],
- 'built-ins/Promise/allSettled/reject-element-function-name': [FAIL],
- 'built-ins/Promise/allSettled/resolve-element-function-name': [FAIL],
- 'built-ins/Promise/executor-function-name': [FAIL],
- 'built-ins/Promise/reject-function-name': [FAIL],
- 'built-ins/Promise/resolve-function-name': [FAIL],
- 'built-ins/Proxy/revocable/revocation-function-name': [FAIL],
'language/expressions/assignment/fn-name-lhs-cover': [FAIL],
- 'language/expressions/assignment/fn-name-lhs-member': [FAIL],
- 'language/expressions/function/name': [FAIL],
- 'language/expressions/generators/name': [FAIL],
- 'intl402/NumberFormat/prototype/format/format-function-name': [FAIL],
- 'intl402/DateTimeFormat/prototype/format/format-function-name': [FAIL],
- 'intl402/Collator/prototype/compare/compare-function-name': [FAIL],
# Intl tests which require flags.
# https://bugs.chromium.org/p/v8/issues/detail?id=9154
'intl402/NumberFormat/numbering-system-options': ['--harmony-intl-add-calendar-numbering-system'],
'intl402/DateTimeFormat/numbering-system-calendar-options': ['--harmony-intl-add-calendar-numbering-system'],
- # https://bugs.chromium.org/p/v8/issues/detail?id=9319
- 'intl402/NumberFormat/prototype/resolvedOptions/order': [FAIL],
-
- # crbug.com/v8/9483
- 'intl402/NumberFormat/currencyDisplay-unit': [FAIL],
-
# https://bugs.chromium.org/p/v8/issues/detail?id=9084
'intl402/supportedLocalesOf-consistent-with-resolvedOptions': [FAIL],
'intl402/fallback-locales-are-supported': [FAIL],
@@ -450,10 +431,6 @@
'built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds': [FAIL],
'built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds': [FAIL],
- # https://bugs.chromium.org/p/v8/issues/detail?id=8100
- 'built-ins/Atomics/notify/bigint/*': [SKIP],
- 'built-ins/Atomics/wait/bigint/*': [SKIP],
-
# https://bugs.chromium.org/p/v8/issues/detail?id=6049
'built-ins/Object/internals/DefineOwnProperty/consistent-value-function-caller': [FAIL_SLOPPY],
'built-ins/Object/internals/DefineOwnProperty/consistent-value-function-arguments': [FAIL_SLOPPY],
@@ -480,25 +457,8 @@
'language/expressions/async-generator/generator-created-after-decl-inst': [FAIL],
'language/statements/async-generator/generator-created-after-decl-inst': [FAIL],
- # await tests that require flags
- 'language/expressions/await/async-generator-interleaved': ['--harmony-await-optimization'],
- 'language/expressions/await/await-monkey-patched-promise': ['--harmony-await-optimization'],
- 'language/expressions/await/for-await-of-interleaved': ['--harmony-await-optimization'],
- 'language/expressions/await/async-await-interleaved': ['--harmony-await-optimization'],
-
- # https://github.com/tc39/test262/issues/2033
- 'language/expressions/class/elements/private-derived-cls-direct-eval-err-contains-supercall': [SKIP],
- 'language/expressions/class/elements/private-derived-cls-direct-eval-err-contains-supercall-1': [SKIP],
- 'language/expressions/class/elements/private-derived-cls-direct-eval-err-contains-supercall-2': [SKIP],
- 'language/expressions/class/elements/private-derived-cls-indirect-eval-err-contains-supercall': [SKIP],
- 'language/expressions/class/elements/private-derived-cls-indirect-eval-err-contains-supercall-1': [SKIP],
- 'language/expressions/class/elements/private-derived-cls-indirect-eval-err-contains-supercall-2': [SKIP],
- 'language/statements/class/elements/private-derived-cls-direct-eval-err-contains-supercall': [SKIP],
- 'language/statements/class/elements/private-derived-cls-direct-eval-err-contains-supercall-1': [SKIP],
- 'language/statements/class/elements/private-derived-cls-direct-eval-err-contains-supercall-2': [SKIP],
- 'language/statements/class/elements/private-derived-cls-indirect-eval-err-contains-supercall': [SKIP],
- 'language/statements/class/elements/private-derived-cls-indirect-eval-err-contains-supercall-1': [SKIP],
- 'language/statements/class/elements/private-derived-cls-indirect-eval-err-contains-supercall-2': [SKIP],
+ # https://bugs.chromium.org/p/v8/issues/detail?id=9611
+ 'language/statements/class/elements/private-field-is-visible-in-computed-properties': [SKIP],
# https://github.com/tc39/test262/issues/2034
'language/expressions/postfix-decrement/arguments': [SKIP],
@@ -565,10 +525,285 @@
# https://github.com/tc39/test262/issues/2255
'built-ins/FinalizationGroup/prototype/cleanupSome/iterator-holdings-multiple-values': [FAIL],
+ # https://github.com/tc39/test262/issues/2260
+ 'built-ins/FinalizationGroup/prototype/cleanupSome/return-undefined-with-gc': [FAIL],
+
+ # https://bugs.chromium.org/p/v8/issues/detail?id=9612
+ 'intl402/DateTimeFormat/prototype/formatRange/fractionalSecondDigits': [FAIL],
+
+ # https://bugs.chromium.org/p/v8/issues/detail?id=9613
+ 'intl402/Intl/getCanonicalLocales/canonicalized-tags': [FAIL],
+ 'intl402/Intl/getCanonicalLocales/grandfathered': [FAIL],
+ 'intl402/Intl/getCanonicalLocales/invalid-tags': [FAIL],
+ 'intl402/Intl/getCanonicalLocales/non-iana-canon': [FAIL],
+ 'intl402/Intl/getCanonicalLocales/preferred-grandfathered': [FAIL],
+ 'intl402/Intl/getCanonicalLocales/preferred-variant': [FAIL],
+ 'intl402/language-tags-invalid': [FAIL],
+ 'intl402/ListFormat/constructor/constructor/locales-valid': [FAIL],
+ 'intl402/Locale/constructor-non-iana-canon': [FAIL],
+ 'intl402/Locale/constructor-options-region-valid': [FAIL],
+ 'intl402/Locale/constructor-tag': [FAIL],
+ 'intl402/Locale/getters': [FAIL],
+ 'intl402/Locale/likely-subtags-grandfathered': [FAIL],
+ 'intl402/PluralRules/prototype/resolvedOptions/order': [FAIL],
+ 'intl402/RelativeTimeFormat/constructor/constructor/locales-valid': [FAIL],
+ 'intl402/Segmenter/constructor/constructor/locales-valid': [FAIL],
+
+ # https://bugs.chromium.org/p/v8/issues/detail?id=9647
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-break-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-case-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-catch-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-class-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-const-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-continue-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-debugger-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-default-escaped-ext': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-default-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-delete-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-do-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-else-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-enum-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-export-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-extends-escaped-ext': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-extends-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-finally-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-for-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-function-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-if-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-import-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-in-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-instanceof-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-new-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-return-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-super-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-switch-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-this-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-throw-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-try-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-typeof-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-var-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-void-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-while-escaped': [FAIL],
+ 'language/expressions/assignment/dstr/ident-name-prop-name-literal-with-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-break-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-case-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-catch-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-class-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-const-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-continue-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-debugger-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-default-escaped-ext': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-default-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-delete-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-do-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-else-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-enum-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-export-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-extends-escaped-ext': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-extends-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-finally-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-for-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-function-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-if-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-import-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-in-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-instanceof-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-new-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-return-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-super-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-switch-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-this-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-throw-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-try-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-typeof-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-var-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-void-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-while-escaped': [FAIL],
+ 'language/expressions/assignment/member-expr-ident-name-with-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-break-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-case-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-catch-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-class-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-const-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-continue-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-debugger-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-default-escaped-ext': [FAIL],
+ 'language/expressions/class/ident-name-method-def-default-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-delete-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-do-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-else-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-enum-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-export-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-extends-escaped-ext': [FAIL],
+ 'language/expressions/class/ident-name-method-def-extends-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-finally-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-for-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-function-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-if-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-import-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-in-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-instanceof-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-new-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-return-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-super-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-switch-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-this-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-throw-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-try-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-typeof-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-var-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-void-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-while-escaped': [FAIL],
+ 'language/expressions/class/ident-name-method-def-with-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-break-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-case-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-catch-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-class-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-const-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-continue-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-debugger-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-default-escaped-ext': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-default-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-delete-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-do-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-else-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-enum-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-export-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-extends-escaped-ext': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-extends-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-finally-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-for-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-function-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-if-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-import-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-in-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-instanceof-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-new-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-return-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-super-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-switch-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-this-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-throw-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-try-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-typeof-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-var-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-void-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-while-escaped': [FAIL],
+ 'language/expressions/object/covered-ident-name-prop-name-literal-with-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-break-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-case-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-catch-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-class-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-const-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-continue-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-debugger-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-default-escaped-ext': [FAIL],
+ 'language/expressions/object/ident-name-method-def-default-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-delete-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-do-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-else-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-enum-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-export-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-extends-escaped-ext': [FAIL],
+ 'language/expressions/object/ident-name-method-def-extends-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-finally-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-for-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-function-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-if-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-import-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-in-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-instanceof-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-new-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-return-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-super-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-switch-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-this-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-throw-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-try-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-typeof-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-var-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-void-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-while-escaped': [FAIL],
+ 'language/expressions/object/ident-name-method-def-with-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-break-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-case-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-catch-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-class-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-const-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-continue-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-debugger-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-default-escaped-ext': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-default-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-delete-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-do-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-else-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-enum-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-export-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-extends-escaped-ext': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-extends-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-finally-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-for-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-function-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-if-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-import-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-in-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-instanceof-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-new-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-return-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-super-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-switch-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-this-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-throw-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-try-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-typeof-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-var-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-void-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-while-escaped': [FAIL],
+ 'language/expressions/object/ident-name-prop-name-literal-with-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-break-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-case-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-catch-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-class-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-const-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-continue-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-debugger-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-default-escaped-ext': [FAIL],
+ 'language/statements/class/ident-name-method-def-default-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-delete-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-do-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-else-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-enum-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-export-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-extends-escaped-ext': [FAIL],
+ 'language/statements/class/ident-name-method-def-extends-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-finally-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-for-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-function-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-if-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-import-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-in-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-instanceof-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-new-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-return-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-super-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-switch-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-this-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-throw-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-try-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-typeof-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-var-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-void-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-while-escaped': [FAIL],
+ 'language/statements/class/ident-name-method-def-with-escaped': [FAIL],
+
######################## NEEDS INVESTIGATION ###########################
# https://bugs.chromium.org/p/v8/issues/detail?id=7833
+ #
+ # Test262 needs to expose CanBlock
+ 'built-ins/Atomics/wait/bigint/cannot-suspend-throws': [SKIP],
'built-ins/Atomics/wait/cannot-suspend-throws': [SKIP],
+ # Flaky
'built-ins/Atomics/wait/undefined-index-defaults-to-zero': [SKIP],
##################### DELIBERATE INCOMPATIBILITIES #####################
@@ -688,10 +923,6 @@
['asan == True', {
# BUG(v8:4653): Test262 tests which rely on quit() are not compatible with
# asan's --omit-quit flag.
- 'built-ins/Promise/allSettled/reject-deferred': [FAIL],
- 'built-ins/Promise/allSettled/reject-ignored-deferred': [FAIL],
- 'built-ins/Promise/allSettled/reject-ignored-immed': [FAIL],
- 'built-ins/Promise/allSettled/reject-immed': [FAIL],
'built-ins/Promise/prototype/then/deferred-is-resolved-value': [SKIP],
'language/expressions/dynamic-import/always-create-new-promise': [SKIP],
'language/expressions/dynamic-import/assign-expr-get-value-abrupt-throws': [SKIP],
@@ -837,8 +1068,6 @@
'language/expressions/dynamic-import/catch/top-level-import-catch-instn-iee-err-circular': [SKIP],
'language/expressions/dynamic-import/catch/top-level-import-catch-specifier-tostring-abrupt-rejects': [SKIP],
'language/expressions/dynamic-import/custom-primitive': [SKIP],
- 'language/expressions/dynamic-import/double-error-resolution': [SKIP],
- 'language/expressions/dynamic-import/double-error-resolution-promise': [SKIP],
'language/expressions/dynamic-import/escape-sequence-import': [SKIP],
'language/expressions/dynamic-import/eval-export-dflt-cls-anon': [SKIP],
'language/expressions/dynamic-import/eval-export-dflt-cls-named': [SKIP],
diff --git a/deps/v8/test/test262/testcfg.py b/deps/v8/test/test262/testcfg.py
index ff866a832f..9aa91dfaef 100644
--- a/deps/v8/test/test262/testcfg.py
+++ b/deps/v8/test/test262/testcfg.py
@@ -44,7 +44,6 @@ from testrunner.outproc import test262
# TODO(littledan): move the flag mapping into the status file
FEATURE_FLAGS = {
- 'numeric-separator-literal': '--harmony-numeric-separator',
'Intl.DateTimeFormat-datetimestyle': '--harmony-intl-datetime-style',
'Intl.DateTimeFormat-formatRange': '--harmony-intl-date-format-range',
'Intl.NumberFormat-unified': '--harmony-intl-numberformat-unified',
@@ -59,10 +58,12 @@ FEATURE_FLAGS = {
'FinalizationGroup': '--harmony-weak-refs',
'WeakRef': '--harmony-weak-refs',
'host-gc-required': '--expose-gc-as=v8GC',
+ 'optional-chaining': '--harmony-optional-chaining',
}
SKIPPED_FEATURES = set(['class-methods-private',
- 'class-static-methods-private'])
+ 'class-static-methods-private',
+ 'top-level-await'])
DATA = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
diff --git a/deps/v8/test/torque/OWNERS b/deps/v8/test/torque/OWNERS
index 5f8830d55a..4e832f8c25 100644
--- a/deps/v8/test/torque/OWNERS
+++ b/deps/v8/test/torque/OWNERS
@@ -1 +1 @@
-file://src/torque/OWNERS
+file:../../src/torque/OWNERS
diff --git a/deps/v8/test/torque/test-torque.tq b/deps/v8/test/torque/test-torque.tq
index 6d2aee1479..4fa106b9c5 100644
--- a/deps/v8/test/torque/test-torque.tq
+++ b/deps/v8/test/torque/test-torque.tq
@@ -83,11 +83,11 @@ namespace test {
}
}
- builtin GenericBuiltinTest<T: type>(_c: Context, _param: T): Object {
+ builtin GenericBuiltinTest<T: type>(_c: Context, _param: T): JSAny {
return Null;
}
- GenericBuiltinTest<Object>(_c: Context, param: Object): Object {
+ GenericBuiltinTest<JSAny>(_c: Context, param: JSAny): JSAny {
return param;
}
@@ -95,8 +95,8 @@ namespace test {
macro TestBuiltinSpecialization(c: Context) {
check(GenericBuiltinTest<Smi>(c, 0) == Null);
check(GenericBuiltinTest<Smi>(c, 1) == Null);
- check(GenericBuiltinTest<Object>(c, Undefined) == Undefined);
- check(GenericBuiltinTest<Object>(c, Undefined) == Undefined);
+ check(GenericBuiltinTest<JSAny>(c, Undefined) == Undefined);
+ check(GenericBuiltinTest<JSAny>(c, Undefined) == Undefined);
}
macro LabelTestHelper4(flag: constexpr bool): never
@@ -202,9 +202,8 @@ namespace test {
@export
macro TestFunctionPointerToGeneric(c: Context) {
- const fptr1: builtin(Context, Smi) => Object = GenericBuiltinTest<Smi>;
- const fptr2: builtin(Context, Object) => Object =
- GenericBuiltinTest<Object>;
+ const fptr1: builtin(Context, Smi) => JSAny = GenericBuiltinTest<Smi>;
+ const fptr2: builtin(Context, JSAny) => JSAny = GenericBuiltinTest<JSAny>;
check(fptr1(c, 0) == Null);
check(fptr1(c, 1) == Null);
@@ -212,7 +211,7 @@ namespace test {
check(fptr2(c, Undefined) == Undefined);
}
- type ObjectToObject = builtin(Context, Object) => Object;
+ type ObjectToObject = builtin(Context, JSAny) => JSAny;
@export
macro TestTypeAlias(x: ObjectToObject): BuiltinPtr {
return x;
@@ -452,7 +451,7 @@ namespace test {
@export
macro TestSubtyping(x: Smi) {
- const _foo: Object = x;
+ const _foo: JSAny = x;
}
macro IncrementIfSmi<A: type>(x: A): A {
@@ -543,95 +542,34 @@ namespace test {
check(equal);
}
- macro BoolToBranch(x: bool): never
- labels Taken, NotTaken {
- if (x) {
- goto Taken;
- } else {
- goto NotTaken;
- }
- }
-
- @export
- macro TestOrAnd1(x: bool, y: bool, z: bool): bool {
- return BoolToBranch(x) || y && z ? true : false;
- }
-
- @export
- macro TestOrAnd2(x: bool, y: bool, z: bool): bool {
- return x || BoolToBranch(y) && z ? true : false;
- }
-
@export
- macro TestOrAnd3(x: bool, y: bool, z: bool): bool {
- return x || y && BoolToBranch(z) ? true : false;
+ macro TestOrAnd(x: bool, y: bool, z: bool): bool {
+ return x || y && z ? true : false;
}
@export
- macro TestAndOr1(x: bool, y: bool, z: bool): bool {
- return BoolToBranch(x) && y || z ? true : false;
- }
-
- @export
- macro TestAndOr2(x: bool, y: bool, z: bool): bool {
- return x && BoolToBranch(y) || z ? true : false;
- }
-
- @export
- macro TestAndOr3(x: bool, y: bool, z: bool): bool {
- return x && y || BoolToBranch(z) ? true : false;
+ macro TestAndOr(x: bool, y: bool, z: bool): bool {
+ return x && y || z ? true : false;
}
@export
macro TestLogicalOperators() {
- check(TestAndOr1(true, true, true));
- check(TestAndOr2(true, true, true));
- check(TestAndOr3(true, true, true));
- check(TestAndOr1(true, true, false));
- check(TestAndOr2(true, true, false));
- check(TestAndOr3(true, true, false));
- check(TestAndOr1(true, false, true));
- check(TestAndOr2(true, false, true));
- check(TestAndOr3(true, false, true));
- check(!TestAndOr1(true, false, false));
- check(!TestAndOr2(true, false, false));
- check(!TestAndOr3(true, false, false));
- check(TestAndOr1(false, true, true));
- check(TestAndOr2(false, true, true));
- check(TestAndOr3(false, true, true));
- check(!TestAndOr1(false, true, false));
- check(!TestAndOr2(false, true, false));
- check(!TestAndOr3(false, true, false));
- check(TestAndOr1(false, false, true));
- check(TestAndOr2(false, false, true));
- check(TestAndOr3(false, false, true));
- check(!TestAndOr1(false, false, false));
- check(!TestAndOr2(false, false, false));
- check(!TestAndOr3(false, false, false));
- check(TestOrAnd1(true, true, true));
- check(TestOrAnd2(true, true, true));
- check(TestOrAnd3(true, true, true));
- check(TestOrAnd1(true, true, false));
- check(TestOrAnd2(true, true, false));
- check(TestOrAnd3(true, true, false));
- check(TestOrAnd1(true, false, true));
- check(TestOrAnd2(true, false, true));
- check(TestOrAnd3(true, false, true));
- check(TestOrAnd1(true, false, false));
- check(TestOrAnd2(true, false, false));
- check(TestOrAnd3(true, false, false));
- check(TestOrAnd1(false, true, true));
- check(TestOrAnd2(false, true, true));
- check(TestOrAnd3(false, true, true));
- check(!TestOrAnd1(false, true, false));
- check(!TestOrAnd2(false, true, false));
- check(!TestOrAnd3(false, true, false));
- check(!TestOrAnd1(false, false, true));
- check(!TestOrAnd2(false, false, true));
- check(!TestOrAnd3(false, false, true));
- check(!TestOrAnd1(false, false, false));
- check(!TestOrAnd2(false, false, false));
- check(!TestOrAnd3(false, false, false));
+ check(TestAndOr(true, true, true));
+ check(TestAndOr(true, true, false));
+ check(TestAndOr(true, false, true));
+ check(!TestAndOr(true, false, false));
+ check(TestAndOr(false, true, true));
+ check(!TestAndOr(false, true, false));
+ check(TestAndOr(false, false, true));
+ check(!TestAndOr(false, false, false));
+ check(TestOrAnd(true, true, true));
+ check(TestOrAnd(true, true, false));
+ check(TestOrAnd(true, false, true));
+ check(TestOrAnd(true, false, false));
+ check(TestOrAnd(false, true, true));
+ check(!TestOrAnd(false, true, false));
+ check(!TestOrAnd(false, false, true));
+ check(!TestOrAnd(false, false, false));
}
@export
@@ -688,7 +626,7 @@ namespace test {
@export
macro TestQualifiedAccess(implicit context: Context)() {
const s: Smi = 0;
- check(!array::IsJSArray(s));
+ check(!Is<JSArray>(s));
}
@export
@@ -746,14 +684,14 @@ namespace test {
@export
macro TestIterator(implicit context: Context)(o: JSReceiver, map: Map) {
try {
- const t1: Object = iterator::GetIteratorMethod(o);
+ const t1: JSAny = iterator::GetIteratorMethod(o);
const t2: iterator::IteratorRecord = iterator::GetIterator(o);
- const _t3: Object = iterator::IteratorStep(t2) otherwise Fail;
- const _t4: Object = iterator::IteratorStep(t2, map) otherwise Fail;
+ const _t3: JSAny = iterator::IteratorStep(t2) otherwise Fail;
+ const _t4: JSAny = iterator::IteratorStep(t2, map) otherwise Fail;
- const t5: Object = iterator::IteratorValue(o);
- const _t6: Object = iterator::IteratorValue(o, map);
+ const t5: JSAny = iterator::IteratorValue(o);
+ const _t6: JSAny = iterator::IteratorValue(o, map);
const _t7: JSArray = iterator::IterableToList(t1, t1);
@@ -904,6 +842,64 @@ namespace test {
}
@export
+ macro TestSlices() {
+ const it = TestIterator{count: 3};
+ const a = new FixedArray{map: kFixedArrayMap, length: 3, objects: ...it};
+ check(a.length == 3);
+
+ const oneTwoThree = Convert<Smi>(123);
+ a.objects[0] = oneTwoThree;
+ const firstRef:&Object = & a.objects[0];
+ check(TaggedEqual(* firstRef, oneTwoThree));
+
+ const slice: torque_internal::Slice<Object> = & a.objects;
+ const firstRefAgain:&Object = slice.TryAtIndex(0) otherwise unreachable;
+ check(TaggedEqual(* firstRefAgain, oneTwoThree));
+
+ const threeTwoOne = Convert<Smi>(321);
+ * firstRefAgain = threeTwoOne;
+ check(TaggedEqual(a.objects[0], threeTwoOne));
+
+ // *slice; // error, not allowed
+ // a.objects; // error, not allowed
+ // a.objects = slice; // error, not allowed
+
+ // TODO(gsps): Currently errors, but should be allowed:
+ // const _sameSlice: torque_internal::Slice<Object> = &(*slice);
+ // (*slice)[0] : Smi
+ }
+
+ @export
+ macro TestSliceEnumeration(implicit context: Context)(): Undefined {
+ const fixedArray: FixedArray = AllocateZeroedFixedArray(3);
+ for (let i: intptr = 0; i < 3; i++) {
+ check(UnsafeCast<Smi>(fixedArray.objects[i]) == 0);
+ fixedArray.objects[i] = Convert<Smi>(i) + 3;
+ }
+
+ let slice = & fixedArray.objects;
+ for (let i: intptr = 0; i < slice.length; i++) {
+ let ref = slice.TryAtIndex(i) otherwise unreachable;
+ const value = UnsafeCast<Smi>(* ref);
+ check(value == Convert<Smi>(i) + 3);
+ * ref = value + 4;
+ }
+
+ let it = slice.Iterator();
+ let count: Smi = 0;
+ while (true) {
+ let ref = it.Next() otherwise break;
+ const value = UnsafeCast<Smi>(* ref);
+ check(value == count + 7);
+ count++;
+ }
+ check(count == 3);
+ check(it.Empty());
+
+ return Undefined;
+ }
+
+ @export
macro TestStaticAssert() {
StaticAssert(1 + 2 == 3);
}
@@ -923,12 +919,12 @@ namespace test {
const v1 = box.value;
box.unrelated = 999;
const v2 = (box.unrelated == 0) ? box.value : box.value;
- StaticAssert(WordEqual(v1, v2));
+ StaticAssert(TaggedEqual(v1, v2));
box.value = 11;
const v3 = box.value;
const eleven: Smi = 11;
- StaticAssert(WordEqual(v3, eleven));
+ StaticAssert(TaggedEqual(v3, eleven));
}
@export
@@ -939,8 +935,8 @@ namespace test {
const u1 = a.objects[box.value + 2];
const v2 = a.objects[box.value];
const u2 = a.objects[box.value + 2];
- StaticAssert(WordEqual(v1, v2));
- StaticAssert(WordEqual(u1, u2));
+ StaticAssert(TaggedEqual(v1, v2));
+ StaticAssert(TaggedEqual(u1, u2));
}
@export
@@ -980,8 +976,8 @@ namespace test {
@export
macro TestGenericStruct1(): intptr {
const i: intptr = 123;
- let box = SBox<intptr>{value: i};
- let boxbox = SBox<SBox<intptr>>{value: box};
+ let box = SBox{value: i};
+ let boxbox: SBox<SBox<intptr>> = SBox{value: box};
check(box.value == 123);
boxbox.value.value *= 2;
check(boxbox.value.value == 246);
@@ -993,18 +989,43 @@ namespace test {
const snd: T2;
}
- macro Swap<T1: type, T2: type>(tuple: TestTuple<T1, T2>):
+ macro TupleSwap<T1: type, T2: type>(tuple: TestTuple<T1, T2>):
TestTuple<T2, T1> {
- return TestTuple<T2, T1>{fst: tuple.snd, snd: tuple.fst};
+ return TestTuple{fst: tuple.snd, snd: tuple.fst};
}
@export
- macro TestGenericStruct2(): TestTuple<Smi, intptr> {
+ macro TestGenericStruct2():
+ TestTuple<TestTuple<intptr, Smi>, TestTuple<Smi, intptr>> {
const intptrAndSmi = TestTuple<intptr, Smi>{fst: 1, snd: 2};
- const smiAndIntptr = Swap<intptr, Smi>(intptrAndSmi);
+ const smiAndIntptr = TupleSwap(intptrAndSmi);
check(intptrAndSmi.fst == smiAndIntptr.snd);
check(intptrAndSmi.snd == smiAndIntptr.fst);
- return smiAndIntptr;
+ const tupleTuple =
+ TestTuple<TestTuple<intptr, Smi>>{fst: intptrAndSmi, snd: smiAndIntptr};
+ return tupleTuple;
+ }
+
+ macro BranchAndWriteResult(x: Smi, box: SmiBox): bool {
+ if (x > 5 || x < 0) {
+ box.value = 1;
+ return true;
+ } else {
+ box.value = 2;
+ return false;
+ }
+ }
+
+ @export
+ macro TestBranchOnBoolOptimization(implicit context: Context)(input: Smi) {
+ const box = NewSmiBox(1);
+ // If the two branches get combined into one, we should be able to determine
+ // the value of {box} statically.
+ if (BranchAndWriteResult(input, box)) {
+ StaticAssert(box.value == 1);
+ } else {
+ StaticAssert(box.value == 2);
+ }
}
}
diff --git a/deps/v8/test/unittests/BUILD.gn b/deps/v8/test/unittests/BUILD.gn
index 87013f9fbc..7a379f77e8 100644
--- a/deps/v8/test/unittests/BUILD.gn
+++ b/deps/v8/test/unittests/BUILD.gn
@@ -224,6 +224,7 @@ v8_source_set("unittests_sources") {
"wasm/wasm-compiler-unittest.cc",
"wasm/wasm-macro-gen-unittest.cc",
"wasm/wasm-module-builder-unittest.cc",
+ "wasm/wasm-module-sourcemap-unittest.cc",
"wasm/wasm-opcodes-unittest.cc",
"wasm/wasm-text-unittest.cc",
"zone/zone-allocator-unittest.cc",
@@ -301,8 +302,8 @@ v8_source_set("unittests_sources") {
"../..:v8_for_testing",
"../..:v8_libbase",
"../..:v8_libplatform",
- "../../third_party/inspector_protocol:encoding_test",
"../../third_party/inspector_protocol:bindings_test",
+ "../../third_party/inspector_protocol:encoding_test",
"//build/win:default_exe_manifest",
"//testing/gmock",
"//testing/gtest",
diff --git a/deps/v8/test/unittests/api/access-check-unittest.cc b/deps/v8/test/unittests/api/access-check-unittest.cc
index 65e20d2510..3b63666f4b 100644
--- a/deps/v8/test/unittests/api/access-check-unittest.cc
+++ b/deps/v8/test/unittests/api/access-check-unittest.cc
@@ -27,6 +27,12 @@ MaybeLocal<Value> CompileRun(Isolate* isolate, const char* source) {
return script->Run(context);
}
+v8::Local<v8::String> v8_str(const char* x) {
+ return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x,
+ v8::NewStringType::kNormal)
+ .ToLocalChecked();
+}
+
} // namespace
TEST_F(AccessCheckTest, GetOwnPropertyDescriptor) {
@@ -42,10 +48,8 @@ TEST_F(AccessCheckTest, GetOwnPropertyDescriptor) {
Local<FunctionTemplate> setter_template = FunctionTemplate::New(
isolate(), [](const FunctionCallbackInfo<v8::Value>& info) { FAIL(); });
setter_template->SetAcceptAnyReceiver(false);
- global_template->SetAccessorProperty(
- String::NewFromUtf8(isolate(), "property", NewStringType::kNormal)
- .ToLocalChecked(),
- getter_template, setter_template);
+ global_template->SetAccessorProperty(v8_str("property"), getter_template,
+ setter_template);
Local<Context> target_context =
Context::New(isolate(), nullptr, global_template);
@@ -53,10 +57,7 @@ TEST_F(AccessCheckTest, GetOwnPropertyDescriptor) {
Context::New(isolate(), nullptr, global_template);
accessing_context->Global()
- ->Set(accessing_context,
- String::NewFromUtf8(isolate(), "other", NewStringType::kNormal)
- .ToLocalChecked(),
- target_context->Global())
+ ->Set(accessing_context, v8_str("other"), target_context->Global())
.FromJust();
Context::Scope context_scope(accessing_context);
@@ -71,15 +72,118 @@ TEST_F(AccessCheckTest, GetOwnPropertyDescriptor) {
" .set.call(other, 42);");
}
-namespace {
-bool failed_access_check_callback_called;
+class AccessRegressionTest : public AccessCheckTest {
+ protected:
+ i::Handle<i::JSFunction> RetrieveFunctionFrom(Local<Context> context,
+ const char* script) {
+ Context::Scope context_scope(context);
+ Local<Value> getter = CompileRun(isolate(), script).ToLocalChecked();
+ EXPECT_TRUE(getter->IsFunction());
+
+ i::Handle<i::JSReceiver> r =
+ Utils::OpenHandle(*Local<Function>::Cast(getter));
+ EXPECT_TRUE(r->IsJSFunction());
+ return i::Handle<i::JSFunction>::cast(r);
+ }
+};
-v8::Local<v8::String> v8_str(const char* x) {
- return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x,
- v8::NewStringType::kNormal)
- .ToLocalChecked();
+TEST_F(AccessRegressionTest,
+ InstantiatedLazyAccessorPairsHaveCorrectNativeContext) {
+ // The setup creates two contexts and sets an object created
+ // in context 1 on the global of context 2.
+ // The object has an accessor pair {property}. Accessing the
+ // property descriptor of {property} causes instantiation of the
+ // accessor pair. The test checks that the access pair has the
+ // correct native context.
+ Local<FunctionTemplate> getter_template = FunctionTemplate::New(
+ isolate(), [](const FunctionCallbackInfo<Value>&) { FAIL(); });
+ Local<FunctionTemplate> setter_template = FunctionTemplate::New(
+ isolate(), [](const FunctionCallbackInfo<v8::Value>&) { FAIL(); });
+
+ Local<ObjectTemplate> object_template = ObjectTemplate::New(isolate());
+ object_template->SetAccessorProperty(v8_str("property"), getter_template,
+ setter_template);
+
+ Local<Context> context1 = Context::New(isolate(), nullptr);
+ Local<Context> context2 = Context::New(isolate(), nullptr);
+
+ Local<Object> object =
+ object_template->NewInstance(context1).ToLocalChecked();
+ context2->Global()
+ ->Set(context2, v8_str("object_from_context1"), object)
+ .Check();
+
+ i::Handle<i::JSFunction> getter = RetrieveFunctionFrom(
+ context2,
+ "Object.getOwnPropertyDescriptor(object_from_context1, 'property').get");
+
+ ASSERT_EQ(getter->native_context(), *Utils::OpenHandle(*context1));
+}
+
+// Regression test for https://crbug.com/986063.
+TEST_F(AccessRegressionTest,
+ InstantiatedLazyAccessorPairsHaveCorrectNativeContextDebug) {
+ // The setup creates two contexts and installs an object "object"
+ // on the global this for each context.
+ // The object consists of:
+ // - an accessor pair "property".
+ // - a normal function "breakfn".
+ //
+ // The test sets a break point on {object.breakfn} in the first context.
+ // This forces instantation of the JSFunction for the {object.property}
+ // accessor pair. The test verifies afterwards that the respective
+ // JSFunction of the getter have the correct native context.
+
+ Local<FunctionTemplate> getter_template = FunctionTemplate::New(
+ isolate(), [](const FunctionCallbackInfo<Value>&) { FAIL(); });
+ Local<FunctionTemplate> setter_template = FunctionTemplate::New(
+ isolate(), [](const FunctionCallbackInfo<v8::Value>&) { FAIL(); });
+ Local<FunctionTemplate> break_template = FunctionTemplate::New(
+ isolate(), [](const FunctionCallbackInfo<v8::Value>&) { FAIL(); });
+
+ Local<Context> context1 = Context::New(isolate(), nullptr);
+ Local<Context> context2 = Context::New(isolate(), nullptr);
+
+ Local<ObjectTemplate> object_template = ObjectTemplate::New(isolate());
+ object_template->Set(isolate(), "breakfn", break_template);
+ object_template->SetAccessorProperty(v8_str("property"), getter_template,
+ setter_template);
+
+ Local<Object> object1 =
+ object_template->NewInstance(context1).ToLocalChecked();
+ EXPECT_TRUE(
+ context1->Global()->Set(context1, v8_str("object"), object1).IsJust());
+
+ Local<Object> object2 =
+ object_template->NewInstance(context2).ToLocalChecked();
+ EXPECT_TRUE(
+ context2->Global()->Set(context2, v8_str("object"), object2).IsJust());
+
+ // Force instantiation of the JSFunction for the getter and setter
+ // of {object.property} by setting a break point on {object.breakfn}
+ {
+ Context::Scope context_scope(context1);
+ i::Isolate* iso = reinterpret_cast<i::Isolate*>(isolate());
+ i::Handle<i::JSFunction> break_fn =
+ RetrieveFunctionFrom(context1, "object.breakfn");
+
+ int id;
+ iso->debug()->SetBreakpointForFunction(i::handle(break_fn->shared(), iso),
+ iso->factory()->empty_string(), &id);
+ }
+
+ i::Handle<i::JSFunction> getter_c1 = RetrieveFunctionFrom(
+ context1, "Object.getOwnPropertyDescriptor(object, 'property').get");
+ i::Handle<i::JSFunction> getter_c2 = RetrieveFunctionFrom(
+ context2, "Object.getOwnPropertyDescriptor(object, 'property').get");
+
+ ASSERT_EQ(getter_c1->native_context(), *Utils::OpenHandle(*context1));
+ ASSERT_EQ(getter_c2->native_context(), *Utils::OpenHandle(*context2));
}
+namespace {
+bool failed_access_check_callback_called;
+
class AccessCheckTestConsoleDelegate : public debug::ConsoleDelegate {
public:
void Log(const debug::ConsoleCallArguments& args,
diff --git a/deps/v8/test/unittests/base/atomic-utils-unittest.cc b/deps/v8/test/unittests/base/atomic-utils-unittest.cc
index 442257eff8..7ef0e948d7 100644
--- a/deps/v8/test/unittests/base/atomic-utils-unittest.cc
+++ b/deps/v8/test/unittests/base/atomic-utils-unittest.cc
@@ -105,7 +105,7 @@ TEST(AsAtomic8, CompareAndSwap_Concurrent) {
}
}
for (int i = 0; i < kThreadCount; i++) {
- threads[i].Start();
+ CHECK(threads[i].Start());
}
for (int i = 0; i < kThreadCount; i++) {
@@ -179,7 +179,7 @@ TEST(AsAtomicWord, SetBits_Concurrent) {
threads[i].Initialize(&word, i * 2);
}
for (int i = 0; i < kThreadCount; i++) {
- threads[i].Start();
+ CHECK(threads[i].Start());
}
for (int i = 0; i < kThreadCount; i++) {
threads[i].Join();
diff --git a/deps/v8/test/unittests/base/platform/condition-variable-unittest.cc b/deps/v8/test/unittests/base/platform/condition-variable-unittest.cc
index 6206569433..375f17ad2f 100644
--- a/deps/v8/test/unittests/base/platform/condition-variable-unittest.cc
+++ b/deps/v8/test/unittests/base/platform/condition-variable-unittest.cc
@@ -64,7 +64,7 @@ TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) {
MutexGuard lock_guard(&threads[n].mutex_);
EXPECT_FALSE(threads[n].running_);
EXPECT_FALSE(threads[n].finished_);
- threads[n].Start();
+ CHECK(threads[n].Start());
// Wait for nth thread to start.
while (!threads[n].running_) {
threads[n].cv_.Wait(&threads[n].mutex_);
@@ -153,7 +153,7 @@ TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) {
for (int n = 0; n < kThreadCount; ++n) {
EXPECT_FALSE(threads[n].running_);
EXPECT_FALSE(threads[n].finished_);
- threads[n].Start();
+ CHECK(threads[n].Start());
}
}
@@ -281,7 +281,7 @@ TEST(ConditionVariable, LoopIncrement) {
// Start all threads.
for (int n = thread_count - 1; n >= 0; --n) {
- threads[n]->Start();
+ CHECK(threads[n]->Start());
}
// Join and cleanup all threads.
diff --git a/deps/v8/test/unittests/base/platform/platform-unittest.cc b/deps/v8/test/unittests/base/platform/platform-unittest.cc
index d31d85447c..27154b3c24 100644
--- a/deps/v8/test/unittests/base/platform/platform-unittest.cc
+++ b/deps/v8/test/unittests/base/platform/platform-unittest.cc
@@ -79,7 +79,7 @@ class ThreadLocalStorageTest : public Thread, public ::testing::Test {
TEST_F(ThreadLocalStorageTest, DoTest) {
Run();
- Start();
+ CHECK(Start());
Join();
}
diff --git a/deps/v8/test/unittests/base/platform/semaphore-unittest.cc b/deps/v8/test/unittests/base/platform/semaphore-unittest.cc
index bd4a00fe95..3cddc565c7 100644
--- a/deps/v8/test/unittests/base/platform/semaphore-unittest.cc
+++ b/deps/v8/test/unittests/base/platform/semaphore-unittest.cc
@@ -94,8 +94,8 @@ TEST(Semaphore, ProducerConsumer) {
Semaphore used_space(0);
ProducerThread producer_thread(buffer, &free_space, &used_space);
ConsumerThread consumer_thread(buffer, &free_space, &used_space);
- producer_thread.Start();
- consumer_thread.Start();
+ CHECK(producer_thread.Start());
+ CHECK(consumer_thread.Start());
producer_thread.Join();
consumer_thread.Join();
}
@@ -106,8 +106,8 @@ TEST(Semaphore, WaitAndSignal) {
WaitAndSignalThread t1(&semaphore);
WaitAndSignalThread t2(&semaphore);
- t1.Start();
- t2.Start();
+ CHECK(t1.Start());
+ CHECK(t2.Start());
// Make something available.
semaphore.Signal();
diff --git a/deps/v8/test/unittests/codegen/code-stub-assembler-unittest.cc b/deps/v8/test/unittests/codegen/code-stub-assembler-unittest.cc
index 287a11442b..df387d3d94 100644
--- a/deps/v8/test/unittests/codegen/code-stub-assembler-unittest.cc
+++ b/deps/v8/test/unittests/codegen/code-stub-assembler-unittest.cc
@@ -14,6 +14,7 @@
using ::testing::_;
using v8::internal::compiler::Node;
+using v8::internal::compiler::TNode;
namespace c = v8::internal::compiler;
@@ -29,11 +30,11 @@ CodeStubAssemblerTestState::CodeStubAssemblerTestState(
TARGET_TEST_F(CodeStubAssemblerTest, SmiTag) {
CodeStubAssemblerTestState state(this);
CodeStubAssemblerForTest m(&state);
- Node* value = m.Int32Constant(44);
+ TNode<IntPtrT> value = m.IntPtrConstant(44);
EXPECT_THAT(m.SmiTag(value),
IsBitcastWordToTaggedSigned(c::IsIntPtrConstant(
static_cast<intptr_t>(44) << (kSmiShiftSize + kSmiTagSize))));
- EXPECT_THAT(m.SmiUntag(value),
+ EXPECT_THAT(m.SmiUntag(m.ReinterpretCast<Smi>(value)),
c::IsIntPtrConstant(static_cast<intptr_t>(44) >>
(kSmiShiftSize + kSmiTagSize)));
}
@@ -42,9 +43,9 @@ TARGET_TEST_F(CodeStubAssemblerTest, IntPtrMax) {
CodeStubAssemblerTestState state(this);
CodeStubAssemblerForTest m(&state);
{
- Node* a = m.IntPtrConstant(100);
- Node* b = m.IntPtrConstant(1);
- Node* z = m.IntPtrMax(a, b);
+ TNode<IntPtrT> a = m.IntPtrConstant(100);
+ TNode<IntPtrT> b = m.IntPtrConstant(1);
+ TNode<IntPtrT> z = m.IntPtrMax(a, b);
EXPECT_THAT(z, c::IsIntPtrConstant(100));
}
}
@@ -53,9 +54,9 @@ TARGET_TEST_F(CodeStubAssemblerTest, IntPtrMin) {
CodeStubAssemblerTestState state(this);
CodeStubAssemblerForTest m(&state);
{
- Node* a = m.IntPtrConstant(100);
- Node* b = m.IntPtrConstant(1);
- Node* z = m.IntPtrMin(a, b);
+ TNode<IntPtrT> a = m.IntPtrConstant(100);
+ TNode<IntPtrT> b = m.IntPtrConstant(1);
+ TNode<IntPtrT> z = m.IntPtrMin(a, b);
EXPECT_THAT(z, c::IsIntPtrConstant(1));
}
}
diff --git a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc
index bc74e6fe19..8b15811d36 100644
--- a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc
+++ b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc
@@ -92,7 +92,7 @@ class CompilerDispatcherTest : public TestWithNativeContext {
ast_node_factory.NewFunctionLiteral(
function_name, function_scope, statements, -1, -1, -1,
FunctionLiteral::kNoDuplicateParameters,
- FunctionLiteral::kAnonymousExpression,
+ FunctionSyntaxKind::kAnonymousExpression,
FunctionLiteral::kShouldEagerCompile, shared->StartPosition(), true,
shared->function_literal_id(), nullptr);
diff --git a/deps/v8/test/unittests/compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc b/deps/v8/test/unittests/compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc
index ae2e42b61f..ff59e79a60 100644
--- a/deps/v8/test/unittests/compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc
+++ b/deps/v8/test/unittests/compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc
@@ -27,8 +27,7 @@ namespace {
class BlockingCompilationJob : public OptimizedCompilationJob {
public:
BlockingCompilationJob(Isolate* isolate, Handle<JSFunction> function)
- : OptimizedCompilationJob(isolate->stack_guard()->real_climit(), &info_,
- "BlockingCompilationJob",
+ : OptimizedCompilationJob(&info_, "BlockingCompilationJob",
State::kReadyToExecute),
shared_(function->shared(), isolate),
zone_(isolate->allocator(), ZONE_NAME),
diff --git a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
index a26a8d9192..bb4848db6c 100644
--- a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
+++ b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
@@ -3225,54 +3225,6 @@ TEST_F(InstructionSelectorTest, Float64Neg) {
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
}
-TEST_F(InstructionSelectorTest, StackCheck0) {
- StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
- Node* const sp = m.LoadStackPointer();
- Node* const stack_limit = m.Load(MachineType::Int32(), m.Parameter(0));
- Node* const interrupt = m.UintPtrLessThan(sp, stack_limit);
-
- RawMachineLabel if_true, if_false;
- m.Branch(interrupt, &if_true, &if_false);
-
- m.Bind(&if_true);
- m.Return(m.Int32Constant(1));
-
- m.Bind(&if_false);
- m.Return(m.Int32Constant(0));
-
- Stream s = m.Build();
-
- ASSERT_EQ(2U, s.size());
- EXPECT_EQ(kArmLdr, s[0]->arch_opcode());
- EXPECT_EQ(kArmCmp, s[1]->arch_opcode());
- EXPECT_EQ(4U, s[1]->InputCount());
- EXPECT_EQ(0U, s[1]->OutputCount());
-}
-
-TEST_F(InstructionSelectorTest, StackCheck1) {
- StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
- Node* const sp = m.LoadStackPointer();
- Node* const stack_limit = m.Load(MachineType::Int32(), m.Parameter(0));
- Node* const sp_within_limit = m.UintPtrLessThan(stack_limit, sp);
-
- RawMachineLabel if_true, if_false;
- m.Branch(sp_within_limit, &if_true, &if_false);
-
- m.Bind(&if_true);
- m.Return(m.Int32Constant(1));
-
- m.Bind(&if_false);
- m.Return(m.Int32Constant(0));
-
- Stream s = m.Build();
-
- ASSERT_EQ(2U, s.size());
- EXPECT_EQ(kArmLdr, s[0]->arch_opcode());
- EXPECT_EQ(kArmCmp, s[1]->arch_opcode());
- EXPECT_EQ(4U, s[1]->InputCount());
- EXPECT_EQ(0U, s[1]->OutputCount());
-}
-
} // namespace compiler
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
index 867f89abfd..b969d9a278 100644
--- a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
+++ b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
@@ -4571,54 +4571,6 @@ TEST_F(InstructionSelectorTest, CompareFloat64HighGreaterThanOrEqualZero64) {
EXPECT_EQ(63, s.ToInt32(s[1]->InputAt(1)));
}
-TEST_F(InstructionSelectorTest, StackCheck0) {
- StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
- Node* const sp = m.LoadStackPointer();
- Node* const stack_limit = m.Load(MachineType::Int64(), m.Parameter(0));
- Node* const interrupt = m.UintPtrLessThan(sp, stack_limit);
-
- RawMachineLabel if_true, if_false;
- m.Branch(interrupt, &if_true, &if_false);
-
- m.Bind(&if_true);
- m.Return(m.Int32Constant(1));
-
- m.Bind(&if_false);
- m.Return(m.Int32Constant(0));
-
- Stream s = m.Build();
-
- ASSERT_EQ(2U, s.size());
- EXPECT_EQ(kArm64Ldr, s[0]->arch_opcode());
- EXPECT_EQ(kArm64Cmp, s[1]->arch_opcode());
- EXPECT_EQ(4U, s[1]->InputCount());
- EXPECT_EQ(0U, s[1]->OutputCount());
-}
-
-TEST_F(InstructionSelectorTest, StackCheck1) {
- StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer());
- Node* const sp = m.LoadStackPointer();
- Node* const stack_limit = m.Load(MachineType::Int64(), m.Parameter(0));
- Node* const sp_within_limit = m.UintPtrLessThan(stack_limit, sp);
-
- RawMachineLabel if_true, if_false;
- m.Branch(sp_within_limit, &if_true, &if_false);
-
- m.Bind(&if_true);
- m.Return(m.Int32Constant(1));
-
- m.Bind(&if_false);
- m.Return(m.Int32Constant(0));
-
- Stream s = m.Build();
-
- ASSERT_EQ(2U, s.size());
- EXPECT_EQ(kArm64Ldr, s[0]->arch_opcode());
- EXPECT_EQ(kArm64Cmp, s[1]->arch_opcode());
- EXPECT_EQ(4U, s[1]->InputCount());
- EXPECT_EQ(0U, s[1]->OutputCount());
-}
-
TEST_F(InstructionSelectorTest, ExternalReferenceLoad1) {
// Test offsets we can use kMode_Root for.
const int64_t kOffsets[] = {0, 1, 4, INT32_MIN, INT32_MAX};
diff --git a/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc
index a48ad1b359..c29979c600 100644
--- a/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc
+++ b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc
@@ -25,7 +25,7 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
InstructionSelector::Features features,
InstructionSelectorTest::StreamBuilderMode mode,
InstructionSelector::SourcePositionMode source_position_mode) {
- Schedule* schedule = Export();
+ Schedule* schedule = ExportForTest();
if (FLAG_trace_turbo) {
StdoutStream{} << "=== Schedule before instruction selection ==="
<< std::endl
@@ -40,11 +40,13 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
instruction_blocks);
SourcePositionTable source_position_table(graph());
TickCounter tick_counter;
+ size_t max_unoptimized_frame_height = 0;
InstructionSelector selector(
test_->zone(), node_count, &linkage, &sequence, schedule,
&source_position_table, nullptr,
InstructionSelector::kEnableSwitchJumpTable, &tick_counter,
- source_position_mode, features, InstructionSelector::kDisableScheduling,
+ &max_unoptimized_frame_height, source_position_mode, features,
+ InstructionSelector::kDisableScheduling,
InstructionSelector::kEnableRootsRelativeAddressing,
PoisoningMitigationLevel::kPoisonAll);
selector.SelectInstructions();
diff --git a/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc b/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc
index 34fb84957c..a231539f6f 100644
--- a/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc
+++ b/deps/v8/test/unittests/compiler/branch-elimination-unittest.cc
@@ -39,7 +39,6 @@ class BranchEliminationTest : public GraphTest {
MachineOperatorBuilder machine_;
};
-
TEST_F(BranchEliminationTest, NestedBranchSameTrue) {
// { return (x ? (x ? 1 : 2) : 3; }
// should be reduced to
@@ -80,7 +79,6 @@ TEST_F(BranchEliminationTest, NestedBranchSameTrue) {
IsInt32Constant(2), IsMerge(outer_if_true, IsDead())));
}
-
TEST_F(BranchEliminationTest, NestedBranchSameFalse) {
// { return (x ? 1 : (x ? 2 : 3); }
// should be reduced to
@@ -122,10 +120,9 @@ TEST_F(BranchEliminationTest, NestedBranchSameFalse) {
IsInt32Constant(3), IsMerge(IsDead(), outer_if_false)));
}
-
TEST_F(BranchEliminationTest, BranchAfterDiamond) {
// { var y = x ? 1 : 2; return y + x ? 3 : 4; }
- // should not be reduced.
+ // second branch's condition should be replaced with a phi.
Node* condition = Parameter(0);
Node* branch1 =
@@ -136,7 +133,7 @@ TEST_F(BranchEliminationTest, BranchAfterDiamond) {
Node* phi1 =
graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
Int32Constant(1), Int32Constant(2), merge1);
-
+ // Second branch use the same condition.
Node* branch2 = graph()->NewNode(common()->Branch(), condition, merge1);
Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
@@ -145,7 +142,6 @@ TEST_F(BranchEliminationTest, BranchAfterDiamond) {
graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
Int32Constant(3), Int32Constant(4), merge1);
-
Node* add = graph()->NewNode(machine()->Int32Add(), phi1, phi2);
Node* zero = graph()->NewNode(common()->Int32Constant(0));
Node* ret =
@@ -154,13 +150,13 @@ TEST_F(BranchEliminationTest, BranchAfterDiamond) {
Reduce();
- // Outer branch should not be rewritten, the inner branch condition should
- // be true.
- EXPECT_THAT(branch1, IsBranch(condition, graph()->start()));
- EXPECT_THAT(branch2, IsBranch(condition, merge1));
+ // The branch condition for branch2 should be a phi with constants.
+ EXPECT_THAT(branch2,
+ IsBranch(IsPhi(MachineRepresentation::kWord32, IsInt32Constant(1),
+ IsInt32Constant(0), merge1),
+ merge1));
}
-
TEST_F(BranchEliminationTest, BranchInsideLoopSame) {
// if (x) while (x) { return 2; } else { return 1; }
// should be rewritten to
@@ -172,7 +168,6 @@ TEST_F(BranchEliminationTest, BranchInsideLoopSame) {
graph()->NewNode(common()->Branch(), condition, graph()->start());
Node* outer_if_true = graph()->NewNode(common()->IfTrue(), outer_branch);
-
Node* loop = graph()->NewNode(common()->Loop(1), outer_if_true);
Node* effect =
graph()->NewNode(common()->EffectPhi(1), graph()->start(), loop);
diff --git a/deps/v8/test/unittests/compiler/code-assembler-unittest.cc b/deps/v8/test/unittests/compiler/code-assembler-unittest.cc
index 0541f68440..43dfd9876f 100644
--- a/deps/v8/test/unittests/compiler/code-assembler-unittest.cc
+++ b/deps/v8/test/unittests/compiler/code-assembler-unittest.cc
@@ -13,6 +13,7 @@
#include "test/unittests/compiler/node-test-utils.h"
using ::testing::_;
+using ::testing::Eq;
namespace v8 {
namespace internal {
@@ -28,29 +29,29 @@ TARGET_TEST_F(CodeAssemblerTest, IntPtrAdd) {
CodeAssemblerForTest m(&state);
{
Node* a = m.Parameter(0);
- Node* b = m.Int32Constant(1);
- Node* add = m.IntPtrAdd(a, b);
- EXPECT_THAT(add, IsIntPtrAdd(a, b));
+ TNode<IntPtrT> b = m.IntPtrConstant(1);
+ TNode<WordT> add = m.IntPtrAdd(a, b);
+ EXPECT_THAT(add, IsIntPtrAdd(Eq(a), Eq(b)));
}
// x + 0 => x
{
Node* a = m.Parameter(0);
- Node* b = m.Int32Constant(0);
- Node* add = m.IntPtrAdd(a, b);
+ TNode<IntPtrT> b = m.IntPtrConstant(0);
+ TNode<WordT> add = m.IntPtrAdd(a, b);
EXPECT_THAT(add, a);
}
// 0 + x => x
{
Node* a = m.Parameter(0);
- Node* b = m.Int32Constant(0);
- Node* add = m.IntPtrAdd(b, a);
+ TNode<IntPtrT> b = m.IntPtrConstant(0);
+ TNode<WordT> add = m.IntPtrAdd(b, a);
EXPECT_THAT(add, a);
}
// CONST_a + CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(22);
- Node* b = m.IntPtrConstant(33);
- Node* c = m.IntPtrAdd(a, b);
+ TNode<IntPtrT> a = m.IntPtrConstant(22);
+ TNode<IntPtrT> b = m.IntPtrConstant(33);
+ TNode<IntPtrT> c = m.IntPtrAdd(a, b);
EXPECT_THAT(c, IsIntPtrConstant(55));
}
}
@@ -60,22 +61,22 @@ TARGET_TEST_F(CodeAssemblerTest, IntPtrSub) {
CodeAssemblerForTest m(&state);
{
Node* a = m.Parameter(0);
- Node* b = m.Int32Constant(1);
- Node* sub = m.IntPtrSub(a, b);
- EXPECT_THAT(sub, IsIntPtrSub(a, b));
+ TNode<IntPtrT> b = m.IntPtrConstant(1);
+ TNode<WordT> sub = m.IntPtrSub(a, b);
+ EXPECT_THAT(sub, IsIntPtrSub(Eq(a), Eq(b)));
}
// x - 0 => x
{
Node* a = m.Parameter(0);
- Node* b = m.Int32Constant(0);
- Node* c = m.IntPtrSub(a, b);
+ TNode<IntPtrT> b = m.IntPtrConstant(0);
+ TNode<WordT> c = m.IntPtrSub(a, b);
EXPECT_THAT(c, a);
}
// CONST_a - CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(100);
- Node* b = m.IntPtrConstant(1);
- Node* c = m.IntPtrSub(a, b);
+ TNode<IntPtrT> a = m.IntPtrConstant(100);
+ TNode<IntPtrT> b = m.IntPtrConstant(1);
+ TNode<IntPtrT> c = m.IntPtrSub(a, b);
EXPECT_THAT(c, IsIntPtrConstant(99));
}
}
@@ -85,43 +86,43 @@ TARGET_TEST_F(CodeAssemblerTest, IntPtrMul) {
CodeAssemblerForTest m(&state);
{
Node* a = m.Parameter(0);
- Node* b = m.Int32Constant(100);
- Node* mul = m.IntPtrMul(a, b);
- EXPECT_THAT(mul, IsIntPtrMul(a, b));
+ TNode<IntPtrT> b = m.IntPtrConstant(100);
+ TNode<WordT> mul = m.IntPtrMul(a, b);
+ EXPECT_THAT(mul, IsIntPtrMul(Eq(a), Eq(b)));
}
// x * 1 => x
{
Node* a = m.Parameter(0);
- Node* b = m.Int32Constant(1);
- Node* mul = m.IntPtrMul(a, b);
+ TNode<IntPtrT> b = m.IntPtrConstant(1);
+ TNode<WordT> mul = m.IntPtrMul(a, b);
EXPECT_THAT(mul, a);
}
// 1 * x => x
{
Node* a = m.Parameter(0);
- Node* b = m.Int32Constant(1);
- Node* mul = m.IntPtrMul(b, a);
+ TNode<IntPtrT> b = m.IntPtrConstant(1);
+ TNode<WordT> mul = m.IntPtrMul(b, a);
EXPECT_THAT(mul, a);
}
// CONST_a * CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(100);
- Node* b = m.IntPtrConstant(5);
- Node* c = m.IntPtrMul(a, b);
+ TNode<IntPtrT> a = m.IntPtrConstant(100);
+ TNode<IntPtrT> b = m.IntPtrConstant(5);
+ TNode<IntPtrT> c = m.IntPtrMul(a, b);
EXPECT_THAT(c, IsIntPtrConstant(500));
}
// x * 2^CONST => x << CONST
{
Node* a = m.Parameter(0);
- Node* b = m.IntPtrConstant(1 << 3);
- Node* c = m.IntPtrMul(a, b);
+ TNode<IntPtrT> b = m.IntPtrConstant(1 << 3);
+ TNode<WordT> c = m.IntPtrMul(a, b);
EXPECT_THAT(c, IsWordShl(a, IsIntPtrConstant(3)));
}
// 2^CONST * x => x << CONST
{
- Node* a = m.IntPtrConstant(1 << 3);
+ TNode<IntPtrT> a = m.IntPtrConstant(1 << 3);
Node* b = m.Parameter(0);
- Node* c = m.IntPtrMul(a, b);
+ TNode<WordT> c = m.IntPtrMul(a, b);
EXPECT_THAT(c, IsWordShl(b, IsIntPtrConstant(3)));
}
}
@@ -169,19 +170,19 @@ TARGET_TEST_F(CodeAssemblerTest, WordShl) {
CodeAssemblerForTest m(&state);
{
Node* a = m.Parameter(0);
- Node* add = m.WordShl(a, 10);
+ TNode<WordT> add = m.WordShl(a, 10);
EXPECT_THAT(add, IsWordShl(a, IsIntPtrConstant(10)));
}
// x << 0 => x
{
Node* a = m.Parameter(0);
- Node* add = m.WordShl(a, 0);
+ TNode<WordT> add = m.WordShl(a, 0);
EXPECT_THAT(add, a);
}
// CONST_a << CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(1024);
- Node* shl = m.WordShl(a, 2);
+ TNode<IntPtrT> a = m.IntPtrConstant(1024);
+ TNode<WordT> shl = m.WordShl(a, 2);
EXPECT_THAT(shl, IsIntPtrConstant(4096));
}
}
@@ -191,25 +192,25 @@ TARGET_TEST_F(CodeAssemblerTest, WordShr) {
CodeAssemblerForTest m(&state);
{
Node* a = m.Parameter(0);
- Node* shr = m.WordShr(a, 10);
+ TNode<WordT> shr = m.WordShr(a, 10);
EXPECT_THAT(shr, IsWordShr(a, IsIntPtrConstant(10)));
}
// x >> 0 => x
{
Node* a = m.Parameter(0);
- Node* shr = m.WordShr(a, 0);
+ TNode<WordT> shr = m.WordShr(a, 0);
EXPECT_THAT(shr, a);
}
// +CONST_a >> CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(4096);
- Node* shr = m.WordShr(a, 2);
+ TNode<IntPtrT> a = m.IntPtrConstant(4096);
+ TNode<IntPtrT> shr = m.WordShr(a, 2);
EXPECT_THAT(shr, IsIntPtrConstant(1024));
}
// -CONST_a >> CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(-1234);
- Node* shr = m.WordShr(a, 2);
+ TNode<IntPtrT> a = m.IntPtrConstant(-1234);
+ TNode<IntPtrT> shr = m.WordShr(a, 2);
EXPECT_THAT(shr, IsIntPtrConstant(static_cast<uintptr_t>(-1234) >> 2));
}
}
@@ -219,25 +220,25 @@ TARGET_TEST_F(CodeAssemblerTest, WordSar) {
CodeAssemblerForTest m(&state);
{
Node* a = m.Parameter(0);
- Node* sar = m.WordSar(a, m.IntPtrConstant(10));
+ TNode<WordT> sar = m.WordSar(a, m.IntPtrConstant(10));
EXPECT_THAT(sar, IsWordSar(a, IsIntPtrConstant(10)));
}
// x >>> 0 => x
{
Node* a = m.Parameter(0);
- Node* sar = m.WordSar(a, m.IntPtrConstant(0));
+ TNode<WordT> sar = m.WordSar(a, m.IntPtrConstant(0));
EXPECT_THAT(sar, a);
}
// +CONST_a >>> CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(4096);
- Node* sar = m.WordSar(a, m.IntPtrConstant(2));
+ TNode<IntPtrT> a = m.IntPtrConstant(4096);
+ TNode<IntPtrT> sar = m.WordSar(a, m.IntPtrConstant(2));
EXPECT_THAT(sar, IsIntPtrConstant(1024));
}
// -CONST_a >>> CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(-1234);
- Node* sar = m.WordSar(a, m.IntPtrConstant(2));
+ TNode<IntPtrT> a = m.IntPtrConstant(-1234);
+ TNode<IntPtrT> sar = m.WordSar(a, m.IntPtrConstant(2));
EXPECT_THAT(sar, IsIntPtrConstant(static_cast<intptr_t>(-1234) >> 2));
}
}
@@ -247,25 +248,25 @@ TARGET_TEST_F(CodeAssemblerTest, WordOr) {
CodeAssemblerForTest m(&state);
{
Node* a = m.Parameter(0);
- Node* z = m.WordOr(a, m.IntPtrConstant(8));
+ TNode<WordT> z = m.WordOr(a, m.IntPtrConstant(8));
EXPECT_THAT(z, IsWordOr(a, IsIntPtrConstant(8)));
}
// x | 0 => x
{
Node* a = m.Parameter(0);
- Node* z = m.WordOr(a, m.IntPtrConstant(0));
+ TNode<WordT> z = m.WordOr(a, m.IntPtrConstant(0));
EXPECT_THAT(z, a);
}
// 0 | x => x
{
Node* a = m.Parameter(0);
- Node* z = m.WordOr(m.IntPtrConstant(0), a);
+ TNode<WordT> z = m.WordOr(m.IntPtrConstant(0), a);
EXPECT_THAT(z, a);
}
// CONST_a | CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(3);
- Node* b = m.WordOr(a, m.IntPtrConstant(7));
+ TNode<IntPtrT> a = m.IntPtrConstant(3);
+ TNode<WordT> b = m.WordOr(a, m.IntPtrConstant(7));
EXPECT_THAT(b, IsIntPtrConstant(7));
}
}
@@ -275,13 +276,13 @@ TARGET_TEST_F(CodeAssemblerTest, WordAnd) {
CodeAssemblerForTest m(&state);
{
Node* a = m.Parameter(0);
- Node* z = m.WordAnd(a, m.IntPtrConstant(8));
+ TNode<WordT> z = m.WordAnd(a, m.IntPtrConstant(8));
EXPECT_THAT(z, IsWordAnd(a, IsIntPtrConstant(8)));
}
// CONST_a & CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(3);
- Node* b = m.WordAnd(a, m.IntPtrConstant(7));
+ TNode<IntPtrT> a = m.IntPtrConstant(3);
+ TNode<IntPtrT> b = m.WordAnd(a, m.IntPtrConstant(7));
EXPECT_THAT(b, IsIntPtrConstant(3));
}
}
@@ -291,13 +292,13 @@ TARGET_TEST_F(CodeAssemblerTest, WordXor) {
CodeAssemblerForTest m(&state);
{
Node* a = m.Parameter(0);
- Node* z = m.WordXor(a, m.IntPtrConstant(8));
+ TNode<WordT> z = m.WordXor(a, m.IntPtrConstant(8));
EXPECT_THAT(z, IsWordXor(a, IsIntPtrConstant(8)));
}
// CONST_a ^ CONST_b => CONST_c
{
- Node* a = m.IntPtrConstant(3);
- Node* b = m.WordXor(a, m.IntPtrConstant(7));
+ TNode<IntPtrT> a = m.IntPtrConstant(3);
+ TNode<WordT> b = m.WordXor(a, m.IntPtrConstant(7));
EXPECT_THAT(b, IsIntPtrConstant(4));
}
}
diff --git a/deps/v8/test/unittests/compiler/graph-unittest.cc b/deps/v8/test/unittests/compiler/graph-unittest.cc
index 485df8e401..ee6b7c02a3 100644
--- a/deps/v8/test/unittests/compiler/graph-unittest.cc
+++ b/deps/v8/test/unittests/compiler/graph-unittest.cc
@@ -23,7 +23,7 @@ GraphTest::GraphTest(int num_parameters)
node_origins_(&graph_) {
graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start()));
- broker()->SetNativeContextRef();
+ broker()->SetTargetNativeContextRef(isolate()->native_context());
}
GraphTest::~GraphTest() = default;
diff --git a/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc b/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
index 8851a6a2df..ba6d3f299e 100644
--- a/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
+++ b/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
@@ -836,58 +836,6 @@ TEST_F(InstructionSelectorTest, Word32Clz) {
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
}
-TEST_F(InstructionSelectorTest, StackCheck0) {
- ExternalReference js_stack_limit =
- ExternalReference::Create(isolate()->stack_guard()->address_of_jslimit());
- StreamBuilder m(this, MachineType::Int32());
- Node* const sp = m.LoadStackPointer();
- Node* const stack_limit =
- m.Load(MachineType::Pointer(), m.ExternalConstant(js_stack_limit));
- Node* const interrupt = m.UintPtrLessThan(sp, stack_limit);
-
- RawMachineLabel if_true, if_false;
- m.Branch(interrupt, &if_true, &if_false);
-
- m.Bind(&if_true);
- m.Return(m.Int32Constant(1));
-
- m.Bind(&if_false);
- m.Return(m.Int32Constant(0));
-
- Stream s = m.Build();
-
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kIA32Cmp, s[0]->arch_opcode());
- EXPECT_EQ(4U, s[0]->InputCount());
- EXPECT_EQ(0U, s[0]->OutputCount());
-}
-
-TEST_F(InstructionSelectorTest, StackCheck1) {
- ExternalReference js_stack_limit =
- ExternalReference::Create(isolate()->stack_guard()->address_of_jslimit());
- StreamBuilder m(this, MachineType::Int32());
- Node* const sp = m.LoadStackPointer();
- Node* const stack_limit =
- m.Load(MachineType::Pointer(), m.ExternalConstant(js_stack_limit));
- Node* const sp_within_limit = m.UintPtrLessThan(stack_limit, sp);
-
- RawMachineLabel if_true, if_false;
- m.Branch(sp_within_limit, &if_true, &if_false);
-
- m.Bind(&if_true);
- m.Return(m.Int32Constant(1));
-
- m.Bind(&if_false);
- m.Return(m.Int32Constant(0));
-
- Stream s = m.Build();
-
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kIA32StackCheck, s[0]->arch_opcode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(0U, s[0]->OutputCount());
-}
-
} // namespace compiler
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc b/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc
index 84d42b31d0..52769b09de 100644
--- a/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc
+++ b/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "src/compiler/int64-lowering.h"
+
+#include "src/codegen/interface-descriptors.h"
+#include "src/codegen/machine-type.h"
#include "src/codegen/signature.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/linkage.h"
@@ -10,7 +13,6 @@
#include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
#include "src/compiler/wasm-compiler.h"
-#include "src/objects/objects-inl.h"
#include "src/wasm/value-type.h"
#include "src/wasm/wasm-module.h"
#include "test/unittests/compiler/graph-unittest.h"
@@ -48,6 +50,25 @@ class Int64LoweringTest : public GraphTest {
lowering.LowerGraph();
}
+ void LowerGraphWithSpecialCase(
+ Node* node, std::unique_ptr<Int64LoweringSpecialCase> special_case,
+ MachineRepresentation rep) {
+ Node* zero = graph()->NewNode(common()->Int32Constant(0));
+ Node* ret = graph()->NewNode(common()->Return(), zero, node,
+ graph()->start(), graph()->start());
+ NodeProperties::MergeControlToEnd(graph(), common(), ret);
+
+ // Create a signature for the outer wasm<>js call; for these tests we focus
+ // on lowering the special cases rather than the wrapper node at the
+ // JavaScript boundaries.
+ Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 0);
+ sig_builder.AddReturn(rep);
+
+ Int64Lowering lowering(graph(), machine(), common(), zone(),
+ sig_builder.Build(), std::move(special_case));
+ lowering.LowerGraph();
+ }
+
void LowerGraph(Node* node, MachineRepresentation return_type,
MachineRepresentation rep = MachineRepresentation::kWord32,
int num_params = 0) {
@@ -968,6 +989,100 @@ TEST_F(Int64LoweringTest, LoopCycle) {
LowerGraph(load, MachineRepresentation::kWord64);
}
+
+TEST_F(Int64LoweringTest, WasmBigIntSpecialCaseBigIntToI64) {
+ Node* target = Int32Constant(1);
+ Node* context = Int32Constant(2);
+ Node* bigint = Int32Constant(4);
+
+ CallDescriptor* bigint_to_i64_call_descriptor =
+ Linkage::GetStubCallDescriptor(
+ zone(), // zone
+ BigIntToI64Descriptor(), // descriptor
+ BigIntToI64Descriptor()
+ .GetStackParameterCount(), // stack parameter count
+ CallDescriptor::kNoFlags, // flags
+ Operator::kNoProperties, // properties
+ StubCallMode::kCallCodeObject); // stub call mode
+
+ CallDescriptor* bigint_to_i32_pair_call_descriptor =
+ Linkage::GetStubCallDescriptor(
+ zone(), // zone
+ BigIntToI32PairDescriptor(), // descriptor
+ BigIntToI32PairDescriptor()
+ .GetStackParameterCount(), // stack parameter count
+ CallDescriptor::kNoFlags, // flags
+ Operator::kNoProperties, // properties
+ StubCallMode::kCallCodeObject); // stub call mode
+
+ auto lowering_special_case = base::make_unique<Int64LoweringSpecialCase>();
+ lowering_special_case->bigint_to_i64_call_descriptor =
+ bigint_to_i64_call_descriptor;
+ lowering_special_case->bigint_to_i32_pair_call_descriptor =
+ bigint_to_i32_pair_call_descriptor;
+
+ Node* call_node =
+ graph()->NewNode(common()->Call(bigint_to_i64_call_descriptor), target,
+ bigint, context, start(), start());
+
+ LowerGraphWithSpecialCase(call_node, std::move(lowering_special_case),
+ MachineRepresentation::kWord64);
+
+ Capture<Node*> call;
+ Matcher<Node*> call_matcher =
+ IsCall(bigint_to_i32_pair_call_descriptor, target, bigint, context,
+ start(), start());
+
+ EXPECT_THAT(graph()->end()->InputAt(1),
+ IsReturn2(IsProjection(0, AllOf(CaptureEq(&call), call_matcher)),
+ IsProjection(1, AllOf(CaptureEq(&call), call_matcher)),
+ start(), start()));
+}
+
+TEST_F(Int64LoweringTest, WasmBigIntSpecialCaseI64ToBigInt) {
+ Node* target = Int32Constant(1);
+ Node* i64 = Int64Constant(value(0));
+
+ CallDescriptor* i64_to_bigint_call_descriptor =
+ Linkage::GetStubCallDescriptor(
+ zone(), // zone
+ I64ToBigIntDescriptor(), // descriptor
+ I64ToBigIntDescriptor()
+ .GetStackParameterCount(), // stack parameter count
+ CallDescriptor::kNoFlags, // flags
+ Operator::kNoProperties, // properties
+ StubCallMode::kCallCodeObject); // stub call mode
+
+ CallDescriptor* i32_pair_to_bigint_call_descriptor =
+ Linkage::GetStubCallDescriptor(
+ zone(), // zone
+ I32PairToBigIntDescriptor(), // descriptor
+ I32PairToBigIntDescriptor()
+ .GetStackParameterCount(), // stack parameter count
+ CallDescriptor::kNoFlags, // flags
+ Operator::kNoProperties, // properties
+ StubCallMode::kCallCodeObject); // stub call mode
+
+ auto lowering_special_case = base::make_unique<Int64LoweringSpecialCase>();
+ lowering_special_case->i64_to_bigint_call_descriptor =
+ i64_to_bigint_call_descriptor;
+ lowering_special_case->i32_pair_to_bigint_call_descriptor =
+ i32_pair_to_bigint_call_descriptor;
+
+ Node* call = graph()->NewNode(common()->Call(i64_to_bigint_call_descriptor),
+ target, i64, start(), start());
+
+ LowerGraphWithSpecialCase(call, std::move(lowering_special_case),
+ MachineRepresentation::kTaggedPointer);
+
+ EXPECT_THAT(
+ graph()->end()->InputAt(1),
+ IsReturn(IsCall(i32_pair_to_bigint_call_descriptor, target,
+ IsInt32Constant(low_word_value(0)),
+ IsInt32Constant(high_word_value(0)), start(), start()),
+ start(), start()));
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/unittests/compiler/js-call-reducer-unittest.cc b/deps/v8/test/unittests/compiler/js-call-reducer-unittest.cc
index 3d4e16ac68..7c062698c4 100644
--- a/deps/v8/test/unittests/compiler/js-call-reducer-unittest.cc
+++ b/deps/v8/test/unittests/compiler/js-call-reducer-unittest.cc
@@ -6,6 +6,7 @@
#include "src/codegen/tick-counter.h"
#include "src/compiler/compilation-dependencies.h"
+#include "src/compiler/feedback-source.h"
#include "src/compiler/js-call-reducer.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/simplified-operator.h"
@@ -23,7 +24,6 @@ class JSCallReducerTest : public TypedGraphTest {
public:
JSCallReducerTest()
: TypedGraphTest(3), javascript_(zone()), deps_(broker(), zone()) {
- broker()->SerializeStandardObjects();
}
~JSCallReducerTest() override = default;
@@ -113,7 +113,7 @@ class JSCallReducerTest : public TypedGraphTest {
ClosureFeedbackCellArray::New(isolate(), shared);
Handle<FeedbackVector> vector =
FeedbackVector::New(isolate(), shared, closure_feedback_cell_array);
- VectorSlotPair feedback(vector, FeedbackSlot(0), UNINITIALIZED);
+ FeedbackSource feedback(vector, FeedbackSlot(0));
return javascript()->Call(arity, CallFrequency(), feedback,
ConvertReceiverMode::kAny,
SpeculationMode::kAllowSpeculation);
diff --git a/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc
index 95c03e543f..fb5254903d 100644
--- a/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc
+++ b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc
@@ -172,7 +172,8 @@ TEST_F(JSCreateLoweringTest, JSCreateFunctionContextViaInlinedAllocation) {
// JSCreateWithContext
TEST_F(JSCreateLoweringTest, JSCreateWithContext) {
- Handle<ScopeInfo> scope_info = ScopeInfo::CreateForEmptyFunction(isolate());
+ Handle<ScopeInfo> scope_info =
+ ReadOnlyRoots(isolate()).empty_function_scope_info_handle();
Node* const object = Parameter(Type::Receiver());
Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start();
@@ -192,7 +193,8 @@ TEST_F(JSCreateLoweringTest, JSCreateWithContext) {
// JSCreateCatchContext
TEST_F(JSCreateLoweringTest, JSCreateCatchContext) {
- Handle<ScopeInfo> scope_info = ScopeInfo::CreateForEmptyFunction(isolate());
+ Handle<ScopeInfo> scope_info =
+ ReadOnlyRoots(isolate()).empty_function_scope_info_handle();
Node* const exception = Parameter(Type::Receiver());
Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start();
diff --git a/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc
index 3510cd4b74..5b4088f28e 100644
--- a/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc
+++ b/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc
@@ -37,7 +37,7 @@ class JSIntrinsicLoweringTest : public GraphTest {
&machine);
// TODO(titzer): mock the GraphReducer here for better unit testing.
GraphReducer graph_reducer(zone(), graph(), tick_counter());
- JSIntrinsicLowering reducer(&graph_reducer, &jsgraph);
+ JSIntrinsicLowering reducer(&graph_reducer, &jsgraph, broker());
return reducer.Reduce(node);
}
diff --git a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc
index 0d7bb946e3..0d85253847 100644
--- a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc
+++ b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc
@@ -322,12 +322,13 @@ TEST_F(JSTypedLoweringTest, JSLoadContext) {
Reduction const r2 = Reduce(graph()->NewNode(
javascript()->LoadContext(1, index, immutable), context, effect));
ASSERT_TRUE(r2.Changed());
- EXPECT_THAT(r2.replacement(),
- IsLoadField(AccessBuilder::ForContextSlot(index),
- IsLoadField(AccessBuilder::ForContextSlot(
- Context::PREVIOUS_INDEX),
- context, effect, graph()->start()),
- _, graph()->start()));
+ EXPECT_THAT(
+ r2.replacement(),
+ IsLoadField(AccessBuilder::ForContextSlot(index),
+ IsLoadField(AccessBuilder::ForContextSlotKnownPointer(
+ Context::PREVIOUS_INDEX),
+ context, effect, graph()->start()),
+ _, graph()->start()));
}
}
}
@@ -357,12 +358,13 @@ TEST_F(JSTypedLoweringTest, JSStoreContext) {
Reduce(graph()->NewNode(javascript()->StoreContext(1, index), value,
context, effect, control));
ASSERT_TRUE(r2.Changed());
- EXPECT_THAT(r2.replacement(),
- IsStoreField(AccessBuilder::ForContextSlot(index),
- IsLoadField(AccessBuilder::ForContextSlot(
- Context::PREVIOUS_INDEX),
- context, effect, graph()->start()),
- value, _, control));
+ EXPECT_THAT(
+ r2.replacement(),
+ IsStoreField(AccessBuilder::ForContextSlot(index),
+ IsLoadField(AccessBuilder::ForContextSlotKnownPointer(
+ Context::PREVIOUS_INDEX),
+ context, effect, graph()->start()),
+ value, _, control));
}
}
}
@@ -373,7 +375,7 @@ TEST_F(JSTypedLoweringTest, JSStoreContext) {
TEST_F(JSTypedLoweringTest, JSLoadNamedStringLength) {
- VectorSlotPair feedback;
+ FeedbackSource feedback;
Handle<Name> name = factory()->length_string();
Node* const receiver = Parameter(Type::String(), 0);
Node* const context = UndefinedConstant();
diff --git a/deps/v8/test/unittests/compiler/linkage-tail-call-unittest.cc b/deps/v8/test/unittests/compiler/linkage-tail-call-unittest.cc
index 17dc998f6d..d86771a8c3 100644
--- a/deps/v8/test/unittests/compiler/linkage-tail-call-unittest.cc
+++ b/deps/v8/test/unittests/compiler/linkage-tail-call-unittest.cc
@@ -55,8 +55,8 @@ TEST_F(LinkageTailCall, EmptyToEmpty) {
CommonOperatorBuilder common(zone());
const Operator* op = common.Call(desc);
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
- EXPECT_TRUE(desc->CanTailCall(node));
const CallDescriptor* callee = CallDescriptorOf(node->op());
+ EXPECT_TRUE(desc->CanTailCall(callee));
int stack_param_delta = callee->GetStackParameterDelta(desc);
EXPECT_EQ(0, stack_param_delta);
}
@@ -74,7 +74,7 @@ TEST_F(LinkageTailCall, SameReturn) {
CommonOperatorBuilder common(zone());
const Operator* op = common.Call(desc2);
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
EXPECT_EQ(0, stack_param_delta);
}
@@ -94,7 +94,7 @@ TEST_F(LinkageTailCall, DifferingReturn) {
CommonOperatorBuilder common(zone());
const Operator* op = common.Call(desc2);
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
- EXPECT_TRUE(!desc1->CanTailCall(node));
+ EXPECT_FALSE(desc1->CanTailCall(CallDescriptorOf(node->op())));
}
@@ -113,7 +113,7 @@ TEST_F(LinkageTailCall, MoreRegisterParametersCallee) {
CommonOperatorBuilder common(zone());
const Operator* op = common.Call(desc2);
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
EXPECT_EQ(0, stack_param_delta);
}
@@ -134,7 +134,7 @@ TEST_F(LinkageTailCall, MoreRegisterParametersCaller) {
CommonOperatorBuilder common(zone());
const Operator* op = common.Call(desc2);
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
EXPECT_EQ(0, stack_param_delta);
}
@@ -155,7 +155,7 @@ TEST_F(LinkageTailCall, MoreRegisterAndStackParametersCallee) {
CommonOperatorBuilder common(zone());
const Operator* op = common.Call(desc2);
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
// We might need to add one slot of padding to the callee arguments.
int expected = kPadArguments ? 2 : 1;
@@ -178,7 +178,7 @@ TEST_F(LinkageTailCall, MoreRegisterAndStackParametersCaller) {
CommonOperatorBuilder common(zone());
const Operator* op = common.Call(desc2);
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
// We might need to drop one slot of padding from the caller's arguments.
int expected = kPadArguments ? -2 : -1;
@@ -206,7 +206,7 @@ TEST_F(LinkageTailCall, MatchingStackParameters) {
const Operator* op = common.Call(desc2);
Node* const node =
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
EXPECT_EQ(0, stack_param_delta);
}
@@ -232,7 +232,7 @@ TEST_F(LinkageTailCall, NonMatchingStackParameters) {
const Operator* op = common.Call(desc2);
Node* const node =
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
EXPECT_EQ(0, stack_param_delta);
}
@@ -259,7 +259,7 @@ TEST_F(LinkageTailCall, MatchingStackParametersExtraCallerRegisters) {
const Operator* op = common.Call(desc2);
Node* const node =
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
EXPECT_EQ(0, stack_param_delta);
}
@@ -287,7 +287,7 @@ TEST_F(LinkageTailCall, MatchingStackParametersExtraCalleeRegisters) {
const Operator* op = common.Call(desc2);
Node* const node =
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
EXPECT_EQ(0, stack_param_delta);
}
@@ -315,7 +315,7 @@ TEST_F(LinkageTailCall, MatchingStackParametersExtraCallerRegistersAndStack) {
const Operator* op = common.Call(desc2);
Node* const node =
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
// We might need to add one slot of padding to the callee arguments.
int expected = kPadArguments ? 0 : -1;
@@ -345,7 +345,7 @@ TEST_F(LinkageTailCall, MatchingStackParametersExtraCalleeRegistersAndStack) {
const Operator* op = common.Call(desc2);
Node* const node =
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
- EXPECT_TRUE(desc1->CanTailCall(node));
+ EXPECT_TRUE(desc1->CanTailCall(CallDescriptorOf(node->op())));
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
// We might need to drop one slot of padding from the caller's arguments.
int expected = kPadArguments ? 0 : 1;
diff --git a/deps/v8/test/unittests/compiler/machine-operator-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-unittest.cc
index 24fc6a31c7..d0acbf341c 100644
--- a/deps/v8/test/unittests/compiler/machine-operator-unittest.cc
+++ b/deps/v8/test/unittests/compiler/machine-operator-unittest.cc
@@ -245,7 +245,7 @@ const PureOperator kPureOperators[] = {
PURE(Float64Equal, 2, 0, 1), // --
PURE(Float64LessThan, 2, 0, 1), // --
PURE(Float64LessThanOrEqual, 2, 0, 1), // --
- PURE(LoadStackPointer, 0, 0, 1), // --
+ PURE(StackPointerGreaterThan, 1, 0, 1), // --
PURE(Float64ExtractLowWord32, 1, 0, 1), // --
PURE(Float64ExtractHighWord32, 1, 0, 1), // --
PURE(Float64InsertLowWord32, 2, 0, 1), // --
diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc
index fc6f1d5500..6fa4ce0cf0 100644
--- a/deps/v8/test/unittests/compiler/node-test-utils.cc
+++ b/deps/v8/test/unittests/compiler/node-test-utils.cc
@@ -2204,6 +2204,7 @@ IS_UNOP_MATCHER(ChangeInt32ToInt64)
IS_UNOP_MATCHER(ChangeUint32ToFloat64)
IS_UNOP_MATCHER(ChangeUint32ToUint64)
IS_UNOP_MATCHER(ChangeCompressedToTagged)
+IS_UNOP_MATCHER(ChangeCompressedPointerToTaggedPointer)
IS_UNOP_MATCHER(TruncateFloat64ToFloat32)
IS_UNOP_MATCHER(TruncateInt64ToInt32)
IS_UNOP_MATCHER(Float32Abs)
diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h
index be8d67cb35..a71aff913b 100644
--- a/deps/v8/test/unittests/compiler/node-test-utils.h
+++ b/deps/v8/test/unittests/compiler/node-test-utils.h
@@ -427,6 +427,8 @@ Matcher<Node*> IsChangeInt32ToInt64(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsChangeUint32ToFloat64(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsChangeUint32ToUint64(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsChangeCompressedToTagged(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeCompressedPointerToTaggedPointer(
+ const Matcher<Node*>& input_matcher);
Matcher<Node*> IsTruncateFloat64ToFloat32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsTruncateInt64ToInt32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsFloat32Abs(const Matcher<Node*>& input_matcher);
diff --git a/deps/v8/test/unittests/compiler/redundancy-elimination-unittest.cc b/deps/v8/test/unittests/compiler/redundancy-elimination-unittest.cc
index 76fbc4a368..9655fc70b2 100644
--- a/deps/v8/test/unittests/compiler/redundancy-elimination-unittest.cc
+++ b/deps/v8/test/unittests/compiler/redundancy-elimination-unittest.cc
@@ -5,6 +5,7 @@
#include "src/compiler/redundancy-elimination.h"
#include "src/codegen/tick-counter.h"
#include "src/compiler/common-operator.h"
+#include "src/compiler/feedback-source.h"
#include "test/unittests/compiler/graph-reducer-unittest.h"
#include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h"
@@ -40,26 +41,24 @@ class RedundancyEliminationTest : public GraphTest {
ClosureFeedbackCellArray::New(isolate(), shared);
Handle<FeedbackVector> feedback_vector =
FeedbackVector::New(isolate(), shared, closure_feedback_cell_array);
- vector_slot_pairs_.push_back(VectorSlotPair());
- vector_slot_pairs_.push_back(
- VectorSlotPair(feedback_vector, slot1, UNINITIALIZED));
- vector_slot_pairs_.push_back(
- VectorSlotPair(feedback_vector, slot2, UNINITIALIZED));
+ vector_slot_pairs_.push_back(FeedbackSource());
+ vector_slot_pairs_.push_back(FeedbackSource(feedback_vector, slot1));
+ vector_slot_pairs_.push_back(FeedbackSource(feedback_vector, slot2));
}
~RedundancyEliminationTest() override = default;
protected:
Reduction Reduce(Node* node) { return reducer_.Reduce(node); }
- std::vector<VectorSlotPair> const& vector_slot_pairs() const {
+ std::vector<FeedbackSource> const& vector_slot_pairs() const {
return vector_slot_pairs_;
}
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
private:
NiceMock<MockAdvancedReducerEditor> editor_;
- std::vector<VectorSlotPair> vector_slot_pairs_;
- VectorSlotPair feedback2_;
+ std::vector<FeedbackSource> vector_slot_pairs_;
+ FeedbackSource feedback2_;
RedundancyElimination reducer_;
SimplifiedOperatorBuilder simplified_;
};
@@ -88,8 +87,8 @@ const NumberOperationHint kNumberOperationHints[] = {
// CheckBounds
TEST_F(RedundancyEliminationTest, CheckBounds) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* index = Parameter(0);
Node* length = Parameter(1);
Node* effect = graph()->start();
@@ -114,8 +113,8 @@ TEST_F(RedundancyEliminationTest, CheckBounds) {
// CheckNumber
TEST_F(RedundancyEliminationTest, CheckNumberSubsumedByCheckSmi) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -201,7 +200,7 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
CheckStringSubsumedByCheckInternalizedString) {
- TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -245,8 +244,8 @@ TEST_F(RedundancyEliminationTest, CheckSymbol) {
// CheckedFloat64ToInt32
TEST_F(RedundancyEliminationTest, CheckedFloat64ToInt32) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
Node* value = Parameter(0);
Node* effect = graph()->start();
@@ -274,8 +273,8 @@ TEST_F(RedundancyEliminationTest, CheckedFloat64ToInt32) {
// CheckedFloat64ToInt64
TEST_F(RedundancyEliminationTest, CheckedFloat64ToInt64) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
Node* value = Parameter(0);
Node* effect = graph()->start();
@@ -306,8 +305,8 @@ TEST_F(RedundancyEliminationTest, CheckedInt32ToCompressedSigned) {
if (!COMPRESS_POINTERS_BOOL) {
return;
}
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -333,8 +332,8 @@ TEST_F(RedundancyEliminationTest, CheckedInt32ToCompressedSigned) {
// CheckedInt32ToTaggedSigned
TEST_F(RedundancyEliminationTest, CheckedInt32ToTaggedSigned) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -360,8 +359,8 @@ TEST_F(RedundancyEliminationTest, CheckedInt32ToTaggedSigned) {
// CheckedInt64ToInt32
TEST_F(RedundancyEliminationTest, CheckedInt64ToInt32) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -385,8 +384,8 @@ TEST_F(RedundancyEliminationTest, CheckedInt64ToInt32) {
// CheckedInt64ToTaggedSigned
TEST_F(RedundancyEliminationTest, CheckedInt64ToTaggedSigned) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -412,8 +411,8 @@ TEST_F(RedundancyEliminationTest, CheckedInt64ToTaggedSigned) {
// CheckedTaggedSignedToInt32
TEST_F(RedundancyEliminationTest, CheckedTaggedSignedToInt32) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -439,8 +438,8 @@ TEST_F(RedundancyEliminationTest, CheckedTaggedSignedToInt32) {
// CheckedTaggedToFloat64
TEST_F(RedundancyEliminationTest, CheckedTaggedToFloat64) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
TRACED_FOREACH(CheckTaggedInputMode, mode, kCheckTaggedInputModes) {
Node* value = Parameter(0);
Node* effect = graph()->start();
@@ -466,8 +465,8 @@ TEST_F(RedundancyEliminationTest, CheckedTaggedToFloat64) {
TEST_F(RedundancyEliminationTest,
CheckedTaggedToFloat64SubsubmedByCheckedTaggedToFloat64) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -497,8 +496,8 @@ TEST_F(RedundancyEliminationTest,
// CheckedTaggedToInt32
TEST_F(RedundancyEliminationTest, CheckedTaggedToInt32) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
Node* value = Parameter(0);
Node* effect = graph()->start();
@@ -524,8 +523,8 @@ TEST_F(RedundancyEliminationTest, CheckedTaggedToInt32) {
TEST_F(RedundancyEliminationTest,
CheckedTaggedToInt32SubsumedByCheckedTaggedSignedToInt32) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
Node* value = Parameter(0);
Node* effect = graph()->start();
@@ -553,8 +552,8 @@ TEST_F(RedundancyEliminationTest,
// CheckedTaggedToInt64
TEST_F(RedundancyEliminationTest, CheckedTaggedToInt64) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) {
Node* value = Parameter(0);
Node* effect = graph()->start();
@@ -582,8 +581,8 @@ TEST_F(RedundancyEliminationTest, CheckedTaggedToInt64) {
// CheckedTaggedToTaggedPointer
TEST_F(RedundancyEliminationTest, CheckedTaggedToTaggedPointer) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -609,8 +608,8 @@ TEST_F(RedundancyEliminationTest, CheckedTaggedToTaggedPointer) {
// CheckedTaggedToTaggedSigned
TEST_F(RedundancyEliminationTest, CheckedTaggedToTaggedSigned) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -636,8 +635,8 @@ TEST_F(RedundancyEliminationTest, CheckedTaggedToTaggedSigned) {
// CheckedCompressedToTaggedPointer
TEST_F(RedundancyEliminationTest, CheckedCompressedToTaggedPointer) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -663,8 +662,8 @@ TEST_F(RedundancyEliminationTest, CheckedCompressedToTaggedPointer) {
// CheckedCompressedToTaggedSigned
TEST_F(RedundancyEliminationTest, CheckedCompressedToTaggedSigned) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -690,8 +689,8 @@ TEST_F(RedundancyEliminationTest, CheckedCompressedToTaggedSigned) {
// CheckedTaggedToCompressedPointer
TEST_F(RedundancyEliminationTest, CheckedTaggedToCompressedPointer) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -717,8 +716,8 @@ TEST_F(RedundancyEliminationTest, CheckedTaggedToCompressedPointer) {
// CheckedTaggedToCompressedSigned
TEST_F(RedundancyEliminationTest, CheckedTaggedToCompressedSigned) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -744,8 +743,8 @@ TEST_F(RedundancyEliminationTest, CheckedTaggedToCompressedSigned) {
// CheckedTruncateTaggedToWord32
TEST_F(RedundancyEliminationTest, CheckedTruncateTaggedToWord32) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
TRACED_FOREACH(CheckTaggedInputMode, mode, kCheckTaggedInputModes) {
Node* value = Parameter(0);
Node* effect = graph()->start();
@@ -771,8 +770,8 @@ TEST_F(RedundancyEliminationTest, CheckedTruncateTaggedToWord32) {
TEST_F(RedundancyEliminationTest,
CheckedTruncateTaggedToWord32SubsumedByCheckedTruncateTaggedToWord32) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -802,8 +801,8 @@ TEST_F(RedundancyEliminationTest,
// CheckedUint32Bounds
TEST_F(RedundancyEliminationTest, CheckedUint32Bounds) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* index = Parameter(0);
Node* length = Parameter(1);
Node* effect = graph()->start();
@@ -832,8 +831,8 @@ TEST_F(RedundancyEliminationTest, CheckedUint32Bounds) {
// CheckedUint32ToInt32
TEST_F(RedundancyEliminationTest, CheckedUint32ToInt32) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -859,8 +858,8 @@ TEST_F(RedundancyEliminationTest, CheckedUint32ToInt32) {
// CheckedUint32ToTaggedSigned
TEST_F(RedundancyEliminationTest, CheckedUint32ToTaggedSigned) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -886,8 +885,8 @@ TEST_F(RedundancyEliminationTest, CheckedUint32ToTaggedSigned) {
// CheckedUint64Bounds
TEST_F(RedundancyEliminationTest, CheckedUint64Bounds) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* index = Parameter(0);
Node* length = Parameter(1);
Node* effect = graph()->start();
@@ -914,8 +913,8 @@ TEST_F(RedundancyEliminationTest, CheckedUint64Bounds) {
// CheckedUint64ToInt32
TEST_F(RedundancyEliminationTest, CheckedUint64ToInt32) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -941,8 +940,8 @@ TEST_F(RedundancyEliminationTest, CheckedUint64ToInt32) {
// CheckedUint64ToTaggedSigned
TEST_F(RedundancyEliminationTest, CheckedUint64ToTaggedSigned) {
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* value = Parameter(0);
Node* effect = graph()->start();
Node* control = graph()->start();
@@ -970,8 +969,8 @@ TEST_F(RedundancyEliminationTest, CheckedUint64ToTaggedSigned) {
TEST_F(RedundancyEliminationTest,
SpeculativeNumberEqualWithCheckBoundsBetterType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* lhs = Parameter(Type::Any(), 0);
Node* rhs = Parameter(Type::Any(), 1);
Node* length = Parameter(Type::Unsigned31(), 2);
@@ -1006,8 +1005,8 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeNumberEqualWithCheckBoundsSameType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* lhs = Parameter(Type::UnsignedSmall(), 0);
Node* rhs = Parameter(Type::UnsignedSmall(), 1);
Node* length = Parameter(Type::Unsigned31(), 2);
@@ -1045,8 +1044,8 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeNumberLessThanWithCheckBoundsBetterType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* lhs = Parameter(Type::Any(), 0);
Node* rhs = Parameter(Type::Any(), 1);
Node* length = Parameter(Type::Unsigned31(), 2);
@@ -1081,8 +1080,8 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeNumberLessThanWithCheckBoundsSameType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* lhs = Parameter(Type::UnsignedSmall(), 0);
Node* rhs = Parameter(Type::UnsignedSmall(), 1);
Node* length = Parameter(Type::Unsigned31(), 2);
@@ -1120,8 +1119,8 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeNumberLessThanOrEqualWithCheckBoundsBetterType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* lhs = Parameter(Type::Any(), 0);
Node* rhs = Parameter(Type::Any(), 1);
Node* length = Parameter(Type::Unsigned31(), 2);
@@ -1156,8 +1155,8 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeNumberLessThanOrEqualWithCheckBoundsSameType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
Node* lhs = Parameter(Type::UnsignedSmall(), 0);
Node* rhs = Parameter(Type::UnsignedSmall(), 1);
Node* length = Parameter(Type::Unsigned31(), 2);
@@ -1195,7 +1194,7 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeNumberAddWithCheckBoundsBetterType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* lhs = Parameter(Type::Any(), 0);
Node* rhs = Parameter(Type::Any(), 1);
@@ -1221,7 +1220,7 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest, SpeculativeNumberAddWithCheckBoundsSameType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0);
Node* rhs = Parameter(Type::Any(), 0);
@@ -1251,7 +1250,7 @@ TEST_F(RedundancyEliminationTest, SpeculativeNumberAddWithCheckBoundsSameType) {
TEST_F(RedundancyEliminationTest,
SpeculativeNumberSubtractWithCheckBoundsBetterType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* lhs = Parameter(Type::Any(), 0);
Node* rhs = Parameter(Type::Any(), 1);
@@ -1279,7 +1278,7 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeNumberSubtractWithCheckBoundsSameType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0);
Node* rhs = Parameter(Type::Any(), 0);
@@ -1310,7 +1309,7 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeSafeIntegerAddWithCheckBoundsBetterType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* lhs = Parameter(Type::Any(), 0);
Node* rhs = Parameter(Type::Any(), 1);
@@ -1338,7 +1337,7 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeSafeIntegerAddWithCheckBoundsSameType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0);
Node* rhs = Parameter(Type::Any(), 0);
@@ -1369,7 +1368,7 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeSafeIntegerSubtractWithCheckBoundsBetterType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* lhs = Parameter(Type::Any(), 0);
Node* rhs = Parameter(Type::Any(), 1);
@@ -1397,7 +1396,7 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeSafeIntegerSubtractWithCheckBoundsSameType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0);
Node* rhs = Parameter(Type::Any(), 0);
@@ -1428,8 +1427,8 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest,
SpeculativeToNumberWithCheckBoundsBetterType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* index = Parameter(Type::Any(), 0);
Node* length = Parameter(Type::Unsigned31(), 1);
@@ -1456,8 +1455,8 @@ TEST_F(RedundancyEliminationTest,
TEST_F(RedundancyEliminationTest, SpeculativeToNumberWithCheckBoundsSameType) {
Typer typer(broker(), Typer::kNoFlags, graph(), tick_counter());
- TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) {
- TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback1, vector_slot_pairs()) {
+ TRACED_FOREACH(FeedbackSource, feedback2, vector_slot_pairs()) {
TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) {
Node* index = Parameter(Type::Range(42.0, 42.0, zone()), 0);
Node* length = Parameter(Type::Unsigned31(), 1);
diff --git a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc
index b198592ddd..e2d4f080f5 100644
--- a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc
+++ b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc
@@ -360,7 +360,7 @@ TEST_F(SimplifiedOperatorReducerTest, CheckedFloat64ToInt32WithConstant) {
TRACED_FOREACH(int32_t, n, kInt32Values) {
Reduction r = Reduce(graph()->NewNode(
simplified()->CheckedFloat64ToInt32(
- CheckForMinusZeroMode::kDontCheckForMinusZero, VectorSlotPair()),
+ CheckForMinusZeroMode::kDontCheckForMinusZero, FeedbackSource()),
Float64Constant(n), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsInt32Constant(n));
@@ -418,7 +418,7 @@ TEST_F(SimplifiedOperatorReducerTest, CheckSmiWithChangeInt31ToTaggedSigned) {
Node* value =
graph()->NewNode(simplified()->ChangeInt31ToTaggedSigned(), param0);
Reduction reduction = Reduce(graph()->NewNode(
- simplified()->CheckSmi(VectorSlotPair()), value, effect, control));
+ simplified()->CheckSmi(FeedbackSource()), value, effect, control));
ASSERT_TRUE(reduction.Changed());
EXPECT_EQ(value, reduction.replacement());
}
@@ -428,7 +428,7 @@ TEST_F(SimplifiedOperatorReducerTest, CheckSmiWithNumberConstant) {
Node* control = graph()->start();
Node* value = NumberConstant(1.0);
Reduction reduction = Reduce(graph()->NewNode(
- simplified()->CheckSmi(VectorSlotPair()), value, effect, control));
+ simplified()->CheckSmi(FeedbackSource()), value, effect, control));
ASSERT_TRUE(reduction.Changed());
EXPECT_EQ(value, reduction.replacement());
}
@@ -438,9 +438,9 @@ TEST_F(SimplifiedOperatorReducerTest, CheckSmiWithCheckSmi) {
Node* effect = graph()->start();
Node* control = graph()->start();
Node* value = effect = graph()->NewNode(
- simplified()->CheckSmi(VectorSlotPair()), param0, effect, control);
+ simplified()->CheckSmi(FeedbackSource()), param0, effect, control);
Reduction reduction = Reduce(graph()->NewNode(
- simplified()->CheckSmi(VectorSlotPair()), value, effect, control));
+ simplified()->CheckSmi(FeedbackSource()), value, effect, control));
ASSERT_TRUE(reduction.Changed());
EXPECT_EQ(value, reduction.replacement());
}
diff --git a/deps/v8/test/unittests/compiler/typer-unittest.cc b/deps/v8/test/unittests/compiler/typer-unittest.cc
index ec68993213..23e4dbe5ae 100644
--- a/deps/v8/test/unittests/compiler/typer-unittest.cc
+++ b/deps/v8/test/unittests/compiler/typer-unittest.cc
@@ -463,7 +463,7 @@ TEST_MONOTONICITY(Add)
#undef TEST_MONOTONICITY
TEST_F(TyperTest, Monotonicity_InstanceOf) {
- TestBinaryMonotonicity(javascript_.InstanceOf(VectorSlotPair()));
+ TestBinaryMonotonicity(javascript_.InstanceOf(FeedbackSource()));
}
// JS BINOPS without hint
diff --git a/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc
index f8e3e26aa9..a62e824600 100644
--- a/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc
+++ b/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc
@@ -1718,58 +1718,6 @@ TEST_F(InstructionSelectorTest, LoadAndWord64ShiftRight32) {
}
}
-TEST_F(InstructionSelectorTest, StackCheck0) {
- ExternalReference js_stack_limit =
- ExternalReference::Create(isolate()->stack_guard()->address_of_jslimit());
- StreamBuilder m(this, MachineType::Int32());
- Node* const sp = m.LoadStackPointer();
- Node* const stack_limit =
- m.Load(MachineType::Pointer(), m.ExternalConstant(js_stack_limit));
- Node* const interrupt = m.UintPtrLessThan(sp, stack_limit);
-
- RawMachineLabel if_true, if_false;
- m.Branch(interrupt, &if_true, &if_false);
-
- m.Bind(&if_true);
- m.Return(m.Int32Constant(1));
-
- m.Bind(&if_false);
- m.Return(m.Int32Constant(0));
-
- Stream s = m.Build();
-
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kX64Cmp, s[0]->arch_opcode());
- EXPECT_EQ(4U, s[0]->InputCount());
- EXPECT_EQ(0U, s[0]->OutputCount());
-}
-
-TEST_F(InstructionSelectorTest, StackCheck1) {
- ExternalReference js_stack_limit =
- ExternalReference::Create(isolate()->stack_guard()->address_of_jslimit());
- StreamBuilder m(this, MachineType::Int32());
- Node* const sp = m.LoadStackPointer();
- Node* const stack_limit =
- m.Load(MachineType::Pointer(), m.ExternalConstant(js_stack_limit));
- Node* const sp_within_limit = m.UintPtrLessThan(stack_limit, sp);
-
- RawMachineLabel if_true, if_false;
- m.Branch(sp_within_limit, &if_true, &if_false);
-
- m.Bind(&if_true);
- m.Return(m.Int32Constant(1));
-
- m.Bind(&if_false);
- m.Return(m.Int32Constant(0));
-
- Stream s = m.Build();
-
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kX64StackCheck, s[0]->arch_opcode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(0U, s[0]->OutputCount());
-}
-
} // namespace compiler
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/unittests/date/date-cache-unittest.cc b/deps/v8/test/unittests/date/date-cache-unittest.cc
index 2ceaaebabb..2c252424e7 100644
--- a/deps/v8/test/unittests/date/date-cache-unittest.cc
+++ b/deps/v8/test/unittests/date/date-cache-unittest.cc
@@ -69,12 +69,12 @@ TEST(DateCache, AdoptDefaultFirst) {
// We finish all the operation AdoptDefaultThread before
// running all other thread so it won't show the problem of
// AdoptDefault trashing newly create default.
- t1.Start();
+ CHECK(t1.Start());
t1.Join();
- t2.Start();
- t3.Start();
- t4.Start();
+ CHECK(t2.Start());
+ CHECK(t3.Start());
+ CHECK(t4.Start());
t2.Join();
t3.Join();
@@ -92,10 +92,10 @@ TEST(DateCache, AdoptDefaultMixed) {
// it will cause crash in other thread because the TimeZone
// newly created by createDefault could be trashed by AdoptDefault
// while a deleted DEFAULT_ZONE got cloned.
- t1.Start();
- t2.Start();
- t3.Start();
- t4.Start();
+ CHECK(t1.Start());
+ CHECK(t2.Start());
+ CHECK(t3.Start());
+ CHECK(t4.Start());
t1.Join();
t2.Join();
diff --git a/deps/v8/test/unittests/execution/microtask-queue-unittest.cc b/deps/v8/test/unittests/execution/microtask-queue-unittest.cc
index 37b037147b..6cb9df0895 100644
--- a/deps/v8/test/unittests/execution/microtask-queue-unittest.cc
+++ b/deps/v8/test/unittests/execution/microtask-queue-unittest.cc
@@ -377,32 +377,6 @@ TEST_F(MicrotaskQueueTest, DetachGlobal_Run) {
}
}
-TEST_F(MicrotaskQueueTest, DetachGlobal_FinalizationGroup) {
- // Enqueue an FinalizationGroupCleanupTask.
- Handle<JSArray> ran = RunJS<JSArray>(
- "var ran = [false];"
- "var wf = new FinalizationGroup(() => { ran[0] = true; });"
- "(function() { wf.register({}, {}); })();"
- "gc();"
- "ran");
-
- EXPECT_TRUE(
- Object::GetElement(isolate(), ran, 0).ToHandleChecked()->IsFalse());
- EXPECT_EQ(1, microtask_queue()->size());
-
- // Detach MicrotaskQueue from the current context.
- context()->DetachGlobal();
-
- microtask_queue()->RunMicrotasks(isolate());
-
- // RunMicrotasks processes the pending Microtask, but Microtasks that are
- // associated to a detached context should be cancelled and should not take
- // effect.
- EXPECT_EQ(0, microtask_queue()->size());
- EXPECT_TRUE(
- Object::GetElement(isolate(), ran, 0).ToHandleChecked()->IsFalse());
-}
-
namespace {
void DummyPromiseHook(PromiseHookType type, Local<Promise> promise,
diff --git a/deps/v8/test/unittests/heap/barrier-unittest.cc b/deps/v8/test/unittests/heap/barrier-unittest.cc
index 07906b20c1..99cf5d8978 100644
--- a/deps/v8/test/unittests/heap/barrier-unittest.cc
+++ b/deps/v8/test/unittests/heap/barrier-unittest.cc
@@ -57,7 +57,7 @@ TEST(OneshotBarrier, DoneAfterWait_Concurrent) {
barrier.Start();
}
for (int i = 0; i < kThreadCount; i++) {
- threads[i].Start();
+ CHECK(threads[i].Start());
}
for (int i = 0; i < kThreadCount; i++) {
threads[i].Join();
@@ -80,7 +80,7 @@ TEST(OneshotBarrier, EarlyFinish_Concurrent) {
barrier.Start();
}
for (int i = 0; i < kThreadCount; i++) {
- threads[i].Start();
+ CHECK(threads[i].Start());
}
for (int i = 0; i < kThreadCount; i++) {
threads[i].Join();
@@ -133,7 +133,7 @@ TEST(OneshotBarrier, Processing_Concurrent) {
barrier.Start();
barrier.Start();
EXPECT_FALSE(barrier.DoneForTesting());
- counting_thread.Start();
+ CHECK(counting_thread.Start());
for (size_t i = 0; i < kWorkCounter; i++) {
{
diff --git a/deps/v8/test/unittests/heap/gc-tracer-unittest.cc b/deps/v8/test/unittests/heap/gc-tracer-unittest.cc
index 53b919a860..742e86c357 100644
--- a/deps/v8/test/unittests/heap/gc-tracer-unittest.cc
+++ b/deps/v8/test/unittests/heap/gc-tracer-unittest.cc
@@ -355,11 +355,9 @@ TEST_F(GCTracerTest, BackgroundScavengerScope) {
tracer->Start(SCAVENGER, GarbageCollectionReason::kTesting,
"collector unittest");
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL, 10,
- nullptr);
+ GCTracer::BackgroundScope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL, 10);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL, 1,
- nullptr);
+ GCTracer::BackgroundScope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL, 1);
tracer->Stop(SCAVENGER);
EXPECT_DOUBLE_EQ(
11, tracer->current_
@@ -372,20 +370,19 @@ TEST_F(GCTracerTest, BackgroundMinorMCScope) {
tracer->Start(MINOR_MARK_COMPACTOR, GarbageCollectionReason::kTesting,
"collector unittest");
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_MARKING, 10, nullptr);
+ GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_MARKING, 10);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_MARKING, 1, nullptr);
+ GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_MARKING, 1);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_COPY, 20,
- nullptr);
+ GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_COPY, 20);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_COPY, 2, nullptr);
+ GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_COPY, 2);
tracer->AddBackgroundScopeSample(
GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_UPDATE_POINTERS,
- 30, nullptr);
+ 30);
tracer->AddBackgroundScopeSample(
GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_UPDATE_POINTERS,
- 3, nullptr);
+ 3);
tracer->Stop(MINOR_MARK_COMPACTOR);
EXPECT_DOUBLE_EQ(
11,
@@ -402,33 +399,31 @@ TEST_F(GCTracerTest, BackgroundMajorMCScope) {
GCTracer* tracer = i_isolate()->heap()->tracer();
tracer->ResetForTesting();
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, 100, nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, 100);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_SWEEPING, 200, nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_SWEEPING, 200);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, 10, nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, 10);
// Scavenger should not affect the major mark-compact scopes.
tracer->Start(SCAVENGER, GarbageCollectionReason::kTesting,
"collector unittest");
tracer->Stop(SCAVENGER);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_SWEEPING, 20, nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_SWEEPING, 20);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, 1, nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, 1);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_SWEEPING, 2, nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_SWEEPING, 2);
tracer->Start(MARK_COMPACTOR, GarbageCollectionReason::kTesting,
"collector unittest");
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_COPY, 30, nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_COPY, 30);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_COPY, 3, nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_COPY, 3);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_UPDATE_POINTERS, 40,
- nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_UPDATE_POINTERS, 40);
tracer->AddBackgroundScopeSample(
- GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_UPDATE_POINTERS, 4,
- nullptr);
+ GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_UPDATE_POINTERS, 4);
tracer->Stop(MARK_COMPACTOR);
EXPECT_DOUBLE_EQ(
111, tracer->current_.scopes[GCTracer::Scope::MC_BACKGROUND_MARKING]);
@@ -448,7 +443,7 @@ class ThreadWithBackgroundScope final : public base::Thread {
: Thread(Options("ThreadWithBackgroundScope")), tracer_(tracer) {}
void Run() override {
GCTracer::BackgroundScope scope(
- tracer_, GCTracer::BackgroundScope::MC_BACKGROUND_MARKING);
+ tracer_, GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, nullptr);
}
private:
@@ -460,8 +455,8 @@ TEST_F(GCTracerTest, MultithreadedBackgroundScope) {
ThreadWithBackgroundScope thread1(tracer);
ThreadWithBackgroundScope thread2(tracer);
tracer->ResetForTesting();
- thread1.Start();
- thread2.Start();
+ CHECK(thread1.Start());
+ CHECK(thread2.Start());
tracer->FetchBackgroundMarkCompactCounters();
thread1.Join();
thread2.Join();
diff --git a/deps/v8/test/unittests/heap/spaces-unittest.cc b/deps/v8/test/unittests/heap/spaces-unittest.cc
index 140d3d45b3..c5acc6c43e 100644
--- a/deps/v8/test/unittests/heap/spaces-unittest.cc
+++ b/deps/v8/test/unittests/heap/spaces-unittest.cc
@@ -143,5 +143,146 @@ TEST_F(SpacesTest, CodeRangeAddressReuse) {
EXPECT_EQ(code_range6, code_range3);
}
+// Tests that FreeListMany::SelectFreeListCategoryType returns what it should.
+TEST_F(SpacesTest, FreeListManySelectFreeListCategoryType) {
+ FreeListMany free_list;
+
+ // Testing that all sizes below 256 bytes get assigned the correct category
+ for (size_t size = 0; size <= FreeListMany::kPreciseCategoryMaxSize; size++) {
+ FreeListCategoryType cat = free_list.SelectFreeListCategoryType(size);
+ if (cat == 0) {
+ // If cat == 0, then we make sure that |size| doesn't fit in the 2nd
+ // category.
+ EXPECT_LT(size, free_list.categories_min[1]);
+ } else {
+ // Otherwise, size should fit in |cat|, but not in |cat+1|.
+ EXPECT_LE(free_list.categories_min[cat], size);
+ EXPECT_LT(size, free_list.categories_min[cat + 1]);
+ }
+ }
+
+ // Testing every size above 256 would take long time, so test only some
+ // "interesting cases": picking some number in the middle of the categories,
+ // as well as at the categories' bounds.
+ for (int cat = kFirstCategory + 1; cat <= free_list.last_category_; cat++) {
+ std::vector<size_t> sizes;
+ // Adding size less than this category's minimum
+ sizes.push_back(free_list.categories_min[cat] - 8);
+ // Adding size equal to this category's minimum
+ sizes.push_back(free_list.categories_min[cat]);
+ // Adding size greater than this category's minimum
+ sizes.push_back(free_list.categories_min[cat] + 8);
+ // Adding size between this category's minimum and the next category
+ if (cat != free_list.last_category_) {
+ sizes.push_back(
+ (free_list.categories_min[cat] + free_list.categories_min[cat + 1]) /
+ 2);
+ }
+
+ for (size_t size : sizes) {
+ FreeListCategoryType cat = free_list.SelectFreeListCategoryType(size);
+ if (cat == free_list.last_category_) {
+ // If cat == last_category, then we make sure that |size| indeeds fits
+ // in the last category.
+ EXPECT_LE(free_list.categories_min[cat], size);
+ } else {
+ // Otherwise, size should fit in |cat|, but not in |cat+1|.
+ EXPECT_LE(free_list.categories_min[cat], size);
+ EXPECT_LT(size, free_list.categories_min[cat + 1]);
+ }
+ }
+ }
+}
+
+// Tests that FreeListMany::GuaranteedAllocatable returns what it should.
+TEST_F(SpacesTest, FreeListManyGuaranteedAllocatable) {
+ FreeListMany free_list;
+
+ for (int cat = kFirstCategory; cat < free_list.last_category_; cat++) {
+ std::vector<size_t> sizes;
+ // Adding size less than this category's minimum
+ sizes.push_back(free_list.categories_min[cat] - 8);
+ // Adding size equal to this category's minimum
+ sizes.push_back(free_list.categories_min[cat]);
+ // Adding size greater than this category's minimum
+ sizes.push_back(free_list.categories_min[cat] + 8);
+ if (cat != free_list.last_category_) {
+ // Adding size between this category's minimum and the next category
+ sizes.push_back(
+ (free_list.categories_min[cat] + free_list.categories_min[cat + 1]) /
+ 2);
+ }
+
+ for (size_t size : sizes) {
+ FreeListCategoryType cat_free =
+ free_list.SelectFreeListCategoryType(size);
+ size_t guaranteed_allocatable = free_list.GuaranteedAllocatable(size);
+ if (cat_free == free_list.last_category_) {
+ // If |cat_free| == last_category, then guaranteed_allocatable must
+ // return the last category, because when allocating, the last category
+ // is searched entirely.
+ EXPECT_EQ(free_list.SelectFreeListCategoryType(guaranteed_allocatable),
+ free_list.last_category_);
+ } else if (size < free_list.categories_min[0]) {
+ // If size < free_list.categories_min[0], then the bytes are wasted, and
+ // guaranteed_allocatable should return 0.
+ EXPECT_EQ(guaranteed_allocatable, 0ul);
+ } else {
+ // Otherwise, |guaranteed_allocatable| is equal to the minimum of
+ // |size|'s category (|cat_free|);
+ EXPECT_EQ(free_list.categories_min[cat_free], guaranteed_allocatable);
+ }
+ }
+ }
+}
+
+// Tests that
+// FreeListManyCachedFastPath::SelectFastAllocationFreeListCategoryType returns
+// what it should.
+TEST_F(SpacesTest,
+ FreeListManyCachedFastPathSelectFastAllocationFreeListCategoryType) {
+ FreeListManyCachedFastPath free_list;
+
+ for (int cat = kFirstCategory; cat <= free_list.last_category_; cat++) {
+ std::vector<size_t> sizes;
+ // Adding size less than this category's minimum
+ sizes.push_back(free_list.categories_min[cat] - 8);
+ // Adding size equal to this category's minimum
+ sizes.push_back(free_list.categories_min[cat]);
+ // Adding size greater than this category's minimum
+ sizes.push_back(free_list.categories_min[cat] + 8);
+ // Adding size between this category's minimum and the next category
+ if (cat != free_list.last_category_) {
+ sizes.push_back(
+ (free_list.categories_min[cat] + free_list.categories_min[cat + 1]) /
+ 2);
+ }
+
+ for (size_t size : sizes) {
+ FreeListCategoryType cat =
+ free_list.SelectFastAllocationFreeListCategoryType(size);
+ if (size <= FreeListManyCachedFastPath::kTinyObjectMaxSize) {
+ // For tiny objects, the first category of the fast path should be
+ // chosen.
+ EXPECT_TRUE(cat == FreeListManyCachedFastPath::kFastPathFirstCategory);
+ } else if (size >= free_list.categories_min[free_list.last_category_] -
+ FreeListManyCachedFastPath::kFastPathOffset) {
+ // For objects close to the minimum of the last category, the last
+ // category is chosen.
+ EXPECT_EQ(cat, free_list.last_category_);
+ } else {
+ // For other objects, the chosen category must satisfy that its minimum
+ // is at least |size|+1.85k.
+ EXPECT_GE(free_list.categories_min[cat],
+ size + FreeListManyCachedFastPath::kFastPathOffset);
+ // And the smaller categoriy's minimum is less than |size|+1.85k
+ // (otherwise it would have been chosen instead).
+ EXPECT_LT(free_list.categories_min[cat - 1],
+ size + FreeListManyCachedFastPath::kFastPathOffset);
+ }
+ }
+ }
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc
index 3d02db7413..a9c631f8d2 100644
--- a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc
+++ b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc
@@ -151,6 +151,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.StoreNamedOwnProperty(reg, name, store_own_slot.ToInt())
.StoreInArrayLiteral(reg, reg, store_array_element_slot.ToInt());
+ // Emit Iterator-protocol operations
+ builder.GetIterator(reg, load_slot.ToInt());
+
// Emit load / store lookup slots.
builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
.LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF)
@@ -283,7 +286,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
BytecodeLoopHeader loop_header;
BytecodeLabel after_jump1, after_jump2, after_jump3, after_jump4,
after_jump5, after_jump6, after_jump7, after_jump8, after_jump9,
- after_jump10, after_loop;
+ after_jump10, after_jump11, after_loop;
builder.JumpIfNull(&after_loop)
.Bind(&loop_header)
.Jump(&after_jump1)
@@ -296,21 +299,23 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.Bind(&after_jump4)
.JumpIfNotUndefined(&after_jump5)
.Bind(&after_jump5)
- .JumpIfJSReceiver(&after_jump6)
+ .JumpIfUndefinedOrNull(&after_jump6)
.Bind(&after_jump6)
- .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &after_jump7)
+ .JumpIfJSReceiver(&after_jump7)
.Bind(&after_jump7)
- .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &after_jump8)
+ .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &after_jump8)
.Bind(&after_jump8)
- .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &after_jump9)
+ .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &after_jump9)
.Bind(&after_jump9)
- .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &after_jump10)
+ .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &after_jump10)
.Bind(&after_jump10)
+ .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &after_jump11)
+ .Bind(&after_jump11)
.JumpLoop(&loop_header, 0)
.Bind(&after_loop);
}
- BytecodeLabel end[10];
+ BytecodeLabel end[11];
{
// Longer jumps with constant operands
BytecodeLabel after_jump;
@@ -325,8 +330,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.JumpIfNotNull(&end[6])
.JumpIfUndefined(&end[7])
.JumpIfNotUndefined(&end[8])
+ .JumpIfUndefinedOrNull(&end[9])
.LoadLiteral(ast_factory.prototype_string())
- .JumpIfJSReceiver(&end[9]);
+ .JumpIfJSReceiver(&end[10]);
}
// Emit Smi table switch bytecode.
diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-writer-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-writer-unittest.cc
index 6e7b945231..339fc33178 100644
--- a/deps/v8/test/unittests/interpreter/bytecode-array-writer-unittest.cc
+++ b/deps/v8/test/unittests/interpreter/bytecode-array-writer-unittest.cc
@@ -146,6 +146,8 @@ TEST_F(BytecodeArrayWriterUnittest, SimpleExample) {
Handle<BytecodeArray> bytecode_array =
writer()->ToBytecodeArray(isolate(), 0, 0, factory()->empty_byte_array());
+ bytecode_array->set_source_position_table(
+ *writer()->ToSourcePositionTable(isolate()));
CHECK_EQ(bytecodes()->size(), arraysize(expected_bytes));
PositionTableEntry expected_positions[] = {
@@ -236,6 +238,8 @@ TEST_F(BytecodeArrayWriterUnittest, ComplexExample) {
Handle<BytecodeArray> bytecode_array =
writer()->ToBytecodeArray(isolate(), 0, 0, factory()->empty_byte_array());
+ bytecode_array->set_source_position_table(
+ *writer()->ToSourcePositionTable(isolate()));
SourcePositionTableIterator source_iterator(
bytecode_array->SourcePositionTable());
for (size_t i = 0; i < arraysize(expected_positions); ++i) {
@@ -288,6 +292,8 @@ TEST_F(BytecodeArrayWriterUnittest, ElideNoneffectfulBytecodes) {
Handle<BytecodeArray> bytecode_array =
writer()->ToBytecodeArray(isolate(), 0, 0, factory()->empty_byte_array());
+ bytecode_array->set_source_position_table(
+ *writer()->ToSourcePositionTable(isolate()));
SourcePositionTableIterator source_iterator(
bytecode_array->SourcePositionTable());
for (size_t i = 0; i < arraysize(expected_positions); ++i) {
@@ -356,6 +362,8 @@ TEST_F(BytecodeArrayWriterUnittest, DeadcodeElimination) {
Handle<BytecodeArray> bytecode_array =
writer()->ToBytecodeArray(isolate(), 0, 0, factory()->empty_byte_array());
+ bytecode_array->set_source_position_table(
+ *writer()->ToSourcePositionTable(isolate()));
SourcePositionTableIterator source_iterator(
bytecode_array->SourcePositionTable());
for (size_t i = 0; i < arraysize(expected_positions); ++i) {
diff --git a/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.cc b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.cc
index cb9a83997e..a8ff998107 100644
--- a/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.cc
+++ b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.cc
@@ -14,7 +14,9 @@
#include "test/unittests/compiler/node-test-utils.h"
using ::testing::_;
+using ::testing::Eq;
using v8::internal::compiler::Node;
+using v8::internal::compiler::TNode;
namespace c = v8::internal::compiler;
@@ -441,7 +443,7 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) {
InterpreterAssemblerTestState state(this, bytecode);
InterpreterAssemblerForTest m(&state, bytecode);
{
- Node* index = m.IntPtrConstant(2);
+ TNode<IntPtrT> index = m.IntPtrConstant(2);
Node* load_constant = m.LoadConstantPoolEntry(index);
#ifdef V8_COMPRESS_POINTERS
Matcher<Node*> constant_pool_matcher =
@@ -511,16 +513,17 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerTestState state(this, bytecode);
InterpreterAssemblerForTest m(&state, bytecode);
- Node* object = m.IntPtrConstant(0xDEADBEEF);
+ TNode<HeapObject> object =
+ m.ReinterpretCast<HeapObject>(m.IntPtrConstant(0xDEADBEEF));
int offset = 16;
- Node* load_field = m.LoadObjectField(object, offset);
+ TNode<Object> load_field = m.LoadObjectField(object, offset);
#ifdef V8_COMPRESS_POINTERS
EXPECT_THAT(load_field, IsChangeCompressedToTagged(m.IsLoadFromObject(
- MachineType::AnyCompressed(), object,
+ MachineType::AnyCompressed(), Eq(object),
c::IsIntPtrConstant(offset - kHeapObjectTag))));
#else
EXPECT_THAT(load_field, m.IsLoadFromObject(
- MachineType::AnyTagged(), object,
+ MachineType::AnyTagged(), Eq(object),
c::IsIntPtrConstant(offset - kHeapObjectTag)));
#endif
}
@@ -530,12 +533,14 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime2) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerTestState state(this, bytecode);
InterpreterAssemblerForTest m(&state, bytecode);
- Node* arg1 = m.Int32Constant(2);
- Node* arg2 = m.Int32Constant(3);
- Node* context = m.Int32Constant(4);
- Node* call_runtime = m.CallRuntime(Runtime::kAdd, context, arg1, arg2);
- EXPECT_THAT(call_runtime, c::IsCall(_, _, arg1, arg2, _,
- c::IsInt32Constant(2), context, _, _));
+ TNode<Object> arg1 = m.ReinterpretCast<Object>(m.Int32Constant(2));
+ TNode<Object> arg2 = m.ReinterpretCast<Object>(m.Int32Constant(3));
+ TNode<Object> context = m.ReinterpretCast<Object>(m.Int32Constant(4));
+ TNode<Object> call_runtime =
+ m.CallRuntime(Runtime::kAdd, context, arg1, arg2);
+ EXPECT_THAT(call_runtime,
+ c::IsCall(_, _, Eq(arg1), Eq(arg2), _, c::IsInt32Constant(2),
+ Eq(context), _, _));
}
}
@@ -549,29 +554,30 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) {
Callable builtin =
CodeFactory::InterpreterCEntry(isolate(), result_size);
- Node* function_id = m.Int32Constant(0);
+ TNode<Int32T> function_id = m.Int32Constant(0);
InterpreterAssembler::RegListNodePair registers(m.IntPtrConstant(1),
m.Int32Constant(2));
- Node* context = m.IntPtrConstant(4);
+ TNode<Object> context = m.ReinterpretCast<Object>(m.Int32Constant(4));
Matcher<Node*> function_table = c::IsExternalConstant(
ExternalReference::runtime_function_table_address_for_unittests(
isolate()));
- Matcher<Node*> function = c::IsIntPtrAdd(
- function_table,
- c::IsChangeUint32ToWord(c::IsInt32Mul(
- function_id, c::IsInt32Constant(sizeof(Runtime::Function)))));
+ Matcher<Node*> function =
+ c::IsIntPtrAdd(function_table,
+ c::IsChangeUint32ToWord(c::IsInt32Mul(
+ Eq(function_id),
+ c::IsInt32Constant(sizeof(Runtime::Function)))));
Matcher<Node*> function_entry =
m.IsLoad(MachineType::Pointer(), function,
c::IsIntPtrConstant(offsetof(Runtime::Function, entry)));
Node* call_runtime =
m.CallRuntimeN(function_id, context, registers, result_size);
- EXPECT_THAT(
- call_runtime,
- c::IsCall(_, c::IsHeapConstant(builtin.code()),
- registers.reg_count(), registers.base_reg_location(),
- function_entry, context, _, _));
+ EXPECT_THAT(call_runtime,
+ c::IsCall(_, c::IsHeapConstant(builtin.code()),
+ Eq(registers.reg_count()),
+ Eq(registers.base_reg_location()), function_entry,
+ Eq(context), _, _));
}
}
}
@@ -581,12 +587,13 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadFeedbackVector) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerTestState state(this, bytecode);
InterpreterAssemblerForTest m(&state, bytecode);
- Node* feedback_vector = m.LoadFeedbackVector();
+ TNode<HeapObject> feedback_vector = m.LoadFeedbackVector();
// Feedback vector is a phi node with two inputs. One of them is loading the
// feedback vector and the other is undefined constant (when feedback
// vectors aren't allocated). Find the input that loads feedback vector.
- CHECK(feedback_vector->opcode() == i::compiler::IrOpcode::kPhi);
+ CHECK_EQ(static_cast<Node*>(feedback_vector)->opcode(),
+ i::compiler::IrOpcode::kPhi);
Node* value0 =
i::compiler::NodeProperties::GetValueInput(feedback_vector, 0);
Node* value1 =
@@ -601,21 +608,22 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadFeedbackVector) {
c::IsIntPtrConstant(Register::function_closure().ToOperand() *
kSystemPointerSize)));
#ifdef V8_COMPRESS_POINTERS
- Matcher<Node*> load_vector_cell_matcher = IsChangeCompressedToTagged(
- m.IsLoadFromObject(MachineType::AnyCompressed(), load_function_matcher,
- c::IsIntPtrConstant(JSFunction::kFeedbackCellOffset -
- kHeapObjectTag)));
+ Matcher<Node*> load_vector_cell_matcher =
+ IsChangeCompressedPointerToTaggedPointer(m.IsLoadFromObject(
+ MachineType::CompressedPointer(), load_function_matcher,
+ c::IsIntPtrConstant(JSFunction::kFeedbackCellOffset -
+ kHeapObjectTag)));
EXPECT_THAT(load_feedback_vector,
- IsChangeCompressedToTagged(m.IsLoadFromObject(
- MachineType::AnyCompressed(), load_vector_cell_matcher,
+ IsChangeCompressedPointerToTaggedPointer(m.IsLoadFromObject(
+ MachineType::CompressedPointer(), load_vector_cell_matcher,
c::IsIntPtrConstant(Cell::kValueOffset - kHeapObjectTag))));
#else
Matcher<Node*> load_vector_cell_matcher = m.IsLoadFromObject(
- MachineType::AnyTagged(), load_function_matcher,
+ MachineType::TaggedPointer(), load_function_matcher,
c::IsIntPtrConstant(JSFunction::kFeedbackCellOffset - kHeapObjectTag));
EXPECT_THAT(load_feedback_vector,
m.IsLoadFromObject(
- MachineType::AnyTagged(), load_vector_cell_matcher,
+ MachineType::TaggedPointer(), load_vector_cell_matcher,
c::IsIntPtrConstant(Cell::kValueOffset - kHeapObjectTag)));
#endif
}
diff --git a/deps/v8/test/unittests/libplatform/task-queue-unittest.cc b/deps/v8/test/unittests/libplatform/task-queue-unittest.cc
index 4001048a8e..1ae440d0c0 100644
--- a/deps/v8/test/unittests/libplatform/task-queue-unittest.cc
+++ b/deps/v8/test/unittests/libplatform/task-queue-unittest.cc
@@ -51,8 +51,8 @@ TEST(TaskQueueTest, TerminateMultipleReaders) {
TaskQueue queue;
TaskQueueThread thread1(&queue);
TaskQueueThread thread2(&queue);
- thread1.Start();
- thread2.Start();
+ CHECK(thread1.Start());
+ CHECK(thread2.Start());
queue.Terminate();
thread1.Join();
thread2.Join();
diff --git a/deps/v8/test/unittests/tasks/background-compile-task-unittest.cc b/deps/v8/test/unittests/tasks/background-compile-task-unittest.cc
index 8b425542c1..8c3fb017a4 100644
--- a/deps/v8/test/unittests/tasks/background-compile-task-unittest.cc
+++ b/deps/v8/test/unittests/tasks/background-compile-task-unittest.cc
@@ -71,7 +71,7 @@ class BackgroundCompileTaskTest : public TestWithNativeContext {
ast_node_factory.NewFunctionLiteral(
function_name, function_scope, statements, -1, -1, -1,
FunctionLiteral::kNoDuplicateParameters,
- FunctionLiteral::kAnonymousExpression,
+ FunctionSyntaxKind::kAnonymousExpression,
FunctionLiteral::kShouldEagerCompile, shared->StartPosition(), true,
shared->function_literal_id(), nullptr);
diff --git a/deps/v8/test/unittests/tasks/cancelable-tasks-unittest.cc b/deps/v8/test/unittests/tasks/cancelable-tasks-unittest.cc
index b3843db46d..2a0e7d7f90 100644
--- a/deps/v8/test/unittests/tasks/cancelable-tasks-unittest.cc
+++ b/deps/v8/test/unittests/tasks/cancelable-tasks-unittest.cc
@@ -160,8 +160,8 @@ TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksStarted) {
ResultType result2{0};
ThreadedRunner runner1(NewTask(&result1, TestTask::kWaitTillCancelTriggered));
ThreadedRunner runner2(NewTask(&result2, TestTask::kWaitTillCancelTriggered));
- runner1.Start();
- runner2.Start();
+ CHECK(runner1.Start());
+ CHECK(runner2.Start());
// Busy wait on result to make sure both tasks are done.
while (result1.load() == 0 || result2.load() == 0) {
}
@@ -179,8 +179,8 @@ TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksNotRun) {
ThreadedRunner runner2(NewTask(&result2, TestTask::kCheckNotRun));
CancelAndWait();
// Tasks are canceled, hence the runner will bail out and not update result.
- runner1.Start();
- runner2.Start();
+ CHECK(runner1.Start());
+ CHECK(runner2.Start());
runner1.Join();
runner2.Join();
EXPECT_EQ(0u, result1);
@@ -193,7 +193,7 @@ TEST_F(CancelableTaskManagerTest, RemoveBeforeCancelAndWait) {
CancelableTaskManager::Id id = runner1.task_id();
EXPECT_EQ(1u, id);
EXPECT_EQ(TryAbortResult::kTaskAborted, manager()->TryAbort(id));
- runner1.Start();
+ CHECK(runner1.Start());
runner1.Join();
CancelAndWait();
EXPECT_EQ(0u, result1);
@@ -204,7 +204,7 @@ TEST_F(CancelableTaskManagerTest, RemoveAfterCancelAndWait) {
ThreadedRunner runner1(NewTask(&result1));
CancelableTaskManager::Id id = runner1.task_id();
EXPECT_EQ(1u, id);
- runner1.Start();
+ CHECK(runner1.Start());
runner1.Join();
CancelAndWait();
EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(id));
@@ -231,8 +231,8 @@ TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksNotRunTryAbortAll) {
ThreadedRunner runner2(NewTask(&result2, TestTask::kCheckNotRun));
EXPECT_EQ(TryAbortResult::kTaskAborted, TryAbortAll());
// Tasks are canceled, hence the runner will bail out and not update result.
- runner1.Start();
- runner2.Start();
+ CHECK(runner1.Start());
+ CHECK(runner2.Start());
runner1.Join();
runner2.Join();
EXPECT_EQ(0u, result1);
@@ -245,7 +245,7 @@ TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksStartedTryAbortAll) {
ResultType result2{0};
ThreadedRunner runner1(NewTask(&result1, TestTask::kWaitTillCancelTriggered));
ThreadedRunner runner2(NewTask(&result2, TestTask::kWaitTillCancelTriggered));
- runner1.Start();
+ CHECK(runner1.Start());
// Busy wait on result to make sure task1 is done.
while (result1.load() == 0) {
}
@@ -255,7 +255,7 @@ TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksStartedTryAbortAll) {
EXPECT_THAT(TryAbortAll(),
testing::AnyOf(testing::Eq(TryAbortResult::kTaskAborted),
testing::Eq(TryAbortResult::kTaskRunning)));
- runner2.Start();
+ CHECK(runner2.Start());
runner1.Join();
runner2.Join();
EXPECT_EQ(1u, result1);
diff --git a/deps/v8/test/unittests/torque/torque-unittest.cc b/deps/v8/test/unittests/torque/torque-unittest.cc
index 1366f86ce7..22ee754321 100644
--- a/deps/v8/test/unittests/torque/torque-unittest.cc
+++ b/deps/v8/test/unittests/torque/torque-unittest.cc
@@ -20,6 +20,13 @@ constexpr const char* kTestTorquePrelude = R"(
type void;
type never;
+namespace torque_internal {
+ struct Reference<T: type> {
+ const object: HeapObject;
+ const offset: intptr;
+ }
+}
+
type Tagged generates 'TNode<Object>' constexpr 'ObjectPtr';
type Smi extends Tagged generates 'TNode<Smi>' constexpr 'Smi';
diff --git a/deps/v8/test/unittests/unittests.status b/deps/v8/test/unittests/unittests.status
index c36a0b70f8..def90fc3b5 100644
--- a/deps/v8/test/unittests/unittests.status
+++ b/deps/v8/test/unittests/unittests.status
@@ -39,4 +39,17 @@
'Torque*': [SKIP],
}], # 'system == windows and asan'
+['system == windows and arch == x64 and mode == release', {
+ # BUG(992783).
+ 'Torque.ConditionalFields': [SKIP],
+ 'Torque.UsingUnderscorePrefixedIdentifierError': [SKIP],
+}], # 'system == windows and arch == x64 and mode == release'
+
+##############################################################################
+['tsan == True', {
+ # https://crbug.com/v8/9380
+ # The test is broken and needs to be fixed to use separate isolates.
+ 'BackingStoreTest.RacyGrowWasmMemoryInPlace': [SKIP],
+}], # 'tsan == True'
+
]
diff --git a/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc b/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc
index 725f7f4a59..791770ee94 100644
--- a/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc
+++ b/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc
@@ -1448,28 +1448,18 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset_void) {
WASM_ZERO, WASM_ZERO)});
}
-#define BYTE0(x) ((x)&0x7F)
-#define BYTE1(x) ((x >> 7) & 0x7F)
-#define BYTE2(x) ((x >> 14) & 0x7F)
-#define BYTE3(x) ((x >> 21) & 0x7F)
-
-#define VARINT1(x) BYTE0(x)
-#define VARINT2(x) BYTE0(x) | 0x80, BYTE1(x)
-#define VARINT3(x) BYTE0(x) | 0x80, BYTE1(x) | 0x80, BYTE2(x)
-#define VARINT4(x) BYTE0(x) | 0x80, BYTE1(x) | 0x80, BYTE2(x) | 0x80, BYTE3(x)
-
TEST_F(FunctionBodyDecoderTest, LoadMemOffset_varint) {
TestModuleBuilder builder;
module = builder.module();
builder.InitializeMemory();
ExpectValidates(sigs.i_i(),
- {WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT, VARINT1(0x45)});
+ {WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT, U32V_1(0x45)});
ExpectValidates(sigs.i_i(), {WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT,
- VARINT2(0x3999)});
+ U32V_2(0x3999)});
ExpectValidates(sigs.i_i(), {WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT,
- VARINT3(0x344445)});
+ U32V_3(0x344445)});
ExpectValidates(sigs.i_i(), {WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT,
- VARINT4(0x36666667)});
+ U32V_4(0x36666667)});
}
TEST_F(FunctionBodyDecoderTest, StoreMemOffset_varint) {
@@ -1477,25 +1467,15 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset_varint) {
module = builder.module();
builder.InitializeMemory();
ExpectValidates(sigs.v_i(), {WASM_ZERO, WASM_ZERO, kExprI32StoreMem,
- ZERO_ALIGNMENT, VARINT1(0x33)});
+ ZERO_ALIGNMENT, U32V_1(0x33)});
ExpectValidates(sigs.v_i(), {WASM_ZERO, WASM_ZERO, kExprI32StoreMem,
- ZERO_ALIGNMENT, VARINT2(0x1111)});
+ ZERO_ALIGNMENT, U32V_2(0x1111)});
ExpectValidates(sigs.v_i(), {WASM_ZERO, WASM_ZERO, kExprI32StoreMem,
- ZERO_ALIGNMENT, VARINT3(0x222222)});
+ ZERO_ALIGNMENT, U32V_3(0x222222)});
ExpectValidates(sigs.v_i(), {WASM_ZERO, WASM_ZERO, kExprI32StoreMem,
- ZERO_ALIGNMENT, VARINT4(0x44444444)});
+ ZERO_ALIGNMENT, U32V_4(0x44444444)});
}
-#undef BYTE0
-#undef BYTE1
-#undef BYTE2
-#undef BYTE3
-
-#undef VARINT1
-#undef VARINT2
-#undef VARINT3
-#undef VARINT4
-
TEST_F(FunctionBodyDecoderTest, AllLoadMemCombinations) {
TestModuleBuilder builder;
module = builder.module();
@@ -2104,6 +2084,9 @@ TEST_F(FunctionBodyDecoderTest, TableGet) {
ExpectValidates(
&sig,
{WASM_SET_LOCAL(local_func, WASM_TABLE_GET(tab_func2, WASM_I32V(7)))});
+ ExpectValidates(
+ &sig, {WASM_SET_LOCAL(local_ref, WASM_SEQ(WASM_I32V(6), kExprTableGet,
+ U32V_2(tab_ref1)))});
// We can store funcref values as anyref, but not the other way around.
ExpectFailure(&sig, {WASM_SET_LOCAL(local_func,
@@ -3542,6 +3525,24 @@ TEST_F(WasmOpcodeLengthTest, VariableLength) {
ExpectLength(4, kExprRefFunc, U32V_3(44));
ExpectLength(5, kExprRefFunc, U32V_4(66));
ExpectLength(6, kExprRefFunc, U32V_5(77));
+
+ ExpectLength(2, kExprTableGet, U32V_1(1));
+ ExpectLength(3, kExprTableGet, U32V_2(33));
+ ExpectLength(4, kExprTableGet, U32V_3(44));
+ ExpectLength(5, kExprTableGet, U32V_4(66));
+ ExpectLength(6, kExprTableGet, U32V_5(77));
+
+ ExpectLength(2, kExprTableSet, U32V_1(1));
+ ExpectLength(3, kExprTableSet, U32V_2(33));
+ ExpectLength(4, kExprTableSet, U32V_3(44));
+ ExpectLength(5, kExprTableSet, U32V_4(66));
+ ExpectLength(6, kExprTableSet, U32V_5(77));
+
+ ExpectLength(3, kExprCallIndirect, U32V_1(1), U32V_1(1));
+ ExpectLength(4, kExprCallIndirect, U32V_1(1), U32V_2(33));
+ ExpectLength(5, kExprCallIndirect, U32V_1(1), U32V_3(44));
+ ExpectLength(6, kExprCallIndirect, U32V_1(1), U32V_4(66));
+ ExpectLength(7, kExprCallIndirect, U32V_1(1), U32V_5(77));
}
TEST_F(WasmOpcodeLengthTest, LoadsAndStores) {
diff --git a/deps/v8/test/unittests/wasm/trap-handler-x64-unittest.cc b/deps/v8/test/unittests/wasm/trap-handler-x64-unittest.cc
index 1659370999..9f7cfc6b1d 100644
--- a/deps/v8/test/unittests/wasm/trap-handler-x64-unittest.cc
+++ b/deps/v8/test/unittests/wasm/trap-handler-x64-unittest.cc
@@ -465,7 +465,7 @@ TEST_P(TrapHandlerTest, TestCrashInOtherThread) {
CHECK(!GetThreadInWasmFlag());
// Set the thread-in-wasm flag manually in this thread.
*trap_handler::GetThreadInWasmThreadLocalAddress() = 1;
- runner.Start();
+ CHECK(runner.Start());
runner.Join();
CHECK(GetThreadInWasmFlag());
// Reset the thread-in-wasm flag.
diff --git a/deps/v8/test/unittests/wasm/wasm-code-manager-unittest.cc b/deps/v8/test/unittests/wasm/wasm-code-manager-unittest.cc
index eea1f8208d..a6b29ffc6c 100644
--- a/deps/v8/test/unittests/wasm/wasm-code-manager-unittest.cc
+++ b/deps/v8/test/unittests/wasm/wasm-code-manager-unittest.cc
@@ -156,8 +156,6 @@ class WasmCodeManagerTest : public TestWithContext,
public ::testing::WithParamInterface<ModuleStyle> {
public:
static constexpr uint32_t kNumFunctions = 10;
- static constexpr uint32_t kJumpTableSize = RoundUp<kCodeAlignment>(
- JumpTableAssembler::SizeForNumberOfSlots(kNumFunctions));
static size_t allocate_page_size;
static size_t commit_page_size;
@@ -169,6 +167,7 @@ class WasmCodeManagerTest : public TestWithContext,
}
CHECK_NE(0, allocate_page_size);
CHECK_NE(0, commit_page_size);
+ manager()->DisableImplicitAllocationsForTesting();
}
using NativeModulePtr = std::shared_ptr<NativeModule>;
@@ -199,12 +198,6 @@ class WasmCodeManagerTest : public TestWithContext,
void SetMaxCommittedMemory(size_t limit) {
manager()->SetMaxCommittedMemoryForTesting(limit);
}
-
- void DisableWin64UnwindInfoForTesting() {
-#if defined(V8_OS_WIN_X64)
- manager()->DisableWin64UnwindInfoForTesting();
-#endif
- }
};
// static
@@ -219,18 +212,18 @@ TEST_P(WasmCodeManagerTest, EmptyCase) {
SetMaxCommittedMemory(0);
CHECK_EQ(0, manager()->committed_code_space());
- ASSERT_DEATH_IF_SUPPORTED(AllocModule(allocate_page_size, GetParam()),
+ NativeModulePtr native_module = AllocModule(allocate_page_size, GetParam());
+ ASSERT_DEATH_IF_SUPPORTED(AddCode(native_module.get(), 0, kCodeAlignment),
"OOM in wasm code commit");
}
TEST_P(WasmCodeManagerTest, AllocateAndGoOverLimit) {
SetMaxCommittedMemory(allocate_page_size);
- DisableWin64UnwindInfoForTesting();
CHECK_EQ(0, manager()->committed_code_space());
NativeModulePtr native_module = AllocModule(allocate_page_size, GetParam());
CHECK(native_module);
- CHECK_EQ(commit_page_size, manager()->committed_code_space());
+ CHECK_EQ(0, manager()->committed_code_space());
WasmCodeRefScope code_ref_scope;
uint32_t index = 0;
WasmCode* code = AddCode(native_module.get(), index++, 1 * kCodeAlignment);
@@ -242,7 +235,7 @@ TEST_P(WasmCodeManagerTest, AllocateAndGoOverLimit) {
CHECK_EQ(commit_page_size, manager()->committed_code_space());
code = AddCode(native_module.get(), index++,
- allocate_page_size - 4 * kCodeAlignment - kJumpTableSize);
+ allocate_page_size - 4 * kCodeAlignment);
CHECK_NOT_NULL(code);
CHECK_EQ(allocate_page_size, manager()->committed_code_space());
@@ -256,29 +249,25 @@ TEST_P(WasmCodeManagerTest, AllocateAndGoOverLimit) {
TEST_P(WasmCodeManagerTest, TotalLimitIrrespectiveOfModuleCount) {
SetMaxCommittedMemory(3 * allocate_page_size);
- DisableWin64UnwindInfoForTesting();
NativeModulePtr nm1 = AllocModule(2 * allocate_page_size, GetParam());
NativeModulePtr nm2 = AllocModule(2 * allocate_page_size, GetParam());
CHECK(nm1);
CHECK(nm2);
WasmCodeRefScope code_ref_scope;
- WasmCode* code =
- AddCode(nm1.get(), 0, 2 * allocate_page_size - kJumpTableSize);
+ WasmCode* code = AddCode(nm1.get(), 0, 2 * allocate_page_size);
CHECK_NOT_NULL(code);
- ASSERT_DEATH_IF_SUPPORTED(
- AddCode(nm2.get(), 0, 2 * allocate_page_size - kJumpTableSize),
- "OOM in wasm code commit");
+ ASSERT_DEATH_IF_SUPPORTED(AddCode(nm2.get(), 0, 2 * allocate_page_size),
+ "OOM in wasm code commit");
}
TEST_P(WasmCodeManagerTest, GrowingVsFixedModule) {
SetMaxCommittedMemory(3 * allocate_page_size);
- DisableWin64UnwindInfoForTesting();
NativeModulePtr nm = AllocModule(allocate_page_size, GetParam());
size_t module_size =
GetParam() == Fixed ? kMaxWasmCodeMemory : allocate_page_size;
- size_t remaining_space_in_module = module_size - kJumpTableSize;
+ size_t remaining_space_in_module = module_size;
if (GetParam() == Fixed) {
// Requesting more than the remaining space fails because the module cannot
// grow.
@@ -297,7 +286,6 @@ TEST_P(WasmCodeManagerTest, GrowingVsFixedModule) {
TEST_P(WasmCodeManagerTest, CommitIncrements) {
SetMaxCommittedMemory(10 * allocate_page_size);
- DisableWin64UnwindInfoForTesting();
NativeModulePtr nm = AllocModule(3 * allocate_page_size, GetParam());
WasmCodeRefScope code_ref_scope;
@@ -308,15 +296,13 @@ TEST_P(WasmCodeManagerTest, CommitIncrements) {
CHECK_NOT_NULL(code);
CHECK_EQ(commit_page_size + 2 * allocate_page_size,
manager()->committed_code_space());
- code = AddCode(nm.get(), 2,
- allocate_page_size - kCodeAlignment - kJumpTableSize);
+ code = AddCode(nm.get(), 2, allocate_page_size - kCodeAlignment);
CHECK_NOT_NULL(code);
CHECK_EQ(3 * allocate_page_size, manager()->committed_code_space());
}
TEST_P(WasmCodeManagerTest, Lookup) {
SetMaxCommittedMemory(2 * allocate_page_size);
- DisableWin64UnwindInfoForTesting();
NativeModulePtr nm1 = AllocModule(allocate_page_size, GetParam());
NativeModulePtr nm2 = AllocModule(allocate_page_size, GetParam());
@@ -362,7 +348,6 @@ TEST_P(WasmCodeManagerTest, Lookup) {
TEST_P(WasmCodeManagerTest, LookupWorksAfterRewrite) {
SetMaxCommittedMemory(2 * allocate_page_size);
- DisableWin64UnwindInfoForTesting();
NativeModulePtr nm1 = AllocModule(allocate_page_size, GetParam());
diff --git a/deps/v8/test/unittests/wasm/wasm-module-sourcemap-unittest.cc b/deps/v8/test/unittests/wasm/wasm-module-sourcemap-unittest.cc
new file mode 100644
index 0000000000..04c611e1de
--- /dev/null
+++ b/deps/v8/test/unittests/wasm/wasm-module-sourcemap-unittest.cc
@@ -0,0 +1,224 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/wasm/wasm-module-sourcemap.h"
+#include <memory>
+
+#include "src/api/api.h"
+#include "test/common/wasm/flag-utils.h"
+#include "test/common/wasm/test-signatures.h"
+#include "test/common/wasm/wasm-macro-gen.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock-support.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+
+class WasmModuleSourceMapTest : public TestWithIsolateAndZone {};
+
+TEST_F(WasmModuleSourceMapTest, InvalidSourceMap) {
+ auto i_isolate = isolate();
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(i_isolate);
+
+ // Incomplete source map without "sources" entry.
+ char incomplete_src_map[] =
+ "{\"version\":3,\"names\":[],\"mappings\":\"6/"
+ "BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto incomplete_src_map_str =
+ v8::String::NewFromUtf8(v8_isolate, incomplete_src_map).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> incomplete_src_map_ptr(
+ new WasmModuleSourceMap(v8_isolate, incomplete_src_map_str));
+ EXPECT_FALSE(incomplete_src_map_ptr->IsValid());
+
+ // Miswrite key "mappings" as "mapping".
+ char wrong_key[] =
+ "{\"version\":3,\"sources\":[\"./"
+ "test.h\",\"main.cpp\"],\"names\":[],\"mapping\":\"6/"
+ "BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto wrong_key_str =
+ v8::String::NewFromUtf8(v8_isolate, wrong_key).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> wrong_key_ptr(
+ new WasmModuleSourceMap(v8_isolate, wrong_key_str));
+ EXPECT_FALSE(wrong_key_ptr->IsValid());
+
+ // Wrong version number.
+ char wrong_ver[] =
+ "{\"version\":2,\"sources\":[\"./"
+ "test.h\",\"main.cpp\"],\"names\":[],\"mappings\":\"6/"
+ "BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto wrong_ver_str =
+ v8::String::NewFromUtf8(v8_isolate, wrong_ver).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> wrong_ver_ptr(
+ new WasmModuleSourceMap(v8_isolate, wrong_ver_str));
+ EXPECT_FALSE(wrong_ver_ptr->IsValid());
+
+ // Wrong type of "version" entry.
+ char ver_as_arr[] =
+ "{\"version\":[3],\"sources\":[\"./"
+ "test.h\",\"main.cpp\"],\"names\":[],\"mappings\":\"6/"
+ "BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto ver_as_arr_str =
+ v8::String::NewFromUtf8(v8_isolate, ver_as_arr).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> ver_as_arr_ptr(
+ new WasmModuleSourceMap(v8_isolate, ver_as_arr_str));
+ EXPECT_FALSE(ver_as_arr_ptr->IsValid());
+
+ // Wrong type of "sources" entry.
+ char sources_as_str[] =
+ "{\"version\":3,\"sources\":\"./"
+ "test.h,main.cpp\",\"names\":[],\"mappings\":\"6/"
+ "BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto sources_as_str_str =
+ v8::String::NewFromUtf8(v8_isolate, sources_as_str).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> sources_as_str_ptr(
+ new WasmModuleSourceMap(v8_isolate, sources_as_str_str));
+ EXPECT_FALSE(sources_as_str_ptr->IsValid());
+
+ // Invalid "mappings" entry.
+ char wrong_mappings[] =
+ "{\"version\":3,\"sources\":[\"./"
+ "test.h\",\"main.cpp\"],\"names\":[],\"mappings\":\"6/"
+ "&BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto wrong_mappings_str =
+ v8::String::NewFromUtf8(v8_isolate, wrong_mappings).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> wrong_mappings_ptr(
+ new WasmModuleSourceMap(v8_isolate, wrong_mappings_str));
+ EXPECT_FALSE(wrong_mappings_ptr->IsValid());
+}
+
+TEST_F(WasmModuleSourceMapTest, HasSource) {
+ char src_map[] =
+ "{\"version\":3,\"sources\":[\"./"
+ "test.h\",\"main.cpp\"],\"names\":[],\"mappings\":\"6/"
+ "BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto i_isolate = isolate();
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(i_isolate);
+ auto src_map_str =
+ v8::String::NewFromUtf8(v8_isolate, src_map).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> src_map_ptr(
+ new WasmModuleSourceMap(v8_isolate, src_map_str));
+ EXPECT_TRUE(src_map_ptr->IsValid());
+
+ EXPECT_FALSE(src_map_ptr->HasSource(0x387, 0x3AF));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x3B0, 0x3B5));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x3B6, 0x3BC));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x3BD, 0x3C7));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x3C8, 0x3DA));
+ EXPECT_TRUE(src_map_ptr->HasSource(0x3DB, 0x414));
+ EXPECT_TRUE(src_map_ptr->HasSource(0x415, 0x44E));
+ EXPECT_TRUE(src_map_ptr->HasSource(0x450, 0x4DC));
+ EXPECT_TRUE(src_map_ptr->HasSource(0x4DE, 0x5F1));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x5F3, 0x437A));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x437C, 0x5507));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x5508, 0x5557));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x5559, 0x5609));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x560A, 0x563D));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x563E, 0x564A));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x564B, 0x5656));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x5658, 0x5713));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x5715, 0x59B0));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x59B1, 0x59BC));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x59BD, 0x59C6));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x59C7, 0x59D8));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x59D9, 0x59E7));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x59E9, 0x5B50));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x5B52, 0x5C53));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x5C54, 0x5C57));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x5C59, 0x5EBD));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x5EBF, 0x6030));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x6031, 0x608D));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x608E, 0x609E));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x609F, 0x60B3));
+ EXPECT_FALSE(src_map_ptr->HasSource(0x60B4, 0x60BD));
+}
+
+TEST_F(WasmModuleSourceMapTest, HasValidEntry) {
+ char src_map[] =
+ "{\"version\":3,\"sources\":[\"./"
+ "test.h\",\"main.cpp\"],\"names\":[],\"mappings\":\"6/"
+ "BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto i_isolate = isolate();
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(i_isolate);
+ auto src_map_str =
+ v8::String::NewFromUtf8(v8_isolate, src_map).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> src_map_ptr(
+ new WasmModuleSourceMap(v8_isolate, src_map_str));
+ EXPECT_TRUE(src_map_ptr->IsValid());
+
+ EXPECT_FALSE(src_map_ptr->HasValidEntry(0x450, 0x467));
+ EXPECT_FALSE(src_map_ptr->HasValidEntry(0x450, 0x450));
+ EXPECT_TRUE(src_map_ptr->HasValidEntry(0x450, 0x47A));
+ EXPECT_TRUE(src_map_ptr->HasValidEntry(0x450, 0x4A9));
+ EXPECT_FALSE(src_map_ptr->HasValidEntry(0x4DE, 0x4F5));
+ EXPECT_TRUE(src_map_ptr->HasValidEntry(0x4DE, 0x541));
+ EXPECT_TRUE(src_map_ptr->HasValidEntry(0x4DE, 0x57D));
+ EXPECT_TRUE(src_map_ptr->HasValidEntry(0x4DE, 0x5B7));
+ EXPECT_FALSE(src_map_ptr->HasValidEntry(0x4DE, 0x4DE));
+ EXPECT_TRUE(src_map_ptr->HasValidEntry(0x4DE, 0x500));
+ EXPECT_TRUE(src_map_ptr->HasValidEntry(0x4DE, 0x521));
+ EXPECT_TRUE(src_map_ptr->HasValidEntry(0x4DE, 0x560));
+ EXPECT_TRUE(src_map_ptr->HasValidEntry(0x4DE, 0x597));
+}
+
+TEST_F(WasmModuleSourceMapTest, GetFilename) {
+ char src_map[] =
+ "{\"version\":3,\"sources\":[\"./"
+ "test.h\",\"main.cpp\"],\"names\":[],\"mappings\":\"6/"
+ "BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto i_isolate = isolate();
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(i_isolate);
+ auto src_map_str =
+ v8::String::NewFromUtf8(v8_isolate, src_map).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> src_map_ptr(
+ new WasmModuleSourceMap(v8_isolate, src_map_str));
+ EXPECT_TRUE(src_map_ptr->IsValid());
+
+ EXPECT_STREQ("./test.h", src_map_ptr->GetFilename(0x47A).c_str());
+ EXPECT_STREQ("./test.h", src_map_ptr->GetFilename(0x4A9).c_str());
+ EXPECT_STREQ("main.cpp", src_map_ptr->GetFilename(0x500).c_str());
+ EXPECT_STREQ("main.cpp", src_map_ptr->GetFilename(0x521).c_str());
+ EXPECT_STREQ("main.cpp", src_map_ptr->GetFilename(0x541).c_str());
+ EXPECT_STREQ("main.cpp", src_map_ptr->GetFilename(0x560).c_str());
+ EXPECT_STREQ("main.cpp", src_map_ptr->GetFilename(0x57D).c_str());
+ EXPECT_STREQ("main.cpp", src_map_ptr->GetFilename(0x597).c_str());
+ EXPECT_STREQ("main.cpp", src_map_ptr->GetFilename(0x5B7).c_str());
+}
+
+TEST_F(WasmModuleSourceMapTest, SourceLine) {
+ char src_map[] =
+ "{\"version\":3,\"sources\":[\"./"
+ "test.h\",\"main.cpp\"],\"names\":[],\"mappings\":\"6/"
+ "BAGA,0DAIA,2DAIA,IAEA,+BACA,wCADA,mBAGA,4CCXA,6BACA,IACA,4BACA,gBADA,"
+ "mBAIA,4BACA,QADA,mBAIA,4BACA,gBADA,mBAVA,mBAcA\"}";
+ auto i_isolate = isolate();
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(i_isolate);
+ auto src_map_str =
+ v8::String::NewFromUtf8(v8_isolate, src_map).ToLocalChecked();
+ std::unique_ptr<WasmModuleSourceMap> src_map_ptr(
+ new WasmModuleSourceMap(v8_isolate, src_map_str));
+ EXPECT_TRUE(src_map_ptr->IsValid());
+
+ EXPECT_EQ(13ul, src_map_ptr->GetSourceLine(0x47A));
+ EXPECT_EQ(14ul, src_map_ptr->GetSourceLine(0x4A9));
+ EXPECT_EQ(5ul, src_map_ptr->GetSourceLine(0x500));
+ EXPECT_EQ(7ul, src_map_ptr->GetSourceLine(0x521));
+ EXPECT_EQ(8ul, src_map_ptr->GetSourceLine(0x541));
+ EXPECT_EQ(11ul, src_map_ptr->GetSourceLine(0x560));
+ EXPECT_EQ(12ul, src_map_ptr->GetSourceLine(0x57D));
+ EXPECT_EQ(15ul, src_map_ptr->GetSourceLine(0x597));
+ EXPECT_EQ(16ul, src_map_ptr->GetSourceLine(0x5B7));
+}
+} // namespace wasm
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/wasm-api-tests/BUILD.gn b/deps/v8/test/wasm-api-tests/BUILD.gn
index d0e2c01ac9..5bc48f57da 100644
--- a/deps/v8/test/wasm-api-tests/BUILD.gn
+++ b/deps/v8/test/wasm-api-tests/BUILD.gn
@@ -32,10 +32,13 @@ v8_executable("wasm_api_tests") {
"callbacks.cc",
"finalize.cc",
"globals.cc",
+ "hostref.cc",
"memory.cc",
+ "multi-return.cc",
"reflect.cc",
"run-all-wasm-api-tests.cc",
"serialize.cc",
+ "startup-errors.cc",
"table.cc",
"threads.cc",
"traps.cc",
diff --git a/deps/v8/test/wasm-api-tests/callbacks.cc b/deps/v8/test/wasm-api-tests/callbacks.cc
index 960fa726dd..350a425d47 100644
--- a/deps/v8/test/wasm-api-tests/callbacks.cc
+++ b/deps/v8/test/wasm-api-tests/callbacks.cc
@@ -14,11 +14,11 @@ namespace wasm {
namespace {
-own<Trap*> Stage2(void* env, const Val args[], Val results[]) {
+own<Trap> Stage2(void* env, const Val args[], Val results[]) {
printf("Stage2...\n");
WasmCapiTest* self = reinterpret_cast<WasmCapiTest*>(env);
Func* stage3 = self->GetExportedFunction(1);
- own<Trap*> trap = stage3->call(args, results);
+ own<Trap> trap = stage3->call(args, results);
if (trap) {
printf("Stage2: got exception: %s\n", trap->message().get());
} else {
@@ -27,7 +27,7 @@ own<Trap*> Stage2(void* env, const Val args[], Val results[]) {
return trap;
}
-own<Trap*> Stage4_GC(void* env, const Val args[], Val results[]) {
+own<Trap> Stage4_GC(void* env, const Val args[], Val results[]) {
printf("Stage4...\n");
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env);
isolate->heap()->PreciseCollectAllGarbage(
@@ -57,7 +57,7 @@ class WasmCapiCallbacksTest : public WasmCapiTest {
}
private:
- own<Func*> stage2_;
+ own<Func> stage2_;
};
} // namespace
@@ -72,7 +72,7 @@ TEST_F(WasmCapiCallbacksTest, Trap) {
Instantiate(imports);
Val args[] = {Val::i32(42)};
Val results[1];
- own<Trap*> trap = GetExportedFunction(0)->call(args, results);
+ own<Trap> trap = GetExportedFunction(0)->call(args, results);
EXPECT_NE(trap, nullptr);
printf("Stage0: Got trap as expected: %s\n", trap->message().get());
}
@@ -87,21 +87,21 @@ TEST_F(WasmCapiCallbacksTest, GC) {
i::Isolate* isolate =
reinterpret_cast<::wasm::StoreImpl*>(store())->i_isolate();
- own<Func*> stage4 = Func::make(store(), cpp_i_i_sig(), Stage4_GC, isolate);
+ own<Func> stage4 = Func::make(store(), cpp_i_i_sig(), Stage4_GC, isolate);
EXPECT_EQ(cpp_i_i_sig()->params().size(), stage4->type()->params().size());
EXPECT_EQ(cpp_i_i_sig()->results().size(), stage4->type()->results().size());
Extern* imports[] = {stage2(), stage4.get()};
Instantiate(imports);
Val args[] = {Val::i32(42)};
Val results[1];
- own<Trap*> trap = GetExportedFunction(0)->call(args, results);
+ own<Trap> trap = GetExportedFunction(0)->call(args, results);
EXPECT_EQ(trap, nullptr);
EXPECT_EQ(43, results[0].i32());
}
namespace {
-own<Trap*> FibonacciC(void* env, const Val args[], Val results[]) {
+own<Trap> FibonacciC(void* env, const Val args[], Val results[]) {
int32_t x = args[0].i32();
if (x == 0 || x == 1) {
results[0] = Val::i32(x);
@@ -113,7 +113,7 @@ own<Trap*> FibonacciC(void* env, const Val args[], Val results[]) {
// style, but this test intentionally ensures that it works if someone
// insists on doing it.
Val recursive_args[] = {Val::i32(x - 1)};
- own<Trap*> trap = fibo_wasm->call(recursive_args, results);
+ own<Trap> trap = fibo_wasm->call(recursive_args, results);
DCHECK_NULL(trap);
int32_t x1 = results[0].i32();
recursive_args[0] = Val::i32(x - 2);
@@ -148,20 +148,20 @@ TEST_F(WasmCapiTest, Recursion) {
AddExportedFunction(CStrVector("fibonacci_wasm"), code_fibo,
sizeof(code_fibo), wasm_i_i_sig());
- own<Func*> fibonacci = Func::make(store(), cpp_i_i_sig(), FibonacciC, this);
+ own<Func> fibonacci = Func::make(store(), cpp_i_i_sig(), FibonacciC, this);
Extern* imports[] = {fibonacci.get()};
Instantiate(imports);
// Enough iterations to make it interesting, few enough to keep it fast.
Val args[] = {Val::i32(15)};
Val results[1];
- own<Trap*> result = GetExportedFunction(0)->call(args, results);
+ own<Trap> result = GetExportedFunction(0)->call(args, results);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(610, results[0].i32());
}
namespace {
-own<Trap*> PlusOne(const Val args[], Val results[]) {
+own<Trap> PlusOne(const Val args[], Val results[]) {
int32_t a0 = args[0].i32();
results[0] = Val::i32(a0 + 1);
int64_t a1 = args[1].i64();
@@ -177,16 +177,16 @@ own<Trap*> PlusOne(const Val args[], Val results[]) {
} // namespace
TEST_F(WasmCapiTest, DirectCallCapiFunction) {
- own<FuncType*> cpp_sig =
- FuncType::make(vec<ValType*>::make(
+ own<FuncType> cpp_sig =
+ FuncType::make(ownvec<ValType>::make(
ValType::make(::wasm::I32), ValType::make(::wasm::I64),
ValType::make(::wasm::F32), ValType::make(::wasm::F64),
ValType::make(::wasm::ANYREF)),
- vec<ValType*>::make(
+ ownvec<ValType>::make(
ValType::make(::wasm::I32), ValType::make(::wasm::I64),
ValType::make(::wasm::F32), ValType::make(::wasm::F64),
ValType::make(::wasm::ANYREF)));
- own<Func*> func = Func::make(store(), cpp_sig.get(), PlusOne);
+ own<Func> func = Func::make(store(), cpp_sig.get(), PlusOne);
Extern* imports[] = {func.get()};
ValueType wasm_types[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64,
kWasmAnyRef, kWasmI32, kWasmI64, kWasmF32,
@@ -203,14 +203,13 @@ TEST_F(WasmCapiTest, DirectCallCapiFunction) {
Val::ref(func->copy())};
Val results[5];
// Test that {func} can be called directly.
- own<Trap*> trap = func->call(args, results);
+ own<Trap> trap = func->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(a0 + 1, results[0].i32());
EXPECT_EQ(a1 + 1, results[1].i64());
EXPECT_EQ(a2 + 1, results[2].f32());
EXPECT_EQ(a3 + 1, results[3].f64());
- // TODO(jkummerow): Check that func == results[4] when we have a way
- // to do so.
+ EXPECT_TRUE(func->same(results[4].ref()));
// Test that {func} can be called after import/export round-tripping.
trap = GetExportedFunction(0)->call(args, results);
@@ -219,8 +218,7 @@ TEST_F(WasmCapiTest, DirectCallCapiFunction) {
EXPECT_EQ(a1 + 1, results[1].i64());
EXPECT_EQ(a2 + 1, results[2].f32());
EXPECT_EQ(a3 + 1, results[3].f64());
- // TODO(jkummerow): Check that func == results[4] when we have a way
- // to do so.
+ EXPECT_TRUE(func->same(results[4].ref()));
}
} // namespace wasm
diff --git a/deps/v8/test/wasm-api-tests/finalize.cc b/deps/v8/test/wasm-api-tests/finalize.cc
index 7b3b976ca7..93da85460e 100644
--- a/deps/v8/test/wasm-api-tests/finalize.cc
+++ b/deps/v8/test/wasm-api-tests/finalize.cc
@@ -15,6 +15,8 @@ int g_functions_finalized = 0;
int g_foreigns_finalized = 0;
int g_modules_finalized = 0;
+const int kModuleMagic = 42;
+
void FinalizeInstance(void* data) {
int iteration = static_cast<int>(reinterpret_cast<intptr_t>(data));
g_instances_finalized += iteration;
@@ -34,6 +36,31 @@ void FinalizeModule(void* data) {
g_modules_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
}
+void RunInStore(Store* store, ZoneBuffer* wire_bytes, int iterations) {
+ size_t size = wire_bytes->end() - wire_bytes->begin();
+ vec<byte_t> binary = vec<byte_t>::make(
+ size, reinterpret_cast<byte_t*>(const_cast<byte*>(wire_bytes->begin())));
+ own<Module> module = Module::make(store, binary);
+ module->set_host_info(reinterpret_cast<void*>(kModuleMagic), &FinalizeModule);
+ for (int iteration = 0; iteration < iterations; iteration++) {
+ void* finalizer_data = reinterpret_cast<void*>(iteration);
+ own<Instance> instance = Instance::make(store, module.get(), nullptr);
+ EXPECT_NE(nullptr, instance.get());
+ instance->set_host_info(finalizer_data, &FinalizeInstance);
+
+ own<Func> func = instance->exports()[0]->func()->copy();
+ ASSERT_NE(func, nullptr);
+ func->set_host_info(finalizer_data, &FinalizeFunction);
+ Val args[] = {Val::i32(iteration)};
+ Val results[1];
+ func->call(args, results);
+ EXPECT_EQ(iteration, results[0].i32());
+
+ own<Foreign> foreign = Foreign::make(store);
+ foreign->set_host_info(finalizer_data, &FinalizeForeign);
+ }
+}
+
} // namespace
TEST_F(WasmCapiTest, InstanceFinalization) {
@@ -45,31 +72,114 @@ TEST_F(WasmCapiTest, InstanceFinalization) {
g_functions_finalized = 0;
g_foreigns_finalized = 0;
g_modules_finalized = 0;
- module()->set_host_info(reinterpret_cast<void*>(42), &FinalizeModule);
+ module()->set_host_info(reinterpret_cast<void*>(kModuleMagic),
+ &FinalizeModule);
static const int kIterations = 10;
- for (int iteration = 0; iteration < kIterations; iteration++) {
- void* finalizer_data = reinterpret_cast<void*>(iteration);
- own<Instance*> instance = Instance::make(store(), module(), nullptr);
- EXPECT_NE(nullptr, instance.get());
- instance->set_host_info(finalizer_data, &FinalizeInstance);
-
- own<Func*> func = instance->exports()[0]->func()->copy();
- ASSERT_NE(func, nullptr);
- func->set_host_info(finalizer_data, &FinalizeFunction);
-
- own<Foreign*> foreign = Foreign::make(store());
- foreign->set_host_info(finalizer_data, &FinalizeForeign);
+ RunInStore(store(), wire_bytes(), kIterations);
+ {
+ own<Store> store2 = Store::make(engine());
+ RunInStore(store2.get(), wire_bytes(), kIterations);
}
+ RunInStore(store(), wire_bytes(), kIterations);
Shutdown();
// Verify that (1) all finalizers were called, and (2) they passed the
// correct host data: the loop above sets {i} as data, and the finalizer
- // callbacks add them all up, so the expected value is
- // sum([0, 1, ..., kIterations - 1]), which per Gauss's formula is:
- static const int kExpected = (kIterations * (kIterations - 1)) / 2;
+ // callbacks add them all up, so the expected value after three rounds is
+ // 3 * sum([0, 1, ..., kIterations - 1]), which per Gauss's formula is:
+ static const int kExpected = 3 * ((kIterations * (kIterations - 1)) / 2);
EXPECT_EQ(g_instances_finalized, kExpected);
+ // There are two functions per iteration.
EXPECT_EQ(g_functions_finalized, kExpected);
EXPECT_EQ(g_foreigns_finalized, kExpected);
- EXPECT_EQ(g_modules_finalized, 42);
+ EXPECT_EQ(g_modules_finalized, 4 * kModuleMagic);
+}
+
+namespace {
+
+own<Trap> CapiFunction(void* env, const Val args[], Val results[]) {
+ int offset = static_cast<int>(reinterpret_cast<intptr_t>(env));
+ results[0] = Val::i32(offset + args[0].i32());
+ return nullptr;
+}
+
+int g_host_data_finalized = 0;
+int g_capi_function_finalized = 0;
+
+void FinalizeCapiFunction(void* data) {
+ int value = static_cast<int>(reinterpret_cast<intptr_t>(data));
+ g_capi_function_finalized += value;
+}
+
+void FinalizeHostData(void* data) {
+ g_host_data_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
+}
+
+} // namespace
+
+TEST_F(WasmCapiTest, CapiFunctionLifetimes) {
+ uint32_t func_index = builder()->AddImport(CStrVector("f"), wasm_i_i_sig());
+ builder()->ExportImportedFunction(CStrVector("f"), func_index);
+ Compile();
+ own<Instance> instance;
+ void* kHostData = reinterpret_cast<void*>(1234);
+ int base_summand = 1000;
+ {
+ // Test that the own<> pointers for Func and FuncType can go out of scope
+ // without affecting the ability of the Func to be called later.
+ own<FuncType> capi_func_type =
+ FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::I32)),
+ ownvec<ValType>::make(ValType::make(::wasm::I32)));
+ own<Func> capi_func =
+ Func::make(store(), capi_func_type.get(), &CapiFunction,
+ reinterpret_cast<void*>(base_summand));
+ Extern* imports[] = {capi_func.get()};
+ instance = Instance::make(store(), module(), imports);
+ // TODO(jkummerow): It may or may not be desirable to be able to set
+ // host data even here and have it survive the import/export dance.
+ // We are awaiting resolution of the discussion at:
+ // https://github.com/WebAssembly/wasm-c-api/issues/100
+ }
+ {
+ ownvec<Extern> exports = instance->exports();
+ Func* exported_func = exports[0]->func();
+ constexpr int kArg = 123;
+ Val args[] = {Val::i32(kArg)};
+ Val results[1];
+ exported_func->call(args, results);
+ EXPECT_EQ(base_summand + kArg, results[0].i32());
+ // Host data should survive destruction of the own<> pointer.
+ exported_func->set_host_info(kHostData);
+ }
+ {
+ ownvec<Extern> exports = instance->exports();
+ Func* exported_func = exports[0]->func();
+ EXPECT_EQ(kHostData, exported_func->get_host_info());
+ }
+ // Test that a Func can have its own internal metadata, an {env}, and
+ // separate {host info}, without any of that interfering with each other.
+ g_host_data_finalized = 0;
+ g_capi_function_finalized = 0;
+ base_summand = 23;
+ constexpr int kFinalizerData = 345;
+ {
+ own<FuncType> capi_func_type =
+ FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::I32)),
+ ownvec<ValType>::make(ValType::make(::wasm::I32)));
+ own<Func> capi_func = Func::make(
+ store(), capi_func_type.get(), &CapiFunction,
+ reinterpret_cast<void*>(base_summand), &FinalizeCapiFunction);
+ capi_func->set_host_info(reinterpret_cast<void*>(kFinalizerData),
+ &FinalizeHostData);
+ constexpr int kArg = 19;
+ Val args[] = {Val::i32(kArg)};
+ Val results[1];
+ capi_func->call(args, results);
+ EXPECT_EQ(base_summand + kArg, results[0].i32());
+ }
+ instance.reset();
+ Shutdown();
+ EXPECT_EQ(base_summand, g_capi_function_finalized);
+ EXPECT_EQ(kFinalizerData, g_host_data_finalized);
}
} // namespace wasm
diff --git a/deps/v8/test/wasm-api-tests/globals.cc b/deps/v8/test/wasm-api-tests/globals.cc
index d47f326cc4..a41cf4c9bc 100644
--- a/deps/v8/test/wasm-api-tests/globals.cc
+++ b/deps/v8/test/wasm-api-tests/globals.cc
@@ -90,21 +90,21 @@ TEST_F(WasmCapiTest, Globals) {
&param_i64);
// Create imported globals.
- own<GlobalType*> const_f32_type =
+ own<GlobalType> const_f32_type =
GlobalType::make(ValType::make(::wasm::F32), ::wasm::CONST);
- own<GlobalType*> const_i64_type =
+ own<GlobalType> const_i64_type =
GlobalType::make(ValType::make(::wasm::I64), ::wasm::CONST);
- own<GlobalType*> var_f32_type =
+ own<GlobalType> var_f32_type =
GlobalType::make(ValType::make(::wasm::F32), ::wasm::VAR);
- own<GlobalType*> var_i64_type =
+ own<GlobalType> var_i64_type =
GlobalType::make(ValType::make(::wasm::I64), ::wasm::VAR);
- own<Global*> const_f32_import =
+ own<Global> const_f32_import =
Global::make(store(), const_f32_type.get(), Val::f32(1));
- own<Global*> const_i64_import =
+ own<Global> const_i64_import =
Global::make(store(), const_i64_type.get(), Val::i64(2));
- own<Global*> var_f32_import =
+ own<Global> var_f32_import =
Global::make(store(), var_f32_type.get(), Val::f32(3));
- own<Global*> var_i64_import =
+ own<Global> var_i64_import =
Global::make(store(), var_i64_type.get(), Val::i64(4));
Extern* imports[] = {const_f32_import.get(), const_i64_import.get(),
var_f32_import.get(), var_i64_import.get()};
@@ -130,6 +130,9 @@ TEST_F(WasmCapiTest, Globals) {
Func* set_var_f32_export = GetExportedFunction(i++);
Func* set_var_i64_export = GetExportedFunction(i++);
+ // Try cloning.
+ EXPECT_TRUE(var_f32_import->copy()->same(var_f32_import.get()));
+
// Check initial values.
EXPECT_EQ(1.f, const_f32_import->get().f32());
EXPECT_EQ(2, const_i64_import->get().i64());
diff --git a/deps/v8/test/wasm-api-tests/hostref.cc b/deps/v8/test/wasm-api-tests/hostref.cc
new file mode 100644
index 0000000000..d40cb25d8f
--- /dev/null
+++ b/deps/v8/test/wasm-api-tests/hostref.cc
@@ -0,0 +1,178 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/wasm-api-tests/wasm-api-test.h"
+
+#include <iostream>
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+
+using ::wasm::Frame;
+using ::wasm::Message;
+
+namespace {
+
+own<Trap> IdentityCallback(const Val args[], Val results[]) {
+ results[0] = args[0].copy();
+ return nullptr;
+}
+
+} // namespace
+
+TEST_F(WasmCapiTest, HostRef) {
+ ValueType rr_reps[] = {kWasmAnyRef, kWasmAnyRef};
+ ValueType ri_reps[] = {kWasmAnyRef, kWasmI32};
+ ValueType ir_reps[] = {kWasmI32, kWasmAnyRef};
+ // Naming convention: result_params_sig.
+ FunctionSig r_r_sig(1, 1, rr_reps);
+ FunctionSig v_r_sig(0, 1, rr_reps);
+ FunctionSig r_v_sig(1, 0, rr_reps);
+ FunctionSig v_ir_sig(0, 2, ir_reps);
+ FunctionSig r_i_sig(1, 1, ri_reps);
+ uint32_t func_index = builder()->AddImport(CStrVector("f"), &r_r_sig);
+ const bool kMutable = true;
+ const WasmInitExpr global_init(WasmInitExpr::kRefNullConst, 0);
+ uint32_t global_index = builder()->AddExportedGlobal(
+ kWasmAnyRef, kMutable, global_init, CStrVector("global"));
+ uint32_t table_index = builder()->AddTable(kWasmAnyRef, 10);
+ builder()->AddExport(CStrVector("table"), kExternalTable, table_index);
+ byte global_set_code[] = {WASM_SET_GLOBAL(global_index, WASM_GET_LOCAL(0))};
+ AddExportedFunction(CStrVector("global.set"), global_set_code,
+ sizeof(global_set_code), &v_r_sig);
+ byte global_get_code[] = {WASM_GET_GLOBAL(global_index)};
+ AddExportedFunction(CStrVector("global.get"), global_get_code,
+ sizeof(global_get_code), &r_v_sig);
+ byte table_set_code[] = {
+ WASM_TABLE_SET(table_index, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))};
+ AddExportedFunction(CStrVector("table.set"), table_set_code,
+ sizeof(table_set_code), &v_ir_sig);
+ byte table_get_code[] = {WASM_TABLE_GET(table_index, WASM_GET_LOCAL(0))};
+ AddExportedFunction(CStrVector("table.get"), table_get_code,
+ sizeof(table_get_code), &r_i_sig);
+ byte func_call_code[] = {WASM_CALL_FUNCTION(func_index, WASM_GET_LOCAL(0))};
+ AddExportedFunction(CStrVector("func.call"), func_call_code,
+ sizeof(func_call_code), &r_r_sig);
+
+ own<FuncType> func_type =
+ FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::ANYREF)),
+ ownvec<ValType>::make(ValType::make(::wasm::ANYREF)));
+ own<Func> callback = Func::make(store(), func_type.get(), IdentityCallback);
+ Extern* imports[] = {callback.get()};
+ Instantiate(imports);
+
+ Global* global = GetExportedGlobal(0);
+ Table* table = GetExportedTable(1);
+ const Func* global_set = GetExportedFunction(2);
+ const Func* global_get = GetExportedFunction(3);
+ const Func* table_set = GetExportedFunction(4);
+ const Func* table_get = GetExportedFunction(5);
+ const Func* func_call = GetExportedFunction(6);
+
+ own<Foreign> host1 = Foreign::make(store());
+ own<Foreign> host2 = Foreign::make(store());
+ host1->set_host_info(reinterpret_cast<void*>(1));
+ host2->set_host_info(reinterpret_cast<void*>(2));
+
+ // Basic checks.
+ EXPECT_TRUE(host1->copy()->same(host1.get()));
+ EXPECT_TRUE(host2->copy()->same(host2.get()));
+ Val val = Val::ref(host1->copy());
+ EXPECT_TRUE(val.ref()->copy()->same(host1.get()));
+ own<Ref> ref = val.release_ref();
+ EXPECT_EQ(nullptr, val.ref());
+ EXPECT_TRUE(ref->copy()->same(host1.get()));
+
+ // Interact with the Global.
+ Val args[2];
+ Val results[1];
+ own<Trap> trap = global_get->call(nullptr, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_EQ(nullptr, results[0].release_ref());
+ args[0] = Val::ref(host1.get()->copy());
+ trap = global_set->call(args, nullptr);
+ EXPECT_EQ(nullptr, trap);
+ trap = global_get->call(nullptr, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_TRUE(results[0].release_ref()->same(host1.get()));
+ args[0] = Val::ref(host2.get()->copy());
+ trap = global_set->call(args, nullptr);
+ EXPECT_EQ(nullptr, trap);
+ trap = global_get->call(nullptr, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_TRUE(results[0].release_ref()->same(host2.get()));
+ args[0] = Val::ref(own<Ref>());
+ trap = global_set->call(args, nullptr);
+ EXPECT_EQ(nullptr, trap);
+ trap = global_get->call(nullptr, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_EQ(nullptr, results[0].release_ref());
+
+ EXPECT_EQ(nullptr, global->get().release_ref());
+ global->set(Val(host2->copy()));
+ trap = global_get->call(nullptr, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_TRUE(results[0].release_ref()->same(host2.get()));
+ EXPECT_TRUE(global->get().release_ref()->same(host2.get()));
+
+ // Interact with the Table.
+ args[0] = Val::i32(0);
+ trap = table_get->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_EQ(nullptr, results[0].release_ref());
+ args[0] = Val::i32(1);
+ trap = table_get->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_EQ(nullptr, results[0].release_ref());
+ args[0] = Val::i32(0);
+ args[1] = Val::ref(host1.get()->copy());
+ trap = table_set->call(args, nullptr);
+ EXPECT_EQ(nullptr, trap);
+ args[0] = Val::i32(1);
+ args[1] = Val::ref(host2.get()->copy());
+ trap = table_set->call(args, nullptr);
+ EXPECT_EQ(nullptr, trap);
+ args[0] = Val::i32(0);
+ trap = table_get->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_TRUE(results[0].release_ref()->same(host1.get()));
+ args[0] = Val::i32(1);
+ trap = table_get->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_TRUE(results[0].release_ref()->same(host2.get()));
+ args[0] = Val::i32(0);
+ args[1] = Val::ref(own<Ref>());
+ trap = table_set->call(args, nullptr);
+ EXPECT_EQ(nullptr, trap);
+ trap = table_get->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_EQ(nullptr, results[0].release_ref());
+
+ EXPECT_EQ(nullptr, table->get(2));
+ table->set(2, host1.get());
+ args[0] = Val::i32(2);
+ trap = table_get->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_TRUE(results[0].release_ref()->same(host1.get()));
+ EXPECT_TRUE(table->get(2)->same(host1.get()));
+
+ // Interact with the Function.
+ args[0] = Val::ref(own<Ref>());
+ trap = func_call->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_EQ(nullptr, results[0].release_ref());
+ args[0] = Val::ref(host1.get()->copy());
+ trap = func_call->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_TRUE(results[0].release_ref()->same(host1.get()));
+ args[0] = Val::ref(host2.get()->copy());
+ trap = func_call->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_TRUE(results[0].release_ref()->same(host2.get()));
+}
+
+} // namespace wasm
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/wasm-api-tests/memory.cc b/deps/v8/test/wasm-api-tests/memory.cc
index aec4cf8ccc..131bdb96e3 100644
--- a/deps/v8/test/wasm-api-tests/memory.cc
+++ b/deps/v8/test/wasm-api-tests/memory.cc
@@ -41,6 +41,9 @@ TEST_F(WasmCapiTest, Memory) {
Func* load_func = GetExportedFunction(2);
Func* store_func = GetExportedFunction(3);
+ // Try cloning.
+ EXPECT_TRUE(memory->copy()->same(memory));
+
// Check initial state.
EXPECT_EQ(2u, memory->size());
EXPECT_EQ(0x20000u, memory->data_size());
@@ -70,7 +73,7 @@ TEST_F(WasmCapiTest, Memory) {
EXPECT_EQ(0, result[0].i32());
// load(0x20000) -> trap
args[0] = Val::i32(0x20000);
- own<Trap*> trap = load_func->call(args, result);
+ own<Trap> trap = load_func->call(args, result);
EXPECT_NE(nullptr, trap.get());
// Mutate memory.
@@ -111,8 +114,8 @@ TEST_F(WasmCapiTest, Memory) {
// Create standalone memory.
// TODO(wasm): Once Wasm allows multiple memories, turn this into an import.
- own<MemoryType*> mem_type = MemoryType::make(Limits(5, 5));
- own<Memory*> memory2 = Memory::make(store(), mem_type.get());
+ own<MemoryType> mem_type = MemoryType::make(Limits(5, 5));
+ own<Memory> memory2 = Memory::make(store(), mem_type.get());
EXPECT_EQ(5u, memory2->size());
EXPECT_EQ(false, memory2->grow(1));
EXPECT_EQ(true, memory2->grow(0));
diff --git a/deps/v8/test/wasm-api-tests/multi-return.cc b/deps/v8/test/wasm-api-tests/multi-return.cc
new file mode 100644
index 0000000000..2cd624d053
--- /dev/null
+++ b/deps/v8/test/wasm-api-tests/multi-return.cc
@@ -0,0 +1,58 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/wasm-api-tests/wasm-api-test.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+
+using ::wasm::I32;
+using ::wasm::I64;
+
+namespace {
+
+own<Trap> Callback(const Val args[], Val results[]) {
+ results[0] = args[3].copy();
+ results[1] = args[1].copy();
+ results[2] = args[2].copy();
+ results[3] = args[0].copy();
+ return nullptr;
+}
+
+} // namespace
+
+TEST_F(WasmCapiTest, MultiReturn) {
+ ValueType reps[] = {kWasmI32, kWasmI64, kWasmI64, kWasmI32,
+ kWasmI32, kWasmI64, kWasmI64, kWasmI32};
+ FunctionSig sig(4, 4, reps);
+ uint32_t func_index = builder()->AddImport(CStrVector("f"), &sig);
+ byte code[] = {WASM_CALL_FUNCTION(func_index, WASM_GET_LOCAL(0),
+ WASM_GET_LOCAL(2), WASM_GET_LOCAL(1),
+ WASM_GET_LOCAL(3))};
+ AddExportedFunction(CStrVector("g"), code, sizeof(code), &sig);
+
+ ownvec<ValType> types =
+ ownvec<ValType>::make(ValType::make(I32), ValType::make(I64),
+ ValType::make(I64), ValType::make(I32));
+ own<FuncType> func_type =
+ FuncType::make(types.deep_copy(), types.deep_copy());
+ own<Func> callback = Func::make(store(), func_type.get(), Callback);
+ Extern* imports[] = {callback.get()};
+ Instantiate(imports);
+
+ Func* run_func = GetExportedFunction(0);
+ Val args[] = {Val::i32(1), Val::i64(2), Val::i64(3), Val::i32(4)};
+ Val results[4];
+ own<Trap> trap = run_func->call(args, results);
+ EXPECT_EQ(nullptr, trap);
+ EXPECT_EQ(4, results[0].i32());
+ EXPECT_EQ(3, results[1].i64());
+ EXPECT_EQ(2, results[2].i64());
+ EXPECT_EQ(1, results[3].i32());
+}
+
+} // namespace wasm
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/wasm-api-tests/reflect.cc b/deps/v8/test/wasm-api-tests/reflect.cc
index a7def627db..dee3334155 100644
--- a/deps/v8/test/wasm-api-tests/reflect.cc
+++ b/deps/v8/test/wasm-api-tests/reflect.cc
@@ -51,8 +51,8 @@ TEST_F(WasmCapiTest, Reflect) {
Instantiate(nullptr);
- vec<ExportType*> export_types = module()->exports();
- const vec<Extern*>& exports = this->exports();
+ ownvec<ExportType> export_types = module()->exports();
+ const ownvec<Extern>& exports = this->exports();
EXPECT_EQ(exports.size(), export_types.size());
EXPECT_EQ(4u, exports.size());
for (size_t i = 0; i < exports.size(); i++) {
@@ -62,13 +62,13 @@ TEST_F(WasmCapiTest, Reflect) {
if (kind == ::wasm::EXTERN_FUNC) {
ExpectName(kFuncName, export_types[i]->name());
const FuncType* type = extern_type->func();
- const vec<ValType*>& params = type->params();
+ const ownvec<ValType>& params = type->params();
EXPECT_EQ(4u, params.size());
EXPECT_EQ(::wasm::I32, params[0]->kind());
EXPECT_EQ(::wasm::I64, params[1]->kind());
EXPECT_EQ(::wasm::F32, params[2]->kind());
EXPECT_EQ(::wasm::F64, params[3]->kind());
- const vec<ValType*>& results = type->results();
+ const ownvec<ValType>& results = type->results();
EXPECT_EQ(2u, results.size());
EXPECT_EQ(::wasm::I32, results[0]->kind());
EXPECT_EQ(::wasm::ANYREF, results[1]->kind());
diff --git a/deps/v8/test/wasm-api-tests/serialize.cc b/deps/v8/test/wasm-api-tests/serialize.cc
index 5f10980cf2..710f123625 100644
--- a/deps/v8/test/wasm-api-tests/serialize.cc
+++ b/deps/v8/test/wasm-api-tests/serialize.cc
@@ -12,7 +12,7 @@ namespace {
bool g_callback_called;
-own<Trap*> Callback(const Val args[], Val results[]) {
+own<Trap> Callback(const Val args[], Val results[]) {
g_callback_called = true;
return nullptr;
}
@@ -27,16 +27,15 @@ TEST_F(WasmCapiTest, Serialize) {
Compile();
vec<byte_t> serialized = module()->serialize();
- own<Module*> deserialized = Module::deserialize(store(), serialized);
+ own<Module> deserialized = Module::deserialize(store(), serialized);
- own<FuncType*> callback_type =
- FuncType::make(vec<ValType*>::make(), vec<ValType*>::make());
- own<Func*> callback = Func::make(store(), callback_type.get(), Callback);
+ own<FuncType> callback_type =
+ FuncType::make(ownvec<ValType>::make(), ownvec<ValType>::make());
+ own<Func> callback = Func::make(store(), callback_type.get(), Callback);
Extern* imports[] = {callback.get()};
- own<Instance*> instance =
- Instance::make(store(), deserialized.get(), imports);
- vec<Extern*> exports = instance->exports();
+ own<Instance> instance = Instance::make(store(), deserialized.get(), imports);
+ ownvec<Extern> exports = instance->exports();
Func* run = exports[0]->func();
g_callback_called = false;
run->call();
diff --git a/deps/v8/test/wasm-api-tests/startup-errors.cc b/deps/v8/test/wasm-api-tests/startup-errors.cc
new file mode 100644
index 0000000000..d2187e569a
--- /dev/null
+++ b/deps/v8/test/wasm-api-tests/startup-errors.cc
@@ -0,0 +1,62 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/wasm-api-tests/wasm-api-test.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+
+namespace {
+
+own<Trap> DummyCallback(const Val args[], Val results[]) { return nullptr; }
+
+} // namespace
+
+TEST_F(WasmCapiTest, StartupErrors) {
+ FunctionSig sig(0, 0, nullptr);
+ byte code[] = {WASM_UNREACHABLE};
+ WasmFunctionBuilder* start_func = builder()->AddFunction(&sig);
+ start_func->EmitCode(code, static_cast<uint32_t>(sizeof(code)));
+ start_func->Emit(kExprEnd);
+ builder()->MarkStartFunction(start_func);
+ builder()->AddImport(CStrVector("dummy"), &sig);
+ Compile();
+ own<Trap> trap;
+
+ // Try to make an Instance with non-matching imports.
+ own<Func> bad_func = Func::make(store(), cpp_i_i_sig(), DummyCallback);
+ Extern* bad_imports[] = {bad_func.get()};
+ own<Instance> instance =
+ Instance::make(store(), module(), bad_imports, &trap);
+ EXPECT_EQ(nullptr, instance);
+ EXPECT_NE(nullptr, trap);
+ EXPECT_STREQ(
+ "Uncaught LinkError: instantiation: Import #0 module=\"\" "
+ "function=\"dummy\" "
+ "error: imported function does not match the expected type",
+ trap->message().get());
+ EXPECT_EQ(nullptr, trap->origin());
+ // Don't crash if there is no {trap}.
+ instance = Instance::make(store(), module(), bad_imports, nullptr);
+ EXPECT_EQ(nullptr, instance);
+
+ // Try to make an instance with a {start} function that traps.
+ own<FuncType> good_sig =
+ FuncType::make(ownvec<ValType>::make(), ownvec<ValType>::make());
+ own<Func> good_func = Func::make(store(), good_sig.get(), DummyCallback);
+ Extern* good_imports[] = {good_func.get()};
+ instance = Instance::make(store(), module(), good_imports, &trap);
+ EXPECT_EQ(nullptr, instance);
+ EXPECT_NE(nullptr, trap);
+ EXPECT_STREQ("Uncaught RuntimeError: unreachable", trap->message().get());
+ EXPECT_NE(nullptr, trap->origin());
+ // Don't crash if there is no {trap}.
+ instance = Instance::make(store(), module(), good_imports, nullptr);
+ EXPECT_EQ(nullptr, instance);
+}
+
+} // namespace wasm
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/test/wasm-api-tests/table.cc b/deps/v8/test/wasm-api-tests/table.cc
index 17ddfa2f0b..bfd5e14a8d 100644
--- a/deps/v8/test/wasm-api-tests/table.cc
+++ b/deps/v8/test/wasm-api-tests/table.cc
@@ -14,7 +14,7 @@ using ::wasm::TableType;
namespace {
-own<Trap*> Negate(const Val args[], Val results[]) {
+own<Trap> Negate(const Val args[], Val results[]) {
results[0] = Val(-args[0].i32());
return nullptr;
}
@@ -22,14 +22,14 @@ own<Trap*> Negate(const Val args[], Val results[]) {
void ExpectTrap(const Func* func, int arg1, int arg2) {
Val args[2] = {Val::i32(arg1), Val::i32(arg2)};
Val results[1];
- own<Trap*> trap = func->call(args, results);
+ own<Trap> trap = func->call(args, results);
EXPECT_NE(nullptr, trap);
}
void ExpectResult(int expected, const Func* func, int arg1, int arg2) {
Val args[2] = {Val::i32(arg1), Val::i32(arg2)};
Val results[1];
- own<Trap*> trap = func->call(args, results);
+ own<Trap> trap = func->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(expected, results[0].i32());
}
@@ -60,7 +60,10 @@ TEST_F(WasmCapiTest, Table) {
Func* call_indirect = GetExportedFunction(1);
Func* f = GetExportedFunction(2);
Func* g = GetExportedFunction(3);
- own<Func*> h = Func::make(store(), cpp_i_i_sig(), Negate);
+ own<Func> h = Func::make(store(), cpp_i_i_sig(), Negate);
+
+ // Try cloning.
+ EXPECT_TRUE(table->copy()->same(table));
// Check initial table state.
EXPECT_EQ(2u, table->size());
@@ -103,9 +106,9 @@ TEST_F(WasmCapiTest, Table) {
// Create standalone table.
// TODO(wasm+): Once Wasm allows multiple tables, turn this into import.
- own<TableType*> tabletype =
+ own<TableType> tabletype =
TableType::make(ValType::make(FUNCREF), Limits(5, 5));
- own<Table*> table2 = Table::make(store(), tabletype.get());
+ own<Table> table2 = Table::make(store(), tabletype.get());
EXPECT_EQ(5u, table2->size());
EXPECT_FALSE(table2->grow(1));
EXPECT_TRUE(table2->grow(0));
diff --git a/deps/v8/test/wasm-api-tests/threads.cc b/deps/v8/test/wasm-api-tests/threads.cc
index c93afc4a89..5fb4309c4b 100644
--- a/deps/v8/test/wasm-api-tests/threads.cc
+++ b/deps/v8/test/wasm-api-tests/threads.cc
@@ -19,26 +19,27 @@ const int kNumThreads = 10;
const int kIterationsPerThread = 3;
int g_traces;
-own<Trap*> Callback(void* env, const Val args[], Val results[]) {
+own<Trap> Callback(void* env, const Val args[], Val results[]) {
std::lock_guard<std::mutex> lock(*reinterpret_cast<std::mutex*>(env));
g_traces += args[0].i32();
return nullptr;
}
void Main(Engine* engine, Shared<Module>* shared, std::mutex* mutex, int id) {
- own<Store*> store = Store::make(engine);
- own<Module*> module = Module::obtain(store.get(), shared);
+ own<Store> store = Store::make(engine);
+ own<Module> module = Module::obtain(store.get(), shared);
EXPECT_NE(nullptr, module.get());
for (int i = 0; i < kIterationsPerThread; i++) {
std::this_thread::sleep_for(std::chrono::microseconds(100));
// Create imports.
- own<FuncType*> func_type = FuncType::make(
- vec<ValType*>::make(ValType::make(::wasm::I32)), vec<ValType*>::make());
- own<Func*> func = Func::make(store.get(), func_type.get(), Callback, mutex);
- own<::wasm::GlobalType*> global_type =
+ own<FuncType> func_type =
+ FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::I32)),
+ ownvec<ValType>::make());
+ own<Func> func = Func::make(store.get(), func_type.get(), Callback, mutex);
+ own<::wasm::GlobalType> global_type =
::wasm::GlobalType::make(ValType::make(::wasm::I32), ::wasm::CONST);
- own<Global*> global =
+ own<Global> global =
Global::make(store.get(), global_type.get(), Val::i32(id));
// Instantiate and run.
@@ -46,9 +47,8 @@ void Main(Engine* engine, Shared<Module>* shared, std::mutex* mutex, int id) {
// imports always come before function imports, regardless of the
// order of builder()->Add*Import() calls below.
Extern* imports[] = {global.get(), func.get()};
- own<Instance*> instance =
- Instance::make(store.get(), module.get(), imports);
- vec<Extern*> exports = instance->exports();
+ own<Instance> instance = Instance::make(store.get(), module.get(), imports);
+ ownvec<Extern> exports = instance->exports();
Func* run_func = exports[0]->func();
run_func->call();
}
@@ -70,7 +70,7 @@ TEST_F(WasmCapiTest, Threads) {
FunctionSig empty_sig(0, 0, nullptr);
AddExportedFunction(CStrVector("run"), code, sizeof(code), &empty_sig);
Compile();
- own<Shared<Module>*> shared = module()->share();
+ own<Shared<Module>> shared = module()->share();
// Spawn threads.
g_traces = 0;
@@ -92,9 +92,9 @@ TEST_F(WasmCapiTest, Threads) {
TEST_F(WasmCapiTest, MultiStoresOneThread) {
// These Stores intentionally have overlapping, but non-nested lifetimes.
- own<Store*> store1 = Store::make(engine());
- own<Store*> store2 = Store::make(engine());
- own<Store*> store3 = Store::make(engine());
+ own<Store> store1 = Store::make(engine());
+ own<Store> store2 = Store::make(engine());
+ own<Store> store3 = Store::make(engine());
store1.reset();
store2.reset();
store3.reset();
diff --git a/deps/v8/test/wasm-api-tests/traps.cc b/deps/v8/test/wasm-api-tests/traps.cc
index b049d09330..e6e425fc4c 100644
--- a/deps/v8/test/wasm-api-tests/traps.cc
+++ b/deps/v8/test/wasm-api-tests/traps.cc
@@ -4,17 +4,23 @@
#include "test/wasm-api-tests/wasm-api-test.h"
+#include "src/execution/isolate.h"
+#include "src/wasm/c-api.h"
+#include "src/wasm/module-decoder.h"
+#include "src/wasm/wasm-engine.h"
+
#include <iostream>
namespace v8 {
namespace internal {
namespace wasm {
+using ::wasm::Frame;
using ::wasm::Message;
namespace {
-own<Trap*> FailCallback(void* env, const Val args[], Val results[]) {
+own<Trap> FailCallback(void* env, const Val args[], Val results[]) {
Store* store = reinterpret_cast<Store*>(env);
Message message = Message::make(std::string("callback abort"));
return Trap::make(store, message);
@@ -34,25 +40,66 @@ TEST_F(WasmCapiTest, Traps) {
uint32_t callback_index = builder()->AddImport(CStrVector("callback"), &sig);
byte code[] = {WASM_CALL_FUNCTION0(callback_index)};
AddExportedFunction(CStrVector("callback"), code, sizeof(code), &sig);
- byte code2[] = {WASM_UNREACHABLE, WASM_I32V_1(1)};
+ // The first constant is a 4-byte dummy so that the {unreachable} trap
+ // has a more interesting offset.
+ byte code2[] = {WASM_I32V_3(0), WASM_UNREACHABLE, WASM_I32V_1(1)};
AddExportedFunction(CStrVector("unreachable"), code2, sizeof(code2), &sig);
- own<FuncType*> func_type = FuncType::make(
- vec<ValType*>::make(), vec<ValType*>::make(ValType::make(::wasm::I32)));
- own<Func*> cpp_callback = Func::make(store(), func_type.get(), FailCallback,
- reinterpret_cast<void*>(store()));
+ own<FuncType> func_type =
+ FuncType::make(ownvec<ValType>::make(),
+ ownvec<ValType>::make(ValType::make(::wasm::I32)));
+ own<Func> cpp_callback = Func::make(store(), func_type.get(), FailCallback,
+ reinterpret_cast<void*>(store()));
Extern* imports[] = {cpp_callback.get()};
Instantiate(imports);
+ // Use internal machinery to parse the module to find the function offsets.
+ // This makes the test more robust than hardcoding them.
+ i::Isolate* isolate =
+ reinterpret_cast<::wasm::StoreImpl*>(store())->i_isolate();
+ ModuleResult result = DecodeWasmModule(
+ kAllWasmFeatures, wire_bytes()->begin(), wire_bytes()->end(), false,
+ ModuleOrigin::kWasmOrigin, isolate->counters(),
+ isolate->wasm_engine()->allocator());
+ ASSERT_TRUE(result.ok());
+ const WasmFunction* func1 = &result.value()->functions[1];
+ const WasmFunction* func2 = &result.value()->functions[2];
+ const uint32_t func1_offset = func1->code.offset();
+ const uint32_t func2_offset = func2->code.offset();
+
Func* cpp_trapping_func = GetExportedFunction(0);
- own<Trap*> cpp_trap = cpp_trapping_func->call();
+ own<Trap> cpp_trap = cpp_trapping_func->call();
EXPECT_NE(nullptr, cpp_trap.get());
ExpectMessage("Uncaught Error: callback abort", cpp_trap->message());
+ own<Frame> frame = cpp_trap->origin();
+ EXPECT_TRUE(frame->instance()->same(instance()));
+ EXPECT_EQ(1u, frame->func_index());
+ EXPECT_EQ(1u, frame->func_offset());
+ EXPECT_EQ(func1_offset + frame->func_offset(), frame->module_offset());
+ ownvec<Frame> trace = cpp_trap->trace();
+ EXPECT_EQ(1u, trace.size());
+ frame.reset(trace[0].release());
+ EXPECT_TRUE(frame->instance()->same(instance()));
+ EXPECT_EQ(1u, frame->func_index());
+ EXPECT_EQ(1u, frame->func_offset());
+ EXPECT_EQ(func1_offset + frame->func_offset(), frame->module_offset());
Func* wasm_trapping_func = GetExportedFunction(1);
- own<Trap*> wasm_trap = wasm_trapping_func->call();
+ own<Trap> wasm_trap = wasm_trapping_func->call();
EXPECT_NE(nullptr, wasm_trap.get());
ExpectMessage("Uncaught RuntimeError: unreachable", wasm_trap->message());
+ frame = wasm_trap->origin();
+ EXPECT_TRUE(frame->instance()->same(instance()));
+ EXPECT_EQ(2u, frame->func_index());
+ EXPECT_EQ(5u, frame->func_offset());
+ EXPECT_EQ(func2_offset + frame->func_offset(), frame->module_offset());
+ trace = wasm_trap->trace();
+ EXPECT_EQ(1u, trace.size());
+ frame.reset(trace[0].release());
+ EXPECT_TRUE(frame->instance()->same(instance()));
+ EXPECT_EQ(2u, frame->func_index());
+ EXPECT_EQ(5u, frame->func_offset());
+ EXPECT_EQ(func2_offset + frame->func_offset(), frame->module_offset());
}
} // namespace wasm
diff --git a/deps/v8/test/wasm-api-tests/wasm-api-test.h b/deps/v8/test/wasm-api-tests/wasm-api-test.h
index cb1d9301e1..6fc70ef5f4 100644
--- a/deps/v8/test/wasm-api-tests/wasm-api-test.h
+++ b/deps/v8/test/wasm-api-tests/wasm-api-test.h
@@ -13,19 +13,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/wasm-api/wasm.hh"
-namespace wasm {
-
-// TODO(jkummerow): Drop these from the API.
-#ifdef DEBUG
-template <class T>
-void vec<T>::make_data() {}
-
-template <class T>
-void vec<T>::free_data() {}
-#endif
-
-} // namespace wasm
-
namespace v8 {
namespace internal {
namespace wasm {
@@ -40,6 +27,7 @@ using ::wasm::Instance;
using ::wasm::Memory;
using ::wasm::Module;
using ::wasm::own;
+using ::wasm::ownvec;
using ::wasm::Ref;
using ::wasm::Store;
using ::wasm::Table;
@@ -53,22 +41,23 @@ class WasmCapiTest : public ::testing::Test {
WasmCapiTest()
: Test(),
zone_(&allocator_, ZONE_NAME),
+ wire_bytes_(&zone_),
builder_(&zone_),
- exports_(vec<Extern*>::make()),
+ exports_(ownvec<Extern>::make()),
wasm_i_i_sig_(1, 1, wasm_i_i_sig_types_) {
engine_ = Engine::make();
store_ = Store::make(engine_.get());
cpp_i_i_sig_ =
- FuncType::make(vec<ValType*>::make(ValType::make(::wasm::I32)),
- vec<ValType*>::make(ValType::make(::wasm::I32)));
+ FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::I32)),
+ ownvec<ValType>::make(ValType::make(::wasm::I32)));
}
void Compile() {
- ZoneBuffer buffer(&zone_);
- builder_.WriteTo(&buffer);
- size_t size = buffer.end() - buffer.begin();
+ builder_.WriteTo(&wire_bytes_);
+ size_t size = wire_bytes_.end() - wire_bytes_.begin();
vec<byte_t> binary = vec<byte_t>::make(
- size, reinterpret_cast<byte_t*>(const_cast<byte*>(buffer.begin())));
+ size,
+ reinterpret_cast<byte_t*>(const_cast<byte*>(wire_bytes_.begin())));
module_ = Module::make(store_.get(), binary);
DCHECK_NE(module_.get(), nullptr);
@@ -91,7 +80,7 @@ class WasmCapiTest : public ::testing::Test {
Func* GetExportedFunction(size_t index) {
DCHECK_GT(exports_.size(), index);
- Extern* exported = exports_[index];
+ Extern* exported = exports_[index].get();
DCHECK_EQ(exported->kind(), ::wasm::EXTERN_FUNC);
Func* func = exported->func();
DCHECK_NE(func, nullptr);
@@ -100,7 +89,7 @@ class WasmCapiTest : public ::testing::Test {
Global* GetExportedGlobal(size_t index) {
DCHECK_GT(exports_.size(), index);
- Extern* exported = exports_[index];
+ Extern* exported = exports_[index].get();
DCHECK_EQ(exported->kind(), ::wasm::EXTERN_GLOBAL);
Global* global = exported->global();
DCHECK_NE(global, nullptr);
@@ -109,7 +98,7 @@ class WasmCapiTest : public ::testing::Test {
Memory* GetExportedMemory(size_t index) {
DCHECK_GT(exports_.size(), index);
- Extern* exported = exports_[index];
+ Extern* exported = exports_[index].get();
DCHECK_EQ(exported->kind(), ::wasm::EXTERN_MEMORY);
Memory* memory = exported->memory();
DCHECK_NE(memory, nullptr);
@@ -118,7 +107,7 @@ class WasmCapiTest : public ::testing::Test {
Table* GetExportedTable(size_t index) {
DCHECK_GT(exports_.size(), index);
- Extern* exported = exports_[index];
+ Extern* exported = exports_[index].get();
DCHECK_EQ(exported->kind(), ::wasm::EXTERN_TABLE);
Table* table = exported->table();
DCHECK_NE(table, nullptr);
@@ -126,6 +115,7 @@ class WasmCapiTest : public ::testing::Test {
}
void Shutdown() {
+ exports_.reset();
instance_.reset();
module_.reset();
store_.reset();
@@ -136,7 +126,9 @@ class WasmCapiTest : public ::testing::Test {
Engine* engine() { return engine_.get(); }
Store* store() { return store_.get(); }
Module* module() { return module_.get(); }
- const vec<Extern*>& exports() { return exports_; }
+ Instance* instance() { return instance_.get(); }
+ const ownvec<Extern>& exports() { return exports_; }
+ ZoneBuffer* wire_bytes() { return &wire_bytes_; }
FunctionSig* wasm_i_i_sig() { return &wasm_i_i_sig_; }
FuncType* cpp_i_i_sig() { return cpp_i_i_sig_.get(); }
@@ -144,13 +136,14 @@ class WasmCapiTest : public ::testing::Test {
private:
AccountingAllocator allocator_;
Zone zone_;
+ ZoneBuffer wire_bytes_;
WasmModuleBuilder builder_;
- own<Engine*> engine_;
- own<Store*> store_;
- own<Module*> module_;
- own<Instance*> instance_;
- vec<Extern*> exports_;
- own<FuncType*> cpp_i_i_sig_;
+ own<Engine> engine_;
+ own<Store> store_;
+ own<Module> module_;
+ own<Instance> instance_;
+ ownvec<Extern> exports_;
+ own<FuncType> cpp_i_i_sig_;
ValueType wasm_i_i_sig_types_[2] = {kWasmI32, kWasmI32};
FunctionSig wasm_i_i_sig_;
};
diff --git a/deps/v8/test/wasm-js/OWNERS b/deps/v8/test/wasm-js/OWNERS
index 4b6b34d24a..32941e6257 100644
--- a/deps/v8/test/wasm-js/OWNERS
+++ b/deps/v8/test/wasm-js/OWNERS
@@ -1 +1 @@
-file://src/wasm/OWNERS
+file:../../src/wasm/OWNERS
diff --git a/deps/v8/test/wasm-js/testcfg.py b/deps/v8/test/wasm-js/testcfg.py
index 3f3c67ac6a..197d9195f1 100644
--- a/deps/v8/test/wasm-js/testcfg.py
+++ b/deps/v8/test/wasm-js/testcfg.py
@@ -13,6 +13,21 @@ WPT_ROOT = "/wasm/jsapi/"
META_SCRIPT_REGEXP = re.compile(r"META:\s*script=(.*)")
META_TIMEOUT_REGEXP = re.compile(r"META:\s*timeout=(.*)")
+proposal_flags = [{
+ 'name': 'reference-types',
+ 'flags': ['--experimental-wasm-anyref',
+ '--no-experimental-wasm-bulk-memory']
+ },
+ {
+ 'name': 'bulk-memory-operations',
+ 'flags': ['--experimental-wasm-bulk-memory']
+ },
+ {
+ 'name': 'js-types',
+ 'flags': ['--experimental-wasm-type-reflection',
+ '--no-experimental-wasm-bulk-memory']
+ }]
+
class TestLoader(testsuite.JSTestLoader):
@property
@@ -25,7 +40,7 @@ class TestSuite(testsuite.TestSuite):
super(TestSuite, self).__init__(*args, **kwargs)
self.mjsunit_js = os.path.join(os.path.dirname(self.root), "mjsunit",
"mjsunit.js")
- self.test_root = os.path.join(self.root, "data", "test", "js-api")
+ self.test_root = os.path.join(self.root, "tests")
self._test_loader.test_root = self.test_root
def _test_loader_class(self):
@@ -34,6 +49,8 @@ class TestSuite(testsuite.TestSuite):
def _test_class(self):
return TestCase
+def get_proposal_path_identifier(proposal):
+ return os.sep.join(['proposals', proposal['name']])
class TestCase(testcase.D8TestCase):
def _get_timeout_param(self):
@@ -50,19 +67,27 @@ class TestCase(testcase.D8TestCase):
return None
def _get_files_params(self):
- files = [os.path.join(self.suite.mjsunit_js),
+ files = [self.suite.mjsunit_js,
os.path.join(self.suite.root, "testharness.js")]
source = self.get_source()
+ current_dir = os.path.dirname(self._get_source_path())
for script in META_SCRIPT_REGEXP.findall(source):
if script.startswith(WPT_ROOT):
# Matched an absolute path, strip the root and replace it with our
# local root.
- script = os.path.join(self.suite.test_root, script[len(WPT_ROOT):])
+ found = False
+ for proposal in proposal_flags:
+ if get_proposal_path_identifier(proposal) in current_dir:
+ found = True
+ script = os.path.join(self.suite.test_root,
+ os.sep.join(['proposals', proposal['name']]),
+ script[len(WPT_ROOT):])
+ if not found:
+ script = os.path.join(self.suite.test_root, script[len(WPT_ROOT):])
elif not script.startswith("/"):
# Matched a relative path, prepend this test's directory.
- thisdir = os.path.dirname(self._get_source_path())
- script = os.path.join(thisdir, script)
+ script = os.path.join(current_dir, script)
else:
raise Exception("Unexpected absolute path for script: \"%s\"" % script);
@@ -74,6 +99,12 @@ class TestCase(testcase.D8TestCase):
])
return files
+ def _get_source_flags(self):
+ for proposal in proposal_flags:
+ if get_proposal_path_identifier(proposal) in self.path:
+ return proposal['flags']
+ return []
+
def _get_source_path(self):
# All tests are named `path/name.any.js`
return os.path.join(self.suite.test_root, self.path + ANY_JS)
diff --git a/deps/v8/test/wasm-js/tests.tar.gz.sha1 b/deps/v8/test/wasm-js/tests.tar.gz.sha1
new file mode 100644
index 0000000000..ec8be70e2a
--- /dev/null
+++ b/deps/v8/test/wasm-js/tests.tar.gz.sha1
@@ -0,0 +1 @@
+26e59563060bd6de4adbb4021684e8cf38fe71c8 \ No newline at end of file
diff --git a/deps/v8/test/wasm-js/wasm-js.status b/deps/v8/test/wasm-js/wasm-js.status
index 51961fd46d..42ad2a4152 100644
--- a/deps/v8/test/wasm-js/wasm-js.status
+++ b/deps/v8/test/wasm-js/wasm-js.status
@@ -6,6 +6,7 @@
[ALWAYS, {
# https://bugs.chromium.org/p/v8/issues/detail?id=8633
'limits': [SKIP],
+ 'proposals/reference-types/limits': [SKIP],
}], # ALWAYS
['arch == s390 or arch == s390x or system == aix', {
diff --git a/deps/v8/test/wasm-spec-tests/testcfg.py b/deps/v8/test/wasm-spec-tests/testcfg.py
index 34230b07d0..e0bd19f268 100644
--- a/deps/v8/test/wasm-spec-tests/testcfg.py
+++ b/deps/v8/test/wasm-spec-tests/testcfg.py
@@ -10,27 +10,36 @@ from testrunner.objects import testcase
proposal_flags = [{
'name': 'reference-types',
'flags': ['--experimental-wasm-anyref',
- '--no-experimental-wasm-bulk-memory']
+ '--no-experimental-wasm-bulk-memory']
},
{
'name': 'bulk-memory-operations',
'flags': ['--experimental-wasm-bulk-memory']
+ },
+ {
+ 'name': 'js-types',
+ 'flags': ['--experimental-wasm-type-reflection',
+ '--no-experimental-wasm-bulk-memory']
}]
class TestLoader(testsuite.JSTestLoader):
pass
class TestSuite(testsuite.TestSuite):
+ def __init__(self, *args, **kwargs):
+ super(TestSuite, self).__init__(*args, **kwargs)
+ self.test_root = os.path.join(self.root, "tests")
+ self._test_loader.test_root = self.test_root
+
def _test_loader_class(self):
return TestLoader
def _test_class(self):
return TestCase
-
class TestCase(testcase.D8TestCase):
def _get_files_params(self):
- return [os.path.join(self.suite.root, self.path + self._get_suffix())]
+ return [os.path.join(self.suite.test_root, self.path + self._get_suffix())]
def _get_source_flags(self):
for proposal in proposal_flags:
diff --git a/deps/v8/test/wasm-spec-tests/tests.tar.gz.sha1 b/deps/v8/test/wasm-spec-tests/tests.tar.gz.sha1
index 0b068afe0a..36c9e08ac1 100644
--- a/deps/v8/test/wasm-spec-tests/tests.tar.gz.sha1
+++ b/deps/v8/test/wasm-spec-tests/tests.tar.gz.sha1
@@ -1 +1 @@
-b02f00e24b28ad76537a10a788a8be966c3577bd \ No newline at end of file
+d9e649f4ea6da6bd18999795201c2bd138c0d786 \ No newline at end of file
diff --git a/deps/v8/test/wasm-spec-tests/wasm-spec-tests.status b/deps/v8/test/wasm-spec-tests/wasm-spec-tests.status
index e61f5ceb26..16faaaed35 100644
--- a/deps/v8/test/wasm-spec-tests/wasm-spec-tests.status
+++ b/deps/v8/test/wasm-spec-tests/wasm-spec-tests.status
@@ -5,56 +5,75 @@
[
[ALWAYS, {
#TODO(ahaas): Add additional stack checks on mips.
- 'tests/skip-stack-guard-page': [PASS, ['arch == mipsel or arch == mips64el or ((arch == ppc or arch == ppc64 or arch == s390 or arch == s390x) and simulator_run)', SKIP]],
+ 'skip-stack-guard-page': [PASS, ['arch == mipsel or arch == mips64el or ((arch == ppc or arch == ppc64 or arch == s390 or arch == s390x) and simulator_run)', SKIP]],
# TODO(v8:9144): The MVP behavior when bounds-checking segments changed in
# the bulk-memory proposal. Since we've enabled bulk-memory by default, we
# need to update to use its testsuite.
- 'tests/linking': [FAIL],
-
- # TODO(ahaas): Needs investigation, I disable the test for now.
- 'tests/conversions': [PASS, ['system == windows and arch == ia32', FAIL]],
-
- # TODO(ahaas): Incorporate recent changes to the bulk-memory-operations
- # proposal.
- 'tests/proposals/bulk-memory-operations/elem': [FAIL],
- 'tests/proposals/bulk-memory-operations/data': [FAIL],
+ 'linking': [FAIL],
+ 'elem': [FAIL],
+ 'data': [FAIL],
+ # TODO(v8:9658): The encoding of element segments changed in the bulk memory
+ # proposal
+ 'proposals/bulk-memory-operations/bulk': [FAIL],
+ 'proposals/bulk-memory-operations/table_init': [FAIL],
+ 'proposals/bulk-memory-operations/table_copy': [FAIL],
+ 'proposals/bulk-memory-operations/elem': [FAIL],
+ 'proposals/bulk-memory-operations/binary': [FAIL],
+ # TODO(mstarzinger): Roll newest tests into "js-types" repository.
+ 'proposals/js-types/exports': [FAIL],
+ 'proposals/js-types/globals': [FAIL],
+ 'proposals/js-types/linking': [FAIL],
}], # ALWAYS
['arch == mipsel or arch == mips64el or arch == mips or arch == mips64', {
# These tests fail because mips does not support the correct NaN bit patterns.
- 'tests/float_misc': [SKIP],
- 'tests/float_exprs': [SKIP],
- 'tests/f32': [SKIP],
- 'tests/f64': [SKIP],
- 'tests/f32_bitwise': [SKIP],
- 'tests/f64_bitwise': [SKIP],
+ 'float_misc': [SKIP],
+ 'float_exprs': [SKIP],
+ 'f32': [SKIP],
+ 'f64': [SKIP],
+ 'f32_bitwise': [SKIP],
+ 'f64_bitwise': [SKIP],
+ 'proposals/reference-types/conversions': [SKIP],
+ 'proposals/bulk-memory-operations/conversions': [SKIP],
+ 'proposals/js-types/f32': [SKIP],
+ 'proposals/js-types/f64': [SKIP],
+ 'proposals/js-types/f32_bitwise': [SKIP],
+ 'proposals/js-types/f64_bitwise': [SKIP],
+ 'proposals/js-types/float_exprs': [SKIP],
+ 'proposals/js-types/float_misc': [SKIP],
+ 'proposals/js-types/conversions': [SKIP],
}], # 'arch == mipsel or arch == mips64el or arch == mips or arch == mips64'
['(arch == mipsel or arch == mips64el or arch == mips or arch == mips64) and not simulator_run', {
# This test fail because mips does not support the correct NaN bit patterns.
# But it doesn't fail in simulator.
- 'tests/conversions': [SKIP],
+ 'conversions': [SKIP],
}], # '(arch == mipsel or arch == mips64el or arch == mips or arch == mips64) and not simulator_run'
['arch == arm and not simulator_run', {
# Too slow on chromebooks.
- 'tests/br_table': [SKIP],
+ 'br_table': [SKIP],
}], # 'arch == arm and not simulator_run'
['arch == ppc or arch == ppc64', {
# These tests fail because ppc float min and max doesn't convert sNaN to qNaN.
- 'tests/f32': [SKIP],
- 'tests/f64': [SKIP],
+ 'f32': [SKIP],
+ 'f64': [SKIP],
+ 'proposals/js-types/f32': [SKIP],
+ 'proposals/js-types/f64': [SKIP],
# This test fails because ppc float to double doesn't convert sNaN to qNaN.
- 'tests/conversions': [SKIP],
- 'tests/proposals/reference-types/conversions': [SKIP],
- 'tests/proposals/bulk-memory-operations/conversions': [SKIP],
+ 'conversions': [SKIP],
+ 'proposals/reference-types/conversions': [SKIP],
+ 'proposals/bulk-memory-operations/conversions': [SKIP],
+ 'proposals/js-types/conversions': [SKIP],
}], # 'arch == ppc or arch == ppc64'
['arch == s390 or arch == s390x', {
# These tests fail because s390 float min and max doesn't convert sNaN to qNaN.
- 'tests/f32': [SKIP],
- 'tests/f64': [SKIP],
+ 'f32': [SKIP],
+ 'f64': [SKIP],
+ 'proposals/js-types/f32': [SKIP],
+ 'proposals/js-types/f64': [SKIP],
}], # 'arch == s390 or arch == s390x'
##############################################################################
diff --git a/deps/v8/testing/OWNERS b/deps/v8/testing/OWNERS
index bdb1d555a4..cb04fa0838 100644
--- a/deps/v8/testing/OWNERS
+++ b/deps/v8/testing/OWNERS
@@ -1 +1 @@
-file://INFRA_OWNERS
+file:../INFRA_OWNERS
diff --git a/deps/v8/third_party/binutils/OWNERS b/deps/v8/third_party/binutils/OWNERS
index bdb1d555a4..09e0096a2e 100644
--- a/deps/v8/third_party/binutils/OWNERS
+++ b/deps/v8/third_party/binutils/OWNERS
@@ -1 +1 @@
-file://INFRA_OWNERS
+file:../../INFRA_OWNERS
diff --git a/deps/v8/third_party/colorama/OWNERS b/deps/v8/third_party/colorama/OWNERS
index bdb1d555a4..09e0096a2e 100644
--- a/deps/v8/third_party/colorama/OWNERS
+++ b/deps/v8/third_party/colorama/OWNERS
@@ -1 +1 @@
-file://INFRA_OWNERS
+file:../../INFRA_OWNERS
diff --git a/deps/v8/third_party/inspector_protocol/README.v8 b/deps/v8/third_party/inspector_protocol/README.v8
index 622ff72f74..a092e3e7a1 100644
--- a/deps/v8/third_party/inspector_protocol/README.v8
+++ b/deps/v8/third_party/inspector_protocol/README.v8
@@ -2,7 +2,7 @@ Name: inspector protocol
Short Name: inspector_protocol
URL: https://chromium.googlesource.com/deps/inspector_protocol/
Version: 0
-Revision: 373efb7fe33a7ae84038868ed08b9f1bd328b55d
+Revision: d114a62e144cdfdae697fe0af6581ce39a31af37
License: BSD
License File: LICENSE
Security Critical: no
diff --git a/deps/v8/third_party/inspector_protocol/code_generator.py b/deps/v8/third_party/inspector_protocol/code_generator.py
index 5cf5a308c5..7c72cc70e4 100755
--- a/deps/v8/third_party/inspector_protocol/code_generator.py
+++ b/deps/v8/third_party/inspector_protocol/code_generator.py
@@ -43,9 +43,6 @@ def read_config():
items = [(k, os.path.join(output_base, v) if k == "output" else v)
for (k, v) in items]
keys, values = list(zip(*items))
- # 'async' is a keyword since Python 3.7.
- # Avoid namedtuple(rename=True) for compatibility with Python 2.X.
- keys = tuple('async_' if k == 'async' else k for k in keys)
return collections.namedtuple('X', keys)(*values)
return json.loads(data, object_hook=json_object_hook)
@@ -558,7 +555,7 @@ class Protocol(object):
if not self.config.protocol.options:
return False
return self.check_options(self.config.protocol.options, domain, command,
- "async_", None, False)
+ "async", None, False)
def is_exported(self, domain, name):
if not self.config.protocol.options:
diff --git a/deps/v8/third_party/inspector_protocol/encoding/encoding.cc b/deps/v8/third_party/inspector_protocol/encoding/encoding.cc
index 1da7c45aa3..6e5619d00e 100644
--- a/deps/v8/third_party/inspector_protocol/encoding/encoding.cc
+++ b/deps/v8/third_party/inspector_protocol/encoding/encoding.cc
@@ -53,6 +53,10 @@ std::string Status::ToASCIIString() const {
return ToASCIIString("CBOR: invalid double");
case Error::CBOR_INVALID_ENVELOPE:
return ToASCIIString("CBOR: invalid envelope");
+ case Error::CBOR_ENVELOPE_CONTENTS_LENGTH_MISMATCH:
+ return ToASCIIString("CBOR: envelope contents length mismatch");
+ case Error::CBOR_MAP_OR_ARRAY_EXPECTED_IN_ENVELOPE:
+ return ToASCIIString("CBOR: map or array expected in envelope");
case Error::CBOR_INVALID_STRING8:
return ToASCIIString("CBOR: invalid string8");
case Error::CBOR_INVALID_STRING16:
@@ -929,6 +933,9 @@ bool ParseArray(int32_t stack_depth,
bool ParseValue(int32_t stack_depth,
CBORTokenizer* tokenizer,
StreamingParserHandler* out);
+bool ParseEnvelope(int32_t stack_depth,
+ CBORTokenizer* tokenizer,
+ StreamingParserHandler* out);
void ParseUTF16String(CBORTokenizer* tokenizer, StreamingParserHandler* out) {
std::vector<uint16_t> value;
@@ -946,6 +953,52 @@ bool ParseUTF8String(CBORTokenizer* tokenizer, StreamingParserHandler* out) {
return true;
}
+bool ParseEnvelope(int32_t stack_depth,
+ CBORTokenizer* tokenizer,
+ StreamingParserHandler* out) {
+ assert(tokenizer->TokenTag() == CBORTokenTag::ENVELOPE);
+ // Before we enter the envelope, we save the position that we
+ // expect to see after we're done parsing the envelope contents.
+ // This way we can compare and produce an error if the contents
+ // didn't fit exactly into the envelope length.
+ size_t pos_past_envelope = tokenizer->Status().pos +
+ kEncodedEnvelopeHeaderSize +
+ tokenizer->GetEnvelopeContents().size();
+ tokenizer->EnterEnvelope();
+ switch (tokenizer->TokenTag()) {
+ case CBORTokenTag::ERROR_VALUE:
+ out->HandleError(tokenizer->Status());
+ return false;
+ case CBORTokenTag::MAP_START:
+ if (!ParseMap(stack_depth + 1, tokenizer, out))
+ return false;
+ break; // Continue to check pos_past_envelope below.
+ case CBORTokenTag::ARRAY_START:
+ if (stack_depth == 0) { // Not allowed at the top level.
+ out->HandleError(
+ Status{Error::CBOR_MAP_START_EXPECTED, tokenizer->Status().pos});
+ return false;
+ }
+ if (!ParseArray(stack_depth + 1, tokenizer, out))
+ return false;
+ break; // Continue to check pos_past_envelope below.
+ default:
+ out->HandleError(Status{
+ stack_depth == 0 ? Error::CBOR_MAP_START_EXPECTED
+ : Error::CBOR_MAP_OR_ARRAY_EXPECTED_IN_ENVELOPE,
+ tokenizer->Status().pos});
+ return false;
+ }
+ // The contents of the envelope parsed OK, now check that we're at
+ // the expected position.
+ if (pos_past_envelope != tokenizer->Status().pos) {
+ out->HandleError(Status{Error::CBOR_ENVELOPE_CONTENTS_LENGTH_MISMATCH,
+ tokenizer->Status().pos});
+ return false;
+ }
+ return true;
+}
+
bool ParseValue(int32_t stack_depth,
CBORTokenizer* tokenizer,
StreamingParserHandler* out) {
@@ -954,9 +1007,6 @@ bool ParseValue(int32_t stack_depth,
Status{Error::CBOR_STACK_LIMIT_EXCEEDED, tokenizer->Status().pos});
return false;
}
- // Skip past the envelope to get to what's inside.
- if (tokenizer->TokenTag() == CBORTokenTag::ENVELOPE)
- tokenizer->EnterEnvelope();
switch (tokenizer->TokenTag()) {
case CBORTokenTag::ERROR_VALUE:
out->HandleError(tokenizer->Status());
@@ -965,6 +1015,8 @@ bool ParseValue(int32_t stack_depth,
out->HandleError(Status{Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE,
tokenizer->Status().pos});
return false;
+ case CBORTokenTag::ENVELOPE:
+ return ParseEnvelope(stack_depth, tokenizer, out);
case CBORTokenTag::TRUE_VALUE:
out->HandleBool(true);
tokenizer->Next();
@@ -1091,13 +1143,7 @@ void ParseCBOR(span<uint8_t> bytes, StreamingParserHandler* out) {
// We checked for the envelope start byte above, so the tokenizer
// must agree here, since it's not an error.
assert(tokenizer.TokenTag() == CBORTokenTag::ENVELOPE);
- tokenizer.EnterEnvelope();
- if (tokenizer.TokenTag() != CBORTokenTag::MAP_START) {
- out->HandleError(
- Status{Error::CBOR_MAP_START_EXPECTED, tokenizer.Status().pos});
- return;
- }
- if (!ParseMap(/*stack_depth=*/1, &tokenizer, out))
+ if (!ParseEnvelope(/*stack_depth=*/0, &tokenizer, out))
return;
if (tokenizer.TokenTag() == CBORTokenTag::DONE)
return;
diff --git a/deps/v8/third_party/inspector_protocol/encoding/encoding.h b/deps/v8/third_party/inspector_protocol/encoding/encoding.h
index 340667f604..c9ddd3a9be 100644
--- a/deps/v8/third_party/inspector_protocol/encoding/encoding.h
+++ b/deps/v8/third_party/inspector_protocol/encoding/encoding.h
@@ -125,21 +125,23 @@ enum class Error {
CBOR_INVALID_INT32 = 0x0e,
CBOR_INVALID_DOUBLE = 0x0f,
CBOR_INVALID_ENVELOPE = 0x10,
- CBOR_INVALID_STRING8 = 0x11,
- CBOR_INVALID_STRING16 = 0x12,
- CBOR_INVALID_BINARY = 0x13,
- CBOR_UNSUPPORTED_VALUE = 0x14,
- CBOR_NO_INPUT = 0x15,
- CBOR_INVALID_START_BYTE = 0x16,
- CBOR_UNEXPECTED_EOF_EXPECTED_VALUE = 0x17,
- CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x18,
- CBOR_UNEXPECTED_EOF_IN_MAP = 0x19,
- CBOR_INVALID_MAP_KEY = 0x1a,
- CBOR_STACK_LIMIT_EXCEEDED = 0x1b,
- CBOR_TRAILING_JUNK = 0x1c,
- CBOR_MAP_START_EXPECTED = 0x1d,
- CBOR_MAP_STOP_EXPECTED = 0x1e,
- CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED = 0x1f,
+ CBOR_ENVELOPE_CONTENTS_LENGTH_MISMATCH = 0x11,
+ CBOR_MAP_OR_ARRAY_EXPECTED_IN_ENVELOPE = 0x12,
+ CBOR_INVALID_STRING8 = 0x13,
+ CBOR_INVALID_STRING16 = 0x14,
+ CBOR_INVALID_BINARY = 0x15,
+ CBOR_UNSUPPORTED_VALUE = 0x16,
+ CBOR_NO_INPUT = 0x17,
+ CBOR_INVALID_START_BYTE = 0x18,
+ CBOR_UNEXPECTED_EOF_EXPECTED_VALUE = 0x19,
+ CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x1a,
+ CBOR_UNEXPECTED_EOF_IN_MAP = 0x1b,
+ CBOR_INVALID_MAP_KEY = 0x1c,
+ CBOR_STACK_LIMIT_EXCEEDED = 0x1d,
+ CBOR_TRAILING_JUNK = 0x1e,
+ CBOR_MAP_START_EXPECTED = 0x1f,
+ CBOR_MAP_STOP_EXPECTED = 0x20,
+ CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED = 0x21,
};
// A status value with position that can be copied. The default status
diff --git a/deps/v8/third_party/inspector_protocol/encoding/encoding_test.cc b/deps/v8/third_party/inspector_protocol/encoding/encoding_test.cc
index 768e19bb9e..a36b200bad 100644
--- a/deps/v8/third_party/inspector_protocol/encoding/encoding_test.cc
+++ b/deps/v8/third_party/inspector_protocol/encoding/encoding_test.cc
@@ -979,6 +979,72 @@ TEST(ParseCBORTest, UnexpectedEofInMapError) {
EXPECT_EQ("", out);
}
+TEST(ParseCBORTest, TopLevelCantBeEmptyEnvelope) {
+ // Normally, an array would be allowed inside an envelope, but
+ // the top-level envelope is required to contain a map.
+ std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, 0}; // envelope
+ std::string out;
+ Status status;
+ std::unique_ptr<StreamingParserHandler> json_writer =
+ NewJSONEncoder(&GetTestPlatform(), &out, &status);
+ ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+ EXPECT_EQ(Error::CBOR_MAP_START_EXPECTED, status.error);
+ EXPECT_EQ(bytes.size(), status.pos);
+ EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, MapStartExpectedAtTopLevel) {
+ // Normally, an array would be allowed inside an envelope, but
+ // the top-level envelope is required to contain a map.
+ constexpr uint8_t kPayloadLen = 1;
+ std::vector<uint8_t> bytes = {0xd8,
+ 0x5a,
+ 0,
+ 0,
+ 0,
+ kPayloadLen, // envelope
+ EncodeIndefiniteLengthArrayStart()};
+ EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+ std::string out;
+ Status status;
+ std::unique_ptr<StreamingParserHandler> json_writer =
+ NewJSONEncoder(&GetTestPlatform(), &out, &status);
+ ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+ EXPECT_EQ(Error::CBOR_MAP_START_EXPECTED, status.error);
+ EXPECT_EQ(6u, status.pos);
+ EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, OnlyMapsAndArraysSupportedInsideEnvelopes) {
+ // The top level is a map with key "foo", and the value
+ // is an envelope that contains just a number (1). We don't
+ // allow numbers to be contained in an envelope though, only
+ // maps and arrays.
+ constexpr uint8_t kPayloadLen = 1;
+ std::vector<uint8_t> bytes = {0xd8,
+ 0x5a,
+ 0,
+ 0,
+ 0,
+ kPayloadLen, // envelope
+ EncodeIndefiniteLengthMapStart()};
+ EncodeString8(SpanFrom("foo"), &bytes);
+ for (uint8_t byte : {0xd8, 0x5a, 0, 0, 0, /*payload_len*/ 1})
+ bytes.emplace_back(byte);
+ size_t error_pos = bytes.size();
+ bytes.push_back(1); // Envelope contents / payload = number 1.
+ bytes.emplace_back(EncodeStop());
+
+ std::string out;
+ Status status;
+ std::unique_ptr<StreamingParserHandler> json_writer =
+ NewJSONEncoder(&GetTestPlatform(), &out, &status);
+ ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+ EXPECT_EQ(Error::CBOR_MAP_OR_ARRAY_EXPECTED_IN_ENVELOPE, status.error);
+ EXPECT_EQ(error_pos, status.pos);
+ EXPECT_EQ("", out);
+}
+
TEST(ParseCBORTest, InvalidMapKeyError) {
constexpr uint8_t kPayloadLen = 2;
std::vector<uint8_t> bytes = {0xd8, 0x5a, 0,
@@ -1195,18 +1261,18 @@ TEST(ParseCBORTest, InvalidSignedError) {
}
TEST(ParseCBORTest, TrailingJunk) {
- constexpr uint8_t kPayloadLen = 35;
+ constexpr uint8_t kPayloadLen = 12;
std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope
0xbf}; // map start
EncodeString8(SpanFrom("key"), &bytes);
EncodeString8(SpanFrom("value"), &bytes);
bytes.push_back(0xff); // Up to here, it's a perfectly fine msg.
+ ASSERT_EQ(kPayloadLen, bytes.size() - 6);
size_t error_pos = bytes.size();
+ // Now write some trailing junk after the message.
EncodeString8(SpanFrom("trailing junk"), &bytes);
-
internals::WriteTokenStart(MajorType::UNSIGNED,
std::numeric_limits<uint64_t>::max(), &bytes);
- EXPECT_EQ(kPayloadLen, bytes.size() - 6);
std::string out;
Status status;
std::unique_ptr<StreamingParserHandler> json_writer =
@@ -1217,6 +1283,29 @@ TEST(ParseCBORTest, TrailingJunk) {
EXPECT_EQ("", out);
}
+TEST(ParseCBORTest, EnvelopeContentsLengthMismatch) {
+ constexpr uint8_t kPartialPayloadLen = 5;
+ std::vector<uint8_t> bytes = {0xd8, 0x5a, 0,
+ 0, 0, kPartialPayloadLen, // envelope
+ 0xbf}; // map start
+ EncodeString8(SpanFrom("key"), &bytes);
+ // kPartialPayloadLen would need to indicate the length of the entire map,
+ // all the way past the 0xff map stop character. Instead, it only covers
+ // a portion of the map.
+ EXPECT_EQ(bytes.size() - 6, kPartialPayloadLen);
+ EncodeString8(SpanFrom("value"), &bytes);
+ bytes.push_back(0xff); // map stop
+
+ std::string out;
+ Status status;
+ std::unique_ptr<StreamingParserHandler> json_writer =
+ NewJSONEncoder(&GetTestPlatform(), &out, &status);
+ ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+ EXPECT_EQ(Error::CBOR_ENVELOPE_CONTENTS_LENGTH_MISMATCH, status.error);
+ EXPECT_EQ(bytes.size(), status.pos);
+ EXPECT_EQ("", out);
+}
+
// =============================================================================
// cbor::AppendString8EntryToMap - for limited in-place editing of messages
// =============================================================================
@@ -1376,7 +1465,7 @@ TEST(JsonEncoder, IncompleteUtf8Sequence) {
{ // 🌎 takes four bytes to encode in UTF-8. We test with the first three;
// This means we're trying to emit a string that consists solely of an
- // incomplete UTF-8 sequence. So the string in the JSON output is emtpy.
+ // incomplete UTF-8 sequence. So the string in the JSON output is empty.
std::string world_utf8 = "🌎";
ASSERT_EQ(4u, world_utf8.size());
std::vector<uint8_t> chars(world_utf8.begin(), world_utf8.begin() + 3);
diff --git a/deps/v8/third_party/v8/builtins/array-sort.tq b/deps/v8/third_party/v8/builtins/array-sort.tq
index 530ed4faf9..04184d9676 100644
--- a/deps/v8/third_party/v8/builtins/array-sort.tq
+++ b/deps/v8/third_party/v8/builtins/array-sort.tq
@@ -15,7 +15,7 @@
namespace array {
class SortState extends Struct {
- Compare(implicit context: Context)(x: Object, y: Object): Number {
+ Compare(implicit context: Context)(x: JSAny, y: JSAny): Number {
const sortCompare: CompareBuiltinFn = this.sortComparePtr;
return sortCompare(context, this.userCmpFn, x, y);
}
@@ -143,7 +143,7 @@ namespace array {
let canUseSameAccessorFn: CanUseSameAccessorFn;
try {
- GotoIfForceSlowPath() otherwise Slow;
+ if (IsForceSlowPath()) goto Slow;
const a: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
// Copy copy-on-write (COW) arrays.
@@ -214,12 +214,12 @@ namespace array {
// it is first requested, but it has always at least this size.
const kSortStateTempSize: Smi = 32;
- type LoadFn = builtin(Context, SortState, Smi) => Object;
- type StoreFn = builtin(Context, SortState, Smi, Object) => Smi;
+ type LoadFn = builtin(Context, SortState, Smi) => (JSAny | TheHole);
+ type StoreFn = builtin(Context, SortState, Smi, JSAny) => Smi;
type DeleteFn = builtin(Context, SortState, Smi) => Smi;
- type CanUseSameAccessorFn = builtin(Context, JSReceiver, Object, Number) =>
+ type CanUseSameAccessorFn = builtin(Context, JSReceiver, Map, Number) =>
Boolean;
- type CompareBuiltinFn = builtin(Context, Object, Object, Object) => Number;
+ type CompareBuiltinFn = builtin(Context, JSAny, JSAny, JSAny) => Number;
// The following builtins implement Load/Store for all the Accessors.
// The most generic baseline version uses Get-/SetProperty. We do not need
@@ -228,28 +228,28 @@ namespace array {
// through a hole.
transitioning builtin Load<ElementsAccessor: type>(
- context: Context, sortState: SortState, index: Smi): Object {
+ context: Context, sortState: SortState, index: Smi): JSAny | TheHole {
const receiver = sortState.receiver;
if (!HasProperty_Inline(receiver, index)) return TheHole;
return GetProperty(receiver, index);
}
Load<FastSmiElements>(context: Context, sortState: SortState, index: Smi):
- Object {
+ JSAny | TheHole {
const object = UnsafeCast<JSObject>(sortState.receiver);
const elements = UnsafeCast<FixedArray>(object.elements);
- return elements.objects[index];
+ return UnsafeCast<(JSAny | TheHole)>(elements.objects[index]);
}
Load<FastObjectElements>(context: Context, sortState: SortState, index: Smi):
- Object {
+ JSAny | TheHole {
const object = UnsafeCast<JSObject>(sortState.receiver);
const elements = UnsafeCast<FixedArray>(object.elements);
- return elements.objects[index];
+ return UnsafeCast<(JSAny | TheHole)>(elements.objects[index]);
}
Load<FastDoubleElements>(context: Context, sortState: SortState, index: Smi):
- Object {
+ JSAny | TheHole {
try {
const object = UnsafeCast<JSObject>(sortState.receiver);
const elements = UnsafeCast<FixedDoubleArray>(object.elements);
@@ -262,13 +262,13 @@ namespace array {
}
transitioning builtin Store<ElementsAccessor: type>(
- context: Context, sortState: SortState, index: Smi, value: Object): Smi {
+ context: Context, sortState: SortState, index: Smi, value: JSAny): Smi {
SetProperty(sortState.receiver, index, value);
return kSuccess;
}
Store<FastSmiElements>(
- context: Context, sortState: SortState, index: Smi, value: Object): Smi {
+ context: Context, sortState: SortState, index: Smi, value: JSAny): Smi {
const object = UnsafeCast<JSObject>(sortState.receiver);
const elements = UnsafeCast<FixedArray>(object.elements);
const value = UnsafeCast<Smi>(value);
@@ -277,7 +277,7 @@ namespace array {
}
Store<FastObjectElements>(
- context: Context, sortState: SortState, index: Smi, value: Object): Smi {
+ context: Context, sortState: SortState, index: Smi, value: JSAny): Smi {
const object = UnsafeCast<JSObject>(sortState.receiver);
const elements = UnsafeCast<FixedArray>(object.elements);
elements.objects[index] = value;
@@ -285,7 +285,7 @@ namespace array {
}
Store<FastDoubleElements>(
- context: Context, sortState: SortState, index: Smi, value: Object): Smi {
+ context: Context, sortState: SortState, index: Smi, value: JSAny): Smi {
const object = UnsafeCast<JSObject>(sortState.receiver);
const elements = UnsafeCast<FixedDoubleArray>(object.elements);
const heapVal = UnsafeCast<HeapNumber>(value);
@@ -333,7 +333,7 @@ namespace array {
}
transitioning builtin SortCompareDefault(
- context: Context, comparefn: Object, x: Object, y: Object): Number {
+ context: Context, comparefn: JSAny, x: JSAny, y: JSAny): Number {
assert(comparefn == Undefined);
if (TaggedIsSmi(x) && TaggedIsSmi(y)) {
@@ -361,7 +361,7 @@ namespace array {
}
transitioning builtin SortCompareUserFn(
- context: Context, comparefn: Object, x: Object, y: Object): Number {
+ context: Context, comparefn: JSAny, x: JSAny, y: JSAny): Number {
assert(comparefn != Undefined);
const cmpfn = UnsafeCast<Callable>(comparefn);
@@ -376,7 +376,7 @@ namespace array {
}
builtin CanUseSameAccessor<ElementsAccessor: type>(
- context: Context, receiver: JSReceiver, initialReceiverMap: Object,
+ context: Context, receiver: JSReceiver, initialReceiverMap: Map,
initialReceiverLength: Number): Boolean {
if (receiver.map != initialReceiverMap) return False;
@@ -389,7 +389,7 @@ namespace array {
}
CanUseSameAccessor<GenericElementsAccessor>(
- _context: Context, _receiver: JSReceiver, _initialReceiverMap: Object,
+ _context: Context, _receiver: JSReceiver, _initialReceiverMap: Map,
_initialReceiverLength: Number): Boolean {
// Do nothing. We are already on the slow path.
return True;
@@ -456,7 +456,7 @@ namespace array {
transitioning builtin
Copy(implicit context: Context)(
source: FixedArray, srcPos: Smi, target: FixedArray, dstPos: Smi,
- length: Smi): Object {
+ length: Smi): JSAny {
assert(srcPos >= 0);
assert(dstPos >= 0);
assert(srcPos <= source.length - length);
@@ -509,7 +509,7 @@ namespace array {
let left: Smi = low;
let right: Smi = start;
- const pivot = workArray.objects[right];
+ const pivot = UnsafeCast<JSAny>(workArray.objects[right]);
// Invariants:
// pivot >= all in [low, left).
@@ -519,7 +519,8 @@ namespace array {
// Find pivot insertion point.
while (left < right) {
const mid: Smi = left + ((right - left) >> 1);
- const order = sortState.Compare(pivot, workArray.objects[mid]);
+ const order =
+ sortState.Compare(pivot, UnsafeCast<JSAny>(workArray.objects[mid]));
if (order < 0) {
right = mid;
@@ -571,8 +572,8 @@ namespace array {
let runLength: Smi = 2;
- const elementLow = workArray.objects[low];
- const elementLowPred = workArray.objects[low - 1];
+ const elementLow = UnsafeCast<JSAny>(workArray.objects[low]);
+ const elementLowPred = UnsafeCast<JSAny>(workArray.objects[low - 1]);
let order = sortState.Compare(elementLow, elementLowPred);
// TODO(szuend): Replace with "order < 0" once Torque supports it.
@@ -580,9 +581,9 @@ namespace array {
// 'never' and uses two labels to branch.
const isDescending: bool = order < 0 ? true : false;
- let previousElement: Object = elementLow;
+ let previousElement: JSAny = elementLow;
for (let idx: Smi = low + 1; idx < high; ++idx) {
- const currentElement = workArray.objects[idx];
+ const currentElement = UnsafeCast<JSAny>(workArray.objects[idx]);
order = sortState.Compare(currentElement, previousElement);
if (isDescending) {
@@ -650,7 +651,7 @@ namespace array {
// Where does b start in a? Elements in a before that can be ignored,
// because they are already in place.
- const keyRight = workArray.objects[baseB];
+ const keyRight = UnsafeCast<JSAny>(workArray.objects[baseB]);
const k: Smi = GallopRight(workArray, keyRight, baseA, lengthA, 0);
assert(k >= 0);
@@ -661,7 +662,7 @@ namespace array {
// Where does a end in b? Elements in b after that can be ignored,
// because they are already in place.
- const keyLeft = workArray.objects[baseA + lengthA - 1];
+ const keyLeft = UnsafeCast<JSAny>(workArray.objects[baseA + lengthA - 1]);
lengthB = GallopLeft(workArray, keyLeft, baseB, lengthB, lengthB - 1);
assert(lengthB >= 0);
if (lengthB == 0) return kSuccess;
@@ -695,14 +696,14 @@ namespace array {
// pretending that array[base - 1] is minus infinity and array[base + len]
// is plus infinity. In other words, key belongs at index base + k.
builtin GallopLeft(implicit context: Context, sortState: SortState)(
- array: FixedArray, key: Object, base: Smi, length: Smi, hint: Smi): Smi {
+ array: FixedArray, key: JSAny, base: Smi, length: Smi, hint: Smi): Smi {
assert(length > 0 && base >= 0);
assert(0 <= hint && hint < length);
let lastOfs: Smi = 0;
let offset: Smi = 1;
- const baseHintElement = array.objects[base + hint];
+ const baseHintElement = UnsafeCast<JSAny>(array.objects[base + hint]);
let order = sortState.Compare(baseHintElement, key);
if (order < 0) {
@@ -712,7 +713,8 @@ namespace array {
// a[base + length - 1] is highest.
const maxOfs: Smi = length - hint;
while (offset < maxOfs) {
- const offsetElement = array.objects[base + hint + offset];
+ const offsetElement =
+ UnsafeCast<JSAny>(array.objects[base + hint + offset]);
order = sortState.Compare(offsetElement, key);
// a[base + hint + offset] >= key? Break.
@@ -738,7 +740,8 @@ namespace array {
// a[base + hint] is lowest.
const maxOfs: Smi = hint + 1;
while (offset < maxOfs) {
- const offsetElement = array.objects[base + hint - offset];
+ const offsetElement =
+ UnsafeCast<JSAny>(array.objects[base + hint - offset]);
order = sortState.Compare(offsetElement, key);
if (order < 0) break;
@@ -768,7 +771,8 @@ namespace array {
while (lastOfs < offset) {
const m: Smi = lastOfs + ((offset - lastOfs) >> 1);
- order = sortState.Compare(array.objects[base + m], key);
+ order =
+ sortState.Compare(UnsafeCast<JSAny>(array.objects[base + m]), key);
if (order < 0) {
lastOfs = m + 1; // a[base + m] < key.
@@ -792,14 +796,14 @@ namespace array {
//
// or kFailure on error.
builtin GallopRight(implicit context: Context, sortState: SortState)(
- array: FixedArray, key: Object, base: Smi, length: Smi, hint: Smi): Smi {
+ array: FixedArray, key: JSAny, base: Smi, length: Smi, hint: Smi): Smi {
assert(length > 0 && base >= 0);
assert(0 <= hint && hint < length);
let lastOfs: Smi = 0;
let offset: Smi = 1;
- const baseHintElement = array.objects[base + hint];
+ const baseHintElement = UnsafeCast<JSAny>(array.objects[base + hint]);
let order = sortState.Compare(key, baseHintElement);
if (order < 0) {
@@ -809,7 +813,8 @@ namespace array {
// a[base + hint] is lowest.
const maxOfs: Smi = hint + 1;
while (offset < maxOfs) {
- const offsetElement = array.objects[base + hint - offset];
+ const offsetElement =
+ UnsafeCast<JSAny>(array.objects[base + hint - offset]);
order = sortState.Compare(key, offsetElement);
if (order >= 0) break;
@@ -834,7 +839,8 @@ namespace array {
// a[base + length - 1] is highest.
const maxOfs: Smi = length - hint;
while (offset < maxOfs) {
- const offsetElement = array.objects[base + hint + offset];
+ const offsetElement =
+ UnsafeCast<JSAny>(array.objects[base + hint + offset]);
order = sortState.Compare(key, offsetElement);
// a[base + hint + ofs] <= key.
@@ -863,7 +869,8 @@ namespace array {
while (lastOfs < offset) {
const m: Smi = lastOfs + ((offset - lastOfs) >> 1);
- order = sortState.Compare(key, array.objects[base + m]);
+ order =
+ sortState.Compare(key, UnsafeCast<JSAny>(array.objects[base + m]));
if (order < 0) {
offset = m; // key < a[base + m].
@@ -921,7 +928,8 @@ namespace array {
assert(lengthA > 1 && lengthB > 0);
const order = sortState.Compare(
- workArray.objects[cursorB], tempArray.objects[cursorTemp]);
+ UnsafeCast<JSAny>(workArray.objects[cursorB]),
+ UnsafeCast<JSAny>(tempArray.objects[cursorTemp]));
if (order < 0) {
workArray.objects[dest++] = workArray.objects[cursorB++];
@@ -958,7 +966,8 @@ namespace array {
sortState.minGallop = minGallop;
nofWinsA = GallopRight(
- tempArray, workArray.objects[cursorB], cursorTemp, lengthA, 0);
+ tempArray, UnsafeCast<JSAny>(workArray.objects[cursorB]),
+ cursorTemp, lengthA, 0);
assert(nofWinsA >= 0);
if (nofWinsA > 0) {
@@ -977,7 +986,8 @@ namespace array {
if (--lengthB == 0) goto Succeed;
nofWinsB = GallopLeft(
- workArray, tempArray.objects[cursorTemp], cursorB, lengthB, 0);
+ workArray, UnsafeCast<JSAny>(tempArray.objects[cursorTemp]),
+ cursorB, lengthB, 0);
assert(nofWinsB >= 0);
if (nofWinsB > 0) {
Copy(workArray, cursorB, workArray, dest, nofWinsB);
@@ -1053,7 +1063,8 @@ namespace array {
assert(lengthA > 0 && lengthB > 1);
const order = sortState.Compare(
- tempArray.objects[cursorTemp], workArray.objects[cursorA]);
+ UnsafeCast<JSAny>(tempArray.objects[cursorTemp]),
+ UnsafeCast<JSAny>(workArray.objects[cursorA]));
if (order < 0) {
workArray.objects[dest--] = workArray.objects[cursorA--];
@@ -1091,8 +1102,8 @@ namespace array {
sortState.minGallop = minGallop;
let k: Smi = GallopRight(
- workArray, tempArray.objects[cursorTemp], baseA, lengthA,
- lengthA - 1);
+ workArray, UnsafeCast<JSAny>(tempArray.objects[cursorTemp]),
+ baseA, lengthA, lengthA - 1);
assert(k >= 0);
nofWinsA = lengthA - k;
@@ -1108,7 +1119,8 @@ namespace array {
if (--lengthB == 1) goto CopyA;
k = GallopLeft(
- tempArray, workArray.objects[cursorA], 0, lengthB, lengthB - 1);
+ tempArray, UnsafeCast<JSAny>(workArray.objects[cursorA]), 0,
+ lengthB, lengthB - 1);
assert(k >= 0);
nofWinsB = lengthB - k;
@@ -1295,7 +1307,7 @@ namespace array {
// are ignored.
let numberOfUndefined: Smi = 0;
for (let i: Smi = 0; i < receiverLength; ++i) {
- const element: Object = loadFn(context, sortState, i);
+ const element: JSAny | TheHole = loadFn(context, sortState, i);
if (element == TheHole) {
// Do nothing for holes. The result is that elements are
@@ -1333,7 +1345,9 @@ namespace array {
// set them to the TheHole up to {sortState.sortLength}.
let index: Smi = 0;
for (; index < numberOfNonUndefined; ++index) {
- storeFn(context, sortState, index, workArray.objects[index]);
+ storeFn(
+ context, sortState, index,
+ UnsafeCast<JSAny>(workArray.objects[index]));
}
const numberOfUndefinedEnd: Smi =
@@ -1350,7 +1364,7 @@ namespace array {
}
transitioning builtin
- ArrayTimSort(context: Context, sortState: SortState): Object {
+ ArrayTimSort(context: Context, sortState: SortState): JSAny {
const numberOfNonUndefined: Smi = CompactReceiverElementsIntoWorkArray();
ArrayTimSortImpl(context, sortState, numberOfNonUndefined);
@@ -1369,11 +1383,11 @@ namespace array {
// https://tc39.github.io/ecma262/#sec-array.prototype.sort
transitioning javascript builtin
- ArrayPrototypeSort(js-implicit context: Context, receiver: Object)(
- ...arguments): Object {
+ ArrayPrototypeSort(js-implicit context: Context, receiver: JSAny)(
+ ...arguments): JSAny {
// 1. If comparefn is not undefined and IsCallable(comparefn) is false,
// throw a TypeError exception.
- const comparefnObj: Object = arguments[0];
+ const comparefnObj: JSAny = arguments[0];
const comparefn = Cast<(Undefined | Callable)>(comparefnObj) otherwise
ThrowTypeError(kBadSortComparisonFunction, comparefnObj);
diff --git a/deps/v8/third_party/wasm-api/README.v8 b/deps/v8/third_party/wasm-api/README.v8
index ea957620b0..bebe47b665 100644
--- a/deps/v8/third_party/wasm-api/README.v8
+++ b/deps/v8/third_party/wasm-api/README.v8
@@ -2,8 +2,8 @@ Name: Wasm C/C++ API
Short Name: wasm-c-api
URL: https://github.com/WebAssembly/wasm-c-api/
Version: 0
-Revision: 5c742b048f7766a0c00be3a7af23fb71ba816026
-Date: 2019-03-18
+Revision: 6db391ee7121a0695602945d11001ea3e00b0afb
+Date: 2019-08-08
License: Apache 2.0
License File: LICENSE
Security Critical: yes
diff --git a/deps/v8/third_party/wasm-api/example/callback.c b/deps/v8/third_party/wasm-api/example/callback.c
index f3b9018594..e17429bdd2 100644
--- a/deps/v8/third_party/wasm-api/example/callback.c
+++ b/deps/v8/third_party/wasm-api/example/callback.c
@@ -111,7 +111,8 @@ int main(int argc, const char* argv[]) {
const wasm_extern_t* imports[] = {
wasm_func_as_extern(print_func), wasm_func_as_extern(closure_func)
};
- own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
diff --git a/deps/v8/third_party/wasm-api/example/callback.cc b/deps/v8/third_party/wasm-api/example/callback.cc
index a9ee9aa919..d9f8751ea6 100644
--- a/deps/v8/third_party/wasm-api/example/callback.cc
+++ b/deps/v8/third_party/wasm-api/example/callback.cc
@@ -36,7 +36,7 @@ auto operator<<(std::ostream& out, const wasm::Val& val) -> std::ostream& {
// A function to be called from Wasm code.
auto print_callback(
const wasm::Val args[], wasm::Val results[]
-) -> wasm::own<wasm::Trap*> {
+) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl << "> " << args[0] << std::endl;
results[0] = args[0].copy();
return nullptr;
@@ -46,7 +46,7 @@ auto print_callback(
// A function closure.
auto closure_callback(
void* env, const wasm::Val args[], wasm::Val results[]
-) -> wasm::own<wasm::Trap*> {
+) -> wasm::own<wasm::Trap> {
auto i = *reinterpret_cast<int*>(env);
std::cout << "Calling back closure..." << std::endl;
std::cout << "> " << i << std::endl;
@@ -73,7 +73,7 @@ void run() {
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
- return;
+ exit(1);
}
// Compile.
@@ -81,14 +81,14 @@ void run() {
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto print_type = wasm::FuncType::make(
- wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)),
- wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32))
+ wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32)),
+ wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32))
);
auto print_func = wasm::Func::make(store, print_type.get(), print_callback);
@@ -96,8 +96,8 @@ void run() {
std::cout << "Creating closure..." << std::endl;
int i = 42;
auto closure_type = wasm::FuncType::make(
- wasm::vec<wasm::ValType*>::make(),
- wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32))
+ wasm::ownvec<wasm::ValType>::make(),
+ wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32))
);
auto closure_func = wasm::Func::make(store, closure_type.get(), closure_callback, &i);
@@ -107,7 +107,7 @@ void run() {
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
- return;
+ exit(1);
}
// Extract export.
@@ -115,7 +115,7 @@ void run() {
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
- return;
+ exit(1);
}
auto run_func = exports[0]->func();
@@ -125,7 +125,7 @@ void run() {
wasm::Val results[1];
if (run_func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
- return;
+ exit(1);
}
// Print result.
diff --git a/deps/v8/third_party/wasm-api/example/finalize.c b/deps/v8/third_party/wasm-api/example/finalize.c
index 6841617262..247368f28e 100644
--- a/deps/v8/third_party/wasm-api/example/finalize.c
+++ b/deps/v8/third_party/wasm-api/example/finalize.c
@@ -9,23 +9,21 @@
const int iterations = 100000;
+int live_count = 0;
+
void finalize(void* data) {
int i = (int)data;
if (i % (iterations / 10) == 0) printf("Finalizing #%d...\n", i);
+ --live_count;
}
-int main(int argc, const char* argv[]) {
- // Initialize.
- printf("Initializing...\n");
- wasm_engine_t* engine = wasm_engine_new();
- wasm_store_t* store = wasm_store_new(engine);
-
+void run_in_store(wasm_store_t* store) {
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("finalize.wasm", "r");
if (!file) {
printf("> Error loading module!\n");
- return 1;
+ exit(1);
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
@@ -34,7 +32,7 @@ int main(int argc, const char* argv[]) {
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
- return 1;
+ exit(1);
}
fclose(file);
@@ -43,7 +41,7 @@ int main(int argc, const char* argv[]) {
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
- return 1;
+ exit(1);
}
wasm_byte_vec_delete(&binary);
@@ -52,21 +50,57 @@ int main(int argc, const char* argv[]) {
printf("Instantiating modules...\n");
for (int i = 0; i <= iterations; ++i) {
if (i % (iterations / 10) == 0) printf("%d\n", i);
- own wasm_instance_t* instance = wasm_instance_new(store, module, NULL);
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, NULL, NULL);
if (!instance) {
printf("> Error instantiating module %d!\n", i);
- return 1;
+ exit(1);
}
void* data = (void*)(intptr_t)i;
wasm_instance_set_host_info_with_finalizer(instance, data, &finalize);
wasm_instance_delete(instance);
+ ++live_count;
}
wasm_module_delete(module);
+}
+
+int main(int argc, const char* argv[]) {
+ // Initialize.
+ printf("Initializing...\n");
+ wasm_engine_t* engine = wasm_engine_new();
+
+ printf("Live count %d\n", live_count);
+ printf("Creating store 1...\n");
+ wasm_store_t* store1 = wasm_store_new(engine);
+
+ printf("Running in store 1...\n");
+ run_in_store(store1);
+ printf("Live count %d\n", live_count);
+
+ printf("Creating store 2...\n");
+ wasm_store_t* store2 = wasm_store_new(engine);
+
+ printf("Running in store 2...\n");
+ run_in_store(store2);
+ printf("Live count %d\n", live_count);
+
+ printf("Deleting store 2...\n");
+ wasm_store_delete(store2);
+ printf("Live count %d\n", live_count);
+
+ printf("Running in store 1...\n");
+ run_in_store(store1);
+ printf("Live count %d\n", live_count);
+
+ printf("Deleting store 1...\n");
+ wasm_store_delete(store1);
+ printf("Live count %d\n", live_count);
+
+ assert(live_count == 0);
// Shut down.
printf("Shutting down...\n");
- wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
diff --git a/deps/v8/third_party/wasm-api/example/finalize.cc b/deps/v8/third_party/wasm-api/example/finalize.cc
index a354a2601d..64e134b8d8 100644
--- a/deps/v8/third_party/wasm-api/example/finalize.cc
+++ b/deps/v8/third_party/wasm-api/example/finalize.cc
@@ -9,20 +9,17 @@
const int iterations = 100000;
+int live_count = 0;
+
void finalize(void* data) {
intptr_t i = reinterpret_cast<intptr_t>(data);
if (i % (iterations / 10) == 0) {
std::cout << "Finalizing #" << i << "..." << std::endl;
}
+ --live_count;
}
-void run() {
- // Initialize.
- std::cout << "Initializing..." << std::endl;
- auto engine = wasm::Engine::make();
- auto store_ = wasm::Store::make(engine.get());
- auto store = store_.get();
-
+void run_in_store(wasm::Store* store) {
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("finalize.wasm");
@@ -34,7 +31,7 @@ void run() {
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
- return;
+ exit(1);
}
// Compile.
@@ -42,7 +39,7 @@ void run() {
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Instantiate.
@@ -52,9 +49,10 @@ void run() {
auto instance = wasm::Instance::make(store, module.get(), nullptr);
if (!instance) {
std::cout << "> Error instantiating module " << i << "!" << std::endl;
- return;
+ exit(1);
}
instance->set_host_info(reinterpret_cast<void*>(i), &finalize);
+ ++live_count;
}
// Shut down.
@@ -62,8 +60,43 @@ void run() {
}
+void run() {
+ // Initialize.
+ std::cout << "Initializing..." << std::endl;
+ auto engine = wasm::Engine::make();
+
+ std::cout << "Live count " << live_count << std::endl;
+ std::cout << "Creating store 1..." << std::endl;
+ auto store1 = wasm::Store::make(engine.get());
+
+ std::cout << "Running in store 1..." << std::endl;
+ run_in_store(store1.get());
+ std::cout << "Live count " << live_count << std::endl;
+
+ {
+ std::cout << "Creating store 2..." << std::endl;
+ auto store2 = wasm::Store::make(engine.get());
+
+ std::cout << "Running in store 2..." << std::endl;
+ run_in_store(store2.get());
+ std::cout << "Live count " << live_count << std::endl;
+
+ std::cout << "Deleting store 2..." << std::endl;
+ std::cout << "Live count " << live_count << std::endl;
+ }
+
+ std::cout << "Running in store 1..." << std::endl;
+ run_in_store(store1.get());
+ std::cout << "Live count " << live_count << std::endl;
+
+ std::cout << "Deleting store 1..." << std::endl;
+}
+
+
int main(int argc, const char* argv[]) {
run();
+ std::cout << "Live count " << live_count << std::endl;
+ assert(live_count == 0);
std::cout << "Done." << std::endl;
return 0;
}
diff --git a/deps/v8/third_party/wasm-api/example/global.c b/deps/v8/third_party/wasm-api/example/global.c
index b82d86242e..5fe357cd4c 100644
--- a/deps/v8/third_party/wasm-api/example/global.c
+++ b/deps/v8/third_party/wasm-api/example/global.c
@@ -91,13 +91,17 @@ int main(int argc, const char* argv[]) {
wasm_valtype_new(WASM_I64), WASM_VAR);
wasm_val_t val_f32_1 = {.kind = WASM_F32, .of = {.f32 = 1}};
- own wasm_global_t* const_f32_import = wasm_global_new(store, const_f32_type, &val_f32_1);
+ own wasm_global_t* const_f32_import =
+ wasm_global_new(store, const_f32_type, &val_f32_1);
wasm_val_t val_i64_2 = {.kind = WASM_I64, .of = {.i64 = 2}};
- own wasm_global_t* const_i64_import = wasm_global_new(store, const_i64_type, &val_i64_2);
+ own wasm_global_t* const_i64_import =
+ wasm_global_new(store, const_i64_type, &val_i64_2);
wasm_val_t val_f32_3 = {.kind = WASM_F32, .of = {.f32 = 3}};
- own wasm_global_t* var_f32_import = wasm_global_new(store, var_f32_type, &val_f32_3);
+ own wasm_global_t* var_f32_import =
+ wasm_global_new(store, var_f32_type, &val_f32_3);
wasm_val_t val_i64_4 = {.kind = WASM_I64, .of = {.i64 = 4}};
- own wasm_global_t* var_i64_import = wasm_global_new(store, var_i64_type, &val_i64_4);
+ own wasm_global_t* var_i64_import =
+ wasm_global_new(store, var_i64_type, &val_i64_4);
wasm_globaltype_delete(const_f32_type);
wasm_globaltype_delete(const_i64_type);
@@ -112,7 +116,8 @@ int main(int argc, const char* argv[]) {
wasm_global_as_extern(var_f32_import),
wasm_global_as_extern(var_i64_import)
};
- own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
@@ -142,6 +147,11 @@ int main(int argc, const char* argv[]) {
wasm_func_t* set_var_f32_export = get_export_func(&exports, i++);
wasm_func_t* set_var_i64_export = get_export_func(&exports, i++);
+ // Try cloning.
+ own wasm_global_t* copy = wasm_global_copy(var_f32_import);
+ assert(wasm_global_same(var_f32_import, copy));
+ wasm_global_delete(copy);
+
// Interact.
printf("Accessing globals...\n");
diff --git a/deps/v8/third_party/wasm-api/example/global.cc b/deps/v8/third_party/wasm-api/example/global.cc
index 75a2513c82..811024e65d 100644
--- a/deps/v8/third_party/wasm-api/example/global.cc
+++ b/deps/v8/third_party/wasm-api/example/global.cc
@@ -7,7 +7,7 @@
#include "wasm.hh"
-auto get_export_global(wasm::vec<wasm::Extern*>& exports, size_t i) -> wasm::Global* {
+auto get_export_global(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Global* {
if (exports.size() <= i || !exports[i]->global()) {
std::cout << "> Error accessing global export " << i << "!" << std::endl;
exit(1);
@@ -15,7 +15,7 @@ auto get_export_global(wasm::vec<wasm::Extern*>& exports, size_t i) -> wasm::Glo
return exports[i]->global();
}
-auto get_export_func(const wasm::vec<wasm::Extern*>& exports, size_t i) -> const wasm::Func* {
+auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> const wasm::Func* {
if (exports.size() <= i || !exports[i]->func()) {
std::cout << "> Error accessing function export " << i << "!" << std::endl;
exit(1);
@@ -67,7 +67,7 @@ void run() {
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
- return;
+ exit(1);
}
// Compile.
@@ -75,7 +75,7 @@ void run() {
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Create external globals.
@@ -102,7 +102,7 @@ void run() {
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
- return;
+ exit(1);
}
// Extract export.
@@ -126,6 +126,9 @@ void run() {
auto set_var_f32_export = get_export_func(exports, i++);
auto set_var_i64_export = get_export_func(exports, i++);
+ // Try cloning.
+ assert(var_f32_import->copy()->same(var_f32_import.get()));
+
// Interact.
std::cout << "Accessing globals..." << std::endl;
diff --git a/deps/v8/third_party/wasm-api/example/hello.c b/deps/v8/third_party/wasm-api/example/hello.c
index b1c8c5fee5..e4ef9837ff 100644
--- a/deps/v8/third_party/wasm-api/example/hello.c
+++ b/deps/v8/third_party/wasm-api/example/hello.c
@@ -62,7 +62,8 @@ int main(int argc, const char* argv[]) {
// Instantiate.
printf("Instantiating module...\n");
const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) };
- own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
diff --git a/deps/v8/third_party/wasm-api/example/hello.cc b/deps/v8/third_party/wasm-api/example/hello.cc
index 4956be885f..e009b3b50d 100644
--- a/deps/v8/third_party/wasm-api/example/hello.cc
+++ b/deps/v8/third_party/wasm-api/example/hello.cc
@@ -10,7 +10,7 @@
// A function to be called from Wasm code.
auto hello_callback(
const wasm::Val args[], wasm::Val results[]
-) -> wasm::own<wasm::Trap*> {
+) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
std::cout << "> Hello world!" << std::endl;
return nullptr;
@@ -35,7 +35,7 @@ void run() {
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
- return;
+ exit(1);
}
// Compile.
@@ -43,13 +43,13 @@ void run() {
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto hello_type = wasm::FuncType::make(
- wasm::vec<wasm::ValType*>::make(), wasm::vec<wasm::ValType*>::make()
+ wasm::ownvec<wasm::ValType>::make(), wasm::ownvec<wasm::ValType>::make()
);
auto hello_func = wasm::Func::make(store, hello_type.get(), hello_callback);
@@ -59,7 +59,7 @@ void run() {
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
- return;
+ exit(1);
}
// Extract export.
@@ -67,7 +67,7 @@ void run() {
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
- return;
+ exit(1);
}
auto run_func = exports[0]->func();
@@ -75,7 +75,7 @@ void run() {
std::cout << "Calling export..." << std::endl;
if (run_func->call()) {
std::cout << "> Error calling function!" << std::endl;
- return;
+ exit(1);
}
// Shut down.
diff --git a/deps/v8/third_party/wasm-api/example/hostref.c b/deps/v8/third_party/wasm-api/example/hostref.c
new file mode 100644
index 0000000000..b70218e610
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/hostref.c
@@ -0,0 +1,269 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "wasm.h"
+
+#define own
+
+
+// A function to be called from Wasm code.
+own wasm_trap_t* callback(
+ const wasm_val_t args[], wasm_val_t results[]
+) {
+ printf("Calling back...\n> ");
+ printf("> %p\n",
+ args[0].of.ref ? wasm_ref_get_host_info(args[0].of.ref) : NULL);
+ wasm_val_copy(&results[0], &args[0]);
+ return NULL;
+}
+
+
+wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
+ if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
+ printf("> Error accessing function export %zu!\n", i);
+ exit(1);
+ }
+ return wasm_extern_as_func(exports->data[i]);
+}
+
+wasm_global_t* get_export_global(const wasm_extern_vec_t* exports, size_t i) {
+ if (exports->size <= i || !wasm_extern_as_global(exports->data[i])) {
+ printf("> Error accessing global export %zu!\n", i);
+ exit(1);
+ }
+ return wasm_extern_as_global(exports->data[i]);
+}
+
+wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) {
+ if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) {
+ printf("> Error accessing table export %zu!\n", i);
+ exit(1);
+ }
+ return wasm_extern_as_table(exports->data[i]);
+}
+
+
+own wasm_ref_t* call_v_r(const wasm_func_t* func) {
+ printf("call_v_r... "); fflush(stdout);
+ wasm_val_t results[1];
+ if (wasm_func_call(func, NULL, results)) {
+ printf("> Error calling function!\n");
+ exit(1);
+ }
+ printf("okay\n");
+ return results[0].of.ref;
+}
+
+void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) {
+ printf("call_r_v... "); fflush(stdout);
+ wasm_val_t args[1];
+ args[0].kind = WASM_ANYREF;
+ args[0].of.ref = ref;
+ if (wasm_func_call(func, args, NULL)) {
+ printf("> Error calling function!\n");
+ exit(1);
+ }
+ printf("okay\n");
+}
+
+own wasm_ref_t* call_r_r(const wasm_func_t* func, wasm_ref_t* ref) {
+ printf("call_r_r... "); fflush(stdout);
+ wasm_val_t args[1];
+ args[0].kind = WASM_ANYREF;
+ args[0].of.ref = ref;
+ wasm_val_t results[1];
+ if (wasm_func_call(func, args, results)) {
+ printf("> Error calling function!\n");
+ exit(1);
+ }
+ printf("okay\n");
+ return results[0].of.ref;
+}
+
+void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) {
+ printf("call_ir_v... "); fflush(stdout);
+ wasm_val_t args[2];
+ args[0].kind = WASM_I32;
+ args[0].of.i32 = i;
+ args[1].kind = WASM_ANYREF;
+ args[1].of.ref = ref;
+ if (wasm_func_call(func, args, NULL)) {
+ printf("> Error calling function!\n");
+ exit(1);
+ }
+ printf("okay\n");
+}
+
+own wasm_ref_t* call_i_r(const wasm_func_t* func, int32_t i) {
+ printf("call_i_r... "); fflush(stdout);
+ wasm_val_t args[1];
+ args[0].kind = WASM_I32;
+ args[0].of.i32 = i;
+ wasm_val_t results[1];
+ if (wasm_func_call(func, args, results)) {
+ printf("> Error calling function!\n");
+ exit(1);
+ }
+ printf("okay\n");
+ return results[0].of.ref;
+}
+
+void check(own wasm_ref_t* actual, const wasm_ref_t* expected) {
+ if (actual != expected &&
+ !(actual && expected && wasm_ref_same(actual, expected))) {
+ printf("> Error reading reference, expected %p, got %p\n",
+ expected ? wasm_ref_get_host_info(expected) : NULL,
+ actual ? wasm_ref_get_host_info(actual) : NULL);
+ exit(1);
+ }
+ if (actual) wasm_ref_delete(actual);
+}
+
+
+int main(int argc, const char* argv[]) {
+ // Initialize.
+ printf("Initializing...\n");
+ wasm_engine_t* engine = wasm_engine_new();
+ wasm_store_t* store = wasm_store_new(engine);
+
+ // Load binary.
+ printf("Loading binary...\n");
+ FILE* file = fopen("hostref.wasm", "r");
+ if (!file) {
+ printf("> Error loading module!\n");
+ return 1;
+ }
+ fseek(file, 0L, SEEK_END);
+ size_t file_size = ftell(file);
+ fseek(file, 0L, SEEK_SET);
+ wasm_byte_vec_t binary;
+ wasm_byte_vec_new_uninitialized(&binary, file_size);
+ if (fread(binary.data, file_size, 1, file) != 1) {
+ printf("> Error loading module!\n");
+ return 1;
+ }
+ fclose(file);
+
+ // Compile.
+ printf("Compiling module...\n");
+ own wasm_module_t* module = wasm_module_new(store, &binary);
+ if (!module) {
+ printf("> Error compiling module!\n");
+ return 1;
+ }
+
+ wasm_byte_vec_delete(&binary);
+
+ // Create external callback function.
+ printf("Creating callback...\n");
+ own wasm_functype_t* callback_type = wasm_functype_new_1_1(
+ wasm_valtype_new(WASM_ANYREF), wasm_valtype_new(WASM_ANYREF));
+ own wasm_func_t* callback_func =
+ wasm_func_new(store, callback_type, callback);
+
+ wasm_functype_delete(callback_type);
+
+ // Instantiate.
+ printf("Instantiating module...\n");
+ const wasm_extern_t* imports[] = { wasm_func_as_extern(callback_func) };
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, imports, NULL);
+ if (!instance) {
+ printf("> Error instantiating module!\n");
+ return 1;
+ }
+
+ wasm_func_delete(callback_func);
+ wasm_module_delete(module);
+
+ // Extract export.
+ printf("Extracting exports...\n");
+ own wasm_extern_vec_t exports;
+ wasm_instance_exports(instance, &exports);
+ size_t i = 0;
+ wasm_global_t* global = get_export_global(&exports, i++);
+ wasm_table_t* table = get_export_table(&exports, i++);
+ wasm_func_t* global_set = get_export_func(&exports, i++);
+ wasm_func_t* global_get = get_export_func(&exports, i++);
+ wasm_func_t* table_set = get_export_func(&exports, i++);
+ wasm_func_t* table_get = get_export_func(&exports, i++);
+ wasm_func_t* func_call = get_export_func(&exports, i++);
+
+ wasm_instance_delete(instance);
+
+ // Create host references.
+ printf("Creating host references...\n");
+ own wasm_ref_t* host1 = wasm_foreign_as_ref(wasm_foreign_new(store));
+ own wasm_ref_t* host2 = wasm_foreign_as_ref(wasm_foreign_new(store));
+ wasm_ref_set_host_info(host1, (void*)1);
+ wasm_ref_set_host_info(host2, (void*)2);
+
+ // Some sanity checks.
+ check(NULL, NULL);
+ check(wasm_ref_copy(host1), host1);
+ check(wasm_ref_copy(host2), host2);
+
+ own wasm_val_t val;
+ val.kind = WASM_ANYREF;
+ val.of.ref = wasm_ref_copy(host1);
+ check(wasm_ref_copy(val.of.ref), host1);
+ own wasm_ref_t* ref = val.of.ref;
+ check(wasm_ref_copy(ref), host1);
+ wasm_val_delete(&val);
+
+ // Interact.
+ printf("Accessing global...\n");
+ check(call_v_r(global_get), NULL);
+ call_r_v(global_set, host1);
+ check(call_v_r(global_get), host1);
+ call_r_v(global_set, host2);
+ check(call_v_r(global_get), host2);
+ call_r_v(global_set, NULL);
+ check(call_v_r(global_get), NULL);
+
+ wasm_global_get(global, &val);
+ assert(val.kind == WASM_ANYREF);
+ check(val.of.ref, NULL);
+ val.of.ref = host2;
+ wasm_global_set(global, &val);
+ check(call_v_r(global_get), host2);
+ wasm_global_get(global, &val);
+ assert(val.kind == WASM_ANYREF);
+ check(val.of.ref, host2);
+
+ printf("Accessing table...\n");
+ check(call_i_r(table_get, 0), NULL);
+ check(call_i_r(table_get, 1), NULL);
+ call_ir_v(table_set, 0, host1);
+ call_ir_v(table_set, 1, host2);
+ check(call_i_r(table_get, 0), host1);
+ check(call_i_r(table_get, 1), host2);
+ call_ir_v(table_set, 0, NULL);
+ check(call_i_r(table_get, 0), NULL);
+
+ check(wasm_table_get(table, 2), NULL);
+ wasm_table_set(table, 2, host1);
+ check(call_i_r(table_get, 2), host1);
+ check(wasm_table_get(table, 2), host1);
+
+ printf("Accessing function...\n");
+ check(call_r_r(func_call, NULL), NULL);
+ check(call_r_r(func_call, host1), host1);
+ check(call_r_r(func_call, host2), host2);
+
+ wasm_ref_delete(host1);
+ wasm_ref_delete(host2);
+
+ wasm_extern_vec_delete(&exports);
+
+ // Shut down.
+ printf("Shutting down...\n");
+ wasm_store_delete(store);
+ wasm_engine_delete(engine);
+
+ // All done.
+ printf("Done.\n");
+ return 0;
+}
diff --git a/deps/v8/third_party/wasm-api/example/hostref.cc b/deps/v8/third_party/wasm-api/example/hostref.cc
new file mode 100644
index 0000000000..74e1f119d3
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/hostref.cc
@@ -0,0 +1,232 @@
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <string>
+#include <cinttypes>
+
+#include "wasm.hh"
+
+
+// A function to be called from Wasm code.
+auto callback(
+ const wasm::Val args[], wasm::Val results[]
+) -> wasm::own<wasm::Trap> {
+ std::cout << "Calling back..." << std::endl;
+ std::cout << "> " << (args[0].ref() ? args[0].ref()->get_host_info() : nullptr) << std::endl;
+ results[0] = args[0].copy();
+ return nullptr;
+}
+
+
+auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> const wasm::Func* {
+ if (exports.size() <= i || !exports[i]->func()) {
+ std::cout << "> Error accessing function export " << i << "/" << exports.size() << "!" << std::endl;
+ exit(1);
+ }
+ return exports[i]->func();
+}
+
+auto get_export_global(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Global* {
+ if (exports.size() <= i || !exports[i]->global()) {
+ std::cout << "> Error accessing global export " << i << "!" << std::endl;
+ exit(1);
+ }
+ return exports[i]->global();
+}
+
+auto get_export_table(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Table* {
+ if (exports.size() <= i || !exports[i]->table()) {
+ std::cout << "> Error accessing table export " << i << "!" << std::endl;
+ exit(1);
+ }
+ return exports[i]->table();
+}
+
+
+void call_r_v(const wasm::Func* func, const wasm::Ref* ref) {
+ std::cout << "call_r_v... " << std::flush;
+ wasm::Val args[1] = {wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>())};
+ if (func->call(args, nullptr)) {
+ std::cout << "> Error calling function!" << std::endl;
+ exit(1);
+ }
+ std::cout << "okay" << std::endl;
+}
+
+auto call_v_r(const wasm::Func* func) -> wasm::own<wasm::Ref> {
+ std::cout << "call_v_r... " << std::flush;
+ wasm::Val results[1];
+ if (func->call(nullptr, results)) {
+ std::cout << "> Error calling function!" << std::endl;
+ exit(1);
+ }
+ std::cout << "okay" << std::endl;
+ return results[0].release_ref();
+}
+
+auto call_r_r(const wasm::Func* func, const wasm::Ref* ref) -> wasm::own<wasm::Ref> {
+ std::cout << "call_r_r... " << std::flush;
+ wasm::Val args[1] = {wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>())};
+ wasm::Val results[1];
+ if (func->call(args, results)) {
+ std::cout << "> Error calling function!" << std::endl;
+ exit(1);
+ }
+ std::cout << "okay" << std::endl;
+ return results[0].release_ref();
+}
+
+void call_ir_v(const wasm::Func* func, int32_t i, const wasm::Ref* ref) {
+ std::cout << "call_ir_v... " << std::flush;
+ wasm::Val args[2] = {wasm::Val::i32(i), wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>())};
+ if (func->call(args, nullptr)) {
+ std::cout << "> Error calling function!" << std::endl;
+ exit(1);
+ }
+ std::cout << "okay" << std::endl;
+}
+
+auto call_i_r(const wasm::Func* func, int32_t i) -> wasm::own<wasm::Ref> {
+ std::cout << "call_i_r... " << std::flush;
+ wasm::Val args[1] = {wasm::Val::i32(i)};
+ wasm::Val results[1];
+ if (func->call(args, results)) {
+ std::cout << "> Error calling function!" << std::endl;
+ exit(1);
+ }
+ std::cout << "okay" << std::endl;
+ return results[0].release_ref();
+}
+
+void check(wasm::own<wasm::Ref> actual, const wasm::Ref* expected) {
+ if (actual.get() != expected &&
+ !(actual && expected && actual->same(expected))) {
+ std::cout << "> Error reading reference, expected "
+ << (expected ? expected->get_host_info() : nullptr) << ", got "
+ << (actual ? actual->get_host_info() : nullptr) << std::endl;
+ exit(1);
+ }
+}
+
+void run() {
+ // Initialize.
+ std::cout << "Initializing..." << std::endl;
+ auto engine = wasm::Engine::make();
+ auto store_ = wasm::Store::make(engine.get());
+ auto store = store_.get();
+
+ // Load binary.
+ std::cout << "Loading binary..." << std::endl;
+ std::ifstream file("hostref.wasm");
+ file.seekg(0, std::ios_base::end);
+ auto file_size = file.tellg();
+ file.seekg(0);
+ auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
+ file.read(binary.get(), file_size);
+ file.close();
+ if (file.fail()) {
+ std::cout << "> Error loading module!" << std::endl;
+ return;
+ }
+
+ // Compile.
+ std::cout << "Compiling module..." << std::endl;
+ auto module = wasm::Module::make(store, binary);
+ if (!module) {
+ std::cout << "> Error compiling module!" << std::endl;
+ return;
+ }
+
+ // Create external callback function.
+ std::cout << "Creating callback..." << std::endl;
+ auto callback_type = wasm::FuncType::make(
+ wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::ANYREF)),
+ wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::ANYREF))
+ );
+ auto callback_func = wasm::Func::make(store, callback_type.get(), callback);
+
+ // Instantiate.
+ std::cout << "Instantiating module..." << std::endl;
+ wasm::Extern* imports[] = {callback_func.get()};
+ auto instance = wasm::Instance::make(store, module.get(), imports);
+ if (!instance) {
+ std::cout << "> Error instantiating module!" << std::endl;
+ return;
+ }
+
+ // Extract export.
+ std::cout << "Extracting exports..." << std::endl;
+ auto exports = instance->exports();
+ size_t i = 0;
+ auto global = get_export_global(exports, i++);
+ auto table = get_export_table(exports, i++);
+ auto global_set = get_export_func(exports, i++);
+ auto global_get = get_export_func(exports, i++);
+ auto table_set = get_export_func(exports, i++);
+ auto table_get = get_export_func(exports, i++);
+ auto func_call = get_export_func(exports, i++);
+
+ // Create host references.
+ std::cout << "Creating host references..." << std::endl;
+ auto host1 = wasm::Foreign::make(store);
+ auto host2 = wasm::Foreign::make(store);
+ host1->set_host_info(reinterpret_cast<void*>(1));
+ host2->set_host_info(reinterpret_cast<void*>(2));
+
+ // Some sanity checks.
+ check(nullptr, nullptr);
+ check(host1->copy(), host1.get());
+ check(host2->copy(), host2.get());
+
+ wasm::Val val = wasm::Val::ref(host1->copy());
+ check(val.ref()->copy(), host1.get());
+ auto ref = val.release_ref();
+ assert(val.ref() == nullptr);
+ check(ref->copy(), host1.get());
+
+ // Interact.
+ std::cout << "Accessing global..." << std::endl;
+ check(call_v_r(global_get), nullptr);
+ call_r_v(global_set, host1.get());
+ check(call_v_r(global_get), host1.get());
+ call_r_v(global_set, host2.get());
+ check(call_v_r(global_get), host2.get());
+ call_r_v(global_set, nullptr);
+ check(call_v_r(global_get), nullptr);
+
+ check(global->get().release_ref(), nullptr);
+ global->set(wasm::Val(host2->copy()));
+ check(call_v_r(global_get), host2.get());
+ check(global->get().release_ref(), host2.get());
+
+ std::cout << "Accessing table..." << std::endl;
+ check(call_i_r(table_get, 0), nullptr);
+ check(call_i_r(table_get, 1), nullptr);
+ call_ir_v(table_set, 0, host1.get());
+ call_ir_v(table_set, 1, host2.get());
+ check(call_i_r(table_get, 0), host1.get());
+ check(call_i_r(table_get, 1), host2.get());
+ call_ir_v(table_set, 0, nullptr);
+ check(call_i_r(table_get, 0), nullptr);
+
+ check(table->get(2), nullptr);
+ table->set(2, host1.get());
+ check(call_i_r(table_get, 2), host1.get());
+ check(table->get(2), host1.get());
+
+ std::cout << "Accessing function..." << std::endl;
+ check(call_r_r(func_call, nullptr), nullptr);
+ check(call_r_r(func_call, host1.get()), host1.get());
+ check(call_r_r(func_call, host2.get()), host2.get());
+
+ // Shut down.
+ std::cout << "Shutting down..." << std::endl;
+}
+
+
+int main(int argc, const char* argv[]) {
+ run();
+ std::cout << "Done." << std::endl;
+ return 0;
+}
+
diff --git a/deps/v8/third_party/wasm-api/example/hostref.wasm b/deps/v8/third_party/wasm-api/example/hostref.wasm
new file mode 100644
index 0000000000..7bfc7288e9
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/hostref.wasm
Binary files differ
diff --git a/deps/v8/third_party/wasm-api/example/hostref.wat b/deps/v8/third_party/wasm-api/example/hostref.wat
new file mode 100644
index 0000000000..4d14ba6ae8
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/hostref.wat
@@ -0,0 +1,24 @@
+(module
+ (import "" "f" (func $fun (param anyref) (result anyref)))
+
+ (global $glob (export "global") (mut anyref) (ref.null))
+ (table $tab (export "table") 10 anyref)
+
+ (func (export "global.set") (param $r anyref)
+ (global.set $glob (local.get $r))
+ )
+ (func (export "global.get") (result anyref)
+ (global.get $glob)
+ )
+
+ (func (export "table.set") (param $i i32) (param $r anyref)
+ (table.set $tab (local.get $i) (local.get $r))
+ )
+ (func (export "table.get") (param $i i32) (result anyref)
+ (table.get $tab (local.get $i))
+ )
+
+ (func (export "func.call") (param $r anyref) (result anyref)
+ (call $fun (local.get $r))
+ )
+)
diff --git a/deps/v8/third_party/wasm-api/example/memory.c b/deps/v8/third_party/wasm-api/example/memory.c
index 64b0f86b51..2c020c4597 100644
--- a/deps/v8/third_party/wasm-api/example/memory.c
+++ b/deps/v8/third_party/wasm-api/example/memory.c
@@ -132,7 +132,8 @@ int main(int argc, const char* argv[]) {
// Instantiate.
printf("Instantiating module...\n");
- own wasm_instance_t* instance = wasm_instance_new(store, module, NULL);
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, NULL, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
@@ -150,6 +151,11 @@ int main(int argc, const char* argv[]) {
wasm_module_delete(module);
+ // Try cloning.
+ own wasm_memory_t* copy = wasm_memory_copy(memory);
+ assert(wasm_memory_same(memory, copy));
+ wasm_memory_delete(copy);
+
// Check initial memory.
printf("Checking memory...\n");
check(wasm_memory_size(memory) == 2);
diff --git a/deps/v8/third_party/wasm-api/example/memory.cc b/deps/v8/third_party/wasm-api/example/memory.cc
index fb50565c85..4094accd8d 100644
--- a/deps/v8/third_party/wasm-api/example/memory.cc
+++ b/deps/v8/third_party/wasm-api/example/memory.cc
@@ -7,7 +7,7 @@
#include "wasm.hh"
-auto get_export_memory(wasm::vec<wasm::Extern*>& exports, size_t i) -> wasm::Memory* {
+auto get_export_memory(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Memory* {
if (exports.size() <= i || !exports[i]->memory()) {
std::cout << "> Error accessing memory export " << i << "!" << std::endl;
exit(1);
@@ -15,7 +15,7 @@ auto get_export_memory(wasm::vec<wasm::Extern*>& exports, size_t i) -> wasm::Mem
return exports[i]->memory();
}
-auto get_export_func(const wasm::vec<wasm::Extern*>& exports, size_t i) -> const wasm::Func* {
+auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> const wasm::Func* {
if (exports.size() <= i || !exports[i]->func()) {
std::cout << "> Error accessing function export " << i << "!" << std::endl;
exit(1);
@@ -79,7 +79,7 @@ void run() {
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
- return;
+ exit(1);
}
// Compile.
@@ -87,7 +87,7 @@ void run() {
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Instantiate.
@@ -95,7 +95,7 @@ void run() {
auto instance = wasm::Instance::make(store, module.get(), nullptr);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
- return;
+ exit(1);
}
// Extract export.
@@ -107,6 +107,9 @@ void run() {
auto load_func = get_export_func(exports, i++);
auto store_func = get_export_func(exports, i++);
+ // Try cloning.
+ assert(memory->copy()->same(memory));
+
// Check initial memory.
std::cout << "Checking memory..." << std::endl;
check(memory->size(), 2u);
diff --git a/deps/v8/third_party/wasm-api/example/multi.c b/deps/v8/third_party/wasm-api/example/multi.c
new file mode 100644
index 0000000000..7bd4676bae
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/multi.c
@@ -0,0 +1,154 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "wasm.h"
+
+#define own
+
+// A function to be called from Wasm code.
+own wasm_trap_t* callback(
+ const wasm_val_t args[], wasm_val_t results[]
+) {
+ printf("Calling back...\n> ");
+ printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n",
+ args[0].of.i32, args[1].of.i64, args[2].of.i64, args[3].of.i32);
+ printf("\n");
+
+ wasm_val_copy(&results[0], &args[0]);
+ return NULL;
+}
+
+
+// A function closure.
+own wasm_trap_t* closure_callback(
+ void* env, const wasm_val_t args[], wasm_val_t results[]
+) {
+ int i = *(int*)env;
+ printf("Calling back closure...\n");
+ printf("> %d\n", i);
+
+ results[0].kind = WASM_I32;
+ results[0].of.i32 = (int32_t)i;
+ return NULL;
+}
+
+
+int main(int argc, const char* argv[]) {
+ // Initialize.
+ printf("Initializing...\n");
+ wasm_engine_t* engine = wasm_engine_new();
+ wasm_store_t* store = wasm_store_new(engine);
+
+ // Load binary.
+ printf("Loading binary...\n");
+ FILE* file = fopen("multi.wasm", "r");
+ if (!file) {
+ printf("> Error loading module!\n");
+ return 1;
+ }
+ fseek(file, 0L, SEEK_END);
+ size_t file_size = ftell(file);
+ fseek(file, 0L, SEEK_SET);
+ wasm_byte_vec_t binary;
+ wasm_byte_vec_new_uninitialized(&binary, file_size);
+ if (fread(binary.data, file_size, 1, file) != 1) {
+ printf("> Error loading module!\n");
+ return 1;
+ }
+ fclose(file);
+
+ // Compile.
+ printf("Compiling module...\n");
+ own wasm_module_t* module = wasm_module_new(store, &binary);
+ if (!module) {
+ printf("> Error compiling module!\n");
+ return 1;
+ }
+
+ wasm_byte_vec_delete(&binary);
+
+ // Create external print functions.
+ printf("Creating callback...\n");
+ wasm_valtype_t* types[4] = {
+ wasm_valtype_new_i32(), wasm_valtype_new_i64(),
+ wasm_valtype_new_i64(), wasm_valtype_new_i32()
+ };
+ own wasm_valtype_vec_t tuple1, tuple2;
+ wasm_valtype_vec_new(&tuple1, 4, types);
+ wasm_valtype_vec_copy(&tuple2, &tuple1);
+ own wasm_functype_t* callback_type = wasm_functype_new(&tuple1, &tuple2);
+ own wasm_func_t* callback_func =
+ wasm_func_new(store, callback_type, callback);
+
+ wasm_functype_delete(callback_type);
+
+ // Instantiate.
+ printf("Instantiating module...\n");
+ const wasm_extern_t* imports[] = {wasm_func_as_extern(callback_func)};
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, imports, NULL);
+ if (!instance) {
+ printf("> Error instantiating module!\n");
+ return 1;
+ }
+
+ wasm_func_delete(callback_func);
+
+ // Extract export.
+ printf("Extracting export...\n");
+ own wasm_extern_vec_t exports;
+ wasm_instance_exports(instance, &exports);
+ if (exports.size == 0) {
+ printf("> Error accessing exports!\n");
+ return 1;
+ }
+ const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]);
+ if (run_func == NULL) {
+ printf("> Error accessing export!\n");
+ return 1;
+ }
+
+ wasm_module_delete(module);
+ wasm_instance_delete(instance);
+
+ // Call.
+ printf("Calling export...\n");
+ wasm_val_t args[4];
+ args[0].kind = WASM_I32;
+ args[0].of.i32 = 1;
+ args[1].kind = WASM_I64;
+ args[1].of.i64 = 2;
+ args[2].kind = WASM_I64;
+ args[2].of.i64 = 3;
+ args[3].kind = WASM_I32;
+ args[3].of.i32 = 4;
+ wasm_val_t results[4];
+ if (wasm_func_call(run_func, args, results)) {
+ printf("> Error calling function!\n");
+ return 1;
+ }
+
+ wasm_extern_vec_delete(&exports);
+
+ // Print result.
+ printf("Printing result...\n");
+ printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n",
+ results[0].of.i32, results[1].of.i64,
+ results[2].of.i64, results[3].of.i32);
+
+ assert(results[0].of.i32 == 4);
+ assert(results[1].of.i64 == 3);
+ assert(results[2].of.i64 == 2);
+ assert(results[3].of.i32 == 1);
+
+ // Shut down.
+ printf("Shutting down...\n");
+ wasm_store_delete(store);
+ wasm_engine_delete(engine);
+
+ // All done.
+ printf("Done.\n");
+ return 0;
+}
diff --git a/deps/v8/third_party/wasm-api/example/multi.cc b/deps/v8/third_party/wasm-api/example/multi.cc
new file mode 100644
index 0000000000..5ed4c9b771
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/multi.cc
@@ -0,0 +1,118 @@
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <string>
+#include <cinttypes>
+
+#include "wasm.hh"
+
+// A function to be called from Wasm code.
+auto callback(
+ const wasm::Val args[], wasm::Val results[]
+) -> wasm::own<wasm::Trap> {
+ std::cout << "Calling back..." << std::endl;
+ std::cout << "> " << args[0].i32();
+ std::cout << " " << args[1].i64();
+ std::cout << " " << args[2].i64();
+ std::cout << " " << args[3].i32() << std::endl;
+ results[0] = args[3].copy();
+ results[1] = args[1].copy();
+ results[2] = args[2].copy();
+ results[3] = args[0].copy();
+ return nullptr;
+}
+
+
+void run() {
+ // Initialize.
+ std::cout << "Initializing..." << std::endl;
+ auto engine = wasm::Engine::make();
+ auto store_ = wasm::Store::make(engine.get());
+ auto store = store_.get();
+
+ // Load binary.
+ std::cout << "Loading binary..." << std::endl;
+ std::ifstream file("multi.wasm");
+ file.seekg(0, std::ios_base::end);
+ auto file_size = file.tellg();
+ file.seekg(0);
+ auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
+ file.read(binary.get(), file_size);
+ file.close();
+ if (file.fail()) {
+ std::cout << "> Error loading module!" << std::endl;
+ exit(1);
+ }
+
+ // Compile.
+ std::cout << "Compiling module..." << std::endl;
+ auto module = wasm::Module::make(store, binary);
+ if (!module) {
+ std::cout << "> Error compiling module!" << std::endl;
+ exit(1);
+ }
+
+ // Create external print functions.
+ std::cout << "Creating callback..." << std::endl;
+ auto tuple = wasm::ownvec<wasm::ValType>::make(
+ wasm::ValType::make(wasm::I32),
+ wasm::ValType::make(wasm::I64),
+ wasm::ValType::make(wasm::I64),
+ wasm::ValType::make(wasm::I32)
+ );
+ auto callback_type =
+ wasm::FuncType::make(tuple.deep_copy(), tuple.deep_copy());
+ auto callback_func = wasm::Func::make(store, callback_type.get(), callback);
+
+ // Instantiate.
+ std::cout << "Instantiating module..." << std::endl;
+ wasm::Extern* imports[] = {callback_func.get()};
+ auto instance = wasm::Instance::make(store, module.get(), imports);
+ if (!instance) {
+ std::cout << "> Error instantiating module!" << std::endl;
+ exit(1);
+ }
+
+ // Extract export.
+ std::cout << "Extracting export..." << std::endl;
+ auto exports = instance->exports();
+ if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
+ std::cout << "> Error accessing export!" << std::endl;
+ exit(1);
+ }
+ auto run_func = exports[0]->func();
+
+ // Call.
+ std::cout << "Calling export..." << std::endl;
+ wasm::Val args[] = {
+ wasm::Val::i32(1), wasm::Val::i64(2), wasm::Val::i64(3), wasm::Val::i32(4)
+ };
+ wasm::Val results[4];
+ if (wasm::own<wasm::Trap> trap = run_func->call(args, results)) {
+ std::cout << "> Error calling function! " << trap->message().get() << std::endl;
+ exit(1);
+ }
+
+ // Print result.
+ std::cout << "Printing result..." << std::endl;
+ std::cout << "> " << results[0].i32();
+ std::cout << " " << results[1].i64();
+ std::cout << " " << results[2].i64();
+ std::cout << " " << results[3].i32() << std::endl;
+
+ assert(results[0].i32() == 4);
+ assert(results[1].i64() == 3);
+ assert(results[2].i64() == 2);
+ assert(results[3].i32() == 1);
+
+ // Shut down.
+ std::cout << "Shutting down..." << std::endl;
+}
+
+
+int main(int argc, const char* argv[]) {
+ run();
+ std::cout << "Done." << std::endl;
+ return 0;
+}
+
diff --git a/deps/v8/third_party/wasm-api/example/multi.wasm b/deps/v8/third_party/wasm-api/example/multi.wasm
new file mode 100644
index 0000000000..bff0143f3f
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/multi.wasm
Binary files differ
diff --git a/deps/v8/third_party/wasm-api/example/multi.wat b/deps/v8/third_party/wasm-api/example/multi.wat
new file mode 100644
index 0000000000..e7fb331125
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/multi.wat
@@ -0,0 +1,7 @@
+(module
+ (func $f (import "" "f") (param i32 i64 i64 i32) (result i32 i64 i64 i32))
+
+ (func $g (export "g") (param i32 i64 i64 i32) (result i32 i64 i64 i32)
+ (call $f (local.get 0) (local.get 2) (local.get 1) (local.get 3))
+ )
+)
diff --git a/deps/v8/third_party/wasm-api/example/reflect.c b/deps/v8/third_party/wasm-api/example/reflect.c
index a210a85c15..15e0165d19 100644
--- a/deps/v8/third_party/wasm-api/example/reflect.c
+++ b/deps/v8/third_party/wasm-api/example/reflect.c
@@ -45,28 +45,32 @@ void print_valtypes(const wasm_valtype_vec_t* types) {
void print_externtype(const wasm_externtype_t* type) {
switch (wasm_externtype_kind(type)) {
case WASM_EXTERN_FUNC: {
- const wasm_functype_t* functype = wasm_externtype_as_functype_const(type);
+ const wasm_functype_t* functype =
+ wasm_externtype_as_functype_const(type);
printf("func ");
print_valtypes(wasm_functype_params(functype));
printf(" -> ");
print_valtypes(wasm_functype_results(functype));
} break;
case WASM_EXTERN_GLOBAL: {
- const wasm_globaltype_t* globaltype = wasm_externtype_as_globaltype_const(type);
+ const wasm_globaltype_t* globaltype =
+ wasm_externtype_as_globaltype_const(type);
printf("global ");
print_mutability(wasm_globaltype_mutability(globaltype));
printf(" ");
print_valtype(wasm_globaltype_content(globaltype));
} break;
case WASM_EXTERN_TABLE: {
- const wasm_tabletype_t* tabletype = wasm_externtype_as_tabletype_const(type);
+ const wasm_tabletype_t* tabletype =
+ wasm_externtype_as_tabletype_const(type);
printf("table ");
print_limits(wasm_tabletype_limits(tabletype));
printf(" ");
print_valtype(wasm_tabletype_element(tabletype));
} break;
case WASM_EXTERN_MEMORY: {
- const wasm_memorytype_t* memorytype = wasm_externtype_as_memorytype_const(type);
+ const wasm_memorytype_t* memorytype =
+ wasm_externtype_as_memorytype_const(type);
printf("memory ");
print_limits(wasm_memorytype_limits(memorytype));
} break;
@@ -114,7 +118,7 @@ int main(int argc, const char* argv[]) {
// Instantiate.
printf("Instantiating module...\n");
- own wasm_instance_t* instance = wasm_instance_new(store, module, NULL);
+ own wasm_instance_t* instance = wasm_instance_new(store, module, NULL, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
@@ -129,7 +133,8 @@ int main(int argc, const char* argv[]) {
assert(exports.size == export_types.size);
for (size_t i = 0; i < exports.size; ++i) {
- assert(wasm_extern_kind(exports.data[i]) == wasm_externtype_kind(wasm_exporttype_type(export_types.data[i])));
+ assert(wasm_extern_kind(exports.data[i]) ==
+ wasm_externtype_kind(wasm_exporttype_type(export_types.data[i])));
printf("> export %zu ", i);
print_name(wasm_exporttype_name(export_types.data[i]));
printf("\n");
diff --git a/deps/v8/third_party/wasm-api/example/reflect.cc b/deps/v8/third_party/wasm-api/example/reflect.cc
index c04b9e4d4e..e0f8ba6856 100644
--- a/deps/v8/third_party/wasm-api/example/reflect.cc
+++ b/deps/v8/third_party/wasm-api/example/reflect.cc
@@ -33,7 +33,7 @@ auto operator<<(std::ostream& out, const wasm::ValType& type) -> std::ostream& {
return out;
}
-auto operator<<(std::ostream& out, const wasm::vec<wasm::ValType*>& types) -> std::ostream& {
+auto operator<<(std::ostream& out, const wasm::ownvec<wasm::ValType>& types) -> std::ostream& {
bool first = true;
for (size_t i = 0; i < types.size(); ++i) {
if (first) {
@@ -88,7 +88,7 @@ void run() {
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
- return;
+ exit(1);
}
// Compile.
@@ -96,7 +96,7 @@ void run() {
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Instantiate.
@@ -104,7 +104,7 @@ void run() {
auto instance = wasm::Instance::make(store, module.get(), nullptr);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
- return;
+ exit(1);
}
// Extract exports.
diff --git a/deps/v8/third_party/wasm-api/example/serialize.c b/deps/v8/third_party/wasm-api/example/serialize.c
index 8c7efc2ee9..4522c00dff 100644
--- a/deps/v8/third_party/wasm-api/example/serialize.c
+++ b/deps/v8/third_party/wasm-api/example/serialize.c
@@ -77,7 +77,8 @@ int main(int argc, const char* argv[]) {
// Instantiate.
printf("Instantiating deserialized module...\n");
const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) };
- own wasm_instance_t* instance = wasm_instance_new(store, deserialized, imports);
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, deserialized, imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
diff --git a/deps/v8/third_party/wasm-api/example/serialize.cc b/deps/v8/third_party/wasm-api/example/serialize.cc
index 895ef396e0..7f74edba76 100644
--- a/deps/v8/third_party/wasm-api/example/serialize.cc
+++ b/deps/v8/third_party/wasm-api/example/serialize.cc
@@ -10,7 +10,7 @@
// A function to be called from Wasm code.
auto hello_callback(
const wasm::Val args[], wasm::Val results[]
-) -> wasm::own<wasm::Trap*> {
+) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
std::cout << "> Hello world!" << std::endl;
return nullptr;
@@ -35,7 +35,7 @@ void run() {
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
- return;
+ exit(1);
}
// Compile.
@@ -43,7 +43,7 @@ void run() {
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Serialize module.
@@ -55,13 +55,13 @@ void run() {
auto deserialized = wasm::Module::deserialize(store, serialized);
if (!deserialized) {
std::cout << "> Error deserializing module!" << std::endl;
- return;
+ exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto hello_type = wasm::FuncType::make(
- wasm::vec<wasm::ValType*>::make(), wasm::vec<wasm::ValType*>::make()
+ wasm::ownvec<wasm::ValType>::make(), wasm::ownvec<wasm::ValType>::make()
);
auto hello_func = wasm::Func::make(store, hello_type.get(), hello_callback);
@@ -71,7 +71,7 @@ void run() {
auto instance = wasm::Instance::make(store, deserialized.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
- return;
+ exit(1);
}
// Extract export.
@@ -79,15 +79,15 @@ void run() {
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
- return;
+ exit(1);
}
auto run_func = exports[0]->func();
// Call.
std::cout << "Calling export..." << std::endl;
- if (! run_func->call()) {
+ if (run_func->call()) {
std::cout << "> Error calling function!" << std::endl;
- return;
+ exit(1);
}
// Shut down.
diff --git a/deps/v8/third_party/wasm-api/example/start.c b/deps/v8/third_party/wasm-api/example/start.c
new file mode 100644
index 0000000000..42fa317490
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/start.c
@@ -0,0 +1,105 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "wasm.h"
+
+#define own
+
+
+void print_frame(wasm_frame_t* frame) {
+ printf("> %p @ 0x%zx = %"PRIu32".0x%zx\n",
+ wasm_frame_instance(frame),
+ wasm_frame_module_offset(frame),
+ wasm_frame_func_index(frame),
+ wasm_frame_func_offset(frame)
+ );
+}
+
+
+int main(int argc, const char* argv[]) {
+ // Initialize.
+ printf("Initializing...\n");
+ wasm_engine_t* engine = wasm_engine_new();
+ wasm_store_t* store = wasm_store_new(engine);
+
+ // Load binary.
+ printf("Loading binary...\n");
+ FILE* file = fopen("start.wasm", "r");
+ if (!file) {
+ printf("> Error loading module!\n");
+ return 1;
+ }
+ fseek(file, 0L, SEEK_END);
+ size_t file_size = ftell(file);
+ fseek(file, 0L, SEEK_SET);
+ wasm_byte_vec_t binary;
+ wasm_byte_vec_new_uninitialized(&binary, file_size);
+ if (fread(binary.data, file_size, 1, file) != 1) {
+ printf("> Error loading module!\n");
+ return 1;
+ }
+ fclose(file);
+
+ // Compile.
+ printf("Compiling module...\n");
+ own wasm_module_t* module = wasm_module_new(store, &binary);
+ if (!module) {
+ printf("> Error compiling module!\n");
+ return 1;
+ }
+
+ wasm_byte_vec_delete(&binary);
+
+ // Instantiate.
+ printf("Instantiating module...\n");
+ own wasm_trap_t* trap = NULL;
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, NULL, &trap);
+ if (instance || !trap) {
+ printf("> Error instantiating module, expected trap!\n");
+ return 1;
+ }
+
+ wasm_module_delete(module);
+
+ // Print result.
+ printf("Printing message...\n");
+ own wasm_name_t message;
+ wasm_trap_message(trap, &message);
+ printf("> %s\n", message.data);
+
+ printf("Printing origin...\n");
+ own wasm_frame_t* frame = wasm_trap_origin(trap);
+ if (frame) {
+ print_frame(frame);
+ wasm_frame_delete(frame);
+ } else {
+ printf("> Empty origin.\n");
+ }
+
+ printf("Printing trace...\n");
+ own wasm_frame_vec_t trace;
+ wasm_trap_trace(trap, &trace);
+ if (trace.size > 0) {
+ for (size_t i = 0; i < trace.size; ++i) {
+ print_frame(trace.data[i]);
+ }
+ } else {
+ printf("> Empty trace.\n");
+ }
+
+ wasm_frame_vec_delete(&trace);
+ wasm_trap_delete(trap);
+ wasm_name_delete(&message);
+
+ // Shut down.
+ printf("Shutting down...\n");
+ wasm_store_delete(store);
+ wasm_engine_delete(engine);
+
+ // All done.
+ printf("Done.\n");
+ return 0;
+}
diff --git a/deps/v8/third_party/wasm-api/example/start.cc b/deps/v8/third_party/wasm-api/example/start.cc
new file mode 100644
index 0000000000..71d6fd25ad
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/start.cc
@@ -0,0 +1,88 @@
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <string>
+#include <cinttypes>
+
+#include "wasm.hh"
+
+
+void print_frame(const wasm::Frame* frame) {
+ std::cout << "> " << frame->instance();
+ std::cout << " @ 0x" << std::hex << frame->module_offset();
+ std::cout << " = " << frame->func_index();
+ std::cout << ".0x" << std::hex << frame->func_offset() << std::endl;
+}
+
+
+void run() {
+ // Initialize.
+ std::cout << "Initializing..." << std::endl;
+ auto engine = wasm::Engine::make();
+ auto store_ = wasm::Store::make(engine.get());
+ auto store = store_.get();
+
+ // Load binary.
+ std::cout << "Loading binary..." << std::endl;
+ std::ifstream file("start.wasm");
+ file.seekg(0, std::ios_base::end);
+ auto file_size = file.tellg();
+ file.seekg(0);
+ auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
+ file.read(binary.get(), file_size);
+ file.close();
+ if (file.fail()) {
+ std::cout << "> Error loading module!" << std::endl;
+ exit(1);
+ }
+
+ // Compile.
+ std::cout << "Compiling module..." << std::endl;
+ auto module = wasm::Module::make(store, binary);
+ if (!module) {
+ std::cout << "> Error compiling module!" << std::endl;
+ exit(1);
+ }
+
+ // Instantiate.
+ std::cout << "Instantiating module..." << std::endl;
+ wasm::own<wasm::Trap> trap;
+ auto instance = wasm::Instance::make(store, module.get(), nullptr, &trap);
+ if (instance || !trap) {
+ std::cout << "> Error instantiating module, expected trap!" << std::endl;
+ exit(1);
+ }
+
+ // Print result.
+ std::cout << "Printing message..." << std::endl;
+ std::cout << "> " << trap->message().get() << std::endl;
+
+ std::cout << "Printing origin..." << std::endl;
+ auto frame = trap->origin();
+ if (frame) {
+ print_frame(frame.get());
+ } else {
+ std::cout << "> Empty origin." << std::endl;
+ }
+
+ std::cout << "Printing trace..." << std::endl;
+ auto trace = trap->trace();
+ if (trace.size() > 0) {
+ for (size_t i = 0; i < trace.size(); ++i) {
+ print_frame(trace[i].get());
+ }
+ } else {
+ std::cout << "> Empty trace." << std::endl;
+ }
+
+ // Shut down.
+ std::cout << "Shutting down..." << std::endl;
+}
+
+
+int main(int argc, const char* argv[]) {
+ run();
+ std::cout << "Done." << std::endl;
+ return 0;
+}
+
diff --git a/deps/v8/third_party/wasm-api/example/start.wasm b/deps/v8/third_party/wasm-api/example/start.wasm
new file mode 100644
index 0000000000..90cba2107d
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/start.wasm
Binary files differ
diff --git a/deps/v8/third_party/wasm-api/example/start.wat b/deps/v8/third_party/wasm-api/example/start.wat
new file mode 100644
index 0000000000..eb95116a49
--- /dev/null
+++ b/deps/v8/third_party/wasm-api/example/start.wat
@@ -0,0 +1,4 @@
+(module
+ (func $start (unreachable))
+ (start $start)
+)
diff --git a/deps/v8/third_party/wasm-api/example/table.c b/deps/v8/third_party/wasm-api/example/table.c
index 8fec71f23f..0ff6617f72 100644
--- a/deps/v8/third_party/wasm-api/example/table.c
+++ b/deps/v8/third_party/wasm-api/example/table.c
@@ -110,7 +110,8 @@ int main(int argc, const char* argv[]) {
// Instantiate.
printf("Instantiating module...\n");
- own wasm_instance_t* instance = wasm_instance_new(store, module, NULL);
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, NULL, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
@@ -135,6 +136,11 @@ int main(int argc, const char* argv[]) {
wasm_functype_delete(neg_type);
+ // Try cloning.
+ own wasm_table_t* copy = wasm_table_copy(table);
+ assert(wasm_table_same(table, copy));
+ wasm_table_delete(copy);
+
// Check initial table.
printf("Checking table...\n");
check(wasm_table_size(table) == 2);
diff --git a/deps/v8/third_party/wasm-api/example/table.cc b/deps/v8/third_party/wasm-api/example/table.cc
index cb669cdb16..b19d37763b 100644
--- a/deps/v8/third_party/wasm-api/example/table.cc
+++ b/deps/v8/third_party/wasm-api/example/table.cc
@@ -10,14 +10,14 @@
// A function to be called from Wasm code.
auto neg_callback(
const wasm::Val args[], wasm::Val results[]
-) -> wasm::own<wasm::Trap*> {
+) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
results[0] = wasm::Val(-args[0].i32());
return nullptr;
}
-auto get_export_table(wasm::vec<wasm::Extern*>& exports, size_t i) -> wasm::Table* {
+auto get_export_table(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Table* {
if (exports.size() <= i || !exports[i]->table()) {
std::cout << "> Error accessing table export " << i << "!" << std::endl;
exit(1);
@@ -25,7 +25,7 @@ auto get_export_table(wasm::vec<wasm::Extern*>& exports, size_t i) -> wasm::Tabl
return exports[i]->table();
}
-auto get_export_func(const wasm::vec<wasm::Extern*>& exports, size_t i) -> const wasm::Func* {
+auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> const wasm::Func* {
if (exports.size() <= i || !exports[i]->func()) {
std::cout << "> Error accessing function export " << i << "!" << std::endl;
exit(1);
@@ -87,7 +87,7 @@ void run() {
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
- return;
+ exit(1);
}
// Compile.
@@ -95,7 +95,7 @@ void run() {
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Instantiate.
@@ -103,7 +103,7 @@ void run() {
auto instance = wasm::Instance::make(store, module.get(), nullptr);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
- return;
+ exit(1);
}
// Extract export.
@@ -118,11 +118,14 @@ void run() {
// Create external function.
std::cout << "Creating callback..." << std::endl;
auto neg_type = wasm::FuncType::make(
- wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)),
- wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32))
+ wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32)),
+ wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32))
);
auto h = wasm::Func::make(store, neg_type.get(), neg_callback);
+ // Try cloning.
+ assert(table->copy()->same(table));
+
// Check initial table.
std::cout << "Checking table..." << std::endl;
check(table->size(), 2u);
diff --git a/deps/v8/third_party/wasm-api/example/threads.c b/deps/v8/third_party/wasm-api/example/threads.c
index 2f5b0f3c1f..9f9d5894a6 100644
--- a/deps/v8/third_party/wasm-api/example/threads.c
+++ b/deps/v8/third_party/wasm-api/example/threads.c
@@ -52,7 +52,8 @@ void* run(void* args_abs) {
const wasm_extern_t* imports[] = {
wasm_func_as_extern(func), wasm_global_as_extern(global),
};
- own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return NULL;
diff --git a/deps/v8/third_party/wasm-api/example/threads.cc b/deps/v8/third_party/wasm-api/example/threads.cc
index 48b4fcd486..3fdaded6cd 100644
--- a/deps/v8/third_party/wasm-api/example/threads.cc
+++ b/deps/v8/third_party/wasm-api/example/threads.cc
@@ -11,7 +11,7 @@ const int N_REPS = 3;
// A function to be called from Wasm code.
auto callback(
void* env, const wasm::Val args[], wasm::Val results[]
-) -> wasm::own<wasm::Trap*> {
+) -> wasm::own<wasm::Trap> {
assert(args[0].kind() == wasm::I32);
std::lock_guard<std::mutex>(*reinterpret_cast<std::mutex*>(env));
std::cout << "Thread " << args[0].i32() << " running..." << std::endl;
@@ -33,7 +33,7 @@ void run(
if (!module) {
std::lock_guard<std::mutex> lock(*mutex);
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Run the example N times.
@@ -42,8 +42,8 @@ void run(
// Create imports.
auto func_type = wasm::FuncType::make(
- wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)),
- wasm::vec<wasm::ValType*>::make()
+ wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32)),
+ wasm::ownvec<wasm::ValType>::make()
);
auto func = wasm::Func::make(store, func_type.get(), callback, mutex);
@@ -58,7 +58,7 @@ void run(
if (!instance) {
std::lock_guard<std::mutex> lock(*mutex);
std::cout << "> Error instantiating module!" << std::endl;
- return;
+ exit(1);
}
// Extract export.
@@ -66,7 +66,7 @@ void run(
if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
std::lock_guard<std::mutex> lock(*mutex);
std::cout << "> Error accessing export!" << std::endl;
- return;
+ exit(1);
}
auto run_func = exports[0]->func();
diff --git a/deps/v8/third_party/wasm-api/example/trap.c b/deps/v8/third_party/wasm-api/example/trap.c
index 74620dce3b..975d6f8599 100644
--- a/deps/v8/third_party/wasm-api/example/trap.c
+++ b/deps/v8/third_party/wasm-api/example/trap.c
@@ -20,6 +20,16 @@ own wasm_trap_t* fail_callback(
}
+void print_frame(wasm_frame_t* frame) {
+ printf("> %p @ 0x%zx = %"PRIu32".0x%zx\n",
+ wasm_frame_instance(frame),
+ wasm_frame_module_offset(frame),
+ wasm_frame_func_index(frame),
+ wasm_frame_func_offset(frame)
+ );
+}
+
+
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
@@ -56,15 +66,18 @@ int main(int argc, const char* argv[]) {
// Create external print functions.
printf("Creating callback...\n");
- own wasm_functype_t* fail_type = wasm_functype_new_0_1(wasm_valtype_new_i32());
- own wasm_func_t* fail_func = wasm_func_new_with_env(store, fail_type, fail_callback, store, NULL);
+ own wasm_functype_t* fail_type =
+ wasm_functype_new_0_1(wasm_valtype_new_i32());
+ own wasm_func_t* fail_func =
+ wasm_func_new_with_env(store, fail_type, fail_callback, store, NULL);
wasm_functype_delete(fail_type);
// Instantiate.
printf("Instantiating module...\n");
const wasm_extern_t* imports[] = { wasm_func_as_extern(fail_func) };
- own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
+ own wasm_instance_t* instance =
+ wasm_instance_new(store, module, imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
@@ -94,8 +107,8 @@ int main(int argc, const char* argv[]) {
printf("Calling export %d...\n", i);
own wasm_trap_t* trap = wasm_func_call(func, NULL, NULL);
- if (! trap) {
- printf("> Error calling function!\n");
+ if (!trap) {
+ printf("> Error calling function, expected trap!\n");
return 1;
}
@@ -104,6 +117,27 @@ int main(int argc, const char* argv[]) {
wasm_trap_message(trap, &message);
printf("> %s\n", message.data);
+ printf("Printing origin...\n");
+ own wasm_frame_t* frame = wasm_trap_origin(trap);
+ if (frame) {
+ print_frame(frame);
+ wasm_frame_delete(frame);
+ } else {
+ printf("> Empty origin.\n");
+ }
+
+ printf("Printing trace...\n");
+ own wasm_frame_vec_t trace;
+ wasm_trap_trace(trap, &trace);
+ if (trace.size > 0) {
+ for (size_t i = 0; i < trace.size; ++i) {
+ print_frame(trace.data[i]);
+ }
+ } else {
+ printf("> Empty trace.\n");
+ }
+
+ wasm_frame_vec_delete(&trace);
wasm_trap_delete(trap);
wasm_name_delete(&message);
}
diff --git a/deps/v8/third_party/wasm-api/example/trap.cc b/deps/v8/third_party/wasm-api/example/trap.cc
index 3311621724..3a7dcc6cff 100644
--- a/deps/v8/third_party/wasm-api/example/trap.cc
+++ b/deps/v8/third_party/wasm-api/example/trap.cc
@@ -9,7 +9,7 @@
// A function to be called from Wasm code.
auto fail_callback(
void* env, const wasm::Val args[], wasm::Val results[]
-) -> wasm::own<wasm::Trap*> {
+) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
auto store = reinterpret_cast<wasm::Store*>(env);
auto message = wasm::Name::make(std::string("callback abort"));
@@ -17,6 +17,14 @@ auto fail_callback(
}
+void print_frame(const wasm::Frame* frame) {
+ std::cout << "> " << frame->instance();
+ std::cout << " @ 0x" << std::hex << frame->module_offset();
+ std::cout << " = " << frame->func_index();
+ std::cout << ".0x" << std::hex << frame->func_offset() << std::endl;
+}
+
+
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
@@ -35,7 +43,7 @@ void run() {
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
- return;
+ exit(1);
}
// Compile.
@@ -43,14 +51,14 @@ void run() {
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
- return;
+ exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto fail_type = wasm::FuncType::make(
- wasm::vec<wasm::ValType*>::make(),
- wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32))
+ wasm::ownvec<wasm::ValType>::make(),
+ wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32))
);
auto fail_func =
wasm::Func::make(store, fail_type.get(), fail_callback, store);
@@ -61,7 +69,7 @@ void run() {
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
- return;
+ exit(1);
}
// Extract export.
@@ -71,7 +79,7 @@ void run() {
exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func() ||
exports[1]->kind() != wasm::EXTERN_FUNC || !exports[1]->func()) {
std::cout << "> Error accessing exports!" << std::endl;
- return;
+ exit(1);
}
// Call.
@@ -79,12 +87,30 @@ void run() {
std::cout << "Calling export " << i << "..." << std::endl;
auto trap = exports[i]->func()->call();
if (!trap) {
- std::cout << "> Error calling function!" << std::endl;
- return;
+ std::cout << "> Error calling function, expected trap!" << std::endl;
+ exit(1);
}
std::cout << "Printing message..." << std::endl;
std::cout << "> " << trap->message().get() << std::endl;
+
+ std::cout << "Printing origin..." << std::endl;
+ auto frame = trap->origin();
+ if (frame) {
+ print_frame(frame.get());
+ } else {
+ std::cout << "> Empty origin." << std::endl;
+ }
+
+ std::cout << "Printing trace..." << std::endl;
+ auto trace = trap->trace();
+ if (trace.size() > 0) {
+ for (size_t i = 0; i < trace.size(); ++i) {
+ print_frame(trace[i].get());
+ }
+ } else {
+ std::cout << "> Empty trace." << std::endl;
+ }
}
// Shut down.
diff --git a/deps/v8/third_party/wasm-api/wasm.h b/deps/v8/third_party/wasm-api/wasm.h
index bb66c042d9..e343c55fae 100644
--- a/deps/v8/third_party/wasm-api/wasm.h
+++ b/deps/v8/third_party/wasm-api/wasm.h
@@ -136,10 +136,11 @@ own wasm_store_t* wasm_store_new(wasm_engine_t*);
// Type attributes
-typedef enum wasm_mutability_t {
+typedef uint8_t wasm_mutability_t;
+enum wasm_mutability_enum {
WASM_CONST,
- WASM_VAR
-} wasm_mutability_t;
+ WASM_VAR,
+};
typedef struct wasm_limits_t {
uint32_t min;
@@ -162,14 +163,15 @@ static const uint32_t wasm_limits_max_default = 0xffffffff;
WASM_DECLARE_TYPE(valtype)
-typedef enum wasm_valkind_t {
+typedef uint8_t wasm_valkind_t;
+enum wasm_valkind_enum {
WASM_I32,
WASM_I64,
WASM_F32,
WASM_F64,
- WASM_ANYREF,
- WASM_FUNCREF
-} wasm_valkind_t;
+ WASM_ANYREF = 128,
+ WASM_FUNCREF,
+};
own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t);
@@ -236,12 +238,13 @@ const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t*);
WASM_DECLARE_TYPE(externtype)
-typedef enum wasm_externkind_t {
+typedef uint8_t wasm_externkind_t;
+enum wasm_externkind_enum {
WASM_EXTERN_FUNC,
WASM_EXTERN_GLOBAL,
WASM_EXTERN_TABLE,
- WASM_EXTERN_MEMORY
-} wasm_externkind_t;
+ WASM_EXTERN_MEMORY,
+};
wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t*);
@@ -315,15 +318,16 @@ WASM_DECLARE_VEC(val, )
// References
-#define WASM_DECLARE_REF_BASE(name) \
- WASM_DECLARE_OWN(name) \
- \
- own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); \
- \
- void* wasm_##name##_get_host_info(const wasm_##name##_t*); \
- void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \
- void wasm_##name##_set_host_info_with_finalizer( \
- wasm_##name##_t*, void*, void (*)(void*));
+#define WASM_DECLARE_REF_BASE(name) \
+ WASM_DECLARE_OWN(name) \
+ \
+ own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); \
+ bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); \
+ \
+ void* wasm_##name##_get_host_info(const wasm_##name##_t*); \
+ void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \
+ void wasm_##name##_set_host_info_with_finalizer(wasm_##name##_t*, void*, \
+ void (*)(void*));
#define WASM_DECLARE_REF(name) \
WASM_DECLARE_REF_BASE(name) \
@@ -344,6 +348,18 @@ WASM_DECLARE_VEC(val, )
WASM_DECLARE_REF_BASE(ref)
+// Frames
+
+WASM_DECLARE_OWN(frame)
+WASM_DECLARE_VEC(frame, *)
+own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*);
+
+struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*);
+uint32_t wasm_frame_func_index(const wasm_frame_t*);
+size_t wasm_frame_func_offset(const wasm_frame_t*);
+size_t wasm_frame_module_offset(const wasm_frame_t*);
+
+
// Traps
typedef wasm_name_t wasm_message_t; // null terminated
@@ -353,6 +369,8 @@ WASM_DECLARE_REF(trap)
own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*);
void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out);
+own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*);
+void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out);
// Foreign Objects
@@ -485,7 +503,9 @@ const wasm_memory_t* wasm_extern_as_memory_const(const wasm_extern_t*);
WASM_DECLARE_REF(instance)
own wasm_instance_t* wasm_instance_new(
- wasm_store_t*, const wasm_module_t*, const wasm_extern_t* const imports[]);
+ wasm_store_t*, const wasm_module_t*, const wasm_extern_t* const imports[],
+ own wasm_trap_t**
+);
void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out);
diff --git a/deps/v8/third_party/wasm-api/wasm.hh b/deps/v8/third_party/wasm-api/wasm.hh
index c153d4b9df..8def22428b 100644
--- a/deps/v8/third_party/wasm-api/wasm.hh
+++ b/deps/v8/third_party/wasm-api/wasm.hh
@@ -29,89 +29,16 @@ using float64_t = double;
namespace wasm {
-// Ownership
-
-template<class T> struct owner { using type = T; };
-template<class T> struct owner<T*> { using type = std::unique_ptr<T>; };
-
-template<class T>
-using own = typename owner<T>::type;
-
-template<class T>
-auto make_own(T x) -> own<T> { return own<T>(std::move(x)); }
-
-
// Vectors
template<class T>
-struct vec_traits {
- static void construct(size_t size, T data[]) {}
- static void destruct(size_t size, T data[]) {}
- static void move(size_t size, T* data, T init[]) {
- for (size_t i = 0; i < size; ++i) data[i] = std::move(init[i]);
- }
- static void copy(size_t size, T data[], const T init[]) {
- for (size_t i = 0; i < size; ++i) data[i] = init[i];
- }
-
- using proxy = T&;
-};
-
-template<class T>
-struct vec_traits<T*> {
- static void construct(size_t size, T* data[]) {
- for (size_t i = 0; i < size; ++i) data[i] = nullptr;
- }
- static void destruct(size_t size, T* data[]) {
- for (size_t i = 0; i < size; ++i) {
- if (data[i]) delete data[i];
- }
- }
- static void move(size_t size, T* data[], own<T*> init[]) {
- for (size_t i = 0; i < size; ++i) data[i] = init[i].release();
- }
- static void copy(size_t size, T* data[], const T* const init[]) {
- for (size_t i = 0; i < size; ++i) {
- if (init[i]) data[i] = init[i]->copy().release();
- }
- }
-
- class proxy {
- T*& elem_;
- public:
- proxy(T*& elem) : elem_(elem) {}
- operator T*() { return elem_; }
- operator const T*() const { return elem_; }
- auto operator=(own<T*>&& elem) -> proxy& {
- reset(std::move(elem));
- return *this;
- }
- void reset(own<T*>&& val = own<T*>()) {
- if (elem_) delete elem_;
- elem_ = val.release();
- }
- auto release() -> T* {
- auto elem = elem_;
- elem_ = nullptr;
- return elem;
- }
- auto move() -> own<T*> { return make_own(release()); }
- auto get() -> T* { return elem_; }
- auto get() const -> const T* { return elem_; }
- auto operator->() -> T* { return elem_; }
- auto operator->() const -> const T* { return elem_; }
- };
-};
-
-
-template<class T>
class vec {
static const size_t invalid_size = SIZE_MAX;
size_t size_;
std::unique_ptr<T[]> data_;
-#ifdef DEBUG
+#ifdef WASM_API_DEBUG
void make_data();
void free_data();
#else
@@ -128,11 +55,11 @@ class vec {
}
public:
- template<class U>
- vec(vec<U>&& that) : vec(that.size_, that.data_.release()) {}
+ using elem_type = T;
+
+ vec(vec<T>&& that) : vec(that.size_, that.data_.release()) {}
~vec() {
- if (data_) vec_traits<T>::destruct(size_, data_.get());
free_data();
}
@@ -157,14 +84,13 @@ public:
}
void reset() {
- if (data_) vec_traits<T>::destruct(size_, data_.get());
free_data();
- size_ = 0;
+ size_ = invalid_size;
data_.reset();
}
void reset(vec& that) {
- reset();
+ free_data();
size_ = that.size_;
data_.reset(that.data_.release());
}
@@ -174,31 +100,36 @@ public:
return *this;
}
- auto operator[](size_t i) -> typename vec_traits<T>::proxy {
+ auto operator[](size_t i) -> T& {
assert(i < size_);
- return typename vec_traits<T>::proxy(data_[i]);
+ return data_[i];
}
- auto operator[](size_t i) const -> const typename vec_traits<T>::proxy {
+ auto operator[](size_t i) const -> const T& {
assert(i < size_);
- return typename vec_traits<T>::proxy(data_[i]);
+ return data_[i];
}
auto copy() const -> vec {
auto v = vec(size_);
- if (v) vec_traits<T>::copy(size_, v.data_.get(), data_.get());
+ if (v) for (size_t i = 0; i < size_; i++) v.data_[i] = data_[i];
return v;
}
- static auto make_uninitialized(size_t size = 0) -> vec {
- auto v = vec(size);
- if (v) vec_traits<T>::construct(size, v.data_.get());
+ // TODO: This can't be used for e.g. vec<Val>
+ auto deep_copy() const -> vec {
+ auto v = vec(size_);
+ if (v) for (size_t i = 0; i < size_; ++i) v.data_[i] = data_[i]->copy();
return v;
}
- static auto make(size_t size, own<T> init[]) -> vec {
+ static auto make_uninitialized(size_t size = 0) -> vec {
+ return vec(size);
+ }
+
+ static auto make(size_t size, T init[]) -> vec {
auto v = vec(size);
- if (v) vec_traits<T>::move(size, v.data_.get(), init);
+ if (v) for (size_t i = 0; i < size; ++i) v.data_[i] = std::move(init[i]);
return v;
}
@@ -208,13 +139,14 @@ public:
return v;
}
+ // TODO(mvsc): MVSC requires this special case:
static auto make() -> vec {
return vec(0);
}
template<class... Ts>
static auto make(Ts&&... args) -> vec {
- own<T> data[] = { make_own(std::move(args))... };
+ T data[] = { std::move(args)... };
return make(sizeof...(Ts), data);
}
@@ -228,6 +160,15 @@ public:
};
+// Ownership
+
+template<class T> using own = std::unique_ptr<T>;
+template<class T> using ownvec = vec<own<T>>;
+
+template<class T>
+auto make_own(T* x) -> own<T> { return own<T>(x); }
+
+
///////////////////////////////////////////////////////////////////////////////
// Runtime Environment
@@ -239,7 +180,7 @@ public:
~Config();
void operator delete(void*);
- static auto make() -> own<Config*>;
+ static auto make() -> own<Config>;
// Implementations may provide custom methods for manipulating Configs.
};
@@ -253,7 +194,7 @@ public:
~Engine();
void operator delete(void*);
- static auto make(own<Config*>&& = Config::make()) -> own<Engine*>;
+ static auto make(own<Config>&& = Config::make()) -> own<Engine>;
};
@@ -265,7 +206,7 @@ public:
~Store();
void operator delete(void*);
- static auto make(Engine*) -> own<Store*>;
+ static auto make(Engine*) -> own<Store>;
};
@@ -274,7 +215,7 @@ public:
// Type attributes
-enum Mutability { CONST, VAR };
+enum Mutability : uint8_t { CONST, VAR };
struct Limits {
uint32_t min;
@@ -287,7 +228,10 @@ struct Limits {
// Value Types
-enum ValKind { I32, I64, F32, F64, ANYREF, FUNCREF };
+enum ValKind : uint8_t {
+ I32, I64, F32, F64,
+ ANYREF = 128, FUNCREF,
+};
inline bool is_num(ValKind k) { return k < ANYREF; }
inline bool is_ref(ValKind k) { return k >= ANYREF; }
@@ -299,8 +243,8 @@ public:
~ValType();
void operator delete(void*);
- static auto make(ValKind) -> own<ValType*>;
- auto copy() const -> own<ValType*>;
+ static auto make(ValKind) -> own<ValType>;
+ auto copy() const -> own<ValType>;
auto kind() const -> ValKind;
auto is_num() const -> bool { return wasm::is_num(kind()); }
@@ -310,7 +254,7 @@ public:
// External Types
-enum ExternKind {
+enum ExternKind : uint8_t {
EXTERN_FUNC, EXTERN_GLOBAL, EXTERN_TABLE, EXTERN_MEMORY
};
@@ -325,7 +269,7 @@ public:
~ExternType();
void operator delete(void*);
- auto copy() const-> own<ExternType*>;
+ auto copy() const-> own<ExternType>;
auto kind() const -> ExternKind;
@@ -343,22 +287,20 @@ public:
// Function Types
-enum class arrow { ARROW };
-
class FuncType : public ExternType {
public:
FuncType() = delete;
~FuncType();
static auto make(
- vec<ValType*>&& params = vec<ValType*>::make(),
- vec<ValType*>&& results = vec<ValType*>::make()
- ) -> own<FuncType*>;
+ ownvec<ValType>&& params = ownvec<ValType>::make(),
+ ownvec<ValType>&& results = ownvec<ValType>::make()
+ ) -> own<FuncType>;
- auto copy() const -> own<FuncType*>;
+ auto copy() const -> own<FuncType>;
- auto params() const -> const vec<ValType*>&;
- auto results() const -> const vec<ValType*>&;
+ auto params() const -> const ownvec<ValType>&;
+ auto results() const -> const ownvec<ValType>&;
};
@@ -369,8 +311,8 @@ public:
GlobalType() = delete;
~GlobalType();
- static auto make(own<ValType*>&&, Mutability) -> own<GlobalType*>;
- auto copy() const -> own<GlobalType*>;
+ static auto make(own<ValType>&&, Mutability) -> own<GlobalType>;
+ auto copy() const -> own<GlobalType>;
auto content() const -> const ValType*;
auto mutability() const -> Mutability;
@@ -384,8 +326,8 @@ public:
TableType() = delete;
~TableType();
- static auto make(own<ValType*>&&, Limits) -> own<TableType*>;
- auto copy() const -> own<TableType*>;
+ static auto make(own<ValType>&&, Limits) -> own<TableType>;
+ auto copy() const -> own<TableType>;
auto element() const -> const ValType*;
auto limits() const -> const Limits&;
@@ -399,8 +341,8 @@ public:
MemoryType() = delete;
~MemoryType();
- static auto make(Limits) -> own<MemoryType*>;
- auto copy() const -> own<MemoryType*>;
+ static auto make(Limits) -> own<MemoryType>;
+ auto copy() const -> own<MemoryType>;
auto limits() const -> const Limits&;
};
@@ -416,9 +358,9 @@ public:
~ImportType();
void operator delete(void*);
- static auto make(Name&& module, Name&& name, own<ExternType*>&&) ->
- own<ImportType*>;
- auto copy() const -> own<ImportType*>;
+ static auto make(Name&& module, Name&& name, own<ExternType>&&) ->
+ own<ImportType>;
+ auto copy() const -> own<ImportType>;
auto module() const -> const Name&;
auto name() const -> const Name&;
@@ -434,8 +376,8 @@ public:
~ExportType();
void operator delete(void*);
- static auto make(Name&&, own<ExternType*>&&) -> own<ExportType*>;
- auto copy() const -> own<ExportType*>;
+ static auto make(Name&&, own<ExternType>&&) -> own<ExportType>;
+ auto copy() const -> own<ExportType>;
auto name() const -> const Name&;
auto type() const -> const ExternType*;
@@ -453,7 +395,8 @@ public:
~Ref();
void operator delete(void*);
- auto copy() const -> own<Ref*>;
+ auto copy() const -> own<Ref>;
+ auto same(const Ref*) const -> bool;
auto get_host_info() const -> void*;
void set_host_info(void* info, void (*finalizer)(void*) = nullptr);
@@ -480,7 +423,7 @@ public:
Val(int64_t i) : kind_(I64) { impl_.i64 = i; }
Val(float32_t z) : kind_(F32) { impl_.f32 = z; }
Val(float64_t z) : kind_(F64) { impl_.f64 = z; }
- Val(own<Ref*>&& r) : kind_(ANYREF) { impl_.ref = r.release(); }
+ Val(own<Ref>&& r) : kind_(ANYREF) { impl_.ref = r.release(); }
Val(Val&& that) : kind_(that.kind_), impl_(that.impl_) {
if (is_ref()) that.impl_.ref = nullptr;
@@ -497,7 +440,7 @@ public:
static auto i64(int64_t x) -> Val { return Val(x); }
static auto f32(float32_t x) -> Val { return Val(x); }
static auto f64(float64_t x) -> Val { return Val(x); }
- static auto ref(own<Ref*>&& x) -> Val { return Val(std::move(x)); }
+ static auto ref(own<Ref>&& x) -> Val { return Val(std::move(x)); }
template<class T> inline static auto make(T x) -> Val;
template<class T> inline static auto make(own<T>&& x) -> Val;
@@ -528,15 +471,17 @@ public:
auto ref() const -> Ref* { assert(is_ref()); return impl_.ref; }
template<class T> inline auto get() const -> T;
- auto release_ref() -> own<Ref*> {
+ auto release_ref() -> own<Ref> {
assert(is_ref());
auto ref = impl_.ref;
- ref = nullptr;
- return own<Ref*>(ref);
+ impl_.ref = nullptr;
+ return own<Ref>(ref);
}
auto copy() const -> Val {
if (is_ref() && impl_.ref != nullptr) {
+ // TODO(mvsc): MVSC cannot handle this:
+ // impl impl = {.ref = impl_.ref->copy().release()};
impl impl;
impl.ref = impl_.ref->copy().release();
return Val(kind_, impl);
@@ -551,7 +496,7 @@ template<> inline auto Val::make<int32_t>(int32_t x) -> Val { return Val(x); }
template<> inline auto Val::make<int64_t>(int64_t x) -> Val { return Val(x); }
template<> inline auto Val::make<float32_t>(float32_t x) -> Val { return Val(x); }
template<> inline auto Val::make<float64_t>(float64_t x) -> Val { return Val(x); }
-template<> inline auto Val::make<Ref*>(own<Ref*>&& x) -> Val {
+template<> inline auto Val::make<Ref>(own<Ref>&& x) -> Val {
return Val(std::move(x));
}
@@ -580,15 +525,33 @@ template<> inline auto Val::get<uint64_t>() const -> uint64_t {
using Message = vec<byte_t>; // null terminated
+class Instance;
+
+class Frame {
+public:
+ Frame() = delete;
+ ~Frame();
+ void operator delete(void*);
+
+ auto copy() const -> own<Frame>;
+
+ auto instance() const -> Instance*;
+ auto func_index() const -> uint32_t;
+ auto func_offset() const -> size_t;
+ auto module_offset() const -> size_t;
+};
+
class Trap : public Ref {
public:
Trap() = delete;
~Trap();
- static auto make(Store*, const Message& msg) -> own<Trap*>;
- auto copy() const -> own<Trap*>;
+ static auto make(Store*, const Message& msg) -> own<Trap>;
+ auto copy() const -> own<Trap>;
auto message() const -> Message;
+ auto origin() const -> own<Frame>; // may be null
+ auto trace() const -> ownvec<Frame>; // may be empty, origin first
};
@@ -611,17 +574,17 @@ public:
~Module();
static auto validate(Store*, const vec<byte_t>& binary) -> bool;
- static auto make(Store*, const vec<byte_t>& binary) -> own<Module*>;
- auto copy() const -> own<Module*>;
+ static auto make(Store*, const vec<byte_t>& binary) -> own<Module>;
+ auto copy() const -> own<Module>;
- auto imports() const -> vec<ImportType*>;
- auto exports() const -> vec<ExportType*>;
+ auto imports() const -> ownvec<ImportType>;
+ auto exports() const -> ownvec<ExportType>;
- auto share() const -> own<Shared<Module>*>;
- static auto obtain(Store*, const Shared<Module>*) -> own<Module*>;
+ auto share() const -> own<Shared<Module>>;
+ static auto obtain(Store*, const Shared<Module>*) -> own<Module>;
auto serialize() const -> vec<byte_t>;
- static auto deserialize(Store*, const vec<byte_t>&) -> own<Module*>;
+ static auto deserialize(Store*, const vec<byte_t>&) -> own<Module>;
};
@@ -632,8 +595,8 @@ public:
Foreign() = delete;
~Foreign();
- static auto make(Store*) -> own<Foreign*>;
- auto copy() const -> own<Foreign*>;
+ static auto make(Store*) -> own<Foreign>;
+ auto copy() const -> own<Foreign>;
};
@@ -649,10 +612,10 @@ public:
Extern() = delete;
~Extern();
- auto copy() const -> own<Extern*>;
+ auto copy() const -> own<Extern>;
auto kind() const -> ExternKind;
- auto type() const -> own<ExternType*>;
+ auto type() const -> own<ExternType>;
auto func() -> Func*;
auto global() -> Global*;
@@ -673,19 +636,19 @@ public:
Func() = delete;
~Func();
- using callback = auto (*)(const Val[], Val[]) -> own<Trap*>;
- using callback_with_env = auto (*)(void*, const Val[], Val[]) -> own<Trap*>;
+ using callback = auto (*)(const Val[], Val[]) -> own<Trap>;
+ using callback_with_env = auto (*)(void*, const Val[], Val[]) -> own<Trap>;
- static auto make(Store*, const FuncType*, callback) -> own<Func*>;
+ static auto make(Store*, const FuncType*, callback) -> own<Func>;
static auto make(Store*, const FuncType*, callback_with_env,
- void*, void (*finalizer)(void*) = nullptr) -> own<Func*>;
- auto copy() const -> own<Func*>;
+ void*, void (*finalizer)(void*) = nullptr) -> own<Func>;
+ auto copy() const -> own<Func>;
- auto type() const -> own<FuncType*>;
+ auto type() const -> own<FuncType>;
auto param_arity() const -> size_t;
auto result_arity() const -> size_t;
- auto call(const Val[] = nullptr, Val[] = nullptr) const -> own<Trap*>;
+ auto call(const Val[] = nullptr, Val[] = nullptr) const -> own<Trap>;
};
@@ -696,10 +659,10 @@ public:
Global() = delete;
~Global();
- static auto make(Store*, const GlobalType*, const Val&) -> own<Global*>;
- auto copy() const -> own<Global*>;
+ static auto make(Store*, const GlobalType*, const Val&) -> own<Global>;
+ auto copy() const -> own<Global>;
- auto type() const -> own<GlobalType*>;
+ auto type() const -> own<GlobalType>;
auto get() const -> Val;
void set(const Val&);
};
@@ -715,11 +678,11 @@ public:
using size_t = uint32_t;
static auto make(
- Store*, const TableType*, const Ref* init = nullptr) -> own<Table*>;
- auto copy() const -> own<Table*>;
+ Store*, const TableType*, const Ref* init = nullptr) -> own<Table>;
+ auto copy() const -> own<Table>;
- auto type() const -> own<TableType*>;
- auto get(size_t index) const -> own<Ref*>;
+ auto type() const -> own<TableType>;
+ auto get(size_t index) const -> own<Ref>;
auto set(size_t index, const Ref*) -> bool;
auto size() const -> size_t;
auto grow(size_t delta, const Ref* init = nullptr) -> bool;
@@ -733,14 +696,14 @@ public:
Memory() = delete;
~Memory();
- static auto make(Store*, const MemoryType*) -> own<Memory*>;
- auto copy() const -> own<Memory*>;
+ static auto make(Store*, const MemoryType*) -> own<Memory>;
+ auto copy() const -> own<Memory>;
using pages_t = uint32_t;
static const size_t page_size = 0x10000;
- auto type() const -> own<MemoryType*>;
+ auto type() const -> own<MemoryType>;
auto data() const -> byte_t*;
auto data_size() const -> size_t;
auto size() const -> pages_t;
@@ -756,15 +719,16 @@ public:
~Instance();
static auto make(
- Store*, const Module*, const Extern* const[]) -> own<Instance*>;
- auto copy() const -> own<Instance*>;
+ Store*, const Module*, const Extern* const[], own<Trap>* = nullptr
+ ) -> own<Instance>;
+ auto copy() const -> own<Instance>;
- auto exports() const -> vec<Extern*>;
+ auto exports() const -> ownvec<Extern>;
};
///////////////////////////////////////////////////////////////////////////////
-} // namespave wasm
+} // namespace wasm
#endif // #ifdef __WASM_HH
diff --git a/deps/v8/tools/BUILD.gn b/deps/v8/tools/BUILD.gn
index e6fd743715..8d18f4df75 100644
--- a/deps/v8/tools/BUILD.gn
+++ b/deps/v8/tools/BUILD.gn
@@ -10,6 +10,7 @@ group("gn_all") {
data_deps = [
":v8_check_static_initializers",
+ "debug_helper:v8_debug_helper",
"gcmole:v8_run_gcmole",
"jsfunfuzz:v8_jsfunfuzz",
]
diff --git a/deps/v8/tools/OWNERS b/deps/v8/tools/OWNERS
index bd9cea5b3e..89ee345b00 100644
--- a/deps/v8/tools/OWNERS
+++ b/deps/v8/tools/OWNERS
@@ -1,2 +1,2 @@
-file://COMMON_OWNERS
+file:../COMMON_OWNERS
diff --git a/deps/v8/tools/clusterfuzz/BUILD.gn b/deps/v8/tools/clusterfuzz/BUILD.gn
index 88219600a2..e0c4531555 100644
--- a/deps/v8/tools/clusterfuzz/BUILD.gn
+++ b/deps/v8/tools/clusterfuzz/BUILD.gn
@@ -13,6 +13,7 @@ if (v8_correctness_fuzzer) {
"v8_fuzz_config.py",
"v8_mock.js",
"v8_mock_archs.js",
+ "v8_sanity_checks.js",
"v8_suppressions.js",
"v8_suppressions.py",
]
diff --git a/deps/v8/tools/clusterfuzz/OWNERS b/deps/v8/tools/clusterfuzz/OWNERS
index bdb1d555a4..09e0096a2e 100644
--- a/deps/v8/tools/clusterfuzz/OWNERS
+++ b/deps/v8/tools/clusterfuzz/OWNERS
@@ -1 +1 @@
-file://INFRA_OWNERS
+file:../../INFRA_OWNERS
diff --git a/deps/v8/tools/clusterfuzz/testdata/failure_output.txt b/deps/v8/tools/clusterfuzz/testdata/failure_output.txt
index fe94bb9ecc..de3c15eab2 100644
--- a/deps/v8/tools/clusterfuzz/testdata/failure_output.txt
+++ b/deps/v8/tools/clusterfuzz/testdata/failure_output.txt
@@ -9,9 +9,9 @@
# Compared x64,ignition with x64,ignition_turbo
#
# Flags of x64,ignition:
---correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --turbo-filter=~ --noopt --liftoff --no-wasm-tier-up --flag1 --flag2=0
+--correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --wasm-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --turbo-filter=~ --noopt --liftoff --no-wasm-tier-up --flag1 --flag2=0
# Flags of x64,ignition_turbo:
---correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --flag3
+--correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --wasm-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --flag3
#
# Difference:
- unknown
diff --git a/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt b/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt
index 636f4c9d9e..1443c61f2b 100644
--- a/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt
+++ b/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt
@@ -9,9 +9,9 @@
# Compared x64,ignition with x64,ignition_turbo
#
# Flags of x64,ignition:
---correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --turbo-filter=~ --noopt --liftoff --no-wasm-tier-up
+--correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --wasm-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --turbo-filter=~ --noopt --liftoff --no-wasm-tier-up
# Flags of x64,ignition_turbo:
---correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345
+--correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --wasm-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345
#
# Difference:
- unknown
diff --git a/deps/v8/tools/clusterfuzz/v8_foozzie.py b/deps/v8/tools/clusterfuzz/v8_foozzie.py
index 55f76e8bc6..ff481e9370 100755
--- a/deps/v8/tools/clusterfuzz/v8_foozzie.py
+++ b/deps/v8/tools/clusterfuzz/v8_foozzie.py
@@ -105,7 +105,7 @@ SANITY_CHECKS = os.path.join(BASE_PATH, 'v8_sanity_checks.js')
FLAGS = ['--correctness-fuzzer-suppressions', '--expose-gc',
'--allow-natives-syntax', '--invoke-weak-callbacks', '--omit-quit',
- '--es-staging', '--no-wasm-async-compilation',
+ '--es-staging', '--wasm-staging', '--no-wasm-async-compilation',
'--suppress-asm-messages']
SUPPORTED_ARCHS = ['ia32', 'x64', 'arm', 'arm64']
diff --git a/deps/v8/tools/clusterfuzz/v8_suppressions.py b/deps/v8/tools/clusterfuzz/v8_suppressions.py
index 04f67b2cf9..f1aaa6448a 100644
--- a/deps/v8/tools/clusterfuzz/v8_suppressions.py
+++ b/deps/v8/tools/clusterfuzz/v8_suppressions.py
@@ -101,6 +101,7 @@ ALLOWED_LINE_DIFFS = [
r'^(.*)TypeError: .* is not a function$',
r'^(.*)TypeError: .* is not a constructor$',
r'^(.*)TypeError: (.*) is not .*$',
+ r'^(.*):\d+: TypeError: Message suppressed for fuzzers.*$',
r'^(.*)ReferenceError: .* is not defined$',
r'^(.*):\d+: ReferenceError: .* is not defined$',
diff --git a/deps/v8/tools/debug_helper/BUILD.gn b/deps/v8/tools/debug_helper/BUILD.gn
new file mode 100644
index 0000000000..c81fddc9e5
--- /dev/null
+++ b/deps/v8/tools/debug_helper/BUILD.gn
@@ -0,0 +1,104 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("../../gni/snapshot_toolchain.gni")
+import("../../gni/v8.gni")
+
+config("internal_config") {
+ visibility = [ ":*" ] # Only targets in this file can depend on this.
+
+ if (is_component_build) {
+ defines = [ "BUILDING_V8_DEBUG_HELPER" ]
+ }
+
+ include_dirs = [
+ ".",
+ "../..",
+ "$target_gen_dir",
+ "$target_gen_dir/../..",
+ ]
+}
+
+# This config should be applied to code using v8_debug_helper.
+config("external_config") {
+ if (is_component_build) {
+ defines = [ "USING_V8_DEBUG_HELPER" ]
+ }
+ include_dirs = [ "." ]
+}
+
+action("run_mkgrokdump") {
+ testonly = true
+ visibility = [ ":*" ]
+
+ deps = [
+ "../../test/mkgrokdump:mkgrokdump($v8_generator_toolchain)",
+ ]
+
+ script = "../run.py"
+
+ outputs = [
+ "$target_gen_dir/v8heapconst.py",
+ ]
+
+ args = [
+ "./" + rebase_path(
+ get_label_info(
+ "../../test/mkgrokdump:mkgrokdump($v8_generator_toolchain)",
+ "root_out_dir") + "/mkgrokdump",
+ root_build_dir),
+ "--outfile",
+ rebase_path("$target_gen_dir/v8heapconst.py", root_build_dir),
+ ]
+}
+
+action("gen_heap_constants") {
+ testonly = true
+ visibility = [ ":*" ]
+ deps = [
+ ":run_mkgrokdump",
+ ]
+ script = "gen-heap-constants.py"
+ outputs = [
+ "$target_gen_dir/heap-constants-gen.cc",
+ ]
+ args = [
+ rebase_path(target_gen_dir, root_build_dir),
+ rebase_path("$target_gen_dir/heap-constants-gen.cc", root_build_dir),
+ ]
+}
+
+v8_component("v8_debug_helper") {
+ testonly = true
+
+ public = [
+ "debug-helper.h",
+ ]
+
+ sources = [
+ "$target_gen_dir/../../torque-generated/class-debug-readers-tq.cc",
+ "$target_gen_dir/../../torque-generated/class-debug-readers-tq.h",
+ "$target_gen_dir/heap-constants-gen.cc",
+ "debug-helper-internal.cc",
+ "debug-helper-internal.h",
+ "debug-helper.h",
+ "get-object-properties.cc",
+ "heap-constants.cc",
+ "heap-constants.h",
+ ]
+
+ deps = [
+ ":gen_heap_constants",
+ "../..:run_torque",
+ "../..:v8_headers",
+ "../..:v8_libbase",
+ ]
+
+ configs = [ ":internal_config" ]
+ if (v8_enable_i18n_support) {
+ configs += [ "//third_party/icu:icu_config" ]
+ }
+
+ public_configs = [ ":external_config" ]
+}
diff --git a/deps/v8/tools/debug_helper/DEPS b/deps/v8/tools/debug_helper/DEPS
new file mode 100644
index 0000000000..2c6adb4df5
--- /dev/null
+++ b/deps/v8/tools/debug_helper/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+torque-generated"
+]
diff --git a/deps/v8/tools/debug_helper/README.md b/deps/v8/tools/debug_helper/README.md
new file mode 100644
index 0000000000..bc99569c43
--- /dev/null
+++ b/deps/v8/tools/debug_helper/README.md
@@ -0,0 +1,6 @@
+# V8 debug helper
+
+This library is for debugging V8 itself, not debugging JavaScript running within
+V8. It is designed to be called from a debugger extension running within a
+native debugger such as WinDbg or LLDB. It can be used on live processes or
+crash dumps, and cannot assume that all memory is available in a dump.
diff --git a/deps/v8/tools/debug_helper/debug-helper-internal.cc b/deps/v8/tools/debug_helper/debug-helper-internal.cc
new file mode 100644
index 0000000000..ee5629b438
--- /dev/null
+++ b/deps/v8/tools/debug_helper/debug-helper-internal.cc
@@ -0,0 +1,58 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "debug-helper-internal.h"
+#include "src/common/ptr-compr-inl.h"
+#include "torque-generated/class-debug-readers-tq.h"
+
+namespace i = v8::internal;
+
+namespace v8_debug_helper_internal {
+
+bool IsPointerCompressed(uintptr_t address) {
+#if COMPRESS_POINTERS_BOOL
+ STATIC_ASSERT(i::kPtrComprHeapReservationSize == uintptr_t{1} << 32);
+ intptr_t signed_address = static_cast<intptr_t>(address);
+ return signed_address >= INT32_MIN && signed_address <= INT32_MAX;
+#else
+ return false;
+#endif
+}
+
+uintptr_t Decompress(uintptr_t address, uintptr_t any_uncompressed_ptr) {
+ if (!COMPRESS_POINTERS_BOOL || !IsPointerCompressed(address)) return address;
+ return i::DecompressTaggedAny(any_uncompressed_ptr,
+ static_cast<i::Tagged_t>(address));
+}
+
+d::PropertyKind GetArrayKind(d::MemoryAccessResult mem_result) {
+ d::PropertyKind indexed_field_kind{};
+ switch (mem_result) {
+ case d::MemoryAccessResult::kOk:
+ indexed_field_kind = d::PropertyKind::kArrayOfKnownSize;
+ break;
+ case d::MemoryAccessResult::kAddressNotValid:
+ indexed_field_kind =
+ d::PropertyKind::kArrayOfUnknownSizeDueToInvalidMemory;
+ break;
+ default:
+ indexed_field_kind =
+ d::PropertyKind::kArrayOfUnknownSizeDueToValidButInaccessibleMemory;
+ break;
+ }
+ return indexed_field_kind;
+}
+
+std::vector<std::unique_ptr<ObjectProperty>> TqObject::GetProperties(
+ d::MemoryAccessor accessor) const {
+ return std::vector<std::unique_ptr<ObjectProperty>>();
+}
+
+const char* TqObject::GetName() const { return "v8::internal::Object"; }
+
+void TqObject::Visit(TqObjectVisitor* visitor) const {
+ visitor->VisitObject(this);
+}
+
+} // namespace v8_debug_helper_internal
diff --git a/deps/v8/tools/debug_helper/debug-helper-internal.h b/deps/v8/tools/debug_helper/debug-helper-internal.h
new file mode 100644
index 0000000000..82506c0941
--- /dev/null
+++ b/deps/v8/tools/debug_helper/debug-helper-internal.h
@@ -0,0 +1,130 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines internal versions of the public API structs. These should
+// all be tidy and simple classes which maintain proper ownership (unique_ptr)
+// of each other. Each contains an instance of its corresponding public type,
+// which can be filled out with GetPublicView.
+
+#ifndef V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_INTERNAL_H_
+#define V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_INTERNAL_H_
+
+#include <string>
+#include <vector>
+
+#include "debug-helper.h"
+#include "src/objects/instance-type.h"
+
+namespace d = v8::debug_helper;
+
+namespace v8_debug_helper_internal {
+
+// A value that was read from the debuggee's memory.
+template <typename TValue>
+struct Value {
+ d::MemoryAccessResult validity;
+ TValue value;
+};
+
+class ObjectProperty {
+ public:
+ inline ObjectProperty(std::string name, std::string type,
+ std::string decompressed_type, uintptr_t address,
+ size_t num_values = 1,
+ d::PropertyKind kind = d::PropertyKind::kSingle)
+ : name_(name),
+ type_(type),
+ decompressed_type_(decompressed_type),
+ address_(address),
+ num_values_(num_values),
+ kind_(kind) {}
+
+ inline d::ObjectProperty* GetPublicView() {
+ public_view_.name = name_.c_str();
+ public_view_.type = type_.c_str();
+ public_view_.decompressed_type = decompressed_type_.c_str();
+ public_view_.address = address_;
+ public_view_.num_values = num_values_;
+ public_view_.kind = kind_;
+ return &public_view_;
+ }
+
+ private:
+ std::string name_;
+ std::string type_;
+ std::string decompressed_type_;
+ uintptr_t address_;
+ size_t num_values_;
+ d::PropertyKind kind_;
+
+ d::ObjectProperty public_view_;
+};
+
+class ObjectPropertiesResult;
+using ObjectPropertiesResultInternal = ObjectPropertiesResult;
+
+struct ObjectPropertiesResultExtended : public d::ObjectPropertiesResult {
+ ObjectPropertiesResultInternal* base; // Back reference for cleanup
+};
+
+class ObjectPropertiesResult {
+ public:
+ inline ObjectPropertiesResult(
+ d::TypeCheckResult type_check_result, std::string brief, std::string type,
+ std::vector<std::unique_ptr<ObjectProperty>> properties)
+ : type_check_result_(type_check_result),
+ brief_(brief),
+ type_(type),
+ properties_(std::move(properties)) {}
+
+ inline void Prepend(const char* prefix) { brief_ = prefix + brief_; }
+
+ inline d::ObjectPropertiesResult* GetPublicView() {
+ public_view_.type_check_result = type_check_result_;
+ public_view_.brief = brief_.c_str();
+ public_view_.type = type_.c_str();
+ public_view_.num_properties = properties_.size();
+ properties_raw_.resize(0);
+ for (const auto& property : properties_) {
+ properties_raw_.push_back(property->GetPublicView());
+ }
+ public_view_.properties = properties_raw_.data();
+ public_view_.base = this;
+ return &public_view_;
+ }
+
+ private:
+ d::TypeCheckResult type_check_result_;
+ std::string brief_;
+ std::string type_;
+ std::vector<std::unique_ptr<ObjectProperty>> properties_;
+
+ ObjectPropertiesResultExtended public_view_;
+ std::vector<d::ObjectProperty*> properties_raw_;
+};
+
+class TqObjectVisitor;
+
+// Base class representing a V8 object in the debuggee's address space.
+// Subclasses for specific object types are generated by the Torque compiler.
+class TqObject {
+ public:
+ inline TqObject(uintptr_t address) : address_(address) {}
+ virtual ~TqObject() = default;
+ virtual std::vector<std::unique_ptr<ObjectProperty>> GetProperties(
+ d::MemoryAccessor accessor) const;
+ virtual const char* GetName() const;
+ virtual void Visit(TqObjectVisitor* visitor) const;
+
+ protected:
+ uintptr_t address_;
+};
+
+bool IsPointerCompressed(uintptr_t address);
+uintptr_t Decompress(uintptr_t address, uintptr_t any_uncompressed_address);
+d::PropertyKind GetArrayKind(d::MemoryAccessResult mem_result);
+
+} // namespace v8_debug_helper_internal
+
+#endif
diff --git a/deps/v8/tools/debug_helper/debug-helper.h b/deps/v8/tools/debug_helper/debug-helper.h
new file mode 100644
index 0000000000..9bbec76c7c
--- /dev/null
+++ b/deps/v8/tools/debug_helper/debug-helper.h
@@ -0,0 +1,177 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the public interface to v8_debug_helper.
+
+#ifndef V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_H_
+#define V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_H_
+
+#include <cstdint>
+#include <memory>
+
+#if defined(_WIN32)
+
+#ifdef BUILDING_V8_DEBUG_HELPER
+#define V8_DEBUG_HELPER_EXPORT __declspec(dllexport)
+#elif USING_V8_DEBUG_HELPER
+#define V8_DEBUG_HELPER_EXPORT __declspec(dllimport)
+#else
+#define V8_DEBUG_HELPER_EXPORT
+#endif
+
+#else // defined(_WIN32)
+
+#ifdef BUILDING_V8_DEBUG_HELPER
+#define V8_DEBUG_HELPER_EXPORT __attribute__((visibility("default")))
+#else
+#define V8_DEBUG_HELPER_EXPORT
+#endif
+
+#endif // defined(_WIN32)
+
+namespace v8 {
+namespace debug_helper {
+
+// Possible results when attempting to fetch memory from the debuggee.
+enum class MemoryAccessResult {
+ kOk,
+ kAddressNotValid,
+ kAddressValidButInaccessible, // Possible in incomplete dump.
+};
+
+// Information about how this tool discovered the type of the object.
+enum class TypeCheckResult {
+ // Success cases:
+ kSmi,
+ kWeakRef,
+ kUsedMap,
+ kUsedTypeHint,
+
+ // Failure cases:
+ kUnableToDecompress, // Caller must provide the heap range somehow.
+ kObjectPointerInvalid,
+ kObjectPointerValidButInaccessible, // Possible in incomplete dump.
+ kMapPointerInvalid,
+ kMapPointerValidButInaccessible, // Possible in incomplete dump.
+ kUnknownInstanceType,
+ kUnknownTypeHint,
+};
+
+enum class PropertyKind {
+ kSingle,
+ kArrayOfKnownSize,
+ kArrayOfUnknownSizeDueToInvalidMemory,
+ kArrayOfUnknownSizeDueToValidButInaccessibleMemory,
+};
+
+struct ObjectProperty {
+ const char* name;
+
+ // Statically-determined type, such as from .tq definition.
+ const char* type;
+
+ // In some cases, |type| may be a simple type representing a compressed
+ // pointer such as v8::internal::TaggedValue. In those cases,
+ // |decompressed_type| will contain the type of the object when decompressed.
+ // Otherwise, |decompressed_type| will match |type|. In any case, it is safe
+ // to pass the |decompressed_type| value as the type_hint on a subsequent call
+ // to GetObjectProperties.
+ const char* decompressed_type;
+
+ // The address where the property value can be found in the debuggee's address
+ // space, or the address of the first value for an array.
+ uintptr_t address;
+
+ // If kind indicates an array of unknown size, num_values will be 0 and debug
+ // tools should display this property as a raw pointer. Note that there is a
+ // semantic difference between num_values=1 and kind=kSingle (normal property)
+ // versus num_values=1 and kind=kArrayOfKnownSize (one-element array).
+ size_t num_values;
+
+ PropertyKind kind;
+};
+
+struct ObjectPropertiesResult {
+ TypeCheckResult type_check_result;
+ const char* brief;
+ const char* type; // Runtime type of the object.
+ size_t num_properties;
+ ObjectProperty** properties;
+};
+
+// Copies byte_count bytes of memory from the given address in the debuggee to
+// the destination buffer.
+typedef MemoryAccessResult (*MemoryAccessor)(uintptr_t address,
+ uint8_t* destination,
+ size_t byte_count);
+
+// Additional data that can help GetObjectProperties to be more accurate. Any
+// fields you don't know can be set to zero and this library will do the best it
+// can with the information available.
+struct Roots {
+ // Beginning of allocated space for various kinds of data. These can help us
+ // to detect certain common objects that are placed in memory during startup.
+ // These values might be provided via name-value pairs in CrashPad dumps.
+ // Otherwise, they can be obtained as follows:
+ // 1. Get the Isolate pointer for the current thread. It might be somewhere on
+ // the stack, or it might be accessible from thread-local storage with the
+ // key stored in v8::internal::Isolate::isolate_key_.
+ // 2. Get isolate->heap_.map_space_->memory_chunk_list_.front_ and similar for
+ // old_space_ and read_only_space_.
+ uintptr_t map_space;
+ uintptr_t old_space;
+ uintptr_t read_only_space;
+
+ // Any valid heap pointer address. On platforms where pointer compression is
+ // enabled, this can allow us to get data from compressed pointers even if the
+ // other data above is not provided. The Isolate pointer is valid for this
+ // purpose if you have it.
+ uintptr_t any_heap_pointer;
+};
+
+} // namespace debug_helper
+} // namespace v8
+
+extern "C" {
+// Raw library interface. If possible, use functions in v8::debug_helper
+// namespace instead because they use smart pointers to prevent leaks.
+V8_DEBUG_HELPER_EXPORT v8::debug_helper::ObjectPropertiesResult*
+_v8_debug_helper_GetObjectProperties(
+ uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor,
+ const v8::debug_helper::Roots& heap_roots, const char* type_hint);
+V8_DEBUG_HELPER_EXPORT void _v8_debug_helper_Free_ObjectPropertiesResult(
+ v8::debug_helper::ObjectPropertiesResult* result);
+}
+
+namespace v8 {
+namespace debug_helper {
+
+struct DebugHelperObjectPropertiesResultDeleter {
+ void operator()(v8::debug_helper::ObjectPropertiesResult* ptr) {
+ _v8_debug_helper_Free_ObjectPropertiesResult(ptr);
+ }
+};
+using ObjectPropertiesResultPtr =
+ std::unique_ptr<ObjectPropertiesResult,
+ DebugHelperObjectPropertiesResultDeleter>;
+
+// Get information about the given object pointer, which could be:
+// - A tagged pointer, strong or weak
+// - A cleared weak pointer
+// - A compressed tagged pointer, sign-extended to 64 bits
+// - A tagged small integer
+// The type hint is only used if the object's Map is missing or corrupt. It
+// should be the fully-qualified name of a class that inherits from
+// v8::internal::Object.
+inline ObjectPropertiesResultPtr GetObjectProperties(
+ uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor,
+ const Roots& heap_roots, const char* type_hint = nullptr) {
+ return ObjectPropertiesResultPtr(_v8_debug_helper_GetObjectProperties(
+ object, memory_accessor, heap_roots, type_hint));
+}
+
+} // namespace debug_helper
+} // namespace v8
+
+#endif
diff --git a/deps/v8/tools/debug_helper/gen-heap-constants.py b/deps/v8/tools/debug_helper/gen-heap-constants.py
new file mode 100644
index 0000000000..0fd575a994
--- /dev/null
+++ b/deps/v8/tools/debug_helper/gen-heap-constants.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""This program writes a C++ file that can be used to look up whether a given
+address matches known object locations. The first argument is the directory
+containing the file v8heapconst.py; the second argument is the output .cc file.
+"""
+
+import sys
+sys.path.insert(0, sys.argv[1])
+import v8heapconst
+
+out = """
+#include <cstdint>
+#include <string>
+
+namespace v8_debug_helper_internal {
+"""
+
+def iterate_objects(target_space, camel_space_name):
+ global out
+ result = []
+ for (space, offset), (instance_type, name) in v8heapconst.KNOWN_MAPS.items():
+ if space == target_space:
+ result.append((offset, name))
+ for (space, offset), name in v8heapconst.KNOWN_OBJECTS.items():
+ if space == target_space:
+ result.append((offset, name))
+ out = out + '\nstd::string FindKnownObjectIn' + camel_space_name \
+ + '(uintptr_t offset) {\n switch (offset) {\n'
+ for offset, name in result:
+ out = out + ' case ' + str(offset) + ': return "' + name + '";\n'
+ out = out + ' default: return "";\n }\n}\n'
+
+iterate_objects('map_space', 'MapSpace')
+iterate_objects('read_only_space', 'ReadOnlySpace')
+iterate_objects('old_space', 'OldSpace')
+
+def iterate_maps(target_space, camel_space_name):
+ global out
+ out = out + '\nint FindKnownMapInstanceTypeIn' + camel_space_name \
+ + '(uintptr_t offset) {\n switch (offset) {\n'
+ for (space, offset), (instance_type, name) in v8heapconst.KNOWN_MAPS.items():
+ if space == target_space:
+ out = out + ' case ' + str(offset) + ': return ' + str(instance_type) \
+ + ';\n'
+ out = out + ' default: return -1;\n }\n}\n'
+
+iterate_maps('map_space', 'MapSpace')
+iterate_maps('read_only_space', 'ReadOnlySpace')
+
+out = out + '\n}\n'
+
+try:
+ with open(sys.argv[2], "r") as out_file:
+ if out == out_file.read():
+ sys.exit(0) # No modification needed.
+except:
+ pass # File probably doesn't exist; write it.
+with open(sys.argv[2], "w") as out_file:
+ out_file.write(out)
diff --git a/deps/v8/tools/debug_helper/get-object-properties.cc b/deps/v8/tools/debug_helper/get-object-properties.cc
new file mode 100644
index 0000000000..fbe992c40e
--- /dev/null
+++ b/deps/v8/tools/debug_helper/get-object-properties.cc
@@ -0,0 +1,535 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+
+#include "debug-helper-internal.h"
+#include "heap-constants.h"
+#include "include/v8-internal.h"
+#include "src/common/ptr-compr-inl.h"
+#include "src/objects/string-inl.h"
+#include "src/strings/unicode-inl.h"
+#include "torque-generated/class-debug-readers-tq.h"
+
+namespace i = v8::internal;
+
+namespace v8_debug_helper_internal {
+
+// INSTANCE_TYPE_CHECKERS_SINGLE_BASE, trimmed down to only classes that have
+// layouts defined in .tq files (this subset relationship is asserted below).
+// For now, this is a hand-maintained list.
+// TODO(v8:7793): Torque should know enough about instance types to generate
+// this list.
+#define TQ_INSTANCE_TYPES_SINGLE_BASE(V) \
+ V(ByteArray, BYTE_ARRAY_TYPE) \
+ V(BytecodeArray, BYTECODE_ARRAY_TYPE) \
+ V(CallHandlerInfo, CALL_HANDLER_INFO_TYPE) \
+ V(Cell, CELL_TYPE) \
+ V(DescriptorArray, DESCRIPTOR_ARRAY_TYPE) \
+ V(EmbedderDataArray, EMBEDDER_DATA_ARRAY_TYPE) \
+ V(FeedbackCell, FEEDBACK_CELL_TYPE) \
+ V(FeedbackVector, FEEDBACK_VECTOR_TYPE) \
+ V(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE) \
+ V(Foreign, FOREIGN_TYPE) \
+ V(FreeSpace, FREE_SPACE_TYPE) \
+ V(HeapNumber, HEAP_NUMBER_TYPE) \
+ V(JSArgumentsObject, JS_ARGUMENTS_TYPE) \
+ V(JSArray, JS_ARRAY_TYPE) \
+ V(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE) \
+ V(JSArrayIterator, JS_ARRAY_ITERATOR_TYPE) \
+ V(JSAsyncFromSyncIterator, JS_ASYNC_FROM_SYNC_ITERATOR_TYPE) \
+ V(JSAsyncFunctionObject, JS_ASYNC_FUNCTION_OBJECT_TYPE) \
+ V(JSAsyncGeneratorObject, JS_ASYNC_GENERATOR_OBJECT_TYPE) \
+ V(JSBoundFunction, JS_BOUND_FUNCTION_TYPE) \
+ V(JSDataView, JS_DATA_VIEW_TYPE) \
+ V(JSDate, JS_DATE_TYPE) \
+ V(JSFunction, JS_FUNCTION_TYPE) \
+ V(JSGlobalObject, JS_GLOBAL_OBJECT_TYPE) \
+ V(JSGlobalProxy, JS_GLOBAL_PROXY_TYPE) \
+ V(JSMap, JS_MAP_TYPE) \
+ V(JSMessageObject, JS_MESSAGE_OBJECT_TYPE) \
+ V(JSModuleNamespace, JS_MODULE_NAMESPACE_TYPE) \
+ V(JSPromise, JS_PROMISE_TYPE) \
+ V(JSProxy, JS_PROXY_TYPE) \
+ V(JSRegExp, JS_REGEXP_TYPE) \
+ V(JSRegExpStringIterator, JS_REGEXP_STRING_ITERATOR_TYPE) \
+ V(JSSet, JS_SET_TYPE) \
+ V(JSStringIterator, JS_STRING_ITERATOR_TYPE) \
+ V(JSTypedArray, JS_TYPED_ARRAY_TYPE) \
+ V(JSPrimitiveWrapper, JS_PRIMITIVE_WRAPPER_TYPE) \
+ V(JSFinalizationGroup, JS_FINALIZATION_GROUP_TYPE) \
+ V(JSFinalizationGroupCleanupIterator, \
+ JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE) \
+ V(JSWeakMap, JS_WEAK_MAP_TYPE) \
+ V(JSWeakRef, JS_WEAK_REF_TYPE) \
+ V(JSWeakSet, JS_WEAK_SET_TYPE) \
+ V(Map, MAP_TYPE) \
+ V(Oddball, ODDBALL_TYPE) \
+ V(PreparseData, PREPARSE_DATA_TYPE) \
+ V(PropertyArray, PROPERTY_ARRAY_TYPE) \
+ V(PropertyCell, PROPERTY_CELL_TYPE) \
+ V(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE) \
+ V(Symbol, SYMBOL_TYPE) \
+ V(WasmExceptionObject, WASM_EXCEPTION_TYPE) \
+ V(WasmGlobalObject, WASM_GLOBAL_TYPE) \
+ V(WasmMemoryObject, WASM_MEMORY_TYPE) \
+ V(WasmModuleObject, WASM_MODULE_TYPE) \
+ V(WasmTableObject, WASM_TABLE_TYPE) \
+ V(WeakArrayList, WEAK_ARRAY_LIST_TYPE) \
+ V(WeakCell, WEAK_CELL_TYPE)
+#ifdef V8_INTL_SUPPORT
+
+#define TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(V) \
+ TQ_INSTANCE_TYPES_SINGLE_BASE(V) \
+ V(JSV8BreakIterator, JS_INTL_V8_BREAK_ITERATOR_TYPE) \
+ V(JSCollator, JS_INTL_COLLATOR_TYPE) \
+ V(JSDateTimeFormat, JS_INTL_DATE_TIME_FORMAT_TYPE) \
+ V(JSListFormat, JS_INTL_LIST_FORMAT_TYPE) \
+ V(JSLocale, JS_INTL_LOCALE_TYPE) \
+ V(JSNumberFormat, JS_INTL_NUMBER_FORMAT_TYPE) \
+ V(JSPluralRules, JS_INTL_PLURAL_RULES_TYPE) \
+ V(JSRelativeTimeFormat, JS_INTL_RELATIVE_TIME_FORMAT_TYPE) \
+ V(JSSegmentIterator, JS_INTL_SEGMENT_ITERATOR_TYPE) \
+ V(JSSegmenter, JS_INTL_SEGMENTER_TYPE)
+
+#else
+
+#define TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(V) TQ_INSTANCE_TYPES_SINGLE_BASE(V)
+
+#endif // V8_INTL_SUPPORT
+
+enum class InstanceTypeCheckersSingle {
+#define ENUM_VALUE(ClassName, INSTANCE_TYPE) k##ClassName = i::INSTANCE_TYPE,
+ INSTANCE_TYPE_CHECKERS_SINGLE(ENUM_VALUE)
+#undef ENUM_VALUE
+};
+
+#define CHECK_VALUE(ClassName, INSTANCE_TYPE) \
+ static_assert( \
+ static_cast<i::InstanceType>( \
+ InstanceTypeCheckersSingle::k##ClassName) == i::INSTANCE_TYPE, \
+ "TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS must be subset of " \
+ "INSTANCE_TYPE_CHECKERS_SINGLE. Invalid class: " #ClassName);
+TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(CHECK_VALUE)
+#undef CHECK_VALUE
+
+// Adapts one STRUCT_LIST_GENERATOR entry to (Name, NAME) format.
+#define STRUCT_INSTANCE_TYPE_ADAPTER(V, NAME, Name, name) V(Name, NAME)
+
+#define TQ_INSTANCE_TYPES_SINGLE(V) \
+ TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(V) \
+ STRUCT_LIST_GENERATOR(STRUCT_INSTANCE_TYPE_ADAPTER, V)
+
+// Likewise, these are the subset of INSTANCE_TYPE_CHECKERS_RANGE that have
+// definitions in .tq files, rearranged with more specific things first. Also
+// includes JSObject and JSReceiver, which in the runtime are optimized to use
+// a one-sided check.
+#define TQ_INSTANCE_TYPES_RANGE(V) \
+ V(Context, FIRST_CONTEXT_TYPE, LAST_CONTEXT_TYPE) \
+ V(FixedArray, FIRST_FIXED_ARRAY_TYPE, LAST_FIXED_ARRAY_TYPE) \
+ V(Microtask, FIRST_MICROTASK_TYPE, LAST_MICROTASK_TYPE) \
+ V(String, FIRST_STRING_TYPE, LAST_STRING_TYPE) \
+ V(Name, FIRST_NAME_TYPE, LAST_NAME_TYPE) \
+ V(WeakFixedArray, FIRST_WEAK_FIXED_ARRAY_TYPE, LAST_WEAK_FIXED_ARRAY_TYPE) \
+ V(JSObject, FIRST_JS_OBJECT_TYPE, LAST_JS_OBJECT_TYPE) \
+ V(JSReceiver, FIRST_JS_RECEIVER_TYPE, LAST_JS_RECEIVER_TYPE)
+
+std::string AppendAddressAndType(const std::string& brief, uintptr_t address,
+ const char* type) {
+ std::stringstream brief_stream;
+ brief_stream << "0x" << std::hex << address << " <" << type << ">";
+ return brief.empty() ? brief_stream.str()
+ : brief + " (" + brief_stream.str() + ")";
+}
+
+struct TypedObject {
+ TypedObject(d::TypeCheckResult type_check_result,
+ std::unique_ptr<TqObject> object)
+ : type_check_result(type_check_result), object(std::move(object)) {}
+ d::TypeCheckResult type_check_result;
+ std::unique_ptr<TqObject> object;
+};
+
+TypedObject GetTypedObjectByHint(uintptr_t address,
+ std::string type_hint_string) {
+#define TYPE_NAME_CASE(ClassName, ...) \
+ if (type_hint_string == "v8::internal::" #ClassName) { \
+ return {d::TypeCheckResult::kUsedTypeHint, \
+ v8::base::make_unique<Tq##ClassName>(address)}; \
+ }
+
+ TQ_INSTANCE_TYPES_SINGLE(TYPE_NAME_CASE)
+ TQ_INSTANCE_TYPES_RANGE(TYPE_NAME_CASE)
+
+#undef TYPE_NAME_CASE
+
+ return {d::TypeCheckResult::kUnknownTypeHint,
+ v8::base::make_unique<TqHeapObject>(address)};
+}
+
+TypedObject GetTypedObjectForString(uintptr_t address, i::InstanceType type) {
+ class StringGetDispatcher : public i::AllStatic {
+ public:
+#define DEFINE_METHOD(ClassName) \
+ static inline TypedObject Handle##ClassName(uintptr_t address) { \
+ return {d::TypeCheckResult::kUsedMap, \
+ v8::base::make_unique<Tq##ClassName>(address)}; \
+ }
+ STRING_CLASS_TYPES(DEFINE_METHOD)
+#undef DEFINE_METHOD
+ static inline TypedObject HandleInvalidString(uintptr_t address) {
+ return {d::TypeCheckResult::kUnknownInstanceType,
+ v8::base::make_unique<TqString>(address)};
+ }
+ };
+
+ return i::StringShape(type)
+ .DispatchToSpecificTypeWithoutCast<StringGetDispatcher, TypedObject>(
+ address);
+}
+
+TypedObject GetTypedHeapObject(uintptr_t address, d::MemoryAccessor accessor,
+ const char* type_hint) {
+ auto heap_object = v8::base::make_unique<TqHeapObject>(address);
+ Value<uintptr_t> map_ptr = heap_object->GetMapValue(accessor);
+
+ if (map_ptr.validity != d::MemoryAccessResult::kOk) {
+ return {map_ptr.validity == d::MemoryAccessResult::kAddressNotValid
+ ? d::TypeCheckResult::kObjectPointerInvalid
+ : d::TypeCheckResult::kObjectPointerValidButInaccessible,
+ std::move(heap_object)};
+ }
+ Value<i::InstanceType> type =
+ TqMap(map_ptr.value).GetInstanceTypeValue(accessor);
+
+ if (type.validity == d::MemoryAccessResult::kOk) {
+ // Dispatch to the appropriate method for each instance type. After calling
+ // the generated method to fetch properties, we can add custom properties.
+ switch (type.value) {
+#define INSTANCE_TYPE_CASE(ClassName, INSTANCE_TYPE) \
+ case i::INSTANCE_TYPE: \
+ return {d::TypeCheckResult::kUsedMap, \
+ v8::base::make_unique<Tq##ClassName>(address)};
+ TQ_INSTANCE_TYPES_SINGLE(INSTANCE_TYPE_CASE)
+#undef INSTANCE_TYPE_CASE
+
+ default:
+
+ // Special case: concrete subtypes of String are not included in the
+ // main instance type list because they use the low bits of the instance
+ // type enum as flags.
+ if (type.value <= i::LAST_STRING_TYPE) {
+ return GetTypedObjectForString(address, type.value);
+ }
+
+#define INSTANCE_RANGE_CASE(ClassName, FIRST_TYPE, LAST_TYPE) \
+ if (type.value >= i::FIRST_TYPE && type.value <= i::LAST_TYPE) { \
+ return {d::TypeCheckResult::kUsedMap, \
+ v8::base::make_unique<Tq##ClassName>(address)}; \
+ }
+ TQ_INSTANCE_TYPES_RANGE(INSTANCE_RANGE_CASE)
+#undef INSTANCE_RANGE_CASE
+
+ return {d::TypeCheckResult::kUnknownInstanceType,
+ std::move(heap_object)};
+ break;
+ }
+ } else if (type_hint != nullptr) {
+ // Try to use the provided type hint, since the real instance type is
+ // unavailable.
+ return GetTypedObjectByHint(address, type_hint);
+ } else {
+ // TODO(v8:9376): Use known maps here. If known map is just a guess (because
+ // root pointers weren't provided), then create a synthetic property with
+ // the more specific type. Then the caller could presumably ask us again
+ // with the type hint we provided. Otherwise, just go ahead and use it to
+ // generate properties.
+ return {type.validity == d::MemoryAccessResult::kAddressNotValid
+ ? d::TypeCheckResult::kMapPointerInvalid
+ : d::TypeCheckResult::kMapPointerValidButInaccessible,
+ std::move(heap_object)};
+ }
+}
+
+#undef STRUCT_INSTANCE_TYPE_ADAPTER
+#undef TQ_INSTANCE_TYPES_SINGLE_BASE
+#undef TQ_INSTANCE_TYPES_SINGLE
+#undef TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS
+#undef TQ_INSTANCE_TYPES_RANGE
+
+// An object visitor that accumulates the first few characters of a string.
+class ReadStringVisitor : public TqObjectVisitor {
+ public:
+ ReadStringVisitor(d::MemoryAccessor accessor)
+ : accessor_(accessor), index_(0), limit_(INT32_MAX), done_(false) {}
+
+ // Returns the result as UTF-8 once visiting is complete.
+ std::string GetString() {
+ std::vector<char> result(
+ string_.size() * unibrow::Utf16::kMaxExtraUtf8BytesForOneUtf16CodeUnit);
+ unsigned write_index = 0;
+ int prev_char = unibrow::Utf16::kNoPreviousCharacter;
+ for (size_t read_index = 0; read_index < string_.size(); ++read_index) {
+ uint16_t character = string_[read_index];
+ write_index +=
+ unibrow::Utf8::Encode(result.data() + write_index, character,
+ prev_char, /*replace_invalid=*/true);
+ prev_char = character;
+ }
+ return {result.data(), write_index};
+ }
+
+ template <typename T>
+ void ReadSeqString(const T* object) {
+ int32_t length = GetOrFinish(object->GetLengthValue(accessor_));
+ for (; index_ < length && index_ < limit_ && !done_; ++index_) {
+ char16_t c = static_cast<char16_t>(
+ GetOrFinish(object->GetCharsValue(accessor_, index_)));
+ if (!done_) AddCharacter(c);
+ }
+ }
+
+ void VisitSeqOneByteString(const TqSeqOneByteString* object) override {
+ ReadSeqString(object);
+ }
+
+ void VisitSeqTwoByteString(const TqSeqTwoByteString* object) override {
+ ReadSeqString(object);
+ }
+
+ void VisitConsString(const TqConsString* object) override {
+ uintptr_t first_address = GetOrFinish(object->GetFirstValue(accessor_));
+ if (done_) return;
+ auto first = GetTypedHeapObject(first_address, accessor_, nullptr).object;
+ first->Visit(this);
+ if (done_) return;
+ int32_t first_length = GetOrFinish(
+ static_cast<TqString*>(first.get())->GetLengthValue(accessor_));
+ uintptr_t second = GetOrFinish(object->GetSecondValue(accessor_));
+ if (done_) return;
+ IndexModifier modifier(this, -first_length, -first_length);
+ GetTypedHeapObject(second, accessor_, nullptr).object->Visit(this);
+ }
+
+ void VisitSlicedString(const TqSlicedString* object) override {
+ uintptr_t parent = GetOrFinish(object->GetParentValue(accessor_));
+ int32_t length = GetOrFinish(object->GetLengthValue(accessor_));
+ int32_t offset = i::PlatformSmiTagging::SmiToInt(
+ GetOrFinish(object->GetOffsetValue(accessor_)));
+ if (done_) return;
+ int32_t limit_adjust = offset + length - limit_;
+ IndexModifier modifier(this, offset, limit_adjust < 0 ? limit_adjust : 0);
+ GetTypedHeapObject(parent, accessor_, nullptr).object->Visit(this);
+ }
+
+ void VisitThinString(const TqThinString* object) override {
+ uintptr_t actual = GetOrFinish(object->GetActualValue(accessor_));
+ if (done_) return;
+ GetTypedHeapObject(actual, accessor_, nullptr).object->Visit(this);
+ }
+
+ void VisitExternalString(const TqExternalString* object) override {
+ // TODO(v8:9376): External strings are very common and important when
+ // attempting to print the source of a function in the browser. For now
+ // we're just ignoring them, but eventually we'll want some kind of
+ // mechanism where the user of this library can provide a callback function
+ // that fetches data from external strings.
+ AddEllipsisAndFinish();
+ }
+
+ void VisitObject(const TqObject* object) override {
+ // If we fail to find a specific type for a sub-object within a cons string,
+ // sliced string, or thin string, we will end up here.
+ AddEllipsisAndFinish();
+ }
+
+ private:
+ // Unpacks a value that was fetched from the debuggee. If the value indicates
+ // that it couldn't successfully fetch memory, then prevents further work.
+ template <typename T>
+ T GetOrFinish(Value<T> value) {
+ if (value.validity != d::MemoryAccessResult::kOk) {
+ AddEllipsisAndFinish();
+ }
+ return value.value;
+ }
+
+ void AddEllipsisAndFinish() {
+ if (!done_) {
+ string_ += u"...";
+ done_ = true;
+ }
+ }
+
+ void AddCharacter(char16_t c) {
+ if (string_.size() >= kMaxCharacters) {
+ AddEllipsisAndFinish();
+ } else {
+ string_.push_back(c);
+ }
+ }
+
+ // Temporarily adds offsets to both index_ and limit_, to handle ConsString
+ // and SlicedString.
+ class IndexModifier {
+ public:
+ IndexModifier(ReadStringVisitor* that, int32_t index_adjust,
+ int32_t limit_adjust)
+ : that_(that),
+ index_adjust_(index_adjust),
+ limit_adjust_(limit_adjust) {
+ that_->index_ += index_adjust_;
+ that_->limit_ += limit_adjust_;
+ }
+ ~IndexModifier() {
+ that_->index_ -= index_adjust_;
+ that_->limit_ -= limit_adjust_;
+ }
+
+ private:
+ ReadStringVisitor* that_;
+ int32_t index_adjust_;
+ int32_t limit_adjust_;
+ DISALLOW_COPY_AND_ASSIGN(IndexModifier);
+ };
+
+ static constexpr int kMaxCharacters = 80; // How many characters to print.
+
+ std::u16string string_; // Result string.
+ d::MemoryAccessor accessor_;
+ int32_t index_; // Index of next char to read.
+ int32_t limit_; // Don't read past this index (set by SlicedString).
+ bool done_; // Whether to stop further work.
+};
+
+// An object visitor that adds extra debugging information for some types.
+class AddInfoVisitor : public TqObjectVisitor {
+ public:
+ AddInfoVisitor(const std::string& brief, d::MemoryAccessor accessor)
+ : accessor_(accessor), brief_(brief) {}
+
+ // Returns the brief object description, once visiting is complete.
+ const std::string& GetBrief() { return brief_; }
+
+ void VisitString(const TqString* object) override {
+ ReadStringVisitor visitor(accessor_);
+ object->Visit(&visitor);
+ if (!brief_.empty()) brief_ += " ";
+ brief_ += "\"" + visitor.GetString() + "\"";
+ }
+
+ private:
+ d::MemoryAccessor accessor_;
+ std::string brief_;
+};
+
+std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
+ uintptr_t address, d::MemoryAccessor accessor, const char* type_hint,
+ std::string brief) {
+ TypedObject typed = GetTypedHeapObject(address, accessor, type_hint);
+
+ // TODO(v8:9376): Many object types need additional data that is not included
+ // in their Torque layout definitions. For example, JSObject has an array of
+ // in-object properties after its Torque-defined fields, which at a minimum
+ // should be represented as an array in this response. If the relevant memory
+ // is available, we should instead represent those properties (and any out-of-
+ // object properties) using their JavaScript property names.
+ AddInfoVisitor visitor(brief, accessor);
+ typed.object->Visit(&visitor);
+ brief = visitor.GetBrief();
+
+ brief = AppendAddressAndType(brief, address, typed.object->GetName());
+
+ return v8::base::make_unique<ObjectPropertiesResult>(
+ typed.type_check_result, brief, typed.object->GetName(),
+ typed.object->GetProperties(accessor));
+}
+
+std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
+ uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots,
+ const char* type_hint) {
+ // Try to figure out the heap range, for pointer compression (this is unused
+ // if pointer compression is disabled).
+ uintptr_t any_uncompressed_ptr = 0;
+ if (!IsPointerCompressed(address)) any_uncompressed_ptr = address;
+ if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.any_heap_pointer;
+ if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.map_space;
+ if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.old_space;
+ if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.read_only_space;
+ if (any_uncompressed_ptr == 0) {
+ // We can't figure out the heap range. Just check for known objects.
+ std::string brief = FindKnownObject(address, roots);
+ brief = AppendAddressAndType(brief, address, "v8::internal::TaggedValue");
+ return v8::base::make_unique<ObjectPropertiesResult>(
+ d::TypeCheckResult::kUnableToDecompress, brief,
+ "v8::internal::TaggedValue",
+ std::vector<std::unique_ptr<ObjectProperty>>());
+ }
+
+ // TODO(v8:9376): It seems that the space roots are at predictable offsets
+ // within the heap reservation block when pointer compression is enabled, so
+ // we should be able to set those here.
+
+ address = Decompress(address, any_uncompressed_ptr);
+ // From here on all addresses should be decompressed.
+
+ // Regardless of whether we can read the object itself, maybe we can find its
+ // pointer in the list of known objects.
+ std::string brief = FindKnownObject(address, roots);
+ return GetHeapObjectProperties(address, memory_accessor, type_hint, brief);
+}
+
+std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl(
+ uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots,
+ const char* type_hint) {
+ std::vector<std::unique_ptr<ObjectProperty>> props;
+ if (static_cast<uint32_t>(address) == i::kClearedWeakHeapObjectLower32) {
+ return v8::base::make_unique<ObjectPropertiesResult>(
+ d::TypeCheckResult::kWeakRef, "cleared weak ref",
+ "v8::internal::HeapObject", std::move(props));
+ }
+ bool is_weak = (address & i::kHeapObjectTagMask) == i::kWeakHeapObjectTag;
+ if (is_weak) {
+ address &= ~i::kWeakHeapObjectMask;
+ }
+ if (i::Internals::HasHeapObjectTag(address)) {
+ std::unique_ptr<ObjectPropertiesResult> result =
+ GetHeapObjectProperties(address, memory_accessor, roots, type_hint);
+ if (is_weak) {
+ result->Prepend("weak ref to ");
+ }
+ return result;
+ }
+
+ // For smi values, construct a response with a description representing the
+ // untagged value.
+ int32_t value = i::PlatformSmiTagging::SmiToInt(address);
+ std::stringstream stream;
+ stream << value << " (0x" << std::hex << value << ")";
+ return v8::base::make_unique<ObjectPropertiesResult>(
+ d::TypeCheckResult::kSmi, stream.str(), "v8::internal::Smi",
+ std::move(props));
+}
+
+} // namespace v8_debug_helper_internal
+
+namespace di = v8_debug_helper_internal;
+
+extern "C" {
+V8_DEBUG_HELPER_EXPORT d::ObjectPropertiesResult*
+_v8_debug_helper_GetObjectProperties(uintptr_t object,
+ d::MemoryAccessor memory_accessor,
+ const d::Roots& heap_roots,
+ const char* type_hint) {
+ return di::GetObjectPropertiesImpl(object, memory_accessor, heap_roots,
+ type_hint)
+ .release()
+ ->GetPublicView();
+}
+V8_DEBUG_HELPER_EXPORT void _v8_debug_helper_Free_ObjectPropertiesResult(
+ d::ObjectPropertiesResult* result) {
+ std::unique_ptr<di::ObjectPropertiesResult> ptr(
+ static_cast<di::ObjectPropertiesResultExtended*>(result)->base);
+}
+}
diff --git a/deps/v8/tools/debug_helper/heap-constants.cc b/deps/v8/tools/debug_helper/heap-constants.cc
new file mode 100644
index 0000000000..2bd0420690
--- /dev/null
+++ b/deps/v8/tools/debug_helper/heap-constants.cc
@@ -0,0 +1,51 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "heap-constants.h"
+#include "src/common/globals.h"
+
+namespace d = v8::debug_helper;
+
+namespace v8_debug_helper_internal {
+
+std::string FindKnownObject(uintptr_t address, const d::Roots& roots) {
+ uintptr_t containing_page = address & ~i::kPageAlignmentMask;
+ uintptr_t offset_in_page = address & i::kPageAlignmentMask;
+
+ // If there's a match with a known root, then search only that page.
+ if (containing_page == roots.map_space) {
+ return FindKnownObjectInMapSpace(offset_in_page);
+ }
+ if (containing_page == roots.old_space) {
+ return FindKnownObjectInOldSpace(offset_in_page);
+ }
+ if (containing_page == roots.read_only_space) {
+ return FindKnownObjectInReadOnlySpace(offset_in_page);
+ }
+
+ // For any unknown roots, compile a list of things this object might be.
+ std::string result;
+ if (roots.map_space == 0) {
+ std::string sub_result = FindKnownObjectInMapSpace(offset_in_page);
+ if (!sub_result.empty()) {
+ result += "maybe " + sub_result;
+ }
+ }
+ if (roots.old_space == 0) {
+ std::string sub_result = FindKnownObjectInOldSpace(offset_in_page);
+ if (!sub_result.empty()) {
+ result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result;
+ }
+ }
+ if (roots.read_only_space == 0) {
+ std::string sub_result = FindKnownObjectInReadOnlySpace(offset_in_page);
+ if (!sub_result.empty()) {
+ result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result;
+ }
+ }
+
+ return result;
+}
+
+} // namespace v8_debug_helper_internal
diff --git a/deps/v8/tools/debug_helper/heap-constants.h b/deps/v8/tools/debug_helper/heap-constants.h
new file mode 100644
index 0000000000..f3149bbb47
--- /dev/null
+++ b/deps/v8/tools/debug_helper/heap-constants.h
@@ -0,0 +1,28 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_TOOLS_DEBUG_HELPER_HEAP_CONSTANTS_H_
+#define V8_TOOLS_DEBUG_HELPER_HEAP_CONSTANTS_H_
+
+#include <cstdint>
+#include <string>
+
+#include "debug-helper.h"
+
+namespace d = v8::debug_helper;
+
+namespace v8_debug_helper_internal {
+
+// Functions generated by mkgrokdump:
+std::string FindKnownObjectInOldSpace(uintptr_t offset);
+std::string FindKnownObjectInReadOnlySpace(uintptr_t offset);
+std::string FindKnownObjectInMapSpace(uintptr_t offset);
+std::string FindKnownMapInstanceTypeInMapSpace(uintptr_t offset);
+std::string FindKnownMapInstanceTypeInReadOnlySpace(uintptr_t offset);
+
+std::string FindKnownObject(uintptr_t address, const d::Roots& roots);
+
+} // namespace v8_debug_helper_internal
+
+#endif
diff --git a/deps/v8/tools/gcmole/BUILD.gn b/deps/v8/tools/gcmole/BUILD.gn
index 0434a64ff5..51b9ef527f 100644
--- a/deps/v8/tools/gcmole/BUILD.gn
+++ b/deps/v8/tools/gcmole/BUILD.gn
@@ -9,12 +9,16 @@ group("v8_run_gcmole") {
data = [
"gccause.lua",
+ "GCMOLE.gn",
"gcmole.lua",
"gcmole-tools/",
"parallel.py",
"run-gcmole.py",
+ "suspects.whitelist",
+ "test-expectations.txt",
# The following contains all relevant source and build files.
+ "../debug_helper/debug-helper.h",
"../../BUILD.gn",
"../../base/",
"../../include/",
diff --git a/deps/v8/tools/gcmole/GCMOLE.gn b/deps/v8/tools/gcmole/GCMOLE.gn
new file mode 100644
index 0000000000..62da0a084b
--- /dev/null
+++ b/deps/v8/tools/gcmole/GCMOLE.gn
@@ -0,0 +1,6 @@
+action("gcmole") {
+ sources = [
+ ### gcmole(all) ###
+ "tools/gcmole/gcmole-test.cc",
+ ]
+}
diff --git a/deps/v8/tools/gcmole/README b/deps/v8/tools/gcmole/README
index 578ea56219..48785b871a 100644
--- a/deps/v8/tools/gcmole/README
+++ b/deps/v8/tools/gcmole/README
@@ -71,6 +71,12 @@ can be ignored.
If any errors were found driver exits with non-zero status.
+TESTING -----------------------------------------------------------------------
+
+Tests are automatically run by the main lua runner. Expectations are in
+test-expectations.txt and need to be updated whenever the sources of the tests
+in gcmole-test.cc are modified (line numbers also count).
+
PACKAGING ---------------------------------------------------------------------
gcmole is deployed on V8's buildbot infrastructure to run it as part of the
diff --git a/deps/v8/tools/gcmole/gcmole-test.cc b/deps/v8/tools/gcmole/gcmole-test.cc
index c00c6e5539..3af1bac3b5 100644
--- a/deps/v8/tools/gcmole/gcmole-test.cc
+++ b/deps/v8/tools/gcmole/gcmole-test.cc
@@ -5,26 +5,43 @@
#include "src/execution/isolate.h"
#include "src/handles/handles-inl.h"
#include "src/handles/handles.h"
+#include "src/objects/foreign-inl.h"
+#include "src/objects/managed.h"
#include "src/objects/maybe-object.h"
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
+// ------- Test simple argument evaluation order problems ---------
+
Handle<Object> CauseGC(Handle<Object> obj, Isolate* isolate) {
isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting);
return obj;
}
+Object CauseGCRaw(Object obj, Isolate* isolate) {
+ isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting);
+
+ return obj;
+}
+
+Managed<Smi> CauseGCManaged(int i, Isolate* isolate) {
+ isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting);
+
+ return Managed<Smi>::cast(Smi::FromInt(i));
+}
+
void TwoArgumentsFunction(Object a, Object b) {
- a->Print();
- b->Print();
+ a.Print();
+ b.Print();
}
void TestTwoArguments(Isolate* isolate) {
Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
Handle<JSObject> obj2 = isolate->factory()->NewJSObjectWithNullProto();
+ // Should cause warning.
TwoArgumentsFunction(*CauseGC(obj1, isolate), *CauseGC(obj2, isolate));
}
@@ -36,13 +53,16 @@ void TwoSizeTArgumentsFunction(size_t a, size_t b) {
void TestTwoSizeTArguments(Isolate* isolate) {
Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
Handle<JSObject> obj2 = isolate->factory()->NewJSObjectWithNullProto();
+ // Should cause warning.
TwoSizeTArgumentsFunction(sizeof(*CauseGC(obj1, isolate)),
sizeof(*CauseGC(obj2, isolate)));
}
+// --------- Test problems with method arguments ----------
+
class SomeObject : public Object {
public:
- void Method(Object a) { a->Print(); }
+ void Method(Object a) { a.Print(); }
SomeObject& operator=(const Object& b) {
this->Print();
@@ -58,14 +78,57 @@ void TestMethodCall(Isolate* isolate) {
SomeObject obj;
Handle<SomeObject> so = handle(obj, isolate);
Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
+ // Should cause warning.
so->Method(*CauseGC(obj1, isolate));
+ // Should cause warning.
+ so->Method(CauseGCRaw(*obj1, isolate));
}
void TestOperatorCall(Isolate* isolate) {
SomeObject obj;
Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
+ // Should not cause warning.
obj = *CauseGC(obj1, isolate);
}
+// --------- Test for templated sub-classes of Object ----------
+
+void TestFollowingTemplates(Isolate* isolate) {
+ // Should cause warning.
+ CauseGCManaged(42, isolate);
+}
+
+// --------- Test for correctly resolving virtual methods ----------
+
+class BaseObject {
+ public:
+ virtual Handle<Object> VirtualCauseGC(Handle<Object> obj, Isolate* isolate) {
+ return obj;
+ }
+};
+
+class DerivedObject : public BaseObject {
+ public:
+ Handle<Object> VirtualCauseGC(Handle<Object> obj, Isolate* isolate) override {
+ isolate->heap()->CollectGarbage(OLD_SPACE,
+ GarbageCollectionReason::kTesting);
+
+ return obj;
+ }
+};
+
+void TestFollowingVirtualFunctions(Isolate* isolate) {
+ DerivedObject derived;
+ BaseObject* base = &derived;
+ Handle<JSObject> obj1 = isolate->factory()->NewJSObjectWithNullProto();
+
+ SomeObject so;
+ Handle<SomeObject> so_handle = handle(so, isolate);
+ // Should cause warning.
+ so_handle->Method(*derived.VirtualCauseGC(obj1, isolate));
+ // Should cause warning.
+ so_handle->Method(*base->VirtualCauseGC(obj1, isolate));
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 b/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1
index 718e967e3b..8f7876fa51 100644
--- a/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1
+++ b/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1
@@ -1 +1 @@
-3d4ba1759c3d5bc7e98c466d24fa0c43f186ba79 \ No newline at end of file
+d2f949820bf1ee7343a7b5f46987a3657aaea2e9 \ No newline at end of file
diff --git a/deps/v8/tools/gcmole/gcmole.cc b/deps/v8/tools/gcmole/gcmole.cc
index 6631583478..806100d381 100644
--- a/deps/v8/tools/gcmole/gcmole.cc
+++ b/deps/v8/tools/gcmole/gcmole.cc
@@ -47,6 +47,7 @@ namespace {
typedef std::string MangledName;
typedef std::set<MangledName> CalleesSet;
+typedef std::map<MangledName, MangledName> CalleesMap;
static bool GetMangledName(clang::MangleContext* ctx,
const clang::NamedDecl* decl,
@@ -138,14 +139,16 @@ class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> {
virtual bool VisitDeclRefExpr(clang::DeclRefExpr* expr) {
// If function mentions EXTERNAL VMState add artificial garbage collection
// mark.
- if (IsExternalVMState(expr->getDecl())) AddCallee("CollectGarbage");
+ if (IsExternalVMState(expr->getDecl()))
+ AddCallee("CollectGarbage", "CollectGarbage");
return true;
}
void AnalyzeFunction(const clang::FunctionDecl* f) {
MangledName name;
if (InV8Namespace(f) && GetMangledName(ctx_, f, &name)) {
- AddCallee(name);
+ const std::string& function = f->getNameAsString();
+ AddCallee(name, function);
const clang::FunctionDecl* body = NULL;
if (f->hasBody(body) && !Analyzed(name)) {
@@ -176,21 +179,22 @@ class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> {
scopes_.pop();
}
- void AddCallee(const MangledName& name) {
+ void AddCallee(const MangledName& name, const MangledName& function) {
if (!scopes_.empty()) scopes_.top()->insert(name);
+ mangled_to_function_[name] = function;
}
void PrintCallGraph() {
for (Callgraph::const_iterator i = callgraph_.begin(), e = callgraph_.end();
i != e;
++i) {
- std::cout << i->first << "\n";
+ std::cout << i->first << "," << mangled_to_function_[i->first] << "\n";
CalleesSet* callees = i->second;
for (CalleesSet::const_iterator j = callees->begin(), e = callees->end();
j != e;
++j) {
- std::cout << "\t" << *j << "\n";
+ std::cout << "\t" << *j << "," << mangled_to_function_[*j] << "\n";
}
}
}
@@ -200,6 +204,7 @@ class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> {
std::stack<CalleesSet* > scopes_;
Callgraph callgraph_;
+ CalleesMap mangled_to_function_;
};
@@ -234,23 +239,40 @@ class FunctionDeclarationFinder
CalleesPrinter* callees_printer_;
};
-
-static bool loaded = false;
+static bool gc_suspects_loaded = false;
static CalleesSet gc_suspects;
-
+static CalleesSet gc_functions;
+static bool whitelist_loaded = false;
+static CalleesSet suspects_whitelist;
static void LoadGCSuspects() {
- if (loaded) return;
+ if (gc_suspects_loaded) return;
std::ifstream fin("gcsuspects");
- std::string s;
+ std::string mangled, function;
- while (fin >> s) gc_suspects.insert(s);
+ while (!fin.eof()) {
+ std::getline(fin, mangled, ',');
+ gc_suspects.insert(mangled);
+ std::getline(fin, function);
+ gc_functions.insert(function);
+ }
- loaded = true;
+ gc_suspects_loaded = true;
}
+static void LoadSuspectsWhitelist() {
+ if (whitelist_loaded) return;
+
+ std::ifstream fin("tools/gcmole/suspects.whitelist");
+ std::string s;
+
+ while (fin >> s) suspects_whitelist.insert(s);
+ whitelist_loaded = true;
+}
+
+// Looks for exact match of the mangled name
static bool KnownToCauseGC(clang::MangleContext* ctx,
const clang::FunctionDecl* decl) {
LoadGCSuspects();
@@ -265,6 +287,25 @@ static bool KnownToCauseGC(clang::MangleContext* ctx,
return false;
}
+// Looks for partial match of only the function name
+static bool SuspectedToCauseGC(clang::MangleContext* ctx,
+ const clang::FunctionDecl* decl) {
+ LoadGCSuspects();
+
+ if (!InV8Namespace(decl)) return false;
+
+ LoadSuspectsWhitelist();
+ if (suspects_whitelist.find(decl->getNameAsString()) !=
+ suspects_whitelist.end()) {
+ return false;
+ }
+
+ if (gc_functions.find(decl->getNameAsString()) != gc_functions.end()) {
+ return true;
+ }
+
+ return false;
+}
static const int kNoEffect = 0;
static const int kCausesGC = 1;
@@ -910,8 +951,30 @@ class FunctionAnalyzer {
RepresentsRawPointerType(call->getType()));
clang::FunctionDecl* callee = call->getDirectCallee();
- if ((callee != NULL) && KnownToCauseGC(ctx_, callee)) {
- out.setGC();
+ if (callee != NULL) {
+ if (KnownToCauseGC(ctx_, callee)) {
+ out.setGC();
+ }
+
+ clang::CXXMethodDecl* method =
+ llvm::dyn_cast_or_null<clang::CXXMethodDecl>(callee);
+ if (method != NULL && method->isVirtual()) {
+ clang::CXXMemberCallExpr* memcall =
+ llvm::dyn_cast_or_null<clang::CXXMemberCallExpr>(call);
+ if (memcall != NULL) {
+ clang::CXXMethodDecl* target = method->getDevirtualizedMethod(
+ memcall->getImplicitObjectArgument(), false);
+ if (target != NULL) {
+ if (KnownToCauseGC(ctx_, target)) {
+ out.setGC();
+ }
+ } else {
+ if (SuspectedToCauseGC(ctx_, method)) {
+ out.setGC();
+ }
+ }
+ }
+ }
}
return out;
diff --git a/deps/v8/tools/gcmole/gcmole.lua b/deps/v8/tools/gcmole/gcmole.lua
index ae17fdc5f6..6758973457 100644
--- a/deps/v8/tools/gcmole/gcmole.lua
+++ b/deps/v8/tools/gcmole/gcmole.lua
@@ -183,12 +183,19 @@ end
-------------------------------------------------------------------------------
-local function ParseGNFile()
+local function ParseGNFile(for_test)
local result = {}
- local gn_files = {
- { "BUILD.gn", '"([^"]-%.cc)"', "" },
- { "test/cctest/BUILD.gn", '"(test-[^"]-%.cc)"', "test/cctest/" }
- }
+ local gn_files
+ if for_test then
+ gn_files = {
+ { "tools/gcmole/GCMOLE.gn", '"([^"]-%.cc)"', "" }
+ }
+ else
+ gn_files = {
+ { "BUILD.gn", '"([^"]-%.cc)"', "" },
+ { "test/cctest/BUILD.gn", '"(test-[^"]-%.cc)"', "test/cctest/" }
+ }
+ end
for i = 1, #gn_files do
local filename = gn_files[i][1]
@@ -231,7 +238,8 @@ local function BuildFileList(sources, props)
end
-local gn_sources = ParseGNFile()
+local gn_sources = ParseGNFile(false)
+local gn_test_sources = ParseGNFile(true)
local function FilesForArch(arch)
return BuildFileList(gn_sources, { os = 'linux',
@@ -240,6 +248,13 @@ local function FilesForArch(arch)
simulator = ''})
end
+local function FilesForTest(arch)
+ return BuildFileList(gn_test_sources, { os = 'linux',
+ arch = arch,
+ mode = 'debug',
+ simulator = ''})
+end
+
local mtConfig = {}
mtConfig.__index = mtConfig
@@ -393,8 +408,13 @@ end
--------------------------------------------------------------------------------
-- Analysis
-local function CheckCorrectnessForArch(arch)
- local files = FilesForArch(arch)
+local function CheckCorrectnessForArch(arch, for_test)
+ local files
+ if for_test then
+ files = FilesForTest(arch)
+ else
+ files = FilesForArch(arch)
+ end
local cfg = ARCHITECTURES[arch]
if not FLAGS.reuse_gcsuspects then
@@ -403,6 +423,7 @@ local function CheckCorrectnessForArch(arch)
local processed_files = 0
local errors_found = false
+ local output = ""
local function SearchForErrors(filename, lines)
processed_files = processed_files + 1
for l in lines do
@@ -410,7 +431,11 @@ local function CheckCorrectnessForArch(arch)
l:match "^[^:]+:%d+:%d+:" or
l:match "error" or
l:match "warning"
- print(l)
+ if for_test then
+ output = output.."\n"..l
+ else
+ print(l)
+ end
end
end
@@ -427,18 +452,34 @@ local function CheckCorrectnessForArch(arch)
processed_files,
errors_found and "Errors found" or "No errors found")
- return errors_found
+ return errors_found, output
end
-local function SafeCheckCorrectnessForArch(arch)
- local status, errors = pcall(CheckCorrectnessForArch, arch)
+local function SafeCheckCorrectnessForArch(arch, for_test)
+ local status, errors, output = pcall(CheckCorrectnessForArch, arch, for_test)
if not status then
print(string.format("There was an error: %s", errors))
errors = true
end
- return errors
+ return errors, output
+end
+
+local function TestRun()
+ local errors, output = SafeCheckCorrectnessForArch('x64', true)
+
+ local filename = "tools/gcmole/test-expectations.txt"
+ local exp_file = assert(io.open(filename), "failed to open test expectations file")
+ local expectations = exp_file:read('*all')
+
+ if output ~= expectations then
+ log("** Output mismatch from running tests. Please run them manually.")
+ else
+ log("** Tests ran successfully")
+ end
end
+TestRun()
+
local errors = false
for _, arch in ipairs(ARCHS) do
@@ -446,7 +487,7 @@ for _, arch in ipairs(ARCHS) do
error ("Unknown arch: " .. arch)
end
- errors = SafeCheckCorrectnessForArch(arch, report) or errors
+ errors = SafeCheckCorrectnessForArch(arch, false) or errors
end
os.exit(errors and 1 or 0)
diff --git a/deps/v8/tools/gcmole/suspects.whitelist b/deps/v8/tools/gcmole/suspects.whitelist
new file mode 100644
index 0000000000..01db7401f2
--- /dev/null
+++ b/deps/v8/tools/gcmole/suspects.whitelist
@@ -0,0 +1,4 @@
+IsConstructor
+IsEval
+IsAsync
+IsPromiseAll
diff --git a/deps/v8/tools/gcmole/test-expectations.txt b/deps/v8/tools/gcmole/test-expectations.txt
new file mode 100644
index 0000000000..36a026a12e
--- /dev/null
+++ b/deps/v8/tools/gcmole/test-expectations.txt
@@ -0,0 +1,20 @@
+
+tools/gcmole/gcmole-test.cc:45:3: warning: Possible problem with evaluation order.
+ TwoArgumentsFunction(*CauseGC(obj1, isolate), *CauseGC(obj2, isolate));
+ ^
+tools/gcmole/gcmole-test.cc:57:3: warning: Possible problem with evaluation order.
+ TwoSizeTArgumentsFunction(sizeof(*CauseGC(obj1, isolate)),
+ ^
+tools/gcmole/gcmole-test.cc:82:7: warning: Possible problem with evaluation order.
+ so->Method(*CauseGC(obj1, isolate));
+ ^
+tools/gcmole/gcmole-test.cc:84:7: warning: Possible problem with evaluation order.
+ so->Method(CauseGCRaw(*obj1, isolate));
+ ^
+tools/gcmole/gcmole-test.cc:128:14: warning: Possible problem with evaluation order.
+ so_handle->Method(*derived.VirtualCauseGC(obj1, isolate));
+ ^
+tools/gcmole/gcmole-test.cc:130:14: warning: Possible problem with evaluation order.
+ so_handle->Method(*base->VirtualCauseGC(obj1, isolate));
+ ^
+6 warnings generated.
diff --git a/deps/v8/tools/gen-postmortem-metadata.py b/deps/v8/tools/gen-postmortem-metadata.py
index b5aba23220..0715b07dc1 100644
--- a/deps/v8/tools/gen-postmortem-metadata.py
+++ b/deps/v8/tools/gen-postmortem-metadata.py
@@ -166,7 +166,7 @@ consts_misc = [
{ 'name': 'bit_field3_number_of_own_descriptors_shift',
'value': 'Map::NumberOfOwnDescriptorsBits::kShift' },
{ 'name': 'class_Map__instance_descriptors_offset',
- 'value': 'Map::kInstanceDescriptorsOffset' },
+ 'value': 'Map::kInstanceDescriptorsOffset' },
{ 'name': 'off_fp_context_or_frame_type',
'value': 'CommonFrameConstants::kContextOrFrameTypeOffset'},
diff --git a/deps/v8/tools/heap-stats/categories.js b/deps/v8/tools/heap-stats/categories.js
index e02571b4f8..6560758f3e 100644
--- a/deps/v8/tools/heap-stats/categories.js
+++ b/deps/v8/tools/heap-stats/categories.js
@@ -77,7 +77,7 @@ const CATEGORIES = new Map([
'JS_TO_WASM_FUNCTION',
'JS_TYPED_ARRAY_TYPE',
'JS_WEAK_MAP_TYPE',
- 'MUTABLE_HEAP_NUMBER_TYPE',
+ 'HEAP_NUMBER_TYPE',
'NATIVE_CONTEXT_TYPE',
'OBJECT_PROPERTY_DICTIONARY_TYPE',
'ONE_BYTE_INTERNALIZED_STRING_TYPE',
diff --git a/deps/v8/tools/heap-stats/global-timeline.js b/deps/v8/tools/heap-stats/global-timeline.js
index 3830b7ca33..c34ba2b913 100644
--- a/deps/v8/tools/heap-stats/global-timeline.js
+++ b/deps/v8/tools/heap-stats/global-timeline.js
@@ -63,9 +63,12 @@ class GlobalTimeline extends HTMLElement {
{type: 'number', label: 'Ptr compression benefit'},
{type: 'string', role: 'tooltip'},
{type: 'number', label: 'Embedder fields'},
- {type: 'number', label: 'Tagged fields'},
+ {type: 'number', label: 'Tagged fields (excl. in-object Smis)'},
+ {type: 'number', label: 'In-object Smi-only fields'},
{type: 'number', label: 'Other raw fields'},
- {type: 'number', label: 'Unboxed doubles'}
+ {type: 'number', label: 'Unboxed doubles'},
+ {type: 'number', label: 'Boxed doubles'},
+ {type: 'number', label: 'String data'}
];
const chart_data = [labels];
const isolate_data = this.data[this.selection.isolate];
@@ -78,10 +81,14 @@ class GlobalTimeline extends HTMLElement {
const data = [];
data.push(gc_data.time * kMillis2Seconds);
const total = data_set.tagged_fields +
+ data_set.inobject_smi_fields +
data_set.embedder_fields +
data_set.other_raw_fields +
- data_set.unboxed_double_fields;
- const ptr_compr_benefit = data_set.tagged_fields / 2;
+ data_set.unboxed_double_fields +
+ data_set.boxed_double_fields +
+ data_set.string_data;
+ const ptr_compr_benefit =
+ (data_set.inobject_smi_fields + data_set.tagged_fields) / 2;
const ptr_compr_benefit_perc = ptr_compr_benefit / total * 100;
sum_total += total;
sum_ptr_compr_benefit_perc += ptr_compr_benefit_perc;
@@ -93,8 +100,11 @@ class GlobalTimeline extends HTMLElement {
data.push(tooltip);
data.push(data_set.embedder_fields / KB);
data.push(data_set.tagged_fields / KB);
+ data.push(data_set.inobject_smi_fields / KB);
data.push(data_set.other_raw_fields / KB);
data.push(data_set.unboxed_double_fields / KB);
+ data.push(data_set.boxed_double_fields / KB);
+ data.push(data_set.string_data / KB);
chart_data.push(data);
});
const avg_ptr_compr_benefit_perc =
diff --git a/deps/v8/tools/heap-stats/trace-file-reader.js b/deps/v8/tools/heap-stats/trace-file-reader.js
index 4fec9a1cb9..86d9d7d551 100644
--- a/deps/v8/tools/heap-stats/trace-file-reader.js
+++ b/deps/v8/tools/heap-stats/trace-file-reader.js
@@ -137,11 +137,15 @@ class TraceFileReader extends HTMLElement {
}
addFieldTypeData(data, isolate, gc_id, data_set, tagged_fields,
- embedder_fields, unboxed_double_fields, other_raw_fields) {
+ inobject_smi_fields, embedder_fields, unboxed_double_fields,
+ boxed_double_fields, string_data, other_raw_fields) {
data[isolate].gcs[gc_id][data_set].field_data = {
tagged_fields,
+ inobject_smi_fields,
embedder_fields,
unboxed_double_fields,
+ boxed_double_fields,
+ string_data,
other_raw_fields
};
}
@@ -217,8 +221,12 @@ class TraceFileReader extends HTMLElement {
const field_data = entry.field_data;
this.addFieldTypeData(data, isolate, gc_id, data_set,
- field_data.tagged_fields, field_data.embedder_fields,
+ field_data.tagged_fields,
+ field_data.inobject_smi_fields,
+ field_data.embedder_fields,
field_data.unboxed_double_fields,
+ field_data.boxed_double_fields,
+ field_data.string_data,
field_data.other_raw_fields);
data[isolate].gcs[gc_id][data_set].bucket_sizes =
@@ -282,8 +290,9 @@ class TraceFileReader extends HTMLElement {
this.createOrUpdateEntryIfNeeded(data, entry);
this.createDatasetIfNeeded(data, entry, entry.key);
this.addFieldTypeData(data, entry.isolate, entry.id, entry.key,
- entry.tagged_fields, entry.embedder_fields,
- entry.unboxed_double_fields, entry.other_raw_fields);
+ entry.tagged_fields, entry.embedder_fields, entry.inobject_smi_fields,
+ entry.unboxed_double_fields, entry.boxed_double_fields,
+ entry.string_data, entry.other_raw_fields);
} else if (entry.type === 'instance_type_data') {
if (entry.id in data[entry.isolate].gcs) {
this.createOrUpdateEntryIfNeeded(data, entry);
diff --git a/deps/v8/tools/run-wasm-api-tests.py b/deps/v8/tools/run-wasm-api-tests.py
index 79f53cb927..ff37c8a465 100755
--- a/deps/v8/tools/run-wasm-api-tests.py
+++ b/deps/v8/tools/run-wasm-api-tests.py
@@ -38,7 +38,8 @@ CLANG_PATH = os.path.join(CHECKOUT_PATH, "third_party", "llvm-build",
"Release+Asserts", "bin")
EXAMPLES = ["hello", "callback", "trap", "reflect", "global", "table",
- "memory", "finalize", "serialize", "threads"]
+ "memory", "finalize", "serialize", "threads", "hostref", "multi",
+ "start"]
CLANG = {
"name": "Clang",
diff --git a/deps/v8/tools/testrunner/OWNERS b/deps/v8/tools/testrunner/OWNERS
index bdb1d555a4..09e0096a2e 100644
--- a/deps/v8/tools/testrunner/OWNERS
+++ b/deps/v8/tools/testrunner/OWNERS
@@ -1 +1 @@
-file://INFRA_OWNERS
+file:../../INFRA_OWNERS
diff --git a/deps/v8/tools/testrunner/base_runner.py b/deps/v8/tools/testrunner/base_runner.py
index 15c5335878..7f9b43435f 100644
--- a/deps/v8/tools/testrunner/base_runner.py
+++ b/deps/v8/tools/testrunner/base_runner.py
@@ -349,9 +349,6 @@ class BaseTestRunner(object):
"color, mono)")
parser.add_option("--json-test-results",
help="Path to a file for storing json results.")
- parser.add_option("--junitout", help="File name of the JUnit output")
- parser.add_option("--junittestsuite", default="v8tests",
- help="The testsuite name in the JUnit output file")
parser.add_option("--exit-after-n-failures", type="int", default=100,
help="Exit after the first N failures instead of "
"running all tests. Pass 0 to disable this feature.")
@@ -794,9 +791,6 @@ class BaseTestRunner(object):
def _create_progress_indicators(self, test_count, options):
procs = [PROGRESS_INDICATORS[options.progress]()]
- if options.junitout:
- procs.append(progress.JUnitTestProgressIndicator(options.junitout,
- options.junittestsuite))
if options.json_test_results:
procs.append(progress.JsonTestProgressIndicator(
self.framework_name,
diff --git a/deps/v8/tools/testrunner/local/junit_output.py b/deps/v8/tools/testrunner/local/junit_output.py
deleted file mode 100644
index 52f31ec422..0000000000
--- a/deps/v8/tools/testrunner/local/junit_output.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright 2013 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-import xml.etree.ElementTree as xml
-
-
-class JUnitTestOutput:
- def __init__(self, test_suite_name):
- self.root = xml.Element("testsuite")
- self.root.attrib["name"] = test_suite_name
-
- def HasRunTest(self, test_name, test_cmd, test_duration, test_failure):
- testCaseElement = xml.Element("testcase")
- testCaseElement.attrib["name"] = test_name
- testCaseElement.attrib["cmd"] = test_cmd
- testCaseElement.attrib["time"] = str(round(test_duration, 3))
- if len(test_failure):
- failureElement = xml.Element("failure")
- failureElement.text = test_failure
- testCaseElement.append(failureElement)
- self.root.append(testCaseElement)
-
- def FinishAndWrite(self, f):
- xml.ElementTree(self.root).write(f, "UTF-8")
diff --git a/deps/v8/tools/testrunner/local/pool.py b/deps/v8/tools/testrunner/local/pool.py
index e0b0ec41c7..9defdd30ee 100644
--- a/deps/v8/tools/testrunner/local/pool.py
+++ b/deps/v8/tools/testrunner/local/pool.py
@@ -115,7 +115,15 @@ class Pool():
# Necessary to not overflow the queue's pipe if a keyboard interrupt happens.
BUFFER_FACTOR = 4
- def __init__(self, num_workers, heartbeat_timeout=1):
+ def __init__(self, num_workers, heartbeat_timeout=1, notify_fun=None):
+ """
+ Args:
+ num_workers: Number of worker processes to run in parallel.
+ heartbeat_timeout: Timeout in seconds for waiting for results. Each time
+ the timeout is reached, a heartbeat is signalled and timeout is reset.
+ notify_fun: Callable called to signale some events like termination. The
+ event name is passed as string.
+ """
self.num_workers = num_workers
self.processes = []
self.terminated = False
@@ -130,6 +138,7 @@ class Pool():
# work_queue.
self.processing_count = 0
self.heartbeat_timeout = heartbeat_timeout
+ self.notify = notify_fun or (lambda x: x)
# Disable sigint and sigterm to prevent subprocesses from capturing the
# signals.
@@ -261,11 +270,13 @@ class Pool():
for p in self.processes:
os.kill(p.pid, signal.SIGTERM)
+ self.notify("Joining workers")
for p in self.processes:
p.join()
# Drain the queues to prevent stderr chatter when queues are garbage
# collected.
+ self.notify("Draining queues")
try:
while True: self.work_queue.get(False)
except:
diff --git a/deps/v8/tools/testrunner/local/variants.py b/deps/v8/tools/testrunner/local/variants.py
index 4b0cf1553b..fe63d0b935 100644
--- a/deps/v8/tools/testrunner/local/variants.py
+++ b/deps/v8/tools/testrunner/local/variants.py
@@ -23,7 +23,7 @@ ALL_VARIANT_FLAGS = {
"nooptimization": [["--no-opt", "--liftoff", "--no-wasm-tier-up"]],
"slow_path": [["--force-slow-path"]],
"stress": [["--stress-opt", "--always-opt", "--no-liftoff",
- "--no-wasm-tier-up"]],
+ "--no-wasm-tier-up", '--stress-lazy-source-positions']],
"stress_js_bg_compile_wasm_code_gc": [["--stress-background-compile",
"--wasm-code-gc",
"--stress-wasm-code-gc"]],
diff --git a/deps/v8/tools/testrunner/testproc/base.py b/deps/v8/tools/testrunner/testproc/base.py
index c52c779752..6048ef5d15 100644
--- a/deps/v8/tools/testrunner/testproc/base.py
+++ b/deps/v8/tools/testrunner/testproc/base.py
@@ -109,6 +109,19 @@ class TestProc(object):
### Communication
+ def notify_previous(self, event):
+ self._on_event(event)
+ if self._prev_proc:
+ self._prev_proc.notify_previous(event)
+
+ def _on_event(self, event):
+ """Called when processors to the right signal events, e.g. termination.
+
+ Args:
+ event: A text describing the signalled event.
+ """
+ pass
+
def _send_test(self, test):
"""Helper method for sending test to the next processor."""
return self._next_proc.next_test(test)
@@ -120,7 +133,6 @@ class TestProc(object):
self._prev_proc.result_for(test, result)
-
class TestProcObserver(TestProc):
"""Processor used for observing the data."""
def __init__(self):
diff --git a/deps/v8/tools/testrunner/testproc/execution.py b/deps/v8/tools/testrunner/testproc/execution.py
index 68ecf45a37..aaf0db1f8f 100644
--- a/deps/v8/tools/testrunner/testproc/execution.py
+++ b/deps/v8/tools/testrunner/testproc/execution.py
@@ -45,7 +45,7 @@ class ExecutionProc(base.TestProc):
def __init__(self, jobs, outproc_factory=None):
super(ExecutionProc, self).__init__()
- self._pool = pool.Pool(jobs)
+ self._pool = pool.Pool(jobs, notify_fun=self.notify_previous)
self._outproc_factory = outproc_factory or (lambda t: t.output_proc)
self._tests = {}
diff --git a/deps/v8/tools/testrunner/testproc/progress.py b/deps/v8/tools/testrunner/testproc/progress.py
index 3ba10f9528..8826c36ea4 100644
--- a/deps/v8/tools/testrunner/testproc/progress.py
+++ b/deps/v8/tools/testrunner/testproc/progress.py
@@ -13,7 +13,6 @@ import sys
import time
from . import base
-from ..local import junit_output
# Base dir of the build products for Release and Debug.
@@ -150,6 +149,10 @@ class VerboseProgressIndicator(SimpleProgressIndicator):
self._print('Still working...')
self._print_processes_linux()
+ def _on_event(self, event):
+ self._print(event)
+ self._print_processes_linux()
+
class DotsProgressIndicator(SimpleProgressIndicator):
def __init__(self):
@@ -282,45 +285,6 @@ class MonochromeProgressIndicator(CompactProgressIndicator):
print(("\r" + (" " * last_length) + "\r"), end='')
-class JUnitTestProgressIndicator(ProgressIndicator):
- def __init__(self, junitout, junittestsuite):
- super(JUnitTestProgressIndicator, self).__init__()
- self._requirement = base.DROP_PASS_STDOUT
-
- self.outputter = junit_output.JUnitTestOutput(junittestsuite)
- if junitout:
- self.outfile = open(junitout, "w")
- else:
- self.outfile = sys.stdout
-
- def _on_result_for(self, test, result):
- # TODO(majeski): Support for dummy/grouped results
- fail_text = ""
- output = result.output
- if result.has_unexpected_output:
- stdout = output.stdout.strip()
- if len(stdout):
- fail_text += "stdout:\n%s\n" % stdout
- stderr = output.stderr.strip()
- if len(stderr):
- fail_text += "stderr:\n%s\n" % stderr
- fail_text += "Command: %s" % result.cmd.to_string()
- if output.HasCrashed():
- fail_text += "exit code: %d\n--- CRASHED ---" % output.exit_code
- if output.HasTimedOut():
- fail_text += "--- TIMEOUT ---"
- self.outputter.HasRunTest(
- test_name=str(test),
- test_cmd=result.cmd.to_string(relative=True),
- test_duration=output.duration,
- test_failure=fail_text)
-
- def finished(self):
- self.outputter.FinishAndWrite(self.outfile)
- if self.outfile != sys.stdout:
- self.outfile.close()
-
-
class JsonTestProgressIndicator(ProgressIndicator):
def __init__(self, framework_name, json_test_results, arch, mode):
super(JsonTestProgressIndicator, self).__init__()
diff --git a/deps/v8/tools/testrunner/testproc/timeout.py b/deps/v8/tools/testrunner/testproc/timeout.py
index 54dc60e9b4..9a4e88c8f0 100644
--- a/deps/v8/tools/testrunner/testproc/timeout.py
+++ b/deps/v8/tools/testrunner/testproc/timeout.py
@@ -14,15 +14,15 @@ class TimeoutProc(base.TestProcObserver):
self._start = time.time()
def _on_next_test(self, test):
- self._on_event()
+ self.__on_event()
def _on_result_for(self, test, result):
- self._on_event()
+ self.__on_event()
def _on_heartbeat(self):
- self._on_event()
+ self.__on_event()
- def _on_event(self):
+ def __on_event(self):
if not self.is_stopped:
if time.time() - self._start > self._duration_sec:
print('>>> Total timeout reached.')
diff --git a/deps/v8/tools/torque/format-torque.py b/deps/v8/tools/torque/format-torque.py
index 2150d7e0cc..2e04e659c1 100755
--- a/deps/v8/tools/torque/format-torque.py
+++ b/deps/v8/tools/torque/format-torque.py
@@ -20,18 +20,9 @@ kPercentEscape = r'α'; # Unicode alpha
def preprocess(input):
input = re.sub(r'(if\s+)constexpr(\s*\()', r'\1/*COxp*/\2', input)
input = re.sub(r'(\s+)operator\s*(\'[^\']+\')', r'\1/*_OPE \2*/', input)
-
- # Mangle typeswitches to look like switch statements with the extra type
- # information and syntax encoded in comments.
- input = re.sub(r'(\s+)typeswitch\s*\(', r'\1/*_TYPE*/switch (', input)
- input = re.sub(r'(\s+)case\s*\(\s*([^\:]+)\s*\)(\s*)\:\s*deferred',
- r'\1case \2: /*_TSXDEFERRED_*/', input)
- input = re.sub(r'(\s+)case\s*\(\s*([^\:]+)\s*\)(\s*)\:',
- r'\1case \2: /*_TSX*/', input)
- input = re.sub(r'(\s+)case\s*\(\s*([^\s]+)\s*\:\s*([^\:]+)\s*\)(\s*)\:\s*deferred',
- r'\1case \3: /*_TSVDEFERRED_\2:*/', input)
- input = re.sub(r'(\s+)case\s*\(\s*([^\s]+)\s*\:\s*([^\:]+)\s*\)(\s*)\:',
- r'\1case \3: /*_TSV\2:*/', input)
+ input = re.sub(r'\btypeswitch\s*(\([^{]*\))\s{', r' if /*tPsW*/ \1 {', input)
+ input = re.sub(r'\bcase\s*(\([^{]*\))\s*:\s*deferred\s*{', r' if /*cAsEdEfF*/ \1 {', input)
+ input = re.sub(r'\bcase\s*(\([^{]*\))\s*:\s*{', r' if /*cA*/ \1 {', input)
# Add extra space around | operators to fix union types later.
while True:
@@ -65,15 +56,9 @@ def postprocess(output):
output = re.sub(r'(\S+)\s*: type([,>])', r'\1: type\2', output)
output = re.sub(r'(\n\s*)labels( [A-Z])', r'\1 labels\2', output)
output = re.sub(r'\/\*_OPE \'([^\']+)\'\*\/', r"operator '\1'", output)
- output = re.sub(r'\/\*_TYPE\*\/(\s*)switch', r'typeswitch', output)
- output = re.sub(r'case (\w+)\:\s*\/\*_TSXDEFERRED_\*\/',
- r'case (\1): deferred', output)
- output = re.sub(r'case (\w+)\:\s*\/\*_TSX\*\/',
- r'case (\1):', output)
- output = re.sub(r'case (\w+)\:\s*\/\*_TSVDEFERRED_([^\:]+)\:\*\/',
- r'case (\2: \1): deferred', output)
- output = re.sub(r'case (\w+)\:\s*\/\*_TSV([^\:]+)\:\*\/',
- r'case (\2: \1):', output)
+ output = re.sub(r'\bif\s*\/\*tPsW\*\/', r'typeswitch', output)
+ output = re.sub(r'\bif\s*\/\*cA\*\/\s*(\([^{]*\))\s*{', r'case \1: {', output)
+ output = re.sub(r'\bif\s*\/\*cAsEdEfF\*\/\s*(\([^{]*\))\s*{', r'case \1: deferred {', output)
output = re.sub(r'\n_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/',
r"\n generates '\1'", output)
output = re.sub(r'_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/',
diff --git a/deps/v8/tools/turbolizer/info-view.html b/deps/v8/tools/turbolizer/info-view.html
index b523e655aa..dc9c177f60 100644
--- a/deps/v8/tools/turbolizer/info-view.html
+++ b/deps/v8/tools/turbolizer/info-view.html
@@ -107,7 +107,7 @@
</tr>
<tr>
<td>^42:</td>
- <td>Select exactly the node with id 14.</td>
+ <td>Select exactly the node with id 42.</td>
</tr>
<tr>
<td>Origin:&nbsp;#42&nbsp;</td>
diff --git a/deps/v8/tools/turbolizer/package-lock.json b/deps/v8/tools/turbolizer/package-lock.json
index 9c8049fdb5..e30838aa3b 100644
--- a/deps/v8/tools/turbolizer/package-lock.json
+++ b/deps/v8/tools/turbolizer/package-lock.json
@@ -1687,9 +1687,9 @@
"dev": true
},
"js-yaml": {
- "version": "3.12.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz",
- "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==",
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
@@ -2344,9 +2344,9 @@
"dev": true
},
"mixin-deep": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
- "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"requires": {
"for-in": "^1.0.2",
"is-extendable": "^1.0.1"
@@ -2872,9 +2872,9 @@
}
},
"set-value": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
- "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
@@ -3407,35 +3407,14 @@
"dev": true
},
"union-value": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
- "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
- "set-value": "^0.4.3"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
- "set-value": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
- "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-extendable": "^0.1.1",
- "is-plain-object": "^2.0.1",
- "to-object-path": "^0.3.0"
- }
- }
+ "set-value": "^2.0.1"
}
},
"universalify": {
diff --git a/deps/v8/tools/turbolizer/src/disassembly-view.ts b/deps/v8/tools/turbolizer/src/disassembly-view.ts
index 4b8fc6ea2d..0455437002 100644
--- a/deps/v8/tools/turbolizer/src/disassembly-view.ts
+++ b/deps/v8/tools/turbolizer/src/disassembly-view.ts
@@ -13,6 +13,7 @@ const toolboxHTML = `<div id="disassembly-toolbox">
<form>
<label><input id="show-instruction-address" type="checkbox" name="instruction-address">Show addresses</label>
<label><input id="show-instruction-binary" type="checkbox" name="instruction-binary">Show binary literal</label>
+ <label><input id="highlight-gap-instructions" type="checkbox" name="instruction-binary">Highlight gap instructions</label>
</form>
</div>`;
@@ -26,13 +27,14 @@ export class DisassemblyView extends TextView {
offsetSelection: MySelection;
showInstructionAddressHandler: () => void;
showInstructionBinaryHandler: () => void;
+ highlightGapInstructionsHandler: () => void;
createViewElement() {
const pane = document.createElement('div');
pane.setAttribute('id', "disassembly");
pane.innerHTML =
`<pre id='disassembly-text-pre' class='prettyprint prettyprinted'>
- <ul id='disassembly-list' class='nolinenums noindent'>
+ <ul class='disassembly-list nolinenums noindent'>
</ul>
</pre>`;
@@ -46,6 +48,19 @@ export class DisassemblyView extends TextView {
associateData: (text, fragment: HTMLElement) => {
const matches = text.match(/(?<address>0?x?[0-9a-fA-F]{8,16})(?<addressSpace>\s+)(?<offset>[0-9a-f]+)(?<offsetSpace>\s*)/);
const offset = Number.parseInt(matches.groups["offset"], 16);
+ const instructionKind = view.sourceResolver.getInstructionKindForPCOffset(offset);
+ fragment.dataset.instructionKind = instructionKind;
+ fragment.title = view.sourceResolver.instructionKindToReadableName(instructionKind);
+ const blockIds = view.sourceResolver.getBlockIdsForOffset(offset);
+ const blockIdElement = document.createElement("SPAN");
+ blockIdElement.className = "block-id com linkable-text";
+ blockIdElement.innerText = "";
+ if (blockIds && blockIds.length > 0) {
+ blockIds.forEach(blockId => view.addHtmlElementForBlockId(blockId, fragment));
+ blockIdElement.innerText = `B${blockIds.join(",")}:`;
+ blockIdElement.dataset.blockId = `${blockIds.join(",")}`;
+ }
+ fragment.appendChild(blockIdElement);
const addressElement = document.createElement("SPAN");
addressElement.className = "instruction-address";
addressElement.innerText = matches.groups["address"];
@@ -58,11 +73,13 @@ export class DisassemblyView extends TextView {
fragment.classList.add('tag');
if (!Number.isNaN(offset)) {
- const pcOffset = view.sourceResolver.getKeyPcOffset(offset);
+ let pcOffset = view.sourceResolver.getKeyPcOffset(offset);
+ if (pcOffset == -1) pcOffset = Number(offset);
fragment.dataset.pcOffset = `${pcOffset}`;
addressElement.classList.add('linkable-text');
offsetElement.classList.add('linkable-text');
}
+ return true;
}
};
const UNCLASSIFIED_STYLE = {
@@ -79,11 +96,20 @@ export class DisassemblyView extends TextView {
fragment.innerHTML = text;
const replacer = (match, hexOffset) => {
const offset = Number.parseInt(hexOffset, 16);
- const keyOffset = view.sourceResolver.getKeyPcOffset(offset);
- return `<span class="tag linkable-text" data-pc-offset="${keyOffset}">${match}</span>`;
+ let keyOffset = view.sourceResolver.getKeyPcOffset(offset);
+ if (keyOffset == -1) keyOffset = Number(offset);
+ const blockIds = view.sourceResolver.getBlockIdsForOffset(offset);
+ let block = "";
+ let blockIdData = "";
+ if (blockIds && blockIds.length > 0) {
+ block = `B${blockIds.join(",")} `;
+ blockIdData = `data-block-id="${blockIds.join(",")}"`;
+ }
+ return `<span class="tag linkable-text" data-pc-offset="${keyOffset}" ${blockIdData}>${block}${match}</span>`;
};
const html = text.replace(/<.0?x?([0-9a-fA-F]+)>/g, replacer);
fragment.innerHTML = html;
+ return true;
}
};
const OPCODE_STYLE = {
@@ -91,12 +117,14 @@ export class DisassemblyView extends TextView {
};
const BLOCK_HEADER_STYLE = {
associateData: function (text, fragment) {
+ if (view.sourceResolver.hasBlockStartInfo()) return false;
const matches = /\d+/.exec(text);
- if (!matches) return;
+ if (!matches) return true;
const blockId = matches[0];
fragment.dataset.blockId = blockId;
fragment.innerHTML = text;
fragment.className = "com block";
+ return true;
}
};
const SOURCE_POSITION_HEADER_STYLE = {
@@ -135,7 +163,7 @@ export class DisassemblyView extends TextView {
const linkHandler = (e: MouseEvent) => {
if (!(e.target instanceof HTMLElement)) return;
- const offsetAsString = e.target.dataset.pcOffset ? e.target.dataset.pcOffset : e.target.parentElement.dataset.pcOffset;
+ const offsetAsString = typeof e.target.dataset.pcOffset != "undefined" ? e.target.dataset.pcOffset : e.target.parentElement.dataset.pcOffset;
const offset = Number.parseInt(offsetAsString, 10);
if ((typeof offsetAsString) != "undefined" && !Number.isNaN(offset)) {
view.offsetSelection.select([offset], true);
@@ -156,12 +184,12 @@ export class DisassemblyView extends TextView {
const linkHandlerBlock = e => {
const blockId = e.target.dataset.blockId;
- if (typeof blockId != "undefined" && !Number.isNaN(blockId)) {
- e.stopPropagation();
+ if (typeof blockId != "undefined") {
+ const blockIds = blockId.split(",");
if (!e.shiftKey) {
view.selectionHandler.clear();
}
- view.blockSelectionHandler.select([blockId], true);
+ view.blockSelectionHandler.select(blockIds, true);
}
};
view.divNode.addEventListener('click', linkHandlerBlock);
@@ -219,6 +247,17 @@ export class DisassemblyView extends TextView {
};
instructionBinaryInput.addEventListener("change", showInstructionBinaryHandler);
this.showInstructionBinaryHandler = showInstructionBinaryHandler;
+
+ const highlightGapInstructionsInput: HTMLInputElement = view.divNode.querySelector("#highlight-gap-instructions");
+ const lastHighlightGapInstructions = window.sessionStorage.getItem("highlight-gap-instructions");
+ highlightGapInstructionsInput.checked = lastHighlightGapInstructions == 'true';
+ const highlightGapInstructionsHandler = () => {
+ window.sessionStorage.setItem("highlight-gap-instructions", `${highlightGapInstructionsInput.checked}`);
+ view.divNode.classList.toggle("highlight-gap-instructions", highlightGapInstructionsInput.checked);
+ };
+
+ highlightGapInstructionsInput.addEventListener("change", highlightGapInstructionsHandler);
+ this.highlightGapInstructionsHandler = highlightGapInstructionsHandler;
}
updateSelection(scrollIntoView: boolean = false) {
@@ -285,6 +324,7 @@ export class DisassemblyView extends TextView {
super.initializeContent(data, null);
this.showInstructionAddressHandler();
this.showInstructionBinaryHandler();
+ this.highlightGapInstructionsHandler();
console.timeEnd("disassembly-view");
}
diff --git a/deps/v8/tools/turbolizer/src/sequence-view.ts b/deps/v8/tools/turbolizer/src/sequence-view.ts
index e7691c688f..1319f3ae1e 100644
--- a/deps/v8/tools/turbolizer/src/sequence-view.ts
+++ b/deps/v8/tools/turbolizer/src/sequence-view.ts
@@ -98,8 +98,10 @@ export class SequenceView extends TextView {
const instNodeEl = createElement("div", "instruction-node");
const instId = createElement("div", "instruction-id", instruction.id);
+ const offsets = view.sourceResolver.instructionToPcOffsets(instruction.id);
instId.classList.add("clickable");
instId.dataset.instructionId = instruction.id;
+ instId.setAttribute("title", `This instruction generated gap code at pc-offset 0x${offsets.gap.toString(16)}, code at pc-offset 0x${offsets.arch.toString(16)}, condition handling at pc-offset 0x${offsets.condition.toString(16)}.`);
instNodeEl.appendChild(instId);
const instContentsEl = createElement("div", "instruction-contents");
diff --git a/deps/v8/tools/turbolizer/src/source-resolver.ts b/deps/v8/tools/turbolizer/src/source-resolver.ts
index 67f9c088a2..588eea5b99 100644
--- a/deps/v8/tools/turbolizer/src/source-resolver.ts
+++ b/deps/v8/tools/turbolizer/src/source-resolver.ts
@@ -83,6 +83,7 @@ interface InstructionsPhase {
instructionOffsetToPCOffset?: any;
blockIdtoInstructionRange?: any;
nodeIdToInstructionRange?: any;
+ codeOffsetsInfo?: CodeOffsetsInfo
}
interface GraphPhase {
@@ -103,6 +104,22 @@ export interface Sequence {
blocks: Array<any>;
}
+class CodeOffsetsInfo {
+ codeStartRegisterCheck: number;
+ deoptCheck: number;
+ initPoison: number;
+ blocksStart: number;
+ outOfLineCode: number;
+ deoptimizationExits: number;
+ pools: number;
+ jumpTables: number;
+}
+export class TurbolizerInstructionStartInfo {
+ gap: number;
+ arch: number;
+ condition: number;
+}
+
export class SourceResolver {
nodePositionMap: Array<AnyPosition>;
sources: Array<Source>;
@@ -115,9 +132,12 @@ export class SourceResolver {
lineToSourcePositions: Map<string, Array<AnyPosition>>;
nodeIdToInstructionRange: Array<[number, number]>;
blockIdToInstructionRange: Array<[number, number]>;
- instructionToPCOffset: Array<number>;
+ instructionToPCOffset: Array<TurbolizerInstructionStartInfo>;
pcOffsetToInstructions: Map<number, Array<number>>;
pcOffsets: Array<number>;
+ blockIdToPCOffset: Array<number>;
+ blockStartPCtoBlockIds: Map<number, Array<number>>;
+ codeOffsetsInfo: CodeOffsetsInfo;
constructor() {
// Maps node ids to source positions.
@@ -147,6 +167,17 @@ export class SourceResolver {
// Maps PC offsets to instructions.
this.pcOffsetToInstructions = new Map();
this.pcOffsets = [];
+ this.blockIdToPCOffset = [];
+ this.blockStartPCtoBlockIds = new Map();
+ this.codeOffsetsInfo = null;
+ }
+
+ getBlockIdsForOffset(offset): Array<number> {
+ return this.blockStartPCtoBlockIds.get(offset);
+ }
+
+ hasBlockStartInfo() {
+ return this.blockIdToPCOffset.length > 0;
}
setSources(sources, mainBackup) {
@@ -369,12 +400,18 @@ export class SourceResolver {
}
readInstructionOffsetToPCOffset(instructionToPCOffset) {
- for (const [instruction, offset] of Object.entries<number>(instructionToPCOffset)) {
- this.instructionToPCOffset[instruction] = offset;
- if (!this.pcOffsetToInstructions.has(offset)) {
- this.pcOffsetToInstructions.set(offset, []);
+ for (const [instruction, numberOrInfo] of Object.entries<number | TurbolizerInstructionStartInfo>(instructionToPCOffset)) {
+ let info: TurbolizerInstructionStartInfo;
+ if (typeof numberOrInfo == "number") {
+ info = { gap: numberOrInfo, arch: numberOrInfo, condition: numberOrInfo };
+ } else {
+ info = numberOrInfo;
+ }
+ this.instructionToPCOffset[instruction] = info;
+ if (!this.pcOffsetToInstructions.has(info.gap)) {
+ this.pcOffsetToInstructions.set(info.gap, []);
}
- this.pcOffsetToInstructions.get(offset).push(Number(instruction));
+ this.pcOffsetToInstructions.get(info.gap).push(Number(instruction));
}
this.pcOffsets = Array.from(this.pcOffsetToInstructions.keys()).sort((a, b) => b - a);
}
@@ -393,15 +430,67 @@ export class SourceResolver {
return -1;
}
- instructionRangeToKeyPcOffsets([start, end]: [number, number]) {
+ getInstructionKindForPCOffset(offset: number) {
+ if (this.codeOffsetsInfo) {
+ if (offset >= this.codeOffsetsInfo.deoptimizationExits) {
+ if (offset >= this.codeOffsetsInfo.pools) {
+ return "pools";
+ } else if (offset >= this.codeOffsetsInfo.jumpTables) {
+ return "jump-tables";
+ } else {
+ return "deoptimization-exits";
+ }
+ }
+ if (offset < this.codeOffsetsInfo.deoptCheck) {
+ return "code-start-register";
+ } else if (offset < this.codeOffsetsInfo.initPoison) {
+ return "deopt-check";
+ } else if (offset < this.codeOffsetsInfo.blocksStart) {
+ return "init-poison";
+ }
+ }
+ const keyOffset = this.getKeyPcOffset(offset);
+ if (keyOffset != -1) {
+ const infos = this.pcOffsetToInstructions.get(keyOffset).map(instrId => this.instructionToPCOffset[instrId]).filter(info => info.gap != info.condition);
+ if (infos.length > 0) {
+ const info = infos[0];
+ if (!info || info.gap == info.condition) return "unknown";
+ if (offset < info.arch) return "gap";
+ if (offset < info.condition) return "arch";
+ return "condition";
+ }
+ }
+ return "unknown";
+ }
+
+ instructionKindToReadableName(instructionKind) {
+ switch (instructionKind) {
+ case "code-start-register": return "Check code register for right value";
+ case "deopt-check": return "Check if function was marked for deoptimization";
+ case "init-poison": return "Initialization of poison register";
+ case "gap": return "Instruction implementing a gap move";
+ case "arch": return "Instruction implementing the actual machine operation";
+ case "condition": return "Code implementing conditional after instruction";
+ case "pools": return "Data in a pool (e.g. constant pool)";
+ case "jump-tables": return "Part of a jump table";
+ case "deoptimization-exits": return "Jump to deoptimization exit";
+ }
+ return null;
+ }
+
+ instructionRangeToKeyPcOffsets([start, end]: [number, number]): Array<TurbolizerInstructionStartInfo> {
if (start == end) return [this.instructionToPCOffset[start]];
return this.instructionToPCOffset.slice(start, end);
}
- instructionsToKeyPcOffsets(instructionIds: Iterable<number>) {
+ instructionToPcOffsets(instr: number): TurbolizerInstructionStartInfo {
+ return this.instructionToPCOffset[instr];
+ }
+
+ instructionsToKeyPcOffsets(instructionIds: Iterable<number>): Array<number> {
const keyPcOffsets = [];
for (const instructionId of instructionIds) {
- keyPcOffsets.push(this.instructionToPCOffset[instructionId]);
+ keyPcOffsets.push(this.instructionToPCOffset[instructionId].gap);
}
return keyPcOffsets;
}
@@ -447,6 +536,15 @@ export class SourceResolver {
switch (phase.type) {
case 'disassembly':
this.disassemblyPhase = phase;
+ if (phase['blockIdToOffset']) {
+ for (const [blockId, pc] of Object.entries<number>(phase['blockIdToOffset'])) {
+ this.blockIdToPCOffset[blockId] = pc;
+ if (!this.blockStartPCtoBlockIds.has(pc)) {
+ this.blockStartPCtoBlockIds.set(pc, []);
+ }
+ this.blockStartPCtoBlockIds.get(pc).push(Number(blockId));
+ }
+ }
break;
case 'schedule':
this.phaseNames.set(phase.name, this.phases.length);
@@ -466,6 +564,9 @@ export class SourceResolver {
if (phase.instructionOffsetToPCOffset) {
this.readInstructionOffsetToPCOffset(phase.instructionOffsetToPCOffset);
}
+ if (phase.codeOffsetsInfo) {
+ this.codeOffsetsInfo = phase.codeOffsetsInfo;
+ }
break;
case 'graph':
const graphPhase: GraphPhase = Object.assign(phase, { highestNodeId: 0 });
diff --git a/deps/v8/tools/turbolizer/src/text-view.ts b/deps/v8/tools/turbolizer/src/text-view.ts
index 41a06eae77..761a16bff4 100644
--- a/deps/v8/tools/turbolizer/src/text-view.ts
+++ b/deps/v8/tools/turbolizer/src/text-view.ts
@@ -129,6 +129,10 @@ export abstract class TextView extends PhaseView {
if (this.divNode.parentNode == null) return;
const mkVisible = new ViewElements(this.divNode.parentNode as HTMLElement);
const view = this;
+ const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset]`);
+ for (const el of elementsToSelect) {
+ el.classList.toggle("selected", false);
+ }
for (const [blockId, elements] of this.blockIdToHtmlElementsMap.entries()) {
const isSelected = view.blockSelection.isSelected(blockId);
for (const element of elements) {
@@ -136,10 +140,6 @@ export abstract class TextView extends PhaseView {
element.classList.toggle("selected", isSelected);
}
}
- const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset]`);
- for (const el of elementsToSelect) {
- el.classList.toggle("selected", false);
- }
for (const key of this.nodeIdToHtmlElementsMap.keys()) {
for (const element of this.nodeIdToHtmlElementsMap.get(key)) {
element.classList.toggle("selected", false);
@@ -170,7 +170,9 @@ export abstract class TextView extends PhaseView {
const fragment = document.createElement("SPAN");
if (typeof style.associateData == 'function') {
- style.associateData(text, fragment);
+ if (style.associateData(text, fragment) === false) {
+ return null;
+ }
} else {
if (style.css != undefined) {
const css = isIterable(style.css) ? style.css : [style.css];
@@ -198,7 +200,7 @@ export abstract class TextView extends PhaseView {
const text = matches[0];
if (text != '') {
const fragment = view.createFragment(matches[0], style);
- result.push(fragment);
+ if (fragment !== null) result.push(fragment);
}
line = line.substr(matches[0].length);
}
diff --git a/deps/v8/tools/turbolizer/turbo-visualizer.css b/deps/v8/tools/turbolizer/turbo-visualizer.css
index 216ca13d04..f89e716ce9 100644
--- a/deps/v8/tools/turbolizer/turbo-visualizer.css
+++ b/deps/v8/tools/turbolizer/turbo-visualizer.css
@@ -696,3 +696,61 @@ text {
padding-left: .5ex;
outline: 1px dotted grey;
}
+
+ul.disassembly-list .block-id {
+ width: 4ex;
+ display: block;
+ padding-top: 2px;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="gap"]+span+span {
+ background-color: #FAEEEE;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="arch"]+span+span {
+ background-color: #EEFFEE;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="condition"]+span+span {
+ background-color: #FFFFEE;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="gap"] {
+ background-color: #FAEEEE;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="arch"] {
+ background-color: #EEFFEE;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="condition"] {
+ background-color: #FFFFEE;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="deopt-check"] {
+ background-color: #FAEEFA;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="init-poison"] {
+ background-color: #EEFFAA;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="pools"] {
+ background-color: #6AA84F;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="code-start-register"] {
+ background-color: #FFCCCC;
+}
+
+div.highlight-gap-instructions [data-instruction-kind="deoptimization-exits"] {
+ background-color: #CCCCFF;
+}
+
+[data-instruction-kind].selected {
+ background-color: yellow;
+}
+
+div.highlight-gap-instructions [data-instruction-kind].selected {
+ background-color: yellow;
+}
diff --git a/deps/v8/tools/v8heapconst.py b/deps/v8/tools/v8heapconst.py
index c6c98c04c3..53aaaf74df 100644
--- a/deps/v8/tools/v8heapconst.py
+++ b/deps/v8/tools/v8heapconst.py
@@ -31,107 +31,105 @@ INSTANCE_TYPES = {
67: "ODDBALL_TYPE",
68: "MAP_TYPE",
69: "CODE_TYPE",
- 70: "MUTABLE_HEAP_NUMBER_TYPE",
- 71: "FOREIGN_TYPE",
- 72: "BYTE_ARRAY_TYPE",
- 73: "BYTECODE_ARRAY_TYPE",
- 74: "FREE_SPACE_TYPE",
- 75: "FIXED_DOUBLE_ARRAY_TYPE",
- 76: "FEEDBACK_METADATA_TYPE",
- 77: "FILLER_TYPE",
- 78: "ACCESS_CHECK_INFO_TYPE",
- 79: "ACCESSOR_INFO_TYPE",
- 80: "ACCESSOR_PAIR_TYPE",
- 81: "ALIASED_ARGUMENTS_ENTRY_TYPE",
- 82: "ALLOCATION_MEMENTO_TYPE",
- 83: "ARRAY_BOILERPLATE_DESCRIPTION_TYPE",
- 84: "ASM_WASM_DATA_TYPE",
- 85: "ASYNC_GENERATOR_REQUEST_TYPE",
- 86: "CLASS_POSITIONS_TYPE",
- 87: "DEBUG_INFO_TYPE",
- 88: "ENUM_CACHE_TYPE",
- 89: "FUNCTION_TEMPLATE_INFO_TYPE",
- 90: "FUNCTION_TEMPLATE_RARE_DATA_TYPE",
- 91: "INTERCEPTOR_INFO_TYPE",
- 92: "INTERPRETER_DATA_TYPE",
- 93: "OBJECT_TEMPLATE_INFO_TYPE",
- 94: "PROMISE_CAPABILITY_TYPE",
- 95: "PROMISE_REACTION_TYPE",
- 96: "PROTOTYPE_INFO_TYPE",
- 97: "SCRIPT_TYPE",
- 98: "SOURCE_POSITION_TABLE_WITH_FRAME_CACHE_TYPE",
- 99: "SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE",
- 100: "STACK_FRAME_INFO_TYPE",
- 101: "STACK_TRACE_FRAME_TYPE",
- 102: "TEMPLATE_OBJECT_DESCRIPTION_TYPE",
- 103: "TUPLE2_TYPE",
- 104: "TUPLE3_TYPE",
- 105: "WASM_CAPI_FUNCTION_DATA_TYPE",
- 106: "WASM_DEBUG_INFO_TYPE",
- 107: "WASM_EXCEPTION_TAG_TYPE",
- 108: "WASM_EXPORTED_FUNCTION_DATA_TYPE",
- 109: "WASM_INDIRECT_FUNCTION_TABLE_TYPE",
- 110: "WASM_JS_FUNCTION_DATA_TYPE",
- 111: "CALLABLE_TASK_TYPE",
- 112: "CALLBACK_TASK_TYPE",
- 113: "PROMISE_FULFILL_REACTION_JOB_TASK_TYPE",
- 114: "PROMISE_REJECT_REACTION_JOB_TASK_TYPE",
- 115: "PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE",
- 116: "FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE",
- 117: "INTERNAL_CLASS_TYPE",
- 118: "SMI_PAIR_TYPE",
- 119: "SMI_BOX_TYPE",
- 120: "SORT_STATE_TYPE",
- 121: "SOURCE_TEXT_MODULE_TYPE",
- 122: "SYNTHETIC_MODULE_TYPE",
- 123: "ALLOCATION_SITE_TYPE",
- 124: "EMBEDDER_DATA_ARRAY_TYPE",
- 125: "FIXED_ARRAY_TYPE",
- 126: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE",
- 127: "CLOSURE_FEEDBACK_CELL_ARRAY_TYPE",
- 128: "HASH_TABLE_TYPE",
- 129: "ORDERED_HASH_MAP_TYPE",
- 130: "ORDERED_HASH_SET_TYPE",
- 131: "ORDERED_NAME_DICTIONARY_TYPE",
- 132: "NAME_DICTIONARY_TYPE",
- 133: "GLOBAL_DICTIONARY_TYPE",
- 134: "NUMBER_DICTIONARY_TYPE",
- 135: "SIMPLE_NUMBER_DICTIONARY_TYPE",
- 136: "STRING_TABLE_TYPE",
- 137: "EPHEMERON_HASH_TABLE_TYPE",
- 138: "SCOPE_INFO_TYPE",
- 139: "SCRIPT_CONTEXT_TABLE_TYPE",
- 140: "AWAIT_CONTEXT_TYPE",
- 141: "BLOCK_CONTEXT_TYPE",
- 142: "CATCH_CONTEXT_TYPE",
- 143: "DEBUG_EVALUATE_CONTEXT_TYPE",
- 144: "EVAL_CONTEXT_TYPE",
- 145: "FUNCTION_CONTEXT_TYPE",
- 146: "MODULE_CONTEXT_TYPE",
- 147: "NATIVE_CONTEXT_TYPE",
- 148: "SCRIPT_CONTEXT_TYPE",
- 149: "WITH_CONTEXT_TYPE",
- 150: "WEAK_FIXED_ARRAY_TYPE",
- 151: "TRANSITION_ARRAY_TYPE",
- 152: "CALL_HANDLER_INFO_TYPE",
- 153: "CELL_TYPE",
- 154: "CODE_DATA_CONTAINER_TYPE",
- 155: "DESCRIPTOR_ARRAY_TYPE",
- 156: "FEEDBACK_CELL_TYPE",
- 157: "FEEDBACK_VECTOR_TYPE",
- 158: "LOAD_HANDLER_TYPE",
- 159: "PREPARSE_DATA_TYPE",
- 160: "PROPERTY_ARRAY_TYPE",
- 161: "PROPERTY_CELL_TYPE",
- 162: "SHARED_FUNCTION_INFO_TYPE",
- 163: "SMALL_ORDERED_HASH_MAP_TYPE",
- 164: "SMALL_ORDERED_HASH_SET_TYPE",
- 165: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
- 166: "STORE_HANDLER_TYPE",
- 167: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE",
- 168: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE",
- 169: "WEAK_ARRAY_LIST_TYPE",
- 170: "WEAK_CELL_TYPE",
+ 70: "FOREIGN_TYPE",
+ 71: "BYTE_ARRAY_TYPE",
+ 72: "BYTECODE_ARRAY_TYPE",
+ 73: "FREE_SPACE_TYPE",
+ 74: "FIXED_DOUBLE_ARRAY_TYPE",
+ 75: "FEEDBACK_METADATA_TYPE",
+ 76: "FILLER_TYPE",
+ 77: "ACCESS_CHECK_INFO_TYPE",
+ 78: "ACCESSOR_INFO_TYPE",
+ 79: "ACCESSOR_PAIR_TYPE",
+ 80: "ALIASED_ARGUMENTS_ENTRY_TYPE",
+ 81: "ALLOCATION_MEMENTO_TYPE",
+ 82: "ARRAY_BOILERPLATE_DESCRIPTION_TYPE",
+ 83: "ASM_WASM_DATA_TYPE",
+ 84: "ASYNC_GENERATOR_REQUEST_TYPE",
+ 85: "CLASS_POSITIONS_TYPE",
+ 86: "DEBUG_INFO_TYPE",
+ 87: "ENUM_CACHE_TYPE",
+ 88: "FUNCTION_TEMPLATE_INFO_TYPE",
+ 89: "FUNCTION_TEMPLATE_RARE_DATA_TYPE",
+ 90: "INTERCEPTOR_INFO_TYPE",
+ 91: "INTERPRETER_DATA_TYPE",
+ 92: "OBJECT_TEMPLATE_INFO_TYPE",
+ 93: "PROMISE_CAPABILITY_TYPE",
+ 94: "PROMISE_REACTION_TYPE",
+ 95: "PROTOTYPE_INFO_TYPE",
+ 96: "SCRIPT_TYPE",
+ 97: "SOURCE_POSITION_TABLE_WITH_FRAME_CACHE_TYPE",
+ 98: "SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE",
+ 99: "STACK_FRAME_INFO_TYPE",
+ 100: "STACK_TRACE_FRAME_TYPE",
+ 101: "TEMPLATE_OBJECT_DESCRIPTION_TYPE",
+ 102: "TUPLE2_TYPE",
+ 103: "TUPLE3_TYPE",
+ 104: "WASM_CAPI_FUNCTION_DATA_TYPE",
+ 105: "WASM_DEBUG_INFO_TYPE",
+ 106: "WASM_EXCEPTION_TAG_TYPE",
+ 107: "WASM_EXPORTED_FUNCTION_DATA_TYPE",
+ 108: "WASM_INDIRECT_FUNCTION_TABLE_TYPE",
+ 109: "WASM_JS_FUNCTION_DATA_TYPE",
+ 110: "CALLABLE_TASK_TYPE",
+ 111: "CALLBACK_TASK_TYPE",
+ 112: "PROMISE_FULFILL_REACTION_JOB_TASK_TYPE",
+ 113: "PROMISE_REJECT_REACTION_JOB_TASK_TYPE",
+ 114: "PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE",
+ 115: "INTERNAL_CLASS_TYPE",
+ 116: "SMI_PAIR_TYPE",
+ 117: "SMI_BOX_TYPE",
+ 118: "SORT_STATE_TYPE",
+ 119: "SOURCE_TEXT_MODULE_TYPE",
+ 120: "SYNTHETIC_MODULE_TYPE",
+ 121: "ALLOCATION_SITE_TYPE",
+ 122: "EMBEDDER_DATA_ARRAY_TYPE",
+ 123: "FIXED_ARRAY_TYPE",
+ 124: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE",
+ 125: "CLOSURE_FEEDBACK_CELL_ARRAY_TYPE",
+ 126: "HASH_TABLE_TYPE",
+ 127: "ORDERED_HASH_MAP_TYPE",
+ 128: "ORDERED_HASH_SET_TYPE",
+ 129: "ORDERED_NAME_DICTIONARY_TYPE",
+ 130: "NAME_DICTIONARY_TYPE",
+ 131: "GLOBAL_DICTIONARY_TYPE",
+ 132: "NUMBER_DICTIONARY_TYPE",
+ 133: "SIMPLE_NUMBER_DICTIONARY_TYPE",
+ 134: "STRING_TABLE_TYPE",
+ 135: "EPHEMERON_HASH_TABLE_TYPE",
+ 136: "SCOPE_INFO_TYPE",
+ 137: "SCRIPT_CONTEXT_TABLE_TYPE",
+ 138: "AWAIT_CONTEXT_TYPE",
+ 139: "BLOCK_CONTEXT_TYPE",
+ 140: "CATCH_CONTEXT_TYPE",
+ 141: "DEBUG_EVALUATE_CONTEXT_TYPE",
+ 142: "EVAL_CONTEXT_TYPE",
+ 143: "FUNCTION_CONTEXT_TYPE",
+ 144: "MODULE_CONTEXT_TYPE",
+ 145: "NATIVE_CONTEXT_TYPE",
+ 146: "SCRIPT_CONTEXT_TYPE",
+ 147: "WITH_CONTEXT_TYPE",
+ 148: "WEAK_FIXED_ARRAY_TYPE",
+ 149: "TRANSITION_ARRAY_TYPE",
+ 150: "CALL_HANDLER_INFO_TYPE",
+ 151: "CELL_TYPE",
+ 152: "CODE_DATA_CONTAINER_TYPE",
+ 153: "DESCRIPTOR_ARRAY_TYPE",
+ 154: "FEEDBACK_CELL_TYPE",
+ 155: "FEEDBACK_VECTOR_TYPE",
+ 156: "LOAD_HANDLER_TYPE",
+ 157: "PREPARSE_DATA_TYPE",
+ 158: "PROPERTY_ARRAY_TYPE",
+ 159: "PROPERTY_CELL_TYPE",
+ 160: "SHARED_FUNCTION_INFO_TYPE",
+ 161: "SMALL_ORDERED_HASH_MAP_TYPE",
+ 162: "SMALL_ORDERED_HASH_SET_TYPE",
+ 163: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
+ 164: "STORE_HANDLER_TYPE",
+ 165: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE",
+ 166: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE",
+ 167: "WEAK_ARRAY_LIST_TYPE",
+ 168: "WEAK_CELL_TYPE",
1024: "JS_PROXY_TYPE",
1025: "JS_GLOBAL_OBJECT_TYPE",
1026: "JS_GLOBAL_PROXY_TYPE",
@@ -192,237 +190,237 @@ INSTANCE_TYPES = {
# List of known V8 maps.
KNOWN_MAPS = {
- ("read_only_space", 0x00111): (74, "FreeSpaceMap"),
- ("read_only_space", 0x00161): (68, "MetaMap"),
- ("read_only_space", 0x001e1): (67, "NullMap"),
- ("read_only_space", 0x00249): (155, "DescriptorArrayMap"),
- ("read_only_space", 0x002a9): (150, "WeakFixedArrayMap"),
- ("read_only_space", 0x002f9): (77, "OnePointerFillerMap"),
- ("read_only_space", 0x00349): (77, "TwoPointerFillerMap"),
- ("read_only_space", 0x003c9): (67, "UninitializedMap"),
- ("read_only_space", 0x00439): (8, "OneByteInternalizedStringMap"),
- ("read_only_space", 0x004d9): (67, "UndefinedMap"),
- ("read_only_space", 0x00539): (65, "HeapNumberMap"),
- ("read_only_space", 0x005b9): (67, "TheHoleMap"),
- ("read_only_space", 0x00661): (67, "BooleanMap"),
- ("read_only_space", 0x00739): (72, "ByteArrayMap"),
- ("read_only_space", 0x00789): (125, "FixedArrayMap"),
- ("read_only_space", 0x007d9): (125, "FixedCOWArrayMap"),
- ("read_only_space", 0x00829): (128, "HashTableMap"),
- ("read_only_space", 0x00879): (64, "SymbolMap"),
- ("read_only_space", 0x008c9): (40, "OneByteStringMap"),
- ("read_only_space", 0x00919): (138, "ScopeInfoMap"),
- ("read_only_space", 0x00969): (162, "SharedFunctionInfoMap"),
- ("read_only_space", 0x009b9): (69, "CodeMap"),
- ("read_only_space", 0x00a09): (145, "FunctionContextMap"),
- ("read_only_space", 0x00a59): (153, "CellMap"),
- ("read_only_space", 0x00aa9): (161, "GlobalPropertyCellMap"),
- ("read_only_space", 0x00af9): (71, "ForeignMap"),
- ("read_only_space", 0x00b49): (151, "TransitionArrayMap"),
- ("read_only_space", 0x00b99): (157, "FeedbackVectorMap"),
- ("read_only_space", 0x00c39): (67, "ArgumentsMarkerMap"),
- ("read_only_space", 0x00cd9): (67, "ExceptionMap"),
- ("read_only_space", 0x00d79): (67, "TerminationExceptionMap"),
- ("read_only_space", 0x00e21): (67, "OptimizedOutMap"),
- ("read_only_space", 0x00ec1): (67, "StaleRegisterMap"),
- ("read_only_space", 0x00f31): (147, "NativeContextMap"),
- ("read_only_space", 0x00f81): (146, "ModuleContextMap"),
- ("read_only_space", 0x00fd1): (144, "EvalContextMap"),
- ("read_only_space", 0x01021): (148, "ScriptContextMap"),
- ("read_only_space", 0x01071): (140, "AwaitContextMap"),
- ("read_only_space", 0x010c1): (141, "BlockContextMap"),
- ("read_only_space", 0x01111): (142, "CatchContextMap"),
- ("read_only_space", 0x01161): (149, "WithContextMap"),
- ("read_only_space", 0x011b1): (143, "DebugEvaluateContextMap"),
- ("read_only_space", 0x01201): (139, "ScriptContextTableMap"),
- ("read_only_space", 0x01251): (127, "ClosureFeedbackCellArrayMap"),
- ("read_only_space", 0x012a1): (76, "FeedbackMetadataArrayMap"),
- ("read_only_space", 0x012f1): (125, "ArrayListMap"),
- ("read_only_space", 0x01341): (66, "BigIntMap"),
- ("read_only_space", 0x01391): (126, "ObjectBoilerplateDescriptionMap"),
- ("read_only_space", 0x013e1): (73, "BytecodeArrayMap"),
- ("read_only_space", 0x01431): (154, "CodeDataContainerMap"),
- ("read_only_space", 0x01481): (75, "FixedDoubleArrayMap"),
- ("read_only_space", 0x014d1): (133, "GlobalDictionaryMap"),
- ("read_only_space", 0x01521): (156, "ManyClosuresCellMap"),
- ("read_only_space", 0x01571): (125, "ModuleInfoMap"),
- ("read_only_space", 0x015c1): (70, "MutableHeapNumberMap"),
- ("read_only_space", 0x01611): (132, "NameDictionaryMap"),
- ("read_only_space", 0x01661): (156, "NoClosuresCellMap"),
- ("read_only_space", 0x016b1): (134, "NumberDictionaryMap"),
- ("read_only_space", 0x01701): (156, "OneClosureCellMap"),
- ("read_only_space", 0x01751): (129, "OrderedHashMapMap"),
- ("read_only_space", 0x017a1): (130, "OrderedHashSetMap"),
- ("read_only_space", 0x017f1): (131, "OrderedNameDictionaryMap"),
- ("read_only_space", 0x01841): (159, "PreparseDataMap"),
- ("read_only_space", 0x01891): (160, "PropertyArrayMap"),
- ("read_only_space", 0x018e1): (152, "SideEffectCallHandlerInfoMap"),
- ("read_only_space", 0x01931): (152, "SideEffectFreeCallHandlerInfoMap"),
- ("read_only_space", 0x01981): (152, "NextCallSideEffectFreeCallHandlerInfoMap"),
- ("read_only_space", 0x019d1): (135, "SimpleNumberDictionaryMap"),
- ("read_only_space", 0x01a21): (125, "SloppyArgumentsElementsMap"),
- ("read_only_space", 0x01a71): (163, "SmallOrderedHashMapMap"),
- ("read_only_space", 0x01ac1): (164, "SmallOrderedHashSetMap"),
- ("read_only_space", 0x01b11): (165, "SmallOrderedNameDictionaryMap"),
- ("read_only_space", 0x01b61): (121, "SourceTextModuleMap"),
- ("read_only_space", 0x01bb1): (136, "StringTableMap"),
- ("read_only_space", 0x01c01): (122, "SyntheticModuleMap"),
- ("read_only_space", 0x01c51): (167, "UncompiledDataWithoutPreparseDataMap"),
- ("read_only_space", 0x01ca1): (168, "UncompiledDataWithPreparseDataMap"),
- ("read_only_space", 0x01cf1): (169, "WeakArrayListMap"),
- ("read_only_space", 0x01d41): (137, "EphemeronHashTableMap"),
- ("read_only_space", 0x01d91): (124, "EmbedderDataArrayMap"),
- ("read_only_space", 0x01de1): (170, "WeakCellMap"),
- ("read_only_space", 0x01e31): (58, "NativeSourceStringMap"),
- ("read_only_space", 0x01e81): (32, "StringMap"),
- ("read_only_space", 0x01ed1): (41, "ConsOneByteStringMap"),
- ("read_only_space", 0x01f21): (33, "ConsStringMap"),
- ("read_only_space", 0x01f71): (45, "ThinOneByteStringMap"),
- ("read_only_space", 0x01fc1): (37, "ThinStringMap"),
- ("read_only_space", 0x02011): (35, "SlicedStringMap"),
- ("read_only_space", 0x02061): (43, "SlicedOneByteStringMap"),
- ("read_only_space", 0x020b1): (34, "ExternalStringMap"),
- ("read_only_space", 0x02101): (42, "ExternalOneByteStringMap"),
- ("read_only_space", 0x02151): (50, "UncachedExternalStringMap"),
- ("read_only_space", 0x021a1): (0, "InternalizedStringMap"),
- ("read_only_space", 0x021f1): (2, "ExternalInternalizedStringMap"),
- ("read_only_space", 0x02241): (10, "ExternalOneByteInternalizedStringMap"),
- ("read_only_space", 0x02291): (18, "UncachedExternalInternalizedStringMap"),
- ("read_only_space", 0x022e1): (26, "UncachedExternalOneByteInternalizedStringMap"),
- ("read_only_space", 0x02331): (58, "UncachedExternalOneByteStringMap"),
- ("read_only_space", 0x02381): (67, "SelfReferenceMarkerMap"),
- ("read_only_space", 0x023e9): (88, "EnumCacheMap"),
- ("read_only_space", 0x02489): (83, "ArrayBoilerplateDescriptionMap"),
- ("read_only_space", 0x02679): (91, "InterceptorInfoMap"),
- ("read_only_space", 0x04e59): (78, "AccessCheckInfoMap"),
- ("read_only_space", 0x04ea9): (79, "AccessorInfoMap"),
- ("read_only_space", 0x04ef9): (80, "AccessorPairMap"),
- ("read_only_space", 0x04f49): (81, "AliasedArgumentsEntryMap"),
- ("read_only_space", 0x04f99): (82, "AllocationMementoMap"),
- ("read_only_space", 0x04fe9): (84, "AsmWasmDataMap"),
- ("read_only_space", 0x05039): (85, "AsyncGeneratorRequestMap"),
- ("read_only_space", 0x05089): (86, "ClassPositionsMap"),
- ("read_only_space", 0x050d9): (87, "DebugInfoMap"),
- ("read_only_space", 0x05129): (89, "FunctionTemplateInfoMap"),
- ("read_only_space", 0x05179): (90, "FunctionTemplateRareDataMap"),
- ("read_only_space", 0x051c9): (92, "InterpreterDataMap"),
- ("read_only_space", 0x05219): (93, "ObjectTemplateInfoMap"),
- ("read_only_space", 0x05269): (94, "PromiseCapabilityMap"),
- ("read_only_space", 0x052b9): (95, "PromiseReactionMap"),
- ("read_only_space", 0x05309): (96, "PrototypeInfoMap"),
- ("read_only_space", 0x05359): (97, "ScriptMap"),
- ("read_only_space", 0x053a9): (98, "SourcePositionTableWithFrameCacheMap"),
- ("read_only_space", 0x053f9): (99, "SourceTextModuleInfoEntryMap"),
- ("read_only_space", 0x05449): (100, "StackFrameInfoMap"),
- ("read_only_space", 0x05499): (101, "StackTraceFrameMap"),
- ("read_only_space", 0x054e9): (102, "TemplateObjectDescriptionMap"),
- ("read_only_space", 0x05539): (103, "Tuple2Map"),
- ("read_only_space", 0x05589): (104, "Tuple3Map"),
- ("read_only_space", 0x055d9): (105, "WasmCapiFunctionDataMap"),
- ("read_only_space", 0x05629): (106, "WasmDebugInfoMap"),
- ("read_only_space", 0x05679): (107, "WasmExceptionTagMap"),
- ("read_only_space", 0x056c9): (108, "WasmExportedFunctionDataMap"),
- ("read_only_space", 0x05719): (109, "WasmIndirectFunctionTableMap"),
- ("read_only_space", 0x05769): (110, "WasmJSFunctionDataMap"),
- ("read_only_space", 0x057b9): (111, "CallableTaskMap"),
- ("read_only_space", 0x05809): (112, "CallbackTaskMap"),
- ("read_only_space", 0x05859): (113, "PromiseFulfillReactionJobTaskMap"),
- ("read_only_space", 0x058a9): (114, "PromiseRejectReactionJobTaskMap"),
- ("read_only_space", 0x058f9): (115, "PromiseResolveThenableJobTaskMap"),
- ("read_only_space", 0x05949): (116, "FinalizationGroupCleanupJobTaskMap"),
- ("read_only_space", 0x05999): (117, "InternalClassMap"),
- ("read_only_space", 0x059e9): (118, "SmiPairMap"),
- ("read_only_space", 0x05a39): (119, "SmiBoxMap"),
- ("read_only_space", 0x05a89): (120, "SortStateMap"),
- ("read_only_space", 0x05ad9): (123, "AllocationSiteWithWeakNextMap"),
- ("read_only_space", 0x05b29): (123, "AllocationSiteWithoutWeakNextMap"),
- ("read_only_space", 0x05b79): (158, "LoadHandler1Map"),
- ("read_only_space", 0x05bc9): (158, "LoadHandler2Map"),
- ("read_only_space", 0x05c19): (158, "LoadHandler3Map"),
- ("read_only_space", 0x05c69): (166, "StoreHandler0Map"),
- ("read_only_space", 0x05cb9): (166, "StoreHandler1Map"),
- ("read_only_space", 0x05d09): (166, "StoreHandler2Map"),
- ("read_only_space", 0x05d59): (166, "StoreHandler3Map"),
- ("map_space", 0x00111): (1057, "ExternalMap"),
- ("map_space", 0x00161): (1073, "JSMessageObjectMap"),
+ ("read_only_space", 0x00119): (73, "FreeSpaceMap"),
+ ("read_only_space", 0x00169): (68, "MetaMap"),
+ ("read_only_space", 0x001e9): (67, "NullMap"),
+ ("read_only_space", 0x00251): (153, "DescriptorArrayMap"),
+ ("read_only_space", 0x002b1): (148, "WeakFixedArrayMap"),
+ ("read_only_space", 0x00301): (76, "OnePointerFillerMap"),
+ ("read_only_space", 0x00351): (76, "TwoPointerFillerMap"),
+ ("read_only_space", 0x003d1): (67, "UninitializedMap"),
+ ("read_only_space", 0x00441): (8, "OneByteInternalizedStringMap"),
+ ("read_only_space", 0x004e1): (67, "UndefinedMap"),
+ ("read_only_space", 0x00541): (65, "HeapNumberMap"),
+ ("read_only_space", 0x005c1): (67, "TheHoleMap"),
+ ("read_only_space", 0x00669): (67, "BooleanMap"),
+ ("read_only_space", 0x00741): (71, "ByteArrayMap"),
+ ("read_only_space", 0x00791): (123, "FixedArrayMap"),
+ ("read_only_space", 0x007e1): (123, "FixedCOWArrayMap"),
+ ("read_only_space", 0x00831): (126, "HashTableMap"),
+ ("read_only_space", 0x00881): (64, "SymbolMap"),
+ ("read_only_space", 0x008d1): (40, "OneByteStringMap"),
+ ("read_only_space", 0x00921): (136, "ScopeInfoMap"),
+ ("read_only_space", 0x00971): (160, "SharedFunctionInfoMap"),
+ ("read_only_space", 0x009c1): (69, "CodeMap"),
+ ("read_only_space", 0x00a11): (143, "FunctionContextMap"),
+ ("read_only_space", 0x00a61): (151, "CellMap"),
+ ("read_only_space", 0x00ab1): (159, "GlobalPropertyCellMap"),
+ ("read_only_space", 0x00b01): (70, "ForeignMap"),
+ ("read_only_space", 0x00b51): (149, "TransitionArrayMap"),
+ ("read_only_space", 0x00ba1): (155, "FeedbackVectorMap"),
+ ("read_only_space", 0x00c41): (67, "ArgumentsMarkerMap"),
+ ("read_only_space", 0x00ce1): (67, "ExceptionMap"),
+ ("read_only_space", 0x00d81): (67, "TerminationExceptionMap"),
+ ("read_only_space", 0x00e29): (67, "OptimizedOutMap"),
+ ("read_only_space", 0x00ec9): (67, "StaleRegisterMap"),
+ ("read_only_space", 0x00f39): (145, "NativeContextMap"),
+ ("read_only_space", 0x00f89): (144, "ModuleContextMap"),
+ ("read_only_space", 0x00fd9): (142, "EvalContextMap"),
+ ("read_only_space", 0x01029): (146, "ScriptContextMap"),
+ ("read_only_space", 0x01079): (138, "AwaitContextMap"),
+ ("read_only_space", 0x010c9): (139, "BlockContextMap"),
+ ("read_only_space", 0x01119): (140, "CatchContextMap"),
+ ("read_only_space", 0x01169): (147, "WithContextMap"),
+ ("read_only_space", 0x011b9): (141, "DebugEvaluateContextMap"),
+ ("read_only_space", 0x01209): (137, "ScriptContextTableMap"),
+ ("read_only_space", 0x01259): (125, "ClosureFeedbackCellArrayMap"),
+ ("read_only_space", 0x012a9): (75, "FeedbackMetadataArrayMap"),
+ ("read_only_space", 0x012f9): (123, "ArrayListMap"),
+ ("read_only_space", 0x01349): (66, "BigIntMap"),
+ ("read_only_space", 0x01399): (124, "ObjectBoilerplateDescriptionMap"),
+ ("read_only_space", 0x013e9): (72, "BytecodeArrayMap"),
+ ("read_only_space", 0x01439): (152, "CodeDataContainerMap"),
+ ("read_only_space", 0x01489): (74, "FixedDoubleArrayMap"),
+ ("read_only_space", 0x014d9): (131, "GlobalDictionaryMap"),
+ ("read_only_space", 0x01529): (154, "ManyClosuresCellMap"),
+ ("read_only_space", 0x01579): (123, "ModuleInfoMap"),
+ ("read_only_space", 0x015c9): (130, "NameDictionaryMap"),
+ ("read_only_space", 0x01619): (154, "NoClosuresCellMap"),
+ ("read_only_space", 0x01669): (132, "NumberDictionaryMap"),
+ ("read_only_space", 0x016b9): (154, "OneClosureCellMap"),
+ ("read_only_space", 0x01709): (127, "OrderedHashMapMap"),
+ ("read_only_space", 0x01759): (128, "OrderedHashSetMap"),
+ ("read_only_space", 0x017a9): (129, "OrderedNameDictionaryMap"),
+ ("read_only_space", 0x017f9): (157, "PreparseDataMap"),
+ ("read_only_space", 0x01849): (158, "PropertyArrayMap"),
+ ("read_only_space", 0x01899): (150, "SideEffectCallHandlerInfoMap"),
+ ("read_only_space", 0x018e9): (150, "SideEffectFreeCallHandlerInfoMap"),
+ ("read_only_space", 0x01939): (150, "NextCallSideEffectFreeCallHandlerInfoMap"),
+ ("read_only_space", 0x01989): (133, "SimpleNumberDictionaryMap"),
+ ("read_only_space", 0x019d9): (123, "SloppyArgumentsElementsMap"),
+ ("read_only_space", 0x01a29): (161, "SmallOrderedHashMapMap"),
+ ("read_only_space", 0x01a79): (162, "SmallOrderedHashSetMap"),
+ ("read_only_space", 0x01ac9): (163, "SmallOrderedNameDictionaryMap"),
+ ("read_only_space", 0x01b19): (119, "SourceTextModuleMap"),
+ ("read_only_space", 0x01b69): (134, "StringTableMap"),
+ ("read_only_space", 0x01bb9): (120, "SyntheticModuleMap"),
+ ("read_only_space", 0x01c09): (165, "UncompiledDataWithoutPreparseDataMap"),
+ ("read_only_space", 0x01c59): (166, "UncompiledDataWithPreparseDataMap"),
+ ("read_only_space", 0x01ca9): (167, "WeakArrayListMap"),
+ ("read_only_space", 0x01cf9): (135, "EphemeronHashTableMap"),
+ ("read_only_space", 0x01d49): (122, "EmbedderDataArrayMap"),
+ ("read_only_space", 0x01d99): (168, "WeakCellMap"),
+ ("read_only_space", 0x01de9): (58, "NativeSourceStringMap"),
+ ("read_only_space", 0x01e39): (32, "StringMap"),
+ ("read_only_space", 0x01e89): (41, "ConsOneByteStringMap"),
+ ("read_only_space", 0x01ed9): (33, "ConsStringMap"),
+ ("read_only_space", 0x01f29): (45, "ThinOneByteStringMap"),
+ ("read_only_space", 0x01f79): (37, "ThinStringMap"),
+ ("read_only_space", 0x01fc9): (35, "SlicedStringMap"),
+ ("read_only_space", 0x02019): (43, "SlicedOneByteStringMap"),
+ ("read_only_space", 0x02069): (34, "ExternalStringMap"),
+ ("read_only_space", 0x020b9): (42, "ExternalOneByteStringMap"),
+ ("read_only_space", 0x02109): (50, "UncachedExternalStringMap"),
+ ("read_only_space", 0x02159): (0, "InternalizedStringMap"),
+ ("read_only_space", 0x021a9): (2, "ExternalInternalizedStringMap"),
+ ("read_only_space", 0x021f9): (10, "ExternalOneByteInternalizedStringMap"),
+ ("read_only_space", 0x02249): (18, "UncachedExternalInternalizedStringMap"),
+ ("read_only_space", 0x02299): (26, "UncachedExternalOneByteInternalizedStringMap"),
+ ("read_only_space", 0x022e9): (58, "UncachedExternalOneByteStringMap"),
+ ("read_only_space", 0x02339): (67, "SelfReferenceMarkerMap"),
+ ("read_only_space", 0x023a1): (87, "EnumCacheMap"),
+ ("read_only_space", 0x02441): (82, "ArrayBoilerplateDescriptionMap"),
+ ("read_only_space", 0x02631): (90, "InterceptorInfoMap"),
+ ("read_only_space", 0x04eb1): (77, "AccessCheckInfoMap"),
+ ("read_only_space", 0x04f01): (78, "AccessorInfoMap"),
+ ("read_only_space", 0x04f51): (79, "AccessorPairMap"),
+ ("read_only_space", 0x04fa1): (80, "AliasedArgumentsEntryMap"),
+ ("read_only_space", 0x04ff1): (81, "AllocationMementoMap"),
+ ("read_only_space", 0x05041): (83, "AsmWasmDataMap"),
+ ("read_only_space", 0x05091): (84, "AsyncGeneratorRequestMap"),
+ ("read_only_space", 0x050e1): (85, "ClassPositionsMap"),
+ ("read_only_space", 0x05131): (86, "DebugInfoMap"),
+ ("read_only_space", 0x05181): (88, "FunctionTemplateInfoMap"),
+ ("read_only_space", 0x051d1): (89, "FunctionTemplateRareDataMap"),
+ ("read_only_space", 0x05221): (91, "InterpreterDataMap"),
+ ("read_only_space", 0x05271): (92, "ObjectTemplateInfoMap"),
+ ("read_only_space", 0x052c1): (93, "PromiseCapabilityMap"),
+ ("read_only_space", 0x05311): (94, "PromiseReactionMap"),
+ ("read_only_space", 0x05361): (95, "PrototypeInfoMap"),
+ ("read_only_space", 0x053b1): (96, "ScriptMap"),
+ ("read_only_space", 0x05401): (97, "SourcePositionTableWithFrameCacheMap"),
+ ("read_only_space", 0x05451): (98, "SourceTextModuleInfoEntryMap"),
+ ("read_only_space", 0x054a1): (99, "StackFrameInfoMap"),
+ ("read_only_space", 0x054f1): (100, "StackTraceFrameMap"),
+ ("read_only_space", 0x05541): (101, "TemplateObjectDescriptionMap"),
+ ("read_only_space", 0x05591): (102, "Tuple2Map"),
+ ("read_only_space", 0x055e1): (103, "Tuple3Map"),
+ ("read_only_space", 0x05631): (104, "WasmCapiFunctionDataMap"),
+ ("read_only_space", 0x05681): (105, "WasmDebugInfoMap"),
+ ("read_only_space", 0x056d1): (106, "WasmExceptionTagMap"),
+ ("read_only_space", 0x05721): (107, "WasmExportedFunctionDataMap"),
+ ("read_only_space", 0x05771): (108, "WasmIndirectFunctionTableMap"),
+ ("read_only_space", 0x057c1): (109, "WasmJSFunctionDataMap"),
+ ("read_only_space", 0x05811): (110, "CallableTaskMap"),
+ ("read_only_space", 0x05861): (111, "CallbackTaskMap"),
+ ("read_only_space", 0x058b1): (112, "PromiseFulfillReactionJobTaskMap"),
+ ("read_only_space", 0x05901): (113, "PromiseRejectReactionJobTaskMap"),
+ ("read_only_space", 0x05951): (114, "PromiseResolveThenableJobTaskMap"),
+ ("read_only_space", 0x059a1): (115, "InternalClassMap"),
+ ("read_only_space", 0x059f1): (116, "SmiPairMap"),
+ ("read_only_space", 0x05a41): (117, "SmiBoxMap"),
+ ("read_only_space", 0x05a91): (118, "SortStateMap"),
+ ("read_only_space", 0x05ae1): (121, "AllocationSiteWithWeakNextMap"),
+ ("read_only_space", 0x05b31): (121, "AllocationSiteWithoutWeakNextMap"),
+ ("read_only_space", 0x05b81): (156, "LoadHandler1Map"),
+ ("read_only_space", 0x05bd1): (156, "LoadHandler2Map"),
+ ("read_only_space", 0x05c21): (156, "LoadHandler3Map"),
+ ("read_only_space", 0x05c71): (164, "StoreHandler0Map"),
+ ("read_only_space", 0x05cc1): (164, "StoreHandler1Map"),
+ ("read_only_space", 0x05d11): (164, "StoreHandler2Map"),
+ ("read_only_space", 0x05d61): (164, "StoreHandler3Map"),
+ ("map_space", 0x00119): (1057, "ExternalMap"),
+ ("map_space", 0x00169): (1073, "JSMessageObjectMap"),
}
# List of known V8 objects.
KNOWN_OBJECTS = {
- ("read_only_space", 0x001b1): "NullValue",
- ("read_only_space", 0x00231): "EmptyDescriptorArray",
- ("read_only_space", 0x00299): "EmptyWeakFixedArray",
- ("read_only_space", 0x00399): "UninitializedValue",
- ("read_only_space", 0x004a9): "UndefinedValue",
- ("read_only_space", 0x00529): "NanValue",
- ("read_only_space", 0x00589): "TheHoleValue",
- ("read_only_space", 0x00621): "HoleNanValue",
- ("read_only_space", 0x00631): "TrueValue",
- ("read_only_space", 0x006e1): "FalseValue",
- ("read_only_space", 0x00729): "empty_string",
- ("read_only_space", 0x00be9): "EmptyScopeInfo",
- ("read_only_space", 0x00bf9): "EmptyFixedArray",
- ("read_only_space", 0x00c09): "ArgumentsMarker",
- ("read_only_space", 0x00ca9): "Exception",
- ("read_only_space", 0x00d49): "TerminationException",
- ("read_only_space", 0x00df1): "OptimizedOut",
- ("read_only_space", 0x00e91): "StaleRegister",
- ("read_only_space", 0x023d1): "EmptyEnumCache",
- ("read_only_space", 0x02439): "EmptyPropertyArray",
- ("read_only_space", 0x02449): "EmptyByteArray",
- ("read_only_space", 0x02459): "EmptyObjectBoilerplateDescription",
- ("read_only_space", 0x02471): "EmptyArrayBoilerplateDescription",
- ("read_only_space", 0x024d9): "EmptyClosureFeedbackCellArray",
- ("read_only_space", 0x024e9): "EmptySloppyArgumentsElements",
- ("read_only_space", 0x02509): "EmptySlowElementDictionary",
- ("read_only_space", 0x02551): "EmptyOrderedHashMap",
- ("read_only_space", 0x02579): "EmptyOrderedHashSet",
- ("read_only_space", 0x025a1): "EmptyFeedbackMetadata",
- ("read_only_space", 0x025b1): "EmptyPropertyCell",
- ("read_only_space", 0x025d9): "EmptyPropertyDictionary",
- ("read_only_space", 0x02629): "NoOpInterceptorInfo",
- ("read_only_space", 0x026c9): "EmptyWeakArrayList",
- ("read_only_space", 0x026e1): "InfinityValue",
- ("read_only_space", 0x026f1): "MinusZeroValue",
- ("read_only_space", 0x02701): "MinusInfinityValue",
- ("read_only_space", 0x02711): "SelfReferenceMarker",
- ("read_only_space", 0x02769): "OffHeapTrampolineRelocationInfo",
- ("read_only_space", 0x02781): "TrampolineTrivialCodeDataContainer",
- ("read_only_space", 0x02799): "TrampolinePromiseRejectionCodeDataContainer",
- ("read_only_space", 0x027b1): "HashSeed",
- ("old_space", 0x00111): "ArgumentsIteratorAccessor",
- ("old_space", 0x00181): "ArrayLengthAccessor",
- ("old_space", 0x001f1): "BoundFunctionLengthAccessor",
- ("old_space", 0x00261): "BoundFunctionNameAccessor",
- ("old_space", 0x002d1): "ErrorStackAccessor",
- ("old_space", 0x00341): "FunctionArgumentsAccessor",
- ("old_space", 0x003b1): "FunctionCallerAccessor",
- ("old_space", 0x00421): "FunctionNameAccessor",
- ("old_space", 0x00491): "FunctionLengthAccessor",
- ("old_space", 0x00501): "FunctionPrototypeAccessor",
- ("old_space", 0x00571): "StringLengthAccessor",
- ("old_space", 0x005e1): "InvalidPrototypeValidityCell",
- ("old_space", 0x005f1): "EmptyScript",
- ("old_space", 0x00671): "ManyClosuresCell",
- ("old_space", 0x00689): "ArrayConstructorProtector",
- ("old_space", 0x00699): "NoElementsProtector",
- ("old_space", 0x006c1): "IsConcatSpreadableProtector",
- ("old_space", 0x006d1): "ArraySpeciesProtector",
- ("old_space", 0x006f9): "TypedArraySpeciesProtector",
- ("old_space", 0x00721): "PromiseSpeciesProtector",
- ("old_space", 0x00749): "StringLengthProtector",
- ("old_space", 0x00759): "ArrayIteratorProtector",
- ("old_space", 0x00781): "ArrayBufferDetachingProtector",
- ("old_space", 0x007a9): "PromiseHookProtector",
- ("old_space", 0x007d1): "PromiseResolveProtector",
- ("old_space", 0x007e1): "MapIteratorProtector",
- ("old_space", 0x00809): "PromiseThenProtector",
- ("old_space", 0x00831): "SetIteratorProtector",
- ("old_space", 0x00859): "StringIteratorProtector",
- ("old_space", 0x00881): "SingleCharacterStringCache",
- ("old_space", 0x01091): "StringSplitCache",
- ("old_space", 0x018a1): "RegExpMultipleCache",
- ("old_space", 0x020b1): "BuiltinsConstantsTable",
+ ("read_only_space", 0x001b9): "NullValue",
+ ("read_only_space", 0x00239): "EmptyDescriptorArray",
+ ("read_only_space", 0x002a1): "EmptyWeakFixedArray",
+ ("read_only_space", 0x003a1): "UninitializedValue",
+ ("read_only_space", 0x004b1): "UndefinedValue",
+ ("read_only_space", 0x00531): "NanValue",
+ ("read_only_space", 0x00591): "TheHoleValue",
+ ("read_only_space", 0x00629): "HoleNanValue",
+ ("read_only_space", 0x00639): "TrueValue",
+ ("read_only_space", 0x006e9): "FalseValue",
+ ("read_only_space", 0x00731): "empty_string",
+ ("read_only_space", 0x00bf1): "EmptyScopeInfo",
+ ("read_only_space", 0x00c01): "EmptyFixedArray",
+ ("read_only_space", 0x00c11): "ArgumentsMarker",
+ ("read_only_space", 0x00cb1): "Exception",
+ ("read_only_space", 0x00d51): "TerminationException",
+ ("read_only_space", 0x00df9): "OptimizedOut",
+ ("read_only_space", 0x00e99): "StaleRegister",
+ ("read_only_space", 0x02389): "EmptyEnumCache",
+ ("read_only_space", 0x023f1): "EmptyPropertyArray",
+ ("read_only_space", 0x02401): "EmptyByteArray",
+ ("read_only_space", 0x02411): "EmptyObjectBoilerplateDescription",
+ ("read_only_space", 0x02429): "EmptyArrayBoilerplateDescription",
+ ("read_only_space", 0x02491): "EmptyClosureFeedbackCellArray",
+ ("read_only_space", 0x024a1): "EmptySloppyArgumentsElements",
+ ("read_only_space", 0x024c1): "EmptySlowElementDictionary",
+ ("read_only_space", 0x02509): "EmptyOrderedHashMap",
+ ("read_only_space", 0x02531): "EmptyOrderedHashSet",
+ ("read_only_space", 0x02559): "EmptyFeedbackMetadata",
+ ("read_only_space", 0x02569): "EmptyPropertyCell",
+ ("read_only_space", 0x02591): "EmptyPropertyDictionary",
+ ("read_only_space", 0x025e1): "NoOpInterceptorInfo",
+ ("read_only_space", 0x02681): "EmptyWeakArrayList",
+ ("read_only_space", 0x02699): "InfinityValue",
+ ("read_only_space", 0x026a9): "MinusZeroValue",
+ ("read_only_space", 0x026b9): "MinusInfinityValue",
+ ("read_only_space", 0x026c9): "SelfReferenceMarker",
+ ("read_only_space", 0x02721): "OffHeapTrampolineRelocationInfo",
+ ("read_only_space", 0x02739): "TrampolineTrivialCodeDataContainer",
+ ("read_only_space", 0x02751): "TrampolinePromiseRejectionCodeDataContainer",
+ ("read_only_space", 0x02769): "GlobalThisBindingScopeInfo",
+ ("read_only_space", 0x027d1): "EmptyFunctionScopeInfo",
+ ("read_only_space", 0x02821): "HashSeed",
+ ("old_space", 0x00119): "ArgumentsIteratorAccessor",
+ ("old_space", 0x00189): "ArrayLengthAccessor",
+ ("old_space", 0x001f9): "BoundFunctionLengthAccessor",
+ ("old_space", 0x00269): "BoundFunctionNameAccessor",
+ ("old_space", 0x002d9): "ErrorStackAccessor",
+ ("old_space", 0x00349): "FunctionArgumentsAccessor",
+ ("old_space", 0x003b9): "FunctionCallerAccessor",
+ ("old_space", 0x00429): "FunctionNameAccessor",
+ ("old_space", 0x00499): "FunctionLengthAccessor",
+ ("old_space", 0x00509): "FunctionPrototypeAccessor",
+ ("old_space", 0x00579): "StringLengthAccessor",
+ ("old_space", 0x005e9): "InvalidPrototypeValidityCell",
+ ("old_space", 0x005f9): "EmptyScript",
+ ("old_space", 0x00679): "ManyClosuresCell",
+ ("old_space", 0x00691): "ArrayConstructorProtector",
+ ("old_space", 0x006a1): "NoElementsProtector",
+ ("old_space", 0x006c9): "IsConcatSpreadableProtector",
+ ("old_space", 0x006d9): "ArraySpeciesProtector",
+ ("old_space", 0x00701): "TypedArraySpeciesProtector",
+ ("old_space", 0x00729): "PromiseSpeciesProtector",
+ ("old_space", 0x00751): "StringLengthProtector",
+ ("old_space", 0x00761): "ArrayIteratorProtector",
+ ("old_space", 0x00789): "ArrayBufferDetachingProtector",
+ ("old_space", 0x007b1): "PromiseHookProtector",
+ ("old_space", 0x007d9): "PromiseResolveProtector",
+ ("old_space", 0x007e9): "MapIteratorProtector",
+ ("old_space", 0x00811): "PromiseThenProtector",
+ ("old_space", 0x00839): "SetIteratorProtector",
+ ("old_space", 0x00861): "StringIteratorProtector",
+ ("old_space", 0x00889): "SingleCharacterStringCache",
+ ("old_space", 0x01099): "StringSplitCache",
+ ("old_space", 0x018a9): "RegExpMultipleCache",
+ ("old_space", 0x020b9): "BuiltinsConstantsTable",
}
# List of known V8 Frame Markers.
diff --git a/deps/v8/tools/wasm/update-wasm-spec-tests.sh b/deps/v8/tools/wasm/update-wasm-spec-tests.sh
index d029ffe604..01688648eb 100755
--- a/deps/v8/tools/wasm/update-wasm-spec-tests.sh
+++ b/deps/v8/tools/wasm/update-wasm-spec-tests.sh
@@ -30,6 +30,8 @@ V8_DIR="${TOOLS_WASM_DIR}/../.."
SPEC_TEST_DIR=${V8_DIR}/test/wasm-spec-tests
TMP_DIR=${SPEC_TEST_DIR}/tmp
+JS_API_TEST_DIR=${V8_DIR}/test/wasm-js
+
log_and_run cd ${V8_DIR}
log_and_run rm -rf ${SPEC_TEST_DIR}/tests
@@ -40,29 +42,40 @@ log_and_run mkdir ${SPEC_TEST_DIR}/tests/proposals
log_and_run rm -rf ${TMP_DIR}
log_and_run mkdir ${TMP_DIR}
+log_and_run rm -rf ${JS_API_TEST_DIR}/tests
+log_and_run mkdir ${JS_API_TEST_DIR}/tests
+log_and_run mkdir ${JS_API_TEST_DIR}/tests/proposals
+
###############################################################################
# Generate the spec tests.
###############################################################################
-log_and_run cd ${V8_DIR}/test/wasm-js/data/interpreter
+echo Process spec
+log_and_run cd ${TMP_DIR}
+log_and_run git clone https://github.com/WebAssembly/spec
+log_and_run cd spec/interpreter
+
# The next step requires that ocaml is installed. See the README.md in
-# ${V8_DIR}/test/wasm-js/data/interpreter/.
+# https://github.com/WebAssembly/spec/tree/master/interpreter/.
log_and_run make clean opt
-log_and_run cd ${V8_DIR}/test/wasm-js/data/test/core
+log_and_run cd ${TMP_DIR}/spec/test/core
log_and_run cp *.wast ${SPEC_TEST_DIR}/tests/
-log_and_run ./run.py --wasm ${V8_DIR}/test/wasm-js/data/interpreter/wasm --out ${TMP_DIR}
+log_and_run ./run.py --wasm ${TMP_DIR}/spec/interpreter/wasm --out ${TMP_DIR}
log_and_run cp ${TMP_DIR}/*.js ${SPEC_TEST_DIR}/tests/
+log_and_run cp -r ${TMP_DIR}/spec/test/js-api/* ${JS_API_TEST_DIR}/tests
+
###############################################################################
# Generate the proposal tests.
###############################################################################
-repos='bulk-memory-operations reference-types'
+repos='bulk-memory-operations reference-types js-types'
for repo in ${repos}; do
echo "Process ${repo}"
+ echo ">> Process core tests"
log_and_run cd ${TMP_DIR}
log_and_run git clone https://github.com/WebAssembly/${repo}
# Compile the spec interpreter to generate the .js test cases later.
@@ -76,13 +89,27 @@ for repo in ${repos}; do
for abs_filename in ${TMP_DIR}/${repo}/test/core/*.wast; do
rel_filename="$(basename -- $abs_filename)"
test_name=${rel_filename%.wast}
- spec_filename=${V8_DIR}/test/wasm-js/data/test/core/${rel_filename}
+ spec_filename=${TMP_DIR}/spec/test/core/${rel_filename}
if [ ! -f "$spec_filename" ] || ! cmp -s $abs_filename $spec_filename ; then
log_and_run cp ${rel_filename} ${SPEC_TEST_DIR}/tests/proposals/${repo}/
log_and_run ./run.py --wasm ../../interpreter/wasm ${rel_filename} --out _build 2> /dev/null
fi
done
log_and_run cp _build/*.js ${SPEC_TEST_DIR}/tests/proposals/${repo}/
+
+ echo ">> Process js-api tests"
+ log_and_run mkdir ${JS_API_TEST_DIR}/tests/proposals/${repo}
+ log_and_run cp -r ${TMP_DIR}/${repo}/test/js-api/* ${JS_API_TEST_DIR}/tests/proposals/${repo}
+ # Delete duplicate tests
+ log_and_run cd ${JS_API_TEST_DIR}/tests
+ for spec_test_name in $(find ./ -name '*.any.js' -not -wholename '*/proposals/*'); do
+ proposal_test_name="proposals/${repo}/${spec_test_name}"
+ if [ -f "$proposal_test_name" ] && cmp -s $spec_test_name $proposal_test_name ; then
+ log_and_run rm $proposal_test_name
+ elif [ -f "$proposal_test_name" ]; then
+ echo "keep" $proposal_test_name
+ fi
+ done
done
###############################################################################
@@ -95,6 +122,10 @@ echo "The following files will get uploaded:"
ls -R tests
echo
+cd ${JS_API_TEST_DIR}
+ls -R tests
+echo
+
log_and_run rm -rf ${TMP_DIR}
###############################################################################
@@ -111,3 +142,6 @@ echo "* When the script asks you for your project-id, use 0."
echo "****************************************************************************"
log_and_run cd ${SPEC_TEST_DIR}
log_and_run upload_to_google_storage.py -a -b v8-wasm-spec-tests tests
+
+log_and_run cd ${JS_API_TEST_DIR}
+log_and_run upload_to_google_storage.py -a -b v8-wasm-spec-tests tests
diff --git a/deps/v8/tools/whitespace.txt b/deps/v8/tools/whitespace.txt
index 9a80a32344..1540f5f52a 100644
--- a/deps/v8/tools/whitespace.txt
+++ b/deps/v8/tools/whitespace.txt
@@ -7,4 +7,6 @@ A Smi balks into a war and says:
The doubles heard this and started to unbox.
The Smi looked at them when a crazy v8-autoroll account showed up...
The autoroller bought a round of Himbeerbrause. Suddenly.....
-The bartender starts to shake the bottles..........
+The bartender starts to shake the bottles..............
+I can't add trailing whitespaces, so I'm adding this line.
+I'm starting to think that just adding trailing whitespaces might not be bad.
diff --git a/deps/v8/tools/windbg.js b/deps/v8/tools/windbg.js
index 3df14f4a2e..91877b4c61 100644
--- a/deps/v8/tools/windbg.js
+++ b/deps/v8/tools/windbg.js
@@ -1,4 +1,4 @@
-// Copyright 2019 the V8 project authors. All rights reserved.
+// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,6 +11,7 @@
=============================================================================*/
function help() {
+ if (supports_call_command()) {
print("--------------------------------------------------------------------");
print(" LIVE debugging only");
print("--------------------------------------------------------------------");
@@ -27,11 +28,22 @@ function help() {
print(" !jsbp() or !jsbp");
print(" sets bp in v8::internal::Execution::Call");
print("");
+ }
+
print("--------------------------------------------------------------------");
- print(" Managed heap");
+ print(" Setup of the script");
print("--------------------------------------------------------------------");
+ print(" !set_module(\"module_name_no_extension\")");
+ print(" we'll try the usual suspects for where v8's code might have");
+ print(" been linked into, but you can also set it manually,");
+ print(" e.g. !set_module(\"v8_for_testing\")");
print(" !set_iso(isolate_address)");
print(" call this function before using !mem or other heap routines");
+ print("");
+
+ print("--------------------------------------------------------------------");
+ print(" Managed heap");
+ print("--------------------------------------------------------------------");
print(" !mem or !mem(\"space1[ space2 ...]\")");
print(" prints memory chunks from the 'space' owned by the heap in the");
print(" isolate set by !set_iso; valid values for 'space' are:");
@@ -42,16 +54,60 @@ function help() {
print(" prints name of the space and address of the MemoryChunk the");
print(" 'address' is from, e.g. !where(0x235cb869f9)");
print("");
+
+ print("--------------------------------------------------------------------");
+ print(" Managed objects");
+ print("--------------------------------------------------------------------");
+ print(" !jot(tagged_addr, depth)");
+ print(" dumps the tree of objects using 'tagged_addr' as a root,");
+ print(" assumes that pointer fields are aligned at ptr_size boundary,");
+ print(" unspecified depth means 'unlimited',");
+ print(" e.g. !jot(0x235cb869f9, 2), !jot 0x235cb869f9");
+ print(" !jo_in_range(start_addr, end_addr)");
+ print(" prints address/map pointers of objects found inside the range");
+ print(" specified by 'start_addr' and 'end_addr', assumes the object");
+ print(" pointers to be aligned at ptr_size boundary,");
+ print(" e.g. !jo_in_range(0x235cb869f8 - 0x100, 0x235cb869f8 + 0x1a0");
+ print(" !jo_prev(address, max_slots = 100)");
+ print(" prints address and map pointer of the nearest object within");
+ print(" 'max_slots' before the given 'address', assumes the object");
+ print(" pointers to be aligned at ptr_size boundary,");
+ print(" e.g. !jo_prev 0x235cb869f8, !jo_prev(0x235cb869f9, 16)");
+ print(" !jo_next(address, max_slots = 100)");
+ print(" prints address and map pointer of the nearest object within");
+ print(" 'max_slots' following the given 'address', assumes the object");
+ print(" pointers to be aligned at ptr_size boundary,");
+ print(" e.g. !jo_next 0x235cb869f8, !jo_next(0x235cb869f9, 20)");
+ print("");
+
+ print("--------------------------------------------------------------------");
+ print(" Miscellaneous");
+ print("--------------------------------------------------------------------");
+ print(" !dp(address, count = 10)");
+ print(" similar to the built-in 'dp' command but augments output with");
+ print(" more data for values that are managed pointers, note that it");
+ print(" aligns the given 'address' at ptr_sized boundary,");
+ print(" e.g. !dp 0x235cb869f9, !dp(0x235cb869f9, 500), !dp @rsp");
+ print(" !handles(print_handles = false)");
+ print(" prints stats for handles, if 'print_handles' is true will");
+ print(" output all handles as well,");
+ print(" e.g. !handles, !handles(), !handles(true)");
+ print("");
+
print("--------------------------------------------------------------------");
print(" To run any function from this script (live or postmortem):");
print("");
print(" dx @$scriptContents.function_name(args)");
print(" e.g. dx @$scriptContents.pointer_size()");
- print(" e.g. dx @$scriptContents.module_name(\"v8_for_test\")");
+ print(" e.g. dx @$scriptContents.is_map(0x235cb869f9)");
print("--------------------------------------------------------------------");
}
/*=============================================================================
+ On scrip load
+=============================================================================*/
+
+/*=============================================================================
Output
=============================================================================*/
function print(s) {
@@ -67,27 +123,60 @@ function print_filtered(obj, filter) {
}
function inspect(s) {
- for (var k of Reflect.ownKeys(s)) {
- print(k + " => " + Reflect.get(s, k));
+ for (let k of Reflect.ownKeys(s)) {
+ // Attempting to print either of:
+ // 'Reflect.get(s, k)', 'typeof Reflect.get(s, k)', 's[k]'
+ // might throw: "Error: Object does not have a size",
+ // while 'typeof s[k]' returns 'undefined' and prints the full list of
+ // properties. Oh well...
+ print(`${k} => ${typeof s[k]}`);
}
}
+function hex(number) {
+ return `0x${number.toString(16)}`;
+}
/*=============================================================================
Utils (postmortem and live)
=============================================================================*/
+// WinDbg wraps large integers into objects that fail isInteger test (and,
+// consequently fail isSafeInteger test even if the original value was a safe
+// integer). I cannot figure out how to extract the original value from the
+// wrapper object so doing it via conversion to a string. Brrr. Ugly.
+function int(val) {
+ if (typeof val === 'number') {
+ return Number.isInteger(val) ? val : undefined;
+ }
+ if (typeof val === 'object') {
+ let n = parseInt(val.toString());
+ return isNaN(n) ? undefined : n;
+ }
+ return undefined;
+}
+
+function is_live_session() {
+ // Assume that there is a single session (not sure how to get multiple ones
+ // going, maybe, in kernel debugging?).
+ return (host.namespace.Debugger.Sessions[0].Attributes.Target.IsLiveTarget);
+}
+
+function is_TTD_session() {
+ // Assume that there is a single session (not sure how to get multiple ones
+ // going, maybe, in kernel debugging?).
+ return (host.namespace.Debugger.Sessions[0].Attributes.Target.IsTTDTarget);
+}
+
+function supports_call_command() {
+ return is_live_session() && !is_TTD_session();
+}
+
function cast(address, type_name) {
return host.createTypedObject(address, module_name(), type_name);
}
-// Failed to figure out how to get pointer size from the debugger's data model,
-// so we parse it out from sizeof(void*) output.
function pointer_size() {
- let ctl = host.namespace.Debugger.Utility.Control;
- let sizeof = ctl.ExecuteCommand("?? sizeof(void*)");
- let output = "";
- for (output of sizeof) {} // unsigned int64 8
- return parseInt(output.trim().split(" ").pop());
+ return host.namespace.Debugger.Sessions[0].Attributes.Machine.PointerSize;
}
function poi(address) {
@@ -105,8 +194,7 @@ function get_register(name) {
// In debug builds v8 code is compiled into v8.dll, and in release builds
// the code is compiled directly into the executable. If you are debugging some
-// other embedder, invoke module_name explicitly from the debugger and provide
-// the module name to use.
+// other embedder, run !set_module and provide the module name to use.
const known_exes = ["d8", "unittests", "mksnapshot", "chrome", "chromium"];
let module_name_cache;
function module_name(use_this_module) {
@@ -138,10 +226,20 @@ function module_name(use_this_module) {
}
}
}
+
+ if (!module_name_cache) {
+ print(`ERROR. Couldn't determine module name for v8's symbols.`);
+ print(`Please run !set_module (e.g. "!set_module \"v8_for_testing\"")`);
+ }
return module_name_cache;
};
function make_call(fn) {
+ if (!supports_call_command()) {
+ print("ERROR: This command is supported in live sessions only!");
+ return;
+ }
+
// .call resets current frame to the top one, so have to manually remember
// and restore it after making the call.
let curframe = host.namespace.Debugger.State.DebuggerVariables.curframe;
@@ -151,21 +249,6 @@ function make_call(fn) {
return output;
}
-// Skips the meta output about the .call invocation.
-function make_call_and_print_return(fn) {
- let output = make_call(fn);
- let print_line = false;
- for (let line of output) {
- if (print_line) {
- print(line);
- break;
- }
- if (line.includes(".call returns")) {
- print_line = true;
- }
- }
-}
-
/*=============================================================================
Wrappers around V8's printing functions and other utils for live-debugging
@@ -206,11 +289,11 @@ function print_object_from_handle(handle_to_object) {
point at any continuous memory that contains Object pointers.
-----------------------------------------------------------------------------*/
function print_objects_array(start_address, count) {
+ const ptr_size = pointer_size();
let ctl = host.namespace.Debugger.Utility.Control;
- let psize = pointer_size();
let addr_int = start_address;
for (let i = 0; i < count; i++) {
- const addr_hex = `0x${addr_int.toString(16)}`;
+ const addr_hex = hex(addr_int);
// TODO: Tried using createPointerObject but it throws unknown exception
// from ChakraCore. Why?
@@ -223,7 +306,7 @@ function print_objects_array(start_address, count) {
print(`${addr_hex} -> ${deref}`);
print_object(deref);
- addr_int += psize;
+ addr_int += ptr_size;
}
}
@@ -245,6 +328,168 @@ function set_isolate_address(addr) {
isolate_address = addr;
}
+function is_map(addr) {
+ let address = int(addr);
+ if (!Number.isSafeInteger(address) || address % 2 == 0) return false;
+
+ // the first field in all objects, including maps, is a map pointer, but for
+ // maps the pointer is always the same - the meta map that points to itself.
+ const map_addr = int(poi(address - 1));
+ if (!Number.isSafeInteger(map_addr)) return false;
+
+ const map_map_addr = int(poi(map_addr - 1));
+ if (!Number.isSafeInteger(map_map_addr)) return false;
+
+ return (map_addr === map_map_addr);
+}
+
+function is_likely_object(addr) {
+ let address = int(addr);
+ if (!Number.isSafeInteger(address) || address % 2 == 0) return false;
+
+ // the first field in all objects must be a map pointer
+ return is_map(poi(address - 1));
+}
+
+function find_object_near(aligned_addr, max_distance, step_op) {
+ if (!step_op) {
+ const step = pointer_size();
+ const prev =
+ find_object_near(aligned_addr, max_distance, x => x - step);
+ const next =
+ find_object_near(aligned_addr, max_distance, x => x + step);
+
+ if (!prev) return next;
+ if (!next) return prev;
+ return (addr - prev <= next - addr) ? prev : next;
+ }
+
+ let maybe_map_addr = poi(aligned_addr);
+ let iters = 0;
+ while (maybe_map_addr && iters < max_distance) {
+ if (is_map(maybe_map_addr)) {
+ return aligned_addr;
+ }
+ aligned_addr = step_op(aligned_addr);
+ maybe_map_addr = poi(aligned_addr);
+ iters++;
+ }
+}
+
+function find_object_prev(addr, max_distance) {
+ if (!Number.isSafeInteger(int(addr))) return;
+
+ const ptr_size = pointer_size();
+ const aligned_addr = addr - (addr % ptr_size);
+ return find_object_near(aligned_addr, max_distance, x => x - ptr_size);
+}
+
+function find_object_next(addr, max_distance) {
+ if (!Number.isSafeInteger(int(addr))) return;
+
+ const ptr_size = pointer_size();
+ const aligned_addr = addr - (addr % ptr_size) + ptr_size;
+ return find_object_near(aligned_addr, max_distance, x => x + ptr_size);
+}
+
+function print_object_prev(addr, max_slots = 100) {
+ let obj_addr = find_object_prev(addr, max_slots);
+ if (!obj_addr) {
+ print(
+ `No object found within ${max_slots} slots prior to ${hex(addr)}`);
+ }
+ else {
+ print(
+ `found object: ${hex(obj_addr + 1)} : ${hex(poi(obj_addr))}`);
+ }
+}
+
+function print_object_next(addr, max_slots = 100) {
+ let obj_addr = find_object_next(addr, max_slots);
+ if (!obj_addr) {
+ print(
+ `No object found within ${max_slots} slots following ${hex(addr)}`);
+ }
+ else {
+ print(
+ `found object: ${hex(obj_addr + 1)} : ${hex(poi(obj_addr))}`);
+ }
+}
+
+// This function assumes that pointers to objects are stored at ptr-size aligned
+// boundaries.
+function print_objects_in_range(start, end){
+ if (!Number.isSafeInteger(int(start)) || !Number.isSafeInteger(int(end))) {
+ return;
+ }
+
+ const ptr_size = pointer_size();
+ let iters = (end - start) / ptr_size;
+ let cur = start;
+ print(`===============================================`);
+ print(`objects in range ${hex(start)} - ${hex(end)}`);
+ print(`===============================================`);
+ let count = 0;
+ while (cur && cur < end) {
+ let obj = find_object_next(cur, iters);
+ if (obj) {
+ count++;
+ print(`${hex(obj + 1)} : ${hex(poi(obj))}`);
+ iters = (end - cur) / ptr_size;
+ }
+ cur = obj + ptr_size;
+ }
+ print(`===============================================`);
+ print(`found ${count} objects in range ${hex(start)} - ${hex(end)}`)
+ print(`===============================================`);
+}
+
+// This function assumes the pointer fields to be ptr-size aligned.
+function print_objects_tree(root, depth_limit) {
+ if(!is_likely_object(root)) {
+ print(`${hex(root)} doesn't look like an object`);
+ return;
+ }
+
+ let path = [];
+
+ function impl(obj, depth, depth_limit) {
+ const ptr_size = pointer_size();
+ // print the current object and its map pointer
+ const this_obj =
+ `${" ".repeat(2 * depth)}${hex(obj)} : ${hex(poi(obj - 1))}`;
+ const cutoff = depth_limit && depth == depth_limit - 1;
+ print(`${this_obj}${cutoff ? " (...)" : ""}`);
+ if (cutoff) return;
+
+ path[depth] = obj;
+ path.length = depth + 1;
+ let cur = obj - 1 + ptr_size;
+
+ // Scan downwards until an address that is likely to be at the start of
+ // another object, in which case it's time to pop out from the recursion.
+ let iter = 0; // an arbitrary guard to avoid hanging the debugger
+ let seen = new Set(path);
+ while (!is_likely_object(cur + 1) && iter < 100) {
+ iter++;
+ let field = poi(cur);
+ if (is_likely_object(field)) {
+ if (seen.has(field)) {
+ print(
+ `${" ".repeat(2 * depth + 2)}cycle: ${hex(cur)}->${hex(field)}`);
+ }
+ else {
+ impl(field, depth + 1, depth_limit);
+ }
+ }
+ cur += ptr_size;
+ }
+ }
+ print(`===============================================`);
+ impl(root, 0, depth_limit);
+ print(`===============================================`);
+}
+
/*-----------------------------------------------------------------------------
Memory in each Space is organized into a linked list of memory chunks
-----------------------------------------------------------------------------*/
@@ -262,11 +507,10 @@ function print_memory_chunk_list(space_type, front, top, age_mark) {
let cur = front;
while (!cur.isNull) {
let imm = cur.flags_ & NEVER_EVACUATE ? "*" : " ";
- let addr = `0x${cur.address.toString(16)}`;
- let area =
- `0x${cur.area_start_.toString(16)} - 0x${cur.area_end_.toString(16)}`;
+ let addr = hex(cur.address);
+ let area = `${hex(cur.area_start_)} - ${hex(cur.area_end_)}`;
let dt = `dt ${addr} ${module_name()}!v8::internal::MemoryChunk`;
- print(`${imm} ${addr}:\t ${area} (0x${cur.size_.toString(16)}) : ${dt}`);
+ print(`${imm} ${addr}:\t ${area} (${hex(cur.size_)}) : ${dt}`);
cur = cur.list_node_.next_;
}
print("");
@@ -307,18 +551,16 @@ function get_chunks() {
}
function find_chunk(address) {
- // if 'address' is greater than Number.MAX_SAFE_INTEGER, comparison ops on it
- // throw "Error: 64 bit value loses precision on conversion to number"
- try {
- let chunks = get_chunks(isolate_address);
- for (let c of chunks) {
- let chunk = cast(c.address, "v8::internal::MemoryChunk");
- if (address >= chunk.area_start_ && address < chunk.area_end_) {
- return c;
- }
+ if (!Number.isSafeInteger(int(address))) return undefined;
+
+ let chunks = get_chunks(isolate_address);
+ for (let c of chunks) {
+ let chunk = cast(c.address, "v8::internal::MemoryChunk");
+ if (address >= chunk.area_start_ && address < chunk.area_end_) {
+ return c;
}
}
- catch (e) { }
+
return undefined;
}
@@ -391,12 +633,111 @@ function print_owning_space(address) {
}
let c = find_chunk(address);
- let addr = `0x${address.toString(16)}`;
if (c) {
- print(`${addr} is in ${c.space} (chunk: 0x${c.address.toString(16)})`);
+ print(`${hex(address)} is in ${c.space} (chunk: ${hex(c.address)})`);
}
else {
- print(`Address ${addr} is not in managed heap`);
+ print(`Address ${hex(address)} is not in managed heap`);
+ }
+}
+
+/*-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------*/
+function print_handles_data(print_handles = false) {
+ if (isolate_address == 0) {
+ print("Please call !set_iso(isolate_address) first.");
+ return;
+ }
+
+ let iso = cast(isolate_address, "v8::internal::Isolate");
+ let hsd = iso.handle_scope_data_;
+ let hsimpl = iso.handle_scope_implementer_;
+
+ // depth level
+ print(`Nested depth level: ${hsd.level}`);
+
+ // count of handles
+ const ptr_size = pointer_size();
+ let blocks = hsimpl.blocks_;
+ const block_size = 1022; // v8::internal::KB - 2
+ const first_block = blocks.data_.address;
+ const last_block = (blocks.size_ == 0)
+ ? first_block
+ : first_block + ptr_size * (blocks.size_ - 1);
+
+ const count = (blocks.size_ == 0)
+ ? 0
+ : (blocks.size_ - 1) * block_size +
+ (hsd.next.address - poi(last_block))/ptr_size;
+ print(`Currently tracking ${count} local handles`);
+
+ // print the handles
+ if (print_handles && count > 0) {
+ for (let block = first_block; block < last_block;
+ block += block_size * ptr_size) {
+ print(`Handles in block at ${hex(block)}`);
+ for (let i = 0; i < block_size; i++) {
+ const location = poi(block + i * ptr_size);
+ print(` ${hex(location)}->${hex(poi(location))}`);
+ }
+ }
+
+ let location = poi(last_block);
+ print(`Handles in block at ${hex(last_block)}`);
+ for (let location = poi(last_block); location < hsd.next.address;
+ location += ptr_size) {
+ print(` ${hex(location)}->${hex(poi(location))}`);
+ }
+ }
+
+ // where will the next handle allocate at?
+ const prefix = "Next handle's location will be";
+ if (hsd.next.address < hsd.limit.address) {
+ print(`${prefix} at ${hex(hsd.next.address)}`);
+ }
+ else if (hsimpl.spare_) {
+ const location = hsimpl.spare_.address;
+ print(`${prefix} from the spare block at ${hex(location)}`);
+ }
+ else {
+ print(`${prefix} from a new block to be allocated`);
+ }
+}
+
+function pad_right(addr) {
+ let addr_hex = hex(addr);
+ return `${addr_hex}${" ".repeat(pointer_size() * 2 + 2 - addr_hex.length)}`;
+}
+
+// TODO irinayat: would be nice to identify handles and smi as well
+function dp(addr, count = 10) {
+ if (isolate_address == 0) {
+ print(`To see where objects are located, run !set_iso.`);
+ }
+
+ if (!Number.isSafeInteger(int(addr))) {
+ print(`${hex(addr)} doesn't look like a valid address`);
+ return;
+ }
+
+ const ptr_size = pointer_size();
+ let aligned_addr = addr - (addr % ptr_size);
+ let val = poi(aligned_addr);
+ let iter = 0;
+ while (val && iter < count) {
+ const augm_map = is_map(val) ? "map" : "";
+ const augm_obj = is_likely_object(val) && !is_map(val) ? "obj" : "";
+ const augm_other = !is_map(val) && !is_likely_object(val) ? "val" : "";
+ let c = find_chunk(val);
+ const augm_space = c ? ` in ${c.space}` : "";
+ const augm = `${augm_map}${augm_obj}${augm_other}${augm_space}`;
+
+ print(`${pad_right(aligned_addr)} ${pad_right(val)} ${augm}`);
+
+ aligned_addr += ptr_size;
+ val = poi(aligned_addr);
+ iter++;
}
}
@@ -412,8 +753,17 @@ function initializeScript() {
new host.functionAlias(print_js_stack, "jst"),
new host.functionAlias(set_isolate_address, "set_iso"),
+ new host.functionAlias(module_name, "set_module"),
new host.functionAlias(print_memory, "mem"),
new host.functionAlias(print_owning_space, "where"),
+ new host.functionAlias(print_handles_data, "handles"),
+
+ new host.functionAlias(print_object_prev, "jo_prev"),
+ new host.functionAlias(print_object_next, "jo_next"),
+ new host.functionAlias(print_objects_in_range, "jo_in_range"),
+ new host.functionAlias(print_objects_tree, "jot"),
+
+ new host.functionAlias(dp, "dp"),
new host.functionAlias(set_user_js_bp, "jsbp"),
]