startup-serializer.cc 7.97 KB
Newer Older
1 2 3 4 5 6
// Copyright 2016 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/snapshot/startup-serializer.h"

7
#include "src/api.h"
8
#include "src/global-handles.h"
9 10 11 12 13 14
#include "src/objects-inl.h"
#include "src/v8threads.h"

namespace v8 {
namespace internal {

15 16
StartupSerializer::StartupSerializer(Isolate* isolate)
    : Serializer(isolate), can_be_rehashed_(true) {
17 18 19 20
  InitializeCodeAddressMap();
}

StartupSerializer::~StartupSerializer() {
21
  RestoreExternalReferenceRedirectors(accessor_infos_);
22
  RestoreExternalReferenceRedirectors(call_handler_infos_);
23 24 25 26 27
  OutputStatistics("StartupSerializer");
}

void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
                                        WhereToPoint where_to_point, int skip) {
28
  DCHECK(!ObjectIsBytecodeHandler(obj));  // Only referenced in dispatch table.
29 30
  DCHECK(!obj->IsJSFunction());

31
  if (SerializeBuiltinReference(obj, how_to_code, where_to_point, skip)) {
32 33
    return;
  }
34 35
  if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;

36
  int root_index = root_index_map()->Lookup(obj);
37 38 39
  // We can only encode roots as such if it has already been serialized.
  // That applies to root indices below the wave front.
  if (root_index != RootIndexMap::kInvalidRootIndex) {
40
    if (root_has_been_serialized(root_index)) {
41 42 43 44 45
      PutRoot(root_index, obj, how_to_code, where_to_point, skip);
      return;
    }
  }

46
  if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
47 48

  FlushSkip(skip);
49 50 51 52
  bool use_simulator = false;
#ifdef USE_SIMULATOR
  use_simulator = true;
#endif
53

54
  if (use_simulator && obj->IsAccessorInfo()) {
55 56 57 58
    // Wipe external reference redirects in the accessor info.
    AccessorInfo* info = AccessorInfo::cast(obj);
    Address original_address = Foreign::cast(info->getter())->foreign_address();
    Foreign::cast(info->js_getter())->set_foreign_address(original_address);
59
    accessor_infos_.push_back(info);
60
  } else if (use_simulator && obj->IsCallHandlerInfo()) {
61 62 63 64 65
    CallHandlerInfo* info = CallHandlerInfo::cast(obj);
    Address original_address =
        Foreign::cast(info->callback())->foreign_address();
    Foreign::cast(info->js_callback())->set_foreign_address(original_address);
    call_handler_infos_.push_back(info);
66 67
  } else if (obj->IsScript() && Script::cast(obj)->IsUserJavaScript()) {
    Script::cast(obj)->set_context_data(
68
        isolate()->heap()->uninitialized_symbol());
69 70 71 72 73 74
  } else if (obj->IsSharedFunctionInfo()) {
    // Clear inferred name for native functions.
    SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
    if (!shared->IsSubjectToDebugging() && shared->HasInferredName()) {
      shared->set_inferred_name(isolate()->heap()->empty_string());
    }
75 76
  }

77
  CheckRehashability(obj);
78

79
  // Object has not yet been serialized.  Serialize it here.
80
  ObjectSerializer object_serializer(this, obj, &sink_, how_to_code,
81 82 83 84 85
                                     where_to_point);
  object_serializer.Serialize();
}

void StartupSerializer::SerializeWeakReferencesAndDeferred() {
86 87 88
  // This comes right after serialization of the partial snapshot, where we
  // add entries to the partial snapshot cache of the startup snapshot. Add
  // one entry with 'undefined' to terminate the partial snapshot cache.
89
  Object* undefined = isolate()->heap()->undefined_value();
90
  VisitRootPointer(Root::kPartialSnapshotCache, nullptr, &undefined);
91
  isolate()->heap()->IterateWeakRoots(this, VISIT_FOR_SERIALIZATION);
92 93 94 95
  SerializeDeferredObjects();
  Pad();
}

96 97 98 99 100 101
int StartupSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
  int index;
  if (!partial_cache_index_map_.LookupOrInsert(heap_object, &index)) {
    // This object is not part of the partial snapshot cache yet. Add it to the
    // startup snapshot so we can refer to it via partial snapshot index from
    // the partial snapshot.
102
    VisitRootPointer(Root::kPartialSnapshotCache, nullptr,
103
                     reinterpret_cast<Object**>(&heap_object));
104 105 106 107
  }
  return index;
}

108
void StartupSerializer::Synchronize(VisitorSynchronization::SyncTag tag) {
109
  sink_.Put(kSynchronize, "Synchronize");
110 111 112 113 114 115 116
}

void StartupSerializer::SerializeStrongReferences() {
  Isolate* isolate = this->isolate();
  // No active threads.
  CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
  // No active or weak handles.
117
  CHECK(isolate->handle_scope_implementer()->blocks()->empty());
118

119
  // Visit smi roots.
120 121 122
  // Clear the stack limits to make the snapshot reproducible.
  // Reset it again afterwards.
  isolate->heap()->ClearStackLimits();
123
  isolate->heap()->IterateSmiRoots(this);
124
  isolate->heap()->SetStackLimits();
125
  // First visit immortal immovables to make sure they end up in the first page.
126
  isolate->heap()->IterateStrongRoots(this, VISIT_FOR_SERIALIZATION);
127 128
}

129 130
void StartupSerializer::VisitRootPointers(Root root, const char* description,
                                          Object** start, Object** end) {
131 132 133 134 135 136 137 138 139
  if (start == isolate()->heap()->roots_array_start()) {
    // Serializing the root list needs special handling:
    // - The first pass over the root list only serializes immortal immovables.
    // - The second pass over the root list serializes the rest.
    // - Only root list elements that have been fully serialized can be
    //   referenced via as root by using kRootArray bytecodes.
    int skip = 0;
    for (Object** current = start; current < end; current++) {
      int root_index = static_cast<int>(current - start);
140 141 142
      if ((*current)->IsSmi()) {
        FlushSkip(skip);
        PutSmi(Smi::cast(*current));
143
      } else {
144 145
        SerializeObject(HeapObject::cast(*current), kPlain, kStartOfObject,
                        skip);
146
      }
147 148
      root_has_been_serialized_.set(root_index);
      skip = 0;
149
    }
150 151
    FlushSkip(skip);
  } else {
152
    Serializer::VisitRootPointers(root, description, start, end);
153 154 155
  }
}

156
void StartupSerializer::CheckRehashability(HeapObject* obj) {
157
  if (!can_be_rehashed_) return;
158 159
  if (!obj->NeedsRehashing()) return;
  if (obj->CanBeRehashed()) return;
160 161 162
  can_be_rehashed_ = false;
}

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
bool StartupSerializer::MustBeDeferred(HeapObject* object) {
  if (root_has_been_serialized_.test(Heap::kFreeSpaceMapRootIndex) &&
      root_has_been_serialized_.test(Heap::kOnePointerFillerMapRootIndex) &&
      root_has_been_serialized_.test(Heap::kTwoPointerFillerMapRootIndex)) {
    // All required root objects are serialized, so any aligned objects can
    // be saved without problems.
    return false;
  }
  // Just defer everything except of Map objects until all required roots are
  // serialized. Some objects may have special alignment requirements, that may
  // not be fulfilled during deserialization until few first root objects are
  // serialized. But we must serialize Map objects since deserializer checks
  // that these root objects are indeed Maps.
  return !object->IsMap();
}

179 180 181 182 183 184 185 186 187 188 189 190 191 192
SerializedHandleChecker::SerializedHandleChecker(
    Isolate* isolate, std::vector<Context*>* contexts)
    : isolate_(isolate) {
  AddToSet(isolate->heap()->serialized_objects());
  for (auto const& context : *contexts) {
    AddToSet(context->serialized_objects());
  }
}

void SerializedHandleChecker::AddToSet(FixedArray* serialized) {
  int length = serialized->length();
  for (int i = 0; i < length; i++) serialized_.insert(serialized->get(i));
}

193 194 195
void SerializedHandleChecker::VisitRootPointers(Root root,
                                                const char* description,
                                                Object** start, Object** end) {
196 197 198 199
  for (Object** p = start; p < end; p++) {
    if (serialized_.find(*p) != serialized_.end()) continue;
    PrintF("%s handle not serialized: ",
           root == Root::kGlobalHandles ? "global" : "eternal");
200
    (*p)->Print(isolate_);
201 202 203 204 205 206 207 208 209 210
    ok_ = false;
  }
}

bool SerializedHandleChecker::CheckGlobalAndEternalHandles() {
  isolate_->global_handles()->IterateAllRoots(this);
  isolate_->eternal_handles()->IterateAllRoots(this);
  return ok_;
}

211 212
}  // namespace internal
}  // namespace v8