[inspector] added type of break location into getPossibleBreakpoints output

This CL provide type with each break location, type could be: call, return or debugger statement.

BUG=chromium:432469
R=yangguo@chromium.org,dgozman@chromium.org

Review-Url: https://codereview.chromium.org/2728563002
Cr-Commit-Position: refs/heads/master@{#43619}
This commit is contained in:
kozyatinskiy 2017-03-06 12:47:55 -08:00 committed by Commit bot
parent a3923ce210
commit 562da35614
16 changed files with 312 additions and 203 deletions

View File

@ -9212,11 +9212,17 @@ namespace {
int GetSmiValue(i::Handle<i::FixedArray> array, int index) {
return i::Smi::cast(array->get(index))->value();
}
bool CompareBreakLocation(const i::BreakLocation& loc1,
const i::BreakLocation& loc2) {
return loc1.position() < loc2.position();
}
} // namespace
bool debug::Script::GetPossibleBreakpoints(
const debug::Location& start, const debug::Location& end,
bool restrict_to_function, std::vector<debug::Location>* locations) const {
bool restrict_to_function,
std::vector<debug::BreakLocation>* locations) const {
CHECK(!start.IsEmpty());
i::Handle<i::Script> script = Utils::OpenHandle(this);
if (script->type() == i::Script::TYPE_WASM) {
@ -9238,15 +9244,17 @@ bool debug::Script::GetPossibleBreakpoints(
: GetSourceOffset(end);
if (start_offset >= end_offset) return true;
std::set<int> offsets;
std::vector<i::BreakLocation> v8_locations;
if (!isolate->debug()->GetPossibleBreakpoints(
script, start_offset, end_offset, restrict_to_function, &offsets)) {
script, start_offset, end_offset, restrict_to_function,
&v8_locations)) {
return false;
}
std::sort(v8_locations.begin(), v8_locations.end(), CompareBreakLocation);
int current_line_end_index = 0;
for (const auto& it : offsets) {
int offset = it;
for (const auto& v8_location : v8_locations) {
int offset = v8_location.position();
while (offset > GetSmiValue(line_ends, current_line_end_index)) {
++current_line_end_index;
CHECK(current_line_end_index < line_ends->length());
@ -9256,10 +9264,11 @@ bool debug::Script::GetPossibleBreakpoints(
if (current_line_end_index > 0) {
line_offset = GetSmiValue(line_ends, current_line_end_index - 1) + 1;
}
locations->push_back(debug::Location(
locations->emplace_back(
current_line_end_index + script->line_offset(),
offset - line_offset +
(current_line_end_index == 0 ? script->column_offset() : 0)));
(current_line_end_index == 0 ? script->column_offset() : 0),
v8_location.type());
}
return true;
}

View File

@ -136,10 +136,10 @@ class V8_EXPORT_PRIVATE Script {
MaybeLocal<String> Source() const;
bool IsWasm() const;
bool IsModule() const;
bool GetPossibleBreakpoints(const debug::Location& start,
const debug::Location& end,
bool restrict_to_function,
std::vector<debug::Location>* locations) const;
bool GetPossibleBreakpoints(
const debug::Location& start, const debug::Location& end,
bool restrict_to_function,
std::vector<debug::BreakLocation>* locations) const;
int GetSourceOffset(const debug::Location& location) const;
v8::debug::Location GetSourceLocation(int offset) const;
};

View File

@ -125,6 +125,20 @@ bool BreakLocation::HasBreakPoint(Handle<DebugInfo> debug_info) const {
}
}
debug::BreakLocationType BreakLocation::type() const {
switch (type_) {
case DEBUGGER_STATEMENT:
return debug::kDebuggerStatementBreakLocation;
case DEBUG_BREAK_SLOT_AT_CALL:
return debug::kCallBreakLocation;
case DEBUG_BREAK_SLOT_AT_RETURN:
return debug::kReturnBreakLocation;
default:
return debug::kCommonBreakLocation;
}
return debug::kCommonBreakLocation;
}
std::unique_ptr<BreakIterator> BreakIterator::GetIterator(
Handle<DebugInfo> debug_info, Handle<AbstractCode> abstract_code) {
if (abstract_code->IsBytecodeArray()) {
@ -1315,36 +1329,32 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
namespace {
template <typename Iterator>
void GetBreakablePositions(Iterator* it, int start_position, int end_position,
BreakPositionAlignment alignment,
std::set<int>* positions) {
it->SkipToPosition(start_position, alignment);
std::vector<BreakLocation>* locations) {
it->SkipToPosition(start_position, BREAK_POSITION_ALIGNED);
while (!it->Done() && it->position() < end_position &&
it->position() >= start_position) {
positions->insert(alignment == STATEMENT_ALIGNED ? it->statement_position()
: it->position());
locations->push_back(it->GetBreakLocation());
it->Next();
}
}
void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position,
int end_position, BreakPositionAlignment alignment,
std::set<int>* positions) {
int end_position,
std::vector<BreakLocation>* locations) {
if (debug_info->HasDebugCode()) {
CodeBreakIterator it(debug_info);
GetBreakablePositions(&it, start_position, end_position, alignment,
positions);
GetBreakablePositions(&it, start_position, end_position, locations);
} else {
DCHECK(debug_info->HasDebugBytecodeArray());
BytecodeArrayBreakIterator it(debug_info);
GetBreakablePositions(&it, start_position, end_position, alignment,
positions);
GetBreakablePositions(&it, start_position, end_position, locations);
}
}
} // namespace
bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
int end_position, bool restrict_to_function,
std::set<int>* positions) {
std::vector<BreakLocation>* locations) {
if (restrict_to_function) {
Handle<Object> result =
FindSharedFunctionInfoInScript(script, start_position);
@ -1356,8 +1366,7 @@ bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
if (!EnsureDebugInfo(shared)) return false;
Handle<DebugInfo> debug_info(shared->GetDebugInfo());
FindBreakablePositions(debug_info, start_position, end_position,
BREAK_POSITION_ALIGNED, positions);
FindBreakablePositions(debug_info, start_position, end_position, locations);
return true;
}
@ -1395,7 +1404,7 @@ bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
CHECK(candidates[i]->HasDebugInfo());
Handle<DebugInfo> debug_info(candidates[i]->GetDebugInfo());
FindBreakablePositions(debug_info, start_position, end_position,
BREAK_POSITION_ALIGNED, positions);
locations);
}
return true;
}

View File

@ -88,6 +88,8 @@ class BreakLocation {
inline int position() const { return position_; }
debug::BreakLocationType type() const;
private:
BreakLocation(Handle<AbstractCode> abstract_code, DebugBreakType type,
int code_offset, int position)
@ -313,7 +315,7 @@ class Debug {
bool PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared);
bool GetPossibleBreakpoints(Handle<Script> script, int start_position,
int end_position, bool restrict_to_function,
std::set<int>* positions);
std::vector<BreakLocation>* locations);
void RecordGenerator(Handle<JSGeneratorObject> generator_object);

View File

@ -50,6 +50,7 @@ struct WasmDisassemblyOffsetTableEntry {
int line;
int column;
};
struct WasmDisassembly {
using OffsetTable = std::vector<WasmDisassemblyOffsetTableEntry>;
WasmDisassembly() {}
@ -71,6 +72,24 @@ enum PromiseDebugActionType {
kDebugDidHandle,
};
enum BreakLocationType {
kCallBreakLocation,
kReturnBreakLocation,
kDebuggerStatementBreakLocation,
kCommonBreakLocation
};
class V8_EXPORT_PRIVATE BreakLocation : public Location {
public:
BreakLocation(int line_number, int column_number, BreakLocationType type)
: Location(line_number, column_number), type_(type) {}
BreakLocationType type() const { return type_; }
private:
BreakLocationType type_;
};
} // namespace debug
} // namespace v8

View File

@ -471,6 +471,17 @@
{ "name": "lineContent", "type": "string", "description": "Line with match content." }
],
"experimental": true
},
{
"id": "BreakLocation",
"type": "object",
"properties": [
{ "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Script identifier as reported in the <code>Debugger.scriptParsed</code>." },
{ "name": "lineNumber", "type": "integer", "description": "Line number in the script (0-based)." },
{ "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script (0-based)." },
{ "name": "type", "type": "string", "enum": [ "debuggerStatement", "call", "return" ], "optional": true }
],
"experimental": true
}
],
"commands": [
@ -538,7 +549,7 @@
{ "name": "restrictToFunction", "type": "boolean", "optional": true, "description": "Only consider locations which are in the same (non-nested) function as start." }
],
"returns": [
{ "name": "locations", "type": "array", "items": { "$ref": "Location" }, "description": "List of the possible breakpoint locations." }
{ "name": "locations", "type": "array", "items": { "$ref": "BreakLocation" }, "description": "List of the possible breakpoint locations." }
],
"description": "Returns possible locations for breakpoint. scriptId in start and end range locations should be the same.",
"experimental": true

View File

@ -171,6 +171,21 @@ void adjustBreakpointLocation(const V8DebuggerScript& script,
breakpoint->line_number = hintPosition.GetLineNumber();
breakpoint->column_number = hintPosition.GetColumnNumber();
}
String16 breakLocationType(v8::debug::BreakLocationType type) {
switch (type) {
case v8::debug::kCallBreakLocation:
return protocol::Debugger::BreakLocation::TypeEnum::Call;
case v8::debug::kReturnBreakLocation:
return protocol::Debugger::BreakLocation::TypeEnum::Return;
case v8::debug::kDebuggerStatementBreakLocation:
return protocol::Debugger::BreakLocation::TypeEnum::DebuggerStatement;
case v8::debug::kCommonBreakLocation:
return String16();
}
return String16();
}
} // namespace
V8DebuggerAgentImpl::V8DebuggerAgentImpl(
@ -420,7 +435,8 @@ void V8DebuggerAgentImpl::removeBreakpointImpl(const String16& breakpointId) {
Response V8DebuggerAgentImpl::getPossibleBreakpoints(
std::unique_ptr<protocol::Debugger::Location> start,
Maybe<protocol::Debugger::Location> end, Maybe<bool> restrictToFunction,
std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations) {
std::unique_ptr<protocol::Array<protocol::Debugger::BreakLocation>>*
locations) {
String16 scriptId = start->getScriptId();
if (start->getLineNumber() < 0 || start->getColumnNumber(0) < 0)
@ -443,19 +459,24 @@ Response V8DebuggerAgentImpl::getPossibleBreakpoints(
auto it = m_scripts.find(scriptId);
if (it == m_scripts.end()) return Response::Error("Script not found");
std::vector<v8::debug::Location> v8Locations;
std::vector<v8::debug::BreakLocation> v8Locations;
if (!it->second->getPossibleBreakpoints(
v8Start, v8End, restrictToFunction.fromMaybe(false), &v8Locations))
v8Start, v8End, restrictToFunction.fromMaybe(false), &v8Locations)) {
return Response::InternalError();
}
*locations = protocol::Array<protocol::Debugger::Location>::create();
*locations = protocol::Array<protocol::Debugger::BreakLocation>::create();
for (size_t i = 0; i < v8Locations.size(); ++i) {
(*locations)
->addItem(protocol::Debugger::Location::create()
.setScriptId(scriptId)
.setLineNumber(v8Locations[i].GetLineNumber())
.setColumnNumber(v8Locations[i].GetColumnNumber())
.build());
std::unique_ptr<protocol::Debugger::BreakLocation> breakLocation =
protocol::Debugger::BreakLocation::create()
.setScriptId(scriptId)
.setLineNumber(v8Locations[i].GetLineNumber())
.setColumnNumber(v8Locations[i].GetColumnNumber())
.build();
if (v8Locations[i].type() != v8::debug::kCommonBreakLocation) {
breakLocation->setType(breakLocationType(v8Locations[i].type()));
}
(*locations)->addItem(std::move(breakLocation));
}
return Response::OK();
}

View File

@ -67,8 +67,8 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
Response getPossibleBreakpoints(
std::unique_ptr<protocol::Debugger::Location> start,
Maybe<protocol::Debugger::Location> end, Maybe<bool> restrictToFunction,
std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations)
override;
std::unique_ptr<protocol::Array<protocol::Debugger::BreakLocation>>*
locations) override;
Response setScriptSource(
const String16& inScriptId, const String16& inScriptSource,
Maybe<bool> dryRun,

View File

@ -155,11 +155,40 @@ class ActualScript : public V8DebuggerScript {
bool getPossibleBreakpoints(
const v8::debug::Location& start, const v8::debug::Location& end,
bool restrictToFunction,
std::vector<v8::debug::Location>* locations) override {
std::vector<v8::debug::BreakLocation>* locations) override {
v8::HandleScope scope(m_isolate);
v8::Local<v8::debug::Script> script = m_script.Get(m_isolate);
return script->GetPossibleBreakpoints(start, end, restrictToFunction,
locations);
std::vector<v8::debug::BreakLocation> allLocations;
if (!script->GetPossibleBreakpoints(start, end, restrictToFunction,
&allLocations)) {
return false;
}
if (!allLocations.size()) return true;
v8::debug::BreakLocation current = allLocations[0];
for (size_t i = 1; i < allLocations.size(); ++i) {
if (allLocations[i].GetLineNumber() == current.GetLineNumber() &&
allLocations[i].GetColumnNumber() == current.GetColumnNumber()) {
if (allLocations[i].type() != v8::debug::kCommonBreakLocation) {
DCHECK(allLocations[i].type() == v8::debug::kCallBreakLocation ||
allLocations[i].type() == v8::debug::kReturnBreakLocation);
// debugger can returns more then one break location at the same
// source location, e.g. foo() - in this case there are two break
// locations before foo: for statement and for function call, we can
// merge them for inspector and report only one with call type.
current = allLocations[i];
}
} else {
// we assume that returned break locations are sorted.
DCHECK(
allLocations[i].GetLineNumber() > current.GetLineNumber() ||
(allLocations[i].GetColumnNumber() >= current.GetColumnNumber() &&
allLocations[i].GetLineNumber() == current.GetLineNumber()));
locations->push_back(current);
current = allLocations[i];
}
}
locations->push_back(current);
return true;
}
void resetBlackboxedStateCache() override {
@ -223,7 +252,7 @@ class WasmVirtualScript : public V8DebuggerScript {
bool getPossibleBreakpoints(
const v8::debug::Location& start, const v8::debug::Location& end,
bool restrictToFunction,
std::vector<v8::debug::Location>* locations) override {
std::vector<v8::debug::BreakLocation>* locations) override {
v8::HandleScope scope(m_isolate);
v8::Local<v8::debug::Script> script = m_script.Get(m_isolate);
String16 v8ScriptId = String16::fromInteger(script->Id());
@ -244,7 +273,7 @@ class WasmVirtualScript : public V8DebuggerScript {
bool success = script->GetPossibleBreakpoints(
translatedStart, translatedEnd, restrictToFunction, locations);
for (v8::debug::Location& loc : *locations) {
for (v8::debug::BreakLocation& loc : *locations) {
TranslateV8LocationToProtocolLocation(m_wasmTranslation, &loc, v8ScriptId,
scriptId());
}

View File

@ -79,7 +79,7 @@ class V8DebuggerScript {
virtual bool getPossibleBreakpoints(
const v8::debug::Location& start, const v8::debug::Location& end,
bool ignoreNestedFunctions,
std::vector<v8::debug::Location>* locations) = 0;
std::vector<v8::debug::BreakLocation>* locations) = 0;
virtual void resetBlackboxedStateCache() = 0;
static const int kNoOffset = -1;

View File

@ -1041,7 +1041,7 @@ v8::debug::WasmDisassembly WasmCompiledModule::DisassembleFunction(
bool WasmCompiledModule::GetPossibleBreakpoints(
const v8::debug::Location& start, const v8::debug::Location& end,
std::vector<v8::debug::Location>* locations) {
std::vector<v8::debug::BreakLocation>* locations) {
DisallowHeapAllocation no_gc;
std::vector<WasmFunction>& functions = module()->functions;
@ -1104,7 +1104,7 @@ bool WasmCompiledModule::GetPossibleBreakpoints(
break;
}
if (total_offset < start_offset) continue;
locations->push_back(v8::debug::Location(func_idx, offset));
locations->emplace_back(func_idx, offset, debug::kCommonBreakLocation);
}
}
return true;

View File

@ -385,7 +385,7 @@ class WasmCompiledModule : public FixedArray {
// Get a list of all possible breakpoints within a given range of this module.
bool GetPossibleBreakpoints(const debug::Location& start,
const debug::Location& end,
std::vector<debug::Location>* locations);
std::vector<debug::BreakLocation>* locations);
// Set a breakpoint on the given byte position inside the given module.
// This will affect all live and future instances of the module.

View File

@ -25,7 +25,7 @@ void CheckLocations(
WasmCompiledModule *compiled_module, debug::Location start,
debug::Location end,
std::initializer_list<debug::Location> expected_locations_init) {
std::vector<debug::Location> locations;
std::vector<debug::BreakLocation> locations;
bool success =
compiled_module->GetPossibleBreakpoints(start, end, &locations);
CHECK(success);
@ -48,7 +48,7 @@ void CheckLocations(
}
void CheckLocationsFail(WasmCompiledModule *compiled_module,
debug::Location start, debug::Location end) {
std::vector<debug::Location> locations;
std::vector<debug::BreakLocation> locations;
bool success =
compiled_module->GetPossibleBreakpoints(start, end, &locations);
CHECK(!success);

View File

@ -16,11 +16,13 @@
columnNumber : 7
lineNumber : 0
scriptId : <scriptId>
type : return
}
[3] : {
columnNumber : 8
lineNumber : 0
scriptId : <scriptId>
type : return
}
]
}

View File

@ -4,267 +4,267 @@ Checks Debugger.getPossibleBreakpoints
// found in the LICENSE file.
function testEval() {
#eval('// comment only');
#eval('// comment only\n');
#}
|C|eval('// comment only');
|C|eval('// comment only\n');
|R|}
// function without return
function procedure() {
var a = #1;
var b = #2;
#}
var a = |_|1;
var b = |_|2;
|R|}
function testProcedure() {
#procedure();
#}
|C|procedure();
|R|}
function returnTrue() {
#return true;
#}
|_|return true;
|R|}
function testIf() {
var a;
#if (true) #a = true;
#if (!a) {
#a = true;
|_|if (true) |_|a = true;
|_|if (!a) {
|_|a = true;
} else {
#a = false;
|_|a = false;
}
#if (#returnTrue()) {
#a = false;
|_|if (|C|returnTrue()) {
|_|a = false;
} else {
#a = true;
|_|a = true;
}
#}
|R|}
function emptyFunction() {#}
function emptyFunction() {|R|}
function testEmptyFunction() {
#emptyFunction();
#}
|C|emptyFunction();
|R|}
function twoArguments(a1, a2) {
#}
|R|}
function testCallArguments() {
#twoArguments(#emptyFunction(), #emptyFunction());
#}
|C|twoArguments(|C|emptyFunction(), |C|emptyFunction());
|R|}
function testNested() {
function nested1() {
function nested2() {
function nested3() {
#}
#nested3();
#return;
#}
#return #nested2();
#}
#nested1();
#}
|R|}
|C|nested3();
|_|return;
|R|}
|_|return |C|nested2();
|R|}
|C|nested1();
|R|}
function return42() {
#return 42;
#}
|_|return 42;
|R|}
function returnCall() {
#return #return42();
#}
|_|return |C|return42();
|R|}
function testCallAtReturn() {
#return #returnCall();
#}
|_|return |C|returnCall();
|R|}
function returnObject() {
#return ({ foo: () => #42# });
#}
|_|return ({ foo: () => |_|42|R| });
|R|}
function testWith() {
#with (#returnObject()) {
#foo();
|_|with (|C|returnObject()) {
|C|foo();
}
#with({}) {
#return;
|_|with({}) {
|_|return;
}
#}
|R|}
function testForLoop() {
for (var i = #0; i #< 1; ++#i) {}
for (var i = #0; i #< 1; ++#i) #i;
for (var i = #0; i #< 0; ++#i) {}
#}
for (var i = |_|0; i |_|< 1; ++|_|i) {}
for (var i = |_|0; i |_|< 1; ++|_|i) |_|i;
for (var i = |_|0; i |_|< 0; ++|_|i) {}
|R|}
function testForOfLoop() {
for (var k #of []) {}
for (var k #of #[1]) #k;
var a = #[];
for (var k #of #a) {}
#}
for (var k |C|of []) {}
for (var k |C|of |_|[1]) |_|k;
var a = |_|[];
for (var k |C|of |_|a) {}
|R|}
function testForInLoop() {
var o = #{};
for (var #k in #o) {}
for (var #k in #o) #k;
for (var #k in #{ a:1 }) {}
for (var #k in #{ a:1 }) #k;
#}
var o = |_|{};
for (var |_|k in |_|o) {}
for (var |_|k in |_|o) |_|k;
for (var |_|k in |_|{ a:1 }) {}
for (var |_|k in |_|{ a:1 }) |_|k;
|R|}
function testSimpleExpressions() {
#1 + 2 + 3;
var a = #1;
#++a;
#a--;
#}
|_|1 + 2 + 3;
var a = |_|1;
|_|++a;
|_|a--;
|R|}
Object.defineProperty(this, 'getterFoo', {
get: () => #return42#
get: () => |_|return42|R|
});
function testGetter() {
#getterFoo();
#}
|C|getterFoo();
|R|}
var obj = {
foo: () => (#{
boo: () => #return42#
})#
foo: () => (|_|{
boo: () => |_|return42|R|
})|R|
};
function testChainedCalls() {
#obj.#foo().#boo()#();
#}
|_|obj.|C|foo().|C|boo()|C|();
|R|}
function testChainedWithNative() {
#Array.#from([1]).#concat([2]).#map(v => v #* 2#);
#}
|_|Array.|C|from([1]).|C|concat([2]).|C|map(v => v |_|* 2|R|);
|R|}
function testPromiseThen() {
#return Promise.#resolve().#then(v => v #* 2#).#then(v => v #* 2#);
#}
|_|return Promise.|C|resolve().|C|then(v => v |_|* 2|R|).|C|then(v => v |_|* 2|R|);
|R|}
function testSwitch() {
for (var i = #0; i #< 3; ++#i) {
#switch(i) {
case 0: #continue;
case 1: #return42(); #break;
default: #return;
for (var i = |_|0; i |_|< 3; ++|_|i) {
|_|switch(i) {
case 0: |_|continue;
case 1: |C|return42(); |_|break;
default: |_|return;
}
}
#}
|R|}
function* idMaker() {
#yield 1;
#yield 2;
#yield 3;
#}
|_|yield 1;
|_|yield 2;
|_|yield 3;
|R|}
function testGenerator() {
var gen = #idMaker();
#return42();
#gen.#next().value;
#debugger;
#gen.#next().value;
#return42();
#gen.#next().value;
#return42();
#gen.#next().value;
#}
var gen = |C|idMaker();
|C|return42();
|_|gen.|C|next().value;
|D|debugger;
|_|gen.|C|next().value;
|C|return42();
|_|gen.|C|next().value;
|C|return42();
|_|gen.|C|next().value;
|R|}
function throwException() {
#throw #new Error();
#}
|_|throw |C|new Error();
|R|}
function testCaughtException() {
try {
#throwException()
|C|throwException()
} catch (e) {
#return;
|_|return;
}
#}
|R|}
function testClasses() {
#class Cat {
|_|class Cat {
constructor(name) {
#this.name = name;
#}
|_|this.name = name;
|R|}
speak() {
#}
|R|}
}
#class Lion extends Cat {
|_|class Lion extends Cat {
constructor(name) {
#super(name);
#}
|C|super(name);
|R|}
speak() {
#super.#speak();
#}
|_|super.|C|speak();
|R|}
}
#new Lion().#speak();
#}
|C|new Lion().|C|speak();
|R|}
async function asyncFoo() {
#await Promise.resolve().then(v => v #* 2#);
#return42();
#await #asyncBoo();
#}
|_|await Promise.resolve().then(v => v |_|* 2|R|);
|C|return42();
|_|await |C|asyncBoo();
|R|}
async function asyncBoo() {
#await Promise.resolve();
#}
|_|await Promise.resolve();
|R|}
async function testAsyncAwait() {
#await asyncFoo();
#await #awaitBoo();
#}
|_|await asyncFoo();
|_|await |C|awaitBoo();
|R|}
// TODO(kozyatinskiy): fix this.
async function testPromiseAsyncWithCode() {
var nextTest;
var testPromise = #new Promise(resolve => nextTest #= resolve#);
var testPromise = |C|new Promise(resolve => nextTest |_|= resolve|R|);
async function main() {
async function foo() {
var resolveNested;
var p = #new Promise(resolve => resolveNested #= resolve#);
#setTimeout(resolveNested, 0);
#await #p;
#}
#setTimeout(returnCall, 0);
#await #foo();
#await #foo();
#nextTest();
#}
#main();
#return testPromise;
#}
var p = |C|new Promise(resolve => resolveNested |_|= resolve|R|);
|C|setTimeout(resolveNested, 0);
|_|await |_|p;
|R|}
|C|setTimeout(returnCall, 0);
|_|await |C|foo();
|_|await |C|foo();
|C|nextTest();
|R|}
|C|main();
|_|return testPromise;
|R|}
function returnFunction() {
#return returnObject;
#}
|_|return returnObject;
|R|}
async function testPromiseComplex() {
var nextTest;
var testPromise = #new Promise(resolve => nextTest #= resolve#);
var testPromise = |C|new Promise(resolve => nextTest |_|= resolve|R|);
async function main() {
async function foo() {
#await Promise.resolve();
#return 42;
#}
var x = #1;
var y = #2;
#returnFunction(#emptyFunction(), x++, --y, x => 2 #* x#, #returnCall())#().a = #await #foo((a => 2 #*a#)#(5));
#nextTest();
#}
#main();
#return testPromise;
#}
|_|await Promise.resolve();
|_|return 42;
|R|}
var x = |_|1;
var y = |_|2;
|C|returnFunction(|C|emptyFunction(), x++, --y, x => 2 |_|* x|R|, |C|returnCall())|C|().a = |_|await |C|foo((a => 2 |_|*a|R|)|C|(5));
|C|nextTest();
|R|}
|C|main();
|_|return testPromise;
|R|}
function twiceDefined() {
return a + b;
}
function twiceDefined() {
#return a + b;
#}
|_|return a + b;
|R|}

View File

@ -25,10 +25,17 @@ function dumpAllLocations(message) {
});
for (var location of locations) {
var line = lines[location.lineNumber];
line = line.slice(0, location.columnNumber) + '#' + line.slice(location.columnNumber);
line = line.slice(0, location.columnNumber) + locationMark(location.type) + line.slice(location.columnNumber);
lines[location.lineNumber] = line;
}
lines = lines.filter(line => line.indexOf('//# sourceURL=') === -1);
InspectorTest.log(lines.join('\n'));
return message;
}
function locationMark(type) {
if (type === 'return') return '|R|';
if (type === 'call') return '|C|';
if (type === 'debuggerStatement') return '|D|';
return '|_|';
}