diff options
Diffstat (limited to 'deps/v8/test/unittests/heap/off-thread-factory-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/heap/off-thread-factory-unittest.cc | 304 |
1 files changed, 247 insertions, 57 deletions
diff --git a/deps/v8/test/unittests/heap/off-thread-factory-unittest.cc b/deps/v8/test/unittests/heap/off-thread-factory-unittest.cc index 2c7bd639a8..0592d7b2db 100644 --- a/deps/v8/test/unittests/heap/off-thread-factory-unittest.cc +++ b/deps/v8/test/unittests/heap/off-thread-factory-unittest.cc @@ -8,65 +8,139 @@ #include <memory> #include "src/ast/ast-value-factory.h" +#include "src/ast/ast.h" +#include "src/ast/scopes.h" +#include "src/common/assert-scope.h" +#include "src/common/globals.h" +#include "src/execution/off-thread-isolate.h" #include "src/handles/handles-inl.h" #include "src/handles/handles.h" -#include "src/heap/off-thread-factory.h" +#include "src/heap/off-thread-factory-inl.h" #include "src/objects/fixed-array.h" +#include "src/objects/script.h" +#include "src/objects/shared-function-info.h" #include "src/objects/string.h" +#include "src/parsing/parse-info.h" +#include "src/parsing/parser.h" +#include "src/parsing/rewriter.h" +#include "src/parsing/scanner-character-streams.h" +#include "src/parsing/scanner.h" +#include "src/strings/unicode-inl.h" +#include "src/utils/utils.h" #include "test/unittests/test-utils.h" namespace v8 { namespace internal { +class OffThreadIsolate; + +namespace { + +std::vector<uint16_t> DecodeUtf8(const std::string& string) { + if (string.empty()) return {}; + + auto utf8_data = + Vector<const uint8_t>::cast(VectorOf(string.data(), string.length())); + Utf8Decoder decoder(utf8_data); + + std::vector<uint16_t> utf16(decoder.utf16_length()); + decoder.Decode(&utf16[0], utf8_data); + + return utf16; +} + +} // namespace + class OffThreadFactoryTest : public TestWithIsolateAndZone { public: OffThreadFactoryTest() - : TestWithIsolateAndZone(), off_thread_factory_(isolate()) {} + : TestWithIsolateAndZone(), + parse_info_(isolate()), + off_thread_isolate_(isolate(), parse_info_.zone()) {} + + FunctionLiteral* ParseProgram(const char* source) { + auto utf16_source = DecodeUtf8(source); - OffThreadFactory* off_thread_factory() { return &off_thread_factory_; } + // Normally this would be an external string or whatever, we don't have to + // worry about it for now. + source_string_ = + factory()->NewStringFromUtf8(CStrVector(source)).ToHandleChecked(); + + parse_info_.set_character_stream( + ScannerStream::ForTesting(utf16_source.data(), utf16_source.size())); + parse_info_.set_toplevel(); + parse_info_.set_allow_lazy_parsing(); + + { + DisallowHeapAllocation no_allocation; + DisallowHandleAllocation no_handles; + DisallowHeapAccess no_heap_access; + + Parser parser(parse_info()); + parser.InitializeEmptyScopeChain(parse_info()); + parser.ParseOnBackground(parse_info()); + + CHECK(DeclarationScope::Analyze(parse_info())); + } + + parse_info()->ast_value_factory()->Internalize(off_thread_isolate()); + DeclarationScope::AllocateScopeInfos(parse_info(), off_thread_isolate()); + + script_ = parse_info_.CreateScript(off_thread_isolate(), + off_thread_factory()->empty_string(), + ScriptOriginOptions()); + + // Create the SFI list on the script so that SFI SetScript works. + Handle<WeakFixedArray> infos = off_thread_factory()->NewWeakFixedArray( + parse_info()->max_function_literal_id() + 1, AllocationType::kOld); + script_->set_shared_function_infos(*infos); + + return parse_info()->literal(); + } + + ParseInfo* parse_info() { return &parse_info_; } + + Handle<Script> script() { return script_; } + + OffThreadIsolate* off_thread_isolate() { return &off_thread_isolate_; } + OffThreadFactory* off_thread_factory() { + return off_thread_isolate()->factory(); + } // We only internalize strings which are referred to in other slots, so create // a wrapper pointing at the off_thread_string. - OffThreadHandle<FixedArray> WrapString(OffThreadHandle<String> string) { + Handle<FixedArray> WrapString(Handle<String> string) { // TODO(leszeks): Replace with a different factory method (e.g. FixedArray) // once OffThreadFactory supports it. return off_thread_factory()->StringWrapperForTest(string); } private: - OffThreadFactory off_thread_factory_; + ParseInfo parse_info_; + OffThreadIsolate off_thread_isolate_; + Handle<String> source_string_; + Handle<Script> script_; }; -TEST_F(OffThreadFactoryTest, HandleOrOffThreadHandle_IsNullWhenConstructed) { - // Default constructed HandleOrOffThreadHandles should be considered both null - // and uninitialized. - EXPECT_TRUE(HandleOrOffThreadHandle<HeapObject>().is_null()); -#ifdef DEBUG - EXPECT_TRUE(!HandleOrOffThreadHandle<HeapObject>().is_initialized()); -#endif - - // Default constructed HandleOrOffThreadHandles should work as both null - // handles and null off-thread handles. - EXPECT_TRUE(HandleOrOffThreadHandle<HeapObject>().get<Factory>().is_null()); - EXPECT_TRUE( - HandleOrOffThreadHandle<HeapObject>().get<OffThreadFactory>().is_null()); -} - TEST_F(OffThreadFactoryTest, OneByteInternalizedString_IsAddedToStringTable) { Vector<const uint8_t> string_vector = StaticCharVector("foo"); uint32_t hash_field = StringHasher::HashSequentialString<uint8_t>( string_vector.begin(), string_vector.length(), HashSeed(isolate())); - OffThreadHandle<String> off_thread_string = - off_thread_factory()->NewOneByteInternalizedString(string_vector, - hash_field); + FixedArray off_thread_wrapper; + { + OffThreadHandleScope handle_scope(off_thread_isolate()); - OffThreadHandle<FixedArray> off_thread_wrapper = - off_thread_factory()->StringWrapperForTest(off_thread_string); + Handle<String> off_thread_string = + off_thread_factory()->NewOneByteInternalizedString(string_vector, + hash_field); - off_thread_factory()->FinishOffThread(); + off_thread_wrapper = + *off_thread_factory()->StringWrapperForTest(off_thread_string); + off_thread_factory()->FinishOffThread(); + } - Handle<FixedArray> wrapper = handle(*off_thread_wrapper, isolate()); + Handle<FixedArray> wrapper = handle(off_thread_wrapper, isolate()); off_thread_factory()->Publish(isolate()); Handle<String> string = handle(String::cast(wrapper->get(0)), isolate()); @@ -92,22 +166,25 @@ TEST_F(OffThreadFactoryTest, uint32_t hash_field = StringHasher::HashSequentialString<uint8_t>( string_vector.begin(), string_vector.length(), HashSeed(isolate())); - OffThreadHandle<String> off_thread_string_1 = - off_thread_factory()->NewOneByteInternalizedString(string_vector, - hash_field); - OffThreadHandle<String> off_thread_string_2 = - off_thread_factory()->NewOneByteInternalizedString(string_vector, - hash_field); - - OffThreadHandle<FixedArray> off_thread_wrapper_1 = - WrapString(off_thread_string_1); - OffThreadHandle<FixedArray> off_thread_wrapper_2 = - WrapString(off_thread_string_2); - - off_thread_factory()->FinishOffThread(); + FixedArray off_thread_wrapper_1; + FixedArray off_thread_wrapper_2; + { + OffThreadHandleScope handle_scope(off_thread_isolate()); + + Handle<String> off_thread_string_1 = + off_thread_factory()->NewOneByteInternalizedString(string_vector, + hash_field); + Handle<String> off_thread_string_2 = + off_thread_factory()->NewOneByteInternalizedString(string_vector, + hash_field); + + off_thread_wrapper_1 = *WrapString(off_thread_string_1); + off_thread_wrapper_2 = *WrapString(off_thread_string_2); + off_thread_factory()->FinishOffThread(); + } - Handle<FixedArray> wrapper_1 = handle(*off_thread_wrapper_1, isolate()); - Handle<FixedArray> wrapper_2 = handle(*off_thread_wrapper_2, isolate()); + Handle<FixedArray> wrapper_1 = handle(off_thread_wrapper_1, isolate()); + Handle<FixedArray> wrapper_2 = handle(off_thread_wrapper_2, isolate()); off_thread_factory()->Publish(isolate()); Handle<String> string_1 = handle(String::cast(wrapper_1->get(0)), isolate()); @@ -124,14 +201,17 @@ TEST_F(OffThreadFactoryTest, AstRawString_IsInternalized) { const AstRawString* raw_string = ast_value_factory.GetOneByteString("foo"); - ast_value_factory.Internalize(off_thread_factory()); + FixedArray off_thread_wrapper; + { + OffThreadHandleScope handle_scope(off_thread_isolate()); - OffThreadHandle<FixedArray> off_thread_wrapper = - WrapString(raw_string->string().get<OffThreadFactory>()); + ast_value_factory.Internalize(off_thread_isolate()); - off_thread_factory()->FinishOffThread(); + off_thread_wrapper = *WrapString(raw_string->string()); + off_thread_factory()->FinishOffThread(); + } - Handle<FixedArray> wrapper = handle(*off_thread_wrapper, isolate()); + Handle<FixedArray> wrapper = handle(off_thread_wrapper, isolate()); off_thread_factory()->Publish(isolate()); Handle<String> string = handle(String::cast(wrapper->get(0)), isolate()); @@ -144,20 +224,24 @@ TEST_F(OffThreadFactoryTest, AstConsString_CreatesConsString) { AstValueFactory ast_value_factory(zone(), isolate()->ast_string_constants(), HashSeed(isolate())); - const AstRawString* foo_string = ast_value_factory.GetOneByteString("foo"); - const AstRawString* bar_string = - ast_value_factory.GetOneByteString("bar-plus-padding-for-length"); - const AstConsString* foobar_string = - ast_value_factory.NewConsString(foo_string, bar_string); + FixedArray off_thread_wrapper; + { + OffThreadHandleScope handle_scope(off_thread_isolate()); - ast_value_factory.Internalize(off_thread_factory()); + const AstRawString* foo_string = ast_value_factory.GetOneByteString("foo"); + const AstRawString* bar_string = + ast_value_factory.GetOneByteString("bar-plus-padding-for-length"); + AstConsString* foobar_string = + ast_value_factory.NewConsString(foo_string, bar_string); - OffThreadHandle<FixedArray> off_thread_wrapper = - WrapString(foobar_string->string().get<OffThreadFactory>()); + ast_value_factory.Internalize(off_thread_isolate()); - off_thread_factory()->FinishOffThread(); + off_thread_wrapper = + *WrapString(foobar_string->GetString(off_thread_isolate())); + off_thread_factory()->FinishOffThread(); + } - Handle<FixedArray> wrapper = handle(*off_thread_wrapper, isolate()); + Handle<FixedArray> wrapper = handle(off_thread_wrapper, isolate()); off_thread_factory()->Publish(isolate()); Handle<String> string = handle(String::cast(wrapper->get(0)), isolate()); @@ -167,5 +251,111 @@ TEST_F(OffThreadFactoryTest, AstConsString_CreatesConsString) { "foobar-plus-padding-for-length"))); } +TEST_F(OffThreadFactoryTest, EmptyScript) { + FunctionLiteral* program = ParseProgram(""); + + SharedFunctionInfo shared; + { + OffThreadHandleScope handle_scope(off_thread_isolate()); + + shared = *off_thread_factory()->NewSharedFunctionInfoForLiteral( + program, script(), true); + + off_thread_factory()->FinishOffThread(); + } + + Handle<SharedFunctionInfo> root_sfi = handle(shared, isolate()); + off_thread_factory()->Publish(isolate()); + + EXPECT_EQ(root_sfi->function_literal_id(), 0); +} + +TEST_F(OffThreadFactoryTest, LazyFunction) { + FunctionLiteral* program = ParseProgram("function lazy() {}"); + FunctionLiteral* lazy = program->scope() + ->declarations() + ->AtForTest(0) + ->AsFunctionDeclaration() + ->fun(); + + SharedFunctionInfo shared; + { + OffThreadHandleScope handle_scope(off_thread_isolate()); + + shared = *off_thread_factory()->NewSharedFunctionInfoForLiteral( + lazy, script(), true); + + off_thread_factory()->FinishOffThread(); + } + + Handle<SharedFunctionInfo> lazy_sfi = handle(shared, isolate()); + off_thread_factory()->Publish(isolate()); + + EXPECT_EQ(lazy_sfi->function_literal_id(), 1); + EXPECT_TRUE(lazy_sfi->Name().IsOneByteEqualTo(CStrVector("lazy"))); + EXPECT_FALSE(lazy_sfi->is_compiled()); + EXPECT_TRUE(lazy_sfi->HasUncompiledDataWithoutPreparseData()); +} + +TEST_F(OffThreadFactoryTest, EagerFunction) { + FunctionLiteral* program = ParseProgram("(function eager() {})"); + FunctionLiteral* eager = program->body() + ->at(0) + ->AsExpressionStatement() + ->expression() + ->AsFunctionLiteral(); + + SharedFunctionInfo shared; + { + OffThreadHandleScope handle_scope(off_thread_isolate()); + + shared = *off_thread_factory()->NewSharedFunctionInfoForLiteral( + eager, script(), true); + + off_thread_factory()->FinishOffThread(); + } + + Handle<SharedFunctionInfo> eager_sfi = handle(shared, isolate()); + off_thread_factory()->Publish(isolate()); + + EXPECT_EQ(eager_sfi->function_literal_id(), 1); + EXPECT_TRUE(eager_sfi->Name().IsOneByteEqualTo(CStrVector("eager"))); + EXPECT_FALSE(eager_sfi->HasUncompiledData()); + // TODO(leszeks): Allocate bytecode and enable these checks. + // EXPECT_TRUE(eager_sfi->is_compiled()); + // EXPECT_TRUE(eager_sfi->HasBytecodeArray()); +} + +TEST_F(OffThreadFactoryTest, ImplicitNameFunction) { + FunctionLiteral* program = ParseProgram("let implicit_name = function() {}"); + FunctionLiteral* implicit_name = program->body() + ->at(0) + ->AsBlock() + ->statements() + ->at(0) + ->AsExpressionStatement() + ->expression() + ->AsAssignment() + ->value() + ->AsFunctionLiteral(); + + SharedFunctionInfo shared; + { + OffThreadHandleScope handle_scope(off_thread_isolate()); + + shared = *off_thread_factory()->NewSharedFunctionInfoForLiteral( + implicit_name, script(), true); + + off_thread_factory()->FinishOffThread(); + } + + Handle<SharedFunctionInfo> implicit_name_sfi = handle(shared, isolate()); + off_thread_factory()->Publish(isolate()); + + EXPECT_EQ(implicit_name_sfi->function_literal_id(), 1); + EXPECT_TRUE( + implicit_name_sfi->Name().IsOneByteEqualTo(CStrVector("implicit_name"))); +} + } // namespace internal } // namespace v8 |