[INFER] Unwind getProto() changes outside of JS, fix test failures, bug 619271.
authorBrian Hackett <bhackett1024@gmail.com>
Sun, 19 Dec 2010 12:21:15 -0800
changeset 74670 0a97e6a40d5cc6fe5ba4592996068d43966d80df
parent 74669 2e3b66a758d3745ec0751014358edd6bc161891e
child 74671 15b2220f3ea981c3ecabac354e1de6babc3a7245
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs619271
milestone2.0b8pre
[INFER] Unwind getProto() changes outside of JS, fix test failures, bug 619271.
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
js/ipc/ObjectWrapperParent.cpp
js/jetpack/Handle.h
js/src/jsapi-tests/testBug604087.cpp
js/src/jsarray.cpp
js/src/jsfun.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsregexpinlines.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/StubCalls.cpp
js/src/xpconnect/src/xpcdebug.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1637,24 +1637,24 @@ jsid nsDOMClassInfo::sOnafterscriptexecu
 jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID;
 
 static const JSClass *sObjectClass = nsnull;
 
 /**
  * Set our JSClass pointer for the Object class
  */
 static void
-FindObjectClass(JSContext *cx, JSObject* aGlobalObject)
+FindObjectClass(JSObject* aGlobalObject)
 {
   NS_ASSERTION(!sObjectClass,
                "Double set of sObjectClass");
   JSObject *obj, *proto = aGlobalObject;
   do {
     obj = proto;
-    proto = JS_GetPrototype(cx, obj);
+    proto = obj->getProto();
   } while (proto);
 
   sObjectClass = obj->getJSClass();
 }
 
 static void
 PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty)
 {
@@ -4656,17 +4656,17 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
                                        count, mData->mInterfaces)) {
     JS_ClearPendingException(cx);
   }
 
   // This is called before any other location that requires
   // sObjectClass, so compute it here. We assume that nobody has had a
   // chance to monkey around with proto's prototype chain before this.
   if (!sObjectClass) {
-    FindObjectClass(cx, proto);
+    FindObjectClass(proto);
     NS_ASSERTION(sObjectClass && !strcmp(sObjectClass->name, "Object"),
                  "Incorrect object class!");
   }
 
   NS_ASSERTION(::JS_GetPrototype(cx, proto) &&
                JS_GET_CLASS(cx, ::JS_GetPrototype(cx, proto)) == sObjectClass,
                "Hmm, somebody did something evil?");
 
@@ -6951,17 +6951,17 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
   // defined on our prototype chain. This way we can access this
   // expando w/o ever getting back into XPConnect.
   if ((flags & JSRESOLVE_ASSIGNING) && !(flags & JSRESOLVE_WITH) &&
       win->IsInnerWindow()) {
     JSObject *realObj;
     wrapper->GetJSObject(&realObj);
 
     if (obj == realObj) {
-      JSObject *proto = JS_GetPrototype(cx, obj);
+      JSObject *proto = obj->getProto();
       if (proto) {
         JSObject *pobj = NULL;
         jsval val;
 
         if (!::JS_LookupPropertyWithFlagsById(cx, proto, id, flags,
                                               &pobj, &val)) {
           *_retval = JS_FALSE;
 
@@ -8647,17 +8647,17 @@ nsHTMLDocumentSH::DocumentAllGetProperty
   // newResolve hook, so nothing to do for those properties here. And
   // we need to return early to prevent <div id="item"> from shadowing
   // document.all.item(), etc.
   if (id == sItem_id || id == sNamedItem_id) {
     return JS_TRUE;
   }
 
   while (obj->getJSClass() != &sHTMLDocumentAllClass) {
-    obj = JS_GetPrototype(cx, obj);
+    obj = obj->getProto();
 
     if (!obj) {
       NS_ERROR("The JS engine lies!");
 
       return JS_TRUE;
     }
   }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -766,17 +766,17 @@ nsOuterWindowProxy::singleton;
 JSObject *
 NS_NewOuterWindowProxy(JSContext *cx, JSObject *parent)
 {
   JSAutoEnterCompartment ac;
   if (!ac.enter(cx, parent)) {
     return nsnull;
   }
 
-  JSObject *obj = JSWrapper::New(cx, parent, JS_GetPrototype(cx, parent), parent,
+  JSObject *obj = JSWrapper::New(cx, parent, parent->getProto(), parent,
                                  &nsOuterWindowProxy::singleton);
   NS_ASSERTION(obj->getClass()->ext.innerObject, "bad class");
   return obj;
 }
 
 //*****************************************************************************
 //***    nsGlobalWindow: Object Management
 //*****************************************************************************
--- a/js/ipc/ObjectWrapperParent.cpp
+++ b/js/ipc/ObjectWrapperParent.cpp
@@ -223,17 +223,17 @@ ObjectWrapperParent::GetJSObject(JSConte
     }
     return mObj;
 }
 
 static ObjectWrapperParent*
 Unwrap(JSContext* cx, JSObject* obj)
 {
     while (obj->getClass() != &ObjectWrapperParent::sCPOW_JSClass)
-        if (!(obj = JS_GetPrototype(cx, obj)))
+        if (!(obj = obj->getProto()))
             return NULL;
     
     ObjectWrapperParent* self =
         static_cast<ObjectWrapperParent*>(JS_GetPrivate(cx, obj));
 
     NS_ASSERTION(!self || self->GetJSObject(cx) == obj,
                  "Wrapper and wrapped object disagree?");
     
--- a/js/jetpack/Handle.h
+++ b/js/jetpack/Handle.h
@@ -195,17 +195,17 @@ private:
   // otherwise a const method.
   JSObject*  mObj;
   JSContext* mCx;
   bool mRooted;
 
   static Handle*
   Unwrap(JSContext* cx, JSObject* obj) {
     while (obj && obj->getJSClass() != &sHandle_JSClass)
-      obj = JS_GetPrototype(cx, obj);
+      obj = obj->getProto();
 
     if (!obj)
       return NULL;
 
     Handle* self = static_cast<Handle*>(JS_GetPrivate(cx, obj));
 
     NS_ASSERTION(!self || self->ToJSObject(cx) == obj,
                  "Wrapper and wrapped object disagree?");
--- a/js/src/jsapi-tests/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -44,17 +44,17 @@ PreWrap(JSContext *cx, JSObject *scope, 
 static JSObject *
 Wrap(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, uintN flags)
 {
     return JSWrapper::New(cx, obj, proto, parent, &JSCrossCompartmentWrapper::singleton);
 }
 
 BEGIN_TEST(testBug604087)
 {
-    JSObject *outerObj = JSWrapper::New(cx, global, JS_GetPrototype(cx, global), global,
+    JSObject *outerObj = JSWrapper::New(cx, global, global->getProto(), global,
                                         &OuterWrapper::singleton);
     JSObject *compartment2 = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
     JSObject *compartment3 = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
     JSObject *compartment4 = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
 
     JSObject *c2wrapper = wrap(cx, outerObj, compartment2);
     CHECK(c2wrapper);
     c2wrapper->setProxyExtra(js::Int32Value(2));
@@ -67,17 +67,17 @@ BEGIN_TEST(testBug604087)
     CHECK(c4wrapper);
     c4wrapper->setProxyExtra(js::Int32Value(4));
     compartment4 = c4wrapper = NULL;
 
     JSObject *next;
     {
         JSAutoEnterCompartment ac;
         CHECK(ac.enter(cx, compartment2));
-        next = JSWrapper::New(cx, compartment2, JS_GetPrototype(cx, compartment2), compartment2,
+        next = JSWrapper::New(cx, compartment2, compartment2->getProto(), compartment2,
                               &OuterWrapper::singleton);
         CHECK(next);
     }
 
     JS_SetWrapObjectCallbacks(JS_GetRuntime(cx), Wrap, PreWrap);
     CHECK(JS_TransplantObject(cx, outerObj, next));
     return true;
 }
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2347,16 +2347,18 @@ array_splice(JSContext *cx, uintN argc, 
     if (obj && obj->isArray()) {
         type = obj->getType();
     } else {
         /*
          * Make a new type object for the return value.  This is an unexpected
          * result of the call so mark it at the callsite.
          */
         type = cx->getTypeCallerInitObject(true);
+        if (!type)
+            return JS_FALSE;
         cx->markTypeObjectUnknownProperties(type);
         cx->markTypeCallerUnexpected((jstype) type);
     }
 
     if (cx->isTypeCallerMonitored())
         cx->markTypeObjectUnknownProperties(type);
 
     /*
@@ -2547,16 +2549,18 @@ array_concat(JSContext *cx, uintN argc, 
         if (!nobj)
             return JS_FALSE;
         vp->setObject(*nobj);
         length = 0;
     }
 
     /* Get the type object to use for the result. */
     TypeObject *ntype = cx->getTypeCallerInitObject(true);
+    if (!ntype)
+        return JS_FALSE;
     if (cx->isTypeCallerMonitored())
         cx->markTypeObjectUnknownProperties(ntype);
 
     AutoValueRooter tvr(cx);
 
     /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
     for (uintN i = 0; i <= argc; i++) {
         if (!JS_CHECK_OPERATION_LIMIT(cx))
@@ -2660,16 +2664,18 @@ array_slice(JSContext *cx, uintN argc, V
     if (obj->isArray()) {
         type = obj->getType();
     } else {
         /*
          * Make a new type object for the return value.  This is an unexpected
          * result of the call so mark it at the callsite.
          */
         type = cx->getTypeCallerInitObject(true);
+        if (!type)
+            return JS_FALSE;
         cx->markTypeObjectUnknownProperties(type);
         cx->markTypeCallerUnexpected((jstype) type);
     }
 
     if (cx->isTypeCallerMonitored())
         cx->markTypeObjectUnknownProperties(type);
 
     if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
@@ -2863,16 +2869,18 @@ array_extra(JSContext *cx, ArrayExtraMod
         break;
       case MAP:
       case FILTER:
         newlen = (mode == MAP) ? length : 0;
         newarr = js_NewArrayObject(cx, newlen, NULL);
         if (!newarr)
             return JS_FALSE;
         newtype = cx->getTypeCallerInitObject(true);
+        if (!newtype)
+            return JS_FALSE;
         newarr->setType(newtype);
         vp->setObject(*newarr);
         break;
       case SOME:
         vp->setBoolean(false);
         break;
       case EVERY:
         vp->setBoolean(true);
@@ -3330,16 +3338,18 @@ NewDenseArrayObject(JSContext *cx, jsuin
 
 JSBool
 js_Array(JSContext *cx, uintN argc, Value *vp)
 {
     jsuint length;
     const Value *vector;
 
     TypeObject *type = cx->getTypeCallerInitObject(true);
+    if (!type)
+        return JS_FALSE;
 
     if (argc == 0) {
         length = 0;
         vector = NULL;
     } else if (argc > 1) {
         length = (jsuint) argc;
         vector = vp + 2;
     } else if (!vp[2].isNumber()) {
@@ -3627,13 +3637,12 @@ js_CloneDensePrimitiveArray(JSContext *c
         }
 
         vector.append(val);
     }
 
     *clone = js_NewArrayObject(cx, initlen, vector.begin());
     if (!*clone)
         return JS_FALSE;
-    (*clone)->setType(obj->getType());
     (*clone)->setArrayLength(cx, length);
 
     return JS_TRUE;
 }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -366,17 +366,18 @@ WrapEscapingClosure(JSContext *cx, JSSta
      */
     JSObject *scopeChain = GetScopeChain(cx, fp);
     if (!scopeChain)
         return NULL;
 
     JSObject *wfunobj = NewFunction(cx, scopeChain);
     if (!wfunobj)
         return NULL;
-    wfunobj->setType(fun->getType());
+    if (fun->getProto() == wfunobj->getProto())
+        wfunobj->setType(fun->getType());
     AutoObjectRooter tvr(cx, wfunobj);
 
     JSFunction *wfun = (JSFunction *) wfunobj;
     wfunobj->setPrivate(wfun);
     wfun->nargs = fun->nargs;
     wfun->flags = fun->flags | JSFUN_HEAVYWEIGHT;
     wfun->u.i.nvars = fun->u.i.nvars;
     wfun->u.i.nupvars = fun->u.i.nupvars;
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -40,16 +40,17 @@
 /* Definitions related to javascript type inference. */
 
 #ifndef jsinfer_h___
 #define jsinfer_h___
 
 #include "jsarena.h"
 #include "jstl.h"
 #include "jsprvtd.h"
+#include "jsvalue.h"
 
 #ifndef _MSC_VER
 #include <sys/time.h>
 #endif
 
 /* Define to get detailed output of inference actions. */
 
 namespace js { namespace analyze {
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -484,16 +484,18 @@ JSScript::setTypeNesting(JSScript *paren
 }
 
 inline js::types::TypeObject *
 JSScript::getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray)
 {
 #ifdef JS_TYPE_INFERENCE
     /* :FIXME: */
     JS_ASSERT(!analysis->failed());
+    if (compileAndGo)
+        return cx->getTypeNewObject(isArray ? JSProto_Array : JSProto_Object);
     return analysis->getCode(pc).getInitObject(cx, isArray);
 #else
     return cx->getTypeNewObject(isArray ? JSProto_Array : JSProto_Object);
 #endif
 }
 
 inline void
 JSScript::typeMonitorResult(JSContext *cx, const jsbytecode *pc, unsigned index,
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2773,16 +2773,18 @@ js_Object(JSContext *cx, uintN argc, Val
     if (!obj) {
         /* Make an object whether this was called with 'new' or not. */
         JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined());
         gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
         obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
             return JS_FALSE;
         TypeObject *type = cx->getTypeCallerInitObject(false);
+        if (!type)
+            return JS_FALSE;
         obj->setType(type);
     }
     vp->setObject(*obj);
     return JS_TRUE;
 }
 
 JSObject*
 js_CreateThis(JSContext *cx, JSObject *callee)
@@ -3421,17 +3423,18 @@ JSObject::clone(JSContext *cx, JSObject 
             return NULL;
         }
     }
     JSObject *clone = NewObject<WithProto::Given>(cx, getClass(),
                                                   proto, parent,
                                                   gc::FinalizeKind(finalizeKind()));
     if (!clone)
         return NULL;
-    clone->setType(getType());
+    if (getProto() == proto)
+        clone->setType(getType());
     if (isNative()) {
         if (clone->isFunction() && (compartment() != clone->compartment())) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_CANT_CLONE_OBJECT);
             return NULL;
         }
 
         if (getClass()->flags & JSCLASS_HAS_PRIVATE)
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -44,16 +44,17 @@
  * JS object definitions.
  *
  * A JS object consists of a possibly-shared object descriptor containing
  * ordered property names, called the map; and a dense vector of property
  * values, called slots.  The map/slot pointer pair is GC'ed, while the map
  * is reference counted and the slot vector is malloc'ed.
  */
 #include "jsapi.h"
+#include "jsinfer.h"
 #include "jshash.h"
 #include "jspubtd.h"
 #include "jsprvtd.h"
 #include "jslock.h"
 #include "jsvalue.h"
 #include "jsvector.h"
 #include "jscell.h"
 
@@ -654,21 +655,24 @@ struct JSObject : js::gc::Cell {
 
     /* Extend this object to have shape as its last-added property. */
     inline void extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom = false);
 
     js::types::TypeObject* getType() const { return type; }
 
     inline void clearType(JSContext *cx);
     inline void setType(js::types::TypeObject *newType);
-    inline JSObject *getProto() const;
 
     inline js::types::TypeObject *getNewType(JSContext *cx);
     void makeNewType(JSContext *cx);
 
+    JSObject * getProto() const {
+        return type->proto;
+    }
+
     JSObject *getParent() const {
         return parent;
     }
 
     void clearParent() {
         parent = NULL;
     }
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -607,22 +607,16 @@ JSObject::getNewType(JSContext *cx)
 {
     if (isDenseArray() && !makeDenseArraySlow(cx))
         return NULL;
     if (!newType)
         makeNewType(cx);
     return newType;
 }
 
-inline JSObject *
-JSObject::getProto() const
-{
-    return type->proto;
-}
-
 inline void
 JSObject::clearType(JSContext *cx)
 {
     type = cx->emptyTypeObject();
 }
 
 inline void
 JSObject::setType(js::types::TypeObject *newType)
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -233,16 +233,18 @@ RegExp::checkMatchPairs(JSString *input,
     }
 #endif
 }
 
 inline types::TypeObject *
 GetRegExpMatchType(JSContext *cx)
 {
     types::TypeObject *type = cx->getTypeCallerInitObject(true);
+    if (!type)
+        return NULL;
 
     cx->addTypeProperty(type, NULL, types::TYPE_STRING);
     cx->addTypeProperty(type, "index", types::TYPE_INT32);
     cx->addTypeProperty(type, "input", types::TYPE_STRING);
     cx->markTypeArrayNotPacked(type, true);
 
     return type;
 }
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -4980,17 +4980,20 @@ mjit::Compiler::jsop_newinit()
         break;
       default:
         JS_NOT_REACHED("Bad op");
         return;
     }
 
     prepareStubCall(Uses(0));
 
-    types::TypeObject *type = script->getTypeInitObject(cx, PC, isArray);
+    /* Don't bake in types for non-compileAndGo scripts. */
+    types::TypeObject *type = NULL;
+    if (script->compileAndGo)
+        type = script->getTypeInitObject(cx, PC, isArray);
     masm.storePtr(ImmPtr(type), FrameAddress(offsetof(VMFrame, scratch)));
 
     if (isArray) {
         masm.move(Imm32(count), Registers::ArgReg1);
         INLINE_STUBCALL(stubs::NewInitArray);
     } else {
         masm.move(ImmPtr(baseobj), Registers::ArgReg1);
         INLINE_STUBCALL(stubs::NewInitObject);
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -1408,36 +1408,40 @@ stubs::NewInitArray(VMFrame &f, uint32 c
     JSContext *cx = f.cx;
 
     gc::FinalizeKind kind = GuessObjectGCKind(count, true);
     JSObject *obj = NewArrayWithKind(cx, kind);
     if (!obj || !obj->ensureSlots(cx, count))
         THROWV(NULL);
 
     TypeObject *type = (TypeObject *) f.scratch;
-    obj->setType(type);
+    if (type)
+        obj->setType(type);
+
     obj->setArrayLength(cx, count);
     return obj;
 }
 
 JSObject * JS_FASTCALL
 stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
 {
     JSContext *cx = f.cx;
     TypeObject *type = (TypeObject *) f.scratch;
 
     if (!baseobj) {
         gc::FinalizeKind kind = GuessObjectGCKind(0, false);
         JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
             THROWV(NULL);
-        obj->setType(type);
+        if (type)
+            obj->setType(type);
         return obj;
     }
 
+    JS_ASSERT(type);
     JSObject *obj = CopyInitializerObject(cx, baseobj, type);
 
     if (!obj)
         THROWV(NULL);
     return obj;
 }
 
 void JS_FASTCALL
--- a/js/src/xpconnect/src/xpcdebug.cpp
+++ b/js/src/xpconnect/src/xpcdebug.cpp
@@ -35,22 +35,16 @@
  * 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 ***** */
 
 #include "xpcprivate.h"
 
-#include "mozilla/mozalloc_undef_macro_wrappers.h"
-
-#include "jscntxt.h"
-#include "jsobj.h"
-#include "jsobjinlines.h"
-
 #ifdef TAB
 #undef TAB
 #endif
 #define TAB "    "
 
 static const char* JSVAL2String(JSContext* cx, jsval val, JSBool* isString,
                                 JSAutoByteString *bytes)
 {
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -48,19 +48,16 @@
 #include "xpclog.h"
 #include "jstl.h"
 #include "nsINode.h"
 #include "xpcquickstubs.h"
 #include "jsproxy.h"
 #include "AccessCheck.h"
 #include "WrapperFactory.h"
 
-#include "mozilla/mozalloc_undef_macro_wrappers.h"
-#include "jsobjinlines.h"
-
 /***************************************************************************/
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
 
 NS_IMETHODIMP
 NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::RootAndUnlinkJSObjects(void *p)
 {
     XPCWrappedNative *tmp = static_cast<XPCWrappedNative*>(p);