Bug 880041 (part 22) - Use JSObject::{is,as} for JSFunction. r=sfink.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 17 Jun 2013 23:53:49 -0700
changeset 147436 1c6097e5c4d4b758f040f0bcc5e46cc4042a997a
parent 147435 8526023eb2b1bac08d21749ce7dd77aea483902d
child 147437 50e5eb0c40087aad9ee2f8bfef448e1f64fb56fa
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs880041
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 880041 (part 22) - Use JSObject::{is,as} for JSFunction. r=sfink.
caps/src/nsScriptSecurityManager.cpp
js/src/builtin/Eval.cpp
js/src/builtin/Intl.cpp
js/src/builtin/ParallelArray.cpp
js/src/builtin/TestingFunctions.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/SharedContext.h
js/src/gc/Nursery.cpp
js/src/ion/AsmJS.cpp
js/src/ion/AsmJSLink.cpp
js/src/ion/BaselineBailouts.cpp
js/src/ion/BaselineIC.cpp
js/src/ion/CodeGenerator.cpp
js/src/ion/Ion.cpp
js/src/ion/IonBuilder.cpp
js/src/ion/IonCaches.cpp
js/src/ion/IonFrames.cpp
js/src/ion/MCallOptimize.cpp
js/src/ion/MIR.cpp
js/src/ion/MIR.h
js/src/ion/ParallelArrayAnalysis.cpp
js/src/ion/ParallelFunctions.cpp
js/src/ion/VMFunctions.cpp
js/src/jsapi-tests/testLookup.cpp
js/src/jsapi-tests/testOriginPrincipals.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jscntxt.cpp
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsgcinlines.h
js/src/jsinfer.cpp
js/src/jsinferinlines.h
js/src/jsmemorymetrics.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsopcode.cpp
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsscript.cpp
js/src/jsscriptinlines.h
js/src/jsstr.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/ForkJoin.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
js/src/vm/ScopeObject-inl.h
js/src/vm/ScopeObject.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/Stack.cpp
js/src/vm/Stack.h
xpcom/base/CycleCollectedJSRuntime.cpp
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2053,47 +2053,44 @@ nsScriptSecurityManager::old_doGetObject
                                                   bool aAllowShortCircuit)
 {
     NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
     nsIPrincipal* result = nullptr;
 
     JSContext* cx = nsXPConnect::XPConnect()->GetCurrentJSContext();
     JS::RootedObject obj(cx, aObj);
     JS::RootedObject origObj(cx, obj);
-    js::Class *jsClass = js::GetObjectClass(obj);
 
     // A common case seen in this code is that we enter this function
     // with obj being a Function object, whose parent is a Call
     // object. Neither of those have object principals, so we can skip
     // those objects here before we enter the below loop. That way we
     // avoid wasting time checking properties of their classes etc in
     // the loop.
 
-    if (jsClass == &js::FunctionClass) {
+    if (js::IsFunctionObject(obj)) {
         obj = js::GetObjectParent(obj);
 
         if (!obj)
             return nullptr;
 
-        jsClass = js::GetObjectClass(obj);
-
         if (js::IsCallObject(obj)) {
             obj = js::GetObjectParentMaybeScope(obj);
 
             if (!obj)
                 return nullptr;
-
-            jsClass = js::GetObjectClass(obj);
         }
     }
 
+    js::Class *jsClass = js::GetObjectClass(obj);
+
     do {
         // Note: jsClass is set before this loop, and also at the
         // *end* of this loop.
-        
+
         if (IS_WN_CLASS(jsClass)) {
             result = nsXPConnect::XPConnect()->GetPrincipal(obj,
                                                             aAllowShortCircuit);
             if (result) {
                 break;
             }
         } else {
             nsISupports *priv;
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -202,18 +202,18 @@ MarkFunctionsWithinEvalScript(JSScript *
     if (!script->hasObjects())
         return;
 
     ObjectArray *objects = script->objects();
     size_t start = script->innerObjectsStart();
 
     for (size_t i = start; i < objects->length; i++) {
         JSObject *obj = objects->vector[i];
-        if (obj->isFunction()) {
-            JSFunction *fun = obj->toFunction();
+        if (obj->is<JSFunction>()) {
+            JSFunction *fun = &obj->as<JSFunction>();
             if (fun->hasScript())
                 fun->nonLazyScript()->directlyInsideEval = true;
             else if (fun->isInterpretedLazy())
                 fun->lazyScript()->setDirectlyInsideEval();
         }
     }
 }
 
@@ -462,27 +462,28 @@ bool
 js::IsAnyBuiltinEval(JSFunction *fun)
 {
     return fun->maybeNative() == IndirectEval;
 }
 
 JSPrincipals *
 js::PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx)
 {
-    JS_ASSERT(IsAnyBuiltinEval(call.callee().toFunction()) ||
-              IsBuiltinFunctionConstructor(call.callee().toFunction()));
+    JSObject &callee = call.callee();
+    JS_ASSERT(IsAnyBuiltinEval(&callee.as<JSFunction>()) ||
+              IsBuiltinFunctionConstructor(&callee.as<JSFunction>()));
 
     // To compute the principals of the compiled eval/Function code, we simply
     // use the callee's principals. To see why the caller's principals are
     // ignored, consider first that, in the capability-model we assume, the
     // high-privileged eval/Function should never have escaped to the
     // low-privileged caller. (For the Mozilla embedding, this is brute-enforced
     // by explicit filtering by wrappers.) Thus, the caller's privileges should
     // subsume the callee's.
     //
     // In the converse situation, where the callee has lower privileges than the
     // caller, we might initially guess that the caller would want to retain
     // their higher privileges in the generated code. However, since the
     // compiled code will be run with the callee's scope chain, this would make
     // fp->script()->compartment() != fp->compartment().
 
-    return call.callee().compartment()->principals;
+    return callee.compartment()->principals;
 }
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -436,17 +436,17 @@ udat_close(UDateFormat *format)
 static bool
 IntlInitialize(JSContext *cx, HandleObject obj, Handle<PropertyName*> initializer,
                HandleValue locales, HandleValue options)
 {
     RootedValue initializerValue(cx);
     if (!cx->global()->getIntrinsicValue(cx, initializer, &initializerValue))
         return false;
     JS_ASSERT(initializerValue.isObject());
-    JS_ASSERT(initializerValue.toObject().isFunction());
+    JS_ASSERT(initializerValue.toObject().is<JSFunction>());
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, 3, &args))
         return false;
 
     args.setCallee(initializerValue);
     args.setThis(NullValue());
     args[0] = ObjectValue(*obj);
@@ -502,17 +502,17 @@ intl_availableLocales(JSContext *cx, Cou
  */
 static bool
 GetInternals(JSContext *cx, HandleObject obj, MutableHandleObject internals)
 {
     RootedValue getInternalsValue(cx);
     if (!cx->global()->getIntrinsicValue(cx, cx->names().getInternals, &getInternalsValue))
         return false;
     JS_ASSERT(getInternalsValue.isObject());
-    JS_ASSERT(getInternalsValue.toObject().isFunction());
+    JS_ASSERT(getInternalsValue.toObject().is<JSFunction>());
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, 1, &args))
         return false;
 
     args.setCallee(getInternalsValue);
     args.setThis(NullValue());
     args[0] = ObjectValue(*obj);
--- a/js/src/builtin/ParallelArray.cpp
+++ b/js/src/builtin/ParallelArray.cpp
@@ -100,18 +100,18 @@ ParallelArrayObject::construct(JSContext
 
 /* static */ JSFunction *
 ParallelArrayObject::getConstructor(JSContext *cx, unsigned argc)
 {
     RootedPropertyName ctorName(cx, ctorNames[js::Min(argc, NumCtors - 1)]);
     RootedValue ctorValue(cx);
     if (!cx->global()->getIntrinsicValue(cx, ctorName, &ctorValue))
         return NULL;
-    JS_ASSERT(ctorValue.isObject() && ctorValue.toObject().isFunction());
-    return ctorValue.toObject().toFunction();
+    JS_ASSERT(ctorValue.isObject() && ctorValue.toObject().is<JSFunction>());
+    return &ctorValue.toObject().as<JSFunction>();
 }
 
 /*static*/ JSObject *
 ParallelArrayObject::newInstance(JSContext *cx, NewObjectKind newKind /* = GenericObject */)
 {
     gc::AllocKind kind = gc::GetGCObjectKind(NumFixedSlots);
     RootedObject result(cx, NewBuiltinClassInstance(cx, &class_, kind, newKind));
     if (!result)
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -878,23 +878,23 @@ DisableSPSProfiling(JSContext *cx, unsig
         cx->runtime()->spsProfiler.enable(false);
     return true;
 }
 
 static JSBool
 DisplayName(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    if (argc == 0 || !args[0].isObject() || !args[0].toObject().isFunction()) {
+    if (argc == 0 || !args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
         RootedObject arg(cx, &args.callee());
         ReportUsageError(cx, arg, "Must have one function argument");
         return false;
     }
 
-    JSFunction *fun = args[0].toObject().toFunction();
+    JSFunction *fun = &args[0].toObject().as<JSFunction>();
     JSString *str = fun->displayAtom();
     vp->setString(str == NULL ? cx->runtime()->emptyString : str);
     return true;
 }
 
 JSBool
 js::testingFunc_inParallelSection(JSContext *cx, unsigned argc, jsval *vp)
 {
@@ -923,17 +923,17 @@ ShellObjectMetadataCallback(JSContext *c
 
 static JSBool
 SetObjectMetadataCallback(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     args.rval().setUndefined();
 
-    if (argc == 0 || !args[0].isObject() || !args[0].toObject().isFunction()) {
+    if (argc == 0 || !args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
         if (objectMetadataFunction)
             JS_RemoveObjectRoot(cx, &objectMetadataFunction);
         objectMetadataFunction = NULL;
         js::SetObjectMetadataCallback(cx, NULL);
         return true;
     }
 
     if (!objectMetadataFunction && !JS_AddObjectRoot(cx, &objectMetadataFunction))
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -746,25 +746,25 @@ NameNode::dump(int indent)
 }
 #endif
 
 ObjectBox::ObjectBox(JSObject *object, ObjectBox* traceLink)
   : object(object),
     traceLink(traceLink),
     emitLink(NULL)
 {
-    JS_ASSERT(!object->isFunction());
+    JS_ASSERT(!object->is<JSFunction>());
 }
 
 ObjectBox::ObjectBox(JSFunction *function, ObjectBox* traceLink)
   : object(function),
     traceLink(traceLink),
     emitLink(NULL)
 {
-    JS_ASSERT(object->isFunction());
+    JS_ASSERT(object->is<JSFunction>());
     JS_ASSERT(asFunctionBox()->function() == function);
 }
 
 ModuleBox *
 ObjectBox::asModuleBox()
 {
     JS_ASSERT(isModuleBox());
     return static_cast<ModuleBox *>(this);
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -1394,17 +1394,17 @@ ParseNode::isConstant()
 
 class ObjectBox
 {
   public:
     JSObject *object;
 
     ObjectBox(JSObject *object, ObjectBox *traceLink);
     bool isModuleBox() { return object->is<Module>(); }
-    bool isFunctionBox() { return object->isFunction(); }
+    bool isFunctionBox() { return object->is<JSFunction>(); }
     ModuleBox *asModuleBox();
     FunctionBox *asFunctionBox();
     void trace(JSTracer *trc);
 
   protected:
     friend struct CGObjectList;
 
     ObjectBox *traceLink;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2021,17 +2021,17 @@ Parser<SyntaxParseHandler>::finishFuncti
         innerFunctions[i].init(pc->innerFunctions[i]);
 
     if (pc->sc->strict)
         lazy->setStrict();
     if (funbox->usesArguments && funbox->usesApply)
         lazy->setUsesArgumentsAndApply();
     PropagateTransitiveParseFlags(funbox, lazy);
 
-    funbox->object->toFunction()->initLazyScript(lazy);
+    funbox->object->as<JSFunction>().initLazyScript(lazy);
     return true;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
                                               HandlePropertyName funName,
                                               size_t startOffset, FunctionType type,
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -221,17 +221,17 @@ class FunctionBox : public ObjectBox, pu
 
     FunctionContextFlags funCxFlags;
 
     template <typename ParseHandler>
     FunctionBox(JSContext *cx, ObjectBox* traceListHead, JSFunction *fun, ParseContext<ParseHandler> *pc,
                 bool strict);
 
     ObjectBox *toObjectBox() { return this; }
-    JSFunction *function() const { return object->toFunction(); }
+    JSFunction *function() const { return &object->as<JSFunction>(); }
 
     bool isGenerator()              const { return funCxFlags.isGenerator; }
     bool mightAliasLocals()         const { return funCxFlags.mightAliasLocals; }
     bool hasExtensibleScope()       const { return funCxFlags.hasExtensibleScope; }
     bool needsDeclEnvObject()       const { return funCxFlags.needsDeclEnvObject; }
     bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
     bool definitelyNeedsArgsObj()   const { return funCxFlags.definitelyNeedsArgsObj; }
 
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -252,18 +252,18 @@ GetObjectAllocKindForCopy(JSRuntime *rt,
         /* Use minimal size object if we are just going to copy the pointer. */
         if (!IsInsideNursery(rt, (void *)obj->getElementsHeader()))
             return FINALIZE_OBJECT0_BACKGROUND;
 
         size_t nelements = obj->getDenseCapacity();
         return GetBackgroundAllocKind(GetGCArrayKind(nelements));
     }
 
-    if (obj->isFunction())
-        return obj->toFunction()->getAllocKind();
+    if (obj->is<JSFunction>())
+        return obj->as<JSFunction>().getAllocKind();
 
     AllocKind kind = GetGCObjectFixedSlotsKind(obj->numFixedSlots());
     if (CanBeFinalizedInBackground(kind, obj->getClass()))
         kind = GetBackgroundAllocKind(kind);
     return kind;
 }
 
 void *
--- a/js/src/ion/AsmJS.cpp
+++ b/js/src/ion/AsmJS.cpp
@@ -6239,17 +6239,17 @@ IsMaybeWrappedNativeFunction(const Value
 {
     if (!v.isObject())
         return false;
 
     JSObject *obj = CheckedUnwrap(&v.toObject());
     if (!obj)
         return false;
 
-    return obj->isFunction() && obj->toFunction()->maybeNative() == native;
+    return obj->is<JSFunction>() && obj->as<JSFunction>().maybeNative() == native;
 }
 
 JSBool
 js::IsAsmJSModule(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     bool rval = args.hasDefined(0) && IsMaybeWrappedNativeFunction(args[0], LinkAsmJS);
     args.rval().set(BooleanValue(rval));
--- a/js/src/ion/AsmJSLink.cpp
+++ b/js/src/ion/AsmJSLink.cpp
@@ -75,20 +75,20 @@ static bool
 ValidateFFI(JSContext *cx, AsmJSModule::Global &global, HandleValue importVal,
             AutoObjectVector *ffis)
 {
     RootedPropertyName field(cx, global.ffiField());
     RootedValue v(cx);
     if (!GetProperty(cx, importVal, field, &v))
         return false;
 
-    if (!v.isObject() || !v.toObject().isFunction())
+    if (!v.isObject() || !v.toObject().is<JSFunction>())
         return LinkFail(cx, "FFI imports must be functions");
 
-    (*ffis)[global.ffiIndex()] = v.toObject().toFunction();
+    (*ffis)[global.ffiIndex()] = &v.toObject().as<JSFunction>();
     return true;
 }
 
 static bool
 ValidateArrayView(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal,
                   HandleValue bufferVal)
 {
     RootedPropertyName field(cx, global.viewName());
@@ -238,17 +238,17 @@ DynamicallyLinkModule(JSContext *cx, Cal
           case AsmJSModule::Global::Constant:
             if (!ValidateGlobalConstant(cx, global, globalVal))
                 return false;
             break;
         }
     }
 
     for (unsigned i = 0; i < module.numExits(); i++)
-        module.exitIndexToGlobalDatum(i).fun = ffis[module.exit(i).ffiIndex()]->toFunction();
+        module.exitIndexToGlobalDatum(i).fun = &ffis[module.exit(i).ffiIndex()]->as<JSFunction>();
 
     module.setIsLinked(heap);
     return true;
 }
 
 AsmJSActivation::AsmJSActivation(JSContext *cx, const AsmJSModule &module)
   : cx_(cx),
     module_(module),
@@ -282,17 +282,17 @@ AsmJSActivation::~AsmJSActivation()
 
 static const unsigned ASM_MODULE_SLOT = 0;
 static const unsigned ASM_EXPORT_INDEX_SLOT = 1;
 
 extern JSBool
 js::CallAsmJS(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs callArgs = CallArgsFromVp(argc, vp);
-    RootedFunction callee(cx, callArgs.callee().toFunction());
+    RootedFunction callee(cx, &callArgs.callee().as<JSFunction>());
 
     // An asm.js function stores, in its extended slots:
     //  - a pointer to the module from which it was returned
     //  - its index in the ordered list of exported functions
     RootedObject moduleObj(cx, &callee->getExtendedSlot(ASM_MODULE_SLOT).toObject());
     const AsmJSModule &module = AsmJSModuleObjectToModule(moduleObj);
 
     // An exported function points to the code as well as the exported
@@ -467,17 +467,17 @@ SendFunctionsToVTune(JSContext *cx, AsmJ
     return true;
 }
 #endif
 
 JSBool
 js::LinkAsmJS(JSContext *cx, unsigned argc, JS::Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedFunction fun(cx, args.callee().toFunction());
+    RootedFunction fun(cx, &args.callee().as<JSFunction>());
     RootedObject moduleObj(cx, &AsmJSModuleObject(fun));
     AsmJSModule &module = AsmJSModuleObjectToModule(moduleObj);
 
     // If linking fails, recompile the function (including emitting bytecode)
     // as if it's normal JS code.
     if (!DynamicallyLinkModule(cx, args, module)) {
         RootedPropertyName name(cx, fun->name());
         return HandleDynamicLinkFailure(cx, args, module, name);
--- a/js/src/ion/BaselineBailouts.cpp
+++ b/js/src/ion/BaselineBailouts.cpp
@@ -908,18 +908,18 @@ InitFromBailout(JSContext *cx, HandleScr
 
     // Push callee token (must be a JS Function)
     uint32_t calleeStackSlot = exprStackSlots - uint32_t(actualArgc + 2);
     size_t calleeOffset = (builder.framePushed() - endOfBaselineJSFrameStack)
                             + ((exprStackSlots - (calleeStackSlot + 1)) * sizeof(Value));
     Value callee = *builder.valuePointerAtStackOffset(calleeOffset);
     IonSpew(IonSpew_BaselineBailouts, "      CalleeStackSlot=%d", (int) calleeStackSlot);
     IonSpew(IonSpew_BaselineBailouts, "      Callee = %016llx", *((uint64_t *) &callee));
-    JS_ASSERT(callee.isObject() && callee.toObject().isFunction());
-    JSFunction *calleeFun = callee.toObject().toFunction();
+    JS_ASSERT(callee.isObject() && callee.toObject().is<JSFunction>());
+    JSFunction *calleeFun = &callee.toObject().as<JSFunction>();
     if (!builder.writePtr(CalleeToToken(calleeFun), "CalleeToken"))
         return false;
     nextCallee.set(calleeFun);
 
     // Push BaselineStub frame descriptor
     if (!builder.writeWord(baselineStubFrameDescr, "Descriptor"))
         return false;
 
--- a/js/src/ion/BaselineIC.cpp
+++ b/js/src/ion/BaselineIC.cpp
@@ -3284,20 +3284,20 @@ IsCacheableGetPropCall(JSObject *obj, JS
         return false;
 
     if (shape->hasSlot() || shape->hasDefaultGetter())
         return false;
 
     if (!shape->hasGetterValue())
         return false;
 
-    if (!shape->getterValue().isObject() || !shape->getterObject()->isFunction())
+    if (!shape->getterValue().isObject() || !shape->getterObject()->is<JSFunction>())
         return false;
 
-    JSFunction *func = shape->getterObject()->toFunction();
+    JSFunction *func = &shape->getterObject()->as<JSFunction>();
     if (func->isNative()) {
         *isScripted = false;
         return true;
     }
 
     if (!func->hasScript())
         return false;
 
@@ -3399,20 +3399,20 @@ IsCacheableSetPropCall(JSObject *obj, JS
         return false;
 
     if (shape->hasSlot() || shape->hasDefaultSetter())
         return false;
 
     if (!shape->hasSetterValue())
         return false;
 
-    if (!shape->setterValue().isObject() || !shape->setterObject()->isFunction())
+    if (!shape->setterValue().isObject() || !shape->setterObject()->is<JSFunction>())
         return false;
 
-    JSFunction *func = shape->setterObject()->toFunction();
+    JSFunction *func = &shape->setterObject()->as<JSFunction>();
     if (func->isNative()) {
         *isScripted = false;
         return true;
     }
 
     if (!func->hasScript())
         return false;
 
@@ -5292,17 +5292,17 @@ TryAttachNativeGetPropStub(JSContext *cx
         return true;
     }
 
     bool isScripted = false;
     bool cacheableCall = IsCacheableGetPropCall(obj, holder, shape, &isScripted, isDOMProxy);
 
     // Try handling scripted getters.
     if (cacheableCall && isScripted && !isDOMProxy) {
-        RootedFunction callee(cx, shape->getterObject()->toFunction());
+        RootedFunction callee(cx, &shape->getterObject()->as<JSFunction>());
         JS_ASSERT(obj != holder);
         JS_ASSERT(callee->hasScript());
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(NativeObj/ScriptedGetter %s:%d) stub",
                     callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno);
 
         ICGetProp_CallScripted::Compiler compiler(cx, monitorStub, obj, holder, callee,
                                                   pc - script->code);
@@ -5312,17 +5312,17 @@ TryAttachNativeGetPropStub(JSContext *cx
 
         stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     // Try handling JSNative getters.
     if (cacheableCall && !isScripted) {
-        RootedFunction callee(cx, shape->getterObject()->toFunction());
+        RootedFunction callee(cx, &shape->getterObject()->as<JSFunction>());
         JS_ASSERT(obj != holder);
         JS_ASSERT(callee->isNative());
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(%s%s/NativeGetter %p) stub",
                 isDOMProxy ? "DOMProxyObj" : "NativeObj",
                 isDOMProxy && domProxyHasGeneration ? "WithGeneration" : "",
                 callee->native());
 
@@ -6222,17 +6222,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         return true;
     }
 
     bool isScripted = false;
     bool cacheableCall = IsCacheableSetPropCall(obj, holder, shape, &isScripted);
 
     // Try handling scripted setters.
     if (cacheableCall && isScripted) {
-        RootedFunction callee(cx, shape->setterObject()->toFunction());
+        RootedFunction callee(cx, &shape->setterObject()->as<JSFunction>());
         JS_ASSERT(obj != holder);
         JS_ASSERT(callee->hasScript());
 
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObj/ScriptedSetter %s:%d) stub",
                     callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno);
 
         ICSetProp_CallScripted::Compiler compiler(cx, obj, holder, callee, pc - script->code);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
@@ -6241,17 +6241,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
 
         stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     // Try handling JSNative setters.
     if (cacheableCall && !isScripted) {
-        RootedFunction callee(cx, shape->setterObject()->toFunction());
+        RootedFunction callee(cx, &shape->setterObject()->as<JSFunction>());
         JS_ASSERT(obj != holder);
         JS_ASSERT(callee->isNative());
 
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObj/NativeSetter %p) stub",
                     callee->native());
 
         ICSetProp_CallNative::Compiler compiler(cx, obj, holder, callee, pc - script->code);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
@@ -6783,19 +6783,19 @@ ICSetProp_CallNative::Compiler::generate
 
 static bool
 TryAttachFunApplyStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsbytecode *pc,
                       HandleValue thisv, uint32_t argc, Value *argv)
 {
     if (argc != 2)
         return true;
 
-    if (!thisv.isObject() || !thisv.toObject().isFunction())
+    if (!thisv.isObject() || !thisv.toObject().is<JSFunction>())
         return true;
-    RootedFunction target(cx, thisv.toObject().toFunction());
+    RootedFunction target(cx, &thisv.toObject().as<JSFunction>());
 
     // right now, only handle situation where second argument is |arguments|
     if (argv[1].isMagic(JS_OPTIMIZED_ARGUMENTS) && !script->needsArgsObj()) {
         if (target->hasScript() &&
             (target->nonLazyScript()->hasBaselineScript() ||
              target->nonLazyScript()->hasIonScript()) &&
             !stub->hasStub(ICStub::Call_ScriptedApplyArguments))
         {
@@ -6831,20 +6831,20 @@ TryAttachCallStub(JSContext *cx, ICCall_
 
     RootedValue callee(cx, vp[0]);
     RootedValue thisv(cx, vp[1]);
 
     if (!callee.isObject())
         return true;
 
     RootedObject obj(cx, &callee.toObject());
-    if (!obj->isFunction())
+    if (!obj->is<JSFunction>())
         return true;
 
-    RootedFunction fun(cx, obj->toFunction());
+    RootedFunction fun(cx, &obj->as<JSFunction>());
 
     if (fun->hasScript()) {
         // Never attach optimized scripted call stubs for JSOP_FUNAPPLY.
         // MagicArguments may escape the frame through them.
         if (op == JSOP_FUNAPPLY)
             return true;
 
         RootedScript calleeScript(cx, fun->nonLazyScript());
@@ -7076,32 +7076,34 @@ ICCallStubCompiler::guardFunApply(MacroA
     // Load the callee, ensure that it's js_fun_apply
     ValueOperand val = regs.takeAnyValue();
     Address calleeSlot(BaselineStackReg, ICStackValueOffset + (3 * sizeof(Value)));
     masm.loadValue(calleeSlot, val);
 
     masm.branchTestObject(Assembler::NotEqual, val, failure);
     Register callee = masm.extractObject(val, ExtractTemp1);
 
-    masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &FunctionClass, failure);
+    masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &JSFunction::class_,
+                            failure);
     masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
 
     masm.branchPtr(Assembler::NotEqual, callee, ImmWord((void*) js_fun_apply), failure);
 
     // Load the |thisv|, ensure that it's a scripted function with a valid baseline or ion
     // script, or a native function.
     Address thisSlot(BaselineStackReg, ICStackValueOffset + (2 * sizeof(Value)));
     masm.loadValue(thisSlot, val);
 
     masm.branchTestObject(Assembler::NotEqual, val, failure);
     Register target = masm.extractObject(val, ExtractTemp1);
     regs.add(val);
     regs.takeUnchecked(target);
 
-    masm.branchTestObjClass(Assembler::NotEqual, target, regs.getAny(), &FunctionClass, failure);
+    masm.branchTestObjClass(Assembler::NotEqual, target, regs.getAny(), &JSFunction::class_,
+                            failure);
 
     if (checkNative) {
         masm.branchIfInterpreted(target, failure);
     } else {
         masm.branchIfFunctionHasNoScript(target, failure);
         Register temp = regs.takeAny();
         masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), temp);
         masm.loadBaselineOrIonRaw(temp, temp, SequentialExecution, failure);
@@ -7245,17 +7247,18 @@ ICCallScriptedCompiler::generateStubCode
     masm.loadValue(calleeSlot, R1);
     regs.take(R1);
 
     // Ensure callee is an object.
     masm.branchTestObject(Assembler::NotEqual, R1, &failure);
 
     // Ensure callee is a function.
     Register callee = masm.extractObject(R1, ExtractTemp0);
-    masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &FunctionClass, &failure);
+    masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &JSFunction::class_,
+                            &failure);
 
     // If calling a specific script, check if the script matches.  Otherwise, ensure that
     // callee function is scripted.  Leave calleeScript in |callee| reg.
     if (calleeScript_) {
         JS_ASSERT(kind == ICStub::Call_Scripted);
 
         // Callee is a function.  Check if script matches.
         masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -1547,17 +1547,17 @@ CodeGenerator::visitCallGeneric(LCallGen
     // Generate an ArgumentsRectifier.
     IonCompartment *ion = gen->ionCompartment();
     IonCode *argumentsRectifier = ion->getArgumentsRectifier(executionMode);
 
     masm.checkStackAlignment();
 
     // Guard that calleereg is actually a function object.
     masm.loadObjClass(calleereg, nargsreg);
-    masm.cmpPtr(nargsreg, ImmWord(&js::FunctionClass));
+    masm.cmpPtr(nargsreg, ImmWord(&JSFunction::class_));
     if (!bailoutIf(Assembler::NotEqual, call->snapshot()))
         return false;
 
     // Guard that calleereg is an interpreted function with a JSScript:
     masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
 
     // Knowing that calleereg is a non-native function, load the JSScript.
     masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
@@ -1870,17 +1870,17 @@ CodeGenerator::visitApplyArgsGeneric(LAp
     Register copyreg = ToRegister(apply->getTempCopy());
 
     // Holds the function nargs. Initially undefined.
     Register argcreg = ToRegister(apply->getArgc());
 
     // Unless already known, guard that calleereg is actually a function object.
     if (!apply->hasSingleTarget()) {
         masm.loadObjClass(calleereg, objreg);
-        masm.cmpPtr(objreg, ImmWord(&js::FunctionClass));
+        masm.cmpPtr(objreg, ImmWord(&JSFunction::class_));
         if (!bailoutIf(Assembler::NotEqual, apply->snapshot()))
             return false;
     }
 
     // Copy the arguments of the current function.
     emitPushArguments(apply, copyreg);
 
     masm.checkStackAlignment();
@@ -6784,19 +6784,19 @@ CodeGenerator::visitOutOfLineParallelAbo
 bool
 CodeGenerator::visitIsCallable(LIsCallable *ins)
 {
     Register object = ToRegister(ins->object());
     Register output = ToRegister(ins->output());
 
     masm.loadObjClass(object, output);
 
-    // An object is callable iff (isFunction() || getClass()->call).
+    // An object is callable iff (is<JSFunction>() || getClass()->call).
     Label notFunction, done;
-    masm.branchPtr(Assembler::NotEqual, output, ImmWord(&js::FunctionClass), &notFunction);
+    masm.branchPtr(Assembler::NotEqual, output, ImmWord(&JSFunction::class_), &notFunction);
     masm.move32(Imm32(1), output);
     masm.jump(&done);
 
     masm.bind(&notFunction);
     masm.cmpPtr(Address(output, offsetof(js::Class, call)), ImmWord((void *)NULL));
     masm.emitSet(Assembler::NonZero, output);
     masm.bind(&done);
 
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1857,17 +1857,17 @@ ion::SetEnterJitData(JSContext *cx, Ente
 
     if (state.isInvoke()) {
         CallArgs &args = state.asInvoke()->args();
         unsigned numFormals = state.script()->function()->nargs;
         data.constructing = state.asInvoke()->constructing();
         data.numActualArgs = args.length();
         data.maxArgc = Max(args.length(), numFormals) + 1;
         data.scopeChain = NULL;
-        data.calleeToken = CalleeToToken(args.callee().toFunction());
+        data.calleeToken = CalleeToToken(&args.callee().as<JSFunction>());
 
         if (data.numActualArgs >= numFormals) {
             data.maxArgv = args.base() + 1;
         } else {
             // Pad missing arguments with |undefined|.
             for (size_t i = 1; i < args.length() + 2; i++) {
                 if (!vals.append(args.base()[i]))
                     return false;
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -148,20 +148,20 @@ IonBuilder::CFGState::TableSwitch(jsbyte
 
 JSFunction *
 IonBuilder::getSingleCallTarget(types::StackTypeSet *calleeTypes)
 {
     if (!calleeTypes)
         return NULL;
 
     JSObject *obj = calleeTypes->getSingleton();
-    if (!obj || !obj->isFunction())
+    if (!obj || !obj->is<JSFunction>())
         return NULL;
 
-    return obj->toFunction();
+    return &obj->as<JSFunction>();
 }
 
 bool
 IonBuilder::getPolyCallTargets(types::StackTypeSet *calleeTypes,
                                AutoObjectVector &targets,
                                uint32_t maxTargets,
                                bool *gotLambda)
 {
@@ -180,22 +180,25 @@ IonBuilder::getPolyCallTargets(types::St
     if (objCount == 0 || objCount > maxTargets)
         return true;
 
     if (!targets.reserve(objCount))
         return false;
     for(unsigned i = 0; i < objCount; i++) {
         JSObject *obj = calleeTypes->getSingleObject(i);
         if (obj) {
-            if (!obj->isFunction()) {
+            if (!obj->is<JSFunction>()) {
                 targets.clear();
                 return true;
             }
-            if (obj->toFunction()->isInterpreted() && !obj->toFunction()->getOrCreateScript(cx))
+            if (obj->as<JSFunction>().isInterpreted() &&
+                !obj->as<JSFunction>().getOrCreateScript(cx))
+            {
                 return false;
+            }
             DebugOnly<bool> appendOk = targets.append(obj);
             JS_ASSERT(appendOk);
         } else {
             types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
             JS_ASSERT(typeObj);
             if (!typeObj->isFunction() || !typeObj->interpretedFunction) {
                 targets.clear();
                 return true;
@@ -3650,17 +3653,17 @@ IonBuilder::selectInliningTargets(AutoOb
 {
     uint32_t totalSize = 0;
     uint32_t numInlineable = 0;
 
     // For each target, ask whether it may be inlined.
     if (!choiceSet.reserve(targets.length()))
         return false;
     for (size_t i = 0; i < targets.length(); i++) {
-        JSFunction *target = targets[i]->toFunction();
+        JSFunction *target = &targets[i]->as<JSFunction>();
         bool inlineable = makeInliningDecision(target, callInfo);
 
         // Enforce a maximum inlined bytecode limit at the callsite.
         if (inlineable && target->isInterpreted()) {
             totalSize += target->nonLazyScript()->length;
             if (totalSize > js_IonOptions.inlineMaxTotalBytecodeLength)
                 inlineable = false;
         }
@@ -3885,17 +3888,17 @@ IonBuilder::inlineCallsite(AutoObjectVec
     // Is the function provided by an MGetPropertyCache?
     // If so, the cache may be movable to a fallback path, with a dispatch
     // instruction guarding on the incoming TypeObject.
     MGetPropertyCache *propCache = getInlineableGetPropertyCache(callInfo);
 
     // Inline single targets -- unless they derive from a cache, in which case
     // avoiding the cache and guarding is still faster.
     if (!propCache && targets.length() == 1) {
-        JSFunction *target = targets[0]->toFunction();
+        JSFunction *target = &targets[0]->as<JSFunction>();
         if (!makeInliningDecision(target, callInfo))
             return InliningStatus_NotInlined;
 
         // Inlining will elminate uses of the original callee, but it needs to
         // be preserved in phis if we bail out.  Mark the old callee definition as
         // folded to ensure this happens.
         callInfo.fun()->setFoldedUnchecked();
 
@@ -4121,17 +4124,17 @@ IonBuilder::inlineCalls(CallInfo &callIn
     // specialized to the type objects which can generate that inlining target.
     // After inlining the original type set is restored.
     types::StackTypeSet *cacheObjectTypeSet =
         maybeCache ? maybeCache->object()->resultTypeSet() : NULL;
 
     // Inline each of the inlineable targets.
     JS_ASSERT(targets.length() == originals.length());
     for (uint32_t i = 0; i < targets.length(); i++) {
-        JSFunction *target = targets[i]->toFunction();
+        JSFunction *target = &targets[i]->as<JSFunction>();
 
         // Target must be inlineable.
         if (!choiceSet[i])
             continue;
 
         // Target must be reachable by the MDispatchInstruction.
         if (maybeCache && !maybeCache->propTable()->hasFunction(target)) {
             choiceSet[i] = false;
@@ -4140,17 +4143,17 @@ IonBuilder::inlineCalls(CallInfo &callIn
 
         MBasicBlock *inlineBlock = newBlock(dispatchBlock, pc);
         if (!inlineBlock)
             return false;
 
         // Create a function MConstant to use in the entry ResumePoint.
         // Note that guarding is on the original function pointer even
         // if there is a clone, since cloning occurs at the callsite.
-        JSFunction *original = originals[i]->toFunction();
+        JSFunction *original = &originals[i]->as<JSFunction>();
         MConstant *funcDef = MConstant::New(ObjectValue(*original));
         funcDef->setFoldedUnchecked();
         dispatchBlock->add(funcDef);
 
         // Use the MConstant in the inline resume point and on stack.
         int funIndex = inlineBlock->entryResumePoint()->numOperands() - callInfo.numFormals();
         inlineBlock->entryResumePoint()->replaceOperand(funIndex, funcDef);
         inlineBlock->rewriteSlot(funIndex, funcDef);
@@ -4234,17 +4237,17 @@ IonBuilder::inlineCalls(CallInfo &callIn
 
             // If there is only 1 remaining case, we can annotate the fallback call
             // with the target information.
             if (dispatch->numCases() + 1 == originals.length()) {
                 for (uint32_t i = 0; i < originals.length(); i++) {
                     if (choiceSet[i])
                         continue;
 
-                    remaining = targets[i]->toFunction();
+                    remaining = &targets[i]->as<JSFunction>();
                     clonedAtCallsite = targets[i] != originals[i];
                     break;
                 }
             }
 
             if (!inlineGenericFallback(remaining, callInfo, dispatchBlock, clonedAtCallsite))
                 return false;
             dispatch->addFallback(current);
@@ -4476,18 +4479,18 @@ bool
 IonBuilder::anyFunctionIsCloneAtCallsite(types::StackTypeSet *funTypes)
 {
     uint32_t count = funTypes->getObjectCount();
     if (count < 1)
         return false;
 
     for (uint32_t i = 0; i < count; i++) {
         JSObject *obj = funTypes->getSingleObject(i);
-        if (obj->isFunction() && obj->toFunction()->isInterpreted() &&
-            obj->toFunction()->nonLazyScript()->shouldCloneAtCallsite)
+        if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted() &&
+            obj->as<JSFunction>().nonLazyScript()->shouldCloneAtCallsite)
         {
             return true;
         }
     }
     return false;
 }
 
 bool
@@ -4725,17 +4728,17 @@ IonBuilder::jsop_call(uint32_t argc, boo
 
     // If any call targets need to be cloned, clone them. Keep track of the
     // originals as we need to case on them for poly inline.
     bool hasClones = false;
     AutoObjectVector targets(cx);
     RootedFunction fun(cx);
     RootedScript scriptRoot(cx, script());
     for (uint32_t i = 0; i < originals.length(); i++) {
-        fun = originals[i]->toFunction();
+        fun = &originals[i]->as<JSFunction>();
         if (fun->isInterpreted() && fun->nonLazyScript()->shouldCloneAtCallsite) {
             fun = CloneFunctionAtCallsite(cx, fun, scriptRoot, pc);
             if (!fun)
                 return false;
             hasClones = true;
         }
         if (!targets.append(fun))
             return false;
@@ -4753,17 +4756,17 @@ IonBuilder::jsop_call(uint32_t argc, boo
     if (status == InliningStatus_Inlined)
         return true;
     if (status == InliningStatus_Error)
         return false;
 
     // No inline, just make the call.
     RootedFunction target(cx, NULL);
     if (targets.length() == 1)
-        target = targets[0]->toFunction();
+        target = &targets[0]->as<JSFunction>();
 
     return makeCall(target, callInfo, hasClones);
 }
 
 MDefinition *
 IonBuilder::makeCallsiteClone(HandleFunction target, MDefinition *fun)
 {
     // Bake in the clone eagerly if we have a known target. We have arrived here
@@ -7268,17 +7271,17 @@ IonBuilder::TestCommonPropFunc(JSContext
                 return true;
         }
 
         JSObject * curFound = isGetter ? shape->getterObject():
                                          shape->setterObject();
 
         // Save the first seen, or verify uniqueness.
         if (!found) {
-            if (!curFound->isFunction())
+            if (!curFound->is<JSFunction>())
                 return true;
             found = curFound;
         } else if (found != curFound) {
             return true;
         }
 
         // We only support cases with a single prototype shared. This is
         // overwhelmingly more likely than having multiple different prototype
@@ -7378,17 +7381,17 @@ IonBuilder::TestCommonPropFunc(JSContext
                     break;
                 curType = curType->proto->getType(cx);
                 if (!curType)
                     return false;
             }
         }
     }
 
-    *funcp = found->toFunction();
+    *funcp = &found->as<JSFunction>();
     *isDOM = types->isDOMClass();
 
     return true;
 }
 
 bool
 IonBuilder::annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache,
                                     types::StackTypeSet *objTypes, types::StackTypeSet *pushedTypes)
@@ -7439,28 +7442,28 @@ IonBuilder::annotateGetPropertyCache(JSC
         if (protoType->unknownProperties())
             continue;
 
         types::HeapTypeSet *protoTypes = protoType->getProperty(cx, id, false);
         if (!protoTypes)
             return false;
 
         JSObject *obj = protoTypes->getSingleton(cx);
-        if (!obj || !obj->isFunction())
+        if (!obj || !obj->is<JSFunction>())
             continue;
 
         bool knownConstant = false;
         if (!TestSingletonProperty(cx, proto, obj, id, &knownConstant))
             return false;
 
         // Don't add cases corresponding to non-observed pushes
         if (!pushedTypes->hasType(types::Type::ObjectType(obj)))
             continue;
 
-        if (!inlinePropTable->addEntry(typeObj, obj->toFunction()))
+        if (!inlinePropTable->addEntry(typeObj, &obj->as<JSFunction>()))
             return false;
     }
 
     if (inlinePropTable->numEntries() == 0) {
         getPropCache->clearInlinePropertyTable();
         return true;
     }
 
@@ -8466,17 +8469,17 @@ IonBuilder::jsop_instanceof()
     MDefinition *rhs = current->pop();
     MDefinition *obj = current->pop();
 
     // If this is an 'x instanceof function' operation and we can determine the
     // exact function and prototype object being tested for, use a typed path.
     do {
         types::StackTypeSet *rhsTypes = rhs->resultTypeSet();
         JSObject *rhsObject = rhsTypes ? rhsTypes->getSingleton() : NULL;
-        if (!rhsObject || !rhsObject->isFunction() || rhsObject->isBoundFunction())
+        if (!rhsObject || !rhsObject->is<JSFunction>() || rhsObject->isBoundFunction())
             break;
 
         types::TypeObject *rhsType = rhsObject->getType(cx);
         if (!rhsType || rhsType->unknownProperties())
             break;
 
         types::HeapTypeSet *protoTypes =
             rhsType->getProperty(cx, NameToId(cx->names().classPrototype), false);
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -589,18 +589,18 @@ static bool
 IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, Shape *shape)
 {
     if (!shape || !IsCacheableProtoChain(obj, holder))
         return false;
 
     if (!shape->hasGetterValue() || !shape->getterValue().isObject())
         return false;
 
-    return shape->getterValue().toObject().isFunction() &&
-           shape->getterValue().toObject().toFunction()->isNative();
+    return shape->getterValue().toObject().is<JSFunction>() &&
+           shape->getterValue().toObject().as<JSFunction>().isNative();
 }
 
 static bool
 IsCacheableGetPropCallPropertyOp(JSObject *obj, JSObject *holder, Shape *shape)
 {
     if (!shape || !IsCacheableProtoChain(obj, holder))
         return false;
 
@@ -885,18 +885,18 @@ GenerateCallGetter(JSContext *cx, IonScr
     DebugOnly<uint32_t> initialStack = masm.framePushed();
 
     Label success, exception;
 
     attacher.pushStubCodePointer(masm);
 
     if (callNative) {
         JS_ASSERT(shape->hasGetterValue() && shape->getterValue().isObject() &&
-                  shape->getterValue().toObject().isFunction());
-        JSFunction *target = shape->getterValue().toObject().toFunction();
+                  shape->getterValue().toObject().is<JSFunction>());
+        JSFunction *target = &shape->getterValue().toObject().as<JSFunction>();
 
         JS_ASSERT(target);
         JS_ASSERT(target->isNative());
 
         // Native functions have the signature:
         //  bool (*)(JSContext *, unsigned, Value *vp)
         // Where vp[0] is space for an outparam, vp[1] is |this|, and vp[2] onward
         // are the function arguments.
@@ -3048,17 +3048,17 @@ CallsiteCloneIC::attach(JSContext *cx, I
 
 JSObject *
 CallsiteCloneIC::update(JSContext *cx, size_t cacheIndex, HandleObject callee)
 {
     AutoFlushCache afc ("CallsiteCloneCache");
 
     // Act as the identity for functions that are not clone-at-callsite, as we
     // generate this cache as long as some callees are clone-at-callsite.
-    RootedFunction fun(cx, callee->toFunction());
+    RootedFunction fun(cx, &callee->as<JSFunction>());
     if (!fun->hasScript() || !fun->nonLazyScript()->shouldCloneAtCallsite)
         return fun;
 
     IonScript *ion = GetTopIonJSScript(cx)->ionScript();
     CallsiteCloneIC &cache = ion->getCache(cacheIndex).toCallsiteClone();
 
     RootedFunction clone(cx, CloneFunctionAtCallsite(cx, fun, cache.callScript(), cache.callPc()));
     if (!clone)
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -1270,17 +1270,17 @@ InlineFrameIteratorMaybeGC<allowGC>::fin
         Value funval = si_.read();
 
         // Skip extra slots.
         while (si_.moreSlots())
             si_.skip();
 
         si_.nextFrame();
 
-        callee_ = funval.toObject().toFunction();
+        callee_ = &funval.toObject().as<JSFunction>();
 
         // Inlined functions may be clones that still point to the lazy script
         // for the executed script, if they are clones. The actual script
         // exists though, just make sure the function points to it.
         script_ = callee_->existingScript();
 
         pc_ = script_->code + si_.pcOffset();
     }
--- a/js/src/ion/MCallOptimize.cpp
+++ b/js/src/ion/MCallOptimize.cpp
@@ -1104,18 +1104,18 @@ IonBuilder::inlineNewParallelArray(CallI
 
     uint32_t argc = callInfo.argc();
     if (argc < 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     types::StackTypeSet *ctorTypes = callInfo.getArg(0)->resultTypeSet();
     JSObject *targetObj = ctorTypes ? ctorTypes->getSingleton() : NULL;
     RootedFunction target(cx);
-    if (targetObj && targetObj->isFunction())
-        target = targetObj->toFunction();
+    if (targetObj && targetObj->is<JSFunction>())
+        target = &targetObj->as<JSFunction>();
     if (target && target->isInterpreted() && target->nonLazyScript()->shouldCloneAtCallsite) {
         RootedScript scriptRoot(cx, script());
         target = CloneFunctionAtCallsite(cx, target, scriptRoot, pc);
         if (!target)
             return InliningStatus_Error;
     }
     MDefinition *ctor = makeCallsiteClone(
         target,
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -408,18 +408,18 @@ MConstant::printOpcode(FILE *fp)
         break;
       case MIRType_Int32:
         fprintf(fp, "0x%x", value().toInt32());
         break;
       case MIRType_Double:
         fprintf(fp, "%f", value().toDouble());
         break;
       case MIRType_Object:
-        if (value().toObject().isFunction()) {
-            JSFunction *fun = value().toObject().toFunction();
+        if (value().toObject().is<JSFunction>()) {
+            JSFunction *fun = &value().toObject().as<JSFunction>();
             if (fun->displayAtom()) {
                 fputs("function ", fp);
                 FileEscapedString(fp, fun->displayAtom(), 0);
             } else {
                 fputs("unnamed function", fp);
             }
             if (fun->hasScript()) {
                 JSScript *script = fun->nonLazyScript();
@@ -2218,17 +2218,17 @@ MLoadSlot::mightAlias(MDefinition *store
 void
 InlinePropertyTable::trimTo(AutoObjectVector &targets, Vector<bool> &choiceSet)
 {
     for (size_t i = 0; i < targets.length(); i++) {
         // If the target was inlined, don't erase the entry.
         if (choiceSet[i])
             continue;
 
-        JSFunction *target = targets[i]->toFunction();
+        JSFunction *target = &targets[i]->as<JSFunction>();
 
         // Eliminate all entries containing the vetoed function from the map.
         size_t j = 0;
         while (j < numEntries()) {
             if (entries_[j]->func == target)
                 entries_.erase(&entries_[j]);
             else
                 j++;
@@ -2246,17 +2246,17 @@ InlinePropertyTable::trimToAndMaybePatch
     size_t i = 0;
     while (i < numEntries()) {
         bool foundFunc = false;
         // Compare using originals, but if we find a matching function,
         // patch it to the target, which might be a clone.
         for (size_t j = 0; j < originals.length(); j++) {
             if (entries_[i]->func == originals[j]) {
                 if (entries_[i]->func != targets[j])
-                    entries_[i] = new Entry(entries_[i]->typeObj, targets[j]->toFunction());
+                    entries_[i] = new Entry(entries_[i]->typeObj, &targets[j]->as<JSFunction>());
                 foundFunc = true;
                 break;
             }
         }
         if (!foundFunc)
             entries_.erase(&(entries_[i]));
         else
             i++;
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -5858,17 +5858,17 @@ class MPolyInlineDispatch : public MCont
     }
 
     MConstant *getFunctionConstant(size_t i) const {
         JS_ASSERT(i < numCallees());
         return dispatchTable_[i].funcConst;
     }
 
     JSFunction *getFunction(size_t i) const {
-        return getFunctionConstant(i)->value().toObject().toFunction();
+        return &getFunctionConstant(i)->value().toObject().as<JSFunction>();
     }
 
     MBasicBlock *getFunctionBlock(size_t i) const {
         JS_ASSERT(i < numCallees());
         return dispatchTable_[i].block;
     }
 
     MBasicBlock *getFunctionBlock(JSFunction *func) const {
--- a/js/src/ion/ParallelArrayAnalysis.cpp
+++ b/js/src/ion/ParallelArrayAnalysis.cpp
@@ -838,18 +838,18 @@ GetPossibleCallees(JSContext *cx,
 
     if (objCount == 0)
         return true;
 
     RootedFunction rootedFun(cx);
     RootedScript rootedScript(cx);
     for (unsigned i = 0; i < objCount; i++) {
         JSObject *obj = calleeTypes->getSingleObject(i);
-        if (obj && obj->isFunction()) {
-            rootedFun = obj->toFunction();
+        if (obj && obj->is<JSFunction>()) {
+            rootedFun = &obj->as<JSFunction>();
         } else {
             types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
             if (!typeObj)
                 continue;
             rootedFun = typeObj->interpretedFunction;
             if (!rootedFun)
                 continue;
         }
--- a/js/src/ion/ParallelFunctions.cpp
+++ b/js/src/ion/ParallelFunctions.cpp
@@ -431,22 +431,22 @@ ion::ParCallToUncompiledScript(JSFunctio
     if (func->hasScript()) {
         JSScript *script = func->nonLazyScript();
         Spew(SpewBailouts, "Call to uncompiled script: %p:%s:%d",
              script, script->filename(), script->lineno);
     } else if (func->isInterpretedLazy()) {
         Spew(SpewBailouts, "Call to uncompiled lazy script");
     } else if (func->isBoundFunction()) {
         int depth = 0;
-        JSFunction *target = func->getBoundFunctionTarget()->toFunction();
+        JSFunction *target = &func->getBoundFunctionTarget()->as<JSFunction>();
         while (depth < max_bound_function_unrolling) {
             if (target->hasScript())
                 break;
             if (target->isBoundFunction())
-                target = target->getBoundFunctionTarget()->toFunction();
+                target = &target->getBoundFunctionTarget()->as<JSFunction>();
             depth--;
         }
         if (target->hasScript()) {
             JSScript *script = target->nonLazyScript();
             Spew(SpewBailouts, "Call to bound function leading (depth: %d) to script: %p:%s:%d",
                  depth, script, script->filename(), script->lineno);
         } else {
             Spew(SpewBailouts, "Call to bound function (excessive depth: %d)", depth);
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -514,18 +514,18 @@ GetIntrinsicValue(JSContext *cx, HandleP
     return true;
 }
 
 bool
 CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval)
 {
     rval.set(MagicValue(JS_IS_CONSTRUCTING));
 
-    if (callee->isFunction()) {
-        JSFunction *fun = callee->toFunction();
+    if (callee->is<JSFunction>()) {
+        JSFunction *fun = &callee->as<JSFunction>();
         if (fun->isInterpreted()) {
             JSScript *script = fun->getOrCreateScript(cx);
             if (!script || !script->ensureHasTypes(cx))
                 return false;
             JSObject *thisObj = CreateThisForFunction(cx, callee, false);
             if (!thisObj)
                 return false;
             rval.set(ObjectValue(*thisObj));
--- a/js/src/jsapi-tests/testLookup.cpp
+++ b/js/src/jsapi-tests/testLookup.cpp
@@ -25,17 +25,17 @@ BEGIN_TEST(testLookup_bug522590)
     EVAL("mkobj()", x.address());
     JS::RootedObject xobj(cx, JSVAL_TO_OBJECT(x));
 
     // This lookup must not return an internal function object.
     JS::RootedValue r(cx);
     CHECK(JS_LookupProperty(cx, xobj, "f", r.address()));
     CHECK(r.isObject());
     JSObject *funobj = &r.toObject();
-    CHECK(funobj->isFunction());
+    CHECK(funobj->is<JSFunction>());
     CHECK(!js::IsInternalFunctionObject(funobj));
 
     return true;
 }
 END_TEST(testLookup_bug522590)
 
 static JSClass DocumentAllClass = {
     "DocumentAll",
--- a/js/src/jsapi-tests/testOriginPrincipals.cpp
+++ b/js/src/jsapi-tests/testOriginPrincipals.cpp
@@ -82,17 +82,17 @@ testOuter(const char *asciiChars)
 }
 
 bool
 testInner(const char *asciiChars, JSPrincipals *principal, JSPrincipals *originPrincipal)
 {
     JS::RootedValue rval(cx);
     CHECK(eval(asciiChars, principal, originPrincipal, rval.address()));
 
-    JSScript *script = JS_GetFunctionScript(cx, JSVAL_TO_OBJECT(rval)->toFunction());
+    JSScript *script = JS_GetFunctionScript(cx, &rval.toObject().as<JSFunction>());
     CHECK(JS_GetScriptPrincipals(script) == principal);
     CHECK(JS_GetScriptOriginPrincipals(script) == originPrincipal);
 
     return true;
 }
 
 bool
 testError(const char *asciiChars)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -366,17 +366,17 @@ JS_ConvertArgumentsVA(JSContext *cx, uns
             *sp = OBJECT_TO_JSVAL(obj);
             *va_arg(ap, JSObject **) = obj;
             break;
           case 'f':
             obj = ReportIfNotFunction(cx, *sp);
             if (!obj)
                 return JS_FALSE;
             *sp = OBJECT_TO_JSVAL(obj);
-            *va_arg(ap, JSFunction **) = obj->toFunction();
+            *va_arg(ap, JSFunction **) = &obj->as<JSFunction>();
             break;
           case 'v':
             *va_arg(ap, jsval *) = *sp;
             break;
           case '*':
             break;
           default:
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
@@ -1801,17 +1801,17 @@ StdNameToPropertyName(JSContext *cx, con
     return OFFSET_TO_NAME(cx->runtime(), stdn->atomOffset);
 }
 
 /*
  * Table of class initializers and their atom offsets in rt->atomState.
  * If you add a "standard" class, remember to update this table.
  */
 static const JSStdName standard_class_atoms[] = {
-    {js_InitFunctionClass,              EAGER_ATOM_AND_CLASP(Function)},
+    {js_InitFunctionClass,              EAGER_CLASS_ATOM(Function), &JSFunction::class_},
     {js_InitObjectClass,                EAGER_ATOM_AND_CLASP(Object)},
     {js_InitArrayClass,                 EAGER_ATOM_AND_CLASP(Array)},
     {js_InitBooleanClass,               EAGER_ATOM_AND_OCLASP(Boolean)},
     {js_InitDateClass,                  EAGER_ATOM_AND_CLASP(Date)},
     {js_InitMathClass,                  EAGER_ATOM_AND_CLASP(Math)},
     {js_InitNumberClass,                EAGER_ATOM_AND_OCLASP(Number)},
     {js_InitStringClass,                EAGER_ATOM_AND_OCLASP(String)},
     {js_InitExceptionClasses,           EAGER_ATOM_AND_CLASP(Error)},
@@ -2501,31 +2501,24 @@ JS_GetTraceThingInfo(char *buf, size_t b
     bufsize -= n;
     *buf = '\0';
 
     if (details && bufsize > 2) {
         switch (kind) {
           case JSTRACE_OBJECT:
           {
             JSObject *obj = (JSObject *)thing;
-            Class *clasp = obj->getClass();
-            if (clasp == &FunctionClass) {
-                JSFunction *fun = obj->toFunction();
-                if (!fun) {
-                    JS_snprintf(buf, bufsize, " <newborn>");
-                } else if (fun != obj) {
-                    JS_snprintf(buf, bufsize, " %p", fun);
-                } else {
-                    if (fun->displayAtom()) {
-                        *buf++ = ' ';
-                        bufsize--;
-                        PutEscapedString(buf, bufsize, fun->displayAtom(), 0);
-                    }
+            if (obj->is<JSFunction>()) {
+                JSFunction *fun = &obj->as<JSFunction>();
+                if (fun->displayAtom()) {
+                    *buf++ = ' ';
+                    bufsize--;
+                    PutEscapedString(buf, bufsize, fun->displayAtom(), 0);
                 }
-            } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
+            } else if (obj->getClass()->flags & JSCLASS_HAS_PRIVATE) {
                 JS_snprintf(buf, bufsize, " %p", obj->getPrivate());
             } else {
                 JS_snprintf(buf, bufsize, " <no private>");
             }
             break;
           }
 
           case JSTRACE_STRING:
@@ -3350,17 +3343,17 @@ JS_NewObject(JSContext *cx, JSClass *jsc
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &ObjectClass;    /* default class is Object */
 
-    JS_ASSERT(clasp != &FunctionClass);
+    JS_ASSERT(clasp != &JSFunction::class_);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
     JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent);
     if (obj) {
         TypeObjectFlags flags = 0;
         if (clasp->emulatesUndefined())
             flags |= OBJECT_FLAG_EMULATES_UNDEFINED;
         if (flags)
@@ -3380,17 +3373,17 @@ JS_NewObjectWithGivenProto(JSContext *cx
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &ObjectClass;    /* default class is Object */
 
-    JS_ASSERT(clasp != &FunctionClass);
+    JS_ASSERT(clasp != &JSFunction::class_);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
     JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
     if (obj)
         MarkTypeObjectUnknownProperties(cx, obj->type());
     return obj;
 }
 
@@ -4793,27 +4786,27 @@ JS_CloneFunctionObject(JSContext *cx, JS
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent);
     // Note that funobj can be in a different compartment.
 
     if (!parent)
         parent = cx->global();
 
-    if (!funobj->isFunction()) {
+    if (!funobj->is<JSFunction>()) {
         AutoCompartment ac(cx, funobj);
         ReportIsNotFunction(cx, ObjectValue(*funobj));
         return NULL;
     }
 
     /*
      * If a function was compiled to be lexically nested inside some other
      * script, we cannot clone it without breaking the compiler's assumptions.
      */
-    RootedFunction fun(cx, funobj->toFunction());
+    RootedFunction fun(cx, &funobj->as<JSFunction>());
     if (fun->isInterpretedLazy()) {
         AutoCompartment ac(cx, funobj);
         if (!fun->getOrCreateScript(cx))
             return NULL;
     }
     if (fun->isInterpreted() && (fun->nonLazyScript()->enclosingStaticScope() ||
         (fun->nonLazyScript()->compileAndGo && !parent->is<GlobalObject>())))
     {
@@ -4856,31 +4849,31 @@ JS_PUBLIC_API(uint16_t)
 JS_GetFunctionArity(JSFunction *fun)
 {
     return fun->nargs;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
 {
-    return obj->isFunction();
+    return obj->is<JSFunction>();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
 {
     return obj->isCallable();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsNativeFunction(JSObject *funobj, JSNative call)
 {
-    if (!funobj->isFunction())
+    if (!funobj->is<JSFunction>())
         return false;
-    JSFunction *fun = funobj->toFunction();
+    JSFunction *fun = &funobj->as<JSFunction>();
     return fun->isNative() && fun->native() == call;
 }
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsConstructor(JSFunction *fun)
 {
     return fun->isNativeConstructor() || fun->isInterpretedConstructor();
 }
@@ -4894,17 +4887,17 @@ JS_BindCallable(JSContext *cx, JSObject 
 }
 
 JSBool
 js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     const JSFunctionSpec *fs = (JSFunctionSpec *)
-        vp->toObject().toFunction()->getExtendedSlot(0).toPrivate();
+        vp->toObject().as<JSFunction>().getExtendedSlot(0).toPrivate();
     JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
 
     if (argc < 1) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return JS_FALSE;
     }
 
     /*
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1516,20 +1516,20 @@ enum ComparatorMatchResult {
  */
 ComparatorMatchResult
 MatchNumericComparator(JSContext *cx, const Value &v)
 {
     if (!v.isObject())
         return Match_None;
 
     JSObject &obj = v.toObject();
-    if (!obj.isFunction())
+    if (!obj.is<JSFunction>())
         return Match_None;
 
-    JSFunction *fun = obj.toFunction();
+    JSFunction *fun = &obj.as<JSFunction>();
     if (!fun->isInterpreted())
         return Match_None;
 
     JSScript *script = fun->getOrCreateScript(cx);
     if (!script)
         return Match_Failure;
 
     jsbytecode *pc = script->code;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1030,17 +1030,17 @@ js_ReportMissingArg(JSContext *cx, Handl
 {
     char argbuf[11];
     char *bytes;
     RootedAtom atom(cx);
 
     JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
     bytes = NULL;
     if (IsFunctionObject(v)) {
-        atom = v.toObject().toFunction()->atom();
+        atom = v.toObject().as<JSFunction>().atom();
         bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
                                         v, atom);
         if (!bytes)
             return;
     }
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_MISSING_FUN_ARG, argbuf,
                          bytes ? bytes : "");
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -390,17 +390,17 @@ CallJSNativeConstructor(JSContext *cx, N
      * - new Iterator(x) is user-hookable; it returns x.__iterator__() which
      *   could be any object.
      *
      * - (new Object(Object)) returns the callee.
      */
     JS_ASSERT_IF(native != FunctionProxyClass.construct &&
                  native != js::CallOrConstructBoundFunction &&
                  native != js::IteratorConstructor &&
-                 (!callee->isFunction() || callee->toFunction()->native() != obj_construct),
+                 (!callee->is<JSFunction>() || callee->as<JSFunction>().native() != obj_construct),
                  !args.rval().isPrimitive() && callee != &args.rval().toObject());
 
     return true;
 }
 
 JS_ALWAYS_INLINE bool
 CallJSPropertyOp(JSContext *cx, PropertyOp op, HandleObject receiver, HandleId id, MutableHandleValue vp)
 {
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -608,17 +608,17 @@ JSCompartment::hasScriptsOnStack()
 static bool
 AddInnerLazyFunctionsFromScript(JSScript *script, AutoObjectVector &lazyFunctions)
 {
     if (!script->hasObjects())
         return true;
     ObjectArray *objects = script->objects();
     for (size_t i = script->innerObjectsStart(); i < objects->length; i++) {
         JSObject *obj = objects->vector[i];
-        if (obj->isFunction() && obj->toFunction()->isInterpretedLazy()) {
+        if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) {
             if (!lazyFunctions.append(obj))
                 return false;
         }
     }
     return true;
 }
 
 static bool
@@ -626,51 +626,51 @@ CreateLazyScriptsForCompartment(JSContex
 {
     AutoObjectVector lazyFunctions(cx);
 
     // Find all root lazy functions in the compartment: those which have not been
     // compiled and which have a source object, indicating that their parent has
     // been compiled.
     for (gc::CellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) {
         JSObject *obj = i.get<JSObject>();
-        if (obj->compartment() == cx->compartment() && obj->isFunction()) {
-            JSFunction *fun = obj->toFunction();
+        if (obj->compartment() == cx->compartment() && obj->is<JSFunction>()) {
+            JSFunction *fun = &obj->as<JSFunction>();
             if (fun->isInterpretedLazy()) {
                 LazyScript *lazy = fun->lazyScriptOrNull();
                 if (lazy && lazy->sourceObject() && !lazy->maybeScript()) {
                     if (!lazyFunctions.append(fun))
                         return false;
                 }
             }
         }
     }
 
     // Create scripts for each lazy function, updating the list of functions to
     // process with any newly exposed inner functions in created scripts.
     // A function cannot be delazified until its outer script exists.
     for (size_t i = 0; i < lazyFunctions.length(); i++) {
-        JSFunction *fun = lazyFunctions[i]->toFunction();
+        JSFunction *fun = &lazyFunctions[i]->as<JSFunction>();
 
         // lazyFunctions may have been populated with multiple functions for
         // a lazy script.
         if (!fun->isInterpretedLazy())
             continue;
 
         JSScript *script = fun->getOrCreateScript(cx);
         if (!script)
             return false;
         if (!AddInnerLazyFunctionsFromScript(script, lazyFunctions))
             return false;
     }
 
     // Repoint any clones of the original functions to their new script.
     for (gc::CellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) {
         JSObject *obj = i.get<JSObject>();
-        if (obj->compartment() == cx->compartment() && obj->isFunction()) {
-            JSFunction *fun = obj->toFunction();
+        if (obj->compartment() == cx->compartment() && obj->is<JSFunction>()) {
+            JSFunction *fun = &obj->as<JSFunction>();
             if (fun->isInterpretedLazy()) {
                 LazyScript *lazy = fun->lazyScriptOrNull();
                 if (lazy && lazy->maybeScript())
                     fun->existingScript();
             }
         }
     }
 
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -591,17 +591,17 @@ Exception(JSContext *cx, unsigned argc, 
     uint32_t lineno, column = 0;
     if (args.length() > 2) {
         if (!ToUint32(cx, args[2], &lineno))
             return false;
     } else {
         lineno = iter.done() ? 0 : PCToLineNumber(script, iter.pc(), &column);
     }
 
-    int exnType = args.callee().toFunction()->getExtendedSlot(0).toInt32();
+    int exnType = args.callee().as<JSFunction>().getExtendedSlot(0).toInt32();
     if (!InitExnPrivate(cx, obj, message, filename, lineno, column, NULL, exnType))
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 /* ES5 15.11.4.4 (NB: with subsequent errata). */
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -81,18 +81,18 @@ JS_FindCompilationScope(JSContext *cx, J
     if (JSObjectOp op = obj->getClass()->ext.innerObject)
         obj = op(cx, obj);
     return obj;
 }
 
 JS_FRIEND_API(JSFunction *)
 JS_GetObjectFunction(JSObject *obj)
 {
-    if (obj->isFunction())
-        return obj->toFunction();
+    if (obj->is<JSFunction>())
+        return &obj->as<JSFunction>();
     return NULL;
 }
 
 JS_FRIEND_API(JSBool)
 JS_SplicePrototype(JSContext *cx, JSObject *objArg, JSObject *protoArg)
 {
     RootedObject obj(cx, objArg);
     RootedObject proto(cx, protoArg);
@@ -343,16 +343,22 @@ js::IsSystemZone(Zone *zone)
 
 JS_FRIEND_API(bool)
 js::IsAtomsCompartment(JSCompartment *comp)
 {
     return comp == comp->rt->atomsCompartment;
 }
 
 JS_FRIEND_API(bool)
+js::IsFunctionObject(JSObject *obj)
+{
+    return obj->is<JSFunction>();
+}
+
+JS_FRIEND_API(bool)
 js::IsScopeObject(JSObject *obj)
 {
     return obj->is<ScopeObject>();
 }
 
 JS_FRIEND_API(bool)
 js::IsCallObject(JSObject *obj)
 {
@@ -486,25 +492,25 @@ js::InitClassWithReserved(JSContext *cx,
     return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor,
                         nargs, ps, fs, static_ps, static_fs, NULL,
                         JSFunction::ExtendedFinalizeKind);
 }
 
 JS_FRIEND_API(const Value &)
 js::GetFunctionNativeReserved(JSObject *fun, size_t which)
 {
-    JS_ASSERT(fun->toFunction()->isNative());
-    return fun->toFunction()->getExtendedSlot(which);
+    JS_ASSERT(fun->as<JSFunction>().isNative());
+    return fun->as<JSFunction>().getExtendedSlot(which);
 }
 
 JS_FRIEND_API(void)
 js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val)
 {
-    JS_ASSERT(fun->toFunction()->isNative());
-    fun->toFunction()->setExtendedSlot(which, val);
+    JS_ASSERT(fun->as<JSFunction>().isNative());
+    fun->as<JSFunction>().setExtendedSlot(which, val);
 }
 
 JS_FRIEND_API(void)
 js::SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const js::Value &value)
 {
     obj->setSlot(slot, value);
 }
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -373,17 +373,20 @@ struct Function {
 struct Atom {
     static const size_t LENGTH_SHIFT = 4;
     size_t lengthAndFlags;
     const jschar *chars;
 };
 
 } /* namespace shadow */
 
-extern JS_FRIEND_DATA(js::Class) FunctionClass;
+// This is equal to JSFunction::class_.  Use it in places where you don't want
+// to #include jsfun.h.
+extern JS_FRIEND_DATA(js::Class*) FunctionClassPtr;
+
 extern JS_FRIEND_DATA(js::Class) FunctionProxyClass;
 extern JS_FRIEND_DATA(js::Class) OuterWindowProxyClass;
 extern JS_FRIEND_DATA(js::Class) ObjectProxyClass;
 extern JS_FRIEND_DATA(js::Class) ObjectClass;
 
 inline js::Class *
 GetObjectClass(JSObject *obj)
 {
@@ -402,16 +405,19 @@ IsInnerObject(JSObject *obj) {
 }
 
 inline bool
 IsOuterObject(JSObject *obj) {
     return !!GetObjectClass(obj)->ext.innerObject;
 }
 
 JS_FRIEND_API(bool)
+IsFunctionObject(JSObject *obj);
+
+JS_FRIEND_API(bool)
 IsScopeObject(JSObject *obj);
 
 JS_FRIEND_API(bool)
 IsCallObject(JSObject *obj);
 
 inline JSObject *
 GetObjectParent(JSObject *obj)
 {
@@ -1566,17 +1572,17 @@ struct JSJitInfo {
                                keep returning the same value for the given
                                "this" object" */
     JSValueType returnType; /* The return type tag.  Might be JSVAL_TYPE_UNKNOWN */
 };
 
 static JS_ALWAYS_INLINE const JSJitInfo *
 FUNCTION_VALUE_TO_JITINFO(const JS::Value& v)
 {
-    JS_ASSERT(js::GetObjectClass(&v.toObject()) == &js::FunctionClass);
+    JS_ASSERT(js::GetObjectClass(&v.toObject()) == js::FunctionClassPtr);
     return reinterpret_cast<js::shadow::Function *>(&v.toObject())->jitinfo;
 }
 
 /* Statically asserted in jsfun.h. */
 static const unsigned JS_FUNCTION_INTERPRETED_BIT = 0x1;
 
 static JS_ALWAYS_INLINE void
 SET_JITINFO(JSFunction * func, const JSJitInfo *info)
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -53,23 +53,23 @@ using namespace js::frontend;
 
 using mozilla::ArrayLength;
 using mozilla::PodCopy;
 
 static JSBool
 fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValue vp)
 {
     RootedObject obj(cx, obj_);
-    while (!obj->isFunction()) {
+    while (!obj->is<JSFunction>()) {
         if (!JSObject::getProto(cx, obj, &obj))
             return false;
         if (!obj)
             return true;
     }
-    RootedFunction fun(cx, obj->toFunction());
+    RootedFunction fun(cx, &obj->as<JSFunction>());
 
     /* Set to early to null in case of error */
     vp.setNull();
 
     /* Find fun's top-most activation record. */
     NonBuiltinScriptFrameIter iter(cx);
     for (; !iter.done(); ++iter) {
         if (!iter.isFunctionFrame() || iter.isEvalFrame())
@@ -112,32 +112,32 @@ fun_getProperty(JSContext *cx, HandleObj
         ++iter;
         if (iter.done() || !iter.isFunctionFrame()) {
             JS_ASSERT(vp.isNull());
             return true;
         }
 
         /* Callsite clones should never escape to script. */
         JSObject &maybeClone = iter.calleev().toObject();
-        if (maybeClone.isFunction() && maybeClone.toFunction()->nonLazyScript()->isCallsiteClone)
-            vp.setObject(*maybeClone.toFunction()->nonLazyScript()->originalFunction());
+        if (maybeClone.is<JSFunction>() && maybeClone.as<JSFunction>().nonLazyScript()->isCallsiteClone)
+            vp.setObject(*maybeClone.as<JSFunction>().nonLazyScript()->originalFunction());
         else
             vp.set(iter.calleev());
 
         if (!cx->compartment()->wrap(cx, vp))
             return false;
 
         /*
          * Censor the caller if we don't have full access to it.
          */
         RootedObject caller(cx, &vp.toObject());
         if (caller->isWrapper() && !Wrapper::wrapperHandler(caller)->isSafeToUnwrap()) {
             vp.setNull();
-        } else if (caller->isFunction()) {
-            JSFunction *callerFun = caller->toFunction();
+        } else if (caller->is<JSFunction>()) {
+            JSFunction *callerFun = &caller->as<JSFunction>();
             if (callerFun->isInterpreted() && callerFun->strict()) {
                 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                              JSMSG_CALLER_IS_STRICT);
                 return false;
             }
         }
 
         return true;
@@ -154,17 +154,17 @@ fun_getProperty(JSContext *cx, HandleObj
 static const uint16_t poisonPillProps[] = {
     NAME_OFFSET(arguments),
     NAME_OFFSET(caller),
 };
 
 static JSBool
 fun_enumerate(JSContext *cx, HandleObject obj)
 {
-    JS_ASSERT(obj->isFunction());
+    JS_ASSERT(obj->is<JSFunction>());
 
     RootedId id(cx);
     bool found;
 
     if (!obj->isBoundFunction()) {
         id = NameToId(cx->names().classPrototype);
         if (!JSObject::hasProperty(cx, obj, id, &found, 0))
             return false;
@@ -187,17 +187,17 @@ fun_enumerate(JSContext *cx, HandleObjec
 
     return true;
 }
 
 static JSObject *
 ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj)
 {
 #ifdef DEBUG
-    JSFunction *fun = obj->toFunction();
+    JSFunction *fun = &obj->as<JSFunction>();
     JS_ASSERT(fun->isInterpreted());
     JS_ASSERT(!fun->isFunctionPrototype());
 #endif
 
     /*
      * Assert that fun is not a compiler-created function object, which
      * must never leak to script or embedding code and then be mutated.
      * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
@@ -238,17 +238,17 @@ ResolveInterpretedFunctionPrototype(JSCo
 
 static JSBool
 fun_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
             MutableHandleObject objp)
 {
     if (!JSID_IS_ATOM(id))
         return true;
 
-    RootedFunction fun(cx, obj->toFunction());
+    RootedFunction fun(cx, &obj->as<JSFunction>());
 
     if (JSID_IS_ATOM(id, cx->names().classPrototype)) {
         /*
          * Built-in functions do not have a .prototype property per ECMA-262,
          * or (Object.prototype, Function.prototype, etc.) have that property
          * created eagerly.
          *
          * ES5 15.3.4: the non-native function object named Function.prototype
@@ -334,17 +334,17 @@ js::XDRInterpretedFunction(XDRState<mode
                                    plus for fun->u.i.skipmin, fun->u.i.wrapper,
                                    and 14 bits reserved for future use */
     uint32_t flagsword;           /* word for argument count and fun->flags */
 
     JSContext *cx = xdr->cx();
     RootedFunction fun(cx);
     RootedScript script(cx);
     if (mode == XDR_ENCODE) {
-        fun = objp->toFunction();
+        fun = &objp->as<JSFunction>();
         if (!fun->isInterpreted()) {
             JSAutoByteString funNameBytes;
             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
                                      name);
             }
             return false;
         }
@@ -430,18 +430,18 @@ js::CloneFunctionAndScript(JSContext *cx
  * property of its 'this' parameter, and walks the prototype chain of v (only
  * if v is an object) returning true if .prototype is found.
  */
 static JSBool
 fun_hasInstance(JSContext *cx, HandleObject objArg, MutableHandleValue v, JSBool *bp)
 {
     RootedObject obj(cx, objArg);
 
-    while (obj->isFunction() && obj->isBoundFunction())
-        obj = obj->toFunction()->getBoundFunctionTarget();
+    while (obj->is<JSFunction>() && obj->isBoundFunction())
+        obj = obj->as<JSFunction>().getBoundFunctionTarget();
 
     RootedValue pval(cx);
     if (!JSObject::getProperty(cx, obj, obj, cx->names().classPrototype, &pval))
         return false;
 
     if (pval.isPrimitive()) {
         /*
          * Throw a runtime error if instanceof is called on a function that
@@ -482,20 +482,20 @@ JSFunction::trace(JSTracer *trc)
         if (u.i.env_)
             MarkObjectUnbarriered(trc, &u.i.env_, "fun_callscope");
     }
 }
 
 static void
 fun_trace(JSTracer *trc, JSObject *obj)
 {
-    obj->toFunction()->trace(trc);
+    obj->as<JSFunction>().trace(trc);
 }
 
-JS_FRIEND_DATA(Class) js::FunctionClass = {
+Class JSFunction::class_ = {
     js_Function_str,
     JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
     JS_PropertyStub,         /* addProperty */
     JS_DeletePropertyStub,   /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     fun_enumerate,
@@ -504,16 +504,17 @@ JS_FRIEND_DATA(Class) js::FunctionClass 
     NULL,                    /* finalize    */
     NULL,                    /* checkAccess */
     NULL,                    /* call        */
     fun_hasInstance,
     NULL,                    /* construct   */
     fun_trace
 };
 
+JS_FRIEND_DATA(Class*) js::FunctionClassPtr = &JSFunction::class_;
 
 /* Find the body of a function (not including braces). */
 static bool
 FindBody(JSContext *cx, HandleFunction fun, StableCharPtr chars, size_t length,
          size_t *bodyStart, size_t *bodyEnd)
 {
     // We don't need principals, since those are only used for error reporting.
     CompileOptions options(cx);
@@ -572,17 +573,17 @@ js::FunctionToString(JSContext *cx, Hand
 {
     if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
         return NULL;
 
     // If the object is an automatically-bound arrow function, get the source
     // of the pre-binding target.
     if (fun->isArrow() && fun->isBoundFunction()) {
         JSObject *target = fun->getBoundFunctionTarget();
-        RootedFunction targetFun(cx, target->toFunction());
+        RootedFunction targetFun(cx, &target->as<JSFunction>());
         JS_ASSERT(targetFun->isArrow());
         return FunctionToString(cx, targetFun, bodyOnly, lambdaParen);
     }
 
     StringBuffer out(cx);
     RootedScript script(cx);
 
     if (fun->hasScript()) {
@@ -734,27 +735,27 @@ js::FunctionToString(JSContext *cx, Hand
             return NULL;
     }
     return out.finishString();
 }
 
 JSString *
 fun_toStringHelper(JSContext *cx, HandleObject obj, unsigned indent)
 {
-    if (!obj->isFunction()) {
+    if (!obj->is<JSFunction>()) {
         if (IsFunctionProxy(obj))
             return Proxy::fun_toString(cx, obj, indent);
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_INCOMPATIBLE_PROTO,
                              js_Function_str, js_toString_str,
                              "object");
         return NULL;
     }
 
-    RootedFunction fun(cx, obj->toFunction());
+    RootedFunction fun(cx, &obj->as<JSFunction>());
     return FunctionToString(cx, fun, false, indent != JS_DONT_PRETTY_PRINT);
 }
 
 static JSBool
 fun_toString(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JS_ASSERT(IsFunctionObject(args.calleev()));
@@ -797,17 +798,17 @@ fun_toSource(JSContext *cx, unsigned arg
 #endif
 
 JSBool
 js_fun_call(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedValue fval(cx, vp[1]);
 
     if (!js_IsCallable(fval)) {
-        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass);
+        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &JSFunction::class_);
         return false;
     }
 
     Value *argv = vp + 2;
     RootedValue thisv(cx, UndefinedValue());
     if (argc != 0) {
         thisv = argv[0];
 
@@ -853,17 +854,17 @@ PushBaselineFunApplyArguments(JSContext 
 
 /* ES5 15.3.4.3 */
 JSBool
 js_fun_apply(JSContext *cx, unsigned argc, Value *vp)
 {
     /* Step 1. */
     RootedValue fval(cx, vp[1]);
     if (!js_IsCallable(fval)) {
-        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass);
+        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &JSFunction::class_);
         return false;
     }
 
     /* Step 2. */
     if (argc < 2 || vp[3].isNullOrUndefined())
         return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
 
     InvokeArgsGuard args;
@@ -989,18 +990,16 @@ static const uint32_t JSSLOT_BOUND_FUNCT
 static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
 
 static const uint32_t BOUND_FUNCTION_RESERVED_SLOTS = 2;
 
 inline bool
 JSFunction::initBoundFunction(JSContext *cx, HandleValue thisArg,
                               const Value *args, unsigned argslen)
 {
-    JS_ASSERT(isFunction());
-
     RootedFunction self(cx, this);
 
     /*
      * Convert to a dictionary to set the BOUND_FUNCTION flag and increase
      * the slot span to cover the arguments and additional slots for the 'this'
      * value and arguments count.
      */
     if (!self->toDictionaryMode(cx))
@@ -1018,36 +1017,33 @@ JSFunction::initBoundFunction(JSContext 
     self->initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen);
 
     return true;
 }
 
 inline const js::Value &
 JSFunction::getBoundFunctionThis() const
 {
-    JS_ASSERT(isFunction());
     JS_ASSERT(isBoundFunction());
 
     return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
 }
 
 inline const js::Value &
 JSFunction::getBoundFunctionArgument(unsigned which) const
 {
-    JS_ASSERT(isFunction());
     JS_ASSERT(isBoundFunction());
     JS_ASSERT(which < getBoundFunctionArgumentCount());
 
     return getSlot(BOUND_FUNCTION_RESERVED_SLOTS + which);
 }
 
 inline size_t
 JSFunction::getBoundFunctionArgumentCount() const
 {
-    JS_ASSERT(isFunction());
     JS_ASSERT(isBoundFunction());
 
     return getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
 }
 
 /* static */ bool
 JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFunction fun)
 {
@@ -1101,17 +1097,17 @@ JSFunction::createScriptForLazilyInterpr
     Rooted<PropertyName *> funName(cx, funAtom->asPropertyName());
     return cx->runtime()->cloneSelfHostedFunctionScript(cx, funName, fun);
 }
 
 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
 JSBool
 js::CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp)
 {
-    RootedFunction fun(cx, vp[0].toObject().toFunction());
+    RootedFunction fun(cx, &vp[0].toObject().as<JSFunction>());
     JS_ASSERT(fun->isBoundFunction());
 
     bool constructing = IsConstructing(vp);
     if (constructing && fun->isArrow()) {
         /*
          * Per spec, arrow functions do not even have a [[Construct]] method.
          * So before anything else, if we are an arrow function, make sure we
          * don't even get here. You never saw me. Burn this comment.
@@ -1183,17 +1179,17 @@ fun_bind(JSContext *cx, unsigned argc, V
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     Value thisv = args.thisv();
 
     /* Step 2. */
     if (!js_IsCallable(thisv)) {
-        ReportIncompatibleMethod(cx, args, &FunctionClass);
+        ReportIncompatibleMethod(cx, args, &JSFunction::class_);
         return false;
     }
 
     /* Step 3. */
     Value *boundArgs = NULL;
     unsigned argslen = 0;
     if (args.length() > 1) {
         boundArgs = args.array() + 1;
@@ -1213,35 +1209,35 @@ fun_bind(JSContext *cx, unsigned argc, V
 }
 
 JSObject*
 js_fun_bind(JSContext *cx, HandleObject target, HandleValue thisArg,
             Value *boundArgs, unsigned argslen)
 {
     /* Steps 15-16. */
     unsigned length = 0;
-    if (target->isFunction()) {
-        unsigned nargs = target->toFunction()->nargs;
+    if (target->is<JSFunction>()) {
+        unsigned nargs = target->as<JSFunction>().nargs;
         if (nargs > argslen)
             length = nargs - argslen;
     }
 
     /* Step 4-6, 10-11. */
-    RootedAtom name(cx, target->isFunction() ? target->toFunction()->atom() : NULL);
+    RootedAtom name(cx, target->is<JSFunction>() ? target->as<JSFunction>().atom() : NULL);
 
     RootedObject funobj(cx, NewFunction(cx, NullPtr(), CallOrConstructBoundFunction, length,
                                         JSFunction::NATIVE_CTOR, target, name));
     if (!funobj)
         return NULL;
 
     /* NB: Bound functions abuse |parent| to store their target. */
     if (!JSObject::setParent(cx, funobj, target))
         return NULL;
 
-    if (!funobj->toFunction()->initBoundFunction(cx, thisArg, boundArgs, argslen))
+    if (!funobj->as<JSFunction>().initBoundFunction(cx, thisArg, boundArgs, argslen))
         return NULL;
 
     /* Steps 17, 19-21 are handled by fun_resolve. */
     /* Step 18 is the default for new functions. */
     return funobj;
 }
 
 /*
@@ -1482,30 +1478,31 @@ js::NewFunction(JSContext *cx, HandleObj
                 NewObjectKind newKind /* = GenericObject */)
 {
     JS_ASSERT(allocKind == JSFunction::FinalizeKind || allocKind == JSFunction::ExtendedFinalizeKind);
     JS_ASSERT(sizeof(JSFunction) <= gc::Arena::thingSize(JSFunction::FinalizeKind));
     JS_ASSERT(sizeof(FunctionExtended) <= gc::Arena::thingSize(JSFunction::ExtendedFinalizeKind));
 
     RootedObject funobj(cx, funobjArg);
     if (funobj) {
-        JS_ASSERT(funobj->isFunction());
+        JS_ASSERT(funobj->is<JSFunction>());
         JS_ASSERT(funobj->getParent() == parent);
         JS_ASSERT_IF(native && cx->typeInferenceEnabled(), funobj->hasSingletonType());
     } else {
         // Don't give asm.js module functions a singleton type since they
         // are cloned (via CloneFunctionObjectIfNotSingleton) which assumes
         // that hasSingletonType implies isInterpreted.
         if (native && !IsAsmJSModuleNative(native))
             newKind = SingletonObject;
-        funobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), allocKind, newKind);
+        funobj = NewObjectWithClassProto(cx, &JSFunction::class_, NULL,
+                                         SkipScopeParent(parent), allocKind, newKind);
         if (!funobj)
             return NULL;
     }
-    RootedFunction fun(cx, funobj->toFunction());
+    RootedFunction fun(cx, &funobj->as<JSFunction>());
 
     /* Initialize all function members. */
     fun->nargs = uint16_t(nargs);
     fun->flags = flags;
     if (fun->isInterpreted()) {
         JS_ASSERT(!native);
         fun->mutableScript().init(NULL);
         fun->initEnvironment(parent);
@@ -1533,21 +1530,21 @@ js::CloneFunctionObject(JSContext *cx, H
     bool useSameScript = cx->compartment() == fun->compartment() &&
                          !fun->hasSingletonType() &&
                          !types::UseNewTypeForClone(fun);
 
     if (!useSameScript && fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
         return NULL;
 
     NewObjectKind newKind = useSameScript ? newKindArg : SingletonObject;
-    JSObject *cloneobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent),
-                                                 allocKind, newKind);
+    JSObject *cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, NULL,
+                                                 SkipScopeParent(parent), allocKind, newKind);
     if (!cloneobj)
         return NULL;
-    RootedFunction clone(cx, cloneobj->toFunction());
+    RootedFunction clone(cx, &cloneobj->as<JSFunction>());
 
     clone->nargs = fun->nargs;
     clone->flags = fun->flags & ~JSFunction::EXTENDED;
     if (fun->hasScript()) {
         clone->initScript(fun->nonLazyScript());
         clone->initEnvironment(parent);
     } else if (fun->isInterpretedLazy()) {
         LazyScript *lazy = fun->lazyScriptOrNull();
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -14,16 +14,18 @@
 
 #include "gc/Barrier.h"
 
 namespace js { class FunctionExtended; }
 
 class JSFunction : public JSObject
 {
   public:
+    static js::Class class_;
+
     enum Flags {
         INTERPRETED      = 0x0001,  /* function has a JSScript and environment. */
         NATIVE_CTOR      = 0x0002,  /* native that can be called as a constructor */
         EXTENDED         = 0x0004,  /* structure is FunctionExtended */
         IS_FUN_PROTO     = 0x0010,  /* function is Function.prototype for some global object */
         EXPR_CLOSURE     = 0x0020,  /* expression closure: function(x) x*x */
         HAS_GUESSED_ATOM = 0x0040,  /* function had no explicit name, but a
                                        name was guessed for it anyway */
@@ -325,40 +327,18 @@ class JSFunction : public JSObject
     /* GC support. */
     js::gc::AllocKind getAllocKind() const {
         js::gc::AllocKind kind = FinalizeKind;
         if (isExtended())
             kind = ExtendedFinalizeKind;
         JS_ASSERT_IF(isTenured(), kind == tenuredGetAllocKind());
         return kind;
     }
-
-  private:
-    /*
-     * These member functions are inherited from JSObject, but should never be applied to
-     * a value statically known to be a JSFunction.
-     */
-    inline JSFunction *toFunction() MOZ_DELETE;
-    inline const JSFunction *toFunction() const MOZ_DELETE;
 };
 
-inline JSFunction *
-JSObject::toFunction()
-{
-    JS_ASSERT(JS_ObjectIsFunction(NULL, this));
-    return static_cast<JSFunction *>(this);
-}
-
-inline const JSFunction *
-JSObject::toFunction() const
-{
-    JS_ASSERT(JS_ObjectIsFunction(NULL, const_cast<JSObject *>(this)));
-    return static_cast<const JSFunction *>(this);
-}
-
 extern JSString *
 fun_toStringHelper(JSContext *cx, js::HandleObject obj, unsigned indent);
 
 inline JSFunction::Flags
 JSAPIToJSFunctionFlags(unsigned flags)
 {
     return (flags & JSFUN_CONSTRUCTOR)
            ? JSFunction::NATIVE_CTOR
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -3,16 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jsfuninlines_h
 #define jsfuninlines_h
 
 #include "jsfun.h"
+
 #include "jsscript.h"
 
 #include "vm/GlobalObject.h"
 
 #include "vm/ScopeObject-inl.h"
 #include "vm/String-inl.h"
 
 inline bool
@@ -113,27 +114,27 @@ JSFunction::getExtendedSlot(size_t which
 
 namespace js {
 
 extern JS_ALWAYS_INLINE bool
 SameTraceType(const Value &lhs, const Value &rhs)
 {
     return SameType(lhs, rhs) &&
            (lhs.isPrimitive() ||
-            lhs.toObject().isFunction() == rhs.toObject().isFunction());
+            lhs.toObject().is<JSFunction>() == rhs.toObject().is<JSFunction>());
 }
 
 /* Valueified JS_IsConstructing. */
 static JS_ALWAYS_INLINE bool
 IsConstructing(const Value *vp)
 {
 #ifdef DEBUG
     JSObject *callee = &JS_CALLEE(cx, vp).toObject();
-    if (callee->isFunction()) {
-        JSFunction *fun = callee->toFunction();
+    if (callee->is<JSFunction>()) {
+        JSFunction *fun = &callee->as<JSFunction>();
         JS_ASSERT(fun->isNativeConstructor());
     } else {
         JS_ASSERT(callee->getClass()->construct != NULL);
     }
 #endif
     return vp[1].isMagic();
 }
 
@@ -280,22 +281,21 @@ JSFunction::initLazyScript(js::LazyScrip
     flags |= INTERPRETED_LAZY;
 
     u.i.s.lazy_ = lazy;
 }
 
 inline JSObject *
 JSFunction::getBoundFunctionTarget() const
 {
-    JS_ASSERT(isFunction());
     JS_ASSERT(isBoundFunction());
 
     /* Bound functions abuse |parent| to store their target function. */
     return getParent();
 }
 
 inline bool
 js::Class::isCallable() const
 {
-    return this == &js::FunctionClass || call;
+    return this == &JSFunction::class_ || call;
 }
 
 #endif /* jsfuninlines_h */
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -68,17 +68,17 @@ GetGCObjectKind(size_t numSlots)
     if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
         return FINALIZE_OBJECT16;
     return slotsToThingKind[numSlots];
 }
 
 static inline AllocKind
 GetGCObjectKind(Class *clasp)
 {
-    if (clasp == &FunctionClass)
+    if (clasp == FunctionClassPtr)
         return JSFunction::FinalizeKind;
     uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
     if (clasp->flags & JSCLASS_HAS_PRIVATE)
         nslots++;
     return GetGCObjectKind(nslots);
 }
 
 /* As for GetGCObjectKind, but for dense array allocation. */
@@ -166,17 +166,17 @@ GetGCKindSlots(AllocKind thingKind, Clas
         JS_ASSERT(nslots > 0);
         nslots--;
     }
 
     /*
      * Functions have a larger finalize kind than FINALIZE_OBJECT to reserve
      * space for the extra fields in JSFunction, but have no fixed slots.
      */
-    if (clasp == &FunctionClass)
+    if (clasp == FunctionClassPtr)
         nslots = 0;
 
     return nslots;
 }
 
 #ifdef JSGC_GENERATIONAL
 inline bool
 ShouldNurseryAllocate(const Nursery &nursery, AllocKind kind, InitialHeap heap)
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1383,38 +1383,38 @@ TypeConstraintCall::newType(JSContext *c
         return;
     }
 
     RootedFunction callee(cx);
 
     if (type.isSingleObject()) {
         RootedObject obj(cx, type.singleObject());
 
-        if (!obj->isFunction()) {
+        if (!obj->is<JSFunction>()) {
             /* Calls on non-functions are dynamically monitored. */
             return;
         }
 
-        if (obj->toFunction()->isNative()) {
+        if (obj->as<JSFunction>().isNative()) {
             /*
              * The return value and all side effects within native calls should
              * be dynamically monitored, except when the compiler is generating
              * specialized inline code or stub calls for a specific natives and
              * knows about the behavior of that native.
              */
             cx->compartment()->types.monitorBytecode(cx, script, pc - script->code, true);
 
             /*
              * Add type constraints capturing the possible behavior of
              * specialized natives which operate on properties. :XXX: use
              * better factoring for both this and the compiler code itself
              * which specializes particular natives.
              */
 
-            Native native = obj->toFunction()->native();
+            Native native = obj->as<JSFunction>().native();
 
             if (native == js::array_push) {
                 for (size_t i = 0; i < callsite->argumentCount; i++) {
                     callsite->thisTypes->addSetProperty(cx, script, pc,
                                                         callsite->argumentTypes[i], JSID_VOID);
                 }
             }
 
@@ -1455,17 +1455,17 @@ TypeConstraintCall::newType(JSContext *c
                     return;
 
                 callsite->returnTypes->addType(cx, Type::ObjectType(res));
             }
 
             return;
         }
 
-        callee = obj->toFunction();
+        callee = &obj->as<JSFunction>();
     } else if (type.isTypeObject()) {
         callee = type.typeObject()->interpretedFunction;
         if (!callee)
             return;
     } else {
         /* Calls on non-objects are dynamically monitored. */
         return;
     }
@@ -1542,19 +1542,19 @@ TypeConstraintPropagateThis::newType(JSC
         return;
     }
 
     /* Ignore calls to natives, these will be handled by TypeConstraintCall. */
     RootedFunction callee(cx);
 
     if (type.isSingleObject()) {
         RootedObject object(cx, type.singleObject());
-        if (!object->isFunction() || !object->toFunction()->isInterpreted())
+        if (!object->is<JSFunction>() || !object->as<JSFunction>().isInterpreted())
             return;
-        callee = object->toFunction();
+        callee = &object->as<JSFunction>();
     } else if (type.isTypeObject()) {
         TypeObject *object = type.typeObject();
         if (!object->interpretedFunction)
             return;
         callee = object->interpretedFunction;
     } else {
         /* Ignore calls to primitives, these will go through a stub. */
         return;
@@ -2341,17 +2341,17 @@ TypeObject *
 TypeCompartment::newTypeObject(JSContext *cx, Class *clasp, Handle<TaggedProto> proto, bool unknown)
 {
     JS_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
 
     TypeObject *object = gc::NewGCThing<TypeObject, CanGC>(cx, gc::FINALIZE_TYPE_OBJECT,
                                                            sizeof(TypeObject), gc::TenuredHeap);
     if (!object)
         return NULL;
-    new(object) TypeObject(clasp, proto, clasp == &FunctionClass, unknown);
+    new(object) TypeObject(clasp, proto, clasp == &JSFunction::class_, unknown);
 
     if (!cx->typeInferenceEnabled())
         object->flags |= OBJECT_FLAG_UNKNOWN_MASK;
 
     return object;
 }
 
 static inline jsbytecode *
@@ -4379,20 +4379,23 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_LAMBDA: {
         RootedObject obj(cx, script->getObject(GET_UINT32_INDEX(pc)));
         TypeSet *res = &pushed[0];
 
         // If the lambda may produce values with different types than the
         // original function, despecialize the type produced here. This includes
         // functions that are deep cloned at each lambda, as well as inner
         // functions to run-once lambdas which may actually execute multiple times.
-        if (script->compileAndGo && !script->treatAsRunOnce && !UseNewTypeForClone(obj->toFunction()))
+        if (script->compileAndGo && !script->treatAsRunOnce &&
+            !UseNewTypeForClone(&obj->as<JSFunction>()))
+        {
             res->addType(cx, Type::ObjectType(obj));
-        else
+        } else {
             res->addType(cx, Type::AnyObjectType());
+        }
         break;
       }
 
       case JSOP_DEFFUN:
         cx->compartment()->types.monitorBytecode(cx, script, offset);
         break;
 
       case JSOP_DEFVAR:
@@ -5140,27 +5143,27 @@ AnalyzePoppedThis(JSContext *cx, SSAUseC
         StackTypeSet *funcallTypes = analysis->poppedTypes(pc, GET_ARGC(pc) + 1);
         StackTypeSet *scriptTypes = analysis->poppedTypes(pc, GET_ARGC(pc));
 
         /* Need to definitely be calling Function.call/apply on a specific script. */
         RootedFunction function(cx);
         {
             JSObject *funcallObj = funcallTypes->getSingleton();
             JSObject *scriptObj = scriptTypes->getSingleton();
-            if (!funcallObj || !funcallObj->isFunction() ||
-                funcallObj->toFunction()->isInterpreted() ||
-                !scriptObj || !scriptObj->isFunction() ||
-                !scriptObj->toFunction()->isInterpreted())
+            if (!funcallObj || !funcallObj->is<JSFunction>() ||
+                funcallObj->as<JSFunction>().isInterpreted() ||
+                !scriptObj || !scriptObj->is<JSFunction>() ||
+                !scriptObj->as<JSFunction>().isInterpreted())
             {
                 return false;
             }
-            Native native = funcallObj->toFunction()->native();
+            Native native = funcallObj->as<JSFunction>().native();
             if (native != js_fun_call && native != js_fun_apply)
                 return false;
-            function = scriptObj->toFunction();
+            function = &scriptObj->as<JSFunction>();
         }
 
         /*
          * Generate constraints to clear definite properties from the type
          * should the Function.call or callee itself change in the future.
          */
         funcallTypes->add(cx,
             cx->analysisLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
@@ -5479,18 +5482,18 @@ types::MarkIteratorUnknownSlow(JSContext
             analysis->pushedTypes(pc, 0)->addType(cx, Type::UnknownType());
     }
 }
 
 void
 types::TypeMonitorCallSlow(JSContext *cx, JSObject *callee, const CallArgs &args,
                            bool constructing)
 {
-    unsigned nargs = callee->toFunction()->nargs;
-    JSScript *script = callee->toFunction()->nonLazyScript();
+    unsigned nargs = callee->as<JSFunction>().nargs;
+    JSScript *script = callee->as<JSFunction>().nonLazyScript();
 
     if (!constructing)
         TypeScript::SetThis(cx, script, args.thisv());
 
     /*
      * Add constraints going up to the minimum of the actual and formal count.
      * If there are more actuals than formals the later values can only be
      * accessed through the arguments object, which is monitored.
@@ -5827,17 +5830,18 @@ JSFunction::setTypeForScriptedFunction(J
     if (!cx->typeInferenceEnabled())
         return true;
 
     if (singleton) {
         if (!setSingletonType(cx, fun))
             return false;
     } else {
         RootedObject funProto(cx, fun->getProto());
-        TypeObject *type = cx->compartment()->types.newTypeObject(cx, &FunctionClass, funProto);
+        TypeObject *type =
+            cx->compartment()->types.newTypeObject(cx, &JSFunction::class_, funProto);
         if (!type)
             return false;
 
         fun->setType(type);
         type->interpretedFunction = fun;
     }
 
     return true;
@@ -5928,18 +5932,18 @@ JSObject::splicePrototype(JSContext *cx,
 
 /* static */ TypeObject *
 JSObject::makeLazyType(JSContext *cx, HandleObject obj)
 {
     JS_ASSERT(obj->hasLazyType());
     JS_ASSERT(cx->compartment() == obj->compartment());
 
     /* De-lazification of functions can GC, so we need to do it up here. */
-    if (obj->isFunction() && obj->toFunction()->isInterpretedLazy()) {
-        RootedFunction fun(cx, obj->toFunction());
+    if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) {
+        RootedFunction fun(cx, &obj->as<JSFunction>());
         if (!fun->getOrCreateScript(cx))
             return NULL;
     }
     Rooted<TaggedProto> proto(cx, obj->getTaggedProto());
     TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto);
     if (!type) {
         if (cx->typeInferenceEnabled())
             cx->compartment()->types.setPendingNukeTypes(cx);
@@ -5953,18 +5957,18 @@ JSObject::makeLazyType(JSContext *cx, Ha
     }
 
     AutoEnterAnalysis enter(cx);
 
     /* Fill in the type according to the state of this object. */
 
     type->singleton = obj;
 
-    if (obj->isFunction() && obj->toFunction()->isInterpreted())
-        type->interpretedFunction = obj->toFunction();
+    if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
+        type->interpretedFunction = &obj->as<JSFunction>();
 
     if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
         type->flags |= OBJECT_FLAG_ITERATED;
 
     if (obj->getClass()->emulatesUndefined())
         type->flags |= OBJECT_FLAG_EMULATES_UNDEFINED;
 
     /*
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -546,18 +546,18 @@ void TypeMonitorCallSlow(JSContext *cx, 
 
 /*
  * Monitor a javascript call, either on entry to the interpreter or made
  * from within the interpreter.
  */
 inline void
 TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
 {
-    if (args.callee().isFunction()) {
-        JSFunction *fun = args.callee().toFunction();
+    if (args.callee().is<JSFunction>()) {
+        JSFunction *fun = &args.callee().as<JSFunction>();
         if (fun->isInterpreted() && fun->nonLazyScript()->types && cx->typeInferenceEnabled())
             TypeMonitorCallSlow(cx, &args.callee(), args, constructing);
     }
 }
 
 inline bool
 TrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
 {
--- a/js/src/jsmemorymetrics.cpp
+++ b/js/src/jsmemorymetrics.cpp
@@ -168,17 +168,17 @@ StatsCellCallback(JSRuntime *rt, void *d
 {
     IteratorClosure *closure = static_cast<IteratorClosure *>(data);
     RuntimeStats *rtStats = closure->rtStats;
     ZoneStats *zStats = rtStats->currZoneStats;
     switch (traceKind) {
       case JSTRACE_OBJECT: {
         JSObject *obj = static_cast<JSObject *>(thing);
         CompartmentStats *cStats = GetCompartmentStats(obj->compartment());
-        if (obj->isFunction())
+        if (obj->is<JSFunction>())
             cStats->gcHeapObjectsFunction += thingSize;
         else if (obj->isArray())
             cStats->gcHeapObjectsDenseArray += thingSize;
         else if (obj->isCrossCompartmentWrapper())
             cStats->gcHeapObjectsCrossCompartmentWrapper += thingSize;
         else
             cStats->gcHeapObjectsOrdinary += thingSize;
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1229,27 +1229,27 @@ JSObject::className(JSContext *cx, Handl
  * Get the GC kind to use for scripted 'new' on the given class.
  * FIXME bug 547327: estimate the size from the allocation site.
  */
 static inline gc::AllocKind
 NewObjectGCKind(js::Class *clasp)
 {
     if (clasp == &ArrayClass)
         return gc::FINALIZE_OBJECT8;
-    if (clasp == &FunctionClass)
+    if (clasp == &JSFunction::class_)
         return gc::FINALIZE_OBJECT2;
     return gc::FINALIZE_OBJECT4;
 }
 
 static inline JSObject *
 NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *parent,
           gc::AllocKind kind, NewObjectKind newKind)
 {
     JS_ASSERT(clasp != &ArrayClass);
-    JS_ASSERT_IF(clasp == &FunctionClass,
+    JS_ASSERT_IF(clasp == &JSFunction::class_,
                  kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
     JS_ASSERT_IF(parent, &parent->global() == cx->compartment()->maybeGlobal());
 
     RootedTypeObject type(cx, type_);
 
     RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(type->proto),
                                                       parent, NewObjectMetadata(cx), kind));
     if (!shape)
@@ -1533,27 +1533,27 @@ CreateThisForFunctionWithType(JSContext 
 
 JSObject *
 js::CreateThisForFunctionWithProto(JSContext *cx, HandleObject callee, JSObject *proto,
                                   NewObjectKind newKind /* = GenericObject */)
 {
     JSObject *res;
 
     if (proto) {
-        RootedTypeObject type(cx, proto->getNewType(cx, &ObjectClass, callee->toFunction()));
+        RootedTypeObject type(cx, proto->getNewType(cx, &ObjectClass, &callee->as<JSFunction>()));
         if (!type)
             return NULL;
         res = CreateThisForFunctionWithType(cx, type, callee->getParent(), newKind);
     } else {
         gc::AllocKind allocKind = NewObjectGCKind(&ObjectClass);
         res = NewObjectWithClassProto(cx, &ObjectClass, proto, callee->getParent(), allocKind, newKind);
     }
 
     if (res && cx->typeInferenceEnabled()) {
-        JSScript *script = callee->toFunction()->nonLazyScript();
+        JSScript *script = callee->as<JSFunction>().nonLazyScript();
         TypeScript::SetThis(cx, script, types::Type::ObjectType(res));
     }
 
     return res;
 }
 
 JSObject *
 js::CreateThisForFunction(JSContext *cx, HandleObject callee, bool newType)
@@ -1570,17 +1570,17 @@ js::CreateThisForFunction(JSContext *cx,
     JSObject *obj = CreateThisForFunctionWithProto(cx, callee, proto, newKind);
 
     if (obj && newType) {
         RootedObject nobj(cx, obj);
 
         /* Reshape the singleton before passing it as the 'this' value. */
         JSObject::clear(cx, nobj);
 
-        JSScript *calleeScript = callee->toFunction()->nonLazyScript();
+        JSScript *calleeScript = callee->as<JSFunction>().nonLazyScript();
         TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(nobj));
 
         return nobj;
     }
 
     return obj;
 }
 
@@ -1777,17 +1777,17 @@ js::CloneObject(JSContext *cx, HandleObj
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_CANT_CLONE_OBJECT);
         return NULL;
     }
     RootedObject clone(cx, NewObjectWithGivenProto(cx, obj->getClass(), proto, parent));
     if (!clone)
         return NULL;
     if (obj->isNative()) {
-        if (clone->isFunction() && (obj->compartment() != clone->compartment())) {
+        if (clone->is<JSFunction>() && (obj->compartment() != clone->compartment())) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_CANT_CLONE_OBJECT);
             return NULL;
         }
 
         if (obj->hasPrivate())
             clone->setPrivate(obj->getPrivate());
     } else {
@@ -1953,28 +1953,28 @@ JSObject::ReserveForTradeGuts(JSContext 
 
     return true;
 }
 
 void
 JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &reserved)
 {
     JS_ASSERT(a->compartment() == b->compartment());
-    JS_ASSERT(a->isFunction() == b->isFunction());
+    JS_ASSERT(a->is<JSFunction>() == b->is<JSFunction>());
 
     /*
      * Swap the object's types, to restore their initial type information.
      * The prototypes and classes of the objects were swapped in ReserveForTradeGuts.
      */
     TypeObject *tmp = a->type_;
     a->type_ = b->type_;
     b->type_ = tmp;
 
     /* Don't try to swap a JSFunction for a plain function JSObject. */
-    JS_ASSERT_IF(a->isFunction(), a->tenuredSizeOfThis() == b->tenuredSizeOfThis());
+    JS_ASSERT_IF(a->is<JSFunction>(), a->tenuredSizeOfThis() == b->tenuredSizeOfThis());
 
     /*
      * Regexp guts are more complicated -- we would need to migrate the
      * refcounted JIT code blob for them across compartments instead of just
      * swapping guts.
      */
     JS_ASSERT(!a->is<RegExpObject>() && !b->is<RegExpObject>());
 
@@ -2194,22 +2194,22 @@ js::DefineConstructorAndPrototype(JSCont
      * 1. NewObject attempting to compute a default prototype object when
      *    passed null for proto; and
      *
      * 2. NewObject tolerating no default prototype (null proto slot value)
      *    due to this js_InitClass call coming from js_InitFunctionClass on an
      *    otherwise-uninitialized global.
      *
      * 3. NewObject allocating a JSFunction-sized GC-thing when clasp is
-     *    &FunctionClass, not a JSObject-sized (smaller) GC-thing.
+     *    &JSFunction::class_, not a JSObject-sized (smaller) GC-thing.
      *
      * The JS_NewObjectForGivenProto and JS_NewObject APIs also allow clasp to
-     * be &FunctionClass (we could break compatibility easily). But fixing
-     * (3) is not enough without addressing the bootstrapping dependency on (1)
-     * and (2).
+     * be &JSFunction::class_ (we could break compatibility easily). But
+     * fixing (3) is not enough without addressing the bootstrapping dependency
+     * on (1) and (2).
      */
 
     /*
      * Create the prototype object.  (GlobalObject::createBlankPrototype isn't
      * used because it parents the prototype object to the global and because
      * it uses WithProto::Given.  FIXME: Undo dependencies on this parentage
      * [which already needs to happen for bug 638316], figure out nicer
      * semantics for null-protoProto, and use createBlankPrototype.)
@@ -5012,18 +5012,18 @@ dumpValue(const Value &v)
     else if (v.isUndefined())
         fprintf(stderr, "undefined");
     else if (v.isInt32())
         fprintf(stderr, "%d", v.toInt32());
     else if (v.isDouble())
         fprintf(stderr, "%g", v.toDouble());
     else if (v.isString())
         v.toString()->dump();
-    else if (v.isObject() && v.toObject().isFunction()) {
-        JSFunction *fun = v.toObject().toFunction();
+    else if (v.isObject() && v.toObject().is<JSFunction>()) {
+        JSFunction *fun = &v.toObject().as<JSFunction>();
         if (fun->displayAtom()) {
             fputs("<function ", stderr);
             FileEscapedString(stderr, fun->displayAtom(), 0);
         } else {
             fputs("<unnamed function", stderr);
         }
         if (fun->hasScript()) {
             JSScript *script = fun->nonLazyScript();
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -640,25 +640,16 @@ class JSObject : public js::ObjectImpl
     static const uint32_t JSSLOT_DATE_LOCAL_MINUTES = JSSLOT_DATE_COMPONENTS_START + 6;
     static const uint32_t JSSLOT_DATE_LOCAL_SECONDS = JSSLOT_DATE_COMPONENTS_START + 7;
 
     static const uint32_t DATE_CLASS_RESERVED_SLOTS = JSSLOT_DATE_LOCAL_SECONDS + 1;
 
     inline const js::Value &getDateUTCTime() const;
     inline void setDateUTCTime(const js::Value &pthis);
 
-    /*
-     * Function-specific getters and setters.
-     */
-
-    friend class JSFunction;
-
-    inline JSFunction *toFunction();
-    inline const JSFunction *toFunction() const;
-
   public:
     /*
      * Iterator-specific getters and setters.
      */
 
     static const uint32_t ITER_CLASS_NFIXED_SLOTS = 1;
 
     /*
@@ -933,17 +924,16 @@ class JSObject : public js::ObjectImpl
         JS_ASSERT(is<T>());
         return *static_cast<const T *>(this);
     }
 
     /* Direct subtypes of JSObject: */
     inline bool isArray()            const { return hasClass(&js::ArrayClass); }
     inline bool isDate()             const { return hasClass(&js::DateClass); }
     inline bool isError()            const { return hasClass(&js::ErrorClass); }
-    inline bool isFunction()         const { return hasClass(&js::FunctionClass); }
     inline bool isObject()           const { return hasClass(&js::ObjectClass); }
     using js::ObjectImpl::isProxy;
     inline bool isRegExpStatics()    const { return hasClass(&js::RegExpStaticsClass); }
     inline bool isTypedArray()       const;
 
     /* Subtypes of Proxy. */
     inline bool isWrapper()                 const;
     inline bool isFunctionProxy()           const { return hasClass(&js::FunctionProxyClass); }
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1245,24 +1245,24 @@ GetOuterObject(JSContext *cx, HandleObje
     if (JSObjectOp op = obj->getClass()->ext.outerObject)
         return op(cx, obj);
     return obj;
 }
 
 static JS_ALWAYS_INLINE bool
 IsFunctionObject(const js::Value &v)
 {
-    return v.isObject() && v.toObject().isFunction();
+    return v.isObject() && v.toObject().is<JSFunction>();
 }
 
 static JS_ALWAYS_INLINE bool
 IsFunctionObject(const js::Value &v, JSFunction **fun)
 {
-    if (v.isObject() && v.toObject().isFunction()) {
-        *fun = v.toObject().toFunction();
+    if (v.isObject() && v.toObject().is<JSFunction>()) {
+        *fun = &v.toObject().as<JSFunction>();
         return true;
     }
     return false;
 }
 
 static JS_ALWAYS_INLINE bool
 IsNativeFunction(const js::Value &v)
 {
@@ -1352,17 +1352,17 @@ ToPrimitive(JSContext *cx, JSType prefer
 /*
  * Return true if this is a compiler-created internal function accessed by
  * its own object. Such a function object must not be accessible to script
  * or embedding code.
  */
 inline bool
 IsInternalFunctionObject(JSObject *funobj)
 {
-    JSFunction *fun = funobj->toFunction();
+    JSFunction *fun = &funobj->as<JSFunction>();
     return fun->isLambda() && !funobj->getParent();
 }
 
 class AutoPropDescArrayRooter : private AutoGCRooter
 {
   public:
     AutoPropDescArrayRooter(JSContext *cx)
       : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx), skip(cx, &descriptors)
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -505,18 +505,18 @@ ToDisassemblySource(JSContext *cx, jsval
 
             source = JS_sprintf_append(source, "}");
             if (!source)
                 return false;
             bytes->initBytes(source);
             return true;
         }
 
-        if (obj->isFunction()) {
-            JSString *str = JS_DecompileFunction(cx, obj->toFunction(), JS_DONT_PRETTY_PRINT);
+        if (obj->is<JSFunction>()) {
+            JSString *str = JS_DecompileFunction(cx, &obj->as<JSFunction>(), JS_DONT_PRETTY_PRINT);
             if (!str)
                 return false;
             return bytes->encodeLatin1(cx, str);
         }
 
         if (obj->is<RegExpObject>()) {
             JSString *source = obj->as<RegExpObject>().toString(cx);
             if (!source)
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1038,17 +1038,17 @@ ScriptedIndirectProxyHandler::nativeCall
 }
 
 JSString *
 ScriptedIndirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent)
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID);
     Value fval = GetCall(proxy);
     if (IsFunctionProxy(proxy) &&
-        (fval.isPrimitive() || !fval.toObject().isFunction())) {
+        (fval.isPrimitive() || !fval.toObject().is<JSFunction>())) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_INCOMPATIBLE_PROTO,
                              js_Function_str, js_toString_str,
                              "object");
         return NULL;
     }
     RootedObject obj(cx, &fval.toObject());
     return fun_toStringHelper(cx, obj, indent);
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -175,17 +175,17 @@ class NodeBuilder
             if (!baseops::GetPropertyDefault(cx, userobj, id, nullVal, &funv))
                 return false;
 
             if (funv.isNullOrUndefined()) {
                 callbacks[i].setNull();
                 continue;
             }
 
-            if (!funv.isObject() || !funv.toObject().isFunction()) {
+            if (!funv.isObject() || !funv.toObject().is<JSFunction>()) {
                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NOT_FUNCTION,
                                          JSDVG_SEARCH_STACK, funv, NullPtr(), NULL, NULL);
                 return false;
             }
 
             callbacks[i] = funv;
         }
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -657,26 +657,26 @@ js::XDRScript(XDRState<mode> *xdr, Handl
      * all references to enclosing blocks (via FindBlockIndex below) happen
      * after the enclosing block has been XDR'd.
      */
     for (i = 0; i != nobjects; ++i) {
         HeapPtr<JSObject> *objp = &script->objects()->vector[i];
         uint32_t isBlock;
         if (mode == XDR_ENCODE) {
             JSObject *obj = *objp;
-            JS_ASSERT(obj->isFunction() || obj->is<StaticBlockObject>());
+            JS_ASSERT(obj->is<JSFunction>() || obj->is<StaticBlockObject>());
             isBlock = obj->is<BlockObject>() ? 1 : 0;
         }
         if (!xdr->codeUint32(&isBlock))
             return false;
         if (isBlock == 0) {
             /* Code the nested function's enclosing scope. */
             uint32_t funEnclosingScopeIndex = 0;
             if (mode == XDR_ENCODE) {
-                JSScript *innerScript = (*objp)->toFunction()->getOrCreateScript(cx);
+                JSScript *innerScript = (*objp)->as<JSFunction>().getOrCreateScript(cx);
                 if (!innerScript)
                     return false;
                 RootedObject staticScope(cx, innerScript->enclosingStaticScope());
                 StaticScopeIter ssi(cx, staticScope);
                 if (ssi.done() || ssi.type() == StaticScopeIter::FUNCTION) {
                     JS_ASSERT(ssi.done() == !fun);
                     funEnclosingScopeIndex = UINT32_MAX;
                 } else {
@@ -1981,18 +1981,18 @@ JSScript::enclosingScriptsCompiledSucces
      * When a nested script is succesfully compiled, it is eagerly given the
      * static JSFunction of its enclosing script. The enclosing function's
      * 'script' field will be NULL until the enclosing script successfully
      * compiles. Thus, we can detect failed compilation by looking for
      * JSFunctions in the enclosingScope chain without scripts.
      */
     JSObject *enclosing = enclosingStaticScope();
     while (enclosing) {
-        if (enclosing->isFunction()) {
-            JSFunction *fun = enclosing->toFunction();
+        if (enclosing->is<JSFunction>()) {
+            JSFunction *fun = &enclosing->as<JSFunction>();
             if (!fun->hasScript() || !fun->nonLazyScript())
                 return false;
             enclosing = fun->nonLazyScript()->enclosingStaticScope();
         } else {
             enclosing = enclosing->as<StaticBlockObject>().enclosingStaticScope();
         }
     }
     return true;
@@ -2311,18 +2311,18 @@ js::CloneScript(JSContext *cx, HandleObj
 
                 RootedObject enclosingScope(cx);
                 if (StaticBlockObject *enclosingBlock = innerBlock->enclosingBlock())
                     enclosingScope = objects[FindBlockIndex(src, *enclosingBlock)];
                 else
                     enclosingScope = fun;
 
                 clone = CloneStaticBlockObject(cx, enclosingScope, innerBlock);
-            } else if (obj->isFunction()) {
-                RootedFunction innerFun(cx, obj->toFunction());
+            } else if (obj->is<JSFunction>()) {
+                RootedFunction innerFun(cx, &obj->as<JSFunction>());
                 if (innerFun->isNative()) {
                     assertSameCompartment(cx, innerFun);
                     clone = innerFun;
                 } else {
                     if (innerFun->isInterpretedLazy()) {
                         AutoCompartment ac(cx, innerFun);
                         if (!innerFun->getOrCreateScript(cx))
                             return NULL;
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -91,22 +91,21 @@ JSScript::setFunction(JSFunction *fun)
 {
     JS_ASSERT(fun->isTenured());
     function_ = fun;
 }
 
 inline JSFunction *
 JSScript::getFunction(size_t index)
 {
-    JSObject *funobj = getObject(index);
+    JSFunction *fun = &getObject(index)->as<JSFunction>();
 #ifdef DEBUG
-    JSFunction *fun = funobj->toFunction();
     JS_ASSERT_IF(fun->isNative(), IsAsmJSModuleNative(fun->native()));
 #endif
-    return funobj->toFunction();
+    return fun;
 }
 
 inline JSFunction *
 JSScript::getCallerFunction()
 {
     JS_ASSERT(savedCallerFun);
     return getFunction(0);
 }
@@ -197,19 +196,19 @@ JSScript::principals()
 {
     return compartment()->principals;
 }
 
 inline JSFunction *
 JSScript::originalFunction() const {
     if (!isCallsiteClone)
         return NULL;
-    return enclosingScopeOrOriginalFunction_->toFunction();
+    return &enclosingScopeOrOriginalFunction_->as<JSFunction>();
 }
 
 inline void
 JSScript::setOriginalFunctionObject(JSObject *fun) {
     JS_ASSERT(isCallsiteClone);
-    JS_ASSERT(fun->isFunction());
+    JS_ASSERT(fun->is<JSFunction>());
     enclosingScopeOrOriginalFunction_ = fun;
 }
 
 #endif /* jsscriptinlines_h */
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -38,16 +38,17 @@
 #include "jsopcode.h"
 #include "jsversion.h"
 
 #include "builtin/RegExp.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
 #include "vm/RegExpObject.h"
+#include "vm/ScopeObject.h"
 #include "vm/Shape.h"
 #include "vm/StringBuffer.h"
 
 #include "jsinferinlines.h"
 #include "jsstrinlines.h"
 #include "jsautooplen.h"        // generated headers last
 
 #include "vm/Interpreter-inl.h"
@@ -2685,20 +2686,20 @@ static const uint32_t ReplaceOptArg = 2;
  * object, e.g. 'function(a) { return b[a]; }'. Avoid calling the script in
  * such cases, which are used by javascript packers (particularly the popular
  * Dean Edwards packer) to efficiently encode large scripts. We only handle the
  * code patterns generated by such packers here.
  */
 static bool
 LambdaIsGetElem(JSContext *cx, JSObject &lambda, MutableHandleObject pobj)
 {
-    if (!lambda.isFunction())
+    if (!lambda.is<JSFunction>())
         return true;
 
-    JSFunction *fun = lambda.toFunction();
+    JSFunction *fun = &lambda.as<JSFunction>();
     if (!fun->isInterpreted())
         return true;
 
     JSScript *script = fun->getOrCreateScript(cx);
     if (!script)
         return false;
 
     jsbytecode *pc = script->code;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1435,18 +1435,18 @@ ValueToScript(JSContext *cx, jsval v, JS
 {
     RootedFunction fun(cx, JS_ValueToFunction(cx, v));
     if (!fun)
         return NULL;
 
     // Unwrap bound functions.
     while (fun->isBoundFunction()) {
         JSObject *target = fun->getBoundFunctionTarget();
-        if (target && target->isFunction())
-            fun = target->toFunction();
+        if (target && target->is<JSFunction>())
+            fun = &target->as<JSFunction>();
         else
             break;
     }
 
     if (!fun->isInterpreted()) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_SCRIPTS_ONLY);
         return NULL;
     }
@@ -1489,17 +1489,17 @@ GetScriptAndPCArgs(JSContext *cx, unsign
                    int32_t *ip)
 {
     RootedScript script(cx, GetTopScript(cx));
     *ip = 0;
     if (argc != 0) {
         jsval v = argv[0];
         unsigned intarg = 0;
         if (!JSVAL_IS_PRIMITIVE(v) &&
-            JS_GetClass(&v.toObject()) == Jsvalify(&FunctionClass)) {
+            JS_GetClass(&v.toObject()) == Jsvalify(&JSFunction::class_)) {
             script = ValueToScript(cx, v);
             if (!script)
                 return false;
             intarg++;
         }
         if (argc > intarg) {
             if (!JS_ValueToInt32(cx, argv[intarg], ip))
                 return false;
@@ -1645,17 +1645,17 @@ LineToPC(JSContext *cx, unsigned argc, j
 
     if (args.length() == 0) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
         return false;
     }
     script = GetTopScript(cx);
     jsval v = args[0];
     if (!JSVAL_IS_PRIMITIVE(v) &&
-        JS_GetClass(&v.toObject()) == Jsvalify(&FunctionClass))
+        JS_GetClass(&v.toObject()) == Jsvalify(&JSFunction::class_))
     {
         script = ValueToScript(cx, v);
         if (!script)
             return false;
         lineArg++;
     }
     if (!JS_ValueToECMAUint32(cx, args[lineArg], &lineno))
         return false;
@@ -1889,19 +1889,19 @@ DisassembleScript(JSContext *cx, HandleS
         return false;
     SrcNotes(cx, script, sp);
     TryNotes(cx, script, sp);
 
     if (recursive && script->hasObjects()) {
         ObjectArray *objects = script->objects();
         for (unsigned i = 0; i != objects->length; ++i) {
             JSObject *obj = objects->vector[i];
-            if (obj->isFunction()) {
+            if (obj->is<JSFunction>()) {
                 Sprint(sp, "\n");
-                RootedFunction fun(cx, obj->toFunction());
+                RootedFunction fun(cx, &obj->as<JSFunction>());
                 if (fun->isInterpreted()) {
                     RootedScript script(cx, fun->getOrCreateScript(cx));
                     if (!script || !DisassembleScript(cx, script, fun, lines, recursive, sp))
                         return false;
                 } else {
                     Sprint(sp, "[native code]\n");
                 }
             }
@@ -2317,27 +2317,27 @@ Clone(JSContext *cx, unsigned argc, jsva
         Maybe<JSAutoCompartment> ac;
         RootedObject obj(cx, JSVAL_IS_PRIMITIVE(args[0]) ? NULL : &args[0].toObject());
 
         if (obj && IsCrossCompartmentWrapper(obj)) {
             obj = UncheckedUnwrap(obj);
             ac.construct(cx, obj);
             args[0] = ObjectValue(*obj);
         }
-        if (obj && obj->isFunction()) {
+        if (obj && obj->is<JSFunction>()) {
             funobj = obj;
         } else {
             JSFunction *fun = JS_ValueToFunction(cx, args[0]);
             if (!fun)
                 return false;
             funobj = JS_GetFunctionObject(fun);
         }
     }
     if (funobj->compartment() != cx->compartment()) {
-        JSFunction *fun = funobj->toFunction();
+        JSFunction *fun = &funobj->as<JSFunction>();
         if (fun->hasScript() && fun->nonLazyScript()->compileAndGo) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                                  "function", "compile-and-go");
             return false;
         }
     }
 
     if (argc > 1) {
@@ -3057,17 +3057,17 @@ Timeout(JSContext *cx, unsigned argc, js
     }
 
     double t;
     if (!JS_ValueToNumber(cx, JS_ARGV(cx, vp)[0], &t))
         return false;
 
     if (argc > 1) {
         RootedValue value(cx, JS_ARGV(cx, vp)[1]);
-        if (!value.isObject() || !value.toObject().isFunction()) {
+        if (!value.isObject() || !value.toObject().is<JSFunction>()) {
             JS_ReportError(cx, "Second argument must be a timeout function");
             return false;
         }
         gTimeoutFunc = value;
     }
 
     JS_SET_RVAL(cx, vp, UndefinedValue());
     return SetTimeoutValue(cx, t);
@@ -3325,21 +3325,21 @@ System(JSContext *cx, unsigned argc, jsv
     return true;
 }
 
 static bool
 DecompileFunctionSomehow(JSContext *cx, unsigned argc, Value *vp,
                          JSString *(*decompiler)(JSContext *, JSFunction *, unsigned))
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    if (args.length() < 1 || !args[0].isObject() || !args[0].toObject().isFunction()) {
+    if (args.length() < 1 || !args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
         args.rval().setUndefined();
         return true;
     }
-    JSString *result = decompiler(cx, args[0].toObject().toFunction(), 0);
+    JSString *result = decompiler(cx, &args[0].toObject().as<JSFunction>(), 0);
     if (!result)
         return false;
     args.rval().setString(result);
     return true;
 }
 
 static JSBool
 DecompileBody(JSContext *cx, unsigned argc, Value *vp)
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2899,17 +2899,17 @@ DebuggerScript_getChildScripts(JSContext
          * innerObjectsStart().
          */
         ObjectArray *objects = script->objects();
         RootedFunction fun(cx);
         RootedScript funScript(cx);
         RootedObject obj(cx), s(cx);
         for (uint32_t i = script->innerObjectsStart(); i < objects->length; i++) {
             obj = objects->vector[i];
-            if (obj->isFunction()) {
+            if (obj->is<JSFunction>()) {
                 fun = static_cast<JSFunction *>(obj.get());
                 funScript = fun->nonLazyScript();
                 s = dbg->wrapScript(cx, funScript);
                 if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s)))
                     return false;
             }
         }
     }
@@ -3848,17 +3848,17 @@ Class DebuggerArguments_class = {
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
 };
 
 /* The getter used for each element of frame.arguments. See DebuggerFrame_getArguments. */
 static JSBool
 DebuggerArguments_getArg(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    int32_t i = args.callee().toFunction()->getExtendedSlot(0).toInt32();
+    int32_t i = args.callee().as<JSFunction>().getExtendedSlot(0).toInt32();
 
     /* Check that the this value is an Arguments object. */
     if (!args.thisv().isObject()) {
         ReportObjectRequired(cx);
         return false;
     }
     RootedObject argsobj(cx, &args.thisv().toObject());
     if (argsobj->getClass() != &DebuggerArguments_class) {
@@ -4397,66 +4397,66 @@ DebuggerObject_getCallable(JSContext *cx
     args.rval().setBoolean(refobj->isCallable());
     return true;
 }
 
 static JSBool
 DebuggerObject_getName(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get name", args, dbg, obj);
-    if (!obj->isFunction()) {
+    if (!obj->is<JSFunction>()) {
         args.rval().setUndefined();
         return true;
     }
 
-    JSString *name = obj->toFunction()->atom();
+    JSString *name = obj->as<JSFunction>().atom();
     if (!name) {
         args.rval().setUndefined();
         return true;
     }
 
     RootedValue namev(cx, StringValue(name));
     if (!dbg->wrapDebuggeeValue(cx, &namev))
         return false;
     args.rval().set(namev);
     return true;
 }
 
 static JSBool
 DebuggerObject_getDisplayName(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get display name", args, dbg, obj);
-    if (!obj->isFunction()) {
+    if (!obj->is<JSFunction>()) {
         args.rval().setUndefined();
         return true;
     }
 
-    JSString *name = obj->toFunction()->displayAtom();
+    JSString *name = obj->as<JSFunction>().displayAtom();
     if (!name) {
         args.rval().setUndefined();
         return true;
     }
 
     RootedValue namev(cx, StringValue(name));
     if (!dbg->wrapDebuggeeValue(cx, &namev))
         return false;
     args.rval().set(namev);
     return true;
 }
 
 static JSBool
 DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get parameterNames", args, obj);
-    if (!obj->isFunction()) {
+    if (!obj->is<JSFunction>()) {
         args.rval().setUndefined();
         return true;
     }
 
-    RootedFunction fun(cx, obj->toFunction());
+    RootedFunction fun(cx, &obj->as<JSFunction>());
     JSObject *result = NewDenseAllocatedArray(cx, fun->nargs);
     if (!result)
         return false;
     result->ensureDenseInitializedLength(cx, 0, fun->nargs);
 
     if (fun->isInterpreted()) {
         JS_ASSERT(fun->nargs == fun->nonLazyScript()->bindings.numArgs());
 
@@ -4483,22 +4483,22 @@ DebuggerObject_getParameterNames(JSConte
     return true;
 }
 
 static JSBool
 DebuggerObject_getScript(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get script", args, dbg, obj);
 
-    if (!obj->isFunction()) {
+    if (!obj->is<JSFunction>()) {
         args.rval().setUndefined();
         return true;
     }
 
-    RootedFunction fun(cx, obj->toFunction());
+    RootedFunction fun(cx, &obj->as<JSFunction>());
     if (fun->isBuiltin()) {
         args.rval().setUndefined();
         return true;
     }
 
     RootedScript script(cx, fun->nonLazyScript());
     RootedObject scriptObject(cx, dbg->wrapScript(cx, script));
     if (!scriptObject)
@@ -4509,25 +4509,25 @@ DebuggerObject_getScript(JSContext *cx, 
 }
 
 static JSBool
 DebuggerObject_getEnvironment(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get environment", args, dbg, obj);
 
     /* Don't bother switching compartments just to check obj's type and get its env. */
-    if (!obj->isFunction() || !obj->toFunction()->isInterpreted()) {
+    if (!obj->is<JSFunction>() || !obj->as<JSFunction>().isInterpreted()) {
         args.rval().setUndefined();
         return true;
     }
 
     Rooted<Env*> env(cx);
     {
         AutoCompartment ac(cx, obj);
-        RootedFunction fun(cx, obj->toFunction());
+        RootedFunction fun(cx, &obj->as<JSFunction>());
         env = GetDebugScopeForFunction(cx, fun);
         if (!env)
             return false;
     }
 
     return dbg->wrapEnvironment(cx, env, args.rval());
 }
 
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -447,17 +447,17 @@ class AutoSetForkJoinSlice
 // parallel execution, and recovering from bailouts.
 
 static const char *ForkJoinModeString(ForkJoinMode mode);
 
 bool
 js::ForkJoin(JSContext *cx, CallArgs &args)
 {
     JS_ASSERT(args[0].isObject()); // else the self-hosted code is wrong
-    JS_ASSERT(args[0].toObject().isFunction());
+    JS_ASSERT(args[0].toObject().is<JSFunction>());
 
     ForkJoinMode mode = ForkJoinModeNormal;
     if (args.length() > 1) {
         JS_ASSERT(args[1].isInt32()); // else the self-hosted code is wrong
         JS_ASSERT(args[1].toInt32() < NumForkJoinModes);
         mode = (ForkJoinMode) args[1].toInt32();
     }
 
@@ -624,20 +624,20 @@ js::ParallelDo::apply()
 
 js::ParallelDo::TrafficLight
 js::ParallelDo::enqueueInitialScript(ExecutionStatus *status)
 {
     // GreenLight: script successfully enqueued if necessary
     // RedLight: fatal error or fell back to sequential
 
     // The kernel should be a self-hosted function.
-    if (!fun_->isFunction())
+    if (!fun_->is<JSFunction>())
         return sequentialExecution(true, status);
 
-    RootedFunction callee(cx_, fun_->toFunction());
+    RootedFunction callee(cx_, &fun_->as<JSFunction>());
 
     if (!callee->isInterpreted() || !callee->isSelfHostedBuiltin())
         return sequentialExecution(true, status);
 
     // If the main script is already compiled, and we have no reason
     // to suspect any of its callees are not compiled, then we can
     // just skip the compilation step.
     RootedScript script(cx_, callee->getOrCreateScript(cx_));
@@ -1208,17 +1208,17 @@ js::ParallelDo::recoverFromBailout(Execu
 
     bailouts += 1;
     determineBailoutCause();
 
     SpewBailout(bailouts, bailoutScript, bailoutBytecode, bailoutCause);
 
     // After any bailout, we always scan over callee list of main
     // function, if nothing else
-    RootedScript mainScript(cx_, fun_->toFunction()->nonLazyScript());
+    RootedScript mainScript(cx_, fun_->as<JSFunction>().nonLazyScript());
     if (!addToWorklist(mainScript))
         return fatalError(status);
 
     // Also invalidate and recompile any callees that were implicated
     // by the bailout
     if (!invalidateBailedOutScripts())
         return fatalError(status);
 
@@ -1457,18 +1457,18 @@ ForkJoinShared::executePortion(PerThread
 
     // Make a new IonContext for the slice, which is needed if we need to
     // re-enter the VM.
     IonContext icx(cx_->compartment(), NULL);
 
     JS_ASSERT(slice.bailoutRecord->topScript == NULL);
 
     RootedObject fun(perThread, fun_);
-    JS_ASSERT(fun->isFunction());
-    RootedFunction callee(perThread, fun->toFunction());
+    JS_ASSERT(fun->is<JSFunction>());
+    RootedFunction callee(perThread, &fun->as<JSFunction>());
     if (!callee->nonLazyScript()->hasParallelIonScript()) {
         // Sometimes, particularly with GCZeal, the parallel ion
         // script can be collected between starting the parallel
         // op and reaching this point.  In that case, we just fail
         // and fallback.
         Spew(SpewOps, "Down (Script no longer present)");
         slice.bailoutRecord->setCause(ParallelBailoutMainScriptNotPresent,
                                       NULL, NULL, NULL);
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -195,21 +195,21 @@ GlobalObject::initFunctionAndObjectClass
      * objects in JSON and script literals.
      */
     if (!setNewTypeUnknown(cx, &ObjectClass, objectProto))
         return NULL;
 
     /* Create |Function.prototype| next so we can create other functions. */
     RootedFunction functionProto(cx);
     {
-        JSObject *functionProto_ = NewObjectWithGivenProto(cx, &FunctionClass, objectProto, self,
-                                                           SingletonObject);
+        JSObject *functionProto_ = NewObjectWithGivenProto(cx, &JSFunction::class_,
+                                                           objectProto, self, SingletonObject);
         if (!functionProto_)
             return NULL;
-        functionProto = functionProto_->toFunction();
+        functionProto = &functionProto_->as<JSFunction>();
 
         /*
          * Bizarrely, |Function.prototype| must be an interpreted function, so
          * give it the guts to be one.
          */
         {
             JSObject *proto = NewFunction(cx, functionProto, NULL, 0, JSFunction::INTERPRETED,
                                           self, NullPtr());
@@ -255,25 +255,25 @@ GlobalObject::initFunctionAndObjectClass
         protoType->interpretedFunction = functionProto;
         script->setFunction(functionProto);
 
         /*
          * The default 'new' type of Function.prototype is required by type
          * inference to have unknown properties, to simplify handling of e.g.
          * CloneFunctionObject.
          */
-        if (!setNewTypeUnknown(cx, &FunctionClass, functionProto))
+        if (!setNewTypeUnknown(cx, &JSFunction::class_, functionProto))
             return NULL;
     }
 
     /* Create the Object function now that we have a [[Prototype]] for it. */
     RootedFunction objectCtor(cx);
     {
-        RootedObject ctor(cx, NewObjectWithGivenProto(cx, &FunctionClass, functionProto, self,
-                                                      SingletonObject));
+        RootedObject ctor(cx, NewObjectWithGivenProto(cx, &JSFunction::class_, functionProto,
+                                                      self, SingletonObject));
         if (!ctor)
             return NULL;
         RootedAtom objectAtom(cx, cx->names().Object);
         objectCtor = NewFunction(cx, ctor, obj_construct, 1, JSFunction::NATIVE_CTOR, self,
                                  objectAtom);
         if (!objectCtor)
             return NULL;
     }
@@ -283,18 +283,18 @@ GlobalObject::initFunctionAndObjectClass
      * code that looks for them.
      */
     self->setObjectClassDetails(objectCtor, objectProto);
 
     /* Create |Function| so it and |Function.prototype| can be installed. */
     RootedFunction functionCtor(cx);
     {
         // Note that ctor is rooted purely for the JS_ASSERT at the end
-        RootedObject ctor(cx, NewObjectWithGivenProto(cx, &FunctionClass, functionProto, self,
-                                                      SingletonObject));
+        RootedObject ctor(cx, NewObjectWithGivenProto(cx, &JSFunction::class_, functionProto,
+                                                      self, SingletonObject));
         if (!ctor)
             return NULL;
         RootedAtom functionAtom(cx, cx->names().Function);
         functionCtor = NewFunction(cx, ctor, Function, 1, JSFunction::NATIVE_CTOR, self,
                                    functionAtom);
         if (!functionCtor)
             return NULL;
         JS_ASSERT(ctor == functionCtor);
@@ -504,17 +504,17 @@ GlobalObject::createConstructor(JSContex
     RootedObject self(cx, this);
     return NewFunction(cx, NullPtr(), ctor, length, JSFunction::NATIVE_CTOR, self, name, kind);
 }
 
 static JSObject *
 CreateBlankProto(JSContext *cx, Class *clasp, JSObject &proto, GlobalObject &global)
 {
     JS_ASSERT(clasp != &ObjectClass);
-    JS_ASSERT(clasp != &FunctionClass);
+    JS_ASSERT(clasp != &JSFunction::class_);
 
     RootedObject blankProto(cx, NewObjectWithGivenProto(cx, clasp, &proto, &global, SingletonObject));
     if (!blankProto)
         return NULL;
 
     return blankProto;
 }
 
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -935,18 +935,18 @@ UrshOperation(JSContext *cx, HandleScrip
     return true;
 }
 
 #undef RELATIONAL_OP
 
 inline JSFunction *
 ReportIfNotFunction(JSContext *cx, const Value &v, MaybeConstruct construct = NO_CONSTRUCT)
 {
-    if (v.isObject() && v.toObject().isFunction())
-        return v.toObject().toFunction();
+    if (v.isObject() && v.toObject().is<JSFunction>())
+        return &v.toObject().as<JSFunction>();
 
     ReportIsNotFunction(cx, v, -1, construct);
     return NULL;
 }
 
 /*
  * FastInvokeGuard is used to optimize calls to JS functions from natives written
  * in C++, for instance Array.map. If the callee is not Ion-compiled, this will
@@ -973,18 +973,18 @@ class FastInvokeGuard
       , useIon_(ion::IsEnabled(cx))
 #endif
     {
         JS_ASSERT(!InParallelSection());
         initFunction(fval);
     }
 
     void initFunction(const Value &fval) {
-        if (fval.isObject() && fval.toObject().isFunction()) {
-            JSFunction *fun = fval.toObject().toFunction();
+        if (fval.isObject() && fval.toObject().is<JSFunction>()) {
+            JSFunction *fun = &fval.toObject().as<JSFunction>();
             if (fun->isInterpreted())
                 fun_ = fun;
         }
     }
 
     InvokeArgsGuard &args() {
         return args_;
     }
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -157,17 +157,17 @@ js::BoxNonStrictThis(JSContext *cx, cons
     /*
      * Check for SynthesizeFrame poisoning and fast constructors which
      * didn't check their callee properly.
      */
     RootedValue thisv(cx, call.thisv());
     JS_ASSERT(!thisv.isMagic());
 
 #ifdef DEBUG
-    JSFunction *fun = call.callee().isFunction() ? call.callee().toFunction() : NULL;
+    JSFunction *fun = call.callee().is<JSFunction>() ? &call.callee().as<JSFunction>() : NULL;
     JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->strict());
 #endif
 
     bool modified;
     if (!BoxNonStrictThis(cx, &thisv, &modified))
         return false;
     if (modified)
         call.setThis(thisv);
@@ -431,29 +431,29 @@ js::Invoke(JSContext *cx, CallArgs args,
 
     if (args.calleev().isPrimitive())
         return ReportIsNotFunction(cx, args.calleev().get(), args.length() + 1, construct);
 
     JSObject &callee = args.callee();
     Class *clasp = callee.getClass();
 
     /* Invoke non-functions. */
-    if (JS_UNLIKELY(clasp != &FunctionClass)) {
+    if (JS_UNLIKELY(clasp != &JSFunction::class_)) {
 #if JS_HAS_NO_SUCH_METHOD
         if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass))
             return NoSuchMethod(cx, args.length(), args.base());
 #endif
         JS_ASSERT_IF(construct, !clasp->construct);
         if (!clasp->call)
             return ReportIsNotFunction(cx, args.calleev().get(), args.length() + 1, construct);
         return CallJSNative(cx, clasp->call, args);
     }
 
     /* Invoke native functions. */
-    JSFunction *fun = callee.toFunction();
+    JSFunction *fun = &callee.as<JSFunction>();
     JS_ASSERT_IF(construct, !fun->isNativeConstructor());
     if (fun->isNative())
         return CallJSNative(cx, fun->native(), args);
 
     if (!fun->getOrCreateScript(cx))
         return false;
 
     /* Run function until JSOP_STOP, JSOP_RETURN or error. */
@@ -506,26 +506,26 @@ js::Invoke(JSContext *cx, const Value &t
 
     *rval = args.rval();
     return true;
 }
 
 bool
 js::InvokeConstructor(JSContext *cx, CallArgs args)
 {
-    JS_ASSERT(!FunctionClass.construct);
+    JS_ASSERT(!JSFunction::class_.construct);
 
     args.setThis(MagicValue(JS_IS_CONSTRUCTING));
 
     if (!args.calleev().isObject())
         return ReportIsNotFunction(cx, args.calleev().get(), args.length() + 1, CONSTRUCT);
 
     JSObject &callee = args.callee();
-    if (callee.isFunction()) {
-        RootedFunction fun(cx, callee.toFunction());
+    if (callee.is<JSFunction>()) {
+        RootedFunction fun(cx, &callee.as<JSFunction>());
 
         if (fun->isNativeConstructor()) {
             bool ok = CallJSNativeConstructor(cx, fun->native(), args);
             return ok;
         }
 
         if (!fun->isInterpretedConstructor())
             return ReportIsNotFunction(cx, args.calleev().get(), args.length() + 1, CONSTRUCT);
@@ -3276,17 +3276,17 @@ js::Lambda(JSContext *cx, HandleFunction
 
         if (!ComputeThis(cx, frame))
             return NULL;
 
         RootedValue thisval(cx, frame.thisValue());
         clone = js_fun_bind(cx, clone, thisval, NULL, 0);
         if (!clone)
             return NULL;
-        clone->toFunction()->flags |= JSFunction::ARROW;
+        clone->as<JSFunction>().flags |= JSFunction::ARROW;
     }
 
     JS_ASSERT(clone->global() == clone->global());
     return clone;
 }
 
 bool
 js::DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain,
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -257,17 +257,17 @@ class InvokeState : public RunState
 {
     mozilla::Maybe<InvokeFrameGuard> ifg_;
     CallArgs &args_;
     InitialFrameFlags initial_;
     bool useNewType_;
 
   public:
     InvokeState(JSContext *cx, CallArgs &args, InitialFrameFlags initial)
-      : RunState(cx, Invoke, args.callee().toFunction()->nonLazyScript()),
+      : RunState(cx, Invoke, args.callee().as<JSFunction>().nonLazyScript()),
         args_(args),
         initial_(initial),
         useNewType_(false)
     { }
 
     bool useNewType() const { return useNewType_; }
     void setUseNewType() { useNewType_ = true; }
 
--- a/js/src/vm/ScopeObject-inl.h
+++ b/js/src/vm/ScopeObject-inl.h
@@ -81,24 +81,24 @@ ScopeObject::offsetOfEnclosingScope()
     return getFixedSlotOffset(SCOPE_CHAIN_SLOT);
 }
 
 inline bool
 CallObject::isForEval() const
 {
     JS_ASSERT(getReservedSlot(CALLEE_SLOT).isObjectOrNull());
     JS_ASSERT_IF(getReservedSlot(CALLEE_SLOT).isObject(),
-                 getReservedSlot(CALLEE_SLOT).toObject().isFunction());
+                 getReservedSlot(CALLEE_SLOT).toObject().is<JSFunction>());
     return getReservedSlot(CALLEE_SLOT).isNull();
 }
 
 inline JSFunction &
 CallObject::callee() const
 {
-    return *getReservedSlot(CALLEE_SLOT).toObject().toFunction();
+    return getReservedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
 }
 
 inline const Value &
 CallObject::aliasedVar(AliasedFormalIter fi)
 {
     return getSlot(fi.scopeSlot());
 }
 
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -27,46 +27,46 @@ using mozilla::PodZero;
 
 typedef Rooted<ArgumentsObject *> RootedArgumentsObject;
 
 /*****************************************************************************/
 
 StaticScopeIter::StaticScopeIter(JSContext *cx, JSObject *objArg)
   : obj(cx, objArg), onNamedLambda(false)
 {
-    JS_ASSERT_IF(obj, obj->is<StaticBlockObject>() || obj->isFunction());
+    JS_ASSERT_IF(obj, obj->is<StaticBlockObject>() || obj->is<JSFunction>());
 }
 
 bool
 StaticScopeIter::done() const
 {
     return !obj;
 }
 
 void
 StaticScopeIter::operator++(int)
 {
     if (obj->is<StaticBlockObject>()) {
         obj = obj->as<StaticBlockObject>().enclosingStaticScope();
-    } else if (onNamedLambda || !obj->toFunction()->isNamedLambda()) {
+    } else if (onNamedLambda || !obj->as<JSFunction>().isNamedLambda()) {
         onNamedLambda = false;
-        obj = obj->toFunction()->nonLazyScript()->enclosingStaticScope();
+        obj = obj->as<JSFunction>().nonLazyScript()->enclosingStaticScope();
     } else {
         onNamedLambda = true;
     }
-    JS_ASSERT_IF(obj, obj->is<StaticBlockObject>() || obj->isFunction());
-    JS_ASSERT_IF(onNamedLambda, obj->isFunction());
+    JS_ASSERT_IF(obj, obj->is<StaticBlockObject>() || obj->is<JSFunction>());
+    JS_ASSERT_IF(onNamedLambda, obj->is<JSFunction>());
 }
 
 bool
 StaticScopeIter::hasDynamicScopeObject() const
 {
     return obj->is<StaticBlockObject>()
            ? obj->as<StaticBlockObject>().needsClone()
-           : obj->toFunction()->isHeavyweight();
+           : obj->as<JSFunction>().isHeavyweight();
 }
 
 Shape *
 StaticScopeIter::scopeShape() const
 {
     JS_ASSERT(hasDynamicScopeObject());
     JS_ASSERT(type() != NAMED_LAMBDA);
     return type() == BLOCK
@@ -88,17 +88,17 @@ StaticScopeIter::block() const
     JS_ASSERT(type() == BLOCK);
     return obj->as<StaticBlockObject>();
 }
 
 JSScript *
 StaticScopeIter::funScript() const
 {
     JS_ASSERT(type() == FUNCTION);
-    return obj->toFunction()->nonLazyScript();
+    return obj->as<JSFunction>().nonLazyScript();
 }
 
 /*****************************************************************************/
 
 static JSObject *
 InnermostStaticScope(JSScript *script, jsbytecode *pc)
 {
     JS_ASSERT(pc >= script->code && pc < script->code + script->length);
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -212,42 +212,42 @@ intrinsic_AssertionFailed(JSContext *cx,
 }
 
 static JSBool
 intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JS_ASSERT(args.length() == 2);
     JS_ASSERT(args[0].isObject());
-    JS_ASSERT(args[0].toObject().isFunction());
+    JS_ASSERT(args[0].toObject().is<JSFunction>());
     JS_ASSERT(args[1].isObject());
 
     // Normal .prototype properties aren't enumerable.  But for this to clone
     // correctly, it must be enumerable.
     RootedObject ctor(cx, &args[0].toObject());
     if (!JSObject::defineProperty(cx, ctor, cx->names().classPrototype, args.handleAt(1),
                                   JS_PropertyStub, JS_StrictPropertyStub,
                                   JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
     {
         return false;
     }
 
-    ctor->toFunction()->setIsSelfHostedConstructor();
+    ctor->as<JSFunction>().setIsSelfHostedConstructor();
     args.rval().setUndefined();
     return true;
 }
 
 static JSBool
 intrinsic_MakeWrappable(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JS_ASSERT(args.length() >= 1);
     JS_ASSERT(args[0].isObject());
-    JS_ASSERT(args[0].toObject().isFunction());
-    args[0].toObject().toFunction()->makeWrappable();
+    JS_ASSERT(args[0].toObject().is<JSFunction>());
+    args[0].toObject().as<JSFunction>().makeWrappable();
     args.rval().setUndefined();
     return true;
 }
 
 /*
  * Used to decompile values in the nearest non-builtin stack frame, falling
  * back to decompiling in the current frame. Helpful for printing higher-order
  * function arguments.
@@ -285,20 +285,20 @@ intrinsic_DecompileArg(JSContext *cx, un
  *   each callsite to improve TI resolution.  This is important for
  *   higher-order functions like |Array.map|.
  */
 static JSBool
 intrinsic_SetScriptHints(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JS_ASSERT(args.length() >= 2);
-    JS_ASSERT(args[0].isObject() && args[0].toObject().isFunction());
+    JS_ASSERT(args[0].isObject() && args[0].toObject().is<JSFunction>());
     JS_ASSERT(args[1].isObject());
 
-    RootedFunction fun(cx, args[0].toObject().toFunction());
+    RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
     RootedScript funScript(cx, fun->nonLazyScript());
     RootedObject flags(cx, &args[1].toObject());
 
     RootedId id(cx);
     RootedValue propv(cx);
 
     id = AtomToId(Atomize(cx, "cloneAtCallsite", strlen("cloneAtCallsite")));
     if (!JSObject::getGeneric(cx, flags, flags, id, &propv))
@@ -355,19 +355,19 @@ intrinsic_ForkJoinSlices(JSContext *cx, 
  * passed to |init|. The new instance will be passed as the |this|
  * argument.
  */
 JSBool
 js::intrinsic_NewParallelArray(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    JS_ASSERT(args[0].isObject() && args[0].toObject().isFunction());
+    JS_ASSERT(args[0].isObject() && args[0].toObject().is<JSFunction>());
 
-    RootedFunction init(cx, args[0].toObject().toFunction());
+    RootedFunction init(cx, &args[0].toObject().as<JSFunction>());
     CallArgs args0 = CallArgsFromVp(argc - 1, vp + 1);
     if (!js::ParallelArrayObject::constructHelper(cx, &init, args0))
         return false;
     args.rval().set(args0.rval());
     return true;
 }
 
 /*
@@ -778,23 +778,23 @@ CloneProperties(JSContext *cx, HandleObj
 
 static JSObject *
 CloneObject(JSContext *cx, HandleObject srcObj, CloneMemory &clonedObjects)
 {
     CloneMemory::AddPtr p = clonedObjects.lookupForAdd(srcObj.get());
     if (p)
         return p->value;
     RootedObject clone(cx);
-    if (srcObj->isFunction()) {
-        if (srcObj->toFunction()->isWrappable()) {
+    if (srcObj->is<JSFunction>()) {
+        if (srcObj->as<JSFunction>().isWrappable()) {
             clone = srcObj;
             if (!cx->compartment()->wrap(cx, clone.address()))
                 return NULL;
         } else {
-            RootedFunction fun(cx, srcObj->toFunction());
+            RootedFunction fun(cx, &srcObj->as<JSFunction>());
             clone = CloneFunctionObject(cx, fun, cx->global(), fun->getAllocKind(), TenuredObject);
         }
     } else if (srcObj->is<RegExpObject>()) {
         RegExpObject &reobj = srcObj->as<RegExpObject>();
         RootedAtom source(cx, reobj.getSource());
         clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), NULL);
     } else if (srcObj->isDate()) {
         clone = JS_NewDateObjectMsec(cx, srcObj->getDateUTCTime().toNumber());
@@ -857,17 +857,17 @@ JSRuntime::cloneSelfHostedFunctionScript
                                          Handle<JSFunction*> targetFun)
 {
     RootedObject shg(cx, selfHostingGlobal_);
     RootedValue funVal(cx);
     RootedId id(cx, NameToId(name));
     if (!GetUnclonedValue(cx, shg, id, &funVal))
         return false;
 
-    RootedFunction sourceFun(cx, funVal.toObject().toFunction());
+    RootedFunction sourceFun(cx, &funVal.toObject().as<JSFunction>());
     RootedScript sourceScript(cx, sourceFun->nonLazyScript());
     JS_ASSERT(!sourceScript->enclosingStaticScope());
     JSScript *cscript = CloneScript(cx, NullPtr(), targetFun, sourceScript);
     if (!cscript)
         return false;
     targetFun->setScript(cscript);
     cscript->setFunction(targetFun);
     JS_ASSERT(sourceFun->nargs == targetFun->nargs);
@@ -905,15 +905,15 @@ JSRuntime::maybeWrappedSelfHostedFunctio
     RootedObject shg(cx, selfHostingGlobal_);
     RootedId id(cx, NameToId(name));
     if (!GetUnclonedValue(cx, shg, id, funVal))
         return false;
 
     JS_ASSERT(funVal.isObject());
     JS_ASSERT(funVal.toObject().isCallable());
 
-    if (!funVal.toObject().toFunction()->isWrappable()) {
+    if (!funVal.toObject().as<JSFunction>().isWrappable()) {
         funVal.setUndefined();
         return true;
     }
 
     return cx->compartment()->wrap(cx, funVal);
 }
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -902,17 +902,17 @@ ContextStack::pushInvokeFrame(JSContext 
     return fp;
 }
 
 bool
 ContextStack::pushInvokeFrame(JSContext *cx, const CallArgs &args,
                               InitialFrameFlags initial, InvokeFrameGuard *ifg)
 {
     JSObject &callee = args.callee();
-    JSFunction *fun = callee.toFunction();
+    JSFunction *fun = &callee.as<JSFunction>();
     if (!pushInvokeFrame(cx, REPORT_ERROR, args, fun, initial, ifg))
         return false;
     return true;
 }
 
 bool
 ContextStack::pushExecuteFrame(JSContext *cx, HandleScript script, const Value &thisv,
                                HandleObject scopeChain, ExecuteType type,
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -701,17 +701,17 @@ class StackFrame
      * Only function frames have a callee. An eval frame in a function has the
      * same callee as its containing function frame. maybeCalleev can be used
      * to return a value that is either the callee object (for function frames) or
      * null (for global frames).
      */
 
     JSFunction &callee() const {
         JS_ASSERT(isFunctionFrame());
-        return *calleev().toObject().toFunction();
+        return calleev().toObject().as<JSFunction>();
     }
 
     const Value &calleev() const {
         JS_ASSERT(isFunctionFrame());
         return mutableCalleev();
     }
 
     const Value &maybeCalleev() const {
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -533,17 +533,17 @@ CycleCollectedJSRuntime::DescribeGCThing
   char name[72];
   if (aTraceKind == JSTRACE_OBJECT) {
     JSObject* obj = static_cast<JSObject*>(aThing);
     js::Class* clasp = js::GetObjectClass(obj);
 
     // Give the subclass a chance to do something
     if (DescribeCustomObjects(obj, clasp, name)) {
       // Nothing else to do!
-    } else if (clasp == &js::FunctionClass) {
+    } else if (js::IsFunctionObject(obj)) {
       JSFunction* fun = JS_GetObjectFunction(obj);
       JSString* str = JS_GetFunctionDisplayId(fun);
       if (str) {
         NS_ConvertUTF16toUTF8 fname(JS_GetInternedStringChars(str));
         JS_snprintf(name, sizeof(name),
                     "JS Object (Function - %s)", fname.get());
       } else {
         JS_snprintf(name, sizeof(name), "JS Object (Function)");