Merge inbound to m-c
authorWes Kocher <wkocher@mozilla.com>
Fri, 07 Mar 2014 17:07:37 -0800
changeset 172604 d01bf8596d3bebdd119767d91aa02026e834af3f
parent 172598 3bb690f96b9250e9470c9614b05d7d1c6353ebaf (current diff)
parent 172603 0827b0fbb8aa2b04c3dc2583a1050e9d1cac8755 (diff)
child 172605 cbd16e8af70211813b604f6d91b2b64f3b6c2fa8
child 172639 8441e058510789ec3693cc63a9f74b5dc948591a
child 172657 479720fcefedd39ed86d0cc36d120e2447f47b90
child 172683 7d6ca20a15b56e96b4439f49edec26d1e5e979d2
push id26368
push userkwierso@gmail.com
push dateSat, 08 Mar 2014 01:07:47 +0000
treeherdermozilla-central@d01bf8596d3b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.0a1
first release with
nightly linux32
d01bf8596d3b / 30.0a1 / 20140308030203 / files
nightly linux64
d01bf8596d3b / 30.0a1 / 20140308030203 / files
nightly mac
d01bf8596d3b / 30.0a1 / 20140308030203 / files
nightly win32
d01bf8596d3b / 30.0a1 / 20140308030203 / files
nightly win64
d01bf8596d3b / 30.0a1 / 20140308030203 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -4575,17 +4575,30 @@ gfxFontGroup::MakeSpaceTextRun(const Par
     gfxFont *font = GetFontAt(0);
     if (MOZ_UNLIKELY(GetStyle()->size == 0)) {
         // Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
         // them, and always create at least size 1 fonts, i.e. they still
         // render something for size 0 fonts.
         textRun->AddGlyphRun(font, gfxTextRange::kFontGroup, 0, false);
     }
     else {
-        textRun->SetSpaceGlyph(font, aParams->mContext, 0);
+        if (font->GetSpaceGlyph()) {
+            // Normally, the font has a cached space glyph, so we can avoid
+            // the cost of calling FindFontForChar.
+            textRun->SetSpaceGlyph(font, aParams->mContext, 0);
+        } else {
+            // In case the primary font doesn't have <space> (bug 970891),
+            // find one that does.
+            uint8_t matchType;
+            nsRefPtr<gfxFont> spaceFont =
+                FindFontForChar(' ', 0, MOZ_SCRIPT_LATIN, nullptr, &matchType);
+            if (spaceFont) {
+                textRun->SetSpaceGlyph(spaceFont, aParams->mContext, 0);
+            }
+        }
     }
 
     // Note that the gfxGlyphExtents glyph bounds storage for the font will
     // always contain an entry for the font's space glyph, so we don't have
     // to call FetchGlyphExtents here.
     return textRun;
 }
 
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -260,22 +260,16 @@ typedef bool
 typedef void
 (* JSFinalizeOp)(JSFreeOp *fop, JSObject *obj);
 
 // Finalizes external strings created by JS_NewExternalString.
 struct JSStringFinalizer {
     void (*finalize)(const JSStringFinalizer *fin, jschar *chars);
 };
 
-// Return whether the first principal subsumes the second. The exact meaning of
-// 'subsumes' is left up to the browser. Subsumption is checked inside the JS
-// engine when determining, e.g., which stack frames to display in a backtrace.
-typedef bool
-(* JSSubsumesOp)(JSPrincipals *first, JSPrincipals *second);
-
 // Check whether v is an instance of obj.  Return false on error or exception,
 // true on success with true in *bp if v is an instance of obj, false in
 // *bp otherwise.
 typedef bool
 (* JSHasInstanceOp)(JSContext *cx, JS::HandleObject obj, JS::MutableHandleValue vp,
                     bool *bp);
 
 // Function type for trace operation of the class called to enumerate all
new file mode 100644
--- /dev/null
+++ b/js/public/Principals.h
@@ -0,0 +1,100 @@
+/* -*- 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/. */
+
+/* JSPrincipals and related interfaces. */
+
+#ifndef js_Principals_h
+#define js_Principals_h
+
+#include "mozilla/Atomics.h"
+
+#include <stdint.h>
+
+#include "jspubtd.h"
+
+struct JSPrincipals {
+    /* Don't call "destroy"; use reference counting macros below. */
+#ifdef JS_THREADSAFE
+    mozilla::Atomic<int32_t> refcount;
+#else
+    int32_t refcount;
+#endif
+
+#ifdef JS_DEBUG
+    /* A helper to facilitate principals debugging. */
+    uint32_t    debugToken;
+#endif
+
+    void setDebugToken(uint32_t token) {
+# ifdef JS_DEBUG
+        debugToken = token;
+# endif
+    }
+
+    /*
+     * This is not defined by the JS engine but should be provided by the
+     * embedding.
+     */
+    JS_PUBLIC_API(void) dump();
+};
+
+extern JS_PUBLIC_API(void)
+JS_HoldPrincipals(JSPrincipals *principals);
+
+extern JS_PUBLIC_API(void)
+JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals);
+
+// Return whether the first principal subsumes the second. The exact meaning of
+// 'subsumes' is left up to the browser. Subsumption is checked inside the JS
+// engine when determining, e.g., which stack frames to display in a backtrace.
+typedef bool
+(* JSSubsumesOp)(JSPrincipals *first, JSPrincipals *second);
+
+/*
+ * Used to check if a CSP instance wants to disable eval() and friends.
+ * See js_CheckCSPPermitsJSAction() in jsobj.
+ */
+typedef bool
+(* JSCSPEvalChecker)(JSContext *cx);
+
+struct JSSecurityCallbacks {
+    JSCSPEvalChecker           contentSecurityPolicyAllows;
+    JSSubsumesOp               subsumes;
+};
+
+extern JS_PUBLIC_API(void)
+JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *callbacks);
+
+extern JS_PUBLIC_API(const JSSecurityCallbacks *)
+JS_GetSecurityCallbacks(JSRuntime *rt);
+
+/*
+ * Code running with "trusted" principals will be given a deeper stack
+ * allocation than ordinary scripts. This allows trusted script to run after
+ * untrusted script has exhausted the stack. This function sets the
+ * runtime-wide trusted principal.
+ *
+ * This principals is not held (via JS_HoldPrincipals/JS_DropPrincipals) since
+ * there is no available JSContext. Instead, the caller must ensure that the
+ * given principals stays valid for as long as 'rt' may point to it. If the
+ * principals would be destroyed before 'rt', JS_SetTrustedPrincipals must be
+ * called again, passing nullptr for 'prin'.
+ */
+extern JS_PUBLIC_API(void)
+JS_SetTrustedPrincipals(JSRuntime *rt, const JSPrincipals *prin);
+
+typedef void
+(* JSDestroyPrincipalsOp)(JSPrincipals *principals);
+
+/*
+ * Initialize the callback that is called to destroy JSPrincipals instance
+ * when its reference counter drops to zero. The initialization can be done
+ * only once per JS runtime.
+ */
+extern JS_PUBLIC_API(void)
+JS_InitDestroyPrincipalsCallback(JSRuntime *rt, JSDestroyPrincipalsOp destroyPrincipals);
+
+#endif  /* js_Principals_h */
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/shell-principals.js
@@ -0,0 +1,52 @@
+// Test the JS shell's toy principals.
+
+var count = 0;
+
+// Given a string of letters |expected|, say "abc", assert that the stack
+// contains calls to a series of functions named by the next letter from
+// the string, say a, b, and then c. Younger frames appear earlier in
+// |expected| than older frames.
+function check(expected, stack) {
+  print("check(" + uneval(expected) + ") against:\n" + stack);
+  count++;
+
+  // Extract only the function names from the stack trace. Omit the frames
+  // for the top-level evaluation, if it is present.
+  var split = stack.split(/(.)?@.*\n/).slice(0, -1);
+  if (split[split.length - 1] === undefined)
+    split = split.slice(0, -2);
+
+  // Check the function names against the expected sequence.
+  assertEq(split.length, expected.length * 2);
+  for (var i = 0; i < expected.length; i++)
+    assertEq(split[i * 2 + 1], expected[i]);
+}
+
+var low = newGlobal({ principal: 0 });
+var mid = newGlobal({ principal: 0xffff });
+var high = newGlobal({ principal: 0xfffff });
+
+     eval('function a() { check("a",        Error().stack); b(); }');
+low .eval('function b() { check("b",        Error().stack); c(); }');
+mid .eval('function c() { check("cba",      Error().stack); d(); }');
+high.eval('function d() { check("dcba",     Error().stack); e(); }');
+     eval('function e() { check("edcba",    Error().stack); f(); }'); // no principal, so checks skipped
+low .eval('function f() { check("fb",       Error().stack); g(); }');
+mid .eval('function g() { check("gfecba",   Error().stack); h(); }');
+high.eval('function h() { check("hgfedcba", Error().stack);      }');
+
+// Make everyone's functions visible to each other, as needed.
+     b = low .b;
+low .c = mid .c;
+mid .d = high.d;
+high.e =      e;
+     f = low .f;
+low .g = mid .g;
+mid .h = high.h;
+
+low.check = mid.check = high.check = check;
+
+// Kick the whole process off.
+a();
+
+assertEq(count, 8);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4,33 +4,33 @@
  * 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/. */
 
 /* JavaScript API. */
 
 #ifndef jsapi_h
 #define jsapi_h
 
-#include "mozilla/Atomics.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/RangedPtr.h"
 
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
 
 #include "jsalloc.h"
 #include "jspubtd.h"
 
 #include "js/CallArgs.h"
 #include "js/Class.h"
 #include "js/HashTable.h"
 #include "js/Id.h"
+#include "js/Principals.h"
 #include "js/RootingAPI.h"
 #include "js/Utility.h"
 #include "js/Value.h"
 #include "js/Vector.h"
 
 /************************************************************************/
 
 struct JSTracer;
@@ -775,30 +775,16 @@ typedef bool
 typedef bool
 (* JSLocaleCompare)(JSContext *cx, JS::HandleString src1, JS::HandleString src2,
                     JS::MutableHandleValue rval);
 
 typedef bool
 (* JSLocaleToUnicode)(JSContext *cx, const char *src, JS::MutableHandleValue rval);
 
 /*
- * Security protocol types.
- */
-
-typedef void
-(* JSDestroyPrincipalsOp)(JSPrincipals *principals);
-
-/*
- * Used to check if a CSP instance wants to disable eval() and friends.
- * See js_CheckCSPPermitsJSAction() in jsobj.
- */
-typedef bool
-(* JSCSPEvalChecker)(JSContext *cx);
-
-/*
  * Callback used to ask the embedding for the cross compartment wrapper handler
  * that implements the desired prolicy for this kind of object in the
  * destination compartment. |obj| is the object to be wrapped. If |existing| is
  * non-nullptr, it will point to an existing wrapper object that should be
  * re-used if possible. |existing| is guaranteed to be a cross-compartment
  * wrapper with a lazily-defined prototype and the correct global. It is
  * guaranteed not to wrap a function.
  */
@@ -3198,87 +3184,16 @@ extern JS_PUBLIC_API(jsval)
 JS_GetReservedSlot(JSObject *obj, uint32_t index);
 
 extern JS_PUBLIC_API(void)
 JS_SetReservedSlot(JSObject *obj, uint32_t index, jsval v);
 
 /************************************************************************/
 
 /*
- * Security protocol.
- */
-struct JSPrincipals {
-    /* Don't call "destroy"; use reference counting macros below. */
-#ifdef JS_THREADSAFE
-    mozilla::Atomic<int32_t> refcount;
-#else
-    int32_t refcount;
-#endif
-
-#ifdef JS_DEBUG
-    /* A helper to facilitate principals debugging. */
-    uint32_t    debugToken;
-#endif
-
-    void setDebugToken(uint32_t token) {
-# ifdef JS_DEBUG
-        debugToken = token;
-# endif
-    }
-
-    /*
-     * This is not defined by the JS engine but should be provided by the
-     * embedding.
-     */
-    JS_PUBLIC_API(void) dump();
-};
-
-extern JS_PUBLIC_API(void)
-JS_HoldPrincipals(JSPrincipals *principals);
-
-extern JS_PUBLIC_API(void)
-JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals);
-
-struct JSSecurityCallbacks {
-    JSCSPEvalChecker           contentSecurityPolicyAllows;
-    JSSubsumesOp               subsumes;
-};
-
-extern JS_PUBLIC_API(void)
-JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *callbacks);
-
-extern JS_PUBLIC_API(const JSSecurityCallbacks *)
-JS_GetSecurityCallbacks(JSRuntime *rt);
-
-/*
- * Code running with "trusted" principals will be given a deeper stack
- * allocation than ordinary scripts. This allows trusted script to run after
- * untrusted script has exhausted the stack. This function sets the
- * runtime-wide trusted principal.
- *
- * This principals is not held (via JS_HoldPrincipals/JS_DropPrincipals) since
- * there is no available JSContext. Instead, the caller must ensure that the
- * given principals stays valid for as long as 'rt' may point to it. If the
- * principals would be destroyed before 'rt', JS_SetTrustedPrincipals must be
- * called again, passing nullptr for 'prin'.
- */
-extern JS_PUBLIC_API(void)
-JS_SetTrustedPrincipals(JSRuntime *rt, const JSPrincipals *prin);
-
-/*
- * Initialize the callback that is called to destroy JSPrincipals instance
- * when its reference counter drops to zero. The initialization can be done
- * only once per JS runtime.
- */
-extern JS_PUBLIC_API(void)
-JS_InitDestroyPrincipalsCallback(JSRuntime *rt, JSDestroyPrincipalsOp destroyPrincipals);
-
-/************************************************************************/
-
-/*
  * Functions and scripts.
  */
 extern JS_PUBLIC_API(JSFunction *)
 JS_NewFunction(JSContext *cx, JSNative call, unsigned nargs, unsigned flags,
                JS::Handle<JSObject*> parent, const char *name);
 
 /*
  * Create the function with the name given by the id. JSID_IS_STRING(id) must
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -72,16 +72,17 @@ EXPORTS.js += [
     '../public/Date.h',
     '../public/GCAPI.h',
     '../public/HashTable.h',
     '../public/HeapAPI.h',
     '../public/Id.h',
     '../public/LegacyIntTypes.h',
     '../public/MemoryMetrics.h',
     '../public/OldDebugAPI.h',
+    '../public/Principals.h',
     '../public/ProfilingStack.h',
     '../public/PropertyKey.h',
     '../public/RequiredDefines.h',
     '../public/RootingAPI.h',
     '../public/SliceBudget.h',
     '../public/StructuredClone.h',
     '../public/Tracer.h',
     '../public/TypeDecls.h',
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -185,21 +185,75 @@ enum JSShellErrNum {
 
 static JSContext *
 NewContext(JSRuntime *rt);
 
 static void
 DestroyContext(JSContext *cx, bool withGC);
 
 static JSObject *
-NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options);
+NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options,
+                JSPrincipals *principals);
 
 static const JSErrorFormatString *
 my_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber);
 
+
+/*
+ * A toy principals type for the shell.
+ *
+ * In the shell, a principal is simply a 32-bit mask: P subsumes Q if the
+ * set bits in P are a superset of those in Q. Thus, the principal 0 is
+ * subsumed by everything, and the principal ~0 subsumes everything.
+ *
+ * As a special case, a null pointer as a principal is treated like 0xffff.
+ *
+ * The 'newGlobal' function takes an option indicating which principal the
+ * new global should have; 'evaluate' does for the new code.
+ */
+class ShellPrincipals: public JSPrincipals {
+    uint32_t bits;
+
+    static uint32_t getBits(JSPrincipals *p) {
+        if (!p)
+            return 0xffff;
+        return static_cast<ShellPrincipals *>(p)->bits;
+    }
+
+  public:
+    ShellPrincipals(uint32_t bits, int32_t refcount = 0) : bits(bits) {
+        this->refcount = refcount;
+    }
+
+    static void destroy(JSPrincipals *principals) {
+        MOZ_ASSERT(principals != &fullyTrusted);
+        MOZ_ASSERT(principals->refcount == 0);
+        js_free(static_cast<ShellPrincipals *>(principals));
+    }
+
+    static bool subsumes(JSPrincipals *first, JSPrincipals *second) {
+        uint32_t firstBits  = getBits(first);
+        uint32_t secondBits = getBits(second);
+        return (firstBits | secondBits) == firstBits;
+    }
+
+    static JSSecurityCallbacks securityCallbacks;
+
+    // Fully-trusted principals singleton.
+    static ShellPrincipals fullyTrusted;
+};
+
+JSSecurityCallbacks ShellPrincipals::securityCallbacks = {
+    nullptr, // contentSecurityPolicyAllows
+    subsumes
+};
+
+// The fully-trusted principal subsumes all other principals.
+ShellPrincipals ShellPrincipals::fullyTrusted(-1, 1);
+
 #ifdef EDITLINE
 extern "C" {
 extern JS_EXPORT_API(char *) readline(const char *prompt);
 extern JS_EXPORT_API(void)   add_history(char *line);
 } // extern "C"
 #endif
 
 static char *
@@ -2824,17 +2878,17 @@ WorkerMain(void *arg)
         return;
     }
 
     do {
         JSAutoRequest ar(cx);
 
         JS::CompartmentOptions compartmentOptions;
         compartmentOptions.setVersion(JSVERSION_LATEST);
-        RootedObject global(cx, NewGlobalObject(cx, compartmentOptions));
+        RootedObject global(cx, NewGlobalObject(cx, compartmentOptions, nullptr));
         if (!global)
             break;
 
         JSAutoCompartment ac(cx, global);
 
         JS::CompileOptions options(cx);
         options.setFileAndLine("<string>", 1)
                .setCompileAndGo(true);
@@ -4099,16 +4153,17 @@ WrapWithProto(JSContext *cx, unsigned ar
 
     JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(wrapped));
     return true;
 }
 
 static bool
 NewGlobal(JSContext *cx, unsigned argc, jsval *vp)
 {
+    JSPrincipals *principals = nullptr;
     JS::CompartmentOptions options;
     options.setVersion(JSVERSION_LATEST);
 
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() == 1 && args[0].isObject()) {
         RootedObject opts(cx, &args[0].toObject());
         RootedValue v(cx);
 
@@ -4116,19 +4171,33 @@ NewGlobal(JSContext *cx, unsigned argc, 
             return false;
         if (v.isObject())
             options.setSameZoneAs(UncheckedUnwrap(&v.toObject()));
 
         if (!JS_GetProperty(cx, opts, "invisibleToDebugger", &v))
             return false;
         if (v.isBoolean())
             options.setInvisibleToDebugger(v.toBoolean());
-    }
-
-    RootedObject global(cx, NewGlobalObject(cx, options));
+
+        if (!JS_GetProperty(cx, opts, "principal", &v))
+            return false;
+        if (!v.isUndefined()) {
+            uint32_t bits;
+            if (!ToUint32(cx, v, &bits))
+                return false;
+            principals = cx->new_<ShellPrincipals>(bits);
+            if (!principals)
+                return false;
+            JS_HoldPrincipals(principals);
+        }
+    }
+
+    RootedObject global(cx, NewGlobalObject(cx, options, principals));
+    if (principals)
+        JS_DropPrincipals(cx->runtime(), principals);
     if (!global)
         return false;
 
     if (!JS_WrapObject(cx, &global))
         return false;
 
     args.rval().setObject(*global);
     return true;
@@ -4596,17 +4665,25 @@ static const JSFunctionSpecWithHelp shel
 "wrapWithProto(obj)",
 "  Wrap an object into a noop wrapper with prototype semantics."),
 
     JS_FN_HELP("newGlobal", NewGlobal, 1, 0,
 "newGlobal([options])",
 "  Return a new global object in a new compartment. If options\n"
 "  is given, it may have any of the following properties:\n"
 "      sameZoneAs: the compartment will be in the same zone as the given object (defaults to a new zone)\n"
-"      invisibleToDebugger: the global will be invisible to the debugger (default false)"),
+"      invisibleToDebugger: the global will be invisible to the debugger (default false)\n"
+"      principal: if present, its value converted to a number must be an\n"
+"         integer that fits in 32 bits; use that as the new compartment's\n"
+"         principal. Shell principals are toys, meant only for testing; one\n"
+"         shell principal subsumes another if its set bits are a superset of\n"
+"         the other's. Thus, a principal of 0 subsumes nothing, while a\n"
+"         principals of ~0 subsumes all other principals. The absence of a\n"
+"         principal is treated as if its bits were 0xffff, for subsumption\n"
+"         purposes. If this property is omitted, supply no principal."),
 
     JS_FN_HELP("enableStackWalkingAssertion", EnableStackWalkingAssertion, 1, 0,
 "enableStackWalkingAssertion(enabled)",
 "  Enables or disables a particularly expensive assertion in stack-walking\n"
 "  code.  If your test isn't ridiculously thorough, such that performing this\n"
 "  assertion increases test duration by an order of magnitude, you shouldn't\n"
 "  use this."),
 
@@ -5515,19 +5592,20 @@ DestroyContext(JSContext *cx, bool withG
 {
     JSShellContextData *data = GetContextData(cx);
     JS_SetContextPrivate(cx, nullptr);
     free(data);
     WITH_SIGNALS_DISABLED(withGC ? JS_DestroyContext(cx) : JS_DestroyContextNoGC(cx));
 }
 
 static JSObject *
-NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options)
-{
-    RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, nullptr,
+NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options,
+                JSPrincipals *principals)
+{
+    RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, principals,
                                              JS::DontFireOnNewGlobalHook, options));
     if (!glob)
         return nullptr;
 
     {
         JSAutoCompartment ac(cx, glob);
 
 #ifndef LAZY_STANDARD_CLASSES
@@ -5844,17 +5922,17 @@ Shell(JSContext *cx, OptionParser *op, c
     if (op->getBoolOption("fuzzing-safe"))
         fuzzingSafe = true;
     else
         fuzzingSafe = (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0');
 
     RootedObject glob(cx);
     JS::CompartmentOptions options;
     options.setVersion(JSVERSION_LATEST);
-    glob = NewGlobalObject(cx, options);
+    glob = NewGlobalObject(cx, options, nullptr);
     if (!glob)
         return 1;
 
     JSAutoCompartment ac(cx, glob);
     js::SetDefaultObjectForContext(cx, glob);
 
     JSObject *envobj = JS_DefineObject(cx, glob, "environment", &env_class, nullptr, 0);
     if (!envobj)
@@ -6098,21 +6176,20 @@ main(int argc, char **argv, char **envp)
     if (op.getBoolOption("no-ggc"))
         noggc.construct(rt);
 #endif
 
     size_t availMem = op.getIntOption("available-memory");
     if (availMem > 0)
         JS_SetGCParametersBasedOnAvailableMemory(rt, availMem);
 
-    /* Set the initial counter to 1 so the principal will never be destroyed. */
-    JSPrincipals shellTrustedPrincipals;
-    shellTrustedPrincipals.refcount = 1;
-
-    JS_SetTrustedPrincipals(rt, &shellTrustedPrincipals);
+    JS_SetTrustedPrincipals(rt, &ShellPrincipals::fullyTrusted);
+    JS_SetSecurityCallbacks(rt, &ShellPrincipals::securityCallbacks);
+    JS_InitDestroyPrincipalsCallback(rt, ShellPrincipals::destroy);
+
     JS_SetOperationCallback(rt, ShellOperationCallback);
     JS::SetAsmJSCacheOps(rt, &asmJSCacheOps);
 
     JS_SetNativeStackQuota(rt, gMaxStackSize);
 
 #ifdef JS_THREADSAFE
     if (!offThreadState.init())
         return 1;
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -290,8 +290,11 @@ pref(layout.css.text-align-true-value.en
 # stray control chars should not be invisible, bug 909344
 != control-chars-01a.html control-chars-01-notref.html
 != control-chars-01b.html control-chars-01-notref.html
 != control-chars-01c.html control-chars-01-notref.html
 != control-chars-01d.html control-chars-01-notref.html
 != control-chars-02.html control-chars-02-notref.html
 == control-chars-03a.html control-chars-03-ref.html
 == control-chars-03b.html control-chars-03-ref.html
+
+# font fallback for <space> when not supported in the primary font family - bug 970891
+HTTP(..) == space-font-1.html space-font-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/space-font-1-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 970891</title>
+  <style type="text/css">
+    @font-face {
+      font-family: "test";
+      src: url(../fonts/markA.ttf);
+    }
+    div {
+      font-family: test, monospace;
+      font-size: 16px;
+      line-height: 32px;
+    }
+    span {
+      font-family: monospace;
+    }
+  </style>
+</head>
+
+<body>
+  <div><b>A</b><span> </span><b>A</b><span> </span><i>A</i><span> </span><i>A</i></div>
+</body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/space-font-1.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 970891</title>
+  <style type="text/css">
+    @font-face {
+      font-family: "test";
+      src: url(../fonts/markA.ttf);
+    }
+    div {
+      font-family: test, monospace;
+      font-size: 16px;
+      line-height: 32px;
+    }
+    span {
+      font-family: monospace;
+    }
+  </style>
+</head>
+
+<body>
+  <!-- markA does not have a glyph for the <space> character,
+       so the spaces should fall back to 'monospace'. -->
+  <div><b>A</b> <b>A</b> <i>A</i> <i>A</i><span>&nbsp;</span></div>
+</body>
+
+</html>
--- a/python/mozbuild/mozbuild/backend/cpp_eclipse.py
+++ b/python/mozbuild/mozbuild/backend/cpp_eclipse.py
@@ -248,19 +248,17 @@ CPROJECT_TEMPLATE_FOOTER = """          
         </storageModule>
         <storageModule moduleId="scannerConfiguration">
                 <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
                 <scannerConfigBuildInfo instanceId="0.1674256904">
                         <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
                 </scannerConfigBuildInfo>
         </storageModule>
         <storageModule moduleId="refreshScope" versionNumber="2">
-                <configuration configurationName="Default">
-                        <resource resourceType="PROJECT" workspacePath="/Gecko"/>
-                </configuration>
+                <configuration configurationName="Default"/>
         </storageModule>
         <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
 </cproject>
 """
 
 WORKSPACE_LANGUAGE_SETTINGS_TEMPLATE = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <plugin>
         <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
@@ -293,16 +291,20 @@ LANGUAGE_SETTINGS_TEMPLATE = """<?xml ve
                                                   we need to make sure headers are parsed with MOZILLA_INTERNAL_API to make sure
                                                   the indexer gets the version that is used in most of the true. This means that
                                                   MOZILLA_EXTERNAL_API code will suffer.
                                                 -->
                                                 <entry kind="macro" name="MOZILLA_INTERNAL_API" value="1"/>
                                         </resource>
                                 </language>
                         </provider>
+                        <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-859273372804152468" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot; -std=c++11" prefer-non-shared="true" store-entries-with-project="true">
+                             <language-scope id="org.eclipse.cdt.core.gcc"/>
+                             <language-scope id="org.eclipse.cdt.core.g++"/>
+                        </provider>
                         <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
                 </extension>
         </configuration>
 </project>
 """
 
 LAUNCH_CONFIG_TEMPLATE = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType">
@@ -320,17 +322,17 @@ LAUNCH_CONFIG_TEMPLATE = """<?xml versio
 <intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="2"/>
 <stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_ID" value="gdb"/>
 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_START_MODE" value="run"/>
 <booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="false"/>
 <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/>
 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_ARGUMENTS" value="@LAUNCH_ARGS@"/>
 <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="@LAUNCH_PROGRAM@"/>
-<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="Gecko"/>
+<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="gecko"/>
 <booleanAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_AUTO_ATTR" value="true"/>
 <stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value=""/>
 <booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/>
 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
 <listEntry value="/gecko"/>
 </listAttribute>
 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
 <listEntry value="4"/>