| /* |
| * Copyright (C) 2015 Apple Inc. All rights reserved. |
| * Copyright (C) 2015 Saam Barati <saambarati1@gmail.com> |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| WI.BasicBlockAnnotator = class BasicBlockAnnotator extends WI.Annotator |
| { |
| constructor(sourceCodeTextEditor, script) |
| { |
| super(sourceCodeTextEditor); |
| |
| this._script = script; |
| this._basicBlockMarkers = new Map; // Only contains unexecuted basic blocks. |
| } |
| |
| // Protected |
| |
| clearAnnotations() |
| { |
| for (var key of this._basicBlockMarkers.keys()) |
| this._clearRangeForBasicBlockMarker(key); |
| } |
| |
| insertAnnotations() |
| { |
| if (!this.isActive()) |
| return; |
| this._annotateBasicBlockExecutionRanges(); |
| } |
| |
| // Private |
| |
| _annotateBasicBlockExecutionRanges() |
| { |
| var sourceID = this._script.id; |
| var startTime = Date.now(); |
| |
| this._script.target.RuntimeAgent.getBasicBlocks(sourceID, function(error, basicBlocks) { |
| if (error) { |
| console.error("Error in getting basic block locations: " + error); |
| return; |
| } |
| |
| if (!this.isActive()) |
| return; |
| |
| var {startOffset, endOffset} = this.sourceCodeTextEditor.visibleRangeOffsets(); |
| basicBlocks = basicBlocks.filter(function(block) { |
| // Viewport: [--] |
| // Block: [--] |
| if (block.startOffset > endOffset) |
| return false; |
| |
| // Viewport: [--] |
| // Block: [--] |
| if (block.endOffset < startOffset) |
| return false; |
| |
| return true; |
| }); |
| |
| for (var block of basicBlocks) { |
| var key = block.startOffset + ":" + block.endOffset; |
| var hasKey = this._basicBlockMarkers.has(key); |
| var hasExecuted = block.hasExecuted; |
| if (hasKey && hasExecuted) |
| this._clearRangeForBasicBlockMarker(key); |
| else if (!hasKey && !hasExecuted) { |
| var marker = this._highlightTextForBasicBlock(block); |
| this._basicBlockMarkers.set(key, marker); |
| } |
| } |
| |
| var totalTime = Date.now() - startTime; |
| var timeoutTime = Number.constrain(30 * totalTime, 500, 5000); |
| this._timeoutIdentifier = setTimeout(this.insertAnnotations.bind(this), timeoutTime); |
| }.bind(this)); |
| } |
| |
| _highlightTextForBasicBlock(basicBlock) |
| { |
| console.assert(basicBlock.startOffset <= basicBlock.endOffset && basicBlock.startOffset >= 0 && basicBlock.endOffset >= 0, "" + basicBlock.startOffset + ":" + basicBlock.endOffset); |
| console.assert(!basicBlock.hasExecuted); |
| |
| var startPosition = this.sourceCodeTextEditor.originalOffsetToCurrentPosition(basicBlock.startOffset); |
| var endPosition = this.sourceCodeTextEditor.originalOffsetToCurrentPosition(basicBlock.endOffset); |
| if (this._isTextRangeOnlyClosingBrace(startPosition, endPosition)) |
| return null; |
| |
| var marker = this.sourceCodeTextEditor.addStyleToTextRange(startPosition, endPosition, WI.BasicBlockAnnotator.HasNotExecutedClassName); |
| return marker; |
| } |
| |
| _isTextRangeOnlyClosingBrace(startPosition, endPosition) |
| { |
| var isOnlyClosingBrace = /^\s*\}$/; |
| return isOnlyClosingBrace.test(this.sourceCodeTextEditor.getTextInRange(startPosition, endPosition)); |
| } |
| |
| _clearRangeForBasicBlockMarker(key) |
| { |
| console.assert(this._basicBlockMarkers.has(key)); |
| var marker = this._basicBlockMarkers.get(key); |
| if (marker) |
| marker.clear(); |
| this._basicBlockMarkers.delete(key); |
| } |
| }; |
| |
| WI.BasicBlockAnnotator.HasNotExecutedClassName = "basic-block-has-not-executed"; |