blob: 8a65fdb197dd35907205d6db37dcc0f21beb5dfe [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/snapshot.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
#include "vm/visitor.h"
namespace dart {
DECLARE_FLAG(int, optimization_counter_threshold);
#define NEW_OBJECT(type) \
((kind == Snapshot::kFull) ? reader->New##type() : type::New())
#define NEW_OBJECT_WITH_LEN(type, len) \
((kind == Snapshot::kFull) ? reader->New##type(len) : type::New(len))
#define NEW_OBJECT_WITH_LEN_SPACE(type, len, kind) \
((kind == Snapshot::kFull) ? \
reader->New##type(len) : type::New(len, HEAP_SPACE(kind)))
#define OFFSET_OF_FROM(obj) \
obj.raw()->from() - reinterpret_cast<RawObject**>(obj.raw()->ptr())
// TODO(18854): Need to assert No GC can happen here, even though
// allocations may happen.
#define READ_OBJECT_FIELDS(object, from, to, as_reference) \
intptr_t num_flds = (to) - (from); \
intptr_t from_offset = OFFSET_OF_FROM(object); \
for (intptr_t i = 0; i <= num_flds; i++) { \
(*reader->PassiveObjectHandle()) = \
reader->ReadObjectImpl(as_reference, object_id, (i + from_offset)); \
object.StorePointer(((from) + i), \
reader->PassiveObjectHandle()->raw()); \
}
RawClass* Class::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
Class& cls = Class::ZoneHandle(reader->zone(), Class::null());
bool is_in_fullsnapshot = reader->Read<bool>();
if ((kind == Snapshot::kFull) ||
(kind == Snapshot::kScript && !is_in_fullsnapshot)) {
// Read in the base information.
classid_t class_id = reader->ReadClassIDValue();
// Allocate class object of specified kind.
if (kind == Snapshot::kFull) {
cls = reader->NewClass(class_id);
} else {
if (class_id < kNumPredefinedCids) {
ASSERT((class_id >= kInstanceCid) && (class_id <= kMirrorReferenceCid));
cls = reader->isolate()->class_table()->At(class_id);
} else {
cls = New<Instance>(kIllegalCid);
}
}
reader->AddBackRef(object_id, &cls, kIsDeserialized);
// Set all non object fields.
if (!RawObject::IsInternalVMdefinedClassId(class_id)) {
// Instance size of a VM defined class is already set up.
cls.set_instance_size_in_words(reader->Read<int32_t>());
cls.set_next_field_offset_in_words(reader->Read<int32_t>());
}
cls.set_type_arguments_field_offset_in_words(reader->Read<int32_t>());
cls.set_num_type_arguments(reader->Read<int16_t>());
cls.set_num_own_type_arguments(reader->Read<int16_t>());
cls.set_num_native_fields(reader->Read<uint16_t>());
cls.set_token_pos(reader->Read<int32_t>());
cls.set_state_bits(reader->Read<uint16_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to(), kAsReference);
ASSERT(!cls.IsInFullSnapshot() || (kind == Snapshot::kFull));
} else {
cls ^= reader->ReadClassId(object_id);
ASSERT((kind == Snapshot::kMessage) || cls.IsInFullSnapshot());
}
return cls.raw();
}
void RawClass::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
bool is_in_fullsnapshot = Class::IsInFullSnapshot(this);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kClassCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the boolean is_in_fullsnapshot first as this will
// help the reader decide how the rest of the information needs
// to be interpreted.
writer->Write<bool>(is_in_fullsnapshot);
if ((kind == Snapshot::kFull) ||
(kind == Snapshot::kScript && !is_in_fullsnapshot)) {
// Write out all the non object pointer fields.
// NOTE: cpp_vtable_ is not written.
classid_t class_id = ptr()->id_;
writer->Write<classid_t>(class_id);
if (!RawObject::IsInternalVMdefinedClassId(class_id)) {
// We don't write the instance size of VM defined classes as they
// are already setup during initialization as part of pre populating
// the class table.
writer->Write<int32_t>(ptr()->instance_size_in_words_);
writer->Write<int32_t>(ptr()->next_field_offset_in_words_);
}
writer->Write<int32_t>(ptr()->type_arguments_field_offset_in_words_);
writer->Write<uint16_t>(ptr()->num_type_arguments_);
writer->Write<uint16_t>(ptr()->num_own_type_arguments_);
writer->Write<uint16_t>(ptr()->num_native_fields_);
writer->Write<int32_t>(ptr()->token_pos_);
writer->Write<uint16_t>(ptr()->state_bits_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
} else {
if (writer->can_send_any_object() ||
writer->AllowObjectsInDartLibrary(ptr()->library_)) {
writer->WriteClassId(this);
} else {
// We do not allow regular dart instances in isolate messages.
writer->SetWriteException(Exceptions::kArgument,
"Illegal argument in isolate message"
" : (object is a regular Dart Instance)");
}
}
}
RawUnresolvedClass* UnresolvedClass::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate unresolved class object.
UnresolvedClass& unresolved_class = UnresolvedClass::ZoneHandle(
reader->zone(), NEW_OBJECT(UnresolvedClass));
reader->AddBackRef(object_id, &unresolved_class, kIsDeserialized);
// Set all non object fields.
unresolved_class.set_token_pos(reader->Read<int32_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(unresolved_class,
unresolved_class.raw()->from(),
unresolved_class.raw()->to(),
kAsReference);
return unresolved_class.raw();
}
void RawUnresolvedClass::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kUnresolvedClassCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object pointer fields.
writer->Write<int32_t>(ptr()->token_pos_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawAbstractType* AbstractType::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE(); // AbstractType is an abstract class.
return NULL;
}
void RawAbstractType::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE(); // AbstractType is an abstract class.
}
RawType* Type::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Determine if the type class of this type is in the full snapshot.
bool typeclass_is_in_fullsnapshot = reader->Read<bool>();
// Allocate type object.
Type& type = Type::ZoneHandle(reader->zone(), NEW_OBJECT(Type));
bool is_canonical = RawObject::IsCanonical(tags);
bool defer_canonicalization = is_canonical &&
(kind != Snapshot::kFull && typeclass_is_in_fullsnapshot);
reader->AddBackRef(object_id, &type, kIsDeserialized, defer_canonicalization);
// Set all non object fields.
type.set_token_pos(reader->Read<int32_t>());
type.set_type_state(reader->Read<int8_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(type, type.raw()->from(), type.raw()->to(), kAsReference);
// Set the canonical bit.
if (!defer_canonicalization && RawObject::IsCanonical(tags)) {
type.SetCanonical();
}
return type.raw();
}
void RawType::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Only resolved and finalized types should be written to a snapshot.
ASSERT((ptr()->type_state_ == RawType::kFinalizedInstantiated) ||
(ptr()->type_state_ == RawType::kFinalizedUninstantiated));
ASSERT(ptr()->type_class_ != Object::null());
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kTypeCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out typeclass_is_in_fullsnapshot first as this will
// help the reader decide on how to canonicalize the type object.
intptr_t tags = writer->GetObjectTags(ptr()->type_class_);
bool typeclass_is_in_fullsnapshot =
(ClassIdTag::decode(tags) == kClassCid) &&
Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(ptr()->type_class_));
writer->Write<bool>(typeclass_is_in_fullsnapshot);
// Write out all the non object pointer fields.
writer->Write<int32_t>(ptr()->token_pos_);
writer->Write<int8_t>(ptr()->type_state_);
// Write out all the object pointer fields. Since we will be canonicalizing
// the type object when reading it back we should write out all the fields
// inline and not as references.
ASSERT(ptr()->type_class_ != Object::null());
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawTypeRef* TypeRef::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate type ref object.
TypeRef& type_ref = TypeRef::ZoneHandle(
reader->zone(), NEW_OBJECT(TypeRef));
reader->AddBackRef(object_id, &type_ref, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(type_ref,
type_ref.raw()->from(), type_ref.raw()->to(),
kAsReference);
return type_ref.raw();
}
void RawTypeRef::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kTypeRefCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawTypeParameter* TypeParameter::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate type parameter object.
TypeParameter& type_parameter = TypeParameter::ZoneHandle(
reader->zone(), NEW_OBJECT(TypeParameter));
reader->AddBackRef(object_id, &type_parameter, kIsDeserialized);
// Set all non object fields.
type_parameter.set_token_pos(reader->Read<int32_t>());
type_parameter.set_index(reader->Read<int16_t>());
type_parameter.set_type_state(reader->Read<int8_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(type_parameter,
type_parameter.raw()->from(), type_parameter.raw()->to(),
kAsReference);
return type_parameter.raw();
}
void RawTypeParameter::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Only finalized type parameters should be written to a snapshot.
ASSERT(ptr()->type_state_ == RawTypeParameter::kFinalizedUninstantiated);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kTypeParameterCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object pointer fields.
writer->Write<int32_t>(ptr()->token_pos_);
writer->Write<int16_t>(ptr()->index_);
writer->Write<int8_t>(ptr()->type_state_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawBoundedType* BoundedType::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate bounded type object.
BoundedType& bounded_type = BoundedType::ZoneHandle(
reader->zone(), NEW_OBJECT(BoundedType));
reader->AddBackRef(object_id, &bounded_type, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(bounded_type,
bounded_type.raw()->from(), bounded_type.raw()->to(),
kAsReference);
return bounded_type.raw();
}
void RawBoundedType::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kBoundedTypeCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawMixinAppType* MixinAppType::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE(); // MixinAppType objects do not survive finalization.
return MixinAppType::null();
}
void RawMixinAppType::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE(); // MixinAppType objects do not survive finalization.
}
RawTypeArguments* TypeArguments::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Read the length so that we can determine instance size to allocate.
intptr_t len = reader->ReadSmiValue();
TypeArguments& type_arguments = TypeArguments::ZoneHandle(
reader->zone(), NEW_OBJECT_WITH_LEN_SPACE(TypeArguments, len, kind));
bool is_canonical = RawObject::IsCanonical(tags);
bool defer_canonicalization = is_canonical && (kind != Snapshot::kFull);
reader->AddBackRef(object_id,
&type_arguments,
kIsDeserialized,
defer_canonicalization);
// Set the instantiations field, which is only read from a full snapshot.
if (kind == Snapshot::kFull) {
*(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
type_arguments.set_instantiations(*(reader->ArrayHandle()));
} else {
type_arguments.set_instantiations(Object::zero_array());
}
// Now set all the type fields.
intptr_t offset = type_arguments.TypeAddr(0) -
reinterpret_cast<RawAbstractType**>(type_arguments.raw()->ptr());
for (intptr_t i = 0; i < len; i++) {
*reader->TypeHandle() ^=
reader->ReadObjectImpl(kAsReference, object_id, (i + offset));
type_arguments.SetTypeAt(i, *reader->TypeHandle());
}
// Set the canonical bit.
if (!defer_canonicalization && RawObject::IsCanonical(tags)) {
type_arguments.SetCanonical();
}
return type_arguments.raw();
}
void RawTypeArguments::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kTypeArgumentsCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the length field.
writer->Write<RawObject*>(ptr()->length_);
// Write out the instantiations field, but only in a full snapshot.
if (kind == Snapshot::kFull) {
writer->WriteObjectImpl(ptr()->instantiations_, kAsInlinedObject);
}
// Write out the individual types.
intptr_t len = Smi::Value(ptr()->length_);
for (intptr_t i = 0; i < len; i++) {
writer->WriteObjectImpl(ptr()->types()[i], kAsReference);
}
}
RawPatchClass* PatchClass::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate function object.
PatchClass& cls = PatchClass::ZoneHandle(reader->zone(),
NEW_OBJECT(PatchClass));
reader->AddBackRef(object_id, &cls, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to(), kAsReference);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
return cls.raw();
}
void RawPatchClass::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kPatchClassCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawClosureData* ClosureData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Allocate closure data object.
ClosureData& data = ClosureData::ZoneHandle(
reader->zone(), NEW_OBJECT(ClosureData));
reader->AddBackRef(object_id, &data, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(data,
data.raw()->from(), data.raw()->to(),
kAsInlinedObject);
return data.raw();
}
void RawClosureData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kClosureDataCid);
writer->WriteTags(writer->GetObjectTags(this));
// Context scope.
if (ptr()->context_scope_ == Object::empty_context_scope().raw()) {
writer->WriteVMIsolateObject(kEmptyContextScopeObject);
} else {
if (ptr()->context_scope_->ptr()->is_implicit_) {
writer->WriteObjectImpl(ptr()->context_scope_, kAsInlinedObject);
} else {
// We don't write non implicit context scopes in the snapshot.
writer->WriteVMIsolateObject(kNullObject);
}
}
// Parent function.
writer->WriteObjectImpl(ptr()->parent_function_, kAsInlinedObject);
// Signature class.
writer->WriteObjectImpl(ptr()->signature_class_, kAsInlinedObject);
// Static closure/Closure allocation stub.
// We don't write the closure or allocation stub in the snapshot.
writer->WriteVMIsolateObject(kNullObject);
}
RawRedirectionData* RedirectionData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Allocate redirection data object.
RedirectionData& data = RedirectionData::ZoneHandle(
reader->zone(), NEW_OBJECT(RedirectionData));
reader->AddBackRef(object_id, &data, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(data,
data.raw()->from(), data.raw()->to(),
kAsReference);
return data.raw();
}
void RawRedirectionData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kRedirectionDataCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawFunction* Function::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
bool is_in_fullsnapshot = reader->Read<bool>();
if ((kind == Snapshot::kFull) || !is_in_fullsnapshot) {
// Allocate function object.
Function& func = Function::ZoneHandle(
reader->zone(), NEW_OBJECT(Function));
reader->AddBackRef(object_id, &func, kIsDeserialized);
// Set all the non object fields.
func.set_token_pos(reader->Read<int32_t>());
func.set_end_token_pos(reader->Read<int32_t>());
func.set_usage_counter(reader->Read<int32_t>());
func.set_num_fixed_parameters(reader->Read<int16_t>());
func.set_num_optional_parameters(reader->Read<int16_t>());
func.set_deoptimization_counter(reader->Read<int16_t>());
func.set_kind_tag(reader->Read<uint32_t>());
func.set_optimized_instruction_count(reader->Read<uint16_t>());
func.set_optimized_call_site_count(reader->Read<uint16_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(func,
func.raw()->from(), func.raw()->to_snapshot(),
kAsReference);
// Initialize all fields that are not part of the snapshot.
if (reader->snapshot_code()) {
func.ClearICDataArray();
func.ClearCode();
// Read the code object and fixup entry point.
(*reader->CodeHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
func.SetInstructions(*reader->CodeHandle());
} else {
bool is_optimized = func.usage_counter() != 0;
if (is_optimized) {
// Read the ic data array as the function is an optimized one.
(*reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsReference);
func.set_ic_data_array(*reader->ArrayHandle());
} else {
func.ClearICDataArray();
}
func.ClearCode();
}
return func.raw();
} else {
return reader->ReadFunctionId(object_id);
}
}
void RawFunction::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
bool is_in_fullsnapshot = false;
bool owner_is_class = false;
if (kind == Snapshot::kScript) {
intptr_t tags = writer->GetObjectTags(ptr()->owner_);
intptr_t cid = ClassIdTag::decode(tags);
owner_is_class = (cid == kClassCid);
is_in_fullsnapshot = owner_is_class ?
Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(ptr()->owner_)) :
PatchClass::IsInFullSnapshot(
reinterpret_cast<RawPatchClass*>(ptr()->owner_));
}
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kFunctionCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the boolean is_in_fullsnapshot first as this will
// help the reader decide how the rest of the information needs
// to be interpreted.
writer->Write<bool>(is_in_fullsnapshot);
if (kind == Snapshot::kFull || !is_in_fullsnapshot) {
bool is_optimized = Code::IsOptimized(ptr()->code_);
// Write out all the non object fields.
writer->Write<int32_t>(ptr()->token_pos_);
writer->Write<int32_t>(ptr()->end_token_pos_);
if (is_optimized) {
writer->Write<int32_t>(FLAG_optimization_counter_threshold);
} else {
writer->Write<int32_t>(0);
}
writer->Write<int16_t>(ptr()->num_fixed_parameters_);
writer->Write<int16_t>(ptr()->num_optional_parameters_);
writer->Write<int16_t>(ptr()->deoptimization_counter_);
writer->Write<uint32_t>(ptr()->kind_tag_);
writer->Write<uint16_t>(ptr()->optimized_instruction_count_);
writer->Write<uint16_t>(ptr()->optimized_call_site_count_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to_snapshot());
if (writer->snapshot_code()) {
ASSERT(ptr()->ic_data_array_ == Array::null());
ASSERT((ptr()->code_ == ptr()->unoptimized_code_) ||
(ptr()->unoptimized_code_ == Code::null()));
// Write out the code object as we are generating a precompiled snapshot.
writer->WriteObjectImpl(ptr()->code_, kAsInlinedObject);
} else if (is_optimized) {
// Write out the ic data array as the function is optimized or
// we are generating a precompiled snapshot.
writer->WriteObjectImpl(ptr()->ic_data_array_, kAsReference);
}
} else {
writer->WriteFunctionId(this, owner_is_class);
}
}
RawField* Field::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Allocate field object.
Field& field = Field::ZoneHandle(reader->zone(), NEW_OBJECT(Field));
reader->AddBackRef(object_id, &field, kIsDeserialized);
// Set all non object fields.
field.set_token_pos(reader->Read<int32_t>());
field.set_guarded_cid(reader->Read<int32_t>());
field.set_is_nullable(reader->Read<int32_t>());
field.set_kind_bits(reader->Read<uint8_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(field,
field.raw()->from(), field.raw()->to(),
kAsReference);
field.InitializeGuardedListLengthInObjectOffset();
return field.raw();
}
void RawField::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kFieldCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object fields.
writer->Write<int32_t>(ptr()->token_pos_);
writer->Write<int32_t>(ptr()->guarded_cid_);
writer->Write<int32_t>(ptr()->is_nullable_);
writer->Write<uint8_t>(ptr()->kind_bits_);
// Write out the name.
writer->WriteObjectImpl(ptr()->name_, kAsReference);
// Write out the owner.
writer->WriteObjectImpl(ptr()->owner_, kAsReference);
// Write out the type.
writer->WriteObjectImpl(ptr()->type_, kAsReference);
// Write out the initial static value or field offset.
if (Field::StaticBit::decode(ptr()->kind_bits_)) {
if (writer->snapshot_code()) {
// For precompiled static fields, the value was already reset and
// initializer_ now contains a Function.
writer->WriteObjectImpl(ptr()->value_.static_value_, kAsReference);
} else {
// Otherwise, for static fields we write out the initial static value.
writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference);
}
} else {
writer->WriteObjectImpl(ptr()->value_.offset_, kAsReference);
}
// Write out the dependent code.
writer->WriteObjectImpl(ptr()->dependent_code_, kAsReference);
// Write out the initializer function or saved initial value.
if (writer->snapshot_code()) {
writer->WriteObjectImpl(ptr()->initializer_.precompiled_, kAsReference);
} else {
writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference);
}
// Write out the guarded list length.
writer->WriteObjectImpl(ptr()->guarded_list_length_, kAsReference);
}
RawLiteralToken* LiteralToken::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT(kind != Snapshot::kMessage);
// Create the literal token object.
LiteralToken& literal_token = LiteralToken::ZoneHandle(
reader->zone(), NEW_OBJECT(LiteralToken));
reader->AddBackRef(object_id, &literal_token, kIsDeserialized);
// Read the token attributes.
Token::Kind token_kind = static_cast<Token::Kind>(reader->Read<int32_t>());
literal_token.set_kind(token_kind);
// Set all the object fields.
READ_OBJECT_FIELDS(literal_token,
literal_token.raw()->from(), literal_token.raw()->to(),
kAsReference);
return literal_token.raw();
}
void RawLiteralToken::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT(kind != Snapshot::kMessage);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kLiteralTokenCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the kind field.
writer->Write<int32_t>(ptr()->kind_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawTokenStream* TokenStream::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Read the length so that we can determine number of tokens to read.
intptr_t len = reader->ReadSmiValue();
// Create the token stream object.
TokenStream& token_stream = TokenStream::ZoneHandle(
reader->zone(), NEW_OBJECT_WITH_LEN(TokenStream, len));
reader->AddBackRef(object_id, &token_stream, kIsDeserialized);
// Read the stream of tokens into the TokenStream object for script
// snapshots as we made a copy of token stream.
if (kind == Snapshot::kScript) {
NoSafepointScope no_safepoint;
RawExternalTypedData* stream = token_stream.GetStream();
reader->ReadBytes(stream->ptr()->data_, len);
}
// Read in the literal/identifier token array.
*(reader->TokensHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
token_stream.SetTokenObjects(*(reader->TokensHandle()));
// Read in the private key in use by the token stream.
*(reader->StringHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
token_stream.SetPrivateKey(*(reader->StringHandle()));
return token_stream.raw();
}
void RawTokenStream::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kTokenStreamCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the length field and the token stream.
RawExternalTypedData* stream = ptr()->stream_;
intptr_t len = Smi::Value(stream->ptr()->length_);
writer->Write<RawObject*>(stream->ptr()->length_);
writer->WriteBytes(stream->ptr()->data_, len);
// Write out the literal/identifier token array.
writer->WriteObjectImpl(ptr()->token_objects_, kAsInlinedObject);
// Write out the private key in use by the token stream.
writer->WriteObjectImpl(ptr()->private_key_, kAsInlinedObject);
}
RawScript* Script::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Allocate script object.
Script& script = Script::ZoneHandle(reader->zone(), NEW_OBJECT(Script));
reader->AddBackRef(object_id, &script, kIsDeserialized);
script.StoreNonPointer(&script.raw_ptr()->line_offset_,
reader->Read<int32_t>());
script.StoreNonPointer(&script.raw_ptr()->col_offset_,
reader->Read<int32_t>());
script.StoreNonPointer(&script.raw_ptr()->kind_,
reader->Read<int8_t>());
// Set all the object fields.
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
intptr_t num_flds = (script.raw()->to_snapshot() - script.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
(*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
script.StorePointer((script.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
// Script wasn't allocated with nulls?
*reader->StringHandle() ^= String::null();
script.set_source(*reader->StringHandle());
return script.raw();
}
void RawScript::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT(tokens_ != TokenStream::null());
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kScriptCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object fields.
writer->Write<int32_t>(ptr()->line_offset_);
writer->Write<int32_t>(ptr()->col_offset_);
writer->Write<int8_t>(ptr()->kind_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to_snapshot());
}
RawLibrary* Library::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT(kind != Snapshot::kMessage);
Library& library = Library::ZoneHandle(reader->zone(), Library::null());
reader->AddBackRef(object_id, &library, kIsDeserialized);
bool is_in_fullsnapshot = reader->Read<bool>();
if ((kind == Snapshot::kScript) && is_in_fullsnapshot) {
// Lookup the object as it should already exist in the heap.
*reader->StringHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
library = Library::LookupLibrary(*reader->StringHandle());
ASSERT(library.is_in_fullsnapshot());
} else {
// Allocate library object.
library = NEW_OBJECT(Library);
// Set all non object fields.
library.StoreNonPointer(&library.raw_ptr()->index_,
reader->ReadClassIDValue());
library.StoreNonPointer(&library.raw_ptr()->num_anonymous_,
reader->ReadClassIDValue());
library.StoreNonPointer(&library.raw_ptr()->num_imports_,
reader->Read<uint16_t>());
library.StoreNonPointer(&library.raw_ptr()->load_state_,
reader->Read<int8_t>());
library.StoreNonPointer(&library.raw_ptr()->corelib_imported_,
reader->Read<bool>());
library.StoreNonPointer(&library.raw_ptr()->is_dart_scheme_,
reader->Read<bool>());
library.StoreNonPointer(&library.raw_ptr()->debuggable_,
reader->Read<bool>());
if (kind == Snapshot::kFull) {
is_in_fullsnapshot = true;
}
library.StoreNonPointer(&library.raw_ptr()->is_in_fullsnapshot_,
is_in_fullsnapshot);
// The native resolver and symbolizer are not serialized.
library.set_native_entry_resolver(NULL);
library.set_native_entry_symbol_resolver(NULL);
// The cache of loaded scripts is not serialized.
library.StorePointer(&library.raw_ptr()->loaded_scripts_, Array::null());
// Set all the object fields.
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
RawObject** toobj = (kind == Snapshot::kFull) ?
library.raw()->to() : library.raw()->to_snapshot();
intptr_t num_flds = (toobj - library.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
(*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
library.StorePointer((library.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
if (kind != Snapshot::kFull) {
// The cache of resolved names in library scope is not serialized.
const intptr_t kInitialNameCacheSize = 64;
library.InitResolvedNamesCache(kInitialNameCacheSize);
library.Register();
}
}
return library.raw();
}
void RawLibrary::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT(kind != Snapshot::kMessage);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kLibraryCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the boolean is_in_fullsnapshot_ first as this will
// help the reader decide how the rest of the information needs
// to be interpreted.
writer->Write<bool>(ptr()->is_in_fullsnapshot_);
if ((kind == Snapshot::kScript) && ptr()->is_in_fullsnapshot_) {
// Write out library URL so that it can be looked up when reading.
writer->WriteObjectImpl(ptr()->url_, kAsInlinedObject);
} else {
ASSERT((kind == Snapshot::kFull) || !ptr()->is_in_fullsnapshot_);
// Write out all non object fields.
writer->WriteClassIDValue(ptr()->index_);
writer->WriteClassIDValue(ptr()->num_anonymous_);
writer->Write<uint16_t>(ptr()->num_imports_);
writer->Write<int8_t>(ptr()->load_state_);
writer->Write<bool>(ptr()->corelib_imported_);
writer->Write<bool>(ptr()->is_dart_scheme_);
writer->Write<bool>(ptr()->debuggable_);
// We do not serialize the native resolver or symbolizer. These need to be
// explicitly set after deserialization.
// We do not write the loaded_scripts_ cache to the snapshot. It gets
// set to NULL when reading the library from the snapshot, and will
// be rebuilt lazily.
// Write out all the object pointer fields.
RawObject** toobj = (kind == Snapshot::kFull) ? to() : to_snapshot();
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), toobj);
}
}
RawLibraryPrefix* LibraryPrefix::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Allocate library prefix object.
LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(
reader->zone(), NEW_OBJECT(LibraryPrefix));
reader->AddBackRef(object_id, &prefix, kIsDeserialized);
// Set all non object fields.
prefix.StoreNonPointer(&prefix.raw_ptr()->num_imports_,
reader->Read<int16_t>());
prefix.StoreNonPointer(&prefix.raw_ptr()->is_deferred_load_,
reader->Read<bool>());
prefix.StoreNonPointer(&prefix.raw_ptr()->is_loaded_, reader->Read<bool>());
// Set all the object fields.
READ_OBJECT_FIELDS(prefix,
prefix.raw()->from(), prefix.raw()->to(),
kAsReference);
return prefix.raw();
}
void RawLibraryPrefix::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kLibraryPrefixCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all non object fields.
writer->Write<int16_t>(ptr()->num_imports_);
writer->Write<bool>(ptr()->is_deferred_load_);
writer->Write<bool>(ptr()->is_loaded_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawNamespace* Namespace::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Allocate Namespace object.
Namespace& ns = Namespace::ZoneHandle(
reader->zone(), NEW_OBJECT(Namespace));
reader->AddBackRef(object_id, &ns, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(ns, ns.raw()->from(), ns.raw()->to(), kAsReference);
return ns.raw();
}
void RawNamespace::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kNamespaceCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawCode* Code::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader->snapshot_code());
ASSERT(kind == Snapshot::kFull);
Code& result = Code::ZoneHandle(reader->zone(), NEW_OBJECT_WITH_LEN(Code, 0));
reader->AddBackRef(object_id, &result, kIsDeserialized);
result.set_compile_timestamp(reader->Read<int64_t>());
result.set_state_bits(reader->Read<int32_t>());
result.set_lazy_deopt_pc_offset(reader->Read<int32_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(result,
result.raw()->from(), result.raw()->to(),
kAsReference);
// Fix entry point.
uword new_entry = result.EntryPoint();
ASSERT(Dart::vm_isolate()->heap()->CodeContains(new_entry));
result.StoreNonPointer(&result.raw_ptr()->entry_point_, new_entry);
return result.raw();
}
void RawCode::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer->snapshot_code());
ASSERT(kind == Snapshot::kFull);
intptr_t pointer_offsets_length =
Code::PtrOffBits::decode(ptr()->state_bits_);
if (pointer_offsets_length != 0) {
// Should only be IA32.
FATAL("Serializing embedded pointer offsets unimplemented");
}
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kCodeCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object fields.
writer->Write<int64_t>(ptr()->compile_timestamp_);
writer->Write<int32_t>(ptr()->state_bits_);
writer->Write<int32_t>(ptr()->lazy_deopt_pc_offset_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
writer->SetInstructionsCode(ptr()->instructions_, this);
}
RawInstructions* Instructions::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader->snapshot_code());
ASSERT(kind == Snapshot::kFull);
intptr_t full_tags = static_cast<uword>(reader->Read<intptr_t>());
intptr_t offset = reader->Read<int32_t>();
Instructions& result =
Instructions::ZoneHandle(reader->zone(),
reader->GetInstructionsAt(offset, full_tags));
reader->AddBackRef(object_id, &result, kIsDeserialized);
return result.raw();
}
void RawInstructions::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer->snapshot_code());
ASSERT(kind == Snapshot::kFull);
writer->WriteInlinedObjectHeader(object_id);
writer->WriteVMIsolateObject(kInstructionsCid);
writer->WriteTags(writer->GetObjectTags(this));
// Instructions will be written pre-marked and in the VM heap. Write out
// the tags we expect to find when reading the snapshot for a sanity check
// that our offsets/alignment didn't get out of sync.
uword written_tags = writer->GetObjectTags(this);
written_tags = RawObject::VMHeapObjectTag::update(true, written_tags);
written_tags = RawObject::MarkBit::update(true, written_tags);
writer->Write<intptr_t>(written_tags);
writer->Write<int32_t>(writer->GetInstructionsId(this));
}
RawObjectPool* ObjectPool::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader->snapshot_code());
ASSERT(kind == Snapshot::kFull);
intptr_t length = reader->Read<intptr_t>();
ObjectPool* result =
reinterpret_cast<ObjectPool*>(reader->GetBackRef(object_id));
if (result == NULL) {
result =
&(ObjectPool::ZoneHandle(reader->zone(),
NEW_OBJECT_WITH_LEN(ObjectPool, length)));
reader->AddBackRef(object_id, result, kIsDeserialized);
}
const TypedData& info_array =
TypedData::Handle(reader->NewTypedData(kTypedDataInt8ArrayCid, length));
result->set_info_array(info_array);
NoSafepointScope no_safepoint;
for (intptr_t i = 0; i < length; i++) {
ObjectPool::EntryType entry_type =
static_cast<ObjectPool::EntryType>(reader->Read<int8_t>());
*reinterpret_cast<int8_t*>(info_array.DataAddr(i)) = entry_type;
switch (entry_type) {
case ObjectPool::kTaggedObject: {
(*reader->PassiveObjectHandle()) =
reader->ReadObjectImpl(kAsReference);
result->SetObjectAt(i, *(reader->PassiveObjectHandle()));
break;
}
case ObjectPool::kImmediate: {
intptr_t raw_value = reader->Read<intptr_t>();
result->SetRawValueAt(i, raw_value);
break;
}
case ObjectPool::kNativeEntry: {
// Read nothing. Initialize with the lazy link entry.
uword new_entry = NativeEntry::LinkNativeCallEntry();
result->SetRawValueAt(i, static_cast<intptr_t>(new_entry));
break;
}
default:
UNREACHABLE();
}
}
return result->raw();
}
void RawObjectPool::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer->snapshot_code());
ASSERT(kind == Snapshot::kFull);
intptr_t tags = writer->GetObjectTags(this);
intptr_t length = ptr()->length_;
if (as_reference) {
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(kOmittedObjectId);
// Write out the class information.
writer->WriteVMIsolateObject(kObjectPoolCid);
writer->WriteTags(tags);
// Write out the length field.
writer->Write<intptr_t>(length);
} else {
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kObjectPoolCid);
writer->WriteTags(tags);
RawTypedData* info_array = ptr()->info_array_->ptr();
ASSERT(info_array != TypedData::null());
writer->Write<intptr_t>(length);
for (intptr_t i = 0; i < length; i++) {
ObjectPool::EntryType entry_type =
static_cast<ObjectPool::EntryType>(info_array->data()[i]);
writer->Write<int8_t>(entry_type);
Entry& entry = ptr()->data()[i];
switch (entry_type) {
case ObjectPool::kTaggedObject: {
if (entry.raw_obj_ == StubCode::CallNativeCFunction_entry()->code()) {
// Natives can run while precompiling, becoming linked and switching
// their stub. Reset to the initial stub used for lazy-linking.
writer->WriteObjectImpl(
StubCode::CallBootstrapCFunction_entry()->code(), kAsReference);
} else {
writer->WriteObjectImpl(entry.raw_obj_, kAsReference);
}
break;
}
case ObjectPool::kImmediate: {
writer->Write<intptr_t>(entry.raw_value_);
break;
}
case ObjectPool::kNativeEntry: {
// Write nothing. Will initialize with the lazy link entry.
break;
}
default:
UNREACHABLE();
}
}
}
}
RawPcDescriptors* PcDescriptors::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader->snapshot_code());
ASSERT(kind == Snapshot::kFull);
const int32_t length = reader->Read<int32_t>();
PcDescriptors& result =
PcDescriptors::ZoneHandle(reader->zone(),
NEW_OBJECT_WITH_LEN(PcDescriptors, length));
reader->AddBackRef(object_id, &result, kIsDeserialized);
if (result.Length() > 0) {
NoSafepointScope no_safepoint;
intptr_t len = result.Length();
uint8_t* data = result.UnsafeMutableNonPointer(result.raw_ptr()->data());
reader->ReadBytes(data, len);
}
return result.raw();
}
void RawPcDescriptors::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer->snapshot_code());
ASSERT(kind == Snapshot::kFull);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
writer->WriteIndexedObject(kPcDescriptorsCid);
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<int32_t>(ptr()->length_);
if (ptr()->length_ > 0) {
intptr_t len = ptr()->length_;
uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
writer->WriteBytes(data, len);
}
}
RawStackmap* Stackmap::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader->snapshot_code());
ASSERT(kind == Snapshot::kFull);
const int32_t length = reader->Read<int32_t>();
Stackmap& result =
Stackmap::ZoneHandle(reader->zone(),
reader->NewStackmap(length));
reader->AddBackRef(object_id, &result, kIsDeserialized);
result.SetRegisterBitCount(reader->Read<int32_t>());
result.SetPcOffset(reader->Read<uint32_t>());
if (length > 0) {
NoSafepointScope no_safepoint;
intptr_t len = (result.Length() + 7) / 8;
uint8_t* data = result.UnsafeMutableNonPointer(result.raw_ptr()->data());
reader->ReadBytes(data, len);
}
return result.raw();
}
void RawStackmap::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer->snapshot_code());
ASSERT(kind == Snapshot::kFull);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
writer->WriteIndexedObject(kStackmapCid);
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<int32_t>(ptr()->length_);
writer->Write<int32_t>(ptr()->register_bit_count_);
writer->Write<uint32_t>(ptr()->pc_offset_);
if (ptr()->length_ > 0) {
intptr_t len = (ptr()->length_ + 7) / 8;
uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
writer->WriteBytes(data, len);
}
}
RawLocalVarDescriptors* LocalVarDescriptors::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader->snapshot_code());
ASSERT(kind == Snapshot::kFull);
const int32_t num_entries = reader->Read<int32_t>();
LocalVarDescriptors& result =
LocalVarDescriptors::ZoneHandle(reader->zone(),
NEW_OBJECT_WITH_LEN(LocalVarDescriptors,
num_entries));
reader->AddBackRef(object_id, &result, kIsDeserialized);
for (intptr_t i = 0; i < num_entries; i++) {
(*reader->StringHandle()) ^= reader->ReadObjectImpl(kAsReference);
result.StorePointer(result.raw()->nameAddrAt(i),
reader->StringHandle()->raw());
}
if (num_entries > 0) {
NoSafepointScope no_safepoint;
intptr_t len = num_entries * sizeof(RawLocalVarDescriptors::VarInfo);
uint8_t* data = result.UnsafeMutableNonPointer(
reinterpret_cast<const uint8_t*>(result.raw()->data()));
reader->ReadBytes(data, len);
}
return result.raw();
}
void RawLocalVarDescriptors::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer->snapshot_code());
ASSERT(kind == Snapshot::kFull);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
writer->WriteIndexedObject(kLocalVarDescriptorsCid);
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<int32_t>(ptr()->num_entries_);
for (intptr_t i = 0; i < ptr()->num_entries_; i++) {
writer->WriteObjectImpl(ptr()->names()[i], kAsReference);
}
if (ptr()->num_entries_ > 0) {
intptr_t len = ptr()->num_entries_ * sizeof(VarInfo);
uint8_t* data = reinterpret_cast<uint8_t*>(this->data());
writer->WriteBytes(data, len);
}
}
RawExceptionHandlers* ExceptionHandlers::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader->snapshot_code());
ASSERT(kind == Snapshot::kFull);
const int32_t num_entries = reader->Read<int32_t>();
ExceptionHandlers& result =
ExceptionHandlers::ZoneHandle(reader->zone(),
NEW_OBJECT_WITH_LEN(ExceptionHandlers,
num_entries));
reader->AddBackRef(object_id, &result, kIsDeserialized);
if (result.num_entries() > 0) {
NoSafepointScope no_safepoint;
const intptr_t len =
result.num_entries() * sizeof(RawExceptionHandlers::HandlerInfo);
uint8_t* data = result.UnsafeMutableNonPointer(
reinterpret_cast<const uint8_t*>(result.raw_ptr()->data()));
reader->ReadBytes(data, len);
}
*(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
result.StorePointer(&result.raw_ptr()->handled_types_data_,
reader->ArrayHandle()->raw());
return result.raw();
}
void RawExceptionHandlers::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer->snapshot_code());
ASSERT(kind == Snapshot::kFull);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
writer->WriteIndexedObject(kExceptionHandlersCid);
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<int32_t>(ptr()->num_entries_);
if (ptr()->num_entries_ > 0) {
intptr_t len = ptr()->num_entries_ * sizeof(HandlerInfo);
uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
writer->WriteBytes(data, len);
}
writer->WriteObjectImpl(ptr()->handled_types_data_, kAsInlinedObject);
}
RawContext* Context::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate context object.
int32_t num_vars = reader->Read<int32_t>();
Context& context = Context::ZoneHandle(reader->zone());
reader->AddBackRef(object_id, &context, kIsDeserialized);
if (num_vars == 0) {
context ^= reader->object_store()->empty_context();
} else {
context ^= NEW_OBJECT_WITH_LEN(Context, num_vars);
// Set all the object fields.
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
intptr_t num_flds = (context.raw()->to(num_vars) - context.raw()->from());
for (intptr_t i = 0; i <= num_flds; i++) {
(*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
context.StorePointer((context.raw()->from() + i),
reader->PassiveObjectHandle()->raw());
}
}
return context.raw();
}
void RawContext::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kContextCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out num of variables in the context.
int32_t num_variables = ptr()->num_variables_;
writer->Write<int32_t>(num_variables);
if (num_variables != 0) {
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to(num_variables));
}
}
RawContextScope* ContextScope::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate context object.
bool is_implicit = reader->Read<bool>();
if (is_implicit) {
ContextScope& context_scope = ContextScope::ZoneHandle();
if (kind == Snapshot::kFull) {
context_scope = reader->NewContextScope(1);
context_scope.set_is_implicit(true);
} else {
context_scope = ContextScope::New(1, true);
}
reader->AddBackRef(object_id, &context_scope, kIsDeserialized);
*reader->TypeHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
// Create a descriptor for 'this' variable.
context_scope.SetTokenIndexAt(0, 0);
context_scope.SetNameAt(0, Symbols::This());
context_scope.SetIsFinalAt(0, true);
context_scope.SetIsConstAt(0, false);
context_scope.SetTypeAt(0, *reader->TypeHandle());
context_scope.SetContextIndexAt(0, 0);
context_scope.SetContextLevelAt(0, 0);
return context_scope.raw();
}
UNREACHABLE();
return NULL;
}
void RawContextScope::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
if (ptr()->is_implicit_) {
ASSERT(ptr()->num_variables_ == 1);
const VariableDesc* var = ptr()->VariableDescAddr(0);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kContextScopeCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out is_implicit flag for the context scope.
writer->Write<bool>(true);
// Write out the type of 'this' the variable.
writer->WriteObjectImpl(var->type, kAsInlinedObject);
return;
}
UNREACHABLE();
}
RawICData* ICData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
ICData& result = ICData::ZoneHandle(reader->zone(), NEW_OBJECT(ICData));
reader->AddBackRef(object_id, &result, kIsDeserialized);
result.set_deopt_id(reader->Read<int32_t>());
result.set_state_bits(reader->Read<uint32_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(result,
result.raw()->from(), result.raw()->to(),
kAsReference);
return result.raw();
}
void RawICData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kICDataCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object fields.
writer->Write<int32_t>(ptr()->deopt_id_);
writer->Write<uint32_t>(ptr()->state_bits_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawMegamorphicCache* MegamorphicCache::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader->snapshot_code());
ASSERT(kind == Snapshot::kFull);
MegamorphicCache& result =
MegamorphicCache::ZoneHandle(reader->zone(),
NEW_OBJECT(MegamorphicCache));
reader->AddBackRef(object_id, &result, kIsDeserialized);
result.set_filled_entry_count(reader->Read<int32_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(result,
result.raw()->from(), result.raw()->to(),
kAsReference);
return result.raw();
}
void RawMegamorphicCache::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer->snapshot_code());
ASSERT(kind == Snapshot::kFull);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kMegamorphicCacheCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object fields.
writer->Write<int32_t>(ptr()->filled_entry_count_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawSubtypeTestCache* SubtypeTestCache::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader->snapshot_code());
ASSERT(kind == Snapshot::kFull);
SubtypeTestCache& result =
SubtypeTestCache::ZoneHandle(reader->zone(),
NEW_OBJECT(SubtypeTestCache));
reader->AddBackRef(object_id, &result, kIsDeserialized);
// Set all the object fields.
// TODO(5411462): Need to assert No GC can happen here, even though
// allocations may happen.
(*reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsReference);
result.StorePointer(&result.raw_ptr()->cache_,
reader->ArrayHandle()->raw());
return result.raw();
}
void RawSubtypeTestCache::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer->snapshot_code());
ASSERT(kind == Snapshot::kFull);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kSubtypeTestCacheCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
writer->WriteObjectImpl(ptr()->cache_, kAsReference);
}
RawError* Error::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_referenec) {
UNREACHABLE();
return Error::null(); // Error is an abstract class.
}
void RawError::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE(); // Error is an abstract class.
}
RawApiError* ApiError::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate ApiError object.
ApiError& api_error =
ApiError::ZoneHandle(reader->zone(), NEW_OBJECT(ApiError));
reader->AddBackRef(object_id, &api_error, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(api_error,
api_error.raw()->from(), api_error.raw()->to(),
kAsReference);
return api_error.raw();
}
void RawApiError::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kApiErrorCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawLanguageError* LanguageError::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate LanguageError object.
LanguageError& language_error =
LanguageError::ZoneHandle(reader->zone(), NEW_OBJECT(LanguageError));
reader->AddBackRef(object_id, &language_error, kIsDeserialized);
// Set all non object fields.
language_error.set_token_pos(reader->Read<int32_t>());
language_error.set_kind(reader->Read<uint8_t>());
// Set all the object fields.
READ_OBJECT_FIELDS(language_error,
language_error.raw()->from(), language_error.raw()->to(),
kAsReference);
return language_error.raw();
}
void RawLanguageError::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kLanguageErrorCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object fields.
writer->Write<int32_t>(ptr()->token_pos_);
writer->Write<uint8_t>(ptr()->kind_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawUnhandledException* UnhandledException::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UnhandledException& result = UnhandledException::ZoneHandle(
reader->zone(), NEW_OBJECT(UnhandledException));
reader->AddBackRef(object_id, &result, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(result,
result.raw()->from(), result.raw()->to(),
kAsReference);
return result.raw();
}
void RawUnhandledException::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kUnhandledExceptionCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawUnwindError* UnwindError::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return UnwindError::null();
}
void RawUnwindError::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawInstance* Instance::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Create an Instance object or get canonical one if it is a canonical
// constant.
Instance& obj = Instance::ZoneHandle(reader->zone(), Instance::null());
if (kind == Snapshot::kFull) {
obj = reader->NewInstance();
// Set the canonical bit.
if (RawObject::IsCanonical(tags)) {
obj.SetCanonical();
}
} else {
obj ^= Object::Allocate(kInstanceCid,
Instance::InstanceSize(),
HEAP_SPACE(kind));
if (RawObject::IsCanonical(tags)) {
obj = obj.CheckAndCanonicalize(NULL);
}
}
reader->AddBackRef(object_id, &obj, kIsDeserialized);
return obj.raw();
}
void RawInstance::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kInstanceCid);
writer->WriteTags(writer->GetObjectTags(this));
}
RawInteger* Mint::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Read the 64 bit value for the object.
int64_t value = reader->Read<int64_t>();
// Check if the value could potentially fit in a Smi in our current
// architecture, if so return the object as a Smi.
if (Smi::IsValid(value)) {
Smi& smi = Smi::ZoneHandle(reader->zone(),
Smi::New(static_cast<intptr_t>(value)));
reader->AddBackRef(object_id, &smi, kIsDeserialized);
return smi.raw();
}
// Create a Mint object or get canonical one if it is a canonical constant.
Mint& mint = Mint::ZoneHandle(reader->zone(), Mint::null());
if (kind == Snapshot::kFull) {
mint = reader->NewMint(value);
// Set the canonical bit.
if (RawObject::IsCanonical(tags)) {
mint.SetCanonical();
}
} else {
// When reading a script snapshot we need to canonicalize only those object
// references that are objects from the core library (loaded from a
// full snapshot). Objects that are only in the script need not be
// canonicalized as they are already canonical.
// When reading a message snapshot we always have to canonicalize.
if (RawObject::IsCanonical(tags)) {
mint = Mint::NewCanonical(value);
ASSERT(mint.IsCanonical());
} else {
mint = Mint::New(value, HEAP_SPACE(kind));
}
}
reader->AddBackRef(object_id, &mint, kIsDeserialized);
return mint.raw();
}
void RawMint::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kMintCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the 64 bit value.
writer->Write<int64_t>(ptr()->value_);
}
RawBigint* Bigint::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate bigint object.
Bigint& obj = Bigint::ZoneHandle(reader->zone(), NEW_OBJECT(Bigint));
reader->AddBackRef(object_id, &obj, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(obj, obj.raw()->from(), obj.raw()->to(), kAsInlinedObject);
// If it is a canonical constant make it one.
// When reading a full snapshot we don't need to canonicalize the object
// as it would already be a canonical object.
// When reading a script snapshot or a message snapshot we always have
// to canonicalize the object.
if (RawObject::IsCanonical(tags)) {
if (kind == Snapshot::kFull) {
// Set the canonical bit.
obj.SetCanonical();
} else {
obj ^= obj.CheckAndCanonicalize(NULL);
ASSERT(!obj.IsNull());
ASSERT(obj.IsCanonical());
}
}
return obj.raw();
}
void RawBigint::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kBigintCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsInlinedObject);
visitor.VisitPointers(from(), to());
}
RawDouble* Double::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
ASSERT(kind != Snapshot::kMessage);
// Read the double value for the object.
double value = reader->ReadDouble();
// Create a Double object or get canonical one if it is a canonical constant.
Double& dbl = Double::ZoneHandle(reader->zone(), Double::null());
if (kind == Snapshot::kFull) {
dbl = reader->NewDouble(value);
// Set the canonical bit.
if (RawObject::IsCanonical(tags)) {
dbl.SetCanonical();
}
} else {
// When reading a script snapshot we need to canonicalize only those object
// references that are objects from the core library (loaded from a
// full snapshot). Objects that are only in the script need not be
// canonicalized as they are already canonical.
if (RawObject::IsCanonical(tags)) {
dbl = Double::NewCanonical(value);
ASSERT(dbl.IsCanonical());
} else {
dbl = Double::New(value, HEAP_SPACE(kind));
}
}
reader->AddBackRef(object_id, &dbl, kIsDeserialized);
return dbl.raw();
}
void RawDouble::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kDoubleCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the double value.
writer->WriteDouble(ptr()->value_);
}
RawString* String::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE(); // String is an abstract class.
return String::null();
}
void RawString::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE(); // String is an abstract class.
}
template<typename StringType, typename CharacterType, typename CallbackType>
void String::ReadFromImpl(SnapshotReader* reader,
String* str_obj,
intptr_t len,
intptr_t tags,
CallbackType new_symbol,
Snapshot::Kind kind) {
ASSERT(reader != NULL);
if (RawObject::IsCanonical(tags)) {
// Set up canonical string object.
ASSERT(reader != NULL);
CharacterType* ptr = reader->zone()->Alloc<CharacterType>(len);
for (intptr_t i = 0; i < len; i++) {
ptr[i] = reader->Read<CharacterType>();
}
*str_obj ^= (*new_symbol)(ptr, len);
} else {
// Set up the string object.
*str_obj = StringType::New(len, HEAP_SPACE(kind));
str_obj->SetHash(0); // Will get computed when needed.
if (len == 0) {
return;
}
NoSafepointScope no_safepoint;
CharacterType* str_addr = StringType::CharAddr(*str_obj, 0);
for (intptr_t i = 0; i < len; i++) {
*str_addr = reader->Read<CharacterType>();
str_addr++;
}
}
}
RawOneByteString* OneByteString::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
// Read the length so that we can determine instance size to allocate.
ASSERT(reader != NULL);
intptr_t len = reader->ReadSmiValue();
intptr_t hash = reader->ReadSmiValue();
String& str_obj = String::ZoneHandle(reader->zone(), String::null());
if (kind == Snapshot::kFull) {
// We currently only expect the Dart mutator to read snapshots.
reader->isolate()->AssertCurrentThreadIsMutator();
ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0);
RawOneByteString* obj = reader->NewOneByteString(len);
str_obj = obj;
if (RawObject::IsCanonical(tags)) {
str_obj.SetCanonical();
}
str_obj.SetHash(hash);
if (len > 0) {
uint8_t* raw_ptr = CharAddr(str_obj, 0);
reader->ReadBytes(raw_ptr, len);
}
ASSERT((hash == 0) || (String::Hash(str_obj, 0, str_obj.Length()) == hash));
} else {
String::ReadFromImpl<OneByteString, uint8_t>(
reader, &str_obj, len, tags, Symbols::FromLatin1, kind);
}
reader->AddBackRef(object_id, &str_obj, kIsDeserialized);
return raw(str_obj);
}
RawTwoByteString* TwoByteString::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
// Read the length so that we can determine instance size to allocate.
ASSERT(reader != NULL);
intptr_t len = reader->ReadSmiValue();
intptr_t hash = reader->ReadSmiValue();
String& str_obj = String::ZoneHandle(reader->zone(), String::null());
if (kind == Snapshot::kFull) {
RawTwoByteString* obj = reader->NewTwoByteString(len);
str_obj = obj;
if (RawObject::IsCanonical(tags)) {
str_obj.SetCanonical();
}
str_obj.SetHash(hash);
NoSafepointScope no_safepoint;
uint16_t* raw_ptr = (len > 0)? CharAddr(str_obj, 0) : NULL;
for (intptr_t i = 0; i < len; i++) {
ASSERT(CharAddr(str_obj, i) == raw_ptr); // Will trigger assertions.
*raw_ptr = reader->Read<uint16_t>();
raw_ptr += 1;
}
ASSERT(String::Hash(str_obj, 0, str_obj.Length()) == hash);
} else {
String::ReadFromImpl<TwoByteString, uint16_t>(
reader, &str_obj, len, tags, Symbols::FromUTF16, kind);
}
reader->AddBackRef(object_id, &str_obj, kIsDeserialized);
return raw(str_obj);
}
template<typename T>
static void StringWriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
intptr_t class_id,
intptr_t tags,
RawSmi* length,
RawSmi* hash,
T* data) {
ASSERT(writer != NULL);
intptr_t len = Smi::Value(length);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(class_id);
writer->WriteTags(tags);
// Write out the length field.
writer->Write<RawObject*>(length);
// Write out the hash field.
writer->Write<RawObject*>(hash);
// Write out the string.
if (len > 0) {
if (class_id == kOneByteStringCid) {
writer->WriteBytes(reinterpret_cast<const uint8_t*>(data), len);
} else {
for (intptr_t i = 0; i < len; i++) {
writer->Write(data[i]);
}
}
}
}
void RawOneByteString::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
StringWriteTo(writer,
object_id,
kind,
kOneByteStringCid,
writer->GetObjectTags(this),
ptr()->length_,
ptr()->hash_,
ptr()->data());
}
void RawTwoByteString::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
StringWriteTo(writer,
object_id,
kind,
kTwoByteStringCid,
writer->GetObjectTags(this),
ptr()->length_,
ptr()->hash_,
ptr()->data());
}
RawExternalOneByteString* ExternalOneByteString::ReadFrom(
SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return ExternalOneByteString::null();
}
RawExternalTwoByteString* ExternalTwoByteString::ReadFrom(
SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return ExternalTwoByteString::null();
}
void RawExternalOneByteString::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
// Serialize as a non-external one byte string.
StringWriteTo(writer,
object_id,
kind,
kOneByteStringCid,
writer->GetObjectTags(this),
ptr()->length_,
ptr()->hash_,
ptr()->external_data_->data());
}
void RawExternalTwoByteString::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
// Serialize as a non-external two byte string.
StringWriteTo(writer,
object_id,
kind,
kTwoByteStringCid,
writer->GetObjectTags(this),
ptr()->length_,
ptr()->hash_,
ptr()->external_data_->data());
}
RawBool* Bool::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Bool::null();
}
void RawBool::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawArray* Array::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Read the length so that we can determine instance size to allocate.
intptr_t len = reader->ReadSmiValue();
Array* array = reinterpret_cast<Array*>(
reader->GetBackRef(object_id));
if (array == NULL) {
array = &(Array::ZoneHandle(reader->zone(),
NEW_OBJECT_WITH_LEN_SPACE(Array, len, kind)));
reader->AddBackRef(object_id, array, kIsDeserialized);
}
ASSERT(!RawObject::IsCanonical(tags));
reader->ArrayReadFrom(object_id, *array, len, tags);
return array->raw();
}
RawImmutableArray* ImmutableArray::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Read the length so that we can determine instance size to allocate.
intptr_t len = reader->ReadSmiValue();
Array* array = reinterpret_cast<Array*>(reader->GetBackRef(object_id));
if (array == NULL) {
array = &(Array::ZoneHandle(
reader->zone(),
NEW_OBJECT_WITH_LEN_SPACE(ImmutableArray, len, kind)));
reader->AddBackRef(object_id, array, kIsDeserialized);
}
reader->ArrayReadFrom(object_id, *array, len, tags);
if (RawObject::IsCanonical(tags)) {
if (kind == Snapshot::kFull) {
array->SetCanonical();
} else {
*array ^= array->CheckAndCanonicalize(NULL);
}
}
return raw(*array);
}
void RawArray::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(!this->IsCanonical());
writer->ArrayWriteTo(object_id,
kArrayCid,
writer->GetObjectTags(this),
ptr()->length_,
ptr()->type_arguments_,
ptr()->data(),
as_reference);
}
void RawImmutableArray::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
writer->ArrayWriteTo(object_id,
kImmutableArrayCid,
writer->GetObjectTags(this),
ptr()->length_,
ptr()->type_arguments_,
ptr()->data(),
as_reference);
}
RawGrowableObjectArray* GrowableObjectArray::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Read the length so that we can determine instance size to allocate.
GrowableObjectArray& array = GrowableObjectArray::ZoneHandle(
reader->zone(), GrowableObjectArray::null());
if (kind == Snapshot::kFull) {
array = reader->NewGrowableObjectArray();
} else {
array = GrowableObjectArray::New(0, HEAP_SPACE(kind));
}
reader->AddBackRef(object_id, &array, kIsDeserialized);
// Read type arguments of growable array object.
const intptr_t typeargs_offset =
GrowableObjectArray::type_arguments_offset() / kWordSize;
*reader->TypeArgumentsHandle() ^=
reader->ReadObjectImpl(kAsInlinedObject, object_id, typeargs_offset);
array.StorePointer(&array.raw_ptr()->type_arguments_,
reader->TypeArgumentsHandle()->raw());
// Read length of growable array object.
array.SetLength(reader->ReadSmiValue());
// Read the backing array of growable array object.
*(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsReference);
array.SetData(*(reader->ArrayHandle()));
return array.raw();
}
void RawGrowableObjectArray::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kGrowableObjectArrayCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the type arguments field.
writer->WriteObjectImpl(ptr()->type_arguments_, kAsInlinedObject);
// Write out the used length field.
writer->Write<RawObject*>(ptr()->length_);
// Write out the Array object.
writer->WriteObjectImpl(ptr()->data_, kAsReference);
}
RawLinkedHashMap* LinkedHashMap::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
LinkedHashMap& map = LinkedHashMap::ZoneHandle(
reader->zone(), LinkedHashMap::null());
if ((kind == Snapshot::kFull && !reader->snapshot_code()) ||
kind == Snapshot::kScript) {
// The immutable maps that seed map literals are not yet VM-internal, so
// we don't reach this.
UNREACHABLE();
} else {
// Since the map might contain itself as a key or value, allocate first.
if (kind == Snapshot::kFull) {
map = reader->NewLinkedHashMap();
} else {
map = LinkedHashMap::NewUninitialized(HEAP_SPACE(kind));
}
}
reader->AddBackRef(object_id, &map, kIsDeserialized);
// Read the type arguments.
const intptr_t typeargs_offset =
GrowableObjectArray::type_arguments_offset() / kWordSize;
*reader->TypeArgumentsHandle() ^=
reader->ReadObjectImpl(kAsInlinedObject, object_id, typeargs_offset);
map.SetTypeArguments(*reader->TypeArgumentsHandle());
// Read the number of key/value pairs.
intptr_t len = reader->ReadSmiValue();
intptr_t used_data = (len << 1);
map.SetUsedData(used_data);
// Allocate the data array.
intptr_t data_size = Utils::Maximum(
Utils::RoundUpToPowerOfTwo(used_data),
static_cast<uintptr_t>(LinkedHashMap::kInitialIndexSize));
Array& data = Array::ZoneHandle(reader->zone(),
NEW_OBJECT_WITH_LEN_SPACE(Array,
data_size,
kind));
map.SetData(data);
map.SetDeletedKeys(0);
// The index and hashMask is regenerated by the maps themselves on demand.
// Thus, the index will probably be allocated in new space (unless it's huge).
// TODO(koda): Eagerly rehash here when no keys have user-defined '==', and
// in particular, if/when (const) maps are needed in the VM isolate snapshot.
ASSERT(reader->isolate() != Dart::vm_isolate());
map.SetHashMask(0); // Prefer sentinel 0 over null for better type feedback.
// Read the keys and values.
bool read_as_reference = RawObject::IsCanonical(tags) ? false : true;
for (intptr_t i = 0; i < used_data; i++) {
*reader->PassiveObjectHandle() = reader->ReadObjectImpl(read_as_reference);
data.SetAt(i, *reader->PassiveObjectHandle());
}
return map.raw();
}
void RawLinkedHashMap::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
if ((kind == Snapshot::kFull && !writer->snapshot_code()) ||
kind == Snapshot::kScript) {
// The immutable maps that seed map literals are not yet VM-internal, so
// we don't reach this.
}
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kLinkedHashMapCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the type arguments.
writer->WriteObjectImpl(ptr()->type_arguments_, kAsInlinedObject);
const intptr_t used_data = Smi::Value(ptr()->used_data_);
ASSERT((used_data & 1) == 0); // Keys + values, so must be even.
const intptr_t deleted_keys = Smi::Value(ptr()->deleted_keys_);
// Write out the number of (not deleted) key/value pairs that will follow.
writer->Write<RawObject*>(Smi::New((used_data >> 1) - deleted_keys));
// Write out the keys and values.
const bool write_as_reference = this->IsCanonical() ? false : true;
RawArray* data_array = ptr()->data_;
RawObject** data_elements = data_array->ptr()->data();
ASSERT(used_data <= Smi::Value(data_array->ptr()->length_));
#if defined(DEBUG)
intptr_t deleted_keys_found = 0;
#endif // DEBUG
for (intptr_t i = 0; i < used_data; i += 2) {
RawObject* key = data_elements[i];
if (key == data_array) {
#if defined(DEBUG)
++deleted_keys_found;
#endif // DEBUG
continue;
}
RawObject* value = data_elements[i + 1];
writer->WriteObjectImpl(key, write_as_reference);
writer->WriteObjectImpl(value, write_as_reference);
}
DEBUG_ASSERT(deleted_keys_found == deleted_keys);
}
RawFloat32x4* Float32x4::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Read the values.
float value0 = reader->Read<float>();
float value1 = reader->Read<float>();
float value2 = reader->Read<float>();
float value3 = reader->Read<float>();
// Create a Float32x4 object.
Float32x4& simd = Float32x4::ZoneHandle(reader->zone(),
Float32x4::null());
if (kind == Snapshot::kFull) {
simd = reader->NewFloat32x4(value0, value1, value2, value3);
} else {
simd = Float32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind));
}
reader->AddBackRef(object_id, &simd, kIsDeserialized);
return simd.raw();
}
void RawFloat32x4::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kFloat32x4Cid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the float values.
writer->Write<float>(ptr()->value_[0]);
writer->Write<float>(ptr()->value_[1]);
writer->Write<float>(ptr()->value_[2]);
writer->Write<float>(ptr()->value_[3]);
}
RawInt32x4* Int32x4::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Read the values.
uint32_t value0 = reader->Read<uint32_t>();
uint32_t value1 = reader->Read<uint32_t>();
uint32_t value2 = reader->Read<uint32_t>();
uint32_t value3 = reader->Read<uint32_t>();
// Create a Float32x4 object.
Int32x4& simd = Int32x4::ZoneHandle(reader->zone(), Int32x4::null());
if (kind == Snapshot::kFull) {
simd = reader->NewInt32x4(value0, value1, value2, value3);
} else {
simd = Int32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind));
}
reader->AddBackRef(object_id, &simd, kIsDeserialized);
return simd.raw();
}
void RawInt32x4::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteIndexedObject(kInt32x4Cid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the mask values.
writer->Write<uint32_t>(ptr()->value_[0]);
writer->Write<uint32_t>(ptr()->value_[1]);
writer->Write<uint32_t>(ptr()->value_[2]);
writer->Write<uint32_t>(ptr()->value_[3]);
<