blob: d21fe69ae309ab7223e814a7fde31fffb27379e1 [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.
#ifndef VM_SNAPSHOT_H_
#define VM_SNAPSHOT_H_
#include "platform/assert.h"
#include "vm/allocation.h"
#include "vm/bitfield.h"
#include "vm/datastream.h"
#include "vm/exceptions.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
#include "vm/isolate.h"
#include "vm/visitor.h"
namespace dart {
// Forward declarations.
class AbstractType;
class AbstractTypeArguments;
class Array;
class Class;
class ClassTable;
class ExternalTypedData;
class GrowableObjectArray;
class Heap;
class LanguageError;
class Library;
class Object;
class ObjectStore;
class RawAbstractTypeArguments;
class RawApiError;
class RawArray;
class RawBigint;
class RawBoundedType;
class RawMixinAppType;
class RawClass;
class RawContext;
class RawDouble;
class RawField;
class RawClosureData;
class RawRedirectionData;
class RawFunction;
class RawGrowableObjectArray;
class RawFloat32x4;
class RawUint32x4;
class RawImmutableArray;
class RawLanguageError;
class RawLibrary;
class RawLibraryPrefix;
class RawNamespace;
class RawLiteralToken;
class RawMint;
class RawObject;
class RawOneByteString;
class RawPatchClass;
class RawScript;
class RawSmi;
class RawStacktrace;
class RawTokenStream;
class RawType;
class RawTypeParameter;
class RawTypeArguments;
class RawTwoByteString;
class RawUnresolvedClass;
class String;
class TokenStream;
class UnhandledException;
// Serialized object header encoding is as follows:
// - Smi: the Smi value is written as is (last bit is not tagged).
// - VM object (from VM isolate): (object id in vm isolate | 0x3)
// This valus is serialized as a negative number.
// (note VM objects are never serialized they are expected to be found
// using ths unique ID assigned to them).
// - Reference to object that has already been written: (object id | 0x3)
// This valus is serialized as a positive number.
// - Object that is seen for the first time (inlined in the stream):
// (a unique id for this object | 0x1)
enum SerializedHeaderType {
kInlined = 0x1,
kObjectId = 0x3,
};
static const int8_t kHeaderTagBits = 2;
static const int8_t kObjectIdBits = (kBitsPerWord - (kHeaderTagBits + 1));
static const intptr_t kMaxObjectId = (kUwordMax >> (kHeaderTagBits + 1));
class SerializedHeaderTag : public BitField<enum SerializedHeaderType,
0,
kHeaderTagBits> {
};
class SerializedHeaderData : public BitField<intptr_t,
kHeaderTagBits,
kObjectIdBits> {
};
enum DeserializeState {
kIsDeserialized = 0,
kIsNotDeserialized = 1,
};
enum SerializeState {
kIsSerialized = 0,
kIsNotSerialized = 1,
};
#define HEAP_SPACE(kind) (kind == Snapshot::kMessage) ? Heap::kNew : Heap::kOld
// Structure capturing the raw snapshot.
//
// TODO(turnidge): Remove this class once the snapshot does not have a
// header anymore. This is pending on making the embedder pass in the
// length of their snapshot.
class Snapshot {
public:
enum Kind {
kFull = 0, // Full snapshot of the current dart heap.
kScript, // A partial snapshot of only the application script.
kMessage, // A partial snapshot used only for isolate messaging.
};
static const int kHeaderSize = 2 * sizeof(int32_t);
static const int kLengthIndex = 0;
static const int kSnapshotFlagIndex = 1;
static const Snapshot* SetupFromBuffer(const void* raw_memory);
// Getters.
const uint8_t* content() const { return content_; }
int32_t length() const { return length_; }
Kind kind() const { return static_cast<Kind>(kind_); }
bool IsMessageSnapshot() const { return kind_ == kMessage; }
bool IsScriptSnapshot() const { return kind_ == kScript; }
bool IsFullSnapshot() const { return kind_ == kFull; }
uint8_t* Addr() { return reinterpret_cast<uint8_t*>(this); }
static intptr_t length_offset() { return OFFSET_OF(Snapshot, length_); }
static intptr_t kind_offset() {
return OFFSET_OF(Snapshot, kind_);
}
private:
Snapshot() : length_(0), kind_(kFull) {}
int32_t length_; // Stream length.
int32_t kind_; // Kind of snapshot.
uint8_t content_[]; // Stream content.
DISALLOW_COPY_AND_ASSIGN(Snapshot);
};
class BaseReader {
public:
BaseReader(const uint8_t* buffer, intptr_t size) : stream_(buffer, size) {}
// Reads raw data (for basic types).
// sizeof(T) must be in {1,2,4,8}.
template <typename T>
T Read() {
return ReadStream::Raw<sizeof(T), T>::Read(&stream_);
}
// Reads an intptr_t type value.
intptr_t ReadIntptrValue() {
int64_t value = Read<int64_t>();
ASSERT((value <= kIntptrMax) && (value >= kIntptrMin));
return static_cast<intptr_t>(value);
}
void ReadBytes(uint8_t* addr, intptr_t len) {
stream_.ReadBytes(addr, len);
}
const uint8_t* CurrentBufferAddress() const {
return stream_.AddressOfCurrentPosition();
}
void Advance(intptr_t value) {
stream_.Advance(value);
}
RawSmi* ReadAsSmi();
intptr_t ReadSmiValue();
// Negative header value indicates VM isolate object id.
bool IsVMIsolateObject(intptr_t header_value) { return (header_value < 0); }
intptr_t GetVMIsolateObjectId(intptr_t header_val) {
ASSERT(IsVMIsolateObject(header_val));
intptr_t value = -header_val; // Header is negative for VM isolate objects.
ASSERT(SerializedHeaderTag::decode(value) == kObjectId);
return SerializedHeaderData::decode(value);
}
private:
ReadStream stream_; // input stream.
};
// Reads a snapshot into objects.
class SnapshotReader : public BaseReader {
public:
SnapshotReader(const uint8_t* buffer,
intptr_t size,
Snapshot::Kind kind,
Isolate* isolate);
~SnapshotReader() { }
Isolate* isolate() const { return isolate_; }
Heap* heap() const { return isolate_->heap(); }
ObjectStore* object_store() const { return isolate_->object_store(); }
ClassTable* class_table() const { return isolate_->class_table(); }
Object* ObjectHandle() { return &obj_; }
String* StringHandle() { return &str_; }
AbstractType* TypeHandle() { return &type_; }
AbstractTypeArguments* TypeArgumentsHandle() { return &type_arguments_; }
Array* TokensHandle() { return &tokens_; }
TokenStream* StreamHandle() { return &stream_; }
ExternalTypedData* DataHandle() { return &data_; }
UnhandledException* ErrorHandle() { return &error_; }
// Reads an object.
RawObject* ReadObject();
// Add object to backward references.
void AddBackRef(intptr_t id, Object* obj, DeserializeState state);
// Get an object from the backward references list.
Object* GetBackRef(intptr_t id);
// Read a full snap shot.
void ReadFullSnapshot();
// Helper functions for creating uninitialized versions
// of various object types. These are used when reading a
// full snapshot.
RawArray* NewArray(intptr_t len);
RawImmutableArray* NewImmutableArray(intptr_t len);
RawOneByteString* NewOneByteString(intptr_t len);
RawTwoByteString* NewTwoByteString(intptr_t len);
RawTypeArguments* NewTypeArguments(intptr_t len);
RawTokenStream* NewTokenStream(intptr_t len);
RawContext* NewContext(intptr_t num_variables);
RawClass* NewClass(intptr_t class_id);
RawMint* NewMint(int64_t value);
RawBigint* NewBigint(const char* hex_string);
RawDouble* NewDouble(double value);
RawUnresolvedClass* NewUnresolvedClass();
RawType* NewType();
RawTypeParameter* NewTypeParameter();
RawBoundedType* NewBoundedType();
RawMixinAppType* NewMixinAppType();
RawPatchClass* NewPatchClass();
RawClosureData* NewClosureData();
RawRedirectionData* NewRedirectionData();
RawFunction* NewFunction();
RawField* NewField();
RawLibrary* NewLibrary();
RawLibraryPrefix* NewLibraryPrefix();
RawNamespace* NewNamespace();
RawScript* NewScript();
RawLiteralToken* NewLiteralToken();
RawGrowableObjectArray* NewGrowableObjectArray();
RawFloat32x4* NewFloat32x4(float v0, float v1, float v2, float v3);
RawUint32x4* NewUint32x4(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3);
RawApiError* NewApiError();
RawLanguageError* NewLanguageError();
RawObject* NewInteger(int64_t value);
RawStacktrace* NewStacktrace();
private:
class BackRefNode : public ZoneAllocated {
public:
BackRefNode(Object* reference, DeserializeState state)
: reference_(reference), state_(state) {}
Object* reference() const { return reference_; }
bool is_deserialized() const { return state_ == kIsDeserialized; }
void set_state(DeserializeState state) { state_ = state; }
private:
Object* reference_;
DeserializeState state_;
DISALLOW_COPY_AND_ASSIGN(BackRefNode);
};
// Allocate uninitialized objects, this is used when reading a full snapshot.
RawObject* AllocateUninitialized(const Class& cls, intptr_t size);
RawClass* ReadClassId(intptr_t object_id);
RawObject* ReadObjectImpl();
RawObject* ReadObjectImpl(intptr_t header);
RawObject* ReadObjectRef();
// Read a VM isolate object that was serialized as an Id.
RawObject* ReadVMIsolateObject(intptr_t object_id);
// Read an object that was serialized as an Id (singleton in object store,
// or an object that was already serialized before).
RawObject* ReadIndexedObject(intptr_t object_id);
// Read an inlined object from the stream.
RawObject* ReadInlinedObject(intptr_t object_id);
// Based on header field check to see if it is an internal VM class.
RawClass* LookupInternalClass(intptr_t class_header);
void ArrayReadFrom(const Array& result, intptr_t len, intptr_t tags);
Snapshot::Kind kind_; // Indicates type of snapshot(full, script, message).
Isolate* isolate_; // Current isolate.
Class& cls_; // Temporary Class handle.
Object& obj_; // Temporary Object handle.
String& str_; // Temporary String handle.
Library& library_; // Temporary library handle.
AbstractType& type_; // Temporary type handle.
AbstractTypeArguments& type_arguments_; // Temporary type argument handle.
Array& tokens_; // Temporary tokens handle.
TokenStream& stream_; // Temporary token stream handle.
ExternalTypedData& data_; // Temporary stream data handle.
UnhandledException& error_; // Error handle.
GrowableArray<BackRefNode*> backward_references_;
friend class ApiError;
friend class Array;
friend class BoundedType;
friend class MixinAppType;
friend class Class;
friend class Context;
friend class ContextScope;
friend class Field;
friend class ClosureData;
friend class RedirectionData;
friend class Function;
friend class GrowableObjectArray;
friend class ImmutableArray;
friend class InstantiatedTypeArguments;
friend class JSRegExp;
friend class LanguageError;
friend class Library;
friend class LibraryPrefix;
friend class Namespace;
friend class LiteralToken;
friend class PatchClass;
friend class Script;
friend class Stacktrace;
friend class TokenStream;
friend class Type;
friend class TypeArguments;
friend class TypeParameter;
friend class UnresolvedClass;
friend class WeakProperty;
DISALLOW_COPY_AND_ASSIGN(SnapshotReader);
};
class BaseWriter {
public:
// Size of the snapshot.
intptr_t BytesWritten() const { return stream_.bytes_written(); }
// Writes raw data to the stream (basic type).
// sizeof(T) must be in {1,2,4,8}.
template <typename T>
void Write(T value) {
WriteStream::Raw<sizeof(T), T>::Write(&stream_, value);
}
// Writes an intptr_t type value out.
void WriteIntptrValue(intptr_t value) {
Write<int64_t>(value);
}
// Write an object that is serialized as an Id (singleton in object store,
// or an object that was already serialized before).
void WriteIndexedObject(intptr_t object_id) {
ASSERT(object_id <= kMaxObjectId);
intptr_t value = 0;
value = SerializedHeaderTag::update(kObjectId, value);
value = SerializedHeaderData::update(object_id, value);
WriteIntptrValue(value);
}
// Write a VM Isolateobject that is serialized as an Id.
void WriteVMIsolateObject(intptr_t object_id) {
ASSERT(object_id <= kMaxObjectId);
intptr_t value = 0;
value = SerializedHeaderTag::update(kObjectId, value);
value = SerializedHeaderData::update(object_id, value);
WriteIntptrValue(-value); // Write as a negative value.
}
// Write serialization header information for an object.
void WriteInlinedObjectHeader(intptr_t id) {
ASSERT(id <= kMaxObjectId);
intptr_t value = 0;
value = SerializedHeaderTag::update(kInlined, value);
value = SerializedHeaderData::update(id, value);
WriteIntptrValue(value);
}
// Write out a buffer of bytes.
void WriteBytes(const uint8_t* addr, intptr_t len) {
stream_.WriteBytes(addr, len);
}
protected:
BaseWriter(uint8_t** buffer,
ReAlloc alloc,
intptr_t initial_size) : stream_(buffer, alloc, initial_size) {
ASSERT(buffer != NULL);
ASSERT(alloc != NULL);
}
~BaseWriter() { }
void ReserveHeader() {
// Make room for recording snapshot buffer size.
stream_.set_current(stream_.buffer() + Snapshot::kHeaderSize);
}
void FillHeader(Snapshot::Kind kind) {
int32_t* data = reinterpret_cast<int32_t*>(stream_.buffer());
data[Snapshot::kLengthIndex] = stream_.bytes_written();
data[Snapshot::kSnapshotFlagIndex] = kind;
}
private:
WriteStream stream_;
DISALLOW_IMPLICIT_CONSTRUCTORS(BaseWriter);
};
class SnapshotWriter : public BaseWriter {
protected:
SnapshotWriter(Snapshot::Kind kind,
uint8_t** buffer,
ReAlloc alloc,
intptr_t initial_size);
public:
// Snapshot kind.
Snapshot::Kind kind() const { return kind_; }
// Serialize an object into the buffer.
void WriteObject(RawObject* raw);
uword GetObjectTags(RawObject* raw);
Exceptions::ExceptionType exception_type() const {
return exception_type_;
}
void set_exception_type(Exceptions::ExceptionType type) {
exception_type_ = type;
}
const char* exception_msg() const { return exception_msg_; }
void set_exception_msg(const char* msg) {
exception_msg_ = msg;
}
void ThrowException(Exceptions::ExceptionType type, const char* msg);
protected:
class ForwardObjectNode : public ZoneAllocated {
public:
ForwardObjectNode(RawObject* raw, uword tags, SerializeState state)
: raw_(raw), tags_(tags), state_(state) {}
RawObject* raw() const { return raw_; }
uword tags() const { return tags_; }
bool is_serialized() const { return state_ == kIsSerialized; }
void set_state(SerializeState value) { state_ = value; }
private:
RawObject* raw_;
uword tags_;
SerializeState state_;
DISALLOW_COPY_AND_ASSIGN(ForwardObjectNode);
};
intptr_t MarkObject(RawObject* raw, SerializeState state);
void UnmarkAll();
bool CheckAndWritePredefinedObject(RawObject* raw);
void HandleVMIsolateObject(RawObject* raw);
void WriteObjectRef(RawObject* raw);
void WriteClassId(RawClass* cls);
void WriteObjectImpl(RawObject* raw);
void WriteInlinedObject(RawObject* raw);
void WriteForwardedObjects();
void ArrayWriteTo(intptr_t object_id,
intptr_t array_kind,
intptr_t tags,
RawSmi* length,
RawAbstractTypeArguments* type_arguments,
RawObject* data[]);
void CheckIfSerializable(RawClass* cls);
void SetWriteException(Exceptions::ExceptionType type, const char* msg);
void WriteInstance(intptr_t object_id,
RawObject* raw,
RawClass* cls,
intptr_t tags);
void WriteInstanceRef(RawObject* raw, RawClass* cls);
ObjectStore* object_store() const { return object_store_; }
private:
Snapshot::Kind kind_;
ObjectStore* object_store_; // Object store for common classes.
ClassTable* class_table_; // Class table for the class index to class lookup.
GrowableArray<ForwardObjectNode*> forward_list_;
Exceptions::ExceptionType exception_type_; // Exception type.
const char* exception_msg_; // Message associated with exception.
friend class RawArray;
friend class RawClass;
friend class RawClosureData;
friend class RawGrowableObjectArray;
friend class RawImmutableArray;
friend class RawJSRegExp;
friend class RawLibrary;
friend class RawLiteralToken;
friend class RawScript;
friend class RawStacktrace;
friend class RawTokenStream;
friend class RawTypeArguments;
friend class SnapshotWriterVisitor;
DISALLOW_COPY_AND_ASSIGN(SnapshotWriter);
};
class FullSnapshotWriter : public SnapshotWriter {
public:
static const intptr_t kInitialSize = 64 * KB;
FullSnapshotWriter(uint8_t** buffer, ReAlloc alloc)
: SnapshotWriter(Snapshot::kFull, buffer, alloc, kInitialSize) {
ASSERT(buffer != NULL);
ASSERT(alloc != NULL);
}
~FullSnapshotWriter() { }
// Writes a full snapshot of the Isolate.
void WriteFullSnapshot();
private:
DISALLOW_COPY_AND_ASSIGN(FullSnapshotWriter);
};
class ScriptSnapshotWriter : public SnapshotWriter {
public:
static const intptr_t kInitialSize = 64 * KB;
ScriptSnapshotWriter(uint8_t** buffer, ReAlloc alloc)
: SnapshotWriter(Snapshot::kScript, buffer, alloc, kInitialSize) {
ASSERT(buffer != NULL);
ASSERT(alloc != NULL);
}
~ScriptSnapshotWriter() { }
// Writes a partial snapshot of the script.
void WriteScriptSnapshot(const Library& lib);
private:
DISALLOW_COPY_AND_ASSIGN(ScriptSnapshotWriter);
};
class MessageWriter : public SnapshotWriter {
public:
static const intptr_t kInitialSize = 512;
MessageWriter(uint8_t** buffer, ReAlloc alloc)
: SnapshotWriter(Snapshot::kMessage, buffer, alloc, kInitialSize) {
ASSERT(buffer != NULL);
ASSERT(alloc != NULL);
}
~MessageWriter() { }
void WriteMessage(const Object& obj);
private:
DISALLOW_COPY_AND_ASSIGN(MessageWriter);
};
// An object pointer visitor implementation which writes out
// objects to a snap shot.
class SnapshotWriterVisitor : public ObjectPointerVisitor {
public:
explicit SnapshotWriterVisitor(SnapshotWriter* writer)
: ObjectPointerVisitor(Isolate::Current()),
writer_(writer),
as_references_(true) {}
SnapshotWriterVisitor(SnapshotWriter* writer, bool as_references)
: ObjectPointerVisitor(Isolate::Current()),
writer_(writer),
as_references_(as_references) {}
virtual void VisitPointers(RawObject** first, RawObject** last);
private:
SnapshotWriter* writer_;
bool as_references_;
DISALLOW_COPY_AND_ASSIGN(SnapshotWriterVisitor);
};
} // namespace dart
#endif // VM_SNAPSHOT_H_