blob: 73d43ef80b2b87298c9005937d0c99d30ad80e23 [file] [log] [blame]
// Copyright (c) 2016, 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 "platform/atomic.h"
#include "platform/growable_array.h"
#include "vm/allocation.h"
#include "vm/raw_object.h"
namespace dart {
class Array;
// Objects that are a source in a become are tranformed into forwarding
// corpses pointing to the corresponding target. Forwarding corpses have the
// same heap sizes as the source object to ensure the heap remains walkable.
// If the heap sizes is small enough to be encoded in the size field of the
// header, a forwarding corpse consists only of a header and the target pointer.
// If the heap size is too big to be encoded in the header's size field, the
// word after the target pointer contains the size. This is the same
// representation as a FreeListElement.
class ForwardingCorpse {
ObjectPtr target() const { return target_; }
void set_target(ObjectPtr target) { target_ = target; }
intptr_t HeapSize() { return HeapSize(tags_); }
intptr_t HeapSize(uword tags) {
intptr_t size = UntaggedObject::SizeTag::decode(tags);
if (size != 0) return size;
return *SizeAddress();
static ForwardingCorpse* AsForwarder(uword addr, intptr_t size);
static void Init();
// Used to allocate class for forwarding corpses in Object::InitOnce.
class FakeInstance {
FakeInstance() {}
static cpp_vtable vtable() { return 0; }
static intptr_t InstanceSize() { return 0; }
static intptr_t NextFieldOffset() { return -kWordSize; }
static const ClassId kClassId = kForwardingCorpse;
static bool IsInstance() { return true; }
// This layout mirrors the layout of RawObject.
RelaxedAtomic<uword> tags_;
RelaxedAtomic<ObjectPtr> target_;
// Returns the address of the embedded size.
intptr_t* SizeAddress() const {
uword addr = reinterpret_cast<uword>(&target_) + kWordSize;
return reinterpret_cast<intptr_t*>(addr);
// ForwardingCorpses cannot be allocated. Instead references to them are
// created using the AsForwarder factory method.
// Forward/exchange object identity within pairs of objects.
// Forward: Redirects all pointers to each 'before' object to the corresponding
// 'after' object. Every 'before' object is guaranteed to be unreachable after
// the operation. The identity hash of the 'before' object is retained.
// This is useful for atomically applying behavior and schema changes, which can
// be done by allocating fresh objects with the new schema and forwarding the
// identity of the old objects to the new objects.
// Exchange: Redirect all pointers to each 'before' object to the corresponding
// 'after' object and vice versa. Both objects remain reachable after the
// operation.
// This is useful for implementing certain types of proxies. For example, an
// infrequently accessed object may be written to disk and swapped with a
// so-called "husk", and swapped back when it is later accessed.
// This operation is named 'become' after its original in Smalltalk:
// x become: y "exchange identity for one pair"
// x becomeForward: y "forward identity for one pair"
// #(x ...) elementsExchangeIdentityWith: #(y ...)
// #(x ...) elementsForwardIdentityTo: #(y ...)
class Become {
void Add(const Object& before, const Object& after);
void Forward();
void Exchange() { UNIMPLEMENTED(); }
void VisitObjectPointers(ObjectPointerVisitor* visitor);
// Convert and instance object into a dummy object,
// making the instance independent of its class.
// (used for morphic instances during reload).
static void MakeDummyObject(const Instance& instance);
// Update any references pointing to forwarding objects to point the
// forwarding objects' targets.
static void FollowForwardingPointers(Thread* thread);
MallocGrowableArray<ObjectPtr> pointers_;
} // namespace dart