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/code-serializer.h"
      6 
      7 #include <memory>
      8 
      9 #include "src/code-stubs.h"
     10 #include "src/counters.h"
     11 #include "src/debug/debug.h"
     12 #include "src/log.h"
     13 #include "src/macro-assembler.h"
     14 #include "src/objects-inl.h"
     15 #include "src/snapshot/object-deserializer.h"
     16 #include "src/snapshot/snapshot.h"
     17 #include "src/version.h"
     18 #include "src/visitors.h"
     19 
     20 namespace v8 {
     21 namespace internal {
     22 
     23 ScriptData::ScriptData(const byte* data, int length)
     24     : owns_data_(false), rejected_(false), data_(data), length_(length) {
     25   if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) {
     26     byte* copy = NewArray<byte>(length);
     27     DCHECK(IsAligned(reinterpret_cast<intptr_t>(copy), kPointerAlignment));
     28     CopyBytes(copy, data, length);
     29     data_ = copy;
     30     AcquireDataOwnership();
     31   }
     32 }
     33 
     34 CodeSerializer::CodeSerializer(Isolate* isolate, uint32_t source_hash)
     35     : Serializer(isolate), source_hash_(source_hash) {
     36   allocator()->UseCustomChunkSize(FLAG_serialization_chunk_size);
     37 }
     38 
     39 // static
     40 ScriptCompiler::CachedData* CodeSerializer::Serialize(
     41     Handle<SharedFunctionInfo> info) {
     42   Isolate* isolate = info->GetIsolate();
     43   TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute");
     44   HistogramTimerScope histogram_timer(isolate->counters()->compile_serialize());
     45   RuntimeCallTimerScope runtimeTimer(isolate,
     46                                      RuntimeCallCounterId::kCompileSerialize);
     47   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileSerialize");
     48 
     49   base::ElapsedTimer timer;
     50   if (FLAG_profile_deserialization) timer.Start();
     51   Handle<Script> script(Script::cast(info->script()), isolate);
     52   if (FLAG_trace_serializer) {
     53     PrintF("[Serializing from");
     54     script->name()->ShortPrint();
     55     PrintF("]\n");
     56   }
     57   // TODO(7110): Enable serialization of Asm modules once the AsmWasmData is
     58   // context independent.
     59   if (script->ContainsAsmModule()) return nullptr;
     60 
     61   isolate->heap()->read_only_space()->ClearStringPaddingIfNeeded();
     62 
     63   // Serialize code object.
     64   Handle<String> source(String::cast(script->source()), isolate);
     65   CodeSerializer cs(isolate, SerializedCodeData::SourceHash(
     66                                  source, script->origin_options()));
     67   DisallowHeapAllocation no_gc;
     68   cs.reference_map()->AddAttachedReference(*source);
     69   ScriptData* script_data = cs.SerializeSharedFunctionInfo(info);
     70 
     71   if (FLAG_profile_deserialization) {
     72     double ms = timer.Elapsed().InMillisecondsF();
     73     int length = script_data->length();
     74     PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms);
     75   }
     76 
     77   ScriptCompiler::CachedData* result =
     78       new ScriptCompiler::CachedData(script_data->data(), script_data->length(),
     79                                      ScriptCompiler::CachedData::BufferOwned);
     80   script_data->ReleaseDataOwnership();
     81   delete script_data;
     82 
     83   return result;
     84 }
     85 
     86 ScriptData* CodeSerializer::SerializeSharedFunctionInfo(
     87     Handle<SharedFunctionInfo> info) {
     88   DisallowHeapAllocation no_gc;
     89 
     90   VisitRootPointer(Root::kHandleScope, nullptr,
     91                    Handle<Object>::cast(info).location());
     92   SerializeDeferredObjects();
     93   Pad();
     94 
     95   SerializedCodeData data(sink_.data(), this);
     96 
     97   return data.GetScriptData();
     98 }
     99 
    100 bool CodeSerializer::SerializeReadOnlyObject(HeapObject* obj,
    101                                              HowToCode how_to_code,
    102                                              WhereToPoint where_to_point,
    103                                              int skip) {
    104   PagedSpace* read_only_space = isolate()->heap()->read_only_space();
    105   if (!read_only_space->Contains(obj)) return false;
    106 
    107   // For objects in RO_SPACE, never serialize the object, but instead create a
    108   // back reference that encodes the page number as the chunk_index and the
    109   // offset within the page as the chunk_offset.
    110   Address address = obj->address();
    111   Page* page = Page::FromAddress(address);
    112   uint32_t chunk_index = 0;
    113   for (Page* p : *read_only_space) {
    114     if (p == page) break;
    115     ++chunk_index;
    116   }
    117   uint32_t chunk_offset = static_cast<uint32_t>(page->Offset(address));
    118   SerializerReference back_reference =
    119       SerializerReference::BackReference(RO_SPACE, chunk_index, chunk_offset);
    120   reference_map()->Add(obj, back_reference);
    121   CHECK(SerializeBackReference(obj, how_to_code, where_to_point, skip));
    122   return true;
    123 }
    124 
    125 void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
    126                                      WhereToPoint where_to_point, int skip) {
    127   if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
    128 
    129   int root_index = root_index_map()->Lookup(obj);
    130   if (root_index != RootIndexMap::kInvalidRootIndex) {
    131     PutRoot(root_index, obj, how_to_code, where_to_point, skip);
    132     return;
    133   }
    134 
    135   if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
    136 
    137   if (SerializeReadOnlyObject(obj, how_to_code, where_to_point, skip)) return;
    138 
    139   FlushSkip(skip);
    140 
    141   if (obj->IsCode()) {
    142     Code* code_object = Code::cast(obj);
    143     switch (code_object->kind()) {
    144       case Code::OPTIMIZED_FUNCTION:  // No optimized code compiled yet.
    145       case Code::REGEXP:              // No regexp literals initialized yet.
    146       case Code::NUMBER_OF_KINDS:     // Pseudo enum value.
    147       case Code::BYTECODE_HANDLER:    // No direct references to handlers.
    148         break;                        // hit UNREACHABLE below.
    149       case Code::BUILTIN:
    150         SerializeBuiltinReference(code_object, how_to_code, where_to_point, 0);
    151         return;
    152       case Code::STUB:
    153         if (code_object->builtin_index() == -1) {
    154           SerializeCodeStub(code_object, how_to_code, where_to_point);
    155         } else {
    156           SerializeBuiltinReference(code_object, how_to_code, where_to_point,
    157                                     0);
    158         }
    159         return;
    160       default:
    161         return SerializeCodeObject(code_object, how_to_code, where_to_point);
    162     }
    163     UNREACHABLE();
    164   }
    165 
    166   ReadOnlyRoots roots(isolate());
    167   if (ElideObject(obj)) {
    168     return SerializeObject(roots.undefined_value(), how_to_code, where_to_point,
    169                            skip);
    170   }
    171 
    172   if (obj->IsScript()) {
    173     Script* script_obj = Script::cast(obj);
    174     DCHECK_NE(script_obj->compilation_type(), Script::COMPILATION_TYPE_EVAL);
    175     // We want to differentiate between undefined and uninitialized_symbol for
    176     // context_data for now. It is hack to allow debugging for scripts that are
    177     // included as a part of custom snapshot. (see debug::Script::IsEmbedded())
    178     Object* context_data = script_obj->context_data();
    179     if (context_data != roots.undefined_value() &&
    180         context_data != roots.uninitialized_symbol()) {
    181       script_obj->set_context_data(roots.undefined_value());
    182     }
    183     // We don't want to serialize host options to avoid serializing unnecessary
    184     // object graph.
    185     FixedArray* host_options = script_obj->host_defined_options();
    186     script_obj->set_host_defined_options(roots.empty_fixed_array());
    187     SerializeGeneric(obj, how_to_code, where_to_point);
    188     script_obj->set_host_defined_options(host_options);
    189     script_obj->set_context_data(context_data);
    190     return;
    191   }
    192 
    193   if (obj->IsSharedFunctionInfo()) {
    194     SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
    195     // TODO(7110): Enable serializing of Asm modules once the AsmWasmData
    196     // is context independent.
    197     DCHECK(!sfi->IsApiFunction() && !sfi->HasAsmWasmData());
    198 
    199     DebugInfo* debug_info = nullptr;
    200     BytecodeArray* debug_bytecode_array = nullptr;
    201     if (sfi->HasDebugInfo()) {
    202       // Clear debug info.
    203       debug_info = sfi->GetDebugInfo();
    204       if (debug_info->HasInstrumentedBytecodeArray()) {
    205         debug_bytecode_array = debug_info->DebugBytecodeArray();
    206         sfi->SetDebugBytecodeArray(debug_info->OriginalBytecodeArray());
    207       }
    208       sfi->set_script_or_debug_info(debug_info->script());
    209     }
    210     DCHECK(!sfi->HasDebugInfo());
    211 
    212     // Mark SFI to indicate whether the code is cached.
    213     bool was_deserialized = sfi->deserialized();
    214     sfi->set_deserialized(sfi->is_compiled());
    215     SerializeGeneric(obj, how_to_code, where_to_point);
    216     sfi->set_deserialized(was_deserialized);
    217 
    218     // Restore debug info
    219     if (debug_info != nullptr) {
    220       sfi->set_script_or_debug_info(debug_info);
    221       if (debug_bytecode_array != nullptr) {
    222         sfi->SetDebugBytecodeArray(debug_bytecode_array);
    223       }
    224     }
    225     return;
    226   }
    227 
    228   if (obj->IsBytecodeArray()) {
    229     // Clear the stack frame cache if present
    230     BytecodeArray::cast(obj)->ClearFrameCacheFromSourcePositionTable();
    231   }
    232 
    233   // Past this point we should not see any (context-specific) maps anymore.
    234   CHECK(!obj->IsMap());
    235   // There should be no references to the global object embedded.
    236   CHECK(!obj->IsJSGlobalProxy() && !obj->IsJSGlobalObject());
    237   // Embedded FixedArrays that need rehashing must support rehashing.
    238   CHECK_IMPLIES(obj->NeedsRehashing(), obj->CanBeRehashed());
    239   // We expect no instantiated function objects or contexts.
    240   CHECK(!obj->IsJSFunction() && !obj->IsContext());
    241 
    242   SerializeGeneric(obj, how_to_code, where_to_point);
    243 }
    244 
    245 void CodeSerializer::SerializeGeneric(HeapObject* heap_object,
    246                                       HowToCode how_to_code,
    247                                       WhereToPoint where_to_point) {
    248   // Object has not yet been serialized.  Serialize it here.
    249   ObjectSerializer serializer(this, heap_object, &sink_, how_to_code,
    250                               where_to_point);
    251   serializer.Serialize();
    252 }
    253 
    254 void CodeSerializer::SerializeCodeStub(Code* code_stub, HowToCode how_to_code,
    255                                        WhereToPoint where_to_point) {
    256   // We only arrive here if we have not encountered this code stub before.
    257   DCHECK(!reference_map()->LookupReference(code_stub).is_valid());
    258   uint32_t stub_key = code_stub->stub_key();
    259   DCHECK(CodeStub::MajorKeyFromKey(stub_key) != CodeStub::NoCache);
    260   DCHECK(!CodeStub::GetCode(isolate(), stub_key).is_null());
    261   stub_keys_.push_back(stub_key);
    262 
    263   SerializerReference reference =
    264       reference_map()->AddAttachedReference(code_stub);
    265   if (FLAG_trace_serializer) {
    266     PrintF(" Encoding code stub %s as attached reference %d\n",
    267            CodeStub::MajorName(CodeStub::MajorKeyFromKey(stub_key)),
    268            reference.attached_reference_index());
    269   }
    270   PutAttachedReference(reference, how_to_code, where_to_point);
    271 }
    272 
    273 MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
    274     Isolate* isolate, ScriptData* cached_data, Handle<String> source,
    275     ScriptOriginOptions origin_options) {
    276   base::ElapsedTimer timer;
    277   if (FLAG_profile_deserialization || FLAG_log_function_events) timer.Start();
    278 
    279   HandleScope scope(isolate);
    280 
    281   SerializedCodeData::SanityCheckResult sanity_check_result =
    282       SerializedCodeData::CHECK_SUCCESS;
    283   const SerializedCodeData scd = SerializedCodeData::FromCachedData(
    284       isolate, cached_data,
    285       SerializedCodeData::SourceHash(source, origin_options),
    286       &sanity_check_result);
    287   if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) {
    288     if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n");
    289     DCHECK(cached_data->rejected());
    290     isolate->counters()->code_cache_reject_reason()->AddSample(
    291         sanity_check_result);
    292     return MaybeHandle<SharedFunctionInfo>();
    293   }
    294 
    295   // Deserialize.
    296   MaybeHandle<SharedFunctionInfo> maybe_result =
    297       ObjectDeserializer::DeserializeSharedFunctionInfo(isolate, &scd, source);
    298 
    299   Handle<SharedFunctionInfo> result;
    300   if (!maybe_result.ToHandle(&result)) {
    301     // Deserializing may fail if the reservations cannot be fulfilled.
    302     if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n");
    303     return MaybeHandle<SharedFunctionInfo>();
    304   }
    305 
    306   if (FLAG_profile_deserialization) {
    307     double ms = timer.Elapsed().InMillisecondsF();
    308     int length = cached_data->length();
    309     PrintF("[Deserializing from %d bytes took %0.3f ms]\n", length, ms);
    310   }
    311 
    312   bool log_code_creation = isolate->logger()->is_listening_to_code_events() ||
    313                            isolate->is_profiling();
    314   if (log_code_creation || FLAG_log_function_events) {
    315     String* name = ReadOnlyRoots(isolate).empty_string();
    316     if (result->script()->IsScript()) {
    317       Script* script = Script::cast(result->script());
    318       if (script->name()->IsString()) name = String::cast(script->name());
    319       if (FLAG_log_function_events) {
    320         LOG(isolate, FunctionEvent("deserialize", script->id(),
    321                                    timer.Elapsed().InMillisecondsF(),
    322                                    result->StartPosition(),
    323                                    result->EndPosition(), name));
    324       }
    325     }
    326     if (log_code_creation) {
    327       PROFILE(isolate, CodeCreateEvent(CodeEventListener::SCRIPT_TAG,
    328                                        result->abstract_code(), *result, name));
    329     }
    330   }
    331 
    332   if (isolate->NeedsSourcePositionsForProfiling()) {
    333     Handle<Script> script(Script::cast(result->script()), isolate);
    334     Script::InitLineEnds(script);
    335   }
    336   return scope.CloseAndEscape(result);
    337 }
    338 
    339 class Checksum {
    340  public:
    341   explicit Checksum(Vector<const byte> payload) {
    342 #ifdef MEMORY_SANITIZER
    343     // Computing the checksum includes padding bytes for objects like strings.
    344     // Mark every object as initialized in the code serializer.
    345     MSAN_MEMORY_IS_INITIALIZED(payload.start(), payload.length());
    346 #endif  // MEMORY_SANITIZER
    347     // Fletcher's checksum. Modified to reduce 64-bit sums to 32-bit.
    348     uintptr_t a = 1;
    349     uintptr_t b = 0;
    350     const uintptr_t* cur = reinterpret_cast<const uintptr_t*>(payload.start());
    351     DCHECK(IsAligned(payload.length(), kIntptrSize));
    352     const uintptr_t* end = cur + payload.length() / kIntptrSize;
    353     while (cur < end) {
    354       // Unsigned overflow expected and intended.
    355       a += *cur++;
    356       b += a;
    357     }
    358 #if V8_HOST_ARCH_64_BIT
    359     a ^= a >> 32;
    360     b ^= b >> 32;
    361 #endif  // V8_HOST_ARCH_64_BIT
    362     a_ = static_cast<uint32_t>(a);
    363     b_ = static_cast<uint32_t>(b);
    364   }
    365 
    366   bool Check(uint32_t a, uint32_t b) const { return a == a_ && b == b_; }
    367 
    368   uint32_t a() const { return a_; }
    369   uint32_t b() const { return b_; }
    370 
    371  private:
    372   uint32_t a_;
    373   uint32_t b_;
    374 
    375   DISALLOW_COPY_AND_ASSIGN(Checksum);
    376 };
    377 
    378 SerializedCodeData::SerializedCodeData(const std::vector<byte>* payload,
    379                                        const CodeSerializer* cs) {
    380   DisallowHeapAllocation no_gc;
    381   const std::vector<uint32_t>* stub_keys = cs->stub_keys();
    382   std::vector<Reservation> reservations = cs->EncodeReservations();
    383 
    384   // Calculate sizes.
    385   uint32_t reservation_size =
    386       static_cast<uint32_t>(reservations.size()) * kUInt32Size;
    387   uint32_t num_stub_keys = static_cast<uint32_t>(stub_keys->size());
    388   uint32_t stub_keys_size = num_stub_keys * kUInt32Size;
    389   uint32_t payload_offset = kHeaderSize + reservation_size + stub_keys_size;
    390   uint32_t padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset);
    391   uint32_t size =
    392       padded_payload_offset + static_cast<uint32_t>(payload->size());
    393 
    394   // Allocate backing store and create result data.
    395   AllocateData(size);
    396 
    397   // Set header values.
    398   SetMagicNumber(cs->isolate());
    399   SetHeaderValue(kVersionHashOffset, Version::Hash());
    400   SetHeaderValue(kSourceHashOffset, cs->source_hash());
    401   SetHeaderValue(kCpuFeaturesOffset,
    402                  static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
    403   SetHeaderValue(kFlagHashOffset, FlagList::Hash());
    404   SetHeaderValue(kNumReservationsOffset,
    405                  static_cast<uint32_t>(reservations.size()));
    406   SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
    407   SetHeaderValue(kPayloadLengthOffset, static_cast<uint32_t>(payload->size()));
    408 
    409   // Zero out any padding in the header.
    410   memset(data_ + kUnalignedHeaderSize, 0, kHeaderSize - kUnalignedHeaderSize);
    411 
    412   // Copy reservation chunk sizes.
    413   CopyBytes(data_ + kHeaderSize,
    414             reinterpret_cast<const byte*>(reservations.data()),
    415             reservation_size);
    416 
    417   // Copy code stub keys.
    418   CopyBytes(data_ + kHeaderSize + reservation_size,
    419             reinterpret_cast<const byte*>(stub_keys->data()), stub_keys_size);
    420 
    421   // Zero out any padding before the payload.
    422   memset(data_ + payload_offset, 0, padded_payload_offset - payload_offset);
    423 
    424   // Copy serialized data.
    425   CopyBytes(data_ + padded_payload_offset, payload->data(),
    426             static_cast<size_t>(payload->size()));
    427 
    428   Checksum checksum(DataWithoutHeader());
    429   SetHeaderValue(kChecksum1Offset, checksum.a());
    430   SetHeaderValue(kChecksum2Offset, checksum.b());
    431 }
    432 
    433 SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
    434     Isolate* isolate, uint32_t expected_source_hash) const {
    435   if (this->size_ < kHeaderSize) return INVALID_HEADER;
    436   uint32_t magic_number = GetMagicNumber();
    437   if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
    438   uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
    439   uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
    440   uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
    441   uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
    442   uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
    443   uint32_t c1 = GetHeaderValue(kChecksum1Offset);
    444   uint32_t c2 = GetHeaderValue(kChecksum2Offset);
    445   if (version_hash != Version::Hash()) return VERSION_MISMATCH;
    446   if (source_hash != expected_source_hash) return SOURCE_MISMATCH;
    447   if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) {
    448     return CPU_FEATURES_MISMATCH;
    449   }
    450   if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
    451   uint32_t max_payload_length =
    452       this->size_ -
    453       POINTER_SIZE_ALIGN(kHeaderSize +
    454                          GetHeaderValue(kNumReservationsOffset) * kInt32Size +
    455                          GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size);
    456   if (payload_length > max_payload_length) return LENGTH_MISMATCH;
    457   if (!Checksum(DataWithoutHeader()).Check(c1, c2)) return CHECKSUM_MISMATCH;
    458   return CHECK_SUCCESS;
    459 }
    460 
    461 uint32_t SerializedCodeData::SourceHash(Handle<String> source,
    462                                         ScriptOriginOptions origin_options) {
    463   const uint32_t source_length = source->length();
    464 
    465   static constexpr uint32_t kModuleFlagMask = (1 << 31);
    466   const uint32_t is_module = origin_options.IsModule() ? kModuleFlagMask : 0;
    467   DCHECK_EQ(0, source_length & kModuleFlagMask);
    468 
    469   return source_length | is_module;
    470 }
    471 
    472 // Return ScriptData object and relinquish ownership over it to the caller.
    473 ScriptData* SerializedCodeData::GetScriptData() {
    474   DCHECK(owns_data_);
    475   ScriptData* result = new ScriptData(data_, size_);
    476   result->AcquireDataOwnership();
    477   owns_data_ = false;
    478   data_ = nullptr;
    479   return result;
    480 }
    481 
    482 std::vector<SerializedData::Reservation> SerializedCodeData::Reservations()
    483     const {
    484   uint32_t size = GetHeaderValue(kNumReservationsOffset);
    485   std::vector<Reservation> reservations(size);
    486   memcpy(reservations.data(), data_ + kHeaderSize,
    487          size * sizeof(SerializedData::Reservation));
    488   return reservations;
    489 }
    490 
    491 Vector<const byte> SerializedCodeData::Payload() const {
    492   int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size;
    493   int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size;
    494   int payload_offset = kHeaderSize + reservations_size + code_stubs_size;
    495   int padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset);
    496   const byte* payload = data_ + padded_payload_offset;
    497   DCHECK(IsAligned(reinterpret_cast<intptr_t>(payload), kPointerAlignment));
    498   int length = GetHeaderValue(kPayloadLengthOffset);
    499   DCHECK_EQ(data_ + size_, payload + length);
    500   return Vector<const byte>(payload, length);
    501 }
    502 
    503 Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const {
    504   int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size;
    505   const byte* start = data_ + kHeaderSize + reservations_size;
    506   return Vector<const uint32_t>(reinterpret_cast<const uint32_t*>(start),
    507                                 GetHeaderValue(kNumCodeStubKeysOffset));
    508 }
    509 
    510 SerializedCodeData::SerializedCodeData(ScriptData* data)
    511     : SerializedData(const_cast<byte*>(data->data()), data->length()) {}
    512 
    513 SerializedCodeData SerializedCodeData::FromCachedData(
    514     Isolate* isolate, ScriptData* cached_data, uint32_t expected_source_hash,
    515     SanityCheckResult* rejection_result) {
    516   DisallowHeapAllocation no_gc;
    517   SerializedCodeData scd(cached_data);
    518   *rejection_result = scd.SanityCheck(isolate, expected_source_hash);
    519   if (*rejection_result != CHECK_SUCCESS) {
    520     cached_data->Reject();
    521     return SerializedCodeData(nullptr, 0);
    522   }
    523   return scd;
    524 }
    525 
    526 }  // namespace internal
    527 }  // namespace v8
    528