summaryrefslogtreecommitdiff
path: root/deps/v8/test/cctest/wasm/test-streaming-compilation.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/cctest/wasm/test-streaming-compilation.cc')
-rw-r--r--deps/v8/test/cctest/wasm/test-streaming-compilation.cc820
1 files changed, 820 insertions, 0 deletions
diff --git a/deps/v8/test/cctest/wasm/test-streaming-compilation.cc b/deps/v8/test/cctest/wasm/test-streaming-compilation.cc
new file mode 100644
index 0000000000..0e541efbbd
--- /dev/null
+++ b/deps/v8/test/cctest/wasm/test-streaming-compilation.cc
@@ -0,0 +1,820 @@
+// Copyright 2017 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/api.h"
+#include "src/objects-inl.h"
+#include "src/v8.h"
+#include "src/vector.h"
+
+#include "src/wasm/compilation-manager.h"
+#include "src/wasm/module-decoder.h"
+#include "src/wasm/streaming-decoder.h"
+#include "src/wasm/wasm-module-builder.h"
+#include "src/wasm/wasm-module.h"
+
+#include "test/cctest/cctest.h"
+
+#include "test/common/wasm/test-signatures.h"
+#include "test/common/wasm/wasm-macro-gen.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+
+class MockPlatform final : public TestPlatform {
+ public:
+ MockPlatform() : old_platform_(i::V8::GetCurrentPlatform()) {
+ // Now that it's completely constructed, make this the current platform.
+ i::V8::SetPlatformForTesting(this);
+ }
+ virtual ~MockPlatform() {
+ // Delete all remaining tasks in the queue.
+ while (!tasks_.empty()) {
+ Task* task = tasks_.back();
+ tasks_.pop_back();
+ delete task;
+ }
+ i::V8::SetPlatformForTesting(old_platform_);
+ }
+
+ void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
+ tasks_.push_back(task);
+ }
+
+ void CallOnBackgroundThread(v8::Task* task,
+ ExpectedRuntime expected_runtime) override {
+ tasks_.push_back(task);
+ }
+
+ bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
+
+ void ExecuteTasks() {
+ while (!tasks_.empty()) {
+ Task* task = tasks_.back();
+ tasks_.pop_back();
+ task->Run();
+ delete task;
+ }
+ }
+
+ private:
+ // We do not execute tasks concurrently, so we only need one list of tasks.
+ std::vector<Task*> tasks_;
+ v8::Platform* old_platform_;
+};
+
+namespace {
+
+class StreamTester {
+ public:
+ StreamTester() : zone_(&allocator_, "StreamTester") {
+ v8::Isolate* isolate = CcTest::isolate();
+ i::Isolate* i_isolate = CcTest::i_isolate();
+
+ // Create the promise for the streaming compilation.
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<Promise::Resolver> resolver;
+ CHECK(Promise::Resolver::New(context).ToLocal(&resolver));
+ CHECK(!i_isolate->has_scheduled_exception());
+ promise_ = resolver->GetPromise();
+
+ i::Handle<i::JSPromise> i_promise = v8::Utils::OpenHandle(*promise_);
+
+ stream_ = i_isolate->wasm_compilation_manager()->StartStreamingCompilation(
+ i_isolate, v8::Utils::OpenHandle(*context), i_promise);
+ }
+
+ std::shared_ptr<StreamingDecoder> stream() { return stream_; }
+
+ // Run all compiler tasks, both foreground and background tasks.
+ void RunCompilerTasks() {
+ static_cast<MockPlatform*>(i::V8::GetCurrentPlatform())->ExecuteTasks();
+ }
+
+ bool IsPromiseFulfilled() {
+ return promise_->State() == v8::Promise::kFulfilled;
+ }
+
+ bool IsPromiseRejected() {
+ return promise_->State() == v8::Promise::kRejected;
+ }
+
+ bool IsPromisePending() { return promise_->State() == v8::Promise::kPending; }
+
+ void OnBytesReceived(const uint8_t* start, size_t length) {
+ stream_->OnBytesReceived(Vector<const uint8_t>(start, length));
+ }
+
+ void FinishStream() { stream_->Finish(); }
+
+ Zone* zone() { return &zone_; }
+
+ private:
+ AccountingAllocator allocator_;
+ Zone zone_;
+ v8::Local<v8::Promise> promise_;
+ std::shared_ptr<StreamingDecoder> stream_;
+};
+} // namespace
+
+#define STREAM_TEST(name) \
+ void RunStream_##name(); \
+ TEST(name) { \
+ MockPlatform platform; \
+ CcTest::InitializeVM(); \
+ v8::HandleScope handle_scope(CcTest::isolate()); \
+ i::HandleScope internal_scope(CcTest::i_isolate()); \
+ RunStream_##name(); \
+ } \
+ void RunStream_##name()
+
+// Create a valid module with 3 functions.
+ZoneBuffer GetValidModuleBytes(Zone* zone) {
+ ZoneBuffer buffer(zone);
+ TestSignatures sigs;
+ WasmModuleBuilder builder(zone);
+ {
+ WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii());
+ uint8_t code[] = {kExprGetLocal, 0, kExprEnd};
+ f->EmitCode(code, arraysize(code));
+ }
+ {
+ WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii());
+ uint8_t code[] = {kExprGetLocal, 1, kExprEnd};
+ f->EmitCode(code, arraysize(code));
+ }
+ {
+ WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii());
+ uint8_t code[] = {kExprGetLocal, 2, kExprEnd};
+ f->EmitCode(code, arraysize(code));
+ }
+ builder.WriteTo(buffer);
+ return buffer;
+}
+
+// Test that all bytes arrive before doing any compilation. FinishStream is
+// called immediately.
+STREAM_TEST(TestAllBytesArriveImmediatelyStreamFinishesFirst) {
+ StreamTester tester;
+ ZoneBuffer buffer = GetValidModuleBytes(tester.zone());
+
+ tester.OnBytesReceived(buffer.begin(), buffer.end() - buffer.begin());
+ tester.FinishStream();
+
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseFulfilled());
+}
+
+// Test that all bytes arrive before doing any compilation. FinishStream is
+// called after the compilation is done.
+STREAM_TEST(TestAllBytesArriveAOTCompilerFinishesFirst) {
+ StreamTester tester;
+ ZoneBuffer buffer = GetValidModuleBytes(tester.zone());
+
+ tester.OnBytesReceived(buffer.begin(), buffer.end() - buffer.begin());
+
+ tester.RunCompilerTasks();
+ tester.FinishStream();
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseFulfilled());
+}
+
+size_t GetFunctionOffset(i::Isolate* isolate, const uint8_t* buffer,
+ size_t size, size_t index) {
+ ModuleResult result = SyncDecodeWasmModule(isolate, buffer, buffer + size,
+ false, ModuleOrigin::kWasmOrigin);
+ CHECK(result.ok());
+ std::unique_ptr<WasmModule> module = std::move(result.val);
+ const WasmFunction* func = &module->functions[1];
+ return func->code.offset();
+}
+
+// Test that some functions come in the beginning, some come after some
+// functions already got compiled.
+STREAM_TEST(TestCutAfterOneFunctionStreamFinishesFirst) {
+ i::Isolate* isolate = CcTest::i_isolate();
+ StreamTester tester;
+ ZoneBuffer buffer = GetValidModuleBytes(tester.zone());
+
+ size_t offset = GetFunctionOffset(isolate, buffer.begin(), buffer.size(), 1);
+ tester.OnBytesReceived(buffer.begin(), offset);
+ tester.RunCompilerTasks();
+ CHECK(tester.IsPromisePending());
+ tester.OnBytesReceived(buffer.begin() + offset, buffer.size() - offset);
+ tester.FinishStream();
+ tester.RunCompilerTasks();
+ CHECK(tester.IsPromiseFulfilled());
+}
+
+// Test that some functions come in the beginning, some come after some
+// functions already got compiled. Call FinishStream after the compilation is
+// done.
+STREAM_TEST(TestCutAfterOneFunctionCompilerFinishesFirst) {
+ i::Isolate* isolate = CcTest::i_isolate();
+ StreamTester tester;
+ ZoneBuffer buffer = GetValidModuleBytes(tester.zone());
+
+ size_t offset = GetFunctionOffset(isolate, buffer.begin(), buffer.size(), 1);
+ tester.OnBytesReceived(buffer.begin(), offset);
+ tester.RunCompilerTasks();
+ CHECK(tester.IsPromisePending());
+ tester.OnBytesReceived(buffer.begin() + offset, buffer.size() - offset);
+ tester.RunCompilerTasks();
+ tester.FinishStream();
+ tester.RunCompilerTasks();
+ CHECK(tester.IsPromiseFulfilled());
+}
+
+// Create a module with an invalid global section.
+ZoneBuffer GetModuleWithInvalidSection(Zone* zone) {
+ ZoneBuffer buffer(zone);
+ TestSignatures sigs;
+ WasmModuleBuilder builder(zone);
+ // Add an invalid global to the module. The decoder will fail there.
+ builder.AddGlobal(kWasmStmt, false, true,
+ WasmInitExpr(WasmInitExpr::kGlobalIndex, 12));
+ {
+ WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii());
+ uint8_t code[] = {kExprGetLocal, 0, kExprEnd};
+ f->EmitCode(code, arraysize(code));
+ }
+ {
+ WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii());
+ uint8_t code[] = {kExprGetLocal, 1, kExprEnd};
+ f->EmitCode(code, arraysize(code));
+ }
+ {
+ WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii());
+ uint8_t code[] = {kExprGetLocal, 2, kExprEnd};
+ f->EmitCode(code, arraysize(code));
+ }
+ builder.WriteTo(buffer);
+ return buffer;
+}
+
+// Test an error in a section, found by the ModuleDecoder.
+STREAM_TEST(TestErrorInSectionStreamFinishesFirst) {
+ StreamTester tester;
+ ZoneBuffer buffer = GetModuleWithInvalidSection(tester.zone());
+
+ tester.OnBytesReceived(buffer.begin(), buffer.end() - buffer.begin());
+ tester.FinishStream();
+
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseRejected());
+}
+
+STREAM_TEST(TestErrorInSectionCompilerFinishesFirst) {
+ StreamTester tester;
+ ZoneBuffer buffer = GetModuleWithInvalidSection(tester.zone());
+
+ tester.OnBytesReceived(buffer.begin(), buffer.end() - buffer.begin());
+ tester.RunCompilerTasks();
+ tester.FinishStream();
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseRejected());
+}
+
+STREAM_TEST(TestErrorInSectionWithCuts) {
+ StreamTester tester;
+ ZoneBuffer buffer = GetModuleWithInvalidSection(tester.zone());
+
+ const uint8_t* current = buffer.begin();
+ size_t remaining = buffer.end() - buffer.begin();
+ while (current < buffer.end()) {
+ size_t size = std::min(remaining, size_t{10});
+ tester.OnBytesReceived(current, size);
+ tester.RunCompilerTasks();
+ current += 10;
+ remaining -= size;
+ }
+ tester.FinishStream();
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseRejected());
+}
+
+ZoneBuffer GetModuleWithInvalidSectionSize(Zone* zone) {
+ // We get a valid module and overwrite the size of the first section with an
+ // invalid value.
+ ZoneBuffer buffer = GetValidModuleBytes(zone);
+ // 9 == 4 (wasm magic) + 4 (version) + 1 (section code)
+ uint8_t* section_size_address = const_cast<uint8_t*>(buffer.begin()) + 9;
+ // 0x808080800f is an invalid module size in leb encoding.
+ section_size_address[0] = 0x80;
+ section_size_address[1] = 0x80;
+ section_size_address[2] = 0x80;
+ section_size_address[3] = 0x80;
+ section_size_address[4] = 0x0f;
+ return buffer;
+}
+
+STREAM_TEST(TestErrorInSectionSizeStreamFinishesFirst) {
+ StreamTester tester;
+ ZoneBuffer buffer = GetModuleWithInvalidSectionSize(tester.zone());
+ tester.OnBytesReceived(buffer.begin(), buffer.end() - buffer.begin());
+ tester.FinishStream();
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseRejected());
+}
+
+STREAM_TEST(TestErrorInSectionSizeCompilerFinishesFirst) {
+ StreamTester tester;
+ ZoneBuffer buffer = GetModuleWithInvalidSectionSize(tester.zone());
+ tester.OnBytesReceived(buffer.begin(), buffer.end() - buffer.begin());
+ tester.RunCompilerTasks();
+ tester.FinishStream();
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseRejected());
+}
+
+STREAM_TEST(TestErrorInSectionSizeWithCuts) {
+ StreamTester tester;
+ ZoneBuffer buffer = GetModuleWithInvalidSectionSize(tester.zone());
+ const uint8_t* current = buffer.begin();
+ size_t remaining = buffer.end() - buffer.begin();
+ while (current < buffer.end()) {
+ size_t size = std::min(remaining, size_t{10});
+ tester.OnBytesReceived(current, size);
+ tester.RunCompilerTasks();
+ current += 10;
+ remaining -= size;
+ }
+ tester.RunCompilerTasks();
+ tester.FinishStream();
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseRejected());
+}
+
+// Test an error in the code section, found by the ModuleDecoder. The error is a
+// functions count in the code section which differs from the functions count in
+// the function section.
+STREAM_TEST(TestErrorInCodeSectionDetectedByModuleDecoder) {
+ StreamTester tester;
+
+ uint8_t code[] = {
+ U32V_1(4), // body size
+ U32V_1(0), // locals count
+ kExprGetLocal, 0, kExprEnd // body
+ };
+
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(1 + arraysize(code) * 2), // section size
+ U32V_1(2), // !!! invalid function count !!!
+ };
+
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.FinishStream();
+
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseRejected());
+}
+
+// Test an error in the code section, found by the StreamingDecoder. The error
+// is an invalid function body size, so that there are not enough bytes in the
+// code section for the function body.
+STREAM_TEST(TestErrorInCodeSectionDetectedByStreamingDecoder) {
+ StreamTester tester;
+
+ uint8_t code[] = {
+ U32V_1(26), // !!! invalid body size !!!
+ U32V_1(0), // locals count
+ kExprGetLocal, 0, kExprEnd // body
+ };
+
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(1 + arraysize(code) * 3), // section size
+ U32V_1(3), // functions count
+ };
+
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.FinishStream();
+
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseRejected());
+}
+
+// Test an error in the code section, found by the Compiler. The error is an
+// invalid return type.
+STREAM_TEST(TestErrorInCodeSectionDetectedByCompiler) {
+ StreamTester tester;
+
+ uint8_t code[] = {
+ U32V_1(4), // !!! invalid body size !!!
+ U32V_1(0), // locals count
+ kExprGetLocal, 0, kExprEnd // body
+ };
+
+ uint8_t invalid_code[] = {
+ U32V_1(4), // !!! invalid body size !!!
+ U32V_1(0), // locals count
+ kExprI64Const, 0, kExprEnd // body
+ };
+
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(1 + arraysize(code) * 2 +
+ arraysize(invalid_code)), // section size
+ U32V_1(3), // functions count
+ };
+
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.RunCompilerTasks();
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.RunCompilerTasks();
+ tester.OnBytesReceived(invalid_code, arraysize(invalid_code));
+ tester.RunCompilerTasks();
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.RunCompilerTasks();
+ tester.FinishStream();
+ tester.RunCompilerTasks();
+
+ CHECK(tester.IsPromiseRejected());
+}
+
+// Test Abort before any bytes arrive.
+STREAM_TEST(TestAbortImmediately) {
+ StreamTester tester;
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+// Test Abort within a section.
+STREAM_TEST(TestAbortWithinSection1) {
+ StreamTester tester;
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1) // type count
+ // Type section is not yet complete.
+ };
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.RunCompilerTasks();
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+// Test Abort within a section.
+STREAM_TEST(TestAbortWithinSection2) {
+ StreamTester tester;
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ // Function section is not yet complete.
+ };
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.RunCompilerTasks();
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+// Test Abort just before the code section.
+STREAM_TEST(TestAbortAfterSection) {
+ StreamTester tester;
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ };
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.RunCompilerTasks();
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+// Test Abort after the function count in the code section. The compiler tasks
+// execute before the abort.
+STREAM_TEST(TestAbortAfterFunctionsCount1) {
+ StreamTester tester;
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(20), // section size
+ U32V_1(3), // functions count
+ };
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.RunCompilerTasks();
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+// Test Abort after the function count in the code section. The compiler tasks
+// do not execute before the abort.
+STREAM_TEST(TestAbortAfterFunctionsCount2) {
+ StreamTester tester;
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(20), // section size
+ U32V_1(3), // functions count
+ };
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+// Test Abort after some functions got compiled. The compiler tasks execute
+// before the abort.
+STREAM_TEST(TestAbortAfterFunctionGotCompiled1) {
+ StreamTester tester;
+
+ uint8_t code[] = {
+ U32V_1(4), // !!! invalid body size !!!
+ U32V_1(0), // locals count
+ kExprGetLocal, 0, kExprEnd // body
+ };
+
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(20), // section size
+ U32V_1(3), // functions count
+ };
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.RunCompilerTasks();
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+// Test Abort after some functions got compiled. The compiler tasks execute
+// before the abort.
+STREAM_TEST(TestAbortAfterFunctionGotCompiled2) {
+ StreamTester tester;
+
+ uint8_t code[] = {
+ U32V_1(4), // !!! invalid body size !!!
+ U32V_1(0), // locals count
+ kExprGetLocal, 0, kExprEnd // body
+ };
+
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(20), // section size
+ U32V_1(3), // functions count
+ };
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+// Test Abort after all functions got compiled.
+STREAM_TEST(TestAbortAfterCodeSection1) {
+ StreamTester tester;
+
+ uint8_t code[] = {
+ U32V_1(4), // body size
+ U32V_1(0), // locals count
+ kExprGetLocal, 0, kExprEnd // body
+ };
+
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(1 + arraysize(code) * 3), // section size
+ U32V_1(3), // functions count
+ };
+
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.RunCompilerTasks();
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+// Test Abort after all functions got compiled.
+STREAM_TEST(TestAbortAfterCodeSection2) {
+ StreamTester tester;
+
+ uint8_t code[] = {
+ U32V_1(4), // body size
+ U32V_1(0), // locals count
+ kExprGetLocal, 0, kExprEnd // body
+ };
+
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(1 + arraysize(code) * 3), // section size
+ U32V_1(3), // functions count
+ };
+
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+STREAM_TEST(TestAbortAfterCompilationError1) {
+ StreamTester tester;
+
+ uint8_t code[] = {
+ U32V_1(4), // !!! invalid body size !!!
+ U32V_1(0), // locals count
+ kExprGetLocal, 0, kExprEnd // body
+ };
+
+ uint8_t invalid_code[] = {
+ U32V_1(4), // !!! invalid body size !!!
+ U32V_1(0), // locals count
+ kExprI64Const, 0, kExprEnd // body
+ };
+
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(1 + arraysize(code) * 2 +
+ arraysize(invalid_code)), // section size
+ U32V_1(3), // functions count
+ };
+
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.OnBytesReceived(invalid_code, arraysize(invalid_code));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.RunCompilerTasks();
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+STREAM_TEST(TestAbortAfterCompilationError2) {
+ StreamTester tester;
+
+ uint8_t code[] = {
+ U32V_1(4), // !!! invalid body size !!!
+ U32V_1(0), // locals count
+ kExprGetLocal, 0, kExprEnd // body
+ };
+
+ uint8_t invalid_code[] = {
+ U32V_1(4), // !!! invalid body size !!!
+ U32V_1(0), // locals count
+ kExprI64Const, 0, kExprEnd // body
+ };
+
+ const uint8_t bytes[] = {
+ WASM_MODULE_HEADER, // module header
+ kTypeSectionCode, // section code
+ U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
+ U32V_1(1), // type count
+ SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
+ kFunctionSectionCode, // section code
+ U32V_1(1 + 3), // section size
+ U32V_1(3), // functions count
+ 0, // signature index
+ 0, // signature index
+ 0, // signature index
+ kCodeSectionCode, // section code
+ U32V_1(1 + arraysize(code) * 2 +
+ arraysize(invalid_code)), // section size
+ U32V_1(3), // functions count
+ };
+
+ tester.OnBytesReceived(bytes, arraysize(bytes));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.OnBytesReceived(invalid_code, arraysize(invalid_code));
+ tester.OnBytesReceived(code, arraysize(code));
+ tester.stream()->Abort();
+ tester.RunCompilerTasks();
+}
+
+#undef STREAM_TEST
+
+} // namespace wasm
+} // namespace internal
+} // namespace v8