bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Breakpoint *hitBreakpoint) { if (!m_breakpointsActivated) return false; SourceIDToBreakpointsMap::const_iterator it = m_sourceIDToBreakpoints.find(sourceID); if (it == m_sourceIDToBreakpoints.end()) return false; unsigned line = position.m_line.zeroBasedInt(); unsigned column = position.m_column.zeroBasedInt(); LineToBreakpointsMap::const_iterator breaksIt = it->value.find(line); if (breaksIt == it->value.end()) return false; bool hit = false; const BreakpointsList& breakpoints = *breaksIt->value; Breakpoint* breakpoint; for (breakpoint = breakpoints.head(); breakpoint; breakpoint = breakpoint->next()) { unsigned breakLine = breakpoint->line; unsigned breakColumn = breakpoint->column; // Since frontend truncates the indent, the first statement in a line must match the breakpoint (line,0). ASSERT(this == m_currentCallFrame->codeBlock()->globalObject()->debugger()); if ((line != m_lastExecutedLine && line == breakLine && !breakColumn) || (line == breakLine && column == breakColumn)) { hit = true; break; } } if (!hit) return false; if (hitBreakpoint) *hitBreakpoint = *breakpoint; if (breakpoint->condition.isEmpty()) return true; // We cannot stop in the debugger while executing condition code, // so make it looks like the debugger is already paused. TemporaryPausedState pausedState(*this); JSValue exception; DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame(); JSValue result = debuggerCallFrame->evaluate(breakpoint->condition, exception); // We can lose the debugger while executing JavaScript. if (!m_currentCallFrame) return false; if (exception) { // An erroneous condition counts as "false". handleExceptionInBreakpointCondition(m_currentCallFrame, exception); return false; } return result.toBoolean(m_currentCallFrame); }
BreakpointID Debugger::setBreakpoint(Breakpoint& breakpoint, bool& existing) { ASSERT(breakpoint.resolved); ASSERT(breakpoint.sourceID != noSourceID); SourceID sourceID = breakpoint.sourceID; unsigned line = breakpoint.line; unsigned column = breakpoint.column; SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(breakpoint.sourceID); if (it == m_sourceIDToBreakpoints.end()) it = m_sourceIDToBreakpoints.set(sourceID, LineToBreakpointsMap()).iterator; LineToBreakpointsMap::iterator breaksIt = it->value.find(line); if (breaksIt == it->value.end()) breaksIt = it->value.set(line, adoptRef(new BreakpointsList)).iterator; BreakpointsList& breakpoints = *breaksIt->value; for (Breakpoint* current = breakpoints.head(); current; current = current->next()) { if (current->column == column) { // Found existing breakpoint. Do not create a duplicate at this location. existing = true; return current->id; } } existing = false; BreakpointID id = ++m_topBreakpointID; RELEASE_ASSERT(id != noBreakpointID); breakpoint.id = id; Breakpoint* newBreakpoint = new Breakpoint(breakpoint); breakpoints.append(newBreakpoint); m_breakpointIDToBreakpoint.set(id, newBreakpoint); toggleBreakpoint(*newBreakpoint, BreakpointEnabled); return id; }
BreakpointID Debugger::setBreakpoint(Breakpoint breakpoint, unsigned& actualLine, unsigned& actualColumn) { SourceID sourceID = breakpoint.sourceID; unsigned line = breakpoint.line; unsigned column = breakpoint.column; SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID); if (it == m_sourceIDToBreakpoints.end()) it = m_sourceIDToBreakpoints.set(sourceID, LineToBreakpointsMap()).iterator; LineToBreakpointsMap::iterator breaksIt = it->value.find(line); if (breaksIt == it->value.end()) breaksIt = it->value.set(line, adoptRef(new BreakpointsList)).iterator; BreakpointsList& breakpoints = *breaksIt->value; for (Breakpoint* current = breakpoints.head(); current; current = current->next()) { if (current->column == column) { // The breakpoint already exists. We're not allowed to create a new // breakpoint at this location. Rather than returning the breakpointID // of the pre-existing breakpoint, we need to return noBreakpointID // to indicate that we're not creating a new one. return noBreakpointID; } } BreakpointID id = ++m_topBreakpointID; RELEASE_ASSERT(id != noBreakpointID); breakpoint.id = id; actualLine = line; actualColumn = column; Breakpoint* newBreakpoint = new Breakpoint(breakpoint); breakpoints.append(newBreakpoint); m_breakpointIDToBreakpoint.set(id, newBreakpoint); toggleBreakpoint(breakpoint, BreakpointEnabled); return id; }
void Debugger::removeBreakpoint(BreakpointID id) { ASSERT(id != noBreakpointID); BreakpointIDToBreakpointMap::iterator idIt = m_breakpointIDToBreakpoint.find(id); ASSERT(idIt != m_breakpointIDToBreakpoint.end()); Breakpoint* breakpoint = idIt->value; SourceID sourceID = breakpoint->sourceID; ASSERT(sourceID); SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID); ASSERT(it != m_sourceIDToBreakpoints.end()); LineToBreakpointsMap::iterator breaksIt = it->value.find(breakpoint->line); ASSERT(breaksIt != it->value.end()); toggleBreakpoint(*breakpoint, BreakpointDisabled); BreakpointsList& breakpoints = *breaksIt->value; #if !ASSERT_DISABLED bool found = false; for (Breakpoint* current = breakpoints.head(); current && !found; current = current->next()) { if (current->id == breakpoint->id) found = true; } ASSERT(found); #endif m_breakpointIDToBreakpoint.remove(idIt); breakpoints.remove(breakpoint); delete breakpoint; if (breakpoints.isEmpty()) { it->value.remove(breaksIt); if (it->value.isEmpty()) m_sourceIDToBreakpoints.remove(it); } }