Source/JavaScriptCore/ChangeLog

 12019-09-24 Yury Semikhatsky <yurys@chromium.org>
 2
 3 Web Inspector: tests under LayoutTests/inspector/debugger are flaky
 4 https://bugs.webkit.org/show_bug.cgi?id=137131
 5 <rdar://problem/18461335>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 Changed breakpoint resolution logic to make it consistent across platforms and
 10 better handle the case when there are several DebuggerPausePositions at the same
 11 offset (but with different types).
 12
 13 * bytecode/CodeBlock.cpp:
 14 (JSC::CodeBlock::hasOpDebugForLineAndColumn):
 15 * bytecode/CodeBlock.h:
 16 * debugger/Breakpoint.h: Removed Breakpoint::unspecifiedColumn, Optional<unsigned>
 17 is used instead where needed. It allows to avoid code that relies on (int)UINT_MAX => -1
 18 conversion.
 19
 20 * debugger/Debugger.cpp:
 21 (JSC::Debugger::resolveBreakpoint): clarified that in the map columns are 0-based.
 22 * debugger/DebuggerParseData.cpp:
 23 (JSC::DebuggerPausePositions::breakpointLocationForLineColumn): replaced custom
 24 binary search with std::lower_bound. If there are several pause positions at the
 25 same offset they will be sorted by the type and the algorithm is guaranteed to see
 26 leftmost one first.
 27
 28 (JSC::DebuggerPausePositions::sort): use type as secondary ordering component.
 29 * debugger/DebuggerParseData.h: Rearranged type constants so that Enter < Pause < Leave
 30 this change along with sorting by type should guarantee that in case of several pause
 31 positions at the same line Enter goes before Pause before Leave and the breakpoint
 32 resolution will yield result similar to that when each pause locations has different
 33 position.
 34
 35 * inspector/protocol/Debugger.json: clarified that positions are 0-based.
 36 * parser/ParserTokens.h:
 37 (JSC::JSTextPosition::column const): added helper method for computing column.
 38
1392019-09-26 Yusuke Suzuki <ysuzuki@apple.com>
240
341 [JSC] DFG recursive-tail-call optimization should not emit jump to call-frame with varargs

Source/WebCore/ChangeLog

 12019-09-20 Yury Semikhatsky <yurys@chromium.org>
 2
 3 Web Inspector: tests under LayoutTests/inspector/debugger are flaky
 4 https://bugs.webkit.org/show_bug.cgi?id=137131
 5 <rdar://problem/18461335>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 Fix debugger tests on GTK. All tests that pause on breakpoint didn't work because
 10 in layout tests InspectorFrontendClientLocal was using Timer to dispatch commands
 11 sent from the local front-end page to the inspected one. When paused inside a script
 12 triggered by the front-end nested timer event would be scheduled but never fired
 13 because in glib implementation of RunLoop::TimerBase uses event source which doesn't
 14 allow recursion (g_source_set_can_recurse is not called on the source), so dispatching
 15 Debugger.resume command didn't work when paused inside another inspector command (e.g.
 16 eval). RunLoop itself uses event source which does allow recursion. So instead of using
 17 a timer for asynchronous command dispatching with delay=0 we now schedule a task in
 18 RunLoop's queue.
 19
 20 * inspector/InspectorFrontendClientLocal.cpp:
 21 (WebCore::InspectorBackendDispatchTask::dispatch):
 22 (WebCore::InspectorBackendDispatchTask::reset):
 23 (WebCore::InspectorBackendDispatchTask::InspectorBackendDispatchTask):
 24 (WebCore::InspectorBackendDispatchTask::scheduleOneShot): ensures that there is one inspector
 25 dispatch task in the queue.
 26 (WebCore::InspectorBackendDispatchTask::dispatchOneMessage): this is mostly the same behavior
 27 as was with timerFired, we should be able to dispatch all accumulated messages from the queue
 28 in one batch but for now I'd like to keep it one per iteration.
 29
1302019-09-27 Zalan Bujtas <zalan@apple.com>
231
332 [LFC][IFC] Replace Line::Run's logicalRect/textContext with Display::Run

Source/JavaScriptCore/bytecode/CodeBlock.cpp

@@void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& d
18661866 line += ownerExecutable()->firstLine();
18671867}
18681868
1869 bool CodeBlock::hasOpDebugForLineAndColumn(unsigned line, unsigned column)
 1869bool CodeBlock::hasOpDebugForLineAndColumn(unsigned line, Optional<unsigned> column)
18701870{
18711871 const InstructionStream& instructionStream = instructions();
18721872 for (const auto& it : instructionStream) {

@@bool CodeBlock::hasOpDebugForLineAndColumn(unsigned line, unsigned column)
18751875 unsigned opDebugLine;
18761876 unsigned opDebugColumn;
18771877 expressionRangeForBytecodeOffset(it.offset(), unused, unused, unused, opDebugLine, opDebugColumn);
1878  if (line == opDebugLine && (column == Breakpoint::unspecifiedColumn || column == opDebugColumn))
 1878 if (line == opDebugLine && (!column || column == opDebugColumn))
18791879 return true;
18801880 }
18811881 }

Source/JavaScriptCore/bytecode/CodeBlock.h

@@public:
787787 unsigned frameRegisterCount();
788788 int stackPointerOffset();
789789
790  bool hasOpDebugForLineAndColumn(unsigned line, unsigned column);
 790 bool hasOpDebugForLineAndColumn(unsigned line, Optional<unsigned> column);
791791
792792 bool hasDebuggerRequests() const { return m_debuggerRequests; }
793793 void* debuggerRequestsAddress() { return &m_debuggerRequests; }

Source/JavaScriptCore/debugger/Breakpoint.h

@@struct Breakpoint : public DoublyLinkedListNode<Breakpoint> {
5757 unsigned hitCount { 0 };
5858 bool resolved { false };
5959
60  static constexpr unsigned unspecifiedColumn = UINT_MAX;
61 
6260private:
6361 Breakpoint* m_prev;
6462 Breakpoint* m_next;

Source/JavaScriptCore/debugger/Debugger.cpp

@@void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, Br
268268 if (breakpoint.sourceID != sourceID)
269269 return;
270270
271  unsigned line = breakpoint.line;
272  unsigned column = breakpoint.column;
273 
274271 unsigned startLine = executable->firstLine();
275272 unsigned startColumn = executable->startColumn();
276273 unsigned endLine = executable->lastLine();

@@void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, Br
278275
279276 // Inspector breakpoint line and column values are zero-based but the executable
280277 // and CodeBlock line and column values are one-based.
281  line += 1;
282  column = column ? column + 1 : Breakpoint::unspecifiedColumn;
 278 unsigned line = breakpoint.line + 1;
 279 Optional<unsigned> column;
 280 if (breakpoint.column)
 281 column = breakpoint.column + 1;
283282
284283 if (line < startLine || line > endLine)
285284 return;
286  if (column != Breakpoint::unspecifiedColumn) {
 285 if (column) {
287286 if (line == startLine && column < startColumn)
288287 return;
289288 if (line == endLine && column > endColumn)

@@void Debugger::resolveBreakpoint(Breakpoint& breakpoint, SourceProvider* sourceP
359358
360359 // FIXME: <https://webkit.org/b/162771> Web Inspector: Adopt TextPosition in Inspector to avoid oneBasedInt/zeroBasedInt ambiguity
361360 // Inspector breakpoint line and column values are zero-based but the executable
362  // and CodeBlock line and column values are one-based.
363  unsigned line = breakpoint.line + 1;
364  unsigned column = breakpoint.column ? breakpoint.column : Breakpoint::unspecifiedColumn;
 361 // and CodeBlock line values are one-based while column is zero-based.
 362 int line = breakpoint.line + 1;
 363 int column = breakpoint.column;
365364
366365 // Account for a <script>'s start position on the first line only.
367  unsigned providerStartLine = sourceProvider->startPosition().m_line.oneBasedInt(); // One based to match the already adjusted line.
368  unsigned providerStartColumn = sourceProvider->startPosition().m_column.zeroBasedInt(); // Zero based so column zero is zero.
369  if (line == providerStartLine && column != Breakpoint::unspecifiedColumn) {
 366 int providerStartLine = sourceProvider->startPosition().m_line.oneBasedInt(); // One based to match the already adjusted line.
 367 int providerStartColumn = sourceProvider->startPosition().m_column.zeroBasedInt(); // Zero based so column zero is zero.
 368 if (line == providerStartLine && breakpoint.column) {
370369 ASSERT(providerStartColumn <= column);
371370 if (providerStartColumn)
372371 column -= providerStartColumn;
373372 }
374373
375374 DebuggerParseData& parseData = debuggerParseData(breakpoint.sourceID, sourceProvider);
376  Optional<JSTextPosition> resolvedPosition = parseData.pausePositions.breakpointLocationForLineColumn((int)line, (int)column);
 375 Optional<JSTextPosition> resolvedPosition = parseData.pausePositions.breakpointLocationForLineColumn(line, column);
377376 if (!resolvedPosition)
378377 return;
379378
380  unsigned resolvedLine = resolvedPosition->line;
381  unsigned resolvedColumn = resolvedPosition->offset - resolvedPosition->lineStartOffset + 1;
 379 int resolvedLine = resolvedPosition->line;
 380 int resolvedColumn = resolvedPosition->offset - resolvedPosition->lineStartOffset;
382381
383382 // Re-account for a <script>'s start position on the first line only.
384  if (resolvedLine == providerStartLine && column != Breakpoint::unspecifiedColumn) {
 383 if (resolvedLine == providerStartLine && breakpoint.column) {
385384 if (providerStartColumn)
386385 resolvedColumn += providerStartColumn;
387386 }
388387
389388 breakpoint.line = resolvedLine - 1;
390  breakpoint.column = resolvedColumn - 1;
 389 breakpoint.column = resolvedColumn;
391390 breakpoint.resolved = true;
392391}
393392

Source/JavaScriptCore/debugger/DebuggerParseData.cpp

@@namespace JSC {
3333
3434Optional<JSTextPosition> DebuggerPausePositions::breakpointLocationForLineColumn(int line, int column)
3535{
36  unsigned start = 0;
37  unsigned end = m_positions.size();
38  while (start != end) {
39  unsigned middle = start + ((end - start) / 2);
40  DebuggerPausePosition& pausePosition = m_positions[middle];
41  int pauseLine = pausePosition.position.line;
42  int pauseColumn = pausePosition.position.offset - pausePosition.position.lineStartOffset;
43 
44  if (line < pauseLine) {
45  end = middle;
46  continue;
47  }
48  if (line > pauseLine) {
49  start = middle + 1;
50  continue;
51  }
52 
53  if (column == pauseColumn) {
54  // Found an exact position match. Roll forward if this was a function Entry.
55  // We are guarenteed to have a Leave for an Entry so we don't need to bounds check.
56  while (true) {
57  if (pausePosition.type != DebuggerPausePositionType::Enter)
58  return Optional<JSTextPosition>(pausePosition.position);
59  pausePosition = m_positions[middle++];
60  }
61  }
 36 DebuggerPausePosition position;
 37 position.position.line = line;
 38 position.position.offset = column;
 39 position.position.lineStartOffset = 0;
 40 auto it = std::lower_bound(m_positions.begin(), m_positions.end(), position, [] (const DebuggerPausePosition& a, const DebuggerPausePosition& b) {
 41 if (a.position.line == b.position.line)
 42 return a.position.column() < b.position.column();
 43 return a.position.line < b.position.line;
 44 });
 45 if (it == m_positions.end())
 46 return WTF::nullopt;
6247
63  if (column < pauseColumn)
64  end = middle;
65  else
66  start = middle + 1;
 48 if (line == it->position.line && column == it->position.column()) {
 49 // Found an exact position match. Roll forward if this was a function Entry.
 50 // We are guaranteed to have a Leave for an Entry so we don't need to bounds check.
 51 while (it->type == DebuggerPausePositionType::Enter)
 52 ++it;
 53 return it->position;
6754 }
6855
69  // Past the end, no possible pause locations.
70  if (start >= m_positions.size())
71  return WTF::nullopt;
72 
7356 // If the next location is a function Entry we will need to decide if we should go into
7457 // the function or go past the function. We decide to go into the function if the
7558 // input is on the same line as the function entry. For example:

@@Optional<JSTextPosition> DebuggerPausePositions::breakpointLocationForLineColumn
8669 // If the input was line 3, go into the function to pause on line 4.
8770
8871 // Valid pause location. Use it.
89  DebuggerPausePosition& firstSlidePosition = m_positions[start];
 72 DebuggerPausePosition& firstSlidePosition = *it;
9073 if (firstSlidePosition.type != DebuggerPausePositionType::Enter)
9174 return Optional<JSTextPosition>(firstSlidePosition.position);
9275

@@Optional<JSTextPosition> DebuggerPausePositions::breakpointLocationForLineColumn
9477 // If entryStackSize is > 0 we are skipping functions.
9578 bool shouldEnterFunction = firstSlidePosition.position.line == line;
9679 int entryStackSize = shouldEnterFunction ? 0 : 1;
97  for (unsigned i = start + 1; i < m_positions.size(); ++i) {
98  DebuggerPausePosition& slidePosition = m_positions[i];
 80 ++it;
 81 for (; it != m_positions.end(); ++it) {
 82 auto& slidePosition = *it;
9983 ASSERT(entryStackSize >= 0);
10084
10185 // Already skipping functions.

@@Optional<JSTextPosition> DebuggerPausePositions::breakpointLocationForLineColumn
124108void DebuggerPausePositions::sort()
125109{
126110 std::sort(m_positions.begin(), m_positions.end(), [] (const DebuggerPausePosition& a, const DebuggerPausePosition& b) {
 111 if (a.position.offset == b.position.offset)
 112 return a.type < b.type;
127113 return a.position.offset < b.position.offset;
128114 });
129115}

Source/JavaScriptCore/debugger/DebuggerParseData.h

@@namespace JSC {
3333class SourceProvider;
3434class VM;
3535
36 enum class DebuggerPausePositionType { Enter, Leave, Pause };
 36// The order of the constants here matters as it is used for
 37// sorting pause positions that have same offset.
 38enum class DebuggerPausePositionType { Enter, Pause, Leave };
3739struct DebuggerPausePosition {
3840 DebuggerPausePositionType type;
3941 JSTextPosition position;

Source/JavaScriptCore/inspector/protocol/Debugger.json

2828 "description": "Location in the source code.",
2929 "properties": [
3030 { "name": "scriptId", "$ref": "ScriptId", "description": "Script identifier as reported in the <code>Debugger.scriptParsed</code>." },
31  { "name": "lineNumber", "type": "integer", "description": "Line number in the script." },
32  { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script." }
 31 { "name": "lineNumber", "type": "integer", "description": "Line number in the script (0-based)." },
 32 { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number in the script (0-based)." }
3333 ]
3434 },
3535 {

Source/JavaScriptCore/parser/ParserTokens.h

@@struct JSTextPosition {
217217 return !(*this == other);
218218 }
219219
 220 int column() const { return offset - lineStartOffset; }
 221
220222 int line { 0 };
221223 int offset { 0 };
222224 int lineStartOffset { 0 };

Source/WebCore/inspector/InspectorFrontendClientLocal.cpp

@@public:
8181 ASSERT_ARG(message, !message.isEmpty());
8282
8383 m_messages.append(message);
84  if (!m_timer.isActive())
85  m_timer.startOneShot(0_s);
 84 scheduleOneShot();
8685 }
8786
8887 void reset()
8988 {
9089 m_messages.clear();
91  m_timer.stop();
9290 m_inspectedPageController = nullptr;
9391 }
9492
95  void timerFired()
 93private:
 94 InspectorBackendDispatchTask(InspectorController* inspectedPageController)
 95 : m_inspectedPageController(inspectedPageController)
 96 {
 97 ASSERT_ARG(inspectedPageController, inspectedPageController);
 98 }
 99
 100 void scheduleOneShot()
96101 {
97  ASSERT(m_inspectedPageController);
 102 if (m_hasScheduledTask)
 103 return;
 104 m_hasScheduledTask = true;
 105
 106 // The frontend can be closed and destroy the owning frontend client before or in the
 107 // process of dispatching the task, so keep a protector reference here.
 108 RunLoop::current().dispatch([this, protectedThis = makeRef(*this)] {
 109 m_hasScheduledTask = false;
 110 dispatchOneMessage();
 111 });
 112 }
98113
99  // Dispatching a message can possibly close the frontend and destroy
100  // the owning frontend client, so keep a protector reference here.
101  Ref<InspectorBackendDispatchTask> protectedThis(*this);
 114 void dispatchOneMessage()
 115 {
 116 // Owning frontend client may have been destroyed after the task was scheduled.
 117 if (!m_inspectedPageController) {
 118 ASSERT(m_messages.isEmpty());
 119 return;
 120 }
102121
103122 if (!m_messages.isEmpty())
104123 m_inspectedPageController->dispatchMessageFromFrontend(m_messages.takeFirst());
105124
106125 if (!m_messages.isEmpty() && m_inspectedPageController)
107  m_timer.startOneShot(0_s);
108  }
109 
110 private:
111  InspectorBackendDispatchTask(InspectorController* inspectedPageController)
112  : m_inspectedPageController(inspectedPageController)
113  , m_timer(*this, &InspectorBackendDispatchTask::timerFired)
114  {
115  ASSERT_ARG(inspectedPageController, inspectedPageController);
 126 scheduleOneShot();
116127 }
117128
118129 InspectorController* m_inspectedPageController { nullptr };
119  Timer m_timer;
120130 Deque<String> m_messages;
 131 bool m_hasScheduledTask { false };
121132};
122133
123134String InspectorFrontendClientLocal::Settings::getProperty(const String&)

LayoutTests/ChangeLog

 12019-09-20 Yury Semikhatsky <yurys@chromium.org>
 2
 3 Web Inspector: tests under LayoutTests/inspector/debugger are flaky
 4 https://bugs.webkit.org/show_bug.cgi?id=137131
 5 <rdar://problem/18461335>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 Enable inspector/debugger tests on GTK.
 10
 11 * inspector/debugger/breakpoints/resolved-dump-all-pause-locations-expected.txt: Rebaselined the test
 12 after changes in the breakpoint resolution code. Now the output on GTK is the same as on Mac.
 13 * platform/gtk/TestExpectations:
 14
1152019-09-27 John Wilander <wilander@apple.com>
216
317 Storage Access API: document.hasStorageAccess() should return false by default

LayoutTests/inspector/debugger/breakpoints/resolved-dump-all-pause-locations-expected.txt

@@PAUSES AT: 89:7
21662166 92 x
21672167
21682168INSERTING AT: 89:8
2169 PAUSES AT: 94:0
 2169PAUSES AT: 98:0
21702170 86
21712171 87 x => x;
21722172 88 () => 1;

@@PAUSES AT: 94:0
21752175 91 (x) => {
21762176 92 x
21772177 93 };
2178  => 94 |() => {
 2178 94 () => {
21792179 95 var x;
21802180 96 };
21812181 97
 2182 => 98 |var fObj = {
 2183 99 f1: function() {
 2184 100 var x;
 2185 101 },
21822186
21832187INSERTING AT: 90:0
21842188PAUSES AT: 90:0

@@PAUSES AT: 93:0
22422246 95 var x;
22432247 96 };
22442248
 2249INSERTING AT: 94:0
 2250PAUSES AT: 94:0
 2251 91 (x) => {
 2252 92 x
 2253 93 };
 2254-=> 94 |() => {
 2255 95 var x;
 2256 96 };
 2257 97
 2258
22452259INSERTING AT: 94:1
22462260PAUSES AT: 95:4
22472261 91 (x) => {

@@PAUSES AT: 96:0
22642278 98 var fObj = {
22652279 99 f1: function() {
22662280
2267 INSERTING AT: 96:1
2268 PAUSES AT: 98:0
2269  93 };
2270  94 () => {
2271  95 var x;
2272  -> 96 }#;
2273  97
2274  => 98 |var fObj = {
2275  99 f1: function() {
2276  100 var x;
2277  101 },
2278 
22792281INSERTING AT: 99:0
22802282PAUSES AT: 100:8
22812283 96 };

LayoutTests/platform/gtk/TestExpectations

@@webkit.org/b/116957 media/track/track-automatic-subtitles.html [ Timeout ]
23202320
23212321webkit.org/b/120682 inspector/page/archive.html [ Timeout ]
23222322
 2323webkit.org/b/147518 inspector/debugger/nested-inspectors.html [ Timeout ]
23232324webkit.org/b/122571 http/tests/inspector/dom/cross-domain-inspected-node-access.html [ Timeout Pass ]
2324 webkit.org/b/122571 inspector/debugger/setBreakpoint.html [ Timeout Pass ]
2325 webkit.org/b/122571 inspector/debugger/call-frame-function-name.html [ Timeout Pass ]
2326 webkit.org/b/122571 inspector/debugger/setBreakpoint-options-exception.html [ Timeout Pass ]
2327 webkit.org/b/122571 inspector/debugger/setPauseOnExceptions-all.html [ Timeout Pass ]
2328 webkit.org/b/122571 inspector/debugger/setPauseOnExceptions-none.html [ Timeout Pass ]
2329 webkit.org/b/122571 inspector/debugger/call-frame-this-host.html [ Timeout Pass Crash ]
2330 webkit.org/b/122571 inspector/debugger/setBreakpoint-autoContinue.html [ Timeout Pass ]
2331 webkit.org/b/122571 inspector/debugger/setPauseOnExceptions-uncaught.html [ Timeout Pass ]
2332 webkit.org/b/122571 inspector/debugger/setBreakpoint-actions.html [ Failure Timeout Pass ]
2333 webkit.org/b/122571 inspector/debugger/call-frame-this-nonstrict.html [ Timeout Pass ]
2334 webkit.org/b/122571 inspector/debugger/setBreakpoint-column.html [ Timeout Pass ]
2335 webkit.org/b/122571 inspector/debugger/setBreakpoint-condition.html [ Timeout Pass ]
2336 webkit.org/b/122571 inspector/debugger/removeBreakpoint.html [ Timeout Pass ]
2337 webkit.org/b/122571 inspector/debugger/call-frame-this-strict.html [ Timeout Pass ]
23382325webkit.org/b/122571 inspector/dom/request-child-nodes-depth.html [ Timeout Pass ]
23392326webkit.org/b/122571 inspector/dom/focus.html [ Failure Timeout Pass ]
23402327webkit.org/b/122571 inspector/runtime/getProperties.html [ Timeout Pass Crash ]

@@webkit.org/b/136674 media/track/track-cue-rendering-with-padding.html [ Timeout
23792366
23802367webkit.org/b/137698 media/video-controls-drag.html [ Timeout ]
23812368
2382 webkit.org/b/137131 inspector/debugger [ Skip ]
23832369webkit.org/b/147518 inspector/dom [ Skip ]
23842370webkit.org/b/147518 inspector/model [ Skip ]
23852371webkit.org/b/147518 inspector/timeline [ Skip ]