startup-serializer.cc 7.02 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/code-tracer.h"
9
#include "src/contexts.h"
10
#include "src/global-handles.h"
11
#include "src/objects-inl.h"
12
#include "src/objects/foreign-inl.h"
13
#include "src/objects/slots.h"
14
#include "src/snapshot/read-only-serializer.h"
15 16 17 18 19
#include "src/v8threads.h"

namespace v8 {
namespace internal {

20 21 22 23
StartupSerializer::StartupSerializer(Isolate* isolate,
                                     ReadOnlySerializer* read_only_serializer)
    : RootsSerializer(isolate, RootIndex::kFirstStrongRoot),
      read_only_serializer_(read_only_serializer) {
24 25 26 27
  InitializeCodeAddressMap();
}

StartupSerializer::~StartupSerializer() {
28
  RestoreExternalReferenceRedirectors(accessor_infos_);
29
  RestoreExternalReferenceRedirectors(call_handler_infos_);
30 31 32
  OutputStatistics("StartupSerializer");
}

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
namespace {

// Due to how we currently create the embedded blob, we may encounter both
// off-heap trampolines and old, outdated full Code objects during
// serialization. This ensures that we only serialize the canonical version of
// each builtin.
// See also CreateOffHeapTrampolines().
HeapObject* MaybeCanonicalizeBuiltin(Isolate* isolate, HeapObject* obj) {
  if (!obj->IsCode()) return obj;

  const int builtin_index = Code::cast(obj)->builtin_index();
  if (!Builtins::IsBuiltinId(builtin_index)) return obj;

  return isolate->builtins()->builtin(builtin_index);
}

}  // namespace

51 52 53 54
void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
                                        WhereToPoint where_to_point, int skip) {
  DCHECK(!obj->IsJSFunction());

55 56 57 58
  // TODO(jgruber): Remove canonicalization once off-heap trampoline creation
  // moves to Isolate::Init().
  obj = MaybeCanonicalizeBuiltin(isolate(), obj);

59
  if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
60 61 62
  if (IsRootAndHasBeenSerialized(obj) &&
      SerializeRoot(obj, how_to_code, where_to_point, skip))
    return;
63 64 65
  if (SerializeUsingReadOnlyObjectCache(&sink_, obj, how_to_code,
                                        where_to_point, skip))
    return;
66
  if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
67 68

  FlushSkip(skip);
69 70 71 72
  bool use_simulator = false;
#ifdef USE_SIMULATOR
  use_simulator = true;
#endif
73

74
  if (use_simulator && obj->IsAccessorInfo()) {
75
    // Wipe external reference redirects in the accessor info.
76
    AccessorInfo info = AccessorInfo::cast(obj);
77 78
    Address original_address = Foreign::cast(info->getter())->foreign_address();
    Foreign::cast(info->js_getter())->set_foreign_address(original_address);
79
    accessor_infos_.push_back(info);
80
  } else if (use_simulator && obj->IsCallHandlerInfo()) {
81
    CallHandlerInfo info = CallHandlerInfo::cast(obj);
82 83 84 85
    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);
86 87
  } else if (obj->IsScript() && Script::cast(obj)->IsUserJavaScript()) {
    Script::cast(obj)->set_context_data(
88
        ReadOnlyRoots(isolate()).uninitialized_symbol());
89 90
  } else if (obj->IsSharedFunctionInfo()) {
    // Clear inferred name for native functions.
91
    SharedFunctionInfo shared = SharedFunctionInfo::cast(obj);
92 93 94
    if (!shared->IsSubjectToDebugging() && shared->HasUncompiledData()) {
      shared->uncompiled_data()->set_inferred_name(
          ReadOnlyRoots(isolate()).empty_string());
95
    }
96 97
  }

98
  CheckRehashability(obj);
99

100
  // Object has not yet been serialized.  Serialize it here.
101
  DCHECK(!isolate()->heap()->read_only_space()->Contains(obj));
102
  ObjectSerializer object_serializer(this, obj, &sink_, how_to_code,
103 104 105 106 107
                                     where_to_point);
  object_serializer.Serialize();
}

void StartupSerializer::SerializeWeakReferencesAndDeferred() {
108 109 110
  // 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.
111
  Object* undefined = ReadOnlyRoots(isolate()).undefined_value();
112
  VisitRootPointer(Root::kPartialSnapshotCache, nullptr,
113
                   FullObjectSlot(&undefined));
114
  isolate()->heap()->IterateWeakRoots(this, VISIT_FOR_SERIALIZATION);
115 116 117 118 119 120 121 122 123
  SerializeDeferredObjects();
  Pad();
}

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

126
  // Visit smi roots.
127 128 129
  // Clear the stack limits to make the snapshot reproducible.
  // Reset it again afterwards.
  isolate->heap()->ClearStackLimits();
130
  isolate->heap()->IterateSmiRoots(this);
131
  isolate->heap()->SetStackLimits();
132
  // First visit immortal immovables to make sure they end up in the first page.
133
  isolate->heap()->IterateStrongRoots(this, VISIT_FOR_SERIALIZATION);
134 135
}

136 137
SerializedHandleChecker::SerializedHandleChecker(Isolate* isolate,
                                                 std::vector<Context>* contexts)
138 139 140 141 142 143 144
    : isolate_(isolate) {
  AddToSet(isolate->heap()->serialized_objects());
  for (auto const& context : *contexts) {
    AddToSet(context->serialized_objects());
  }
}

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
bool StartupSerializer::SerializeUsingReadOnlyObjectCache(
    SnapshotByteSink* sink, HeapObject* obj, HowToCode how_to_code,
    WhereToPoint where_to_point, int skip) {
  return read_only_serializer_->SerializeUsingReadOnlyObjectCache(
      sink, obj, how_to_code, where_to_point, skip);
}

void StartupSerializer::SerializeUsingPartialSnapshotCache(
    SnapshotByteSink* sink, HeapObject* obj, HowToCode how_to_code,
    WhereToPoint where_to_point, int skip) {
  FlushSkip(sink, skip);

  int cache_index = SerializeInObjectCache(obj);
  sink->Put(kPartialSnapshotCache + how_to_code + where_to_point,
            "PartialSnapshotCache");
  sink->PutInt(cache_index, "partial_snapshot_cache_index");
}

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

168 169
void SerializedHandleChecker::VisitRootPointers(Root root,
                                                const char* description,
170 171 172
                                                FullObjectSlot start,
                                                FullObjectSlot end) {
  for (FullObjectSlot p = start; p < end; ++p) {
173 174 175
    if (serialized_.find(*p) != serialized_.end()) continue;
    PrintF("%s handle not serialized: ",
           root == Root::kGlobalHandles ? "global" : "eternal");
176
    (*p)->Print();
177 178 179 180 181 182 183 184 185 186
    ok_ = false;
  }
}

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

187 188
}  // namespace internal
}  // namespace v8