--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -3932,16 +3932,17 @@ XREMain::XRE_main(int argc, char* argv[]
SaveFileToEnvIfUnset("XRE_PROFILE_PATH", mProfD);
SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", mProfLD);
SaveWordToEnvIfUnset("XRE_PROFILE_NAME", mProfileName);
#ifdef MOZ_WIDGET_GTK
MOZ_gdk_display_close(mGdkDisplay);
#endif
+ SAMPLER_SHUTDOWN();
rv = LaunchChild(mNativeApp, true);
#ifdef MOZ_CRASHREPORTER
if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
CrashReporter::UnsetExceptionHandler();
#endif
return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
}
@@ -3954,16 +3955,18 @@ XREMain::XRE_main(int argc, char* argv[]
#ifdef MOZ_CRASHREPORTER
if (mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
CrashReporter::UnsetExceptionHandler();
#endif
XRE_DeinitCommandLine();
+ SAMPLER_SHUTDOWN();
+
return NS_FAILED(rv) ? 1 : 0;
}
#if defined(MOZ_METRO) && defined(XP_WIN)
extern bool XRE_MetroCoreApplicationRun();
static XREMain* xreMainPtr;
// must be called by the thread we want as the main thread
@@ -4065,16 +4068,17 @@ XRE_mainMetro(int argc, char* argv[], co
if (!XRE_MetroCoreApplicationRun()) {
return 1;
}
// XRE_metroShutdown should have already been called on the worker
// thread that called XRE_metroStartup.
NS_ASSERTION(!xreMainPtr->mScopedXPCom,
"XPCOM Shutdown hasn't occured, and we are exiting.");
+ SAMPLER_SHUTDOWN();
return 0;
}
void SetWindowsEnvironment(WindowsEnvironmentType aEnvID);
#endif // MOZ_METRO || !defined(XP_WIN)
int
XRE_main(int argc, char* argv[], const nsXREAppData* aAppData, uint32_t aFlags)
new file mode 100644
--- /dev/null
+++ b/tools/profiler/JSAObjectBuilder.h
@@ -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
new file mode 100644
--- /dev/null
+++ b/tools/profiler/JSCustomObjectBuilder.cpp
@@ -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();
+}
+
new file mode 100644
--- /dev/null
+++ b/tools/profiler/JSCustomObjectBuilder.h
@@ -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
--- a/tools/profiler/JSObjectBuilder.cpp
+++ b/tools/profiler/JSObjectBuilder.cpp
@@ -6,144 +6,148 @@
#include "jsapi.h"
#include "nsStringGlue.h"
#include "JSObjectBuilder.h"
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)
{
- if (!mOk)
- return;
-
- mOk = JS_DefineProperty(mCx, aObject, name, OBJECT_TO_JSVAL(aValue), NULL, NULL, JSPROP_ENUMERATE);
+ DefineProperty(aObject, name, (JSCustomObject*)aValue);
}
void
-JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, int value)
+JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue)
{
if (!mOk)
return;
- mOk = JS_DefineProperty(mCx, aObject, name, INT_TO_JSVAL(value), 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, double value)
+JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, int 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, INT_TO_JSVAL(value), nullptr, nullptr, JSPROP_ENUMERATE);
}
void
-JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, nsAString &value)
+JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, double value)
+{
+ if (!mOk)
+ return;
+
+ mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, DOUBLE_TO_JSVAL(value), nullptr, nullptr, JSPROP_ENUMERATE);
+}
+
+void
+JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, nsAString &value)
{
if (!mOk)
return;
const nsString &flat = PromiseFlatString(value);
JSString *string = JS_NewUCStringCopyN(mCx, static_cast<const jschar*>(flat.get()), flat.Length());
if (!string)
mOk = JS_FALSE;
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;
JSString *string = JS_InternStringN(mCx, value, valueLength);
if (!string) {
mOk = JS_FALSE;
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;
JSString *string = JS_NewStringCopyN(mCx, value, strlen(value));
if (!string) {
mOk = JS_FALSE;
return;
}
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;
return obj;
}
--- a/tools/profiler/JSObjectBuilder.h
+++ b/tools/profiler/JSObjectBuilder.h
@@ -1,39 +1,62 @@
/* -*- 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/. */
-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
--- a/tools/profiler/Makefile.in
+++ b/tools/profiler/Makefile.in
@@ -59,16 +59,17 @@ EXPORT_LIBRARY = 1
LIBXUL_LIBRARY = 1
IS_COMPONENT = 1
CPPSRCS = \
nsProfilerFactory.cpp \
nsProfiler.cpp \
TableTicker.cpp \
JSObjectBuilder.cpp \
+ JSCustomObjectBuilder.cpp \
$(NULL)
XPIDLSRCS = \
nsIProfiler.idl \
$(NULL)
EXTRA_JS_MODULES = \
Profiler.jsm \
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -1,28 +1,28 @@
/* -*- 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 <string>
#include <stdio.h>
-#include <iostream>
#include <fstream>
#include <sstream>
#include "sps_sampler.h"
#include "platform.h"
#include "nsXULAppAPI.h"
#include "nsThreadUtils.h"
#include "prenv.h"
#include "shared-libraries.h"
#include "mozilla/StackWalk.h"
// JSON
#include "JSObjectBuilder.h"
+#include "JSCustomObjectBuilder.h"
#include "nsIJSRuntimeService.h"
// Meta
#include "nsXPCOM.h"
#include "nsXPCOMCID.h"
#include "nsIHttpProtocolHandler.h"
#include "nsServiceManagerUtils.h"
#include "nsIXULRuntime.h"
@@ -302,27 +302,41 @@ public:
}
aCallback(entry, tagStringData);
readPos = (readPos + incBy) % mEntrySize;
}
}
- 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) {
// Number of tag consumed
int incBy = 1;
ProfileEntry entry = mEntries[readPos];
// Read ahead to the next tag, if it's a 'd' tag process it now
@@ -377,17 +391,17 @@ public:
b.DefineProperty(sample, "time", entry.mTagFloat);
}
}
break;
case 'c':
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
// extend 32-bit addresses starting with 0xFXXXXXX.
unsigned long long pc = (unsigned long long)(uintptr_t)entry.mTagPtr;
snprintf(tagBuff, DYNAMIC_MAX_STRING, "%#llx", pc);
b.DefineProperty(frame, "location", tagBuff);
} else {
@@ -401,18 +415,16 @@ public:
}
}
b.ArrayPush(frames, frame);
}
}
}
readPos = (readPos + incBy) % mEntrySize;
}
-
- return profile;
}
ProfileStack* GetStack()
{
return mStack;
}
private:
// Circular buffer 'Keep One Slot Open' implementation
@@ -468,25 +480,27 @@ class TableTicker: public Sampler {
virtual void HandleSaveRequest();
ThreadProfile* GetPrimaryThreadProfile()
{
return &mPrimaryThreadProfile;
}
+ void ToStreamAsJSON(std::ostream& stream);
JSObject *ToJSObject(JSContext *aCx);
- JSObject *GetMetaJSObject(JSObjectBuilder& b);
+ JSCustomObject *GetMetaJSCustomObject(JSAObjectBuilder& b);
const bool ProfileJS() { return mProfileJS; }
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;
TimeStamp mStartTime;
bool mSaveRequested;
bool mUseStackWalk;
bool mJankOnly;
bool mProfileJS;
@@ -508,17 +522,16 @@ WriteCallback(const jschar *buf, uint32_
* to be sure that it is not being modified while saving.
*/
class SaveProfileTask : public nsRunnable {
public:
SaveProfileTask() {}
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
// prevent bugs caused by the circular buffer not
// being thread safe. Bug 750989.
t->SetPaused(true);
// Get file path
@@ -538,17 +551,17 @@ public:
if (NS_FAILED(rv))
return rv;
rv = tmpFile->GetNativePath(tmpPath);
if (NS_FAILED(rv))
return rv;
#endif
- // Create a JSContext to run a JSObjectBuilder :(
+ // Create a JSContext to run a JSCustomObjectBuilder :(
// Based on XPCShellEnvironment
JSRuntime *rt;
JSContext *cx;
nsCOMPtr<nsIJSRuntimeService> rtsvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
if (!rtsvc || NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
LOG("failed to get RuntimeService");
return NS_ERROR_FAILURE;;
}
@@ -570,52 +583,49 @@ public:
std::ofstream stream;
stream.open(tmpPath.get());
// Pause the profiler during saving.
// This will prevent us from recording sampling
// 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);
jsval val = OBJECT_TO_JSVAL(profileObj);
JS_Stringify(cx, &val, nullptr, JSVAL_NULL, WriteCallback, &stream);
stream.close();
LOGF("Saved to %s", tmpPath.get());
} else {
LOG("Fail to open profile log file.");
}
}
JS_EndRequest(cx);
JS_DestroyContext(cx);
- t->SetPaused(false);
-
return NS_OK;
}
};
void TableTicker::HandleSaveRequest()
{
if (!mSaveRequested)
return;
mSaveRequested = false;
// TODO: Use use the ipc/chromium Tasks here to support processes
// without XPCOM.
nsCOMPtr<nsIRunnable> runnable = new SaveProfileTask();
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());
b.DefineProperty(meta, "stackwalk", mUseStackWalk);
b.DefineProperty(meta, "jank", mJankOnly);
b.DefineProperty(meta, "processType", XRE_GetProcessType());
nsresult res;
@@ -656,40 +666,54 @@ JSObject* TableTicker::GetMetaJSObject(J
res = appInfo->GetName(string);
if (!NS_FAILED(res))
b.DefineProperty(meta, "product", string.Data());
}
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
void addProfileEntry(volatile StackEntry &entry, ThreadProfile &aProfile,
ProfileStack *stack, void *lastpc)
{
int lineno = -1;
@@ -1057,18 +1081,31 @@ void mozilla_sampler_init()
#if defined(XP_WIN) || defined(XP_MACOSX)
, "stackwalk"
#endif
};
mozilla_sampler_start(PROFILE_DEFAULT_ENTRY, PROFILE_DEFAULT_INTERVAL,
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.
// TODO Need to find a safe time to delete Stack
}
void mozilla_sampler_save()
{
--- a/tools/profiler/sps_sampler.h
+++ b/tools/profiler/sps_sampler.h
@@ -3,51 +3,52 @@
* 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 <stdlib.h>
#include <signal.h>
#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 */
#ifdef MOZ_WIDGET_QT
#undef slots
#endif
#include "jsfriendapi.h"
using mozilla::TimeStamp;
using mozilla::TimeDuration;
struct ProfileStack;
class TableTicker;
+class JSCustomObject;
extern mozilla::ThreadLocal<ProfileStack *> tlsStack;
extern mozilla::ThreadLocal<TableTicker *> tlsTicker;
extern bool stack_key_initialized;
#ifndef SAMPLE_FUNCTION_NAME
# ifdef __GNUC__
# define SAMPLE_FUNCTION_NAME __FUNCTION__
# elif defined(_MSC_VER)
# define SAMPLE_FUNCTION_NAME __FUNCTION__
# else
# define SAMPLE_FUNCTION_NAME __func__ // defined in C99, supported in various C++ compilers. Just raw function name.
# endif
#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()
#define SAMPLER_RESPONSIVENESS(time) mozilla_sampler_responsiveness(time)
#define SAMPLER_GET_RESPONSIVENESS() mozilla_sampler_get_responsiveness()
#define SAMPLER_FRAME_NUMBER(frameNumber) mozilla_sampler_frame_number(frameNumber)
#define SAMPLER_SAVE() mozilla_sampler_save()
#define SAMPLER_GET_PROFILE() mozilla_sampler_get_profile()
@@ -167,16 +168,17 @@ bool mozilla_sampler_is_active();
void mozilla_sampler_responsiveness(TimeStamp time);
void mozilla_sampler_frame_number(int frameNumber);
const double* mozilla_sampler_get_responsiveness();
void mozilla_sampler_save();
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();
namespace mozilla {
class NS_STACK_CLASS SamplerStackFrameRAII {
public:
// we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.