0ab55451f4
TEST=ci Change-Id: I840fc1a614186e0f330f4b2313a6706452af6998 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/388665 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
125 lines
4.3 KiB
C++
125 lines
4.3 KiB
C++
// 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.
|
|
|
|
#ifndef RUNTIME_VM_HEAP_BECOME_H_
|
|
#define RUNTIME_VM_HEAP_BECOME_H_
|
|
|
|
#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 transformed 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 {
|
|
public:
|
|
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 {
|
|
public:
|
|
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; }
|
|
|
|
private:
|
|
DISALLOW_ALLOCATION();
|
|
DISALLOW_COPY_AND_ASSIGN(FakeInstance);
|
|
};
|
|
|
|
private:
|
|
// This layout mirrors the layout of UntaggedObject.
|
|
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.
|
|
DISALLOW_ALLOCATION();
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ForwardingCorpse);
|
|
};
|
|
|
|
// 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 {
|
|
public:
|
|
Become();
|
|
~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);
|
|
|
|
private:
|
|
MallocGrowableArray<ObjectPtr> pointers_;
|
|
DISALLOW_COPY_AND_ASSIGN(Become);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_HEAP_BECOME_H_
|