Bug 655907 - Start adding GlobalObject-specific methods to get Object.prototype, Function.prototype, and a few others, and use them where it's easy to do so. r=jorendorff
authorJeff Walden <jwalden@mit.edu>
Mon, 09 May 2011 13:06:53 -0700
changeset 79623 bdd89e099e60a020e3b6a8be3bef42374bf7a8e6
parent 79622 5b13e63313a8b76b47db2b1066d1c5597f384441
child 79624 d5e6ea418eea2d650a2f1fdbe4cff4e368888cd0
push id506
push userclegnitto@mozilla.com
push dateWed, 09 Nov 2011 02:03:18 +0000
treeherdermozilla-aurora@63587fc7bb93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs655907
milestone10.0a1
Bug 655907 - Start adding GlobalObject-specific methods to get Object.prototype, Function.prototype, and a few others, and use them where it's easy to do so. r=jorendorff
js/src/jsbool.h
js/src/jsboolinlines.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/json.cpp
js/src/jsproxy.cpp
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
--- a/js/src/jsbool.h
+++ b/js/src/jsbool.h
@@ -53,25 +53,16 @@ extern JSString *
 js_BooleanToString(JSContext *cx, JSBool b);
 
 namespace js {
 
 extern bool
 BooleanToStringBuffer(JSContext *cx, JSBool b, StringBuffer &sb);
 
 inline bool
-BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp)
-{
-    if (obj.isBoolean()) {
-        *vp = obj.getPrimitiveThis();
-        return true;
-    }
-
-    extern bool BooleanGetPrimitiveValueSlow(JSContext *, JSObject &, Value *);
-    return BooleanGetPrimitiveValueSlow(cx, obj, vp);
-}
+BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp);
 
 } /* namespace js */
 
 extern JSBool
 js_ValueToBoolean(const js::Value &v);
 
 #endif /* jsbool_h___ */
new file mode 100644
--- /dev/null
+++ b/js/src/jsboolinlines.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** 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 SpiderMonkey code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jeff Walden <jwalden+code@mit.edu>  (original author)
+ *
+ * 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 jsboolinlines_h___
+#define jsboolinlines_h___
+
+#include "jsobjinlines.h"
+
+namespace js {
+
+inline bool
+BooleanGetPrimitiveValue(JSContext *cx, JSObject &obj, Value *vp)
+{
+    if (obj.isBoolean()) {
+        *vp = obj.getPrimitiveThis();
+        return true;
+    }
+
+    extern bool BooleanGetPrimitiveValueSlow(JSContext *, JSObject &, Value *);
+    return BooleanGetPrimitiveValueSlow(cx, obj, vp);
+}
+
+} /* namespace js */
+
+#endif /* jsboolinlines_h___ */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -187,18 +187,18 @@ js_GetArgsProperty(JSContext *cx, StackF
     return true;
 }
 
 js::ArgumentsObject *
 ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
 {
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
 
-    JSObject *proto;
-    if (!js_GetClassPrototype(cx, callee.getGlobal(), JSProto_Object, &proto))
+    JSObject *proto = callee.getGlobal()->getOrCreateObjectPrototype(cx);
+    if (!proto)
         return NULL;
 
     TypeObject *type = proto->getNewType(cx);
     if (!type)
         return NULL;
 
     JS_STATIC_ASSERT(NormalArgumentsObject::RESERVED_SLOTS == 2);
     JS_STATIC_ASSERT(StrictArgumentsObject::RESERVED_SLOTS == 2);
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -443,38 +443,17 @@ extern void
 js_FinalizeFunction(JSContext *cx, JSFunction *fun);
 
 extern JSObject * JS_FASTCALL
 js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
                        JSObject *proto);
 
 inline JSObject *
 CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
-                    bool ignoreSingletonClone = false)
-{
-    JS_ASSERT(parent);
-    JSObject *proto;
-    if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto))
-        return NULL;
-
-    /*
-     * For attempts to clone functions at a function definition opcode or from
-     * a method barrier, don't perform the clone if the function has singleton
-     * type. CloneFunctionObject was called pessimistically, and we need to
-     * preserve the type's property that if it is singleton there is only a
-     * single object with its type in existence.
-     */
-    if (ignoreSingletonClone && fun->hasSingletonType()) {
-        JS_ASSERT(fun->getProto() == proto);
-        fun->setParent(parent);
-        return fun;
-    }
-
-    return js_CloneFunctionObject(cx, fun, parent, proto);
-}
+                    bool ignoreSingletonClone = false);
 
 inline JSObject *
 CloneFunctionObject(JSContext *cx, JSFunction *fun)
 {
     /*
      * Variant which makes an exact clone of fun, preserving parent and proto.
      * Calling the above version CloneFunctionObject(cx, fun, fun->getParent())
      * is not equivalent: API clients, including XPConnect, can reparent
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -38,16 +38,18 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsfuninlines_h___
 #define jsfuninlines_h___
 
 #include "jsfun.h"
 #include "jsscript.h"
 
+#include "vm/GlobalObject.h"
+
 inline bool
 js::IsConstructing(CallReceiver call)
 {
     return IsConstructing(call.base());
 }
 
 inline bool
 JSFunction::inStrictMode() const
@@ -65,9 +67,34 @@ JSFunction::setJoinable()
 
 inline void
 JSFunction::setMethodAtom(JSAtom *atom)
 {
     JS_ASSERT(joinable());
     setSlot(METHOD_ATOM_SLOT, js::StringValue(atom));
 }
 
+inline JSObject *
+CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
+                    bool ignoreSingletonClone /* = false */)
+{
+    JS_ASSERT(parent);
+    JSObject *proto = parent->getGlobal()->getOrCreateFunctionPrototype(cx);
+    if (!proto)
+        return NULL;
+
+    /*
+     * For attempts to clone functions at a function definition opcode or from
+     * a method barrier, don't perform the clone if the function has singleton
+     * type. CloneFunctionObject was called pessimistically, and we need to
+     * preserve the type's property that if it is singleton there is only a
+     * single object with its type in existence.
+     */
+    if (ignoreSingletonClone && fun->hasSingletonType()) {
+        JS_ASSERT(fun->getProto() == proto);
+        fun->setParent(parent);
+        return fun;
+    }
+
+    return js_CloneFunctionObject(cx, fun, parent, proto);
+}
+
 #endif /* jsfuninlines_h___ */
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -3552,30 +3552,30 @@ END_CASE(JSOP_GETPROP)
 BEGIN_CASE(JSOP_CALLPROP)
 {
     Value lval = regs.sp[-1];
 
     Value objv;
     if (lval.isObject()) {
         objv = lval;
     } else {
-        JSProtoKey protoKey;
+        GlobalObject *global = regs.fp()->scopeChain().getGlobal();
+        JSObject *pobj;
         if (lval.isString()) {
-            protoKey = JSProto_String;
+            pobj = global->getOrCreateStringPrototype(cx);
         } else if (lval.isNumber()) {
-            protoKey = JSProto_Number;
+            pobj = global->getOrCreateNumberPrototype(cx);
         } else if (lval.isBoolean()) {
-            protoKey = JSProto_Boolean;
+            pobj = global->getOrCreateBooleanPrototype(cx);
         } else {
             JS_ASSERT(lval.isNull() || lval.isUndefined());
             js_ReportIsNullOrUndefined(cx, -1, lval, NULL);
             goto error;
         }
-        JSObject *pobj;
-        if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj))
+        if (!pobj)
             goto error;
         objv.setObject(*pobj);
     }
 
     JSObject *aobj = js_GetProtoIfDenseArray(&objv.toObject());
     Value rval;
 
     PropertyCacheEntry *entry;
@@ -4210,27 +4210,22 @@ BEGIN_CASE(JSOP_OBJECT)
     PUSH_OBJECT(*obj);
 }
 END_CASE(JSOP_OBJECT)
 
 BEGIN_CASE(JSOP_REGEXP)
 {
     /*
      * Push a regexp object cloned from the regexp literal object mapped by the
-     * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
-     * flouted by many browser-based implementations.
-     *
-     * We avoid the GetScopeChain call here and pass fp->scopeChain as
-     * js_GetClassPrototype uses the latter only to locate the global.
+     * bytecode at pc.
      */
     jsatomid index = GET_FULL_INDEX(0);
-    JSObject *proto;
-    if (!js_GetClassPrototype(cx, &regs.fp()->scopeChain(), JSProto_RegExp, &proto))
+    JSObject *proto = regs.fp()->scopeChain().getGlobal()->getOrCreateRegExpPrototype(cx);
+    if (!proto)
         goto error;
-    JS_ASSERT(proto);
     JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto);
     if (!obj)
         goto error;
     PUSH_OBJECT(*obj);
 }
 END_CASE(JSOP_REGEXP)
 
 BEGIN_CASE(JSOP_ZERO)
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3121,17 +3121,18 @@ js_CreateThisFromTrace(JSContext *cx, JS
     const Value &protov = ctor->getSlot(protoSlot);
     if (protov.isObject()) {
         proto = &protov.toObject();
     } else {
         /*
          * GetInterpretedFunctionPrototype found that ctor.prototype is
          * primitive. Use Object.prototype for proto, per ES5 13.2.2 step 7.
          */
-        if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
+        proto = parent->getGlobal()->getOrCreateObjectPrototype(cx);
+        if (!proto)
             return NULL;
     }
 
     gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
     return NewNativeClassInstance(cx, &ObjectClass, proto, parent, kind);
 }
 JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, OBJECT, UINTN, 0,
                      nanojit::ACCSET_STORE_ANY)
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -57,16 +57,17 @@
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
 #include "jsxml.h"
 
 #include "frontend/TokenStream.h"
 
 #include "jsatominlines.h"
+#include "jsboolinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1487,17 +1487,18 @@ proxy_createFunction(JSContext *cx, uint
                              "createFunction", "1", "");
         return false;
     }
     JSObject *handler = NonNullObject(cx, vp[2]);
     if (!handler)
         return false;
     JSObject *proto, *parent;
     parent = vp[0].toObject().getParent();
-    if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto))
+    proto = parent->getGlobal()->getOrCreateFunctionPrototype(cx);
+    if (!proto)
         return false;
     parent = proto->getParent();
 
     JSObject *call = js_ValueToCallableObject(cx, &vp[3], JSV2F_SEARCH_STACK);
     if (!call)
         return false;
     JSObject *construct = NULL;
     if (argc > 2) {
@@ -1600,17 +1601,18 @@ callable_Construct(JSContext *cx, uintN 
         Value protov;
         if (!callable->getProperty(cx, ATOM(classPrototype), &protov))
             return false;
 
         JSObject *proto;
         if (protov.isObject()) {
             proto = &protov.toObject();
         } else {
-            if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto))
+            proto = callable->getGlobal()->getOrCreateObjectPrototype(cx);
+            if (!proto)
                 return false;
         }
 
         JSObject *newobj = NewNativeClassInstance(cx, &ObjectClass, proto, proto->getParent());
         if (!newobj)
             return false;
 
         /* If the call returns an object, return that, otherwise the original newobj. */
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -4589,27 +4589,25 @@ HasFunctionProperty(JSContext *cx, JSObj
 
     JS_ASSERT(obj->getClass() == &XMLClass);
 
     if (!js_LookupProperty(cx, obj, funid, &pobj, &prop))
         return false;
     if (!prop) {
         xml = (JSXML *) obj->getPrivate();
         if (HasSimpleContent(xml)) {
-            AutoObjectRooter tvr(cx);
-
             /*
              * Search in String.prototype to set found whenever
              * GetXMLFunction returns existing function.
              */
-            if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr()))
+            JSObject *proto = obj->getGlobal()->getOrCreateStringPrototype(cx);
+            if (!proto)
                 return false;
 
-            JS_ASSERT(tvr.object());
-            if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop))
+            if (!js_LookupProperty(cx, proto, funid, &pobj, &prop))
                 return false;
         }
     }
     *found = (prop != NULL);
     return true;
 }
 
 static bool
@@ -7727,38 +7725,36 @@ GetXMLFunction(JSContext *cx, JSObject *
 {
     JS_ASSERT(obj->isXML());
 
     /*
      * See comments before xml_lookupGeneric about the need for the proto
      * chain lookup.
      */
     JSObject *target = obj;
-    AutoObjectRooter tvr(cx);
     for (;;) {
         if (!js_GetProperty(cx, target, id, vp))
             return false;
         if (!JSVAL_IS_PRIMITIVE(*vp) && JSVAL_TO_OBJECT(*vp)->isFunction())
             return true;
         target = target->getProto();
         if (target == NULL || !target->isNative())
             break;
-        tvr.setObject(target);
     }
 
     JSXML *xml = (JSXML *) obj->getPrivate();
     if (!HasSimpleContent(xml))
         return true;
 
     /* Search in String.prototype to implement 11.2.2.1 Step 3(f). */
-    if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr()))
+    JSObject *proto = obj->getGlobal()->getOrCreateStringPrototype(cx);
+    if (!proto)
         return false;
 
-    JS_ASSERT(tvr.object());
-    return tvr.object()->getGeneric(cx, id, vp);
+    return proto->getGeneric(cx, id, vp);
 }
 
 static JSXML *
 GetPrivate(JSContext *cx, JSObject *obj, const char *method)
 {
     if (!obj->isXML()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_INCOMPATIBLE_METHOD,
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -4705,24 +4705,19 @@ mjit::Compiler::jsop_callprop_generic(JS
 bool
 mjit::Compiler::jsop_callprop_str(JSAtom *atom)
 {
     if (!globalObj) {
         jsop_callprop_slow(atom);
         return true;
     }
 
-    /*
-     * Bake in String.prototype. This is safe because of compileAndGo.
-     * We must pass an explicit scope chain only because JSD calls into
-     * here via the recompiler with a dummy context, and we need to use
-     * the global object for the script we are now compiling.
-     */
-    JSObject *obj;
-    if (!js_GetClassPrototype(cx, globalObj, JSProto_String, &obj))
+    /* Bake in String.prototype. This is safe because of compileAndGo. */
+    JSObject *obj = globalObj->getOrCreateStringPrototype(cx);
+    if (!obj)
         return false;
 
     /*
      * Root the proto, since JS_ClearScope might overwrite the global object's
      * copy.
      */
     rootedObjects.append(obj);
 
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -2070,30 +2070,30 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pi
 
     // Do this first in case js_GetClassPrototype triggers a recompilation.
     jsid id = ATOM_TO_JSID(pic->atom);
 
     Value objv;
     if (lval.isObject()) {
         objv = lval;
     } else {
-        JSProtoKey protoKey;
+        GlobalObject *global = f.fp()->scopeChain().getGlobal();
+        JSObject *pobj;
         if (lval.isString()) {
-            protoKey = JSProto_String;
+            pobj = global->getOrCreateStringPrototype(cx);
         } else if (lval.isNumber()) {
-            protoKey = JSProto_Number;
+            pobj = global->getOrCreateNumberPrototype(cx);
         } else if (lval.isBoolean()) {
-            protoKey = JSProto_Boolean;
+            pobj = global->getOrCreateBooleanPrototype(cx);
         } else {
             JS_ASSERT(lval.isNull() || lval.isUndefined());
             js_ReportIsNullOrUndefined(cx, -1, lval, NULL);
             THROW();
         }
-        JSObject *pobj;
-        if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj))
+        if (!pobj)
             THROW();
         objv.setObject(*pobj);
     }
 
     JSObject *aobj = js_GetProtoIfDenseArray(&objv.toObject());
     Value rval;
 
     PropertyCacheEntry *entry;
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -1433,24 +1433,20 @@ stubs::DefLocalFun_FC(VMFrame &f, JSFunc
     return obj;
 }
 
 void JS_FASTCALL
 stubs::RegExp(VMFrame &f, JSObject *regex)
 {
     /*
      * Push a regexp object cloned from the regexp literal object mapped by the
-     * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
-     * flouted by many browser-based implementations.
-     *
-     * We avoid the GetScopeChain call here and pass fp->scopeChain() as
-     * js_GetClassPrototype uses the latter only to locate the global.
+     * bytecode at pc.
      */
-    JSObject *proto;
-    if (!js_GetClassPrototype(f.cx, &f.fp()->scopeChain(), JSProto_RegExp, &proto))
+    JSObject *proto = f.fp()->scopeChain().getGlobal()->getOrCreateRegExpPrototype(f.cx);
+    if (!proto)
         THROW();
     JS_ASSERT(proto);
     JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto);
     if (!obj)
         THROW();
     f.regs.sp[0].setObject(*obj);
 }
 
@@ -1633,30 +1629,30 @@ stubs::CallProp(VMFrame &f, JSAtom *orig
 
     Value lval;
     lval = regs.sp[-1];
 
     Value objv;
     if (lval.isObject()) {
         objv = lval;
     } else {
-        JSProtoKey protoKey;
+        GlobalObject *global = f.fp()->scopeChain().getGlobal();
+        JSObject *pobj;
         if (lval.isString()) {
-            protoKey = JSProto_String;
+            pobj = global->getOrCreateStringPrototype(cx);
         } else if (lval.isNumber()) {
-            protoKey = JSProto_Number;
+            pobj = global->getOrCreateNumberPrototype(cx);
         } else if (lval.isBoolean()) {
-            protoKey = JSProto_Boolean;
+            pobj = global->getOrCreateBooleanPrototype(cx);
         } else {
             JS_ASSERT(lval.isNull() || lval.isUndefined());
             js_ReportIsNullOrUndefined(cx, -1, lval, NULL);
             THROW();
         }
-        JSObject *pobj;
-        if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj))
+        if (!pobj)
             THROW();
         objv.setObject(*pobj);
     }
 
     JSObject *aobj = js_GetProtoIfDenseArray(&objv.toObject());
     Value rval;
 
     PropertyCacheEntry *entry;
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -53,34 +53,25 @@
 
 using namespace js;
 
 JSObject *
 js_InitObjectClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
-    GlobalObject *global = obj->asGlobal();
-    if (!global->functionObjectClassesInitialized()) {
-        if (!global->initFunctionAndObjectClasses(cx))
-            return NULL;
-    }
-
-    return global->getObjectPrototype();
+    return obj->asGlobal()->getOrCreateObjectPrototype(cx);
 }
 
 JSObject *
 js_InitFunctionClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
-    GlobalObject *global = obj->asGlobal();
-    return global->functionObjectClassesInitialized()
-           ? global->getFunctionPrototype()
-           : global->initFunctionAndObjectClasses(cx);
+    return obj->asGlobal()->getOrCreateFunctionPrototype(cx);
 }
 
 static JSBool
 ThrowTypeError(JSContext *cx, uintN argc, Value *vp)
 {
     JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                  JSMSG_THROW_TYPE_ERROR);
     return false;
@@ -395,18 +386,18 @@ CreateBlankProto(JSContext *cx, Class *c
         return NULL;
 
     return blankProto;
 }
 
 JSObject *
 GlobalObject::createBlankPrototype(JSContext *cx, Class *clasp)
 {
-    JSObject *objectProto;
-    if (!js_GetClassPrototype(cx, this, JSProto_Object, &objectProto))
+    JSObject *objectProto = getOrCreateObjectPrototype(cx);
+    if (!objectProto)
         return NULL;
 
     return CreateBlankProto(cx, clasp, *objectProto, *this);
 }
 
 JSObject *
 GlobalObject::createBlankPrototypeInheriting(JSContext *cx, Class *clasp, JSObject &proto)
 {
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -36,21 +36,26 @@
  * 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 GlobalObject_h___
 #define GlobalObject_h___
 
+#include "jsbool.h"
 #include "jsfun.h"
 #include "jsiter.h"
+#include "jsnum.h"
+#include "jstypedarray.h"
 
 #include "js/Vector.h"
 
+#include "builtin/RegExp.h"
+
 extern JSObject *
 js_InitObjectClass(JSContext *cx, JSObject *obj);
 
 extern JSObject *
 js_InitFunctionClass(JSContext *cx, JSObject *obj);
 
 namespace js {
 
@@ -154,16 +159,54 @@ class GlobalObject : public ::JSObject {
     }
 
     void setOriginalEval(JSObject *evalobj) {
         Value &v = getSlotRef(EVAL);
         JS_ASSERT(v.isUndefined());
         v.setObject(*evalobj);
     }
 
+    Value getConstructor(JSProtoKey key) const {
+        JS_ASSERT(key <= JSProto_LIMIT);
+        return getSlot(key);
+    }
+
+    Value getPrototype(JSProtoKey key) const {
+        JS_ASSERT(key <= JSProto_LIMIT);
+        return getSlot(JSProto_LIMIT + key);
+    }
+
+    bool classIsInitialized(JSProtoKey key) const {
+        bool inited = !getConstructor(key).isUndefined();
+        JS_ASSERT(inited == !getPrototype(key).isUndefined());
+        return inited;
+    }
+
+    bool functionObjectClassesInitialized() const {
+        bool inited = classIsInitialized(JSProto_Function);
+        JS_ASSERT(inited == classIsInitialized(JSProto_Object));
+        return inited;
+    }
+
+    bool booleanClassInitialized() const {
+        return classIsInitialized(JSProto_Boolean);
+    }
+    bool numberClassInitialized() const {
+        return classIsInitialized(JSProto_Number);
+    }
+    bool stringClassInitialized() const {
+        return classIsInitialized(JSProto_String);
+    }
+    bool regexpClassInitialized() const {
+        return classIsInitialized(JSProto_RegExp);
+    }
+    bool arrayBufferClassInitialized() const {
+        return classIsInitialized(JSProto_ArrayBuffer);
+    }
+
   public:
     static GlobalObject *create(JSContext *cx, Class *clasp);
 
     /*
      * Create a constructor function with the specified name and length using
      * ctor, a method which creates objects with the given class.
      */
     JSFunction *
@@ -180,47 +223,85 @@ class GlobalObject : public ::JSObject {
     JSObject *createBlankPrototype(JSContext *cx, js::Class *clasp);
 
     /*
      * Identical to createBlankPrototype, but uses proto as the [[Prototype]]
      * of the returned blank prototype.
      */
     JSObject *createBlankPrototypeInheriting(JSContext *cx, js::Class *clasp, JSObject &proto);
 
-    bool functionObjectClassesInitialized() const {
-        bool inited = !getSlot(JSProto_Function).isUndefined();
-        JS_ASSERT(inited == !getSlot(JSProto_LIMIT + JSProto_Function).isUndefined());
-        JS_ASSERT(inited == !getSlot(JSProto_Object).isUndefined());
-        JS_ASSERT(inited == !getSlot(JSProto_LIMIT + JSProto_Object).isUndefined());
-        return inited;
+    JSObject *getOrCreateObjectPrototype(JSContext *cx) {
+        if (!functionObjectClassesInitialized()) {
+            if (!initFunctionAndObjectClasses(cx))
+                return NULL;
+        }
+        return &getPrototype(JSProto_Object).toObject();
+    }
+
+    JSObject *getOrCreateFunctionPrototype(JSContext *cx) {
+        if (!functionObjectClassesInitialized()) {
+            if (!initFunctionAndObjectClasses(cx))
+                return NULL;
+        }
+        return &getPrototype(JSProto_Function).toObject();
+    }
+
+    JSObject *getOrCreateBooleanPrototype(JSContext *cx) {
+        if (!booleanClassInitialized()) {
+            if (!js_InitBooleanClass(cx, this))
+                return NULL;
+        }
+        return &getPrototype(JSProto_Boolean).toObject();
     }
 
-    JSObject *getFunctionPrototype() const {
-        JS_ASSERT(functionObjectClassesInitialized());
-        return &getSlot(JSProto_LIMIT + JSProto_Function).toObject();
+    JSObject *getOrCreateNumberPrototype(JSContext *cx) {
+        if (!numberClassInitialized()) {
+            if (!js_InitNumberClass(cx, this))
+                return NULL;
+        }
+        return &getPrototype(JSProto_Number).toObject();
     }
 
-    JSObject *getObjectPrototype() const {
-        JS_ASSERT(functionObjectClassesInitialized());
-        return &getSlot(JSProto_LIMIT + JSProto_Object).toObject();
+    JSObject *getOrCreateStringPrototype(JSContext *cx) {
+        if (!stringClassInitialized()) {
+            if (!js_InitStringClass(cx, this))
+                return NULL;
+        }
+        return &getPrototype(JSProto_String).toObject();
     }
 
-    JSObject *getThrowTypeError() const {
-        JS_ASSERT(functionObjectClassesInitialized());
-        return &getSlot(THROWTYPEERROR).toObject();
+    JSObject *getOrCreateRegExpPrototype(JSContext *cx) {
+        if (!regexpClassInitialized()) {
+            if (!js_InitRegExpClass(cx, this))
+                return NULL;
+        }
+        return &getPrototype(JSProto_RegExp).toObject();
+    }
+
+    JSObject *getOrCreateArrayBufferPrototype(JSContext *cx) {
+        if (!arrayBufferClassInitialized()) {
+            if (!js_InitTypedArrayClasses(cx, this))
+                return NULL;
+        }
+        return &getPrototype(JSProto_ArrayBuffer).toObject();
     }
 
     JSObject *getOrCreateGeneratorPrototype(JSContext *cx) {
         Value &v = getSlotRef(GENERATOR_PROTO);
         if (!v.isObject() && !js_InitIteratorClasses(cx, this))
             return NULL;
         JS_ASSERT(v.toObject().isGenerator());
         return &v.toObject();
     }
 
+    JSObject *getThrowTypeError() const {
+        JS_ASSERT(functionObjectClassesInitialized());
+        return &getSlot(THROWTYPEERROR).toObject();
+    }
+
     RegExpStatics *getRegExpStatics() const {
         JSObject &resObj = getSlot(REGEXP_STATICS).toObject();
         return static_cast<RegExpStatics *>(resObj.getPrivate());
     }
 
     void clear(JSContext *cx);
 
     bool isCleared() const {