1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/snapshot.h"
6
7#include "platform/assert.h"
8#include "vm/bootstrap.h"
9#include "vm/class_finalizer.h"
10#include "vm/dart.h"
11#include "vm/exceptions.h"
12#include "vm/heap/heap.h"
13#include "vm/longjump.h"
14#include "vm/message.h"
15#include "vm/object.h"
16#include "vm/object_store.h"
17#include "vm/snapshot_ids.h"
18#include "vm/stub_code.h"
19#include "vm/symbols.h"
20#include "vm/timeline.h"
21#include "vm/type_testing_stubs.h"
22#include "vm/version.h"
23
24// We currently only expect the Dart mutator to read snapshots.
25#define ASSERT_NO_SAFEPOINT_SCOPE() \
26 isolate()->AssertCurrentThreadIsMutator(); \
27 ASSERT(thread()->no_safepoint_scope_depth() != 0)
28
29namespace dart {
30
31static const int kNumInitialReferences = 32;
32
33static bool IsSingletonClassId(intptr_t class_id) {
34 // Check if this is a singleton object class which is shared by all isolates.
35 return ((class_id >= kClassCid && class_id <= kUnwindErrorCid) ||
36 (class_id == kTypeArgumentsCid) ||
37 (class_id >= kNullCid && class_id <= kVoidCid));
38}
39
40static bool IsBootstrapedClassId(intptr_t class_id) {
41 // Check if this is a class which is created during bootstrapping.
42 return (class_id == kObjectCid ||
43 (class_id >= kInstanceCid && class_id <= kUserTagCid) ||
44 class_id == kArrayCid || class_id == kImmutableArrayCid ||
45 IsStringClassId(class_id) || IsTypedDataClassId(class_id) ||
46 IsExternalTypedDataClassId(class_id) ||
47 IsTypedDataViewClassId(class_id) || class_id == kNullCid ||
48 class_id == kNeverCid || class_id == kTransferableTypedDataCid);
49}
50
51static bool IsObjectStoreTypeId(intptr_t index) {
52 // Check if this is a type which is stored in the object store.
53 static_assert(kFirstTypeArgumentsSnapshotId == kLastTypeSnapshotId + 1,
54 "Type and type arguments snapshot ids should be adjacent");
55 return index >= kFirstTypeSnapshotId && index <= kLastTypeArgumentsSnapshotId;
56}
57
58static bool IsSplitClassId(intptr_t class_id) {
59 // Return whether this class is serialized in two steps: first a reference,
60 // with sufficient information to allocate a correctly sized object, and then
61 // later inline with complete contents.
62 return class_id >= kNumPredefinedCids || class_id == kArrayCid ||
63 class_id == kImmutableArrayCid || class_id == kObjectPoolCid ||
64 IsImplicitFieldClassId(class_id);
65}
66
67static intptr_t ClassIdFromObjectId(intptr_t object_id) {
68 ASSERT(object_id > kClassIdsOffset);
69 intptr_t class_id = (object_id - kClassIdsOffset);
70 return class_id;
71}
72
73static intptr_t ObjectIdFromClassId(intptr_t class_id) {
74 ASSERT((class_id > kIllegalCid) && (class_id < kNumPredefinedCids));
75 return (class_id + kClassIdsOffset);
76}
77
78static ObjectPtr GetType(ObjectStore* object_store, intptr_t index) {
79 switch (index) {
80 case kLegacyObjectType:
81 return object_store->legacy_object_type();
82 case kNullableObjectType:
83 return object_store->nullable_object_type();
84 case kNullType:
85 return object_store->null_type();
86 case kNeverType:
87 return object_store->never_type();
88 case kLegacyFunctionType:
89 return object_store->legacy_function_type();
90 case kLegacyNumberType:
91 return object_store->legacy_number_type();
92 case kLegacySmiType:
93 return object_store->legacy_smi_type();
94 case kLegacyMintType:
95 return object_store->legacy_mint_type();
96 case kLegacyDoubleType:
97 return object_store->legacy_double_type();
98 case kLegacyIntType:
99 return object_store->legacy_int_type();
100 case kLegacyBoolType:
101 return object_store->legacy_bool_type();
102 case kLegacyStringType:
103 return object_store->legacy_string_type();
104 case kLegacyArrayType:
105 return object_store->legacy_array_type();
106 case kLegacyIntTypeArguments:
107 return object_store->type_argument_legacy_int();
108 case kLegacyDoubleTypeArguments:
109 return object_store->type_argument_legacy_double();
110 case kLegacyStringTypeArguments:
111 return object_store->type_argument_legacy_string();
112 case kLegacyStringDynamicTypeArguments:
113 return object_store->type_argument_legacy_string_dynamic();
114 case kLegacyStringLegacyStringTypeArguments:
115 return object_store->type_argument_legacy_string_legacy_string();
116 case kNonNullableObjectType:
117 return object_store->non_nullable_object_type();
118 case kNonNullableFunctionType:
119 return object_store->non_nullable_function_type();
120 case kNonNullableNumberType:
121 return object_store->non_nullable_number_type();
122 case kNonNullableSmiType:
123 return object_store->non_nullable_smi_type();
124 case kNonNullableMintType:
125 return object_store->non_nullable_mint_type();
126 case kNonNullableDoubleType:
127 return object_store->non_nullable_double_type();
128 case kNonNullableIntType:
129 return object_store->non_nullable_int_type();
130 case kNonNullableBoolType:
131 return object_store->non_nullable_bool_type();
132 case kNonNullableStringType:
133 return object_store->non_nullable_string_type();
134 case kNonNullableArrayType:
135 return object_store->non_nullable_array_type();
136 case kNonNullableIntTypeArguments:
137 return object_store->type_argument_non_nullable_int();
138 case kNonNullableDoubleTypeArguments:
139 return object_store->type_argument_non_nullable_double();
140 case kNonNullableStringTypeArguments:
141 return object_store->type_argument_non_nullable_string();
142 case kNonNullableStringDynamicTypeArguments:
143 return object_store->type_argument_non_nullable_string_dynamic();
144 case kNonNullableStringNonNullableStringTypeArguments:
145 return object_store
146 ->type_argument_non_nullable_string_non_nullable_string();
147 default:
148 break;
149 }
150 UNREACHABLE();
151 return Type::null();
152}
153
154static intptr_t GetTypeIndex(ObjectStore* object_store,
155 const ObjectPtr raw_type) {
156 if (raw_type == object_store->legacy_object_type()) {
157 return kLegacyObjectType;
158 } else if (raw_type == object_store->null_type()) {
159 return kNullType;
160 } else if (raw_type == object_store->never_type()) {
161 return kNeverType;
162 } else if (raw_type == object_store->legacy_function_type()) {
163 return kLegacyFunctionType;
164 } else if (raw_type == object_store->legacy_number_type()) {
165 return kLegacyNumberType;
166 } else if (raw_type == object_store->legacy_smi_type()) {
167 return kLegacySmiType;
168 } else if (raw_type == object_store->legacy_mint_type()) {
169 return kLegacyMintType;
170 } else if (raw_type == object_store->legacy_double_type()) {
171 return kLegacyDoubleType;
172 } else if (raw_type == object_store->legacy_int_type()) {
173 return kLegacyIntType;
174 } else if (raw_type == object_store->legacy_bool_type()) {
175 return kLegacyBoolType;
176 } else if (raw_type == object_store->legacy_string_type()) {
177 return kLegacyStringType;
178 } else if (raw_type == object_store->legacy_array_type()) {
179 return kLegacyArrayType;
180 } else if (raw_type == object_store->type_argument_legacy_int()) {
181 return kLegacyIntTypeArguments;
182 } else if (raw_type == object_store->type_argument_legacy_double()) {
183 return kLegacyDoubleTypeArguments;
184 } else if (raw_type == object_store->type_argument_legacy_string()) {
185 return kLegacyStringTypeArguments;
186 } else if (raw_type == object_store->type_argument_legacy_string_dynamic()) {
187 return kLegacyStringDynamicTypeArguments;
188 } else if (raw_type ==
189 object_store->type_argument_legacy_string_legacy_string()) {
190 return kLegacyStringLegacyStringTypeArguments;
191 } else if (raw_type == object_store->non_nullable_object_type()) {
192 return kNonNullableObjectType;
193 } else if (raw_type == object_store->non_nullable_function_type()) {
194 return kNonNullableFunctionType;
195 } else if (raw_type == object_store->non_nullable_number_type()) {
196 return kNonNullableNumberType;
197 } else if (raw_type == object_store->non_nullable_smi_type()) {
198 return kNonNullableSmiType;
199 } else if (raw_type == object_store->non_nullable_mint_type()) {
200 return kNonNullableMintType;
201 } else if (raw_type == object_store->non_nullable_double_type()) {
202 return kNonNullableDoubleType;
203 } else if (raw_type == object_store->non_nullable_int_type()) {
204 return kNonNullableIntType;
205 } else if (raw_type == object_store->non_nullable_bool_type()) {
206 return kNonNullableBoolType;
207 } else if (raw_type == object_store->non_nullable_string_type()) {
208 return kNonNullableStringType;
209 } else if (raw_type == object_store->non_nullable_array_type()) {
210 return kNonNullableArrayType;
211 } else if (raw_type == object_store->type_argument_non_nullable_int()) {
212 return kNonNullableIntTypeArguments;
213 } else if (raw_type == object_store->type_argument_non_nullable_double()) {
214 return kNonNullableDoubleTypeArguments;
215 } else if (raw_type == object_store->type_argument_non_nullable_string()) {
216 return kNonNullableStringTypeArguments;
217 } else if (raw_type ==
218 object_store->type_argument_non_nullable_string_dynamic()) {
219 return kNonNullableStringDynamicTypeArguments;
220 } else if (raw_type ==
221 object_store
222 ->type_argument_non_nullable_string_non_nullable_string()) {
223 return kNonNullableStringNonNullableStringTypeArguments;
224 }
225 return kInvalidIndex;
226}
227
228const char* Snapshot::KindToCString(Kind kind) {
229 switch (kind) {
230 case kFull:
231 return "full";
232 case kFullJIT:
233 return "full-jit";
234 case kFullAOT:
235 return "full-aot";
236 case kMessage:
237 return "message";
238 case kNone:
239 return "none";
240 case kInvalid:
241 default:
242 return "invalid";
243 }
244}
245
246const Snapshot* Snapshot::SetupFromBuffer(const void* raw_memory) {
247 ASSERT(raw_memory != NULL);
248 const Snapshot* snapshot = reinterpret_cast<const Snapshot*>(raw_memory);
249 if (!snapshot->check_magic()) {
250 return NULL;
251 }
252 // If the raw length is negative or greater than what the local machine can
253 // handle, then signal an error.
254 int64_t length = snapshot->large_length();
255 if ((length < 0) || (length > kIntptrMax)) {
256 return NULL;
257 }
258 return snapshot;
259}
260
261SmiPtr BaseReader::ReadAsSmi() {
262 SmiPtr value = static_cast<SmiPtr>(Read<intptr_t>());
263 ASSERT((static_cast<uword>(value) & kSmiTagMask) == kSmiTag);
264 return value;
265}
266
267intptr_t BaseReader::ReadSmiValue() {
268 return Smi::Value(ReadAsSmi());
269}
270
271SnapshotReader::SnapshotReader(const uint8_t* buffer,
272 intptr_t size,
273 Snapshot::Kind kind,
274 ZoneGrowableArray<BackRefNode>* backward_refs,
275 Thread* thread)
276 : BaseReader(buffer, size),
277 kind_(kind),
278 thread_(thread),
279 zone_(thread->zone()),
280 heap_(isolate()->heap()),
281 old_space_(thread_->isolate()->heap()->old_space()),
282 cls_(Class::Handle(zone_)),
283 code_(Code::Handle(zone_)),
284 instance_(Instance::Handle(zone_)),
285 instructions_(Instructions::Handle(zone_)),
286 obj_(Object::Handle(zone_)),
287 pobj_(PassiveObject::Handle(zone_)),
288 array_(Array::Handle(zone_)),
289 field_(Field::Handle(zone_)),
290 str_(String::Handle(zone_)),
291 library_(Library::Handle(zone_)),
292 type_(AbstractType::Handle(zone_)),
293 type_arguments_(TypeArguments::Handle(zone_)),
294 tokens_(GrowableObjectArray::Handle(zone_)),
295 data_(ExternalTypedData::Handle(zone_)),
296 typed_data_base_(TypedDataBase::Handle(zone_)),
297 typed_data_(TypedData::Handle(zone_)),
298 typed_data_view_(TypedDataView::Handle(zone_)),
299 function_(Function::Handle(zone_)),
300 error_(UnhandledException::Handle(zone_)),
301 set_class_(Class::ZoneHandle(
302 zone_,
303 thread_->isolate()->object_store()->linked_hash_set_class())),
304 max_vm_isolate_object_id_(
305 (Snapshot::IsFull(kind))
306 ? Object::vm_isolate_snapshot_object_table().Length()
307 : 0),
308 backward_references_(backward_refs),
309 types_to_postprocess_(GrowableObjectArray::Handle(zone_)),
310 objects_to_rehash_(GrowableObjectArray::Handle(zone_)) {}
311
312ObjectPtr SnapshotReader::ReadObject() {
313 // Setup for long jump in case there is an exception while reading.
314 LongJumpScope jump;
315 if (setjmp(*jump.Set()) == 0) {
316 PassiveObject& obj =
317 PassiveObject::Handle(zone(), ReadObjectImpl(kAsInlinedObject));
318 for (intptr_t i = 0; i < backward_references_->length(); i++) {
319 if (!(*backward_references_)[i].is_deserialized()) {
320 ReadObjectImpl(kAsInlinedObject);
321 (*backward_references_)[i].set_state(kIsDeserialized);
322 }
323 }
324 Object& result = Object::Handle(zone_);
325 if (backward_references_->length() > 0) {
326 result = (*backward_references_)[0].reference()->raw();
327 } else {
328 result = obj.raw();
329 }
330 RunDelayedTypePostprocessing();
331 const Object& ok = Object::Handle(zone_, RunDelayedRehashingOfMaps());
332 objects_to_rehash_ = GrowableObjectArray::null();
333 if (!ok.IsNull()) {
334 return ok.raw();
335 }
336 return result.raw();
337 } else {
338 // An error occurred while reading, return the error object.
339 return Thread::Current()->StealStickyError();
340 }
341}
342
343void SnapshotReader::EnqueueTypePostprocessing(const AbstractType& type) {
344 if (types_to_postprocess_.IsNull()) {
345 types_to_postprocess_ = GrowableObjectArray::New();
346 }
347 types_to_postprocess_.Add(type);
348}
349
350void SnapshotReader::RunDelayedTypePostprocessing() {
351 if (types_to_postprocess_.IsNull()) {
352 return;
353 }
354
355 AbstractType& type = AbstractType::Handle();
356 Code& code = Code::Handle();
357 for (intptr_t i = 0; i < types_to_postprocess_.Length(); ++i) {
358 type ^= types_to_postprocess_.At(i);
359 code = TypeTestingStubGenerator::DefaultCodeForType(type);
360 type.SetTypeTestingStub(code);
361 }
362}
363
364void SnapshotReader::EnqueueRehashingOfMap(const LinkedHashMap& map) {
365 if (objects_to_rehash_.IsNull()) {
366 objects_to_rehash_ = GrowableObjectArray::New();
367 }
368 objects_to_rehash_.Add(map);
369}
370
371ObjectPtr SnapshotReader::RunDelayedRehashingOfMaps() {
372 if (!objects_to_rehash_.IsNull()) {
373 const Library& collections_lib =
374 Library::Handle(zone_, Library::CollectionLibrary());
375 const Function& rehashing_function = Function::Handle(
376 zone_,
377 collections_lib.LookupFunctionAllowPrivate(Symbols::_rehashObjects()));
378 ASSERT(!rehashing_function.IsNull());
379
380 const Array& arguments = Array::Handle(zone_, Array::New(1));
381 arguments.SetAt(0, objects_to_rehash_);
382
383 return DartEntry::InvokeFunction(rehashing_function, arguments);
384 }
385 return Object::null();
386}
387
388ClassPtr SnapshotReader::ReadClassId(intptr_t object_id) {
389 ASSERT(!Snapshot::IsFull(kind_));
390 // Read the class header information and lookup the class.
391 intptr_t class_header = Read<int32_t>();
392 ASSERT((class_header & kSmiTagMask) != kSmiTag);
393 ASSERT(!IsVMIsolateObject(class_header) ||
394 !IsSingletonClassId(GetVMIsolateObjectId(class_header)));
395 ASSERT((SerializedHeaderTag::decode(class_header) != kObjectId) ||
396 !IsBootstrapedClassId(SerializedHeaderData::decode(class_header)));
397 Class& cls = Class::ZoneHandle(zone(), Class::null());
398 AddBackRef(object_id, &cls, kIsDeserialized);
399 // Read the library/class information and lookup the class.
400 str_ ^= ReadObjectImpl(class_header, kAsInlinedObject);
401 library_ = Library::LookupLibrary(thread(), str_);
402 if (library_.IsNull() || !library_.Loaded()) {
403 SetReadException(
404 "Invalid object found in message: library is not found or loaded.");
405 }
406 str_ ^= ReadObjectImpl(kAsInlinedObject);
407 if (str_.raw() == Symbols::TopLevel().raw()) {
408 cls = library_.toplevel_class();
409 } else {
410 str_ = String::New(String::ScrubName(str_));
411 cls = library_.LookupClassAllowPrivate(str_);
412 }
413 if (cls.IsNull()) {
414 SetReadException("Invalid object found in message: class not found");
415 }
416 cls.EnsureIsFinalized(thread());
417 return cls.raw();
418}
419
420ObjectPtr SnapshotReader::ReadStaticImplicitClosure(intptr_t object_id,
421 intptr_t class_header) {
422 ASSERT(!Snapshot::IsFull(kind_));
423
424 // First create a function object and associate it with the specified
425 // 'object_id'.
426 Function& func = Function::Handle(zone(), Function::null());
427 Instance& obj = Instance::ZoneHandle(zone(), Instance::null());
428 AddBackRef(object_id, &obj, kIsDeserialized);
429
430 // Read the library/class/function information and lookup the function.
431 // Note: WriteStaticImplicitClosure is *not* scrubbing the names before
432 // writing them into the snapshot, because scrubbing requires allocation.
433 // This means that names we read here might be mangled with private
434 // keys. These keys need to be scrubbed before performing lookups
435 // otherwise lookups might fail.
436 str_ ^= ReadObjectImpl(kAsInlinedObject);
437 library_ = Library::LookupLibrary(thread(), str_);
438 if (library_.IsNull() || !library_.Loaded()) {
439 SetReadException("Invalid Library object found in message.");
440 }
441 str_ ^= ReadObjectImpl(kAsInlinedObject);
442 if (str_.Equals(Symbols::TopLevel())) {
443 str_ ^= ReadObjectImpl(kAsInlinedObject);
444 str_ = String::New(String::ScrubName(str_));
445 func = library_.LookupFunctionAllowPrivate(str_);
446 } else {
447 str_ = String::New(String::ScrubName(str_));
448 cls_ = library_.LookupClassAllowPrivate(str_);
449 if (cls_.IsNull()) {
450 OS::PrintErr("Name of class not found %s\n", str_.ToCString());
451 SetReadException("Invalid Class object found in message.");
452 }
453 cls_.EnsureIsFinalized(thread());
454 str_ ^= ReadObjectImpl(kAsInlinedObject);
455 str_ = String::New(String::ScrubName(str_));
456 func = cls_.LookupFunctionAllowPrivate(str_);
457 }
458 if (func.IsNull()) {
459 SetReadException("Invalid function object found in message.");
460 }
461 func = func.ImplicitClosureFunction();
462 ASSERT(!func.IsNull());
463
464 // Return the associated implicit static closure.
465 obj = func.ImplicitStaticClosure();
466 return obj.raw();
467}
468
469intptr_t SnapshotReader::NextAvailableObjectId() const {
470 return backward_references_->length() + kMaxPredefinedObjectIds +
471 max_vm_isolate_object_id_;
472}
473
474void SnapshotReader::SetReadException(const char* msg) {
475 const String& error_str = String::Handle(zone(), String::New(msg));
476 const Array& args = Array::Handle(zone(), Array::New(1));
477 args.SetAt(0, error_str);
478 Object& result = Object::Handle(zone());
479 const Library& library = Library::Handle(zone(), Library::CoreLibrary());
480 result = DartLibraryCalls::InstanceCreate(library, Symbols::ArgumentError(),
481 Symbols::Dot(), args);
482 const StackTrace& stacktrace = StackTrace::Handle(zone());
483 const UnhandledException& error = UnhandledException::Handle(
484 zone(), UnhandledException::New(Instance::Cast(result), stacktrace));
485 thread()->long_jump_base()->Jump(1, error);
486}
487
488ObjectPtr SnapshotReader::VmIsolateSnapshotObject(intptr_t index) const {
489 return Object::vm_isolate_snapshot_object_table().At(index);
490}
491
492bool SnapshotReader::is_vm_isolate() const {
493 return isolate() == Dart::vm_isolate();
494}
495
496ObjectPtr SnapshotReader::ReadObjectImpl(bool as_reference) {
497 int64_t header_value = Read<int64_t>();
498 if ((header_value & kSmiTagMask) == kSmiTag) {
499 return NewInteger(header_value);
500 }
501 ASSERT((header_value <= kIntptrMax) && (header_value >= kIntptrMin));
502 return ReadObjectImpl(static_cast<intptr_t>(header_value), as_reference);
503}
504
505ObjectPtr SnapshotReader::ReadObjectImpl(intptr_t header_value,
506 bool as_reference) {
507 if (IsVMIsolateObject(header_value)) {
508 return ReadVMIsolateObject(header_value);
509 }
510 if (SerializedHeaderTag::decode(header_value) == kObjectId) {
511 return ReadIndexedObject(SerializedHeaderData::decode(header_value));
512 }
513 ASSERT(SerializedHeaderTag::decode(header_value) == kInlined);
514 intptr_t object_id = SerializedHeaderData::decode(header_value);
515 if (object_id == kOmittedObjectId) {
516 object_id = NextAvailableObjectId();
517 }
518
519 // Read the class header information.
520 intptr_t class_header = Read<int32_t>();
521 intptr_t tags = ReadTags();
522 bool read_as_reference = as_reference && !ObjectLayout::IsCanonical(tags);
523 intptr_t header_id = SerializedHeaderData::decode(class_header);
524 if (header_id == kInstanceObjectId) {
525 return ReadInstance(object_id, tags, read_as_reference);
526 } else if (header_id == kStaticImplicitClosureObjectId) {
527 // We skip the tags that have been written as the implicit static
528 // closure is going to be created in this isolate or the canonical
529 // version already created in the isolate will be used.
530 return ReadStaticImplicitClosure(object_id, class_header);
531 }
532 ASSERT((class_header & kSmiTagMask) != kSmiTag);
533
534 intptr_t class_id = LookupInternalClass(class_header);
535 switch (class_id) {
536#define SNAPSHOT_READ(clazz) \
537 case clazz::kClassId: { \
538 pobj_ = clazz::ReadFrom(this, object_id, tags, kind_, read_as_reference); \
539 break; \
540 }
541 CLASS_LIST_NO_OBJECT(SNAPSHOT_READ)
542#undef SNAPSHOT_READ
543#define SNAPSHOT_READ(clazz) case kTypedData##clazz##Cid:
544
545 CLASS_LIST_TYPED_DATA(SNAPSHOT_READ) {
546 tags = ObjectLayout::ClassIdTag::update(class_id, tags);
547 pobj_ =
548 TypedData::ReadFrom(this, object_id, tags, kind_, read_as_reference);
549 break;
550 }
551#undef SNAPSHOT_READ
552#define SNAPSHOT_READ(clazz) case kExternalTypedData##clazz##Cid:
553
554 CLASS_LIST_TYPED_DATA(SNAPSHOT_READ) {
555 tags = ObjectLayout::ClassIdTag::update(class_id, tags);
556 pobj_ = ExternalTypedData::ReadFrom(this, object_id, tags, kind_, true);
557 break;
558 }
559#undef SNAPSHOT_READ
560#define SNAPSHOT_READ(clazz) case kTypedData##clazz##ViewCid:
561
562 case kByteDataViewCid:
563 CLASS_LIST_TYPED_DATA(SNAPSHOT_READ) {
564 tags = ObjectLayout::ClassIdTag::update(class_id, tags);
565 pobj_ = TypedDataView::ReadFrom(this, object_id, tags, kind_, true);
566 break;
567 }
568#undef SNAPSHOT_READ
569#define SNAPSHOT_READ(clazz) case kFfi##clazz##Cid:
570
571 CLASS_LIST_FFI(SNAPSHOT_READ) { UNREACHABLE(); }
572#undef SNAPSHOT_READ
573 default:
574 UNREACHABLE();
575 break;
576 }
577 return pobj_.raw();
578}
579
580void SnapshotReader::EnqueueRehashingOfSet(const Object& set) {
581 if (objects_to_rehash_.IsNull()) {
582 objects_to_rehash_ = GrowableObjectArray::New();
583 }
584 objects_to_rehash_.Add(set);
585}
586
587ObjectPtr SnapshotReader::ReadInstance(intptr_t object_id,
588 intptr_t tags,
589 bool as_reference) {
590 // Object is regular dart instance.
591 intptr_t instance_size = 0;
592 Instance* result = NULL;
593 DeserializeState state;
594 if (!as_reference) {
595 result = reinterpret_cast<Instance*>(GetBackRef(object_id));
596 state = kIsDeserialized;
597 } else {
598 state = kIsNotDeserialized;
599 }
600 if (result == NULL) {
601 result = &(Instance::ZoneHandle(zone(), Instance::null()));
602 AddBackRef(object_id, result, state);
603 cls_ ^= ReadObjectImpl(kAsInlinedObject);
604 ASSERT(!cls_.IsNull());
605 // Closure instances are handled by Closure::ReadFrom().
606 ASSERT(!cls_.IsClosureClass());
607 instance_size = cls_.host_instance_size();
608 ASSERT(instance_size > 0);
609 // Allocate the instance and read in all the fields for the object.
610 *result ^= Object::Allocate(cls_.id(), instance_size, Heap::kNew);
611 } else {
612 cls_ ^= ReadObjectImpl(kAsInlinedObject);
613 ASSERT(!cls_.IsNull());
614 instance_size = cls_.host_instance_size();
615 }
616 if (cls_.id() == set_class_.id()) {
617 EnqueueRehashingOfSet(*result);
618 }
619 if (!as_reference) {
620 // Read all the individual fields for inlined objects.
621 intptr_t next_field_offset = cls_.host_next_field_offset();
622
623 intptr_t type_argument_field_offset =
624 cls_.host_type_arguments_field_offset();
625 ASSERT(next_field_offset > 0);
626 // Instance::NextFieldOffset() returns the offset of the first field in
627 // a Dart object.
628 bool read_as_reference = ObjectLayout::IsCanonical(tags) ? false : true;
629 intptr_t offset = Instance::NextFieldOffset();
630 intptr_t result_cid = result->GetClassId();
631
632 const auto unboxed_fields =
633 isolate()->group()->shared_class_table()->GetUnboxedFieldsMapAt(
634 result_cid);
635
636 while (offset < next_field_offset) {
637 if (unboxed_fields.Get(offset / kWordSize)) {
638 uword* p = reinterpret_cast<uword*>(result->raw_value() -
639 kHeapObjectTag + offset);
640 // Reads 32 bits of the unboxed value at a time
641 *p = ReadWordWith32BitReads();
642 } else {
643 pobj_ = ReadObjectImpl(read_as_reference);
644 result->SetFieldAtOffset(offset, pobj_);
645 if ((offset != type_argument_field_offset) &&
646 (kind_ == Snapshot::kMessage) && isolate()->use_field_guards() &&
647 (pobj_.raw() != Object::sentinel().raw())) {
648 // TODO(fschneider): Consider hoisting these lookups out of the loop.
649 // This would involve creating a handle, since cls_ can't be reused
650 // across the call to ReadObjectImpl.
651 cls_ = isolate()->class_table()->At(result_cid);
652 array_ = cls_.OffsetToFieldMap();
653 field_ ^= array_.At(offset >> kWordSizeLog2);
654 ASSERT(!field_.IsNull());
655 ASSERT(field_.HostOffset() == offset);
656 obj_ = pobj_.raw();
657 field_.RecordStore(obj_);
658 }
659 // TODO(fschneider): Verify the guarded cid and length for other kinds
660 // of snapshot (kFull, kScript) with asserts.
661 }
662 offset += kWordSize;
663 }
664 if (ObjectLayout::IsCanonical(tags)) {
665 const char* error_str = NULL;
666 *result = result->CheckAndCanonicalize(thread(), &error_str);
667 if (error_str != NULL) {
668 FATAL1("Failed to canonicalize %s\n", error_str);
669 }
670 ASSERT(!result->IsNull());
671 }
672 }
673 return result->raw();
674}
675
676void SnapshotReader::AddBackRef(intptr_t id,
677 Object* obj,
678 DeserializeState state) {
679 intptr_t index = (id - kMaxPredefinedObjectIds);
680 ASSERT(index >= max_vm_isolate_object_id_);
681 index -= max_vm_isolate_object_id_;
682 ASSERT(index == backward_references_->length());
683 BackRefNode node(obj, state);
684 backward_references_->Add(node);
685}
686
687Object* SnapshotReader::GetBackRef(intptr_t id) {
688 ASSERT(id >= kMaxPredefinedObjectIds);
689 intptr_t index = (id - kMaxPredefinedObjectIds);
690 ASSERT(index >= max_vm_isolate_object_id_);
691 index -= max_vm_isolate_object_id_;
692 if (index < backward_references_->length()) {
693 return (*backward_references_)[index].reference();
694 }
695 return NULL;
696}
697
698ApiErrorPtr SnapshotReader::VerifyVersionAndFeatures(Isolate* isolate) {
699 // If the version string doesn't match, return an error.
700 // Note: New things are allocated only if we're going to return an error.
701
702 const char* expected_version = Version::SnapshotString();
703 ASSERT(expected_version != NULL);
704 const intptr_t version_len = strlen(expected_version);
705 if (PendingBytes() < version_len) {
706 const intptr_t kMessageBufferSize = 128;
707 char message_buffer[kMessageBufferSize];
708 Utils::SNPrint(message_buffer, kMessageBufferSize,
709 "No full snapshot version found, expected '%s'",
710 expected_version);
711 // This can also fail while bringing up the VM isolate, so make sure to
712 // allocate the error message in old space.
713 const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
714 return ApiError::New(msg, Heap::kOld);
715 }
716
717 const char* version = reinterpret_cast<const char*>(CurrentBufferAddress());
718 ASSERT(version != NULL);
719 if (strncmp(version, expected_version, version_len) != 0) {
720 const intptr_t kMessageBufferSize = 256;
721 char message_buffer[kMessageBufferSize];
722 char* actual_version = Utils::StrNDup(version, version_len);
723 Utils::SNPrint(message_buffer, kMessageBufferSize,
724 "Wrong %s snapshot version, expected '%s' found '%s'",
725 (Snapshot::IsFull(kind_)) ? "full" : "script",
726 expected_version, actual_version);
727 free(actual_version);
728 // This can also fail while bringing up the VM isolate, so make sure to
729 // allocate the error message in old space.
730 const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
731 return ApiError::New(msg, Heap::kOld);
732 }
733 Advance(version_len);
734
735 const char* expected_features = Dart::FeaturesString(isolate, false, kind_);
736 ASSERT(expected_features != NULL);
737 const intptr_t expected_len = strlen(expected_features);
738
739 const char* features = reinterpret_cast<const char*>(CurrentBufferAddress());
740 ASSERT(features != NULL);
741 intptr_t buffer_len = Utils::StrNLen(features, PendingBytes());
742 if ((buffer_len != expected_len) ||
743 (strncmp(features, expected_features, expected_len) != 0)) {
744 const intptr_t kMessageBufferSize = 256;
745 char message_buffer[kMessageBufferSize];
746 char* actual_features =
747 Utils::StrNDup(features, buffer_len < 128 ? buffer_len : 128);
748 Utils::SNPrint(message_buffer, kMessageBufferSize,
749 "Snapshot not compatible with the current VM configuration: "
750 "the snapshot requires '%s' but the VM has '%s'",
751 actual_features, expected_features);
752 free(const_cast<char*>(expected_features));
753 free(actual_features);
754 // This can also fail while bringing up the VM isolate, so make sure to
755 // allocate the error message in old space.
756 const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
757 return ApiError::New(msg, Heap::kOld);
758 }
759 free(const_cast<char*>(expected_features));
760 Advance(expected_len + 1);
761 return ApiError::null();
762}
763
764ObjectPtr SnapshotReader::NewInteger(int64_t value) {
765 ASSERT((value & kSmiTagMask) == kSmiTag);
766 value = value >> kSmiTagShift;
767 if (Smi::IsValid(value)) {
768 return Smi::New(static_cast<intptr_t>(value));
769 }
770 return Mint::NewCanonical(value);
771}
772
773intptr_t SnapshotReader::LookupInternalClass(intptr_t class_header) {
774 // If the header is an object Id, lookup singleton VM classes or classes
775 // stored in the object store.
776 if (IsVMIsolateObject(class_header)) {
777 intptr_t class_id = GetVMIsolateObjectId(class_header);
778 ASSERT(IsSingletonClassId(class_id));
779 return class_id;
780 }
781 ASSERT(SerializedHeaderTag::decode(class_header) == kObjectId);
782 intptr_t class_id = SerializedHeaderData::decode(class_header);
783 ASSERT(IsBootstrapedClassId(class_id) || IsSingletonClassId(class_id));
784 return class_id;
785}
786
787#define READ_VM_SINGLETON_OBJ(id, obj) \
788 if (object_id == id) { \
789 return obj; \
790 }
791
792ObjectPtr SnapshotReader::ReadVMIsolateObject(intptr_t header_value) {
793 intptr_t object_id = GetVMIsolateObjectId(header_value);
794
795 // First check if it is one of the singleton objects.
796 READ_VM_SINGLETON_OBJ(kNullObject, Object::null());
797 READ_VM_SINGLETON_OBJ(kSentinelObject, Object::sentinel().raw());
798 READ_VM_SINGLETON_OBJ(kTransitionSentinelObject,
799 Object::transition_sentinel().raw());
800 READ_VM_SINGLETON_OBJ(kEmptyArrayObject, Object::empty_array().raw());
801 READ_VM_SINGLETON_OBJ(kZeroArrayObject, Object::zero_array().raw());
802 READ_VM_SINGLETON_OBJ(kDynamicType, Object::dynamic_type().raw());
803 READ_VM_SINGLETON_OBJ(kVoidType, Object::void_type().raw());
804 READ_VM_SINGLETON_OBJ(kEmptyTypeArguments,
805 Object::empty_type_arguments().raw());
806 READ_VM_SINGLETON_OBJ(kTrueValue, Bool::True().raw());
807 READ_VM_SINGLETON_OBJ(kFalseValue, Bool::False().raw());
808 READ_VM_SINGLETON_OBJ(kExtractorParameterTypes,
809 Object::extractor_parameter_types().raw());
810 READ_VM_SINGLETON_OBJ(kExtractorParameterNames,
811 Object::extractor_parameter_names().raw());
812 READ_VM_SINGLETON_OBJ(kEmptyContextScopeObject,
813 Object::empty_context_scope().raw());
814 READ_VM_SINGLETON_OBJ(kEmptyObjectPool, Object::empty_object_pool().raw());
815 READ_VM_SINGLETON_OBJ(kEmptyDescriptors, Object::empty_descriptors().raw());
816 READ_VM_SINGLETON_OBJ(kEmptyVarDescriptors,
817 Object::empty_var_descriptors().raw());
818 READ_VM_SINGLETON_OBJ(kEmptyExceptionHandlers,
819 Object::empty_exception_handlers().raw());
820
821 // Check if it is a double.
822 if (object_id == kDoubleObject) {
823 ASSERT(kind_ == Snapshot::kMessage);
824 return Double::New(ReadDouble());
825 }
826
827 // Check it is a singleton class object.
828 intptr_t class_id = ClassIdFromObjectId(object_id);
829 if (IsSingletonClassId(class_id)) {
830 return isolate()->class_table()->At(class_id); // get singleton class.
831 }
832
833 // Check if it is a singleton Argument descriptor object.
834 for (intptr_t i = 0; i < ArgumentsDescriptor::kCachedDescriptorCount; i++) {
835 if (object_id == (kCachedArgumentsDescriptor0 + i)) {
836 return ArgumentsDescriptor::cached_args_descriptors_[i];
837 }
838 }
839
840 // Check if it is a singleton ICData array object.
841 for (intptr_t i = 0; i < ICData::kCachedICDataArrayCount; i++) {
842 if (object_id == (kCachedICDataArray0 + i)) {
843 return ICData::cached_icdata_arrays_[i];
844 }
845 }
846
847 ASSERT(Symbols::IsPredefinedSymbolId(object_id));
848 return Symbols::GetPredefinedSymbol(object_id); // return VM symbol.
849}
850
851ObjectPtr SnapshotReader::ReadIndexedObject(intptr_t object_id) {
852 intptr_t class_id = ClassIdFromObjectId(object_id);
853 if (IsBootstrapedClassId(class_id)) {
854 return isolate()->class_table()->At(class_id); // get singleton class.
855 }
856 if (IsObjectStoreTypeId(object_id)) {
857 return GetType(object_store(), object_id); // return type obj.
858 }
859 ASSERT(object_id >= kMaxPredefinedObjectIds);
860 intptr_t index = (object_id - kMaxPredefinedObjectIds);
861 if (index < max_vm_isolate_object_id_) {
862 return VmIsolateSnapshotObject(index);
863 }
864 return GetBackRef(object_id)->raw();
865}
866
867void SnapshotReader::ArrayReadFrom(intptr_t object_id,
868 const Array& result,
869 intptr_t len,
870 intptr_t tags) {
871 // Setup the object fields.
872 *TypeArgumentsHandle() ^= ReadObjectImpl(kAsInlinedObject);
873 result.SetTypeArguments(*TypeArgumentsHandle());
874
875 bool as_reference = ObjectLayout::IsCanonical(tags) ? false : true;
876 for (intptr_t i = 0; i < len; i++) {
877 *PassiveObjectHandle() = ReadObjectImpl(as_reference);
878 result.SetAt(i, *PassiveObjectHandle());
879 }
880}
881
882MessageSnapshotReader::MessageSnapshotReader(Message* message, Thread* thread)
883 : SnapshotReader(message->snapshot(),
884 message->snapshot_length(),
885 Snapshot::kMessage,
886 new ZoneGrowableArray<BackRefNode>(kNumInitialReferences),
887 thread),
888 finalizable_data_(message->finalizable_data()) {}
889
890MessageSnapshotReader::~MessageSnapshotReader() {
891 ResetBackwardReferenceTable();
892}
893
894SnapshotWriter::SnapshotWriter(Thread* thread,
895 Snapshot::Kind kind,
896 ReAlloc alloc,
897 DeAlloc dealloc,
898 intptr_t initial_size,
899 ForwardList* forward_list,
900 bool can_send_any_object)
901 : BaseWriter(alloc, dealloc, initial_size),
902 thread_(thread),
903 kind_(kind),
904 object_store_(isolate()->object_store()),
905 class_table_(isolate()->class_table()),
906 forward_list_(forward_list),
907 exception_type_(Exceptions::kNone),
908 exception_msg_(NULL),
909 can_send_any_object_(can_send_any_object) {
910 ASSERT(forward_list_ != NULL);
911}
912
913void SnapshotWriter::WriteObject(ObjectPtr rawobj) {
914 WriteObjectImpl(rawobj, kAsInlinedObject);
915 WriteForwardedObjects();
916}
917
918uint32_t SnapshotWriter::GetObjectTags(ObjectPtr raw) {
919 return raw->ptr()->tags_;
920}
921
922uint32_t SnapshotWriter::GetObjectTags(ObjectLayout* raw) {
923 return raw->tags_;
924}
925
926uword SnapshotWriter::GetObjectTagsAndHash(ObjectPtr raw) {
927 uword result = raw->ptr()->tags_;
928#if defined(HASH_IN_OBJECT_HEADER)
929 result |= static_cast<uword>(raw->ptr()->hash_) << 32;
930#endif
931 return result;
932}
933
934#define VM_OBJECT_CLASS_LIST(V) \
935 V(OneByteString) \
936 V(TwoByteString) \
937 V(Mint) \
938 V(Double) \
939 V(ImmutableArray)
940
941#define VM_OBJECT_WRITE(clazz) \
942 case clazz::kClassId: { \
943 object_id = forward_list_->AddObject(zone(), rawobj, kIsSerialized); \
944 clazz##Ptr raw_obj = static_cast<clazz##Ptr>(rawobj); \
945 raw_obj->ptr()->WriteTo(this, object_id, kind(), false); \
946 return true; \
947 }
948
949#define WRITE_VM_SINGLETON_OBJ(obj, id) \
950 if (rawobj == obj) { \
951 WriteVMIsolateObject(id); \
952 return true; \
953 }
954
955bool SnapshotWriter::HandleVMIsolateObject(ObjectPtr rawobj) {
956 // Check if it is one of the singleton VM objects.
957 WRITE_VM_SINGLETON_OBJ(Object::null(), kNullObject);
958 WRITE_VM_SINGLETON_OBJ(Object::sentinel().raw(), kSentinelObject);
959 WRITE_VM_SINGLETON_OBJ(Object::transition_sentinel().raw(),
960 kTransitionSentinelObject);
961 WRITE_VM_SINGLETON_OBJ(Object::empty_array().raw(), kEmptyArrayObject);
962 WRITE_VM_SINGLETON_OBJ(Object::zero_array().raw(), kZeroArrayObject);
963 WRITE_VM_SINGLETON_OBJ(Object::dynamic_type().raw(), kDynamicType);
964 WRITE_VM_SINGLETON_OBJ(Object::void_type().raw(), kVoidType);
965 WRITE_VM_SINGLETON_OBJ(Object::empty_type_arguments().raw(),
966 kEmptyTypeArguments);
967 WRITE_VM_SINGLETON_OBJ(Bool::True().raw(), kTrueValue);
968 WRITE_VM_SINGLETON_OBJ(Bool::False().raw(), kFalseValue);
969 WRITE_VM_SINGLETON_OBJ(Object::extractor_parameter_types().raw(),
970 kExtractorParameterTypes);
971 WRITE_VM_SINGLETON_OBJ(Object::extractor_parameter_names().raw(),
972 kExtractorParameterNames);
973 WRITE_VM_SINGLETON_OBJ(Object::empty_context_scope().raw(),
974 kEmptyContextScopeObject);
975 WRITE_VM_SINGLETON_OBJ(Object::empty_object_pool().raw(), kEmptyObjectPool);
976 WRITE_VM_SINGLETON_OBJ(Object::empty_descriptors().raw(), kEmptyDescriptors);
977 WRITE_VM_SINGLETON_OBJ(Object::empty_var_descriptors().raw(),
978 kEmptyVarDescriptors);
979 WRITE_VM_SINGLETON_OBJ(Object::empty_exception_handlers().raw(),
980 kEmptyExceptionHandlers);
981
982 // Check if it is a singleton class object which is shared by
983 // all isolates.
984 intptr_t id = rawobj->GetClassId();
985 if (id == kClassCid) {
986 ClassPtr raw_class = static_cast<ClassPtr>(rawobj);
987 intptr_t class_id = raw_class->ptr()->id_;
988 if (IsSingletonClassId(class_id)) {
989 intptr_t object_id = ObjectIdFromClassId(class_id);
990 WriteVMIsolateObject(object_id);
991 return true;
992 }
993 }
994
995 // Check if it is a singleton Argument descriptor object.
996 for (intptr_t i = 0; i < ArgumentsDescriptor::kCachedDescriptorCount; i++) {
997 if (rawobj == ArgumentsDescriptor::cached_args_descriptors_[i]) {
998 WriteVMIsolateObject(kCachedArgumentsDescriptor0 + i);
999 return true;
1000 }
1001 }
1002
1003 // Check if it is a singleton ICData array object.
1004 for (intptr_t i = 0; i < ICData::kCachedICDataArrayCount; i++) {
1005 if (rawobj == ICData::cached_icdata_arrays_[i]) {
1006 WriteVMIsolateObject(kCachedICDataArray0 + i);
1007 return true;
1008 }
1009 }
1010
1011 // In the case of script snapshots or for messages we do not use
1012 // the index into the vm isolate snapshot object table, instead we
1013 // explicitly write the object out.
1014 intptr_t object_id = forward_list_->FindObject(rawobj);
1015 if (object_id != -1) {
1016 WriteIndexedObject(object_id);
1017 return true;
1018 } else {
1019 // We do this check down here, because it's quite expensive.
1020 if (!rawobj->ptr()->InVMIsolateHeap()) {
1021 return false;
1022 }
1023
1024 switch (id) {
1025 VM_OBJECT_CLASS_LIST(VM_OBJECT_WRITE)
1026 case kTypedDataUint32ArrayCid: {
1027 object_id = forward_list_->AddObject(zone(), rawobj, kIsSerialized);
1028 TypedDataPtr raw_obj = static_cast<TypedDataPtr>(rawobj);
1029 raw_obj->ptr()->WriteTo(this, object_id, kind(), false);
1030 return true;
1031 }
1032 default:
1033 OS::PrintErr("class id = %" Pd "\n", id);
1034 break;
1035 }
1036 }
1037
1038 const Object& obj = Object::Handle(rawobj);
1039 FATAL1("Unexpected reference to object in VM isolate: %s\n", obj.ToCString());
1040 return false;
1041}
1042
1043#undef VM_OBJECT_WRITE
1044
1045ForwardList::ForwardList(Thread* thread, intptr_t first_object_id)
1046 : thread_(thread),
1047 first_object_id_(first_object_id),
1048 nodes_(),
1049 first_unprocessed_object_id_(first_object_id) {
1050 ASSERT(first_object_id > 0);
1051 isolate()->set_forward_table_new(new WeakTable());
1052 isolate()->set_forward_table_old(new WeakTable());
1053}
1054
1055ForwardList::~ForwardList() {
1056 isolate()->set_forward_table_new(nullptr);
1057 isolate()->set_forward_table_old(nullptr);
1058}
1059
1060intptr_t ForwardList::AddObject(Zone* zone,
1061 ObjectPtr raw,
1062 SerializeState state) {
1063 NoSafepointScope no_safepoint;
1064 intptr_t object_id = next_object_id();
1065 ASSERT(object_id > 0 && object_id <= kMaxObjectId);
1066 const Object& obj = Object::ZoneHandle(zone, raw);
1067 Node* node = new Node(&obj, state);
1068 ASSERT(node != NULL);
1069 nodes_.Add(node);
1070 ASSERT(object_id != 0);
1071 SetObjectId(raw, object_id);
1072 return object_id;
1073}
1074
1075intptr_t ForwardList::FindObject(ObjectPtr raw) {
1076 NoSafepointScope no_safepoint;
1077 intptr_t id = GetObjectId(raw);
1078 ASSERT(id == 0 || NodeForObjectId(id)->obj()->raw() == raw);
1079 return (id == 0) ? static_cast<intptr_t>(kInvalidIndex) : id;
1080}
1081
1082void ForwardList::SetObjectId(ObjectPtr object, intptr_t id) {
1083 if (object->IsNewObject()) {
1084 isolate()->forward_table_new()->SetValueExclusive(object, id);
1085 } else {
1086 isolate()->forward_table_old()->SetValueExclusive(object, id);
1087 }
1088}
1089
1090intptr_t ForwardList::GetObjectId(ObjectPtr object) {
1091 if (object->IsNewObject()) {
1092 return isolate()->forward_table_new()->GetValueExclusive(object);
1093 } else {
1094 return isolate()->forward_table_old()->GetValueExclusive(object);
1095 }
1096}
1097
1098bool SnapshotWriter::CheckAndWritePredefinedObject(ObjectPtr rawobj) {
1099 // Check if object can be written in one of the following ways:
1100 // - Smi: the Smi value is written as is (last bit is not tagged).
1101 // - VM internal class (from VM isolate): (index of class in vm isolate | 0x3)
1102 // - Object that has already been written: (negative id in stream | 0x3)
1103
1104 NoSafepointScope no_safepoint;
1105
1106 // First check if it is a Smi (i.e not a heap object).
1107 if (!rawobj->IsHeapObject()) {
1108 Write<int64_t>(static_cast<intptr_t>(rawobj));
1109 return true;
1110 }
1111
1112 intptr_t cid = rawobj->GetClassId();
1113
1114 if ((kind_ == Snapshot::kMessage) && (cid == kDoubleCid)) {
1115 WriteVMIsolateObject(kDoubleObject);
1116 DoublePtr rd = static_cast<DoublePtr>(rawobj);
1117 WriteDouble(rd->ptr()->value_);
1118 return true;
1119 }
1120
1121 // Check if object has already been serialized, in that case just write
1122 // the object id out.
1123 intptr_t object_id = forward_list_->FindObject(rawobj);
1124 if (object_id != kInvalidIndex) {
1125 WriteIndexedObject(object_id);
1126 return true;
1127 }
1128
1129 // Check if it is a code object in that case just write a Null object
1130 // as we do not want code objects in the snapshot.
1131 if ((cid == kCodeCid) || (cid == kBytecodeCid)) {
1132 WriteVMIsolateObject(kNullObject);
1133 return true;
1134 }
1135
1136 // Now check if it is an object from the VM isolate. These objects are shared
1137 // by all isolates.
1138 if (HandleVMIsolateObject(rawobj)) {
1139 return true;
1140 }
1141
1142 // Check if classes are not being serialized and it is preinitialized type
1143 // or a predefined internal VM class in the object store.
1144 // Check if it is an internal VM class which is in the object store.
1145 if (cid == kClassCid) {
1146 ClassPtr raw_class = static_cast<ClassPtr>(rawobj);
1147 intptr_t class_id = raw_class->ptr()->id_;
1148 if (IsBootstrapedClassId(class_id)) {
1149 intptr_t object_id = ObjectIdFromClassId(class_id);
1150 WriteIndexedObject(object_id);
1151 return true;
1152 }
1153 }
1154
1155 // Now check it is a preinitialized type object.
1156 intptr_t index = GetTypeIndex(object_store(), rawobj);
1157 if (index != kInvalidIndex) {
1158 WriteIndexedObject(index);
1159 return true;
1160 }
1161
1162 return false;
1163}
1164
1165void SnapshotWriter::WriteObjectImpl(ObjectPtr raw, bool as_reference) {
1166 // First check if object can be written as a simple predefined type.
1167 if (CheckAndWritePredefinedObject(raw)) {
1168 return;
1169 }
1170
1171 // When we know that we are dealing with leaf or shallow objects we write
1172 // these objects inline even when 'as_reference' is true.
1173 const bool write_as_reference = as_reference && !raw->ptr()->IsCanonical();
1174 uintptr_t tags = GetObjectTagsAndHash(raw);
1175
1176 // Add object to the forward ref list and mark it so that future references
1177 // to this object in the snapshot will use this object id. Mark the
1178 // serialization state so that we do the right thing when we go through
1179 // the forward list.
1180 intptr_t class_id = raw->GetClassId();
1181 intptr_t object_id;
1182 if (write_as_reference && IsSplitClassId(class_id)) {
1183 object_id = forward_list_->AddObject(zone(), raw, kIsNotSerialized);
1184 } else {
1185 object_id = forward_list_->AddObject(zone(), raw, kIsSerialized);
1186 }
1187 if (write_as_reference || !IsSplitClassId(class_id)) {
1188 object_id = kOmittedObjectId;
1189 }
1190 WriteMarkedObjectImpl(raw, tags, object_id, write_as_reference);
1191}
1192
1193void SnapshotWriter::WriteMarkedObjectImpl(ObjectPtr raw,
1194 intptr_t tags,
1195 intptr_t object_id,
1196 bool as_reference) {
1197 NoSafepointScope no_safepoint;
1198 ClassPtr cls = class_table_->At(ObjectLayout::ClassIdTag::decode(tags));
1199 intptr_t class_id = cls->ptr()->id_;
1200 ASSERT(class_id == ObjectLayout::ClassIdTag::decode(tags));
1201 if (class_id >= kNumPredefinedCids || IsImplicitFieldClassId(class_id)) {
1202 WriteInstance(raw, cls, tags, object_id, as_reference);
1203 return;
1204 }
1205 switch (class_id) {
1206#define SNAPSHOT_WRITE(clazz) \
1207 case clazz::kClassId: { \
1208 clazz##Ptr raw_obj = static_cast<clazz##Ptr>(raw); \
1209 raw_obj->ptr()->WriteTo(this, object_id, kind_, as_reference); \
1210 return; \
1211 }
1212
1213 CLASS_LIST_NO_OBJECT(SNAPSHOT_WRITE)
1214#undef SNAPSHOT_WRITE
1215#define SNAPSHOT_WRITE(clazz) case kTypedData##clazz##Cid:
1216
1217 CLASS_LIST_TYPED_DATA(SNAPSHOT_WRITE) {
1218 TypedDataPtr raw_obj = static_cast<TypedDataPtr>(raw);
1219 raw_obj->ptr()->WriteTo(this, object_id, kind_, as_reference);
1220 return;
1221 }
1222#undef SNAPSHOT_WRITE
1223#define SNAPSHOT_WRITE(clazz) case kExternalTypedData##clazz##Cid:
1224
1225 CLASS_LIST_TYPED_DATA(SNAPSHOT_WRITE) {
1226 ExternalTypedDataPtr raw_obj = static_cast<ExternalTypedDataPtr>(raw);
1227 raw_obj->ptr()->WriteTo(this, object_id, kind_, as_reference);
1228 return;
1229 }
1230#undef SNAPSHOT_WRITE
1231#define SNAPSHOT_WRITE(clazz) case kTypedData##clazz##ViewCid:
1232
1233 case kByteDataViewCid:
1234 CLASS_LIST_TYPED_DATA(SNAPSHOT_WRITE) {
1235 auto raw_obj = static_cast<TypedDataViewPtr>(raw);
1236 raw_obj->ptr()->WriteTo(this, object_id, kind_, as_reference);
1237 return;
1238 }
1239#undef SNAPSHOT_WRITE
1240
1241#define SNAPSHOT_WRITE(clazz) case kFfi##clazz##Cid:
1242
1243 CLASS_LIST_FFI(SNAPSHOT_WRITE) {
1244 SetWriteException(Exceptions::kArgument,
1245 "Native objects (from dart:ffi) such as Pointers and "
1246 "Structs cannot be passed between isolates.");
1247 UNREACHABLE();
1248 }
1249#undef SNAPSHOT_WRITE
1250 default:
1251 break;
1252 }
1253
1254 const Object& obj = Object::Handle(raw);
1255 FATAL1("Unexpected object: %s\n", obj.ToCString());
1256}
1257
1258class WriteInlinedObjectVisitor : public ObjectVisitor {
1259 public:
1260 explicit WriteInlinedObjectVisitor(SnapshotWriter* writer)
1261 : writer_(writer) {}
1262
1263 virtual void VisitObject(ObjectPtr obj) {
1264 intptr_t object_id = writer_->forward_list_->FindObject(obj);
1265 ASSERT(object_id != kInvalidIndex);
1266 intptr_t tags = MessageWriter::GetObjectTagsAndHash(ObjectPtr(obj));
1267 writer_->WriteMarkedObjectImpl(obj, tags, object_id, kAsInlinedObject);
1268 }
1269
1270 private:
1271 SnapshotWriter* writer_;
1272};
1273
1274void SnapshotWriter::WriteForwardedObjects() {
1275 WriteInlinedObjectVisitor visitor(this);
1276 forward_list_->SerializeAll(&visitor);
1277}
1278
1279void ForwardList::SerializeAll(ObjectVisitor* writer) {
1280// Write out all objects that were added to the forward list and have
1281// not been serialized yet. These would typically be fields of instance
1282// objects, arrays or immutable arrays (this is done in order to avoid
1283// deep recursive calls to WriteObjectImpl).
1284// NOTE: The forward list might grow as we process the list.
1285#ifdef DEBUG
1286 for (intptr_t i = first_object_id(); i < first_unprocessed_object_id_; ++i) {
1287 ASSERT(NodeForObjectId(i)->is_serialized());
1288 }
1289#endif // DEBUG
1290 for (intptr_t id = first_unprocessed_object_id_; id < next_object_id();
1291 ++id) {
1292 if (!NodeForObjectId(id)->is_serialized()) {
1293 // Write the object out in the stream.
1294 ObjectPtr raw = NodeForObjectId(id)->obj()->raw();
1295 writer->VisitObject(raw);
1296
1297 // Mark object as serialized.
1298 NodeForObjectId(id)->set_state(kIsSerialized);
1299 }
1300 }
1301 first_unprocessed_object_id_ = next_object_id();
1302}
1303
1304void SnapshotWriter::WriteClassId(ClassLayout* cls) {
1305 ASSERT(!Snapshot::IsFull(kind_));
1306 int class_id = cls->id_;
1307 ASSERT(!IsSingletonClassId(class_id) && !IsBootstrapedClassId(class_id));
1308
1309 // Write out the library url and class name.
1310 LibraryPtr library = cls->library_;
1311 ASSERT(library != Library::null());
1312 WriteObjectImpl(library->ptr()->url_, kAsInlinedObject);
1313 WriteObjectImpl(cls->name_, kAsInlinedObject);
1314}
1315
1316void SnapshotWriter::WriteStaticImplicitClosure(intptr_t object_id,
1317 FunctionPtr func,
1318 intptr_t tags) {
1319 // Write out the serialization header value for this object.
1320 WriteInlinedObjectHeader(object_id);
1321
1322 // Indicate this is a static implicit closure object.
1323 Write<int32_t>(SerializedHeaderData::encode(kStaticImplicitClosureObjectId));
1324
1325 // Write out the tags.
1326 WriteTags(tags);
1327
1328 // Write out the library url, class name and signature function name.
1329 ClassPtr cls = GetFunctionOwner(func);
1330 ASSERT(cls != Class::null());
1331 LibraryPtr library = cls->ptr()->library_;
1332 ASSERT(library != Library::null());
1333 WriteObjectImpl(library->ptr()->url_, kAsInlinedObject);
1334 WriteObjectImpl(cls->ptr()->name_, kAsInlinedObject);
1335 WriteObjectImpl(func->ptr()->name_, kAsInlinedObject);
1336}
1337
1338void SnapshotWriter::ArrayWriteTo(intptr_t object_id,
1339 intptr_t array_kind,
1340 intptr_t tags,
1341 SmiPtr length,
1342 TypeArgumentsPtr type_arguments,
1343 ObjectPtr data[],
1344 bool as_reference) {
1345 if (as_reference) {
1346 // Write out the serialization header value for this object.
1347 WriteInlinedObjectHeader(kOmittedObjectId);
1348
1349 // Write out the class information.
1350 WriteIndexedObject(array_kind);
1351 WriteTags(tags);
1352
1353 // Write out the length field.
1354 Write<ObjectPtr>(length);
1355 } else {
1356 intptr_t len = Smi::Value(length);
1357
1358 // Write out the serialization header value for this object.
1359 WriteInlinedObjectHeader(object_id);
1360
1361 // Write out the class and tags information.
1362 WriteIndexedObject(array_kind);
1363 WriteTags(tags);
1364
1365 // Write out the length field.
1366 Write<ObjectPtr>(length);
1367
1368 // Write out the type arguments.
1369 WriteObjectImpl(type_arguments, kAsInlinedObject);
1370
1371 // Write out the individual object ids.
1372 bool write_as_reference = ObjectLayout::IsCanonical(tags) ? false : true;
1373 for (intptr_t i = 0; i < len; i++) {
1374 WriteObjectImpl(data[i], write_as_reference);
1375 }
1376 }
1377}
1378
1379FunctionPtr SnapshotWriter::IsSerializableClosure(ClosurePtr closure) {
1380 // Extract the function object to check if this closure
1381 // can be sent in an isolate message.
1382 FunctionPtr func = closure->ptr()->function_;
1383 // We only allow closure of top level methods or static functions in a
1384 // class to be sent in isolate messages.
1385 if (can_send_any_object() &&
1386 Function::IsImplicitStaticClosureFunction(func)) {
1387 return func;
1388 }
1389 // Not a closure of a top level method or static function, throw an
1390 // exception as we do not allow these objects to be serialized.
1391 HANDLESCOPE(thread());
1392
1393 const Function& errorFunc = Function::Handle(zone(), func);
1394 ASSERT(!errorFunc.IsNull());
1395
1396 // All other closures are errors.
1397 char* chars = OS::SCreate(
1398 thread()->zone(),
1399 "Illegal argument in isolate message : (object is a closure - %s)",
1400 errorFunc.ToCString());
1401 SetWriteException(Exceptions::kArgument, chars);
1402 return Function::null();
1403}
1404
1405ClassPtr SnapshotWriter::GetFunctionOwner(FunctionPtr func) {
1406 ObjectPtr owner = func->ptr()->owner_;
1407 uint32_t tags = GetObjectTags(owner);
1408 intptr_t class_id = ObjectLayout::ClassIdTag::decode(tags);
1409 if (class_id == kClassCid) {
1410 return static_cast<ClassPtr>(owner);
1411 }
1412 ASSERT(class_id == kPatchClassCid);
1413 return static_cast<PatchClassPtr>(owner)->ptr()->patched_class_;
1414}
1415
1416void SnapshotWriter::CheckForNativeFields(ClassPtr cls) {
1417 if (cls->ptr()->num_native_fields_ != 0) {
1418 // We do not allow objects with native fields in an isolate message.
1419 HANDLESCOPE(thread());
1420 const Class& clazz = Class::Handle(zone(), cls);
1421 char* chars = OS::SCreate(thread()->zone(),
1422 "Illegal argument in isolate message"
1423 " : (object extends NativeWrapper - %s)",
1424 clazz.ToCString());
1425 SetWriteException(Exceptions::kArgument, chars);
1426 }
1427}
1428
1429void SnapshotWriter::SetWriteException(Exceptions::ExceptionType type,
1430 const char* msg) {
1431 set_exception_type(type);
1432 set_exception_msg(msg);
1433 // The more specific error is set up in SnapshotWriter::ThrowException().
1434 thread()->long_jump_base()->Jump(1, Object::snapshot_writer_error());
1435}
1436
1437void SnapshotWriter::WriteInstance(ObjectPtr raw,
1438 ClassPtr cls,
1439 intptr_t tags,
1440 intptr_t object_id,
1441 bool as_reference) {
1442 // Closure instances are handled by ClosureLayout::WriteTo().
1443 ASSERT(!Class::IsClosureClass(cls));
1444
1445 // Check if the instance has native fields and throw an exception if it does.
1446 CheckForNativeFields(cls);
1447
1448 // Object is regular dart instance.
1449 if (as_reference) {
1450 // Write out the serialization header value for this object.
1451 WriteInlinedObjectHeader(kOmittedObjectId);
1452
1453 // Indicate this is an instance object.
1454 Write<int32_t>(SerializedHeaderData::encode(kInstanceObjectId));
1455 WriteTags(tags);
1456
1457 // Write out the class information for this object.
1458 WriteObjectImpl(cls, kAsInlinedObject);
1459 } else {
1460 intptr_t next_field_offset = Class::host_next_field_offset_in_words(cls)
1461 << kWordSizeLog2;
1462 ASSERT(next_field_offset > 0);
1463
1464 // Write out the serialization header value for this object.
1465 WriteInlinedObjectHeader(object_id);
1466
1467 // Indicate this is an instance object.
1468 Write<int32_t>(SerializedHeaderData::encode(kInstanceObjectId));
1469
1470 // Write out the tags.
1471 WriteTags(tags);
1472
1473 // Write out the class information for this object.
1474 WriteObjectImpl(cls, kAsInlinedObject);
1475
1476 const auto unboxed_fields =
1477 isolate()->group()->shared_class_table()->GetUnboxedFieldsMapAt(
1478 cls->ptr()->id_);
1479
1480 // Write out all the fields for the object.
1481 // Instance::NextFieldOffset() returns the offset of the first field in
1482 // a Dart object.
1483 bool write_as_reference = ObjectLayout::IsCanonical(tags) ? false : true;
1484
1485 intptr_t offset = Instance::NextFieldOffset();
1486 while (offset < next_field_offset) {
1487 if (unboxed_fields.Get(offset / kWordSize)) {
1488 // Writes 32 bits of the unboxed value at a time
1489 const uword value = *reinterpret_cast<uword*>(
1490 reinterpret_cast<uword>(raw->ptr()) + offset);
1491 WriteWordWith32BitWrites(value);
1492 } else {
1493 ObjectPtr raw_obj = *reinterpret_cast<ObjectPtr*>(
1494 reinterpret_cast<uword>(raw->ptr()) + offset);
1495 WriteObjectImpl(raw_obj, write_as_reference);
1496 }
1497 offset += kWordSize;
1498 }
1499 }
1500 return;
1501}
1502
1503bool SnapshotWriter::AllowObjectsInDartLibrary(LibraryPtr library) {
1504 return (library == object_store()->collection_library() ||
1505 library == object_store()->core_library() ||
1506 library == object_store()->typed_data_library());
1507}
1508
1509intptr_t SnapshotWriter::FindVmSnapshotObject(ObjectPtr rawobj) {
1510 intptr_t length = Object::vm_isolate_snapshot_object_table().Length();
1511 for (intptr_t i = 0; i < length; i++) {
1512 if (Object::vm_isolate_snapshot_object_table().At(i) == rawobj) {
1513 return (i + kMaxPredefinedObjectIds);
1514 }
1515 }
1516 return kInvalidIndex;
1517}
1518
1519void SnapshotWriter::ThrowException(Exceptions::ExceptionType type,
1520 const char* msg) {
1521 {
1522 NoSafepointScope no_safepoint;
1523 ErrorPtr error = thread()->StealStickyError();
1524 ASSERT(error == Object::snapshot_writer_error().raw());
1525 }
1526
1527 if (msg != NULL) {
1528 const String& msg_obj = String::Handle(String::New(msg));
1529 const Array& args = Array::Handle(Array::New(1));
1530 args.SetAt(0, msg_obj);
1531 Exceptions::ThrowByType(type, args);
1532 } else {
1533 Exceptions::ThrowByType(type, Object::empty_array());
1534 }
1535 UNREACHABLE();
1536}
1537
1538void SnapshotWriter::WriteVersionAndFeatures() {
1539 const char* expected_version = Version::SnapshotString();
1540 ASSERT(expected_version != NULL);
1541 const intptr_t version_len = strlen(expected_version);
1542 WriteBytes(reinterpret_cast<const uint8_t*>(expected_version), version_len);
1543
1544 const char* expected_features =
1545 Dart::FeaturesString(Isolate::Current(), false, kind_);
1546 ASSERT(expected_features != NULL);
1547 const intptr_t features_len = strlen(expected_features);
1548 WriteBytes(reinterpret_cast<const uint8_t*>(expected_features),
1549 features_len + 1);
1550 free(const_cast<char*>(expected_features));
1551}
1552
1553void SnapshotWriterVisitor::VisitPointers(ObjectPtr* first, ObjectPtr* last) {
1554 ASSERT(Utils::IsAligned(first, sizeof(*first)));
1555 ASSERT(Utils::IsAligned(last, sizeof(*last)));
1556 for (ObjectPtr* current = first; current <= last; current++) {
1557 ObjectPtr raw_obj = *current;
1558 writer_->WriteObjectImpl(raw_obj, as_references_);
1559 }
1560}
1561
1562static uint8_t* malloc_allocator(uint8_t* ptr,
1563 intptr_t old_size,
1564 intptr_t new_size) {
1565 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
1566 return reinterpret_cast<uint8_t*>(new_ptr);
1567}
1568
1569static void malloc_deallocator(uint8_t* ptr) {
1570 free(reinterpret_cast<void*>(ptr));
1571}
1572
1573MessageWriter::MessageWriter(bool can_send_any_object)
1574 : SnapshotWriter(Thread::Current(),
1575 Snapshot::kMessage,
1576 malloc_allocator,
1577 malloc_deallocator,
1578 kInitialSize,
1579 &forward_list_,
1580 can_send_any_object),
1581 forward_list_(thread(), kMaxPredefinedObjectIds),
1582 finalizable_data_(new MessageFinalizableData()) {}
1583
1584MessageWriter::~MessageWriter() {
1585 delete finalizable_data_;
1586}
1587
1588std::unique_ptr<Message> MessageWriter::WriteMessage(
1589 const Object& obj,
1590 Dart_Port dest_port,
1591 Message::Priority priority) {
1592 ASSERT(kind() == Snapshot::kMessage);
1593 ASSERT(isolate() != NULL);
1594
1595 // Setup for long jump in case there is an exception while writing
1596 // the message.
1597 volatile bool has_exception = false;
1598 {
1599 LongJumpScope jump;
1600 if (setjmp(*jump.Set()) == 0) {
1601 NoSafepointScope no_safepoint;
1602 WriteObject(obj.raw());
1603 } else {
1604 FreeBuffer();
1605 has_exception = true;
1606 }
1607 }
1608 if (has_exception) {
1609 ThrowException(exception_type(), exception_msg());
1610 } else {
1611 finalizable_data_->SerializationSucceeded();
1612 }
1613
1614 MessageFinalizableData* finalizable_data = finalizable_data_;
1615 finalizable_data_ = NULL;
1616 return Message::New(dest_port, buffer(), BytesWritten(), finalizable_data,
1617 priority);
1618}
1619
1620} // namespace dart
1621