曾经写了一篇简单的文章,讲述了qtwebkit中获取错误时候js的行号以及文件名的 http://blogold.chinaunix.net/u/18544/showart.php?id=2622370。
但是经过一段时间的验证,发现这个还是有缺陷。
即当测试时候如果发现问题,就需要remote debug或者即使在本机也不是很方便,因此后来加了一些特别处理。
简单来说想在弹出那个shouldinterruptjs的dlg之前能够弹另外一个自定义对话框,而这个对话框能够显示出问题的行号,文件名。
所以做了如下一些修改。
1. 当然还是关闭jit,流氓关闭方法前面的文章也有。
2. 截获timeout的触发点,修改通知方式
src\3rdparty\webkit\JavaScriptCore\interpreter\Interpreter.cpp
#define CHECK_FOR_TIMEOUT() \
if (!--tickCount) { \
- if (globalData->timeoutChecker.didTimeOut(callFrame)) { \
+ if (globalData->timeoutChecker.didTimeOut(callFrame,vPC)) { \
exceptionValue = jsNull(); \
goto vm_throw; \
} \
3. src\3rdparty\webkit\JavaScriptCore\runtime\JSGlobalObject.h
+ virtual void internalException(const char*) const { }
4. src\3rdparty\webkit\JavaScriptCore\runtime\TimeoutChecker.cpp
+bool TimeoutChecker::didTimeOut(ExecState* exec,Instruction* vPC)
+{
+ unsigned currentTime = getCPUTime();
+
+ if (!m_timeAtLastCheck) {
+ // Suspicious amount of looping in a script -- start timing it
+ m_timeAtLastCheck = currentTime;
+ return false;
+ }
+
+ unsigned timeDiff = currentTime - m_timeAtLastCheck;
+
+ if (timeDiff == 0)
+ timeDiff = 1;
+
+ m_timeExecuting += timeDiff;
+ m_timeAtLastCheck = currentTime;
+
+ // Adjust the tick threshold so we get the next checkTimeout call in the
+ // interval specified in intervalBetweenChecks.
+ m_ticksUntilNextCheck = static_cast((static_cast(intervalBetweenChecks) / timeDiff) * m_ticksUntilNextCheck);
+ // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
+ // preferred script check time interval.
+ if (m_ticksUntilNextCheck == 0)
+ m_ticksUntilNextCheck = ticksUntilFirstCheck;
+
+ if (m_timeoutInterval && m_timeExecuting > m_timeoutInterval) {
+ CodeBlock* codeBlock = exec->codeBlock();
+ int bytecodeOffset = vPC - exec->codeBlock()->instructions().begin();
+ int linenm = codeBlock->lineNumberForBytecodeOffset(exec, bytecodeOffset);
+ int sourceID = codeBlock->ownerExecutable()->sourceID();
+ const UString& strURL = codeBlock->ownerExecutable()->sourceURL();
+ const UString& strCode = UString(codeBlock->source()->data(),codeBlock->source()->length());
+
+ UString strSourceOffset = UString::from(codeBlock->sourceOffset());
+ UString strLineNum = UString::from(linenm);
+ UString strSourceID = UString::from(sourceID);
+
+ CString strMsg("linenum=");
+ strMsg += CString(strLineNum.ascii());
+ strMsg += ("\n");
+ strMsg += "offset=";
+ strMsg += CString(strSourceOffset.ascii());
+ //strMsg += ("\n");
+ //strMsg += "sourceid=";
+ //strMsg += CString(strSourceID.ascii());
+ strMsg += ("\n");
+ strMsg += "url=";
+ strMsg += CString(strURL.ascii());
+ strMsg += ("\n");
+ strMsg += "code=";
+ strMsg += CString(strCode.ascii());
+
+ exec->dynamicGlobalObject()->internalException(strMsg.c_str());
+ // endif
+ if (exec->dynamicGlobalObject()->shouldInterruptScript())
+ return true;
+
+ reset();
+ }
+
+ return false;
+}
5. src\3rdparty\webkit\WebCore\bindings\js\JSDOMWindowBase.cpp
+void JSDOMWindowBase::internalException(const char* msg) const
+{
+ ASSERT(impl()->frame());
+ Page* page = impl()->frame()->page();
+
+ // See . We don't think that page can ever be NULL
+ // in this case, but if it is, we've gotten into a state where we may have
+ // hung the UI, with no way to ask the client whether to cancel execution.
+ // For now, our solution is just to cancel execution no matter what,
+ // ensuring that we never hang. We might want to consider other solutions
+ // if we discover problems with this one.
+ ASSERT(page);
+ if (!page)
+ return ;
+
+ return page->chrome()->runJavaScriptAlert(impl()->frame(),String(msg));
+}
这样当出现问题时候就会弹出文件,行号,偏移量。
这儿有个小插曲,上面红色部分代码还print了code,那么为什么呢?
当初首次修改的时候,发现如果发生问题的代码出现在一个html ref的js或者js ref的另外一个js时候,url 竟然是空的,行号是有的。
后来找来找去把这个code print出来即可,而且这个code本身最后还带有这个code是来自于哪个js文件的信息。
这样当出现问题时候,100%知道了是谁,即使碰到压缩过的js文件也可以通过offset找到是哪个地方。