Reapply "Per-closure breakpoints; restructure breakpoint implementation to keep a list of conditions."

Fix copying breakpoints over to a new location when a latent location is resolved.

Fix bad assumption that BreakpointLocationAtLine always returns non-null result.

Review URL: https://codereview.chromium.org//1149983003
This commit is contained in:
Ryan Macnak 2015-05-27 09:59:33 -07:00
parent dfee2bf45d
commit 74dfae69e3
11 changed files with 821 additions and 302 deletions

View file

@ -1206,6 +1206,11 @@ class Isolate extends ServiceObjectOwner with Coverage {
{ 'functionId': function.id });
}
Future<ServiceObject> addBreakOnActivation(Instance closure) {
return invokeRpc('_addBreakpointAtActivation',
{ 'objectId': closure.id });
}
Future removeBreakpoint(Breakpoint bpt) {
return invokeRpc('removeBreakpoint',
{ 'breakpointId': bpt.id });

View file

@ -0,0 +1,191 @@
// 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';
genRepeater(value) {
return () => print(value);
}
genRepeaterNamed(value) {
return ({x, y}) => print(value);
}
var r1;
var r2;
var r3;
var r1_named;
var r2_named;
var r3_named;
void testeeSetup() {
// These closures have the same function.
r1 = genRepeater('r1');
r2 = genRepeater('r2');
r3 = genRepeater('r3');
// These closures have the same function.
r1_named = genRepeaterNamed('r1_named');
r2_named = genRepeaterNamed('r2_named');
r3_named = genRepeaterNamed('r3_named');
}
void testeeDo() {
r1();
r2();
r3();
}
void testeeDoNamed() {
r1_named(y: 'Not a closure', x: 'Not a closure');
r2_named(y: 'Not a closure', x: 'Not a closure');
r3_named(y: 'Not a closure', x: 'Not a closure');
}
var tests = [
(Isolate isolate) async {
var rootLib = await isolate.rootLibrary.load();
var breaksHit = 0;
var subscription;
subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kPauseBreakpoint) {
print("Hit breakpoint ${event.breakpoint}");
breaksHit++;
isolate.resume();
}
});
valueOfField(String name) {
return rootLib.variables.singleWhere((v) => v.name == name).value;
}
var r1Ref = valueOfField('r1');
var r2Ref = valueOfField('r2');
var r3Ref = valueOfField('r3');
var bpt1 = await isolate.addBreakOnActivation(r1Ref);
print("Added breakpoint $bpt1");
expect(bpt1 is Breakpoint, isTrue);
expect(breaksHit, equals(0));
print("testeeDo()");
var res = await rootLib.evaluate("testeeDo()");
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(1));
await isolate.removeBreakpoint(bpt1);
print("Removed breakpoint $bpt1");
print("testeeDo()");
res = await rootLib.evaluate("testeeDo()");
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(1));
await subscription.cancel();
},
(Isolate isolate) async {
var rootLib = await isolate.rootLibrary.load();
var breaksHit = 0;
var subscription;
subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kPauseBreakpoint) {
print("Hit breakpoint ${event.breakpoint}");
breaksHit++;
isolate.resume();
}
});
valueOfField(String name) {
return rootLib.variables.singleWhere((v) => v.name == name).value;
}
var r1Ref = valueOfField('r1_named');
var r2Ref = valueOfField('r2_named');
var r3Ref = valueOfField('r3_named');
var bpt1 = await isolate.addBreakOnActivation(r1Ref);
print("Added breakpoint $bpt1");
expect(bpt1 is Breakpoint, isTrue);
expect(breaksHit, equals(0));
print("testeeDoNamed()");
var res = await rootLib.evaluate("testeeDoNamed()");
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(1));
await isolate.removeBreakpoint(bpt1);
print("Removed breakpoint $bpt1");
print("testeeDoNamed()");
res = await rootLib.evaluate("testeeDoNamed()");
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(1));
await subscription.cancel();
},
(Isolate isolate) async {
var rootLib = await isolate.rootLibrary.load();
var breaksHit = 0;
var subscription;
subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kPauseBreakpoint) {
print("Hit breakpoint ${event.breakpoint}");
breaksHit++;
isolate.resume();
}
});
valueOfField(String name) {
return rootLib.variables.singleWhere((v) => v.name == name).value;
}
var r1Ref = valueOfField('r1');
var r2Ref = valueOfField('r2');
var r3Ref = valueOfField('r3');
var bpt1 = await isolate.addBreakOnActivation(r1Ref);
print("Added breakpoint $bpt1");
expect(bpt1 is Breakpoint, isTrue);
expect(breaksHit, equals(0));
print("testeeDo()");
var res = await rootLib.evaluate("testeeDo()");
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(1));
var bpt2 = await isolate.addBreakOnActivation(r2Ref);
print("Added breakpoint $bpt2");
expect(bpt2 is Breakpoint, isTrue);
expect(breaksHit, equals(1));
print("testeeDo()");
res = await rootLib.evaluate("testeeDo()");
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(3));
await isolate.removeBreakpoint(bpt1);
print("Removed breakpoint $bpt1");
print("testeeDo()");
res = await rootLib.evaluate("testeeDo()");
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(4));
await isolate.removeBreakpoint(bpt2);
print("Removed breakpoint $bpt2");
print("testeeDo()");
res = await rootLib.evaluate("testeeDo()");
expect(res is Instance, isTrue); // Not error.
expect(breaksHit, equals(4));
await subscription.cancel();
},
];
main(args) => runIsolateTests(args, tests, testeeBefore: testeeSetup);

View file

@ -108,6 +108,9 @@ void runIsolateTests(List<String> mainArgs,
} else {
var process = new _TestLauncher();
process.launch(pause_on_exit).then((port) {
if (mainArgs.contains("--gdb")) {
port = 8181;
}
String addr = 'ws://localhost:$port/ws';
var testIndex = 1;
var totalTests = tests.length;
@ -192,6 +195,9 @@ Future runVMTests(List<String> mainArgs,
} else {
var process = new _TestLauncher();
process.launch(pause_on_exit).then((port) async {
if (mainArgs.contains("--gdb")) {
port = 8181;
}
String addr = 'ws://localhost:$port/ws';
var testIndex = 1;
var totalTests = tests.length;

File diff suppressed because it is too large Load diff

View file

@ -18,12 +18,74 @@ class JSONArray;
class JSONStream;
class ObjectPointerVisitor;
class RemoteObjectCache;
class SourceBreakpoint;
class BreakpointLocation;
class StackFrame;
// SourceBreakpoint represents a user-specified breakpoint location in
// Dart source. There may be more than one CodeBreakpoint object per
// SourceBreakpoint.
// A user-defined breakpoint, which either fires once, for a particular closure,
// or always. The API's notion of a breakpoint corresponds to this object.
class Breakpoint {
public:
Breakpoint(intptr_t id, BreakpointLocation* bpt_location)
: id_(id),
kind_(Breakpoint::kNone),
next_(NULL),
closure_(Instance::null()),
bpt_location_(bpt_location) {}
intptr_t id() const { return id_; }
Breakpoint* next() const { return next_; }
void set_next(Breakpoint* n) { next_ = n; }
BreakpointLocation* bpt_location() const { return bpt_location_; }
void set_bpt_location(BreakpointLocation* new_bpt_location);
bool IsRepeated() const { return kind_ == kRepeated; }
bool IsSingleShot() const { return kind_ == kSingleShot; }
bool IsPerClosure() const { return kind_ == kPerClosure; }
RawInstance* closure() const { return closure_; }
void SetIsRepeated() {
ASSERT(kind_ == kNone);
kind_ = kRepeated;
}
void SetIsSingleShot() {
ASSERT(kind_ == kNone);
kind_ = kSingleShot;
}
void SetIsPerClosure(const Instance& closure) {
ASSERT(kind_ == kNone);
kind_ = kPerClosure;
closure_ = closure.raw();
}
void PrintJSON(JSONStream* stream);
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
enum ConditionKind {
kNone,
kRepeated,
kSingleShot,
kPerClosure,
};
intptr_t id_;
ConditionKind kind_;
Breakpoint* next_;
RawInstance* closure_;
BreakpointLocation* bpt_location_;
friend class BreakpointLocation;
DISALLOW_COPY_AND_ASSIGN(Breakpoint);
};
// BreakpointLocation represents a collection of breakpoint conditions at the
// same token position in Dart source. There may be more than one CodeBreakpoint
// object per BreakpointLocation.
// An unresolved breakpoint is one where the underlying code has not
// been compiled yet. Since the code has not been compiled, we don't know
// the definitive source location yet. The requested source location may
@ -32,22 +94,21 @@ class StackFrame;
// that is not loaded in the VM when the breakpoint is requested.
// When a script with matching url is loaded, a latent breakpoint
// becomes an unresolved breakpoint.
class SourceBreakpoint {
class BreakpointLocation {
public:
// Create a new unresolved breakpoint.
SourceBreakpoint(intptr_t id,
const Script& script,
intptr_t token_pos,
intptr_t end_token_pos);
BreakpointLocation(const Script& script,
intptr_t token_pos,
intptr_t end_token_pos);
// Create a new latent breakpoint.
SourceBreakpoint(intptr_t id,
const String& url,
intptr_t line_number);
BreakpointLocation(const String& url,
intptr_t line_number);
~BreakpointLocation();
RawFunction* function() const { return function_; }
intptr_t token_pos() const { return token_pos_; }
intptr_t end_token_pos() const { return end_token_pos_; }
intptr_t id() const { return id_; }
RawScript* script() const { return script_; }
RawString* url() const { return url_; }
@ -55,45 +116,46 @@ class SourceBreakpoint {
void GetCodeLocation(Library* lib, Script* script, intptr_t* token_pos);
void Enable();
void Disable();
bool IsEnabled() const { return is_enabled_; }
Breakpoint* AddRepeated(Debugger* dbg);
Breakpoint* AddSingleShot(Debugger* dbg);
Breakpoint* AddPerClosure(Debugger* dbg, const Instance& closure);
bool AnyEnabled() const;
bool IsResolved() const { return is_resolved_; }
bool IsLatent() const { return token_pos_ < 0; }
bool IsOneShot() const { return is_one_shot_; }
void SetIsOneShot() { is_one_shot_ = true; }
void PrintJSON(JSONStream* stream);
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
void SetResolved(const Function& func, intptr_t token_pos);
void set_next(SourceBreakpoint* value) { next_ = value; }
SourceBreakpoint* next() const { return this->next_; }
const intptr_t id_;
BreakpointLocation* next() const { return this->next_; }
void set_next(BreakpointLocation* value) { next_ = value; }
void AddBreakpoint(Breakpoint* bpt, Debugger* dbg);
Breakpoint* breakpoints() const { return this->conditions_; }
void set_breakpoints(Breakpoint* head) { this->conditions_ = head; }
RawScript* script_;
RawString* url_;
intptr_t token_pos_;
intptr_t end_token_pos_;
bool is_resolved_;
bool is_enabled_;
bool is_one_shot_;
SourceBreakpoint* next_;
BreakpointLocation* next_;
Breakpoint* conditions_;
// Valid for resolved breakpoints:
RawFunction* function_;
intptr_t line_number_;
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(SourceBreakpoint);
DISALLOW_COPY_AND_ASSIGN(BreakpointLocation);
};
// CodeBreakpoint represents a location in compiled code. There may be
// more than one CodeBreakpoint for one SourceBreakpoint, e.g. when a
// more than one CodeBreakpoint for one BreakpointLocation, e.g. when a
// function gets compiled as a regular function and as a closure.
class CodeBreakpoint {
public:
@ -106,7 +168,7 @@ class CodeBreakpoint {
RawFunction* function() const;
uword pc() const { return pc_; }
intptr_t token_pos() const { return token_pos_; }
bool IsInternal() const { return src_bpt_ == NULL; }
bool IsInternal() const { return bpt_location_ == NULL; }
RawScript* SourceCode();
RawString* SourceUrl();
@ -121,8 +183,8 @@ class CodeBreakpoint {
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
SourceBreakpoint* src_bpt() const { return src_bpt_; }
void set_src_bpt(SourceBreakpoint* value) { src_bpt_ = value; }
BreakpointLocation* bpt_location() const { return bpt_location_; }
void set_bpt_location(BreakpointLocation* value) { bpt_location_ = value; }
void set_next(CodeBreakpoint* value) { next_ = value; }
CodeBreakpoint* next() const { return this->next_; }
@ -136,7 +198,7 @@ class CodeBreakpoint {
intptr_t line_number_;
bool is_enabled_;
SourceBreakpoint* src_bpt_;
BreakpointLocation* bpt_location_;
CodeBreakpoint* next_;
RawPcDescriptors::Kind breakpoint_kind_;
@ -194,6 +256,8 @@ class ActivationFrame : public ZoneAllocated {
Object* value);
RawArray* GetLocalVariables();
RawObject* GetParameter(intptr_t index);
RawObject* GetClosure();
RawObject* GetReceiver();
const Context& GetSavedCurrentContext();
@ -273,11 +337,6 @@ class DebuggerStackTrace : public ZoneAllocated {
};
typedef void BreakpointHandler(Dart_Port isolate_id,
SourceBreakpoint* bpt,
DebuggerStackTrace* stack);
class DebuggerEvent {
public:
enum EventType {
@ -315,11 +374,11 @@ class DebuggerEvent {
top_frame_ = frame;
}
SourceBreakpoint* breakpoint() const {
Breakpoint* breakpoint() const {
ASSERT(type_ == kBreakpointReached || type_ == kBreakpointResolved);
return breakpoint_;
}
void set_breakpoint(SourceBreakpoint* bpt) {
void set_breakpoint(Breakpoint* bpt) {
ASSERT(type_ == kBreakpointReached || type_ == kBreakpointResolved);
breakpoint_ = bpt;
}
@ -341,7 +400,7 @@ class DebuggerEvent {
Isolate* isolate_;
EventType type_;
ActivationFrame* top_frame_;
SourceBreakpoint* breakpoint_;
Breakpoint* breakpoint_;
const Object* exception_;
};
@ -365,15 +424,21 @@ class Debugger {
const String& function_name);
// Set breakpoint at closest location to function entry.
SourceBreakpoint* SetBreakpointAtEntry(const Function& target_function);
Breakpoint* SetBreakpointAtEntry(const Function& target_function,
bool single_shot);
Breakpoint* SetBreakpointAtActivation(const Instance& closure);
// TODO(turnidge): script_url may no longer be specific enough.
SourceBreakpoint* SetBreakpointAtLine(const String& script_url,
intptr_t line_number);
Breakpoint* SetBreakpointAtLine(const String& script_url,
intptr_t line_number);
RawError* OneTimeBreakAtEntry(const Function& target_function);
BreakpointLocation* BreakpointLocationAtLine(const String& script_url,
intptr_t line_number);
void RemoveBreakpoint(intptr_t bp_id);
SourceBreakpoint* GetBreakpointById(intptr_t id);
Breakpoint* GetBreakpointById(intptr_t id);
void SetStepOver();
void SetSingleStep();
@ -476,22 +541,22 @@ class Debugger {
intptr_t requested_token_pos,
intptr_t last_token_pos);
void DeoptimizeWorld();
SourceBreakpoint* SetBreakpoint(const Script& script,
intptr_t token_pos,
intptr_t last_token_pos);
BreakpointLocation* SetBreakpoint(const Script& script,
intptr_t token_pos,
intptr_t last_token_pos);
void RemoveInternalBreakpoints();
void UnlinkCodeBreakpoints(SourceBreakpoint* src_bpt);
SourceBreakpoint* GetLatentBreakpoint(const String& url, intptr_t line);
void RegisterSourceBreakpoint(SourceBreakpoint* bpt);
void UnlinkCodeBreakpoints(BreakpointLocation* bpt_location);
BreakpointLocation* GetLatentBreakpoint(const String& url, intptr_t line);
void RegisterBreakpointLocation(BreakpointLocation* bpt);
void RegisterCodeBreakpoint(CodeBreakpoint* bpt);
SourceBreakpoint* GetSourceBreakpoint(const Script& script,
intptr_t token_pos);
BreakpointLocation* GetBreakpointLocation(const Script& script,
intptr_t token_pos);
void MakeCodeBreakpointAt(const Function& func,
SourceBreakpoint* bpt);
BreakpointLocation* bpt);
// Returns NULL if no breakpoint exists for the given address.
CodeBreakpoint* GetCodeBreakpoint(uword breakpoint_address);
void SyncBreakpoint(SourceBreakpoint* bpt);
void SyncBreakpointLocation(BreakpointLocation* loc);
ActivationFrame* TopDartFrame() const;
static ActivationFrame* CollectDartFrame(Isolate* isolate,
@ -504,9 +569,9 @@ class Debugger {
StackFrame* frame,
const Code& code);
static DebuggerStackTrace* CollectStackTrace();
void SignalBpResolved(SourceBreakpoint *bpt);
void SignalBpResolved(Breakpoint *bpt);
void SignalPausedEvent(ActivationFrame* top_frame,
SourceBreakpoint* bpt);
Breakpoint* bpt);
intptr_t nextId() { return next_id_++; }
@ -531,8 +596,8 @@ class Debugger {
// ID number generator.
intptr_t next_id_;
SourceBreakpoint* latent_breakpoints_;
SourceBreakpoint* src_breakpoints_;
BreakpointLocation* latent_locations_;
BreakpointLocation* breakpoint_locations_;
CodeBreakpoint* code_breakpoints_;
// Tells debugger what to do when resuming execution after a breakpoint.
@ -565,7 +630,7 @@ class Debugger {
static EventHandler* event_handler_;
friend class Isolate;
friend class SourceBreakpoint;
friend class BreakpointLocation;
DISALLOW_COPY_AND_ASSIGN(Debugger);
};

View file

@ -130,13 +130,13 @@ static void DebuggerEventHandler(DebuggerEvent* event) {
}
} else if (event->type() == DebuggerEvent::kBreakpointResolved) {
if (bp_resolved_handler != NULL) {
SourceBreakpoint* bpt = event->breakpoint();
Breakpoint* bpt = event->breakpoint();
ASSERT(bpt != NULL);
Dart_CodeLocation location;
Library& library = Library::Handle(isolate);
Script& script = Script::Handle(isolate);
intptr_t token_pos;
bpt->GetCodeLocation(&library, &script, &token_pos);
bpt->bpt_location()->GetCodeLocation(&library, &script, &token_pos);
location.script_url = Api::NewHandle(isolate, script.url());
location.library_id = library.index();
location.token_pos = token_pos;
@ -341,7 +341,7 @@ DART_EXPORT Dart_Handle Dart_SetBreakpoint(
Debugger* debugger = isolate->debugger();
ASSERT(debugger != NULL);
SourceBreakpoint* bpt =
Breakpoint* bpt =
debugger->SetBreakpointAtLine(script_url, line_number);
if (bpt == NULL) {
return Api::NewError("%s: could not set breakpoint at line %" Pd " in '%s'",
@ -357,12 +357,12 @@ DART_EXPORT Dart_Handle Dart_GetBreakpointURL(intptr_t bp_id) {
Debugger* debugger = isolate->debugger();
ASSERT(debugger != NULL);
SourceBreakpoint* bpt = debugger->GetBreakpointById(bp_id);
Breakpoint* bpt = debugger->GetBreakpointById(bp_id);
if (bpt == NULL) {
return Api::NewError("%s: breakpoint with id %" Pd " does not exist",
CURRENT_FUNC, bp_id);
}
return Api::NewHandle(isolate, bpt->url());
return Api::NewHandle(isolate, bpt->bpt_location()->url());
}
@ -372,12 +372,12 @@ DART_EXPORT Dart_Handle Dart_GetBreakpointLine(intptr_t bp_id) {
Debugger* debugger = isolate->debugger();
ASSERT(debugger != NULL);
SourceBreakpoint* bpt = debugger->GetBreakpointById(bp_id);
Breakpoint* bpt = debugger->GetBreakpointById(bp_id);
if (bpt == NULL) {
return Api::NewError("%s: breakpoint with id %" Pd " does not exist",
CURRENT_FUNC, bp_id);
}
return Dart_NewInteger(bpt->LineNumber());
return Dart_NewInteger(bpt->bpt_location()->LineNumber());
}
@ -411,7 +411,7 @@ DART_EXPORT Dart_Handle Dart_SetBreakpointAtEntry(
function_name.ToCString());
}
SourceBreakpoint* bpt = debugger->SetBreakpointAtEntry(bp_target);
Breakpoint* bpt = debugger->SetBreakpointAtEntry(bp_target, false);
if (bpt == NULL) {
const char* target_name = Debugger::QualifiedFunctionName(bp_target);
return Api::NewError("%s: no breakpoint location found in '%s'",

View file

@ -327,7 +327,7 @@ void JSONStream::PrintValue(const Object& o, bool ref) {
}
void JSONStream::PrintValue(SourceBreakpoint* bpt) {
void JSONStream::PrintValue(Breakpoint* bpt) {
PrintCommaIfNeeded();
bpt->PrintJSON(this);
}
@ -415,7 +415,7 @@ void JSONStream::PrintProperty(const char* name, const ServiceEvent* event) {
}
void JSONStream::PrintProperty(const char* name, SourceBreakpoint* bpt) {
void JSONStream::PrintProperty(const char* name, Breakpoint* bpt) {
PrintPropertyName(name);
PrintValue(bpt);
}

View file

@ -22,7 +22,7 @@ class MessageQueue;
class Metric;
class Object;
class ServiceEvent;
class SourceBreakpoint;
class Breakpoint;
class String;
class Zone;
@ -115,7 +115,7 @@ class JSONStream : ValueObject {
void PrintValueNoEscape(const char* s);
void PrintfValue(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
void PrintValue(const Object& o, bool ref = true);
void PrintValue(SourceBreakpoint* bpt);
void PrintValue(Breakpoint* bpt);
void PrintValue(const ServiceEvent* event);
void PrintValue(Metric* metric);
void PrintValue(MessageQueue* queue);
@ -135,7 +135,7 @@ class JSONStream : ValueObject {
void PrintProperty(const char* name, const Object& o, bool ref = true);
void PrintProperty(const char* name, const ServiceEvent* event);
void PrintProperty(const char* name, SourceBreakpoint* bpt);
void PrintProperty(const char* name, Breakpoint* bpt);
void PrintProperty(const char* name, Metric* metric);
void PrintProperty(const char* name, MessageQueue* queue);
void PrintProperty(const char* name, Isolate* isolate);
@ -216,7 +216,7 @@ class JSONObject : public ValueObject {
void AddProperty(const char* name, const ServiceEvent* event) const {
stream_->PrintProperty(name, event);
}
void AddProperty(const char* name, SourceBreakpoint* bpt) const {
void AddProperty(const char* name, Breakpoint* bpt) const {
stream_->PrintProperty(name, bpt);
}
void AddProperty(const char* name, Metric* metric) const {
@ -267,7 +267,7 @@ class JSONArray : public ValueObject {
void AddValue(Isolate* isolate, bool ref = true) const {
stream_->PrintValue(isolate, ref);
}
void AddValue(SourceBreakpoint* bpt) const {
void AddValue(Breakpoint* bpt) const {
stream_->PrintValue(bpt);
}
void AddValue(const ServiceEvent* event) const {

View file

@ -4182,7 +4182,7 @@ TEST_CASE(FunctionWithBreakpointNotInlined) {
EXPECT(func_b.CanBeInlined());
// After setting a breakpoint in a function A.b, it is no longer inlineable.
SourceBreakpoint* bpt =
Breakpoint* bpt =
Isolate::Current()->debugger()->SetBreakpointAtLine(name,
kBreakpointLine);
ASSERT(bpt != NULL);

View file

@ -1196,7 +1196,7 @@ static void PrintSentinel(JSONStream* js, SentinelType sentinel_type) {
}
static SourceBreakpoint* LookupBreakpoint(Isolate* isolate, const char* id) {
static Breakpoint* LookupBreakpoint(Isolate* isolate, const char* id) {
size_t end_pos = strcspn(id, "/");
if (end_pos == strlen(id)) {
return NULL;
@ -1204,7 +1204,7 @@ static SourceBreakpoint* LookupBreakpoint(Isolate* isolate, const char* id) {
const char* rest = id + end_pos + 1; // +1 for '/'.
if (strncmp("breakpoints", id, end_pos) == 0) {
intptr_t bpt_id = 0;
SourceBreakpoint* bpt = NULL;
Breakpoint* bpt = NULL;
if (GetIntegerId(rest, &bpt_id)) {
bpt = isolate->debugger()->GetBreakpointById(bpt_id);
}
@ -1808,7 +1808,7 @@ static bool AddBreakpoint(Isolate* isolate, JSONStream* js) {
}
const Script& script = Script::Cast(obj);
const String& script_url = String::Handle(script.url());
SourceBreakpoint* bpt =
Breakpoint* bpt =
isolate->debugger()->SetBreakpointAtLine(script_url, line);
if (bpt == NULL) {
js->PrintError(kNoBreakAtLine, NULL);
@ -1834,8 +1834,34 @@ static bool AddBreakpointAtEntry(Isolate* isolate, JSONStream* js) {
return true;
}
const Function& function = Function::Cast(obj);
SourceBreakpoint* bpt =
isolate->debugger()->SetBreakpointAtEntry(function);
Breakpoint* bpt =
isolate->debugger()->SetBreakpointAtEntry(function, false);
if (bpt == NULL) {
js->PrintError(kNoBreakAtFunction, NULL);
return true;
}
bpt->PrintJSON(js);
return true;
}
static const MethodParameter* add_breakpoint_at_activation_params[] = {
ISOLATE_PARAMETER,
new IdParameter("objectId", true),
NULL,
};
static bool AddBreakpointAtActivation(Isolate* isolate, JSONStream* js) {
const char* object_id = js->LookupParam("objectId");
Object& obj = Object::Handle(LookupHeapObject(isolate, object_id, NULL));
if (obj.raw() == Object::sentinel().raw() || !obj.IsInstance()) {
PrintInvalidParamError(js, "objectId");
return true;
}
const Instance& closure = Instance::Cast(obj);
Breakpoint* bpt =
isolate->debugger()->SetBreakpointAtActivation(closure);
if (bpt == NULL) {
js->PrintError(kNoBreakAtFunction, NULL);
return true;
@ -1857,7 +1883,7 @@ static bool RemoveBreakpoint(Isolate* isolate, JSONStream* js) {
return true;
}
const char* bpt_id = js->LookupParam("breakpointId");
SourceBreakpoint* bpt = LookupBreakpoint(isolate, bpt_id);
Breakpoint* bpt = LookupBreakpoint(isolate, bpt_id);
if (bpt == NULL) {
fprintf(stderr, "ERROR1");
PrintInvalidParamError(js, "breakpointId");
@ -2402,7 +2428,7 @@ static bool GetObject(Isolate* isolate, JSONStream* js) {
}
// Handle non-heap objects.
SourceBreakpoint* bpt = LookupBreakpoint(isolate, id);
Breakpoint* bpt = LookupBreakpoint(isolate, id);
if (bpt != NULL) {
bpt->PrintJSON(js);
return true;
@ -2592,6 +2618,8 @@ static ServiceMethodDescriptor service_methods_[] = {
add_breakpoint_params },
{ "addBreakpointAtEntry", AddBreakpointAtEntry,
add_breakpoint_at_entry_params },
{ "_addBreakpointAtActivation", AddBreakpointAtActivation,
add_breakpoint_at_activation_params },
{ "clearCpuProfile", ClearCpuProfile,
clear_cpu_profile_params },
{ "evaluate", Evaluate,

View file

@ -50,10 +50,10 @@ class ServiceEvent {
EventType type() const { return type_; }
SourceBreakpoint* breakpoint() const {
Breakpoint* breakpoint() const {
return breakpoint_;
}
void set_breakpoint(SourceBreakpoint* bpt) {
void set_breakpoint(Breakpoint* bpt) {
ASSERT(type() == kPauseBreakpoint ||
type() == kBreakpointAdded ||
type() == kBreakpointResolved ||
@ -103,7 +103,7 @@ class ServiceEvent {
private:
Isolate* isolate_;
EventType type_;
SourceBreakpoint* breakpoint_;
Breakpoint* breakpoint_;
ActivationFrame* top_frame_;
const Object* exception_;
const Object* inspectee_;