Bug 642381, part 3: Hoist Maybe into mfbt and eliminate Gecko's use of jstl. r=jorendorff,luke
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -111,16 +111,18 @@
// Force PR_LOGGING so we can get JS strict warnings even in release builds
#define FORCE_PR_LOG 1
#endif
#include "prlog.h"
#include "prthread.h"
#include "mozilla/FunctionTimer.h"
+using namespace mozilla;
+
const size_t gStackSize = 8192;
#ifdef PR_LOGGING
static PRLogModuleInfo* gJSDiagnostics;
#endif
// Thank you Microsoft!
#ifndef WINCE
@@ -1881,18 +1883,18 @@ nsJSContext::CallEventHandler(nsISupport
jsval funval = OBJECT_TO_JSVAL(funobj);
JSAutoEnterCompartment ac;
if (!ac.enter(mContext, funobj) || !JS_WrapObject(mContext, &target)) {
sSecurityManager->PopContextPrincipal(mContext);
return NS_ERROR_FAILURE;
}
- js::Maybe<nsAutoPoolRelease> poolRelease;
- js::Maybe<js::AutoArrayRooter> tvr;
+ Maybe<nsAutoPoolRelease> poolRelease;
+ Maybe<js::AutoArrayRooter> tvr;
// Use |target| as the scope for wrapping the arguments, since aScope is
// the safe scope in many cases, which isn't very useful. Wrapping aTarget
// was OK because those typically have PreCreate methods that give them the
// right scope anyway, and we want to make sure that the arguments end up
// in the same scope as aTarget.
rv = ConvertSupportsTojsvals(aargv, target, &argc,
&argv, poolRelease, tvr);
@@ -2370,18 +2372,18 @@ nsJSContext::InitializeExternalClasses()
nsresult
nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArgs)
{
PRUint32 argc;
jsval *argv = nsnull;
JSAutoRequest ar(mContext);
- js::Maybe<nsAutoPoolRelease> poolRelease;
- js::Maybe<js::AutoArrayRooter> tvr;
+ Maybe<nsAutoPoolRelease> poolRelease;
+ Maybe<js::AutoArrayRooter> tvr;
nsresult rv;
rv = ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc,
&argv, poolRelease, tvr);
NS_ENSURE_SUCCESS(rv, rv);
jsval vargs;
@@ -2411,18 +2413,18 @@ nsJSContext::SetProperty(void *aTarget,
return rv;
}
nsresult
nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
void *aScope,
PRUint32 *aArgc,
jsval **aArgv,
- js::Maybe<nsAutoPoolRelease> &aPoolRelease,
- js::Maybe<js::AutoArrayRooter> &aRooter)
+ Maybe<nsAutoPoolRelease> &aPoolRelease,
+ Maybe<js::AutoArrayRooter> &aRooter)
{
nsresult rv = NS_OK;
// If the array implements nsIJSArgArray, just grab the values directly.
nsCOMPtr<nsIJSArgArray> fastArray = do_QueryInterface(aArgs);
if (fastArray != nsnull)
return fastArray->GetArgs(aArgc, reinterpret_cast<void **>(aArgv));
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -46,16 +46,18 @@
#include "prtime.h"
#include "nsCycleCollectionParticipant.h"
#include "nsScriptNameSpaceManager.h"
class nsIXPConnectJSObjectHolder;
class nsAutoPoolRelease;
namespace js {
class AutoArrayRooter;
+}
+namespace mozilla {
template <class> class Maybe;
}
class nsJSContext : public nsIScriptContext,
public nsIXPCScriptNotify
{
public:
nsJSContext(JSRuntime *aRuntime);
@@ -200,18 +202,18 @@ public:
protected:
nsresult InitializeExternalClasses();
// Helper to convert xpcom datatypes to jsvals.
nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
void *aScope,
PRUint32 *aArgc,
jsval **aArgv,
- js::Maybe<nsAutoPoolRelease> &aPoolRelease,
- js::Maybe<js::AutoArrayRooter> &aRooter);
+ mozilla::Maybe<nsAutoPoolRelease> &aPoolRelease,
+ mozilla::Maybe<js::AutoArrayRooter> &aRooter);
nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, jsval *aArgv);
// given an nsISupports object (presumably an event target or some other
// DOM object), get (or create) the JSObject wrapping it.
nsresult JSObjectFromInterface(nsISupports *aSup, void *aScript,
JSObject **aRet);
--- a/js/jetpack/JetpackActorCommon.cpp
+++ b/js/jetpack/JetpackActorCommon.cpp
@@ -35,36 +35,27 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "base/basictypes.h"
#include "jscntxt.h"
#include "jsapi.h"
-#include "jstl.h"
#include "jshashtable.h"
#include "mozilla/jetpack/JetpackActorCommon.h"
#include "mozilla/jetpack/PJetpack.h"
#include "mozilla/jetpack/PHandleParent.h"
#include "mozilla/jetpack/PHandleChild.h"
#include "mozilla/jetpack/Handle.h"
#include "nsJSUtils.h"
-using mozilla::jetpack::JetpackActorCommon;
-using mozilla::jetpack::PHandleParent;
-using mozilla::jetpack::HandleParent;
-using mozilla::jetpack::PHandleChild;
-using mozilla::jetpack::HandleChild;
-using mozilla::jetpack::KeyValue;
-using mozilla::jetpack::PrimVariant;
-using mozilla::jetpack::CompVariant;
-using mozilla::jetpack::Variant;
+using namespace mozilla::jetpack;
class JetpackActorCommon::OpaqueSeenType
{
public:
typedef JSObject* KeyType;
typedef size_t IdType;
typedef js::HashMap<
KeyType, IdType,
@@ -171,17 +162,17 @@ JetpackActorCommon::jsval_to_PrimVariant
bool
JetpackActorCommon::jsval_to_CompVariant(JSContext* cx, JSType type, jsval from,
CompVariant* to, OpaqueSeenType* seen)
{
if (type != JSTYPE_OBJECT)
return false;
- js::Maybe<OpaqueSeenType> lost;
+ Maybe<OpaqueSeenType> lost;
if (!seen) {
lost.construct();
seen = lost.addr();
if (!seen->ok())
return false;
}
OpaqueSeenType::KeyType obj = JSVAL_TO_OBJECT(from);
@@ -332,17 +323,17 @@ JetpackActorCommon::jsval_from_PrimVaria
}
bool
JetpackActorCommon::jsval_from_CompVariant(JSContext* cx,
const CompVariant& from,
jsval* to,
OpaqueSeenType* seen)
{
- js::Maybe<OpaqueSeenType> lost;
+ Maybe<OpaqueSeenType> lost;
if (!seen) {
lost.construct();
seen = lost.addr();
if (!seen->ok())
return false;
}
JSObject* obj = NULL;
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -287,16 +287,17 @@ EXPORTS_vm = \
#
VPATH += \
$(srcdir)/../../mfbt \
$(NULL)
EXPORTS_NAMESPACES += mozilla
EXPORTS_mozilla = \
+ Types.h \
Util.h \
$(NULL)
ifdef ENABLE_TRACEJIT
VPATH += \
$(srcdir)/tracejit \
$(srcdir)/nanojit \
@@ -723,16 +724,21 @@ distclean::
$(RM) $(DIST_GARBAGE)
# our build system doesn't handle subdir srcs very gracefully today
export::
$(MKDIR) -p nanojit
DEFINES += -DEXPORT_JS_API
+# mfbt is always packed with us, so if we're building a shared object,
+# we need to declare "exported" mfbt symbols on its behalf when we use
+# its headers.
+DEFINES += -DIMPL_MFBT
+
# Some platforms that have stdint.h include it in system headers. So
# to reliably get limit macros defined, we'd always have to define the
# one below before including any header, but that's obscure and
# fragile, so we do it here.
DEFINES += -D__STDC_LIMIT_MACROS
INCLUDES += -I$(srcdir)
--- a/js/src/jstl.h
+++ b/js/src/jstl.h
@@ -229,133 +229,16 @@ RoundUpPow2(size_t x)
*/
template <class T>
JS_ALWAYS_INLINE size_t
PointerRangeSize(T *begin, T *end)
{
return (size_t(end) - size_t(begin)) / sizeof(T);
}
-/*
- * This utility pales in comparison to Boost's aligned_storage. The utility
- * simply assumes that JSUint64 is enough alignment for anyone. This may need
- * to be extended one day...
- *
- * As an important side effect, pulling the storage into this template is
- * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving
- * false negatives when we cast from the char buffer to whatever type we've
- * constructed using the bytes.
- */
-template <size_t nbytes>
-struct AlignedStorage
-{
- union U {
- char bytes[nbytes];
- uint64 _;
- } u;
-
- const void *addr() const { return u.bytes; }
- void *addr() { return u.bytes; }
-};
-
-template <class T>
-struct AlignedStorage2
-{
- union U {
- char bytes[sizeof(T)];
- uint64 _;
- } u;
-
- const T *addr() const { return (const T *)u.bytes; }
- T *addr() { return (T *)u.bytes; }
-};
-
-/*
- * Small utility for lazily constructing objects without using dynamic storage.
- * When a Maybe<T> is constructed, it is |empty()|, i.e., no value of T has
- * been constructed and no T destructor will be called when the Maybe<T> is
- * destroyed. Upon calling |construct|, a T object will be constructed with the
- * given arguments and that object will be destroyed when the owning Maybe<T>
- * is destroyed.
- *
- * N.B. GCC seems to miss some optimizations with Maybe and may generate extra
- * branches/loads/stores. Use with caution on hot paths.
- */
-template <class T>
-class Maybe
-{
- AlignedStorage2<T> storage;
- bool constructed;
-
- T &asT() { return *storage.addr(); }
-
- explicit Maybe(const Maybe &other);
- const Maybe &operator=(const Maybe &other);
-
- public:
- Maybe() { constructed = false; }
- ~Maybe() { if (constructed) asT().~T(); }
-
- bool empty() const { return !constructed; }
-
- void construct() {
- JS_ASSERT(!constructed);
- new(storage.addr()) T();
- constructed = true;
- }
-
- template <class T1>
- void construct(const T1 &t1) {
- JS_ASSERT(!constructed);
- new(storage.addr()) T(t1);
- constructed = true;
- }
-
- template <class T1, class T2>
- void construct(const T1 &t1, const T2 &t2) {
- JS_ASSERT(!constructed);
- new(storage.addr()) T(t1, t2);
- constructed = true;
- }
-
- template <class T1, class T2, class T3>
- void construct(const T1 &t1, const T2 &t2, const T3 &t3) {
- JS_ASSERT(!constructed);
- new(storage.addr()) T(t1, t2, t3);
- constructed = true;
- }
-
- template <class T1, class T2, class T3, class T4>
- void construct(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) {
- JS_ASSERT(!constructed);
- new(storage.addr()) T(t1, t2, t3, t4);
- constructed = true;
- }
-
- T *addr() {
- JS_ASSERT(constructed);
- return &asT();
- }
-
- T &ref() {
- JS_ASSERT(constructed);
- return asT();
- }
-
- void destroy() {
- ref().~T();
- constructed = false;
- }
-
- void destroyIfConstructed() {
- if (!empty())
- destroy();
- }
-};
-
template <class T>
class AlignedPtrAndFlag
{
uintptr_t bits;
public:
AlignedPtrAndFlag(T *t, bool flag) {
JS_ASSERT((uintptr_t(t) & 1) == 0);
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -41,16 +41,17 @@
*
* ***** END LICENSE BLOCK ***** */
/* state and methods used while laying out a single line of a block frame */
#define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
#include "plarena.h"
+#include "mozilla/Util.h"
#include "nsCOMPtr.h"
#include "nsLineLayout.h"
#include "nsBlockFrame.h"
#include "nsInlineFrame.h"
#include "nsStyleConsts.h"
#include "nsHTMLContainerFrame.h"
#include "nsFloatManager.h"
#include "nsStyleContext.h"
@@ -61,17 +62,16 @@
#include "nsIDocument.h"
#include "nsIHTMLDocument.h"
#include "nsIContent.h"
#include "nsTextFragment.h"
#include "nsBidiUtils.h"
#include "nsLayoutUtils.h"
#include "nsTextFrame.h"
#include "nsCSSRendering.h"
-#include "jstl.h"
#ifdef DEBUG
#undef NOISY_HORIZONTAL_ALIGN
#undef NOISY_VERTICAL_ALIGN
#undef REALLY_NOISY_VERTICAL_ALIGN
#undef NOISY_REFLOW
#undef REALLY_NOISY_REFLOW
#undef NOISY_PUSHING
@@ -79,16 +79,18 @@
#undef DEBUG_ADD_TEXT
#undef NOISY_MAX_ELEMENT_SIZE
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
#undef NOISY_CAN_PLACE_FRAME
#undef NOISY_TRIM
#undef REALLY_NOISY_TRIM
#endif
+using namespace mozilla;
+
//----------------------------------------------------------------------
#define FIX_BUG_50257
nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
nsFloatManager* aFloatManager,
const nsHTMLReflowState* aOuterReflowState,
const nsLineList::iterator* aLine)
@@ -781,17 +783,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
// reflects the space left on the line.
NS_WARN_IF_FALSE(psd->mRightEdge != NS_UNCONSTRAINEDSIZE,
"have unconstrained width; this should only result from "
"very large sizes, not attempts at intrinsic width "
"calculation");
nscoord availableSpaceOnLine = psd->mRightEdge - psd->mX;
// Setup reflow state for reflowing the frame
- js::Maybe<nsHTMLReflowState> reflowStateHolder;
+ Maybe<nsHTMLReflowState> reflowStateHolder;
if (!isText) {
reflowStateHolder.construct(mPresContext, *psd->mReflowState,
aFrame, availSize);
nsHTMLReflowState& reflowState = reflowStateHolder.ref();
reflowState.mLineLayout = this;
reflowState.mFlags.mIsTopOfPage = GetFlag(LL_ISTOPOFPAGE);
if (reflowState.ComputedWidth() == NS_UNCONSTRAINEDSIZE)
reflowState.availableWidth = availableSpaceOnLine;
new file mode 100644
--- /dev/null
+++ b/mfbt/Types.h
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99 ft=cpp:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Code.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyrigght (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * NB: This header must be both valid C and C++. It must be
+ * include-able by code embedding SpiderMonkey *and* Gecko.
+ */
+
+#ifndef mozilla_Types_h_
+#define mozilla_Types_h_
+
+/*
+ * mfbt is logically "lower level" than js/src, but needs basic
+ * definitions of numerical types and macros for compiler/linker
+ * directives. js/src already goes through some pain to provide them
+ * on numerous platforms, so instead of moving all that goop here,
+ * this header makes use of the fact that for the foreseeable future
+ * mfbt code will be part and parcel with libmozjs, static or not.
+ *
+ * For now, the policy is to use jstypes definitions but add a layer
+ * of indirection on top of them in case a Great Refactoring ever
+ * happens.
+ */
+#include "jstypes.h"
+
+/*
+ * The numerical types provided by jstypes.h that are allowed within
+ * mfbt code are
+ *
+ * stddef types: size_t, ptrdiff_t, etc.
+ * stdin [sic] types: int8, uint32, etc.
+ *
+ * stdint types (int8_t etc.), are available for use here, but doing
+ * so would change SpiderMonkey's and Gecko's contracts with
+ * embedders: stdint types have not yet appeared in public APIs.
+ */
+
+#define MOZ_EXPORT_API(type_) JS_EXPORT_API(type_)
+#define MOZ_IMPORT_API(type_) JS_IMPORT_API(type_)
+
+/*
+ * mfbt definitions need to see export declarations when built, but
+ * other code needs to see import declarations when using mfbt.
+ */
+#if defined(IMPL_MFBT)
+# define MFBT_API(type_) MOZ_EXPORT_API(type_)
+#else
+# define MFBT_API(type_) MOZ_IMPORT_API(type_)
+#endif
+
+
+#define MOZ_BEGIN_EXTERN_C JS_BEGIN_EXTERN_C
+#define MOZ_END_EXTERN_C JS_END_EXTERN_C
+
+#endif // mozilla_Types_h_
--- a/mfbt/Util.h
+++ b/mfbt/Util.h
@@ -35,16 +35,52 @@
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_Util_h_
#define mozilla_Util_h_
+#include "mozilla/Types.h"
+
+/*
+ * XXX: we're cheating here in order to avoid creating object files
+ * for mfbt /just/ to provide a function like FatalError() to be used
+ * by MOZ_ASSERT(). (It'll happen eventually, but for just ASSERT()
+ * it isn't worth the pain.) JS_Assert(), although unfortunately
+ * named, is part of SpiderMonkey's stable, external API, so this
+ * isn't quite as bad as it seems.
+ *
+ * Once mfbt needs object files, this unholy union with JS_Assert()
+ * will be broken.
+ */
+MOZ_BEGIN_EXTERN_C
+
+extern MFBT_API(void)
+JS_Assert(const char *s, const char *file, JSIntn ln);
+
+MOZ_END_EXTERN_C
+
+/*
+ * MOZ_ASSERT() is a "strong" assertion of state, like libc's
+ * assert(). If a MOZ_ASSERT() fails in a debug build, the process in
+ * which it fails will stop running in a loud and dramatic way.
+ */
+#ifdef DEBUG
+
+# define MOZ_ASSERT(expr_) \
+ ((expr_) ? (void)0 : JS_Assert(#expr_, __FILE__, __LINE__))
+
+#else
+
+# define MOZ_ASSERT(expr_) ((void)0)
+
+#endif // DEBUG
+
#ifdef __cplusplus
namespace mozilla {
/**
* DebugOnly contains a value of type T, but only in debug builds. In
* release builds, it does not contain a value. This helper is
* intended to be used along with ASSERT()-style macros, allowing one
@@ -86,13 +122,131 @@ struct DebugOnly
/*
* DebugOnly must always have a destructor or else it will
* generate "unused variable" warnings, exactly what it's intended
* to avoid!
*/
~DebugOnly() {}
};
+
+/*
+ * This utility pales in comparison to Boost's aligned_storage. The utility
+ * simply assumes that JSUint64 is enough alignment for anyone. This may need
+ * to be extended one day...
+ *
+ * As an important side effect, pulling the storage into this template is
+ * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving
+ * false negatives when we cast from the char buffer to whatever type we've
+ * constructed using the bytes.
+ */
+template <size_t nbytes>
+struct AlignedStorage
+{
+ union U {
+ char bytes[nbytes];
+ uint64 _;
+ } u;
+
+ const void *addr() const { return u.bytes; }
+ void *addr() { return u.bytes; }
+};
+
+template <class T>
+struct AlignedStorage2
+{
+ union U {
+ char bytes[sizeof(T)];
+ uint64 _;
+ } u;
+
+ const T *addr() const { return (const T *)u.bytes; }
+ T *addr() { return (T *)u.bytes; }
+};
+
+/*
+ * Small utility for lazily constructing objects without using dynamic storage.
+ * When a Maybe<T> is constructed, it is |empty()|, i.e., no value of T has
+ * been constructed and no T destructor will be called when the Maybe<T> is
+ * destroyed. Upon calling |construct|, a T object will be constructed with the
+ * given arguments and that object will be destroyed when the owning Maybe<T>
+ * is destroyed.
+ *
+ * N.B. GCC seems to miss some optimizations with Maybe and may generate extra
+ * branches/loads/stores. Use with caution on hot paths.
+ */
+template <class T>
+class Maybe
+{
+ AlignedStorage2<T> storage;
+ bool constructed;
+
+ T &asT() { return *storage.addr(); }
+
+ explicit Maybe(const Maybe &other);
+ const Maybe &operator=(const Maybe &other);
+
+ public:
+ Maybe() { constructed = false; }
+ ~Maybe() { if (constructed) asT().~T(); }
+
+ bool empty() const { return !constructed; }
+
+ void construct() {
+ MOZ_ASSERT(!constructed);
+ new(storage.addr()) T();
+ constructed = true;
+ }
+
+ template <class T1>
+ void construct(const T1 &t1) {
+ MOZ_ASSERT(!constructed);
+ new(storage.addr()) T(t1);
+ constructed = true;
+ }
+
+ template <class T1, class T2>
+ void construct(const T1 &t1, const T2 &t2) {
+ MOZ_ASSERT(!constructed);
+ new(storage.addr()) T(t1, t2);
+ constructed = true;
+ }
+
+ template <class T1, class T2, class T3>
+ void construct(const T1 &t1, const T2 &t2, const T3 &t3) {
+ MOZ_ASSERT(!constructed);
+ new(storage.addr()) T(t1, t2, t3);
+ constructed = true;
+ }
+
+ template <class T1, class T2, class T3, class T4>
+ void construct(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) {
+ MOZ_ASSERT(!constructed);
+ new(storage.addr()) T(t1, t2, t3, t4);
+ constructed = true;
+ }
+
+ T *addr() {
+ MOZ_ASSERT(constructed);
+ return &asT();
+ }
+
+ T &ref() {
+ MOZ_ASSERT(constructed);
+ return asT();
+ }
+
+ void destroy() {
+ ref().~T();
+ constructed = false;
+ }
+
+ void destroyIfConstructed() {
+ if (!empty())
+ destroy();
+ }
+};
+
} /* namespace mozilla */
#endif /* __cplusplus */
#endif /* mozilla_Util_h_ */