Bug 905017 (part 3) - Move profiling stack stuff from jsapi.h to js/ProfilingStack.h. r=billm.

--HG--
extra : rebase_source : 8322f1c96b95685912375484172d47f53107947f
This commit is contained in:
Nicholas Nethercote 2013-08-19 23:45:26 -07:00
parent 4caa0f8ea2
commit c8e2369441
17 changed files with 221 additions and 147 deletions

View File

@ -302,6 +302,28 @@ def module_name(name):
return name.replace('inlines.h', '').replace('-inl.h', '').replace('.h', '').replace('.cpp', '')
def is_module_header(enclosing_inclname, header_inclname):
'''Determine if an included name is the "module header", i.e. should be
first in the file.'''
module = module_name(enclosing_inclname)
# Normal case, e.g. module == "foo/Bar", header_inclname == "foo/Bar.h".
if module == module_name(header_inclname):
return True
# A public header, e.g. module == "foo/Bar", header_inclname == "js/Bar.h".
m = re.match(r'js\/(.*)\.h', header_inclname)
if m is not None and module.endswith('/' + m.group(1)):
return True
# A weird public header case.
if module == 'jsmemorymetrics' and header_inclname == 'js/MemoryMetrics.h':
return True
return False
class Include(object):
'''Important information for a single #include statement.'''
@ -313,7 +335,7 @@ class Include(object):
def isLeaf(self):
return True
def section(self, module):
def section(self, enclosing_inclname):
'''Identify which section inclname belongs to.
The section numbers are as follows.
@ -333,12 +355,9 @@ class Include(object):
if not self.inclname.endswith('.h'):
return 7
# A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need special
# handling.
if module == module_name(self.inclname) or \
module == 'jsmemorymetrics' and self.inclname == 'js/MemoryMetrics.h' or \
module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h' or \
module == 'vm/StructuredClone' and self.inclname == 'js/StructuredClone.h':
# A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need
# special handling.
if is_module_header(enclosing_inclname, self.inclname):
return 0
if '/' in self.inclname:
@ -452,8 +471,6 @@ def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclname
if inclname == include.inclname:
error(filename, include.linenum, 'the file includes itself')
module = module_name(inclname)
def check_includes_order(include1, include2):
'''Check the ordering of two #include statements.'''
@ -461,8 +478,8 @@ def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclname
include2.inclname in oddly_ordered_inclnames:
return
section1 = include1.section(module)
section2 = include2.section(module)
section1 = include1.section(inclname)
section2 = include2.section(inclname)
if (section1 > section2) or \
((section1 == section2) and (include1.inclname.lower() > include2.inclname.lower())):
error(filename, str(include1.linenum) + ':' + str(include2.linenum),

View File

@ -10,6 +10,7 @@
#include "JavaScriptShared.h"
#include "mozilla/jsipc/PJavaScriptParent.h"
#include "jsclass.h"
#ifdef XP_WIN
#undef GetClassName

View File

@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 js_ProfilingStack_h
#define js_ProfilingStack_h
#include "jsbytecode.h"
#include "jstypes.h"
#include "js/Utility.h"
struct JSRuntime;
class JSScript;
namespace js {
// A call stack can be specified to the JS engine such that all JS entry/exits
// to functions push/pop an entry to/from the specified stack.
//
// For more detailed information, see vm/SPSProfiler.h.
//
class ProfileEntry
{
// All fields are marked volatile to prevent the compiler from re-ordering
// instructions. Namely this sequence:
//
// entry[size] = ...;
// size++;
//
// If the size modification were somehow reordered before the stores, then
// if a sample were taken it would be examining bogus information.
//
// A ProfileEntry represents both a C++ profile entry and a JS one. Both use
// the string as a description, but JS uses the sp as NULL to indicate that
// it is a JS entry. The script_ is then only ever examined for a JS entry,
// and the idx is used by both, but with different meanings.
//
const char * volatile string; // Descriptive string of this entry
void * volatile sp; // Relevant stack pointer for the entry
JSScript * volatile script_; // if js(), non-null script which is running
int32_t volatile idx; // if js(), idx of pc, otherwise line number
public:
// All of these methods are marked with the 'volatile' keyword because SPS's
// representation of the stack is stored such that all ProfileEntry
// instances are volatile. These methods would not be available unless they
// were marked as volatile as well.
bool js() volatile {
JS_ASSERT_IF(sp == NULL, script_ != NULL);
return sp == NULL;
}
uint32_t line() volatile { JS_ASSERT(!js()); return idx; }
JSScript *script() volatile { JS_ASSERT(js()); return script_; }
void *stackAddress() volatile { return sp; }
const char *label() volatile { return string; }
void setLine(uint32_t aLine) volatile { JS_ASSERT(!js()); idx = aLine; }
void setLabel(const char *aString) volatile { string = aString; }
void setStackAddress(void *aSp) volatile { sp = aSp; }
void setScript(JSScript *aScript) volatile { script_ = aScript; }
// We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp.
JS_FRIEND_API(jsbytecode *) pc() volatile;
JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile;
static size_t offsetOfString() { return offsetof(ProfileEntry, string); }
static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); }
static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); }
static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); }
// The index used in the entry can either be a line number or the offset of
// a pc into a script's code. To signify a NULL pc, use a -1 index. This is
// checked against in pc() and setPC() to set/get the right pc.
static const int32_t NullPCIndex = -1;
};
JS_FRIEND_API(void)
SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
uint32_t max);
JS_FRIEND_API(void)
EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
JS_FRIEND_API(jsbytecode*)
ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip);
} // namespace js
#endif /* js_ProfilingStack_h */

View File

@ -1907,6 +1907,13 @@ extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
namespace JS {
extern JS_PUBLIC_DATA(const Handle<Value>) NullHandleValue;
extern JS_PUBLIC_DATA(const Handle<Value>) UndefinedHandleValue;
}
#undef JS_VALUE_IS_CONSTEXPR
#undef JS_RETURN_LAYOUT_FROM_BITS

View File

@ -302,6 +302,28 @@ def module_name(name):
return name.replace('inlines.h', '').replace('-inl.h', '').replace('.h', '').replace('.cpp', '')
def is_module_header(enclosing_inclname, header_inclname):
'''Determine if an included name is the "module header", i.e. should be
first in the file.'''
module = module_name(enclosing_inclname)
# Normal case, e.g. module == "foo/Bar", header_inclname == "foo/Bar.h".
if module == module_name(header_inclname):
return True
# A public header, e.g. module == "foo/Bar", header_inclname == "js/Bar.h".
m = re.match(r'js\/(.*)\.h', header_inclname)
if m is not None and module.endswith('/' + m.group(1)):
return True
# A weird public header case.
if module == 'jsmemorymetrics' and header_inclname == 'js/MemoryMetrics.h':
return True
return False
class Include(object):
'''Important information for a single #include statement.'''
@ -313,7 +335,7 @@ class Include(object):
def isLeaf(self):
return True
def section(self, module):
def section(self, enclosing_inclname):
'''Identify which section inclname belongs to.
The section numbers are as follows.
@ -333,12 +355,9 @@ class Include(object):
if not self.inclname.endswith('.h'):
return 7
# A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need special
# handling.
if module == module_name(self.inclname) or \
module == 'jsmemorymetrics' and self.inclname == 'js/MemoryMetrics.h' or \
module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h' or \
module == 'vm/StructuredClone' and self.inclname == 'js/StructuredClone.h':
# A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need
# special handling.
if is_module_header(enclosing_inclname, self.inclname):
return 0
if '/' in self.inclname:
@ -452,8 +471,6 @@ def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclname
if inclname == include.inclname:
error(filename, include.linenum, 'the file includes itself')
module = module_name(inclname)
def check_includes_order(include1, include2):
'''Check the ordering of two #include statements.'''
@ -461,8 +478,8 @@ def do_file(filename, inclname, file_kind, f, all_inclnames, included_h_inclname
include2.inclname in oddly_ordered_inclnames:
return
section1 = include1.section(module)
section2 = include2.section(module)
section1 = include1.section(inclname)
section2 = include2.section(inclname)
if (section1 > section2) or \
((section1 == section2) and (include1.inclname.lower() > include2.inclname.lower())):
error(filename, str(include1.linenum) + ':' + str(include2.linenum),

View File

@ -128,15 +128,6 @@ const jsid JSID_VOID = { size_t(JSID_TYPE_VOID) };
const jsid JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
#endif
const jsval JSVAL_NULL = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
const jsval JSVAL_ZERO = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32, 0));
const jsval JSVAL_ONE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32, 1));
const jsval JSVAL_FALSE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN, false));
const jsval JSVAL_TRUE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN, true));
const jsval JSVAL_VOID = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0));
const HandleValue JS::NullHandleValue = HandleValue::fromMarkedLocation(&JSVAL_NULL);
const HandleValue JS::UndefinedHandleValue = HandleValue::fromMarkedLocation(&JSVAL_VOID);
const jsid voidIdValue = JSID_VOID;
const jsid emptyIdValue = JSID_EMPTY;
const HandleId JS::JSID_VOIDHANDLE = HandleId::fromMarkedLocation(&voidIdValue);

View File

@ -5087,9 +5087,6 @@ JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
namespace JS {
extern JS_PUBLIC_DATA(const Handle<Value>) NullHandleValue;
extern JS_PUBLIC_DATA(const Handle<Value>) UndefinedHandleValue;
extern JS_PUBLIC_DATA(const Handle<jsid>) JSID_VOIDHANDLE;
extern JS_PUBLIC_DATA(const Handle<jsid>) JSID_EMPTYHANDLE;

View File

@ -991,24 +991,6 @@ js::GetEnterCompartmentDepth(JSContext *cx)
}
#endif
JS_FRIEND_API(void)
js::SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, uint32_t max)
{
rt->spsProfiler.setProfilingStack(stack, size, max);
}
JS_FRIEND_API(void)
js::EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled)
{
rt->spsProfiler.enable(enabled);
}
JS_FRIEND_API(jsbytecode*)
js::ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip)
{
return rt->spsProfiler.ipToPC(script, size_t(ip));
}
JS_FRIEND_API(void)
js::SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks)
{

View File

@ -669,84 +669,6 @@ GetPCCountScriptSummary(JSContext *cx, size_t script);
JS_FRIEND_API(JSString *)
GetPCCountScriptContents(JSContext *cx, size_t script);
/*
* A call stack can be specified to the JS engine such that all JS entry/exits
* to functions push/pop an entry to/from the specified stack.
*
* For more detailed information, see vm/SPSProfiler.h
*/
class ProfileEntry
{
/*
* All fields are marked volatile to prevent the compiler from re-ordering
* instructions. Namely this sequence:
*
* entry[size] = ...;
* size++;
*
* If the size modification were somehow reordered before the stores, then
* if a sample were taken it would be examining bogus information.
*
* A ProfileEntry represents both a C++ profile entry and a JS one. Both use
* the string as a description, but JS uses the sp as NULL to indicate that
* it is a JS entry. The script_ is then only ever examined for a JS entry,
* and the idx is used by both, but with different meanings.
*/
const char * volatile string; // Descriptive string of this entry
void * volatile sp; // Relevant stack pointer for the entry
JSScript * volatile script_; // if js(), non-null script which is running
int32_t volatile idx; // if js(), idx of pc, otherwise line number
public:
/*
* All of these methods are marked with the 'volatile' keyword because SPS's
* representation of the stack is stored such that all ProfileEntry
* instances are volatile. These methods would not be available unless they
* were marked as volatile as well
*/
bool js() volatile {
JS_ASSERT_IF(sp == NULL, script_ != NULL);
return sp == NULL;
}
uint32_t line() volatile { JS_ASSERT(!js()); return idx; }
JSScript *script() volatile { JS_ASSERT(js()); return script_; }
void *stackAddress() volatile { return sp; }
const char *label() volatile { return string; }
void setLine(uint32_t aLine) volatile { JS_ASSERT(!js()); idx = aLine; }
void setLabel(const char *aString) volatile { string = aString; }
void setStackAddress(void *aSp) volatile { sp = aSp; }
void setScript(JSScript *aScript) volatile { script_ = aScript; }
/* we can't know the layout of JSScript, so look in vm/SPSProfiler.cpp */
JS_FRIEND_API(jsbytecode *) pc() volatile;
JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile;
static size_t offsetOfString() { return offsetof(ProfileEntry, string); }
static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); }
static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); }
static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); }
/*
* The index used in the entry can either be a line number or the offset of
* a pc into a script's code. To signify a NULL pc, use a -1 index. This is
* checked against in pc() and setPC() to set/get the right pc.
*/
static const int32_t NullPCIndex = -1;
};
JS_FRIEND_API(void)
SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
uint32_t max);
JS_FRIEND_API(void)
EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
JS_FRIEND_API(jsbytecode*)
ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip);
#ifdef JS_THREADSAFE
JS_FRIEND_API(bool)
ContextHasOutstandingRequests(const JSContext *cx);

View File

@ -68,6 +68,7 @@ EXPORTS.js += [
'../public/HeapAPI.h',
'../public/LegacyIntTypes.h',
'../public/MemoryMetrics.h',
'../public/ProfilingStack.h',
'../public/PropertyKey.h',
'../public/RequiredDefines.h',
'../public/RootingAPI.h',
@ -132,6 +133,7 @@ CPP_SOURCES += [
'TokenStream.cpp',
'TypedArrayObject.cpp',
'Unicode.cpp',
'Value.cpp',
'Verifier.cpp',
'Xdr.cpp',
'YarrCanonicalizeUCS2.cpp',

View File

@ -4,11 +4,11 @@
* 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 "js/CharacterEncoding.h"
#include "jscntxt.h"
#include "jsprf.h"
#include "js/CharacterEncoding.h"
using namespace JS;
Latin1CharsZ

View File

@ -265,14 +265,33 @@ SPSEntryMarker::~SPSEntryMarker()
}
JS_FRIEND_API(jsbytecode*)
ProfileEntry::pc() volatile {
ProfileEntry::pc() volatile
{
JS_ASSERT_IF(idx != NullPCIndex, idx >= 0 && uint32_t(idx) < script()->length);
return idx == NullPCIndex ? NULL : script()->code + idx;
}
JS_FRIEND_API(void)
ProfileEntry::setPC(jsbytecode *pc) volatile {
JS_ASSERT_IF(pc != NULL, script()->code <= pc &&
pc < script()->code + script()->length);
ProfileEntry::setPC(jsbytecode *pc) volatile
{
JS_ASSERT_IF(pc != NULL, script()->code <= pc && pc < script()->code + script()->length);
idx = pc == NULL ? NullPCIndex : pc - script()->code;
}
JS_FRIEND_API(void)
js::SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, uint32_t max)
{
rt->spsProfiler.setProfilingStack(stack, size, max);
}
JS_FRIEND_API(void)
js::EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled)
{
rt->spsProfiler.enable(enabled);
}
JS_FRIEND_API(jsbytecode*)
js::ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip)
{
return rt->spsProfiler.ipToPC(script, size_t(ip));
}

View File

@ -14,6 +14,8 @@
#include "jsscript.h"
#include "js/ProfilingStack.h"
/*
* SPS Profiler integration with the JS Engine
* https://developer.mozilla.org/en/Performance/Profiling_with_the_Built-in_Profiler

21
js/src/vm/Value.cpp Normal file
View File

@ -0,0 +1,21 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 "js/Value.h"
const jsval JSVAL_NULL = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
const jsval JSVAL_ZERO = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32, 0));
const jsval JSVAL_ONE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32, 1));
const jsval JSVAL_FALSE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN, false));
const jsval JSVAL_TRUE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN, true));
const jsval JSVAL_VOID = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0));
namespace JS {
const HandleValue NullHandleValue = HandleValue::fromMarkedLocation(&JSVAL_NULL);
const HandleValue UndefinedHandleValue = HandleValue::fromMarkedLocation(&JSVAL_VOID);
} // namespace JS

View File

@ -7,9 +7,10 @@
#define __NSAUTOJSVALHOLDER_H__
#include "nsDebug.h"
#include "jsapi.h"
/**
* Simple class that looks and acts like a jsval except that it unroots
* Simple class that looks and acts like a JS::Value except that it unroots
* itself automatically if Root() is ever called. Designed to be rooted on the
* context or runtime (but not both!).
*/
@ -44,7 +45,7 @@ public:
else {
this->Release();
}
*this = static_cast<jsval>(aOther);
*this = static_cast<JS::Value>(aOther);
}
return *this;
}
@ -76,10 +77,10 @@ public:
/**
* Manually release, nullifying mVal, and mRt, but returning
* the original jsval.
* the original JS::Value.
*/
jsval Release() {
jsval oldval = mVal;
JS::Value Release() {
JS::Value oldval = mVal;
if (mRt) {
JS_RemoveValueRootRT(mRt, &mVal); // infallible
@ -107,20 +108,20 @@ public:
: nullptr;
}
jsval* ToJSValPtr() {
JS::Value* ToJSValPtr() {
return &mVal;
}
/**
* Pretend to be a jsval.
* Pretend to be a JS::Value.
*/
operator jsval() const { return mVal; }
operator JS::Value() const { return mVal; }
nsAutoJSValHolder &operator=(JSObject* aOther) {
return *this = OBJECT_TO_JSVAL(aOther);
}
nsAutoJSValHolder &operator=(jsval aOther) {
nsAutoJSValHolder &operator=(JS::Value aOther) {
#ifdef DEBUG
if (JSVAL_IS_GCTHING(aOther) && !JSVAL_IS_NULL(aOther)) {
MOZ_ASSERT(IsHeld(), "Not rooted!");
@ -131,7 +132,7 @@ public:
}
private:
jsval mVal;
JS::Value mVal;
JSRuntime* mRt;
};

View File

@ -7,6 +7,7 @@
#include "nsNSSComponent.h"
#include "nsNSSIOLayer.h"
#include "mozilla/Casting.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Telemetry.h"

View File

@ -8,7 +8,7 @@
#include "mozilla/NullPtr.h"
#include <stdint.h>
#include "jsfriendapi.h"
#include "js/ProfilingStack.h"
#include <stdlib.h>
#include <algorithm>