mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:22:12 +00:00
37526fc8d7
This reverts commit 7dca34c235
.
Reason for revert: b/226085355 dart_vm_test crashing. Unclear what
the cause is. Reverting so we can triage the issue.
TEST=This is a revert.
Original change's description:
> [vm] Implement `Finalizer`
>
> This CL implements the `Finalizer` in the GC.
>
> (This CL does not yet implement `NativeFinalizer`.)
>
> The GC is specially aware of two types of objects for the purposes of
> running finalizers.
>
> 1) `FinalizerEntry`
> 2) `Finalizer` (`FinalizerBase`, `_FinalizerImpl`)
>
> A `FinalizerEntry` contains the `value`, the optional `detach` key, and
> the `token`, and a reference to the `finalizer`.
> An entry only holds on weakly to the value, detach key, and finalizer.
> (Similar to how `WeakReference` only holds on weakly to target).
>
> A `Finalizer` contains all entries, a list of entries of which the value
> is collected, and a reference to the isolate.
>
> When a the value of an entry is GCed, the enry is added over to the
> collected list.
> If any entry is moved to the collected list, a message is sent that
> invokes the finalizer to call the callback on all entries in that list.
>
> When a finalizer is detached by the user, the entry token is set to the
> entry itself and is removed from the all entries set.
> This ensures that if the entry was already moved to the collected list,
> the finalizer is not executed.
>
> To speed up detaching, we use a weak map from detach keys to list of
> entries. This ensures entries can be GCed.
>
> Both the scavenger and marker tasks process finalizer entries in
> parallel.
> Parallel tasks use an atomic exchange on the head of the collected
> entries list, ensuring no entries get lost.
> The mutator thread is guaranteed to be stopped when processing entries.
> This ensures that we do not need barriers for moving entries into the
> finalizers collected list.
> Dart reads and replaces the collected entries list also with an atomic
> exchange, ensuring the GC doesn't run in between a load/store.
>
> When a finalizer gets posted a message to process finalized objects, it
> is being kept alive by the message.
> An alternative design would be to pre-allocate a `WeakReference` in the
> finalizer pointing to the finalizer, and send that itself.
> This would be at the cost of an extra object.
>
> Send and exit is not supported in this CL, support will be added in a
> follow up CL. Trying to send will throw.
>
> Bug: https://github.com/dart-lang/sdk/issues/47777
>
> TEST=runtime/tests/vm/dart/finalizer/*
> TEST=runtime/tests/vm/dart_2/isolates/fast_object_copy_test.dart
> TEST=runtime/vm/object_test.cc
>
> Change-Id: I03e6b4a46212316254bf46ba3f2df333abaa686c
> Cq-Include-Trybots: luci.dart.try:vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-ffi-android-debug-arm64c-try,dart-sdk-mac-arm64-try,vm-kernel-mac-release-arm64-try,pkg-mac-release-arm64-try,vm-kernel-precomp-nnbd-mac-release-arm64-try,vm-kernel-win-debug-x64c-try,vm-kernel-win-debug-x64-try,vm-kernel-precomp-win-debug-x64c-try,vm-kernel-nnbd-win-release-ia32-try,vm-ffi-android-debug-arm-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-mac-debug-x64-try,vm-kernel-nnbd-mac-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,benchmark-linux-try,flutter-analyze-try,flutter-frontend-try,pkg-linux-debug-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-gcc-linux-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/229544
> Reviewed-by: Lasse Nielsen <lrn@google.com>
> Reviewed-by: Slava Egorov <vegorov@google.com>
> Reviewed-by: Martin Kustermann <kustermann@google.com>
> Reviewed-by: Ryan Macnak <rmacnak@google.com>
> Commit-Queue: Daco Harkes <dacoharkes@google.com>
TBR=lrn@google.com,vegorov@google.com,kustermann@google.com,rmacnak@google.com,dacoharkes@google.com
Change-Id: I991f6e49896d18a8d70210cf315d858b462d66c9
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: https://github.com/dart-lang/sdk/issues/47777
Cq-Include-Trybots: luci.dart.try:vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-ffi-android-debug-arm64c-try,dart-sdk-mac-arm64-try,vm-kernel-mac-release-arm64-try,pkg-mac-release-arm64-try,vm-kernel-precomp-nnbd-mac-release-arm64-try,vm-kernel-win-debug-x64c-try,vm-kernel-win-debug-x64-try,vm-kernel-precomp-win-debug-x64c-try,vm-kernel-nnbd-win-release-ia32-try,vm-ffi-android-debug-arm-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-mac-debug-x64-try,vm-kernel-nnbd-mac-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,benchmark-linux-try,flutter-analyze-try,flutter-frontend-try,pkg-linux-debug-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-gcc-linux-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/238080
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
247 lines
6.6 KiB
C++
247 lines
6.6 KiB
C++
// Copyright (c) 2011, 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 <utility>
|
|
|
|
#include "vm/dart_api_state.h"
|
|
#include "vm/dart_entry.h"
|
|
#include "vm/json_stream.h"
|
|
#include "vm/object.h"
|
|
#include "vm/port.h"
|
|
|
|
namespace dart {
|
|
|
|
const Dart_Port Message::kIllegalPort = 0;
|
|
|
|
Message::Message(Dart_Port dest_port,
|
|
uint8_t* snapshot,
|
|
intptr_t snapshot_length,
|
|
MessageFinalizableData* finalizable_data,
|
|
Priority priority)
|
|
: dest_port_(dest_port),
|
|
payload_(snapshot),
|
|
snapshot_length_(snapshot_length),
|
|
finalizable_data_(finalizable_data),
|
|
priority_(priority) {
|
|
ASSERT(IsSnapshot());
|
|
}
|
|
|
|
Message::Message(Dart_Port dest_port, ObjectPtr raw_obj, Priority priority)
|
|
: dest_port_(dest_port), payload_(raw_obj), priority_(priority) {
|
|
ASSERT(!raw_obj->IsHeapObject() || raw_obj->untag()->InVMIsolateHeap());
|
|
ASSERT(IsRaw());
|
|
}
|
|
|
|
Message::Message(Dart_Port dest_port,
|
|
PersistentHandle* handle,
|
|
Priority priority)
|
|
: dest_port_(dest_port),
|
|
payload_(handle),
|
|
snapshot_length_(kPersistentHandleSnapshotLen),
|
|
priority_(priority) {
|
|
ASSERT(IsPersistentHandle());
|
|
}
|
|
|
|
Message::~Message() {
|
|
if (IsSnapshot()) {
|
|
free(payload_.snapshot_);
|
|
}
|
|
delete finalizable_data_;
|
|
if (IsPersistentHandle()) {
|
|
auto isolate_group = IsolateGroup::Current();
|
|
isolate_group->api_state()->FreePersistentHandle(
|
|
payload_.persistent_handle_);
|
|
}
|
|
}
|
|
|
|
intptr_t Message::Id() const {
|
|
// Messages are allocated on the C heap. Use the raw address as the id.
|
|
return reinterpret_cast<intptr_t>(this);
|
|
}
|
|
|
|
const char* Message::PriorityAsString(Priority priority) {
|
|
switch (priority) {
|
|
case kNormalPriority:
|
|
return "Normal";
|
|
break;
|
|
case kOOBPriority:
|
|
return "OOB";
|
|
break;
|
|
default:
|
|
UNIMPLEMENTED();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
MessageQueue::MessageQueue() {
|
|
head_ = NULL;
|
|
tail_ = NULL;
|
|
}
|
|
|
|
MessageQueue::~MessageQueue() {
|
|
// Ensure that all pending messages have been released.
|
|
Clear();
|
|
ASSERT(head_ == NULL);
|
|
}
|
|
|
|
void MessageQueue::Enqueue(std::unique_ptr<Message> msg0, bool before_events) {
|
|
// TODO(mdempsky): Use unique_ptr internally?
|
|
Message* msg = msg0.release();
|
|
|
|
// Make sure messages are not reused.
|
|
ASSERT(msg->next_ == NULL);
|
|
if (head_ == NULL) {
|
|
// Only element in the queue.
|
|
ASSERT(tail_ == NULL);
|
|
head_ = msg;
|
|
tail_ = msg;
|
|
} else {
|
|
ASSERT(tail_ != NULL);
|
|
if (!before_events) {
|
|
// Append at the tail.
|
|
tail_->next_ = msg;
|
|
tail_ = msg;
|
|
} else {
|
|
ASSERT(msg->dest_port() == Message::kIllegalPort);
|
|
if (head_->dest_port() != Message::kIllegalPort) {
|
|
msg->next_ = head_;
|
|
head_ = msg;
|
|
} else {
|
|
Message* cur = head_;
|
|
while (cur->next_ != NULL) {
|
|
if (cur->next_->dest_port() != Message::kIllegalPort) {
|
|
// Splice in the new message at the break.
|
|
msg->next_ = cur->next_;
|
|
cur->next_ = msg;
|
|
return;
|
|
}
|
|
cur = cur->next_;
|
|
}
|
|
// All pending messages are isolate library control messages. Append at
|
|
// the tail.
|
|
ASSERT(tail_ == cur);
|
|
ASSERT(tail_->dest_port() == Message::kIllegalPort);
|
|
tail_->next_ = msg;
|
|
tail_ = msg;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<Message> MessageQueue::Dequeue() {
|
|
Message* result = head_;
|
|
if (result != nullptr) {
|
|
head_ = result->next_;
|
|
// The following update to tail_ is not strictly needed.
|
|
if (head_ == nullptr) {
|
|
tail_ = nullptr;
|
|
}
|
|
#if defined(DEBUG)
|
|
result->next_ = result; // Make sure to trigger ASSERT in Enqueue.
|
|
#endif // DEBUG
|
|
return std::unique_ptr<Message>(result);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void MessageQueue::Clear() {
|
|
std::unique_ptr<Message> cur(head_);
|
|
head_ = nullptr;
|
|
tail_ = nullptr;
|
|
while (cur != nullptr) {
|
|
std::unique_ptr<Message> next(cur->next_);
|
|
cur = std::move(next);
|
|
}
|
|
}
|
|
|
|
MessageQueue::Iterator::Iterator(const MessageQueue* queue) : next_(NULL) {
|
|
Reset(queue);
|
|
}
|
|
|
|
MessageQueue::Iterator::~Iterator() {}
|
|
|
|
void MessageQueue::Iterator::Reset(const MessageQueue* queue) {
|
|
ASSERT(queue != NULL);
|
|
next_ = queue->head_;
|
|
}
|
|
|
|
// returns false when there are no more messages left.
|
|
bool MessageQueue::Iterator::HasNext() {
|
|
return next_ != NULL;
|
|
}
|
|
|
|
// Returns the current message and moves forward.
|
|
Message* MessageQueue::Iterator::Next() {
|
|
Message* current = next_;
|
|
next_ = next_->next_;
|
|
return current;
|
|
}
|
|
|
|
intptr_t MessageQueue::Length() const {
|
|
MessageQueue::Iterator it(this);
|
|
intptr_t length = 0;
|
|
while (it.HasNext()) {
|
|
it.Next();
|
|
length++;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
Message* MessageQueue::FindMessageById(intptr_t id) {
|
|
MessageQueue::Iterator it(this);
|
|
while (it.HasNext()) {
|
|
Message* current = it.Next();
|
|
ASSERT(current != NULL);
|
|
if (current->Id() == id) {
|
|
return current;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void MessageQueue::PrintJSON(JSONStream* stream) {
|
|
#ifndef PRODUCT
|
|
JSONArray messages(stream);
|
|
|
|
Object& msg_handler = Object::Handle();
|
|
|
|
MessageQueue::Iterator it(this);
|
|
intptr_t depth = 0;
|
|
while (it.HasNext()) {
|
|
Message* current = it.Next();
|
|
JSONObject message(&messages);
|
|
message.AddProperty("type", "Message");
|
|
message.AddPropertyF("name", "Isolate Message (%" Px ")", current->Id());
|
|
message.AddPropertyF("messageObjectId", "messages/%" Px "", current->Id());
|
|
message.AddProperty("size", current->Size());
|
|
message.AddProperty("index", depth++);
|
|
message.AddPropertyF("_destinationPort", "%" Pd64 "",
|
|
static_cast<int64_t>(current->dest_port()));
|
|
message.AddProperty("_priority",
|
|
Message::PriorityAsString(current->priority()));
|
|
// TODO(johnmccutchan): Move port -> handler map out of Dart and into the
|
|
// VM, that way we can lookup the handler without invoking Dart code.
|
|
msg_handler = DartLibraryCalls::LookupHandler(current->dest_port());
|
|
if (msg_handler.IsClosure()) {
|
|
// Grab function from closure.
|
|
msg_handler = Closure::Cast(msg_handler).function();
|
|
}
|
|
if (msg_handler.IsFunction()) {
|
|
const Function& function = Function::Cast(msg_handler);
|
|
message.AddProperty("handler", function);
|
|
|
|
const Script& script = Script::Handle(function.script());
|
|
if (!script.IsNull()) {
|
|
message.AddLocation(script, function.token_pos(),
|
|
function.end_token_pos());
|
|
}
|
|
}
|
|
}
|
|
#endif // !PRODUCT
|
|
}
|
|
|
|
} // namespace dart
|