Merge from tracemonkey.
authorDavid Anderson <danderson@mozilla.com>
Fri, 03 Sep 2010 17:27:07 -0700
changeset 74536 e9c0f9eb7d3ea08d510d456387bc375e225897ac
parent 74535 621a97f3779660793dddaca4dff43d082ee70b1a (current diff)
parent 53579 802d34381fe4b0813b3dc39625fe1be79e07aa1c (diff)
child 74537 40fe2614ef8e7a70f3f539cfa094bb4e4a39f1da
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone2.0b6pre
Merge from tracemonkey.
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -50,16 +50,17 @@
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsIChromeRegistry.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "mozilla/Services.h"
+#include "xpcpublic.h"
  
 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 // An XBLDocumentInfo object has a special context associated with it which we can use to pre-compile 
 // properties and methods of XBL bindings against.
 class nsXBLDocGlobalObject : public nsIScriptGlobalObject,
                              public nsIScriptObjectPrincipal
 {
@@ -319,19 +320,25 @@ nsXBLDocGlobalObject::EnsureScriptEnviro
 
   JSContext *cx = (JSContext *)mScriptContext->GetNativeContext();
   JSAutoRequest ar(cx);
 
   // nsJSEnvironment set the error reporter to NS_ScriptErrorReporter so
   // we must apparently override that with our own (although it isn't clear 
   // why - see bug 339647)
   JS_SetErrorReporter(cx, XBL_ProtoErrorReporter);
-  mJSObject = ::JS_NewGlobalObject(cx, &gSharedGlobalClass);
-  if (!mJSObject)
-    return nsnull;
+
+  nsIPrincipal *principal = GetPrincipal();
+  nsCString origin;
+  JSCompartment *compartment;
+
+  principal->GetOrigin(getter_Copies(origin));
+  rv = xpc_CreateGlobalObject(cx, &gSharedGlobalClass, origin, principal,
+                              &mJSObject, &compartment);
+  NS_ENSURE_SUCCESS(rv, nsnull);
 
   ::JS_SetGlobalObject(cx, mJSObject);
 
   // Add an owning reference from JS back to us. This'll be
   // released when the JSObject is finalized.
   ::JS_SetPrivate(cx, mJSObject, this);
   NS_ADDREF(this);
   return NS_OK;
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -60,16 +60,17 @@
 #include "nsIScriptError.h"
 #include "mozilla/FunctionTimer.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsDOMCID.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
+#include "xpcpublic.h"
 
 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
                      NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 
 class nsXULPDGlobalObject : public nsIScriptGlobalObject,
                             public nsIScriptObjectPrincipal
 {
@@ -724,19 +725,26 @@ nsXULPDGlobalObject::EnsureScriptEnviron
     rv = languageRuntime->CreateContext(getter_AddRefs(ctxNew));
     // For JS, we have to setup a special global object.  We do this then
     // attach it as the global for this context.  Then, ::SetScriptContext
     // will re-fetch the global and set it up in our language globals array.
     if (lang_id == nsIProgrammingLanguage::JAVASCRIPT) {
       // some special JS specific code we should abstract
       JSContext *cx = (JSContext *)ctxNew->GetNativeContext();
       JSAutoRequest ar(cx);
-      JSObject *newGlob = ::JS_NewGlobalObject(cx, &gSharedGlobalClass);
-      if (!newGlob)
-        return nsnull;
+
+      nsIPrincipal *principal = GetPrincipal();
+      nsCString origin;
+      JSObject *newGlob;
+      JSCompartment *compartment;
+
+      principal->GetOrigin(getter_Copies(origin));
+      rv = xpc_CreateGlobalObject(cx, &gSharedGlobalClass, origin, principal,
+                                  &newGlob, &compartment);
+      NS_ENSURE_SUCCESS(rv, nsnull);
 
       ::JS_SetGlobalObject(cx, newGlob);
 
       // Add an owning reference from JS back to us. This'll be
       // released when the JSObject is finalized.
       ::JS_SetPrivate(cx, newGlob, this);
       NS_ADDREF(this);
     }
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1087,16 +1087,19 @@ struct JSThreadData {
     JSGSNCache          gsnCache;
 
     /* Property cache for faster call/get/set invocation. */
     js::PropertyCache   propertyCache;
 
 #ifdef JS_TRACER
     /* Trace-tree JIT recorder/interpreter state. */
     js::TraceMonitor    traceMonitor;
+
+    /* Counts the number of iterations run by a trace. */
+    unsigned            iterationCounter;
 #endif
 
 #ifdef JS_METHODJIT
     js::mjit::ThreadData jmData;
 #endif
 
     /* Lock-free hashed lists of scripts created by eval to garbage-collect. */
     JSScript            *scriptsToGC[JS_EVAL_CACHE_SIZE];
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1124,17 +1124,17 @@ obj_eval(JSContext *cx, uintN argc, Valu
 
     JSObject *callee = &vp[0].toObject();
     JSPrincipals *principals = js_EvalFramePrincipals(cx, callee, caller);
     uintN line;
     const char *file = js_ComputeFilename(cx, caller, principals, &line);
 
     JSString *str = argv[0].toString();
     JSScript *script = NULL;
-    
+
     const jschar *chars;
     size_t length;
     str->getCharsAndLength(chars, length);
 
     /*
      * If the eval string starts with '(' and ends with ')', it may be JSON.
      * Try the JSON parser first because it's much faster.  If the eval string
      * isn't JSON, JSON parsing will probably fail quickly, so little time
@@ -5058,16 +5058,34 @@ js_SetPropertyHelper(JSContext *cx, JSOb
             }
 
             /*
              * Forget we found the proto-property now that we've copied any
              * needed member values.
              */
             shape = NULL;
         }
+
+        if (shape) {
+            if (shape->isMethod()) {
+                JS_ASSERT(pobj->hasMethodBarrier());
+            } else if ((defineHow & JSDNP_SET_METHOD) && obj->canHaveMethodBarrier()) {
+                JS_ASSERT(IsFunctionObject(*vp));
+                JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
+
+                JSObject *funobj = &vp->toObject();
+                JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
+                if (fun == funobj) {
+                    funobj = CloneFunctionObject(cx, fun, fun->parent);
+                    if (!funobj)
+                        return JS_FALSE;
+                    vp->setObject(*funobj);
+                }
+            }
+        }
     }
 
     added = false;
     if (!shape) {
         /*
          * Purge the property cache of now-shadowed id in obj's scope chain.
          * Do this early, before locking obj to avoid nesting locks.
          */
@@ -6053,25 +6071,27 @@ JSObject::getCompartment(JSContext *cx)
     Class *clasp = obj->getClass();
     if (!(clasp->flags & JSCLASS_IS_GLOBAL)) {
         // The magic AnyName object is runtime-wide.
         if (clasp == &js_AnyNameClass)
             return cx->runtime->defaultCompartment;
 
         // The magic function namespace object is runtime-wide.
         if (clasp == &js_NamespaceClass &&
-            obj->getNameURI() == ATOM_TO_JSVAL(cx->runtime->atomState.lazy.functionNamespaceURIAtom)) {
+            obj->getNameURI() == ATOM_TO_JSVAL(cx->runtime->
+                                               atomState.lazy.functionNamespaceURIAtom)) {
             return cx->runtime->defaultCompartment;
         }
 
-        /* 
+        /*
          * Script objects and compile-time Function, Block, RegExp objects
          * are not parented.
          */
-        if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass || clasp == &js_ScriptClass) {
+        if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass ||
+            clasp == &js_ScriptClass) {
             // This is a bogus answer, but it'll do for now.
             return cx->runtime->defaultCompartment;
         }
         JS_NOT_REACHED("non-global object at end of scope chain");
     }
     const Value &v = obj->getReservedSlot(JSRESERVED_GLOBAL_COMPARTMENT);
     return (JSCompartment *)v.toPrivate();
 }
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -298,18 +298,18 @@ ValueToTypeChar(const Value &v)
 #define HOTLOOP 4
 
 /* Attempt recording this many times before blacklisting permanently. */
 #define BL_ATTEMPTS 2
 
 /* Skip this many hits before attempting recording again, after an aborted attempt. */
 #define BL_BACKOFF 32
 
-/* Number of times a loop can execute before it becomes blacklisted. */
-#define MAX_LOOP_EXECS 300
+/* Minimum number of times a loop must execute, or else it is blacklisted. */
+#define MIN_LOOP_ITERS 2
 
 /* Number of times we wait to exit on a side exit before we try to extend the tree. */
 #define HOTEXIT 1
 
 /* Number of times we try to extend the tree along a side exit. */
 #define MAXEXIT 3
 
 /* Maximum number of peer trees allowed. */
@@ -2397,16 +2397,31 @@ TraceRecorder::TraceRecorder(JSContext* 
         /*
          * We poll the operation callback request flag. It is updated asynchronously whenever
          * the callback is to be invoked. We can use INS_CONSTPTR here as JIT-ed code is per
          * thread and cannot outlive the corresponding JSThreadData.
          */
         LIns* flagptr = INS_CONSTPTR((void *) &JS_THREAD_DATA(cx)->interruptFlags);
         LIns* x = lir->insLoad(LIR_ldi, flagptr, 0, ACCSET_OTHER, LOAD_VOLATILE);
         guard(true, lir->insEqI_0(x), snapshot(TIMEOUT_EXIT));
+
+        /*
+         * Count the number of iterations run by a trace, so that we can blacklist if
+         * the trace runs too few iterations to be worthwhile. Do this only if the methodjit
+         * is on--otherwise we must try to trace as much as possible.
+         */
+        if (JS_HAS_OPTION(cx, JSOPTION_METHODJIT)) {
+            LIns* counterPtr = INS_CONSTPTR((void *) &JS_THREAD_DATA(cx)->iterationCounter);
+            LIns* counterValue = lir->insLoad(LIR_ldi, counterPtr, 0, ACCSET_OTHER, LOAD_VOLATILE);
+            LIns* test =  lir->ins2ImmI(LIR_lti, counterValue, MIN_LOOP_ITERS);
+            LIns *branch = lir->insBranch(LIR_jf, test, NULL);
+            counterValue = lir->ins2(LIR_addi, counterValue, INS_CONST(1));
+            lir->insStore(counterValue, counterPtr, 0, ACCSET_OTHER);
+            branch->setTarget(lir->ins0(LIR_label));
+        }
     }
 
     /*
      * If we are attached to a tree call guard, make sure the guard the inner
      * tree exited from is what we expect it to be.
      */
     if (anchor && anchor->exitType == NESTED_EXIT) {
         LIns* nested_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state,
@@ -5514,16 +5529,20 @@ CheckGlobalObjectShape(JSContext* cx, Tr
         JS_LOCK_OBJ(cx, globalObj);
         bool ok = globalObj->globalObjectOwnShapeChange(cx);
         JS_UNLOCK_OBJ(cx, globalObj);
         if (!ok) {
             debug_only_print0(LC_TMTracer,
                               "Can't record: failed to give globalObj a unique shape.\n");
             return false;
         }
+    } else {
+        /* Claim the title so we don't abort at the top of recordLoopEdge. */
+        JS_LOCK_OBJ(cx, globalObj);
+        JS_UNLOCK_OBJ(cx, globalObj);
     }
 
     uint32 globalShape = globalObj->shape();
 
     if (tm->recorder) {
         TreeFragment* root = tm->recorder->getFragment()->root;
 
         /* Check the global shape matches the recorder's treeinfo's shape. */
@@ -6024,16 +6043,17 @@ RecordingIfTrue(bool b)
 /*
  * A postcondition of recordLoopEdge is that if recordLoopEdge does not return
  * MONITOR_RECORDING, the recording has been aborted.
  */
 JS_REQUIRES_STACK MonitorResult
 TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount)
 {
 #ifdef JS_THREADSAFE
+    /* If changing this, see "Claim the title" in CheckGlobalObjectShape. */
     if (cx->fp()->getScopeChain()->getGlobal()->title.ownercx != cx) {
         AbortRecording(cx, "Global object not owned by this context");
         return MONITOR_NOT_RECORDING; /* we stay away from shared global objects */
     }
 #endif
 
     TraceMonitor* tm = &JS_TRACE_MONITOR(cx);
 
@@ -6180,77 +6200,45 @@ TraceRecorder::attemptTreeCall(TreeFragm
         AbortRecording(cx, "Inner tree not suitable for calling");
         return ARECORD_ABORTED;
     }
 }
 
 static inline bool
 IsEntryTypeCompatible(const Value &v, JSValueType type)
 {
-#ifdef DEBUG
-    char tag = ValueToTypeChar(v);
-    debug_only_printf(LC_TMTracer, "%c/%c ", tag, TypeToChar(type));
-#endif
+    bool ok;
 
     JS_ASSERT(type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET);
-    switch (type) {
-      case JSVAL_TYPE_DOUBLE:
-        if (v.isNumber())
-            return true;
-        debug_only_printf(LC_TMTracer, "double != tag%c ", tag);
-        break;
-      case JSVAL_TYPE_INT32: {
+    JS_ASSERT(type != JSVAL_TYPE_OBJECT);   /* JSVAL_TYPE_OBJECT does not belong in a type map */
+
+    if (v.isInt32()) {
+        ok = (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_DOUBLE);
+
+    } else if (v.isDouble()) {
         int32_t _;
-        if (v.isInt32() || (v.isDouble() && JSDOUBLE_IS_INT32(v.toDouble(), &_)))
-            return true;
-        debug_only_printf(LC_TMTracer, "int != tag%c ", tag);
-        break;
-      }
-      case JSVAL_TYPE_UNDEFINED:
-        if (v.isUndefined())
-            return true;
-        debug_only_printf(LC_TMTracer, "undefined != tag%c ", tag);
-        break;
-      case JSVAL_TYPE_BOOLEAN:
-        if (v.isBoolean())
-            return true;
-        debug_only_printf(LC_TMTracer, "bool != tag%c ", tag);
-        break;
-      case JSVAL_TYPE_MAGIC:
-        if (v.isMagic())
-            return true;
-        debug_only_printf(LC_TMTracer, "magic != tag%c ", tag);
-        break;
-      case JSVAL_TYPE_STRING:
-        if (v.isString())
-            return true;
-        debug_only_printf(LC_TMTracer, "string != tag%c ", tag);
-        break;
-      case JSVAL_TYPE_NULL:
-        if (v.isNull())
-            return true;
-        debug_only_printf(LC_TMTracer, "null != tag%c ", tag);
-        break;
-      case JSVAL_TYPE_OBJECT:
-        JS_NOT_REACHED("JSVAL_TYPE_OBJECT does not belong in a type map");
-        break;
-      case JSVAL_TYPE_NONFUNOBJ:
-        if (v.isObject() && !v.toObject().isFunction())
-            return true;
-        debug_only_printf(LC_TMTracer, "object != tag%c ", tag);
-        break;
-      case JSVAL_TYPE_FUNOBJ:
-        if (v.isObject() && v.toObject().isFunction())
-            return true;
-        debug_only_printf(LC_TMTracer, "fun != tag%c ", tag);
-        break;
-      default:
-        JS_NOT_REACHED("unexpected type");
-    }
-    return false;
+        ok = (type == JSVAL_TYPE_DOUBLE) || 
+             (type == JSVAL_TYPE_INT32 && JSDOUBLE_IS_INT32(v.toDouble(), &_));
+
+    } else if (v.isObject()) {
+        ok = v.toObject().isFunction()
+           ? type == JSVAL_TYPE_FUNOBJ
+           : type == JSVAL_TYPE_NONFUNOBJ;
+
+    } else {
+        ok = v.extractNonDoubleObjectTraceType() == type;
+    }
+#ifdef DEBUG
+    char ttag = TypeToChar(type);
+    char vtag = ValueToTypeChar(v);
+    debug_only_printf(LC_TMTracer, "%c/%c ", vtag, ttag);
+    if (!ok)
+        debug_only_printf(LC_TMTracer, "%s", "(incompatible types)");
+#endif
+    return ok;
 }
 
 class TypeCompatibilityVisitor : public SlotVisitorBase
 {
     TraceRecorder &mRecorder;
     JSContext *mCx;
     Oracle *mOracle;
     JSValueType *mTypeMap;
@@ -6616,31 +6604,40 @@ ExecuteTree(JSContext* cx, TreeFragment*
                       FramePCOffset(cx, cx->fp()),
            f->execs,
            f->code());
 
     debug_only_stmt(uint32 globalSlots = globalObj->numSlots();)
     debug_only_stmt(*(uint64*)&tm->storage->global()[globalSlots] = 0xdeadbeefdeadbeefLL;)
 
     /* Execute trace. */
+    JS_THREAD_DATA(cx)->iterationCounter = 0;
 #ifdef MOZ_TRACEVIS
     VMSideExit* lr = (TraceVisStateObj(cx, S_NATIVE), ExecuteTrace(cx, f, state));
 #else
     VMSideExit* lr = ExecuteTrace(cx, f, state);
 #endif
 
     JS_ASSERT(*(uint64*)&tm->storage->global()[globalSlots] == 0xdeadbeefdeadbeefLL);
     JS_ASSERT_IF(lr->exitType == LOOP_EXIT, !lr->calldepth);
 
     /* Restore interpreter state. */
     LeaveTree(tm, state, lr);
 
     *lrp = state.innermost;
     bool ok = !(state.builtinStatus & BUILTIN_ERROR);
     JS_ASSERT_IF(cx->throwing, !ok);
+
+    if (JS_HAS_OPTION(cx, JSOPTION_METHODJIT)) {
+        if (lr->exitType == LOOP_EXIT && JS_THREAD_DATA(cx)->iterationCounter < MIN_LOOP_ITERS) {
+            debug_only_printf(LC_TMTracer, "tree %p executed only %d iterations, blacklisting\n",
+                              (void*)f, f->execs);
+            Blacklist((jsbytecode *)f->ip);
+        }
+    }
     return ok;
 }
 
 class Guardian {
     bool *flagp;
 public:
     Guardian(bool *flagp) {
         this->flagp = flagp;
@@ -6964,29 +6961,16 @@ LeaveTree(TraceMonitor *tm, TracerState&
         AUDIT(sideExitIntoInterpreter);
     else
         AUDIT(timeoutIntoInterpreter);
 #endif
 
     state.innermost = innermost;
 }
 
-static bool
-ApplyBlacklistHeuristics(JSContext *cx, TreeFragment *tree)
-{
-    if (tree->execs >= MAX_LOOP_EXECS) {
-        debug_only_printf(LC_TMTracer, "tree %p executed %d times, blacklisting\n",
-                          (void*)tree, tree->execs);
-        Blacklist((jsbytecode *)tree->ip);
-        return false;
-    }
-    tree->execs++;
-    return true;
-}
-
 JS_REQUIRES_STACK MonitorResult
 MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
 {
 #ifdef MOZ_TRACEVIS
     TraceVisStateObj tvso(cx, S_MONITOR);
 #endif
 
     TraceMonitor* tm = &JS_TRACE_MONITOR(cx);
@@ -7104,19 +7088,16 @@ MonitorLoopEdge(JSContext* cx, uintN& in
         tvso.r = R_MAX_PEERS;
 #endif
         return MONITOR_NOT_RECORDING;
     }
 
     VMSideExit* lr = NULL;
     VMSideExit* innermostNestedGuard = NULL;
 
-    if (!ApplyBlacklistHeuristics(cx, match))
-        return MONITOR_NOT_RECORDING;
-
     if (!ExecuteTree(cx, match, inlineCallCount, &innermostNestedGuard, &lr))
         return MONITOR_ERROR;
 
     if (!lr) {
 #ifdef MOZ_TRACEVIS
         tvso.r = R_FAIL_EXECUTE_TREE;
 #endif
         return MONITOR_NOT_RECORDING;
@@ -16164,19 +16145,16 @@ MonitorTracePoint(JSContext* cx, uintN& 
 
     if (tree->code() || tree->peer) {
         uintN count;
         TreeFragment* match = FindVMCompatiblePeer(cx, globalObj, tree, count);
         if (match) {
             VMSideExit* lr = NULL;
             VMSideExit* innermostNestedGuard = NULL;
 
-            if (!ApplyBlacklistHeuristics(cx, match))
-                return TPA_Nothing;
-
             /* Best case - just go and execute. */
             if (!ExecuteTree(cx, match, inlineCallCount, &innermostNestedGuard, &lr))
                 return TPA_Error;
 
             if (!lr)
                 return TPA_Nothing;
 
             switch (lr->exitType) {
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/basic/testExistingPropToJoinedMethodAttempt.js
@@ -0,0 +1,17 @@
+function f() {
+  var a = [{m: 0}, {m: 1}, {m: 2}, {m: 3}, {m: 4}];
+  var b = [{}, {}, {}, {}, {}];
+  for (var i = 0; i < a.length; i++) {
+    a[i].m = function() { return 0; };
+    b[i].m = function() { return 1; };
+  }
+  assertEq(false, a[0].m === a[1].m);
+  assertEq(false, a[0].m === a[2].m);
+  assertEq(false, a[0].m === a[3].m);
+  assertEq(false, a[0].m === a[4].m);
+  assertEq(false, b[0].m === b[1].m);
+  assertEq(false, b[0].m === b[2].m);
+  assertEq(false, b[0].m === b[3].m);
+  assertEq(false, b[0].m === b[4].m);
+}
+f();
--- a/js/src/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.h
@@ -169,16 +169,17 @@ class mozJSComponentLoader : public mozi
             Clear();
         }
 
         void Clear() {
             getfactoryobj = NULL;
 
             if (global) {
                 JSAutoRequest ar(sSelf->mContext);
+                JSAutoEnterCompartment ac(sSelf->mContext, global);
                 JS_ClearScope(sSelf->mContext, global);
                 JS_RemoveObjectRoot(sSelf->mContext, &global);
             }
 
             if (location)
                 NS_Free(location);
 
             global = NULL;
--- a/js/src/xpconnect/src/Makefile.in
+++ b/js/src/xpconnect/src/Makefile.in
@@ -57,16 +57,17 @@ ifeq ($(OS_ARCH)$(MOZ_ENABLE_LIBXUL),WIN
 LIBRARY_NAME	= xpc32$(VERSION_NUMBER)
 SHORT_LIBNAME	= xpc32$(VERSION_NUMBER)
 endif
 else
 LIBRARY_NAME    = xpconnect_s
 FORCE_STATIC_LIB = 1
 endif
 LIBXUL_LIBRARY = 1
+EXPORTS = xpcpublic.h
 
 CPPSRCS		= \
 		nsScriptError.cpp \
 		nsXPConnect.cpp \
 		xpccallcontext.cpp \
 		xpccomponents.cpp \
 		xpccontext.cpp \
 		xpcconvert.cpp \
--- a/js/src/xpconnect/src/xpcinlines.h
+++ b/js/src/xpconnect/src/xpcinlines.h
@@ -408,24 +408,16 @@ XPCNativeInterface::FindMember(jsid name
 inline JSBool
 XPCNativeInterface::HasAncestor(const nsIID* iid) const
 {
     PRBool found = PR_FALSE;
     mInfo->HasAncestor(iid, &found);
     return found;
 }
 
-inline void
-XPCNativeInterface::DealWithDyingGCThings(JSContext* cx, XPCJSRuntime* rt)
-{
-    XPCNativeMember* member = mMembers;
-    for(int i = (int) mMemberCount; i > 0; i--, member++)
-        member->DealWithDyingGCThings(cx, rt);
-}
-
 /***************************************************************************/
 
 inline JSBool
 XPCNativeSet::FindMember(jsid name, XPCNativeMember** pMember,
                          PRUint16* pInterfaceIndex) const
 {
     XPCNativeInterface* const * iface;
     int count = (int) mInterfaceCount;
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -101,26 +101,16 @@ WrappedJSDyingJSObjectFinder(JSDHashTabl
 
 struct CX_AND_XPCRT_Data
 {
     JSContext* cx;
     XPCJSRuntime* rt;
 };
 
 static JSDHashOperator
-NativeInterfaceGC(JSDHashTable *table, JSDHashEntryHdr *hdr,
-                  uint32 number, void *arg)
-{
-    CX_AND_XPCRT_Data* data = (CX_AND_XPCRT_Data*) arg;
-    ((IID2NativeInterfaceMap::Entry*)hdr)->value->
-            DealWithDyingGCThings(data->cx, data->rt);
-    return JS_DHASH_NEXT;
-}
-
-static JSDHashOperator
 NativeInterfaceSweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
                        uint32 number, void *arg)
 {
     XPCNativeInterface* iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
     if(iface->IsMarked())
     {
         iface->Unmark();
         return JS_DHASH_NEXT;
@@ -530,25 +520,16 @@ JSBool XPCJSRuntime::GCCallback(JSContex
                     // refcount of these wrappers.
                     // We add them to the array now and Release the array members
                     // later to avoid the posibility of doing any JS GCThing
                     // allocations during the gc cycle.
                     self->mWrappedJSMap->
                         Enumerate(WrappedJSDyingJSObjectFinder, &data);
                 }
 
-                // Do cleanup in NativeInterfaces. This part just finds 
-                // member cloned function objects that are about to be 
-                // collected. It does not deal with collection of interfaces or
-                // sets at this point.
-                CX_AND_XPCRT_Data data = {cx, self};
-
-                self->mIID2NativeInterfaceMap->
-                    Enumerate(NativeInterfaceGC, &data);
-
                 // Find dying scopes...
                 XPCWrappedNativeScope::FinishedMarkPhaseOfGC(cx, self);
 
                 self->mDoingFinalization = JS_TRUE;
                 break;
             }
             case JSGC_FINALIZE_END:
             {
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -1590,18 +1590,17 @@ public:
     jsid   GetName() const {return mName;}
 
     PRUint16 GetIndex() const {return mIndex;}
 
     JSBool GetConstantValue(XPCCallContext& ccx, XPCNativeInterface* iface,
                             jsval* pval)
         {NS_ASSERTION(IsConstant(),
                       "Only call this if you're sure this is a constant!");
-         if(!IsResolved() && !Resolve(ccx, iface)) return JS_FALSE;
-         *pval = mVal; return JS_TRUE;}
+         return Resolve(ccx, iface, nsnull, pval);}
 
     JSBool NewFunctionObject(XPCCallContext& ccx, XPCNativeInterface* iface,
                              JSObject *parent, jsval* pval);
 
     JSBool IsMethod() const
         {return 0 != (mFlags & METHOD);}
 
     JSBool IsConstant() const
@@ -1615,52 +1614,45 @@ public:
 
     JSBool IsReadOnlyAttribute() const
         {return IsAttribute() && !IsWritableAttribute();}
 
 
     void SetName(jsid a) {mName = a;}
 
     void SetMethod(PRUint16 index)
-        {mVal = JSVAL_NULL; mFlags = METHOD; mIndex = index;}
+        {mFlags = METHOD; mIndex = index;}
 
     void SetConstant(PRUint16 index)
-        {mVal = JSVAL_NULL; mFlags = CONSTANT; mIndex = index;}
+        {mFlags = CONSTANT; mIndex = index;}
 
     void SetReadOnlyAttribute(PRUint16 index)
-        {mVal = JSVAL_NULL; mFlags = GETTER; mIndex = index;}
+        {mFlags = GETTER; mIndex = index;}
 
     void SetWritableAttribute()
         {NS_ASSERTION(mFlags == GETTER,"bad"); mFlags = GETTER | SETTER_TOO;}
 
     /* default ctor - leave random contents */
     XPCNativeMember()  {MOZ_COUNT_CTOR(XPCNativeMember);}
     ~XPCNativeMember() {MOZ_COUNT_DTOR(XPCNativeMember);}
 
-    void DealWithDyingGCThings(JSContext* cx, XPCJSRuntime* rt)
-        {if(IsResolved() && JSVAL_IS_GCTHING(mVal) &&
-           JS_IsAboutToBeFinalized(cx, JSVAL_TO_GCTHING(mVal)))
-           {mVal = JSVAL_NULL; mFlags &= ~RESOLVED;}}
-
 private:
-    JSBool IsResolved() const {return mFlags & RESOLVED;}
-    JSBool Resolve(XPCCallContext& ccx, XPCNativeInterface* iface);
+    JSBool Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
+                   JSObject *parent, jsval *vp);
 
     enum {
-        RESOLVED    = 0x01,
-        METHOD      = 0x02,
-        CONSTANT    = 0x04,
-        GETTER      = 0x08,
-        SETTER_TOO  = 0x10
+        METHOD      = 0x01,
+        CONSTANT    = 0x02,
+        GETTER      = 0x04,
+        SETTER_TOO  = 0x08
     };
 
 private:
     // our only data...
     jsid     mName;
-    jsval    mVal;
     PRUint16 mIndex;
     PRUint16 mFlags;
 };
 
 /***************************************************************************/
 // XPCNativeInterface represents a single idl declared interface. This is
 // primarily the set of XPCNativeMembers.
 
@@ -1689,18 +1681,16 @@ public:
     const char* GetMemberName(XPCCallContext& ccx,
                               const XPCNativeMember* member) const;
 
     PRUint16 GetMemberCount() const
         {NS_ASSERTION(!IsMarked(), "bad"); return mMemberCount;}
     XPCNativeMember* GetMemberAt(PRUint16 i)
         {NS_ASSERTION(i < mMemberCount, "bad index"); return &mMembers[i];}
 
-    inline void DealWithDyingGCThings(JSContext* cx, XPCJSRuntime* rt);
-
     void DebugDump(PRInt16 depth);
 
 #define XPC_NATIVE_IFACE_MARK_FLAG ((PRUint16)JS_BIT(15)) // only high bit of 16 is set
 
     void Mark()     {mMemberCount |= XPC_NATIVE_IFACE_MARK_FLAG;}
     void Unmark()   {mMemberCount &= ~XPC_NATIVE_IFACE_MARK_FLAG;}
     JSBool IsMarked() const
                     {return 0 != (mMemberCount & XPC_NATIVE_IFACE_MARK_FLAG);}
new file mode 100644
--- /dev/null
+++ b/js/src/xpconnect/src/xpcpublic.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=78:
+ *
+ * ***** 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 XPConnect  code, released
+ * June 30, 2009.
+ *
+ * The Initial Developer of the Original Code is
+ *    The Mozilla Foundation
+ *
+ * Contributor(s):
+ *    Andreas Gal <gal@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef xpcpublic_h
+#define xpcpublic_h
+
+#include "jsapi.h"
+#include "nsAString.h"
+#include "nsIPrincipal.h"
+
+nsresult
+xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
+                       const nsACString &origin, nsIPrincipal *principal,
+                       JSObject **global, JSCompartment **compartment);
+
+#endif
--- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp
+++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp
@@ -242,16 +242,20 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
 {
     JSContext* cx = ccx.GetJSContext();
     JSObject* id;
     jsval retval;
     JSObject* retObj;
     JSBool success = JS_FALSE;
     jsid funid;
     jsval fun;
+    JSAutoCrossCompartmentCall accc;
+
+    if(!accc.enter(cx, jsobj))
+        return nsnull;
 
     // Don't call the actual function on a content object. We'll determine
     // whether or not a content object is capable of implementing the
     // interface (i.e. whether the interface is scriptable) and most content
     // objects don't have QI implementations anyway. Also see bug 503926.
     if(XPCPerThreadData::IsMainThread(ccx) &&
        !JS_GetGlobalForObject(ccx, jsobj)->isSystem())
     {
--- a/js/src/xpconnect/src/xpcwrappednativeinfo.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativeinfo.cpp
@@ -112,32 +112,23 @@ XPCNativeMember::GetCallInfo(XPCCallCont
 
 JSBool
 XPCNativeMember::NewFunctionObject(XPCCallContext& ccx,
                                    XPCNativeInterface* iface, JSObject *parent,
                                    jsval* pval)
 {
     NS_ASSERTION(!IsConstant(),
                  "Only call this if you're sure this is not a constant!");
-    if(!IsResolved() && !Resolve(ccx, iface))
-        return JS_FALSE;
 
-    AUTO_MARK_JSVAL(ccx, &mVal);
-    JSObject* funobj =
-        xpc_CloneJSFunction(ccx, JSVAL_TO_OBJECT(mVal), parent);
-    if(!funobj)
-        return JS_FALSE;
-
-    *pval = OBJECT_TO_JSVAL(funobj);
-
-    return JS_TRUE;
+    return Resolve(ccx, iface, parent, pval);
 }
 
 JSBool
-XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface)
+XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
+                         JSObject *parent, jsval *vp)
 {
     if(IsConstant())
     {
         const nsXPTConstant* constant;
         if(NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &constant)))
             return JS_FALSE;
 
         const nsXPTCMiniVariant& mv = *constant->GetValue();
@@ -149,21 +140,17 @@ XPCNativeMember::Resolve(XPCCallContext&
         memcpy(&v.val, &mv.val, sizeof(mv.val));
 
         jsval resultVal;
 
         if(!XPCConvert::NativeData2JS(ccx, &resultVal, &v.val, v.type,
                                       nsnull, nsnull, nsnull))
             return JS_FALSE;
 
-        {   // scoped lock
-            XPCAutoLock lock(ccx.GetRuntime()->GetMapLock());
-            mVal = resultVal;
-            mFlags |= RESOLVED;
-        }
+        *vp = resultVal;
 
         return JS_TRUE;
     }
     // else...
 
     // This is a method or attribute - we'll be needing a function object
 
     intN argc;
@@ -183,54 +170,31 @@ XPCNativeMember::Resolve(XPCCallContext&
         callback = XPC_WN_CallMethod;
     }
     else
     {
         argc = 0;
         callback = XPC_WN_GetterSetter;
     }
 
-    // We need to use the safe context for this thread because we don't want
-    // to parent the new (and cached forever!) function object to the current
-    // JSContext's global object. That would be bad!
-
-    JSContext* cx = ccx.GetSafeJSContext();
-    if(!cx)
-        return JS_FALSE;
-
     const char *memberName = iface->GetMemberName(ccx, this);
 
-    JSFunction *fun;
-    // Switching contexts, suspend the old and enter the new request.
-    {
-        JSAutoRequest req(cx);
-        fun = JS_NewFunction(cx, callback, argc, 0, nsnull, memberName);
-    }
-
+    JSFunction *fun = JS_NewFunction(ccx, callback, argc, 0, parent, memberName);
     if(!fun)
         return JS_FALSE;
 
     JSObject* funobj = JS_GetFunctionObject(fun);
     if(!funobj)
         return JS_FALSE;
 
-    AUTO_MARK_JSVAL(ccx, OBJECT_TO_JSVAL(funobj));
-
-    funobj->clearParent();
-    funobj->clearProto();
-
     if(!JS_SetReservedSlot(ccx, funobj, 0, PRIVATE_TO_JSVAL(iface))||
        !JS_SetReservedSlot(ccx, funobj, 1, PRIVATE_TO_JSVAL(this)))
         return JS_FALSE;
 
-    {   // scoped lock
-        XPCAutoLock lock(ccx.GetRuntime()->GetMapLock());
-        mVal = OBJECT_TO_JSVAL(funobj);
-        mFlags |= RESOLVED;
-    }
+    *vp = OBJECT_TO_JSVAL(funobj);
 
     return JS_TRUE;
 }
 
 /***************************************************************************/
 // XPCNativeInterface
 
 // static