From 735f3a689b31b37145f5160f5b33095b544afd00 Mon Sep 17 00:00:00 2001 From: Dan Elphick Date: Fri, 23 Aug 2019 13:11:12 +0100 Subject: [PATCH] [compiler] Skip creating unneeded objects for lazy source positions This changes Compiler::CollectSourcePositions to skip finalization of the BytecodeArray, constant table, handler table, ScopeInfos as well as internalization of Ast values since only the source position table is used and the others will be collected soon after by the GC. It will also now avoid recompiling inner functions that would otherwise be eagerly compiled. BytecodeArrayWriter::ToBytecodeArray has been changed to never populate the source_position_table. Bug: v8:8510 Change-Id: I2db2f2da6b48fde11f17a20d017c1a54c0a34fc2 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1763538 Commit-Queue: Dan Elphick Reviewed-by: Ross McIlroy Cr-Commit-Position: refs/heads/master@{#63365} --- src/codegen/compiler.cc | 74 ++++++++----------- src/interpreter/bytecode-array-builder.cc | 17 ++++- src/interpreter/bytecode-array-builder.h | 6 ++ src/interpreter/bytecode-array-writer.cc | 32 +++++--- src/interpreter/bytecode-array-writer.h | 6 ++ src/interpreter/bytecode-generator.cc | 28 ++++++- src/interpreter/bytecode-generator.h | 2 + src/interpreter/interpreter.cc | 29 ++++++-- src/interpreter/interpreter.h | 11 ++- src/objects/code.cc | 10 --- src/objects/code.h | 3 - .../bytecode-array-writer-unittest.cc | 8 ++ 12 files changed, 149 insertions(+), 77 deletions(-) diff --git a/src/codegen/compiler.cc b/src/codegen/compiler.cc index c39201d7b0..7bc01a0e51 100644 --- a/src/codegen/compiler.cc +++ b/src/codegen/compiler.cc @@ -535,20 +535,16 @@ std::unique_ptr GenerateUnoptimizedCode( DisallowHeapAccess no_heap_access; DCHECK(inner_function_jobs->empty()); - if (!Compiler::Analyze(parse_info)) { - return std::unique_ptr(); + std::unique_ptr job; + if (Compiler::Analyze(parse_info)) { + job = ExecuteUnoptimizedCompileJobs(parse_info, parse_info->literal(), + allocator, inner_function_jobs); } - // Prepare and execute compilation of the outer-most function. - std::unique_ptr outer_function_job( - ExecuteUnoptimizedCompileJobs(parse_info, parse_info->literal(), - allocator, inner_function_jobs)); - if (!outer_function_job) return std::unique_ptr(); - // Character stream shouldn't be used again. parse_info->ResetCharacterStream(); - return outer_function_job; + return job; } MaybeHandle GenerateUnoptimizedCodeForToplevel( @@ -1234,51 +1230,41 @@ bool Compiler::CollectSourcePositions(Isolate* isolate, isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION); } + // Character stream shouldn't be used again. + parse_info.ResetCharacterStream(); + // Generate the unoptimized bytecode. // TODO(v8:8510): Consider forcing preparsing of inner functions to avoid // wasting time fully parsing them when they won't ever be used. - UnoptimizedCompilationJobList inner_function_jobs; - std::unique_ptr outer_function_job( - GenerateUnoptimizedCode(&parse_info, isolate->allocator(), - &inner_function_jobs)); - if (!outer_function_job) { - // Recompiling failed probably as a result of stack exhaustion. - bytecode->SetSourcePositionsFailedToCollect(); - return FailWithPendingException( - isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION); - } - - DCHECK(outer_function_job->compilation_info()->collect_source_positions()); - - // TODO(v8:8510) Avoid re-allocating bytecode array/constant pool and - // re-internalizeing the ast values. Maybe we could use the - // unoptimized_compilation_flag to signal that all we need is the source - // position table (and we could do the DCHECK that the bytecode array is the - // same in the bytecode-generator, by comparing the real bytecode array on the - // SFI with the off-heap bytecode array). - - // Internalize ast values onto the heap. - parse_info.ast_value_factory()->Internalize(isolate); - + std::unique_ptr job; { - // Allocate scope infos for the literal. - DeclarationScope::AllocateScopeInfos(&parse_info, isolate); - CHECK_EQ(outer_function_job->FinalizeJob(shared_info, isolate), - CompilationJob::SUCCEEDED); + if (!Compiler::Analyze(&parse_info)) { + // Recompiling failed probably as a result of stack exhaustion. + bytecode->SetSourcePositionsFailedToCollect(); + return FailWithPendingException( + isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION); + } + + job = interpreter::Interpreter::NewSourcePositionCollectionJob( + &parse_info, parse_info.literal(), bytecode, isolate->allocator()); + + if (!job || job->ExecuteJob() != CompilationJob::SUCCEEDED || + job->FinalizeJob(shared_info, isolate) != CompilationJob::SUCCEEDED) { + // Recompiling failed probably as a result of stack exhaustion. + bytecode->SetSourcePositionsFailedToCollect(); + return FailWithPendingException( + isolate, &parse_info, Compiler::ClearExceptionFlag::CLEAR_EXCEPTION); + } } - // Update the source position table on the original bytecode. - DCHECK(bytecode->IsBytecodeEqual( - *outer_function_job->compilation_info()->bytecode_array())); - DCHECK(outer_function_job->compilation_info()->has_bytecode_array()); - ByteArray source_position_table = outer_function_job->compilation_info() - ->bytecode_array() - ->SourcePositionTable(); - bytecode->set_source_position_table(source_position_table); + DCHECK(job->compilation_info()->collect_source_positions()); + // If debugging, make sure that instrumented bytecode has the source position // table set on it as well. if (shared_info->HasDebugInfo() && shared_info->GetDebugInfo().HasInstrumentedBytecodeArray()) { + ByteArray source_position_table = + job->compilation_info()->bytecode_array()->SourcePositionTable(); shared_info->GetDebugBytecodeArray().set_source_position_table( source_position_table); } diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc index c8b2a1d57b..e25838fafc 100644 --- a/src/interpreter/bytecode-array-builder.cc +++ b/src/interpreter/bytecode-array-builder.cc @@ -23,7 +23,8 @@ class RegisterTransferWriter final : public NON_EXPORTED_BASE(BytecodeRegisterOptimizer::BytecodeWriter), public NON_EXPORTED_BASE(ZoneObject) { public: - RegisterTransferWriter(BytecodeArrayBuilder* builder) : builder_(builder) {} + explicit RegisterTransferWriter(BytecodeArrayBuilder* builder) + : builder_(builder) {} ~RegisterTransferWriter() override = default; void EmitLdar(Register input) override { builder_->OutputLdarRaw(input); } @@ -98,6 +99,20 @@ Handle BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) { isolate, register_count, parameter_count(), handler_table); } +#ifdef DEBUG +void BytecodeArrayBuilder::CheckBytecodeMatches( + Handle bytecode) { + bytecode_array_writer_.CheckBytecodeMatches(bytecode); +} +#endif + +Handle BytecodeArrayBuilder::ToSourcePositionTable( + Isolate* isolate) { + DCHECK(RemainderOfBlockIsDead()); + + return bytecode_array_writer_.ToSourcePositionTable(isolate); +} + BytecodeSourceInfo BytecodeArrayBuilder::CurrentSourcePosition( Bytecode bytecode) { BytecodeSourceInfo source_position; diff --git a/src/interpreter/bytecode-array-builder.h b/src/interpreter/bytecode-array-builder.h index 7773545800..e648ae3d49 100644 --- a/src/interpreter/bytecode-array-builder.h +++ b/src/interpreter/bytecode-array-builder.h @@ -21,6 +21,7 @@ namespace v8 { namespace internal { +class BytecodeArray; class FeedbackVectorSpec; class Isolate; @@ -42,6 +43,11 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final { SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS); Handle ToBytecodeArray(Isolate* isolate); + Handle ToSourcePositionTable(Isolate* isolate); + +#ifdef DEBUG + void CheckBytecodeMatches(Handle bytecode); +#endif // Get the number of parameters expected by function. int parameter_count() const { diff --git a/src/interpreter/bytecode-array-writer.cc b/src/interpreter/bytecode-array-writer.cc index 0d1ce5df86..e6a9d99dfa 100644 --- a/src/interpreter/bytecode-array-writer.cc +++ b/src/interpreter/bytecode-array-writer.cc @@ -12,7 +12,6 @@ #include "src/interpreter/bytecode-source-info.h" #include "src/interpreter/constant-array-builder.h" #include "src/interpreter/handler-table-builder.h" -#include "src/logging/log.h" #include "src/objects/objects-inl.h" namespace v8 { @@ -50,19 +49,30 @@ Handle BytecodeArrayWriter::ToBytecodeArray( bytecode_size, &bytecodes()->front(), frame_size, parameter_count, constant_pool); bytecode_array->set_handler_table(*handler_table); - if (!source_position_table_builder_.Lazy()) { - Handle source_position_table = - source_position_table_builder_.Omit() - ? ReadOnlyRoots(isolate).empty_byte_array_handle() - : source_position_table_builder()->ToSourcePositionTable(isolate); - bytecode_array->set_source_position_table(*source_position_table); - LOG_CODE_EVENT(isolate, CodeLinePosInfoRecordEvent( - bytecode_array->GetFirstBytecodeAddress(), - *source_position_table)); - } return bytecode_array; } +Handle BytecodeArrayWriter::ToSourcePositionTable(Isolate* isolate) { + DCHECK(!source_position_table_builder_.Lazy()); + Handle source_position_table = + source_position_table_builder_.Omit() + ? ReadOnlyRoots(isolate).empty_byte_array_handle() + : source_position_table_builder_.ToSourcePositionTable(isolate); + return source_position_table; +} + +#ifdef DEBUG +void BytecodeArrayWriter::CheckBytecodeMatches(Handle bytecode) { + int bytecode_size = static_cast(bytecodes()->size()); + const byte* bytecode_ptr = &bytecodes()->front(); + CHECK_EQ(bytecode_size, bytecode->length()); + + for (int i = 0; i < bytecode_size; ++i) { + CHECK_EQ(bytecode_ptr[i], bytecode->get(i)); + } +} +#endif + void BytecodeArrayWriter::Write(BytecodeNode* node) { DCHECK(!Bytecodes::IsJump(node->bytecode())); diff --git a/src/interpreter/bytecode-array-writer.h b/src/interpreter/bytecode-array-writer.h index 5dac1b41c3..dc1a11086a 100644 --- a/src/interpreter/bytecode-array-writer.h +++ b/src/interpreter/bytecode-array-writer.h @@ -55,6 +55,12 @@ class V8_EXPORT_PRIVATE BytecodeArrayWriter final { int parameter_count, Handle handler_table); + Handle ToSourcePositionTable(Isolate* isolate); + +#ifdef DEBUG + void CheckBytecodeMatches(Handle bytecode); +#endif + bool RemainderOfBlockIsDead() const { return exit_seen_in_block_; } private: diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc index 1865f37dc9..e19528c275 100644 --- a/src/interpreter/bytecode-generator.cc +++ b/src/interpreter/bytecode-generator.cc @@ -15,6 +15,7 @@ #include "src/interpreter/bytecode-label.h" #include "src/interpreter/bytecode-register-allocator.h" #include "src/interpreter/control-flow-builders.h" +#include "src/logging/log.h" #include "src/objects/debug-objects.h" #include "src/objects/literal-objects-inl.h" #include "src/objects/objects-inl.h" @@ -1065,6 +1066,28 @@ Handle BytecodeGenerator::FinalizeBytecode( return bytecode_array; } +Handle BytecodeGenerator::FinalizeSourcePositionTable( + Isolate* isolate) { + DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); +#ifdef DEBUG + // Unoptimized compilation should be context-independent. Verify that we don't + // access the native context by nulling it out during finalization. + NullContextScope null_context_scope(isolate); + + builder()->CheckBytecodeMatches(info_->bytecode_array()); +#endif + + Handle source_position_table = + builder()->ToSourcePositionTable(isolate); + + LOG_CODE_EVENT(isolate, + CodeLinePosInfoRecordEvent( + info_->bytecode_array()->GetFirstBytecodeAddress(), + *source_position_table)); + + return source_position_table; +} + void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate, Handle