mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 799640 - Part 2: Save profiles on shutdown using custom JSON encoder. r=ehsan
This commit is contained in:
parent
e9dec350e6
commit
5137011d7b
@ -3937,6 +3937,7 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
|
||||
MOZ_gdk_display_close(mGdkDisplay);
|
||||
#endif
|
||||
|
||||
SAMPLER_SHUTDOWN();
|
||||
rv = LaunchChild(mNativeApp, true);
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
@ -3959,6 +3960,8 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
|
||||
|
||||
XRE_DeinitCommandLine();
|
||||
|
||||
SAMPLER_SHUTDOWN();
|
||||
|
||||
return NS_FAILED(rv) ? 1 : 0;
|
||||
}
|
||||
|
||||
@ -4070,6 +4073,7 @@ XRE_mainMetro(int argc, char* argv[], const nsXREAppData* aAppData)
|
||||
// thread that called XRE_metroStartup.
|
||||
NS_ASSERTION(!xreMainPtr->mScopedXPCom,
|
||||
"XPCOM Shutdown hasn't occured, and we are exiting.");
|
||||
SAMPLER_SHUTDOWN();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
30
tools/profiler/JSAObjectBuilder.h
Normal file
30
tools/profiler/JSAObjectBuilder.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef JSAOBJECTBUILDER_H
|
||||
#define JSAOBJECTBUILDER_H
|
||||
|
||||
class JSCustomObject;
|
||||
class JSCustomArray;
|
||||
class nsAString;
|
||||
|
||||
class JSAObjectBuilder
|
||||
{
|
||||
public:
|
||||
virtual ~JSAObjectBuilder() = 0;
|
||||
|
||||
virtual void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue) = 0;
|
||||
virtual void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue) = 0;
|
||||
virtual void DefineProperty(JSCustomObject *aObject, const char *name, int value) = 0;
|
||||
virtual void DefineProperty(JSCustomObject *aObject, const char *name, double value) = 0;
|
||||
virtual void DefineProperty(JSCustomObject *aObject, const char *name, const char *value) = 0;
|
||||
virtual void ArrayPush(JSCustomArray *aArray, int value) = 0;
|
||||
virtual void ArrayPush(JSCustomArray *aArray, const char *value) = 0;
|
||||
virtual void ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject) = 0;
|
||||
virtual JSCustomArray *CreateArray() = 0;
|
||||
virtual JSCustomObject *CreateObject() = 0;
|
||||
};
|
||||
|
||||
#endif
|
311
tools/profiler/JSCustomObjectBuilder.cpp
Normal file
311
tools/profiler/JSCustomObjectBuilder.cpp
Normal file
@ -0,0 +1,311 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "JSCustomObjectBuilder.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsUTF8Utils.h"
|
||||
|
||||
#if _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
// These are owned and deleted by JSCustomObject
|
||||
struct PropertyValue {
|
||||
virtual ~PropertyValue() {}
|
||||
virtual void SendToStream(std::ostream& stream) = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct finalizer_impl
|
||||
{
|
||||
static void run(T) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct finalizer_impl<T*>
|
||||
{
|
||||
static void run(T* p) {
|
||||
delete p;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct finalizer_impl<char *>
|
||||
{
|
||||
static void run(char* p) {
|
||||
free(p);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class TemplatePropertyValue : public PropertyValue {
|
||||
public:
|
||||
TemplatePropertyValue(T aValue)
|
||||
: mValue(aValue)
|
||||
{}
|
||||
|
||||
~TemplatePropertyValue() {
|
||||
finalizer_impl<T>::run(mValue);
|
||||
}
|
||||
|
||||
virtual void SendToStream(std::ostream& stream);
|
||||
private:
|
||||
T mValue;
|
||||
};
|
||||
|
||||
// Escape a UTF8 string to a stream. When an illegal encoding
|
||||
// is found it will insert "INVALID" and the function will return.
|
||||
void EscapeToStream(std::ostream& stream, const char* str) {
|
||||
stream << "\"";
|
||||
|
||||
size_t len = strlen(str);
|
||||
const char* end = &str[len];
|
||||
while (str < end) {
|
||||
bool err;
|
||||
const char* utf8CharStart = str;
|
||||
uint32_t ucs4Char = UTF8CharEnumerator::NextChar(&str, end, &err);
|
||||
|
||||
if (err) {
|
||||
// Encoding error
|
||||
stream << "INVALID\"";
|
||||
return;
|
||||
}
|
||||
|
||||
// See http://www.ietf.org/rfc/rfc4627.txt?number=4627
|
||||
// characters that must be escaped: quotation mark,
|
||||
// reverse solidus, and the control characters
|
||||
// (U+0000 through U+001F).
|
||||
if (ucs4Char == '\"') {
|
||||
stream << "\\\"";
|
||||
} else if (ucs4Char == '\\') {
|
||||
stream << "\\\\";
|
||||
} else if (ucs4Char > 0xFF) {
|
||||
PRUnichar chr[2];
|
||||
ConvertUTF8toUTF16 encoder(chr);
|
||||
encoder.write(utf8CharStart, str-utf8CharStart);
|
||||
char escChar[13];
|
||||
snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X\\u%04X", chr[0], chr[1]);
|
||||
stream << escChar;
|
||||
} else if (ucs4Char < 0x1F || ucs4Char > 0xFF) {
|
||||
char escChar[7];
|
||||
snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X", ucs4Char);
|
||||
stream << escChar;
|
||||
} else {
|
||||
stream << char(ucs4Char);
|
||||
}
|
||||
}
|
||||
stream << "\"";
|
||||
}
|
||||
|
||||
class JSCustomObject {
|
||||
public:
|
||||
JSCustomObject() {
|
||||
mProperties.Init();
|
||||
}
|
||||
~JSCustomObject();
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, JSCustomObject* entry);
|
||||
|
||||
template<class T>
|
||||
void AddProperty(const char* aName, T aValue) {
|
||||
mProperties.Put(nsDependentCString(aName), new TemplatePropertyValue<T>(aValue));
|
||||
}
|
||||
|
||||
nsDataHashtable<nsCStringHashKey, PropertyValue*> mProperties;
|
||||
};
|
||||
|
||||
class JSCustomArray {
|
||||
public:
|
||||
nsTArray<PropertyValue*> mValues;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, JSCustomArray* entry);
|
||||
|
||||
template<class T>
|
||||
void AppendElement(T aValue) {
|
||||
mValues.AppendElement(new TemplatePropertyValue<T>(aValue));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct SendToStreamImpl
|
||||
{
|
||||
static void run(std::ostream& stream, const T& t) {
|
||||
stream << t;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SendToStreamImpl<T*>
|
||||
{
|
||||
static void run(std::ostream& stream, T* t) {
|
||||
stream << *t;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct SendToStreamImpl<char *>
|
||||
{
|
||||
static void run(std::ostream& stream, char* p) {
|
||||
EscapeToStream(stream, p);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct SendToStreamImpl<JSCustomObject*>
|
||||
{
|
||||
static void run(std::ostream& stream, JSCustomObject* p) {
|
||||
stream << p;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct SendToStreamImpl<JSCustomArray*>
|
||||
{
|
||||
static void run(std::ostream& stream, JSCustomArray* p) {
|
||||
stream << p;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> void
|
||||
TemplatePropertyValue<T>::SendToStream(std::ostream& stream)
|
||||
{
|
||||
SendToStreamImpl<T>::run(stream, mValue);
|
||||
}
|
||||
|
||||
struct JSONStreamClosure {
|
||||
std::ostream& mStream;
|
||||
bool mNeedsComma;
|
||||
};
|
||||
|
||||
PLDHashOperator HashTableOutput(const nsACString& aKey, PropertyValue* aValue, void* stream)
|
||||
{
|
||||
JSONStreamClosure& streamClosure = *(JSONStreamClosure*)stream;
|
||||
if (streamClosure.mNeedsComma) {
|
||||
streamClosure.mStream << ",";
|
||||
}
|
||||
streamClosure.mNeedsComma = true;
|
||||
EscapeToStream(streamClosure.mStream, (const char*)aKey.BeginReading());
|
||||
streamClosure.mStream << ":";
|
||||
aValue->SendToStream(streamClosure.mStream);
|
||||
return PLDHashOperator::PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& stream, JSCustomObject* entry)
|
||||
{
|
||||
JSONStreamClosure streamClosure = {stream, false};
|
||||
stream << "{";
|
||||
entry->mProperties.EnumerateRead(HashTableOutput, &streamClosure);
|
||||
stream << "}";
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& stream, JSCustomArray* entry)
|
||||
{
|
||||
bool needsComma = false;
|
||||
stream << "[";
|
||||
for (int i = 0; i < entry->mValues.Length(); i++) {
|
||||
if (needsComma) {
|
||||
stream << ",";
|
||||
}
|
||||
entry->mValues[i]->SendToStream(stream);
|
||||
needsComma = true;
|
||||
}
|
||||
stream << "]";
|
||||
return stream;
|
||||
}
|
||||
|
||||
PLDHashOperator HashTableFree(const nsACString& aKey, PropertyValue* aValue, void* stream)
|
||||
{
|
||||
delete aValue;
|
||||
return PLDHashOperator::PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
JSCustomObject::~JSCustomObject()
|
||||
{
|
||||
mProperties.EnumerateRead(HashTableFree, nullptr);
|
||||
}
|
||||
|
||||
JSAObjectBuilder::~JSAObjectBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
JSCustomObjectBuilder::JSCustomObjectBuilder()
|
||||
{}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::DeleteObject(JSCustomObject* aObject)
|
||||
{
|
||||
delete aObject;
|
||||
}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::Serialize(JSCustomObject* aObject, std::ostream& stream)
|
||||
{
|
||||
stream << aObject;
|
||||
}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue)
|
||||
{
|
||||
aObject->AddProperty(name, aValue);
|
||||
}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue)
|
||||
{
|
||||
aObject->AddProperty(name, aValue);
|
||||
}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, int aValue)
|
||||
{
|
||||
aObject->AddProperty(name, aValue);
|
||||
}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, double aValue)
|
||||
{
|
||||
aObject->AddProperty(name, aValue);
|
||||
}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, const char *aValue)
|
||||
{
|
||||
// aValue copy will be freed by the property desctructor (template specialization)
|
||||
aObject->AddProperty(name, strdup(aValue));
|
||||
}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::ArrayPush(JSCustomArray *aArray, int aValue)
|
||||
{
|
||||
aArray->AppendElement(aValue);
|
||||
}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::ArrayPush(JSCustomArray *aArray, const char *aValue)
|
||||
{
|
||||
// aValue copy will be freed by the property desctructor (template specialization)
|
||||
aArray->AppendElement(strdup(aValue));
|
||||
}
|
||||
|
||||
void
|
||||
JSCustomObjectBuilder::ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject)
|
||||
{
|
||||
aArray->AppendElement(aObject);
|
||||
}
|
||||
|
||||
JSCustomArray*
|
||||
JSCustomObjectBuilder::CreateArray() {
|
||||
return new JSCustomArray();
|
||||
}
|
||||
|
||||
JSCustomObject*
|
||||
JSCustomObjectBuilder::CreateObject() {
|
||||
return new JSCustomObject();
|
||||
}
|
||||
|
57
tools/profiler/JSCustomObjectBuilder.h
Normal file
57
tools/profiler/JSCustomObjectBuilder.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef JSCUSTOMOBJECTBUILDER_H
|
||||
#define JSCUSTOMOBJECTBUILDER_H
|
||||
|
||||
#include <ostream>
|
||||
#include "JSAObjectBuilder.h"
|
||||
|
||||
class JSCustomObject;
|
||||
class JSCustomArray;
|
||||
class JSCustomObjectBuilder;
|
||||
|
||||
class JSCustomObjectBuilder : public JSAObjectBuilder
|
||||
{
|
||||
public:
|
||||
|
||||
// We need to ensure that this object lives on the stack so that GC sees it properly
|
||||
JSCustomObjectBuilder();
|
||||
|
||||
void Serialize(JSCustomObject* aObject, std::ostream& stream);
|
||||
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, int value);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, double value);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value, size_t valueLength);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value);
|
||||
void ArrayPush(JSCustomArray *aArray, int value);
|
||||
void ArrayPush(JSCustomArray *aArray, const char *value);
|
||||
void ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject);
|
||||
JSCustomArray *CreateArray();
|
||||
JSCustomObject *CreateObject();
|
||||
|
||||
// Delete this object and all of its descendant
|
||||
void DeleteObject(JSCustomObject* aObject);
|
||||
|
||||
private:
|
||||
// This class can't be copied
|
||||
JSCustomObjectBuilder(const JSCustomObjectBuilder&);
|
||||
JSCustomObjectBuilder& operator=(const JSCustomObjectBuilder&);
|
||||
|
||||
void* operator new(size_t);
|
||||
void* operator new[](size_t);
|
||||
void operator delete(void*) {
|
||||
// Since JSCustomObjectBuilder has a virtual destructor the compiler
|
||||
// has to provide a destructor in the object file that will call
|
||||
// operate delete in case there is a derived class since its
|
||||
// destructor wont know how to free this instance.
|
||||
abort();
|
||||
}
|
||||
void operator delete[](void*);
|
||||
};
|
||||
|
||||
#endif
|
@ -11,34 +11,40 @@ JSObjectBuilder::JSObjectBuilder(JSContext *aCx) : mCx(aCx), mOk(JS_TRUE)
|
||||
{}
|
||||
|
||||
void
|
||||
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, JSObject *aValue)
|
||||
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue)
|
||||
{
|
||||
DefineProperty(aObject, name, (JSCustomObject*)aValue);
|
||||
}
|
||||
|
||||
void
|
||||
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue)
|
||||
{
|
||||
if (!mOk)
|
||||
return;
|
||||
|
||||
mOk = JS_DefineProperty(mCx, aObject, name, OBJECT_TO_JSVAL(aValue), NULL, NULL, JSPROP_ENUMERATE);
|
||||
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, OBJECT_TO_JSVAL((JSObject*)aValue), nullptr, nullptr, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
void
|
||||
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, int value)
|
||||
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, int value)
|
||||
{
|
||||
if (!mOk)
|
||||
return;
|
||||
|
||||
mOk = JS_DefineProperty(mCx, aObject, name, INT_TO_JSVAL(value), NULL, NULL, JSPROP_ENUMERATE);
|
||||
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, INT_TO_JSVAL(value), nullptr, nullptr, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
void
|
||||
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, double value)
|
||||
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, double value)
|
||||
{
|
||||
if (!mOk)
|
||||
return;
|
||||
|
||||
mOk = JS_DefineProperty(mCx, aObject, name, DOUBLE_TO_JSVAL(value), NULL, NULL, JSPROP_ENUMERATE);
|
||||
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, DOUBLE_TO_JSVAL(value), nullptr, nullptr, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
void
|
||||
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, nsAString &value)
|
||||
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, nsAString &value)
|
||||
{
|
||||
if (!mOk)
|
||||
return;
|
||||
@ -51,11 +57,11 @@ JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, nsAString &
|
||||
if (!mOk)
|
||||
return;
|
||||
|
||||
mOk = JS_DefineProperty(mCx, aObject, name, STRING_TO_JSVAL(string), NULL, NULL, JSPROP_ENUMERATE);
|
||||
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, STRING_TO_JSVAL(string), nullptr, nullptr, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
void
|
||||
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, const char *value, size_t valueLength)
|
||||
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, const char *value, size_t valueLength)
|
||||
{
|
||||
if (!mOk)
|
||||
return;
|
||||
@ -66,33 +72,32 @@ JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, const char
|
||||
return;
|
||||
}
|
||||
|
||||
mOk = JS_DefineProperty(mCx, aObject, name, STRING_TO_JSVAL(string), NULL, NULL, JSPROP_ENUMERATE);
|
||||
}
|
||||
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, STRING_TO_JSVAL(string), nullptr, nullptr, JSPROP_ENUMERATE); }
|
||||
|
||||
void
|
||||
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, const char *value)
|
||||
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, const char *value)
|
||||
{
|
||||
DefineProperty(aObject, name, value, strlen(value));
|
||||
}
|
||||
|
||||
void
|
||||
JSObjectBuilder::ArrayPush(JSObject *aArray, int value)
|
||||
JSObjectBuilder::ArrayPush(JSCustomArray *aArray, int value)
|
||||
{
|
||||
if (!mOk)
|
||||
return;
|
||||
|
||||
jsval objval = INT_TO_JSVAL(value);
|
||||
uint32_t length;
|
||||
mOk = JS_GetArrayLength(mCx, aArray, &length);
|
||||
mOk = JS_GetArrayLength(mCx, (JSObject*)aArray, &length);
|
||||
|
||||
if (!mOk)
|
||||
return;
|
||||
|
||||
mOk = JS_SetElement(mCx, aArray, length, &objval);
|
||||
mOk = JS_SetElement(mCx, (JSObject*)aArray, length, &objval);
|
||||
}
|
||||
|
||||
void
|
||||
JSObjectBuilder::ArrayPush(JSObject *aArray, const char *value)
|
||||
JSObjectBuilder::ArrayPush(JSCustomArray *aArray, const char *value)
|
||||
{
|
||||
if (!mOk)
|
||||
return;
|
||||
@ -105,42 +110,41 @@ JSObjectBuilder::ArrayPush(JSObject *aArray, const char *value)
|
||||
|
||||
jsval objval = STRING_TO_JSVAL(string);
|
||||
uint32_t length;
|
||||
mOk = JS_GetArrayLength(mCx, aArray, &length);
|
||||
mOk = JS_GetArrayLength(mCx, (JSObject*)aArray, &length);
|
||||
|
||||
if (!mOk)
|
||||
return;
|
||||
|
||||
mOk = JS_SetElement(mCx, aArray, length, &objval);
|
||||
mOk = JS_SetElement(mCx, (JSObject*)aArray, length, &objval);
|
||||
}
|
||||
|
||||
void
|
||||
JSObjectBuilder::ArrayPush(JSObject *aArray, JSObject *aObject)
|
||||
JSObjectBuilder::ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject)
|
||||
{
|
||||
if (!mOk)
|
||||
return;
|
||||
|
||||
jsval objval = OBJECT_TO_JSVAL(aObject);
|
||||
uint32_t length;
|
||||
mOk = JS_GetArrayLength(mCx, aArray, &length);
|
||||
jsval objval = OBJECT_TO_JSVAL((JSObject*)aObject); uint32_t length;
|
||||
mOk = JS_GetArrayLength(mCx, (JSObject*)aArray, &length);
|
||||
|
||||
if (!mOk)
|
||||
return;
|
||||
|
||||
mOk = JS_SetElement(mCx, aArray, length, &objval);
|
||||
mOk = JS_SetElement(mCx, (JSObject*)aArray, length, &objval);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
JSCustomArray*
|
||||
JSObjectBuilder::CreateArray() {
|
||||
JSObject *array = JS_NewArrayObject(mCx, 0, NULL);
|
||||
JSCustomArray *array = (JSCustomArray*)JS_NewArrayObject(mCx, 0, nullptr);
|
||||
if (!array)
|
||||
mOk = JS_FALSE;
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
JSCustomObject*
|
||||
JSObjectBuilder::CreateObject() {
|
||||
JSObject *obj = JS_NewObject(mCx, NULL, NULL, NULL);
|
||||
JSCustomObject *obj = (JSCustomObject*)JS_NewObject(mCx, nullptr, nullptr, nullptr);
|
||||
if (!obj)
|
||||
mOk = JS_FALSE;
|
||||
|
||||
|
@ -3,37 +3,60 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
class JSObject;
|
||||
class JSObjectBuilder;
|
||||
#ifndef JSOBJECTBUILDER_H
|
||||
#define JSOBJECTBUILDER_H
|
||||
|
||||
#include "JSAObjectBuilder.h"
|
||||
|
||||
class JSCustomObject;
|
||||
class JSCustomObjectBuilder;
|
||||
class JSContext;
|
||||
class nsAString;
|
||||
|
||||
/* this is handy wrapper around JSAPI to make it more pleasant to use.
|
||||
* We collect the JSAPI errors and so that callers don't need to */
|
||||
class JSObjectBuilder
|
||||
class JSObjectBuilder : public JSAObjectBuilder
|
||||
{
|
||||
public:
|
||||
|
||||
// We need to ensure that this object lives on the stack so that GC sees it properly
|
||||
JSObjectBuilder(JSContext *aCx);
|
||||
explicit JSObjectBuilder(JSContext *aCx);
|
||||
~JSObjectBuilder() {}
|
||||
|
||||
void DefineProperty(JSObject *aObject, const char *name, JSObject *aValue);
|
||||
void DefineProperty(JSObject *aObject, const char *name, int value);
|
||||
void DefineProperty(JSObject *aObject, const char *name, double value);
|
||||
void DefineProperty(JSObject *aObject, const char *name, nsAString &value);
|
||||
void DefineProperty(JSObject *aObject, const char *name, const char *value, size_t valueLength);
|
||||
void DefineProperty(JSObject *aObject, const char *name, const char *value);
|
||||
void ArrayPush(JSObject *aArray, int value);
|
||||
void ArrayPush(JSObject *aArray, const char *value);
|
||||
void ArrayPush(JSObject *aArray, JSObject *aObject);
|
||||
JSObject *CreateArray();
|
||||
JSObject *CreateObject();
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, int value);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, double value);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, nsAString &value);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value, size_t valueLength);
|
||||
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value);
|
||||
void ArrayPush(JSCustomArray *aArray, int value);
|
||||
void ArrayPush(JSCustomArray *aArray, const char *value);
|
||||
void ArrayPush(JSCustomArray *aArray, JSCustomArray *aObject);
|
||||
void ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject);
|
||||
JSCustomArray *CreateArray();
|
||||
JSCustomObject *CreateObject();
|
||||
|
||||
JSObject* GetJSObject(JSCustomObject* aObject) { return (JSObject*)aObject; }
|
||||
|
||||
private:
|
||||
JSObjectBuilder(JSObjectBuilder&);
|
||||
JSObjectBuilder(const JSObjectBuilder&);
|
||||
JSObjectBuilder& operator=(const JSObjectBuilder&);
|
||||
|
||||
void* operator new(size_t);
|
||||
void* operator new[](size_t);
|
||||
void operator delete(void*) {
|
||||
// Since JSObjectBuilder has a virtual destructor the compiler
|
||||
// has to provide a destructor in the object file that will call
|
||||
// operate delete in case there is a derived class since its
|
||||
// destructor wont know how to free this instance.
|
||||
abort();
|
||||
}
|
||||
void operator delete[](void*);
|
||||
|
||||
JSContext *mCx;
|
||||
JSObject *mObj;
|
||||
int mOk;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -64,6 +64,7 @@ CPPSRCS = \
|
||||
nsProfiler.cpp \
|
||||
TableTicker.cpp \
|
||||
JSObjectBuilder.cpp \
|
||||
JSCustomObjectBuilder.cpp \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "sps_sampler.h"
|
||||
@ -18,6 +17,7 @@
|
||||
|
||||
// JSON
|
||||
#include "JSObjectBuilder.h"
|
||||
#include "JSCustomObjectBuilder.h"
|
||||
#include "nsIJSRuntimeService.h"
|
||||
|
||||
// Meta
|
||||
@ -307,17 +307,31 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
JSObject *ToJSObject(JSContext *aCx)
|
||||
void ToStreamAsJSON(std::ostream& stream)
|
||||
{
|
||||
JSCustomObjectBuilder b;
|
||||
JSCustomObject *profile = b.CreateObject();
|
||||
BuildJSObject(b, profile);
|
||||
b.Serialize(profile, stream);
|
||||
b.DeleteObject(profile);
|
||||
}
|
||||
|
||||
JSCustomObject *ToJSObject(JSContext *aCx)
|
||||
{
|
||||
JSObjectBuilder b(aCx);
|
||||
JSCustomObject *profile = b.CreateObject();
|
||||
BuildJSObject(b, profile);
|
||||
|
||||
JSObject *profile = b.CreateObject();
|
||||
JSObject *samples = b.CreateArray();
|
||||
return profile;
|
||||
}
|
||||
|
||||
void BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile) {
|
||||
JSCustomArray *samples = b.CreateArray();
|
||||
b.DefineProperty(profile, "samples", samples);
|
||||
|
||||
JSObject *sample = NULL;
|
||||
JSObject *frames = NULL;
|
||||
JSObject *marker = NULL;
|
||||
JSCustomObject *sample = nullptr;
|
||||
JSCustomArray *frames = nullptr;
|
||||
JSCustomArray *marker = nullptr;
|
||||
|
||||
int readPos = mReadPos;
|
||||
while (readPos != mLastFlushPos) {
|
||||
@ -382,7 +396,7 @@ public:
|
||||
case 'l':
|
||||
{
|
||||
if (sample) {
|
||||
JSObject *frame = b.CreateObject();
|
||||
JSCustomObject *frame = b.CreateObject();
|
||||
if (entry.mTagName == 'l') {
|
||||
// Bug 753041
|
||||
// We need a double cast here to tell GCC that we don't want to sign
|
||||
@ -406,8 +420,6 @@ public:
|
||||
}
|
||||
readPos = (readPos + incBy) % mEntrySize;
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
ProfileStack* GetStack()
|
||||
@ -473,8 +485,9 @@ class TableTicker: public Sampler {
|
||||
return &mPrimaryThreadProfile;
|
||||
}
|
||||
|
||||
void ToStreamAsJSON(std::ostream& stream);
|
||||
JSObject *ToJSObject(JSContext *aCx);
|
||||
JSObject *GetMetaJSObject(JSObjectBuilder& b);
|
||||
JSCustomObject *GetMetaJSCustomObject(JSAObjectBuilder& b);
|
||||
|
||||
const bool ProfileJS() { return mProfileJS; }
|
||||
|
||||
@ -482,6 +495,7 @@ private:
|
||||
// Not implemented on platforms which do not support backtracing
|
||||
void doBacktrace(ThreadProfile &aProfile, TickSample* aSample);
|
||||
|
||||
void BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile);
|
||||
private:
|
||||
// This represent the application's main thread (SAMPLER_INIT)
|
||||
ThreadProfile mPrimaryThreadProfile;
|
||||
@ -513,7 +527,6 @@ public:
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
TableTicker *t = tlsTicker.get();
|
||||
|
||||
// Pause the profiler during saving.
|
||||
// This will prevent us from recording sampling
|
||||
// regarding profile saving. This will also
|
||||
@ -543,7 +556,7 @@ public:
|
||||
return rv;
|
||||
#endif
|
||||
|
||||
// Create a JSContext to run a JSObjectBuilder :(
|
||||
// Create a JSContext to run a JSCustomObjectBuilder :(
|
||||
// Based on XPCShellEnvironment
|
||||
JSRuntime *rt;
|
||||
JSContext *cx;
|
||||
@ -575,7 +588,6 @@ public:
|
||||
// regarding profile saving. This will also
|
||||
// prevent bugs caused by the circular buffer not
|
||||
// being thread safe. Bug 750989.
|
||||
t->SetPaused(true);
|
||||
if (stream.is_open()) {
|
||||
JSAutoCompartment autoComp(cx, obj);
|
||||
JSObject* profileObj = mozilla_sampler_get_profile_data(cx);
|
||||
@ -590,8 +602,6 @@ public:
|
||||
JS_EndRequest(cx);
|
||||
JS_DestroyContext(cx);
|
||||
|
||||
t->SetPaused(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
@ -608,9 +618,9 @@ void TableTicker::HandleSaveRequest()
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
JSObject* TableTicker::GetMetaJSObject(JSObjectBuilder& b)
|
||||
JSCustomObject* TableTicker::GetMetaJSCustomObject(JSAObjectBuilder& b)
|
||||
{
|
||||
JSObject *meta = b.CreateObject();
|
||||
JSCustomObject *meta = b.CreateObject();
|
||||
|
||||
b.DefineProperty(meta, "version", 2);
|
||||
b.DefineProperty(meta, "interval", interval());
|
||||
@ -661,30 +671,44 @@ JSObject* TableTicker::GetMetaJSObject(JSObjectBuilder& b)
|
||||
return meta;
|
||||
}
|
||||
|
||||
void TableTicker::ToStreamAsJSON(std::ostream& stream)
|
||||
{
|
||||
JSCustomObjectBuilder b;
|
||||
JSCustomObject* profile = b.CreateObject();
|
||||
BuildJSObject(b, profile);
|
||||
b.Serialize(profile, stream);
|
||||
b.DeleteObject(profile);
|
||||
}
|
||||
|
||||
JSObject* TableTicker::ToJSObject(JSContext *aCx)
|
||||
{
|
||||
JSObjectBuilder b(aCx);
|
||||
JSCustomObject* profile = b.CreateObject();
|
||||
BuildJSObject(b, profile);
|
||||
JSObject* jsProfile = b.GetJSObject(profile);
|
||||
|
||||
JSObject *profile = b.CreateObject();
|
||||
return jsProfile;
|
||||
}
|
||||
|
||||
void TableTicker::BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile)
|
||||
{
|
||||
// Put shared library info
|
||||
b.DefineProperty(profile, "libs", GetSharedLibraryInfoString().c_str());
|
||||
|
||||
// Put meta data
|
||||
JSObject *meta = GetMetaJSObject(b);
|
||||
JSCustomObject *meta = GetMetaJSCustomObject(b);
|
||||
b.DefineProperty(profile, "meta", meta);
|
||||
|
||||
// Lists the samples for each ThreadProfile
|
||||
JSObject *threads = b.CreateArray();
|
||||
JSCustomArray *threads = b.CreateArray();
|
||||
b.DefineProperty(profile, "threads", threads);
|
||||
|
||||
// For now we only have one thread
|
||||
SetPaused(true);
|
||||
JSObject* threadSamples = GetPrimaryThreadProfile()->ToJSObject(aCx);
|
||||
JSCustomObject* threadSamples = b.CreateObject();
|
||||
GetPrimaryThreadProfile()->BuildJSObject(b, threadSamples);
|
||||
b.ArrayPush(threads, threadSamples);
|
||||
SetPaused(false);
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
static
|
||||
@ -1062,8 +1086,21 @@ void mozilla_sampler_init()
|
||||
features, sizeof(features)/sizeof(const char*));
|
||||
}
|
||||
|
||||
void mozilla_sampler_deinit()
|
||||
void mozilla_sampler_shutdown()
|
||||
{
|
||||
TableTicker *t = tlsTicker.get();
|
||||
if (t) {
|
||||
const char *val = PR_GetEnv("MOZ_PROFILER_SHUTDOWN");
|
||||
if (val) {
|
||||
std::ofstream stream;
|
||||
stream.open(val);
|
||||
if (stream.is_open()) {
|
||||
t->ToStreamAsJSON(stream);
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mozilla_sampler_stop();
|
||||
// We can't delete the Stack because we can be between a
|
||||
// sampler call_enter/call_exit point.
|
||||
|
@ -8,11 +8,11 @@
|
||||
#include <stdarg.h>
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#include "nscore.h"
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "nsAlgorithm.h"
|
||||
|
||||
|
||||
/* QT has a #define for the word "slots" and jsfriendapi.h has a struct with
|
||||
* this variable name, causing compilation problems. Alleviate this for now by
|
||||
* removing this #define */
|
||||
@ -26,6 +26,7 @@ using mozilla::TimeDuration;
|
||||
|
||||
struct ProfileStack;
|
||||
class TableTicker;
|
||||
class JSCustomObject;
|
||||
|
||||
extern mozilla::ThreadLocal<ProfileStack *> tlsStack;
|
||||
extern mozilla::ThreadLocal<TableTicker *> tlsTicker;
|
||||
@ -42,7 +43,7 @@ extern bool stack_key_initialized;
|
||||
#endif
|
||||
|
||||
#define SAMPLER_INIT() mozilla_sampler_init()
|
||||
#define SAMPLER_DEINIT() mozilla_sampler_deinit()
|
||||
#define SAMPLER_SHUTDOWN() mozilla_sampler_shutdown()
|
||||
#define SAMPLER_START(entries, interval, features, featureCount) mozilla_sampler_start(entries, interval, features, featureCount)
|
||||
#define SAMPLER_STOP() mozilla_sampler_stop()
|
||||
#define SAMPLER_IS_ACTIVE() mozilla_sampler_is_active()
|
||||
@ -172,6 +173,7 @@ char* mozilla_sampler_get_profile();
|
||||
JSObject *mozilla_sampler_get_profile_data(JSContext *aCx);
|
||||
const char** mozilla_sampler_get_features();
|
||||
void mozilla_sampler_init();
|
||||
void mozilla_sampler_shutdown();
|
||||
|
||||
void mozilla_sampler_print_location();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user