diff options
author | Michaël Zasso <targos@protonmail.com> | 2019-03-12 09:01:49 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2019-03-14 18:49:21 +0100 |
commit | 7b48713334469818661fe276cf571de9c7899f2d (patch) | |
tree | 4dbda49ac88db76ce09dc330a0cb587e68e139ba /deps/v8/test/unittests | |
parent | 8549ac09b256666cf5275224ec58fab9939ff32e (diff) | |
download | android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.tar.gz android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.tar.bz2 android-node-v8-7b48713334469818661fe276cf571de9c7899f2d.zip |
deps: update V8 to 7.3.492.25
PR-URL: https://github.com/nodejs/node/pull/25852
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/test/unittests')
104 files changed, 4577 insertions, 2996 deletions
diff --git a/deps/v8/test/unittests/BUILD.gn b/deps/v8/test/unittests/BUILD.gn index f63e2af197..77d503c7d4 100644 --- a/deps/v8/test/unittests/BUILD.gn +++ b/deps/v8/test/unittests/BUILD.gn @@ -54,7 +54,7 @@ v8_source_set("unittests_sources") { "api/v8-object-unittest.cc", "asmjs/asm-scanner-unittest.cc", "asmjs/asm-types-unittest.cc", - "asmjs/switch-logic-unittest.cc", + "background-compile-task-unittest.cc", "base/address-region-unittest.cc", "base/atomic-utils-unittest.cc", "base/bits-unittest.cc", @@ -83,10 +83,13 @@ v8_source_set("unittests_sources") { "char-predicates-unittest.cc", "code-stub-assembler-unittest.cc", "code-stub-assembler-unittest.h", - "compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc", "compiler-dispatcher/compiler-dispatcher-unittest.cc", "compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc", - "compiler-dispatcher/unoptimized-compile-job-unittest.cc", + "compiler/backend/instruction-selector-unittest.cc", + "compiler/backend/instruction-selector-unittest.h", + "compiler/backend/instruction-sequence-unittest.cc", + "compiler/backend/instruction-sequence-unittest.h", + "compiler/backend/instruction-unittest.cc", "compiler/branch-elimination-unittest.cc", "compiler/bytecode-analysis-unittest.cc", "compiler/checkpoint-elimination-unittest.cc", @@ -106,11 +109,6 @@ v8_source_set("unittests_sources") { "compiler/graph-trimmer-unittest.cc", "compiler/graph-unittest.cc", "compiler/graph-unittest.h", - "compiler/instruction-selector-unittest.cc", - "compiler/instruction-selector-unittest.h", - "compiler/instruction-sequence-unittest.cc", - "compiler/instruction-sequence-unittest.h", - "compiler/instruction-unittest.cc", "compiler/int64-lowering-unittest.cc", "compiler/js-call-reducer-unittest.cc", "compiler/js-create-lowering-unittest.cc", @@ -119,7 +117,6 @@ v8_source_set("unittests_sources") { "compiler/js-operator-unittest.cc", "compiler/js-typed-lowering-unittest.cc", "compiler/linkage-tail-call-unittest.cc", - "compiler/live-range-builder.h", "compiler/load-elimination-unittest.cc", "compiler/loop-peeling-unittest.cc", "compiler/machine-operator-reducer-unittest.cc", @@ -147,6 +144,7 @@ v8_source_set("unittests_sources") { "compiler/typer-unittest.cc", "compiler/value-numbering-reducer-unittest.cc", "compiler/zone-stats-unittest.cc", + "conversions-unittest.cc", "counters-unittest.cc", "detachable-vector-unittest.cc", "eh-frame-iterator-unittest.cc", @@ -186,11 +184,12 @@ v8_source_set("unittests_sources") { "libplatform/task-queue-unittest.cc", "libplatform/worker-thread-unittest.cc", "locked-queue-unittest.cc", + "microtask-queue-unittest.cc", "object-unittest.cc", - "objects/microtask-queue-unittest.cc", "parser/ast-value-unittest.cc", "parser/preparser-unittest.cc", "register-configuration-unittest.cc", + "regress/regress-crbug-938251-unittest.cc", "run-all-unittests.cc", "source-position-table-unittest.cc", "strings-storage-unittest.cc", @@ -199,6 +198,7 @@ v8_source_set("unittests_sources") { "test-utils.cc", "test-utils.h", "torque/earley-parser-unittest.cc", + "torque/torque-unittest.cc", "unicode-unittest.cc", "utils-unittest.cc", "value-serializer-unittest.cc", @@ -209,8 +209,8 @@ v8_source_set("unittests_sources") { "wasm/loop-assignment-analysis-unittest.cc", "wasm/module-decoder-unittest.cc", "wasm/streaming-decoder-unittest.cc", - "wasm/trap-handler-unittest.cc", "wasm/wasm-code-manager-unittest.cc", + "wasm/wasm-compiler-unittest.cc", "wasm/wasm-macro-gen-unittest.cc", "wasm/wasm-module-builder-unittest.cc", "wasm/wasm-opcodes-unittest.cc", @@ -258,6 +258,7 @@ v8_source_set("unittests_sources") { sources += [ "assembler/turbo-assembler-x64-unittest.cc", "compiler/x64/instruction-selector-x64-unittest.cc", + "wasm/trap-handler-x64-unittest.cc", ] } else if (v8_current_cpu == "ppc" || v8_current_cpu == "ppc64") { sources += [ @@ -271,6 +272,14 @@ v8_source_set("unittests_sources") { ] } + if (is_posix) { + sources += [ "wasm/trap-handler-posix-unittest.cc" ] + } + + if (is_win) { + sources += [ "wasm/trap-handler-win-unittest.cc" ] + } + configs = [ "../..:external_config", "../..:internal_config_base", diff --git a/deps/v8/test/unittests/api/isolate-unittest.cc b/deps/v8/test/unittests/api/isolate-unittest.cc index 8ddf8a29c8..10fa7bba22 100644 --- a/deps/v8/test/unittests/api/isolate-unittest.cc +++ b/deps/v8/test/unittests/api/isolate-unittest.cc @@ -74,8 +74,7 @@ using IncumbentContextTest = TestWithIsolate; // Check that Isolate::GetIncumbentContext() returns the correct one in basic // scenarios. -#if !defined(V8_USE_ADDRESS_SANITIZER) -TEST_F(IncumbentContextTest, MAYBE_Basic) { +TEST_F(IncumbentContextTest, Basic) { auto Str = [&](const char* s) { return String::NewFromUtf8(isolate(), s, NewStringType::kNormal) .ToLocalChecked(); @@ -137,6 +136,5 @@ TEST_F(IncumbentContextTest, MAYBE_Basic) { EXPECT_EQ(global_c, Run(context_a, "funcA()")); } } -#endif // !defined(V8_USE_ADDRESS_SANITIZER) } // namespace v8 diff --git a/deps/v8/test/unittests/asmjs/asm-types-unittest.cc b/deps/v8/test/unittests/asmjs/asm-types-unittest.cc index db5ed2ba52..afc1be0991 100644 --- a/deps/v8/test/unittests/asmjs/asm-types-unittest.cc +++ b/deps/v8/test/unittests/asmjs/asm-types-unittest.cc @@ -250,7 +250,7 @@ TEST_F(AsmTypeTest, IsExactly) { for (size_t ii = 0; ii < arraysize(test_types); ++ii) { for (size_t jj = 0; jj < arraysize(test_types); ++jj) { - EXPECT_EQ(ii == jj, test_types[ii]->IsExactly(test_types[jj])) + EXPECT_EQ(ii == jj, AsmType::IsExactly(test_types[ii], test_types[jj])) << test_types[ii]->Name() << ((ii == jj) ? " is not exactly " : " is exactly ") << test_types[jj]->Name(); diff --git a/deps/v8/test/unittests/asmjs/switch-logic-unittest.cc b/deps/v8/test/unittests/asmjs/switch-logic-unittest.cc deleted file mode 100644 index cc3fbb05cc..0000000000 --- a/deps/v8/test/unittests/asmjs/switch-logic-unittest.cc +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/asmjs/switch-logic.h" -#include "test/unittests/test-utils.h" - -namespace v8 { -namespace internal { -namespace wasm { -class SwitchLogicTest : public TestWithZone {}; - -void CheckNodeValues(CaseNode* node, int begin, int end) { - CHECK_EQ(node->begin, begin); - CHECK_EQ(node->end, end); -} - -TEST_F(SwitchLogicTest, Single_Table_Test) { - ZoneVector<int> values(zone()); - values.push_back(14); - values.push_back(12); - values.push_back(15); - values.push_back(19); - values.push_back(18); - values.push_back(16); - CaseNode* root = OrderCases(&values, zone()); - CHECK_NULL(root->left); - CHECK_NULL(root->right); - CheckNodeValues(root, 12, 19); -} - -TEST_F(SwitchLogicTest, Balanced_Tree_Test) { - ZoneVector<int> values(zone()); - values.push_back(5); - values.push_back(1); - values.push_back(6); - values.push_back(9); - values.push_back(-4); - CaseNode* root = OrderCases(&values, zone()); - CheckNodeValues(root, 5, 5); - CheckNodeValues(root->left, -4, -4); - CHECK_NULL(root->left->left); - CheckNodeValues(root->left->right, 1, 1); - CHECK_NULL(root->left->right->left); - CHECK_NULL(root->left->right->right); - CheckNodeValues(root->right, 6, 6); - CHECK_NULL(root->right->left); - CheckNodeValues(root->right->right, 9, 9); - CHECK_NULL(root->right->right->left); - CHECK_NULL(root->right->right->right); -} - -TEST_F(SwitchLogicTest, Hybrid_Test) { - ZoneVector<int> values(zone()); - values.push_back(1); - values.push_back(2); - values.push_back(3); - values.push_back(4); - values.push_back(7); - values.push_back(10); - values.push_back(11); - values.push_back(12); - values.push_back(13); - values.push_back(16); - CaseNode* root = OrderCases(&values, zone()); - CheckNodeValues(root, 7, 7); - CheckNodeValues(root->left, 1, 4); - CheckNodeValues(root->right, 10, 13); - CheckNodeValues(root->right->right, 16, 16); -} - -TEST_F(SwitchLogicTest, Single_Case) { - ZoneVector<int> values(zone()); - values.push_back(3); - CaseNode* root = OrderCases(&values, zone()); - CheckNodeValues(root, 3, 3); - CHECK_NULL(root->left); - CHECK_NULL(root->right); -} - -TEST_F(SwitchLogicTest, Empty_Case) { - ZoneVector<int> values(zone()); - CaseNode* root = OrderCases(&values, zone()); - CHECK_NULL(root); -} - -} // namespace wasm -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/unittests/assembler/turbo-assembler-arm-unittest.cc b/deps/v8/test/unittests/assembler/turbo-assembler-arm-unittest.cc index 056bd1c2c6..63c68ff48f 100644 --- a/deps/v8/test/unittests/assembler/turbo-assembler-arm-unittest.cc +++ b/deps/v8/test/unittests/assembler/turbo-assembler-arm-unittest.cc @@ -30,28 +30,26 @@ namespace internal { class TurboAssemblerTest : public TestWithIsolate {}; TEST_F(TurboAssemblerTest, TestHardAbort) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); __ Abort(AbortReason::kNoReason); CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, ERROR_MESSAGE("abort: no reason")); } TEST_F(TurboAssemblerTest, TestCheck) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); // Fail if the first parameter is 17. @@ -62,9 +60,9 @@ TEST_F(TurboAssemblerTest, TestCheck) { CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); f.Call(0); f.Call(18); diff --git a/deps/v8/test/unittests/assembler/turbo-assembler-arm64-unittest.cc b/deps/v8/test/unittests/assembler/turbo-assembler-arm64-unittest.cc index e354fb91d9..57e82ecde3 100644 --- a/deps/v8/test/unittests/assembler/turbo-assembler-arm64-unittest.cc +++ b/deps/v8/test/unittests/assembler/turbo-assembler-arm64-unittest.cc @@ -30,28 +30,26 @@ namespace internal { class TurboAssemblerTest : public TestWithIsolate {}; TEST_F(TurboAssemblerTest, TestHardAbort) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); __ Abort(AbortReason::kNoReason); CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, ERROR_MESSAGE("abort: no reason")); } TEST_F(TurboAssemblerTest, TestCheck) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); // Fail if the first parameter is 17. @@ -62,9 +60,9 @@ TEST_F(TurboAssemblerTest, TestCheck) { CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); f.Call(0); f.Call(18); diff --git a/deps/v8/test/unittests/assembler/turbo-assembler-ia32-unittest.cc b/deps/v8/test/unittests/assembler/turbo-assembler-ia32-unittest.cc index ba3634314f..3ef812e07a 100644 --- a/deps/v8/test/unittests/assembler/turbo-assembler-ia32-unittest.cc +++ b/deps/v8/test/unittests/assembler/turbo-assembler-ia32-unittest.cc @@ -17,27 +17,25 @@ namespace internal { // V8 library, create a context, or use any V8 objects. TEST(TurboAssemblerTest, TestHardAbort) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); __ Abort(AbortReason::kNoReason); CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); - auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer); + buffer->MakeExecutable(); + auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer->start()); ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason"); } TEST(TurboAssemblerTest, TestCheck) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); // Fail if the first parameter is 17. @@ -48,8 +46,8 @@ TEST(TurboAssemblerTest, TestCheck) { CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); - auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer); + buffer->MakeExecutable(); + auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer->start()); f.Call(0); f.Call(18); diff --git a/deps/v8/test/unittests/assembler/turbo-assembler-mips-unittest.cc b/deps/v8/test/unittests/assembler/turbo-assembler-mips-unittest.cc index abba0ff30b..6da112c5dd 100644 --- a/deps/v8/test/unittests/assembler/turbo-assembler-mips-unittest.cc +++ b/deps/v8/test/unittests/assembler/turbo-assembler-mips-unittest.cc @@ -21,28 +21,26 @@ namespace internal { class TurboAssemblerTest : public TestWithIsolate {}; TEST_F(TurboAssemblerTest, TestHardAbort) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); __ Abort(AbortReason::kNoReason); CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason"); } TEST_F(TurboAssemblerTest, TestCheck) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); // Fail if the first parameter (in {a0}) is 17. @@ -51,9 +49,9 @@ TEST_F(TurboAssemblerTest, TestCheck) { CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); f.Call(0); f.Call(18); diff --git a/deps/v8/test/unittests/assembler/turbo-assembler-mips64-unittest.cc b/deps/v8/test/unittests/assembler/turbo-assembler-mips64-unittest.cc index 8d8bc0756c..5b798b8e02 100644 --- a/deps/v8/test/unittests/assembler/turbo-assembler-mips64-unittest.cc +++ b/deps/v8/test/unittests/assembler/turbo-assembler-mips64-unittest.cc @@ -21,28 +21,26 @@ namespace internal { class TurboAssemblerTest : public TestWithIsolate {}; TEST_F(TurboAssemblerTest, TestHardAbort) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); __ Abort(AbortReason::kNoReason); CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason"); } TEST_F(TurboAssemblerTest, TestCheck) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); // Fail if the first parameter (in {a0}) is 17. @@ -51,9 +49,9 @@ TEST_F(TurboAssemblerTest, TestCheck) { CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); f.Call(0); f.Call(18); diff --git a/deps/v8/test/unittests/assembler/turbo-assembler-ppc-unittest.cc b/deps/v8/test/unittests/assembler/turbo-assembler-ppc-unittest.cc index dcc138fce1..24e2e71fd8 100644 --- a/deps/v8/test/unittests/assembler/turbo-assembler-ppc-unittest.cc +++ b/deps/v8/test/unittests/assembler/turbo-assembler-ppc-unittest.cc @@ -21,12 +21,9 @@ namespace internal { class TurboAssemblerTest : public TestWithIsolate {}; TEST_F(TurboAssemblerTest, TestHardAbort) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); - // Called from C - __ function_descriptor(); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); @@ -34,20 +31,17 @@ TEST_F(TurboAssemblerTest, TestHardAbort) { CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason"); } TEST_F(TurboAssemblerTest, TestCheck) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); - // Called from C - __ function_descriptor(); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); @@ -59,9 +53,9 @@ TEST_F(TurboAssemblerTest, TestCheck) { CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); f.Call(0); f.Call(18); diff --git a/deps/v8/test/unittests/assembler/turbo-assembler-s390-unittest.cc b/deps/v8/test/unittests/assembler/turbo-assembler-s390-unittest.cc index 7d45ec907f..f3f0a532d6 100644 --- a/deps/v8/test/unittests/assembler/turbo-assembler-s390-unittest.cc +++ b/deps/v8/test/unittests/assembler/turbo-assembler-s390-unittest.cc @@ -21,28 +21,26 @@ namespace internal { class TurboAssemblerTest : public TestWithIsolate {}; TEST_F(TurboAssemblerTest, TestHardAbort) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); __ Abort(AbortReason::kNoReason); CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason"); } TEST_F(TurboAssemblerTest, TestCheck) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); // Fail if the first parameter is 17. @@ -53,9 +51,9 @@ TEST_F(TurboAssemblerTest, TestCheck) { CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); + buffer->MakeExecutable(); // We need an isolate here to execute in the simulator. - auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer); + auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); f.Call(0); f.Call(18); diff --git a/deps/v8/test/unittests/assembler/turbo-assembler-x64-unittest.cc b/deps/v8/test/unittests/assembler/turbo-assembler-x64-unittest.cc index 060060c762..8142cbc274 100644 --- a/deps/v8/test/unittests/assembler/turbo-assembler-x64-unittest.cc +++ b/deps/v8/test/unittests/assembler/turbo-assembler-x64-unittest.cc @@ -17,27 +17,25 @@ namespace internal { // V8 library, create a context, or use any V8 objects. TEST(TurboAssemblerTest, TestHardAbort) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); __ Abort(AbortReason::kNoReason); CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); - auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer); + buffer->MakeExecutable(); + auto f = GeneratedCode<void>::FromBuffer(nullptr, buffer->start()); ASSERT_DEATH_IF_SUPPORTED({ f.Call(); }, "abort: no reason"); } TEST(TurboAssemblerTest, TestCheck) { - size_t allocated; - byte* buffer = AllocateAssemblerBuffer(&allocated); - TurboAssembler tasm(nullptr, AssemblerOptions{}, buffer, - static_cast<int>(allocated), CodeObjectRequired::kNo); + auto buffer = AllocateAssemblerBuffer(); + TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer->CreateView()); __ set_abort_hard(true); // Fail if the first parameter is 17. @@ -48,8 +46,8 @@ TEST(TurboAssemblerTest, TestCheck) { CodeDesc desc; tasm.GetCode(nullptr, &desc); - MakeAssemblerBufferExecutable(buffer, allocated); - auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer); + buffer->MakeExecutable(); + auto f = GeneratedCode<void, int>::FromBuffer(nullptr, buffer->start()); f.Call(0); f.Call(18); diff --git a/deps/v8/test/unittests/compiler-dispatcher/unoptimized-compile-job-unittest.cc b/deps/v8/test/unittests/background-compile-task-unittest.cc index e3d4ae078b..5bb6b68285 100644 --- a/deps/v8/test/unittests/compiler-dispatcher/unoptimized-compile-job-unittest.cc +++ b/deps/v8/test/unittests/background-compile-task-unittest.cc @@ -1,4 +1,4 @@ -// Copyright 2016 the V8 project authors. All rights reserved. +// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,13 +10,13 @@ #include "src/ast/scopes.h" #include "src/base/platform/semaphore.h" #include "src/base/template-utils.h" -#include "src/compiler-dispatcher/compiler-dispatcher-job.h" -#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" -#include "src/compiler-dispatcher/unoptimized-compile-job.h" +#include "src/compiler.h" #include "src/flags.h" #include "src/isolate-inl.h" +#include "src/objects/smi.h" #include "src/parsing/parse-info.h" -#include "src/parsing/preparsed-scope-data.h" +#include "src/parsing/parser.h" +#include "src/parsing/preparse-data.h" #include "src/v8.h" #include "test/unittests/test-helpers.h" #include "test/unittests/test-utils.h" @@ -25,14 +25,12 @@ namespace v8 { namespace internal { -class UnoptimizedCompileJobTest : public TestWithNativeContext { +class BackgroundCompileTaskTest : public TestWithNativeContext { public: - UnoptimizedCompileJobTest() - : tracer_(isolate()), allocator_(isolate()->allocator()) {} - ~UnoptimizedCompileJobTest() override = default; + BackgroundCompileTaskTest() : allocator_(isolate()->allocator()) {} + ~BackgroundCompileTaskTest() override = default; AccountingAllocator* allocator() { return allocator_; } - CompilerDispatcherTracer* tracer() { return &tracer_; } static void SetUpTestCase() { CHECK_NULL(save_flags_); @@ -47,7 +45,7 @@ class UnoptimizedCompileJobTest : public TestWithNativeContext { save_flags_ = nullptr; } - UnoptimizedCompileJob* NewUnoptimizedCompileJob( + BackgroundCompileTask* NewBackgroundCompileTask( Isolate* isolate, Handle<SharedFunctionInfo> shared, size_t stack_size = FLAG_stack_size) { std::unique_ptr<ParseInfo> outer_parse_info = @@ -66,82 +64,55 @@ class UnoptimizedCompileJobTest : public TestWithNativeContext { outer_parse_info->zone(), script_scope, FUNCTION_SCOPE); function_scope->set_start_position(shared->StartPosition()); function_scope->set_end_position(shared->EndPosition()); + std::vector<void*> buffer; + ScopedPtrList<Statement> statements(&buffer); const FunctionLiteral* function_literal = ast_node_factory.NewFunctionLiteral( - function_name, function_scope, nullptr, -1, -1, -1, + function_name, function_scope, statements, -1, -1, -1, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, FunctionLiteral::kShouldEagerCompile, shared->StartPosition(), true, shared->FunctionLiteralId(isolate), nullptr); - return new UnoptimizedCompileJob( - tracer(), allocator(), outer_parse_info.get(), function_name, - function_literal, + return new BackgroundCompileTask( + allocator(), outer_parse_info.get(), function_name, function_literal, isolate->counters()->worker_thread_runtime_call_stats(), isolate->counters()->compile_function_on_background(), FLAG_stack_size); } private: - CompilerDispatcherTracer tracer_; AccountingAllocator* allocator_; static SaveFlags* save_flags_; - DISALLOW_COPY_AND_ASSIGN(UnoptimizedCompileJobTest); + DISALLOW_COPY_AND_ASSIGN(BackgroundCompileTaskTest); }; -SaveFlags* UnoptimizedCompileJobTest::save_flags_ = nullptr; +SaveFlags* BackgroundCompileTaskTest::save_flags_ = nullptr; -#define ASSERT_JOB_STATUS(STATUS, JOB) ASSERT_EQ(STATUS, JOB->status()) - -TEST_F(UnoptimizedCompileJobTest, Construct) { - Handle<SharedFunctionInfo> shared = - test::CreateSharedFunctionInfo(isolate(), nullptr); - ASSERT_FALSE(shared->is_compiled()); - std::unique_ptr<UnoptimizedCompileJob> job( - NewUnoptimizedCompileJob(isolate(), shared)); -} - -TEST_F(UnoptimizedCompileJobTest, StateTransitions) { +TEST_F(BackgroundCompileTaskTest, Construct) { Handle<SharedFunctionInfo> shared = test::CreateSharedFunctionInfo(isolate(), nullptr); ASSERT_FALSE(shared->is_compiled()); - std::unique_ptr<UnoptimizedCompileJob> job( - NewUnoptimizedCompileJob(isolate(), shared)); - - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kInitial, job); - job->Compile(false); - ASSERT_FALSE(job->IsFailed()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kReadyToFinalize, job); - job->FinalizeOnMainThread(isolate(), shared); - ASSERT_FALSE(job->IsFailed()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kDone, job); - job->ResetOnMainThread(isolate()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kInitial, job); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); } -TEST_F(UnoptimizedCompileJobTest, SyntaxError) { +TEST_F(BackgroundCompileTaskTest, SyntaxError) { test::ScriptResource* script = new test::ScriptResource("^^^", strlen("^^^")); Handle<SharedFunctionInfo> shared = test::CreateSharedFunctionInfo(isolate(), script); - std::unique_ptr<UnoptimizedCompileJob> job( - NewUnoptimizedCompileJob(isolate(), shared)); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); - job->Compile(false); - ASSERT_FALSE(job->IsFailed()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kReadyToFinalize, job); - - job->FinalizeOnMainThread(isolate(), shared); - ASSERT_TRUE(job->IsFailed()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kFailed, job); + task->Run(); + ASSERT_FALSE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); ASSERT_TRUE(isolate()->has_pending_exception()); isolate()->clear_pending_exception(); - - job->ResetOnMainThread(isolate()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kInitial, job); } -TEST_F(UnoptimizedCompileJobTest, CompileAndRun) { +TEST_F(BackgroundCompileTaskTest, CompileAndRun) { const char raw_script[] = "function g() {\n" " f = function(a) {\n" @@ -156,21 +127,19 @@ TEST_F(UnoptimizedCompileJobTest, CompileAndRun) { Handle<JSFunction> f = RunJS<JSFunction>(script); Handle<SharedFunctionInfo> shared = handle(f->shared(), isolate()); ASSERT_FALSE(shared->is_compiled()); - std::unique_ptr<UnoptimizedCompileJob> job( - NewUnoptimizedCompileJob(isolate(), shared)); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); - job->Compile(false); - job->FinalizeOnMainThread(isolate(), shared); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kDone, job); + task->Run(); + ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); ASSERT_TRUE(shared->is_compiled()); - job->ResetOnMainThread(isolate()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kInitial, job); - Smi* value = Smi::cast(*RunJS("f(100);")); + Smi value = Smi::cast(*RunJS("f(100);")); ASSERT_TRUE(value == Smi::FromInt(160)); } -TEST_F(UnoptimizedCompileJobTest, CompileFailure) { +TEST_F(BackgroundCompileTaskTest, CompileFailure) { std::string raw_script("() { var a = "); for (int i = 0; i < 10000; i++) { // TODO(leszeks): Figure out a more "unit-test-y" way of forcing an analysis @@ -184,42 +153,35 @@ TEST_F(UnoptimizedCompileJobTest, CompileFailure) { new test::ScriptResource(raw_script.c_str(), strlen(raw_script.c_str())); Handle<SharedFunctionInfo> shared = test::CreateSharedFunctionInfo(isolate(), script); - std::unique_ptr<UnoptimizedCompileJob> job( - NewUnoptimizedCompileJob(isolate(), shared, 100)); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared, 100)); - job->Compile(false); - ASSERT_FALSE(job->IsFailed()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kReadyToFinalize, job); - - job->FinalizeOnMainThread(isolate(), shared); - ASSERT_TRUE(job->IsFailed()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kFailed, job); + task->Run(); + ASSERT_FALSE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); ASSERT_TRUE(isolate()->has_pending_exception()); isolate()->clear_pending_exception(); - job->ResetOnMainThread(isolate()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kInitial, job); } class CompileTask : public Task { public: - CompileTask(UnoptimizedCompileJob* job, base::Semaphore* semaphore) - : job_(job), semaphore_(semaphore) {} + CompileTask(BackgroundCompileTask* task, base::Semaphore* semaphore) + : task_(task), semaphore_(semaphore) {} ~CompileTask() override = default; void Run() override { - job_->Compile(true); - ASSERT_FALSE(job_->IsFailed()); + task_->Run(); semaphore_->Signal(); } private: - UnoptimizedCompileJob* job_; + BackgroundCompileTask* task_; base::Semaphore* semaphore_; DISALLOW_COPY_AND_ASSIGN(CompileTask); }; -TEST_F(UnoptimizedCompileJobTest, CompileOnBackgroundThread) { +TEST_F(BackgroundCompileTaskTest, CompileOnBackgroundThread) { const char* raw_script = "(a, b) {\n" " var c = a + b;\n" @@ -231,24 +193,20 @@ TEST_F(UnoptimizedCompileJobTest, CompileOnBackgroundThread) { new test::ScriptResource(raw_script, strlen(raw_script)); Handle<SharedFunctionInfo> shared = test::CreateSharedFunctionInfo(isolate(), script); - std::unique_ptr<UnoptimizedCompileJob> job( - NewUnoptimizedCompileJob(isolate(), shared)); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); base::Semaphore semaphore(0); - auto background_task = base::make_unique<CompileTask>(job.get(), &semaphore); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kInitial, job); + auto background_task = base::make_unique<CompileTask>(task.get(), &semaphore); V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(background_task)); semaphore.Wait(); - job->FinalizeOnMainThread(isolate(), shared); - ASSERT_FALSE(job->IsFailed()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kDone, job); - - job->ResetOnMainThread(isolate()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kInitial, job); + ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); + ASSERT_TRUE(shared->is_compiled()); } -TEST_F(UnoptimizedCompileJobTest, EagerInnerFunctions) { +TEST_F(BackgroundCompileTaskTest, EagerInnerFunctions) { const char raw_script[] = "function g() {\n" " f = function() {\n" @@ -264,25 +222,20 @@ TEST_F(UnoptimizedCompileJobTest, EagerInnerFunctions) { Handle<JSFunction> f = RunJS<JSFunction>(script); Handle<SharedFunctionInfo> shared = handle(f->shared(), isolate()); ASSERT_FALSE(shared->is_compiled()); - std::unique_ptr<UnoptimizedCompileJob> job( - NewUnoptimizedCompileJob(isolate(), shared)); - - job->Compile(false); - ASSERT_FALSE(job->IsFailed()); - job->FinalizeOnMainThread(isolate(), shared); - ASSERT_FALSE(job->IsFailed()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kDone, job); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); + + task->Run(); + ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); ASSERT_TRUE(shared->is_compiled()); Handle<JSFunction> e = RunJS<JSFunction>("f();"); ASSERT_TRUE(e->shared()->is_compiled()); - - job->ResetOnMainThread(isolate()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kInitial, job); } -TEST_F(UnoptimizedCompileJobTest, LazyInnerFunctions) { +TEST_F(BackgroundCompileTaskTest, LazyInnerFunctions) { const char raw_script[] = "function g() {\n" " f = function() {\n" @@ -297,25 +250,18 @@ TEST_F(UnoptimizedCompileJobTest, LazyInnerFunctions) { Handle<JSFunction> f = RunJS<JSFunction>(script); Handle<SharedFunctionInfo> shared = handle(f->shared(), isolate()); ASSERT_FALSE(shared->is_compiled()); - std::unique_ptr<UnoptimizedCompileJob> job( - NewUnoptimizedCompileJob(isolate(), shared)); - - job->Compile(false); - ASSERT_FALSE(job->IsFailed()); - job->FinalizeOnMainThread(isolate(), shared); - ASSERT_FALSE(job->IsFailed()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kDone, job); + std::unique_ptr<BackgroundCompileTask> task( + NewBackgroundCompileTask(isolate(), shared)); + + task->Run(); + ASSERT_TRUE(Compiler::FinalizeBackgroundCompileTask( + task.get(), shared, isolate(), Compiler::KEEP_EXCEPTION)); ASSERT_TRUE(shared->is_compiled()); Handle<JSFunction> e = RunJS<JSFunction>("f();"); ASSERT_FALSE(e->shared()->is_compiled()); - - job->ResetOnMainThread(isolate()); - ASSERT_JOB_STATUS(CompilerDispatcherJob::Status::kInitial, job); } -#undef ASSERT_JOB_STATUS - } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/base/atomic-utils-unittest.cc b/deps/v8/test/unittests/base/atomic-utils-unittest.cc index 1d8e71c9aa..442257eff8 100644 --- a/deps/v8/test/unittests/base/atomic-utils-unittest.cc +++ b/deps/v8/test/unittests/base/atomic-utils-unittest.cc @@ -12,11 +12,7 @@ namespace v8 { namespace base { namespace { -enum TestFlag : base::AtomicWord { - kA, - kB, - kC, -}; +enum TestFlag : base::AtomicWord { kA, kB, kC }; } // namespace @@ -26,15 +22,6 @@ TEST(AtomicValue, Initial) { EXPECT_EQ(TestFlag::kA, a.Value()); } - -TEST(AtomicValue, TrySetValue) { - AtomicValue<TestFlag> a(kA); - EXPECT_FALSE(a.TrySetValue(kB, kC)); - EXPECT_TRUE(a.TrySetValue(kA, kC)); - EXPECT_EQ(TestFlag::kC, a.Value()); -} - - TEST(AtomicValue, SetValue) { AtomicValue<TestFlag> a(kB); a.SetValue(kC); @@ -48,9 +35,6 @@ TEST(AtomicValue, WithVoidStar) { EXPECT_EQ(nullptr, a.Value()); a.SetValue(&a); EXPECT_EQ(&a, a.Value()); - EXPECT_FALSE(a.TrySetValue(nullptr, &dummy)); - EXPECT_TRUE(a.TrySetValue(&a, &dummy)); - EXPECT_EQ(&dummy, a.Value()); } TEST(AsAtomic8, CompareAndSwap_Sequential) { diff --git a/deps/v8/test/unittests/base/ieee754-unittest.cc b/deps/v8/test/unittests/base/ieee754-unittest.cc index 2110b63976..56f1812a9e 100644 --- a/deps/v8/test/unittests/base/ieee754-unittest.cc +++ b/deps/v8/test/unittests/base/ieee754-unittest.cc @@ -6,6 +6,7 @@ #include "src/base/ieee754.h" #include "src/base/macros.h" +#include "src/base/overflowing-math.h" #include "testing/gmock-support.h" #include "testing/gtest-support.h" @@ -314,8 +315,8 @@ TEST(Ieee754, Sin) { EXPECT_THAT(sin(-kInfinity), IsNaN()); // Tests for sin for |x| < pi/4 - EXPECT_EQ(-kInfinity, 1 / sin(-0.0)); - EXPECT_EQ(kInfinity, 1 / sin(0.0)); + EXPECT_EQ(-kInfinity, Divide(1.0, sin(-0.0))); + EXPECT_EQ(kInfinity, Divide(1.0, sin(0.0))); // sin(x) = x for x < 2^-27 EXPECT_EQ(2.3283064365386963e-10, sin(2.3283064365386963e-10)); EXPECT_EQ(-2.3283064365386963e-10, sin(-2.3283064365386963e-10)); @@ -361,8 +362,8 @@ TEST(Ieee754, Tan) { EXPECT_THAT(tan(-kInfinity), IsNaN()); // Tests for tan for |x| < pi/4 - EXPECT_EQ(kInfinity, 1 / tan(0.0)); - EXPECT_EQ(-kInfinity, 1 / tan(-0.0)); + EXPECT_EQ(kInfinity, Divide(1.0, tan(0.0))); + EXPECT_EQ(-kInfinity, Divide(1.0, tan(-0.0))); // tan(x) = x for |x| < 2^-28 EXPECT_EQ(2.3283064365386963e-10, tan(2.3283064365386963e-10)); EXPECT_EQ(-2.3283064365386963e-10, tan(-2.3283064365386963e-10)); diff --git a/deps/v8/test/unittests/base/logging-unittest.cc b/deps/v8/test/unittests/base/logging-unittest.cc index d73845c373..b720331c9e 100644 --- a/deps/v8/test/unittests/base/logging-unittest.cc +++ b/deps/v8/test/unittests/base/logging-unittest.cc @@ -6,6 +6,7 @@ #include "src/base/logging.h" #include "src/objects.h" +#include "src/objects/smi.h" #include "testing/gtest-support.h" namespace v8 { @@ -64,7 +65,7 @@ TEST(LoggingTest, CompareSignedMismatch) { TEST(LoggingTest, CompareAgainstStaticConstPointer) { // These used to produce link errors before http://crrev.com/2524093002. - CHECK_FAIL(EQ, v8::internal::Smi::kZero, v8::internal::Smi::FromInt(17)); + CHECK_FAIL(EQ, v8::internal::Smi::zero(), v8::internal::Smi::FromInt(17)); CHECK_SUCCEED(GT, 0, v8::internal::Smi::kMinValue); } diff --git a/deps/v8/test/unittests/base/platform/condition-variable-unittest.cc b/deps/v8/test/unittests/base/platform/condition-variable-unittest.cc index b32863f4b2..6206569433 100644 --- a/deps/v8/test/unittests/base/platform/condition-variable-unittest.cc +++ b/deps/v8/test/unittests/base/platform/condition-variable-unittest.cc @@ -16,7 +16,7 @@ TEST(ConditionVariable, WaitForAfterNofityOnSameThread) { Mutex mutex; ConditionVariable cv; - LockGuard<Mutex> lock_guard(&mutex); + MutexGuard lock_guard(&mutex); cv.NotifyOne(); EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n))); @@ -37,7 +37,7 @@ class ThreadWithMutexAndConditionVariable final : public Thread { finished_(false) {} void Run() override { - LockGuard<Mutex> lock_guard(&mutex_); + MutexGuard lock_guard(&mutex_); running_ = true; cv_.NotifyOne(); while (running_) { @@ -61,7 +61,7 @@ TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) { ThreadWithMutexAndConditionVariable threads[kThreadCount]; for (int n = 0; n < kThreadCount; ++n) { - LockGuard<Mutex> lock_guard(&threads[n].mutex_); + MutexGuard lock_guard(&threads[n].mutex_); EXPECT_FALSE(threads[n].running_); EXPECT_FALSE(threads[n].finished_); threads[n].Start(); @@ -72,13 +72,13 @@ TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) { } for (int n = kThreadCount - 1; n >= 0; --n) { - LockGuard<Mutex> lock_guard(&threads[n].mutex_); + MutexGuard lock_guard(&threads[n].mutex_); EXPECT_TRUE(threads[n].running_); EXPECT_FALSE(threads[n].finished_); } for (int n = 0; n < kThreadCount; ++n) { - LockGuard<Mutex> lock_guard(&threads[n].mutex_); + MutexGuard lock_guard(&threads[n].mutex_); EXPECT_TRUE(threads[n].running_); EXPECT_FALSE(threads[n].finished_); // Tell the nth thread to quit. @@ -88,7 +88,7 @@ TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) { for (int n = kThreadCount - 1; n >= 0; --n) { // Wait for nth thread to quit. - LockGuard<Mutex> lock_guard(&threads[n].mutex_); + MutexGuard lock_guard(&threads[n].mutex_); while (!threads[n].finished_) { threads[n].cv_.Wait(&threads[n].mutex_); } @@ -98,7 +98,7 @@ TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) { for (int n = 0; n < kThreadCount; ++n) { threads[n].Join(); - LockGuard<Mutex> lock_guard(&threads[n].mutex_); + MutexGuard lock_guard(&threads[n].mutex_); EXPECT_FALSE(threads[n].running_); EXPECT_TRUE(threads[n].finished_); } @@ -117,7 +117,7 @@ class ThreadWithSharedMutexAndConditionVariable final : public Thread { mutex_(nullptr) {} void Run() override { - LockGuard<Mutex> lock_guard(mutex_); + MutexGuard lock_guard(mutex_); running_ = true; cv_->NotifyAll(); while (running_) { @@ -149,7 +149,7 @@ TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) { // Start all threads. { - LockGuard<Mutex> lock_guard(&mutex); + MutexGuard lock_guard(&mutex); for (int n = 0; n < kThreadCount; ++n) { EXPECT_FALSE(threads[n].running_); EXPECT_FALSE(threads[n].finished_); @@ -159,7 +159,7 @@ TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) { // Wait for all threads to start. { - LockGuard<Mutex> lock_guard(&mutex); + MutexGuard lock_guard(&mutex); for (int n = kThreadCount - 1; n >= 0; --n) { while (!threads[n].running_) { cv.Wait(&mutex); @@ -169,7 +169,7 @@ TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) { // Make sure that all threads are running. { - LockGuard<Mutex> lock_guard(&mutex); + MutexGuard lock_guard(&mutex); for (int n = 0; n < kThreadCount; ++n) { EXPECT_TRUE(threads[n].running_); EXPECT_FALSE(threads[n].finished_); @@ -178,7 +178,7 @@ TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) { // Tell all threads to quit. { - LockGuard<Mutex> lock_guard(&mutex); + MutexGuard lock_guard(&mutex); for (int n = kThreadCount - 1; n >= 0; --n) { EXPECT_TRUE(threads[n].running_); EXPECT_FALSE(threads[n].finished_); @@ -190,7 +190,7 @@ TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) { // Wait for all threads to quit. { - LockGuard<Mutex> lock_guard(&mutex); + MutexGuard lock_guard(&mutex); for (int n = 0; n < kThreadCount; ++n) { while (!threads[n].finished_) { cv.Wait(&mutex); @@ -200,7 +200,7 @@ TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) { // Make sure all threads are finished. { - LockGuard<Mutex> lock_guard(&mutex); + MutexGuard lock_guard(&mutex); for (int n = kThreadCount - 1; n >= 0; --n) { EXPECT_FALSE(threads[n].running_); EXPECT_TRUE(threads[n].finished_); @@ -234,7 +234,7 @@ class LoopIncrementThread final : public Thread { void Run() override { int last_count = -1; while (true) { - LockGuard<Mutex> lock_guard(mutex_); + MutexGuard lock_guard(mutex_); int count = *counter_; while (count % thread_count_ != rem_ && count < limit_) { cv_->Wait(mutex_); diff --git a/deps/v8/test/unittests/base/platform/mutex-unittest.cc b/deps/v8/test/unittests/base/platform/mutex-unittest.cc index 5af5efb5a9..7eb3973e51 100644 --- a/deps/v8/test/unittests/base/platform/mutex-unittest.cc +++ b/deps/v8/test/unittests/base/platform/mutex-unittest.cc @@ -11,8 +11,8 @@ namespace base { TEST(Mutex, LockGuardMutex) { Mutex mutex; - { LockGuard<Mutex> lock_guard(&mutex); } - { LockGuard<Mutex> lock_guard(&mutex); } + { MutexGuard lock_guard(&mutex); } + { MutexGuard lock_guard(&mutex); } } @@ -28,8 +28,8 @@ TEST(Mutex, LockGuardRecursiveMutex) { TEST(Mutex, LockGuardLazyMutex) { LazyMutex lazy_mutex = LAZY_MUTEX_INITIALIZER; - { LockGuard<Mutex> lock_guard(lazy_mutex.Pointer()); } - { LockGuard<Mutex> lock_guard(lazy_mutex.Pointer()); } + { MutexGuard lock_guard(lazy_mutex.Pointer()); } + { MutexGuard lock_guard(lazy_mutex.Pointer()); } } diff --git a/deps/v8/test/unittests/base/threaded-list-unittest.cc b/deps/v8/test/unittests/base/threaded-list-unittest.cc index 96a730370b..effe9b08f7 100644 --- a/deps/v8/test/unittests/base/threaded-list-unittest.cc +++ b/deps/v8/test/unittests/base/threaded-list-unittest.cc @@ -20,6 +20,10 @@ struct ThreadedListTestNode { ThreadedListTestNode* next_; struct OtherTraits { + static ThreadedListTestNode** start(ThreadedListTestNode** h) { return h; } + static ThreadedListTestNode* const* start(ThreadedListTestNode* const* h) { + return h; + } static ThreadedListTestNode** next(ThreadedListTestNode* t) { return t->other_next(); } @@ -134,16 +138,6 @@ TEST_F(ThreadedListTest, AddFront) { CHECK_EQ(list.first(), &new_node); } -TEST_F(ThreadedListTest, ReinitializeHead) { - CHECK_EQ(list.LengthForTest(), 5); - CHECK_NE(extra_test_list.first(), list.first()); - list.ReinitializeHead(&extra_test_node_0); - list.Verify(); - CHECK_EQ(extra_test_list.first(), list.first()); - CHECK_EQ(extra_test_list.end(), list.end()); - CHECK_EQ(extra_test_list.LengthForTest(), 3); -} - TEST_F(ThreadedListTest, DropHead) { CHECK_EQ(extra_test_list.LengthForTest(), 3); CHECK_EQ(extra_test_list.first(), &extra_test_node_0); @@ -166,6 +160,23 @@ TEST_F(ThreadedListTest, Append) { CHECK_EQ(list.end(), initial_extra_list_end); } +TEST_F(ThreadedListTest, AppendOutOfScope) { + ThreadedListTestNode local_extra_test_node_0; + CHECK_EQ(list.LengthForTest(), 5); + { + ThreadedList<ThreadedListTestNode, ThreadedListTestNode::OtherTraits> + scoped_extra_test_list; + + list.Append(std::move(scoped_extra_test_list)); + } + list.Add(&local_extra_test_node_0); + + list.Verify(); + CHECK_EQ(list.LengthForTest(), 6); + CHECK_EQ(list.AtForTest(4), &nodes[4]); + CHECK_EQ(list.AtForTest(5), &local_extra_test_node_0); +} + TEST_F(ThreadedListTest, Prepend) { CHECK_EQ(list.LengthForTest(), 5); list.Prepend(std::move(extra_test_list)); diff --git a/deps/v8/test/unittests/cancelable-tasks-unittest.cc b/deps/v8/test/unittests/cancelable-tasks-unittest.cc index 97ac4d4b7d..05048136aa 100644 --- a/deps/v8/test/unittests/cancelable-tasks-unittest.cc +++ b/deps/v8/test/unittests/cancelable-tasks-unittest.cc @@ -5,258 +5,262 @@ #include "src/base/atomicops.h" #include "src/base/platform/platform.h" #include "src/cancelable-task.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" - namespace v8 { namespace internal { namespace { +using ResultType = std::atomic<CancelableTaskManager::Id>; + +class CancelableTaskManagerTest; + class TestTask : public Task, public Cancelable { public: - enum Mode { kDoNothing, kWaitTillCanceledAgain, kCheckNotRun }; + enum Mode { kDoNothing, kWaitTillCancelTriggered, kCheckNotRun }; - TestTask(CancelableTaskManager* parent, base::AtomicWord* result, - Mode mode = kDoNothing) - : Cancelable(parent), result_(result), mode_(mode) {} + TestTask(CancelableTaskManagerTest* test, ResultType* result, Mode mode); - // Task overrides. - void Run() final { - if (TryRun()) { - RunInternal(); - } - } + // Task override. + void Run() final; private: - void RunInternal() { - base::Release_Store(result_, id()); - - switch (mode_) { - case kWaitTillCanceledAgain: - // Simple busy wait until the main thread tried to cancel. - while (CancelAttempts() == 0) { - } - break; - case kCheckNotRun: - // Check that we never execute {RunInternal}. - EXPECT_TRUE(false); - break; - default: - break; - } - } - - base::AtomicWord* result_; - Mode mode_; + ResultType* const result_; + const Mode mode_; + CancelableTaskManagerTest* const test_; }; - class SequentialRunner { public: - explicit SequentialRunner(TestTask* task) : task_(task) {} + explicit SequentialRunner(std::unique_ptr<TestTask> task) + : task_(std::move(task)), task_id_(task_->id()) {} void Run() { task_->Run(); - delete task_; + task_.reset(); } + CancelableTaskManager::Id task_id() const { return task_id_; } + private: - TestTask* task_; + std::unique_ptr<TestTask> task_; + const CancelableTaskManager::Id task_id_; }; - class ThreadedRunner final : public base::Thread { public: - explicit ThreadedRunner(TestTask* task) - : Thread(Options("runner thread")), task_(task) {} + explicit ThreadedRunner(std::unique_ptr<TestTask> task) + : Thread(Options("runner thread")), + task_(std::move(task)), + task_id_(task_->id()) {} void Run() override { task_->Run(); - delete task_; + task_.reset(); } + CancelableTaskManager::Id task_id() const { return task_id_; } + private: - TestTask* task_; + std::unique_ptr<TestTask> task_; + const CancelableTaskManager::Id task_id_; }; +class CancelableTaskManagerTest : public ::testing::Test { + public: + CancelableTaskManager* manager() { return &manager_; } -typedef base::AtomicWord ResultType; + std::unique_ptr<TestTask> NewTask( + ResultType* result, TestTask::Mode mode = TestTask::kDoNothing) { + return base::make_unique<TestTask>(this, result, mode); + } + void CancelAndWait() { + cancel_triggered_.store(true); + manager_.CancelAndWait(); + } -intptr_t GetValue(ResultType* result) { return base::Acquire_Load(result); } + TryAbortResult TryAbortAll() { + cancel_triggered_.store(true); + return manager_.TryAbortAll(); + } -} // namespace + bool cancel_triggered() const { return cancel_triggered_.load(); } + private: + CancelableTaskManager manager_; + std::atomic<bool> cancel_triggered_{false}; +}; -TEST(CancelableTask, EmptyCancelableTaskManager) { - CancelableTaskManager manager; - manager.CancelAndWait(); +TestTask::TestTask(CancelableTaskManagerTest* test, ResultType* result, + Mode mode) + : Cancelable(test->manager()), result_(result), mode_(mode), test_(test) {} + +void TestTask::Run() { + if (!TryRun()) return; + + result_->store(id()); + + switch (mode_) { + case kWaitTillCancelTriggered: + // Simple busy wait until the main thread tried to cancel. + while (!test_->cancel_triggered()) { + } + break; + case kCheckNotRun: + // Check that we never execute {RunInternal}. + EXPECT_TRUE(false); + break; + default: + break; + } } +} // namespace -TEST(CancelableTask, SequentialCancelAndWait) { - CancelableTaskManager manager; - ResultType result1 = 0; - SequentialRunner runner1( - new TestTask(&manager, &result1, TestTask::kCheckNotRun)); - EXPECT_EQ(GetValue(&result1), 0); - manager.CancelAndWait(); - EXPECT_EQ(GetValue(&result1), 0); - runner1.Run(); // Run to avoid leaking the Task. - EXPECT_EQ(GetValue(&result1), 0); +TEST_F(CancelableTaskManagerTest, EmptyCancelableTaskManager) { + CancelAndWait(); } - -TEST(CancelableTask, SequentialMultipleTasks) { - CancelableTaskManager manager; - ResultType result1 = 0; - ResultType result2 = 0; - TestTask* task1 = new TestTask(&manager, &result1); - TestTask* task2 = new TestTask(&manager, &result2); - SequentialRunner runner1(task1); - SequentialRunner runner2(task2); - EXPECT_EQ(task1->id(), 1u); - EXPECT_EQ(task2->id(), 2u); - - EXPECT_EQ(GetValue(&result1), 0); - runner1.Run(); // Don't touch task1 after running it. - EXPECT_EQ(GetValue(&result1), 1); - - EXPECT_EQ(GetValue(&result2), 0); - runner2.Run(); // Don't touch task2 after running it. - EXPECT_EQ(GetValue(&result2), 2); - - manager.CancelAndWait(); - EXPECT_FALSE(manager.TryAbort(1)); - EXPECT_FALSE(manager.TryAbort(2)); +TEST_F(CancelableTaskManagerTest, SequentialCancelAndWait) { + ResultType result1{0}; + SequentialRunner runner1(NewTask(&result1, TestTask::kCheckNotRun)); + EXPECT_EQ(0u, result1); + CancelAndWait(); + EXPECT_EQ(0u, result1); + runner1.Run(); + EXPECT_EQ(0u, result1); } +TEST_F(CancelableTaskManagerTest, SequentialMultipleTasks) { + ResultType result1{0}; + ResultType result2{0}; + SequentialRunner runner1(NewTask(&result1)); + SequentialRunner runner2(NewTask(&result2)); + EXPECT_EQ(1u, runner1.task_id()); + EXPECT_EQ(2u, runner2.task_id()); + + EXPECT_EQ(0u, result1); + runner1.Run(); + EXPECT_EQ(1u, result1); + + EXPECT_EQ(0u, result2); + runner2.Run(); + EXPECT_EQ(2u, result2); + + CancelAndWait(); + EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(1)); + EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(2)); +} -TEST(CancelableTask, ThreadedMultipleTasksStarted) { - CancelableTaskManager manager; - ResultType result1 = 0; - ResultType result2 = 0; - TestTask* task1 = - new TestTask(&manager, &result1, TestTask::kWaitTillCanceledAgain); - TestTask* task2 = - new TestTask(&manager, &result2, TestTask::kWaitTillCanceledAgain); - ThreadedRunner runner1(task1); - ThreadedRunner runner2(task2); +TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksStarted) { + ResultType result1{0}; + ResultType result2{0}; + ThreadedRunner runner1(NewTask(&result1, TestTask::kWaitTillCancelTriggered)); + ThreadedRunner runner2(NewTask(&result2, TestTask::kWaitTillCancelTriggered)); runner1.Start(); runner2.Start(); // Busy wait on result to make sure both tasks are done. - while ((GetValue(&result1) == 0) || (GetValue(&result2) == 0)) { + while (result1.load() == 0 || result2.load() == 0) { } - manager.CancelAndWait(); + CancelAndWait(); runner1.Join(); runner2.Join(); - EXPECT_EQ(GetValue(&result1), 1); - EXPECT_EQ(GetValue(&result2), 2); + EXPECT_EQ(1u, result1); + EXPECT_EQ(2u, result2); } - -TEST(CancelableTask, ThreadedMultipleTasksNotRun) { - CancelableTaskManager manager; - ResultType result1 = 0; - ResultType result2 = 0; - TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun); - TestTask* task2 = new TestTask(&manager, &result2, TestTask::kCheckNotRun); - ThreadedRunner runner1(task1); - ThreadedRunner runner2(task2); - manager.CancelAndWait(); +TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksNotRun) { + ResultType result1{0}; + ResultType result2{0}; + ThreadedRunner runner1(NewTask(&result1, TestTask::kCheckNotRun)); + ThreadedRunner runner2(NewTask(&result2, TestTask::kCheckNotRun)); + CancelAndWait(); // Tasks are canceled, hence the runner will bail out and not update result. runner1.Start(); runner2.Start(); runner1.Join(); runner2.Join(); - EXPECT_EQ(GetValue(&result1), 0); - EXPECT_EQ(GetValue(&result2), 0); + EXPECT_EQ(0u, result1); + EXPECT_EQ(0u, result2); } - -TEST(CancelableTask, RemoveBeforeCancelAndWait) { - CancelableTaskManager manager; - ResultType result1 = 0; - TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun); - ThreadedRunner runner1(task1); - CancelableTaskManager::Id id = task1->id(); - EXPECT_EQ(id, 1u); - EXPECT_TRUE(manager.TryAbort(id)); +TEST_F(CancelableTaskManagerTest, RemoveBeforeCancelAndWait) { + ResultType result1{0}; + ThreadedRunner runner1(NewTask(&result1, TestTask::kCheckNotRun)); + CancelableTaskManager::Id id = runner1.task_id(); + EXPECT_EQ(1u, id); + EXPECT_EQ(TryAbortResult::kTaskAborted, manager()->TryAbort(id)); runner1.Start(); runner1.Join(); - manager.CancelAndWait(); - EXPECT_EQ(GetValue(&result1), 0); + CancelAndWait(); + EXPECT_EQ(0u, result1); } - -TEST(CancelableTask, RemoveAfterCancelAndWait) { - CancelableTaskManager manager; - ResultType result1 = 0; - TestTask* task1 = new TestTask(&manager, &result1); - ThreadedRunner runner1(task1); - CancelableTaskManager::Id id = task1->id(); - EXPECT_EQ(id, 1u); +TEST_F(CancelableTaskManagerTest, RemoveAfterCancelAndWait) { + ResultType result1{0}; + ThreadedRunner runner1(NewTask(&result1)); + CancelableTaskManager::Id id = runner1.task_id(); + EXPECT_EQ(1u, id); runner1.Start(); runner1.Join(); - manager.CancelAndWait(); - EXPECT_FALSE(manager.TryAbort(id)); - EXPECT_EQ(GetValue(&result1), 1); + CancelAndWait(); + EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(id)); + EXPECT_EQ(1u, result1); } - -TEST(CancelableTask, RemoveUnmanagedId) { - CancelableTaskManager manager; - EXPECT_FALSE(manager.TryAbort(1)); - EXPECT_FALSE(manager.TryAbort(2)); - manager.CancelAndWait(); - EXPECT_FALSE(manager.TryAbort(1)); - EXPECT_FALSE(manager.TryAbort(3)); +TEST_F(CancelableTaskManagerTest, RemoveUnmanagedId) { + EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(1)); + EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(2)); + CancelAndWait(); + EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(1)); + EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(3)); } -TEST(CancelableTask, EmptyTryAbortAll) { - CancelableTaskManager manager; - EXPECT_EQ(manager.TryAbortAll(), CancelableTaskManager::kTaskRemoved); +TEST_F(CancelableTaskManagerTest, EmptyTryAbortAll) { + EXPECT_EQ(TryAbortResult::kTaskRemoved, TryAbortAll()); + CancelAndWait(); } -TEST(CancelableTask, ThreadedMultipleTasksNotRunTryAbortAll) { - CancelableTaskManager manager; - ResultType result1 = 0; - ResultType result2 = 0; - TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun); - TestTask* task2 = new TestTask(&manager, &result2, TestTask::kCheckNotRun); - ThreadedRunner runner1(task1); - ThreadedRunner runner2(task2); - EXPECT_EQ(manager.TryAbortAll(), CancelableTaskManager::kTaskAborted); +TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksNotRunTryAbortAll) { + ResultType result1{0}; + ResultType result2{0}; + ThreadedRunner runner1(NewTask(&result1, TestTask::kCheckNotRun)); + ThreadedRunner runner2(NewTask(&result2, TestTask::kCheckNotRun)); + EXPECT_EQ(TryAbortResult::kTaskAborted, TryAbortAll()); // Tasks are canceled, hence the runner will bail out and not update result. runner1.Start(); runner2.Start(); runner1.Join(); runner2.Join(); - EXPECT_EQ(GetValue(&result1), 0); - EXPECT_EQ(GetValue(&result2), 0); + EXPECT_EQ(0u, result1); + EXPECT_EQ(0u, result2); + CancelAndWait(); } -TEST(CancelableTask, ThreadedMultipleTasksStartedTryAbortAll) { - CancelableTaskManager manager; - ResultType result1 = 0; - ResultType result2 = 0; - TestTask* task1 = - new TestTask(&manager, &result1, TestTask::kWaitTillCanceledAgain); - TestTask* task2 = - new TestTask(&manager, &result2, TestTask::kWaitTillCanceledAgain); - ThreadedRunner runner1(task1); - ThreadedRunner runner2(task2); +TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksStartedTryAbortAll) { + ResultType result1{0}; + ResultType result2{0}; + ThreadedRunner runner1(NewTask(&result1, TestTask::kWaitTillCancelTriggered)); + ThreadedRunner runner2(NewTask(&result2, TestTask::kWaitTillCancelTriggered)); runner1.Start(); // Busy wait on result to make sure task1 is done. - while (GetValue(&result1) == 0) { + while (result1.load() == 0) { } - EXPECT_EQ(manager.TryAbortAll(), CancelableTaskManager::kTaskRunning); + // If the task saw that we triggered the cancel and finished *before* the + // actual cancel happened, we get {kTaskAborted}. Otherwise, we get + // {kTaskRunning}. + EXPECT_THAT(TryAbortAll(), + testing::AnyOf(testing::Eq(TryAbortResult::kTaskAborted), + testing::Eq(TryAbortResult::kTaskRunning))); runner2.Start(); runner1.Join(); runner2.Join(); - EXPECT_EQ(GetValue(&result1), 1); - EXPECT_EQ(GetValue(&result2), 0); + EXPECT_EQ(1u, result1); + EXPECT_EQ(0u, result2); + CancelAndWait(); } } // namespace internal diff --git a/deps/v8/test/unittests/char-predicates-unittest.cc b/deps/v8/test/unittests/char-predicates-unittest.cc index 3c6cf5d6a6..85c550a7e2 100644 --- a/deps/v8/test/unittests/char-predicates-unittest.cc +++ b/deps/v8/test/unittests/char-predicates-unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "src/char-predicates.h" +#include "src/char-predicates-inl.h" #include "src/unicode.h" #include "testing/gtest/include/gtest/gtest.h" @@ -10,122 +11,122 @@ namespace v8 { namespace internal { TEST(CharPredicatesTest, WhiteSpace) { - EXPECT_TRUE(WhiteSpace::Is(0x0009)); - EXPECT_TRUE(WhiteSpace::Is(0x000B)); - EXPECT_TRUE(WhiteSpace::Is(0x000C)); - EXPECT_TRUE(WhiteSpace::Is(' ')); - EXPECT_TRUE(WhiteSpace::Is(0x00A0)); - EXPECT_TRUE(WhiteSpace::Is(0x1680)); - EXPECT_TRUE(WhiteSpace::Is(0x2000)); - EXPECT_TRUE(WhiteSpace::Is(0x2007)); - EXPECT_TRUE(WhiteSpace::Is(0x202F)); - EXPECT_TRUE(WhiteSpace::Is(0x205F)); - EXPECT_TRUE(WhiteSpace::Is(0x3000)); - EXPECT_TRUE(WhiteSpace::Is(0xFEFF)); - EXPECT_FALSE(WhiteSpace::Is(0x180E)); + EXPECT_TRUE(IsWhiteSpace(0x0009)); + EXPECT_TRUE(IsWhiteSpace(0x000B)); + EXPECT_TRUE(IsWhiteSpace(0x000C)); + EXPECT_TRUE(IsWhiteSpace(' ')); + EXPECT_TRUE(IsWhiteSpace(0x00A0)); + EXPECT_TRUE(IsWhiteSpace(0x1680)); + EXPECT_TRUE(IsWhiteSpace(0x2000)); + EXPECT_TRUE(IsWhiteSpace(0x2007)); + EXPECT_TRUE(IsWhiteSpace(0x202F)); + EXPECT_TRUE(IsWhiteSpace(0x205F)); + EXPECT_TRUE(IsWhiteSpace(0x3000)); + EXPECT_TRUE(IsWhiteSpace(0xFEFF)); + EXPECT_FALSE(IsWhiteSpace(0x180E)); } TEST(CharPredicatesTest, WhiteSpaceOrLineTerminator) { - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x0009)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000B)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000C)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(' ')); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x00A0)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x1680)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x2000)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x2007)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x202F)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x205F)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0xFEFF)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x0009)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x000B)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x000C)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(' ')); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x00A0)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x1680)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x2000)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x2007)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x202F)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x205F)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0xFEFF)); // Line terminators - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000A)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000D)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x2028)); - EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x2029)); - EXPECT_FALSE(WhiteSpaceOrLineTerminator::Is(0x180E)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x000A)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x000D)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x2028)); + EXPECT_TRUE(IsWhiteSpaceOrLineTerminator(0x2029)); + EXPECT_FALSE(IsWhiteSpaceOrLineTerminator(0x180E)); } TEST(CharPredicatesTest, IdentifierStart) { - EXPECT_TRUE(IdentifierStart::Is('$')); - EXPECT_TRUE(IdentifierStart::Is('_')); - EXPECT_TRUE(IdentifierStart::Is('\\')); + EXPECT_TRUE(IsIdentifierStart('$')); + EXPECT_TRUE(IsIdentifierStart('_')); + EXPECT_TRUE(IsIdentifierStart('\\')); // http://www.unicode.org/reports/tr31/ // curl http://www.unicode.org/Public/UCD/latest/ucd/PropList.txt | // grep 'Other_ID_Start' // Other_ID_Start - EXPECT_TRUE(IdentifierStart::Is(0x1885)); - EXPECT_TRUE(IdentifierStart::Is(0x1886)); - EXPECT_TRUE(IdentifierStart::Is(0x2118)); - EXPECT_TRUE(IdentifierStart::Is(0x212E)); - EXPECT_TRUE(IdentifierStart::Is(0x309B)); - EXPECT_TRUE(IdentifierStart::Is(0x309C)); + EXPECT_TRUE(IsIdentifierStart(0x1885)); + EXPECT_TRUE(IsIdentifierStart(0x1886)); + EXPECT_TRUE(IsIdentifierStart(0x2118)); + EXPECT_TRUE(IsIdentifierStart(0x212E)); + EXPECT_TRUE(IsIdentifierStart(0x309B)); + EXPECT_TRUE(IsIdentifierStart(0x309C)); // Issue 2892: // \u2E2F has the Pattern_Syntax property, excluding it from ID_Start. - EXPECT_FALSE(IdentifierStart::Is(0x2E2F)); + EXPECT_FALSE(IsIdentifierStart(0x2E2F)); #ifdef V8_INTL_SUPPORT // New in Unicode 8.0 (6,847 code points) // [:ID_Start:] & [[:Age=8.0:] - [:Age=7.0:]] - EXPECT_TRUE(IdentifierStart::Is(0x08B3)); - EXPECT_TRUE(IdentifierStart::Is(0x0AF9)); - EXPECT_TRUE(IdentifierStart::Is(0x13F8)); - EXPECT_TRUE(IdentifierStart::Is(0x9FCD)); - EXPECT_TRUE(IdentifierStart::Is(0xAB60)); - EXPECT_TRUE(IdentifierStart::Is(0x10CC0)); - EXPECT_TRUE(IdentifierStart::Is(0x108E0)); - EXPECT_TRUE(IdentifierStart::Is(0x2B820)); + EXPECT_TRUE(IsIdentifierStart(0x08B3)); + EXPECT_TRUE(IsIdentifierStart(0x0AF9)); + EXPECT_TRUE(IsIdentifierStart(0x13F8)); + EXPECT_TRUE(IsIdentifierStart(0x9FCD)); + EXPECT_TRUE(IsIdentifierStart(0xAB60)); + EXPECT_TRUE(IsIdentifierStart(0x10CC0)); + EXPECT_TRUE(IsIdentifierStart(0x108E0)); + EXPECT_TRUE(IsIdentifierStart(0x2B820)); // New in Unicode 9.0 (7,177 code points) // [:ID_Start:] & [[:Age=9.0:] - [:Age=8.0:]] - EXPECT_TRUE(IdentifierStart::Is(0x1C80)); - EXPECT_TRUE(IdentifierStart::Is(0x104DB)); - EXPECT_TRUE(IdentifierStart::Is(0x1E922)); + EXPECT_TRUE(IsIdentifierStart(0x1C80)); + EXPECT_TRUE(IsIdentifierStart(0x104DB)); + EXPECT_TRUE(IsIdentifierStart(0x1E922)); #endif } TEST(CharPredicatesTest, IdentifierPart) { - EXPECT_TRUE(IdentifierPart::Is('$')); - EXPECT_TRUE(IdentifierPart::Is('_')); - EXPECT_TRUE(IdentifierPart::Is('\\')); - EXPECT_TRUE(IdentifierPart::Is(0x200C)); - EXPECT_TRUE(IdentifierPart::Is(0x200D)); + EXPECT_TRUE(IsIdentifierPart('$')); + EXPECT_TRUE(IsIdentifierPart('_')); + EXPECT_TRUE(IsIdentifierPart('\\')); + EXPECT_TRUE(IsIdentifierPart(0x200C)); + EXPECT_TRUE(IsIdentifierPart(0x200D)); #ifdef V8_INTL_SUPPORT // New in Unicode 8.0 (6,847 code points) // [:ID_Start:] & [[:Age=8.0:] - [:Age=7.0:]] - EXPECT_TRUE(IdentifierPart::Is(0x08B3)); - EXPECT_TRUE(IdentifierPart::Is(0x0AF9)); - EXPECT_TRUE(IdentifierPart::Is(0x13F8)); - EXPECT_TRUE(IdentifierPart::Is(0x9FCD)); - EXPECT_TRUE(IdentifierPart::Is(0xAB60)); - EXPECT_TRUE(IdentifierPart::Is(0x10CC0)); - EXPECT_TRUE(IdentifierPart::Is(0x108E0)); - EXPECT_TRUE(IdentifierPart::Is(0x2B820)); + EXPECT_TRUE(IsIdentifierPart(0x08B3)); + EXPECT_TRUE(IsIdentifierPart(0x0AF9)); + EXPECT_TRUE(IsIdentifierPart(0x13F8)); + EXPECT_TRUE(IsIdentifierPart(0x9FCD)); + EXPECT_TRUE(IsIdentifierPart(0xAB60)); + EXPECT_TRUE(IsIdentifierPart(0x10CC0)); + EXPECT_TRUE(IsIdentifierPart(0x108E0)); + EXPECT_TRUE(IsIdentifierPart(0x2B820)); // [[:ID_Continue:]-[:ID_Start:]] & [[:Age=8.0:]-[:Age=7.0:]] // 162 code points - EXPECT_TRUE(IdentifierPart::Is(0x08E3)); - EXPECT_TRUE(IdentifierPart::Is(0xA69E)); - EXPECT_TRUE(IdentifierPart::Is(0x11730)); + EXPECT_TRUE(IsIdentifierPart(0x08E3)); + EXPECT_TRUE(IsIdentifierPart(0xA69E)); + EXPECT_TRUE(IsIdentifierPart(0x11730)); // New in Unicode 9.0 (7,177 code points) // [:ID_Start:] & [[:Age=9.0:] - [:Age=8.0:]] - EXPECT_TRUE(IdentifierPart::Is(0x1C80)); - EXPECT_TRUE(IdentifierPart::Is(0x104DB)); - EXPECT_TRUE(IdentifierPart::Is(0x1E922)); + EXPECT_TRUE(IsIdentifierPart(0x1C80)); + EXPECT_TRUE(IsIdentifierPart(0x104DB)); + EXPECT_TRUE(IsIdentifierPart(0x1E922)); // [[:ID_Continue:]-[:ID_Start:]] & [[:Age=9.0:]-[:Age=8.0:]] // 162 code points - EXPECT_TRUE(IdentifierPart::Is(0x08D4)); - EXPECT_TRUE(IdentifierPart::Is(0x1DFB)); - EXPECT_TRUE(IdentifierPart::Is(0xA8C5)); - EXPECT_TRUE(IdentifierPart::Is(0x11450)); + EXPECT_TRUE(IsIdentifierPart(0x08D4)); + EXPECT_TRUE(IsIdentifierPart(0x1DFB)); + EXPECT_TRUE(IsIdentifierPart(0xA8C5)); + EXPECT_TRUE(IsIdentifierPart(0x11450)); #endif // http://www.unicode.org/reports/tr31/ @@ -133,58 +134,58 @@ TEST(CharPredicatesTest, IdentifierPart) { // grep 'Other_ID_(Continue|Start)' // Other_ID_Start - EXPECT_TRUE(IdentifierPart::Is(0x1885)); - EXPECT_TRUE(IdentifierPart::Is(0x1886)); - EXPECT_TRUE(IdentifierPart::Is(0x2118)); - EXPECT_TRUE(IdentifierPart::Is(0x212E)); - EXPECT_TRUE(IdentifierPart::Is(0x309B)); - EXPECT_TRUE(IdentifierPart::Is(0x309C)); + EXPECT_TRUE(IsIdentifierPart(0x1885)); + EXPECT_TRUE(IsIdentifierPart(0x1886)); + EXPECT_TRUE(IsIdentifierPart(0x2118)); + EXPECT_TRUE(IsIdentifierPart(0x212E)); + EXPECT_TRUE(IsIdentifierPart(0x309B)); + EXPECT_TRUE(IsIdentifierPart(0x309C)); // Other_ID_Continue - EXPECT_TRUE(IdentifierPart::Is(0x00B7)); - EXPECT_TRUE(IdentifierPart::Is(0x0387)); - EXPECT_TRUE(IdentifierPart::Is(0x1369)); - EXPECT_TRUE(IdentifierPart::Is(0x1370)); - EXPECT_TRUE(IdentifierPart::Is(0x1371)); - EXPECT_TRUE(IdentifierPart::Is(0x19DA)); + EXPECT_TRUE(IsIdentifierPart(0x00B7)); + EXPECT_TRUE(IsIdentifierPart(0x0387)); + EXPECT_TRUE(IsIdentifierPart(0x1369)); + EXPECT_TRUE(IsIdentifierPart(0x1370)); + EXPECT_TRUE(IsIdentifierPart(0x1371)); + EXPECT_TRUE(IsIdentifierPart(0x19DA)); // Issue 2892: // \u2E2F has the Pattern_Syntax property, excluding it from ID_Start. - EXPECT_FALSE(IdentifierPart::Is(0x2E2F)); + EXPECT_FALSE(IsIdentifierPart(0x2E2F)); } #ifdef V8_INTL_SUPPORT TEST(CharPredicatesTest, SupplementaryPlaneIdentifiers) { // Both ID_Start and ID_Continue. - EXPECT_TRUE(IdentifierStart::Is(0x10403)); // Category Lu - EXPECT_TRUE(IdentifierPart::Is(0x10403)); - EXPECT_TRUE(IdentifierStart::Is(0x1043C)); // Category Ll - EXPECT_TRUE(IdentifierPart::Is(0x1043C)); - EXPECT_TRUE(IdentifierStart::Is(0x16F9C)); // Category Lm - EXPECT_TRUE(IdentifierPart::Is(0x16F9C)); - EXPECT_TRUE(IdentifierStart::Is(0x10048)); // Category Lo - EXPECT_TRUE(IdentifierPart::Is(0x10048)); - EXPECT_TRUE(IdentifierStart::Is(0x1014D)); // Category Nl - EXPECT_TRUE(IdentifierPart::Is(0x1014D)); + EXPECT_TRUE(IsIdentifierStart(0x10403)); // Category Lu + EXPECT_TRUE(IsIdentifierPart(0x10403)); + EXPECT_TRUE(IsIdentifierStart(0x1043C)); // Category Ll + EXPECT_TRUE(IsIdentifierPart(0x1043C)); + EXPECT_TRUE(IsIdentifierStart(0x16F9C)); // Category Lm + EXPECT_TRUE(IsIdentifierPart(0x16F9C)); + EXPECT_TRUE(IsIdentifierStart(0x10048)); // Category Lo + EXPECT_TRUE(IsIdentifierPart(0x10048)); + EXPECT_TRUE(IsIdentifierStart(0x1014D)); // Category Nl + EXPECT_TRUE(IsIdentifierPart(0x1014D)); // New in Unicode 8.0 // [ [:ID_Start=Yes:] & [:Age=8.0:]] - [:Age=7.0:] - EXPECT_TRUE(IdentifierStart::Is(0x108E0)); - EXPECT_TRUE(IdentifierStart::Is(0x10C80)); + EXPECT_TRUE(IsIdentifierStart(0x108E0)); + EXPECT_TRUE(IsIdentifierStart(0x10C80)); // Only ID_Continue. - EXPECT_FALSE(IdentifierStart::Is(0x101FD)); // Category Mn - EXPECT_TRUE(IdentifierPart::Is(0x101FD)); - EXPECT_FALSE(IdentifierStart::Is(0x11002)); // Category Mc - EXPECT_TRUE(IdentifierPart::Is(0x11002)); - EXPECT_FALSE(IdentifierStart::Is(0x104A9)); // Category Nd - EXPECT_TRUE(IdentifierPart::Is(0x104A9)); + EXPECT_FALSE(IsIdentifierStart(0x101FD)); // Category Mn + EXPECT_TRUE(IsIdentifierPart(0x101FD)); + EXPECT_FALSE(IsIdentifierStart(0x11002)); // Category Mc + EXPECT_TRUE(IsIdentifierPart(0x11002)); + EXPECT_FALSE(IsIdentifierStart(0x104A9)); // Category Nd + EXPECT_TRUE(IsIdentifierPart(0x104A9)); // Neither. - EXPECT_FALSE(IdentifierStart::Is(0x10111)); // Category No - EXPECT_FALSE(IdentifierPart::Is(0x10111)); - EXPECT_FALSE(IdentifierStart::Is(0x1F4A9)); // Category So - EXPECT_FALSE(IdentifierPart::Is(0x1F4A9)); + EXPECT_FALSE(IsIdentifierStart(0x10111)); // Category No + EXPECT_FALSE(IsIdentifierPart(0x10111)); + EXPECT_FALSE(IsIdentifierStart(0x1F4A9)); // Category So + EXPECT_FALSE(IsIdentifierPart(0x1F4A9)); } #endif // V8_INTL_SUPPORT diff --git a/deps/v8/test/unittests/code-stub-assembler-unittest.cc b/deps/v8/test/unittests/code-stub-assembler-unittest.cc index dab7e3e3a6..836a18e2e6 100644 --- a/deps/v8/test/unittests/code-stub-assembler-unittest.cc +++ b/deps/v8/test/unittests/code-stub-assembler-unittest.cc @@ -20,14 +20,6 @@ namespace c = v8::internal::compiler; namespace v8 { namespace internal { -#ifdef ENABLE_VERIFY_CSA -#define IS_BITCAST_WORD_TO_TAGGED_SIGNED(x) IsBitcastWordToTaggedSigned(x) -#define IS_BITCAST_TAGGED_TO_WORD(x) IsBitcastTaggedToWord(x) -#else -#define IS_BITCAST_WORD_TO_TAGGED_SIGNED(x) (x) -#define IS_BITCAST_TAGGED_TO_WORD(x) (x) -#endif - CodeStubAssemblerTestState::CodeStubAssemblerTestState( CodeStubAssemblerTest* test) : compiler::CodeAssemblerState( @@ -39,7 +31,7 @@ TARGET_TEST_F(CodeStubAssemblerTest, SmiTag) { CodeStubAssemblerForTest m(&state); Node* value = m.Int32Constant(44); EXPECT_THAT(m.SmiTag(value), - IS_BITCAST_WORD_TO_TAGGED_SIGNED(c::IsIntPtrConstant( + IsBitcastWordToTaggedSigned(c::IsIntPtrConstant( static_cast<intptr_t>(44) << (kSmiShiftSize + kSmiTagSize)))); EXPECT_THAT(m.SmiUntag(value), c::IsIntPtrConstant(static_cast<intptr_t>(44) >> diff --git a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc deleted file mode 100644 index 6ae5c7bd6c..0000000000 --- a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-tracer-unittest.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" -#include "testing/gtest-support.h" - -namespace v8 { -namespace internal { - -TEST(CompilerDispatcherTracerTest, EstimateWithoutSamples) { - CompilerDispatcherTracer tracer(nullptr); - - EXPECT_EQ(0.0, tracer.EstimatePrepareInMs()); - EXPECT_EQ(1.0, tracer.EstimateCompileInMs(1)); - EXPECT_EQ(1.0, tracer.EstimateCompileInMs(42)); - EXPECT_EQ(0.0, tracer.EstimateFinalizeInMs()); -} - -TEST(CompilerDispatcherTracerTest, Average) { - CompilerDispatcherTracer tracer(nullptr); - - EXPECT_EQ(0.0, tracer.EstimatePrepareInMs()); - - tracer.RecordPrepare(1.0); - tracer.RecordPrepare(2.0); - tracer.RecordPrepare(3.0); - - EXPECT_EQ((1.0 + 2.0 + 3.0) / 3, tracer.EstimatePrepareInMs()); -} - -TEST(CompilerDispatcherTracerTest, SizeBasedAverage) { - CompilerDispatcherTracer tracer(nullptr); - - EXPECT_EQ(1.0, tracer.EstimateCompileInMs(100)); - - // All three samples parse 100 units/ms. - tracer.RecordCompile(1.0, 100); - tracer.RecordCompile(2.0, 200); - tracer.RecordCompile(3.0, 300); - - EXPECT_EQ(1.0, tracer.EstimateCompileInMs(100)); - EXPECT_EQ(5.0, tracer.EstimateCompileInMs(500)); -} - -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc index bfc111aed5..0f918e3a07 100644 --- a/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc +++ b/deps/v8/test/unittests/compiler-dispatcher/compiler-dispatcher-unittest.cc @@ -13,9 +13,6 @@ #include "src/ast/scopes.h" #include "src/base/platform/semaphore.h" #include "src/base/template-utils.h" -#include "src/compiler-dispatcher/compiler-dispatcher-job.h" -#include "src/compiler-dispatcher/compiler-dispatcher-tracer.h" -#include "src/compiler-dispatcher/unoptimized-compile-job.h" #include "src/compiler.h" #include "src/flags.h" #include "src/handles.h" @@ -88,9 +85,11 @@ class CompilerDispatcherTest : public TestWithNativeContext { outer_parse_info->zone(), script_scope, FUNCTION_SCOPE); function_scope->set_start_position(shared->StartPosition()); function_scope->set_end_position(shared->EndPosition()); + std::vector<void*> pointer_buffer; + ScopedPtrList<Statement> statements(&pointer_buffer); const FunctionLiteral* function_literal = ast_node_factory.NewFunctionLiteral( - function_name, function_scope, nullptr, -1, -1, -1, + function_name, function_scope, statements, -1, -1, -1, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, FunctionLiteral::kShouldEagerCompile, shared->StartPosition(), true, @@ -115,7 +114,7 @@ class MockPlatform : public v8::Platform { sem_(0), tracing_controller_(V8::GetCurrentPlatform()->GetTracingController()) {} ~MockPlatform() override { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); EXPECT_TRUE(foreground_tasks_.empty()); EXPECT_TRUE(worker_tasks_.empty()); EXPECT_TRUE(idle_task_ == nullptr); @@ -129,7 +128,7 @@ class MockPlatform : public v8::Platform { } void CallOnWorkerThread(std::unique_ptr<Task> task) override { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); worker_tasks_.push_back(std::move(task)); } @@ -139,7 +138,7 @@ class MockPlatform : public v8::Platform { } void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); foreground_tasks_.push_back(std::unique_ptr<Task>(task)); } @@ -150,7 +149,7 @@ class MockPlatform : public v8::Platform { void CallIdleOnForegroundThread(v8::Isolate* isolate, IdleTask* task) override { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); ASSERT_TRUE(idle_task_ == nullptr); idle_task_ = task; } @@ -174,7 +173,7 @@ class MockPlatform : public v8::Platform { time_step_ = time_step; IdleTask* task; { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); task = idle_task_; ASSERT_TRUE(idle_task_ != nullptr); idle_task_ = nullptr; @@ -184,24 +183,24 @@ class MockPlatform : public v8::Platform { } bool IdleTaskPending() { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); return idle_task_; } bool WorkerTasksPending() { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); return !worker_tasks_.empty(); } bool ForegroundTasksPending() { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); return !foreground_tasks_.empty(); } void RunWorkerTasksAndBlock(Platform* platform) { std::vector<std::unique_ptr<Task>> tasks; { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); tasks.swap(worker_tasks_); } platform->CallOnWorkerThread( @@ -212,7 +211,7 @@ class MockPlatform : public v8::Platform { void RunWorkerTasks(Platform* platform) { std::vector<std::unique_ptr<Task>> tasks; { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); tasks.swap(worker_tasks_); } platform->CallOnWorkerThread( @@ -222,7 +221,7 @@ class MockPlatform : public v8::Platform { void RunForegroundTasks() { std::vector<std::unique_ptr<Task>> tasks; { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); tasks.swap(foreground_tasks_); } for (auto& task : tasks) { @@ -235,7 +234,7 @@ class MockPlatform : public v8::Platform { void ClearWorkerTasks() { std::vector<std::unique_ptr<Task>> tasks; { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); tasks.swap(worker_tasks_); } } @@ -243,13 +242,13 @@ class MockPlatform : public v8::Platform { void ClearForegroundTasks() { std::vector<std::unique_ptr<Task>> tasks; { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); tasks.swap(foreground_tasks_); } } void ClearIdleTask() { - base::LockGuard<base::Mutex> lock(&mutex_); + base::MutexGuard lock(&mutex_); ASSERT_TRUE(idle_task_ != nullptr); delete idle_task_; idle_task_ = nullptr; @@ -286,7 +285,7 @@ class MockPlatform : public v8::Platform { : platform_(platform) {} void PostTask(std::unique_ptr<v8::Task> task) override { - base::LockGuard<base::Mutex> lock(&platform_->mutex_); + base::MutexGuard lock(&platform_->mutex_); platform_->foreground_tasks_.push_back(std::move(task)); } @@ -297,7 +296,7 @@ class MockPlatform : public v8::Platform { void PostIdleTask(std::unique_ptr<IdleTask> task) override { DCHECK(IdleTasksEnabled()); - base::LockGuard<base::Mutex> lock(&platform_->mutex_); + base::MutexGuard lock(&platform_->mutex_); ASSERT_TRUE(platform_->idle_task_ == nullptr); platform_->idle_task_ = task.release(); } @@ -330,6 +329,7 @@ class MockPlatform : public v8::Platform { TEST_F(CompilerDispatcherTest, Construct) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); + dispatcher.AbortAll(); } TEST_F(CompilerDispatcherTest, IsEnqueued) { @@ -352,12 +352,13 @@ TEST_F(CompilerDispatcherTest, IsEnqueued) { ASSERT_TRUE(dispatcher.IsEnqueued(*job_id)); ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - dispatcher.AbortAll(BlockingBehavior::kBlock); + dispatcher.AbortAll(); ASSERT_FALSE(dispatcher.IsEnqueued(*job_id)); ASSERT_FALSE(dispatcher.IsEnqueued(shared)); - ASSERT_TRUE(platform.IdleTaskPending()); + + ASSERT_FALSE(platform.IdleTaskPending()); + ASSERT_TRUE(platform.WorkerTasksPending()); platform.ClearWorkerTasks(); - platform.ClearIdleTask(); } TEST_F(CompilerDispatcherTest, FinishNow) { @@ -377,12 +378,13 @@ TEST_F(CompilerDispatcherTest, FinishNow) { ASSERT_FALSE(dispatcher.IsEnqueued(*job_id)); ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(shared->is_compiled()); - ASSERT_TRUE(platform.IdleTaskPending()); + platform.ClearWorkerTasks(); - platform.ClearIdleTask(); + ASSERT_FALSE(platform.IdleTaskPending()); + dispatcher.AbortAll(); } -TEST_F(CompilerDispatcherTest, IdleTask) { +TEST_F(CompilerDispatcherTest, CompileAndFinalize) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); @@ -393,11 +395,10 @@ TEST_F(CompilerDispatcherTest, IdleTask) { base::Optional<CompilerDispatcher::JobId> job_id = EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); - ASSERT_TRUE(platform.IdleTaskPending()); + ASSERT_TRUE(platform.WorkerTasksPending()); - // Since time doesn't progress on the MockPlatform, this is enough idle time - // to finish compiling the function. - platform.RunIdleTask(1000.0, 0.0); + // Run compile steps. + platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); // Since we haven't yet registered the SFI for the job, it should still be // enqueued and waiting. @@ -405,7 +406,7 @@ TEST_F(CompilerDispatcherTest, IdleTask) { ASSERT_FALSE(shared->is_compiled()); ASSERT_FALSE(platform.IdleTaskPending()); - // Register SFI, which should schedule another idle task to complete the + // Register SFI, which should schedule another idle task to finalize the // compilation. dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); ASSERT_TRUE(platform.IdleTaskPending()); @@ -413,10 +414,12 @@ TEST_F(CompilerDispatcherTest, IdleTask) { ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(shared->is_compiled()); - platform.ClearWorkerTasks(); + ASSERT_FALSE(platform.WorkerTasksPending()); + ASSERT_FALSE(platform.IdleTaskPending()); + dispatcher.AbortAll(); } -TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) { +TEST_F(CompilerDispatcherTest, IdleTaskNoIdleTime) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); @@ -429,25 +432,24 @@ TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) { EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); - ASSERT_TRUE(platform.IdleTaskPending()); + // Run compile steps. + platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); - // The job should be scheduled for the main thread. + // Job should be ready to finalize. ASSERT_EQ(dispatcher.jobs_.size(), 1u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, - dispatcher.jobs_.begin()->second->status()); + ASSERT_TRUE(dispatcher.jobs_.begin()->second->has_run); + ASSERT_TRUE(platform.IdleTaskPending()); - // Only grant a little idle time and have time advance beyond it in one step. - platform.RunIdleTask(2.0, 1.0); + // Grant no idle time and have time advance beyond it in one step. + platform.RunIdleTask(0.0, 1.0); ASSERT_TRUE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(shared->is_compiled()); ASSERT_TRUE(platform.IdleTaskPending()); - // The job should be still scheduled for the main thread, but ready for - // finalization. + // Job should be ready to finalize. ASSERT_EQ(dispatcher.jobs_.size(), 1u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToFinalize, - dispatcher.jobs_.begin()->second->status()); + ASSERT_TRUE(dispatcher.jobs_.begin()->second->has_run); // Now grant a lot of idle time and freeze time. platform.RunIdleTask(1000.0, 0.0); @@ -455,7 +457,58 @@ TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) { ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_TRUE(shared->is_compiled()); ASSERT_FALSE(platform.IdleTaskPending()); - platform.ClearWorkerTasks(); + ASSERT_FALSE(platform.WorkerTasksPending()); + dispatcher.AbortAll(); +} + +TEST_F(CompilerDispatcherTest, IdleTaskSmallIdleTime) { + MockPlatform platform; + CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); + + Handle<SharedFunctionInfo> shared_1 = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared_1->is_compiled()); + Handle<SharedFunctionInfo> shared_2 = + test::CreateSharedFunctionInfo(i_isolate(), nullptr); + ASSERT_FALSE(shared_2->is_compiled()); + + base::Optional<CompilerDispatcher::JobId> job_id_1 = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_1); + base::Optional<CompilerDispatcher::JobId> job_id_2 = + EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_2); + + dispatcher.RegisterSharedFunctionInfo(*job_id_1, *shared_1); + dispatcher.RegisterSharedFunctionInfo(*job_id_2, *shared_2); + + // Run compile steps. + platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); + + // Both jobs should be ready to finalize. + ASSERT_EQ(dispatcher.jobs_.size(), 2u); + ASSERT_TRUE(dispatcher.jobs_.begin()->second->has_run); + ASSERT_TRUE((++dispatcher.jobs_.begin())->second->has_run); + ASSERT_TRUE(platform.IdleTaskPending()); + + // Grant a small anount of idle time and have time advance beyond it in one + // step. + platform.RunIdleTask(2.0, 1.0); + + // Only one of the jobs should be finalized. + ASSERT_EQ(dispatcher.jobs_.size(), 1u); + ASSERT_TRUE(dispatcher.jobs_.begin()->second->has_run); + ASSERT_NE(dispatcher.IsEnqueued(shared_1), dispatcher.IsEnqueued(shared_2)); + ASSERT_NE(shared_1->is_compiled(), shared_2->is_compiled()); + ASSERT_TRUE(platform.IdleTaskPending()); + + // Now grant a lot of idle time and freeze time. + platform.RunIdleTask(1000.0, 0.0); + + ASSERT_FALSE(dispatcher.IsEnqueued(shared_1) || + dispatcher.IsEnqueued(shared_2)); + ASSERT_TRUE(shared_1->is_compiled() && shared_2->is_compiled()); + ASSERT_FALSE(platform.IdleTaskPending()); + ASSERT_FALSE(platform.WorkerTasksPending()); + dispatcher.AbortAll(); } TEST_F(CompilerDispatcherTest, IdleTaskException) { @@ -478,49 +531,15 @@ TEST_F(CompilerDispatcherTest, IdleTaskException) { EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); - // Since time doesn't progress on the MockPlatform, this is enough idle time - // to finish compiling the function. + // Run compile steps and finalize. + platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); platform.RunIdleTask(1000.0, 0.0); ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(shared->is_compiled()); ASSERT_FALSE(i_isolate()->has_pending_exception()); platform.ClearWorkerTasks(); -} - -TEST_F(CompilerDispatcherTest, CompileOnBackgroundThread) { - MockPlatform platform; - CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - - Handle<SharedFunctionInfo> shared = - test::CreateSharedFunctionInfo(i_isolate(), nullptr); - ASSERT_FALSE(shared->is_compiled()); - - base::Optional<CompilerDispatcher::JobId> job_id = - EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); - dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); - - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - ASSERT_FALSE(shared->is_compiled()); - ASSERT_EQ(dispatcher.jobs_.size(), 1u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, - dispatcher.jobs_.begin()->second->status()); - ASSERT_TRUE(platform.WorkerTasksPending()); - - platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); - - ASSERT_TRUE(platform.IdleTaskPending()); - ASSERT_FALSE(platform.WorkerTasksPending()); - ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToFinalize, - dispatcher.jobs_.begin()->second->status()); - - // Now grant a lot of idle time and freeze time. - platform.RunIdleTask(1000.0, 0.0); - - ASSERT_FALSE(dispatcher.IsEnqueued(shared)); - ASSERT_TRUE(shared->is_compiled()); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_FALSE(platform.WorkerTasksPending()); + dispatcher.AbortAll(); } TEST_F(CompilerDispatcherTest, FinishNowWithWorkerTask) { @@ -536,14 +555,12 @@ TEST_F(CompilerDispatcherTest, FinishNowWithWorkerTask) { dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); ASSERT_EQ(dispatcher.jobs_.size(), 1u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, - dispatcher.jobs_.begin()->second->status()); + ASSERT_FALSE(dispatcher.jobs_.begin()->second->has_run); ASSERT_TRUE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(shared->is_compiled()); ASSERT_EQ(dispatcher.jobs_.size(), 1u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, - dispatcher.jobs_.begin()->second->status()); + ASSERT_FALSE(dispatcher.jobs_.begin()->second->has_run); ASSERT_TRUE(platform.WorkerTasksPending()); // This does not block, but races with the FinishNow() call below. @@ -555,6 +572,7 @@ TEST_F(CompilerDispatcherTest, FinishNowWithWorkerTask) { ASSERT_TRUE(shared->is_compiled()); if (platform.IdleTaskPending()) platform.ClearIdleTask(); ASSERT_FALSE(platform.WorkerTasksPending()); + dispatcher.AbortAll(); } TEST_F(CompilerDispatcherTest, IdleTaskMultipleJobs) { @@ -579,15 +597,17 @@ TEST_F(CompilerDispatcherTest, IdleTaskMultipleJobs) { ASSERT_TRUE(dispatcher.IsEnqueued(shared_1)); ASSERT_TRUE(dispatcher.IsEnqueued(shared_2)); - // Since time doesn't progress on the MockPlatform, this is enough idle time - // to finish compiling the function. + // Run compile steps and finalize. + platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); platform.RunIdleTask(1000.0, 0.0); ASSERT_FALSE(dispatcher.IsEnqueued(shared_1)); ASSERT_FALSE(dispatcher.IsEnqueued(shared_2)); ASSERT_TRUE(shared_1->is_compiled()); ASSERT_TRUE(shared_2->is_compiled()); - platform.ClearWorkerTasks(); + ASSERT_FALSE(platform.IdleTaskPending()); + ASSERT_FALSE(platform.WorkerTasksPending()); + dispatcher.AbortAll(); } TEST_F(CompilerDispatcherTest, FinishNowException) { @@ -617,11 +637,12 @@ TEST_F(CompilerDispatcherTest, FinishNowException) { ASSERT_TRUE(i_isolate()->has_pending_exception()); i_isolate()->clear_pending_exception(); - platform.ClearIdleTask(); + ASSERT_FALSE(platform.IdleTaskPending()); platform.ClearWorkerTasks(); + dispatcher.AbortAll(); } -TEST_F(CompilerDispatcherTest, AsyncAbortAllPendingWorkerTask) { +TEST_F(CompilerDispatcherTest, AbortJobNotStarted) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); @@ -631,107 +652,27 @@ TEST_F(CompilerDispatcherTest, AsyncAbortAllPendingWorkerTask) { base::Optional<CompilerDispatcher::JobId> job_id = EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); - dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); ASSERT_EQ(dispatcher.jobs_.size(), 1u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, - dispatcher.jobs_.begin()->second->status()); - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - ASSERT_FALSE(shared->is_compiled()); - ASSERT_TRUE(platform.WorkerTasksPending()); + ASSERT_FALSE(dispatcher.jobs_.begin()->second->has_run); - // The background task hasn't yet started, so we can just cancel it. - dispatcher.AbortAll(BlockingBehavior::kDontBlock); - ASSERT_FALSE(platform.ForegroundTasksPending()); - - ASSERT_FALSE(dispatcher.IsEnqueued(shared)); + ASSERT_TRUE(dispatcher.IsEnqueued(*job_id)); ASSERT_FALSE(shared->is_compiled()); - - platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); - - if (platform.IdleTaskPending()) platform.ClearIdleTask(); - ASSERT_FALSE(platform.WorkerTasksPending()); - ASSERT_FALSE(platform.ForegroundTasksPending()); -} - -TEST_F(CompilerDispatcherTest, AsyncAbortAllRunningWorkerTask) { - MockPlatform platform; - CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - - Handle<SharedFunctionInfo> shared_1 = - test::CreateSharedFunctionInfo(i_isolate(), nullptr); - ASSERT_FALSE(shared_1->is_compiled()); - Handle<SharedFunctionInfo> shared_2 = - test::CreateSharedFunctionInfo(i_isolate(), nullptr); - ASSERT_FALSE(shared_2->is_compiled()); - - base::Optional<CompilerDispatcher::JobId> job_id_1 = - EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_1); - dispatcher.RegisterSharedFunctionInfo(*job_id_1, *shared_1); - ASSERT_EQ(dispatcher.jobs_.size(), 1u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, - dispatcher.jobs_.begin()->second->status()); - ASSERT_TRUE(dispatcher.IsEnqueued(shared_1)); - ASSERT_FALSE(shared_1->is_compiled()); - ASSERT_TRUE(platform.IdleTaskPending()); + ASSERT_FALSE(dispatcher.jobs_.begin()->second->has_run); ASSERT_TRUE(platform.WorkerTasksPending()); - // Kick off background tasks and freeze them. - dispatcher.block_for_testing_.SetValue(true); - platform.RunWorkerTasks(V8::GetCurrentPlatform()); + dispatcher.AbortJob(*job_id); - // Busy loop until the background task started running. - while (dispatcher.block_for_testing_.Value()) { - } - dispatcher.AbortAll(BlockingBehavior::kDontBlock); - ASSERT_TRUE(platform.ForegroundTasksPending()); - - // We can't schedule new tasks while we're aborting. - base::Optional<CompilerDispatcher::JobId> job_id_2 = - EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_2); - ASSERT_FALSE(job_id_2); - - // Run the first AbortTask. Since the background job is still pending, it - // can't do anything. - platform.RunForegroundTasks(); - { - base::LockGuard<base::Mutex> lock(&dispatcher.mutex_); - ASSERT_TRUE(dispatcher.abort_); - } - - // Release background task. - dispatcher.semaphore_for_testing_.Signal(); - - // Busy loop until the background task scheduled another AbortTask task. - while (!platform.ForegroundTasksPending()) { - } - - platform.RunForegroundTasks(); - ASSERT_TRUE(dispatcher.jobs_.empty()); - { - base::LockGuard<base::Mutex> lock(&dispatcher.mutex_); - ASSERT_FALSE(dispatcher.abort_); - } - - ASSERT_TRUE(platform.IdleTaskPending()); - platform.RunIdleTask(5.0, 1.0); - ASSERT_FALSE(platform.WorkerTasksPending()); - ASSERT_FALSE(platform.ForegroundTasksPending()); - - // Now it's possible to enqueue new functions again. - job_id_2 = EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_2); - ASSERT_TRUE(job_id_2); - ASSERT_TRUE(platform.IdleTaskPending()); - ASSERT_TRUE(platform.WorkerTasksPending()); - ASSERT_FALSE(platform.ForegroundTasksPending()); - - dispatcher.AbortAll(BlockingBehavior::kBlock); + // Aborting removes the job from the queue. + ASSERT_FALSE(dispatcher.IsEnqueued(*job_id)); + ASSERT_FALSE(shared->is_compiled()); + ASSERT_FALSE(platform.IdleTaskPending()); platform.ClearWorkerTasks(); - platform.ClearIdleTask(); + dispatcher.AbortAll(); } -TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) { +TEST_F(CompilerDispatcherTest, AbortJobAlreadyStarted) { MockPlatform platform; CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); @@ -741,154 +682,59 @@ TEST_F(CompilerDispatcherTest, FinishNowDuringAbortAll) { base::Optional<CompilerDispatcher::JobId> job_id = EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); - dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); + ASSERT_EQ(dispatcher.jobs_.size(), 1u); + ASSERT_FALSE(dispatcher.jobs_.begin()->second->has_run); + + ASSERT_TRUE(dispatcher.IsEnqueued(*job_id)); ASSERT_FALSE(shared->is_compiled()); ASSERT_EQ(dispatcher.jobs_.size(), 1u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, - dispatcher.jobs_.begin()->second->status()); - ASSERT_TRUE(platform.IdleTaskPending()); + ASSERT_FALSE(dispatcher.jobs_.begin()->second->has_run); ASSERT_TRUE(platform.WorkerTasksPending()); - // Kick off background tasks and freeze them. - dispatcher.block_for_testing_.SetValue(true); - platform.RunWorkerTasks(V8::GetCurrentPlatform()); - - // Busy loop until the background task started running. - while (dispatcher.block_for_testing_.Value()) { - } - dispatcher.AbortAll(BlockingBehavior::kDontBlock); - ASSERT_TRUE(platform.ForegroundTasksPending()); - - // Run the first AbortTask. Since the background job is still pending, it - // can't do anything. - platform.RunForegroundTasks(); + // Have dispatcher block on the background thread when running the job. { base::LockGuard<base::Mutex> lock(&dispatcher.mutex_); - ASSERT_TRUE(dispatcher.abort_); + dispatcher.block_for_testing_.SetValue(true); } - // Run the idle task, which should have already been canceled and won't do - // anything. - ASSERT_TRUE(platform.IdleTaskPending()); - platform.RunIdleTask(5.0, 1.0); - - // While the background thread holds on to a job, it is still enqueued. - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - - // Release background task. - dispatcher.semaphore_for_testing_.Signal(); - - // Force the compilation to finish, even while aborting. - ASSERT_TRUE(dispatcher.FinishNow(shared)); - ASSERT_TRUE(dispatcher.jobs_.empty()); - - // Busy wait for the background task to finish. - for (;;) { - base::LockGuard<base::Mutex> lock(&dispatcher.mutex_); - if (dispatcher.num_worker_tasks_ == 0) { - break; - } + // Start background thread and wait until it is about to run the job. + platform.RunWorkerTasks(V8::GetCurrentPlatform()); + while (dispatcher.block_for_testing_.Value()) { } - ASSERT_TRUE(platform.ForegroundTasksPending()); - ASSERT_FALSE(platform.IdleTaskPending()); - ASSERT_FALSE(platform.WorkerTasksPending()); + // Now abort while dispatcher is in the middle of running the job. + dispatcher.AbortJob(*job_id); - platform.RunForegroundTasks(); + // Unblock background thread, and wait for job to complete. { base::LockGuard<base::Mutex> lock(&dispatcher.mutex_); - ASSERT_FALSE(dispatcher.abort_); + dispatcher.main_thread_blocking_on_job_ = + dispatcher.jobs_.begin()->second.get(); + dispatcher.semaphore_for_testing_.Signal(); + while (dispatcher.main_thread_blocking_on_job_ != nullptr) { + dispatcher.main_thread_blocking_signal_.Wait(&dispatcher.mutex_); + } } -} -TEST_F(CompilerDispatcherTest, MemoryPressure) { - MockPlatform platform; - CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - - Handle<SharedFunctionInfo> shared = - test::CreateSharedFunctionInfo(i_isolate(), nullptr); + // Job should have finished running and then been aborted. + ASSERT_TRUE(dispatcher.IsEnqueued(*job_id)); ASSERT_FALSE(shared->is_compiled()); + ASSERT_EQ(dispatcher.jobs_.size(), 1u); + ASSERT_TRUE(dispatcher.jobs_.begin()->second->has_run); + ASSERT_TRUE(dispatcher.jobs_.begin()->second->aborted); + ASSERT_FALSE(platform.WorkerTasksPending()); + ASSERT_TRUE(platform.IdleTaskPending()); - // Can't enqueue tasks under memory pressure. - dispatcher.MemoryPressureNotification(v8::MemoryPressureLevel::kCritical, - true); - base::Optional<CompilerDispatcher::JobId> job_id = - EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); - ASSERT_FALSE(job_id); - - dispatcher.MemoryPressureNotification(v8::MemoryPressureLevel::kNone, true); - - job_id = EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); - ASSERT_TRUE(job_id); + // Runt the pending idle task + platform.RunIdleTask(1000.0, 0.0); - // Memory pressure cancels current jobs. - dispatcher.MemoryPressureNotification(v8::MemoryPressureLevel::kCritical, - true); + // Aborting removes the SFI from the queue. ASSERT_FALSE(dispatcher.IsEnqueued(*job_id)); - platform.ClearIdleTask(); - platform.ClearWorkerTasks(); -} - -namespace { - -class PressureNotificationTask : public CancelableTask { - public: - PressureNotificationTask(Isolate* isolate, CompilerDispatcher* dispatcher, - base::Semaphore* sem) - : CancelableTask(isolate), dispatcher_(dispatcher), sem_(sem) {} - ~PressureNotificationTask() override = default; - - void RunInternal() override { - dispatcher_->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical, - false); - sem_->Signal(); - } - - private: - CompilerDispatcher* dispatcher_; - base::Semaphore* sem_; - - DISALLOW_COPY_AND_ASSIGN(PressureNotificationTask); -}; - -} // namespace - -TEST_F(CompilerDispatcherTest, MemoryPressureFromBackground) { - MockPlatform platform; - CompilerDispatcher dispatcher(i_isolate(), &platform, FLAG_stack_size); - - Handle<SharedFunctionInfo> shared = - test::CreateSharedFunctionInfo(i_isolate(), nullptr); - ASSERT_FALSE(shared->is_compiled()); - - base::Optional<CompilerDispatcher::JobId> job_id = - EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared); - dispatcher.RegisterSharedFunctionInfo(*job_id, *shared); - - base::Semaphore sem(0); - V8::GetCurrentPlatform()->CallOnWorkerThread( - base::make_unique<PressureNotificationTask>(i_isolate(), &dispatcher, - &sem)); - - sem.Wait(); - - // A memory pressure task is pending, and running it will cancel the job. - ASSERT_TRUE(platform.ForegroundTasksPending()); - ASSERT_TRUE(dispatcher.IsEnqueued(shared)); - platform.RunForegroundTasks(); - ASSERT_FALSE(dispatcher.IsEnqueued(shared)); ASSERT_FALSE(shared->is_compiled()); - - // Since the AbortAll() call is made from a task, AbortAll thinks that there - // is at least one task running, and fires of an AbortTask to be safe. - ASSERT_TRUE(platform.ForegroundTasksPending()); - platform.RunForegroundTasks(); - ASSERT_FALSE(platform.ForegroundTasksPending()); - - platform.ClearIdleTask(); - platform.ClearWorkerTasks(); + ASSERT_FALSE(platform.IdleTaskPending()); + ASSERT_FALSE(platform.WorkerTasksPending()); + dispatcher.AbortAll(); } TEST_F(CompilerDispatcherTest, CompileLazyFinishesDispatcherJob) { @@ -972,16 +818,14 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) { dispatcher.RegisterSharedFunctionInfo(*job_id_2, *shared_2); ASSERT_EQ(dispatcher.jobs_.size(), 2u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, - dispatcher.jobs_.begin()->second->status()); - ASSERT_EQ(UnoptimizedCompileJob::Status::kInitial, - (++dispatcher.jobs_.begin())->second->status()); + ASSERT_FALSE(dispatcher.jobs_.begin()->second->has_run); + ASSERT_FALSE((++dispatcher.jobs_.begin())->second->has_run); ASSERT_TRUE(dispatcher.IsEnqueued(shared_1)); ASSERT_TRUE(dispatcher.IsEnqueued(shared_2)); ASSERT_FALSE(shared_1->is_compiled()); ASSERT_FALSE(shared_2->is_compiled()); - ASSERT_TRUE(platform.IdleTaskPending()); + ASSERT_FALSE(platform.IdleTaskPending()); ASSERT_TRUE(platform.WorkerTasksPending()); platform.RunWorkerTasksAndBlock(V8::GetCurrentPlatform()); @@ -989,10 +833,8 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) { ASSERT_TRUE(platform.IdleTaskPending()); ASSERT_FALSE(platform.WorkerTasksPending()); ASSERT_EQ(dispatcher.jobs_.size(), 2u); - ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToFinalize, - dispatcher.jobs_.begin()->second->status()); - ASSERT_EQ(UnoptimizedCompileJob::Status::kReadyToFinalize, - (++dispatcher.jobs_.begin())->second->status()); + ASSERT_TRUE(dispatcher.jobs_.begin()->second->has_run); + ASSERT_TRUE((++dispatcher.jobs_.begin())->second->has_run); // Now grant a lot of idle time and freeze time. platform.RunIdleTask(1000.0, 0.0); @@ -1002,6 +844,7 @@ TEST_F(CompilerDispatcherTest, CompileMultipleOnBackgroundThread) { ASSERT_TRUE(shared_1->is_compiled()); ASSERT_TRUE(shared_2->is_compiled()); ASSERT_FALSE(platform.IdleTaskPending()); + dispatcher.AbortAll(); } } // namespace internal diff --git a/deps/v8/test/unittests/compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc b/deps/v8/test/unittests/compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc index b796e457d4..d9e1731dc1 100644 --- a/deps/v8/test/unittests/compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc +++ b/deps/v8/test/unittests/compiler-dispatcher/optimizing-compile-dispatcher-unittest.cc @@ -73,6 +73,9 @@ TEST_F(OptimizingCompileDispatcherTest, Construct) { TEST_F(OptimizingCompileDispatcherTest, NonBlockingFlush) { Handle<JSFunction> fun = RunJS<JSFunction>("function f() { function g() {}; return g;}; f();"); + IsCompiledScope is_compiled_scope; + ASSERT_TRUE( + Compiler::Compile(fun, Compiler::CLEAR_EXCEPTION, &is_compiled_scope)); BlockingCompilationJob* job = new BlockingCompilationJob(i_isolate(), fun); OptimizingCompileDispatcher dispatcher(i_isolate()); diff --git a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc index 011cc67c81..77a1587f0b 100644 --- a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc @@ -4,7 +4,7 @@ #include <limits> -#include "test/unittests/compiler/instruction-selector-unittest.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" #include "src/objects-inl.h" diff --git a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc index aa54abe320..bca04a5cf3 100644 --- a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "src/objects-inl.h" -#include "test/unittests/compiler/instruction-selector-unittest.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" namespace v8 { namespace internal { @@ -1288,7 +1288,7 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) { TRACED_FORRANGE(int, bit, 0, 63) { - uint64_t mask = 1L << bit; + uint64_t mask = 1LL << bit; StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); RawMachineLabel a, b; m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(mask)), &a, &b); @@ -1309,7 +1309,7 @@ TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) { TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) { TRACED_FORRANGE(int, bit, 0, 63) { - uint64_t mask = 1L << bit; + uint64_t mask = 1LL << bit; StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); RawMachineLabel a, b; m.Branch(m.Word64And(m.Int64Constant(mask), m.Parameter(0)), &a, &b); @@ -4542,9 +4542,8 @@ TEST_F(InstructionSelectorTest, ExternalReferenceLoad1) { const int64_t kOffsets[] = {0, 1, 4, INT32_MIN, INT32_MAX}; TRACED_FOREACH(int64_t, offset, kOffsets) { StreamBuilder m(this, MachineType::Int64()); - ExternalReference reference = bit_cast<ExternalReference>( - reinterpret_cast<intptr_t>(isolate()->heap()->roots_array_start()) + - offset + kRootRegisterBias); + ExternalReference reference = + bit_cast<ExternalReference>(isolate()->isolate_root() + offset); Node* const value = m.Load(MachineType::Int64(), m.ExternalConstant(reference)); m.Return(value); @@ -4564,9 +4563,8 @@ TEST_F(InstructionSelectorTest, ExternalReferenceLoad2) { // Offset too large, we cannot use kMode_Root. StreamBuilder m(this, MachineType::Int64()); int64_t offset = 0x100000000; - ExternalReference reference = bit_cast<ExternalReference>( - reinterpret_cast<intptr_t>(isolate()->heap()->roots_array_start()) + - offset + kRootRegisterBias); + ExternalReference reference = + bit_cast<ExternalReference>(isolate()->isolate_root() + offset); Node* const value = m.Load(MachineType::Int64(), m.ExternalConstant(reference)); m.Return(value); diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc index 2d59393f9d..59d5dccd06 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc +++ b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/unittests/compiler/instruction-selector-unittest.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" #include "src/code-factory.h" #include "src/compiler/compiler-source-position-table.h" @@ -16,13 +16,10 @@ namespace v8 { namespace internal { namespace compiler { - InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {} - InstructionSelectorTest::~InstructionSelectorTest() = default; - InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( InstructionSelector::Features features, InstructionSelectorTest::StreamBuilderMode mode, @@ -50,11 +47,9 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( PoisoningMitigationLevel::kPoisonAll); selector.SelectInstructions(); if (FLAG_trace_turbo) { - PrintableInstructionSequence printable = {RegisterConfiguration::Default(), - &sequence}; StdoutStream{} << "=== Code sequence after instruction selection ===" << std::endl - << printable; + << sequence; } Stream s; s.virtual_registers_ = selector.GetVirtualRegistersForTesting(); @@ -115,14 +110,12 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( return s; } - int InstructionSelectorTest::Stream::ToVreg(const Node* node) const { VirtualRegisters::const_iterator i = virtual_registers_.find(node->id()); CHECK(i != virtual_registers_.end()); return i->second; } - bool InstructionSelectorTest::Stream::IsFixed(const InstructionOperand* operand, Register reg) const { if (!operand->IsUnallocated()) return false; @@ -131,7 +124,6 @@ bool InstructionSelectorTest::Stream::IsFixed(const InstructionOperand* operand, return unallocated->fixed_register_index() == reg.code(); } - bool InstructionSelectorTest::Stream::IsSameAsFirst( const InstructionOperand* operand) const { if (!operand->IsUnallocated()) return false; @@ -139,7 +131,6 @@ bool InstructionSelectorTest::Stream::IsSameAsFirst( return unallocated->HasSameAsInputPolicy(); } - bool InstructionSelectorTest::Stream::IsUsedAtStart( const InstructionOperand* operand) const { if (!operand->IsUnallocated()) return false; @@ -147,7 +138,6 @@ bool InstructionSelectorTest::Stream::IsUsedAtStart( return unallocated->IsUsedAtStart(); } - const FrameStateFunctionInfo* InstructionSelectorTest::StreamBuilder::GetFrameStateFunctionInfo( int parameter_count, int local_count) { @@ -156,11 +146,9 @@ InstructionSelectorTest::StreamBuilder::GetFrameStateFunctionInfo( Handle<SharedFunctionInfo>()); } - // ----------------------------------------------------------------------------- // Return. - TARGET_TEST_F(InstructionSelectorTest, ReturnFloat32Constant) { const float kValue = 4.2f; StreamBuilder m(this, MachineType::Float32()); @@ -174,7 +162,6 @@ TARGET_TEST_F(InstructionSelectorTest, ReturnFloat32Constant) { EXPECT_EQ(2U, s[1]->InputCount()); } - TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Parameter(0)); @@ -186,7 +173,6 @@ TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) { EXPECT_EQ(2U, s[1]->InputCount()); } - TARGET_TEST_F(InstructionSelectorTest, ReturnZero) { StreamBuilder m(this, MachineType::Int32()); m.Return(m.Int32Constant(0)); @@ -200,7 +186,6 @@ TARGET_TEST_F(InstructionSelectorTest, ReturnZero) { EXPECT_EQ(2U, s[1]->InputCount()); } - // ----------------------------------------------------------------------------- // Conversions. @@ -216,11 +201,9 @@ TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToWord32WithParameter) { EXPECT_EQ(kArchRet, s[2]->arch_opcode()); } - // ----------------------------------------------------------------------------- // Parameters. - TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) { StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); Node* param = m.Parameter(0); @@ -229,7 +212,6 @@ TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) { EXPECT_TRUE(s.IsDouble(param)); } - TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) { StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged()); Node* param = m.Parameter(0); @@ -238,11 +220,9 @@ TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) { EXPECT_TRUE(s.IsReference(param)); } - // ----------------------------------------------------------------------------- // FinishRegion. - TARGET_TEST_F(InstructionSelectorTest, FinishRegion) { StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged()); Node* param = m.Parameter(0); @@ -260,15 +240,12 @@ TARGET_TEST_F(InstructionSelectorTest, FinishRegion) { EXPECT_TRUE(s.IsReference(finish)); } - // ----------------------------------------------------------------------------- // Phi. - typedef InstructionSelectorTestWithParam<MachineType> InstructionSelectorPhiTest; - TARGET_TEST_P(InstructionSelectorPhiTest, Doubleness) { const MachineType type = GetParam(); StreamBuilder m(this, type, type, type); @@ -288,7 +265,6 @@ TARGET_TEST_P(InstructionSelectorPhiTest, Doubleness) { EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param1)); } - TARGET_TEST_P(InstructionSelectorPhiTest, Referenceness) { const MachineType type = GetParam(); StreamBuilder m(this, type, type, type); @@ -308,7 +284,6 @@ TARGET_TEST_P(InstructionSelectorPhiTest, Referenceness) { EXPECT_EQ(s.IsReference(phi), s.IsReference(param1)); } - INSTANTIATE_TEST_CASE_P( InstructionSelectorTest, InstructionSelectorPhiTest, ::testing::Values(MachineType::Float64(), MachineType::Int8(), @@ -318,11 +293,9 @@ INSTANTIATE_TEST_CASE_P( MachineType::Uint64(), MachineType::Pointer(), MachineType::AnyTagged())); - // ----------------------------------------------------------------------------- // ValueEffect. - TARGET_TEST_F(InstructionSelectorTest, ValueEffect) { StreamBuilder m1(this, MachineType::Int32(), MachineType::Pointer()); Node* p1 = m1.Parameter(0); @@ -346,11 +319,9 @@ TARGET_TEST_F(InstructionSelectorTest, ValueEffect) { } } - // ----------------------------------------------------------------------------- // Calls with deoptimization. - TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()); @@ -405,7 +376,6 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { // TODO(jarin) Check deoptimization table. } - TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeopt) { StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()); @@ -498,7 +468,6 @@ TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeopt) { EXPECT_EQ(index, s.size()); } - TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeoptRecursiveFrameState) { StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()); diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.h index 19f85ff1ff..3c4374101c 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h +++ b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.h @@ -9,7 +9,7 @@ #include <set> #include "src/base/utils/random-number-generator.h" -#include "src/compiler/instruction-selector.h" +#include "src/compiler/backend/instruction-selector.h" #include "src/compiler/raw-machine-assembler.h" #include "src/macro-assembler.h" #include "test/unittests/test-utils.h" @@ -18,8 +18,7 @@ namespace v8 { namespace internal { namespace compiler { -class InstructionSelectorTest : public TestWithContext, - public TestWithIsolateAndZone { +class InstructionSelectorTest : public TestWithNativeContextAndZone { public: InstructionSelectorTest(); ~InstructionSelectorTest() override; @@ -288,7 +287,6 @@ class InstructionSelectorTest : public TestWithContext, base::RandomNumberGenerator rng_; }; - template <typename T> class InstructionSelectorTestWithParam : public InstructionSelectorTest, diff --git a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc b/deps/v8/test/unittests/compiler/backend/instruction-sequence-unittest.cc index 2dd910aafb..f5fe72d5be 100644 --- a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc +++ b/deps/v8/test/unittests/compiler/backend/instruction-sequence-unittest.cc @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "test/unittests/compiler/backend/instruction-sequence-unittest.h" #include "src/base/utils/random-number-generator.h" #include "src/compiler/pipeline.h" -#include "test/unittests/compiler/instruction-sequence-unittest.h" #include "test/unittests/test-utils.h" #include "testing/gmock/include/gmock/gmock.h" @@ -12,48 +12,29 @@ namespace v8 { namespace internal { namespace compiler { -static const char* - general_register_names_[RegisterConfiguration::kMaxGeneralRegisters]; -static const char* - double_register_names_[RegisterConfiguration::kMaxFPRegisters]; -static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters + - RegisterConfiguration::kMaxFPRegisters)]; - namespace { -static int allocatable_codes[InstructionSequenceTest::kDefaultNRegs] = { - 0, 1, 2, 3, 4, 5, 6, 7}; -} - -static void InitializeRegisterNames() { - char* loc = register_names_; - for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) { - general_register_names_[i] = loc; - loc += base::OS::SNPrintF(loc, 100, "gp_%d", i); - *loc++ = 0; - } - for (int i = 0; i < RegisterConfiguration::kMaxFPRegisters; ++i) { - double_register_names_[i] = loc; - loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1; - *loc++ = 0; - } +constexpr int kMaxNumAllocatable = + Max(Register::kNumRegisters, DoubleRegister::kNumRegisters); +static std::array<int, kMaxNumAllocatable> kAllocatableCodes = + base::make_array<kMaxNumAllocatable>( + [](size_t i) { return static_cast<int>(i); }); } InstructionSequenceTest::InstructionSequenceTest() : sequence_(nullptr), - num_general_registers_(kDefaultNRegs), - num_double_registers_(kDefaultNRegs), + num_general_registers_(Register::kNumRegisters), + num_double_registers_(DoubleRegister::kNumRegisters), instruction_blocks_(zone()), current_block_(nullptr), - block_returns_(false) { - InitializeRegisterNames(); -} - + block_returns_(false) {} void InstructionSequenceTest::SetNumRegs(int num_general_registers, int num_double_registers) { CHECK(!config_); CHECK(instructions_.empty()); CHECK(instruction_blocks_.empty()); + CHECK_GE(Register::kNumRegisters, num_general_registers); + CHECK_GE(DoubleRegister::kNumRegisters, num_double_registers); num_general_registers_ = num_general_registers; num_double_registers_ = num_double_registers; } @@ -89,18 +70,14 @@ const RegisterConfiguration* InstructionSequenceTest::config() { if (!config_) { config_.reset(new RegisterConfiguration( num_general_registers_, num_double_registers_, num_general_registers_, - num_double_registers_, allocatable_codes, allocatable_codes, + num_double_registers_, kAllocatableCodes.data(), + kAllocatableCodes.data(), kSimpleFPAliasing ? RegisterConfiguration::OVERLAP - : RegisterConfiguration::COMBINE, - general_register_names_, - double_register_names_, // float register names - double_register_names_, - double_register_names_)); // SIMD 128 register names + : RegisterConfiguration::COMBINE)); } return config_.get(); } - InstructionSequence* InstructionSequenceTest::sequence() { if (sequence_ == nullptr) { sequence_ = new (zone()) @@ -111,7 +88,6 @@ InstructionSequence* InstructionSequenceTest::sequence() { return sequence_; } - void InstructionSequenceTest::StartLoop(int loop_blocks) { CHECK_NULL(current_block_); if (!loop_blocks_.empty()) { @@ -121,7 +97,6 @@ void InstructionSequenceTest::StartLoop(int loop_blocks) { loop_blocks_.push_back(loop_data); } - void InstructionSequenceTest::EndLoop() { CHECK_NULL(current_block_); CHECK(!loop_blocks_.empty()); @@ -129,13 +104,11 @@ void InstructionSequenceTest::EndLoop() { loop_blocks_.pop_back(); } - void InstructionSequenceTest::StartBlock(bool deferred) { block_returns_ = false; NewBlock(deferred); } - Instruction* InstructionSequenceTest::EndBlock(BlockCompletion completion) { Instruction* result = nullptr; if (block_returns_) { @@ -168,12 +141,10 @@ Instruction* InstructionSequenceTest::EndBlock(BlockCompletion completion) { return result; } - InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) { return TestOperand(kImmediate, imm); } - InstructionSequenceTest::VReg InstructionSequenceTest::Define( TestOperand output_op) { VReg vreg = NewReg(output_op); @@ -188,7 +159,6 @@ Instruction* InstructionSequenceTest::Return(TestOperand input_op_0) { return Emit(kArchRet, 0, nullptr, 1, inputs); } - PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0, VReg incoming_vreg_1, VReg incoming_vreg_2, @@ -208,7 +178,6 @@ PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0, return phi; } - PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0, size_t input_count) { auto phi = new (zone()) PhiInstruction(zone(), NewReg().value_, input_count); @@ -217,14 +186,12 @@ PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0, return phi; } - void InstructionSequenceTest::SetInput(PhiInstruction* phi, size_t input, VReg vreg) { CHECK_NE(kNoValue, vreg.value_); phi->SetInput(input, vreg.value_); } - InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant( int32_t imm) { VReg vreg = NewReg(); @@ -234,10 +201,8 @@ InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant( return vreg; } - Instruction* InstructionSequenceTest::EmitNop() { return Emit(kArchNop); } - static size_t CountInputs(size_t size, InstructionSequenceTest::TestOperand* inputs) { size_t i = 0; @@ -247,14 +212,12 @@ static size_t CountInputs(size_t size, return i; } - Instruction* InstructionSequenceTest::EmitI(size_t input_size, TestOperand* inputs) { InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); return Emit(kArchNop, 0, nullptr, input_size, mapped_inputs); } - Instruction* InstructionSequenceTest::EmitI(TestOperand input_op_0, TestOperand input_op_1, TestOperand input_op_2, @@ -263,7 +226,6 @@ Instruction* InstructionSequenceTest::EmitI(TestOperand input_op_0, return EmitI(CountInputs(arraysize(inputs), inputs), inputs); } - InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( TestOperand output_op, size_t input_size, TestOperand* inputs) { VReg output_vreg = NewReg(output_op); @@ -273,7 +235,6 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( return output_vreg; } - InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1, TestOperand input_op_2, TestOperand input_op_3) { @@ -281,7 +242,6 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( return EmitOI(output_op, CountInputs(arraysize(inputs), inputs), inputs); } - InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI( TestOperand output_op_0, TestOperand output_op_1, size_t input_size, TestOperand* inputs) { @@ -295,7 +255,6 @@ InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI( return output_vregs; } - InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI( TestOperand output_op_0, TestOperand output_op_1, TestOperand input_op_0, TestOperand input_op_1, TestOperand input_op_2, TestOperand input_op_3) { @@ -304,7 +263,6 @@ InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI( CountInputs(arraysize(inputs), inputs), inputs); } - InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( TestOperand output_op, size_t input_size, TestOperand* inputs) { VReg output_vreg = NewReg(output_op); @@ -316,7 +274,6 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( return output_vreg; } - InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1, TestOperand input_op_2, TestOperand input_op_3) { @@ -324,7 +281,6 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( return EmitCall(output_op, CountInputs(arraysize(inputs), inputs), inputs); } - Instruction* InstructionSequenceTest::EmitBranch(TestOperand input_op) { InstructionOperand inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()), ConvertInputOp(Imm()), ConvertInputOp(Imm())}; @@ -334,20 +290,17 @@ Instruction* InstructionSequenceTest::EmitBranch(TestOperand input_op) { return AddInstruction(instruction); } - Instruction* InstructionSequenceTest::EmitFallThrough() { auto instruction = NewInstruction(kArchNop, 0, nullptr); return AddInstruction(instruction); } - Instruction* InstructionSequenceTest::EmitJump() { InstructionOperand inputs[1]{ConvertInputOp(Imm())}; auto instruction = NewInstruction(kArchJmp, 0, nullptr, 1, inputs); return AddInstruction(instruction); } - Instruction* InstructionSequenceTest::NewInstruction( InstructionCode code, size_t outputs_size, InstructionOperand* outputs, size_t inputs_size, InstructionOperand* inputs, size_t temps_size, @@ -357,32 +310,27 @@ Instruction* InstructionSequenceTest::NewInstruction( inputs, temps_size, temps); } - InstructionOperand InstructionSequenceTest::Unallocated( TestOperand op, UnallocatedOperand::ExtendedPolicy policy) { return UnallocatedOperand(policy, op.vreg_.value_); } - InstructionOperand InstructionSequenceTest::Unallocated( TestOperand op, UnallocatedOperand::ExtendedPolicy policy, UnallocatedOperand::Lifetime lifetime) { return UnallocatedOperand(policy, lifetime, op.vreg_.value_); } - InstructionOperand InstructionSequenceTest::Unallocated( TestOperand op, UnallocatedOperand::ExtendedPolicy policy, int index) { return UnallocatedOperand(policy, index, op.vreg_.value_); } - InstructionOperand InstructionSequenceTest::Unallocated( TestOperand op, UnallocatedOperand::BasicPolicy policy, int index) { return UnallocatedOperand(policy, index, op.vreg_.value_); } - InstructionOperand* InstructionSequenceTest::ConvertInputs( size_t input_size, TestOperand* inputs) { InstructionOperand* mapped_inputs = @@ -393,7 +341,6 @@ InstructionOperand* InstructionSequenceTest::ConvertInputs( return mapped_inputs; } - InstructionOperand InstructionSequenceTest::ConvertInputOp(TestOperand op) { if (op.type_ == kImmediate) { CHECK_EQ(op.vreg_.value_, kNoValue); @@ -439,7 +386,6 @@ InstructionOperand InstructionSequenceTest::ConvertInputOp(TestOperand op) { UNREACHABLE(); } - InstructionOperand InstructionSequenceTest::ConvertOutputOp(VReg vreg, TestOperand op) { CHECK_EQ(op.vreg_.value_, kNoValue); @@ -474,7 +420,6 @@ InstructionOperand InstructionSequenceTest::ConvertOutputOp(VReg vreg, UNREACHABLE(); } - InstructionBlock* InstructionSequenceTest::NewBlock(bool deferred) { CHECK_NULL(current_block_); Rpo rpo = Rpo::FromInt(static_cast<int>(instruction_blocks_.size())); @@ -504,7 +449,6 @@ InstructionBlock* InstructionSequenceTest::NewBlock(bool deferred) { return instruction_block; } - void InstructionSequenceTest::WireBlocks() { CHECK(!current_block()); CHECK(instruction_blocks_.size() == completions_.size()); @@ -536,7 +480,6 @@ void InstructionSequenceTest::WireBlocks() { } } - void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) { size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset); CHECK(block_offset < instruction_blocks_.size()); @@ -547,7 +490,6 @@ void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) { target->predecessors().push_back(block->rpo_number()); } - Instruction* InstructionSequenceTest::Emit( InstructionCode code, size_t outputs_size, InstructionOperand* outputs, size_t inputs_size, InstructionOperand* inputs, size_t temps_size, @@ -558,7 +500,6 @@ Instruction* InstructionSequenceTest::Emit( return AddInstruction(instruction); } - Instruction* InstructionSequenceTest::AddInstruction(Instruction* instruction) { sequence()->AddInstruction(instruction); return instruction; diff --git a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h b/deps/v8/test/unittests/compiler/backend/instruction-sequence-unittest.h index 2c4df038fb..55dbe167c1 100644 --- a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h +++ b/deps/v8/test/unittests/compiler/backend/instruction-sequence-unittest.h @@ -7,7 +7,8 @@ #include <memory> -#include "src/compiler/instruction.h" +#include "src/compiler/backend/instruction.h" +#include "src/register-configuration.h" #include "test/unittests/test-utils.h" #include "testing/gmock/include/gmock/gmock.h" @@ -17,12 +18,14 @@ namespace compiler { class InstructionSequenceTest : public TestWithIsolateAndZone { public: - static const int kDefaultNRegs = 8; - static const int kNoValue = kMinInt; - static const MachineRepresentation kNoRep = MachineRepresentation::kNone; - static const MachineRepresentation kFloat32 = MachineRepresentation::kFloat32; - static const MachineRepresentation kFloat64 = MachineRepresentation::kFloat64; - static const MachineRepresentation kSimd128 = MachineRepresentation::kSimd128; + static constexpr int kNoValue = kMinInt; + static constexpr MachineRepresentation kNoRep = MachineRepresentation::kNone; + static constexpr MachineRepresentation kFloat32 = + MachineRepresentation::kFloat32; + static constexpr MachineRepresentation kFloat64 = + MachineRepresentation::kFloat64; + static constexpr MachineRepresentation kSimd128 = + MachineRepresentation::kSimd128; typedef RpoNumber Rpo; diff --git a/deps/v8/test/unittests/compiler/instruction-unittest.cc b/deps/v8/test/unittests/compiler/backend/instruction-unittest.cc index 72deb12d02..09b4ea9295 100644 --- a/deps/v8/test/unittests/compiler/instruction-unittest.cc +++ b/deps/v8/test/unittests/compiler/backend/instruction-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/compiler/instruction.h" +#include "src/compiler/backend/instruction.h" #include "src/register-configuration.h" #include "test/unittests/test-utils.h" #include "testing/gtest-support.h" diff --git a/deps/v8/test/unittests/compiler/code-assembler-unittest.cc b/deps/v8/test/unittests/compiler/code-assembler-unittest.cc index 8a28ef389a..68a701136f 100644 --- a/deps/v8/test/unittests/compiler/code-assembler-unittest.cc +++ b/deps/v8/test/unittests/compiler/code-assembler-unittest.cc @@ -126,6 +126,44 @@ TARGET_TEST_F(CodeAssemblerTest, IntPtrMul) { } } +TARGET_TEST_F(CodeAssemblerTest, IntPtrDiv) { + CodeAssemblerTestState state(this); + CodeAssemblerForTest m(&state); + { + TNode<IntPtrT> a = m.UncheckedCast<IntPtrT>(m.Parameter(0)); + TNode<IntPtrT> b = m.IntPtrConstant(100); + TNode<IntPtrT> div = m.IntPtrDiv(a, b); + EXPECT_THAT(div, IsIntPtrDiv(Matcher<Node*>(a), Matcher<Node*>(b))); + } + // x / 1 => x + { + TNode<IntPtrT> a = m.UncheckedCast<IntPtrT>(m.Parameter(0)); + TNode<IntPtrT> b = m.IntPtrConstant(1); + TNode<IntPtrT> div = m.IntPtrDiv(a, b); + EXPECT_THAT(div, a); + } + // CONST_a / CONST_b => CONST_c + { + TNode<IntPtrT> a = m.IntPtrConstant(100); + TNode<IntPtrT> b = m.IntPtrConstant(5); + TNode<IntPtrT> div = m.IntPtrDiv(a, b); + EXPECT_THAT(div, IsIntPtrConstant(20)); + } + { + TNode<IntPtrT> a = m.IntPtrConstant(100); + TNode<IntPtrT> b = m.IntPtrConstant(5); + TNode<IntPtrT> div = m.IntPtrDiv(a, b); + EXPECT_THAT(div, IsIntPtrConstant(20)); + } + // x / 2^CONST => x >> CONST + { + TNode<IntPtrT> a = m.UncheckedCast<IntPtrT>(m.Parameter(0)); + TNode<IntPtrT> b = m.IntPtrConstant(1 << 3); + TNode<IntPtrT> div = m.IntPtrDiv(a, b); + EXPECT_THAT(div, IsWordSar(Matcher<Node*>(a), IsIntPtrConstant(3))); + } +} + TARGET_TEST_F(CodeAssemblerTest, WordShl) { CodeAssemblerTestState state(this); CodeAssemblerForTest m(&state); diff --git a/deps/v8/test/unittests/compiler/constant-folding-reducer-unittest.cc b/deps/v8/test/unittests/compiler/constant-folding-reducer-unittest.cc index fd0845159f..640526bc90 100644 --- a/deps/v8/test/unittests/compiler/constant-folding-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/constant-folding-reducer-unittest.cc @@ -63,7 +63,7 @@ class ConstantFoldingReducerTest : public TypedGraphTest { public: ConstantFoldingReducerTest() : TypedGraphTest(3), - js_heap_broker_(isolate(), zone()), + broker_(isolate(), zone()), simplified_(zone()), deps_(isolate(), zone()) {} ~ConstantFoldingReducerTest() override = default; @@ -76,23 +76,23 @@ class ConstantFoldingReducerTest : public TypedGraphTest { &machine); // TODO(titzer): mock the GraphReducer here for better unit testing. GraphReducer graph_reducer(zone(), graph()); - ConstantFoldingReducer reducer(&graph_reducer, &jsgraph, js_heap_broker()); + ConstantFoldingReducer reducer(&graph_reducer, &jsgraph, broker()); return reducer.Reduce(node); } SimplifiedOperatorBuilder* simplified() { return &simplified_; } - JSHeapBroker* js_heap_broker() { return &js_heap_broker_; } + JSHeapBroker* broker() { return &broker_; } private: - JSHeapBroker js_heap_broker_; + JSHeapBroker broker_; SimplifiedOperatorBuilder simplified_; CompilationDependencies deps_; }; TEST_F(ConstantFoldingReducerTest, ParameterWithMinusZero) { { - Reduction r = Reduce(Parameter(Type::NewConstant( - js_heap_broker(), factory()->minus_zero_value(), zone()))); + Reduction r = Reduce(Parameter( + Type::NewConstant(broker(), factory()->minus_zero_value(), zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0)); } @@ -104,8 +104,7 @@ TEST_F(ConstantFoldingReducerTest, ParameterWithMinusZero) { { Reduction r = Reduce(Parameter(Type::Union( Type::MinusZero(), - Type::NewConstant(js_heap_broker(), factory()->NewNumber(0), zone()), - zone()))); + Type::NewConstant(broker(), factory()->NewNumber(0), zone()), zone()))); EXPECT_FALSE(r.Changed()); } } @@ -113,8 +112,7 @@ TEST_F(ConstantFoldingReducerTest, ParameterWithMinusZero) { TEST_F(ConstantFoldingReducerTest, ParameterWithNull) { Handle<HeapObject> null = factory()->null_value(); { - Reduction r = - Reduce(Parameter(Type::NewConstant(js_heap_broker(), null, zone()))); + Reduction r = Reduce(Parameter(Type::NewConstant(broker(), null, zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsHeapConstant(null)); } @@ -131,14 +129,14 @@ TEST_F(ConstantFoldingReducerTest, ParameterWithNaN) { std::numeric_limits<double>::signaling_NaN()}; TRACED_FOREACH(double, nan, kNaNs) { Handle<Object> constant = factory()->NewNumber(nan); - Reduction r = Reduce( - Parameter(Type::NewConstant(js_heap_broker(), constant, zone()))); + Reduction r = + Reduce(Parameter(Type::NewConstant(broker(), constant, zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); } { - Reduction r = Reduce(Parameter( - Type::NewConstant(js_heap_broker(), factory()->nan_value(), zone()))); + Reduction r = Reduce( + Parameter(Type::NewConstant(broker(), factory()->nan_value(), zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); } @@ -152,8 +150,8 @@ TEST_F(ConstantFoldingReducerTest, ParameterWithNaN) { TEST_F(ConstantFoldingReducerTest, ParameterWithPlainNumber) { TRACED_FOREACH(double, value, kFloat64Values) { Handle<Object> constant = factory()->NewNumber(value); - Reduction r = Reduce( - Parameter(Type::NewConstant(js_heap_broker(), constant, zone()))); + Reduction r = + Reduce(Parameter(Type::NewConstant(broker(), constant, zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsNumberConstant(value)); } @@ -172,8 +170,8 @@ TEST_F(ConstantFoldingReducerTest, ParameterWithUndefined) { EXPECT_THAT(r.replacement(), IsHeapConstant(undefined)); } { - Reduction r = Reduce( - Parameter(Type::NewConstant(js_heap_broker(), undefined, zone()))); + Reduction r = + Reduce(Parameter(Type::NewConstant(broker(), undefined, zone()))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsHeapConstant(undefined)); } @@ -194,10 +192,10 @@ TEST_F(ConstantFoldingReducerTest, ToBooleanWithFalsish) { Type::Undefined(), Type::Union( Type::Undetectable(), - Type::Union(Type::NewConstant( - js_heap_broker(), - factory()->false_value(), zone()), - Type::Range(0.0, 0.0, zone()), zone()), + Type::Union( + Type::NewConstant( + broker(), factory()->false_value(), zone()), + Type::Range(0.0, 0.0, zone()), zone()), zone()), zone()), zone()), @@ -212,7 +210,7 @@ TEST_F(ConstantFoldingReducerTest, ToBooleanWithFalsish) { TEST_F(ConstantFoldingReducerTest, ToBooleanWithTruish) { Node* input = Parameter( Type::Union( - Type::NewConstant(js_heap_broker(), factory()->true_value(), zone()), + Type::NewConstant(broker(), factory()->true_value(), zone()), Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()), zone()), 0); diff --git a/deps/v8/test/unittests/compiler/graph-unittest.cc b/deps/v8/test/unittests/compiler/graph-unittest.cc index 4736ddefa2..051aa68e64 100644 --- a/deps/v8/test/unittests/compiler/graph-unittest.cc +++ b/deps/v8/test/unittests/compiler/graph-unittest.cc @@ -15,17 +15,15 @@ namespace internal { namespace compiler { GraphTest::GraphTest(int num_parameters) - : TestWithNativeContext(), - TestWithIsolateAndZone(), - canonical_(isolate()), + : canonical_(isolate()), common_(zone()), graph_(zone()), - js_heap_broker_(isolate(), zone()), + broker_(isolate(), zone()), source_positions_(&graph_), node_origins_(&graph_) { graph()->SetStart(graph()->NewNode(common()->Start(num_parameters))); graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start())); - js_heap_broker()->SetNativeContextRef(); + broker()->SetNativeContextRef(); } @@ -69,7 +67,7 @@ Node* GraphTest::NumberConstant(volatile double value) { Node* GraphTest::HeapConstant(const Handle<HeapObject>& value) { Node* node = graph()->NewNode(common()->HeapConstant(value)); - Type type = Type::NewConstant(js_heap_broker(), value, zone()); + Type type = Type::NewConstant(broker(), value, zone()); NodeProperties::SetType(node, type); return node; } @@ -119,8 +117,7 @@ Matcher<Node*> GraphTest::IsUndefinedConstant() { } TypedGraphTest::TypedGraphTest(int num_parameters) - : GraphTest(num_parameters), - typer_(js_heap_broker(), Typer::kNoFlags, graph()) {} + : GraphTest(num_parameters), typer_(broker(), Typer::kNoFlags, graph()) {} TypedGraphTest::~TypedGraphTest() = default; diff --git a/deps/v8/test/unittests/compiler/graph-unittest.h b/deps/v8/test/unittests/compiler/graph-unittest.h index 8317ebf279..a4b719fe6b 100644 --- a/deps/v8/test/unittests/compiler/graph-unittest.h +++ b/deps/v8/test/unittests/compiler/graph-unittest.h @@ -24,8 +24,7 @@ namespace compiler { using ::testing::Matcher; -class GraphTest : public virtual TestWithNativeContext, - public virtual TestWithIsolateAndZone { +class GraphTest : public TestWithNativeContextAndZone { public: explicit GraphTest(int num_parameters = 1); ~GraphTest() override; @@ -62,13 +61,13 @@ class GraphTest : public virtual TestWithNativeContext, Graph* graph() { return &graph_; } SourcePositionTable* source_positions() { return &source_positions_; } NodeOriginTable* node_origins() { return &node_origins_; } - JSHeapBroker* js_heap_broker() { return &js_heap_broker_; } + JSHeapBroker* broker() { return &broker_; } private: CanonicalHandleScope canonical_; CommonOperatorBuilder common_; Graph graph_; - JSHeapBroker js_heap_broker_; + JSHeapBroker broker_; SourcePositionTable source_positions_; NodeOriginTable node_origins_; }; diff --git a/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc b/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc index 5b808eab25..65903506ad 100644 --- a/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc +++ b/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/unittests/compiler/instruction-selector-unittest.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" #include "src/objects-inl.h" diff --git a/deps/v8/test/unittests/compiler/js-call-reducer-unittest.cc b/deps/v8/test/unittests/compiler/js-call-reducer-unittest.cc index 7660f5851e..171658d830 100644 --- a/deps/v8/test/unittests/compiler/js-call-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-call-reducer-unittest.cc @@ -22,9 +22,7 @@ class JSCallReducerTest : public TypedGraphTest { public: JSCallReducerTest() : TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) { - if (FLAG_concurrent_compiler_frontend) { - js_heap_broker()->SerializeStandardObjects(); - } + broker()->SerializeStandardObjects(); } ~JSCallReducerTest() override = default; @@ -37,24 +35,13 @@ class JSCallReducerTest : public TypedGraphTest { // TODO(titzer): mock the GraphReducer here for better unit testing. GraphReducer graph_reducer(zone(), graph()); - JSCallReducer reducer(&graph_reducer, &jsgraph, js_heap_broker(), - JSCallReducer::kNoFlags, native_context(), &deps_); + JSCallReducer reducer(&graph_reducer, &jsgraph, broker(), + JSCallReducer::kNoFlags, &deps_); return reducer.Reduce(node); } JSOperatorBuilder* javascript() { return &javascript_; } - static void SetUpTestCase() { - old_flag_lazy_ = i::FLAG_lazy_deserialization; - i::FLAG_lazy_deserialization = false; - TypedGraphTest::SetUpTestCase(); - } - - static void TearDownTestCase() { - TypedGraphTest::TearDownTestCase(); - i::FLAG_lazy_deserialization = old_flag_lazy_; - } - Node* GlobalFunction(const char* name) { Handle<JSFunction> f = Handle<JSFunction>::cast( Object::GetProperty( @@ -131,9 +118,6 @@ class JSCallReducerTest : public TypedGraphTest { private: JSOperatorBuilder javascript_; CompilationDependencies deps_; - - static bool old_flag_lazy_; - static bool old_flag_lazy_handler_; }; TEST_F(JSCallReducerTest, PromiseConstructorNoArgs) { @@ -217,9 +201,6 @@ TEST_F(JSCallReducerTest, PromiseConstructorWithHook) { ASSERT_FALSE(r.Changed()); } -bool JSCallReducerTest::old_flag_lazy_; -bool JSCallReducerTest::old_flag_lazy_handler_; - // ----------------------------------------------------------------------------- // Math unaries diff --git a/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc index eafd7fa35e..41f0c180e6 100644 --- a/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc @@ -45,7 +45,7 @@ class JSCreateLoweringTest : public TypedGraphTest { &machine); // TODO(titzer): mock the GraphReducer here for better unit testing. GraphReducer graph_reducer(zone(), graph()); - JSCreateLowering reducer(&graph_reducer, &deps_, &jsgraph, js_heap_broker(), + JSCreateLowering reducer(&graph_reducer, &deps_, &jsgraph, broker(), zone()); return reducer.Reduce(node); } @@ -75,8 +75,8 @@ class JSCreateLoweringTest : public TypedGraphTest { TEST_F(JSCreateLoweringTest, JSCreate) { Handle<JSFunction> function = isolate()->object_function(); - Node* const target = Parameter( - Type::HeapConstant(js_heap_broker(), function, graph()->zone())); + Node* const target = + Parameter(Type::HeapConstant(broker(), function, graph()->zone())); Node* const context = Parameter(Type::Any()); Node* const effect = graph()->start(); Node* const control = graph()->start(); diff --git a/deps/v8/test/unittests/compiler/js-native-context-specialization-unittest.cc b/deps/v8/test/unittests/compiler/js-native-context-specialization-unittest.cc index fdc87904c4..bf9a144fab 100644 --- a/deps/v8/test/unittests/compiler/js-native-context-specialization-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-native-context-specialization-unittest.cc @@ -34,14 +34,14 @@ TEST_F(JSNativeContextSpecializationTest, GetMaxStringLengthOfString) { Node* const str_node = graph()->NewNode( common()->HeapConstant(factory()->InternalizeUtf8String("str"))); - EXPECT_EQ(JSNativeContextSpecialization::GetMaxStringLength(js_heap_broker(), - str_node), - str_len); + EXPECT_EQ( + JSNativeContextSpecialization::GetMaxStringLength(broker(), str_node), + str_len); Node* const num_node = graph()->NewNode(common()->NumberConstant(10.0 / 3)); - EXPECT_EQ(JSNativeContextSpecialization::GetMaxStringLength(js_heap_broker(), - num_node), - num_len); + EXPECT_EQ( + JSNativeContextSpecialization::GetMaxStringLength(broker(), num_node), + num_len); } } // namespace js_native_context_specialization_unittest diff --git a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc index 43998824d2..b3326b0ad4 100644 --- a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -48,12 +48,13 @@ class JSTypedLoweringTest : public TypedGraphTest { &machine); // TODO(titzer): mock the GraphReducer here for better unit testing. GraphReducer graph_reducer(zone(), graph()); - JSTypedLowering reducer(&graph_reducer, &jsgraph, js_heap_broker(), zone()); + JSTypedLowering reducer(&graph_reducer, &jsgraph, broker(), zone()); return reducer.Reduce(node); } Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) { - Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer(); + Handle<JSArrayBuffer> buffer = + factory()->NewJSArrayBuffer(SharedFlag::kNotShared); JSArrayBuffer::Setup(buffer, isolate(), true, bytes, byte_length); return buffer; } diff --git a/deps/v8/test/unittests/compiler/live-range-builder.h b/deps/v8/test/unittests/compiler/live-range-builder.h deleted file mode 100644 index 4a5621fab7..0000000000 --- a/deps/v8/test/unittests/compiler/live-range-builder.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2015 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_LIVE_RANGE_BUILDER_H_ -#define V8_LIVE_RANGE_BUILDER_H_ - -#include "src/compiler/register-allocator.h" - -namespace v8 { -namespace internal { -namespace compiler { - - -// Utility offering shorthand syntax for building up a range by providing its ID -// and pairs (start, end) specifying intervals. Circumvents current incomplete -// support for C++ features such as instantiation lists, on OS X and Android. -class TestRangeBuilder { - public: - explicit TestRangeBuilder(Zone* zone) - : id_(-1), pairs_(), uses_(), zone_(zone) {} - - TestRangeBuilder& Id(int id) { - id_ = id; - return *this; - } - TestRangeBuilder& Add(int start, int end) { - pairs_.push_back({start, end}); - return *this; - } - - TestRangeBuilder& AddUse(int pos) { - uses_.insert(pos); - return *this; - } - - TopLevelLiveRange* Build(int start, int end) { - return Add(start, end).Build(); - } - - TopLevelLiveRange* Build() { - TopLevelLiveRange* range = - new (zone_) TopLevelLiveRange(id_, MachineRepresentation::kTagged); - // Traverse the provided interval specifications backwards, because that is - // what LiveRange expects. - for (int i = static_cast<int>(pairs_.size()) - 1; i >= 0; --i) { - Interval pair = pairs_[i]; - LifetimePosition start = LifetimePosition::FromInt(pair.first); - LifetimePosition end = LifetimePosition::FromInt(pair.second); - CHECK(start < end); - range->AddUseInterval(start, end, zone_); - } - for (int pos : uses_) { - UsePosition* use_position = - new (zone_) UsePosition(LifetimePosition::FromInt(pos), nullptr, - nullptr, UsePositionHintType::kNone); - range->AddUsePosition(use_position); - } - - pairs_.clear(); - return range; - } - - private: - typedef std::pair<int, int> Interval; - typedef std::vector<Interval> IntervalList; - int id_; - IntervalList pairs_; - std::set<int> uses_; - Zone* zone_; -}; - - -} // namespace compiler -} // namespace internal -} // namespace v8 - -#endif // V8_LIVE_RANGE_BUILDER_H_ diff --git a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc index b8b0c9004f..cd70b3bc41 100644 --- a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -6,6 +6,7 @@ #include "src/base/bits.h" #include "src/base/division-by-constant.h" #include "src/base/ieee754.h" +#include "src/base/overflowing-math.h" #include "src/compiler/js-graph.h" #include "src/compiler/typer.h" #include "src/conversions-inl.h" @@ -26,14 +27,20 @@ namespace compiler { class MachineOperatorReducerTest : public GraphTest { public: explicit MachineOperatorReducerTest(int num_parameters = 2) - : GraphTest(num_parameters), machine_(zone()) {} + : GraphTest(num_parameters), + machine_(zone()), + common_(zone()), + javascript_(zone()), + jsgraph_(isolate(), graph(), &common_, &javascript_, nullptr, + &machine_), + graph_reducer_(zone(), graph(), jsgraph_.Dead()) {} protected: Reduction Reduce(Node* node) { JSOperatorBuilder javascript(zone()); JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr, &machine_); - MachineOperatorReducer reducer(&jsgraph); + MachineOperatorReducer reducer(&graph_reducer_, &jsgraph); return reducer.Reduce(node); } @@ -61,6 +68,10 @@ class MachineOperatorReducerTest : public GraphTest { private: MachineOperatorBuilder machine_; + CommonOperatorBuilder common_; + JSOperatorBuilder javascript_; + JSGraph jsgraph_; + GraphReducer graph_reducer_; }; @@ -968,7 +979,8 @@ TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndLoad) { TEST_F(MachineOperatorReducerTest, Word32ShrWithWord32And) { Node* const p0 = Parameter(0); TRACED_FORRANGE(int32_t, shift, 1, 31) { - uint32_t mask = (1 << shift) - 1; + uint32_t mask = + base::SubWithWraparound(base::ShlWithWraparound(1, shift), 1); Node* node = graph()->NewNode( machine()->Word32Shr(), graph()->NewNode(machine()->Word32And(), p0, Int32Constant(mask)), @@ -1057,7 +1069,9 @@ TEST_F(MachineOperatorReducerTest, Int32SubWithConstant) { if (k == 0) { EXPECT_EQ(p0, r.replacement()); } else { - EXPECT_THAT(r.replacement(), IsInt32Add(p0, IsInt32Constant(-k))); + EXPECT_THAT( + r.replacement(), + IsInt32Add(p0, IsInt32Constant(base::NegateWithWraparound(k)))); } } } diff --git a/deps/v8/test/unittests/compiler/machine-operator-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-unittest.cc index eea7276f6f..9eddb1d311 100644 --- a/deps/v8/test/unittests/compiler/machine-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/machine-operator-unittest.cc @@ -13,8 +13,6 @@ namespace internal { namespace compiler { namespace machine_operator_unittest { -#if GTEST_HAS_COMBINE - template <typename T> class MachineOperatorTestWithParam : public TestWithZone, @@ -159,7 +157,6 @@ INSTANTIATE_TEST_CASE_P( ::testing::Combine(::testing::ValuesIn(kRepresentationsForStore), ::testing::Values(kNoWriteBarrier, kFullWriteBarrier)))); -#endif // ----------------------------------------------------------------------------- // Pure operators. diff --git a/deps/v8/test/unittests/compiler/mips/OWNERS b/deps/v8/test/unittests/compiler/mips/OWNERS index 8bbcab4c2d..b455d9ef29 100644 --- a/deps/v8/test/unittests/compiler/mips/OWNERS +++ b/deps/v8/test/unittests/compiler/mips/OWNERS @@ -1,2 +1,3 @@ -ibogosavljevic@wavecomp.com -skovacevic@wavecomp.com
\ No newline at end of file +arikalo@wavecomp.com +prudic@wavecomp.com +skovacevic@wavecomp.com diff --git a/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc b/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc index 15f5de7b2f..83edb6a21e 100644 --- a/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc +++ b/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file -#include "test/unittests/compiler/instruction-selector-unittest.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" #include "src/objects-inl.h" diff --git a/deps/v8/test/unittests/compiler/mips64/OWNERS b/deps/v8/test/unittests/compiler/mips64/OWNERS index 8bbcab4c2d..b455d9ef29 100644 --- a/deps/v8/test/unittests/compiler/mips64/OWNERS +++ b/deps/v8/test/unittests/compiler/mips64/OWNERS @@ -1,2 +1,3 @@ -ibogosavljevic@wavecomp.com -skovacevic@wavecomp.com
\ No newline at end of file +arikalo@wavecomp.com +prudic@wavecomp.com +skovacevic@wavecomp.com diff --git a/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc b/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc index c090e29321..c6c1ff3ee8 100644 --- a/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc +++ b/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file -#include "test/unittests/compiler/instruction-selector-unittest.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" #include "src/objects-inl.h" diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc index 0b3d8786f8..f23265e8e4 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.cc +++ b/deps/v8/test/unittests/compiler/node-test-utils.cc @@ -6,7 +6,6 @@ #include <vector> -#include "src/assembler.h" #include "src/compiler/common-operator.h" #include "src/compiler/js-operator.h" #include "src/compiler/node-properties.h" @@ -2152,6 +2151,7 @@ IS_BINOP_MATCHER(Word64Equal) IS_BINOP_MATCHER(Int32AddWithOverflow) IS_BINOP_MATCHER(Int32SubWithOverflow) IS_BINOP_MATCHER(Int32Add) +IS_BINOP_MATCHER(Int32Div) IS_BINOP_MATCHER(Int32Sub) IS_BINOP_MATCHER(Int32Mul) IS_BINOP_MATCHER(Int32MulHigh) @@ -2159,6 +2159,7 @@ IS_BINOP_MATCHER(Int32LessThan) IS_BINOP_MATCHER(Uint32LessThan) IS_BINOP_MATCHER(Uint32LessThanOrEqual) IS_BINOP_MATCHER(Int64Add) +IS_BINOP_MATCHER(Int64Div) IS_BINOP_MATCHER(Int64Sub) IS_BINOP_MATCHER(Int64Mul) IS_BINOP_MATCHER(JSAdd) @@ -2255,22 +2256,14 @@ IS_UNOP_MATCHER(TaggedPoisonOnSpeculation) // Special-case Bitcast operators which are disabled when ENABLE_VERIFY_CSA is // not enabled. Matcher<Node*> IsBitcastTaggedToWord(const Matcher<Node*>& input_matcher) { -#ifdef ENABLE_VERIFY_CSA return MakeMatcher( new IsUnopMatcher(IrOpcode::kBitcastTaggedToWord, input_matcher)); -#else - return input_matcher; -#endif } Matcher<Node*> IsBitcastWordToTaggedSigned( const Matcher<Node*>& input_matcher) { -#ifdef ENABLE_VERIFY_CSA return MakeMatcher( new IsUnopMatcher(IrOpcode::kBitcastWordToTaggedSigned, input_matcher)); -#else - return input_matcher; -#endif } #undef LOAD_MATCHER diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h index 4e9c32e6d6..96bdbdf3be 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.h +++ b/deps/v8/test/unittests/compiler/node-test-utils.h @@ -387,6 +387,8 @@ Matcher<Node*> IsInt32Add(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsInt32Sub(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsInt32Div(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsInt32Mul(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsInt32MulHigh(const Matcher<Node*>& lhs_matcher, @@ -403,6 +405,8 @@ Matcher<Node*> IsInt64Sub(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsInt64Mul(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsInt64Div(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsJSAdd(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsJSParseInt(const Matcher<Node*>& lhs_matcher, @@ -517,6 +521,12 @@ static inline Matcher<Node*> IsIntPtrMul(const Matcher<Node*>& lhs_matcher, : IsInt32Mul(lhs_matcher, rhs_matcher); } +static inline Matcher<Node*> IsIntPtrDiv(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher) { + return kPointerSize == 8 ? IsInt64Div(lhs_matcher, rhs_matcher) + : IsInt32Div(lhs_matcher, rhs_matcher); +} + static inline Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher) diff --git a/deps/v8/test/unittests/compiler/persistent-unittest.cc b/deps/v8/test/unittests/compiler/persistent-unittest.cc index 8454aeaeb1..4c5a1974c7 100644 --- a/deps/v8/test/unittests/compiler/persistent-unittest.cc +++ b/deps/v8/test/unittests/compiler/persistent-unittest.cc @@ -83,19 +83,19 @@ TEST(PersistentMap, Zip) { // Provoke hash collisions to stress the iterator. struct bad_hash { - size_t operator()(int key) { + size_t operator()(uint32_t key) { return base::hash_value(static_cast<size_t>(key) % 1000); } }; - PersistentMap<int, int, bad_hash> a(&zone); - PersistentMap<int, int, bad_hash> b(&zone); + PersistentMap<int, uint32_t, bad_hash> a(&zone); + PersistentMap<int, uint32_t, bad_hash> b(&zone); - int sum_a = 0; - int sum_b = 0; + uint32_t sum_a = 0; + uint32_t sum_b = 0; for (int i = 0; i < 30000; ++i) { int key = small_big_distr(&rand); - int value = small_big_distr(&rand); + uint32_t value = small_big_distr(&rand); if (rand.NextBool()) { sum_a += value; a.Set(key, a.Get(key) + value); @@ -105,28 +105,28 @@ TEST(PersistentMap, Zip) { } } - int sum = sum_a + sum_b; + uint32_t sum = sum_a + sum_b; for (auto pair : a) { sum_a -= pair.second; } - ASSERT_EQ(0, sum_a); + ASSERT_EQ(0u, sum_a); for (auto pair : b) { sum_b -= pair.second; } - ASSERT_EQ(0, sum_b); + ASSERT_EQ(0u, sum_b); for (auto triple : a.Zip(b)) { int key = std::get<0>(triple); - int value_a = std::get<1>(triple); - int value_b = std::get<2>(triple); + uint32_t value_a = std::get<1>(triple); + uint32_t value_b = std::get<2>(triple); ASSERT_EQ(value_a, a.Get(key)); ASSERT_EQ(value_b, b.Get(key)); sum -= value_a; sum -= value_b; } - ASSERT_EQ(0, sum); + ASSERT_EQ(0u, sum); } } // namespace compiler diff --git a/deps/v8/test/unittests/compiler/ppc/OWNERS b/deps/v8/test/unittests/compiler/ppc/OWNERS index eb007cb908..6d1a8fc472 100644 --- a/deps/v8/test/unittests/compiler/ppc/OWNERS +++ b/deps/v8/test/unittests/compiler/ppc/OWNERS @@ -1,5 +1,4 @@ jyan@ca.ibm.com -dstence@us.ibm.com joransiu@ca.ibm.com -mbrandy@us.ibm.com michael_dawson@ca.ibm.com +miladfar@ca.ibm.com
\ No newline at end of file diff --git a/deps/v8/test/unittests/compiler/ppc/instruction-selector-ppc-unittest.cc b/deps/v8/test/unittests/compiler/ppc/instruction-selector-ppc-unittest.cc index 86f7d69ec9..611e766edb 100644 --- a/deps/v8/test/unittests/compiler/ppc/instruction-selector-ppc-unittest.cc +++ b/deps/v8/test/unittests/compiler/ppc/instruction-selector-ppc-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/unittests/compiler/instruction-selector-unittest.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" #include "src/assembler-inl.h" diff --git a/deps/v8/test/unittests/compiler/redundancy-elimination-unittest.cc b/deps/v8/test/unittests/compiler/redundancy-elimination-unittest.cc index f3ecd228a5..079cc4b99a 100644 --- a/deps/v8/test/unittests/compiler/redundancy-elimination-unittest.cc +++ b/deps/v8/test/unittests/compiler/redundancy-elimination-unittest.cc @@ -133,6 +133,67 @@ TEST_F(RedundancyEliminationTest, CheckNumberSubsumedByCheckSmi) { } // ----------------------------------------------------------------------------- +// CheckReceiver + +TEST_F(RedundancyEliminationTest, CheckReceiver) { + Node* value = Parameter(0); + Node* effect = graph()->start(); + Node* control = graph()->start(); + + Node* check1 = effect = + graph()->NewNode(simplified()->CheckReceiver(), value, effect, control); + Reduction r1 = Reduce(check1); + ASSERT_TRUE(r1.Changed()); + EXPECT_EQ(r1.replacement(), check1); + + Node* check2 = effect = + graph()->NewNode(simplified()->CheckReceiver(), value, effect, control); + Reduction r2 = Reduce(check2); + ASSERT_TRUE(r2.Changed()); + EXPECT_EQ(r2.replacement(), check1); +} + +// ----------------------------------------------------------------------------- +// CheckReceiverOrNullOrUndefined + +TEST_F(RedundancyEliminationTest, CheckReceiverOrNullOrUndefined) { + Node* value = Parameter(0); + Node* effect = graph()->start(); + Node* control = graph()->start(); + + Node* check1 = effect = graph()->NewNode( + simplified()->CheckReceiverOrNullOrUndefined(), value, effect, control); + Reduction r1 = Reduce(check1); + ASSERT_TRUE(r1.Changed()); + EXPECT_EQ(r1.replacement(), check1); + + Node* check2 = effect = graph()->NewNode( + simplified()->CheckReceiverOrNullOrUndefined(), value, effect, control); + Reduction r2 = Reduce(check2); + ASSERT_TRUE(r2.Changed()); + EXPECT_EQ(r2.replacement(), check1); +} + +TEST_F(RedundancyEliminationTest, + CheckReceiverOrNullOrUndefinedSubsumedByCheckReceiver) { + Node* value = Parameter(0); + Node* effect = graph()->start(); + Node* control = graph()->start(); + + Node* check1 = effect = + graph()->NewNode(simplified()->CheckReceiver(), value, effect, control); + Reduction r1 = Reduce(check1); + ASSERT_TRUE(r1.Changed()); + EXPECT_EQ(r1.replacement(), check1); + + Node* check2 = effect = graph()->NewNode( + simplified()->CheckReceiverOrNullOrUndefined(), value, effect, control); + Reduction r2 = Reduce(check2); + ASSERT_TRUE(r2.Changed()); + EXPECT_EQ(r2.replacement(), check1); +} + +// ----------------------------------------------------------------------------- // CheckString TEST_F(RedundancyEliminationTest, @@ -207,6 +268,35 @@ TEST_F(RedundancyEliminationTest, CheckedFloat64ToInt32) { } // ----------------------------------------------------------------------------- +// CheckedFloat64ToInt64 + +TEST_F(RedundancyEliminationTest, CheckedFloat64ToInt64) { + TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { + TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { + TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) { + Node* value = Parameter(0); + Node* effect = graph()->start(); + Node* control = graph()->start(); + + Node* check1 = effect = graph()->NewNode( + simplified()->CheckedFloat64ToInt64(mode, feedback1), value, effect, + control); + Reduction r1 = Reduce(check1); + ASSERT_TRUE(r1.Changed()); + EXPECT_EQ(r1.replacement(), check1); + + Node* check2 = effect = graph()->NewNode( + simplified()->CheckedFloat64ToInt64(mode, feedback2), value, effect, + control); + Reduction r2 = Reduce(check2); + ASSERT_TRUE(r2.Changed()); + EXPECT_EQ(r2.replacement(), check1); + } + } + } +} + +// ----------------------------------------------------------------------------- // CheckedInt32ToTaggedSigned TEST_F(RedundancyEliminationTest, CheckedInt32ToTaggedSigned) { @@ -427,6 +517,35 @@ TEST_F(RedundancyEliminationTest, } // ----------------------------------------------------------------------------- +// CheckedTaggedToInt64 + +TEST_F(RedundancyEliminationTest, CheckedTaggedToInt64) { + TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { + TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { + TRACED_FOREACH(CheckForMinusZeroMode, mode, kCheckForMinusZeroModes) { + Node* value = Parameter(0); + Node* effect = graph()->start(); + Node* control = graph()->start(); + + Node* check1 = effect = graph()->NewNode( + simplified()->CheckedTaggedToInt64(mode, feedback1), value, effect, + control); + Reduction r1 = Reduce(check1); + ASSERT_TRUE(r1.Changed()); + EXPECT_EQ(r1.replacement(), check1); + + Node* check2 = effect = graph()->NewNode( + simplified()->CheckedTaggedToInt64(mode, feedback2), value, effect, + control); + Reduction r2 = Reduce(check2); + ASSERT_TRUE(r2.Changed()); + EXPECT_EQ(r2.replacement(), check1); + } + } + } +} + +// ----------------------------------------------------------------------------- // CheckedTaggedToTaggedPointer TEST_F(RedundancyEliminationTest, CheckedTaggedToTaggedPointer) { @@ -539,6 +658,34 @@ TEST_F(RedundancyEliminationTest, } // ----------------------------------------------------------------------------- +// CheckedUint32Bounds + +TEST_F(RedundancyEliminationTest, CheckedUint32Bounds) { + TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { + TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { + Node* index = Parameter(0); + Node* length = Parameter(1); + Node* effect = graph()->start(); + Node* control = graph()->start(); + + Node* check1 = effect = + graph()->NewNode(simplified()->CheckedUint32Bounds(feedback1), index, + length, effect, control); + Reduction r1 = Reduce(check1); + ASSERT_TRUE(r1.Changed()); + EXPECT_EQ(r1.replacement(), check1); + + Node* check2 = effect = + graph()->NewNode(simplified()->CheckedUint32Bounds(feedback2), index, + length, effect, control); + Reduction r2 = Reduce(check2); + ASSERT_TRUE(r2.Changed()); + EXPECT_EQ(r2.replacement(), check1); + } + } +} + +// ----------------------------------------------------------------------------- // CheckedUint32ToInt32 TEST_F(RedundancyEliminationTest, CheckedUint32ToInt32) { @@ -593,6 +740,34 @@ TEST_F(RedundancyEliminationTest, CheckedUint32ToTaggedSigned) { } // ----------------------------------------------------------------------------- +// CheckedUint64Bounds + +TEST_F(RedundancyEliminationTest, CheckedUint64Bounds) { + TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { + TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { + Node* index = Parameter(0); + Node* length = Parameter(1); + Node* effect = graph()->start(); + Node* control = graph()->start(); + + Node* check1 = effect = + graph()->NewNode(simplified()->CheckedUint64Bounds(feedback1), index, + length, effect, control); + Reduction r1 = Reduce(check1); + ASSERT_TRUE(r1.Changed()); + EXPECT_EQ(r1.replacement(), check1); + + Node* check2 = effect = + graph()->NewNode(simplified()->CheckedUint64Bounds(feedback2), index, + length, effect, control); + Reduction r2 = Reduce(check2); + ASSERT_TRUE(r2.Changed()); + EXPECT_EQ(r2.replacement(), check1); + } + } +} + +// ----------------------------------------------------------------------------- // CheckedUint64ToInt32 TEST_F(RedundancyEliminationTest, CheckedUint64ToInt32) { @@ -651,7 +826,7 @@ TEST_F(RedundancyEliminationTest, CheckedUint64ToTaggedSigned) { TEST_F(RedundancyEliminationTest, SpeculativeNumberEqualWithCheckBoundsBetterType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { Node* lhs = Parameter(Type::Any(), 0); @@ -687,7 +862,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeNumberEqualWithCheckBoundsSameType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { Node* lhs = Parameter(Type::UnsignedSmall(), 0); @@ -726,7 +901,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeNumberLessThanWithCheckBoundsBetterType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { Node* lhs = Parameter(Type::Any(), 0); @@ -762,7 +937,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeNumberLessThanWithCheckBoundsSameType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { Node* lhs = Parameter(Type::UnsignedSmall(), 0); @@ -801,7 +976,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeNumberLessThanOrEqualWithCheckBoundsBetterType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { Node* lhs = Parameter(Type::Any(), 0); @@ -837,7 +1012,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeNumberLessThanOrEqualWithCheckBoundsSameType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { Node* lhs = Parameter(Type::UnsignedSmall(), 0); @@ -876,7 +1051,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeNumberAddWithCheckBoundsBetterType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { Node* lhs = Parameter(Type::Any(), 0); @@ -902,7 +1077,7 @@ TEST_F(RedundancyEliminationTest, } TEST_F(RedundancyEliminationTest, SpeculativeNumberAddWithCheckBoundsSameType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0); @@ -932,7 +1107,7 @@ TEST_F(RedundancyEliminationTest, SpeculativeNumberAddWithCheckBoundsSameType) { TEST_F(RedundancyEliminationTest, SpeculativeNumberSubtractWithCheckBoundsBetterType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { Node* lhs = Parameter(Type::Any(), 0); @@ -960,7 +1135,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeNumberSubtractWithCheckBoundsSameType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0); @@ -991,7 +1166,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeSafeIntegerAddWithCheckBoundsBetterType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { Node* lhs = Parameter(Type::Any(), 0); @@ -1019,7 +1194,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeSafeIntegerAddWithCheckBoundsSameType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0); @@ -1050,7 +1225,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeSafeIntegerSubtractWithCheckBoundsBetterType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { Node* lhs = Parameter(Type::Any(), 0); @@ -1078,7 +1253,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeSafeIntegerSubtractWithCheckBoundsSameType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { Node* lhs = Parameter(Type::Range(42.0, 42.0, zone()), 0); @@ -1109,7 +1284,7 @@ TEST_F(RedundancyEliminationTest, TEST_F(RedundancyEliminationTest, SpeculativeToNumberWithCheckBoundsBetterType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { @@ -1137,7 +1312,7 @@ TEST_F(RedundancyEliminationTest, } TEST_F(RedundancyEliminationTest, SpeculativeToNumberWithCheckBoundsSameType) { - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); TRACED_FOREACH(VectorSlotPair, feedback1, vector_slot_pairs()) { TRACED_FOREACH(VectorSlotPair, feedback2, vector_slot_pairs()) { TRACED_FOREACH(NumberOperationHint, hint, kNumberOperationHints) { diff --git a/deps/v8/test/unittests/compiler/regalloc/live-range-unittest.cc b/deps/v8/test/unittests/compiler/regalloc/live-range-unittest.cc index fc7b268b44..9ac6ca8810 100644 --- a/deps/v8/test/unittests/compiler/regalloc/live-range-unittest.cc +++ b/deps/v8/test/unittests/compiler/regalloc/live-range-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/unittests/compiler/live-range-builder.h" +#include "src/compiler/backend/register-allocator.h" #include "test/unittests/test-utils.h" // TODO(mtrofin): would we want to centralize this definition? @@ -20,6 +20,64 @@ namespace v8 { namespace internal { namespace compiler { +// Utility offering shorthand syntax for building up a range by providing its ID +// and pairs (start, end) specifying intervals. Circumvents current incomplete +// support for C++ features such as instantiation lists, on OS X and Android. +class TestRangeBuilder { + public: + explicit TestRangeBuilder(Zone* zone) + : id_(-1), pairs_(), uses_(), zone_(zone) {} + + TestRangeBuilder& Id(int id) { + id_ = id; + return *this; + } + TestRangeBuilder& Add(int start, int end) { + pairs_.push_back({start, end}); + return *this; + } + + TestRangeBuilder& AddUse(int pos) { + uses_.insert(pos); + return *this; + } + + TopLevelLiveRange* Build(int start, int end) { + return Add(start, end).Build(); + } + + TopLevelLiveRange* Build() { + TopLevelLiveRange* range = + new (zone_) TopLevelLiveRange(id_, MachineRepresentation::kTagged); + // Traverse the provided interval specifications backwards, because that is + // what LiveRange expects. + for (int i = static_cast<int>(pairs_.size()) - 1; i >= 0; --i) { + Interval pair = pairs_[i]; + LifetimePosition start = LifetimePosition::FromInt(pair.first); + LifetimePosition end = LifetimePosition::FromInt(pair.second); + CHECK(start < end); + range->AddUseInterval(start, end, zone_); + } + for (int pos : uses_) { + UsePosition* use_position = + new (zone_) UsePosition(LifetimePosition::FromInt(pos), nullptr, + nullptr, UsePositionHintType::kNone); + range->AddUsePosition(use_position); + } + + pairs_.clear(); + return range; + } + + private: + typedef std::pair<int, int> Interval; + typedef std::vector<Interval> IntervalList; + int id_; + IntervalList pairs_; + std::set<int> uses_; + Zone* zone_; +}; + class LiveRangeUnitTest : public TestWithZone { public: // Split helper, to avoid int->LifetimePosition conversion nuisance. diff --git a/deps/v8/test/unittests/compiler/regalloc/move-optimizer-unittest.cc b/deps/v8/test/unittests/compiler/regalloc/move-optimizer-unittest.cc index 71767a964e..23f17b2b6c 100644 --- a/deps/v8/test/unittests/compiler/regalloc/move-optimizer-unittest.cc +++ b/deps/v8/test/unittests/compiler/regalloc/move-optimizer-unittest.cc @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/compiler/move-optimizer.h" -#include "src/compiler/pipeline.h" +#include "src/compiler/backend/move-optimizer.h" #include "src/ostreams.h" -#include "test/unittests/compiler/instruction-sequence-unittest.h" +#include "test/unittests/compiler/backend/instruction-sequence-unittest.h" namespace v8 { namespace internal { @@ -54,18 +53,16 @@ class MoveOptimizerTest : public InstructionSequenceTest { void Optimize() { WireBlocks(); if (FLAG_trace_turbo) { - PrintableInstructionSequence printable = {config(), sequence()}; StdoutStream{} << "----- Instruction sequence before move optimization -----\n" - << printable; + << *sequence(); } MoveOptimizer move_optimizer(zone(), sequence()); move_optimizer.Run(); if (FLAG_trace_turbo) { - PrintableInstructionSequence printable = {config(), sequence()}; StdoutStream{} << "----- Instruction sequence after move optimization -----\n" - << printable; + << *sequence(); } } diff --git a/deps/v8/test/unittests/compiler/regalloc/register-allocator-unittest.cc b/deps/v8/test/unittests/compiler/regalloc/register-allocator-unittest.cc index e12d53caf5..d77f424ef7 100644 --- a/deps/v8/test/unittests/compiler/regalloc/register-allocator-unittest.cc +++ b/deps/v8/test/unittests/compiler/regalloc/register-allocator-unittest.cc @@ -4,7 +4,7 @@ #include "src/assembler-inl.h" #include "src/compiler/pipeline.h" -#include "test/unittests/compiler/instruction-sequence-unittest.h" +#include "test/unittests/compiler/backend/instruction-sequence-unittest.h" namespace v8 { namespace internal { @@ -187,7 +187,7 @@ TEST_F(RegisterAllocatorTest, SimpleDiamondPhi) { } TEST_F(RegisterAllocatorTest, DiamondManyPhis) { - const int kPhis = kDefaultNRegs * 2; + constexpr int kPhis = Register::kNumRegisters * 2; StartBlock(); EndBlock(Branch(Reg(DefineConstant()), 1, 2)); @@ -218,7 +218,7 @@ TEST_F(RegisterAllocatorTest, DiamondManyPhis) { } TEST_F(RegisterAllocatorTest, DoubleDiamondManyRedundantPhis) { - const int kPhis = kDefaultNRegs * 2; + constexpr int kPhis = Register::kNumRegisters * 2; // First diamond. StartBlock(); @@ -326,16 +326,16 @@ TEST_F(RegisterAllocatorTest, SpillPhi) { TEST_F(RegisterAllocatorTest, MoveLotsOfConstants) { StartBlock(); - VReg constants[kDefaultNRegs]; + VReg constants[Register::kNumRegisters]; for (size_t i = 0; i < arraysize(constants); ++i) { constants[i] = DefineConstant(); } - TestOperand call_ops[kDefaultNRegs * 2]; - for (int i = 0; i < kDefaultNRegs; ++i) { + TestOperand call_ops[Register::kNumRegisters * 2]; + for (int i = 0; i < Register::kNumRegisters; ++i) { call_ops[i] = Reg(constants[i], i); } - for (int i = 0; i < kDefaultNRegs; ++i) { - call_ops[i + kDefaultNRegs] = Slot(constants[i], i); + for (int i = 0; i < Register::kNumRegisters; ++i) { + call_ops[i + Register::kNumRegisters] = Slot(constants[i], i); } EmitCall(Slot(-1), arraysize(call_ops), call_ops); EndBlock(Last()); @@ -488,7 +488,7 @@ TEST_F(RegisterAllocatorTest, RegressionSplitBeforeAndMove) { StartBlock(); // Fill registers. - VReg values[kDefaultNRegs]; + VReg values[Register::kNumRegisters]; for (size_t i = 0; i < arraysize(values); ++i) { if (i == 0 || i == 1) continue; // Leave a hole for c_1 to take. values[i] = Define(Reg(static_cast<int>(i))); @@ -522,7 +522,7 @@ TEST_F(RegisterAllocatorTest, RegressionSpillTwice) { TEST_F(RegisterAllocatorTest, RegressionLoadConstantBeforeSpill) { StartBlock(); // Fill registers. - VReg values[kDefaultNRegs]; + VReg values[Register::kNumRegisters]; for (size_t i = arraysize(values); i > 0; --i) { values[i - 1] = Define(Reg(static_cast<int>(i - 1))); } @@ -711,8 +711,6 @@ class SlotConstraintTest : public RegisterAllocatorTest, } // namespace -#if GTEST_HAS_COMBINE - TEST_P(SlotConstraintTest, SlotConstraint) { StartBlock(); VReg p_0; @@ -762,8 +760,6 @@ INSTANTIATE_TEST_CASE_P( ::testing::Combine(::testing::ValuesIn(kParameterTypes), ::testing::Range(0, SlotConstraintTest::kMaxVariant))); -#endif // GTEST_HAS_COMBINE - } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/s390/OWNERS b/deps/v8/test/unittests/compiler/s390/OWNERS index eb007cb908..6d1a8fc472 100644 --- a/deps/v8/test/unittests/compiler/s390/OWNERS +++ b/deps/v8/test/unittests/compiler/s390/OWNERS @@ -1,5 +1,4 @@ jyan@ca.ibm.com -dstence@us.ibm.com joransiu@ca.ibm.com -mbrandy@us.ibm.com michael_dawson@ca.ibm.com +miladfar@ca.ibm.com
\ No newline at end of file diff --git a/deps/v8/test/unittests/compiler/s390/instruction-selector-s390-unittest.cc b/deps/v8/test/unittests/compiler/s390/instruction-selector-s390-unittest.cc index 86f7d69ec9..611e766edb 100644 --- a/deps/v8/test/unittests/compiler/s390/instruction-selector-s390-unittest.cc +++ b/deps/v8/test/unittests/compiler/s390/instruction-selector-s390-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/unittests/compiler/instruction-selector-unittest.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" #include "src/assembler-inl.h" diff --git a/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc b/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc index 82bcda6e9f..722384da5b 100644 --- a/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc @@ -42,12 +42,12 @@ class SimplifiedLoweringTest : public GraphTest { { // Simplified lowering needs to run w/o the typer decorator so make sure // the object is not live at the same time. - Typer typer(js_heap_broker(), Typer::kNoFlags, graph()); + Typer typer(broker(), Typer::kNoFlags, graph()); typer.Run(); } - SimplifiedLowering lowering(jsgraph(), js_heap_broker(), zone(), - source_positions(), node_origins(), + SimplifiedLowering lowering(jsgraph(), broker(), zone(), source_positions(), + node_origins(), PoisoningMitigationLevel::kDontPoison); lowering.LowerAllNodes(); } diff --git a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc index 5e2f8f15cc..f3573d6379 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc @@ -29,14 +29,13 @@ class SimplifiedOperatorReducerTest : public GraphTest { protected: Reduction Reduce(Node* node) { - JSHeapBroker js_heap_broker(isolate(), zone()); + JSHeapBroker broker(isolate(), zone()); MachineOperatorBuilder machine(zone()); JSOperatorBuilder javascript(zone()); JSGraph jsgraph(isolate(), graph(), common(), &javascript, simplified(), &machine); GraphReducer graph_reducer(zone(), graph()); - SimplifiedOperatorReducer reducer(&graph_reducer, &jsgraph, - &js_heap_broker); + SimplifiedOperatorReducer reducer(&graph_reducer, &jsgraph, &broker); return reducer.Reduce(node); } diff --git a/deps/v8/test/unittests/compiler/typed-optimization-unittest.cc b/deps/v8/test/unittests/compiler/typed-optimization-unittest.cc index 51426a5f85..da1f3941f0 100644 --- a/deps/v8/test/unittests/compiler/typed-optimization-unittest.cc +++ b/deps/v8/test/unittests/compiler/typed-optimization-unittest.cc @@ -38,8 +38,7 @@ class TypedOptimizationTest : public TypedGraphTest { &machine); // TODO(titzer): mock the GraphReducer here for better unit testing. GraphReducer graph_reducer(zone(), graph()); - TypedOptimization reducer(&graph_reducer, &deps_, &jsgraph, - js_heap_broker()); + TypedOptimization reducer(&graph_reducer, &deps_, &jsgraph, broker()); return reducer.Reduce(node); } diff --git a/deps/v8/test/unittests/compiler/typer-unittest.cc b/deps/v8/test/unittests/compiler/typer-unittest.cc index b827088336..5954dbc638 100644 --- a/deps/v8/test/unittests/compiler/typer-unittest.cc +++ b/deps/v8/test/unittests/compiler/typer-unittest.cc @@ -4,7 +4,7 @@ #include <functional> -#include "src/codegen.h" +#include "src/base/overflowing-math.h" #include "src/compiler/js-operator.h" #include "src/compiler/node-properties.h" #include "src/compiler/operator-properties.h" @@ -22,8 +22,8 @@ class TyperTest : public TypedGraphTest { public: TyperTest() : TypedGraphTest(3), - js_heap_broker_(isolate(), zone()), - operation_typer_(&js_heap_broker_, zone()), + broker_(isolate(), zone()), + operation_typer_(&broker_, zone()), types_(zone(), isolate(), random_number_generator()), javascript_(zone()), simplified_(zone()) { @@ -56,7 +56,7 @@ class TyperTest : public TypedGraphTest { const int kRepetitions = 50; - JSHeapBroker js_heap_broker_; + JSHeapBroker broker_; OperationTyper operation_typer_; Types types_; JSOperatorBuilder javascript_; @@ -176,8 +176,8 @@ class TyperTest : public TypedGraphTest { for (int x2 = rmin; x2 < rmin + width; x2++) { double result_value = opfun(x1, x2); Type result_type = Type::NewConstant( - &js_heap_broker_, - isolate()->factory()->NewNumber(result_value), zone()); + &broker_, isolate()->factory()->NewNumber(result_value), + zone()); EXPECT_TRUE(result_type.Is(expected_type)); } } @@ -198,23 +198,21 @@ class TyperTest : public TypedGraphTest { double x2 = RandomInt(r2.AsRange()); double result_value = opfun(x1, x2); Type result_type = Type::NewConstant( - &js_heap_broker_, isolate()->factory()->NewNumber(result_value), - zone()); + &broker_, isolate()->factory()->NewNumber(result_value), zone()); EXPECT_TRUE(result_type.Is(expected_type)); } } // Test extreme cases. double x1 = +1e-308; double x2 = -1e-308; - Type r1 = Type::NewConstant(&js_heap_broker_, - isolate()->factory()->NewNumber(x1), zone()); - Type r2 = Type::NewConstant(&js_heap_broker_, - isolate()->factory()->NewNumber(x2), zone()); + Type r1 = Type::NewConstant(&broker_, isolate()->factory()->NewNumber(x1), + zone()); + Type r2 = Type::NewConstant(&broker_, isolate()->factory()->NewNumber(x2), + zone()); Type expected_type = TypeBinaryOp(op, r1, r2); double result_value = opfun(x1, x2); Type result_type = Type::NewConstant( - &js_heap_broker_, isolate()->factory()->NewNumber(result_value), - zone()); + &broker_, isolate()->factory()->NewNumber(result_value), zone()); EXPECT_TRUE(result_type.Is(expected_type)); } @@ -229,7 +227,7 @@ class TyperTest : public TypedGraphTest { double x2 = RandomInt(r2.AsRange()); bool result_value = opfun(x1, x2); Type result_type = Type::NewConstant( - &js_heap_broker_, + &broker_, result_value ? isolate()->factory()->true_value() : isolate()->factory()->false_value(), zone()); @@ -249,8 +247,7 @@ class TyperTest : public TypedGraphTest { int32_t x2 = static_cast<int32_t>(RandomInt(r2.AsRange())); double result_value = opfun(x1, x2); Type result_type = Type::NewConstant( - &js_heap_broker_, isolate()->factory()->NewNumber(result_value), - zone()); + &broker_, isolate()->factory()->NewNumber(result_value), zone()); EXPECT_TRUE(result_type.Is(expected_type)); } } @@ -311,6 +308,7 @@ int32_t shift_right(int32_t x, int32_t y) { return x >> (y & 0x1F); } int32_t bit_or(int32_t x, int32_t y) { return x | y; } int32_t bit_and(int32_t x, int32_t y) { return x & y; } int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; } +double divide_double_double(double x, double y) { return base::Divide(x, y); } double modulo_double_double(double x, double y) { return Modulo(x, y); } } // namespace @@ -335,7 +333,7 @@ TEST_F(TyperTest, TypeJSMultiply) { } TEST_F(TyperTest, TypeJSDivide) { - TestBinaryArithOp(javascript_.Divide(), std::divides<double>()); + TestBinaryArithOp(javascript_.Divide(), divide_double_double); } TEST_F(TyperTest, TypeJSModulus) { diff --git a/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc index fb7caa4bf9..f174b92731 100644 --- a/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc +++ b/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/unittests/compiler/instruction-selector-unittest.h" +#include "test/unittests/compiler/backend/instruction-selector-unittest.h" #include "src/compiler/node-matchers.h" #include "src/objects-inl.h" @@ -1205,10 +1205,114 @@ TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) { EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); } - // ----------------------------------------------------------------------------- // Binops with a memory operand. +TEST_F(InstructionSelectorTest, LoadCmp32) { + { + // Word32Equal(Load[Int8](p0, p1), Int32Constant(0)) -> cmpb [p0,p1], 0 + StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(), + MachineType::Int64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + m.Return( + m.Word32Equal(m.Load(MachineType::Int8(), p0, p1), m.Int32Constant(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Cmp8, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); + } + { + // Word32Equal(Load[Uint8](p0, p1), Int32Constant(0)) -> cmpb [p0,p1], 0 + StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(), + MachineType::Int64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + m.Return(m.Word32Equal(m.Load(MachineType::Uint8(), p0, p1), + m.Int32Constant(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Cmp8, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); + } + { + // Word32Equal(Load[Int16](p0, p1), Int32Constant(0)) -> cmpw [p0,p1], 0 + StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(), + MachineType::Int64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + m.Return(m.Word32Equal(m.Load(MachineType::Int16(), p0, p1), + m.Int32Constant(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Cmp16, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); + } + { + // Word32Equal(Load[Uint16](p0, p1), Int32Constant(0)) -> cmpw [p0,p1], 0 + StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(), + MachineType::Int64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + m.Return(m.Word32Equal(m.Load(MachineType::Uint16(), p0, p1), + m.Int32Constant(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Cmp16, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); + } + { + // Word32Equal(Load[Int32](p0, p1), Int32Constant(0)) -> cmpl [p0,p1], 0 + StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(), + MachineType::Int64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + m.Return(m.Word32Equal(m.Load(MachineType::Int32(), p0, p1), + m.Int32Constant(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); + } + { + // Word32Equal(Load[Uint32](p0, p1), Int32Constant(0)) -> cmpl [p0,p1], 0 + StreamBuilder m(this, MachineType::Int32(), MachineType::Int64(), + MachineType::Int64()); + Node* const p0 = m.Parameter(0); + Node* const p1 = m.Parameter(1); + m.Return(m.Word32Equal(m.Load(MachineType::Uint32(), p0, p1), + m.Int32Constant(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MR1, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); + EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate()); + } +} + TEST_F(InstructionSelectorTest, LoadAnd32) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), MachineType::Int32()); diff --git a/deps/v8/test/unittests/compiler/zone-stats-unittest.cc b/deps/v8/test/unittests/compiler/zone-stats-unittest.cc index a643d1480c..9f3bd3493f 100644 --- a/deps/v8/test/unittests/compiler/zone-stats-unittest.cc +++ b/deps/v8/test/unittests/compiler/zone-stats-unittest.cc @@ -10,7 +10,7 @@ namespace v8 { namespace internal { namespace compiler { -class ZoneStatsTest : public TestWithIsolate { +class ZoneStatsTest : public ::testing::Test { public: ZoneStatsTest() : zone_stats_(&allocator_) {} diff --git a/deps/v8/test/unittests/conversions-unittest.cc b/deps/v8/test/unittests/conversions-unittest.cc new file mode 100644 index 0000000000..7c4bd96a6f --- /dev/null +++ b/deps/v8/test/unittests/conversions-unittest.cc @@ -0,0 +1,76 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#include "src/conversions.h" +#include "test/unittests/test-utils.h" + +namespace v8 { +namespace internal { +namespace interpreter { + +class ConversionsTest : public ::testing::Test { + public: + ConversionsTest() = default; + ~ConversionsTest() override = default; + + SourcePosition toPos(int offset) { + return SourcePosition(offset, offset % 10 - 1); + } +}; + +// Some random offsets, mostly at 'suspicious' bit boundaries. + +struct IntStringPair { + int integer; + std::string string; +}; + +static IntStringPair int_pairs[] = {{0, "0"}, + {101, "101"}, + {-1, "-1"}, + {1024, "1024"}, + {200000, "200000"}, + {-1024, "-1024"}, + {-200000, "-200000"}, + {kMinInt, "-2147483648"}, + {kMaxInt, "2147483647"}}; + +TEST_F(ConversionsTest, IntToCString) { + std::unique_ptr<char[]> buf(new char[4096]); + + for (size_t i = 0; i < arraysize(int_pairs); i++) { + ASSERT_STREQ(IntToCString(int_pairs[i].integer, {buf.get(), 4096}), + int_pairs[i].string.c_str()); + } +} + +struct DoubleStringPair { + double number; + std::string string; +}; + +static DoubleStringPair double_pairs[] = { + {0.0, "0"}, + {kMinInt, "-2147483648"}, + {kMaxInt, "2147483647"}, + // ES section 7.1.12.1 #sec-tostring-applied-to-the-number-type: + // -0.0 is stringified to "0". + {-0.0, "0"}, + {1.1, "1.1"}, + {0.1, "0.1"}}; + +TEST_F(ConversionsTest, DoubleToCString) { + std::unique_ptr<char[]> buf(new char[4096]); + + for (size_t i = 0; i < arraysize(double_pairs); i++) { + ASSERT_STREQ(DoubleToCString(double_pairs[i].number, {buf.get(), 4096}), + double_pairs[i].string.c_str()); + } +} + +} // namespace interpreter +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/detachable-vector-unittest.cc b/deps/v8/test/unittests/detachable-vector-unittest.cc index f9c846df22..b805352a7e 100644 --- a/deps/v8/test/unittests/detachable-vector-unittest.cc +++ b/deps/v8/test/unittests/detachable-vector-unittest.cc @@ -63,5 +63,65 @@ TEST(DetachableVector, DetachLeaksBackingStore) { // The destructor of v2 will release the backing store. } +TEST(DetachableVector, PushAndPopWithReallocation) { + DetachableVector<size_t> v; + const size_t kMinimumCapacity = DetachableVector<size_t>::kMinimumCapacity; + + EXPECT_EQ(0u, v.capacity()); + EXPECT_EQ(0u, v.size()); + v.push_back(0); + EXPECT_EQ(kMinimumCapacity, v.capacity()); + EXPECT_EQ(1u, v.size()); + + // Push values until the reallocation happens. + for (size_t i = 1; i <= kMinimumCapacity; ++i) { + v.push_back(i); + } + EXPECT_EQ(2 * kMinimumCapacity, v.capacity()); + EXPECT_EQ(kMinimumCapacity + 1, v.size()); + + EXPECT_EQ(kMinimumCapacity, v.back()); + v.pop_back(); + + v.push_back(100); + EXPECT_EQ(100u, v.back()); + v.pop_back(); + EXPECT_EQ(kMinimumCapacity - 1, v.back()); +} + +TEST(DetachableVector, ShrinkToFit) { + DetachableVector<size_t> v; + const size_t kMinimumCapacity = DetachableVector<size_t>::kMinimumCapacity; + + // shrink_to_fit doesn't affect the empty capacity DetachableVector. + EXPECT_EQ(0u, v.capacity()); + v.shrink_to_fit(); + EXPECT_EQ(0u, v.capacity()); + + // Do not shrink the buffer if it's smaller than kMinimumCapacity. + v.push_back(0); + EXPECT_EQ(kMinimumCapacity, v.capacity()); + v.shrink_to_fit(); + EXPECT_EQ(kMinimumCapacity, v.capacity()); + + // Fill items to |v| until the buffer grows twice. + for (size_t i = 0; i < 2 * kMinimumCapacity; ++i) { + v.push_back(i); + } + EXPECT_EQ(2 * kMinimumCapacity + 1, v.size()); + EXPECT_EQ(4 * kMinimumCapacity, v.capacity()); + + // Do not shrink the buffer if the number of unused slots is not large enough. + v.shrink_to_fit(); + EXPECT_EQ(2 * kMinimumCapacity + 1, v.size()); + EXPECT_EQ(4 * kMinimumCapacity, v.capacity()); + + v.pop_back(); + v.pop_back(); + v.shrink_to_fit(); + EXPECT_EQ(2 * kMinimumCapacity - 1, v.size()); + EXPECT_EQ(2 * kMinimumCapacity - 1, v.capacity()); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/heap/barrier-unittest.cc b/deps/v8/test/unittests/heap/barrier-unittest.cc index 1d42f97a4f..07906b20c1 100644 --- a/deps/v8/test/unittests/heap/barrier-unittest.cc +++ b/deps/v8/test/unittests/heap/barrier-unittest.cc @@ -4,19 +4,27 @@ #include "src/heap/barrier.h" #include "src/base/platform/platform.h" +#include "src/base/platform/time.h" #include "testing/gtest/include/gtest/gtest.h" namespace v8 { namespace internal { namespace heap { +namespace { + +// Large timeout that will not trigger in tests. +constexpr base::TimeDelta test_timeout = base::TimeDelta::FromHours(3); + +} // namespace + TEST(OneshotBarrier, InitializeNotDone) { - OneshotBarrier barrier; + OneshotBarrier barrier(test_timeout); EXPECT_FALSE(barrier.DoneForTesting()); } TEST(OneshotBarrier, DoneAfterWait_Sequential) { - OneshotBarrier barrier; + OneshotBarrier barrier(test_timeout); barrier.Start(); barrier.Wait(); EXPECT_TRUE(barrier.DoneForTesting()); @@ -41,7 +49,7 @@ class ThreadWaitingOnBarrier final : public base::Thread { TEST(OneshotBarrier, DoneAfterWait_Concurrent) { const int kThreadCount = 2; - OneshotBarrier barrier; + OneshotBarrier barrier(test_timeout); ThreadWaitingOnBarrier threads[kThreadCount]; for (int i = 0; i < kThreadCount; i++) { threads[i].Initialize(&barrier); @@ -59,7 +67,7 @@ TEST(OneshotBarrier, DoneAfterWait_Concurrent) { TEST(OneshotBarrier, EarlyFinish_Concurrent) { const int kThreadCount = 2; - OneshotBarrier barrier; + OneshotBarrier barrier(test_timeout); ThreadWaitingOnBarrier threads[kThreadCount]; // Test that one thread that actually finishes processing work before other // threads call Start() will move the barrier in Done state. @@ -103,7 +111,7 @@ class CountingThread final : public base::Thread { private: void ProcessWork() { - base::LockGuard<base::Mutex> guard(mutex_); + base::MutexGuard guard(mutex_); processed_work_ += *work_; *work_ = 0; } @@ -118,7 +126,7 @@ class CountingThread final : public base::Thread { TEST(OneshotBarrier, Processing_Concurrent) { const size_t kWorkCounter = 173173; - OneshotBarrier barrier; + OneshotBarrier barrier(test_timeout); base::Mutex mutex; size_t work = 0; CountingThread counting_thread(&barrier, &mutex, &work); @@ -129,7 +137,7 @@ TEST(OneshotBarrier, Processing_Concurrent) { for (size_t i = 0; i < kWorkCounter; i++) { { - base::LockGuard<base::Mutex> guard(&mutex); + base::MutexGuard guard(&mutex); work++; } barrier.NotifyAll(); diff --git a/deps/v8/test/unittests/heap/embedder-tracing-unittest.cc b/deps/v8/test/unittests/heap/embedder-tracing-unittest.cc index 33cc05e692..5bbbaceb3c 100644 --- a/deps/v8/test/unittests/heap/embedder-tracing-unittest.cc +++ b/deps/v8/test/unittests/heap/embedder-tracing-unittest.cc @@ -83,6 +83,14 @@ TEST(LocalEmbedderHeapTracer, EnterFinalPauseForwards) { local_tracer.EnterFinalPause(); } +TEST(LocalEmbedderHeapTracer, IsRemoteTracingDoneForwards) { + StrictMock<MockEmbedderHeapTracer> remote_tracer; + LocalEmbedderHeapTracer local_tracer(nullptr); + local_tracer.SetRemoteTracer(&remote_tracer); + EXPECT_CALL(remote_tracer, IsTracingDone()); + local_tracer.IsRemoteTracingDone(); +} + TEST(LocalEmbedderHeapTracer, EnterFinalPauseDefaultStackStateUnkown) { StrictMock<MockEmbedderHeapTracer> remote_tracer; LocalEmbedderHeapTracer local_tracer(nullptr); @@ -102,6 +110,36 @@ TEST(LocalEmbedderHeapTracer, EnterFinalPauseStackStateIsForwarded) { local_tracer.EnterFinalPause(); } +TEST(LocalEmbedderHeapTracer, TemporaryEmbedderStackState) { + StrictMock<MockEmbedderHeapTracer> remote_tracer; + LocalEmbedderHeapTracer local_tracer(nullptr); + local_tracer.SetRemoteTracer(&remote_tracer); + // Default is unknown, see above. + { + EmbedderStackStateScope scope(&local_tracer, EmbedderHeapTracer::kEmpty); + EXPECT_CALL(remote_tracer, EnterFinalPause(EmbedderHeapTracer::kEmpty)); + local_tracer.EnterFinalPause(); + } +} + +TEST(LocalEmbedderHeapTracer, TemporaryEmbedderStackStateRestores) { + StrictMock<MockEmbedderHeapTracer> remote_tracer; + LocalEmbedderHeapTracer local_tracer(nullptr); + local_tracer.SetRemoteTracer(&remote_tracer); + // Default is unknown, see above. + { + EmbedderStackStateScope scope(&local_tracer, EmbedderHeapTracer::kEmpty); + { + EmbedderStackStateScope scope(&local_tracer, + EmbedderHeapTracer::kUnknown); + EXPECT_CALL(remote_tracer, EnterFinalPause(EmbedderHeapTracer::kUnknown)); + local_tracer.EnterFinalPause(); + } + EXPECT_CALL(remote_tracer, EnterFinalPause(EmbedderHeapTracer::kEmpty)); + local_tracer.EnterFinalPause(); + } +} + TEST(LocalEmbedderHeapTracer, EnterFinalPauseStackStateResets) { StrictMock<MockEmbedderHeapTracer> remote_tracer; LocalEmbedderHeapTracer local_tracer(nullptr); @@ -122,52 +160,19 @@ TEST(LocalEmbedderHeapTracer, IsRemoteTracingDoneIncludesRemote) { local_tracer.IsRemoteTracingDone(); } -TEST(LocalEmbedderHeapTracer, NumberOfCachedWrappersToTraceExcludesRemote) { - LocalEmbedderHeapTracer local_tracer(nullptr); - StrictMock<MockEmbedderHeapTracer> remote_tracer; - local_tracer.SetRemoteTracer(&remote_tracer); - local_tracer.NumberOfCachedWrappersToTrace(); -} - -TEST(LocalEmbedderHeapTracer, RegisterWrappersWithRemoteTracer) { +TEST(LocalEmbedderHeapTracer, RegisterV8ReferencesWithRemoteTracer) { StrictMock<MockEmbedderHeapTracer> remote_tracer; LocalEmbedderHeapTracer local_tracer(nullptr); local_tracer.SetRemoteTracer(&remote_tracer); - local_tracer.AddWrapperToTrace(CreateWrapperInfo()); - EXPECT_EQ(1u, local_tracer.NumberOfCachedWrappersToTrace()); - EXPECT_CALL(remote_tracer, RegisterV8References(_)); - local_tracer.RegisterWrappersWithRemoteTracer(); - EXPECT_EQ(0u, local_tracer.NumberOfCachedWrappersToTrace()); + { + LocalEmbedderHeapTracer::ProcessingScope scope(&local_tracer); + scope.AddWrapperInfoForTesting(CreateWrapperInfo()); + EXPECT_CALL(remote_tracer, RegisterV8References(_)); + } EXPECT_CALL(remote_tracer, IsTracingDone()).WillOnce(Return(false)); EXPECT_FALSE(local_tracer.IsRemoteTracingDone()); } -TEST(LocalEmbedderHeapTracer, TraceFinishes) { - StrictMock<MockEmbedderHeapTracer> remote_tracer; - LocalEmbedderHeapTracer local_tracer(nullptr); - local_tracer.SetRemoteTracer(&remote_tracer); - local_tracer.AddWrapperToTrace(CreateWrapperInfo()); - EXPECT_EQ(1u, local_tracer.NumberOfCachedWrappersToTrace()); - EXPECT_CALL(remote_tracer, RegisterV8References(_)); - local_tracer.RegisterWrappersWithRemoteTracer(); - EXPECT_CALL(remote_tracer, AdvanceTracing(_)).WillOnce(Return(true)); - EXPECT_TRUE(local_tracer.Trace(std::numeric_limits<double>::infinity())); - EXPECT_EQ(0u, local_tracer.NumberOfCachedWrappersToTrace()); -} - -TEST(LocalEmbedderHeapTracer, TraceDoesNotFinish) { - StrictMock<MockEmbedderHeapTracer> remote_tracer; - LocalEmbedderHeapTracer local_tracer(nullptr); - local_tracer.SetRemoteTracer(&remote_tracer); - local_tracer.AddWrapperToTrace(CreateWrapperInfo()); - EXPECT_EQ(1u, local_tracer.NumberOfCachedWrappersToTrace()); - EXPECT_CALL(remote_tracer, RegisterV8References(_)); - local_tracer.RegisterWrappersWithRemoteTracer(); - EXPECT_CALL(remote_tracer, AdvanceTracing(_)).WillOnce(Return(false)); - EXPECT_FALSE(local_tracer.Trace(1.0)); - EXPECT_EQ(0u, local_tracer.NumberOfCachedWrappersToTrace()); -} - TEST_F(LocalEmbedderHeapTracerWithIsolate, SetRemoteTracerSetsIsolate) { StrictMock<MockEmbedderHeapTracer> remote_tracer; LocalEmbedderHeapTracer local_tracer(isolate()); diff --git a/deps/v8/test/unittests/heap/gc-tracer-unittest.cc b/deps/v8/test/unittests/heap/gc-tracer-unittest.cc index ac18e1817b..b1e646fa2c 100644 --- a/deps/v8/test/unittests/heap/gc-tracer-unittest.cc +++ b/deps/v8/test/unittests/heap/gc-tracer-unittest.cc @@ -468,7 +468,7 @@ class GcHistogram { static void CleanUp() { histograms_.clear(); } - int Total() { + int Total() const { int result = 0; for (int i : samples_) { result += i; @@ -476,7 +476,7 @@ class GcHistogram { return result; } - int Count() { return static_cast<int>(samples_.size()); } + int Count() const { return static_cast<int>(samples_.size()); } private: std::vector<int> samples_; @@ -524,5 +524,27 @@ TEST_F(GCTracerTest, RecordScavengerHistograms) { GcHistogram::CleanUp(); } +TEST_F(GCTracerTest, RecordGCSumHistograms) { + if (FLAG_stress_incremental_marking) return; + isolate()->SetCreateHistogramFunction(&GcHistogram::CreateHistogram); + isolate()->SetAddHistogramSampleFunction(&GcHistogram::AddHistogramSample); + GCTracer* tracer = i_isolate()->heap()->tracer(); + tracer->ResetForTesting(); + tracer->current_ + .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_START] + .duration = 1; + tracer->current_ + .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_SWEEPING] + .duration = 2; + tracer->AddIncrementalMarkingStep(3.0, 1024); + tracer->current_ + .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE] + .duration = 4; + const double atomic_pause_duration = 5.0; + tracer->RecordGCSumCounters(atomic_pause_duration); + EXPECT_EQ(15, GcHistogram::Get("V8.GCMarkCompactor")->Total()); + GcHistogram::CleanUp(); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/heap/heap-unittest.cc b/deps/v8/test/unittests/heap/heap-unittest.cc index dd14e22d54..53954d8178 100644 --- a/deps/v8/test/unittests/heap/heap-unittest.cc +++ b/deps/v8/test/unittests/heap/heap-unittest.cc @@ -20,6 +20,7 @@ namespace v8 { namespace internal { typedef TestWithIsolate HeapTest; +typedef TestWithIsolateAndPointerCompression HeapWithPointerCompressionTest; TEST(Heap, SemiSpaceSize) { const size_t KB = static_cast<size_t>(i::KB); @@ -61,15 +62,46 @@ TEST_F(HeapTest, ASLR) { TEST_F(HeapTest, ExternalLimitDefault) { Heap* heap = i_isolate()->heap(); - EXPECT_EQ(kExternalAllocationSoftLimit, heap->external_memory_limit_); + EXPECT_EQ(kExternalAllocationSoftLimit, + heap->isolate()->isolate_data()->external_memory_limit_); } TEST_F(HeapTest, ExternalLimitStaysAboveDefaultForExplicitHandling) { v8_isolate()->AdjustAmountOfExternalAllocatedMemory(+10 * MB); v8_isolate()->AdjustAmountOfExternalAllocatedMemory(-10 * MB); Heap* heap = i_isolate()->heap(); - EXPECT_GE(heap->external_memory_limit_, kExternalAllocationSoftLimit); + EXPECT_GE(heap->isolate()->isolate_data()->external_memory_limit_, + kExternalAllocationSoftLimit); } +#if V8_TARGET_ARCH_64_BIT +TEST_F(HeapWithPointerCompressionTest, HeapLayout) { + // Produce some garbage. + RunJS( + "let ar = [];" + "for (let i = 0; i < 100; i++) {" + " ar.push(Array(i));" + "}" + "ar.push(Array(32 * 1024 * 1024));"); + + Address isolate_root = i_isolate()->isolate_root(); + EXPECT_TRUE(IsAligned(isolate_root, size_t{4} * GB)); + + // Check that all memory chunks belong this region. + base::AddressRegion heap_reservation(isolate_root - size_t{2} * GB, + size_t{4} * GB); + + OldGenerationMemoryChunkIterator iter(i_isolate()->heap()); + for (;;) { + MemoryChunk* chunk = iter.next(); + if (chunk == nullptr) break; + + Address address = chunk->address(); + size_t size = chunk->area_end() - address; + EXPECT_TRUE(heap_reservation.contains(address, size)); + } +} +#endif // V8_TARGET_ARCH_64_BIT + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/heap/marking-unittest.cc b/deps/v8/test/unittests/heap/marking-unittest.cc index 0553dc0ea5..be26d4eebd 100644 --- a/deps/v8/test/unittests/heap/marking-unittest.cc +++ b/deps/v8/test/unittests/heap/marking-unittest.cc @@ -14,7 +14,7 @@ namespace internal { TEST(Marking, TransitionWhiteBlackWhite) { Bitmap* bitmap = reinterpret_cast<Bitmap*>( - calloc(Bitmap::kSize / kPointerSize, kPointerSize)); + calloc(Bitmap::kSize / kTaggedSize, kTaggedSize)); const int kLocationsSize = 3; int position[kLocationsSize] = { Bitmap::kBitsPerCell - 2, Bitmap::kBitsPerCell - 1, Bitmap::kBitsPerCell}; @@ -34,7 +34,7 @@ TEST(Marking, TransitionWhiteBlackWhite) { TEST(Marking, TransitionWhiteGreyBlack) { Bitmap* bitmap = reinterpret_cast<Bitmap*>( - calloc(Bitmap::kSize / kPointerSize, kPointerSize)); + calloc(Bitmap::kSize / kTaggedSize, kTaggedSize)); const int kLocationsSize = 3; int position[kLocationsSize] = { Bitmap::kBitsPerCell - 2, Bitmap::kBitsPerCell - 1, Bitmap::kBitsPerCell}; @@ -60,7 +60,7 @@ TEST(Marking, TransitionWhiteGreyBlack) { TEST(Marking, SetAndClearRange) { Bitmap* bitmap = reinterpret_cast<Bitmap*>( - calloc(Bitmap::kSize / kPointerSize, kPointerSize)); + calloc(Bitmap::kSize / kTaggedSize, kTaggedSize)); for (int i = 0; i < 3; i++) { bitmap->SetRange(i, Bitmap::kBitsPerCell + i); CHECK_EQ(reinterpret_cast<uint32_t*>(bitmap)[0], 0xFFFFFFFFu << i); @@ -74,7 +74,7 @@ TEST(Marking, SetAndClearRange) { TEST(Marking, ClearMultipleRanges) { Bitmap* bitmap = reinterpret_cast<Bitmap*>( - calloc(Bitmap::kSize / kPointerSize, kPointerSize)); + calloc(Bitmap::kSize / kTaggedSize, kTaggedSize)); CHECK(bitmap->AllBitsClearInRange(0, Bitmap::kBitsPerCell * 3)); bitmap->SetRange(0, Bitmap::kBitsPerCell * 3); CHECK_EQ(reinterpret_cast<uint32_t*>(bitmap)[0], 0xFFFFFFFFu); diff --git a/deps/v8/test/unittests/heap/slot-set-unittest.cc b/deps/v8/test/unittests/heap/slot-set-unittest.cc index aff6f02130..168bc9c7bc 100644 --- a/deps/v8/test/unittests/heap/slot-set-unittest.cc +++ b/deps/v8/test/unittests/heap/slot-set-unittest.cc @@ -8,6 +8,7 @@ #include "src/globals.h" #include "src/heap/slot-set.h" #include "src/heap/spaces.h" +#include "src/objects/slots.h" #include "testing/gtest/include/gtest/gtest.h" namespace v8 { @@ -16,13 +17,13 @@ namespace internal { TEST(SlotSet, InsertAndLookup1) { SlotSet set; set.SetPageStart(0); - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { EXPECT_FALSE(set.Lookup(i)); } - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { set.Insert(i); } - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { EXPECT_TRUE(set.Lookup(i)); } } @@ -30,12 +31,12 @@ TEST(SlotSet, InsertAndLookup1) { TEST(SlotSet, InsertAndLookup2) { SlotSet set; set.SetPageStart(0); - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { if (i % 7 == 0) { set.Insert(i); } } - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { if (i % 7 == 0) { EXPECT_TRUE(set.Lookup(i)); } else { @@ -47,15 +48,15 @@ TEST(SlotSet, InsertAndLookup2) { TEST(SlotSet, Iterate) { SlotSet set; set.SetPageStart(0); - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { if (i % 7 == 0) { set.Insert(i); } } set.Iterate( - [](Address slot_address) { - if (slot_address % 3 == 0) { + [](MaybeObjectSlot slot) { + if (slot.address() % 3 == 0) { return KEEP_SLOT; } else { return REMOVE_SLOT; @@ -63,7 +64,7 @@ TEST(SlotSet, Iterate) { }, SlotSet::KEEP_EMPTY_BUCKETS); - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { if (i % 21 == 0) { EXPECT_TRUE(set.Lookup(i)); } else { @@ -75,19 +76,19 @@ TEST(SlotSet, Iterate) { TEST(SlotSet, Remove) { SlotSet set; set.SetPageStart(0); - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { if (i % 7 == 0) { set.Insert(i); } } - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { if (i % 3 != 0) { set.Remove(i); } } - for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + for (int i = 0; i < Page::kPageSize; i += kTaggedSize) { if (i % 21 == 0) { EXPECT_TRUE(set.Lookup(i)); } else { @@ -99,11 +100,11 @@ TEST(SlotSet, Remove) { void CheckRemoveRangeOn(uint32_t start, uint32_t end) { SlotSet set; set.SetPageStart(0); - uint32_t first = start == 0 ? 0 : start - kPointerSize; - uint32_t last = end == Page::kPageSize ? end - kPointerSize : end; + uint32_t first = start == 0 ? 0 : start - kTaggedSize; + uint32_t last = end == Page::kPageSize ? end - kTaggedSize : end; for (const auto mode : {SlotSet::FREE_EMPTY_BUCKETS, SlotSet::KEEP_EMPTY_BUCKETS}) { - for (uint32_t i = first; i <= last; i += kPointerSize) { + for (uint32_t i = first; i <= last; i += kTaggedSize) { set.Insert(i); } set.RemoveRange(start, end, mode); @@ -113,7 +114,7 @@ void CheckRemoveRangeOn(uint32_t start, uint32_t end) { if (last == end) { EXPECT_TRUE(set.Lookup(last)); } - for (uint32_t i = start; i < end; i += kPointerSize) { + for (uint32_t i = start; i < end; i += kTaggedSize) { EXPECT_FALSE(set.Lookup(i)); } } @@ -121,16 +122,16 @@ void CheckRemoveRangeOn(uint32_t start, uint32_t end) { TEST(SlotSet, RemoveRange) { CheckRemoveRangeOn(0, Page::kPageSize); - CheckRemoveRangeOn(1 * kPointerSize, 1023 * kPointerSize); + CheckRemoveRangeOn(1 * kTaggedSize, 1023 * kTaggedSize); for (uint32_t start = 0; start <= 32; start++) { - CheckRemoveRangeOn(start * kPointerSize, (start + 1) * kPointerSize); - CheckRemoveRangeOn(start * kPointerSize, (start + 2) * kPointerSize); + CheckRemoveRangeOn(start * kTaggedSize, (start + 1) * kTaggedSize); + CheckRemoveRangeOn(start * kTaggedSize, (start + 2) * kTaggedSize); const uint32_t kEnds[] = {32, 64, 100, 128, 1024, 1500, 2048}; for (size_t i = 0; i < sizeof(kEnds) / sizeof(uint32_t); i++) { for (int k = -3; k <= 3; k++) { uint32_t end = (kEnds[i] + k); if (start < end) { - CheckRemoveRangeOn(start * kPointerSize, end * kPointerSize); + CheckRemoveRangeOn(start * kTaggedSize, end * kTaggedSize); } } } @@ -141,7 +142,7 @@ TEST(SlotSet, RemoveRange) { {SlotSet::FREE_EMPTY_BUCKETS, SlotSet::KEEP_EMPTY_BUCKETS}) { set.Insert(Page::kPageSize / 2); set.RemoveRange(0, Page::kPageSize, mode); - for (uint32_t i = 0; i < Page::kPageSize; i += kPointerSize) { + for (uint32_t i = 0; i < Page::kPageSize; i += kTaggedSize) { EXPECT_FALSE(set.Lookup(i)); } } @@ -153,23 +154,18 @@ TEST(TypedSlotSet, Iterate) { // for a MSVC++ bug about lambda captures, see the discussion at // https://social.msdn.microsoft.com/Forums/SqlServer/4abf18bd-4ae4-4c72-ba3e-3b13e7909d5f static const int kDelta = 10000001; - static const int kHostDelta = 50001; int added = 0; - uint32_t j = 0; - for (uint32_t i = 0; i < TypedSlotSet::kMaxOffset; - i += kDelta, j += kHostDelta) { + for (uint32_t i = 0; i < TypedSlotSet::kMaxOffset; i += kDelta) { SlotType type = static_cast<SlotType>(i % CLEARED_SLOT); - set.Insert(type, j, i); + set.Insert(type, i); ++added; } int iterated = 0; set.Iterate( - [&iterated](SlotType type, Address host_addr, Address addr) { + [&iterated](SlotType type, Address addr) { uint32_t i = static_cast<uint32_t>(addr); - uint32_t j = static_cast<uint32_t>(host_addr); EXPECT_EQ(i % CLEARED_SLOT, static_cast<uint32_t>(type)); EXPECT_EQ(0u, i % kDelta); - EXPECT_EQ(0u, j % kHostDelta); ++iterated; return i % 2 == 0 ? KEEP_SLOT : REMOVE_SLOT; }, @@ -177,7 +173,7 @@ TEST(TypedSlotSet, Iterate) { EXPECT_EQ(added, iterated); iterated = 0; set.Iterate( - [&iterated](SlotType type, Address host_addr, Address addr) { + [&iterated](SlotType type, Address addr) { uint32_t i = static_cast<uint32_t>(addr); EXPECT_EQ(0u, i % 2); ++iterated; @@ -187,13 +183,13 @@ TEST(TypedSlotSet, Iterate) { EXPECT_EQ(added / 2, iterated); } -TEST(TypedSlotSet, RemoveInvalidSlots) { +TEST(TypedSlotSet, ClearInvalidSlots) { TypedSlotSet set(0); const int kHostDelta = 100; uint32_t entries = 10; for (uint32_t i = 0; i < entries; i++) { SlotType type = static_cast<SlotType>(i % CLEARED_SLOT); - set.Insert(type, i * kHostDelta, i * kHostDelta); + set.Insert(type, i * kHostDelta); } std::map<uint32_t, uint32_t> invalid_ranges; @@ -202,19 +198,48 @@ TEST(TypedSlotSet, RemoveInvalidSlots) { std::pair<uint32_t, uint32_t>(i * kHostDelta, i * kHostDelta + 1)); } - set.RemoveInvaldSlots(invalid_ranges); + set.ClearInvalidSlots(invalid_ranges); for (std::map<uint32_t, uint32_t>::iterator it = invalid_ranges.begin(); it != invalid_ranges.end(); ++it) { uint32_t start = it->first; uint32_t end = it->second; set.Iterate( - [start, end](SlotType slot_type, Address host_addr, Address slot_addr) { - CHECK(host_addr < start || host_addr >= end); + [=](SlotType slot_type, Address slot_addr) { + CHECK(slot_addr < start || slot_addr >= end); return KEEP_SLOT; }, TypedSlotSet::KEEP_EMPTY_CHUNKS); } } +TEST(TypedSlotSet, Merge) { + TypedSlotSet set0(0), set1(0); + static const uint32_t kEntries = 10000; + for (uint32_t i = 0; i < kEntries; i++) { + set0.Insert(EMBEDDED_OBJECT_SLOT, 2 * i); + set1.Insert(EMBEDDED_OBJECT_SLOT, 2 * i + 1); + } + uint32_t count = 0; + set0.Merge(&set1); + set0.Iterate( + [&count](SlotType slot_type, Address slot_addr) { + if (count < kEntries) { + CHECK_EQ(slot_addr % 2, 0); + } else { + CHECK_EQ(slot_addr % 2, 1); + } + ++count; + return KEEP_SLOT; + }, + TypedSlotSet::KEEP_EMPTY_CHUNKS); + CHECK_EQ(2 * kEntries, count); + set1.Iterate( + [](SlotType slot_type, Address slot_addr) { + CHECK(false); // Unreachable. + return KEEP_SLOT; + }, + TypedSlotSet::KEEP_EMPTY_CHUNKS); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/heap/spaces-unittest.cc b/deps/v8/test/unittests/heap/spaces-unittest.cc index 5266e54e09..de4bd39e1e 100644 --- a/deps/v8/test/unittests/heap/spaces-unittest.cc +++ b/deps/v8/test/unittests/heap/spaces-unittest.cc @@ -36,7 +36,7 @@ TEST_F(SpacesTest, CompactionSpaceMerge) { const int kExpectedPages = (kNumObjects + kNumObjectsPerPage - 1) / kNumObjectsPerPage; for (int i = 0; i < kNumObjects; i++) { - HeapObject* object = + HeapObject object = compaction_space->AllocateRawUnaligned(kMaxRegularHeapObjectSize) .ToObjectChecked(); heap->CreateFillerObjectAt(object->address(), kMaxRegularHeapObjectSize, @@ -54,13 +54,13 @@ TEST_F(SpacesTest, CompactionSpaceMerge) { TEST_F(SpacesTest, WriteBarrierFromHeapObject) { constexpr Address address1 = Page::kPageSize; - HeapObject* object1 = reinterpret_cast<HeapObject*>(address1); + HeapObject object1 = HeapObject::unchecked_cast(Object(address1)); MemoryChunk* chunk1 = MemoryChunk::FromHeapObject(object1); heap_internals::MemoryChunk* slim_chunk1 = heap_internals::MemoryChunk::FromHeapObject(object1); EXPECT_EQ(static_cast<void*>(chunk1), static_cast<void*>(slim_chunk1)); constexpr Address address2 = 2 * Page::kPageSize - 1; - HeapObject* object2 = reinterpret_cast<HeapObject*>(address2); + HeapObject object2 = HeapObject::unchecked_cast(Object(address2)); MemoryChunk* chunk2 = MemoryChunk::FromHeapObject(object2); heap_internals::MemoryChunk* slim_chunk2 = heap_internals::MemoryChunk::FromHeapObject(object2); @@ -68,8 +68,9 @@ TEST_F(SpacesTest, WriteBarrierFromHeapObject) { } TEST_F(SpacesTest, WriteBarrierIsMarking) { - char memory[256]; - memset(&memory, 0, sizeof(memory)); + const size_t kSizeOfMemoryChunk = sizeof(MemoryChunk); + char memory[kSizeOfMemoryChunk]; + memset(&memory, 0, kSizeOfMemoryChunk); MemoryChunk* chunk = reinterpret_cast<MemoryChunk*>(&memory); heap_internals::MemoryChunk* slim_chunk = reinterpret_cast<heap_internals::MemoryChunk*>(&memory); @@ -84,8 +85,9 @@ TEST_F(SpacesTest, WriteBarrierIsMarking) { } TEST_F(SpacesTest, WriteBarrierInNewSpaceToSpace) { - char memory[256]; - memset(&memory, 0, sizeof(memory)); + const size_t kSizeOfMemoryChunk = sizeof(MemoryChunk); + char memory[kSizeOfMemoryChunk]; + memset(&memory, 0, kSizeOfMemoryChunk); MemoryChunk* chunk = reinterpret_cast<MemoryChunk*>(&memory); heap_internals::MemoryChunk* slim_chunk = reinterpret_cast<heap_internals::MemoryChunk*>(&memory); @@ -100,8 +102,9 @@ TEST_F(SpacesTest, WriteBarrierInNewSpaceToSpace) { } TEST_F(SpacesTest, WriteBarrierInNewSpaceFromSpace) { - char memory[256]; - memset(&memory, 0, sizeof(memory)); + const size_t kSizeOfMemoryChunk = sizeof(MemoryChunk); + char memory[kSizeOfMemoryChunk]; + memset(&memory, 0, kSizeOfMemoryChunk); MemoryChunk* chunk = reinterpret_cast<MemoryChunk*>(&memory); heap_internals::MemoryChunk* slim_chunk = reinterpret_cast<heap_internals::MemoryChunk*>(&memory); diff --git a/deps/v8/test/unittests/heap/unmapper-unittest.cc b/deps/v8/test/unittests/heap/unmapper-unittest.cc index e28e50e3b7..5b783c42b5 100644 --- a/deps/v8/test/unittests/heap/unmapper-unittest.cc +++ b/deps/v8/test/unittests/heap/unmapper-unittest.cc @@ -2,26 +2,237 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifdef __linux__ -#include <sys/mman.h> -#undef MAP_TYPE -#endif // __linux__ +#include <map> +#include "src/base/region-allocator.h" #include "src/heap/heap-inl.h" #include "src/heap/spaces-inl.h" #include "src/isolate.h" +#include "src/ostreams.h" #include "test/unittests/test-utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace v8 { namespace internal { +// This is a v8::PageAllocator implementation that decorates provided page +// allocator object with page tracking functionality. +class TrackingPageAllocator : public ::v8::PageAllocator { + public: + explicit TrackingPageAllocator(v8::PageAllocator* page_allocator) + : page_allocator_(page_allocator), + allocate_page_size_(page_allocator_->AllocatePageSize()), + commit_page_size_(page_allocator_->CommitPageSize()), + region_allocator_(kNullAddress, size_t{0} - commit_page_size_, + commit_page_size_) { + CHECK_NOT_NULL(page_allocator); + CHECK(IsAligned(allocate_page_size_, commit_page_size_)); + } + ~TrackingPageAllocator() override = default; + + size_t AllocatePageSize() override { return allocate_page_size_; } + + size_t CommitPageSize() override { return commit_page_size_; } + + void SetRandomMmapSeed(int64_t seed) override { + return page_allocator_->SetRandomMmapSeed(seed); + } + + void* GetRandomMmapAddr() override { + return page_allocator_->GetRandomMmapAddr(); + } + + void* AllocatePages(void* address, size_t size, size_t alignment, + PageAllocator::Permission access) override { + void* result = + page_allocator_->AllocatePages(address, size, alignment, access); + if (result) { + // Mark pages as used. + Address current_page = reinterpret_cast<Address>(result); + CHECK(IsAligned(current_page, allocate_page_size_)); + CHECK(IsAligned(size, allocate_page_size_)); + CHECK(region_allocator_.AllocateRegionAt(current_page, size)); + Address end = current_page + size; + while (current_page < end) { + page_permissions_.insert({current_page, access}); + current_page += commit_page_size_; + } + } + return result; + } + + bool FreePages(void* address, size_t size) override { + bool result = page_allocator_->FreePages(address, size); + if (result) { + // Mark pages as free. + Address start = reinterpret_cast<Address>(address); + CHECK(IsAligned(start, allocate_page_size_)); + CHECK(IsAligned(size, allocate_page_size_)); + size_t freed_size = region_allocator_.FreeRegion(start); + CHECK(IsAligned(freed_size, commit_page_size_)); + CHECK_EQ(RoundUp(freed_size, allocate_page_size_), size); + auto start_iter = page_permissions_.find(start); + CHECK_NE(start_iter, page_permissions_.end()); + auto end_iter = page_permissions_.lower_bound(start + size); + page_permissions_.erase(start_iter, end_iter); + } + return result; + } + + bool ReleasePages(void* address, size_t size, size_t new_size) override { + bool result = page_allocator_->ReleasePages(address, size, new_size); + if (result) { + Address start = reinterpret_cast<Address>(address); + CHECK(IsAligned(start, allocate_page_size_)); + CHECK(IsAligned(size, commit_page_size_)); + CHECK(IsAligned(new_size, commit_page_size_)); + CHECK_LT(new_size, size); + CHECK_EQ(region_allocator_.TrimRegion(start, new_size), size - new_size); + auto start_iter = page_permissions_.find(start + new_size); + CHECK_NE(start_iter, page_permissions_.end()); + auto end_iter = page_permissions_.lower_bound(start + size); + page_permissions_.erase(start_iter, end_iter); + } + return result; + } + + bool SetPermissions(void* address, size_t size, + PageAllocator::Permission access) override { + bool result = page_allocator_->SetPermissions(address, size, access); + if (result) { + UpdatePagePermissions(reinterpret_cast<Address>(address), size, access); + } + return result; + } + + // Returns true if all the allocated pages were freed. + bool IsEmpty() { return page_permissions_.empty(); } + + void CheckIsFree(Address address, size_t size) { + CHECK(IsAligned(address, allocate_page_size_)); + CHECK(IsAligned(size, allocate_page_size_)); + EXPECT_TRUE(region_allocator_.IsFree(address, size)); + } + + void CheckPagePermissions(Address address, size_t size, + PageAllocator::Permission access) { + ForEachPage(address, size, [=](PagePermissionsMap::value_type* value) { + EXPECT_EQ(access, value->second); + }); + } + + void Print(const char* comment) const { + i::StdoutStream os; + os << "\n=========================================" + << "\nTracingPageAllocator state: "; + if (comment) os << comment; + os << "\n-----------------------------------------\n"; + region_allocator_.Print(os); + os << "-----------------------------------------" + << "\nPage permissions:"; + if (page_permissions_.empty()) { + os << " empty\n"; + return; + } + os << "\n" << std::hex << std::showbase; + + Address contiguous_region_start = static_cast<Address>(-1); + Address contiguous_region_end = contiguous_region_start; + PageAllocator::Permission contiguous_region_access = + PageAllocator::kNoAccess; + for (auto& pair : page_permissions_) { + if (contiguous_region_end == pair.first && + pair.second == contiguous_region_access) { + contiguous_region_end += commit_page_size_; + continue; + } + if (contiguous_region_start != contiguous_region_end) { + PrintRegion(os, contiguous_region_start, contiguous_region_end, + contiguous_region_access); + } + contiguous_region_start = pair.first; + contiguous_region_end = pair.first + commit_page_size_; + contiguous_region_access = pair.second; + } + if (contiguous_region_start != contiguous_region_end) { + PrintRegion(os, contiguous_region_start, contiguous_region_end, + contiguous_region_access); + } + } + + private: + typedef std::map<Address, PageAllocator::Permission> PagePermissionsMap; + typedef std::function<void(PagePermissionsMap::value_type*)> ForEachFn; + + static void PrintRegion(std::ostream& os, Address start, Address end, + PageAllocator::Permission access) { + os << " page: [" << start << ", " << end << "), access: "; + switch (access) { + case PageAllocator::kNoAccess: + os << "--"; + break; + case PageAllocator::kRead: + os << "R"; + break; + case PageAllocator::kReadWrite: + os << "RW"; + break; + case PageAllocator::kReadWriteExecute: + os << "RWX"; + break; + case PageAllocator::kReadExecute: + os << "RX"; + break; + } + os << "\n"; + } + + void ForEachPage(Address address, size_t size, const ForEachFn& fn) { + CHECK(IsAligned(address, commit_page_size_)); + CHECK(IsAligned(size, commit_page_size_)); + auto start_iter = page_permissions_.find(address); + // Start page must exist in page_permissions_. + CHECK_NE(start_iter, page_permissions_.end()); + auto end_iter = page_permissions_.find(address + size - commit_page_size_); + // Ensure the last but one page exists in page_permissions_. + CHECK_NE(end_iter, page_permissions_.end()); + // Now make it point to the next element in order to also process is by the + // following for loop. + ++end_iter; + for (auto iter = start_iter; iter != end_iter; ++iter) { + PagePermissionsMap::value_type& pair = *iter; + fn(&pair); + } + } + + void UpdatePagePermissions(Address address, size_t size, + PageAllocator::Permission access) { + ForEachPage(address, size, [=](PagePermissionsMap::value_type* value) { + value->second = access; + }); + } + + v8::PageAllocator* const page_allocator_; + const size_t allocate_page_size_; + const size_t commit_page_size_; + // Region allocator tracks page allocation/deallocation requests. + base::RegionAllocator region_allocator_; + // This map keeps track of allocated pages' permissions. + PagePermissionsMap page_permissions_; +}; + class SequentialUnmapperTest : public TestWithIsolate { public: SequentialUnmapperTest() = default; ~SequentialUnmapperTest() override = default; static void SetUpTestCase() { + CHECK_NULL(tracking_page_allocator_); + old_page_allocator_ = GetPlatformPageAllocator(); + tracking_page_allocator_ = new TrackingPageAllocator(old_page_allocator_); + CHECK(tracking_page_allocator_->IsEmpty()); + CHECK_EQ(old_page_allocator_, + SetPlatformPageAllocatorForTesting(tracking_page_allocator_)); old_flag_ = i::FLAG_concurrent_sweeping; i::FLAG_concurrent_sweeping = false; TestWithIsolate::SetUpTestCase(); @@ -30,57 +241,91 @@ class SequentialUnmapperTest : public TestWithIsolate { static void TearDownTestCase() { TestWithIsolate::TearDownTestCase(); i::FLAG_concurrent_sweeping = old_flag_; + CHECK(tracking_page_allocator_->IsEmpty()); + delete tracking_page_allocator_; + tracking_page_allocator_ = nullptr; } Heap* heap() { return isolate()->heap(); } MemoryAllocator* allocator() { return heap()->memory_allocator(); } MemoryAllocator::Unmapper* unmapper() { return allocator()->unmapper(); } + TrackingPageAllocator* tracking_page_allocator() { + return tracking_page_allocator_; + } + private: + static TrackingPageAllocator* tracking_page_allocator_; + static v8::PageAllocator* old_page_allocator_; static bool old_flag_; DISALLOW_COPY_AND_ASSIGN(SequentialUnmapperTest); }; +TrackingPageAllocator* SequentialUnmapperTest::tracking_page_allocator_ = + nullptr; +v8::PageAllocator* SequentialUnmapperTest::old_page_allocator_ = nullptr; bool SequentialUnmapperTest::old_flag_; -#ifdef __linux__ - // See v8:5945. TEST_F(SequentialUnmapperTest, UnmapOnTeardownAfterAlreadyFreeingPooled) { - Page* page = - allocator()->AllocatePage(MemoryAllocator::PageAreaSize(OLD_SPACE), - static_cast<PagedSpace*>(heap()->old_space()), - Executability::NOT_EXECUTABLE); + Page* page = allocator()->AllocatePage( + MemoryChunkLayout::AllocatableMemoryInDataPage(), + static_cast<PagedSpace*>(heap()->old_space()), + Executability::NOT_EXECUTABLE); EXPECT_NE(nullptr, page); - const int page_size = getpagesize(); - void* start_address = reinterpret_cast<void*>(page->address()); - EXPECT_EQ(0, msync(start_address, page_size, MS_SYNC)); + const size_t page_size = tracking_page_allocator()->AllocatePageSize(); + tracking_page_allocator()->CheckPagePermissions(page->address(), page_size, + PageAllocator::kReadWrite); allocator()->Free<MemoryAllocator::kPooledAndQueue>(page); - EXPECT_EQ(0, msync(start_address, page_size, MS_SYNC)); + tracking_page_allocator()->CheckPagePermissions(page->address(), page_size, + PageAllocator::kReadWrite); unmapper()->FreeQueuedChunks(); - EXPECT_EQ(0, msync(start_address, page_size, MS_SYNC)); + tracking_page_allocator()->CheckPagePermissions(page->address(), page_size, + PageAllocator::kNoAccess); unmapper()->TearDown(); - EXPECT_EQ(-1, msync(start_address, page_size, MS_SYNC)); + if (i_isolate()->isolate_allocation_mode() == + IsolateAllocationMode::kInV8Heap) { + // In this mode Isolate uses bounded page allocator which allocates pages + // inside prereserved region. Thus these pages are kept reserved until + // the Isolate dies. + tracking_page_allocator()->CheckPagePermissions(page->address(), page_size, + PageAllocator::kNoAccess); + } else { + CHECK_EQ(IsolateAllocationMode::kInCppHeap, + i_isolate()->isolate_allocation_mode()); + tracking_page_allocator()->CheckIsFree(page->address(), page_size); + } } // See v8:5945. TEST_F(SequentialUnmapperTest, UnmapOnTeardown) { - Page* page = - allocator()->AllocatePage(MemoryAllocator::PageAreaSize(OLD_SPACE), - static_cast<PagedSpace*>(heap()->old_space()), - Executability::NOT_EXECUTABLE); + Page* page = allocator()->AllocatePage( + MemoryChunkLayout::AllocatableMemoryInDataPage(), + static_cast<PagedSpace*>(heap()->old_space()), + Executability::NOT_EXECUTABLE); EXPECT_NE(nullptr, page); - const int page_size = getpagesize(); - void* start_address = reinterpret_cast<void*>(page->address()); - EXPECT_EQ(0, msync(start_address, page_size, MS_SYNC)); + const size_t page_size = tracking_page_allocator()->AllocatePageSize(); + tracking_page_allocator()->CheckPagePermissions(page->address(), page_size, + PageAllocator::kReadWrite); + allocator()->Free<MemoryAllocator::kPooledAndQueue>(page); - EXPECT_EQ(0, msync(start_address, page_size, MS_SYNC)); + tracking_page_allocator()->CheckPagePermissions(page->address(), page_size, + PageAllocator::kReadWrite); unmapper()->TearDown(); - EXPECT_EQ(-1, msync(start_address, page_size, MS_SYNC)); + if (i_isolate()->isolate_allocation_mode() == + IsolateAllocationMode::kInV8Heap) { + // In this mode Isolate uses bounded page allocator which allocates pages + // inside prereserved region. Thus these pages are kept reserved until + // the Isolate dies. + tracking_page_allocator()->CheckPagePermissions(page->address(), page_size, + PageAllocator::kNoAccess); + } else { + CHECK_EQ(IsolateAllocationMode::kInCppHeap, + i_isolate()->isolate_allocation_mode()); + tracking_page_allocator()->CheckIsFree(page->address(), page_size); + } } -#endif // __linux__ - } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc index a2c8d94793..ed53b8b0d2 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -13,6 +13,7 @@ #include "src/interpreter/bytecode-label.h" #include "src/interpreter/bytecode-register-allocator.h" #include "src/objects-inl.h" +#include "src/objects/smi.h" #include "test/unittests/interpreter/bytecode-utils.h" #include "test/unittests/test-utils.h" @@ -54,7 +55,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .CreateArguments(CreateArgumentsType::kRestParameter); // Emit constant loads. - builder.LoadLiteral(Smi::kZero) + builder.LoadLiteral(Smi::zero()) .StoreAccumulatorInRegister(reg) .LoadLiteral(Smi::FromInt(8)) .CompareOperation(Token::Value::EQ, reg, @@ -179,7 +180,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { // Emit literal creation operations. builder.CreateRegExpLiteral(ast_factory.GetOneByteString("a"), 0, 0); builder.CreateArrayLiteral(0, 0, 0); - builder.CreateObjectLiteral(0, 0, 0, reg); + builder.CreateObjectLiteral(0, 0, 0); // Emit tagged template operations. builder.GetTemplateObject(0, 0); @@ -380,7 +381,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .CreateArrayLiteral(0, 0, 0) .CreateEmptyArrayLiteral(0) .CreateArrayFromIterable() - .CreateObjectLiteral(0, 0, 0, reg) + .CreateObjectLiteral(0, 0, 0) .CreateEmptyObjectLiteral() .CloneObject(reg, 0, 0); @@ -488,12 +489,12 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { BytecodeArrayBuilder builder(zone(), 1, locals); BytecodeRegisterAllocator* allocator(builder.register_allocator()); for (int i = 0; i < locals; i++) { - builder.LoadLiteral(Smi::kZero); + builder.LoadLiteral(Smi::zero()); builder.StoreAccumulatorInRegister(Register(i)); } for (int i = 0; i < temps; i++) { Register temp = allocator->NewRegister(); - builder.LoadLiteral(Smi::kZero); + builder.LoadLiteral(Smi::zero()); builder.StoreAccumulatorInRegister(temp); // Ensure temporaries are used so not optimized away by the // register optimizer. diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc index 69d0e96507..ec70605dde 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc @@ -7,6 +7,7 @@ #include "src/interpreter/bytecode-array-builder.h" #include "src/interpreter/bytecode-array-iterator.h" #include "src/objects-inl.h" +#include "src/objects/smi.h" #include "test/unittests/interpreter/bytecode-utils.h" #include "test/unittests/test-utils.h" @@ -29,9 +30,9 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { isolate()->heap()->HashSeed()); double heap_num_0 = 2.718; double heap_num_1 = 2.0 * Smi::kMaxValue; - Smi* zero = Smi::kZero; - Smi* smi_0 = Smi::FromInt(64); - Smi* smi_1 = Smi::FromInt(-65536); + Smi zero = Smi::zero(); + Smi smi_0 = Smi::FromInt(64); + Smi smi_1 = Smi::FromInt(-65536); Register reg_0(0); Register reg_1(1); RegisterList pair = BytecodeUtils::NewRegisterList(0, 2); diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-random-iterator-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-random-iterator-unittest.cc index 71c79300f3..2e2d92628f 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-array-random-iterator-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-array-random-iterator-unittest.cc @@ -7,6 +7,7 @@ #include "src/interpreter/bytecode-array-builder.h" #include "src/interpreter/bytecode-array-random-iterator.h" #include "src/objects-inl.h" +#include "src/objects/smi.h" #include "test/unittests/interpreter/bytecode-utils.h" #include "test/unittests/test-utils.h" @@ -29,9 +30,9 @@ TEST_F(BytecodeArrayRandomIteratorTest, InvalidBeforeStart) { isolate()->heap()->HashSeed()); double heap_num_0 = 2.718; double heap_num_1 = 2.0 * Smi::kMaxValue; - Smi* zero = Smi::kZero; - Smi* smi_0 = Smi::FromInt(64); - Smi* smi_1 = Smi::FromInt(-65536); + Smi zero = Smi::zero(); + Smi smi_0 = Smi::FromInt(64); + Smi smi_1 = Smi::FromInt(-65536); Register reg_0(0); Register reg_1(1); RegisterList pair = BytecodeUtils::NewRegisterList(0, 2); @@ -83,9 +84,9 @@ TEST_F(BytecodeArrayRandomIteratorTest, InvalidAfterEnd) { isolate()->heap()->HashSeed()); double heap_num_0 = 2.718; double heap_num_1 = 2.0 * Smi::kMaxValue; - Smi* zero = Smi::kZero; - Smi* smi_0 = Smi::FromInt(64); - Smi* smi_1 = Smi::FromInt(-65536); + Smi zero = Smi::zero(); + Smi smi_0 = Smi::FromInt(64); + Smi smi_1 = Smi::FromInt(-65536); Register reg_0(0); Register reg_1(1); RegisterList pair = BytecodeUtils::NewRegisterList(0, 2); @@ -137,9 +138,9 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesFirst) { isolate()->heap()->HashSeed()); double heap_num_0 = 2.718; double heap_num_1 = 2.0 * Smi::kMaxValue; - Smi* zero = Smi::kZero; - Smi* smi_0 = Smi::FromInt(64); - Smi* smi_1 = Smi::FromInt(-65536); + Smi zero = Smi::zero(); + Smi smi_0 = Smi::FromInt(64); + Smi smi_1 = Smi::FromInt(-65536); Register reg_0(0); Register reg_1(1); RegisterList pair = BytecodeUtils::NewRegisterList(0, 2); @@ -195,9 +196,9 @@ TEST_F(BytecodeArrayRandomIteratorTest, AccessesLast) { isolate()->heap()->HashSeed()); double heap_num_0 = 2.718; double heap_num_1 = 2.0 * Smi::kMaxValue; - Smi* zero = Smi::kZero; - Smi* smi_0 = Smi::FromInt(64); - Smi* smi_1 = Smi::FromInt(-65536); + Smi zero = Smi::zero(); + Smi smi_0 = Smi::FromInt(64); + Smi smi_1 = Smi::FromInt(-65536); Register reg_0(0); Register reg_1(1); RegisterList pair = BytecodeUtils::NewRegisterList(0, 2); @@ -254,9 +255,9 @@ TEST_F(BytecodeArrayRandomIteratorTest, RandomAccessValid) { isolate()->heap()->HashSeed()); double heap_num_0 = 2.718; double heap_num_1 = 2.0 * Smi::kMaxValue; - Smi* zero = Smi::kZero; - Smi* smi_0 = Smi::FromInt(64); - Smi* smi_1 = Smi::FromInt(-65536); + Smi zero = Smi::zero(); + Smi smi_0 = Smi::FromInt(64); + Smi smi_1 = Smi::FromInt(-65536); Register reg_0(0); Register reg_1(1); RegisterList pair = BytecodeUtils::NewRegisterList(0, 2); @@ -439,9 +440,9 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArray) { isolate()->heap()->HashSeed()); double heap_num_0 = 2.718; double heap_num_1 = 2.0 * Smi::kMaxValue; - Smi* zero = Smi::kZero; - Smi* smi_0 = Smi::FromInt(64); - Smi* smi_1 = Smi::FromInt(-65536); + Smi zero = Smi::zero(); + Smi smi_0 = Smi::FromInt(64); + Smi smi_1 = Smi::FromInt(-65536); Register reg_0(0); Register reg_1(1); RegisterList pair = BytecodeUtils::NewRegisterList(0, 2); @@ -718,9 +719,9 @@ TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) { isolate()->heap()->HashSeed()); double heap_num_0 = 2.718; double heap_num_1 = 2.0 * Smi::kMaxValue; - Smi* zero = Smi::kZero; - Smi* smi_0 = Smi::FromInt(64); - Smi* smi_1 = Smi::FromInt(-65536); + Smi zero = Smi::zero(); + Smi smi_0 = Smi::FromInt(64); + Smi smi_1 = Smi::FromInt(-65536); Register reg_0(0); Register reg_1(1); RegisterList pair = BytecodeUtils::NewRegisterList(0, 2); diff --git a/deps/v8/test/unittests/interpreter/bytecode-decoder-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-decoder-unittest.cc index eb4fdbb745..9c010f25e3 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-decoder-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-decoder-unittest.cc @@ -58,11 +58,10 @@ TEST(BytecodeDecoder, DecodeBytecodeAndOperands) { 2, 3, " Ldar a1"}, - {{B(Wide), B(CreateObjectLiteral), U16(513), U16(1027), U8(165), - R16(137)}, - 9, + {{B(Wide), B(CreateObjectLiteral), U16(513), U16(1027), U8(165)}, + 7, 0, - "CreateObjectLiteral.Wide [513], [1027], #165, r137"}, + "CreateObjectLiteral.Wide [513], [1027], #165"}, {{B(ExtraWide), B(JumpIfNull), U32(123456789)}, 6, 0, diff --git a/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc b/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc index ce6ba81fc1..16b4e80489 100644 --- a/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc @@ -88,7 +88,7 @@ TEST(OperandScaling, ScalableAndNonScalable) { CHECK_EQ(Bytecodes::Size(Bytecode::kCallRuntime, operand_scale), 1 + 2 + 2 * scale); CHECK_EQ(Bytecodes::Size(Bytecode::kCreateObjectLiteral, operand_scale), - 1 + 2 * scale + 1 + 1 * scale); + 1 + 2 * scale + 1); CHECK_EQ(Bytecodes::Size(Bytecode::kTestIn, operand_scale), 1 + scale); } } diff --git a/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc b/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc index 46bbb900c0..55f1cacf56 100644 --- a/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc +++ b/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc @@ -138,7 +138,7 @@ TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx8Reservations) { CHECK_EQ(operand_size, OperandSize::kByte); } for (size_t i = 0; i < duplicates_in_idx8_space; i++) { - Smi* value = Smi::FromInt(static_cast<int>(2 * k8BitCapacity + i)); + Smi value = Smi::FromInt(static_cast<int>(2 * k8BitCapacity + i)); size_t index = builder.CommitReservedEntry(OperandSize::kByte, value); CHECK_EQ(index, k8BitCapacity - reserved + i); } @@ -155,13 +155,13 @@ TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx8Reservations) { // Check all committed values match expected for (size_t i = 0; i < k8BitCapacity - reserved; i++) { - Object* value = constant_array->get(static_cast<int>(i)); - Smi* smi = Smi::FromInt(static_cast<int>(i)); + Object value = constant_array->get(static_cast<int>(i)); + Smi smi = Smi::FromInt(static_cast<int>(i)); CHECK(value->SameValue(smi)); } for (size_t i = k8BitCapacity; i < 2 * k8BitCapacity + reserved; i++) { - Object* value = constant_array->get(static_cast<int>(i)); - Smi* smi = Smi::FromInt(static_cast<int>(i - reserved)); + Object value = constant_array->get(static_cast<int>(i)); + Smi smi = Smi::FromInt(static_cast<int>(i - reserved)); CHECK(value->SameValue(smi)); } } @@ -207,7 +207,7 @@ TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithWideReservations) { CHECK_EQ(constant_array->length(), static_cast<int>(k8BitCapacity + reserved)); for (size_t i = 0; i < k8BitCapacity + reserved; i++) { - Object* value = constant_array->get(static_cast<int>(i)); + Object value = constant_array->get(static_cast<int>(i)); CHECK(value->SameValue(*isolate()->factory()->NewNumberFromSize(i))); } } @@ -237,8 +237,8 @@ TEST_F(ConstantArrayBuilderTest, GapFilledWhenLowReservationCommitted) { Handle<FixedArray> constant_array = builder.ToFixedArray(isolate()); CHECK_EQ(constant_array->length(), static_cast<int>(2 * k8BitCapacity)); for (size_t i = 0; i < k8BitCapacity; i++) { - Object* original = constant_array->get(static_cast<int>(k8BitCapacity + i)); - Object* duplicate = constant_array->get(static_cast<int>(i)); + Object original = constant_array->get(static_cast<int>(k8BitCapacity + i)); + Object duplicate = constant_array->get(static_cast<int>(i)); CHECK(original->SameValue(duplicate)); Handle<Object> reference = isolate()->factory()->NewNumberFromSize(i); CHECK(original->SameValue(*reference)); diff --git a/deps/v8/test/unittests/microtask-queue-unittest.cc b/deps/v8/test/unittests/microtask-queue-unittest.cc new file mode 100644 index 0000000000..cc2c7f0de7 --- /dev/null +++ b/deps/v8/test/unittests/microtask-queue-unittest.cc @@ -0,0 +1,187 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/microtask-queue.h" + +#include <algorithm> +#include <functional> +#include <memory> +#include <vector> + +#include "src/heap/factory.h" +#include "src/objects/foreign.h" +#include "src/visitors.h" +#include "test/unittests/test-utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8 { +namespace internal { + +using Closure = std::function<void()>; + +void RunStdFunction(void* data) { + std::unique_ptr<Closure> f(static_cast<Closure*>(data)); + (*f)(); +} + +class MicrotaskQueueTest : public TestWithNativeContext { + public: + template <typename F> + Handle<Microtask> NewMicrotask(F&& f) { + Handle<Foreign> runner = + factory()->NewForeign(reinterpret_cast<Address>(&RunStdFunction)); + Handle<Foreign> data = factory()->NewForeign( + reinterpret_cast<Address>(new Closure(std::forward<F>(f)))); + return factory()->NewCallbackTask(runner, data); + } + + void SetUp() override { + microtask_queue_ = MicrotaskQueue::New(isolate()); + native_context()->set_microtask_queue(microtask_queue()); + } + + void TearDown() override { + if (microtask_queue()) { + microtask_queue()->RunMicrotasks(isolate()); + context()->DetachGlobal(); + } + } + + MicrotaskQueue* microtask_queue() const { return microtask_queue_.get(); } + + void ClearTestMicrotaskQueue() { + context()->DetachGlobal(); + microtask_queue_ = nullptr; + } + + private: + std::unique_ptr<MicrotaskQueue> microtask_queue_; +}; + +class RecordingVisitor : public RootVisitor { + public: + RecordingVisitor() = default; + ~RecordingVisitor() override = default; + + void VisitRootPointers(Root root, const char* description, + FullObjectSlot start, FullObjectSlot end) override { + for (FullObjectSlot current = start; current != end; ++current) { + visited_.push_back(*current); + } + } + + const std::vector<Object>& visited() const { return visited_; } + + private: + std::vector<Object> visited_; +}; + +// Sanity check. Ensure a microtask is stored in a queue and run. +TEST_F(MicrotaskQueueTest, EnqueueAndRun) { + bool ran = false; + EXPECT_EQ(0, microtask_queue()->capacity()); + EXPECT_EQ(0, microtask_queue()->size()); + microtask_queue()->EnqueueMicrotask(*NewMicrotask([&ran] { + EXPECT_FALSE(ran); + ran = true; + })); + EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity()); + EXPECT_EQ(1, microtask_queue()->size()); + microtask_queue()->RunMicrotasks(isolate()); + EXPECT_TRUE(ran); + EXPECT_EQ(0, microtask_queue()->size()); +} + +// Check for a buffer growth. +TEST_F(MicrotaskQueueTest, BufferGrowth) { + int count = 0; + + // Enqueue and flush the queue first to have non-zero |start_|. + microtask_queue()->EnqueueMicrotask( + *NewMicrotask([&count] { EXPECT_EQ(0, count++); })); + microtask_queue()->RunMicrotasks(isolate()); + + EXPECT_LT(0, microtask_queue()->capacity()); + EXPECT_EQ(0, microtask_queue()->size()); + EXPECT_EQ(1, microtask_queue()->start()); + + // Fill the queue with Microtasks. + for (int i = 1; i <= MicrotaskQueue::kMinimumCapacity; ++i) { + microtask_queue()->EnqueueMicrotask( + *NewMicrotask([&count, i] { EXPECT_EQ(i, count++); })); + } + EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity()); + EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->size()); + + // Add another to grow the ring buffer. + microtask_queue()->EnqueueMicrotask(*NewMicrotask( + [&] { EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, count++); })); + + EXPECT_LT(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity()); + EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, microtask_queue()->size()); + + // Run all pending Microtasks to ensure they run in the proper order. + microtask_queue()->RunMicrotasks(isolate()); + EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 2, count); +} + +// MicrotaskQueue instances form a doubly linked list. +TEST_F(MicrotaskQueueTest, InstanceChain) { + ClearTestMicrotaskQueue(); + + MicrotaskQueue* default_mtq = isolate()->default_microtask_queue(); + ASSERT_TRUE(default_mtq); + EXPECT_EQ(default_mtq, default_mtq->next()); + EXPECT_EQ(default_mtq, default_mtq->prev()); + + // Create two instances, and check their connection. + // The list contains all instances in the creation order, and the next of the + // last instance is the first instance: + // default_mtq -> mtq1 -> mtq2 -> default_mtq. + std::unique_ptr<MicrotaskQueue> mtq1 = MicrotaskQueue::New(isolate()); + std::unique_ptr<MicrotaskQueue> mtq2 = MicrotaskQueue::New(isolate()); + EXPECT_EQ(default_mtq->next(), mtq1.get()); + EXPECT_EQ(mtq1->next(), mtq2.get()); + EXPECT_EQ(mtq2->next(), default_mtq); + EXPECT_EQ(default_mtq, mtq1->prev()); + EXPECT_EQ(mtq1.get(), mtq2->prev()); + EXPECT_EQ(mtq2.get(), default_mtq->prev()); + + // Deleted item should be also removed from the list. + mtq1 = nullptr; + EXPECT_EQ(default_mtq->next(), mtq2.get()); + EXPECT_EQ(mtq2->next(), default_mtq); + EXPECT_EQ(default_mtq, mtq2->prev()); + EXPECT_EQ(mtq2.get(), default_mtq->prev()); +} + +// Pending Microtasks in MicrotaskQueues are strong roots. Ensure they are +// visited exactly once. +TEST_F(MicrotaskQueueTest, VisitRoot) { + // Ensure that the ring buffer has separate in-use region. + for (int i = 0; i < MicrotaskQueue::kMinimumCapacity / 2 + 1; ++i) { + microtask_queue()->EnqueueMicrotask(*NewMicrotask([] {})); + } + microtask_queue()->RunMicrotasks(isolate()); + + std::vector<Object> expected; + for (int i = 0; i < MicrotaskQueue::kMinimumCapacity / 2 + 1; ++i) { + Handle<Microtask> microtask = NewMicrotask([] {}); + expected.push_back(*microtask); + microtask_queue()->EnqueueMicrotask(*microtask); + } + EXPECT_GT(microtask_queue()->start() + microtask_queue()->size(), + microtask_queue()->capacity()); + + RecordingVisitor visitor; + microtask_queue()->IterateMicrotasks(&visitor); + + std::vector<Object> actual = visitor.visited(); + std::sort(expected.begin(), expected.end()); + std::sort(actual.begin(), actual.end()); + EXPECT_EQ(expected, actual); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/objects/microtask-queue-unittest.cc b/deps/v8/test/unittests/objects/microtask-queue-unittest.cc deleted file mode 100644 index 2b237ebc50..0000000000 --- a/deps/v8/test/unittests/objects/microtask-queue-unittest.cc +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2018 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/objects/microtask-queue-inl.h" - -#include "test/unittests/test-utils.h" - -namespace v8 { -namespace internal { - -void NoopCallback(void*) {} - -class MicrotaskQueueTest : public TestWithIsolate { - public: - Handle<Microtask> NewMicrotask() { - MicrotaskCallback callback = &NoopCallback; - void* data = nullptr; - return factory()->NewCallbackTask( - factory()->NewForeign(reinterpret_cast<Address>(callback)), - factory()->NewForeign(reinterpret_cast<Address>(data))); - } -}; - -TEST_F(MicrotaskQueueTest, EnqueueMicrotask) { - Handle<MicrotaskQueue> microtask_queue = factory()->NewMicrotaskQueue(); - Handle<Microtask> microtask = NewMicrotask(); - - EXPECT_EQ(0, microtask_queue->pending_microtask_count()); - MicrotaskQueue::EnqueueMicrotask(isolate(), microtask_queue, microtask); - EXPECT_EQ(1, microtask_queue->pending_microtask_count()); - ASSERT_LE(1, microtask_queue->queue()->length()); - EXPECT_EQ(*microtask, microtask_queue->queue()->get(0)); - - std::vector<Handle<Microtask>> microtasks; - microtasks.push_back(microtask); - - // Queue microtasks until the reallocation happens. - int queue_capacity = microtask_queue->queue()->length(); - for (int i = 0; i < queue_capacity; ++i) { - microtask = NewMicrotask(); - MicrotaskQueue::EnqueueMicrotask(isolate(), microtask_queue, microtask); - microtasks.push_back(microtask); - } - - int num_tasks = static_cast<int>(microtasks.size()); - EXPECT_EQ(num_tasks, microtask_queue->pending_microtask_count()); - ASSERT_LE(num_tasks, microtask_queue->queue()->length()); - for (int i = 0; i < num_tasks; ++i) { - EXPECT_EQ(*microtasks[i], microtask_queue->queue()->get(i)); - } -} - -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/unittests/register-configuration-unittest.cc b/deps/v8/test/unittests/register-configuration-unittest.cc index f0da8a5b93..15873dd69c 100644 --- a/deps/v8/test/unittests/register-configuration-unittest.cc +++ b/deps/v8/test/unittests/register-configuration-unittest.cc @@ -26,10 +26,10 @@ TEST_F(RegisterConfigurationUnitTest, BasicProperties) { int general_codes[kNumAllocatableGeneralRegs] = {1, 2}; int double_codes[kNumAllocatableDoubleRegs] = {2, 3}; - RegisterConfiguration test( - kNumGeneralRegs, kNumDoubleRegs, kNumAllocatableGeneralRegs, - kNumAllocatableDoubleRegs, general_codes, double_codes, - RegisterConfiguration::OVERLAP, nullptr, nullptr, nullptr, nullptr); + RegisterConfiguration test(kNumGeneralRegs, kNumDoubleRegs, + kNumAllocatableGeneralRegs, + kNumAllocatableDoubleRegs, general_codes, + double_codes, RegisterConfiguration::OVERLAP); EXPECT_EQ(test.num_general_registers(), kNumGeneralRegs); EXPECT_EQ(test.num_double_registers(), kNumDoubleRegs); @@ -62,10 +62,10 @@ TEST_F(RegisterConfigurationUnitTest, CombineAliasing) { int general_codes[] = {1, 2}; int double_codes[] = {2, 3, 16}; // reg 16 should not alias registers 32, 33. - RegisterConfiguration test( - kNumGeneralRegs, kNumDoubleRegs, kNumAllocatableGeneralRegs, - kNumAllocatableDoubleRegs, general_codes, double_codes, - RegisterConfiguration::COMBINE, nullptr, nullptr, nullptr, nullptr); + RegisterConfiguration test(kNumGeneralRegs, kNumDoubleRegs, + kNumAllocatableGeneralRegs, + kNumAllocatableDoubleRegs, general_codes, + double_codes, RegisterConfiguration::COMBINE); // There are 3 allocatable double regs, but only 2 can alias float regs. EXPECT_EQ(test.num_allocatable_float_registers(), 4); diff --git a/deps/v8/test/unittests/regress/regress-crbug-938251-unittest.cc b/deps/v8/test/unittests/regress/regress-crbug-938251-unittest.cc new file mode 100644 index 0000000000..3a04fc46e6 --- /dev/null +++ b/deps/v8/test/unittests/regress/regress-crbug-938251-unittest.cc @@ -0,0 +1,20 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/heap/factory.h" +#include "src/isolate.h" +#include "test/unittests/test-utils.h" + +namespace v8 { +namespace internal { + +using NewFixedDoubleArrayTest = TestWithIsolateAndZone; + +TEST_F(NewFixedDoubleArrayTest, ThrowOnNegativeLength) { + ASSERT_DEATH_IF_SUPPORTED({ factory()->NewFixedDoubleArray(-1); }, + "Fatal javascript OOM in invalid array length"); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/test-helpers.cc b/deps/v8/test/unittests/test-helpers.cc index 1ff25337e4..53b07da23b 100644 --- a/deps/v8/test/unittests/test-helpers.cc +++ b/deps/v8/test/unittests/test-helpers.cc @@ -44,7 +44,7 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo( int function_literal_id = 1; // Ensure that the function can be compiled lazily. shared->set_uncompiled_data( - *isolate->factory()->NewUncompiledDataWithoutPreParsedScope( + *isolate->factory()->NewUncompiledDataWithoutPreparseData( ReadOnlyRoots(isolate).empty_string_handle(), 0, source->length(), function_literal_id)); // Make sure we have an outer scope info, even though it's empty diff --git a/deps/v8/test/unittests/test-helpers.h b/deps/v8/test/unittests/test-helpers.h index fadc0c3e2b..8a4d9f02ce 100644 --- a/deps/v8/test/unittests/test-helpers.h +++ b/deps/v8/test/unittests/test-helpers.h @@ -8,7 +8,6 @@ #include <memory> #include "include/v8.h" -#include "src/compiler-dispatcher/compiler-dispatcher-job.h" #include "src/parsing/parse-info.h" namespace v8 { diff --git a/deps/v8/test/unittests/test-utils.cc b/deps/v8/test/unittests/test-utils.cc index 32f405764d..8a31b9ce02 100644 --- a/deps/v8/test/unittests/test-utils.cc +++ b/deps/v8/test/unittests/test-utils.cc @@ -15,109 +15,34 @@ namespace v8 { -// static -v8::ArrayBuffer::Allocator* TestWithIsolate::array_buffer_allocator_ = nullptr; - -// static -Isolate* TestWithIsolate::isolate_ = nullptr; - -TestWithIsolate::TestWithIsolate() - : isolate_scope_(isolate()), handle_scope_(isolate()) {} - -TestWithIsolate::~TestWithIsolate() = default; - -// static -void TestWithIsolate::SetUpTestCase() { - Test::SetUpTestCase(); - EXPECT_EQ(nullptr, isolate_); +IsolateWrapper::IsolateWrapper(bool enforce_pointer_compression) + : array_buffer_allocator_( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()) { v8::Isolate::CreateParams create_params; - array_buffer_allocator_ = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); create_params.array_buffer_allocator = array_buffer_allocator_; - isolate_ = v8::Isolate::New(create_params); - EXPECT_TRUE(isolate_ != nullptr); + if (enforce_pointer_compression) { + isolate_ = reinterpret_cast<v8::Isolate*>( + i::Isolate::New(i::IsolateAllocationMode::kInV8Heap)); + v8::Isolate::Initialize(isolate_, create_params); + } else { + isolate_ = v8::Isolate::New(create_params); + } + CHECK_NOT_NULL(isolate_); } - -// static -void TestWithIsolate::TearDownTestCase() { - ASSERT_TRUE(isolate_ != nullptr); +IsolateWrapper::~IsolateWrapper() { v8::Platform* platform = internal::V8::GetCurrentPlatform(); - ASSERT_TRUE(platform != nullptr); + CHECK_NOT_NULL(platform); while (platform::PumpMessageLoop(platform, isolate_)) continue; isolate_->Dispose(); - isolate_ = nullptr; delete array_buffer_allocator_; - Test::TearDownTestCase(); -} - -Local<Value> TestWithIsolate::RunJS(const char* source) { - Local<Script> script = - v8::Script::Compile( - isolate()->GetCurrentContext(), - v8::String::NewFromUtf8(isolate(), source, v8::NewStringType::kNormal) - .ToLocalChecked()) - .ToLocalChecked(); - return script->Run(isolate()->GetCurrentContext()).ToLocalChecked(); -} - -Local<Value> TestWithIsolate::RunJS( - String::ExternalOneByteStringResource* source) { - Local<Script> script = - v8::Script::Compile( - isolate()->GetCurrentContext(), - v8::String::NewExternalOneByte(isolate(), source).ToLocalChecked()) - .ToLocalChecked(); - return script->Run(isolate()->GetCurrentContext()).ToLocalChecked(); } -TestWithContext::TestWithContext() - : context_(Context::New(isolate())), context_scope_(context_) {} - -TestWithContext::~TestWithContext() = default; - -v8::Local<v8::String> TestWithContext::NewString(const char* string) { - return v8::String::NewFromUtf8(v8_isolate(), string, - v8::NewStringType::kNormal) - .ToLocalChecked(); -} - -void TestWithContext::SetGlobalProperty(const char* name, - v8::Local<v8::Value> value) { - CHECK(v8_context() - ->Global() - ->Set(v8_context(), NewString(name), value) - .FromJust()); -} +// static +v8::IsolateWrapper* SharedIsolateHolder::isolate_wrapper_ = nullptr; namespace internal { -TestWithIsolate::~TestWithIsolate() = default; - -TestWithIsolateAndZone::~TestWithIsolateAndZone() = default; - -Factory* TestWithIsolate::factory() const { return isolate()->factory(); } - -Handle<Object> TestWithIsolate::RunJSInternal(const char* source) { - return Utils::OpenHandle(*::v8::TestWithIsolate::RunJS(source)); -} - -Handle<Object> TestWithIsolate::RunJSInternal( - ::v8::String::ExternalOneByteStringResource* source) { - return Utils::OpenHandle(*::v8::TestWithIsolate::RunJS(source)); -} - -base::RandomNumberGenerator* TestWithIsolate::random_number_generator() const { - return isolate()->random_number_generator(); -} - -TestWithZone::~TestWithZone() = default; - -TestWithNativeContext::~TestWithNativeContext() = default; - -Handle<Context> TestWithNativeContext::native_context() const { - return isolate()->native_context(); -} - SaveFlags::SaveFlags() { non_default_flags_ = FlagList::argv(); } SaveFlags::~SaveFlags() { diff --git a/deps/v8/test/unittests/test-utils.h b/deps/v8/test/unittests/test-utils.h index 289ef5edf2..57db1a39e2 100644 --- a/deps/v8/test/unittests/test-utils.h +++ b/deps/v8/test/unittests/test-utils.h @@ -8,6 +8,7 @@ #include <vector> #include "include/v8.h" +#include "src/api-inl.h" #include "src/base/macros.h" #include "src/base/utils/random-number-generator.h" #include "src/handles.h" @@ -21,126 +22,286 @@ namespace v8 { class ArrayBufferAllocator; -// Use v8::internal::TestWithIsolate if you are testing internals, -// aka. directly work with Handles. -class TestWithIsolate : public virtual ::testing::Test { +// RAII-like Isolate instance wrapper. +class IsolateWrapper final { public: - TestWithIsolate(); - ~TestWithIsolate() override; + // When enforce_pointer_compression is true the Isolate is created with + // enabled pointer compression. When it's false then the Isolate is created + // with the default pointer compression state for current build. + explicit IsolateWrapper(bool enforce_pointer_compression = false); + ~IsolateWrapper(); - v8::Isolate* isolate() const { return v8_isolate(); } + v8::Isolate* isolate() const { return isolate_; } + + private: + v8::ArrayBuffer::Allocator* array_buffer_allocator_; + v8::Isolate* isolate_; - v8::Isolate* v8_isolate() const { return isolate_; } + DISALLOW_COPY_AND_ASSIGN(IsolateWrapper); +}; - v8::internal::Isolate* i_isolate() const { - return reinterpret_cast<v8::internal::Isolate*>(isolate()); +class SharedIsolateHolder final { + public: + static v8::Isolate* isolate() { return isolate_wrapper_->isolate(); } + + static void CreateIsolate() { + CHECK_NULL(isolate_wrapper_); + isolate_wrapper_ = new IsolateWrapper(); + } + + static void DeleteIsolate() { + CHECK_NOT_NULL(isolate_wrapper_); + delete isolate_wrapper_; + isolate_wrapper_ = nullptr; + } + + private: + static v8::IsolateWrapper* isolate_wrapper_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(SharedIsolateHolder); +}; + +// +// A set of mixins from which the test fixtures will be constructed. +// +template <typename TMixin> +class WithPrivateIsolateMixin : public TMixin { + public: + explicit WithPrivateIsolateMixin(bool enforce_pointer_compression = false) + : isolate_wrapper_(enforce_pointer_compression) {} + + v8::Isolate* v8_isolate() const { return isolate_wrapper_.isolate(); } + + static void SetUpTestCase() { TMixin::SetUpTestCase(); } + static void TearDownTestCase() { TMixin::TearDownTestCase(); } + + private: + v8::IsolateWrapper isolate_wrapper_; + + DISALLOW_COPY_AND_ASSIGN(WithPrivateIsolateMixin); +}; + +template <typename TMixin> +class WithSharedIsolateMixin : public TMixin { + public: + WithSharedIsolateMixin() = default; + + v8::Isolate* v8_isolate() const { return SharedIsolateHolder::isolate(); } + + static void SetUpTestCase() { + TMixin::SetUpTestCase(); + SharedIsolateHolder::CreateIsolate(); } - Local<Value> RunJS(const char* source); - Local<Value> RunJS(String::ExternalOneByteStringResource* source); + static void TearDownTestCase() { + SharedIsolateHolder::DeleteIsolate(); + TMixin::TearDownTestCase(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(WithSharedIsolateMixin); +}; + +template <typename TMixin> +class WithPointerCompressionIsolateMixin + : public WithPrivateIsolateMixin<TMixin> { + public: + WithPointerCompressionIsolateMixin() + : WithPrivateIsolateMixin<TMixin>(true) {} + + private: + DISALLOW_COPY_AND_ASSIGN(WithPointerCompressionIsolateMixin); +}; + +template <typename TMixin> +class WithIsolateScopeMixin : public TMixin { + public: + WithIsolateScopeMixin() + : isolate_scope_(v8_isolate()), handle_scope_(v8_isolate()) {} - static void SetUpTestCase(); - static void TearDownTestCase(); + v8::Isolate* isolate() const { return v8_isolate(); } + v8::Isolate* v8_isolate() const { return TMixin::v8_isolate(); } + + v8::internal::Isolate* i_isolate() const { + return reinterpret_cast<v8::internal::Isolate*>(v8_isolate()); + } + + static void SetUpTestCase() { TMixin::SetUpTestCase(); } + static void TearDownTestCase() { TMixin::TearDownTestCase(); } private: - static v8::ArrayBuffer::Allocator* array_buffer_allocator_; - static v8::Isolate* isolate_; v8::Isolate::Scope isolate_scope_; v8::HandleScope handle_scope_; - DISALLOW_COPY_AND_ASSIGN(TestWithIsolate); + DISALLOW_COPY_AND_ASSIGN(WithIsolateScopeMixin); }; -// Use v8::internal::TestWithNativeContext if you are testing internals, -// aka. directly work with Handles. -class TestWithContext : public virtual v8::TestWithIsolate { +template <typename TMixin> +class WithContextMixin : public TMixin { public: - TestWithContext(); - ~TestWithContext() override; + WithContextMixin() + : context_(Context::New(v8_isolate())), context_scope_(context_) {} + + v8::Isolate* v8_isolate() const { return TMixin::v8_isolate(); } const Local<Context>& context() const { return v8_context(); } const Local<Context>& v8_context() const { return context_; } - v8::Local<v8::String> NewString(const char* string); - void SetGlobalProperty(const char* name, v8::Local<v8::Value> value); + Local<Value> RunJS(const char* source) { + return RunJS(v8::String::NewFromUtf8(v8_isolate(), source, + v8::NewStringType::kNormal) + .ToLocalChecked()); + } + + Local<Value> RunJS(v8::String::ExternalOneByteStringResource* source) { + return RunJS( + v8::String::NewExternalOneByte(v8_isolate(), source).ToLocalChecked()); + } + + v8::Local<v8::String> NewString(const char* string) { + return v8::String::NewFromUtf8(v8_isolate(), string, + v8::NewStringType::kNormal) + .ToLocalChecked(); + } + + void SetGlobalProperty(const char* name, v8::Local<v8::Value> value) { + CHECK(v8_context() + ->Global() + ->Set(v8_context(), NewString(name), value) + .FromJust()); + } + + static void SetUpTestCase() { TMixin::SetUpTestCase(); } + static void TearDownTestCase() { TMixin::TearDownTestCase(); } private: - Local<Context> context_; + Local<Value> RunJS(Local<String> source) { + auto context = v8_isolate()->GetCurrentContext(); + Local<Script> script = + v8::Script::Compile(context, source).ToLocalChecked(); + return script->Run(context).ToLocalChecked(); + } + + v8::Local<v8::Context> context_; v8::Context::Scope context_scope_; - DISALLOW_COPY_AND_ASSIGN(TestWithContext); + DISALLOW_COPY_AND_ASSIGN(WithContextMixin); }; +// Use v8::internal::TestWithIsolate if you are testing internals, +// aka. directly work with Handles. +using TestWithIsolate = // + WithIsolateScopeMixin< // + WithSharedIsolateMixin< // + ::testing::Test>>; + +// Use v8::internal::TestWithNativeContext if you are testing internals, +// aka. directly work with Handles. +using TestWithContext = // + WithContextMixin< // + WithIsolateScopeMixin< // + WithSharedIsolateMixin< // + ::testing::Test>>>; + +using TestWithIsolateAndPointerCompression = // + WithContextMixin< // + WithIsolateScopeMixin< // + WithPointerCompressionIsolateMixin< // + ::testing::Test>>>; + namespace internal { // Forward declarations. class Factory; - -class TestWithIsolate : public virtual ::v8::TestWithIsolate { +template <typename TMixin> +class WithInternalIsolateMixin : public TMixin { public: - TestWithIsolate() = default; - ~TestWithIsolate() override; + WithInternalIsolateMixin() = default; + + Factory* factory() const { return isolate()->factory(); } + Isolate* isolate() const { return TMixin::i_isolate(); } + + Handle<NativeContext> native_context() const { + return isolate()->native_context(); + } - Factory* factory() const; - Isolate* isolate() const { return i_isolate(); } template <typename T = Object> Handle<T> RunJS(const char* source) { return Handle<T>::cast(RunJSInternal(source)); } - Handle<Object> RunJSInternal(const char* source); + + Handle<Object> RunJSInternal(const char* source) { + return Utils::OpenHandle(*TMixin::RunJS(source)); + } + template <typename T = Object> Handle<T> RunJS(::v8::String::ExternalOneByteStringResource* source) { return Handle<T>::cast(RunJSInternal(source)); } - Handle<Object> RunJSInternal( - ::v8::String::ExternalOneByteStringResource* source); - base::RandomNumberGenerator* random_number_generator() const; - - private: - DISALLOW_COPY_AND_ASSIGN(TestWithIsolate); -}; + Handle<Object> RunJSInternal( + ::v8::String::ExternalOneByteStringResource* source) { + return Utils::OpenHandle(*TMixin::RunJS(source)); + } -class TestWithZone : public virtual ::testing::Test { - public: - TestWithZone() : zone_(&allocator_, ZONE_NAME) {} - ~TestWithZone() override; + base::RandomNumberGenerator* random_number_generator() const { + return isolate()->random_number_generator(); + } - Zone* zone() { return &zone_; } + static void SetUpTestCase() { TMixin::SetUpTestCase(); } + static void TearDownTestCase() { TMixin::TearDownTestCase(); } private: - v8::internal::AccountingAllocator allocator_; - Zone zone_; - - DISALLOW_COPY_AND_ASSIGN(TestWithZone); + DISALLOW_COPY_AND_ASSIGN(WithInternalIsolateMixin); }; -class TestWithIsolateAndZone : public virtual TestWithIsolate { +template <typename TMixin> +class WithZoneMixin : public TMixin { public: - TestWithIsolateAndZone() : zone_(&allocator_, ZONE_NAME) {} - ~TestWithIsolateAndZone() override; + WithZoneMixin() : zone_(&allocator_, ZONE_NAME) {} Zone* zone() { return &zone_; } + static void SetUpTestCase() { TMixin::SetUpTestCase(); } + static void TearDownTestCase() { TMixin::TearDownTestCase(); } + private: v8::internal::AccountingAllocator allocator_; Zone zone_; - DISALLOW_COPY_AND_ASSIGN(TestWithIsolateAndZone); + DISALLOW_COPY_AND_ASSIGN(WithZoneMixin); }; -class TestWithNativeContext : public virtual ::v8::TestWithContext, - public virtual TestWithIsolate { - public: - TestWithNativeContext() = default; - ~TestWithNativeContext() override; - - Handle<Context> native_context() const; - - private: - DISALLOW_COPY_AND_ASSIGN(TestWithNativeContext); -}; +using TestWithIsolate = // + WithInternalIsolateMixin< // + WithIsolateScopeMixin< // + WithSharedIsolateMixin< // + ::testing::Test>>>; + +using TestWithZone = WithZoneMixin<::testing::Test>; + +using TestWithIsolateAndZone = // + WithInternalIsolateMixin< // + WithIsolateScopeMixin< // + WithSharedIsolateMixin< // + WithZoneMixin< // + ::testing::Test>>>>; + +using TestWithNativeContext = // + WithInternalIsolateMixin< // + WithContextMixin< // + WithIsolateScopeMixin< // + WithSharedIsolateMixin< // + ::testing::Test>>>>; + +using TestWithNativeContextAndZone = // + WithZoneMixin< // + WithInternalIsolateMixin< // + WithContextMixin< // + WithIsolateScopeMixin< // + WithSharedIsolateMixin< // + ::testing::Test>>>>>; class SaveFlags { public: @@ -153,6 +314,14 @@ class SaveFlags { DISALLOW_COPY_AND_ASSIGN(SaveFlags); }; +// For GTest. +inline void PrintTo(Object o, ::std::ostream* os) { + *os << reinterpret_cast<void*>(o.ptr()); +} +inline void PrintTo(Smi o, ::std::ostream* os) { + *os << reinterpret_cast<void*>(o.ptr()); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/torque/torque-unittest.cc b/deps/v8/test/unittests/torque/torque-unittest.cc new file mode 100644 index 0000000000..eca4e6fda2 --- /dev/null +++ b/deps/v8/test/unittests/torque/torque-unittest.cc @@ -0,0 +1,21 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/torque/utils.h" +#include "test/unittests/test-utils.h" + +namespace v8 { +namespace internal { +namespace torque { + +TEST(Torque, StackDeleteRange) { + Stack<int> stack = {1, 2, 3, 4, 5, 6, 7}; + stack.DeleteRange(StackRange{BottomOffset{2}, BottomOffset{4}}); + Stack<int> result = {1, 2, 5, 6, 7}; + ASSERT_TRUE(stack == result); +} + +} // namespace torque +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/unicode-unittest.cc b/deps/v8/test/unittests/unicode-unittest.cc index 068052a3fc..1bede08343 100644 --- a/deps/v8/test/unittests/unicode-unittest.cc +++ b/deps/v8/test/unittests/unicode-unittest.cc @@ -29,8 +29,7 @@ template <size_t kBufferSize> void DecodeUtf16(unibrow::Utf8Decoder<kBufferSize>* decoder, const std::vector<byte>& bytes, std::vector<unibrow::uchar>* output) { - const char* bytes_begin = reinterpret_cast<const char*>(&(*bytes.begin())); - auto vector = Vector<const char>(bytes_begin, bytes.size()); + auto vector = Vector<const char>::cast(VectorOf(bytes)); decoder->Reset(vector); std::vector<uint16_t> utf16(decoder->Utf16Length()); diff --git a/deps/v8/test/unittests/unittests.status b/deps/v8/test/unittests/unittests.status index f0eef446d1..7582deaedd 100644 --- a/deps/v8/test/unittests/unittests.status +++ b/deps/v8/test/unittests/unittests.status @@ -20,4 +20,11 @@ # Uses too much memory. 'Parameterized/WasmCodeManagerTest.GrowingVsFixedModule/Fixed': [SKIP] }], # '(arch == arm or arch == mips) and not simulator_run' + +############################################################################## +['lite_mode', { + # TODO(v8:7777): Re-enable once wasm is supported in jitless mode. + 'ValueSerializerTestWithWasm.*': [SKIP], +}], # lite_mode + ] diff --git a/deps/v8/test/unittests/utils-unittest.cc b/deps/v8/test/unittests/utils-unittest.cc index 0a37e84ab5..c8032d187d 100644 --- a/deps/v8/test/unittests/utils-unittest.cc +++ b/deps/v8/test/unittests/utils-unittest.cc @@ -132,5 +132,73 @@ TYPED_TEST(UtilsTest, PassesFilterTest) { EXPECT_FALSE(PassesFilter(CStrVector(""), CStrVector("a"))); } +TEST(UtilsTest, IsInBounds) { +// for column consistency and terseness +#define INB(x, y, z) EXPECT_TRUE(IsInBounds(x, y, z)) +#define OOB(x, y, z) EXPECT_FALSE(IsInBounds(x, y, z)) + INB(0, 0, 1); + INB(0, 1, 1); + INB(1, 0, 1); + + OOB(0, 2, 1); + OOB(2, 0, 1); + + INB(0, 0, 2); + INB(0, 1, 2); + INB(0, 2, 2); + + INB(0, 0, 2); + INB(1, 0, 2); + INB(2, 0, 2); + + OOB(0, 3, 2); + OOB(3, 0, 2); + + INB(0, 1, 2); + INB(1, 1, 2); + + OOB(1, 2, 2); + OOB(2, 1, 2); + + const size_t max = std::numeric_limits<size_t>::max(); + const size_t half = max / 2; + + // limit cases. + INB(0, 0, max); + INB(0, 1, max); + INB(1, 0, max); + INB(max, 0, max); + INB(0, max, max); + INB(max - 1, 0, max); + INB(0, max - 1, max); + INB(max - 1, 1, max); + INB(1, max - 1, max); + + INB(half, half, max); + INB(half + 1, half, max); + INB(half, half + 1, max); + + OOB(max, 0, 0); + OOB(0, max, 0); + OOB(max, 0, 1); + OOB(0, max, 1); + OOB(max, 0, 2); + OOB(0, max, 2); + + OOB(max, 0, max - 1); + OOB(0, max, max - 1); + + // wraparound cases. + OOB(max, 1, max); + OOB(1, max, max); + OOB(max - 1, 2, max); + OOB(2, max - 1, max); + OOB(half + 1, half + 1, max); + OOB(half + 1, half + 1, max); + +#undef INB +#undef OOB +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/value-serializer-unittest.cc b/deps/v8/test/unittests/value-serializer-unittest.cc index 2cc0bdc8a6..3e6cac2175 100644 --- a/deps/v8/test/unittests/value-serializer-unittest.cc +++ b/deps/v8/test/unittests/value-serializer-unittest.cc @@ -119,7 +119,10 @@ class ValueSerializerTest : public TestWithIsolate { } std::pair<uint8_t*, size_t> buffer = serializer.Release(); std::vector<uint8_t> result(buffer.first, buffer.first + buffer.second); - free(buffer.first); + if (auto* delegate = GetSerializerDelegate()) + delegate->FreeBufferMemory(buffer.first); + else + free(buffer.first); return Just(std::move(result)); } @@ -138,6 +141,10 @@ class ValueSerializerTest : public TestWithIsolate { return buffer; } + std::vector<uint8_t> EncodeTest(const char* source) { + return EncodeTest(EvaluateScriptForInput(source)); + } + v8::Local<v8::Message> InvalidEncodeTest(Local<Value> input_value) { Context::Scope scope(serialization_context()); TryCatch try_catch(isolate()); @@ -318,6 +325,89 @@ TEST_F(ValueSerializerTest, DecodeOddball) { EXPECT_TRUE(value->IsNull()); } +TEST_F(ValueSerializerTest, EncodeArrayStackOverflow) { + InvalidEncodeTest("var a = []; for (var i = 0; i < 1E5; i++) a = [a]; a"); +} + +TEST_F(ValueSerializerTest, EncodeObjectStackOverflow) { + InvalidEncodeTest("var a = {}; for (var i = 0; i < 1E5; i++) a = {a}; a"); +} + +TEST_F(ValueSerializerTest, DecodeArrayStackOverflow) { + static const int nesting_level = 1E5; + std::vector<uint8_t> payload; + // Header. + payload.push_back(0xFF); + payload.push_back(0x0D); + + // Nested arrays, each with one element. + for (int i = 0; i < nesting_level; i++) { + payload.push_back(0x41); + payload.push_back(0x01); + } + + // Innermost array is empty. + payload.push_back(0x41); + payload.push_back(0x00); + payload.push_back(0x24); + payload.push_back(0x00); + payload.push_back(0x00); + + // Close nesting. + for (int i = 0; i < nesting_level; i++) { + payload.push_back(0x24); + payload.push_back(0x00); + payload.push_back(0x01); + } + + InvalidDecodeTest(payload); +} + +TEST_F(ValueSerializerTest, DecodeObjectStackOverflow) { + static const int nesting_level = 1E5; + std::vector<uint8_t> payload; + // Header. + payload.push_back(0xFF); + payload.push_back(0x0D); + + // Nested objects, each with one property 'a'. + for (int i = 0; i < nesting_level; i++) { + payload.push_back(0x6F); + payload.push_back(0x22); + payload.push_back(0x01); + payload.push_back(0x61); + } + + // Innermost array is empty. + payload.push_back(0x6F); + payload.push_back(0x7B); + payload.push_back(0x00); + + // Close nesting. + for (int i = 0; i < nesting_level; i++) { + payload.push_back(0x7B); + payload.push_back(0x01); + } + + InvalidDecodeTest(payload); +} + +TEST_F(ValueSerializerTest, DecodeVerifyObjectCount) { + static const int nesting_level = 1E5; + std::vector<uint8_t> payload; + // Header. + payload.push_back(0xFF); + payload.push_back(0x0D); + + // Repeat SerializationTag:kVerifyObjectCount. This leads to stack overflow. + for (int i = 0; i < nesting_level; i++) { + payload.push_back(0x3F); + payload.push_back(0x01); + } + + InvalidDecodeTest(payload); +} + TEST_F(ValueSerializerTest, RoundTripNumber) { Local<Value> value = RoundTripTest(Integer::New(isolate(), 42)); ASSERT_TRUE(value->IsInt32()); @@ -1871,19 +1961,15 @@ TEST_F(ValueSerializerTest, DecodeDataView) { } TEST_F(ValueSerializerTest, DecodeArrayWithLengthProperty1) { - ASSERT_DEATH_IF_SUPPORTED( - DecodeTest({0xff, 0x0d, 0x41, 0x03, 0x49, 0x02, 0x49, 0x04, - 0x49, 0x06, 0x22, 0x06, 0x6c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x49, 0x02, 0x24, 0x01, 0x03}), - ".*LookupIterator::NOT_FOUND == it.state\\(\\).*"); + InvalidDecodeTest({0xff, 0x0d, 0x41, 0x03, 0x49, 0x02, 0x49, 0x04, + 0x49, 0x06, 0x22, 0x06, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x49, 0x02, 0x24, 0x01, 0x03}); } TEST_F(ValueSerializerTest, DecodeArrayWithLengthProperty2) { - ASSERT_DEATH_IF_SUPPORTED( - DecodeTest({0xff, 0x0d, 0x41, 0x03, 0x49, 0x02, 0x49, 0x04, - 0x49, 0x06, 0x22, 0x06, 0x6c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x6f, 0x7b, 0x00, 0x24, 0x01, 0x03}), - ".*LookupIterator::NOT_FOUND == it.state\\(\\).*"); + InvalidDecodeTest({0xff, 0x0d, 0x41, 0x03, 0x49, 0x02, 0x49, 0x04, + 0x49, 0x06, 0x22, 0x06, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x6f, 0x7b, 0x00, 0x24, 0x01, 0x03}); } TEST_F(ValueSerializerTest, DecodeInvalidDataView) { @@ -2386,7 +2472,7 @@ class ValueSerializerTestWithWasm : public ValueSerializerTest { class ThrowingSerializer : public ValueSerializer::Delegate { public: Maybe<uint32_t> GetWasmModuleTransferId( - Isolate* isolate, Local<WasmCompiledModule> module) override { + Isolate* isolate, Local<WasmModuleObject> module) override { isolate->ThrowException(Exception::Error( String::NewFromOneByte( isolate, @@ -2402,10 +2488,10 @@ class ValueSerializerTestWithWasm : public ValueSerializerTest { class SerializeToTransfer : public ValueSerializer::Delegate { public: SerializeToTransfer( - std::vector<WasmCompiledModule::TransferrableModule>* modules) + std::vector<WasmModuleObject::TransferrableModule>* modules) : modules_(modules) {} Maybe<uint32_t> GetWasmModuleTransferId( - Isolate* isolate, Local<WasmCompiledModule> module) override { + Isolate* isolate, Local<WasmModuleObject> module) override { modules_->push_back(module->GetTransferrableModule()); return Just(static_cast<uint32_t>(modules_->size()) - 1); } @@ -2413,23 +2499,23 @@ class ValueSerializerTestWithWasm : public ValueSerializerTest { void ThrowDataCloneError(Local<String> message) override { UNREACHABLE(); } private: - std::vector<WasmCompiledModule::TransferrableModule>* modules_; + std::vector<WasmModuleObject::TransferrableModule>* modules_; }; class DeserializeFromTransfer : public ValueDeserializer::Delegate { public: DeserializeFromTransfer( - std::vector<WasmCompiledModule::TransferrableModule>* modules) + std::vector<WasmModuleObject::TransferrableModule>* modules) : modules_(modules) {} - MaybeLocal<WasmCompiledModule> GetWasmModuleFromId(Isolate* isolate, - uint32_t id) override { - return WasmCompiledModule::FromTransferrableModule(isolate, - modules_->at(id)); + MaybeLocal<WasmModuleObject> GetWasmModuleFromId(Isolate* isolate, + uint32_t id) override { + return WasmModuleObject::FromTransferrableModule(isolate, + modules_->at(id)); } private: - std::vector<WasmCompiledModule::TransferrableModule>* modules_; + std::vector<WasmModuleObject::TransferrableModule>* modules_; }; ValueSerializer::Delegate* GetSerializerDelegate() override { @@ -2440,9 +2526,9 @@ class ValueSerializerTestWithWasm : public ValueSerializerTest { return current_deserializer_delegate_; } - Local<WasmCompiledModule> MakeWasm() { + Local<WasmModuleObject> MakeWasm() { Context::Scope scope(serialization_context()); - return WasmCompiledModule::DeserializeOrCompile( + return WasmModuleObject::DeserializeOrCompile( isolate(), {nullptr, 0}, {kIncrementerWasm, sizeof(kIncrementerWasm)}) .ToLocalChecked(); @@ -2509,7 +2595,7 @@ class ValueSerializerTestWithWasm : public ValueSerializerTest { private: static bool g_saved_flag; - std::vector<WasmCompiledModule::TransferrableModule> transfer_modules_; + std::vector<WasmModuleObject::TransferrableModule> transfer_modules_; SerializeToTransfer serialize_delegate_; DeserializeFromTransfer deserialize_delegate_; ValueSerializer::Delegate* current_serializer_delegate_ = nullptr; @@ -2715,5 +2801,89 @@ TEST_F(ValueSerializerTestWithWasm, DecodeWasmModuleWithInvalidDataLength) { InvalidDecodeTest({0xFF, 0x09, 0x3F, 0x00, 0x57, 0x79, 0x00, 0x7F}); } +class ValueSerializerTestWithLimitedMemory : public ValueSerializerTest { + protected: +// GMock doesn't use the "override" keyword. +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + + class SerializerDelegate : public ValueSerializer::Delegate { + public: + explicit SerializerDelegate(ValueSerializerTestWithLimitedMemory* test) + : test_(test) {} + + ~SerializerDelegate() { EXPECT_EQ(nullptr, last_buffer_); } + + void SetMemoryLimit(size_t limit) { memory_limit_ = limit; } + + void* ReallocateBufferMemory(void* old_buffer, size_t size, + size_t* actual_size) override { + EXPECT_EQ(old_buffer, last_buffer_); + if (size > memory_limit_) return nullptr; + *actual_size = size; + last_buffer_ = realloc(old_buffer, size); + return last_buffer_; + } + + void FreeBufferMemory(void* buffer) override { + EXPECT_EQ(buffer, last_buffer_); + last_buffer_ = nullptr; + free(buffer); + } + + void ThrowDataCloneError(Local<String> message) override { + test_->isolate()->ThrowException(Exception::Error(message)); + } + + MOCK_METHOD2(WriteHostObject, + Maybe<bool>(Isolate* isolate, Local<Object> object)); + + private: + ValueSerializerTestWithLimitedMemory* test_; + void* last_buffer_ = nullptr; + size_t memory_limit_ = 0; + }; + +#if __clang__ +#pragma clang diagnostic pop +#endif + + ValueSerializer::Delegate* GetSerializerDelegate() override { + return &serializer_delegate_; + } + + void BeforeEncode(ValueSerializer* serializer) override { + serializer_ = serializer; + } + + SerializerDelegate serializer_delegate_{this}; + ValueSerializer* serializer_ = nullptr; +}; + +TEST_F(ValueSerializerTestWithLimitedMemory, FailIfNoMemoryInWriteHostObject) { + EXPECT_CALL(serializer_delegate_, WriteHostObject(isolate(), _)) + .WillRepeatedly(Invoke([this](Isolate*, Local<Object>) { + static const char kDummyData[1024] = {}; + serializer_->WriteRawBytes(&kDummyData, sizeof(kDummyData)); + return Just(true); + })); + + // If there is enough memory, things work. + serializer_delegate_.SetMemoryLimit(2048); + EncodeTest("new ExampleHostObject()"); + + // If not, we get a graceful failure, rather than silent misbehavior. + serializer_delegate_.SetMemoryLimit(1024); + InvalidEncodeTest("new ExampleHostObject()"); + + // And we definitely don't continue to serialize other things. + serializer_delegate_.SetMemoryLimit(1024); + EvaluateScriptForInput("gotA = false"); + InvalidEncodeTest("[new ExampleHostObject, {get a() { gotA = true; }}]"); + EXPECT_TRUE(EvaluateScriptForInput("gotA")->IsFalse()); +} + } // namespace } // namespace v8 diff --git a/deps/v8/test/unittests/wasm/OWNERS b/deps/v8/test/unittests/wasm/OWNERS index 3972f0dd99..dc68b39733 100644 --- a/deps/v8/test/unittests/wasm/OWNERS +++ b/deps/v8/test/unittests/wasm/OWNERS @@ -1,7 +1,5 @@ ahaas@chromium.org -bradnelson@chromium.org clemensh@chromium.org -eholk@chromium.org titzer@chromium.org # COMPONENT: Blink>JavaScript>WebAssembly diff --git a/deps/v8/test/unittests/wasm/decoder-unittest.cc b/deps/v8/test/unittests/wasm/decoder-unittest.cc index e2a7bcc388..1d9d0ea15c 100644 --- a/deps/v8/test/unittests/wasm/decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/decoder-unittest.cc @@ -4,6 +4,7 @@ #include "test/unittests/test-utils.h" +#include "src/base/overflowing-math.h" #include "src/objects-inl.h" #include "src/wasm/decoder.h" #include "test/common/wasm/wasm-macro-gen.h" @@ -475,7 +476,8 @@ TEST_F(DecoderTest, ReadU32v_Bits) { // foreach length 1...32 for (int i = 1; i <= 32; i++) { uint32_t val = kVals[v]; - if (i < 32) val &= ((1 << i) - 1); + if (i < 32) + val &= base::SubWithWraparound(base::ShlWithWraparound(1, i), 1); unsigned length = 1 + i / 7; for (unsigned j = 0; j < kMaxSize; j++) { diff --git a/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc b/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc index 31e4a12ae7..e13816744f 100644 --- a/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc @@ -18,6 +18,7 @@ #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "testing/gmock-support.h" namespace v8 { namespace internal { @@ -54,39 +55,37 @@ static const WasmOpcode kInt32BinopOpcodes[] = { val, WASM_ZERO, kExprBrIf, static_cast<byte>(depth) #define EXPECT_VERIFIES_C(sig, x) \ - Verify(true, sigs.sig(), x, x + arraysize(x), kAppendEnd) + Verify(true, sigs.sig(), ArrayVector(x), kAppendEnd) -#define EXPECT_FAILURE_C(sig, x) \ - Verify(false, sigs.sig(), x, x + arraysize(x), kAppendEnd) +#define EXPECT_FAILURE_C(sig, x, ...) \ + Verify(false, sigs.sig(), ArrayVector(x), kAppendEnd, ##__VA_ARGS__) -#define EXPECT_VERIFIES_SC(sig, x) \ - Verify(true, sig, x, x + arraysize(x), kAppendEnd) +#define EXPECT_VERIFIES_SC(sig, x) Verify(true, sig, ArrayVector(x), kAppendEnd) -#define EXPECT_FAILURE_SC(sig, x) \ - Verify(false, sig, x, x + arraysize(x), kAppendEnd) +#define EXPECT_FAILURE_SC(sig, x) Verify(false, sig, ArrayVector(x), kAppendEnd) -#define EXPECT_VERIFIES_S(env, ...) \ - do { \ - static byte code[] = {__VA_ARGS__}; \ - Verify(true, env, code, code + arraysize(code), kAppendEnd); \ +#define EXPECT_VERIFIES_S(env, ...) \ + do { \ + static byte code[] = {__VA_ARGS__}; \ + Verify(true, env, ArrayVector(code), kAppendEnd); \ } while (false) -#define EXPECT_FAILURE_S(env, ...) \ - do { \ - static byte code[] = {__VA_ARGS__}; \ - Verify(false, env, code, code + arraysize(code), kAppendEnd); \ +#define EXPECT_FAILURE_S(env, ...) \ + do { \ + static byte code[] = {__VA_ARGS__}; \ + Verify(false, env, ArrayVector(code), kAppendEnd); \ } while (false) -#define EXPECT_VERIFIES(sig, ...) \ - do { \ - static const byte code[] = {__VA_ARGS__}; \ - Verify(true, sigs.sig(), code, code + sizeof(code), kAppendEnd); \ +#define EXPECT_VERIFIES(sig, ...) \ + do { \ + static const byte code[] = {__VA_ARGS__}; \ + EXPECT_VERIFIES_C(sig, code); \ } while (false) -#define EXPECT_FAILURE(sig, ...) \ - do { \ - static const byte code[] = {__VA_ARGS__}; \ - Verify(false, sigs.sig(), code, code + sizeof(code), kAppendEnd); \ +#define EXPECT_FAILURE(sig, ...) \ + do { \ + static const byte code[] = {__VA_ARGS__}; \ + EXPECT_FAILURE_C(sig, code); \ } while (false) class FunctionBodyDecoderTest : public TestWithZone { @@ -108,49 +107,48 @@ class FunctionBodyDecoderTest : public TestWithZone { enum AppendEnd : bool { kAppendEnd, kOmitEnd }; - void PrepareBytecode(const byte** startp, const byte** endp, - AppendEnd append_end) { - const byte* start = *startp; - const byte* end = *endp; + Vector<const byte> PrepareBytecode(Vector<const byte> code, + AppendEnd append_end) { size_t locals_size = local_decls.Size(); - size_t total_size = end - start + locals_size; - if (append_end == kAppendEnd) ++total_size; + size_t total_size = + code.size() + locals_size + (append_end == kAppendEnd ? 1 : 0); byte* buffer = static_cast<byte*>(zone()->New(total_size)); // Prepend the local decls to the code. local_decls.Emit(buffer); // Emit the code. - memcpy(buffer + locals_size, start, end - start); + memcpy(buffer + locals_size, code.start(), code.size()); if (append_end == kAppendEnd) { // Append an extra end opcode. buffer[total_size - 1] = kExprEnd; } - *startp = buffer; - *endp = buffer + total_size; + return {buffer, total_size}; } // Prepends local variable declarations and renders nice error messages for // verification failures. - void Verify(bool expected_success, FunctionSig* sig, const byte* start, - const byte* end, AppendEnd append_end) { - PrepareBytecode(&start, &end, append_end); + void Verify(bool expected_success, FunctionSig* sig, Vector<const byte> code, + AppendEnd append_end, const char* message = nullptr) { + code = PrepareBytecode(code, append_end); // Verify the code. - FunctionBody body(sig, 0, start, end); + FunctionBody body(sig, 0, code.start(), code.end()); WasmFeatures unused_detected_features; DecodeResult result = VerifyWasmCode(zone()->allocator(), enabled_features_, module, &unused_detected_features, body); - uint32_t pc = result.error_offset(); std::ostringstream str; - if (expected_success) { - str << "Verification failed: pc = +" << pc - << ", msg = " << result.error_msg(); + if (result.failed()) { + str << "Verification failed: pc = +" << result.error().offset() + << ", msg = " << result.error().message(); } else { - str << "Verification successed, expected failure; pc = +" << pc; + str << "Verification successed, expected failure"; } EXPECT_EQ(result.ok(), expected_success) << str.str(); + if (result.failed() && message) { + EXPECT_THAT(result.error().message(), ::testing::HasSubstr(message)); + } } void TestBinop(WasmOpcode opcode, FunctionSig* success) { @@ -264,6 +262,18 @@ class TestModuleBuilder { void InitializeTable() { mod.tables.emplace_back(); } + byte AddPassiveElementSegment() { + mod.elem_segments.emplace_back(); + return static_cast<byte>(mod.elem_segments.size() - 1); + } + + // Set the number of data segments as declared by the DataCount section. + void SetDataSegmentCount(uint32_t data_segment_count) { + // The Data section occurs after the Code section, so we don't need to + // update mod.data_segments, as it is always empty. + mod.num_declared_data_segments = data_segment_count; + } + WasmModule* module() { return &mod; } private: @@ -286,9 +296,8 @@ TEST_F(FunctionBodyDecoderTest, RefNull) { } TEST_F(FunctionBodyDecoderTest, EmptyFunction) { - byte code[] = {0}; - Verify(true, sigs.v_v(), code, code, kAppendEnd); - Verify(false, sigs.i_i(), code, code, kAppendEnd); + Verify(true, sigs.v_v(), {}, kAppendEnd); + Verify(false, sigs.i_i(), {}, kAppendEnd); } TEST_F(FunctionBodyDecoderTest, IncompleteIf1) { @@ -343,10 +352,10 @@ TEST_F(FunctionBodyDecoderTest, Float64Const) { TEST_F(FunctionBodyDecoderTest, Int32Const_off_end) { byte code[] = {kExprI32Const, 0xAA, 0xBB, 0xCC, 0x44}; - for (int size = 1; size <= 4; size++) { - Verify(false, sigs.i_i(), code, code + size, kAppendEnd); + for (size_t size = 1; size <= 4; ++size) { + Verify(false, sigs.i_i(), {code, size}, kAppendEnd); // Should also fail without the trailing 'end' opcode. - Verify(false, sigs.i_i(), code, code + size, kOmitEnd); + Verify(false, sigs.i_i(), {code, size}, kOmitEnd); } } @@ -524,15 +533,15 @@ TEST_F(FunctionBodyDecoderTest, TeeLocalN_local) { } TEST_F(FunctionBodyDecoderTest, BlockN) { - const int kMaxSize = 200; + constexpr size_t kMaxSize = 200; byte buffer[kMaxSize + 3]; - for (int i = 0; i <= kMaxSize; i++) { + for (size_t i = 0; i <= kMaxSize; i++) { memset(buffer, kExprNop, sizeof(buffer)); buffer[0] = kExprBlock; buffer[1] = kLocalVoid; buffer[i + 2] = kExprEnd; - Verify(true, sigs.v_i(), buffer, buffer + i + 3, kAppendEnd); + Verify(true, sigs.v_i(), {buffer, i + 3}, kAppendEnd); } } @@ -679,8 +688,8 @@ TEST_F(FunctionBodyDecoderTest, BlockN_off_end) { byte code[] = {WASM_BLOCK(kExprNop, kExprNop, kExprNop, kExprNop)}; EXPECT_VERIFIES_C(v_v, code); for (size_t i = 1; i < arraysize(code); i++) { - Verify(false, sigs.v_v(), code, code + i, kAppendEnd); - Verify(false, sigs.v_v(), code, code + i, kOmitEnd); + Verify(false, sigs.v_v(), {code, i}, kAppendEnd); + Verify(false, sigs.v_v(), {code, i}, kOmitEnd); } } @@ -787,6 +796,13 @@ TEST_F(FunctionBodyDecoderTest, IfElseUnreachable2) { } } +TEST_F(FunctionBodyDecoderTest, OneArmedIfWithArity) { + static const byte code[] = {WASM_ZERO, kExprIf, kLocalI32, WASM_ONE, + kExprEnd}; + EXPECT_FAILURE_C(i_v, code, + "start-arity and end-arity of one-armed if must match"); +} + TEST_F(FunctionBodyDecoderTest, IfBreak) { EXPECT_VERIFIES(v_i, WASM_IF(WASM_GET_LOCAL(0), WASM_BR(0))); EXPECT_VERIFIES(v_i, WASM_IF(WASM_GET_LOCAL(0), WASM_BR(1))); @@ -1011,8 +1027,8 @@ TEST_F(FunctionBodyDecoderTest, If_off_end) { static const byte kCode[] = { WASM_IF_ELSE(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))}; for (size_t len = 3; len < arraysize(kCode); len++) { - Verify(false, sigs.i_i(), kCode, kCode + len, kAppendEnd); - Verify(false, sigs.i_i(), kCode, kCode + len, kOmitEnd); + Verify(false, sigs.i_i(), {kCode, len}, kAppendEnd); + Verify(false, sigs.i_i(), {kCode, len}, kOmitEnd); } } @@ -1614,7 +1630,7 @@ TEST_F(FunctionBodyDecoderTest, IncompleteIndirectCall) { module = builder.module(); static byte code[] = {kExprCallIndirect}; - Verify(false, sig, code, code + arraysize(code), kOmitEnd); + Verify(false, sig, ArrayVector(code), kOmitEnd); } TEST_F(FunctionBodyDecoderTest, IncompleteStore) { @@ -1625,7 +1641,7 @@ TEST_F(FunctionBodyDecoderTest, IncompleteStore) { module = builder.module(); static byte code[] = {kExprI32StoreMem}; - Verify(false, sig, code, code + arraysize(code), kOmitEnd); + Verify(false, sig, ArrayVector(code), kOmitEnd); } TEST_F(FunctionBodyDecoderTest, IncompleteS8x16Shuffle) { @@ -1638,7 +1654,7 @@ TEST_F(FunctionBodyDecoderTest, IncompleteS8x16Shuffle) { static byte code[] = {kSimdPrefix, static_cast<byte>(kExprS8x16Shuffle & 0xff)}; - Verify(false, sig, code, code + arraysize(code), kOmitEnd); + Verify(false, sig, ArrayVector(code), kOmitEnd); } TEST_F(FunctionBodyDecoderTest, SimpleImportCalls) { @@ -1798,22 +1814,22 @@ TEST_F(FunctionBodyDecoderTest, AllSetGlobalCombinations) { } } -TEST_F(FunctionBodyDecoderTest, WasmGrowMemory) { +TEST_F(FunctionBodyDecoderTest, WasmMemoryGrow) { TestModuleBuilder builder; module = builder.module(); builder.InitializeMemory(); - byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0}; + byte code[] = {WASM_GET_LOCAL(0), kExprMemoryGrow, 0}; EXPECT_VERIFIES_C(i_i, code); EXPECT_FAILURE_C(i_d, code); } -TEST_F(FunctionBodyDecoderTest, AsmJsGrowMemory) { +TEST_F(FunctionBodyDecoderTest, AsmJsMemoryGrow) { TestModuleBuilder builder(kAsmJsOrigin); module = builder.module(); builder.InitializeMemory(); - byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0}; + byte code[] = {WASM_GET_LOCAL(0), kExprMemoryGrow, 0}; EXPECT_FAILURE_C(i_i, code); } @@ -2214,8 +2230,8 @@ TEST_F(FunctionBodyDecoderTest, BrTable2b) { TEST_F(FunctionBodyDecoderTest, BrTable_off_end) { static byte code[] = {B1(WASM_BR_TABLE(WASM_GET_LOCAL(0), 0, BR_TARGET(0)))}; for (size_t len = 1; len < sizeof(code); len++) { - Verify(false, sigs.i_i(), code, code + len, kAppendEnd); - Verify(false, sigs.i_i(), code, code + len, kOmitEnd); + Verify(false, sigs.i_i(), {code, len}, kAppendEnd); + Verify(false, sigs.i_i(), {code, len}, kOmitEnd); } } @@ -2429,38 +2445,57 @@ TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) { } #define WASM_TRY_OP kExprTry, kLocalVoid -#define WASM_CATCH(index) kExprCatch, static_cast<byte>(index) +#define WASM_BR_ON_EXN(depth, index) \ + kExprBrOnExn, static_cast<byte>(depth), static_cast<byte>(index) TEST_F(FunctionBodyDecoderTest, TryCatch) { WASM_FEATURE_SCOPE(eh); TestModuleBuilder builder; module = builder.module(); - byte ex1 = builder.AddException(sigs.v_v()); - byte ex2 = builder.AddException(sigs.v_v()); - EXPECT_VERIFIES(v_v, WASM_TRY_OP, WASM_CATCH(ex1), kExprEnd); - EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprEnd); // Missing catch. - EXPECT_FAILURE(v_v, WASM_TRY_OP, WASM_CATCH(ex1)); // Missing end. - EXPECT_FAILURE(v_v, WASM_CATCH(ex1), kExprEnd); // Missing try. - - // TODO(mstarzinger): Double catch. Fix this to verify. - EXPECT_FAILURE(v_v, WASM_TRY_OP, WASM_CATCH(ex1), WASM_CATCH(ex2), kExprEnd); + EXPECT_VERIFIES(v_v, WASM_TRY_OP, kExprCatch, kExprDrop, kExprEnd); + EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatch, kExprCatch, kExprEnd); + EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprEnd); // Missing catch. + EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatch); // Missing end. + EXPECT_FAILURE(v_v, kExprCatch, kExprEnd); // Missing try. } -TEST_F(FunctionBodyDecoderTest, TryCatchAll) { +TEST_F(FunctionBodyDecoderTest, Rethrow) { WASM_FEATURE_SCOPE(eh); TestModuleBuilder builder; module = builder.module(); - byte ex1 = builder.AddException(sigs.v_v()); - EXPECT_VERIFIES(v_v, WASM_TRY_OP, kExprCatchAll, kExprEnd); - EXPECT_VERIFIES(v_v, WASM_TRY_OP, WASM_CATCH(ex1), kExprCatchAll, kExprEnd); - EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatchAll, kExprCatchAll, kExprEnd); - EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatchAll, WASM_CATCH(ex1), kExprEnd); - EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatchAll); // Missing end. - EXPECT_FAILURE(v_v, kExprCatchAll, kExprEnd); // Missing try. + EXPECT_VERIFIES(v_v, WASM_TRY_OP, kExprCatch, kExprRethrow, kExprEnd); + EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprRethrow, kExprCatch, kExprEnd); + EXPECT_FAILURE(v_v, WASM_BLOCK(kExprRethrow)); + EXPECT_FAILURE(v_v, kExprRethrow); } +TEST_F(FunctionBodyDecoderTest, BrOnExn) { + WASM_FEATURE_SCOPE(eh); + TestModuleBuilder builder; + module = builder.module(); + byte ex1 = builder.AddException(sigs.v_v()); + byte ex2 = builder.AddException(sigs.v_i()); + EXPECT_VERIFIES(v_v, WASM_TRY_OP, kExprCatch, WASM_BR_ON_EXN(0, ex1), + kExprDrop, kExprEnd); + EXPECT_VERIFIES(v_v, WASM_TRY_OP, kExprCatch, WASM_BR_ON_EXN(1, ex1), + kExprDrop, kExprEnd); + EXPECT_VERIFIES(v_v, WASM_TRY_OP, kExprCatch, WASM_BR_ON_EXN(0, ex1), + WASM_BR_ON_EXN(0, ex1), kExprDrop, kExprEnd); + EXPECT_VERIFIES(v_v, WASM_BLOCK(WASM_TRY_OP, kExprCatch, + WASM_BR_ON_EXN(1, ex1), kExprDrop, kExprEnd)); + EXPECT_VERIFIES(i_v, + WASM_BLOCK_I(WASM_TRY_OP, kExprCatch, WASM_BR_ON_EXN(1, ex2), + kExprDrop, kExprEnd, kExprI32Const, 0)); + EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatch, WASM_BR_ON_EXN(2, ex1), + kExprDrop, kExprEnd); + EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatch, kExprDrop, + WASM_BR_ON_EXN(0, ex1), kExprEnd); + EXPECT_FAILURE(v_v, WASM_TRY_OP, kExprCatch, WASM_BR_ON_EXN(0, ex1), + kExprEnd); +} + +#undef WASM_BR_ON_EXN #undef WASM_TRY_OP -#undef WASM_CATCH TEST_F(FunctionBodyDecoderTest, MultiValBlock1) { WASM_FEATURE_SCOPE(mv); @@ -2690,13 +2725,10 @@ TEST_F(FunctionBodyDecoderTest, IfParam) { TEST_F(FunctionBodyDecoderTest, Regression709741) { AddLocals(kWasmI32, kV8MaxWasmFunctionLocals - 1); EXPECT_VERIFIES(v_v, WASM_NOP); - byte code[] = {WASM_NOP}; - const byte* start = code; - const byte* end = code + sizeof(code); - PrepareBytecode(&start, &end, kAppendEnd); + byte code[] = {WASM_NOP, WASM_END}; - for (const byte* i = start; i < end; i++) { - FunctionBody body(sigs.v_v(), 0, start, i); + for (size_t i = 0; i < arraysize(code); ++i) { + FunctionBody body(sigs.v_v(), 0, code, code + i); WasmFeatures unused_detected_features; DecodeResult result = VerifyWasmCode(zone()->allocator(), kAllWasmFeatures, nullptr, @@ -2708,6 +2740,129 @@ TEST_F(FunctionBodyDecoderTest, Regression709741) { } } +TEST_F(FunctionBodyDecoderTest, MemoryInit) { + TestModuleBuilder builder; + builder.InitializeMemory(); + builder.SetDataSegmentCount(1); + module = builder.module(); + + EXPECT_FAILURE(v_v, WASM_MEMORY_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO)); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(v_v, WASM_MEMORY_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO)); + EXPECT_FAILURE(v_v, WASM_TABLE_INIT(1, WASM_ZERO, WASM_ZERO, WASM_ZERO)); +} + +TEST_F(FunctionBodyDecoderTest, MemoryInitInvalid) { + TestModuleBuilder builder; + builder.InitializeMemory(); + builder.SetDataSegmentCount(1); + module = builder.module(); + + WASM_FEATURE_SCOPE(bulk_memory); + byte code[] = {WASM_MEMORY_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO), + WASM_END}; + for (size_t i = 0; i <= arraysize(code); ++i) { + Verify(i == arraysize(code), sigs.v_v(), {code, i}, kOmitEnd); + } +} + +TEST_F(FunctionBodyDecoderTest, MemoryDrop) { + TestModuleBuilder builder; + builder.InitializeMemory(); + builder.SetDataSegmentCount(1); + module = builder.module(); + + EXPECT_FAILURE(v_v, WASM_MEMORY_DROP(0)); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(v_v, WASM_MEMORY_DROP(0)); + EXPECT_FAILURE(v_v, WASM_MEMORY_DROP(1)); +} + +TEST_F(FunctionBodyDecoderTest, MemoryCopy) { + TestModuleBuilder builder; + builder.InitializeMemory(); + module = builder.module(); + + EXPECT_FAILURE(v_v, WASM_MEMORY_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO)); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(v_v, WASM_MEMORY_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO)); +} + +TEST_F(FunctionBodyDecoderTest, MemoryFill) { + TestModuleBuilder builder; + builder.InitializeMemory(); + module = builder.module(); + + EXPECT_FAILURE(v_v, WASM_MEMORY_FILL(WASM_ZERO, WASM_ZERO, WASM_ZERO)); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(v_v, WASM_MEMORY_FILL(WASM_ZERO, WASM_ZERO, WASM_ZERO)); +} + +TEST_F(FunctionBodyDecoderTest, BulkMemoryOpsWithoutMemory) { + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_FAILURE(v_v, WASM_MEMORY_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO)); + EXPECT_FAILURE(v_v, WASM_MEMORY_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO)); + EXPECT_FAILURE(v_v, WASM_MEMORY_FILL(WASM_ZERO, WASM_ZERO, WASM_ZERO)); +} + +TEST_F(FunctionBodyDecoderTest, TableInit) { + TestModuleBuilder builder; + builder.InitializeTable(); + builder.AddPassiveElementSegment(); + module = builder.module(); + + EXPECT_FAILURE(v_v, WASM_TABLE_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO)); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(v_v, WASM_TABLE_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO)); + EXPECT_FAILURE(v_v, WASM_TABLE_INIT(1, WASM_ZERO, WASM_ZERO, WASM_ZERO)); +} + +TEST_F(FunctionBodyDecoderTest, TableInitInvalid) { + TestModuleBuilder builder; + builder.InitializeTable(); + builder.AddPassiveElementSegment(); + module = builder.module(); + + WASM_FEATURE_SCOPE(bulk_memory); + byte code[] = {WASM_TABLE_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO), WASM_END}; + for (size_t i = 0; i <= arraysize(code); ++i) { + Verify(i == arraysize(code), sigs.v_v(), {code, i}, kOmitEnd); + } +} + +TEST_F(FunctionBodyDecoderTest, TableDrop) { + TestModuleBuilder builder; + builder.InitializeTable(); + builder.AddPassiveElementSegment(); + module = builder.module(); + + EXPECT_FAILURE(v_v, WASM_TABLE_DROP(0)); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(v_v, WASM_TABLE_DROP(0)); + EXPECT_FAILURE(v_v, WASM_TABLE_DROP(1)); +} + +TEST_F(FunctionBodyDecoderTest, TableCopy) { + TestModuleBuilder builder; + builder.InitializeTable(); + module = builder.module(); + + EXPECT_FAILURE(v_v, WASM_TABLE_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO)); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(v_v, WASM_TABLE_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO)); +} + +TEST_F(FunctionBodyDecoderTest, BulkTableOpsWithoutTable) { + TestModuleBuilder builder; + builder.InitializeTable(); + builder.AddPassiveElementSegment(); + + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_FAILURE(v_v, WASM_TABLE_INIT(0, WASM_ZERO, WASM_ZERO, WASM_ZERO)); + EXPECT_FAILURE(v_v, WASM_TABLE_DROP(0)); + EXPECT_FAILURE(v_v, WASM_TABLE_COPY(WASM_ZERO, WASM_ZERO, WASM_ZERO)); +} + class BranchTableIteratorTest : public TestWithZone { public: BranchTableIteratorTest() : TestWithZone() {} @@ -2795,10 +2950,12 @@ TEST_F(WasmOpcodeLengthTest, Statements) { EXPECT_LENGTH(1, kExprElse); EXPECT_LENGTH(1, kExprEnd); EXPECT_LENGTH(1, kExprSelect); + EXPECT_LENGTH(1, kExprCatch); + EXPECT_LENGTH(1, kExprRethrow); EXPECT_LENGTH(2, kExprBr); EXPECT_LENGTH(2, kExprBrIf); EXPECT_LENGTH(2, kExprThrow); - EXPECT_LENGTH(2, kExprCatch); + EXPECT_LENGTH(3, kExprBrOnExn); EXPECT_LENGTH_N(2, kExprBlock, kLocalI32); EXPECT_LENGTH_N(2, kExprLoop, kLocalI32); EXPECT_LENGTH_N(2, kExprIf, kLocalI32); @@ -2874,7 +3031,7 @@ TEST_F(WasmOpcodeLengthTest, LoadsAndStores) { TEST_F(WasmOpcodeLengthTest, MiscMemExpressions) { EXPECT_LENGTH(2, kExprMemorySize); - EXPECT_LENGTH(2, kExprGrowMemory); + EXPECT_LENGTH(2, kExprMemoryGrow); } TEST_F(WasmOpcodeLengthTest, SimpleExpressions) { diff --git a/deps/v8/test/unittests/wasm/module-decoder-unittest.cc b/deps/v8/test/unittests/wasm/module-decoder-unittest.cc index 83876b3e0f..3d99dffa72 100644 --- a/deps/v8/test/unittests/wasm/module-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/module-decoder-unittest.cc @@ -12,6 +12,9 @@ #include "src/wasm/wasm-opcodes.h" #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "testing/gmock-support.h" + +using testing::HasSubstr; namespace v8 { namespace internal { @@ -29,38 +32,50 @@ namespace module_decoder_unittest { #define WASM_INIT_EXPR_ANYREF WASM_REF_NULL, kExprEnd #define WASM_INIT_EXPR_GLOBAL(index) WASM_GET_GLOBAL(index), kExprEnd -#define SIZEOF_EMPTY_FUNCTION ((size_t)5) #define EMPTY_BODY 0 -#define SIZEOF_EMPTY_BODY ((size_t)1) #define NOP_BODY 2, 0, kExprNop -#define SIZEOF_NOP_BODY ((size_t)3) #define SIG_ENTRY_i_i SIG_ENTRY_x_x(kLocalI32, kLocalI32) -#define UNKNOWN_SECTION(size) 0, U32V_1(size + 5), 4, 'l', 'u', 'l', 'z' +#define UNKNOWN_SECTION(size) 0, U32V_1(size + 5), ADD_COUNT('l', 'u', 'l', 'z') + +template <typename... Args> +std::integral_constant<size_t, sizeof...(Args)> CountArgsHelper(Args...); +#define COUNT_ARGS(...) (decltype(CountArgsHelper(__VA_ARGS__))::value) + +template <size_t num> +struct CheckLEB1 : std::integral_constant<size_t, num> { + static_assert(num <= I32V_MAX(1), "LEB range check"); +}; +#define CHECK_LEB1(num) CheckLEB1<num>::value -#define SECTION(name, size) k##name##SectionCode, U32V_1(size) +#define ADD_COUNT(...) CHECK_LEB1(COUNT_ARGS(__VA_ARGS__)), __VA_ARGS__ -#define SIGNATURES_SECTION(count, ...) \ - SECTION(Type, 1 + 3 * (count)), U32V_1(count), __VA_ARGS__ +#define SECTION(name, ...) k##name##SectionCode, ADD_COUNT(__VA_ARGS__) + +#define SIGNATURES_SECTION(count, ...) SECTION(Type, U32V_1(count), __VA_ARGS__) #define FUNCTION_SIGNATURES_SECTION(count, ...) \ - SECTION(Function, 1 + (count)), U32V_1(count), __VA_ARGS__ + SECTION(Function, U32V_1(count), __VA_ARGS__) -#define FOO_STRING 3, 'f', 'o', 'o' +#define FOO_STRING ADD_COUNT('f', 'o', 'o') #define NO_LOCAL_NAMES 0 -#define EMPTY_SIGNATURES_SECTION SECTION(Type, 1), 0 -#define EMPTY_FUNCTION_SIGNATURES_SECTION SECTION(Function, 1), 0 -#define EMPTY_FUNCTION_BODIES_SECTION SECTION(Code, 1), 0 -#define SECTION_NAMES(size) SECTION(Unknown, size + 5), 4, 'n', 'a', 'm', 'e' -#define SECTION_EXCEPTIONS(size) SECTION(Exception, size) -#define EMPTY_NAMES_SECTION SECTION_NAMES(1), 0 +#define EMPTY_SIGNATURES_SECTION SECTION(Type, ENTRY_COUNT(0)) +#define EMPTY_FUNCTION_SIGNATURES_SECTION SECTION(Function, ENTRY_COUNT(0)) +#define EMPTY_FUNCTION_BODIES_SECTION SECTION(Code, ENTRY_COUNT(0)) +#define SECTION_NAMES(...) \ + SECTION(Unknown, ADD_COUNT('n', 'a', 'm', 'e'), ##__VA_ARGS__) +#define EMPTY_NAMES_SECTION SECTION_NAMES() +#define SECTION_SRC_MAP(...) \ + SECTION(Unknown, \ + ADD_COUNT('s', 'o', 'u', 'r', 'c', 'e', 'M', 'a', 'p', 'p', 'i', \ + 'n', 'g', 'U', 'R', 'L'), \ + ADD_COUNT(__VA_ARGS__)) #define FAIL_IF_NO_EXPERIMENTAL_EH(data) \ do { \ ModuleResult result = DecodeModule((data), (data) + sizeof((data))); \ EXPECT_FALSE(result.ok()); \ - EXPECT_EQ(0u, result.val->exceptions.size()); \ } while (false) #define X1(...) __VA_ARGS__ @@ -68,35 +83,30 @@ namespace module_decoder_unittest { #define X3(...) __VA_ARGS__, __VA_ARGS__, __VA_ARGS__ #define X4(...) __VA_ARGS__, __VA_ARGS__, __VA_ARGS__, __VA_ARGS__ -#define ONE_EMPTY_FUNCTION SECTION(Function, 1 + 1 * 1), 1, X1(0) - -#define TWO_EMPTY_FUNCTIONS SECTION(Function, 1 + 2 * 1), 2, X2(0) - -#define THREE_EMPTY_FUNCTIONS SECTION(Function, 1 + 3 * 1), 3, X3(0) +#define ONE_EMPTY_FUNCTION(sig_index) \ + SECTION(Function, ENTRY_COUNT(1), X1(sig_index)) -#define FOUR_EMPTY_FUNCTIONS SECTION(Function, 1 + 4 * 1), 4, X4(0) +#define TWO_EMPTY_FUNCTIONS(sig_index) \ + SECTION(Function, ENTRY_COUNT(2), X2(sig_index)) -#define ONE_EMPTY_BODY \ - SECTION(Code, 1 + 1 * (1 + SIZEOF_EMPTY_BODY)) \ - , 1, X1(SIZEOF_EMPTY_BODY, EMPTY_BODY) +#define THREE_EMPTY_FUNCTIONS(sig_index) \ + SECTION(Function, ENTRY_COUNT(3), X3(sig_index)) -#define TWO_EMPTY_BODIES \ - SECTION(Code, 1 + 2 * (1 + SIZEOF_EMPTY_BODY)) \ - , 2, X2(SIZEOF_EMPTY_BODY, EMPTY_BODY) +#define FOUR_EMPTY_FUNCTIONS(sig_index) \ + SECTION(Function, ENTRY_COUNT(4), X4(sig_index)) -#define THREE_EMPTY_BODIES \ - SECTION(Code, 1 + 3 * (1 + SIZEOF_EMPTY_BODY)) \ - , 3, X3(SIZEOF_EMPTY_BODY, EMPTY_BODY) - -#define FOUR_EMPTY_BODIES \ - SECTION(Code, 1 + 4 * (1 + SIZEOF_EMPTY_BODY)) \ - , 4, X4(SIZEOF_EMPTY_BODY, EMPTY_BODY) +#define ONE_EMPTY_BODY SECTION(Code, ENTRY_COUNT(1), X1(EMPTY_BODY)) +#define TWO_EMPTY_BODIES SECTION(Code, ENTRY_COUNT(2), X2(EMPTY_BODY)) +#define THREE_EMPTY_BODIES SECTION(Code, ENTRY_COUNT(3), X3(EMPTY_BODY)) +#define FOUR_EMPTY_BODIES SECTION(Code, ENTRY_COUNT(4), X4(EMPTY_BODY)) #define SIGNATURES_SECTION_VOID_VOID \ - SECTION(Type, 1 + SIZEOF_SIG_ENTRY_v_v), 1, SIG_ENTRY_v_v + SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_v) #define LINEAR_MEMORY_INDEX_0 0 +#define EXCEPTION_ENTRY(sig_index) U32V_1(kExceptionAttribute), sig_index + #define EXPECT_VERIFIES(data) \ do { \ ModuleResult result = DecodeModule(data, data + sizeof(data)); \ @@ -111,11 +121,12 @@ namespace module_decoder_unittest { #define EXPECT_FAILURE(data) EXPECT_FAILURE_LEN(data, sizeof(data)) -#define EXPECT_OFF_END_FAILURE(data, min, max) \ - do { \ - for (size_t length = min; length < max; length++) { \ - EXPECT_FAILURE_LEN(data, length); \ - } \ +#define EXPECT_OFF_END_FAILURE(data, min) \ + do { \ + STATIC_ASSERT(min < arraysize(data)); \ + for (size_t length = min; length < arraysize(data); length++) { \ + EXPECT_FAILURE_LEN(data, length); \ + } \ } while (false) #define EXPECT_OK(result) \ @@ -124,6 +135,12 @@ namespace module_decoder_unittest { if (!result.ok()) return; \ } while (false) +#define EXPECT_NOT_OK(result, msg) \ + do { \ + EXPECT_FALSE(result.ok()); \ + EXPECT_THAT(result.error().message(), HasSubstr(msg)); \ + } while (false) + static size_t SizeOfVarInt(size_t value) { size_t size = 0; do { @@ -213,22 +230,22 @@ TEST_F(WasmModuleVerifyTest, DecodeEmpty) { TEST_F(WasmModuleVerifyTest, OneGlobal) { static const byte data[] = { - SECTION(Global, 6), // -- - 1, - kLocalI32, // local type - 0, // immutable - WASM_INIT_EXPR_I32V_1(13) // init + SECTION(Global, // -- + ENTRY_COUNT(1), // -- + kLocalI32, // local type + 0, // immutable + WASM_INIT_EXPR_I32V_1(13)) // init }; { // Should decode to exactly one global. ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(1u, result.val->globals.size()); - EXPECT_EQ(0u, result.val->functions.size()); - EXPECT_EQ(0u, result.val->data_segments.size()); + EXPECT_EQ(1u, result.value()->globals.size()); + EXPECT_EQ(0u, result.value()->functions.size()); + EXPECT_EQ(0u, result.value()->data_segments.size()); - const WasmGlobal* global = &result.val->globals.back(); + const WasmGlobal* global = &result.value()->globals.back(); EXPECT_EQ(kWasmI32, global->type); EXPECT_EQ(0u, global->offset); @@ -237,28 +254,28 @@ TEST_F(WasmModuleVerifyTest, OneGlobal) { EXPECT_EQ(13, global->init.val.i32_const); } - EXPECT_OFF_END_FAILURE(data, 1, sizeof(data)); + EXPECT_OFF_END_FAILURE(data, 1); } TEST_F(WasmModuleVerifyTest, AnyRefGlobal) { WASM_FEATURE_SCOPE(anyref); static const byte data[] = { - SECTION(Global, 5), // -- - 1, - kLocalAnyRef, // local type - 0, // immutable - WASM_INIT_EXPR_ANYREF // init + SECTION(Global, // -- + ENTRY_COUNT(1), // -- + kLocalAnyRef, // local type + 0, // immutable + WASM_INIT_EXPR_ANYREF) // init }; { // Should decode to exactly one global. ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(1u, result.val->globals.size()); - EXPECT_EQ(0u, result.val->functions.size()); - EXPECT_EQ(0u, result.val->data_segments.size()); + EXPECT_EQ(1u, result.value()->globals.size()); + EXPECT_EQ(0u, result.value()->functions.size()); + EXPECT_EQ(0u, result.value()->data_segments.size()); - const WasmGlobal* global = &result.val->globals.back(); + const WasmGlobal* global = &result.value()->globals.back(); EXPECT_EQ(kWasmAnyRef, global->type); EXPECT_FALSE(global->mutability); @@ -269,31 +286,29 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobal) { TEST_F(WasmModuleVerifyTest, AnyRefGlobalWithGlobalInit) { WASM_FEATURE_SCOPE(anyref); static const byte data[] = { - SECTION(Import, 8), // section header - 1, // number of imports - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 'f', // global name - kExternalGlobal, // import kind - kLocalAnyRef, // type - 0, // mutability - SECTION(Global, 6), // -- - 1, - kLocalAnyRef, // local type - 0, // immutable - WASM_INIT_EXPR_GLOBAL(0), + SECTION(Import, // -- + ENTRY_COUNT(1), // number of imports + ADD_COUNT('m'), // module name + ADD_COUNT('f'), // global name + kExternalGlobal, // import kind + kLocalAnyRef, // type + 0), // mutability + SECTION(Global, // -- + ENTRY_COUNT(1), + kLocalAnyRef, // local type + 0, // immutable + WASM_INIT_EXPR_GLOBAL(0)), }; { // Should decode to exactly one global. ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(2u, result.val->globals.size()); - EXPECT_EQ(0u, result.val->functions.size()); - EXPECT_EQ(0u, result.val->data_segments.size()); + EXPECT_EQ(2u, result.value()->globals.size()); + EXPECT_EQ(0u, result.value()->functions.size()); + EXPECT_EQ(0u, result.value()->data_segments.size()); - const WasmGlobal* global = &result.val->globals.back(); + const WasmGlobal* global = &result.value()->globals.back(); EXPECT_EQ(kWasmAnyRef, global->type); EXPECT_FALSE(global->mutability); @@ -303,76 +318,62 @@ TEST_F(WasmModuleVerifyTest, AnyRefGlobalWithGlobalInit) { TEST_F(WasmModuleVerifyTest, Global_invalid_type) { static const byte data[] = { - SECTION(Global, 6), // -- - 1, - 64, // invalid memory type - 1, // mutable - WASM_INIT_EXPR_I32V_1(33), // init + SECTION(Global, // -- + ENTRY_COUNT(1), // -- + 64, // invalid memory type + 1, // mutable + WASM_INIT_EXPR_I32V_1(33)), // init }; - ModuleResult result = DecodeModule(data, data + sizeof(data)); - EXPECT_FALSE(result.ok()); + EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, Global_invalid_type2) { static const byte data[] = { - SECTION(Global, 6), // -- - 1, - kLocalVoid, // invalid memory type - 1, // mutable - WASM_INIT_EXPR_I32V_1(33), // init + SECTION(Global, // -- + ENTRY_COUNT(1), // -- + kLocalVoid, // invalid memory type + 1, // mutable + WASM_INIT_EXPR_I32V_1(33)), // init }; - ModuleResult result = DecodeModule(data, data + sizeof(data)); - EXPECT_FALSE(result.ok()); + EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, ZeroGlobals) { - static const byte data[] = { - SECTION(Global, 1), // -- - 0, // declare 0 globals - }; + static const byte data[] = {SECTION(Global, ENTRY_COUNT(0))}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); } TEST_F(WasmModuleVerifyTest, ExportMutableGlobal) { - WASM_FEATURE_SCOPE(mut_global); { static const byte data[] = { - SECTION(Global, 6), // -- - 1, - kLocalI32, // local type - 0, // immutable - WASM_INIT_EXPR_I32V_1(13), // init - SECTION(Export, 8), // -- - 1, // Export count - 4, // name length - 'n', // -- - 'a', // -- - 'm', // -- - 'e', // -- - kExternalGlobal, // global - 0, // global index + SECTION(Global, // -- + ENTRY_COUNT(1), // -- + kLocalI32, // local type + 0, // immutable + WASM_INIT_EXPR_I32V_1(13)), // init + SECTION(Export, // -- + ENTRY_COUNT(1), // export count + ADD_COUNT('n', 'a', 'm', 'e'), // name + kExternalGlobal, // global + 0), // global index }; EXPECT_VERIFIES(data); } { static const byte data[] = { - SECTION(Global, 6), // -- - 1, // -- - kLocalI32, // local type - 1, // mutable - WASM_INIT_EXPR_I32V_1(13), // init - SECTION(Export, 8), // -- - 1, // Export count - 4, // name length - 'n', // -- - 'a', // -- - 'm', // -- - 'e', // -- - kExternalGlobal, // global - 0, // global index + SECTION(Global, // -- + ENTRY_COUNT(1), // -- + kLocalI32, // local type + 1, // mutable + WASM_INIT_EXPR_I32V_1(13)), // init + SECTION(Export, // -- + ENTRY_COUNT(1), // export count + ADD_COUNT('n', 'a', 'm', 'e'), // name + kExternalGlobal, // global + 0), // global index }; EXPECT_VERIFIES(data); } @@ -417,42 +418,41 @@ TEST_F(WasmModuleVerifyTest, NGlobals) { } TEST_F(WasmModuleVerifyTest, GlobalWithInvalidMemoryType) { - static const byte data[] = {SECTION(Global, 7), - 33, // memory type - 0, // exported - WASM_INIT_EXPR_I32V_1(1)}; + static const byte data[] = {SECTION(Global, // -- + ENTRY_COUNT(1), // -- + 33, // memory type + 0, // exported + WASM_INIT_EXPR_I32V_1(1))}; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, TwoGlobals) { - static const byte data[] = { - SECTION(Global, 21), - 2, - kLocalF32, // type - 0, // immutable - WASM_INIT_EXPR_F32(22.0), - kLocalF64, // type - 1, // mutable - WASM_INIT_EXPR_F64(23.0), - }; + static const byte data[] = {SECTION(Global, // -- + ENTRY_COUNT(2), // -- + kLocalF32, // type + 0, // immutable + WASM_INIT_EXPR_F32(22.0), // -- + kLocalF64, // type + 1, // mutable + WASM_INIT_EXPR_F64(23.0))}; // -- { // Should decode to exactly two globals. ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(2u, result.val->globals.size()); - EXPECT_EQ(0u, result.val->functions.size()); - EXPECT_EQ(0u, result.val->data_segments.size()); + EXPECT_EQ(2u, result.value()->globals.size()); + EXPECT_EQ(0u, result.value()->functions.size()); + EXPECT_EQ(0u, result.value()->data_segments.size()); - const WasmGlobal* g0 = &result.val->globals[0]; + const WasmGlobal* g0 = &result.value()->globals[0]; EXPECT_EQ(kWasmF32, g0->type); EXPECT_EQ(0u, g0->offset); EXPECT_FALSE(g0->mutability); EXPECT_EQ(WasmInitExpr::kF32Const, g0->init.kind); - const WasmGlobal* g1 = &result.val->globals[1]; + const WasmGlobal* g1 = &result.value()->globals[1]; EXPECT_EQ(kWasmF64, g1->type); EXPECT_EQ(8u, g1->offset); @@ -460,72 +460,103 @@ TEST_F(WasmModuleVerifyTest, TwoGlobals) { EXPECT_EQ(WasmInitExpr::kF64Const, g1->init.kind); } - EXPECT_OFF_END_FAILURE(data, 1, sizeof(data)); + EXPECT_OFF_END_FAILURE(data, 1); } TEST_F(WasmModuleVerifyTest, ZeroExceptions) { - static const byte data[] = { - SECTION_EXCEPTIONS(1), 0, - }; + static const byte data[] = {SECTION(Exception, ENTRY_COUNT(0))}; FAIL_IF_NO_EXPERIMENTAL_EH(data); WASM_FEATURE_SCOPE(eh); ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(0u, result.val->exceptions.size()); + EXPECT_EQ(0u, result.value()->exceptions.size()); } TEST_F(WasmModuleVerifyTest, OneI32Exception) { - static const byte data[] = {SECTION_EXCEPTIONS(3), 1, - // except[0] (i32) - 1, kLocalI32}; + static const byte data[] = { + SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_v_x(kLocalI32)), // sig#0 (i32) + SECTION(Exception, ENTRY_COUNT(1), + EXCEPTION_ENTRY(SIG_INDEX(0)))}; // except[0] (sig#0) FAIL_IF_NO_EXPERIMENTAL_EH(data); WASM_FEATURE_SCOPE(eh); ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(1u, result.val->exceptions.size()); + EXPECT_EQ(1u, result.value()->exceptions.size()); - const WasmException& e0 = result.val->exceptions.front(); + const WasmException& e0 = result.value()->exceptions.front(); EXPECT_EQ(1u, e0.sig->parameter_count()); EXPECT_EQ(kWasmI32, e0.sig->GetParam(0)); } TEST_F(WasmModuleVerifyTest, TwoExceptions) { - static const byte data[] = {SECTION_EXCEPTIONS(6), 2, - // except[0] (f32, i64) - 2, kLocalF32, kLocalI64, - // except[1] (i32) - 1, kLocalI32}; + static const byte data[] = { + SECTION(Type, ENTRY_COUNT(2), + SIG_ENTRY_v_x(kLocalI32), // sig#0 (i32) + SIG_ENTRY_v_xx(kLocalF32, kLocalI64)), // sig#1 (f32, i64) + SECTION(Exception, ENTRY_COUNT(2), + EXCEPTION_ENTRY(SIG_INDEX(1)), // except[0] (sig#1) + EXCEPTION_ENTRY(SIG_INDEX(0)))}; // except[1] (sig#0) FAIL_IF_NO_EXPERIMENTAL_EH(data); WASM_FEATURE_SCOPE(eh); ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(2u, result.val->exceptions.size()); - const WasmException& e0 = result.val->exceptions.front(); + EXPECT_EQ(2u, result.value()->exceptions.size()); + const WasmException& e0 = result.value()->exceptions.front(); EXPECT_EQ(2u, e0.sig->parameter_count()); EXPECT_EQ(kWasmF32, e0.sig->GetParam(0)); EXPECT_EQ(kWasmI64, e0.sig->GetParam(1)); - const WasmException& e1 = result.val->exceptions.back(); + const WasmException& e1 = result.value()->exceptions.back(); EXPECT_EQ(kWasmI32, e1.sig->GetParam(0)); } -TEST_F(WasmModuleVerifyTest, Exception_invalid_type) { - static const byte data[] = {SECTION_EXCEPTIONS(3), 1, - // except[0] (?) - 1, 64}; +TEST_F(WasmModuleVerifyTest, Exception_invalid_sig_index) { + static const byte data[] = { + SIGNATURES_SECTION_VOID_VOID, + SECTION(Exception, ENTRY_COUNT(1), + EXCEPTION_ENTRY( + SIG_INDEX(23)))}; // except[0] (sig#23 [out-of-bounds]) + FAIL_IF_NO_EXPERIMENTAL_EH(data); + + // Should fail decoding exception section. + WASM_FEATURE_SCOPE(eh); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "signature index 23 out of bounds"); +} + +TEST_F(WasmModuleVerifyTest, Exception_invalid_sig_return) { + static const byte data[] = { + SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_i_i), + SECTION(Exception, ENTRY_COUNT(1), + EXCEPTION_ENTRY( + SIG_INDEX(0)))}; // except[0] (sig#0 [invalid-return-type]) + FAIL_IF_NO_EXPERIMENTAL_EH(data); + + // Should fail decoding exception section. + WASM_FEATURE_SCOPE(eh); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "exception signature 0 has non-void return"); +} + +TEST_F(WasmModuleVerifyTest, Exception_invalid_attribute) { + static const byte data[] = { + SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_i_i), + SECTION(Exception, ENTRY_COUNT(1), 23, + SIG_INDEX(0))}; // except[0] (sig#0) [invalid-attribute] FAIL_IF_NO_EXPERIMENTAL_EH(data); // Should fail decoding exception section. WASM_FEATURE_SCOPE(eh); ModuleResult result = DecodeModule(data, data + sizeof(data)); - EXPECT_FALSE(result.ok()); + EXPECT_NOT_OK(result, "exception attribute 23 not supported"); } TEST_F(WasmModuleVerifyTest, ExceptionSectionCorrectPlacement) { - static const byte data[] = {SECTION(Import, 1), 0, SECTION_EXCEPTIONS(1), 0, - SECTION(Export, 1), 0}; + static const byte data[] = {SECTION(Import, ENTRY_COUNT(0)), + SECTION(Exception, ENTRY_COUNT(0)), + SECTION(Export, ENTRY_COUNT(0))}; FAIL_IF_NO_EXPERIMENTAL_EH(data); WASM_FEATURE_SCOPE(eh); @@ -534,57 +565,72 @@ TEST_F(WasmModuleVerifyTest, ExceptionSectionCorrectPlacement) { } TEST_F(WasmModuleVerifyTest, ExceptionSectionAfterExport) { - static const byte data[] = {SECTION(Export, 1), 0, SECTION_EXCEPTIONS(1), 0}; + static const byte data[] = {SECTION(Export, ENTRY_COUNT(0)), + SECTION(Exception, ENTRY_COUNT(0))}; FAIL_IF_NO_EXPERIMENTAL_EH(data); WASM_FEATURE_SCOPE(eh); ModuleResult result = DecodeModule(data, data + sizeof(data)); - EXPECT_FALSE(result.ok()); + EXPECT_NOT_OK(result, + "The Exception section must appear before the Export section"); } -TEST_F(WasmModuleVerifyTest, ExceptionSectionBeforeImport) { - static const byte data[] = {SECTION_EXCEPTIONS(1), 0, SECTION(Import, 1), 0}; +TEST_F(WasmModuleVerifyTest, ExceptionSectionBeforeGlobal) { + static const byte data[] = {SECTION(Exception, ENTRY_COUNT(0)), + SECTION(Global, ENTRY_COUNT(0))}; FAIL_IF_NO_EXPERIMENTAL_EH(data); WASM_FEATURE_SCOPE(eh); ModuleResult result = DecodeModule(data, data + sizeof(data)); - EXPECT_FALSE(result.ok()); + EXPECT_NOT_OK(result, "unexpected section: Global"); +} + +TEST_F(WasmModuleVerifyTest, ExceptionSectionAfterMemoryBeforeGlobal) { + STATIC_ASSERT(kMemorySectionCode + 1 == kGlobalSectionCode); + static const byte data[] = {SECTION(Memory, ENTRY_COUNT(0)), + SECTION(Exception, ENTRY_COUNT(0)), + SECTION(Global, ENTRY_COUNT(0))}; + FAIL_IF_NO_EXPERIMENTAL_EH(data); + + WASM_FEATURE_SCOPE(eh); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "unexpected section: Global"); } TEST_F(WasmModuleVerifyTest, ExceptionImport) { - static const byte data[] = {SECTION(Import, 9), // section header - 1, // number of imports - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(2), // -- - 'e', 'x', // exception name - kExternalException, // import kind - // except[0] (i32) - 1, kLocalI32}; + static const byte data[] = { + SIGNATURES_SECTION_VOID_VOID, + SECTION(Import, // section header + ENTRY_COUNT(1), // number of imports + ADD_COUNT('m'), // module name + ADD_COUNT('e', 'x'), // exception name + kExternalException, // import kind + EXCEPTION_ENTRY(SIG_INDEX(0)))}; // except[0] (sig#0) FAIL_IF_NO_EXPERIMENTAL_EH(data); WASM_FEATURE_SCOPE(eh); ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(1u, result.val->exceptions.size()); - EXPECT_EQ(1u, result.val->import_table.size()); + EXPECT_EQ(1u, result.value()->exceptions.size()); + EXPECT_EQ(1u, result.value()->import_table.size()); } TEST_F(WasmModuleVerifyTest, ExceptionExport) { - static const byte data[] = {SECTION_EXCEPTIONS(3), 1, - // except[0] (i32) - 1, kLocalI32, SECTION(Export, 4), - 1, // exports - NO_NAME, // -- - kExternalException, // -- - EXCEPTION_INDEX(0)}; + static const byte data[] = { + SIGNATURES_SECTION_VOID_VOID, + SECTION(Exception, ENTRY_COUNT(1), + EXCEPTION_ENTRY(SIG_INDEX(0))), // except[0] (sig#0) + SECTION(Export, ENTRY_COUNT(1), // -- + NO_NAME, // -- + kExternalException, // -- + EXCEPTION_INDEX(0))}; FAIL_IF_NO_EXPERIMENTAL_EH(data); WASM_FEATURE_SCOPE(eh); ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(1u, result.val->exceptions.size()); - EXPECT_EQ(1u, result.val->export_table.size()); + EXPECT_EQ(1u, result.value()->exceptions.size()); + EXPECT_EQ(1u, result.value()->export_table.size()); } TEST_F(WasmModuleVerifyTest, OneSignature) { @@ -594,74 +640,61 @@ TEST_F(WasmModuleVerifyTest, OneSignature) { } { - static const byte data[] = {SECTION(Type, 1 + SIZEOF_SIG_ENTRY_x_x), 1, - SIG_ENTRY_i_i}; + static const byte data[] = {SECTION(Type, ENTRY_COUNT(1), SIG_ENTRY_i_i)}; EXPECT_VERIFIES(data); } } TEST_F(WasmModuleVerifyTest, MultipleSignatures) { static const byte data[] = { - SECTION(Type, 1 + SIZEOF_SIG_ENTRY_v_v + SIZEOF_SIG_ENTRY_x_x + - SIZEOF_SIG_ENTRY_x_xx), // -- - 3, // -- - SIG_ENTRY_v_v, // void -> void - SIG_ENTRY_x_x(kLocalI32, kLocalF32), // f32 -> i32 - SIG_ENTRY_x_xx(kLocalI32, kLocalF64, kLocalF64), // f64,f64 -> i32 + SECTION( + Type, // -- + ENTRY_COUNT(3), // -- + SIG_ENTRY_v_v, // void -> void + SIG_ENTRY_x_x(kLocalI32, kLocalF32), // f32 -> i32 + SIG_ENTRY_x_xx(kLocalI32, kLocalF64, kLocalF64)), // f64,f64 -> i32 }; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(3u, result.val->signatures.size()); - if (result.val->signatures.size() == 3) { - EXPECT_EQ(0u, result.val->signatures[0]->return_count()); - EXPECT_EQ(1u, result.val->signatures[1]->return_count()); - EXPECT_EQ(1u, result.val->signatures[2]->return_count()); - - EXPECT_EQ(0u, result.val->signatures[0]->parameter_count()); - EXPECT_EQ(1u, result.val->signatures[1]->parameter_count()); - EXPECT_EQ(2u, result.val->signatures[2]->parameter_count()); + EXPECT_EQ(3u, result.value()->signatures.size()); + if (result.value()->signatures.size() == 3) { + EXPECT_EQ(0u, result.value()->signatures[0]->return_count()); + EXPECT_EQ(1u, result.value()->signatures[1]->return_count()); + EXPECT_EQ(1u, result.value()->signatures[2]->return_count()); + + EXPECT_EQ(0u, result.value()->signatures[0]->parameter_count()); + EXPECT_EQ(1u, result.value()->signatures[1]->parameter_count()); + EXPECT_EQ(2u, result.value()->signatures[2]->parameter_count()); } - EXPECT_OFF_END_FAILURE(data, 1, sizeof(data)); + EXPECT_OFF_END_FAILURE(data, 1); } TEST_F(WasmModuleVerifyTest, DataSegmentWithImmutableImportedGlobal) { // Import 2 globals so that we can initialize data with a global index != 0. const byte data[] = { - SECTION(Import, 15), // section header - 2, // number of imports - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 'f', // global name - kExternalGlobal, // import kind - kLocalI32, // type - 0, // mutability - NAME_LENGTH(1), // -- - 'n', // module name - NAME_LENGTH(1), // -- - 'g', // global name - kExternalGlobal, // import kind - kLocalI32, // type - 0, // mutability - SECTION(Memory, 4), - ENTRY_COUNT(1), - kHasMaximumFlag, - 28, - 28, - SECTION(Data, 9), - ENTRY_COUNT(1), - LINEAR_MEMORY_INDEX_0, - WASM_INIT_EXPR_GLOBAL(1), // dest addr - U32V_1(3), // source size - 'a', - 'b', - 'c' // data bytes + SECTION(Import, // section header + ENTRY_COUNT(2), // number of imports + ADD_COUNT('m'), // module name + ADD_COUNT('f'), // global name + kExternalGlobal, // import kind + kLocalI32, // type + 0, // mutability + ADD_COUNT('n'), // module name + ADD_COUNT('g'), // global name + kExternalGlobal, // import kind + kLocalI32, // type + 0), // mutability + SECTION(Memory, ENTRY_COUNT(1), kHasMaximumFlag, 28, 28), + SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, + WASM_INIT_EXPR_GLOBAL(1), // dest addr + U32V_1(3), // source size + 'a', 'b', 'c') // data bytes }; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - WasmInitExpr expr = result.val->data_segments.back().dest_addr; + WasmInitExpr expr = result.value()->data_segments.back().dest_addr; EXPECT_EQ(WasmInitExpr::kGlobalIndex, expr.kind); EXPECT_EQ(1u, expr.val.global_index); } @@ -669,52 +702,33 @@ TEST_F(WasmModuleVerifyTest, DataSegmentWithImmutableImportedGlobal) { TEST_F(WasmModuleVerifyTest, DataSegmentWithMutableImportedGlobal) { // Only an immutable imported global can be used as an init_expr. const byte data[] = { - SECTION(Import, 8), // section header - 1, // number of imports - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 'f', // global name - kExternalGlobal, // import kind - kLocalI32, // type - 1, // mutability - SECTION(Memory, 4), - ENTRY_COUNT(1), - kHasMaximumFlag, - 28, - 28, - SECTION(Data, 9), - ENTRY_COUNT(1), - LINEAR_MEMORY_INDEX_0, - WASM_INIT_EXPR_GLOBAL(0), // dest addr - U32V_1(3), // source size - 'a', - 'b', - 'c' // data bytes + SECTION(Import, // section header + ENTRY_COUNT(1), // number of imports + ADD_COUNT('m'), // module name + ADD_COUNT('f'), // global name + kExternalGlobal, // import kind + kLocalI32, // type + 1), // mutability + SECTION(Memory, ENTRY_COUNT(1), kHasMaximumFlag, 28, 28), + SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, + WASM_INIT_EXPR_GLOBAL(0), // dest addr + U32V_1(3), // source size + 'a', 'b', 'c') // data bytes }; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, DataSegmentWithImmutableGlobal) { // Only an immutable imported global can be used as an init_expr. const byte data[] = { - SECTION(Memory, 4), - ENTRY_COUNT(1), - kHasMaximumFlag, - 28, - 28, - SECTION(Global, 8), // -- - 1, - kLocalI32, // local type - 0, // immutable - WASM_INIT_EXPR_I32V_3(0x9BBAA), // init - SECTION(Data, 9), - ENTRY_COUNT(1), - LINEAR_MEMORY_INDEX_0, - WASM_INIT_EXPR_GLOBAL(0), // dest addr - U32V_1(3), // source size - 'a', - 'b', - 'c' // data bytes + SECTION(Memory, ENTRY_COUNT(1), kHasMaximumFlag, 28, 28), + SECTION(Global, ENTRY_COUNT(1), + kLocalI32, // local type + 0, // immutable + WASM_INIT_EXPR_I32V_3(0x9BBAA)), // init + SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, + WASM_INIT_EXPR_GLOBAL(0), // dest addr + U32V_1(3), // source size + 'a', 'b', 'c') // data bytes }; EXPECT_FAILURE(data); } @@ -722,30 +736,22 @@ TEST_F(WasmModuleVerifyTest, DataSegmentWithImmutableGlobal) { TEST_F(WasmModuleVerifyTest, OneDataSegment) { const byte kDataSegmentSourceOffset = 24; const byte data[] = { - SECTION(Memory, 4), - ENTRY_COUNT(1), - kHasMaximumFlag, - 28, - 28, - SECTION(Data, 11), - ENTRY_COUNT(1), - LINEAR_MEMORY_INDEX_0, - WASM_INIT_EXPR_I32V_3(0x9BBAA), // dest addr - U32V_1(3), // source size - 'a', - 'b', - 'c' // data bytes + SECTION(Memory, ENTRY_COUNT(1), kHasMaximumFlag, 28, 28), + SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, + WASM_INIT_EXPR_I32V_3(0x9BBAA), // dest addr + U32V_1(3), // source size + 'a', 'b', 'c') // data bytes }; { EXPECT_VERIFIES(data); ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(0u, result.val->globals.size()); - EXPECT_EQ(0u, result.val->functions.size()); - EXPECT_EQ(1u, result.val->data_segments.size()); + EXPECT_EQ(0u, result.value()->globals.size()); + EXPECT_EQ(0u, result.value()->functions.size()); + EXPECT_EQ(1u, result.value()->data_segments.size()); - const WasmDataSegment* segment = &result.val->data_segments.back(); + const WasmDataSegment* segment = &result.value()->data_segments.back(); EXPECT_EQ(WasmInitExpr::kI32Const, segment->dest_addr.kind); EXPECT_EQ(0x9BBAA, segment->dest_addr.val.i32_const); @@ -753,7 +759,7 @@ TEST_F(WasmModuleVerifyTest, OneDataSegment) { EXPECT_EQ(3u, segment->source.length()); } - EXPECT_OFF_END_FAILURE(data, 14, sizeof(data)); + EXPECT_OFF_END_FAILURE(data, 14); } TEST_F(WasmModuleVerifyTest, TwoDataSegments) { @@ -761,44 +767,28 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) { const byte kDataSegment1SourceOffset = kDataSegment0SourceOffset + 11; const byte data[] = { - SECTION(Memory, 4), - ENTRY_COUNT(1), - kHasMaximumFlag, - 28, - 28, - SECTION(Data, 29), - ENTRY_COUNT(2), // segment count - LINEAR_MEMORY_INDEX_0, - WASM_INIT_EXPR_I32V_3(0x7FFEE), // #0: dest addr - U32V_1(4), // source size - 1, - 2, - 3, - 4, // data bytes - LINEAR_MEMORY_INDEX_0, - WASM_INIT_EXPR_I32V_3(0x6DDCC), // #1: dest addr - U32V_1(10), // source size - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10 // data bytes + SECTION(Memory, ENTRY_COUNT(1), kHasMaximumFlag, 28, 28), + SECTION(Data, + ENTRY_COUNT(2), // segment count + LINEAR_MEMORY_INDEX_0, + WASM_INIT_EXPR_I32V_3(0x7FFEE), // #0: dest addr + U32V_1(4), // source size + 1, 2, 3, 4, // data bytes + LINEAR_MEMORY_INDEX_0, + WASM_INIT_EXPR_I32V_3(0x6DDCC), // #1: dest addr + U32V_1(10), // source size + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // data bytes }; { ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(0u, result.val->globals.size()); - EXPECT_EQ(0u, result.val->functions.size()); - EXPECT_EQ(2u, result.val->data_segments.size()); + EXPECT_EQ(0u, result.value()->globals.size()); + EXPECT_EQ(0u, result.value()->functions.size()); + EXPECT_EQ(2u, result.value()->data_segments.size()); - const WasmDataSegment* s0 = &result.val->data_segments[0]; - const WasmDataSegment* s1 = &result.val->data_segments[1]; + const WasmDataSegment* s0 = &result.value()->data_segments[0]; + const WasmDataSegment* s1 = &result.value()->data_segments[1]; EXPECT_EQ(WasmInitExpr::kI32Const, s0->dest_addr.kind); EXPECT_EQ(0x7FFEE, s0->dest_addr.val.i32_const); @@ -811,19 +801,15 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) { EXPECT_EQ(10u, s1->source.length()); } - EXPECT_OFF_END_FAILURE(data, 14, sizeof(data)); + EXPECT_OFF_END_FAILURE(data, 14); } TEST_F(WasmModuleVerifyTest, DataWithoutMemory) { const byte data[] = { - SECTION(Data, 11), - ENTRY_COUNT(1), - LINEAR_MEMORY_INDEX_0, - WASM_INIT_EXPR_I32V_3(0x9BBAA), // dest addr - U32V_1(3), // source size - 'a', - 'b', - 'c' // data bytes + SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, + WASM_INIT_EXPR_I32V_3(0x9BBAA), // dest addr + U32V_1(3), // source size + 'a', 'b', 'c') // data bytes }; EXPECT_FAILURE(data); } @@ -831,33 +817,23 @@ TEST_F(WasmModuleVerifyTest, DataWithoutMemory) { TEST_F(WasmModuleVerifyTest, MaxMaximumMemorySize) { { const byte data[] = { - SECTION(Memory, 6), ENTRY_COUNT(1), kHasMaximumFlag, 0, U32V_3(65536), - }; + SECTION(Memory, ENTRY_COUNT(1), kHasMaximumFlag, 0, U32V_3(65536))}; EXPECT_VERIFIES(data); } { const byte data[] = { - SECTION(Memory, 6), ENTRY_COUNT(1), kHasMaximumFlag, 0, U32V_3(65537), - }; + SECTION(Memory, ENTRY_COUNT(1), kHasMaximumFlag, 0, U32V_3(65537))}; EXPECT_FAILURE(data); } } TEST_F(WasmModuleVerifyTest, DataSegment_wrong_init_type) { const byte data[] = { - SECTION(Memory, 4), - ENTRY_COUNT(1), - kHasMaximumFlag, - 28, - 28, - SECTION(Data, 11), - ENTRY_COUNT(1), - LINEAR_MEMORY_INDEX_0, - WASM_INIT_EXPR_F64(9.9), // dest addr - U32V_1(3), // source size - 'a', - 'b', - 'c' // data bytes + SECTION(Memory, ENTRY_COUNT(1), kHasMaximumFlag, 28, 28), + SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, + WASM_INIT_EXPR_F64(9.9), // dest addr + U32V_1(3), // source size + 'a', 'b', 'c') // data bytes }; EXPECT_FAILURE(data); @@ -865,13 +841,13 @@ TEST_F(WasmModuleVerifyTest, DataSegment_wrong_init_type) { TEST_F(WasmModuleVerifyTest, DataSegmentEndOverflow) { const byte data[] = { - SECTION(Memory, 4), // memory section - ENTRY_COUNT(1), kHasMaximumFlag, 28, 28, - SECTION(Data, 10), // data section - ENTRY_COUNT(1), // one entry - LINEAR_MEMORY_INDEX_0, // mem index - WASM_INIT_EXPR_I32V_1(0), // offset - U32V_5(0xFFFFFFFF) // size + SECTION(Memory, // memory section + ENTRY_COUNT(1), kHasMaximumFlag, 28, 28), + SECTION(Data, // data section + ENTRY_COUNT(1), // one entry + LINEAR_MEMORY_INDEX_0, // mem index + WASM_INIT_EXPR_I32V_1(0), // offset + U32V_5(0xFFFFFFFF)) // size }; EXPECT_FAILURE(data); @@ -882,28 +858,28 @@ TEST_F(WasmModuleVerifyTest, OneIndirectFunction) { // sig#0 --------------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // funcs --------------------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // table declaration --------------------------------------------------- - SECTION(Table, 4), ENTRY_COUNT(1), kLocalAnyFunc, 0, 1}; + SECTION(Table, ENTRY_COUNT(1), kLocalAnyFunc, 0, 1), + // code ---------------------------------------------------------------- + ONE_EMPTY_BODY}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); if (result.ok()) { - EXPECT_EQ(1u, result.val->signatures.size()); - EXPECT_EQ(1u, result.val->functions.size()); - EXPECT_EQ(1u, result.val->tables.size()); - EXPECT_EQ(1u, result.val->tables[0].initial_size); + EXPECT_EQ(1u, result.value()->signatures.size()); + EXPECT_EQ(1u, result.value()->functions.size()); + EXPECT_EQ(1u, result.value()->tables.size()); + EXPECT_EQ(1u, result.value()->tables[0].initial_size); } } TEST_F(WasmModuleVerifyTest, ElementSectionWithInternalTable) { static const byte data[] = { // table --------------------------------------------------------------- - SECTION(Table, 4), ENTRY_COUNT(1), kLocalAnyFunc, 0, 1, + SECTION(Table, ENTRY_COUNT(1), kLocalAnyFunc, 0, 1), // elements ------------------------------------------------------------ - SECTION(Element, 1), - 0 // entry count - }; + SECTION(Element, ENTRY_COUNT(0))}; EXPECT_VERIFIES(data); } @@ -911,19 +887,15 @@ TEST_F(WasmModuleVerifyTest, ElementSectionWithInternalTable) { TEST_F(WasmModuleVerifyTest, ElementSectionWithImportedTable) { static const byte data[] = { // imports ------------------------------------------------------------- - SECTION(Import, 9), ENTRY_COUNT(1), - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 't', // table name - kExternalTable, // import kind - kLocalAnyFunc, // elem_type - 0, // no maximum field - 1, // initial size + SECTION(Import, ENTRY_COUNT(1), + ADD_COUNT('m'), // module name + ADD_COUNT('t'), // table name + kExternalTable, // import kind + kLocalAnyFunc, // elem_type + 0, // no maximum field + 1), // initial size // elements ------------------------------------------------------------ - SECTION(Element, 1), - 0 // entry count - }; + SECTION(Element, ENTRY_COUNT(0))}; EXPECT_VERIFIES(data); } @@ -932,11 +904,11 @@ TEST_F(WasmModuleVerifyTest, ElementSectionWithoutTable) { // Test that an element section without a table causes a validation error. static const byte data[] = { // elements ------------------------------------------------------------ - SECTION(Element, 4), - 1, // entry count - 0, // table index - 0, // offset - 0 // number of elements + SECTION(Element, + ENTRY_COUNT(1), // entry count + 0, // table index + 0, // offset + 0) // number of elements }; EXPECT_FAILURE(data); @@ -948,15 +920,15 @@ TEST_F(WasmModuleVerifyTest, Regression_735887) { // sig#0 --------------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // funcs --------------------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // table declaration --------------------------------------------------- - SECTION(Table, 4), ENTRY_COUNT(1), kLocalAnyFunc, 0, 1, + SECTION(Table, ENTRY_COUNT(1), kLocalAnyFunc, 0, 1), // elements ------------------------------------------------------------ - SECTION(Element, 7), - 1, // entry count - TABLE_INDEX(0), WASM_INIT_EXPR_I32V_1(0), - 1, // elements count - 0x9A // invalid I32V as function index + SECTION(Element, + ENTRY_COUNT(1), // entry count + TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0), + 1, // elements count + 0x9A) // invalid I32V as function index }; EXPECT_FAILURE(data); @@ -967,88 +939,82 @@ TEST_F(WasmModuleVerifyTest, OneIndirectFunction_one_entry) { // sig#0 --------------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // funcs --------------------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // table declaration --------------------------------------------------- - SECTION(Table, 4), ENTRY_COUNT(1), kLocalAnyFunc, 0, 1, + SECTION(Table, ENTRY_COUNT(1), kLocalAnyFunc, 0, 1), // elements ------------------------------------------------------------ - SECTION(Element, 7), - 1, // entry count - TABLE_INDEX(0), WASM_INIT_EXPR_I32V_1(0), - 1, // elements count - FUNC_INDEX(0)}; + SECTION(Element, + ENTRY_COUNT(1), // entry count + TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0), + 1, // elements count + FUNC_INDEX(0)), + // code ---------------------------------------------------------------- + ONE_EMPTY_BODY}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - if (result.ok()) { - EXPECT_EQ(1u, result.val->signatures.size()); - EXPECT_EQ(1u, result.val->functions.size()); - EXPECT_EQ(1u, result.val->tables.size()); - EXPECT_EQ(1u, result.val->tables[0].initial_size); - } + EXPECT_EQ(1u, result.value()->signatures.size()); + EXPECT_EQ(1u, result.value()->functions.size()); + EXPECT_EQ(1u, result.value()->tables.size()); + EXPECT_EQ(1u, result.value()->tables[0].initial_size); } TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) { static const byte data[] = { // sig#0 ------------------------------------------------------- - SECTION(Type, 1 + SIZEOF_SIG_ENTRY_v_v + SIZEOF_SIG_ENTRY_v_x), - 2, // -- - SIG_ENTRY_v_v, // void -> void - SIG_ENTRY_v_x(kLocalI32), // void -> i32 + SECTION(Type, + ENTRY_COUNT(2), // -- + SIG_ENTRY_v_v, // void -> void + SIG_ENTRY_v_x(kLocalI32)), // void -> i32 // funcs ------------------------------------------------------ - FOUR_EMPTY_FUNCTIONS, + FOUR_EMPTY_FUNCTIONS(SIG_INDEX(0)), // table declaration ------------------------------------------- - SECTION(Table, 4), ENTRY_COUNT(1), kLocalAnyFunc, 0, 8, + SECTION(Table, ENTRY_COUNT(1), kLocalAnyFunc, 0, 8), // table elements ---------------------------------------------- - SECTION(Element, 14), - 1, // entry count - TABLE_INDEX(0), WASM_INIT_EXPR_I32V_1(0), - 8, // elements count - FUNC_INDEX(0), // -- - FUNC_INDEX(1), // -- - FUNC_INDEX(2), // -- - FUNC_INDEX(3), // -- - FUNC_INDEX(0), // -- - FUNC_INDEX(1), // -- - FUNC_INDEX(2), // -- - FUNC_INDEX(3), // -- + SECTION(Element, + ENTRY_COUNT(1), // entry count + TABLE_INDEX0, WASM_INIT_EXPR_I32V_1(0), + ADD_COUNT(FUNC_INDEX(0), FUNC_INDEX(1), FUNC_INDEX(2), + FUNC_INDEX(3), FUNC_INDEX(0), FUNC_INDEX(1), + FUNC_INDEX(2), FUNC_INDEX(3))), FOUR_EMPTY_BODIES}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - if (result.ok()) { - EXPECT_EQ(2u, result.val->signatures.size()); - EXPECT_EQ(4u, result.val->functions.size()); - EXPECT_EQ(1u, result.val->tables.size()); - EXPECT_EQ(8u, result.val->tables[0].initial_size); - } + EXPECT_EQ(2u, result.value()->signatures.size()); + EXPECT_EQ(4u, result.value()->functions.size()); + EXPECT_EQ(1u, result.value()->tables.size()); + EXPECT_EQ(8u, result.value()->tables[0].initial_size); } TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTables) { // Test that if we have multiple tables, in the element section we can target // and initialize all tables. WASM_FEATURE_SCOPE(anyref); + WASM_FEATURE_SCOPE(bulk_memory); static const byte data[] = { // sig#0 --------------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // funcs --------------------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // table declaration --------------------------------------------------- - SECTION(Table, 7), ENTRY_COUNT(2), // section header - kLocalAnyFunc, 0, 5, // table 0 - kLocalAnyFunc, 0, 9, // table 1 + SECTION(Table, ENTRY_COUNT(2), // section header + kLocalAnyFunc, 0, 5, // table 0 + kLocalAnyFunc, 0, 9), // table 1 // elements ------------------------------------------------------------ - SECTION(Element, 14), - 2, // entry count - TABLE_INDEX(0), // element for table 0 - WASM_INIT_EXPR_I32V_1(0), // index - 1, // elements count - FUNC_INDEX(0), // function - TABLE_INDEX(1), // element for table 1 - WASM_INIT_EXPR_I32V_1(7), // index - 2, // elements count - FUNC_INDEX(0), // entry 0 - FUNC_INDEX(0), // entry 1 - }; + SECTION(Element, + ENTRY_COUNT(2), // entry count + TABLE_INDEX0, // element for table 0 + WASM_INIT_EXPR_I32V_1(0), // index + 1, // elements count + FUNC_INDEX(0), // function + TABLE_INDEX(1), // element for table 1 + WASM_INIT_EXPR_I32V_1(7), // index + 2, // elements count + FUNC_INDEX(0), // entry 0 + FUNC_INDEX(0)), // entry 1 + // code ---------------------------------------------------------------- + ONE_EMPTY_BODY}; EXPECT_VERIFIES(data); } @@ -1057,55 +1023,53 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTables) { // Test that if we have multiple tables, both imported and module-defined, in // the element section we can target and initialize all tables. WASM_FEATURE_SCOPE(anyref); + WASM_FEATURE_SCOPE(bulk_memory); static const byte data[] = { // sig#0 --------------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // imports ------------------------------------------------------------- - SECTION(Import, 17), ENTRY_COUNT(2), - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 't', // table name - kExternalTable, // import kind - kLocalAnyFunc, // elem_type - 0, // no maximum field - 5, // initial size - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 's', // table name - kExternalTable, // import kind - kLocalAnyFunc, // elem_type - 0, // no maximum field - 10, // initial size + SECTION(Import, ENTRY_COUNT(2), + ADD_COUNT('m'), // module name + ADD_COUNT('t'), // table name + kExternalTable, // import kind + kLocalAnyFunc, // elem_type + 0, // no maximum field + 5, // initial size + ADD_COUNT('m'), // module name + ADD_COUNT('s'), // table name + kExternalTable, // import kind + kLocalAnyFunc, // elem_type + 0, // no maximum field + 10), // initial size // funcs --------------------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // table declaration --------------------------------------------------- - SECTION(Table, 7), ENTRY_COUNT(2), // section header - kLocalAnyFunc, 0, 15, // table 0 - kLocalAnyFunc, 0, 19, // table 1 + SECTION(Table, ENTRY_COUNT(2), // section header + kLocalAnyFunc, 0, 15, // table 0 + kLocalAnyFunc, 0, 19), // table 1 // elements ------------------------------------------------------------ - SECTION(Element, 27), - 4, // entry count - TABLE_INDEX(0), // element for table 0 - WASM_INIT_EXPR_I32V_1(0), // index - 1, // elements count - FUNC_INDEX(0), // function - TABLE_INDEX(1), // element for table 1 - WASM_INIT_EXPR_I32V_1(7), // index - 2, // elements count - FUNC_INDEX(0), // entry 0 - FUNC_INDEX(0), // entry 1 - TABLE_INDEX(2), // element for table 2 - WASM_INIT_EXPR_I32V_1(12), // index - 1, // elements count - FUNC_INDEX(0), // function - TABLE_INDEX(3), // element for table 1 - WASM_INIT_EXPR_I32V_1(17), // index - 2, // elements count - FUNC_INDEX(0), // entry 0 - FUNC_INDEX(0), // entry 1 - }; + SECTION(Element, + 4, // entry count + TABLE_INDEX0, // element for table 0 + WASM_INIT_EXPR_I32V_1(0), // index + 1, // elements count + FUNC_INDEX(0), // function + TABLE_INDEX(1), // element for table 1 + WASM_INIT_EXPR_I32V_1(7), // index + 2, // elements count + FUNC_INDEX(0), // entry 0 + FUNC_INDEX(0), // entry 1 + TABLE_INDEX(2), // element for table 2 + WASM_INIT_EXPR_I32V_1(12), // index + 1, // elements count + FUNC_INDEX(0), // function + TABLE_INDEX(3), // element for table 1 + WASM_INIT_EXPR_I32V_1(17), // index + 2, // elements count + FUNC_INDEX(0), // entry 0 + FUNC_INDEX(0)), // entry 1 + // code ---------------------------------------------------------------- + ONE_EMPTY_BODY}; EXPECT_VERIFIES(data); } @@ -1114,32 +1078,34 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMultipleTablesArbitraryOrder) { // Test that the order in which tables are targeted in the element secion // can be arbitrary. WASM_FEATURE_SCOPE(anyref); + WASM_FEATURE_SCOPE(bulk_memory); static const byte data[] = { // sig#0 --------------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // funcs --------------------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // table declaration --------------------------------------------------- - SECTION(Table, 7), ENTRY_COUNT(2), // section header - kLocalAnyFunc, 0, 5, // table 0 - kLocalAnyFunc, 0, 9, // table 1 + SECTION(Table, ENTRY_COUNT(2), // section header + kLocalAnyFunc, 0, 5, // table 0 + kLocalAnyFunc, 0, 9), // table 1 // elements ------------------------------------------------------------ - SECTION(Element, 20), - 3, // entry count - TABLE_INDEX(0), // element for table 1 - WASM_INIT_EXPR_I32V_1(0), // index - 1, // elements count - FUNC_INDEX(0), // function - TABLE_INDEX(1), // element for table 0 - WASM_INIT_EXPR_I32V_1(7), // index - 2, // elements count - FUNC_INDEX(0), // entry 0 - FUNC_INDEX(0), // entry 1 - TABLE_INDEX(0), // element for table 1 - WASM_INIT_EXPR_I32V_1(3), // index - 1, // elements count - FUNC_INDEX(0), // function - }; + SECTION(Element, + ENTRY_COUNT(3), // entry count + TABLE_INDEX0, // element for table 1 + WASM_INIT_EXPR_I32V_1(0), // index + 1, // elements count + FUNC_INDEX(0), // function + TABLE_INDEX(1), // element for table 0 + WASM_INIT_EXPR_I32V_1(7), // index + 2, // elements count + FUNC_INDEX(0), // entry 0 + FUNC_INDEX(0), // entry 1 + TABLE_INDEX0, // element for table 1 + WASM_INIT_EXPR_I32V_1(3), // index + 1, // elements count + FUNC_INDEX(0)), // function + // code ---------------------------------------------------------------- + ONE_EMPTY_BODY}; EXPECT_VERIFIES(data); } @@ -1148,55 +1114,53 @@ TEST_F(WasmModuleVerifyTest, ElementSectionMixedTablesArbitraryOrder) { // Test that the order in which tables are targeted in the element secion can // be arbitrary. In this test, tables can be both imported and module-defined. WASM_FEATURE_SCOPE(anyref); + WASM_FEATURE_SCOPE(bulk_memory); static const byte data[] = { // sig#0 --------------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // imports ------------------------------------------------------------- - SECTION(Import, 17), ENTRY_COUNT(2), - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 't', // table name - kExternalTable, // import kind - kLocalAnyFunc, // elem_type - 0, // no maximum field - 5, // initial size - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 's', // table name - kExternalTable, // import kind - kLocalAnyFunc, // elem_type - 0, // no maximum field - 10, // initial size + SECTION(Import, ENTRY_COUNT(2), + ADD_COUNT('m'), // module name + ADD_COUNT('t'), // table name + kExternalTable, // import kind + kLocalAnyFunc, // elem_type + 0, // no maximum field + 5, // initial size + ADD_COUNT('m'), // module name + ADD_COUNT('s'), // table name + kExternalTable, // import kind + kLocalAnyFunc, // elem_type + 0, // no maximum field + 10), // initial size // funcs --------------------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // table declaration --------------------------------------------------- - SECTION(Table, 7), ENTRY_COUNT(2), // section header - kLocalAnyFunc, 0, 15, // table 0 - kLocalAnyFunc, 0, 19, // table 1 + SECTION(Table, ENTRY_COUNT(2), // section header + kLocalAnyFunc, 0, 15, // table 0 + kLocalAnyFunc, 0, 19), // table 1 // elements ------------------------------------------------------------ - SECTION(Element, 27), - 4, // entry count - TABLE_INDEX(2), // element for table 0 - WASM_INIT_EXPR_I32V_1(10), // index - 1, // elements count - FUNC_INDEX(0), // function - TABLE_INDEX(3), // element for table 1 - WASM_INIT_EXPR_I32V_1(17), // index - 2, // elements count - FUNC_INDEX(0), // entry 0 - FUNC_INDEX(0), // entry 1 - TABLE_INDEX(0), // element for table 2 - WASM_INIT_EXPR_I32V_1(2), // index - 1, // elements count - FUNC_INDEX(0), // function - TABLE_INDEX(1), // element for table 1 - WASM_INIT_EXPR_I32V_1(7), // index - 2, // elements count - FUNC_INDEX(0), // entry 0 - FUNC_INDEX(0), // entry 1 - }; + SECTION(Element, + 4, // entry count + TABLE_INDEX(2), // element for table 0 + WASM_INIT_EXPR_I32V_1(10), // index + 1, // elements count + FUNC_INDEX(0), // function + TABLE_INDEX(3), // element for table 1 + WASM_INIT_EXPR_I32V_1(17), // index + 2, // elements count + FUNC_INDEX(0), // entry 0 + FUNC_INDEX(0), // entry 1 + TABLE_INDEX0, // element for table 2 + WASM_INIT_EXPR_I32V_1(2), // index + 1, // elements count + FUNC_INDEX(0), // function + TABLE_INDEX(1), // element for table 1 + WASM_INIT_EXPR_I32V_1(7), // index + 2, // elements count + FUNC_INDEX(0), // entry 0 + FUNC_INDEX(0)), // entry 1 + // code ---------------------------------------------------------------- + ONE_EMPTY_BODY}; EXPECT_VERIFIES(data); } @@ -1205,27 +1169,28 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefTable) { // Test that tables of type 'AnyRef' cannot be initialized by the element // section. WASM_FEATURE_SCOPE(anyref); + WASM_FEATURE_SCOPE(bulk_memory); static const byte data[] = { // sig#0 --------------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // funcs --------------------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // table declaration --------------------------------------------------- - SECTION(Table, 7), ENTRY_COUNT(2), // section header - kLocalAnyRef, 0, 5, // table 0 - kLocalAnyFunc, 0, 9, // table 1 + SECTION(Table, ENTRY_COUNT(2), // section header + kLocalAnyRef, 0, 5, // table 0 + kLocalAnyFunc, 0, 9), // table 1 // elements ------------------------------------------------------------ - SECTION(Element, 14), - 2, // entry count - TABLE_INDEX(0), // element for table 0 - WASM_INIT_EXPR_I32V_1(0), // index - 1, // elements count - FUNC_INDEX(0), // function - TABLE_INDEX(1), // element for table 1 - WASM_INIT_EXPR_I32V_1(7), // index - 2, // elements count - FUNC_INDEX(0), // entry 0 - FUNC_INDEX(0), // entry 1 + SECTION(Element, + ENTRY_COUNT(2), // entry count + TABLE_INDEX0, // element for table 0 + WASM_INIT_EXPR_I32V_1(0), // index + 1, // elements count + FUNC_INDEX(0), // function + TABLE_INDEX(1), // element for table 1 + WASM_INIT_EXPR_I32V_1(7), // index + 2, // elements count + FUNC_INDEX(0), // entry 0 + FUNC_INDEX(0)), // entry 1 }; EXPECT_FAILURE(data); @@ -1235,45 +1200,42 @@ TEST_F(WasmModuleVerifyTest, ElementSectionDontInitAnyRefImportedTable) { // Test that imported tables of type AnyRef cannot be initialized in the // elements section. WASM_FEATURE_SCOPE(anyref); + WASM_FEATURE_SCOPE(bulk_memory); static const byte data[] = { // sig#0 --------------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // imports ------------------------------------------------------------- - SECTION(Import, 17), ENTRY_COUNT(2), - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 't', // table name - kExternalTable, // import kind - kLocalAnyFunc, // elem_type - 0, // no maximum field - 5, // initial size - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 's', // table name - kExternalTable, // import kind - kLocalAnyRef, // elem_type - 0, // no maximum field - 10, // initial size + SECTION(Import, ENTRY_COUNT(2), + ADD_COUNT('m'), // module name + ADD_COUNT('t'), // table name + kExternalTable, // import kind + kLocalAnyFunc, // elem_type + 0, // no maximum field + 5, // initial size + ADD_COUNT('m'), // module name + ADD_COUNT('s'), // table name + kExternalTable, // import kind + kLocalAnyRef, // elem_type + 0, // no maximum field + 10), // initial size // funcs --------------------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // table declaration --------------------------------------------------- - SECTION(Table, 7), ENTRY_COUNT(2), // section header - kLocalAnyFunc, 0, 15, // table 0 - kLocalAnyFunc, 0, 19, // table 1 + SECTION(Table, ENTRY_COUNT(2), // section header + kLocalAnyFunc, 0, 15, // table 0 + kLocalAnyFunc, 0, 19), // table 1 // elements ------------------------------------------------------------ - SECTION(Element, 14), - 4, // entry count - TABLE_INDEX(0), // element for table 0 - WASM_INIT_EXPR_I32V_1(10), // index - 1, // elements count - FUNC_INDEX(0), // function - TABLE_INDEX(1), // element for table 1 - WASM_INIT_EXPR_I32V_1(17), // index - 2, // elements count - FUNC_INDEX(0), // entry 0 - FUNC_INDEX(0), // entry 1 + SECTION(Element, + ENTRY_COUNT(4), // entry count + TABLE_INDEX0, // element for table 0 + WASM_INIT_EXPR_I32V_1(10), // index + 1, // elements count + FUNC_INDEX(0), // function + TABLE_INDEX(1), // element for table 1 + WASM_INIT_EXPR_I32V_1(17), // index + 2, // elements count + FUNC_INDEX(0), // entry 0 + FUNC_INDEX(0)), // entry 1 }; EXPECT_FAILURE(data); @@ -1284,8 +1246,7 @@ TEST_F(WasmModuleVerifyTest, IndirectFunctionNoFunctions) { // sig#0 ------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // indirect table ---------------------------------------------- - SECTION(Table, 4), ENTRY_COUNT(1), 1, 0, 0, - }; + SECTION(Table, ENTRY_COUNT(1), 1, 0, 0)}; EXPECT_FAILURE(data); } @@ -1295,24 +1256,23 @@ TEST_F(WasmModuleVerifyTest, IndirectFunctionInvalidIndex) { // sig#0 ------------------------------------------------------- SIGNATURES_SECTION_VOID_VOID, // functions --------------------------------------------------- - ONE_EMPTY_FUNCTION, + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // indirect table ---------------------------------------------- - SECTION(Table, 4), ENTRY_COUNT(1), 1, 1, 0, - }; + SECTION(Table, ENTRY_COUNT(1), 1, 1, 0)}; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, MultipleTablesWithoutFlag) { static const byte data[] = { - SECTION(Table, 7), // table section - ENTRY_COUNT(2), // 2 tables - kLocalAnyFunc, // table 1: type - 0, // table 1: no maximum - 10, // table 1: minimum size - kLocalAnyFunc, // table 2: type - 0, // table 2: no maximum - 10, // table 2: minimum size + SECTION(Table, // table section + ENTRY_COUNT(2), // 2 tables + kLocalAnyFunc, // table 1: type + 0, // table 1: no maximum + 10, // table 1: minimum size + kLocalAnyFunc, // table 2: type + 0, // table 2: no maximum + 10), // table 2: minimum size }; EXPECT_FAILURE(data); } @@ -1320,26 +1280,26 @@ TEST_F(WasmModuleVerifyTest, MultipleTablesWithoutFlag) { TEST_F(WasmModuleVerifyTest, MultipleTablesWithFlag) { WASM_FEATURE_SCOPE(anyref); static const byte data[] = { - SECTION(Table, 7), // table section - ENTRY_COUNT(2), // 2 tables - kLocalAnyFunc, // table 1: type - 0, // table 1: no maximum - 10, // table 1: minimum size - kLocalAnyRef, // table 2: type - 0, // table 2: no maximum - 11, // table 2: minimum size + SECTION(Table, // table section + ENTRY_COUNT(2), // 2 tables + kLocalAnyFunc, // table 1: type + 0, // table 1: no maximum + 10, // table 1: minimum size + kLocalAnyRef, // table 2: type + 0, // table 2: no maximum + 11), // table 2: minimum size }; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(2u, result.val->tables.size()); + EXPECT_EQ(2u, result.value()->tables.size()); - EXPECT_EQ(10u, result.val->tables[0].initial_size); - EXPECT_EQ(kWasmAnyFunc, result.val->tables[0].type); + EXPECT_EQ(10u, result.value()->tables[0].initial_size); + EXPECT_EQ(kWasmAnyFunc, result.value()->tables[0].type); - EXPECT_EQ(11u, result.val->tables[1].initial_size); - EXPECT_EQ(kWasmAnyRef, result.val->tables[1].type); + EXPECT_EQ(11u, result.value()->tables[1].initial_size); + EXPECT_EQ(kWasmAnyRef, result.value()->tables[1].type); } class WasmSignatureDecodeTest : public TestWithZone { @@ -1490,8 +1450,9 @@ TEST_F(WasmSignatureDecodeTest, Fail_anyref_without_flag) { WASM_FEATURE_SCOPE_VAL(anyref, false); byte ref_types[] = {kLocalAnyFunc, kLocalAnyRef}; for (byte invalid_type : ref_types) { - for (size_t i = 0; i < SIZEOF_SIG_ENTRY_x_xx; i++) { + for (size_t i = 0;; i++) { byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalI32)}; + if (i >= arraysize(data)) break; data[i] = invalid_type; FunctionSig* sig = DecodeSig(data, data + sizeof(data)); EXPECT_EQ(nullptr, sig); @@ -1501,8 +1462,9 @@ TEST_F(WasmSignatureDecodeTest, Fail_anyref_without_flag) { TEST_F(WasmSignatureDecodeTest, Fail_invalid_type) { byte kInvalidType = 76; - for (size_t i = 0; i < SIZEOF_SIG_ENTRY_x_xx; i++) { + for (size_t i = 0;; i++) { byte data[] = {SIG_ENTRY_x_xx(kLocalI32, kLocalI32, kLocalI32)}; + if (i >= arraysize(data)) break; data[i] = kInvalidType; FunctionSig* sig = DecodeSig(data, data + sizeof(data)); EXPECT_EQ(nullptr, sig); @@ -1529,15 +1491,12 @@ TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type2) { class WasmFunctionVerifyTest : public TestWithIsolateAndZone { public: - WasmFeatures enabled_features_; - WasmModule module; - Vector<const byte> bytes; - FunctionResult DecodeWasmFunction(const ModuleWireBytes& wire_bytes, const WasmModule* module, const byte* function_start, const byte* function_end) { - return DecodeWasmFunctionForTesting(enabled_features_, zone(), wire_bytes, + WasmFeatures enabled_features; + return DecodeWasmFunctionForTesting(enabled_features, zone(), wire_bytes, module, function_start, function_end, isolate()->counters()); } @@ -1558,16 +1517,16 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) { kExprEnd // body }; - FunctionResult result = - DecodeWasmFunction(bytes, &module, data, data + sizeof(data)); + WasmModule module; + FunctionResult result = DecodeWasmFunction(ModuleWireBytes({}), &module, data, + data + sizeof(data)); EXPECT_OK(result); - if (result.val && result.ok()) { - WasmFunction* function = result.val.get(); + if (result.value() && result.ok()) { + WasmFunction* function = result.value().get(); EXPECT_EQ(0u, function->sig->parameter_count()); EXPECT_EQ(0u, function->sig->return_count()); - EXPECT_EQ(static_cast<uint32_t>(SIZEOF_SIG_ENTRY_v_v), - function->code.offset()); + EXPECT_EQ(COUNT_ARGS(SIG_ENTRY_v_v), function->code.offset()); EXPECT_EQ(sizeof(data), function->code.end_offset()); // TODO(titzer): verify encoding of local declarations } @@ -1658,102 +1617,94 @@ TEST_F(WasmModuleVerifyTest, UnknownSectionSkipped) { static const byte data[] = { UNKNOWN_SECTION(1), 0, // one byte section - SECTION(Global, 6), - 1, - kLocalI32, // memory type - 0, // exported - WASM_INIT_EXPR_I32V_1(33), // init + SECTION(Global, ENTRY_COUNT(1), + kLocalI32, // memory type + 0, // exported + WASM_INIT_EXPR_I32V_1(33)), // init }; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(1u, result.val->globals.size()); - EXPECT_EQ(0u, result.val->functions.size()); - EXPECT_EQ(0u, result.val->data_segments.size()); + EXPECT_EQ(1u, result.value()->globals.size()); + EXPECT_EQ(0u, result.value()->functions.size()); + EXPECT_EQ(0u, result.value()->data_segments.size()); - const WasmGlobal* global = &result.val->globals.back(); + const WasmGlobal* global = &result.value()->globals.back(); EXPECT_EQ(kWasmI32, global->type); EXPECT_EQ(0u, global->offset); } TEST_F(WasmModuleVerifyTest, ImportTable_empty) { - static const byte data[] = {SECTION(Type, 1), 0, SECTION(Import, 1), 0}; + static const byte data[] = {SECTION(Type, ENTRY_COUNT(0)), + SECTION(Import, ENTRY_COUNT(0))}; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, ImportTable_nosigs1) { - static const byte data[] = {SECTION(Import, 1), 0}; + static const byte data[] = {SECTION(Import, ENTRY_COUNT(0))}; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, ImportTable_mutable_global) { - WASM_FEATURE_SCOPE(mut_global); { static const byte data[] = { - SECTION(Import, 8), // section header - 1, // number of imports - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 'f', // global name - kExternalGlobal, // import kind - kLocalI32, // type - 0, // mutability + SECTION(Import, // section header + ENTRY_COUNT(1), // number of imports + ADD_COUNT('m'), // module name + ADD_COUNT('f'), // global name + kExternalGlobal, // import kind + kLocalI32, // type + 0), // mutability }; EXPECT_VERIFIES(data); } { static const byte data[] = { - SECTION(Import, 8), // section header - 1, // sig table - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 'f', // global name - kExternalGlobal, // import kind - kLocalI32, // type - 1, // mutability + SECTION(Import, // section header + ENTRY_COUNT(1), // sig table + ADD_COUNT('m'), // module name + ADD_COUNT('f'), // global name + kExternalGlobal, // import kind + kLocalI32, // type + 1), // mutability }; EXPECT_VERIFIES(data); } } TEST_F(WasmModuleVerifyTest, ImportTable_mutability_malformed) { - WASM_FEATURE_SCOPE(mut_global); - static const byte data[] = { - SECTION(Import, 8), - 1, // -- - NAME_LENGTH(1), // -- - 'm', // module name - NAME_LENGTH(1), // -- - 'g', // global name - kExternalGlobal, // import kind - kLocalI32, // type - 2, // invalid mutability + static const byte data[] = { + SECTION(Import, + ENTRY_COUNT(1), // -- + ADD_COUNT('m'), // module name + ADD_COUNT('g'), // global name + kExternalGlobal, // import kind + kLocalI32, // type + 2), // invalid mutability }; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, ImportTable_nosigs2) { static const byte data[] = { - SECTION(Import, 6), 1, // sig table - NAME_LENGTH(1), 'm', // module name - NAME_LENGTH(1), 'f', // function name - kExternalFunction, // import kind - IMPORT_SIG_INDEX(0), // sig index + SECTION(Import, ENTRY_COUNT(1), // sig table + ADD_COUNT('m'), // module name + ADD_COUNT('f'), // function name + kExternalFunction, // import kind + SIG_INDEX(0)), // sig index }; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, ImportTable_invalid_sig) { static const byte data[] = { - SECTION(Type, 1), 0, // -- - SECTION(Import, 6), 1, // -- - NAME_LENGTH(1), 'm', // module name - NAME_LENGTH(1), 'f', // function name - kExternalFunction, // import kind - IMPORT_SIG_INDEX(0), // sig index + SECTION(Type, ENTRY_COUNT(0)), // -- + SECTION(Import, ENTRY_COUNT(1), // -- + ADD_COUNT('m'), // module name + ADD_COUNT('f'), // function name + kExternalFunction, // import kind + SIG_INDEX(0)), // sig index }; EXPECT_FAILURE(data); } @@ -1762,14 +1713,12 @@ TEST_F(WasmModuleVerifyTest, ImportTable_one_sig) { static const byte data[] = { // signatures SIGNATURES_SECTION_VOID_VOID, - SECTION(Import, 7), - 1, // -- - NAME_LENGTH(1), - 'm', // module name - NAME_LENGTH(1), - 'f', // function name - kExternalFunction, // import kind - IMPORT_SIG_INDEX(0), // sig index + SECTION(Import, + ENTRY_COUNT(1), // -- + ADD_COUNT('m'), // module name + ADD_COUNT('f'), // function name + kExternalFunction, // import kind + SIG_INDEX(0)), // sig index }; EXPECT_VERIFIES(data); } @@ -1778,13 +1727,13 @@ TEST_F(WasmModuleVerifyTest, ImportTable_invalid_module) { static const byte data[] = { // signatures SIGNATURES_SECTION_VOID_VOID, // -- - SECTION(Import, 7), // -- - 1, // -- - NO_NAME, // module name - NAME_LENGTH(1), // -- - 'f', // function name - kExternalFunction, // import kind - IMPORT_SIG_INDEX(0), // sig index + SECTION(Import, // -- + ENTRY_COUNT(1), // -- + NO_NAME, // module name + ADD_COUNT('f'), // function name + kExternalFunction, // import kind + SIG_INDEX(0), // sig index + 0), // auxiliary data }; EXPECT_FAILURE(data); } @@ -1793,143 +1742,129 @@ TEST_F(WasmModuleVerifyTest, ImportTable_off_end) { static const byte data[] = { // signatures SIGNATURES_SECTION_VOID_VOID, - SECTION(Import, 6), - 1, - NAME_LENGTH(1), - 'm', // module name - NAME_LENGTH(1), - 'f', // function name - kExternalFunction, // import kind - IMPORT_SIG_INDEX(0), // sig index + SECTION(Import, ENTRY_COUNT(1), + ADD_COUNT('m'), // module name + ADD_COUNT('f'), // function name + kExternalFunction), // import kind + SIG_INDEX(0), // sig index (outside import section!) }; - EXPECT_OFF_END_FAILURE(data, 16, sizeof(data)); + EXPECT_OFF_END_FAILURE(data, arraysize(data) - 3); } TEST_F(WasmModuleVerifyTest, ExportTable_empty1) { static const byte data[] = { // signatures SIGNATURES_SECTION_VOID_VOID, // -- - ONE_EMPTY_FUNCTION, SECTION(Export, 1), // -- - 0, // -- + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), + SECTION(Export, ENTRY_COUNT(0)), // -- ONE_EMPTY_BODY}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(1u, result.val->functions.size()); - EXPECT_EQ(0u, result.val->export_table.size()); + EXPECT_EQ(1u, result.value()->functions.size()); + EXPECT_EQ(0u, result.value()->export_table.size()); } TEST_F(WasmModuleVerifyTest, ExportTable_empty2) { - static const byte data[] = { - SECTION(Type, 1), 0, SECTION(Export, 1), 0 // -- - }; + static const byte data[] = {SECTION(Type, ENTRY_COUNT(0)), + SECTION(Export, ENTRY_COUNT(0))}; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, ExportTable_NoFunctions2) { - static const byte data[] = {SECTION(Export, 1), 0}; + static const byte data[] = {SECTION(Export, ENTRY_COUNT(0))}; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, ExportTableOne) { - static const byte data[] = {// signatures - SIGNATURES_SECTION_VOID_VOID, - ONE_EMPTY_FUNCTION, - SECTION(Export, 4), - 1, // exports - NO_NAME, // -- - kExternalFunction, // -- - FUNC_INDEX(0), // -- - ONE_EMPTY_BODY}; + static const byte data[] = { + // signatures + SIGNATURES_SECTION_VOID_VOID, ONE_EMPTY_FUNCTION(SIG_INDEX(0)), + SECTION(Export, + ENTRY_COUNT(1), // exports + NO_NAME, // -- + kExternalFunction, // -- + FUNC_INDEX(0)), // -- + ONE_EMPTY_BODY}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(1u, result.val->functions.size()); - EXPECT_EQ(1u, result.val->export_table.size()); + EXPECT_EQ(1u, result.value()->functions.size()); + EXPECT_EQ(1u, result.value()->export_table.size()); } TEST_F(WasmModuleVerifyTest, ExportNameWithInvalidStringLength) { - static const byte data[] = {// signatures - SIGNATURES_SECTION_VOID_VOID, - ONE_EMPTY_FUNCTION, - SECTION(Export, 12), - 1, // exports - NAME_LENGTH(84), // invalid string length - 'e', // -- - kExternalFunction, // -- - FUNC_INDEX(0)}; + static const byte data[] = { + // signatures + SIGNATURES_SECTION_VOID_VOID, ONE_EMPTY_FUNCTION(SIG_INDEX(0)), + SECTION(Export, + ENTRY_COUNT(1), // exports + U32V_1(84), // invalid string length + 'e', // -- + kExternalFunction, // -- + FUNC_INDEX(0), // -- + 0, 0, 0) // auxiliary data + }; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, ExportTableTwo) { - static const byte data[] = {// signatures - SIGNATURES_SECTION_VOID_VOID, - ONE_EMPTY_FUNCTION, - SECTION(Export, 14), - 2, // exports - NAME_LENGTH(4), - 'n', - 'a', - 'm', - 'e', // -- - kExternalFunction, - FUNC_INDEX(0), // -- - NAME_LENGTH(3), - 'n', - 'o', - 'm', // -- - kExternalFunction, // -- - FUNC_INDEX(0), // -- - ONE_EMPTY_BODY}; + static const byte data[] = { + // signatures + SIGNATURES_SECTION_VOID_VOID, ONE_EMPTY_FUNCTION(SIG_INDEX(0)), + SECTION(Export, + ENTRY_COUNT(2), // exports + ADD_COUNT('n', 'a', 'm', 'e'), // -- + kExternalFunction, // -- + FUNC_INDEX(0), // -- + ADD_COUNT('n', 'o', 'm'), // -- + kExternalFunction, // -- + FUNC_INDEX(0)), // -- + ONE_EMPTY_BODY}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(1u, result.val->functions.size()); - EXPECT_EQ(2u, result.val->export_table.size()); + EXPECT_EQ(1u, result.value()->functions.size()); + EXPECT_EQ(2u, result.value()->export_table.size()); } TEST_F(WasmModuleVerifyTest, ExportTableThree) { - static const byte data[] = {// signatures - SIGNATURES_SECTION_VOID_VOID, - THREE_EMPTY_FUNCTIONS, - SECTION(Export, 13), - 3, // exports - NAME_LENGTH(1), - 'a', // -- - kExternalFunction, - FUNC_INDEX(0), // -- - NAME_LENGTH(1), - 'b', // -- - kExternalFunction, - FUNC_INDEX(1), // -- - NAME_LENGTH(1), - 'c', // -- - kExternalFunction, - FUNC_INDEX(2), // -- - THREE_EMPTY_BODIES}; + static const byte data[] = { + // signatures + SIGNATURES_SECTION_VOID_VOID, THREE_EMPTY_FUNCTIONS(SIG_INDEX(0)), + SECTION(Export, + ENTRY_COUNT(3), // exports + ADD_COUNT('a'), // -- + kExternalFunction, + FUNC_INDEX(0), // -- + ADD_COUNT('b'), // -- + kExternalFunction, + FUNC_INDEX(1), // -- + ADD_COUNT('c'), // -- + kExternalFunction, + FUNC_INDEX(2)), // -- + THREE_EMPTY_BODIES}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_OK(result); - EXPECT_EQ(3u, result.val->functions.size()); - EXPECT_EQ(3u, result.val->export_table.size()); + EXPECT_EQ(3u, result.value()->functions.size()); + EXPECT_EQ(3u, result.value()->export_table.size()); } TEST_F(WasmModuleVerifyTest, ExportTableThreeOne) { for (int i = 0; i < 6; i++) { - const byte data[] = {// signatures - SIGNATURES_SECTION_VOID_VOID, - THREE_EMPTY_FUNCTIONS, - SECTION(Export, 6), - 1, // exports - NAME_LENGTH(2), - 'e', - 'x', // -- - kExternalFunction, - FUNC_INDEX(i), // -- - THREE_EMPTY_BODIES}; + const byte data[] = { + // signatures + SIGNATURES_SECTION_VOID_VOID, THREE_EMPTY_FUNCTIONS(SIG_INDEX(0)), + SECTION(Export, + ENTRY_COUNT(1), // exports + ADD_COUNT('e', 'x'), // -- + kExternalFunction, + FUNC_INDEX(i)), // -- + THREE_EMPTY_BODIES}; if (i < 3) { EXPECT_VERIFIES(data); @@ -1942,43 +1877,23 @@ TEST_F(WasmModuleVerifyTest, ExportTableThreeOne) { TEST_F(WasmModuleVerifyTest, ExportTableOne_off_end) { static const byte data[] = { // signatures - SIGNATURES_SECTION_VOID_VOID, - ONE_EMPTY_FUNCTION, - SECTION(Export, 1 + 6), - 1, // exports - NO_NAME, // -- - kExternalFunction, - FUNC_INDEX(0), // -- + SIGNATURES_SECTION_VOID_VOID, ONE_EMPTY_FUNCTION(SIG_INDEX(0)), + SECTION(Export, + ENTRY_COUNT(1), // exports + NO_NAME, // -- + kExternalFunction, + FUNC_INDEX(0), // -- + 0, 0, 0) // auxiliary data }; - for (size_t length = 33; length < sizeof(data); length++) { - ModuleResult result = DecodeModule(data, data + length); - EXPECT_FALSE(result.ok()); - } -} - -TEST_F(WasmModuleVerifyTest, FunctionSignatures_empty) { - static const byte data[] = { - SECTION(Type, 1), 0, // -- - SECTION(Function, 1), 0 // -- - }; // -- - EXPECT_VERIFIES(data); -} - -TEST_F(WasmModuleVerifyTest, FunctionSignatures_one) { - static const byte data[] = { - SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- - FUNCTION_SIGNATURES_SECTION(1, 0) // -- - }; - EXPECT_VERIFIES(data); + EXPECT_OFF_END_FAILURE(data, arraysize(data) - 3); } TEST_F(WasmModuleVerifyTest, Regression_648070) { static const byte data[] = { - SECTION(Type, 1), 0, // -- - SECTION(Function, 5), // -- - U32V_5(3500228624) // function count = 3500228624 - }; // -- + SECTION(Type, ENTRY_COUNT(0)), // -- + SECTION(Function, U32V_5(3500228624)) // function count = 3500228624 + }; // -- EXPECT_FAILURE(data); } @@ -1987,10 +1902,10 @@ TEST_F(WasmModuleVerifyTest, Regression_738097) { static const byte data[] = { SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- FUNCTION_SIGNATURES_SECTION(1, 0), // -- - SECTION(Code, 1 + 5 + 1), // -- - 1, // -- - U32V_5(0xFFFFFFFF), // function size, - 0 // No real body + SECTION(Code, // -- + ENTRY_COUNT(1), // -- + U32V_5(0xFFFFFFFF), // function size, + 0) // No real body }; EXPECT_FAILURE(data); } @@ -2031,40 +1946,36 @@ TEST_F(WasmModuleVerifyTest, FunctionBodies_empty) { TEST_F(WasmModuleVerifyTest, FunctionBodies_one_empty) { static const byte data[] = { - SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- - FUNCTION_SIGNATURES_SECTION(1, 0), // -- - SECTION(Code, 1 + SIZEOF_EMPTY_BODY), 1, EMPTY_BODY // -- + SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- + FUNCTION_SIGNATURES_SECTION(1, 0), // -- + ONE_EMPTY_BODY // -- }; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, FunctionBodies_one_nop) { static const byte data[] = { - SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- - FUNCTION_SIGNATURES_SECTION(1, 0), // -- - SECTION(Code, 1 + SIZEOF_NOP_BODY), 1, NOP_BODY // -- + SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- + FUNCTION_SIGNATURES_SECTION(1, 0), // -- + SECTION(Code, ENTRY_COUNT(1), NOP_BODY) // -- }; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch1) { static const byte data[] = { - SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- - FUNCTION_SIGNATURES_SECTION(2, 0, 0), // -- - SECTION(Code, 1 + SIZEOF_EMPTY_BODY), 1, // -- - EMPTY_BODY // -- + SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- + FUNCTION_SIGNATURES_SECTION(2, 0, 0), // -- + ONE_EMPTY_BODY // -- }; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch2) { static const byte data[] = { - SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- - FUNCTION_SIGNATURES_SECTION(1, 0), // -- - SECTION(Code, 1 + 2 * SIZEOF_NOP_BODY), // -- - ENTRY_COUNT(2), // -- - NOP_BODY, // -- - NOP_BODY // -- + SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- + FUNCTION_SIGNATURES_SECTION(1, 0), // -- + SECTION(Code, ENTRY_COUNT(2), NOP_BODY, NOP_BODY) // -- }; EXPECT_FAILURE(data); } @@ -2077,54 +1988,71 @@ TEST_F(WasmModuleVerifyTest, Names_empty) { } TEST_F(WasmModuleVerifyTest, Names_one_empty) { + // TODO(wasm): This test does not test anything (corrupt name section does not + // fail validation). static const byte data[] = { - SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- - FUNCTION_SIGNATURES_SECTION(1, 0), // -- - SECTION(Code, 1 + SIZEOF_EMPTY_BODY), - ENTRY_COUNT(1), - EMPTY_BODY, // -- - SECTION_NAMES(1 + 5), - ENTRY_COUNT(1), - FOO_STRING, - NO_LOCAL_NAMES // -- + SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- + FUNCTION_SIGNATURES_SECTION(1, 0), // -- + ONE_EMPTY_BODY, // -- + SECTION_NAMES(ENTRY_COUNT(1), FOO_STRING, NO_LOCAL_NAMES) // -- }; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, Names_two_empty) { + // TODO(wasm): This test does not test anything (corrupt name section does not + // fail validation). static const byte data[] = { - SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- - FUNCTION_SIGNATURES_SECTION(2, 0, 0), // -- - SECTION(Code, 1 + 2 * SIZEOF_EMPTY_BODY), // -- - ENTRY_COUNT(2), - EMPTY_BODY, - EMPTY_BODY, // -- - SECTION_NAMES(1 + 10), - ENTRY_COUNT(2), // -- - FOO_STRING, - NO_LOCAL_NAMES, // -- - FOO_STRING, - NO_LOCAL_NAMES, // -- + SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // -- + FUNCTION_SIGNATURES_SECTION(2, 0, 0), // -- + TWO_EMPTY_BODIES, // -- + SECTION_NAMES(ENTRY_COUNT(2), // -- + FOO_STRING, NO_LOCAL_NAMES, // -- + FOO_STRING, NO_LOCAL_NAMES), // -- }; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, Regression684855) { static const byte data[] = { - SECTION_NAMES(12), - 0xFB, // functions count - 0x27, // | - 0x00, // function name length - 0xFF, // local names count - 0xFF, // | - 0xFF, // | - 0xFF, // | - 0xFF, // | - 0xFF, // error: "varint too large" - 0xFF, // | - 0x00, // -- - 0x00 // -- + SECTION_NAMES(0xFB, // functions count + 0x27, // | + 0x00, // function name length + 0xFF, // local names count + 0xFF, // | + 0xFF, // | + 0xFF, // | + 0xFF, // | + 0xFF, // error: "varint too large" + 0xFF, // | + 0x00, // -- + 0x00) // -- + }; + EXPECT_VERIFIES(data); +} + +TEST_F(WasmModuleVerifyTest, FunctionSectionWithoutCodeSection) { + static const byte data[] = { + SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // Type section. + FUNCTION_SIGNATURES_SECTION(1, 0), // Function section. }; + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "function count is 1, but code section is absent"); +} + +TEST_F(WasmModuleVerifyTest, CodeSectionWithoutFunctionSection) { + static const byte data[] = {ONE_EMPTY_BODY}; + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "function body count 1 mismatch (0 expected)"); +} + +TEST_F(WasmModuleVerifyTest, EmptyFunctionSectionWithoutCodeSection) { + static const byte data[] = {SECTION(Function, ENTRY_COUNT(0))}; + EXPECT_VERIFIES(data); +} + +TEST_F(WasmModuleVerifyTest, EmptyCodeSectionWithoutFunctionSection) { + static const byte data[] = {SECTION(Code, ENTRY_COUNT(0))}; EXPECT_VERIFIES(data); } @@ -2199,15 +2127,15 @@ TEST_F(WasmInitExprDecodeTest, InitExpr_illegal) { TEST_F(WasmModuleVerifyTest, Multiple_Named_Sections) { static const byte data[] = { - SECTION(Unknown, 4), 1, 'X', 17, 18, // -- - SECTION(Unknown, 9), 3, 'f', 'o', 'o', 5, 6, 7, 8, 9, // -- - SECTION(Unknown, 8), 5, 'o', 't', 'h', 'e', 'r', 7, 8, // -- + SECTION(Unknown, ADD_COUNT('X'), 17, 18), // -- + SECTION(Unknown, ADD_COUNT('f', 'o', 'o'), 5, 6, 7, 8, 9), // -- + SECTION(Unknown, ADD_COUNT('o', 't', 'h', 'e', 'r'), 7, 8), // -- }; EXPECT_VERIFIES(data); } TEST_F(WasmModuleVerifyTest, Section_Name_No_UTF8) { - static const byte data[] = {SECTION(Unknown, 4), 1, 0xFF, 17, 18}; + static const byte data[] = {SECTION(Unknown, 1, 0xFF, 17, 18)}; EXPECT_FAILURE(data); } @@ -2237,11 +2165,11 @@ class WasmModuleCustomSectionTest : public TestWithIsolateAndZone { TEST_F(WasmModuleCustomSectionTest, ThreeUnknownSections) { static constexpr byte data[] = { - U32_LE(kWasmMagic), // -- - U32_LE(kWasmVersion), // -- - SECTION(Unknown, 4), 1, 'X', 17, 18, // -- - SECTION(Unknown, 9), 3, 'f', 'o', 'o', 5, 6, 7, 8, 9, // -- - SECTION(Unknown, 8), 5, 'o', 't', 'h', 'e', 'r', 7, 8, // -- + U32_LE(kWasmMagic), // -- + U32_LE(kWasmVersion), // -- + SECTION(Unknown, 1, 'X', 17, 18), // -- + SECTION(Unknown, 3, 'f', 'o', 'o', 5, 6, 7, 8, 9), // -- + SECTION(Unknown, 5, 'o', 't', 'h', 'e', 'r', 7, 8), // -- }; static const CustomSectionOffset expected[] = { @@ -2256,24 +2184,12 @@ TEST_F(WasmModuleCustomSectionTest, ThreeUnknownSections) { TEST_F(WasmModuleCustomSectionTest, TwoKnownTwoUnknownSections) { static const byte data[] = { - U32_LE(kWasmMagic), // -- - U32_LE(kWasmVersion), // -- - SIGNATURES_SECTION(2, SIG_ENTRY_v_v, SIG_ENTRY_v_v), // -- - SECTION(Unknown, 4), - 1, - 'X', - 17, - 18, // -- - ONE_EMPTY_FUNCTION, - SECTION(Unknown, 8), - 5, - 'o', - 't', - 'h', - 'e', - 'r', - 7, - 8, // -- + U32_LE(kWasmMagic), // -- + U32_LE(kWasmVersion), // -- + SIGNATURES_SECTION(2, SIG_ENTRY_v_v, SIG_ENTRY_v_v), // -- + SECTION(Unknown, ADD_COUNT('X'), 17, 18), // -- + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), // -- + SECTION(Unknown, ADD_COUNT('o', 't', 'h', 'e', 'r'), 7, 8), // -- }; static const CustomSectionOffset expected[] = { @@ -2285,79 +2201,162 @@ TEST_F(WasmModuleCustomSectionTest, TwoKnownTwoUnknownSections) { CheckSections(data, data + sizeof(data), expected, arraysize(expected)); } -#define SRC_MAP \ - 16, 's', 'o', 'u', 'r', 'c', 'e', 'M', 'a', 'p', 'p', 'i', 'n', 'g', 'U', \ - 'R', 'L' TEST_F(WasmModuleVerifyTest, SourceMappingURLSection) { -#define SRC 's', 'r', 'c', '/', 'x', 'y', 'z', '.', 'c' - static const byte data[] = {SECTION(Unknown, 27), SRC_MAP, 9, SRC}; + static const byte data[] = { + SECTION_SRC_MAP('s', 'r', 'c', '/', 'x', 'y', 'z', '.', 'c')}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_TRUE(result.ok()); - EXPECT_EQ(9u, result.val->source_map_url.size()); - const char src[] = {SRC}; - EXPECT_EQ( - 0, - strncmp(reinterpret_cast<const char*>(result.val->source_map_url.data()), - src, 9)); -#undef SRC + EXPECT_EQ("src/xyz.c", result.value()->source_map_url); } TEST_F(WasmModuleVerifyTest, BadSourceMappingURLSection) { -#define BAD_SRC 's', 'r', 'c', '/', 'x', 0xff, 'z', '.', 'c' - static const byte data[] = {SECTION(Unknown, 27), SRC_MAP, 9, BAD_SRC}; + static const byte data[] = { + SECTION_SRC_MAP('s', 'r', 'c', '/', 'x', 0xff, 'z', '.', 'c')}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_TRUE(result.ok()); - EXPECT_EQ(0u, result.val->source_map_url.size()); -#undef BAD_SRC + EXPECT_EQ(0u, result.value()->source_map_url.size()); } TEST_F(WasmModuleVerifyTest, MultipleSourceMappingURLSections) { -#define SRC 'a', 'b', 'c' - static const byte data[] = {SECTION(Unknown, 21), - SRC_MAP, - 3, - SRC, - SECTION(Unknown, 21), - SRC_MAP, - 3, - 'p', - 'q', - 'r'}; + static const byte data[] = {SECTION_SRC_MAP('a', 'b', 'c'), + SECTION_SRC_MAP('p', 'q', 'r')}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_TRUE(result.ok()); - EXPECT_EQ(3u, result.val->source_map_url.size()); - const char src[] = {SRC}; - EXPECT_EQ( - 0, - strncmp(reinterpret_cast<const char*>(result.val->source_map_url.data()), - src, 3)); -#undef SRC + EXPECT_EQ("abc", result.value()->source_map_url); } -#undef SRC_MAP TEST_F(WasmModuleVerifyTest, MultipleNameSections) { -#define NAME_SECTION 4, 'n', 'a', 'm', 'e' - static const byte data[] = {SECTION(Unknown, 11), - NAME_SECTION, - 0, - 4, - 3, - 'a', - 'b', - 'c', - SECTION(Unknown, 12), - NAME_SECTION, - 0, - 5, - 4, - 'p', - 'q', - 'r', - 's'}; + static const byte data[] = { + SECTION_NAMES(0, ADD_COUNT(ADD_COUNT('a', 'b', 'c'))), + SECTION_NAMES(0, ADD_COUNT(ADD_COUNT('p', 'q', 'r', 's')))}; ModuleResult result = DecodeModule(data, data + sizeof(data)); EXPECT_TRUE(result.ok()); - EXPECT_EQ(3u, result.val->name.length()); -#undef NAME_SECTION + EXPECT_EQ(3u, result.value()->name.length()); +} + +TEST_F(WasmModuleVerifyTest, PassiveDataSegment) { + static const byte data[] = { + // memory declaration ---------------------------------------------------- + SECTION(Memory, ENTRY_COUNT(1), 0, 1), + // data segments -------------------------------------------------------- + SECTION(Data, ENTRY_COUNT(1), PASSIVE, ADD_COUNT('h', 'i')), + }; + EXPECT_FAILURE(data); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(data); + EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5); +} + +TEST_F(WasmModuleVerifyTest, PassiveElementSegment) { + static const byte data[] = { + // sig#0 ----------------------------------------------------------------- + SIGNATURES_SECTION_VOID_VOID, + // funcs ----------------------------------------------------------------- + ONE_EMPTY_FUNCTION(SIG_INDEX(0)), + // table declaration ----------------------------------------------------- + SECTION(Table, ENTRY_COUNT(1), kLocalAnyFunc, 0, 1), + // element segments ----------------------------------------------------- + SECTION(Element, ENTRY_COUNT(1), PASSIVE, + ADD_COUNT(FUNC_INDEX(0), FUNC_INDEX(0))), + // code ------------------------------------------------------------------ + ONE_EMPTY_BODY}; + EXPECT_FAILURE(data); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(data); + EXPECT_OFF_END_FAILURE(data, arraysize(data) - 5); +} + +TEST_F(WasmModuleVerifyTest, DataCountSectionCorrectPlacement) { + static const byte data[] = {SECTION(Element, ENTRY_COUNT(0)), + SECTION(DataCount, ENTRY_COUNT(0)), + SECTION(Code, ENTRY_COUNT(0))}; + EXPECT_FAILURE(data); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(data); +} + +TEST_F(WasmModuleVerifyTest, DataCountSectionAfterCode) { + static const byte data[] = {SECTION(Code, ENTRY_COUNT(0)), + SECTION(DataCount, ENTRY_COUNT(0))}; + WASM_FEATURE_SCOPE(bulk_memory); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, + "The DataCount section must appear before the Code section"); +} + +TEST_F(WasmModuleVerifyTest, DataCountSectionBeforeElement) { + static const byte data[] = {SECTION(DataCount, ENTRY_COUNT(0)), + SECTION(Element, ENTRY_COUNT(0))}; + WASM_FEATURE_SCOPE(bulk_memory); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "unexpected section: Element"); +} + +TEST_F(WasmModuleVerifyTest, DataCountSectionAfterStartBeforeElement) { + STATIC_ASSERT(kStartSectionCode + 1 == kElementSectionCode); + static const byte data[] = { + // We need the start section for this test, but the start section must + // reference a valid function, which requires the type and function + // sections too. + SIGNATURES_SECTION(1, SIG_ENTRY_v_v), // Type section. + FUNCTION_SIGNATURES_SECTION(1, 0), // Function section. + + SECTION(Start, U32V_1(0)), // Start section. + SECTION(DataCount, ENTRY_COUNT(0)), // DataCount section. + SECTION(Element, ENTRY_COUNT(0)) // Element section. + }; + WASM_FEATURE_SCOPE(bulk_memory); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "unexpected section: Element"); +} + +TEST_F(WasmModuleVerifyTest, MultipleDataCountSections) { + static const byte data[] = {SECTION(DataCount, ENTRY_COUNT(0)), + SECTION(DataCount, ENTRY_COUNT(0))}; + WASM_FEATURE_SCOPE(bulk_memory); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "Multiple DataCount sections not allowed"); +} + +TEST_F(WasmModuleVerifyTest, DataCountSegmentCountMatch) { + static const byte data[] = { + SECTION(Memory, ENTRY_COUNT(1), 0, 1), // Memory section. + SECTION(DataCount, ENTRY_COUNT(1)), // DataCount section. + SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, // Data section. + WASM_INIT_EXPR_I32V_1(12), ADD_COUNT('h', 'i'))}; + + EXPECT_FAILURE(data); + WASM_FEATURE_SCOPE(bulk_memory); + EXPECT_VERIFIES(data); +} + +TEST_F(WasmModuleVerifyTest, DataCountSegmentCount_greater) { + static const byte data[] = { + SECTION(Memory, ENTRY_COUNT(1), 0, 1), // Memory section. + SECTION(DataCount, ENTRY_COUNT(3)), // DataCount section. + SECTION(Data, ENTRY_COUNT(0))}; // Data section. + WASM_FEATURE_SCOPE(bulk_memory); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "data segments count 0 mismatch (3 expected)"); +} + +TEST_F(WasmModuleVerifyTest, DataCountSegmentCount_less) { + static const byte data[] = { + SECTION(Memory, ENTRY_COUNT(1), 0, 1), // Memory section. + SECTION(DataCount, ENTRY_COUNT(0)), // DataCount section. + SECTION(Data, ENTRY_COUNT(1), LINEAR_MEMORY_INDEX_0, // Data section. + WASM_INIT_EXPR_I32V_1(12), ADD_COUNT('a', 'b', 'c'))}; + WASM_FEATURE_SCOPE(bulk_memory); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "data segments count 1 mismatch (0 expected)"); +} + +TEST_F(WasmModuleVerifyTest, DataCountSegmentCount_omitted) { + static const byte data[] = {SECTION(Memory, ENTRY_COUNT(1), 0, 1), + SECTION(DataCount, ENTRY_COUNT(1))}; + WASM_FEATURE_SCOPE(bulk_memory); + ModuleResult result = DecodeModule(data, data + sizeof(data)); + EXPECT_NOT_OK(result, "data segments count 0 mismatch (1 expected)"); } #undef WASM_FEATURE_SCOPE @@ -2374,13 +2373,13 @@ TEST_F(WasmModuleVerifyTest, MultipleNameSections) { #undef WASM_INIT_EXPR_F64 #undef WASM_INIT_EXPR_ANYREF #undef WASM_INIT_EXPR_GLOBAL -#undef SIZEOF_EMPTY_FUNCTION #undef EMPTY_BODY -#undef SIZEOF_EMPTY_BODY #undef NOP_BODY -#undef SIZEOF_NOP_BODY #undef SIG_ENTRY_i_i #undef UNKNOWN_SECTION +#undef COUNT_ARGS +#undef CHECK_LEB1 +#undef ADD_COUNT #undef SECTION #undef SIGNATURES_SECTION #undef FUNCTION_SIGNATURES_SECTION @@ -2390,8 +2389,8 @@ TEST_F(WasmModuleVerifyTest, MultipleNameSections) { #undef EMPTY_FUNCTION_SIGNATURES_SECTION #undef EMPTY_FUNCTION_BODIES_SECTION #undef SECTION_NAMES -#undef SECTION_EXCEPTIONS #undef EMPTY_NAMES_SECTION +#undef SECTION_SRC_MAP #undef FAIL_IF_NO_EXPERIMENTAL_EH #undef X1 #undef X2 @@ -2407,11 +2406,13 @@ TEST_F(WasmModuleVerifyTest, MultipleNameSections) { #undef FOUR_EMPTY_BODIES #undef SIGNATURES_SECTION_VOID_VOID #undef LINEAR_MEMORY_INDEX_0 +#undef EXCEPTION_ENTRY #undef EXPECT_VERIFIES #undef EXPECT_FAILURE_LEN #undef EXPECT_FAILURE #undef EXPECT_OFF_END_FAILURE #undef EXPECT_OK +#undef EXPECT_NOT_OK } // namespace module_decoder_unittest } // namespace wasm diff --git a/deps/v8/test/unittests/wasm/streaming-decoder-unittest.cc b/deps/v8/test/unittests/wasm/streaming-decoder-unittest.cc index 4159117c26..a5b89762ad 100644 --- a/deps/v8/test/unittests/wasm/streaming-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/streaming-decoder-unittest.cc @@ -17,20 +17,32 @@ namespace v8 { namespace internal { namespace wasm { +struct MockStreamingResult { + size_t num_sections = 0; + size_t num_functions = 0; + bool ok = true; + OwnedVector<uint8_t> received_bytes; + + MockStreamingResult() = default; +}; + class MockStreamingProcessor : public StreamingProcessor { public: + explicit MockStreamingProcessor(MockStreamingResult* result) + : result_(result) {} + bool ProcessModuleHeader(Vector<const uint8_t> bytes, uint32_t offset) override { // TODO(ahaas): Share code with the module-decoder. Decoder decoder(bytes.begin(), bytes.end()); uint32_t magic_word = decoder.consume_u32("wasm magic"); if (decoder.failed() || magic_word != kWasmMagic) { - ok_ = false; + result_->ok = false; return false; } uint32_t magic_version = decoder.consume_u32("wasm version"); if (decoder.failed() || magic_version != kWasmVersion) { - ok_ = false; + result_->ok = false; return false; } return true; @@ -38,19 +50,19 @@ class MockStreamingProcessor : public StreamingProcessor { // Process all sections but the code section. bool ProcessSection(SectionCode section_code, Vector<const uint8_t> bytes, uint32_t offset) override { - ++num_sections_; + ++result_->num_sections; return true; } - bool ProcessCodeSectionHeader(size_t num_functions, - uint32_t offset) override { + bool ProcessCodeSectionHeader(size_t num_functions, uint32_t offset, + std::shared_ptr<WireBytesStorage>) override { return true; } // Process a function body. bool ProcessFunctionBody(Vector<const uint8_t> bytes, uint32_t offset) override { - ++num_functions_; + ++result_->num_functions; return true; } @@ -58,26 +70,21 @@ class MockStreamingProcessor : public StreamingProcessor { // Finish the processing of the stream. void OnFinishedStream(OwnedVector<uint8_t> bytes) override { - received_bytes_ = std::move(bytes); + result_->received_bytes = std::move(bytes); } // Report an error detected in the StreamingDecoder. - void OnError(DecodeResult result) override { ok_ = false; } + void OnError(const WasmError&) override { result_->ok = false; } void OnAbort() override {} - size_t num_sections() const { return num_sections_; } - size_t num_functions() const { return num_functions_; } - bool ok() const { return ok_; } - Vector<const uint8_t> received_bytes() const { - return received_bytes_.as_vector(); - } + bool Deserialize(Vector<const uint8_t> module_bytes, + Vector<const uint8_t> wire_bytes) override { + return false; + }; private: - size_t num_sections_ = 0; - size_t num_functions_ = 0; - bool ok_ = true; - OwnedVector<uint8_t> received_bytes_; + MockStreamingResult* const result_; }; class WasmStreamingDecoderTest : public ::testing::Test { @@ -85,50 +92,49 @@ class WasmStreamingDecoderTest : public ::testing::Test { void ExpectVerifies(Vector<const uint8_t> data, size_t expected_sections, size_t expected_functions) { for (int split = 0; split <= data.length(); ++split) { - // Use a unique_ptr so that the StreamingDecoder can own the processor. - std::unique_ptr<MockStreamingProcessor> p(new MockStreamingProcessor()); - MockStreamingProcessor* processor = p.get(); - StreamingDecoder stream(std::move(p)); + MockStreamingResult result; + StreamingDecoder stream( + base::make_unique<MockStreamingProcessor>(&result)); stream.OnBytesReceived(data.SubVector(0, split)); stream.OnBytesReceived(data.SubVector(split, data.length())); stream.Finish(); - EXPECT_TRUE(processor->ok()); - EXPECT_EQ(expected_sections, processor->num_sections()); - EXPECT_EQ(expected_functions, processor->num_functions()); - EXPECT_EQ(data, processor->received_bytes()); + EXPECT_TRUE(result.ok); + EXPECT_EQ(expected_sections, result.num_sections); + EXPECT_EQ(expected_functions, result.num_functions); + EXPECT_EQ(data, result.received_bytes.as_vector()); } } void ExpectFailure(Vector<const uint8_t> data) { for (int split = 0; split <= data.length(); ++split) { - std::unique_ptr<MockStreamingProcessor> p(new MockStreamingProcessor()); - MockStreamingProcessor* processor = p.get(); - StreamingDecoder stream(std::move(p)); + MockStreamingResult result; + StreamingDecoder stream( + base::make_unique<MockStreamingProcessor>(&result)); stream.OnBytesReceived(data.SubVector(0, split)); stream.OnBytesReceived(data.SubVector(split, data.length())); stream.Finish(); - EXPECT_FALSE(processor->ok()); + EXPECT_FALSE(result.ok); } } + + MockStreamingResult result; }; TEST_F(WasmStreamingDecoderTest, EmptyStream) { - std::unique_ptr<MockStreamingProcessor> p(new MockStreamingProcessor()); - MockStreamingProcessor* processor = p.get(); - StreamingDecoder stream(std::move(p)); + MockStreamingResult result; + StreamingDecoder stream(base::make_unique<MockStreamingProcessor>(&result)); stream.Finish(); - EXPECT_FALSE(processor->ok()); + EXPECT_FALSE(result.ok); } TEST_F(WasmStreamingDecoderTest, IncompleteModuleHeader) { const uint8_t data[] = {U32_LE(kWasmMagic), U32_LE(kWasmVersion)}; { - std::unique_ptr<MockStreamingProcessor> p(new MockStreamingProcessor()); - MockStreamingProcessor* processor = p.get(); - StreamingDecoder stream(std::move(p)); + MockStreamingResult result; + StreamingDecoder stream(base::make_unique<MockStreamingProcessor>(&result)); stream.OnBytesReceived(Vector<const uint8_t>(data, 1)); stream.Finish(); - EXPECT_FALSE(processor->ok()); + EXPECT_FALSE(result.ok); } for (int length = 1; length < static_cast<int>(arraysize(data)); ++length) { ExpectFailure(Vector<const uint8_t>(data, length)); diff --git a/deps/v8/test/unittests/wasm/trap-handler-unittest.cc b/deps/v8/test/unittests/wasm/trap-handler-posix-unittest.cc index 07e3ca888d..604d2adfb2 100644 --- a/deps/v8/test/unittests/wasm/trap-handler-unittest.cc +++ b/deps/v8/test/unittests/wasm/trap-handler-posix-unittest.cc @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/trap-handler/trap-handler.h" #include "include/v8.h" +#include "src/trap-handler/trap-handler.h" #include "testing/gtest/include/gtest/gtest.h" #if V8_OS_POSIX @@ -58,7 +58,7 @@ TEST_F(SignalHandlerFallbackTest, DoTest) { FAIL(); } else { // Our signal handler ran. - v8::internal::trap_handler::RestoreOriginalSignalHandler(); + v8::internal::trap_handler::RemoveTrapHandler(); SUCCEED(); return; } diff --git a/deps/v8/test/unittests/wasm/trap-handler-win-unittest.cc b/deps/v8/test/unittests/wasm/trap-handler-win-unittest.cc new file mode 100644 index 0000000000..58302bad74 --- /dev/null +++ b/deps/v8/test/unittests/wasm/trap-handler-win-unittest.cc @@ -0,0 +1,93 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <windows.h> + +#include "include/v8.h" +#include "src/allocation.h" +#include "src/base/page-allocator.h" +#include "src/trap-handler/trap-handler.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +#if V8_TRAP_HANDLER_SUPPORTED + +bool g_handler_got_executed = false; +// The start address of the virtual memory we use to cause an exception. +i::Address g_start_address; + +// When using V8::EnableWebAssemblyTrapHandler, we save the old one to fall back +// on if V8 doesn't handle the exception. This allows tools like ASan to +// register a handler early on during the process startup and still generate +// stack traces on failures. +class ExceptionHandlerFallbackTest : public ::testing::Test { + protected: + void SetUp() override { + // Register this handler as the last handler. + registered_handler_ = AddVectoredExceptionHandler(/*first=*/0, TestHandler); + CHECK_NOT_NULL(registered_handler_); + + v8::PageAllocator* page_allocator = i::GetPlatformPageAllocator(); + // We only need a single page. + size_t size = page_allocator->AllocatePageSize(); + void* hint = page_allocator->GetRandomMmapAddr(); + i::VirtualMemory mem(page_allocator, size, hint, size); + g_start_address = mem.address(); + // Set the permissions of the memory to no-access. + CHECK(mem.SetPermissions(g_start_address, size, + v8::PageAllocator::kNoAccess)); + mem_ = std::move(mem); + } + + void WriteToTestMemory(int value) { + *reinterpret_cast<volatile int*>(g_start_address) = value; + } + + int ReadFromTestMemory() { + return *reinterpret_cast<volatile int*>(g_start_address); + } + + void TearDown() override { + // be a good citizen and remove the exception handler. + ULONG result = RemoveVectoredExceptionHandler(registered_handler_); + CHECK(result); + } + + private: + static LONG WINAPI TestHandler(EXCEPTION_POINTERS* exception) { + g_handler_got_executed = true; + v8::PageAllocator* page_allocator = i::GetPlatformPageAllocator(); + // Make the allocated memory accessible so that from now on memory accesses + // do not cause an exception anymore. + CHECK(i::SetPermissions(page_allocator, g_start_address, + page_allocator->AllocatePageSize(), + v8::PageAllocator::kReadWrite)); + // The memory access should work now, we can continue execution. + return EXCEPTION_CONTINUE_EXECUTION; + } + + i::VirtualMemory mem_; + void* registered_handler_; +}; + +TEST_F(ExceptionHandlerFallbackTest, DoTest) { + constexpr bool use_default_handler = true; + CHECK(v8::V8::EnableWebAssemblyTrapHandler(use_default_handler)); + // In the original test setup the test memory is protected against any kind of + // access. Therefore the access here causes an access violation exception, + // which should be caught by the exception handler we install above. In the + // exception handler we change the permission of the test memory to make it + // accessible, and then return from the exception handler to execute the + // memory access again. This time we expect the memory access to work. + constexpr int test_value = 42; + WriteToTestMemory(test_value); + CHECK_EQ(test_value, ReadFromTestMemory()); + CHECK(g_handler_got_executed); + v8::internal::trap_handler::RemoveTrapHandler(); +} + +#endif + +} // namespace diff --git a/deps/v8/test/unittests/wasm/trap-handler-x64-unittest.cc b/deps/v8/test/unittests/wasm/trap-handler-x64-unittest.cc new file mode 100644 index 0000000000..8c42b1735c --- /dev/null +++ b/deps/v8/test/unittests/wasm/trap-handler-x64-unittest.cc @@ -0,0 +1,478 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "include/v8config.h" + +#if V8_OS_LINUX +#include <signal.h> +#include <ucontext.h> +#elif V8_OS_MACOSX +#include <signal.h> +#include <sys/ucontext.h> +#elif V8_OS_WIN +#include <windows.h> +#endif + +#include "testing/gtest/include/gtest/gtest.h" + +#if V8_OS_POSIX +#include "include/v8-wasm-trap-handler-posix.h" +#elif V8_OS_WIN +#include "include/v8-wasm-trap-handler-win.h" +#endif +#include "src/allocation.h" +#include "src/assembler-inl.h" +#include "src/base/page-allocator.h" +#include "src/macro-assembler-inl.h" +#include "src/simulator.h" +#include "src/trap-handler/trap-handler.h" +#include "src/vector.h" +#include "src/wasm/wasm-engine.h" +#include "src/wasm/wasm-memory.h" + +#include "test/common/assembler-tester.h" +#include "test/unittests/test-utils.h" + +namespace v8 { +namespace internal { +namespace wasm { + +namespace { +constexpr Register scratch = r10; +bool g_test_handler_executed = false; +#if V8_OS_LINUX || V8_OS_MACOSX +struct sigaction g_old_segv_action; +struct sigaction g_old_fpe_action; +struct sigaction g_old_bus_action; // We get SIGBUS on Mac sometimes. +#elif V8_OS_WIN +void* g_registered_handler = nullptr; +#endif + +// The recovery address allows us to recover from an intentional crash. +Address g_recovery_address; +// Flag to indicate if the test handler should call the trap handler as a first +// chance handler. +bool g_use_as_first_chance_handler = false; +} // namespace + +#define __ masm. + +enum TrapHandlerStyle : int { + // The test uses the default trap handler of V8. + kDefault = 0, + // The test installs the trap handler callback in its own test handler. + kCallback = 1 +}; + +std::string PrintTrapHandlerTestParam( + ::testing::TestParamInfo<TrapHandlerStyle> info) { + switch (info.param) { + case kDefault: + return "DefaultTrapHandler"; + case kCallback: + return "Callback"; + } + UNREACHABLE(); +} + +class TrapHandlerTest : public TestWithIsolate, + public ::testing::WithParamInterface<TrapHandlerStyle> { + protected: + void SetUp() override { + void* base = nullptr; + size_t length = 0; + accessible_memory_start_ = + i_isolate() + ->wasm_engine() + ->memory_tracker() + ->TryAllocateBackingStoreForTesting( + i_isolate()->heap(), 1 * kWasmPageSize, &base, &length); + memory_buffer_ = + base::AddressRegion(reinterpret_cast<Address>(base), length); + + // The allocated memory buffer ends with a guard page. + crash_address_ = memory_buffer_.end() - 32; + // Allocate a buffer for the generated code. + buffer_ = AllocateAssemblerBuffer(AssemblerBase::kMinimalBufferSize, + GetRandomMmapAddr()); + + InitRecoveryCode(); + +#if V8_OS_LINUX || V8_OS_MACOSX + // Set up a signal handler to recover from the expected crash. + struct sigaction action; + action.sa_sigaction = SignalHandler; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; + // SIGSEGV happens for wasm oob memory accesses on Linux. + CHECK_EQ(0, sigaction(SIGSEGV, &action, &g_old_segv_action)); + // SIGBUS happens for wasm oob memory accesses on macOS. + CHECK_EQ(0, sigaction(SIGBUS, &action, &g_old_bus_action)); + // SIGFPE to simulate crashes which are not handled by the trap handler. + CHECK_EQ(0, sigaction(SIGFPE, &action, &g_old_fpe_action)); +#elif V8_OS_WIN + g_registered_handler = + AddVectoredExceptionHandler(/*first=*/0, TestHandler); +#endif + } + + void TearDown() override { + // We should always have left wasm code. + CHECK(!GetThreadInWasmFlag()); + buffer_.reset(); + recovery_buffer_.reset(); + + // Free the allocated backing store. + i_isolate()->wasm_engine()->memory_tracker()->FreeBackingStoreForTesting( + memory_buffer_, accessible_memory_start_); + + // Clean up the trap handler + trap_handler::RemoveTrapHandler(); + if (!g_test_handler_executed) { +#if V8_OS_LINUX || V8_OS_MACOSX + // The test handler cleans up the signal handler setup in the test. If the + // test handler was not called, we have to do the cleanup ourselves. + CHECK_EQ(0, sigaction(SIGSEGV, &g_old_segv_action, nullptr)); + CHECK_EQ(0, sigaction(SIGFPE, &g_old_fpe_action, nullptr)); + CHECK_EQ(0, sigaction(SIGBUS, &g_old_bus_action, nullptr)); +#elif V8_OS_WIN + RemoveVectoredExceptionHandler(g_registered_handler); + g_registered_handler = nullptr; +#endif + } + } + + void InitRecoveryCode() { + // Create a code snippet where we can jump to to recover from a signal or + // exception. The code snippet only consists of a return statement. + recovery_buffer_ = AllocateAssemblerBuffer( + AssemblerBase::kMinimalBufferSize, GetRandomMmapAddr()); + + MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + recovery_buffer_->CreateView()); + int recovery_offset = __ pc_offset(); + __ Pop(scratch); + __ Ret(); + CodeDesc desc; + masm.GetCode(nullptr, &desc); + recovery_buffer_->MakeExecutable(); + g_recovery_address = + reinterpret_cast<Address>(desc.buffer + recovery_offset); + } + +#if V8_OS_LINUX || V8_OS_MACOSX + static void SignalHandler(int signal, siginfo_t* info, void* context) { + if (g_use_as_first_chance_handler) { + if (v8::TryHandleWebAssemblyTrapPosix(signal, info, context)) { + return; + } + } + + // Reset the signal handler, to avoid that this signal handler is called + // repeatedly. + sigaction(SIGSEGV, &g_old_segv_action, nullptr); + sigaction(SIGFPE, &g_old_fpe_action, nullptr); + sigaction(SIGBUS, &g_old_bus_action, nullptr); + + g_test_handler_executed = true; + // Set the $rip to the recovery code. + ucontext_t* uc = reinterpret_cast<ucontext_t*>(context); +#if V8_OS_LINUX + uc->uc_mcontext.gregs[REG_RIP] = g_recovery_address; +#else // V8_OS_MACOSX + uc->uc_mcontext->__ss.__rip = g_recovery_address; +#endif + } +#endif + +#if V8_OS_WIN + static LONG WINAPI TestHandler(EXCEPTION_POINTERS* exception) { + if (g_use_as_first_chance_handler) { + if (v8::TryHandleWebAssemblyTrapWindows(exception)) { + return EXCEPTION_CONTINUE_EXECUTION; + } + } + RemoveVectoredExceptionHandler(g_registered_handler); + g_registered_handler = nullptr; + g_test_handler_executed = true; + exception->ContextRecord->Rip = g_recovery_address; + return EXCEPTION_CONTINUE_EXECUTION; + } +#endif + + public: + void SetupTrapHandler(TrapHandlerStyle style) { + bool use_default_handler = style == kDefault; + g_use_as_first_chance_handler = !use_default_handler; + CHECK(v8::V8::EnableWebAssemblyTrapHandler(use_default_handler)); + } + + void GenerateSetThreadInWasmFlagCode(MacroAssembler* masm) { + masm->Move(scratch, + i_isolate()->thread_local_top()->thread_in_wasm_flag_address_, + RelocInfo::NONE); + masm->movl(MemOperand(scratch, 0), Immediate(1)); + } + + void GenerateResetThreadInWasmFlagCode(MacroAssembler* masm) { + masm->Move(scratch, + i_isolate()->thread_local_top()->thread_in_wasm_flag_address_, + RelocInfo::NONE); + masm->movl(MemOperand(scratch, 0), Immediate(0)); + } + + bool GetThreadInWasmFlag() { + return *reinterpret_cast<int*>( + trap_handler::GetThreadInWasmThreadLocalAddress()); + } + + // Execute the code in buffer. + void ExecuteBuffer() { + buffer_->MakeExecutable(); + GeneratedCode<void>::FromAddress( + i_isolate(), reinterpret_cast<Address>(buffer_->start())) + .Call(); + CHECK(!g_test_handler_executed); + } + + // Execute the code in buffer. We expect a crash which we recover from in the + // test handler. + void ExecuteExpectCrash(TestingAssemblerBuffer* buffer, + bool check_wasm_flag = true) { + CHECK(!g_test_handler_executed); + buffer->MakeExecutable(); + GeneratedCode<void>::FromAddress(i_isolate(), + reinterpret_cast<Address>(buffer->start())) + .Call(); + CHECK(g_test_handler_executed); + g_test_handler_executed = false; + if (check_wasm_flag) CHECK(!GetThreadInWasmFlag()); + } + + bool test_handler_executed() { return g_test_handler_executed; } + + // Allocated memory which corresponds to wasm memory with guard regions. + base::AddressRegion memory_buffer_; + // Address within the guard region of the wasm memory. Accessing this memory + // address causes a signal or exception. + Address crash_address_; + // The start of the accessible region in the allocated memory. This pointer is + // needed to de-register the memory from the wasm memory tracker again. + void* accessible_memory_start_; + + // Buffer for generated code. + std::unique_ptr<TestingAssemblerBuffer> buffer_; + // Buffer for the code for the landing pad of the test handler. + std::unique_ptr<TestingAssemblerBuffer> recovery_buffer_; +}; + +TEST_P(TrapHandlerTest, TestTrapHandlerRecovery) { + // Test that the wasm trap handler can recover a memory access violation in + // wasm code (we fake the wasm code and the access violation). + MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer_->CreateView()); + __ Push(scratch); + GenerateSetThreadInWasmFlagCode(&masm); + __ Move(scratch, crash_address_, RelocInfo::NONE); + int crash_offset = __ pc_offset(); + __ testl(MemOperand(scratch, 0), Immediate(1)); + int recovery_offset = __ pc_offset(); + GenerateResetThreadInWasmFlagCode(&masm); + __ Pop(scratch); + __ Ret(); + CodeDesc desc; + masm.GetCode(nullptr, &desc); + + SetupTrapHandler(GetParam()); + trap_handler::ProtectedInstructionData protected_instruction{crash_offset, + recovery_offset}; + trap_handler::RegisterHandlerData(reinterpret_cast<Address>(desc.buffer), + desc.instr_size, 1, &protected_instruction); + + ExecuteBuffer(); +} + +TEST_P(TrapHandlerTest, TestReleaseHandlerData) { + // Test that after we release handler data in the trap handler, it cannot + // recover from the specific memory access violation anymore. + MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer_->CreateView()); + __ Push(scratch); + GenerateSetThreadInWasmFlagCode(&masm); + __ Move(scratch, crash_address_, RelocInfo::NONE); + int crash_offset = __ pc_offset(); + __ testl(MemOperand(scratch, 0), Immediate(1)); + int recovery_offset = __ pc_offset(); + GenerateResetThreadInWasmFlagCode(&masm); + __ Pop(scratch); + __ Ret(); + CodeDesc desc; + masm.GetCode(nullptr, &desc); + + trap_handler::ProtectedInstructionData protected_instruction{crash_offset, + recovery_offset}; + int handler_id = trap_handler::RegisterHandlerData( + reinterpret_cast<Address>(desc.buffer), desc.instr_size, 1, + &protected_instruction); + + SetupTrapHandler(GetParam()); + + ExecuteBuffer(); + + // Deregister from the trap handler. The trap handler should not do the + // recovery now. + trap_handler::ReleaseHandlerData(handler_id); + + ExecuteExpectCrash(buffer_.get()); +} + +TEST_P(TrapHandlerTest, TestNoThreadInWasmFlag) { + // That that if the thread_in_wasm flag is not set, the trap handler does not + // get active. + MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer_->CreateView()); + __ Push(scratch); + __ Move(scratch, crash_address_, RelocInfo::NONE); + int crash_offset = __ pc_offset(); + __ testl(MemOperand(scratch, 0), Immediate(1)); + int recovery_offset = __ pc_offset(); + __ Pop(scratch); + __ Ret(); + CodeDesc desc; + masm.GetCode(nullptr, &desc); + + trap_handler::ProtectedInstructionData protected_instruction{crash_offset, + recovery_offset}; + trap_handler::RegisterHandlerData(reinterpret_cast<Address>(desc.buffer), + desc.instr_size, 1, &protected_instruction); + + SetupTrapHandler(GetParam()); + + ExecuteExpectCrash(buffer_.get()); +} + +TEST_P(TrapHandlerTest, TestCrashInWasmNoProtectedInstruction) { + // Test that if the crash in wasm happened at an instruction which is not + // protected, then the trap handler does not handle it. + MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer_->CreateView()); + __ Push(scratch); + GenerateSetThreadInWasmFlagCode(&masm); + int no_crash_offset = __ pc_offset(); + __ Move(scratch, crash_address_, RelocInfo::NONE); + __ testl(MemOperand(scratch, 0), Immediate(1)); + // Offset where the crash is not happening. + int recovery_offset = __ pc_offset(); + GenerateResetThreadInWasmFlagCode(&masm); + __ Pop(scratch); + __ Ret(); + CodeDesc desc; + masm.GetCode(nullptr, &desc); + + trap_handler::ProtectedInstructionData protected_instruction{no_crash_offset, + recovery_offset}; + trap_handler::RegisterHandlerData(reinterpret_cast<Address>(desc.buffer), + desc.instr_size, 1, &protected_instruction); + + SetupTrapHandler(GetParam()); + + ExecuteExpectCrash(buffer_.get()); +} + +TEST_P(TrapHandlerTest, TestCrashInWasmWrongCrashType) { + // Test that if the crash reason is not a memory access violation, then the + // wasm trap handler does not handle it. + MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer_->CreateView()); + __ Push(scratch); + GenerateSetThreadInWasmFlagCode(&masm); + __ xorq(scratch, scratch); + int crash_offset = __ pc_offset(); + __ divq(scratch); + // Offset where the crash is not happening. + int recovery_offset = __ pc_offset(); + GenerateResetThreadInWasmFlagCode(&masm); + __ Pop(scratch); + __ Ret(); + CodeDesc desc; + masm.GetCode(nullptr, &desc); + + trap_handler::ProtectedInstructionData protected_instruction{crash_offset, + recovery_offset}; + trap_handler::RegisterHandlerData(reinterpret_cast<Address>(desc.buffer), + desc.instr_size, 1, &protected_instruction); + + SetupTrapHandler(GetParam()); + +#if V8_OS_POSIX + // The V8 default trap handler does not register for SIGFPE, therefore the + // thread-in-wasm flag is never reset in this test. We therefore do not check + // the value of this flag. + bool check_wasm_flag = GetParam() != kDefault; +#else + bool check_wasm_flag = true; +#endif + ExecuteExpectCrash(buffer_.get(), check_wasm_flag); + if (!check_wasm_flag) { + // Reset the thread-in-wasm flag because it was probably not reset in the + // trap handler. + *trap_handler::GetThreadInWasmThreadLocalAddress() = 0; + } +} + +class CodeRunner : public v8::base::Thread { + public: + CodeRunner(TrapHandlerTest* test, TestingAssemblerBuffer* buffer) + : Thread(Options("CodeRunner")), test_(test), buffer_(buffer) {} + + void Run() override { test_->ExecuteExpectCrash(buffer_); } + + private: + TrapHandlerTest* test_; + TestingAssemblerBuffer* buffer_; +}; + +TEST_P(TrapHandlerTest, TestCrashInOtherThread) { + // Test setup: + // The current thread enters wasm land (sets the thread_in_wasm flag) + // A second thread crashes at a protected instruction without having the flag + // set. + MacroAssembler masm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, + buffer_->CreateView()); + __ Push(scratch); + __ Move(scratch, crash_address_, RelocInfo::NONE); + int crash_offset = __ pc_offset(); + __ testl(MemOperand(scratch, 0), Immediate(1)); + int recovery_offset = __ pc_offset(); + __ Pop(scratch); + __ Ret(); + CodeDesc desc; + masm.GetCode(nullptr, &desc); + + trap_handler::ProtectedInstructionData protected_instruction{crash_offset, + recovery_offset}; + trap_handler::RegisterHandlerData(reinterpret_cast<Address>(desc.buffer), + desc.instr_size, 1, &protected_instruction); + + SetupTrapHandler(GetParam()); + + CodeRunner runner(this, buffer_.get()); + CHECK(!GetThreadInWasmFlag()); + // Set the thread-in-wasm flag manually in this thread. + *trap_handler::GetThreadInWasmThreadLocalAddress() = 1; + runner.Start(); + runner.Join(); + CHECK(GetThreadInWasmFlag()); + // Reset the thread-in-wasm flag. + *trap_handler::GetThreadInWasmThreadLocalAddress() = 0; +} + +INSTANTIATE_TEST_CASE_P(/* no prefix */, TrapHandlerTest, + ::testing::Values(kDefault, kCallback), + PrintTrapHandlerTestParam); + +#undef __ +} // namespace wasm +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/wasm/wasm-code-manager-unittest.cc b/deps/v8/test/unittests/wasm/wasm-code-manager-unittest.cc index 5d695c8275..e90c97f3a1 100644 --- a/deps/v8/test/unittests/wasm/wasm-code-manager-unittest.cc +++ b/deps/v8/test/unittests/wasm/wasm-code-manager-unittest.cc @@ -8,6 +8,7 @@ #include "src/wasm/function-compiler.h" #include "src/wasm/jump-table-assembler.h" #include "src/wasm/wasm-code-manager.h" +#include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-memory.h" namespace v8 { @@ -160,15 +161,12 @@ class WasmCodeManagerTest : public TestWithContext, using NativeModulePtr = std::unique_ptr<NativeModule>; - NativeModulePtr AllocModule(WasmCodeManager* manager, size_t size, - ModuleStyle style) { + NativeModulePtr AllocModule(size_t size, ModuleStyle style) { std::shared_ptr<WasmModule> module(new WasmModule); module->num_declared_functions = kNumFunctions; bool can_request_more = style == Growable; - ModuleEnv env(module.get(), UseTrapHandler::kNoTrapHandler, - RuntimeExceptionSupport::kNoRuntimeExceptionSupport); - return manager->NewNativeModule(i_isolate(), kAllWasmFeatures, size, - can_request_more, std::move(module), env); + return manager()->NewNativeModule(i_isolate(), kAllWasmFeatures, size, + can_request_more, std::move(module)); } WasmCode* AddCode(NativeModule* native_module, uint32_t index, size_t size) { @@ -178,15 +176,18 @@ class WasmCodeManagerTest : public TestWithContext, desc.buffer = exec_buff.get(); desc.instr_size = static_cast<int>(size); return native_module->AddCode(index, desc, 0, 0, 0, {}, OwnedVector<byte>(), - WasmCode::kOther); + WasmCode::kFunction, WasmCode::kOther); } size_t page() const { return AllocatePageSize(); } - WasmMemoryTracker* memory_tracker() { return &memory_tracker_; } + WasmCodeManager* manager() { + return i_isolate()->wasm_engine()->code_manager(); + } - private: - WasmMemoryTracker memory_tracker_; + void SetMaxCommittedMemory(size_t limit) { + manager()->SetMaxCommittedMemoryForTesting(limit); + } }; INSTANTIATE_TEST_CASE_P(Parameterized, WasmCodeManagerTest, @@ -194,32 +195,32 @@ INSTANTIATE_TEST_CASE_P(Parameterized, WasmCodeManagerTest, PrintWasmCodeManageTestParam); TEST_P(WasmCodeManagerTest, EmptyCase) { - WasmCodeManager manager(memory_tracker(), 0 * page()); - CHECK_EQ(0, manager.remaining_uncommitted_code_space()); + SetMaxCommittedMemory(0 * page()); + CHECK_EQ(0, manager()->remaining_uncommitted_code_space()); - ASSERT_DEATH_IF_SUPPORTED(AllocModule(&manager, 1 * page(), GetParam()), + ASSERT_DEATH_IF_SUPPORTED(AllocModule(1 * page(), GetParam()), "OOM in NativeModule::AllocateForCode commit"); } TEST_P(WasmCodeManagerTest, AllocateAndGoOverLimit) { - WasmCodeManager manager(memory_tracker(), 1 * page()); - CHECK_EQ(1 * page(), manager.remaining_uncommitted_code_space()); - NativeModulePtr native_module = AllocModule(&manager, 1 * page(), GetParam()); + SetMaxCommittedMemory(1 * page()); + CHECK_EQ(1 * page(), manager()->remaining_uncommitted_code_space()); + NativeModulePtr native_module = AllocModule(1 * page(), GetParam()); CHECK(native_module); - CHECK_EQ(0, manager.remaining_uncommitted_code_space()); + CHECK_EQ(0, manager()->remaining_uncommitted_code_space()); uint32_t index = 0; WasmCode* code = AddCode(native_module.get(), index++, 1 * kCodeAlignment); CHECK_NOT_NULL(code); - CHECK_EQ(0, manager.remaining_uncommitted_code_space()); + CHECK_EQ(0, manager()->remaining_uncommitted_code_space()); code = AddCode(native_module.get(), index++, 3 * kCodeAlignment); CHECK_NOT_NULL(code); - CHECK_EQ(0, manager.remaining_uncommitted_code_space()); + CHECK_EQ(0, manager()->remaining_uncommitted_code_space()); code = AddCode(native_module.get(), index++, page() - 4 * kCodeAlignment - kJumpTableSize); CHECK_NOT_NULL(code); - CHECK_EQ(0, manager.remaining_uncommitted_code_space()); + CHECK_EQ(0, manager()->remaining_uncommitted_code_space()); // This fails in "reservation" if we cannot extend the code space, or in // "commit" it we can (since we hit the allocation limit in the @@ -230,9 +231,9 @@ TEST_P(WasmCodeManagerTest, AllocateAndGoOverLimit) { } TEST_P(WasmCodeManagerTest, TotalLimitIrrespectiveOfModuleCount) { - WasmCodeManager manager(memory_tracker(), 3 * page()); - NativeModulePtr nm1 = AllocModule(&manager, 2 * page(), GetParam()); - NativeModulePtr nm2 = AllocModule(&manager, 2 * page(), GetParam()); + SetMaxCommittedMemory(3 * page()); + NativeModulePtr nm1 = AllocModule(2 * page(), GetParam()); + NativeModulePtr nm2 = AllocModule(2 * page(), GetParam()); CHECK(nm1); CHECK(nm2); WasmCode* code = AddCode(nm1.get(), 0, 2 * page() - kJumpTableSize); @@ -241,23 +242,9 @@ TEST_P(WasmCodeManagerTest, TotalLimitIrrespectiveOfModuleCount) { "OOM in NativeModule::AllocateForCode commit"); } -TEST_P(WasmCodeManagerTest, DifferentHeapsApplyLimitsIndependently) { - WasmCodeManager manager1(memory_tracker(), 1 * page()); - WasmCodeManager manager2(memory_tracker(), 2 * page()); - NativeModulePtr nm1 = AllocModule(&manager1, 1 * page(), GetParam()); - NativeModulePtr nm2 = AllocModule(&manager2, 1 * page(), GetParam()); - CHECK(nm1); - CHECK(nm2); - WasmCode* code = AddCode(nm1.get(), 0, 1 * page() - kJumpTableSize); - CHECK_NOT_NULL(code); - CHECK_EQ(0, manager1.remaining_uncommitted_code_space()); - code = AddCode(nm2.get(), 0, 1 * page() - kJumpTableSize); - CHECK_NOT_NULL(code); -} - TEST_P(WasmCodeManagerTest, GrowingVsFixedModule) { - WasmCodeManager manager(memory_tracker(), 3 * page()); - NativeModulePtr nm = AllocModule(&manager, 1 * page(), GetParam()); + SetMaxCommittedMemory(3 * page()); + NativeModulePtr nm = AllocModule(1 * page(), GetParam()); size_t module_size = GetParam() == Fixed ? kMaxWasmCodeMemory : 1 * page(); size_t remaining_space_in_module = module_size - kJumpTableSize; if (GetParam() == Fixed) { @@ -270,29 +257,29 @@ TEST_P(WasmCodeManagerTest, GrowingVsFixedModule) { // The module grows by one page. One page remains uncommitted. CHECK_NOT_NULL( AddCode(nm.get(), 0, remaining_space_in_module + kCodeAlignment)); - CHECK_EQ(manager.remaining_uncommitted_code_space(), 1 * page()); + CHECK_EQ(manager()->remaining_uncommitted_code_space(), 1 * page()); } } TEST_P(WasmCodeManagerTest, CommitIncrements) { - WasmCodeManager manager(memory_tracker(), 10 * page()); - NativeModulePtr nm = AllocModule(&manager, 3 * page(), GetParam()); + SetMaxCommittedMemory(10 * page()); + NativeModulePtr nm = AllocModule(3 * page(), GetParam()); WasmCode* code = AddCode(nm.get(), 0, kCodeAlignment); CHECK_NOT_NULL(code); - CHECK_EQ(manager.remaining_uncommitted_code_space(), 9 * page()); + CHECK_EQ(manager()->remaining_uncommitted_code_space(), 9 * page()); code = AddCode(nm.get(), 1, 2 * page()); CHECK_NOT_NULL(code); - CHECK_EQ(manager.remaining_uncommitted_code_space(), 7 * page()); + CHECK_EQ(manager()->remaining_uncommitted_code_space(), 7 * page()); code = AddCode(nm.get(), 2, page() - kCodeAlignment - kJumpTableSize); CHECK_NOT_NULL(code); - CHECK_EQ(manager.remaining_uncommitted_code_space(), 7 * page()); + CHECK_EQ(manager()->remaining_uncommitted_code_space(), 7 * page()); } TEST_P(WasmCodeManagerTest, Lookup) { - WasmCodeManager manager(memory_tracker(), 2 * page()); + SetMaxCommittedMemory(2 * page()); - NativeModulePtr nm1 = AllocModule(&manager, 1 * page(), GetParam()); - NativeModulePtr nm2 = AllocModule(&manager, 1 * page(), GetParam()); + NativeModulePtr nm1 = AllocModule(1 * page(), GetParam()); + NativeModulePtr nm2 = AllocModule(1 * page(), GetParam()); WasmCode* code1_0 = AddCode(nm1.get(), 0, kCodeAlignment); CHECK_EQ(nm1.get(), code1_0->native_module()); WasmCode* code1_1 = AddCode(nm1.get(), 1, kCodeAlignment); @@ -307,63 +294,41 @@ TEST_P(WasmCodeManagerTest, Lookup) { // we know the manager object is allocated here, so we shouldn't // find any WasmCode* associated with that ptr. - WasmCode* not_found = manager.LookupCode(reinterpret_cast<Address>(&manager)); + WasmCode* not_found = + manager()->LookupCode(reinterpret_cast<Address>(manager())); CHECK_NULL(not_found); - WasmCode* found = manager.LookupCode(code1_0->instruction_start()); + WasmCode* found = manager()->LookupCode(code1_0->instruction_start()); CHECK_EQ(found, code1_0); - found = manager.LookupCode(code2_1->instruction_start() + - (code2_1->instructions().size() / 2)); + found = manager()->LookupCode(code2_1->instruction_start() + + (code2_1->instructions().size() / 2)); CHECK_EQ(found, code2_1); - found = manager.LookupCode(code2_1->instruction_start() + - code2_1->instructions().size() - 1); + found = manager()->LookupCode(code2_1->instruction_start() + + code2_1->instructions().size() - 1); CHECK_EQ(found, code2_1); - found = manager.LookupCode(code2_1->instruction_start() + - code2_1->instructions().size()); + found = manager()->LookupCode(code2_1->instruction_start() + + code2_1->instructions().size()); CHECK_NULL(found); Address mid_code1_1 = code1_1->instruction_start() + (code1_1->instructions().size() / 2); - CHECK_EQ(code1_1, manager.LookupCode(mid_code1_1)); + CHECK_EQ(code1_1, manager()->LookupCode(mid_code1_1)); nm1.reset(); - CHECK_NULL(manager.LookupCode(mid_code1_1)); -} - -TEST_P(WasmCodeManagerTest, MultiManagerLookup) { - WasmCodeManager manager1(memory_tracker(), 2 * page()); - WasmCodeManager manager2(memory_tracker(), 2 * page()); - - NativeModulePtr nm1 = AllocModule(&manager1, 1 * page(), GetParam()); - NativeModulePtr nm2 = AllocModule(&manager2, 1 * page(), GetParam()); - - WasmCode* code1_0 = AddCode(nm1.get(), 0, kCodeAlignment); - CHECK_EQ(nm1.get(), code1_0->native_module()); - WasmCode* code1_1 = AddCode(nm1.get(), 1, kCodeAlignment); - WasmCode* code2_0 = AddCode(nm2.get(), 0, kCodeAlignment); - WasmCode* code2_1 = AddCode(nm2.get(), 1, kCodeAlignment); - CHECK_EQ(nm2.get(), code2_1->native_module()); - - CHECK_EQ(0, code1_0->index()); - CHECK_EQ(1, code1_1->index()); - CHECK_EQ(0, code2_0->index()); - CHECK_EQ(1, code2_1->index()); - - CHECK_EQ(code1_0, manager1.LookupCode(code1_0->instruction_start())); - CHECK_NULL(manager2.LookupCode(code1_0->instruction_start())); + CHECK_NULL(manager()->LookupCode(mid_code1_1)); } TEST_P(WasmCodeManagerTest, LookupWorksAfterRewrite) { - WasmCodeManager manager(memory_tracker(), 2 * page()); + SetMaxCommittedMemory(2 * page()); - NativeModulePtr nm1 = AllocModule(&manager, 1 * page(), GetParam()); + NativeModulePtr nm1 = AllocModule(1 * page(), GetParam()); WasmCode* code0 = AddCode(nm1.get(), 0, kCodeAlignment); WasmCode* code1 = AddCode(nm1.get(), 1, kCodeAlignment); CHECK_EQ(0, code0->index()); CHECK_EQ(1, code1->index()); - CHECK_EQ(code1, manager.LookupCode(code1->instruction_start())); + CHECK_EQ(code1, manager()->LookupCode(code1->instruction_start())); WasmCode* code1_1 = AddCode(nm1.get(), 1, kCodeAlignment); CHECK_EQ(1, code1_1->index()); - CHECK_EQ(code1, manager.LookupCode(code1->instruction_start())); - CHECK_EQ(code1_1, manager.LookupCode(code1_1->instruction_start())); + CHECK_EQ(code1, manager()->LookupCode(code1->instruction_start())); + CHECK_EQ(code1_1, manager()->LookupCode(code1_1->instruction_start())); } } // namespace wasm_heap_unittest diff --git a/deps/v8/test/unittests/wasm/wasm-compiler-unittest.cc b/deps/v8/test/unittests/wasm/wasm-compiler-unittest.cc new file mode 100644 index 0000000000..3cca4bc55c --- /dev/null +++ b/deps/v8/test/unittests/wasm/wasm-compiler-unittest.cc @@ -0,0 +1,71 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "test/unittests/test-utils.h" + +#include "src/compiler/linkage.h" +#include "src/compiler/wasm-compiler.h" +#include "src/machine-type.h" +#include "src/signature.h" +#include "src/wasm/value-type.h" + +namespace v8 { +namespace internal { +namespace wasm { + +class WasmCallDescriptorTest : public TestWithZone {}; + +TEST_F(WasmCallDescriptorTest, TestAnyRefIsGrouped) { + constexpr size_t kMaxCount = 30; + ValueType params[kMaxCount]; + + for (size_t i = 0; i < kMaxCount; i += 2) { + params[i] = ValueType::kWasmAnyRef; + CHECK_LT(i + 1, kMaxCount); + params[i + 1] = ValueType::kWasmI32; + } + + for (size_t count = 1; count <= kMaxCount; ++count) { + FunctionSig sig(/*return_count=*/0, count, params); + compiler::CallDescriptor* desc = + compiler::GetWasmCallDescriptor(zone(), &sig); + + // The WasmInstance is the implicit first parameter. + CHECK_EQ(count + 1, desc->ParameterCount()); + + bool has_untagged_stack_param = false; + bool has_tagged_register_param = false; + int max_tagged_stack_location = std::numeric_limits<int>::min(); + int min_untagged_stack_location = std::numeric_limits<int>::max(); + for (size_t i = 1; i < desc->ParameterCount(); ++i) { + // InputLocation i + 1, because target is the first input. + compiler::LinkageLocation location = desc->GetInputLocation(i + 1); + if (desc->GetParameterType(i).IsTagged()) { + if (location.IsRegister()) { + has_tagged_register_param = true; + } else { + CHECK(location.IsCallerFrameSlot()); + max_tagged_stack_location = + std::max(max_tagged_stack_location, location.AsCallerFrameSlot()); + } + } else { // !isTagged() + if (location.IsCallerFrameSlot()) { + has_untagged_stack_param = true; + min_untagged_stack_location = std::min(min_untagged_stack_location, + location.AsCallerFrameSlot()); + } else { + CHECK(location.IsRegister()); + } + } + } + // There should never be a tagged parameter in a register and an untagged + // parameter on the stack at the same time. + CHECK_EQ(false, has_tagged_register_param && has_untagged_stack_param); + CHECK_LT(max_tagged_stack_location, min_untagged_stack_location); + } +} + +} // namespace wasm +} // namespace internal +} // namespace v8 |