Bug 880041 (part 13) - Use JSObject::{is,as} for CallObject. r=evilpies.
authorNicholas Nethercote <nnethercote@mozilla.com>
Sun, 16 Jun 2013 18:46:36 -0700
changeset 135242 af5e07a1308bd2db5ad492c0194fe10b0fc50005
parent 135241 94a2fb737feaaaed6d0eff1e5453aabe396bd3b4
child 135243 90b688861270ea9b1462786122a6ac2546fff018
push id29584
push usernnethercote@mozilla.com
push dateMon, 17 Jun 2013 05:34:23 +0000
treeherdermozilla-inbound@90b688861270 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersevilpies
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 13) - Use JSObject::{is,as} for CallObject. r=evilpies.
caps/src/nsScriptSecurityManager.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/ion/BaselineFrame-inl.h
js/src/ion/IonBuilder.cpp
js/src/ion/IonCaches.cpp
js/src/ion/LiveRangeAllocator.cpp
js/src/ion/VMFunctions.cpp
js/src/jsdbgapi.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsscript.cpp
js/src/shell/jsheaptools.cpp
js/src/vm/ArgumentsObject-inl.h
js/src/vm/ArgumentsObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/ScopeObject-inl.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2071,17 +2071,17 @@ nsScriptSecurityManager::old_doGetObject
     if (jsClass == &js::FunctionClass) {
         obj = js::GetObjectParent(obj);
 
         if (!obj)
             return nullptr;
 
         jsClass = js::GetObjectClass(obj);
 
-        if (jsClass == &js::CallClass) {
+        if (js::IsCallObject(obj)) {
             obj = js::GetObjectParentMaybeScope(obj);
 
             if (!obj)
                 return nullptr;
 
             jsClass = js::GetObjectClass(obj);
         }
     }
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -103,18 +103,18 @@ MaybeCheckEvalFreeVariables(JSContext *c
 
     // If the eval'ed script contains any debugger statement, force construction
     // of arguments objects for the caller script and any other scripts it is
     // transitively nested inside. The debugger can access any variable on the
     // scope chain.
     if (pc.sc->hasDebuggerStatement()) {
         RootedObject scope(cx, scopeChain);
         while (scope->isScope() || scope->isDebugScope()) {
-            if (scope->isCall() && !scope->asCall().isForEval()) {
-                RootedScript script(cx, scope->asCall().callee().nonLazyScript());
+            if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
+                RootedScript script(cx, scope->as<CallObject>().callee().nonLazyScript());
                 if (script->argumentsHasVarBinding()) {
                     if (!JSScript::argumentsOptimizationFailed(cx, script))
                         return false;
                 }
             }
             scope = scope->enclosingScope();
         }
     }
--- a/js/src/ion/BaselineFrame-inl.h
+++ b/js/src/ion/BaselineFrame-inl.h
@@ -17,17 +17,17 @@
 
 namespace js {
 namespace ion {
 
 inline void
 BaselineFrame::pushOnScopeChain(ScopeObject &scope)
 {
     JS_ASSERT(*scopeChain() == scope.enclosingScope() ||
-              *scopeChain() == scope.asCall().enclosingScope().asDeclEnv().enclosingScope());
+              *scopeChain() == scope.as<CallObject>().enclosingScope().asDeclEnv().enclosingScope());
     scopeChain_ = &scope;
 }
 
 inline void
 BaselineFrame::popOffScopeChain()
 {
     scopeChain_ = &scopeChain_->asScope().enclosingScope();
 }
@@ -67,19 +67,19 @@ BaselineFrame::popBlock(JSContext *cx)
 
 inline CallObject &
 BaselineFrame::callObj() const
 {
     JS_ASSERT(hasCallObj());
     JS_ASSERT(fun()->isHeavyweight());
 
     JSObject *obj = scopeChain();
-    while (!obj->isCall())
+    while (!obj->is<CallObject>())
         obj = obj->enclosingScope();
-    return obj->asCall();
+    return obj->as<CallObject>();
 }
 
 } // namespace ion
 } // namespace js
 
 #endif // JS_ION
 
 #endif // jsion_baseline_frame_inl_h__
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -5969,17 +5969,17 @@ IonBuilder::pushTypeBarrier(MInstruction
     }
     current->push(barrier);
     return true;
 }
 
 bool
 IonBuilder::getStaticName(HandleObject staticObject, HandlePropertyName name, bool *psucceeded)
 {
-    JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
+    JS_ASSERT(staticObject->isGlobal() || staticObject->is<CallObject>());
 
     *psucceeded = true;
 
     if (staticObject->isGlobal()) {
         // Optimize undefined, NaN, and Infinity.
         if (name == cx->names().undefined)
             return pushConstant(UndefinedValue());
         if (name == cx->names().NaN)
@@ -6085,17 +6085,17 @@ ion::NeedsPostBarrier(CompileInfo &info,
     return info.executionMode() != ParallelExecution && value->mightBeType(MIRType_Object);
 }
 
 bool
 IonBuilder::setStaticName(HandleObject staticObject, HandlePropertyName name)
 {
     RootedId id(cx, NameToId(name));
 
-    JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
+    JS_ASSERT(staticObject->isGlobal() || staticObject->is<CallObject>());
 
     MDefinition *value = current->peek(-1);
 
     if (staticObject->watched())
         return jsop_setprop(name);
 
     // For the fastest path, the property must be found, and it must be found
     // as a normal data property on exactly the global object.
@@ -8262,35 +8262,37 @@ IonBuilder::hasStaticScopeObject(ScopeCo
     // If the current script is inner to the outer script and the function has
     // singleton type then it should show up here.
 
     MDefinition *scope = current->getSlot(info().scopeChainSlot());
     scope->setFoldedUnchecked();
 
     JSObject *environment = script()->function()->environment();
     while (environment && !environment->isGlobal()) {
-        if (environment->isCall() &&
-            !environment->asCall().isForEval() &&
-            environment->asCall().callee().nonLazyScript() == outerScript)
+        if (environment->is<CallObject>() &&
+            !environment->as<CallObject>().isForEval() &&
+            environment->as<CallObject>().callee().nonLazyScript() == outerScript)
         {
             JS_ASSERT(environment->hasSingletonType());
             pcall.set(environment);
             return true;
         }
         environment = environment->enclosingScope();
     }
 
     // Look for the call object on the current frame, if we are compiling the
     // outer script itself. Don't do this if we are at entry to the outer
     // script, as the call object we see will not be the real one --- after
     // entering the Ion code a different call object will be created.
 
     if (script() == outerScript && fp && info().osrPc()) {
         JSObject *scope = fp.scopeChain();
-        if (scope->isCall() && scope->asCall().callee().nonLazyScript() == outerScript) {
+        if (scope->is<CallObject>() &&
+            scope->as<CallObject>().callee().nonLazyScript() == outerScript)
+        {
             JS_ASSERT(scope->hasSingletonType());
             pcall.set(scope);
             return true;
         }
     }
 
     return true;
 }
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -2729,21 +2729,21 @@ BindNameIC::attachGlobal(JSContext *cx, 
 
     return linkAndAttachStub(cx, masm, attacher, ion, "global");
 }
 
 static inline void
 GenerateScopeChainGuard(MacroAssembler &masm, JSObject *scopeObj,
                         Register scopeObjReg, Shape *shape, Label *failures)
 {
-    if (scopeObj->isCall()) {
+    if (scopeObj->is<CallObject>()) {
         // We can skip a guard on the call object if the script's bindings are
         // guaranteed to be immutable (and thus cannot introduce shadowing
         // variables).
-        CallObject *callObj = &scopeObj->asCall();
+        CallObject *callObj = &scopeObj->as<CallObject>();
         if (!callObj->isForEval()) {
             JSFunction *fun = &callObj->callee();
             JSScript *script = fun->nonLazyScript();
             if (!script->funHasExtensibleScope)
                 return;
         }
     } else if (scopeObj->isGlobal()) {
         // If this is the last object on the scope walk, and the property we've
@@ -2918,17 +2918,17 @@ IsCacheableNameReadSlot(JSContext *cx, H
     if (obj != holder)
         return false;
 
     if (obj->isGlobal()) {
         // Support only simple property lookups.
         if (!IsCacheableGetPropReadSlot(obj, holder, shape) &&
             !IsCacheableNoProperty(obj, holder, shape, pc, output))
             return false;
-    } else if (obj->isCall()) {
+    } else if (obj->is<CallObject>()) {
         if (!shape->hasDefaultGetter())
             return false;
     } else {
         // We don't yet support lookups on Block or DeclEnv objects.
         return false;
     }
 
     RootedObject obj2(cx, scopeChain);
--- a/js/src/ion/LiveRangeAllocator.cpp
+++ b/js/src/ion/LiveRangeAllocator.cpp
@@ -630,17 +630,18 @@ LiveRangeAllocator<VREG>::buildLivenessI
                         if (LSafepoint *safepoint = ins->safepoint())
                             AddRegisterToSafepoint(safepoint, reg, *temp);
                     } else {
                         JS_ASSERT(!ins->isCall());
                         if (!vregs[temp].getInterval(0)->addRangeAtHead(inputOf(*ins), outputOf(*ins)))
                             return false;
                     }
                 } else {
-                    CodePosition to = ins->isCall() ? outputOf(*ins) : outputOf(*ins).next();
+                    CodePosition to =
+                        ins->isCall() ? outputOf(*ins) : outputOf(*ins).next();
                     if (!vregs[temp].getInterval(0)->addRangeAtHead(inputOf(*ins), to))
                         return false;
                 }
             }
 
             DebugOnly<bool> hasUseRegister = false;
             DebugOnly<bool> hasUseRegisterAtStart = false;
 
@@ -696,17 +697,18 @@ LiveRangeAllocator<VREG>::buildLivenessI
                             // here.
                             LSafepoint *safepoint = ins->safepoint();
                             if (!ins->isCall() && safepoint)
                                 AddRegisterToSafepoint(safepoint, reg, *vregs[use].def());
                         } else {
                             to = use->usedAtStart() ? inputOf(*ins) : outputOf(*ins);
                         }
                     } else {
-                        to = (use->usedAtStart() || ins->isCall()) ? inputOf(*ins) : outputOf(*ins);
+                        to = (use->usedAtStart() || ins->isCall())
+                           ? inputOf(*ins) : outputOf(*ins);
                         if (use->isFixedRegister()) {
                             LAllocation reg(AnyRegister::FromCode(use->registerCode()));
                             for (size_t i = 0; i < ins->numDefs(); i++) {
                                 LDefinition *def = ins->getDef(i);
                                 if (def->policy() == LDefinition::PRESET && *def->output() == reg)
                                     to = inputOf(*ins);
                             }
                         }
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -634,17 +634,17 @@ DebugEpilogue(JSContext *cx, BaselineFra
     // return value. If it returns |false|, the debugger threw an exception.
     // In both cases we have to pop debug scopes.
     ok = ScriptDebugEpilogue(cx, frame, ok);
 
     if (frame->isNonEvalFunctionFrame()) {
         JS_ASSERT_IF(ok, frame->hasReturnValue());
         DebugScopes::onPopCall(frame, cx);
     } else if (frame->isStrictEvalFrame()) {
-        JS_ASSERT_IF(frame->hasCallObj(), frame->scopeChain()->asCall().isForEval());
+        JS_ASSERT_IF(frame->hasCallObj(), frame->scopeChain()->as<CallObject>().isForEval());
         DebugScopes::onPopStrictEvalScope(frame);
     }
 
     // If the frame has a pushed SPS frame, make sure to pop it.
     if (frame->hasPushedSPSFrame()) {
         cx->runtime()->spsProfiler.exit(cx, frame->script(), frame->maybeFun());
         // Unset the pushedSPSFrame flag because DebugEpilogue may get called before
         // Probes::exitScript in baseline during exception handling, and we don't
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1260,17 +1260,17 @@ JSAbstractFramePtr::callObject(JSContext
      * in missing scopes, we can expect to find fp's CallObject on 'o'. Note:
      *  - GetDebugScopeForFrame wraps every ScopeObject (missing or not) with
      *    a DebugScopeObject proxy.
      *  - If fp is an eval-in-function, then fp has no callobj of its own and
      *    JS_GetFrameCallObject will return the innermost function's callobj.
      */
     while (o) {
         ScopeObject &scope = o->asDebugScope().scope();
-        if (scope.isCall())
+        if (scope.is<CallObject>())
             return o;
         o = o->enclosingScope();
     }
     return NULL;
 }
 
 JSFunction *
 JSAbstractFramePtr::maybeFun()
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -348,16 +348,22 @@ js::IsAtomsCompartment(JSCompartment *co
 }
 
 JS_FRIEND_API(bool)
 js::IsScopeObject(JSObject *obj)
 {
     return obj->isScope();
 }
 
+JS_FRIEND_API(bool)
+js::IsCallObject(JSObject *obj)
+{
+    return obj->is<CallObject>();
+}
+
 JS_FRIEND_API(JSObject *)
 js::GetObjectParentMaybeScope(JSObject *obj)
 {
     return obj->enclosingScope();
 }
 
 JS_FRIEND_API(JSObject *)
 js::GetGlobalForObjectCrossCompartment(JSObject *obj)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -371,17 +371,16 @@ 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) CallClass;
 extern JS_FRIEND_DATA(js::Class) DeclEnvClass;
 extern JS_FRIEND_DATA(js::Class) FunctionClass;
 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 *
@@ -404,16 +403,19 @@ IsInnerObject(JSObject *obj) {
 inline bool
 IsOuterObject(JSObject *obj) {
     return !!GetObjectClass(obj)->ext.innerObject;
 }
 
 JS_FRIEND_API(bool)
 IsScopeObject(JSObject *obj);
 
+JS_FRIEND_API(bool)
+IsCallObject(JSObject *obj);
+
 inline JSObject *
 GetObjectParent(JSObject *obj)
 {
     JS_ASSERT(!IsScopeObject(obj));
     return reinterpret_cast<shadow::Object*>(obj)->shape->base->parent;
 }
 
 static JS_ALWAYS_INLINE JSCompartment *
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2548,17 +2548,17 @@ JSObject::shrinkSlots(JSContext *cx, Han
     JS_ASSERT(newCount < oldCount);
 
     /*
      * Refuse to shrink slots for call objects. This only happens in a very
      * obscure situation (deleting names introduced by a direct 'eval') and
      * allowing the slots pointer to change may require updating pointers in
      * the function's active args/vars information.
      */
-    if (obj->isCall())
+    if (obj->is<CallObject>())
         return;
 
     if (newCount == 0) {
         FreeSlots(cx, obj->slots);
         obj->slots = NULL;
         return;
     }
 
@@ -3205,17 +3205,17 @@ js_PurgeScopeChainHelper(JSContext *cx, 
     PurgeProtoChain(cx, obj->getProto(), id);
 
     /*
      * We must purge the scope chain only for Call objects as they are the only
      * kind of cacheable non-global object that can gain properties after outer
      * properties with the same names have been cached or traced. Call objects
      * may gain such properties via eval introducing new vars; see bug 490364.
      */
-    if (obj->isCall()) {
+    if (obj->is<CallObject>()) {
         while ((obj = obj->enclosingScope()) != NULL) {
             if (!PurgeProtoChain(cx, obj, id))
                 return false;
         }
     }
 
     return true;
 }
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -29,17 +29,16 @@
 namespace JS {
 struct ObjectsExtraSizes;
 }
 
 namespace js {
 
 class AutoPropDescArrayRooter;
 class BaseProxyHandler;
-class CallObject;
 struct GCMarker;
 struct NativeIterator;
 class Nursery;
 class Shape;
 struct StackShape;
 
 namespace mjit { class Compiler; }
 
@@ -200,17 +199,16 @@ DeleteSpecial(JSContext *cx, HandleObjec
 
 extern JSBool
 DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded);
 
 } /* namespace js::baseops */
 
 extern Class ArrayClass;
 extern Class BooleanClass;
-extern Class CallableObjectClass;
 extern Class DateClass;
 extern Class ErrorClass;
 extern Class GeneratorClass;
 extern Class IntlClass;
 extern Class JSONClass;
 extern Class MathClass;
 extern Class NumberClass;
 extern Class ObjectClass;
@@ -973,17 +971,16 @@ class JSObject : public js::ObjectImpl
     using js::ObjectImpl::isProxy;
     inline bool isRegExpStatics()    const { return hasClass(&js::RegExpStaticsClass); }
     inline bool isScope()            const;
     inline bool isStopIteration()    const { return hasClass(&js::StopIterationClass); }
     inline bool isTypedArray()       const;
     inline bool isWeakMap()          const { return hasClass(&js::WeakMapClass); }
 
     /* Subtypes of ScopeObject. */
-    inline bool isCall()        const { return hasClass(&js::CallClass); }
     inline bool isDeclEnv()     const { return hasClass(&js::DeclEnvClass); }
     inline bool isNestedScope() const;
     inline bool isWith()        const { return hasClass(&js::WithClass); }
     inline bool isClonedBlock() const;
     inline bool isStaticBlock() const;
 
     /* Subtypes of PrimitiveObject. */
     inline bool isBoolean() const { return hasClass(&js::BooleanClass); }
@@ -992,17 +989,16 @@ class JSObject : public js::ObjectImpl
 
     /* Subtypes of Proxy. */
     inline bool isDebugScope()              const;
     inline bool isWrapper()                 const;
     inline bool isFunctionProxy()           const { return hasClass(&js::FunctionProxyClass); }
     inline bool isCrossCompartmentWrapper() const;
 
     inline js::BooleanObject &asBoolean();
-    inline js::CallObject &asCall();
     inline js::ClonedBlockObject &asClonedBlock();
     inline js::DeclEnvObject &asDeclEnv();
     inline js::DebugScopeObject &asDebugScope();
     inline js::GlobalObject &asGlobal();
     inline js::MapObject &asMap();
     inline js::NestedScopeObject &asNestedScope();
     inline js::NumberObject &asNumber();
     inline js::ScopeObject &asScope();
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -87,17 +87,17 @@ Bindings::initWithTemporaryStorage(JSCon
      * any time, such accesses are mediated by DebugScopeProxy (see
      * DebugScopeProxy::handleUnaliasedAccess).
      */
 
     JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == 2);
     gc::AllocKind allocKind = gc::FINALIZE_OBJECT2_BACKGROUND;
     JS_ASSERT(gc::GetGCKindSlots(allocKind) == CallObject::RESERVED_SLOTS);
     RootedShape initial(cx,
-        EmptyShape::getInitialShape(cx, &CallClass, NULL, cx->global(), NULL,
+        EmptyShape::getInitialShape(cx, &CallObject::class_, NULL, cx->global(), NULL,
                                     allocKind, BaseShape::VAROBJ | BaseShape::DELEGATE));
     if (!initial)
         return false;
     self->callObjShape_.init(initial);
 
 #ifdef DEBUG
     HashSet<PropertyName *> added(cx);
     if (!added.init())
@@ -112,17 +112,17 @@ Bindings::initWithTemporaryStorage(JSCon
 
 #ifdef DEBUG
         /* The caller ensures no duplicate aliased names. */
         JS_ASSERT(!added.has(bi->name()));
         if (!added.put(bi->name()))
             return false;
 #endif
 
-        StackBaseShape base(cx->compartment(), &CallClass, cx->global(), NULL,
+        StackBaseShape base(cx->compartment(), &CallObject::class_, cx->global(), NULL,
                             BaseShape::VAROBJ | BaseShape::DELEGATE);
 
         UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
         if (!nbase)
             return false;
 
         RootedId id(cx, NameToId(bi->name()));
         unsigned attrs = JSPROP_PERMANENT | JSPROP_ENUMERATE |
--- a/js/src/shell/jsheaptools.cpp
+++ b/js/src/shell/jsheaptools.cpp
@@ -379,17 +379,17 @@ class ReferenceFinder {
      * value; otherwise, return JSVAL_VOID.
      */
     jsval representable(void *cell, int kind) {
         if (kind == JSTRACE_OBJECT) {
             JSObject *object = static_cast<JSObject *>(cell);
 
             /* Certain classes of object are for internal use only. */
             if (object->is<BlockObject>() ||
-                object->isCall() ||
+                object->is<CallObject>() ||
                 object->isWith() ||
                 object->isDeclEnv()) {
                 return JSVAL_VOID;
             }
 
             /* Internal function objects should also not be revealed. */
             if (JS_ObjectIsFunction(context, object) && IsInternalFunctionObject(object))
                 return JSVAL_VOID;
--- a/js/src/vm/ArgumentsObject-inl.h
+++ b/js/src/vm/ArgumentsObject-inl.h
@@ -66,32 +66,32 @@ ArgumentsObject::setArg(unsigned i, cons
 }
 
 inline const Value &
 ArgumentsObject::element(uint32_t i) const
 {
     JS_ASSERT(!isElementDeleted(i));
     const Value &v = data()->args[i];
     if (v.isMagic(JS_FORWARD_TO_CALL_OBJECT)) {
-        CallObject &callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall();
+        CallObject &callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().as<CallObject>();
         for (AliasedFormalIter fi(callobj.callee().nonLazyScript()); ; fi++) {
             if (fi.frameIndex() == i)
                 return callobj.aliasedVar(fi);
         }
     }
     return v;
 }
 
 inline void
 ArgumentsObject::setElement(JSContext *cx, uint32_t i, const Value &v)
 {
     JS_ASSERT(!isElementDeleted(i));
     HeapValue &lhs = data()->args[i];
     if (lhs.isMagic(JS_FORWARD_TO_CALL_OBJECT)) {
-        CallObject &callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall();
+        CallObject &callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().as<CallObject>();
         for (AliasedFormalIter fi(callobj.callee().nonLazyScript()); ; fi++) {
             if (fi.frameIndex() == i) {
                 callobj.setAliasedVar(cx, fi, fi->name(), v);
                 return;
             }
         }
     }
     lhs = v;
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -54,17 +54,17 @@ ArgumentsObject::MaybeForwardToCallObjec
 #if defined(JS_ION)
 /* static */ void
 ArgumentsObject::MaybeForwardToCallObject(ion::IonJSFrameLayout *frame, HandleObject callObj,
                                           JSObject *obj, ArgumentsData *data)
 {
     JSFunction *callee = ion::CalleeTokenToFunction(frame->calleeToken());
     JSScript *script = callee->nonLazyScript();
     if (callee->isHeavyweight() && script->argsObjAliasesFormals()) {
-        JS_ASSERT(callObj && callObj->isCall());
+        JS_ASSERT(callObj && callObj->is<CallObject>());
         obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
         for (AliasedFormalIter fi(script); fi; fi++)
             data->args[fi.frameIndex()] = MagicValue(JS_FORWARD_TO_CALL_OBJECT);
     }
 }
 #endif
 
 struct CopyFrameArgs
@@ -268,17 +268,17 @@ ArgumentsObject::createUnexpected(JSCont
 #if defined(JS_ION)
 ArgumentsObject *
 ArgumentsObject::createForIon(JSContext *cx, ion::IonJSFrameLayout *frame, HandleObject scopeChain)
 {
     ion::CalleeToken token = frame->calleeToken();
     JS_ASSERT(ion::CalleeTokenIsFunction(token));
     RootedScript script(cx, ion::ScriptFromCalleeToken(token));
     RootedFunction callee(cx, ion::CalleeTokenToFunction(token));
-    RootedObject callObj(cx, scopeChain->isCall() ? scopeChain.get() : NULL);
+    RootedObject callObj(cx, scopeChain->is<CallObject>() ? scopeChain.get() : NULL);
     CopyIonJSFrameArgs copy(frame, callObj);
     return create(cx, script, callee, frame->numActualArgs(), copy);
 }
 #endif
 
 static JSBool
 args_delProperty(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded)
 {
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -5229,20 +5229,20 @@ DebuggerEnv_getCallee(JSContext *cx, uns
     THIS_DEBUGENV_OWNER(cx, argc, vp, "get callee", args, envobj, env, dbg);
 
     args.rval().setNull();
 
     if (!env->isDebugScope())
         return true;
 
     JSObject &scope = env->asDebugScope().scope();
-    if (!scope.isCall())
+    if (!scope.is<CallObject>())
         return true;
 
-    CallObject &callobj = scope.asCall();
+    CallObject &callobj = scope.as<CallObject>();
     if (callobj.isForEval())
         return true;
 
     args.rval().setObject(callobj.callee());
     if (!dbg->wrapDebuggeeValue(cx, args.rval()))
         return false;
     return true;
 }
--- a/js/src/vm/ScopeObject-inl.h
+++ b/js/src/vm/ScopeObject-inl.h
@@ -26,32 +26,32 @@ inline JSObject &
 ScopeObject::enclosingScope() const
 {
     return getReservedSlot(SCOPE_CHAIN_SLOT).toObject();
 }
 
 inline void
 ScopeObject::setEnclosingScope(HandleObject obj)
 {
-    JS_ASSERT_IF(obj->isCall() || obj->isDeclEnv() || obj->is<BlockObject>(),
+    JS_ASSERT_IF(obj->is<CallObject>() || obj->isDeclEnv() || obj->is<BlockObject>(),
                  obj->isDelegate());
     setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*obj));
 }
 
 inline const Value &
 ScopeObject::aliasedVar(ScopeCoordinate sc)
 {
-    JS_ASSERT(isCall() || isClonedBlock());
+    JS_ASSERT(is<CallObject>() || isClonedBlock());
     return getSlot(sc.slot);
 }
 
 inline void
 ScopeObject::setAliasedVar(JSContext *cx, ScopeCoordinate sc, PropertyName *name, const Value &v)
 {
-    JS_ASSERT(isCall() || isClonedBlock());
+    JS_ASSERT(is<CallObject>() || isClonedBlock());
     JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == BlockObject::RESERVED_SLOTS);
 
     // name may be null for non-singletons, whose types do not need to be tracked.
     JS_ASSERT_IF(hasSingletonType(), name);
 
     setSlot(sc.slot, v);
     if (hasSingletonType())
         types::AddTypePropertyId(cx, this, NameToId(name), v);
@@ -254,23 +254,16 @@ ClonedBlockObject::setVar(unsigned i, co
 
 inline js::ScopeObject &
 JSObject::asScope()
 {
     JS_ASSERT(isScope());
     return *static_cast<js::ScopeObject *>(this);
 }
 
-inline js::CallObject &
-JSObject::asCall()
-{
-    JS_ASSERT(isCall());
-    return *static_cast<js::CallObject *>(this);
-}
-
 inline js::DeclEnvObject &
 JSObject::asDeclEnv()
 {
     JS_ASSERT(isDeclEnv());
     return *static_cast<js::DeclEnvObject *>(this);
 }
 
 inline js::NestedScopeObject &
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -165,58 +165,58 @@ js::ScopeCoordinateFunctionScript(JSCont
 /*
  * Construct a bare-bones call object given a shape, type, and slots pointer.
  * The call object must be further initialized to be usable.
  */
 CallObject *
 CallObject::create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
 {
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
-    JS_ASSERT(CanBeFinalizedInBackground(kind, &CallClass));
+    JS_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
     kind = gc::GetBackgroundAllocKind(kind);
 
     gc::InitialHeap heap = script->treatAsRunOnce ? gc::TenuredHeap : gc::DefaultHeap;
     JSObject *obj = JSObject::create(cx, kind, heap, shape, type, slots);
     if (!obj)
         return NULL;
 
     if (script->treatAsRunOnce) {
         RootedObject nobj(cx, obj);
         if (!JSObject::setSingletonType(cx, nobj))
             return NULL;
-        return &nobj->asCall();
+        return &nobj->as<CallObject>();
     }
 
-    return &obj->asCall();
+    return &obj->as<CallObject>();
 }
 
 /*
  * Create a CallObject for a JSScript that is not initialized to any particular
  * callsite. This object can either be initialized (with an enclosing scope and
  * callee) or used as a template for jit compilation.
  */
 CallObject *
 CallObject::createTemplateObject(JSContext *cx, HandleScript script, gc::InitialHeap heap)
 {
     RootedShape shape(cx, script->bindings.callObjShape());
-    JS_ASSERT(shape->getObjectClass() == &CallClass);
+    JS_ASSERT(shape->getObjectClass() == &class_);
 
-    RootedTypeObject type(cx, cx->compartment()->getNewType(cx, &CallClass, NULL));
+    RootedTypeObject type(cx, cx->compartment()->getNewType(cx, &class_, NULL));
     if (!type)
         return NULL;
 
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
-    JS_ASSERT(CanBeFinalizedInBackground(kind, &CallClass));
+    JS_ASSERT(CanBeFinalizedInBackground(kind, &class_));
     kind = gc::GetBackgroundAllocKind(kind);
 
     JSObject *obj = JSObject::create(cx, kind, heap, shape, type);
     if (!obj)
         return NULL;
 
-    return &obj->asCall();
+    return &obj->as<CallObject>();
 }
 
 /*
  * Construct a call object for the given bindings.  If this is a call object
  * for a function invocation, callee should be the function being called.
  * Otherwise it must be a call object for eval of strict mode code, and callee
  * must be null.
  */
@@ -291,17 +291,17 @@ CallObject::createForStrictEval(JSContex
     JS_ASSERT_IF(frame.isStackFrame(), cx->regs().pc == frame.script()->code);
 
     RootedFunction callee(cx);
     RootedScript script(cx, frame.script());
     RootedObject scopeChain(cx, frame.scopeChain());
     return create(cx, script, scopeChain, callee);
 }
 
-JS_PUBLIC_DATA(Class) js::CallClass = {
+Class CallObject::class_ = {
     "Call",
     JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS),
     JS_PropertyStub,         /* addProperty */
     JS_DeletePropertyStub,   /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
@@ -1015,17 +1015,17 @@ ScopeIter::scope() const
 
 ScopeIter &
 ScopeIter::operator++()
 {
     JS_ASSERT(!done());
     switch (type_) {
       case Call:
         if (hasScopeObject_) {
-            cur_ = &cur_->asCall().enclosingScope();
+            cur_ = &cur_->as<CallObject>().enclosingScope();
             if (CallObjectLambdaName(*frame_.fun()))
                 cur_ = &cur_->asDeclEnv().enclosingScope();
         }
         frame_ = NullFramePtr();
         break;
       case Block:
         block_ = block_->enclosingBlock();
         if (hasScopeObject_)
@@ -1034,17 +1034,17 @@ ScopeIter::operator++()
         break;
       case With:
         JS_ASSERT(hasScopeObject_);
         cur_ = &cur_->asWith().enclosingScope();
         settle();
         break;
       case StrictEvalScope:
         if (hasScopeObject_)
-            cur_ = &cur_->asCall().enclosingScope();
+            cur_ = &cur_->as<CallObject>().enclosingScope();
         frame_ = NullFramePtr();
         break;
     }
     return *this;
 }
 
 void
 ScopeIter::settle()
@@ -1099,18 +1099,18 @@ ScopeIter::settle()
         JS_ASSERT_IF(block_, block_->needsClone());
         JS_ASSERT_IF(block_, block_->stackDepth() < cur_->asWith().stackDepth());
         type_ = With;
         hasScopeObject_ = true;
     } else if (block_) {
         type_ = Block;
         hasScopeObject_ = block_->needsClone();
         JS_ASSERT_IF(hasScopeObject_, cur_->asClonedBlock().staticBlock() == *block_);
-    } else if (cur_->isCall()) {
-        CallObject &callobj = cur_->asCall();
+    } else if (cur_->is<CallObject>()) {
+        CallObject &callobj = cur_->as<CallObject>();
         type_ = callobj.isForEval() ? StrictEvalScope : Call;
         hasScopeObject_ = true;
         JS_ASSERT_IF(type_ == Call, callobj.callee().nonLazyScript() == frame_.script());
     } else {
         JS_ASSERT(!cur_->isScope());
         JS_ASSERT(frame_.isGlobalFrame() || frame_.isDebuggerFrame());
         frame_ = NullFramePtr();
     }
@@ -1183,18 +1183,18 @@ class DebugScopeProxy : public BaseProxy
      */
     bool handleUnaliasedAccess(JSContext *cx, Handle<DebugScopeObject*> debugScope, Handle<ScopeObject*> scope,
                                jsid id, Action action, MutableHandleValue vp)
     {
         JS_ASSERT(&debugScope->scope() == scope);
         AbstractFramePtr maybeframe = DebugScopes::hasLiveFrame(*scope);
 
         /* Handle unaliased formals, vars, and consts at function scope. */
-        if (scope->isCall() && !scope->asCall().isForEval()) {
-            CallObject &callobj = scope->asCall();
+        if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
+            CallObject &callobj = scope->as<CallObject>();
             RootedScript script(cx, callobj.callee().nonLazyScript());
             if (!script->ensureHasTypes(cx))
                 return false;
 
             Bindings &bindings = script->bindings;
             BindingIter bi(script);
             while (bi && NameToId(bi->name()) != id)
                 bi++;
@@ -1282,57 +1282,57 @@ class DebugScopeProxy : public BaseProxy
                 else
                     block->setVar(i, vp, DONT_CHECK_ALIASING);
             }
 
             return true;
         }
 
         /* The rest of the internal scopes do not have unaliased vars. */
-        JS_ASSERT(scope->isDeclEnv() || scope->isWith() || scope->asCall().isForEval());
+        JS_ASSERT(scope->isDeclEnv() || scope->isWith() || scope->as<CallObject>().isForEval());
         return false;
     }
 
     static bool isArguments(JSContext *cx, jsid id)
     {
         return id == NameToId(cx->names().arguments);
     }
 
     static bool isFunctionScope(ScopeObject &scope)
     {
-        return scope.isCall() && !scope.asCall().isForEval();
+        return scope.is<CallObject>() && !scope.as<CallObject>().isForEval();
     }
 
     /*
      * In theory, every function scope contains an 'arguments' bindings.
      * However, the engine only adds a binding if 'arguments' is used in the
      * function body. Thus, from the debugger's perspective, 'arguments' may be
      * missing from the list of bindings.
      */
     static bool isMissingArgumentsBinding(ScopeObject &scope)
     {
         return isFunctionScope(scope) &&
-               !scope.asCall().callee().nonLazyScript()->argumentsHasVarBinding();
+               !scope.as<CallObject>().callee().nonLazyScript()->argumentsHasVarBinding();
     }
 
     /*
      * This function creates an arguments object when the debugger requests
      * 'arguments' for a function scope where the arguments object has been
      * optimized away (either because the binding is missing altogether or
      * because !ScriptAnalysis::needsArgsObj).
      */
     static bool checkForMissingArguments(JSContext *cx, jsid id, ScopeObject &scope,
                                          ArgumentsObject **maybeArgsObj)
     {
         *maybeArgsObj = NULL;
 
         if (!isArguments(cx, id) || !isFunctionScope(scope))
             return true;
 
-        if (scope.asCall().callee().nonLazyScript()->needsArgsObj())
+        if (scope.as<CallObject>().callee().nonLazyScript()->needsArgsObj())
             return true;
 
         AbstractFramePtr maybeframe = DebugScopes::hasLiveFrame(scope);
         if (!maybeframe) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_LIVE,
                                  "Debugger scope");
             return false;
         }
@@ -1455,18 +1455,18 @@ class DebugScopeProxy : public BaseProxy
 
         if (!GetPropertyNames(cx, scope, flags, &props))
             return false;
 
         /*
          * Function scopes are optimized to not contain unaliased variables so
          * they must be manually appended here.
          */
-        if (scope->isCall() && !scope->asCall().isForEval()) {
-            RootedScript script(cx, scope->asCall().callee().nonLazyScript());
+        if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
+            RootedScript script(cx, scope->as<CallObject>().callee().nonLazyScript());
             for (BindingIter bi(script); bi; bi++) {
                 if (!bi->aliased() && !props.append(NameToId(bi->name())))
                     return false;
             }
         }
 
         return true;
     }
@@ -1495,18 +1495,18 @@ class DebugScopeProxy : public BaseProxy
         RootedObject scope(cx, &scopeObj);
         if (!JS_HasPropertyById(cx, scope, id, &found))
             return false;
 
         /*
          * Function scopes are optimized to not contain unaliased variables so
          * a manual search is necessary.
          */
-        if (!found && scope->isCall() && !scope->asCall().isForEval()) {
-            RootedScript script(cx, scope->asCall().callee().nonLazyScript());
+        if (!found && scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
+            RootedScript script(cx, scope->as<CallObject>().callee().nonLazyScript());
             for (BindingIter bi(script); bi; bi++) {
                 if (!bi->aliased() && NameToId(bi->name()) == id) {
                     found = true;
                     break;
                 }
             }
         }
 
@@ -1552,32 +1552,32 @@ JSObject &
 DebugScopeObject::enclosingScope() const
 {
     return GetProxyExtra(const_cast<DebugScopeObject*>(this), ENCLOSING_EXTRA).toObject();
 }
 
 JSObject *
 DebugScopeObject::maybeSnapshot() const
 {
-    JS_ASSERT(!scope().asCall().isForEval());
+    JS_ASSERT(!scope().as<CallObject>().isForEval());
     return GetProxyExtra(const_cast<DebugScopeObject*>(this), SNAPSHOT_EXTRA).toObjectOrNull();
 }
 
 void
 DebugScopeObject::initSnapshot(JSObject &o)
 {
     JS_ASSERT(maybeSnapshot() == NULL);
     SetProxyExtra(this, SNAPSHOT_EXTRA, ObjectValue(o));
 }
 
 bool
 DebugScopeObject::isForDeclarative() const
 {
     ScopeObject &s = scope();
-    return s.isCall() || s.is<BlockObject>() || s.isDeclEnv();
+    return s.is<CallObject>() || s.is<BlockObject>() || s.isDeclEnv();
 }
 
 bool
 js_IsDebugScopeSlow(JSObject *obj)
 {
     return obj->getClass() == &ObjectProxyClass &&
            GetProxyHandler(obj) == &DebugScopeProxy::singleton;
 }
@@ -1781,25 +1781,25 @@ DebugScopes::onPopCall(AbstractFramePtr 
     if (frame.fun()->isHeavyweight()) {
         /*
          * The StackFrame may be observed before the prologue has created the
          * CallObject. See ScopeIter::settle.
          */
         if (!frame.hasCallObj())
             return;
 
-        CallObject &callobj = frame.scopeChain()->asCall();
+        CallObject &callobj = frame.scopeChain()->as<CallObject>();
         scopes->liveScopes.remove(&callobj);
         if (ObjectWeakMap::Ptr p = scopes->proxiedScopes.lookup(&callobj))
             debugScope = &p->value->asDebugScope();
     } else {
         ScopeIter si(frame, cx);
         if (MissingScopeMap::Ptr p = scopes->missingScopes.lookup(si)) {
             debugScope = p->value;
-            scopes->liveScopes.remove(&debugScope->scope().asCall());
+            scopes->liveScopes.remove(&debugScope->scope().as<CallObject>());
             scopes->missingScopes.remove(p);
         }
     }
 
     /*
      * When the StackFrame is popped, the values of unaliased variables
      * are lost. If there is any debug scope referring to this scope, save a
      * copy of the unaliased variables' values in an array for later debugger
@@ -1885,17 +1885,17 @@ DebugScopes::onPopStrictEvalScope(Abstra
     if (!scopes)
         return;
 
     /*
      * The StackFrame may be observed before the prologue has created the
      * CallObject. See ScopeIter::settle.
      */
     if (frame.hasCallObj())
-        scopes->liveScopes.remove(&frame.scopeChain()->asCall());
+        scopes->liveScopes.remove(&frame.scopeChain()->as<CallObject>());
 }
 
 void
 DebugScopes::onGeneratorFrameChange(AbstractFramePtr from, AbstractFramePtr to, JSContext *cx)
 {
     for (ScopeIter toIter(to, cx); !toIter.done(); ++toIter) {
         DebugScopes *scopes = ensureCompartmentData(cx);
         if (!scopes)
@@ -2031,17 +2031,17 @@ GetDebugScopeForScope(JSContext *cx, Han
         return debugScope;
 
     RootedObject enclosingDebug(cx, GetDebugScope(cx, enclosing));
     if (!enclosingDebug)
         return NULL;
 
     JSObject &maybeDecl = scope->enclosingScope();
     if (maybeDecl.isDeclEnv()) {
-        JS_ASSERT(CallObjectLambdaName(scope->asCall().callee()));
+        JS_ASSERT(CallObjectLambdaName(scope->as<CallObject>().callee()));
         enclosingDebug = DebugScopeObject::create(cx, maybeDecl.asDeclEnv(), enclosingDebug);
         if (!enclosingDebug)
             return NULL;
     }
 
     DebugScopeObject *debugScope = DebugScopeObject::create(cx, *scope, enclosingDebug);
     if (!debugScope)
         return NULL;
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -184,16 +184,18 @@ class ScopeObject : public JSObject
 class CallObject : public ScopeObject
 {
     static const uint32_t CALLEE_SLOT = 1;
 
     static CallObject *
     create(JSContext *cx, HandleScript script, HandleObject enclosing, HandleFunction callee);
 
   public:
+    static Class class_;
+
     /* These functions are internal and are exposed only for JITs. */
     static CallObject *
     create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
 
     static CallObject *
     createTemplateObject(JSContext *cx, HandleScript script, gc::InitialHeap heap);
 
     static const uint32_t RESERVED_SLOTS = 2;
@@ -624,12 +626,12 @@ inline bool
 JSObject::isNestedScope() const
 {
     return is<js::BlockObject>() || isWith();
 }
 
 inline bool
 JSObject::isScope() const
 {
-    return isCall() || isDeclEnv() || isNestedScope();
+    return is<js::CallObject>() || isDeclEnv() || isNestedScope();
 }
 
 #endif /* ScopeObject_h___ */
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -26,17 +26,17 @@ namespace js {
 /*
  * We cache name lookup results only for the global object or for native
  * non-global objects without prototype or with prototype that never mutates,
  * see bug 462734 and bug 487039.
  */
 static inline bool
 IsCacheableNonGlobalScope(JSObject *obj)
 {
-    bool cacheable = (obj->isCall() || obj->is<BlockObject>() || obj->isDeclEnv());
+    bool cacheable = (obj->is<CallObject>() || obj->is<BlockObject>() || obj->isDeclEnv());
 
     JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
     return cacheable;
 }
 
 inline HandleObject
 StackFrame::scopeChain() const
 {
@@ -204,17 +204,17 @@ StackFrame::aliasedVarScope(ScopeCoordin
         scope = &scope->asScope().enclosingScope();
     return scope->asScope();
 }
 
 inline void
 StackFrame::pushOnScopeChain(ScopeObject &scope)
 {
     JS_ASSERT(*scopeChain() == scope.enclosingScope() ||
-              *scopeChain() == scope.asCall().enclosingScope().asDeclEnv().enclosingScope());
+              *scopeChain() == scope.as<CallObject>().enclosingScope().asDeclEnv().enclosingScope());
     scopeChain_ = &scope;
     flags_ |= HAS_SCOPECHAIN;
 }
 
 inline void
 StackFrame::popOffScopeChain()
 {
     JS_ASSERT(flags_ & HAS_SCOPECHAIN);
@@ -222,19 +222,19 @@ StackFrame::popOffScopeChain()
 }
 
 inline CallObject &
 StackFrame::callObj() const
 {
     JS_ASSERT(fun()->isHeavyweight());
 
     JSObject *pobj = scopeChain();
-    while (JS_UNLIKELY(!pobj->isCall()))
+    while (JS_UNLIKELY(!pobj->is<CallObject>()))
         pobj = pobj->enclosingScope();
-    return pobj->asCall();
+    return pobj->as<CallObject>();
 }
 
 /*****************************************************************************/
 
 STATIC_POSTCONDITION(!return || ubound(from) >= nvals)
 JS_ALWAYS_INLINE bool
 StackSpace::ensureSpace(JSContext *cx, MaybeReportError report, Value *from, ptrdiff_t nvals) const
 {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -256,18 +256,18 @@ AssertDynamicScopeMatchesStaticScope(JSC
                 scope = &scope->asWith().enclosingScope();
 
             switch (i.type()) {
               case StaticScopeIter::BLOCK:
                 JS_ASSERT(i.block() == scope->asClonedBlock().staticBlock());
                 scope = &scope->asClonedBlock().enclosingScope();
                 break;
               case StaticScopeIter::FUNCTION:
-                JS_ASSERT(scope->asCall().callee().nonLazyScript() == i.funScript());
-                scope = &scope->asCall().enclosingScope();
+                JS_ASSERT(scope->as<CallObject>().callee().nonLazyScript() == i.funScript());
+                scope = &scope->as<CallObject>().enclosingScope();
                 break;
               case StaticScopeIter::NAMED_LAMBDA:
                 scope = &scope->asDeclEnv().enclosingScope();
                 break;
             }
         }
     }
 
@@ -338,17 +338,17 @@ StackFrame::epilogue(JSContext *cx)
     JS_ASSERT(!isYielding());
     JS_ASSERT(!hasBlockChain());
 
     RootedScript script(cx, this->script());
     Probes::exitScript(cx, script, script->function(), this);
 
     if (isEvalFrame()) {
         if (isStrictEvalFrame()) {
-            JS_ASSERT_IF(hasCallObj(), scopeChain()->asCall().isForEval());
+            JS_ASSERT_IF(hasCallObj(), scopeChain()->as<CallObject>().isForEval());
             if (cx->compartment()->debugMode())
                 DebugScopes::onPopStrictEvalScope(this);
         } else if (isDirectEvalFrame()) {
             if (isDebuggerFrame())
                 JS_ASSERT(!scopeChain()->isScope());
         } else {
             /*
              * Debugger.Object.prototype.evalInGlobal creates indirect eval
@@ -368,17 +368,18 @@ StackFrame::epilogue(JSContext *cx)
     if (isGlobalFrame()) {
         JS_ASSERT(!scopeChain()->isScope());
         return;
     }
 
     JS_ASSERT(isNonEvalFunctionFrame());
 
     if (fun()->isHeavyweight())
-        JS_ASSERT_IF(hasCallObj(), scopeChain()->asCall().callee().nonLazyScript() == script);
+        JS_ASSERT_IF(hasCallObj(),
+                     scopeChain()->as<CallObject>().callee().nonLazyScript() == script);
     else
         AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
 
     if (cx->compartment()->debugMode())
         DebugScopes::onPopCall(this, cx);
 
     if (isConstructing() && thisValue().isObject() && returnValue().isPrimitive())
         setReturnValue(ObjectValue(constructorThis()));
@@ -1636,19 +1637,19 @@ ScriptFrameIter::scopeChain() const
 }
 
 CallObject &
 ScriptFrameIter::callObj() const
 {
     JS_ASSERT(callee()->isHeavyweight());
 
     JSObject *pobj = scopeChain();
-    while (!pobj->isCall())
+    while (!pobj->is<CallObject>())
         pobj = pobj->enclosingScope();
-    return pobj->asCall();
+    return pobj->as<CallObject>();
 }
 
 bool
 ScriptFrameIter::hasArgsObj() const
 {
     switch (data_.state_) {
       case DONE:
         break;