mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 932837 part 3. Make JSStackFrame get information from the JS stack lazily. r=khuey
This commit is contained in:
parent
dd2f4ef162
commit
030ccd9f4a
@ -151,6 +151,8 @@ 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
|
||||
|
||||
@ -160,6 +162,8 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception)
|
||||
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
|
||||
|
@ -232,6 +232,11 @@ public:
|
||||
return mDescription->frames[aIndex];
|
||||
}
|
||||
|
||||
unsigned NumFrames()
|
||||
{
|
||||
return mDescription->nframes;
|
||||
}
|
||||
|
||||
private:
|
||||
JS::StackDescription* mDescription;
|
||||
};
|
||||
@ -262,10 +267,15 @@ 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>
|
||||
@ -282,20 +292,48 @@ private:
|
||||
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()
|
||||
{
|
||||
@ -307,7 +345,15 @@ JSStackFrame::~JSStackFrame()
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@ -331,14 +377,35 @@ NS_IMETHODIMP JSStackFrame::GetLanguageName(char** aLanguageName)
|
||||
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;
|
||||
}
|
||||
@ -346,14 +413,42 @@ NS_IMETHODIMP JSStackFrame::GetFilename(char** aFilename)
|
||||
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;
|
||||
}
|
||||
@ -361,10 +456,22 @@ NS_IMETHODIMP JSStackFrame::GetName(char** aFunction)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -386,15 +493,21 @@ NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller)
|
||||
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;
|
||||
}
|
||||
@ -404,9 +517,6 @@ 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;
|
||||
@ -414,36 +524,21 @@ JSStackFrame::CreateStack(JSContext* cx)
|
||||
|
||||
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));
|
||||
// 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);
|
||||
|
||||
if (last) {
|
||||
last->mCaller = frame;
|
||||
} else {
|
||||
MOZ_ASSERT(!first, "How can we have a first but not a last?");
|
||||
first = frame;
|
||||
}
|
||||
|
||||
self->mLineno = desc->frames[i].lineno();
|
||||
|
||||
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';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<JSStackFrame> frame = new JSStackFrame();
|
||||
self->mCaller = frame;
|
||||
self.swap(frame);
|
||||
last.swap(frame);
|
||||
}
|
||||
|
||||
return first.forget();
|
||||
@ -456,7 +551,7 @@ JSStackFrame::CreateStackFrameLocation(uint32_t aLanguage,
|
||||
int32_t aLineNumber,
|
||||
nsIStackFrame* aCaller)
|
||||
{
|
||||
nsRefPtr<JSStackFrame> self = new JSStackFrame();
|
||||
nsRefPtr<JSStackFrame> self = new JSStackFrame(nullptr, 0);
|
||||
|
||||
self->mLanguage = aLanguage;
|
||||
self->mLineno = aLineNumber;
|
||||
|
Loading…
Reference in New Issue
Block a user