js/src/jit/BaselineIC.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "jit/BaselineIC.h"
     9 #include "mozilla/DebugOnly.h"
    10 #include "mozilla/TemplateLib.h"
    12 #include "jslibmath.h"
    13 #include "jstypes.h"
    15 #include "builtin/Eval.h"
    16 #include "jit/BaselineDebugModeOSR.h"
    17 #include "jit/BaselineHelpers.h"
    18 #include "jit/BaselineJIT.h"
    19 #include "jit/IonLinker.h"
    20 #include "jit/IonSpewer.h"
    21 #include "jit/Lowering.h"
    22 #ifdef JS_ION_PERF
    23 # include "jit/PerfSpewer.h"
    24 #endif
    25 #include "jit/VMFunctions.h"
    26 #include "vm/Opcodes.h"
    28 #include "jsboolinlines.h"
    29 #include "jsscriptinlines.h"
    31 #include "jit/IonFrames-inl.h"
    32 #include "vm/Interpreter-inl.h"
    33 #include "vm/ScopeObject-inl.h"
    34 #include "vm/StringObject-inl.h"
    36 using mozilla::DebugOnly;
    38 namespace js {
    39 namespace jit {
    41 #ifdef DEBUG
    42 void
    43 FallbackICSpew(JSContext *cx, ICFallbackStub *stub, const char *fmt, ...)
    44 {
    45     if (IonSpewEnabled(IonSpew_BaselineICFallback)) {
    46         RootedScript script(cx, GetTopIonJSScript(cx));
    47         jsbytecode *pc = stub->icEntry()->pc(script);
    49         char fmtbuf[100];
    50         va_list args;
    51         va_start(args, fmt);
    52         vsnprintf(fmtbuf, 100, fmt, args);
    53         va_end(args);
    55         IonSpew(IonSpew_BaselineICFallback,
    56                 "Fallback hit for (%s:%d) (pc=%d,line=%d,uses=%d,stubs=%d): %s",
    57                 script->filename(),
    58                 script->lineno(),
    59                 (int) script->pcToOffset(pc),
    60                 PCToLineNumber(script, pc),
    61                 script->getUseCount(),
    62                 (int) stub->numOptimizedStubs(),
    63                 fmtbuf);
    64     }
    65 }
    67 void
    68 TypeFallbackICSpew(JSContext *cx, ICTypeMonitor_Fallback *stub, const char *fmt, ...)
    69 {
    70     if (IonSpewEnabled(IonSpew_BaselineICFallback)) {
    71         RootedScript script(cx, GetTopIonJSScript(cx));
    72         jsbytecode *pc = stub->icEntry()->pc(script);
    74         char fmtbuf[100];
    75         va_list args;
    76         va_start(args, fmt);
    77         vsnprintf(fmtbuf, 100, fmt, args);
    78         va_end(args);
    80         IonSpew(IonSpew_BaselineICFallback,
    81                 "Type monitor fallback hit for (%s:%d) (pc=%d,line=%d,uses=%d,stubs=%d): %s",
    82                 script->filename(),
    83                 script->lineno(),
    84                 (int) script->pcToOffset(pc),
    85                 PCToLineNumber(script, pc),
    86                 script->getUseCount(),
    87                 (int) stub->numOptimizedMonitorStubs(),
    88                 fmtbuf);
    89     }
    90 }
    92 #else
    93 #define FallbackICSpew(...)
    94 #define TypeFallbackICSpew(...)
    95 #endif
    98 ICFallbackStub *
    99 ICEntry::fallbackStub() const
   100 {
   101     return firstStub()->getChainFallback();
   102 }
   105 ICStubConstIterator &
   106 ICStubConstIterator::operator++()
   107 {
   108     JS_ASSERT(currentStub_ != nullptr);
   109     currentStub_ = currentStub_->next();
   110     return *this;
   111 }
   114 ICStubIterator::ICStubIterator(ICFallbackStub *fallbackStub, bool end)
   115   : icEntry_(fallbackStub->icEntry()),
   116     fallbackStub_(fallbackStub),
   117     previousStub_(nullptr),
   118     currentStub_(end ? fallbackStub : icEntry_->firstStub()),
   119     unlinked_(false)
   120 { }
   122 ICStubIterator &
   123 ICStubIterator::operator++()
   124 {
   125     JS_ASSERT(currentStub_->next() != nullptr);
   126     if (!unlinked_)
   127         previousStub_ = currentStub_;
   128     currentStub_ = currentStub_->next();
   129     unlinked_ = false;
   130     return *this;
   131 }
   133 void
   134 ICStubIterator::unlink(JSContext *cx)
   135 {
   136     JS_ASSERT(currentStub_->next() != nullptr);
   137     JS_ASSERT(currentStub_ != fallbackStub_);
   138     JS_ASSERT(!unlinked_);
   140     fallbackStub_->unlinkStub(cx->zone(), previousStub_, currentStub_);
   142     // Mark the current iterator position as unlinked, so operator++ works properly.
   143     unlinked_ = true;
   144 }
   147 void
   148 ICStub::markCode(JSTracer *trc, const char *name)
   149 {
   150     JitCode *stubJitCode = jitCode();
   151     MarkJitCodeUnbarriered(trc, &stubJitCode, name);
   152 }
   154 void
   155 ICStub::updateCode(JitCode *code)
   156 {
   157     // Write barrier on the old code.
   158 #ifdef JSGC_INCREMENTAL
   159     JitCode::writeBarrierPre(jitCode());
   160 #endif
   161     stubCode_ = code->raw();
   162 }
   164 /* static */ void
   165 ICStub::trace(JSTracer *trc)
   166 {
   167     markCode(trc, "baseline-stub-jitcode");
   169     // If the stub is a monitored fallback stub, then mark the monitor ICs hanging
   170     // off of that stub.  We don't need to worry about the regular monitored stubs,
   171     // because the regular monitored stubs will always have a monitored fallback stub
   172     // that references the same stub chain.
   173     if (isMonitoredFallback()) {
   174         ICTypeMonitor_Fallback *lastMonStub = toMonitoredFallbackStub()->fallbackMonitorStub();
   175         for (ICStubConstIterator iter = lastMonStub->firstMonitorStub(); !iter.atEnd(); iter++) {
   176             JS_ASSERT_IF(iter->next() == nullptr, *iter == lastMonStub);
   177             iter->trace(trc);
   178         }
   179     }
   181     if (isUpdated()) {
   182         for (ICStubConstIterator iter = toUpdatedStub()->firstUpdateStub(); !iter.atEnd(); iter++) {
   183             JS_ASSERT_IF(iter->next() == nullptr, iter->isTypeUpdate_Fallback());
   184             iter->trace(trc);
   185         }
   186     }
   188     switch (kind()) {
   189       case ICStub::Call_Scripted: {
   190         ICCall_Scripted *callStub = toCall_Scripted();
   191         MarkScript(trc, &callStub->calleeScript(), "baseline-callscripted-callee");
   192         if (callStub->templateObject())
   193             MarkObject(trc, &callStub->templateObject(), "baseline-callscripted-template");
   194         break;
   195       }
   196       case ICStub::Call_Native: {
   197         ICCall_Native *callStub = toCall_Native();
   198         MarkObject(trc, &callStub->callee(), "baseline-callnative-callee");
   199         if (callStub->templateObject())
   200             MarkObject(trc, &callStub->templateObject(), "baseline-callnative-template");
   201         break;
   202       }
   203       case ICStub::GetElem_NativeSlot: {
   204         ICGetElem_NativeSlot *getElemStub = toGetElem_NativeSlot();
   205         MarkShape(trc, &getElemStub->shape(), "baseline-getelem-native-shape");
   206         MarkString(trc, &getElemStub->name(), "baseline-getelem-native-name");
   207         break;
   208       }
   209       case ICStub::GetElem_NativePrototypeSlot: {
   210         ICGetElem_NativePrototypeSlot *getElemStub = toGetElem_NativePrototypeSlot();
   211         MarkShape(trc, &getElemStub->shape(), "baseline-getelem-nativeproto-shape");
   212         MarkString(trc, &getElemStub->name(), "baseline-getelem-nativeproto-name");
   213         MarkObject(trc, &getElemStub->holder(), "baseline-getelem-nativeproto-holder");
   214         MarkShape(trc, &getElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
   215         break;
   216       }
   217       case ICStub::GetElem_NativePrototypeCallNative:
   218       case ICStub::GetElem_NativePrototypeCallScripted: {
   219         ICGetElemNativePrototypeCallStub *callStub =
   220             reinterpret_cast<ICGetElemNativePrototypeCallStub *>(this);
   221         MarkShape(trc, &callStub->shape(), "baseline-getelem-nativeprotocall-shape");
   222         MarkString(trc, &callStub->name(), "baseline-getelem-nativeprotocall-name");
   223         MarkObject(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
   224         MarkObject(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
   225         MarkShape(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
   226         break;
   227       }
   228       case ICStub::GetElem_Dense: {
   229         ICGetElem_Dense *getElemStub = toGetElem_Dense();
   230         MarkShape(trc, &getElemStub->shape(), "baseline-getelem-dense-shape");
   231         break;
   232       }
   233       case ICStub::GetElem_TypedArray: {
   234         ICGetElem_TypedArray *getElemStub = toGetElem_TypedArray();
   235         MarkShape(trc, &getElemStub->shape(), "baseline-getelem-typedarray-shape");
   236         break;
   237       }
   238       case ICStub::SetElem_Dense: {
   239         ICSetElem_Dense *setElemStub = toSetElem_Dense();
   240         MarkShape(trc, &setElemStub->shape(), "baseline-getelem-dense-shape");
   241         MarkTypeObject(trc, &setElemStub->type(), "baseline-setelem-dense-type");
   242         break;
   243       }
   244       case ICStub::SetElem_DenseAdd: {
   245         ICSetElem_DenseAdd *setElemStub = toSetElem_DenseAdd();
   246         MarkTypeObject(trc, &setElemStub->type(), "baseline-setelem-denseadd-type");
   248         JS_STATIC_ASSERT(ICSetElem_DenseAdd::MAX_PROTO_CHAIN_DEPTH == 4);
   250         switch (setElemStub->protoChainDepth()) {
   251           case 0: setElemStub->toImpl<0>()->traceShapes(trc); break;
   252           case 1: setElemStub->toImpl<1>()->traceShapes(trc); break;
   253           case 2: setElemStub->toImpl<2>()->traceShapes(trc); break;
   254           case 3: setElemStub->toImpl<3>()->traceShapes(trc); break;
   255           case 4: setElemStub->toImpl<4>()->traceShapes(trc); break;
   256           default: MOZ_ASSUME_UNREACHABLE("Invalid proto stub.");
   257         }
   258         break;
   259       }
   260       case ICStub::SetElem_TypedArray: {
   261         ICSetElem_TypedArray *setElemStub = toSetElem_TypedArray();
   262         MarkShape(trc, &setElemStub->shape(), "baseline-setelem-typedarray-shape");
   263         break;
   264       }
   265       case ICStub::TypeMonitor_SingleObject: {
   266         ICTypeMonitor_SingleObject *monitorStub = toTypeMonitor_SingleObject();
   267         MarkObject(trc, &monitorStub->object(), "baseline-monitor-singleobject");
   268         break;
   269       }
   270       case ICStub::TypeMonitor_TypeObject: {
   271         ICTypeMonitor_TypeObject *monitorStub = toTypeMonitor_TypeObject();
   272         MarkTypeObject(trc, &monitorStub->type(), "baseline-monitor-typeobject");
   273         break;
   274       }
   275       case ICStub::TypeUpdate_SingleObject: {
   276         ICTypeUpdate_SingleObject *updateStub = toTypeUpdate_SingleObject();
   277         MarkObject(trc, &updateStub->object(), "baseline-update-singleobject");
   278         break;
   279       }
   280       case ICStub::TypeUpdate_TypeObject: {
   281         ICTypeUpdate_TypeObject *updateStub = toTypeUpdate_TypeObject();
   282         MarkTypeObject(trc, &updateStub->type(), "baseline-update-typeobject");
   283         break;
   284       }
   285       case ICStub::Profiler_PushFunction: {
   286         ICProfiler_PushFunction *pushFunStub = toProfiler_PushFunction();
   287         MarkScript(trc, &pushFunStub->script(), "baseline-profilerpushfunction-stub-script");
   288         break;
   289       }
   290       case ICStub::GetName_Global: {
   291         ICGetName_Global *globalStub = toGetName_Global();
   292         MarkShape(trc, &globalStub->shape(), "baseline-global-stub-shape");
   293         break;
   294       }
   295       case ICStub::GetName_Scope0:
   296         static_cast<ICGetName_Scope<0>*>(this)->traceScopes(trc);
   297         break;
   298       case ICStub::GetName_Scope1:
   299         static_cast<ICGetName_Scope<1>*>(this)->traceScopes(trc);
   300         break;
   301       case ICStub::GetName_Scope2:
   302         static_cast<ICGetName_Scope<2>*>(this)->traceScopes(trc);
   303         break;
   304       case ICStub::GetName_Scope3:
   305         static_cast<ICGetName_Scope<3>*>(this)->traceScopes(trc);
   306         break;
   307       case ICStub::GetName_Scope4:
   308         static_cast<ICGetName_Scope<4>*>(this)->traceScopes(trc);
   309         break;
   310       case ICStub::GetName_Scope5:
   311         static_cast<ICGetName_Scope<5>*>(this)->traceScopes(trc);
   312         break;
   313       case ICStub::GetName_Scope6:
   314         static_cast<ICGetName_Scope<6>*>(this)->traceScopes(trc);
   315         break;
   316       case ICStub::GetIntrinsic_Constant: {
   317         ICGetIntrinsic_Constant *constantStub = toGetIntrinsic_Constant();
   318         gc::MarkValue(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
   319         break;
   320       }
   321       case ICStub::GetProp_Primitive: {
   322         ICGetProp_Primitive *propStub = toGetProp_Primitive();
   323         MarkShape(trc, &propStub->protoShape(), "baseline-getprop-primitive-stub-shape");
   324         break;
   325       }
   326       case ICStub::GetProp_Native: {
   327         ICGetProp_Native *propStub = toGetProp_Native();
   328         MarkShape(trc, &propStub->shape(), "baseline-getpropnative-stub-shape");
   329         break;
   330       }
   331       case ICStub::GetProp_NativePrototype: {
   332         ICGetProp_NativePrototype *propStub = toGetProp_NativePrototype();
   333         MarkShape(trc, &propStub->shape(), "baseline-getpropnativeproto-stub-shape");
   334         MarkObject(trc, &propStub->holder(), "baseline-getpropnativeproto-stub-holder");
   335         MarkShape(trc, &propStub->holderShape(), "baseline-getpropnativeproto-stub-holdershape");
   336         break;
   337       }
   338       case ICStub::GetProp_CallDOMProxyNative:
   339       case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
   340         ICGetPropCallDOMProxyNativeStub *propStub;
   341         if (kind() ==  ICStub::GetProp_CallDOMProxyNative)
   342             propStub = toGetProp_CallDOMProxyNative();
   343         else
   344             propStub = toGetProp_CallDOMProxyWithGenerationNative();
   345         MarkShape(trc, &propStub->shape(), "baseline-getproplistbasenative-stub-shape");
   346         if (propStub->expandoShape()) {
   347             MarkShape(trc, &propStub->expandoShape(),
   348                       "baseline-getproplistbasenative-stub-expandoshape");
   349         }
   350         MarkObject(trc, &propStub->holder(), "baseline-getproplistbasenative-stub-holder");
   351         MarkShape(trc, &propStub->holderShape(), "baseline-getproplistbasenative-stub-holdershape");
   352         MarkObject(trc, &propStub->getter(), "baseline-getproplistbasenative-stub-getter");
   353         break;
   354       }
   355       case ICStub::GetProp_DOMProxyShadowed: {
   356         ICGetProp_DOMProxyShadowed *propStub = toGetProp_DOMProxyShadowed();
   357         MarkShape(trc, &propStub->shape(), "baseline-getproplistbaseshadowed-stub-shape");
   358         MarkString(trc, &propStub->name(), "baseline-getproplistbaseshadowed-stub-name");
   359         break;
   360       }
   361       case ICStub::GetProp_CallScripted: {
   362         ICGetProp_CallScripted *callStub = toGetProp_CallScripted();
   363         MarkShape(trc, &callStub->receiverShape(), "baseline-getpropcallscripted-stub-receivershape");
   364         MarkObject(trc, &callStub->holder(), "baseline-getpropcallscripted-stub-holder");
   365         MarkShape(trc, &callStub->holderShape(), "baseline-getpropcallscripted-stub-holdershape");
   366         MarkObject(trc, &callStub->getter(), "baseline-getpropcallscripted-stub-getter");
   367         break;
   368       }
   369       case ICStub::GetProp_CallNative: {
   370         ICGetProp_CallNative *callStub = toGetProp_CallNative();
   371         MarkObject(trc, &callStub->holder(), "baseline-getpropcallnative-stub-holder");
   372         MarkShape(trc, &callStub->holderShape(), "baseline-getpropcallnative-stub-holdershape");
   373         MarkObject(trc, &callStub->getter(), "baseline-getpropcallnative-stub-getter");
   374         break;
   375       }
   376       case ICStub::GetProp_CallNativePrototype: {
   377         ICGetProp_CallNativePrototype *callStub = toGetProp_CallNativePrototype();
   378         MarkShape(trc, &callStub->receiverShape(), "baseline-getpropcallnativeproto-stub-receivershape");
   379         MarkObject(trc, &callStub->holder(), "baseline-getpropcallnativeproto-stub-holder");
   380         MarkShape(trc, &callStub->holderShape(), "baseline-getpropcallnativeproto-stub-holdershape");
   381         MarkObject(trc, &callStub->getter(), "baseline-getpropcallnativeproto-stub-getter");
   382         break;
   383       }
   384       case ICStub::SetProp_Native: {
   385         ICSetProp_Native *propStub = toSetProp_Native();
   386         MarkShape(trc, &propStub->shape(), "baseline-setpropnative-stub-shape");
   387         MarkTypeObject(trc, &propStub->type(), "baseline-setpropnative-stub-type");
   388         break;
   389       }
   390       case ICStub::SetProp_NativeAdd: {
   391         ICSetProp_NativeAdd *propStub = toSetProp_NativeAdd();
   392         MarkTypeObject(trc, &propStub->type(), "baseline-setpropnativeadd-stub-type");
   393         MarkShape(trc, &propStub->newShape(), "baseline-setpropnativeadd-stub-newshape");
   394         JS_STATIC_ASSERT(ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH == 4);
   395         switch (propStub->protoChainDepth()) {
   396           case 0: propStub->toImpl<0>()->traceShapes(trc); break;
   397           case 1: propStub->toImpl<1>()->traceShapes(trc); break;
   398           case 2: propStub->toImpl<2>()->traceShapes(trc); break;
   399           case 3: propStub->toImpl<3>()->traceShapes(trc); break;
   400           case 4: propStub->toImpl<4>()->traceShapes(trc); break;
   401           default: MOZ_ASSUME_UNREACHABLE("Invalid proto stub.");
   402         }
   403         break;
   404       }
   405       case ICStub::SetProp_CallScripted: {
   406         ICSetProp_CallScripted *callStub = toSetProp_CallScripted();
   407         MarkShape(trc, &callStub->shape(), "baseline-setpropcallscripted-stub-shape");
   408         MarkObject(trc, &callStub->holder(), "baseline-setpropcallscripted-stub-holder");
   409         MarkShape(trc, &callStub->holderShape(), "baseline-setpropcallscripted-stub-holdershape");
   410         MarkObject(trc, &callStub->setter(), "baseline-setpropcallscripted-stub-setter");
   411         break;
   412       }
   413       case ICStub::SetProp_CallNative: {
   414         ICSetProp_CallNative *callStub = toSetProp_CallNative();
   415         MarkShape(trc, &callStub->shape(), "baseline-setpropcallnative-stub-shape");
   416         MarkObject(trc, &callStub->holder(), "baseline-setpropcallnative-stub-holder");
   417         MarkShape(trc, &callStub->holderShape(), "baseline-setpropcallnative-stub-holdershape");
   418         MarkObject(trc, &callStub->setter(), "baseline-setpropcallnative-stub-setter");
   419         break;
   420       }
   421       case ICStub::NewArray_Fallback: {
   422         ICNewArray_Fallback *stub = toNewArray_Fallback();
   423         MarkObject(trc, &stub->templateObject(), "baseline-newarray-template");
   424         break;
   425       }
   426       case ICStub::NewObject_Fallback: {
   427         ICNewObject_Fallback *stub = toNewObject_Fallback();
   428         MarkObject(trc, &stub->templateObject(), "baseline-newobject-template");
   429         break;
   430       }
   431       case ICStub::Rest_Fallback: {
   432         ICRest_Fallback *stub = toRest_Fallback();
   433         MarkObject(trc, &stub->templateObject(), "baseline-rest-template");
   434         break;
   435       }
   436       default:
   437         break;
   438     }
   439 }
   441 void
   442 ICFallbackStub::unlinkStub(Zone *zone, ICStub *prev, ICStub *stub)
   443 {
   444     JS_ASSERT(stub->next());
   446     // If stub is the last optimized stub, update lastStubPtrAddr.
   447     if (stub->next() == this) {
   448         JS_ASSERT(lastStubPtrAddr_ == stub->addressOfNext());
   449         if (prev)
   450             lastStubPtrAddr_ = prev->addressOfNext();
   451         else
   452             lastStubPtrAddr_ = icEntry()->addressOfFirstStub();
   453         *lastStubPtrAddr_ = this;
   454     } else {
   455         if (prev) {
   456             JS_ASSERT(prev->next() == stub);
   457             prev->setNext(stub->next());
   458         } else {
   459             JS_ASSERT(icEntry()->firstStub() == stub);
   460             icEntry()->setFirstStub(stub->next());
   461         }
   462     }
   464     JS_ASSERT(numOptimizedStubs_ > 0);
   465     numOptimizedStubs_--;
   467     if (zone->needsBarrier()) {
   468         // We are removing edges from ICStub to gcthings. Perform one final trace
   469         // of the stub for incremental GC, as it must know about those edges.
   470         stub->trace(zone->barrierTracer());
   471     }
   473     if (ICStub::CanMakeCalls(stub->kind()) && stub->isMonitored()) {
   474         // This stub can make calls so we can return to it if it's on the stack.
   475         // We just have to reset its firstMonitorStub_ field to avoid a stale
   476         // pointer when purgeOptimizedStubs destroys all optimized monitor
   477         // stubs (unlinked stubs won't be updated).
   478         ICTypeMonitor_Fallback *monitorFallback = toMonitoredFallbackStub()->fallbackMonitorStub();
   479         stub->toMonitoredStub()->resetFirstMonitorStub(monitorFallback);
   480     }
   482 #ifdef DEBUG
   483     // Poison stub code to ensure we don't call this stub again. However, if this
   484     // stub can make calls, a pointer to it may be stored in a stub frame on the
   485     // stack, so we can't touch the stubCode_ or GC will crash when marking this
   486     // pointer.
   487     if (!ICStub::CanMakeCalls(stub->kind()))
   488         stub->stubCode_ = (uint8_t *)0xbad;
   489 #endif
   490 }
   492 void
   493 ICFallbackStub::unlinkStubsWithKind(JSContext *cx, ICStub::Kind kind)
   494 {
   495     for (ICStubIterator iter = beginChain(); !iter.atEnd(); iter++) {
   496         if (iter->kind() == kind)
   497             iter.unlink(cx);
   498     }
   499 }
   501 void
   502 ICTypeMonitor_Fallback::resetMonitorStubChain(Zone *zone)
   503 {
   504     if (zone->needsBarrier()) {
   505         // We are removing edges from monitored stubs to gcthings (JitCode).
   506         // Perform one final trace of all monitor stubs for incremental GC,
   507         // as it must know about those edges.
   508         for (ICStub *s = firstMonitorStub_; !s->isTypeMonitor_Fallback(); s = s->next())
   509             s->trace(zone->barrierTracer());
   510     }
   512     firstMonitorStub_ = this;
   513     numOptimizedMonitorStubs_ = 0;
   515     if (hasFallbackStub_) {
   516         lastMonitorStubPtrAddr_ = nullptr;
   518         // Reset firstMonitorStub_ field of all monitored stubs.
   519         for (ICStubConstIterator iter = mainFallbackStub_->beginChainConst();
   520              !iter.atEnd(); iter++)
   521         {
   522             if (!iter->isMonitored())
   523                 continue;
   524             iter->toMonitoredStub()->resetFirstMonitorStub(this);
   525         }
   526     } else {
   527         icEntry_->setFirstStub(this);
   528         lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
   529     }
   530 }
   532 ICMonitoredStub::ICMonitoredStub(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub)
   533   : ICStub(kind, ICStub::Monitored, stubCode),
   534     firstMonitorStub_(firstMonitorStub)
   535 {
   536     // If the first monitored stub is a ICTypeMonitor_Fallback stub, then
   537     // double check that _its_ firstMonitorStub is the same as this one.
   538     JS_ASSERT_IF(firstMonitorStub_->isTypeMonitor_Fallback(),
   539                  firstMonitorStub_->toTypeMonitor_Fallback()->firstMonitorStub() ==
   540                     firstMonitorStub_);
   541 }
   543 bool
   544 ICMonitoredFallbackStub::initMonitoringChain(JSContext *cx, ICStubSpace *space)
   545 {
   546     JS_ASSERT(fallbackMonitorStub_ == nullptr);
   548     ICTypeMonitor_Fallback::Compiler compiler(cx, this);
   549     ICTypeMonitor_Fallback *stub = compiler.getStub(space);
   550     if (!stub)
   551         return false;
   552     fallbackMonitorStub_ = stub;
   553     return true;
   554 }
   556 bool
   557 ICMonitoredFallbackStub::addMonitorStubForValue(JSContext *cx, JSScript *script, HandleValue val)
   558 {
   559     return fallbackMonitorStub_->addMonitorStubForValue(cx, script, val);
   560 }
   562 bool
   563 ICUpdatedStub::initUpdatingChain(JSContext *cx, ICStubSpace *space)
   564 {
   565     JS_ASSERT(firstUpdateStub_ == nullptr);
   567     ICTypeUpdate_Fallback::Compiler compiler(cx);
   568     ICTypeUpdate_Fallback *stub = compiler.getStub(space);
   569     if (!stub)
   570         return false;
   572     firstUpdateStub_ = stub;
   573     return true;
   574 }
   576 JitCode *
   577 ICStubCompiler::getStubCode()
   578 {
   579     JitCompartment *comp = cx->compartment()->jitCompartment();
   581     // Check for existing cached stubcode.
   582     uint32_t stubKey = getKey();
   583     JitCode *stubCode = comp->getStubCode(stubKey);
   584     if (stubCode)
   585         return stubCode;
   587     // Compile new stubcode.
   588     IonContext ictx(cx, nullptr);
   589     MacroAssembler masm;
   590 #ifdef JS_CODEGEN_ARM
   591     masm.setSecondScratchReg(BaselineSecondScratchReg);
   592 #endif
   594     if (!generateStubCode(masm))
   595         return nullptr;
   596     Linker linker(masm);
   597     AutoFlushICache afc("getStubCode");
   598     Rooted<JitCode *> newStubCode(cx, linker.newCode<CanGC>(cx, JSC::BASELINE_CODE));
   599     if (!newStubCode)
   600         return nullptr;
   602     // After generating code, run postGenerateStubCode()
   603     if (!postGenerateStubCode(masm, newStubCode))
   604         return nullptr;
   606     // All barriers are emitted off-by-default, enable them if needed.
   607     if (cx->zone()->needsBarrier())
   608         newStubCode->togglePreBarriers(true);
   610     // Cache newly compiled stubcode.
   611     if (!comp->putStubCode(stubKey, newStubCode))
   612         return nullptr;
   614     JS_ASSERT(entersStubFrame_ == ICStub::CanMakeCalls(kind));
   616 #ifdef JS_ION_PERF
   617     writePerfSpewerJitCodeProfile(newStubCode, "BaselineIC");
   618 #endif
   620     return newStubCode;
   621 }
   623 bool
   624 ICStubCompiler::tailCallVM(const VMFunction &fun, MacroAssembler &masm)
   625 {
   626     JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
   627     if (!code)
   628         return false;
   630     uint32_t argSize = fun.explicitStackSlots() * sizeof(void *);
   631     EmitTailCallVM(code, masm, argSize);
   632     return true;
   633 }
   635 bool
   636 ICStubCompiler::callVM(const VMFunction &fun, MacroAssembler &masm)
   637 {
   638     JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
   639     if (!code)
   640         return false;
   642     EmitCallVM(code, masm);
   643     return true;
   644 }
   646 bool
   647 ICStubCompiler::callTypeUpdateIC(MacroAssembler &masm, uint32_t objectOffset)
   648 {
   649     JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(DoTypeUpdateFallbackInfo);
   650     if (!code)
   651         return false;
   653     EmitCallTypeUpdateIC(masm, code, objectOffset);
   654     return true;
   655 }
   657 void
   658 ICStubCompiler::enterStubFrame(MacroAssembler &masm, Register scratch)
   659 {
   660     EmitEnterStubFrame(masm, scratch);
   661 #ifdef DEBUG
   662     entersStubFrame_ = true;
   663 #endif
   664 }
   666 void
   667 ICStubCompiler::leaveStubFrame(MacroAssembler &masm, bool calledIntoIon)
   668 {
   669     JS_ASSERT(entersStubFrame_);
   670     EmitLeaveStubFrame(masm, calledIntoIon);
   671 }
   673 void
   674 ICStubCompiler::leaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon)
   675 {
   676     JS_ASSERT(entersStubFrame_);
   677     EmitLeaveStubFrameHead(masm, calledIntoIon);
   678 }
   680 void
   681 ICStubCompiler::leaveStubFrameCommonTail(MacroAssembler &masm)
   682 {
   683     JS_ASSERT(entersStubFrame_);
   684     EmitLeaveStubFrameCommonTail(masm);
   685 }
   687 void
   688 ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip)
   689 {
   690     // This should only be called from the following stubs.
   691     JS_ASSERT(kind == ICStub::Call_Scripted                             ||
   692               kind == ICStub::Call_AnyScripted                          ||
   693               kind == ICStub::Call_Native                               ||
   694               kind == ICStub::Call_ScriptedApplyArray                   ||
   695               kind == ICStub::Call_ScriptedApplyArguments               ||
   696               kind == ICStub::Call_ScriptedFunCall                      ||
   697               kind == ICStub::GetProp_CallScripted                      ||
   698               kind == ICStub::GetProp_CallNative                        ||
   699               kind == ICStub::GetProp_CallNativePrototype               ||
   700               kind == ICStub::GetProp_CallDOMProxyNative                ||
   701               kind == ICStub::GetElem_NativePrototypeCallNative         ||
   702               kind == ICStub::GetElem_NativePrototypeCallScripted       ||
   703               kind == ICStub::GetProp_CallDOMProxyWithGenerationNative  ||
   704               kind == ICStub::GetProp_DOMProxyShadowed                  ||
   705               kind == ICStub::SetProp_CallScripted                      ||
   706               kind == ICStub::SetProp_CallNative);
   708     // Guard on bit in frame that indicates if the SPS frame was pushed in the first
   709     // place.  This code is expected to be called from within a stub that has already
   710     // entered a stub frame.
   711     JS_ASSERT(entersStubFrame_);
   712     masm.loadPtr(Address(BaselineFrameReg, 0), scratch);
   713     masm.branchTest32(Assembler::Zero,
   714                       Address(scratch, BaselineFrame::reverseOffsetOfFlags()),
   715                       Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME),
   716                       skip);
   718     // Check if profiling is enabled
   719     uint32_t *enabledAddr = cx->runtime()->spsProfiler.addressOfEnabled();
   720     masm.branch32(Assembler::Equal, AbsoluteAddress(enabledAddr), Imm32(0), skip);
   721 }
   723 void
   724 ICStubCompiler::emitProfilingUpdate(MacroAssembler &masm, Register pcIdx, Register scratch,
   725                                     uint32_t stubPcOffset)
   726 {
   727     Label skipProfilerUpdate;
   729     // Check if profiling is enabled.
   730     guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
   732     // Update profiling entry before leaving function.
   733     masm.load32(Address(BaselineStubReg, stubPcOffset), pcIdx);
   734     masm.spsUpdatePCIdx(&cx->runtime()->spsProfiler, pcIdx, scratch);
   736     masm.bind(&skipProfilerUpdate);
   737 }
   739 void
   740 ICStubCompiler::emitProfilingUpdate(MacroAssembler &masm, GeneralRegisterSet regs,
   741                                     uint32_t stubPcOffset)
   742 {
   743     emitProfilingUpdate(masm, regs.takeAny(), regs.takeAny(), stubPcOffset);
   744 }
   746 #ifdef JSGC_GENERATIONAL
   747 inline bool
   748 ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
   749                                          Register scratch, GeneralRegisterSet saveRegs)
   750 {
   751     Nursery &nursery = cx->runtime()->gcNursery;
   753     Label skipBarrier;
   754     masm.branchTestObject(Assembler::NotEqual, val, &skipBarrier);
   756     masm.branchPtrInNurseryRange(obj, scratch, &skipBarrier);
   758     Register valReg = masm.extractObject(val, scratch);
   759     masm.branchPtr(Assembler::Below, valReg, ImmWord(nursery.start()), &skipBarrier);
   760     masm.branchPtr(Assembler::AboveOrEqual, valReg, ImmWord(nursery.heapEnd()), &skipBarrier);
   762     // void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
   763 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
   764     saveRegs.add(BaselineTailCallReg);
   765 #endif
   766     saveRegs = GeneralRegisterSet::Intersect(saveRegs, GeneralRegisterSet::Volatile());
   767     masm.PushRegsInMask(saveRegs);
   768     masm.setupUnalignedABICall(2, scratch);
   769     masm.movePtr(ImmPtr(cx->runtime()), scratch);
   770     masm.passABIArg(scratch);
   771     masm.passABIArg(obj);
   772     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PostWriteBarrier));
   773     masm.PopRegsInMask(saveRegs);
   775     masm.bind(&skipBarrier);
   776     return true;
   777 }
   778 #endif // JSGC_GENERATIONAL
   780 //
   781 // UseCount_Fallback
   782 //
   783 static bool
   784 IsTopFrameConstructing(JSContext *cx)
   785 {
   786     JS_ASSERT(cx->currentlyRunningInJit());
   787     JitActivationIterator activations(cx->runtime());
   788     JitFrameIterator iter(activations);
   789     JS_ASSERT(iter.type() == JitFrame_Exit);
   791     ++iter;
   792     JS_ASSERT(iter.type() == JitFrame_BaselineStub);
   794     ++iter;
   795     JS_ASSERT(iter.isBaselineJS());
   797     return iter.isConstructing();
   798 }
   800 static bool
   801 EnsureCanEnterIon(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *frame,
   802                   HandleScript script, jsbytecode *pc, void **jitcodePtr)
   803 {
   804     JS_ASSERT(jitcodePtr);
   805     JS_ASSERT(!*jitcodePtr);
   807     bool isLoopEntry = (JSOp(*pc) == JSOP_LOOPENTRY);
   809     bool isConstructing = IsTopFrameConstructing(cx);
   810     MethodStatus stat;
   811     if (isLoopEntry) {
   812         JS_ASSERT(LoopEntryCanIonOsr(pc));
   813         IonSpew(IonSpew_BaselineOSR, "  Compile at loop entry!");
   814         stat = CanEnterAtBranch(cx, script, frame, pc, isConstructing);
   815     } else if (frame->isFunctionFrame()) {
   816         IonSpew(IonSpew_BaselineOSR, "  Compile function from top for later entry!");
   817         stat = CompileFunctionForBaseline(cx, script, frame, isConstructing);
   818     } else {
   819         return true;
   820     }
   822     if (stat == Method_Error) {
   823         IonSpew(IonSpew_BaselineOSR, "  Compile with Ion errored!");
   824         return false;
   825     }
   827     if (stat == Method_CantCompile)
   828         IonSpew(IonSpew_BaselineOSR, "  Can't compile with Ion!");
   829     else if (stat == Method_Skipped)
   830         IonSpew(IonSpew_BaselineOSR, "  Skipped compile with Ion!");
   831     else if (stat == Method_Compiled)
   832         IonSpew(IonSpew_BaselineOSR, "  Compiled with Ion!");
   833     else
   834         MOZ_ASSUME_UNREACHABLE("Invalid MethodStatus!");
   836     // Failed to compile.  Reset use count and return.
   837     if (stat != Method_Compiled) {
   838         // TODO: If stat == Method_CantCompile, insert stub that just skips the useCount
   839         // entirely, instead of resetting it.
   840         bool bailoutExpected = script->hasIonScript() && script->ionScript()->bailoutExpected();
   841         if (stat == Method_CantCompile || bailoutExpected) {
   842             IonSpew(IonSpew_BaselineOSR, "  Reset UseCount cantCompile=%s bailoutExpected=%s!",
   843                     stat == Method_CantCompile ? "yes" : "no",
   844                     bailoutExpected ? "yes" : "no");
   845             script->resetUseCount();
   846         }
   847         return true;
   848     }
   850     if (isLoopEntry) {
   851         IonScript *ion = script->ionScript();
   852         JS_ASSERT(cx->runtime()->spsProfiler.enabled() == ion->hasSPSInstrumentation());
   853         JS_ASSERT(ion->osrPc() == pc);
   855         // If the baseline frame's SPS handling doesn't match up with the Ion code's SPS
   856         // handling, don't OSR.
   857         if (frame->hasPushedSPSFrame() != ion->hasSPSInstrumentation()) {
   858             IonSpew(IonSpew_BaselineOSR, "  OSR crosses SPS handling boundaries, skipping!");
   859             return true;
   860         }
   862         IonSpew(IonSpew_BaselineOSR, "  OSR possible!");
   863         *jitcodePtr = ion->method()->raw() + ion->osrEntryOffset();
   864     }
   866     return true;
   867 }
   869 //
   870 // The following data is kept in a temporary heap-allocated buffer, stored in
   871 // JitRuntime (high memory addresses at top, low at bottom):
   872 //
   873 //     +----->+=================================+  --      <---- High Address
   874 //     |      |                                 |   |
   875 //     |      |     ...BaselineFrame...         |   |-- Copy of BaselineFrame + stack values
   876 //     |      |                                 |   |
   877 //     |      +---------------------------------+   |
   878 //     |      |                                 |   |
   879 //     |      |     ...Locals/Stack...          |   |
   880 //     |      |                                 |   |
   881 //     |      +=================================+  --
   882 //     |      |     Padding(Maybe Empty)        |
   883 //     |      +=================================+  --
   884 //     +------|-- baselineFrame                 |   |-- IonOsrTempData
   885 //            |   jitcode                       |   |
   886 //            +=================================+  --      <---- Low Address
   887 //
   888 // A pointer to the IonOsrTempData is returned.
   890 struct IonOsrTempData
   891 {
   892     void *jitcode;
   893     uint8_t *baselineFrame;
   894 };
   896 static IonOsrTempData *
   897 PrepareOsrTempData(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *frame,
   898                    HandleScript script, jsbytecode *pc, void *jitcode)
   899 {
   900     size_t numLocalsAndStackVals = frame->numValueSlots();
   902     // Calculate the amount of space to allocate:
   903     //      BaselineFrame space:
   904     //          (sizeof(Value) * (numLocals + numStackVals))
   905     //        + sizeof(BaselineFrame)
   906     //
   907     //      IonOsrTempData space:
   908     //          sizeof(IonOsrTempData)
   910     size_t frameSpace = sizeof(BaselineFrame) + sizeof(Value) * numLocalsAndStackVals;
   911     size_t ionOsrTempDataSpace = sizeof(IonOsrTempData);
   913     size_t totalSpace = AlignBytes(frameSpace, sizeof(Value)) +
   914                         AlignBytes(ionOsrTempDataSpace, sizeof(Value));
   916     IonOsrTempData *info = (IonOsrTempData *)cx->runtime()->getJitRuntime(cx)->allocateOsrTempData(totalSpace);
   917     if (!info)
   918         return nullptr;
   920     memset(info, 0, totalSpace);
   922     info->jitcode = jitcode;
   924     // Copy the BaselineFrame + local/stack Values to the buffer. Arguments and
   925     // |this| are not copied but left on the stack: the Baseline and Ion frame
   926     // share the same frame prefix and Ion won't clobber these values. Note
   927     // that info->baselineFrame will point to the *end* of the frame data, like
   928     // the frame pointer register in baseline frames.
   929     uint8_t *frameStart = (uint8_t *)info + AlignBytes(ionOsrTempDataSpace, sizeof(Value));
   930     info->baselineFrame = frameStart + frameSpace;
   932     memcpy(frameStart, (uint8_t *)frame - numLocalsAndStackVals * sizeof(Value), frameSpace);
   934     IonSpew(IonSpew_BaselineOSR, "Allocated IonOsrTempData at %p", (void *) info);
   935     IonSpew(IonSpew_BaselineOSR, "Jitcode is %p", info->jitcode);
   937     // All done.
   938     return info;
   939 }
   941 static bool
   942 DoUseCountFallback(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *frame,
   943                    IonOsrTempData **infoPtr)
   944 {
   945     JS_ASSERT(infoPtr);
   946     *infoPtr = nullptr;
   948     // A TI OOM will disable TI and Ion.
   949     if (!jit::IsIonEnabled(cx))
   950         return true;
   952     RootedScript script(cx, frame->script());
   953     jsbytecode *pc = stub->icEntry()->pc(script);
   954     bool isLoopEntry = JSOp(*pc) == JSOP_LOOPENTRY;
   956     JS_ASSERT(!isLoopEntry || LoopEntryCanIonOsr(pc));
   958     FallbackICSpew(cx, stub, "UseCount(%d)", isLoopEntry ? int(script->pcToOffset(pc)) : int(-1));
   960     if (!script->canIonCompile()) {
   961         // TODO: ASSERT that ion-compilation-disabled checker stub doesn't exist.
   962         // TODO: Clear all optimized stubs.
   963         // TODO: Add a ion-compilation-disabled checker IC stub
   964         script->resetUseCount();
   965         return true;
   966     }
   968     JS_ASSERT(!script->isIonCompilingOffThread());
   970     // If Ion script exists, but PC is not at a loop entry, then Ion will be entered for
   971     // this script at an appropriate LOOPENTRY or the next time this function is called.
   972     if (script->hasIonScript() && !isLoopEntry) {
   973         IonSpew(IonSpew_BaselineOSR, "IonScript exists, but not at loop entry!");
   974         // TODO: ASSERT that a ion-script-already-exists checker stub doesn't exist.
   975         // TODO: Clear all optimized stubs.
   976         // TODO: Add a ion-script-already-exists checker stub.
   977         return true;
   978     }
   980     // Ensure that Ion-compiled code is available.
   981     IonSpew(IonSpew_BaselineOSR,
   982             "UseCount for %s:%d reached %d at pc %p, trying to switch to Ion!",
   983             script->filename(), script->lineno(), (int) script->getUseCount(), (void *) pc);
   984     void *jitcode = nullptr;
   985     if (!EnsureCanEnterIon(cx, stub, frame, script, pc, &jitcode))
   986         return false;
   988     // Jitcode should only be set here if not at loop entry.
   989     JS_ASSERT_IF(!isLoopEntry, !jitcode);
   990     if (!jitcode)
   991         return true;
   993     // Prepare the temporary heap copy of the fake InterpreterFrame and actual args list.
   994     IonSpew(IonSpew_BaselineOSR, "Got jitcode.  Preparing for OSR into ion.");
   995     IonOsrTempData *info = PrepareOsrTempData(cx, stub, frame, script, pc, jitcode);
   996     if (!info)
   997         return false;
   998     *infoPtr = info;
  1000     return true;
  1003 typedef bool (*DoUseCountFallbackFn)(JSContext *, ICUseCount_Fallback *, BaselineFrame *frame,
  1004                                      IonOsrTempData **infoPtr);
  1005 static const VMFunction DoUseCountFallbackInfo =
  1006     FunctionInfo<DoUseCountFallbackFn>(DoUseCountFallback);
  1008 bool
  1009 ICUseCount_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  1011     // enterStubFrame is going to clobber the BaselineFrameReg, save it in R0.scratchReg()
  1012     // first.
  1013     masm.movePtr(BaselineFrameReg, R0.scratchReg());
  1015     // Push a stub frame so that we can perform a non-tail call.
  1016     enterStubFrame(masm, R1.scratchReg());
  1018     Label noCompiledCode;
  1019     // Call DoUseCountFallback to compile/check-for Ion-compiled function
  1021         // Push IonOsrTempData pointer storage
  1022         masm.subPtr(Imm32(sizeof(void *)), BaselineStackReg);
  1023         masm.push(BaselineStackReg);
  1025         // Push IonJSFrameLayout pointer.
  1026         masm.loadBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
  1027         masm.push(R0.scratchReg());
  1029         // Push stub pointer.
  1030         masm.push(BaselineStubReg);
  1032         if (!callVM(DoUseCountFallbackInfo, masm))
  1033             return false;
  1035         // Pop IonOsrTempData pointer.
  1036         masm.pop(R0.scratchReg());
  1038         leaveStubFrame(masm);
  1040         // If no JitCode was found, then skip just exit the IC.
  1041         masm.branchPtr(Assembler::Equal, R0.scratchReg(), ImmPtr(nullptr), &noCompiledCode);
  1044     // Get a scratch register.
  1045     GeneralRegisterSet regs(availableGeneralRegs(0));
  1046     Register osrDataReg = R0.scratchReg();
  1047     regs.take(osrDataReg);
  1048     regs.takeUnchecked(OsrFrameReg);
  1050     Register scratchReg = regs.takeAny();
  1052     // At this point, stack looks like:
  1053     //  +-> [...Calling-Frame...]
  1054     //  |   [...Actual-Args/ThisV/ArgCount/Callee...]
  1055     //  |   [Descriptor]
  1056     //  |   [Return-Addr]
  1057     //  +---[Saved-FramePtr]            <-- BaselineFrameReg points here.
  1058     //      [...Baseline-Frame...]
  1060     // Restore the stack pointer to point to the saved frame pointer.
  1061     masm.movePtr(BaselineFrameReg, BaselineStackReg);
  1063     // Discard saved frame pointer, so that the return address is on top of
  1064     // the stack.
  1065     masm.pop(scratchReg);
  1067     // Jump into Ion.
  1068     masm.loadPtr(Address(osrDataReg, offsetof(IonOsrTempData, jitcode)), scratchReg);
  1069     masm.loadPtr(Address(osrDataReg, offsetof(IonOsrTempData, baselineFrame)), OsrFrameReg);
  1070     masm.jump(scratchReg);
  1072     // No jitcode available, do nothing.
  1073     masm.bind(&noCompiledCode);
  1074     EmitReturnFromIC(masm);
  1075     return true;
  1078 //
  1079 // ICProfile_Fallback
  1080 //
  1082 static bool
  1083 DoProfilerFallback(JSContext *cx, BaselineFrame *frame, ICProfiler_Fallback *stub)
  1085     RootedScript script(cx, frame->script());
  1086     RootedFunction func(cx, frame->maybeFun());
  1087     mozilla::DebugOnly<ICEntry *> icEntry = stub->icEntry();
  1089     FallbackICSpew(cx, stub, "Profiler");
  1091     SPSProfiler *profiler = &cx->runtime()->spsProfiler;
  1093     // Manually enter SPS this time.
  1094     JS_ASSERT(profiler->enabled());
  1095     if (!cx->runtime()->spsProfiler.enter(script, func))
  1096         return false;
  1097     frame->setPushedSPSFrame();
  1099     // Unlink any existing PushFunction stub (which may hold stale 'const char *' to
  1100     // the profile string.
  1101     JS_ASSERT_IF(icEntry->firstStub() != stub,
  1102                  icEntry->firstStub()->isProfiler_PushFunction() &&
  1103                  icEntry->firstStub()->next() == stub);
  1104     stub->unlinkStubsWithKind(cx, ICStub::Profiler_PushFunction);
  1105     JS_ASSERT(icEntry->firstStub() == stub);
  1107     // Generate the string to use to identify this stack frame.
  1108     const char *string = profiler->profileString(script, func);
  1109     if (string == nullptr)
  1110         return false;
  1112     IonSpew(IonSpew_BaselineIC, "  Generating Profiler_PushFunction stub for %s:%d",
  1113             script->filename(), script->lineno());
  1115     // Create a new optimized stub.
  1116     ICProfiler_PushFunction::Compiler compiler(cx, string, script);
  1117     ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
  1118     if (!optStub)
  1119         return false;
  1120     stub->addNewStub(optStub);
  1122     return true;
  1125 typedef bool (*DoProfilerFallbackFn)(JSContext *, BaselineFrame *frame, ICProfiler_Fallback *);
  1126 static const VMFunction DoProfilerFallbackInfo =
  1127     FunctionInfo<DoProfilerFallbackFn>(DoProfilerFallback);
  1129 bool
  1130 ICProfiler_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  1132     EmitRestoreTailCallReg(masm);
  1134     masm.push(BaselineStubReg);         // Push stub.
  1135     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg()); // Push frame.
  1137     return tailCallVM(DoProfilerFallbackInfo, masm);
  1140 bool
  1141 ICProfiler_PushFunction::Compiler::generateStubCode(MacroAssembler &masm)
  1144     Register scratch = R0.scratchReg();
  1145     Register scratch2 = R1.scratchReg();
  1147     // Profiling should be enabled if we ever reach here.
  1148 #ifdef DEBUG
  1149     Label spsEnabled;
  1150     uint32_t *enabledAddr = cx->runtime()->spsProfiler.addressOfEnabled();
  1151     masm.branch32(Assembler::NotEqual, AbsoluteAddress(enabledAddr), Imm32(0), &spsEnabled);
  1152     masm.assumeUnreachable("Profiling should have been enabled.");
  1153     masm.bind(&spsEnabled);
  1154 #endif
  1156     // Push SPS entry.
  1157     masm.spsPushFrame(&cx->runtime()->spsProfiler,
  1158                       Address(BaselineStubReg, ICProfiler_PushFunction::offsetOfStr()),
  1159                       Address(BaselineStubReg, ICProfiler_PushFunction::offsetOfScript()),
  1160                       scratch,
  1161                       scratch2);
  1163     // Mark frame as having profiler entry pushed.
  1164     Address flagsOffset(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags());
  1165     masm.or32(Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME), flagsOffset);
  1167     EmitReturnFromIC(masm);
  1169     return true;
  1172 //
  1173 // TypeMonitor_Fallback
  1174 //
  1176 bool
  1177 ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, JSScript *script, HandleValue val)
  1179     bool wasDetachedMonitorChain = lastMonitorStubPtrAddr_ == nullptr;
  1180     JS_ASSERT_IF(wasDetachedMonitorChain, numOptimizedMonitorStubs_ == 0);
  1182     if (numOptimizedMonitorStubs_ >= MAX_OPTIMIZED_STUBS) {
  1183         // TODO: if the TypeSet becomes unknown or has the AnyObject type,
  1184         // replace stubs with a single stub to handle these.
  1185         return true;
  1188     if (val.isPrimitive()) {
  1189         JS_ASSERT(!val.isMagic());
  1190         JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
  1192         // Check for existing TypeMonitor stub.
  1193         ICTypeMonitor_PrimitiveSet *existingStub = nullptr;
  1194         for (ICStubConstIterator iter = firstMonitorStub(); !iter.atEnd(); iter++) {
  1195             if (iter->isTypeMonitor_PrimitiveSet()) {
  1196                 existingStub = iter->toTypeMonitor_PrimitiveSet();
  1197                 if (existingStub->containsType(type))
  1198                     return true;
  1202         ICTypeMonitor_PrimitiveSet::Compiler compiler(cx, existingStub, type);
  1203         ICStub *stub = existingStub ? compiler.updateStub()
  1204                                     : compiler.getStub(compiler.getStubSpace(script));
  1205         if (!stub) {
  1206             js_ReportOutOfMemory(cx);
  1207             return false;
  1210         IonSpew(IonSpew_BaselineIC, "  %s TypeMonitor stub %p for primitive type %d",
  1211                 existingStub ? "Modified existing" : "Created new", stub, type);
  1213         if (!existingStub) {
  1214             JS_ASSERT(!hasStub(TypeMonitor_PrimitiveSet));
  1215             addOptimizedMonitorStub(stub);
  1218     } else if (val.toObject().hasSingletonType()) {
  1219         RootedObject obj(cx, &val.toObject());
  1221         // Check for existing TypeMonitor stub.
  1222         for (ICStubConstIterator iter = firstMonitorStub(); !iter.atEnd(); iter++) {
  1223             if (iter->isTypeMonitor_SingleObject() &&
  1224                 iter->toTypeMonitor_SingleObject()->object() == obj)
  1226                 return true;
  1230         ICTypeMonitor_SingleObject::Compiler compiler(cx, obj);
  1231         ICStub *stub = compiler.getStub(compiler.getStubSpace(script));
  1232         if (!stub) {
  1233             js_ReportOutOfMemory(cx);
  1234             return false;
  1237         IonSpew(IonSpew_BaselineIC, "  Added TypeMonitor stub %p for singleton %p",
  1238                 stub, obj.get());
  1240         addOptimizedMonitorStub(stub);
  1242     } else {
  1243         RootedTypeObject type(cx, val.toObject().type());
  1245         // Check for existing TypeMonitor stub.
  1246         for (ICStubConstIterator iter = firstMonitorStub(); !iter.atEnd(); iter++) {
  1247             if (iter->isTypeMonitor_TypeObject() &&
  1248                 iter->toTypeMonitor_TypeObject()->type() == type)
  1250                 return true;
  1254         ICTypeMonitor_TypeObject::Compiler compiler(cx, type);
  1255         ICStub *stub = compiler.getStub(compiler.getStubSpace(script));
  1256         if (!stub) {
  1257             js_ReportOutOfMemory(cx);
  1258             return false;
  1261         IonSpew(IonSpew_BaselineIC, "  Added TypeMonitor stub %p for TypeObject %p",
  1262                 stub, type.get());
  1264         addOptimizedMonitorStub(stub);
  1267     bool firstMonitorStubAdded = wasDetachedMonitorChain && (numOptimizedMonitorStubs_ > 0);
  1269     if (firstMonitorStubAdded) {
  1270         // Was an empty monitor chain before, but a new stub was added.  This is the
  1271         // only time that any main stubs' firstMonitorStub fields need to be updated to
  1272         // refer to the newly added monitor stub.
  1273         ICStub *firstStub = mainFallbackStub_->icEntry()->firstStub();
  1274         for (ICStubConstIterator iter = firstStub; !iter.atEnd(); iter++) {
  1275             // Non-monitored stubs are used if the result has always the same type,
  1276             // e.g. a StringLength stub will always return int32.
  1277             if (!iter->isMonitored())
  1278                 continue;
  1280             // Since we just added the first optimized monitoring stub, any
  1281             // existing main stub's |firstMonitorStub| MUST be pointing to the fallback
  1282             // monitor stub (i.e. this stub).
  1283             JS_ASSERT(iter->toMonitoredStub()->firstMonitorStub() == this);
  1284             iter->toMonitoredStub()->updateFirstMonitorStub(firstMonitorStub_);
  1288     return true;
  1291 static bool
  1292 DoTypeMonitorFallback(JSContext *cx, BaselineFrame *frame, ICTypeMonitor_Fallback *stub,
  1293                       HandleValue value, MutableHandleValue res)
  1295     RootedScript script(cx, frame->script());
  1296     jsbytecode *pc = stub->icEntry()->pc(script);
  1297     TypeFallbackICSpew(cx, stub, "TypeMonitor");
  1299     uint32_t argument;
  1300     if (stub->monitorsThis()) {
  1301         JS_ASSERT(pc == script->code());
  1302         types::TypeScript::SetThis(cx, script, value);
  1303     } else if (stub->monitorsArgument(&argument)) {
  1304         JS_ASSERT(pc == script->code());
  1305         types::TypeScript::SetArgument(cx, script, argument, value);
  1306     } else {
  1307         types::TypeScript::Monitor(cx, script, pc, value);
  1310     if (!stub->addMonitorStubForValue(cx, script, value))
  1311         return false;
  1313     // Copy input value to res.
  1314     res.set(value);
  1315     return true;
  1318 typedef bool (*DoTypeMonitorFallbackFn)(JSContext *, BaselineFrame *, ICTypeMonitor_Fallback *,
  1319                                         HandleValue, MutableHandleValue);
  1320 static const VMFunction DoTypeMonitorFallbackInfo =
  1321     FunctionInfo<DoTypeMonitorFallbackFn>(DoTypeMonitorFallback);
  1323 bool
  1324 ICTypeMonitor_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  1326     JS_ASSERT(R0 == JSReturnOperand);
  1328     // Restore the tail call register.
  1329     EmitRestoreTailCallReg(masm);
  1331     masm.pushValue(R0);
  1332     masm.push(BaselineStubReg);
  1333     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  1335     return tailCallVM(DoTypeMonitorFallbackInfo, masm);
  1338 bool
  1339 ICTypeMonitor_PrimitiveSet::Compiler::generateStubCode(MacroAssembler &masm)
  1341     Label success;
  1342     if ((flags_ & TypeToFlag(JSVAL_TYPE_INT32)) && !(flags_ & TypeToFlag(JSVAL_TYPE_DOUBLE)))
  1343         masm.branchTestInt32(Assembler::Equal, R0, &success);
  1345     if (flags_ & TypeToFlag(JSVAL_TYPE_DOUBLE))
  1346         masm.branchTestNumber(Assembler::Equal, R0, &success);
  1348     if (flags_ & TypeToFlag(JSVAL_TYPE_UNDEFINED))
  1349         masm.branchTestUndefined(Assembler::Equal, R0, &success);
  1351     if (flags_ & TypeToFlag(JSVAL_TYPE_BOOLEAN))
  1352         masm.branchTestBoolean(Assembler::Equal, R0, &success);
  1354     if (flags_ & TypeToFlag(JSVAL_TYPE_STRING))
  1355         masm.branchTestString(Assembler::Equal, R0, &success);
  1357     // Currently, we will never generate primitive stub checks for object.  However,
  1358     // when we do get to the point where we want to collapse our monitor chains of
  1359     // objects and singletons down (when they get too long) to a generic "any object"
  1360     // in coordination with the typeset doing the same thing, this will need to
  1361     // be re-enabled.
  1362     /*
  1363     if (flags_ & TypeToFlag(JSVAL_TYPE_OBJECT))
  1364         masm.branchTestObject(Assembler::Equal, R0, &success);
  1365     */
  1366     JS_ASSERT(!(flags_ & TypeToFlag(JSVAL_TYPE_OBJECT)));
  1368     if (flags_ & TypeToFlag(JSVAL_TYPE_NULL))
  1369         masm.branchTestNull(Assembler::Equal, R0, &success);
  1371     EmitStubGuardFailure(masm);
  1373     masm.bind(&success);
  1374     EmitReturnFromIC(masm);
  1375     return true;
  1378 bool
  1379 ICTypeMonitor_SingleObject::Compiler::generateStubCode(MacroAssembler &masm)
  1381     Label failure;
  1382     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  1384     // Guard on the object's identity.
  1385     Register obj = masm.extractObject(R0, ExtractTemp0);
  1386     Address expectedObject(BaselineStubReg, ICTypeMonitor_SingleObject::offsetOfObject());
  1387     masm.branchPtr(Assembler::NotEqual, expectedObject, obj, &failure);
  1389     EmitReturnFromIC(masm);
  1391     masm.bind(&failure);
  1392     EmitStubGuardFailure(masm);
  1393     return true;
  1396 bool
  1397 ICTypeMonitor_TypeObject::Compiler::generateStubCode(MacroAssembler &masm)
  1399     Label failure;
  1400     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  1402     // Guard on the object's TypeObject.
  1403     Register obj = masm.extractObject(R0, ExtractTemp0);
  1404     masm.loadPtr(Address(obj, JSObject::offsetOfType()), R1.scratchReg());
  1406     Address expectedType(BaselineStubReg, ICTypeMonitor_TypeObject::offsetOfType());
  1407     masm.branchPtr(Assembler::NotEqual, expectedType, R1.scratchReg(), &failure);
  1409     EmitReturnFromIC(masm);
  1411     masm.bind(&failure);
  1412     EmitStubGuardFailure(masm);
  1413     return true;
  1416 bool
  1417 ICUpdatedStub::addUpdateStubForValue(JSContext *cx, HandleScript script, HandleObject obj,
  1418                                      HandleId id, HandleValue val)
  1420     if (numOptimizedStubs_ >= MAX_OPTIMIZED_STUBS) {
  1421         // TODO: if the TypeSet becomes unknown or has the AnyObject type,
  1422         // replace stubs with a single stub to handle these.
  1423         return true;
  1426     types::EnsureTrackPropertyTypes(cx, obj, id);
  1428     // Make sure that undefined values are explicitly included in the property
  1429     // types for an object if generating a stub to write an undefined value.
  1430     if (val.isUndefined() && types::CanHaveEmptyPropertyTypesForOwnProperty(obj))
  1431         types::AddTypePropertyId(cx, obj, id, val);
  1433     if (val.isPrimitive()) {
  1434         JSValueType type = val.isDouble() ? JSVAL_TYPE_DOUBLE : val.extractNonDoubleType();
  1436         // Check for existing TypeUpdate stub.
  1437         ICTypeUpdate_PrimitiveSet *existingStub = nullptr;
  1438         for (ICStubConstIterator iter = firstUpdateStub_; !iter.atEnd(); iter++) {
  1439             if (iter->isTypeUpdate_PrimitiveSet()) {
  1440                 existingStub = iter->toTypeUpdate_PrimitiveSet();
  1441                 if (existingStub->containsType(type))
  1442                     return true;
  1446         ICTypeUpdate_PrimitiveSet::Compiler compiler(cx, existingStub, type);
  1447         ICStub *stub = existingStub ? compiler.updateStub()
  1448                                     : compiler.getStub(compiler.getStubSpace(script));
  1449         if (!stub)
  1450             return false;
  1451         if (!existingStub) {
  1452             JS_ASSERT(!hasTypeUpdateStub(TypeUpdate_PrimitiveSet));
  1453             addOptimizedUpdateStub(stub);
  1456         IonSpew(IonSpew_BaselineIC, "  %s TypeUpdate stub %p for primitive type %d",
  1457                 existingStub ? "Modified existing" : "Created new", stub, type);
  1459     } else if (val.toObject().hasSingletonType()) {
  1460         RootedObject obj(cx, &val.toObject());
  1462         // Check for existing TypeUpdate stub.
  1463         for (ICStubConstIterator iter = firstUpdateStub_; !iter.atEnd(); iter++) {
  1464             if (iter->isTypeUpdate_SingleObject() &&
  1465                 iter->toTypeUpdate_SingleObject()->object() == obj)
  1467                 return true;
  1471         ICTypeUpdate_SingleObject::Compiler compiler(cx, obj);
  1472         ICStub *stub = compiler.getStub(compiler.getStubSpace(script));
  1473         if (!stub)
  1474             return false;
  1476         IonSpew(IonSpew_BaselineIC, "  Added TypeUpdate stub %p for singleton %p", stub, obj.get());
  1478         addOptimizedUpdateStub(stub);
  1480     } else {
  1481         RootedTypeObject type(cx, val.toObject().type());
  1483         // Check for existing TypeUpdate stub.
  1484         for (ICStubConstIterator iter = firstUpdateStub_; !iter.atEnd(); iter++) {
  1485             if (iter->isTypeUpdate_TypeObject() &&
  1486                 iter->toTypeUpdate_TypeObject()->type() == type)
  1488                 return true;
  1492         ICTypeUpdate_TypeObject::Compiler compiler(cx, type);
  1493         ICStub *stub = compiler.getStub(compiler.getStubSpace(script));
  1494         if (!stub)
  1495             return false;
  1497         IonSpew(IonSpew_BaselineIC, "  Added TypeUpdate stub %p for TypeObject %p",
  1498                 stub, type.get());
  1500         addOptimizedUpdateStub(stub);
  1503     return true;
  1506 //
  1507 // TypeUpdate_Fallback
  1508 //
  1509 static bool
  1510 DoTypeUpdateFallback(JSContext *cx, BaselineFrame *frame, ICUpdatedStub *stub, HandleValue objval,
  1511                      HandleValue value)
  1513     FallbackICSpew(cx, stub->getChainFallback(), "TypeUpdate(%s)",
  1514                    ICStub::KindString(stub->kind()));
  1516     RootedScript script(cx, frame->script());
  1517     RootedObject obj(cx, &objval.toObject());
  1518     RootedId id(cx);
  1520     switch(stub->kind()) {
  1521       case ICStub::SetElem_Dense:
  1522       case ICStub::SetElem_DenseAdd: {
  1523         JS_ASSERT(obj->isNative());
  1524         id = JSID_VOID;
  1525         types::AddTypePropertyId(cx, obj, id, value);
  1526         break;
  1528       case ICStub::SetProp_Native:
  1529       case ICStub::SetProp_NativeAdd: {
  1530         JS_ASSERT(obj->isNative());
  1531         jsbytecode *pc = stub->getChainFallback()->icEntry()->pc(script);
  1532         if (*pc == JSOP_SETALIASEDVAR)
  1533             id = NameToId(ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc));
  1534         else
  1535             id = NameToId(script->getName(pc));
  1536         types::AddTypePropertyId(cx, obj, id, value);
  1537         break;
  1539       default:
  1540         MOZ_ASSUME_UNREACHABLE("Invalid stub");
  1543     return stub->addUpdateStubForValue(cx, script, obj, id, value);
  1546 typedef bool (*DoTypeUpdateFallbackFn)(JSContext *, BaselineFrame *, ICUpdatedStub *, HandleValue,
  1547                                        HandleValue);
  1548 const VMFunction DoTypeUpdateFallbackInfo =
  1549     FunctionInfo<DoTypeUpdateFallbackFn>(DoTypeUpdateFallback);
  1551 bool
  1552 ICTypeUpdate_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  1554     // Just store false into R1.scratchReg() and return.
  1555     masm.move32(Imm32(0), R1.scratchReg());
  1556     EmitReturnFromIC(masm);
  1557     return true;
  1560 bool
  1561 ICTypeUpdate_PrimitiveSet::Compiler::generateStubCode(MacroAssembler &masm)
  1563     Label success;
  1564     if ((flags_ & TypeToFlag(JSVAL_TYPE_INT32)) && !(flags_ & TypeToFlag(JSVAL_TYPE_DOUBLE)))
  1565         masm.branchTestInt32(Assembler::Equal, R0, &success);
  1567     if (flags_ & TypeToFlag(JSVAL_TYPE_DOUBLE))
  1568         masm.branchTestNumber(Assembler::Equal, R0, &success);
  1570     if (flags_ & TypeToFlag(JSVAL_TYPE_UNDEFINED))
  1571         masm.branchTestUndefined(Assembler::Equal, R0, &success);
  1573     if (flags_ & TypeToFlag(JSVAL_TYPE_BOOLEAN))
  1574         masm.branchTestBoolean(Assembler::Equal, R0, &success);
  1576     if (flags_ & TypeToFlag(JSVAL_TYPE_STRING))
  1577         masm.branchTestString(Assembler::Equal, R0, &success);
  1579     // Currently, we will never generate primitive stub checks for object.  However,
  1580     // when we do get to the point where we want to collapse our monitor chains of
  1581     // objects and singletons down (when they get too long) to a generic "any object"
  1582     // in coordination with the typeset doing the same thing, this will need to
  1583     // be re-enabled.
  1584     /*
  1585     if (flags_ & TypeToFlag(JSVAL_TYPE_OBJECT))
  1586         masm.branchTestObject(Assembler::Equal, R0, &success);
  1587     */
  1588     JS_ASSERT(!(flags_ & TypeToFlag(JSVAL_TYPE_OBJECT)));
  1590     if (flags_ & TypeToFlag(JSVAL_TYPE_NULL))
  1591         masm.branchTestNull(Assembler::Equal, R0, &success);
  1593     EmitStubGuardFailure(masm);
  1595     // Type matches, load true into R1.scratchReg() and return.
  1596     masm.bind(&success);
  1597     masm.mov(ImmWord(1), R1.scratchReg());
  1598     EmitReturnFromIC(masm);
  1600     return true;
  1603 bool
  1604 ICTypeUpdate_SingleObject::Compiler::generateStubCode(MacroAssembler &masm)
  1606     Label failure;
  1607     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  1609     // Guard on the object's identity.
  1610     Register obj = masm.extractObject(R0, R1.scratchReg());
  1611     Address expectedObject(BaselineStubReg, ICTypeUpdate_SingleObject::offsetOfObject());
  1612     masm.branchPtr(Assembler::NotEqual, expectedObject, obj, &failure);
  1614     // Identity matches, load true into R1.scratchReg() and return.
  1615     masm.mov(ImmWord(1), R1.scratchReg());
  1616     EmitReturnFromIC(masm);
  1618     masm.bind(&failure);
  1619     EmitStubGuardFailure(masm);
  1620     return true;
  1623 bool
  1624 ICTypeUpdate_TypeObject::Compiler::generateStubCode(MacroAssembler &masm)
  1626     Label failure;
  1627     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  1629     // Guard on the object's TypeObject.
  1630     Register obj = masm.extractObject(R0, R1.scratchReg());
  1631     masm.loadPtr(Address(obj, JSObject::offsetOfType()), R1.scratchReg());
  1633     Address expectedType(BaselineStubReg, ICTypeUpdate_TypeObject::offsetOfType());
  1634     masm.branchPtr(Assembler::NotEqual, expectedType, R1.scratchReg(), &failure);
  1636     // Type matches, load true into R1.scratchReg() and return.
  1637     masm.mov(ImmWord(1), R1.scratchReg());
  1638     EmitReturnFromIC(masm);
  1640     masm.bind(&failure);
  1641     EmitStubGuardFailure(masm);
  1642     return true;
  1645 //
  1646 // VM function to help call native getters.
  1647 //
  1649 static bool
  1650 DoCallNativeGetter(JSContext *cx, HandleFunction callee, HandleObject obj,
  1651                    MutableHandleValue result)
  1653     JS_ASSERT(callee->isNative());
  1654     JSNative natfun = callee->native();
  1656     JS::AutoValueArray<2> vp(cx);
  1657     vp[0].setObject(*callee.get());
  1658     vp[1].setObject(*obj.get());
  1660     if (!natfun(cx, 0, vp.begin()))
  1661         return false;
  1663     result.set(vp[0]);
  1664     return true;
  1667 typedef bool (*DoCallNativeGetterFn)(JSContext *, HandleFunction, HandleObject, MutableHandleValue);
  1668 static const VMFunction DoCallNativeGetterInfo =
  1669     FunctionInfo<DoCallNativeGetterFn>(DoCallNativeGetter);
  1671 //
  1672 // This_Fallback
  1673 //
  1675 static bool
  1676 DoThisFallback(JSContext *cx, ICThis_Fallback *stub, HandleValue thisv, MutableHandleValue ret)
  1678     FallbackICSpew(cx, stub, "This");
  1680     JSObject *thisObj = BoxNonStrictThis(cx, thisv);
  1681     if (!thisObj)
  1682         return false;
  1684     ret.setObject(*thisObj);
  1685     return true;
  1688 typedef bool (*DoThisFallbackFn)(JSContext *, ICThis_Fallback *, HandleValue, MutableHandleValue);
  1689 static const VMFunction DoThisFallbackInfo = FunctionInfo<DoThisFallbackFn>(DoThisFallback);
  1691 bool
  1692 ICThis_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  1694     JS_ASSERT(R0 == JSReturnOperand);
  1696     // Restore the tail call register.
  1697     EmitRestoreTailCallReg(masm);
  1699     masm.pushValue(R0);
  1700     masm.push(BaselineStubReg);
  1702     return tailCallVM(DoThisFallbackInfo, masm);
  1705 //
  1706 // NewArray_Fallback
  1707 //
  1709 static bool
  1710 DoNewArray(JSContext *cx, ICNewArray_Fallback *stub, uint32_t length,
  1711            HandleTypeObject type, MutableHandleValue res)
  1713     FallbackICSpew(cx, stub, "NewArray");
  1715     JSObject *obj = NewInitArray(cx, length, type);
  1716     if (!obj)
  1717         return false;
  1719     res.setObject(*obj);
  1720     return true;
  1723 typedef bool(*DoNewArrayFn)(JSContext *, ICNewArray_Fallback *, uint32_t, HandleTypeObject,
  1724                             MutableHandleValue);
  1725 static const VMFunction DoNewArrayInfo = FunctionInfo<DoNewArrayFn>(DoNewArray);
  1727 bool
  1728 ICNewArray_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  1730     EmitRestoreTailCallReg(masm);
  1732     masm.push(R1.scratchReg()); // type
  1733     masm.push(R0.scratchReg()); // length
  1734     masm.push(BaselineStubReg); // stub.
  1736     return tailCallVM(DoNewArrayInfo, masm);
  1739 //
  1740 // NewObject_Fallback
  1741 //
  1743 static bool
  1744 DoNewObject(JSContext *cx, ICNewObject_Fallback *stub, MutableHandleValue res)
  1746     FallbackICSpew(cx, stub, "NewObject");
  1748     RootedObject templateObject(cx, stub->templateObject());
  1749     JSObject *obj = NewInitObject(cx, templateObject);
  1750     if (!obj)
  1751         return false;
  1753     res.setObject(*obj);
  1754     return true;
  1757 typedef bool(*DoNewObjectFn)(JSContext *, ICNewObject_Fallback *, MutableHandleValue);
  1758 static const VMFunction DoNewObjectInfo = FunctionInfo<DoNewObjectFn>(DoNewObject);
  1760 bool
  1761 ICNewObject_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  1763     EmitRestoreTailCallReg(masm);
  1765     masm.push(BaselineStubReg); // stub.
  1767     return tailCallVM(DoNewObjectInfo, masm);
  1770 //
  1771 // Compare_Fallback
  1772 //
  1774 static bool
  1775 DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub_, HandleValue lhs,
  1776                   HandleValue rhs, MutableHandleValue ret)
  1778     // This fallback stub may trigger debug mode toggling.
  1779     DebugModeOSRVolatileStub<ICCompare_Fallback *> stub(frame, stub_);
  1781     jsbytecode *pc = stub->icEntry()->pc(frame->script());
  1782     JSOp op = JSOp(*pc);
  1784     FallbackICSpew(cx, stub, "Compare(%s)", js_CodeName[op]);
  1786     // Case operations in a CONDSWITCH are performing strict equality.
  1787     if (op == JSOP_CASE)
  1788         op = JSOP_STRICTEQ;
  1790     // Don't pass lhs/rhs directly, we need the original values when
  1791     // generating stubs.
  1792     RootedValue lhsCopy(cx, lhs);
  1793     RootedValue rhsCopy(cx, rhs);
  1795     // Perform the compare operation.
  1796     bool out;
  1797     switch(op) {
  1798       case JSOP_LT:
  1799         if (!LessThan(cx, &lhsCopy, &rhsCopy, &out))
  1800             return false;
  1801         break;
  1802       case JSOP_LE:
  1803         if (!LessThanOrEqual(cx, &lhsCopy, &rhsCopy, &out))
  1804             return false;
  1805         break;
  1806       case JSOP_GT:
  1807         if (!GreaterThan(cx, &lhsCopy, &rhsCopy, &out))
  1808             return false;
  1809         break;
  1810       case JSOP_GE:
  1811         if (!GreaterThanOrEqual(cx, &lhsCopy, &rhsCopy, &out))
  1812             return false;
  1813         break;
  1814       case JSOP_EQ:
  1815         if (!LooselyEqual<true>(cx, &lhsCopy, &rhsCopy, &out))
  1816             return false;
  1817         break;
  1818       case JSOP_NE:
  1819         if (!LooselyEqual<false>(cx, &lhsCopy, &rhsCopy, &out))
  1820             return false;
  1821         break;
  1822       case JSOP_STRICTEQ:
  1823         if (!StrictlyEqual<true>(cx, &lhsCopy, &rhsCopy, &out))
  1824             return false;
  1825         break;
  1826       case JSOP_STRICTNE:
  1827         if (!StrictlyEqual<false>(cx, &lhsCopy, &rhsCopy, &out))
  1828             return false;
  1829         break;
  1830       default:
  1831         JS_ASSERT(!"Unhandled baseline compare op");
  1832         return false;
  1835     ret.setBoolean(out);
  1837     // Check if debug mode toggling made the stub invalid.
  1838     if (stub.invalid())
  1839         return true;
  1841     // Check to see if a new stub should be generated.
  1842     if (stub->numOptimizedStubs() >= ICCompare_Fallback::MAX_OPTIMIZED_STUBS) {
  1843         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
  1844         // But for now we just bail.
  1845         return true;
  1848     JSScript *script = frame->script();
  1850     // Try to generate new stubs.
  1851     if (lhs.isInt32() && rhs.isInt32()) {
  1852         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32, Int32) stub", js_CodeName[op]);
  1853         ICCompare_Int32::Compiler compiler(cx, op);
  1854         ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
  1855         if (!int32Stub)
  1856             return false;
  1858         stub->addNewStub(int32Stub);
  1859         return true;
  1862     if (!cx->runtime()->jitSupportsFloatingPoint && (lhs.isNumber() || rhs.isNumber()))
  1863         return true;
  1865     if (lhs.isNumber() && rhs.isNumber()) {
  1866         IonSpew(IonSpew_BaselineIC, "  Generating %s(Number, Number) stub", js_CodeName[op]);
  1868         // Unlink int32 stubs, it's faster to always use the double stub.
  1869         stub->unlinkStubsWithKind(cx, ICStub::Compare_Int32);
  1871         ICCompare_Double::Compiler compiler(cx, op);
  1872         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
  1873         if (!doubleStub)
  1874             return false;
  1876         stub->addNewStub(doubleStub);
  1877         return true;
  1880     if ((lhs.isNumber() && rhs.isUndefined()) ||
  1881         (lhs.isUndefined() && rhs.isNumber()))
  1883         IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
  1884                     rhs.isUndefined() ? "Number" : "Undefined",
  1885                     rhs.isUndefined() ? "Undefined" : "Number");
  1886         ICCompare_NumberWithUndefined::Compiler compiler(cx, op, lhs.isUndefined());
  1887         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
  1888         if (!doubleStub)
  1889             return false;
  1891         stub->addNewStub(doubleStub);
  1892         return true;
  1895     if (lhs.isBoolean() && rhs.isBoolean()) {
  1896         IonSpew(IonSpew_BaselineIC, "  Generating %s(Boolean, Boolean) stub", js_CodeName[op]);
  1897         ICCompare_Boolean::Compiler compiler(cx, op);
  1898         ICStub *booleanStub = compiler.getStub(compiler.getStubSpace(script));
  1899         if (!booleanStub)
  1900             return false;
  1902         stub->addNewStub(booleanStub);
  1903         return true;
  1906     if ((lhs.isBoolean() && rhs.isInt32()) || (lhs.isInt32() && rhs.isBoolean())) {
  1907         IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
  1908                     rhs.isInt32() ? "Boolean" : "Int32",
  1909                     rhs.isInt32() ? "Int32" : "Boolean");
  1910         ICCompare_Int32WithBoolean::Compiler compiler(cx, op, lhs.isInt32());
  1911         ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
  1912         if (!optStub)
  1913             return false;
  1915         stub->addNewStub(optStub);
  1916         return true;
  1919     if (IsEqualityOp(op)) {
  1920         if (lhs.isString() && rhs.isString() && !stub->hasStub(ICStub::Compare_String)) {
  1921             IonSpew(IonSpew_BaselineIC, "  Generating %s(String, String) stub", js_CodeName[op]);
  1922             ICCompare_String::Compiler compiler(cx, op);
  1923             ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script));
  1924             if (!stringStub)
  1925                 return false;
  1927             stub->addNewStub(stringStub);
  1928             return true;
  1931         if (lhs.isObject() && rhs.isObject()) {
  1932             JS_ASSERT(!stub->hasStub(ICStub::Compare_Object));
  1933             IonSpew(IonSpew_BaselineIC, "  Generating %s(Object, Object) stub", js_CodeName[op]);
  1934             ICCompare_Object::Compiler compiler(cx, op);
  1935             ICStub *objectStub = compiler.getStub(compiler.getStubSpace(script));
  1936             if (!objectStub)
  1937                 return false;
  1939             stub->addNewStub(objectStub);
  1940             return true;
  1943         if ((lhs.isObject() || lhs.isNull() || lhs.isUndefined()) &&
  1944             (rhs.isObject() || rhs.isNull() || rhs.isUndefined()) &&
  1945             !stub->hasStub(ICStub::Compare_ObjectWithUndefined))
  1947             IonSpew(IonSpew_BaselineIC, "  Generating %s(Obj/Null/Undef, Obj/Null/Undef) stub",
  1948                     js_CodeName[op]);
  1949             bool lhsIsUndefined = lhs.isNull() || lhs.isUndefined();
  1950             bool compareWithNull = lhs.isNull() || rhs.isNull();
  1951             ICCompare_ObjectWithUndefined::Compiler compiler(cx, op,
  1952                                                              lhsIsUndefined, compareWithNull);
  1953             ICStub *objectStub = compiler.getStub(compiler.getStubSpace(script));
  1954             if (!objectStub)
  1955                 return false;
  1957             stub->addNewStub(objectStub);
  1958             return true;
  1962     return true;
  1965 typedef bool (*DoCompareFallbackFn)(JSContext *, BaselineFrame *, ICCompare_Fallback *,
  1966                                     HandleValue, HandleValue, MutableHandleValue);
  1967 static const VMFunction DoCompareFallbackInfo =
  1968     FunctionInfo<DoCompareFallbackFn>(DoCompareFallback, PopValues(2));
  1970 bool
  1971 ICCompare_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  1973     JS_ASSERT(R0 == JSReturnOperand);
  1975     // Restore the tail call register.
  1976     EmitRestoreTailCallReg(masm);
  1978     // Ensure stack is fully synced for the expression decompiler.
  1979     masm.pushValue(R0);
  1980     masm.pushValue(R1);
  1982     // Push arguments.
  1983     masm.pushValue(R1);
  1984     masm.pushValue(R0);
  1985     masm.push(BaselineStubReg);
  1986     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  1987     return tailCallVM(DoCompareFallbackInfo, masm);
  1990 //
  1991 // Compare_String
  1992 //
  1994 bool
  1995 ICCompare_String::Compiler::generateStubCode(MacroAssembler &masm)
  1997     Label failure;
  1998     masm.branchTestString(Assembler::NotEqual, R0, &failure);
  1999     masm.branchTestString(Assembler::NotEqual, R1, &failure);
  2001     JS_ASSERT(IsEqualityOp(op));
  2003     Register left = masm.extractString(R0, ExtractTemp0);
  2004     Register right = masm.extractString(R1, ExtractTemp1);
  2006     GeneralRegisterSet regs(availableGeneralRegs(2));
  2007     Register scratchReg = regs.takeAny();
  2008     // x86 doesn't have the luxury of a second scratch.
  2009     Register scratchReg2;
  2010     if (regs.empty()) {
  2011         scratchReg2 = BaselineStubReg;
  2012         masm.push(BaselineStubReg);
  2013     } else {
  2014         scratchReg2 = regs.takeAny();
  2016     JS_ASSERT(scratchReg2 != scratchReg);
  2018     Label inlineCompareFailed;
  2019     masm.compareStrings(op, left, right, scratchReg2, scratchReg, &inlineCompareFailed);
  2020     masm.tagValue(JSVAL_TYPE_BOOLEAN, scratchReg2, R0);
  2021     if (scratchReg2 == BaselineStubReg)
  2022         masm.pop(BaselineStubReg);
  2023     EmitReturnFromIC(masm);
  2025     masm.bind(&inlineCompareFailed);
  2026     if (scratchReg2 == BaselineStubReg)
  2027         masm.pop(BaselineStubReg);
  2028     masm.bind(&failure);
  2029     EmitStubGuardFailure(masm);
  2030     return true;
  2033 //
  2034 // Compare_Boolean
  2035 //
  2037 bool
  2038 ICCompare_Boolean::Compiler::generateStubCode(MacroAssembler &masm)
  2040     Label failure;
  2041     masm.branchTestBoolean(Assembler::NotEqual, R0, &failure);
  2042     masm.branchTestBoolean(Assembler::NotEqual, R1, &failure);
  2044     Register left = masm.extractInt32(R0, ExtractTemp0);
  2045     Register right = masm.extractInt32(R1, ExtractTemp1);
  2047     // Compare payload regs of R0 and R1.
  2048     Assembler::Condition cond = JSOpToCondition(op, /* signed = */true);
  2049     masm.cmp32Set(cond, left, right, left);
  2051     // Box the result and return
  2052     masm.tagValue(JSVAL_TYPE_BOOLEAN, left, R0);
  2053     EmitReturnFromIC(masm);
  2055     // Failure case - jump to next stub
  2056     masm.bind(&failure);
  2057     EmitStubGuardFailure(masm);
  2058     return true;
  2061 //
  2062 // Compare_NumberWithUndefined
  2063 //
  2065 bool
  2066 ICCompare_NumberWithUndefined::Compiler::generateStubCode(MacroAssembler &masm)
  2068     ValueOperand numberOperand, undefinedOperand;
  2069     if (lhsIsUndefined) {
  2070         numberOperand = R1;
  2071         undefinedOperand = R0;
  2072     } else {
  2073         numberOperand = R0;
  2074         undefinedOperand = R1;
  2077     Label failure;
  2078     masm.branchTestNumber(Assembler::NotEqual, numberOperand, &failure);
  2079     masm.branchTestUndefined(Assembler::NotEqual, undefinedOperand, &failure);
  2081     // Comparing a number with undefined will always be true for NE/STRICTNE,
  2082     // and always be false for other compare ops.
  2083     masm.moveValue(BooleanValue(op == JSOP_NE || op == JSOP_STRICTNE), R0);
  2085     EmitReturnFromIC(masm);
  2087     // Failure case - jump to next stub
  2088     masm.bind(&failure);
  2089     EmitStubGuardFailure(masm);
  2090     return true;
  2093 //
  2094 // Compare_Object
  2095 //
  2097 bool
  2098 ICCompare_Object::Compiler::generateStubCode(MacroAssembler &masm)
  2100     Label failure;
  2101     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  2102     masm.branchTestObject(Assembler::NotEqual, R1, &failure);
  2104     JS_ASSERT(IsEqualityOp(op));
  2106     Register left = masm.extractObject(R0, ExtractTemp0);
  2107     Register right = masm.extractObject(R1, ExtractTemp1);
  2109     Label ifTrue;
  2110     masm.branchPtr(JSOpToCondition(op, /* signed = */true), left, right, &ifTrue);
  2112     masm.moveValue(BooleanValue(false), R0);
  2113     EmitReturnFromIC(masm);
  2115     masm.bind(&ifTrue);
  2116     masm.moveValue(BooleanValue(true), R0);
  2117     EmitReturnFromIC(masm);
  2119     // Failure case - jump to next stub
  2120     masm.bind(&failure);
  2121     EmitStubGuardFailure(masm);
  2122     return true;
  2125 //
  2126 // Compare_ObjectWithUndefined
  2127 //
  2129 bool
  2130 ICCompare_ObjectWithUndefined::Compiler::generateStubCode(MacroAssembler &masm)
  2132     JS_ASSERT(IsEqualityOp(op));
  2134     ValueOperand objectOperand, undefinedOperand;
  2135     if (lhsIsUndefined) {
  2136         objectOperand = R1;
  2137         undefinedOperand = R0;
  2138     } else {
  2139         objectOperand = R0;
  2140         undefinedOperand = R1;
  2143     Label failure;
  2144     if (compareWithNull)
  2145         masm.branchTestNull(Assembler::NotEqual, undefinedOperand, &failure);
  2146     else
  2147         masm.branchTestUndefined(Assembler::NotEqual, undefinedOperand, &failure);
  2149     Label notObject;
  2150     masm.branchTestObject(Assembler::NotEqual, objectOperand, &notObject);
  2152     if (op == JSOP_STRICTEQ || op == JSOP_STRICTNE) {
  2153         // obj !== undefined for all objects.
  2154         masm.moveValue(BooleanValue(op == JSOP_STRICTNE), R0);
  2155         EmitReturnFromIC(masm);
  2156     } else {
  2157         // obj != undefined only where !obj->getClass()->emulatesUndefined()
  2158         Label emulatesUndefined;
  2159         Register obj = masm.extractObject(objectOperand, ExtractTemp0);
  2160         masm.loadPtr(Address(obj, JSObject::offsetOfType()), obj);
  2161         masm.loadPtr(Address(obj, types::TypeObject::offsetOfClasp()), obj);
  2162         masm.branchTest32(Assembler::NonZero,
  2163                           Address(obj, Class::offsetOfFlags()),
  2164                           Imm32(JSCLASS_EMULATES_UNDEFINED),
  2165                           &emulatesUndefined);
  2166         masm.moveValue(BooleanValue(op == JSOP_NE), R0);
  2167         EmitReturnFromIC(masm);
  2168         masm.bind(&emulatesUndefined);
  2169         masm.moveValue(BooleanValue(op == JSOP_EQ), R0);
  2170         EmitReturnFromIC(masm);
  2173     masm.bind(&notObject);
  2175     // Also support null == null or undefined == undefined comparisons.
  2176     if (compareWithNull)
  2177         masm.branchTestNull(Assembler::NotEqual, objectOperand, &failure);
  2178     else
  2179         masm.branchTestUndefined(Assembler::NotEqual, objectOperand, &failure);
  2181     masm.moveValue(BooleanValue(op == JSOP_STRICTEQ || op == JSOP_EQ), R0);
  2182     EmitReturnFromIC(masm);
  2184     // Failure case - jump to next stub
  2185     masm.bind(&failure);
  2186     EmitStubGuardFailure(masm);
  2187     return true;
  2190 //
  2191 // Compare_Int32WithBoolean
  2192 //
  2194 bool
  2195 ICCompare_Int32WithBoolean::Compiler::generateStubCode(MacroAssembler &masm)
  2197     Label failure;
  2198     ValueOperand int32Val;
  2199     ValueOperand boolVal;
  2200     if (lhsIsInt32_) {
  2201         int32Val = R0;
  2202         boolVal = R1;
  2203     } else {
  2204         boolVal = R0;
  2205         int32Val = R1;
  2207     masm.branchTestBoolean(Assembler::NotEqual, boolVal, &failure);
  2208     masm.branchTestInt32(Assembler::NotEqual, int32Val, &failure);
  2210     if (op_ == JSOP_STRICTEQ || op_ == JSOP_STRICTNE) {
  2211         // Ints and booleans are never strictly equal, always strictly not equal.
  2212         masm.moveValue(BooleanValue(op_ == JSOP_STRICTNE), R0);
  2213         EmitReturnFromIC(masm);
  2214     } else {
  2215         Register boolReg = masm.extractBoolean(boolVal, ExtractTemp0);
  2216         Register int32Reg = masm.extractInt32(int32Val, ExtractTemp1);
  2218         // Compare payload regs of R0 and R1.
  2219         Assembler::Condition cond = JSOpToCondition(op_, /* signed = */true);
  2220         masm.cmp32Set(cond, (lhsIsInt32_ ? int32Reg : boolReg),
  2221                       (lhsIsInt32_ ? boolReg : int32Reg), R0.scratchReg());
  2223         // Box the result and return
  2224         masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.scratchReg(), R0);
  2225         EmitReturnFromIC(masm);
  2228     // Failure case - jump to next stub
  2229     masm.bind(&failure);
  2230     EmitStubGuardFailure(masm);
  2231     return true;
  2234 //
  2235 // ToBool_Fallback
  2236 //
  2238 static bool
  2239 DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, HandleValue arg,
  2240                  MutableHandleValue ret)
  2242     FallbackICSpew(cx, stub, "ToBool");
  2244     bool cond = ToBoolean(arg);
  2245     ret.setBoolean(cond);
  2247     // Check to see if a new stub should be generated.
  2248     if (stub->numOptimizedStubs() >= ICToBool_Fallback::MAX_OPTIMIZED_STUBS) {
  2249         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
  2250         // But for now we just bail.
  2251         return true;
  2254     JS_ASSERT(!arg.isBoolean());
  2256     JSScript *script = frame->script();
  2258     // Try to generate new stubs.
  2259     if (arg.isInt32()) {
  2260         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(Int32) stub.");
  2261         ICToBool_Int32::Compiler compiler(cx);
  2262         ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
  2263         if (!int32Stub)
  2264             return false;
  2266         stub->addNewStub(int32Stub);
  2267         return true;
  2270     if (arg.isDouble() && cx->runtime()->jitSupportsFloatingPoint) {
  2271         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(Double) stub.");
  2272         ICToBool_Double::Compiler compiler(cx);
  2273         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
  2274         if (!doubleStub)
  2275             return false;
  2277         stub->addNewStub(doubleStub);
  2278         return true;
  2281     if (arg.isString()) {
  2282         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(String) stub");
  2283         ICToBool_String::Compiler compiler(cx);
  2284         ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script));
  2285         if (!stringStub)
  2286             return false;
  2288         stub->addNewStub(stringStub);
  2289         return true;
  2292     if (arg.isNull() || arg.isUndefined()) {
  2293         ICToBool_NullUndefined::Compiler compiler(cx);
  2294         ICStub *nilStub = compiler.getStub(compiler.getStubSpace(script));
  2295         if (!nilStub)
  2296             return false;
  2298         stub->addNewStub(nilStub);
  2299         return true;
  2302     if (arg.isObject()) {
  2303         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(Object) stub.");
  2304         ICToBool_Object::Compiler compiler(cx);
  2305         ICStub *objStub = compiler.getStub(compiler.getStubSpace(script));
  2306         if (!objStub)
  2307             return false;
  2309         stub->addNewStub(objStub);
  2310         return true;
  2313     return true;
  2316 typedef bool (*pf)(JSContext *, BaselineFrame *, ICToBool_Fallback *, HandleValue,
  2317                    MutableHandleValue);
  2318 static const VMFunction fun = FunctionInfo<pf>(DoToBoolFallback);
  2320 bool
  2321 ICToBool_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  2323     JS_ASSERT(R0 == JSReturnOperand);
  2325     // Restore the tail call register.
  2326     EmitRestoreTailCallReg(masm);
  2328     // Push arguments.
  2329     masm.pushValue(R0);
  2330     masm.push(BaselineStubReg);
  2331     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  2333     return tailCallVM(fun, masm);
  2336 //
  2337 // ToBool_Int32
  2338 //
  2340 bool
  2341 ICToBool_Int32::Compiler::generateStubCode(MacroAssembler &masm)
  2343     Label failure;
  2344     masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
  2346     Label ifFalse;
  2347     masm.branchTestInt32Truthy(false, R0, &ifFalse);
  2349     masm.moveValue(BooleanValue(true), R0);
  2350     EmitReturnFromIC(masm);
  2352     masm.bind(&ifFalse);
  2353     masm.moveValue(BooleanValue(false), R0);
  2354     EmitReturnFromIC(masm);
  2356     // Failure case - jump to next stub
  2357     masm.bind(&failure);
  2358     EmitStubGuardFailure(masm);
  2359     return true;
  2362 //
  2363 // ToBool_String
  2364 //
  2366 bool
  2367 ICToBool_String::Compiler::generateStubCode(MacroAssembler &masm)
  2369     Label failure;
  2370     masm.branchTestString(Assembler::NotEqual, R0, &failure);
  2372     Label ifFalse;
  2373     masm.branchTestStringTruthy(false, R0, &ifFalse);
  2375     masm.moveValue(BooleanValue(true), R0);
  2376     EmitReturnFromIC(masm);
  2378     masm.bind(&ifFalse);
  2379     masm.moveValue(BooleanValue(false), R0);
  2380     EmitReturnFromIC(masm);
  2382     // Failure case - jump to next stub
  2383     masm.bind(&failure);
  2384     EmitStubGuardFailure(masm);
  2385     return true;
  2388 //
  2389 // ToBool_NullUndefined
  2390 //
  2392 bool
  2393 ICToBool_NullUndefined::Compiler::generateStubCode(MacroAssembler &masm)
  2395     Label failure, ifFalse;
  2396     masm.branchTestNull(Assembler::Equal, R0, &ifFalse);
  2397     masm.branchTestUndefined(Assembler::NotEqual, R0, &failure);
  2399     masm.bind(&ifFalse);
  2400     masm.moveValue(BooleanValue(false), R0);
  2401     EmitReturnFromIC(masm);
  2403     // Failure case - jump to next stub
  2404     masm.bind(&failure);
  2405     EmitStubGuardFailure(masm);
  2406     return true;
  2409 //
  2410 // ToBool_Double
  2411 //
  2413 bool
  2414 ICToBool_Double::Compiler::generateStubCode(MacroAssembler &masm)
  2416     Label failure, ifTrue;
  2417     masm.branchTestDouble(Assembler::NotEqual, R0, &failure);
  2418     masm.unboxDouble(R0, FloatReg0);
  2419     masm.branchTestDoubleTruthy(true, FloatReg0, &ifTrue);
  2421     masm.moveValue(BooleanValue(false), R0);
  2422     EmitReturnFromIC(masm);
  2424     masm.bind(&ifTrue);
  2425     masm.moveValue(BooleanValue(true), R0);
  2426     EmitReturnFromIC(masm);
  2428     // Failure case - jump to next stub
  2429     masm.bind(&failure);
  2430     EmitStubGuardFailure(masm);
  2431     return true;
  2434 //
  2435 // ToBool_Object
  2436 //
  2438 bool
  2439 ICToBool_Object::Compiler::generateStubCode(MacroAssembler &masm)
  2441     Label failure, ifFalse, slowPath;
  2442     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  2444     Register objReg = masm.extractObject(R0, ExtractTemp0);
  2445     Register scratch = R1.scratchReg();
  2446     masm.branchTestObjectTruthy(false, objReg, scratch, &slowPath, &ifFalse);
  2448     // If object doesn't emulate undefined, it evaulates to true.
  2449     masm.moveValue(BooleanValue(true), R0);
  2450     EmitReturnFromIC(masm);
  2452     masm.bind(&ifFalse);
  2453     masm.moveValue(BooleanValue(false), R0);
  2454     EmitReturnFromIC(masm);
  2456     masm.bind(&slowPath);
  2457     masm.setupUnalignedABICall(1, scratch);
  2458     masm.passABIArg(objReg);
  2459     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::EmulatesUndefined));
  2460     masm.convertBoolToInt32(ReturnReg, ReturnReg);
  2461     masm.xor32(Imm32(1), ReturnReg);
  2462     masm.tagValue(JSVAL_TYPE_BOOLEAN, ReturnReg, R0);
  2463     EmitReturnFromIC(masm);
  2465     // Failure case - jump to next stub
  2466     masm.bind(&failure);
  2467     EmitStubGuardFailure(masm);
  2468     return true;
  2471 //
  2472 // ToNumber_Fallback
  2473 //
  2475 static bool
  2476 DoToNumberFallback(JSContext *cx, ICToNumber_Fallback *stub, HandleValue arg, MutableHandleValue ret)
  2478     FallbackICSpew(cx, stub, "ToNumber");
  2479     ret.set(arg);
  2480     return ToNumber(cx, ret);
  2483 typedef bool (*DoToNumberFallbackFn)(JSContext *, ICToNumber_Fallback *, HandleValue, MutableHandleValue);
  2484 static const VMFunction DoToNumberFallbackInfo =
  2485     FunctionInfo<DoToNumberFallbackFn>(DoToNumberFallback, PopValues(1));
  2487 bool
  2488 ICToNumber_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  2490     JS_ASSERT(R0 == JSReturnOperand);
  2492     // Restore the tail call register.
  2493     EmitRestoreTailCallReg(masm);
  2495     // Ensure stack is fully synced for the expression decompiler.
  2496     masm.pushValue(R0);
  2498     // Push arguments.
  2499     masm.pushValue(R0);
  2500     masm.push(BaselineStubReg);
  2502     return tailCallVM(DoToNumberFallbackInfo, masm);
  2505 //
  2506 // BinaryArith_Fallback
  2507 //
  2509 // Disable PGO (see bug 851490).
  2510 #if defined(_MSC_VER)
  2511 # pragma optimize("g", off)
  2512 #endif
  2513 static bool
  2514 DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallback *stub_,
  2515                       HandleValue lhs, HandleValue rhs, MutableHandleValue ret)
  2517     // This fallback stub may trigger debug mode toggling.
  2518     DebugModeOSRVolatileStub<ICBinaryArith_Fallback *> stub(frame, stub_);
  2520     RootedScript script(cx, frame->script());
  2521     jsbytecode *pc = stub->icEntry()->pc(script);
  2522     JSOp op = JSOp(*pc);
  2523     FallbackICSpew(cx, stub, "BinaryArith(%s,%d,%d)", js_CodeName[op],
  2524             int(lhs.isDouble() ? JSVAL_TYPE_DOUBLE : lhs.extractNonDoubleType()),
  2525             int(rhs.isDouble() ? JSVAL_TYPE_DOUBLE : rhs.extractNonDoubleType()));
  2527     // Don't pass lhs/rhs directly, we need the original values when
  2528     // generating stubs.
  2529     RootedValue lhsCopy(cx, lhs);
  2530     RootedValue rhsCopy(cx, rhs);
  2532     // Perform the compare operation.
  2533     switch(op) {
  2534       case JSOP_ADD:
  2535         // Do an add.
  2536         if (!AddValues(cx, &lhsCopy, &rhsCopy, ret))
  2537             return false;
  2538         break;
  2539       case JSOP_SUB:
  2540         if (!SubValues(cx, &lhsCopy, &rhsCopy, ret))
  2541             return false;
  2542         break;
  2543       case JSOP_MUL:
  2544         if (!MulValues(cx, &lhsCopy, &rhsCopy, ret))
  2545             return false;
  2546         break;
  2547       case JSOP_DIV:
  2548         if (!DivValues(cx, &lhsCopy, &rhsCopy, ret))
  2549             return false;
  2550         break;
  2551       case JSOP_MOD:
  2552         if (!ModValues(cx, &lhsCopy, &rhsCopy, ret))
  2553             return false;
  2554         break;
  2555       case JSOP_BITOR: {
  2556         int32_t result;
  2557         if (!BitOr(cx, lhs, rhs, &result))
  2558             return false;
  2559         ret.setInt32(result);
  2560         break;
  2562       case JSOP_BITXOR: {
  2563         int32_t result;
  2564         if (!BitXor(cx, lhs, rhs, &result))
  2565             return false;
  2566         ret.setInt32(result);
  2567         break;
  2569       case JSOP_BITAND: {
  2570         int32_t result;
  2571         if (!BitAnd(cx, lhs, rhs, &result))
  2572             return false;
  2573         ret.setInt32(result);
  2574         break;
  2576       case JSOP_LSH: {
  2577         int32_t result;
  2578         if (!BitLsh(cx, lhs, rhs, &result))
  2579             return false;
  2580         ret.setInt32(result);
  2581         break;
  2583       case JSOP_RSH: {
  2584         int32_t result;
  2585         if (!BitRsh(cx, lhs, rhs, &result))
  2586             return false;
  2587         ret.setInt32(result);
  2588         break;
  2590       case JSOP_URSH: {
  2591         if (!UrshOperation(cx, lhs, rhs, ret))
  2592             return false;
  2593         break;
  2595       default:
  2596         MOZ_ASSUME_UNREACHABLE("Unhandled baseline arith op");
  2599     // Check if debug mode toggling made the stub invalid.
  2600     if (stub.invalid())
  2601         return true;
  2603     if (ret.isDouble())
  2604         stub->setSawDoubleResult();
  2606     // Check to see if a new stub should be generated.
  2607     if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
  2608         stub->noteUnoptimizableOperands();
  2609         return true;
  2612     // Handle string concat.
  2613     if (op == JSOP_ADD) {
  2614         if (lhs.isString() && rhs.isString()) {
  2615             IonSpew(IonSpew_BaselineIC, "  Generating %s(String, String) stub", js_CodeName[op]);
  2616             JS_ASSERT(ret.isString());
  2617             ICBinaryArith_StringConcat::Compiler compiler(cx);
  2618             ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
  2619             if (!strcatStub)
  2620                 return false;
  2621             stub->addNewStub(strcatStub);
  2622             return true;
  2625         if ((lhs.isString() && rhs.isObject()) || (lhs.isObject() && rhs.isString())) {
  2626             IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
  2627                     lhs.isString() ? "String" : "Object",
  2628                     lhs.isString() ? "Object" : "String");
  2629             JS_ASSERT(ret.isString());
  2630             ICBinaryArith_StringObjectConcat::Compiler compiler(cx, lhs.isString());
  2631             ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
  2632             if (!strcatStub)
  2633                 return false;
  2634             stub->addNewStub(strcatStub);
  2635             return true;
  2639     if (((lhs.isBoolean() && (rhs.isBoolean() || rhs.isInt32())) ||
  2640          (rhs.isBoolean() && (lhs.isBoolean() || lhs.isInt32()))) &&
  2641         (op == JSOP_ADD || op == JSOP_SUB || op == JSOP_BITOR || op == JSOP_BITAND ||
  2642          op == JSOP_BITXOR))
  2644         IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
  2645                 lhs.isBoolean() ? "Boolean" : "Int32", rhs.isBoolean() ? "Boolean" : "Int32");
  2646         ICBinaryArith_BooleanWithInt32::Compiler compiler(cx, op, lhs.isBoolean(), rhs.isBoolean());
  2647         ICStub *arithStub = compiler.getStub(compiler.getStubSpace(script));
  2648         if (!arithStub)
  2649             return false;
  2650         stub->addNewStub(arithStub);
  2651         return true;
  2654     // Handle only int32 or double.
  2655     if (!lhs.isNumber() || !rhs.isNumber()) {
  2656         stub->noteUnoptimizableOperands();
  2657         return true;
  2660     JS_ASSERT(ret.isNumber());
  2662     if (lhs.isDouble() || rhs.isDouble() || ret.isDouble()) {
  2663         if (!cx->runtime()->jitSupportsFloatingPoint)
  2664             return true;
  2666         switch (op) {
  2667           case JSOP_ADD:
  2668           case JSOP_SUB:
  2669           case JSOP_MUL:
  2670           case JSOP_DIV:
  2671           case JSOP_MOD: {
  2672             // Unlink int32 stubs, it's faster to always use the double stub.
  2673             stub->unlinkStubsWithKind(cx, ICStub::BinaryArith_Int32);
  2674             IonSpew(IonSpew_BaselineIC, "  Generating %s(Double, Double) stub", js_CodeName[op]);
  2676             ICBinaryArith_Double::Compiler compiler(cx, op);
  2677             ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
  2678             if (!doubleStub)
  2679                 return false;
  2680             stub->addNewStub(doubleStub);
  2681             return true;
  2683           default:
  2684             break;
  2688     if (lhs.isInt32() && rhs.isInt32()) {
  2689         bool allowDouble = ret.isDouble();
  2690         if (allowDouble)
  2691             stub->unlinkStubsWithKind(cx, ICStub::BinaryArith_Int32);
  2692         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32, Int32%s) stub", js_CodeName[op],
  2693                 allowDouble ? " => Double" : "");
  2694         ICBinaryArith_Int32::Compiler compilerInt32(cx, op, allowDouble);
  2695         ICStub *int32Stub = compilerInt32.getStub(compilerInt32.getStubSpace(script));
  2696         if (!int32Stub)
  2697             return false;
  2698         stub->addNewStub(int32Stub);
  2699         return true;
  2702     // Handle Double <BITOP> Int32 or Int32 <BITOP> Double case.
  2703     if (((lhs.isDouble() && rhs.isInt32()) || (lhs.isInt32() && rhs.isDouble())) &&
  2704         ret.isInt32())
  2706         switch(op) {
  2707           case JSOP_BITOR:
  2708           case JSOP_BITXOR:
  2709           case JSOP_BITAND: {
  2710             IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
  2711                         lhs.isDouble() ? "Double" : "Int32",
  2712                         lhs.isDouble() ? "Int32" : "Double");
  2713             ICBinaryArith_DoubleWithInt32::Compiler compiler(cx, op, lhs.isDouble());
  2714             ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
  2715             if (!optStub)
  2716                 return false;
  2717             stub->addNewStub(optStub);
  2718             return true;
  2720           default:
  2721             break;
  2725     stub->noteUnoptimizableOperands();
  2726     return true;
  2728 #if defined(_MSC_VER)
  2729 # pragma optimize("", on)
  2730 #endif
  2732 typedef bool (*DoBinaryArithFallbackFn)(JSContext *, BaselineFrame *, ICBinaryArith_Fallback *,
  2733                                         HandleValue, HandleValue, MutableHandleValue);
  2734 static const VMFunction DoBinaryArithFallbackInfo =
  2735     FunctionInfo<DoBinaryArithFallbackFn>(DoBinaryArithFallback, PopValues(2));
  2737 bool
  2738 ICBinaryArith_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  2740     JS_ASSERT(R0 == JSReturnOperand);
  2742     // Restore the tail call register.
  2743     EmitRestoreTailCallReg(masm);
  2745     // Ensure stack is fully synced for the expression decompiler.
  2746     masm.pushValue(R0);
  2747     masm.pushValue(R1);
  2749     // Push arguments.
  2750     masm.pushValue(R1);
  2751     masm.pushValue(R0);
  2752     masm.push(BaselineStubReg);
  2753     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  2755     return tailCallVM(DoBinaryArithFallbackInfo, masm);
  2758 static bool
  2759 DoConcatStrings(JSContext *cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
  2761     JS_ASSERT(lhs.isString());
  2762     JS_ASSERT(rhs.isString());
  2763     JSString *lstr = lhs.toString();
  2764     JSString *rstr = rhs.toString();
  2765     JSString *result = ConcatStrings<NoGC>(cx, lstr, rstr);
  2766     if (result) {
  2767         res.set(StringValue(result));
  2768         return true;
  2771     RootedString rootedl(cx, lstr), rootedr(cx, rstr);
  2772     result = ConcatStrings<CanGC>(cx, rootedl, rootedr);
  2773     if (!result)
  2774         return false;
  2776     res.set(StringValue(result));
  2777     return true;
  2780 typedef bool (*DoConcatStringsFn)(JSContext *, HandleValue, HandleValue, MutableHandleValue);
  2781 static const VMFunction DoConcatStringsInfo = FunctionInfo<DoConcatStringsFn>(DoConcatStrings);
  2783 bool
  2784 ICBinaryArith_StringConcat::Compiler::generateStubCode(MacroAssembler &masm)
  2786     Label failure;
  2787     masm.branchTestString(Assembler::NotEqual, R0, &failure);
  2788     masm.branchTestString(Assembler::NotEqual, R1, &failure);
  2790     // Restore the tail call register.
  2791     EmitRestoreTailCallReg(masm);
  2793     masm.pushValue(R1);
  2794     masm.pushValue(R0);
  2795     if (!tailCallVM(DoConcatStringsInfo, masm))
  2796         return false;
  2798     // Failure case - jump to next stub
  2799     masm.bind(&failure);
  2800     EmitStubGuardFailure(masm);
  2801     return true;
  2804 static JSString *
  2805 ConvertObjectToStringForConcat(JSContext *cx, HandleValue obj)
  2807     JS_ASSERT(obj.isObject());
  2808     RootedValue rootedObj(cx, obj);
  2809     if (!ToPrimitive(cx, &rootedObj))
  2810         return nullptr;
  2811     return ToString<CanGC>(cx, rootedObj);
  2814 static bool
  2815 DoConcatStringObject(JSContext *cx, bool lhsIsString, HandleValue lhs, HandleValue rhs,
  2816                      MutableHandleValue res)
  2818     JSString *lstr = nullptr;
  2819     JSString *rstr = nullptr;
  2820     if (lhsIsString) {
  2821         // Convert rhs first.
  2822         JS_ASSERT(lhs.isString() && rhs.isObject());
  2823         rstr = ConvertObjectToStringForConcat(cx, rhs);
  2824         if (!rstr)
  2825             return false;
  2827         // lhs is already string.
  2828         lstr = lhs.toString();
  2829     } else {
  2830         JS_ASSERT(rhs.isString() && lhs.isObject());
  2831         // Convert lhs first.
  2832         lstr = ConvertObjectToStringForConcat(cx, lhs);
  2833         if (!lstr)
  2834             return false;
  2836         // rhs is already string.
  2837         rstr = rhs.toString();
  2840     JSString *str = ConcatStrings<NoGC>(cx, lstr, rstr);
  2841     if (!str) {
  2842         RootedString nlstr(cx, lstr), nrstr(cx, rstr);
  2843         str = ConcatStrings<CanGC>(cx, nlstr, nrstr);
  2844         if (!str)
  2845             return false;
  2848     // Technically, we need to call TypeScript::MonitorString for this PC, however
  2849     // it was called when this stub was attached so it's OK.
  2851     res.setString(str);
  2852     return true;
  2855 typedef bool (*DoConcatStringObjectFn)(JSContext *, bool lhsIsString, HandleValue, HandleValue,
  2856                                        MutableHandleValue);
  2857 static const VMFunction DoConcatStringObjectInfo =
  2858     FunctionInfo<DoConcatStringObjectFn>(DoConcatStringObject, PopValues(2));
  2860 bool
  2861 ICBinaryArith_StringObjectConcat::Compiler::generateStubCode(MacroAssembler &masm)
  2863     Label failure;
  2864     if (lhsIsString_) {
  2865         masm.branchTestString(Assembler::NotEqual, R0, &failure);
  2866         masm.branchTestObject(Assembler::NotEqual, R1, &failure);
  2867     } else {
  2868         masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  2869         masm.branchTestString(Assembler::NotEqual, R1, &failure);
  2872     // Restore the tail call register.
  2873     EmitRestoreTailCallReg(masm);
  2875     // Sync for the decompiler.
  2876     masm.pushValue(R0);
  2877     masm.pushValue(R1);
  2879     // Push arguments.
  2880     masm.pushValue(R1);
  2881     masm.pushValue(R0);
  2882     masm.push(Imm32(lhsIsString_));
  2883     if (!tailCallVM(DoConcatStringObjectInfo, masm))
  2884         return false;
  2886     // Failure case - jump to next stub
  2887     masm.bind(&failure);
  2888     EmitStubGuardFailure(masm);
  2889     return true;
  2892 bool
  2893 ICBinaryArith_Double::Compiler::generateStubCode(MacroAssembler &masm)
  2895     Label failure;
  2896     masm.ensureDouble(R0, FloatReg0, &failure);
  2897     masm.ensureDouble(R1, FloatReg1, &failure);
  2899     switch (op) {
  2900       case JSOP_ADD:
  2901         masm.addDouble(FloatReg1, FloatReg0);
  2902         break;
  2903       case JSOP_SUB:
  2904         masm.subDouble(FloatReg1, FloatReg0);
  2905         break;
  2906       case JSOP_MUL:
  2907         masm.mulDouble(FloatReg1, FloatReg0);
  2908         break;
  2909       case JSOP_DIV:
  2910         masm.divDouble(FloatReg1, FloatReg0);
  2911         break;
  2912       case JSOP_MOD:
  2913         masm.setupUnalignedABICall(2, R0.scratchReg());
  2914         masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
  2915         masm.passABIArg(FloatReg1, MoveOp::DOUBLE);
  2916         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MoveOp::DOUBLE);
  2917         JS_ASSERT(ReturnFloatReg == FloatReg0);
  2918         break;
  2919       default:
  2920         MOZ_ASSUME_UNREACHABLE("Unexpected op");
  2923     masm.boxDouble(FloatReg0, R0);
  2924     EmitReturnFromIC(masm);
  2926     // Failure case - jump to next stub
  2927     masm.bind(&failure);
  2928     EmitStubGuardFailure(masm);
  2929     return true;
  2932 bool
  2933 ICBinaryArith_BooleanWithInt32::Compiler::generateStubCode(MacroAssembler &masm)
  2935     Label failure;
  2936     if (lhsIsBool_)
  2937         masm.branchTestBoolean(Assembler::NotEqual, R0, &failure);
  2938     else
  2939         masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
  2941     if (rhsIsBool_)
  2942         masm.branchTestBoolean(Assembler::NotEqual, R1, &failure);
  2943     else
  2944         masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  2946     Register lhsReg = lhsIsBool_ ? masm.extractBoolean(R0, ExtractTemp0)
  2947                                  : masm.extractInt32(R0, ExtractTemp0);
  2948     Register rhsReg = rhsIsBool_ ? masm.extractBoolean(R1, ExtractTemp1)
  2949                                  : masm.extractInt32(R1, ExtractTemp1);
  2951     JS_ASSERT(op_ == JSOP_ADD || op_ == JSOP_SUB ||
  2952               op_ == JSOP_BITOR || op_ == JSOP_BITXOR || op_ == JSOP_BITAND);
  2954     switch(op_) {
  2955       case JSOP_ADD: {
  2956         Label fixOverflow;
  2958         masm.branchAdd32(Assembler::Overflow, rhsReg, lhsReg, &fixOverflow);
  2959         masm.tagValue(JSVAL_TYPE_INT32, lhsReg, R0);
  2960         EmitReturnFromIC(masm);
  2962         masm.bind(&fixOverflow);
  2963         masm.sub32(rhsReg, lhsReg);
  2964         // Proceed to failure below.
  2965         break;
  2967       case JSOP_SUB: {
  2968         Label fixOverflow;
  2970         masm.branchSub32(Assembler::Overflow, rhsReg, lhsReg, &fixOverflow);
  2971         masm.tagValue(JSVAL_TYPE_INT32, lhsReg, R0);
  2972         EmitReturnFromIC(masm);
  2974         masm.bind(&fixOverflow);
  2975         masm.add32(rhsReg, lhsReg);
  2976         // Proceed to failure below.
  2977         break;
  2979       case JSOP_BITOR: {
  2980         masm.orPtr(rhsReg, lhsReg);
  2981         masm.tagValue(JSVAL_TYPE_INT32, lhsReg, R0);
  2982         EmitReturnFromIC(masm);
  2983         break;
  2985       case JSOP_BITXOR: {
  2986         masm.xorPtr(rhsReg, lhsReg);
  2987         masm.tagValue(JSVAL_TYPE_INT32, lhsReg, R0);
  2988         EmitReturnFromIC(masm);
  2989         break;
  2991       case JSOP_BITAND: {
  2992         masm.andPtr(rhsReg, lhsReg);
  2993         masm.tagValue(JSVAL_TYPE_INT32, lhsReg, R0);
  2994         EmitReturnFromIC(masm);
  2995         break;
  2997       default:
  2998        MOZ_ASSUME_UNREACHABLE("Unhandled op for BinaryArith_BooleanWithInt32.");
  3001     // Failure case - jump to next stub
  3002     masm.bind(&failure);
  3003     EmitStubGuardFailure(masm);
  3004     return true;
  3007 bool
  3008 ICBinaryArith_DoubleWithInt32::Compiler::generateStubCode(MacroAssembler &masm)
  3010     JS_ASSERT(op == JSOP_BITOR || op == JSOP_BITAND || op == JSOP_BITXOR);
  3012     Label failure;
  3013     Register intReg;
  3014     Register scratchReg;
  3015     if (lhsIsDouble_) {
  3016         masm.branchTestDouble(Assembler::NotEqual, R0, &failure);
  3017         masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  3018         intReg = masm.extractInt32(R1, ExtractTemp0);
  3019         masm.unboxDouble(R0, FloatReg0);
  3020         scratchReg = R0.scratchReg();
  3021     } else {
  3022         masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
  3023         masm.branchTestDouble(Assembler::NotEqual, R1, &failure);
  3024         intReg = masm.extractInt32(R0, ExtractTemp0);
  3025         masm.unboxDouble(R1, FloatReg0);
  3026         scratchReg = R1.scratchReg();
  3029     // Truncate the double to an int32.
  3031         Label doneTruncate;
  3032         Label truncateABICall;
  3033         masm.branchTruncateDouble(FloatReg0, scratchReg, &truncateABICall);
  3034         masm.jump(&doneTruncate);
  3036         masm.bind(&truncateABICall);
  3037         masm.push(intReg);
  3038         masm.setupUnalignedABICall(1, scratchReg);
  3039         masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
  3040         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
  3041         masm.storeCallResult(scratchReg);
  3042         masm.pop(intReg);
  3044         masm.bind(&doneTruncate);
  3047     Register intReg2 = scratchReg;
  3048     // All handled ops commute, so no need to worry about ordering.
  3049     switch(op) {
  3050       case JSOP_BITOR:
  3051         masm.orPtr(intReg, intReg2);
  3052         break;
  3053       case JSOP_BITXOR:
  3054         masm.xorPtr(intReg, intReg2);
  3055         break;
  3056       case JSOP_BITAND:
  3057         masm.andPtr(intReg, intReg2);
  3058         break;
  3059       default:
  3060        MOZ_ASSUME_UNREACHABLE("Unhandled op for BinaryArith_DoubleWithInt32.");
  3062     masm.tagValue(JSVAL_TYPE_INT32, intReg2, R0);
  3063     EmitReturnFromIC(masm);
  3065     // Failure case - jump to next stub
  3066     masm.bind(&failure);
  3067     EmitStubGuardFailure(masm);
  3068     return true;
  3071 //
  3072 // UnaryArith_Fallback
  3073 //
  3075 // Disable PGO (see bug 851490).
  3076 #if defined(_MSC_VER)
  3077 # pragma optimize("g", off)
  3078 #endif
  3079 static bool
  3080 DoUnaryArithFallback(JSContext *cx, BaselineFrame *frame, ICUnaryArith_Fallback *stub_,
  3081                      HandleValue val, MutableHandleValue res)
  3083     // This fallback stub may trigger debug mode toggling.
  3084     DebugModeOSRVolatileStub<ICUnaryArith_Fallback *> stub(frame, stub_);
  3086     RootedScript script(cx, frame->script());
  3087     jsbytecode *pc = stub->icEntry()->pc(script);
  3088     JSOp op = JSOp(*pc);
  3089     FallbackICSpew(cx, stub, "UnaryArith(%s)", js_CodeName[op]);
  3091     switch (op) {
  3092       case JSOP_BITNOT: {
  3093         int32_t result;
  3094         if (!BitNot(cx, val, &result))
  3095             return false;
  3096         res.setInt32(result);
  3097         break;
  3099       case JSOP_NEG:
  3100         if (!NegOperation(cx, script, pc, val, res))
  3101             return false;
  3102         break;
  3103       default:
  3104         MOZ_ASSUME_UNREACHABLE("Unexpected op");
  3107     // Check if debug mode toggling made the stub invalid.
  3108     if (stub.invalid())
  3109         return true;
  3111     if (res.isDouble())
  3112         stub->setSawDoubleResult();
  3114     if (stub->numOptimizedStubs() >= ICUnaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
  3115         // TODO: Discard/replace stubs.
  3116         return true;
  3119     if (val.isInt32() && res.isInt32()) {
  3120         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32 => Int32) stub", js_CodeName[op]);
  3121         ICUnaryArith_Int32::Compiler compiler(cx, op);
  3122         ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
  3123         if (!int32Stub)
  3124             return false;
  3125         stub->addNewStub(int32Stub);
  3126         return true;
  3129     if (val.isNumber() && res.isNumber() && cx->runtime()->jitSupportsFloatingPoint) {
  3130         IonSpew(IonSpew_BaselineIC, "  Generating %s(Number => Number) stub", js_CodeName[op]);
  3132         // Unlink int32 stubs, the double stub handles both cases and TI specializes for both.
  3133         stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32);
  3135         ICUnaryArith_Double::Compiler compiler(cx, op);
  3136         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
  3137         if (!doubleStub)
  3138             return false;
  3139         stub->addNewStub(doubleStub);
  3140         return true;
  3143     return true;
  3145 #if defined(_MSC_VER)
  3146 # pragma optimize("", on)
  3147 #endif
  3149 typedef bool (*DoUnaryArithFallbackFn)(JSContext *, BaselineFrame *, ICUnaryArith_Fallback *,
  3150                                        HandleValue, MutableHandleValue);
  3151 static const VMFunction DoUnaryArithFallbackInfo =
  3152     FunctionInfo<DoUnaryArithFallbackFn>(DoUnaryArithFallback, PopValues(1));
  3154 bool
  3155 ICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  3157     JS_ASSERT(R0 == JSReturnOperand);
  3159     // Restore the tail call register.
  3160     EmitRestoreTailCallReg(masm);
  3162     // Ensure stack is fully synced for the expression decompiler.
  3163     masm.pushValue(R0);
  3165     // Push arguments.
  3166     masm.pushValue(R0);
  3167     masm.push(BaselineStubReg);
  3168     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  3170     return tailCallVM(DoUnaryArithFallbackInfo, masm);
  3173 bool
  3174 ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler &masm)
  3176     Label failure;
  3177     masm.ensureDouble(R0, FloatReg0, &failure);
  3179     JS_ASSERT(op == JSOP_NEG || op == JSOP_BITNOT);
  3181     if (op == JSOP_NEG) {
  3182         masm.negateDouble(FloatReg0);
  3183         masm.boxDouble(FloatReg0, R0);
  3184     } else {
  3185         // Truncate the double to an int32.
  3186         Register scratchReg = R1.scratchReg();
  3188         Label doneTruncate;
  3189         Label truncateABICall;
  3190         masm.branchTruncateDouble(FloatReg0, scratchReg, &truncateABICall);
  3191         masm.jump(&doneTruncate);
  3193         masm.bind(&truncateABICall);
  3194         masm.setupUnalignedABICall(1, scratchReg);
  3195         masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
  3196         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ToInt32));
  3197         masm.storeCallResult(scratchReg);
  3199         masm.bind(&doneTruncate);
  3200         masm.not32(scratchReg);
  3201         masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
  3204     EmitReturnFromIC(masm);
  3206     // Failure case - jump to next stub
  3207     masm.bind(&failure);
  3208     EmitStubGuardFailure(masm);
  3209     return true;
  3212 //
  3213 // GetElem_Fallback
  3214 //
  3216 static void GetFixedOrDynamicSlotOffset(HandleObject obj, uint32_t slot,
  3217                                         bool *isFixed, uint32_t *offset)
  3219     JS_ASSERT(isFixed);
  3220     JS_ASSERT(offset);
  3221     *isFixed = obj->isFixedSlot(slot);
  3222     *offset = *isFixed ? JSObject::getFixedSlotOffset(slot)
  3223                        : obj->dynamicSlotIndex(slot) * sizeof(Value);
  3226 static bool
  3227 IsCacheableDOMProxy(JSObject *obj)
  3229     if (!obj->is<ProxyObject>())
  3230         return false;
  3232     BaseProxyHandler *handler = obj->as<ProxyObject>().handler();
  3234     if (handler->family() != GetDOMProxyHandlerFamily())
  3235         return false;
  3237     if (obj->numFixedSlots() <= GetDOMProxyExpandoSlot())
  3238         return false;
  3240     return true;
  3243 static JSObject *
  3244 GetDOMProxyProto(JSObject *obj)
  3246     JS_ASSERT(IsCacheableDOMProxy(obj));
  3247     return obj->getTaggedProto().toObjectOrNull();
  3250 static void
  3251 GenerateDOMProxyChecks(JSContext *cx, MacroAssembler &masm, Register object,
  3252                        Address checkProxyHandlerAddr,
  3253                        Address *checkExpandoShapeAddr,
  3254                        Address *expandoAndGenerationAddr,
  3255                        Address *generationAddr,
  3256                        Register scratch,
  3257                        GeneralRegisterSet &domProxyRegSet,
  3258                        Label *checkFailed)
  3260     // Guard the following:
  3261     //      1. The object is a DOMProxy.
  3262     //      2. The object does not have expando properties, or has an expando
  3263     //          which is known to not have the desired property.
  3264     Address handlerAddr(object, ProxyObject::offsetOfHandler());
  3265     Address expandoAddr(object, JSObject::getFixedSlotOffset(GetDOMProxyExpandoSlot()));
  3267     // Check that object is a DOMProxy.
  3268     masm.loadPtr(checkProxyHandlerAddr, scratch);
  3269     masm.branchPrivatePtr(Assembler::NotEqual, handlerAddr, scratch, checkFailed);
  3271     // At this point, if not checking for an expando object, just return.
  3272     if (!checkExpandoShapeAddr)
  3273         return;
  3275     // For the remaining code, we need to reserve some registers to load a value.
  3276     // This is ugly, but unavoidable.
  3277     ValueOperand tempVal = domProxyRegSet.takeAnyValue();
  3278     masm.pushValue(tempVal);
  3280     Label failDOMProxyCheck;
  3281     Label domProxyOk;
  3283     if (expandoAndGenerationAddr) {
  3284         JS_ASSERT(generationAddr);
  3286         masm.loadPtr(*expandoAndGenerationAddr, tempVal.scratchReg());
  3287         masm.branchPrivatePtr(Assembler::NotEqual, expandoAddr, tempVal.scratchReg(),
  3288                               &failDOMProxyCheck);
  3290         masm.load32(*generationAddr, scratch);
  3291         masm.branch32(Assembler::NotEqual,
  3292                       Address(tempVal.scratchReg(), offsetof(ExpandoAndGeneration, generation)),
  3293                       scratch, &failDOMProxyCheck);
  3295         masm.loadValue(Address(tempVal.scratchReg(), 0), tempVal);
  3296     } else {
  3297         masm.loadValue(expandoAddr, tempVal);
  3300     // If the incoming object does not have an expando object then we're sure we're not
  3301     // shadowing.
  3302     masm.branchTestUndefined(Assembler::Equal, tempVal, &domProxyOk);
  3304     // The reference object used to generate this check may not have had an
  3305     // expando object at all, in which case the presence of a non-undefined
  3306     // expando value in the incoming object is automatically a failure.
  3307     masm.loadPtr(*checkExpandoShapeAddr, scratch);
  3308     masm.branchPtr(Assembler::Equal, scratch, ImmPtr(nullptr), &failDOMProxyCheck);
  3310     // Otherwise, ensure that the incoming object has an object for its expando value and that
  3311     // the shape matches.
  3312     masm.branchTestObject(Assembler::NotEqual, tempVal, &failDOMProxyCheck);
  3313     Register objReg = masm.extractObject(tempVal, tempVal.scratchReg());
  3314     masm.branchTestObjShape(Assembler::Equal, objReg, scratch, &domProxyOk);
  3316     // Failure case: restore the tempVal registers and jump to failures.
  3317     masm.bind(&failDOMProxyCheck);
  3318     masm.popValue(tempVal);
  3319     masm.jump(checkFailed);
  3321     // Success case: restore the tempval and proceed.
  3322     masm.bind(&domProxyOk);
  3323     masm.popValue(tempVal);
  3326 // Look up a property's shape on an object, being careful never to do any effectful
  3327 // operations.  This procedure not yielding a shape should not be taken as a lack of
  3328 // existence of the property on the object.
  3329 static bool
  3330 EffectlesslyLookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
  3331                            MutableHandleObject holder, MutableHandleShape shape,
  3332                            bool *checkDOMProxy=nullptr,
  3333                            DOMProxyShadowsResult *shadowsResult=nullptr,
  3334                            bool *domProxyHasGeneration=nullptr)
  3336     shape.set(nullptr);
  3337     holder.set(nullptr);
  3339     if (checkDOMProxy)
  3340         *checkDOMProxy = false;
  3342     // Check for list base if asked to.
  3343     RootedObject checkObj(cx, obj);
  3344     if (checkDOMProxy && IsCacheableDOMProxy(obj)) {
  3345         JS_ASSERT(domProxyHasGeneration);
  3346         JS_ASSERT(shadowsResult);
  3348         *checkDOMProxy = true;
  3349         if (obj->hasUncacheableProto())
  3350             return true;
  3352         RootedId id(cx, NameToId(name));
  3353         *shadowsResult = GetDOMProxyShadowsCheck()(cx, obj, id);
  3354         if (*shadowsResult == ShadowCheckFailed)
  3355             return false;
  3357         if (*shadowsResult == Shadows) {
  3358             holder.set(obj);
  3359             return true;
  3362         *domProxyHasGeneration = (*shadowsResult == DoesntShadowUnique);
  3364         checkObj = GetDOMProxyProto(obj);
  3365         if (!checkObj)
  3366             return true;
  3367     } else if (!obj->isNative()) {
  3368         return true;
  3371     if (checkObj->hasIdempotentProtoChain()) {
  3372         if (!JSObject::lookupProperty(cx, checkObj, name, holder, shape))
  3373             return false;
  3374     } else if (checkObj->isNative()) {
  3375         shape.set(checkObj->nativeLookup(cx, NameToId(name)));
  3376         if (shape)
  3377             holder.set(checkObj);
  3379     return true;
  3382 static bool
  3383 IsCacheableProtoChain(JSObject *obj, JSObject *holder, bool isDOMProxy=false)
  3385     JS_ASSERT_IF(isDOMProxy, IsCacheableDOMProxy(obj));
  3386     JS_ASSERT_IF(!isDOMProxy, obj->isNative());
  3388     // Don't handle objects which require a prototype guard. This should
  3389     // be uncommon so handling it is likely not worth the complexity.
  3390     if (obj->hasUncacheableProto())
  3391         return false;
  3393     JSObject *cur = obj;
  3394     while (cur != holder) {
  3395         // We cannot assume that we find the holder object on the prototype
  3396         // chain and must check for null proto. The prototype chain can be
  3397         // altered during the lookupProperty call.
  3398         JSObject *proto;
  3399         if (isDOMProxy && cur == obj)
  3400             proto = cur->getTaggedProto().toObjectOrNull();
  3401         else
  3402             proto = cur->getProto();
  3404         if (!proto || !proto->isNative())
  3405             return false;
  3407         if (proto->hasUncacheableProto())
  3408             return false;
  3410         cur = proto;
  3412     return true;
  3415 static bool
  3416 IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, Shape *shape, bool isDOMProxy=false)
  3418     if (!shape || !IsCacheableProtoChain(obj, holder, isDOMProxy))
  3419         return false;
  3421     if (!shape->hasSlot() || !shape->hasDefaultGetter())
  3422         return false;
  3424     return true;
  3427 static bool
  3428 IsCacheableGetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape, bool *isScripted,
  3429                        bool isDOMProxy=false)
  3431     JS_ASSERT(isScripted);
  3433     if (!shape || !IsCacheableProtoChain(obj, holder, isDOMProxy))
  3434         return false;
  3436     if (shape->hasSlot() || shape->hasDefaultGetter())
  3437         return false;
  3439     if (!shape->hasGetterValue())
  3440         return false;
  3442     if (!shape->getterValue().isObject() || !shape->getterObject()->is<JSFunction>())
  3443         return false;
  3445     JSFunction *func = &shape->getterObject()->as<JSFunction>();
  3447 #ifdef JSGC_GENERATIONAL
  3448     // Information from get prop call ICs may be used directly from Ion code,
  3449     // and should not be nursery allocated.
  3450     if (cx->runtime()->gcNursery.isInside(holder) || cx->runtime()->gcNursery.isInside(func))
  3451         return false;
  3452 #endif
  3454     if (func->isNative()) {
  3455         *isScripted = false;
  3456         return true;
  3459     if (!func->hasJITCode())
  3460         return false;
  3462     *isScripted = true;
  3463     return true;
  3466 static bool
  3467 IsCacheableSetPropWriteSlot(JSObject *obj, Shape *oldShape, JSObject *holder, Shape *shape)
  3469     if (!shape)
  3470         return false;
  3472     // Object shape must not have changed during the property set.
  3473     if (obj->lastProperty() != oldShape)
  3474         return false;
  3476     // Currently we only optimize direct writes.
  3477     if (obj != holder)
  3478         return false;
  3480     if (!shape->hasSlot() || !shape->hasDefaultSetter() || !shape->writable())
  3481         return false;
  3483     return true;
  3486 static bool
  3487 IsCacheableSetPropAddSlot(JSContext *cx, HandleObject obj, HandleShape oldShape, uint32_t oldSlots,
  3488                           HandleId id, HandleObject holder, HandleShape shape,
  3489                           size_t *protoChainDepth)
  3491     if (!shape)
  3492         return false;
  3494     // Property must be set directly on object, and be last added property of object.
  3495     if (obj != holder || shape != obj->lastProperty())
  3496         return false;
  3498     // Object must be extensible, oldShape must be immediate parent of curShape.
  3499     if (!obj->nonProxyIsExtensible() || obj->lastProperty()->previous() != oldShape)
  3500         return false;
  3502     // Basic shape checks.
  3503     if (shape->inDictionary() || !shape->hasSlot() || !shape->hasDefaultSetter() ||
  3504         !shape->writable())
  3506         return false;
  3509     // If object has a non-default resolve hook, don't inline
  3510     if (obj->getClass()->resolve != JS_ResolveStub)
  3511         return false;
  3513     size_t chainDepth = 0;
  3514     // walk up the object prototype chain and ensure that all prototypes
  3515     // are native, and that all prototypes have setter defined on the property
  3516     for (JSObject *proto = obj->getProto(); proto; proto = proto->getProto()) {
  3517         chainDepth++;
  3518         // if prototype is non-native, don't optimize
  3519         if (!proto->isNative())
  3520             return false;
  3522         // if prototype defines this property in a non-plain way, don't optimize
  3523         Shape *protoShape = proto->nativeLookup(cx, id);
  3524         if (protoShape && !protoShape->hasDefaultSetter())
  3525             return false;
  3527         // Otherise, if there's no such property, watch out for a resolve hook that would need
  3528         // to be invoked and thus prevent inlining of property addition.
  3529         if (proto->getClass()->resolve != JS_ResolveStub)
  3530              return false;
  3533     // Only add a IC entry if the dynamic slots didn't change when the shapes
  3534     // changed.  Need to ensure that a shape change for a subsequent object
  3535     // won't involve reallocating the slot array.
  3536     if (obj->numDynamicSlots() != oldSlots)
  3537         return false;
  3539     *protoChainDepth = chainDepth;
  3540     return true;
  3543 static bool
  3544 IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *shape, bool *isScripted)
  3546     JS_ASSERT(isScripted);
  3548     // Currently we only optimize setter calls for setters bound on prototypes.
  3549     if (obj == holder)
  3550         return false;
  3552     if (!shape || !IsCacheableProtoChain(obj, holder))
  3553         return false;
  3555     if (shape->hasSlot() || shape->hasDefaultSetter())
  3556         return false;
  3558     if (!shape->hasSetterValue())
  3559         return false;
  3561     if (!shape->setterValue().isObject() || !shape->setterObject()->is<JSFunction>())
  3562         return false;
  3564     JSFunction *func = &shape->setterObject()->as<JSFunction>();
  3566 #ifdef JSGC_GENERATIONAL
  3567     // Information from set prop call ICs may be used directly from Ion code,
  3568     // and should not be nursery allocated.
  3569     if (cx->runtime()->gcNursery.isInside(holder) || cx->runtime()->gcNursery.isInside(func))
  3570         return false;
  3571 #endif
  3573     if (func->isNative()) {
  3574         *isScripted = false;
  3575         return true;
  3578     if (!func->hasJITCode())
  3579         return false;
  3581     *isScripted = true;
  3582     return true;
  3585 static bool
  3586 LookupNoSuchMethodHandler(JSContext *cx, HandleObject obj, HandleValue id,
  3587                           MutableHandleValue result)
  3589     return OnUnknownMethod(cx, obj, id, result);
  3592 typedef bool (*LookupNoSuchMethodHandlerFn)(JSContext *, HandleObject, HandleValue,
  3593                                             MutableHandleValue);
  3594 static const VMFunction LookupNoSuchMethodHandlerInfo =
  3595     FunctionInfo<LookupNoSuchMethodHandlerFn>(LookupNoSuchMethodHandler);
  3597 static bool
  3598 GetElemNativeStubExists(ICGetElem_Fallback *stub, HandleObject obj, HandleObject holder,
  3599                         HandlePropertyName propName, bool needsAtomize)
  3601     bool indirect = (obj.get() != holder.get());
  3603     for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
  3604         if (iter->kind() != ICStub::GetElem_NativeSlot &&
  3605             iter->kind() != ICStub::GetElem_NativePrototypeSlot &&
  3606             iter->kind() != ICStub::GetElem_NativePrototypeCallNative &&
  3607             iter->kind() != ICStub::GetElem_NativePrototypeCallScripted)
  3609             continue;
  3612         if (indirect && (iter->kind() != ICStub::GetElem_NativePrototypeSlot &&
  3613                          iter->kind() != ICStub::GetElem_NativePrototypeCallNative &&
  3614                          iter->kind() != ICStub::GetElem_NativePrototypeCallScripted))
  3616             continue;
  3619         ICGetElemNativeStub *getElemNativeStub = reinterpret_cast<ICGetElemNativeStub *>(*iter);
  3620         if (propName != getElemNativeStub->name())
  3621             continue;
  3623         if (obj->lastProperty() != getElemNativeStub->shape())
  3624             continue;
  3626         // If the new stub needs atomization, and the old stub doesn't atomize, then
  3627         // an appropriate stub doesn't exist.
  3628         if (needsAtomize && !getElemNativeStub->needsAtomize())
  3629             continue;
  3631         // For prototype gets, check the holder and holder shape.
  3632         if (indirect) {
  3633             if (iter->isGetElem_NativePrototypeSlot()) {
  3634                 ICGetElem_NativePrototypeSlot *protoStub = iter->toGetElem_NativePrototypeSlot();
  3636                 if (holder != protoStub->holder())
  3637                     continue;
  3639                 if (holder->lastProperty() != protoStub->holderShape())
  3640                     continue;
  3641             } else {
  3642                 JS_ASSERT(iter->isGetElem_NativePrototypeCallNative() ||
  3643                           iter->isGetElem_NativePrototypeCallScripted());
  3645                 ICGetElemNativePrototypeCallStub *protoStub =
  3646                     reinterpret_cast<ICGetElemNativePrototypeCallStub *>(*iter);
  3648                 if (holder != protoStub->holder())
  3649                     continue;
  3651                 if (holder->lastProperty() != protoStub->holderShape())
  3652                     continue;
  3656         return true;
  3658     return false;
  3661 static void
  3662 RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, HandleObject obj,
  3663                                  HandleObject holder, HandlePropertyName propName,
  3664                                  bool needsAtomize)
  3666     bool indirect = (obj.get() != holder.get());
  3668     for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++) {
  3669         switch (iter->kind()) {
  3670           case ICStub::GetElem_NativeSlot:
  3671             if (indirect)
  3672                 continue;
  3673           case ICStub::GetElem_NativePrototypeSlot:
  3674           case ICStub::GetElem_NativePrototypeCallNative:
  3675           case ICStub::GetElem_NativePrototypeCallScripted:
  3676             break;
  3677           default:
  3678             continue;
  3681         ICGetElemNativeStub *getElemNativeStub = reinterpret_cast<ICGetElemNativeStub *>(*iter);
  3682         if (propName != getElemNativeStub->name())
  3683             continue;
  3685         if (obj->lastProperty() != getElemNativeStub->shape())
  3686             continue;
  3688         // For prototype gets, check the holder and holder shape.
  3689         if (indirect) {
  3690             if (iter->isGetElem_NativePrototypeSlot()) {
  3691                 ICGetElem_NativePrototypeSlot *protoStub = iter->toGetElem_NativePrototypeSlot();
  3693                 if (holder != protoStub->holder())
  3694                     continue;
  3696                 // If the holder matches, but the holder's lastProperty doesn't match, then
  3697                 // this stub is invalid anyway.  Unlink it.
  3698                 if (holder->lastProperty() != protoStub->holderShape()) {
  3699                     iter.unlink(cx);
  3700                     continue;
  3702             } else {
  3703                 JS_ASSERT(iter->isGetElem_NativePrototypeCallNative() ||
  3704                           iter->isGetElem_NativePrototypeCallScripted());
  3706                 ICGetElemNativePrototypeCallStub *protoStub =
  3707                     reinterpret_cast<ICGetElemNativePrototypeCallStub *>(*iter);
  3709                 if (holder != protoStub->holder())
  3710                     continue;
  3712                 // If the holder matches, but the holder's lastProperty doesn't match, then
  3713                 // this stub is invalid anyway.  Unlink it.
  3714                 if (holder->lastProperty() != protoStub->holderShape()) {
  3715                     iter.unlink(cx);
  3716                     continue;
  3721         // If the new stub needs atomization, and the old stub doesn't atomize, then
  3722         // remove the old stub.
  3723         if (needsAtomize && !getElemNativeStub->needsAtomize()) {
  3724             iter.unlink(cx);
  3725             continue;
  3728         // Should never get here, because this means a matching stub exists, and if
  3729         // a matching stub exists, this procedure should never have been called.
  3730         MOZ_ASSUME_UNREACHABLE("Procedure should never have been called.");
  3734 static bool
  3735 TypedArrayGetElemStubExists(ICGetElem_Fallback *stub, HandleObject obj)
  3737     for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
  3738         if (!iter->isGetElem_TypedArray())
  3739             continue;
  3740         if (obj->lastProperty() == iter->toGetElem_TypedArray()->shape())
  3741             return true;
  3743     return false;
  3746 static bool
  3747 ArgumentsGetElemStubExists(ICGetElem_Fallback *stub, ICGetElem_Arguments::Which which)
  3749     for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
  3750         if (!iter->isGetElem_Arguments())
  3751             continue;
  3752         if (iter->toGetElem_Arguments()->which() == which)
  3753             return true;
  3755     return false;
  3759 static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc,
  3760                                        ICGetElem_Fallback *stub, HandleObject obj,
  3761                                        HandleValue key)
  3763     // Native-object GetElem stubs can't deal with non-string keys.
  3764     if (!key.isString())
  3765         return true;
  3767     // Convert to interned property name.
  3768     RootedId id(cx);
  3769     if (!ValueToId<CanGC>(cx, key, &id))
  3770         return false;
  3772     uint32_t dummy;
  3773     if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy))
  3774         return true;
  3776     RootedPropertyName propName(cx, JSID_TO_ATOM(id)->asPropertyName());
  3777     bool needsAtomize = !key.toString()->isAtom();
  3778     bool isCallElem = (JSOp(*pc) == JSOP_CALLELEM);
  3780     RootedShape shape(cx);
  3781     RootedObject holder(cx);
  3782     if (!EffectlesslyLookupProperty(cx, obj, propName, &holder, &shape))
  3783         return false;
  3785     if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
  3786         // If a suitable stub already exists, nothing else to do.
  3787         if (GetElemNativeStubExists(stub, obj, holder, propName, needsAtomize))
  3788             return true;
  3790         // Remove any existing stubs that may interfere with the new stub being added.
  3791         RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, propName, needsAtomize);
  3793         bool isFixedSlot;
  3794         uint32_t offset;
  3795         GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
  3797         ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
  3798         ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_NativeSlot
  3799                                             : ICStub::GetElem_NativePrototypeSlot;
  3801         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(Native %s%s slot) stub "
  3802                                     "(obj=%p, shape=%p, holder=%p, holderShape=%p)",
  3803                     (obj == holder) ? "direct" : "prototype",
  3804                     needsAtomize ? " atomizing" : "",
  3805                     obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
  3807         ICGetElemNativeStub::AccessType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot
  3808                                                               : ICGetElemNativeStub::DynamicSlot;
  3809         ICGetElemNativeCompiler compiler(cx, kind, isCallElem, monitorStub, obj, holder, propName,
  3810                                          acctype, needsAtomize, offset);
  3811         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  3812         if (!newStub)
  3813             return false;
  3815         stub->addNewStub(newStub);
  3816         return true;
  3819     bool getterIsScripted = false;
  3820     if (IsCacheableGetPropCall(cx, obj, holder, shape, &getterIsScripted, /*isDOMProxy=*/false)) {
  3821         RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
  3823 #if JS_HAS_NO_SUCH_METHOD
  3824         // It's unlikely that a getter function will be used in callelem locations.
  3825         // Just don't attach stubs in that case to avoid issues with __noSuchMethod__ handling.
  3826         if (isCallElem)
  3827             return true;
  3828 #endif
  3830         // For now, we do not handle own property getters
  3831         if (obj == holder)
  3832             return true;
  3834         // If a suitable stub already exists, nothing else to do.
  3835         if (GetElemNativeStubExists(stub, obj, holder, propName, needsAtomize))
  3836             return true;
  3838         // Remove any existing stubs that may interfere with the new stub being added.
  3839         RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, propName, needsAtomize);
  3841         ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
  3842         ICStub::Kind kind = getterIsScripted ? ICStub::GetElem_NativePrototypeCallScripted
  3843                                              : ICStub::GetElem_NativePrototypeCallNative;
  3845         if (getterIsScripted) {
  3846             IonSpew(IonSpew_BaselineIC,
  3847                     "  Generating GetElem(Native %s%s call scripted %s:%d) stub "
  3848                     "(obj=%p, shape=%p, holder=%p, holderShape=%p)",
  3849                         (obj == holder) ? "direct" : "prototype",
  3850                         needsAtomize ? " atomizing" : "",
  3851                         getter->nonLazyScript()->filename(), getter->nonLazyScript()->lineno(),
  3852                         obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
  3853         } else {
  3854             IonSpew(IonSpew_BaselineIC,
  3855                     "  Generating GetElem(Native %s%s call native) stub "
  3856                     "(obj=%p, shape=%p, holder=%p, holderShape=%p)",
  3857                         (obj == holder) ? "direct" : "prototype",
  3858                         needsAtomize ? " atomizing" : "",
  3859                         obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty());
  3862         ICGetElemNativeStub::AccessType acctype = getterIsScripted
  3863                                                            ? ICGetElemNativeStub::ScriptedGetter
  3864                                                            : ICGetElemNativeStub::NativeGetter;
  3865         ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, propName, acctype,
  3866                                          needsAtomize, getter, script->pcToOffset(pc), isCallElem);
  3867         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  3868         if (!newStub)
  3869             return false;
  3871         stub->addNewStub(newStub);
  3872         return true;
  3875     return true;
  3878 static bool
  3879 TypedArrayRequiresFloatingPoint(TypedArrayObject *tarr)
  3881     uint32_t type = tarr->type();
  3882     return (type == ScalarTypeDescr::TYPE_UINT32 ||
  3883             type == ScalarTypeDescr::TYPE_FLOAT32 ||
  3884             type == ScalarTypeDescr::TYPE_FLOAT64);
  3887 static bool
  3888 TryAttachGetElemStub(JSContext *cx, JSScript *script, jsbytecode *pc, ICGetElem_Fallback *stub,
  3889                      HandleValue lhs, HandleValue rhs, HandleValue res)
  3891     bool isCallElem = (JSOp(*pc) == JSOP_CALLELEM);
  3893     // Check for String[i] => Char accesses.
  3894     if (lhs.isString() && rhs.isInt32() && res.isString() &&
  3895         !stub->hasStub(ICStub::GetElem_String))
  3897         // NoSuchMethod handling doesn't apply to string targets.
  3899         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(String[Int32]) stub");
  3900         ICGetElem_String::Compiler compiler(cx);
  3901         ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script));
  3902         if (!stringStub)
  3903             return false;
  3905         stub->addNewStub(stringStub);
  3906         return true;
  3909     if (lhs.isMagic(JS_OPTIMIZED_ARGUMENTS) && rhs.isInt32() &&
  3910         !ArgumentsGetElemStubExists(stub, ICGetElem_Arguments::Magic))
  3912         // Any script with a CALLPROP on arguments (arguments.foo())
  3913         // should not have optimized arguments.
  3914         JS_ASSERT(!isCallElem);
  3916         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(MagicArgs[Int32]) stub");
  3917         ICGetElem_Arguments::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
  3918                                                ICGetElem_Arguments::Magic, false);
  3919         ICStub *argsStub = compiler.getStub(compiler.getStubSpace(script));
  3920         if (!argsStub)
  3921             return false;
  3923         stub->addNewStub(argsStub);
  3924         return true;
  3927     // Otherwise, GetElem is only optimized on objects.
  3928     if (!lhs.isObject())
  3929         return true;
  3930     RootedObject obj(cx, &lhs.toObject());
  3932     // Check for ArgumentsObj[int] accesses
  3933     if (obj->is<ArgumentsObject>() && rhs.isInt32()) {
  3934         ICGetElem_Arguments::Which which = ICGetElem_Arguments::Normal;
  3935         if (obj->is<StrictArgumentsObject>())
  3936             which = ICGetElem_Arguments::Strict;
  3937         if (!ArgumentsGetElemStubExists(stub, which)) {
  3938             IonSpew(IonSpew_BaselineIC, "  Generating GetElem(ArgsObj[Int32]) stub");
  3939             ICGetElem_Arguments::Compiler compiler(
  3940                 cx, stub->fallbackMonitorStub()->firstMonitorStub(), which, isCallElem);
  3941             ICStub *argsStub = compiler.getStub(compiler.getStubSpace(script));
  3942             if (!argsStub)
  3943                 return false;
  3945             stub->addNewStub(argsStub);
  3946             return true;
  3950     if (obj->isNative()) {
  3951         // Check for NativeObject[int] dense accesses.
  3952         if (rhs.isInt32() && rhs.toInt32() >= 0 && !obj->is<TypedArrayObject>()) {
  3953             IonSpew(IonSpew_BaselineIC, "  Generating GetElem(Native[Int32] dense) stub");
  3954             ICGetElem_Dense::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
  3955                                                obj->lastProperty(), isCallElem);
  3956             ICStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
  3957             if (!denseStub)
  3958                 return false;
  3960             stub->addNewStub(denseStub);
  3961             return true;
  3964         // Check for NativeObject[id] shape-optimizable accesses.
  3965         if (rhs.isString()) {
  3966             RootedScript rootedScript(cx, script);
  3967             if (!TryAttachNativeGetElemStub(cx, rootedScript, pc, stub, obj, rhs))
  3968                 return false;
  3969             script = rootedScript;
  3973     // Check for TypedArray[int] => Number accesses.
  3974     if (obj->is<TypedArrayObject>() && rhs.isNumber() && res.isNumber() &&
  3975         !TypedArrayGetElemStubExists(stub, obj))
  3977         // Don't attach CALLELEM stubs for accesses on typed array expected to yield numbers.
  3978 #if JS_HAS_NO_SUCH_METHOD
  3979         if (isCallElem)
  3980             return true;
  3981 #endif
  3983         TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
  3984         if (!cx->runtime()->jitSupportsFloatingPoint &&
  3985             (TypedArrayRequiresFloatingPoint(tarr) || rhs.isDouble()))
  3987             return true;
  3990         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(TypedArray[Int32]) stub");
  3991         ICGetElem_TypedArray::Compiler compiler(cx, tarr->lastProperty(), tarr->type());
  3992         ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
  3993         if (!typedArrayStub)
  3994             return false;
  3996         stub->addNewStub(typedArrayStub);
  3997         return true;
  4000     // GetElem operations on non-native objects cannot be cached by either
  4001     // Baseline or Ion. Indicate this in the cache so that Ion does not
  4002     // generate a cache for this op.
  4003     if (!obj->isNative())
  4004         stub->noteNonNativeAccess();
  4006     // GetElem operations which could access negative indexes generally can't
  4007     // be optimized without the potential for bailouts, as we can't statically
  4008     // determine that an object has no properties on such indexes.
  4009     if (rhs.isNumber() && rhs.toNumber() < 0)
  4010         stub->noteNegativeIndex();
  4012     return true;
  4015 static bool
  4016 DoGetElemFallback(JSContext *cx, BaselineFrame *frame, ICGetElem_Fallback *stub_, HandleValue lhs,
  4017                   HandleValue rhs, MutableHandleValue res)
  4019     // This fallback stub may trigger debug mode toggling.
  4020     DebugModeOSRVolatileStub<ICGetElem_Fallback *> stub(frame, stub_);
  4022     RootedScript script(cx, frame->script());
  4023     jsbytecode *pc = stub->icEntry()->pc(frame->script());
  4024     JSOp op = JSOp(*pc);
  4025     FallbackICSpew(cx, stub, "GetElem(%s)", js_CodeName[op]);
  4027     JS_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
  4029     // Don't pass lhs directly, we need it when generating stubs.
  4030     RootedValue lhsCopy(cx, lhs);
  4032     bool isOptimizedArgs = false;
  4033     if (lhs.isMagic(JS_OPTIMIZED_ARGUMENTS)) {
  4034         // Handle optimized arguments[i] access.
  4035         if (!GetElemOptimizedArguments(cx, frame, &lhsCopy, rhs, res, &isOptimizedArgs))
  4036             return false;
  4037         if (isOptimizedArgs)
  4038             types::TypeScript::Monitor(cx, frame->script(), pc, res);
  4041     if (!isOptimizedArgs) {
  4042         if (!GetElementOperation(cx, op, &lhsCopy, rhs, res))
  4043             return false;
  4044         types::TypeScript::Monitor(cx, frame->script(), pc, res);
  4047     // Check if debug mode toggling made the stub invalid.
  4048     if (stub.invalid())
  4049         return true;
  4051     // Add a type monitor stub for the resulting value.
  4052     if (!stub->addMonitorStubForValue(cx, frame->script(), res))
  4053         return false;
  4055     if (stub->numOptimizedStubs() >= ICGetElem_Fallback::MAX_OPTIMIZED_STUBS) {
  4056         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
  4057         // But for now we just bail.
  4058         return true;
  4061     // Try to attach an optimized stub.
  4062     if (!TryAttachGetElemStub(cx, frame->script(), pc, stub, lhs, rhs, res))
  4063         return false;
  4065     return true;
  4068 typedef bool (*DoGetElemFallbackFn)(JSContext *, BaselineFrame *, ICGetElem_Fallback *,
  4069                                     HandleValue, HandleValue, MutableHandleValue);
  4070 static const VMFunction DoGetElemFallbackInfo =
  4071     FunctionInfo<DoGetElemFallbackFn>(DoGetElemFallback, PopValues(2));
  4073 bool
  4074 ICGetElem_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  4076     JS_ASSERT(R0 == JSReturnOperand);
  4078     // Restore the tail call register.
  4079     EmitRestoreTailCallReg(masm);
  4081     // Ensure stack is fully synced for the expression decompiler.
  4082     masm.pushValue(R0);
  4083     masm.pushValue(R1);
  4085     // Push arguments.
  4086     masm.pushValue(R1);
  4087     masm.pushValue(R0);
  4088     masm.push(BaselineStubReg);
  4089     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  4091     return tailCallVM(DoGetElemFallbackInfo, masm);
  4094 //
  4095 // GetElem_NativeSlot
  4096 //
  4098 static bool
  4099 DoAtomizeString(JSContext *cx, HandleString string, MutableHandleValue result)
  4101     IonSpew(IonSpew_BaselineIC, "  AtomizeString called");
  4103     RootedValue key(cx, StringValue(string));
  4105     // Convert to interned property name.
  4106     RootedId id(cx);
  4107     if (!ValueToId<CanGC>(cx, key, &id))
  4108         return false;
  4110     if (!JSID_IS_ATOM(id)) {
  4111         result.set(key);
  4112         return true;
  4115     result.set(StringValue(JSID_TO_ATOM(id)));
  4116     return true;
  4119 typedef bool (*DoAtomizeStringFn)(JSContext *, HandleString, MutableHandleValue);
  4120 static const VMFunction DoAtomizeStringInfo = FunctionInfo<DoAtomizeStringFn>(DoAtomizeString);
  4122 bool
  4123 ICGetElemNativeCompiler::emitCallNative(MacroAssembler &masm, Register objReg)
  4125     GeneralRegisterSet regs = availableGeneralRegs(0);
  4126     regs.takeUnchecked(objReg);
  4127     regs.takeUnchecked(BaselineTailCallReg);
  4129     enterStubFrame(masm, regs.getAny());
  4131     // Push object.
  4132     masm.push(objReg);
  4134     // Push native callee.
  4135     masm.loadPtr(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), objReg);
  4136     masm.push(objReg);
  4138     regs.add(objReg);
  4140     // Profiler hook.
  4141     emitProfilingUpdate(masm, regs, ICGetElemNativeGetterStub::offsetOfPCOffset());
  4143     // Call helper.
  4144     if (!callVM(DoCallNativeGetterInfo, masm))
  4145         return false;
  4147     leaveStubFrame(masm);
  4149     return true;
  4152 bool
  4153 ICGetElemNativeCompiler::emitCallScripted(MacroAssembler &masm, Register objReg)
  4155     GeneralRegisterSet regs = availableGeneralRegs(0);
  4156     regs.takeUnchecked(objReg);
  4157     regs.takeUnchecked(BaselineTailCallReg);
  4159     // Enter stub frame.
  4160     enterStubFrame(masm, regs.getAny());
  4162     // Push |this| for getter (target object).
  4164         ValueOperand val = regs.takeAnyValue();
  4165         masm.tagValue(JSVAL_TYPE_OBJECT, objReg, val);
  4166         masm.Push(val);
  4167         regs.add(val);
  4170     regs.add(objReg);
  4172     Register callee = regs.takeAny();
  4173     masm.loadPtr(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), callee);
  4175     // Push argc, callee, and descriptor.
  4177         Register callScratch = regs.takeAny();
  4178         EmitCreateStubFrameDescriptor(masm, callScratch);
  4179         masm.Push(Imm32(0));  // ActualArgc is 0
  4180         masm.Push(callee);
  4181         masm.Push(callScratch);
  4182         regs.add(callScratch);
  4185     Register code = regs.takeAnyExcluding(ArgumentsRectifierReg);
  4186     masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
  4187     masm.loadBaselineOrIonRaw(code, code, SequentialExecution, nullptr);
  4189     Register scratch = regs.takeAny();
  4191     // Handle arguments underflow.
  4192     Label noUnderflow;
  4193     masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
  4194     masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
  4196         // Call the arguments rectifier.
  4197         JS_ASSERT(ArgumentsRectifierReg != code);
  4199         JitCode *argumentsRectifier =
  4200             cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
  4202         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
  4203         masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
  4204         masm.mov(ImmWord(0), ArgumentsRectifierReg);
  4207     masm.bind(&noUnderflow);
  4209     // If needed, update SPS Profiler frame entry.  At this point, callee and scratch can
  4210     // be clobbered.
  4212         GeneralRegisterSet availRegs = availableGeneralRegs(0);
  4213         availRegs.take(ArgumentsRectifierReg);
  4214         availRegs.take(code);
  4215         emitProfilingUpdate(masm, availRegs, ICGetElemNativeGetterStub::offsetOfPCOffset());
  4218     masm.callIon(code);
  4220     leaveStubFrame(masm, true);
  4222     return true;
  4225 bool
  4226 ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm)
  4228     Label failure;
  4229     Label failurePopR1;
  4230     bool popR1 = false;
  4232     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  4233     masm.branchTestString(Assembler::NotEqual, R1, &failure);
  4235     GeneralRegisterSet regs(availableGeneralRegs(2));
  4236     Register scratchReg = regs.takeAny();
  4238     // Unbox object.
  4239     Register objReg = masm.extractObject(R0, ExtractTemp0);
  4241     // Check object shape.
  4242     masm.loadPtr(Address(objReg, JSObject::offsetOfShape()), scratchReg);
  4243     Address shapeAddr(BaselineStubReg, ICGetElemNativeStub::offsetOfShape());
  4244     masm.branchPtr(Assembler::NotEqual, shapeAddr, scratchReg, &failure);
  4246     // Check key identity.  Don't automatically fail if this fails, since the incoming
  4247     // key maybe a non-interned string.  Switch to a slowpath vm-call based check.
  4248     Address nameAddr(BaselineStubReg, ICGetElemNativeStub::offsetOfName());
  4249     Register strExtract = masm.extractString(R1, ExtractTemp1);
  4251     // If needsAtomize_ is true, and the string is not already an atom, then atomize the
  4252     // string before proceeding.
  4253     if (needsAtomize_) {
  4254         Label skipAtomize;
  4256         // If string is already an atom, skip the atomize.
  4257         masm.branchTestPtr(Assembler::NonZero,
  4258                            Address(strExtract, JSString::offsetOfLengthAndFlags()),
  4259                            Imm32(JSString::ATOM_BIT),
  4260                            &skipAtomize);
  4262         // Stow R0.
  4263         EmitStowICValues(masm, 1);
  4265         enterStubFrame(masm, R0.scratchReg());
  4267         // Atomize the string into a new value.
  4268         masm.push(strExtract);
  4269         if (!callVM(DoAtomizeStringInfo, masm))
  4270             return false;
  4272         // Atomized string is now in JSReturnOperand (R0).
  4273         // Leave stub frame, move atomized string into R1.
  4274         JS_ASSERT(R0 == JSReturnOperand);
  4275         leaveStubFrame(masm);
  4276         masm.moveValue(JSReturnOperand, R1);
  4278         // Unstow R0
  4279         EmitUnstowICValues(masm, 1);
  4281         // Extract string from R1 again.
  4282         DebugOnly<Register> strExtract2 = masm.extractString(R1, ExtractTemp1);
  4283         JS_ASSERT(Register(strExtract2) == strExtract);
  4285         masm.bind(&skipAtomize);
  4288     // Since this stub sometimes enter a stub frame, we manually set this to true (lie).
  4289 #ifdef DEBUG
  4290     entersStubFrame_ = true;
  4291 #endif
  4293     // Key has been atomized if necessary.  Do identity check on string pointer.
  4294     masm.branchPtr(Assembler::NotEqual, nameAddr, strExtract, &failure);
  4296     Register holderReg;
  4297     if (obj_ == holder_) {
  4298         holderReg = objReg;
  4299     } else {
  4300         // Shape guard holder.
  4301         if (regs.empty()) {
  4302             masm.push(R1.scratchReg());
  4303             popR1 = true;
  4304             holderReg = R1.scratchReg();
  4305         } else {
  4306             holderReg = regs.takeAny();
  4309         if (kind == ICStub::GetElem_NativePrototypeCallNative ||
  4310             kind == ICStub::GetElem_NativePrototypeCallScripted)
  4312             masm.loadPtr(Address(BaselineStubReg,
  4313                                  ICGetElemNativePrototypeCallStub::offsetOfHolder()),
  4314                          holderReg);
  4315             masm.loadPtr(Address(BaselineStubReg,
  4316                                  ICGetElemNativePrototypeCallStub::offsetOfHolderShape()),
  4317                          scratchReg);
  4318         } else {
  4319             masm.loadPtr(Address(BaselineStubReg,
  4320                                  ICGetElem_NativePrototypeSlot::offsetOfHolder()),
  4321                          holderReg);
  4322             masm.loadPtr(Address(BaselineStubReg,
  4323                                  ICGetElem_NativePrototypeSlot::offsetOfHolderShape()),
  4324                          scratchReg);
  4326         masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratchReg,
  4327                                 popR1 ? &failurePopR1 : &failure);
  4330     if (acctype_ == ICGetElemNativeStub::DynamicSlot ||
  4331         acctype_ == ICGetElemNativeStub::FixedSlot)
  4333         masm.load32(Address(BaselineStubReg, ICGetElemNativeSlotStub::offsetOfOffset()),
  4334                     scratchReg);
  4336         // Load from object.
  4337         if (acctype_ == ICGetElemNativeStub::DynamicSlot)
  4338             masm.addPtr(Address(holderReg, JSObject::offsetOfSlots()), scratchReg);
  4339         else
  4340             masm.addPtr(holderReg, scratchReg);
  4342         Address valAddr(scratchReg, 0);
  4344         // Check if __noSuchMethod__ needs to be called.
  4345 #if JS_HAS_NO_SUCH_METHOD
  4346         if (isCallElem_) {
  4347             Label afterNoSuchMethod;
  4348             Label skipNoSuchMethod;
  4350             masm.branchTestUndefined(Assembler::NotEqual, valAddr, &skipNoSuchMethod);
  4352             GeneralRegisterSet regs = availableGeneralRegs(0);
  4353             regs.take(R1);
  4354             regs.take(R0);
  4355             regs.takeUnchecked(objReg);
  4356             if (popR1)
  4357                 masm.pop(R1.scratchReg());
  4359             // Box and push obj and key onto baseline frame stack for decompiler.
  4360             masm.tagValue(JSVAL_TYPE_OBJECT, objReg, R0);
  4361             EmitStowICValues(masm, 2);
  4363             regs.add(R0);
  4364             regs.takeUnchecked(objReg);
  4366             enterStubFrame(masm, regs.getAnyExcluding(BaselineTailCallReg));
  4368             masm.pushValue(R1);
  4369             masm.push(objReg);
  4370             if (!callVM(LookupNoSuchMethodHandlerInfo, masm))
  4371                 return false;
  4373             leaveStubFrame(masm);
  4375             // Pop pushed obj and key from baseline stack.
  4376             EmitUnstowICValues(masm, 2, /* discard = */ true);
  4378             // Result is already in R0
  4379             masm.jump(&afterNoSuchMethod);
  4380             masm.bind(&skipNoSuchMethod);
  4382             if (popR1)
  4383                 masm.pop(R1.scratchReg());
  4384             masm.loadValue(valAddr, R0);
  4385             masm.bind(&afterNoSuchMethod);
  4386         } else {
  4387             masm.loadValue(valAddr, R0);
  4388             if (popR1)
  4389                 masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg);
  4391 #else
  4392         masm.loadValue(valAddr, R0);
  4393         if (popR1)
  4394             masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg);
  4395 #endif
  4397     } else {
  4398         JS_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter ||
  4399                   acctype_ == ICGetElemNativeStub::ScriptedGetter);
  4400         JS_ASSERT(kind == ICStub::GetElem_NativePrototypeCallNative ||
  4401                   kind == ICStub::GetElem_NativePrototypeCallScripted);
  4403         if (acctype_ == ICGetElemNativeStub::NativeGetter) {
  4404             // If calling a native getter, there is no chance of failure now.
  4406             // GetElem key (R1) is no longer needed.
  4407             if (popR1)
  4408                 masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg);
  4410             emitCallNative(masm, objReg);
  4412         } else {
  4413             JS_ASSERT(acctype_ == ICGetElemNativeStub::ScriptedGetter);
  4415             // Load function in scratchReg and ensure that it has a jit script.
  4416             masm.loadPtr(Address(BaselineStubReg, ICGetElemNativeGetterStub::offsetOfGetter()),
  4417                          scratchReg);
  4418             masm.branchIfFunctionHasNoScript(scratchReg, popR1 ? &failurePopR1 : &failure);
  4419             masm.loadPtr(Address(scratchReg, JSFunction::offsetOfNativeOrScript()), scratchReg);
  4420             masm.loadBaselineOrIonRaw(scratchReg, scratchReg, SequentialExecution,
  4421                                       popR1 ? &failurePopR1 : &failure);
  4423             // At this point, we are guaranteed to successfully complete.
  4424             if (popR1)
  4425                 masm.addPtr(Imm32(sizeof(size_t)), BaselineStackReg);
  4427             emitCallScripted(masm, objReg);
  4431     // Enter type monitor IC to type-check result.
  4432     EmitEnterTypeMonitorIC(masm);
  4434     // Failure case - jump to next stub
  4435     if (popR1) {
  4436         masm.bind(&failurePopR1);
  4437         masm.pop(R1.scratchReg());
  4439     masm.bind(&failure);
  4440     EmitStubGuardFailure(masm);
  4442     return true;
  4445 //
  4446 // GetElem_String
  4447 //
  4449 bool
  4450 ICGetElem_String::Compiler::generateStubCode(MacroAssembler &masm)
  4452     Label failure;
  4453     masm.branchTestString(Assembler::NotEqual, R0, &failure);
  4454     masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  4456     GeneralRegisterSet regs(availableGeneralRegs(2));
  4457     Register scratchReg = regs.takeAny();
  4459     // Unbox string in R0.
  4460     Register str = masm.extractString(R0, ExtractTemp0);
  4462     // Load string lengthAndFlags
  4463     Address lengthAndFlagsAddr(str, JSString::offsetOfLengthAndFlags());
  4464     masm.loadPtr(lengthAndFlagsAddr, scratchReg);
  4466     // Check for non-linear strings.
  4467     masm.branchTest32(Assembler::Zero, scratchReg, Imm32(JSString::FLAGS_MASK), &failure);
  4469     // Unbox key.
  4470     Register key = masm.extractInt32(R1, ExtractTemp1);
  4472     // Extract length and bounds check.
  4473     masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), scratchReg);
  4474     masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
  4476     // Get char code.
  4477     Address charsAddr(str, JSString::offsetOfChars());
  4478     masm.loadPtr(charsAddr, scratchReg);
  4479     masm.load16ZeroExtend(BaseIndex(scratchReg, key, TimesTwo, 0), scratchReg);
  4481     // Check if char code >= UNIT_STATIC_LIMIT.
  4482     masm.branch32(Assembler::AboveOrEqual, scratchReg, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
  4483                   &failure);
  4485     // Load static string.
  4486     masm.movePtr(ImmPtr(&cx->staticStrings().unitStaticTable), str);
  4487     masm.loadPtr(BaseIndex(str, scratchReg, ScalePointer), str);
  4489     // Return.
  4490     masm.tagValue(JSVAL_TYPE_STRING, str, R0);
  4491     EmitReturnFromIC(masm);
  4493     // Failure case - jump to next stub
  4494     masm.bind(&failure);
  4495     EmitStubGuardFailure(masm);
  4496     return true;
  4499 //
  4500 // GetElem_Dense
  4501 //
  4503 bool
  4504 ICGetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
  4506     Label failure;
  4507     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  4508     masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  4510     GeneralRegisterSet regs(availableGeneralRegs(2));
  4511     Register scratchReg = regs.takeAny();
  4513     // Unbox R0 and shape guard.
  4514     Register obj = masm.extractObject(R0, ExtractTemp0);
  4515     masm.loadPtr(Address(BaselineStubReg, ICGetElem_Dense::offsetOfShape()), scratchReg);
  4516     masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
  4518     // Load obj->elements.
  4519     masm.loadPtr(Address(obj, JSObject::offsetOfElements()), scratchReg);
  4521     // Unbox key.
  4522     Register key = masm.extractInt32(R1, ExtractTemp1);
  4524     // Bounds check.
  4525     Address initLength(scratchReg, ObjectElements::offsetOfInitializedLength());
  4526     masm.branch32(Assembler::BelowOrEqual, initLength, key, &failure);
  4528     // Hole check and load value.
  4529     JS_STATIC_ASSERT(sizeof(Value) == 8);
  4530     BaseIndex element(scratchReg, key, TimesEight);
  4531     masm.branchTestMagic(Assembler::Equal, element, &failure);
  4533     // Check if __noSuchMethod__ should be called.
  4534 #if JS_HAS_NO_SUCH_METHOD
  4535 #ifdef DEBUG
  4536     entersStubFrame_ = true;
  4537 #endif
  4538     if (isCallElem_) {
  4539         Label afterNoSuchMethod;
  4540         Label skipNoSuchMethod;
  4541         regs = availableGeneralRegs(0);
  4542         regs.takeUnchecked(obj);
  4543         regs.takeUnchecked(key);
  4544         regs.takeUnchecked(BaselineTailCallReg);
  4545         ValueOperand val = regs.takeValueOperand();
  4547         masm.loadValue(element, val);
  4548         masm.branchTestUndefined(Assembler::NotEqual, val, &skipNoSuchMethod);
  4550         // Box and push obj and key onto baseline frame stack for decompiler.
  4551         EmitRestoreTailCallReg(masm);
  4552         masm.tagValue(JSVAL_TYPE_OBJECT, obj, val);
  4553         masm.pushValue(val);
  4554         masm.tagValue(JSVAL_TYPE_INT32, key, val);
  4555         masm.pushValue(val);
  4556         EmitRepushTailCallReg(masm);
  4558         regs.add(val);
  4560         // Call __noSuchMethod__ checker.  Object pointer is in objReg.
  4561         enterStubFrame(masm, regs.getAnyExcluding(BaselineTailCallReg));
  4563         regs.take(val);
  4565         masm.tagValue(JSVAL_TYPE_INT32, key, val);
  4566         masm.pushValue(val);
  4567         masm.push(obj);
  4568         if (!callVM(LookupNoSuchMethodHandlerInfo, masm))
  4569             return false;
  4571         leaveStubFrame(masm);
  4573         // Pop pushed obj and key from baseline stack.
  4574         EmitUnstowICValues(masm, 2, /* discard = */ true);
  4576         // Result is already in R0
  4577         masm.jump(&afterNoSuchMethod);
  4578         masm.bind(&skipNoSuchMethod);
  4580         masm.moveValue(val, R0);
  4581         masm.bind(&afterNoSuchMethod);
  4582     } else {
  4583         masm.loadValue(element, R0);
  4585 #else
  4586     // Load value from element location.
  4587     masm.loadValue(element, R0);
  4588 #endif
  4590     // Enter type monitor IC to type-check result.
  4591     EmitEnterTypeMonitorIC(masm);
  4593     // Failure case - jump to next stub
  4594     masm.bind(&failure);
  4595     EmitStubGuardFailure(masm);
  4596     return true;
  4599 //
  4600 // GetElem_TypedArray
  4601 //
  4603 bool
  4604 ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
  4606     Label failure;
  4607     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  4609     GeneralRegisterSet regs(availableGeneralRegs(2));
  4610     Register scratchReg = regs.takeAny();
  4612     // Unbox R0 and shape guard.
  4613     Register obj = masm.extractObject(R0, ExtractTemp0);
  4614     masm.loadPtr(Address(BaselineStubReg, ICGetElem_TypedArray::offsetOfShape()), scratchReg);
  4615     masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
  4617     // Ensure the index is an integer.
  4618     if (cx->runtime()->jitSupportsFloatingPoint) {
  4619         Label isInt32;
  4620         masm.branchTestInt32(Assembler::Equal, R1, &isInt32);
  4622             // If the index is a double, try to convert it to int32. It's okay
  4623             // to convert -0 to 0: the shape check ensures the object is a typed
  4624             // array so the difference is not observable.
  4625             masm.branchTestDouble(Assembler::NotEqual, R1, &failure);
  4626             masm.unboxDouble(R1, FloatReg0);
  4627             masm.convertDoubleToInt32(FloatReg0, scratchReg, &failure, /* negZeroCheck = */false);
  4628             masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R1);
  4630         masm.bind(&isInt32);
  4631     } else {
  4632         masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  4635     // Unbox key.
  4636     Register key = masm.extractInt32(R1, ExtractTemp1);
  4638     // Bounds check.
  4639     masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), scratchReg);
  4640     masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
  4642     // Load the elements vector.
  4643     masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), scratchReg);
  4645     // Load the value.
  4646     BaseIndex source(scratchReg, key, ScaleFromElemWidth(TypedArrayObject::slotWidth(type_)));
  4647     masm.loadFromTypedArray(type_, source, R0, false, scratchReg, &failure);
  4649     // Todo: Allow loading doubles from uint32 arrays, but this requires monitoring.
  4650     EmitReturnFromIC(masm);
  4652     // Failure case - jump to next stub
  4653     masm.bind(&failure);
  4654     EmitStubGuardFailure(masm);
  4655     return true;
  4658 //
  4659 // GetEelem_Arguments
  4660 //
  4661 bool
  4662 ICGetElem_Arguments::Compiler::generateStubCode(MacroAssembler &masm)
  4664     // Variants of GetElem_Arguments can enter stub frames if entered in CallProp
  4665     // context when noSuchMethod support is on.
  4666 #if JS_HAS_NO_SUCH_METHOD
  4667 #ifdef DEBUG
  4668     entersStubFrame_ = true;
  4669 #endif
  4670 #endif
  4672     Label failure;
  4673     if (which_ == ICGetElem_Arguments::Magic) {
  4674         JS_ASSERT(!isCallElem_);
  4676         // Ensure that this is a magic arguments value.
  4677         masm.branchTestMagicValue(Assembler::NotEqual, R0, JS_OPTIMIZED_ARGUMENTS, &failure);
  4679         // Ensure that frame has not loaded different arguments object since.
  4680         masm.branchTest32(Assembler::NonZero,
  4681                           Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()),
  4682                           Imm32(BaselineFrame::HAS_ARGS_OBJ),
  4683                           &failure);
  4685         // Ensure that index is an integer.
  4686         masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  4687         Register idx = masm.extractInt32(R1, ExtractTemp1);
  4689         GeneralRegisterSet regs(availableGeneralRegs(2));
  4690         Register scratch = regs.takeAny();
  4692         // Load num actual arguments
  4693         Address actualArgs(BaselineFrameReg, BaselineFrame::offsetOfNumActualArgs());
  4694         masm.loadPtr(actualArgs, scratch);
  4696         // Ensure idx < argc
  4697         masm.branch32(Assembler::AboveOrEqual, idx, scratch, &failure);
  4699         // Load argval
  4700         JS_STATIC_ASSERT(sizeof(Value) == 8);
  4701         masm.movePtr(BaselineFrameReg, scratch);
  4702         masm.addPtr(Imm32(BaselineFrame::offsetOfArg(0)), scratch);
  4703         BaseIndex element(scratch, idx, TimesEight);
  4704         masm.loadValue(element, R0);
  4706         // Enter type monitor IC to type-check result.
  4707         EmitEnterTypeMonitorIC(masm);
  4709         masm.bind(&failure);
  4710         EmitStubGuardFailure(masm);
  4711         return true;
  4714     JS_ASSERT(which_ == ICGetElem_Arguments::Strict ||
  4715               which_ == ICGetElem_Arguments::Normal);
  4717     bool isStrict = which_ == ICGetElem_Arguments::Strict;
  4718     const Class *clasp = isStrict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_;
  4720     GeneralRegisterSet regs(availableGeneralRegs(2));
  4721     Register scratchReg = regs.takeAny();
  4723     // Guard on input being an arguments object.
  4724     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  4725     Register objReg = masm.extractObject(R0, ExtractTemp0);
  4726     masm.branchTestObjClass(Assembler::NotEqual, objReg, scratchReg, clasp, &failure);
  4728     // Guard on index being int32
  4729     masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  4730     Register idxReg = masm.extractInt32(R1, ExtractTemp1);
  4732     // Get initial ArgsObj length value.
  4733     masm.unboxInt32(Address(objReg, ArgumentsObject::getInitialLengthSlotOffset()), scratchReg);
  4735     // Test if length has been overridden.
  4736     masm.branchTest32(Assembler::NonZero,
  4737                       scratchReg,
  4738                       Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT),
  4739                       &failure);
  4741     // Length has not been overridden, ensure that R1 is an integer and is <= length.
  4742     masm.rshiftPtr(Imm32(ArgumentsObject::PACKED_BITS_COUNT), scratchReg);
  4743     masm.branch32(Assembler::AboveOrEqual, idxReg, scratchReg, &failure);
  4745     // Length check succeeded, now check the correct bit.  We clobber potential type regs
  4746     // now.  Inputs will have to be reconstructed if we fail after this point, but that's
  4747     // unlikely.
  4748     Label failureReconstructInputs;
  4749     regs = availableGeneralRegs(0);
  4750     regs.takeUnchecked(objReg);
  4751     regs.takeUnchecked(idxReg);
  4752     regs.take(scratchReg);
  4753     Register argData = regs.takeAny();
  4754     Register tempReg = regs.takeAny();
  4756     // Load ArgumentsData
  4757     masm.loadPrivate(Address(objReg, ArgumentsObject::getDataSlotOffset()), argData);
  4759     // Load deletedBits bitArray pointer into scratchReg
  4760     masm.loadPtr(Address(argData, offsetof(ArgumentsData, deletedBits)), scratchReg);
  4762     // In tempReg, calculate index of word containing bit: (idx >> logBitsPerWord)
  4763     masm.movePtr(idxReg, tempReg);
  4764     const uint32_t shift = mozilla::tl::FloorLog2<(sizeof(size_t) * JS_BITS_PER_BYTE)>::value;
  4765     JS_ASSERT(shift == 5 || shift == 6);
  4766     masm.rshiftPtr(Imm32(shift), tempReg);
  4767     masm.loadPtr(BaseIndex(scratchReg, tempReg, ScaleFromElemWidth(sizeof(size_t))), scratchReg);
  4769     // Don't bother testing specific bit, if any bit is set in the word, fail.
  4770     masm.branchPtr(Assembler::NotEqual, scratchReg, ImmPtr(nullptr), &failureReconstructInputs);
  4772     // Load the value.  use scratchReg and tempReg to form a ValueOperand to load into.
  4773     masm.addPtr(Imm32(ArgumentsData::offsetOfArgs()), argData);
  4774     regs.add(scratchReg);
  4775     regs.add(tempReg);
  4776     ValueOperand tempVal = regs.takeAnyValue();
  4777     masm.loadValue(BaseIndex(argData, idxReg, ScaleFromElemWidth(sizeof(Value))), tempVal);
  4779     // Makesure that this is not a FORWARD_TO_CALL_SLOT magic value.
  4780     masm.branchTestMagic(Assembler::Equal, tempVal, &failureReconstructInputs);
  4782 #if JS_HAS_NO_SUCH_METHOD
  4783     if (isCallElem_) {
  4784         Label afterNoSuchMethod;
  4785         Label skipNoSuchMethod;
  4787         masm.branchTestUndefined(Assembler::NotEqual, tempVal, &skipNoSuchMethod);
  4789         // Call __noSuchMethod__ checker.  Object pointer is in objReg.
  4790         regs = availableGeneralRegs(0);
  4791         regs.takeUnchecked(objReg);
  4792         regs.takeUnchecked(idxReg);
  4793         regs.takeUnchecked(BaselineTailCallReg);
  4794         ValueOperand val = regs.takeValueOperand();
  4796         // Box and push obj and key onto baseline frame stack for decompiler.
  4797         EmitRestoreTailCallReg(masm);
  4798         masm.tagValue(JSVAL_TYPE_OBJECT, objReg, val);
  4799         masm.pushValue(val);
  4800         masm.tagValue(JSVAL_TYPE_INT32, idxReg, val);
  4801         masm.pushValue(val);
  4802         EmitRepushTailCallReg(masm);
  4804         regs.add(val);
  4805         enterStubFrame(masm, regs.getAnyExcluding(BaselineTailCallReg));
  4806         regs.take(val);
  4808         masm.pushValue(val);
  4809         masm.push(objReg);
  4810         if (!callVM(LookupNoSuchMethodHandlerInfo, masm))
  4811             return false;
  4813         leaveStubFrame(masm);
  4815         // Pop pushed obj and key from baseline stack.
  4816         EmitUnstowICValues(masm, 2, /* discard = */ true);
  4818         // Result is already in R0
  4819         masm.jump(&afterNoSuchMethod);
  4820         masm.bind(&skipNoSuchMethod);
  4822         masm.moveValue(tempVal, R0);
  4823         masm.bind(&afterNoSuchMethod);
  4824     } else {
  4825         masm.moveValue(tempVal, R0);
  4827 #else
  4828     // Copy value from temp to R0.
  4829     masm.moveValue(tempVal, R0);
  4830 #endif
  4832     // Type-check result
  4833     EmitEnterTypeMonitorIC(masm);
  4835     // Failed, but inputs are deconstructed into object and int, and need to be
  4836     // reconstructed into values.
  4837     masm.bind(&failureReconstructInputs);
  4838     masm.tagValue(JSVAL_TYPE_OBJECT, objReg, R0);
  4839     masm.tagValue(JSVAL_TYPE_INT32, idxReg, R1);
  4841     masm.bind(&failure);
  4842     EmitStubGuardFailure(masm);
  4843     return true;
  4846 //
  4847 // SetElem_Fallback
  4848 //
  4850 static bool
  4851 SetElemDenseAddHasSameShapes(ICSetElem_DenseAdd *stub, JSObject *obj)
  4853     size_t numShapes = stub->protoChainDepth() + 1;
  4854     for (size_t i = 0; i < numShapes; i++) {
  4855         static const size_t MAX_DEPTH = ICSetElem_DenseAdd::MAX_PROTO_CHAIN_DEPTH;
  4856         if (obj->lastProperty() != stub->toImplUnchecked<MAX_DEPTH>()->shape(i))
  4857             return false;
  4858         obj = obj->getProto();
  4859         if (!obj && i != numShapes - 1)
  4860             return false;
  4863     return true;
  4866 static bool
  4867 DenseSetElemStubExists(JSContext *cx, ICStub::Kind kind, ICSetElem_Fallback *stub, HandleObject obj)
  4869     JS_ASSERT(kind == ICStub::SetElem_Dense || kind == ICStub::SetElem_DenseAdd);
  4871     for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
  4872         if (kind == ICStub::SetElem_Dense && iter->isSetElem_Dense()) {
  4873             ICSetElem_Dense *dense = iter->toSetElem_Dense();
  4874             if (obj->lastProperty() == dense->shape() && obj->getType(cx) == dense->type())
  4875                 return true;
  4878         if (kind == ICStub::SetElem_DenseAdd && iter->isSetElem_DenseAdd()) {
  4879             ICSetElem_DenseAdd *dense = iter->toSetElem_DenseAdd();
  4880             if (obj->getType(cx) == dense->type() && SetElemDenseAddHasSameShapes(dense, obj))
  4881                 return true;
  4884     return false;
  4887 static bool
  4888 TypedArraySetElemStubExists(ICSetElem_Fallback *stub, HandleObject obj, bool expectOOB)
  4890     for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
  4891         if (!iter->isSetElem_TypedArray())
  4892             continue;
  4893         ICSetElem_TypedArray *taStub = iter->toSetElem_TypedArray();
  4894         if (obj->lastProperty() == taStub->shape() && taStub->expectOutOfBounds() == expectOOB)
  4895             return true;
  4897     return false;
  4900 static bool
  4901 RemoveExistingTypedArraySetElemStub(JSContext *cx, ICSetElem_Fallback *stub, HandleObject obj)
  4903     for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++) {
  4904         if (!iter->isSetElem_TypedArray())
  4905             continue;
  4907         if (obj->lastProperty() != iter->toSetElem_TypedArray()->shape())
  4908             continue;
  4910         // TypedArraySetElem stubs are only removed using this procedure if
  4911         // being replaced with one that expects out of bounds index.
  4912         JS_ASSERT(!iter->toSetElem_TypedArray()->expectOutOfBounds());
  4913         iter.unlink(cx);
  4914         return true;
  4916     return false;
  4919 static bool
  4920 CanOptimizeDenseSetElem(JSContext *cx, HandleObject obj, uint32_t index,
  4921                         HandleShape oldShape, uint32_t oldCapacity, uint32_t oldInitLength,
  4922                         bool *isAddingCaseOut, size_t *protoDepthOut)
  4924     uint32_t initLength = obj->getDenseInitializedLength();
  4925     uint32_t capacity = obj->getDenseCapacity();
  4927     *isAddingCaseOut = false;
  4928     *protoDepthOut = 0;
  4930     // Some initial sanity checks.
  4931     if (initLength < oldInitLength || capacity < oldCapacity)
  4932         return false;
  4934     RootedShape shape(cx, obj->lastProperty());
  4936     // Cannot optimize if the shape changed.
  4937     if (oldShape != shape)
  4938         return false;
  4940     // Cannot optimize if the capacity changed.
  4941     if (oldCapacity != capacity)
  4942         return false;
  4944     // Cannot optimize if the index doesn't fit within the new initialized length.
  4945     if (index >= initLength)
  4946         return false;
  4948     // Cannot optimize if the value at position after the set is a hole.
  4949     if (!obj->containsDenseElement(index))
  4950         return false;
  4952     // At this point, if we know that the initLength did not change, then
  4953     // an optimized set is possible.
  4954     if (oldInitLength == initLength)
  4955         return true;
  4957     // If it did change, ensure that it changed specifically by incrementing by 1
  4958     // to accomodate this particular indexed set.
  4959     if (oldInitLength + 1 != initLength)
  4960         return false;
  4961     if (index != oldInitLength)
  4962         return false;
  4964     // The checks are not complete.  The object may have a setter definition,
  4965     // either directly, or via a prototype, or via the target object for a prototype
  4966     // which is a proxy, that handles a particular integer write.
  4967     // Scan the prototype and shape chain to make sure that this is not the case.
  4968     RootedObject curObj(cx, obj);
  4969     while (curObj) {
  4970         // Ensure object is native.
  4971         if (!curObj->isNative())
  4972             return false;
  4974         // Ensure all indexed properties are stored in dense elements.
  4975         if (curObj->isIndexed())
  4976             return false;
  4978         curObj = curObj->getProto();
  4979         if (curObj)
  4980             ++*protoDepthOut;
  4983     if (*protoDepthOut > ICSetElem_DenseAdd::MAX_PROTO_CHAIN_DEPTH)
  4984         return false;
  4986     *isAddingCaseOut = true;
  4988     return true;
  4991 static bool
  4992 DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub_, Value *stack,
  4993                   HandleValue objv, HandleValue index, HandleValue rhs)
  4995     // This fallback stub may trigger debug mode toggling.
  4996     DebugModeOSRVolatileStub<ICSetElem_Fallback *> stub(frame, stub_);
  4998     RootedScript script(cx, frame->script());
  4999     jsbytecode *pc = stub->icEntry()->pc(script);
  5000     JSOp op = JSOp(*pc);
  5001     FallbackICSpew(cx, stub, "SetElem(%s)", js_CodeName[JSOp(*pc)]);
  5003     JS_ASSERT(op == JSOP_SETELEM ||
  5004               op == JSOP_INITELEM ||
  5005               op == JSOP_INITELEM_ARRAY);
  5007     RootedObject obj(cx, ToObjectFromStack(cx, objv));
  5008     if (!obj)
  5009         return false;
  5011     RootedShape oldShape(cx, obj->lastProperty());
  5013     // Check the old capacity
  5014     uint32_t oldCapacity = 0;
  5015     uint32_t oldInitLength = 0;
  5016     if (obj->isNative() && index.isInt32() && index.toInt32() >= 0) {
  5017         oldCapacity = obj->getDenseCapacity();
  5018         oldInitLength = obj->getDenseInitializedLength();
  5021     if (op == JSOP_INITELEM) {
  5022         if (!InitElemOperation(cx, obj, index, rhs))
  5023             return false;
  5024     } else if (op == JSOP_INITELEM_ARRAY) {
  5025         JS_ASSERT(uint32_t(index.toInt32()) == GET_UINT24(pc));
  5026         if (!InitArrayElemOperation(cx, pc, obj, index.toInt32(), rhs))
  5027             return false;
  5028     } else {
  5029         if (!SetObjectElement(cx, obj, index, rhs, script->strict(), script, pc))
  5030             return false;
  5033     // Overwrite the object on the stack (pushed for the decompiler) with the rhs.
  5034     JS_ASSERT(stack[2] == objv);
  5035     stack[2] = rhs;
  5037     // Check if debug mode toggling made the stub invalid.
  5038     if (stub.invalid())
  5039         return true;
  5041     if (stub->numOptimizedStubs() >= ICSetElem_Fallback::MAX_OPTIMIZED_STUBS) {
  5042         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
  5043         // But for now we just bail.
  5044         return true;
  5047     // Try to generate new stubs.
  5048     if (obj->isNative() &&
  5049         !obj->is<TypedArrayObject>() &&
  5050         index.isInt32() && index.toInt32() >= 0 &&
  5051         !rhs.isMagic(JS_ELEMENTS_HOLE))
  5053         bool addingCase;
  5054         size_t protoDepth;
  5056         if (CanOptimizeDenseSetElem(cx, obj, index.toInt32(), oldShape, oldCapacity, oldInitLength,
  5057                                     &addingCase, &protoDepth))
  5059             RootedShape shape(cx, obj->lastProperty());
  5060             RootedTypeObject type(cx, obj->getType(cx));
  5061             if (!type)
  5062                 return false;
  5064             if (addingCase && !DenseSetElemStubExists(cx, ICStub::SetElem_DenseAdd, stub, obj)) {
  5065                 IonSpew(IonSpew_BaselineIC,
  5066                         "  Generating SetElem_DenseAdd stub "
  5067                         "(shape=%p, type=%p, protoDepth=%u)",
  5068                         obj->lastProperty(), type.get(), protoDepth);
  5069                 ICSetElemDenseAddCompiler compiler(cx, obj, protoDepth);
  5070                 ICUpdatedStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
  5071                 if (!denseStub)
  5072                     return false;
  5073                 if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
  5074                     return false;
  5076                 stub->addNewStub(denseStub);
  5077             } else if (!addingCase &&
  5078                        !DenseSetElemStubExists(cx, ICStub::SetElem_Dense, stub, obj))
  5080                 IonSpew(IonSpew_BaselineIC,
  5081                         "  Generating SetElem_Dense stub (shape=%p, type=%p)",
  5082                         obj->lastProperty(), type.get());
  5083                 ICSetElem_Dense::Compiler compiler(cx, shape, type);
  5084                 ICUpdatedStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
  5085                 if (!denseStub)
  5086                     return false;
  5087                 if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
  5088                     return false;
  5090                 stub->addNewStub(denseStub);
  5094         return true;
  5097     if (obj->is<TypedArrayObject>() && index.isNumber() && rhs.isNumber()) {
  5098         Rooted<TypedArrayObject*> tarr(cx, &obj->as<TypedArrayObject>());
  5099         if (!cx->runtime()->jitSupportsFloatingPoint &&
  5100             (TypedArrayRequiresFloatingPoint(tarr) || index.isDouble()))
  5102             return true;
  5105         uint32_t len = tarr->length();
  5106         double idx = index.toNumber();
  5107         bool expectOutOfBounds = (idx < 0 || idx >= double(len));
  5109         if (!TypedArraySetElemStubExists(stub, tarr, expectOutOfBounds)) {
  5110             // Remove any existing TypedArraySetElemStub that doesn't handle out-of-bounds
  5111             if (expectOutOfBounds)
  5112                 RemoveExistingTypedArraySetElemStub(cx, stub, tarr);
  5114             IonSpew(IonSpew_BaselineIC,
  5115                     "  Generating SetElem_TypedArray stub (shape=%p, type=%u, oob=%s)",
  5116                     tarr->lastProperty(), tarr->type(), expectOutOfBounds ? "yes" : "no");
  5117             ICSetElem_TypedArray::Compiler compiler(cx, tarr->lastProperty(), tarr->type(),
  5118                                                     expectOutOfBounds);
  5119             ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
  5120             if (!typedArrayStub)
  5121                 return false;
  5123             stub->addNewStub(typedArrayStub);
  5124             return true;
  5128     return true;
  5131 typedef bool (*DoSetElemFallbackFn)(JSContext *, BaselineFrame *, ICSetElem_Fallback *, Value *,
  5132                                     HandleValue, HandleValue, HandleValue);
  5133 static const VMFunction DoSetElemFallbackInfo =
  5134     FunctionInfo<DoSetElemFallbackFn>(DoSetElemFallback, PopValues(2));
  5136 bool
  5137 ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  5139     JS_ASSERT(R0 == JSReturnOperand);
  5141     EmitRestoreTailCallReg(masm);
  5143     // State: R0: object, R1: index, stack: rhs.
  5144     // For the decompiler, the stack has to be: object, index, rhs,
  5145     // so we push the index, then overwrite the rhs Value with R0
  5146     // and push the rhs value.
  5147     masm.pushValue(R1);
  5148     masm.loadValue(Address(BaselineStackReg, sizeof(Value)), R1);
  5149     masm.storeValue(R0, Address(BaselineStackReg, sizeof(Value)));
  5150     masm.pushValue(R1);
  5152     // Push arguments.
  5153     masm.pushValue(R1); // RHS
  5155     // Push index. On x86 and ARM two push instructions are emitted so use a
  5156     // separate register to store the old stack pointer.
  5157     masm.mov(BaselineStackReg, R1.scratchReg());
  5158     masm.pushValue(Address(R1.scratchReg(), 2 * sizeof(Value)));
  5159     masm.pushValue(R0); // Object.
  5161     // Push pointer to stack values, so that the stub can overwrite the object
  5162     // (pushed for the decompiler) with the rhs.
  5163     masm.computeEffectiveAddress(Address(BaselineStackReg, 3 * sizeof(Value)), R0.scratchReg());
  5164     masm.push(R0.scratchReg());
  5166     masm.push(BaselineStubReg);
  5167     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  5169     return tailCallVM(DoSetElemFallbackInfo, masm);
  5172 void
  5173 BaselineScript::noteArrayWriteHole(uint32_t pcOffset)
  5175     ICEntry &entry = icEntryFromPCOffset(pcOffset);
  5176     ICFallbackStub *stub = entry.fallbackStub();
  5178     if (stub->isSetElem_Fallback())
  5179         stub->toSetElem_Fallback()->noteArrayWriteHole();
  5182 //
  5183 // SetElem_Dense
  5184 //
  5186 bool
  5187 ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
  5189     // R0 = object
  5190     // R1 = key
  5191     // Stack = { ... rhs-value, <return-addr>? }
  5192     Label failure;
  5193     Label failureUnstow;
  5194     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  5195     masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  5197     GeneralRegisterSet regs(availableGeneralRegs(2));
  5198     Register scratchReg = regs.takeAny();
  5200     // Unbox R0 and guard on its shape.
  5201     Register obj = masm.extractObject(R0, ExtractTemp0);
  5202     masm.loadPtr(Address(BaselineStubReg, ICSetElem_Dense::offsetOfShape()), scratchReg);
  5203     masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
  5205     // Stow both R0 and R1 (object and key)
  5206     // But R0 and R1 still hold their values.
  5207     EmitStowICValues(masm, 2);
  5209     // We may need to free up some registers.
  5210     regs = availableGeneralRegs(0);
  5211     regs.take(R0);
  5213     // Guard that the type object matches.
  5214     Register typeReg = regs.takeAny();
  5215     masm.loadPtr(Address(BaselineStubReg, ICSetElem_Dense::offsetOfType()), typeReg);
  5216     masm.branchPtr(Assembler::NotEqual, Address(obj, JSObject::offsetOfType()), typeReg,
  5217                    &failureUnstow);
  5218     regs.add(typeReg);
  5220     // Stack is now: { ..., rhs-value, object-value, key-value, maybe?-RET-ADDR }
  5221     // Load rhs-value in to R0
  5222     masm.loadValue(Address(BaselineStackReg, 2 * sizeof(Value) + ICStackValueOffset), R0);
  5224     // Call the type-update stub.
  5225     if (!callTypeUpdateIC(masm, sizeof(Value)))
  5226         return false;
  5228     // Unstow R0 and R1 (object and key)
  5229     EmitUnstowICValues(masm, 2);
  5231     // Reset register set.
  5232     regs = availableGeneralRegs(2);
  5233     scratchReg = regs.takeAny();
  5235     // Unbox object and key.
  5236     obj = masm.extractObject(R0, ExtractTemp0);
  5237     Register key = masm.extractInt32(R1, ExtractTemp1);
  5239     // Load obj->elements in scratchReg.
  5240     masm.loadPtr(Address(obj, JSObject::offsetOfElements()), scratchReg);
  5242     // Bounds check.
  5243     Address initLength(scratchReg, ObjectElements::offsetOfInitializedLength());
  5244     masm.branch32(Assembler::BelowOrEqual, initLength, key, &failure);
  5246     // Hole check.
  5247     BaseIndex element(scratchReg, key, TimesEight);
  5248     masm.branchTestMagic(Assembler::Equal, element, &failure);
  5250     // Failure is not possible now.  Free up registers.
  5251     regs.add(R0);
  5252     regs.add(R1);
  5253     regs.takeUnchecked(obj);
  5254     regs.takeUnchecked(key);
  5255     Address valueAddr(BaselineStackReg, ICStackValueOffset);
  5257     // Convert int32 values to double if convertDoubleElements is set. In this
  5258     // case the heap typeset is guaranteed to contain both int32 and double, so
  5259     // it's okay to store a double.
  5260     Label dontConvertDoubles;
  5261     Address elementsFlags(scratchReg, ObjectElements::offsetOfFlags());
  5262     masm.branchTest32(Assembler::Zero, elementsFlags,
  5263                       Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
  5264                       &dontConvertDoubles);
  5265     // Note that double arrays are only created by IonMonkey, so if we have no
  5266     // floating-point support Ion is disabled and there should be no double arrays.
  5267     if (cx->runtime()->jitSupportsFloatingPoint)
  5268         masm.convertInt32ValueToDouble(valueAddr, regs.getAny(), &dontConvertDoubles);
  5269     else
  5270         masm.assumeUnreachable("There shouldn't be double arrays when there is no FP support.");
  5271     masm.bind(&dontConvertDoubles);
  5273     // Don't overwrite R0 becuase |obj| might overlap with it, and it's needed
  5274     // for post-write barrier later.
  5275     ValueOperand tmpVal = regs.takeAnyValue();
  5276     masm.loadValue(valueAddr, tmpVal);
  5277     EmitPreBarrier(masm, element, MIRType_Value);
  5278     masm.storeValue(tmpVal, element);
  5279     regs.add(key);
  5280 #ifdef JSGC_GENERATIONAL
  5282         Register r = regs.takeAny();
  5283         GeneralRegisterSet saveRegs;
  5284         emitPostWriteBarrierSlot(masm, obj, tmpVal, r, saveRegs);
  5285         regs.add(r);
  5287 #endif
  5288     EmitReturnFromIC(masm);
  5291     // Failure case - fail but first unstow R0 and R1
  5292     masm.bind(&failureUnstow);
  5293     EmitUnstowICValues(masm, 2);
  5295     // Failure case - jump to next stub
  5296     masm.bind(&failure);
  5297     EmitStubGuardFailure(masm);
  5298     return true;
  5301 static bool
  5302 GetProtoShapes(JSObject *obj, size_t protoChainDepth, AutoShapeVector *shapes)
  5304     JS_ASSERT(shapes->length() == 1);
  5305     JSObject *curProto = obj->getProto();
  5306     for (size_t i = 0; i < protoChainDepth; i++) {
  5307         if (!shapes->append(curProto->lastProperty()))
  5308             return false;
  5309         curProto = curProto->getProto();
  5311     JS_ASSERT(!curProto);
  5312     return true;
  5315 //
  5316 // SetElem_DenseAdd
  5317 //
  5319 ICUpdatedStub *
  5320 ICSetElemDenseAddCompiler::getStub(ICStubSpace *space)
  5322     AutoShapeVector shapes(cx);
  5323     if (!shapes.append(obj_->lastProperty()))
  5324         return nullptr;
  5326     if (!GetProtoShapes(obj_, protoChainDepth_, &shapes))
  5327         return nullptr;
  5329     JS_STATIC_ASSERT(ICSetElem_DenseAdd::MAX_PROTO_CHAIN_DEPTH == 4);
  5331     ICUpdatedStub *stub = nullptr;
  5332     switch (protoChainDepth_) {
  5333       case 0: stub = getStubSpecific<0>(space, &shapes); break;
  5334       case 1: stub = getStubSpecific<1>(space, &shapes); break;
  5335       case 2: stub = getStubSpecific<2>(space, &shapes); break;
  5336       case 3: stub = getStubSpecific<3>(space, &shapes); break;
  5337       case 4: stub = getStubSpecific<4>(space, &shapes); break;
  5338       default: MOZ_ASSUME_UNREACHABLE("ProtoChainDepth too high.");
  5340     if (!stub || !stub->initUpdatingChain(cx, space))
  5341         return nullptr;
  5342     return stub;
  5345 bool
  5346 ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm)
  5348     // R0 = object
  5349     // R1 = key
  5350     // Stack = { ... rhs-value, <return-addr>? }
  5351     Label failure;
  5352     Label failureUnstow;
  5353     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  5354     masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  5356     GeneralRegisterSet regs(availableGeneralRegs(2));
  5357     Register scratchReg = regs.takeAny();
  5359     // Unbox R0 and guard on its shape.
  5360     Register obj = masm.extractObject(R0, ExtractTemp0);
  5361     masm.loadPtr(Address(BaselineStubReg, ICSetElem_DenseAddImpl<0>::offsetOfShape(0)),
  5362                  scratchReg);
  5363     masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
  5365     // Stow both R0 and R1 (object and key)
  5366     // But R0 and R1 still hold their values.
  5367     EmitStowICValues(masm, 2);
  5369     // We may need to free up some registers.
  5370     regs = availableGeneralRegs(0);
  5371     regs.take(R0);
  5373     // Guard that the type object matches.
  5374     Register typeReg = regs.takeAny();
  5375     masm.loadPtr(Address(BaselineStubReg, ICSetElem_DenseAdd::offsetOfType()), typeReg);
  5376     masm.branchPtr(Assembler::NotEqual, Address(obj, JSObject::offsetOfType()), typeReg,
  5377                    &failureUnstow);
  5378     regs.add(typeReg);
  5380     // Shape guard objects on the proto chain.
  5381     scratchReg = regs.takeAny();
  5382     Register protoReg = regs.takeAny();
  5383     for (size_t i = 0; i < protoChainDepth_; i++) {
  5384         masm.loadObjProto(i == 0 ? obj : protoReg, protoReg);
  5385         masm.branchTestPtr(Assembler::Zero, protoReg, protoReg, &failureUnstow);
  5386         masm.loadPtr(Address(BaselineStubReg, ICSetElem_DenseAddImpl<0>::offsetOfShape(i + 1)),
  5387                      scratchReg);
  5388         masm.branchTestObjShape(Assembler::NotEqual, protoReg, scratchReg, &failureUnstow);
  5390     regs.add(protoReg);
  5391     regs.add(scratchReg);
  5393     // Stack is now: { ..., rhs-value, object-value, key-value, maybe?-RET-ADDR }
  5394     // Load rhs-value in to R0
  5395     masm.loadValue(Address(BaselineStackReg, 2 * sizeof(Value) + ICStackValueOffset), R0);
  5397     // Call the type-update stub.
  5398     if (!callTypeUpdateIC(masm, sizeof(Value)))
  5399         return false;
  5401     // Unstow R0 and R1 (object and key)
  5402     EmitUnstowICValues(masm, 2);
  5404     // Reset register set.
  5405     regs = availableGeneralRegs(2);
  5406     scratchReg = regs.takeAny();
  5408     // Unbox obj and key.
  5409     obj = masm.extractObject(R0, ExtractTemp0);
  5410     Register key = masm.extractInt32(R1, ExtractTemp1);
  5412     // Load obj->elements in scratchReg.
  5413     masm.loadPtr(Address(obj, JSObject::offsetOfElements()), scratchReg);
  5415     // Bounds check (key == initLength)
  5416     Address initLength(scratchReg, ObjectElements::offsetOfInitializedLength());
  5417     masm.branch32(Assembler::NotEqual, initLength, key, &failure);
  5419     // Capacity check.
  5420     Address capacity(scratchReg, ObjectElements::offsetOfCapacity());
  5421     masm.branch32(Assembler::BelowOrEqual, capacity, key, &failure);
  5423     // Failure is not possible now.  Free up registers.
  5424     regs.add(R0);
  5425     regs.add(R1);
  5426     regs.takeUnchecked(obj);
  5427     regs.takeUnchecked(key);
  5429     // Increment initLength before write.
  5430     masm.add32(Imm32(1), initLength);
  5432     // If length is now <= key, increment length before write.
  5433     Label skipIncrementLength;
  5434     Address length(scratchReg, ObjectElements::offsetOfLength());
  5435     masm.branch32(Assembler::Above, length, key, &skipIncrementLength);
  5436     masm.add32(Imm32(1), length);
  5437     masm.bind(&skipIncrementLength);
  5439     Address valueAddr(BaselineStackReg, ICStackValueOffset);
  5441     // Convert int32 values to double if convertDoubleElements is set. In this
  5442     // case the heap typeset is guaranteed to contain both int32 and double, so
  5443     // it's okay to store a double.
  5444     Label dontConvertDoubles;
  5445     Address elementsFlags(scratchReg, ObjectElements::offsetOfFlags());
  5446     masm.branchTest32(Assembler::Zero, elementsFlags,
  5447                       Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
  5448                       &dontConvertDoubles);
  5449     // Note that double arrays are only created by IonMonkey, so if we have no
  5450     // floating-point support Ion is disabled and there should be no double arrays.
  5451     if (cx->runtime()->jitSupportsFloatingPoint)
  5452         masm.convertInt32ValueToDouble(valueAddr, regs.getAny(), &dontConvertDoubles);
  5453     else
  5454         masm.assumeUnreachable("There shouldn't be double arrays when there is no FP support.");
  5455     masm.bind(&dontConvertDoubles);
  5457     // Write the value.  No need for pre-barrier since we're not overwriting an old value.
  5458     ValueOperand tmpVal = regs.takeAnyValue();
  5459     BaseIndex element(scratchReg, key, TimesEight);
  5460     masm.loadValue(valueAddr, tmpVal);
  5461     masm.storeValue(tmpVal, element);
  5462     regs.add(key);
  5463 #ifdef JSGC_GENERATIONAL
  5465         Register r = regs.takeAny();
  5466         GeneralRegisterSet saveRegs;
  5467         emitPostWriteBarrierSlot(masm, obj, tmpVal, r, saveRegs);
  5468         regs.add(r);
  5470 #endif
  5471     EmitReturnFromIC(masm);
  5473     // Failure case - fail but first unstow R0 and R1
  5474     masm.bind(&failureUnstow);
  5475     EmitUnstowICValues(masm, 2);
  5477     // Failure case - jump to next stub
  5478     masm.bind(&failure);
  5479     EmitStubGuardFailure(masm);
  5480     return true;
  5483 //
  5484 // SetElem_TypedArray
  5485 //
  5487 bool
  5488 ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
  5490     Label failure;
  5491     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  5493     GeneralRegisterSet regs(availableGeneralRegs(2));
  5494     Register scratchReg = regs.takeAny();
  5496     // Unbox R0 and shape guard.
  5497     Register obj = masm.extractObject(R0, ExtractTemp0);
  5498     masm.loadPtr(Address(BaselineStubReg, ICSetElem_TypedArray::offsetOfShape()), scratchReg);
  5499     masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
  5501     // Ensure the index is an integer.
  5502     if (cx->runtime()->jitSupportsFloatingPoint) {
  5503         Label isInt32;
  5504         masm.branchTestInt32(Assembler::Equal, R1, &isInt32);
  5506             // If the index is a double, try to convert it to int32. It's okay
  5507             // to convert -0 to 0: the shape check ensures the object is a typed
  5508             // array so the difference is not observable.
  5509             masm.branchTestDouble(Assembler::NotEqual, R1, &failure);
  5510             masm.unboxDouble(R1, FloatReg0);
  5511             masm.convertDoubleToInt32(FloatReg0, scratchReg, &failure, /* negZeroCheck = */false);
  5512             masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R1);
  5514         masm.bind(&isInt32);
  5515     } else {
  5516         masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
  5519     // Unbox key.
  5520     Register key = masm.extractInt32(R1, ExtractTemp1);
  5522     // Bounds check.
  5523     Label oobWrite;
  5524     masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), scratchReg);
  5525     masm.branch32(Assembler::BelowOrEqual, scratchReg, key,
  5526                   expectOutOfBounds_ ? &oobWrite : &failure);
  5528     // Load the elements vector.
  5529     masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), scratchReg);
  5531     BaseIndex dest(scratchReg, key, ScaleFromElemWidth(TypedArrayObject::slotWidth(type_)));
  5532     Address value(BaselineStackReg, ICStackValueOffset);
  5534     // We need a second scratch register. It's okay to clobber the type tag of
  5535     // R0 or R1, as long as it's restored before jumping to the next stub.
  5536     regs = availableGeneralRegs(0);
  5537     regs.takeUnchecked(obj);
  5538     regs.takeUnchecked(key);
  5539     regs.take(scratchReg);
  5540     Register secondScratch = regs.takeAny();
  5542     if (type_ == ScalarTypeDescr::TYPE_FLOAT32 || type_ == ScalarTypeDescr::TYPE_FLOAT64) {
  5543         masm.ensureDouble(value, FloatReg0, &failure);
  5544         if (LIRGenerator::allowFloat32Optimizations() &&
  5545             type_ == ScalarTypeDescr::TYPE_FLOAT32)
  5547             masm.convertDoubleToFloat32(FloatReg0, ScratchFloatReg);
  5548             masm.storeToTypedFloatArray(type_, ScratchFloatReg, dest);
  5549         } else {
  5550             masm.storeToTypedFloatArray(type_, FloatReg0, dest);
  5552         EmitReturnFromIC(masm);
  5553     } else if (type_ == ScalarTypeDescr::TYPE_UINT8_CLAMPED) {
  5554         Label notInt32;
  5555         masm.branchTestInt32(Assembler::NotEqual, value, &notInt32);
  5556         masm.unboxInt32(value, secondScratch);
  5557         masm.clampIntToUint8(secondScratch);
  5559         Label clamped;
  5560         masm.bind(&clamped);
  5561         masm.storeToTypedIntArray(type_, secondScratch, dest);
  5562         EmitReturnFromIC(masm);
  5564         // If the value is a double, clamp to uint8 and jump back.
  5565         // Else, jump to failure.
  5566         masm.bind(&notInt32);
  5567         if (cx->runtime()->jitSupportsFloatingPoint) {
  5568             masm.branchTestDouble(Assembler::NotEqual, value, &failure);
  5569             masm.unboxDouble(value, FloatReg0);
  5570             masm.clampDoubleToUint8(FloatReg0, secondScratch);
  5571             masm.jump(&clamped);
  5572         } else {
  5573             masm.jump(&failure);
  5575     } else {
  5576         Label notInt32;
  5577         masm.branchTestInt32(Assembler::NotEqual, value, &notInt32);
  5578         masm.unboxInt32(value, secondScratch);
  5580         Label isInt32;
  5581         masm.bind(&isInt32);
  5582         masm.storeToTypedIntArray(type_, secondScratch, dest);
  5583         EmitReturnFromIC(masm);
  5585         // If the value is a double, truncate and jump back.
  5586         // Else, jump to failure.
  5587         Label failureRestoreRegs;
  5588         masm.bind(&notInt32);
  5589         if (cx->runtime()->jitSupportsFloatingPoint) {
  5590             masm.branchTestDouble(Assembler::NotEqual, value, &failure);
  5591             masm.unboxDouble(value, FloatReg0);
  5592             masm.branchTruncateDouble(FloatReg0, secondScratch, &failureRestoreRegs);
  5593             masm.jump(&isInt32);
  5594         } else {
  5595             masm.jump(&failure);
  5598         // Writing to secondScratch may have clobbered R0 or R1, restore them
  5599         // first.
  5600         masm.bind(&failureRestoreRegs);
  5601         masm.tagValue(JSVAL_TYPE_OBJECT, obj, R0);
  5602         masm.tagValue(JSVAL_TYPE_INT32, key, R1);
  5605     // Failure case - jump to next stub
  5606     masm.bind(&failure);
  5607     EmitStubGuardFailure(masm);
  5609     if (expectOutOfBounds_) {
  5610         masm.bind(&oobWrite);
  5611         EmitReturnFromIC(masm);
  5613     return true;
  5616 //
  5617 // In_Fallback
  5618 //
  5620 static bool
  5621 DoInFallback(JSContext *cx, ICIn_Fallback *stub, HandleValue key, HandleValue objValue,
  5622              MutableHandleValue res)
  5624     FallbackICSpew(cx, stub, "In");
  5626     if (!objValue.isObject()) {
  5627         js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, objValue, NullPtr());
  5628         return false;
  5631     RootedObject obj(cx, &objValue.toObject());
  5633     bool cond = false;
  5634     if (!OperatorIn(cx, key, obj, &cond))
  5635         return false;
  5637     res.setBoolean(cond);
  5638     return true;
  5641 typedef bool (*DoInFallbackFn)(JSContext *, ICIn_Fallback *, HandleValue, HandleValue,
  5642                                MutableHandleValue);
  5643 static const VMFunction DoInFallbackInfo =
  5644     FunctionInfo<DoInFallbackFn>(DoInFallback, PopValues(2));
  5646 bool
  5647 ICIn_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  5649     EmitRestoreTailCallReg(masm);
  5651     // Sync for the decompiler.
  5652     masm.pushValue(R0);
  5653     masm.pushValue(R1);
  5655     // Push arguments.
  5656     masm.pushValue(R1);
  5657     masm.pushValue(R0);
  5658     masm.push(BaselineStubReg);
  5660     return tailCallVM(DoInFallbackInfo, masm);
  5663 // Attach an optimized stub for a GETGNAME/CALLGNAME op.
  5664 static bool
  5665 TryAttachGlobalNameStub(JSContext *cx, HandleScript script, jsbytecode *pc,
  5666                         ICGetName_Fallback *stub, HandleObject global,
  5667                         HandlePropertyName name)
  5669     JS_ASSERT(global->is<GlobalObject>());
  5671     RootedId id(cx, NameToId(name));
  5673     // Instantiate this global property, for use during Ion compilation.
  5674     if (IsIonEnabled(cx))
  5675         types::EnsureTrackPropertyTypes(cx, global, NameToId(name));
  5677     // The property must be found, and it must be found as a normal data property.
  5678     RootedShape shape(cx, global->nativeLookup(cx, id));
  5679     if (!shape)
  5680         return true;
  5682     if (shape->hasDefaultGetter() && shape->hasSlot()) {
  5684         JS_ASSERT(shape->slot() >= global->numFixedSlots());
  5685         uint32_t slot = shape->slot() - global->numFixedSlots();
  5687         // TODO: if there's a previous stub discard it, or just update its Shape + slot?
  5689         ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
  5690         IonSpew(IonSpew_BaselineIC, "  Generating GetName(GlobalName) stub");
  5691         ICGetName_Global::Compiler compiler(cx, monitorStub, global->lastProperty(), slot);
  5692         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  5693         if (!newStub)
  5694             return false;
  5696         stub->addNewStub(newStub);
  5697         return true;
  5700     bool isScripted;
  5701     if (IsCacheableGetPropCall(cx, global, global, shape, &isScripted) && !isScripted)
  5703         ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
  5704         IonSpew(IonSpew_BaselineIC, "  Generating GetName(GlobalName/NativeGetter) stub");
  5705         RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
  5706         ICGetProp_CallNative::Compiler compiler(cx, monitorStub, global,
  5707                                                 getter, script->pcToOffset(pc),
  5708                                                 /* inputDefinitelyObject = */ true);
  5709         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  5710         if (!newStub)
  5711             return false;
  5713         stub->addNewStub(newStub);
  5714         return true;
  5717     return true;
  5720 static bool
  5721 TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *stub,
  5722                        HandleObject initialScopeChain, HandlePropertyName name)
  5724     AutoShapeVector shapes(cx);
  5725     RootedId id(cx, NameToId(name));
  5726     RootedObject scopeChain(cx, initialScopeChain);
  5728     Shape *shape = nullptr;
  5729     while (scopeChain) {
  5730         if (!shapes.append(scopeChain->lastProperty()))
  5731             return false;
  5733         if (scopeChain->is<GlobalObject>()) {
  5734             shape = scopeChain->nativeLookup(cx, id);
  5735             if (shape)
  5736                 break;
  5737             return true;
  5740         if (!scopeChain->is<ScopeObject>() || scopeChain->is<DynamicWithObject>())
  5741             return true;
  5743         // Check for an 'own' property on the scope. There is no need to
  5744         // check the prototype as non-with scopes do not inherit properties
  5745         // from any prototype.
  5746         shape = scopeChain->nativeLookup(cx, id);
  5747         if (shape)
  5748             break;
  5750         scopeChain = scopeChain->enclosingScope();
  5753     if (!IsCacheableGetPropReadSlot(scopeChain, scopeChain, shape))
  5754         return true;
  5756     bool isFixedSlot;
  5757     uint32_t offset;
  5758     GetFixedOrDynamicSlotOffset(scopeChain, shape->slot(), &isFixedSlot, &offset);
  5760     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
  5761     ICStub *newStub;
  5763     switch (shapes.length()) {
  5764       case 1: {
  5765         ICGetName_Scope<0>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset);
  5766         newStub = compiler.getStub(compiler.getStubSpace(script));
  5767         break;
  5769       case 2: {
  5770         ICGetName_Scope<1>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset);
  5771         newStub = compiler.getStub(compiler.getStubSpace(script));
  5772         break;
  5774       case 3: {
  5775         ICGetName_Scope<2>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset);
  5776         newStub = compiler.getStub(compiler.getStubSpace(script));
  5777         break;
  5779       case 4: {
  5780         ICGetName_Scope<3>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset);
  5781         newStub = compiler.getStub(compiler.getStubSpace(script));
  5782         break;
  5784       case 5: {
  5785         ICGetName_Scope<4>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset);
  5786         newStub = compiler.getStub(compiler.getStubSpace(script));
  5787         break;
  5789       case 6: {
  5790         ICGetName_Scope<5>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset);
  5791         newStub = compiler.getStub(compiler.getStubSpace(script));
  5792         break;
  5794       case 7: {
  5795         ICGetName_Scope<6>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset);
  5796         newStub = compiler.getStub(compiler.getStubSpace(script));
  5797         break;
  5799       default:
  5800         return true;
  5803     if (!newStub)
  5804         return false;
  5806     stub->addNewStub(newStub);
  5807     return true;
  5810 static bool
  5811 DoGetNameFallback(JSContext *cx, BaselineFrame *frame, ICGetName_Fallback *stub_,
  5812                   HandleObject scopeChain, MutableHandleValue res)
  5814     // This fallback stub may trigger debug mode toggling.
  5815     DebugModeOSRVolatileStub<ICGetName_Fallback *> stub(frame, stub_);
  5817     RootedScript script(cx, frame->script());
  5818     jsbytecode *pc = stub->icEntry()->pc(script);
  5819     mozilla::DebugOnly<JSOp> op = JSOp(*pc);
  5820     FallbackICSpew(cx, stub, "GetName(%s)", js_CodeName[JSOp(*pc)]);
  5822     JS_ASSERT(op == JSOP_NAME || op == JSOP_GETGNAME);
  5824     RootedPropertyName name(cx, script->getName(pc));
  5826     if (JSOp(pc[JSOP_GETGNAME_LENGTH]) == JSOP_TYPEOF) {
  5827         if (!GetScopeNameForTypeOf(cx, scopeChain, name, res))
  5828             return false;
  5829     } else {
  5830         if (!GetScopeName(cx, scopeChain, name, res))
  5831             return false;
  5834     types::TypeScript::Monitor(cx, script, pc, res);
  5836     // Check if debug mode toggling made the stub invalid.
  5837     if (stub.invalid())
  5838         return true;
  5840     // Add a type monitor stub for the resulting value.
  5841     if (!stub->addMonitorStubForValue(cx, script, res))
  5842         return false;
  5844     // Attach new stub.
  5845     if (stub->numOptimizedStubs() >= ICGetName_Fallback::MAX_OPTIMIZED_STUBS) {
  5846         // TODO: Discard all stubs in this IC and replace with generic stub.
  5847         return true;
  5850     if (js_CodeSpec[*pc].format & JOF_GNAME) {
  5851         if (!TryAttachGlobalNameStub(cx, script, pc, stub, scopeChain, name))
  5852             return false;
  5853     } else {
  5854         if (!TryAttachScopeNameStub(cx, script, stub, scopeChain, name))
  5855             return false;
  5858     return true;
  5861 typedef bool (*DoGetNameFallbackFn)(JSContext *, BaselineFrame *, ICGetName_Fallback *,
  5862                                     HandleObject, MutableHandleValue);
  5863 static const VMFunction DoGetNameFallbackInfo = FunctionInfo<DoGetNameFallbackFn>(DoGetNameFallback);
  5865 bool
  5866 ICGetName_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  5868     JS_ASSERT(R0 == JSReturnOperand);
  5870     EmitRestoreTailCallReg(masm);
  5872     masm.push(R0.scratchReg());
  5873     masm.push(BaselineStubReg);
  5874     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  5876     return tailCallVM(DoGetNameFallbackInfo, masm);
  5879 bool
  5880 ICGetName_Global::Compiler::generateStubCode(MacroAssembler &masm)
  5882     Label failure;
  5883     Register obj = R0.scratchReg();
  5884     Register scratch = R1.scratchReg();
  5886     // Shape guard.
  5887     masm.loadPtr(Address(BaselineStubReg, ICGetName_Global::offsetOfShape()), scratch);
  5888     masm.branchTestObjShape(Assembler::NotEqual, obj, scratch, &failure);
  5890     // Load dynamic slot.
  5891     masm.loadPtr(Address(obj, JSObject::offsetOfSlots()), obj);
  5892     masm.load32(Address(BaselineStubReg, ICGetName_Global::offsetOfSlot()), scratch);
  5893     masm.loadValue(BaseIndex(obj, scratch, TimesEight), R0);
  5895     // Enter type monitor IC to type-check result.
  5896     EmitEnterTypeMonitorIC(masm);
  5898     // Failure case - jump to next stub
  5899     masm.bind(&failure);
  5900     EmitStubGuardFailure(masm);
  5901     return true;
  5904 template <size_t NumHops>
  5905 bool
  5906 ICGetName_Scope<NumHops>::Compiler::generateStubCode(MacroAssembler &masm)
  5908     Label failure;
  5909     GeneralRegisterSet regs(availableGeneralRegs(1));
  5910     Register obj = R0.scratchReg();
  5911     Register walker = regs.takeAny();
  5912     Register scratch = regs.takeAny();
  5914     // Use a local to silence Clang tautological-compare warning if NumHops is 0.
  5915     size_t numHops = NumHops;
  5917     for (size_t index = 0; index < NumHops + 1; index++) {
  5918         Register scope = index ? walker : obj;
  5920         // Shape guard.
  5921         masm.loadPtr(Address(BaselineStubReg, ICGetName_Scope::offsetOfShape(index)), scratch);
  5922         masm.branchTestObjShape(Assembler::NotEqual, scope, scratch, &failure);
  5924         if (index < numHops)
  5925             masm.extractObject(Address(scope, ScopeObject::offsetOfEnclosingScope()), walker);
  5928     Register scope = NumHops ? walker : obj;
  5930     if (!isFixedSlot_) {
  5931         masm.loadPtr(Address(scope, JSObject::offsetOfSlots()), walker);
  5932         scope = walker;
  5935     masm.load32(Address(BaselineStubReg, ICGetName_Scope::offsetOfOffset()), scratch);
  5936     masm.loadValue(BaseIndex(scope, scratch, TimesOne), R0);
  5938     // Enter type monitor IC to type-check result.
  5939     EmitEnterTypeMonitorIC(masm);
  5941     // Failure case - jump to next stub
  5942     masm.bind(&failure);
  5943     EmitStubGuardFailure(masm);
  5944     return true;
  5947 //
  5948 // BindName_Fallback
  5949 //
  5951 static bool
  5952 DoBindNameFallback(JSContext *cx, BaselineFrame *frame, ICBindName_Fallback *stub,
  5953                    HandleObject scopeChain, MutableHandleValue res)
  5955     jsbytecode *pc = stub->icEntry()->pc(frame->script());
  5956     mozilla::DebugOnly<JSOp> op = JSOp(*pc);
  5957     FallbackICSpew(cx, stub, "BindName(%s)", js_CodeName[JSOp(*pc)]);
  5959     JS_ASSERT(op == JSOP_BINDNAME);
  5961     RootedPropertyName name(cx, frame->script()->getName(pc));
  5963     RootedObject scope(cx);
  5964     if (!LookupNameWithGlobalDefault(cx, name, scopeChain, &scope))
  5965         return false;
  5967     res.setObject(*scope);
  5968     return true;
  5971 typedef bool (*DoBindNameFallbackFn)(JSContext *, BaselineFrame *, ICBindName_Fallback *,
  5972                                      HandleObject, MutableHandleValue);
  5973 static const VMFunction DoBindNameFallbackInfo =
  5974     FunctionInfo<DoBindNameFallbackFn>(DoBindNameFallback);
  5976 bool
  5977 ICBindName_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  5979     JS_ASSERT(R0 == JSReturnOperand);
  5981     EmitRestoreTailCallReg(masm);
  5983     masm.push(R0.scratchReg());
  5984     masm.push(BaselineStubReg);
  5985     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  5987     return tailCallVM(DoBindNameFallbackInfo, masm);
  5990 //
  5991 // GetIntrinsic_Fallback
  5992 //
  5994 static bool
  5995 DoGetIntrinsicFallback(JSContext *cx, BaselineFrame *frame, ICGetIntrinsic_Fallback *stub_,
  5996                        MutableHandleValue res)
  5998     // This fallback stub may trigger debug mode toggling.
  5999     DebugModeOSRVolatileStub<ICGetIntrinsic_Fallback *> stub(frame, stub_);
  6001     RootedScript script(cx, frame->script());
  6002     jsbytecode *pc = stub->icEntry()->pc(script);
  6003     mozilla::DebugOnly<JSOp> op = JSOp(*pc);
  6004     FallbackICSpew(cx, stub, "GetIntrinsic(%s)", js_CodeName[JSOp(*pc)]);
  6006     JS_ASSERT(op == JSOP_GETINTRINSIC);
  6008     if (!GetIntrinsicOperation(cx, pc, res))
  6009         return false;
  6011     // An intrinsic operation will always produce the same result, so only
  6012     // needs to be monitored once. Attach a stub to load the resulting constant
  6013     // directly.
  6015     types::TypeScript::Monitor(cx, script, pc, res);
  6017     // Check if debug mode toggling made the stub invalid.
  6018     if (stub.invalid())
  6019         return true;
  6021     IonSpew(IonSpew_BaselineIC, "  Generating GetIntrinsic optimized stub");
  6022     ICGetIntrinsic_Constant::Compiler compiler(cx, res);
  6023     ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6024     if (!newStub)
  6025         return false;
  6027     stub->addNewStub(newStub);
  6028     return true;
  6031 typedef bool (*DoGetIntrinsicFallbackFn)(JSContext *, BaselineFrame *, ICGetIntrinsic_Fallback *,
  6032                                          MutableHandleValue);
  6033 static const VMFunction DoGetIntrinsicFallbackInfo =
  6034     FunctionInfo<DoGetIntrinsicFallbackFn>(DoGetIntrinsicFallback);
  6036 bool
  6037 ICGetIntrinsic_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  6039     EmitRestoreTailCallReg(masm);
  6041     masm.push(BaselineStubReg);
  6042     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  6044     return tailCallVM(DoGetIntrinsicFallbackInfo, masm);
  6047 bool
  6048 ICGetIntrinsic_Constant::Compiler::generateStubCode(MacroAssembler &masm)
  6050     masm.loadValue(Address(BaselineStubReg, ICGetIntrinsic_Constant::offsetOfValue()), R0);
  6052     EmitReturnFromIC(masm);
  6053     return true;
  6056 //
  6057 // GetProp_Fallback
  6058 //
  6060 static bool
  6061 TryAttachLengthStub(JSContext *cx, JSScript *script, ICGetProp_Fallback *stub, HandleValue val,
  6062                     HandleValue res, bool *attached)
  6064     JS_ASSERT(!*attached);
  6066     if (val.isString()) {
  6067         JS_ASSERT(res.isInt32());
  6068         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(String.length) stub");
  6069         ICGetProp_StringLength::Compiler compiler(cx);
  6070         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6071         if (!newStub)
  6072             return false;
  6074         *attached = true;
  6075         stub->addNewStub(newStub);
  6076         return true;
  6079     if (val.isMagic(JS_OPTIMIZED_ARGUMENTS) && res.isInt32()) {
  6080         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(MagicArgs.length) stub");
  6081         ICGetProp_ArgumentsLength::Compiler compiler(cx, ICGetProp_ArgumentsLength::Magic);
  6082         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6083         if (!newStub)
  6084             return false;
  6086         *attached = true;
  6087         stub->addNewStub(newStub);
  6088         return true;
  6091     if (!val.isObject())
  6092         return true;
  6094     RootedObject obj(cx, &val.toObject());
  6096     if (obj->is<ArrayObject>() && res.isInt32()) {
  6097         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(Array.length) stub");
  6098         ICGetProp_ArrayLength::Compiler compiler(cx);
  6099         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6100         if (!newStub)
  6101             return false;
  6103         *attached = true;
  6104         stub->addNewStub(newStub);
  6105         return true;
  6108     if (obj->is<TypedArrayObject>() && res.isInt32()) {
  6109         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(TypedArray.length) stub");
  6110         ICGetProp_TypedArrayLength::Compiler compiler(cx);
  6111         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6112         if (!newStub)
  6113             return false;
  6115         *attached = true;
  6116         stub->addNewStub(newStub);
  6117         return true;
  6120     if (obj->is<ArgumentsObject>() && res.isInt32()) {
  6121         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(ArgsObj.length %s) stub",
  6122                 obj->is<StrictArgumentsObject>() ? "Strict" : "Normal");
  6123         ICGetProp_ArgumentsLength::Which which = ICGetProp_ArgumentsLength::Normal;
  6124         if (obj->is<StrictArgumentsObject>())
  6125             which = ICGetProp_ArgumentsLength::Strict;
  6126         ICGetProp_ArgumentsLength::Compiler compiler(cx, which);
  6127         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6128         if (!newStub)
  6129             return false;
  6131         *attached = true;
  6132         stub->addNewStub(newStub);
  6133         return true;
  6136     return true;
  6139 static bool
  6140 UpdateExistingGenerationalDOMProxyStub(ICGetProp_Fallback *stub,
  6141                                        HandleObject obj)
  6143     Value expandoSlot = obj->getFixedSlot(GetDOMProxyExpandoSlot());
  6144     JS_ASSERT(!expandoSlot.isObject() && !expandoSlot.isUndefined());
  6145     ExpandoAndGeneration *expandoAndGeneration = (ExpandoAndGeneration*)expandoSlot.toPrivate();
  6146     for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
  6147         if (iter->isGetProp_CallDOMProxyWithGenerationNative()) {
  6148             ICGetProp_CallDOMProxyWithGenerationNative* updateStub =
  6149                 iter->toGetProp_CallDOMProxyWithGenerationNative();
  6150             if (updateStub->expandoAndGeneration() == expandoAndGeneration) {
  6151                 // Update generation
  6152                 uint32_t generation = expandoAndGeneration->generation;
  6153                 IonSpew(IonSpew_BaselineIC,
  6154                         "  Updating existing stub with generation, old value: %i, "
  6155                         "new value: %i", updateStub->generation(),
  6156                         generation);
  6157                 updateStub->setGeneration(generation);
  6158                 return true;
  6162     return false;
  6165 static bool
  6166 TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
  6167                            ICGetProp_Fallback *stub, HandlePropertyName name,
  6168                            HandleValue val, HandleValue res, bool *attached)
  6170     JS_ASSERT(!*attached);
  6172     if (!val.isObject())
  6173         return true;
  6175     RootedObject obj(cx, &val.toObject());
  6177     bool isDOMProxy;
  6178     bool domProxyHasGeneration;
  6179     DOMProxyShadowsResult domProxyShadowsResult;
  6180     RootedShape shape(cx);
  6181     RootedObject holder(cx);
  6182     if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape, &isDOMProxy,
  6183                                     &domProxyShadowsResult, &domProxyHasGeneration))
  6185         return false;
  6188     if (!isDOMProxy && !obj->isNative())
  6189         return true;
  6191     bool isCallProp = (JSOp(*pc) == JSOP_CALLPROP);
  6193     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
  6194     if (!isDOMProxy && IsCacheableGetPropReadSlot(obj, holder, shape)) {
  6195         bool isFixedSlot;
  6196         uint32_t offset;
  6197         GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
  6199         // Instantiate this property for singleton holders, for use during Ion compilation.
  6200         if (IsIonEnabled(cx))
  6201             types::EnsureTrackPropertyTypes(cx, holder, NameToId(name));
  6203         ICStub::Kind kind = (obj == holder) ? ICStub::GetProp_Native
  6204                                             : ICStub::GetProp_NativePrototype;
  6206         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(%s %s) stub",
  6207                     isDOMProxy ? "DOMProxy" : "Native",
  6208                     (obj == holder) ? "direct" : "prototype");
  6209         ICGetPropNativeCompiler compiler(cx, kind, isCallProp, monitorStub, obj, holder,
  6210                                          name, isFixedSlot, offset);
  6211         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6212         if (!newStub)
  6213             return false;
  6215         stub->addNewStub(newStub);
  6216         *attached = true;
  6217         return true;
  6220     bool isScripted = false;
  6221     bool cacheableCall = IsCacheableGetPropCall(cx, obj, holder, shape, &isScripted, isDOMProxy);
  6223     // Try handling scripted getters.
  6224     if (cacheableCall && isScripted && !isDOMProxy) {
  6225 #if JS_HAS_NO_SUCH_METHOD
  6226         // It's hard to keep the original object alive through a call, and it's unlikely
  6227         // that a getter will be used to generate functions for calling in CALLPROP locations.
  6228         // Just don't attach stubs in that case.
  6229         if (isCallProp)
  6230             return true;
  6231 #endif
  6233         // Don't handle scripted own property getters
  6234         if (obj == holder)
  6235             return true;
  6237         RootedFunction callee(cx, &shape->getterObject()->as<JSFunction>());
  6238         JS_ASSERT(obj != holder);
  6239         JS_ASSERT(callee->hasScript());
  6241         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(NativeObj/ScriptedGetter %s:%d) stub",
  6242                     callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno());
  6244         ICGetProp_CallScripted::Compiler compiler(cx, monitorStub, obj, holder, callee,
  6245                                                   script->pcToOffset(pc));
  6246         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6247         if (!newStub)
  6248             return false;
  6250         stub->addNewStub(newStub);
  6251         *attached = true;
  6252         return true;
  6255     // Try handling JSNative getters.
  6256     if (cacheableCall && !isScripted) {
  6257 #if JS_HAS_NO_SUCH_METHOD
  6258         // It's unlikely that a getter function will be used to generate functions for calling
  6259         // in CALLPROP locations.  Just don't attach stubs in that case to avoid issues with
  6260         // __noSuchMethod__ handling.
  6261         if (isCallProp)
  6262             return true;
  6263 #endif
  6265         RootedFunction callee(cx, &shape->getterObject()->as<JSFunction>());
  6266         JS_ASSERT(callee->isNative());
  6268         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(%s%s/NativeGetter %p) stub",
  6269                 isDOMProxy ? "DOMProxyObj" : "NativeObj",
  6270                 isDOMProxy && domProxyHasGeneration ? "WithGeneration" : "",
  6271                 callee->native());
  6273         ICStub *newStub = nullptr;
  6274         if (isDOMProxy) {
  6275             JS_ASSERT(obj != holder);
  6276             ICStub::Kind kind;
  6277             if (domProxyHasGeneration) {
  6278                 if (UpdateExistingGenerationalDOMProxyStub(stub, obj)) {
  6279                     *attached = true;
  6280                     return true;
  6282                 kind = ICStub::GetProp_CallDOMProxyWithGenerationNative;
  6283             } else {
  6284                 kind = ICStub::GetProp_CallDOMProxyNative;
  6286             Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
  6287             ICGetPropCallDOMProxyNativeCompiler
  6288                 compiler(cx, kind, monitorStub, proxy, holder, callee, script->pcToOffset(pc));
  6289             newStub = compiler.getStub(compiler.getStubSpace(script));
  6290         } else if (obj == holder) {
  6291             ICGetProp_CallNative::Compiler compiler(cx, monitorStub, obj, callee,
  6292                                                     script->pcToOffset(pc));
  6293             newStub = compiler.getStub(compiler.getStubSpace(script));
  6294         } else {
  6295             ICGetProp_CallNativePrototype::Compiler compiler(cx, monitorStub, obj, holder, callee,
  6296                                                              script->pcToOffset(pc));
  6297             newStub = compiler.getStub(compiler.getStubSpace(script));
  6299         if (!newStub)
  6300             return false;
  6301         stub->addNewStub(newStub);
  6302         *attached = true;
  6303         return true;
  6306     // If it's a shadowed listbase proxy property, attach stub to call Proxy::get instead.
  6307     if (isDOMProxy && domProxyShadowsResult == Shadows) {
  6308         JS_ASSERT(obj == holder);
  6309 #if JS_HAS_NO_SUCH_METHOD
  6310         if (isCallProp)
  6311             return true;
  6312 #endif
  6314         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(DOMProxyProxy) stub");
  6315         Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
  6316         ICGetProp_DOMProxyShadowed::Compiler compiler(cx, monitorStub, proxy, name,
  6317                                                       script->pcToOffset(pc));
  6318         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6319         if (!newStub)
  6320             return false;
  6321         stub->addNewStub(newStub);
  6322         *attached = true;
  6323         return true;
  6326     return true;
  6329 static bool
  6330 TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
  6331                               ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
  6332                               HandleValue res, bool *attached)
  6334     JS_ASSERT(!*attached);
  6336     JSValueType primitiveType;
  6337     RootedObject proto(cx);
  6338     Rooted<GlobalObject*> global(cx, &script->global());
  6339     if (val.isString()) {
  6340         primitiveType = JSVAL_TYPE_STRING;
  6341         proto = GlobalObject::getOrCreateStringPrototype(cx, global);
  6342     } else if (val.isNumber()) {
  6343         primitiveType = JSVAL_TYPE_DOUBLE;
  6344         proto = GlobalObject::getOrCreateNumberPrototype(cx, global);
  6345     } else {
  6346         JS_ASSERT(val.isBoolean());
  6347         primitiveType = JSVAL_TYPE_BOOLEAN;
  6348         proto = GlobalObject::getOrCreateBooleanPrototype(cx, global);
  6350     if (!proto)
  6351         return false;
  6353     // Instantiate this property, for use during Ion compilation.
  6354     RootedId id(cx, NameToId(name));
  6355     if (IsIonEnabled(cx))
  6356         types::EnsureTrackPropertyTypes(cx, proto, id);
  6358     // For now, only look for properties directly set on the prototype.
  6359     RootedShape shape(cx, proto->nativeLookup(cx, id));
  6360     if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter())
  6361         return true;
  6363     bool isFixedSlot;
  6364     uint32_t offset;
  6365     GetFixedOrDynamicSlotOffset(proto, shape->slot(), &isFixedSlot, &offset);
  6367     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
  6369     IonSpew(IonSpew_BaselineIC, "  Generating GetProp_Primitive stub");
  6370     ICGetProp_Primitive::Compiler compiler(cx, monitorStub, primitiveType, proto,
  6371                                            isFixedSlot, offset);
  6372     ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  6373     if (!newStub)
  6374         return false;
  6376     stub->addNewStub(newStub);
  6377     *attached = true;
  6378     return true;
  6381 static bool
  6382 DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_,
  6383                   MutableHandleValue val, MutableHandleValue res)
  6385     // This fallback stub may trigger debug mode toggling.
  6386     DebugModeOSRVolatileStub<ICGetProp_Fallback *> stub(frame, stub_);
  6388     jsbytecode *pc = stub->icEntry()->pc(frame->script());
  6389     JSOp op = JSOp(*pc);
  6390     FallbackICSpew(cx, stub, "GetProp(%s)", js_CodeName[op]);
  6392     JS_ASSERT(op == JSOP_GETPROP || op == JSOP_CALLPROP || op == JSOP_LENGTH || op == JSOP_GETXPROP);
  6394     RootedPropertyName name(cx, frame->script()->getName(pc));
  6396     if (op == JSOP_LENGTH && val.isMagic(JS_OPTIMIZED_ARGUMENTS)) {
  6397         // Handle arguments.length access.
  6398         if (IsOptimizedArguments(frame, val.address())) {
  6399             res.setInt32(frame->numActualArgs());
  6401             // Monitor result
  6402             types::TypeScript::Monitor(cx, frame->script(), pc, res);
  6403             if (!stub->addMonitorStubForValue(cx, frame->script(), res))
  6404                 return false;
  6406             bool attached = false;
  6407             if (!TryAttachLengthStub(cx, frame->script(), stub, val, res, &attached))
  6408                 return false;
  6409             JS_ASSERT(attached);
  6411             return true;
  6415     RootedObject obj(cx, ToObjectFromStack(cx, val));
  6416     if (!obj)
  6417         return false;
  6419     RootedId id(cx, NameToId(name));
  6420     if (!JSObject::getGeneric(cx, obj, obj, id, res))
  6421         return false;
  6423 #if JS_HAS_NO_SUCH_METHOD
  6424     // Handle objects with __noSuchMethod__.
  6425     if (op == JSOP_CALLPROP && MOZ_UNLIKELY(res.isUndefined()) && val.isObject()) {
  6426         if (!OnUnknownMethod(cx, obj, IdToValue(id), res))
  6427             return false;
  6429 #endif
  6431     types::TypeScript::Monitor(cx, frame->script(), pc, res);
  6433     // Check if debug mode toggling made the stub invalid.
  6434     if (stub.invalid())
  6435         return true;
  6437     // Add a type monitor stub for the resulting value.
  6438     if (!stub->addMonitorStubForValue(cx, frame->script(), res))
  6439         return false;
  6441     if (stub->numOptimizedStubs() >= ICGetProp_Fallback::MAX_OPTIMIZED_STUBS) {
  6442         // TODO: Discard all stubs in this IC and replace with generic getprop stub.
  6443         return true;
  6446     bool attached = false;
  6448     if (op == JSOP_LENGTH) {
  6449         if (!TryAttachLengthStub(cx, frame->script(), stub, val, res, &attached))
  6450             return false;
  6451         if (attached)
  6452             return true;
  6455     RootedScript script(cx, frame->script());
  6457     if (!TryAttachNativeGetPropStub(cx, script, pc, stub, name, val, res, &attached))
  6458         return false;
  6459     if (attached)
  6460         return true;
  6462     if (val.isString() || val.isNumber() || val.isBoolean()) {
  6463         if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
  6464             return false;
  6465         if (attached)
  6466             return true;
  6469     JS_ASSERT(!attached);
  6470     stub->noteUnoptimizableAccess();
  6472     return true;
  6475 typedef bool (*DoGetPropFallbackFn)(JSContext *, BaselineFrame *, ICGetProp_Fallback *,
  6476                                     MutableHandleValue, MutableHandleValue);
  6477 static const VMFunction DoGetPropFallbackInfo =
  6478     FunctionInfo<DoGetPropFallbackFn>(DoGetPropFallback, PopValues(1));
  6480 bool
  6481 ICGetProp_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  6483     JS_ASSERT(R0 == JSReturnOperand);
  6485     EmitRestoreTailCallReg(masm);
  6487     // Ensure stack is fully synced for the expression decompiler.
  6488     masm.pushValue(R0);
  6490     // Push arguments.
  6491     masm.pushValue(R0);
  6492     masm.push(BaselineStubReg);
  6493     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  6495     if (!tailCallVM(DoGetPropFallbackInfo, masm))
  6496         return false;
  6498     // What follows is bailout for inlined scripted getters or for on-stack
  6499     // debug mode recompile. The return address pointed to by the baseline
  6500     // stack points here.
  6501     //
  6502     // Even though the fallback frame doesn't enter a stub frame, the CallScripted
  6503     // frame that we are emulating does. Again, we lie.
  6504 #ifdef DEBUG
  6505     entersStubFrame_ = true;
  6506 #endif
  6508     Label leaveStubCommon;
  6510     returnFromStubOffset_ = masm.currentOffset();
  6511     leaveStubFrameHead(masm, false);
  6512     masm.jump(&leaveStubCommon);
  6514     returnFromIonOffset_ = masm.currentOffset();
  6515     leaveStubFrameHead(masm, true);
  6517     masm.bind(&leaveStubCommon);
  6518     leaveStubFrameCommonTail(masm);
  6520     // When we get here, BaselineStubReg contains the ICGetProp_Fallback stub,
  6521     // which we can't use to enter the TypeMonitor IC, because it's a MonitoredFallbackStub
  6522     // instead of a MonitoredStub. So, we cheat.
  6523     masm.loadPtr(Address(BaselineStubReg, ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()),
  6524                  BaselineStubReg);
  6525     EmitEnterTypeMonitorIC(masm, ICTypeMonitor_Fallback::offsetOfFirstMonitorStub());
  6527     return true;
  6530 bool
  6531 ICGetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code)
  6533     JitCompartment *comp = cx->compartment()->jitCompartment();
  6535     CodeOffsetLabel fromIon(returnFromIonOffset_);
  6536     fromIon.fixup(&masm);
  6537     comp->initBaselineGetPropReturnFromIonAddr(code->raw() + fromIon.offset());
  6539     CodeOffsetLabel fromVM(returnFromStubOffset_);
  6540     fromVM.fixup(&masm);
  6541     comp->initBaselineGetPropReturnFromStubAddr(code->raw() + fromVM.offset());
  6543     return true;
  6546 bool
  6547 ICGetProp_ArrayLength::Compiler::generateStubCode(MacroAssembler &masm)
  6549     Label failure;
  6550     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  6552     Register scratch = R1.scratchReg();
  6554     // Unbox R0 and guard it's an array.
  6555     Register obj = masm.extractObject(R0, ExtractTemp0);
  6556     masm.branchTestObjClass(Assembler::NotEqual, obj, scratch, &ArrayObject::class_, &failure);
  6558     // Load obj->elements->length.
  6559     masm.loadPtr(Address(obj, JSObject::offsetOfElements()), scratch);
  6560     masm.load32(Address(scratch, ObjectElements::offsetOfLength()), scratch);
  6562     // Guard length fits in an int32.
  6563     masm.branchTest32(Assembler::Signed, scratch, scratch, &failure);
  6565     masm.tagValue(JSVAL_TYPE_INT32, scratch, R0);
  6566     EmitReturnFromIC(masm);
  6568     // Failure case - jump to next stub
  6569     masm.bind(&failure);
  6570     EmitStubGuardFailure(masm);
  6571     return true;
  6574 bool
  6575 ICGetProp_TypedArrayLength::Compiler::generateStubCode(MacroAssembler &masm)
  6577     Label failure;
  6578     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  6580     Register scratch = R1.scratchReg();
  6582     // Unbox R0.
  6583     Register obj = masm.extractObject(R0, ExtractTemp0);
  6585     // Implement the negated version of JSObject::isTypedArray predicate.
  6586     masm.loadObjClass(obj, scratch);
  6587     masm.branchPtr(Assembler::Below, scratch, ImmPtr(&TypedArrayObject::classes[0]),
  6588                    &failure);
  6589     masm.branchPtr(Assembler::AboveOrEqual, scratch,
  6590                    ImmPtr(&TypedArrayObject::classes[ScalarTypeDescr::TYPE_MAX]),
  6591                    &failure);
  6593     // Load length from fixed slot.
  6594     masm.loadValue(Address(obj, TypedArrayObject::lengthOffset()), R0);
  6595     EmitReturnFromIC(masm);
  6597     // Failure case - jump to next stub
  6598     masm.bind(&failure);
  6599     EmitStubGuardFailure(masm);
  6600     return true;
  6603 bool
  6604 ICGetProp_StringLength::Compiler::generateStubCode(MacroAssembler &masm)
  6606     Label failure;
  6607     masm.branchTestString(Assembler::NotEqual, R0, &failure);
  6609     // Unbox string and load its length.
  6610     Register string = masm.extractString(R0, ExtractTemp0);
  6611     masm.loadStringLength(string, string);
  6613     masm.tagValue(JSVAL_TYPE_INT32, string, R0);
  6614     EmitReturnFromIC(masm);
  6616     // Failure case - jump to next stub
  6617     masm.bind(&failure);
  6618     EmitStubGuardFailure(masm);
  6619     return true;
  6622 bool
  6623 ICGetProp_Primitive::Compiler::generateStubCode(MacroAssembler &masm)
  6625     Label failure;
  6626     switch (primitiveType_) {
  6627       case JSVAL_TYPE_STRING:
  6628         masm.branchTestString(Assembler::NotEqual, R0, &failure);
  6629         break;
  6630       case JSVAL_TYPE_DOUBLE: // Also used for int32.
  6631         masm.branchTestNumber(Assembler::NotEqual, R0, &failure);
  6632         break;
  6633       case JSVAL_TYPE_BOOLEAN:
  6634         masm.branchTestBoolean(Assembler::NotEqual, R0, &failure);
  6635         break;
  6636       default:
  6637         MOZ_ASSUME_UNREACHABLE("unexpected type");
  6640     GeneralRegisterSet regs(availableGeneralRegs(1));
  6641     Register holderReg = regs.takeAny();
  6642     Register scratchReg = regs.takeAny();
  6644     // Verify the shape of the prototype.
  6645     masm.movePtr(ImmGCPtr(prototype_.get()), holderReg);
  6647     Address shapeAddr(BaselineStubReg, ICGetProp_Primitive::offsetOfProtoShape());
  6648     masm.loadPtr(Address(holderReg, JSObject::offsetOfShape()), scratchReg);
  6649     masm.branchPtr(Assembler::NotEqual, shapeAddr, scratchReg, &failure);
  6651     if (!isFixedSlot_)
  6652         masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), holderReg);
  6654     masm.load32(Address(BaselineStubReg, ICGetPropNativeStub::offsetOfOffset()), scratchReg);
  6655     masm.loadValue(BaseIndex(holderReg, scratchReg, TimesOne), R0);
  6657     // Enter type monitor IC to type-check result.
  6658     EmitEnterTypeMonitorIC(masm);
  6660     // Failure case - jump to next stub
  6661     masm.bind(&failure);
  6662     EmitStubGuardFailure(masm);
  6663     return true;
  6666 bool
  6667 ICGetPropNativeCompiler::generateStubCode(MacroAssembler &masm)
  6669     Label failure;
  6670     GeneralRegisterSet regs(availableGeneralRegs(1));
  6672     // Guard input is an object.
  6673     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  6675     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
  6677     // Unbox and shape guard.
  6678     Register objReg = masm.extractObject(R0, ExtractTemp0);
  6679     masm.loadPtr(Address(BaselineStubReg, ICGetPropNativeStub::offsetOfShape()), scratch);
  6680     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
  6682     Register holderReg;
  6683     if (obj_ == holder_) {
  6684         holderReg = objReg;
  6685     } else {
  6686         // Shape guard holder.
  6687         holderReg = regs.takeAny();
  6688         masm.loadPtr(Address(BaselineStubReg, ICGetProp_NativePrototype::offsetOfHolder()),
  6689                      holderReg);
  6690         masm.loadPtr(Address(BaselineStubReg, ICGetProp_NativePrototype::offsetOfHolderShape()),
  6691                      scratch);
  6692         masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure);
  6695     if (!isFixedSlot_) {
  6696         // Don't overwrite actual holderReg if we need to load a dynamic slots object.
  6697         // May need to preserve object for noSuchMethod check later.
  6698         Register nextHolder = regs.takeAny();
  6699         masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), nextHolder);
  6700         holderReg = nextHolder;
  6703     masm.load32(Address(BaselineStubReg, ICGetPropNativeStub::offsetOfOffset()), scratch);
  6704     BaseIndex result(holderReg, scratch, TimesOne);
  6706 #if JS_HAS_NO_SUCH_METHOD
  6707 #ifdef DEBUG
  6708     entersStubFrame_ = true;
  6709 #endif
  6710     if (isCallProp_) {
  6711         // Check for __noSuchMethod__ invocation.
  6712         Label afterNoSuchMethod;
  6713         Label skipNoSuchMethod;
  6715         masm.push(objReg);
  6716         masm.loadValue(result, R0);
  6717         masm.branchTestUndefined(Assembler::NotEqual, R0, &skipNoSuchMethod);
  6719         masm.pop(objReg);
  6721         // Call __noSuchMethod__ checker.  Object pointer is in objReg.
  6722         regs = availableGeneralRegs(0);
  6723         regs.takeUnchecked(objReg);
  6724         regs.takeUnchecked(BaselineTailCallReg);
  6725         ValueOperand val = regs.takeValueOperand();
  6727         // Box and push obj onto baseline frame stack for decompiler.
  6728         EmitRestoreTailCallReg(masm);
  6729         masm.tagValue(JSVAL_TYPE_OBJECT, objReg, val);
  6730         masm.pushValue(val);
  6731         EmitRepushTailCallReg(masm);
  6733         enterStubFrame(masm, regs.getAnyExcluding(BaselineTailCallReg));
  6735         masm.movePtr(ImmGCPtr(propName_.get()), val.scratchReg());
  6736         masm.tagValue(JSVAL_TYPE_STRING, val.scratchReg(), val);
  6737         masm.pushValue(val);
  6738         masm.push(objReg);
  6739         if (!callVM(LookupNoSuchMethodHandlerInfo, masm))
  6740             return false;
  6742         leaveStubFrame(masm);
  6744         // Pop pushed obj from baseline stack.
  6745         EmitUnstowICValues(masm, 1, /* discard = */ true);
  6747         masm.jump(&afterNoSuchMethod);
  6748         masm.bind(&skipNoSuchMethod);
  6750         // Pop pushed objReg.
  6751         masm.addPtr(Imm32(sizeof(void *)), BaselineStackReg);
  6752         masm.bind(&afterNoSuchMethod);
  6753     } else {
  6754         masm.loadValue(result, R0);
  6756 #else
  6757     masm.loadValue(result, R0);
  6758 #endif
  6760     // Enter type monitor IC to type-check result.
  6761     EmitEnterTypeMonitorIC(masm);
  6763     // Failure case - jump to next stub
  6764     masm.bind(&failure);
  6765     EmitStubGuardFailure(masm);
  6766     return true;
  6769 bool
  6770 ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
  6772     Label failure;
  6773     Label failureLeaveStubFrame;
  6774     GeneralRegisterSet regs(availableGeneralRegs(1));
  6775     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
  6777     // Guard input is an object.
  6778     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  6780     // Unbox and shape guard.
  6781     Register objReg = masm.extractObject(R0, ExtractTemp0);
  6782     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallScripted::offsetOfReceiverShape()), scratch);
  6783     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
  6785     Register holderReg = regs.takeAny();
  6786     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallScripted::offsetOfHolder()), holderReg);
  6787     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallScripted::offsetOfHolderShape()), scratch);
  6788     masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure);
  6789     regs.add(holderReg);
  6791     // Push a stub frame so that we can perform a non-tail call.
  6792     enterStubFrame(masm, scratch);
  6794     // Load callee function and code.  To ensure that |code| doesn't end up being
  6795     // ArgumentsRectifierReg, if it's available we assign it to |callee| instead.
  6796     Register callee;
  6797     if (regs.has(ArgumentsRectifierReg)) {
  6798         callee = ArgumentsRectifierReg;
  6799         regs.take(callee);
  6800     } else {
  6801         callee = regs.takeAny();
  6803     Register code = regs.takeAny();
  6804     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallScripted::offsetOfGetter()), callee);
  6805     masm.branchIfFunctionHasNoScript(callee, &failureLeaveStubFrame);
  6806     masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
  6807     masm.loadBaselineOrIonRaw(code, code, SequentialExecution, &failureLeaveStubFrame);
  6809     // Getter is called with 0 arguments, just |obj| as thisv.
  6810     // Note that we use Push, not push, so that callIon will align the stack
  6811     // properly on ARM.
  6812     masm.Push(R0);
  6813     EmitCreateStubFrameDescriptor(masm, scratch);
  6814     masm.Push(Imm32(0));  // ActualArgc is 0
  6815     masm.Push(callee);
  6816     masm.Push(scratch);
  6818     // Handle arguments underflow.
  6819     Label noUnderflow;
  6820     masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
  6821     masm.branch32(Assembler::Equal, scratch, Imm32(0), &noUnderflow);
  6823         // Call the arguments rectifier.
  6824         JS_ASSERT(ArgumentsRectifierReg != code);
  6826         JitCode *argumentsRectifier =
  6827             cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
  6829         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
  6830         masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
  6831         masm.mov(ImmWord(0), ArgumentsRectifierReg);
  6834     masm.bind(&noUnderflow);
  6836     // If needed, update SPS Profiler frame entry.  At this point, callee and scratch can
  6837     // be clobbered.
  6839         GeneralRegisterSet availRegs = availableGeneralRegs(0);
  6840         availRegs.take(ArgumentsRectifierReg);
  6841         availRegs.take(code);
  6842         emitProfilingUpdate(masm, availRegs, ICGetProp_CallScripted::offsetOfPCOffset());
  6845     masm.callIon(code);
  6847     leaveStubFrame(masm, true);
  6849     // Enter type monitor IC to type-check result.
  6850     EmitEnterTypeMonitorIC(masm);
  6852     // Leave stub frame and go to next stub.
  6853     masm.bind(&failureLeaveStubFrame);
  6854     leaveStubFrame(masm, false);
  6856     // Failure case - jump to next stub
  6857     masm.bind(&failure);
  6858     EmitStubGuardFailure(masm);
  6859     return true;
  6862 bool
  6863 ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
  6865     Label failure;
  6867     GeneralRegisterSet regs(availableGeneralRegs(0));
  6868     Register obj = InvalidReg;
  6869     if (inputDefinitelyObject_) {
  6870         obj = R0.scratchReg();
  6871     } else {
  6872         regs.take(R0);
  6873         masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  6874         obj = masm.extractObject(R0, ExtractTemp0);
  6876     regs.takeUnchecked(obj);
  6878     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
  6880     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNative::offsetOfHolderShape()), scratch);
  6881     masm.branchTestObjShape(Assembler::NotEqual, obj, scratch, &failure);
  6883     enterStubFrame(masm, scratch);
  6885     masm.Push(obj);
  6887     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNative::offsetOfGetter()), scratch);
  6888     masm.Push(scratch);
  6890     regs.add(scratch);
  6891     if (!inputDefinitelyObject_)
  6892         regs.add(R0);
  6894     // If needed, update SPS Profiler frame entry.
  6895     emitProfilingUpdate(masm, regs, ICGetProp_CallNative::offsetOfPCOffset());
  6897     if (!callVM(DoCallNativeGetterInfo, masm))
  6898         return false;
  6899     leaveStubFrame(masm);
  6901     EmitEnterTypeMonitorIC(masm);
  6903     masm.bind(&failure);
  6904     EmitStubGuardFailure(masm);
  6906     return true;
  6909 bool
  6910 ICGetProp_CallNativePrototype::Compiler::generateStubCode(MacroAssembler &masm)
  6912     Label failure;
  6913     GeneralRegisterSet regs(availableGeneralRegs(1));
  6914     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
  6916     // Guard input is an object.
  6917     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  6919     // Unbox and shape guard.
  6920     Register objReg = masm.extractObject(R0, ExtractTemp0);
  6921     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNativePrototype::offsetOfReceiverShape()), scratch);
  6922     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
  6924     Register holderReg = regs.takeAny();
  6925     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNativePrototype::offsetOfHolder()), holderReg);
  6926     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNativePrototype::offsetOfHolderShape()), scratch);
  6927     masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure);
  6928     regs.add(holderReg);
  6930     // Push a stub frame so that we can perform a non-tail call.
  6931     enterStubFrame(masm, scratch);
  6933     // Load callee function.
  6934     Register callee = regs.takeAny();
  6935     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNativePrototype::offsetOfGetter()), callee);
  6937     // Push args for vm call.
  6938     masm.push(objReg);
  6939     masm.push(callee);
  6941     // Don't to preserve R0 anymore.
  6942     regs.add(R0);
  6944     // If needed, update SPS Profiler frame entry.
  6945     emitProfilingUpdate(masm, regs, ICGetProp_CallNativePrototype::offsetOfPCOffset());
  6947     if (!callVM(DoCallNativeGetterInfo, masm))
  6948         return false;
  6949     leaveStubFrame(masm);
  6951     // Enter type monitor IC to type-check result.
  6952     EmitEnterTypeMonitorIC(masm);
  6954     // Failure case - jump to next stub
  6955     masm.bind(&failure);
  6956     EmitStubGuardFailure(masm);
  6957     return true;
  6960 bool
  6961 ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler &masm,
  6962                                                       Address* expandoAndGenerationAddr,
  6963                                                       Address* generationAddr)
  6965     Label failure;
  6966     GeneralRegisterSet regs(availableGeneralRegs(1));
  6967     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
  6969     // Guard input is an object.
  6970     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  6972     // Unbox.
  6973     Register objReg = masm.extractObject(R0, ExtractTemp0);
  6975     // Shape guard.
  6976     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfShape()), scratch);
  6977     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
  6979     // Guard for ListObject.
  6981         GeneralRegisterSet domProxyRegSet(GeneralRegisterSet::All());
  6982         domProxyRegSet.take(BaselineStubReg);
  6983         domProxyRegSet.take(objReg);
  6984         domProxyRegSet.take(scratch);
  6985         Address expandoShapeAddr(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfExpandoShape());
  6986         GenerateDOMProxyChecks(
  6987                 cx, masm, objReg,
  6988                 Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfProxyHandler()),
  6989                 &expandoShapeAddr, expandoAndGenerationAddr, generationAddr,
  6990                 scratch,
  6991                 domProxyRegSet,
  6992                 &failure);
  6995     Register holderReg = regs.takeAny();
  6996     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfHolder()),
  6997                  holderReg);
  6998     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfHolderShape()),
  6999                  scratch);
  7000     masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure);
  7001     regs.add(holderReg);
  7003     // Push a stub frame so that we can perform a non-tail call.
  7004     enterStubFrame(masm, scratch);
  7006     // Load callee function.
  7007     Register callee = regs.takeAny();
  7008     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallDOMProxyNative::offsetOfGetter()), callee);
  7010     // Push args for vm call.
  7011     masm.push(objReg);
  7012     masm.push(callee);
  7014     // Don't have to preserve R0 anymore.
  7015     regs.add(R0);
  7017     // If needed, update SPS Profiler frame entry.
  7018     emitProfilingUpdate(masm, regs, ICGetProp_CallDOMProxyNative::offsetOfPCOffset());
  7020     if (!callVM(DoCallNativeGetterInfo, masm))
  7021         return false;
  7022     leaveStubFrame(masm);
  7024     // Enter type monitor IC to type-check result.
  7025     EmitEnterTypeMonitorIC(masm);
  7027     // Failure case - jump to next stub
  7028     masm.bind(&failure);
  7029     EmitStubGuardFailure(masm);
  7030     return true;
  7033 bool
  7034 ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler &masm)
  7036     if (kind == ICStub::GetProp_CallDOMProxyNative)
  7037         return generateStubCode(masm, nullptr, nullptr);
  7039     Address internalStructAddress(BaselineStubReg,
  7040         ICGetProp_CallDOMProxyWithGenerationNative::offsetOfInternalStruct());
  7041     Address generationAddress(BaselineStubReg,
  7042         ICGetProp_CallDOMProxyWithGenerationNative::offsetOfGeneration());
  7043     return generateStubCode(masm, &internalStructAddress, &generationAddress);
  7046 ICStub *
  7047 ICGetPropCallDOMProxyNativeCompiler::getStub(ICStubSpace *space)
  7049     RootedShape shape(cx, proxy_->lastProperty());
  7050     RootedShape holderShape(cx, holder_->lastProperty());
  7052     Value expandoSlot = proxy_->getFixedSlot(GetDOMProxyExpandoSlot());
  7053     RootedShape expandoShape(cx, nullptr);
  7054     ExpandoAndGeneration *expandoAndGeneration;
  7055     int32_t generation;
  7056     Value expandoVal;
  7057     if (kind == ICStub::GetProp_CallDOMProxyNative) {
  7058         expandoVal = expandoSlot;
  7059     } else {
  7060         JS_ASSERT(kind == ICStub::GetProp_CallDOMProxyWithGenerationNative);
  7061         JS_ASSERT(!expandoSlot.isObject() && !expandoSlot.isUndefined());
  7062         expandoAndGeneration = (ExpandoAndGeneration*)expandoSlot.toPrivate();
  7063         expandoVal = expandoAndGeneration->expando;
  7064         generation = expandoAndGeneration->generation;
  7067     if (expandoVal.isObject())
  7068         expandoShape = expandoVal.toObject().lastProperty();
  7070     if (kind == ICStub::GetProp_CallDOMProxyNative) {
  7071         return ICGetProp_CallDOMProxyNative::New(
  7072             space, getStubCode(), firstMonitorStub_, shape, proxy_->handler(),
  7073             expandoShape, holder_, holderShape, getter_, pcOffset_);
  7076     return ICGetProp_CallDOMProxyWithGenerationNative::New(
  7077         space, getStubCode(), firstMonitorStub_, shape, proxy_->handler(),
  7078         expandoAndGeneration, generation, expandoShape, holder_, holderShape, getter_,
  7079         pcOffset_);
  7082 ICStub *
  7083 ICGetProp_DOMProxyShadowed::Compiler::getStub(ICStubSpace *space)
  7085     RootedShape shape(cx, proxy_->lastProperty());
  7086     return ICGetProp_DOMProxyShadowed::New(space, getStubCode(), firstMonitorStub_, shape,
  7087                                            proxy_->handler(), name_, pcOffset_);
  7090 static bool
  7091 ProxyGet(JSContext *cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp)
  7093     RootedId id(cx, NameToId(name));
  7094     return Proxy::get(cx, proxy, proxy, id, vp);
  7097 typedef bool (*ProxyGetFn)(JSContext *cx, HandleObject proxy, HandlePropertyName name,
  7098                            MutableHandleValue vp);
  7099 static const VMFunction ProxyGetInfo = FunctionInfo<ProxyGetFn>(ProxyGet);
  7101 bool
  7102 ICGetProp_DOMProxyShadowed::Compiler::generateStubCode(MacroAssembler &masm)
  7104     Label failure;
  7106     GeneralRegisterSet regs(availableGeneralRegs(1));
  7107     // Need to reserve a scratch register, but the scratch register should not be
  7108     // BaselineTailCallReg, because it's used for |enterStubFrame| which needs a
  7109     // non-BaselineTailCallReg scratch reg.
  7110     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
  7112     // Guard input is an object.
  7113     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  7115     // Unbox.
  7116     Register objReg = masm.extractObject(R0, ExtractTemp0);
  7118     // Shape guard.
  7119     masm.loadPtr(Address(BaselineStubReg, ICGetProp_DOMProxyShadowed::offsetOfShape()), scratch);
  7120     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
  7122     // Guard for ListObject.
  7124         GeneralRegisterSet domProxyRegSet(GeneralRegisterSet::All());
  7125         domProxyRegSet.take(BaselineStubReg);
  7126         domProxyRegSet.take(objReg);
  7127         domProxyRegSet.take(scratch);
  7128         GenerateDOMProxyChecks(
  7129                 cx, masm, objReg,
  7130                 Address(BaselineStubReg, ICGetProp_DOMProxyShadowed::offsetOfProxyHandler()),
  7131                 /*expandoShapeAddr=*/nullptr,
  7132                 /*expandoAndGenerationAddr=*/nullptr,
  7133                 /*generationAddr=*/nullptr,
  7134                 scratch,
  7135                 domProxyRegSet,
  7136                 &failure);
  7139     // Call ProxyGet(JSContext *cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp);
  7141     // Push a stub frame so that we can perform a non-tail call.
  7142     enterStubFrame(masm, scratch);
  7144     // Push property name and proxy object.
  7145     masm.loadPtr(Address(BaselineStubReg, ICGetProp_DOMProxyShadowed::offsetOfName()), scratch);
  7146     masm.push(scratch);
  7147     masm.push(objReg);
  7149     // Don't have to preserve R0 anymore.
  7150     regs.add(R0);
  7152     // If needed, update SPS Profiler frame entry.
  7153     emitProfilingUpdate(masm, regs, ICGetProp_DOMProxyShadowed::offsetOfPCOffset());
  7155     if (!callVM(ProxyGetInfo, masm))
  7156         return false;
  7157     leaveStubFrame(masm);
  7159     // Enter type monitor IC to type-check result.
  7160     EmitEnterTypeMonitorIC(masm);
  7162     // Failure case - jump to next stub
  7163     masm.bind(&failure);
  7164     EmitStubGuardFailure(masm);
  7165     return true;
  7168 bool
  7169 ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler &masm)
  7171     Label failure;
  7172     if (which_ == ICGetProp_ArgumentsLength::Magic) {
  7173         // Ensure that this is lazy arguments.
  7174         masm.branchTestMagicValue(Assembler::NotEqual, R0, JS_OPTIMIZED_ARGUMENTS, &failure);
  7176         // Ensure that frame has not loaded different arguments object since.
  7177         masm.branchTest32(Assembler::NonZero,
  7178                           Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()),
  7179                           Imm32(BaselineFrame::HAS_ARGS_OBJ),
  7180                           &failure);
  7182         Address actualArgs(BaselineFrameReg, BaselineFrame::offsetOfNumActualArgs());
  7183         masm.loadPtr(actualArgs, R0.scratchReg());
  7184         masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0);
  7185         EmitReturnFromIC(masm);
  7187         masm.bind(&failure);
  7188         EmitStubGuardFailure(masm);
  7189         return true;
  7191     JS_ASSERT(which_ == ICGetProp_ArgumentsLength::Strict ||
  7192               which_ == ICGetProp_ArgumentsLength::Normal);
  7194     bool isStrict = which_ == ICGetProp_ArgumentsLength::Strict;
  7195     const Class *clasp = isStrict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_;
  7197     Register scratchReg = R1.scratchReg();
  7199     // Guard on input being an arguments object.
  7200     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  7201     Register objReg = masm.extractObject(R0, ExtractTemp0);
  7202     masm.branchTestObjClass(Assembler::NotEqual, objReg, scratchReg, clasp, &failure);
  7204     // Get initial length value.
  7205     masm.unboxInt32(Address(objReg, ArgumentsObject::getInitialLengthSlotOffset()), scratchReg);
  7207     // Test if length has been overridden.
  7208     masm.branchTest32(Assembler::NonZero,
  7209                       scratchReg,
  7210                       Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT),
  7211                       &failure);
  7213     // Nope, shift out arguments length and return it.
  7214     // No need to type monitor because this stub always returns Int32.
  7215     masm.rshiftPtr(Imm32(ArgumentsObject::PACKED_BITS_COUNT), scratchReg);
  7216     masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
  7217     EmitReturnFromIC(masm);
  7219     masm.bind(&failure);
  7220     EmitStubGuardFailure(masm);
  7221     return true;
  7224 void
  7225 BaselineScript::noteAccessedGetter(uint32_t pcOffset)
  7227     ICEntry &entry = icEntryFromPCOffset(pcOffset);
  7228     ICFallbackStub *stub = entry.fallbackStub();
  7230     if (stub->isGetProp_Fallback())
  7231         stub->toGetProp_Fallback()->noteAccessedGetter();
  7234 //
  7235 // SetProp_Fallback
  7236 //
  7238 // Attach an optimized stub for a SETPROP/SETGNAME/SETNAME op.
  7239 static bool
  7240 TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetProp_Fallback *stub,
  7241                      HandleObject obj, HandleShape oldShape, uint32_t oldSlots,
  7242                      HandlePropertyName name, HandleId id, HandleValue rhs, bool *attached)
  7244     JS_ASSERT(!*attached);
  7246     if (!obj->isNative() || obj->watched())
  7247         return true;
  7249     RootedShape shape(cx);
  7250     RootedObject holder(cx);
  7251     if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape))
  7252         return false;
  7254     size_t chainDepth;
  7255     if (IsCacheableSetPropAddSlot(cx, obj, oldShape, oldSlots, id, holder, shape, &chainDepth)) {
  7256         // Don't attach if proto chain depth is too high.
  7257         if (chainDepth > ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH)
  7258             return true;
  7260         bool isFixedSlot;
  7261         uint32_t offset;
  7262         GetFixedOrDynamicSlotOffset(obj, shape->slot(), &isFixedSlot, &offset);
  7264         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObject.ADD) stub");
  7265         ICSetPropNativeAddCompiler compiler(cx, obj, oldShape, chainDepth, isFixedSlot, offset);
  7266         ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  7267         if (!newStub)
  7268             return false;
  7269         if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
  7270             return false;
  7272         stub->addNewStub(newStub);
  7273         *attached = true;
  7274         return true;
  7277     if (IsCacheableSetPropWriteSlot(obj, oldShape, holder, shape)) {
  7278         bool isFixedSlot;
  7279         uint32_t offset;
  7280         GetFixedOrDynamicSlotOffset(obj, shape->slot(), &isFixedSlot, &offset);
  7282         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObject.PROP) stub");
  7283         ICSetProp_Native::Compiler compiler(cx, obj, isFixedSlot, offset);
  7284         ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  7285         if (!newStub)
  7286             return false;
  7287         if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
  7288             return false;
  7290         stub->addNewStub(newStub);
  7291         *attached = true;
  7292         return true;
  7295     bool isScripted = false;
  7296     bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape, &isScripted);
  7298     // Try handling scripted setters.
  7299     if (cacheableCall && isScripted) {
  7300         RootedFunction callee(cx, &shape->setterObject()->as<JSFunction>());
  7301         JS_ASSERT(obj != holder);
  7302         JS_ASSERT(callee->hasScript());
  7304         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObj/ScriptedSetter %s:%d) stub",
  7305                     callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno());
  7307         ICSetProp_CallScripted::Compiler compiler(cx, obj, holder, callee, script->pcToOffset(pc));
  7308         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  7309         if (!newStub)
  7310             return false;
  7312         stub->addNewStub(newStub);
  7313         *attached = true;
  7314         return true;
  7317     // Try handling JSNative setters.
  7318     if (cacheableCall && !isScripted) {
  7319         RootedFunction callee(cx, &shape->setterObject()->as<JSFunction>());
  7320         JS_ASSERT(obj != holder);
  7321         JS_ASSERT(callee->isNative());
  7323         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObj/NativeSetter %p) stub",
  7324                     callee->native());
  7326         ICSetProp_CallNative::Compiler compiler(cx, obj, holder, callee, script->pcToOffset(pc));
  7327         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  7328         if (!newStub)
  7329             return false;
  7331         stub->addNewStub(newStub);
  7332         *attached = true;
  7333         return true;
  7336     return true;
  7339 static bool
  7340 DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_,
  7341                   HandleValue lhs, HandleValue rhs, MutableHandleValue res)
  7343     // This fallback stub may trigger debug mode toggling.
  7344     DebugModeOSRVolatileStub<ICSetProp_Fallback *> stub(frame, stub_);
  7346     RootedScript script(cx, frame->script());
  7347     jsbytecode *pc = stub->icEntry()->pc(script);
  7348     JSOp op = JSOp(*pc);
  7349     FallbackICSpew(cx, stub, "SetProp(%s)", js_CodeName[op]);
  7351     JS_ASSERT(op == JSOP_SETPROP ||
  7352               op == JSOP_SETNAME ||
  7353               op == JSOP_SETGNAME ||
  7354               op == JSOP_INITPROP ||
  7355               op == JSOP_SETALIASEDVAR);
  7357     RootedPropertyName name(cx);
  7358     if (op == JSOP_SETALIASEDVAR)
  7359         name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc);
  7360     else
  7361         name = script->getName(pc);
  7362     RootedId id(cx, NameToId(name));
  7364     RootedObject obj(cx, ToObjectFromStack(cx, lhs));
  7365     if (!obj)
  7366         return false;
  7367     RootedShape oldShape(cx, obj->lastProperty());
  7368     uint32_t oldSlots = obj->numDynamicSlots();
  7370     if (op == JSOP_INITPROP) {
  7371         MOZ_ASSERT(name != cx->names().proto, "should have used JSOP_MUTATEPROTO");
  7372         MOZ_ASSERT(obj->is<JSObject>());
  7373         if (!DefineNativeProperty(cx, obj, id, rhs, nullptr, nullptr, JSPROP_ENUMERATE))
  7374             return false;
  7375     } else if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
  7376         if (!SetNameOperation(cx, script, pc, obj, rhs))
  7377             return false;
  7378     } else if (op == JSOP_SETALIASEDVAR) {
  7379         obj->as<ScopeObject>().setAliasedVar(cx, pc, name, rhs);
  7380     } else {
  7381         MOZ_ASSERT(op == JSOP_SETPROP);
  7382         if (script->strict()) {
  7383             if (!js::SetProperty<true>(cx, obj, id, rhs))
  7384                 return false;
  7385         } else {
  7386             if (!js::SetProperty<false>(cx, obj, id, rhs))
  7387                 return false;
  7391     // Leave the RHS on the stack.
  7392     res.set(rhs);
  7394     // Check if debug mode toggling made the stub invalid.
  7395     if (stub.invalid())
  7396         return true;
  7398     if (stub->numOptimizedStubs() >= ICSetProp_Fallback::MAX_OPTIMIZED_STUBS) {
  7399         // TODO: Discard all stubs in this IC and replace with generic setprop stub.
  7400         return true;
  7403     bool attached = false;
  7404     if (!TryAttachSetPropStub(cx, script, pc, stub, obj, oldShape, oldSlots, name, id, rhs,
  7405          &attached))
  7407         return false;
  7409     if (attached)
  7410         return true;
  7412     JS_ASSERT(!attached);
  7413     stub->noteUnoptimizableAccess();
  7415     return true;
  7418 typedef bool (*DoSetPropFallbackFn)(JSContext *, BaselineFrame *, ICSetProp_Fallback *,
  7419                                     HandleValue, HandleValue, MutableHandleValue);
  7420 static const VMFunction DoSetPropFallbackInfo =
  7421     FunctionInfo<DoSetPropFallbackFn>(DoSetPropFallback, PopValues(2));
  7423 bool
  7424 ICSetProp_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  7426     JS_ASSERT(R0 == JSReturnOperand);
  7428     EmitRestoreTailCallReg(masm);
  7430     // Ensure stack is fully synced for the expression decompiler.
  7431     masm.pushValue(R0);
  7432     masm.pushValue(R1);
  7434     // Push arguments.
  7435     masm.pushValue(R1);
  7436     masm.pushValue(R0);
  7437     masm.push(BaselineStubReg);
  7438     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  7440     if (!tailCallVM(DoSetPropFallbackInfo, masm))
  7441         return false;
  7443     // What follows is bailout debug mode recompile code for inlined scripted
  7444     // getters The return address pointed to by the baseline stack points
  7445     // here.
  7446     //
  7447     // Even though the fallback frame doesn't enter a stub frame, the CallScripted
  7448     // frame that we are emulating does. Again, we lie.
  7449 #ifdef DEBUG
  7450     entersStubFrame_ = true;
  7451 #endif
  7453     Label leaveStubCommon;
  7455     returnFromStubOffset_ = masm.currentOffset();
  7456     leaveStubFrameHead(masm, false);
  7457     masm.jump(&leaveStubCommon);
  7459     returnFromIonOffset_ = masm.currentOffset();
  7460     leaveStubFrameHead(masm, true);
  7462     masm.bind(&leaveStubCommon);
  7463     leaveStubFrameCommonTail(masm);
  7465     // Retrieve the stashed initial argument from the caller's frame before returning
  7466     EmitUnstowICValues(masm, 1);
  7467     EmitReturnFromIC(masm);
  7469     return true;
  7472 bool
  7473 ICSetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code)
  7475     JitCompartment *comp = cx->compartment()->jitCompartment();
  7477     CodeOffsetLabel fromIon(returnFromIonOffset_);
  7478     fromIon.fixup(&masm);
  7479     comp->initBaselineSetPropReturnFromIonAddr(code->raw() + fromIon.offset());
  7481     CodeOffsetLabel fromVM(returnFromStubOffset_);
  7482     fromVM.fixup(&masm);
  7483     comp->initBaselineSetPropReturnFromStubAddr(code->raw() + fromVM.offset());
  7485     return true;
  7488 bool
  7489 ICSetProp_Native::Compiler::generateStubCode(MacroAssembler &masm)
  7491     Label failure;
  7493     // Guard input is an object.
  7494     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  7496     GeneralRegisterSet regs(availableGeneralRegs(2));
  7497     Register scratch = regs.takeAny();
  7499     // Unbox and shape guard.
  7500     Register objReg = masm.extractObject(R0, ExtractTemp0);
  7501     masm.loadPtr(Address(BaselineStubReg, ICSetProp_Native::offsetOfShape()), scratch);
  7502     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
  7504     // Guard that the type object matches.
  7505     masm.loadPtr(Address(BaselineStubReg, ICSetProp_Native::offsetOfType()), scratch);
  7506     masm.branchPtr(Assembler::NotEqual, Address(objReg, JSObject::offsetOfType()), scratch,
  7507                    &failure);
  7509     // Stow both R0 and R1 (object and value).
  7510     EmitStowICValues(masm, 2);
  7512     // Type update stub expects the value to check in R0.
  7513     masm.moveValue(R1, R0);
  7515     // Call the type-update stub.
  7516     if (!callTypeUpdateIC(masm, sizeof(Value)))
  7517         return false;
  7519     // Unstow R0 and R1 (object and key)
  7520     EmitUnstowICValues(masm, 2);
  7522     regs.add(R0);
  7523     regs.takeUnchecked(objReg);
  7525     Register holderReg;
  7526     if (isFixedSlot_) {
  7527         holderReg = objReg;
  7528     } else {
  7529         holderReg = regs.takeAny();
  7530         masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), holderReg);
  7533     // Perform the store.
  7534     masm.load32(Address(BaselineStubReg, ICSetProp_Native::offsetOfOffset()), scratch);
  7535     EmitPreBarrier(masm, BaseIndex(holderReg, scratch, TimesOne), MIRType_Value);
  7536     masm.storeValue(R1, BaseIndex(holderReg, scratch, TimesOne));
  7537     if (holderReg != objReg)
  7538         regs.add(holderReg);
  7539 #ifdef JSGC_GENERATIONAL
  7541         Register scr = regs.takeAny();
  7542         GeneralRegisterSet saveRegs;
  7543         saveRegs.add(R1);
  7544         emitPostWriteBarrierSlot(masm, objReg, R1, scr, saveRegs);
  7545         regs.add(scr);
  7547 #endif
  7549     // The RHS has to be in R0.
  7550     masm.moveValue(R1, R0);
  7551     EmitReturnFromIC(masm);
  7553     // Failure case - jump to next stub
  7554     masm.bind(&failure);
  7555     EmitStubGuardFailure(masm);
  7556     return true;
  7559 ICUpdatedStub *
  7560 ICSetPropNativeAddCompiler::getStub(ICStubSpace *space)
  7562     AutoShapeVector shapes(cx);
  7563     if (!shapes.append(oldShape_))
  7564         return nullptr;
  7566     if (!GetProtoShapes(obj_, protoChainDepth_, &shapes))
  7567         return nullptr;
  7569     JS_STATIC_ASSERT(ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH == 4);
  7571     ICUpdatedStub *stub = nullptr;
  7572     switch(protoChainDepth_) {
  7573       case 0: stub = getStubSpecific<0>(space, &shapes); break;
  7574       case 1: stub = getStubSpecific<1>(space, &shapes); break;
  7575       case 2: stub = getStubSpecific<2>(space, &shapes); break;
  7576       case 3: stub = getStubSpecific<3>(space, &shapes); break;
  7577       case 4: stub = getStubSpecific<4>(space, &shapes); break;
  7578       default: MOZ_ASSUME_UNREACHABLE("ProtoChainDepth too high.");
  7580     if (!stub || !stub->initUpdatingChain(cx, space))
  7581         return nullptr;
  7582     return stub;
  7585 bool
  7586 ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
  7588     Label failure;
  7589     Label failureUnstow;
  7591     // Guard input is an object.
  7592     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  7594     GeneralRegisterSet regs(availableGeneralRegs(2));
  7595     Register scratch = regs.takeAny();
  7597     // Unbox and guard against old shape.
  7598     Register objReg = masm.extractObject(R0, ExtractTemp0);
  7599     masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAddImpl<0>::offsetOfShape(0)), scratch);
  7600     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
  7602     // Guard that the type object matches.
  7603     masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfType()), scratch);
  7604     masm.branchPtr(Assembler::NotEqual, Address(objReg, JSObject::offsetOfType()), scratch,
  7605                    &failure);
  7607     // Stow both R0 and R1 (object and value).
  7608     EmitStowICValues(masm, 2);
  7610     regs = availableGeneralRegs(1);
  7611     scratch = regs.takeAny();
  7612     Register protoReg = regs.takeAny();
  7613     // Check the proto chain.
  7614     for (size_t i = 0; i < protoChainDepth_; i++) {
  7615         masm.loadObjProto(i == 0 ? objReg : protoReg, protoReg);
  7616         masm.branchTestPtr(Assembler::Zero, protoReg, protoReg, &failureUnstow);
  7617         masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAddImpl<0>::offsetOfShape(i + 1)),
  7618                      scratch);
  7619         masm.branchTestObjShape(Assembler::NotEqual, protoReg, scratch, &failureUnstow);
  7622     // Shape and type checks succeeded, ok to proceed.
  7624     // Load RHS into R0 for TypeUpdate check.
  7625     // Stack is currently: [..., ObjValue, RHSValue, MaybeReturnAddr? ]
  7626     masm.loadValue(Address(BaselineStackReg, ICStackValueOffset), R0);
  7628     // Call the type-update stub.
  7629     if (!callTypeUpdateIC(masm, sizeof(Value)))
  7630         return false;
  7632     // Unstow R0 and R1 (object and key)
  7633     EmitUnstowICValues(masm, 2);
  7634     regs = availableGeneralRegs(2);
  7635     scratch = regs.takeAny();
  7637     // Changing object shape.  Write the object's new shape.
  7638     Address shapeAddr(objReg, JSObject::offsetOfShape());
  7639     EmitPreBarrier(masm, shapeAddr, MIRType_Shape);
  7640     masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfNewShape()), scratch);
  7641     masm.storePtr(scratch, shapeAddr);
  7643     Register holderReg;
  7644     regs.add(R0);
  7645     regs.takeUnchecked(objReg);
  7646     if (isFixedSlot_) {
  7647         holderReg = objReg;
  7648     } else {
  7649         holderReg = regs.takeAny();
  7650         masm.loadPtr(Address(objReg, JSObject::offsetOfSlots()), holderReg);
  7653     // Perform the store.  No write barrier required since this is a new
  7654     // initialization.
  7655     masm.load32(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfOffset()), scratch);
  7656     masm.storeValue(R1, BaseIndex(holderReg, scratch, TimesOne));
  7658     if (holderReg != objReg)
  7659         regs.add(holderReg);
  7661 #ifdef JSGC_GENERATIONAL
  7663         Register scr = regs.takeAny();
  7664         GeneralRegisterSet saveRegs;
  7665         saveRegs.add(R1);
  7666         emitPostWriteBarrierSlot(masm, objReg, R1, scr, saveRegs);
  7668 #endif
  7670     // The RHS has to be in R0.
  7671     masm.moveValue(R1, R0);
  7672     EmitReturnFromIC(masm);
  7674     // Failure case - jump to next stub
  7675     masm.bind(&failureUnstow);
  7676     EmitUnstowICValues(masm, 2);
  7678     masm.bind(&failure);
  7679     EmitStubGuardFailure(masm);
  7680     return true;
  7683 bool
  7684 ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
  7686     Label failure;
  7687     Label failureUnstow;
  7688     Label failureLeaveStubFrame;
  7690     // Guard input is an object.
  7691     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  7693     // Stow R0 and R1 to free up registers.
  7694     EmitStowICValues(masm, 2);
  7696     GeneralRegisterSet regs(availableGeneralRegs(1));
  7697     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
  7699     // Unbox and shape guard.
  7700     Register objReg = masm.extractObject(R0, ExtractTemp0);
  7701     masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfShape()), scratch);
  7702     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failureUnstow);
  7704     Register holderReg = regs.takeAny();
  7705     masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfHolder()), holderReg);
  7706     masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfHolderShape()), scratch);
  7707     masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failureUnstow);
  7708     regs.add(holderReg);
  7710     // Push a stub frame so that we can perform a non-tail call.
  7711     enterStubFrame(masm, scratch);
  7713     // Load callee function and code.  To ensure that |code| doesn't end up being
  7714     // ArgumentsRectifierReg, if it's available we assign it to |callee| instead.
  7715     Register callee;
  7716     if (regs.has(ArgumentsRectifierReg)) {
  7717         callee = ArgumentsRectifierReg;
  7718         regs.take(callee);
  7719     } else {
  7720         callee = regs.takeAny();
  7722     Register code = regs.takeAny();
  7723     masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfSetter()), callee);
  7724     masm.branchIfFunctionHasNoScript(callee, &failureLeaveStubFrame);
  7725     masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
  7726     masm.loadBaselineOrIonRaw(code, code, SequentialExecution, &failureLeaveStubFrame);
  7728     // Setter is called with the new value as the only argument, and |obj| as thisv.
  7729     // Note that we use Push, not push, so that callIon will align the stack
  7730     // properly on ARM.
  7732     // To Push R1, read it off of the stowed values on stack.
  7733     // Stack: [ ..., R0, R1, ..STUBFRAME-HEADER.. ]
  7734     masm.movePtr(BaselineStackReg, scratch);
  7735     masm.PushValue(Address(scratch, STUB_FRAME_SIZE));
  7736     masm.Push(R0);
  7737     EmitCreateStubFrameDescriptor(masm, scratch);
  7738     masm.Push(Imm32(1));  // ActualArgc is 1
  7739     masm.Push(callee);
  7740     masm.Push(scratch);
  7742     // Handle arguments underflow.
  7743     Label noUnderflow;
  7744     masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch);
  7745     masm.branch32(Assembler::BelowOrEqual, scratch, Imm32(1), &noUnderflow);
  7747         // Call the arguments rectifier.
  7748         JS_ASSERT(ArgumentsRectifierReg != code);
  7750         JitCode *argumentsRectifier =
  7751             cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
  7753         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
  7754         masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
  7755         masm.mov(ImmWord(1), ArgumentsRectifierReg);
  7758     masm.bind(&noUnderflow);
  7760     // If needed, update SPS Profiler frame entry.  At this point, callee and scratch can
  7761     // be clobbered.
  7763         GeneralRegisterSet availRegs = availableGeneralRegs(0);
  7764         availRegs.take(ArgumentsRectifierReg);
  7765         availRegs.take(code);
  7766         emitProfilingUpdate(masm, availRegs, ICSetProp_CallScripted::offsetOfPCOffset());
  7769     masm.callIon(code);
  7771     leaveStubFrame(masm, true);
  7772     // Do not care about return value from function. The original RHS should be returned
  7773     // as the result of this operation.
  7774     EmitUnstowICValues(masm, 2);
  7775     masm.moveValue(R1, R0);
  7776     EmitReturnFromIC(masm);
  7778     // Leave stub frame and go to next stub.
  7779     masm.bind(&failureLeaveStubFrame);
  7780     leaveStubFrame(masm, false);
  7782     // Unstow R0 and R1
  7783     masm.bind(&failureUnstow);
  7784     EmitUnstowICValues(masm, 2);
  7786     // Failure case - jump to next stub
  7787     masm.bind(&failure);
  7788     EmitStubGuardFailure(masm);
  7789     return true;
  7792 static bool
  7793 DoCallNativeSetter(JSContext *cx, HandleFunction callee, HandleObject obj, HandleValue val)
  7795     JS_ASSERT(callee->isNative());
  7796     JSNative natfun = callee->native();
  7798     JS::AutoValueArray<3> vp(cx);
  7799     vp[0].setObject(*callee.get());
  7800     vp[1].setObject(*obj.get());
  7801     vp[2].set(val);
  7803     return natfun(cx, 1, vp.begin());
  7806 typedef bool (*DoCallNativeSetterFn)(JSContext *, HandleFunction, HandleObject, HandleValue);
  7807 static const VMFunction DoCallNativeSetterInfo =
  7808     FunctionInfo<DoCallNativeSetterFn>(DoCallNativeSetter);
  7810 bool
  7811 ICSetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
  7813     Label failure;
  7814     Label failureUnstow;
  7816     // Guard input is an object.
  7817     masm.branchTestObject(Assembler::NotEqual, R0, &failure);
  7819     // Stow R0 and R1 to free up registers.
  7820     EmitStowICValues(masm, 2);
  7822     GeneralRegisterSet regs(availableGeneralRegs(1));
  7823     Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
  7825     // Unbox and shape guard.
  7826     Register objReg = masm.extractObject(R0, ExtractTemp0);
  7827     masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfShape()), scratch);
  7828     masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failureUnstow);
  7830     Register holderReg = regs.takeAny();
  7831     masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfHolder()), holderReg);
  7832     masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfHolderShape()), scratch);
  7833     masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failureUnstow);
  7834     regs.add(holderReg);
  7836     // Push a stub frame so that we can perform a non-tail call.
  7837     enterStubFrame(masm, scratch);
  7839     // Load callee function and code.  To ensure that |code| doesn't end up being
  7840     // ArgumentsRectifierReg, if it's available we assign it to |callee| instead.
  7841     Register callee = regs.takeAny();
  7842     masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfSetter()), callee);
  7844     // To Push R1, read it off of the stowed values on stack.
  7845     // Stack: [ ..., R0, R1, ..STUBFRAME-HEADER.. ]
  7846     masm.movePtr(BaselineStackReg, scratch);
  7847     masm.pushValue(Address(scratch, STUB_FRAME_SIZE));
  7848     masm.push(objReg);
  7849     masm.push(callee);
  7851     // Don't need to preserve R0 anymore.
  7852     regs.add(R0);
  7854     // If needed, update SPS Profiler frame entry.
  7855     emitProfilingUpdate(masm, regs, ICSetProp_CallNative::offsetOfPCOffset());
  7857     if (!callVM(DoCallNativeSetterInfo, masm))
  7858         return false;
  7859     leaveStubFrame(masm);
  7861     // Do not care about return value from function. The original RHS should be returned
  7862     // as the result of this operation.
  7863     EmitUnstowICValues(masm, 2);
  7864     masm.moveValue(R1, R0);
  7865     EmitReturnFromIC(masm);
  7867     // Unstow R0 and R1
  7868     masm.bind(&failureUnstow);
  7869     EmitUnstowICValues(masm, 2);
  7871     // Failure case - jump to next stub
  7872     masm.bind(&failure);
  7873     EmitStubGuardFailure(masm);
  7874     return true;
  7877 //
  7878 // Call_Fallback
  7879 //
  7881 static bool
  7882 TryAttachFunApplyStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsbytecode *pc,
  7883                       HandleValue thisv, uint32_t argc, Value *argv)
  7885     if (argc != 2)
  7886         return true;
  7888     if (!thisv.isObject() || !thisv.toObject().is<JSFunction>())
  7889         return true;
  7890     RootedFunction target(cx, &thisv.toObject().as<JSFunction>());
  7892     bool isScripted = target->hasJITCode();
  7894     // right now, only handle situation where second argument is |arguments|
  7895     if (argv[1].isMagic(JS_OPTIMIZED_ARGUMENTS) && !script->needsArgsObj()) {
  7896         if (isScripted && !stub->hasStub(ICStub::Call_ScriptedApplyArguments)) {
  7897             IonSpew(IonSpew_BaselineIC, "  Generating Call_ScriptedApplyArguments stub");
  7899             ICCall_ScriptedApplyArguments::Compiler compiler(
  7900                 cx, stub->fallbackMonitorStub()->firstMonitorStub(), script->pcToOffset(pc));
  7901             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  7902             if (!newStub)
  7903                 return false;
  7905             stub->addNewStub(newStub);
  7906             return true;
  7909         // TODO: handle FUNAPPLY for native targets.
  7912     if (argv[1].isObject() && argv[1].toObject().is<ArrayObject>()) {
  7913         if (isScripted && !stub->hasStub(ICStub::Call_ScriptedApplyArray)) {
  7914             IonSpew(IonSpew_BaselineIC, "  Generating Call_ScriptedApplyArray stub");
  7916             ICCall_ScriptedApplyArray::Compiler compiler(
  7917                 cx, stub->fallbackMonitorStub()->firstMonitorStub(), script->pcToOffset(pc));
  7918             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  7919             if (!newStub)
  7920                 return false;
  7922             stub->addNewStub(newStub);
  7923             return true;
  7926     return true;
  7929 static bool
  7930 TryAttachFunCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsbytecode *pc,
  7931                      HandleValue thisv, bool *attached)
  7933     // Try to attach a stub for Function.prototype.call with scripted |this|.
  7935     *attached = false;
  7936     if (!thisv.isObject() || !thisv.toObject().is<JSFunction>())
  7937         return true;
  7938     RootedFunction target(cx, &thisv.toObject().as<JSFunction>());
  7940     // Attach a stub if the script can be Baseline-compiled. We do this also
  7941     // if the script is not yet compiled to avoid attaching a CallNative stub
  7942     // that handles everything, even after the callee becomes hot.
  7943     if (target->hasScript() && target->nonLazyScript()->canBaselineCompile() &&
  7944         !stub->hasStub(ICStub::Call_ScriptedFunCall))
  7946         IonSpew(IonSpew_BaselineIC, "  Generating Call_ScriptedFunCall stub");
  7948         ICCall_ScriptedFunCall::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
  7949                                                   script->pcToOffset(pc));
  7950         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  7951         if (!newStub)
  7952             return false;
  7954         *attached = true;
  7955         stub->addNewStub(newStub);
  7956         return true;
  7959     return true;
  7962 static bool
  7963 GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
  7964                            Native native, const CallArgs &args, MutableHandleObject res)
  7966     // Check for natives to which template objects can be attached. This is
  7967     // done to provide templates to Ion for inlining these natives later on.
  7969     if (native == js_Array) {
  7970         // Note: the template array won't be used if its length is inaccurately
  7971         // computed here.  (We allocate here because compilation may occur on a
  7972         // separate thread where allocation is impossible.)
  7973         size_t count = 0;
  7974         if (args.length() != 1)
  7975             count = args.length();
  7976         else if (args.length() == 1 && args[0].isInt32() && args[0].toInt32() >= 0)
  7977             count = args[0].toInt32();
  7978         res.set(NewDenseUnallocatedArray(cx, count, nullptr, TenuredObject));
  7979         if (!res)
  7980             return false;
  7982         types::TypeObject *type = types::TypeScript::InitObject(cx, script, pc, JSProto_Array);
  7983         if (!type)
  7984             return false;
  7985         res->setType(type);
  7986         return true;
  7989     if (native == intrinsic_NewDenseArray) {
  7990         res.set(NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject));
  7991         if (!res)
  7992             return false;
  7994         types::TypeObject *type = types::TypeScript::InitObject(cx, script, pc, JSProto_Array);
  7995         if (!type)
  7996             return false;
  7997         res->setType(type);
  7998         return true;
  8001     if (native == js::array_concat) {
  8002         if (args.thisv().isObject() && args.thisv().toObject().is<ArrayObject>() &&
  8003             !args.thisv().toObject().hasSingletonType())
  8005             res.set(NewDenseEmptyArray(cx, args.thisv().toObject().getProto(), TenuredObject));
  8006             if (!res)
  8007                 return false;
  8008             res->setType(args.thisv().toObject().type());
  8009             return true;
  8013     if (native == js::str_split && args.length() == 1 && args[0].isString()) {
  8014         res.set(NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject));
  8015         if (!res)
  8016             return false;
  8018         types::TypeObject *type = types::TypeScript::InitObject(cx, script, pc, JSProto_Array);
  8019         if (!type)
  8020             return false;
  8021         res->setType(type);
  8022         return true;
  8025     if (native == js_String) {
  8026         RootedString emptyString(cx, cx->runtime()->emptyString);
  8027         res.set(StringObject::create(cx, emptyString, TenuredObject));
  8028         if (!res)
  8029             return false;
  8030         return true;
  8033     return true;
  8036 static bool
  8037 TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsbytecode *pc,
  8038                   JSOp op, uint32_t argc, Value *vp, bool constructing, bool useNewType)
  8040     if (useNewType || op == JSOP_EVAL)
  8041         return true;
  8043     if (stub->numOptimizedStubs() >= ICCall_Fallback::MAX_OPTIMIZED_STUBS) {
  8044         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
  8045         // But for now we just bail.
  8046         return true;
  8049     RootedValue callee(cx, vp[0]);
  8050     RootedValue thisv(cx, vp[1]);
  8052     if (!callee.isObject())
  8053         return true;
  8055     RootedObject obj(cx, &callee.toObject());
  8056     if (!obj->is<JSFunction>())
  8057         return true;
  8059     RootedFunction fun(cx, &obj->as<JSFunction>());
  8061     if (fun->hasScript()) {
  8062         // Never attach optimized scripted call stubs for JSOP_FUNAPPLY.
  8063         // MagicArguments may escape the frame through them.
  8064         if (op == JSOP_FUNAPPLY)
  8065             return true;
  8067         // If callee is not an interpreted constructor, we have to throw.
  8068         if (constructing && !fun->isInterpretedConstructor())
  8069             return true;
  8071         RootedScript calleeScript(cx, fun->nonLazyScript());
  8072         if (!calleeScript->hasBaselineScript() && !calleeScript->hasIonScript())
  8073             return true;
  8075         if (calleeScript->shouldCloneAtCallsite())
  8076             return true;
  8078         // Check if this stub chain has already generalized scripted calls.
  8079         if (stub->scriptedStubsAreGeneralized()) {
  8080             IonSpew(IonSpew_BaselineIC, "  Chain already has generalized scripted call stub!");
  8081             return true;
  8084         if (stub->scriptedStubCount() >= ICCall_Fallback::MAX_SCRIPTED_STUBS) {
  8085             // Create a Call_AnyScripted stub.
  8086             IonSpew(IonSpew_BaselineIC, "  Generating Call_AnyScripted stub (cons=%s)",
  8087                     constructing ? "yes" : "no");
  8089             ICCallScriptedCompiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
  8090                                             constructing, script->pcToOffset(pc));
  8091             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  8092             if (!newStub)
  8093                 return false;
  8095             // Before adding new stub, unlink all previous Call_Scripted.
  8096             stub->unlinkStubsWithKind(cx, ICStub::Call_Scripted);
  8098             // Add new generalized stub.
  8099             stub->addNewStub(newStub);
  8100             return true;
  8103         // Keep track of the function's |prototype| property in type
  8104         // information, for use during Ion compilation.
  8105         if (IsIonEnabled(cx))
  8106             types::EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
  8108         // Remember the template object associated with any script being called
  8109         // as a constructor, for later use during Ion compilation.
  8110         RootedObject templateObject(cx);
  8111         if (constructing) {
  8112             templateObject = CreateThisForFunction(cx, fun, MaybeSingletonObject);
  8113             if (!templateObject)
  8114                 return false;
  8117         IonSpew(IonSpew_BaselineIC,
  8118                 "  Generating Call_Scripted stub (fun=%p, %s:%d, cons=%s)",
  8119                 fun.get(), fun->nonLazyScript()->filename(), fun->nonLazyScript()->lineno(),
  8120                 constructing ? "yes" : "no");
  8121         ICCallScriptedCompiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
  8122                                         calleeScript, templateObject,
  8123                                         constructing, script->pcToOffset(pc));
  8124         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  8125         if (!newStub)
  8126             return false;
  8128         stub->addNewStub(newStub);
  8129         return true;
  8132     if (fun->isNative() && (!constructing || (constructing && fun->isNativeConstructor()))) {
  8133         // Generalized native call stubs are not here yet!
  8134         JS_ASSERT(!stub->nativeStubsAreGeneralized());
  8136         // Check for JSOP_FUNAPPLY
  8137         if (op == JSOP_FUNAPPLY) {
  8138             if (fun->native() == js_fun_apply)
  8139                 return TryAttachFunApplyStub(cx, stub, script, pc, thisv, argc, vp + 2);
  8141             // Don't try to attach a "regular" optimized call stubs for FUNAPPLY ops,
  8142             // since MagicArguments may escape through them.
  8143             return true;
  8146         if (op == JSOP_FUNCALL && fun->native() == js_fun_call) {
  8147             bool attached;
  8148             if (!TryAttachFunCallStub(cx, stub, script, pc, thisv, &attached))
  8149                 return false;
  8150             if (attached)
  8151                 return true;
  8154         if (stub->nativeStubCount() >= ICCall_Fallback::MAX_NATIVE_STUBS) {
  8155             IonSpew(IonSpew_BaselineIC,
  8156                     "  Too many Call_Native stubs. TODO: add Call_AnyNative!");
  8157             return true;
  8160         CallArgs args = CallArgsFromVp(argc, vp);
  8161         RootedObject templateObject(cx);
  8162         if (!GetTemplateObjectForNative(cx, script, pc, fun->native(), args, &templateObject))
  8163             return false;
  8165         IonSpew(IonSpew_BaselineIC, "  Generating Call_Native stub (fun=%p, cons=%s)",
  8166                 fun.get(), constructing ? "yes" : "no");
  8167         ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
  8168                                          fun, templateObject, constructing, script->pcToOffset(pc));
  8169         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
  8170         if (!newStub)
  8171             return false;
  8173         stub->addNewStub(newStub);
  8174         return true;
  8177     return true;
  8180 static bool
  8181 MaybeCloneFunctionAtCallsite(JSContext *cx, MutableHandleValue callee, HandleScript script,
  8182                              jsbytecode *pc)
  8184     RootedFunction fun(cx);
  8185     if (!IsFunctionObject(callee, fun.address()))
  8186         return true;
  8188     if (!fun->hasScript() || !fun->nonLazyScript()->shouldCloneAtCallsite())
  8189         return true;
  8191     fun = CloneFunctionAtCallsite(cx, fun, script, pc);
  8192     if (!fun)
  8193         return false;
  8195     callee.setObject(*fun);
  8196     return true;
  8199 static bool
  8200 DoCallFallback(JSContext *cx, BaselineFrame *frame, ICCall_Fallback *stub_, uint32_t argc,
  8201                Value *vp, MutableHandleValue res)
  8203     // This fallback stub may trigger debug mode toggling.
  8204     DebugModeOSRVolatileStub<ICCall_Fallback *> stub(frame, stub_);
  8206     // Ensure vp array is rooted - we may GC in here.
  8207     AutoArrayRooter vpRoot(cx, argc + 2, vp);
  8209     RootedScript script(cx, frame->script());
  8210     jsbytecode *pc = stub->icEntry()->pc(script);
  8211     JSOp op = JSOp(*pc);
  8212     FallbackICSpew(cx, stub, "Call(%s)", js_CodeName[op]);
  8214     JS_ASSERT(argc == GET_ARGC(pc));
  8216     RootedValue callee(cx, vp[0]);
  8217     RootedValue thisv(cx, vp[1]);
  8219     Value *args = vp + 2;
  8221     // Handle funapply with JSOP_ARGUMENTS
  8222     if (op == JSOP_FUNAPPLY && argc == 2 && args[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
  8223         if (!GuardFunApplyArgumentsOptimization(cx, frame, callee, args, argc))
  8224             return false;
  8227     // Compute construcing and useNewType flags.
  8228     bool constructing = (op == JSOP_NEW);
  8229     bool newType = types::UseNewType(cx, script, pc);
  8231     // Try attaching a call stub.
  8232     if (!TryAttachCallStub(cx, stub, script, pc, op, argc, vp, constructing, newType))
  8233         return false;
  8235     // Maybe update PC in profiler entry before leaving this script by call.
  8236     if (cx->runtime()->spsProfiler.enabled() && frame->hasPushedSPSFrame())
  8237         cx->runtime()->spsProfiler.updatePC(script, pc);
  8239     if (!MaybeCloneFunctionAtCallsite(cx, &callee, script, pc))
  8240         return false;
  8242     if (op == JSOP_NEW) {
  8243         if (!InvokeConstructor(cx, callee, argc, args, res.address()))
  8244             return false;
  8245     } else if (op == JSOP_EVAL && frame->scopeChain()->global().valueIsEval(callee)) {
  8246         if (!DirectEval(cx, CallArgsFromVp(argc, vp)))
  8247             return false;
  8248         res.set(vp[0]);
  8249     } else {
  8250         JS_ASSERT(op == JSOP_CALL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY || op == JSOP_EVAL);
  8251         if (!Invoke(cx, thisv, callee, argc, args, res))
  8252             return false;
  8255     types::TypeScript::Monitor(cx, script, pc, res);
  8257     // Check if debug mode toggling made the stub invalid.
  8258     if (stub.invalid())
  8259         return true;
  8261     // Attach a new TypeMonitor stub for this value.
  8262     ICTypeMonitor_Fallback *typeMonFbStub = stub->fallbackMonitorStub();
  8263     if (!typeMonFbStub->addMonitorStubForValue(cx, script, res))
  8264         return false;
  8265     // Add a type monitor stub for the resulting value.
  8266     if (!stub->addMonitorStubForValue(cx, script, res))
  8267         return false;
  8269     return true;
  8272 void
  8273 ICCallStubCompiler::pushCallArguments(MacroAssembler &masm, GeneralRegisterSet regs, Register argcReg)
  8275     JS_ASSERT(!regs.has(argcReg));
  8277     // Push the callee and |this| too.
  8278     Register count = regs.takeAny();
  8279     masm.mov(argcReg, count);
  8280     masm.add32(Imm32(2), count);
  8282     // argPtr initially points to the last argument.
  8283     Register argPtr = regs.takeAny();
  8284     masm.mov(BaselineStackReg, argPtr);
  8286     // Skip 4 pointers pushed on top of the arguments: the frame descriptor,
  8287     // return address, old frame pointer and stub reg.
  8288     masm.addPtr(Imm32(STUB_FRAME_SIZE), argPtr);
  8290     // Push all values, starting at the last one.
  8291     Label loop, done;
  8292     masm.bind(&loop);
  8293     masm.branchTest32(Assembler::Zero, count, count, &done);
  8295         masm.pushValue(Address(argPtr, 0));
  8296         masm.addPtr(Imm32(sizeof(Value)), argPtr);
  8298         masm.sub32(Imm32(1), count);
  8299         masm.jump(&loop);
  8301     masm.bind(&done);
  8304 Register
  8305 ICCallStubCompiler::guardFunApply(MacroAssembler &masm, GeneralRegisterSet regs, Register argcReg,
  8306                                   bool checkNative, FunApplyThing applyThing, Label *failure)
  8308     // Ensure argc == 2
  8309     masm.branch32(Assembler::NotEqual, argcReg, Imm32(2), failure);
  8311     // Stack looks like:
  8312     //      [..., CalleeV, ThisV, Arg0V, Arg1V <MaybeReturnReg>]
  8314     Address secondArgSlot(BaselineStackReg, ICStackValueOffset);
  8315     if (applyThing == FunApply_MagicArgs) {
  8316         // Ensure that the second arg is magic arguments.
  8317         masm.branchTestMagic(Assembler::NotEqual, secondArgSlot, failure);
  8319         // Ensure that this frame doesn't have an arguments object.
  8320         masm.branchTest32(Assembler::NonZero,
  8321                           Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()),
  8322                           Imm32(BaselineFrame::HAS_ARGS_OBJ),
  8323                           failure);
  8324     } else {
  8325         JS_ASSERT(applyThing == FunApply_Array);
  8327         GeneralRegisterSet regsx = regs;
  8329         // Ensure that the second arg is an array.
  8330         ValueOperand secondArgVal = regsx.takeAnyValue();
  8331         masm.loadValue(secondArgSlot, secondArgVal);
  8333         masm.branchTestObject(Assembler::NotEqual, secondArgVal, failure);
  8334         Register secondArgObj = masm.extractObject(secondArgVal, ExtractTemp1);
  8336         regsx.add(secondArgVal);
  8337         regsx.takeUnchecked(secondArgObj);
  8339         masm.branchTestObjClass(Assembler::NotEqual, secondArgObj, regsx.getAny(),
  8340                                 &ArrayObject::class_, failure);
  8342         // Get the array elements and ensure that initializedLength == length
  8343         masm.loadPtr(Address(secondArgObj, JSObject::offsetOfElements()), secondArgObj);
  8345         Register lenReg = regsx.takeAny();
  8346         masm.load32(Address(secondArgObj, ObjectElements::offsetOfLength()), lenReg);
  8348         masm.branch32(Assembler::NotEqual,
  8349                       Address(secondArgObj, ObjectElements::offsetOfInitializedLength()),
  8350                       lenReg, failure);
  8352         // Limit the length to something reasonable (huge number of arguments can
  8353         // blow the stack limit).
  8354         masm.branch32(Assembler::Above, lenReg,
  8355                       Imm32(ICCall_ScriptedApplyArray::MAX_ARGS_ARRAY_LENGTH),
  8356                       failure);
  8358         // Ensure no holes.  Loop through values in array and make sure none are magic.
  8359         // Start address is secondArgObj, end address is secondArgObj + (lenReg * sizeof(Value))
  8360         JS_STATIC_ASSERT(sizeof(Value) == 8);
  8361         masm.lshiftPtr(Imm32(3), lenReg);
  8362         masm.addPtr(secondArgObj, lenReg);
  8364         Register start = secondArgObj;
  8365         Register end = lenReg;
  8366         Label loop;
  8367         Label endLoop;
  8368         masm.bind(&loop);
  8369         masm.branchPtr(Assembler::AboveOrEqual, start, end, &endLoop);
  8370         masm.branchTestMagic(Assembler::Equal, Address(start, 0), failure);
  8371         masm.addPtr(Imm32(sizeof(Value)), start);
  8372         masm.jump(&loop);
  8373         masm.bind(&endLoop);
  8376     // Stack now confirmed to be like:
  8377     //      [..., CalleeV, ThisV, Arg0V, MagicValue(Arguments), <MaybeReturnAddr>]
  8379     // Load the callee, ensure that it's js_fun_apply
  8380     ValueOperand val = regs.takeAnyValue();
  8381     Address calleeSlot(BaselineStackReg, ICStackValueOffset + (3 * sizeof(Value)));
  8382     masm.loadValue(calleeSlot, val);
  8384     masm.branchTestObject(Assembler::NotEqual, val, failure);
  8385     Register callee = masm.extractObject(val, ExtractTemp1);
  8387     masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &JSFunction::class_,
  8388                             failure);
  8389     masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
  8391     masm.branchPtr(Assembler::NotEqual, callee, ImmPtr(js_fun_apply), failure);
  8393     // Load the |thisv|, ensure that it's a scripted function with a valid baseline or ion
  8394     // script, or a native function.
  8395     Address thisSlot(BaselineStackReg, ICStackValueOffset + (2 * sizeof(Value)));
  8396     masm.loadValue(thisSlot, val);
  8398     masm.branchTestObject(Assembler::NotEqual, val, failure);
  8399     Register target = masm.extractObject(val, ExtractTemp1);
  8400     regs.add(val);
  8401     regs.takeUnchecked(target);
  8403     masm.branchTestObjClass(Assembler::NotEqual, target, regs.getAny(), &JSFunction::class_,
  8404                             failure);
  8406     if (checkNative) {
  8407         masm.branchIfInterpreted(target, failure);
  8408     } else {
  8409         masm.branchIfFunctionHasNoScript(target, failure);
  8410         Register temp = regs.takeAny();
  8411         masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), temp);
  8412         masm.loadBaselineOrIonRaw(temp, temp, SequentialExecution, failure);
  8413         regs.add(temp);
  8415     return target;
  8418 void
  8419 ICCallStubCompiler::pushCallerArguments(MacroAssembler &masm, GeneralRegisterSet regs)
  8421     // Initialize copyReg to point to start caller arguments vector.
  8422     // Initialize argcReg to poitn to the end of it.
  8423     Register startReg = regs.takeAny();
  8424     Register endReg = regs.takeAny();
  8425     masm.loadPtr(Address(BaselineFrameReg, 0), startReg);
  8426     masm.loadPtr(Address(startReg, BaselineFrame::offsetOfNumActualArgs()), endReg);
  8427     masm.addPtr(Imm32(BaselineFrame::offsetOfArg(0)), startReg);
  8428     JS_STATIC_ASSERT(sizeof(Value) == 8);
  8429     masm.lshiftPtr(Imm32(3), endReg);
  8430     masm.addPtr(startReg, endReg);
  8432     // Copying pre-decrements endReg by 8 until startReg is reached
  8433     Label copyDone;
  8434     Label copyStart;
  8435     masm.bind(&copyStart);
  8436     masm.branchPtr(Assembler::Equal, endReg, startReg, &copyDone);
  8437     masm.subPtr(Imm32(sizeof(Value)), endReg);
  8438     masm.pushValue(Address(endReg, 0));
  8439     masm.jump(&copyStart);
  8440     masm.bind(&copyDone);
  8443 void
  8444 ICCallStubCompiler::pushArrayArguments(MacroAssembler &masm, Address arrayVal,
  8445                                        GeneralRegisterSet regs)
  8447     // Load start and end address of values to copy.
  8448     // guardFunApply has already gauranteed that the array is packed and contains
  8449     // no holes.
  8450     Register startReg = regs.takeAny();
  8451     Register endReg = regs.takeAny();
  8452     masm.extractObject(arrayVal, startReg);
  8453     masm.loadPtr(Address(startReg, JSObject::offsetOfElements()), startReg);
  8454     masm.load32(Address(startReg, ObjectElements::offsetOfInitializedLength()), endReg);
  8455     JS_STATIC_ASSERT(sizeof(Value) == 8);
  8456     masm.lshiftPtr(Imm32(3), endReg);
  8457     masm.addPtr(startReg, endReg);
  8459     // Copying pre-decrements endReg by 8 until startReg is reached
  8460     Label copyDone;
  8461     Label copyStart;
  8462     masm.bind(&copyStart);
  8463     masm.branchPtr(Assembler::Equal, endReg, startReg, &copyDone);
  8464     masm.subPtr(Imm32(sizeof(Value)), endReg);
  8465     masm.pushValue(Address(endReg, 0));
  8466     masm.jump(&copyStart);
  8467     masm.bind(&copyDone);
  8470 typedef bool (*DoCallFallbackFn)(JSContext *, BaselineFrame *, ICCall_Fallback *,
  8471                                  uint32_t, Value *, MutableHandleValue);
  8472 static const VMFunction DoCallFallbackInfo = FunctionInfo<DoCallFallbackFn>(DoCallFallback);
  8474 bool
  8475 ICCall_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  8477     JS_ASSERT(R0 == JSReturnOperand);
  8479     // Push a stub frame so that we can perform a non-tail call.
  8480     enterStubFrame(masm, R1.scratchReg());
  8482     // Values are on the stack left-to-right. Calling convention wants them
  8483     // right-to-left so duplicate them on the stack in reverse order.
  8484     // |this| and callee are pushed last.
  8486     GeneralRegisterSet regs(availableGeneralRegs(0));
  8487     regs.take(R0.scratchReg()); // argc.
  8489     pushCallArguments(masm, regs, R0.scratchReg());
  8491     masm.push(BaselineStackReg);
  8492     masm.push(R0.scratchReg());
  8493     masm.push(BaselineStubReg);
  8495     // Load previous frame pointer, push BaselineFrame *.
  8496     masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg());
  8497     masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
  8499     if (!callVM(DoCallFallbackInfo, masm))
  8500         return false;
  8502     leaveStubFrame(masm);
  8503     EmitReturnFromIC(masm);
  8505     // The following asmcode is only used either when an Ion inlined frame
  8506     // bails out into baseline jitcode or we need to do on-stack script
  8507     // replacement for debug mode recompile.
  8508     Label leaveStubCommon;
  8509     returnFromStubOffset_ = masm.currentOffset();
  8511     // Load passed-in ThisV into R1 just in case it's needed.  Need to do this before
  8512     // we leave the stub frame since that info will be lost.
  8513     // Current stack:  [...., ThisV, ActualArgc, CalleeToken, Descriptor ]
  8514     masm.loadValue(Address(BaselineStackReg, 3 * sizeof(size_t)), R1);
  8516     // Emit the coming-from-VM specific part of the stub-leaving code.
  8517     leaveStubFrameHead(masm, /* calledIntoIon = */ false);
  8519     // Jump to the common leave stub tail.
  8520     masm.jump(&leaveStubCommon);
  8522     // For Ion bailouts, the return address pushed onto the reconstructed
  8523     // baseline stack points here.
  8524     returnFromIonOffset_ = masm.currentOffset();
  8526     masm.loadValue(Address(BaselineStackReg, 3 * sizeof(size_t)), R1);
  8528     // Emit the coming-from-Ion specific part of the stub-leaving code.
  8529     leaveStubFrameHead(masm, /* calledIntoIon = */ true);
  8531     // Emit the common stub-leaving tail.
  8532     masm.bind(&leaveStubCommon);
  8533     leaveStubFrameCommonTail(masm);
  8535     // R1 and R0 are taken.
  8536     regs = availableGeneralRegs(2);
  8537     Register scratch = regs.takeAny();
  8539     // If this is a |constructing| call, if the callee returns a non-object, we replace it with
  8540     // the |this| object passed in.
  8541     JS_ASSERT(JSReturnOperand == R0);
  8542     Label skipThisReplace;
  8543     masm.load16ZeroExtend(Address(BaselineStubReg, ICStub::offsetOfExtra()), scratch);
  8544     masm.branchTest32(Assembler::Zero, scratch, Imm32(ICCall_Fallback::CONSTRUCTING_FLAG),
  8545                       &skipThisReplace);
  8546     masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
  8547     masm.moveValue(R1, R0);
  8548 #ifdef DEBUG
  8549     masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
  8550     masm.assumeUnreachable("Failed to return object in constructing call.");
  8551 #endif
  8552     masm.bind(&skipThisReplace);
  8554     // At this point, BaselineStubReg points to the ICCall_Fallback stub, which is NOT
  8555     // a MonitoredStub, but rather a MonitoredFallbackStub.  To use EmitEnterTypeMonitorIC,
  8556     // first load the ICTypeMonitor_Fallback stub into BaselineStubReg.  Then, use
  8557     // EmitEnterTypeMonitorIC with a custom struct offset.
  8558     masm.loadPtr(Address(BaselineStubReg, ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()),
  8559                  BaselineStubReg);
  8560     EmitEnterTypeMonitorIC(masm, ICTypeMonitor_Fallback::offsetOfFirstMonitorStub());
  8562     return true;
  8565 bool
  8566 ICCall_Fallback::Compiler::postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code)
  8568     JitCompartment *comp = cx->compartment()->jitCompartment();
  8570     CodeOffsetLabel fromIon(returnFromIonOffset_);
  8571     fromIon.fixup(&masm);
  8572     comp->initBaselineCallReturnFromIonAddr(code->raw() + fromIon.offset());
  8574     CodeOffsetLabel fromVM(returnFromStubOffset_);
  8575     fromVM.fixup(&masm);
  8576     comp->initBaselineCallReturnFromStubAddr(code->raw() + fromVM.offset());
  8578     return true;
  8581 typedef bool (*CreateThisFn)(JSContext *cx, HandleObject callee, MutableHandleValue rval);
  8582 static const VMFunction CreateThisInfoBaseline = FunctionInfo<CreateThisFn>(CreateThis);
  8584 bool
  8585 ICCallScriptedCompiler::generateStubCode(MacroAssembler &masm)
  8587     Label failure;
  8588     GeneralRegisterSet regs(availableGeneralRegs(0));
  8589     bool canUseTailCallReg = regs.has(BaselineTailCallReg);
  8591     Register argcReg = R0.scratchReg();
  8592     JS_ASSERT(argcReg != ArgumentsRectifierReg);
  8594     regs.take(argcReg);
  8595     regs.take(ArgumentsRectifierReg);
  8596     regs.takeUnchecked(BaselineTailCallReg);
  8598     // Load the callee in R1.
  8599     // Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, +ICStackValueOffset+ ]
  8600     BaseIndex calleeSlot(BaselineStackReg, argcReg, TimesEight, ICStackValueOffset + sizeof(Value));
  8601     masm.loadValue(calleeSlot, R1);
  8602     regs.take(R1);
  8604     // Ensure callee is an object.
  8605     masm.branchTestObject(Assembler::NotEqual, R1, &failure);
  8607     // Ensure callee is a function.
  8608     Register callee = masm.extractObject(R1, ExtractTemp0);
  8609     masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &JSFunction::class_,
  8610                             &failure);
  8612     // If calling a specific script, check if the script matches.  Otherwise, ensure that
  8613     // callee function is scripted.  Leave calleeScript in |callee| reg.
  8614     if (calleeScript_) {
  8615         JS_ASSERT(kind == ICStub::Call_Scripted);
  8617         // Callee is a function.  Check if script matches.
  8618         masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
  8619         Address expectedScript(BaselineStubReg, ICCall_Scripted::offsetOfCalleeScript());
  8620         masm.branchPtr(Assembler::NotEqual, expectedScript, callee, &failure);
  8621     } else {
  8622         if (isConstructing_)
  8623             masm.branchIfNotInterpretedConstructor(callee, regs.getAny(), &failure);
  8624         else
  8625             masm.branchIfFunctionHasNoScript(callee, &failure);
  8626         masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
  8629     // Load the start of the target JitCode.
  8630     Register code;
  8631     if (!isConstructing_) {
  8632         code = regs.takeAny();
  8633         masm.loadBaselineOrIonRaw(callee, code, SequentialExecution, &failure);
  8634     } else {
  8635         Address scriptCode(callee, JSScript::offsetOfBaselineOrIonRaw());
  8636         masm.branchPtr(Assembler::Equal, scriptCode, ImmPtr(nullptr), &failure);
  8639     // We no longer need R1.
  8640     regs.add(R1);
  8642     // Push a stub frame so that we can perform a non-tail call.
  8643     enterStubFrame(masm, regs.getAny());
  8644     if (canUseTailCallReg)
  8645         regs.add(BaselineTailCallReg);
  8647     Label failureLeaveStubFrame;
  8649     if (isConstructing_) {
  8650         // Save argc before call.
  8651         masm.push(argcReg);
  8653         // Stack now looks like:
  8654         //      [..., Callee, ThisV, Arg0V, ..., ArgNV, StubFrameHeader, ArgC ]
  8655         BaseIndex calleeSlot2(BaselineStackReg, argcReg, TimesEight,
  8656                                sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t));
  8657         masm.loadValue(calleeSlot2, R1);
  8658         masm.push(masm.extractObject(R1, ExtractTemp0));
  8659         if (!callVM(CreateThisInfoBaseline, masm))
  8660             return false;
  8662         // Return of CreateThis must be an object.
  8663 #ifdef DEBUG
  8664         Label createdThisIsObject;
  8665         masm.branchTestObject(Assembler::Equal, JSReturnOperand, &createdThisIsObject);
  8666         masm.assumeUnreachable("The return of CreateThis must be an object.");
  8667         masm.bind(&createdThisIsObject);
  8668 #endif
  8670         // Reset the register set from here on in.
  8671         JS_ASSERT(JSReturnOperand == R0);
  8672         regs = availableGeneralRegs(0);
  8673         regs.take(R0);
  8674         regs.take(ArgumentsRectifierReg);
  8675         argcReg = regs.takeAny();
  8677         // Restore saved argc so we can use it to calculate the address to save
  8678         // the resulting this object to.
  8679         masm.pop(argcReg);
  8681         // Save "this" value back into pushed arguments on stack.  R0 can be clobbered after that.
  8682         // Stack now looks like:
  8683         //      [..., Callee, ThisV, Arg0V, ..., ArgNV, StubFrameHeader ]
  8684         BaseIndex thisSlot(BaselineStackReg, argcReg, TimesEight, STUB_FRAME_SIZE);
  8685         masm.storeValue(R0, thisSlot);
  8687         // Restore the stub register from the baseline stub frame.
  8688         masm.loadPtr(Address(BaselineStackReg, STUB_FRAME_SAVED_STUB_OFFSET), BaselineStubReg);
  8690         // Reload callee script. Note that a GC triggered by CreateThis may
  8691         // have destroyed the callee BaselineScript and IonScript. CreateThis is
  8692         // safely repeatable though, so in this case we just leave the stub frame
  8693         // and jump to the next stub.
  8695         // Just need to load the script now.
  8696         BaseIndex calleeSlot3(BaselineStackReg, argcReg, TimesEight,
  8697                                sizeof(Value) + STUB_FRAME_SIZE);
  8698         masm.loadValue(calleeSlot3, R0);
  8699         callee = masm.extractObject(R0, ExtractTemp0);
  8700         regs.add(R0);
  8701         regs.takeUnchecked(callee);
  8702         masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
  8704         code = regs.takeAny();
  8705         masm.loadBaselineOrIonRaw(callee, code, SequentialExecution, &failureLeaveStubFrame);
  8707         // Release callee register, but don't add ExtractTemp0 back into the pool
  8708         // ExtractTemp0 is used later, and if it's allocated to some other register at that
  8709         // point, it will get clobbered when used.
  8710         if (callee != ExtractTemp0)
  8711             regs.add(callee);
  8713         if (canUseTailCallReg)
  8714             regs.addUnchecked(BaselineTailCallReg);
  8716     Register scratch = regs.takeAny();
  8718     // Values are on the stack left-to-right. Calling convention wants them
  8719     // right-to-left so duplicate them on the stack in reverse order.
  8720     // |this| and callee are pushed last.
  8721     pushCallArguments(masm, regs, argcReg);
  8723     // The callee is on top of the stack. Pop and unbox it.
  8724     ValueOperand val = regs.takeAnyValue();
  8725     masm.popValue(val);
  8726     callee = masm.extractObject(val, ExtractTemp0);
  8728     EmitCreateStubFrameDescriptor(masm, scratch);
  8730     // Note that we use Push, not push, so that callIon will align the stack
  8731     // properly on ARM.
  8732     masm.Push(argcReg);
  8733     masm.Push(callee);
  8734     masm.Push(scratch);
  8736     // Handle arguments underflow.
  8737     Label noUnderflow;
  8738     masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), callee);
  8739     masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
  8741         // Call the arguments rectifier.
  8742         JS_ASSERT(ArgumentsRectifierReg != code);
  8743         JS_ASSERT(ArgumentsRectifierReg != argcReg);
  8745         JitCode *argumentsRectifier =
  8746             cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
  8748         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
  8749         masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
  8750         masm.mov(argcReg, ArgumentsRectifierReg);
  8753     masm.bind(&noUnderflow);
  8755     // If needed, update SPS Profiler frame entry before and after call.
  8757         JS_ASSERT(kind == ICStub::Call_Scripted || kind == ICStub::Call_AnyScripted);
  8758         GeneralRegisterSet availRegs = availableGeneralRegs(0);
  8759         availRegs.take(ArgumentsRectifierReg);
  8760         availRegs.take(code);
  8761         emitProfilingUpdate(masm, availRegs, kind == ICStub::Call_Scripted ?
  8762                                                 ICCall_Scripted::offsetOfPCOffset()
  8763                                               : ICCall_AnyScripted::offsetOfPCOffset());
  8766     masm.callIon(code);
  8768     // If this is a constructing call, and the callee returns a non-object, replace it with
  8769     // the |this| object passed in.
  8770     if (isConstructing_) {
  8771         Label skipThisReplace;
  8772         masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
  8774         Register scratchReg = JSReturnOperand.scratchReg();
  8776         // Current stack: [ ARGVALS..., ThisVal, ActualArgc, Callee, Descriptor ]
  8777         // However, we can't use this ThisVal, because it hasn't been traced.  We need to use
  8778         // The ThisVal higher up the stack:
  8779         // Current stack: [ ThisVal, ARGVALS..., ...STUB FRAME...,
  8780         //                  ARGVALS..., ThisVal, ActualArgc, Callee, Descriptor ]
  8781         masm.loadPtr(Address(BaselineStackReg, 2*sizeof(size_t)), scratchReg);
  8783         // scratchReg now contains actualArgCount.  Double it to account for skipping past two
  8784         // pushed copies of argument values.  Additionally, we need to add:
  8785         // STUB_FRAME_SIZE + sizeof(ThisVal) + sizeof(size_t) + sizeof(void *) + sizoef(size_t)
  8786         // for: stub frame, this value, actual argc, callee, and descriptor
  8787         masm.lshiftPtr(Imm32(1), scratchReg);
  8788         BaseIndex reloadThisSlot(BaselineStackReg, scratchReg, TimesEight,
  8789                                  STUB_FRAME_SIZE + sizeof(Value) + 3*sizeof(size_t));
  8790         masm.loadValue(reloadThisSlot, JSReturnOperand);
  8791 #ifdef DEBUG
  8792         masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
  8793         masm.assumeUnreachable("Return of constructing call should be an object.");
  8794 #endif
  8795         masm.bind(&skipThisReplace);
  8798     leaveStubFrame(masm, true);
  8800     // Enter type monitor IC to type-check result.
  8801     EmitEnterTypeMonitorIC(masm);
  8803     // Leave stub frame and restore argc for the next stub.
  8804     masm.bind(&failureLeaveStubFrame);
  8805     leaveStubFrame(masm, false);
  8806     if (argcReg != R0.scratchReg())
  8807         masm.mov(argcReg, R0.scratchReg());
  8809     masm.bind(&failure);
  8810     EmitStubGuardFailure(masm);
  8811     return true;
  8814 bool
  8815 ICCall_Native::Compiler::generateStubCode(MacroAssembler &masm)
  8817     Label failure;
  8818     GeneralRegisterSet regs(availableGeneralRegs(0));
  8820     Register argcReg = R0.scratchReg();
  8821     regs.take(argcReg);
  8822     regs.takeUnchecked(BaselineTailCallReg);
  8824     // Load the callee in R1.
  8825     BaseIndex calleeSlot(BaselineStackReg, argcReg, TimesEight, ICStackValueOffset + sizeof(Value));
  8826     masm.loadValue(calleeSlot, R1);
  8827     regs.take(R1);
  8829     masm.branchTestObject(Assembler::NotEqual, R1, &failure);
  8831     // Ensure callee matches this stub's callee.
  8832     Register callee = masm.extractObject(R1, ExtractTemp0);
  8833     Address expectedCallee(BaselineStubReg, ICCall_Native::offsetOfCallee());
  8834     masm.branchPtr(Assembler::NotEqual, expectedCallee, callee, &failure);
  8836     regs.add(R1);
  8837     regs.takeUnchecked(callee);
  8839     // Push a stub frame so that we can perform a non-tail call.
  8840     // Note that this leaves the return address in TailCallReg.
  8841     enterStubFrame(masm, regs.getAny());
  8843     // Values are on the stack left-to-right. Calling convention wants them
  8844     // right-to-left so duplicate them on the stack in reverse order.
  8845     // |this| and callee are pushed last.
  8846     pushCallArguments(masm, regs, argcReg);
  8848     if (isConstructing_) {
  8849         // Stack looks like: [ ..., Arg0Val, ThisVal, CalleeVal ]
  8850         // Replace ThisVal with MagicValue(JS_IS_CONSTRUCTING)
  8851         masm.storeValue(MagicValue(JS_IS_CONSTRUCTING), Address(BaselineStackReg, sizeof(Value)));
  8854     masm.checkStackAlignment();
  8856     // Native functions have the signature:
  8857     //
  8858     //    bool (*)(JSContext *, unsigned, Value *vp)
  8859     //
  8860     // Where vp[0] is space for callee/return value, vp[1] is |this|, and vp[2] onward
  8861     // are the function arguments.
  8863     // Initialize vp.
  8864     Register vpReg = regs.takeAny();
  8865     masm.movePtr(StackPointer, vpReg);
  8867     // Construct a native exit frame.
  8868     masm.push(argcReg);
  8870     Register scratch = regs.takeAny();
  8871     EmitCreateStubFrameDescriptor(masm, scratch);
  8872     masm.push(scratch);
  8873     masm.push(BaselineTailCallReg);
  8874     masm.enterFakeExitFrame();
  8876     // If needed, update SPS Profiler frame entry.  At this point, BaselineTailCallReg
  8877     // and scratch can be clobbered.
  8878     emitProfilingUpdate(masm, BaselineTailCallReg, scratch, ICCall_Native::offsetOfPCOffset());
  8880     // Execute call.
  8881     masm.setupUnalignedABICall(3, scratch);
  8882     masm.loadJSContext(scratch);
  8883     masm.passABIArg(scratch);
  8884     masm.passABIArg(argcReg);
  8885     masm.passABIArg(vpReg);
  8887 #ifdef JS_ARM_SIMULATOR
  8888     // The simulator requires VM calls to be redirected to a special swi
  8889     // instruction to handle them, so we store the redirected pointer in the
  8890     // stub and use that instead of the original one.
  8891     masm.callWithABI(Address(BaselineStubReg, ICCall_Native::offsetOfNative()));
  8892 #else
  8893     masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript()));
  8894 #endif
  8896     // Test for failure.
  8897     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
  8899     // Load the return value into R0.
  8900     masm.loadValue(Address(StackPointer, IonNativeExitFrameLayout::offsetOfResult()), R0);
  8902     leaveStubFrame(masm);
  8904     // Enter type monitor IC to type-check result.
  8905     EmitEnterTypeMonitorIC(masm);
  8907     masm.bind(&failure);
  8908     EmitStubGuardFailure(masm);
  8909     return true;
  8912 bool
  8913 ICCall_ScriptedApplyArray::Compiler::generateStubCode(MacroAssembler &masm)
  8915     Label failure;
  8916     GeneralRegisterSet regs(availableGeneralRegs(0));
  8918     Register argcReg = R0.scratchReg();
  8919     regs.take(argcReg);
  8920     regs.takeUnchecked(BaselineTailCallReg);
  8921     regs.takeUnchecked(ArgumentsRectifierReg);
  8923     //
  8924     // Validate inputs
  8925     //
  8927     Register target = guardFunApply(masm, regs, argcReg, /*checkNative=*/false,
  8928                                     FunApply_Array, &failure);
  8929     if (regs.has(target)) {
  8930         regs.take(target);
  8931     } else {
  8932         // If target is already a reserved reg, take another register for it, because it's
  8933         // probably currently an ExtractTemp, which might get clobbered later.
  8934         Register targetTemp = regs.takeAny();
  8935         masm.movePtr(target, targetTemp);
  8936         target = targetTemp;
  8939     // Push a stub frame so that we can perform a non-tail call.
  8940     enterStubFrame(masm, regs.getAny());
  8942     //
  8943     // Push arguments
  8944     //
  8946     // Stack now looks like:
  8947     //                                      BaselineFrameReg -------------------.
  8948     //                                                                          v
  8949     //      [..., js_fun_apply, TargetV, TargetThisV, ArgsArrayV, StubFrameHeader]
  8951     // Push all array elements onto the stack:
  8952     Address arrayVal(BaselineFrameReg, STUB_FRAME_SIZE);
  8953     pushArrayArguments(masm, arrayVal, regs);
  8955     // Stack now looks like:
  8956     //                                      BaselineFrameReg -------------------.
  8957     //                                                                          v
  8958     //      [..., js_fun_apply, TargetV, TargetThisV, ArgsArrayV, StubFrameHeader,
  8959     //       PushedArgN, ..., PushedArg0]
  8960     // Can't fail after this, so it's ok to clobber argcReg.
  8962     // Push actual argument 0 as |thisv| for call.
  8963     masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + sizeof(Value)));
  8965     // All pushes after this use Push instead of push to make sure ARM can align
  8966     // stack properly for call.
  8967     Register scratch = regs.takeAny();
  8968     EmitCreateStubFrameDescriptor(masm, scratch);
  8970     // Reload argc from length of array.
  8971     masm.extractObject(arrayVal, argcReg);
  8972     masm.loadPtr(Address(argcReg, JSObject::offsetOfElements()), argcReg);
  8973     masm.load32(Address(argcReg, ObjectElements::offsetOfInitializedLength()), argcReg);
  8975     masm.Push(argcReg);
  8976     masm.Push(target);
  8977     masm.Push(scratch);
  8979     // Load nargs into scratch for underflow check, and then load jitcode pointer into target.
  8980     masm.load16ZeroExtend(Address(target, JSFunction::offsetOfNargs()), scratch);
  8981     masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), target);
  8982     masm.loadBaselineOrIonRaw(target, target, SequentialExecution, nullptr);
  8984     // Handle arguments underflow.
  8985     Label noUnderflow;
  8986     masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
  8988         // Call the arguments rectifier.
  8989         JS_ASSERT(ArgumentsRectifierReg != target);
  8990         JS_ASSERT(ArgumentsRectifierReg != argcReg);
  8992         JitCode *argumentsRectifier =
  8993             cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
  8995         masm.movePtr(ImmGCPtr(argumentsRectifier), target);
  8996         masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
  8997         masm.mov(argcReg, ArgumentsRectifierReg);
  8999     masm.bind(&noUnderflow);
  9000     regs.add(argcReg);
  9002     // If needed, update SPS Profiler frame entry.  At this point, BaselineTailCallReg
  9003     // and scratch can be clobbered.
  9004     emitProfilingUpdate(masm, regs.getAny(), scratch,
  9005                         ICCall_ScriptedApplyArguments::offsetOfPCOffset());
  9007     // Do call
  9008     masm.callIon(target);
  9009     leaveStubFrame(masm, true);
  9011     // Enter type monitor IC to type-check result.
  9012     EmitEnterTypeMonitorIC(masm);
  9014     masm.bind(&failure);
  9015     EmitStubGuardFailure(masm);
  9016     return true;
  9019 bool
  9020 ICCall_ScriptedApplyArguments::Compiler::generateStubCode(MacroAssembler &masm)
  9022     Label failure;
  9023     GeneralRegisterSet regs(availableGeneralRegs(0));
  9025     Register argcReg = R0.scratchReg();
  9026     regs.take(argcReg);
  9027     regs.takeUnchecked(BaselineTailCallReg);
  9028     regs.takeUnchecked(ArgumentsRectifierReg);
  9030     //
  9031     // Validate inputs
  9032     //
  9034     Register target = guardFunApply(masm, regs, argcReg, /*checkNative=*/false,
  9035                                     FunApply_MagicArgs, &failure);
  9036     if (regs.has(target)) {
  9037         regs.take(target);
  9038     } else {
  9039         // If target is already a reserved reg, take another register for it, because it's
  9040         // probably currently an ExtractTemp, which might get clobbered later.
  9041         Register targetTemp = regs.takeAny();
  9042         masm.movePtr(target, targetTemp);
  9043         target = targetTemp;
  9046     // Push a stub frame so that we can perform a non-tail call.
  9047     enterStubFrame(masm, regs.getAny());
  9049     //
  9050     // Push arguments
  9051     //
  9053     // Stack now looks like:
  9054     //      [..., js_fun_apply, TargetV, TargetThisV, MagicArgsV, StubFrameHeader]
  9056     // Push all arguments supplied to caller function onto the stack.
  9057     pushCallerArguments(masm, regs);
  9059     // Stack now looks like:
  9060     //                                      BaselineFrameReg -------------------.
  9061     //                                                                          v
  9062     //      [..., js_fun_apply, TargetV, TargetThisV, MagicArgsV, StubFrameHeader,
  9063     //       PushedArgN, ..., PushedArg0]
  9064     // Can't fail after this, so it's ok to clobber argcReg.
  9066     // Push actual argument 0 as |thisv| for call.
  9067     masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + sizeof(Value)));
  9069     // All pushes after this use Push instead of push to make sure ARM can align
  9070     // stack properly for call.
  9071     Register scratch = regs.takeAny();
  9072     EmitCreateStubFrameDescriptor(masm, scratch);
  9074     masm.loadPtr(Address(BaselineFrameReg, 0), argcReg);
  9075     masm.loadPtr(Address(argcReg, BaselineFrame::offsetOfNumActualArgs()), argcReg);
  9076     masm.Push(argcReg);
  9077     masm.Push(target);
  9078     masm.Push(scratch);
  9080     // Load nargs into scratch for underflow check, and then load jitcode pointer into target.
  9081     masm.load16ZeroExtend(Address(target, JSFunction::offsetOfNargs()), scratch);
  9082     masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), target);
  9083     masm.loadBaselineOrIonRaw(target, target, SequentialExecution, nullptr);
  9085     // Handle arguments underflow.
  9086     Label noUnderflow;
  9087     masm.branch32(Assembler::AboveOrEqual, argcReg, scratch, &noUnderflow);
  9089         // Call the arguments rectifier.
  9090         JS_ASSERT(ArgumentsRectifierReg != target);
  9091         JS_ASSERT(ArgumentsRectifierReg != argcReg);
  9093         JitCode *argumentsRectifier =
  9094             cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
  9096         masm.movePtr(ImmGCPtr(argumentsRectifier), target);
  9097         masm.loadPtr(Address(target, JitCode::offsetOfCode()), target);
  9098         masm.mov(argcReg, ArgumentsRectifierReg);
  9100     masm.bind(&noUnderflow);
  9101     regs.add(argcReg);
  9103     // If needed, update SPS Profiler frame entry.  At this point, BaselineTailCallReg
  9104     // and scratch can be clobbered.
  9105     emitProfilingUpdate(masm, regs.getAny(), scratch,
  9106                         ICCall_ScriptedApplyArguments::offsetOfPCOffset());
  9108     // Do call
  9109     masm.callIon(target);
  9110     leaveStubFrame(masm, true);
  9112     // Enter type monitor IC to type-check result.
  9113     EmitEnterTypeMonitorIC(masm);
  9115     masm.bind(&failure);
  9116     EmitStubGuardFailure(masm);
  9117     return true;
  9120 bool
  9121 ICCall_ScriptedFunCall::Compiler::generateStubCode(MacroAssembler &masm)
  9123     Label failure;
  9124     GeneralRegisterSet regs(availableGeneralRegs(0));
  9125     bool canUseTailCallReg = regs.has(BaselineTailCallReg);
  9127     Register argcReg = R0.scratchReg();
  9128     JS_ASSERT(argcReg != ArgumentsRectifierReg);
  9130     regs.take(argcReg);
  9131     regs.take(ArgumentsRectifierReg);
  9132     regs.takeUnchecked(BaselineTailCallReg);
  9134     // Load the callee in R1.
  9135     // Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, +ICStackValueOffset+ ]
  9136     BaseIndex calleeSlot(BaselineStackReg, argcReg, TimesEight, ICStackValueOffset + sizeof(Value));
  9137     masm.loadValue(calleeSlot, R1);
  9138     regs.take(R1);
  9140     // Ensure callee is js_fun_call.
  9141     masm.branchTestObject(Assembler::NotEqual, R1, &failure);
  9143     Register callee = masm.extractObject(R1, ExtractTemp0);
  9144     masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &JSFunction::class_,
  9145                             &failure);
  9146     masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
  9147     masm.branchPtr(Assembler::NotEqual, callee, ImmPtr(js_fun_call), &failure);
  9149     // Ensure |this| is a scripted function with JIT code.
  9150     BaseIndex thisSlot(BaselineStackReg, argcReg, TimesEight, ICStackValueOffset);
  9151     masm.loadValue(thisSlot, R1);
  9153     masm.branchTestObject(Assembler::NotEqual, R1, &failure);
  9154     callee = masm.extractObject(R1, ExtractTemp0);
  9156     masm.branchTestObjClass(Assembler::NotEqual, callee, regs.getAny(), &JSFunction::class_,
  9157                             &failure);
  9158     masm.branchIfFunctionHasNoScript(callee, &failure);
  9159     masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
  9161     // Load the start of the target JitCode.
  9162     Register code = regs.takeAny();
  9163     masm.loadBaselineOrIonRaw(callee, code, SequentialExecution, &failure);
  9165     // We no longer need R1.
  9166     regs.add(R1);
  9168     // Push a stub frame so that we can perform a non-tail call.
  9169     enterStubFrame(masm, regs.getAny());
  9170     if (canUseTailCallReg)
  9171         regs.add(BaselineTailCallReg);
  9173     // Values are on the stack left-to-right. Calling convention wants them
  9174     // right-to-left so duplicate them on the stack in reverse order.
  9175     pushCallArguments(masm, regs, argcReg);
  9177     // Discard callee (function.call).
  9178     masm.addPtr(Imm32(sizeof(Value)), StackPointer);
  9180     // Pop scripted callee (the original |this|).
  9181     ValueOperand val = regs.takeAnyValue();
  9182     masm.popValue(val);
  9184     // Decrement argc if argc > 0. If argc == 0, push |undefined| as |this|.
  9185     Label zeroArgs, done;
  9186     masm.branchTest32(Assembler::Zero, argcReg, argcReg, &zeroArgs);
  9187     masm.sub32(Imm32(1), argcReg);
  9188     masm.jump(&done);
  9190     masm.bind(&zeroArgs);
  9191     masm.pushValue(UndefinedValue());
  9192     masm.bind(&done);
  9194     // Unbox scripted callee.
  9195     callee = masm.extractObject(val, ExtractTemp0);
  9197     Register scratch = regs.takeAny();
  9198     EmitCreateStubFrameDescriptor(masm, scratch);
  9200     // Note that we use Push, not push, so that callIon will align the stack
  9201     // properly on ARM.
  9202     masm.Push(argcReg);
  9203     masm.Push(callee);
  9204     masm.Push(scratch);
  9206     // Handle arguments underflow.
  9207     Label noUnderflow;
  9208     masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), callee);
  9209     masm.branch32(Assembler::AboveOrEqual, argcReg, callee, &noUnderflow);
  9211         // Call the arguments rectifier.
  9212         JS_ASSERT(ArgumentsRectifierReg != code);
  9213         JS_ASSERT(ArgumentsRectifierReg != argcReg);
  9215         JitCode *argumentsRectifier =
  9216             cx->runtime()->jitRuntime()->getArgumentsRectifier(SequentialExecution);
  9218         masm.movePtr(ImmGCPtr(argumentsRectifier), code);
  9219         masm.loadPtr(Address(code, JitCode::offsetOfCode()), code);
  9220         masm.mov(argcReg, ArgumentsRectifierReg);
  9223     masm.bind(&noUnderflow);
  9225     // If needed, update SPS Profiler frame entry.
  9227         // Need to avoid using ArgumentsRectifierReg and code register.
  9228         GeneralRegisterSet availRegs = availableGeneralRegs(0);
  9229         availRegs.take(ArgumentsRectifierReg);
  9230         availRegs.take(code);
  9231         emitProfilingUpdate(masm, availRegs, ICCall_ScriptedFunCall::offsetOfPCOffset());
  9234     masm.callIon(code);
  9236     leaveStubFrame(masm, true);
  9238     // Enter type monitor IC to type-check result.
  9239     EmitEnterTypeMonitorIC(masm);
  9241     masm.bind(&failure);
  9242     EmitStubGuardFailure(masm);
  9243     return true;
  9246 static bool
  9247 DoubleValueToInt32ForSwitch(Value *v)
  9249     double d = v->toDouble();
  9250     int32_t truncated = int32_t(d);
  9251     if (d != double(truncated))
  9252         return false;
  9254     v->setInt32(truncated);
  9255     return true;
  9258 bool
  9259 ICTableSwitch::Compiler::generateStubCode(MacroAssembler &masm)
  9261     Label isInt32, notInt32, outOfRange;
  9262     Register scratch = R1.scratchReg();
  9264     masm.branchTestInt32(Assembler::NotEqual, R0, &notInt32);
  9266     Register key = masm.extractInt32(R0, ExtractTemp0);
  9268     masm.bind(&isInt32);
  9270     masm.load32(Address(BaselineStubReg, offsetof(ICTableSwitch, min_)), scratch);
  9271     masm.sub32(scratch, key);
  9272     masm.branch32(Assembler::BelowOrEqual,
  9273                   Address(BaselineStubReg, offsetof(ICTableSwitch, length_)), key, &outOfRange);
  9275     masm.loadPtr(Address(BaselineStubReg, offsetof(ICTableSwitch, table_)), scratch);
  9276     masm.loadPtr(BaseIndex(scratch, key, ScalePointer), scratch);
  9278     EmitChangeICReturnAddress(masm, scratch);
  9279     EmitReturnFromIC(masm);
  9281     masm.bind(&notInt32);
  9283     masm.branchTestDouble(Assembler::NotEqual, R0, &outOfRange);
  9284     if (cx->runtime()->jitSupportsFloatingPoint) {
  9285         masm.unboxDouble(R0, FloatReg0);
  9287         // N.B. -0 === 0, so convert -0 to a 0 int32.
  9288         masm.convertDoubleToInt32(FloatReg0, key, &outOfRange, /* negativeZeroCheck = */ false);
  9289     } else {
  9290         // Pass pointer to double value.
  9291         masm.pushValue(R0);
  9292         masm.movePtr(StackPointer, R0.scratchReg());
  9294         masm.setupUnalignedABICall(1, scratch);
  9295         masm.passABIArg(R0.scratchReg());
  9296         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, DoubleValueToInt32ForSwitch));
  9298         // If the function returns |true|, the value has been converted to
  9299         // int32.
  9300         masm.mov(ReturnReg, scratch);
  9301         masm.popValue(R0);
  9302         masm.branchIfFalseBool(scratch, &outOfRange);
  9303         masm.unboxInt32(R0, key);
  9305     masm.jump(&isInt32);
  9307     masm.bind(&outOfRange);
  9309     masm.loadPtr(Address(BaselineStubReg, offsetof(ICTableSwitch, defaultTarget_)), scratch);
  9311     EmitChangeICReturnAddress(masm, scratch);
  9312     EmitReturnFromIC(masm);
  9313     return true;
  9316 ICStub *
  9317 ICTableSwitch::Compiler::getStub(ICStubSpace *space)
  9319     JitCode *code = getStubCode();
  9320     if (!code)
  9321         return nullptr;
  9323     jsbytecode *pc = pc_;
  9324     pc += JUMP_OFFSET_LEN;
  9325     int32_t low = GET_JUMP_OFFSET(pc);
  9326     pc += JUMP_OFFSET_LEN;
  9327     int32_t high = GET_JUMP_OFFSET(pc);
  9328     int32_t length = high - low + 1;
  9329     pc += JUMP_OFFSET_LEN;
  9331     void **table = (void**) space->alloc(sizeof(void*) * length);
  9332     if (!table)
  9333         return nullptr;
  9335     jsbytecode *defaultpc = pc_ + GET_JUMP_OFFSET(pc_);
  9337     for (int32_t i = 0; i < length; i++) {
  9338         int32_t off = GET_JUMP_OFFSET(pc);
  9339         if (off)
  9340             table[i] = pc_ + off;
  9341         else
  9342             table[i] = defaultpc;
  9343         pc += JUMP_OFFSET_LEN;
  9346     return ICTableSwitch::New(space, code, table, low, length, defaultpc);
  9349 void
  9350 ICTableSwitch::fixupJumpTable(JSScript *script, BaselineScript *baseline)
  9352     defaultTarget_ = baseline->nativeCodeForPC(script, (jsbytecode *) defaultTarget_);
  9354     for (int32_t i = 0; i < length_; i++)
  9355         table_[i] = baseline->nativeCodeForPC(script, (jsbytecode *) table_[i]);
  9358 //
  9359 // IteratorNew_Fallback
  9360 //
  9362 static bool
  9363 DoIteratorNewFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNew_Fallback *stub,
  9364                       HandleValue value, MutableHandleValue res)
  9366     jsbytecode *pc = stub->icEntry()->pc(frame->script());
  9367     FallbackICSpew(cx, stub, "IteratorNew");
  9369     uint8_t flags = GET_UINT8(pc);
  9370     res.set(value);
  9371     return ValueToIterator(cx, flags, res);
  9374 typedef bool (*DoIteratorNewFallbackFn)(JSContext *, BaselineFrame *, ICIteratorNew_Fallback *,
  9375                                         HandleValue, MutableHandleValue);
  9376 static const VMFunction DoIteratorNewFallbackInfo =
  9377     FunctionInfo<DoIteratorNewFallbackFn>(DoIteratorNewFallback, PopValues(1));
  9379 bool
  9380 ICIteratorNew_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  9382     EmitRestoreTailCallReg(masm);
  9384     // Sync stack for the decompiler.
  9385     masm.pushValue(R0);
  9387     masm.pushValue(R0);
  9388     masm.push(BaselineStubReg);
  9389     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  9391     return tailCallVM(DoIteratorNewFallbackInfo, masm);
  9394 //
  9395 // IteratorMore_Fallback
  9396 //
  9398 static bool
  9399 DoIteratorMoreFallback(JSContext *cx, BaselineFrame *frame, ICIteratorMore_Fallback *stub_,
  9400                        HandleValue iterValue, MutableHandleValue res)
  9402     // This fallback stub may trigger debug mode toggling.
  9403     DebugModeOSRVolatileStub<ICIteratorMore_Fallback *> stub(frame, stub_);
  9405     FallbackICSpew(cx, stub, "IteratorMore");
  9407     bool cond;
  9408     if (!IteratorMore(cx, &iterValue.toObject(), &cond, res))
  9409         return false;
  9410     res.setBoolean(cond);
  9412     // Check if debug mode toggling made the stub invalid.
  9413     if (stub.invalid())
  9414         return true;
  9416     if (iterValue.toObject().is<PropertyIteratorObject>() &&
  9417         !stub->hasStub(ICStub::IteratorMore_Native))
  9419         ICIteratorMore_Native::Compiler compiler(cx);
  9420         ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
  9421         if (!newStub)
  9422             return false;
  9423         stub->addNewStub(newStub);
  9426     return true;
  9429 typedef bool (*DoIteratorMoreFallbackFn)(JSContext *, BaselineFrame *, ICIteratorMore_Fallback *,
  9430                                          HandleValue, MutableHandleValue);
  9431 static const VMFunction DoIteratorMoreFallbackInfo =
  9432     FunctionInfo<DoIteratorMoreFallbackFn>(DoIteratorMoreFallback);
  9434 bool
  9435 ICIteratorMore_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  9437     EmitRestoreTailCallReg(masm);
  9439     masm.pushValue(R0);
  9440     masm.push(BaselineStubReg);
  9441     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  9443     return tailCallVM(DoIteratorMoreFallbackInfo, masm);
  9446 //
  9447 // IteratorMore_Native
  9448 //
  9450 bool
  9451 ICIteratorMore_Native::Compiler::generateStubCode(MacroAssembler &masm)
  9453     Label failure;
  9455     Register obj = masm.extractObject(R0, ExtractTemp0);
  9457     GeneralRegisterSet regs(availableGeneralRegs(1));
  9458     Register nativeIterator = regs.takeAny();
  9459     Register scratch = regs.takeAny();
  9461     masm.branchTestObjClass(Assembler::NotEqual, obj, scratch,
  9462                             &PropertyIteratorObject::class_, &failure);
  9463     masm.loadObjPrivate(obj, JSObject::ITER_CLASS_NFIXED_SLOTS, nativeIterator);
  9465     masm.branchTest32(Assembler::NonZero, Address(nativeIterator, offsetof(NativeIterator, flags)),
  9466                       Imm32(JSITER_FOREACH), &failure);
  9468     // Set output to true if props_cursor < props_end.
  9469     masm.loadPtr(Address(nativeIterator, offsetof(NativeIterator, props_end)), scratch);
  9470     Address cursorAddr = Address(nativeIterator, offsetof(NativeIterator, props_cursor));
  9471     masm.cmpPtrSet(Assembler::LessThan, cursorAddr, scratch, scratch);
  9473     masm.tagValue(JSVAL_TYPE_BOOLEAN, scratch, R0);
  9474     EmitReturnFromIC(masm);
  9476     // Failure case - jump to next stub
  9477     masm.bind(&failure);
  9478     EmitStubGuardFailure(masm);
  9479     return true;
  9482 //
  9483 // IteratorNext_Fallback
  9484 //
  9486 static bool
  9487 DoIteratorNextFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNext_Fallback *stub_,
  9488                        HandleValue iterValue, MutableHandleValue res)
  9490     // This fallback stub may trigger debug mode toggling.
  9491     DebugModeOSRVolatileStub<ICIteratorNext_Fallback *> stub(frame, stub_);
  9493     FallbackICSpew(cx, stub, "IteratorNext");
  9495     RootedObject iteratorObject(cx, &iterValue.toObject());
  9496     if (!IteratorNext(cx, iteratorObject, res))
  9497         return false;
  9499     // Check if debug mode toggling made the stub invalid.
  9500     if (stub.invalid())
  9501         return true;
  9503     if (!res.isString() && !stub->hasNonStringResult())
  9504         stub->setHasNonStringResult();
  9506     if (iteratorObject->is<PropertyIteratorObject>() &&
  9507         !stub->hasStub(ICStub::IteratorNext_Native))
  9509         ICIteratorNext_Native::Compiler compiler(cx);
  9510         ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
  9511         if (!newStub)
  9512             return false;
  9513         stub->addNewStub(newStub);
  9516     return true;
  9519 typedef bool (*DoIteratorNextFallbackFn)(JSContext *, BaselineFrame *, ICIteratorNext_Fallback *,
  9520                                          HandleValue, MutableHandleValue);
  9521 static const VMFunction DoIteratorNextFallbackInfo =
  9522     FunctionInfo<DoIteratorNextFallbackFn>(DoIteratorNextFallback);
  9524 bool
  9525 ICIteratorNext_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  9527     EmitRestoreTailCallReg(masm);
  9529     masm.pushValue(R0);
  9530     masm.push(BaselineStubReg);
  9531     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  9533     return tailCallVM(DoIteratorNextFallbackInfo, masm);
  9536 //
  9537 // IteratorNext_Native
  9538 //
  9540 bool
  9541 ICIteratorNext_Native::Compiler::generateStubCode(MacroAssembler &masm)
  9543     Label failure;
  9545     Register obj = masm.extractObject(R0, ExtractTemp0);
  9547     GeneralRegisterSet regs(availableGeneralRegs(1));
  9548     Register nativeIterator = regs.takeAny();
  9549     Register scratch = regs.takeAny();
  9551     masm.branchTestObjClass(Assembler::NotEqual, obj, scratch,
  9552                             &PropertyIteratorObject::class_, &failure);
  9553     masm.loadObjPrivate(obj, JSObject::ITER_CLASS_NFIXED_SLOTS, nativeIterator);
  9555     masm.branchTest32(Assembler::NonZero, Address(nativeIterator, offsetof(NativeIterator, flags)),
  9556                       Imm32(JSITER_FOREACH), &failure);
  9558     // Get cursor, next string.
  9559     masm.loadPtr(Address(nativeIterator, offsetof(NativeIterator, props_cursor)), scratch);
  9560     masm.loadPtr(Address(scratch, 0), scratch);
  9562     // Increase the cursor.
  9563     masm.addPtr(Imm32(sizeof(JSString *)),
  9564                 Address(nativeIterator, offsetof(NativeIterator, props_cursor)));
  9566     masm.tagValue(JSVAL_TYPE_STRING, scratch, R0);
  9567     EmitReturnFromIC(masm);
  9569     // Failure case - jump to next stub
  9570     masm.bind(&failure);
  9571     EmitStubGuardFailure(masm);
  9572     return true;
  9575 //
  9576 // IteratorClose_Fallback
  9577 //
  9579 static bool
  9580 DoIteratorCloseFallback(JSContext *cx, ICIteratorClose_Fallback *stub, HandleValue iterValue)
  9582     FallbackICSpew(cx, stub, "IteratorClose");
  9584     RootedObject iteratorObject(cx, &iterValue.toObject());
  9585     return CloseIterator(cx, iteratorObject);
  9588 typedef bool (*DoIteratorCloseFallbackFn)(JSContext *, ICIteratorClose_Fallback *, HandleValue);
  9589 static const VMFunction DoIteratorCloseFallbackInfo =
  9590     FunctionInfo<DoIteratorCloseFallbackFn>(DoIteratorCloseFallback);
  9592 bool
  9593 ICIteratorClose_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  9595     EmitRestoreTailCallReg(masm);
  9597     masm.pushValue(R0);
  9598     masm.push(BaselineStubReg);
  9600     return tailCallVM(DoIteratorCloseFallbackInfo, masm);
  9603 //
  9604 // InstanceOf_Fallback
  9605 //
  9607 static bool
  9608 DoInstanceOfFallback(JSContext *cx, ICInstanceOf_Fallback *stub,
  9609                      HandleValue lhs, HandleValue rhs,
  9610                      MutableHandleValue res)
  9612     FallbackICSpew(cx, stub, "InstanceOf");
  9614     if (!rhs.isObject()) {
  9615         js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rhs, NullPtr());
  9616         return false;
  9619     RootedObject obj(cx, &rhs.toObject());
  9621     // For functions, keep track of the |prototype| property in type information,
  9622     // for use during Ion compilation.
  9623     if (obj->is<JSFunction>() && IsIonEnabled(cx))
  9624         types::EnsureTrackPropertyTypes(cx, obj, NameToId(cx->names().prototype));
  9626     bool cond = false;
  9627     if (!HasInstance(cx, obj, lhs, &cond))
  9628         return false;
  9630     res.setBoolean(cond);
  9631     return true;
  9634 typedef bool (*DoInstanceOfFallbackFn)(JSContext *, ICInstanceOf_Fallback *, HandleValue, HandleValue,
  9635                                        MutableHandleValue);
  9636 static const VMFunction DoInstanceOfFallbackInfo =
  9637     FunctionInfo<DoInstanceOfFallbackFn>(DoInstanceOfFallback, PopValues(2));
  9639 bool
  9640 ICInstanceOf_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  9642     EmitRestoreTailCallReg(masm);
  9644     // Sync stack for the decompiler.
  9645     masm.pushValue(R0);
  9646     masm.pushValue(R1);
  9648     masm.pushValue(R1);
  9649     masm.pushValue(R0);
  9650     masm.push(BaselineStubReg);
  9652     return tailCallVM(DoInstanceOfFallbackInfo, masm);
  9655 //
  9656 // TypeOf_Fallback
  9657 //
  9659 static bool
  9660 DoTypeOfFallback(JSContext *cx, BaselineFrame *frame, ICTypeOf_Fallback *stub, HandleValue val,
  9661                  MutableHandleValue res)
  9663     FallbackICSpew(cx, stub, "TypeOf");
  9664     JSType type = js::TypeOfValue(val);
  9665     RootedString string(cx, TypeName(type, cx->names()));
  9667     res.setString(string);
  9669     JS_ASSERT(type != JSTYPE_NULL);
  9670     if (type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION) {
  9671         // Create a new TypeOf stub.
  9672         IonSpew(IonSpew_BaselineIC, "  Generating TypeOf stub for JSType (%d)", (int) type);
  9673         ICTypeOf_Typed::Compiler compiler(cx, type, string);
  9674         ICStub *typeOfStub = compiler.getStub(compiler.getStubSpace(frame->script()));
  9675         if (!typeOfStub)
  9676             return false;
  9677         stub->addNewStub(typeOfStub);
  9680     return true;
  9683 typedef bool (*DoTypeOfFallbackFn)(JSContext *, BaselineFrame *frame, ICTypeOf_Fallback *,
  9684                                    HandleValue, MutableHandleValue);
  9685 static const VMFunction DoTypeOfFallbackInfo =
  9686     FunctionInfo<DoTypeOfFallbackFn>(DoTypeOfFallback);
  9688 bool
  9689 ICTypeOf_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  9691     EmitRestoreTailCallReg(masm);
  9693     masm.pushValue(R0);
  9694     masm.push(BaselineStubReg);
  9695     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
  9697     return tailCallVM(DoTypeOfFallbackInfo, masm);
  9700 bool
  9701 ICTypeOf_Typed::Compiler::generateStubCode(MacroAssembler &masm)
  9703     JS_ASSERT(type_ != JSTYPE_NULL);
  9704     JS_ASSERT(type_ != JSTYPE_FUNCTION);
  9705     JS_ASSERT(type_ != JSTYPE_OBJECT);
  9707     Label failure;
  9708     switch(type_) {
  9709       case JSTYPE_VOID:
  9710         masm.branchTestUndefined(Assembler::NotEqual, R0, &failure);
  9711         break;
  9713       case JSTYPE_STRING:
  9714         masm.branchTestString(Assembler::NotEqual, R0, &failure);
  9715         break;
  9717       case JSTYPE_NUMBER:
  9718         masm.branchTestNumber(Assembler::NotEqual, R0, &failure);
  9719         break;
  9721       case JSTYPE_BOOLEAN:
  9722         masm.branchTestBoolean(Assembler::NotEqual, R0, &failure);
  9723         break;
  9725       default:
  9726         MOZ_ASSUME_UNREACHABLE("Unexpected type");
  9729     masm.movePtr(ImmGCPtr(typeString_), R0.scratchReg());
  9730     masm.tagValue(JSVAL_TYPE_STRING, R0.scratchReg(), R0);
  9731     EmitReturnFromIC(masm);
  9733     masm.bind(&failure);
  9734     EmitStubGuardFailure(masm);
  9735     return true;
  9738 static bool
  9739 DoRetSubFallback(JSContext *cx, BaselineFrame *frame, ICRetSub_Fallback *stub,
  9740                  HandleValue val, uint8_t **resumeAddr)
  9742     FallbackICSpew(cx, stub, "RetSub");
  9744     // |val| is the bytecode offset where we should resume.
  9746     JS_ASSERT(val.isInt32());
  9747     JS_ASSERT(val.toInt32() >= 0);
  9749     JSScript *script = frame->script();
  9750     uint32_t offset = uint32_t(val.toInt32());
  9752     *resumeAddr = script->baselineScript()->nativeCodeForPC(script, script->offsetToPC(offset));
  9754     if (stub->numOptimizedStubs() >= ICRetSub_Fallback::MAX_OPTIMIZED_STUBS)
  9755         return true;
  9757     // Attach an optimized stub for this pc offset.
  9758     IonSpew(IonSpew_BaselineIC, "  Generating RetSub stub for pc offset %u", offset);
  9759     ICRetSub_Resume::Compiler compiler(cx, offset, *resumeAddr);
  9760     ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
  9761     if (!optStub)
  9762         return false;
  9764     stub->addNewStub(optStub);
  9765     return true;
  9768 typedef bool(*DoRetSubFallbackFn)(JSContext *cx, BaselineFrame *, ICRetSub_Fallback *,
  9769                                   HandleValue, uint8_t **);
  9770 static const VMFunction DoRetSubFallbackInfo = FunctionInfo<DoRetSubFallbackFn>(DoRetSubFallback);
  9772 typedef bool (*ThrowFn)(JSContext *, HandleValue);
  9773 static const VMFunction ThrowInfoBaseline = FunctionInfo<ThrowFn>(js::Throw);
  9775 bool
  9776 ICRetSub_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
  9778     // If R0 is BooleanValue(true), rethrow R1.
  9779     Label rethrow;
  9780     masm.branchTestBooleanTruthy(true, R0, &rethrow);
  9782         // Call a stub to get the native code address for the pc offset in R1.
  9783         GeneralRegisterSet regs(availableGeneralRegs(0));
  9784         regs.take(R1);
  9785         regs.takeUnchecked(BaselineTailCallReg);
  9787         Register frame = regs.takeAny();
  9788         masm.movePtr(BaselineFrameReg, frame);
  9790         enterStubFrame(masm, regs.getAny());
  9792         masm.pushValue(R1);
  9793         masm.push(BaselineStubReg);
  9794         masm.pushBaselineFramePtr(frame, frame);
  9796         if (!callVM(DoRetSubFallbackInfo, masm))
  9797             return false;
  9799         leaveStubFrame(masm);
  9801         EmitChangeICReturnAddress(masm, ReturnReg);
  9802         EmitReturnFromIC(masm);
  9805     masm.bind(&rethrow);
  9806     EmitRestoreTailCallReg(masm);
  9807     masm.pushValue(R1);
  9808     return tailCallVM(ThrowInfoBaseline, masm);
  9811 bool
  9812 ICRetSub_Resume::Compiler::generateStubCode(MacroAssembler &masm)
  9814     // If R0 is BooleanValue(true), rethrow R1.
  9815     Label fail, rethrow;
  9816     masm.branchTestBooleanTruthy(true, R0, &rethrow);
  9818     // R1 is the pc offset. Ensure it matches this stub's offset.
  9819     Register offset = masm.extractInt32(R1, ExtractTemp0);
  9820     masm.branch32(Assembler::NotEqual,
  9821                   Address(BaselineStubReg, ICRetSub_Resume::offsetOfPCOffset()),
  9822                   offset,
  9823                   &fail);
  9825     // pc offset matches, resume at the target pc.
  9826     masm.loadPtr(Address(BaselineStubReg, ICRetSub_Resume::offsetOfAddr()), R0.scratchReg());
  9827     EmitChangeICReturnAddress(masm, R0.scratchReg());
  9828     EmitReturnFromIC(masm);
  9830     // Rethrow the Value stored in R1.
  9831     masm.bind(&rethrow);
  9832     EmitRestoreTailCallReg(masm);
  9833     masm.pushValue(R1);
  9834     if (!tailCallVM(ThrowInfoBaseline, masm))
  9835         return false;
  9837     masm.bind(&fail);
  9838     EmitStubGuardFailure(masm);
  9839     return true;
  9842 ICProfiler_PushFunction::ICProfiler_PushFunction(JitCode *stubCode, const char *str,
  9843                                                  HandleScript script)
  9844   : ICStub(ICStub::Profiler_PushFunction, stubCode),
  9845     str_(str),
  9846     script_(script)
  9847 { }
  9849 ICTypeMonitor_SingleObject::ICTypeMonitor_SingleObject(JitCode *stubCode, HandleObject obj)
  9850   : ICStub(TypeMonitor_SingleObject, stubCode),
  9851     obj_(obj)
  9852 { }
  9854 ICTypeMonitor_TypeObject::ICTypeMonitor_TypeObject(JitCode *stubCode, HandleTypeObject type)
  9855   : ICStub(TypeMonitor_TypeObject, stubCode),
  9856     type_(type)
  9857 { }
  9859 ICTypeUpdate_SingleObject::ICTypeUpdate_SingleObject(JitCode *stubCode, HandleObject obj)
  9860   : ICStub(TypeUpdate_SingleObject, stubCode),
  9861     obj_(obj)
  9862 { }
  9864 ICTypeUpdate_TypeObject::ICTypeUpdate_TypeObject(JitCode *stubCode, HandleTypeObject type)
  9865   : ICStub(TypeUpdate_TypeObject, stubCode),
  9866     type_(type)
  9867 { }
  9869 ICGetElemNativeStub::ICGetElemNativeStub(ICStub::Kind kind, JitCode *stubCode,
  9870                                          ICStub *firstMonitorStub,
  9871                                          HandleShape shape, HandlePropertyName name,
  9872                                          AccessType acctype, bool needsAtomize)
  9873   : ICMonitoredStub(kind, stubCode, firstMonitorStub),
  9874     shape_(shape),
  9875     name_(name)
  9877     extra_ = (static_cast<uint16_t>(acctype) << ACCESSTYPE_SHIFT) |
  9878              (static_cast<uint16_t>(needsAtomize) << NEEDS_ATOMIZE_SHIFT);
  9881 ICGetElemNativeStub::~ICGetElemNativeStub()
  9882 { }
  9884 ICGetElemNativeGetterStub::ICGetElemNativeGetterStub(
  9885                         ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
  9886                         HandleShape shape, HandlePropertyName name, AccessType acctype,
  9887                         bool needsAtomize, HandleFunction getter, uint32_t pcOffset)
  9888   : ICGetElemNativeStub(kind, stubCode, firstMonitorStub, shape, name, acctype, needsAtomize),
  9889     getter_(getter),
  9890     pcOffset_(pcOffset)
  9892     JS_ASSERT(kind == GetElem_NativePrototypeCallNative ||
  9893               kind == GetElem_NativePrototypeCallScripted);
  9894     JS_ASSERT(acctype == NativeGetter || acctype == ScriptedGetter);
  9897 ICGetElem_NativePrototypeSlot::ICGetElem_NativePrototypeSlot(
  9898                             JitCode *stubCode, ICStub *firstMonitorStub,
  9899                             HandleShape shape, HandlePropertyName name,
  9900                             AccessType acctype, bool needsAtomize, uint32_t offset,
  9901                             HandleObject holder, HandleShape holderShape)
  9902   : ICGetElemNativeSlotStub(ICStub::GetElem_NativePrototypeSlot, stubCode, firstMonitorStub, shape,
  9903                             name, acctype, needsAtomize, offset),
  9904     holder_(holder),
  9905     holderShape_(holderShape)
  9906 { }
  9908 ICGetElemNativePrototypeCallStub::ICGetElemNativePrototypeCallStub(
  9909                                 ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
  9910                                 HandleShape shape, HandlePropertyName name,
  9911                                 AccessType acctype, bool needsAtomize, HandleFunction getter,
  9912                                 uint32_t pcOffset, HandleObject holder, HandleShape holderShape)
  9913   : ICGetElemNativeGetterStub(kind, stubCode, firstMonitorStub, shape, name, acctype, needsAtomize,
  9914                               getter, pcOffset),
  9915     holder_(holder),
  9916     holderShape_(holderShape)
  9917 {}
  9919 ICGetElem_Dense::ICGetElem_Dense(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape)
  9920     : ICMonitoredStub(GetElem_Dense, stubCode, firstMonitorStub),
  9921       shape_(shape)
  9922 { }
  9924 ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type)
  9925   : ICStub(GetElem_TypedArray, stubCode),
  9926     shape_(shape)
  9928     extra_ = uint16_t(type);
  9929     JS_ASSERT(extra_ == type);
  9932 ICSetElem_Dense::ICSetElem_Dense(JitCode *stubCode, HandleShape shape, HandleTypeObject type)
  9933   : ICUpdatedStub(SetElem_Dense, stubCode),
  9934     shape_(shape),
  9935     type_(type)
  9936 { }
  9938 ICSetElem_DenseAdd::ICSetElem_DenseAdd(JitCode *stubCode, types::TypeObject *type,
  9939                                        size_t protoChainDepth)
  9940   : ICUpdatedStub(SetElem_DenseAdd, stubCode),
  9941     type_(type)
  9943     JS_ASSERT(protoChainDepth <= MAX_PROTO_CHAIN_DEPTH);
  9944     extra_ = protoChainDepth;
  9947 template <size_t ProtoChainDepth>
  9948 ICUpdatedStub *
  9949 ICSetElemDenseAddCompiler::getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes)
  9951     RootedTypeObject objType(cx, obj_->getType(cx));
  9952     if (!objType)
  9953         return nullptr;
  9954     Rooted<JitCode *> stubCode(cx, getStubCode());
  9955     return ICSetElem_DenseAddImpl<ProtoChainDepth>::New(space, stubCode, objType, shapes);
  9958 ICSetElem_TypedArray::ICSetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type,
  9959                                            bool expectOutOfBounds)
  9960   : ICStub(SetElem_TypedArray, stubCode),
  9961     shape_(shape)
  9963     extra_ = uint8_t(type);
  9964     JS_ASSERT(extra_ == type);
  9965     extra_ |= (static_cast<uint16_t>(expectOutOfBounds) << 8);
  9968 ICGetName_Global::ICGetName_Global(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
  9969                                    uint32_t slot)
  9970   : ICMonitoredStub(GetName_Global, stubCode, firstMonitorStub),
  9971     shape_(shape),
  9972     slot_(slot)
  9973 { }
  9975 template <size_t NumHops>
  9976 ICGetName_Scope<NumHops>::ICGetName_Scope(JitCode *stubCode, ICStub *firstMonitorStub,
  9977                                           AutoShapeVector *shapes, uint32_t offset)
  9978   : ICMonitoredStub(GetStubKind(), stubCode, firstMonitorStub),
  9979     offset_(offset)
  9981     JS_STATIC_ASSERT(NumHops <= MAX_HOPS);
  9982     JS_ASSERT(shapes->length() == NumHops + 1);
  9983     for (size_t i = 0; i < NumHops + 1; i++)
  9984         shapes_[i].init((*shapes)[i]);
  9987 ICGetIntrinsic_Constant::ICGetIntrinsic_Constant(JitCode *stubCode, HandleValue value)
  9988   : ICStub(GetIntrinsic_Constant, stubCode),
  9989     value_(value)
  9990 { }
  9992 ICGetIntrinsic_Constant::~ICGetIntrinsic_Constant()
  9993 { }
  9995 ICGetProp_Primitive::ICGetProp_Primitive(JitCode *stubCode, ICStub *firstMonitorStub,
  9996                                          HandleShape protoShape, uint32_t offset)
  9997   : ICMonitoredStub(GetProp_Primitive, stubCode, firstMonitorStub),
  9998     protoShape_(protoShape),
  9999     offset_(offset)
 10000 { }
 10002 ICGetPropNativeStub::ICGetPropNativeStub(ICStub::Kind kind, JitCode *stubCode,
 10003                                          ICStub *firstMonitorStub,
 10004                                          HandleShape shape, uint32_t offset)
 10005   : ICMonitoredStub(kind, stubCode, firstMonitorStub),
 10006     shape_(shape),
 10007     offset_(offset)
 10008 { }
 10010 ICGetProp_NativePrototype::ICGetProp_NativePrototype(JitCode *stubCode, ICStub *firstMonitorStub,
 10011                                                      HandleShape shape, uint32_t offset,
 10012                                                      HandleObject holder, HandleShape holderShape)
 10013   : ICGetPropNativeStub(GetProp_NativePrototype, stubCode, firstMonitorStub, shape, offset),
 10014     holder_(holder),
 10015     holderShape_(holderShape)
 10016 { }
 10018 ICGetPropCallGetter::ICGetPropCallGetter(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
 10019                                          HandleObject holder, HandleShape holderShape, HandleFunction getter,
 10020                                          uint32_t pcOffset)
 10021   : ICMonitoredStub(kind, stubCode, firstMonitorStub),
 10022     holder_(holder),
 10023     holderShape_(holderShape),
 10024     getter_(getter),
 10025     pcOffset_(pcOffset)
 10027     JS_ASSERT(kind == ICStub::GetProp_CallScripted  ||
 10028               kind == ICStub::GetProp_CallNative    ||
 10029               kind == ICStub::GetProp_CallNativePrototype);
 10032 ICGetPropCallPrototypeGetter::ICGetPropCallPrototypeGetter(Kind kind, JitCode *stubCode,
 10033                                                            ICStub *firstMonitorStub,
 10034                                                            HandleShape receiverShape, HandleObject holder,
 10035                                                            HandleShape holderShape,
 10036                                                            HandleFunction getter, uint32_t pcOffset)
 10037   : ICGetPropCallGetter(kind, stubCode, firstMonitorStub, holder, holderShape, getter, pcOffset),
 10038     receiverShape_(receiverShape)
 10040     JS_ASSERT(kind == ICStub::GetProp_CallScripted || kind == ICStub::GetProp_CallNativePrototype);
 10043 ICSetProp_Native::ICSetProp_Native(JitCode *stubCode, HandleTypeObject type, HandleShape shape,
 10044                                    uint32_t offset)
 10045   : ICUpdatedStub(SetProp_Native, stubCode),
 10046     type_(type),
 10047     shape_(shape),
 10048     offset_(offset)
 10049 { }
 10051 ICUpdatedStub *
 10052 ICSetProp_Native::Compiler::getStub(ICStubSpace *space)
 10054     RootedTypeObject type(cx, obj_->getType(cx));
 10055     if (!type)
 10056         return nullptr;
 10058     RootedShape shape(cx, obj_->lastProperty());
 10059     ICUpdatedStub *stub = ICSetProp_Native::New(space, getStubCode(), type, shape, offset_);
 10060     if (!stub || !stub->initUpdatingChain(cx, space))
 10061         return nullptr;
 10062     return stub;
 10065 ICSetProp_NativeAdd::ICSetProp_NativeAdd(JitCode *stubCode, HandleTypeObject type,
 10066                                          size_t protoChainDepth,
 10067                                          HandleShape newShape,
 10068                                          uint32_t offset)
 10069   : ICUpdatedStub(SetProp_NativeAdd, stubCode),
 10070     type_(type),
 10071     newShape_(newShape),
 10072     offset_(offset)
 10074     JS_ASSERT(protoChainDepth <= MAX_PROTO_CHAIN_DEPTH);
 10075     extra_ = protoChainDepth;
 10078 template <size_t ProtoChainDepth>
 10079 ICSetProp_NativeAddImpl<ProtoChainDepth>::ICSetProp_NativeAddImpl(JitCode *stubCode,
 10080                                                                   HandleTypeObject type,
 10081                                                                   const AutoShapeVector *shapes,
 10082                                                                   HandleShape newShape,
 10083                                                                   uint32_t offset)
 10084   : ICSetProp_NativeAdd(stubCode, type, ProtoChainDepth, newShape, offset)
 10086     JS_ASSERT(shapes->length() == NumShapes);
 10087     for (size_t i = 0; i < NumShapes; i++)
 10088         shapes_[i].init((*shapes)[i]);
 10091 ICSetPropNativeAddCompiler::ICSetPropNativeAddCompiler(JSContext *cx, HandleObject obj,
 10092                                                        HandleShape oldShape,
 10093                                                        size_t protoChainDepth,
 10094                                                        bool isFixedSlot,
 10095                                                        uint32_t offset)
 10096   : ICStubCompiler(cx, ICStub::SetProp_NativeAdd),
 10097     obj_(cx, obj),
 10098     oldShape_(cx, oldShape),
 10099     protoChainDepth_(protoChainDepth),
 10100     isFixedSlot_(isFixedSlot),
 10101     offset_(offset)
 10103     JS_ASSERT(protoChainDepth_ <= ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH);
 10106 ICSetPropCallSetter::ICSetPropCallSetter(Kind kind, JitCode *stubCode, HandleShape shape,
 10107                                          HandleObject holder, HandleShape holderShape,
 10108                                          HandleFunction setter, uint32_t pcOffset)
 10109   : ICStub(kind, stubCode),
 10110     shape_(shape),
 10111     holder_(holder),
 10112     holderShape_(holderShape),
 10113     setter_(setter),
 10114     pcOffset_(pcOffset)
 10116     JS_ASSERT(kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
 10119 ICCall_Scripted::ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub,
 10120                                  HandleScript calleeScript, HandleObject templateObject,
 10121                                  uint32_t pcOffset)
 10122   : ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
 10123     calleeScript_(calleeScript),
 10124     templateObject_(templateObject),
 10125     pcOffset_(pcOffset)
 10126 { }
 10128 ICCall_Native::ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
 10129                              HandleFunction callee, HandleObject templateObject,
 10130                              uint32_t pcOffset)
 10131   : ICMonitoredStub(ICStub::Call_Native, stubCode, firstMonitorStub),
 10132     callee_(callee),
 10133     templateObject_(templateObject),
 10134     pcOffset_(pcOffset)
 10136 #ifdef JS_ARM_SIMULATOR
 10137     // The simulator requires VM calls to be redirected to a special swi
 10138     // instruction to handle them. To make this work, we store the redirected
 10139     // pointer in the stub.
 10140     native_ = Simulator::RedirectNativeFunction(JS_FUNC_TO_DATA_PTR(void *, callee->native()),
 10141                                                 Args_General3);
 10142 #endif
 10145 ICGetPropCallDOMProxyNativeStub::ICGetPropCallDOMProxyNativeStub(Kind kind, JitCode *stubCode,
 10146                                                                  ICStub *firstMonitorStub,
 10147                                                                  HandleShape shape,
 10148                                                                  BaseProxyHandler *proxyHandler,
 10149                                                                  HandleShape expandoShape,
 10150                                                                  HandleObject holder,
 10151                                                                  HandleShape holderShape,
 10152                                                                  HandleFunction getter,
 10153                                                                  uint32_t pcOffset)
 10154   : ICMonitoredStub(kind, stubCode, firstMonitorStub),
 10155     shape_(shape),
 10156     proxyHandler_(proxyHandler),
 10157     expandoShape_(expandoShape),
 10158     holder_(holder),
 10159     holderShape_(holderShape),
 10160     getter_(getter),
 10161     pcOffset_(pcOffset)
 10162 { }
 10164 ICGetPropCallDOMProxyNativeCompiler::ICGetPropCallDOMProxyNativeCompiler(JSContext *cx,
 10165                                                                          ICStub::Kind kind,
 10166                                                                          ICStub *firstMonitorStub,
 10167                                                                          Handle<ProxyObject*> proxy,
 10168                                                                          HandleObject holder,
 10169                                                                          HandleFunction getter,
 10170                                                                          uint32_t pcOffset)
 10171   : ICStubCompiler(cx, kind),
 10172     firstMonitorStub_(firstMonitorStub),
 10173     proxy_(cx, proxy),
 10174     holder_(cx, holder),
 10175     getter_(cx, getter),
 10176     pcOffset_(pcOffset)
 10178     JS_ASSERT(kind == ICStub::GetProp_CallDOMProxyNative ||
 10179               kind == ICStub::GetProp_CallDOMProxyWithGenerationNative);
 10180     JS_ASSERT(proxy_->handler()->family() == GetDOMProxyHandlerFamily());
 10183 ICGetProp_DOMProxyShadowed::ICGetProp_DOMProxyShadowed(JitCode *stubCode,
 10184                                                        ICStub *firstMonitorStub,
 10185                                                        HandleShape shape,
 10186                                                        BaseProxyHandler *proxyHandler,
 10187                                                        HandlePropertyName name,
 10188                                                        uint32_t pcOffset)
 10189   : ICMonitoredStub(ICStub::GetProp_DOMProxyShadowed, stubCode, firstMonitorStub),
 10190     shape_(shape),
 10191     proxyHandler_(proxyHandler),
 10192     name_(name),
 10193     pcOffset_(pcOffset)
 10194 { }
 10196 //
 10197 // Rest_Fallback
 10198 //
 10200 static bool DoRestFallback(JSContext *cx, ICRest_Fallback *stub,
 10201                            BaselineFrame *frame, MutableHandleValue res)
 10203     unsigned numFormals = frame->numFormalArgs() - 1;
 10204     unsigned numActuals = frame->numActualArgs();
 10205     unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
 10206     Value *rest = frame->argv() + numFormals;
 10208     JSObject *obj = NewDenseCopiedArray(cx, numRest, rest, nullptr);
 10209     if (!obj)
 10210         return false;
 10211     types::FixRestArgumentsType(cx, obj);
 10212     res.setObject(*obj);
 10213     return true;
 10216 typedef bool (*DoRestFallbackFn)(JSContext *, ICRest_Fallback *, BaselineFrame *,
 10217                                  MutableHandleValue);
 10218 static const VMFunction DoRestFallbackInfo =
 10219     FunctionInfo<DoRestFallbackFn>(DoRestFallback);
 10221 bool
 10222 ICRest_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
 10224     EmitRestoreTailCallReg(masm);
 10226     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 10227     masm.push(BaselineStubReg);
 10229     return tailCallVM(DoRestFallbackInfo, masm);
 10232 } // namespace jit
 10233 } // namespace js

mercurial