author | Boris Zbarsky <bzbarsky@mit.edu> |
Tue, 07 Jan 2014 19:53:18 -0500 (2014-01-08) | |
changeset 162464 | e0de03b97222e6ce7d6c2a1c402690eb23ea35f1 |
parent 162463 | a3427a45608df38c83b7d5f68b4a99645f87b14d |
child 162465 | b6d1eaed0807b5adf618e632dd555cea670932cf |
push id | 25953 |
push user | cbook@mozilla.com |
push date | Wed, 08 Jan 2014 12:11:30 +0000 (2014-01-08) |
treeherder | mozilla-central@f8b2a073d930 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | khuey |
bugs | 932837 |
milestone | 29.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
dom/base/DOMException.cpp | file | annotate | diff | comparison | revisions | |
dom/bindings/Exceptions.cpp | file | annotate | diff | comparison | revisions |
--- a/dom/base/DOMException.cpp +++ b/dom/base/DOMException.cpp @@ -146,25 +146,29 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION( NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception) NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception) NS_IMPL_CYCLE_COLLECTION_CLASS(Exception) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInner) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mThrownJSVal); NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mInner) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER tmp->mThrownJSVal.setNull(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CI_INTERFACE_GETTER1(Exception, nsIXPCException) Exception::Exception(const char *aMessage, nsresult aResult,
--- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -227,16 +227,21 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(StackDescriptionOwner) JS::FrameDescription& FrameAt(size_t aIndex) { MOZ_ASSERT(aIndex < mDescription->nframes); return mDescription->frames[aIndex]; } + unsigned NumFrames() + { + return mDescription->nframes; + } + private: JS::StackDescription* mDescription; }; NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(StackDescriptionOwner, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(StackDescriptionOwner, Release) NS_IMPL_CYCLE_COLLECTION_CLASS(StackDescriptionOwner) @@ -257,62 +262,103 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Sta NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDescription->frames[i].fun()); } } NS_IMPL_CYCLE_COLLECTION_TRACE_END class JSStackFrame : public nsIStackFrame { public: - NS_DECL_ISUPPORTS + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(JSStackFrame) NS_DECL_NSISTACKFRAME - JSStackFrame(); + // A null aStackDescription or an aIndex that's out of range for the + // number of frames aStackDescription has will mean that the + // JSStackFrame will never look at the stack description. Instead, + // it is expected to be initialized by the caller as needed. + JSStackFrame(StackDescriptionOwner* aStackDescription, size_t aIndex); virtual ~JSStackFrame(); static already_AddRefed<nsIStackFrame> CreateStack(JSContext* cx); static already_AddRefed<nsIStackFrame> CreateStackFrameLocation(uint32_t aLanguage, const char* aFilename, const char* aFunctionName, int32_t aLineNumber, nsIStackFrame* aCaller); private: bool IsJSFrame() const { return mLanguage == nsIProgrammingLanguage::JAVASCRIPT; } + const char* GetFilename(); + const char* GetFunname(); + int32_t GetLineno(); + + nsRefPtr<StackDescriptionOwner> mStackDescription; nsCOMPtr<nsIStackFrame> mCaller; + // Cached values char* mFilename; char* mFunname; int32_t mLineno; uint32_t mLanguage; + + size_t mIndex; + + bool mFilenameInitialized; + bool mFunnameInitialized; + bool mLinenoInitialized; }; -JSStackFrame::JSStackFrame() +JSStackFrame::JSStackFrame(StackDescriptionOwner* aStackDescription, + size_t aIndex) : mFilename(nullptr), mFunname(nullptr), - mLineno(0), - mLanguage(nsIProgrammingLanguage::UNKNOWN) -{} + mLineno(0) +{ + if (aStackDescription && aIndex < aStackDescription->NumFrames()) { + mStackDescription = aStackDescription; + mIndex = aIndex; + mFilenameInitialized = false; + mFunnameInitialized = false; + mLinenoInitialized = false; + mLanguage = nsIProgrammingLanguage::JAVASCRIPT; + } else { + MOZ_ASSERT(!mStackDescription); + mIndex = 0; + mFilenameInitialized = true; + mFunnameInitialized = true; + mLinenoInitialized = true; + mLanguage = nsIProgrammingLanguage::UNKNOWN; + } +} JSStackFrame::~JSStackFrame() { if (mFilename) { nsMemory::Free(mFilename); } if (mFunname) { nsMemory::Free(mFunname); } } -NS_IMPL_ISUPPORTS1(JSStackFrame, nsIStackFrame) +NS_IMPL_CYCLE_COLLECTION_2(JSStackFrame, mStackDescription, mCaller) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(JSStackFrame) +NS_IMPL_CYCLE_COLLECTING_RELEASE(JSStackFrame) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSStackFrame) + NS_INTERFACE_MAP_ENTRY(nsIStackFrame) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END /* readonly attribute uint32_t language; */ NS_IMETHODIMP JSStackFrame::GetLanguage(uint32_t* aLanguage) { *aLanguage = mLanguage; return NS_OK; } @@ -326,50 +372,111 @@ NS_IMETHODIMP JSStackFrame::GetLanguageN *aLanguageName = (char*) nsMemory::Clone(js, sizeof(js)); } else { *aLanguageName = (char*) nsMemory::Clone(cpp, sizeof(cpp)); } return NS_OK; } +const char* +JSStackFrame::GetFilename() +{ + if (!mFilenameInitialized) { + JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex); + if (desc.script()) { + AutoJSContext cx; + JSAutoCompartment ac(cx, desc.script()); + const char* filename = JS_GetScriptFilename(cx, desc.script()); + if (filename) { + mFilename = + (char*)nsMemory::Clone(filename, sizeof(char)*(strlen(filename)+1)); + } + } + mFilenameInitialized = true; + } + + return mFilename; +} + /* readonly attribute string filename; */ NS_IMETHODIMP JSStackFrame::GetFilename(char** aFilename) { NS_ENSURE_ARG_POINTER(aFilename); - if (mFilename) { - *aFilename = (char*) nsMemory::Clone(mFilename, - sizeof(char)*(strlen(mFilename)+1)); + const char* filename = GetFilename(); + if (filename) { + *aFilename = (char*) nsMemory::Clone(filename, + sizeof(char)*(strlen(filename)+1)); } else { *aFilename = nullptr; } return NS_OK; } +const char* +JSStackFrame::GetFunname() +{ + if (!mFunnameInitialized) { + JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex); + if (desc.fun() && desc.script()) { + AutoJSContext cx; + JSAutoCompartment ac(cx, desc.script()); + JS::Rooted<JSFunction*> fun(cx, desc.fun()); + JS::Rooted<JSString*> funid(cx, JS_GetFunctionDisplayId(fun)); + if (funid) { + size_t length = JS_GetStringEncodingLength(cx, funid); + if (length != size_t(-1)) { + mFunname = static_cast<char *>(nsMemory::Alloc(length + 1)); + if (mFunname) { + JS_EncodeStringToBuffer(cx, funid, mFunname, length); + mFunname[length] = '\0'; + } + } + } + } + mFunnameInitialized = true; + } + + return mFunname; +} + /* readonly attribute string name; */ NS_IMETHODIMP JSStackFrame::GetName(char** aFunction) { NS_ENSURE_ARG_POINTER(aFunction); - if (mFunname) { - *aFunction = (char*) nsMemory::Clone(mFunname, - sizeof(char)*(strlen(mFunname)+1)); + const char* funname = GetFunname(); + if (funname) { + *aFunction = (char*) nsMemory::Clone(funname, + sizeof(char)*(strlen(funname)+1)); } else { *aFunction = nullptr; } return NS_OK; } +int32_t +JSStackFrame::GetLineno() +{ + if (!mLinenoInitialized) { + JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex); + mLineno = desc.lineno(); + mLinenoInitialized = true; + } + + return mLineno; +} + /* readonly attribute int32_t lineNumber; */ NS_IMETHODIMP JSStackFrame::GetLineNumber(int32_t* aLineNumber) { - *aLineNumber = mLineno; + *aLineNumber = GetLineno(); return NS_OK; } /* readonly attribute string sourceLine; */ NS_IMETHODIMP JSStackFrame::GetSourceLine(char** aSourceLine) { *aSourceLine = nullptr; return NS_OK; @@ -381,87 +488,75 @@ NS_IMETHODIMP JSStackFrame::GetCaller(ns NS_IF_ADDREF(*aCaller = mCaller); return NS_OK; } /* string toString (); */ NS_IMETHODIMP JSStackFrame::ToString(char** _retval) { const char* frametype = IsJSFrame() ? "JS" : "native"; - const char* filename = mFilename ? mFilename : "<unknown filename>"; - const char* funname = mFunname ? mFunname : "<TOP_LEVEL>"; + const char* filename = GetFilename(); + if (!filename) { + filename = "<unknown filename>"; + } + const char* funname = GetFunname(); + if (!funname) { + funname = "<TOP_LEVEL>"; + } static const char format[] = "%s frame :: %s :: %s :: line %d"; int len = sizeof(char)* (strlen(frametype) + strlen(filename) + strlen(funname)) + sizeof(format) + 3 * sizeof(mLineno); char* buf = (char*) nsMemory::Alloc(len); - JS_snprintf(buf, len, format, frametype, filename, funname, mLineno); + JS_snprintf(buf, len, format, frametype, filename, funname, GetLineno()); *_retval = buf; return NS_OK; } /* static */ already_AddRefed<nsIStackFrame> JSStackFrame::CreateStack(JSContext* cx) { static const unsigned MAX_FRAMES = 100; - nsRefPtr<JSStackFrame> first = new JSStackFrame(); - nsRefPtr<JSStackFrame> self = first; - JS::StackDescription* desc = JS::DescribeStack(cx, MAX_FRAMES); if (!desc) { return nullptr; } nsRefPtr<StackDescriptionOwner> descOwner = new StackDescriptionOwner(desc); - for (size_t i = 0; i < desc->nframes && self; i++) { - self->mLanguage = nsIProgrammingLanguage::JAVASCRIPT; + nsRefPtr<JSStackFrame> first; + nsRefPtr<JSStackFrame> last; - JSAutoCompartment ac(cx, desc->frames[i].script()); - const char* filename = JS_GetScriptFilename(cx, desc->frames[i].script()); - if (filename) { - self->mFilename = - (char*)nsMemory::Clone(filename, sizeof(char)*(strlen(filename)+1)); - } - - self->mLineno = desc->frames[i].lineno(); + // We create one dummy frame at the end (why?), so go up through + // desc->nframes+1 + for (size_t i = 0; i < desc->nframes+1; i++) { + nsRefPtr<JSStackFrame> frame = new JSStackFrame(descOwner, i); - JSFunction* fun = desc->frames[i].fun(); - if (fun) { - JS::Rooted<JSString*> funid(cx, JS_GetFunctionDisplayId(fun)); - if (funid) { - size_t length = JS_GetStringEncodingLength(cx, funid); - if (length != size_t(-1)) { - self->mFunname = static_cast<char *>(nsMemory::Alloc(length + 1)); - if (self->mFunname) { - JS_EncodeStringToBuffer(cx, funid, self->mFunname, length); - self->mFunname[length] = '\0'; - } - } - } + if (last) { + last->mCaller = frame; + } else { + MOZ_ASSERT(!first, "How can we have a first but not a last?"); + first = frame; } - - nsRefPtr<JSStackFrame> frame = new JSStackFrame(); - self->mCaller = frame; - self.swap(frame); + last.swap(frame); } return first.forget(); } /* static */ already_AddRefed<nsIStackFrame> JSStackFrame::CreateStackFrameLocation(uint32_t aLanguage, const char* aFilename, const char* aFunctionName, int32_t aLineNumber, nsIStackFrame* aCaller) { - nsRefPtr<JSStackFrame> self = new JSStackFrame(); + nsRefPtr<JSStackFrame> self = new JSStackFrame(nullptr, 0); self->mLanguage = aLanguage; self->mLineno = aLineNumber; if (aFilename) { self->mFilename = (char*)nsMemory::Clone(aFilename, sizeof(char)*(strlen(aFilename)+1)); }