Home | History | Annotate | Download | only in snapshot
      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/partial-serializer.h"
      6 #include "src/snapshot/startup-serializer.h"
      7 
      8 #include "src/objects-inl.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 
     13 PartialSerializer::PartialSerializer(
     14     Isolate* isolate, StartupSerializer* startup_serializer,
     15     v8::SerializeInternalFieldsCallback callback)
     16     : Serializer(isolate),
     17       startup_serializer_(startup_serializer),
     18       serialize_internal_fields_(callback) {
     19   InitializeCodeAddressMap();
     20 }
     21 
     22 PartialSerializer::~PartialSerializer() {
     23   OutputStatistics("PartialSerializer");
     24 }
     25 
     26 void PartialSerializer::Serialize(Object** o, bool include_global_proxy) {
     27   if ((*o)->IsContext()) {
     28     Context* context = Context::cast(*o);
     29     reference_map()->AddAttachedReference(context->global_proxy());
     30     // The bootstrap snapshot has a code-stub context. When serializing the
     31     // partial snapshot, it is chained into the weak context list on the isolate
     32     // and it's next context pointer may point to the code-stub context.  Clear
     33     // it before serializing, it will get re-added to the context list
     34     // explicitly when it's loaded.
     35     if (context->IsNativeContext()) {
     36       context->set(Context::NEXT_CONTEXT_LINK,
     37                    isolate_->heap()->undefined_value());
     38       DCHECK(!context->global_object()->IsUndefined(context->GetIsolate()));
     39       // Reset math random cache to get fresh random numbers.
     40       context->set_math_random_index(Smi::kZero);
     41       context->set_math_random_cache(isolate_->heap()->undefined_value());
     42     }
     43   }
     44   VisitPointer(o);
     45   SerializeDeferredObjects();
     46   SerializeInternalFields();
     47   Pad();
     48 }
     49 
     50 void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
     51                                         WhereToPoint where_to_point, int skip) {
     52   if (obj->IsMap()) {
     53     // The code-caches link to context-specific code objects, which
     54     // the startup and context serializes cannot currently handle.
     55     DCHECK(Map::cast(obj)->code_cache() == obj->GetHeap()->empty_fixed_array());
     56   }
     57 
     58   // Replace typed arrays by undefined.
     59   if (obj->IsJSTypedArray()) obj = isolate_->heap()->undefined_value();
     60 
     61   if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
     62 
     63   int root_index = root_index_map_.Lookup(obj);
     64   if (root_index != RootIndexMap::kInvalidRootIndex) {
     65     PutRoot(root_index, obj, how_to_code, where_to_point, skip);
     66     return;
     67   }
     68 
     69   if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
     70 
     71   if (ShouldBeInThePartialSnapshotCache(obj)) {
     72     FlushSkip(skip);
     73 
     74     int cache_index = startup_serializer_->PartialSnapshotCacheIndex(obj);
     75     sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
     76               "PartialSnapshotCache");
     77     sink_.PutInt(cache_index, "partial_snapshot_cache_index");
     78     return;
     79   }
     80 
     81   // Pointers from the partial snapshot to the objects in the startup snapshot
     82   // should go through the root array or through the partial snapshot cache.
     83   // If this is not the case you may have to add something to the root array.
     84   DCHECK(!startup_serializer_->reference_map()->Lookup(obj).is_valid());
     85   // All the internalized strings that the partial snapshot needs should be
     86   // either in the root table or in the partial snapshot cache.
     87   DCHECK(!obj->IsInternalizedString());
     88   // Function and object templates are not context specific.
     89   DCHECK(!obj->IsTemplateInfo());
     90 
     91   FlushSkip(skip);
     92 
     93   // Clear literal boilerplates.
     94   if (obj->IsJSFunction()) {
     95     JSFunction* function = JSFunction::cast(obj);
     96     function->ClearTypeFeedbackInfo();
     97   }
     98 
     99   if (obj->IsJSObject()) {
    100     JSObject* jsobj = JSObject::cast(obj);
    101     if (jsobj->GetInternalFieldCount() > 0) {
    102       DCHECK_NOT_NULL(serialize_internal_fields_.callback);
    103       internal_field_holders_.Add(jsobj);
    104     }
    105   }
    106 
    107   // Object has not yet been serialized.  Serialize it here.
    108   ObjectSerializer serializer(this, obj, &sink_, how_to_code, where_to_point);
    109   serializer.Serialize();
    110 }
    111 
    112 bool PartialSerializer::ShouldBeInThePartialSnapshotCache(HeapObject* o) {
    113   // Scripts should be referred only through shared function infos.  We can't
    114   // allow them to be part of the partial snapshot because they contain a
    115   // unique ID, and deserializing several partial snapshots containing script
    116   // would cause dupes.
    117   DCHECK(!o->IsScript());
    118   return o->IsName() || o->IsSharedFunctionInfo() || o->IsHeapNumber() ||
    119          o->IsCode() || o->IsScopeInfo() || o->IsAccessorInfo() ||
    120          o->IsTemplateInfo() ||
    121          o->map() ==
    122              startup_serializer_->isolate()->heap()->fixed_cow_array_map();
    123 }
    124 
    125 void PartialSerializer::SerializeInternalFields() {
    126   int count = internal_field_holders_.length();
    127   if (count == 0) return;
    128   DisallowHeapAllocation no_gc;
    129   DisallowJavascriptExecution no_js(isolate());
    130   DisallowCompilation no_compile(isolate());
    131   DCHECK_NOT_NULL(serialize_internal_fields_.callback);
    132   sink_.Put(kInternalFieldsData, "internal fields data");
    133   while (internal_field_holders_.length() > 0) {
    134     HandleScope scope(isolate());
    135     Handle<JSObject> obj(internal_field_holders_.RemoveLast(), isolate());
    136     SerializerReference reference = reference_map_.Lookup(*obj);
    137     DCHECK(reference.is_back_reference());
    138     int internal_fields_count = obj->GetInternalFieldCount();
    139     for (int i = 0; i < internal_fields_count; i++) {
    140       if (obj->GetInternalField(i)->IsHeapObject()) continue;
    141       StartupData data = serialize_internal_fields_.callback(
    142           v8::Utils::ToLocal(obj), i, serialize_internal_fields_.data);
    143       sink_.Put(kNewObject + reference.space(), "internal field holder");
    144       PutBackReference(*obj, reference);
    145       sink_.PutInt(i, "internal field index");
    146       sink_.PutInt(data.raw_size, "internal fields data size");
    147       sink_.PutRaw(reinterpret_cast<const byte*>(data.data), data.raw_size,
    148                    "internal fields data");
    149       delete[] data.data;
    150     }
    151   }
    152   sink_.Put(kSynchronize, "Finished with internal fields data");
    153 }
    154 
    155 }  // namespace internal
    156 }  // namespace v8
    157