Files
sdk/runtime/lib/developer.cc
T
Martin Kustermann e1c2192110 [vm] Make writeHeapSnapshotToFile() API public in dart:developer
This API can be used by app developers that want to diagnose high
memory consumption by dumping state of Dart VM heap at specific
points in their apps code and later analyzing those dumps offline
(e.g. using the tool in `<sdk>/runtime/tools/heapsnapshot`).

TEST=Existing test suite.

Change-Id: I04de6ba564f7b9eaf8b59d41fc4b3ec35ce8d2e5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279972
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Michael Thomsen <mit@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Reviewed-by: Jacob Richman <jacobr@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
2023-04-03 12:25:55 +00:00

206 lines
6.4 KiB
C++

// Copyright (c) 2015, 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/bootstrap_natives.h"
#include "include/dart_api.h"
#include "vm/debugger.h"
#include "vm/exceptions.h"
#include "vm/flags.h"
#include "vm/heap/heap.h"
#include "vm/isolate.h"
#include "vm/message.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/object_graph.h"
#include "vm/object_store.h"
#include "vm/service.h"
#include "vm/service_isolate.h"
namespace dart {
// Native implementations for the dart:developer library.
DEFINE_NATIVE_ENTRY(Developer_debugger, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Bool, when, arguments->NativeArgAt(0));
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
GET_NATIVE_ARGUMENT(String, msg, arguments->NativeArgAt(1));
Debugger* debugger = isolate->debugger();
if (debugger == nullptr) {
return when.ptr();
}
if (when.value()) {
debugger->PauseDeveloper(msg);
}
#endif
return when.ptr();
}
DEFINE_NATIVE_ENTRY(Developer_inspect, 0, 1) {
GET_NATIVE_ARGUMENT(Instance, inspectee, arguments->NativeArgAt(0));
#ifndef PRODUCT
Service::SendInspectEvent(isolate, inspectee);
#endif // !PRODUCT
return inspectee.ptr();
}
DEFINE_NATIVE_ENTRY(Developer_log, 0, 8) {
#if defined(PRODUCT)
return Object::null();
#else
GET_NON_NULL_NATIVE_ARGUMENT(String, message, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Integer, timestamp, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(Integer, sequence, arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, level, arguments->NativeArgAt(3));
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(4));
GET_NATIVE_ARGUMENT(Instance, dart_zone, arguments->NativeArgAt(5));
GET_NATIVE_ARGUMENT(Instance, error, arguments->NativeArgAt(6));
GET_NATIVE_ARGUMENT(Instance, stack_trace, arguments->NativeArgAt(7));
Service::SendLogEvent(isolate, sequence.AsInt64Value(),
timestamp.AsInt64Value(), level.Value(), name, message,
dart_zone, error, stack_trace);
return Object::null();
#endif // PRODUCT
}
DEFINE_NATIVE_ENTRY(Developer_postEvent, 0, 2) {
#if defined(PRODUCT)
return Object::null();
#else
GET_NON_NULL_NATIVE_ARGUMENT(String, event_kind, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(String, event_data, arguments->NativeArgAt(1));
Service::SendExtensionEvent(isolate, event_kind, event_data);
return Object::null();
#endif // PRODUCT
}
DEFINE_NATIVE_ENTRY(Developer_lookupExtension, 0, 1) {
#if defined(PRODUCT)
return Object::null();
#else
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
return isolate->LookupServiceExtensionHandler(name);
#endif // PRODUCT
}
DEFINE_NATIVE_ENTRY(Developer_registerExtension, 0, 2) {
#if defined(PRODUCT)
return Object::null();
#else
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Instance, handler, arguments->NativeArgAt(1));
// We don't allow service extensions to be registered for the
// service isolate. This can happen, for example, because the
// service isolate uses dart:io. If we decide that we want to start
// supporting this in the future, it will take some work.
if (!ServiceIsolate::IsServiceIsolateDescendant(isolate)) {
isolate->RegisterServiceExtensionHandler(name, handler);
}
return Object::null();
#endif // PRODUCT
}
DEFINE_NATIVE_ENTRY(Developer_getServiceMajorVersion, 0, 0) {
#if defined(PRODUCT)
return Smi::New(0);
#else
return Smi::New(SERVICE_PROTOCOL_MAJOR_VERSION);
#endif
}
DEFINE_NATIVE_ENTRY(Developer_getServiceMinorVersion, 0, 0) {
#if defined(PRODUCT)
return Smi::New(0);
#else
return Smi::New(SERVICE_PROTOCOL_MINOR_VERSION);
#endif
}
static void SendNull(const SendPort& port) {
const Dart_Port destination_port_id = port.Id();
PortMap::PostMessage(Message::New(destination_port_id, Object::null(),
Message::kNormalPriority));
}
DEFINE_NATIVE_ENTRY(Developer_getServerInfo, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
#if defined(PRODUCT)
SendNull(port);
return Object::null();
#else
ServiceIsolate::WaitForServiceIsolateStartup();
if (!ServiceIsolate::IsRunning()) {
SendNull(port);
} else {
ServiceIsolate::RequestServerInfo(port);
}
return Object::null();
#endif
}
DEFINE_NATIVE_ENTRY(Developer_webServerControl, 0, 3) {
GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
#if defined(PRODUCT)
SendNull(port);
return Object::null();
#else
GET_NON_NULL_NATIVE_ARGUMENT(Bool, enabled, arguments->NativeArgAt(1));
GET_NATIVE_ARGUMENT(Bool, silence_output, arguments->NativeArgAt(2));
ServiceIsolate::WaitForServiceIsolateStartup();
if (!ServiceIsolate::IsRunning()) {
SendNull(port);
} else {
ServiceIsolate::ControlWebServer(port, enabled.value(), silence_output);
}
return Object::null();
#endif
}
DEFINE_NATIVE_ENTRY(Developer_getIsolateIDFromSendPort, 0, 1) {
#if defined(PRODUCT)
return Object::null();
#else
GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
int64_t port_id = port.Id();
return String::NewFormatted(ISOLATE_SERVICE_ID_FORMAT_STRING, port_id);
#endif
}
DEFINE_NATIVE_ENTRY(Developer_reachability_barrier, 0, 0) {
#if defined(PRODUCT)
return Smi::New(0);
#else
IsolateGroup* isolate_group = thread->isolate_group();
ASSERT(isolate_group != nullptr);
Heap* heap = isolate_group->heap();
ASSERT(heap != nullptr);
return Integer::New(heap->ReachabilityBarrier());
#endif
}
DEFINE_NATIVE_ENTRY(Developer_NativeRuntime_writeHeapSnapshotToFile, 0, 1) {
#if defined(DART_ENABLE_HEAP_SNAPSHOT_WRITER)
const String& filename =
String::CheckedHandle(zone, arguments->NativeArgAt(0));
bool successful = false;
{
FileHeapSnapshotWriter file_writer(thread, filename.ToCString(),
&successful);
HeapSnapshotWriter writer(thread, &file_writer);
writer.Write();
}
if (!successful) {
Exceptions::ThrowUnsupportedError(
"Could not create & write heapsnapshot to disc. Possibly due to "
"missing embedder functionality.");
}
#else
Exceptions::ThrowUnsupportedError(
"Heap snapshots are only supported in non-product mode.");
#endif // !defined(PRODUCT)
return Object::null();
}
} // namespace dart