1 | // Copyright 2016 the V8 project authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include "src/snapshot/serializer-common.h" |
6 | |
7 | #include "src/external-reference-table.h" |
8 | #include "src/objects-inl.h" |
9 | #include "src/objects/foreign-inl.h" |
10 | #include "src/objects/slots.h" |
11 | |
12 | namespace v8 { |
13 | namespace internal { |
14 | |
15 | ExternalReferenceEncoder::ExternalReferenceEncoder(Isolate* isolate) { |
16 | #ifdef DEBUG |
17 | api_references_ = isolate->api_external_references(); |
18 | if (api_references_ != nullptr) { |
19 | for (uint32_t i = 0; api_references_[i] != 0; ++i) count_.push_back(0); |
20 | } |
21 | #endif // DEBUG |
22 | map_ = isolate->external_reference_map(); |
23 | if (map_ != nullptr) return; |
24 | map_ = new AddressToIndexHashMap(); |
25 | isolate->set_external_reference_map(map_); |
26 | // Add V8's external references. |
27 | ExternalReferenceTable* table = isolate->external_reference_table(); |
28 | for (uint32_t i = 0; i < ExternalReferenceTable::kSize; ++i) { |
29 | Address addr = table->address(i); |
30 | // Ignore duplicate references. |
31 | // This can happen due to ICF. See http://crbug.com/726896. |
32 | if (map_->Get(addr).IsNothing()) map_->Set(addr, Value::Encode(i, false)); |
33 | DCHECK(map_->Get(addr).IsJust()); |
34 | } |
35 | // Add external references provided by the embedder. |
36 | const intptr_t* api_references = isolate->api_external_references(); |
37 | if (api_references == nullptr) return; |
38 | for (uint32_t i = 0; api_references[i] != 0; ++i) { |
39 | Address addr = static_cast<Address>(api_references[i]); |
40 | // Ignore duplicate references. |
41 | // This can happen due to ICF. See http://crbug.com/726896. |
42 | if (map_->Get(addr).IsNothing()) map_->Set(addr, Value::Encode(i, true)); |
43 | DCHECK(map_->Get(addr).IsJust()); |
44 | } |
45 | } |
46 | |
47 | ExternalReferenceEncoder::~ExternalReferenceEncoder() { |
48 | #ifdef DEBUG |
49 | if (!i::FLAG_external_reference_stats) return; |
50 | if (api_references_ == nullptr) return; |
51 | for (uint32_t i = 0; api_references_[i] != 0; ++i) { |
52 | Address addr = static_cast<Address>(api_references_[i]); |
53 | DCHECK(map_->Get(addr).IsJust()); |
54 | v8::base::OS::Print( |
55 | "index=%5d count=%5d %-60s\n" , i, count_[i], |
56 | ExternalReferenceTable::ResolveSymbol(reinterpret_cast<void*>(addr))); |
57 | } |
58 | #endif // DEBUG |
59 | } |
60 | |
61 | Maybe<ExternalReferenceEncoder::Value> ExternalReferenceEncoder::TryEncode( |
62 | Address address) { |
63 | Maybe<uint32_t> maybe_index = map_->Get(address); |
64 | if (maybe_index.IsNothing()) return Nothing<Value>(); |
65 | Value result(maybe_index.FromJust()); |
66 | #ifdef DEBUG |
67 | if (result.is_from_api()) count_[result.index()]++; |
68 | #endif // DEBUG |
69 | return Just<Value>(result); |
70 | } |
71 | |
72 | ExternalReferenceEncoder::Value ExternalReferenceEncoder::Encode( |
73 | Address address) { |
74 | Maybe<uint32_t> maybe_index = map_->Get(address); |
75 | if (maybe_index.IsNothing()) { |
76 | void* addr = reinterpret_cast<void*>(address); |
77 | v8::base::OS::PrintError("Unknown external reference %p.\n" , addr); |
78 | v8::base::OS::PrintError("%s" , ExternalReferenceTable::ResolveSymbol(addr)); |
79 | v8::base::OS::Abort(); |
80 | } |
81 | Value result(maybe_index.FromJust()); |
82 | #ifdef DEBUG |
83 | if (result.is_from_api()) count_[result.index()]++; |
84 | #endif // DEBUG |
85 | return result; |
86 | } |
87 | |
88 | const char* ExternalReferenceEncoder::NameOfAddress(Isolate* isolate, |
89 | Address address) const { |
90 | Maybe<uint32_t> maybe_index = map_->Get(address); |
91 | if (maybe_index.IsNothing()) return "<unknown>" ; |
92 | Value value(maybe_index.FromJust()); |
93 | if (value.is_from_api()) return "<from api>" ; |
94 | return isolate->external_reference_table()->name(value.index()); |
95 | } |
96 | |
97 | void SerializedData::AllocateData(uint32_t size) { |
98 | DCHECK(!owns_data_); |
99 | data_ = NewArray<byte>(size); |
100 | size_ = size; |
101 | owns_data_ = true; |
102 | DCHECK(IsAligned(reinterpret_cast<intptr_t>(data_), kPointerAlignment)); |
103 | } |
104 | |
105 | // static |
106 | constexpr uint32_t SerializedData::kMagicNumber; |
107 | |
108 | // The partial snapshot cache is terminated by undefined. We visit the |
109 | // partial snapshot... |
110 | // - during deserialization to populate it. |
111 | // - during normal GC to keep its content alive. |
112 | // - not during serialization. The partial serializer adds to it explicitly. |
113 | DISABLE_CFI_PERF |
114 | void SerializerDeserializer::Iterate(Isolate* isolate, RootVisitor* visitor) { |
115 | std::vector<Object>* cache = isolate->partial_snapshot_cache(); |
116 | for (size_t i = 0;; ++i) { |
117 | // Extend the array ready to get a value when deserializing. |
118 | if (cache->size() <= i) cache->push_back(Smi::kZero); |
119 | // During deserialization, the visitor populates the partial snapshot cache |
120 | // and eventually terminates the cache with undefined. |
121 | visitor->VisitRootPointer(Root::kPartialSnapshotCache, nullptr, |
122 | FullObjectSlot(&cache->at(i))); |
123 | if (cache->at(i)->IsUndefined(isolate)) break; |
124 | } |
125 | } |
126 | |
127 | bool SerializerDeserializer::CanBeDeferred(HeapObject o) { |
128 | return !o->IsString() && !o->IsScript() && !o->IsJSTypedArray(); |
129 | } |
130 | |
131 | void SerializerDeserializer::RestoreExternalReferenceRedirectors( |
132 | const std::vector<AccessorInfo>& accessor_infos) { |
133 | // Restore wiped accessor infos. |
134 | for (AccessorInfo info : accessor_infos) { |
135 | Foreign::cast(info->js_getter()) |
136 | ->set_foreign_address(info->redirected_getter()); |
137 | } |
138 | } |
139 | |
140 | void SerializerDeserializer::RestoreExternalReferenceRedirectors( |
141 | const std::vector<CallHandlerInfo>& call_handler_infos) { |
142 | for (CallHandlerInfo info : call_handler_infos) { |
143 | Foreign::cast(info->js_callback()) |
144 | ->set_foreign_address(info->redirected_callback()); |
145 | } |
146 | } |
147 | |
148 | } // namespace internal |
149 | } // namespace v8 |
150 | |