summaryrefslogtreecommitdiff
path: root/chromium/v8
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-12-08 10:22:59 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-12-08 12:17:14 +0000
commit69b8f9169ffd66fdeca1ac60a4bc06b91d106186 (patch)
treec8b7f735583d0b4e0c0b61a014a7f4b3b26e85ab /chromium/v8
parentdaa093eea7c773db06799a13bd7e4e2e2a9f8f14 (diff)
downloadqtwebengine-chromium-69b8f9169ffd66fdeca1ac60a4bc06b91d106186.tar.gz
BASELINE: Update Chromium to 63.0.3239.87
Change-Id: Iac27464730121b4fac76869d87d622504642e016 Reviewed-by: Peter Varga <pvarga@inf.u-szeged.hu>
Diffstat (limited to 'chromium/v8')
-rw-r--r--chromium/v8/AUTHORS2
-rw-r--r--chromium/v8/BUILD.gn6
-rw-r--r--chromium/v8/DEPS2
-rw-r--r--chromium/v8/Makefile26
-rw-r--r--chromium/v8/gni/isolate.gni2
-rw-r--r--chromium/v8/gypfiles/features.gypi4
-rw-r--r--chromium/v8/gypfiles/isolate.gypi1
-rwxr-xr-xchromium/v8/gypfiles/run-tests-legacy.py50
-rw-r--r--chromium/v8/gypfiles/toolchain.gypi1
-rw-r--r--chromium/v8/include/v8-inspector.h2
-rw-r--r--chromium/v8/include/v8-version.h2
-rw-r--r--chromium/v8/include/v8.h23
-rw-r--r--chromium/v8/src/api-natives.cc6
-rw-r--r--chromium/v8/src/api.cc12
-rw-r--r--chromium/v8/src/arm/assembler-arm.cc21
-rw-r--r--chromium/v8/src/arm/simulator-arm.cc2
-rw-r--r--chromium/v8/src/asmjs/asm-js.cc1
-rw-r--r--chromium/v8/src/asmjs/asm-parser.cc7
-rw-r--r--chromium/v8/src/assembler.cc14
-rw-r--r--chromium/v8/src/assembler.h5
-rw-r--r--chromium/v8/src/ast/scopes.cc4
-rw-r--r--chromium/v8/src/ast/scopes.h9
-rw-r--r--chromium/v8/src/base/platform/platform-aix.cc3
-rw-r--r--chromium/v8/src/bootstrapper.cc12
-rw-r--r--chromium/v8/src/builtins/builtins-collections-gen.cc9
-rw-r--r--chromium/v8/src/builtins/builtins-definitions.h2
-rw-r--r--chromium/v8/src/builtins/builtins-proxy-gen.cc4
-rw-r--r--chromium/v8/src/builtins/builtins-string-gen.cc29
-rw-r--r--chromium/v8/src/builtins/builtins-string-gen.h2
-rw-r--r--chromium/v8/src/builtins/builtins-typedarray-gen.cc346
-rw-r--r--chromium/v8/src/builtins/builtins-typedarray.cc296
-rw-r--r--chromium/v8/src/code-stub-assembler.cc71
-rw-r--r--chromium/v8/src/code-stub-assembler.h13
-rw-r--r--chromium/v8/src/compiler/arm/code-generator-arm.cc99
-rw-r--r--chromium/v8/src/compiler/arm/instruction-selector-arm.cc24
-rw-r--r--chromium/v8/src/compiler/code-assembler.cc19
-rw-r--r--chromium/v8/src/compiler/code-assembler.h13
-rw-r--r--chromium/v8/src/compiler/common-operator.cc4
-rw-r--r--chromium/v8/src/compiler/common-operator.h12
-rw-r--r--chromium/v8/src/compiler/effect-control-linearizer.cc28
-rw-r--r--chromium/v8/src/compiler/effect-control-linearizer.h1
-rw-r--r--chromium/v8/src/compiler/escape-analysis.cc40
-rw-r--r--chromium/v8/src/compiler/escape-analysis.h5
-rw-r--r--chromium/v8/src/compiler/js-call-reducer.cc50
-rw-r--r--chromium/v8/src/compiler/js-create-lowering.cc5
-rw-r--r--chromium/v8/src/compiler/js-native-context-specialization.cc8
-rw-r--r--chromium/v8/src/compiler/js-typed-lowering.cc1
-rw-r--r--chromium/v8/src/compiler/opcodes.h1
-rw-r--r--chromium/v8/src/compiler/raw-machine-assembler.cc35
-rw-r--r--chromium/v8/src/compiler/raw-machine-assembler.h11
-rw-r--r--chromium/v8/src/compiler/simplified-lowering.cc20
-rw-r--r--chromium/v8/src/compiler/simplified-operator.cc1
-rw-r--r--chromium/v8/src/compiler/simplified-operator.h1
-rw-r--r--chromium/v8/src/compiler/typer.cc11
-rw-r--r--chromium/v8/src/compiler/verifier.cc1
-rw-r--r--chromium/v8/src/compiler/wasm-compiler.cc65
-rw-r--r--chromium/v8/src/debug/debug-scope-iterator.cc17
-rw-r--r--chromium/v8/src/deoptimizer.cc41
-rw-r--r--chromium/v8/src/deoptimizer.h9
-rw-r--r--chromium/v8/src/elements.cc145
-rw-r--r--chromium/v8/src/elements.h14
-rw-r--r--chromium/v8/src/external-reference-table.cc7
-rw-r--r--chromium/v8/src/factory.cc4
-rw-r--r--chromium/v8/src/flag-definitions.h3
-rw-r--r--chromium/v8/src/frames.cc8
-rw-r--r--chromium/v8/src/global-handles.cc52
-rw-r--r--chromium/v8/src/global-handles.h11
-rw-r--r--chromium/v8/src/heap/concurrent-marking.cc6
-rw-r--r--chromium/v8/src/heap/heap.cc9
-rw-r--r--chromium/v8/src/heap/mark-compact.cc11
-rw-r--r--chromium/v8/src/heap/setup-heap-internal.cc2
-rw-r--r--chromium/v8/src/ic/accessor-assembler.cc284
-rw-r--r--chromium/v8/src/ic/accessor-assembler.h5
-rw-r--r--chromium/v8/src/ic/handler-configuration-inl.h18
-rw-r--r--chromium/v8/src/ic/handler-configuration.cc100
-rw-r--r--chromium/v8/src/ic/handler-configuration.h35
-rw-r--r--chromium/v8/src/ic/ic.cc19
-rw-r--r--chromium/v8/src/ic/keyed-store-generic.cc4
-rw-r--r--chromium/v8/src/inspector/inspector.gypi4
-rw-r--r--chromium/v8/src/inspector/v8-debugger.cc6
-rw-r--r--chromium/v8/src/isolate.cc15
-rw-r--r--chromium/v8/src/isolate.h6
-rw-r--r--chromium/v8/src/log.cc5
-rw-r--r--chromium/v8/src/lookup.cc14
-rw-r--r--chromium/v8/src/map-updater.cc33
-rw-r--r--chromium/v8/src/map-updater.h4
-rw-r--r--chromium/v8/src/messages.cc3
-rw-r--r--chromium/v8/src/messages.h2
-rw-r--r--chromium/v8/src/objects-debug.cc9
-rw-r--r--chromium/v8/src/objects-inl.h22
-rw-r--r--chromium/v8/src/objects-printer.cc9
-rw-r--r--chromium/v8/src/objects.cc95
-rw-r--r--chromium/v8/src/objects.h30
-rw-r--r--chromium/v8/src/objects/dictionary.h10
-rw-r--r--chromium/v8/src/objects/map-inl.h33
-rw-r--r--chromium/v8/src/objects/map.h24
-rw-r--r--chromium/v8/src/parsing/parser.cc7
-rw-r--r--chromium/v8/src/parsing/preparsed-scope-data.cc20
-rw-r--r--chromium/v8/src/parsing/preparsed-scope-data.h10
-rw-r--r--chromium/v8/src/parsing/preparser.cc3
-rw-r--r--chromium/v8/src/parsing/preparser.h17
-rw-r--r--chromium/v8/src/ppc/simulator-ppc.cc1
-rw-r--r--chromium/v8/src/regexp/jsregexp.cc8
-rw-r--r--chromium/v8/src/runtime/runtime-intl.cc106
-rw-r--r--chromium/v8/src/runtime/runtime-object.cc29
-rw-r--r--chromium/v8/src/runtime/runtime-proxy.cc17
-rw-r--r--chromium/v8/src/runtime/runtime-test.cc12
-rw-r--r--chromium/v8/src/runtime/runtime-typedarray.cc143
-rw-r--r--chromium/v8/src/runtime/runtime.h6
-rw-r--r--chromium/v8/src/v8.gyp39
-rw-r--r--chromium/v8/src/wasm/module-compiler.cc1
-rw-r--r--chromium/v8/src/wasm/wasm-js.cc4
-rw-r--r--chromium/v8/src/wasm/wasm-memory.cc2
-rw-r--r--chromium/v8/src/wasm/wasm-objects.cc2
-rwxr-xr-xchromium/v8/tools/foozzie/v8_foozzie.py2
-rw-r--r--chromium/v8/tools/mb/docs/design_spec.md4
-rw-r--r--chromium/v8/tools/mb/docs/user_guide.md29
-rwxr-xr-xchromium/v8/tools/mb/mb.py592
-rwxr-xr-xchromium/v8/tools/mb/mb_unittest.py274
-rw-r--r--chromium/v8/tools/testrunner/testrunner.isolate8
-rw-r--r--chromium/v8/tools/testrunner/utils/dump_build_config.py4
-rw-r--r--chromium/v8/tools/testrunner/utils/dump_build_config_gyp.py54
-rw-r--r--chromium/v8/tools/whitespace.txt1
123 files changed, 2500 insertions, 1467 deletions
diff --git a/chromium/v8/AUTHORS b/chromium/v8/AUTHORS
index 6ac0491aba0..be50e6e4996 100644
--- a/chromium/v8/AUTHORS
+++ b/chromium/v8/AUTHORS
@@ -43,7 +43,7 @@ Alexis Campailla <alexis@janeasystems.com>
Andreas Anyuru <andreas.anyuru@gmail.com>
Andrew Paprocki <andrew@ishiboo.com>
Andrei Kashcha <anvaka@gmail.com>
-Anna Henningsen <addaleax@gmail.com>
+Anna Henningsen <anna@addaleax.net>
Bangfu Tao <bangfu.tao@samsung.com>
Ben Noordhuis <info@bnoordhuis.nl>
Benjamin Tan <demoneaux@gmail.com>
diff --git a/chromium/v8/BUILD.gn b/chromium/v8/BUILD.gn
index cf706d6a0bd..daed449c0a5 100644
--- a/chromium/v8/BUILD.gn
+++ b/chromium/v8/BUILD.gn
@@ -56,7 +56,7 @@ declare_args() {
v8_enable_vtunejit = false
# Sets -dENABLE_HANDLE_ZAPPING.
- v8_enable_handle_zapping = true
+ v8_enable_handle_zapping = is_debug
# Enable slow dchecks.
v8_enable_slow_dchecks = false
@@ -84,7 +84,7 @@ declare_args() {
v8_enable_trace_ignition = false
# Sets -dV8_CONCURRENT_MARKING
- v8_enable_concurrent_marking = true
+ v8_enable_concurrent_marking = false
# Sets -dV8_CSA_WRITE_BARRIER
v8_enable_csa_write_barrier = true
@@ -834,7 +834,6 @@ action("v8_dump_build_config") {
is_gcov_coverage = v8_code_coverage && !is_clang
args = [
rebase_path("$root_out_dir/v8_build_config.json", root_build_dir),
- "current_cpu=\"$current_cpu\"",
"dcheck_always_on=$dcheck_always_on",
"is_asan=$is_asan",
"is_cfi=$is_cfi",
@@ -845,7 +844,6 @@ action("v8_dump_build_config") {
"is_tsan=$is_tsan",
"is_ubsan_vptr=$is_ubsan_vptr",
"target_cpu=\"$target_cpu\"",
- "v8_current_cpu=\"$v8_current_cpu\"",
"v8_enable_i18n_support=$v8_enable_i18n_support",
"v8_target_cpu=\"$v8_target_cpu\"",
"v8_use_snapshot=$v8_use_snapshot",
diff --git a/chromium/v8/DEPS b/chromium/v8/DEPS
index 2fb83e97861..b675dd830ef 100644
--- a/chromium/v8/DEPS
+++ b/chromium/v8/DEPS
@@ -12,7 +12,7 @@ deps = {
'v8/tools/gyp':
Var('chromium_url') + '/external/gyp.git' + '@' + 'd61a9397e668fa9843c4aa7da9e79460fe590bfb',
'v8/third_party/icu':
- Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '08cb956852a5ccdba7f9c941728bb833529ba3c6',
+ Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '21d33b1a09a77f033478ea4ffffb61e6970f83bd',
'v8/third_party/instrumented_libraries':
Var('chromium_url') + '/chromium/src/third_party/instrumented_libraries.git' + '@' + '644afd349826cb68204226a16c38bde13abe9c3c',
'v8/buildtools':
diff --git a/chromium/v8/Makefile b/chromium/v8/Makefile
index eb146ac2447..167ebf8c082 100644
--- a/chromium/v8/Makefile
+++ b/chromium/v8/Makefile
@@ -338,32 +338,32 @@ $(ANDROID_BUILDS): $(GYPFILES) $(ENVFILE) Makefile.android
# Test targets.
check: all
- @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ @gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch=$(shell echo $(DEFAULT_ARCHES) | sed -e 's/ /,/g') \
$(TESTFLAGS)
$(addsuffix .check,$(MODES)): $$(basename $$@)
- @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ @gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--mode=$(basename $@) $(TESTFLAGS)
$(addsuffix .check,$(ARCHES)): $$(basename $$@)
- @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ @gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch=$(basename $@) $(TESTFLAGS)
$(CHECKS): $$(basename $$@)
- @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ @gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(basename $@) $(TESTFLAGS)
$(addsuffix .quickcheck,$(MODES)): $$(basename $$@)
- @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ @gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--mode=$(basename $@) $(TESTFLAGS) --quickcheck
$(addsuffix .quickcheck,$(ARCHES)): $$(basename $$@)
- @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ @gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch=$(basename $@) $(TESTFLAGS) --quickcheck
$(QUICKCHECKS): $$(basename $$@)
- @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ @gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(basename $@) $(TESTFLAGS) --quickcheck
$(addsuffix .sync, $(ANDROID_BUILDS)): $$(basename $$@)
@@ -371,7 +371,7 @@ $(addsuffix .sync, $(ANDROID_BUILDS)): $$(basename $$@)
$(shell pwd) $(ANDROID_V8)
$(addsuffix .check, $(ANDROID_BUILDS)): $$(basename $$@).sync
- @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ @gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(basename $@) \
--timeout=600 \
--command-prefix="tools/android-run.py" $(TESTFLAGS)
@@ -380,7 +380,7 @@ $(addsuffix .check, $(ANDROID_ARCHES)): \
$(addprefix $$(basename $$@).,$(MODES)).check
native.check: native
- @tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR)/native \
+ @gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR)/native \
--arch-and-mode=. $(TESTFLAGS)
SUPERFASTTESTMODES = ia32.release
@@ -391,18 +391,18 @@ COMMA = ,
EMPTY =
SPACE = $(EMPTY) $(EMPTY)
quickcheck: $(subst $(COMMA),$(SPACE),$(FASTCOMPILEMODES))
- tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(SUPERFASTTESTMODES) $(TESTFLAGS) --quickcheck \
--download-data mozilla webkit
- tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(FASTTESTMODES) $(TESTFLAGS) --quickcheck
qc: quickcheck
turbocheck: $(subst $(COMMA),$(SPACE),$(FASTCOMPILEMODES))
- tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(SUPERFASTTESTMODES) $(TESTFLAGS) \
--quickcheck --variants=turbofan --download-data mozilla webkit
- tools/run-tests.py $(TESTJOBS) --outdir=$(OUTDIR) \
+ gypfiles/run-tests-legacy.py $(TESTJOBS) --outdir=$(OUTDIR) \
--arch-and-mode=$(FASTTESTMODES) $(TESTFLAGS) \
--quickcheck --variants=turbofan
tc: turbocheck
diff --git a/chromium/v8/gni/isolate.gni b/chromium/v8/gni/isolate.gni
index 4b0ffdc413e..4bdf0c0fad2 100644
--- a/chromium/v8/gni/isolate.gni
+++ b/chromium/v8/gni/isolate.gni
@@ -156,8 +156,6 @@ template("v8_isolate_run") {
"--config-variable",
"icu_use_data_file_flag=$icu_use_data_file_flag",
"--config-variable",
- "is_gn=1",
- "--config-variable",
"msan=$msan",
"--config-variable",
"tsan=$tsan",
diff --git a/chromium/v8/gypfiles/features.gypi b/chromium/v8/gypfiles/features.gypi
index 964e81f46cc..1d3f67daee3 100644
--- a/chromium/v8/gypfiles/features.gypi
+++ b/chromium/v8/gypfiles/features.gypi
@@ -85,7 +85,7 @@
'v8_check_microtasks_scopes_consistency%': 'false',
# Enable concurrent marking.
- 'v8_enable_concurrent_marking%': 1,
+ 'v8_enable_concurrent_marking%': 0,
# Controls the threshold for on-heap/off-heap Typed Arrays.
'v8_typed_array_max_size_in_heap%': 64,
@@ -158,7 +158,7 @@
}, # Debug
'Release': {
'variables': {
- 'v8_enable_handle_zapping%': 1,
+ 'v8_enable_handle_zapping%': 0,
},
'conditions': [
['v8_enable_handle_zapping==1', {
diff --git a/chromium/v8/gypfiles/isolate.gypi b/chromium/v8/gypfiles/isolate.gypi
index 11b05705307..149818c8d06 100644
--- a/chromium/v8/gypfiles/isolate.gypi
+++ b/chromium/v8/gypfiles/isolate.gypi
@@ -74,7 +74,6 @@
'--config-variable', 'gcmole=<(gcmole)',
'--config-variable', 'has_valgrind=<(has_valgrind)',
'--config-variable', 'icu_use_data_file_flag=<(icu_use_data_file_flag)',
- '--config-variable', 'is_gn=0',
'--config-variable', 'msan=<(msan)',
'--config-variable', 'tsan=<(tsan)',
'--config-variable', 'coverage=<(coverage)',
diff --git a/chromium/v8/gypfiles/run-tests-legacy.py b/chromium/v8/gypfiles/run-tests-legacy.py
new file mode 100755
index 00000000000..f1ea478c62d
--- /dev/null
+++ b/chromium/v8/gypfiles/run-tests-legacy.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# 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.
+
+"""
+Legacy test-runner wrapper supporting a product of multiple architectures and
+modes.
+"""
+
+import argparse
+import itertools
+from os.path import abspath, dirname, join
+import subprocess
+import sys
+
+BASE_DIR = dirname(dirname(abspath(__file__)))
+RUN_TESTS = join(BASE_DIR, 'tools', 'run-tests.py')
+
+def main():
+ parser = argparse.ArgumentParser(description='Legacy test-runner wrapper')
+ parser.add_argument(
+ '--arch', help='Comma-separated architectures to run tests on')
+ parser.add_argument(
+ '--mode', help='Comma-separated modes to run tests on')
+ parser.add_argument(
+ '--arch-and-mode',
+ help='Architecture and mode in the format \'arch.mode\'',
+ )
+
+ args, remaining_args = parser.parse_known_args(sys.argv)
+ if (args.arch or args.mode) and args.arch_and_mode:
+ parser.error('The flags --arch-and-mode and --arch/--mode are exclusive.')
+ arch = (args.arch or 'ia32,x64,arm').split(',')
+ mode = (args.mode or 'release,debug').split(',')
+ if args.arch_and_mode:
+ arch_and_mode = map(
+ lambda am: am.split('.'),
+ args.arch_and_mode.split(','))
+ arch = map(lambda am: am[0], arch_and_mode)
+ mode = map(lambda am: am[1], arch_and_mode)
+
+ ret_code = 0
+ for a, m in itertools.product(arch, mode):
+ ret_code |= subprocess.check_call(
+ [RUN_TESTS] + remaining_args[1:] + ['--arch', a, '--mode', m])
+ return ret_code
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/chromium/v8/gypfiles/toolchain.gypi b/chromium/v8/gypfiles/toolchain.gypi
index 5733d2d54ca..80844cecc67 100644
--- a/chromium/v8/gypfiles/toolchain.gypi
+++ b/chromium/v8/gypfiles/toolchain.gypi
@@ -32,6 +32,7 @@
'msvs_use_common_release': 0,
'clang%': 0,
'asan%': 0,
+ 'cfi_vptr%': 0,
'lsan%': 0,
'msan%': 0,
'tsan%': 0,
diff --git a/chromium/v8/include/v8-inspector.h b/chromium/v8/include/v8-inspector.h
index 43bf3b4f60b..d0bb9b47fe4 100644
--- a/chromium/v8/include/v8-inspector.h
+++ b/chromium/v8/include/v8-inspector.h
@@ -211,6 +211,8 @@ class V8_EXPORT V8InspectorClient {
// TODO(dgozman): this was added to support service worker shadow page. We
// should not connect at all.
virtual bool canExecuteScripts(int contextGroupId) { return true; }
+
+ virtual void maxAsyncCallStackDepthChanged(int depth) {}
};
class V8_EXPORT V8Inspector {
diff --git a/chromium/v8/include/v8-version.h b/chromium/v8/include/v8-version.h
index 4a42e6b48d7..46bb92f6506 100644
--- a/chromium/v8/include/v8-version.h
+++ b/chromium/v8/include/v8-version.h
@@ -11,7 +11,7 @@
#define V8_MAJOR_VERSION 6
#define V8_MINOR_VERSION 3
#define V8_BUILD_NUMBER 292
-#define V8_PATCH_LEVEL 0
+#define V8_PATCH_LEVEL 46
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/chromium/v8/include/v8.h b/chromium/v8/include/v8.h
index 5d6b04ad1a4..f1001533649 100644
--- a/chromium/v8/include/v8.h
+++ b/chromium/v8/include/v8.h
@@ -7976,9 +7976,8 @@ class V8_EXPORT V8 {
* This function removes callback which was installed by
* AddGCPrologueCallback function.
*/
- V8_INLINE static V8_DEPRECATED(
- "Use isolate version",
- void RemoveGCPrologueCallback(GCCallback callback));
+ static V8_DEPRECATED("Use isolate version",
+ void RemoveGCPrologueCallback(GCCallback callback));
/**
* Enables the host application to receive a notification after a
@@ -7999,9 +7998,8 @@ class V8_EXPORT V8 {
* This function removes callback which was installed by
* AddGCEpilogueCallback function.
*/
- V8_INLINE static V8_DEPRECATED(
- "Use isolate version",
- void RemoveGCEpilogueCallback(GCCallback callback));
+ static V8_DEPRECATED("Use isolate version",
+ void RemoveGCEpilogueCallback(GCCallback callback));
/**
* Initializes V8. This function needs to be called before the first Isolate
@@ -10385,19 +10383,6 @@ void V8::SetFatalErrorHandler(FatalErrorCallback callback) {
isolate->SetFatalErrorHandler(callback);
}
-void V8::RemoveGCPrologueCallback(GCCallback callback) {
- Isolate* isolate = Isolate::GetCurrent();
- isolate->RemoveGCPrologueCallback(
- reinterpret_cast<Isolate::GCCallback>(callback));
-}
-
-
-void V8::RemoveGCEpilogueCallback(GCCallback callback) {
- Isolate* isolate = Isolate::GetCurrent();
- isolate->RemoveGCEpilogueCallback(
- reinterpret_cast<Isolate::GCCallback>(callback));
-}
-
void V8::TerminateExecution(Isolate* isolate) { isolate->TerminateExecution(); }
diff --git a/chromium/v8/src/api-natives.cc b/chromium/v8/src/api-natives.cc
index a685d4e0fda..35759459c69 100644
--- a/chromium/v8/src/api-natives.cc
+++ b/chromium/v8/src/api-natives.cc
@@ -556,7 +556,7 @@ MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
Handle<Map> object_map = isolate->factory()->NewMap(
JS_SPECIAL_API_OBJECT_TYPE,
JSObject::kHeaderSize + data->embedder_field_count() * kPointerSize,
- HOLEY_SMI_ELEMENTS);
+ TERMINAL_FAST_ELEMENTS_KIND);
object_map->SetConstructor(*constructor);
object_map->set_is_access_check_needed(true);
object_map->set_may_have_interesting_symbols(true);
@@ -692,8 +692,8 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
break;
}
- Handle<Map> map =
- isolate->factory()->NewMap(type, instance_size, HOLEY_SMI_ELEMENTS);
+ Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
+ TERMINAL_FAST_ELEMENTS_KIND);
JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
// Mark as undetectable if needed.
diff --git a/chromium/v8/src/api.cc b/chromium/v8/src/api.cc
index 9cbe3462a5e..300b88f70eb 100644
--- a/chromium/v8/src/api.cc
+++ b/chromium/v8/src/api.cc
@@ -8585,6 +8585,18 @@ void V8::AddGCEpilogueCallback(v8::GCCallback callback, GCType gc_type) {
data, gc_type);
}
+void V8::RemoveGCPrologueCallback(GCCallback callback) {
+ void* data = reinterpret_cast<void*>(callback);
+ Isolate::GetCurrent()->RemoveGCPrologueCallback(CallGCCallbackWithoutIsolate,
+ data);
+}
+
+void V8::RemoveGCEpilogueCallback(GCCallback callback) {
+ void* data = reinterpret_cast<void*>(callback);
+ Isolate::GetCurrent()->RemoveGCEpilogueCallback(CallGCCallbackWithoutIsolate,
+ data);
+}
+
void Isolate::SetEmbedderHeapTracer(EmbedderHeapTracer* tracer) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->heap()->SetEmbedderHeapTracer(tracer);
diff --git a/chromium/v8/src/arm/assembler-arm.cc b/chromium/v8/src/arm/assembler-arm.cc
index 9799950728d..c9aa9ef015c 100644
--- a/chromium/v8/src/arm/assembler-arm.cc
+++ b/chromium/v8/src/arm/assembler-arm.cc
@@ -2131,6 +2131,8 @@ void Assembler::strd(Register src1, Register src2,
void Assembler::ldrex(Register dst, Register src, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.75.
// cond(31-28) | 00011001(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
+ DCHECK(dst != pc);
+ DCHECK(src != pc);
emit(cond | B24 | B23 | B20 | src.code() * B16 | dst.code() * B12 | 0xf9f);
}
@@ -2139,6 +2141,11 @@ void Assembler::strex(Register src1, Register src2, Register dst,
// Instruction details available in ARM DDI 0406C.b, A8.8.212.
// cond(31-28) | 00011000(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
// Rt(3-0)
+ DCHECK(dst != pc);
+ DCHECK(src1 != pc);
+ DCHECK(src2 != pc);
+ DCHECK(src1 != dst);
+ DCHECK(src1 != src2);
emit(cond | B24 | B23 | dst.code() * B16 | src1.code() * B12 | 0xf9 * B4 |
src2.code());
}
@@ -2146,6 +2153,8 @@ void Assembler::strex(Register src1, Register src2, Register dst,
void Assembler::ldrexb(Register dst, Register src, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.76.
// cond(31-28) | 00011101(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
+ DCHECK(dst != pc);
+ DCHECK(src != pc);
emit(cond | B24 | B23 | B22 | B20 | src.code() * B16 | dst.code() * B12 |
0xf9f);
}
@@ -2155,6 +2164,11 @@ void Assembler::strexb(Register src1, Register src2, Register dst,
// Instruction details available in ARM DDI 0406C.b, A8.8.213.
// cond(31-28) | 00011100(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
// Rt(3-0)
+ DCHECK(dst != pc);
+ DCHECK(src1 != pc);
+ DCHECK(src2 != pc);
+ DCHECK(src1 != dst);
+ DCHECK(src1 != src2);
emit(cond | B24 | B23 | B22 | dst.code() * B16 | src1.code() * B12 |
0xf9 * B4 | src2.code());
}
@@ -2162,6 +2176,8 @@ void Assembler::strexb(Register src1, Register src2, Register dst,
void Assembler::ldrexh(Register dst, Register src, Condition cond) {
// Instruction details available in ARM DDI 0406C.b, A8.8.78.
// cond(31-28) | 00011111(27-20) | Rn(19-16) | Rt(15-12) | 111110011111(11-0)
+ DCHECK(dst != pc);
+ DCHECK(src != pc);
emit(cond | B24 | B23 | B22 | B21 | B20 | src.code() * B16 |
dst.code() * B12 | 0xf9f);
}
@@ -2171,6 +2187,11 @@ void Assembler::strexh(Register src1, Register src2, Register dst,
// Instruction details available in ARM DDI 0406C.b, A8.8.215.
// cond(31-28) | 00011110(27-20) | Rn(19-16) | Rd(15-12) | 11111001(11-4) |
// Rt(3-0)
+ DCHECK(dst != pc);
+ DCHECK(src1 != pc);
+ DCHECK(src2 != pc);
+ DCHECK(src1 != dst);
+ DCHECK(src1 != src2);
emit(cond | B24 | B23 | B22 | B21 | dst.code() * B16 | src1.code() * B12 |
0xf9 * B4 | src2.code());
}
diff --git a/chromium/v8/src/arm/simulator-arm.cc b/chromium/v8/src/arm/simulator-arm.cc
index c5b9b00adac..f83d6f2a2af 100644
--- a/chromium/v8/src/arm/simulator-arm.cc
+++ b/chromium/v8/src/arm/simulator-arm.cc
@@ -2176,6 +2176,8 @@ void Simulator::DecodeType01(Instruction* instr) {
int rd = instr->RdValue();
int rt = instr->RmValue();
int rn = instr->RnValue();
+ DCHECK_NE(rd, rn);
+ DCHECK_NE(rd, rt);
int32_t addr = get_register(rn);
switch (instr->Bits(22, 21)) {
case 0: {
diff --git a/chromium/v8/src/asmjs/asm-js.cc b/chromium/v8/src/asmjs/asm-js.cc
index 583163e4086..97da2c2af2f 100644
--- a/chromium/v8/src/asmjs/asm-js.cc
+++ b/chromium/v8/src/asmjs/asm-js.cc
@@ -371,6 +371,7 @@ MaybeHandle<Object> AsmJs::InstantiateAsmWasm(Isolate* isolate,
ReportInstantiationFailure(script, position, "Requires heap buffer");
return MaybeHandle<Object>();
}
+ memory->set_is_growable(false);
size_t size = NumberToSize(memory->byte_length());
// TODO(mstarzinger): We currently only limit byte length of the buffer to
// be a multiple of 8, we should enforce the stricter spec limits here.
diff --git a/chromium/v8/src/asmjs/asm-parser.cc b/chromium/v8/src/asmjs/asm-parser.cc
index 033e9bc3b35..d0eb1050f65 100644
--- a/chromium/v8/src/asmjs/asm-parser.cc
+++ b/chromium/v8/src/asmjs/asm-parser.cc
@@ -14,6 +14,7 @@
#include "src/base/optional.h"
#include "src/flags.h"
#include "src/parsing/scanner.h"
+#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-opcodes.h"
namespace v8 {
@@ -781,6 +782,11 @@ void AsmJsParser::ValidateFunction() {
current_function_builder_->AddLocal(kWasmI32);
}
+ // Check against limit on number of local variables.
+ if (locals.size() + function_temp_locals_used_ > kV8MaxWasmFunctionLocals) {
+ FAIL("Number of local variables exceeds internal limit");
+ }
+
// End function
current_function_builder_->Emit(kExprEnd);
@@ -866,6 +872,7 @@ void AsmJsParser::ValidateFunctionParams(ZoneVector<AsmType*>* params) {
// 6.4 ValidateFunction - locals
void AsmJsParser::ValidateFunctionLocals(size_t param_count,
ZoneVector<ValueType>* locals) {
+ DCHECK(locals->empty());
// Local Variables.
while (Peek(TOK(var))) {
scanner_.EnterLocalScope();
diff --git a/chromium/v8/src/assembler.cc b/chromium/v8/src/assembler.cc
index 8fb315234fc..b36c4941294 100644
--- a/chromium/v8/src/assembler.cc
+++ b/chromium/v8/src/assembler.cc
@@ -52,6 +52,7 @@
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
#include "src/disassembler.h"
+#include "src/elements.h"
#include "src/execution.h"
#include "src/ic/ic.h"
#include "src/ic/stub-cache.h"
@@ -1414,6 +1415,19 @@ ExternalReference ExternalReference::get_or_create_hash_raw(Isolate* isolate) {
return ExternalReference(Redirect(isolate, FUNCTION_ADDR(f)));
}
+ExternalReference
+ExternalReference::copy_fast_number_jsarray_elements_to_typed_array(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(
+ isolate, FUNCTION_ADDR(CopyFastNumberJSArrayElementsToTypedArray)));
+}
+
+ExternalReference ExternalReference::copy_typed_array_elements_to_typed_array(
+ Isolate* isolate) {
+ return ExternalReference(
+ Redirect(isolate, FUNCTION_ADDR(CopyTypedArrayElementsToTypedArray)));
+}
+
ExternalReference ExternalReference::try_internalize_string_function(
Isolate* isolate) {
return ExternalReference(Redirect(
diff --git a/chromium/v8/src/assembler.h b/chromium/v8/src/assembler.h
index 2eae2d543f5..2ebe88d534d 100644
--- a/chromium/v8/src/assembler.h
+++ b/chromium/v8/src/assembler.h
@@ -985,6 +985,11 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference get_or_create_hash_raw(Isolate* isolate);
+ static ExternalReference copy_fast_number_jsarray_elements_to_typed_array(
+ Isolate* isolate);
+ static ExternalReference copy_typed_array_elements_to_typed_array(
+ Isolate* isolate);
+
static ExternalReference page_flags(Page* page);
static ExternalReference ForDeoptEntry(Address entry);
diff --git a/chromium/v8/src/ast/scopes.cc b/chromium/v8/src/ast/scopes.cc
index 189c22f0284..07eacd3fe97 100644
--- a/chromium/v8/src/ast/scopes.cc
+++ b/chromium/v8/src/ast/scopes.cc
@@ -1741,8 +1741,8 @@ void Scope::Print(int n) {
if (is_declaration_scope() && AsDeclarationScope()->calls_sloppy_eval()) {
Indent(n1, "// scope calls sloppy 'eval'\n");
}
- if (is_declaration_scope() && AsDeclarationScope()->uses_super_property()) {
- Indent(n1, "// scope uses 'super' property\n");
+ if (is_declaration_scope() && AsDeclarationScope()->NeedsHomeObject()) {
+ Indent(n1, "// scope needs home object\n");
}
if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
if (is_declaration_scope()) {
diff --git a/chromium/v8/src/ast/scopes.h b/chromium/v8/src/ast/scopes.h
index 9bd24ba1cce..fe155080276 100644
--- a/chromium/v8/src/ast/scopes.h
+++ b/chromium/v8/src/ast/scopes.h
@@ -666,14 +666,13 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// Inform the scope that the corresponding code uses "super".
void RecordSuperPropertyUsage() {
- DCHECK((IsConciseMethod(function_kind()) ||
- IsAccessorFunction(function_kind()) ||
- IsClassConstructor(function_kind())));
+ DCHECK(IsConciseMethod(function_kind()) ||
+ IsAccessorFunction(function_kind()) ||
+ IsClassConstructor(function_kind()));
scope_uses_super_property_ = true;
}
- // Does this scope access "super" property (super.foo).
- bool uses_super_property() const { return scope_uses_super_property_; }
+ // Does this scope access "super" property (super.foo).
bool NeedsHomeObject() const {
return scope_uses_super_property_ ||
(inner_scope_calls_eval_ && (IsConciseMethod(function_kind()) ||
diff --git a/chromium/v8/src/base/platform/platform-aix.cc b/chromium/v8/src/base/platform/platform-aix.cc
index dfc926ea981..6c1bde7b859 100644
--- a/chromium/v8/src/base/platform/platform-aix.cc
+++ b/chromium/v8/src/base/platform/platform-aix.cc
@@ -126,9 +126,6 @@ void* OS::ReserveAlignedRegion(size_t size, size_t alignment, void* hint,
DCHECK(aligned_size == request_size);
- address_ = static_cast<void*>(aligned_base);
- size_ = aligned_size;
-
*allocated = aligned_size;
return static_cast<void*>(aligned_base);
}
diff --git a/chromium/v8/src/bootstrapper.cc b/chromium/v8/src/bootstrapper.cc
index a0c91f4fef1..fe7d63fa956 100644
--- a/chromium/v8/src/bootstrapper.cc
+++ b/chromium/v8/src/bootstrapper.cc
@@ -1034,8 +1034,8 @@ void Genesis::CreateJSProxyMaps() {
// Allocate maps for all Proxy types.
// Next to the default proxy, we need maps indicating callable and
// constructable proxies.
- Handle<Map> proxy_map =
- factory()->NewMap(JS_PROXY_TYPE, JSProxy::kSize, PACKED_ELEMENTS);
+ Handle<Map> proxy_map = factory()->NewMap(JS_PROXY_TYPE, JSProxy::kSize,
+ TERMINAL_FAST_ELEMENTS_KIND);
proxy_map->set_dictionary_map(true);
proxy_map->set_may_have_interesting_symbols(true);
native_context()->set_proxy_map(*proxy_map);
@@ -1624,9 +1624,11 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
array_function->shared()->SetConstructStub(*code);
// Set up %ArrayPrototype%.
+ // The %ArrayPrototype% has TERMINAL_FAST_ELEMENTS_KIND in order to ensure
+ // that constant functions stay constant after turning prototype to setup
+ // mode and back when constant field tracking is enabled.
Handle<JSArray> proto =
- Handle<JSArray>::cast(factory->NewJSObject(array_function, TENURED));
- JSArray::Initialize(proto, 0);
+ factory->NewJSArray(0, TERMINAL_FAST_ELEMENTS_KIND, TENURED);
JSFunction::SetPrototype(array_function, proto);
native_context()->set_initial_array_prototype(*proto);
@@ -5482,7 +5484,7 @@ Genesis::Genesis(Isolate* isolate,
DCHECK_EQ(global_proxy_data->embedder_field_count(),
global_proxy_template->InternalFieldCount());
Handle<Map> global_proxy_map = isolate->factory()->NewMap(
- JS_GLOBAL_PROXY_TYPE, proxy_size, HOLEY_SMI_ELEMENTS);
+ JS_GLOBAL_PROXY_TYPE, proxy_size, TERMINAL_FAST_ELEMENTS_KIND);
global_proxy_map->set_is_access_check_needed(true);
global_proxy_map->set_has_hidden_prototype(true);
global_proxy_map->set_may_have_interesting_symbols(true);
diff --git a/chromium/v8/src/builtins/builtins-collections-gen.cc b/chromium/v8/src/builtins/builtins-collections-gen.cc
index a1928632abd..4aa7fa310b1 100644
--- a/chromium/v8/src/builtins/builtins-collections-gen.cc
+++ b/chromium/v8/src/builtins/builtins-collections-gen.cc
@@ -314,10 +314,11 @@ TF_BUILTIN(MapConstructor, CollectionsBuiltinsAssembler) {
BIND(&if_notobject);
{
- Node* const exception = MakeTypeError(
- MessageTemplate::kIteratorValueNotAnObject, context, next_value);
- var_exception.Bind(exception);
- Goto(&if_exception);
+ Node* ret = CallRuntime(
+ Runtime::kThrowTypeError, context,
+ SmiConstant(MessageTemplate::kIteratorValueNotAnObject), next_value);
+ GotoIfException(ret, &if_exception, &var_exception);
+ Unreachable();
}
}
diff --git a/chromium/v8/src/builtins/builtins-definitions.h b/chromium/v8/src/builtins/builtins-definitions.h
index 746051b6cd9..cc89c4e3650 100644
--- a/chromium/v8/src/builtins/builtins-definitions.h
+++ b/chromium/v8/src/builtins/builtins-definitions.h
@@ -1024,7 +1024,7 @@ namespace internal {
/* ES6 #sec-%typedarray%.prototype.reverse */ \
CPP(TypedArrayPrototypeReverse) \
/* ES6 %TypedArray%.prototype.set */ \
- CPP(TypedArrayPrototypeSet) \
+ TFJ(TypedArrayPrototypeSet, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-%typedarray%.prototype.slice */ \
CPP(TypedArrayPrototypeSlice) \
/* ES6 #sec-get-%typedarray%.prototype-@@tostringtag */ \
diff --git a/chromium/v8/src/builtins/builtins-proxy-gen.cc b/chromium/v8/src/builtins/builtins-proxy-gen.cc
index c4fd34290a8..29c5a4eaeb3 100644
--- a/chromium/v8/src/builtins/builtins-proxy-gen.cc
+++ b/chromium/v8/src/builtins/builtins-proxy-gen.cc
@@ -491,7 +491,7 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
Node* 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);
+ check_passed, &check_in_runtime, kReturnAccessorPair);
BIND(&if_found_value);
{
@@ -589,7 +589,7 @@ void ProxiesCodeStubAssembler::CheckHasTrapResult(Node* context, Node* target,
Node* 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, if_bailout);
+ check_passed, if_bailout, kReturnAccessorPair);
// 9.b. If targetDesc is not undefined, then (see 9.b.i. below).
BIND(&if_found_value);
diff --git a/chromium/v8/src/builtins/builtins-string-gen.cc b/chromium/v8/src/builtins/builtins-string-gen.cc
index 9cb0e474e21..8d407b35e61 100644
--- a/chromium/v8/src/builtins/builtins-string-gen.cc
+++ b/chromium/v8/src/builtins/builtins-string-gen.cc
@@ -1052,9 +1052,9 @@ void StringBuiltinsAssembler::RequireObjectCoercible(Node* const context,
}
void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
- Node* const context, Node* const object, Handle<Symbol> symbol,
- const NodeFunction0& regexp_call, const NodeFunction1& generic_call,
- CodeStubArguments* args) {
+ Node* const context, Node* const object, Node* const maybe_string,
+ Handle<Symbol> symbol, const NodeFunction0& regexp_call,
+ const NodeFunction1& generic_call, CodeStubArguments* args) {
Label out(this);
// Smis definitely don't have an attached symbol.
@@ -1084,14 +1084,21 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
}
// Take the fast path for RegExps.
+ // There's two conditions: {object} needs to be a fast regexp, and
+ // {maybe_string} must be a string (we can't call ToString on the fast path
+ // since it may mutate {object}).
{
Label stub_call(this), slow_lookup(this);
+ GotoIf(TaggedIsSmi(maybe_string), &slow_lookup);
+ GotoIfNot(IsString(maybe_string), &slow_lookup);
+
RegExpBuiltinsAssembler regexp_asm(state());
regexp_asm.BranchIfFastRegExp(context, object, object_map, &stub_call,
&slow_lookup);
BIND(&stub_call);
+ // TODO(jgruber): Add a no-JS scope once it exists.
Node* const result = regexp_call();
if (args == nullptr) {
Return(result);
@@ -1307,12 +1314,10 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
// Redirect to replacer method if {search[@@replace]} is not undefined.
MaybeCallFunctionAtSymbol(
- context, search, isolate()->factory()->replace_symbol(),
+ context, search, receiver, isolate()->factory()->replace_symbol(),
[=]() {
- Node* const subject_string = ToString_Inline(context, receiver);
-
- return CallBuiltin(Builtins::kRegExpReplace, context, search,
- subject_string, replace);
+ return CallBuiltin(Builtins::kRegExpReplace, context, search, receiver,
+ replace);
},
[=](Node* fn) {
Callable call_callable = CodeFactory::Call(isolate());
@@ -1550,12 +1555,10 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
// Redirect to splitter method if {separator[@@split]} is not undefined.
MaybeCallFunctionAtSymbol(
- context, separator, isolate()->factory()->split_symbol(),
+ context, separator, receiver, isolate()->factory()->split_symbol(),
[=]() {
- Node* const subject_string = ToString_Inline(context, receiver);
-
- return CallBuiltin(Builtins::kRegExpSplit, context, separator,
- subject_string, limit);
+ return CallBuiltin(Builtins::kRegExpSplit, context, separator, receiver,
+ limit);
},
[=](Node* fn) {
Callable call_callable = CodeFactory::Call(isolate());
diff --git a/chromium/v8/src/builtins/builtins-string-gen.h b/chromium/v8/src/builtins/builtins-string-gen.h
index 607f7b6acb2..c9af3802707 100644
--- a/chromium/v8/src/builtins/builtins-string-gen.h
+++ b/chromium/v8/src/builtins/builtins-string-gen.h
@@ -82,9 +82,11 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
// }
//
// Contains fast paths for Smi and RegExp objects.
+ // Important: {regexp_call} may not contain any code that can call into JS.
typedef std::function<Node*()> NodeFunction0;
typedef std::function<Node*(Node* fn)> NodeFunction1;
void MaybeCallFunctionAtSymbol(Node* const context, Node* const object,
+ Node* const maybe_string,
Handle<Symbol> symbol,
const NodeFunction0& regexp_call,
const NodeFunction1& generic_call,
diff --git a/chromium/v8/src/builtins/builtins-typedarray-gen.cc b/chromium/v8/src/builtins/builtins-typedarray-gen.cc
index a58f3a4093f..07f122b9098 100644
--- a/chromium/v8/src/builtins/builtins-typedarray-gen.cc
+++ b/chromium/v8/src/builtins/builtins-typedarray-gen.cc
@@ -10,6 +10,10 @@
namespace v8 {
namespace internal {
+using compiler::Node;
+template <class T>
+using TNode = compiler::TNode<T>;
+
// This is needed for gc_mole which will compile this file without the full set
// of GN defined macros.
#ifndef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
@@ -41,9 +45,37 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
Node* CalculateExternalPointer(Node* backing_store, Node* byte_offset);
Node* LoadDataPtr(Node* typed_array);
Node* ByteLengthIsValid(Node* byte_length);
+
+ // Loads the element kind of TypedArray instance.
+ TNode<Word32T> LoadElementsKind(TNode<Object> typed_array);
+
+ // Returns the byte size of an element for a TypedArray elements kind.
+ TNode<IntPtrT> GetTypedArrayElementSize(TNode<Word32T> elements_kind);
+
+ // Fast path for setting a TypedArray (source) onto another TypedArray
+ // (target) at an element offset.
+ void SetTypedArraySource(TNode<Context> context, TNode<JSTypedArray> source,
+ TNode<JSTypedArray> target, TNode<IntPtrT> offset,
+ Label* call_runtime, Label* if_source_too_large);
+
+ void SetJSArraySource(TNode<Context> context, TNode<JSArray> source,
+ TNode<JSTypedArray> target, TNode<IntPtrT> offset,
+ Label* call_runtime, Label* if_source_too_large);
+
+ void CallCMemmove(TNode<IntPtrT> dest_ptr, TNode<IntPtrT> src_ptr,
+ TNode<IntPtrT> byte_length);
+
+ void CallCCopyFastNumberJSArrayElementsToTypedArray(
+ TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> dest,
+ TNode<IntPtrT> source_length, TNode<IntPtrT> offset);
+
+ void CallCCopyTypedArrayElementsToTypedArray(TNode<JSTypedArray> source,
+ TNode<JSTypedArray> dest,
+ TNode<IntPtrT> source_length,
+ TNode<IntPtrT> offset);
};
-compiler::Node* TypedArrayBuiltinsAssembler::LoadMapForType(Node* array) {
+Node* TypedArrayBuiltinsAssembler::LoadMapForType(Node* array) {
CSA_ASSERT(this, IsJSTypedArray(array));
Label unreachable(this), done(this);
@@ -96,8 +128,8 @@ compiler::Node* TypedArrayBuiltinsAssembler::LoadMapForType(Node* array) {
// can't allocate an array bigger than our 32-bit arithmetic range anyway. 64
// bit platforms could theoretically have an offset up to 2^35 - 1, so we may
// need to convert the float heap number to an intptr.
-compiler::Node* TypedArrayBuiltinsAssembler::CalculateExternalPointer(
- Node* backing_store, Node* byte_offset) {
+Node* TypedArrayBuiltinsAssembler::CalculateExternalPointer(Node* backing_store,
+ Node* byte_offset) {
return IntPtrAdd(backing_store, ChangeNumberToIntPtr(byte_offset));
}
@@ -518,7 +550,7 @@ TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
}
}
-compiler::Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
+Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
CSA_ASSERT(this, IsJSTypedArray(typed_array));
Node* elements = LoadElements(typed_array);
CSA_ASSERT(this, IsFixedTypedArray(elements));
@@ -529,8 +561,7 @@ compiler::Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
return IntPtrAdd(base_pointer, external_pointer);
}
-compiler::Node* TypedArrayBuiltinsAssembler::ByteLengthIsValid(
- Node* byte_length) {
+Node* TypedArrayBuiltinsAssembler::ByteLengthIsValid(Node* byte_length) {
Label smi(this), done(this);
VARIABLE(is_valid, MachineRepresentation::kWord32);
GotoIf(TaggedIsSmi(byte_length), &smi);
@@ -674,6 +705,309 @@ TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
JSTypedArray::kLengthOffset);
}
+TNode<Word32T> TypedArrayBuiltinsAssembler::LoadElementsKind(
+ TNode<Object> typed_array) {
+ CSA_ASSERT(this, IsJSTypedArray(typed_array));
+ return Int32Sub(LoadMapElementsKind(LoadMap(CAST(typed_array))),
+ Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
+}
+
+TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
+ TNode<Word32T> elements_kind) {
+ TVARIABLE(IntPtrT, element_size);
+ Label next(this), if_unknown_type(this, Label::kDeferred);
+
+ size_t const kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
+ FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
+ 1;
+
+ int32_t elements_kinds[kTypedElementsKindCount] = {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ TYPE##_ELEMENTS - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+ };
+
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ Label if_##type##array(this);
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ Label* elements_kind_labels[kTypedElementsKindCount] = {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) &if_##type##array,
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+ };
+
+ Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
+ kTypedElementsKindCount);
+
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ BIND(&if_##type##array); \
+ { \
+ element_size = IntPtrConstant(size); \
+ Goto(&next); \
+ }
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ BIND(&if_unknown_type);
+ {
+ element_size = IntPtrConstant(0);
+ Goto(&next);
+ }
+ BIND(&next);
+ return element_size;
+}
+
+void TypedArrayBuiltinsAssembler::SetTypedArraySource(
+ TNode<Context> context, TNode<JSTypedArray> source,
+ TNode<JSTypedArray> target, TNode<IntPtrT> offset, Label* call_runtime,
+ Label* if_source_too_large) {
+ CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
+ LoadObjectField(source, JSTypedArray::kBufferOffset))));
+ CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
+ LoadObjectField(target, JSTypedArray::kBufferOffset))));
+ CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
+ CSA_ASSERT(this,
+ IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
+
+ // Check for possible range errors.
+
+ TNode<IntPtrT> source_length =
+ LoadAndUntagObjectField(source, JSTypedArray::kLengthOffset);
+ TNode<IntPtrT> target_length =
+ LoadAndUntagObjectField(target, JSTypedArray::kLengthOffset);
+ TNode<IntPtrT> required_target_length = IntPtrAdd(source_length, offset);
+
+ GotoIf(IntPtrGreaterThan(required_target_length, target_length),
+ if_source_too_large);
+
+ // Grab pointers and byte lengths we need later on.
+
+ TNode<IntPtrT> target_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(target));
+ TNode<IntPtrT> source_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(source));
+
+ TNode<Word32T> source_el_kind = LoadElementsKind(source);
+ TNode<Word32T> target_el_kind = LoadElementsKind(target);
+
+ TNode<IntPtrT> source_el_size = GetTypedArrayElementSize(source_el_kind);
+ TNode<IntPtrT> target_el_size = GetTypedArrayElementSize(target_el_kind);
+
+ // A note on byte lengths: both source- and target byte lengths must be valid,
+ // i.e. it must be possible to allocate an array of the given length. That
+ // means we're safe from overflows in the following multiplication.
+ TNode<IntPtrT> source_byte_length = IntPtrMul(source_length, source_el_size);
+ CSA_ASSERT(this,
+ IntPtrGreaterThanOrEqual(source_byte_length, IntPtrConstant(0)));
+
+ Label call_memmove(this), fast_c_call(this), out(this);
+ Branch(Word32Equal(source_el_kind, target_el_kind), &call_memmove,
+ &fast_c_call);
+
+ BIND(&call_memmove);
+ {
+ TNode<IntPtrT> target_start =
+ IntPtrAdd(target_data_ptr, IntPtrMul(offset, target_el_size));
+ CallCMemmove(target_start, source_data_ptr, source_byte_length);
+ Goto(&out);
+ }
+
+ BIND(&fast_c_call);
+ {
+ // Overlapping backing stores of different element kinds are handled in
+ // runtime. We're a bit conservative here and bail to runtime if ranges
+ // overlap and element kinds differ.
+
+ TNode<IntPtrT> target_byte_length =
+ IntPtrMul(target_length, target_el_size);
+ CSA_ASSERT(this,
+ IntPtrGreaterThanOrEqual(target_byte_length, IntPtrConstant(0)));
+
+ TNode<IntPtrT> target_data_end_ptr =
+ IntPtrAdd(target_data_ptr, target_byte_length);
+ TNode<IntPtrT> source_data_end_ptr =
+ IntPtrAdd(source_data_ptr, source_byte_length);
+
+ GotoIfNot(
+ Word32Or(IntPtrLessThanOrEqual(target_data_end_ptr, source_data_ptr),
+ IntPtrLessThanOrEqual(source_data_end_ptr, target_data_ptr)),
+ call_runtime);
+
+ TNode<IntPtrT> source_length =
+ LoadAndUntagObjectField(source, JSTypedArray::kLengthOffset);
+ CallCCopyTypedArrayElementsToTypedArray(source, target, source_length,
+ offset);
+ Goto(&out);
+ }
+
+ BIND(&out);
+}
+
+void TypedArrayBuiltinsAssembler::SetJSArraySource(
+ TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> target,
+ TNode<IntPtrT> offset, Label* call_runtime, Label* if_source_too_large) {
+ CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
+ CSA_ASSERT(this,
+ IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
+
+ TNode<IntPtrT> source_length = SmiUntag(LoadFastJSArrayLength(source));
+ TNode<IntPtrT> target_length =
+ LoadAndUntagObjectField(target, JSTypedArray::kLengthOffset);
+
+ // Maybe out of bounds?
+ GotoIf(IntPtrGreaterThan(IntPtrAdd(source_length, offset), target_length),
+ if_source_too_large);
+
+ // Nothing to do if {source} is empty.
+ Label out(this), fast_c_call(this);
+ GotoIf(IntPtrEqual(source_length, IntPtrConstant(0)), &out);
+
+ // Dispatch based on the source elements kind.
+ {
+ // These are the supported elements kinds in TryCopyElementsFastNumber.
+ int32_t values[] = {
+ PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS,
+ HOLEY_DOUBLE_ELEMENTS,
+ };
+ Label* labels[] = {
+ &fast_c_call, &fast_c_call, &fast_c_call, &fast_c_call,
+ };
+ STATIC_ASSERT(arraysize(values) == arraysize(labels));
+
+ TNode<Int32T> source_elements_kind = LoadMapElementsKind(LoadMap(source));
+ Switch(source_elements_kind, call_runtime, values, labels,
+ arraysize(values));
+ }
+
+ BIND(&fast_c_call);
+ CallCCopyFastNumberJSArrayElementsToTypedArray(context, source, target,
+ source_length, offset);
+ Goto(&out);
+ BIND(&out);
+}
+
+void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<IntPtrT> dest_ptr,
+ TNode<IntPtrT> src_ptr,
+ TNode<IntPtrT> byte_length) {
+ TNode<ExternalReference> memmove =
+ ExternalConstant(ExternalReference::libc_memmove_function(isolate()));
+ CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
+ MachineType::Pointer(), MachineType::UintPtr(), memmove,
+ dest_ptr, src_ptr, byte_length);
+}
+
+void TypedArrayBuiltinsAssembler::
+ CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,
+ TNode<JSArray> source,
+ TNode<JSTypedArray> dest,
+ TNode<IntPtrT> source_length,
+ TNode<IntPtrT> offset) {
+ TNode<ExternalReference> f = ExternalConstant(
+ ExternalReference::copy_fast_number_jsarray_elements_to_typed_array(
+ isolate()));
+ CallCFunction5(MachineType::AnyTagged(), MachineType::AnyTagged(),
+ MachineType::AnyTagged(), MachineType::AnyTagged(),
+ MachineType::UintPtr(), MachineType::UintPtr(), f, context,
+ source, dest, source_length, offset);
+}
+
+void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray(
+ TNode<JSTypedArray> source, TNode<JSTypedArray> dest,
+ TNode<IntPtrT> source_length, TNode<IntPtrT> offset) {
+ TNode<ExternalReference> f = ExternalConstant(
+ ExternalReference::copy_typed_array_elements_to_typed_array(isolate()));
+ CallCFunction4(MachineType::AnyTagged(), MachineType::AnyTagged(),
+ MachineType::AnyTagged(), MachineType::UintPtr(),
+ MachineType::UintPtr(), f, source, dest, source_length,
+ offset);
+}
+
+// ES #sec-get-%typedarray%.prototype.set
+TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
+ TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
+ CodeStubArguments args(
+ this, ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)));
+
+ Label if_source_is_typed_array(this), if_source_is_fast_jsarray(this),
+ if_offset_is_out_of_bounds(this, Label::kDeferred),
+ if_source_too_large(this, Label::kDeferred),
+ if_typed_array_is_neutered(this, Label::kDeferred),
+ if_receiver_is_not_typedarray(this, Label::kDeferred);
+
+ // Check the receiver is a typed array.
+ TNode<Object> receiver = args.GetReceiver();
+ GotoIf(TaggedIsSmi(receiver), &if_receiver_is_not_typedarray);
+ GotoIfNot(IsJSTypedArray(receiver), &if_receiver_is_not_typedarray);
+
+ // Normalize offset argument (using ToInteger) and handle heap number cases.
+ TNode<Object> offset = args.GetOptionalArgumentValue(1, SmiConstant(0));
+ TNode<Object> offset_num = ToInteger(context, offset, kTruncateMinusZero);
+ CSA_ASSERT(this, IsNumberNormalized(offset_num));
+
+ // Since ToInteger always returns a Smi if the given value is within Smi
+ // range, and the only corner case of -0.0 has already been truncated to 0.0,
+ // we can simply throw unless the offset is a non-negative Smi.
+ // TODO(jgruber): It's an observable spec violation to throw here if
+ // {offset_num} is a positive number outside the Smi range. Per spec, we need
+ // to check for detached buffers and call the observable ToObject/ToLength
+ // operations first.
+ GotoIfNot(TaggedIsPositiveSmi(offset_num), &if_offset_is_out_of_bounds);
+ TNode<Smi> offset_smi = CAST(offset_num);
+
+ // Check the receiver is not neutered.
+ TNode<Object> receiver_buffer =
+ LoadObjectField(CAST(receiver), JSTypedArray::kBufferOffset);
+ GotoIf(IsDetachedBuffer(receiver_buffer), &if_typed_array_is_neutered);
+
+ // Check the source argument is valid and whether a fast path can be taken.
+ Label call_runtime(this);
+ TNode<Object> source = args.GetOptionalArgumentValue(0);
+ GotoIf(TaggedIsSmi(source), &call_runtime);
+ GotoIf(IsJSTypedArray(source), &if_source_is_typed_array);
+ BranchIfFastJSArray(source, context, &if_source_is_fast_jsarray,
+ &call_runtime);
+
+ // Fast path for a typed array source argument.
+ BIND(&if_source_is_typed_array);
+ {
+ // Check the source argument is not neutered.
+ TNode<Object> source_buffer =
+ LoadObjectField(CAST(source), JSTypedArray::kBufferOffset);
+ GotoIf(IsDetachedBuffer(source_buffer), &if_typed_array_is_neutered);
+
+ SetTypedArraySource(context, CAST(source), CAST(receiver),
+ SmiUntag(offset_smi), &call_runtime,
+ &if_source_too_large);
+ args.PopAndReturn(UndefinedConstant());
+ }
+
+ // Fast path for a fast JSArray source argument.
+ BIND(&if_source_is_fast_jsarray);
+ {
+ SetJSArraySource(context, CAST(source), CAST(receiver),
+ SmiUntag(offset_smi), &call_runtime, &if_source_too_large);
+ args.PopAndReturn(UndefinedConstant());
+ }
+
+ BIND(&call_runtime);
+ args.PopAndReturn(CallRuntime(Runtime::kTypedArraySet, context, receiver,
+ source, offset_smi));
+
+ BIND(&if_offset_is_out_of_bounds);
+ ThrowRangeError(context, MessageTemplate::kTypedArraySetOffsetOutOfBounds);
+
+ BIND(&if_source_too_large);
+ ThrowRangeError(context, MessageTemplate::kTypedArraySetSourceTooLarge);
+
+ BIND(&if_typed_array_is_neutered);
+ ThrowTypeError(context, MessageTemplate::kDetachedOperation,
+ "%TypedArray%.prototype.set");
+
+ BIND(&if_receiver_is_not_typedarray);
+ ThrowTypeError(context, MessageTemplate::kNotTypedArray);
+}
+
// ES #sec-get-%typedarray%.prototype-@@tostringtag
TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver);
diff --git a/chromium/v8/src/builtins/builtins-typedarray.cc b/chromium/v8/src/builtins/builtins-typedarray.cc
index 3d40d3755f8..176a79965b2 100644
--- a/chromium/v8/src/builtins/builtins-typedarray.cc
+++ b/chromium/v8/src/builtins/builtins-typedarray.cc
@@ -277,302 +277,6 @@ BUILTIN(TypedArrayPrototypeReverse) {
return *array;
}
-namespace {
-Object* TypedArrayCopyElements(Handle<JSTypedArray> target,
- Handle<JSReceiver> source, Object* length_obj) {
- size_t length;
- CHECK(TryNumberToSize(length_obj, &length));
-
- ElementsAccessor* accessor = target->GetElementsAccessor();
- return accessor->CopyElements(source, target, length);
-}
-
-enum class TypedArraySetResultCodes {
- // Set from typed array of the same type.
- // This is processed by TypedArraySetFastCases
- SAME_TYPE,
- // Set from typed array of the different type, overlapping in memory.
- OVERLAPPING,
- // Set from typed array of the different type, non-overlapping.
- NONOVERLAPPING,
- // Set from non-typed array.
- NON_TYPED_ARRAY
-};
-
-MaybeHandle<Object> TypedArraySetFromArrayLike(Isolate* isolate,
- Handle<JSTypedArray> target,
- Handle<Object> source,
- int source_length, int offset) {
- DCHECK_GE(source_length, 0);
- DCHECK_GE(offset, 0);
-
- for (int i = 0; i < source_length; i++) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::GetElement(isolate, source, i), Object);
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::SetElement(isolate, target, offset + i,
- value, LanguageMode::STRICT),
- Object);
- }
-
- return target;
-}
-
-MaybeHandle<Object> TypedArraySetFromOverlapping(Isolate* isolate,
- Handle<JSTypedArray> target,
- Handle<JSTypedArray> source,
- int offset) {
- DCHECK_GE(offset, 0);
-
- size_t sourceElementSize = source->element_size();
- size_t targetElementSize = target->element_size();
-
- uint32_t source_length = source->length_value();
- if (source_length == 0) return target;
-
- // Copy left part.
-
- // First un-mutated byte after the next write
- uint32_t target_ptr = 0;
- CHECK(target->byte_offset()->ToUint32(&target_ptr));
- target_ptr += (offset + 1) * targetElementSize;
-
- // Next read at sourcePtr. We do not care for memory changing before
- // sourcePtr - we have already copied it.
- uint32_t source_ptr = 0;
- CHECK(source->byte_offset()->ToUint32(&source_ptr));
-
- uint32_t left_index;
- for (left_index = 0; left_index < source_length && target_ptr <= source_ptr;
- left_index++) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::GetElement(isolate, source, left_index),
- Object);
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value,
- Object::SetElement(isolate, target, offset + left_index, value,
- LanguageMode::STRICT),
- Object);
-
- target_ptr += targetElementSize;
- source_ptr += sourceElementSize;
- }
-
- // Copy right part;
- // First unmutated byte before the next write
- CHECK(target->byte_offset()->ToUint32(&target_ptr));
- target_ptr += (offset + source_length - 1) * targetElementSize;
-
- // Next read before sourcePtr. We do not care for memory changing after
- // sourcePtr - we have already copied it.
- CHECK(target->byte_offset()->ToUint32(&source_ptr));
- source_ptr += source_length * sourceElementSize;
-
- uint32_t right_index;
- DCHECK_GE(source_length, 1);
- for (right_index = source_length - 1;
- right_index > left_index && target_ptr >= source_ptr; right_index--) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::GetElement(isolate, source, right_index),
- Object);
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value,
- Object::SetElement(isolate, target, offset + right_index, value,
- LanguageMode::STRICT),
- Object);
-
- target_ptr -= targetElementSize;
- source_ptr -= sourceElementSize;
- }
-
- std::vector<Handle<Object>> temp(right_index + 1 - left_index);
-
- for (uint32_t i = left_index; i <= right_index; i++) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::GetElement(isolate, source, i), Object);
- temp[i - left_index] = value;
- }
-
- for (uint32_t i = left_index; i <= right_index; i++) {
- Handle<Object> value;
-
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value,
- Object::SetElement(isolate, target, offset + i, temp[i - left_index],
- LanguageMode::STRICT),
- Object);
- }
-
- return target;
-}
-
-MaybeHandle<Smi> TypedArraySetFastCases(Isolate* isolate,
- Handle<JSTypedArray> target,
- Handle<Object> source_obj,
- Handle<Object> offset_obj) {
- if (!source_obj->IsJSTypedArray()) {
- return MaybeHandle<Smi>(
- Smi::FromEnum(TypedArraySetResultCodes::NON_TYPED_ARRAY), isolate);
- }
-
- Handle<JSTypedArray> source = Handle<JSTypedArray>::cast(source_obj);
-
- size_t offset = 0;
- CHECK(TryNumberToSize(*offset_obj, &offset));
- size_t target_length = target->length_value();
- size_t source_length = source->length_value();
- size_t target_byte_length = NumberToSize(target->byte_length());
- size_t source_byte_length = NumberToSize(source->byte_length());
- if (offset > target_length || offset + source_length > target_length ||
- offset + source_length < offset) { // overflow
- THROW_NEW_ERROR(
- isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge),
- Smi);
- }
-
- size_t target_offset = NumberToSize(target->byte_offset());
- size_t source_offset = NumberToSize(source->byte_offset());
- uint8_t* target_base =
- static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
- target_offset;
- uint8_t* source_base =
- static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
- source_offset;
-
- // Typed arrays of the same type: use memmove.
- if (target->type() == source->type()) {
- memmove(target_base + offset * target->element_size(), source_base,
- source_byte_length);
- return MaybeHandle<Smi>(Smi::FromEnum(TypedArraySetResultCodes::SAME_TYPE),
- isolate);
- }
-
- // Typed arrays of different types over the same backing store
- if ((source_base <= target_base &&
- source_base + source_byte_length > target_base) ||
- (target_base <= source_base &&
- target_base + target_byte_length > source_base)) {
- // We do not support overlapping ArrayBuffers
- DCHECK(target->GetBuffer()->backing_store() ==
- source->GetBuffer()->backing_store());
- return MaybeHandle<Smi>(
- Smi::FromEnum(TypedArraySetResultCodes::OVERLAPPING), isolate);
- } else { // Non-overlapping typed arrays
- return MaybeHandle<Smi>(
- Smi::FromEnum(TypedArraySetResultCodes::NONOVERLAPPING), isolate);
- }
-}
-
-} // anonymous namespace
-
-// 22.2.3.23%TypedArray%.prototype.set ( overloaded [ , offset ] )
-BUILTIN(TypedArrayPrototypeSet) {
- HandleScope scope(isolate);
-
- Handle<Object> target = args.receiver();
- Handle<Object> obj = args.atOrUndefined(isolate, 1);
- Handle<Object> offset = args.atOrUndefined(isolate, 2);
-
- if (offset->IsUndefined(isolate)) {
- offset = Handle<Object>(Smi::kZero, isolate);
- } else {
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, offset,
- Object::ToInteger(isolate, offset));
- }
-
- if (offset->Number() < 0) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewRangeError(MessageTemplate::kTypedArraySetNegativeOffset));
- }
-
- if (offset->Number() > Smi::kMaxValue) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
- }
-
- if (!target->IsJSTypedArray()) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewTypeError(MessageTemplate::kNotTypedArray));
- }
- auto int_offset = static_cast<int>(offset->Number());
-
- Handle<Smi> result_code;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result_code,
- TypedArraySetFastCases(isolate, Handle<JSTypedArray>::cast(target), obj,
- offset));
-
- switch (static_cast<TypedArraySetResultCodes>(result_code->value())) {
- case TypedArraySetResultCodes::SAME_TYPE: {
- break;
- }
- case TypedArraySetResultCodes::OVERLAPPING: {
- RETURN_FAILURE_ON_EXCEPTION(
- isolate, TypedArraySetFromOverlapping(
- isolate, Handle<JSTypedArray>::cast(target),
- Handle<JSTypedArray>::cast(obj), int_offset));
- break;
- }
- case TypedArraySetResultCodes::NONOVERLAPPING: {
- if (int_offset == 0) {
- TypedArrayCopyElements(Handle<JSTypedArray>::cast(target),
- Handle<JSTypedArray>::cast(obj),
- Handle<JSTypedArray>::cast(obj)->length());
- } else {
- RETURN_FAILURE_ON_EXCEPTION(
- isolate,
- TypedArraySetFromArrayLike(
- isolate, Handle<JSTypedArray>::cast(target), obj,
- Handle<JSTypedArray>::cast(obj)->length_value(), int_offset));
- }
- break;
- }
- case TypedArraySetResultCodes::NON_TYPED_ARRAY: {
- if (obj->IsNumber()) {
- // For number as a first argument, throw TypeError
- // instead of silently ignoring the call, so that
- // users know they did something wrong.
- // (Consistent with Firefox and Blink/WebKit)
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewTypeError(MessageTemplate::kInvalidArgument));
- }
-
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, obj,
- Object::ToObject(isolate, obj));
-
- Handle<Object> len;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, len,
- Object::GetProperty(obj, isolate->factory()->length_string()));
- if (len->IsUndefined(isolate)) {
- break;
- }
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len,
- Object::ToLength(isolate, len));
-
- DCHECK_GE(int_offset, 0);
- if (int_offset + len->Number() >
- Handle<JSTypedArray>::cast(target)->length_value()) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate,
- NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
- }
- uint32_t int_l;
- CHECK(DoubleToUint32IfEqualToSelf(len->Number(), &int_l));
- RETURN_FAILURE_ON_EXCEPTION(
- isolate, TypedArraySetFromArrayLike(
- isolate, Handle<JSTypedArray>::cast(target), obj, int_l,
- int_offset));
- } break;
- }
-
- return *isolate->factory()->undefined_value();
-}
-
BUILTIN(TypedArrayPrototypeSlice) {
HandleScope scope(isolate);
diff --git a/chromium/v8/src/code-stub-assembler.cc b/chromium/v8/src/code-stub-assembler.cc
index 612d9b76af7..0c64d011d41 100644
--- a/chromium/v8/src/code-stub-assembler.cc
+++ b/chromium/v8/src/code-stub-assembler.cc
@@ -1253,8 +1253,8 @@ TNode<Int32T> CodeStubAssembler::LoadHashForJSObject(
{
Node* length_and_hash_int32 = LoadAndUntagToWord32ObjectField(
properties_or_hash, PropertyArray::kLengthAndHashOffset);
- var_hash.Bind(Word32And(length_and_hash_int32,
- Int32Constant(PropertyArray::kHashMask)));
+ var_hash.Bind(
+ DecodeWord32<PropertyArray::HashField>(length_and_hash_int32));
Goto(&done);
}
@@ -2322,6 +2322,7 @@ Node* CodeStubAssembler::AllocateNameDictionary(Node* at_least_space_for) {
Node* CodeStubAssembler::AllocateNameDictionaryWithCapacity(Node* capacity) {
CSA_ASSERT(this, WordIsPowerOfTwo(capacity));
+ CSA_ASSERT(this, IntPtrGreaterThan(capacity, IntPtrConstant(0)));
Node* length = EntryToIndex<NameDictionary>(capacity);
Node* store_size = IntPtrAdd(TimesPointerSize(length),
IntPtrConstant(NameDictionary::kHeaderSize));
@@ -2644,7 +2645,8 @@ void CodeStubAssembler::InitializePropertyArrayLength(Node* property_array,
CSA_ASSERT(
this,
IntPtrOrSmiLessThanOrEqual(
- length, IntPtrOrSmiConstant(PropertyArray::kMaxLength, mode), mode));
+ length, IntPtrOrSmiConstant(PropertyArray::LengthField::kMax, mode),
+ mode));
StoreObjectFieldNoWriteBarrier(
property_array, PropertyArray::kLengthAndHashOffset,
ParameterToTagged(length, mode), MachineRepresentation::kTaggedSigned);
@@ -3539,6 +3541,23 @@ Node* CodeStubAssembler::ThrowIfNotInstanceType(Node* context, Node* value,
return var_value_map.value();
}
+void CodeStubAssembler::ThrowRangeError(Node* context,
+ MessageTemplate::Template message,
+ Node* arg0, Node* arg1, Node* arg2) {
+ Node* template_index = SmiConstant(message);
+ if (arg0 == nullptr) {
+ CallRuntime(Runtime::kThrowRangeError, context, template_index);
+ } else if (arg1 == nullptr) {
+ CallRuntime(Runtime::kThrowRangeError, context, template_index, arg0);
+ } else if (arg2 == nullptr) {
+ CallRuntime(Runtime::kThrowRangeError, context, template_index, arg0, arg1);
+ } else {
+ CallRuntime(Runtime::kThrowRangeError, context, template_index, arg0, arg1,
+ arg2);
+ }
+ Unreachable();
+}
+
void CodeStubAssembler::ThrowTypeError(Node* context,
MessageTemplate::Template message,
char const* arg0, char const* arg1) {
@@ -6166,7 +6185,8 @@ void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary,
// Returns either the original value, or the result of the getter call.
Node* CodeStubAssembler::CallGetterIfAccessor(Node* value, Node* details,
Node* context, Node* receiver,
- Label* if_bailout) {
+ Label* if_bailout,
+ GetOwnPropertyMode mode) {
VARIABLE(var_value, MachineRepresentation::kTagged, value);
Label done(this), if_accessor_info(this, Label::kDeferred);
@@ -6178,23 +6198,26 @@ Node* CodeStubAssembler::CallGetterIfAccessor(Node* value, Node* details,
// AccessorPair case.
{
- Node* accessor_pair = value;
- Node* getter = LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
- Node* getter_map = LoadMap(getter);
- Node* instance_type = LoadMapInstanceType(getter_map);
- // FunctionTemplateInfo getters are not supported yet.
- GotoIf(
- Word32Equal(instance_type, Int32Constant(FUNCTION_TEMPLATE_INFO_TYPE)),
- if_bailout);
-
- // Return undefined if the {getter} is not callable.
- var_value.Bind(UndefinedConstant());
- GotoIfNot(IsCallableMap(getter_map), &done);
-
- // Call the accessor.
- Callable callable = CodeFactory::Call(isolate());
- Node* result = CallJS(callable, context, getter, receiver);
- var_value.Bind(result);
+ 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);
+ // FunctionTemplateInfo getters are not supported yet.
+ GotoIf(Word32Equal(instance_type,
+ Int32Constant(FUNCTION_TEMPLATE_INFO_TYPE)),
+ if_bailout);
+
+ // Return undefined if the {getter} is not callable.
+ var_value.Bind(UndefinedConstant());
+ GotoIfNot(IsCallableMap(getter_map), &done);
+
+ // Call the accessor.
+ Callable callable = CodeFactory::Call(isolate());
+ Node* result = CallJS(callable, context, getter, receiver);
+ var_value.Bind(result);
+ }
Goto(&done);
}
@@ -6264,14 +6287,14 @@ void CodeStubAssembler::TryGetOwnProperty(
Label* if_not_found, Label* if_bailout) {
TryGetOwnProperty(context, receiver, object, map, instance_type, unique_name,
if_found_value, var_value, nullptr, nullptr, if_not_found,
- if_bailout);
+ if_bailout, kCallJSGetter);
}
void CodeStubAssembler::TryGetOwnProperty(
Node* context, Node* receiver, Node* object, Node* map, Node* instance_type,
Node* unique_name, Label* if_found_value, Variable* var_value,
Variable* var_details, Variable* var_raw_value, Label* if_not_found,
- Label* if_bailout) {
+ Label* if_bailout, GetOwnPropertyMode mode) {
DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
Comment("TryGetOwnProperty");
@@ -6322,7 +6345,7 @@ void CodeStubAssembler::TryGetOwnProperty(
var_raw_value->Bind(var_value->value());
}
Node* value = CallGetterIfAccessor(var_value->value(), var_details->value(),
- context, receiver, if_bailout);
+ context, receiver, if_bailout, mode);
var_value->Bind(value);
Goto(if_found_value);
}
diff --git a/chromium/v8/src/code-stub-assembler.h b/chromium/v8/src/code-stub-assembler.h
index 7c7777e1acc..a2d5e800156 100644
--- a/chromium/v8/src/code-stub-assembler.h
+++ b/chromium/v8/src/code-stub-assembler.h
@@ -867,6 +867,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* ThrowIfNotInstanceType(Node* context, Node* value,
InstanceType instance_type,
char const* method_name);
+
+ void ThrowRangeError(Node* context, MessageTemplate::Template message,
+ Node* arg0 = nullptr, Node* arg1 = nullptr,
+ Node* arg2 = nullptr);
void ThrowTypeError(Node* context, MessageTemplate::Template message,
char const* arg0 = nullptr, char const* arg1 = nullptr);
void ThrowTypeError(Node* context, MessageTemplate::Template message,
@@ -1321,6 +1325,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* unique_name, Label* if_found,
Label* if_not_found, Label* if_bailout);
+ // Operating mode for TryGetOwnProperty and CallGetterIfAccessor
+ // kReturnAccessorPair is used when we're only getting the property descriptor
+ enum GetOwnPropertyMode { kCallJSGetter, kReturnAccessorPair };
// Tries to get {object}'s own {unique_name} property value. If the property
// is an accessor then it also calls a getter. If the property is a double
// field it re-wraps value in an immutable heap number.
@@ -1332,7 +1339,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* instance_type, Node* unique_name,
Label* if_found, Variable* var_value,
Variable* var_details, Variable* var_raw_value,
- Label* if_not_found, Label* if_bailout);
+ Label* if_not_found, Label* if_bailout,
+ GetOwnPropertyMode mode);
Node* GetProperty(Node* context, Node* receiver, Handle<Name> name) {
return GetProperty(context, receiver, HeapConstant(name));
@@ -1669,7 +1677,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* DescriptorArrayGetKey(Node* descriptors, Node* descriptor_number);
Node* CallGetterIfAccessor(Node* value, Node* details, Node* context,
- Node* receiver, Label* if_bailout);
+ Node* receiver, Label* if_bailout,
+ GetOwnPropertyMode mode = kCallJSGetter);
Node* TryToIntptr(Node* key, Label* miss);
diff --git a/chromium/v8/src/compiler/arm/code-generator-arm.cc b/chromium/v8/src/compiler/arm/code-generator-arm.cc
index c2de64467fd..fa9f6a027e6 100644
--- a/chromium/v8/src/compiler/arm/code-generator-arm.cc
+++ b/chromium/v8/src/compiler/arm/code-generator-arm.cc
@@ -424,51 +424,51 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
__ dmb(ISH); \
} while (0)
-#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_instr, store_instr) \
- do { \
- Label exchange; \
- __ dmb(ISH); \
- __ bind(&exchange); \
- __ add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
- __ load_instr(i.OutputRegister(0), i.TempRegister(0)); \
- __ store_instr(i.TempRegister(0), i.InputRegister(2), i.TempRegister(0)); \
- __ teq(i.TempRegister(0), Operand(0)); \
- __ b(ne, &exchange); \
- __ dmb(ISH); \
+#define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_instr, store_instr) \
+ do { \
+ Label exchange; \
+ __ add(i.InputRegister(0), i.InputRegister(0), i.InputRegister(1)); \
+ __ dmb(ISH); \
+ __ bind(&exchange); \
+ __ load_instr(i.OutputRegister(0), i.InputRegister(0)); \
+ __ store_instr(i.TempRegister(0), i.InputRegister(2), i.InputRegister(0)); \
+ __ teq(i.TempRegister(0), Operand(0)); \
+ __ b(ne, &exchange); \
+ __ dmb(ISH); \
} while (0)
-#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_instr, store_instr) \
+#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_instr, store_instr) \
+ do { \
+ Label compareExchange; \
+ Label exit; \
+ __ add(i.InputRegister(0), i.InputRegister(0), i.InputRegister(1)); \
+ __ dmb(ISH); \
+ __ bind(&compareExchange); \
+ __ load_instr(i.OutputRegister(0), i.InputRegister(0)); \
+ __ teq(i.InputRegister(2), Operand(i.OutputRegister(0))); \
+ __ b(ne, &exit); \
+ __ store_instr(i.TempRegister(0), i.InputRegister(3), i.InputRegister(0)); \
+ __ teq(i.TempRegister(0), Operand(0)); \
+ __ b(ne, &compareExchange); \
+ __ bind(&exit); \
+ __ dmb(ISH); \
+ } while (0)
+
+#define ASSEMBLE_ATOMIC_BINOP(load_instr, store_instr, bin_instr) \
do { \
- Label compareExchange; \
- Label exit; \
+ Label binop; \
+ __ add(i.InputRegister(0), i.InputRegister(0), i.InputRegister(1)); \
__ dmb(ISH); \
- __ bind(&compareExchange); \
- __ add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
- __ load_instr(i.OutputRegister(0), i.TempRegister(0)); \
- __ teq(i.TempRegister(1), Operand(i.OutputRegister(0))); \
- __ b(ne, &exit); \
- __ store_instr(i.TempRegister(0), i.InputRegister(3), i.TempRegister(0)); \
- __ teq(i.TempRegister(0), Operand(0)); \
- __ b(ne, &compareExchange); \
- __ bind(&exit); \
+ __ bind(&binop); \
+ __ load_instr(i.OutputRegister(0), i.InputRegister(0)); \
+ __ bin_instr(i.TempRegister(0), i.OutputRegister(0), \
+ Operand(i.InputRegister(2))); \
+ __ store_instr(i.TempRegister(1), i.TempRegister(0), i.InputRegister(0)); \
+ __ teq(i.TempRegister(1), Operand(0)); \
+ __ b(ne, &binop); \
__ dmb(ISH); \
} while (0)
-#define ASSEMBLE_ATOMIC_BINOP(load_instr, store_instr, bin_instr) \
- do { \
- Label binop; \
- __ add(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1)); \
- __ dmb(ISH); \
- __ bind(&binop); \
- __ load_instr(i.OutputRegister(0), i.TempRegister(0)); \
- __ bin_instr(i.TempRegister(1), i.OutputRegister(0), \
- Operand(i.InputRegister(2))); \
- __ store_instr(i.TempRegister(1), i.TempRegister(1), i.TempRegister(0)); \
- __ teq(i.TempRegister(1), Operand(0)); \
- __ b(ne, &binop); \
- __ dmb(ISH); \
- } while (0)
-
#define ASSEMBLE_IEEE754_BINOP(name) \
do { \
/* TODO(bmeurer): We should really get rid of this special instruction, */ \
@@ -2588,25 +2588,24 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(ldrex, strex);
break;
case kAtomicCompareExchangeInt8:
- __ uxtb(i.TempRegister(1), i.InputRegister(2));
+ __ uxtb(i.InputRegister(2), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexb, strexb);
__ sxtb(i.OutputRegister(0), i.OutputRegister(0));
break;
case kAtomicCompareExchangeUint8:
- __ uxtb(i.TempRegister(1), i.InputRegister(2));
+ __ uxtb(i.InputRegister(2), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexb, strexb);
break;
case kAtomicCompareExchangeInt16:
- __ uxth(i.TempRegister(1), i.InputRegister(2));
+ __ uxth(i.InputRegister(2), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexh, strexh);
__ sxth(i.OutputRegister(0), i.OutputRegister(0));
break;
case kAtomicCompareExchangeUint16:
- __ uxth(i.TempRegister(1), i.InputRegister(2));
+ __ uxth(i.InputRegister(2), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrexh, strexh);
break;
case kAtomicCompareExchangeWord32:
- __ mov(i.TempRegister(1), i.InputRegister(2));
ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(ldrex, strex);
break;
#define ATOMIC_BINOP_CASE(op, inst) \
@@ -2633,6 +2632,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ATOMIC_BINOP_CASE(Or, orr)
ATOMIC_BINOP_CASE(Xor, eor)
#undef ATOMIC_BINOP_CASE
+#undef ASSEMBLE_CHECKED_LOAD_FP
+#undef ASSEMBLE_CHECKED_LOAD_INTEGER
+#undef ASSEMBLE_CHECKED_STORE_FP
+#undef ASSEMBLE_CHECKED_STORE_INTEGER
+#undef ASSEMBLE_ATOMIC_LOAD_INTEGER
+#undef ASSEMBLE_ATOMIC_STORE_INTEGER
+#undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER
+#undef ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER
+#undef ASSEMBLE_ATOMIC_BINOP
+#undef ASSEMBLE_IEEE754_BINOP
+#undef ASSEMBLE_IEEE754_UNOP
+#undef ASSEMBLE_NEON_NARROWING_OP
+#undef ASSEMBLE_NEON_PAIRWISE_OP
}
return kSuccess;
} // NOLINT(readability/fn_size)
@@ -3226,6 +3238,7 @@ void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
}
#undef __
+#undef kScratchReg
} // namespace compiler
} // namespace internal
diff --git a/chromium/v8/src/compiler/arm/instruction-selector-arm.cc b/chromium/v8/src/compiler/arm/instruction-selector-arm.cc
index 75021eb9d31..391356e960b 100644
--- a/chromium/v8/src/compiler/arm/instruction-selector-arm.cc
+++ b/chromium/v8/src/compiler/arm/instruction-selector-arm.cc
@@ -2275,10 +2275,10 @@ void InstructionSelector::VisitAtomicExchange(Node* node) {
InstructionOperand inputs[3];
size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base);
- inputs[input_count++] = g.UseUniqueRegister(index);
+ inputs[input_count++] = g.UseRegister(index);
inputs[input_count++] = g.UseUniqueRegister(value);
InstructionOperand outputs[1];
- outputs[0] = g.UseUniqueRegister(node);
+ outputs[0] = g.DefineAsRegister(node);
InstructionOperand temp[1];
temp[0] = g.TempRegister();
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
@@ -2312,16 +2312,15 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) {
InstructionOperand inputs[4];
size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base);
- inputs[input_count++] = g.UseUniqueRegister(index);
+ inputs[input_count++] = g.UseRegister(index);
inputs[input_count++] = g.UseUniqueRegister(old_value);
inputs[input_count++] = g.UseUniqueRegister(new_value);
InstructionOperand outputs[1];
- outputs[0] = g.UseUniqueRegister(node);
- InstructionOperand temp[2];
+ outputs[0] = g.DefineAsRegister(node);
+ InstructionOperand temp[1];
temp[0] = g.TempRegister();
- temp[1] = g.TempRegister();
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
- Emit(code, 1, outputs, input_count, inputs, 2, temp);
+ Emit(code, 1, outputs, input_count, inputs, 1, temp);
}
void InstructionSelector::VisitAtomicBinaryOperation(
@@ -2352,15 +2351,16 @@ void InstructionSelector::VisitAtomicBinaryOperation(
InstructionOperand inputs[3];
size_t input_count = 0;
inputs[input_count++] = g.UseUniqueRegister(base);
- inputs[input_count++] = g.UseUniqueRegister(index);
+ inputs[input_count++] = g.UseRegister(index);
inputs[input_count++] = g.UseUniqueRegister(value);
InstructionOperand outputs[1];
- outputs[0] = g.UseUniqueRegister(node);
+ outputs[0] = g.DefineAsRegister(node);
InstructionOperand temps[2];
- temps[0] = g.TempRegister();
- temps[1] = g.TempRegister();
+ size_t temp_count = 0;
+ temps[temp_count++] = g.TempRegister();
+ temps[temp_count++] = g.TempRegister();
InstructionCode code = opcode | AddressingModeField::encode(addressing_mode);
- Emit(code, 1, outputs, input_count, inputs, 2, temps);
+ Emit(code, 1, outputs, input_count, inputs, temp_count, temps);
}
#define VISIT_ATOMIC_BINOP(op) \
diff --git a/chromium/v8/src/compiler/code-assembler.cc b/chromium/v8/src/compiler/code-assembler.cc
index aa3ba471973..a0ed0af93db 100644
--- a/chromium/v8/src/compiler/code-assembler.cc
+++ b/chromium/v8/src/compiler/code-assembler.cc
@@ -1150,6 +1150,25 @@ Node* CodeAssembler::CallCFunction3WithCallerSavedRegisters(
mode);
}
+Node* CodeAssembler::CallCFunction4(
+ MachineType return_type, MachineType arg0_type, MachineType arg1_type,
+ MachineType arg2_type, MachineType arg3_type, Node* function, Node* arg0,
+ Node* arg1, Node* arg2, Node* arg3) {
+ return raw_assembler()->CallCFunction4(return_type, arg0_type, arg1_type,
+ arg2_type, arg3_type, function, arg0,
+ arg1, arg2, arg3);
+}
+
+Node* CodeAssembler::CallCFunction5(
+ MachineType return_type, MachineType arg0_type, MachineType arg1_type,
+ MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
+ Node* function, Node* arg0, Node* arg1, Node* arg2, Node* arg3,
+ Node* arg4) {
+ return raw_assembler()->CallCFunction5(
+ return_type, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type,
+ function, arg0, arg1, arg2, arg3, arg4);
+}
+
Node* CodeAssembler::CallCFunction6(
MachineType return_type, MachineType arg0_type, MachineType arg1_type,
MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
diff --git a/chromium/v8/src/compiler/code-assembler.h b/chromium/v8/src/compiler/code-assembler.h
index 159d4d7c12b..64e959a1c09 100644
--- a/chromium/v8/src/compiler/code-assembler.h
+++ b/chromium/v8/src/compiler/code-assembler.h
@@ -805,6 +805,19 @@ class V8_EXPORT_PRIVATE CodeAssembler {
MachineType arg2_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
SaveFPRegsMode mode);
+ // Call to a C function with four arguments.
+ Node* CallCFunction4(MachineType return_type, MachineType arg0_type,
+ MachineType arg1_type, MachineType arg2_type,
+ MachineType arg3_type, Node* function, Node* arg0,
+ Node* arg1, Node* arg2, Node* arg3);
+
+ // Call to a C function with five arguments.
+ Node* CallCFunction5(MachineType return_type, MachineType arg0_type,
+ MachineType arg1_type, MachineType arg2_type,
+ MachineType arg3_type, MachineType arg4_type,
+ Node* function, Node* arg0, Node* arg1, Node* arg2,
+ Node* arg3, Node* arg4);
+
// Call to a C function with six arguments.
Node* CallCFunction6(MachineType return_type, MachineType arg0_type,
MachineType arg1_type, MachineType arg2_type,
diff --git a/chromium/v8/src/compiler/common-operator.cc b/chromium/v8/src/compiler/common-operator.cc
index bda0e20ed58..1693e90ec24 100644
--- a/chromium/v8/src/compiler/common-operator.cc
+++ b/chromium/v8/src/compiler/common-operator.cc
@@ -1258,7 +1258,7 @@ ArgumentsStateType ArgumentsStateTypeOf(Operator const* op) {
return OpParameter<ArgumentsStateType>(op);
}
-const Operator* CommonOperatorBuilder::ObjectState(int object_id,
+const Operator* CommonOperatorBuilder::ObjectState(uint32_t object_id,
int pointer_slots) {
return new (zone()) Operator1<ObjectStateInfo>( // --
IrOpcode::kObjectState, Operator::kPure, // opcode
@@ -1268,7 +1268,7 @@ const Operator* CommonOperatorBuilder::ObjectState(int object_id,
}
const Operator* CommonOperatorBuilder::TypedObjectState(
- int object_id, const ZoneVector<MachineType>* types) {
+ uint32_t object_id, const ZoneVector<MachineType>* types) {
return new (zone()) Operator1<TypedObjectStateInfo>( // --
IrOpcode::kTypedObjectState, Operator::kPure, // opcode
"TypedObjectState", // name
diff --git a/chromium/v8/src/compiler/common-operator.h b/chromium/v8/src/compiler/common-operator.h
index 33ddaf96646..4f722676178 100644
--- a/chromium/v8/src/compiler/common-operator.h
+++ b/chromium/v8/src/compiler/common-operator.h
@@ -125,7 +125,8 @@ V8_EXPORT_PRIVATE int ParameterIndexOf(const Operator* const);
const ParameterInfo& ParameterInfoOf(const Operator* const);
struct ObjectStateInfo final : std::pair<uint32_t, int> {
- using std::pair<uint32_t, int>::pair;
+ ObjectStateInfo(uint32_t object_id, int size)
+ : std::pair<uint32_t, int>(object_id, size) {}
uint32_t object_id() const { return first; }
int size() const { return second; }
};
@@ -134,7 +135,10 @@ size_t hash_value(ObjectStateInfo const& p);
struct TypedObjectStateInfo final
: std::pair<uint32_t, const ZoneVector<MachineType>*> {
- using std::pair<uint32_t, const ZoneVector<MachineType>*>::pair;
+ TypedObjectStateInfo(uint32_t object_id,
+ const ZoneVector<MachineType>* machine_types)
+ : std::pair<uint32_t, const ZoneVector<MachineType>*>(object_id,
+ machine_types) {}
uint32_t object_id() const { return first; }
const ZoneVector<MachineType>* machine_types() const { return second; }
};
@@ -403,8 +407,8 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
SparseInputMask bitmask);
const Operator* ArgumentsElementsState(ArgumentsStateType type);
const Operator* ArgumentsLengthState(ArgumentsStateType type);
- const Operator* ObjectState(int object_id, int pointer_slots);
- const Operator* TypedObjectState(int object_id,
+ const Operator* ObjectState(uint32_t object_id, int pointer_slots);
+ const Operator* TypedObjectState(uint32_t object_id,
const ZoneVector<MachineType>* types);
const Operator* FrameState(BailoutId bailout_id,
OutputFrameStateCombine state_combine,
diff --git a/chromium/v8/src/compiler/effect-control-linearizer.cc b/chromium/v8/src/compiler/effect-control-linearizer.cc
index 3e0ac820dd3..d886fda97a8 100644
--- a/chromium/v8/src/compiler/effect-control-linearizer.cc
+++ b/chromium/v8/src/compiler/effect-control-linearizer.cc
@@ -718,6 +718,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kObjectIsCallable:
result = LowerObjectIsCallable(node);
break;
+ case IrOpcode::kObjectIsConstructor:
+ result = LowerObjectIsConstructor(node);
+ break;
case IrOpcode::kObjectIsDetectableCallable:
result = LowerObjectIsDetectableCallable(node);
break;
@@ -1931,6 +1934,31 @@ Node* EffectControlLinearizer::LowerObjectIsCallable(Node* node) {
return done.PhiAt(0);
}
+Node* EffectControlLinearizer::LowerObjectIsConstructor(Node* node) {
+ Node* value = node->InputAt(0);
+
+ auto if_smi = __ MakeDeferredLabel();
+ auto done = __ MakeLabel(MachineRepresentation::kBit);
+
+ Node* check = ObjectIsSmi(value);
+ __ GotoIf(check, &if_smi);
+
+ Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
+ Node* value_bit_field =
+ __ LoadField(AccessBuilder::ForMapBitField(), value_map);
+ Node* vfalse =
+ __ Word32Equal(__ Int32Constant(1 << Map::kIsConstructor),
+ __ Word32And(value_bit_field,
+ __ Int32Constant(1 << Map::kIsConstructor)));
+ __ Goto(&done, vfalse);
+
+ __ Bind(&if_smi);
+ __ Goto(&done, __ Int32Constant(0));
+
+ __ Bind(&done);
+ return done.PhiAt(0);
+}
+
Node* EffectControlLinearizer::LowerObjectIsDetectableCallable(Node* node) {
Node* value = node->InputAt(0);
diff --git a/chromium/v8/src/compiler/effect-control-linearizer.h b/chromium/v8/src/compiler/effect-control-linearizer.h
index 46ef687d601..e17f097e9e6 100644
--- a/chromium/v8/src/compiler/effect-control-linearizer.h
+++ b/chromium/v8/src/compiler/effect-control-linearizer.h
@@ -86,6 +86,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerCheckedTruncateTaggedToWord32(Node* node, Node* frame_state);
Node* LowerObjectIsArrayBufferView(Node* node);
Node* LowerObjectIsCallable(Node* node);
+ Node* LowerObjectIsConstructor(Node* node);
Node* LowerObjectIsDetectableCallable(Node* node);
Node* LowerObjectIsMinusZero(Node* node);
Node* LowerObjectIsNaN(Node* node);
diff --git a/chromium/v8/src/compiler/escape-analysis.cc b/chromium/v8/src/compiler/escape-analysis.cc
index 45829734c5d..ab2b06a9528 100644
--- a/chromium/v8/src/compiler/escape-analysis.cc
+++ b/chromium/v8/src/compiler/escape-analysis.cc
@@ -125,7 +125,18 @@ class VariableTracker {
public:
Scope(VariableTracker* tracker, Node* node, Reduction* reduction);
~Scope();
- Node* Get(Variable var) { return current_state_.Get(var); }
+ Maybe<Node*> Get(Variable var) {
+ Node* node = current_state_.Get(var);
+ if (node && node->opcode() == IrOpcode::kDead) {
+ // TODO(tebbi): We use {Dead} as a sentinel for uninitialized memory.
+ // Reading uninitialized memory can only happen in unreachable code. In
+ // this case, we have to mark the object as escaping to avoid dead nodes
+ // in the graph. This is a workaround that should be removed once we can
+ // handle dead nodes everywhere.
+ return Nothing<Node*>();
+ }
+ return Just(node);
+ }
void Set(Variable var, Node* node) { current_state_.Set(var, node); }
private:
@@ -585,14 +596,12 @@ void ReduceNode(const Operator* op, EscapeAnalysisTracker::Scope* current,
Node* object = current->ValueInput(0);
const VirtualObject* vobject = current->GetVirtualObject(object);
Variable var;
+ Node* value;
if (vobject && !vobject->HasEscaped() &&
- vobject->FieldAt(OffsetOfFieldAccess(op)).To(&var)) {
- current->SetReplacement(current->Get(var));
+ vobject->FieldAt(OffsetOfFieldAccess(op)).To(&var) &&
+ current->Get(var).To(&value)) {
+ current->SetReplacement(value);
} else {
- // TODO(tebbi): At the moment, we mark objects as escaping if there
- // is a load from an invalid location to avoid dead nodes. This is a
- // workaround that should be removed once we can handle dead nodes
- // everywhere.
current->SetEscaped(object);
}
break;
@@ -603,10 +612,11 @@ void ReduceNode(const Operator* op, EscapeAnalysisTracker::Scope* current,
const VirtualObject* vobject = current->GetVirtualObject(object);
int offset;
Variable var;
+ Node* value;
if (vobject && !vobject->HasEscaped() &&
OffsetOfElementsAccess(op, index).To(&offset) &&
- vobject->FieldAt(offset).To(&var)) {
- current->SetReplacement(current->Get(var));
+ vobject->FieldAt(offset).To(&var) && current->Get(var).To(&value)) {
+ current->SetReplacement(value);
} else {
current->SetEscaped(object);
}
@@ -656,9 +666,11 @@ void ReduceNode(const Operator* op, EscapeAnalysisTracker::Scope* current,
Node* checked = current->ValueInput(0);
const VirtualObject* vobject = current->GetVirtualObject(checked);
Variable map_field;
+ Node* map;
if (vobject && !vobject->HasEscaped() &&
- vobject->FieldAt(HeapObject::kMapOffset).To(&map_field)) {
- if (Node* map = current->Get(map_field)) {
+ vobject->FieldAt(HeapObject::kMapOffset).To(&map_field) &&
+ current->Get(map_field).To(&map)) {
+ if (map) {
Type* const map_type = NodeProperties::GetType(map);
if (map_type->IsHeapConstant() &&
params.maps().contains(ZoneHandleSet<Map>(bit_cast<Handle<Map>>(
@@ -679,9 +691,11 @@ void ReduceNode(const Operator* op, EscapeAnalysisTracker::Scope* current,
Node* object = current->ValueInput(0);
const VirtualObject* vobject = current->GetVirtualObject(object);
Variable map_field;
+ Node* object_map;
if (vobject && !vobject->HasEscaped() &&
- vobject->FieldAt(HeapObject::kMapOffset).To(&map_field)) {
- if (Node* object_map = current->Get(map_field)) {
+ vobject->FieldAt(HeapObject::kMapOffset).To(&map_field) &&
+ current->Get(map_field).To(&object_map)) {
+ if (object_map) {
current->SetReplacement(LowerCompareMapsWithoutLoad(
object_map, CompareMapsParametersOf(op), jsgraph));
break;
diff --git a/chromium/v8/src/compiler/escape-analysis.h b/chromium/v8/src/compiler/escape-analysis.h
index e0d65cfacc1..504729bc811 100644
--- a/chromium/v8/src/compiler/escape-analysis.h
+++ b/chromium/v8/src/compiler/escape-analysis.h
@@ -130,7 +130,10 @@ class VirtualObject : public Dependable {
}
CHECK(!HasEscaped());
if (offset >= size()) {
- // This can only happen in unreachable code.
+ // TODO(tebbi): Reading out-of-bounds can only happen in unreachable
+ // code. In this case, we have to mark the object as escaping to avoid
+ // dead nodes in the graph. This is a workaround that should be removed
+ // once we can handle dead nodes everywhere.
return Nothing<Variable>();
}
return Just(fields_.at(offset / kPointerSize));
diff --git a/chromium/v8/src/compiler/js-call-reducer.cc b/chromium/v8/src/compiler/js-call-reducer.cc
index c8f2c9789df..d8fcf4553af 100644
--- a/chromium/v8/src/compiler/js-call-reducer.cc
+++ b/chromium/v8/src/compiler/js-call-reducer.cc
@@ -1298,6 +1298,56 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
} else {
NodeProperties::ChangeOp(
node, javascript()->Construct(arity + 2, frequency, feedback));
+ Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
+ Node* frame_state = NodeProperties::GetFrameStateInput(node);
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+
+ // Check whether the given new target value is a constructor function. The
+ // replacement {JSConstruct} operator only checks the passed target value
+ // but relies on the new target value to be implicitly valid.
+ Node* check =
+ graph()->NewNode(simplified()->ObjectIsConstructor(), new_target);
+ Node* check_branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
+ Node* check_fail = graph()->NewNode(common()->IfFalse(), check_branch);
+ Node* check_throw = check_fail =
+ graph()->NewNode(javascript()->CallRuntime(Runtime::kThrowTypeError, 2),
+ jsgraph()->Constant(MessageTemplate::kNotConstructor),
+ new_target, context, frame_state, effect, check_fail);
+ control = graph()->NewNode(common()->IfTrue(), check_branch);
+ NodeProperties::ReplaceControlInput(node, control);
+
+ // Rewire potential exception edges.
+ Node* on_exception = nullptr;
+ if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
+ // Create appropriate {IfException} and {IfSuccess} nodes.
+ Node* if_exception =
+ graph()->NewNode(common()->IfException(), check_throw, check_fail);
+ check_fail = graph()->NewNode(common()->IfSuccess(), check_fail);
+
+ // Join the exception edges.
+ Node* merge =
+ graph()->NewNode(common()->Merge(2), if_exception, on_exception);
+ Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception,
+ on_exception, merge);
+ Node* phi =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ if_exception, on_exception, merge);
+ ReplaceWithValue(on_exception, phi, ephi, merge);
+ merge->ReplaceInput(1, on_exception);
+ ephi->ReplaceInput(1, on_exception);
+ phi->ReplaceInput(1, on_exception);
+ }
+
+ // The above %ThrowTypeError runtime call is an unconditional throw, making
+ // it impossible to return a successful completion in this case. We simply
+ // connect the successful completion to the graph end.
+ Node* terminate =
+ graph()->NewNode(common()->Throw(), check_throw, check_fail);
+ NodeProperties::MergeControlToEnd(graph(), common(), terminate);
+
Reduction const reduction = ReduceJSConstruct(node);
return reduction.Changed() ? reduction : Changed(node);
}
diff --git a/chromium/v8/src/compiler/js-create-lowering.cc b/chromium/v8/src/compiler/js-create-lowering.cc
index d740f7681cb..bd4f1069abb 100644
--- a/chromium/v8/src/compiler/js-create-lowering.cc
+++ b/chromium/v8/src/compiler/js-create-lowering.cc
@@ -255,13 +255,14 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) {
Node* const control = NodeProperties::GetControlInput(node);
// Extract constructor and original constructor function.
if (target_type->IsHeapConstant() && new_target_type->IsHeapConstant() &&
+ target_type->AsHeapConstant()->Value()->IsJSFunction() &&
new_target_type->AsHeapConstant()->Value()->IsJSFunction()) {
Handle<JSFunction> constructor =
Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
+ if (!constructor->IsConstructor()) return NoChange();
Handle<JSFunction> original_constructor =
Handle<JSFunction>::cast(new_target_type->AsHeapConstant()->Value());
- DCHECK(constructor->IsConstructor());
- DCHECK(original_constructor->IsConstructor());
+ if (!original_constructor->IsConstructor()) return NoChange();
// Check if we can inline the allocation.
if (IsAllocationInlineable(constructor, original_constructor)) {
diff --git a/chromium/v8/src/compiler/js-native-context-specialization.cc b/chromium/v8/src/compiler/js-native-context-specialization.cc
index 18093ec9e7e..06f059e24ea 100644
--- a/chromium/v8/src/compiler/js-native-context-specialization.cc
+++ b/chromium/v8/src/compiler/js-native-context-specialization.cc
@@ -2438,14 +2438,18 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
jsgraph()->SmiConstant(PropertyArray::kNoHashSentinel));
hash = graph()->NewNode(common()->TypeGuard(Type::SignedSmall()), hash,
control);
+ hash =
+ graph()->NewNode(simplified()->NumberShiftLeft(), hash,
+ jsgraph()->Constant(PropertyArray::HashField::kShift));
} else {
hash = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForPropertyArrayLengthAndHash()),
properties, effect, control);
effect = graph()->NewNode(
common()->BeginRegion(RegionObservability::kNotObservable), effect);
- hash = graph()->NewNode(simplified()->NumberBitwiseAnd(), hash,
- jsgraph()->Constant(JSReceiver::kHashMask));
+ hash =
+ graph()->NewNode(simplified()->NumberBitwiseAnd(), hash,
+ jsgraph()->Constant(PropertyArray::HashField::kMask));
}
Node* new_length_and_hash = graph()->NewNode(
diff --git a/chromium/v8/src/compiler/js-typed-lowering.cc b/chromium/v8/src/compiler/js-typed-lowering.cc
index 73db9790015..6f50ba15a3c 100644
--- a/chromium/v8/src/compiler/js-typed-lowering.cc
+++ b/chromium/v8/src/compiler/js-typed-lowering.cc
@@ -668,6 +668,7 @@ Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
// Morph the {node} into a {FinishRegion}.
ReplaceWithValue(node, node, node, control);
+ NodeProperties::SetType(value, NodeProperties::GetType(node));
node->ReplaceInput(0, value);
node->ReplaceInput(1, effect);
node->TrimInputCount(2);
diff --git a/chromium/v8/src/compiler/opcodes.h b/chromium/v8/src/compiler/opcodes.h
index ef0a517001e..97f91b8cacc 100644
--- a/chromium/v8/src/compiler/opcodes.h
+++ b/chromium/v8/src/compiler/opcodes.h
@@ -355,6 +355,7 @@
V(TransitionAndStoreElement) \
V(ObjectIsArrayBufferView) \
V(ObjectIsCallable) \
+ V(ObjectIsConstructor) \
V(ObjectIsDetectableCallable) \
V(ObjectIsMinusZero) \
V(ObjectIsNaN) \
diff --git a/chromium/v8/src/compiler/raw-machine-assembler.cc b/chromium/v8/src/compiler/raw-machine-assembler.cc
index 89190f40a7d..b685fc5d66f 100644
--- a/chromium/v8/src/compiler/raw-machine-assembler.cc
+++ b/chromium/v8/src/compiler/raw-machine-assembler.cc
@@ -301,6 +301,41 @@ Node* RawMachineAssembler::CallCFunction3WithCallerSavedRegisters(
arg0, arg1, arg2);
}
+Node* RawMachineAssembler::CallCFunction4(
+ MachineType return_type, MachineType arg0_type, MachineType arg1_type,
+ MachineType arg2_type, MachineType arg3_type, Node* function, Node* arg0,
+ Node* arg1, Node* arg2, Node* arg3) {
+ MachineSignature::Builder builder(zone(), 1, 4);
+ builder.AddReturn(return_type);
+ builder.AddParam(arg0_type);
+ builder.AddParam(arg1_type);
+ builder.AddParam(arg2_type);
+ builder.AddParam(arg3_type);
+ const CallDescriptor* descriptor =
+ Linkage::GetSimplifiedCDescriptor(zone(), builder.Build());
+
+ return AddNode(common()->Call(descriptor), function, arg0, arg1, arg2, arg3);
+}
+
+Node* RawMachineAssembler::CallCFunction5(
+ MachineType return_type, MachineType arg0_type, MachineType arg1_type,
+ MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
+ Node* function, Node* arg0, Node* arg1, Node* arg2, Node* arg3,
+ Node* arg4) {
+ MachineSignature::Builder builder(zone(), 1, 5);
+ builder.AddReturn(return_type);
+ builder.AddParam(arg0_type);
+ builder.AddParam(arg1_type);
+ builder.AddParam(arg2_type);
+ builder.AddParam(arg3_type);
+ builder.AddParam(arg4_type);
+ const CallDescriptor* descriptor =
+ Linkage::GetSimplifiedCDescriptor(zone(), builder.Build());
+
+ return AddNode(common()->Call(descriptor), function, arg0, arg1, arg2, arg3,
+ arg4);
+}
+
Node* RawMachineAssembler::CallCFunction6(
MachineType return_type, MachineType arg0_type, MachineType arg1_type,
MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
diff --git a/chromium/v8/src/compiler/raw-machine-assembler.h b/chromium/v8/src/compiler/raw-machine-assembler.h
index 8eaaf256239..3ee91a1ff9f 100644
--- a/chromium/v8/src/compiler/raw-machine-assembler.h
+++ b/chromium/v8/src/compiler/raw-machine-assembler.h
@@ -778,6 +778,17 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
MachineType return_type, MachineType arg0_type, MachineType arg1_type,
MachineType arg2_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
SaveFPRegsMode mode = kSaveFPRegs);
+ // Call to a C function with four arguments.
+ Node* CallCFunction4(MachineType return_type, MachineType arg0_type,
+ MachineType arg1_type, MachineType arg2_type,
+ MachineType arg3_type, Node* function, Node* arg0,
+ Node* arg1, Node* arg2, Node* arg3);
+ // Call to a C function with five arguments.
+ Node* CallCFunction5(MachineType return_type, MachineType arg0_type,
+ MachineType arg1_type, MachineType arg2_type,
+ MachineType arg3_type, MachineType arg4_type,
+ Node* function, Node* arg0, Node* arg1, Node* arg2,
+ Node* arg3, Node* arg4);
// Call to a C function with six arguments.
Node* CallCFunction6(MachineType return_type, MachineType arg0_type,
MachineType arg1_type, MachineType arg2_type,
diff --git a/chromium/v8/src/compiler/simplified-lowering.cc b/chromium/v8/src/compiler/simplified-lowering.cc
index b11ce164e10..28634b8c9f3 100644
--- a/chromium/v8/src/compiler/simplified-lowering.cc
+++ b/chromium/v8/src/compiler/simplified-lowering.cc
@@ -2683,6 +2683,11 @@ class RepresentationSelector {
VisitObjectIs(node, Type::Callable(), lowering);
return;
}
+ case IrOpcode::kObjectIsConstructor: {
+ // TODO(turbofan): Introduce a Type::Constructor?
+ VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
+ return;
+ }
case IrOpcode::kObjectIsDetectableCallable: {
VisitObjectIs(node, Type::DetectableCallable(), lowering);
return;
@@ -2928,19 +2933,8 @@ class RepresentationSelector {
return SetOutput(node, MachineRepresentation::kTagged);
case IrOpcode::kFindOrderedHashMapEntry: {
- Type* const key_type = TypeOf(node->InputAt(1));
- if (key_type->Is(Type::Signed32())) {
- VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
- MachineRepresentation::kWord32);
- if (lower()) {
- NodeProperties::ChangeOp(
- node,
- lowering->simplified()->FindOrderedHashMapEntryForInt32Key());
- }
- } else {
- VisitBinop(node, UseInfo::AnyTagged(),
- MachineRepresentation::kTaggedSigned);
- }
+ VisitBinop(node, UseInfo::AnyTagged(),
+ MachineRepresentation::kTaggedSigned);
return;
}
diff --git a/chromium/v8/src/compiler/simplified-operator.cc b/chromium/v8/src/compiler/simplified-operator.cc
index 45eca8ddf15..0d2333e126c 100644
--- a/chromium/v8/src/compiler/simplified-operator.cc
+++ b/chromium/v8/src/compiler/simplified-operator.cc
@@ -501,6 +501,7 @@ BailoutReason BailoutReasonOf(const Operator* op) {
V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \
V(ObjectIsArrayBufferView, Operator::kNoProperties, 1, 0) \
V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \
+ V(ObjectIsConstructor, Operator::kNoProperties, 1, 0) \
V(ObjectIsDetectableCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsMinusZero, Operator::kNoProperties, 1, 0) \
V(ObjectIsNaN, Operator::kNoProperties, 1, 0) \
diff --git a/chromium/v8/src/compiler/simplified-operator.h b/chromium/v8/src/compiler/simplified-operator.h
index 5a237a1f54c..6d43bcac505 100644
--- a/chromium/v8/src/compiler/simplified-operator.h
+++ b/chromium/v8/src/compiler/simplified-operator.h
@@ -437,6 +437,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* ObjectIsArrayBufferView();
const Operator* ObjectIsCallable();
+ const Operator* ObjectIsConstructor();
const Operator* ObjectIsDetectableCallable();
const Operator* ObjectIsMinusZero();
const Operator* ObjectIsNaN();
diff --git a/chromium/v8/src/compiler/typer.cc b/chromium/v8/src/compiler/typer.cc
index 9ea962b8659..2590342d2e4 100644
--- a/chromium/v8/src/compiler/typer.cc
+++ b/chromium/v8/src/compiler/typer.cc
@@ -289,6 +289,7 @@ class Typer::Visitor : public Reducer {
static Type* ObjectIsArrayBufferView(Type*, Typer*);
static Type* ObjectIsCallable(Type*, Typer*);
+ static Type* ObjectIsConstructor(Type*, Typer*);
static Type* ObjectIsDetectableCallable(Type*, Typer*);
static Type* ObjectIsMinusZero(Type*, Typer*);
static Type* ObjectIsNaN(Type*, Typer*);
@@ -523,6 +524,12 @@ Type* Typer::Visitor::ObjectIsCallable(Type* type, Typer* t) {
return Type::Boolean();
}
+Type* Typer::Visitor::ObjectIsConstructor(Type* type, Typer* t) {
+ // TODO(turbofan): Introduce a Type::Constructor?
+ if (!type->Maybe(Type::Callable())) return t->singleton_false_;
+ return Type::Boolean();
+}
+
Type* Typer::Visitor::ObjectIsDetectableCallable(Type* type, Typer* t) {
if (type->Is(Type::DetectableCallable())) return t->singleton_true_;
if (!type->Maybe(Type::DetectableCallable())) return t->singleton_false_;
@@ -1986,6 +1993,10 @@ Type* Typer::Visitor::TypeObjectIsCallable(Node* node) {
return TypeUnaryOp(node, ObjectIsCallable);
}
+Type* Typer::Visitor::TypeObjectIsConstructor(Node* node) {
+ return TypeUnaryOp(node, ObjectIsConstructor);
+}
+
Type* Typer::Visitor::TypeObjectIsDetectableCallable(Node* node) {
return TypeUnaryOp(node, ObjectIsDetectableCallable);
}
diff --git a/chromium/v8/src/compiler/verifier.cc b/chromium/v8/src/compiler/verifier.cc
index 541818c3d8f..5869a0d491c 100644
--- a/chromium/v8/src/compiler/verifier.cc
+++ b/chromium/v8/src/compiler/verifier.cc
@@ -1007,6 +1007,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kObjectIsArrayBufferView:
case IrOpcode::kObjectIsCallable:
+ case IrOpcode::kObjectIsConstructor:
case IrOpcode::kObjectIsDetectableCallable:
case IrOpcode::kObjectIsMinusZero:
case IrOpcode::kObjectIsNaN:
diff --git a/chromium/v8/src/compiler/wasm-compiler.cc b/chromium/v8/src/compiler/wasm-compiler.cc
index 7bcdb5092a4..bc731b2bb8f 100644
--- a/chromium/v8/src/compiler/wasm-compiler.cc
+++ b/chromium/v8/src/compiler/wasm-compiler.cc
@@ -3221,6 +3221,10 @@ Node* WasmGraphBuilder::LoadMemSize() {
static_cast<int32_t>(offsetof(WasmContext, mem_size))),
*effect_, *control_);
*effect_ = mem_size;
+ if (jsgraph()->machine()->Is64()) {
+ mem_size = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(),
+ mem_size);
+ }
return mem_size;
}
@@ -3235,8 +3239,13 @@ Node* WasmGraphBuilder::CurrentMemoryPages() {
// CurrentMemoryPages can not be called from asm.js.
DCHECK_EQ(wasm::kWasmOrigin, env_->module->origin());
DCHECK_NOT_NULL(*mem_size_);
+ Node* mem_size = *mem_size_;
+ if (jsgraph()->machine()->Is64()) {
+ mem_size = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(),
+ mem_size);
+ }
return graph()->NewNode(
- jsgraph()->machine()->Word32Shr(), *mem_size_,
+ jsgraph()->machine()->Word32Shr(), mem_size,
jsgraph()->Int32Constant(WhichPowerOf2(wasm::WasmModule::kPageSize)));
}
@@ -3397,15 +3406,21 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
// The end offset is larger than the smallest memory.
// Dynamically check the end offset against the actual memory size, which
// is not known at compile time.
- Node* cond = graph()->NewNode(
- jsgraph()->machine()->Uint32LessThanOrEqual(),
- jsgraph()->IntPtrConstant(static_cast<uintptr_t>(end_offset)),
- *mem_size_);
+ Node* cond;
+ if (jsgraph()->machine()->Is32()) {
+ cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(),
+ jsgraph()->Int32Constant(end_offset), *mem_size_);
+ } else {
+ cond = graph()->NewNode(
+ jsgraph()->machine()->Uint64LessThanOrEqual(),
+ jsgraph()->Int64Constant(static_cast<int64_t>(end_offset)),
+ *mem_size_);
+ }
TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
} else {
// The end offset is within the bounds of the smallest memory, so only
// one check is required. Check to see if the index is also a constant.
- Uint32Matcher m(index);
+ UintPtrMatcher m(index);
if (m.HasValue()) {
uint64_t index_val = m.Value();
if ((index_val + offset + access_size) <= min_size) {
@@ -3416,12 +3431,22 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
}
}
- Node* effective_size =
- graph()->NewNode(jsgraph()->machine()->Int32Sub(), *mem_size_,
- jsgraph()->Int32Constant(end_offset - 1));
+ Node* effective_size;
+ if (jsgraph()->machine()->Is32()) {
+ effective_size =
+ graph()->NewNode(jsgraph()->machine()->Int32Sub(), *mem_size_,
+ jsgraph()->Int32Constant(end_offset - 1));
+ } else {
+ effective_size = graph()->NewNode(
+ jsgraph()->machine()->Int64Sub(), *mem_size_,
+ jsgraph()->Int64Constant(static_cast<int64_t>(end_offset - 1)));
+ }
+
+ const Operator* less = jsgraph()->machine()->Is32()
+ ? jsgraph()->machine()->Uint32LessThan()
+ : jsgraph()->machine()->Uint64LessThan();
- Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(), index,
- effective_size);
+ Node* cond = graph()->NewNode(less, index, effective_size);
TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
}
@@ -3475,6 +3500,10 @@ Node* WasmGraphBuilder::LoadMem(wasm::ValueType type, MachineType memtype,
wasm::WasmCodePosition position) {
Node* load;
+ if (jsgraph()->machine()->Is64()) {
+ index =
+ graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
+ }
// Wasm semantics throw on OOB. Introduce explicit bounds check.
if (!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED) {
BoundsCheckMem(memtype, index, offset, position);
@@ -3530,6 +3559,10 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
wasm::ValueType type) {
Node* store;
+ if (jsgraph()->machine()->Is64()) {
+ index =
+ graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
+ }
// Wasm semantics throw on OOB. Introduce explicit bounds check.
if (!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED) {
BoundsCheckMem(memtype, index, offset, position);
@@ -3576,6 +3609,10 @@ Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) {
// asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
DCHECK_NOT_NULL(*mem_size_);
DCHECK_NOT_NULL(*mem_start_);
+ if (jsgraph()->machine()->Is64()) {
+ index =
+ graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
+ }
const Operator* op = jsgraph()->machine()->CheckedLoad(type);
Node* load =
graph()->NewNode(op, *mem_start_, index, *mem_size_, *effect_, *control_);
@@ -3589,6 +3626,10 @@ Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index,
// asm.js semantics use CheckedStore (i.e. ignore OOB writes).
DCHECK_NOT_NULL(*mem_size_);
DCHECK_NOT_NULL(*mem_start_);
+ if (jsgraph()->machine()->Is64()) {
+ index =
+ graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
+ }
const Operator* op =
jsgraph()->machine()->CheckedStore(type.representation());
Node* store = graph()->NewNode(op, *mem_start_, index, *mem_size_, val,
@@ -3609,7 +3650,7 @@ Node* WasmGraphBuilder::String(const char* string) {
Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); }
void WasmGraphBuilder::LowerInt64() {
- if (!jsgraph()->machine()->Is32()) return;
+ if (jsgraph()->machine()->Is64()) return;
Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(), jsgraph()->common(),
jsgraph()->zone(), sig_);
r.LowerGraph();
diff --git a/chromium/v8/src/debug/debug-scope-iterator.cc b/chromium/v8/src/debug/debug-scope-iterator.cc
index 5dc377375ee..2e06dccab68 100644
--- a/chromium/v8/src/debug/debug-scope-iterator.cc
+++ b/chromium/v8/src/debug/debug-scope-iterator.cc
@@ -15,13 +15,22 @@ namespace v8 {
std::unique_ptr<debug::ScopeIterator> debug::ScopeIterator::CreateForFunction(
v8::Isolate* v8_isolate, v8::Local<v8::Function> v8_func) {
- internal::Handle<internal::JSFunction> func =
- internal::Handle<internal::JSFunction>::cast(Utils::OpenHandle(*v8_func));
+ internal::Handle<internal::JSReceiver> receiver =
+ internal::Handle<internal::JSReceiver>::cast(Utils::OpenHandle(*v8_func));
+
+ // Besides JSFunction and JSBoundFunction, {v8_func} could be an
+ // ObjectTemplate with a CallAsFunctionHandler. We only handle plain
+ // JSFunctions.
+ if (!receiver->IsJSFunction()) return nullptr;
+
+ internal::Handle<internal::JSFunction> function =
+ internal::Handle<internal::JSFunction>::cast(receiver);
+
// Blink has function objects with callable map, JS_SPECIAL_API_OBJECT_TYPE
// but without context on heap.
- if (!func->has_context()) return nullptr;
+ if (!function->has_context()) return nullptr;
return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator(
- reinterpret_cast<internal::Isolate*>(v8_isolate), func));
+ reinterpret_cast<internal::Isolate*>(v8_isolate), function));
}
std::unique_ptr<debug::ScopeIterator>
diff --git a/chromium/v8/src/deoptimizer.cc b/chromium/v8/src/deoptimizer.cc
index b5d77803ab1..125ca932f70 100644
--- a/chromium/v8/src/deoptimizer.cc
+++ b/chromium/v8/src/deoptimizer.cc
@@ -2759,8 +2759,7 @@ void TranslatedValue::Handlify() {
TranslatedFrame TranslatedFrame::InterpretedFrame(
BailoutId bytecode_offset, SharedFunctionInfo* shared_info, int height) {
- TranslatedFrame frame(kInterpretedFunction, shared_info->GetIsolate(),
- shared_info, height);
+ TranslatedFrame frame(kInterpretedFunction, shared_info, height);
frame.node_id_ = bytecode_offset;
return frame;
}
@@ -2769,36 +2768,32 @@ TranslatedFrame TranslatedFrame::InterpretedFrame(
TranslatedFrame TranslatedFrame::AccessorFrame(
Kind kind, SharedFunctionInfo* shared_info) {
DCHECK(kind == kSetter || kind == kGetter);
- return TranslatedFrame(kind, shared_info->GetIsolate(), shared_info);
+ return TranslatedFrame(kind, shared_info);
}
TranslatedFrame TranslatedFrame::ArgumentsAdaptorFrame(
SharedFunctionInfo* shared_info, int height) {
- return TranslatedFrame(kArgumentsAdaptor, shared_info->GetIsolate(),
- shared_info, height);
+ return TranslatedFrame(kArgumentsAdaptor, shared_info, height);
}
TranslatedFrame TranslatedFrame::ConstructStubFrame(
BailoutId bailout_id, SharedFunctionInfo* shared_info, int height) {
- TranslatedFrame frame(kConstructStub, shared_info->GetIsolate(), shared_info,
- height);
+ TranslatedFrame frame(kConstructStub, shared_info, height);
frame.node_id_ = bailout_id;
return frame;
}
TranslatedFrame TranslatedFrame::BuiltinContinuationFrame(
BailoutId bailout_id, SharedFunctionInfo* shared_info, int height) {
- TranslatedFrame frame(kBuiltinContinuation, shared_info->GetIsolate(),
- shared_info, height);
+ TranslatedFrame frame(kBuiltinContinuation, shared_info, height);
frame.node_id_ = bailout_id;
return frame;
}
TranslatedFrame TranslatedFrame::JavaScriptBuiltinContinuationFrame(
BailoutId bailout_id, SharedFunctionInfo* shared_info, int height) {
- TranslatedFrame frame(kJavaScriptBuiltinContinuation,
- shared_info->GetIsolate(), shared_info, height);
+ TranslatedFrame frame(kJavaScriptBuiltinContinuation, shared_info, height);
frame.node_id_ = bailout_id;
return frame;
}
@@ -3462,10 +3457,32 @@ class TranslatedState::CapturedObjectMaterializer {
int field_count)
: state_(state), frame_index_(frame_index), field_count_(field_count) {}
+ // Ensure the properties never contain mutable heap numbers. This is necessary
+ // because the deoptimizer generalizes all maps to tagged representation
+ // fields (so mutable heap numbers are not allowed).
+ static void EnsurePropertiesGeneralized(Handle<Object> properties_or_hash) {
+ if (properties_or_hash->IsPropertyArray()) {
+ Handle<PropertyArray> properties =
+ Handle<PropertyArray>::cast(properties_or_hash);
+ int length = properties->length();
+ for (int i = 0; i < length; i++) {
+ if (properties->get(i)->IsMutableHeapNumber()) {
+ Handle<HeapObject> box(HeapObject::cast(properties->get(i)));
+ box->set_map(properties->GetIsolate()->heap()->heap_number_map());
+ }
+ }
+ }
+ }
+
Handle<Object> FieldAt(int* value_index) {
CHECK(field_count_ > 0);
--field_count_;
- return state_->MaterializeAt(frame_index_, value_index);
+ Handle<Object> object = state_->MaterializeAt(frame_index_, value_index);
+ // This is a big hammer to make sure that the materialized objects do not
+ // have property arrays with mutable heap numbers (mutable heap numbers are
+ // bad because we generalize maps for all materialized objects).
+ EnsurePropertiesGeneralized(object);
+ return object;
}
~CapturedObjectMaterializer() { CHECK_EQ(0, field_count_); }
diff --git a/chromium/v8/src/deoptimizer.h b/chromium/v8/src/deoptimizer.h
index a60c40db571..dcc56198124 100644
--- a/chromium/v8/src/deoptimizer.h
+++ b/chromium/v8/src/deoptimizer.h
@@ -205,14 +205,12 @@ class TranslatedFrame {
static void AdvanceIterator(std::deque<TranslatedValue>::iterator* iter);
- TranslatedFrame(Kind kind, Isolate* isolate,
- SharedFunctionInfo* shared_info = nullptr, int height = 0)
+ TranslatedFrame(Kind kind, SharedFunctionInfo* shared_info = nullptr,
+ int height = 0)
: kind_(kind),
node_id_(BailoutId::None()),
raw_shared_info_(shared_info),
- height_(height),
- isolate_(isolate) {}
-
+ height_(height) {}
void Add(const TranslatedValue& value) { values_.push_back(value); }
void Handlify();
@@ -222,7 +220,6 @@ class TranslatedFrame {
SharedFunctionInfo* raw_shared_info_;
Handle<SharedFunctionInfo> shared_info_;
int height_;
- Isolate* isolate_;
typedef std::deque<TranslatedValue> ValuesContainer;
diff --git a/chromium/v8/src/elements.cc b/chromium/v8/src/elements.cc
index 577f77ddc84..8c692ecab82 100644
--- a/chromium/v8/src/elements.cc
+++ b/chromium/v8/src/elements.cc
@@ -1020,13 +1020,14 @@ class ElementsAccessorBase : public ElementsAccessor {
}
Object* CopyElements(Handle<JSReceiver> source, Handle<JSObject> destination,
- size_t length) final {
- return Subclass::CopyElementsHandleImpl(source, destination, length);
+ size_t length, uint32_t offset) final {
+ return Subclass::CopyElementsHandleImpl(source, destination, length,
+ offset);
}
static Object* CopyElementsHandleImpl(Handle<JSReceiver> source,
Handle<JSObject> destination,
- size_t length) {
+ size_t length, uint32_t offset) {
UNREACHABLE();
}
@@ -3168,28 +3169,30 @@ class TypedElementsAccessor
template <typename SourceTraits>
static void CopyBetweenBackingStores(FixedTypedArrayBase* source,
- BackingStore* dest, size_t length) {
+ BackingStore* dest, size_t length,
+ uint32_t offset) {
FixedTypedArray<SourceTraits>* source_fta =
FixedTypedArray<SourceTraits>::cast(source);
for (uint32_t i = 0; i < length; i++) {
typename SourceTraits::ElementType elem = source_fta->get_scalar(i);
- dest->set(i, dest->from(elem));
+ dest->set(offset + i, dest->from(elem));
}
}
- static void CopyElementsHandleFromTypedArray(Handle<JSTypedArray> source,
- Handle<JSTypedArray> destination,
- size_t length) {
+ static void CopyElementsFromTypedArray(JSTypedArray* source,
+ JSTypedArray* destination,
+ size_t length, uint32_t offset) {
// The source is a typed array, so we know we don't need to do ToNumber
// side-effects, as the source elements will always be a number or
// undefined.
DisallowHeapAllocation no_gc;
- Handle<FixedTypedArrayBase> source_elements(
- FixedTypedArrayBase::cast(source->elements()));
- Handle<BackingStore> destination_elements(
- BackingStore::cast(destination->elements()));
+ FixedTypedArrayBase* source_elements =
+ FixedTypedArrayBase::cast(source->elements());
+ BackingStore* destination_elements =
+ BackingStore::cast(destination->elements());
+ DCHECK_LE(offset + source->length(), destination->length());
DCHECK_GE(destination->length(), source->length());
DCHECK(source->length()->IsSmi());
DCHECK_EQ(Smi::FromInt(static_cast<int>(length)), source->length());
@@ -3219,15 +3222,16 @@ class TypedElementsAccessor
// which have special conversion operations.
if (same_type || (same_size && both_are_simple)) {
size_t element_size = source->element_size();
- std::memcpy(dest_data, source_data, length * element_size);
+ std::memcpy(dest_data + offset * element_size, source_data,
+ length * element_size);
} else {
// We use scalar accessors below to avoid boxing/unboxing, so there are
// no allocations.
switch (source->GetElementsKind()) {
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
- case TYPE##_ELEMENTS: \
- CopyBetweenBackingStores<Type##ArrayTraits>( \
- *source_elements, *destination_elements, length); \
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case TYPE##_ELEMENTS: \
+ CopyBetweenBackingStores<Type##ArrayTraits>( \
+ source_elements, destination_elements, length, offset); \
break;
TYPED_ARRAYS(TYPED_ARRAY_CASE)
default:
@@ -3238,23 +3242,27 @@ class TypedElementsAccessor
}
}
- static bool HoleyPrototypeLookupRequired(Isolate* isolate,
- Handle<JSArray> source) {
+ static bool HoleyPrototypeLookupRequired(Isolate* isolate, Context* context,
+ JSArray* source) {
+ DisallowHeapAllocation no_gc;
+ DisallowJavascriptExecution no_js(isolate);
+
Object* source_proto = source->map()->prototype();
+
// Null prototypes are OK - we don't need to do prototype chain lookups on
// them.
if (source_proto->IsNull(isolate)) return false;
if (source_proto->IsJSProxy()) return true;
- DCHECK(source_proto->IsJSObject());
- if (!isolate->is_initial_array_prototype(JSObject::cast(source_proto))) {
+ if (!context->is_initial_array_prototype(JSObject::cast(source_proto))) {
return true;
}
- return !isolate->IsFastArrayConstructorPrototypeChainIntact();
+
+ return !isolate->IsFastArrayConstructorPrototypeChainIntact(context);
}
- static bool TryCopyElementsHandleFastNumber(Handle<JSArray> source,
- Handle<JSTypedArray> destination,
- size_t length) {
+ static bool TryCopyElementsFastNumber(Context* context, JSArray* source,
+ JSTypedArray* destination,
+ size_t length, uint32_t offset) {
Isolate* isolate = source->GetIsolate();
DisallowHeapAllocation no_gc;
DisallowJavascriptExecution no_js(isolate);
@@ -3267,7 +3275,7 @@ class TypedElementsAccessor
// When the array has the original array prototype, and that prototype has
// not been changed in a way that would affect lookups, we can just convert
// the hole into undefined.
- if (HoleyPrototypeLookupRequired(isolate, source)) return false;
+ if (HoleyPrototypeLookupRequired(isolate, context, source)) return false;
Object* undefined = isolate->heap()->undefined_value();
@@ -3279,19 +3287,19 @@ class TypedElementsAccessor
Object* elem = source_store->get(i);
DCHECK(elem->IsSmi());
int int_value = Smi::ToInt(elem);
- dest->set(i, dest->from(int_value));
+ dest->set(offset + i, dest->from(int_value));
}
return true;
} else if (kind == HOLEY_SMI_ELEMENTS) {
FixedArray* source_store = FixedArray::cast(source->elements());
for (uint32_t i = 0; i < length; i++) {
if (source_store->is_the_hole(isolate, i)) {
- dest->SetValue(i, undefined);
+ dest->SetValue(offset + i, undefined);
} else {
Object* elem = source_store->get(i);
DCHECK(elem->IsSmi());
int int_value = Smi::ToInt(elem);
- dest->set(i, dest->from(int_value));
+ dest->set(offset + i, dest->from(int_value));
}
}
return true;
@@ -3305,7 +3313,7 @@ class TypedElementsAccessor
// Use the from_double conversion for this specific TypedArray type,
// rather than relying on C++ to convert elem.
double elem = source_store->get_scalar(i);
- dest->set(i, dest->from(elem));
+ dest->set(offset + i, dest->from(elem));
}
return true;
} else if (kind == HOLEY_DOUBLE_ELEMENTS) {
@@ -3313,10 +3321,10 @@ class TypedElementsAccessor
FixedDoubleArray::cast(source->elements());
for (uint32_t i = 0; i < length; i++) {
if (source_store->is_the_hole(i)) {
- dest->SetValue(i, undefined);
+ dest->SetValue(offset + i, undefined);
} else {
double elem = source_store->get_scalar(i);
- dest->set(i, dest->from(elem));
+ dest->set(offset + i, dest->from(elem));
}
}
return true;
@@ -3326,7 +3334,7 @@ class TypedElementsAccessor
static Object* CopyElementsHandleSlow(Handle<JSReceiver> source,
Handle<JSTypedArray> destination,
- size_t length) {
+ size_t length, uint32_t offset) {
Isolate* isolate = source->GetIsolate();
Handle<BackingStore> destination_elements(
BackingStore::cast(destination->elements()));
@@ -3336,13 +3344,21 @@ class TypedElementsAccessor
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,
Object::GetProperty(&it));
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem, Object::ToNumber(elem));
- // We don't need to check for buffer neutering here, because the
- // source cannot be a TypedArray.
+
+ if (V8_UNLIKELY(destination->WasNeutered())) {
+ const char* op = "set";
+ const MessageTemplate::Template message =
+ MessageTemplate::kDetachedOperation;
+ Handle<String> operation =
+ isolate->factory()->NewStringFromAsciiChecked(op);
+ THROW_NEW_ERROR_RETURN_FAILURE(isolate,
+ NewTypeError(message, operation));
+ }
// The spec says we store the length, then get each element, so we don't
// need to check changes to length.
- destination_elements->SetValue(i, *elem);
+ destination_elements->SetValue(offset + i, *elem);
}
- return Smi::kZero;
+ return *isolate->factory()->undefined_value();
}
// This doesn't guarantee that the destination array will be completely
@@ -3350,28 +3366,32 @@ class TypedElementsAccessor
// that is required.
static Object* CopyElementsHandleImpl(Handle<JSReceiver> source,
Handle<JSObject> destination,
- size_t length) {
+ size_t length, uint32_t offset) {
+ Isolate* isolate = destination->GetIsolate();
Handle<JSTypedArray> destination_ta =
Handle<JSTypedArray>::cast(destination);
+ DCHECK_LE(offset + length, destination_ta->length_value());
+
+ if (length == 0) return *isolate->factory()->undefined_value();
// All conversions from TypedArrays can be done without allocation.
if (source->IsJSTypedArray()) {
Handle<JSTypedArray> source_ta = Handle<JSTypedArray>::cast(source);
- CopyElementsHandleFromTypedArray(source_ta, destination_ta, length);
- return Smi::kZero;
+ CopyElementsFromTypedArray(*source_ta, *destination_ta, length, offset);
+ return *isolate->factory()->undefined_value();
}
// Fast cases for packed numbers kinds where we don't need to allocate.
if (source->IsJSArray()) {
Handle<JSArray> source_array = Handle<JSArray>::cast(source);
- if (TryCopyElementsHandleFastNumber(source_array, destination_ta,
- length)) {
- return Smi::kZero;
+ if (TryCopyElementsFastNumber(isolate->context(), *source_array,
+ *destination_ta, length, offset)) {
+ return *isolate->factory()->undefined_value();
}
}
// Final generic case that handles prototype chain lookups, getters, proxies
// and observable side effects via valueOf, etc.
- return CopyElementsHandleSlow(source, destination_ta, length);
+ return CopyElementsHandleSlow(source, destination_ta, length, offset);
}
};
@@ -4307,6 +4327,43 @@ MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
return array;
}
+void CopyFastNumberJSArrayElementsToTypedArray(Context* context,
+ JSArray* source,
+ JSTypedArray* destination,
+ uintptr_t length,
+ uintptr_t offset) {
+ DCHECK(context->IsContext());
+ DCHECK(source->IsJSArray());
+ DCHECK(destination->IsJSTypedArray());
+
+ switch (destination->GetElementsKind()) {
+#define TYPED_ARRAYS_CASE(Type, type, TYPE, ctype, size) \
+ case TYPE##_ELEMENTS: \
+ CHECK(Fixed##Type##ElementsAccessor::TryCopyElementsFastNumber( \
+ context, source, destination, length, static_cast<uint32_t>(offset))); \
+ break;
+ TYPED_ARRAYS(TYPED_ARRAYS_CASE)
+#undef TYPED_ARRAYS_CASE
+ default:
+ UNREACHABLE();
+ }
+}
+
+void CopyTypedArrayElementsToTypedArray(JSTypedArray* source,
+ JSTypedArray* destination,
+ uintptr_t length, uintptr_t offset) {
+ switch (destination->GetElementsKind()) {
+#define TYPED_ARRAYS_CASE(Type, type, TYPE, ctype, size) \
+ case TYPE##_ELEMENTS: \
+ Fixed##Type##ElementsAccessor::CopyElementsFromTypedArray( \
+ source, destination, length, static_cast<uint32_t>(offset)); \
+ break;
+ TYPED_ARRAYS(TYPED_ARRAYS_CASE)
+#undef TYPED_ARRAYS_CASE
+ default:
+ UNREACHABLE();
+ }
+}
void ElementsAccessor::InitializeOncePerProcess() {
static ElementsAccessor* accessor_array[] = {
diff --git a/chromium/v8/src/elements.h b/chromium/v8/src/elements.h
index a43b6f73ad4..3f81be0c51b 100644
--- a/chromium/v8/src/elements.h
+++ b/chromium/v8/src/elements.h
@@ -192,7 +192,8 @@ class ElementsAccessor {
Handle<FixedArrayBase> destination, int size) = 0;
virtual Object* CopyElements(Handle<JSReceiver> source,
- Handle<JSObject> destination, size_t length) = 0;
+ Handle<JSObject> destination, size_t length,
+ uint32_t offset = 0) = 0;
virtual Handle<FixedArray> CreateListFromArrayLike(Isolate* isolate,
Handle<JSObject> object,
@@ -236,6 +237,17 @@ MUST_USE_RESULT MaybeHandle<Object> ArrayConstructInitializeElements(
Handle<JSArray> array,
Arguments* args);
+// Called directly from CSA.
+class JSTypedArray;
+void CopyFastNumberJSArrayElementsToTypedArray(Context* context,
+ JSArray* source,
+ JSTypedArray* destination,
+ uintptr_t length,
+ uintptr_t offset);
+void CopyTypedArrayElementsToTypedArray(JSTypedArray* source,
+ JSTypedArray* destination,
+ uintptr_t length, uintptr_t offset);
+
} // namespace internal
} // namespace v8
diff --git a/chromium/v8/src/external-reference-table.cc b/chromium/v8/src/external-reference-table.cc
index 5d3d0728eda..eeb668a25f2 100644
--- a/chromium/v8/src/external-reference-table.cc
+++ b/chromium/v8/src/external-reference-table.cc
@@ -268,6 +268,13 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"orderedhashmap_gethash_raw");
Add(ExternalReference::get_or_create_hash_raw(isolate).address(),
"get_or_create_hash_raw");
+ Add(ExternalReference::copy_fast_number_jsarray_elements_to_typed_array(
+ isolate)
+ .address(),
+ "copy_fast_number_jsarray_elements_to_typed_array");
+ Add(ExternalReference::copy_typed_array_elements_to_typed_array(isolate)
+ .address(),
+ "copy_typed_array_elements_to_typed_array");
Add(ExternalReference::log_enter_external_function(isolate).address(),
"Logger::EnterExternal");
Add(ExternalReference::log_leave_external_function(isolate).address(),
diff --git a/chromium/v8/src/factory.cc b/chromium/v8/src/factory.cc
index 6e8369fdd1b..7710b0c7883 100644
--- a/chromium/v8/src/factory.cc
+++ b/chromium/v8/src/factory.cc
@@ -181,6 +181,7 @@ Handle<FixedArray> Factory::NewFixedArray(int size, PretenureFlag pretenure) {
Handle<PropertyArray> Factory::NewPropertyArray(int size,
PretenureFlag pretenure) {
DCHECK_LE(0, size);
+ if (size == 0) return empty_property_array();
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->AllocatePropertyArray(size, pretenure),
PropertyArray);
@@ -1331,6 +1332,7 @@ Handle<FixedArray> Factory::CopyFixedArrayAndGrow(Handle<FixedArray> array,
Handle<PropertyArray> Factory::CopyPropertyArrayAndGrow(
Handle<PropertyArray> array, int grow_by, PretenureFlag pretenure) {
+ DCHECK_LE(0, grow_by);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->CopyArrayAndGrow(*array, grow_by, pretenure),
@@ -1621,7 +1623,7 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code,
NewFunction(name, code, prototype, language_mode, prototype_mutability);
ElementsKind elements_kind =
- type == JS_ARRAY_TYPE ? PACKED_SMI_ELEMENTS : HOLEY_SMI_ELEMENTS;
+ type == JS_ARRAY_TYPE ? PACKED_SMI_ELEMENTS : TERMINAL_FAST_ELEMENTS_KIND;
Handle<Map> initial_map = NewMap(type, instance_size, elements_kind);
// TODO(littledan): Why do we have this is_generator test when
// NewFunctionPrototype already handles finding an appropriately
diff --git a/chromium/v8/src/flag-definitions.h b/chromium/v8/src/flag-definitions.h
index c9d87fb5f1e..50a1e660c0f 100644
--- a/chromium/v8/src/flag-definitions.h
+++ b/chromium/v8/src/flag-definitions.h
@@ -266,7 +266,8 @@ HARMONY_SHIPPING(FLAG_SHIPPING_FEATURES)
#undef FLAG_SHIPPING_FEATURES
#ifdef V8_INTL_SUPPORT
-DEFINE_BOOL(icu_timezone_data, true, "get information about timezones from ICU")
+DEFINE_BOOL(icu_timezone_data, false,
+ "get information about timezones from ICU")
#endif
#ifdef V8_ENABLE_FUTURE
diff --git a/chromium/v8/src/frames.cc b/chromium/v8/src/frames.cc
index f33dba8ba29..d578a64ed3d 100644
--- a/chromium/v8/src/frames.cc
+++ b/chromium/v8/src/frames.cc
@@ -1886,10 +1886,10 @@ void JavaScriptFrame::Print(StringStream* accumulator,
Context* context = NULL;
if (this->context() != NULL && this->context()->IsContext()) {
context = Context::cast(this->context());
- }
- while (context->IsWithContext()) {
- context = context->previous();
- DCHECK(context != NULL);
+ while (context->IsWithContext()) {
+ context = context->previous();
+ DCHECK(context != NULL);
+ }
}
// Print heap-allocated local variables.
diff --git a/chromium/v8/src/global-handles.cc b/chromium/v8/src/global-handles.cc
index 504a92702a2..9ae13d59f43 100644
--- a/chromium/v8/src/global-handles.cc
+++ b/chromium/v8/src/global-handles.cc
@@ -160,14 +160,21 @@ class GlobalHandles::Node {
bool IsInUse() const { return state() != FREE; }
+ bool IsPhantomCallback() const {
+ return weakness_type() == PHANTOM_WEAK ||
+ weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS;
+ }
+
+ bool IsPhantomResetHandle() const {
+ return weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
+ }
+
bool IsPendingPhantomCallback() const {
- return state() == PENDING &&
- (weakness_type() == PHANTOM_WEAK ||
- weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
+ return state() == PENDING && IsPhantomCallback();
}
bool IsPendingPhantomResetHandle() const {
- return state() == PENDING && weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
+ return state() == PENDING && IsPhantomResetHandle();
}
bool IsRetainer() const {
@@ -613,29 +620,44 @@ bool GlobalHandles::IsWeak(Object** location) {
}
DISABLE_CFI_PERF
-void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
+void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) {
Node* node = it.node();
- if (node->IsWeakRetainer()) {
- // Pending weak phantom handles die immediately. Everything else survives.
- if (node->IsPendingPhantomResetHandle()) {
+ if (node->IsWeakRetainer() && node->state() == Node::PENDING) {
+ DCHECK(!node->IsPhantomCallback());
+ DCHECK(!node->IsPhantomResetHandle());
+ // Finalizers need to survive.
+ v->VisitRootPointer(Root::kGlobalHandles, node->location());
+ }
+ }
+}
+
+DISABLE_CFI_PERF
+void GlobalHandles::IterateWeakRootsForPhantomHandles(
+ WeakSlotCallback should_reset_handle) {
+ for (NodeIterator it(this); !it.done(); it.Advance()) {
+ Node* node = it.node();
+ if (node->IsWeakRetainer() && should_reset_handle(node->location())) {
+ if (node->IsPhantomResetHandle()) {
+ node->MarkPending();
node->ResetPhantomHandle();
++number_of_phantom_handle_resets_;
- } else if (node->IsPendingPhantomCallback()) {
+ } else if (node->IsPhantomCallback()) {
+ node->MarkPending();
node->CollectPhantomCallbackData(isolate(),
&pending_phantom_callbacks_);
- } else {
- v->VisitRootPointer(Root::kGlobalHandles, node->location());
}
}
}
}
-
-void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
+void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback should_reset_handle) {
for (NodeIterator it(this); !it.done(); it.Advance()) {
- if (it.node()->IsWeak() && f(it.node()->location())) {
- it.node()->MarkPending();
+ Node* node = it.node();
+ if (node->IsWeak() && should_reset_handle(node->location())) {
+ if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
+ node->MarkPending();
+ }
}
}
}
diff --git a/chromium/v8/src/global-handles.h b/chromium/v8/src/global-handles.h
index 4e3d8161b8d..b5c3b2191d7 100644
--- a/chromium/v8/src/global-handles.h
+++ b/chromium/v8/src/global-handles.h
@@ -133,12 +133,13 @@ class GlobalHandles {
// and have class IDs
void IterateWeakRootsInNewSpaceWithClassIds(v8::PersistentHandleVisitor* v);
- // Iterates over all weak roots in heap.
- void IterateWeakRoots(RootVisitor* v);
+ // Iterates over weak roots on the heap.
+ void IterateWeakRootsForFinalizers(RootVisitor* v);
+ void IterateWeakRootsForPhantomHandles(WeakSlotCallback should_reset_handle);
- // Find all weak handles satisfying the callback predicate, mark
- // them as pending.
- void IdentifyWeakHandles(WeakSlotCallback f);
+ // Marks all handles that should be finalized based on the predicate
+ // |should_reset_handle| as pending.
+ void IdentifyWeakHandles(WeakSlotCallback should_reset_handle);
// NOTE: Five ...NewSpace... functions below are used during
// scavenge collections and iterate over sets of handles that are
diff --git a/chromium/v8/src/heap/concurrent-marking.cc b/chromium/v8/src/heap/concurrent-marking.cc
index 5a282e7f9cd..60bcbe9bab1 100644
--- a/chromium/v8/src/heap/concurrent-marking.cc
+++ b/chromium/v8/src/heap/concurrent-marking.cc
@@ -121,12 +121,6 @@ class ConcurrentMarkingVisitor final
int VisitJSApiObject(Map* map, JSObject* object) {
if (marking_state_.IsGrey(object)) {
- int size = JSObject::BodyDescriptor::SizeOf(map, object);
- VisitMapPointer(object, object->map_slot());
- // It is OK to iterate body of JS API object here because they do not have
- // unboxed double fields.
- DCHECK_IMPLIES(FLAG_unbox_double_fields, map->HasFastPointerLayout());
- JSObject::BodyDescriptor::IterateBody(object, size, this);
// The main thread will do wrapper tracing in Blink.
bailout_.Push(object);
}
diff --git a/chromium/v8/src/heap/heap.cc b/chromium/v8/src/heap/heap.cc
index c5c0a7c54ea..458c6c7e094 100644
--- a/chromium/v8/src/heap/heap.cc
+++ b/chromium/v8/src/heap/heap.cc
@@ -2381,6 +2381,7 @@ AllocationResult Heap::AllocatePartialMap(InstanceType instance_type,
Map::ConstructionCounter::encode(Map::kNoSlackTracking);
map->set_bit_field3(bit_field3);
map->set_weak_cell_cache(Smi::kZero);
+ map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
return map;
}
@@ -2388,6 +2389,11 @@ AllocationResult Heap::AllocatePartialMap(InstanceType instance_type,
AllocationResult Heap::AllocateMap(InstanceType instance_type,
int instance_size,
ElementsKind elements_kind) {
+ STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
+ DCHECK_IMPLIES(instance_type >= FIRST_JS_OBJECT_TYPE &&
+ !Map::CanHaveFastTransitionableElementsKind(instance_type),
+ IsDictionaryElementsKind(elements_kind) ||
+ IsTerminalElementsKind(elements_kind));
HeapObject* result = nullptr;
AllocationResult allocation = AllocateRaw(Map::kSize, MAP_SPACE);
if (!allocation.To(&result)) return allocation;
@@ -3760,7 +3766,10 @@ AllocationResult Heap::AllocateFixedArrayWithFiller(int length,
AllocationResult Heap::AllocatePropertyArray(int length,
PretenureFlag pretenure) {
+ // Allow length = 0 for the empty_property_array singleton.
DCHECK_LE(0, length);
+ DCHECK_IMPLIES(length == 0, pretenure == TENURED);
+
DCHECK(!InNewSpace(undefined_value()));
HeapObject* result = nullptr;
{
diff --git a/chromium/v8/src/heap/mark-compact.cc b/chromium/v8/src/heap/mark-compact.cc
index 37bce9162b9..3d28a18c7af 100644
--- a/chromium/v8/src/heap/mark-compact.cc
+++ b/chromium/v8/src/heap/mark-compact.cc
@@ -2568,6 +2568,7 @@ void MarkCompactCollector::MarkLiveObjects() {
TRACE_GC(heap()->tracer(),
GCTracer::Scope::MC_MARK_WEAK_CLOSURE_EPHEMERAL);
ProcessEphemeralMarking(false);
+ DCHECK(marking_worklist()->IsEmpty());
}
// The objects reachable from the roots, weak maps or object groups
@@ -2584,12 +2585,12 @@ void MarkCompactCollector::MarkLiveObjects() {
&IsUnmarkedHeapObject);
ProcessMarkingWorklist();
}
- // Then we mark the objects.
{
TRACE_GC(heap()->tracer(),
GCTracer::Scope::MC_MARK_WEAK_CLOSURE_WEAK_ROOTS);
- heap()->isolate()->global_handles()->IterateWeakRoots(&root_visitor);
+ heap()->isolate()->global_handles()->IterateWeakRootsForFinalizers(
+ &root_visitor);
ProcessMarkingWorklist();
}
@@ -2605,6 +2606,12 @@ void MarkCompactCollector::MarkLiveObjects() {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WRAPPER_EPILOGUE);
heap()->local_embedder_heap_tracer()->TraceEpilogue();
}
+ DCHECK(marking_worklist()->IsEmpty());
+ }
+
+ {
+ heap()->isolate()->global_handles()->IterateWeakRootsForPhantomHandles(
+ &IsUnmarkedHeapObject);
}
}
diff --git a/chromium/v8/src/heap/setup-heap-internal.cc b/chromium/v8/src/heap/setup-heap-internal.cc
index 25bb5d01b03..592fb53a7fd 100644
--- a/chromium/v8/src/heap/setup-heap-internal.cc
+++ b/chromium/v8/src/heap/setup-heap-internal.cc
@@ -103,10 +103,8 @@ bool Heap::CreateInitialMaps() {
}
ALLOCATE_PARTIAL_MAP(FIXED_ARRAY_TYPE, kVariableSizeSentinel, fixed_array);
- fixed_array_map()->set_elements_kind(HOLEY_ELEMENTS);
ALLOCATE_PARTIAL_MAP(FIXED_ARRAY_TYPE, kVariableSizeSentinel,
fixed_cow_array)
- fixed_cow_array_map()->set_elements_kind(HOLEY_ELEMENTS);
DCHECK_NE(fixed_array_map(), fixed_cow_array_map());
ALLOCATE_PARTIAL_MAP(ODDBALL_TYPE, Oddball::kSize, undefined);
diff --git a/chromium/v8/src/ic/accessor-assembler.cc b/chromium/v8/src/ic/accessor-assembler.cc
index 5e269963201..2472febd032 100644
--- a/chromium/v8/src/ic/accessor-assembler.cc
+++ b/chromium/v8/src/ic/accessor-assembler.cc
@@ -537,43 +537,51 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase(
}
}
+void AccessorAssembler::EmitAccessCheck(Node* expected_native_context,
+ Node* 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);
+ // 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 =
+ LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
+ Branch(WordEqual(expected_token, current_token), can_access, miss);
+}
+
Node* AccessorAssembler::EmitLoadICProtoArrayCheck(const LoadICParameters* p,
Node* handler,
Node* handler_length,
Node* handler_flags,
Label* miss) {
- VARIABLE(start_index, MachineType::PointerRepresentation());
- start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex));
+ VARIABLE(var_start_index, MachineType::PointerRepresentation(),
+ IntPtrConstant(LoadHandler::kFirstPrototypeIndex));
Label can_access(this);
GotoIfNot(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
&can_access);
{
// Skip this entry of a handler.
- start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1));
+ var_start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1));
int offset =
FixedArray::OffsetOfElementAt(LoadHandler::kFirstPrototypeIndex);
Node* expected_native_context =
LoadWeakCellValue(LoadObjectField(handler, offset), miss);
- CSA_ASSERT(this, IsNativeContext(expected_native_context));
-
- Node* native_context = LoadNativeContext(p->context);
- GotoIf(WordEqual(expected_native_context, native_context), &can_access);
- // If the receiver is not a JSGlobalProxy then we miss.
- GotoIfNot(IsJSGlobalProxy(p->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 =
- LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
- Branch(WordEqual(expected_token, current_token), &can_access, miss);
+
+ EmitAccessCheck(expected_native_context, p->context, p->receiver,
+ &can_access, miss);
}
BIND(&can_access);
- BuildFastLoop(start_index.value(), handler_length,
- [this, p, handler, miss](Node* current) {
+ BuildFastLoop(var_start_index.value(), handler_length,
+ [=](Node* current) {
Node* prototype_cell =
LoadFixedArrayElement(handler, current);
CheckPrototype(prototype_cell, p->name, miss);
@@ -649,16 +657,19 @@ void AccessorAssembler::HandleStoreICHandlerCase(
Label if_fast_smi(this), if_proxy(this);
+ STATIC_ASSERT(StoreHandler::kStoreGlobalProxy + 1 ==
+ StoreHandler::kStoreNormal);
STATIC_ASSERT(StoreHandler::kStoreNormal + 1 == StoreHandler::kProxy);
STATIC_ASSERT(StoreHandler::kProxy + 1 == StoreHandler::kKindsNumber);
Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
GotoIf(IntPtrLessThan(handler_kind,
- IntPtrConstant(StoreHandler::kStoreNormal)),
+ IntPtrConstant(StoreHandler::kStoreGlobalProxy)),
&if_fast_smi);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)),
&if_proxy);
-
+ CSA_ASSERT(this, WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kStoreNormal)));
Node* properties = LoadSlowProperties(holder);
VARIABLE(var_name_index, MachineType::PointerRepresentation());
@@ -716,62 +727,11 @@ void AccessorAssembler::HandleStoreICHandlerCase(
BIND(&store_global);
{
+ // Load value or miss if the {handler} weak cell is cleared.
Node* cell = LoadWeakCellValue(handler, miss);
- CSA_ASSERT(this, IsPropertyCell(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 = LoadObjectField(cell, PropertyCell::kValueOffset);
- Node* details =
- LoadAndUntagToWord32ObjectField(cell, PropertyCell::kDetailsOffset);
- Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
-
- Label constant(this), store(this), not_smi(this);
-
- GotoIf(
- Word32Equal(
- type, Int32Constant(static_cast<int>(PropertyCellType::kConstant))),
- &constant);
-
- GotoIf(IsTheHole(cell_contents), miss);
-
- GotoIf(
- Word32Equal(
- type, Int32Constant(static_cast<int>(PropertyCellType::kMutable))),
- &store);
- CSA_ASSERT(this,
- Word32Or(Word32Equal(type,
- Int32Constant(static_cast<int>(
- PropertyCellType::kConstantType))),
- Word32Equal(type,
- Int32Constant(static_cast<int>(
- PropertyCellType::kUndefined)))));
-
- GotoIfNot(TaggedIsSmi(cell_contents), &not_smi);
- GotoIfNot(TaggedIsSmi(p->value), miss);
- Goto(&store);
-
- BIND(&not_smi);
- {
- GotoIf(TaggedIsSmi(p->value), miss);
- Node* expected_map = LoadMap(cell_contents);
- Node* map = LoadMap(p->value);
- GotoIfNot(WordEqual(expected_map, map), miss);
- Goto(&store);
- }
-
- BIND(&store);
- {
- StoreObjectField(cell, PropertyCell::kValueOffset, p->value);
- Return(p->value);
- }
- BIND(&constant);
- {
- GotoIfNot(WordEqual(cell_contents, p->value), miss);
- Return(p->value);
- }
+ ExitPoint direct_exit(this);
+ StoreGlobalIC_PropertyCellCase(cell, p->value, &direct_exit, miss);
}
}
@@ -794,9 +754,11 @@ void AccessorAssembler::HandleStoreICElementHandlerCase(
void AccessorAssembler::HandleStoreICProtoHandler(
const StoreICParameters* p, Node* handler, Label* miss,
ElementSupport support_elements) {
+ Comment("HandleStoreICProtoHandler");
+
// IC dispatchers rely on these assumptions to be held.
STATIC_ASSERT(FixedArray::kLengthOffset ==
- StoreHandler::kTransitionCellOffset);
+ StoreHandler::kTransitionOrHolderCellOffset);
DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kSmiHandlerIndex),
StoreHandler::kSmiHandlerOffset);
DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kValidityCellIndex),
@@ -817,56 +779,77 @@ void AccessorAssembler::HandleStoreICProtoHandler(
Node* smi_or_code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
Node* maybe_transition_cell =
- LoadObjectField(handler, StoreHandler::kTransitionCellOffset);
+ LoadObjectField(handler, StoreHandler::kTransitionOrHolderCellOffset);
Label array_handler(this), tuple_handler(this);
Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &tuple_handler);
- VARIABLE(var_transition, MachineRepresentation::kTagged);
- Label if_transition(this), if_transition_to_constant(this),
- if_store_normal(this), if_proxy(this), do_store(this);
+ VARIABLE(var_transition_map_or_holder, MachineRepresentation::kTagged);
+ Label do_store(this), if_transition_map(this), if_holder_object(this);
BIND(&tuple_handler);
{
Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
- var_transition.Bind(transition);
+ var_transition_map_or_holder.Bind(transition);
Goto(&do_store);
}
BIND(&array_handler);
{
+ VARIABLE(var_start_index, MachineType::PointerRepresentation(),
+ IntPtrConstant(StoreHandler::kFirstPrototypeIndex));
+
+ Comment("array_handler");
+ Label can_access(this);
+ // Only Tuple3 handlers are allowed to have code handlers.
+ CSA_ASSERT(this, TaggedIsSmi(smi_or_code));
+ GotoIfNot(
+ IsSetSmi(smi_or_code, StoreHandler::DoAccessCheckOnReceiverBits::kMask),
+ &can_access);
+
+ {
+ // Skip this entry of a handler.
+ var_start_index.Bind(
+ IntPtrConstant(StoreHandler::kFirstPrototypeIndex + 1));
+
+ int offset =
+ FixedArray::OffsetOfElementAt(StoreHandler::kFirstPrototypeIndex);
+ Node* expected_native_context =
+ LoadWeakCellValue(LoadObjectField(handler, offset), miss);
+
+ EmitAccessCheck(expected_native_context, p->context, p->receiver,
+ &can_access, miss);
+ }
+ BIND(&can_access);
+
Node* length = SmiUntag(maybe_transition_cell);
- BuildFastLoop(IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length,
- [this, p, handler, miss](Node* current) {
+ BuildFastLoop(var_start_index.value(), length,
+ [=](Node* current) {
Node* prototype_cell =
LoadFixedArrayElement(handler, current);
CheckPrototype(prototype_cell, p->name, miss);
},
1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
- Node* maybe_transition_cell =
- LoadFixedArrayElement(handler, StoreHandler::kTransitionCellIndex);
+ Node* maybe_transition_cell = LoadFixedArrayElement(
+ handler, StoreHandler::kTransitionMapOrHolderCellIndex);
Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
- var_transition.Bind(transition);
+ var_transition_map_or_holder.Bind(transition);
Goto(&do_store);
}
BIND(&do_store);
{
- Branch(SmiEqual(smi_or_code, SmiConstant(StoreHandler::kProxy)), &if_proxy,
- &if_transition);
+ Node* transition = var_transition_map_or_holder.value();
+ Branch(IsMap(transition), &if_transition_map, &if_holder_object);
}
- BIND(&if_proxy);
+ BIND(&if_transition_map);
{
- Node* proxy = var_transition.value();
- HandleStoreToProxy(p, proxy, miss, support_elements);
- }
+ Label if_transition_to_constant(this), if_store_normal(this);
- BIND(&if_transition);
- {
Node* holder = p->receiver;
- Node* transition = var_transition.value();
+ Node* transition_map = var_transition_map_or_holder.value();
- GotoIf(IsDeprecatedMap(transition), miss);
+ GotoIf(IsDeprecatedMap(transition_map), miss);
if (support_elements == kSupportElements) {
Label if_smi_handler(this);
@@ -877,7 +860,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
StoreTransitionDescriptor descriptor(isolate());
TailCallStub(descriptor, code_handler, p->context, p->receiver, p->name,
- transition, p->value, p->slot, p->vector);
+ transition_map, p->value, p->slot, p->vector);
BIND(&if_smi_handler);
}
@@ -892,9 +875,12 @@ void AccessorAssembler::HandleStoreICProtoHandler(
GotoIf(WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kTransitionToConstant)),
&if_transition_to_constant);
+ CSA_ASSERT(this,
+ WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kTransitionToField)));
// Handle transitioning field stores.
- HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition,
+ HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition_map,
miss);
BIND(&if_transition_to_constant);
@@ -907,7 +893,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
IntPtrAdd(scaled_descriptor,
IntPtrConstant(DescriptorArray::kFirstIndex +
DescriptorArray::kEntryValueIndex));
- Node* descriptors = LoadMapDescriptors(transition);
+ Node* descriptors = LoadMapDescriptors(transition_map);
CSA_ASSERT(
this, UintPtrLessThan(descriptor,
LoadAndUntagFixedArrayBaseLength(descriptors)));
@@ -915,7 +901,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
Node* constant = LoadFixedArrayElement(descriptors, value_index);
GotoIf(WordNotEqual(p->value, constant), miss);
- StoreMap(p->receiver, transition);
+ StoreMap(p->receiver, transition_map);
Return(p->value);
}
@@ -955,6 +941,29 @@ void AccessorAssembler::HandleStoreICProtoHandler(
}
}
}
+ BIND(&if_holder_object);
+ {
+ Label if_store_global_proxy(this);
+ Node* holder = var_transition_map_or_holder.value();
+
+ Node* smi_handler = smi_or_code;
+ CSA_ASSERT(this, TaggedIsSmi(smi_handler));
+ Node* handler_word = SmiUntag(smi_handler);
+
+ Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
+ GotoIf(WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kStoreGlobalProxy)),
+ &if_store_global_proxy);
+ CSA_ASSERT(this,
+ WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)));
+ HandleStoreToProxy(p, holder, miss, support_elements);
+
+ BIND(&if_store_global_proxy);
+ {
+ ExitPoint direct_exit(this);
+ StoreGlobalIC_PropertyCellCase(holder, p->value, &direct_exit, miss);
+ }
+ }
}
void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
@@ -1174,7 +1183,7 @@ void AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
// TODO(gsathya): Clean up the type conversions by creating smarter
// helpers that do the correct op based on the mode.
VARIABLE(var_properties, MachineRepresentation::kTaggedPointer);
- VARIABLE(var_hash, MachineRepresentation::kWord32);
+ VARIABLE(var_encoded_hash, MachineRepresentation::kWord32);
VARIABLE(var_length, ParameterRepresentation(mode));
Node* properties = LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
@@ -1185,7 +1194,10 @@ void AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
BIND(&if_smi_hash);
{
- var_hash.Bind(SmiToWord32(properties));
+ Node* hash = SmiToWord32(properties);
+ Node* encoded_hash =
+ Word32Shl(hash, Int32Constant(PropertyArray::HashField::kShift));
+ var_encoded_hash.Bind(encoded_hash);
var_length.Bind(IntPtrOrSmiConstant(0, mode));
var_properties.Bind(EmptyFixedArrayConstant());
Goto(&extend_store);
@@ -1195,10 +1207,11 @@ void AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
{
Node* length_and_hash_int32 = LoadAndUntagToWord32ObjectField(
var_properties.value(), PropertyArray::kLengthAndHashOffset);
- var_hash.Bind(Word32And(length_and_hash_int32,
- Int32Constant(PropertyArray::kHashMask)));
- Node* length_intptr = ChangeInt32ToIntPtr(Word32And(
- length_and_hash_int32, Int32Constant(PropertyArray::kLengthMask)));
+ var_encoded_hash.Bind(Word32And(
+ length_and_hash_int32, Int32Constant(PropertyArray::HashField::kMask)));
+ Node* length_intptr = ChangeInt32ToIntPtr(
+ Word32And(length_and_hash_int32,
+ Int32Constant(PropertyArray::LengthField::kMask)));
Node* length = WordToParameter(length_intptr, mode);
var_length.Bind(length);
Goto(&extend_store);
@@ -1244,7 +1257,7 @@ void AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
Node* new_capacity_int32 =
TruncateWordToWord32(ParameterToWord(new_capacity, mode));
Node* new_length_and_hash_int32 =
- Word32Or(var_hash.value(), new_capacity_int32);
+ Word32Or(var_encoded_hash.value(), new_capacity_int32);
StoreObjectField(new_properties, PropertyArray::kLengthAndHashOffset,
SmiFromWord32(new_length_and_hash_int32));
StoreObjectField(object, JSObject::kPropertiesOrHashOffset, new_properties);
@@ -2392,6 +2405,65 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
}
}
+void AccessorAssembler::StoreGlobalIC_PropertyCellCase(Node* property_cell,
+ Node* value,
+ ExitPoint* exit_point,
+ Label* miss) {
+ Comment("StoreGlobalIC_TryPropertyCellCase");
+ CSA_ASSERT(this, IsPropertyCell(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 =
+ LoadObjectField(property_cell, PropertyCell::kValueOffset);
+ Node* details = LoadAndUntagToWord32ObjectField(property_cell,
+ PropertyCell::kDetailsOffset);
+ Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
+
+ Label constant(this), store(this), not_smi(this);
+
+ GotoIf(Word32Equal(type, Int32Constant(
+ static_cast<int>(PropertyCellType::kConstant))),
+ &constant);
+
+ GotoIf(IsTheHole(cell_contents), miss);
+
+ GotoIf(Word32Equal(
+ type, Int32Constant(static_cast<int>(PropertyCellType::kMutable))),
+ &store);
+ CSA_ASSERT(this,
+ Word32Or(Word32Equal(type, Int32Constant(static_cast<int>(
+ PropertyCellType::kConstantType))),
+ Word32Equal(type, Int32Constant(static_cast<int>(
+ PropertyCellType::kUndefined)))));
+
+ GotoIfNot(TaggedIsSmi(cell_contents), &not_smi);
+ GotoIfNot(TaggedIsSmi(value), miss);
+ Goto(&store);
+
+ BIND(&not_smi);
+ {
+ GotoIf(TaggedIsSmi(value), miss);
+ Node* expected_map = LoadMap(cell_contents);
+ Node* map = LoadMap(value);
+ GotoIfNot(WordEqual(expected_map, map), miss);
+ Goto(&store);
+ }
+
+ BIND(&store);
+ {
+ StoreObjectField(property_cell, PropertyCell::kValueOffset, value);
+ exit_point->Return(value);
+ }
+
+ BIND(&constant);
+ {
+ GotoIfNot(WordEqual(cell_contents, value), miss);
+ exit_point->Return(value);
+ }
+}
+
void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
Label miss(this, Label::kDeferred);
{
diff --git a/chromium/v8/src/ic/accessor-assembler.h b/chromium/v8/src/ic/accessor-assembler.h
index 1f330e58a4f..4fe1c0bbf99 100644
--- a/chromium/v8/src/ic/accessor-assembler.h
+++ b/chromium/v8/src/ic/accessor-assembler.h
@@ -115,6 +115,8 @@ class AccessorAssembler : public CodeStubAssembler {
void KeyedLoadIC(const LoadICParameters* p);
void KeyedLoadICGeneric(const LoadICParameters* p);
void StoreIC(const StoreICParameters* p);
+ void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
+ ExitPoint* exit_point, Label* miss);
void KeyedStoreIC(const StoreICParameters* p);
// IC dispatcher behavior.
@@ -150,6 +152,9 @@ class 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);
+
Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
Node* handler_length, Node* handler_flags,
Label* miss);
diff --git a/chromium/v8/src/ic/handler-configuration-inl.h b/chromium/v8/src/ic/handler-configuration-inl.h
index 26586141d77..dc1d5957239 100644
--- a/chromium/v8/src/ic/handler-configuration-inl.h
+++ b/chromium/v8/src/ic/handler-configuration-inl.h
@@ -108,6 +108,11 @@ Handle<Smi> LoadHandler::LoadElement(Isolate* isolate,
return handle(Smi::FromInt(config), isolate);
}
+Handle<Smi> StoreHandler::StoreGlobalProxy(Isolate* isolate) {
+ int config = KindBits::encode(kStoreGlobalProxy);
+ return handle(Smi::FromInt(config), isolate);
+}
+
Handle<Smi> StoreHandler::StoreNormal(Isolate* isolate) {
int config = KindBits::encode(kStoreNormal);
return handle(Smi::FromInt(config), isolate);
@@ -118,6 +123,13 @@ Handle<Smi> StoreHandler::StoreProxy(Isolate* isolate) {
return handle(Smi::FromInt(config), isolate);
}
+Handle<Smi> StoreHandler::EnableAccessCheckOnReceiver(Isolate* isolate,
+ Handle<Smi> smi_handler) {
+ int config = smi_handler->value();
+ config = DoAccessCheckOnReceiverBits::update(config, true);
+ return handle(Smi::FromInt(config), isolate);
+}
+
Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation,
@@ -184,15 +196,15 @@ Handle<Smi> StoreHandler::TransitionToConstant(Isolate* isolate,
// static
WeakCell* StoreHandler::GetTransitionCell(Object* handler) {
if (handler->IsTuple3()) {
- STATIC_ASSERT(kTransitionCellOffset == Tuple3::kValue1Offset);
+ STATIC_ASSERT(kTransitionOrHolderCellOffset == Tuple3::kValue1Offset);
WeakCell* cell = WeakCell::cast(Tuple3::cast(handler)->value1());
DCHECK(!cell->cleared());
return cell;
}
DCHECK(handler->IsFixedArray());
- WeakCell* cell =
- WeakCell::cast(FixedArray::cast(handler)->get(kTransitionCellIndex));
+ WeakCell* cell = WeakCell::cast(
+ FixedArray::cast(handler)->get(kTransitionMapOrHolderCellIndex));
DCHECK(!cell->cleared());
return cell;
}
diff --git a/chromium/v8/src/ic/handler-configuration.cc b/chromium/v8/src/ic/handler-configuration.cc
index e5ddf06d64a..b294c864a94 100644
--- a/chromium/v8/src/ic/handler-configuration.cc
+++ b/chromium/v8/src/ic/handler-configuration.cc
@@ -232,41 +232,59 @@ Handle<Object> StoreHandler::StoreElementTransition(
Handle<Object> StoreHandler::StoreTransition(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSObject> holder,
- Handle<Map> transition,
+ Handle<HeapObject> transition,
Handle<Name> name) {
- Handle<Object> smi_handler;
- if (transition->is_dictionary_map()) {
- smi_handler = StoreNormal(isolate);
- } else {
- int descriptor = transition->LastAdded();
- Handle<DescriptorArray> descriptors(transition->instance_descriptors());
- PropertyDetails details = descriptors->GetDetails(descriptor);
- Representation representation = details.representation();
- DCHECK(!representation.IsNone());
+ Handle<Smi> smi_handler;
+ Handle<WeakCell> transition_cell;
+
+ if (transition->IsMap()) {
+ Handle<Map> transition_map = Handle<Map>::cast(transition);
+ if (transition_map->is_dictionary_map()) {
+ smi_handler = StoreNormal(isolate);
+ } else {
+ int descriptor = transition_map->LastAdded();
+ Handle<DescriptorArray> descriptors(
+ transition_map->instance_descriptors());
+ PropertyDetails details = descriptors->GetDetails(descriptor);
+ Representation representation = details.representation();
+ DCHECK(!representation.IsNone());
- // Declarative handlers don't support access checks.
- DCHECK(!transition->is_access_check_needed());
+ // Declarative handlers don't support access checks.
+ DCHECK(!transition_map->is_access_check_needed());
- DCHECK_EQ(kData, details.kind());
- if (details.location() == kDescriptor) {
- smi_handler = TransitionToConstant(isolate, descriptor);
+ DCHECK_EQ(kData, details.kind());
+ if (details.location() == kDescriptor) {
+ smi_handler = TransitionToConstant(isolate, descriptor);
+ } else {
+ DCHECK_EQ(kField, details.location());
+ bool extend_storage = Map::cast(transition_map->GetBackPointer())
+ ->unused_property_fields() == 0;
+
+ FieldIndex index =
+ FieldIndex::ForDescriptor(*transition_map, descriptor);
+ smi_handler = TransitionToField(isolate, descriptor, index,
+ representation, extend_storage);
+ }
+ }
+ // |holder| is either a receiver if the property is non-existent or
+ // one of the prototypes.
+ DCHECK(!holder.is_null());
+ bool is_nonexistent = holder->map() == transition_map->GetBackPointer();
+ if (is_nonexistent) holder = Handle<JSObject>::null();
+ transition_cell = Map::WeakCellForMap(transition_map);
+
+ } else {
+ DCHECK(transition->IsPropertyCell());
+ if (receiver_map->IsJSGlobalObjectMap()) {
+ // TODO(ishell): this must be handled by StoreGlobalIC once it's finished.
+ return StoreGlobal(isolate, Handle<PropertyCell>::cast(transition));
} else {
- DCHECK_EQ(kField, details.location());
- bool extend_storage =
- Map::cast(transition->GetBackPointer())->unused_property_fields() ==
- 0;
-
- FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
- smi_handler = TransitionToField(isolate, descriptor, index,
- representation, extend_storage);
+ DCHECK(receiver_map->IsJSGlobalProxyMap());
+ smi_handler = StoreGlobalProxy(isolate);
+ transition_cell = isolate->factory()->NewWeakCell(transition);
}
}
- // |holder| is either a receiver if the property is non-existent or
- // one of the prototypes.
- DCHECK(!holder.is_null());
- bool is_nonexistent = holder->map() == transition->GetBackPointer();
- if (is_nonexistent) holder = Handle<JSObject>::null();
int checks_count =
GetPrototypeCheckCount(isolate, receiver_map, holder, name);
@@ -274,6 +292,12 @@ Handle<Object> StoreHandler::StoreTransition(Isolate* isolate,
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
+ if (receiver_map->is_access_check_needed()) {
+ DCHECK(!receiver_map->is_dictionary_map());
+ DCHECK_LE(1, checks_count); // For native context.
+ smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
+ }
+
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
if (validity_cell.is_null()) {
@@ -281,8 +305,6 @@ Handle<Object> StoreHandler::StoreTransition(Isolate* isolate,
validity_cell = handle(Smi::kZero, isolate);
}
- Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition);
-
Factory* factory = isolate->factory();
if (checks_count == 0) {
return factory->NewTuple3(transition_cell, smi_handler, validity_cell,
@@ -292,19 +314,25 @@ Handle<Object> StoreHandler::StoreTransition(Isolate* isolate,
factory->NewFixedArray(kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(kSmiHandlerIndex, *smi_handler);
handler_array->set(kValidityCellIndex, *validity_cell);
- handler_array->set(kTransitionCellIndex, *transition_cell);
+ handler_array->set(kTransitionMapOrHolderCellIndex, *transition_cell);
InitPrototypeChecks(isolate, receiver_map, holder, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
}
// static
+Handle<Object> StoreHandler::StoreGlobal(Isolate* isolate,
+ Handle<PropertyCell> cell) {
+ return isolate->factory()->NewWeakCell(cell);
+}
+
+// static
Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSProxy> proxy,
Handle<JSReceiver> receiver,
Handle<Name> name) {
- Handle<Object> smi_handler = StoreProxy(isolate);
+ Handle<Smi> smi_handler = StoreProxy(isolate);
if (receiver.is_identical_to(proxy)) return smi_handler;
@@ -312,6 +340,12 @@ Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
DCHECK_LE(0, checks_count);
+ if (receiver_map->is_access_check_needed()) {
+ DCHECK(!receiver_map->is_dictionary_map());
+ DCHECK_LE(1, checks_count); // For native context.
+ smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
+ }
+
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
if (validity_cell.is_null()) {
@@ -329,7 +363,7 @@ Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
factory->NewFixedArray(kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(kSmiHandlerIndex, *smi_handler);
handler_array->set(kValidityCellIndex, *validity_cell);
- handler_array->set(kTransitionCellIndex, *holder_cell);
+ handler_array->set(kTransitionMapOrHolderCellIndex, *holder_cell);
InitPrototypeChecks(isolate, receiver_map, proxy, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
diff --git a/chromium/v8/src/ic/handler-configuration.h b/chromium/v8/src/ic/handler-configuration.h
index a4c83b1220b..87ff45a46ae 100644
--- a/chromium/v8/src/ic/handler-configuration.h
+++ b/chromium/v8/src/ic/handler-configuration.h
@@ -178,12 +178,13 @@ class StoreHandler {
kStoreElement,
kStoreField,
kStoreConstField,
+ // TODO(ishell): remove once constant field tracking is done.
+ kTransitionToConstant = kStoreConstField,
kTransitionToField,
+ kStoreGlobalProxy,
kStoreNormal,
kProxy,
- kKindsNumber, // Keep last
- // TODO(ishell): remove once constant field tracking is done.
- kTransitionToConstant = kStoreConstField
+ kKindsNumber // Keep last
};
class KindBits : public BitField<Kind, 0, 3> {};
@@ -191,12 +192,19 @@ class StoreHandler {
static inline bool IsHandler(Object* maybe_handler);
+ // Applicable to kStoreGlobalProxy, kProxy kinds.
+
+ // Defines whether access rights check should be done on receiver object.
+ class DoAccessCheckOnReceiverBits
+ : public BitField<bool, KindBits::kNext, 1> {};
+
// Applicable to kStoreField, kTransitionToField and kTransitionToConstant
// kinds.
// Index of a value entry in the descriptor array.
class DescriptorBits
- : public BitField<unsigned, KindBits::kNext, kDescriptorIndexBitCount> {};
+ : public BitField<unsigned, DoAccessCheckOnReceiverBits::kNext,
+ kDescriptorIndexBitCount> {};
//
// Encoding when KindBits contains kTransitionToConstant.
//
@@ -221,7 +229,7 @@ class StoreHandler {
// The layout of an Tuple3 handler representing a transitioning store
// when prototype chain checks do not include non-existing lookups or access
// checks.
- static const int kTransitionCellOffset = Tuple3::kValue1Offset;
+ static const int kTransitionOrHolderCellOffset = Tuple3::kValue1Offset;
static const int kSmiHandlerOffset = Tuple3::kValue2Offset;
static const int kValidityCellOffset = Tuple3::kValue3Offset;
@@ -233,7 +241,7 @@ class StoreHandler {
// when prototype chain checks include non-existing lookups and access checks.
static const int kSmiHandlerIndex = 0;
static const int kValidityCellIndex = 1;
- static const int kTransitionCellIndex = 2;
+ static const int kTransitionMapOrHolderCellIndex = 2;
static const int kFirstPrototypeIndex = 3;
// Creates a Smi-handler for storing a field to fast object.
@@ -245,7 +253,7 @@ class StoreHandler {
static Handle<Object> StoreTransition(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSObject> holder,
- Handle<Map> transition,
+ Handle<HeapObject> transition,
Handle<Name> name);
static Handle<Object> StoreElementTransition(Isolate* isolate,
@@ -258,6 +266,14 @@ class StoreHandler {
Handle<JSReceiver> receiver,
Handle<Name> name);
+ // Creates a handler for storing a property to the property cell of a global
+ // object.
+ static Handle<Object> StoreGlobal(Isolate* isolate,
+ Handle<PropertyCell> cell);
+
+ // Creates a Smi-handler for storing a property to a global proxy object.
+ static inline Handle<Smi> StoreGlobalProxy(Isolate* isolate);
+
// Creates a Smi-handler for storing a property to a slow object.
static inline Handle<Smi> StoreNormal(Isolate* isolate);
@@ -265,6 +281,11 @@ class StoreHandler {
static inline Handle<Smi> StoreProxy(Isolate* isolate);
private:
+ // Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver
+ // check is a part of a prototype chain check.
+ static inline Handle<Smi> EnableAccessCheckOnReceiver(
+ Isolate* isolate, Handle<Smi> smi_handler);
+
static inline Handle<Smi> StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation,
diff --git a/chromium/v8/src/ic/ic.cc b/chromium/v8/src/ic/ic.cc
index fe7e372c6bb..09920241eec 100644
--- a/chromium/v8/src/ic/ic.cc
+++ b/chromium/v8/src/ic/ic.cc
@@ -1366,23 +1366,19 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
TRACE_IC("StoreIC", lookup->name());
}
-namespace {
-
-Handle<Object> StoreGlobal(Isolate* isolate, Handle<PropertyCell> cell) {
- return isolate->factory()->NewWeakCell(cell);
-}
-
-} // namespace
-
Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
switch (lookup->state()) {
case LookupIterator::TRANSITION: {
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
- auto store_target = lookup->GetStoreTarget();
+ Handle<JSObject> store_target = lookup->GetStoreTarget();
if (store_target->IsJSGlobalObject()) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
- return StoreGlobal(isolate(), lookup->transition_cell());
+
+ Handle<Object> handler = StoreHandler::StoreTransition(
+ isolate(), receiver_map(), store_target, lookup->transition_cell(),
+ lookup->name());
+ return handler;
}
// Currently not handled by CompileStoreTransition.
if (!holder->HasFastProperties()) {
@@ -1477,7 +1473,8 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
if (lookup->is_dictionary_holder()) {
if (holder->IsJSGlobalObject()) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH);
- return StoreGlobal(isolate(), lookup->GetPropertyCell());
+ return StoreHandler::StoreGlobal(isolate(),
+ lookup->GetPropertyCell());
}
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
DCHECK(holder.is_identical_to(receiver));
diff --git a/chromium/v8/src/ic/keyed-store-generic.cc b/chromium/v8/src/ic/keyed-store-generic.cc
index 0f4b3eee466..7ff72bb72fd 100644
--- a/chromium/v8/src/ic/keyed-store-generic.cc
+++ b/chromium/v8/src/ic/keyed-store-generic.cc
@@ -811,14 +811,14 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&tuple3);
{
var_transition_cell.Bind(LoadObjectField(
- maybe_handler, StoreHandler::kTransitionCellOffset));
+ maybe_handler, StoreHandler::kTransitionOrHolderCellOffset));
Goto(&check_key);
}
BIND(&fixedarray);
{
var_transition_cell.Bind(LoadFixedArrayElement(
- maybe_handler, StoreHandler::kTransitionCellIndex));
+ maybe_handler, StoreHandler::kTransitionMapOrHolderCellIndex));
Goto(&check_key);
}
diff --git a/chromium/v8/src/inspector/inspector.gypi b/chromium/v8/src/inspector/inspector.gypi
index 96614e692a8..d6443283f5a 100644
--- a/chromium/v8/src/inspector/inspector.gypi
+++ b/chromium/v8/src/inspector/inspector.gypi
@@ -31,8 +31,8 @@
'inspector_all_sources': [
'<@(inspector_generated_sources)',
'<(inspector_generated_injected_script)',
- '../../include/v8-inspector.h',
- '../../include/v8-inspector-protocol.h',
+ '../include/v8-inspector.h',
+ '../include/v8-inspector-protocol.h',
'inspector/injected-script.cc',
'inspector/injected-script.h',
'inspector/inspected-context.cc',
diff --git a/chromium/v8/src/inspector/v8-debugger.cc b/chromium/v8/src/inspector/v8-debugger.cc
index 981a622b62d..3e321a42757 100644
--- a/chromium/v8/src/inspector/v8-debugger.cc
+++ b/chromium/v8/src/inspector/v8-debugger.cc
@@ -669,10 +669,8 @@ v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
}
if (value->IsFunction()) {
v8::Local<v8::Function> function = value.As<v8::Function>();
- v8::Local<v8::Value> boundFunction = function->GetBoundFunction();
v8::Local<v8::Value> scopes;
- if (boundFunction->IsUndefined() &&
- functionScopes(context, function).ToLocal(&scopes)) {
+ if (functionScopes(context, function).ToLocal(&scopes)) {
createDataProperty(context, properties, properties->Length(),
toV8StringInternalized(m_isolate, "[[Scopes]]"));
createDataProperty(context, properties, properties->Length(), scopes);
@@ -720,6 +718,8 @@ void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) {
if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) return;
// TODO(dgozman): ideally, this should be per context group.
m_maxAsyncCallStackDepth = maxAsyncCallStackDepth;
+ m_inspector->client()->maxAsyncCallStackDepthChanged(
+ m_maxAsyncCallStackDepth);
if (!maxAsyncCallStackDepth) allAsyncTasksCanceled();
}
diff --git a/chromium/v8/src/isolate.cc b/chromium/v8/src/isolate.cc
index 942938eded2..9312432763c 100644
--- a/chromium/v8/src/isolate.cc
+++ b/chromium/v8/src/isolate.cc
@@ -3055,16 +3055,17 @@ bool Isolate::IsInAnyContext(Object* object, uint32_t index) {
return false;
}
-bool Isolate::IsFastArrayConstructorPrototypeChainIntact() {
+bool Isolate::IsFastArrayConstructorPrototypeChainIntact(Context* context) {
PropertyCell* no_elements_cell = heap()->array_protector();
bool cell_reports_intact =
no_elements_cell->value()->IsSmi() &&
Smi::ToInt(no_elements_cell->value()) == kProtectorValid;
#ifdef DEBUG
+ Context* native_context = context->native_context();
+
Map* root_array_map =
- raw_native_context()->GetInitialJSArrayMap(GetInitialFastElementsKind());
- Context* native_context = context()->native_context();
+ native_context->GetInitialJSArrayMap(GetInitialFastElementsKind());
JSObject* initial_array_proto = JSObject::cast(
native_context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
JSObject* initial_object_proto = JSObject::cast(
@@ -3093,8 +3094,11 @@ bool Isolate::IsFastArrayConstructorPrototypeChainIntact() {
PrototypeIterator iter(this, initial_array_proto);
if (iter.IsAtEnd() || iter.GetCurrent() != initial_object_proto) {
DCHECK_EQ(false, cell_reports_intact);
+ DCHECK(!has_pending_exception());
return cell_reports_intact;
}
+ DCHECK(!has_pending_exception());
+ DCHECK(!has_pending_exception());
elements = initial_object_proto->elements();
if (elements != heap()->empty_fixed_array() &&
@@ -3108,12 +3112,15 @@ bool Isolate::IsFastArrayConstructorPrototypeChainIntact() {
DCHECK_EQ(false, cell_reports_intact);
return cell_reports_intact;
}
-
#endif
return cell_reports_intact;
}
+bool Isolate::IsFastArrayConstructorPrototypeChainIntact() {
+ return Isolate::IsFastArrayConstructorPrototypeChainIntact(context());
+}
+
bool Isolate::IsIsConcatSpreadableLookupChainIntact() {
Cell* is_concat_spreadable_cell = heap()->is_concat_spreadable_protector();
bool is_is_concat_spreadable_set =
diff --git a/chromium/v8/src/isolate.h b/chromium/v8/src/isolate.h
index 43ffb8ce000..44a52508086 100644
--- a/chromium/v8/src/isolate.h
+++ b/chromium/v8/src/isolate.h
@@ -1070,7 +1070,13 @@ class Isolate {
static const int kProtectorInvalid = 0;
inline bool IsArrayConstructorIntact();
+
+ // The version with an explicit context parameter can be used when
+ // Isolate::context is not set up, e.g. when calling directly into C++ from
+ // CSA.
+ bool IsFastArrayConstructorPrototypeChainIntact(Context* context);
bool IsFastArrayConstructorPrototypeChainIntact();
+
inline bool IsArraySpeciesLookupChainIntact();
bool IsIsConcatSpreadableLookupChainIntact();
bool IsIsConcatSpreadableLookupChainIntact(JSReceiver* receiver);
diff --git a/chromium/v8/src/log.cc b/chromium/v8/src/log.cc
index 0eb9b250089..006acf71b95 100644
--- a/chromium/v8/src/log.cc
+++ b/chromium/v8/src/log.cc
@@ -1547,7 +1547,10 @@ static int EnumerateCompiledFunctions(Heap* heap,
!Script::cast(maybe_script)->HasValidSource()) {
continue;
}
- if (function->HasOptimizedCode()) {
+ // TODO(jarin) This leaves out deoptimized code that might still be on the
+ // stack. Also note that we will not log optimized code objects that are
+ // only on a type feedback vector. We should make this mroe precise.
+ if (function->IsOptimized()) {
AddFunctionAndCode(sfi, AbstractCode::cast(function->code()), sfis,
code_objects, compiled_funcs_count);
++compiled_funcs_count;
diff --git a/chromium/v8/src/lookup.cc b/chromium/v8/src/lookup.cc
index 75f008f105d..91d87ebbff9 100644
--- a/chromium/v8/src/lookup.cc
+++ b/chromium/v8/src/lookup.cc
@@ -94,21 +94,9 @@ LookupIterator LookupIterator::ForTransitionHandler(
has_property);
if (!transition_map->is_dictionary_map()) {
- PropertyConstness new_constness = kConst;
- if (FLAG_track_constant_fields) {
- if (it.constness() == kConst) {
- DCHECK_EQ(kData, it.property_details_.kind());
- // Check that current value matches new value otherwise we should make
- // the property mutable.
- if (!it.IsConstFieldValueEqualTo(*value)) new_constness = kMutable;
- }
- } else {
- new_constness = kMutable;
- }
-
int descriptor_number = transition_map->LastAdded();
Handle<Map> new_map = Map::PrepareForDataProperty(
- transition_map, descriptor_number, new_constness, value);
+ transition_map, descriptor_number, kConst, value);
// Reload information; this is no-op if nothing changed.
it.property_details_ =
new_map->instance_descriptors()->GetDetails(descriptor_number);
diff --git a/chromium/v8/src/map-updater.cc b/chromium/v8/src/map-updater.cc
index 05ef5fd3e21..3a9a9caf14c 100644
--- a/chromium/v8/src/map-updater.cc
+++ b/chromium/v8/src/map-updater.cc
@@ -123,8 +123,9 @@ Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
new_field_type_ = field_type;
}
- GeneralizeIfTransitionableFastElementsKind(
- &new_constness_, &new_representation_, &new_field_type_);
+ Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
+ isolate_, old_map_->instance_type(), &new_constness_,
+ &new_representation_, &new_field_type_);
if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
if (FindRootMap() == kEnd) return result_map_;
@@ -158,28 +159,6 @@ Handle<Map> MapUpdater::Update() {
return result_map_;
}
-void MapUpdater::GeneralizeIfTransitionableFastElementsKind(
- PropertyConstness* constness, Representation* representation,
- Handle<FieldType>* field_type) {
- DCHECK_EQ(is_transitionable_fast_elements_kind_,
- IsTransitionableFastElementsKind(new_elements_kind_));
- if (is_transitionable_fast_elements_kind_ &&
- Map::IsInplaceGeneralizableField(*constness, *representation,
- **field_type)) {
- // We don't support propagation of field generalization through elements
- // kind transitions because they are inserted into the transition tree
- // before field transitions. In order to avoid complexity of handling
- // such a case we ensure that all maps with transitionable elements kinds
- // do not have fields that can be generalized in-place (without creation
- // of a new map).
- if (FLAG_track_constant_fields && FLAG_modify_map_inplace) {
- *constness = kMutable;
- }
- DCHECK(representation->IsHeapObject());
- *field_type = FieldType::Any(isolate_);
- }
-}
-
void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
PropertyConstness new_constness,
Representation new_representation,
@@ -437,6 +416,7 @@ MapUpdater::State MapUpdater::FindTargetMap() {
}
Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
+ InstanceType instance_type = old_map_->instance_type();
int target_nof = target_map_->NumberOfOwnDescriptors();
Handle<DescriptorArray> target_descriptors(
target_map_->instance_descriptors(), isolate_);
@@ -518,8 +498,9 @@ Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
old_details.representation(), old_field_type, next_representation,
target_field_type, isolate_);
- GeneralizeIfTransitionableFastElementsKind(
- &next_constness, &next_representation, &next_field_type);
+ Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
+ isolate_, instance_type, &next_constness, &next_representation,
+ &next_field_type);
Handle<Object> wrapped_type(Map::WrapFieldType(next_field_type));
Descriptor d;
diff --git a/chromium/v8/src/map-updater.h b/chromium/v8/src/map-updater.h
index a1d052261c0..7c5e92f2bf2 100644
--- a/chromium/v8/src/map-updater.h
+++ b/chromium/v8/src/map-updater.h
@@ -148,10 +148,6 @@ class MapUpdater {
Handle<DescriptorArray> descriptors, int descriptor,
PropertyLocation location, Representation representation);
- inline void GeneralizeIfTransitionableFastElementsKind(
- PropertyConstness* constness, Representation* representation,
- Handle<FieldType>* field_type);
-
void GeneralizeField(Handle<Map> map, int modify_index,
PropertyConstness new_constness,
Representation new_representation,
diff --git a/chromium/v8/src/messages.cc b/chromium/v8/src/messages.cc
index c1f08739dca..ddc5124cfcf 100644
--- a/chromium/v8/src/messages.cc
+++ b/chromium/v8/src/messages.cc
@@ -113,6 +113,9 @@ void MessageHandler::ReportMessage(Isolate* isolate, const MessageLocation* loc,
}
if (!maybe_stringified.ToHandle(&stringified)) {
+ DCHECK(isolate->has_pending_exception());
+ isolate->clear_pending_exception();
+ isolate->set_external_caught_exception(false);
stringified =
isolate->factory()->NewStringFromAsciiChecked("exception");
}
diff --git a/chromium/v8/src/messages.h b/chromium/v8/src/messages.h
index 51a62582157..9237f7a231e 100644
--- a/chromium/v8/src/messages.h
+++ b/chromium/v8/src/messages.h
@@ -543,7 +543,7 @@ class ErrorUtils : public AllStatic {
T(ToPrecisionFormatRange, \
"toPrecision() argument must be between 1 and 100") \
T(ToRadixFormatRange, "toString() radix argument must be between 2 and 36") \
- T(TypedArraySetNegativeOffset, "Start offset is negative") \
+ T(TypedArraySetOffsetOutOfBounds, "offset is out of bounds") \
T(TypedArraySetSourceTooLarge, "Source is too large") \
T(UnsupportedTimeZone, "Unsupported time zone specified %") \
T(ValueOutOfRange, "Value % out of range for % options property %") \
diff --git a/chromium/v8/src/objects-debug.cc b/chromium/v8/src/objects-debug.cc
index 98ccfc74682..e403fe9b25d 100644
--- a/chromium/v8/src/objects-debug.cc
+++ b/chromium/v8/src/objects-debug.cc
@@ -424,6 +424,9 @@ void Map::MapVerify() {
CHECK_IMPLIES(has_named_interceptor(), may_have_interesting_symbols());
CHECK_IMPLIES(is_dictionary_map(), may_have_interesting_symbols());
CHECK_IMPLIES(is_access_check_needed(), may_have_interesting_symbols());
+ CHECK_IMPLIES(IsJSObjectMap() && !CanHaveFastTransitionableElementsKind(),
+ IsDictionaryElementsKind(elements_kind()) ||
+ IsTerminalElementsKind(elements_kind()));
}
@@ -456,6 +459,12 @@ void FixedArray::FixedArrayVerify() {
}
void PropertyArray::PropertyArrayVerify() {
+ if (length() == 0) {
+ CHECK_EQ(this, this->GetHeap()->empty_property_array());
+ return;
+ }
+ // There are no empty PropertyArrays.
+ CHECK_LT(0, length());
for (int i = 0; i < length(); i++) {
Object* e = get(i);
VerifyPointer(e);
diff --git a/chromium/v8/src/objects-inl.h b/chromium/v8/src/objects-inl.h
index 7212a43d27a..f29c4d8c492 100644
--- a/chromium/v8/src/objects-inl.h
+++ b/chromium/v8/src/objects-inl.h
@@ -2654,33 +2654,31 @@ SYNCHRONIZED_SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
int PropertyArray::length() const {
Object* value_obj = READ_FIELD(this, kLengthAndHashOffset);
int value = Smi::ToInt(value_obj);
- return value & kLengthMask;
+ return LengthField::decode(value);
}
void PropertyArray::initialize_length(int len) {
SLOW_DCHECK(len >= 0);
- SLOW_DCHECK(len < kMaxLength);
+ SLOW_DCHECK(len < LengthField::kMax);
WRITE_FIELD(this, kLengthAndHashOffset, Smi::FromInt(len));
}
int PropertyArray::synchronized_length() const {
Object* value_obj = ACQUIRE_READ_FIELD(this, kLengthAndHashOffset);
int value = Smi::ToInt(value_obj);
- return value & kLengthMask;
+ return LengthField::decode(value);
}
int PropertyArray::Hash() const {
Object* value_obj = READ_FIELD(this, kLengthAndHashOffset);
int value = Smi::ToInt(value_obj);
- int hash = value & kHashMask;
- return hash;
+ return HashField::decode(value);
}
-void PropertyArray::SetHash(int masked_hash) {
- DCHECK_EQ(masked_hash & JSReceiver::kHashMask, masked_hash);
+void PropertyArray::SetHash(int hash) {
Object* value_obj = READ_FIELD(this, kLengthAndHashOffset);
int value = Smi::ToInt(value_obj);
- value = (value & kLengthMask) | masked_hash;
+ value = HashField::update(value, hash);
WRITE_FIELD(this, kLengthAndHashOffset, Smi::FromInt(value));
}
@@ -5039,12 +5037,12 @@ void JSArrayBuffer::set_has_guard_region(bool value) {
set_bit_field(HasGuardRegion::update(bit_field(), value));
}
-bool JSArrayBuffer::is_wasm_buffer() {
- return IsWasmBuffer::decode(bit_field());
+bool JSArrayBuffer::is_growable() {
+ return IsGrowable::decode(bit_field());
}
-void JSArrayBuffer::set_is_wasm_buffer(bool value) {
- set_bit_field(IsWasmBuffer::update(bit_field(), value));
+void JSArrayBuffer::set_is_growable(bool value) {
+ set_bit_field(IsGrowable::update(bit_field(), value));
}
Object* JSArrayBufferView::byte_offset() const {
diff --git a/chromium/v8/src/objects-printer.cc b/chromium/v8/src/objects-printer.cc
index 7dbbdc5a627..33928a5aa71 100644
--- a/chromium/v8/src/objects-printer.cc
+++ b/chromium/v8/src/objects-printer.cc
@@ -495,7 +495,12 @@ static void JSObjectPrintHeader(std::ostream& os, JSObject* obj,
static void JSObjectPrintBody(std::ostream& os, JSObject* obj, // NOLINT
bool print_elements = true) {
- os << "\n - properties = " << Brief(obj->raw_properties_or_hash()) << " {";
+ os << "\n - properties = ";
+ Object* properties_or_hash = obj->raw_properties_or_hash();
+ if (!properties_or_hash->IsSmi()) {
+ os << Brief(properties_or_hash);
+ }
+ os << " {";
if (obj->PrintProperties(os)) os << "\n ";
os << "}\n";
if (print_elements && obj->elements()->length() > 0) {
@@ -972,7 +977,7 @@ void JSArrayBuffer::JSArrayBufferPrint(std::ostream& os) { // NOLINT
if (was_neutered()) os << "\n - neutered";
if (is_shared()) os << "\n - shared";
if (has_guard_region()) os << "\n - has_guard_region";
- if (is_wasm_buffer()) os << "\n - wasm_buffer";
+ if (is_growable()) os << "\n - growable";
JSObjectPrintBody(os, this, !was_neutered());
}
diff --git a/chromium/v8/src/objects.cc b/chromium/v8/src/objects.cc
index 7b7728c3014..b61d1eca324 100644
--- a/chromium/v8/src/objects.cc
+++ b/chromium/v8/src/objects.cc
@@ -3664,18 +3664,12 @@ MaybeHandle<Map> Map::CopyWithField(Handle<Map> map, Handle<Name> name,
int index = map->NextFreePropertyIndex();
if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
+ constness = kMutable;
representation = Representation::Tagged();
type = FieldType::Any(isolate);
- } else if (IsTransitionableFastElementsKind(map->elements_kind()) &&
- IsInplaceGeneralizableField(constness, representation, *type)) {
- // We don't support propagation of field generalization through elements
- // kind transitions because they are inserted into the transition tree
- // before field transitions. In order to avoid complexity of handling
- // such a case we ensure that all maps with transitionable elements kinds
- // do not have fields that can be generalized in-place (without creation
- // of a new map).
- DCHECK(representation.IsHeapObject());
- type = FieldType::Any(isolate);
+ } else {
+ Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
+ isolate, map->instance_type(), &constness, &representation, &type);
}
Handle<Object> wrapped_type(WrapFieldType(type));
@@ -4051,9 +4045,7 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
}
}
- if (external > 0) {
- object->SetProperties(*array);
- }
+ object->SetProperties(*array);
// Create filler object past the new instance size.
int new_instance_size = new_map->instance_size();
@@ -4257,6 +4249,10 @@ int Map::NumberOfFields() const {
return result;
}
+bool Map::HasOutOfObjectProperties() const {
+ return GetInObjectProperties() < NumberOfFields();
+}
+
void DescriptorArray::GeneralizeAllFields() {
int length = number_of_descriptors();
for (int i = 0; i < length; i++) {
@@ -5843,10 +5839,8 @@ void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
storage = isolate->factory()->NewFixedArray(inobject);
}
- Handle<PropertyArray> array;
- if (external > 0) {
- array = isolate->factory()->NewPropertyArray(external);
- }
+ Handle<PropertyArray> array =
+ isolate->factory()->NewPropertyArray(external);
for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
PropertyDetails details = descriptors->GetDetails(i);
@@ -5862,9 +5856,7 @@ void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
}
}
- if (external > 0) {
- object->SetProperties(*array);
- }
+ object->SetProperties(*array);
if (!FLAG_unbox_double_fields) {
for (int i = 0; i < inobject; i++) {
@@ -6231,6 +6223,9 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Handle<PropertyArray> fields =
factory->NewPropertyArray(number_of_allocated_fields);
+ bool is_transitionable_elements_kind =
+ IsTransitionableFastElementsKind(old_map->elements_kind());
+
// Fill in the instance descriptor and the fields.
int current_offset = 0;
for (int i = 0; i < instance_descriptor_length; i++) {
@@ -6258,8 +6253,14 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
d = Descriptor::DataConstant(key, handle(value, isolate),
details.attributes());
} else {
+ // Ensure that we make constant field only when elements kind is not
+ // transitionable.
+ PropertyConstness constness =
+ FLAG_track_constant_fields && !is_transitionable_elements_kind
+ ? kConst
+ : kMutable;
d = Descriptor::DataField(
- key, current_offset, details.attributes(), kDefaultFieldConstness,
+ key, current_offset, details.attributes(), constness,
// TODO(verwaest): value->OptimalRepresentation();
Representation::Tagged(), FieldType::Any(isolate));
}
@@ -6373,22 +6374,25 @@ Handle<SeededNumberDictionary> JSObject::NormalizeElements(
namespace {
-Object* SetHashAndUpdateProperties(HeapObject* properties, int masked_hash) {
- DCHECK_NE(PropertyArray::kNoHashSentinel, masked_hash);
- DCHECK_EQ(masked_hash & JSReceiver::kHashMask, masked_hash);
+Object* SetHashAndUpdateProperties(HeapObject* properties, int hash) {
+ DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
+ DCHECK(PropertyArray::HashField::is_valid(hash));
- if (properties == properties->GetHeap()->empty_fixed_array() ||
- properties == properties->GetHeap()->empty_property_dictionary()) {
- return Smi::FromInt(masked_hash);
+ Heap* heap = properties->GetHeap();
+ if (properties == heap->empty_fixed_array() ||
+ properties == heap->empty_property_array() ||
+ properties == heap->empty_property_dictionary()) {
+ return Smi::FromInt(hash);
}
if (properties->IsPropertyArray()) {
- PropertyArray::cast(properties)->SetHash(masked_hash);
+ PropertyArray::cast(properties)->SetHash(hash);
+ DCHECK_LT(0, PropertyArray::cast(properties)->length());
return properties;
}
DCHECK(properties->IsDictionary());
- NameDictionary::cast(properties)->SetHash(masked_hash);
+ NameDictionary::cast(properties)->SetHash(hash);
return properties;
}
@@ -6419,18 +6423,21 @@ int GetIdentityHashHelper(Isolate* isolate, JSReceiver* object) {
}
} // namespace
-void JSReceiver::SetIdentityHash(int masked_hash) {
+void JSReceiver::SetIdentityHash(int hash) {
DisallowHeapAllocation no_gc;
- DCHECK_NE(PropertyArray::kNoHashSentinel, masked_hash);
- DCHECK_EQ(masked_hash & JSReceiver::kHashMask, masked_hash);
+ DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
+ DCHECK(PropertyArray::HashField::is_valid(hash));
HeapObject* existing_properties = HeapObject::cast(raw_properties_or_hash());
Object* new_properties =
- SetHashAndUpdateProperties(existing_properties, masked_hash);
+ SetHashAndUpdateProperties(existing_properties, hash);
set_raw_properties_or_hash(new_properties);
}
void JSReceiver::SetProperties(HeapObject* properties) {
+ DCHECK_IMPLIES(properties->IsPropertyArray() &&
+ PropertyArray::cast(properties)->length() == 0,
+ properties == properties->GetHeap()->empty_property_array());
DisallowHeapAllocation no_gc;
Isolate* isolate = properties->GetIsolate();
int hash = GetIdentityHashHelper(isolate, this);
@@ -6481,11 +6488,11 @@ Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate) {
return Smi::cast(hash_obj);
}
- int masked_hash = isolate->GenerateIdentityHash(JSReceiver::kHashMask);
- DCHECK_NE(PropertyArray::kNoHashSentinel, masked_hash);
+ int hash = isolate->GenerateIdentityHash(PropertyArray::HashField::kMax);
+ DCHECK_NE(PropertyArray::kNoHashSentinel, hash);
- SetIdentityHash(masked_hash);
- return Smi::FromInt(masked_hash);
+ SetIdentityHash(hash);
+ return Smi::FromInt(hash);
}
Object* JSProxy::GetIdentityHash() { return hash(); }
@@ -9397,6 +9404,13 @@ void Map::InstallDescriptors(Handle<Map> parent, Handle<Map> child,
Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
TransitionFlag flag) {
+ // Only certain objects are allowed to have non-terminal fast transitional
+ // elements kinds.
+ DCHECK(map->IsJSObjectMap());
+ DCHECK_IMPLIES(
+ !map->CanHaveFastTransitionableElementsKind(),
+ IsDictionaryElementsKind(kind) || IsTerminalElementsKind(kind));
+
Map* maybe_elements_transition_map = NULL;
if (flag == INSERT_TRANSITION) {
// Ensure we are requested to add elements kind transition "near the root".
@@ -12779,6 +12793,10 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
case JS_VALUE_TYPE:
case JS_WEAK_MAP_TYPE:
case JS_WEAK_SET_TYPE:
+ case WASM_INSTANCE_TYPE:
+ case WASM_MEMORY_TYPE:
+ case WASM_MODULE_TYPE:
+ case WASM_TABLE_TYPE:
return true;
case BIGINT_TYPE:
@@ -15170,6 +15188,9 @@ bool JSObject::WouldConvertToSlowElements(uint32_t index) {
static ElementsKind BestFittingFastElementsKind(JSObject* object) {
+ if (!object->map()->CanHaveFastTransitionableElementsKind()) {
+ return HOLEY_ELEMENTS;
+ }
if (object->HasSloppyArgumentsElements()) {
return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
}
diff --git a/chromium/v8/src/objects.h b/chromium/v8/src/objects.h
index 18911a77fa3..895d92ba319 100644
--- a/chromium/v8/src/objects.h
+++ b/chromium/v8/src/objects.h
@@ -1950,17 +1950,10 @@ class PropertyArray : public HeapObject {
// No weak fields.
typedef BodyDescriptor BodyDescriptorWeak;
- static const int kLengthMask = 0x3ff;
-#if V8_TARGET_ARCH_64_BIT
- static const int kHashMask = 0x7ffffc00;
- STATIC_ASSERT(kLengthMask + kHashMask == 0x7fffffff);
-#else
- static const int kHashMask = 0x3ffffc00;
- STATIC_ASSERT(kLengthMask + kHashMask == 0x3fffffff);
-#endif
-
- static const int kMaxLength = kLengthMask;
- STATIC_ASSERT(kMaxLength > kMaxNumberOfDescriptors);
+ static const int kLengthFieldSize = 10;
+ class LengthField : public BitField<int, 0, kLengthFieldSize> {};
+ class HashField : public BitField<int, kLengthFieldSize,
+ kSmiValueSize - kLengthFieldSize - 1> {};
static const int kNoHashSentinel = 0;
@@ -1984,6 +1977,9 @@ class JSReceiver: public HeapObject {
// Gets slow properties for non-global objects.
inline NameDictionary* property_dictionary() const;
+ // Sets the properties backing store and makes sure any existing hash is moved
+ // to the new properties store. To clear out the properties store, pass in the
+ // empty_fixed_array(), the hash will be maintained in this case as well.
void SetProperties(HeapObject* properties);
// There are five possible values for the properties offset.
@@ -2187,7 +2183,7 @@ class JSReceiver: public HeapObject {
MUST_USE_RESULT static MaybeHandle<FixedArray> GetOwnEntries(
Handle<JSReceiver> object, PropertyFilter filter);
- static const int kHashMask = PropertyArray::kHashMask;
+ static const int kHashMask = PropertyArray::HashField::kMask;
// Layout description.
static const int kPropertiesOrHashOffset = HeapObject::kHeaderSize;
@@ -6249,10 +6245,8 @@ class JSArrayBuffer: public JSObject {
inline bool has_guard_region() const;
inline void set_has_guard_region(bool value);
- // TODO(gdeepti): This flag is introduced to disable asm.js optimizations in
- // js-typer-lowering.cc, remove when the asm.js case is fixed.
- inline bool is_wasm_buffer();
- inline void set_is_wasm_buffer(bool value);
+ inline bool is_growable();
+ inline void set_is_growable(bool value);
DECL_CAST(JSArrayBuffer)
@@ -6312,7 +6306,7 @@ class JSArrayBuffer: public JSObject {
class WasNeutered : public BitField<bool, 3, 1> {};
class IsShared : public BitField<bool, 4, 1> {};
class HasGuardRegion : public BitField<bool, 5, 1> {};
- class IsWasmBuffer : public BitField<bool, 6, 1> {};
+ class IsGrowable : public BitField<bool, 6, 1> {};
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer);
@@ -6387,7 +6381,7 @@ class JSTypedArray: public JSArrayBufferView {
DECL_PRINTER(JSTypedArray)
DECL_VERIFIER(JSTypedArray)
- static const int kLengthOffset = kViewSize + kPointerSize;
+ static const int kLengthOffset = kViewSize;
static const int kSize = kLengthOffset + kPointerSize;
static const int kSizeWithEmbedderFields =
diff --git a/chromium/v8/src/objects/dictionary.h b/chromium/v8/src/objects/dictionary.h
index 0297a7f28b3..11cf8b11639 100644
--- a/chromium/v8/src/objects/dictionary.h
+++ b/chromium/v8/src/objects/dictionary.h
@@ -138,14 +138,16 @@ class BaseNameDictionary : public Dictionary<Derived, Shape> {
return Smi::ToInt(this->get(kNextEnumerationIndexIndex));
}
- void SetHash(int masked_hash) {
- DCHECK_EQ(masked_hash & JSReceiver::kHashMask, masked_hash);
- this->set(kObjectHashIndex, Smi::FromInt(masked_hash));
+ void SetHash(int hash) {
+ DCHECK(PropertyArray::HashField::is_valid(hash));
+ this->set(kObjectHashIndex, Smi::FromInt(hash));
}
int Hash() const {
Object* hash_obj = this->get(kObjectHashIndex);
- return Smi::ToInt(hash_obj);
+ int hash = Smi::ToInt(hash_obj);
+ DCHECK(PropertyArray::HashField::is_valid(hash));
+ return hash;
}
// Creates a new dictionary.
diff --git a/chromium/v8/src/objects/map-inl.h b/chromium/v8/src/objects/map-inl.h
index aab6e786689..a5421a32cad 100644
--- a/chromium/v8/src/objects/map-inl.h
+++ b/chromium/v8/src/objects/map-inl.h
@@ -42,6 +42,39 @@ bool Map::IsInplaceGeneralizableField(PropertyConstness constness,
return false;
}
+bool Map::CanHaveFastTransitionableElementsKind(InstanceType instance_type) {
+ return instance_type == JS_ARRAY_TYPE || instance_type == JS_VALUE_TYPE ||
+ instance_type == JS_ARGUMENTS_TYPE;
+}
+
+bool Map::CanHaveFastTransitionableElementsKind() const {
+ return CanHaveFastTransitionableElementsKind(instance_type());
+}
+
+// static
+void Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
+ Isolate* isolate, InstanceType instance_type, PropertyConstness* constness,
+ Representation* representation, Handle<FieldType>* field_type) {
+ if (CanHaveFastTransitionableElementsKind(instance_type)) {
+ // We don't support propagation of field generalization through elements
+ // kind transitions because they are inserted into the transition tree
+ // before field transitions. In order to avoid complexity of handling
+ // such a case we ensure that all maps with transitionable elements kinds
+ // do not have fields that can be generalized in-place (without creation
+ // of a new map).
+ if (FLAG_track_constant_fields && FLAG_modify_map_inplace) {
+ // The constness is either already kMutable or should become kMutable if
+ // it was kConst.
+ *constness = kMutable;
+ }
+ if (representation->IsHeapObject()) {
+ // The field type is either already Any or should become Any if it was
+ // something else.
+ *field_type = FieldType::Any(isolate);
+ }
+ }
+}
+
int NormalizedMapCache::GetIndex(Handle<Map> map) {
return map->Hash() % NormalizedMapCache::kEntries;
}
diff --git a/chromium/v8/src/objects/map.h b/chromium/v8/src/objects/map.h
index 2bbf7ac1ce9..5806a24ae0f 100644
--- a/chromium/v8/src/objects/map.h
+++ b/chromium/v8/src/objects/map.h
@@ -406,6 +406,8 @@ class Map : public HeapObject {
int NumberOfFields() const;
+ bool HasOutOfObjectProperties() const;
+
// Returns true if transition to the given map requires special
// synchronization with the concurrent marker.
bool TransitionRequiresSynchronizationWithGC(Map* target) const;
@@ -436,6 +438,18 @@ class Map : public HeapObject {
Representation representation,
FieldType* field_type);
+ // Generalizes constness, representation and field_type if objects with given
+ // instance type can have fast elements that can be transitioned by stubs or
+ // optimized code to more general elements kind.
+ // This generalization is necessary in order to ensure that elements kind
+ // transitions performed by stubs / optimized code don't silently transition
+ // kMutable fields back to kConst state or fields with HeapObject
+ // representation and "Any" type back to "Class" type.
+ static inline void GeneralizeIfCanHaveTransitionableFastElementsKind(
+ Isolate* isolate, InstanceType instance_type,
+ PropertyConstness* constness, Representation* representation,
+ Handle<FieldType>* field_type);
+
static Handle<Map> ReconfigureProperty(Handle<Map> map, int modify_index,
PropertyKind new_kind,
PropertyAttributes new_attributes,
@@ -823,6 +837,16 @@ class Map : public HeapObject {
static VisitorId GetVisitorId(Map* map);
+ // Returns true if objects with given instance type are allowed to have
+ // fast transitionable elements kinds. This predicate is used to ensure
+ // that objects that can have transitionable fast elements kind will not
+ // get in-place generalizable fields because the elements kind transition
+ // performed by stubs or optimized code can't properly generalize such
+ // fields.
+ static inline bool CanHaveFastTransitionableElementsKind(
+ InstanceType instance_type);
+ inline bool CanHaveFastTransitionableElementsKind() const;
+
private:
// Returns the map that this (root) map transitions to if its elements_kind
// is changed to |elements_kind|, or |nullptr| if no such map is cached yet.
diff --git a/chromium/v8/src/parsing/parser.cc b/chromium/v8/src/parsing/parser.cc
index 7eebfbdafce..a554d7d2423 100644
--- a/chromium/v8/src/parsing/parser.cc
+++ b/chromium/v8/src/parsing/parser.cc
@@ -2790,7 +2790,7 @@ Parser::LazyParsingResult Parser::SkipFunction(
DCHECK(log_);
log_->LogFunction(function_scope->start_position(),
function_scope->end_position(), *num_parameters,
- language_mode(), function_scope->uses_super_property(),
+ language_mode(), function_scope->NeedsHomeObject(),
logger->num_inner_functions());
}
return kLazyParsingComplete;
@@ -3383,8 +3383,9 @@ void Parser::ParseOnBackground(ParseInfo* info) {
if (result != NULL) *info->cached_data() = logger.GetScriptData();
log_ = NULL;
}
- if (FLAG_runtime_stats &
- v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
+ if (runtime_call_stats_ &&
+ (FLAG_runtime_stats &
+ v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
auto value = v8::tracing::TracedValue::Create();
runtime_call_stats_->Dump(value.get());
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats"),
diff --git a/chromium/v8/src/parsing/preparsed-scope-data.cc b/chromium/v8/src/parsing/preparsed-scope-data.cc
index f73a61bfb6b..8d2ce2d1a55 100644
--- a/chromium/v8/src/parsing/preparsed-scope-data.cc
+++ b/chromium/v8/src/parsing/preparsed-scope-data.cc
@@ -101,16 +101,16 @@ void ProducedPreParsedScopeData::ByteData::WriteUint32(uint32_t data) {
}
void ProducedPreParsedScopeData::ByteData::OverwriteFirstUint32(uint32_t data) {
- size_t position = 0;
+ auto it = backing_store_.begin();
#ifdef DEBUG
// Check that that position already holds an item of the expected size.
DCHECK_GE(backing_store_.size(), kUint32Size);
- DCHECK_EQ(backing_store_[0], kUint32Size);
- ++position;
+ DCHECK_EQ(*it, kUint32Size);
+ ++it;
#endif
const uint8_t* d = reinterpret_cast<uint8_t*>(&data);
for (size_t i = 0; i < 4; ++i) {
- backing_store_[position + i] = *d++;
+ *it++ = *d++;
}
}
@@ -123,7 +123,7 @@ void ProducedPreParsedScopeData::ByteData::WriteUint8(uint8_t data) {
}
Handle<PodArray<uint8_t>> ProducedPreParsedScopeData::ByteData::Serialize(
- Isolate* isolate) const {
+ Isolate* isolate) {
Handle<PodArray<uint8_t>> array = PodArray<uint8_t>::New(
isolate, static_cast<int>(backing_store_.size()), TENURED);
@@ -193,7 +193,7 @@ void ProducedPreParsedScopeData::DataGatheringScope::MarkFunctionAsSkippable(
produced_preparsed_scope_data_->parent_->AddSkippableFunction(
function_scope_->start_position(), end_position,
function_scope_->num_parameters(), num_inner_functions,
- function_scope_->language_mode(), function_scope_->uses_super_property());
+ function_scope_->language_mode(), function_scope_->NeedsHomeObject());
}
void ProducedPreParsedScopeData::AddSkippableFunction(
@@ -251,7 +251,7 @@ void ProducedPreParsedScopeData::SaveScopeAllocationData(
}
MaybeHandle<PreParsedScopeData> ProducedPreParsedScopeData::Serialize(
- Isolate* isolate) const {
+ Isolate* isolate) {
if (!previously_produced_preparsed_scope_data_.is_null()) {
DCHECK(!bailed_out_);
DCHECK_EQ(data_for_inner_functions_.size(), 0);
@@ -336,12 +336,6 @@ bool ProducedPreParsedScopeData::ScopeIsSkippableFunctionScope(Scope* scope) {
void ProducedPreParsedScopeData::SaveDataForScope(Scope* scope) {
DCHECK_NE(scope->end_position(), kNoSourcePosition);
- // We're not trying to save data for default constructors because the
- // PreParser doesn't construct them.
- DCHECK_IMPLIES(scope->scope_type() == ScopeType::FUNCTION_SCOPE,
- (scope->AsDeclarationScope()->function_kind() &
- kDefaultConstructor) == 0);
-
if (!ScopeNeedsData(scope)) {
return;
}
diff --git a/chromium/v8/src/parsing/preparsed-scope-data.h b/chromium/v8/src/parsing/preparsed-scope-data.h
index 205de42207a..290bfba2fd4 100644
--- a/chromium/v8/src/parsing/preparsed-scope-data.h
+++ b/chromium/v8/src/parsing/preparsed-scope-data.h
@@ -13,7 +13,7 @@
#include "src/handles.h"
#include "src/objects/shared-function-info.h"
#include "src/parsing/preparse-data.h"
-#include "src/zone/zone-containers.h"
+#include "src/zone/zone-chunk-list.h"
namespace v8 {
namespace internal {
@@ -77,12 +77,12 @@ class ProducedPreParsedScopeData : public ZoneObject {
// For overwriting previously written data at position 0.
void OverwriteFirstUint32(uint32_t data);
- Handle<PodArray<uint8_t>> Serialize(Isolate* isolate) const;
+ Handle<PodArray<uint8_t>> Serialize(Isolate* isolate);
size_t size() const { return backing_store_.size(); }
private:
- ZoneDeque<uint8_t> backing_store_;
+ ZoneChunkList<uint8_t> backing_store_;
};
// Create a ProducedPreParsedScopeData object which will collect data as we
@@ -145,7 +145,7 @@ class ProducedPreParsedScopeData : public ZoneObject {
// If there is data (if the Scope contains skippable inner functions), move
// the data into the heap and return a Handle to it; otherwise return a null
// MaybeHandle.
- MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) const;
+ MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate);
static bool ScopeNeedsData(Scope* scope);
static bool ScopeIsSkippableFunctionScope(Scope* scope);
@@ -163,7 +163,7 @@ class ProducedPreParsedScopeData : public ZoneObject {
ProducedPreParsedScopeData* parent_;
ByteData* byte_data_;
- ZoneDeque<ProducedPreParsedScopeData*> data_for_inner_functions_;
+ ZoneChunkList<ProducedPreParsedScopeData*> data_for_inner_functions_;
// Whether we've given up producing the data for this function.
bool bailed_out_;
diff --git a/chromium/v8/src/parsing/preparser.cc b/chromium/v8/src/parsing/preparser.cc
index 289059bc7f3..c31fd4af8e9 100644
--- a/chromium/v8/src/parsing/preparser.cc
+++ b/chromium/v8/src/parsing/preparser.cc
@@ -206,7 +206,8 @@ PreParser::PreParseResult PreParser::PreParseFunction(
}
}
- if (!IsArrowFunction(kind) && track_unresolved_variables_) {
+ if (!IsArrowFunction(kind) && track_unresolved_variables_ &&
+ result == kLazyParsingComplete) {
CreateFunctionNameAssignment(function_name, function_type, function_scope);
// Declare arguments after parsing the function since lexical 'arguments'
diff --git a/chromium/v8/src/parsing/preparser.h b/chromium/v8/src/parsing/preparser.h
index 0403bcdec61..275c5e9e0bd 100644
--- a/chromium/v8/src/parsing/preparser.h
+++ b/chromium/v8/src/parsing/preparser.h
@@ -1124,7 +1124,22 @@ class PreParser : public ParserBase<PreParser> {
ClassInfo* class_info, int pos, int end_pos, bool* ok) {
bool has_default_constructor = !class_info->has_seen_constructor;
// Account for the default constructor.
- if (has_default_constructor) GetNextFunctionLiteralId();
+ if (has_default_constructor) {
+ // Creating and disposing of a FunctionState makes tracking of
+ // next_function_is_likely_called match what Parser does. TODO(marja):
+ // Make the lazy function + next_function_is_likely_called + default ctor
+ // logic less surprising. Default ctors shouldn't affect the laziness of
+ // functions.
+ bool has_extends = class_info->extends.IsNull();
+ FunctionKind kind = has_extends ? FunctionKind::kDefaultDerivedConstructor
+ : FunctionKind::kDefaultBaseConstructor;
+ DeclarationScope* function_scope = NewFunctionScope(kind);
+ SetLanguageMode(function_scope, STRICT);
+ function_scope->set_start_position(pos);
+ function_scope->set_end_position(pos);
+ FunctionState function_state(&function_state_, &scope_, function_scope);
+ GetNextFunctionLiteralId();
+ }
return PreParserExpression::Default();
}
diff --git a/chromium/v8/src/ppc/simulator-ppc.cc b/chromium/v8/src/ppc/simulator-ppc.cc
index ef6e64a9f36..0f90700c81c 100644
--- a/chromium/v8/src/ppc/simulator-ppc.cc
+++ b/chromium/v8/src/ppc/simulator-ppc.cc
@@ -1334,7 +1334,6 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
int arg0_regnum = 3;
intptr_t result_buffer = 0;
bool uses_result_buffer =
- redirection->type() == ExternalReference::BUILTIN_CALL_TRIPLE ||
(redirection->type() == ExternalReference::BUILTIN_CALL_PAIR &&
!ABI_RETURNS_OBJECT_PAIRS_IN_REGS);
if (uses_result_buffer) {
diff --git a/chromium/v8/src/regexp/jsregexp.cc b/chromium/v8/src/regexp/jsregexp.cc
index 399c6153c5a..52ed47cf533 100644
--- a/chromium/v8/src/regexp/jsregexp.cc
+++ b/chromium/v8/src/regexp/jsregexp.cc
@@ -5905,7 +5905,7 @@ Vector<const int> CharacterRange::GetWordBounds() {
return Vector<const int>(kWordRanges, kWordRangeCount - 1);
}
-
+// static
void CharacterRange::AddCaseEquivalents(Isolate* isolate, Zone* zone,
ZoneList<CharacterRange>* ranges,
bool is_one_byte) {
@@ -5914,12 +5914,12 @@ void CharacterRange::AddCaseEquivalents(Isolate* isolate, Zone* zone,
for (int i = 0; i < range_count; i++) {
CharacterRange range = ranges->at(i);
uc32 bottom = range.from();
- if (bottom > String::kMaxUtf16CodeUnit) return;
+ if (bottom > String::kMaxUtf16CodeUnit) continue;
uc32 top = Min(range.to(), String::kMaxUtf16CodeUnit);
// Nothing to be done for surrogates.
- if (bottom >= kLeadSurrogateStart && top <= kTrailSurrogateEnd) return;
+ if (bottom >= kLeadSurrogateStart && top <= kTrailSurrogateEnd) continue;
if (is_one_byte && !RangeContainsLatin1Equivalents(range)) {
- if (bottom > String::kMaxOneByteCharCode) return;
+ if (bottom > String::kMaxOneByteCharCode) continue;
if (top > String::kMaxOneByteCharCode) top = String::kMaxOneByteCharCode;
}
unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
diff --git a/chromium/v8/src/runtime/runtime-intl.cc b/chromium/v8/src/runtime/runtime-intl.cc
index 22acba28cd1..783450c8ef1 100644
--- a/chromium/v8/src/runtime/runtime-intl.cc
+++ b/chromium/v8/src/runtime/runtime-intl.cc
@@ -68,18 +68,21 @@ RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
v8::String::Utf8Value locale_id(v8_isolate,
v8::Utils::ToLocal(locale_id_str));
+ // TODO(jshin): uloc_{for,to}TanguageTag can fail even for a structually valid
+ // language tag if it's too long (much longer than 100 chars). Even if we
+ // allocate a longer buffer, ICU will still fail if it's too long. Either
+ // propose to Ecma 402 to put a limit on the locale length or change ICU to
+ // handle long locale names better. See
+ // https://ssl.icu-project.org/trac/ticket/13417 .
+
// Return value which denotes invalid language tag.
- // TODO(jshin): Can uloc_{for,to}TanguageTag fail even for structually valid
- // language tags? If not, just add CHECK instead of returning 'invalid-tag'.
const char* const kInvalidTag = "invalid-tag";
UErrorCode error = U_ZERO_ERROR;
char icu_result[ULOC_FULLNAME_CAPACITY];
- int icu_length = 0;
-
- uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
- &icu_length, &error);
- if (U_FAILURE(error) || icu_length == 0) {
+ uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, nullptr,
+ &error);
+ if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
return *factory->NewStringFromAsciiChecked(kInvalidTag);
}
@@ -88,7 +91,7 @@ RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
// Force strict BCP47 rules.
uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
- if (U_FAILURE(error)) {
+ if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
return *factory->NewStringFromAsciiChecked(kInvalidTag);
}
@@ -134,7 +137,7 @@ RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) {
error = U_ZERO_ERROR;
// No need to force strict BCP47 rules.
uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
- if (U_FAILURE(error)) {
+ if (U_FAILURE(error) || error == U_STRING_NOT_TERMINATED_WARNING) {
// This shouldn't happen, but lets not break the user.
continue;
}
@@ -173,91 +176,6 @@ RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) {
return *factory->NewStringFromStaticChars("und");
}
-RUNTIME_FUNCTION(Runtime_GetLanguageTagVariants) {
- HandleScope scope(isolate);
- v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
- Factory* factory = isolate->factory();
-
- DCHECK_EQ(1, args.length());
-
- CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
-
- uint32_t length = static_cast<uint32_t>(input->length()->Number());
- // Set some limit to prevent fuzz tests from going OOM.
- // Can be bumped when callers' requirements change.
- if (length >= 100) return isolate->ThrowIllegalOperation();
- Handle<FixedArray> output = factory->NewFixedArray(length);
- Handle<Name> maximized = factory->NewStringFromStaticChars("maximized");
- Handle<Name> base = factory->NewStringFromStaticChars("base");
- for (unsigned int i = 0; i < length; ++i) {
- Handle<Object> locale_id;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, locale_id, JSReceiver::GetElement(isolate, input, i));
- if (!locale_id->IsString()) {
- return isolate->Throw(*factory->illegal_argument_string());
- }
-
- v8::String::Utf8Value utf8_locale_id(
- v8_isolate, v8::Utils::ToLocal(Handle<String>::cast(locale_id)));
-
- UErrorCode error = U_ZERO_ERROR;
-
- // Convert from BCP47 to ICU format.
- // de-DE-u-co-phonebk -> de_DE@collation=phonebook
- char icu_locale[ULOC_FULLNAME_CAPACITY];
- int icu_locale_length = 0;
- uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
- &icu_locale_length, &error);
- if (U_FAILURE(error) || icu_locale_length == 0) {
- return isolate->Throw(*factory->illegal_argument_string());
- }
-
- // Maximize the locale.
- // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
- char icu_max_locale[ULOC_FULLNAME_CAPACITY];
- uloc_addLikelySubtags(icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY,
- &error);
-
- // Remove extensions from maximized locale.
- // de_Latn_DE@collation=phonebook -> de_Latn_DE
- char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
- uloc_getBaseName(icu_max_locale, icu_base_max_locale,
- ULOC_FULLNAME_CAPACITY, &error);
-
- // Get original name without extensions.
- // de_DE@collation=phonebook -> de_DE
- char icu_base_locale[ULOC_FULLNAME_CAPACITY];
- uloc_getBaseName(icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY,
- &error);
-
- // Convert from ICU locale format to BCP47 format.
- // de_Latn_DE -> de-Latn-DE
- char base_max_locale[ULOC_FULLNAME_CAPACITY];
- uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
- ULOC_FULLNAME_CAPACITY, FALSE, &error);
-
- // de_DE -> de-DE
- char base_locale[ULOC_FULLNAME_CAPACITY];
- uloc_toLanguageTag(icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY,
- FALSE, &error);
-
- if (U_FAILURE(error)) {
- return isolate->Throw(*factory->illegal_argument_string());
- }
-
- Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
- Handle<String> value = factory->NewStringFromAsciiChecked(base_max_locale);
- JSObject::AddProperty(result, maximized, value, NONE);
- value = factory->NewStringFromAsciiChecked(base_locale);
- JSObject::AddProperty(result, base, value, NONE);
- output->set(i, *result);
- }
-
- Handle<JSArray> result = factory->NewJSArrayWithElements(output);
- result->set_length(Smi::FromInt(length));
- return *result;
-}
-
RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) {
HandleScope scope(isolate);
diff --git a/chromium/v8/src/runtime/runtime-object.cc b/chromium/v8/src/runtime/runtime-object.cc
index 711a55e2ff7..4c8805eb254 100644
--- a/chromium/v8/src/runtime/runtime-object.cc
+++ b/chromium/v8/src/runtime/runtime-object.cc
@@ -163,16 +163,23 @@ bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
if (details.location() == kField) {
isolate->heap()->NotifyObjectLayoutChange(*receiver, map->instance_size(),
no_allocation);
- Object* filler = isolate->heap()->one_pointer_filler_map();
FieldIndex index = FieldIndex::ForPropertyIndex(map, details.field_index());
- JSObject::cast(*receiver)->RawFastPropertyAtPut(index, filler);
- // We must clear any recorded slot for the deleted property, because
- // subsequent object modifications might put a raw double there.
- // Slot clearing is the reason why this entire function cannot currently
- // be implemented in the DeleteProperty stub.
- if (index.is_inobject() && !map->IsUnboxedDoubleField(index)) {
- isolate->heap()->ClearRecordedSlot(
- *receiver, HeapObject::RawField(*receiver, index.offset()));
+ // Special case deleting the last out-of object property.
+ if (!index.is_inobject() && index.outobject_array_index() == 0) {
+ DCHECK(!Map::cast(backpointer)->HasOutOfObjectProperties());
+ // Clear out the properties backing store.
+ receiver->SetProperties(isolate->heap()->empty_fixed_array());
+ } else {
+ Object* filler = isolate->heap()->one_pointer_filler_map();
+ JSObject::cast(*receiver)->RawFastPropertyAtPut(index, filler);
+ // We must clear any recorded slot for the deleted property, because
+ // subsequent object modifications might put a raw double there.
+ // Slot clearing is the reason why this entire function cannot currently
+ // be implemented in the DeleteProperty stub.
+ if (index.is_inobject() && !map->IsUnboxedDoubleField(index)) {
+ isolate->heap()->ClearRecordedSlot(
+ *receiver, HeapObject::RawField(*receiver, index.offset()));
+ }
}
}
// If the map was marked stable before, then there could be optimized code
@@ -182,6 +189,10 @@ bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
map->NotifyLeafMapLayoutChange();
// Finally, perform the map rollback.
receiver->synchronized_set_map(Map::cast(backpointer));
+#if VERIFY_HEAP
+ receiver->HeapObjectVerify();
+ receiver->property_array()->PropertyArrayVerify();
+#endif
return true;
}
diff --git a/chromium/v8/src/runtime/runtime-proxy.cc b/chromium/v8/src/runtime/runtime-proxy.cc
index 028f3e2046c..472cbdf79d6 100644
--- a/chromium/v8/src/runtime/runtime-proxy.cc
+++ b/chromium/v8/src/runtime/runtime-proxy.cc
@@ -51,11 +51,11 @@ RUNTIME_FUNCTION(Runtime_GetPropertyWithReceiver) {
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, holder, 0);
- CONVERT_ARG_HANDLE_CHECKED(Object, name, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 2);
- bool success;
- LookupIterator it = LookupIterator::PropertyOrElement(isolate, receiver, name,
+ bool success = false;
+ LookupIterator it = LookupIterator::PropertyOrElement(isolate, receiver, key,
&success, holder);
if (!success) {
DCHECK(isolate->has_pending_exception());
@@ -69,15 +69,18 @@ RUNTIME_FUNCTION(Runtime_SetPropertyWithReceiver) {
DCHECK_EQ(5, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, holder, 0);
- CONVERT_ARG_HANDLE_CHECKED(Object, name, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 3);
CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 4);
- bool success;
- LookupIterator it = LookupIterator::PropertyOrElement(isolate, receiver, name,
+ bool success = false;
+ LookupIterator it = LookupIterator::PropertyOrElement(isolate, receiver, key,
&success, holder);
-
+ if (!success) {
+ DCHECK(isolate->has_pending_exception());
+ return isolate->heap()->exception();
+ }
Maybe<bool> result = Object::SetSuperProperty(
&it, value, language_mode, Object::MAY_BE_STORE_FROM_KEYED);
MAYBE_RETURN(result, isolate->heap()->exception());
diff --git a/chromium/v8/src/runtime/runtime-test.cc b/chromium/v8/src/runtime/runtime-test.cc
index 587c1dc251e..19a4af50d1c 100644
--- a/chromium/v8/src/runtime/runtime-test.cc
+++ b/chromium/v8/src/runtime/runtime-test.cc
@@ -892,6 +892,7 @@ RUNTIME_FUNCTION(Runtime_GetWasmRecoveredTrapCount) {
return isolate->heap()->ToBoolean(obj->Has##Name()); \
}
+ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SmiElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ObjectElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SmiOrObjectElements)
@@ -1070,5 +1071,16 @@ RUNTIME_FUNCTION(Runtime_WasmTraceMemory) {
return isolate->heap()->undefined_value();
}
+RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTracking) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(1, args.length());
+
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+ object->map()->CompleteInobjectSlackTracking();
+
+ return isolate->heap()->undefined_value();
+}
+
+
} // namespace internal
} // namespace v8
diff --git a/chromium/v8/src/runtime/runtime-typedarray.cc b/chromium/v8/src/runtime/runtime-typedarray.cc
index 58a2bbdcfc8..8dfa8f166c2 100644
--- a/chromium/v8/src/runtime/runtime-typedarray.cc
+++ b/chromium/v8/src/runtime/runtime-typedarray.cc
@@ -214,5 +214,148 @@ RUNTIME_FUNCTION(Runtime_TypedArraySpeciesCreateByLength) {
return *result_array;
}
+namespace {
+
+Object* TypedArraySetFromOverlapping(Isolate* isolate,
+ Handle<JSTypedArray> target,
+ Handle<JSTypedArray> source,
+ uint32_t offset) {
+#ifdef DEBUG
+ Handle<FixedTypedArrayBase> source_elements(
+ FixedTypedArrayBase::cast(source->elements()));
+ Handle<FixedTypedArrayBase> target_elements(
+ FixedTypedArrayBase::cast(target->elements()));
+ uint8_t* source_data = static_cast<uint8_t*>(source_elements->DataPtr());
+ uint8_t* target_data = static_cast<uint8_t*>(target_elements->DataPtr());
+ size_t source_byte_length = NumberToSize(source->byte_length());
+ size_t target_byte_length = NumberToSize(target->byte_length());
+
+ CHECK_LE(offset + source->length(), target->length());
+ CHECK_GE(target->length(), source->length());
+ CHECK(source->length()->IsSmi());
+
+ CHECK(!target->WasNeutered());
+ CHECK(!source->WasNeutered());
+
+ // Assert that target and source in fact overlapping.
+ CHECK(target_data + target_byte_length > source_data &&
+ source_data + source_byte_length > target_data);
+#endif
+
+ size_t sourceElementSize = source->element_size();
+ size_t targetElementSize = target->element_size();
+
+ uint32_t source_length = source->length_value();
+ if (source_length == 0) return isolate->heap()->undefined_value();
+
+ // Copy left part.
+
+ // First un-mutated byte after the next write
+ uint32_t target_ptr = 0;
+ CHECK(target->byte_offset()->ToUint32(&target_ptr));
+ target_ptr += (offset + 1) * targetElementSize;
+
+ // Next read at sourcePtr. We do not care for memory changing before
+ // sourcePtr - we have already copied it.
+ uint32_t source_ptr = 0;
+ CHECK(source->byte_offset()->ToUint32(&source_ptr));
+
+ ElementsAccessor* source_accessor = source->GetElementsAccessor();
+ ElementsAccessor* target_accessor = target->GetElementsAccessor();
+
+ uint32_t left_index;
+ for (left_index = 0; left_index < source_length && target_ptr <= source_ptr;
+ left_index++) {
+ Handle<Object> value = source_accessor->Get(source, left_index);
+ target_accessor->Set(target, offset + left_index, *value);
+
+ target_ptr += targetElementSize;
+ source_ptr += sourceElementSize;
+ }
+
+ // Copy right part;
+ // First unmutated byte before the next write
+ CHECK(target->byte_offset()->ToUint32(&target_ptr));
+ target_ptr += (offset + source_length - 1) * targetElementSize;
+
+ // Next read before sourcePtr. We do not care for memory changing after
+ // sourcePtr - we have already copied it.
+ CHECK(target->byte_offset()->ToUint32(&source_ptr));
+ source_ptr += source_length * sourceElementSize;
+
+ uint32_t right_index;
+ DCHECK_GE(source_length, 1);
+ for (right_index = source_length - 1;
+ right_index > left_index && target_ptr >= source_ptr; right_index--) {
+ Handle<Object> value = source_accessor->Get(source, right_index);
+ target_accessor->Set(target, offset + right_index, *value);
+
+ target_ptr -= targetElementSize;
+ source_ptr -= sourceElementSize;
+ }
+
+ std::vector<Handle<Object>> temp(right_index + 1 - left_index);
+
+ for (uint32_t i = left_index; i <= right_index; i++) {
+ temp[i - left_index] = source_accessor->Get(source, i);
+ }
+
+ for (uint32_t i = left_index; i <= right_index; i++) {
+ target_accessor->Set(target, offset + i, *temp[i - left_index]);
+ }
+
+ return isolate->heap()->undefined_value();
+}
+
+} // namespace
+
+// 22.2.3.23 %TypedArray%.prototype.set ( overloaded [ , offset ] )
+RUNTIME_FUNCTION(Runtime_TypedArraySet) {
+ HandleScope scope(isolate);
+ Handle<JSTypedArray> target = args.at<JSTypedArray>(0);
+ Handle<Object> obj = args.at(1);
+ Handle<Smi> offset = args.at<Smi>(2);
+
+ DCHECK(!target->WasNeutered()); // Checked in TypedArrayPrototypeSet.
+ DCHECK_LE(0, offset->value());
+
+ const uint32_t uint_offset = static_cast<uint32_t>(offset->value());
+
+ if (obj->IsNumber()) {
+ // For number as a first argument, throw TypeError
+ // instead of silently ignoring the call, so that
+ // users know they did something wrong.
+ // (Consistent with Firefox and Blink/WebKit)
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewTypeError(MessageTemplate::kInvalidArgument));
+ } else if (obj->IsJSTypedArray()) {
+ // The non-overlapping case is handled in CSA.
+ Handle<JSTypedArray> source = Handle<JSTypedArray>::cast(obj);
+ return TypedArraySetFromOverlapping(isolate, target, source, uint_offset);
+ }
+
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, obj,
+ Object::ToObject(isolate, obj));
+
+ Handle<Object> len;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, len,
+ Object::GetProperty(obj, isolate->factory()->length_string()));
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len,
+ Object::ToLength(isolate, len));
+
+ if (uint_offset + len->Number() > target->length_value()) {
+ THROW_NEW_ERROR_RETURN_FAILURE(
+ isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
+ }
+
+ uint32_t int_l;
+ CHECK(DoubleToUint32IfEqualToSelf(len->Number(), &int_l));
+
+ Handle<JSReceiver> source = Handle<JSReceiver>::cast(obj);
+ ElementsAccessor* accessor = target->GetElementsAccessor();
+ return accessor->CopyElements(source, target, int_l, uint_offset);
+}
+
} // namespace internal
} // namespace v8
diff --git a/chromium/v8/src/runtime/runtime.h b/chromium/v8/src/runtime/runtime.h
index a84efc10328..e7084a8ccaa 100644
--- a/chromium/v8/src/runtime/runtime.h
+++ b/chromium/v8/src/runtime/runtime.h
@@ -252,7 +252,6 @@ namespace internal {
F(CanonicalizeLanguageTag, 1, 1) \
F(AvailableLocalesOf, 1, 1) \
F(GetDefaultICULocale, 0, 1) \
- F(GetLanguageTagVariants, 1, 1) \
F(IsInitializedIntlObject, 1, 1) \
F(IsInitializedIntlObjectOfType, 2, 1) \
F(MarkAsInitializedIntlObjectOfType, 2, 1) \
@@ -588,6 +587,7 @@ namespace internal {
F(TraceExit, 1, 1) \
F(HaveSameMap, 2, 1) \
F(InNewSpace, 1, 1) \
+ F(HasFastElements, 1, 1) \
F(HasSmiElements, 1, 1) \
F(HasObjectElements, 1, 1) \
F(HasSmiOrObjectElements, 1, 1) \
@@ -622,7 +622,8 @@ namespace internal {
F(HeapObjectVerify, 1, 1) \
F(WasmNumInterpretedCalls, 1, 1) \
F(RedirectToWasmInterpreter, 2, 1) \
- F(WasmTraceMemory, 4, 1)
+ F(WasmTraceMemory, 4, 1) \
+ F(CompleteInobjectSlackTracking, 1, 1)
#define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
F(ArrayBufferGetByteLength, 1, 1) \
@@ -634,6 +635,7 @@ namespace internal {
F(TypedArrayGetLength, 1, 1) \
F(TypedArrayGetBuffer, 1, 1) \
F(TypedArraySortFast, 1, 1) \
+ F(TypedArraySet, 2, 1) \
F(IsTypedArray, 1, 1) \
F(IsSharedTypedArray, 1, 1) \
F(IsSharedIntegerTypedArray, 1, 1) \
diff --git a/chromium/v8/src/v8.gyp b/chromium/v8/src/v8.gyp
index b4f1dfefd3a..89eb271f618 100644
--- a/chromium/v8/src/v8.gyp
+++ b/chromium/v8/src/v8.gyp
@@ -42,7 +42,7 @@
{
'target_name': 'v8',
'dependencies_traverse': 1,
- 'dependencies': ['v8_maybe_snapshot'],
+ 'dependencies': ['v8_maybe_snapshot', 'v8_dump_build_config#target'],
'conditions': [
['want_separate_host_toolset==1', {
'toolsets': ['host', 'target'],
@@ -2510,5 +2510,42 @@
}],
],
},
+ {
+ 'target_name': 'v8_dump_build_config',
+ 'type': 'none',
+ 'variables': {
+ },
+ 'actions': [
+ {
+ 'action_name': 'v8_dump_build_config',
+ 'inputs': [
+ '../tools/testrunner/utils/dump_build_config_gyp.py',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/v8_build_config.json',
+ ],
+ 'action': [
+ 'python',
+ '../tools/testrunner/utils/dump_build_config_gyp.py',
+ '<(PRODUCT_DIR)/v8_build_config.json',
+ 'dcheck_always_on=<(dcheck_always_on)',
+ 'is_asan=<(asan)',
+ 'is_cfi=<(cfi_vptr)',
+ 'is_component_build=<(component)',
+ 'is_debug=<(CONFIGURATION_NAME)',
+ # Not available in gyp.
+ 'is_gcov_coverage=0',
+ 'is_msan=<(msan)',
+ 'is_tsan=<(tsan)',
+ # Not available in gyp.
+ 'is_ubsan_vptr=0',
+ 'target_cpu=<(target_arch)',
+ 'v8_enable_i18n_support=<(v8_enable_i18n_support)',
+ 'v8_target_cpu=<(v8_target_arch)',
+ 'v8_use_snapshot=<(v8_use_snapshot)',
+ ],
+ },
+ ],
+ },
],
}
diff --git a/chromium/v8/src/wasm/module-compiler.cc b/chromium/v8/src/wasm/module-compiler.cc
index bc4945b923e..e42c139ce1c 100644
--- a/chromium/v8/src/wasm/module-compiler.cc
+++ b/chromium/v8/src/wasm/module-compiler.cc
@@ -1798,7 +1798,6 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
// Set externally passed ArrayBuffer non neuterable.
memory->set_is_neuterable(false);
- memory->set_is_wasm_buffer(true);
DCHECK_IMPLIES(trap_handler::UseTrapHandler(),
module_->is_asm_js() || memory->has_guard_region());
diff --git a/chromium/v8/src/wasm/wasm-js.cc b/chromium/v8/src/wasm/wasm-js.cc
index 5e624d48f1f..6a017365aad 100644
--- a/chromium/v8/src/wasm/wasm-js.cc
+++ b/chromium/v8/src/wasm/wasm-js.cc
@@ -752,6 +752,10 @@ void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
max_size64 = i::FLAG_wasm_max_mem_pages;
}
i::Handle<i::JSArrayBuffer> old_buffer(receiver->array_buffer());
+ if (!old_buffer->is_growable()) {
+ thrower.RangeError("This memory cannot be grown");
+ return;
+ }
uint32_t old_size =
old_buffer->byte_length()->Number() / i::wasm::kSpecMaxWasmMemoryPages;
int64_t new_size64 = old_size + delta_size;
diff --git a/chromium/v8/src/wasm/wasm-memory.cc b/chromium/v8/src/wasm/wasm-memory.cc
index 2b5ae0052d9..4ddda981895 100644
--- a/chromium/v8/src/wasm/wasm-memory.cc
+++ b/chromium/v8/src/wasm/wasm-memory.cc
@@ -67,7 +67,7 @@ Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* allocation_base,
allocation_length, backing_store, static_cast<int>(size),
shared);
buffer->set_is_neuterable(false);
- buffer->set_is_wasm_buffer(true);
+ buffer->set_is_growable(true);
buffer->set_has_guard_region(enable_guard_regions);
return buffer;
}
diff --git a/chromium/v8/src/wasm/wasm-objects.cc b/chromium/v8/src/wasm/wasm-objects.cc
index 8d47293a630..012aa6644bb 100644
--- a/chromium/v8/src/wasm/wasm-objects.cc
+++ b/chromium/v8/src/wasm/wasm-objects.cc
@@ -315,6 +315,7 @@ namespace {
Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
Handle<JSArrayBuffer> old_buffer,
uint32_t pages, uint32_t maximum_pages) {
+ if (!old_buffer->is_growable()) return Handle<JSArrayBuffer>::null();
Address old_mem_start = nullptr;
uint32_t old_size = 0;
if (!old_buffer.is_null()) {
@@ -459,6 +460,7 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate,
Handle<WasmMemoryObject> memory_object,
uint32_t pages) {
Handle<JSArrayBuffer> old_buffer(memory_object->array_buffer());
+ if (!old_buffer->is_growable()) return -1;
uint32_t old_size = 0;
CHECK(old_buffer->byte_length()->ToUint32(&old_size));
Handle<JSArrayBuffer> new_buffer;
diff --git a/chromium/v8/tools/foozzie/v8_foozzie.py b/chromium/v8/tools/foozzie/v8_foozzie.py
index 0c6d65d1e89..21781786526 100755
--- a/chromium/v8/tools/foozzie/v8_foozzie.py
+++ b/chromium/v8/tools/foozzie/v8_foozzie.py
@@ -127,7 +127,7 @@ def infer_arch(d8):
executable.
"""
with open(os.path.join(os.path.dirname(d8), 'v8_build_config.json')) as f:
- arch = json.load(f)['v8_current_cpu']
+ arch = json.load(f)['v8_target_cpu']
return 'ia32' if arch == 'x86' else arch
diff --git a/chromium/v8/tools/mb/docs/design_spec.md b/chromium/v8/tools/mb/docs/design_spec.md
index 33fda806e8a..fb202da74e9 100644
--- a/chromium/v8/tools/mb/docs/design_spec.md
+++ b/chromium/v8/tools/mb/docs/design_spec.md
@@ -411,9 +411,9 @@ config file change, however.
### Non-goals
* MB is not intended to replace direct invocation of GN or GYP for
- complicated build scenarios (aka ChromeOS), where multiple flags need
+ complicated build scenarios (a.k.a. Chrome OS), where multiple flags need
to be set to user-defined paths for specific toolchains (e.g., where
- ChromeOS needs to specify specific board types and compilers).
+ Chrome OS needs to specify specific board types and compilers).
* MB is not intended at this time to be something developers use frequently,
or to add a lot of features to. We hope to be able to get rid of it once
diff --git a/chromium/v8/tools/mb/docs/user_guide.md b/chromium/v8/tools/mb/docs/user_guide.md
index b897fa4d671..a7d72c88395 100644
--- a/chromium/v8/tools/mb/docs/user_guide.md
+++ b/chromium/v8/tools/mb/docs/user_guide.md
@@ -20,7 +20,7 @@ For more discussion of MB, see also [the design spec](design_spec.md).
### `mb analyze`
-`mb analyze` is responsible for determining what targets are affected by
+`mb analyze` is reponsible for determining what targets are affected by
a list of files (e.g., the list of files in a patch on a trybot):
```
@@ -45,12 +45,12 @@ a single object with the following fields:
reflect the stuff we might want to build *in addition to* the list
passed in `test_targets`. Targets in this list will be treated
specially, in the following way: if a given target is a "meta"
- (GN: group, GYP: none) target like 'blink_tests' or
- 'chromium_builder_tests', or even the ninja-specific 'all' target,
- then only the *dependencies* of the target that are affected by
- the modified files will be rebuilt (not the target itself, which
- might also cause unaffected dependencies to be rebuilt). An empty
- list will be treated as if there are no additional targets to build.
+ (GN: group, GYP: none) target like 'blink_tests' or or even the
+ ninja-specific 'all' target, then only the *dependencies* of the
+ target that are affected by the modified files will be rebuilt
+ (not the target itself, which might also cause unaffected dependencies
+ to be rebuilt). An empty list will be treated as if there are no additional
+ targets to build.
Empty lists for both `test_targets` and `additional_compile_targets`
would cause no work to be done, so will result in an error.
* `targets`: a legacy field that resembled a union of `compile_targets`
@@ -167,6 +167,21 @@ The `-f/--config-file` and `-q/--quiet` flags work as documented for
This is mostly useful as a presubmit check and for verifying changes to
the config file.
+### `mb gerrit-buildbucket-config`
+
+Generates a gerrit buildbucket configuration file and prints it to
+stdout. This file contains the list of trybots shown in gerrit's UI.
+
+The master copy of the buildbucket.config file lives
+in a separate branch of the chromium repository. Run `mb
+gerrit-buildbucket-config > buildbucket.config.new && git fetch origin
+refs/meta/config:refs/remotes/origin/meta/config && git checkout
+-t -b meta_config origin/meta/config && mv buildbucket.config.new
+buildbucket.config` to update the file.
+
+Note that after committing, `git cl upload` will not work. Instead, use `git
+push origin HEAD:refs/for/refs/meta/config` to upload the CL for review.
+
## Isolates and Swarming
`mb gen` is also responsible for generating the `.isolate` and
diff --git a/chromium/v8/tools/mb/mb.py b/chromium/v8/tools/mb/mb.py
index 86a5e575fd2..9a6600225b8 100755
--- a/chromium/v8/tools/mb/mb.py
+++ b/chromium/v8/tools/mb/mb.py
@@ -10,6 +10,10 @@ MB is a wrapper script for GYP and GN that can be used to generate build files
for sets of canned configurations and analyze them.
"""
+# TODO(thomasanderson): Remove this comment. It is added to
+# workaround https://crbug.com/736215 for CL
+# https://codereview.chromium.org/2974603002/
+
from __future__ import print_function
import argparse
@@ -46,11 +50,14 @@ class MetaBuildWrapper(object):
self.chromium_src_dir = CHROMIUM_SRC_DIR
self.default_config = os.path.join(self.chromium_src_dir, 'infra', 'mb',
'mb_config.pyl')
+ self.default_isolate_map = os.path.join(self.chromium_src_dir, 'infra',
+ 'mb', 'gn_isolate_map.pyl')
self.executable = sys.executable
self.platform = sys.platform
self.sep = os.sep
self.args = argparse.Namespace()
self.configs = {}
+ self.luci_tryservers = {}
self.masters = {}
self.mixins = {}
@@ -62,7 +69,7 @@ class MetaBuildWrapper(object):
self.DumpInputFiles()
return ret
except KeyboardInterrupt:
- self.Print('interrupted, exiting', stream=sys.stderr)
+ self.Print('interrupted, exiting')
return 130
except Exception:
self.DumpInputFiles()
@@ -79,13 +86,18 @@ class MetaBuildWrapper(object):
help='master name to look up config from')
subp.add_argument('-c', '--config',
help='configuration to analyze')
- subp.add_argument('--phase', type=int,
- help=('build phase for a given build '
- '(int in [1, 2, ...))'))
+ subp.add_argument('--phase',
+ help='optional phase name (used when builders '
+ 'do multiple compiles with different '
+ 'arguments in a single build)')
subp.add_argument('-f', '--config-file', metavar='PATH',
default=self.default_config,
help='path to config file '
- '(default is //tools/mb/mb_config.pyl)')
+ '(default is %(default)s)')
+ subp.add_argument('-i', '--isolate-map-file', metavar='PATH',
+ default=self.default_isolate_map,
+ help='path to isolate map file '
+ '(default is %(default)s)')
subp.add_argument('-g', '--goma-dir',
help='path to goma directory')
subp.add_argument('--gyp-script', metavar='PATH',
@@ -121,6 +133,16 @@ class MetaBuildWrapper(object):
'as a JSON object.')
subp.set_defaults(func=self.CmdAnalyze)
+ subp = subps.add_parser('export',
+ help='print out the expanded configuration for'
+ 'each builder as a JSON object')
+ subp.add_argument('-f', '--config-file', metavar='PATH',
+ default=self.default_config,
+ help='path to config file (default is %(default)s)')
+ subp.add_argument('-g', '--goma-dir',
+ help='path to goma directory')
+ subp.set_defaults(func=self.CmdExport)
+
subp = subps.add_parser('gen',
help='generate a new set of build files')
AddCommonOptions(subp)
@@ -192,16 +214,14 @@ class MetaBuildWrapper(object):
help='validate the config file')
subp.add_argument('-f', '--config-file', metavar='PATH',
default=self.default_config,
- help='path to config file '
- '(default is //infra/mb/mb_config.pyl)')
+ help='path to config file (default is %(default)s)')
subp.set_defaults(func=self.CmdValidate)
subp = subps.add_parser('audit',
help='Audit the config file to track progress')
subp.add_argument('-f', '--config-file', metavar='PATH',
default=self.default_config,
- help='path to config file '
- '(default is //infra/mb/mb_config.pyl)')
+ help='path to config file (default is %(default)s)')
subp.add_argument('-i', '--internal', action='store_true',
help='check internal masters also')
subp.add_argument('-m', '--master', action='append',
@@ -217,6 +237,14 @@ class MetaBuildWrapper(object):
' do compiles')
subp.set_defaults(func=self.CmdAudit)
+ subp = subps.add_parser('gerrit-buildbucket-config',
+ help='Print buildbucket.config for gerrit '
+ '(see MB user guide)')
+ subp.add_argument('-f', '--config-file', metavar='PATH',
+ default=self.default_config,
+ help='path to config file (default is %(default)s)')
+ subp.set_defaults(func=self.CmdBuildbucket)
+
subp = subps.add_parser('help',
help='Get help on a subcommand.')
subp.add_argument(nargs='?', action='store', dest='subcommand',
@@ -225,12 +253,16 @@ class MetaBuildWrapper(object):
self.args = parser.parse_args(argv)
+ # TODO(machenbach): This prepares passing swarming targets to isolate on the
+ # infra side.
+ self.args.swarming_targets_file = None
+
def DumpInputFiles(self):
def DumpContentsOfFilePassedTo(arg_name, path):
if path and self.Exists(path):
self.Print("\n# To recreate the file passed to %s:" % arg_name)
- self.Print("%% cat > %s <<EOF)" % path)
+ self.Print("%% cat > %s <<EOF" % path)
contents = self.ReadFile(path)
self.Print(contents)
self.Print("EOF\n%\n")
@@ -250,6 +282,34 @@ class MetaBuildWrapper(object):
else:
return self.RunGYPAnalyze(vals)
+ def CmdExport(self):
+ self.ReadConfigFile()
+ obj = {}
+ for master, builders in self.masters.items():
+ obj[master] = {}
+ for builder in builders:
+ config = self.masters[master][builder]
+ if not config:
+ continue
+
+ if isinstance(config, dict):
+ args = {k: self.FlattenConfig(v)['gn_args']
+ for k, v in config.items()}
+ elif config.startswith('//'):
+ args = config
+ else:
+ args = self.FlattenConfig(config)['gn_args']
+ if 'error' in args:
+ continue
+
+ obj[master][builder] = args
+
+ # Dump object and trim trailing whitespace.
+ s = '\n'.join(l.rstrip() for l in
+ json.dumps(obj, sort_keys=True, indent=2).splitlines())
+ self.Print(s)
+ return 0
+
def CmdGen(self):
vals = self.Lookup()
self.ClobberIfNeeded(vals)
@@ -270,7 +330,7 @@ class MetaBuildWrapper(object):
return 1
if vals['type'] == 'gn':
- return self.RunGNIsolate(vals)
+ return self.RunGNIsolate()
else:
return self.Build('%s_run' % self.args.target[0])
@@ -300,7 +360,7 @@ class MetaBuildWrapper(object):
ret = self.Build(target)
if ret:
return ret
- ret = self.RunGNIsolate(vals)
+ ret = self.RunGNIsolate()
if ret:
return ret
else:
@@ -322,6 +382,25 @@ class MetaBuildWrapper(object):
return ret
+ def CmdBuildbucket(self):
+ self.ReadConfigFile()
+
+ self.Print('# This file was generated using '
+ '"tools/mb/mb.py gerrit-buildbucket-config".')
+
+ for luci_tryserver in sorted(self.luci_tryservers):
+ self.Print('[bucket "luci.%s"]' % luci_tryserver)
+ for bot in sorted(self.luci_tryservers[luci_tryserver]):
+ self.Print('\tbuilder = %s' % bot)
+
+ for master in sorted(self.masters):
+ if master.startswith('tryserver.'):
+ self.Print('[bucket "master.%s"]' % master)
+ for bot in sorted(self.masters[master]):
+ self.Print('\tbuilder = %s' % bot)
+
+ return 0
+
def CmdValidate(self, print_ok=True):
errs = []
@@ -332,8 +411,8 @@ class MetaBuildWrapper(object):
all_configs = {}
for master in self.masters:
for config in self.masters[master].values():
- if isinstance(config, list):
- for c in config:
+ if isinstance(config, dict):
+ for c in config.values():
all_configs[c] = master
else:
all_configs[config] = master
@@ -461,8 +540,8 @@ class MetaBuildWrapper(object):
config = self.masters[master][builder]
if config == 'tbd':
tbd.add(builder)
- elif isinstance(config, list):
- vals = self.FlattenConfig(config[0])
+ elif isinstance(config, dict):
+ vals = self.FlattenConfig(config.values()[0])
if vals['type'] == 'gyp':
gyp.add(builder)
else:
@@ -504,7 +583,7 @@ class MetaBuildWrapper(object):
def GetConfig(self):
build_dir = self.args.path[0]
- vals = {}
+ vals = self.DefaultVals()
if self.args.builder or self.args.master or self.args.config:
vals = self.Lookup()
if vals['type'] == 'gn':
@@ -528,14 +607,12 @@ class MetaBuildWrapper(object):
mb_type = self.ReadFile(mb_type_path).strip()
if mb_type == 'gn':
- vals = self.GNValsFromDir(build_dir)
- else:
- vals = {}
+ vals['gn_args'] = self.GNArgsFromDir(build_dir)
vals['type'] = mb_type
return vals
- def GNValsFromDir(self, build_dir):
+ def GNArgsFromDir(self, build_dir):
args_contents = ""
gn_args_path = self.PathJoin(self.ToAbsPath(build_dir), 'args.gn')
if self.Exists(gn_args_path):
@@ -547,27 +624,18 @@ class MetaBuildWrapper(object):
val = ' '.join(fields[2:])
gn_args.append('%s=%s' % (name, val))
- return {
- 'gn_args': ' '.join(gn_args),
- 'type': 'gn',
- }
+ return ' '.join(gn_args)
def Lookup(self):
- vals = self.ReadBotConfig()
+ vals = self.ReadIOSBotConfig()
if not vals:
self.ReadConfigFile()
config = self.ConfigFromArgs()
if config.startswith('//'):
if not self.Exists(self.ToAbsPath(config)):
raise MBErr('args file "%s" not found' % config)
- vals = {
- 'args_file': config,
- 'cros_passthrough': False,
- 'gn_args': '',
- 'gyp_crosscompile': False,
- 'gyp_defines': '',
- 'type': 'gn',
- }
+ vals = self.DefaultVals()
+ vals['args_file'] = config
else:
if not config in self.configs:
raise MBErr('Config "%s" not found in %s' %
@@ -576,13 +644,14 @@ class MetaBuildWrapper(object):
# Do some basic sanity checking on the config so that we
# don't have to do this in every caller.
- assert 'type' in vals, 'No meta-build type specified in the config'
+ if 'type' not in vals:
+ vals['type'] = 'gn'
assert vals['type'] in ('gn', 'gyp'), (
'Unknown meta-build type "%s"' % vals['gn_args'])
return vals
- def ReadBotConfig(self):
+ def ReadIOSBotConfig(self):
if not self.args.master or not self.args.builder:
return {}
path = self.PathJoin(self.chromium_src_dir, 'ios', 'build', 'bots',
@@ -598,14 +667,11 @@ class MetaBuildWrapper(object):
gyp_defines = ' '.join(gyp_vals)
gn_args = ' '.join(contents.get('gn_args', []))
- return {
- 'args_file': '',
- 'cros_passthrough': False,
- 'gn_args': gn_args,
- 'gyp_crosscompile': False,
- 'gyp_defines': gyp_defines,
- 'type': contents.get('mb_type', ''),
- }
+ vals = self.DefaultVals()
+ vals['gn_args'] = gn_args
+ vals['gyp_defines'] = gyp_defines
+ vals['type'] = contents.get('mb_type', 'gn')
+ return vals
def ReadConfigFile(self):
if not self.Exists(self.args.config_file):
@@ -618,9 +684,20 @@ class MetaBuildWrapper(object):
(self.args.config_file, e))
self.configs = contents['configs']
+ self.luci_tryservers = contents.get('luci_tryservers', {})
self.masters = contents['masters']
self.mixins = contents['mixins']
+ def ReadIsolateMap(self):
+ if not self.Exists(self.args.isolate_map_file):
+ raise MBErr('isolate map file not found at %s' %
+ self.args.isolate_map_file)
+ try:
+ return ast.literal_eval(self.ReadFile(self.args.isolate_map_file))
+ except SyntaxError as e:
+ raise MBErr('Failed to parse isolate map file "%s": %s' %
+ (self.args.isolate_map_file, e))
+
def ConfigFromArgs(self):
if self.args.config:
if self.args.master or self.args.builder:
@@ -642,15 +719,15 @@ class MetaBuildWrapper(object):
(self.args.builder, self.args.master, self.args.config_file))
config = self.masters[self.args.master][self.args.builder]
- if isinstance(config, list):
+ if isinstance(config, dict):
if self.args.phase is None:
raise MBErr('Must specify a build --phase for %s on %s' %
(self.args.builder, self.args.master))
- phase = int(self.args.phase)
- if phase < 1 or phase > len(config):
- raise MBErr('Phase %d out of bounds for %s on %s' %
+ phase = str(self.args.phase)
+ if phase not in config:
+ raise MBErr('Phase %s doesn\'t exist for %s on %s' %
(phase, self.args.builder, self.args.master))
- return config[phase-1]
+ return config[phase]
if self.args.phase is not None:
raise MBErr('Must not specify a build --phase for %s on %s' %
@@ -659,19 +736,22 @@ class MetaBuildWrapper(object):
def FlattenConfig(self, config):
mixins = self.configs[config]
- vals = {
+ vals = self.DefaultVals()
+
+ visited = []
+ self.FlattenMixins(mixins, vals, visited)
+ return vals
+
+ def DefaultVals(self):
+ return {
'args_file': '',
'cros_passthrough': False,
- 'gn_args': [],
+ 'gn_args': '',
'gyp_defines': '',
'gyp_crosscompile': False,
- 'type': None,
+ 'type': 'gn',
}
- visited = []
- self.FlattenMixins(mixins, vals, visited)
- return vals
-
def FlattenMixins(self, mixins, vals, visited):
for m in mixins:
if m not in self.mixins:
@@ -683,6 +763,11 @@ class MetaBuildWrapper(object):
if 'cros_passthrough' in mixin_vals:
vals['cros_passthrough'] = mixin_vals['cros_passthrough']
+ if 'args_file' in mixin_vals:
+ if vals['args_file']:
+ raise MBErr('args_file specified multiple times in mixins '
+ 'for %s on %s' % (self.args.builder, self.args.master))
+ vals['args_file'] = mixin_vals['args_file']
if 'gn_args' in mixin_vals:
if vals['gn_args']:
vals['gn_args'] += ' ' + mixin_vals['gn_args']
@@ -732,11 +817,13 @@ class MetaBuildWrapper(object):
self.MaybeMakeDirectory(build_dir)
self.WriteFile(mb_type_path, new_mb_type)
- def RunGNGen(self, vals):
+ def RunGNGen(self, vals, compute_grit_inputs_for_analyze=False):
build_dir = self.args.path[0]
cmd = self.GNCmd('gen', build_dir, '--check')
gn_args = self.GNArgs(vals)
+ if compute_grit_inputs_for_analyze:
+ gn_args += ' compute_grit_inputs_for_analyze=true'
# Since GN hasn't run yet, the build directory may not even exist.
self.MaybeMakeDirectory(self.ToAbsPath(build_dir))
@@ -748,7 +835,7 @@ class MetaBuildWrapper(object):
if getattr(self.args, 'swarming_targets_file', None):
# We need GN to generate the list of runtime dependencies for
# the compile targets listed (one per line) in the file so
- # we can run them via swarming. We use ninja_to_gn.pyl to convert
+ # we can run them via swarming. We use gn_isolate_map.pyl to convert
# the compile targets to the matching GN labels.
path = self.args.swarming_targets_file
if not self.Exists(path):
@@ -756,34 +843,17 @@ class MetaBuildWrapper(object):
output_path=None)
contents = self.ReadFile(path)
swarming_targets = set(contents.splitlines())
- gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin(
- self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl')))
- gn_labels = []
- err = ''
- for target in swarming_targets:
- target_name = self.GNTargetName(target)
- if not target_name in gn_isolate_map:
- err += ('test target "%s" not found\n' % target_name)
- elif gn_isolate_map[target_name]['type'] == 'unknown':
- err += ('test target "%s" type is unknown\n' % target_name)
- else:
- gn_labels.append(gn_isolate_map[target_name]['label'])
+ isolate_map = self.ReadIsolateMap()
+ err, labels = self.MapTargetsToLabels(isolate_map, swarming_targets)
if err:
- raise MBErr('Error: Failed to match swarming targets to %s:\n%s' %
- ('//testing/buildbot/gn_isolate_map.pyl', err))
+ raise MBErr(err)
gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps')
- self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n')
+ self.WriteFile(gn_runtime_deps_path, '\n'.join(labels) + '\n')
cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path)
- # Override msvs infra environment variables.
- # TODO(machenbach): Remove after GYP_MSVS_VERSION is removed on infra side.
- env = {}
- env.update(os.environ)
- env['GYP_MSVS_VERSION'] = '2017'
-
- ret, _, _ = self.Run(cmd, env=env)
+ ret, _, _ = self.Run(cmd)
if ret:
# If `gn gen` failed, we should exit early rather than trying to
# generate isolates. Run() will have already logged any error output.
@@ -796,24 +866,23 @@ class MetaBuildWrapper(object):
# Android targets may be either android_apk or executable. The former
# will result in runtime_deps associated with the stamp file, while the
# latter will result in runtime_deps associated with the executable.
- target_name = self.GNTargetName(target)
- label = gn_isolate_map[target_name]['label']
+ label = isolate_map[target]['label']
runtime_deps_targets = [
- target_name + '.runtime_deps',
+ target + '.runtime_deps',
'obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
- elif gn_isolate_map[target]['type'] == 'gpu_browser_test':
- if self.platform == 'win32':
- runtime_deps_targets = ['browser_tests.exe.runtime_deps']
- else:
- runtime_deps_targets = ['browser_tests.runtime_deps']
- elif (gn_isolate_map[target]['type'] == 'script' or
- gn_isolate_map[target].get('label_type') == 'group'):
+ elif (isolate_map[target]['type'] == 'script' or
+ isolate_map[target].get('label_type') == 'group'):
# For script targets, the build target is usually a group,
# for which gn generates the runtime_deps next to the stamp file
- # for the label, which lives under the obj/ directory.
- label = gn_isolate_map[target]['label']
+ # for the label, which lives under the obj/ directory, but it may
+ # also be an executable.
+ label = isolate_map[target]['label']
runtime_deps_targets = [
'obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
+ if self.platform == 'win32':
+ runtime_deps_targets += [ target + '.exe.runtime_deps' ]
+ else:
+ runtime_deps_targets += [ target + '.runtime_deps' ]
elif self.platform == 'win32':
runtime_deps_targets = [target + '.exe.runtime_deps']
else:
@@ -827,26 +896,22 @@ class MetaBuildWrapper(object):
raise MBErr('did not generate any of %s' %
', '.join(runtime_deps_targets))
- command, extra_files = self.GetIsolateCommand(target, vals,
- gn_isolate_map)
-
runtime_deps = self.ReadFile(runtime_deps_path).splitlines()
- self.WriteIsolateFiles(build_dir, command, target, runtime_deps,
- extra_files)
+ self.WriteIsolateFiles(build_dir, target, runtime_deps)
return 0
- def RunGNIsolate(self, vals):
- gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin(
- self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl')))
+ def RunGNIsolate(self):
+ target = self.args.target[0]
+ isolate_map = self.ReadIsolateMap()
+ err, labels = self.MapTargetsToLabels(isolate_map, [target])
+ if err:
+ raise MBErr(err)
+ label = labels[0]
build_dir = self.args.path[0]
- target = self.args.target[0]
- target_name = self.GNTargetName(target)
- command, extra_files = self.GetIsolateCommand(target, vals, gn_isolate_map)
- label = gn_isolate_map[target_name]['label']
cmd = self.GNCmd('desc', build_dir, label, 'runtime_deps')
ret, out, _ = self.Call(cmd)
if ret:
@@ -856,8 +921,7 @@ class MetaBuildWrapper(object):
runtime_deps = out.splitlines()
- self.WriteIsolateFiles(build_dir, command, target, runtime_deps,
- extra_files)
+ self.WriteIsolateFiles(build_dir, target, runtime_deps)
ret, _, _ = self.Run([
self.executable,
@@ -871,14 +935,12 @@ class MetaBuildWrapper(object):
return ret
- def WriteIsolateFiles(self, build_dir, command, target, runtime_deps,
- extra_files):
+ def WriteIsolateFiles(self, build_dir, target, runtime_deps):
isolate_path = self.ToAbsPath(build_dir, target + '.isolate')
self.WriteFile(isolate_path,
pprint.pformat({
'variables': {
- 'command': command,
- 'files': sorted(runtime_deps + extra_files),
+ 'files': sorted(runtime_deps),
}
}) + '\n')
@@ -896,6 +958,27 @@ class MetaBuildWrapper(object):
isolate_path + 'd.gen.json',
)
+ def MapTargetsToLabels(self, isolate_map, targets):
+ labels = []
+ err = ''
+
+ for target in targets:
+ if target == 'all':
+ labels.append(target)
+ elif target.startswith('//'):
+ labels.append(target)
+ else:
+ if target in isolate_map:
+ if isolate_map[target]['type'] == 'unknown':
+ err += ('test target "%s" type is unknown\n' % target)
+ else:
+ labels.append(isolate_map[target]['label'])
+ else:
+ err += ('target "%s" not found in '
+ '//infra/mb/gn_isolate_map.pyl\n' % target)
+
+ return err, labels
+
def GNCmd(self, subcommand, path, *args):
if self.platform == 'linux2':
subdir, exe = 'linux64', 'gn'
@@ -905,9 +988,9 @@ class MetaBuildWrapper(object):
subdir, exe = 'win', 'gn.exe'
gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, exe)
-
return [gn_path, subcommand, path] + list(args)
+
def GNArgs(self, vals):
if vals['cros_passthrough']:
if not 'GN_ARGS' in os.environ:
@@ -972,109 +1055,6 @@ class MetaBuildWrapper(object):
return ret
- def GetIsolateCommand(self, target, vals, gn_isolate_map):
- android = 'target_os="android"' in vals['gn_args']
-
- # This needs to mirror the settings in //build/config/ui.gni:
- # use_x11 = is_linux && !use_ozone.
- use_x11 = (self.platform == 'linux2' and
- not android and
- not 'use_ozone=true' in vals['gn_args'])
-
- asan = 'is_asan=true' in vals['gn_args']
- msan = 'is_msan=true' in vals['gn_args']
- tsan = 'is_tsan=true' in vals['gn_args']
-
- target_name = self.GNTargetName(target)
- test_type = gn_isolate_map[target_name]['type']
-
- executable = gn_isolate_map[target_name].get('executable', target_name)
- executable_suffix = '.exe' if self.platform == 'win32' else ''
-
- cmdline = []
- extra_files = []
-
- if android and test_type != "script":
- logdog_command = [
- '--logdog-bin-cmd', './../../bin/logdog_butler',
- '--project', 'chromium',
- '--service-account-json',
- '/creds/service_accounts/service-account-luci-logdog-publisher.json',
- '--prefix', 'android/swarming/logcats/${SWARMING_TASK_ID}',
- '--source', '${ISOLATED_OUTDIR}/logcats',
- '--name', 'unified_logcats',
- ]
- test_cmdline = [
- self.PathJoin('bin', 'run_%s' % target_name),
- '--logcat-output-file', '${ISOLATED_OUTDIR}/logcats',
- '--target-devices-file', '${SWARMING_BOT_FILE}',
- '-v'
- ]
- cmdline = (['./../../build/android/test_wrapper/logdog_wrapper.py']
- + logdog_command + test_cmdline)
- elif use_x11 and test_type == 'windowed_test_launcher':
- extra_files = [
- '../../testing/test_env.py',
- '../../testing/xvfb.py',
- ]
- cmdline = [
- '../../testing/xvfb.py',
- '.',
- './' + str(executable) + executable_suffix,
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=%d' % asan,
- '--msan=%d' % msan,
- '--tsan=%d' % tsan,
- ]
- elif test_type in ('windowed_test_launcher', 'console_test_launcher'):
- extra_files = [
- '../../testing/test_env.py'
- ]
- cmdline = [
- '../../testing/test_env.py',
- './' + str(executable) + executable_suffix,
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=%d' % asan,
- '--msan=%d' % msan,
- '--tsan=%d' % tsan,
- ]
- elif test_type == 'gpu_browser_test':
- extra_files = [
- '../../testing/test_env.py'
- ]
- gtest_filter = gn_isolate_map[target]['gtest_filter']
- cmdline = [
- '../../testing/test_env.py',
- './browser_tests' + executable_suffix,
- '--test-launcher-bot-mode',
- '--enable-gpu',
- '--test-launcher-jobs=1',
- '--gtest_filter=%s' % gtest_filter,
- ]
- elif test_type == 'script':
- extra_files = [
- '../../testing/test_env.py'
- ]
- cmdline = [
- '../../testing/test_env.py',
- '../../' + self.ToSrcRelPath(gn_isolate_map[target]['script'])
- ]
- elif test_type in ('raw'):
- extra_files = []
- cmdline = [
- './' + str(target) + executable_suffix,
- ]
-
- else:
- self.WriteFailureAndRaise('No command line for %s found (test type %s).'
- % (target, test_type), output_path=None)
-
- cmdline += gn_isolate_map[target_name].get('args', [])
-
- return cmdline, extra_files
-
def ToAbsPath(self, build_path, *comps):
return self.PathJoin(self.chromium_src_dir,
self.ToSrcRelPath(build_path),
@@ -1167,12 +1147,18 @@ class MetaBuildWrapper(object):
return cmd, env
def RunGNAnalyze(self, vals):
- # analyze runs before 'gn gen' now, so we need to run gn gen
+ # Analyze runs before 'gn gen' now, so we need to run gn gen
# in order to ensure that we have a build directory.
- ret = self.RunGNGen(vals)
+ ret = self.RunGNGen(vals, compute_grit_inputs_for_analyze=True)
if ret:
return ret
+ build_path = self.args.path[0]
+ input_path = self.args.input_path[0]
+ gn_input_path = input_path + '.gn'
+ output_path = self.args.output_path[0]
+ gn_output_path = output_path + '.gn'
+
inp = self.ReadInputJSON(['files', 'test_targets',
'additional_compile_targets'])
if self.args.verbose:
@@ -1181,26 +1167,6 @@ class MetaBuildWrapper(object):
self.PrintJSON(inp)
self.Print()
- # TODO(crbug.com/555273) - currently GN treats targets and
- # additional_compile_targets identically since we can't tell the
- # difference between a target that is a group in GN and one that isn't.
- # We should eventually fix this and treat the two types differently.
- targets = (set(inp['test_targets']) |
- set(inp['additional_compile_targets']))
-
- output_path = self.args.output_path[0]
-
- # Bail out early if a GN file was modified, since 'gn refs' won't know
- # what to do about it. Also, bail out early if 'all' was asked for,
- # since we can't deal with it yet.
- if (any(f.endswith('.gn') or f.endswith('.gni') for f in inp['files']) or
- 'all' in targets):
- self.WriteJSON({
- 'status': 'Found dependency (all)',
- 'compile_targets': sorted(targets),
- 'test_targets': sorted(targets & set(inp['test_targets'])),
- }, output_path)
- return 0
# This shouldn't normally happen, but could due to unusual race conditions,
# like a try job that gets scheduled before a patch lands but runs after
@@ -1214,68 +1180,103 @@ class MetaBuildWrapper(object):
}, output_path)
return 0
- ret = 0
- response_file = self.TempFile()
- response_file.write('\n'.join(inp['files']) + '\n')
- response_file.close()
+ gn_inp = {}
+ gn_inp['files'] = ['//' + f for f in inp['files'] if not f.startswith('//')]
+
+ isolate_map = self.ReadIsolateMap()
+ err, gn_inp['additional_compile_targets'] = self.MapTargetsToLabels(
+ isolate_map, inp['additional_compile_targets'])
+ if err:
+ raise MBErr(err)
+
+ err, gn_inp['test_targets'] = self.MapTargetsToLabels(
+ isolate_map, inp['test_targets'])
+ if err:
+ raise MBErr(err)
+ labels_to_targets = {}
+ for i, label in enumerate(gn_inp['test_targets']):
+ labels_to_targets[label] = inp['test_targets'][i]
- matching_targets = set()
try:
- cmd = self.GNCmd('refs',
- self.args.path[0],
- '@%s' % response_file.name,
- '--all',
- '--as=output')
- ret, out, _ = self.Run(cmd, force_verbose=False)
- if ret and not 'The input matches no targets' in out:
- self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out),
- output_path)
- build_dir = self.ToSrcRelPath(self.args.path[0]) + self.sep
- for output in out.splitlines():
- build_output = output.replace(build_dir, '')
- if build_output in targets:
- matching_targets.add(build_output)
-
- cmd = self.GNCmd('refs',
- self.args.path[0],
- '@%s' % response_file.name,
- '--all')
- ret, out, _ = self.Run(cmd, force_verbose=False)
- if ret and not 'The input matches no targets' in out:
- self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out),
- output_path)
- for label in out.splitlines():
- build_target = label[2:]
- # We want to accept 'chrome/android:chrome_public_apk' and
- # just 'chrome_public_apk'. This may result in too many targets
- # getting built, but we can adjust that later if need be.
- for input_target in targets:
- if (input_target == build_target or
- build_target.endswith(':' + input_target)):
- matching_targets.add(input_target)
- finally:
- self.RemoveFile(response_file.name)
+ self.WriteJSON(gn_inp, gn_input_path)
+ cmd = self.GNCmd('analyze', build_path, gn_input_path, gn_output_path)
+ ret, _, _ = self.Run(cmd, force_verbose=True)
+ if ret:
+ return ret
- if matching_targets:
- self.WriteJSON({
- 'status': 'Found dependency',
- 'compile_targets': sorted(matching_targets),
- 'test_targets': sorted(matching_targets &
- set(inp['test_targets'])),
- }, output_path)
- else:
- self.WriteJSON({
- 'status': 'No dependency',
- 'compile_targets': [],
- 'test_targets': [],
- }, output_path)
+ gn_outp_str = self.ReadFile(gn_output_path)
+ try:
+ gn_outp = json.loads(gn_outp_str)
+ except Exception as e:
+ self.Print("Failed to parse the JSON string GN returned: %s\n%s"
+ % (repr(gn_outp_str), str(e)))
+ raise
- if self.args.verbose:
- outp = json.loads(self.ReadFile(output_path))
- self.Print()
- self.Print('analyze output:')
- self.PrintJSON(outp)
- self.Print()
+ outp = {}
+ if 'status' in gn_outp:
+ outp['status'] = gn_outp['status']
+ if 'error' in gn_outp:
+ outp['error'] = gn_outp['error']
+ if 'invalid_targets' in gn_outp:
+ outp['invalid_targets'] = gn_outp['invalid_targets']
+ if 'compile_targets' in gn_outp:
+ all_input_compile_targets = sorted(
+ set(inp['test_targets'] + inp['additional_compile_targets']))
+
+ # If we're building 'all', we can throw away the rest of the targets
+ # since they're redundant.
+ if 'all' in gn_outp['compile_targets']:
+ outp['compile_targets'] = ['all']
+ else:
+ outp['compile_targets'] = gn_outp['compile_targets']
+
+ # crbug.com/736215: When GN returns targets back, for targets in
+ # the default toolchain, GN will have generated a phony ninja
+ # target matching the label, and so we can safely (and easily)
+ # transform any GN label into the matching ninja target. For
+ # targets in other toolchains, though, GN doesn't generate the
+ # phony targets, and we don't know how to turn the labels into
+ # compile targets. In this case, we also conservatively give up
+ # and build everything. Probably the right thing to do here is
+ # to have GN return the compile targets directly.
+ if any("(" in target for target in outp['compile_targets']):
+ self.Print('WARNING: targets with non-default toolchains were '
+ 'found, building everything instead.')
+ outp['compile_targets'] = all_input_compile_targets
+ else:
+ outp['compile_targets'] = [
+ label.replace('//', '') for label in outp['compile_targets']]
+
+ # Windows has a maximum command line length of 8k; even Linux
+ # maxes out at 128k; if analyze returns a *really long* list of
+ # targets, we just give up and conservatively build everything instead.
+ # Probably the right thing here is for ninja to support response
+ # files as input on the command line
+ # (see https://github.com/ninja-build/ninja/issues/1355).
+ if len(' '.join(outp['compile_targets'])) > 7*1024:
+ self.Print('WARNING: Too many compile targets were affected.')
+ self.Print('WARNING: Building everything instead to avoid '
+ 'command-line length issues.')
+ outp['compile_targets'] = all_input_compile_targets
+
+
+ if 'test_targets' in gn_outp:
+ outp['test_targets'] = [
+ labels_to_targets[label] for label in gn_outp['test_targets']]
+
+ if self.args.verbose:
+ self.Print()
+ self.Print('analyze output:')
+ self.PrintJSON(outp)
+ self.Print()
+
+ self.WriteJSON(outp, output_path)
+
+ finally:
+ if self.Exists(gn_input_path):
+ self.RemoveFile(gn_input_path)
+ if self.Exists(gn_output_path):
+ self.RemoveFile(gn_output_path)
return 0
@@ -1358,9 +1359,6 @@ class MetaBuildWrapper(object):
def PrintJSON(self, obj):
self.Print(json.dumps(obj, indent=2, sort_keys=True))
- def GNTargetName(self, target):
- return target
-
def Build(self, target):
build_dir = self.ToSrcRelPath(self.args.path[0])
ninja_cmd = ['ninja', '-C', build_dir]
diff --git a/chromium/v8/tools/mb/mb_unittest.py b/chromium/v8/tools/mb/mb_unittest.py
index ac58c0284f9..15763750da5 100755
--- a/chromium/v8/tools/mb/mb_unittest.py
+++ b/chromium/v8/tools/mb/mb_unittest.py
@@ -23,12 +23,15 @@ class FakeMBW(mb.MetaBuildWrapper):
if win32:
self.chromium_src_dir = 'c:\\fake_src'
self.default_config = 'c:\\fake_src\\tools\\mb\\mb_config.pyl'
+ self.default_isolate_map = ('c:\\fake_src\\testing\\buildbot\\'
+ 'gn_isolate_map.pyl')
self.platform = 'win32'
self.executable = 'c:\\python\\python.exe'
self.sep = '\\'
else:
self.chromium_src_dir = '/fake_src'
self.default_config = '/fake_src/tools/mb/mb_config.pyl'
+ self.default_isolate_map = '/fake_src/testing/buildbot/gn_isolate_map.pyl'
self.executable = '/usr/bin/python'
self.platform = 'linux2'
self.sep = '/'
@@ -115,10 +118,14 @@ TEST_CONFIG = """\
'fake_gn_debug_builder': 'gn_debug_goma',
'fake_gyp_builder': 'gyp_debug',
'fake_gn_args_bot': '//build/args/bots/fake_master/fake_gn_args_bot.gn',
- 'fake_multi_phase': ['gn_phase_1', 'gn_phase_2'],
+ 'fake_multi_phase': { 'phase_1': 'gn_phase_1', 'phase_2': 'gn_phase_2'},
+ 'fake_args_file': 'args_file_goma',
+ 'fake_args_file_twice': 'args_file_twice',
},
},
'configs': {
+ 'args_file_goma': ['args_file', 'goma'],
+ 'args_file_twice': ['args_file', 'args_file'],
'gyp_rel_bot': ['gyp', 'rel', 'goma'],
'gn_debug_goma': ['gn', 'debug', 'goma'],
'gyp_debug': ['gyp', 'debug', 'fake_feature1'],
@@ -141,6 +148,9 @@ TEST_CONFIG = """\
'gn_args': 'use_goma=true',
'gyp_defines': 'goma=1',
},
+ 'args_file': {
+ 'args_file': '//build/args/fake.gn',
+ },
'phase_1': {
'gn_args': 'phase=1',
'gyp_args': 'phase=1',
@@ -159,35 +169,6 @@ TEST_CONFIG = """\
}
"""
-
-TEST_BAD_CONFIG = """\
-{
- 'configs': {
- 'gn_rel_bot_1': ['gn', 'rel', 'chrome_with_codecs'],
- 'gn_rel_bot_2': ['gn', 'rel', 'bad_nested_config'],
- },
- 'masters': {
- 'chromium': {
- 'a': 'gn_rel_bot_1',
- 'b': 'gn_rel_bot_2',
- },
- },
- 'mixins': {
- 'gn': {'type': 'gn'},
- 'chrome_with_codecs': {
- 'gn_args': 'proprietary_codecs=true',
- },
- 'bad_nested_config': {
- 'mixins': ['chrome_with_codecs'],
- },
- 'rel': {
- 'gn_args': 'is_debug=false',
- },
- },
-}
-"""
-
-
GYP_HACKS_CONFIG = """\
{
'masters': {
@@ -211,12 +192,43 @@ GYP_HACKS_CONFIG = """\
}
"""
+TRYSERVER_CONFIG = """\
+{
+ 'masters': {
+ 'not_a_tryserver': {
+ 'fake_builder': 'fake_config',
+ },
+ 'tryserver.chromium.linux': {
+ 'try_builder': 'fake_config',
+ },
+ 'tryserver.chromium.mac': {
+ 'try_builder2': 'fake_config',
+ },
+ },
+ 'luci_tryservers': {
+ 'luci_tryserver1': ['luci_builder1'],
+ 'luci_tryserver2': ['luci_builder2'],
+ },
+ 'configs': {},
+ 'mixins': {},
+}
+"""
+
class UnitTest(unittest.TestCase):
def fake_mbw(self, files=None, win32=False):
mbw = FakeMBW(win32=win32)
mbw.files.setdefault(mbw.default_config, TEST_CONFIG)
mbw.files.setdefault(
+ mbw.ToAbsPath('//testing/buildbot/gn_isolate_map.pyl'),
+ '''{
+ "foo_unittests": {
+ "label": "//foo:foo_unittests",
+ "type": "console_test_launcher",
+ "args": [],
+ },
+ }''')
+ mbw.files.setdefault(
mbw.ToAbsPath('//build/args/bots/fake_master/fake_gn_args_bot.gn'),
'is_debug = false\n')
if files:
@@ -268,78 +280,104 @@ class UnitTest(unittest.TestCase):
['/fake_src/out/Debug', '/fake_src/out/Debug'])
self.assertEqual(mbw.files['/fake_src/out/Debug/mb_type'], 'gyp')
- def test_gn_analyze(self):
- files = {'/tmp/in.json': """{\
+ def test_analyze(self):
+ files = {'/tmp/in.json': '''{\
"files": ["foo/foo_unittest.cc"],
- "test_targets": ["foo_unittests", "bar_unittests"],
- "additional_compile_targets": []
- }"""}
+ "test_targets": ["foo_unittests"],
+ "additional_compile_targets": ["all"]
+ }''',
+ '/tmp/out.json.gn': '''{\
+ "status": "Found dependency",
+ "compile_targets": ["//foo:foo_unittests"],
+ "test_targets": ["//foo:foo_unittests"]
+ }'''}
mbw = self.fake_mbw(files)
- mbw.Call = lambda cmd, env=None, buffer_output=True: (
- 0, 'out/Default/foo_unittests\n', '')
+ mbw.Call = lambda cmd, env=None, buffer_output=True: (0, '', '')
self.check(['analyze', '-c', 'gn_debug_goma', '//out/Default',
'/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
out = json.loads(mbw.files['/tmp/out.json'])
self.assertEqual(out, {
'status': 'Found dependency',
- 'compile_targets': ['foo_unittests'],
+ 'compile_targets': ['foo:foo_unittests'],
'test_targets': ['foo_unittests']
})
- def test_gn_analyze_fails(self):
- files = {'/tmp/in.json': """{\
+ def test_analyze_optimizes_compile_for_all(self):
+ files = {'/tmp/in.json': '''{\
"files": ["foo/foo_unittest.cc"],
- "test_targets": ["foo_unittests", "bar_unittests"],
- "additional_compile_targets": []
- }"""}
+ "test_targets": ["foo_unittests"],
+ "additional_compile_targets": ["all"]
+ }''',
+ '/tmp/out.json.gn': '''{\
+ "status": "Found dependency",
+ "compile_targets": ["//foo:foo_unittests", "all"],
+ "test_targets": ["//foo:foo_unittests"]
+ }'''}
mbw = self.fake_mbw(files)
- mbw.Call = lambda cmd, env=None, buffer_output=True: (1, '', '')
+ mbw.Call = lambda cmd, env=None, buffer_output=True: (0, '', '')
self.check(['analyze', '-c', 'gn_debug_goma', '//out/Default',
- '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=1)
+ '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
+ out = json.loads(mbw.files['/tmp/out.json'])
+
+ # check that 'foo_unittests' is not in the compile_targets
+ self.assertEqual(['all'], out['compile_targets'])
- def test_gn_analyze_all(self):
- files = {'/tmp/in.json': """{\
+ def test_analyze_handles_other_toolchains(self):
+ files = {'/tmp/in.json': '''{\
"files": ["foo/foo_unittest.cc"],
- "test_targets": ["bar_unittests"],
+ "test_targets": ["foo_unittests"],
"additional_compile_targets": ["all"]
- }"""}
+ }''',
+ '/tmp/out.json.gn': '''{\
+ "status": "Found dependency",
+ "compile_targets": ["//foo:foo_unittests",
+ "//foo:foo_unittests(bar)"],
+ "test_targets": ["//foo:foo_unittests"]
+ }'''}
+
mbw = self.fake_mbw(files)
- mbw.Call = lambda cmd, env=None, buffer_output=True: (
- 0, 'out/Default/foo_unittests\n', '')
+ mbw.Call = lambda cmd, env=None, buffer_output=True: (0, '', '')
+
self.check(['analyze', '-c', 'gn_debug_goma', '//out/Default',
'/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
out = json.loads(mbw.files['/tmp/out.json'])
- self.assertEqual(out, {
- 'status': 'Found dependency (all)',
- 'compile_targets': ['all', 'bar_unittests'],
- 'test_targets': ['bar_unittests'],
- })
- def test_gn_analyze_missing_file(self):
- files = {'/tmp/in.json': """{\
+ # crbug.com/736215: If GN returns a label containing a toolchain,
+ # MB (and Ninja) don't know how to handle it; to work around this,
+ # we give up and just build everything we were asked to build. The
+ # output compile_targets should include all of the input test_targets and
+ # additional_compile_targets.
+ self.assertEqual(['all', 'foo_unittests'], out['compile_targets'])
+
+ def test_analyze_handles_way_too_many_results(self):
+ too_many_files = ', '.join(['"//foo:foo%d"' % i for i in xrange(4 * 1024)])
+ files = {'/tmp/in.json': '''{\
"files": ["foo/foo_unittest.cc"],
- "test_targets": ["bar_unittests"],
- "additional_compile_targets": []
- }"""}
+ "test_targets": ["foo_unittests"],
+ "additional_compile_targets": ["all"]
+ }''',
+ '/tmp/out.json.gn': '''{\
+ "status": "Found dependency",
+ "compile_targets": [''' + too_many_files + '''],
+ "test_targets": ["//foo:foo_unittests"]
+ }'''}
+
mbw = self.fake_mbw(files)
- mbw.cmds = [
- (0, '', ''),
- (1, 'The input matches no targets, configs, or files\n', ''),
- (1, 'The input matches no targets, configs, or files\n', ''),
- ]
+ mbw.Call = lambda cmd, env=None, buffer_output=True: (0, '', '')
self.check(['analyze', '-c', 'gn_debug_goma', '//out/Default',
'/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
out = json.loads(mbw.files['/tmp/out.json'])
- self.assertEqual(out, {
- 'status': 'No dependency',
- 'compile_targets': [],
- 'test_targets': [],
- })
+
+ # If GN returns so many compile targets that we might have command-line
+ # issues, we should give up and just build everything we were asked to
+ # build. The output compile_targets should include all of the input
+ # test_targets and additional_compile_targets.
+ self.assertEqual(['all', 'foo_unittests'], out['compile_targets'])
def test_gn_gen(self):
mbw = self.fake_mbw()
@@ -373,12 +411,27 @@ class UnitTest(unittest.TestCase):
mbw.files['/fake_src/out/Debug/args.gn'],
'import("//build/args/bots/fake_master/fake_gn_args_bot.gn")\n')
+ def test_gn_gen_args_file_mixins(self):
+ mbw = self.fake_mbw()
+ self.check(['gen', '-m', 'fake_master', '-b', 'fake_args_file',
+ '//out/Debug'], mbw=mbw, ret=0)
+
+ self.assertEqual(
+ mbw.files['/fake_src/out/Debug/args.gn'],
+ ('import("//build/args/fake.gn")\n'
+ 'use_goma = true\n'))
+
+ mbw = self.fake_mbw()
+ self.check(['gen', '-m', 'fake_master', '-b', 'fake_args_file_twice',
+ '//out/Debug'], mbw=mbw, ret=1)
def test_gn_gen_fails(self):
mbw = self.fake_mbw()
mbw.Call = lambda cmd, env=None, buffer_output=True: (1, '', '')
self.check(['gen', '-c', 'gn_debug_goma', '//out/Default'], mbw=mbw, ret=1)
+ # TODO(machenbach): Comment back in after swarming file parameter is used.
+ """
def test_gn_gen_swarming(self):
files = {
'/tmp/swarming_targets': 'base_unittests\n',
@@ -403,6 +456,34 @@ class UnitTest(unittest.TestCase):
self.assertIn('/fake_src/out/Default/base_unittests.isolated.gen.json',
mbw.files)
+ def test_gn_gen_swarming_script(self):
+ files = {
+ '/tmp/swarming_targets': 'cc_perftests\n',
+ '/fake_src/testing/buildbot/gn_isolate_map.pyl': (
+ "{'cc_perftests': {"
+ " 'label': '//cc:cc_perftests',"
+ " 'type': 'script',"
+ " 'script': '/fake_src/out/Default/test_script.py',"
+ " 'args': [],"
+ "}}\n"
+ ),
+ 'c:\\fake_src\out\Default\cc_perftests.exe.runtime_deps': (
+ "cc_perftests\n"
+ ),
+ }
+ mbw = self.fake_mbw(files=files, win32=True)
+ self.check(['gen',
+ '-c', 'gn_debug_goma',
+ '--swarming-targets-file', '/tmp/swarming_targets',
+ '--isolate-map-file',
+ '/fake_src/testing/buildbot/gn_isolate_map.pyl',
+ '//out/Default'], mbw=mbw, ret=0)
+ self.assertIn('c:\\fake_src\\out\\Default\\cc_perftests.isolate',
+ mbw.files)
+ self.assertIn('c:\\fake_src\\out\\Default\\cc_perftests.isolated.gen.json',
+ mbw.files)
+ """ # pylint: disable=pointless-string-statement
+
def test_gn_isolate(self):
files = {
'/fake_src/out/Default/toolchain.ninja': "",
@@ -509,27 +590,23 @@ class UnitTest(unittest.TestCase):
# Check that passing a --phase to a single-phase builder fails.
mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_gn_builder',
- '--phase', '1'],
- ret=1)
+ '--phase', 'phase_1'], ret=1)
self.assertIn('Must not specify a build --phase', mbw.out)
- # Check different ranges; 0 and 3 are out of bounds, 1 and 2 should work.
+ # Check that passing a wrong phase key to a multi-phase builder fails.
mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_multi_phase',
- '--phase', '0'], ret=1)
- self.assertIn('Phase 0 out of bounds', mbw.out)
+ '--phase', 'wrong_phase'], ret=1)
+ self.assertIn('Phase wrong_phase doesn\'t exist', mbw.out)
+ # Check that passing a correct phase key to a multi-phase builder passes.
mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_multi_phase',
- '--phase', '1'], ret=0)
+ '--phase', 'phase_1'], ret=0)
self.assertIn('phase = 1', mbw.out)
mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_multi_phase',
- '--phase', '2'], ret=0)
+ '--phase', 'phase_2'], ret=0)
self.assertIn('phase = 2', mbw.out)
- mbw = self.check(['lookup', '-m', 'fake_master', '-b', 'fake_multi_phase',
- '--phase', '3'], ret=1)
- self.assertIn('Phase 3 out of bounds', mbw.out)
-
def test_validate(self):
mbw = self.fake_mbw()
self.check(['validate'], mbw=mbw, ret=0)
@@ -544,28 +621,21 @@ class UnitTest(unittest.TestCase):
"LLVM_FORCE_HEAD_REVISION=1\n"
"python build/gyp_chromium -G output_dir=_path_\n"))
-
-if __name__ == '__main__':
- unittest.main()
-
- def test_validate(self):
- mbw = self.fake_mbw()
- self.check(['validate'], mbw=mbw, ret=0)
-
- def test_bad_validate(self):
- mbw = self.fake_mbw()
- mbw.files[mbw.default_config] = TEST_BAD_CONFIG
- self.check(['validate'], mbw=mbw, ret=1)
-
- def test_gyp_env_hacks(self):
+ def test_buildbucket(self):
mbw = self.fake_mbw()
- mbw.files[mbw.default_config] = GYP_HACKS_CONFIG
- self.check(['lookup', '-c', 'fake_config'], mbw=mbw,
+ mbw.files[mbw.default_config] = TRYSERVER_CONFIG
+ self.check(['gerrit-buildbucket-config'], mbw=mbw,
ret=0,
- out=("GYP_DEFINES='foo=bar baz=1'\n"
- "GYP_LINK_CONCURRENCY=1\n"
- "LLVM_FORCE_HEAD_REVISION=1\n"
- "python build/gyp_chromium -G output_dir=_path_\n"))
+ out=('# This file was generated using '
+ '"tools/mb/mb.py gerrit-buildbucket-config".\n'
+ '[bucket "luci.luci_tryserver1"]\n'
+ '\tbuilder = luci_builder1\n'
+ '[bucket "luci.luci_tryserver2"]\n'
+ '\tbuilder = luci_builder2\n'
+ '[bucket "master.tryserver.chromium.linux"]\n'
+ '\tbuilder = try_builder\n'
+ '[bucket "master.tryserver.chromium.mac"]\n'
+ '\tbuilder = try_builder2\n'))
if __name__ == '__main__':
diff --git a/chromium/v8/tools/testrunner/testrunner.isolate b/chromium/v8/tools/testrunner/testrunner.isolate
index e29f1df98df..56667c20215 100644
--- a/chromium/v8/tools/testrunner/testrunner.isolate
+++ b/chromium/v8/tools/testrunner/testrunner.isolate
@@ -7,6 +7,7 @@
'../run-tests.py',
],
'files': [
+ '<(PRODUCT_DIR)/v8_build_config.json',
'../run-tests.py',
'./'
],
@@ -20,12 +21,5 @@
],
},
}],
- ['is_gn==1', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/v8_build_config.json',
- ],
- },
- }],
],
}
diff --git a/chromium/v8/tools/testrunner/utils/dump_build_config.py b/chromium/v8/tools/testrunner/utils/dump_build_config.py
index bd57b5f34e2..b691bb3dc8d 100644
--- a/chromium/v8/tools/testrunner/utils/dump_build_config.py
+++ b/chromium/v8/tools/testrunner/utils/dump_build_config.py
@@ -15,7 +15,7 @@ import json
import os
import sys
-assert len(sys.argv) > 1
+assert len(sys.argv) > 2
def as_json(kv):
assert '=' in kv
@@ -23,4 +23,4 @@ def as_json(kv):
return k, json.loads(v)
with open(sys.argv[1], 'w') as f:
- json.dump(dict(as_json(kv) for kv in sys.argv[2:]), f)
+ json.dump(dict(map(as_json, sys.argv[2:])), f)
diff --git a/chromium/v8/tools/testrunner/utils/dump_build_config_gyp.py b/chromium/v8/tools/testrunner/utils/dump_build_config_gyp.py
new file mode 100644
index 00000000000..7f726271314
--- /dev/null
+++ b/chromium/v8/tools/testrunner/utils/dump_build_config_gyp.py
@@ -0,0 +1,54 @@
+# 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.
+
+"""The same as dump_build_config.py but for gyp legacy.
+
+Expected to be called like:
+dump_build_config.py path/to/file.json [key1=value1 ...]
+
+Raw gyp values are supported - they will be tranformed into valid json.
+"""
+# TODO(machenbach): Remove this when gyp is deprecated.
+
+import json
+import os
+import sys
+
+assert len(sys.argv) > 2
+
+
+GYP_GN_CONVERSION = {
+ 'is_component_build': {
+ 'shared_library': 'true',
+ 'static_library': 'false',
+ },
+ 'is_debug': {
+ 'Debug': 'true',
+ 'Release': 'false',
+ },
+}
+
+DEFAULT_CONVERSION ={
+ '0': 'false',
+ '1': 'true',
+ 'ia32': 'x86',
+}
+
+def gyp_to_gn(key, value):
+ value = GYP_GN_CONVERSION.get(key, DEFAULT_CONVERSION).get(value, value)
+ value = value if value in ['true', 'false'] else '"{0}"'.format(value)
+ return value
+
+def as_json(kv):
+ assert '=' in kv
+ k, v = kv.split('=', 1)
+ v2 = gyp_to_gn(k, v)
+ try:
+ return k, json.loads(v2)
+ except ValueError as e:
+ print(k, v, v2)
+ raise e
+
+with open(sys.argv[1], 'w') as f:
+ json.dump(dict(map(as_json, sys.argv[2:])), f)
diff --git a/chromium/v8/tools/whitespace.txt b/chromium/v8/tools/whitespace.txt
index 83c467a908f..37b1d825531 100644
--- a/chromium/v8/tools/whitespace.txt
+++ b/chromium/v8/tools/whitespace.txt
@@ -8,3 +8,4 @@ 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..........
+.