Line data Source code
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/log.h"
12 : #include "src/macro-assembler.h"
13 : #include "src/objects-inl.h"
14 : #include "src/snapshot/deserializer.h"
15 : #include "src/snapshot/snapshot.h"
16 : #include "src/version.h"
17 : #include "src/visitors.h"
18 : #include "src/wasm/wasm-module.h"
19 : #include "src/wasm/wasm-objects.h"
20 :
21 : namespace v8 {
22 : namespace internal {
23 :
24 407 : ScriptData* CodeSerializer::Serialize(Isolate* isolate,
25 : Handle<SharedFunctionInfo> info,
26 : Handle<String> source) {
27 : base::ElapsedTimer timer;
28 407 : if (FLAG_profile_deserialization) timer.Start();
29 407 : if (FLAG_trace_serializer) {
30 0 : PrintF("[Serializing from");
31 : Object* script = info->script();
32 0 : if (script->IsScript()) Script::cast(script)->name()->ShortPrint();
33 0 : PrintF("]\n");
34 : }
35 :
36 : // Serialize code object.
37 : CodeSerializer cs(isolate, SerializedCodeData::SourceHash(source));
38 : DisallowHeapAllocation no_gc;
39 407 : cs.reference_map()->AddAttachedReference(*source);
40 407 : ScriptData* ret = cs.Serialize(info);
41 :
42 407 : if (FLAG_profile_deserialization) {
43 0 : double ms = timer.Elapsed().InMillisecondsF();
44 : int length = ret->length();
45 0 : PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms);
46 : }
47 :
48 407 : return ret;
49 : }
50 :
51 557 : ScriptData* CodeSerializer::Serialize(Handle<HeapObject> obj) {
52 : DisallowHeapAllocation no_gc;
53 :
54 557 : VisitRootPointer(Root::kHandleScope, Handle<Object>::cast(obj).location());
55 557 : SerializeDeferredObjects();
56 557 : Pad();
57 :
58 557 : SerializedCodeData data(sink()->data(), this);
59 :
60 1114 : return data.GetScriptData();
61 : }
62 :
63 265143 : void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
64 : WhereToPoint where_to_point, int skip) {
65 266378 : if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
66 :
67 214233 : int root_index = root_index_map_.Lookup(obj);
68 214233 : if (root_index != RootIndexMap::kInvalidRootIndex) {
69 117239 : PutRoot(root_index, obj, how_to_code, where_to_point, skip);
70 117239 : return;
71 : }
72 :
73 96994 : if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
74 :
75 70041 : FlushSkip(skip);
76 :
77 70041 : if (obj->IsCode()) {
78 : Code* code_object = Code::cast(obj);
79 18283 : switch (code_object->kind()) {
80 : case Code::OPTIMIZED_FUNCTION: // No optimized code compiled yet.
81 : case Code::HANDLER: // No handlers patched in yet.
82 : case Code::REGEXP: // No regexp literals initialized yet.
83 : case Code::NUMBER_OF_KINDS: // Pseudo enum value.
84 : case Code::BYTECODE_HANDLER: // No direct references to handlers.
85 0 : CHECK(false);
86 : case Code::BUILTIN:
87 : SerializeBuiltin(code_object->builtin_index(), how_to_code,
88 15608 : where_to_point);
89 15608 : return;
90 : case Code::STUB:
91 : #define IC_KIND_CASE(KIND) case Code::KIND:
92 : IC_KIND_LIST(IC_KIND_CASE)
93 : #undef IC_KIND_CASE
94 1844 : if (code_object->builtin_index() == -1) {
95 508 : SerializeCodeStub(code_object, how_to_code, where_to_point);
96 : } else {
97 : SerializeBuiltin(code_object->builtin_index(), how_to_code,
98 1336 : where_to_point);
99 : }
100 : return;
101 : case Code::FUNCTION:
102 : DCHECK(code_object->has_reloc_info_for_serialization());
103 366 : SerializeGeneric(code_object, how_to_code, where_to_point);
104 366 : return;
105 : default:
106 465 : return SerializeCodeObject(code_object, how_to_code, where_to_point);
107 : }
108 : UNREACHABLE();
109 : }
110 :
111 51758 : if (ElideObject(obj)) {
112 690 : return SerializeObject(isolate()->heap()->undefined_value(), how_to_code,
113 1380 : where_to_point, skip);
114 : }
115 :
116 51068 : if (obj->IsScript()) {
117 : // Wrapper object is a context-dependent JSValue. Reset it here.
118 545 : Script::cast(obj)->set_wrapper(isolate()->heap()->undefined_value());
119 : }
120 :
121 : // Past this point we should not see any (context-specific) maps anymore.
122 51068 : CHECK(!obj->IsMap());
123 : // There should be no references to the global object embedded.
124 102136 : CHECK(!obj->IsJSGlobalProxy() && !obj->IsJSGlobalObject());
125 : // There should be no hash table embedded. They would require rehashing.
126 51068 : CHECK(!obj->IsHashTable());
127 : // We expect no instantiated function objects or contexts.
128 102136 : CHECK(!obj->IsJSFunction() && !obj->IsContext());
129 :
130 51068 : SerializeGeneric(obj, how_to_code, where_to_point);
131 : }
132 :
133 51839 : void CodeSerializer::SerializeGeneric(HeapObject* heap_object,
134 : HowToCode how_to_code,
135 : WhereToPoint where_to_point) {
136 : // Object has not yet been serialized. Serialize it here.
137 : ObjectSerializer serializer(this, heap_object, &sink_, how_to_code,
138 51839 : where_to_point);
139 51839 : serializer.Serialize();
140 51839 : }
141 :
142 17004 : void CodeSerializer::SerializeBuiltin(int builtin_index, HowToCode how_to_code,
143 : WhereToPoint where_to_point) {
144 : DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
145 : (how_to_code == kPlain && where_to_point == kInnerPointer) ||
146 : (how_to_code == kFromCode && where_to_point == kInnerPointer));
147 : DCHECK_LT(builtin_index, Builtins::builtin_count);
148 : DCHECK_LE(0, builtin_index);
149 :
150 17004 : if (FLAG_trace_serializer) {
151 : PrintF(" Encoding builtin: %s\n",
152 0 : isolate()->builtins()->name(builtin_index));
153 : }
154 :
155 17004 : sink_.Put(kBuiltin + how_to_code + where_to_point, "Builtin");
156 17004 : sink_.PutInt(builtin_index, "builtin_index");
157 17004 : }
158 :
159 508 : void CodeSerializer::SerializeCodeStub(Code* code_stub, HowToCode how_to_code,
160 : WhereToPoint where_to_point) {
161 : // We only arrive here if we have not encountered this code stub before.
162 : DCHECK(!reference_map()->Lookup(code_stub).is_valid());
163 508 : uint32_t stub_key = code_stub->stub_key();
164 : DCHECK(CodeStub::MajorKeyFromKey(stub_key) != CodeStub::NoCache);
165 : DCHECK(!CodeStub::GetCode(isolate(), stub_key).is_null());
166 508 : stub_keys_.Add(stub_key);
167 :
168 : SerializerReference reference =
169 508 : reference_map()->AddAttachedReference(code_stub);
170 508 : if (FLAG_trace_serializer) {
171 : PrintF(" Encoding code stub %s as attached reference %d\n",
172 : CodeStub::MajorName(CodeStub::MajorKeyFromKey(stub_key)),
173 0 : reference.attached_reference_index());
174 : }
175 508 : PutAttachedReference(reference, how_to_code, where_to_point);
176 508 : }
177 :
178 291 : MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
179 540 : Isolate* isolate, ScriptData* cached_data, Handle<String> source) {
180 : base::ElapsedTimer timer;
181 291 : if (FLAG_profile_deserialization) timer.Start();
182 :
183 : HandleScope scope(isolate);
184 :
185 : SerializedCodeData::SanityCheckResult sanity_check_result =
186 291 : SerializedCodeData::CHECK_SUCCESS;
187 : const SerializedCodeData scd = SerializedCodeData::FromCachedData(
188 : isolate, cached_data, SerializedCodeData::SourceHash(source),
189 291 : &sanity_check_result);
190 291 : if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) {
191 18 : if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n");
192 : DCHECK(cached_data->rejected());
193 : source->GetIsolate()->counters()->code_cache_reject_reason()->AddSample(
194 36 : sanity_check_result);
195 : return MaybeHandle<SharedFunctionInfo>();
196 : }
197 :
198 546 : Deserializer deserializer(&scd);
199 : deserializer.AddAttachedObject(source);
200 : Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys();
201 464 : for (int i = 0; i < code_stub_keys.length(); i++) {
202 : deserializer.AddAttachedObject(
203 382 : CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked());
204 : }
205 :
206 : // Deserialize.
207 : Handle<HeapObject> as_heap_object;
208 546 : if (!deserializer.DeserializeObject(isolate).ToHandle(&as_heap_object)) {
209 : // Deserializing may fail if the reservations cannot be fulfilled.
210 0 : if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n");
211 : return MaybeHandle<SharedFunctionInfo>();
212 : }
213 :
214 : Handle<SharedFunctionInfo> result =
215 : Handle<SharedFunctionInfo>::cast(as_heap_object);
216 273 : if (FLAG_profile_deserialization) {
217 0 : double ms = timer.Elapsed().InMillisecondsF();
218 : int length = cached_data->length();
219 0 : PrintF("[Deserializing from %d bytes took %0.3f ms]\n", length, ms);
220 : }
221 273 : result->set_deserialized(true);
222 :
223 540 : if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
224 6 : String* name = isolate->heap()->empty_string();
225 6 : if (result->script()->IsScript()) {
226 : Script* script = Script::cast(result->script());
227 6 : if (script->name()->IsString()) name = String::cast(script->name());
228 : }
229 6 : PROFILE(isolate, CodeCreateEvent(CodeEventListener::SCRIPT_TAG,
230 : result->abstract_code(), *result, name));
231 : }
232 273 : return scope.CloseAndEscape(result);
233 : }
234 :
235 150 : WasmCompiledModuleSerializer::WasmCompiledModuleSerializer(
236 : Isolate* isolate, uint32_t source_hash, Handle<Context> native_context,
237 : Handle<SeqOneByteString> module_bytes)
238 150 : : CodeSerializer(isolate, source_hash) {
239 300 : reference_map()->AddAttachedReference(*isolate->native_context());
240 150 : reference_map()->AddAttachedReference(*module_bytes);
241 150 : }
242 :
243 150 : std::unique_ptr<ScriptData> WasmCompiledModuleSerializer::SerializeWasmModule(
244 : Isolate* isolate, Handle<FixedArray> input) {
245 : Handle<WasmCompiledModule> compiled_module =
246 : Handle<WasmCompiledModule>::cast(input);
247 : WasmCompiledModuleSerializer wasm_cs(isolate, 0, isolate->native_context(),
248 300 : handle(compiled_module->module_bytes()));
249 150 : ScriptData* data = wasm_cs.Serialize(compiled_module);
250 150 : return std::unique_ptr<ScriptData>(data);
251 : }
252 :
253 174 : MaybeHandle<FixedArray> WasmCompiledModuleSerializer::DeserializeWasmModule(
254 : Isolate* isolate, ScriptData* data, Vector<const byte> wire_bytes) {
255 : MaybeHandle<FixedArray> nothing;
256 174 : if (!wasm::IsWasmCodegenAllowed(isolate, isolate->native_context())) {
257 7 : return nothing;
258 : }
259 : SerializedCodeData::SanityCheckResult sanity_check_result =
260 167 : SerializedCodeData::CHECK_SUCCESS;
261 :
262 : const SerializedCodeData scd = SerializedCodeData::FromCachedData(
263 167 : isolate, data, 0, &sanity_check_result);
264 :
265 167 : if (sanity_check_result != SerializedCodeData::CHECK_SUCCESS) {
266 55 : return nothing;
267 : }
268 :
269 224 : Deserializer deserializer(&scd, true);
270 112 : deserializer.AddAttachedObject(isolate->native_context());
271 :
272 : MaybeHandle<String> maybe_wire_bytes_as_string =
273 112 : isolate->factory()->NewStringFromOneByte(wire_bytes, TENURED);
274 : Handle<String> wire_bytes_as_string;
275 112 : if (!maybe_wire_bytes_as_string.ToHandle(&wire_bytes_as_string)) {
276 0 : return nothing;
277 : }
278 : deserializer.AddAttachedObject(
279 : handle(SeqOneByteString::cast(*wire_bytes_as_string)));
280 :
281 : Vector<const uint32_t> stub_keys = scd.CodeStubKeys();
282 202 : for (int i = 0; i < stub_keys.length(); ++i) {
283 : deserializer.AddAttachedObject(
284 180 : CodeStub::GetCode(isolate, stub_keys[i]).ToHandleChecked());
285 : }
286 :
287 112 : MaybeHandle<HeapObject> obj = deserializer.DeserializeObject(isolate);
288 224 : if (obj.is_null() || !obj.ToHandleChecked()->IsFixedArray()) return nothing;
289 : // Cast without type checks, as the module wrapper is not there yet.
290 : Handle<WasmCompiledModule> compiled_module(
291 : static_cast<WasmCompiledModule*>(*obj.ToHandleChecked()), isolate);
292 :
293 : WasmCompiledModule::ReinitializeAfterDeserialization(isolate,
294 112 : compiled_module);
295 : DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
296 : return compiled_module;
297 : }
298 :
299 465 : void WasmCompiledModuleSerializer::SerializeCodeObject(
300 : Code* code_object, HowToCode how_to_code, WhereToPoint where_to_point) {
301 : Code::Kind kind = code_object->kind();
302 465 : switch (kind) {
303 : case Code::WASM_FUNCTION:
304 : case Code::JS_TO_WASM_FUNCTION:
305 : // Just serialize the code_object.
306 405 : SerializeGeneric(code_object, how_to_code, where_to_point);
307 405 : break;
308 : case Code::WASM_INTERPRETER_ENTRY:
309 : case Code::WASM_TO_JS_FUNCTION:
310 : // Serialize the illegal builtin instead. On instantiation of a
311 : // deserialized module, these will be replaced again.
312 60 : SerializeBuiltin(Builtins::kIllegal, how_to_code, where_to_point);
313 60 : break;
314 : default:
315 0 : UNREACHABLE();
316 : }
317 465 : }
318 :
319 2700 : bool WasmCompiledModuleSerializer::ElideObject(Object* obj) {
320 6870 : return obj->IsWeakCell() || obj->IsForeign() || obj->IsBreakPointInfo();
321 : }
322 :
323 : class Checksum {
324 : public:
325 : explicit Checksum(Vector<const byte> payload) {
326 : #ifdef MEMORY_SANITIZER
327 : // Computing the checksum includes padding bytes for objects like strings.
328 : // Mark every object as initialized in the code serializer.
329 : MSAN_MEMORY_IS_INITIALIZED(payload.start(), payload.length());
330 : #endif // MEMORY_SANITIZER
331 : // Fletcher's checksum. Modified to reduce 64-bit sums to 32-bit.
332 : uintptr_t a = 1;
333 : uintptr_t b = 0;
334 : const uintptr_t* cur = reinterpret_cast<const uintptr_t*>(payload.start());
335 : DCHECK(IsAligned(payload.length(), kIntptrSize));
336 948 : const uintptr_t* end = cur + payload.length() / kIntptrSize;
337 30882252 : while (cur < end) {
338 : // Unsigned overflow expected and intended.
339 30881304 : a += *cur++;
340 30881304 : b += a;
341 : }
342 : #if V8_HOST_ARCH_64_BIT
343 948 : a ^= a >> 32;
344 948 : b ^= b >> 32;
345 : #endif // V8_HOST_ARCH_64_BIT
346 948 : a_ = static_cast<uint32_t>(a);
347 948 : b_ = static_cast<uint32_t>(b);
348 : }
349 :
350 391 : bool Check(uint32_t a, uint32_t b) const { return a == a_ && b == b_; }
351 :
352 : uint32_t a() const { return a_; }
353 : uint32_t b() const { return b_; }
354 :
355 : private:
356 : uint32_t a_;
357 : uint32_t b_;
358 :
359 : DISALLOW_COPY_AND_ASSIGN(Checksum);
360 : };
361 :
362 2785 : SerializedCodeData::SerializedCodeData(const List<byte>* payload,
363 5013 : const CodeSerializer* cs) {
364 : DisallowHeapAllocation no_gc;
365 1114 : const List<uint32_t>* stub_keys = cs->stub_keys();
366 :
367 : List<Reservation> reservations;
368 1114 : cs->EncodeReservations(&reservations);
369 :
370 : // Calculate sizes.
371 557 : int reservation_size = reservations.length() * kInt32Size;
372 : int num_stub_keys = stub_keys->length();
373 557 : int stub_keys_size = stub_keys->length() * kInt32Size;
374 557 : int payload_offset = kHeaderSize + reservation_size + stub_keys_size;
375 557 : int padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset);
376 557 : int size = padded_payload_offset + payload->length();
377 :
378 : // Allocate backing store and create result data.
379 557 : AllocateData(size);
380 :
381 : // Set header values.
382 557 : SetMagicNumber(cs->isolate());
383 557 : SetHeaderValue(kVersionHashOffset, Version::Hash());
384 : SetHeaderValue(kSourceHashOffset, cs->source_hash());
385 : SetHeaderValue(kCpuFeaturesOffset,
386 : static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
387 557 : SetHeaderValue(kFlagHashOffset, FlagList::Hash());
388 557 : SetHeaderValue(kNumReservationsOffset, reservations.length());
389 557 : SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
390 557 : SetHeaderValue(kPayloadLengthOffset, payload->length());
391 :
392 : // Zero out any padding in the header.
393 557 : memset(data_ + kUnalignedHeaderSize, 0, kHeaderSize - kUnalignedHeaderSize);
394 :
395 : // Copy reservation chunk sizes.
396 557 : CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
397 1114 : reservation_size);
398 :
399 : // Copy code stub keys.
400 557 : CopyBytes(data_ + kHeaderSize + reservation_size,
401 1671 : reinterpret_cast<byte*>(stub_keys->begin()), stub_keys_size);
402 :
403 : // Zero out any padding before the payload.
404 557 : memset(data_ + payload_offset, 0, padded_payload_offset - payload_offset);
405 :
406 : // Copy serialized data.
407 : CopyBytes(data_ + padded_payload_offset, payload->begin(),
408 1114 : static_cast<size_t>(payload->length()));
409 :
410 : Checksum checksum(DataWithoutHeader());
411 : SetHeaderValue(kChecksum1Offset, checksum.a());
412 : SetHeaderValue(kChecksum2Offset, checksum.b());
413 557 : }
414 :
415 458 : SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
416 : Isolate* isolate, uint32_t expected_source_hash) const {
417 458 : if (this->size_ < kHeaderSize) return INVALID_HEADER;
418 816 : uint32_t magic_number = GetMagicNumber();
419 418 : if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
420 418 : if (GetExtraReferences() > GetExtraReferences(isolate)) {
421 : return MAGIC_NUMBER_MISMATCH;
422 : }
423 : uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
424 : uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
425 : uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
426 : uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
427 : uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
428 : uint32_t c1 = GetHeaderValue(kChecksum1Offset);
429 : uint32_t c2 = GetHeaderValue(kChecksum2Offset);
430 418 : if (version_hash != Version::Hash()) return VERSION_MISMATCH;
431 404 : if (source_hash != expected_source_hash) return SOURCE_MISMATCH;
432 404 : if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) {
433 : return CPU_FEATURES_MISMATCH;
434 : }
435 404 : if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
436 : uint32_t max_payload_length =
437 : this->size_ -
438 796 : POINTER_SIZE_ALIGN(kHeaderSize +
439 : GetHeaderValue(kNumReservationsOffset) * kInt32Size +
440 : GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size);
441 398 : if (payload_length > max_payload_length) return LENGTH_MISMATCH;
442 391 : if (!Checksum(DataWithoutHeader()).Check(c1, c2)) return CHECKSUM_MISMATCH;
443 385 : return CHECK_SUCCESS;
444 : }
445 :
446 0 : uint32_t SerializedCodeData::SourceHash(Handle<String> source) {
447 698 : return source->length();
448 : }
449 :
450 : // Return ScriptData object and relinquish ownership over it to the caller.
451 557 : ScriptData* SerializedCodeData::GetScriptData() {
452 : DCHECK(owns_data_);
453 557 : ScriptData* result = new ScriptData(data_, size_);
454 : result->AcquireDataOwnership();
455 557 : owns_data_ = false;
456 557 : data_ = NULL;
457 557 : return result;
458 : }
459 :
460 0 : Vector<const SerializedData::Reservation> SerializedCodeData::Reservations()
461 : const {
462 : return Vector<const Reservation>(
463 : reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
464 385 : GetHeaderValue(kNumReservationsOffset));
465 : }
466 :
467 0 : Vector<const byte> SerializedCodeData::Payload() const {
468 770 : int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size;
469 385 : int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size;
470 385 : int payload_offset = kHeaderSize + reservations_size + code_stubs_size;
471 385 : int padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset);
472 385 : const byte* payload = data_ + padded_payload_offset;
473 : DCHECK(IsAligned(reinterpret_cast<intptr_t>(payload), kPointerAlignment));
474 385 : int length = GetHeaderValue(kPayloadLengthOffset);
475 : DCHECK_EQ(data_ + size_, payload + length);
476 0 : return Vector<const byte>(payload, length);
477 : }
478 :
479 0 : Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const {
480 770 : int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size;
481 385 : const byte* start = data_ + kHeaderSize + reservations_size;
482 : return Vector<const uint32_t>(reinterpret_cast<const uint32_t*>(start),
483 385 : GetHeaderValue(kNumCodeStubKeysOffset));
484 : }
485 :
486 458 : SerializedCodeData::SerializedCodeData(ScriptData* data)
487 0 : : SerializedData(const_cast<byte*>(data->data()), data->length()) {}
488 :
489 458 : SerializedCodeData SerializedCodeData::FromCachedData(
490 : Isolate* isolate, ScriptData* cached_data, uint32_t expected_source_hash,
491 : SanityCheckResult* rejection_result) {
492 : DisallowHeapAllocation no_gc;
493 : SerializedCodeData scd(cached_data);
494 458 : *rejection_result = scd.SanityCheck(isolate, expected_source_hash);
495 458 : if (*rejection_result != CHECK_SUCCESS) {
496 : cached_data->Reject();
497 : return SerializedCodeData(nullptr, 0);
498 : }
499 : return scd;
500 : }
501 :
502 : } // namespace internal
503 : } // namespace v8
|