Bug 905017 (part 3, attempt 2) - Move profiling stack stuff from jsapi.h to js/ProfilingStack.h. r=billm.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 19 Aug 2013 23:45:26 -0700
changeset 143992 051e287b802fb1beba2b75fe877fdb29c741da87
parent 143991 781c291ec961689df23010bfd1d290cb7fb7c91f
child 143993 ca9792cc99ab2e7988c474030bc03903e7a67389
push id32837
push usernnethercote@mozilla.com
push dateFri, 23 Aug 2013 02:42:38 +0000
treeherdermozilla-inbound@051e287b802f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs905017
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 905017 (part 3, attempt 2) - Move profiling stack stuff from jsapi.h to js/ProfilingStack.h. r=billm.
config/check_spidermonkey_style.py
js/ipc/JavaScriptParent.h
js/public/ProfilingStack.h
js/public/Value.h
js/src/config/check_spidermonkey_style.py
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/moz.build
js/src/vm/CharacterEncoding.cpp
js/src/vm/SPSProfiler.cpp
js/src/vm/SPSProfiler.h
js/src/vm/StructuredClone.cpp
js/src/vm/Value.cpp
js/xpconnect/public/nsAutoJSValHolder.h
security/manager/ssl/src/nsNSSIOLayer.cpp
tools/profiler/PseudoStack.h
--- a/config/check_spidermonkey_style.py
+++ b/config/check_spidermonkey_style.py
@@ -297,28 +297,50 @@ def check_style():
 
 
 def module_name(name):
     '''Strip the trailing .cpp, .h, inlines.h or -inl.h from a filename.'''
 
     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.'''
 
     def __init__(self, inclname, linenum, is_system):
         self.inclname = inclname
         self.linenum = linenum
         self.is_system = is_system
 
     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.
           0. Module header (e.g. jsfoo.h or jsfooinlines.h within jsfoo.cpp)
           1. mozilla/Foo.h
           2. <foo.h> or <foo>
           3. jsfoo.h, prmjtime.h, etc
           4. foo/Bar.h
@@ -328,22 +350,19 @@ class Include(object):
         '''
 
         if self.is_system:
             return 2
 
         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:
             if self.inclname.startswith('mozilla/'):
                 return 1
 
             if self.inclname.endswith('-inl.h'):
                 return 6
@@ -447,27 +466,25 @@ def do_file(filename, inclname, file_kin
                     error(filename, include.linenum,
                           'vanilla header includes an inline-header file ' + include.quote())
 
                 # Check a file doesn't #include itself.  (We do this here because the cycle
                 # detection below doesn't detect this case.)
                 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.'''
 
         if include1.inclname in oddly_ordered_inclnames or \
            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),
                   include1.quote() + ' should be included after ' + include2.quote())
 
     # The #include statements in the files in assembler/ and yarr/ have all manner of implicit
     # ordering requirements.  Boo.  Ignore them.
     skip_order_checking = inclname.startswith(('assembler/', 'yarr/'))
--- a/js/ipc/JavaScriptParent.h
+++ b/js/ipc/JavaScriptParent.h
@@ -5,16 +5,17 @@
  * 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 mozilla_jsipc_JavaScriptParent__
 #define mozilla_jsipc_JavaScriptParent__
 
 #include "JavaScriptShared.h"
 #include "mozilla/jsipc/PJavaScriptParent.h"
+#include "jsclass.h"
 
 #ifdef XP_WIN
 #undef GetClassName
 #undef GetClassInfo
 #endif
 
 namespace mozilla {
 namespace jsipc {
new file mode 100644
--- /dev/null
+++ b/js/public/ProfilingStack.h
@@ -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 */
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1902,12 +1902,19 @@ JSVAL_TO_PRIVATE(jsval v)
 // using them requires memory loads and will be correspondingly slow.
 extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
 extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
 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
 
 #endif /* js_Value_h */
--- a/js/src/config/check_spidermonkey_style.py
+++ b/js/src/config/check_spidermonkey_style.py
@@ -297,28 +297,50 @@ def check_style():
 
 
 def module_name(name):
     '''Strip the trailing .cpp, .h, inlines.h or -inl.h from a filename.'''
 
     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.'''
 
     def __init__(self, inclname, linenum, is_system):
         self.inclname = inclname
         self.linenum = linenum
         self.is_system = is_system
 
     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.
           0. Module header (e.g. jsfoo.h or jsfooinlines.h within jsfoo.cpp)
           1. mozilla/Foo.h
           2. <foo.h> or <foo>
           3. jsfoo.h, prmjtime.h, etc
           4. foo/Bar.h
@@ -328,22 +350,19 @@ class Include(object):
         '''
 
         if self.is_system:
             return 2
 
         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:
             if self.inclname.startswith('mozilla/'):
                 return 1
 
             if self.inclname.endswith('-inl.h'):
                 return 6
@@ -447,27 +466,25 @@ def do_file(filename, inclname, file_kin
                     error(filename, include.linenum,
                           'vanilla header includes an inline-header file ' + include.quote())
 
                 # Check a file doesn't #include itself.  (We do this here because the cycle
                 # detection below doesn't detect this case.)
                 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.'''
 
         if include1.inclname in oddly_ordered_inclnames or \
            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),
                   include1.quote() + ' should be included after ' + include2.quote())
 
     # The #include statements in the files in assembler/ and yarr/ have all manner of implicit
     # ordering requirements.  Boo.  Ignore them.
     skip_order_checking = inclname.startswith(('assembler/', 'yarr/'))
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -123,25 +123,16 @@ JS::detail::CallMethodIfWrapped(JSContex
 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
 #endif
 
 #ifdef JS_USE_JSID_STRUCT_TYPES
 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);
 const HandleId JS::JSID_EMPTYHANDLE = HandleId::fromMarkedLocation(&emptyIdValue);
 
 /* Make sure that jschar is two bytes unsigned integer */
 JS_STATIC_ASSERT((jschar)-1 > 0);
 JS_STATIC_ASSERT(sizeof(jschar) == 2);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5084,19 +5084,16 @@ JS_DecodeScript(JSContext *cx, const voi
                 JSPrincipals *principals, JSPrincipals *originPrincipals);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
                              JSPrincipals *principals, JSPrincipals *originPrincipals);
 
 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;
 
 } /* namespace JS */
 
 namespace js {
 
 /*
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -987,34 +987,16 @@ js::GetTestingFunctions(JSContext *cx)
 JS_FRIEND_API(unsigned)
 js::GetEnterCompartmentDepth(JSContext *cx)
 {
   return cx->getEnterCompartmentDepth();
 }
 #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)
 {
     rt->DOMcallbacks = callbacks;
 }
 
 JS_FRIEND_API(const DOMCallbacks *)
 js::GetDOMCallbacks(JSRuntime *rt)
 {
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -664,94 +664,16 @@ JS_FRIEND_API(size_t)
 GetPCCountScriptCount(JSContext *cx);
 
 JS_FRIEND_API(JSString *)
 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);
 #endif
 
 JS_FRIEND_API(bool)
 HasUnrootedGlobal(const JSContext *cx);
 
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -63,16 +63,17 @@ EXPORTS.js += [
     '../public/CallArgs.h',
     '../public/CharacterEncoding.h',
     '../public/Date.h',
     '../public/GCAPI.h',
     '../public/HashTable.h',
     '../public/HeapAPI.h',
     '../public/LegacyIntTypes.h',
     '../public/MemoryMetrics.h',
+    '../public/ProfilingStack.h',
     '../public/PropertyKey.h',
     '../public/RequiredDefines.h',
     '../public/RootingAPI.h',
     '../public/StructuredClone.h',
     '../public/Utility.h',
     '../public/Value.h',
     '../public/Vector.h',
 ]
@@ -127,16 +128,17 @@ CPP_SOURCES += [
     'String.cpp',
     'StringBuffer.cpp',
     'StructuredClone.cpp',
     'TestingFunctions.cpp',
     'ThreadPool.cpp',
     'TokenStream.cpp',
     'TypedArrayObject.cpp',
     'Unicode.cpp',
+    'Value.cpp',
     'Verifier.cpp',
     'Xdr.cpp',
     'YarrCanonicalizeUCS2.cpp',
     'YarrInterpreter.cpp',
     'YarrPattern.cpp',
     'YarrSyntaxChecker.cpp',
     'Zone.cpp',
     'jsalloc.cpp',
--- a/js/src/vm/CharacterEncoding.cpp
+++ b/js/src/vm/CharacterEncoding.cpp
@@ -1,19 +1,19 @@
 /* -*- 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/CharacterEncoding.h"
+
 #include "jscntxt.h"
 #include "jsprf.h"
 
-#include "js/CharacterEncoding.h"
-
 using namespace JS;
 
 Latin1CharsZ
 JS::LossyTwoByteCharsToNewLatin1CharsZ(js::ThreadSafeContext *cx, TwoByteChars tbchars)
 {
     JS_ASSERT(cx);
     size_t len = tbchars.length();
     unsigned char *latin1 = cx->pod_malloc<unsigned char>(len + 1);
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -260,19 +260,38 @@ SPSEntryMarker::~SPSEntryMarker()
 {
     if (profiler != NULL) {
         profiler->pop();
         JS_ASSERT(size_before == *profiler->size_);
     }
 }
 
 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));
+}
--- a/js/src/vm/SPSProfiler.h
+++ b/js/src/vm/SPSProfiler.h
@@ -9,16 +9,18 @@
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/GuardObjects.h"
 
 #include <stddef.h>
 
 #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
  *
  * The SPS profiler (found in tools/profiler) is an implementation of a profiler
  * which has the ability to walk the C++ stack as well as use instrumentation to
  * gather information. When dealing with JS, however, SPS needs integration
  * with the engine because otherwise it is very difficult to figure out what
new file mode 100644
--- /dev/null
+++ b/js/src/vm/Value.cpp
@@ -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
--- a/js/xpconnect/public/nsAutoJSValHolder.h
+++ b/js/xpconnect/public/nsAutoJSValHolder.h
@@ -2,19 +2,20 @@
 /* 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 __NSAUTOJSVALHOLDER_H__
 #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!).
  */
 class nsAutoJSValHolder
 {
 public:
   nsAutoJSValHolder()
     : mVal(JSVAL_NULL), mRt(nullptr)
@@ -39,17 +40,17 @@ public:
     if (this != &aOther) {
       if (aOther.IsHeld()) {
         // XXX No error handling here...
         this->Hold(aOther.mRt);
       }
       else {
         this->Release();
       }
-      *this = static_cast<jsval>(aOther);
+      *this = static_cast<JS::Value>(aOther);
     }
     return *this;
   }
 
   /**
    * Hold by rooting on the context's runtime.
    */
   bool Hold(JSContext* aCx) {
@@ -71,20 +72,20 @@ public:
       mRt = aRt;
     }
 
     return !!mRt;
   }
 
   /**
    * 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
       mRt = nullptr;
     }
 
     mVal = JSVAL_NULL;
 
@@ -102,37 +103,37 @@ public:
    * Explicit JSObject* conversion.
    */
   JSObject* ToJSObject() const {
     return mVal.isObject()
          ? &mVal.toObject()
          : 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!");
     }
 #endif
     mVal = aOther;
     return *this;
   }
 
 private:
-  jsval mVal;
+  JS::Value mVal;
   JSRuntime* mRt;
 };
 
 #endif /* __NSAUTOJSVALHOLDER_H__ */
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -2,16 +2,17 @@
  *
  * 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 "nsNSSComponent.h"
 #include "nsNSSIOLayer.h"
 
+#include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Telemetry.h"
 
 #include "prlog.h"
 #include "prnetdb.h"
 #include "nsIPrefService.h"
 #include "nsIClientAuthDialogs.h"
 #include "nsClientAuthRemember.h"
--- a/tools/profiler/PseudoStack.h
+++ b/tools/profiler/PseudoStack.h
@@ -3,17 +3,17 @@
  * 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 PROFILER_PSEUDO_STACK_H_
 #define PROFILER_PSEUDO_STACK_H_
 
 #include "mozilla/NullPtr.h"
 #include <stdint.h>
-#include "jsfriendapi.h"
+#include "js/ProfilingStack.h"
 #include <stdlib.h>
 #include <algorithm>
 
 /* we duplicate this code here to avoid header dependencies
  * which make it more difficult to include in other places */
 #if defined(_M_X64) || defined(__x86_64__)
 #define V8_HOST_ARCH_X64 1
 #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)