Commit f0fb6583 authored by kozyatinskiy's avatar kozyatinskiy Committed by Commit bot

[inspector] added Debugger.getPossibleBreakpoints method

This method iterates through all shared function info which are related to passed script, compiles debug code for SFI in range if needed and returns possible break locations.

BUG=chromium:566801
CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_precise_blink_rel

Review-Url: https://codereview.chromium.org/2465553003
Cr-Commit-Position: refs/heads/master@{#40783}
parent efdc8ace
......@@ -8950,6 +8950,82 @@ MaybeLocal<String> DebugInterface::Script::Source() const {
handle_scope.CloseAndEscape(i::Handle<i::String>::cast(value)));
}
namespace {
int GetSmiValue(i::Handle<i::FixedArray> array, int index) {
return i::Smi::cast(array->get(index))->value();
}
} // namespace
bool DebugInterface::Script::GetPossibleBreakpoints(
const Location& start, const Location& end,
std::vector<Location>* locations) const {
CHECK(!start.IsEmpty());
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Script::InitLineEnds(script);
CHECK(script->line_ends()->IsFixedArray());
i::Isolate* isolate = script->GetIsolate();
i::Handle<i::FixedArray> line_ends =
i::Handle<i::FixedArray>::cast(i::handle(script->line_ends(), isolate));
CHECK(line_ends->length());
int start_offset = GetSourcePosition(start);
int end_offset;
if (end.IsEmpty()) {
end_offset = GetSmiValue(line_ends, line_ends->length() - 1) + 1;
} else {
end_offset = GetSourcePosition(end);
}
if (start_offset >= end_offset) return true;
std::set<int> offsets;
if (!isolate->debug()->GetPossibleBreakpoints(script, start_offset,
end_offset, &offsets)) {
return false;
}
int current_line_end_index = 0;
for (const auto& it : offsets) {
int offset = it;
while (offset > GetSmiValue(line_ends, current_line_end_index)) {
++current_line_end_index;
CHECK(current_line_end_index < line_ends->length());
}
int line_offset = 0;
if (current_line_end_index > 0) {
line_offset = GetSmiValue(line_ends, current_line_end_index - 1) + 1;
}
locations->push_back(Location(
current_line_end_index + script->line_offset(),
offset - line_offset +
(current_line_end_index == 0 ? script->column_offset() : 0)));
}
return true;
}
int DebugInterface::Script::GetSourcePosition(const Location& location) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
int line = std::max(location.GetLineNumber() - script->line_offset(), 0);
int column = location.GetColumnNumber();
if (line == 0) {
column = std::max(0, column - script->column_offset());
}
i::Script::InitLineEnds(script);
CHECK(script->line_ends()->IsFixedArray());
i::Handle<i::FixedArray> line_ends = i::Handle<i::FixedArray>::cast(
i::handle(script->line_ends(), script->GetIsolate()));
CHECK(line_ends->length());
if (line >= line_ends->length())
return GetSmiValue(line_ends, line_ends->length() - 1);
int line_offset = GetSmiValue(line_ends, line);
if (line == 0) return std::min(column, line_offset);
int prev_line_offset = GetSmiValue(line_ends, line - 1);
return std::min(prev_line_offset + column + 1, line_offset);
}
MaybeLocal<DebugInterface::Script> DebugInterface::Script::Wrap(
v8::Isolate* v8_isolate, v8::Local<v8::Object> script) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
......@@ -8968,6 +9044,28 @@ MaybeLocal<DebugInterface::Script> DebugInterface::Script::Wrap(
handle_scope.CloseAndEscape(script_obj));
}
DebugInterface::Location::Location(int lineNumber, int columnNumber)
: lineNumber_(lineNumber), columnNumber_(columnNumber) {
CHECK(lineNumber >= 0);
CHECK(columnNumber >= 0);
}
DebugInterface::Location::Location() : lineNumber_(-1), columnNumber_(-1) {}
int DebugInterface::Location::GetLineNumber() const {
CHECK(lineNumber_ >= 0);
return lineNumber_;
}
int DebugInterface::Location::GetColumnNumber() const {
CHECK(columnNumber_ >= 0);
return columnNumber_;
}
bool DebugInterface::Location::IsEmpty() const {
return lineNumber_ == -1 && columnNumber_ == -1;
}
void DebugInterface::GetLoadedScripts(
v8::Isolate* v8_isolate,
PersistentValueVector<DebugInterface::Script>& scripts) {
......
......@@ -140,6 +140,27 @@ class DebugInterface {
static void PrepareStep(Isolate* isolate, StepAction action);
static void ClearStepping(Isolate* isolate);
/**
* Defines location inside script.
* Lines and columns are 0-based.
*/
class Location {
public:
Location(int lineNumber, int columnNumber);
/**
* Create empty location.
*/
Location();
int GetLineNumber() const;
int GetColumnNumber() const;
bool IsEmpty() const;
private:
int lineNumber_;
int columnNumber_;
};
/**
* Native wrapper around v8::internal::Script object.
*/
......@@ -158,6 +179,8 @@ class DebugInterface {
MaybeLocal<String> SourceMappingURL() const;
MaybeLocal<String> ContextData() const;
MaybeLocal<String> Source() const;
bool GetPossibleBreakpoints(const Location& start, const Location& end,
std::vector<Location>* locations) const;
/**
* script parameter is a wrapper v8::internal::JSObject for
......@@ -169,6 +192,9 @@ class DebugInterface {
*/
static MaybeLocal<Script> Wrap(Isolate* isolate,
v8::Local<v8::Object> script);
private:
int GetSourcePosition(const Location& location) const;
};
/**
......
......@@ -1352,6 +1352,84 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
return true;
}
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);
while (!it->Done() && it->position() < end_position &&
it->position() >= start_position) {
positions->insert(alignment == STATEMENT_ALIGNED ? it->statement_position()
: it->position());
it->Next();
}
}
void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position,
int end_position, BreakPositionAlignment alignment,
std::set<int>* positions) {
if (debug_info->HasDebugCode()) {
CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
GetBreakablePositions(&it, start_position, end_position, alignment,
positions);
} else {
DCHECK(debug_info->HasDebugBytecodeArray());
BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS);
GetBreakablePositions(&it, start_position, end_position, alignment,
positions);
}
}
} // namespace
bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
int end_position, std::set<int>* positions) {
while (true) {
if (!script->shared_function_infos()->IsWeakFixedArray()) return false;
WeakFixedArray* infos =
WeakFixedArray::cast(script->shared_function_infos());
HandleScope scope(isolate_);
List<Handle<SharedFunctionInfo>> candidates;
{
WeakFixedArray::Iterator iterator(infos);
SharedFunctionInfo* info;
while ((info = iterator.Next<SharedFunctionInfo>())) {
if (info->end_position() < start_position ||
info->start_position() >= end_position) {
continue;
}
if (!info->IsSubjectToDebugging()) continue;
if (!info->HasDebugCode() && !info->allows_lazy_compilation()) continue;
candidates.Add(i::handle(info));
}
}
bool was_compiled = false;
for (int i = 0; i < candidates.length(); ++i) {
if (!candidates[i]->HasDebugCode()) {
if (!Compiler::CompileDebugCode(candidates[i])) {
return false;
} else {
was_compiled = true;
}
}
if (!candidates[i]->HasDebugInfo()) CreateDebugInfo(candidates[i]);
}
if (was_compiled) continue;
for (int i = 0; i < candidates.length(); ++i) {
CHECK(candidates[i]->HasDebugInfo());
Handle<DebugInfo> debug_info(candidates[i]->GetDebugInfo());
FindBreakablePositions(debug_info, start_position, end_position,
STATEMENT_ALIGNED, positions);
}
return true;
}
UNREACHABLE();
return false;
}
void Debug::RecordAsyncFunction(Handle<JSGeneratorObject> generator_object) {
if (last_step_action() <= StepOut) return;
if (!IsAsyncFunction(generator_object->function()->shared()->kind())) return;
......
......@@ -461,6 +461,8 @@ class Debug {
void ClearStepOut();
bool PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared);
bool GetPossibleBreakpoints(Handle<Script> script, int start_position,
int end_position, std::set<int>* positions);
void RecordAsyncFunction(Handle<JSGeneratorObject> generator_object);
......
......@@ -537,6 +537,18 @@
],
"description": "Removes JavaScript breakpoint."
},
{
"name": "getPossibleBreakpoints",
"parameters": [
{ "name": "start", "$ref": "Location", "description": "Start of range to search possible breakpoint locations in." },
{ "name": "end", "$ref": "Location", "optional": true, "description": "End of range to search possible breakpoint locations in (excluding). When not specifed, end of scripts is used as end of range." }
],
"returns": [
{ "name": "locations", "type": "array", "items": { "$ref": "Location" }, "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
},
{
"name": "continueToLocation",
"parameters": [
......
......@@ -349,6 +349,48 @@ void V8DebuggerAgentImpl::removeBreakpointImpl(const String16& breakpointId) {
m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId);
}
Response V8DebuggerAgentImpl::getPossibleBreakpoints(
std::unique_ptr<protocol::Debugger::Location> start,
Maybe<protocol::Debugger::Location> end,
std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations) {
String16 scriptId = start->getScriptId();
if (start->getLineNumber() < 0 || start->getColumnNumber(0) < 0)
return Response::Error(
"start.lineNumber and start.columnNumber should be >= 0");
v8::DebugInterface::Location v8Start(start->getLineNumber(),
start->getColumnNumber(0));
v8::DebugInterface::Location v8End;
if (end.isJust()) {
if (end.fromJust()->getScriptId() != scriptId)
return Response::Error("Locations should contain the same scriptId");
int line = end.fromJust()->getLineNumber();
int column = end.fromJust()->getColumnNumber(0);
if (line < 0 || column < 0)
return Response::Error(
"end.lineNumber and end.columnNumber should be >= 0");
v8End = v8::DebugInterface::Location(line, column);
}
auto it = m_scripts.find(scriptId);
if (it == m_scripts.end()) return Response::Error("Script not found");
std::vector<v8::DebugInterface::Location> v8Locations;
if (!it->second->getPossibleBreakpoints(v8Start, v8End, &v8Locations))
return Response::InternalError();
*locations = protocol::Array<protocol::Debugger::Location>::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());
}
return Response::OK();
}
Response V8DebuggerAgentImpl::continueToLocation(
std::unique_ptr<protocol::Debugger::Location> location) {
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
......@@ -509,7 +551,7 @@ Response V8DebuggerAgentImpl::setScriptSource(
if (!response.isSuccess() || compileError) return response;
ScriptsMap::iterator it = m_scripts.find(scriptId);
if (it != m_scripts.end()) it->second->setSource(m_isolate, newSource);
if (it != m_scripts.end()) it->second->setSource(newSource);
std::unique_ptr<Array<CallFrame>> callFrames;
response = currentCallFrames(&callFrames);
......
......@@ -71,6 +71,11 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex,
std::unique_ptr<protocol::Array<protocol::Debugger::SearchMatch>>*)
override;
Response getPossibleBreakpoints(
std::unique_ptr<protocol::Debugger::Location> start,
Maybe<protocol::Debugger::Location> end,
std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations)
override;
Response setScriptSource(
const String16& inScriptId, const String16& inScriptSource,
Maybe<bool> dryRun,
......
......@@ -70,6 +70,7 @@ static String16 calculateHash(const String16& str) {
V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate,
v8::Local<v8::DebugInterface::Script> script,
bool isLiveEdit) {
m_isolate = script->GetIsolate();
m_id = String16::fromInteger(script->Id());
v8::Local<v8::String> tmp;
if (script->Name().ToLocal(&tmp)) m_url = toProtocolString(tmp);
......@@ -113,8 +114,9 @@ V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate,
}
m_isLiveEdit = isLiveEdit;
if (script->Source().ToLocal(&tmp)) {
m_source.Reset(isolate, tmp);
m_source.Reset(m_isolate, tmp);
String16 source = toProtocolString(tmp);
m_hash = calculateHash(source);
// V8 will not count last line if script source ends with \n.
......@@ -123,6 +125,8 @@ V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate,
m_endColumn = 0;
}
}
m_script.Reset(m_isolate, script);
}
V8DebuggerScript::~V8DebuggerScript() {}
......@@ -143,10 +147,18 @@ void V8DebuggerScript::setSourceMappingURL(const String16& sourceMappingURL) {
m_sourceMappingURL = sourceMappingURL;
}
void V8DebuggerScript::setSource(v8::Isolate* isolate,
v8::Local<v8::String> source) {
m_source.Reset(isolate, source);
void V8DebuggerScript::setSource(v8::Local<v8::String> source) {
m_source.Reset(m_isolate, source);
m_hash = calculateHash(toProtocolString(source));
}
bool V8DebuggerScript::getPossibleBreakpoints(
const v8::DebugInterface::Location& start,
const v8::DebugInterface::Location& end,
std::vector<v8::DebugInterface::Location>* locations) {
v8::HandleScope scope(m_isolate);
v8::Local<v8::DebugInterface::Script> script = m_script.Get(m_isolate);
return script->GetPossibleBreakpoints(start, end, locations);
}
} // namespace v8_inspector
......@@ -64,7 +64,12 @@ class V8DebuggerScript {
void setSourceURL(const String16&);
void setSourceMappingURL(const String16&);
void setSource(v8::Isolate*, v8::Local<v8::String>);
void setSource(v8::Local<v8::String>);
bool getPossibleBreakpoints(
const v8::DebugInterface::Location& start,
const v8::DebugInterface::Location& end,
std::vector<v8::DebugInterface::Location>* locations);
private:
String16 m_id;
......@@ -81,6 +86,9 @@ class V8DebuggerScript {
String16 m_executionContextAuxData;
bool m_isLiveEdit;
v8::Isolate* m_isolate;
v8::Global<v8::DebugInterface::Script> m_script;
DISALLOW_COPY_AND_ASSIGN(V8DebuggerScript);
};
......
Test for Debugger.getPossibleBreakpoints
Running test: getPossibleBreakpointsInRange
Test start.scriptId != end.scriptId.
{
error : {
code : -32000
message : Locations should contain the same scriptId
}
id : <messageId>
}
Test not existing scriptId.
{
error : {
code : -32000
message : Script not found
}
id : <messageId>
}
Test end < start.
{
id : <messageId>
result : {
locations : [
]
}
}
Test empty range in first line.
{
id : <messageId>
result : {
locations : [
]
}
}
Test one character range in first line.
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 16
lineNumber : 0
scriptId : <scriptId>
}
]
}
}
Test empty range in not first line.
{
id : <messageId>
result : {
locations : [
]
}
}
Test one character range in not first line.
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 16
lineNumber : 1
scriptId : <scriptId>
}
]
}
}
Test end is undefined
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 16
lineNumber : 0
scriptId : <scriptId>
}
[1] : {
columnNumber : 42
lineNumber : 0
scriptId : <scriptId>
}
[2] : {
columnNumber : 16
lineNumber : 1
scriptId : <scriptId>
}
[3] : {
columnNumber : 49
lineNumber : 1
scriptId : <scriptId>
}
[4] : {
columnNumber : 53
lineNumber : 1
scriptId : <scriptId>
}
[5] : {
columnNumber : 57
lineNumber : 1
scriptId : <scriptId>
}
[6] : {
columnNumber : 0
lineNumber : 2
scriptId : <scriptId>
}
]
}
}
Test end.lineNumber > scripts.lineCount()
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 16
lineNumber : 0
scriptId : <scriptId>
}
[1] : {
columnNumber : 42
lineNumber : 0
scriptId : <scriptId>
}
[2] : {
columnNumber : 16
lineNumber : 1
scriptId : <scriptId>
}
[3] : {
columnNumber : 49
lineNumber : 1
scriptId : <scriptId>
}
[4] : {
columnNumber : 53
lineNumber : 1
scriptId : <scriptId>
}
[5] : {
columnNumber : 57
lineNumber : 1
scriptId : <scriptId>
}
[6] : {
columnNumber : 0
lineNumber : 2
scriptId : <scriptId>
}
]
}
}
Test one string
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 16
lineNumber : 0
scriptId : <scriptId>
}
[1] : {
columnNumber : 42
lineNumber : 0
scriptId : <scriptId>
}
]
}
}
Test end.columnNumber > end.line.length(), should be the same as previous.
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 16
lineNumber : 0
scriptId : <scriptId>
}
[1] : {
columnNumber : 42
lineNumber : 0
scriptId : <scriptId>
}
]
}
}
Running test: getPossibleBreakpointsInArrow
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 17
lineNumber : 0
scriptId : <scriptId>
}
[1] : {
columnNumber : 50
lineNumber : 0
scriptId : <scriptId>
}
[2] : {
columnNumber : 55
lineNumber : 0
scriptId : <scriptId>
}
[3] : {
columnNumber : 66
lineNumber : 0
scriptId : <scriptId>
}
[4] : {
columnNumber : 70
lineNumber : 0
scriptId : <scriptId>
}
[5] : {
columnNumber : 81
lineNumber : 0
scriptId : <scriptId>
}
[6] : {
columnNumber : 87
lineNumber : 0
scriptId : <scriptId>
}
[7] : {
columnNumber : 91
lineNumber : 0
scriptId : <scriptId>
}
[8] : {
columnNumber : 94
lineNumber : 0
scriptId : <scriptId>
}
]
}
}
Running test: arrowFunctionFirstLine
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 18
lineNumber : 0
scriptId : <scriptId>
}
[1] : {
columnNumber : 44
lineNumber : 0
scriptId : <scriptId>
}
[2] : {
columnNumber : 48
lineNumber : 0
scriptId : <scriptId>
}
[3] : {
columnNumber : 51
lineNumber : 0
scriptId : <scriptId>
}
]
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 18
lineNumber : 0
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 44
lineNumber : 0
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 48
lineNumber : 0
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 51
lineNumber : 0
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
paused in foo1
{
columnNumber : 18
lineNumber : 0
scriptId : <scriptId>
}
paused in foo1
{
columnNumber : 51
lineNumber : 0
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 44
lineNumber : 0
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 48
lineNumber : 0
scriptId : <scriptId>
}
Running test: arrowFunctionOnPause
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
[1] : {
columnNumber : 28
lineNumber : 0
scriptId : <scriptId>
}
[2] : {
columnNumber : 54
lineNumber : 0
scriptId : <scriptId>
}
[3] : {
columnNumber : 58
lineNumber : 0
scriptId : <scriptId>
}
[4] : {
columnNumber : 61
lineNumber : 0
scriptId : <scriptId>
}
[5] : {
columnNumber : 18
lineNumber : 1
scriptId : <scriptId>
}
[6] : {
columnNumber : 44
lineNumber : 1
scriptId : <scriptId>
}
[7] : {
columnNumber : 48
lineNumber : 1
scriptId : <scriptId>
}
[8] : {
columnNumber : 51
lineNumber : 1
scriptId : <scriptId>
}
[9] : {
columnNumber : 0
lineNumber : 2
scriptId : <scriptId>
}
[10] : {
columnNumber : 0
lineNumber : 3
scriptId : <scriptId>
}
[11] : {
columnNumber : 6
lineNumber : 3
scriptId : <scriptId>
}
]
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 0
lineNumber : 0
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 28
lineNumber : 0
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 54
lineNumber : 0
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 58
lineNumber : 0
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 61
lineNumber : 0
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 18
lineNumber : 1
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 44
lineNumber : 1
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 48
lineNumber : 1
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 51
lineNumber : 1
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 0
lineNumber : 2
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 0
lineNumber : 3
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 6
lineNumber : 3
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
paused in foo3
{
columnNumber : 28
lineNumber : 0
scriptId : <scriptId>
}
paused in foo3
{
columnNumber : 61
lineNumber : 0
scriptId : <scriptId>
}
paused in foo4
{
columnNumber : 18
lineNumber : 1
scriptId : <scriptId>
}
paused in foo4
{
columnNumber : 51
lineNumber : 1
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 54
lineNumber : 0
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 58
lineNumber : 0
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 44
lineNumber : 1
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 48
lineNumber : 1
scriptId : <scriptId>
}
Running test: getPossibleBreakpointsInRangeWithOffset
Test empty range in first line.
{
id : <messageId>
result : {
locations : [
]
}
}
Test one character range in first line.
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 17
lineNumber : 1
scriptId : <scriptId>
}
]
}
}
Test empty range in not first line.
{
id : <messageId>
result : {
locations : [
]
}
}
Test one character range in not first line.
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 16
lineNumber : 2
scriptId : <scriptId>
}
]
}
}
Test end is undefined
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 17
lineNumber : 1
scriptId : <scriptId>
}
[1] : {
columnNumber : 43
lineNumber : 1
scriptId : <scriptId>
}
[2] : {
columnNumber : 16
lineNumber : 2
scriptId : <scriptId>
}
[3] : {
columnNumber : 49
lineNumber : 2
scriptId : <scriptId>
}
[4] : {
columnNumber : 53
lineNumber : 2
scriptId : <scriptId>
}
[5] : {
columnNumber : 57
lineNumber : 2
scriptId : <scriptId>
}
[6] : {
columnNumber : 0
lineNumber : 3
scriptId : <scriptId>
}
]
}
}
Test end.lineNumber > scripts.lineCount()
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 17
lineNumber : 1
scriptId : <scriptId>
}
[1] : {
columnNumber : 43
lineNumber : 1
scriptId : <scriptId>
}
[2] : {
columnNumber : 16
lineNumber : 2
scriptId : <scriptId>
}
[3] : {
columnNumber : 49
lineNumber : 2
scriptId : <scriptId>
}
[4] : {
columnNumber : 53
lineNumber : 2
scriptId : <scriptId>
}
[5] : {
columnNumber : 57
lineNumber : 2
scriptId : <scriptId>
}
[6] : {
columnNumber : 0
lineNumber : 3
scriptId : <scriptId>
}
]
}
}
Test one string
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 17
lineNumber : 1
scriptId : <scriptId>
}
[1] : {
columnNumber : 43
lineNumber : 1
scriptId : <scriptId>
}
]
}
}
Test end.columnNumber > end.line.length(), should be the same as previous.
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 17
lineNumber : 1
scriptId : <scriptId>
}
[1] : {
columnNumber : 43
lineNumber : 1
scriptId : <scriptId>
}
]
}
}
Running test: withOffset
{
id : <messageId>
result : {
locations : [
[0] : {
columnNumber : 36
lineNumber : 3
scriptId : <scriptId>
}
[1] : {
columnNumber : 62
lineNumber : 3
scriptId : <scriptId>
}
[2] : {
columnNumber : 66
lineNumber : 3
scriptId : <scriptId>
}
[3] : {
columnNumber : 69
lineNumber : 3
scriptId : <scriptId>
}
[4] : {
columnNumber : 18
lineNumber : 4
scriptId : <scriptId>
}
[5] : {
columnNumber : 44
lineNumber : 4
scriptId : <scriptId>
}
[6] : {
columnNumber : 48
lineNumber : 4
scriptId : <scriptId>
}
[7] : {
columnNumber : 51
lineNumber : 4
scriptId : <scriptId>
}
]
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 36
lineNumber : 3
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 62
lineNumber : 3
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 66
lineNumber : 3
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 69
lineNumber : 3
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 18
lineNumber : 4
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 44
lineNumber : 4
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 48
lineNumber : 4
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
{
id : <messageId>
result : {
actualLocation : {
columnNumber : 51
lineNumber : 4
scriptId : <scriptId>
}
breakpointId : <breakpointId>
}
}
paused in foo5
{
columnNumber : 36
lineNumber : 3
scriptId : <scriptId>
}
paused in foo5
{
columnNumber : 69
lineNumber : 3
scriptId : <scriptId>
}
paused in foo6
{
columnNumber : 18
lineNumber : 4
scriptId : <scriptId>
}
paused in foo6
{
columnNumber : 51
lineNumber : 4
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 62
lineNumber : 3
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 66
lineNumber : 3
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 44
lineNumber : 4
scriptId : <scriptId>
}
paused in Promise.resolve.then
{
columnNumber : 48
lineNumber : 4
scriptId : <scriptId>
}
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-gc
print("Test for Debugger.getPossibleBreakpoints");
Protocol.Runtime.enable();
Protocol.Debugger.enable();
InspectorTest.runTestSuite([
function getPossibleBreakpointsInRange(next) {
var source = "function foo(){ return Promise.resolve(); }\nfunction boo(){ return Promise.resolve().then(() => 42); }\n\n";
var scriptId;
compileScript(source)
.then(id => scriptId = id)
.then(() => InspectorTest.log("Test start.scriptId != end.scriptId."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 0, scriptId: scriptId }, end: { lineNumber: 0, columnNumber: 0, scriptId: scriptId + "0" }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test not existing scriptId."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 0, scriptId: "-1" }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test end < start."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 1, columnNumber: 0, scriptId: scriptId }, end: { lineNumber: 0, columnNumber: 0, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test empty range in first line."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 16, scriptId: scriptId }, end: { lineNumber: 0, columnNumber: 16, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test one character range in first line."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 16, scriptId: scriptId }, end: { lineNumber: 0, columnNumber: 17, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test empty range in not first line."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 1, columnNumber: 16, scriptId: scriptId }, end: { lineNumber: 1, columnNumber: 16, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test one character range in not first line."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 1, columnNumber: 16, scriptId: scriptId }, end: { lineNumber: 1, columnNumber: 17, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test end is undefined"))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 0, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test end.lineNumber > scripts.lineCount()"))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 0, scriptId: scriptId }, end: { lineNumber: 5, columnNumber: 0, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test one string"))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 0, scriptId: scriptId }, end: { lineNumber: 1, columnNumber: 0, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test end.columnNumber > end.line.length(), should be the same as previous."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 0, scriptId: scriptId }, end: { lineNumber: 0, columnNumber: 256, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(next);
},
function getPossibleBreakpointsInArrow(next) {
var source = "function foo() { return Promise.resolve().then(() => 239).then(() => 42).then(() => () => 42) }";
var scriptId;
compileScript(source)
.then(id => scriptId = id)
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 0, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(next);
},
function arrowFunctionFirstLine(next) {
Protocol.Debugger.onPaused(message => {
InspectorTest.log("paused in " + message.params.callFrames[0].functionName);
InspectorTest.logMessage(message.params.callFrames[0].location);
Protocol.Debugger.resume();
});
var source = `function foo1() { Promise.resolve().then(() => 42) }
function foo2() { Promise.resolve().then(() => 42) }`;
waitForPossibleBreakpoints(source, { lineNumber: 0, columnNumber: 0 }, { lineNumber: 1, columnNumber: 0 })
.then(InspectorTest.logMessage)
.then(setAllBreakpoints)
.then(() => Protocol.Runtime.evaluate({ expression: "foo1(); foo2()"}))
.then(next);
},
function arrowFunctionOnPause(next) {
function dumpAndResume(message) {
InspectorTest.log("paused in " + message.params.callFrames[0].functionName);
InspectorTest.logMessage(message.params.callFrames[0].location);
Protocol.Debugger.resume();
}
var source = `debugger; function foo3() { Promise.resolve().then(() => 42) }
function foo4() { Promise.resolve().then(() => 42) };\nfoo3();\nfoo4();`;
waitForPossibleBreakpointsOnPause(source, { lineNumber: 0, columnNumber: 0 }, undefined, next)
.then(InspectorTest.logMessage)
.then(setAllBreakpoints)
.then(() => Protocol.Debugger.onPaused(dumpAndResume))
.then(() => Protocol.Debugger.resume());
},
function getPossibleBreakpointsInRangeWithOffset(next) {
var source = "function foo(){ return Promise.resolve(); }\nfunction boo(){ return Promise.resolve().then(() => 42); }\n\n";
var scriptId;
compileScript(source, { name: "with-offset.js", line_offset: 1, column_offset: 1 })
.then(id => scriptId = id)
.then(() => InspectorTest.log("Test empty range in first line."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 1, columnNumber: 17, scriptId: scriptId }, end: { lineNumber: 1, columnNumber: 17, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test one character range in first line."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 1, columnNumber: 17, scriptId: scriptId }, end: { lineNumber: 1, columnNumber: 18, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test empty range in not first line."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 2, columnNumber: 16, scriptId: scriptId }, end: { lineNumber: 2, columnNumber: 16, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test one character range in not first line."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 2, columnNumber: 16, scriptId: scriptId }, end: { lineNumber: 2, columnNumber: 17, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test end is undefined"))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 0, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test end.lineNumber > scripts.lineCount()"))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 0, columnNumber: 0, scriptId: scriptId }, end: { lineNumber: 5, columnNumber: 0, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test one string"))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 1, columnNumber: 1, scriptId: scriptId }, end: { lineNumber: 2, columnNumber: 0, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(() => InspectorTest.log("Test end.columnNumber > end.line.length(), should be the same as previous."))
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: { lineNumber: 1, columnNumber: 1, scriptId: scriptId }, end: { lineNumber: 1, columnNumber: 256, scriptId: scriptId }}))
.then(InspectorTest.logMessage)
.then(next);
},
function withOffset(next) {
Protocol.Debugger.onPaused(message => {
InspectorTest.log("paused in " + message.params.callFrames[0].functionName);
InspectorTest.logMessage(message.params.callFrames[0].location);
Protocol.Debugger.resume();
});
var source = `function foo5() { Promise.resolve().then(() => 42) }
function foo6() { Promise.resolve().then(() => 42) }`;
waitForPossibleBreakpoints(source, { lineNumber: 0, columnNumber: 0 }, undefined, { name: "with-offset.js", line_offset: 3, column_offset: 18 })
.then(InspectorTest.logMessage)
.then(setAllBreakpoints)
.then(() => Protocol.Runtime.evaluate({ expression: "foo5(); foo6()"}))
.then(next);
}
]);
function compileScript(source, origin) {
var promise = Protocol.Debugger.onceScriptParsed().then(message => message.params.scriptId);
if (!origin) origin = { name: "", line_offset: 0, column_offset: 0 };
compileAndRunWithOrigin(source, origin.name, origin.line_offset, origin.column_offset);
return promise;
}
function waitForPossibleBreakpoints(source, start, end, origin) {
return compileScript(source, origin)
.then(scriptId => { (start || {}).scriptId = scriptId; (end || {}).scriptId = scriptId })
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: start, end: end }));
}
function waitForPossibleBreakpointsOnPause(source, start, end, next) {
var promise = Protocol.Debugger.oncePaused()
.then(msg => { (start || {}).scriptId = msg.params.callFrames[0].location.scriptId; (end || {}).scriptId = msg.params.callFrames[0].location.scriptId })
.then(() => Protocol.Debugger.getPossibleBreakpoints({ start: start, end: end }));
Protocol.Runtime.evaluate({ expression: source }).then(next);
return promise;
}
function setAllBreakpoints(message) {
var promises = [];
for (var location of message.result.locations)
promises.push(Protocol.Debugger.setBreakpoint({ location: location }).then(checkBreakpointAndDump));
return Promise.all(promises);
}
function checkBreakpointAndDump(message) {
if (message.error) {
InspectorTest.log("FAIL: error in setBreakpoint");
InspectorTest.logMessage(message);
return;
}
var id_data = message.result.breakpointId.split(":");
if (parseInt(id_data[1]) !== message.result.actualLocation.lineNumber || parseInt(id_data[2]) !== message.result.actualLocation.columnNumber) {
InspectorTest.log("FAIL: possible breakpoint was resolved in another location");
InspectorTest.logMessage(message);
}
InspectorTest.logMessage(message);
}
......@@ -38,6 +38,13 @@ void Exit() {
Terminate();
}
v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
v8::internal::Vector<uint16_t> buffer =
v8::internal::Vector<uint16_t>::New(str->Length());
str->Write(buffer.start(), 0, str->Length());
return buffer;
}
class UtilsExtension : public v8::Extension {
public:
UtilsExtension()
......@@ -45,7 +52,8 @@ class UtilsExtension : public v8::Extension {
"native function print();"
"native function quit();"
"native function setlocale();"
"native function load();") {}
"native function load();"
"native function compileAndRunWithOrigin();") {}
virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
v8::Isolate* isolate, v8::Local<v8::String> name) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
......@@ -72,11 +80,24 @@ class UtilsExtension : public v8::Extension {
.ToLocalChecked())
.FromJust()) {
return v8::FunctionTemplate::New(isolate, UtilsExtension::Load);
} else if (name->Equals(context, v8::String::NewFromUtf8(
isolate, "compileAndRunWithOrigin",
v8::NewStringType::kNormal)
.ToLocalChecked())
.FromJust()) {
return v8::FunctionTemplate::New(isolate,
UtilsExtension::CompileAndRunWithOrigin);
}
return v8::Local<v8::FunctionTemplate>();
}
static void set_backend_task_runner(TaskRunner* runner) {
backend_runner_ = runner;
}
private:
static TaskRunner* backend_runner_;
static void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope(args.GetIsolate());
......@@ -143,8 +164,25 @@ class UtilsExtension : public v8::Extension {
v8::Global<v8::Context> context(isolate, isolate->GetCurrentContext());
task.Run(isolate, context);
}
static void CompileAndRunWithOrigin(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 4 || !args[0]->IsString() || !args[1]->IsString() ||
!args[2]->IsInt32() || !args[3]->IsInt32()) {
fprintf(stderr,
"Internal error: compileAndRunWithOrigin(source, name, line, "
"column).");
Exit();
}
backend_runner_->Append(new ExecuteStringTask(
ToVector(args[0].As<v8::String>()), args[1].As<v8::String>(),
args[2].As<v8::Int32>(), args[3].As<v8::Int32>()));
}
};
TaskRunner* UtilsExtension::backend_runner_ = nullptr;
class SetTimeoutTask : public TaskRunner::Task {
public:
SetTimeoutTask(v8::Isolate* isolate, v8::Local<v8::Function> function)
......@@ -174,13 +212,6 @@ class SetTimeoutTask : public TaskRunner::Task {
v8::Global<v8::Function> function_;
};
v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
v8::internal::Vector<uint16_t> buffer =
v8::internal::Vector<uint16_t>::New(str->Length());
str->Write(buffer.start(), 0, str->Length());
return buffer;
}
class SetTimeoutExtension : public v8::Extension {
public:
SetTimeoutExtension()
......@@ -201,13 +232,15 @@ class SetTimeoutExtension : public v8::Extension {
"Internal error: only setTimeout(function, 0) is supported.");
Exit();
}
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
v8::Isolate* isolate = args.GetIsolate();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
if (args[0]->IsFunction()) {
TaskRunner::FromContext(context)->Append(new SetTimeoutTask(
args.GetIsolate(), v8::Local<v8::Function>::Cast(args[0])));
} else {
TaskRunner::FromContext(context)->Append(
new ExecuteStringTask(ToVector(args[0].As<v8::String>())));
new SetTimeoutTask(isolate, v8::Local<v8::Function>::Cast(args[0])));
} else {
TaskRunner::FromContext(context)->Append(new ExecuteStringTask(
ToVector(args[0].As<v8::String>()), v8::String::Empty(isolate),
v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0)));
}
}
};
......@@ -301,7 +334,9 @@ class FrontendChannelImpl : public InspectorClientImpl::FrontendChannel {
v8::Local<v8::String> result = v8::String::Concat(prefix, message_string);
result = v8::String::Concat(result, suffix);
frontend_task_runner_->Append(new ExecuteStringTask(ToVector(result)));
frontend_task_runner_->Append(new ExecuteStringTask(
ToVector(result), v8::String::Empty(isolate),
v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0)));
}
private:
......@@ -336,6 +371,7 @@ int main(int argc, char* argv[]) {
TaskRunner backend_runner(&backend_configuration, false, &ready_semaphore);
ready_semaphore.Wait();
SendMessageToBackendExtension::set_backend_task_runner(&backend_runner);
UtilsExtension::set_backend_task_runner(&backend_runner);
const char* frontend_extensions[] = {"v8_inspector/utils",
"v8_inspector/frontend"};
......
......@@ -31,12 +31,13 @@ Protocol = new Proxy({}, {
InspectorTest.log = print.bind(null);
InspectorTest.logMessage = function(message)
InspectorTest.logMessage = function(originalMessage)
{
var message = JSON.parse(JSON.stringify(originalMessage));
if (message.id)
message.id = "<messageId>";
const nonStableFields = new Set(["objectId", "scriptId", "exceptionId", "timestamp", "executionContextId", "callFrameId"]);
const nonStableFields = new Set(["objectId", "scriptId", "exceptionId", "timestamp", "executionContextId", "callFrameId", "breakpointId"]);
var objects = [ message ];
while (objects.length) {
var object = objects.shift();
......@@ -49,7 +50,7 @@ InspectorTest.logMessage = function(message)
}
InspectorTest.logObject(message);
return message;
return originalMessage;
}
InspectorTest.logObject = function(object, title)
......@@ -112,18 +113,7 @@ InspectorTest.completeTestAfterPendingTimeouts = function()
awaitPromise: true }).then(InspectorTest.completeTest);
}
InspectorTest.addScript = function(string)
{
return InspectorTest._sendCommandPromise("Runtime.evaluate", { "expression": string }).then(dumpErrorIfNeeded);
function dumpErrorIfNeeded(message)
{
if (message.error) {
InspectorTest.log("Error while executing '" + string + "': " + message.error.message);
InspectorTest.completeTest();
}
}
};
InspectorTest.addScript = (string) => compileAndRunWithOrigin(string, "", 0, 0);
InspectorTest.startDumpingProtocolMessages = function()
{
......
......@@ -123,13 +123,29 @@ TaskRunner* TaskRunner::FromContext(v8::Local<v8::Context> context) {
context->GetAlignedPointerFromEmbedderData(kTaskRunnerIndex));
}
namespace {
v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) {
v8::internal::Vector<uint16_t> buffer =
v8::internal::Vector<uint16_t>::New(str->Length());
str->Write(buffer.start(), 0, str->Length());
return buffer;
}
} // namespace
ExecuteStringTask::ExecuteStringTask(
const v8::internal::Vector<uint16_t>& expression)
: expression_(expression) {}
const v8::internal::Vector<uint16_t>& expression,
v8::Local<v8::String> name, v8::Local<v8::Integer> line_offset,
v8::Local<v8::Integer> column_offset)
: expression_(expression),
name_(ToVector(name)),
line_offset_(line_offset.As<v8::Int32>()->Value()),
column_offset_(column_offset.As<v8::Int32>()->Value()) {}
ExecuteStringTask::ExecuteStringTask(
const v8::internal::Vector<const char>& expression)
: expression_utf8_(expression) {}
: expression_utf8_(expression), line_offset_(0), column_offset_(0) {}
void ExecuteStringTask::Run(v8::Isolate* isolate,
const v8::Global<v8::Context>& context) {
......@@ -139,7 +155,15 @@ void ExecuteStringTask::Run(v8::Isolate* isolate,
v8::Local<v8::Context> local_context = context.Get(isolate);
v8::Context::Scope context_scope(local_context);
v8::ScriptOrigin origin(v8::String::Empty(isolate));
v8::Local<v8::String> name =
v8::String::NewFromTwoByte(isolate, name_.start(),
v8::NewStringType::kNormal, name_.length())
.ToLocalChecked();
v8::Local<v8::Integer> line_offset = v8::Integer::New(isolate, line_offset_);
v8::Local<v8::Integer> column_offset =
v8::Integer::New(isolate, column_offset_);
v8::ScriptOrigin origin(name, line_offset, column_offset);
v8::Local<v8::String> source;
if (expression_.length()) {
source = v8::String::NewFromTwoByte(isolate, expression_.start(),
......
......@@ -69,7 +69,10 @@ class TaskRunner : public v8::base::Thread {
class ExecuteStringTask : public TaskRunner::Task {
public:
explicit ExecuteStringTask(const v8::internal::Vector<uint16_t>& expression);
ExecuteStringTask(const v8::internal::Vector<uint16_t>& expression,
v8::Local<v8::String> name,
v8::Local<v8::Integer> line_offset,
v8::Local<v8::Integer> column_offset);
explicit ExecuteStringTask(
const v8::internal::Vector<const char>& expression);
bool is_inspector_task() override { return false; }
......@@ -80,6 +83,9 @@ class ExecuteStringTask : public TaskRunner::Task {
private:
v8::internal::Vector<uint16_t> expression_;
v8::internal::Vector<const char> expression_utf8_;
v8::internal::Vector<uint16_t> name_;
int32_t line_offset_;
int32_t column_offset_;
DISALLOW_COPY_AND_ASSIGN(ExecuteStringTask);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment