mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 20:41:24 +00:00
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:
parent
83abae13a2
commit
016214f002
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -1086,6 +1086,7 @@ class ObservatoryDebugger extends Debugger {
|
|||
case ServiceEvent.kIsolateStart:
|
||||
case ServiceEvent.kGraph:
|
||||
case ServiceEvent.kGC:
|
||||
case ServiceEvent.kInspect:
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -333,6 +333,13 @@
|
|||
<a class="boxclose" on-click="{{ closeItem }}">×</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 }}">×</a>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</polymer-element>
|
||||
|
||||
|
|
|
@ -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'];
|
||||
}
|
||||
|
|
43
runtime/observatory/tests/service/debugger_inspect_test.dart
Normal file
43
runtime/observatory/tests/service/debugger_inspect_test.dart
Normal 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);
|
|
@ -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) \
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
17
tests/lib/developer/inspect_test.dart
Normal file
17
tests/lib/developer/inspect_test.dart
Normal 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));
|
||||
}
|
Loading…
Reference in a new issue