Merge pull request #185 from ethereum/sourceLocationStep2

step to next source location change
pull/7/head
chriseth 8 years ago committed by GitHub
commit 63702ccaef
  1. 21
      src/helpers/util.js
  2. 7
      src/ui/ButtonNavigator.js
  3. 8
      src/ui/CodeListView.js
  4. 6
      src/ui/DropdownPanel.js
  5. 89
      src/ui/Slider.js
  6. 64
      src/ui/StepManager.js
  7. 13
      src/util/internalCallTree.js
  8. 7
      test-browser/init.js
  9. 6
      test-browser/vmdebugger.js

@ -85,6 +85,27 @@ module.exports = {
return index >= 0 ? array[index] : null
},
/*
Binary Search:
Assumes that @arg array is sorted increasingly
return Return i such that |array[i] - target| is smallest among all i and -1 for an empty array.
Returns the smallest i for multiple candidates.
*/
findClosestIndex: function (target, array) {
if (array.length === 0) {
return -1
}
var index = this.findLowerBound(target, array)
if (index < 0) {
return array[0]
} else if (index >= array.length - 1) {
return array[array.length - 1]
} else {
var middle = (array[index] + array[index + 1]) / 2
return target <= middle ? index : index + 1
}
},
/**
* Find the call from @args rootCall which contains @args index (recursive)
*

@ -10,7 +10,6 @@ function ButtonNavigator (_parent, _traceManager) {
this.overBackDisabled = true
this.intoForwardDisabled = true
this.overForwardDisabled = true
this.nextCallDisabled = true
this.jumpOutDisabled = true
this.traceManager = _traceManager
@ -67,8 +66,6 @@ ButtonNavigator.prototype.render = function () {
</button>
<button id='overforward' title='step over forward' class='fa fa-angle-double-right' style=${ui.formatCss(style.button)} onclick=${function () { self.event.trigger('stepOverForward') }} disabled=${this.overForwardDisabled} >
</button>
<button id='nextcall' title='step next call' class='fa fa-chevron-right' style=${ui.formatCss(style.button)} onclick=${function () { self.event.trigger('jumpNextCall') }} disabled=${this.nextCallDisabled} >
</button>
<button id='jumpout' title='jump out' class='fa fa-share' style=${ui.formatCss(style.button)} onclick=${function () { self.event.trigger('jumpOut') }} disabled=${this.jumpOutDisabled} >
</button>
<div id='reverted' style="display:none">
@ -90,7 +87,6 @@ ButtonNavigator.prototype.reset = function () {
this.overBackDisabled = true
this.intoForwardDisabled = true
this.overForwardDisabled = true
this.nextCallDisabled = true
this.jumpOutDisabled = true
resetWarning(this)
}
@ -110,8 +106,6 @@ ButtonNavigator.prototype.stepChanged = function (step) {
} else {
self.intoForwardDisabled = step >= length - 1
self.overForwardDisabled = step >= length - 1
var nextCall = self.traceManager.findNextCall(step)
self.nextCallDisabled = nextCall === step
var stepOut = self.traceManager.findStepOut(step)
self.jumpOutDisabled = stepOut === step
}
@ -126,7 +120,6 @@ ButtonNavigator.prototype.updateAll = function () {
this.updateDisabled('overback', this.overBackDisabled)
this.updateDisabled('overforward', this.overForwardDisabled)
this.updateDisabled('intoforward', this.intoForwardDisabled)
this.updateDisabled('nextcall', this.nextCallDisabled)
this.updateDisabled('jumpout', this.jumpOutDisabled)
this.updateDisabled('jumptoexception', this.jumpOutDisabled)
}

@ -3,8 +3,10 @@ var style = require('./styles/basicStyles')
var yo = require('yo-yo')
var ui = require('../helpers/ui')
var DropdownPanel = require('./DropdownPanel')
var EventManager = require('../lib/eventManager')
function CodeListView (_parent, _codeManager) {
this.event = new EventManager()
this.parent = _parent
this.codeManager = _codeManager
this.code
@ -12,6 +14,12 @@ function CodeListView (_parent, _codeManager) {
this.codeView
this.itemSelected
this.basicPanel = new DropdownPanel('Instructions', {json: false})
this.basicPanel.event.register('hide', () => {
this.event.trigger('hide', [])
})
this.basicPanel.event.register('show', () => {
this.event.trigger('show', [])
})
this.init()
}

@ -4,8 +4,10 @@ var ui = require('../helpers/ui')
var styleDropdown = require('./styles/dropdownPanel')
var basicStyles = require('./styles/basicStyles')
var TreeView = require('./TreeView')
var EventManager = require('../lib/eventManager')
function DropdownPanel (_name, _opts) {
this.event = new EventManager()
if (!_opts) {
_opts = {}
}
@ -70,9 +72,11 @@ DropdownPanel.prototype.toggle = function () {
if (el.style.display === '') {
el.style.display = 'none'
caret.className = 'fa fa-caret-right'
this.event.trigger('hide', [])
} else {
el.style.display = ''
caret.className = 'fa fa-caret-down'
this.event.trigger('show', [])
}
}
@ -82,6 +86,7 @@ DropdownPanel.prototype.hide = function () {
var el = this.view.querySelector('.dropdownpanel')
el.style.display = 'none'
caret.className = 'fa fa-caret-right'
this.event.trigger('hide', [])
}
}
@ -91,6 +96,7 @@ DropdownPanel.prototype.show = function () {
var el = this.view.querySelector('.dropdownpanel')
el.style.display = ''
caret.className = 'fa fa-caret-down'
this.event.trigger('show', [])
}
}

@ -4,19 +4,22 @@ var EventManager = require('../lib/eventManager')
var yo = require('yo-yo')
var ui = require('../helpers/ui')
function Slider (_traceManager) {
this.event = new EventManager()
this.traceManager = _traceManager
this.max
this.disabled = true
this.view
class Slider {
constructor (_traceManager, _stepOverride) {
this.event = new EventManager()
this.traceManager = _traceManager
this.max
this.disabled = true
this.view
this.solidityMode = false
this.stepOverride = _stepOverride
this.previousValue = null
}
this.previousValue = null
}
Slider.prototype.render = function () {
var self = this
var view = yo`<div>
render () {
var self = this
var view = yo`<div>
<input
id='slider'
style=${ui.formatCss(style.rule)}
@ -28,43 +31,45 @@ Slider.prototype.render = function () {
oninput=${function () { self.onChange() }}
disabled=${this.disabled} />
</div>`
if (!this.view) {
this.view = view
if (!this.view) {
this.view = view
}
return view
}
return view
}
Slider.prototype.init = function (length) {
var slider = document.getElementById('slider')
slider.setAttribute('max', length - 1)
this.max = length - 1
this.updateDisabled(length === 0)
this.disabled = length === 0
this.setValue(0)
}
init (length) {
var slider = this.view.querySelector('#slider')
slider.setAttribute('max', length - 1)
this.max = length - 1
this.updateDisabled(length === 0)
this.disabled = length === 0
this.setValue(0)
}
Slider.prototype.onChange = function (event) {
var value = parseInt(document.getElementById('slider').value)
if (value === this.previousValue) return
this.previousValue = value
this.event.trigger('moved', [value])
}
onChange (event) {
var value = parseInt(this.view.querySelector('#slider').value)
if (this.stepOverride) {
var correctedValue = this.stepOverride(value)
if (correctedValue !== value) {
this.setValue(correctedValue)
value = correctedValue
}
}
if (value === this.previousValue) return
this.previousValue = value
this.event.trigger('moved', [value])
}
Slider.prototype.setValue = function (value) {
var slider = document.getElementById('slider')
var diff = value - slider.value
if (diff > 0) {
slider.stepUp(diff)
} else {
slider.stepDown(Math.abs(diff))
setValue (value) {
this.view.querySelector('#slider').value = value
}
}
Slider.prototype.updateDisabled = function (disabled) {
if (disabled) {
document.getElementById('slider').setAttribute('disabled', true)
} else {
document.getElementById('slider').removeAttribute('disabled')
updateDisabled (disabled) {
if (disabled) {
this.view.querySelector('#slider').setAttribute('disabled', true)
} else {
this.view.querySelector('#slider').removeAttribute('disabled')
}
}
}

@ -3,11 +3,14 @@ var ButtonNavigator = require('./ButtonNavigator')
var Slider = require('./Slider')
var EventManager = require('../lib/eventManager')
var yo = require('yo-yo')
var utils = require('../helpers/util.js')
function StepManager (_parent, _traceManager) {
this.event = new EventManager()
this.parent = _parent
this.traceManager = _traceManager
this.sourceMapByAddress = {}
this.solidityMode = false
var self = this
this.parent.event.register('newTraceLoaded', this, function () {
@ -21,11 +24,23 @@ function StepManager (_parent, _traceManager) {
})
})
this.slider = new Slider(this.traceManager)
this.slider = new Slider(this.traceManager, (step) => {
return this.solidityMode ? this.resolveToReducedTrace(step, 0) : step
})
this.slider.event.register('moved', this, function (step) {
self.sliderMoved(step)
})
this.parent.callTree.event.register('callTreeReady', () => {
this.solidityMode = true
this.parent.vmDebugger.asmCode.event.register('hide', () => {
this.solidityMode = this.parent.callTree.reducedTrace.length !== 0
})
this.parent.vmDebugger.asmCode.event.register('show', () => {
this.solidityMode = false
})
})
this.buttonNavigator = new ButtonNavigator(_parent, this.traceManager)
this.buttonNavigator.event.register('stepIntoBack', this, function () {
self.stepIntoBack()
@ -39,9 +54,6 @@ function StepManager (_parent, _traceManager) {
this.buttonNavigator.event.register('stepOverForward', this, function () {
self.stepOverForward()
})
this.buttonNavigator.event.register('jumpNextCall', this, function () {
self.jumpNextCall()
})
this.buttonNavigator.event.register('jumpOut', this, function () {
self.jumpOut()
})
@ -50,6 +62,20 @@ function StepManager (_parent, _traceManager) {
})
}
StepManager.prototype.resolveToReducedTrace = function (value, incr) {
if (this.parent.callTree.reducedTrace.length) {
var nextSource = utils.findClosestIndex(value, this.parent.callTree.reducedTrace)
nextSource = nextSource + incr
if (nextSource <= 0) {
nextSource = 0
} else if (nextSource > this.parent.callTree.reducedTrace.length) {
nextSource = this.parent.callTree.reducedTrace.length - 1
}
return this.parent.callTree.reducedTrace[nextSource]
}
return value
}
StepManager.prototype.render = function () {
return (
yo`<div>
@ -93,7 +119,12 @@ StepManager.prototype.stepIntoForward = function () {
if (!this.traceManager.isLoaded()) {
return
}
var step = this.currentStepIndex + 1
var step = this.currentStepIndex
if (this.solidityMode) {
step = this.resolveToReducedTrace(step, 1)
} else {
step += 1
}
if (!this.traceManager.inRange(step)) {
return
}
@ -105,7 +136,12 @@ StepManager.prototype.stepIntoBack = function () {
if (!this.traceManager.isLoaded()) {
return
}
var step = this.currentStepIndex - 1
var step = this.currentStepIndex
if (this.solidityMode) {
step = this.resolveToReducedTrace(step, -1)
} else {
step -= 1
}
if (!this.traceManager.inRange(step)) {
return
}
@ -118,6 +154,9 @@ StepManager.prototype.stepOverForward = function () {
return
}
var step = this.traceManager.findStepOverForward(this.currentStepIndex)
if (this.solidityMode) {
step = this.resolveToReducedTrace(step, 1)
}
this.slider.setValue(step)
this.changeState(step)
}
@ -127,15 +166,9 @@ StepManager.prototype.stepOverBack = function () {
return
}
var step = this.traceManager.findStepOverBack(this.currentStepIndex)
this.slider.setValue(step)
this.changeState(step)
}
StepManager.prototype.jumpNextCall = function () {
if (!this.traceManager.isLoaded()) {
return
if (this.solidityMode) {
step = this.resolveToReducedTrace(step, -1)
}
var step = this.traceManager.findNextCall(this.currentStepIndex)
this.slider.setValue(step)
this.changeState(step)
}
@ -145,6 +178,9 @@ StepManager.prototype.jumpOut = function () {
return
}
var step = this.traceManager.findStepOut(this.currentStepIndex)
if (this.solidityMode) {
step = this.resolveToReducedTrace(step, 0)
}
this.slider.setValue(step)
this.changeState(step)
}

@ -37,6 +37,7 @@ class InternalCallTree {
this.event.trigger('callTreeBuildFailed', [result.error])
} else {
console.log('ready')
createReducedTrace(this, traceManager.trace.length - 1)
this.event.trigger('callTreeReady', [this.scopes, this.scopeStarts])
}
})
@ -59,6 +60,7 @@ class InternalCallTree {
this.scopeStarts = {}
this.variableDeclarationByFile = {}
this.astWalker = new AstWalker()
this.reducedTrace = []
}
/**
@ -87,10 +89,17 @@ async function buildTree (tree, step, scopeId) {
let subScope = 1
tree.scopeStarts[step] = scopeId
tree.scopes[scopeId] = { firstStep: step, locals: {} }
var currentSourceLocation = {}
while (step < tree.traceManager.trace.length) {
var sourceLocation
try {
sourceLocation = await extractSourceLocation(tree, step)
if (sourceLocation.start !== currentSourceLocation.start ||
sourceLocation.length !== currentSourceLocation.length ||
sourceLocation.file !== currentSourceLocation.file) {
tree.reducedTrace.push(step)
currentSourceLocation = sourceLocation
}
} catch (e) {
return { outStep: step, error: 'InternalCallTree - Error resolving source location. ' + step + ' ' + e.message }
}
@ -122,6 +131,10 @@ async function buildTree (tree, step, scopeId) {
return { outStep: step }
}
function createReducedTrace (tree, index) {
tree.reducedTrace.push(index)
}
function includeVariableDeclaration (tree, step, sourceLocation, scopeId) {
var variableDeclaration = resolveVariableDeclaration(tree, step, sourceLocation)
if (variableDeclaration && !tree.scopes[scopeId].locals[variableDeclaration.attributes.name]) {

@ -11,6 +11,13 @@ module.exports = function (browser, callback) {
}
function extendBrowser (browser) {
browser.multipleClick = function (id, time) {
for (var k = 0; k < time; k++) {
browser.click(id)
}
return browser
}
browser.assertCurrentSelectedItem = function (expected) {
browser.execute(function (id) {
var node = document.querySelector('#asmcodes div div[selected="selected"] span')

@ -62,7 +62,7 @@ function panels (browser) {
.clearValue('#txinput')
.setValue('#txinput', '0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51')
.click('#load')
.click('#nextcall')
.multipleClick('#intoforward', 63)
.assertStack(['0:0x', '1:0x60', '2:0x65', '3:0x38', '4:0x55', '5:0x60fe47b1'])
.assertStorageChanges(['0x00:0x38'])
.assertCallData(['0:0x60fe47b10000000000000000000000000000000000000000000000000000000000000038'])
@ -121,7 +121,7 @@ function stepping (browser) {
.click('#intoback')
.click('#intoback')
.assertCurrentSelectedItem('002 PUSH1 40')
.click('#nextcall')
.multipleClick('#intoforward', 62)
.assertCurrentSelectedItem('181 CREATE')
.click('#intoforward')
.click('#intoforward')
@ -170,7 +170,7 @@ function stepdetail (browser) {
})
*/
.assertStepDetail('6', '6', '', '3', '84476', '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5')
.click('#nextcall')
.multipleClick('#intoforward', 57)
.assertStepDetail('63', '63', '', '32000', '79283', '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5')
.click('#overforward')
.click('#intoback')

Loading…
Cancel
Save