diff options
author | Refael Ackermann <refack@gmail.com> | 2019-05-28 08:46:21 -0400 |
---|---|---|
committer | Refael Ackermann <refack@gmail.com> | 2019-06-01 09:55:12 -0400 |
commit | ed74896b1fae1c163b3906163f3bf46326618ddb (patch) | |
tree | 7fb05c5a19808e0c5cd95837528e9005999cf540 /deps/v8/src/snapshot | |
parent | 2a850cd0664a4eee51f44d0bb8c2f7a3fe444154 (diff) | |
download | node-new-ed74896b1fae1c163b3906163f3bf46326618ddb.tar.gz |
deps: update V8 to 7.5.288.22
PR-URL: https://github.com/nodejs/node/pull/27375
Reviewed-By: Michaƫl Zasso <targos@protonmail.com>
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'deps/v8/src/snapshot')
21 files changed, 435 insertions, 92 deletions
diff --git a/deps/v8/src/snapshot/code-serializer.cc b/deps/v8/src/snapshot/code-serializer.cc index 47aa104bae..4743138ae5 100644 --- a/deps/v8/src/snapshot/code-serializer.cc +++ b/deps/v8/src/snapshot/code-serializer.cc @@ -245,7 +245,7 @@ void CreateInterpreterDataForDeserializedCode(Isolate* isolate, Handle<InterpreterData> interpreter_data = Handle<InterpreterData>::cast(isolate->factory()->NewStruct( - INTERPRETER_DATA_TYPE, TENURED)); + INTERPRETER_DATA_TYPE, AllocationType::kOld)); interpreter_data->set_bytecode_array(info->GetBytecodeArray()); interpreter_data->set_interpreter_trampoline(*code); @@ -319,12 +319,11 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( Script script = Script::cast(result->script()); Handle<Script> script_handle(script, isolate); if (script->name()->IsString()) name = String::cast(script->name()); - Handle<String> name_handle(name, isolate); if (FLAG_log_function_events) { - LOG(isolate, FunctionEvent("deserialize", script->id(), - timer.Elapsed().InMillisecondsF(), - result->StartPosition(), result->EndPosition(), - *name_handle)); + LOG(isolate, + FunctionEvent("deserialize", script->id(), + timer.Elapsed().InMillisecondsF(), + result->StartPosition(), result->EndPosition(), name)); } if (log_code_creation) { Script::InitLineEnds(Handle<Script>(script, isolate)); @@ -336,8 +335,8 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( int line_num = script->GetLineNumber(info->StartPosition()) + 1; int column_num = script->GetColumnNumber(info->StartPosition()) + 1; PROFILE(isolate, CodeCreateEvent(CodeEventListener::SCRIPT_TAG, - info->abstract_code(), info, - *name_handle, line_num, column_num)); + info->abstract_code(), info, name, + line_num, column_num)); } } } diff --git a/deps/v8/src/snapshot/code-serializer.h b/deps/v8/src/snapshot/code-serializer.h index 720995f163..78b1cdc77c 100644 --- a/deps/v8/src/snapshot/code-serializer.h +++ b/deps/v8/src/snapshot/code-serializer.h @@ -5,12 +5,13 @@ #ifndef V8_SNAPSHOT_CODE_SERIALIZER_H_ #define V8_SNAPSHOT_CODE_SERIALIZER_H_ +#include "src/base/macros.h" #include "src/snapshot/serializer.h" namespace v8 { namespace internal { -class ScriptData { +class V8_EXPORT_PRIVATE ScriptData { public: ScriptData(const byte* data, int length); ~ScriptData() { @@ -44,7 +45,8 @@ class ScriptData { class CodeSerializer : public Serializer { public: - static ScriptCompiler::CachedData* Serialize(Handle<SharedFunctionInfo> info); + V8_EXPORT_PRIVATE static ScriptCompiler::CachedData* Serialize( + Handle<SharedFunctionInfo> info); ScriptData* SerializeSharedFunctionInfo(Handle<SharedFunctionInfo> info); diff --git a/deps/v8/src/snapshot/deserializer-allocator.h b/deps/v8/src/snapshot/deserializer-allocator.h index b44248aff1..56bd4d1b0e 100644 --- a/deps/v8/src/snapshot/deserializer-allocator.h +++ b/deps/v8/src/snapshot/deserializer-allocator.h @@ -57,7 +57,8 @@ class DeserializerAllocator final { // ------- Reservation Methods ------- // Methods related to memory reservations (prior to deserialization). - void DecodeReservation(const std::vector<SerializedData::Reservation>& res); + V8_EXPORT_PRIVATE void DecodeReservation( + const std::vector<SerializedData::Reservation>& res); bool ReserveSpace(); bool ReservationsAreFullyUsed() const; diff --git a/deps/v8/src/snapshot/deserializer.cc b/deps/v8/src/snapshot/deserializer.cc index 2569ca18c4..3759c53c21 100644 --- a/deps/v8/src/snapshot/deserializer.cc +++ b/deps/v8/src/snapshot/deserializer.cc @@ -24,6 +24,8 @@ #include "src/roots.h" #include "src/snapshot/natives.h" #include "src/snapshot/snapshot.h" +#include "src/tracing/trace-event.h" +#include "src/tracing/traced-value.h" namespace v8 { namespace internal { @@ -48,14 +50,18 @@ void Deserializer::Initialize(Isolate* isolate) { DCHECK_NOT_NULL(isolate); isolate_ = isolate; allocator()->Initialize(isolate->heap()); - DCHECK_NULL(external_reference_table_); - external_reference_table_ = isolate->external_reference_table(); + #ifdef DEBUG - // Count the number of external references registered through the API. - num_api_references_ = 0; - if (isolate_->api_external_references() != nullptr) { - while (isolate_->api_external_references()[num_api_references_] != 0) { - num_api_references_++; + // The read-only deserializer is run by read-only heap set-up before the heap + // is fully set up. External reference table relies on a few parts of this + // set-up (like old-space), so it may be uninitialized at this point. + if (isolate->isolate_data()->external_reference_table()->is_initialized()) { + // Count the number of external references registered through the API. + num_api_references_ = 0; + if (isolate_->api_external_references() != nullptr) { + while (isolate_->api_external_references()[num_api_references_] != 0) { + num_api_references_++; + } } } #endif // DEBUG @@ -64,8 +70,9 @@ void Deserializer::Initialize(Isolate* isolate) { void Deserializer::Rehash() { DCHECK(can_rehash() || deserializing_user_code()); - for (HeapObject item : to_rehash_) - item->RehashBasedOnMap(ReadOnlyRoots(isolate())); + for (HeapObject item : to_rehash_) { + item->RehashBasedOnMap(ReadOnlyRoots(isolate_)); + } } Deserializer::~Deserializer() { @@ -149,6 +156,13 @@ void Deserializer::LogScriptEvents(Script script) { LOG(isolate_, ScriptEvent(Logger::ScriptEventType::kDeserialize, script->id())); LOG(isolate_, ScriptDetails(script)); + TRACE_EVENT_OBJECT_CREATED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("v8.compile"), "Script", + TRACE_ID_WITH_SCOPE("v8::internal::Script", script->id())); + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("v8.compile"), "Script", + TRACE_ID_WITH_SCOPE("v8::internal::Script", script->id()), + script->ToTracedValue()); } StringTableInsertionKey::StringTableInsertionKey(String string) @@ -180,6 +194,11 @@ HeapObject Deserializer::PostProcessNewObject(HeapObject obj, int space) { // Uninitialize hash field as we need to recompute the hash. String string = String::cast(obj); string->set_hash_field(String::kEmptyHashField); + // Rehash strings before read-only space is sealed. Strings outside + // read-only space are rehashed lazily. (e.g. when rehashing dictionaries) + if (space == RO_SPACE) { + to_rehash_.push_back(obj); + } } else if (obj->NeedsRehashing()) { to_rehash_.push_back(obj); } @@ -287,8 +306,6 @@ HeapObject Deserializer::PostProcessNewObject(HeapObject obj, int space) { // TODO(mythria): Remove these once we store the default values for these // fields in the serializer. BytecodeArray bytecode_array = BytecodeArray::cast(obj); - bytecode_array->set_interrupt_budget( - interpreter::Interpreter::InterruptBudget()); bytecode_array->set_osr_loop_nesting_level(0); } #ifdef DEBUG @@ -765,7 +782,7 @@ bool Deserializer::ReadData(TSlot current, TSlot limit, int source_space, Address Deserializer::ReadExternalReferenceCase() { uint32_t reference_id = static_cast<uint32_t>(source_.GetInt()); - return external_reference_table_->address(reference_id); + return isolate_->external_reference_table()->address(reference_id); } template <typename TSlot, SerializerDeserializer::Bytecode bytecode, diff --git a/deps/v8/src/snapshot/deserializer.h b/deps/v8/src/snapshot/deserializer.h index c4e6d216d7..86536ca81c 100644 --- a/deps/v8/src/snapshot/deserializer.h +++ b/deps/v8/src/snapshot/deserializer.h @@ -34,7 +34,7 @@ class Object; #endif // A Deserializer reads a snapshot and reconstructs the Object graph it defines. -class Deserializer : public SerializerDeserializer { +class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer { public: ~Deserializer() override; @@ -47,7 +47,6 @@ class Deserializer : public SerializerDeserializer { : isolate_(nullptr), source_(data->Payload()), magic_number_(data->GetMagicNumber()), - external_reference_table_(nullptr), deserializing_user_code_(deserializing_user_code), can_rehash_(false) { allocator()->DecodeReservation(data->Reservations()); @@ -160,8 +159,6 @@ class Deserializer : public SerializerDeserializer { SnapshotByteSource source_; uint32_t magic_number_; - ExternalReferenceTable* external_reference_table_; - std::vector<Map> new_maps_; std::vector<AllocationSite> new_allocation_sites_; std::vector<Code> new_code_objects_; diff --git a/deps/v8/src/snapshot/embedded-file-writer.cc b/deps/v8/src/snapshot/embedded-file-writer.cc index 38073ec012..191ebf7b7c 100644 --- a/deps/v8/src/snapshot/embedded-file-writer.cc +++ b/deps/v8/src/snapshot/embedded-file-writer.cc @@ -41,7 +41,7 @@ namespace internal { // Name mangling. // Symbols are prefixed with an underscore on 32-bit architectures. -#if defined(V8_OS_WIN) && !defined(V8_TARGET_ARCH_X64) && \ +#if defined(V8_TARGET_OS_WIN) && !defined(V8_TARGET_ARCH_X64) && \ !defined(V8_TARGET_ARCH_ARM64) #define SYMBOL_PREFIX "_" #else @@ -65,7 +65,7 @@ DataDirective PointerSizeDirective() { } // namespace const char* DirectiveAsString(DataDirective directive) { -#if defined(V8_OS_WIN) && defined(V8_ASSEMBLER_IS_MASM) +#if defined(V8_TARGET_OS_WIN) && defined(V8_ASSEMBLER_IS_MASM) switch (directive) { case kByte: return "BYTE"; @@ -76,7 +76,7 @@ const char* DirectiveAsString(DataDirective directive) { default: UNREACHABLE(); } -#elif defined(V8_OS_WIN) && defined(V8_ASSEMBLER_IS_MARMASM) +#elif defined(V8_TARGET_OS_WIN) && defined(V8_ASSEMBLER_IS_MARMASM) switch (directive) { case kByte: return "DCB"; @@ -127,6 +127,119 @@ void EmbeddedFileWriter::PrepareBuiltinSourcePositionMap(Builtins* builtins) { } } +#if defined(V8_OS_WIN_X64) +std::string EmbeddedFileWriter::BuiltinsUnwindInfoLabel() const { + char embedded_blob_data_symbol[kTemporaryStringLength]; + i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol), + "%s_Builtins_UnwindInfo", embedded_variant_); + return embedded_blob_data_symbol; +} + +void EmbeddedFileWriter::SetBuiltinUnwindData( + int builtin_index, const win64_unwindinfo::BuiltinUnwindInfo& unwind_info) { + DCHECK_LT(builtin_index, Builtins::builtin_count); + unwind_infos_[builtin_index] = unwind_info; +} + +void EmbeddedFileWriter::WriteUnwindInfoEntry( + PlatformDependentEmbeddedFileWriter* w, uint64_t rva_start, + uint64_t rva_end) const { + w->DeclareRvaToSymbol(EmbeddedBlobDataSymbol().c_str(), rva_start); + w->DeclareRvaToSymbol(EmbeddedBlobDataSymbol().c_str(), rva_end); + w->DeclareRvaToSymbol(BuiltinsUnwindInfoLabel().c_str()); +} + +void EmbeddedFileWriter::WriteUnwindInfo(PlatformDependentEmbeddedFileWriter* w, + const i::EmbeddedData* blob) const { + // Emit an UNWIND_INFO (XDATA) struct, which contains the unwinding + // information that is used for all builtin functions. + DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins()); + w->Comment("xdata for all the code in the embedded blob."); + w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING); + + w->StartXdataSection(); + { + w->DeclareLabel(BuiltinsUnwindInfoLabel().c_str()); + std::vector<uint8_t> xdata = + win64_unwindinfo::GetUnwindInfoForBuiltinFunctions(); + WriteBinaryContentsAsInlineAssembly(w, xdata.data(), + static_cast<uint32_t>(xdata.size())); + w->Comment(" ExceptionHandler"); + w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING); + } + w->EndXdataSection(); + w->Newline(); + + // Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as + // documented here: + // https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64. + w->Comment( + "pdata for all the code in the embedded blob (structs of type " + "RUNTIME_FUNCTION)."); + w->Comment(" BeginAddress"); + w->Comment(" EndAddress"); + w->Comment(" UnwindInfoAddress"); + w->StartPdataSection(); + { + Address prev_builtin_end_offset = 0; + for (int i = 0; i < Builtins::builtin_count; i++) { + // Some builtins are leaf functions from the point of view of Win64 stack + // walking: they do not move the stack pointer and do not require a PDATA + // entry because the return address can be retrieved from [rsp]. + if (!blob->ContainsBuiltin(i)) continue; + if (unwind_infos_[i].is_leaf_function()) continue; + + uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(i) - + reinterpret_cast<Address>(blob->data()); + uint32_t builtin_size = blob->InstructionSizeOfBuiltin(i); + + const std::vector<int>& xdata_desc = unwind_infos_[i].fp_offsets(); + if (xdata_desc.empty()) { + // Some builtins do not have any "push rbp - mov rbp, rsp" instructions + // to start a stack frame. We still emit a PDATA entry as if they had, + // relying on the fact that we can find the previous frame address from + // rbp in most cases. Note that since the function does not really start + // with a 'push rbp' we need to specify the start RVA in the PDATA entry + // a few bytes before the beginning of the function, if it does not + // overlap the end of the previous builtin. + WriteUnwindInfoEntry( + w, + std::max(prev_builtin_end_offset, + builtin_start_offset - win64_unwindinfo::kRbpPrefixLength), + builtin_start_offset + builtin_size); + } else { + // Some builtins have one or more "push rbp - mov rbp, rsp" sequences, + // but not necessarily at the beginning of the function. In this case + // we want to yield a PDATA entry for each block of instructions that + // emit an rbp frame. If the function does not start with 'push rbp' + // we also emit a PDATA entry for the initial block of code up to the + // first 'push rbp', like in the case above. + if (xdata_desc[0] > 0) { + WriteUnwindInfoEntry(w, + std::max(prev_builtin_end_offset, + builtin_start_offset - + win64_unwindinfo::kRbpPrefixLength), + builtin_start_offset + xdata_desc[0]); + } + + for (size_t j = 0; j < xdata_desc.size(); j++) { + int chunk_start = xdata_desc[j]; + int chunk_end = + (j < xdata_desc.size() - 1) ? xdata_desc[j + 1] : builtin_size; + WriteUnwindInfoEntry(w, builtin_start_offset + chunk_start, + builtin_start_offset + chunk_end); + } + } + + prev_builtin_end_offset = builtin_start_offset + builtin_size; + w->Newline(); + } + } + w->EndPdataSection(); + w->Newline(); +} +#endif + // V8_OS_MACOSX // Fuchsia target is explicitly excluded here for Mac hosts. This is to avoid // generating uncompilable assembly files for the Fuchsia target. @@ -319,10 +432,10 @@ int PlatformDependentEmbeddedFileWriter::IndentedDataDirective( return fprintf(fp_, " %s ", DirectiveAsString(directive)); } -// V8_OS_WIN (MSVC) +// V8_TARGET_OS_WIN (MSVC) // ----------------------------------------------------------------------------- -#elif defined(V8_OS_WIN) && defined(V8_ASSEMBLER_IS_MASM) +#elif defined(V8_TARGET_OS_WIN) && defined(V8_ASSEMBLER_IS_MASM) // For MSVC builds we emit assembly in MASM syntax. // See https://docs.microsoft.com/en-us/cpp/assembler/masm/directives-reference. @@ -353,6 +466,42 @@ void PlatformDependentEmbeddedFileWriter::DeclarePointerToSymbol( DirectiveAsString(PointerSizeDirective()), SYMBOL_PREFIX, target); } +#if defined(V8_OS_WIN_X64) + +void PlatformDependentEmbeddedFileWriter::StartPdataSection() { + fprintf(fp_, "OPTION DOTNAME\n"); + fprintf(fp_, ".pdata SEGMENT DWORD READ ''\n"); +} + +void PlatformDependentEmbeddedFileWriter::EndPdataSection() { + fprintf(fp_, ".pdata ENDS\n"); +} + +void PlatformDependentEmbeddedFileWriter::StartXdataSection() { + fprintf(fp_, "OPTION DOTNAME\n"); + fprintf(fp_, ".xdata SEGMENT DWORD READ ''\n"); +} + +void PlatformDependentEmbeddedFileWriter::EndXdataSection() { + fprintf(fp_, ".xdata ENDS\n"); +} + +void PlatformDependentEmbeddedFileWriter::DeclareExternalFunction( + const char* name) { + fprintf(fp_, "EXTERN %s : PROC\n", name); +} + +void PlatformDependentEmbeddedFileWriter::DeclareRvaToSymbol(const char* name, + uint64_t offset) { + if (offset > 0) { + fprintf(fp_, "DD IMAGEREL %s+%llu\n", name, offset); + } else { + fprintf(fp_, "DD IMAGEREL %s\n", name); + } +} + +#endif // defined(V8_OS_WIN_X64) + void PlatformDependentEmbeddedFileWriter::DeclareSymbolGlobal( const char* name) { fprintf(fp_, "PUBLIC %s%s\n", SYMBOL_PREFIX, name); @@ -417,7 +566,7 @@ int PlatformDependentEmbeddedFileWriter::IndentedDataDirective( #undef V8_ASSEMBLER_IS_MASM -#elif defined(V8_OS_WIN) && defined(V8_ASSEMBLER_IS_MARMASM) +#elif defined(V8_TARGET_OS_WIN) && defined(V8_ASSEMBLER_IS_MARMASM) // The the AARCH64 ABI requires instructions be 4-byte-aligned and Windows does // not have a stricter alignment requirement (see the TEXTAREA macro of @@ -543,11 +692,10 @@ void PlatformDependentEmbeddedFileWriter::SectionData() { } void PlatformDependentEmbeddedFileWriter::SectionRoData() { -#if defined(V8_OS_WIN) - fprintf(fp_, ".section .rdata\n"); -#else - fprintf(fp_, ".section .rodata\n"); -#endif + if (i::FLAG_target_os == std::string("win")) + fprintf(fp_, ".section .rdata\n"); + else + fprintf(fp_, ".section .rodata\n"); } void PlatformDependentEmbeddedFileWriter::DeclareUint32(const char* name, @@ -567,6 +715,34 @@ void PlatformDependentEmbeddedFileWriter::DeclarePointerToSymbol( SYMBOL_PREFIX, target); } +#if defined(V8_OS_WIN_X64) + +void PlatformDependentEmbeddedFileWriter::StartPdataSection() { + fprintf(fp_, ".section .pdata\n"); +} + +void PlatformDependentEmbeddedFileWriter::EndPdataSection() {} + +void PlatformDependentEmbeddedFileWriter::StartXdataSection() { + fprintf(fp_, ".section .xdata\n"); +} + +void PlatformDependentEmbeddedFileWriter::EndXdataSection() {} + +void PlatformDependentEmbeddedFileWriter::DeclareExternalFunction( + const char* name) {} + +void PlatformDependentEmbeddedFileWriter::DeclareRvaToSymbol(const char* name, + uint64_t offset) { + if (offset > 0) { + fprintf(fp_, ".rva %s + %llu\n", name, offset); + } else { + fprintf(fp_, ".rva %s\n", name); + } +} + +#endif // defined(V8_OS_WIN_X64) + void PlatformDependentEmbeddedFileWriter::DeclareSymbolGlobal( const char* name) { fprintf(fp_, ".global %s%s\n", SYMBOL_PREFIX, name); @@ -602,29 +778,31 @@ void PlatformDependentEmbeddedFileWriter::DeclareFunctionBegin( const char* name) { DeclareLabel(name); -#if defined(V8_OS_WIN) + if (i::FLAG_target_os == std::string("win")) { #if defined(V8_TARGET_ARCH_ARM64) - // Windows ARM64 assembly is in GAS syntax, but ".type" is invalid directive - // in PE/COFF for Windows. + // Windows ARM64 assembly is in GAS syntax, but ".type" is invalid directive + // in PE/COFF for Windows. #else - // The directives for inserting debugging information on Windows come - // from the PE (Portable Executable) and COFF (Common Object File Format) - // standards. Documented here: - // https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format - // - // .scl 2 means StorageClass external. - // .type 32 means Type Representation Function. - fprintf(fp_, ".def %s%s; .scl 2; .type 32; .endef;\n", SYMBOL_PREFIX, name); + // The directives for inserting debugging information on Windows come + // from the PE (Portable Executable) and COFF (Common Object File Format) + // standards. Documented here: + // https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format + // + // .scl 2 means StorageClass external. + // .type 32 means Type Representation Function. + fprintf(fp_, ".def %s%s; .scl 2; .type 32; .endef;\n", SYMBOL_PREFIX, name); #endif -#elif defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_ARM64) - // ELF format binaries on ARM use ".type <function name>, %function" - // to create a DWARF subprogram entry. - fprintf(fp_, ".type %s, %%function\n", name); + } else { +#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_ARM64) + // ELF format binaries on ARM use ".type <function name>, %function" + // to create a DWARF subprogram entry. + fprintf(fp_, ".type %s, %%function\n", name); #else - // Other ELF Format binaries use ".type <function name>, @function" - // to create a DWARF subprogram entry. - fprintf(fp_, ".type %s, @function\n", name); + // Other ELF Format binaries use ".type <function name>, @function" + // to create a DWARF subprogram entry. + fprintf(fp_, ".type %s, @function\n", name); #endif + } } void PlatformDependentEmbeddedFileWriter::DeclareFunctionEnd(const char* name) { diff --git a/deps/v8/src/snapshot/embedded-file-writer.h b/deps/v8/src/snapshot/embedded-file-writer.h index 04da018d14..0f4978cfd8 100644 --- a/deps/v8/src/snapshot/embedded-file-writer.h +++ b/deps/v8/src/snapshot/embedded-file-writer.h @@ -12,6 +12,10 @@ #include "src/snapshot/snapshot.h" #include "src/source-position-table.h" +#if defined(V8_OS_WIN_X64) +#include "src/unwinding-info-win64.h" +#endif + namespace v8 { namespace internal { @@ -41,6 +45,18 @@ class PlatformDependentEmbeddedFileWriter final { void DeclareUint32(const char* name, uint32_t value); void DeclarePointerToSymbol(const char* name, const char* target); +#if defined(V8_OS_WIN_X64) + void StartPdataSection(); + void EndPdataSection(); + void StartXdataSection(); + void EndXdataSection(); + void DeclareExternalFunction(const char* name); + + // Emits an RVA (address relative to the module load address) specified as an + // offset from a given symbol. + void DeclareRvaToSymbol(const char* name, uint64_t offset = 0); +#endif + void DeclareLabel(const char* name); void SourceInfo(int fileid, const char* filename, int line); @@ -81,6 +97,12 @@ class EmbeddedFileWriterInterface { // The isolate will call the method below just prior to replacing the // compiled builtin Code objects with trampolines. virtual void PrepareBuiltinSourcePositionMap(Builtins* builtins) = 0; + +#if defined(V8_OS_WIN_X64) + virtual void SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) = 0; +#endif }; // Generates the embedded.S file which is later compiled into the final v8 @@ -121,6 +143,12 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { void PrepareBuiltinSourcePositionMap(Builtins* builtins) override; +#if defined(V8_OS_WIN_X64) + void SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) override; +#endif + void SetEmbeddedFile(const char* embedded_src_path) { embedded_src_path_ = embedded_src_path; } @@ -183,17 +211,20 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { // Fairly arbitrary but should fit all symbol names. static constexpr int kTemporaryStringLength = 256; - void WriteMetadataSection(PlatformDependentEmbeddedFileWriter* w, - const i::EmbeddedData* blob) const { + std::string EmbeddedBlobDataSymbol() const { char embedded_blob_data_symbol[kTemporaryStringLength]; i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol), "v8_%s_embedded_blob_data_", embedded_variant_); + return embedded_blob_data_symbol; + } + void WriteMetadataSection(PlatformDependentEmbeddedFileWriter* w, + const i::EmbeddedData* blob) const { w->Comment("The embedded blob starts here. Metadata comes first, followed"); w->Comment("by builtin instruction streams."); w->SectionText(); w->AlignToCodeAlignment(); - w->DeclareLabel(embedded_blob_data_symbol); + w->DeclareLabel(EmbeddedBlobDataSymbol().c_str()); WriteBinaryContentsAsInlineAssembly(w, blob->data(), i::EmbeddedData::RawDataOffset()); @@ -265,10 +296,6 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { void WriteFileEpilogue(PlatformDependentEmbeddedFileWriter* w, const i::EmbeddedData* blob) const { { - char embedded_blob_data_symbol[kTemporaryStringLength]; - i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol), - "v8_%s_embedded_blob_data_", embedded_variant_); - char embedded_blob_symbol[kTemporaryStringLength]; i::SNPrintF(i::Vector<char>(embedded_blob_symbol), "v8_%s_embedded_blob_", embedded_variant_); @@ -277,7 +304,7 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { w->SectionData(); w->AlignToDataAlignment(); w->DeclarePointerToSymbol(embedded_blob_symbol, - embedded_blob_data_symbol); + EmbeddedBlobDataSymbol().c_str()); w->Newline(); } @@ -293,9 +320,23 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { w->Newline(); } +#if defined(V8_OS_WIN_X64) + if (win64_unwindinfo::CanEmitUnwindInfoForBuiltins()) { + WriteUnwindInfo(w, blob); + } +#endif + w->FileEpilogue(); } +#if defined(V8_OS_WIN_X64) + std::string BuiltinsUnwindInfoLabel() const; + void WriteUnwindInfo(PlatformDependentEmbeddedFileWriter* w, + const i::EmbeddedData* blob) const; + void WriteUnwindInfoEntry(PlatformDependentEmbeddedFileWriter* w, + uint64_t rva_start, uint64_t rva_end) const; +#endif + #if defined(_MSC_VER) && !defined(__clang__) #define V8_COMPILER_IS_MSVC #endif @@ -423,6 +464,10 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { std::vector<byte> source_positions_[Builtins::builtin_count]; +#if defined(V8_OS_WIN_X64) + win64_unwindinfo::BuiltinUnwindInfo unwind_infos_[Builtins::builtin_count]; +#endif + // In assembly directives, filename ids need to begin with 1. static const int kFirstExternalFilenameId = 1; std::map<const char*, int> external_filenames_; diff --git a/deps/v8/src/snapshot/mksnapshot.cc b/deps/v8/src/snapshot/mksnapshot.cc index 98af2bf0e8..f44f71e145 100644 --- a/deps/v8/src/snapshot/mksnapshot.cc +++ b/deps/v8/src/snapshot/mksnapshot.cc @@ -5,6 +5,7 @@ #include <errno.h> #include <signal.h> #include <stdio.h> +#include <iomanip> #include "include/libplatform/libplatform.h" #include "src/assembler-arch.h" @@ -244,6 +245,31 @@ void WriteEmbeddedFile(i::EmbeddedFileWriter* writer) { i::EmbeddedData embedded_blob = i::EmbeddedData::FromBlob(); writer->WriteEmbedded(&embedded_blob); } + +using CounterMap = std::map<std::string, int>; +CounterMap* counter_map_ = nullptr; + +void MaybeSetCounterFunction(v8::Isolate* isolate) { + // If --native-code-counters is on then we enable all counters to make + // sure we generate code to increment them from the snapshot. + // + // Note: For the sake of the mksnapshot, the counter function must only + // return distinct addresses for each counter s.t. the serializer can properly + // distinguish between them. In theory it should be okay to just return an + // incremented int value each time this function is called, but we play it + // safe and return a real distinct memory location tied to every counter name. + if (i::FLAG_native_code_counters) { + counter_map_ = new CounterMap(); + isolate->SetCounterFunction([](const char* name) -> int* { + auto map_entry = counter_map_->find(name); + if (map_entry == counter_map_->end()) { + counter_map_->emplace(name, 0); + } + return &counter_map_->at(name); + }); + } +} + } // namespace int main(int argc, char** argv) { @@ -275,7 +301,9 @@ int main(int argc, char** argv) { i::EmbeddedFileWriter embedded_writer; embedded_writer.SetEmbeddedFile(i::FLAG_embedded_src); - embedded_writer.SetEmbeddedVariant(i::FLAG_embedded_variant); + if (i::FLAG_embedded_variant != nullptr) { + embedded_writer.SetEmbeddedVariant(i::FLAG_embedded_variant); + } std::unique_ptr<char> embed_script( GetExtraCode(argc >= 2 ? argv[1] : nullptr, "embedding")); @@ -286,6 +314,9 @@ int main(int argc, char** argv) { v8::StartupData blob; { v8::Isolate* isolate = v8::Isolate::Allocate(); + + MaybeSetCounterFunction(isolate); + if (i::FLAG_embedded_builtins) { // Set code range such that relative jumps for builtins to // builtin calls in the snapshot are possible. @@ -315,6 +346,8 @@ int main(int argc, char** argv) { delete[] cold.data; } + delete counter_map_; + CHECK(blob.data); snapshot_writer.WriteSnapshot(blob); delete[] blob.data; diff --git a/deps/v8/src/snapshot/natives.h b/deps/v8/src/snapshot/natives.h index a5701979f4..76b8bf1bde 100644 --- a/deps/v8/src/snapshot/natives.h +++ b/deps/v8/src/snapshot/natives.h @@ -39,8 +39,7 @@ class V8_EXPORT_PRIVATE NativesCollection { static Vector<const char> GetScriptsSource(); }; -typedef NativesCollection<EXTRAS> ExtraNatives; - +using ExtraNatives = NativesCollection<EXTRAS>; #ifdef V8_USE_EXTERNAL_STARTUP_DATA // Used for reading the natives at runtime. Implementation in natives-empty.cc diff --git a/deps/v8/src/snapshot/partial-deserializer.h b/deps/v8/src/snapshot/partial-deserializer.h index d4362f5f23..0869793a9d 100644 --- a/deps/v8/src/snapshot/partial-deserializer.h +++ b/deps/v8/src/snapshot/partial-deserializer.h @@ -15,7 +15,7 @@ class Context; // Deserializes the context-dependent object graph rooted at a given object. // The PartialDeserializer is not expected to deserialize any code objects. -class PartialDeserializer final : public Deserializer { +class V8_EXPORT_PRIVATE PartialDeserializer final : public Deserializer { public: static MaybeHandle<Context> DeserializeContext( Isolate* isolate, const SnapshotData* data, bool can_rehash, diff --git a/deps/v8/src/snapshot/partial-serializer.cc b/deps/v8/src/snapshot/partial-serializer.cc index 638c4f702c..6c650be4c1 100644 --- a/deps/v8/src/snapshot/partial-serializer.cc +++ b/deps/v8/src/snapshot/partial-serializer.cc @@ -101,6 +101,12 @@ void PartialSerializer::SerializeObject(HeapObject obj) { // Clear literal boilerplates and feedback. if (obj->IsFeedbackVector()) FeedbackVector::cast(obj)->ClearSlots(isolate()); + // Clear InterruptBudget when serializing FeedbackCell. + if (obj->IsFeedbackCell()) { + FeedbackCell::cast(obj)->set_interrupt_budget( + FeedbackCell::GetInitialInterruptBudget()); + } + if (SerializeJSObjectWithEmbedderFields(obj)) { return; } @@ -143,7 +149,6 @@ bool PartialSerializer::SerializeJSObjectWithEmbedderFields(Object obj) { int embedder_fields_count = js_obj->GetEmbedderFieldCount(); if (embedder_fields_count == 0) return false; CHECK_GT(embedder_fields_count, 0); - DCHECK_NOT_NULL(serialize_embedder_fields_.callback); DCHECK(!js_obj->NeedsRehashing()); DisallowHeapAllocation no_gc; @@ -169,9 +174,17 @@ bool PartialSerializer::SerializeJSObjectWithEmbedderFields(Object obj) { DCHECK(isolate()->heap()->Contains(HeapObject::cast(object))); serialized_data.push_back({nullptr, 0}); } else { - StartupData data = serialize_embedder_fields_.callback( - api_obj, i, serialize_embedder_fields_.data); - serialized_data.push_back(data); + // If no serializer is provided and the field was empty, we serialize it + // by default to nullptr. + if (serialize_embedder_fields_.callback == nullptr && + object->ptr() == 0) { + serialized_data.push_back({nullptr, 0}); + } else { + DCHECK_NOT_NULL(serialize_embedder_fields_.callback); + StartupData data = serialize_embedder_fields_.callback( + api_obj, i, serialize_embedder_fields_.data); + serialized_data.push_back(data); + } } } diff --git a/deps/v8/src/snapshot/partial-serializer.h b/deps/v8/src/snapshot/partial-serializer.h index 55bc5c8aee..fcba9feed2 100644 --- a/deps/v8/src/snapshot/partial-serializer.h +++ b/deps/v8/src/snapshot/partial-serializer.h @@ -14,7 +14,7 @@ namespace internal { class StartupSerializer; -class PartialSerializer : public Serializer { +class V8_EXPORT_PRIVATE PartialSerializer : public Serializer { public: PartialSerializer(Isolate* isolate, StartupSerializer* startup_serializer, v8::SerializeEmbedderFieldsCallback callback); diff --git a/deps/v8/src/snapshot/read-only-serializer.cc b/deps/v8/src/snapshot/read-only-serializer.cc index 7fa38f78ea..a65ce4903e 100644 --- a/deps/v8/src/snapshot/read-only-serializer.cc +++ b/deps/v8/src/snapshot/read-only-serializer.cc @@ -7,7 +7,7 @@ #include "src/api.h" #include "src/code-tracer.h" #include "src/global-handles.h" -#include "src/heap/heap-inl.h" // For InReadOnlySpace. +#include "src/heap/read-only-heap.h" #include "src/objects-inl.h" #include "src/objects/slots.h" #include "src/snapshot/startup-serializer.h" @@ -26,7 +26,7 @@ ReadOnlySerializer::~ReadOnlySerializer() { } void ReadOnlySerializer::SerializeObject(HeapObject obj) { - CHECK(isolate()->heap()->InReadOnlySpace(obj)); + CHECK(ReadOnlyHeap::Contains(obj)); CHECK_IMPLIES(obj->IsString(), obj->IsInternalizedString()); if (SerializeHotObject(obj)) return; @@ -80,7 +80,7 @@ bool ReadOnlySerializer::MustBeDeferred(HeapObject object) { bool ReadOnlySerializer::SerializeUsingReadOnlyObjectCache( SnapshotByteSink* sink, HeapObject obj) { - if (!isolate()->heap()->InReadOnlySpace(obj)) return false; + if (!ReadOnlyHeap::Contains(obj)) return false; // Get the cache index and serialize it into the read-only snapshot if // necessary. diff --git a/deps/v8/src/snapshot/read-only-serializer.h b/deps/v8/src/snapshot/read-only-serializer.h index 06aaa91df7..753432502e 100644 --- a/deps/v8/src/snapshot/read-only-serializer.h +++ b/deps/v8/src/snapshot/read-only-serializer.h @@ -13,7 +13,7 @@ namespace internal { class HeapObject; class SnapshotByteSink; -class ReadOnlySerializer : public RootsSerializer { +class V8_EXPORT_PRIVATE ReadOnlySerializer : public RootsSerializer { public: explicit ReadOnlySerializer(Isolate* isolate); ~ReadOnlySerializer() override; diff --git a/deps/v8/src/snapshot/references.h b/deps/v8/src/snapshot/references.h index a54e76316f..ff3196115c 100644 --- a/deps/v8/src/snapshot/references.h +++ b/deps/v8/src/snapshot/references.h @@ -154,7 +154,7 @@ class SerializerReferenceMap base::KeyEqualityMatcher<intptr_t>, base::DefaultAllocationPolicy> { public: - typedef base::TemplateHashMapEntry<uintptr_t, SerializerReference> Entry; + using Entry = base::TemplateHashMapEntry<uintptr_t, SerializerReference>; SerializerReferenceMap() : attached_reference_index_(0) {} diff --git a/deps/v8/src/snapshot/serializer-allocator.cc b/deps/v8/src/snapshot/serializer-allocator.cc index e69441dc14..d596678789 100644 --- a/deps/v8/src/snapshot/serializer-allocator.cc +++ b/deps/v8/src/snapshot/serializer-allocator.cc @@ -137,7 +137,7 @@ void SerializerAllocator::OutputStatistics() { PrintF(" Spaces (bytes):\n"); for (int space = FIRST_SPACE; space < kNumberOfSpaces; space++) { - PrintF("%16s", AllocationSpaceName(static_cast<AllocationSpace>(space))); + PrintF("%16s", Heap::GetSpaceName(static_cast<AllocationSpace>(space))); } PrintF("\n"); diff --git a/deps/v8/src/snapshot/serializer.cc b/deps/v8/src/snapshot/serializer.cc index 660d2ce04a..0096b2c4fb 100644 --- a/deps/v8/src/snapshot/serializer.cc +++ b/deps/v8/src/snapshot/serializer.cc @@ -6,6 +6,7 @@ #include "src/assembler-inl.h" #include "src/heap/heap-inl.h" // For Space::identity(). +#include "src/heap/read-only-heap.h" #include "src/interpreter/interpreter.h" #include "src/objects/code.h" #include "src/objects/js-array-buffer-inl.h" @@ -71,14 +72,14 @@ void Serializer::OutputStatistics(const char* name) { #ifdef OBJECT_PRINT PrintF(" Instance types (count and bytes):\n"); -#define PRINT_INSTANCE_TYPE(Name) \ - for (int space = 0; space < LAST_SPACE; ++space) { \ - if (instance_type_count_[space][Name]) { \ - PrintF("%10d %10" PRIuS " %-10s %s\n", \ - instance_type_count_[space][Name], \ - instance_type_size_[space][Name], \ - AllocationSpaceName(static_cast<AllocationSpace>(space)), #Name); \ - } \ +#define PRINT_INSTANCE_TYPE(Name) \ + for (int space = 0; space < LAST_SPACE; ++space) { \ + if (instance_type_count_[space][Name]) { \ + PrintF("%10d %10" PRIuS " %-10s %s\n", \ + instance_type_count_[space][Name], \ + instance_type_size_[space][Name], \ + Heap::GetSpaceName(static_cast<AllocationSpace>(space)), #Name); \ + } \ } INSTANCE_TYPE_LIST(PRINT_INSTANCE_TYPE) #undef PRINT_INSTANCE_TYPE @@ -540,7 +541,7 @@ void Serializer::ObjectSerializer::Serialize() { if (object_->IsExternalString()) { SerializeExternalString(); return; - } else if (!serializer_->isolate()->heap()->InReadOnlySpace(object_)) { + } else if (!ReadOnlyHeap::Contains(object_)) { // Only clear padding for strings outside RO_SPACE. RO_SPACE should have // been cleared elsewhere. if (object_->IsSeqOneByteString()) { diff --git a/deps/v8/src/snapshot/snapshot-common.cc b/deps/v8/src/snapshot/snapshot-common.cc index 8d65235902..09532aafa0 100644 --- a/deps/v8/src/snapshot/snapshot-common.cc +++ b/deps/v8/src/snapshot/snapshot-common.cc @@ -351,5 +351,56 @@ Vector<const byte> SnapshotData::Payload() const { return Vector<const byte>(payload, length); } +namespace { + +bool RunExtraCode(v8::Isolate* isolate, v8::Local<v8::Context> context, + const char* utf8_source, const char* name) { + v8::Context::Scope context_scope(context); + v8::TryCatch try_catch(isolate); + v8::Local<v8::String> source_string; + if (!v8::String::NewFromUtf8(isolate, utf8_source, v8::NewStringType::kNormal) + .ToLocal(&source_string)) { + return false; + } + v8::Local<v8::String> resource_name = + v8::String::NewFromUtf8(isolate, name, v8::NewStringType::kNormal) + .ToLocalChecked(); + v8::ScriptOrigin origin(resource_name); + v8::ScriptCompiler::Source source(source_string, origin); + v8::Local<v8::Script> script; + if (!v8::ScriptCompiler::Compile(context, &source).ToLocal(&script)) + return false; + if (script->Run(context).IsEmpty()) return false; + CHECK(!try_catch.HasCaught()); + return true; +} + +} // namespace + +// TODO(jgruber): Merge with related code in mksnapshot.cc and +// inspector-test.cc. +v8::StartupData CreateSnapshotDataBlobInternal( + v8::SnapshotCreator::FunctionCodeHandling function_code_handling, + const char* embedded_source) { + // Create a new isolate and a new context from scratch, optionally run + // a script to embed, and serialize to create a snapshot blob. + v8::StartupData result = {nullptr, 0}; + { + v8::SnapshotCreator snapshot_creator; + v8::Isolate* isolate = snapshot_creator.GetIsolate(); + { + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + if (embedded_source != nullptr && + !RunExtraCode(isolate, context, embedded_source, "<embedded>")) { + return result; + } + snapshot_creator.SetDefaultContext(context); + } + result = snapshot_creator.CreateBlob(function_code_handling); + } + return result; +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/snapshot/snapshot.h b/deps/v8/src/snapshot/snapshot.h index 01da513106..e8894a2331 100644 --- a/deps/v8/src/snapshot/snapshot.h +++ b/deps/v8/src/snapshot/snapshot.h @@ -19,7 +19,7 @@ class PartialSerializer; class StartupSerializer; // Wrapper around reservation sizes and the serialization payload. -class SnapshotData : public SerializedData { +class V8_EXPORT_PRIVATE SnapshotData : public SerializedData { public: // Used when producing. explicit SnapshotData(const Serializer* serializer); @@ -72,7 +72,7 @@ class Snapshot : public AllStatic { // To be implemented by the snapshot source. static const v8::StartupData* DefaultSnapshotBlob(); - static bool VerifyChecksum(const v8::StartupData* data); + V8_EXPORT_PRIVATE static bool VerifyChecksum(const v8::StartupData* data); // ---------------- Serialization ---------------- @@ -157,6 +157,12 @@ class Snapshot : public AllStatic { DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot); }; +// Convenience wrapper around snapshot data blob creation used e.g. by tests and +// mksnapshot. +V8_EXPORT_PRIVATE v8::StartupData CreateSnapshotDataBlobInternal( + v8::SnapshotCreator::FunctionCodeHandling function_code_handling, + const char* embedded_source); + #ifdef V8_USE_EXTERNAL_STARTUP_DATA void SetSnapshotFromFile(StartupData* snapshot_blob); #endif diff --git a/deps/v8/src/snapshot/startup-serializer.cc b/deps/v8/src/snapshot/startup-serializer.cc index 79b6fe5b72..907b338742 100644 --- a/deps/v8/src/snapshot/startup-serializer.cc +++ b/deps/v8/src/snapshot/startup-serializer.cc @@ -10,6 +10,7 @@ #include "src/deoptimizer.h" #include "src/global-handles.h" #include "src/heap/heap-inl.h" +#include "src/heap/read-only-heap.h" #include "src/objects-inl.h" #include "src/objects/foreign-inl.h" #include "src/objects/slots.h" @@ -111,7 +112,7 @@ void StartupSerializer::SerializeObject(HeapObject obj) { CheckRehashability(obj); // Object has not yet been serialized. Serialize it here. - DCHECK(!isolate()->heap()->InReadOnlySpace(obj)); + DCHECK(!ReadOnlyHeap::Contains(obj)); ObjectSerializer object_serializer(this, obj, &sink_); object_serializer.Serialize(); } diff --git a/deps/v8/src/snapshot/startup-serializer.h b/deps/v8/src/snapshot/startup-serializer.h index 13638eae5e..5ab98ed8ba 100644 --- a/deps/v8/src/snapshot/startup-serializer.h +++ b/deps/v8/src/snapshot/startup-serializer.h @@ -16,7 +16,7 @@ class HeapObject; class SnapshotByteSink; class ReadOnlySerializer; -class StartupSerializer : public RootsSerializer { +class V8_EXPORT_PRIVATE StartupSerializer : public RootsSerializer { public: StartupSerializer(Isolate* isolate, ReadOnlySerializer* read_only_serializer); ~StartupSerializer() override; |