Commit d0740c87 authored by ggaren@apple.com's avatar ggaren@apple.com

JavaScriptCore:

2008-05-27  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Tim Hatcher.

        Fixed https://bugs.webkit.org/show_bug.cgi?id=19183
        REGRESSION (r33979): Crash in DebuggerCallFrame::functionName when
        clicking button in returnEvent-crash.html

        Added two new debugger hooks, willExecuteProgram and didExecuteProgram,
        along with code to generate them, code to invoke them when unwinding
        due to an exception, and code to dump them.
        
        SunSpider reports no change.

        * VM/CodeBlock.cpp:
        (KJS::debugHookName): I had to mark this function NEVER_INLINE to avoid
        a .4% performance regression. The mind boggles.

WebCore:

2008-05-27  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Tim Hatcher.

        Fixed https://bugs.webkit.org/show_bug.cgi?id=19183
        REGRESSION (r33979): Crash in DebuggerCallFrame::functionName when
        clicking button in returnEvent-crash.html
        
        Added implementations for willExecuteProgram and didExecuteProgram. They
        take care to update our call frame when entering and exiting programs,
        preventing us from keeping around a stale global frame after executing
        a program.
        
        eval programs now show up as "anonymous function" in a new scope. This
        is slightly better than what they used to do -- overwriting the current
        scope -- but obviously we can do better.

WebKit/mac:

2008-05-27  Geoffrey Garen  <ggaren@apple.com>

        Reviewed by Tim Hatcher.
        
        Fixed https://bugs.webkit.org/show_bug.cgi?id=19183
        REGRESSION (r33979): Crash in DebuggerCallFrame::functionName when
        clicking button in returnEvent-crash.html
        
        Added implementations for willExecuteProgram and didExecuteProgram, which
        take care of making sure we're not hanging on to stale data.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@34182 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 6962c143
2008-05-27 Geoffrey Garen <ggaren@apple.com>
Reviewed by Tim Hatcher.
Fixed https://bugs.webkit.org/show_bug.cgi?id=19183
REGRESSION (r33979): Crash in DebuggerCallFrame::functionName when
clicking button in returnEvent-crash.html
Added two new debugger hooks, willExecuteProgram and didExecuteProgram,
along with code to generate them, code to invoke them when unwinding
due to an exception, and code to dump them.
SunSpider reports no change.
* VM/CodeBlock.cpp:
(KJS::debugHookName): I had to mark this function NEVER_INLINE to avoid
a .4% performance regression. The mind boggles.
2008-05-28 Adam Roben <aroben@apple.com>
Fix JavaScriptCore tests on OS X
......
......@@ -95,16 +95,23 @@ static CString regexpName(int re, RegExp* regexp)
return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
}
static const char* debugHookName(int debugHookID)
NEVER_INLINE static const char* debugHookName(int debugHookID)
{
if (debugHookID == DidEnterCallFrame)
switch((DebugHookID)debugHookID) {
case DidEnterCallFrame:
return "didEnterCallFrame";
else if (debugHookID == WillLeaveCallFrame)
case WillLeaveCallFrame:
return "willLeaveCallFrame";
else {
ASSERT(debugHookID == WillExecuteStatement);
case WillExecuteStatement:
return "willExecuteStatement";
case WillExecuteProgram:
return "willExecuteProgram";
case DidExecuteProgram:
return "didExecuteProgram";
}
ASSERT_NOT_REACHED();
return "";
}
static int jumpTarget(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset)
......
......@@ -564,16 +564,16 @@ bool Machine::isOpcode(Opcode opcode)
NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction*& vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
{
CodeBlock* oldCodeBlock = codeBlock;
Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
if (!isGlobalCallFrame(registerBase, r)) {
DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
if (!isGlobalCallFrame(registerBase, r) && callFrame[Callee].u.jsObject) // Check for global and eval code
debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
}
else
debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
}
Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
if (!isGlobalCallFrame(registerBase, r) && callFrame[Callee].u.jsObject) // Check for global and eval code
profiler->didExecute(exec, callFrame[Callee].u.jsObject);
......@@ -851,6 +851,14 @@ NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const
debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
return;
}
case WillExecuteProgram: {
debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
return;
}
case DidExecuteProgram: {
debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
return;
}
}
}
......@@ -2351,10 +2359,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
BEGIN_OPCODE(op_debug) {
/* debug debugHookID(n) firstLine(n) lastLine(n)
Notifies the debugger of the current state of execution:
didEnterCallFrame; willLeaveCallFrame; or willExecuteStatement.
This opcode is only generated while the debugger is attached.
Notifies the debugger of the current state of execution. This opcode
is only generated while the debugger is attached.
*/
int registerOffset = r - (*registerBase);
......
......@@ -47,9 +47,11 @@ namespace KJS {
class ScopeChainNode;
enum DebugHookID {
WillExecuteStatement,
WillExecuteProgram,
DidExecuteProgram,
DidEnterCallFrame,
WillLeaveCallFrame
WillLeaveCallFrame,
WillExecuteStatement
};
class Machine {
......
......@@ -164,6 +164,9 @@ namespace KJS {
*/
virtual void returnEvent(const DebuggerCallFrame&, int sourceId, int lineno) = 0;
virtual void willExecuteProgram(const DebuggerCallFrame&, int sourceId, int lineno) = 0;
virtual void didExecuteProgram(const DebuggerCallFrame&, int sourceId, int lineno) = 0;
private:
HashSet<JSGlobalObject*> m_globalObjects;
};
......
......@@ -5825,9 +5825,13 @@ EvalNode::~EvalNode()
RegisterID* EvalNode::emitCode(CodeGenerator& generator, RegisterID*)
{
generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine());
RefPtr<RegisterID> dstRegister = generator.newTemporary();
generator.emitLoad(dstRegister.get(), jsUndefined());
statementListEmitCode(m_children, generator, dstRegister.get());
generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
generator.emitEnd(dstRegister.get());
return 0;
}
......@@ -5901,9 +5905,13 @@ RegisterID* FunctionBodyNode::emitCode(CodeGenerator& generator, RegisterID*)
RegisterID* ProgramNode::emitCode(CodeGenerator& generator, RegisterID*)
{
generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine());
RefPtr<RegisterID> dstRegister = generator.newTemporary();
generator.emitLoad(dstRegister.get(), jsUndefined());
statementListEmitCode(m_children, generator, dstRegister.get());
generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
generator.emitEnd(dstRegister.get());
return 0;
}
......
2008-05-27 Geoffrey Garen <ggaren@apple.com>
Reviewed by Tim Hatcher.
Fixed https://bugs.webkit.org/show_bug.cgi?id=19183
REGRESSION (r33979): Crash in DebuggerCallFrame::functionName when
clicking button in returnEvent-crash.html
Added implementations for willExecuteProgram and didExecuteProgram. They
take care to update our call frame when entering and exiting programs,
preventing us from keeping around a stale global frame after executing
a program.
eval programs now show up as "anonymous function" in a new scope. This
is slightly better than what they used to do -- overwriting the current
scope -- but obviously we can do better.
2008-05-28 Brady Eidson <beidson@apple.com>
Reviewed by Dan Bernstein
......@@ -45,6 +45,7 @@
#include "kjs_proxy.h"
#include <kjs/DebuggerCallFrame.h>
#include <wtf/MainThread.h>
#include <wtf/UnusedParam.h>
using namespace KJS;
......@@ -419,6 +420,7 @@ void JavaScriptDebugServer::callEvent(const DebuggerCallFrame& debuggerCallFrame
{
if (m_paused)
return;
m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber);
pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}
......@@ -427,10 +429,12 @@ void JavaScriptDebugServer::atStatement(const DebuggerCallFrame& debuggerCallFra
{
if (m_paused)
return;
ASSERT(m_currentCallFrame);
if (!m_currentCallFrame)
m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, 0, sourceID, lineNumber);
else
m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
return;
m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}
......@@ -438,10 +442,15 @@ void JavaScriptDebugServer::returnEvent(const DebuggerCallFrame& debuggerCallFra
{
if (m_paused)
return;
ASSERT(m_currentCallFrame);
if (!m_currentCallFrame)
return;
m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
// Treat stepping over a return statement like stepping out of a function.
// Treat stepping over a return statement like stepping out.
if (m_currentCallFrame == m_pauseOnCallFrame)
m_pauseOnCallFrame = m_currentCallFrame->caller();
m_currentCallFrame = m_currentCallFrame->caller();
......@@ -451,10 +460,43 @@ void JavaScriptDebugServer::exception(const DebuggerCallFrame& debuggerCallFrame
{
if (m_paused)
return;
ASSERT(m_currentCallFrame);
if (!m_currentCallFrame)
return;
if (m_pauseOnExceptions)
m_pauseOnNextStatement = true;
m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}
void JavaScriptDebugServer::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
if (m_paused)
return;
m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber);
pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}
void JavaScriptDebugServer::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
if (m_paused)
return;
ASSERT(m_currentCallFrame);
if (!m_currentCallFrame)
return;
m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
// Treat stepping over the end of a program like stepping out.
if (m_currentCallFrame == m_pauseOnCallFrame)
m_pauseOnCallFrame = m_currentCallFrame->caller();
m_currentCallFrame = m_currentCallFrame->caller();
}
} // namespace WebCore
......@@ -100,6 +100,8 @@ namespace WebCore {
virtual void atStatement(const KJS::DebuggerCallFrame&, int sourceID, int firstLine);
virtual void returnEvent(const KJS::DebuggerCallFrame&, int sourceID, int lineNumber);
virtual void exception(const KJS::DebuggerCallFrame&, int sourceID, int lineNumber);
virtual void willExecuteProgram(const KJS::DebuggerCallFrame&, int sourceId, int lineno);
virtual void didExecuteProgram(const KJS::DebuggerCallFrame&, int sourceId, int lineno);
typedef HashMap<Page*, ListenerSet*> PageListenersMap;
PageListenersMap m_pageListenersMap;
......
2008-05-27 Geoffrey Garen <ggaren@apple.com>
Reviewed by Tim Hatcher.
Fixed https://bugs.webkit.org/show_bug.cgi?id=19183
REGRESSION (r33979): Crash in DebuggerCallFrame::functionName when
clicking button in returnEvent-crash.html
Added implementations for willExecuteProgram and didExecuteProgram, which
take care of making sure we're not hanging on to stale data.
2008-05-27 Timothy Hatcher <timothy@apple.com>
Fixes a bug where unplugging the monitor from a video card and
......
......@@ -90,14 +90,16 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber";
_private = [[WebScriptCallFramePrivate alloc] init];
_private->globalObject = globalObj;
_private->caller = [caller retain];
_private->debuggerCallFrame = new DebuggerCallFrame(debuggerCallFrame);
}
return self;
}
- (void)_setDebuggerCallFrame:(const DebuggerCallFrame&)debuggerCallFrame
{
*_private->debuggerCallFrame = debuggerCallFrame;
if (!_private->debuggerCallFrame)
_private->debuggerCallFrame = new DebuggerCallFrame(debuggerCallFrame);
else
*_private->debuggerCallFrame = debuggerCallFrame;
}
- (void)_clearDebuggerCallFrame
......@@ -164,6 +166,9 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber";
- (NSArray *)scopeChain
{
if (!_private->debuggerCallFrame)
return [NSArray array];
const ScopeChainNode* scopeChain = _private->debuggerCallFrame->scopeChain();
if (!scopeChain->next) // global frame
return [NSArray arrayWithObject:_private->globalObject];
......@@ -184,6 +189,9 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber";
- (NSString *)functionName
{
if (!_private->debuggerCallFrame)
return nil;
const UString* functionName = _private->debuggerCallFrame->functionName();
return functionName ? toNSString(*functionName) : nil;
}
......@@ -192,6 +200,9 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber";
- (id)exception
{
if (!_private->debuggerCallFrame)
return nil;
JSValue* exception = _private->debuggerCallFrame->exception();
return exception ? [self _convertValueToObjcValue:exception] : nil;
}
......@@ -204,6 +215,9 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber";
- (id)evaluateWebScript:(NSString *)script
{
if (!_private->debuggerCallFrame)
return nil;
JSLock lock;
JSValue* exception = 0;
......
......@@ -56,6 +56,8 @@ public:
virtual void atStatement(const KJS::DebuggerCallFrame&, int sourceID, int lineNumber);
virtual void returnEvent(const KJS::DebuggerCallFrame&, int sourceID, int lineNumber);
virtual void exception(const KJS::DebuggerCallFrame&, int sourceID, int lineNumber);
virtual void willExecuteProgram(const KJS::DebuggerCallFrame&, int sourceId, int lineno);
virtual void didExecuteProgram(const KJS::DebuggerCallFrame&, int sourceId, int lineno);
private:
bool m_callingDelegate;
......
......@@ -178,3 +178,13 @@ void WebScriptDebugger::exception(const DebuggerCallFrame& debuggerCallFrame, in
m_callingDelegate = false;
}
void WebScriptDebugger::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, int sourceId, int lineno)
{
[m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame];
}
void WebScriptDebugger::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, int sourceId, int lineno)
{
[m_topCallFrame.get() _clearDebuggerCallFrame];
}
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