Add Debugger.inspect. 1976 here we come!

R=johnmccutchan@google.com

Review URL: https://codereview.chromium.org//1132153002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@45664 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
rmacnak@google.com 2015-05-08 22:18:43 +00:00
parent 83abae13a2
commit 016214f002
15 changed files with 126 additions and 1 deletions

View file

@ -11,6 +11,7 @@
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/service.h"
namespace dart {
@ -29,4 +30,11 @@ DEFINE_NATIVE_ENTRY(Developer_debugger, 2) {
return when.raw();
}
DEFINE_NATIVE_ENTRY(Developer_inspect, 1) {
GET_NATIVE_ARGUMENT(Instance, inspectee, arguments->NativeArgAt(0));
Service::SendInspectEvent(isolate, inspectee);
return inspectee.raw();
}
} // namespace dart

View file

@ -3,3 +3,5 @@
// BSD-style license that can be found in the LICENSE file.
patch bool debugger({bool when: true, String msg}) native "Developer_debugger";
patch inspect(object) native "Developer_inspect";

View file

@ -107,6 +107,10 @@ class ObservatoryApplication extends Observable {
notifications.add(event);
break;
case ServiceEvent.kInspect:
notifications.add(event);
break;
default:
// Ignore unrecognized events.
Logger.root.severe('Unrecognized event: $event');

View file

@ -1086,6 +1086,7 @@ class ObservatoryDebugger extends Debugger {
case ServiceEvent.kIsolateStart:
case ServiceEvent.kGraph:
case ServiceEvent.kGC:
case ServiceEvent.kInspect:
break;
default:

View file

@ -333,6 +333,13 @@
<a class="boxclose" on-click="{{ closeItem }}">&times;</a>
</div>
</template>
<template if="{{ event.eventType == 'Inspect' }}">
<div class="item">
Inspect <any-service-ref ref="{{ event.inspectee }}"></any-service-ref>
<br><br>
<a class="boxclose" on-click="{{ closeItem }}">&times;</a>
</div>
</template>
</template>
</polymer-element>

View file

@ -1067,6 +1067,7 @@ class Isolate extends ServiceObjectOwner with Coverage {
switch(event.eventType) {
case ServiceEvent.kIsolateStart:
case ServiceEvent.kIsolateExit:
case ServiceEvent.kInspect:
// Handled elsewhere.
break;
@ -1455,6 +1456,7 @@ class ServiceEvent extends ServiceObject {
static const kBreakpointRemoved = 'BreakpointRemoved';
static const kGraph = '_Graph';
static const kGC = 'GC';
static const kInspect = 'Inspect';
static const kConnectionClosed = 'ConnectionClosed';
ServiceEvent._empty(ServiceObjectOwner owner) : super._empty(owner);
@ -1467,6 +1469,7 @@ class ServiceEvent extends ServiceObject {
@observable Breakpoint breakpoint;
@observable ServiceMap topFrame;
@observable ServiceMap exception;
@observable ServiceObject inspectee;
@observable ByteData data;
@observable int count;
@observable String reason;
@ -1487,6 +1490,9 @@ class ServiceEvent extends ServiceObject {
if (map['exception'] != null) {
exception = map['exception'];
}
if (map['inspectee'] != null) {
inspectee = map['inspectee'];
}
if (map['_data'] != null) {
data = map['_data'];
}

View file

@ -0,0 +1,43 @@
// 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.
// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
import 'dart:async';
import 'dart:developer';
class Point {
int x, y;
Point(this.x, this.y);
}
void testeeDo() {
Debugger.inspect(new Point(3, 4));
}
var tests = [
(Isolate isolate) async {
Completer completer = new Completer();
var subscription;
subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
print(event);
if (event.eventType == ServiceEvent.kInspect) {
expect((event.inspectee as Instance).clazz.name, equals('Point'));
subscription.cancel();
completer.complete();
}
});
// Start listening for events first.
await isolate.eval(isolate.rootLib, 'testeeDo();');
return completer.future;
},
];
main(args) => runIsolateTests(args, tests);

View file

@ -63,6 +63,8 @@ namespace dart {
V(Bigint_getUsed, 1) \
V(Bigint_getDigits, 1) \
V(Bigint_allocate, 4) \
V(Developer_debugger, 2) \
V(Developer_inspect, 1) \
V(Double_getIsNegative, 1) \
V(Double_getIsInfinite, 1) \
V(Double_getIsNaN, 1) \
@ -87,7 +89,6 @@ namespace dart {
V(Double_toStringAsFixed, 2) \
V(Double_toStringAsExponential, 2) \
V(Double_toStringAsPrecision, 2) \
V(Developer_debugger, 2) \
V(JSSyntaxRegExp_factory, 4) \
V(JSSyntaxRegExp_getPattern, 1) \
V(JSSyntaxRegExp_getIsMultiLine, 1) \

View file

@ -2254,6 +2254,13 @@ void Service::SendGraphEvent(Isolate* isolate) {
}
void Service::SendInspectEvent(Isolate* isolate, const Object& inspectee) {
ServiceEvent event(isolate, ServiceEvent::kInspect);
event.set_inspectee(&inspectee);
Service::HandleEvent(&event);
}
class ContainsAddressVisitor : public FindObjectVisitor {
public:
ContainsAddressVisitor(Isolate* isolate, uword addr)

View file

@ -47,6 +47,7 @@ class Service : public AllStatic {
static void SendEchoEvent(Isolate* isolate, const char* text);
static void SendGraphEvent(Isolate* isolate);
static void SendInspectEvent(Isolate* isolate, const Object& inspectee);
private:
static void InvokeMethod(Isolate* isolate, const Array& message);

View file

@ -37,6 +37,7 @@ ServiceEvent::ServiceEvent(const DebuggerEvent* debugger_event)
breakpoint_(NULL),
top_frame_(NULL),
exception_(NULL),
inspectee_(NULL),
gc_stats_(NULL) {
DebuggerEvent::EventType type = debugger_event->type();
if (type == DebuggerEvent::kBreakpointReached) {
@ -81,6 +82,8 @@ const char* ServiceEvent::EventTypeToCString(EventType type) {
return "BreakpointRemoved";
case kGC:
return "GC"; // TODO(koda): Change to GarbageCollected.
case kInspect:
return "Inspect";
default:
UNREACHABLE();
return "Unknown";
@ -103,6 +106,9 @@ void ServiceEvent::PrintJSON(JSONStream* js) const {
if (exception() != NULL) {
jsobj.AddProperty("exception", *(exception()));
}
if (inspectee() != NULL) {
jsobj.AddProperty("inspectee", *(inspectee()));
}
if (gc_stats() != NULL) {
jsobj.AddProperty("reason", Heap::GCReasonToString(gc_stats()->reason_));
isolate()->heap()->PrintToJSONObject(Heap::kNew, &jsobj);

View file

@ -30,6 +30,7 @@ class ServiceEvent {
kBreakpointRemoved,
kGC,
kInspect,
kIllegal,
};
@ -40,6 +41,7 @@ class ServiceEvent {
breakpoint_(NULL),
top_frame_(NULL),
exception_(NULL),
inspectee_(NULL),
gc_stats_(NULL) {}
explicit ServiceEvent(const DebuggerEvent* debugger_event);
@ -78,6 +80,14 @@ class ServiceEvent {
exception_ = exception;
}
const Object* inspectee() const {
return inspectee_;
}
void set_inspectee(const Object* inspectee) {
ASSERT(type_ == kInspect);
inspectee_ = inspectee;
}
const Heap::GCStats* gc_stats() const {
return gc_stats_;
}
@ -96,6 +106,7 @@ class ServiceEvent {
SourceBreakpoint* breakpoint_;
ActivationFrame* top_frame_;
const Object* exception_;
const Object* inspectee_;
const Heap::GCStats* gc_stats_;
};

View file

@ -23,3 +23,10 @@ bool debugger({bool when: true, String msg}) {
}
return when;
}
/// Send a reference to [object] to any attached debuggers so they may open an
/// inspector on the object. Returns the argument.
@patch
inspect(object) {
return object;
}

View file

@ -20,3 +20,7 @@ library dart.developer;
/// JavaScript, this uses the "debugger" statement, and behaves exactly as
/// that does.
external bool debugger({bool when: true, String msg});
/// Send a reference to [object] to any attached debuggers so they may open an
/// inspector on the object. Returns the argument.
external inspect(object);

View file

@ -0,0 +1,17 @@
// 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.
import 'dart:developer';
import 'package:expect/expect.dart';
class Point {
int x, y;
Point(this.x, this.y);
}
void main() {
var p_in = new Point(3, 4);
var p_out = inspect(p_in);
Expect.isTrue(identical(p_in, p_out));
}