blob: f743ea678b3e4ed3b9867940b8ca998d298c86a9 [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/message.h"
#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/type_testing_stubs.h"
#include "vm/visitor.h"
namespace dart {
// TODO(dartbug.com/34796): enable or remove this optimization.
DEFINE_FLAG(
uint64_t,
externalize_typed_data_threshold,
kMaxUint64,
"Convert TypedData to ExternalTypedData when sending through a message"
" port after it exceeds certain size in bytes.");
#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); \
for (intptr_t i = 0; i <= num_flds; i++) { \
(*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(as_reference); \
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());
cls ^= reader->ReadClassId(object_id);
return cls.raw();
}
void RawClass::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(kClassCid);
writer->WriteTags(writer->GetObjectTags(this));
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)");
}
}
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.
reader->Read<bool>();
// Allocate type object.
Type& type = Type::ZoneHandle(reader->zone(), Type::New());
bool is_canonical = RawObject::IsCanonical(tags);
reader->AddBackRef(object_id, &type, kIsDeserialized);
// Set all non object fields.
type.set_token_pos(TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
type.set_type_state(reader->Read<int8_t>());
// Read the code object for the type testing stub and set its entrypoint.
reader->EnqueueTypePostprocessing(type);
// Set all the object fields.
READ_OBJECT_FIELDS(type, type.raw()->from(), type.raw()->to(), as_reference);
// Read in the type class.
(*reader->ClassHandle()) =
Class::RawCast(reader->ReadObjectImpl(as_reference));
type.set_type_class(*reader->ClassHandle());
if (is_canonical) {
type ^= type.Canonicalize();
}
// Fill in the type testing stub.
Code& code = *reader->CodeHandle();
code = TypeTestingStubGenerator::DefaultCodeForType(type);
type.SetTypeTestingStub(code);
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_id_ != 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));
if (ptr()->type_class_id_->IsHeapObject()) {
// Type class is still an unresolved class.
UNREACHABLE();
}
// Lookup the type class.
RawSmi* raw_type_class_id = Smi::RawCast(ptr()->type_class_id_);
RawClass* type_class =
writer->isolate()->class_table()->At(Smi::Value(raw_type_class_id));
// 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(type_class);
bool typeclass_is_in_fullsnapshot =
(ClassIdTag::decode(tags) == kClassCid) &&
Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(type_class));
writer->Write<bool>(typeclass_is_in_fullsnapshot);
// Write out all the non object pointer fields.
writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
writer->Write<int8_t>(ptr()->type_state_);
// Write out all the object pointer fields.
ASSERT(ptr()->type_class_id_ != Object::null());
SnapshotWriterVisitor visitor(writer, as_reference);
visitor.VisitPointers(from(), to());
// Write out the type class.
writer->WriteObjectImpl(type_class, as_reference);
}
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(), TypeRef::New());
reader->AddBackRef(object_id, &type_ref, kIsDeserialized);
// Read the code object for the type testing stub and set its entrypoint.
reader->EnqueueTypePostprocessing(type_ref);
// Set all the object fields.
READ_OBJECT_FIELDS(type_ref, type_ref.raw()->from(), type_ref.raw()->to(),
kAsReference);
// Fill in the type testing stub.
Code& code = *reader->CodeHandle();
code = TypeTestingStubGenerator::DefaultCodeForType(type_ref);
type_ref.SetTypeTestingStub(code);
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(), TypeParameter::New());
reader->AddBackRef(object_id, &type_parameter, kIsDeserialized);
// Set all non object fields.
type_parameter.set_token_pos(
TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
type_parameter.set_index(reader->Read<int16_t>());
type_parameter.set_flags(reader->Read<uint8_t>());
// Read the code object for the type testing stub and set its entrypoint.
reader->EnqueueTypePostprocessing(type_parameter);
// Set all the object fields.
READ_OBJECT_FIELDS(type_parameter, type_parameter.raw()->from(),
type_parameter.raw()->to(), kAsReference);
// Read in the parameterized class.
(*reader->ClassHandle()) =
Class::RawCast(reader->ReadObjectImpl(kAsReference));
type_parameter.set_parameterized_class(*reader->ClassHandle());
// Fill in the type testing stub.
Code& code = *reader->CodeHandle();
code = TypeTestingStubGenerator::DefaultCodeForType(type_parameter);
type_parameter.SetTypeTestingStub(code);
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(FinalizedBit::decode(ptr()->flags_));
// 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_.SnapshotEncode());
writer->Write<int16_t>(ptr()->index_);
writer->Write<uint8_t>(ptr()->flags_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
// Write out the parameterized class.
RawClass* param_class =
writer->isolate()->class_table()->At(ptr()->parameterized_class_id_);
writer->WriteObjectImpl(param_class, kAsReference);
}
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(), TypeArguments::New(len));
bool is_canonical = RawObject::IsCanonical(tags);
reader->AddBackRef(object_id, &type_arguments, kIsDeserialized);
// Set the instantiations field, which is only read from a full snapshot.
type_arguments.set_instantiations(Object::zero_array());
// Now set all the type fields.
for (intptr_t i = 0; i < len; i++) {
*reader->TypeHandle() ^= reader->ReadObjectImpl(as_reference);
type_arguments.SetTypeAt(i, *reader->TypeHandle());
}
// Set the canonical bit.
if (is_canonical) {
type_arguments ^= type_arguments.Canonicalize();
}
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 individual types.
intptr_t len = Smi::Value(ptr()->length_);
for (intptr_t i = 0; i < len; i++) {
// The Dart VM reuses type argument lists across instances in order
// to reduce memory footprint, this can sometimes lead to a type from
// such a shared type argument list being sent over to another isolate.
// In such scenarios where it is not appropriate to send the types
// across (isolates spawned using spawnURI) we send them as dynamic.
if (!writer->can_send_any_object()) {
// Lookup the type class.
RawType* raw_type = Type::RawCast(ptr()->types()[i]);
RawSmi* raw_type_class_id = Smi::RawCast(raw_type->ptr()->type_class_id_);
RawClass* type_class =
writer->isolate()->class_table()->At(Smi::Value(raw_type_class_id));
if (!writer->AllowObjectsInDartLibrary(type_class->ptr()->library_)) {
writer->WriteVMIsolateObject(kDynamicType);
} else {
writer->WriteObjectImpl(ptr()->types()[i], as_reference);
}
} else {
writer->WriteObjectImpl(ptr()->types()[i], as_reference);
}
}
}
RawPatchClass* PatchClass::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return PatchClass::null();
}
void RawPatchClass::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawClosure* Closure::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Closure::null();
}
void RawClosure::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
ASSERT(kind == Snapshot::kMessage);
// Check if closure is serializable, throw an exception otherwise.
RawFunction* func = writer->IsSerializableClosure(this);
if (func != Function::null()) {
writer->WriteStaticImplicitClosure(object_id, func,
writer->GetObjectTags(this));
return;
}
UNREACHABLE();
}
RawClosureData* ClosureData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return ClosureData::null();
}
void RawClosureData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawSignatureData* SignatureData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return SignatureData::null();
}
void RawSignatureData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawRedirectionData* RedirectionData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return RedirectionData::null();
}
void RawRedirectionData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawFfiTrampolineData* FfiTrampolineData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return FfiTrampolineData::null();
}
void RawFfiTrampolineData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawFunction* Function::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Function::null();
}
void RawFunction::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawField* Field::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Field::null();
}
void RawField::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawScript* Script::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Script::null();
}
void RawScript::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawLibrary* Library::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Library::null();
}
void RawLibrary::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawLibraryPrefix* LibraryPrefix::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return LibraryPrefix::null();
}
void RawLibraryPrefix::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawNamespace* Namespace::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Namespace::null();
}
void RawNamespace::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawKernelProgramInfo* KernelProgramInfo::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return KernelProgramInfo::null();
}
void RawKernelProgramInfo::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawCode* Code::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Code::null();
}
void RawCode::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawBytecode* Bytecode::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Bytecode::null();
}
void RawBytecode::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawInstructions* Instructions::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return Instructions::null();
}
void RawInstructions::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawObjectPool* ObjectPool::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return ObjectPool::null();
}
void RawObjectPool::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawPcDescriptors* PcDescriptors::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return PcDescriptors::null();
}
void RawPcDescriptors::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawCodeSourceMap* CodeSourceMap::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return CodeSourceMap::null();
}
void RawCodeSourceMap::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawStackMap* StackMap::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return StackMap::null();
}
void RawStackMap::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawLocalVarDescriptors* LocalVarDescriptors::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return LocalVarDescriptors::null();
}
void RawLocalVarDescriptors::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawExceptionHandlers* ExceptionHandlers::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return ExceptionHandlers::null();
}
void RawExceptionHandlers::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
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 ^= Context::New(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(reader->zone());
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, TokenPosition::kMinSource);
context_scope.SetDeclarationTokenIndexAt(0, TokenPosition::kMinSource);
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();
}
RawSingleTargetCache* SingleTargetCache::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return SingleTargetCache::null();
}
void RawSingleTargetCache::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawUnlinkedCall* UnlinkedCall::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return UnlinkedCall::null();
}
void RawUnlinkedCall::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawICData* ICData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return ICData::null();
}
void RawICData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawMegamorphicCache* MegamorphicCache::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return MegamorphicCache::null();
}
void RawMegamorphicCache::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
RawSubtypeTestCache* SubtypeTestCache::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return SubtypeTestCache::null();
}
void RawSubtypeTestCache::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
}
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(), ApiError::New());
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(), LanguageError::New());
reader->AddBackRef(object_id, &language_error, kIsDeserialized);
// Set all non object fields.
language_error.set_token_pos(
TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
language_error.set_report_after_token(reader->Read<bool>());
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_.SnapshotEncode());
writer->Write<bool>(ptr()->report_after_token_);
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(), UnhandledException::New());
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());
obj ^= Object::Allocate(kInstanceCid, Instance::InstanceSize(), Heap::kNew);
if (RawObject::IsCanonical(tags)) {
const char* error_str = NULL;
obj = obj.CheckAndCanonicalize(reader->thread(), &error_str);
if (error_str != NULL) {
FATAL1("Failed to canonicalize: %s", error_str);
}
}
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());
// 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);
}
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_);
}
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());
// 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);
}
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)(reader->thread(), ptr, len);
} else {
// Set up the string object.
*str_obj = StringType::New(len, Heap::kNew);
str_obj->SetHash(0); // Will get computed when needed.
if (len == 0) {
return;
}
NoSafepointScope no_safepoint;
CharacterType* str_addr = StringType::DataStart(*str_obj);
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();
String& str_obj = String::ZoneHandle(reader->zone(), String::null());
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();
String& str_obj = String::ZoneHandle(reader->zone(), String::null());
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,
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 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()->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()->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()->external_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()->external_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 = NULL;
DeserializeState state;
if (!as_reference) {
array = reinterpret_cast<Array*>(reader->GetBackRef(object_id));
state = kIsDeserialized;
} else {
state = kIsNotDeserialized;
}
if (array == NULL) {
array = &(Array::ZoneHandle(reader->zone(), Array::New(len)));
reader->AddBackRef(object_id, array, state);
}
if (!as_reference) {
// Read all the individual elements for inlined objects.
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 = NULL;
DeserializeState state;
if (!as_reference) {
array = reinterpret_cast<Array*>(reader->GetBackRef(object_id));
state = kIsDeserialized;
} else {
state = kIsNotDeserialized;
}
if (array == NULL) {
array = &(Array::ZoneHandle(reader->zone(), ImmutableArray::New(len)));
reader->AddBackRef(object_id, array, state);
}
if (!as_reference) {
// Read all the individual elements for inlined objects.
reader->ArrayReadFrom(object_id, *array, len, tags);
if (RawObject::IsCanonical(tags)) {
const char* error_str = NULL;
*array ^= array->CheckAndCanonicalize(reader->thread(), &error_str);
if (error_str != NULL) {
FATAL1("Failed to canonicalize: %s", error_str);
}
}
}
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());
array = GrowableObjectArray::New(0);
reader->AddBackRef(object_id, &array, kIsDeserialized);
// Read type arguments of growable array object.
*reader->TypeArgumentsHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
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());
// Since the map might contain itself as a key or value, allocate first.
map = LinkedHashMap::NewUninitialized();
reader->AddBackRef(object_id, &map, kIsDeserialized);
// Read the type arguments.
*reader->TypeArgumentsHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
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(), Array::New(data_size));
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.
reader->EnqueueRehashingOfMap(map);
// 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) {
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());
simd = Float32x4::New(value0, value1, value2, value3);
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());
simd = Int32x4::New(value0, value1, value2, value3);
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]);
}
RawFloat64x2* Float64x2::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Read the values.
double value0 = reader->Read<double>();
double value1 = reader->Read<double>();
// Create a Float64x2 object.
Float64x2& simd = Float64x2::ZoneHandle(reader->zone(), Float64x2::null());
simd = Float64x2::New(value0, value1);
reader->AddBackRef(object_id, &simd, kIsDeserialized);
return simd.raw();
}
void RawFloat64x2::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(kFloat64x2Cid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out the float values.
writer->Write<double>(ptr()->value_[0]);
writer->Write<double>(ptr()->value_[1]);
}
RawTypedData* TypedData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
intptr_t cid = RawObject::ClassIdTag::decode(tags);
intptr_t len = reader->ReadSmiValue();
TypedData& result =
TypedData::ZoneHandle(reader->zone(), TypedData::New(cid, len));
reader->AddBackRef(object_id, &result, kIsDeserialized);
// Setup the array elements.
intptr_t element_size = ElementSizeInBytes(cid);
intptr_t length_in_bytes = len * element_size;
NoSafepointScope no_safepoint;
uint8_t* data = reinterpret_cast<uint8_t*>(result.DataAddr(0));
reader->ReadBytes(data, length_in_bytes);
// 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)) {
const char* error_str = NULL;
result ^= result.CheckAndCanonicalize(reader->thread(), &error_str);
if (error_str != NULL) {
FATAL1("Failed to canonicalize: %s", error_str);
}
ASSERT(!result.IsNull());
ASSERT(result.IsCanonical());
}
return result.raw();
}
RawExternalTypedData* ExternalTypedData::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(!Snapshot::IsFull(kind));
intptr_t cid = RawObject::ClassIdTag::decode(tags);
intptr_t length = reader->ReadSmiValue();
FinalizableData finalizable_data =
static_cast<MessageSnapshotReader*>(reader)->finalizable_data()->Take();
uint8_t* data = reinterpret_cast<uint8_t*>(finalizable_data.data);
ExternalTypedData& obj =
ExternalTypedData::ZoneHandle(ExternalTypedData::New(cid, data, length));
reader->AddBackRef(object_id, &obj, kIsDeserialized);
intptr_t external_size = obj.LengthInBytes();
obj.AddFinalizer(finalizable_data.peer, finalizable_data.callback,
external_size);
return obj.raw();
}
// This function's name can appear in Observatory.
static void IsolateMessageTypedDataFinalizer(void* isolate_callback_data,
Dart_WeakPersistentHandle handle,
void* buffer) {
free(buffer);
}
void RawTypedData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
intptr_t cid = this->GetClassId();
intptr_t length = Smi::Value(ptr()->length_); // In elements.
intptr_t external_cid;
intptr_t bytes;
switch (cid) {
case kTypedDataInt8ArrayCid:
external_cid = kExternalTypedDataInt8ArrayCid;
bytes = length * sizeof(int8_t);
break;
case kTypedDataUint8ArrayCid:
external_cid = kExternalTypedDataUint8ArrayCid;
bytes = length * sizeof(uint8_t);
break;
case kTypedDataUint8ClampedArrayCid:
external_cid = kExternalTypedDataUint8ClampedArrayCid;
bytes = length * sizeof(uint8_t);
break;
case kTypedDataInt16ArrayCid:
external_cid = kExternalTypedDataInt16ArrayCid;
bytes = length * sizeof(int16_t);
break;
case kTypedDataUint16ArrayCid:
external_cid = kExternalTypedDataUint16ArrayCid;
bytes = length * sizeof(uint16_t);
break;
case kTypedDataInt32ArrayCid:
external_cid = kExternalTypedDataInt32ArrayCid;
bytes = length * sizeof(int32_t);
break;
case kTypedDataUint32ArrayCid:
external_cid = kExternalTypedDataUint32ArrayCid;
bytes = length * sizeof(uint32_t);
break;
case kTypedDataInt64ArrayCid:
external_cid = kExternalTypedDataInt64ArrayCid;
bytes = length * sizeof(int64_t);
break;
case kTypedDataUint64ArrayCid:
external_cid = kExternalTypedDataUint64ArrayCid;
bytes = length * sizeof(uint64_t);
break;
case kTypedDataFloat32ArrayCid:
external_cid = kExternalTypedDataFloat32ArrayCid;
bytes = length * sizeof(float);
break;
case kTypedDataFloat64ArrayCid:
external_cid = kExternalTypedDataFloat64ArrayCid;
bytes = length * sizeof(double);
break;
case kTypedDataInt32x4ArrayCid:
external_cid = kExternalTypedDataInt32x4ArrayCid;
bytes = length * sizeof(int32_t) * 4;
break;
case kTypedDataFloat32x4ArrayCid:
external_cid = kExternalTypedDataFloat32x4ArrayCid;
bytes = length * sizeof(float) * 4;
break;
case kTypedDataFloat64x2ArrayCid:
external_cid = kExternalTypedDataFloat64x2ArrayCid;
bytes = length * sizeof(double) * 2;
break;
default:
external_cid = kIllegalCid;
bytes = 0;
UNREACHABLE();
}
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
if ((kind == Snapshot::kMessage) &&
(static_cast<uint64_t>(bytes) >= FLAG_externalize_typed_data_threshold)) {
// Write as external.
writer->WriteIndexedObject(external_cid);
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<RawObject*>(ptr()->length_);
uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
void* passed_data = malloc(bytes);
if (passed_data == NULL) {
OUT_OF_MEMORY();
}
memmove(passed_data, data, bytes);
static_cast<MessageWriter*>(writer)->finalizable_data()->Put(
bytes,
passed_data, // data
passed_data, // peer,
IsolateMessageTypedDataFinalizer);
} else {
// Write as internal.
writer->WriteIndexedObject(cid);
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<RawObject*>(ptr()->length_);
uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
writer->WriteBytes(data, bytes);
}
}
void RawExternalTypedData::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
intptr_t cid = this->GetClassId();
intptr_t length = Smi::Value(ptr()->length_); // In elements.
intptr_t bytes;
switch (cid) {
case kExternalTypedDataInt8ArrayCid:
bytes = length * sizeof(int8_t);
break;
case kExternalTypedDataUint8ArrayCid:
bytes = length * sizeof(uint8_t);
break;
case kExternalTypedDataUint8ClampedArrayCid:
bytes = length * sizeof(uint8_t);
break;
case kExternalTypedDataInt16ArrayCid:
bytes = length * sizeof(int16_t);
break;
case kExternalTypedDataUint16ArrayCid:
bytes = length * sizeof(uint16_t);
break;
case kExternalTypedDataInt32ArrayCid:
bytes = length * sizeof(int32_t);
break;
case kExternalTypedDataUint32ArrayCid:
bytes = length * sizeof(uint32_t);
break;
case kExternalTypedDataInt64ArrayCid:
bytes = length * sizeof(int64_t);
break;
case kExternalTypedDataUint64ArrayCid:
bytes = length * sizeof(uint64_t);
break;
case kExternalTypedDataFloat32ArrayCid:
bytes = length * sizeof(float); // NOLINT.
break;
case kExternalTypedDataFloat64ArrayCid:
bytes = length * sizeof(double); // NOLINT.
break;
case kExternalTypedDataInt32x4ArrayCid:
bytes = length * sizeof(int32_t) * 4;
break;
case kExternalTypedDataFloat32x4ArrayCid:
bytes = length * sizeof(float) * 4;
break;
case kExternalTypedDataFloat64x2ArrayCid:
bytes = length * sizeof(double) * 2;
break;
default:
bytes = 0;
UNREACHABLE();
}
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write as external.
writer->WriteIndexedObject(cid);
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<RawObject*>(ptr()->length_);
uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data_);
void* passed_data = malloc(bytes);
if (passed_data == NULL) {
OUT_OF_MEMORY();
}
memmove(passed_data, data, bytes);
static_cast<MessageWriter*>(writer)->finalizable_data()->Put(
bytes,
passed_data, // data
passed_data, // peer,
IsolateMessageTypedDataFinalizer);
}
RawPointer* Pointer::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
FATAL("Snapshotting Pointers is not supported");
UNREACHABLE();
}
void RawPointer::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
FATAL("Snapshotting Pointers is not supported");
}
RawDynamicLibrary* DynamicLibrary::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
FATAL("Snapshotting DynamicLibraries is not supported");
UNREACHABLE();
}
void RawDynamicLibrary::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
FATAL("Snapshotting DynamicLibraries is not supported");
}
RawCapability* Capability::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
uint64_t id = reader->Read<uint64_t>();
Capability& result =
Capability::ZoneHandle(reader->zone(), Capability::New(id));
reader->AddBackRef(object_id, &result, kIsDeserialized);
return result.raw();
}
void RawCapability::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->WriteIndexedObject(kCapabilityCid);
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<uint64_t>(ptr()->id_);
}
RawReceivePort* ReceivePort::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return ReceivePort::null();
}
void RawReceivePort::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
if (kind == Snapshot::kMessage) {
// We do not allow objects with native fields in an isolate message.
writer->SetWriteException(Exceptions::kArgument,
"Illegal argument in isolate message"
" : (object is a RawReceivePort)");
} else {
UNREACHABLE();
}
}
RawSendPort* SendPort::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(kind == Snapshot::kMessage);
uint64_t id = reader->Read<uint64_t>();
uint64_t origin_id = reader->Read<uint64_t>();
SendPort& result =
SendPort::ZoneHandle(reader->zone(), SendPort::New(id, origin_id));
reader->AddBackRef(object_id, &result, kIsDeserialized);
return result.raw();
}
void RawSendPort::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->WriteIndexedObject(kSendPortCid);
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<uint64_t>(ptr()->id_);
writer->Write<uint64_t>(ptr()->origin_id_);
}
RawStackTrace* StackTrace::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE(); // StackTraces are not sent in a snapshot.
return StackTrace::null();
}
void RawStackTrace::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(kind == Snapshot::kMessage);
writer->SetWriteException(Exceptions::kArgument,
"Illegal argument in isolate message"
" : (object is a stacktrace)");
}
RawRegExp* RegExp::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate RegExp object.
RegExp& regex = RegExp::ZoneHandle(reader->zone(), RegExp::New());
reader->AddBackRef(object_id, &regex, kIsDeserialized);
// Read and Set all the other fields.
regex.StoreSmi(&regex.raw_ptr()->num_bracket_expressions_,
reader->ReadAsSmi());
*reader->StringHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
regex.set_pattern(*reader->StringHandle());
regex.StoreNonPointer(&regex.raw_ptr()->num_registers_,
reader->Read<int32_t>());
regex.StoreNonPointer(&regex.raw_ptr()->type_flags_, reader->Read<int8_t>());
const Function& no_function = Function::Handle(reader->zone());
for (intptr_t cid = kOneByteStringCid; cid <= kExternalTwoByteStringCid;
cid++) {
regex.set_function(cid, /*sticky=*/false, no_function);
regex.set_function(cid, /*sticky=*/true, no_function);
}
return regex.raw();
}
void RawRegExp::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(kRegExpCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the other fields.
writer->Write<RawObject*>(ptr()->num_bracket_expressions_);
writer->WriteObjectImpl(ptr()->pattern_, kAsInlinedObject);
writer->Write<int32_t>(ptr()->num_registers_);
writer->Write<int8_t>(ptr()->type_flags_);
}
RawWeakProperty* WeakProperty::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
// Allocate the weak property object.
WeakProperty& weak_property =
WeakProperty::ZoneHandle(reader->zone(), WeakProperty::New());
reader->AddBackRef(object_id, &weak_property, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(weak_property, weak_property.raw()->from(),
weak_property.raw()->to(), kAsReference);
return weak_property.raw();
}
void RawWeakProperty::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(kWeakPropertyCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
}
RawMirrorReference* MirrorReference::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_referenec) {
UNREACHABLE();
return MirrorReference::null();
}
void RawMirrorReference::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
if (kind == Snapshot::kMessage) {
// We do not allow objects with native fields in an isolate message.
writer->SetWriteException(Exceptions::kArgument,
"Illegal argument in isolate message"
" : (object is a MirrorReference)");
} else {
UNREACHABLE();
}
}
RawUserTag* UserTag::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
UNREACHABLE();
return UserTag::null();
}
void RawUserTag::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
if (kind == Snapshot::kMessage) {
// We do not allow objects with native fields in an isolate message.
writer->SetWriteException(Exceptions::kArgument,
"Illegal argument in isolate message"
" : (object is a UserTag)");
} else {
UNREACHABLE();
}
}
} // namespace dart