[INFER] Objects with same shape have same type, objects with same type have same prototype, bug 619271.
authorBrian Hackett <bhackett1024@gmail.com>
Sat, 18 Dec 2010 20:44:51 -0800
changeset 75433 4d5cc9be4eea59a9f1ba1e5d737cc02094d8473b
parent 75432 a2630fc3cd9001dcdb391077cc62b38a550ab7ff
child 75434 3abf17e28705b62d8df9edcf493627b3957c3d03
push idunknown
push userunknown
push dateunknown
bugs619271
milestone2.0b8pre
[INFER] Objects with same shape have same type, objects with same type have same prototype, bug 619271.
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jsbool.cpp
js/src/jsbuiltins.cpp
js/src/jsclone.cpp
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsemit.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsparse.cpp
js/src/jsprf.cpp
js/src/jsprobes.cpp
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsregexp.cpp
js/src/jsregexpinlines.h
js/src/jsscopeinlines.h
js/src/jsscript.cpp
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/tracejit/Writer.cpp
js/src/tracejit/Writer.h
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -38,16 +38,231 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "jsanalyze.h"
 #include "jsautooplen.h"
 #include "jscompartment.h"
 #include "jscntxt.h"
 
 #include "jsinferinlines.h"
+#include "jsobjinlines.h"
+
+/////////////////////////////////////////////////////////////////////
+// TypeCompartment
+/////////////////////////////////////////////////////////////////////
+
+/*
+ * These are the definitions needed for skeleton TypeCompartments and TypeObjects
+ * as used when type inference is disabled.
+ */
+
+namespace js {
+namespace types {
+
+void
+TypeCompartment::init()
+{
+    PodZero(this);
+    JS_InitArenaPool(&pool, "typeinfer", 512, 8, NULL);
+
+#ifdef DEBUG
+    emptyObject.name_ = JSID_VOID;
+#endif
+    emptyObject.unknownProperties = true;
+    emptyObject.pool = &pool;
+}
+
+TypeCompartment::~TypeCompartment()
+{
+    JS_FinishArenaPool(&pool);
+}
+
+types::TypeObject *
+TypeCompartment::newTypeObject(JSContext *cx, analyze::Script *script, const char *name,
+                               bool isFunction, JSObject *proto)
+{
+    JSArenaPool &pool = script ? script->pool : this->pool;
+
+#ifdef DEBUG
+    jsid id = ATOM_TO_JSID(js_Atomize(cx, name, strlen(name), ATOM_PINNED));
+#else
+    jsid id = JSID_VOID;
+#endif
+
+    TypeObject *object;
+    if (isFunction)
+        object = ArenaNew<TypeFunction>(pool, &pool, id, proto);
+    else
+        object = ArenaNew<TypeObject>(pool, &pool, id, proto);
+
+#ifdef JS_TYPE_INFERENCE
+    TypeObject *&objects = script ? script->objects : this->objects;
+    object->next = objects;
+    objects = object;
+#else
+    object->next = this->objects;
+    this->objects = object;
+#endif
+
+    return object;
+}
+
+const char *
+TypeIdStringImpl(jsid id)
+{
+    if (JSID_IS_VOID(id))
+        return "(index)";
+    if (JSID_IS_EMPTY(id))
+        return "(new)";
+    static char bufs[4][100];
+    static unsigned which = 0;
+    which = (which + 1) & 3;
+    PutEscapedString(bufs[which], 100, JSID_TO_STRING(id), 0);
+    return bufs[which];
+}
+
+void
+TypeObject::splicePrototype(JSObject *proto)
+{
+    JS_ASSERT(!this->proto);
+    this->proto = proto;
+    this->instanceNext = proto->getType()->instanceList;
+    proto->getType()->instanceList = this;
+}
+
+} } /* namespace js::types */
+
+js::types::TypeFunction *
+JSContext::newTypeFunction(const char *name, JSObject *proto)
+{
+    return (js::types::TypeFunction *) compartment->types.newTypeObject(this, NULL, name, true, proto);
+}
+
+js::types::TypeObject *
+JSContext::newTypeObject(const char *name, JSObject *proto)
+{
+    return compartment->types.newTypeObject(this, NULL, name, false, proto);
+}
+
+js::types::TypeObject *
+JSContext::newTypeObject(const char *base, const char *postfix, JSObject *proto)
+{
+    char *name = NULL;
+#ifdef DEBUG
+    unsigned len = strlen(base) + strlen(postfix) + 5;
+    name = (char *)alloca(len);
+    JS_snprintf(name, len, "%s:%s", base, postfix);
+#endif
+    return compartment->types.newTypeObject(this, NULL, name, false, proto);
+}
+
+void
+JSObject::makeNewType(JSContext *cx)
+{
+    JS_ASSERT(!newType);
+    setDelegate();
+    newType = cx->newTypeObject(getType()->name(), "new", this);
+
+#ifdef JS_TYPE_INFERENCE
+    if (!getType()->unknownProperties) {
+        /* Update the possible 'new' types for all prototype objects sharing the same type object. */
+        js::types::TypeSet *types = getType()->getProperty(cx, JSID_EMPTY, true);
+        cx->compartment->types.addDynamicType(cx, types, (js::types::jstype) newType);
+    }
+#endif
+}
+
+/////////////////////////////////////////////////////////////////////
+// Tracing
+/////////////////////////////////////////////////////////////////////
+
+namespace js {
+
+void
+types::TypeObject::trace(JSTracer *trc)
+{
+    JS_ASSERT(!marked);
+
+    /*
+     * Only mark types if the Mark/Sweep GC is running; the bit won't be cleared
+     * by the cycle collector.
+     */
+    if (trc->context->runtime->gcMarkAndSweep)
+        marked = true;
+
+    if (emptyShapes) {
+        int count = gc::FINALIZE_OBJECT_LAST - gc::FINALIZE_OBJECT0 + 1;
+        for (int i = 0; i < count; i++) {
+            if (emptyShapes[i])
+                emptyShapes[i]->trace(trc);
+        }
+    }
+
+    if (proto)
+        gc::MarkObject(trc, *proto, "type_proto");
+}
+
+void
+analyze::Script::trace(JSTracer *trc)
+{
+#ifdef JS_TYPE_INFERENCE
+    /* If a script is live, so are all type objects within it. */
+    types::TypeObject *object = objects;
+    while (object) {
+        if (!object->marked)
+            object->trace(trc);
+        object = object->next;
+    }
+#endif
+}
+
+static inline void
+SweepObjectList(JSContext *cx, types::TypeObject *objects)
+{
+    types::TypeObject *object = objects;
+    while (object) {
+        if (object->marked) {
+            object->marked = false;
+        } else {
+            object->proto = NULL;
+            if (object->emptyShapes) {
+                cx->free(object->emptyShapes);
+                object->emptyShapes = NULL;
+            }
+        }
+        object = object->next;
+    }
+}
+
+void
+analyze::Script::sweep(JSContext *cx)
+{
+#ifdef JS_TYPE_INFERENCE
+    SweepObjectList(cx, objects);
+#endif
+}
+
+void
+analyze::Script::detach()
+{
+    /* :FIXME: bug 613221 should unlink incoming type constraints and destroy the analysis. */
+    script = NULL;
+#ifdef JS_TYPE_INFERENCE
+    fun = NULL;
+    localNames = NULL;
+#endif
+}
+
+void
+types::TypeCompartment::sweep(JSContext *cx)
+{
+    SweepObjectList(cx, objects);
+}
+
+} /* namespace js */
 
 namespace js {
 namespace analyze {
 
 /////////////////////////////////////////////////////////////////////
 // Script
 /////////////////////////////////////////////////////////////////////
 
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -286,16 +286,20 @@ class Script
             return true;
         for (unsigned i = 0; i < script->nClosedVars; i++) {
             if (local == script->getClosedVar(i))
                 return true;
         }
         return false;
     }
 
+    void trace(JSTracer *trc);
+    void sweep(JSContext *cx);
+    void detach();
+
   private:
     void setOOM(JSContext *cx) {
         if (!outOfMemory)
             js_ReportOutOfMemory(cx);
         outOfMemory = true;
         hadFailure = true;
     }
 
@@ -342,17 +346,17 @@ class Script
 
     /* Whether this is eval code. */
     bool isEval() { return parent && !fun; }
 
     /* Whether this is global code, including from a global-scope eval(). */
     bool isGlobal() { return !parent || (!fun && !parent->analysis->parent); }
 
     unsigned argCount() { return fun ? fun->nargs : 0; }
-    types::TypeFunction *function() { return fun->getTypeObject()->asFunction(); }
+    types::TypeFunction *function() { return fun->getType()->asFunction(); }
 
     /*
      * Get the non-eval script which this one is nested in, returning this script
      * if it was not produced as the result of an eval.
      */
     inline Script *evalParent();
 
     /* Bytecode where this script is nested. */
@@ -473,20 +477,18 @@ class Script
 
     /* Get any known type tag for an argument or local variable. */
     inline JSValueType knownArgumentTypeTag(JSContext *cx, JSScript *script, unsigned arg);
     inline JSValueType knownLocalTypeTag(JSContext *cx, JSScript *script, unsigned local);
 
     /* Helpers */
 
     void addVariable(JSContext *cx, jsid id, types::Variable *&var);
-    void trace(JSTracer *trc);
 
 #endif /* JS_TYPE_INFERENCE */
-
 };
 
 static inline unsigned
 GetBytecodeLength(jsbytecode *pc)
 {
     JSOp op = (JSOp)*pc;
     JS_ASSERT(op < JSOP_LIMIT);
     JS_ASSERT(op != JSOP_TRAP);
--- a/js/src/jsapi-tests/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  *
  * Tests JS_TransplantObject
  */
 
 #include "tests.h"
 #include "jswrapper.h"
+#include "jsobjinlines.h"
 
 struct OuterWrapper : JSWrapper
 {
     OuterWrapper() : JSWrapper(0) {}
 
     virtual bool isOuterWindow() {
         return true;
     }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1406,19 +1406,19 @@ js_InitFunctionAndObjectClasses(JSContex
     if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
         return NULL;
     if (!obj_proto)
         obj_proto = js_InitObjectClass(cx, obj);
     if (!obj_proto)
         return NULL;
 
     /* Function.prototype and the global object delegate to Object.prototype. */
-    fun_proto->setProto(cx, obj_proto);
+    fun_proto->getType()->splicePrototype(obj_proto);
     if (!obj->getProto())
-        obj->setProto(cx, obj_proto);
+        obj->getType()->splicePrototype(obj_proto);
 
     return fun_proto;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
@@ -2951,32 +2951,36 @@ JS_GetObjectId(JSContext *cx, JSObject *
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
     CHECK_REQUEST(cx);
     JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
-    TypeObject *objType = cx->getGlobalTypeObject();
-    JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL, objType);
+    JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL);
     if (!obj)
         return NULL;
 
+    TypeObject *type = cx->newTypeObject("Global", NULL);
+    if (!type)
+        return NULL;
+    obj->setType(type);
+
     obj->syncSpecialEquality();
 
     /* Construct a regexp statics object for this global object. */
     JSObject *res = regexp_statics_construct(cx, obj);
     if (!res ||
         !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS,
                             ObjectValue(*res))) {
         return NULL;
     }
 
-    cx->addTypeProperty(obj->getTypeObject(), js_undefined_str, UndefinedValue());
+    cx->addTypeProperty(obj->getType(), js_undefined_str, UndefinedValue());
 
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
 {
     CHECK_REQUEST(cx);
@@ -2988,56 +2992,52 @@ JS_NewCompartmentAndGlobalObject(JSConte
     cx->compartment = compartment;
     JSObject *obj = JS_NewGlobalObject(cx, clasp);
     cx->compartment = saved;
 
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_NewObjectWithType(JSContext *cx, JSClass *jsclasp,
-                     JSObject *proto, JSObject *parent, JSTypeObject *jstype)
+JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &js_ObjectClass;    /* default class is Object */
 
     JS_ASSERT(clasp != &js_FunctionClass);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
-    TypeObject *type = Valueify(jstype);
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent, type);
+    JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
     if (obj)
         obj->syncSpecialEquality();
 
     JS_ASSERT_IF(obj, obj->getParent());
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_NewObjectWithGivenProtoAndType(JSContext *cx, JSClass *jsclasp, JSObject *proto,
-                                  JSObject *parent, JSTypeObject *jstype)
+JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &js_ObjectClass;    /* default class is Object */
 
     JS_ASSERT(clasp != &js_FunctionClass);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
-    TypeObject *type = Valueify(jstype);
-    JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, type);
+    JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
     if (obj)
         obj->syncSpecialEquality();
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
 {
@@ -3083,52 +3083,48 @@ JS_DeepFreezeObject(JSContext *cx, JSObj
         if (!JS_DeepFreezeObject(cx, &v.toObject()))
             return false;
     }
 
     return true;
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_ConstructObjectWithType(JSContext *cx, JSClass *jsclasp, JSObject *proto,
-                           JSObject *parent, JSTypeObject *jstype)
+JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &js_ObjectClass;    /* default class is Object */
-    TypeObject *type = Valueify(jstype);
-    return js_ConstructObject(cx, clasp, proto, parent, type, 0, NULL);
+    return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_ConstructObjectWithArgumentsAndType(JSContext *cx, JSClass *jsclasp, JSObject *proto,
-                                       JSObject *parent, JSTypeObject *jstype,
-                                       uintN argc, jsval *argv)
+JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto,
+                                JSObject *parent, uintN argc, jsval *argv)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc));
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &js_ObjectClass;    /* default class is Object */
-    TypeObject *type = Valueify(jstype);
-    return js_ConstructObject(cx, clasp, proto, parent, type, argc, Valueify(argv));
+    return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
 }
 
 JS_PUBLIC_API(void)
 JS_AddTypeProperty(JSContext *cx, JSObject *obj, const char *name, jsval value)
 {
-    cx->addTypeProperty(obj->getTypeObject(), name, Valueify(value));
+    cx->addTypeProperty(obj->getType(), name, Valueify(value));
 }
 
 JS_PUBLIC_API(void)
 JS_AddTypePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value)
 {
-    cx->addTypePropertyId(obj->getTypeObject(), id, Valueify(value));
+    cx->addTypePropertyId(obj->getType(), id, Valueify(value));
 }
 
 static JSBool
 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                    JSObject **objp, JSProperty **propp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
@@ -3385,17 +3381,17 @@ JS_DefinePropertyWithTinyId(JSContext *c
 }
 
 static JSBool
 DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                  const Value &value, PropertyOp getter, PropertyOp setter, uintN attrs,
                  uintN flags, intN tinyid)
 {
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
-    cx->addTypePropertyId(obj->getTypeObject(), ATOM_TO_JSID(atom), value);
+    cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), value);
     return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
                                       flags, tinyid);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                     jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
 {
@@ -3426,27 +3422,21 @@ JS_DefineObject(JSContext *cx, JSObject 
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, proto);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &js_ObjectClass;    /* default class is Object */
 
-    TypeObject *type;
-    if (clasp == &js_FunctionClass)
-        type = cx->getTypeFunction(name);
-    else
-        type = cx->getTypeObject(name, /* :FIXME: wrong */ NULL);
-
-    JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj, type);
+    JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
     if (!nobj)
         return NULL;
 
-    cx->addTypeProperty(obj->getTypeObject(), name, ObjectValue(*nobj));
+    cx->addTypeProperty(obj->getType(), name, ObjectValue(*nobj));
     nobj->syncSpecialEquality();
 
     if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
         return NULL;
 
     return nobj;
 }
 
@@ -3457,17 +3447,17 @@ JS_DefineConstDoubles(JSContext *cx, JSO
     uintN attrs;
 
     CHECK_REQUEST(cx);
     for (ok = JS_TRUE; cds->name; cds++) {
         Value value = DoubleValue(cds->dval);
         attrs = cds->flags;
         if (!attrs)
             attrs = JSPROP_READONLY | JSPROP_PERMANENT;
-        cx->addTypeProperty(obj->getTypeObject(), cds->name, value);
+        cx->addTypeProperty(obj->getType(), cds->name, value);
         ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
         if (!ok)
             break;
     }
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -3490,17 +3480,17 @@ JS_DefineProperties(JSContext *cx, JSObj
             else if (ps->handler == JS_TypeHandlerInt)
                 type = TYPE_INT32;
             else if (ps->handler == JS_TypeHandlerFloat)
                 type = TYPE_DOUBLE;
             else if (ps->handler == JS_TypeHandlerString)
                 type = TYPE_STRING;
             JS_ASSERT(type);
 
-            cx->addTypeProperty(obj->getTypeObject(), ps->name, type);
+            cx->addTypeProperty(obj->getType(), ps->name, type);
         }
 #endif
     }
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *alias)
@@ -3535,17 +3525,17 @@ JS_AliasProperty(JSContext *cx, JSObject
         ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(aliasAtom),
                                    shape->getter(), shape->setter(), shape->slot,
                                    shape->attributes(), shape->getFlags() | Shape::ALIAS,
                                    shape->shortid)
               != NULL);
     }
 
     /* Alias the properties within the type information for the object. */
-    cx->aliasTypeProperties(obj->getTypeObject(), ATOM_TO_JSID(nameAtom), ATOM_TO_JSID(aliasAtom));
+    cx->aliasTypeProperties(obj->getType(), ATOM_TO_JSID(nameAtom), ATOM_TO_JSID(aliasAtom));
 
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
 {
     JSObject *obj2;
@@ -3982,18 +3972,17 @@ JS_NewPropertyIterator(JSContext *cx, JS
 {
     JSObject *iterobj;
     const void *pdata;
     jsint index;
     JSIdArray *ida;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_PROPERTY_ITERATOR);
-    iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj, type);
+    iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj);
     if (!iterobj)
         return NULL;
 
     if (obj->isNative()) {
         /* Native case: start with the last property in obj. */
         pdata = obj->lastProperty();
         index = -1;
     } else {
@@ -4069,24 +4058,23 @@ JS_PUBLIC_API(JSBool)
 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, v);
     return js_SetReservedSlot(cx, obj, index, Valueify(v));
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_NewArrayObjectWithType(JSContext *cx, jsint length, jsval *vector, JSTypeObject *jstype)
+JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
     CHECK_REQUEST(cx);
     /* NB: jsuint cast does ToUint32. */
     assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
-    TypeObject *type = Valueify(jstype);
-    return js_NewArrayObject(cx, (jsuint)length, Valueify(vector), type);
+    return js_NewArrayObject(cx, (jsuint)length, Valueify(vector));
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsArrayObject(JSContext *cx, JSObject *obj)
 {
     assertSameCompartment(cx, obj);
     return obj->isArray() ||
            (obj->isWrapper() && JSWrapper::wrappedObject(obj)->isArray());
@@ -4189,18 +4177,21 @@ JS_NewFunctionWithType(JSContext *cx, JS
 
     if (!name) {
         atom = NULL;
     } else {
         atom = js_Atomize(cx, name, strlen(name), 0);
         if (!atom)
             return NULL;
     }
-    if (!handler)
+    if (!handler) {
         handler = JS_TypeHandlerMissing;
+        if (!fullName)
+            fullName = "Unknown";
+    }
     return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom,
                           handler, fullName);
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_NewFunctionById(JSContext *cx, JSNative native, uintN nargs, uintN flags, JSObject *parent,
                    jsid id)
 {
@@ -4289,17 +4280,17 @@ JS_PUBLIC_API(void)
 JS_TypeHandlerMissing(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
     TypeFunction *fun = Valueify(jsfun);
     TypeCallsite *site = Valueify(jssite);
 
     /* Don't mark the return type as anything, and add a warning. */
     TypeFailure(cx, "Call to unimplemented handler at #%u:%05u: %s",
-                site->code->script->id, site->code->offset, TypeIdString(fun->name));
+                site->code->script->id, site->code->offset, fun->name());
 #endif
 }
 
 JS_PUBLIC_API(void) JS_TypeHandlerVoid(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
     TypeCallsite *site = Valueify(jssite);
     if (site->returnTypes)
@@ -4357,18 +4348,19 @@ JS_TypeHandlerNew(JSContext *cx, JSTypeF
 {
 #ifdef JS_TYPE_INFERENCE
     TypeFunction *fun = Valueify(jsfun);
     TypeCallsite *site = Valueify(jssite);
 
     if (!site->returnTypes)
         return;
 
-    TypeObject *object = fun->prototypeObject->getNewObject(cx);
-    site->returnTypes->addType(cx, (jstype) object);
+    TypeSet *prototypeTypes =
+        fun->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), true);
+    prototypeTypes->addNewObject(cx, *fun->pool, site->returnTypes);
 #endif
 }
 
 JS_PUBLIC_API(void)
 JS_TypeHandlerThis(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
     TypeCallsite *site = Valueify(jssite);
@@ -4502,35 +4494,34 @@ JS_DefineFunctionsWithPrefix(JSContext *
                                             flags & ~JSFUN_TRCINFO,
                                             fs->handler,
                                             genericName);
             if (!fun)
                 return JS_FALSE;
 
 #ifdef JS_TYPE_INFERENCE
             /* Mark the type handler for this function as generic. */
-            fun->getTypeObject()->asFunction()->isGeneric = true;
+            fun->getType()->asFunction()->isGeneric = true;
 #endif
 
             /*
              * As jsapi.h notes, fs must point to storage that lives as long
              * as fun->object lives.
              */
             Value priv = PrivateValue(fs);
             if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv))
                 return JS_FALSE;
         }
 
-#ifdef JS_TYPE_INFERENCE
+        char *fullName = NULL;
+#ifdef DEBUG
         JS_ASSERT(namePrefix);
         size_t fullLen = strlen(namePrefix) + strlen(fs->name) + 2;
-        char *fullName = (char*) alloca(fullLen);
+        fullName = (char*) alloca(fullLen);
         JS_snprintf(fullName, fullLen, "%s.%s", namePrefix, fs->name);
-#else
-        char *fullName = NULL;
 #endif
 
         fun = JS_DefineFunctionWithType(cx, obj, fs->name, fs->call, fs->nargs, flags,
                                         fs->handler, fullName);
         if (!fun)
             return JS_FALSE;
     }
     return JS_TRUE;
@@ -4848,20 +4839,18 @@ JS_CompileFileHandle(JSContext *cx, JSOb
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewScriptObject(JSContext *cx, JSScript *script)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, script);
-    if (!script) {
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_SCRIPT);
-        return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL, type);
-    }
+    if (!script)
+        return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
 
     /*
      * This function should only ever be applied to JSScripts that had
      * script objects allocated for them when they were created, as
      * described in the comment for JSScript::u.object.
      */
     JS_ASSERT(script->u.object);
     JS_ASSERT(script != JSScript::emptyScript());
@@ -4905,41 +4894,16 @@ JS_CompileUCFunctionForPrincipalsVersion
                                          const char *filename, uintN lineno,
                                          JSVersion version)
 {
     AutoVersionAPI avi(cx, version);
     return JS_CompileUCFunctionForPrincipals(cx, obj, principals, name, nargs, argnames, chars,
                                              length, filename, lineno);
 }
 
-JS_PUBLIC_API(JSTypeObject *)
-JS_MakeTypeObject(JSContext *cx, const char *name, JSBool unknownProperties, JSTypeObject *proto)
-{
-#ifdef JS_TYPE_INFERENCE
-    TypeObject *type = cx->getTypeObject(name, Valueify(proto));
-
-    if (unknownProperties)
-        cx->markTypeObjectUnknownProperties(type);
-
-    return (JSTypeObject*) type;
-#endif
-    return NULL;
-}
-
-JS_PUBLIC_API(JSTypeObject *)
-JS_MakeTypeFunction(JSContext *cx, const char *name, JSTypeHandler handler)
-{
-#ifdef JS_TYPE_INFERENCE
-    if (!handler)
-        handler = JS_TypeHandlerDynamic;
-    return (JSTypeObject*) cx->getTypeFunctionHandler(name, handler);
-#endif
-    return NULL;
-}
-
 JS_PUBLIC_API(JSFunction *)
 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
                                   JSPrincipals *principals, const char *name,
                                   uintN nargs, const char **argnames,
                                   const jschar *chars, size_t length,
                                   const char *filename, uintN lineno)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1960,92 +1960,55 @@ JS_GetObjectId(JSContext *cx, JSObject *
 
 extern JS_PUBLIC_API(JSObject *)
 JS_NewGlobalObject(JSContext *cx, JSClass *clasp);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals);
 
 extern JS_PUBLIC_API(JSObject *)
-JS_NewObjectWithType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent,
-                     JSTypeObject *type);
-
-static JS_ALWAYS_INLINE JSObject*
-JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
-{
-    return JS_NewObjectWithType(cx, clasp, proto, parent, NULL);
-}
+JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent);
 
 /* Queries the [[Extensible]] property of the object. */
 extern JS_PUBLIC_API(JSBool)
 JS_IsExtensible(JSObject *obj);
 
 /*
  * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default
  * proto if proto's actual parameter value is null.
  */
 extern JS_PUBLIC_API(JSObject *)
-JS_NewObjectWithGivenProtoAndType(JSContext *cx, JSClass *clasp,
-                                  JSObject *proto, JSObject *parent,
-                                  JSTypeObject *type);
-
-static JS_ALWAYS_INLINE JSObject*
 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
-                           JSObject *parent)
-{
-    return JS_NewObjectWithGivenProtoAndType(cx, clasp, proto, parent, NULL);
-}
+                           JSObject *parent);
 
 /*
  * Freeze obj, and all objects it refers to, recursively. This will not recurse
  * through non-extensible objects, on the assumption that those are already
  * deep-frozen.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_DeepFreezeObject(JSContext *cx, JSObject *obj);
 
 /*
  * Freezes an object; see ES5's Object.freeze(obj) method.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_FreezeObject(JSContext *cx, JSObject *obj);
 
 extern JS_PUBLIC_API(JSObject *)
-JS_ConstructObjectWithType(JSContext *cx, JSClass *clasp, JSObject *proto,
-                           JSObject *parent, JSTypeObject *type);
-
-static JS_ALWAYS_INLINE JSObject*
 JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
-                   JSObject *parent)
-{
-    return JS_ConstructObjectWithType(cx, clasp, proto, parent, NULL);
-}
+                   JSObject *parent);
 
 extern JS_PUBLIC_API(JSObject *)
-JS_ConstructObjectWithArgumentsAndType(JSContext *cx, JSClass *clasp, JSObject *proto,
-                                       JSObject *parent, JSTypeObject *type,
-                                       uintN argc, jsval *argv);
-
-static JS_ALWAYS_INLINE JSObject*
 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
-                                JSObject *parent, uintN argc, jsval *argv)
-{
-    return JS_ConstructObjectWithArgumentsAndType(cx, clasp, proto, parent,
-                                                  NULL, argc, argv);
-}
+                                JSObject *parent, uintN argc, jsval *argv);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv);
 
-extern JS_PUBLIC_API(JSTypeObject *)
-JS_MakeTypeObject(JSContext *cx, const char *name, JSBool unknownProperties, JSTypeObject *proto);
-
-extern JS_PUBLIC_API(JSTypeObject *)
-JS_MakeTypeFunction(JSContext *cx, const char *name, JSTypeHandler handler);
-
 extern JS_PUBLIC_API(JSObject *)
 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
                 JSObject *proto, uintN attrs);
 
 extern JS_PUBLIC_API(JSBool)
 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds);
 
 extern JS_PUBLIC_API(JSBool)
@@ -2298,24 +2261,17 @@ JS_SetUCProperty(JSContext *cx, JSObject
                  jsval *vp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
                      const jschar *name, size_t namelen,
                      jsval *rval);
 
 extern JS_PUBLIC_API(JSObject *)
-JS_NewArrayObjectWithType(JSContext *cx, jsint length, jsval *vector,
-                          JSTypeObject *type);
-
-static JS_ALWAYS_INLINE JSObject*
-JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
-{
-    return JS_NewArrayObjectWithType(cx, length, vector, NULL);
-}
+JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector);
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsArrayObject(JSContext *cx, JSObject *obj);
 
 extern JS_PUBLIC_API(JSBool)
 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp);
 
 extern JS_PUBLIC_API(JSBool)
@@ -2503,17 +2459,17 @@ JS_ObjectIsFunction(JSContext *cx, JSObj
 
 extern JS_PUBLIC_API(JSBool)
 JS_DefineFunctionsWithPrefix(JSContext *cx, JSObject *obj, JSFunctionSpec *fs,
                              const char *namePrefix);
 
 static JS_ALWAYS_INLINE JSBool
 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
 {
-    return JS_DefineFunctionsWithPrefix(cx, obj, fs, NULL);
+    return JS_DefineFunctionsWithPrefix(cx, obj, fs, "Unknown");
 }
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_DefineFunctionWithType(JSContext *cx, JSObject *obj,
                           const char *name, JSNative call,
                           uintN nargs, uintN attrs,
                           JSTypeHandler handler, const char *fullName);
 
@@ -3675,78 +3631,16 @@ JS_IsConstructing_PossiblyWithGivenThisO
  * object to create, it can request that the JS engine create a default new
  * 'this' object, as is done for non-constructor natives when called with new.
  */
 extern JS_PUBLIC_API(JSObject *)
 JS_NewObjectForConstructor(JSContext *cx, const jsval *vp);
 
 /************************************************************************/
 
-/*
- * Defines to tag type information for objects with the file/line at which
- * they were allocated, helpful for debugging.
- */
-
-#if JS_TYPE_INFERENCE && DEBUG
-
-#define JS_TYPE_FUNCTION_LINE(CX)                                             \
-    ({ size_t len = strlen(__FILE__) + 10;                                    \
-       char *name = (char*) alloca(len);                                      \
-       snprintf(name, len, "%s:%d", __FILE__, __LINE__);                      \
-       name; })
-
-#define JS_TYPE_OBJECT_LINE(CX)                                               \
-    ({ size_t len = strlen(__FILE__) + 10;                                    \
-       char *name = (char*) alloca(len);                                      \
-       snprintf(name, len, "%s:%d", __FILE__, __LINE__);                      \
-       JS_MakeTypeObject(CX, name, JS_FALSE, JS_FALSE); })
-
-#define JS_NewObject(cx,clasp,proto,parent)                                   \
-    JS_NewObjectWithType(cx, clasp, proto, parent, JS_TYPE_OBJECT_LINE(cx))
-
-#define JS_NewObjectWithGivenProto(cx,clasp,proto,parent)                     \
-    JS_NewObjectWithGivenProtoAndType(cx, clasp, proto, parent,               \
-                                      JS_TYPE_OBJECT_LINE(cx))
-
-#define JS_ConstructObject(cx,clasp,proto,parent)                             \
-    JS_ConstructObjectWithType(cx, clasp, proto, parent,                      \
-                               JS_TYPE_OBJECT_LINE(cx))
-
-#define JS_ConstructObjectWithArguments(cx,clasp,proto,parent,argc,argv)      \
-    JS_ConstructObjectWithArgumentsAndType(cx, clasp, proto, parent,          \
-                                           JS_TYPE_OBJECT_LINE(cx),           \
-                                           argc, argv);
-
-#define JS_NewArrayObject(cx,length,vector)                                   \
-    JS_NewArrayObjectWithType(cx, length, vector, JS_TYPE_OBJECT_LINE(cx))
-
-#define JS_NewFunction(cx,call,nargs,flags,parent,name)                       \
-    JS_NewFunctionWithType(cx, call, nargs, flags, parent, name,              \
-                           NULL, JS_TYPE_FUNCTION_LINE(cx))
-
-#define JS_DefineFunction(cx,obj,name,call,nargs,attrs)                       \
-    JS_DefineFunctionWithType(cx, obj, name, call, nargs, attrs,              \
-                              NULL, JS_TYPE_FUNCTION_LINE(cx))
-
-#define JS_DefineUCFunction(cx,obj,name,namelen,call,nargs,attrs)             \
-    JS_DefineUCFunctionWithType(cx, obj, name, namelen, call, nargs, attrs,   \
-                                NULL, JS_TYPE_FUNCTION_LINE(cx))
-
-#define JS_DefineFunctions(cx,obj,fs)                                         \
-    JS_DefineFunctionsWithPrefix(cx, obj, fs, JS_TYPE_FUNCTION_LINE(cx))
-
-#else /* JS_TYPE_INFERENCE && DEBUG */
-
-#define JS_TYPE_FUNCTION_LINE(cx) NULL
-#define JS_TYPE_OBJECT_LINE(cx) NULL
-
-#endif /* JS_TYPE_INFERENCE && DEBUG */
-
-/************************************************************************/
-
 #ifdef DEBUG
 #define JS_GC_ZEAL 1
 #endif
 
 #ifdef JS_GC_ZEAL
 extern JS_PUBLIC_API(void)
 JS_SetGCZeal(JSContext *cx, uint8 zeal);
 #endif
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1050,29 +1050,28 @@ Class js_SlowArrayClass = {
 /*
  * Convert an array object from fast-and-dense to slow-and-flexible.
  */
 JSBool
 JSObject::makeDenseArraySlow(JSContext *cx)
 {
     JS_ASSERT(isDenseArray());
 
-    cx->markTypeArrayNotPacked(getTypeObject(), true);
+    cx->markTypeArrayNotPacked(getType(), true);
     setDenseArrayNotPacked(cx);
 
     /*
      * Save old map now, before calling InitScopeForObject. We'll have to undo
      * on error. This is gross, but a better way is not obvious.
      */
     JSObjectMap *oldMap = map;
 
     /* Create a native scope. */
-    JSObject *arrayProto = getProto();
     js::gc::FinalizeKind kind = js::gc::FinalizeKind(arena()->header()->thingKind);
-    if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, kind))
+    if (!InitScopeForObject(cx, this, &js_SlowArrayClass, getType(), kind))
         return false;
 
     uint32 initlen = getDenseArrayInitializedLength();
 
     /*
      * Begin with the length property to share more of the property tree.
      * The getter/setter here will directly access the object's private value.
      */
@@ -1105,17 +1104,17 @@ JSObject::makeDenseArraySlow(JSContext *
             return false;
         }
 
         next++;
     }
 
     /* initialized length is not used anymore. */
     initializedLength = 0;
-    JS_ASSERT(emptyShapes == NULL);
+    JS_ASSERT(newType == NULL);
 
     /*
      * Dense arrays with different numbers of slots but the same number of fixed
      * slots and the same non-hole indexes must use their fixed slots consistently.
      */
     if (hasSlotsArray() && next <= numFixedSlots())
         revertToFixedSlots(cx);
 
@@ -2058,17 +2057,17 @@ array_push_slowly(JSContext *cx, JSObjec
 
     /* Per ECMA-262, return the new array length. */
     jsdouble newlength = length + jsdouble(argc);
     rval->setNumber(newlength);
 
     /* watch for length overflowing to a double, and report to type inference. */
     if (!rval->isInt32()) {
         cx->markTypeCallerOverflow();
-        cx->addTypeProperty(obj->getTypeObject(), "length", *rval);
+        cx->addTypeProperty(obj->getType(), "length", *rval);
     }
 
     return js_SetLengthProperty(cx, obj, newlength);
 }
 
 static JSBool
 array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval)
 {
@@ -2147,17 +2146,17 @@ static JSBool
 array_push(JSContext *cx, uintN argc, Value *vp)
 {
     /* Insist on one argument and obj of the expected class. */
     JSObject *obj = ComputeThisFromVp(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     if (cx->isTypeCallerMonitored())
-        cx->markTypeObjectUnknownProperties(obj->getTypeObject());
+        cx->markTypeObjectUnknownProperties(obj->getType());
 
     if (argc != 1 || !obj->isDenseArray())
         return array_push_slowly(cx, obj, argc, vp + 2, vp);
 
     return array_push1_dense(cx, obj, vp[2], vp);
 }
 
 static JSBool
@@ -2275,17 +2274,17 @@ array_unshift(JSContext *cx, uintN argc,
     JSBool hole;
     jsdouble last, newlen;
 
     JSObject *obj = ComputeThisFromVp(cx, vp);
     if (!obj || !js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     if (cx->isTypeCallerMonitored())
-        cx->markTypeObjectUnknownProperties(obj->getTypeObject());
+        cx->markTypeObjectUnknownProperties(obj->getType());
 
     newlen = length;
     if (argc > 0) {
         /* Slide up the array to make room for argc at the bottom. */
         argv = JS_ARGV(cx, vp);
         if (length > 0) {
             bool optimized = false;
             do {
@@ -2338,43 +2337,43 @@ array_unshift(JSContext *cx, uintN argc,
 static JSBool
 array_splice(JSContext *cx, uintN argc, Value *vp)
 {
     jsuint length, begin, end, count, delta, last;
     JSBool hole;
 
     JSObject *obj = ComputeThisFromVp(cx, vp);
 
-    /* Get the type object for the returned array. */
-    TypeObject *type = obj ? obj->getTypeObject() : NULL;
-
-#ifdef JS_TYPE_INFERENCE
-    if (!type || !type->isArray(cx)) {
+    /* Get the type of the result object. */
+    TypeObject *type;
+    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);
         cx->markTypeObjectUnknownProperties(type);
         cx->markTypeCallerUnexpected((jstype) type);
     }
-#endif
 
     if (cx->isTypeCallerMonitored())
         cx->markTypeObjectUnknownProperties(type);
 
     /*
      * Create a new array value to return.  Our ECMA v2 proposal specs
      * that splice always returns an array value, even when given no
      * arguments.  We think this is best because it eliminates the need
      * for callers to do an extra test to handle the empty splice case.
      */
-    JSObject *obj2 = js_NewArrayObject(cx, 0, NULL, type);
+    JSObject *obj2 = js_NewArrayObject(cx, 0, NULL);
     if (!obj2)
         return JS_FALSE;
+    obj2->setType(type);
     vp->setObject(*obj2);
 
     /* Nothing to do if no args.  Otherwise get length. */
     if (argc == 0)
         return JS_TRUE;
     Value *argv = JS_ARGV(cx, vp);
     if (!obj || !js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
@@ -2522,46 +2521,45 @@ array_splice(JSContext *cx, uintN argc, 
  * Python-esque sequence operations.
  */
 static JSBool
 array_concat(JSContext *cx, uintN argc, Value *vp)
 {
     /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */
     Value *p = JS_ARGV(cx, vp) - 1;
 
-    /* Get the type object to use for the result. */
-    TypeObject *ntype = cx->getTypeCallerInitObject(true);
-
-    if (cx->isTypeCallerMonitored())
-        cx->markTypeObjectUnknownProperties(ntype);
-
     /* Create a new Array object and root it using *vp. */
     JSObject *aobj = ComputeThisFromVp(cx, vp);
     JSObject *nobj;
     jsuint length;
     if (aobj->isDenseArray()) {
         length = aobj->getArrayLength();
         jsuint initlen = aobj->getDenseArrayInitializedLength();
-        nobj = js_NewArrayObject(cx, initlen, aobj->getDenseArrayElements(), ntype);
+        nobj = js_NewArrayObject(cx, initlen, aobj->getDenseArrayElements());
         if (!nobj)
             return JS_FALSE;
         nobj->setArrayLength(cx, length);
         vp->setObject(*nobj);
         if (argc == 0)
             return JS_TRUE;
         argc--;
         p++;
     } else {
-        nobj = js_NewArrayObject(cx, 0, NULL, ntype);
+        nobj = js_NewArrayObject(cx, 0, NULL);
         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 (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))
             return false;
         const Value &v = p[i];
         if (v.isObject()) {
@@ -2653,46 +2651,47 @@ array_slice(JSContext *cx, uintN argc, V
             end = (jsuint)d;
         }
     }
 
     if (begin > end)
         begin = end;
 
     /* Get the type object for the returned array. */
-    TypeObject *type = obj->getTypeObject();
-
-#ifdef JS_TYPE_INFERENCE
-    if (!type->isArray(cx)) {
+    TypeObject *type;
+    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);
         cx->markTypeObjectUnknownProperties(type);
         cx->markTypeCallerUnexpected((jstype) type);
     }
-#endif
 
     if (cx->isTypeCallerMonitored())
         cx->markTypeObjectUnknownProperties(type);
 
     if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
         !js_PrototypeHasIndexedProperties(cx, obj)) {
-        nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin, type);
+        nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin);
         if (!nobj)
             return JS_FALSE;
+        nobj->setType(type);
         vp->setObject(*nobj);
         return JS_TRUE;
     }
 
     /* Create a new Array object and root it using *vp. */
-    nobj = js_NewArrayObject(cx, 0, NULL, type);
+    nobj = js_NewArrayObject(cx, 0, NULL);
     if (!nobj)
         return JS_FALSE;
+    nobj->setType(type);
     vp->setObject(*nobj);
 
     AutoValueRooter tvr(cx);
     for (slot = begin; slot < end; slot++) {
         if (!JS_CHECK_OPERATION_LIMIT(cx) ||
             !GetElement(cx, obj, slot, &hole, tvr.addr())) {
             return JS_FALSE;
         }
@@ -2860,20 +2859,21 @@ array_extra(JSContext *cx, ArrayExtraMod
                                      JSMSG_EMPTY_ARRAY_REDUCE);
                 return JS_FALSE;
             }
         }
         break;
       case MAP:
       case FILTER:
         newlen = (mode == MAP) ? length : 0;
-        newtype = cx->getTypeCallerInitObject(true);
-        newarr = js_NewArrayObject(cx, newlen, NULL, newtype);
+        newarr = js_NewArrayObject(cx, newlen, NULL);
         if (!newarr)
             return JS_FALSE;
+        newtype = cx->getTypeCallerInitObject(true);
+        newarr->setType(newtype);
         vp->setObject(*newarr);
         break;
       case SOME:
         vp->setBoolean(false);
         break;
       case EVERY:
         vp->setBoolean(true);
         break;
@@ -3041,37 +3041,37 @@ static void array_TypeSort(JSContext *cx
     if (site->returnTypes)
         site->thisTypes->addSubset(cx, site->pool(), site->returnTypes);
 
     if (site->argumentCount == 0)
         return;
 
     TypeSet *funTypes = site->argumentTypes[0];
 
-    // make a callsite for the calls to the sorting function this will perform.
-    jstype globalType = (jstype) cx->getGlobalTypeObject();
+    /* Make a callsite for the calls to the sorting function this will perform. */
+    jstype globalType = (jstype) cx->globalTypeObject();
     TypeCallsite *sortSite = ArenaNew<TypeCallsite>(site->pool(), site->code, false, 2);
     sortSite->thisType = globalType;
 
-    // both arguments to the argument function are array elements.
+    /* Both arguments to the argument function are array elements. */
     TypeSet *argTypes = sortSite->argumentTypes[0] = sortSite->argumentTypes[1] =
         TypeSet::make(cx, site->pool(), "ArraySort");
     site->thisTypes->addGetProperty(cx, site->code, argTypes, JSID_VOID);
 
     funTypes->addCall(cx, sortSite);
 #endif
 }
 
 static void array_TypeInsert(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
     TypeCallsite *site = Valueify(jssite);
 
     if (site->returnTypes) {
-        // the return type is an integer (array length).
+        /* The return type is an integer (array length). */
         site->returnTypes->addType(cx, TYPE_INT32);
     }
 
     site->forceThisTypes(cx);
 
     for (size_t ind = 0; ind < site->argumentCount; ind++)
         site->thisTypes->addSetProperty(cx, site->code, site->argumentTypes[ind], JSID_VOID);
 #endif
@@ -3095,21 +3095,21 @@ static void array_TypeRemove(JSContext *
 static void array_TypeSplice(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
     TypeCallsite *site = Valueify(jssite);
 
     site->forceThisTypes(cx);
 
     if (site->returnTypes) {
-        // treat the returned array the same as the 'this' array.
+        /* Treat the returned array the same as the 'this' array. */
         site->thisTypes->addSubset(cx, site->pool(), site->returnTypes);
     }
 
-    // all arguments beyond the first two are new array elements.
+    /* All arguments beyond the first two are new array elements. */
     for (size_t ind = 2; ind < site->argumentCount; ind++)
         site->thisTypes->addSetProperty(cx, site->code, site->argumentTypes[ind], JSID_VOID);
 #endif
 }
 
 static void array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
@@ -3128,108 +3128,114 @@ static void array_TypeConcat(JSContext *
     site->thisTypes->addGetProperty(cx, site->code, indexTypes, JSID_VOID);
 
     /* Ditto for all arguments to the call. */
     for (size_t ind = 0; ind < site->argumentCount; ind++)
         site->argumentTypes[ind]->addGetProperty(cx, site->code, indexTypes, JSID_VOID);
 #endif
 }
 
-// general purpose handler for all higher order array builtins.
+/* Handler for all higher order array builtins. */
 static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite,
                             ArrayExtraMode mode)
 {
 #ifdef JS_TYPE_INFERENCE
     TypeCallsite *site = Valueify(jssite);
     analyze::Bytecode *code = site->code;
 
     JSArenaPool &pool = site->pool();
 
     if (site->argumentCount == 0)
         return;
     TypeSet *funTypes = site->argumentTypes[0];
 
-    // get a type set of all possible element types of this array, and the
-    // singleton type of array indexes.
+    /*
+     * Get a type set of all possible element types of this array, and the singleton
+     * type of array indexes.
+     */
     TypeSet *elemTypes = TypeSet::make(cx, pool, "array_extra");
     TypeSet *intTypes = TypeSet::make(cx, pool, "array_extra_int");
     intTypes->addType(cx, TYPE_INT32);
 
     site->forceThisTypes(cx);
     site->forceReturnTypes(cx);
 
     site->thisTypes->addGetProperty(cx, code, elemTypes, JSID_VOID);
 
-    // make the call site to use for the higher order function.
+    /* Make the call site to use for the higher order function. */
     TypeCallsite *extraSite = ArenaNew<TypeCallsite>(pool, code, false, REDUCE_MODE(mode) ? 4 : 3);
 
-    // figure out the 'this' type passed to the higher order function.
+    /* Figure out the 'this' type passed to the higher order function. */
     if (site->argumentCount > 1 && !REDUCE_MODE(mode))
         extraSite->thisTypes = site->argumentTypes[1];
     else
-        extraSite->thisType = (jstype) cx->getGlobalTypeObject();
+        extraSite->thisType = (jstype) cx->globalTypeObject();
 
     switch (mode) {
 
       case FOREACH:
         site->returnTypes->addType(cx, TYPE_UNDEFINED);
         break;
 
       case REDUCE: {
-        // the return value of the function is also the return value of the reduce call.
+        /* The return value of the function is also the return value of the reduce call. */
         extraSite->returnTypes = site->returnTypes;
 
-        // the first argument of the function is either its own return value,
-        // the second argument of reduce, or the array element type (if there
-        // is no second argument of reduce).
+        /*
+         * The first argument of the function is either its own return value, the second
+         * argument of reduce, or the array element type (if there is no second argument
+         * of reduce).
+         */
         extraSite->argumentTypes[0] = TypeSet::make(cx, pool, "ArrayReduce");
         site->returnTypes->addSubset(cx, pool, extraSite->argumentTypes[0]);
 
         TypeSet *initialTypes = NULL;
         if (site->argumentCount >= 2)
             initialTypes = site->argumentTypes[1];
         else
             initialTypes = elemTypes;
         initialTypes->addSubset(cx, pool, extraSite->argumentTypes[0]);
         initialTypes->addSubset(cx, pool, site->returnTypes);
         break;
       }
 
       case MAP: {
-        // makes a new array whose element type is the return value of the
-        // argument function.
+        /* Makes a new array whose element type is the return value of the argument function. */
         TypeObject *object = site->getInitObject(cx, true);
         extraSite->returnTypes = object->getProperty(cx, JSID_VOID, true);
 
         site->returnTypes->addType(cx, (jstype) object);
         break;
       }
 
       case FILTER: {
-        // makes a new array, whose element type is the same as the element
-        // type of the 'this' array. TODO: could use the same type information
-        // as the 'this' array, but might run into problems when we're able
-        // to handle receiver types other than arrays.
+        /*
+         * Makes a new array, whose element type is the same as the element type of the
+         * 'this' array. TODO: could use the same type information as the 'this' array,
+         * but might run into problems when we're able to handle receiver types other than arrays.
+         */
         TypeObject *object = site->getInitObject(cx, true);
         elemTypes->addSubset(cx, pool, object->getProperty(cx, JSID_VOID, true));
 
         site->returnTypes->addType(cx, (jstype) object);
         break;
       }
 
       case SOME:
         site->returnTypes->addType(cx, TYPE_BOOLEAN);
         break;
 
       default:
         JS_NOT_REACHED("Unexpected ArrayExtraMode");
     }
 
-    // fill in the remaining argument types. regardless of mode, the last three
-    // arguments are the element value, element index, and array itself.
+    /*
+     * Fill in the remaining argument types. regardless of mode, the last three
+     * arguments are the element value, element index, and array itself.
+     */
     size_t argind = (mode == REDUCE) ? 1 : 0;
     extraSite->argumentTypes[argind++] = elemTypes;
     extraSite->argumentTypes[argind++] = intTypes;
     extraSite->argumentTypes[argind++] = site->thisTypes;
     JS_ASSERT(argind == extraSite->argumentCount);
 
     funTypes->addCall(cx, extraSite);
 #endif
@@ -3311,20 +3317,20 @@ static JSFunctionSpec array_methods[] = 
 
 static JSFunctionSpec array_static_methods[] = {
     JS_FN_TYPE("isArray",            array_isArray,      1,0, JS_TypeHandlerBool),
     JS_FS_END
 };
 
 /* The count here is a guess for the final capacity. */
 static inline JSObject *
-NewDenseArrayObject(JSContext *cx, TypeObject *type, jsuint count)
+NewDenseArrayObject(JSContext *cx, jsuint count)
 {
     gc::FinalizeKind kind = GuessObjectGCKind(count, true);
-    return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, type, kind);
+    return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
 }
 
 JSBool
 js_Array(JSContext *cx, uintN argc, Value *vp)
 {
     jsuint length;
     const Value *vector;
 
@@ -3348,53 +3354,56 @@ js_Array(JSContext *cx, uintN argc, Valu
             return JS_FALSE;
         vector = NULL;
     }
 
     if (cx->isTypeCallerMonitored() && vector)
         cx->markTypeObjectUnknownProperties(type);
 
     /* Whether called with 'new' or not, use a new Array object. */
-    JSObject *obj = NewDenseArrayObject(cx, type, length);
+    JSObject *obj = NewDenseArrayObject(cx, length);
     if (!obj)
         return JS_FALSE;
+    obj->setType(type);
     vp->setObject(*obj);
 
     return InitArrayObject(cx, obj, length, vector);
 }
 
 JSObject* JS_FASTCALL
 js_NewEmptyArray(JSContext* cx, JSObject* proto, int32 len)
 {
     if (len < 0)
         return NULL;
 
     JS_ASSERT(proto->isArray());
 
+    TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return NULL;
+
     gc::FinalizeKind kind = GuessObjectGCKind(len, true);
     JSObject* obj = js_NewGCObject(cx, kind);
     if (!obj)
         return NULL;
 
-    // TODO: pass type object to use in from tracer.
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_UNKNOWN_ARRAY);
-
     /* Initialize all fields, calling init before setting obj->map. */
-    obj->init(cx, &js_ArrayClass, proto, proto->getParent(), type, (void*) len, true);
+    obj->init(cx, &js_ArrayClass, type, proto->getParent(), (void*) len, true);
     obj->setSharedNonNativeMap();
     return obj;
 }
 #ifdef JS_TRACER
 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewEmptyArray, CONTEXT, OBJECT, INT32, 0,
                      nanojit::ACCSET_STORE_ANY)
 #endif
 
 JSObject* JS_FASTCALL
 js_NewPreallocatedArray(JSContext* cx, JSObject* proto, int32 len)
 {
+    /* :FIXME: new Arrays do not have the right type when created on trace. */
     JSObject *obj = js_NewEmptyArray(cx, proto, len);
     if (!obj)
         return NULL;
 
     /* Avoid ensureDenseArrayElements to skip sparse array checks there. */
     if (!obj->ensureSlots(cx, len))     
         return NULL;
     ClearValueRange(obj->getDenseArrayElements(), len, true);
@@ -3434,51 +3443,47 @@ static void array_TypeNew(JSContext *cx,
 JSObject *
 js_InitArrayClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto = js_InitClass(cx, obj, NULL, &js_ArrayClass, js_Array, 1, array_TypeNew,
                                    NULL, array_methods, NULL, array_static_methods);
     if (!proto)
         return NULL;
 
-    /*
-     * Assert that js_InitClass used the correct (slow array, not dense array)
-     * class for proto's emptyShape class.
-     */
-    JS_ASSERT(proto->emptyShapes && proto->emptyShapes[0]->getClass() == proto->getClass());
-
     JS_AddTypeProperty(cx, proto, "length", INT_TO_JSVAL(0));
     proto->setArrayLength(cx, 0);
+
+    /* The default 'new' object for Array.prototype has unknown properties. */
+    cx->markTypeObjectUnknownProperties(proto->getNewType(cx));
+
     return proto;
 }
 
 JSObject *
-js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector, TypeObject *type)
+js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
 {
-    JSObject *obj = NewDenseArrayObject(cx, type, length);
+    JSObject *obj = NewDenseArrayObject(cx, length);
     if (!obj)
         return NULL;
 
     /*
      * If this fails, the global object was not initialized and its class does
      * not have JSCLASS_IS_GLOBAL.
      */
     JS_ASSERT(obj->getProto());
 
     return InitArrayObject(cx, obj, length, vector) ? obj : NULL;
 }
 
 JSObject *
-js_NewSlowArrayObject(JSContext *cx, TypeObject *type)
+js_NewSlowArrayObject(JSContext *cx)
 {
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL, type);
+    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL);
     if (obj)
         obj->setArrayLength(cx, 0);
-
-    cx->markTypeArrayNotPacked(type, true);
     return obj;
 }
 
 #ifdef DEBUG
 JSBool
 js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp)
 {
     uintN i;
@@ -3619,15 +3624,16 @@ js_CloneDensePrimitiveArray(JSContext *c
              */
             *clone = NULL;
             return JS_TRUE;
         }
 
         vector.append(val);
     }
 
-    *clone = js_NewArrayObject(cx, initlen, vector.begin(), obj->getTypeObject());
+    *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/jsarray.h
+++ b/js/src/jsarray.h
@@ -73,17 +73,17 @@ JSObject::isPackedDenseArray()
 }
 
 inline void
 JSObject::setDenseArrayNotPacked(JSContext *cx)
 {
     JS_ASSERT(isDenseArray());
     if (flags & PACKED_ARRAY) {
         flags ^= PACKED_ARRAY;
-        cx->markTypeArrayNotPacked(getTypeObject(), false);
+        cx->markTypeArrayNotPacked(getType(), false);
     }
 }
 
 inline JSObject::EnsureDenseResult
 JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
 {
     JS_ASSERT(isDenseArray());
     uintN currentCapacity = numSlots();
@@ -219,34 +219,31 @@ JSObject::isArray() const
  * (to wit, Array.prototype) in which to probe for cached methods.
  *
  * Note that setting aobj.__proto__ for a dense array aobj turns aobj into a
  * slow array, avoiding the neede to skip.
  *
  * Callers of js_GetProtoIfDenseArray must take care to use the original object
  * (obj) for the |this| value of a getter, setter, or method call (bug 476447).
  */
-static JS_INLINE JSObject *
-js_GetProtoIfDenseArray(JSObject *obj)
-{
-    return obj->isDenseArray() ? obj->getProto() : obj;
-}
+inline JSObject *
+js_GetProtoIfDenseArray(JSObject *obj);
 
 extern JSObject *
 js_InitArrayClass(JSContext *cx, JSObject *obj);
 
 extern bool
 js_InitContextBusyArrayTable(JSContext *cx);
 
 extern JSObject *
-js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector, js::types::TypeObject *type);
+js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector);
 
 /* Create an array object that starts out already made slow/sparse. */
 extern JSObject *
-js_NewSlowArrayObject(JSContext *cx, js::types::TypeObject *type);
+js_NewSlowArrayObject(JSContext *cx);
 
 extern JSBool
 js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
 
 extern JSBool
 js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length);
 
 extern JSBool
@@ -354,18 +351,17 @@ js_Array(JSContext *cx, uintN argc, js::
  * that the resulting array has length and count both equal to |capacity|.
  *
  * FIXME: for some strange reason, when this file is included from
  * dom/ipc/TabParent.cpp in MSVC, jsuint resolves to a slightly different
  * builtin than when mozjs.dll is built, resulting in a link error in xul.dll.
  * It would be useful to find out what is causing this insanity.
  */
 JS_FRIEND_API(JSObject *)
-js_NewArrayObjectWithCapacity(JSContext *cx, uint32_t capacity, jsval **vector,
-                              js::types::TypeObject *type);
+js_NewArrayObjectWithCapacity(JSContext *cx, uint32_t capacity, jsval **vector);
 
 /*
  * Makes a fast clone of a dense array as long as the array only contains
  * primitive values.
  *
  * If the return value is JS_FALSE then clone will not be set.
  *
  * If the return value is JS_TRUE then clone will either be set to the address
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -133,38 +133,34 @@ static JSFunctionSpec boolean_methods[] 
 
 static JSBool
 Boolean(JSContext *cx, uintN argc, Value *vp)
 {
     Value *argv = vp + 2;
     bool b = argc != 0 ? js_ValueToBoolean(argv[0]) : false;
 
     if (IsConstructing(vp)) {
-        TypeObject *objType = cx->getFixedTypeObject(TYPE_OBJECT_NEW_BOOLEAN);
-        JSObject *obj = NewBuiltinClassInstance(cx, &js_BooleanClass, objType);
+        JSObject *obj = NewBuiltinClassInstance(cx, &js_BooleanClass);
         if (!obj)
             return false;
         obj->setPrimitiveThis(BooleanValue(b));
         vp->setObject(*obj);
     } else {
         vp->setBoolean(b);
     }
     return true;
 }
 
 static void type_NewBoolean(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
-    TypeCallsite *site = Valueify(jssite);
-    if (site->isNew) {
-        TypeObject *object = cx->getFixedTypeObject(TYPE_OBJECT_NEW_BOOLEAN);
-        site->returnTypes->addType(cx, (jstype) object);
-    } else {
+    if (Valueify(jssite)->isNew)
+        JS_TypeHandlerNew(cx, jsfun, jssite);
+    else
         JS_TypeHandlerBool(cx, jsfun, jssite);
-    }
 #endif
 }
 
 JSObject *
 js_InitBooleanClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto = js_InitClass(cx, obj, NULL, &js_BooleanClass, Boolean, 1, type_NewBoolean,
                                    NULL, boolean_methods, NULL, NULL);
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -286,22 +286,25 @@ js_NewNullClosure(JSContext* cx, JSObjec
 {
     JS_ASSERT(funobj->isFunction());
     JS_ASSERT(proto->isFunction());
     JS_ASSERT(JS_ON_TRACE(cx));
 
     JSFunction *fun = (JSFunction*) funobj;
     JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
 
+    types::TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return NULL;
+
     JSObject* closure = js_NewGCObject(cx, gc::FINALIZE_OBJECT2);
     if (!closure)
         return NULL;
 
-    types::TypeObject *type = cx->getFixedTypeObject(types::TYPE_OBJECT_NULL_CLOSURE);
-    if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, proto, parent, type,
+    if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, type, parent,
                                         fun, gc::FINALIZE_OBJECT2)) {
         return NULL;
     }
     return closure;
 }
 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT,
                      0, ACCSET_STORE_ANY)
 
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -751,27 +751,25 @@ JSStructuredCloneReader::startRead(Value
         JSObject *obj = RegExp::createObjectNoStatics(context(), chars, length, data);
         if (!obj)
             return false;
         vp->setObject(*obj);
         break;
       }
 
       case SCTAG_ARRAY_OBJECT: {
-        types::TypeObject *objType = context()->getFixedTypeObject(types::TYPE_OBJECT_CLONE_ARRAY);
-        JSObject *obj = js_NewArrayObject(context(), 0, NULL, objType);
+        JSObject *obj = js_NewArrayObject(context(), 0, NULL);
         if (!obj || !objs.append(ObjectValue(*obj)))
             return false;
         vp->setObject(*obj);
         break;
       }
 
       case SCTAG_OBJECT_OBJECT: {
-        types::TypeObject *objType = context()->getFixedTypeObject(types::TYPE_OBJECT_CLONE_OBJECT);
-        JSObject *obj = NewBuiltinClassInstance(context(), &js_ObjectClass, objType);
+        JSObject *obj = NewBuiltinClassInstance(context(), &js_ObjectClass);
         if (!obj || !objs.append(ObjectValue(*obj)))
             return false;
         vp->setObject(*obj);
         break;
       }
 
       case SCTAG_ARRAY_BUFFER_OBJECT:
         return readArrayBuffer(data, vp);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -2389,48 +2389,39 @@ private:
      * when p is null or that a memory pressure counter has reached some
      * threshold when p is not null. The function takes the pointer and not
      * a boolean flag to minimize the amount of code in its inlined callers.
      */
     JS_FRIEND_API(void) checkMallocGCPressure(void *p);
 
 public:
 
-    /*
-     * Definitions for type inference.  The implementations of these are no-ops
-     * when inference is not enabled.
-     */
-
-    /* Get the type object shared by all globals in the compartment. */
-    inline js::types::TypeObject *
-    getGlobalTypeObject();
-
-    /* Get a fixed singleton type object. */
-    inline js::types::TypeObject *
-    getFixedTypeObject(js::types::FixedTypeObjectName which);
+    /* Make a type function or object with the specified name. */
+    js::types::TypeFunction *newTypeFunction(const char *name, JSObject *proto);
+    js::types::TypeObject   *newTypeObject(const char *name, JSObject *proto);
+
+    /* Make a type object whose name is that of base followed by postfix. */
+    js::types::TypeObject *newTypeObject(const char *base, const char *postfix, JSObject *proto);
+
+    /* Get the default 'new' object for a given standard class. */
+    inline js::types::TypeObject *getTypeNewObject(JSProtoKey key);
 
     /*
-     * Get a type object or function with the specified name.  Fetching the same
-     * name repeatedly will produce the same value.
+     * Get the type of the global object to use. :XXX: This function is probably
+     * totally broken when analyzing code involved with multiple global objects.
+     * It uses cx->globalObject even if that's not the global object attached to the
+     * COMPILE_N_GO script being analyzed.
      */
-
-    /* Get a function or non-function object. */
-    inline js::types::TypeObject *getTypeFunction(const char *name,
-                                                  js::types::TypeObject *prototype = NULL);
-    inline js::types::TypeObject *getTypeObject(const char *name,
-                                                js::types::TypeObject *prototype);
-
-    /* Get a function with the specified handler. */
-    inline js::types::TypeFunction *
-    getTypeFunctionHandler(const char *name, JSTypeHandler handler,
-                           js::types::TypeObject *prototype = NULL);
+    inline js::types::TypeObject *globalTypeObject();
+
+    /* Get a singleton type object to use for objects with no prototype. */
+    inline js::types::TypeObject *emptyTypeObject();
 
     /* Set the type information for fun to the specified script. */
-    inline void
-    setTypeFunctionScript(JSFunction *fun, JSScript *script);
+    inline void setTypeFunctionScript(JSFunction *fun, JSScript *script);
 
     /* Get a type object for the immediate allocation site in this context. */
     inline js::types::TypeObject *
     getTypeCallerInitObject(bool isArray);
 
     /* Whether the immediate caller is being monitored for side effects. */
     inline bool isTypeCallerMonitored();
 
@@ -2443,32 +2434,25 @@ public:
      * Monitor a javascript call, either on entry to the interpreter or made
      * from within the interpreter.
      */
     inline void typeMonitorCall(JSScript *caller, const jsbytecode *callerpc,
                                 const js::CallArgs &args, bool constructing, bool force);
     inline void typeMonitorEntry(JSScript *script);
     inline void typeMonitorEntry(JSScript *script, const js::Value &thisv);
 
-    /*
-     * Mark a function as the constructor for a builtin class, whose 'prototype'
-     * field is specified manually with setTypeFunctionPrototype.
-     */
-    inline void markTypeBuiltinFunction(js::types::TypeObject *fun);
-
-    /* Add proto as the 'prototype' field of a function. */
-    inline void setTypeFunctionPrototype(js::types::TypeObject *fun,
-                                         js::types::TypeObject *proto);
-
     /* Add a possible value for the named property of obj. */
     inline void addTypeProperty(js::types::TypeObject *obj, const char *name, js::types::jstype type);
     inline void addTypeProperty(js::types::TypeObject *obj, const char *name, const js::Value &value);
     inline void addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jstype type);
     inline void addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value);
 
+    /* Get the type to add for properties which can be scripted getters/setters. */
+    inline js::types::TypeObject *getTypeGetSet();
+
     /* Alias two properties in the type information for obj. */
     inline void aliasTypeProperties(js::types::TypeObject *obj, jsid first, jsid second);
 
     /* Mark an array type as being not packed and, possibly, not dense. */
     inline void markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense, bool dynamic = true);
 
     /* Monitor all properties of a type object as unknown. */
     inline void markTypeObjectUnknownProperties(js::types::TypeObject *obj);
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -73,19 +73,17 @@ JSCompartment::init()
     chunk = NULL;
     for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
         arenas[i].init();
     for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
         freeLists.finalizables[i] = NULL;
 #ifdef JS_GCMETER
     memset(&compartmentStats, 0, sizeof(JSGCArenaStats) * FINALIZE_LIMIT);
 #endif
-#ifdef JS_TYPE_INFERENCE
     types.init();
-#endif
     if (!crossCompartmentWrappers.init())
         return false;
 
 #ifdef JS_METHODJIT
     if (!(jaegerCompartment = new mjit::JaegerCompartment))
         return false;
     return jaegerCompartment->Initialize();
 #else
@@ -236,17 +234,16 @@ JSCompartment::wrap(JSContext *cx, Value
      * to the object.
      */
     JSObject *wrapper = cx->runtime->wrapObjectCallback(cx, obj, proto, global, flags);
     if (!wrapper)
         return false;
 
     vp->setObject(*wrapper);
 
-    wrapper->setProto(cx, proto);
     if (!crossCompartmentWrappers.put(wrapper->getProxyPrivate(), *vp))
         return false;
 
     wrapper->setParent(global);
     return true;
 }
 
 bool
@@ -341,23 +338,27 @@ JSCompartment::sweep(JSContext *cx)
                      !IsAboutToBeFinalized(e.front().value.toGCThing()),
                      e.front().key.isString());
         if (IsAboutToBeFinalized(e.front().key.toGCThing()) ||
             IsAboutToBeFinalized(e.front().value.toGCThing())) {
             e.removeFront();
         }
     }
 
-#if defined JS_METHODJIT && defined JS_MONOIC
     for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
         JSScript *script = reinterpret_cast<JSScript *>(cursor);
+#if defined JS_METHODJIT && defined JS_MONOIC
         if (script->hasJITCode())
             mjit::ic::SweepCallICs(script);
+#endif
+        if (script->analysis)
+            script->analysis->sweep(cx);
     }
-#endif
+
+    types.sweep(cx);
 }
 
 void
 JSCompartment::purge(JSContext *cx)
 {
     freeLists.purge();
 
 #ifdef JS_METHODJIT
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -67,20 +67,18 @@ struct JS_FRIEND_API(JSCompartment) {
 
     js::gc::ArenaList            arenas[js::gc::FINALIZE_LIMIT];
     js::gc::FreeLists            freeLists;
 
 #ifdef JS_GCMETER
     js::gc::JSGCArenaStats       compartmentStats[js::gc::FINALIZE_LIMIT];
 #endif
 
-#ifdef JS_TYPE_INFERENCE
     /* Type information about the scripts and objects in this compartment. */
     js::types::TypeCompartment   types;
-#endif
 
     void                         *data;
     bool                         marked;
     js::WrapperMap               crossCompartmentWrappers;
 
 #ifdef JS_METHODJIT
     js::mjit::JaegerCompartment  *jaegerCompartment;
 #endif
@@ -149,25 +147,9 @@ class SwitchToCompartment : public Prese
 
     SwitchToCompartment(JSContext *cx, JSObject *target) : PreserveCompartment(cx) {
         cx->compartment = target->getCompartment();
     }
 };
 
 }
 
-inline js::types::TypeObject *
-JSContext::getFixedTypeObject(js::types::FixedTypeObjectName which)
-{
-#ifdef JS_TYPE_INFERENCE
-    JS_ASSERT(which < js::types::TYPE_OBJECT_FIXED_LIMIT);
-    js::types::TypeObject *type = compartment->types.fixedTypeObjects[which];
-    if (type)
-        return type;
-    type = compartment->types.makeFixedTypeObject(this, which);
-    compartment->types.fixedTypeObjects[which] = type;
-    return type;
-#else
-    return NULL;
-#endif
-}
-
 #endif /* jscompartment_h___ */
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2547,23 +2547,20 @@ js_Date(JSContext *cx, uintN argc, Value
     vp->setObject(*obj);
 
     return true;
 }
 
 static void type_NewDate(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
-    TypeCallsite *site = Valueify(jssite);
-    if (site->isNew) {
-        TypeObject *object = Valueify(jsfun)->prototypeObject->getNewObject(cx);
-        site->returnTypes->addType(cx, (jstype) object);
-    } else {
+    if (Valueify(jssite)->isNew)
+        JS_TypeHandlerNew(cx, jsfun, jssite);
+    else
         JS_TypeHandlerString(cx, jsfun, jssite);
-    }
 #endif
 }
 
 JSObject *
 js_InitDateClass(JSContext *cx, JSObject *obj)
 {
     /* set static LocalTZA */
     LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
@@ -2586,25 +2583,25 @@ js_InitDateClass(JSContext *cx, JSObject
     AutoValueRooter toUTCStringFun(cx);
     jsid toUTCStringId = ATOM_TO_JSID(cx->runtime->atomState.toUTCStringAtom);
     jsid toGMTStringId = ATOM_TO_JSID(cx->runtime->atomState.toGMTStringAtom);
     if (!js_GetProperty(cx, proto, toUTCStringId, toUTCStringFun.addr()) ||
         !js_DefineProperty(cx, proto, toGMTStringId, toUTCStringFun.addr(),
                            PropertyStub, PropertyStub, 0)) {
         return NULL;
     }
-    cx->addTypePropertyId(proto->getTypeObject(), toGMTStringId, toUTCStringFun.value());
+    cx->addTypePropertyId(proto->getType(), toGMTStringId, toUTCStringFun.value());
 
     return proto;
 }
 
 JS_FRIEND_API(JSObject *)
 js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
 {
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_DateClass, NULL);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_DateClass);
     if (!obj || !obj->ensureSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
         return NULL;
     if (!SetUTCTime(cx, obj, msec_time))
         return NULL;
     return obj;
 }
 
 JS_FRIEND_API(JSObject *)
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -782,17 +782,17 @@ WrapWatchedSetter(JSContext *cx, jsid id
             return NULL;
         atom = JSID_TO_ATOM(id);
     } else {
         atom = NULL;
     }
 
     wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
                              setter ? CastAsObject(setter)->getParent() : NULL, atom,
-                             JS_TypeHandlerMissing, JS_TYPE_FUNCTION_LINE(cx));
+                             JS_TypeHandlerMissing, "SetWrapper");
     if (!wrapper)
         return NULL;
     return CastAsPropertyOp(FUN_OBJECT(wrapper));
 }
 
 static bool
 UpdateWatchpointShape(JSContext *cx, JSWatchPoint *wp, const js::Shape *newShape)
 {
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -6876,18 +6876,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
         /*
          * Try to construct the shape of the object as we go, so we can emit a
          * JSOP_NEWOBJECT with the final shape instead.
          */
         JSObject *obj = NULL;
         if (!cg->hasSharps() && cg->compileAndGo()) {
             gc::FinalizeKind kind = GuessObjectGCKind(pn->pn_count, false);
-            types::TypeObject *type = cx->getFixedTypeObject(types::TYPE_OBJECT_UNKNOWN_OBJECT);
-            obj = NewBuiltinClassInstance(cx, &js_ObjectClass, type, kind);
+            obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
             if (!obj)
                 return JS_FALSE;
         }
 
         uintN methodInits = 0, slowMethodInits = 0;
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
             pn3 = pn2->pn_left;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -714,18 +714,17 @@ Exception(JSContext *cx, uintN argc, Val
      * class prototype ourselves.
      */
     JSObject &callee = vp[0].toObject();
     Value protov;
     if (!callee.getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov))
         return JS_FALSE;
 
     JSObject *errProto = &protov.toObject();
-    TypeObject *type = errProto->getTypePrototypeNewObject(cx);
-    JSObject *obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent(), type);
+    JSObject *obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent());
     if (!obj)
         return JS_FALSE;
 
     /*
      * If it's a new object of class Exception, then null out the private
      * data so that the finalizer doesn't attempt to free it.
      */
     if (obj->getClass() == &js_ErrorClass)
@@ -988,86 +987,69 @@ GetExceptionProtoKey(intN exn)
     return (JSProtoKey) (JSProto_Error + exn);
 }
 
 JSObject *
 js_InitExceptionClasses(JSContext *cx, JSObject *obj)
 {
     jsval roots[3];
     JSObject *obj_proto, *error_proto;
-    TypeObject *obj_type, *error_type;
 
     /*
      * If lazy class initialization occurs for any Error subclass, then all
      * classes are initialized, starting with Error.  To avoid reentry and
      * redundant initialization, we must not pass a null proto parameter to
      * NewNonFunction below, when called for the Error superclass.  We need to
      * ensure that Object.prototype is the proto of Error.prototype.
      *
      * See the equivalent code to ensure that parent_proto is non-null when
      * js_InitClass calls NewObject, in jsobj.cpp.
      */
     if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
         return NULL;
 
-    obj_type = cx->getTypeObject("Error:prototype:new", NULL);
-
     PodArrayZero(roots);
     AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots));
 
 #ifdef __GNUC__
     error_proto = NULL;   /* quell GCC overwarning */
-    error_type = NULL;
 #endif
 
     jsval empty = STRING_TO_JSVAL(cx->runtime->emptyString);
 
     /* Initialize the prototypes first. */
     for (intN i = JSEXN_ERR; i != JSEXN_LIMIT; i++) {
         /* Make the prototype for the current constructor name. */
-        TypeObject *protoType = (i != JSEXN_ERR) ? error_type : obj_type;
         JSObject *proto =
-            NewNonFunction<WithProto::Class>(cx, &js_ErrorClass,
-                                             (i != JSEXN_ERR) ? error_proto : obj_proto,
-                                             obj, protoType);
+            NewNonFunction<WithProto::Class>(cx, &js_ErrorClass, (i != JSEXN_ERR) ? error_proto : obj_proto, obj);
         if (!proto)
             return NULL;
         if (i == JSEXN_ERR) {
             error_proto = proto;
-            error_type = proto->getTypePrototypeNewObject(cx);
             roots[0] = OBJECT_TO_JSVAL(proto);
         } else {
             // We cannot share the root for error_proto and other prototypes
             // as error_proto must be rooted until the function returns.
             roots[1] = OBJECT_TO_JSVAL(proto);
         }
 
         /* So exn_finalize knows whether to destroy private data. */
         proto->setPrivate(NULL);
 
         /* Get the text name of this function, needs to be in sync with jsatom.h.  Blech. */
         JSProtoKey protoKey = GetExceptionProtoKey(i);
         const char *fullName = js_common_atom_names[1 + 2 + JSTYPE_LIMIT + 1 + protoKey];
 
-        /*
-         * Mark the function as a builtin before constructing and adding it to the global
-         * object, which could trigger accesses on its properties.
-         */
-        cx->markTypeBuiltinFunction(cx->getTypeFunction(fullName));
-        
         jsid id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[protoKey]);
         JSFunction *fun = js_DefineFunction(cx, obj, id, Exception, 1, JSFUN_CONSTRUCTOR,
                                             JS_TypeHandlerNew, fullName);
         if (!fun)
             return NULL;
         roots[2] = OBJECT_TO_JSVAL(FUN_OBJECT(fun));
 
-        /* This is a builtin class, specify its 'prototype' field for inference. */
-        cx->setTypeFunctionPrototype(fun->getTypeObject(), protoType);
-
         /* Make this constructor make objects of class Exception. */
         FUN_CLASP(fun) = &js_ErrorClass;
 
         /* Make the prototype and constructor links. */
         if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), proto,
                                   JSPROP_READONLY | JSPROP_PERMANENT)) {
             return NULL;
         }
@@ -1132,17 +1114,16 @@ js_ErrorToException(JSContext *cx, const
                     JSErrorCallback callback, void *userRef)
 {
     JSErrNum errorNumber;
     const JSErrorFormatString *errorString;
     JSExnType exn;
     jsval tv[4];
     JSBool ok;
     JSObject *errProto, *errObject;
-    TypeObject *type;
     JSString *messageStr, *filenameStr;
 
     /*
      * Tell our caller to report immediately if this report is just a warning.
      */
     JS_ASSERT(reportp);
     if (JSREPORT_IS_WARNING(reportp->flags))
         return JS_FALSE;
@@ -1191,18 +1172,17 @@ js_ErrorToException(JSContext *cx, const
      * exception constructor name in the scope chain of the current context's
      * top stack frame, or in the global object if no frame is active.
      */
     ok = js_GetClassPrototype(cx, NULL, GetExceptionProtoKey(exn), &errProto);
     if (!ok)
         goto out;
     tv[0] = OBJECT_TO_JSVAL(errProto);
 
-    type = errProto->getTypePrototypeNewObject(cx);
-    errObject = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent(), type);
+    errObject = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent());
     if (!errObject) {
         ok = JS_FALSE;
         goto out;
     }
     tv[1] = OBJECT_TO_JSVAL(errObject);
 
     messageStr = JS_NewStringCopyZ(cx, message);
     if (!messageStr) {
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -180,33 +180,36 @@ js_GetArgsProperty(JSContext *cx, JSStac
 
 static JSObject *
 NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
 {
     JSObject *proto;
     if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
         return NULL;
 
+    TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return NULL;
+
     JS_STATIC_ASSERT(JSObject::ARGS_CLASS_RESERVED_SLOTS == 2);
     JSObject *argsobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!argsobj)
         return NULL;
 
     ArgumentsData *data = (ArgumentsData *)
         cx->malloc(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
     if (!data)
         return NULL;
     SetValueRangeToUndefined(data->slots, argc);
 
     /* Can't fail from here on, so initialize everything in argsobj. */
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_ARGUMENTS);
     argsobj->init(cx, callee.getFunctionPrivate()->inStrictMode()
                   ? &StrictArgumentsClass
                   : &js_ArgumentsClass,
-                  proto, parent, type, NULL, false);
+                  type, parent, NULL, false);
 
     argsobj->setMap(cx->runtime->emptyArgumentsShape);
 
     argsobj->setArgsLength(argc);
     argsobj->setArgsData(data);
     data->callee.setObject(callee);
 
     return argsobj;
@@ -360,19 +363,20 @@ WrapEscapingClosure(JSContext *cx, JSSta
      * fragile in the face of ongoing compile-time optimization. Instead, the
      * _DBG* opcodes used by wrappers created here must cope with unresolved
      * upvars and throw them as reference errors. Caveat debuggers!
      */
     JSObject *scopeChain = GetScopeChain(cx, fp);
     if (!scopeChain)
         return NULL;
 
-    JSObject *wfunobj = NewFunction(cx, scopeChain, fun->getTypeObject());
+    JSObject *wfunobj = NewFunction(cx, scopeChain);
     if (!wfunobj)
         return NULL;
+    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;
@@ -960,24 +964,22 @@ CalleeGetter(JSContext *cx, JSObject *ob
 
 static JSObject *
 NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &callee)
 {
     size_t vars = fun->countArgsAndVars();
     size_t slots = JSObject::CALL_RESERVED_SLOTS + vars;
     gc::FinalizeKind kind = gc::GetGCObjectKind(slots);
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_CALL);
-
     JSObject *callobj = js_NewGCObject(cx, kind);
     if (!callobj)
         return NULL;
 
     /* Init immediately to avoid GC seeing a half-init'ed object. */
-    callobj->init(cx, &js_CallClass, NULL, &scopeChain, type, NULL, false);
+    callobj->init(cx, &js_CallClass, cx->emptyTypeObject(), &scopeChain, NULL, false);
     callobj->setMap(fun->u.i.names);
 
     /* This must come after callobj->lastProp has been set. */
     if (!callobj->ensureInstanceReservedSlots(cx, vars))
         return NULL;
 
 #ifdef DEBUG
     for (Shape::Range r = callobj->lastProp; !r.empty(); r.popFront()) {
@@ -991,23 +993,21 @@ NewCallObject(JSContext *cx, JSFunction 
 
     callobj->setCallObjCallee(callee);
     return callobj;
 }
 
 static inline JSObject *
 NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
 {
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_DECLENV);
-
     JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!envobj)
         return NULL;
 
-    envobj->init(cx, &js_DeclEnvClass, NULL, &fp->scopeChain(), type, fp, false);
+    envobj->init(cx, &js_DeclEnvClass, cx->emptyTypeObject(), &fp->scopeChain(), fp, false);
     envobj->setMap(cx->runtime->emptyDeclEnvShape);
     return envobj;
 }
 
 JSObject *
 js_GetCallObject(JSContext *cx, JSStackFrame *fp)
 {
     /* Create a call object for fp only if it lacks one. */
@@ -1611,16 +1611,17 @@ fun_getProperty(JSContext *cx, JSObject 
 
       default:
         /* XXX fun[0] and fun.arguments[0] are equivalent. */
         if (fp && fp->isFunctionFrame() && uint16(slot) < fp->numFormalArgs())
             *vp = fp->formalArg(slot);
         break;
     }
 
+    cx->addTypePropertyId(obj->getType(), id, *vp);
     return true;
 }
 
 struct LazyFunctionDataProp {
     uint16      atomOffset;
     int8        tinyid;
     uint8       attrs;
 };
@@ -1716,40 +1717,46 @@ fun_resolve(JSContext *cx, JSObject *obj
         if (flags & JSRESOLVE_ASSIGNING)
             return true;
 
         /*
          * Make the prototype object an instance of Object with the same parent
          * as the function object itself.
          */
         JSObject *parent = obj->getParent();
-        JSObject *proto;
-        if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
+        JSObject *objProto;
+        if (!js_GetClassPrototype(cx, parent, JSProto_Object, &objProto))
             return false;
-        TypeObject *typeProto = obj->getTypePrototype(cx);
-        proto = NewNativeClassInstance(cx, &js_ObjectClass, proto, parent, typeProto);
+        JSObject *proto = NewNativeClassInstance(cx, &js_ObjectClass, objProto, parent);
         if (!proto)
             return false;
 
+        /* Make a new type for the prototype object. */
+        TypeObject *protoType = cx->newTypeObject(obj->getType()->name(), "prototype", objProto);
+        if (!protoType)
+            return false;
+        proto->setType(protoType);
+
         /*
          * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
          * user-defined functions, but DontEnum | ReadOnly | DontDelete for
          * native "system" constructors such as Object or Function.  So lazily
          * set the former here in fun_resolve, but eagerly define the latter
          * in js_InitClass, with the right attributes.
          */
         if (!js_SetClassPrototype(cx, obj, proto, JSPROP_PERMANENT))
             return false;
 
         *objp = obj;
         return true;
     }
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         JS_ASSERT(!IsInternalFunctionObject(obj));
+        cx->addTypePropertyId(obj->getType(), id, types::TYPE_INT32);
         if (!js_DefineNativeProperty(cx, obj, id, Int32Value(fun->nargs),
                                      PropertyStub, PropertyStub,
                                      JSPROP_PERMANENT | JSPROP_READONLY, 0, 0, NULL)) {
             return false;
         }
         *objp = obj;
         return true;
     }
@@ -1843,17 +1850,17 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
         nupvars = fun->u.i.nupvars;
         localsword = (nargs << 16) | nvars;
         flagsword = (nupvars << 16) | fun->flags;
     } else {
         fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL, NULL, NULL);
         if (!fun)
             return false;
         FUN_OBJECT(fun)->clearParent();
-        FUN_OBJECT(fun)->clearProto();
+        FUN_OBJECT(fun)->clearType(cx);
 #ifdef __GNUC__
         nvars = nargs = nupvars = 0;    /* quell GCC uninitialized warning */
 #endif
     }
 
     AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
 
     if (!JS_XDRUint32(xdr, &firstword))
@@ -2494,17 +2501,17 @@ static JSFunctionSpec function_methods[]
     JS_FN_TYPE(js_call_str,       js_fun_call,    1,0, JS_TypeHandlerDynamic),
     JS_FN_TYPE("bind",            fun_bind,       1,0, JS_TypeHandlerDynamic),
     JS_FS_END
 };
 
 static JSBool
 Function(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = NewFunction(cx, NULL, NULL);
+    JSObject *obj = NewFunction(cx, NULL);
     if (!obj)
         return JS_FALSE;
 
     /* N.B. overwriting callee with return value */
     JSObject *parent = vp[0].toObject().getParent();
     vp[0].setObject(*obj);
 
     /*
@@ -2731,39 +2738,22 @@ ThrowTypeError(JSContext *cx, uintN argc
 JSObject *
 js_InitFunctionClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
                                    JS_TypeHandlerDynamic, NULL, function_methods, NULL, NULL);
     if (!proto)
         return NULL;
 
-    /*
-     * Remember the prototype's type information as js_NewFunction will overwrite it.
-     * we also need to attach any lazy properties. :TODO: these are also own properties
-     * of individual functions, but we don't add them to the ownTypes of those objects.
-     * This is OK as ownTypes vs. prototype types are used only when the property
-     * holds a singleton object, but needs to be cleaned up and clarified.
-     */
-    TypeObject *protoFunc = proto->getTypeObject();
-    cx->addTypeProperty(protoFunc, "name", TYPE_STRING);
-    cx->addTypeProperty(protoFunc, "length", TYPE_INT32);
-    cx->addTypeProperty(protoFunc, "arguments",
-                        (jstype) cx->getFixedTypeObject(TYPE_OBJECT_ARGUMENTS));
-
     JSFunction *fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL, NULL, NULL);
     if (!fun)
         return NULL;
     fun->flags |= JSFUN_PROTOTYPE;
     fun->u.i.script = JSScript::emptyScript();
 
-#ifdef JS_TYPE_INFERENCE
-    fun->typeObject = protoFunc;
-#endif
-
     if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
         /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
         JSObject *throwTypeError =
             js_NewFunction(cx, NULL, reinterpret_cast<Native>(ThrowTypeError), 0,
                            0, obj, NULL, JS_TypeHandlerVoid, "ThrowTypeError");
         if (!throwTypeError)
             return NULL;
 
@@ -2780,20 +2770,26 @@ js_NewFunction(JSContext *cx, JSObject *
                JSTypeHandler handler, const char *fullName)
 {
     JSFunction *fun;
 
     if (funobj) {
         JS_ASSERT(funobj->isFunction());
         funobj->setParent(parent);
     } else {
-        TypeObject *funType = handler ? cx->getTypeFunctionHandler(fullName, handler) : NULL;
-        funobj = NewFunction(cx, parent, funType);
+        funobj = NewFunction(cx, parent);
         if (!funobj)
             return NULL;
+        if (handler) {
+            TypeFunction *type = cx->newTypeFunction(fullName, funobj->getProto());
+            if (!type)
+                return NULL;
+            type->handler = handler;
+            funobj->setType(type);
+        }
     }
     JS_ASSERT(!funobj->getPrivate());
     fun = (JSFunction *) funobj;
 
     /* Initialize all function members. */
     fun->nargs = uint16(nargs);
     fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRCINFO);
     if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
@@ -2837,28 +2833,30 @@ js_CloneFunctionObject(JSContext *cx, JS
     JS_ASSERT(proto);
 
     JSObject *clone;
     if (cx->compartment == fun->compartment()) {
         /*
          * The cloned function object does not need the extra JSFunction members
          * beyond JSObject as it points to fun via the private slot.
          */
-        clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent, fun->getTypeObject());
+        clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent);
         if (!clone)
             return NULL;
         clone->setPrivate(fun);
+        clone->setType(fun->getType());
     } else {
         /*
          * Across compartments we have to deep copy JSFunction and clone the
          * script (for interpreted functions).
          */
-        clone = NewFunction(cx, parent, fun->getTypeObject());
+        clone = NewFunction(cx, parent);
         if (!clone)
             return NULL;
+        clone->setType(fun->getType());
         JSFunction *cfun = (JSFunction *) clone;
         cfun->nargs = fun->nargs;
         cfun->flags = fun->flags;
         cfun->u = fun->getFunctionPrivate()->u;
         cfun->atom = fun->atom;
         clone->setPrivate(cfun);
         if (cfun->isInterpreted()) {
             JSScript *script = cfun->u.i.script;
@@ -2955,18 +2953,22 @@ js_NewDebuggableFlatClosure(JSContext *c
 JSFunction *
 js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
                   uintN nargs, uintN attrs,
                   JSTypeHandler handler, const char *fullName)
 {
     PropertyOp gsop;
     JSFunction *fun;
 
-    if (!handler)
+    if (!handler) {
         handler = JS_TypeHandlerMissing;
+        if (!fullName)
+            fullName = "Unknown";
+    }
+    JS_ASSERT(fullName);
 
     if (attrs & JSFUN_STUB_GSOPS) {
         /*
          * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
          * the defined property's attributes. This allows us to encode another,
          * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
          * for more on this.
          */
@@ -3027,17 +3029,17 @@ js_DefineFunction(JSContext *cx, JSObjec
         return NULL;
 
     if (!wasDelegate && obj->isDelegate())
         obj->clearDelegate();
 
     if (!obj->defineProperty(cx, id, ObjectValue(*fun), gsop, gsop, attrs & ~JSFUN_FLAGS_MASK))
         return NULL;
 
-    cx->addTypePropertyId(obj->getTypeObject(), id, ObjectValue(*fun));
+    cx->addTypePropertyId(obj->getType(), id, ObjectValue(*fun));
     return fun;
 }
 
 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
 # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
 #endif
 
 JSFunction *
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1707,35 +1707,16 @@ MarkRuntime(JSTracer *trc)
             HM &h = (k == 0) ? rt->methodReadBarrierCountMap : rt->unjoinedFunctionCountMap;
             for (HM::Range r = h.all(); !r.empty(); r.popFront()) {
                 JSFunction *fun = r.front().key;
                 JS_CALL_OBJECT_TRACER(trc, fun, "FunctionCountMap key");
             }
         }
     }
 #endif
-
-#ifdef JS_TYPE_INFERENCE
-    /* Mark all scripts which have analysis information. :FIXME: bug 613221 */
-    JSCompartment **read = rt->compartments.begin();
-    JSCompartment **end = rt->compartments.end();
-    while (read < end) {
-        JSCompartment *compartment = (*read++);
-        if (compartment->marked) {
-            for (JSCList *cursor = compartment->scripts.next;
-                 cursor != &compartment->scripts;
-                 cursor = cursor->next) {
-                JSScript *script = reinterpret_cast<JSScript *>(cursor);
-                if (script->analysis)
-                    js_TraceScript(trc, script);
-            }
-            compartment->types.trace(trc);
-        }
-    }
-#endif
 }
 
 void
 TriggerGC(JSRuntime *rt)
 {
     JS_ASSERT(!rt->gcRunning);
     if (rt->gcIsNeeded)
         return;
@@ -2566,17 +2547,17 @@ js_GC(JSContext *cx, JSGCInvocationKind 
 #endif
     GCTIMER_END(gckind == GC_LAST_CONTEXT);
 }
 
 namespace js {
 namespace gc {
 
 bool
-SetProtoCheckingForCycles(JSContext *cx, JSObject *obj, JSObject *proto)
+SetTypeCheckingForCycles(JSContext *cx, JSObject *obj, types::TypeObject *type)
 {
     /*
      * This function cannot be called during the GC and always requires a
      * request.
      */
 #ifdef JS_THREADSAFE
     JS_ASSERT(cx->thread->data.requestDepth);
 
@@ -2589,25 +2570,25 @@ SetProtoCheckingForCycles(JSContext *cx,
 #endif
 
     JSRuntime *rt = cx->runtime;
     AutoLockGC lock(rt);
     AutoGCSession gcsession(cx);
     AutoUnlockGC unlock(rt);
 
     bool cycle = false;
-    for (JSObject *obj2 = proto; obj2;) {
+    for (JSObject *obj2 = type->proto; obj2;) {
         if (obj2 == obj) {
             cycle = true;
             break;
         }
         obj2 = obj2->getProto();
     }
     if (!cycle)
-        obj->setProto(cx, proto);
+        obj->setType(type);
 
     return !cycle;
 }
 
 JSCompartment *
 NewCompartment(JSContext *cx, JSPrincipals *principals)
 {
     JSRuntime *rt = cx->runtime;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1031,24 +1031,24 @@ namespace gc {
 
 #if JS_HAS_XML_SUPPORT
 # define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) < JSTRACE_LIMIT)
 #else
 # define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_STRING)
 #endif
 
 /*
- * Set object's prototype while checking that doing so would not create
+ * Set object's type/prototype while checking that doing so would not create
  * a cycle in the proto chain. The cycle check and proto change are done
  * only when all other requests are finished or suspended to ensure exclusive
  * access to the chain. If there is a cycle, return false without reporting
  * an error. Otherwise, set the proto and return true.
  */
 extern bool
-SetProtoCheckingForCycles(JSContext *cx, JSObject *obj, JSObject *proto);
+SetTypeCheckingForCycles(JSContext *cx, JSObject *obj, types::TypeObject *type);
 
 JSCompartment *
 NewCompartment(JSContext *cx, JSPrincipals *principals);
 
 } /* namespace js */
 } /* namespace gc */
 
 inline JSCompartment *
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -243,29 +243,23 @@ MarkObject(JSTracer *trc, JSObject &obj,
 static inline void
 MarkChildren(JSTracer *trc, JSObject *obj)
 {
     /* If obj has no map, it must be a newborn. */
     if (!obj->map)
         return;
 
     /* Trace universal (ops-independent) members. */
-    if (JSObject *proto = obj->getProto())
-        MarkObject(trc, *proto, "proto");
+    if (!obj->type->marked)
+        obj->type->trace(trc);
+    if (!obj->isDenseArray() && obj->newType && !obj->newType->marked)
+        obj->newType->trace(trc);
     if (JSObject *parent = obj->getParent())
         MarkObject(trc, *parent, "parent");
 
-    if (!obj->isDenseArray() && obj->emptyShapes) {
-        int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
-        for (int i = 0; i < count; i++) {
-            if (obj->emptyShapes[i])
-                obj->emptyShapes[i]->trace(trc);
-        }
-    }
-
     /* Delegate to ops or the native marking op. */
     TraceOp op = obj->getOps()->trace;
     (op ? op : js_TraceObject)(trc, obj);
 }
 
 static inline void
 MarkChildren(JSTracer *trc, JSString *str)
 {
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -153,34 +153,16 @@ static bool InferSpewActive(SpewChannel 
         }
     }
     return active[channel];
 }
 
 #ifdef DEBUG
 
 const char *
-TypeIdStringImpl(jsid id)
-{
-    if (JSID_IS_VOID(id))
-        return "(index)";
-    static char bufs[4][100];
-    static unsigned which = 0;
-    which = (which + 1) & 3;
-    PutEscapedString(bufs[which], 100, JSID_TO_STRING(id), 0);
-    return bufs[which];
-}
-
-const char *
-TypeObjectString(TypeObject *object)
-{
-    return TypeIdString(object->name);
-}
-
-const char *
 TypeString(jstype type)
 {
     switch (type) {
       case TYPE_UNDEFINED:
         return "void";
       case TYPE_NULL:
         return "null";
       case TYPE_BOOLEAN:
@@ -191,17 +173,17 @@ TypeString(jstype type)
         return "float";
       case TYPE_STRING:
         return "string";
       case TYPE_UNKNOWN:
         return "unknown";
       default: {
         JS_ASSERT(TypeIsObject(type));
         TypeObject *object = (TypeObject *) type;
-        return TypeIdString(object->name);
+        return object->name();
       }
     }
 }
 
 void InferSpew(SpewChannel channel, const char *fmt, ...)
 {
     if (!InferSpewActive(channel))
         return;
@@ -301,21 +283,21 @@ TypeSet::print(JSContext *cx)
     if (typeFlags & TYPE_FLAG_OBJECT) {
         printf(" object[%u]", objectCount);
 
         if (objectCount >= 2) {
             unsigned objectCapacity = HashSetCapacity(objectCount);
             for (unsigned i = 0; i < objectCapacity; i++) {
                 TypeObject *object = objectSet[i];
                 if (object)
-                    printf(" %s", TypeIdString(object->name));
+                    printf(" %s", object->name());
             }
         } else if (objectCount == 1) {
             TypeObject *object = (TypeObject*) objectSet;
-            printf(" %s", TypeIdString(object->name));
+            printf(" %s", object->name());
         }
     }
 }
 
 /* Standard subset constraint, propagate all types from one set to another. */
 class TypeConstraintSubset : public TypeConstraint
 {
 public:
@@ -353,17 +335,16 @@ public:
 
     /* Property being accessed. */
     jsid id;
 
     TypeConstraintProp(analyze::Bytecode *code, TypeSet *target, jsid id, bool assign)
         : TypeConstraint("prop"), code(code), assign(assign), target(target), id(id)
     {
         JS_ASSERT(code);
-        JS_ASSERT(id == MakeTypeId(id));
 
         /* If the target is NULL, this is as an inc/dec on the property. */
         JS_ASSERT_IF(!target, assign);
     }
 
     void newType(JSContext *cx, TypeSet *source, jstype type);
 };
 
@@ -416,16 +397,36 @@ TypeSet::addGetElem(JSContext *cx, analy
 
 void
 TypeSet::addSetElem(JSContext *cx, analyze::Bytecode *code, TypeSet *object, TypeSet *target)
 {
     JS_ASSERT(this->pool == &code->pool());
     add(cx, ArenaNew<TypeConstraintElem>(code->pool(), code, object, target, true));
 }
 
+/* Constraints for determining the 'this' object at sites invoked using 'new'. */
+class TypeConstraintNewObject : public TypeConstraint
+{
+    TypeSet *target;
+
+  public:
+    TypeConstraintNewObject(TypeSet *target)
+        : TypeConstraint("newObject"), target(target)
+    {}
+
+    void newType(JSContext *cx, TypeSet *source, jstype type);
+};
+
+void
+TypeSet::addNewObject(JSContext *cx, JSArenaPool &pool, TypeSet *target)
+{
+    JS_ASSERT(this->pool == &pool);
+    add(cx, ArenaNew<TypeConstraintNewObject>(pool, target));
+}
+
 /*
  * Constraints for watching call edges as they are discovered and invoking native
  * function handlers, adding constraints for arguments, receiver objects and the
  * return value, and updating script foundOffsets.
  */
 class TypeConstraintCall : public TypeConstraint
 {
 public:
@@ -597,27 +598,27 @@ GetPropertyObject(JSContext *cx, jstype 
      * read on the primitive's new object.
      */
     switch (type) {
 
       case TYPE_INT32:
       case TYPE_DOUBLE:
         if (!cx->globalObject->getReservedSlot(JSProto_Number).isObject())
             js_InitNumberClass(cx, cx->globalObject);
-        return cx->getFixedTypeObject(TYPE_OBJECT_NEW_NUMBER);
+        return cx->getTypeNewObject(JSProto_Number);
 
       case TYPE_BOOLEAN:
         if (!cx->globalObject->getReservedSlot(JSProto_Boolean).isObject())
             js_InitBooleanClass(cx, cx->globalObject);
-        return cx->getFixedTypeObject(TYPE_OBJECT_NEW_BOOLEAN);
+        return cx->getTypeNewObject(JSProto_Boolean);
 
       case TYPE_STRING:
         if (!cx->globalObject->getReservedSlot(JSProto_String).isObject())
             js_InitStringClass(cx, cx->globalObject);
-        return cx->getFixedTypeObject(TYPE_OBJECT_NEW_STRING);
+        return cx->getTypeNewObject(JSProto_String);
 
       default:
         /* undefined and null do not have properties. */
         return NULL;
     }
 }
 
 /*
@@ -721,39 +722,31 @@ TypeConstraintElem::newType(JSContext *c
          */
         if (assign)
             cx->compartment->types.monitorBytecode(cx, code);
         else
             target->addType(cx, TYPE_UNKNOWN);
     }
 };
 
-class TypeConstraintNewObject : public TypeConstraint
+void
+TypeConstraintNewObject::newType(JSContext *cx, TypeSet *source, jstype type)
 {
-    TypeSet *target;
-
-  public:
-    TypeConstraintNewObject(TypeSet *target)
-        : TypeConstraint("newObject"), target(target)
-    {}
-
-    void newType(JSContext *cx, TypeSet *source, jstype type)
-    {
-        if (type == TYPE_UNKNOWN) {
-            target->addType(cx, TYPE_UNKNOWN);
-            return;
-        }
-
-        /* :FIXME: Handle non-object prototype case dynamically. */
-        if (TypeIsObject(type)) {
-            TypeObject *object = (TypeObject *) type;
-            target->addType(cx, (jstype) object->getNewObject(cx));
-        }
+    if (type == TYPE_UNKNOWN) {
+        target->addType(cx, TYPE_UNKNOWN);
+        return;
     }
-};
+
+    /* :FIXME: Handle non-object prototype case dynamically. */
+    if (TypeIsObject(type)) {
+        TypeObject *object = (TypeObject *) type;
+        TypeSet *newTypes = object->getProperty(cx, JSID_EMPTY, true);
+        newTypes->addSubset(cx, *object->pool, target);
+    }
+}
 
 void
 TypeConstraintCall::newType(JSContext *cx, TypeSet *source, jstype type)
 {
     if (type == TYPE_UNKNOWN) {
         /* Monitor calls on unknown functions. */
         cx->compartment->types.monitorBytecode(cx, callsite->code);
         return;
@@ -805,32 +798,16 @@ TypeConstraintCall::newType(JSContext *c
                 newSite->argumentTypes[i] = callsite->argumentTypes[i + 1];
 
             function->handler(cx, (JSTypeFunction*)function, (JSTypeCallsite*)newSite);
         } else {
             /* Model the function's effects directly. */
             function->handler(cx, (JSTypeFunction*)function, (JSTypeCallsite*)callsite);
         }
 
-        /*
-         * When invoking 'new' on natives other than Object, Function, and Array
-         * (whose handlers take care of the 'new' case), add the 'new' object of
-         * the function to the return types.
-         */
-        if (callsite->isNew && callsite->returnTypes &&
-            function != cx->getFixedTypeObject(TYPE_OBJECT_OBJECT) &&
-            function != cx->getFixedTypeObject(TYPE_OBJECT_FUNCTION) &&
-            function != cx->getFixedTypeObject(TYPE_OBJECT_ARRAY)) {
-            if (!function->prototypeObject)
-                function->getProperty(cx, id_prototype(cx), false);
-            TypeObject *object = function->prototypeObject->getNewObject(cx);
-            if (callsite->returnTypes)
-                callsite->returnTypes->addType(cx, (jstype) object);
-        }
-
         return;
     }
 
     analyze::Script *script = function->script->analysis;
 
     /* Add bindings for the arguments of the call. */
     for (unsigned i = 0; i < callsite->argumentCount; i++) {
         TypeSet *argTypes = callsite->argumentTypes[i];
@@ -857,18 +834,17 @@ TypeConstraintCall::newType(JSContext *c
 
     /* Add a binding for the receiver object of the call. */
     if (callsite->isNew) {
         /* The receiver object is the 'new' object for the function's prototype. */
         if (function->unknownProperties) {
             script->thisTypes.addType(cx, TYPE_UNKNOWN);
         } else {
             TypeSet *prototypeTypes = function->getProperty(cx, id_prototype(cx), false);
-            prototypeTypes->add(cx,
-                ArenaNew<TypeConstraintNewObject>(*function->pool, &script->thisTypes));
+            prototypeTypes->addNewObject(cx, *function->pool, &script->thisTypes);
         }
 
         /*
          * If the script does not return a value then the pushed value is the new
          * object (typical case).
          */
         if (callsite->returnTypes) {
             script->thisTypes.addSubset(cx, script->pool, callsite->returnTypes);
@@ -959,27 +935,27 @@ TypeConstraintTransformThis::newType(JSC
         return;
     }
 
     /* TODO: handle strict mode code correctly. */
     TypeObject *object = NULL;
     switch (type) {
       case TYPE_NULL:
       case TYPE_UNDEFINED:
-        object = cx->getGlobalTypeObject();
+        object = cx->globalTypeObject();
         break;
       case TYPE_INT32:
       case TYPE_DOUBLE:
-        object = cx->getFixedTypeObject(TYPE_OBJECT_NEW_NUMBER);
+        object = cx->getTypeNewObject(JSProto_Number);
         break;
       case TYPE_BOOLEAN:
-        object = cx->getFixedTypeObject(TYPE_OBJECT_NEW_BOOLEAN);
+        object = cx->getTypeNewObject(JSProto_Boolean);
         break;
       case TYPE_STRING:
-        object = cx->getFixedTypeObject(TYPE_OBJECT_NEW_STRING);
+        object = cx->getTypeNewObject(JSProto_String);
         break;
       default:
         JS_NOT_REACHED("Bad type");
     }
 
     target->addType(cx, (jstype) object);
 }
 
@@ -994,32 +970,44 @@ TypeConstraintFilterPrimitive::newType(J
     }
 
     target->addType(cx, type);
 }
 
 void
 TypeConstraintMonitorRead::newType(JSContext *cx, TypeSet *source, jstype type)
 {
-    if (type == (jstype) cx->getFixedTypeObject(TYPE_OBJECT_GETSET)) {
+    if (type == (jstype) cx->compartment->types.typeGetSet) {
         target->addType(cx, TYPE_UNKNOWN);
         return;
     }
 
     target->addType(cx, type);
 }
 
 void
 TypeConstraintGenerator::newType(JSContext *cx, TypeSet *source, jstype type)
 {
-    if (type == TYPE_UNKNOWN)
+    if (type == TYPE_UNKNOWN) {
         target->addType(cx, TYPE_UNKNOWN);
-
-    if (type == (jstype) cx->getFixedTypeObject(TYPE_OBJECT_NEW_ITERATOR) ||
-        type == (jstype) cx->getFixedTypeObject(TYPE_OBJECT_NEW_GENERATOR)) {
+        return;
+    }
+
+    if (TypeIsPrimitive(type))
+        return;
+
+    /*
+     * Watch for 'for in' loops which could produce values other than strings.
+     * This includes loops on Iterator and Generator objects, and objects with
+     * a custom __iterator__ property that is marked as typeGetSet (see GetCustomIterator).
+     */
+    TypeObject *object = (TypeObject *) type;
+    if (object == cx->compartment->types.typeGetSet ||
+        object->proto->getClass() == &js_IteratorClass ||
+        object->proto->getClass() == &js_GeneratorClass) {
         target->addType(cx, TYPE_UNKNOWN);
     }
 }
 
 /* Constraint marking incoming arrays as possibly packed. */
 class TypeConstraintPossiblyPacked : public TypeConstraint
 {
 public:
@@ -1119,17 +1107,17 @@ CombineObjectKind(TypeObject *object, Ob
     /*
      * Our initial guess is that all arrays are packed, but if the array is
      * created through [], Array() or Array(N) and we don't see later code
      * which looks to be filling it in starting at zero, consider it not packed.
      * All requests for the kind of an object go through here, so there are
      * no FreezeObjectKind constraints to update if we unset isPackedArray here.
      */
     if (object->isPackedArray && !object->possiblePackedArray) {
-        InferSpew(ISpewDynamic, "Possible unpacked array: %s", TypeIdString(object->name));
+        InferSpew(ISpewDynamic, "Possible unpacked array: %s", object->name());
         object->isPackedArray = false;
     }
 
     ObjectKind nkind;
     if (object->isFunction)
         nkind = object->asFunction()->script ? OBJECT_SCRIPTED_FUNCTION : OBJECT_NATIVE_FUNCTION;
     else if (object->isPackedArray)
         nkind = OBJECT_PACKED_ARRAY;
@@ -1304,224 +1292,25 @@ TypeSet::knownNonEmpty(JSContext *cx, JS
 
     return false;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
-/*
- * These names need to be consistent with those of the function, prototype and new
- * objects produced by js_InitClass where objects have propagation other than from
- * Array.prototype/Object.prototype.  Since names are unique identifiers for type
- * objects within a compartment, this ensures that the propagation performed by
- * js_InitClass affects the objects later accessed via getFixedTypeObject.  This
- * design is pretty goofy and fragile but keeps js_InitClass simple.
- */
-const char * const fixedTypeObjectNames[] = {
-    "Object",
-    "Function",
-    "Array",
-    "Function:prototype",
-    "#EmptyFunction",
-    "Object:prototype",
-    "Array:prototype",
-    "Boolean:prototype:new",
-    "Number:prototype:new",
-    "String:prototype:new",
-    "RegExp:prototype:new",
-    "Iterator:prototype:new",
-    "Generator:prototype:new",
-    "ArrayBuffer:prototype:new",
-    "#XML",
-    "#Arguments",
-    "#NoSuchMethod",
-    "#NoSuchMethodArguments",
-    "#PropertyDescriptor",
-    "#KeyValuePair",
-    "#JSON",
-    "#Proxy",
-    "#RegExpMatchArray",
-    "#StringSplitArray",
-    "#UnknownArray",
-    "#CloneArray",
-    "#PropertyArray",
-    "#ReflectArray",
-    "#UnknownObject",
-    "#CloneObject",
-    "#ReflectObject",
-    "#XMLSettings",
-    "#GetSet",
-    "#RegExpStatics",
-    "#Call",
-    "#DeclEnv",
-    "#SharpArray",
-    "#With",
-    "#Block",
-    "#NullClosure",
-    "#PropertyIterator",
-    "#Script"
-};
-
-JS_STATIC_ASSERT(JS_ARRAY_LENGTH(fixedTypeObjectNames) == TYPE_OBJECT_FIXED_LIMIT);
-
-void
-TypeCompartment::init()
-{
-    PodZero(this);
-
-    JS_InitArenaPool(&pool, "typeinfer", 512, 8, NULL);
-
-    objectNameTable = new ObjectNameTable();
-#ifdef DEBUG
-    bool success =
-#endif
-        objectNameTable->init();
-    JS_ASSERT(success);
-}
-
-TypeCompartment::~TypeCompartment()
-{
-    /* fclose(out); */
-    JS_FinishArenaPool(&pool);
-
-    delete objectNameTable;
-    JS_ASSERT(!pendingRecompiles);
-}
-
 void 
 TypeCompartment::growPendingArray()
 {
     pendingCapacity = js::Max(unsigned(100), pendingCapacity * 2);
     PendingWork *oldArray = pendingArray;
     pendingArray = ArenaArray<PendingWork>(pool, pendingCapacity);
     memcpy(pendingArray, oldArray, pendingCount * sizeof(PendingWork));
 }
 
-TypeObject *
-TypeCompartment::makeFixedTypeObject(JSContext *cx, FixedTypeObjectName which)
-{
-    const char *name = fixedTypeObjectNames[which];
-    switch (which) {
-
-      case TYPE_OBJECT_OBJECT:
-      case TYPE_OBJECT_FUNCTION:
-      case TYPE_OBJECT_ARRAY:
-        return cx->getTypeFunction(name);
-      case TYPE_OBJECT_FUNCTION_PROTOTYPE: {
-        TypeObject *proto = cx->getFixedTypeObject(TYPE_OBJECT_OBJECT_PROTOTYPE);
-        return cx->getTypeFunctionHandler(name, JS_TypeHandlerVoid, proto);
-      }
-      case TYPE_OBJECT_EMPTY_FUNCTION:
-        return cx->getTypeFunction(name, NULL);
-
-      case TYPE_OBJECT_OBJECT_PROTOTYPE:
-        return getTypeObject(cx, NULL, name, false, NULL);
-      case TYPE_OBJECT_ARRAY_PROTOTYPE:
-        return cx->getTypeObject(name, NULL);
-      case TYPE_OBJECT_NEW_BOOLEAN:
-        return cx->getTypeObject(name, cx->getTypeObject("Boolean:prototype", NULL));
-      case TYPE_OBJECT_NEW_NUMBER:
-        return cx->getTypeObject(name, cx->getTypeObject("Number:prototype", NULL));
-      case TYPE_OBJECT_NEW_STRING:
-        return cx->getTypeObject(name, cx->getTypeObject("String:prototype", NULL));
-      case TYPE_OBJECT_NEW_REGEXP:
-        return cx->getTypeObject(name, cx->getTypeObject("RegExp:prototype", NULL));
-      case TYPE_OBJECT_NEW_ITERATOR:
-        return cx->getTypeObject(name, cx->getTypeObject("Iterator:prototype", NULL));
-      case TYPE_OBJECT_NEW_GENERATOR:
-        return cx->getTypeObject(name, cx->getTypeObject("Generator:prototype", NULL));
-      case TYPE_OBJECT_NEW_ARRAYBUFFER:
-        return cx->getTypeObject(name, cx->getTypeObject("ArrayBuffer:prototype", NULL));
-
-      case TYPE_OBJECT_XML:
-      case TYPE_OBJECT_ARGUMENTS:
-      case TYPE_OBJECT_NOSUCHMETHOD:
-      case TYPE_OBJECT_NOSUCHMETHOD_ARGUMENTS:
-      case TYPE_OBJECT_PROPERTY_DESCRIPTOR:
-      case TYPE_OBJECT_KEY_VALUE_PAIR:
-      case TYPE_OBJECT_JSON:
-      case TYPE_OBJECT_PROXY: {
-        TypeObject *object = getTypeObject(cx, NULL, name, false, NULL);
-        cx->markTypeObjectUnknownProperties(object);
-        return object;
-      }
-
-      case TYPE_OBJECT_REGEXP_MATCH_ARRAY:
-      case TYPE_OBJECT_STRING_SPLIT_ARRAY:
-      case TYPE_OBJECT_UNKNOWN_ARRAY:
-      case TYPE_OBJECT_CLONE_ARRAY:
-      case TYPE_OBJECT_PROPERTY_ARRAY:
-      case TYPE_OBJECT_REFLECT_ARRAY:
-        return cx->getTypeObject(name, cx->getFixedTypeObject(TYPE_OBJECT_ARRAY_PROTOTYPE));
-
-      case TYPE_OBJECT_UNKNOWN_OBJECT:
-      case TYPE_OBJECT_CLONE_OBJECT:
-      case TYPE_OBJECT_REFLECT_OBJECT:
-      case TYPE_OBJECT_XML_SETTINGS:
-        return cx->getTypeObject(name, NULL);
-
-      case TYPE_OBJECT_GETSET:
-      case TYPE_OBJECT_REGEXP_STATICS:
-      case TYPE_OBJECT_CALL:
-      case TYPE_OBJECT_DECLENV:
-      case TYPE_OBJECT_SHARP_ARRAY:
-      case TYPE_OBJECT_WITH:
-      case TYPE_OBJECT_BLOCK:
-      case TYPE_OBJECT_NULL_CLOSURE:
-      case TYPE_OBJECT_PROPERTY_ITERATOR:
-      case TYPE_OBJECT_SCRIPT:
-        return getTypeObject(cx, NULL, name, false, NULL);
-
-      default:
-        JS_NOT_REACHED("Unknown fixed object");
-        return NULL;
-    }
-}
-
-TypeObject *
-TypeCompartment::getTypeObject(JSContext *cx, analyze::Script *script, const char *name,
-                               bool isFunction, TypeObject *prototype)
-{
-#ifdef JS_TYPE_INFERENCE
-    jsid id = ATOM_TO_JSID(js_Atomize(cx, name, strlen(name), 0));
-
-    JSArenaPool &pool = script ? script->pool : this->pool;
-
-    /*
-     * Check for an existing object with the same name first.  If we have one
-     * then reuse it.
-     */
-    ObjectNameTable::AddPtr p = objectNameTable->lookupForAdd(id);
-    if (p) {
-        js::types::TypeObject *object = p->value;
-        JS_ASSERT(object->isFunction == isFunction);
-        JS_ASSERT(object->prototype == prototype);
-        JS_ASSERT(object->pool == &pool);
-        return object;
-    }
-
-    js::types::TypeObject *object;
-    if (isFunction)
-        object = ArenaNew<TypeFunction>(pool, cx, &pool, id, prototype);
-    else
-        object = ArenaNew<TypeObject>(pool, cx, &pool, id, prototype);
-
-    TypeObject *&objects = script ? script->objects : this->objects;
-    object->next = objects;
-    objects = object;
-
-    objectNameTable->add(p, id, object);
-    return object;
-#else
-    return NULL;
-#endif
-}
-
 void
 TypeCompartment::addDynamicType(JSContext *cx, TypeSet *types, jstype type)
 {
     JS_ASSERT(!types->hasType(type));
 
     interpreting = false;
     uint64_t startTime = currentTime();
 
@@ -1619,38 +1408,37 @@ TypeCompartment::addPendingRecompile(JSC
 
 void
 TypeCompartment::dynamicAssign(JSContext *cx, JSObject *obj, jsid id, const Value &rval)
 {
     if (obj->isWith())
         obj = js_UnwrapWithObject(cx, obj);
 
     jstype rvtype = GetValueType(cx, rval);
-    TypeObject *object = obj->getTypeObject();
-
-    if (object->unknownProperties)
-        return;
+    TypeObject *object = obj->getType();
 
     TypeSet *assignTypes;
 
     /*
      * :XXX: Does this need to be moved to a more general place? We aren't considering
      * call objects in, e.g. addTypeProperty, but call objects might not be able to
      * flow there as they do not escape to scripts.
      */
     if (obj->isCall() || obj->isBlock()) {
         /* Local variable, let variable or argument assignment. */
         while (!obj->isCall())
             obj = obj->getParent();
         analyze::Script *script = obj->getCallObjCalleeFunction()->script()->analysis;
         JS_ASSERT(!script->isEval());
 
         assignTypes = script->getVariable(cx, id);
+    } else if (object->unknownProperties) {
+        return;
     } else {
-        id = MakeTypeId(id);
+        id = MakeTypeId(cx, id);
 
         /*
          * Mark as unknown any object which has had dynamic assignments to __proto__,
          * and any object which has had dynamic assignments to string properties through SETELEM.
          * The latter avoids making large numbers of type properties for hashmap-style objects.
          * :FIXME: this is too aggressive for things like prototype library initialization.
          */
         JSOp op = JSOp(*cx->regs->pc);
@@ -1663,17 +1451,17 @@ TypeCompartment::dynamicAssign(JSContext
 
         assignTypes = object->getProperty(cx, id, true);
     }
 
     if (assignTypes->hasType(rvtype))
         return;
 
     InferSpew(ISpewDynamic, "MonitorAssign: %s %s: %s",
-              TypeIdString(object->name), TypeIdString(id), TypeString(rvtype));
+              object->name(), TypeIdString(id), TypeString(rvtype));
     addDynamicType(cx, assignTypes, rvtype);
 }
 
 void
 TypeCompartment::monitorBytecode(JSContext *cx, analyze::Bytecode *code)
 {
     if (code->monitorNeeded)
         return;
@@ -1805,34 +1593,16 @@ TypeStack::merge(JSContext *cx, TypeStac
     PodZero(one);
     one->mergedGroup = two;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeObject
 /////////////////////////////////////////////////////////////////////
 
-TypeObject::TypeObject(JSContext *cx, JSArenaPool *pool, jsid name, TypeObject *prototype)
-    : name(name), isFunction(false), propertySet(NULL), propertyCount(0),
-      prototype(prototype), instanceList(NULL), instanceNext(NULL), newObject(NULL),
-      pool(pool), next(NULL), unknownProperties(false),
-      isDenseArray(false), isPackedArray(false), possiblePackedArray(false)
-{
-    InferSpew(ISpewOps, "newObject: %s", TypeIdString(name));
-
-    if (prototype) {
-        if (prototype->unknownProperties)
-            unknownProperties = true;
-        else if (prototype == cx->compartment->types.fixedTypeObjects[TYPE_OBJECT_ARRAY_PROTOTYPE])
-            isDenseArray = isPackedArray = true;
-        instanceNext = prototype->instanceList;
-        prototype->instanceList = this;
-    }
-}
-
 void
 TypeObject::storeToInstances(JSContext *cx, Property *base)
 {
     TypeObject *object = instanceList;
     while (object) {
         Property *p =
             HashSetLookup<jsid,Property,Property>(object->propertySet, object->propertyCount, base->id);
         if (p)
@@ -1845,17 +1615,17 @@ TypeObject::storeToInstances(JSContext *
 
 void
 TypeObject::addProperty(JSContext *cx, jsid id, Property *&base)
 {
     JS_ASSERT(!base);
     base = ArenaNew<Property>(*pool, pool, id);
 
     InferSpew(ISpewOps, "addProperty: %s %s T%u own T%u",
-              TypeIdString(name), TypeIdString(id), base->types.id(), base->ownTypes.id());
+              name(), TypeIdString(id), base->types.id(), base->ownTypes.id());
 
     base->ownTypes.addSubset(cx, *pool, &base->types);
 
     if (unknownProperties) {
         /*
          * Immediately mark the variable as unknown. Ideally we won't be doing this
          * too often, but we don't assert !unknownProperties to avoid extra complexity
          * in other code accessing object properties.
@@ -1863,46 +1633,25 @@ TypeObject::addProperty(JSContext *cx, j
         base->ownTypes.addType(cx, TYPE_UNKNOWN);
     }
 
     /* Check all transitive instances for this property. */
     if (instanceList)
         storeToInstances(cx, base);
 
     /* Pull in this property from all prototypes up the chain. */
-    TypeObject *object = prototype;
-    while (object) {
+    JSObject *obj = proto;
+    while (obj) {
+        TypeObject *object = obj->getType();
         Property *p =
             HashSetLookup<jsid,Property,Property>(object->propertySet, object->propertyCount, id);
         if (p)
             p->ownTypes.addSubset(cx, *object->pool, &base->types);
-        object = object->prototype;
+        obj = obj->getProto();
     }
-
-    /*
-     * If this is the 'prototype' property on a function with a lazily generated
-     * prototype (not builtin), make the object now.
-     */
-    if (!isFunction || asFunction()->isBuiltin || id != id_prototype(cx))
-        return;
-
-    TypeFunction *function = asFunction();
-    JS_ASSERT(!function->prototypeObject);
-
-    JSString *baseName = JSID_TO_STRING(name);
-    unsigned len = baseName->length() + 15;
-
-    char *prototypeName = (char *)alloca(len);
-    unsigned nlen = PutEscapedString(prototypeName, len, baseName, 0);
-    JS_ASSERT(nlen == baseName->length());
-
-    JS_snprintf(prototypeName + nlen, len - nlen, ":prototype");
-    function->prototypeObject = cx->getTypeObject(prototypeName, NULL);
-
-    base->ownTypes.addType(cx, (jstype) function->prototypeObject);
 }
 
 void
 TypeObject::markUnknown(JSContext *cx)
 {
     JS_ASSERT(!unknownProperties);
     unknownProperties = true;
 
@@ -1934,38 +1683,23 @@ TypeObject::markUnknown(JSContext *cx)
     TypeObject *instance = instanceList;
     while (instance) {
         if (!instance->unknownProperties)
             instance->markUnknown(cx);
         instance = instance->instanceNext;
     }
 }
 
-TypeObject *
-TypeObject::getNewObject(JSContext *cx)
-{
-    if (newObject)
-        return newObject;
-
-    JSString *baseName = JSID_TO_STRING(name);
-    unsigned len = baseName->length() + 10;
-
-    char *newName = (char *)alloca(len);
-    unsigned nlen = PutEscapedString(newName, len, baseName, 0);
-    JS_ASSERT(nlen == baseName->length());
-
-    JS_snprintf(newName + nlen, len - nlen, ":new");
-    newObject = cx->getTypeObject(newName, this);
-    return newObject;
-}
-
 void
 TypeObject::print(JSContext *cx)
 {
-    printf("%s : %s", TypeIdString(name), prototype ? TypeIdString(prototype->name) : "(null)");
+    printf("%s : %s", name(), proto ? proto->getType()->name() : "(null)");
+
+    if (unknownProperties)
+        printf(" unknown");
 
     if (propertyCount == 0) {
         printf(" {}\n");
         return;
     }
 
     printf(" {");
 
@@ -1983,29 +1717,16 @@ TypeObject::print(JSContext *cx)
         printf("\n    %s:", TypeIdString(prop->id));
         prop->ownTypes.print(cx);
     }
 
     printf("\n}\n");
 }
 
 /////////////////////////////////////////////////////////////////////
-// TypeFunction
-/////////////////////////////////////////////////////////////////////
-
-TypeFunction::TypeFunction(JSContext *cx, JSArenaPool *pool, jsid name, TypeObject *prototype)
-    : TypeObject(cx, pool, name, prototype), handler(NULL), script(NULL),
-      prototypeObject(NULL), returnTypes(pool),
-      isBuiltin(false), isGeneric(false)
-{
-    isFunction = true;
-    InferSpew(ISpewOps, "newFunction: %s return T%u", TypeIdString(name), returnTypes.id());
-}
-
-/////////////////////////////////////////////////////////////////////
 // TypeScript
 /////////////////////////////////////////////////////////////////////
 
 } } /* namespace js::types */
 
 /*
  * Returns true if we don't expect to compute the correct types for some value
  * popped by the specified bytecode.
@@ -2101,40 +1822,24 @@ JSScript::typeCheckBytecode(JSContext *c
             JSObject *obj = &val.toObject();
             js::types::TypeObject *object = (js::types::TypeObject *) type;
 
             if (object->unknownProperties) {
                 JS_ASSERT(!object->isDenseArray);
                 continue;
             }
 
-            /*
-             * Check that the immediate prototype is correct. We don't check when
-             * making the object as the prototypes of some objects change after creation.
-             */
-            if (((object->prototype != NULL) != (obj->getProto() != NULL)) ||
-                (object->prototype && object->prototype != obj->getProto()->getTypeObject())) {
-                jsid protoName = object->prototype ? object->prototype->name : JSID_VOID;
-                jsid needName = obj->getProto() ? obj->getProto()->getTypeObject()->name : JSID_VOID;
-                js::types::TypeFailure(cx, "Wrong prototype %s for %s at #%u:%05u popped %u: need %s",
-                                       js::types::TypeIdString(protoName),
-                                       js::types::TypeIdString(object->name),
-                                       analysis->id, code.offset, i,
-                                       js::types::TypeIdString(needName));
-            }
-
             /* Make sure information about the array status of this object is right. */
             JS_ASSERT_IF(object->isPackedArray, object->isDenseArray);
             if (object->isDenseArray) {
                 if (!obj->isDenseArray() ||
                     (object->isPackedArray && !obj->isPackedDenseArray())) {
                     js::types::TypeFailure(cx, "Object not %s array at #%u:%05u popped %u: %s",
                         object->isPackedArray ? "packed" : "dense",
-                        analysis->id, code.offset, i,
-                        js::types::TypeIdString(object->name));
+                        analysis->id, code.offset, i, object->name());
                 }
             }
         }
     }
 }
 
 namespace js {
 namespace analyze {
@@ -2185,17 +1890,17 @@ Script::setFunction(JSContext *cx, JSFun
      * and definitions information will be cleared for any scripts that could use
      * the declared variable.
      */
     if (fun->hasLocalNames())
         localNames = fun->getLocalNameArray(cx, &pool);
 
     /* Make a local variable for the function. */
     if (fun->atom)
-        getVariable(cx, ATOM_TO_JSID(fun->atom))->addType(cx, (jstype) fun->getTypeObject());
+        getVariable(cx, ATOM_TO_JSID(fun->atom))->addType(cx, (jstype) fun->getType());
 }
 
 static inline ptrdiff_t
 GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
 {
     uint32 type = JOF_OPTYPE(*pc);
     if (JOF_TYPE_IS_EXTENDED_JUMP(type))
         return GET_JUMPX_OFFSET(pc2);
@@ -2264,17 +1969,17 @@ SearchScope(JSContext *cx, Script *scrip
         }
 
         if (!script->parent)
             break;
 
         /* Function scripts have 'arguments' local variables. */
         if (id == id_arguments(cx) && script->fun) {
             TypeSet *types = script->getVariable(cx, id);
-            types->addType(cx, (jstype) cx->getFixedTypeObject(TYPE_OBJECT_ARGUMENTS));
+            types->addType(cx, (jstype) cx->getTypeNewObject(JSProto_Object));
             return script;
         }
 
         /* Function scripts with names have local variables of that name. */
         if (script->fun && id == ATOM_TO_JSID(script->fun->atom)) {
             TypeSet *types = script->getVariable(cx, id);
             types->addType(cx, (jstype) script->function());
             return script;
@@ -2307,32 +2012,32 @@ TrashScope(JSContext *cx, Script *script
         if (!script->isEval()) {
             TypeSet *types = script->getVariable(cx, id);
             types->addType(cx, TYPE_UNKNOWN);
         }
         if (!script->parent)
             break;
         script = script->parent->analysis;
     }
-    TypeSet *types = cx->getGlobalTypeObject()->getProperty(cx, id, true);
+    TypeSet *types = cx->globalTypeObject()->getProperty(cx, id, true);
     types->addType(cx, TYPE_UNKNOWN);
 }
 
 static inline jsid
 GetAtomId(JSContext *cx, Script *script, const jsbytecode *pc, unsigned offset)
 {
     unsigned index = js_GetIndexFromBytecode(cx, script->getScript(), (jsbytecode*) pc, offset);
-    return MakeTypeId(ATOM_TO_JSID(script->getScript()->getAtom(index)));
+    return MakeTypeId(cx, ATOM_TO_JSID(script->getScript()->getAtom(index)));
 }
 
 static inline jsid
 GetGlobalId(JSContext *cx, Script *script, const jsbytecode *pc)
 {
     unsigned index = GET_SLOTNO(pc);
-    return MakeTypeId(ATOM_TO_JSID(script->getScript()->getGlobalAtom(index)));
+    return MakeTypeId(cx, ATOM_TO_JSID(script->getScript()->getGlobalAtom(index)));
 }
 
 static inline JSObject *
 GetScriptObject(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset)
 {
     unsigned index = js_GetIndexFromBytecode(cx, script, (jsbytecode*) pc, offset);
     return script->getObject(index);
 }
@@ -2553,17 +2258,17 @@ Script::analyzeTypes(JSContext *cx, Byte
       case JSOP_ADDATTRVAL:
       case JSOP_XMLELTEXPR:
         code->setFixed(cx, 0, TYPE_STRING);
         break;
       case JSOP_NULL:
         code->setFixed(cx, 0, TYPE_NULL);
         break;
       case JSOP_REGEXP:
-        code->setFixed(cx, 0, (jstype) cx->getFixedTypeObject(TYPE_OBJECT_NEW_REGEXP));
+        code->setFixed(cx, 0, (jstype) cx->getTypeNewObject(JSProto_RegExp));
         break;
 
       case JSOP_STOP:
         /* If a stop is reachable then the return type may be void. */
         if (fun)
             function()->returnTypes.addType(cx, TYPE_UNDEFINED);
         break;
 
@@ -2623,17 +2328,17 @@ Script::analyzeTypes(JSContext *cx, Byte
             JSObject *obj;
             JSProperty *prop;
             js_LookupPropertyWithFlags(cx, cx->globalObject, id,
                                        JSRESOLVE_QUALIFIED, &obj, &prop);
             uint64_t endTime = cx->compartment->types.currentTime();
             cx->compartment->types.analysisTime -= (endTime - startTime);
 
             /* Handle as a property access. */
-            PropertyAccess(cx, code, cx->getGlobalTypeObject(), false, code->pushed(0), id);
+            PropertyAccess(cx, code, cx->globalTypeObject(), false, code->pushed(0), id);
         } else if (scope) {
             /* Definitely a local variable. */
             TypeSet *types = scope->getVariable(cx, id);
             types->addSubset(cx, scope->pool, code->pushed(0));
         } else {
             /* Ambiguous access, unknown result. */
             code->setFixed(cx, 0, TYPE_UNKNOWN);
         }
@@ -2650,34 +2355,34 @@ Script::analyzeTypes(JSContext *cx, Byte
         break;
 
       case JSOP_SETGNAME:
       case JSOP_SETNAME: {
         jsid id = GetAtomId(cx, this, pc, 0);
 
         const AnalyzeStateStack &stack = state.popped(1);
         if (stack.scope == SCOPE_GLOBAL) {
-            PropertyAccess(cx, code, cx->getGlobalTypeObject(), true, code->popped(0), id);
+            PropertyAccess(cx, code, cx->globalTypeObject(), true, code->popped(0), id);
         } else if (stack.scope) {
             TypeSet *types = stack.scope->getVariable(cx, id);
             code->popped(0)->addSubset(cx, pool, types);
         } else {
             cx->compartment->types.monitorBytecode(cx, code);
         }
 
         MergePushed(cx, pool, code, 0, code->popped(0));
         break;
       }
 
       case JSOP_GETXPROP: {
         jsid id = GetAtomId(cx, this, pc, 0);
 
         const AnalyzeStateStack &stack = state.popped(0);
         if (stack.scope == SCOPE_GLOBAL) {
-            PropertyAccess(cx, code, cx->getGlobalTypeObject(), false, code->pushed(0), id);
+            PropertyAccess(cx, code, cx->globalTypeObject(), false, code->pushed(0), id);
         } else if (stack.scope) {
             TypeSet *types = stack.scope->getVariable(cx, id);
             types->addSubset(cx, stack.scope->pool, code->pushed(0));
         } else {
             code->setFixed(cx, 0, TYPE_UNKNOWN);
         }
 
         break;
@@ -2686,18 +2391,18 @@ Script::analyzeTypes(JSContext *cx, Byte
       case JSOP_INCNAME:
       case JSOP_DECNAME:
       case JSOP_NAMEINC:
       case JSOP_NAMEDEC: {
         jsid id = GetAtomId(cx, this, pc, 0);
 
         Script *scope = SearchScope(cx, this, code->inStack, id);
         if (scope == SCOPE_GLOBAL) {
-            PropertyAccess(cx, code, cx->getGlobalTypeObject(), true, NULL, id);
-            PropertyAccess(cx, code, cx->getGlobalTypeObject(), false, code->pushed(0), id);
+            PropertyAccess(cx, code, cx->globalTypeObject(), true, NULL, id);
+            PropertyAccess(cx, code, cx->globalTypeObject(), false, code->pushed(0), id);
         } else if (scope) {
             TypeSet *types = scope->getVariable(cx, id);
             types->addSubset(cx, scope->pool, code->pushed(0));
             types->addArith(cx, scope->pool, code, types);
             if (code->hasIncDecOverflow)
                 types->addType(cx, TYPE_DOUBLE);
         } else {
             cx->compartment->types.monitorBytecode(cx, code);
@@ -2711,42 +2416,42 @@ Script::analyzeTypes(JSContext *cx, Byte
         /*
          * Even though they are on the global object, GLOBAL accesses do not run into
          * the issues which require monitoring that other property accesses do:
          * __proto__ is still emitted as a SETGNAME even if there is a 'var __proto__',
          * and there will be no getter/setter in a prototype, and 'constructor',
          * 'prototype' and 'caller' do not have special meaning on the global object.
          */
         jsid id = (op == JSOP_SETGLOBAL) ? GetGlobalId(cx, this, pc) : GetAtomId(cx, this, pc, 0);
-        TypeSet *types = cx->getGlobalTypeObject()->getProperty(cx, id, true);
+        TypeSet *types = cx->globalTypeObject()->getProperty(cx, id, true);
         code->popped(0)->addSubset(cx, pool, types);
         MergePushed(cx, pool, code, 0, code->popped(0));
         break;
       }
 
       case JSOP_INCGLOBAL:
       case JSOP_DECGLOBAL:
       case JSOP_GLOBALINC:
       case JSOP_GLOBALDEC: {
         jsid id = GetGlobalId(cx, this, pc);
-        TypeSet *types = cx->getGlobalTypeObject()->getProperty(cx, id, true);
+        TypeSet *types = cx->globalTypeObject()->getProperty(cx, id, true);
         types->addArith(cx, cx->compartment->types.pool, code, types);
         MergePushed(cx, cx->compartment->types.pool, code, 0, types);
         if (code->hasIncDecOverflow)
             types->addType(cx, TYPE_DOUBLE);
         break;
       }
 
       case JSOP_INCGNAME:
       case JSOP_DECGNAME:
       case JSOP_GNAMEINC:
       case JSOP_GNAMEDEC: {
         jsid id = GetAtomId(cx, this, pc, 0);
-        PropertyAccess(cx, code, cx->getGlobalTypeObject(), true, NULL, id);
-        PropertyAccess(cx, code, cx->getGlobalTypeObject(), false, code->pushed(0), id);
+        PropertyAccess(cx, code, cx->globalTypeObject(), true, NULL, id);
+        PropertyAccess(cx, code, cx->globalTypeObject(), false, code->pushed(0), id);
         break;
       }
 
       case JSOP_GETUPVAR:
       case JSOP_CALLUPVAR:
       case JSOP_GETFCSLOT:
       case JSOP_CALLFCSLOT: {
         unsigned index = GET_UINT16(pc);
@@ -2862,25 +2567,25 @@ Script::analyzeTypes(JSContext *cx, Byte
 
       case JSOP_ARGUMENTS: {
         /*
          * This can show up either when the arguments array is being accessed
          * or when there is a local variable named arguments.
          */
         JS_ASSERT(fun);
         TypeSet *types = getVariable(cx, id_arguments(cx));
-        types->addType(cx, (jstype) cx->getFixedTypeObject(TYPE_OBJECT_ARGUMENTS));
+        types->addType(cx, (jstype) cx->getTypeNewObject(JSProto_Object));
         MergePushed(cx, pool, code, 0, types);
         break;
       }
 
       case JSOP_ARGCNT: {
         JS_ASSERT(fun);
         TypeSet *types = getVariable(cx, id_arguments(cx));
-        types->addType(cx, (jstype) cx->getFixedTypeObject(TYPE_OBJECT_ARGUMENTS));
+        types->addType(cx, (jstype) cx->getTypeNewObject(JSProto_Object));
 
         types->addGetProperty(cx, code, code->pushed(0), id_length(cx));
         break;
       }
 
       case JSOP_SETPROP:
       case JSOP_SETMETHOD: {
         jsid id = GetAtomId(cx, this, pc, 0);
@@ -2985,17 +2690,17 @@ Script::analyzeTypes(JSContext *cx, Byte
         code->popped(0)->addGetProperty(cx, code, code->pushed(0), id_length(cx));
         break;
 
       case JSOP_THIS:
         thisTypes.addTransformThis(cx, pool, code->pushed(0));
 
         /* 'this' refers to the parent global/scope object in non-function scripts. */
         if (!fun)
-            code->setFixed(cx, 0, (jstype) cx->getGlobalTypeObject());
+            code->setFixed(cx, 0, (jstype) cx->globalTypeObject());
         break;
 
       case JSOP_RETURN:
       case JSOP_SETRVAL:
         if (fun)
             code->popped(0)->addSubset(cx, pool, &function()->returnTypes);
         break;
 
@@ -3024,17 +2729,17 @@ Script::analyzeTypes(JSContext *cx, Byte
       case JSOP_DEFLOCALFUN:
       case JSOP_DEFLOCALFUN_FC: {
         unsigned funOffset = 0;
         if (op == JSOP_DEFLOCALFUN || op == JSOP_DEFLOCALFUN_FC)
             funOffset = SLOTNO_LEN;
 
         unsigned off = (op == JSOP_DEFLOCALFUN || op == JSOP_DEFLOCALFUN_FC) ? SLOTNO_LEN : 0;
         JSObject *obj = GetScriptObject(cx, script, pc, off);
-        TypeFunction *function = obj->getTypeObject()->asFunction();
+        TypeFunction *function = obj->getType()->asFunction();
 
         /* Remember where this script was defined. */
         function->script->analysis->parent = script;
         function->script->analysis->parentpc = pc;
 
         TypeSet *res = NULL;
 
         if (op == JSOP_LAMBDA || op == JSOP_LAMBDA_FC) {
@@ -3043,17 +2748,17 @@ Script::analyzeTypes(JSContext *cx, Byte
             jsid id = getLocalId(GET_SLOTNO(pc), code);
             res = evalParent()->getVariable(cx, id);
         } else {
             JSAtom *atom = obj->getFunctionPrivate()->atom;
             JS_ASSERT(atom);
             jsid id = ATOM_TO_JSID(atom);
             if (isGlobal()) {
                 /* Defined function at global scope. */
-                res = cx->getGlobalTypeObject()->getProperty(cx, id, true);
+                res = cx->globalTypeObject()->getProperty(cx, id, true);
             } else {
                 /* Defined function in a function eval() or ambiguous function scope. */
                 TrashScope(cx, this, id);
                 break;
             }
         }
 
         if (res)
@@ -3117,17 +2822,17 @@ Script::analyzeTypes(JSContext *cx, Byte
             if (!js_InternNonIntElementId(cx, NULL, val, &id))
                 JS_NOT_REACHED("Bad");
             types = object->getProperty(cx, id, true);
         } else {
             types = object->getProperty(cx, JSID_VOID, true);
         }
 
         if (state.hasGetSet)
-            types->addType(cx, (jstype) cx->getFixedTypeObject(TYPE_OBJECT_GETSET));
+            types->addType(cx, (jstype) cx->getTypeGetSet());
         else if (state.hasHole)
             cx->markTypeArrayNotPacked(object, false);
         else
             code->popped(0)->addSubset(cx, pool, types);
         state.hasGetSet = false;
         state.hasHole = false;
         break;
       }
@@ -3149,17 +2854,17 @@ Script::analyzeTypes(JSContext *cx, Byte
         code->pushed(0)->addType(cx, (jstype) object);
 
         jsid id = GetAtomId(cx, this, pc, 0);
         TypeSet *types = object->getProperty(cx, id, true);
 
         if (id == id___proto__(cx) || id == id_prototype(cx))
             cx->compartment->types.monitorBytecode(cx, code);
         else if (state.hasGetSet)
-            types->addType(cx, (jstype) cx->getFixedTypeObject(TYPE_OBJECT_GETSET));
+            types->addType(cx, (jstype) cx->getTypeGetSet());
         else
             code->popped(0)->addSubset(cx, pool, types);
         state.hasGetSet = false;
         JS_ASSERT(!state.hasHole);
         break;
       }
 
       case JSOP_ENTERWITH:
@@ -3200,27 +2905,27 @@ Script::analyzeTypes(JSContext *cx, Byte
         code->setFixed(cx, 1, TYPE_BOOLEAN);
         break;
 
       case JSOP_FORNAME: {
         jsid id = GetAtomId(cx, this, pc, 0);
         Script *scope = SearchScope(cx, this, code->inStack, id);
 
         if (scope == SCOPE_GLOBAL)
-            SetForTypes(cx, state, code, cx->getGlobalTypeObject()->getProperty(cx, id, true));
+            SetForTypes(cx, state, code, cx->globalTypeObject()->getProperty(cx, id, true));
         else if (scope)
             SetForTypes(cx, state, code, scope->getVariable(cx, id));
         else
             cx->compartment->types.monitorBytecode(cx, code);
         break;
       }
 
       case JSOP_FORGLOBAL: {
         jsid id = GetGlobalId(cx, this, pc);
-        SetForTypes(cx, state, code, cx->getGlobalTypeObject()->getProperty(cx, id, true));
+        SetForTypes(cx, state, code, cx->globalTypeObject()->getProperty(cx, id, true));
         break;
       }
 
       case JSOP_FORLOCAL: {
         jsid id = getLocalId(GET_SLOTNO(pc), code);
         JS_ASSERT(!JSID_IS_VOID(id));
 
         SetForTypes(cx, state, code, evalParent()->getVariable(cx, id)); 
@@ -3285,17 +2990,17 @@ Script::analyzeTypes(JSContext *cx, Byte
         break;
 
       case JSOP_UNBRAND:
         MergePushed(cx, pool, code, 0, code->popped(0));
         break;
 
       case JSOP_GENERATOR:
         if (fun) {
-            TypeObject *object = cx->getFixedTypeObject(TYPE_OBJECT_NEW_GENERATOR);
+            TypeObject *object = cx->getTypeNewObject(JSProto_Generator);
             function()->returnTypes.addType(cx, (jstype) object);
         }
         break;
 
       case JSOP_YIELD:
         code->setFixed(cx, 0, TYPE_UNKNOWN);
         break;
 
@@ -3319,17 +3024,17 @@ Script::analyzeTypes(JSContext *cx, Byte
       case JSOP_XMLCDATA:
       case JSOP_XMLCOMMENT:
       case JSOP_DESCENDANTS:
       case JSOP_TOATTRNAME:
       case JSOP_QNAMECONST:
       case JSOP_QNAME:
       case JSOP_ANYNAME:
       case JSOP_GETFUNNS:
-        code->setFixed(cx, 0, (jstype) cx->getFixedTypeObject(TYPE_OBJECT_XML));
+        code->setFixed(cx, 0, TYPE_UNKNOWN);
         break;
 
       case JSOP_FILTER:
         /* Note: the second value pushed by filter is a hole, and not modelled. */
         MergePushed(cx, pool, code, 0, code->popped(0));
         code->pushedArray[0].group()->boundWith = true;
 
         /* Name binding inside filters is currently broken :FIXME: bug 605200. */
@@ -3745,77 +3450,8 @@ Script::finish(JSContext *cx)
         object = object->next;
     }
 
 #endif /* DEBUG */
 
 }
 
 } } /* namespace js::analyze */
-
-/////////////////////////////////////////////////////////////////////
-// Tracing
-/////////////////////////////////////////////////////////////////////
-
-namespace js {
-
-static inline void
-TraceObjectList(JSTracer *trc, types::TypeObject *objects)
-{
-    types::TypeObject *object = objects;
-    while (object) {
-        gc::MarkString(trc, JSID_TO_STRING(object->name), "type_object_name");
-
-        if (object->propertyCount >= 2) {
-            unsigned capacity = types::HashSetCapacity(object->propertyCount);
-            for (unsigned i = 0; i < capacity; i++) {
-                types::Property *prop = object->propertySet[i];
-                if (prop && !JSID_IS_VOID(prop->id))
-                    gc::MarkString(trc, JSID_TO_STRING(prop->id), "type_property");
-            }
-        } else if (object->propertyCount == 1) {
-            types::Property *prop = (types::Property *) object->propertySet;
-            if (!JSID_IS_VOID(prop->id))
-                gc::MarkString(trc, JSID_TO_STRING(prop->id), "type_property");
-        }
-
-        object = object->next;
-    }
-}
-
-void
-analyze::Script::trace(JSTracer *trc)
-{
-    if (fun) {
-        JS_SET_TRACING_NAME(trc, "type_script");
-        gc::Mark(trc, fun);
-    }
-
-    TraceObjectList(trc, objects);
-
-    if (variableCount >= 2) {
-        unsigned capacity = types::HashSetCapacity(variableCount);
-        for (unsigned i = 0; i < capacity; i++) {
-            types::Variable *var = variableSet[i];
-            if (var)
-                gc::MarkString(trc, JSID_TO_STRING(var->id), "type_property");
-        }
-    } else if (variableCount == 1) {
-        types::Variable *var = (types::Variable *) variableSet;
-        gc::MarkString(trc, JSID_TO_STRING(var->id), "type_property");
-    }
-
-    unsigned nameCount = script->nfixed + argCount();
-    for (unsigned i = 0; i < nameCount; i++) {
-        if (localNames[i]) {
-            JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[i]);
-            gc::MarkString(trc, ATOM_TO_STRING(atom), "type_script_local");
-        }
-    }
-}
-
-void
-types::TypeCompartment::trace(JSTracer *trc)
-{
-    TraceObjectList(trc, objects);
-}
-
-} /* namespace js */
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -217,17 +217,17 @@ struct TypeSet
     TypeSet(JSArenaPool *pool)
         : typeFlags(0), objectSet(NULL), objectCount(0), constraintList(NULL)
     {
         setPool(pool);
     }
 
     void setPool(JSArenaPool *pool)
     {
-#ifdef DEBUG
+#if defined DEBUG && defined JS_TYPE_INFERENCE
         this->id_ = ++typesetCount;
         this->pool = pool;
 #endif
     }
 
     void print(JSContext *cx);
 
     /* Whether this set contains a specific type. */
@@ -241,16 +241,17 @@ struct TypeSet
 
     /* Add specific kinds of constraints to this set. */
     inline void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
     void addSubset(JSContext *cx, JSArenaPool &pool, TypeSet *target);
     void addGetProperty(JSContext *cx, analyze::Bytecode *code, TypeSet *target, jsid id);
     void addSetProperty(JSContext *cx, analyze::Bytecode *code, TypeSet *target, jsid id);
     void addGetElem(JSContext *cx, analyze::Bytecode *code, TypeSet *object, TypeSet *target);
     void addSetElem(JSContext *cx, analyze::Bytecode *code, TypeSet *object, TypeSet *target);
+    void addNewObject(JSContext *cx, JSArenaPool &pool, TypeSet *target);
     void addCall(JSContext *cx, TypeCallsite *site);
     void addArith(JSContext *cx, JSArenaPool &pool, analyze::Bytecode *code,
                   TypeSet *target, TypeSet *other = NULL);
     void addTransformThis(JSContext *cx, JSArenaPool &pool, TypeSet *target);
     void addFilterPrimitives(JSContext *cx, JSArenaPool &pool, TypeSet *target, bool onlyNullVoid);
     void addMonitorRead(JSContext *cx, JSArenaPool &pool, analyze::Bytecode *code, TypeSet *target);
 
     /*
@@ -402,48 +403,47 @@ struct Property
 
     static uint32 keyBits(jsid id) { return (uint32) JSID_BITS(id); }
     static jsid getKey(Property *p) { return p->id; }
 };
 
 /* Type information about an object accessed by a script. */
 struct TypeObject
 {
-    /*
-     * Name of this object.  This is unique among all objects in the compartment;
-     * if someone tries to make an object with the same name, they will get back
-     * this object instead.
-     */
-    jsid name;
+#ifdef DEBUG
+    /* Name of this object. */
+    jsid name_;
+#endif
+
+    /* Prototype shared by objects using this type. */
+    JSObject *proto;
+
+    /* Lazily filled array of empty shapes for each size of objects with this type. */
+    js::EmptyShape **emptyShapes;
 
     /* Whether this is a function object, and may be cast into TypeFunction. */
     bool isFunction;
 
+    /* Mark bit for GC. */
+    bool marked;
+
     /*
-     * Properties of this object. This is filled in lazily for function objects
-     * to avoid unnecessary prototype and new object creation.
+     * Properties of this object. This may contain JSID_VOID, representing the types
+     * of all integer indexes of the object, and/or JSID_EMPTY, representing the types
+     * of new objects that can be created with different instances of this type.
      */
     Property **propertySet;
     unsigned propertyCount;
 
-    /*
-     * Prototype of this object. This is immutable; setting or changing the __proto__
-     * property of an object causes its properties to become unknown.
-     */
-    TypeObject *prototype;
-
     /* List of objects using this one as their prototype. */
     TypeObject *instanceList;
 
     /* Chain for objects sharing the same prototype. */
     TypeObject *instanceNext;
 
-    /* Object to use in ConstructThis with this as the prototype. :XXX: fuse with instance. */
-    TypeObject *newObject;
-
     /*
      * Pool in which this object was allocated, and link in the list of objects
      * for that pool.
      */
     JSArenaPool *pool;
     TypeObject *next;
 
     /* Whether all the properties of this object are unknown. */
@@ -457,198 +457,109 @@ struct TypeObject
 
     /*
      * Whether this object is thought to be a possible packed array: either it came
      * from a [a,b,c] initializer, an Array(a,b,c) call, or is another array for
      * which we've seen what looks like initialization code. This is purely heuristic.
      */
     bool possiblePackedArray;
 
+    TypeObject() {}
+
     /* Make an object with the specified name. */
-    TypeObject(JSContext *cx, JSArenaPool *pool, jsid id, TypeObject *prototype);
+    inline TypeObject(JSArenaPool *pool, jsid id, JSObject *proto);
 
     /* Coerce this object to a function. */
     TypeFunction* asFunction()
     {
         JS_ASSERT(isFunction);
         return (TypeFunction *) this;
     }
 
     /*
+     * Return an immutable, shareable, empty shape with the same clasp as this
+     * and the same slotSpan as this had when empty.
+     *
+     * If |this| is the scope of an object |proto|, the resulting scope can be
+     * used as the scope of a new object whose prototype is |proto|.
+     */
+    inline bool canProvideEmptyShape(js::Class *clasp);
+    inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp,
+                                         /* gc::FinalizeKind */ unsigned kind);
+
+    /*
      * Get or create a property of this object. Only call this for properties which
      * a script accesses explicitly. 'assign' indicates whether this is for an
      * assignment, and the own types of the property will be used instead of
      * aggregate types.
      */
     inline TypeSet *getProperty(JSContext *cx, jsid id, bool assign);
 
-    /* Whether this type has Array.prototype in its prototype chain. */
-    inline bool isArray(JSContext *cx);
+    inline const char * name();
+
+    /* Mark proto as the prototype of this object and all instances. */
+    void splicePrototype(JSObject *proto);
 
     /* Helpers */
 
     void addPrototype(JSContext *cx, TypeObject *proto);
     void addProperty(JSContext *cx, jsid id, Property *&prop);
     void markUnknown(JSContext *cx);
     void storeToInstances(JSContext *cx, Property *base);
-    TypeObject *getNewObject(JSContext *cx);
 
     void print(JSContext *cx);
+    void trace(JSTracer *trc);
 };
 
 /* Type information about an interpreted or native function. */
 struct TypeFunction : public TypeObject
 {
     /* If this function is native, the handler to use at calls to it. */
     JSTypeHandler handler;
 
     /* If this function is interpreted, the corresponding script. */
     JSScript *script;
 
-    /* Default prototype object of this function. */
-    TypeObject *prototypeObject;
-
     /*
      * For interpreted functions and functions with dynamic handlers, the possible
      * return types of the function.
      */
     TypeSet returnTypes;
 
     /*
-     * Whether this is the constructor for a builtin class, whose prototype must
-     * be specified manually.
-     */
-    bool isBuiltin;
-
-    /*
      * Whether this is a generic native handler, and treats its first parameter
      * the way it normally would its 'this' variable, e.g. Array.reverse(arr)
      * instead of arr.reverse().
      */
     bool isGeneric;
 
-    TypeFunction(JSContext *cx, JSArenaPool *pool, jsid id, TypeObject *prototype);
+    inline TypeFunction(JSArenaPool *pool, jsid id, JSObject *proto);
 };
 
-/*
- * Singleton type objects referred to at various points in the system.
- * At most one of these will exist for each compartment, though many JSObjects
- * may use them for type information.
- */
-enum FixedTypeObjectName
-{
-    /* Functions. */
-    TYPE_OBJECT_OBJECT,
-    TYPE_OBJECT_FUNCTION,
-    TYPE_OBJECT_ARRAY,
-    TYPE_OBJECT_FUNCTION_PROTOTYPE,
-    TYPE_OBJECT_EMPTY_FUNCTION,
-
-    /* Builtin prototypes and 'new' objects. */
-    TYPE_OBJECT_OBJECT_PROTOTYPE,
-    TYPE_OBJECT_ARRAY_PROTOTYPE,
-    TYPE_OBJECT_NEW_BOOLEAN,
-    TYPE_OBJECT_NEW_NUMBER,
-    TYPE_OBJECT_NEW_STRING,
-    TYPE_OBJECT_NEW_REGEXP,
-    TYPE_OBJECT_NEW_ITERATOR,
-    TYPE_OBJECT_NEW_GENERATOR,
-    TYPE_OBJECT_NEW_ARRAYBUFFER,
-
-    /* Builtin objects with unknown properties. */
-    TYPE_OBJECT_XML,
-    TYPE_OBJECT_ARGUMENTS,
-    TYPE_OBJECT_NOSUCHMETHOD,
-    TYPE_OBJECT_NOSUCHMETHOD_ARGUMENTS,
-    TYPE_OBJECT_PROPERTY_DESCRIPTOR,
-    TYPE_OBJECT_KEY_VALUE_PAIR,
-    TYPE_OBJECT_JSON,
-    TYPE_OBJECT_PROXY,
-
-    /* Builtin Array objects. */
-    TYPE_OBJECT_REGEXP_MATCH_ARRAY,
-    TYPE_OBJECT_STRING_SPLIT_ARRAY,
-    TYPE_OBJECT_UNKNOWN_ARRAY,
-    TYPE_OBJECT_CLONE_ARRAY,
-    TYPE_OBJECT_PROPERTY_ARRAY,
-    TYPE_OBJECT_REFLECT_ARRAY,
-
-    /* Builtin Object objects. */
-    TYPE_OBJECT_UNKNOWN_OBJECT,
-    TYPE_OBJECT_CLONE_OBJECT,
-    TYPE_OBJECT_REFLECT_OBJECT,
-    TYPE_OBJECT_XML_SETTINGS,
-
-    /* Objects which probably can't escape to scripts. Maybe condense these. */
-    TYPE_OBJECT_GETSET,  /* For properties with a scripted getter/setter. */
-    TYPE_OBJECT_REGEXP_STATICS,
-    TYPE_OBJECT_CALL,
-    TYPE_OBJECT_DECLENV,
-    TYPE_OBJECT_SHARP_ARRAY,
-    TYPE_OBJECT_WITH,
-    TYPE_OBJECT_BLOCK,
-    TYPE_OBJECT_NULL_CLOSURE,
-    TYPE_OBJECT_PROPERTY_ITERATOR,
-    TYPE_OBJECT_SCRIPT,
-
-    TYPE_OBJECT_FIXED_LIMIT
-};
-
-extern const char* const fixedTypeObjectNames[];
-
 /* Type information for a compartment. */
 struct TypeCompartment
 {
     /*
      * Pool for compartment-wide objects and their variables and constraints.
      * These aren't collected until the compartment is destroyed.
      */
     JSArenaPool pool;
     TypeObject *objects;
 
-    TypeObject *fixedTypeObjects[TYPE_OBJECT_FIXED_LIMIT];
-
     /* Number of scripts in this compartment. */
     unsigned scriptCount;
 
     /* Whether the interpreter is currently active (we are not inferring types). */
     bool interpreting;
 
-    /* Object containing all global variables. root of all parent chains. */
-    TypeObject *globalObject;
+    /* Object to use throughout the compartment as the default type of objects with no prototype. */
+    TypeObject emptyObject;
 
-    struct IdHasher
-    {
-        typedef jsid Lookup;
-        static uint32 hashByte(uint32 hash, uint8 byte) {
-            hash = (hash << 4) + byte;
-            uint32 x = hash & 0xF0000000L;
-            if (x)
-                hash ^= (x >> 24);
-            return hash & ~x;
-        }
-        static uint32 hash(jsid id) {
-            /* Do an ELF hash of the lower four bytes of the ID. */
-            uint32 hash = 0, v = uint32(JSID_BITS(id));
-            hash = hashByte(hash, v & 0xff);
-            v >>= 8;
-            hash = hashByte(hash, v & 0xff);
-            v >>= 8;
-            hash = hashByte(hash, v & 0xff);
-            v >>= 8;
-            return hashByte(hash, v & 0xff);
-        }
-        static bool match(jsid id0, jsid id1) {
-            return id0 == id1;
-        }
-    };
-
-    /* Map from object names to the object. */
-    typedef HashMap<jsid, TypeObject*, IdHasher, SystemAllocPolicy> ObjectNameTable;
-    ObjectNameTable *objectNameTable;
+    /* Dummy object added to properties which can have scripted getters/setters. */
+    TypeObject *typeGetSet;
 
     /* Pending recompilations to perform before execution of JIT code can resume. */
     Vector<JSScript*> *pendingRecompiles;
 
     /* Constraint solving worklist structures. */
 
     /* A type that needs to be registered with a constraint. */
     struct PendingWork
@@ -695,48 +606,46 @@ struct TypeCompartment
         gettimeofday(&current, NULL);
         return current.tv_sec * (uint64_t) 1000000 + current.tv_usec;
 #else
         /* Timing not available on Windows. */
         return 0;
 #endif
     }
 
-    TypeObject *makeFixedTypeObject(JSContext *cx, FixedTypeObjectName which);
-
     /* Add a type to register with a list of constraints. */
     inline void addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, jstype type);
     void growPendingArray();
 
     /* Resolve pending type registrations, excluding delayed ones. */
     inline void resolvePending(JSContext *cx);
 
     /* Prints results of this compartment if spew is enabled, checks for warnings. */
     void finish(JSContext *cx, JSCompartment *compartment);
 
-    /* Get a function or non-function object associated with an optional script. */
-    TypeObject *getTypeObject(JSContext *cx, analyze::Script *script,
-                              const char *name, bool isFunction, TypeObject *prototype);
+    /* Make a function or non-function object associated with an optional script. */
+    TypeObject *newTypeObject(JSContext *cx, analyze::Script *script,
+                              const char *name, bool isFunction, JSObject *proto);
 
     /*
      * Add the specified type to the specified set, do any necessary reanalysis
      * stemming from the change and recompile any affected scripts.
      */
     void addDynamicType(JSContext *cx, TypeSet *types, jstype type);
     void addDynamicPush(JSContext *cx, analyze::Bytecode &code, unsigned index, jstype type);
     void dynamicAssign(JSContext *cx, JSObject *obj, jsid id, const Value &rval);
 
     inline bool hasPendingRecompiles() { return pendingRecompiles != NULL; }
     void processPendingRecompiles(JSContext *cx);
     void addPendingRecompile(JSContext *cx, JSScript *script);
 
     /* Monitor future effects on a bytecode. */
     void monitorBytecode(JSContext *cx, analyze::Bytecode *code);
 
-    void trace(JSTracer *trc);
+    void sweep(JSContext *cx);
 };
 
 enum SpewChannel {
     ISpewDynamic,  /* dynamic: Dynamic type changes and inference entry points. */
     ISpewOps,      /* ops: New constraints and types. */
     ISpewResult,   /* result: Final type sets. */
     SPEW_COUNT
 };
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -46,18 +46,16 @@
 
 #ifndef jsinferinlines_h___
 #define jsinferinlines_h___
 
 /////////////////////////////////////////////////////////////////////
 // Types
 /////////////////////////////////////////////////////////////////////
 
-#ifdef JS_TYPE_INFERENCE
-
 namespace js {
 namespace types {
 
 inline jstype
 GetValueType(JSContext *cx, const Value &val)
 {
     if (val.isDouble())
         return TYPE_DOUBLE;
@@ -69,32 +67,32 @@ GetValueType(JSContext *cx, const Value 
       case JSVAL_TYPE_BOOLEAN:
         return TYPE_BOOLEAN;
       case JSVAL_TYPE_STRING:
         return TYPE_STRING;
       case JSVAL_TYPE_NULL:
         return TYPE_NULL;
       case JSVAL_TYPE_OBJECT: {
         JSObject *obj = &val.toObject();
-        JS_ASSERT(obj->typeObject);
-        return (jstype) obj->typeObject;
+        JS_ASSERT(obj->type);
+        return (jstype) obj->type;
       }
       default:
         JS_NOT_REACHED("Unknown value");
         return (jstype) 0;
     }
 }
 
 /*
  * Get the canonical representation of an id to use when doing inference.  This
  * maintains the constraint that if two different jsids map to the same property
  * in JS (e.g. 3 and "3"), they have the same type representation.
  */
 inline jsid
-MakeTypeId(jsid id)
+MakeTypeId(JSContext *cx, jsid id)
 {
     if (JSID_IS_VOID(id))
         return JSID_VOID;
 
     /*
      * All integers must map to the aggregate property for index types, including
      * negative integers.
      */
@@ -102,30 +100,30 @@ MakeTypeId(jsid id)
         return JSID_VOID;
 
     /* TODO: XML does this.  Is this the right behavior? */
     if (JSID_IS_OBJECT(id))
         return JSID_VOID;
 
     /*
      * Check for numeric strings, as in js_StringIsIndex, but allow negative
-     * and overflowing integers.  TODO: figure out the canonical representation
-     * for doubles, particularly NaN vs. overflowing integer doubles.
+     * and overflowing integers.
      */
     if (JSID_IS_STRING(id)) {
         JSString *str = JSID_TO_STRING(id);
         jschar *cp = str->chars();
         if (JS7_ISDEC(*cp) || *cp == '-') {
             cp++;
             while (JS7_ISDEC(*cp))
                 cp++;
             if (unsigned(cp - str->chars()) == str->length())
                 return JSID_VOID;
         }
-        return id;
+        /* :FIXME: bug 613221 sweep type constraints so that atoms don't need to be pinned. */
+        return ATOM_TO_JSID(js_AtomizeString(cx, str, ATOM_PINNED));
     }
 
     JS_NOT_REACHED("Unknown id");
     return JSID_VOID;
 }
 
 /* Convert an id for printing during debug. */
 static inline const char *
@@ -136,117 +134,59 @@ TypeIdString(jsid id)
     return TypeIdStringImpl(id);
 #else
     return "(missing)";
 #endif
 }
 
 } } /* namespace js::types */
 
-#endif /* JS_TYPE_INFERENCE */
-
 /////////////////////////////////////////////////////////////////////
 // JSContext
 /////////////////////////////////////////////////////////////////////
 
 inline js::types::TypeObject *
-JSContext::getTypeFunction(const char *name, js::types::TypeObject *prototype)
+JSContext::getTypeNewObject(JSProtoKey key)
 {
-#ifdef JS_TYPE_INFERENCE
-    if (!prototype)
-        prototype = getFixedTypeObject(js::types::TYPE_OBJECT_FUNCTION_PROTOTYPE);
-    return compartment->types.getTypeObject(this, NULL, name, true, prototype);
-#else
-    return NULL;
-#endif
+    JSObject *proto;
+    if (!js_GetClassPrototype(this, NULL, key, &proto, NULL))
+        return NULL;
+    return proto->getNewType(this);
 }
 
 inline js::types::TypeObject *
-JSContext::getTypeObject(const char *name, js::types::TypeObject *prototype)
+JSContext::globalTypeObject()
 {
-#ifdef JS_TYPE_INFERENCE
-    if (!prototype)
-        prototype = getFixedTypeObject(js::types::TYPE_OBJECT_OBJECT_PROTOTYPE);
-    return compartment->types.getTypeObject(this, NULL, name, false, prototype);
-#else
-    return NULL;
-#endif
+    return globalObject->getType();
 }
 
 inline js::types::TypeObject *
-JSContext::getGlobalTypeObject()
+JSContext::emptyTypeObject()
 {
-#ifdef JS_TYPE_INFERENCE
-    if (!compartment->types.globalObject) {
-        js::types::TypeObject *prototype = getFixedTypeObject(js::types::TYPE_OBJECT_OBJECT_PROTOTYPE);
-        compartment->types.globalObject = getTypeObject("Global", prototype);
-    }
-    return compartment->types.globalObject;
-#else
-    return NULL;
-#endif
+    return &compartment->types.emptyObject;
 }
 
 inline void
 JSContext::setTypeFunctionScript(JSFunction *fun, JSScript *script)
 {
 #ifdef JS_TYPE_INFERENCE
-    char name[8];
-    JS_snprintf(name, 16, "#%u", script->analysis->id);
-
-    js::types::TypeObject *proto = getFixedTypeObject(js::types::TYPE_OBJECT_FUNCTION_PROTOTYPE);
-    js::types::TypeFunction *typeFun =
-        compartment->types.getTypeObject(this, script->analysis, name, true, proto)->asFunction();
-
-    /* We should not be attaching multiple scripts to the same function. */
-    if (typeFun->script) {
-        JS_ASSERT(typeFun->script == script);
-        fun->typeObject = typeFun;
-        return;
-    }
+    js::types::TypeFunction *typeFun = fun->getType()->asFunction();
 
     typeFun->script = script;
-    fun->typeObject = typeFun;
+    fun->type = typeFun;
 
     script->analysis->setFunction(this, fun);
 #endif
 }
 
-inline js::types::TypeFunction *
-JSContext::getTypeFunctionHandler(const char *name, JSTypeHandler handler,
-                                  js::types::TypeObject *prototype)
-{
-#ifdef JS_TYPE_INFERENCE
-    if (!prototype)
-        prototype = getFixedTypeObject(js::types::TYPE_OBJECT_FUNCTION_PROTOTYPE);
-    js::types::TypeFunction *typeFun =
-        compartment->types.getTypeObject(this, NULL, name, true, prototype)->asFunction();
-
-    if (typeFun->handler) {
-        /* Saw this function before, make sure it has the same behavior. */
-        JS_ASSERT(typeFun->handler == handler);
-        return typeFun;
-    }
-
-    typeFun->handler = handler;
-    return typeFun;
-#else
-    return NULL;
-#endif
-}
-
 inline js::types::TypeObject *
 JSContext::getTypeCallerInitObject(bool isArray)
 {
-#ifdef JS_TYPE_INFERENCE
     JSStackFrame *caller = js_GetScriptedCaller(this, NULL);
     return caller->script()->getTypeInitObject(this, caller->pc(this), isArray);
-#else
-    return NULL;
-#endif
 }
 
 inline bool
 JSContext::isTypeCallerMonitored()
 {
 #ifdef JS_TYPE_INFERENCE
     JSStackFrame *caller = js_GetScriptedCaller(this, NULL);
     js::analyze::Script *analysis = caller->script()->analysis;
@@ -275,48 +215,23 @@ JSContext::markTypeCallerUnexpected(cons
 
 inline void
 JSContext::markTypeCallerOverflow()
 {
     markTypeCallerUnexpected(js::types::TYPE_DOUBLE);
 }
 
 inline void
-JSContext::markTypeBuiltinFunction(js::types::TypeObject *fun)
-{
-#ifdef JS_TYPE_INFERENCE
-    JS_ASSERT(fun->isFunction);
-    fun->asFunction()->isBuiltin = true;
-#endif
-}
-
-inline void
-JSContext::setTypeFunctionPrototype(js::types::TypeObject *fun, js::types::TypeObject *proto)
-{
-#ifdef JS_TYPE_INFERENCE
-    js::types::TypeFunction *nfun = fun->asFunction();
-    JS_ASSERT(nfun->isBuiltin);
-
-    if (nfun->prototypeObject) {
-        JS_ASSERT(nfun->prototypeObject == proto);
-        return;
-    }
-
-    nfun->prototypeObject = proto;
-    addTypePropertyId(fun, ATOM_TO_JSID(runtime->atomState.classPrototypeAtom), (js::types::jstype) proto);
-#endif
-}
-
-inline void
 JSContext::addTypeProperty(js::types::TypeObject *obj, const char *name, js::types::jstype type)
 {
 #ifdef JS_TYPE_INFERENCE
+    /* :FIXME: bug 613221 don't pin atom. */
     jsid id = JSID_VOID;
     if (name)
-        id = ATOM_TO_JSID(js_Atomize(this, name, strlen(name), 0));
+        id = ATOM_TO_JSID(js_Atomize(this, name, strlen(name), ATOM_PINNED));
     addTypePropertyId(obj, id, type);
 #endif
 }
 
 inline void
 JSContext::addTypeProperty(js::types::TypeObject *obj, const char *name, const js::Value &value)
 {
 #ifdef JS_TYPE_INFERENCE
@@ -324,49 +239,56 @@ JSContext::addTypeProperty(js::types::Ty
 #endif
 }
 
 inline void
 JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jstype type)
 {
 #ifdef JS_TYPE_INFERENCE
     /* Convert string index properties into the common index property. */
-    id = js::types::MakeTypeId(id);
+    id = js::types::MakeTypeId(this, id);
 
     js::types::TypeSet *types = obj->getProperty(this, id, true);
 
     if (types->hasType(type))
         return;
 
     if (compartment->types.interpreting) {
         js::types::InferSpew(js::types::ISpewDynamic, "AddBuiltin: %s %s: %s",
-                             js::types::TypeIdString(obj->name),
-                             js::types::TypeIdString(id),
+                             obj->name(), js::types::TypeIdString(id),
                              js::types::TypeString(type));
         compartment->types.addDynamicType(this, types, type);
     } else {
         types->addType(this, type);
     }
 #endif
 }
 
 inline void
 JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value)
 {
 #ifdef JS_TYPE_INFERENCE
     addTypePropertyId(obj, id, js::types::GetValueType(this, value));
 #endif
 }
 
+inline js::types::TypeObject *
+JSContext::getTypeGetSet()
+{
+    if (!compartment->types.typeGetSet)
+        compartment->types.typeGetSet = newTypeObject("GetSet", NULL);
+    return compartment->types.typeGetSet;
+}
+
 inline void
 JSContext::aliasTypeProperties(js::types::TypeObject *obj, jsid first, jsid second)
 {
 #ifdef JS_TYPE_INFERENCE
-    first = js::types::MakeTypeId(first);
-    second = js::types::MakeTypeId(second);
+    first = js::types::MakeTypeId(this, first);
+    second = js::types::MakeTypeId(this, second);
 
     js::types::TypeSet *firstTypes = obj->getProperty(this, first, true);
     js::types::TypeSet *secondTypes = obj->getProperty(this, second, true);
 
     firstTypes->addSubset(this, *obj->pool, secondTypes);
     secondTypes->addSubset(this, *obj->pool, firstTypes);
 #endif
 }
@@ -381,18 +303,17 @@ JSContext::markTypeArrayNotPacked(js::ty
         obj->isDenseArray = false;
     } else if (!obj->isPackedArray) {
         return;
     }
     obj->isPackedArray = false;
 
     if (dynamic) {
         js::types::InferSpew(js::types::ISpewDynamic, "%s: %s",
-                             notDense ? "NonDenseArray" : "NonPackedArray",
-                             js::types::TypeIdString(obj->name));
+                             notDense ? "NonDenseArray" : "NonPackedArray", obj->name());
     }
 
     /* All constraints listening to changes in packed/dense status are on the element types. */
     js::types::TypeSet *elementTypes = obj->getProperty(this, JSID_VOID, false);
     js::types::TypeConstraint *constraint = elementTypes->constraintList;
     while (constraint) {
         constraint->arrayNotPacked(this, notDense);
         constraint = constraint->next;
@@ -417,17 +338,17 @@ inline void
 JSContext::typeMonitorCall(JSScript *caller, const jsbytecode *callerpc,
                            const js::CallArgs &args, bool constructing, bool force)
 {
     JS_ASSERT_IF(caller == NULL, force);
 #ifdef JS_TYPE_INFERENCE
     if (!args.callee().isObject() || !args.callee().toObject().isFunction())
         return;
     JSObject *callee = &args.callee().toObject();
-    js::types::TypeFunction *fun = callee->getTypeObject()->asFunction();
+    js::types::TypeFunction *fun = callee->getType()->asFunction();
 
     /*
      * Don't do anything on calls to native functions.  If the call is monitored
      * then the return value is unknown, and when cx->isTypeCallerMonitored() natives
      * should inform inference of any side effects not on the return value.
      */
     if (!fun->script)
         return;
@@ -441,34 +362,28 @@ JSContext::typeMonitorCall(JSScript *cal
     typeMonitorEntry(fun->script);
 
     /* Don't need to do anything if this is at a non-monitored callsite. */
     if (!force)
         return;
 
     js::types::jstype type;
     if (constructing) {
-        js::Value protov;
-        if (!callee->getProperty(this, ATOM_TO_JSID(runtime->atomState.classPrototypeAtom),
-                                 &protov)) {
-            JS_NOT_REACHED("FIXME");
-            return;
-        }
-        JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL;
-        js::types::TypeObject *protoType = proto
-            ? proto->getTypeObject()
-            : getFixedTypeObject(js::types::TYPE_OBJECT_OBJECT_PROTOTYPE);
-        type = (js::types::jstype) protoType->getNewObject(this);
+        /* Don't duplicate the logic in js_CreateThis, just mark 'this' as unknown. */
+        type = js::types::TYPE_UNKNOWN;
     } else {
         type = js::types::GetValueType(this, args.thisv());
     }
-    if (!script->thisTypes.hasType(type)) {
-        js::types::InferSpew(js::types::ISpewDynamic, "AddThis: #%u: %s",
-                             script->id, js::types::TypeString(type));
-        compartment->types.addDynamicType(this, &script->thisTypes, type);
+
+    if (!constructing) {
+        if (!script->thisTypes.hasType(type)) {
+            js::types::InferSpew(js::types::ISpewDynamic, "AddThis: #%u: %s",
+                                 script->id, js::types::TypeString(type));
+            compartment->types.addDynamicType(this, &script->thisTypes, type);
+        }
     }
 
     unsigned arg = 0;
     for (; arg < args.argc(); arg++) {
         js::types::jstype type = js::types::GetValueType(this, args[arg]);
 
         jsid id = script->getArgumentId(arg);
         if (!JSID_IS_VOID(id)) {
@@ -557,24 +472,21 @@ JSScript::setTypeNesting(JSScript *paren
     analysis->parentpc = pc;
 #endif
 }
 
 inline js::types::TypeObject *
 JSScript::getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray)
 {
 #ifdef JS_TYPE_INFERENCE
-    if (analysis->failed()) {
-        return cx->getFixedTypeObject(isArray
-                                      ? js::types::TYPE_OBJECT_UNKNOWN_ARRAY
-                                      : js::types::TYPE_OBJECT_UNKNOWN_OBJECT);
-    }
+    /* :FIXME: */
+    JS_ASSERT(!analysis->failed());
     return analysis->getCode(pc).getInitObject(cx, isArray);
 #else
-    return NULL;
+    return cx->getTypeNewObject(isArray ? JSProto_Array : JSProto_Object);
 #endif
 }
 
 inline void
 JSScript::typeMonitorResult(JSContext *cx, const jsbytecode *pc, unsigned index,
                             js::types::jstype type)
 {
 #ifdef JS_TYPE_INFERENCE
@@ -618,17 +530,17 @@ JSScript::typeMonitorAssign(JSContext *c
 {
 #ifdef JS_TYPE_INFERENCE
     if (!analysis->failed()) {
         js::analyze::Bytecode &code = analysis->getCode(pc);
         if (!code.monitorNeeded)
             return;
     }
 
-    if (!obj->getTypeObject()->unknownProperties)
+    if (!obj->getType()->unknownProperties || obj->isCall() || obj->isBlock() || obj->isWith())
         cx->compartment->types.dynamicAssign(cx, obj, id, rval);
 #endif
 }
 
 inline void
 JSScript::typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value)
 {
 #ifdef JS_TYPE_INFERENCE
@@ -642,44 +554,16 @@ JSScript::typeSetArgument(JSContext *cx,
                                  js::types::TypeString(type));
             cx->compartment->types.addDynamicType(cx, argTypes, type);
         }
     }
 #endif
 }
 
 /////////////////////////////////////////////////////////////////////
-// JSObject
-/////////////////////////////////////////////////////////////////////
-
-inline js::types::TypeObject *
-JSObject::getTypePrototypeNewObject(JSContext *cx)
-{
-#ifdef JS_TYPE_INFERENCE
-    if (typeObject->newObject)
-        return typeObject->newObject;
-    return typeObject->getNewObject(cx);
-#else
-    return NULL;
-#endif
-}
-
-inline js::types::TypeObject *
-JSObject::getTypePrototype(JSContext *cx)
-{
-#ifdef JS_TYPE_INFERENCE
-    if (!typeObject->asFunction()->prototypeObject)
-        typeObject->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), false);
-    return typeObject->asFunction()->prototypeObject;
-#else
-    return NULL;
-#endif
-}
-
-/////////////////////////////////////////////////////////////////////
 // analyze::Bytecode
 /////////////////////////////////////////////////////////////////////
 
 #ifdef JS_TYPE_INFERENCE
 
 namespace js {
 namespace analyze {
 
@@ -711,32 +595,29 @@ inline void
 Bytecode::setFixed(JSContext *cx, unsigned num, types::jstype type)
 {
     pushed(num)->addType(cx, type);
 }
 
 inline types::TypeObject *
 Bytecode::getInitObject(JSContext *cx, bool isArray)
 {
-    if (isArray) {
-        if (!initArray) {
-            char name[32];
-            JS_snprintf(name, 32, "#%u:%u:Array", script->id, offset);
-            types::TypeObject *proto = cx->getFixedTypeObject(types::TYPE_OBJECT_ARRAY_PROTOTYPE);
-            initArray = cx->compartment->types.getTypeObject(cx, script, name, false, proto);
-        }
-        return initArray;
+    types::TypeObject *&object = isArray ? initArray : initObject;
+    if (!object) {
+        char *name = NULL;
+#ifdef DEBUG
+        name = (char *) alloca(32);
+        JS_snprintf(name, 32, "#%u:%u:%s", script->id, offset, isArray ? "Array" : "Object");
+#endif
+        JSObject *proto;
+        if (!js_GetClassPrototype(cx, NULL, isArray ? JSProto_Array : JSProto_Object, &proto, NULL))
+            return NULL;
+        object = cx->compartment->types.newTypeObject(cx, script, name, false, proto);
     }
-    if (!initObject) {
-        char name[32];
-        JS_snprintf(name, 32, "#%u:%u:Object", script->id, offset);
-        types::TypeObject *proto = cx->getFixedTypeObject(types::TYPE_OBJECT_OBJECT_PROTOTYPE);
-        initObject = cx->compartment->types.getTypeObject(cx, script, name, false, proto);
-    }
-    return initObject;
+    return object;
 }
 
 /////////////////////////////////////////////////////////////////////
 // analyze::Script
 /////////////////////////////////////////////////////////////////////
 
 inline jsid
 Script::getLocalId(unsigned index, Bytecode *code)
@@ -1200,39 +1081,26 @@ TypeCallsite::pool()
 
 /////////////////////////////////////////////////////////////////////
 // TypeObject
 /////////////////////////////////////////////////////////////////////
 
 inline TypeSet *
 TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
 {
-    JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_STRING(id));
+    JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
     JS_ASSERT_IF(JSID_IS_STRING(id), JSID_TO_STRING(id) != NULL);
 
     Property *&prop = HashSetInsert<jsid,Property,Property>(cx, propertySet, propertyCount, id);
     if (!prop)
         addProperty(cx, id, prop);
 
     return assign ? &prop->ownTypes : &prop->types;
 }
 
-inline bool
-TypeObject::isArray(JSContext *cx)
-{
-    TypeObject *array = cx->getFixedTypeObject(TYPE_OBJECT_ARRAY_PROTOTYPE);
-    TypeObject *obj = prototype;
-    while (obj) {
-        if (obj == array)
-            return true;
-        obj = obj->prototype;
-    }
-    return false;
-}
-
 } /* namespace types */
 
 inline types::TypeSet *
 analyze::Script::getVariable(JSContext *cx, jsid id)
 {
     JS_ASSERT(JSID_IS_STRING(id) && JSID_TO_STRING(id) != NULL);
 
     types::Variable *&var = types::HashSetInsert<jsid,types::Variable,types::Variable>
@@ -1242,9 +1110,60 @@ analyze::Script::getVariable(JSContext *
 
     return &var->types;
 }
 
 } /* namespace js */
 
 #endif /* JS_TYPE_INFERENCE */
 
+namespace js {
+namespace types {
+
+inline const char *
+TypeObject::name()
+{
+#ifdef DEBUG
+    return TypeIdString(name_);
+#else
+    return NULL;
+#endif
+}
+
+inline TypeObject::TypeObject(JSArenaPool *pool, jsid name, JSObject *proto)
+    : proto(proto), emptyShapes(NULL), isFunction(false), marked(false),
+      propertySet(NULL), propertyCount(0),
+      instanceList(NULL), instanceNext(NULL), pool(pool), next(NULL), unknownProperties(false),
+      isDenseArray(false), isPackedArray(false), possiblePackedArray(false)
+{
+#ifdef DEBUG
+    this->name_ = name;
+#endif
+
+#ifdef JS_TYPE_INFERENCE
+    InferSpew(ISpewOps, "newObject: %s", this->name());
+#endif
+
+    if (proto) {
+        TypeObject *prototype = proto->getType();
+        if (prototype->unknownProperties)
+            unknownProperties = true;
+        else if (proto->isArray())
+            isDenseArray = isPackedArray = true;
+        instanceNext = prototype->instanceList;
+        prototype->instanceList = this;
+    }
+}
+
+inline TypeFunction::TypeFunction(JSArenaPool *pool, jsid name, JSObject *proto)
+    : TypeObject(pool, name, proto), handler(NULL), script(NULL),
+      returnTypes(pool), isGeneric(false)
+{
+    isFunction = true;
+
+#ifdef JS_TYPE_INFERENCE
+    InferSpew(ISpewOps, "newFunction: %s return T%u", this->name(), returnTypes.id());
+#endif
+}
+
+} } /* namespace js::types */
+
 #endif // jsinferinlines_h___
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -579,29 +579,28 @@ js_OnUnknownMethod(JSContext *cx, Value 
         if (vp[0].isObject()) {
             obj = &vp[0].toObject();
             if (!js_IsFunctionQName(cx, obj, &id))
                 return false;
             if (!JSID_IS_VOID(id))
                 vp[0] = IdToValue(id);
         }
 #endif
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_NOSUCHMETHOD);
         obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
         if (!obj)
             return false;
 
         /*
          * Null map to cause prompt and safe crash if this object were to
          * escape due to a bug. This will make the object appear to be a
          * stillborn instance that needs no finalization, which is sound:
          * NoSuchMethod helper objects own no manually allocated resources.
          */
         obj->map = NULL;
-        obj->init(cx, &js_NoSuchMethodClass, NULL, NULL, type, NULL, false);
+        obj->init(cx, &js_NoSuchMethodClass, cx->emptyTypeObject(), NULL, NULL, false);
         obj->setSlot(JSSLOT_FOUND_FUNCTION, tvr.value());
         obj->setSlot(JSSLOT_SAVED_ID, vp[0]);
         vp[0].setObject(*obj);
 
         cx->fp()->script()->typeMonitorResult(cx, cx->regs->pc, 0, *vp);
     }
     return true;
 }
@@ -613,22 +612,20 @@ NoSuchMethod(JSContext *cx, uintN argc, 
     if (!cx->stack().pushInvokeArgs(cx, 2, &args))
         return JS_FALSE;
 
     JS_ASSERT(vp[0].isObject());
     JS_ASSERT(vp[1].isObject());
     JSObject *obj = &vp[0].toObject();
     JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass);
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_NOSUCHMETHOD_ARGUMENTS);
-
     args.callee() = obj->getSlot(JSSLOT_FOUND_FUNCTION);
     args.thisv() = vp[1];
     args[0] = obj->getSlot(JSSLOT_SAVED_ID);
-    JSObject *argsobj = js_NewArrayObject(cx, argc, vp + 2, type);
+    JSObject *argsobj = js_NewArrayObject(cx, argc, vp + 2);
     if (!argsobj)
         return JS_FALSE;
     args[1].setObject(*argsobj);
     JSBool ok = (flags & JSINVOKE_CONSTRUCT)
                 ? InvokeConstructor(cx, args)
                 : Invoke(cx, args, flags);
     vp[0] = args.rval();
     return ok;
@@ -4007,17 +4004,17 @@ do_incop:
         ref.setInt32(tmp);
     } else {
         /* We need an extra root for the result. */
         PUSH_NULL();
         if (!js_DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
             goto error;
         if (!regs.sp[-1].isInt32()) {
             script->typeMonitorOverflow(cx, regs.pc, 0);
-            cx->addTypePropertyId(obj->getTypeObject(), id, TYPE_DOUBLE);
+            cx->addTypePropertyId(obj->getType(), id, TYPE_DOUBLE);
         }
         regs.fp->setAssigning();
         JSBool ok = obj->setProperty(cx, id, &regs.sp[-1], script->strictModeCode);
         script->typeMonitorAssign(cx, regs.pc, obj, id, regs.sp[-1]);
         regs.fp->clearAssigning();
         if (!ok)
             goto error;
         regs.sp--;
@@ -4575,17 +4572,17 @@ BEGIN_CASE(JSOP_GETELEM)
     copyFrom = &rval;
 
   end_getelem:
     regs.sp--;
     regs.sp[-1] = *copyFrom;
     assertSameCompartment(cx, regs.sp[-1]);
     if (copyFrom->isUndefined() || !rref.isInt32()) {
         if (rref.isInt32())
-            cx->addTypeProperty(obj->getTypeObject(), NULL, TYPE_UNDEFINED);
+            cx->addTypeProperty(obj->getType(), NULL, TYPE_UNDEFINED);
         script->typeMonitorResult(cx, regs.pc, 0, *copyFrom);
     }
 }
 END_CASE(JSOP_GETELEM)
 
 BEGIN_CASE(JSOP_CALLELEM)
 {
     /* Find the object on which to look for |this|'s properties. */
@@ -5963,43 +5960,51 @@ BEGIN_CASE(JSOP_HOLE)
 END_CASE(JSOP_HOLE)
 
 BEGIN_CASE(JSOP_NEWINIT)
 {
     jsint i = regs.pc[1];
 
     JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
     JSObject *obj;
-    TypeObject *type = script->getTypeInitObject(cx, regs.pc, i == JSProto_Array);
 
     if (i == JSProto_Array) {
-        obj = js_NewArrayObject(cx, 0, NULL, type);
+        obj = js_NewArrayObject(cx, 0, NULL);
     } else {
         gc::FinalizeKind kind = GuessObjectGCKind(0, false);
-        obj = NewBuiltinClassInstance(cx, &js_ObjectClass, type, kind);
+        obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
     }
 
     if (!obj)
         goto error;
 
+    TypeObject *type = script->getTypeInitObject(cx, regs.pc, i == JSProto_Array);
+    if (!type)
+        goto error;
+    obj->setType(type);
+
     PUSH_OBJECT(*obj);
     CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWINIT)
 
 BEGIN_CASE(JSOP_NEWARRAY)
 {
     unsigned count = GET_UINT24(regs.pc);
-    TypeObject *type = script->getTypeInitObject(cx, regs.pc, true);
-    JSObject *obj = js_NewArrayObject(cx, count, NULL, type);
+    JSObject *obj = js_NewArrayObject(cx, count, NULL);
 
     /* Avoid ensureDenseArrayElements to skip sparse array checks there. */
     if (!obj || !obj->ensureSlots(cx, count))
         goto error;
 
+    TypeObject *type = script->getTypeInitObject(cx, regs.pc, true);
+    if (!type)
+        goto error;
+    obj->setType(type);
+
     PUSH_OBJECT(*obj);
     CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWARRAY)
 
 BEGIN_CASE(JSOP_NEWOBJECT)
 {
     JSObject *baseobj;
@@ -6149,18 +6154,17 @@ BEGIN_CASE(JSOP_DEFSHARP)
     uint32 slot = GET_UINT16(regs.pc);
     JS_ASSERT(slot + 1 < regs.fp->numFixed());
     const Value &lref = regs.fp->slots()[slot];
     JSObject *obj;
     if (lref.isObject()) {
         obj = &lref.toObject();
     } else {
         JS_ASSERT(lref.isUndefined());
-        TypeObject *objType = cx->getFixedTypeObject(TYPE_OBJECT_SHARP_ARRAY);
-        obj = js_NewArrayObject(cx, 0, NULL, objType);
+        obj = js_NewArrayObject(cx, 0, NULL);
         if (!obj)
             goto error;
         regs.fp->slots()[slot].setObject(*obj);
     }
     jsint i = (jsint) GET_UINT16(regs.pc + UINT16_LEN);
     jsid id = INT_TO_JSID(i);
     const Value &rref = regs.sp[-1];
     if (rref.isPrimitive()) {
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -163,18 +163,17 @@ struct IdHashPolicy {
 typedef HashSet<jsid, IdHashPolicy, ContextAllocPolicy> IdSet;
 
 static inline bool
 NewKeyValuePair(JSContext *cx, jsid id, const Value &val, Value *rval)
 {
     Value vec[2] = { IdToValue(id), val };
     AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec);
 
-    TypeObject *aobjType = cx->getFixedTypeObject(TYPE_OBJECT_KEY_VALUE_PAIR);
-    JSObject *aobj = js_NewArrayObject(cx, 2, vec, aobjType);
+    JSObject *aobj = js_NewArrayObject(cx, 2, vec);
     if (!aobj)
         return false;
     rval->setObject(*aobj);
     return true;
 }
 
 struct KeyEnumeration
 {
@@ -431,18 +430,17 @@ GetCustomIterator(JSContext *cx, JSObjec
     /*
      * Notify type inference of the custom iterator.  This only needs to be done
      * if this is coming from a 'for in' loop, not a call to Iterator itself.
      * If an Iterator object is used in a for loop then the values fetched in
      * that loop are unknown, whether there is a custom __iterator__ or not.
      */
     if (!(flags & JSITER_OWNONLY)) {
         JS_ASSERT(JSOp(*cx->regs->pc) == JSOP_ITER);
-        cx->fp()->script()->typeMonitorResult(cx, cx->regs->pc, 0,
-            (jstype) cx->getFixedTypeObject(TYPE_OBJECT_NEW_ITERATOR));
+        cx->fp()->script()->typeMonitorResult(cx, cx->regs->pc, 0, (jstype) cx->getTypeGetSet());
     }
     return true;
 }
 
 template <typename T>
 static inline bool
 Compare(T *a, T *b, size_t c)
 {
@@ -459,36 +457,34 @@ Compare(T *a, T *b, size_t c)
               } while (--n > 0);
     }
     return true;
 }
 
 static inline JSObject *
 NewIteratorObject(JSContext *cx, uintN flags)
 {
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_NEW_ITERATOR);
-
     if (flags & JSITER_ENUMERATE) {
         /*
          * Non-escaping native enumerator objects do not need map, proto, or
          * parent. However, code in jstracer.cpp and elsewhere may find such a
          * native enumerator object via the stack and (as for all objects that
          * are not stillborn, with the exception of "NoSuchMethod" internal
          * helper objects) expect it to have a non-null map pointer, so we
          * share an empty Enumerator scope in the runtime.
          */
         JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT0);
         if (!obj)
             return false;
-        obj->init(cx, &js_IteratorClass, NULL, NULL, type, NULL, false);
+        obj->init(cx, &js_IteratorClass, cx->emptyTypeObject(), NULL, NULL, false);
         obj->setMap(cx->runtime->emptyEnumeratorShape);
         return obj;
     }
 
-    return NewBuiltinClassInstance(cx, &js_IteratorClass, type);
+    return NewBuiltinClassInstance(cx, &js_IteratorClass);
 }
 
 NativeIterator *
 NativeIterator::allocateKeyIterator(JSContext *cx, uint32 slength, const AutoIdVector &props)
 {
     size_t plength = props.length();
     NativeIterator *ni = (NativeIterator *)
         cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsid) + slength * sizeof(uint32));
@@ -1199,18 +1195,17 @@ RebaseRegsFromTo(JSFrameRegs *regs, JSSt
  * JSGenerator object, which contains its own JSStackFrame that we populate
  * from *fp.  We know that upon return, the JSOP_GENERATOR opcode will return
  * from the activation in fp, so we can steal away fp->callobj and fp->argsobj
  * if they are non-null.
  */
 JS_REQUIRES_STACK JSObject *
 js_NewGenerator(JSContext *cx)
 {
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_NEW_GENERATOR);
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_GeneratorClass, type);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_GeneratorClass);
     if (!obj)
         return NULL;
 
     JSStackFrame *stackfp = cx->fp();
     JS_ASSERT(stackfp->base() == cx->regs->sp);
     JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs());
 
     /* Load and compute stack slot counts. */
@@ -1502,39 +1497,28 @@ static JSFunctionSpec generator_methods[
     JS_FN_TYPE(js_send_str,      generator_send,     1,JSPROP_ROPERM, JS_TypeHandlerDynamic),
     JS_FN_TYPE(js_throw_str,     generator_throw,    1,JSPROP_ROPERM, JS_TypeHandlerDynamic),
     JS_FN_TYPE(js_close_str,     generator_close,    0,JSPROP_ROPERM, JS_TypeHandlerVoid),
     JS_FS_END
 };
 
 #endif /* JS_HAS_GENERATORS */
 
-static void type_GeneratorNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
-{
-#ifdef JS_TYPE_INFERENCE
-    TypeCallsite *site = Valueify(jssite);
-
-    TypeObject *generator = cx->getFixedTypeObject(TYPE_OBJECT_NEW_ITERATOR);
-    if (site->returnTypes)
-        site->returnTypes->addType(cx, (types::jstype) generator);
-#endif
-}
-
 JSObject *
 js_InitIteratorClasses(JSContext *cx, JSObject *obj)
 {
     JSObject *proto, *stop;
 
     /* Idempotency required: we initialize several things, possibly lazily. */
     if (!js_GetClassObject(cx, obj, JSProto_StopIteration, &stop))
         return NULL;
     if (stop)
         return stop;
 
-    proto = js_InitClass(cx, obj, NULL, &js_IteratorClass, Iterator, 2, type_GeneratorNew,
+    proto = js_InitClass(cx, obj, NULL, &js_IteratorClass, Iterator, 2, JS_TypeHandlerNew,
                          NULL, iterator_methods, NULL, NULL);
     if (!proto)
         return NULL;
 
 #if JS_HAS_GENERATORS
     /* Initialize the generator internals if configured. */
     if (!js_InitClass(cx, obj, NULL, &js_GeneratorClass, NULL, 0, NULL,
                       NULL, generator_methods, NULL, NULL)) {
@@ -1542,12 +1526,12 @@ js_InitIteratorClasses(JSContext *cx, JS
     }
 #endif
 
     proto = js_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0, NULL,
                          NULL, NULL, NULL, NULL);
     if (!proto)
         return NULL;
 
-    cx->addTypeProperty(obj->getTypeObject(), js_StopIteration_str, ObjectValue(*proto));
+    cx->addTypeProperty(obj->getType(), js_StopIteration_str, ObjectValue(*proto));
 
     return proto;
 }
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -898,20 +898,25 @@ js_IsMathFunction(JSNative native)
             return true;
     }
     return false;
 }
 
 JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj)
 {
-    types::TypeObject *type = cx->getTypeObject(js_Math_str, NULL);
-    JSObject *Math = NewNonFunction<WithProto::Class>(cx, &js_MathClass, NULL, obj, type);
+    JSObject *Math = NewNonFunction<WithProto::Class>(cx, &js_MathClass, NULL, obj);
     if (!Math)
         return NULL;
+
+    types::TypeObject *type = cx->newTypeObject(js_Math_str, Math->getProto());
+    if (!type)
+        return NULL;
+    Math->setType(type);
+
     if (!JS_DefinePropertyWithType(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
                                    JS_PropertyStub, JS_PropertyStub, 0)) {
         return NULL;
     }
 
     if (!JS_DefineFunctionsWithPrefix(cx, Math, math_static_methods, js_Math_str))
         return NULL;
     if (!JS_DefineConstDoubles(cx, Math, math_constants))
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -543,18 +543,17 @@ Number(JSContext *cx, uintN argc, Value 
         vp[0] = vp[2];
     } else {
         vp[0].setInt32(0);
     }
 
     if (!isConstructing)
         return true;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_NEW_NUMBER);
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_NumberClass, type);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_NumberClass);
     if (!obj)
         return false;
     obj->setPrimitiveThis(vp[0]);
     vp->setObject(*obj);
     return true;
 }
 
 #if JS_HAS_TOSOURCE
@@ -1040,25 +1039,20 @@ js_FinishRuntimeNumberState(JSContext *c
     cx->free((void *) rt->thousandsSeparator);
     cx->free((void *) rt->decimalSeparator);
     cx->free((void *) rt->numGrouping);
     rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = NULL;
 }
 
 static void type_NewNumber(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
-#ifdef JS_TYPE_INFERENCE
-    TypeCallsite *site = Valueify(jssite);
-    if (site->isNew) {
-        TypeObject *object = cx->getFixedTypeObject(TYPE_OBJECT_NEW_NUMBER);
-        site->returnTypes->addType(cx, (jstype) object);
-    } else {
+    if (Valueify(jssite)->isNew)
+        JS_TypeHandlerNew(cx, jsfun, jssite);
+    else
         JS_TypeHandlerFloat(cx, jsfun, jssite);
-    }
-#endif
 }
 
 JSObject *
 js_InitNumberClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto, *ctor;
     JSRuntime *rt;
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1557,18 +1557,20 @@ js_obj_defineGetter(JSContext *cx, uintN
      * Getters and setters are just like watchpoints from an access
      * control point of view.
      */
     Value junk;
     uintN attrs;
     if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs))
         return JS_FALSE;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_GETSET);
-    cx->addTypePropertyId(obj->getTypeObject(), id, (jstype) type);
+    TypeObject *type = cx->getTypeGetSet();
+    if (!type)
+        return JS_FALSE;
+    cx->addTypePropertyId(obj->getType(), id, (jstype) type);
 
     vp->setUndefined();
     return obj->defineProperty(cx, id, UndefinedValue(), getter, PropertyStub,
                                JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED);
 }
 
 JS_FRIEND_API(JSBool)
 js_obj_defineSetter(JSContext *cx, uintN argc, Value *vp)
@@ -1591,18 +1593,20 @@ js_obj_defineSetter(JSContext *cx, uintN
      * Getters and setters are just like watchpoints from an access
      * control point of view.
      */
     Value junk;
     uintN attrs;
     if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs))
         return JS_FALSE;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_GETSET);
-    cx->addTypePropertyId(obj->getTypeObject(), id, (jstype) type);
+    TypeObject *type = cx->getTypeGetSet();
+    if (!type)
+        return JS_FALSE;
+    cx->addTypePropertyId(obj->getType(), id, (jstype) type);
 
     vp->setUndefined();
     return obj->defineProperty(cx, id, UndefinedValue(), PropertyStub, setter,
                                JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED);
 }
 
 static JSBool
 obj_lookupGetter(JSContext *cx, uintN argc, Value *vp)
@@ -1674,18 +1678,17 @@ obj_getPrototypeOf(JSContext *cx, uintN 
 }
 
 extern JSBool
 js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs,
                                const Value &getter, const Value &setter,
                                const Value &value, Value *vp)
 {
     /* We have our own property, so start creating the descriptor. */
-    TypeObject *descType = cx->getFixedTypeObject(TYPE_OBJECT_PROPERTY_DESCRIPTOR);
-    JSObject *desc = NewBuiltinClassInstance(cx, &js_ObjectClass, descType);
+    JSObject *desc = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!desc)
         return false;
     vp->setObject(*desc);    /* Root and return. */
 
     const JSAtomState &atomState = cx->runtime->atomState;
     if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
         if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.getAtom), getter,
                                   PropertyStub, PropertyStub, JSPROP_ENUMERATE) ||
@@ -1815,21 +1818,18 @@ obj_keys(JSContext *cx, uintN argc, Valu
             if (!str)
                 return false;
             JS_ALWAYS_TRUE(vals.append(StringValue(str)));
         } else {
             JS_ASSERT(JSID_IS_OBJECT(id));
         }
     }
 
-    TypeObject *aobjType = cx->getFixedTypeObject(TYPE_OBJECT_PROPERTY_ARRAY);
-    cx->addTypeProperty(aobjType, NULL, TYPE_STRING);
-
     JS_ASSERT(props.length() <= UINT32_MAX);
-    JSObject *aobj = js_NewArrayObject(cx, jsuint(vals.length()), vals.begin(), aobjType);
+    JSObject *aobj = js_NewArrayObject(cx, jsuint(vals.length()), vals.begin());
     if (!aobj)
         return false;
     vp->setObject(*aobj);
 
     return true;
 }
 
 static bool
@@ -2327,17 +2327,17 @@ DefinePropertyOnArray(JSContext *cx, JSO
 }
 
 static JSBool
 DefineProperty(JSContext *cx, JSObject *obj, const PropDesc &desc, bool throwError,
                bool *rval)
 {
     /* Add this to the type information for the object.
      * TODO: handle getters and setters. */
-    cx->addTypePropertyId(obj->getTypeObject(), desc.id, desc.value);
+    cx->addTypePropertyId(obj->getType(), desc.id, desc.value);
 
     if (obj->isArray())
         return DefinePropertyOnArray(cx, obj, desc, throwError, rval);
 
     if (obj->getOps()->lookupProperty) {
         if (obj->isProxy())
             return JSProxy::defineProperty(cx, obj, desc.id, desc.pd);
         return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
@@ -2463,25 +2463,22 @@ obj_create(JSContext *cx, uintN argc, Va
         if (!bytes)
             return JS_FALSE;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                              bytes, "not an object or null");
         JS_free(cx, bytes);
         return JS_FALSE;
     }
 
-    TypeObject *type = cx->getTypeCallerInitObject(false);
-    cx->markTypeObjectUnknownProperties(type);
-
     /*
      * Use the callee's global as the parent of the new object to avoid dynamic
      * scoping (i.e., using the caller's global).
      */
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, &js_ObjectClass, v.toObjectOrNull(),
-                                                     vp->toObject().getGlobal(), type);
+                                                        vp->toObject().getGlobal());
     if (!obj)
         return JS_FALSE;
     vp->setObject(*obj); /* Root and prepare for eventual return. */
 
     /* 15.2.3.5 step 4. */
     if (argc > 1 && !vp[3].isUndefined()) {
         if (vp[3].isPrimitive()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
@@ -2539,20 +2536,17 @@ obj_getOwnPropertyNames(JSContext *cx, u
              vals[i].setString(str);
          } else if (JSID_IS_ATOM(id)) {
              vals[i].setString(JSID_TO_STRING(id));
          } else {
              vals[i].setObject(*JSID_TO_OBJECT(id));
          }
     }
 
-    TypeObject *aobjType = cx->getFixedTypeObject(TYPE_OBJECT_PROPERTY_ARRAY);
-    cx->addTypeProperty(aobjType, NULL, TYPE_STRING);
-
-    JSObject *aobj = js_NewArrayObject(cx, vals.length(), vals.begin(), aobjType);
+    JSObject *aobj = js_NewArrayObject(cx, vals.length(), vals.begin());
     if (!aobj)
         return false;
 
     vp->setObject(*aobj);
     return true;
 }
 
 static JSBool
@@ -2774,21 +2768,22 @@ js_Object(JSContext *cx, uintN argc, Val
     } else {
         /* If argv[0] is null or undefined, obj comes back null. */
         if (!js_ValueToObjectOrNull(cx, vp[2], &obj))
             return JS_FALSE;
     }
     if (!obj) {
         /* Make an object whether this was called with 'new' or not. */
         JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined());
-        TypeObject *type = cx->getTypeCallerInitObject(false);
         gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
-        obj = NewBuiltinClassInstance(cx, &js_ObjectClass, type, kind);
+        obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
             return JS_FALSE;
+        TypeObject *type = cx->getTypeCallerInitObject(false);
+        obj->setType(type);
     }
     vp->setObject(*obj);
     return JS_TRUE;
 }
 
 JSObject*
 js_CreateThis(JSContext *cx, JSObject *callee)
 {
@@ -2802,40 +2797,28 @@ js_CreateThis(JSContext *cx, JSObject *c
     }
 
     Value protov;
     if (!callee->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov))
         return NULL;
 
     JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL;
     JSObject *parent = callee->getParent();
-
-    TypeObject *type = NULL;
-#ifdef JS_TYPE_INFERENCE
-    if (proto) {
-        type = proto->getTypePrototypeNewObject(cx);
-    } else {
-        JS_ASSERT(newclasp == &js_ObjectClass);
-        type = cx->getFixedTypeObject(TYPE_OBJECT_OBJECT_PROTOTYPE)->getNewObject(cx);
-    }
-#endif
-
     gc::FinalizeKind kind = NewObjectGCKind(cx, newclasp);
-    JSObject *obj = NewObject<WithProto::Class>(cx, newclasp, proto, parent, type, kind);
+    JSObject *obj = NewObject<WithProto::Class>(cx, newclasp, proto, parent, kind);
     if (obj)
         obj->syncSpecialEquality();
     return obj;
 }
 
 JSObject *
 js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto)
 {
-    TypeObject *type = proto ? proto->getTypePrototypeNewObject(cx) : NULL;
     gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
-    return NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent(), type, kind);
+    return NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent(), kind);
 }
 
 JSObject *
 js_CreateThisForFunction(JSContext *cx, JSObject *callee)
 {
     Value protov;
     if (!callee->getProperty(cx,
                              ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
@@ -2850,22 +2833,25 @@ js_CreateThisForFunction(JSContext *cx, 
 
 static JS_ALWAYS_INLINE JSObject*
 NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
                         /*gc::FinalizeKind*/ unsigned _kind)
 {
     JS_ASSERT(clasp->isNative());
     gc::FinalizeKind kind = gc::FinalizeKind(_kind);
 
+    TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return NULL;
+
     JSObject* obj = js_NewGCObject(cx, kind);
     if (!obj)
         return NULL;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_UNKNOWN_OBJECT);
-    if (!obj->initSharingEmptyShape(cx, clasp, proto, proto->getParent(), type, NULL, kind))
+    if (!obj->initSharingEmptyShape(cx, clasp, type, proto->getParent(), NULL, kind))
         return NULL;
     return obj;
 }
 
 JSObject* FASTCALL
 js_Object_tn(JSContext* cx, JSObject* proto)
 {
     JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
@@ -2879,17 +2865,19 @@ JS_DEFINE_TRCINFO_1(js_Object,
 JSObject* FASTCALL
 js_InitializerObject(JSContext* cx, JSObject *proto, JSObject *baseobj)
 {
     if (!baseobj) {
         gc::FinalizeKind kind = GuessObjectGCKind(0, false);
         return NewObjectWithClassProto(cx, &js_ObjectClass, proto, kind);
     }
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_UNKNOWN_OBJECT);
+    /* :FIXME: new Objects do not have the right type when created on trace. */
+    TypeObject *type = proto->getNewType(cx);
+
     return CopyInitializerObject(cx, baseobj, type);
 }
 
 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_InitializerObject, CONTEXT, OBJECT, OBJECT,
                      0, nanojit::ACCSET_STORE_ANY)
 
 JSObject* FASTCALL
 js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
@@ -2919,46 +2907,50 @@ js_CreateThisFromTrace(JSContext *cx, Cl
 
     JSObject *parent = ctor->getParent();
     JSObject *proto;
     if (pval.isObject()) {
         /* An object in ctor.prototype, let's use it as the new instance's proto. */
         proto = &pval.toObject();
     } else {
         /* A hole or a primitive: either way, we need to get Object.prototype. */
-        if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
+        JSObject *objProto;
+        if (!js_GetClassPrototype(cx, parent, JSProto_Object, &objProto))
             return NULL;
 
         if (pval.isMagic(JS_GENERIC_MAGIC)) {
             /*
              * No ctor.prototype was set, so we inline-expand and optimize
              * fun_resolve's prototype creation code.
              */
-            TypeObject *typeProto = ctor->getTypePrototype(cx);
-            proto = NewNativeClassInstance(cx, clasp, proto, parent, typeProto);
+            proto = NewNativeClassInstance(cx, clasp, objProto, parent);
             if (!proto)
                 return NULL;
+
+            TypeObject *protoType = cx->newTypeObject(ctor->getType()->name(), "prototype", objProto);
+            if (!protoType)
+                return NULL;
+            proto->setType(protoType);
+
             if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT))
                 return NULL;
         } else {
             /*
              * A primitive value in .prototype means to use Object.prototype
              * for proto. See ES5 13.2.2 step 7.
              */
         }
     }
 
     /*
      * FIXME: 561785 at least. Quasi-natives including XML objects prevent us
      * from easily or unconditionally calling NewNativeClassInstance here.
      */
-    JS_ASSERT(proto);
-    TypeObject *type = proto->getTypePrototypeNewObject(cx);
     gc::FinalizeKind kind = NewObjectGCKind(cx, clasp);
-    return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, type, kind);
+    return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
 }
 
 JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, CLASS, OBJECT, 0,
                      nanojit::ACCSET_STORE_ANY)
 
 #else  /* !JS_TRACER */
 
 # define js_Object_trcinfo NULL
@@ -3170,24 +3162,27 @@ Class js_WithClass = {
     }
 };
 
 JS_REQUIRES_STACK JSObject *
 js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
 {
     JSObject *obj;
 
+    TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return NULL;
+
     obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!obj)
         return NULL;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_WITH);
     JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
 
-    obj->init(cx, &js_WithClass, proto, parent, type, priv, false);
+    obj->init(cx, &js_WithClass, type, parent, priv, false);
     obj->setMap(cx->runtime->emptyWithShape);
     OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
 
     AutoObjectRooter tvr(cx, obj);
     JSObject *thisp = proto->thisObject(cx);
     if (!thisp)
         return NULL;
 
@@ -3203,39 +3198,41 @@ js_NewBlockObject(JSContext *cx)
     /*
      * Null obj's proto slot so that Object.prototype.* does not pollute block
      * scopes and to give the block object its own scope.
      */
     JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!blockObj)
         return NULL;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_BLOCK);
-    blockObj->init(cx, &js_BlockClass, NULL, NULL, type, NULL, false);
+    blockObj->init(cx, &js_BlockClass, cx->emptyTypeObject(), NULL, NULL, false);
     blockObj->setMap(cx->runtime->emptyBlockShape);
     return blockObj;
 }
 
 JSObject *
 js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
 {
     JS_ASSERT(proto->isStaticBlock());
 
     size_t count = OBJ_BLOCK_COUNT(cx, proto);
     gc::FinalizeKind kind = gc::GetGCObjectKind(count + 1);
 
+    TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return NULL;
+
     JSObject *clone = js_NewGCObject(cx, kind);
     if (!clone)
         return NULL;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_BLOCK);
     JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, fp);
 
     /* The caller sets parent on its own. */
-    clone->init(cx, &js_BlockClass, proto, NULL, type, priv, false);
+    clone->init(cx, &js_BlockClass, type, NULL, priv, false);
 
     clone->setMap(proto->map);
     if (!clone->ensureInstanceReservedSlots(cx, count + 1))
         return NULL;
 
     clone->setSlot(JSSLOT_BLOCK_DEPTH, proto->getSlot(JSSLOT_BLOCK_DEPTH));
 
     JS_ASSERT(clone->isClonedBlock());
@@ -3420,20 +3417,21 @@ JSObject::clone(JSContext *cx, JSObject 
                 return NULL;
         } else if (!isProxy()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_CANT_CLONE_OBJECT);
             return NULL;
         }
     }
     JSObject *clone = NewObject<WithProto::Given>(cx, getClass(),
-                                                  proto, parent, getTypeObject(),
+                                                  proto, parent,
                                                   gc::FinalizeKind(finalizeKind()));
     if (!clone)
         return NULL;
+    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)
@@ -3720,16 +3718,19 @@ js_InitObjectClass(JSContext *cx, JSObje
     if (!proto)
         return NULL;
 
     /* ECMA (15.1.2.1) says 'eval' is a property of the global object. */
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.evalAtom);
     if (!js_DefineFunction(cx, obj, id, eval, 1, JSFUN_STUB_GSOPS, JS_TypeHandlerDynamic, js_eval_str))
         return NULL;
 
+    /* The default 'new' object for Object.prototype has unknown properties. */
+    cx->markTypeObjectUnknownProperties(proto->getNewType(cx));
+
     return proto;
 }
 
 static bool
 DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
                    const Value &v, uint32 attrs, bool &named)
 {
     jsid id = ATOM_TO_JSID(atom);
@@ -3769,17 +3770,16 @@ js_InitClass(JSContext *cx, JSObject *ob
              JSTypeHandler ctorHandler,
              JSPropertySpec *ps, JSFunctionSpec *fs,
              JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
 {
     JSAtom *atom;
     JSProtoKey key;
     JSFunction *fun;
     bool named = false;
-    const char *prefix;
 
     atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
     if (!atom)
         return NULL;
 
     /*
      * When initializing a standard class, if no parent_proto (grand-proto of
      * instances of the class, parent-proto of the class's prototype object)
@@ -3796,33 +3796,16 @@ js_InitClass(JSContext *cx, JSObject *ob
      */
     key = JSCLASS_CACHED_PROTO_KEY(clasp);
     if (key != JSProto_Null &&
         !parent_proto &&
         !js_GetClassPrototype(cx, obj, JSProto_Object, &parent_proto)) {
         return NULL;
     }
 
-    /* Create type information for the prototype object. */
-    TypeObject *protoType = NULL;
-#ifdef JS_TYPE_INFERENCE
-    size_t protoLen = strlen(clasp->name) + 15;
-    char *protoName = (char*) alloca(protoLen);
-    JS_snprintf(protoName, protoLen, "%s:prototype", clasp->name);
-    if (clasp == &js_FunctionClass) {
-        TypeObject *protoProto = cx->getFixedTypeObject(TYPE_OBJECT_OBJECT_PROTOTYPE);
-        protoType = cx->getTypeFunctionHandler(protoName, JS_TypeHandlerVoid, protoProto);
-    } else if (clasp == &js_ObjectClass) {
-        protoType = cx->compartment->types.getTypeObject(cx, NULL, protoName, false, NULL);
-    } else {
-        TypeObject *protoProto = cx->getFixedTypeObject(TYPE_OBJECT_OBJECT_PROTOTYPE);
-        protoType = cx->compartment->types.getTypeObject(cx, NULL, protoName, false, protoProto);
-    }
-#endif
-
     /*
      * Create a prototype object for this class.
      *
      * FIXME: lazy standard (built-in) class initialization and even older
      * eager boostrapping code rely on all of these properties:
      *
      * 1. NewObject attempting to compute a default prototype object when
      *    passed null for proto; and
@@ -3834,20 +3817,32 @@ js_InitClass(JSContext *cx, JSObject *ob
      * 3. NewObject allocating a JSFunction-sized GC-thing when clasp is
      *    &js_FunctionClass, not a JSObject-sized (smaller) GC-thing.
      *
      * The JS_NewObjectForGivenProto and JS_NewObject APIs also allow clasp to
      * be &js_FunctionClass (we could break compatibility easily). But fixing
      * (3) is not enough without addressing the bootstrapping dependency on (1)
      * and (2).
      */
-    JSObject *proto = NewObject<WithProto::Class>(cx, clasp, parent_proto, obj, protoType);
+    JSObject *proto = NewObject<WithProto::Class>(cx, clasp, parent_proto, obj);
     if (!proto)
         return NULL;
 
+    TypeObject *protoType = cx->newTypeObject(clasp->name, "prototype", parent_proto);
+    if (!protoType)
+        return NULL;
+    proto->setType(protoType);
+
+    if (clasp == &js_ArrayClass && !proto->makeDenseArraySlow(cx))
+        return NULL;
+
+    TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return NULL;
+
     proto->syncSpecialEquality();
     
     /* After this point, control must exit via label bad or out. */
     AutoObjectRooter tvr(cx, proto);
 
     JSObject *ctor;
     if (!constructor) {
         /*
@@ -3872,18 +3867,17 @@ js_InitClass(JSContext *cx, JSObject *ob
         if (!ctorHandler)
             ctorHandler = JS_TypeHandlerMissing;
 
         fun = js_NewFunction(cx, NULL, constructor, nargs, JSFUN_CONSTRUCTOR, obj, atom,
                              ctorHandler, clasp->name);
         if (!fun)
             return NULL;
 
-        cx->markTypeBuiltinFunction(fun->getTypeObject());
-        cx->addTypePropertyId(obj->getTypeObject(), ATOM_TO_JSID(atom), ObjectValue(*fun));
+        cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), ObjectValue(*fun));
 
         AutoValueRooter tvr2(cx, ObjectValue(*fun));
         if (!DefineStandardSlot(cx, obj, key, atom, tvr2.value(), 0, named))
             goto bad;
 
         /*
          * Remember the class this function is a constructor for so that
          * we know to create an object of this class when we call the
@@ -3899,84 +3893,70 @@ js_InitClass(JSContext *cx, JSObject *ob
          */
         ctor = FUN_OBJECT(fun);
         if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
             Value rval;
             if (!InvokeConstructorWithGivenThis(cx, proto, ObjectOrNullValue(ctor),
                                                 0, NULL, &rval)) {
                 goto bad;
             }
-            if (rval.isObject() && &rval.toObject() != proto)
+            if (rval.isObject() && &rval.toObject() != proto) {
                 proto = &rval.toObject();
+                type = proto->getNewType(cx);
+                if (!type)
+                    goto bad;
+            }
         }
 
         /* Connect constructor and prototype by named properties. */
         if (!js_SetClassPrototype(cx, ctor, proto,
                                   JSPROP_READONLY | JSPROP_PERMANENT)) {
             goto bad;
         }
 
         /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
         if (ctor->getClass() == clasp)
-            ctor->setProto(cx, proto);
-
-#ifdef JS_TYPE_INFERENCE
-        if (clasp == &js_FunctionClass) {
-            /*
-             * Fixup the type information for the prototype class. protoType
-             * was ignored when proto was constructed.
-             */
-            proto->typeObject = protoType;
-            cx->markTypeBuiltinFunction(proto->getTypeObject());
-
-            cx->setTypeFunctionPrototype(fun->getTypeObject(), protoType);
-        } else {
-            cx->setTypeFunctionPrototype(fun->getTypeObject(), protoType);
-        }
-#endif
-    }
-
-    /* Get the type prefix for the class methods. This is normally the
-     * class name, with an exception for the Iterator class which is folded
-     * together with Generator. */
-    prefix = clasp->name;
-    if (clasp == &js_GeneratorClass)
-        prefix = js_IteratorClass.name;
+            ctor->getType()->splicePrototype(proto);
+    }
 
     /* Add properties and methods to the prototype and the constructor. */
     if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
-        (fs && !JS_DefineFunctionsWithPrefix(cx, proto, fs, prefix)) ||
+        (fs && !JS_DefineFunctionsWithPrefix(cx, proto, fs, clasp->name)) ||
         (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
-        (static_fs && !JS_DefineFunctionsWithPrefix(cx, ctor, static_fs, prefix))) {
+        (static_fs && !JS_DefineFunctionsWithPrefix(cx, ctor, static_fs, clasp->name))) {
         goto bad;
     }
 
     /*
      * Pre-brand the prototype and constructor if they have built-in methods.
      * This avoids extra shape guard branch exits in the tracejitted code.
      */
     if (fs && !proto->brand(cx))
         goto bad;
     if (ctor != proto && static_fs && !ctor->brand(cx))
         goto bad;
 
+    type = proto->getNewType(cx);
+    if (!type)
+        goto bad;
+
     /*
      * Make sure proto's emptyShape is available to be shared by objects of
-     * this class.  JSObject::emptyShape is a one-slot cache. If we omit this,
+     * this class.  TypeObject::emptyShape is a one-slot cache. If we omit this,
      * some other class could snap it up. (The risk is particularly great for
      * Object.prototype.)
      *
      * All callers of JSObject::initSharingEmptyShape depend on this.
      *
      * FIXME: bug 592296 -- js_InitArrayClass should pass &js_SlowArrayClass
      * and make the Array.prototype slow from the start.
      */
     JS_ASSERT_IF(proto->clasp != clasp,
                  clasp == &js_ArrayClass && proto->clasp == &js_SlowArrayClass);
-    if (!proto->getEmptyShape(cx, proto->clasp, FINALIZE_OBJECT0))
+    if (!type->getEmptyShape(cx, proto->clasp, FINALIZE_OBJECT0))
         goto bad;
 
     if (clasp->flags & (JSCLASS_FREEZE_PROTO|JSCLASS_FREEZE_CTOR)) {
         JS_ASSERT_IF(ctor == proto, !(clasp->flags & JSCLASS_FREEZE_CTOR));
         if (proto && (clasp->flags & JSCLASS_FREEZE_PROTO) && !proto->freeze(cx))
             goto bad;
         if (ctor && (clasp->flags & JSCLASS_FREEZE_CTOR) && !ctor->freeze(cx))
             goto bad;
@@ -4147,19 +4127,35 @@ SetProto(JSContext *cx, JSObject *obj, J
      * case any entries were filled by looking up through obj.
      */
     JSObject *oldproto = obj;
     while (oldproto && oldproto->isNative()) {
         oldproto->protoShapeChange(cx);
         oldproto = oldproto->getProto();
     }
 
+    TypeObject *type;
+    if (proto) {
+        type = proto->getNewType(cx);
+        if (!type)
+            return false;
+    } else {
+        type = cx->emptyTypeObject();
+    }
+
+    /*
+     * Setting __proto__ on an object that has escaped and may be referenced by
+     * other heap objects can only be done if the properties of both objects are unknown.
+     */
+    cx->markTypeObjectUnknownProperties(obj->getType());
+    cx->markTypeObjectUnknownProperties(type);
+
     if (!proto || !checkForCycles) {
-        obj->setProto(cx, proto);
-    } else if (!SetProtoCheckingForCycles(cx, obj, proto)) {
+        obj->setType(type);
+    } else if (!SetTypeCheckingForCycles(cx, obj, type)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CYCLIC_VALUE, js_proto_str);
         return false;
     }
     return true;
 }
 
 }
 
@@ -4296,17 +4292,17 @@ js_FindClassObject(JSContext *cx, JSObje
         }
     }
     *vp = v;
     return JS_TRUE;
 }
 
 JSObject *
 js_ConstructObject(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent,
-                   TypeObject *type, uintN argc, Value *argv)
+                   uintN argc, Value *argv)
 {
     AutoArrayRooter argtvr(cx, argc, argv);
 
     JSProtoKey protoKey = GetClassProtoKey(clasp);
 
     /* Protect constructor in case a crazy getter for .prototype uproots it. */
     AutoValueRooter tvr(cx);
     if (!js_FindClassObject(cx, parent, protoKey, tvr.addr(), clasp))
@@ -4330,17 +4326,17 @@ js_ConstructObject(JSContext *cx, Class 
         if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
                                &rval)) {
             return NULL;
         }
         if (rval.isObjectOrNull())
             proto = rval.toObjectOrNull();
     }
 
-    JSObject *obj = NewObject<WithProto::Class>(cx, clasp, proto, parent, type);
+    JSObject *obj = NewObject<WithProto::Class>(cx, clasp, proto, parent);
     if (!obj)
         return NULL;
 
     obj->syncSpecialEquality();
 
     Value rval;
     if (!InvokeConstructorWithGivenThis(cx, obj, cval, argc, argv, &rval))
         return NULL;
@@ -6138,16 +6134,19 @@ js_GetClassPrototype(JSContext *cx, JSOb
     }
 
     return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);
 }
 
 JSBool
 js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs)
 {
+    cx->addTypePropertyId(ctor->getType(), ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
+                          ObjectOrNullValue(proto));
+
     /*
      * Use the given attributes for the prototype property of the constructor,
      * as user-defined constructors have a DontDelete prototype (which may be
      * reset), while native or "system" constructors have DontEnum | ReadOnly |
      * DontDelete.
      */
     if (!ctor->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
                               ObjectOrNullValue(proto), PropertyStub, PropertyStub, attrs)) {
@@ -6164,31 +6163,26 @@ js_SetClassPrototype(JSContext *cx, JSOb
 
 JSBool
 js_PrimitiveToObject(JSContext *cx, Value *vp)
 {
     Value v = *vp;
     JS_ASSERT(v.isPrimitive());
 
     Class *clasp;
-    FixedTypeObjectName name;
     if (v.isNumber()) {
         clasp = &js_NumberClass;
-        name = TYPE_OBJECT_NEW_NUMBER;
     } else if (v.isString()) {
         clasp = &js_StringClass;
-        name = TYPE_OBJECT_NEW_STRING;
     } else {
         JS_ASSERT(v.isBoolean());
         clasp = &js_BooleanClass;
-        name = TYPE_OBJECT_NEW_BOOLEAN;
-    }
-
-    TypeObject *type = cx->getFixedTypeObject(name);
-    JSObject *obj = NewBuiltinClassInstance(cx, clasp, type);
+    }
+
+    JSObject *obj = NewBuiltinClassInstance(cx, clasp);
     if (!obj)
         return JS_FALSE;
 
     obj->setPrimitiveThis(v);
     vp->setObject(*obj);
     return JS_TRUE;
 }
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -254,20 +254,22 @@ namespace nanojit {
 class ValidateWriter;
 }
 
 /*
  * JSObject struct, with members sized to fit in 32 bytes on 32-bit targets,
  * 64 bytes on 64-bit systems. The JSFunction struct is an extension of this
  * struct allocated from a larger GC size-class.
  *
- * The clasp member stores the js::Class pointer for this object. We do *not*
- * synchronize updates of clasp or flags -- API clients must take care.
+ * The clasp member stores the js::Class pointer for this object.
  *
- * An object is a delegate if it is on another object's prototype (the proto
+ * The type member stores the type of the object, which contains its prototype
+ * object and the possible types of its properties.
+ *
+ * An object is a delegate if it is on another object's prototype (type->proto
  * field) or scope chain (the parent field), and therefore the delegate might
  * be asked implicitly to get or set a property on behalf of another object.
  * Delegates may be accessed directly too, as may any object, but only those
  * objects linked after the head of any prototype or scope chain are flagged
  * as delegates. This definition helps to optimize shape-based property cache
  * invalidation (see Purge{Scope,Proto}Chain in jsobj.cpp).
  *
  * The meaning of the system object bit is defined by the API client. It is
@@ -357,50 +359,30 @@ struct JSObject : js::gc::Cell {
         NSLOTS_BITS     = 29,
         NSLOTS_LIMIT    = JS_BIT(NSLOTS_BITS)
     };
 
     uint32      flags;                      /* flags */
     uint32      objShape;                   /* copy of lastProp->shape, or override if different */
 
     union {
-        /* If prototype, lazily filled array of empty shapes for each object size. */
-        js::EmptyShape **emptyShapes;
+        /* If prototype, type of values using this as their prototype. */
+        js::types::TypeObject *newType;
 
         /* If dense array, initialized length of the array. */
         jsuword initializedLength;
     };
 
-    JSObject    *proto;                     /* object's prototype */
+    js::types::TypeObject *type;            /* object's type and prototype */
     JSObject    *parent;                    /* object's parent */
     void        *privateData;               /* private data */
     jsuword     capacity;                   /* capacity of slots */
     js::Value   *slots;                     /* dynamically allocated slots,
                                                or pointer to fixedSlots() */
 
-#ifdef JS_TYPE_INFERENCE
-    /* Type information for this object. */
-    js::types::TypeObject *typeObject;
-
-#if JS_BITS_PER_WORD == 32
-    void *padding;
-#endif
-#endif
-
-    /*
-     * Return an immutable, shareable, empty shape with the same clasp as this
-     * and the same slotSpan as this had when empty.
-     *
-     * If |this| is the scope of an object |proto|, the resulting scope can be
-     * used as the scope of a new object whose prototype is |proto|.
-     */
-    inline bool canProvideEmptyShape(js::Class *clasp);
-    inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp,
-                                         /* gc::FinalizeKind */ unsigned kind);
-
     bool isNative() const       { return map->isNative(); }
 
     js::Class *getClass() const { return clasp; }
     JSClass *getJSClass() const { return Jsvalify(clasp); }
 
     bool hasClass(const js::Class *c) const {
         return c == clasp;
     }
@@ -668,20 +650,24 @@ struct JSObject : js::gc::Cell {
 
     /* Defined in jsscopeinlines.h to avoid including implementation dependencies here. */
     inline void updateShape(JSContext *cx);
     inline void updateFlags(const js::Shape *shape, bool isDefinitelyAtom = false);
 
     /* Extend this object to have shape as its last-added property. */
     inline void extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom = false);
 
-    JSObject *getProto() const  { return proto; }
-    void clearProto()           { proto = NULL; }
+    js::types::TypeObject* getType() const { return type; }
 
-    inline void setProto(JSContext *cx, JSObject *newProto);
+    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 *getParent() const {
         return parent;
     }
 
     void clearParent() {
         parent = NULL;
     }
@@ -706,32 +692,16 @@ struct JSObject : js::gc::Cell {
         return privateData;
     }
 
     void setPrivate(void *data) {
         JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
         privateData = data;
     }
 
-    /* Get the type information for this object. */
-    js::types::TypeObject* getTypeObject()
-    {
-#ifdef JS_TYPE_INFERENCE
-        return typeObject;
-#else
-        return NULL;
-#endif
-    }
-
-    /* Get the type of objects which use this as their prototype. */
-    inline js::types::TypeObject *getTypePrototypeNewObject(JSContext *cx);
-
-    /* Get the type of the default prototype of this function object. */
-    inline js::types::TypeObject *getTypePrototype(JSContext *cx);
-
     /*
      * ES5 meta-object properties and operations.
      */
 
   private:
     enum ImmutabilityType { SEAL, FREEZE };
 
     /*
@@ -1025,31 +995,30 @@ struct JSObject : js::gc::Cell {
     inline void setWithThis(JSObject *thisp);
 
     /*
      * Back to generic stuff.
      */
     inline bool isCallable();
 
     /* The map field is not initialized here and should be set separately. */
-    void init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent,
-              js::types::TypeObject *type, void *priv, bool useHoles);
+    void init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type,
+              JSObject *parent, void *priv, bool useHoles);
 
     inline void finish(JSContext *cx);
     JS_ALWAYS_INLINE void finalize(JSContext *cx);
 
     /*
      * Like init, but also initializes map. The catch: proto must be the result
      * of a call to js_InitClass(...clasp, ...).
      */
     inline bool initSharingEmptyShape(JSContext *cx,
                                       js::Class *clasp,
-                                      JSObject *proto,
+                                      js::types::TypeObject *type,
                                       JSObject *parent,
-                                      js::types::TypeObject *type,
                                       void *priv,
                                       /* gc::FinalizeKind */ unsigned kind);
 
     inline bool hasSlotsArray() const;
 
     /* This method can only be called when hasSlotsArray() returns true. */
     inline void freeSlotsArray(JSContext *cx);
 
@@ -1317,28 +1286,16 @@ inline bool JSObject::isBlock() const  {
  * object named in the with statement, the slots containing the block's local
  * variables); and both have a private slot referring to the JSStackFrame in
  * whose activation they were created (or null if the with or block object
  * outlives the frame).
  */
 static const uint32 JSSLOT_BLOCK_DEPTH = 0;
 static const uint32 JSSLOT_BLOCK_FIRST_FREE_SLOT = JSSLOT_BLOCK_DEPTH + 1;
 
-inline bool
-JSObject::isStaticBlock() const
-{
-    return isBlock() && !getProto();
-}
-
-inline bool
-JSObject::isClonedBlock() const
-{
-    return isBlock() && !!getProto();
-}
-
 static const uint32 JSSLOT_WITH_THIS = 1;
 
 #define OBJ_BLOCK_COUNT(cx,obj)                                               \
     (obj)->propertyCount()
 #define OBJ_BLOCK_DEPTH(cx,obj)                                               \
     (obj)->getSlot(JSSLOT_BLOCK_DEPTH).toInt32()
 #define OBJ_SET_BLOCK_DEPTH(cx,obj,depth)                                     \
     (obj)->setSlot(JSSLOT_BLOCK_DEPTH, Value(Int32Value(depth)))
@@ -1350,21 +1307,17 @@ static const uint32 JSSLOT_WITH_THIS = 1
  *
  * When popping the stack across this object's "with" statement, client code
  * must call withobj->setPrivate(NULL).
  */
 extern JS_REQUIRES_STACK JSObject *
 js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth);
 
 inline JSObject *
-js_UnwrapWithObject(JSContext *cx, JSObject *withobj)
-{
-    JS_ASSERT(withobj->getClass() == &js_WithClass);
-    return withobj->getProto();
-}
+js_UnwrapWithObject(JSContext *cx, JSObject *withobj);
 
 /*
  * Create a new block scope object not linked to any proto or parent object.
  * Blocks are created by the compiler to reify let blocks and comprehensions.
  * Only when dynamic scope is captured do they need to be cloned and spliced
  * into an active scope chain.
  */
 extern JSObject *
@@ -1474,18 +1427,17 @@ js_SetClassObject(JSContext *cx, JSObjec
  * JSProto_Null, clasp must non-null.
  */
 extern JSBool
 js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey key,
                    js::Value *vp, js::Class *clasp = NULL);
 
 extern JSObject *
 js_ConstructObject(JSContext *cx, js::Class *clasp, JSObject *proto,
-                   JSObject *parent, js::types::TypeObject *type,
-                   uintN argc, js::Value *argv);
+                   JSObject *parent, uintN argc, js::Value *argv);
 
 // Specialized call for constructing |this| with a known function callee,
 // and a known prototype.
 extern JSObject *
 js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto);
 
 // Specialized call for constructing |this| with a known function callee.
 extern JSObject *
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -293,17 +293,17 @@ JSObject::getArrayLength() const
 
 inline void
 JSObject::setArrayLength(JSContext *cx, uint32 length)
 {
     JS_ASSERT(isArray());
     setPrivate((void*) length);
 
     if (length > INT32_MAX) {
-        cx->addTypePropertyId(getTypeObject(), ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
+        cx->addTypePropertyId(getType(), ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
                               js::types::TYPE_DOUBLE);
     }
 }
 
 inline uint32
 JSObject::getDenseArrayCapacity()
 {
     JS_ASSERT(isDenseArray());
@@ -597,101 +597,112 @@ JSObject::getWithThis() const
 }
 
 inline void
 JSObject::setWithThis(JSObject *thisp)
 {
     getSlotRef(JSSLOT_WITH_THIS).setObject(*thisp);
 }
 
-inline void
-JSObject::setProto(JSContext *cx, JSObject *newProto)
+inline js::types::TypeObject *
+JSObject::getNewType(JSContext *cx)
 {
-#ifdef DEBUG
-    for (JSObject *obj = newProto; obj; obj = obj->getProto())
-        JS_ASSERT(obj != this);
-#endif
-    if (newProto && newProto->isDenseArray())
-        newProto->makeDenseArraySlow(cx);
+    if (isDenseArray() && !makeDenseArraySlow(cx))
+        return NULL;
+    if (!newType)
+        makeNewType(cx);
+    return newType;
+}
 
-    setDelegateNullSafe(newProto);
-    proto = newProto;
+inline JSObject *
+JSObject::getProto() const
+{
+    return type->proto;
 }
 
 inline void
-JSObject::init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent,
-               js::types::TypeObject *type, void *priv, bool useHoles)
+JSObject::clearType(JSContext *cx)
+{
+    type = cx->emptyTypeObject();
+}
+
+inline void
+JSObject::setType(js::types::TypeObject *newType)
+{
+#ifdef DEBUG
+    JS_ASSERT(newType);
+    for (JSObject *obj = newType->proto; obj; obj = obj->getProto())
+        JS_ASSERT(obj != this);
+#endif
+    type = newType;
+}
+
+inline void
+JSObject::init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type,
+               JSObject *parent, void *priv, bool useHoles)
 {
     clasp = aclasp;
 
 #ifdef DEBUG
     /*
      * NB: objShape must not be set here; rather, the caller must call setMap
      * or setSharedNonNativeMap after calling init. To defend this requirement
      * we set map to null in DEBUG builds, and set objShape to a value we then
      * assert obj->shape() never returns.
      */
     map = NULL;
     objShape = JSObjectMap::INVALID_SHAPE;
 #endif
 
-    setProto(cx, proto);
+    setType(type);
     setParent(parent);
 
     privateData = priv;
     slots = fixedSlots();
 
     /*
      * Fill the fixed slots with undefined if needed.  This object must
      * already have its capacity filled in, as by js_NewGCObject.
      */
     JS_ASSERT(capacity == numFixedSlots());
     JS_ASSERT(useHoles == (aclasp == &js_ArrayClass));
     if (useHoles) {
         initializedLength = 0;
         flags = PACKED_ARRAY;
     } else {
         ClearValueRange(slots, capacity, false);
-        emptyShapes = NULL;
+        newType = NULL;
         flags = 0;
     }
-
-#ifdef JS_TYPE_INFERENCE
-    JS_ASSERT_IF(aclasp != &js_FunctionClass, type);
-    typeObject = type;
-#endif
 }
 
 inline void
 JSObject::finish(JSContext *cx)
 {
 #ifdef DEBUG
     if (isNative())
         JS_LOCK_RUNTIME_VOID(cx->runtime, cx->runtime->liveObjectProps -= propertyCount());
 #endif
     if (hasSlotsArray())
         freeSlotsArray(cx);
-    if (!isDenseArray() && emptyShapes)
-        cx->free(emptyShapes);
 }
 
 inline bool
 JSObject::initSharingEmptyShape(JSContext *cx,
                                 js::Class *aclasp,
-                                JSObject *proto,
+                                js::types::TypeObject *type,
                                 JSObject *parent,
-                                js::types::TypeObject *type,
                                 void *privateValue,
                                 /* js::gc::FinalizeKind */ unsigned kind)
 {
-    init(cx, aclasp, proto, parent, type, privateValue, false);
+    init(cx, aclasp, type, parent, privateValue, false);
 
     JS_ASSERT(!isDenseArray());
 
-    js::EmptyShape *empty = proto->getEmptyShape(cx, aclasp, kind);
+    js::EmptyShape *empty = type->getEmptyShape(cx, aclasp, kind);
     if (!empty)
         return false;
 
     setMap(empty);
     return true;
 }
 
 inline void
@@ -732,16 +743,35 @@ JSObject::isCallable()
 }
 
 static inline bool
 js_IsCallable(const js::Value &v)
 {
     return v.isObject() && v.toObject().isCallable();
 }
 
+inline bool
+JSObject::isStaticBlock() const
+{
+    return isBlock() && !getProto();
+}
+
+inline bool
+JSObject::isClonedBlock() const
+{
+    return isBlock() && !!getProto();
+}
+
+inline JSObject *
+js_UnwrapWithObject(JSContext *cx, JSObject *withobj)
+{
+    JS_ASSERT(withobj->getClass() == &js_WithClass);
+    return withobj->getProto();
+}
+
 namespace js {
 
 class AutoPropDescArrayRooter : private AutoGCRooter
 {
   public:
     AutoPropDescArrayRooter(JSContext *cx)
       : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx)
     { }
@@ -782,31 +812,29 @@ class AutoPropertyDescriptorRooter : pri
         setter = desc->setter;
         value = desc->value;
     }
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 };
 
 static inline bool
-InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto,
+InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, js::types::TypeObject *type,
                    gc::FinalizeKind kind)
 {
     JS_ASSERT(clasp->isNative());
-    JS_ASSERT(proto == obj->getProto());
+    JS_ASSERT(type == obj->getType());
 
     /* Share proto's emptyShape only if obj is similar to proto. */
     js::EmptyShape *empty = NULL;
 
-    if (proto) {
-        if (proto->canProvideEmptyShape(clasp)) {
-            empty = proto->getEmptyShape(cx, clasp, kind);
-            if (!empty)
-                goto bad;
-        }
+    if (type && type->canProvideEmptyShape(clasp)) {
+        empty = type->getEmptyShape(cx, clasp, kind);
+        if (!empty)
+            goto bad;
     }
 
     if (!empty) {
         empty = js::EmptyShape::create(cx, clasp);
         if (!empty)
             goto bad;
         uint32 freeslot = JSSLOT_FREE(clasp);
         if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot))
@@ -825,68 +853,71 @@ InitScopeForObject(JSContext* cx, JSObje
 /*
  * Helper optimized for creating a native instance of the given class (not the
  * class's prototype object). Use this in preference to NewObject, but use
  * NewBuiltinClassInstance if you need the default class prototype as proto,
  * and its parent global as parent.
  */
 static inline JSObject *
 NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
-                       JSObject *parent, js::types::TypeObject *type, gc::FinalizeKind kind)
+                       JSObject *parent, gc::FinalizeKind kind)
 {
     JS_ASSERT(proto);
     JS_ASSERT(proto->isNative());
     JS_ASSERT(parent);
 
+    types::TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return NULL;
+
     /*
      * Allocate an object from the GC heap and initialize all its fields before
      * doing any operation that can potentially trigger GC.
      */
     JSObject* obj = js_NewGCObject(cx, kind);
 
     if (obj) {
         /*
          * Default parent to the parent of the prototype, which was set from
          * the parent of the prototype's constructor.
          */
         bool useHoles = (clasp == &js_ArrayClass);
-        obj->init(cx, clasp, proto, parent, type, NULL, useHoles);
+        obj->init(cx, clasp, type, parent, NULL, useHoles);
 
-        JS_ASSERT(proto->canProvideEmptyShape(clasp));
-        js::EmptyShape *empty = proto->getEmptyShape(cx, clasp, kind);
+        JS_ASSERT(type->canProvideEmptyShape(clasp));
+        js::EmptyShape *empty = type->getEmptyShape(cx, clasp, kind);
 
         if (empty)
             obj->setMap(empty);
         else
             obj = NULL;
     }
 
     return obj;
 }
 
 static inline JSObject *
-NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent,
-                       js::types::TypeObject *type)
+NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
 {
     gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
-    return NewNativeClassInstance(cx, clasp, proto, parent, type, kind);
+    return NewNativeClassInstance(cx, clasp, proto, parent, kind);
 }
 
 bool
 FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
                    Class *clasp);
 
 /*
  * Helper used to create Boolean, Date, RegExp, etc. instances of built-in
  * classes with class prototypes of the same Class. See, e.g., jsdate.cpp,
  * jsregexp.cpp, and js_PrimitiveToObject in jsobj.cpp. Use this to get the
  * right default proto and parent for clasp in cx.
  */
 static inline JSObject *
-NewBuiltinClassInstance(JSContext *cx, Class *clasp, js::types::TypeObject *type, gc::FinalizeKind kind)
+NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::FinalizeKind kind)
 {
     VOUCH_DOES_NOT_REQUIRE_STACK();
 
     JSProtoKey protoKey = JSCLASS_CACHED_PROTO_KEY(clasp);
     JS_ASSERT(protoKey != JSProto_Null);
 
     /* NB: inline-expanded and specialized version of js_GetClassPrototype. */
     JSObject *global;
@@ -904,31 +935,25 @@ NewBuiltinClassInstance(JSContext *cx, C
     JSObject *proto;
     if (v.isObject()) {
         proto = &v.toObject();
         JS_ASSERT(proto->getParent() == global);
     } else {
         if (!FindClassPrototype(cx, global, protoKey, &proto, clasp))
             return NULL;
     }
-#ifdef JS_TYPE_INFERENCE
-    if (!type) {
-        JS_ASSERT(proto);
-        type = proto->getTypePrototypeNewObject(cx);
-    }
-#endif
 
-    return NewNativeClassInstance(cx, clasp, proto, global, type, kind);
+    return NewNativeClassInstance(cx, clasp, proto, global, kind);
 }
 
 static inline JSObject *
-NewBuiltinClassInstance(JSContext *cx, Class *clasp, js::types::TypeObject *type)
+NewBuiltinClassInstance(JSContext *cx, Class *clasp)
 {
     gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
-    return NewBuiltinClassInstance(cx, clasp, type, kind);
+    return NewBuiltinClassInstance(cx, clasp, kind);
 }
 
 static inline JSProtoKey
 GetClassProtoKey(js::Class *clasp)
 {
     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
     if (key != JSProto_Null)
         return key;
@@ -965,37 +990,49 @@ namespace WithProto {
  *    defaults to proto->getParent() if proto is non-null (else to null).
  *
  * If isFunction is true, return a JSFunction-sized object. If isFunction is
  * false, return a normal object.
  *
  * Note that as a template, there will be lots of instantiations, which means
  * the internals will be specialized based on the template parameters.
  */
+static JS_ALWAYS_INLINE bool
+FindProto(JSContext *cx, js::Class *clasp, JSObject *parent, JSObject ** proto)
+{
+    JSProtoKey protoKey = GetClassProtoKey(clasp);
+    if (!js_GetClassPrototype(cx, parent, protoKey, proto, clasp))
+        return false;
+    if (!(*proto) && !js_GetClassPrototype(cx, parent, JSProto_Object, proto))
+        return false;
+
+    return true;
+}
+
 namespace detail
 {
 template <bool withProto, bool isFunction>
 static JS_ALWAYS_INLINE JSObject *
 NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
-          js::types::TypeObject *type, gc::FinalizeKind kind)
+          gc::FinalizeKind kind)
 {
     /* Bootstrap the ur-object, and make it the default prototype object. */
     if (withProto == WithProto::Class && !proto) {
-        JSProtoKey protoKey = GetClassProtoKey(clasp);
-        if (!js_GetClassPrototype(cx, parent, protoKey, &proto, clasp))
-            return NULL;
-        if (!proto && !js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
-            return NULL;
+        if (!FindProto (cx, clasp, parent, &proto))
+          return NULL;
     }
-#ifdef JS_TYPE_INFERENCE
-    if (!type) {
-        JS_ASSERT(proto);
-        type = proto->getTypePrototypeNewObject(cx);
+
+    types::TypeObject *type;
+    if (proto) {
+        type = proto->getNewType(cx);
+        if (!type)
+            return NULL;
+    } else {
+        type = cx->emptyTypeObject();
     }
-#endif
 
     /*
      * Allocate an object from the GC heap and initialize all its fields before
      * doing any operation that can potentially trigger GC. Functions have a
      * larger non-standard allocation size.
      *
      * The should be specialized by the template.
      */
@@ -1005,83 +1042,81 @@ NewObject(JSContext *cx, js::Class *clas
 
     /* This needs to match up with the size of JSFunction::data_padding. */
     JS_ASSERT_IF(isFunction, kind == gc::FINALIZE_OBJECT2);
 
     /*
      * Default parent to the parent of the prototype, which was set from
      * the parent of the prototype's constructor.
      */
-    obj->init(cx, clasp, proto,
-              (!parent && proto) ? proto->getParent() : parent, type,
+    obj->init(cx, clasp, type,
+              (!parent && proto) ? proto->getParent() : parent,
               NULL, clasp == &js_ArrayClass);
 
     if (clasp->isNative()) {
-        if (!InitScopeForObject(cx, obj, clasp, proto, kind)) {
+        if (!InitScopeForObject(cx, obj, clasp, type, kind)) {
             obj = NULL;
             goto out;
         }
     } else {
         obj->setSharedNonNativeMap();
     }
 
 out:
     Probes::createObject(cx, obj);
     return obj;
 }
 } /* namespace detail */
 
 static JS_ALWAYS_INLINE JSObject *
-NewFunction(JSContext *cx, JSObject *parent, js::types::TypeObject *type)
+NewFunction(JSContext *cx, JSObject *parent)
 {
-    return detail::NewObject<WithProto::Class, true>(cx, &js_FunctionClass, NULL, parent, type,
+    return detail::NewObject<WithProto::Class, true>(cx, &js_FunctionClass, NULL, parent,
                                                      gc::FINALIZE_OBJECT2);
 }
 
 template <WithProto::e withProto>
 static JS_ALWAYS_INLINE JSObject *
 NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
-               js::types::TypeObject *type, gc::FinalizeKind kind)
+               gc::FinalizeKind kind)
 {
-    return detail::NewObject<withProto, false>(cx, clasp, proto, parent, type, kind);
+    return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
 }
 
 template <WithProto::e withProto>
 static JS_ALWAYS_INLINE JSObject *
-NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
-               js::types::TypeObject *type)
+NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
 {
     gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
-    return detail::NewObject<withProto, false>(cx, clasp, proto, parent, type, kind);
+    return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
 }
 
 template <WithProto::e withProto>
 static JS_ALWAYS_INLINE JSObject *
 NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
-          js::types::TypeObject *type, gc::FinalizeKind kind)
+          gc::FinalizeKind kind)
 {
     if (clasp == &js_FunctionClass)
-        return detail::NewObject<withProto, true>(cx, clasp, proto, parent, type, kind);
-    return detail::NewObject<withProto, false>(cx, clasp, proto, parent, type, kind);
+        return detail::NewObject<withProto, true>(cx, clasp, proto, parent, kind);
+    return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
 }
 
 template <WithProto::e withProto>
 static JS_ALWAYS_INLINE JSObject *
-NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
-          js::types::TypeObject *type)
+NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
 {
     gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
-    return NewObject<withProto>(cx, clasp, proto, parent, type, kind);
+    return NewObject<withProto>(cx, clasp, proto, parent, kind);
 }
 
 /* Creates a new array with a zero length and the given finalize kind. */
 static inline JSObject *
-NewArrayWithKind(JSContext* cx, js::types::TypeObject *type, gc::FinalizeKind kind)
+NewArrayWithKind(JSContext* cx, gc::FinalizeKind kind)
 {
-    return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, type, kind);
+    return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
 }
 
 /*
  * As for js_GetGCObjectKind, where numSlots is a guess at the final size of
  * the object, zero if the final size is unknown.
  */
 static inline gc::FinalizeKind
 GuessObjectGCKind(size_t numSlots, bool isArray)
@@ -1108,23 +1143,30 @@ NewObjectGCKind(JSContext *cx, js::Class
 /* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
 static inline JSObject *
 CopyInitializerObject(JSContext *cx, JSObject *baseobj, types::TypeObject *type)
 {
     JS_ASSERT(baseobj->getClass() == &js_ObjectClass);
     JS_ASSERT(!baseobj->inDictionaryMode());
 
     gc::FinalizeKind kind = gc::FinalizeKind(baseobj->finalizeKind());
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, type, kind);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
 
     if (!obj || !obj->ensureSlots(cx, baseobj->numSlots()))
         return NULL;
 
+    obj->type = type;
     obj->flags = baseobj->flags;
     obj->lastProp = baseobj->lastProp;
     obj->objShape = baseobj->objShape;
 
     return obj;
 }
 
 } /* namespace js */
 
+inline JSObject *
+js_GetProtoIfDenseArray(JSObject *obj)
+{
+    return obj->isDenseArray() ? obj->getProto() : obj;
+}
+
 #endif /* jsobjinlines_h___ */
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -553,18 +553,17 @@ Str(JSContext *cx, jsid id, JSObject *ho
 JSBool
 js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, const Value &space,
              JSCharBuffer &cb)
 {
     StringifyContext scx(cx, cb, replacer);
     if (!scx.initializeGap(cx, space) || !scx.initializeStack())
         return JS_FALSE;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_JSON);
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, type);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!obj)
         return JS_FALSE;
 
     AutoObjectRooter tvr(cx, obj);
     if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
                              *vp, NULL, NULL, JSPROP_ENUMERATE)) {
         return JS_FALSE;
     }
@@ -658,18 +657,17 @@ JSONParseError(JSONParser *jp, JSContext
     if (!jp->suppressErrors)
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE);
     return JS_FALSE;
 }
 
 static bool
 Revive(JSContext *cx, const Value &reviver, Value *vp)
 {
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_JSON);
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, type);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!obj)
         return false;
 
     AutoObjectRooter tvr(cx, obj);
     if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
                              *vp, NULL, NULL, JSPROP_ENUMERATE)) {
         return false;
     }
@@ -678,18 +676,17 @@ Revive(JSContext *cx, const Value &reviv
 }
 
 JSONParser *
 js_BeginJSONParse(JSContext *cx, Value *rootVal, bool suppressErrors /*= false*/)
 {
     if (!cx)
         return NULL;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_JSON);
-    JSObject *arr = js_NewArrayObject(cx, 0, NULL, type);
+    JSObject *arr = js_NewArrayObject(cx, 0, NULL);
     if (!arr)
         return NULL;
 
     JSONParser *jp = cx->create<JSONParser>(cx);
     if (!jp)
         return NULL;
 
     jp->objectStack = arr;
@@ -844,31 +841,28 @@ PushObject(JSContext *cx, JSONParser *jp
     }
 
     return JS_TRUE;
 }
 
 static JSBool
 OpenObject(JSContext *cx, JSONParser *jp)
 {
-    // TODO: need better type objects following the structure of the JSON.
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_JSON);
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, type);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!obj)
         return JS_FALSE;
 
     return PushObject(cx, jp, obj);
 }
 
 static JSBool
 OpenArray(JSContext *cx, JSONParser *jp)
 {
     // Add an array to an existing array or object
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_JSON);
-    JSObject *arr = js_NewArrayObject(cx, 0, NULL, type);
+    JSObject *arr = js_NewArrayObject(cx, 0, NULL);
     if (!arr)
         return JS_FALSE;
 
     return PushObject(cx, jp, arr);
 }
 
 static JSBool
 CloseObject(JSContext *cx, JSONParser *jp)
@@ -1251,20 +1245,25 @@ static JSFunctionSpec json_static_method
     JS_FN_TYPE("parse",          js_json_parse,      2, 0, JS_TypeHandlerDynamic),
     JS_FN_TYPE("stringify",      js_json_stringify,  3, 0, JS_TypeHandlerString),
     JS_FS_END
 };
 
 JSObject *
 js_InitJSONClass(JSContext *cx, JSObject *obj)
 {
-    TypeObject *type = cx->getTypeObject(js_JSON_str, NULL);
-    JSObject *JSON = NewNonFunction<WithProto::Class>(cx, &js_JSONClass, NULL, obj, type);
+    JSObject *JSON = NewNonFunction<WithProto::Class>(cx, &js_JSONClass, NULL, obj);
     if (!JSON)
         return NULL;
+
+    TypeObject *type = cx->newTypeObject(js_JSON_str, JSON->getProto());
+    if (!type)
+        return NULL;
+    JSON->setType(type);
+
     if (!JS_DefinePropertyWithType(cx, obj, js_JSON_str, OBJECT_TO_JSVAL(JSON),
                                    JS_PropertyStub, JS_PropertyStub, 0))
         return NULL;
 
     if (!JS_DefineFunctionsWithPrefix(cx, JSON, json_static_methods, js_JSON_str))
         return NULL;
 
     return JSON;
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -1047,17 +1047,17 @@ Compiler::defineGlobals(JSContext *cx, G
 
         if (!js_DefineNativeProperty(cx, globalObj, id, rval, PropertyStub,
                                      PropertyStub, JSPROP_ENUMERATE | JSPROP_PERMANENT,
                                      0, 0, &prop)) {
             return false;
         }
 
         if (!rval.isUndefined()) {
-            cx->addTypePropertyId(globalObj->getTypeObject(), id, rval);
+            cx->addTypePropertyId(globalObj->getType(), id, rval);
             if (rval.isObject() && rval.toObject().isFunction()) {
                 JSFunction *fun = rval.toObject().getFunctionPrivate();
                 if (fun->isInterpreted())
                     fun->u.i.script->setTypeNesting(script, script->code);
             }
         }
 
         JS_ASSERT(prop);
@@ -1842,17 +1842,17 @@ Parser::newFunction(JSTreeContext *tc, J
      */
     while (tc->parent)
         tc = tc->parent;
     parent = tc->inFunction() ? NULL : tc->scopeChain();
 
     fun = js_NewFunction(context, NULL, NULL, 0, JSFUN_INTERPRETED | lambda, parent, atom, NULL, NULL);
     if (fun && !tc->compileAndGo()) {
         FUN_OBJECT(fun)->clearParent();
-        FUN_OBJECT(fun)->clearProto();
+        FUN_OBJECT(fun)->clearType(context);
     }
     return fun;
 }
 
 static JSBool
 MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts)
 {
     TokenKind tt = ts->peekTokenSameLine(TSF_OPERAND);
@@ -8712,17 +8712,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
                                                 tokenStream.getTokenbuf().length(),
                                                 tokenStream.currentToken().t_reflags);
         }
 
         if (!obj)
             return NULL;
         if (!tc->compileAndGo()) {
             obj->clearParent();
-            obj->clearProto();
+            obj->clearType(context);
         }
 
         pn->pn_objbox = tc->parser->newObjectBox(obj);
         if (!pn->pn_objbox)
             return NULL;
 
         pn->pn_op = JSOP_REGEXP;
         break;
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -46,16 +46,17 @@
 #include <string.h>
 #include <stdlib.h>
 #include "jsprf.h"
 #include "jsstdint.h"
 #include "jslong.h"
 #include "jsutil.h"
 #include "jspubtd.h"
 #include "jsstr.h"
+#include "jsobjinlines.h"
 
 /*
 ** Note: on some platforms va_list is defined as an array,
 ** and requires array notation.
 */
 #ifdef HAVE_VA_COPY
 #define VARARGS_ASSIGN(foo, bar)        VA_COPY(foo,bar)
 #elif defined(HAVE_VA_LIST_AS_ARRAY)
--- a/js/src/jsprobes.cpp
+++ b/js/src/jsprobes.cpp
@@ -38,16 +38,17 @@
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsinterp.h"
 #include "jsobj.h"
 #include "jsscript.h"
 #include "jsstr.h"
+#include "jsobjinlines.h"
 
 #include "jsprobes.h"
 #include <sys/types.h>
 
 #define TYPEOF(cx,v)    (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
 
 using namespace js;
 
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1097,19 +1097,18 @@ NewProxyObject(JSContext *cx, JSProxyHan
                JSObject *parent, JSObject *call, JSObject *construct)
 {
     bool fun = call || construct;
     Class *clasp;
     if (fun)
         clasp = &FunctionProxyClass;
     else
         clasp = handler->isOuterWindow() ? &OuterWindowProxyClass : &ObjectProxyClass;
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_PROXY);
 
-    JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, type);
+    JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
     if (!obj || !obj->ensureInstanceReservedSlots(cx, 0))
         return NULL;
     obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
     obj->setSlot(JSSLOT_PROXY_PRIVATE, priv);
     if (fun) {
         obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
         if (construct) {
             obj->setSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
@@ -1290,18 +1289,17 @@ callable_Construct(JSContext *cx, uintN 
         JSObject *proto;
         if (protov.isObject()) {
             proto = &protov.toObject();
         } else {
             if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto))
                 return false;
         }
 
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_PROXY);
-        JSObject *newobj = NewNativeClassInstance(cx, &js_ObjectClass, proto, proto->getParent(), type);
+        JSObject *newobj = NewNativeClassInstance(cx, &js_ObjectClass, proto, proto->getParent());
         if (!newobj)
             return false;
 
         /* If the call returns an object, return that, otherwise the original newobj. */
         Value rval;
         if (!ExternalInvoke(cx, newobj, callable->getSlot(JSSLOT_CALLABLE_CALL),
                             argc, vp + 2, &rval)) {
             return false;
@@ -1359,19 +1357,18 @@ FixProxy(JSContext *cx, JSObject *proxy,
     JSObject *proto = proxy->getProto();
     JSObject *parent = proxy->getParent();
     Class *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &js_ObjectClass;
 
     /*
      * Make a blank object from the recipe fix provided to us.  This must have
      * number of fixed slots as the proxy so that we can swap their contents.
      */
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_PROXY);
     gc::FinalizeKind kind = gc::FinalizeKind(proxy->arena()->header()->thingKind);
-    JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, type, kind);
+    JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
     if (!newborn)
         return false;
     AutoObjectRooter tvr2(cx, newborn);
 
     if (clasp == &CallableObjectClass) {
         newborn->setSlot(JSSLOT_CALLABLE_CALL, GetCall(proxy));
         newborn->setSlot(JSSLOT_CALLABLE_CONSTRUCT, GetConstruct(proxy));
     }
@@ -1404,20 +1401,25 @@ Class js_ProxyClass = {
     EnumerateStub,
     ResolveStub,
     ConvertStub
 };
 
 JS_FRIEND_API(JSObject *)
 js_InitProxyClass(JSContext *cx, JSObject *obj)
 {
-    TypeObject *type = cx->getTypeObject(js_ProxyClass.name, NULL);
-    JSObject *module = NewNonFunction<WithProto::Class>(cx, &js_ProxyClass, NULL, obj, type);
+    JSObject *module = NewNonFunction<WithProto::Class>(cx, &js_ProxyClass, NULL, obj);
     if (!module)
         return NULL;
+
+    TypeObject *type = cx->newTypeObject(js_ProxyClass.name, module->getProto());
+    if (!type)
+        return NULL;
+    module->setType(type);
+
     if (!JS_DefinePropertyWithType(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
                                    JS_PropertyStub, JS_PropertyStub, 0)) {
         return NULL;
     }
     if (!JS_DefineFunctionsWithPrefix(cx, module, static_methods, "Proxy"))
         return NULL;
     return module;
 }
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -188,18 +188,17 @@ class NodeBuilder
         if (!atom)
             return false;
 
         *dst = Valueify(ATOM_TO_JSVAL(atom));
         return true;
     }
 
     bool newObject(JSObject **dst) {
-        types::TypeObject *type = cx->getFixedTypeObject(types::TYPE_OBJECT_REFLECT_OBJECT);
-        JSObject *nobj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL, type);
+        JSObject *nobj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
         if (!nobj)
             return false;
 
         *dst = nobj;
         return true;
     }
 
     bool newArray(NodeVector &elts, Value *dst);
@@ -492,34 +491,32 @@ class NodeBuilder
 
 bool
 NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst)
 {
     JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
 
     Value tv;
 
-    types::TypeObject *nodeType = cx->getFixedTypeObject(types::TYPE_OBJECT_REFLECT_OBJECT);
-    JSObject *node = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL, nodeType);
+    JSObject *node = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
     if (!node ||
         !setNodeLoc(node, pos) ||
         !atomValue(nodeTypeNames[type], &tv) ||
         !setProperty(node, "type", tv)) {
         return false;
     }
 
     *dst = node;
     return true;
 }
 
 bool
 NodeBuilder::newArray(NodeVector &elts, Value *dst)
 {
-    types::TypeObject *type = cx->getFixedTypeObject(types::TYPE_OBJECT_REFLECT_ARRAY);
-    JSObject *array = js_NewArrayObject(cx, 0, NULL, type);
+    JSObject *array = js_NewArrayObject(cx, 0, NULL);
     if (!array)
         return false;
 
     const size_t len = elts.length();
     for (size_t i = 0; i < len; i++) {
         Value val = elts[i];
 
         JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
@@ -2880,21 +2877,25 @@ static JSFunctionSpec static_methods[] =
     JS_FN("parse", reflect_parse, 1, 0),
     JS_FS_END
 };
 
 
 JSObject *
 js_InitReflectClass(JSContext *cx, JSObject *obj)
 {
-    types::TypeObject *type = cx->getTypeObject(js_ReflectClass.name, NULL);
-    JSObject *Reflect = NewNonFunction<WithProto::Class>(cx, &js_ReflectClass, NULL, obj, type);
+    JSObject *Reflect = NewNonFunction<WithProto::Class>(cx, &js_ReflectClass, NULL, obj);
     if (!Reflect)
         return NULL;
 
+    types::TypeObject *type = cx->newTypeObject(js_ReflectClass.name, Reflect->getProto());
+    if (!type)
+        return NULL;
+    Reflect->setType(type);
+
     if (!JS_DefineProperty(cx, obj, js_Reflect_str, OBJECT_TO_JSVAL(Reflect),
                            JS_PropertyStub, JS_PropertyStub, 0)) {
         return NULL;
     }
 
     if (!JS_DefineFunctions(cx, Reflect, static_methods))
         return NULL;
 
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -127,18 +127,17 @@ SwapObjectRegExp(JSContext *cx, JSObject
 }
 
 JSObject * JS_FASTCALL
 js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto)
 {
     JS_ASSERT(obj->getClass() == &js_RegExpClass);
     JS_ASSERT(proto);
     JS_ASSERT(proto->getClass() == &js_RegExpClass);
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_NEW_REGEXP);
-    JSObject *clone = NewNativeClassInstance(cx, &js_RegExpClass, proto, proto->getParent(), type);
+    JSObject *clone = NewNativeClassInstance(cx, &js_RegExpClass, proto, proto->getParent());
     if (!clone)
         return NULL;
     RegExpStatics *res = cx->regExpStatics();
     RegExp *re = RegExp::extractFrom(obj);
     {
         uint32 origFlags = re->getFlags();
         uint32 staticsFlags = res->getFlags();
         if ((origFlags & staticsFlags) != staticsFlags) {
@@ -504,22 +503,21 @@ js_XDRRegExpObject(JSXDRState *xdr, JSOb
         if (!re)
             return false;
         source = re->getSource();
         flagsword = re->getFlags();
     }
     if (!JS_XDRString(xdr, &source) || !JS_XDRUint32(xdr, &flagsword))
         return false;
     if (xdr->mode == JSXDR_DECODE) {
-        TypeObject *type = xdr->cx->getFixedTypeObject(TYPE_OBJECT_NEW_REGEXP);
-        JSObject *obj = NewBuiltinClassInstance(xdr->cx, &js_RegExpClass, type);
+        JSObject *obj = NewBuiltinClassInstance(xdr->cx, &js_RegExpClass);
         if (!obj)
             return false;
         obj->clearParent();
-        obj->clearProto();
+        obj->clearType(xdr->cx);
         RegExp *re = RegExp::create(xdr->cx, source, flagsword);
         if (!re)
             return false;
         obj->setPrivate(re);
         obj->zeroRegExpLastIndex();
         *objp = obj;
     }
     return true;
@@ -877,18 +875,17 @@ regexp_construct(JSContext *cx, uintN ar
             (argc == 1 || argv[1].isUndefined()))
         {
             *vp = argv[0];
             return true;
         }
     }
 
     /* Otherwise, replace obj with a new RegExp object. */
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_NEW_REGEXP);
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass, type);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass);
     if (!obj)
         return false;
 
     return regexp_compile_sub(cx, obj, argc, argv, vp);
 }
 
 /* Similar to regexp_compile_sub_tail. */
 static bool
@@ -920,23 +917,19 @@ js_InitRegExpClass(JSContext *cx, JSObje
         !JS_AliasProperty(cx, ctor, "lastMatch",    "$&") ||
         !JS_AliasProperty(cx, ctor, "lastParen",    "$+") ||
         !JS_AliasProperty(cx, ctor, "leftContext",  "$`") ||
         !JS_AliasProperty(cx, ctor, "rightContext", "$'") ||
         !InitRegExpClassCompile(cx, proto)) {
         return NULL;
     }
 
-    TypeObject *regexpType = cx->getFixedTypeObject(TYPE_OBJECT_NEW_REGEXP);
+    TypeObject *regexpType = proto->getNewType(cx);
+    JS_ASSERT(regexpType);
+
     cx->addTypeProperty(regexpType, "source", TYPE_STRING);
     cx->addTypeProperty(regexpType, "global", TYPE_BOOLEAN);
     cx->addTypeProperty(regexpType, "ignoreCase", TYPE_BOOLEAN);
     cx->addTypeProperty(regexpType, "multiline", TYPE_BOOLEAN);
     cx->addTypeProperty(regexpType, "lastIndex", TYPE_INT32);
 
-    TypeObject *arrayType = cx->getFixedTypeObject(TYPE_OBJECT_REGEXP_MATCH_ARRAY);
-    cx->addTypeProperty(arrayType, NULL, TYPE_STRING);
-    cx->addTypeProperty(arrayType, "index", TYPE_INT32);
-    cx->addTypeProperty(arrayType, "input", TYPE_STRING);
-    cx->markTypeArrayNotPacked(arrayType, true);
-
     return proto;
 }
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -57,18 +57,17 @@ namespace js {
  * res = RegExp statics.
  */
 
 extern Class regexp_statics_class;
 
 static inline JSObject *
 regexp_statics_construct(JSContext *cx, JSObject *parent)
 {
-    types::TypeObject *type = cx->getFixedTypeObject(types::TYPE_OBJECT_REGEXP_STATICS);
-    JSObject *obj = NewObject<WithProto::Given>(cx, &regexp_statics_class, NULL, parent, type);
+    JSObject *obj = NewObject<WithProto::Given>(cx, &regexp_statics_class, parent, NULL);
     if (!obj)
         return NULL;
     RegExpStatics *res = cx->create<RegExpStatics>();
     if (!res)
         return NULL;
     obj->setPrivate(static_cast<void *>(res));
     return obj;
 }
@@ -230,28 +229,45 @@ RegExp::checkMatchPairs(JSString *input,
         if (start == -1)
             continue;
         JS_ASSERT(start >= 0);
         JS_ASSERT(size_t(limit) <= inputLength);
     }
 #endif
 }
 
+inline types::TypeObject *
+GetRegExpMatchType(JSContext *cx)
+{
+    types::TypeObject *type = cx->getTypeCallerInitObject(true);
+
+    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;
+}
+
 inline JSObject *
 RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount)
 {
     /*
      * Create the result array for a match. Array contents:
      *  0:              matched string
      *  1..pairCount-1: paren matches
      */
-    types::TypeObject *arrayType = cx->getFixedTypeObject(types::TYPE_OBJECT_REGEXP_MATCH_ARRAY);
-    JSObject *array = js_NewSlowArrayObject(cx, arrayType);
+    JSObject *array = js_NewSlowArrayObject(cx);
     if (!array)
         return NULL;
+    types::TypeObject *type = GetRegExpMatchType(cx);
+    if (!type)
+        return NULL;
+    array->setType(type);
+    cx->markTypeArrayNotPacked(type, true);
 
     RegExpMatchBuilder builder(cx, array);
     for (size_t i = 0; i < matchItemCount; i += 2) {
         int start = buf[i];
         int end = buf[i + 1];
 
         JSString *captured;
         if (start >= 0) {
@@ -387,18 +403,17 @@ RegExp::createObjectNoStatics(JSContext 
 {
     JS_ASSERT((flags & allFlags) == flags);
     JSString *str = js_NewStringCopyN(cx, chars, length);
     if (!str)
         return NULL;
     RegExp *re = RegExp::create(cx, str, flags);
     if (!re)
         return NULL;
-    types::TypeObject *objType = cx->getFixedTypeObject(types::TYPE_OBJECT_NEW_REGEXP);
-    JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass, objType);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass);
     if (!obj) {
         re->decref(cx);
         return NULL;
     }
     obj->setPrivate(re);
     obj->zeroRegExpLastIndex();
     return obj;
 }
--- a/js/src/jsscopeinlines.h
+++ b/js/src/jsscopeinlines.h
@@ -55,24 +55,22 @@ js::Shape::freeTable(JSContext *cx)
 {
     if (table) {
         cx->destroy(table);
         table = NULL;
     }
 }
 
 inline js::EmptyShape *
-JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
-                        /* gc::FinalizeKind */ unsigned kind)
+js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
+                                     /* gc::FinalizeKind */ unsigned kind)
 {
     JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
     int i = kind - js::gc::FINALIZE_OBJECT0;
 
-    JS_ASSERT(!isDenseArray());
-
     if (!emptyShapes) {
         emptyShapes = (js::EmptyShape**)
             cx->calloc(sizeof(js::EmptyShape*) * js::gc::JS_FINALIZE_OBJECT_LIMIT);
         if (!emptyShapes)
             return NULL;
 
         /*
          * Always fill in emptyShapes[0], so canProvideEmptyShape works.
@@ -93,19 +91,18 @@ JSObject::getEmptyShape(JSContext *cx, j
         if (!emptyShapes[i])
             return NULL;
     }
 
     return emptyShapes[i];
 }
 
 inline bool
-JSObject::canProvideEmptyShape(js::Class *aclasp)
+js::types::TypeObject::canProvideEmptyShape(js::Class *aclasp)
 {
-    JS_ASSERT(!isDenseArray());
     return !emptyShapes || emptyShapes[0]->getClass() == aclasp;
 }
 
 inline void
 JSObject::updateShape(JSContext *cx)
 {
     JS_ASSERT(isNative());
     js::LeaveTraceIfGlobalObject(cx, this);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1156,25 +1156,16 @@ JSScript::NewScriptFromCG(JSContext *cx,
                      * Fixing this requires the compiler to track upvar uses as
                      * it analyzes and optimizes closures, and subsequently as
                      * the emitter performs useless expression elimination.
                      */
                     goto skip_empty;
                 }
                 fun->freezeLocalNames(cx);
                 fun->u.i.script = empty;
-
-#ifdef JS_TYPE_INFERENCE
-                /* Set type information for the script and function. */
-                if (!empty->analysis)
-                    empty->makeAnalysis(cx);
-                fun->typeObject = cx->getFixedTypeObject(types::TYPE_OBJECT_EMPTY_FUNCTION);
-                if (!fun->typeObject->asFunction()->script)
-                    fun->typeObject->asFunction()->script = empty;
-#endif
             }
 
 #ifdef DEBUG
             {
                 jsrefcount newEmptyLive = JS_RUNTIME_METER(cx->runtime, liveEmptyScripts);
                 jsrefcount newLive = cx->runtime->liveScripts;
                 jsrefcount newTotal =
                     JS_RUNTIME_METER(cx->runtime, totalEmptyScripts) + cx->runtime->totalScripts;
@@ -1296,17 +1287,26 @@ JSScript::NewScriptFromCG(JSContext *cx,
         if (script->upvarsOffset != 0)
             JS_ASSERT(script->upvars()->length == fun->u.i.nupvars);
         else
             fun->u.i.nupvars = 0;
 
         fun->freezeLocalNames(cx);
         fun->u.i.script = script;
 
+#ifdef JS_TYPE_INFERENCE
+        char *name = NULL;
+#ifdef DEBUG
+        name = (char *) alloca(10);
+        JS_snprintf(name, 10, "#%u", script->analysis->id);
+#endif
+        types::TypeObject *type = cx->newTypeFunction(name, fun->getProto());
+        fun->setType(type);
         cx->setTypeFunctionScript(fun, script);
+#endif
 
 #ifdef CHECK_SCRIPT_OWNER
         script->owner = NULL;
 #endif
         if (cg->flags & TCF_FUN_HEAVYWEIGHT)
             fun->flags |= JSFUN_HEAVYWEIGHT;
     }
 
@@ -1435,16 +1435,20 @@ DestroyScript(JSContext *cx, JSScript *s
 # else
     PurgeScriptFragments(&JS_TRACE_MONITOR(cx), script);
 # endif
 #endif
 
 #if defined(JS_METHODJIT)
     mjit::ReleaseScriptCode(cx, script);
 #endif
+
+    if (script->analysis)
+        script->analysis->detach();
+
     JS_REMOVE_LINK(&script->links);
 
     cx->free(script);
 }
 
 void
 js_DestroyScript(JSContext *cx, JSScript *script)
 {
@@ -1497,42 +1501,39 @@ js_TraceScript(JSTracer *trc, JSScript *
     if (script->u.object) {
         JS_SET_TRACING_NAME(trc, "object");
         Mark(trc, script->u.object);
     }
 
     if (IS_GC_MARKING_TRACER(trc) && script->filename)
         js_MarkScriptFilename(script->filename);
 
-#ifdef JS_TYPE_INFERENCE
     if (script->analysis)
         script->analysis->trace(trc);
-#endif
 }
 
 JSBool
 js_NewScriptObject(JSContext *cx, JSScript *script)
 {
     AutoScriptRooter root(cx, script);
 
     JS_ASSERT(!script->u.object);
     JS_ASSERT(script != JSScript::emptyScript());
 
-    types::TypeObject *type = cx->getFixedTypeObject(types::TYPE_OBJECT_SCRIPT);
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL, type);
+    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
     if (!obj)
         return JS_FALSE;
     obj->setPrivate(script);
     script->u.object = obj;
 
     /*
-     * Clear the object's proto, to avoid entraining stuff. Once we no longer use the parent
+     * Clear the object's type/proto, to avoid entraining stuff. Once we no longer use the parent
      * for security checks, then we can clear the parent, too.
      */
-    obj->clearProto();
+    obj->clearType(cx);
 
 #ifdef CHECK_SCRIPT_OWNER
     script->owner = NULL;
 #endif
 
     return JS_TRUE;
 }
 
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1869,20 +1869,26 @@ static bool
 BuildFlatMatchArray(JSContext *cx, JSString *textstr, const FlatMatch &fm, Value *vp)
 {
     if (fm.match() < 0) {
         vp->setNull();
         return true;
     }
 
     /* For this non-global match, produce a RegExp.exec-style array. */
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_REGEXP_MATCH_ARRAY);
-    JSObject *obj = js_NewSlowArrayObject(cx, type);
+    JSObject *obj = js_NewSlowArrayObject(cx);
     if (!obj)
         return false;
+
+    TypeObject *type = GetRegExpMatchType(cx);
+    if (!type)
+        return false;
+    obj->setType(type);
+    cx->markTypeArrayNotPacked(type, true);
+
     vp->setObject(*obj);
 
     return obj->defineProperty(cx, INT_TO_JSID(0), StringValue(fm.pattern())) &&
            obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.indexAtom),
                                Int32Value(fm.match())) &&
            obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.inputAtom),
                                StringValue(textstr));
 }
@@ -1895,20 +1901,24 @@ typedef JSObject **MatchArgType;
  */
 static bool
 MatchCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p)
 {
     JS_ASSERT(count <= JSID_INT_MAX);  /* by max string length */
 
     JSObject *&arrayobj = *static_cast<MatchArgType>(p);
     if (!arrayobj) {
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_REGEXP_MATCH_ARRAY);
-        arrayobj = js_NewArrayObject(cx, 0, NULL, type);
+        arrayobj = js_NewArrayObject(cx, 0, NULL);
         if (!arrayobj)
             return false;
+
+        TypeObject *type = GetRegExpMatchType(cx);
+        if (!type)
+            return false;
+        arrayobj->setType(type);
     }
 
     Value v;
     if (!res->createLastMatch(cx, &v))
         return false;
 
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
     return !!arrayobj->setProperty(cx, INT_TO_JSID(count), &v, false);
@@ -2717,23 +2727,27 @@ find_split(JSContext *cx, RegExpStatics 
 }
 
 static JSBool
 str_split(JSContext *cx, uintN argc, Value *vp)
 {
     JSString *str;
     NORMALIZE_THIS(cx, vp, str);
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_STRING_SPLIT_ARRAY);
+    TypeObject *type = cx->getTypeCallerInitObject(true);
+    if (!type)
+        return false;
+    cx->addTypeProperty(type, NULL, types::TYPE_STRING);
 
     if (argc == 0) {
         Value v = StringValue(str);
-        JSObject *aobj = js_NewArrayObject(cx, 1, &v, type);
+        JSObject *aobj = js_NewArrayObject(cx, 1, &v);
         if (!aobj)
             return false;
+        aobj->setType(type);
         vp->setObject(*aobj);
         return true;
     }
 
     RegExp *re;
     JSSubString *sep, tmp;
     if (VALUE_IS_REGEXP(cx, vp[2])) {
         re = static_cast<RegExp *>(vp[2].toObject().getPrivate());
@@ -2804,19 +2818,20 @@ str_split(JSContext *cx, uintN argc, Val
             sep->chars = NULL;
         }
         i = j + sep->length;
     }
 
     if (j == -2)
         return false;
 
-    JSObject *aobj = js_NewArrayObject(cx, splits.length(), splits.begin(), type);
+    JSObject *aobj = js_NewArrayObject(cx, splits.length(), splits.begin());
     if (!aobj)
         return false;
+    aobj->setType(type);
     vp->setObject(*aobj);
     return true;
 }
 
 #if JS_HAS_PERL_SUBSTR
 static JSBool
 str_substr(JSContext *cx, uintN argc, Value *vp)
 {
@@ -3138,17 +3153,17 @@ JS_DEFINE_TRCINFO_1(str_concat,
 static void type_StringMatch(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
     TypeCallsite *site = Valueify(jssite);
 
     if (!site->returnTypes)
         return;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_REGEXP_MATCH_ARRAY);
+    TypeObject *type = site->getInitObject(cx, true);
     cx->addTypeProperty(type, NULL, TYPE_STRING);
     cx->addTypeProperty(type, "index", TYPE_INT32);
     cx->addTypeProperty(type, "input", TYPE_STRING);
 
     site->returnTypes->addType(cx, TYPE_NULL);
     site->returnTypes->addType(cx, (jstype) type);
 #endif
 }
@@ -3156,17 +3171,17 @@ static void type_StringMatch(JSContext *
 static void type_StringSplit(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
     TypeCallsite *site = Valueify(jssite);
 
     if (!site->returnTypes)
         return;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_STRING_SPLIT_ARRAY);
+    TypeObject *type = site->getInitObject(cx, true);
     cx->addTypeProperty(type, NULL, TYPE_STRING);
 
     site->returnTypes->addType(cx, (jstype) type);
 #endif
 }
 
 static const uint16 GENERIC_PRIMITIVE = JSFUN_GENERIC_NATIVE | JSFUN_PRIMITIVE_THIS;
 
@@ -3404,18 +3419,17 @@ js_String(JSContext *cx, uintN argc, Val
         str = js_ValueToString(cx, argv[0]);
         if (!str)
             return false;
     } else {
         str = cx->runtime->emptyString;
     }
 
     if (IsConstructing(vp)) {
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_NEW_STRING);
-        JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass, type);
+        JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass);
         if (!obj)
             return false;
         obj->setPrimitiveThis(StringValue(str));
         vp->setObject(*obj);
     } else {
         vp->setString(str);
     }
     return true;
@@ -3483,23 +3497,20 @@ JS_DEFINE_TRCINFO_1(str_fromCharCode,
 static JSFunctionSpec string_static_methods[] = {
     JS_TN("fromCharCode", str_fromCharCode, 1, 0, &str_fromCharCode_trcinfo, JS_TypeHandlerString),
     JS_FS_END
 };
 
 static void type_NewString(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
-    TypeCallsite *site = Valueify(jssite);
-    if (site->isNew) {
-        TypeObject *object = cx->getFixedTypeObject(TYPE_OBJECT_NEW_STRING);
-        site->returnTypes->addType(cx, (jstype) object);
-    } else {
+    if (Valueify(jssite)->isNew)
+        JS_TypeHandlerNew(cx, jsfun, jssite);
+    else
         JS_TypeHandlerString(cx, jsfun, jssite);
-    }
 #endif
 }
 
 JSObject *
 js_InitStringClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto;
 
@@ -3517,19 +3528,18 @@ js_InitStringClass(JSContext *cx, JSObje
     jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
     if (!js_DefineNativeProperty(cx, proto, lengthId,
                                  UndefinedValue(), NULL, NULL,
                                  JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0,
                                  NULL)) {
         return JS_FALSE;
     }
 
-    cx->addTypePropertyId(proto->getTypeObject(), lengthId, TYPE_INT32);
-    TypeObject *stringType = cx->getFixedTypeObject(TYPE_OBJECT_NEW_STRING);
-    cx->addTypeProperty(stringType, NULL, TYPE_STRING);
+    cx->addTypePropertyId(proto->getType(), lengthId, TYPE_INT32);
+    cx->addTypeProperty(proto->getNewType(cx), NULL, TYPE_STRING);
 
     return proto;
 }
 
 JSString *
 js_NewString(JSContext *cx, jschar *chars, size_t length)
 {
     JSString *str;
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -10770,17 +10770,17 @@ TraceRecorder::getClassPrototype(JSObjec
     JS_ASSERT((~attrs & (JSPROP_READONLY | JSPROP_PERMANENT)) == 0);
 #endif
 
     // Since ctor was built by js_InitClass, we can assert (rather than check)
     // that pval is usable.
     JS_ASSERT(!pval.isPrimitive());
     JSObject *proto = &pval.toObject();
     JS_ASSERT(!proto->isDenseArray());
-    JS_ASSERT_IF(clasp != &js_ArrayClass, proto->emptyShapes[0]->getClass() == clasp);
+    JS_ASSERT_IF(clasp != &js_ArrayClass, proto->getNewType(cx)->emptyShapes[0]->getClass() == clasp);
 
     proto_ins = w.immpObjGC(proto);
     return RECORD_CONTINUE;
 }
 
 RecordingStatus
 TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
 {
@@ -10794,18 +10794,18 @@ TraceRecorder::getClassPrototype(JSProto
 
     // This should not have reentered.
     JS_ASSERT(localtm.recorder);
 
 #ifdef DEBUG
     /* Double-check that a native proto has a matching emptyShape. */
     if (key != JSProto_Array) {
         JS_ASSERT(proto->isNative());
-        JS_ASSERT(proto->emptyShapes);
-        EmptyShape *empty = proto->emptyShapes[0];
+        JS_ASSERT(proto->getNewType(cx)->emptyShapes);
+        EmptyShape *empty = proto->getNewType(cx)->emptyShapes[0];
         JS_ASSERT(empty);
         JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getClass()) == key);
     }
 #endif
 
     proto_ins = w.immpObjGC(proto);
     return RECORD_CONTINUE;
 }
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -112,17 +112,17 @@ ArrayBuffer::class_constructor(JSContext
     return create(cx, argc, JS_ARGV(cx, vp), vp);
 }
 
 bool
 ArrayBuffer::create(JSContext *cx, uintN argc, Value *argv, Value *rval)
 {
     /* N.B. there may not be an argv[-2]/argv[-1]. */
 
-    JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass, NULL);
+    JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass);
     if (!obj)
         return false;
 
     int32_t nbytes = 0;
     if (argc > 0) {
         if (!ValueToECMAInt32(cx, argv[0], &nbytes))
             return false;
     }
@@ -721,17 +721,17 @@ class TypedArrayTemplate
         return create(cx, argc, JS_ARGV(cx, vp), vp);
     }
 
     static JSBool
     create(JSContext *cx, uintN argc, Value *argv, Value *rval)
     {
         /* N.B. there may not be an argv[-2]/argv[-1]. */
 
-        JSObject *obj = NewBuiltinClassInstance(cx, slowClass(), NULL);
+        JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
         if (!obj)
             return false;
 
         ThisTypeArray *tarray = 0;
 
         // figure out the type of the first argument;
         // no args is treated like an int arg of 0.
         if (argc == 0 || argv[0].isInt32()) {
@@ -866,17 +866,17 @@ class TypedArrayTemplate
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
 
         // note the usage of NewObject here -- we don't want the
         // constructor to be called!
         JS_ASSERT(slowClass() != &js_FunctionClass);
-        JSObject *nobj = NewNonFunction<WithProto::Class>(cx, slowClass(), NULL, NULL, NULL);
+        JSObject *nobj = NewNonFunction<WithProto::Class>(cx, slowClass(), NULL, NULL);
         if (!nobj) {
             delete ntarray;
             return false;
         }
 
         vp->setObject(*nobj);
         return makeFastWithPrivate(cx, nobj, ntarray);
     }
@@ -1530,21 +1530,19 @@ do {                                    
                          &TypedArray::slowClasses[TypedArray::_type],          \
                          _typedArray::class_constructor, 3,                    \
                          JS_TypeHandlerNew,                                    \
                          _typedArray::jsprops,                                 \
                          _typedArray::jsfuncs,                                 \
                          NULL, NULL);                                          \
     if (!proto)                                                                \
         return NULL;                                                           \
-    cx->addTypeProperty(proto->getTypeObject(), "buffer",                      \
-        (types::jstype) cx->getFixedTypeObject(TYPE_OBJECT_NEW_ARRAYBUFFER));  \
-    cx->addTypeProperty(proto->getTypeObject(), NULL, types::TYPE_INT32);      \
+    cx->addTypeProperty(proto->getType(), NULL, types::TYPE_INT32);            \
     if (_typedArray::ArrayElementTypeMayBeDouble())                            \
-        cx->addTypeProperty(proto->getTypeObject(), NULL, types::TYPE_DOUBLE); \
+        cx->addTypeProperty(proto->getType(), NULL, types::TYPE_DOUBLE);       \
     JSObject *ctor = JS_GetConstructor(cx, proto);                             \
     if (!ctor ||                                                               \
         !JS_DefinePropertyWithType(cx, ctor, "BYTES_PER_ELEMENT",              \
                            INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
                            JS_PropertyStub, JS_PropertyStub,                   \
                            JSPROP_PERMANENT | JSPROP_READONLY) ||              \
         !JS_DefinePropertyWithType(cx, proto, "BYTES_PER_ELEMENT",             \
                            INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
@@ -1765,20 +1763,30 @@ js_ReparentTypedArrayToScope(JSContext *
     JS_ASSERT(js_IsArrayBuffer(buffer));
 
     JSObject *proto;
     JSProtoKey key =
         JSCLASS_CACHED_PROTO_KEY(&TypedArray::slowClasses[typedArray->type]);
     if (!js_GetClassPrototype(cx, scope, key, &proto))
         return JS_FALSE;
 
-    obj->setProto(cx, proto);
+    /*
+     * :XXX: This is changing the type of a previous object, which will mess up
+     * type information if this has any expando properties (possible?).
+     */
+    TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return JS_FALSE;
+    obj->setType(type);
     obj->setParent(scope);
 
     key = JSCLASS_CACHED_PROTO_KEY(&ArrayBuffer::jsclass);
     if (!js_GetClassPrototype(cx, scope, key, &proto))
         return JS_FALSE;
 
-    buffer->setProto(cx, proto);
+    type = proto->getNewType(cx);
+    if (!type)
+        return JS_FALSE;
+    buffer->setType(type);
     buffer->setParent(scope);
 
     return JS_TRUE;
 }
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -219,18 +219,17 @@ AppendString(JSCharBuffer &cb, JSString 
 /*
  * This wrapper is needed because NewBuiltinClassInstance doesn't
  * call the constructor, and we need a place to set the
  * HAS_EQUALITY bit.
  */
 static inline JSObject *
 NewBuiltinClassInstanceXML(JSContext *cx, Class *clasp)
 {
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    JSObject *obj = NewBuiltinClassInstance(cx, clasp, type);
+    JSObject *obj = NewBuiltinClassInstance(cx, clasp);
     if (obj)
         obj->syncSpecialEquality();
     return obj;
 }
 
 #define DEFINE_GETTER(name,code)                                               \
     static JSBool                                                              \
     name(JSContext *cx, JSObject *obj, jsid id, jsval *vp)                     \
@@ -559,18 +558,17 @@ js_ConstructXMLQNameObject(JSContext *cx
      */
     if (nsval.isObject() &&
         nsval.toObject().getClass() == &js_AnyNameClass) {
         argv[0].setNull();
     } else {
         argv[0] = nsval;
     }
     argv[1] = lnval;
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    return js_ConstructObject(cx, &js_QNameClass, NULL, NULL, type, 2, argv);
+    return js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, argv);
 }
 
 static JSBool
 IsXMLName(const jschar *cp, size_t n)
 {
     JSBool rv;
     jschar c;
 
@@ -2237,19 +2235,18 @@ GetNamespace(JSContext *cx, JSObject *qn
             }
         }
     }
 
     /* If we didn't match, make a new namespace from qn. */
     if (!match) {
         argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID;
         argv[1] = STRING_TO_JSVAL(uri);
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
         ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL,
-                                type, 2, Valueify(argv));
+                                2, Valueify(argv));
         if (!ns)
             return NULL;
         match = ns;
     }
     return match;
 }
 
 static JSString *
@@ -2854,17 +2851,16 @@ js_IsFunctionQName(JSContext *cx, JSObje
 }
 
 static JSObject *
 ToXMLName(JSContext *cx, jsval v, jsid *funidp)
 {
     JSAtom *atomizedName;
     JSString *name;
     JSObject *obj;
-    TypeObject *type;
     Class *clasp;
     uint32 index;
 
     if (JSVAL_IS_STRING(v)) {
         name = JSVAL_TO_STRING(v);
     } else {
         if (JSVAL_IS_PRIMITIVE(v)) {
             ReportBadXMLName(cx, Valueify(v));
@@ -2909,18 +2905,17 @@ ToXMLName(JSContext *cx, jsval v, jsid *
         if (!name)
             return NULL;
         *funidp = JSID_VOID;
         return ToAttributeName(cx, STRING_TO_JSVAL(name));
     }
 
 construct:
     v = STRING_TO_JSVAL(name);
-    type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    obj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, type, 1, Valueify(&v));
+    obj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&v));
     if (!obj)
         return NULL;
 
 out:
     if (!IsFunctionQName(cx, obj, funidp))
         return NULL;
     return obj;
 
@@ -5776,18 +5771,17 @@ FindInScopeNamespaces(JSContext *cx, JSX
 
 /*
  * Populate a new JS array with elements of array and place the result into
  * rval.  rval must point to a rooted location.
  */
 static bool
 NamespacesToJSArray(JSContext *cx, JSXMLArray *array, jsval *rval)
 {
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    JSObject *arrayobj = js_NewArrayObject(cx, 0, NULL, type);
+    JSObject *arrayobj = js_NewArrayObject(cx, 0, NULL);
     if (!arrayobj)
         return false;
     *rval = OBJECT_TO_JSVAL(arrayobj);
 
     AutoValueRooter tvr(cx);
     for (uint32 i = 0, n = array->length; i < n; i++) {
         JSObject *ns = XMLARRAY_MEMBER(array, i, JSObject);
         if (!ns)
@@ -6455,18 +6449,17 @@ xml_setName(JSContext *cx, uintN argc, j
         name = vp[2];
         if (!JSVAL_IS_PRIMITIVE(name) &&
             JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass &&
             !GetURI(nameqn = JSVAL_TO_OBJECT(name))) {
             name = vp[2] = nameqn->getQNameLocalName();
         }
     }
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    nameqn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, type, 1, Valueify(&name));
+    nameqn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&name));
     if (!nameqn)
         return JS_FALSE;
 
     /* ECMA-357 13.4.4.35 Step 4. */
     if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION)
         nameqn->setNameURI(STRING_TO_JSVAL(cx->runtime->emptyString));
 
     xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
@@ -6558,28 +6551,26 @@ xml_setNamespace(JSContext *cx, uintN ar
     NON_LIST_XML_METHOD_PROLOG;
     if (!JSXML_HAS_NAME(xml))
         return JS_TRUE;
 
     xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
     if (!xml)
         return JS_FALSE;
 
-    TypeObject *nstype = cx->getFixedTypeObject(TYPE_OBJECT_XML);
     ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj,
-                            nstype, argc == 0 ? 0 : 1, Valueify(vp + 2));
+                            argc == 0 ? 0 : 1, Valueify(vp + 2));
     if (!ns)
         return JS_FALSE;
     vp[0] = OBJECT_TO_JSVAL(ns);
     ns->setNamespaceDeclared(JSVAL_TRUE);
 
     qnargv[0] = OBJECT_TO_JSVAL(ns);
     qnargv[1] = OBJECT_TO_JSVAL(xml->name);
-    TypeObject *qntype = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    qn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, qntype, 2, Valueify(qnargv));
+    qn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, Valueify(qnargv));
     if (!qn)
         return JS_FALSE;
 
     xml->name = qn;
 
     /*
      * Erratum: the spec fails to update the governing in-scope namespaces.
      * See the erratum noted in xml_setName, above.
@@ -6737,88 +6728,53 @@ xml_toXMLString(JSContext *cx, uintN arg
 /* XML and XMLList */
 static JSBool
 xml_valueOf(JSContext *cx, uintN argc, jsval *vp)
 {
     *vp = JS_THIS(cx, vp);
     return !JSVAL_IS_NULL(*vp);
 }
 
-JS_PUBLIC_API(void)
-type_XMLNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
-{
-#ifdef JS_TYPE_INFERENCE
-    TypeCallsite *site = Valueify(jssite);
-
-    if (site->returnTypes) {
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-        site->returnTypes->addType(cx, (types::jstype) type);
-    }
-#endif
-}
-
-JS_PUBLIC_API(void)
-type_XMLSettings(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
-{
-#ifdef JS_TYPE_INFERENCE
-    TypeCallsite *site = Valueify(jssite);
-
-    if (site->returnTypes) {
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML_SETTINGS);
-        site->returnTypes->addType(cx, (types::jstype) type);
-    }
-#endif
-}
-
-// function returns an XML object if found, null or void (sometimes both possible) if not found.
-JS_PUBLIC_API(void)
-type_XMLOptional(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
-{
-    type_XMLNew(cx, jsfun, jssite);
-    JS_TypeHandlerNull(cx, jsfun, jssite);
-    JS_TypeHandlerVoid(cx, jsfun, jssite);
-}
-
 static JSFunctionSpec xml_methods[] = {
     JS_FN_TYPE("addNamespace",          xml_addNamespace,          1,0, JS_TypeHandlerThis),
     JS_FN_TYPE("appendChild",           xml_appendChild,           1,0, JS_TypeHandlerThis),
-    JS_FN_TYPE(js_attribute_str,        xml_attribute,             1,0, type_XMLOptional),
-    JS_FN_TYPE("attributes",            xml_attributes,            0,0, type_XMLOptional),
-    JS_FN_TYPE("child",                 xml_child,                 1,0, type_XMLNew),
+    JS_FN_TYPE(js_attribute_str,        xml_attribute,             1,0, JS_TypeHandlerDynamic),
+    JS_FN_TYPE("attributes",            xml_attributes,            0,0, JS_TypeHandlerDynamic),
+    JS_FN_TYPE("child",                 xml_child,                 1,0, JS_TypeHandlerDynamic),
     JS_FN_TYPE("childIndex",            xml_childIndex,            0,0, JS_TypeHandlerInt),
-    JS_FN_TYPE("children",              xml_children,              0,0, type_XMLNew),
-    JS_FN_TYPE("comments",              xml_comments,              0,0, type_XMLNew),
+    JS_FN_TYPE("children",              xml_children,              0,0, JS_TypeHandlerDynamic),
+    JS_FN_TYPE("comments",              xml_comments,              0,0, JS_TypeHandlerDynamic),
     JS_FN_TYPE("contains",              xml_contains,              1,0, JS_TypeHandlerBool),
     JS_FN_TYPE("copy",                  xml_copy,                  0,0, JS_TypeHandlerThis),
-    JS_FN_TYPE("descendants",           xml_descendants,           1,0, type_XMLNew),
-    JS_FN_TYPE("elements",              xml_elements,              1,0, type_XMLNew),
+    JS_FN_TYPE("descendants",           xml_descendants,           1,0, JS_TypeHandlerDynamic),
+    JS_FN_TYPE("elements",              xml_elements,              1,0, JS_TypeHandlerDynamic),
     JS_FN_TYPE("hasOwnProperty",        xml_hasOwnProperty,        1,0, JS_TypeHandlerBool),
     JS_FN_TYPE("hasComplexContent",     xml_hasComplexContent,     1,0, JS_TypeHandlerBool),
     JS_FN_TYPE("hasSimpleContent",      xml_hasSimpleContent,      1,0, JS_TypeHandlerBool),
-    JS_FN_TYPE("inScopeNamespaces",     xml_inScopeNamespaces,     0,0, type_XMLNew),
+    JS_FN_TYPE("inScopeNamespaces",     xml_inScopeNamespaces,     0,0, JS_TypeHandlerDynamic),
     JS_FN_TYPE("insertChildAfter",      xml_insertChildAfter,      2,0, JS_TypeHandlerThis),
     JS_FN_TYPE("insertChildBefore",     xml_insertChildBefore,     2,0, JS_TypeHandlerThis),
     JS_FN_TYPE(js_length_str,           xml_length,                0,0, JS_TypeHandlerInt),
     JS_FN_TYPE(js_localName_str,        xml_localName,             0,0, JS_TypeHandlerString),
-    JS_FN_TYPE(js_name_str,             xml_name,                  0,0, type_XMLNew),
-    JS_FN_TYPE(js_namespace_str,        xml_namespace,             1,0, type_XMLNew),
-    JS_FN_TYPE("namespaceDeclarations", xml_namespaceDeclarations, 0,0, type_XMLNew),
+    JS_FN_TYPE(js_name_str,             xml_name,                  0,0, JS_TypeHandlerDynamic),
+    JS_FN_TYPE(js_namespace_str,        xml_namespace,             1,0, JS_TypeHandlerDynamic),
+    JS_FN_TYPE("namespaceDeclarations", xml_namespaceDeclarations, 0,0, JS_TypeHandlerDynamic),
     JS_FN_TYPE("nodeKind",              xml_nodeKind,              0,0, JS_TypeHandlerString),
     JS_FN_TYPE("normalize",             xml_normalize,             0,0, JS_TypeHandlerThis),
-    JS_FN_TYPE(js_xml_parent_str,       xml_parent,                0,0, type_XMLOptional),
-    JS_FN_TYPE("processingInstructions",xml_processingInstructions,1,0, type_XMLNew),
+    JS_FN_TYPE(js_xml_parent_str,       xml_parent,                0,0, JS_TypeHandlerDynamic),
+    JS_FN_TYPE("processingInstructions",xml_processingInstructions,1,0, JS_TypeHandlerDynamic),
     JS_FN_TYPE("prependChild",          xml_prependChild,          1,0, JS_TypeHandlerThis),
     JS_FN_TYPE("propertyIsEnumerable",  xml_propertyIsEnumerable,  1,0, JS_TypeHandlerBool),
     JS_FN_TYPE("removeNamespace",       xml_removeNamespace,       1,0, JS_TypeHandlerThis),
     JS_FN_TYPE("replace",               xml_replace,               2,0, JS_TypeHandlerThis),
     JS_FN_TYPE("setChildren",           xml_setChildren,           1,0, JS_TypeHandlerThis),
     JS_FN_TYPE("setLocalName",          xml_setLocalName,          1,0, JS_TypeHandlerVoid),
     JS_FN_TYPE("setName",               xml_setName,               1,0, JS_TypeHandlerVoid),
     JS_FN_TYPE("setNamespace",          xml_setNamespace,          1,0, JS_TypeHandlerVoid),
-    JS_FN_TYPE(js_text_str,             xml_text,                  0,0, type_XMLNew),
+    JS_FN_TYPE(js_text_str,             xml_text,                  0,0, JS_TypeHandlerDynamic),
     JS_FN_TYPE(js_toSource_str,         xml_toSource,              0,0, JS_TypeHandlerString),
     JS_FN_TYPE(js_toString_str,         xml_toString,              0,0, JS_TypeHandlerString),
     JS_FN_TYPE(js_toXMLString_str,      xml_toXMLString,           0,0, JS_TypeHandlerString),
     JS_FN_TYPE(js_valueOf_str,          xml_valueOf,               0,0, JS_TypeHandlerThis),
     JS_FS_END
 };
 
 static JSBool
@@ -6865,18 +6821,17 @@ SetDefaultXMLSettings(JSContext *cx, JSO
 }
 
 static JSBool
 xml_settings(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *settings;
     JSObject *obj;
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML_SETTINGS);
-    settings = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL, type);
+    settings = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
     if (!settings)
         return JS_FALSE;
     *vp = OBJECT_TO_JSVAL(settings);
     obj = JS_THIS_OBJECT(cx, vp);
     return obj && CopyXMLSettings(cx, obj, settings);
 }
 
 static JSBool
@@ -6912,19 +6867,19 @@ xml_defaultSettings(JSContext *cx, uintN
     settings = JS_NewObject(cx, NULL, NULL, NULL);
     if (!settings)
         return JS_FALSE;
     *vp = OBJECT_TO_JSVAL(settings);
     return SetDefaultXMLSettings(cx, settings);
 }
 
 static JSFunctionSpec xml_static_methods[] = {
-    JS_FN_TYPE("settings",         xml_settings,          0,0, type_XMLSettings),
+    JS_FN_TYPE("settings",         xml_settings,          0,0, JS_TypeHandlerDynamic),
     JS_FN_TYPE("setSettings",      xml_setSettings,       1,0, JS_TypeHandlerVoid),
-    JS_FN_TYPE("defaultSettings",  xml_defaultSettings,   0,0, type_XMLSettings),
+    JS_FN_TYPE("defaultSettings",  xml_defaultSettings,   0,0, JS_TypeHandlerDynamic),
     JS_FS_END
 };
 
 static JSBool
 XML(JSContext *cx, uintN argc, Value *vp)
 {
     JSXML *xml, *copy;
     JSObject *xobj, *vobj;
@@ -7088,18 +7043,17 @@ js_NewXMLObject(JSContext *cx, JSXMLClas
 
     AutoXMLRooter root(cx, xml);
     return js_GetXMLObject(cx, xml);
 }
 
 static JSObject *
 NewXMLObject(JSContext *cx, JSXML *xml)
 {
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_XMLClass, NULL, NULL, type);
+    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_XMLClass, NULL, NULL);
     if (!obj)
         return NULL;
     obj->setPrivate(xml);
     METER(xml_stats.xmlobj);
     return obj;
 }
 
 JSObject *
@@ -7118,36 +7072,32 @@ js_GetXMLObject(JSContext *cx, JSXML *xm
         return NULL;
     xml->object = obj;
     return obj;
 }
 
 JSObject *
 js_InitNamespaceClass(JSContext *cx, JSObject *obj)
 {
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    TypeObject *arrayType = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    cx->addTypeProperty(arrayType, NULL, (js::types::jstype) type);
-
     /* :FIXME: handler is broken here and below when called with other object as 'this'. */
-    return js_InitClass(cx, obj, NULL, &js_NamespaceClass, Namespace, 2, type_XMLNew,
+    return js_InitClass(cx, obj, NULL, &js_NamespaceClass, Namespace, 2, JS_TypeHandlerDynamic,
                         namespace_props, namespace_methods, NULL, NULL);
 }
 
 JSObject *
 js_InitQNameClass(JSContext *cx, JSObject *obj)
 {
-    return js_InitClass(cx, obj, NULL, &js_QNameClass, QName, 2, type_XMLNew,
+    return js_InitClass(cx, obj, NULL, &js_QNameClass, QName, 2, JS_TypeHandlerDynamic,
                         qname_props, qname_methods, NULL, NULL);
 }
 
 JSObject *
 js_InitAttributeNameClass(JSContext *cx, JSObject *obj)
 {
-    return js_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2, type_XMLNew,
+    return js_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2, JS_TypeHandlerDynamic,
                         qname_props, qname_methods, NULL, NULL);
 }
 
 JSObject *
 js_InitAnyNameClass(JSContext *cx, JSObject *obj)
 {
     jsid id;
 
@@ -7167,17 +7117,17 @@ js_InitXMLClass(JSContext *cx, JSObject 
     jsval cval, vp[3];
 
     /* Define the isXMLName function. */
     if (!JS_DefineFunctionWithType(cx, obj, js_isXMLName_str, xml_isXMLName, 1, 0,
                                    JS_TypeHandlerBool, js_isXMLName_str))
         return NULL;
 
     /* Define the XML class constructor and prototype. */
-    proto = js_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1, type_XMLNew,
+    proto = js_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1, JS_TypeHandlerDynamic,
                          NULL, xml_methods,
                          xml_static_props, xml_static_methods);
     if (!proto)
         return NULL;
 
     xml = js_NewXML(cx, JSXML_CLASS_TEXT);
     if (!xml)
         return NULL;
@@ -7203,30 +7153,26 @@ js_InitXMLClass(JSContext *cx, JSObject 
 
     /* Set default settings. */
     vp[0] = JSVAL_NULL;
     vp[1] = cval;
     vp[2] = JSVAL_VOID;
     if (!xml_setSettings(cx, 1, vp))
         return NULL;
 
-    cx->markTypeBuiltinFunction(cx->getTypeFunction(js_XMLList_str));
-
     /* Define the XMLList function and give it the same prototype as XML. */
     fun = JS_DefineFunctionWithType(cx, obj, js_XMLList_str, XMLList, 1, JSFUN_CONSTRUCTOR,
-                                    type_XMLNew, js_XMLList_str);
+                                    JS_TypeHandlerDynamic, js_XMLList_str);
     if (!fun)
         return NULL;
     if (!js_SetClassPrototype(cx, FUN_OBJECT(fun), proto,
                               JSPROP_READONLY | JSPROP_PERMANENT)) {
         return NULL;
     }
 
-    cx->setTypeFunctionPrototype(fun->getTypeObject(), proto->getTypeObject());
-
     return proto;
 }
 
 JSObject *
 js_InitXMLClasses(JSContext *cx, JSObject *obj)
 {
     if (!js_InitNamespaceClass(cx, obj))
         return NULL;
@@ -7255,17 +7201,17 @@ js_GetFunctionNamespace(JSContext *cx, V
             return false;
 
         /*
          * Avoid entraining any in-scope Object.prototype.  The loss of
          * Namespace.prototype is not detectable, as there is no way to
          * refer to this instance in scripts.  When used to qualify method
          * names, its prefix and uri references are copied to the QName.
          */
-        obj->clearProto();
+        obj->clearType(cx);
         obj->clearParent();
 
         cx->compartment->functionNamespaceObject = obj;
     }
     vp->setObject(*obj);
 
     return true;
 }
@@ -7302,18 +7248,17 @@ js_GetDefaultXMLNamespace(JSContext *cx,
             return JS_FALSE;
         if (!JSVAL_IS_PRIMITIVE(v)) {
             *vp = v;
             return JS_TRUE;
         }
         obj = tmp;
     }
 
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj, type, 0, NULL);
+    ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj, 0, NULL);
     if (!ns)
         return JS_FALSE;
     v = OBJECT_TO_JSVAL(ns);
     if (!obj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(v),
                              PropertyStub, PropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
     }
     *vp = v;
@@ -7321,18 +7266,17 @@ js_GetDefaultXMLNamespace(JSContext *cx,
 }
 
 JSBool
 js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
 {
     Value argv[2];
     argv[0].setString(cx->runtime->emptyString);
     argv[1] = v;
-    TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-    JSObject *ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, type, 2, argv);
+    JSObject *ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv);
     if (!ns)
         return JS_FALSE;
 
     JSStackFrame *fp = js_GetTopStackFrame(cx);
     JSObject &varobj = fp->varobj(cx);
     if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
                                PropertyStub, PropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
@@ -7414,18 +7358,17 @@ JSBool
 js_GetAnyName(JSContext *cx, jsid *idp)
 {
     JSObject *obj;
 
     obj = cx->compartment->anynameObject;
     if (!obj) {
         JSRuntime *rt = cx->runtime;
 
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-        obj = NewNonFunction<WithProto::Given>(cx, &js_AnyNameClass, NULL, NULL, type);
+        obj = NewNonFunction<WithProto::Given>(cx, &js_AnyNameClass, NULL, NULL);
         if (!obj)
             return false;
 
         InitXMLQName(obj, rt->emptyString, rt->emptyString,
                      ATOM_TO_STRING(rt->atomState.starAtom));
         METER(xml_stats.qname);
 
         /*
@@ -7460,19 +7403,18 @@ js_FindXMLProperty(JSContext *cx, const 
     JSXML *xml;
     JSBool found;
     JSProperty *prop;
 
     JS_ASSERT(nameval.isObject());
     nameobj = &nameval.toObject();
     if (nameobj->getClass() == &js_AnyNameClass) {
         v = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom);
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
         nameobj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL,
-                                     type, 1, Valueify(&v));
+                                     1, Valueify(&v));
         if (!nameobj)
             return JS_FALSE;
     } else {
         JS_ASSERT(nameobj->getClass() == &js_AttributeNameClass ||
                   nameobj->getClass() == &js_QNameClass);
     }
 
     qn = nameobj;
@@ -7696,18 +7638,17 @@ js_StepXMLListFilter(JSContext *cx, JSBo
              * as it may be the only root holding xml.
              */
             sp[-1] = OBJECT_TO_JSVAL(obj);
             list = (JSXML *) obj->getPrivate();
             if (!Append(cx, list, xml))
                 return JS_FALSE;
         }
 
-        TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_XML);
-        filterobj = NewNonFunction<WithProto::Given>(cx, &js_XMLFilterClass, NULL, NULL, type);
+        filterobj = NewNonFunction<WithProto::Given>(cx, &js_XMLFilterClass, NULL, NULL);
         if (!filterobj)
             return JS_FALSE;
 
         /*
          * Init all filter fields before setPrivate exposes it to
          * xmlfilter_trace or xmlfilter_finalize.
          */
         filter = cx->create<JSXMLFilter>(list, &list->xml_kids);
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -4324,31 +4324,34 @@ mjit::Compiler::iter(uintN flags)
     /* Compare shape of object with iterator. */
     masm.loadShape(reg, T1);
     masm.loadPtr(Address(nireg, offsetof(NativeIterator, shapes_array)), T2);
     masm.load32(Address(T2, 0), T2);
     Jump mismatchedObject = masm.branch32(Assembler::NotEqual, T1, T2);
     stubcc.linkExit(mismatchedObject, Uses(1));
 
     /* Compare shape of object's prototype with iterator. */
-    masm.loadPtr(Address(reg, offsetof(JSObject, proto)), T1);
+    masm.loadPtr(Address(reg, offsetof(JSObject, type)), T1);
+    masm.loadPtr(Address(T1, offsetof(types::TypeObject, proto)), T1);
     masm.loadShape(T1, T1);
     masm.loadPtr(Address(nireg, offsetof(NativeIterator, shapes_array)), T2);
     masm.load32(Address(T2, sizeof(uint32)), T2);
     Jump mismatchedProto = masm.branch32(Assembler::NotEqual, T1, T2);
     stubcc.linkExit(mismatchedProto, Uses(1));
 
     /*
      * Compare object's prototype's prototype with NULL. The last native
      * iterator will always have a prototype chain length of one
      * (i.e. it must be a plain object), so we do not need to generate
      * a loop here.
      */
-    masm.loadPtr(Address(reg, offsetof(JSObject, proto)), T1);
-    masm.loadPtr(Address(T1, offsetof(JSObject, proto)), T1);
+    masm.loadPtr(Address(reg, offsetof(JSObject, type)), T1);
+    masm.loadPtr(Address(T1, offsetof(types::TypeObject, proto)), T1);
+    masm.loadPtr(Address(T1, offsetof(JSObject, type)), T1);
+    masm.loadPtr(Address(T1, offsetof(types::TypeObject, proto)), T1);
     Jump overlongChain = masm.branchPtr(Assembler::NonZero, T1, T1);
     stubcc.linkExit(overlongChain, Uses(1));
 
     /* Found a match with the most recent iterator. Hooray! */
 
     /* Mark iterator as active. */
     masm.load32(flagsAddr, T1);
     masm.or32(Imm32(JSITER_ACTIVE), T1);
@@ -4899,21 +4902,21 @@ mjit::Compiler::jsop_instanceof()
     obj = frame.copyDataIntoReg(lhs);
     RegisterID proto = frame.copyDataIntoReg(rhs);
     RegisterID temp = frame.allocReg();
 
     MaybeJump isFalse;
     if (!lhs->isTypeKnown())
         isFalse = frame.testPrimitive(Assembler::Equal, lhs);
 
-    Address protoAddr(obj, offsetof(JSObject, proto));
     Label loop = masm.label();
 
     /* Walk prototype chain, break out on NULL or hit. */
-    masm.loadPayload(protoAddr, obj);
+    masm.loadPtr(Address(obj, offsetof(JSObject, type)), obj);
+    masm.loadPtr(Address(obj, offsetof(types::TypeObject, proto)), obj);
     Jump isFalse2 = masm.branchTestPtr(Assembler::Zero, obj, obj);
     Jump isTrue = masm.branchPtr(Assembler::NotEqual, obj, proto);
     isTrue.linkTo(loop, &masm);
     masm.move(Imm32(1), temp);
     isTrue = masm.jump();
 
     if (isFalse.isSet())
         isFalse.getJump().linkTo(masm.label(), &masm);
@@ -5455,17 +5458,23 @@ mjit::Compiler::knownPoppedObjectKind(ui
 #endif
     return types::OBJECT_UNKNOWN;
 }
 
 bool
 mjit::Compiler::arrayPrototypeHasIndexedProperty()
 {
 #ifdef JS_TYPE_INFERENCE
-    types::TypeSet *arrayTypes =
-        cx->getFixedTypeObject(types::TYPE_OBJECT_ARRAY_PROTOTYPE)->getProperty(cx, JSID_VOID, false);
-    types::TypeSet *objectTypes =
-        cx->getFixedTypeObject(types::TYPE_OBJECT_OBJECT_PROTOTYPE)->getProperty(cx, JSID_VOID, false);
+    /*
+     * Get the types of Array.prototype and Object.prototype to use. :XXX: This is broken
+     * in the presence of multiple global objects, we should figure out the possible
+     * prototype(s) from the objects in the type set that triggered this call.
+     */
+    JSObject *proto;
+    if (!js_GetClassPrototype(cx, NULL, JSProto_Array, &proto, NULL))
+        return false;
+    types::TypeSet *arrayTypes = proto->getType()->getProperty(cx, JSID_VOID, false);
+    types::TypeSet *objectTypes = proto->getProto()->getType()->getProperty(cx, JSID_VOID, false);
     return arrayTypes->knownNonEmpty(cx, script)
         || objectTypes->knownNonEmpty(cx, script);
 #endif
     return true;
 }
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -318,17 +318,18 @@ class SetPropCompiler : public PICStubCo
         if (adding) {
             JS_ASSERT(shape->hasSlot());
             pic.shapeRegHasBaseShape = false;
 
             /* Emit shape guards for the object's prototype chain. */
             JSObject *proto = obj->getProto();
             RegisterID lastReg = pic.objReg;
             while (proto) {
-                masm.loadPtr(Address(lastReg, offsetof(JSObject, proto)), pic.shapeReg);
+                masm.loadPtr(Address(lastReg, offsetof(JSObject, type)), pic.shapeReg);
+                masm.loadPtr(Address(pic.shapeReg, offsetof(types::TypeObject, proto)), pic.shapeReg);
                 Jump protoGuard = masm.guardShape(pic.shapeReg, proto);
                 if (!otherGuards.append(protoGuard))
                     return error();
 
                 proto = proto->getProto();
                 lastReg = pic.shapeReg;
             }
 
@@ -2333,17 +2334,17 @@ ic::GetElement(VMFrame &f, ic::GetElemen
             return;
         }
     }
 
     if (!obj->getProperty(cx, id, &f.regs.sp[-2]))
         THROW();
     if (f.regs.sp[-2].isUndefined()) {
         if (idval.isInt32())
-            cx->addTypeProperty(obj->getTypeObject(), NULL, types::TYPE_UNDEFINED);
+            cx->addTypeProperty(obj->getType(), NULL, types::TYPE_UNDEFINED);
         f.script()->typeMonitorUndefined(cx, f.regs.pc, 0);
     }
 }
 
 #define APPLY_STRICTNESS(f, s)                          \
     (FunctionTemplateConditional(s, f<true>, f<false>))
 
 LookupStatus
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -512,17 +512,17 @@ stubs::GetElem(VMFrame &f)
     if (!obj->getProperty(cx, id, &rval))
         THROW();
     copyFrom = &rval;
 
   end_getelem:
     f.regs.sp[-2] = *copyFrom;
     if (copyFrom->isUndefined() || !rref.isInt32()) {
         if (rref.isInt32())
-            cx->addTypeProperty(obj->getTypeObject(), NULL, TYPE_UNDEFINED);
+            cx->addTypeProperty(obj->getType(), NULL, TYPE_UNDEFINED);
         f.script()->typeMonitorResult(cx, regs.pc, 0, *copyFrom);
     }
 }
 
 static inline bool
 FetchElementId(VMFrame &f, JSObject *obj, const Value &idval, jsid &id, Value *vp)
 {
     int32_t i_;
@@ -1402,38 +1402,39 @@ stubs::Neg(VMFrame &f)
         f.script()->typeMonitorOverflow(f.cx, f.regs.pc, 0);
 }
 
 JSObject * JS_FASTCALL
 stubs::NewInitArray(VMFrame &f, uint32 count)
 {
     JSContext *cx = f.cx;
 
-    TypeObject *type = (TypeObject *) f.scratch;
     gc::FinalizeKind kind = GuessObjectGCKind(count, true);
-
-    JSObject *obj = NewArrayWithKind(cx, type, kind);
+    JSObject *obj = NewArrayWithKind(cx, kind);
     if (!obj || !obj->ensureSlots(cx, count))
         THROWV(NULL);
 
+    TypeObject *type = (TypeObject *) f.scratch;
+    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, type, kind);
+        JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
             THROWV(NULL);
+        obj->setType(type);
         return obj;
     }
 
     JSObject *obj = CopyInitializerObject(cx, baseobj, type);
 
     if (!obj)
         THROWV(NULL);
     return obj;
@@ -1704,17 +1705,17 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid
             ref.setNumber(d);
             d += N;
         } else {
             d += N;
             ref.setNumber(d);
         }
         if (!v.setNumber(d)) {
             f.script()->typeMonitorOverflow(cx, f.regs.pc, 0);
-            cx->addTypePropertyId(obj->getTypeObject(), id, TYPE_DOUBLE);
+            cx->addTypePropertyId(obj->getType(), id, TYPE_DOUBLE);
         }
         f.script()->typeMonitorAssign(cx, f.regs.pc, obj, id, v);
         fp->setAssigning();
         JSBool ok = obj->setProperty(cx, id, &v, strict);
         fp->clearAssigning();
         if (!ok)
             return false;
     }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -731,18 +731,17 @@ ProcessArgs(JSContext *cx, JSObject *obj
           default:;
         }
     }
 
     /*
      * Create arguments early and define it to root it, so it's safe from any
      * GC calls nested below, and so it is available to -f <file> arguments.
      */
-    js::types::TypeObject *argstype = cx->getFixedTypeObject(js::types::TYPE_OBJECT_ARGUMENTS);
-    argsObj = js_NewArrayObject(cx, 0, NULL, argstype);
+    argsObj = js_NewArrayObject(cx, 0, NULL);
     if (!argsObj)
         return 1;
 
     if (!JS_DefinePropertyWithType(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj),
                                    NULL, NULL, 0)) {
         return 1;
     }
 
--- a/js/src/tracejit/Writer.cpp
+++ b/js/src/tracejit/Writer.cpp
@@ -36,16 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "jsprf.h"
 #include "jstl.h"
 #include "Writer.h"
 #include "nanojit.h"
+#include "jsobjinlines.h"
 
 namespace js {
 namespace tjit {
 
 using namespace nanojit;
 
 class FuncFilter : public LirWriter
 {
@@ -282,17 +283,19 @@ isConstPrivatePtr(LIns *ins, unsigned sl
  * annotations on calls cannot be checked here;  in some cases they can be
  * partially checked via assertions (eg. by checking that certain values
  * are not changed by the function).
  */
 void ValidateWriter::checkAccSet(LOpcode op, LIns *base, int32_t disp, AccSet accSet)
 {
     bool ok;
 
-    NanoAssert(accSet != ACCSET_NONE);
+    // accesses to ACCSET_NONE are on immutable state
+    if (accSet == ACCSET_NONE)
+        return;
 
     #define dispWithin(Struct) \
         (0 <= disp && disp < int32_t(sizeof(Struct)))
 
     switch (accSet) {
       case ACCSET_STATE:
         // base = paramp 0 0
         // ins  = {ld,st}X.state base[<disp within TracerState>]
@@ -388,18 +391,18 @@ void ValidateWriter::checkAccSet(LOpcode
       case ACCSET_OBJ_FLAGS:
         ok = OK_OBJ_FIELD(LIR_ldi, flags);
         break;
 
       case ACCSET_OBJ_SHAPE:
         ok = OK_OBJ_FIELD(LIR_ldi, objShape);
         break;
 
-      case ACCSET_OBJ_PROTO:
-        ok = OK_OBJ_FIELD(LIR_ldp, proto);
+      case ACCSET_OBJ_TYPE:
+        ok = OK_OBJ_FIELD(LIR_ldp, type);
         break;
 
       case ACCSET_OBJ_PARENT:
         ok = OK_OBJ_FIELD(LIR_ldp, parent);
         break;
 
       case ACCSET_OBJ_PRIVATE:
         // base = <JSObject>
--- a/js/src/tracejit/Writer.h
+++ b/js/src/tracejit/Writer.h
@@ -106,17 +106,17 @@ enum LC_TMBits {
  * - ACCSET_ALLOC:         All memory blocks allocated with LIR_allocp (in
  *                         other words, this region is the AR space).
  * - ACCSET_FRAMEREGS:     All JSFrameRegs structs.
  * - ACCSET_STACKFRAME:    All JSStackFrame objects.
  * - ACCSET_RUNTIME:       The JSRuntime object.
  * - ACCSET_OBJ_CLASP:     The 'clasp'    field of all JSObjects.
  * - ACCSET_OBJ_FLAGS:     The 'flags'    field of all JSObjects.
  * - ACCSET_OBJ_SHAPE:     The 'shape'    field of all JSObjects.
- * - ACCSET_OBJ_PROTO:     The 'proto'    field of all JSObjects.
+ * - ACCSET_OBJ_TYPE:      The 'type'     field of all JSObjects.
  * - ACCSET_OBJ_PARENT:    The 'parent'   field of all JSObjects.
  * - ACCSET_OBJ_PRIVATE:   The 'private'  field of all JSObjects.
  * - ACCSET_OBJ_CAPACITY:  The 'capacity' or 'initializedLength' field of all JSObjects.
  * - ACCSET_OBJ_SLOTS:     The 'slots'    field of all JSObjects.
  * - ACCSET_SLOTS:         The slots (be they fixed or dynamic) of all JSObjects.
  * - ACCSET_TARRAY:        All TypedArray structs.
  * - ACCSET_TARRAY_DATA:   All TypedArray data arrays.
  * - ACCSET_ITER:          All NativeIterator structs.
@@ -136,17 +136,17 @@ static const nanojit::AccSet ACCSET_ALLO
 static const nanojit::AccSet ACCSET_FRAMEREGS     = (1 <<  6);
 static const nanojit::AccSet ACCSET_STACKFRAME    = (1 <<  7);
 static const nanojit::AccSet ACCSET_RUNTIME       = (1 <<  8);
 
 // Nb: JSObject::{lastProp,map,flags} don't have an AccSet because they are never accessed on trace
 static const nanojit::AccSet ACCSET_OBJ_CLASP     = (1 <<  9);
 static const nanojit::AccSet ACCSET_OBJ_FLAGS     = (1 << 10);
 static const nanojit::AccSet ACCSET_OBJ_SHAPE     = (1 << 11);
-static const nanojit::AccSet ACCSET_OBJ_PROTO     = (1 << 12);
+static const nanojit::AccSet ACCSET_OBJ_TYPE      = (1 << 12);
 static const nanojit::AccSet ACCSET_OBJ_PARENT    = (1 << 13);
 static const nanojit::AccSet ACCSET_OBJ_PRIVATE   = (1 << 14);
 static const nanojit::AccSet ACCSET_OBJ_CAPACITY  = (1 << 15);
 static const nanojit::AccSet ACCSET_OBJ_SLOTS     = (1 << 16);  // the pointer to the slots
 
 static const nanojit::AccSet ACCSET_SLOTS         = (1 << 17);  // the slots themselves
 static const nanojit::AccSet ACCSET_TARRAY        = (1 << 18);
 static const nanojit::AccSet ACCSET_TARRAY_DATA   = (1 << 19);
@@ -470,17 +470,19 @@ class Writer
     }
 
     nj::LIns *ldiObjShape(nj::LIns *obj) const {
         return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, objShape), ACCSET_OBJ_SHAPE),
                     "objShape");
     }
 
     nj::LIns *ldpObjProto(nj::LIns *obj) const {
-        return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, proto), ACCSET_OBJ_PROTO),
+        nj::LIns *type = name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, type), ACCSET_OBJ_TYPE),
+                              "type");
+        return name(lir->insLoad(nj::LIR_ldp, type, offsetof(types::TypeObject, proto), 0),
                     "proto");
     }
 
     nj::LIns *ldpObjParent(nj::LIns *obj) const {
         return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, parent), ACCSET_OBJ_PARENT),
                     "parent");
     }