1// Copyright 2021 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/web-snapshot/web-snapshot.h" 6 7#include <limits> 8 9#include "include/v8-isolate.h" 10#include "include/v8-local-handle.h" 11#include "include/v8-object.h" 12#include "include/v8-primitive.h" 13#include "include/v8-script.h" 14#include "src/api/api-inl.h" 15#include "src/base/platform/wrappers.h" 16#include "src/handles/handles.h" 17#include "src/logging/runtime-call-stats-scope.h" 18#include "src/objects/contexts.h" 19#include "src/objects/js-regexp-inl.h" 20#include "src/objects/script.h" 21 22namespace v8 { 23namespace internal { 24 25constexpr uint8_t WebSnapshotSerializerDeserializer::kMagicNumber[4]; 26 27// When encountering an error during deserializing, we note down the error but 28// don't bail out from processing the snapshot further. This is to speed up 29// deserialization; the error case is now slower since we don't bail out, but 30// the non-error case is faster, since we don't repeatedly check for errors. 31// (Invariant: we might fill our internal data structures with arbitrary data, 32// but it shouldn't have an observable effect.) 33 34// This doesn't increase the complexity of processing the data in a robust and 35// secure way. We cannot trust the data anyway, so every upcoming byte can have 36// an arbitrary value, not depending on whether or not we've encountered an 37// error before. 38void WebSnapshotSerializerDeserializer::Throw(const char* message) { 39 if (error_message_ != nullptr) { 40 return; 41 } 42 error_message_ = message; 43 if (!isolate_->has_pending_exception()) { 44 isolate_->Throw(*factory()->NewError( 45 MessageTemplate::kWebSnapshotError, 46 factory()->NewStringFromAsciiChecked(error_message_))); 47 } 48} 49 50uint32_t WebSnapshotSerializerDeserializer::FunctionKindToFunctionFlags( 51 FunctionKind kind) { 52 // TODO(v8:11525): Support more function kinds. 53 switch (kind) { 54 case FunctionKind::kNormalFunction: 55 case FunctionKind::kArrowFunction: 56 case FunctionKind::kGeneratorFunction: 57 case FunctionKind::kAsyncFunction: 58 case FunctionKind::kAsyncArrowFunction: 59 case FunctionKind::kAsyncGeneratorFunction: 60 case FunctionKind::kBaseConstructor: 61 case FunctionKind::kDefaultBaseConstructor: 62 case FunctionKind::kConciseMethod: 63 case FunctionKind::kAsyncConciseMethod: 64 break; 65 default: 66 Throw("Unsupported function kind"); 67 } 68 auto flags = AsyncFunctionBitField::encode(IsAsyncFunction(kind)) | 69 GeneratorFunctionBitField::encode(IsGeneratorFunction(kind)) | 70 ArrowFunctionBitField::encode(IsArrowFunction(kind)) | 71 MethodBitField::encode(IsConciseMethod(kind)) | 72 StaticBitField::encode(IsStatic(kind)) | 73 ClassConstructorBitField::encode(IsClassConstructor(kind)) | 74 DefaultConstructorBitField::encode(IsDefaultConstructor(kind)) | 75 DerivedConstructorBitField::encode(IsDerivedConstructor(kind)); 76 return flags; 77} 78 79// TODO(v8:11525): Optionally, use an enum instead. 80FunctionKind WebSnapshotSerializerDeserializer::FunctionFlagsToFunctionKind( 81 uint32_t flags) { 82 FunctionKind kind; 83 if (IsFunctionOrMethod(flags)) { 84 if (ArrowFunctionBitField::decode(flags) && MethodBitField::decode(flags)) { 85 kind = FunctionKind::kInvalid; 86 } else { 87 uint32_t index = AsyncFunctionBitField::decode(flags) << 0 | 88 GeneratorFunctionBitField::decode(flags) << 1 | 89 (ArrowFunctionBitField::decode(flags) || 90 StaticBitField::decode(flags)) 91 << 2 | 92 MethodBitField::decode(flags) << 3; 93 static const FunctionKind kFunctionKinds[] = { 94 // kNormalFunction 95 // is_generator = false 96 FunctionKind::kNormalFunction, // is_async = false 97 FunctionKind::kAsyncFunction, // is_async = true 98 // is_generator = true 99 FunctionKind::kGeneratorFunction, // is_async = false 100 FunctionKind::kAsyncGeneratorFunction, // is_async = true 101 102 // kArrowFunction 103 // is_generator = false 104 FunctionKind::kArrowFunction, // is_async = false 105 FunctionKind::kAsyncArrowFunction, // is_async = true 106 // is_generator = true 107 FunctionKind::kInvalid, // is_async = false 108 FunctionKind::kInvalid, // is_async = true 109 110 // kNonStaticMethod 111 // is_generator = false 112 FunctionKind::kConciseMethod, // is_async = false 113 FunctionKind::kAsyncConciseMethod, // is_async = true 114 // is_generator = true 115 // TODO(v8::11525) Support FunctionKind::kConciseGeneratorMethod. 116 FunctionKind::kInvalid, // is_async = false 117 // TODO(v8::11525) Support FunctionKind::kAsyncConciseGeneratorMethod. 118 FunctionKind::kInvalid, // is_async = true 119 120 // kStaticMethod 121 // is_generator = false 122 // TODO(v8::11525) Support FunctionKind::kStaticConciseMethod. 123 FunctionKind::kInvalid, // is_async = false 124 // TODO(v8::11525) Support FunctionKind::kStaticAsyncConciseMethod. 125 FunctionKind::kInvalid, // is_async = true 126 // is_generator = true 127 // TODO(v8::11525) Support 128 // FunctionKind::kStaticConciseGeneratorMethod. 129 FunctionKind::kInvalid, // is_async = false 130 // TODO(v8::11525) Support 131 // FunctionKind::kStaticAsyncConciseGeneratorMethod. 132 FunctionKind::kInvalid // is_async = true 133 }; 134 kind = kFunctionKinds[index]; 135 } 136 } else if (IsConstructor(flags)) { 137 static const FunctionKind kFunctionKinds[] = { 138 // is_derived = false 139 FunctionKind::kBaseConstructor, // is_default = false 140 FunctionKind::kDefaultBaseConstructor, // is_default = true 141 // is_derived = true 142 FunctionKind::kDerivedConstructor, // is_default = false 143 FunctionKind::kDefaultDerivedConstructor // is_default = true 144 }; 145 kind = kFunctionKinds[flags >> DefaultConstructorBitField::kShift]; 146 } else { 147 kind = FunctionKind::kInvalid; 148 } 149 if (kind == FunctionKind::kInvalid) { 150 Throw("Invalid function flags\n"); 151 } 152 return kind; 153} 154 155bool WebSnapshotSerializerDeserializer::IsFunctionOrMethod(uint32_t flags) { 156 uint32_t mask = AsyncFunctionBitField::kMask | 157 GeneratorFunctionBitField::kMask | 158 ArrowFunctionBitField::kMask | MethodBitField::kMask | 159 StaticBitField::kMask; 160 return (flags & mask) == flags; 161} 162 163bool WebSnapshotSerializerDeserializer::IsConstructor(uint32_t flags) { 164 uint32_t mask = ClassConstructorBitField::kMask | 165 DefaultConstructorBitField::kMask | 166 DerivedConstructorBitField::kMask; 167 return ClassConstructorBitField::decode(flags) && (flags & mask) == flags; 168} 169 170uint32_t WebSnapshotSerializerDeserializer::GetDefaultAttributeFlags() { 171 auto flags = ReadOnlyBitField::encode(false) | 172 ConfigurableBitField::encode(true) | 173 EnumerableBitField::encode(true); 174 return flags; 175} 176 177uint32_t WebSnapshotSerializerDeserializer::AttributesToFlags( 178 PropertyDetails details) { 179 auto flags = ReadOnlyBitField::encode(details.IsReadOnly()) | 180 ConfigurableBitField::encode(details.IsConfigurable()) | 181 EnumerableBitField::encode(details.IsEnumerable()); 182 return flags; 183} 184 185PropertyAttributes WebSnapshotSerializerDeserializer::FlagsToAttributes( 186 uint32_t flags) { 187 int attributes = ReadOnlyBitField::decode(flags) * READ_ONLY + 188 !ConfigurableBitField::decode(flags) * DONT_DELETE + 189 !EnumerableBitField::decode(flags) * DONT_ENUM; 190 return PropertyAttributesFromInt(attributes); 191} 192 193WebSnapshotSerializer::WebSnapshotSerializer(v8::Isolate* isolate) 194 : WebSnapshotSerializer(reinterpret_cast<v8::internal::Isolate*>(isolate)) { 195} 196 197WebSnapshotSerializer::WebSnapshotSerializer(Isolate* isolate) 198 : WebSnapshotSerializerDeserializer(isolate), 199 string_serializer_(isolate_, nullptr), 200 map_serializer_(isolate_, nullptr), 201 context_serializer_(isolate_, nullptr), 202 function_serializer_(isolate_, nullptr), 203 class_serializer_(isolate_, nullptr), 204 array_serializer_(isolate_, nullptr), 205 object_serializer_(isolate_, nullptr), 206 export_serializer_(isolate_, nullptr), 207 external_objects_ids_(isolate_->heap()), 208 string_ids_(isolate_->heap()), 209 map_ids_(isolate_->heap()), 210 context_ids_(isolate_->heap()), 211 function_ids_(isolate_->heap()), 212 class_ids_(isolate_->heap()), 213 array_ids_(isolate_->heap()), 214 object_ids_(isolate_->heap()), 215 all_strings_(isolate_->heap()) { 216 auto empty_array_list = factory()->empty_array_list(); 217 contexts_ = empty_array_list; 218 functions_ = empty_array_list; 219 classes_ = empty_array_list; 220 arrays_ = empty_array_list; 221 objects_ = empty_array_list; 222 strings_ = empty_array_list; 223 maps_ = empty_array_list; 224} 225 226WebSnapshotSerializer::~WebSnapshotSerializer() {} 227 228bool WebSnapshotSerializer::TakeSnapshot( 229 Handle<Object> object, MaybeHandle<FixedArray> maybe_externals, 230 WebSnapshotData& data_out) { 231 if (string_ids_.size() > 0) { 232 Throw("Can't reuse WebSnapshotSerializer"); 233 return false; 234 } 235 if (!maybe_externals.is_null()) { 236 ShallowDiscoverExternals(*maybe_externals.ToHandleChecked()); 237 } 238 239 if (object->IsHeapObject()) Discover(Handle<HeapObject>::cast(object)); 240 241 ConstructSource(); 242 // The export is serialized with the empty string as name; we need to 243 // "discover" the name here. 244 DiscoverString(factory()->empty_string()); 245 SerializeExport(object, factory()->empty_string()); 246 247 WriteSnapshot(data_out.buffer, data_out.buffer_size); 248 249 if (has_error()) { 250 isolate_->ReportPendingMessages(); 251 return false; 252 } 253 return true; 254} 255 256bool WebSnapshotSerializer::TakeSnapshot(v8::Local<v8::Context> context, 257 v8::Local<v8::PrimitiveArray> exports, 258 WebSnapshotData& data_out) { 259 if (string_ids_.size() > 0) { 260 Throw("Can't reuse WebSnapshotSerializer"); 261 return false; 262 } 263 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 264 265 std::unique_ptr<Handle<JSObject>[]> export_objects( 266 new Handle<JSObject>[exports->Length()]); 267 for (int i = 0, length = exports->Length(); i < length; ++i) { 268 v8::Local<v8::String> str = 269 exports->Get(v8_isolate, i)->ToString(context).ToLocalChecked(); 270 if (str->Length() == 0) { 271 continue; 272 } 273 // Discover the export name. 274 DiscoverString(Handle<String>::cast(Utils::OpenHandle(*str))); 275 v8::ScriptCompiler::Source source(str); 276 auto script = ScriptCompiler::Compile(context, &source).ToLocalChecked(); 277 v8::MaybeLocal<v8::Value> script_result = script->Run(context); 278 v8::Local<v8::Object> v8_object; 279 if (script_result.IsEmpty() || 280 !script_result.ToLocalChecked()->ToObject(context).ToLocal( 281 &v8_object)) { 282 Throw("Exported object not found"); 283 return false; 284 } 285 export_objects[i] = Handle<JSObject>::cast(Utils::OpenHandle(*v8_object)); 286 Discover(export_objects[i]); 287 } 288 289 ConstructSource(); 290 291 for (int i = 0, length = exports->Length(); i < length; ++i) { 292 v8::Local<v8::String> str = 293 exports->Get(v8_isolate, i)->ToString(context).ToLocalChecked(); 294 if (str->Length() == 0) { 295 continue; 296 } 297 SerializeExport(export_objects[i], 298 Handle<String>::cast(Utils::OpenHandle(*str))); 299 } 300 301 WriteSnapshot(data_out.buffer, data_out.buffer_size); 302 303 if (has_error()) { 304 isolate_->ReportPendingMessages(); 305 return false; 306 } 307 return true; 308} 309 310void WebSnapshotSerializer::SerializePendingItems() { 311 // The information about string reference counts is now complete. The strings 312 // in strings_ are not in place and can be serialized now. The in-place 313 // strings will be serialized as part of their respective objects. 314 for (int i = 0; i < strings_->Length(); ++i) { 315 Handle<String> string = handle(String::cast(strings_->Get(i)), isolate_); 316 SerializeString(string, string_serializer_); 317 } 318 319 for (int i = 0; i < maps_->Length(); ++i) { 320 Handle<Map> map = handle(Map::cast(maps_->Get(i)), isolate_); 321 SerializeMap(map); 322 } 323 324 // Serialize the items in the reverse order. The items at the end of the 325 // contexts_ etc get lower IDs and vice versa. IDs which items use for 326 // referring to each other are reversed by Get<item>Id functions(). 327 for (int i = contexts_->Length() - 1; i >= 0; --i) { 328 Handle<Context> context = 329 handle(Context::cast(contexts_->Get(i)), isolate_); 330 SerializeContext(context); 331 } 332 for (int i = functions_->Length() - 1; i >= 0; --i) { 333 Handle<JSFunction> function = 334 handle(JSFunction::cast(functions_->Get(i)), isolate_); 335 SerializeFunction(function); 336 } 337 for (int i = classes_->Length() - 1; i >= 0; --i) { 338 Handle<JSFunction> function = 339 handle(JSFunction::cast(classes_->Get(i)), isolate_); 340 SerializeClass(function); 341 } 342 for (int i = arrays_->Length() - 1; i >= 0; --i) { 343 Handle<JSArray> array = handle(JSArray::cast(arrays_->Get(i)), isolate_); 344 SerializeArray(array); 345 } 346 for (int i = objects_->Length() - 1; i >= 0; --i) { 347 Handle<JSObject> object = 348 handle(JSObject::cast(objects_->Get(i)), isolate_); 349 SerializeObject(object); 350 } 351} 352 353// Format (full snapshot): 354// - Magic number (4 bytes) 355// - String count 356// - For each string: 357// - Serialized string 358// - Shape count 359// - For each shape: 360// - Serialized shape 361// - Context count 362// - For each context: 363// - Serialized context 364// - Function count 365// - For each function: 366// - Serialized function 367// - Object count 368// - For each object: 369// - Serialized object 370// - Export count 371// - For each export: 372// - Serialized export 373void WebSnapshotSerializer::WriteSnapshot(uint8_t*& buffer, 374 size_t& buffer_size) { 375 if (has_error()) { 376 return; 377 } 378 SerializePendingItems(); 379 380 ValueSerializer total_serializer(isolate_, nullptr); 381 size_t needed_size = 382 sizeof(kMagicNumber) + string_serializer_.buffer_size_ + 383 map_serializer_.buffer_size_ + context_serializer_.buffer_size_ + 384 function_serializer_.buffer_size_ + class_serializer_.buffer_size_ + 385 array_serializer_.buffer_size_ + object_serializer_.buffer_size_ + 386 export_serializer_.buffer_size_ + 8 * sizeof(uint32_t); 387 if (total_serializer.ExpandBuffer(needed_size).IsNothing()) { 388 Throw("Out of memory"); 389 return; 390 } 391 392 total_serializer.WriteRawBytes(kMagicNumber, 4); 393 WriteObjects(total_serializer, string_count(), string_serializer_, "strings"); 394 WriteObjects(total_serializer, map_count(), map_serializer_, "maps"); 395 WriteObjects(total_serializer, context_count(), context_serializer_, 396 "contexts"); 397 WriteObjects(total_serializer, function_count(), function_serializer_, 398 "functions"); 399 WriteObjects(total_serializer, array_count(), array_serializer_, "arrays"); 400 WriteObjects(total_serializer, object_count(), object_serializer_, "objects"); 401 WriteObjects(total_serializer, class_count(), class_serializer_, "classes"); 402 WriteObjects(total_serializer, export_count_, export_serializer_, "exports"); 403 404 if (has_error()) { 405 return; 406 } 407 408 auto result = total_serializer.Release(); 409 buffer = result.first; 410 buffer_size = result.second; 411} 412void WebSnapshotSerializer::WriteObjects(ValueSerializer& destination, 413 size_t count, ValueSerializer& source, 414 const char* name) { 415 if (count > std::numeric_limits<uint32_t>::max()) { 416 Throw("Too many objects"); 417 return; 418 } 419 destination.WriteUint32(static_cast<uint32_t>(count)); 420 destination.WriteRawBytes(source.buffer_, source.buffer_size_); 421} 422 423bool WebSnapshotSerializer::InsertIntoIndexMap(ObjectCacheIndexMap& map, 424 HeapObject heap_object, 425 uint32_t& id) { 426 DisallowGarbageCollection no_gc; 427 int index_out; 428 if (external_objects_ids_.Lookup(heap_object, &index_out)) { 429 return true; 430 } 431 bool found = map.LookupOrInsert(heap_object, &index_out); 432 id = static_cast<uint32_t>(index_out); 433 return found; 434} 435 436// Format: 437// - Length 438// - Raw bytes (data) 439void WebSnapshotSerializer::SerializeString(Handle<String> string, 440 ValueSerializer& serializer) { 441 DisallowGarbageCollection no_gc; 442 String::FlatContent flat = string->GetFlatContent(no_gc); 443 DCHECK(flat.IsFlat()); 444 if (flat.IsOneByte()) { 445 base::Vector<const uint8_t> chars = flat.ToOneByteVector(); 446 serializer.WriteUint32(chars.length()); 447 serializer.WriteRawBytes(chars.begin(), chars.length() * sizeof(uint8_t)); 448 } else if (flat.IsTwoByte()) { 449 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 450 v8::Local<v8::String> api_string = Utils::ToLocal(string); 451 int length = api_string->Utf8Length(v8_isolate); 452 std::unique_ptr<char[]> buffer(new char[length]); 453 api_string->WriteUtf8(v8_isolate, buffer.get(), length); 454 serializer.WriteUint32(length); 455 serializer.WriteRawBytes(buffer.get(), length * sizeof(uint8_t)); 456 } else { 457 UNREACHABLE(); 458 } 459} 460 461// Format (serialized shape): 462// - PropertyAttributesType 463// - 0 if the __proto__ is Object.prototype, 1 + object id for the __proto__ 464// otherwise 465// - Property count 466// - For each property 467// - String id (name) 468// - If the PropertyAttributesType is CUSTOM: attributes 469void WebSnapshotSerializer::SerializeMap(Handle<Map> map) { 470 int first_custom_index = -1; 471 std::vector<Handle<String>> keys; 472 std::vector<uint32_t> attributes; 473 keys.reserve(map->NumberOfOwnDescriptors()); 474 attributes.reserve(map->NumberOfOwnDescriptors()); 475 for (InternalIndex i : map->IterateOwnDescriptors()) { 476 Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i), 477 isolate_); 478 keys.push_back(Handle<String>::cast(key)); 479 480 PropertyDetails details = 481 map->instance_descriptors(kRelaxedLoad).GetDetails(i); 482 483 if (details.location() != PropertyLocation::kField) { 484 Throw("Properties which are not fields not supported"); 485 return; 486 } 487 if (first_custom_index >= 0 || details.IsReadOnly() || 488 !details.IsConfigurable() || details.IsDontEnum()) { 489 if (first_custom_index == -1) first_custom_index = i.as_int(); 490 attributes.push_back(AttributesToFlags(details)); 491 } 492 } 493 494 map_serializer_.WriteUint32(first_custom_index == -1 495 ? PropertyAttributesType::DEFAULT 496 : PropertyAttributesType::CUSTOM); 497 498 if (map->prototype() == 499 isolate_->native_context()->initial_object_prototype()) { 500 map_serializer_.WriteUint32(0); 501 } else { 502 // TODO(v8:11525): Support non-JSObject prototypes, at least null. Recognize 503 // well-known objects to that we don't end up encoding them in the snapshot. 504 if (!map->prototype().IsJSObject()) { 505 Throw("Non-JSObject __proto__s not supported"); 506 return; 507 } 508 uint32_t prototype_id = GetObjectId(JSObject::cast(map->prototype())); 509 map_serializer_.WriteUint32(prototype_id + 1); 510 } 511 512 map_serializer_.WriteUint32(static_cast<uint32_t>(keys.size())); 513 514 uint32_t default_flags = GetDefaultAttributeFlags(); 515 for (size_t i = 0; i < keys.size(); ++i) { 516 if (first_custom_index >= 0) { 517 if (static_cast<int>(i) < first_custom_index) { 518 map_serializer_.WriteUint32(default_flags); 519 } else { 520 map_serializer_.WriteUint32(attributes[i - first_custom_index]); 521 } 522 } 523 WriteStringId(keys[i], map_serializer_); 524 } 525} 526 527// Construct the minimal source string to be included in the snapshot. Maintain 528// the "inner function is textually inside its outer function" relationship. 529// Example: 530// Input: 531// Full source: abcdefghijklmnopqrstuvwxyzåäö 532// Functions: 11111111 22222222 3 533// Inner functions: 44 55 666 534// Output: 535// Constructed source: defghijkstuvwxyzö 536// Functions: 11111111222222223 537// Inner functions 44 55 666 538void WebSnapshotSerializer::ConstructSource() { 539 if (source_intervals_.empty()) { 540 return; 541 } 542 543 Handle<String> source_string = factory()->empty_string(); 544 int current_interval_start = 0; 545 int current_interval_end = 0; 546 for (const auto& interval : source_intervals_) { 547 DCHECK_LE(current_interval_start, interval.first); // Iterated in order. 548 DCHECK_LE(interval.first, interval.second); 549 if (interval.second <= current_interval_end) { 550 // This interval is fully within the current interval. We don't need to 551 // include any new source code, just record the position conversion. 552 auto offset_within_parent = interval.first - current_interval_start; 553 source_offset_to_compacted_source_offset_[interval.first] = 554 source_offset_to_compacted_source_offset_[current_interval_start] + 555 offset_within_parent; 556 continue; 557 } 558 // Start a new interval. 559 current_interval_start = interval.first; 560 current_interval_end = interval.second; 561 source_offset_to_compacted_source_offset_[current_interval_start] = 562 source_string->length(); 563 MaybeHandle<String> new_source_string = factory()->NewConsString( 564 source_string, 565 factory()->NewSubString(full_source_, current_interval_start, 566 current_interval_end)); 567 if (!new_source_string.ToHandle(&source_string)) { 568 Throw("Cannot construct source string"); 569 return; 570 } 571 } 572 DiscoverString(source_string); 573 bool in_place = false; 574 source_id_ = GetStringId(source_string, in_place); 575 DCHECK(!in_place); 576} 577 578void WebSnapshotSerializer::SerializeFunctionInfo(ValueSerializer* serializer, 579 Handle<JSFunction> function) { 580 if (!function->shared().HasSourceCode()) { 581 Throw("Function without source code"); 582 return; 583 } 584 585 { 586 DisallowGarbageCollection no_gc; 587 Context context = function->context(); 588 if (context.IsNativeContext() || context.IsScriptContext()) { 589 serializer->WriteUint32(0); 590 } else { 591 DCHECK(context.IsFunctionContext() || context.IsBlockContext()); 592 uint32_t context_id = GetContextId(context); 593 serializer->WriteUint32(context_id + 1); 594 } 595 } 596 597 serializer->WriteUint32(source_id_); 598 int start = function->shared().StartPosition(); 599 int end = function->shared().EndPosition(); 600 serializer->WriteUint32(source_offset_to_compacted_source_offset_[start]); 601 serializer->WriteUint32(end - start); 602 603 serializer->WriteUint32( 604 function->shared().internal_formal_parameter_count_without_receiver()); 605 serializer->WriteUint32( 606 FunctionKindToFunctionFlags(function->shared().kind())); 607 608 if (function->has_prototype_slot() && function->has_instance_prototype()) { 609 DisallowGarbageCollection no_gc; 610 JSObject prototype = JSObject::cast(function->instance_prototype()); 611 uint32_t prototype_id = GetObjectId(prototype); 612 serializer->WriteUint32(prototype_id + 1); 613 } else { 614 serializer->WriteUint32(0); 615 } 616} 617 618void WebSnapshotSerializer::ShallowDiscoverExternals(FixedArray externals) { 619 DisallowGarbageCollection no_gc; 620 for (int i = 0; i < externals.length(); i++) { 621 Object object = externals.get(i); 622 if (!object.IsHeapObject()) continue; 623 uint32_t unused_id = 0; 624 InsertIntoIndexMap(external_objects_ids_, HeapObject::cast(object), 625 unused_id); 626 } 627} 628 629void WebSnapshotSerializer::Discover(Handle<HeapObject> start_object) { 630 // The object discovery phase assigns IDs for objects / functions / classes / 631 // arrays and discovers outgoing references from them. This is needed so that 632 // e.g., we know all functions upfront and can construct the source code that 633 // covers them before serializing the functions. 634 635 discovery_queue_.push(start_object); 636 637 while (!discovery_queue_.empty()) { 638 const Handle<HeapObject>& object = discovery_queue_.front(); 639 switch (object->map().instance_type()) { 640 case JS_FUNCTION_TYPE: 641 DiscoverFunction(Handle<JSFunction>::cast(object)); 642 break; 643 case JS_CLASS_CONSTRUCTOR_TYPE: 644 DiscoverClass(Handle<JSFunction>::cast(object)); 645 break; 646 case JS_OBJECT_TYPE: 647 DiscoverObject(Handle<JSObject>::cast(object)); 648 break; 649 case JS_ARRAY_TYPE: 650 DiscoverArray(Handle<JSArray>::cast(object)); 651 break; 652 case ODDBALL_TYPE: 653 case HEAP_NUMBER_TYPE: 654 // Can't contain references to other objects. 655 break; 656 case JS_PRIMITIVE_WRAPPER_TYPE: { 657 Handle<JSPrimitiveWrapper> wrapper = 658 Handle<JSPrimitiveWrapper>::cast(object); 659 Handle<Object> value = handle(wrapper->value(), isolate_); 660 if (value->IsHeapObject()) { 661 discovery_queue_.push(Handle<HeapObject>::cast(value)); 662 } 663 break; 664 } 665 case JS_REG_EXP_TYPE: { 666 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object); 667 Handle<String> pattern = handle(regexp->source(), isolate_); 668 DiscoverString(pattern); 669 Handle<String> flags_string = 670 JSRegExp::StringFromFlags(isolate_, regexp->flags()); 671 DiscoverString(flags_string); 672 break; 673 } 674 default: 675 if (object->IsString()) { 676 // These are array elements / object properties -> allow in place 677 // strings. 678 DiscoverString(Handle<String>::cast(object), AllowInPlace::Yes); 679 break; 680 } else if (external_objects_ids_.size() > 0) { 681 int unused_id; 682 external_objects_ids_.LookupOrInsert(*object, &unused_id); 683 } else { 684 Throw("Unsupported object"); 685 } 686 } 687 discovery_queue_.pop(); 688 } 689} 690 691void WebSnapshotSerializer::DiscoverMap(Handle<Map> map) { 692 uint32_t id; 693 if (InsertIntoIndexMap(map_ids_, *map, id)) { 694 return; 695 } 696 DCHECK_EQ(id, maps_->Length()); 697 maps_ = ArrayList::Add(isolate_, maps_, map); 698 for (InternalIndex i : map->IterateOwnDescriptors()) { 699 Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i), 700 isolate_); 701 if (!key->IsString()) { 702 Throw("Key is not a string"); 703 return; 704 } 705 DiscoverString(Handle<String>::cast(key)); 706 } 707} 708 709void WebSnapshotSerializer::DiscoverString(Handle<String> string, 710 AllowInPlace can_be_in_place) { 711 // Can't contain references to other objects. We only log the existence of the 712 // string itself. Internalize the strings so that we can properly track which 713 // String objects are the same string. 714 string = factory()->InternalizeString(string); 715 auto result = all_strings_.FindOrInsert(string); 716 if (can_be_in_place == AllowInPlace::Yes && !result.already_exists) { 717 // This is the only reference to the string so far. Don't generate and 718 // ID for it yet; only generate it when another reference to the string is 719 // found. 720 return; 721 } 722 // The string is referred to more than two places, or in-placing not allowed 723 // -> not a candidate for writing it in-place. Generate an ID for it. 724 725 // TODO(v8:11525): Allow in-place strings in more places. Heuristics for 726 // when to make them in place? 727 uint32_t id; 728 if (InsertIntoIndexMap(string_ids_, *string, id)) { 729 return; 730 } 731 DCHECK_EQ(id, strings_->Length()); 732 strings_ = ArrayList::Add(isolate_, strings_, string); 733} 734 735void WebSnapshotSerializer::DiscoverFunction(Handle<JSFunction> function) { 736 uint32_t id; 737 if (InsertIntoIndexMap(function_ids_, *function, id)) { 738 return; 739 } 740 741 DCHECK_EQ(id, functions_->Length()); 742 functions_ = ArrayList::Add(isolate_, functions_, function); 743 DiscoverContextAndPrototype(function); 744 // TODO(v8:11525): Support properties in functions. 745 DiscoverSource(function); 746} 747 748void WebSnapshotSerializer::DiscoverClass(Handle<JSFunction> function) { 749 uint32_t id; 750 if (InsertIntoIndexMap(class_ids_, *function, id)) { 751 return; 752 } 753 754 DCHECK_EQ(id, classes_->Length()); 755 classes_ = ArrayList::Add(isolate_, classes_, function); 756 757 DiscoverContextAndPrototype(function); 758 // TODO(v8:11525): Support properties in classes. 759 // TODO(v8:11525): Support class members. 760 DiscoverSource(function); 761} 762 763void WebSnapshotSerializer::DiscoverContextAndPrototype( 764 Handle<JSFunction> function) { 765 Handle<Context> context(function->context(), isolate_); 766 if (context->IsFunctionContext() || context->IsBlockContext()) { 767 DiscoverContext(context); 768 } 769 770 if (function->has_prototype_slot() && 771 function->map().has_non_instance_prototype()) { 772 Throw("Functions with non-instance prototypes not supported"); 773 return; 774 } 775 776 if (function->has_prototype_slot() && function->has_instance_prototype()) { 777 Handle<JSObject> prototype = Handle<JSObject>::cast( 778 handle(function->instance_prototype(), isolate_)); 779 discovery_queue_.push(prototype); 780 } 781} 782 783void WebSnapshotSerializer::DiscoverContext(Handle<Context> context) { 784 uint32_t id; 785 if (InsertIntoIndexMap(context_ids_, *context, id)) return; 786 787 DCHECK_EQ(id, contexts_->Length()); 788 contexts_ = ArrayList::Add(isolate_, contexts_, context); 789 790 Handle<ScopeInfo> scope_info = handle(context->scope_info(), isolate_); 791 int count = scope_info->ContextLocalCount(); 792 793 for (int i = 0; i < count; ++i) { 794 // TODO(v8:11525): support parameters 795 // TODO(v8:11525): distinguish variable modes 796 Handle<String> name(scope_info->context_local_names(i), isolate_); 797 DiscoverString(name); 798 Object value = context->get(scope_info->ContextHeaderLength() + i); 799 if (!value.IsHeapObject()) continue; 800 discovery_queue_.push(handle(HeapObject::cast(value), isolate_)); 801 } 802 803 if (!context->previous().IsNativeContext() && 804 !context->previous().IsScriptContext()) { 805 DiscoverContext(handle(context->previous(), isolate_)); 806 } 807} 808 809void WebSnapshotSerializer::DiscoverSource(Handle<JSFunction> function) { 810 source_intervals_.emplace(function->shared().StartPosition(), 811 function->shared().EndPosition()); 812 Handle<String> function_script_source = 813 handle(String::cast(Script::cast(function->shared().script()).source()), 814 isolate_); 815 if (full_source_.is_null()) { 816 full_source_ = function_script_source; 817 } else if (!full_source_->Equals(*function_script_source)) { 818 Throw("Cannot include functions from multiple scripts"); 819 } 820} 821 822void WebSnapshotSerializer::DiscoverArray(Handle<JSArray> array) { 823 uint32_t id; 824 if (InsertIntoIndexMap(array_ids_, *array, id)) { 825 return; 826 } 827 DCHECK_EQ(id, arrays_->Length()); 828 arrays_ = ArrayList::Add(isolate_, arrays_, array); 829 830 auto elements_kind = array->GetElementsKind(); 831 if (elements_kind != PACKED_SMI_ELEMENTS && 832 elements_kind != PACKED_ELEMENTS) { 833 Throw("Unsupported array"); 834 return; 835 } 836 // TODO(v8:11525): Support sparse arrays & arrays with holes. 837 DisallowGarbageCollection no_gc; 838 FixedArray elements = FixedArray::cast(array->elements()); 839 for (int i = 0; i < elements.length(); ++i) { 840 Object object = elements.get(i); 841 if (!object.IsHeapObject()) continue; 842 discovery_queue_.push(handle(HeapObject::cast(object), isolate_)); 843 } 844} 845 846void WebSnapshotSerializer::DiscoverObject(Handle<JSObject> object) { 847 uint32_t id; 848 if (InsertIntoIndexMap(object_ids_, *object, id)) return; 849 850 DCHECK_EQ(id, objects_->Length()); 851 objects_ = ArrayList::Add(isolate_, objects_, object); 852 853 // TODO(v8:11525): Support objects with so many properties that they can't be 854 // in fast mode. 855 JSObject::MigrateSlowToFast(object, 0, "Web snapshot"); 856 if (!object->HasFastProperties()) { 857 Throw("Dictionary mode objects not supported"); 858 } 859 860 Handle<Map> map(object->map(), isolate_); 861 DiscoverMap(map); 862 863 // Discover __proto__. 864 if (map->prototype() != 865 isolate_->native_context()->initial_object_prototype()) { 866 discovery_queue_.push(handle(map->prototype(), isolate_)); 867 } 868 869 // Discover property values. 870 for (InternalIndex i : map->IterateOwnDescriptors()) { 871 PropertyDetails details = 872 map->instance_descriptors(kRelaxedLoad).GetDetails(i); 873 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); 874 Handle<Object> value = JSObject::FastPropertyAt( 875 isolate_, object, details.representation(), field_index); 876 if (!value->IsHeapObject()) continue; 877 discovery_queue_.push(Handle<HeapObject>::cast(value)); 878 } 879 880 // Discover elements. 881 Handle<FixedArray> elements = 882 handle(FixedArray::cast(object->elements()), isolate_); 883 for (int i = 0; i < elements->length(); ++i) { 884 Object object = elements->get(i); 885 if (!object.IsHeapObject()) continue; 886 discovery_queue_.push(handle(HeapObject::cast(object), isolate_)); 887 } 888} 889 890// Format (serialized function): 891// - 0 if there's no context, 1 + context id otherwise 892// - String id (source snippet) 893// - Start position in the source snippet 894// - Length in the source snippet 895// - Formal parameter count 896// - Flags (see FunctionFlags) 897// - 0 if there's no function prototype, 1 + object id for the function 898// prototype otherwise 899// TODO(v8:11525): Investigate whether the length is really needed. 900void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function) { 901 SerializeFunctionInfo(&function_serializer_, function); 902 // TODO(v8:11525): Support properties in functions. 903} 904 905// Format (serialized class): 906// - 1 + context id 907// - String id (source snippet) 908// - Start position in the source snippet 909// - Length in the source snippet 910// - Formal parameter count 911// - Flags (see FunctionFlags) 912// - 1 + object id for the function prototype 913void WebSnapshotSerializer::SerializeClass(Handle<JSFunction> function) { 914 SerializeFunctionInfo(&class_serializer_, function); 915 // TODO(v8:11525): Support properties in classes. 916 // TODO(v8:11525): Support class members. 917} 918 919// Format (serialized context): 920// - 0 if there's no parent context, 1 + parent context id otherwise 921// - Variable count 922// - For each variable: 923// - String id (name) 924// - Serialized value 925void WebSnapshotSerializer::SerializeContext(Handle<Context> context) { 926 uint32_t parent_context_id = 0; 927 if (!context->previous().IsNativeContext() && 928 !context->previous().IsScriptContext()) { 929 parent_context_id = GetContextId(context->previous()) + 1; 930 } 931 932 // TODO(v8:11525): Use less space for encoding the context type. 933 if (context->IsFunctionContext()) { 934 context_serializer_.WriteUint32(ContextType::FUNCTION); 935 } else if (context->IsBlockContext()) { 936 context_serializer_.WriteUint32(ContextType::BLOCK); 937 } else { 938 Throw("Unsupported context type"); 939 return; 940 } 941 942 context_serializer_.WriteUint32(parent_context_id); 943 944 Handle<ScopeInfo> scope_info(context->scope_info(), isolate_); 945 int count = scope_info->ContextLocalCount(); 946 context_serializer_.WriteUint32(count); 947 948 for (int i = 0; i < count; ++i) { 949 // TODO(v8:11525): support parameters 950 // TODO(v8:11525): distinguish variable modes 951 Handle<String> name(scope_info->context_local_names(i), isolate_); 952 WriteStringId(name, context_serializer_); 953 Handle<Object> value(context->get(scope_info->ContextHeaderLength() + i), 954 isolate_); 955 WriteValue(value, context_serializer_); 956 } 957} 958 959// Format (serialized object): 960// - Shape id 961// - For each property: 962// - Serialized value 963// - Max element index + 1 (or 0 if there are no elements) 964// - For each element: 965// - Index 966// - Serialized value 967// TODO(v8:11525): Support packed elements with a denser format. 968void WebSnapshotSerializer::SerializeObject(Handle<JSObject> object) { 969 Handle<Map> map(object->map(), isolate_); 970 uint32_t map_id = GetMapId(*map); 971 object_serializer_.WriteUint32(map_id); 972 973 // Properties. 974 for (InternalIndex i : map->IterateOwnDescriptors()) { 975 PropertyDetails details = 976 map->instance_descriptors(kRelaxedLoad).GetDetails(i); 977 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); 978 Handle<Object> value = JSObject::FastPropertyAt( 979 isolate_, object, details.representation(), field_index); 980 WriteValue(value, object_serializer_); 981 } 982 983 // Elements. 984 ReadOnlyRoots roots(isolate_); 985 Handle<FixedArray> elements = 986 handle(FixedArray::cast(object->elements()), isolate_); 987 uint32_t max_element_index = 0; 988 for (int i = 0; i < elements->length(); ++i) { 989 DisallowGarbageCollection no_gc; 990 Object value = elements->get(i); 991 if (value != roots.the_hole_value()) { 992 if (i > static_cast<int>(max_element_index)) { 993 max_element_index = i; 994 } 995 } 996 } 997 if (max_element_index == 0) { 998 object_serializer_.WriteUint32(0); 999 } else { 1000 object_serializer_.WriteUint32(max_element_index + 1); 1001 } 1002 for (int i = 0; i < elements->length(); ++i) { 1003 Handle<Object> value = handle(elements->get(i), isolate_); 1004 if (*value != roots.the_hole_value()) { 1005 DCHECK_LE(i, max_element_index); 1006 object_serializer_.WriteUint32(i); 1007 WriteValue(value, object_serializer_); 1008 } 1009 } 1010} 1011 1012// Format (serialized array): 1013// - Length 1014// - For each element: 1015// - Serialized value 1016void WebSnapshotSerializer::SerializeArray(Handle<JSArray> array) { 1017 auto elements_kind = array->GetElementsKind(); 1018 if (elements_kind != PACKED_SMI_ELEMENTS && 1019 elements_kind != PACKED_ELEMENTS) { 1020 Throw("Unsupported array"); 1021 return; 1022 } 1023 // TODO(v8:11525): Support sparse arrays & arrays with holes. 1024 uint32_t length = static_cast<uint32_t>(array->length().ToSmi().value()); 1025 array_serializer_.WriteUint32(length); 1026 Handle<FixedArray> elements = 1027 handle(FixedArray::cast(array->elements()), isolate_); 1028 for (uint32_t i = 0; i < length; ++i) { 1029 WriteValue(handle(elements->get(i), isolate_), array_serializer_); 1030 } 1031} 1032 1033// Format (serialized export): 1034// - String id (export name) 1035// - Serialized value (export value) 1036void WebSnapshotSerializer::SerializeExport(Handle<Object> object, 1037 Handle<String> export_name) { 1038 ++export_count_; 1039 WriteStringId(export_name, export_serializer_); 1040 if (object->IsJSPrimitiveWrapper()) { 1041 Handle<JSPrimitiveWrapper> wrapper = 1042 Handle<JSPrimitiveWrapper>::cast(object); 1043 Handle<Object> export_value = handle(wrapper->value(), isolate_); 1044 WriteValue(export_value, export_serializer_); 1045 } else { 1046 WriteValue(object, export_serializer_); 1047 } 1048} 1049 1050// Format (serialized value): 1051// - Type id (ValueType enum) 1052// - Value or id (interpretation depends on the type) 1053void WebSnapshotSerializer::WriteValue(Handle<Object> object, 1054 ValueSerializer& serializer) { 1055 if (object->IsSmi()) { 1056 serializer.WriteUint32(ValueType::INTEGER); 1057 serializer.WriteZigZag<int32_t>(Smi::cast(*object).value()); 1058 return; 1059 } 1060 1061 int external_id; 1062 if (external_objects_ids_.Lookup(HeapObject::cast(*object), &external_id)) { 1063 serializer.WriteUint32(ValueType::EXTERNAL_ID); 1064 serializer.WriteUint32(static_cast<uint32_t>(external_id)); 1065 return; 1066 } 1067 1068 DCHECK(object->IsHeapObject()); 1069 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); 1070 switch ((*heap_object).map().instance_type()) { 1071 case ODDBALL_TYPE: 1072 switch (Oddball::cast(*heap_object).kind()) { 1073 case Oddball::kFalse: 1074 serializer.WriteUint32(ValueType::FALSE_CONSTANT); 1075 return; 1076 case Oddball::kTrue: 1077 serializer.WriteUint32(ValueType::TRUE_CONSTANT); 1078 return; 1079 case Oddball::kNull: 1080 serializer.WriteUint32(ValueType::NULL_CONSTANT); 1081 return; 1082 case Oddball::kUndefined: 1083 serializer.WriteUint32(ValueType::UNDEFINED_CONSTANT); 1084 return; 1085 default: 1086 UNREACHABLE(); 1087 } 1088 case HEAP_NUMBER_TYPE: 1089 // TODO(v8:11525): Handle possible endianness mismatch. 1090 serializer.WriteUint32(ValueType::DOUBLE); 1091 serializer.WriteDouble(HeapNumber::cast(*heap_object).value()); 1092 break; 1093 case JS_FUNCTION_TYPE: 1094 serializer.WriteUint32(ValueType::FUNCTION_ID); 1095 serializer.WriteUint32(GetFunctionId(JSFunction::cast(*heap_object))); 1096 break; 1097 case JS_CLASS_CONSTRUCTOR_TYPE: 1098 serializer.WriteUint32(ValueType::CLASS_ID); 1099 serializer.WriteUint32(GetClassId(JSFunction::cast(*heap_object))); 1100 break; 1101 case JS_OBJECT_TYPE: 1102 serializer.WriteUint32(ValueType::OBJECT_ID); 1103 serializer.WriteUint32(GetObjectId(JSObject::cast(*heap_object))); 1104 break; 1105 case JS_ARRAY_TYPE: 1106 serializer.WriteUint32(ValueType::ARRAY_ID); 1107 serializer.WriteUint32(GetArrayId(JSArray::cast(*heap_object))); 1108 break; 1109 case JS_REG_EXP_TYPE: { 1110 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(heap_object); 1111 if (regexp->map() != isolate_->regexp_function()->initial_map()) { 1112 Throw("Unsupported RegExp map"); 1113 return; 1114 } 1115 serializer.WriteUint32(ValueType::REGEXP); 1116 Handle<String> pattern = handle(regexp->source(), isolate_); 1117 WriteStringId(pattern, serializer); 1118 Handle<String> flags_string = 1119 JSRegExp::StringFromFlags(isolate_, regexp->flags()); 1120 WriteStringId(flags_string, serializer); 1121 break; 1122 } 1123 default: 1124 if (heap_object->IsString()) { 1125 // Write strings which are referred to only once as in-place strings. 1126 WriteStringMaybeInPlace(Handle<String>::cast(heap_object), serializer); 1127 } else { 1128 Throw("Unsupported object"); 1129 } 1130 } 1131 // TODO(v8:11525): Support more types. 1132} 1133 1134void WebSnapshotSerializer::WriteStringMaybeInPlace( 1135 Handle<String> string, ValueSerializer& serializer) { 1136 // If the string is only referred to by one location, write it in-place. 1137 bool in_place = false; 1138 uint32_t id = GetStringId(string, in_place); 1139 if (in_place) { 1140 serializer.WriteUint32(ValueType::IN_PLACE_STRING_ID); 1141 SerializeString(string, serializer); 1142 } else { 1143 serializer.WriteUint32(ValueType::STRING_ID); 1144 serializer.WriteUint32(id); 1145 } 1146} 1147 1148void WebSnapshotSerializer::WriteStringId(Handle<String> string, 1149 ValueSerializer& serializer) { 1150 bool in_place = false; 1151 uint32_t id = GetStringId(string, in_place); 1152 CHECK(!in_place); // The string must have an ID. 1153 serializer.WriteUint32(id); 1154} 1155 1156uint32_t WebSnapshotSerializer::GetStringId(Handle<String> string, 1157 bool& in_place) { 1158 // Internalize strings so that they're unique. 1159 string = factory()->InternalizeString(string); 1160 1161 // Strings referred to more than one places are inserted in string_ids_. 1162 // Strings referred to by only one place aren't. 1163#ifdef DEBUG 1164 auto result = all_strings_.FindOrInsert(string); 1165 DCHECK(result.already_exists); 1166#endif 1167 int id = 0; 1168 in_place = !string_ids_.Lookup(*string, &id); 1169 return static_cast<uint32_t>(id); 1170} 1171 1172uint32_t WebSnapshotSerializer::GetMapId(Map map) { 1173 int id; 1174 bool return_value = map_ids_.Lookup(map, &id); 1175 DCHECK(return_value); 1176 USE(return_value); 1177 return static_cast<uint32_t>(id); 1178} 1179 1180uint32_t WebSnapshotSerializer::GetFunctionId(JSFunction function) { 1181 int id; 1182 bool return_value = function_ids_.Lookup(function, &id); 1183 DCHECK(return_value); 1184 USE(return_value); 1185 return static_cast<uint32_t>(function_ids_.size() - 1 - id); 1186} 1187 1188uint32_t WebSnapshotSerializer::GetClassId(JSFunction function) { 1189 int id; 1190 bool return_value = class_ids_.Lookup(function, &id); 1191 DCHECK(return_value); 1192 USE(return_value); 1193 return static_cast<uint32_t>(class_ids_.size() - 1 - id); 1194} 1195 1196uint32_t WebSnapshotSerializer::GetContextId(Context context) { 1197 int id; 1198 bool return_value = context_ids_.Lookup(context, &id); 1199 DCHECK(return_value); 1200 USE(return_value); 1201 return static_cast<uint32_t>(context_ids_.size() - 1 - id); 1202} 1203 1204uint32_t WebSnapshotSerializer::GetArrayId(JSArray array) { 1205 int id; 1206 bool return_value = array_ids_.Lookup(array, &id); 1207 DCHECK(return_value); 1208 USE(return_value); 1209 return static_cast<uint32_t>(array_ids_.size() - 1 - id); 1210} 1211 1212uint32_t WebSnapshotSerializer::GetObjectId(JSObject object) { 1213 int id; 1214 bool return_value = object_ids_.Lookup(object, &id); 1215 DCHECK(return_value); 1216 USE(return_value); 1217 return static_cast<uint32_t>(object_ids_.size() - 1 - id); 1218} 1219 1220uint32_t WebSnapshotSerializer::GetExternalId(HeapObject object) { 1221 int id; 1222 bool return_value = external_objects_ids_.Lookup(object, &id); 1223 DCHECK(return_value); 1224 USE(return_value); 1225 return static_cast<uint32_t>(id); 1226} 1227 1228Handle<FixedArray> WebSnapshotSerializer::GetExternals() { 1229 return external_objects_ids_.Values(isolate_); 1230} 1231 1232WebSnapshotDeserializer::WebSnapshotDeserializer(v8::Isolate* isolate, 1233 const uint8_t* data, 1234 size_t buffer_size) 1235 : WebSnapshotDeserializer(reinterpret_cast<i::Isolate*>(isolate), 1236 Handle<Object>(), {data, buffer_size}) {} 1237 1238WebSnapshotDeserializer::WebSnapshotDeserializer( 1239 Isolate* isolate, Handle<Script> snapshot_as_script) 1240 : WebSnapshotDeserializer( 1241 isolate, handle(snapshot_as_script->name(), isolate), 1242 ExtractScriptBuffer(isolate, snapshot_as_script)) {} 1243 1244WebSnapshotDeserializer::WebSnapshotDeserializer( 1245 Isolate* isolate, Handle<Object> script_name, 1246 base::Vector<const uint8_t> buffer) 1247 : WebSnapshotSerializerDeserializer(isolate), 1248 script_name_(script_name), 1249 deserializer_(isolate_, buffer.data(), buffer.length()), 1250 roots_(isolate) { 1251 Handle<FixedArray> empty_array = factory()->empty_fixed_array(); 1252 strings_handle_ = empty_array; 1253 maps_handle_ = empty_array; 1254 contexts_handle_ = empty_array; 1255 functions_handle_ = empty_array; 1256 classes_handle_ = empty_array; 1257 arrays_handle_ = empty_array; 1258 objects_handle_ = empty_array; 1259 external_references_handle_ = empty_array; 1260 isolate_->heap()->AddGCEpilogueCallback(UpdatePointersCallback, 1261 v8::kGCTypeAll, this); 1262} 1263 1264WebSnapshotDeserializer::~WebSnapshotDeserializer() { 1265 isolate_->heap()->RemoveGCEpilogueCallback(UpdatePointersCallback, this); 1266} 1267 1268void WebSnapshotDeserializer::UpdatePointers() { 1269 strings_ = *strings_handle_; 1270 maps_ = *maps_handle_; 1271 contexts_ = *contexts_handle_; 1272 functions_ = *functions_handle_; 1273 classes_ = *classes_handle_; 1274 arrays_ = *arrays_handle_; 1275 objects_ = *objects_handle_; 1276 external_references_ = *external_references_handle_; 1277} 1278 1279// static 1280base::Vector<const uint8_t> WebSnapshotDeserializer::ExtractScriptBuffer( 1281 Isolate* isolate, Handle<Script> snapshot_as_script) { 1282 Handle<String> source = 1283 handle(String::cast(snapshot_as_script->source()), isolate); 1284 if (source->IsExternalOneByteString()) { 1285 const v8::String::ExternalOneByteStringResource* resource = 1286 ExternalOneByteString::cast(*source).resource(); 1287 return {reinterpret_cast<const uint8_t*>(resource->data()), 1288 resource->length()}; 1289 } else if (source->IsSeqOneByteString()) { 1290 SeqOneByteString source_as_seq = SeqOneByteString::cast(*source); 1291 size_t length = source_as_seq.length(); 1292 std::unique_ptr<uint8_t[]> data_copy(new uint8_t[length]); 1293 { 1294 DisallowGarbageCollection no_gc; 1295 uint8_t* data = source_as_seq.GetChars(no_gc); 1296 memcpy(data_copy.get(), data, length); 1297 } 1298 return {data_copy.get(), length}; 1299 } else if (source->IsExternalTwoByteString()) { 1300 // TODO(v8:11525): Implement end-to-end snapshot processing which gets rid 1301 // of the need to copy the data here. 1302 const v8::String::ExternalStringResource* resource = 1303 ExternalTwoByteString::cast(*source).resource(); 1304 size_t length = resource->length(); 1305 std::unique_ptr<uint8_t[]> data_copy(new uint8_t[length]); 1306 { 1307 DisallowGarbageCollection no_gc; 1308 const uint16_t* data = resource->data(); 1309 uint8_t* data_copy_ptr = data_copy.get(); 1310 for (size_t i = 0; i < length; ++i) { 1311 data_copy_ptr[i] = static_cast<uint8_t>(data[i]); 1312 } 1313 } 1314 return {data_copy.get(), length}; 1315 } else if (source->IsSeqTwoByteString()) { 1316 SeqTwoByteString source_as_seq = SeqTwoByteString::cast(*source); 1317 size_t length = source_as_seq.length(); 1318 std::unique_ptr<uint8_t[]> data_copy(new uint8_t[length]); 1319 { 1320 DisallowGarbageCollection no_gc; 1321 uint16_t* data = source_as_seq.GetChars(no_gc); 1322 uint8_t* data_copy_ptr = data_copy.get(); 1323 for (size_t i = 0; i < length; ++i) { 1324 data_copy_ptr[i] = static_cast<uint8_t>(data[i]); 1325 } 1326 } 1327 return {data_copy.get(), length}; 1328 } 1329 UNREACHABLE(); 1330} 1331 1332void WebSnapshotDeserializer::Throw(const char* message) { 1333 string_count_ = 0; 1334 map_count_ = 0; 1335 context_count_ = 0; 1336 class_count_ = 0; 1337 function_count_ = 0; 1338 object_count_ = 0; 1339 deferred_references_->SetLength(0); 1340 1341 // Make sure we don't read any more data 1342 deserializer_.position_ = deserializer_.end_; 1343 1344 WebSnapshotSerializerDeserializer::Throw(message); 1345} 1346 1347bool WebSnapshotDeserializer::Deserialize( 1348 MaybeHandle<FixedArray> external_references, bool skip_exports) { 1349 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize); 1350 if (external_references.ToHandle(&external_references_handle_)) { 1351 external_references_ = *external_references_handle_; 1352 } else { 1353 external_references_handle_ = roots_.empty_fixed_array_handle(); 1354 } 1355 1356 if (deserialized_) { 1357 Throw("Can't reuse WebSnapshotDeserializer"); 1358 return false; 1359 } 1360 deserialized_ = true; 1361 auto buffer_size = deserializer_.end_ - deserializer_.position_; 1362 1363 base::ElapsedTimer timer; 1364 if (FLAG_trace_web_snapshot) { 1365 timer.Start(); 1366 } 1367 if (!DeserializeSnapshot(skip_exports)) { 1368 return false; 1369 } 1370 if (!DeserializeScript()) { 1371 return false; 1372 } 1373 1374 if (FLAG_trace_web_snapshot) { 1375 double ms = timer.Elapsed().InMillisecondsF(); 1376 PrintF("[Deserializing snapshot (%zu bytes) took %0.3f ms]\n", buffer_size, 1377 ms); 1378 } 1379 return true; 1380} 1381 1382bool WebSnapshotDeserializer::DeserializeSnapshot(bool skip_exports) { 1383 deferred_references_ = ArrayList::New(isolate_, 30); 1384 1385 const void* magic_bytes; 1386 if (!deserializer_.ReadRawBytes(sizeof(kMagicNumber), &magic_bytes) || 1387 memcmp(magic_bytes, kMagicNumber, sizeof(kMagicNumber)) != 0) { 1388 Throw("Invalid magic number"); 1389 return false; 1390 } 1391 1392 DeserializeStrings(); 1393 DeserializeMaps(); 1394 DeserializeContexts(); 1395 DeserializeFunctions(); 1396 DeserializeArrays(); 1397 DeserializeObjects(); 1398 DeserializeClasses(); 1399 ProcessDeferredReferences(); 1400 DeserializeExports(skip_exports); 1401 DCHECK_EQ(0, deferred_references_->Length()); 1402 1403 return !has_error(); 1404} 1405 1406bool WebSnapshotDeserializer::DeserializeScript() { 1407 // If there is more data, treat it as normal JavaScript. 1408 DCHECK_LE(deserializer_.position_, deserializer_.end_); 1409 auto remaining_bytes = deserializer_.end_ - deserializer_.position_; 1410 if (remaining_bytes > 0 && remaining_bytes < v8::String::kMaxLength) { 1411 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 1412 v8::Local<v8::String> source = 1413 v8::String::NewFromUtf8( 1414 v8_isolate, reinterpret_cast<const char*>(deserializer_.position_), 1415 NewStringType::kNormal, static_cast<int>(remaining_bytes)) 1416 .ToLocalChecked(); 1417 1418 ScriptOrigin origin(v8_isolate, Utils::ToLocal(script_name_)); 1419 1420 ScriptCompiler::Source script_source(source, origin); 1421 Local<UnboundScript> script; 1422 if (!ScriptCompiler::CompileUnboundScript(v8_isolate, &script_source) 1423 .ToLocal(&script)) { 1424 // The exception has already been reported. 1425 DCHECK(!isolate_->has_pending_exception()); 1426 return false; 1427 } 1428 Local<Value> result; 1429 if (!script->BindToCurrentContext() 1430 ->Run(v8_isolate->GetCurrentContext()) 1431 .ToLocal(&result)) { 1432 // The exception has already been reported. 1433 DCHECK(!isolate_->has_pending_exception()); 1434 return false; 1435 } 1436 } 1437 1438 // TODO(v8:11525): Add verification mode; verify the objects we just produced. 1439 return !has_error(); 1440} 1441 1442void WebSnapshotDeserializer::DeserializeStrings() { 1443 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Strings); 1444 if (!deserializer_.ReadUint32(&string_count_) || 1445 string_count_ > kMaxItemCount) { 1446 Throw("Malformed string table"); 1447 return; 1448 } 1449 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); 1450 strings_handle_ = factory()->NewFixedArray(string_count_); 1451 strings_ = *strings_handle_; 1452 for (uint32_t i = 0; i < string_count_; ++i) { 1453 MaybeHandle<String> maybe_string = 1454 deserializer_.ReadUtf8String(AllocationType::kOld); 1455 Handle<String> string; 1456 if (!maybe_string.ToHandle(&string)) { 1457 Throw("Malformed string"); 1458 return; 1459 } 1460 strings_.set(i, *string); 1461 } 1462} 1463 1464String WebSnapshotDeserializer::ReadString(bool internalize) { 1465 DCHECK(!strings_handle_->is_null()); 1466 uint32_t string_id; 1467 if (!deserializer_.ReadUint32(&string_id) || string_id >= string_count_) { 1468 Throw("malformed string id\n"); 1469 return roots_.empty_string(); 1470 } 1471 String string = String::cast(strings_.get(string_id)); 1472 if (internalize && !string.IsInternalizedString(isolate_)) { 1473 string = *factory()->InternalizeString(handle(string, isolate_)); 1474 strings_.set(string_id, string); 1475 } 1476 return string; 1477} 1478 1479String WebSnapshotDeserializer::ReadInPlaceString(bool internalize) { 1480 MaybeHandle<String> maybe_string = 1481 deserializer_.ReadUtf8String(AllocationType::kOld); 1482 Handle<String> string; 1483 if (!maybe_string.ToHandle(&string)) { 1484 Throw("Malformed string"); 1485 return roots_.empty_string(); 1486 } 1487 if (internalize) { 1488 string = factory()->InternalizeString(string); 1489 } 1490 return *string; 1491} 1492 1493void WebSnapshotDeserializer::DeserializeMaps() { 1494 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Maps); 1495 if (!deserializer_.ReadUint32(&map_count_) || map_count_ > kMaxItemCount) { 1496 Throw("Malformed shape table"); 1497 return; 1498 } 1499 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); 1500 maps_handle_ = factory()->NewFixedArray(map_count_); 1501 maps_ = *maps_handle_; 1502 for (uint32_t i = 0; i < map_count_; ++i) { 1503 uint32_t map_type; 1504 if (!deserializer_.ReadUint32(&map_type)) { 1505 Throw("Malformed shape"); 1506 return; 1507 } 1508 bool has_custom_property_attributes; 1509 switch (map_type) { 1510 case PropertyAttributesType::DEFAULT: 1511 has_custom_property_attributes = false; 1512 break; 1513 case PropertyAttributesType::CUSTOM: 1514 has_custom_property_attributes = true; 1515 break; 1516 default: 1517 Throw("Unsupported map type"); 1518 return; 1519 } 1520 1521 uint32_t prototype_id; 1522 if (!deserializer_.ReadUint32(&prototype_id) || 1523 prototype_id > kMaxItemCount) { 1524 Throw("Malformed shape"); 1525 return; 1526 } 1527 1528 uint32_t property_count; 1529 if (!deserializer_.ReadUint32(&property_count)) { 1530 Throw("Malformed shape"); 1531 return; 1532 } 1533 // TODO(v8:11525): Consider passing the upper bound as a param and 1534 // systematically enforcing it on the ValueSerializer side. 1535 if (property_count > kMaxNumberOfDescriptors) { 1536 Throw("Malformed shape: too many properties"); 1537 return; 1538 } 1539 1540 if (property_count == 0) { 1541 DisallowGarbageCollection no_gc; 1542 Map empty_map = 1543 isolate_->native_context()->object_function().initial_map(); 1544 maps_.set(i, empty_map); 1545 continue; 1546 } 1547 1548 Handle<DescriptorArray> descriptors = 1549 factory()->NewDescriptorArray(property_count, 0); 1550 for (InternalIndex i : InternalIndex::Range(property_count)) { 1551 PropertyAttributes attributes = PropertyAttributes::NONE; 1552 if (has_custom_property_attributes) { 1553 uint32_t flags; 1554 if (!deserializer_.ReadUint32(&flags)) { 1555 Throw("Malformed shape"); 1556 return; 1557 } 1558 attributes = FlagsToAttributes(flags); 1559 } 1560 1561 Handle<String> key(ReadString(true), isolate_); 1562 1563 // Use the "none" representation until we see the first object having this 1564 // map. At that point, modify the representation. 1565 Descriptor desc = Descriptor::DataField( 1566 isolate_, key, i.as_int(), attributes, Representation::None()); 1567 descriptors->Set(i, &desc); 1568 } 1569 DCHECK_EQ(descriptors->number_of_descriptors(), property_count); 1570 descriptors->Sort(); 1571 1572 Handle<Map> map = factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize, 1573 HOLEY_ELEMENTS, 0); 1574 map->InitializeDescriptors(isolate_, *descriptors); 1575 // TODO(v8:11525): Set 'constructor'. 1576 1577 if (prototype_id == 0) { 1578 // Use Object.prototype as the prototype. 1579 map->set_prototype(isolate_->native_context()->initial_object_prototype(), 1580 UPDATE_WRITE_BARRIER); 1581 } else { 1582 // TODO(v8::11525): Implement stricter checks, e.g., disallow cycles. 1583 --prototype_id; 1584 if (prototype_id < current_object_count_) { 1585 map->set_prototype(HeapObject::cast(objects_.get(prototype_id)), 1586 UPDATE_WRITE_BARRIER); 1587 } else { 1588 // The object hasn't been deserialized yet. 1589 AddDeferredReference(map, 0, OBJECT_ID, prototype_id); 1590 } 1591 } 1592 maps_.set(i, *map); 1593 } 1594} 1595 1596void WebSnapshotDeserializer::DeserializeContexts() { 1597 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Contexts); 1598 if (!deserializer_.ReadUint32(&context_count_) || 1599 context_count_ > kMaxItemCount) { 1600 Throw("Malformed context table"); 1601 return; 1602 } 1603 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); 1604 contexts_handle_ = factory()->NewFixedArray(context_count_); 1605 contexts_ = *contexts_handle_; 1606 for (uint32_t i = 0; i < context_count_; ++i) { 1607 uint32_t context_type; 1608 if (!deserializer_.ReadUint32(&context_type)) { 1609 Throw("Malformed context type"); 1610 return; 1611 } 1612 1613 uint32_t parent_context_id; 1614 // Parent context is serialized before child context. Note: not >= on 1615 // purpose, we're going to subtract 1 later. 1616 if (!deserializer_.ReadUint32(&parent_context_id) || 1617 parent_context_id > i) { 1618 Throw("Malformed context"); 1619 return; 1620 } 1621 1622 uint32_t variable_count; 1623 if (!deserializer_.ReadUint32(&variable_count)) { 1624 Throw("Malformed context"); 1625 return; 1626 } 1627 // TODO(v8:11525): Enforce upper limit for variable count. 1628 Handle<ScopeInfo> scope_info = 1629 CreateScopeInfo(variable_count, parent_context_id > 0, 1630 static_cast<ContextType>(context_type)); 1631 1632 Handle<Context> parent_context; 1633 if (parent_context_id > 0) { 1634 parent_context = 1635 handle(Context::cast(contexts_.get(parent_context_id - 1)), isolate_); 1636 scope_info->set_outer_scope_info(parent_context->scope_info()); 1637 } else { 1638 parent_context = handle(isolate_->context(), isolate_); 1639 } 1640 1641 const int context_local_base = ScopeInfo::kVariablePartIndex; 1642 const int context_local_info_base = context_local_base + variable_count; 1643 for (int variable_index = 0; 1644 variable_index < static_cast<int>(variable_count); ++variable_index) { 1645 { 1646 String name = ReadString(true); 1647 scope_info->set(context_local_base + variable_index, name); 1648 } 1649 1650 // TODO(v8:11525): Support variable modes etc. 1651 uint32_t info = 1652 ScopeInfo::VariableModeBits::encode(VariableMode::kLet) | 1653 ScopeInfo::InitFlagBit::encode( 1654 InitializationFlag::kNeedsInitialization) | 1655 ScopeInfo::MaybeAssignedFlagBit::encode( 1656 MaybeAssignedFlag::kMaybeAssigned) | 1657 ScopeInfo::ParameterNumberBits::encode( 1658 ScopeInfo::ParameterNumberBits::kMax) | 1659 ScopeInfo::IsStaticFlagBit::encode(IsStaticFlag::kNotStatic); 1660 scope_info->set(context_local_info_base + variable_index, 1661 Smi::FromInt(info)); 1662 } 1663 1664 // Allocate the FunctionContext after setting up the ScopeInfo to avoid 1665 // pointing to a ScopeInfo which is not set up yet. 1666 Handle<Context> context; 1667 switch (context_type) { 1668 case ContextType::FUNCTION: 1669 context = factory()->NewFunctionContext(parent_context, scope_info); 1670 break; 1671 case ContextType::BLOCK: 1672 context = factory()->NewBlockContext(parent_context, scope_info); 1673 break; 1674 default: 1675 Throw("Unsupported context type"); 1676 return; 1677 } 1678 int context_header_length = scope_info->ContextHeaderLength(); 1679 for (int variable_index = 0; 1680 variable_index < static_cast<int>(variable_count); ++variable_index) { 1681 int context_index = context_header_length + variable_index; 1682 Object value = ReadValue(context, context_index); 1683 context->set(context_index, value); 1684 } 1685 contexts_.set(i, *context); 1686 } 1687} 1688 1689Handle<ScopeInfo> WebSnapshotDeserializer::CreateScopeInfo( 1690 uint32_t variable_count, bool has_parent, ContextType context_type) { 1691 // TODO(v8:11525): Decide how to handle language modes. (The code below sets 1692 // the language mode as strict.) 1693 // TODO(v8:11525): Support (context-allocating) receiver. 1694 // TODO(v8:11525): Support function variable & function name. 1695 // TODO(v8:11525): Support classes. 1696 1697 ScopeType scope_type; 1698 int flags = 1699 ScopeInfo::SloppyEvalCanExtendVarsBit::encode(false) | 1700 ScopeInfo::LanguageModeBit::encode(LanguageMode::kStrict) | 1701 ScopeInfo::DeclarationScopeBit::encode(false) | 1702 ScopeInfo::ReceiverVariableBits::encode(VariableAllocationInfo::NONE) | 1703 ScopeInfo::ClassScopeHasPrivateBrandBit::encode(false) | 1704 ScopeInfo::HasSavedClassVariableBit::encode(false) | 1705 ScopeInfo::HasNewTargetBit::encode(false) | 1706 ScopeInfo::FunctionVariableBits::encode(VariableAllocationInfo::NONE) | 1707 ScopeInfo::HasInferredFunctionNameBit::encode(false) | 1708 ScopeInfo::IsAsmModuleBit::encode(false) | 1709 ScopeInfo::HasSimpleParametersBit::encode(false) | 1710 ScopeInfo::FunctionKindBits::encode(FunctionKind::kNormalFunction) | 1711 ScopeInfo::HasOuterScopeInfoBit::encode(has_parent) | 1712 ScopeInfo::IsDebugEvaluateScopeBit::encode(false) | 1713 ScopeInfo::ForceContextAllocationBit::encode(false) | 1714 ScopeInfo::PrivateNameLookupSkipsOuterClassBit::encode(false) | 1715 ScopeInfo::HasContextExtensionSlotBit::encode(false) | 1716 ScopeInfo::IsReplModeScopeBit::encode(false) | 1717 ScopeInfo::HasLocalsBlockListBit::encode(false); 1718 switch (context_type) { 1719 case ContextType::FUNCTION: 1720 scope_type = ScopeType::FUNCTION_SCOPE; 1721 flags |= ScopeInfo::DeclarationScopeBit::encode(true) | 1722 ScopeInfo::HasSimpleParametersBit::encode(true); 1723 break; 1724 case ContextType::BLOCK: 1725 scope_type = ScopeType::CLASS_SCOPE; 1726 flags |= ScopeInfo::ForceContextAllocationBit::encode(true); 1727 break; 1728 default: 1729 // Default to a CLASS_SCOPE, so that the rest of the code can be executed 1730 // without failures. 1731 scope_type = ScopeType::CLASS_SCOPE; 1732 Throw("Unsupported context type"); 1733 } 1734 flags |= ScopeInfo::ScopeTypeBits::encode(scope_type); 1735 const int length = ScopeInfo::kVariablePartIndex + 1736 (ScopeInfo::NeedsPositionInfo(scope_type) 1737 ? ScopeInfo::kPositionInfoEntries 1738 : 0) + 1739 (has_parent ? 1 : 0) + 2 * variable_count; 1740 Handle<ScopeInfo> scope_info = factory()->NewScopeInfo(length); 1741 { 1742 DisallowGarbageCollection no_gc; 1743 ScopeInfo raw = *scope_info; 1744 1745 raw.set_flags(flags); 1746 DCHECK(!raw.IsEmpty()); 1747 1748 raw.set_context_local_count(variable_count); 1749 // TODO(v8:11525): Support parameters. 1750 raw.set_parameter_count(0); 1751 if (raw.HasPositionInfo()) { 1752 raw.SetPositionInfo(0, 0); 1753 } 1754 } 1755 return scope_info; 1756} 1757 1758Handle<JSFunction> WebSnapshotDeserializer::CreateJSFunction( 1759 int shared_function_info_index, uint32_t start_position, uint32_t length, 1760 uint32_t parameter_count, uint32_t flags, uint32_t context_id) { 1761 // TODO(v8:11525): Deduplicate the SFIs for class methods. 1762 FunctionKind kind = FunctionFlagsToFunctionKind(flags); 1763 Handle<SharedFunctionInfo> shared = factory()->NewSharedFunctionInfo( 1764 factory()->empty_string(), MaybeHandle<Code>(), Builtin::kCompileLazy, 1765 kind); 1766 Handle<UncompiledData> uncompiled_data = 1767 factory()->NewUncompiledDataWithoutPreparseData( 1768 roots_.empty_string_handle(), start_position, 1769 start_position + length); 1770 { 1771 DisallowGarbageCollection no_gc; 1772 SharedFunctionInfo raw = *shared; 1773 if (IsConciseMethod(kind)) { 1774 raw.set_syntax_kind(FunctionSyntaxKind::kAccessorOrMethod); 1775 } 1776 raw.set_script(*script_); 1777 raw.set_function_literal_id(shared_function_info_index); 1778 raw.set_internal_formal_parameter_count(JSParameterCount(parameter_count)); 1779 // TODO(v8:11525): Decide how to handle language modes. 1780 raw.set_language_mode(LanguageMode::kStrict); 1781 raw.set_uncompiled_data(*uncompiled_data); 1782 raw.set_allows_lazy_compilation(true); 1783 shared_function_infos_.Set(shared_function_info_index, 1784 HeapObjectReference::Weak(raw)); 1785 } 1786 shared_function_info_table_ = ObjectHashTable::Put( 1787 shared_function_info_table_, 1788 handle(Smi::FromInt(start_position), isolate_), 1789 handle(Smi::FromInt(shared_function_info_index), isolate_)); 1790 1791 Handle<JSFunction> function = 1792 Factory::JSFunctionBuilder(isolate_, shared, isolate_->native_context()) 1793 .Build(); 1794 if (context_id > 0) { 1795 DCHECK_LT(context_id - 1, context_count_); 1796 // Guards raw pointer "context" below. 1797 DisallowHeapAllocation no_heap_access; 1798 Context context = Context::cast(contexts_.get(context_id - 1)); 1799 function->set_context(context); 1800 shared->set_outer_scope_info(context.scope_info()); 1801 } 1802 return function; 1803} 1804 1805void WebSnapshotDeserializer::DeserializeFunctions() { 1806 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Functions); 1807 if (!deserializer_.ReadUint32(&function_count_) || 1808 function_count_ > kMaxItemCount) { 1809 Throw("Malformed function table"); 1810 return; 1811 } 1812 STATIC_ASSERT(kMaxItemCount + 1 <= FixedArray::kMaxLength); 1813 functions_handle_ = factory()->NewFixedArray(function_count_); 1814 functions_ = *functions_handle_; 1815 1816 // Overallocate the array for SharedFunctionInfos; functions which we 1817 // deserialize soon will create more SharedFunctionInfos when called. 1818 shared_function_infos_handle_ = factory()->NewWeakFixedArray( 1819 WeakArrayList::CapacityForLength(function_count_ + 1), 1820 AllocationType::kOld); 1821 shared_function_infos_ = *shared_function_infos_handle_; 1822 shared_function_info_table_ = ObjectHashTable::New(isolate_, function_count_); 1823 script_ = factory()->NewScript(factory()->empty_string()); 1824 { 1825 DisallowGarbageCollection no_gc; 1826 Script raw = *script_; 1827 raw.set_type(Script::TYPE_WEB_SNAPSHOT); 1828 raw.set_shared_function_infos(shared_function_infos_); 1829 raw.set_shared_function_info_table(*shared_function_info_table_); 1830 } 1831 1832 for (; current_function_count_ < function_count_; ++current_function_count_) { 1833 uint32_t context_id; 1834 // Note: > (not >= on purpose, we will subtract 1). 1835 if (!deserializer_.ReadUint32(&context_id) || context_id > context_count_) { 1836 Throw("Malformed function"); 1837 return; 1838 } 1839 { 1840 String source = ReadString(false); 1841 DisallowGarbageCollection no_gc; 1842 if (current_function_count_ == 0) { 1843 script_->set_source(source); 1844 } else { 1845 // TODO(v8:11525): Support multiple source snippets. 1846 DCHECK_EQ(script_->source(), source); 1847 } 1848 } 1849 1850 uint32_t start_position; 1851 uint32_t length; 1852 uint32_t parameter_count; 1853 uint32_t flags; 1854 if (!deserializer_.ReadUint32(&start_position) || 1855 !deserializer_.ReadUint32(&length) || 1856 !deserializer_.ReadUint32(¶meter_count) || 1857 !deserializer_.ReadUint32(&flags)) { 1858 Throw("Malformed function"); 1859 return; 1860 } 1861 1862 // Index 0 is reserved for top-level shared function info (which web 1863 // snapshot scripts don't have). 1864 Handle<JSFunction> function = 1865 CreateJSFunction(current_function_count_ + 1, start_position, length, 1866 parameter_count, flags, context_id); 1867 functions_.set(current_function_count_, *function); 1868 1869 ReadFunctionPrototype(function); 1870 } 1871} 1872 1873void WebSnapshotDeserializer::DeserializeClasses() { 1874 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Classes); 1875 if (!deserializer_.ReadUint32(&class_count_) || 1876 class_count_ > kMaxItemCount) { 1877 Throw("Malformed class table"); 1878 return; 1879 } 1880 STATIC_ASSERT(kMaxItemCount + 1 <= FixedArray::kMaxLength); 1881 classes_handle_ = factory()->NewFixedArray(class_count_); 1882 classes_ = *classes_handle_; 1883 1884 // Grow the array for SharedFunctionInfos. 1885 shared_function_infos_handle_ = WeakFixedArray::EnsureSpace( 1886 isolate_, shared_function_infos_handle_, 1887 WeakArrayList::CapacityForLength(function_count_ + 1 + class_count_)); 1888 shared_function_infos_ = *shared_function_infos_handle_; 1889 script_->set_shared_function_infos(shared_function_infos_); 1890 1891 for (; current_class_count_ < class_count_; ++current_class_count_) { 1892 uint32_t context_id; 1893 // Note: > (not >= on purpose, we will subtract 1). 1894 if (!deserializer_.ReadUint32(&context_id) || context_id > context_count_) { 1895 Throw("Malformed class"); 1896 return; 1897 } 1898 1899 { 1900 String source = ReadString(false); 1901 if (current_function_count_ + current_class_count_ == 0) { 1902 script_->set_source(source); 1903 } else { 1904 // TODO(v8:11525): Support multiple source snippets. 1905 DCHECK_EQ(script_->source(), source); 1906 } 1907 } 1908 1909 uint32_t start_position; 1910 uint32_t length; 1911 uint32_t parameter_count; 1912 uint32_t flags; 1913 if (!deserializer_.ReadUint32(&start_position) || 1914 !deserializer_.ReadUint32(&length) || 1915 !deserializer_.ReadUint32(¶meter_count) || 1916 !deserializer_.ReadUint32(&flags)) { 1917 Throw("Malformed class"); 1918 return; 1919 } 1920 1921 // Index 0 is reserved for top-level shared function info (which web 1922 // snapshot scripts don't have). 1923 Handle<JSFunction> function = CreateJSFunction( 1924 function_count_ + current_class_count_ + 1, start_position, length, 1925 parameter_count, flags, context_id); 1926 classes_.set(current_class_count_, *function); 1927 1928 ReadFunctionPrototype(function); 1929 } 1930} 1931 1932void WebSnapshotDeserializer::DeserializeObjects() { 1933 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Objects); 1934 if (!deserializer_.ReadUint32(&object_count_) || 1935 object_count_ > kMaxItemCount) { 1936 Throw("Malformed objects table"); 1937 return; 1938 } 1939 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); 1940 objects_handle_ = factory()->NewFixedArray(object_count_); 1941 objects_ = *objects_handle_; 1942 for (; current_object_count_ < object_count_; ++current_object_count_) { 1943 uint32_t map_id; 1944 if (!deserializer_.ReadUint32(&map_id) || map_id >= map_count_) { 1945 Throw("Malformed object"); 1946 return; 1947 } 1948 Map raw_map = Map::cast(maps_.get(map_id)); 1949 Handle<DescriptorArray> descriptors = 1950 handle(raw_map.instance_descriptors(kRelaxedLoad), isolate_); 1951 int no_properties = raw_map.NumberOfOwnDescriptors(); 1952 // TODO(v8:11525): In-object properties. 1953 Handle<Map> map(raw_map, isolate_); 1954 Handle<PropertyArray> property_array = 1955 factory()->NewPropertyArray(no_properties); 1956 for (int i = 0; i < no_properties; ++i) { 1957 Object value = ReadValue(property_array, i); 1958 DisallowGarbageCollection no_gc; 1959 // Read the representation from the map. 1960 DescriptorArray raw_descriptors = *descriptors; 1961 PropertyDetails details = raw_descriptors.GetDetails(InternalIndex(i)); 1962 CHECK_EQ(details.location(), PropertyLocation::kField); 1963 CHECK_EQ(PropertyKind::kData, details.kind()); 1964 Representation r = details.representation(); 1965 if (r.IsNone()) { 1966 // Switch over to wanted_representation. 1967 details = details.CopyWithRepresentation(Representation::Tagged()); 1968 raw_descriptors.SetDetails(InternalIndex(i), details); 1969 } else if (!r.Equals(Representation::Tagged())) { 1970 // TODO(v8:11525): Support this case too. 1971 UNREACHABLE(); 1972 } 1973 property_array->set(i, value); 1974 } 1975 Handle<JSObject> object = factory()->NewJSObjectFromMap(map); 1976 object->set_raw_properties_or_hash(*property_array, kRelaxedStore); 1977 1978 uint32_t max_element_index = 0; 1979 if (!deserializer_.ReadUint32(&max_element_index) || 1980 max_element_index > kMaxItemCount + 1) { 1981 Throw("Malformed object"); 1982 return; 1983 } 1984 if (max_element_index > 0) { 1985 --max_element_index; // Subtract 1 to get the real max_element_index. 1986 Handle<FixedArray> elements = 1987 factory()->NewFixedArray(max_element_index + 1); 1988 // Read (index, value) pairs until we encounter one where index == 1989 // max_element_index. 1990 while (true) { 1991 uint32_t index; 1992 if (!deserializer_.ReadUint32(&index) || index > max_element_index) { 1993 Throw("Malformed object"); 1994 return; 1995 } 1996 Object value = ReadValue(elements, index); 1997 elements->set(index, value); 1998 if (index == max_element_index) { 1999 break; 2000 } 2001 } 2002 object->set_elements(*elements); 2003 // Objects always get HOLEY_ELEMENTS. 2004 DCHECK(!IsSmiElementsKind(object->map().elements_kind())); 2005 DCHECK(!IsDoubleElementsKind(object->map().elements_kind())); 2006 DCHECK(IsHoleyElementsKind(object->map().elements_kind())); 2007 } 2008 objects_.set(static_cast<int>(current_object_count_), *object); 2009 } 2010} 2011 2012void WebSnapshotDeserializer::DeserializeArrays() { 2013 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Arrays); 2014 if (!deserializer_.ReadUint32(&array_count_) || 2015 object_count_ > kMaxItemCount) { 2016 Throw("Malformed array table"); 2017 return; 2018 } 2019 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); 2020 arrays_handle_ = factory()->NewFixedArray(array_count_); 2021 arrays_ = *arrays_handle_; 2022 for (; current_array_count_ < array_count_; ++current_array_count_) { 2023 uint32_t length; 2024 if (!deserializer_.ReadUint32(&length) || length > kMaxItemCount) { 2025 Throw("Malformed array"); 2026 return; 2027 } 2028 Handle<FixedArray> elements = factory()->NewFixedArray(length); 2029 ElementsKind elements_kind = PACKED_SMI_ELEMENTS; 2030 for (uint32_t i = 0; i < length; ++i) { 2031 Object value = ReadValue(elements, i); 2032 DisallowGarbageCollection no_gc; 2033 if (!value.IsSmi()) { 2034 elements_kind = PACKED_ELEMENTS; 2035 } 2036 elements->set(static_cast<int>(i), value); 2037 } 2038 Handle<JSArray> array = 2039 factory()->NewJSArrayWithElements(elements, elements_kind, length); 2040 arrays_.set(static_cast<int>(current_array_count_), *array); 2041 } 2042} 2043 2044void WebSnapshotDeserializer::DeserializeExports(bool skip_exports) { 2045 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Exports); 2046 uint32_t count; 2047 if (!deserializer_.ReadUint32(&count) || count > kMaxItemCount) { 2048 Throw("Malformed export table"); 2049 return; 2050 } 2051 2052 if (skip_exports) { 2053 // In the skip_exports mode, we read the exports but don't do anything about 2054 // them. This is useful for stress testing; otherwise the GlobalDictionary 2055 // handling below dominates. 2056 for (uint32_t i = 0; i < count; ++i) { 2057 Handle<String> export_name(ReadString(true), isolate_); 2058 // No deferred references should occur at this point, since all objects 2059 // have been deserialized. 2060 Object export_value = ReadValue(); 2061 USE(export_name); 2062 USE(export_value); 2063 } 2064 return; 2065 } 2066 2067 // Pre-reserve the space for the properties we're going to add to the global 2068 // object. 2069 Handle<JSGlobalObject> global = isolate_->global_object(); 2070 Handle<GlobalDictionary> dictionary( 2071 global->global_dictionary(isolate_, kAcquireLoad), isolate_); 2072 2073 dictionary = GlobalDictionary::EnsureCapacity( 2074 isolate_, dictionary, dictionary->NumberOfElements() + count, 2075 AllocationType::kYoung); 2076 bool has_exported_values = false; 2077 2078 // TODO(v8:11525): The code below skips checks, in particular 2079 // LookupIterator::UpdateProtectors and 2080 // LookupIterator::ExtendingNonExtensible. 2081 InternalIndex entry = InternalIndex::NotFound(); 2082 for (uint32_t i = 0; i < count; ++i) { 2083 Handle<String> export_name(ReadString(true), isolate_); 2084 // No deferred references should occur at this point, since all objects have 2085 // been deserialized. 2086 Object export_value = ReadValue(); 2087 2088 if (export_name->length() == 0 && i == 0) { 2089 // Hack: treat the first empty-string-named export value as a return value 2090 // from the deserializer. 2091 CHECK_EQ(i, 0); 2092 return_value_ = handle(export_value, isolate_); 2093 continue; 2094 } 2095 2096 DisallowGarbageCollection no_gc; 2097 // Check for the correctness of the snapshot (thus far) before producing 2098 // something observable. TODO(v8:11525): Strictly speaking, we should 2099 // produce observable effects only when we know that the whole snapshot is 2100 // correct. 2101 if (has_error()) return; 2102 2103 PropertyDetails property_details = 2104 PropertyDetails(PropertyKind::kData, NONE, 2105 PropertyCell::InitialType(isolate_, export_value)); 2106 Handle<Object> export_value_handle(export_value, isolate_); 2107 AllowGarbageCollection allow_gc; 2108 Handle<PropertyCell> transition_cell = factory()->NewPropertyCell( 2109 export_name, property_details, export_value_handle); 2110 dictionary = 2111 GlobalDictionary::Add(isolate_, dictionary, export_name, 2112 transition_cell, property_details, &entry); 2113 has_exported_values = true; 2114 } 2115 2116 if (!has_exported_values) return; 2117 2118 global->set_global_dictionary(*dictionary, kReleaseStore); 2119 JSObject::InvalidatePrototypeChains(global->map(isolate_)); 2120} 2121 2122Object WebSnapshotDeserializer::ReadValue(Handle<HeapObject> container, 2123 uint32_t container_index) { 2124 uint32_t value_type; 2125 // TODO(v8:11525): Consider adding a ReadByte. 2126 if (!deserializer_.ReadUint32(&value_type)) { 2127 Throw("Malformed variable"); 2128 // Set "value" here so that the "keep on trucking" error handling won't fail 2129 // when dereferencing the handle. 2130 return Smi::zero(); 2131 } 2132 switch (value_type) { 2133 case ValueType::FALSE_CONSTANT: 2134 return roots_.false_value(); 2135 case ValueType::TRUE_CONSTANT: 2136 return roots_.true_value(); 2137 case ValueType::NULL_CONSTANT: 2138 return roots_.null_value(); 2139 case ValueType::UNDEFINED_CONSTANT: 2140 return roots_.undefined_value(); 2141 case ValueType::INTEGER: 2142 return ReadInteger(); 2143 case ValueType::DOUBLE: 2144 return ReadNumber(); 2145 case ValueType::STRING_ID: 2146 return ReadString(false); 2147 case ValueType::ARRAY_ID: 2148 return ReadArray(container, container_index); 2149 case ValueType::OBJECT_ID: 2150 return ReadObject(container, container_index); 2151 case ValueType::FUNCTION_ID: 2152 return ReadFunction(container, container_index); 2153 case ValueType::CLASS_ID: 2154 return ReadClass(container, container_index); 2155 case ValueType::REGEXP: 2156 return ReadRegexp(); 2157 case ValueType::EXTERNAL_ID: 2158 return ReadExternalReference(); 2159 case ValueType::IN_PLACE_STRING_ID: 2160 return ReadInPlaceString(false); 2161 default: 2162 // TODO(v8:11525): Handle other value types. 2163 Throw("Unsupported value type"); 2164 return Smi::zero(); 2165 } 2166} 2167 2168Object WebSnapshotDeserializer::ReadInteger() { 2169 Maybe<int32_t> number = deserializer_.ReadZigZag<int32_t>(); 2170 if (number.IsNothing()) { 2171 Throw("Malformed integer"); 2172 return Smi::zero(); 2173 } 2174 return *factory()->NewNumberFromInt(number.FromJust()); 2175} 2176 2177Object WebSnapshotDeserializer::ReadNumber() { 2178 double number; 2179 if (!deserializer_.ReadDouble(&number)) { 2180 Throw("Malformed double"); 2181 return Smi::zero(); 2182 } 2183 return *factory()->NewNumber(number); 2184} 2185 2186Object WebSnapshotDeserializer::ReadArray(Handle<HeapObject> container, 2187 uint32_t index) { 2188 uint32_t array_id; 2189 if (!deserializer_.ReadUint32(&array_id) || array_id >= kMaxItemCount) { 2190 Throw("Malformed variable"); 2191 return Smi::zero(); 2192 } 2193 if (array_id < current_array_count_) { 2194 return arrays_.get(array_id); 2195 } 2196 // The array hasn't been deserialized yet. 2197 return AddDeferredReference(container, index, ARRAY_ID, array_id); 2198} 2199 2200Object WebSnapshotDeserializer::ReadObject(Handle<HeapObject> container, 2201 uint32_t index) { 2202 uint32_t object_id; 2203 if (!deserializer_.ReadUint32(&object_id) || object_id > kMaxItemCount) { 2204 Throw("Malformed variable"); 2205 return Smi::zero(); 2206 } 2207 if (object_id < current_object_count_) { 2208 return objects_.get(object_id); 2209 } 2210 // The object hasn't been deserialized yet. 2211 return AddDeferredReference(container, index, OBJECT_ID, object_id); 2212} 2213 2214Object WebSnapshotDeserializer::ReadFunction(Handle<HeapObject> container, 2215 uint32_t index) { 2216 uint32_t function_id; 2217 if (!deserializer_.ReadUint32(&function_id) || 2218 function_id >= function_count_) { 2219 Throw("Malformed object property"); 2220 return Smi::zero(); 2221 } 2222 if (function_id < current_function_count_) { 2223 return functions_.get(function_id); 2224 } 2225 // The function hasn't been deserialized yet. 2226 return AddDeferredReference(container, index, FUNCTION_ID, function_id); 2227} 2228 2229Object WebSnapshotDeserializer::ReadClass(Handle<HeapObject> container, 2230 uint32_t index) { 2231 uint32_t class_id; 2232 if (!deserializer_.ReadUint32(&class_id) || class_id >= kMaxItemCount) { 2233 Throw("Malformed object property"); 2234 return Smi::zero(); 2235 } 2236 if (class_id < current_class_count_) { 2237 return classes_.get(class_id); 2238 } 2239 // The class hasn't been deserialized yet. 2240 return AddDeferredReference(container, index, CLASS_ID, class_id); 2241} 2242 2243Object WebSnapshotDeserializer::ReadRegexp() { 2244 Handle<String> pattern(ReadString(false), isolate_); 2245 Handle<String> flags_string(ReadString(false), isolate_); 2246 base::Optional<JSRegExp::Flags> flags = 2247 JSRegExp::FlagsFromString(isolate_, flags_string); 2248 if (!flags.has_value()) { 2249 Throw("Malformed flags in regular expression"); 2250 return Smi::zero(); 2251 } 2252 MaybeHandle<JSRegExp> maybe_regexp = 2253 JSRegExp::New(isolate_, pattern, flags.value()); 2254 Handle<JSRegExp> regexp; 2255 if (!maybe_regexp.ToHandle(®exp)) { 2256 Throw("Malformed RegExp"); 2257 return Smi::zero(); 2258 } 2259 return *regexp; 2260} 2261 2262Object WebSnapshotDeserializer::ReadExternalReference() { 2263 uint32_t ref_id; 2264 if (!deserializer_.ReadUint32(&ref_id) || 2265 ref_id >= static_cast<uint32_t>(external_references_.length())) { 2266 Throw("Invalid external reference"); 2267 return Smi::zero(); 2268 } 2269 return external_references_.get(ref_id); 2270} 2271 2272void WebSnapshotDeserializer::ReadFunctionPrototype( 2273 Handle<JSFunction> function) { 2274 uint32_t object_id; 2275 2276 if (!deserializer_.ReadUint32(&object_id) || object_id > kMaxItemCount + 1) { 2277 Throw("Malformed class / function"); 2278 return; 2279 } 2280 if (object_id == 0) { 2281 // No prototype. 2282 return; 2283 } 2284 --object_id; 2285 if (object_id < current_object_count_) { 2286 if (!SetFunctionPrototype(*function, 2287 JSReceiver::cast(objects_.get(object_id)))) { 2288 Throw("Can't reuse function prototype"); 2289 return; 2290 } 2291 } else { 2292 // The object hasn't been deserialized yet. 2293 AddDeferredReference(function, 0, OBJECT_ID, object_id); 2294 } 2295} 2296 2297bool WebSnapshotDeserializer::SetFunctionPrototype(JSFunction function, 2298 JSReceiver prototype) { 2299 DisallowGarbageCollection no_gc; 2300 // TODO(v8:11525): Enforce the invariant that no two prototypes share a map. 2301 Map map = prototype.map(); 2302 map.set_is_prototype_map(true); 2303 if (!map.constructor_or_back_pointer().IsNullOrUndefined(isolate_)) { 2304 return false; 2305 } 2306 map.set_constructor_or_back_pointer(function); 2307 function.set_prototype_or_initial_map(prototype, kReleaseStore); 2308 return true; 2309} 2310 2311HeapObject WebSnapshotDeserializer::AddDeferredReference( 2312 Handle<HeapObject> container, uint32_t index, ValueType target_type, 2313 uint32_t target_index) { 2314 if (container.is_null()) { 2315 const char* message = "Invalid reference"; 2316 switch (target_type) { 2317 case ARRAY_ID: 2318 message = "Invalid array reference"; 2319 break; 2320 case OBJECT_ID: 2321 message = "Invalid object reference"; 2322 break; 2323 case CLASS_ID: 2324 message = "Invalid class reference"; 2325 break; 2326 case FUNCTION_ID: 2327 message = "Invalid function reference"; 2328 break; 2329 default: 2330 break; 2331 } 2332 Throw(message); 2333 return roots_.undefined_value(); 2334 } 2335 DCHECK(container->IsPropertyArray() || container->IsContext() || 2336 container->IsFixedArray() || container->IsJSFunction() || 2337 container->IsMap()); 2338 deferred_references_ = ArrayList::Add( 2339 isolate_, deferred_references_, container, Smi::FromInt(index), 2340 Smi::FromInt(target_type), Smi::FromInt(target_index)); 2341 // Use HeapObject as placeholder since this might break elements kinds. 2342 return roots_.undefined_value(); 2343} 2344 2345void WebSnapshotDeserializer::ProcessDeferredReferences() { 2346 // Check for error now, since the FixedArrays below might not have been 2347 // created if there was an error. 2348 if (has_error()) return; 2349 2350 DisallowGarbageCollection no_gc; 2351 ArrayList raw_deferred_references = *deferred_references_; 2352 2353 // Deferred references is a list of (object, index, target type, target index) 2354 // tuples. 2355 for (int i = 0; i < raw_deferred_references.Length() - 3; i += 4) { 2356 HeapObject container = HeapObject::cast(raw_deferred_references.Get(i)); 2357 int index = raw_deferred_references.Get(i + 1).ToSmi().value(); 2358 ValueType target_type = static_cast<ValueType>( 2359 raw_deferred_references.Get(i + 2).ToSmi().value()); 2360 int target_index = raw_deferred_references.Get(i + 3).ToSmi().value(); 2361 Object target; 2362 switch (target_type) { 2363 case FUNCTION_ID: 2364 if (static_cast<uint32_t>(target_index) >= function_count_) { 2365 // Throw can allocate, but it's ok, since we're not using the raw 2366 // pointers after that. 2367 AllowGarbageCollection allow_gc; 2368 Throw("Invalid function reference"); 2369 return; 2370 } 2371 target = functions_.get(target_index); 2372 break; 2373 case CLASS_ID: 2374 if (static_cast<uint32_t>(target_index) >= class_count_) { 2375 AllowGarbageCollection allow_gc; 2376 Throw("Invalid class reference"); 2377 return; 2378 } 2379 target = classes_.get(target_index); 2380 break; 2381 case ARRAY_ID: 2382 if (static_cast<uint32_t>(target_index) >= array_count_) { 2383 AllowGarbageCollection allow_gc; 2384 Throw("Invalid array reference"); 2385 return; 2386 } 2387 target = arrays_.get(target_index); 2388 break; 2389 case OBJECT_ID: 2390 if (static_cast<uint32_t>(target_index) >= object_count_) { 2391 AllowGarbageCollection allow_gc; 2392 Throw("Invalid object reference"); 2393 return; 2394 } 2395 target = objects_.get(target_index); 2396 break; 2397 default: 2398 UNREACHABLE(); 2399 } 2400 InstanceType instance_type = container.map().instance_type(); 2401 if (InstanceTypeChecker::IsPropertyArray(instance_type)) { 2402 PropertyArray::cast(container).set(index, target); 2403 } else if (InstanceTypeChecker::IsContext(instance_type)) { 2404 Context::cast(container).set(index, target); 2405 } else if (InstanceTypeChecker::IsFixedArray(instance_type)) { 2406 FixedArray::cast(container).set(index, target); 2407 } else if (InstanceTypeChecker::IsJSFunction(instance_type)) { 2408 // The only deferred reference allowed for a JSFunction is the function 2409 // prototype. 2410 DCHECK_EQ(index, 0); 2411 DCHECK(target.IsJSReceiver()); 2412 if (!SetFunctionPrototype(JSFunction::cast(container), 2413 JSReceiver::cast(target))) { 2414 AllowGarbageCollection allow_gc; 2415 Throw("Can't reuse function prototype"); 2416 return; 2417 } 2418 } else if (InstanceTypeChecker::IsMap(instance_type)) { 2419 // The only deferred reference allowed for a Map is the __proto__. 2420 DCHECK_EQ(index, 0); 2421 DCHECK(target.IsJSReceiver()); 2422 Map::cast(container).set_prototype(HeapObject::cast(target), 2423 UPDATE_WRITE_BARRIER); 2424 } else { 2425 UNREACHABLE(); 2426 } 2427 } 2428 deferred_references_->SetLength(0); 2429} 2430 2431} // namespace internal 2432} // namespace v8 2433