LCOV - app.info - js/src/methodjit/PolyIC.cpp

LCOV - code coverage report
| Current view: | directory - js/src/methodjit - PolyIC.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1405 | 1227 | 87.3 %
| Date: | 2012-04-07 | Functions: | 93 | 83 | 89.2 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=4 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
          18                 :  * May 28, 2008.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  *   Brendan Eich <brendan@mozilla.org>
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   David Mandelin <dmandelin@mozilla.com>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 : #include "PolyIC.h"
          40                 : #include "StubCalls.h"
          41                 : #include "CodeGenIncludes.h"
          42                 : #include "StubCalls-inl.h"
          43                 : #include "BaseCompiler.h"
          44                 : #include "assembler/assembler/LinkBuffer.h"
          45                 : #include "TypedArrayIC.h"
          46                 : #include "jsscope.h"
          47                 : #include "jsnum.h"
          48                 : #include "jstypedarray.h"
          49                 : #include "jsatominlines.h"
          50                 : #include "jsobjinlines.h"
          51                 : #include "jsscopeinlines.h"
          52                 : #include "jsinterpinlines.h"
          53                 : #include "jsautooplen.h"
          54                 :
          55                 : #include "vm/ScopeObject-inl.h"
          56                 : #include "vm/StringObject-inl.h"
          57                 :
          58                 : #if defined JS_POLYIC
          59                 :
          60                 : using namespace js;
          61                 : using namespace js::mjit;
          62                 : using namespace js::mjit::ic;
          63                 :
          64                 : typedef JSC::FunctionPtr FunctionPtr;
          65                 : typedef JSC::MacroAssembler::RegisterID RegisterID;
          66                 : typedef JSC::MacroAssembler::Jump Jump;
          67                 : typedef JSC::MacroAssembler::Imm32 Imm32;
          68                 :
          69                 : /* Rough over-estimate of how much memory we need to unprotect. */
          70                 : static const uint32_t INLINE_PATH_LENGTH = 64;
          71                 :
          72                 : // Helper class to simplify LinkBuffer usage in PIC stub generators.
          73                 : // This guarantees correct OOM and refcount handling for buffers while they
          74                 : // are instantiated and rooted.
          75                 : class PICLinker : public LinkerHelper
          76           47565 : {
          77                 :     ic::BasePolyIC &ic;
          78                 :
          79                 :   public:
          80           47565 :     PICLinker(Assembler &masm, ic::BasePolyIC &ic)
          81           47565 :       : LinkerHelper(masm, JSC::METHOD_CODE), ic(ic)
          82           47565 :     { }
          83                 :
          84           47565 :     bool init(JSContext *cx) {
          85           47565 :         JSC::ExecutablePool *pool = LinkerHelper::init(cx);
          86           47565 :         if (!pool)
          87               0 :             return false;
          88           47565 :         if (!ic.addPool(cx, pool)) {
          89               0 :             pool->release();
          90               0 :             js_ReportOutOfMemory(cx);
          91               0 :             return false;
          92                 :         }
          93           47565 :         return true;
          94                 :     }
          95                 : };
          96                 :
          97                 : class PICStubCompiler : public BaseCompiler
          98                 : {
          99                 :   protected:
         100                 :     const char *type;
         101                 :     VMFrame &f;
         102                 :     JSScript *script;
         103                 :     ic::PICInfo &pic;
         104                 :     void *stub;
         105                 :     uint64_t gcNumber;
         106                 :
         107                 :   public:
         108                 :     bool canCallHook;
         109                 :
         110           62683 :     PICStubCompiler(const char *type, VMFrame &f, JSScript *script, ic::PICInfo &pic, void *stub)
         111                 :       : BaseCompiler(f.cx), type(type), f(f), script(script), pic(pic), stub(stub),
         112           62683 :         gcNumber(f.cx->runtime->gcNumber), canCallHook(pic.canCallHook)
         113           62683 :     { }
         114                 :
         115               0 :     LookupStatus error() {
         116                 :         /*
         117                 :          * N.B. Do not try to disable the IC, we do not want to guard on
         118                 :          * whether the IC has been recompiled when propagating errors.
         119                 :          */
         120               0 :         return Lookup_Error;
         121                 :     }
         122                 :
         123               0 :     LookupStatus error(JSContext *cx) {
         124               0 :         return error();
         125                 :     }
         126                 :
         127            9849 :     LookupStatus disable(const char *reason) {
         128            9849 :         return disable(f.cx, reason);
         129                 :     }
         130                 :
         131            9929 :     LookupStatus disable(JSContext *cx, const char *reason) {
         132            9929 :         return pic.disable(f, reason, stub);
         133                 :     }
         134                 :
         135            2547 :     LookupStatus disable(VMFrame &f, const char *reason) {
         136            2547 :         return pic.disable(f, reason, stub);
         137                 :     }
         138                 :
         139           27090 :     bool hadGC() {
         140           27090 :         return gcNumber != f.cx->runtime->gcNumber;
         141                 :     }
         142                 :
         143                 :   protected:
         144           30465 :     void spew(const char *event, const char *op) {
         145                 : #ifdef JS_METHODJIT_SPEW
         146                 :         JaegerSpew(JSpew_PICs, "%s %s: %s (%s: %d)\n",
         147           30465 :                    type, event, op, script->filename, CurrentLine(cx));
         148                 : #endif
         149           30465 :     }
         150                 : };
         151                 :
         152                 : static bool
         153            9237 : GeneratePrototypeGuards(JSContext *cx, Vector<JSC::MacroAssembler::Jump,8> &mismatches, Assembler &masm,
         154                 :                         JSObject *obj, JSObject *holder,
         155                 :                         JSC::MacroAssembler::RegisterID objReg,
         156                 :                         JSC::MacroAssembler::RegisterID scratchReg)
         157                 : {
         158                 :     typedef JSC::MacroAssembler::Address Address;
         159                 :     typedef JSC::MacroAssembler::AbsoluteAddress AbsoluteAddress;
         160                 :     typedef JSC::MacroAssembler::ImmPtr ImmPtr;
         161                 :     typedef JSC::MacroAssembler::Jump Jump;
         162                 :
         163            9237 :     if (obj->hasUncacheableProto()) {
         164               4 :         masm.loadPtr(Address(objReg, JSObject::offsetOfType()), scratchReg);
         165                 :         Jump j = masm.branchPtr(Assembler::NotEqual,
         166                 :                                 Address(scratchReg, offsetof(types::TypeObject, proto)),
         167               4 :                                 ImmPtr(obj->getProto()));
         168               4 :         if (!mismatches.append(j))
         169               0 :             return false;
         170                 :     }
         171                 :
         172            9237 :     JSObject *pobj = obj->getProto();
         173           22604 :     while (pobj != holder) {
         174            4130 :         if (pobj->hasUncacheableProto()) {
         175            1231 :             Jump j;
         176            1231 :             if (pobj->hasSingletonType()) {
         177               0 :                 types::TypeObject *type = pobj->getType(cx);
         178                 :                 j = masm.branchPtr(Assembler::NotEqual,
         179                 :                                    AbsoluteAddress(&type->proto),
         180               0 :                                    ImmPtr(pobj->getProto()),
         181               0 :                                    scratchReg);
         182                 :             } else {
         183                 :                 j = masm.branchPtr(Assembler::NotEqual,
         184            1231 :                                    AbsoluteAddress(pobj->addressOfType()),
         185            1231 :                                    ImmPtr(pobj->type()),
         186            2462 :                                    scratchReg);
         187                 :             }
         188            1231 :             if (!mismatches.append(j))
         189               0 :                 return false;
         190                 :         }
         191            4130 :         pobj = pobj->getProto();
         192                 :     }
         193                 :
         194            9237 :     return true;
         195                 : }
         196                 :
         197                 : class SetPropCompiler : public PICStubCompiler
         198                 : {
         199                 :     JSObject *obj;
         200                 :     PropertyName *name;
         201                 :     int lastStubSecondShapeGuard;
         202                 :
         203                 :   public:
         204            4900 :     SetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, PropertyName *name,
         205                 :                     VoidStubPIC stub)
         206                 :       : PICStubCompiler("setprop", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
         207            4900 :         obj(obj), name(name), lastStubSecondShapeGuard(pic.secondShapeGuard)
         208            4900 :     { }
         209                 :
         210                 :     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
         211                 :     {
         212                 :         SetPropLabels &labels = pic.setPropLabels();
         213                 :         repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin, pic.u.vr));
         214                 :         repatcher.repatch(labels.getInlineShapeData(pic.fastPathStart, pic.shapeGuard),
         215                 :                           NULL);
         216                 :         repatcher.relink(labels.getInlineShapeJump(pic.fastPathStart.labelAtOffset(pic.shapeGuard)),
         217                 :                          pic.slowPathStart);
         218                 :
         219                 :         FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, ic::SetProp));
         220                 :         repatcher.relink(pic.slowPathCall, target);
         221                 :     }
         222                 :
         223            1485 :     LookupStatus patchInline(const Shape *shape)
         224                 :     {
         225            1485 :         JS_ASSERT(!pic.inlinePathPatched);
         226            1485 :         JaegerSpew(JSpew_PICs, "patch setprop inline at %p\n", pic.fastPathStart.executableAddress());
         227                 :
         228            2970 :         Repatcher repatcher(f.chunk());
         229            1485 :         SetPropLabels &labels = pic.setPropLabels();
         230                 :
         231                 :         int32_t offset;
         232            1485 :         if (obj->isFixedSlot(shape->slot())) {
         233            1069 :             CodeLocationInstruction istr = labels.getDslotsLoad(pic.fastPathRejoin, pic.u.vr);
         234            1069 :             repatcher.repatchLoadPtrToLEA(istr);
         235                 :
         236                 :             //
         237                 :             // We've patched | mov dslots, [obj + DSLOTS_OFFSET]
         238                 :             // To:           | lea fslots, [obj + DSLOTS_OFFSET]
         239                 :             //
         240                 :             // Because the offset is wrong, it's necessary to correct it
         241                 :             // below.
         242                 :             //
         243            1069 :             int32_t diff = int32_t(JSObject::getFixedSlotOffset(0)) -
         244            1069 :                          int32_t(JSObject::offsetOfSlots());
         245            1069 :             JS_ASSERT(diff != 0);
         246            1069 :             offset = (int32_t(shape->slot()) * sizeof(Value)) + diff;
         247                 :         } else {
         248             416 :             offset = obj->dynamicSlotIndex(shape->slot()) * sizeof(Value);
         249                 :         }
         250                 :
         251            1485 :         repatcher.repatch(labels.getInlineShapeData(pic.fastPathStart, pic.shapeGuard),
         252            2970 :                           obj->lastProperty());
         253            1485 :         repatcher.patchAddressOffsetForValueStore(labels.getInlineValueStore(pic.fastPathRejoin),
         254            2970 :                                                   offset, pic.u.vr.isTypeKnown());
         255                 :
         256            1485 :         pic.inlinePathPatched = true;
         257                 :
         258            1485 :         return Lookup_Cacheable;
         259                 :     }
         260                 :
         261            2582 :     int getLastStubSecondShapeGuard() const {
         262            2582 :         return lastStubSecondShapeGuard ? POST_INST_OFFSET(lastStubSecondShapeGuard) : 0;
         263                 :     }
         264                 :
         265            2582 :     void patchPreviousToHere(CodeLocationLabel cs)
         266                 :     {
         267            5164 :         Repatcher repatcher(pic.lastCodeBlock(f.chunk()));
         268            2582 :         CodeLocationLabel label = pic.lastPathStart();
         269                 :
         270                 :         // Patch either the inline fast path or a generated stub. The stub
         271                 :         // omits the prefix of the inline fast path that loads the shape, so
         272                 :         // the offsets are different.
         273            2582 :         if (pic.stubsGenerated) {
         274             499 :             repatcher.relink(pic.setPropLabels().getStubShapeJump(label), cs);
         275                 :         } else {
         276            2083 :             CodeLocationLabel shapeGuard = label.labelAtOffset(pic.shapeGuard);
         277            2083 :             repatcher.relink(pic.setPropLabels().getInlineShapeJump(shapeGuard), cs);
         278                 :         }
         279            2582 :         if (int secondGuardOffset = getLastStubSecondShapeGuard())
         280             294 :             repatcher.relink(label.jumpAtOffset(secondGuardOffset), cs);
         281            2582 :     }
         282                 :
         283            2582 :     LookupStatus generateStub(const Shape *initialShape, const Shape *shape, bool adding)
         284                 :     {
         285            2582 :         if (hadGC())
         286               0 :             return Lookup_Uncacheable;
         287                 :
         288                 :         /* Exits to the slow path. */
         289            5164 :         Vector<Jump, 8> slowExits(cx);
         290            5164 :         Vector<Jump, 8> otherGuards(cx);
         291                 :
         292            5164 :         Assembler masm;
         293                 :
         294                 :         // Shape guard.
         295            2582 :         if (pic.shapeNeedsRemat()) {
         296             230 :             masm.loadShape(pic.objReg, pic.shapeReg);
         297             230 :             pic.shapeRegHasBaseShape = true;
         298                 :         }
         299                 :
         300            2582 :         Label start = masm.label();
         301                 :         Jump shapeGuard = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
         302            2582 :                                          ImmPtr(initialShape));
         303                 :
         304            2582 :         Label stubShapeJumpLabel = masm.label();
         305                 :
         306            2582 :         pic.setPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel);
         307                 :
         308            2582 :         if (pic.typeMonitored) {
         309                 :             /*
         310                 :              * Inference does not know the type of the object being updated,
         311                 :              * and we need to make sure that the updateMonitoredTypes() call
         312                 :              * covers this stub, i.e. we will be writing to an object with the
         313                 :              * same type. Add a type guard in addition to the shape guard.
         314                 :              * Note: it is possible that this test gets a spurious hit if the
         315                 :              * object has a lazy type, but in such cases no analyzed scripts
         316                 :              * depend on the object and we will reconstruct its type from the
         317                 :              * value being written here.
         318                 :              */
         319                 :             Jump typeGuard = masm.branchPtr(Assembler::NotEqual,
         320             662 :                                             Address(pic.objReg, JSObject::offsetOfType()),
         321            1324 :                                             ImmPtr(obj->getType(cx)));
         322             662 :             if (!otherGuards.append(typeGuard))
         323               0 :                 return error();
         324                 :         }
         325                 :
         326            2582 :         JS_ASSERT_IF(!shape->hasDefaultSetter(), obj->isCall());
         327                 :
         328            2582 :         MaybeJump skipOver;
         329                 :
         330            2582 :         if (adding) {
         331            1244 :             JS_ASSERT(shape->hasSlot());
         332            1244 :             pic.shapeRegHasBaseShape = false;
         333                 :
         334            1244 :             if (!GeneratePrototypeGuards(cx, otherGuards, masm, obj, NULL,
         335            1244 :                                          pic.objReg, pic.shapeReg)) {
         336               0 :                 return error();
         337                 :             }
         338                 :
         339                 :             /* Emit shape guards for the object's prototype chain. */
         340            1244 :             JSObject *proto = obj->getProto();
         341            1244 :             RegisterID lastReg = pic.objReg;
         342            4934 :             while (proto) {
         343            2446 :                 masm.loadPtr(Address(lastReg, JSObject::offsetOfType()), pic.shapeReg);
         344            2446 :                 masm.loadPtr(Address(pic.shapeReg, offsetof(types::TypeObject, proto)), pic.shapeReg);
         345            2446 :                 Jump protoGuard = masm.guardShape(pic.shapeReg, proto);
         346            2446 :                 if (!otherGuards.append(protoGuard))
         347               0 :                     return error();
         348                 :
         349            2446 :                 proto = proto->getProto();
         350            2446 :                 lastReg = pic.shapeReg;
         351                 :             }
         352                 :
         353            1244 :             if (obj->isFixedSlot(shape->slot())) {
         354                 :                 Address address(pic.objReg,
         355            1053 :                                 JSObject::getFixedSlotOffset(shape->slot()));
         356            1053 :                 masm.storeValue(pic.u.vr, address);
         357                 :             } else {
         358                 :                 /*
         359                 :                  * Note: the guard on the initial shape determines the object's
         360                 :                  * number of fixed slots and slot span, which in turn determine
         361                 :                  * the number of dynamic slots allocated for the object.
         362                 :                  * We don't need to check capacity here.
         363                 :                  */
         364             191 :                 masm.loadPtr(Address(pic.objReg, JSObject::offsetOfSlots()), pic.shapeReg);
         365             191 :                 Address address(pic.shapeReg, obj->dynamicSlotIndex(shape->slot()) * sizeof(Value));
         366             191 :                 masm.storeValue(pic.u.vr, address);
         367                 :             }
         368                 :
         369            1244 :             JS_ASSERT(shape == obj->lastProperty());
         370            1244 :             JS_ASSERT(shape != initialShape);
         371                 :
         372                 :             /* Write the object's new shape. */
         373            1244 :             masm.storePtr(ImmPtr(shape), Address(pic.objReg, JSObject::offsetOfShape()));
         374            1338 :         } else if (shape->hasDefaultSetter()) {
         375             827 :             Address address = masm.objPropAddress(obj, pic.objReg, shape->slot());
         376             827 :             masm.storeValue(pic.u.vr, address);
         377                 :         } else {
         378                 :             //   \ /        In general, two function objects with different JSFunctions
         379                 :             //    #         can have the same shape, thus we must not rely on the identity
         380                 :             // >--+--<      of 'fun' remaining the same. However, since:
         381                 :             //   |||         1. the shape includes all arguments and locals and their setters
         382                 :             //    \\     V     and getters, and
         383                 :             //      \===/    2. arguments and locals have different getters
         384                 :             //              then we can rely on fun->nargs remaining invariant.
         385             511 :             JSFunction *fun = obj->asCall().getCalleeFunction();
         386             511 :             uint16_t slot = uint16_t(shape->shortid());
         387                 :
         388                 :             /* Guard that the call object has a frame. */
         389             511 :             masm.loadObjPrivate(pic.objReg, pic.shapeReg, obj->numFixedSlots());
         390             511 :             Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg);
         391                 :
         392                 :             {
         393             511 :                 Address addr(pic.shapeReg, shape->setterOp() == CallObject::setArgOp
         394              31 :                                            ? StackFrame::offsetOfFormalArg(fun, slot)
         395             542 :                                            : StackFrame::offsetOfFixed(slot));
         396             511 :                 masm.storeValue(pic.u.vr, addr);
         397             511 :                 skipOver = masm.jump();
         398                 :             }
         399                 :
         400             511 :             escapedFrame.linkTo(masm.label(), &masm);
         401                 :             {
         402             511 :                 if (shape->setterOp() == CallObject::setVarOp)
         403             480 :                     slot += fun->nargs;
         404                 :
         405             511 :                 slot += CallObject::RESERVED_SLOTS;
         406             511 :                 Address address = masm.objPropAddress(obj, pic.objReg, slot);
         407                 :
         408             511 :                 masm.storeValue(pic.u.vr, address);
         409                 :             }
         410                 :
         411             511 :             pic.shapeRegHasBaseShape = false;
         412                 :         }
         413                 :
         414            2582 :         Jump done = masm.jump();
         415                 :
         416                 :         // Common all secondary guards into one big exit.
         417            2582 :         MaybeJump slowExit;
         418            2582 :         if (otherGuards.length()) {
         419            5617 :             for (Jump *pj = otherGuards.begin(); pj != otherGuards.end(); ++pj)
         420            3814 :                 pj->linkTo(masm.label(), &masm);
         421            1803 :             slowExit = masm.jump();
         422            1803 :             pic.secondShapeGuard = masm.distanceOf(masm.label()) - masm.distanceOf(start);
         423                 :         } else {
         424             779 :             pic.secondShapeGuard = 0;
         425                 :         }
         426                 :
         427            2582 :         pic.updatePCCounters(f, masm);
         428                 :
         429            5164 :         PICLinker buffer(masm, pic);
         430            2582 :         if (!buffer.init(cx))
         431               0 :             return error();
         432                 :
         433            5164 :         if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
         434            2582 :             !buffer.verifyRange(f.chunk())) {
         435               0 :             return disable("code memory is out of range");
         436                 :         }
         437                 :
         438            2582 :         buffer.link(shapeGuard, pic.slowPathStart);
         439            2582 :         if (slowExit.isSet())
         440            1803 :             buffer.link(slowExit.get(), pic.slowPathStart);
         441            2582 :         for (Jump *pj = slowExits.begin(); pj != slowExits.end(); ++pj)
         442               0 :             buffer.link(*pj, pic.slowPathStart);
         443            2582 :         buffer.link(done, pic.fastPathRejoin);
         444            2582 :         if (skipOver.isSet())
         445             511 :             buffer.link(skipOver.get(), pic.fastPathRejoin);
         446            2582 :         CodeLocationLabel cs = buffer.finalize(f);
         447                 :         JaegerSpew(JSpew_PICs, "generate setprop stub %p %p %d at %p\n",
         448                 :                    (void*)&pic,
         449                 :                    (void*)initialShape,
         450                 :                    pic.stubsGenerated,
         451            2582 :                    cs.executableAddress());
         452                 :
         453                 :         // This function can patch either the inline fast path for a generated
         454                 :         // stub. The stub omits the prefix of the inline fast path that loads
         455                 :         // the shape, so the offsets are different.
         456            2582 :         patchPreviousToHere(cs);
         457                 :
         458            2582 :         pic.stubsGenerated++;
         459            2582 :         pic.updateLastPath(buffer, start);
         460                 :
         461            2582 :         if (pic.stubsGenerated == MAX_PIC_STUBS)
         462               6 :             disable("max stubs reached");
         463                 :
         464            2582 :         return Lookup_Cacheable;
         465                 :     }
         466                 :
         467             515 :     bool updateMonitoredTypes()
         468                 :     {
         469             515 :         JS_ASSERT(pic.typeMonitored);
         470                 :
         471             515 :         RecompilationMonitor monitor(cx);
         472             515 :         jsid id = ATOM_TO_JSID(name);
         473                 :
         474             515 :         if (!obj->getType(cx)->unknownProperties()) {
         475             946 :             types::AutoEnterTypeInference enter(cx);
         476             473 :             types::TypeSet *types = obj->getType(cx)->getProperty(cx, types::MakeTypeId(cx, id), true);
         477             473 :             if (!types)
         478               0 :                 return false;
         479             946 :             pic.rhsTypes->addSubset(cx, types);
         480                 :         }
         481                 :
         482             515 :         return !monitor.recompiled();
         483                 :     }
         484                 :
         485            4900 :     LookupStatus update()
         486                 :     {
         487            4900 :         JS_ASSERT(pic.hit);
         488                 :
         489            4900 :         if (obj->isDenseArray())
         490              67 :             return disable("dense array");
         491            4833 :         if (!obj->isNative())
         492             148 :             return disable("non-native");
         493            4685 :         if (obj->watched())
         494              47 :             return disable("watchpoint");
         495                 :
         496            4638 :         Class *clasp = obj->getClass();
         497                 :
         498            4638 :         if (clasp->setProperty != JS_StrictPropertyStub)
         499               0 :             return disable("set property hook");
         500            4638 :         if (clasp->ops.lookupProperty)
         501               4 :             return disable("ops lookup property hook");
         502            4634 :         if (clasp->ops.setProperty)
         503               0 :             return disable("ops set property hook");
         504                 :
         505                 :         JSObject *holder;
         506            4634 :         JSProperty *prop = NULL;
         507                 :
         508                 :         /* lookupProperty can trigger recompilations. */
         509            4634 :         RecompilationMonitor monitor(cx);
         510            4634 :         if (!obj->lookupProperty(cx, name, &holder, &prop))
         511               0 :             return error();
         512            4634 :         if (monitor.recompiled())
         513               0 :             return Lookup_Uncacheable;
         514                 :
         515                 :         /* If the property exists but is on a prototype, treat as addprop. */
         516            4634 :         if (prop && holder != obj) {
         517             795 :             const Shape *shape = (const Shape *) prop;
         518                 :
         519             795 :             if (!holder->isNative())
         520               0 :                 return disable("non-native holder");
         521                 :
         522             795 :             if (!shape->writable())
         523               0 :                 return disable("readonly");
         524             795 :             if (!shape->hasDefaultSetter() || !shape->hasDefaultGetter())
         525             406 :                 return disable("getter/setter in prototype");
         526             389 :             if (shape->hasShortID())
         527               0 :                 return disable("short ID in prototype");
         528             389 :             if (!shape->hasSlot())
         529               0 :                 return disable("missing slot");
         530                 :
         531             389 :             prop = NULL;
         532                 :         }
         533                 :
         534            4228 :         if (!prop) {
         535                 :             /* Adding a property to the object. */
         536            1368 :             if (obj->isDelegate())
         537               8 :                 return disable("delegate");
         538            1360 :             if (!obj->isExtensible())
         539               0 :                 return disable("not extensible");
         540                 :
         541            1360 :             if (clasp->addProperty != JS_PropertyStub)
         542               4 :                 return disable("add property hook");
         543            1356 :             if (clasp->ops.defineProperty)
         544               0 :                 return disable("ops define property hook");
         545                 :
         546                 :             /*
         547                 :              * Don't add properties for SETNAME, which requires checks in
         548                 :              * strict mode code.
         549                 :              */
         550            1356 :             if (JSOp(*f.pc()) == JSOP_SETNAME)
         551               2 :                 return disable("add property under SETNAME");
         552                 :
         553                 :             /*
         554                 :              * When adding a property we need to check shapes along the entire
         555                 :              * prototype chain to watch for an added setter.
         556                 :              */
         557            1354 :             JSObject *proto = obj;
         558            6713 :             while (proto) {
         559            4009 :                 if (!proto->isNative())
         560               4 :                     return disable("non-native proto");
         561            4005 :                 proto = proto->getProto();
         562                 :             }
         563                 :
         564            1350 :             const Shape *initialShape = obj->lastProperty();
         565            1350 :             uint32_t slots = obj->numDynamicSlots();
         566                 :
         567            1350 :             unsigned flags = 0;
         568            1350 :             PropertyOp getter = clasp->getProperty;
         569                 :
         570                 :             /*
         571                 :              * Define the property but do not set it yet. For setmethod,
         572                 :              * populate the slot to satisfy the method invariant (in case we
         573                 :              * hit an early return below).
         574                 :              */
         575                 :             const Shape *shape =
         576                 :                 obj->putProperty(cx, name, getter, clasp->setProperty,
         577            1350 :                                  SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0);
         578            1350 :             if (!shape)
         579               0 :                 return error();
         580                 :
         581            1350 :             if (monitor.recompiled())
         582               0 :                 return Lookup_Uncacheable;
         583                 :
         584                 :             /*
         585                 :              * Test after calling putProperty since it can switch obj into
         586                 :              * dictionary mode, specifically if the shape tree ancestor line
         587                 :              * exceeds PropertyTree::MAX_HEIGHT.
         588                 :              */
         589            1350 :             if (obj->inDictionaryMode())
         590               2 :                 return disable("dictionary");
         591                 :
         592            1348 :             if (!shape->hasDefaultSetter())
         593               0 :                 return disable("adding non-default setter");
         594            1348 :             if (!shape->hasSlot())
         595               0 :                 return disable("adding invalid slot");
         596                 :
         597                 :             /*
         598                 :              * Watch for cases where the object reallocated its slots when
         599                 :              * adding the property, and disable the PIC.  Otherwise we will
         600                 :              * keep generating identical PICs as side exits are taken on the
         601                 :              * capacity checks.  Alternatively, we could avoid the disable
         602                 :              * and just not generate a stub in case there are multiple shapes
         603                 :              * that can flow here which don't all require reallocation.
         604                 :              * Doing this would cause us to walk down this same update path
         605                 :              * every time a reallocation is needed, however, which will
         606                 :              * usually be a slowdown even if there *are* other shapes that
         607                 :              * don't realloc.
         608                 :              */
         609            1348 :             if (obj->numDynamicSlots() != slots)
         610             104 :                 return disable("insufficient slot capacity");
         611                 :
         612            1244 :             if (pic.typeMonitored && !updateMonitoredTypes())
         613               0 :                 return Lookup_Uncacheable;
         614                 :
         615            1244 :             return generateStub(initialShape, shape, true);
         616                 :         }
         617                 :
         618            2860 :         const Shape *shape = (const Shape *) prop;
         619            2860 :         if (!shape->writable())
         620               2 :             return disable("readonly");
         621            2858 :         if (shape->hasDefaultSetter()) {
         622            2312 :             if (!shape->hasSlot())
         623               0 :                 return disable("invalid slot");
         624            2312 :             if (pic.typeMonitored && !updateMonitoredTypes())
         625               0 :                 return Lookup_Uncacheable;
         626                 :         } else {
         627             546 :             if (shape->hasSetterValue())
         628              11 :                 return disable("scripted setter");
         629            1039 :             if (shape->setterOp() != CallObject::setArgOp &&
         630             504 :                 shape->setterOp() != CallObject::setVarOp) {
         631              24 :                 return disable("setter");
         632                 :             }
         633             511 :             JS_ASSERT(obj->isCall());
         634             511 :             if (pic.typeMonitored) {
         635                 :                 /*
         636                 :                  * Update the types of the locals/args in the script according
         637                 :                  * to the possible RHS types of the assignment. Note that the
         638                 :                  * shape guards we have performed do not by themselves
         639                 :                  * guarantee that future call objects hit will be for the same
         640                 :                  * script. We also depend on the fact that the scope chains hit
         641                 :                  * at the same bytecode are all isomorphic: the same scripts,
         642                 :                  * in the same order (though the properties on their call
         643                 :                  * objects may differ due to eval(), DEFFUN, etc.).
         644                 :                  */
         645             147 :                 RecompilationMonitor monitor(cx);
         646             147 :                 JSFunction *fun = obj->asCall().getCalleeFunction();
         647             147 :                 JSScript *script = fun->script();
         648             147 :                 uint16_t slot = uint16_t(shape->shortid());
         649             147 :                 if (!script->ensureHasTypes(cx))
         650               0 :                     return error();
         651                 :                 {
         652             294 :                     types::AutoEnterTypeInference enter(cx);
         653             147 :                     if (shape->setterOp() == CallObject::setArgOp)
         654               9 :                         pic.rhsTypes->addSubset(cx, types::TypeScript::ArgTypes(script, slot));
         655                 :                     else
         656             138 :                         pic.rhsTypes->addSubset(cx, types::TypeScript::LocalTypes(script, slot));
         657                 :                 }
         658             147 :                 if (monitor.recompiled())
         659               0 :                     return Lookup_Uncacheable;
         660                 :             }
         661                 :         }
         662                 :
         663            2823 :         JS_ASSERT(obj == holder);
         664            8613 :         if (!pic.inlinePathPatched &&
         665            2408 :             shape->hasDefaultSetter() &&
         666            1897 :             !pic.typeMonitored &&
         667            1485 :             !obj->isDenseArray()) {
         668            1485 :             return patchInline(shape);
         669                 :         }
         670                 :
         671            1338 :         return generateStub(obj->lastProperty(), shape, false);
         672                 :     }
         673                 : };
         674                 :
         675                 : static bool
         676           54988 : IsCacheableProtoChain(JSObject *obj, JSObject *holder)
         677                 : {
         678          119254 :     while (obj != holder) {
         679                 :         /*
         680                 :          * We cannot assume that we find the holder object on the prototype
         681                 :          * chain and must check for null proto. The prototype chain can be
         682                 :          * altered during the lookupProperty call.
         683                 :          */
         684            9300 :         JSObject *proto = obj->getProto();
         685            9300 :         if (!proto || !proto->isNative())
         686              22 :             return false;
         687            9278 :         obj = proto;
         688                 :     }
         689           54966 :     return true;
         690                 : }
         691                 :
         692                 : template <typename IC>
         693                 : struct GetPropHelper {
         694                 :     // These fields are set in the constructor and describe a property lookup.
         695                 :     JSContext   *cx;
         696                 :     JSObject    *obj;
         697                 :     PropertyName *name;
         698                 :     IC          &ic;
         699                 :     VMFrame     &f;
         700                 :
         701                 :     // These fields are set by |bind| and |lookup|. After a call to either
         702                 :     // function, these are set exactly as they are in JSOP_GETPROP or JSOP_NAME.
         703                 :     JSObject    *aobj;
         704                 :     JSObject    *holder;
         705                 :     JSProperty  *prop;
         706                 :
         707                 :     // This field is set by |bind| and |lookup| only if they returned
         708                 :     // Lookup_Cacheable, otherwise it is NULL.
         709                 :     const Shape *shape;
         710                 :
         711           55982 :     GetPropHelper(JSContext *cx, JSObject *obj, PropertyName *name, IC &ic, VMFrame &f)
         712           55982 :       : cx(cx), obj(obj), name(name), ic(ic), f(f), holder(NULL), prop(NULL), shape(NULL)
         713           55982 :     { }
         714                 :
         715                 :   public:
         716           22938 :     LookupStatus bind() {
         717           22938 :         RecompilationMonitor monitor(cx);
         718           22938 :         JSObject *scopeChain = cx->stack.currentScriptedScopeChain();
         719           22938 :         if (js_CodeSpec[*f.pc()].format & JOF_GNAME)
         720               0 :             scopeChain = &scopeChain->global();
         721           22938 :         if (!FindProperty(cx, name, scopeChain, &obj, &holder, &prop))
         722               0 :             return ic.error(cx);
         723           22938 :         if (monitor.recompiled())
         724               2 :             return Lookup_Uncacheable;
         725           22936 :         if (!prop)
         726              76 :             return ic.disable(cx, "lookup failed");
         727           22860 :         if (!obj->isNative())
         728               0 :             return ic.disable(cx, "non-native");
         729           22860 :         if (!IsCacheableProtoChain(obj, holder))
         730               4 :             return ic.disable(cx, "non-native holder");
         731           22856 :         shape = (const Shape *)prop;
         732           22856 :         return Lookup_Cacheable;
         733                 :     }
         734                 :
         735           33044 :     LookupStatus lookup() {
         736           33044 :         JSObject *aobj = js_GetProtoIfDenseArray(obj);
         737           33044 :         if (!aobj->isNative())
         738             749 :             return ic.disable(f, "non-native");
         739                 :
         740           32295 :         RecompilationMonitor monitor(cx);
         741           32295 :         if (!aobj->lookupProperty(cx, name, &holder, &prop))
         742               0 :             return ic.error(cx);
         743           32295 :         if (monitor.recompiled())
         744               0 :             return Lookup_Uncacheable;
         745                 :
         746           32295 :         if (!prop)
         747             167 :             return ic.disable(f, "lookup failed");
         748           32128 :         if (!IsCacheableProtoChain(obj, holder))
         749              18 :             return ic.disable(f, "non-native holder");
         750           32110 :         shape = (const Shape *)prop;
         751           32110 :         return Lookup_Cacheable;
         752                 :     }
         753                 :
         754           47127 :     LookupStatus testForGet() {
         755           47127 :         if (!shape->hasDefaultGetter()) {
         756            1808 :             if (shape->hasGetterValue())
         757            1194 :                 return ic.disable(f, "getter value shape");
         758             614 :             if (shape->hasSlot() && holder != obj)
         759               0 :                 return ic.disable(f, "slotful getter hook through prototype");
         760             614 :             if (!ic.canCallHook)
         761             450 :                 return ic.disable(f, "can't call getter hook");
         762             164 :             if (f.regs.inlined()) {
         763                 :                 /*
         764                 :                  * As with native stubs, getter hook stubs can't be
         765                 :                  * generated for inline frames. Mark the inner function
         766                 :                  * as uninlineable and recompile.
         767                 :                  */
         768               0 :                 f.script()->uninlineable = true;
         769               0 :                 MarkTypeObjectFlags(cx, f.script()->function(),
         770                 :                                     types::OBJECT_FLAG_UNINLINEABLE);
         771               0 :                 return Lookup_Uncacheable;
         772                 :             }
         773           45319 :         } else if (!shape->hasSlot()) {
         774              29 :             return ic.disable(f, "no slot");
         775                 :         }
         776                 :
         777           45454 :         return Lookup_Cacheable;
         778                 :     }
         779                 :
         780           32789 :     LookupStatus lookupAndTest() {
         781           32789 :         LookupStatus status = lookup();
         782           32789 :         if (status != Lookup_Cacheable)
         783             934 :             return status;
         784           31855 :         return testForGet();
         785                 :     }
         786                 : };
         787                 :
         788                 : class GetPropCompiler : public PICStubCompiler
         789                 : {
         790                 :     JSObject    *obj;
         791                 :     PropertyName *name;
         792                 :     int         lastStubSecondShapeGuard;
         793                 :
         794                 :   public:
         795           32186 :     GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, PropertyName *name,
         796                 :                     VoidStubPIC stub)
         797                 :       : PICStubCompiler("getprop", f, script, pic,
         798                 :                         JS_FUNC_TO_DATA_PTR(void *, stub)),
         799                 :         obj(obj),
         800                 :         name(name),
         801           32186 :         lastStubSecondShapeGuard(pic.secondShapeGuard)
         802           32186 :     { }
         803                 :
         804           14849 :     int getLastStubSecondShapeGuard() const {
         805           14849 :         return lastStubSecondShapeGuard ? POST_INST_OFFSET(lastStubSecondShapeGuard) : 0;
         806                 :     }
         807                 :
         808                 :     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
         809                 :     {
         810                 :         GetPropLabels &labels = pic.getPropLabels();
         811                 :         repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin));
         812                 :         repatcher.repatch(labels.getInlineShapeData(pic.getFastShapeGuard()), NULL);
         813                 :         repatcher.relink(labels.getInlineShapeJump(pic.getFastShapeGuard()), pic.slowPathStart);
         814                 :
         815                 :         if (pic.hasTypeCheck()) {
         816                 :             /* TODO: combine pic.u.get into ICLabels? */
         817                 :             repatcher.relink(labels.getInlineTypeJump(pic.fastPathStart), pic.getSlowTypeCheck());
         818                 :         }
         819                 :
         820                 :         JS_ASSERT(pic.kind == ic::PICInfo::GET);
         821                 :
         822                 :         FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, ic::GetProp));
         823                 :         repatcher.relink(pic.slowPathCall, target);
         824                 :     }
         825                 :
         826            5199 :     LookupStatus generateArrayLengthStub()
         827                 :     {
         828           10398 :         Assembler masm;
         829                 :
         830            5199 :         masm.loadObjClass(pic.objReg, pic.shapeReg);
         831            5199 :         Jump isDense = masm.testClass(Assembler::Equal, pic.shapeReg, &ArrayClass);
         832            5199 :         Jump notArray = masm.testClass(Assembler::NotEqual, pic.shapeReg, &SlowArrayClass);
         833                 :
         834            5199 :         isDense.linkTo(masm.label(), &masm);
         835            5199 :         masm.loadPtr(Address(pic.objReg, JSObject::offsetOfElements()), pic.objReg);
         836            5199 :         masm.load32(Address(pic.objReg, ObjectElements::offsetOfLength()), pic.objReg);
         837            5199 :         Jump oob = masm.branch32(Assembler::Above, pic.objReg, Imm32(JSVAL_INT_MAX));
         838            5199 :         masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
         839            5199 :         Jump done = masm.jump();
         840                 :
         841            5199 :         pic.updatePCCounters(f, masm);
         842                 :
         843           10398 :         PICLinker buffer(masm, pic);
         844            5199 :         if (!buffer.init(cx))
         845               0 :             return error();
         846                 :
         847           10398 :         if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
         848            5199 :             !buffer.verifyRange(f.chunk())) {
         849               0 :             return disable("code memory is out of range");
         850                 :         }
         851                 :
         852            5199 :         buffer.link(notArray, pic.slowPathStart);
         853            5199 :         buffer.link(oob, pic.slowPathStart);
         854            5199 :         buffer.link(done, pic.fastPathRejoin);
         855                 :
         856            5199 :         CodeLocationLabel start = buffer.finalize(f);
         857                 :         JaegerSpew(JSpew_PICs, "generate array length stub at %p\n",
         858            5199 :                    start.executableAddress());
         859                 :
         860            5199 :         patchPreviousToHere(start);
         861                 :
         862            5199 :         disable("array length done");
         863                 :
         864            5199 :         return Lookup_Cacheable;
         865                 :     }
         866                 :
         867              69 :     LookupStatus generateStringObjLengthStub()
         868                 :     {
         869             138 :         Assembler masm;
         870                 :
         871              69 :         Jump notStringObj = masm.guardShape(pic.objReg, obj);
         872                 :
         873              69 :         masm.loadPayload(Address(pic.objReg, StringObject::getPrimitiveValueOffset()), pic.objReg);
         874              69 :         masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg);
         875              69 :         masm.urshift32(Imm32(JSString::LENGTH_SHIFT), pic.objReg);
         876              69 :         masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
         877              69 :         Jump done = masm.jump();
         878                 :
         879              69 :         pic.updatePCCounters(f, masm);
         880                 :
         881             138 :         PICLinker buffer(masm, pic);
         882              69 :         if (!buffer.init(cx))
         883               0 :             return error();
         884                 :
         885             138 :         if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
         886              69 :             !buffer.verifyRange(f.chunk())) {
         887               0 :             return disable("code memory is out of range");
         888                 :         }
         889                 :
         890              69 :         buffer.link(notStringObj, pic.slowPathStart);
         891              69 :         buffer.link(done, pic.fastPathRejoin);
         892                 :
         893              69 :         CodeLocationLabel start = buffer.finalize(f);
         894                 :         JaegerSpew(JSpew_PICs, "generate string object length stub at %p\n",
         895              69 :                    start.executableAddress());
         896                 :
         897              69 :         patchPreviousToHere(start);
         898                 :
         899              69 :         disable("string object length done");
         900                 :
         901              69 :         return Lookup_Cacheable;
         902                 :     }
         903                 :
         904             879 :     LookupStatus generateStringPropertyStub()
         905                 :     {
         906             879 :         if (!f.fp()->script()->hasGlobal())
         907              36 :             return disable("String.prototype without compile-and-go global");
         908                 :
         909             843 :         RecompilationMonitor monitor(f.cx);
         910                 :
         911             843 :         JSObject *obj = f.fp()->scopeChain().global().getOrCreateStringPrototype(f.cx);
         912             843 :         if (!obj)
         913               0 :             return error();
         914                 :
         915             843 :         if (monitor.recompiled())
         916               7 :             return Lookup_Uncacheable;
         917                 :
         918             836 :         GetPropHelper<GetPropCompiler> getprop(cx, obj, name, *this, f);
         919             836 :         LookupStatus status = getprop.lookupAndTest();
         920             836 :         if (status != Lookup_Cacheable)
         921               4 :             return status;
         922             832 :         if (getprop.obj != getprop.holder)
         923               2 :             return disable("proto walk on String.prototype");
         924             830 :         if (!getprop.shape->hasDefaultGetter())
         925               0 :             return disable("getter hook on String.prototype");
         926             830 :         if (hadGC())
         927               0 :             return Lookup_Uncacheable;
         928                 :
         929            1660 :         Assembler masm;
         930                 :
         931                 :         /* Only strings are allowed. */
         932                 :         Jump notString = masm.branchPtr(Assembler::NotEqual, pic.typeReg(),
         933             830 :                                         ImmType(JSVAL_TYPE_STRING));
         934                 :
         935                 :         /*
         936                 :          * Clobber objReg with String.prototype and do some PIC stuff. Well,
         937                 :          * really this is now a MIC, except it won't ever be patched, so we
         938                 :          * just disable the PIC at the end. :FIXME:? String.prototype probably
         939                 :          * does not get random shape changes.
         940                 :          */
         941             830 :         masm.move(ImmPtr(obj), pic.objReg);
         942             830 :         masm.loadShape(pic.objReg, pic.shapeReg);
         943                 :         Jump shapeMismatch = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
         944             830 :                                             ImmPtr(obj->lastProperty()));
         945             830 :         masm.loadObjProp(obj, pic.objReg, getprop.shape, pic.shapeReg, pic.objReg);
         946                 :
         947             830 :         Jump done = masm.jump();
         948                 :
         949             830 :         pic.updatePCCounters(f, masm);
         950                 :
         951            1660 :         PICLinker buffer(masm, pic);
         952             830 :         if (!buffer.init(cx))
         953               0 :             return error();
         954                 :
         955            1660 :         if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
         956             830 :             !buffer.verifyRange(f.chunk())) {
         957               0 :             return disable("code memory is out of range");
         958                 :         }
         959                 :
         960             830 :         buffer.link(notString, pic.getSlowTypeCheck());
         961             830 :         buffer.link(shapeMismatch, pic.slowPathStart);
         962             830 :         buffer.link(done, pic.fastPathRejoin);
         963                 :
         964             830 :         CodeLocationLabel cs = buffer.finalize(f);
         965                 :         JaegerSpew(JSpew_PICs, "generate string call stub at %p\n",
         966             830 :                    cs.executableAddress());
         967                 :
         968                 :         /* Patch the type check to jump here. */
         969             830 :         if (pic.hasTypeCheck()) {
         970            1660 :             Repatcher repatcher(f.chunk());
         971             830 :             repatcher.relink(pic.getPropLabels().getInlineTypeJump(pic.fastPathStart), cs);
         972                 :         }
         973                 :
         974                 :         /* Disable the PIC so we don't keep generating stubs on the above shape mismatch. */
         975             830 :         disable("generated string call stub");
         976             830 :         return Lookup_Cacheable;
         977                 :     }
         978                 :
         979             121 :     LookupStatus generateStringLengthStub()
         980                 :     {
         981             121 :         JS_ASSERT(pic.hasTypeCheck());
         982                 :
         983             242 :         Assembler masm;
         984                 :         Jump notString = masm.branchPtr(Assembler::NotEqual, pic.typeReg(),
         985             121 :                                         ImmType(JSVAL_TYPE_STRING));
         986             121 :         masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg);
         987                 :         // String length is guaranteed to be no more than 2**28, so the 32-bit operation is OK.
         988             121 :         masm.urshift32(Imm32(JSString::LENGTH_SHIFT), pic.objReg);
         989             121 :         masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
         990             121 :         Jump done = masm.jump();
         991                 :
         992             121 :         pic.updatePCCounters(f, masm);
         993                 :
         994             242 :         PICLinker buffer(masm, pic);
         995             121 :         if (!buffer.init(cx))
         996               0 :             return error();
         997                 :
         998             242 :         if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
         999             121 :             !buffer.verifyRange(f.chunk())) {
        1000               0 :             return disable("code memory is out of range");
        1001                 :         }
        1002                 :
        1003             121 :         buffer.link(notString, pic.getSlowTypeCheck());
        1004             121 :         buffer.link(done, pic.fastPathRejoin);
        1005                 :
        1006             121 :         CodeLocationLabel start = buffer.finalize(f);
        1007                 :         JaegerSpew(JSpew_PICs, "generate string length stub at %p\n",
        1008             121 :                    start.executableAddress());
        1009                 :
        1010             121 :         if (pic.hasTypeCheck()) {
        1011             242 :             Repatcher repatcher(f.chunk());
        1012             121 :             repatcher.relink(pic.getPropLabels().getInlineTypeJump(pic.fastPathStart), start);
        1013                 :         }
        1014                 :
        1015             121 :         disable("generated string length stub");
        1016                 :
        1017             121 :         return Lookup_Cacheable;
        1018                 :     }
        1019                 :
        1020           14097 :     LookupStatus patchInline(JSObject *holder, const Shape *shape)
        1021                 :     {
        1022           14097 :         spew("patch", "inline");
        1023           28194 :         Repatcher repatcher(f.chunk());
        1024           14097 :         GetPropLabels &labels = pic.getPropLabels();
        1025                 :
        1026                 :         int32_t offset;
        1027           14097 :         if (holder->isFixedSlot(shape->slot())) {
        1028            8908 :             CodeLocationInstruction istr = labels.getDslotsLoad(pic.fastPathRejoin);
        1029            8908 :             repatcher.repatchLoadPtrToLEA(istr);
        1030                 :
        1031                 :             //
        1032                 :             // We've patched | mov dslots, [obj + DSLOTS_OFFSET]
        1033                 :             // To:           | lea fslots, [obj + DSLOTS_OFFSET]
        1034                 :             //
        1035                 :             // Because the offset is wrong, it's necessary to correct it
        1036                 :             // below.
        1037                 :             //
        1038            8908 :             int32_t diff = int32_t(JSObject::getFixedSlotOffset(0)) -
        1039            8908 :                          int32_t(JSObject::offsetOfSlots());
        1040            8908 :             JS_ASSERT(diff != 0);
        1041            8908 :             offset  = (int32_t(shape->slot()) * sizeof(Value)) + diff;
        1042                 :         } else {
        1043            5189 :             offset = holder->dynamicSlotIndex(shape->slot()) * sizeof(Value);
        1044                 :         }
        1045                 :
        1046           14097 :         repatcher.repatch(labels.getInlineShapeData(pic.getFastShapeGuard()), obj->lastProperty());
        1047           14097 :         repatcher.patchAddressOffsetForValueLoad(labels.getValueLoad(pic.fastPathRejoin), offset);
        1048                 :
        1049           14097 :         pic.inlinePathPatched = true;
        1050                 :
        1051           14097 :         return Lookup_Cacheable;
        1052                 :     }
        1053                 :
        1054             164 :     void generateGetterStub(Assembler &masm, const Shape *shape,
        1055                 :                             Label start, Vector<Jump, 8> &shapeMismatches)
        1056                 :     {
        1057                 :         /*
        1058                 :          * Getter hook needs to be called from the stub. The state is fully
        1059                 :          * synced and no registers are live except the result registers.
        1060                 :          */
        1061             164 :         JS_ASSERT(pic.canCallHook);
        1062             164 :         PropertyOp getter = shape->getterOp();
        1063                 :
        1064                 :         masm.storePtr(ImmPtr((void *) REJOIN_NATIVE_GETTER),
        1065             164 :                       FrameAddress(offsetof(VMFrame, stubRejoin)));
        1066                 :
        1067             164 :         Registers tempRegs = Registers::tempCallRegMask();
        1068             164 :         if (tempRegs.hasReg(Registers::ClobberInCall))
        1069             164 :             tempRegs.takeReg(Registers::ClobberInCall);
        1070                 :
        1071                 :         /* Get a register to hold obj while we set up the rest of the frame. */
        1072             164 :         RegisterID holdObjReg = pic.objReg;
        1073             164 :         if (tempRegs.hasReg(pic.objReg)) {
        1074             142 :             tempRegs.takeReg(pic.objReg);
        1075                 :         } else {
        1076              22 :             holdObjReg = tempRegs.takeAnyReg().reg();
        1077              22 :             masm.move(pic.objReg, holdObjReg);
        1078                 :         }
        1079                 :
        1080             164 :         RegisterID t0 = tempRegs.takeAnyReg().reg();
        1081             164 :         masm.bumpStubCount(f.script(), f.pc(), t0);
        1082                 :
        1083                 :         /*
        1084                 :          * Initialize vp, which is either a slot in the object (the holder,
        1085                 :          * actually, which must equal the object here) or undefined.
        1086                 :          * Use vp == sp (which for CALLPROP will actually be the original
        1087                 :          * sp + 1), to avoid clobbering stack values.
        1088                 :          */
        1089             164 :         int32_t vpOffset = (char *) f.regs.sp - (char *) f.fp();
        1090             164 :         if (shape->hasSlot()) {
        1091                 :             masm.loadObjProp(obj, holdObjReg, shape,
        1092               5 :                              Registers::ClobberInCall, t0);
        1093               5 :             masm.storeValueFromComponents(Registers::ClobberInCall, t0, Address(JSFrameReg, vpOffset));
        1094                 :         } else {
        1095             159 :             masm.storeValue(UndefinedValue(), Address(JSFrameReg, vpOffset));
        1096                 :         }
        1097                 :
        1098             164 :         int32_t initialFrameDepth = f.regs.sp - f.fp()->slots();
        1099             164 :         masm.setupFallibleABICall(cx->typeInferenceEnabled(), f.regs.pc, initialFrameDepth);
        1100                 :
        1101                 :         /* Grab cx. */
        1102                 : #ifdef JS_CPU_X86
        1103             164 :         RegisterID cxReg = tempRegs.takeAnyReg().reg();
        1104                 : #else
        1105                 :         RegisterID cxReg = Registers::ArgReg0;
        1106                 : #endif
        1107             164 :         masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), cxReg);
        1108                 :
        1109                 :         /* Grap vp. */
        1110             164 :         RegisterID vpReg = t0;
        1111             164 :         masm.addPtr(Imm32(vpOffset), JSFrameReg, vpReg);
        1112                 :
        1113             164 :         masm.restoreStackBase();
        1114             164 :         masm.setupABICall(Registers::NormalCall, 4);
        1115             164 :         masm.storeArg(3, vpReg);
        1116             164 :         masm.storeArg(2, ImmPtr((void *) JSID_BITS(shape->getUserId())));
        1117             164 :         masm.storeArg(1, holdObjReg);
        1118             164 :         masm.storeArg(0, cxReg);
        1119                 :
        1120             164 :         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, getter), false);
        1121                 :
        1122             164 :         NativeStubLinker::FinalJump done;
        1123             164 :         if (!NativeStubEpilogue(f, masm, &done, 0, vpOffset, pic.shapeReg, pic.objReg))
        1124               0 :             return;
        1125             328 :         NativeStubLinker linker(masm, f.chunk(), f.regs.pc, done);
        1126             164 :         if (!linker.init(f.cx))
        1127               0 :             THROW();
        1128                 :
        1129             328 :         if (!linker.verifyRange(pic.lastCodeBlock(f.chunk())) ||
        1130             164 :             !linker.verifyRange(f.chunk())) {
        1131               0 :             disable("code memory is out of range");
        1132                 :             return;
        1133                 :         }
        1134                 :
        1135             164 :         linker.patchJump(pic.fastPathRejoin);
        1136                 :
        1137             164 :         linkerEpilogue(linker, start, shapeMismatches);
        1138                 :     }
        1139                 :
        1140            9581 :     LookupStatus generateStub(JSObject *holder, const Shape *shape)
        1141                 :     {
        1142           19162 :         Vector<Jump, 8> shapeMismatches(cx);
        1143                 :
        1144           19162 :         Assembler masm;
        1145                 :
        1146            9581 :         Label start;
        1147            9581 :         Jump shapeGuardJump;
        1148            9581 :         Jump argsLenGuard;
        1149                 :
        1150            9581 :         bool setStubShapeOffset = true;
        1151            9581 :         if (obj->isDenseArray()) {
        1152            1760 :             start = masm.label();
        1153                 :             shapeGuardJump = masm.branchPtr(Assembler::NotEqual,
        1154            1760 :                                             Address(pic.objReg, JSObject::offsetOfShape()),
        1155            3520 :                                             ImmPtr(obj->lastProperty()));
        1156                 :
        1157                 :             /*
        1158                 :              * No need to assert validity of GETPROP_STUB_SHAPE_JUMP in this case:
        1159                 :              * the IC is disabled after a dense array hit, so no patching can occur.
        1160                 :              */
        1161                 : #ifndef JS_HAS_IC_LABELS
        1162            1760 :             setStubShapeOffset = false;
        1163                 : #endif
        1164                 :         } else {
        1165            7821 :             if (pic.shapeNeedsRemat()) {
        1166            1259 :                 masm.loadShape(pic.objReg, pic.shapeReg);
        1167            1259 :                 pic.shapeRegHasBaseShape = true;
        1168                 :             }
        1169                 :
        1170            7821 :             start = masm.label();
        1171                 :             shapeGuardJump = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
        1172            7821 :                                             ImmPtr(obj->lastProperty()));
        1173                 :         }
        1174            9581 :         Label stubShapeJumpLabel = masm.label();
        1175                 :
        1176            9581 :         if (!shapeMismatches.append(shapeGuardJump))
        1177               0 :             return error();
        1178                 :
        1179            9581 :         RegisterID holderReg = pic.objReg;
        1180            9581 :         if (obj != holder) {
        1181            7373 :             if (!GeneratePrototypeGuards(cx, shapeMismatches, masm, obj, holder,
        1182            7373 :                                          pic.objReg, pic.shapeReg)) {
        1183               0 :                 return error();
        1184                 :             }
        1185                 :
        1186                 :             // Bake in the holder identity. Careful not to clobber |objReg|, since we can't remat it.
        1187            7373 :             holderReg = pic.shapeReg;
        1188            7373 :             masm.move(ImmPtr(holder), holderReg);
        1189            7373 :             pic.shapeRegHasBaseShape = false;
        1190                 :
        1191                 :             // Guard on the holder's shape.
        1192            7373 :             Jump j = masm.guardShape(holderReg, holder);
        1193            7373 :             if (!shapeMismatches.append(j))
        1194               0 :                 return error();
        1195                 :
        1196            7373 :             pic.secondShapeGuard = masm.distanceOf(masm.label()) - masm.distanceOf(start);
        1197                 :         } else {
        1198            2208 :             pic.secondShapeGuard = 0;
        1199                 :         }
        1200                 :
        1201            9581 :         if (!shape->hasDefaultGetter()) {
        1202             164 :             generateGetterStub(masm, shape, start, shapeMismatches);
        1203             164 :             if (setStubShapeOffset)
        1204             164 :                 pic.getPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel);
        1205             164 :             return Lookup_Cacheable;
        1206                 :         }
        1207                 :
        1208                 :         /* Load the value out of the object. */
        1209            9417 :         masm.loadObjProp(holder, holderReg, shape, pic.shapeReg, pic.objReg);
        1210            9417 :         Jump done = masm.jump();
        1211                 :
        1212            9417 :         pic.updatePCCounters(f, masm);
        1213                 :
        1214           18834 :         PICLinker buffer(masm, pic);
        1215            9417 :         if (!buffer.init(cx))
        1216               0 :             return error();
        1217                 :
        1218           18834 :         if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
        1219            9417 :             !buffer.verifyRange(f.chunk())) {
        1220               0 :             return disable("code memory is out of range");
        1221                 :         }
        1222                 :
        1223                 :         // The final exit jumps to the store-back in the inline stub.
        1224            9417 :         buffer.link(done, pic.fastPathRejoin);
        1225                 :
        1226            9417 :         linkerEpilogue(buffer, start, shapeMismatches);
        1227                 :
        1228            9417 :         if (setStubShapeOffset)
        1229            7657 :             pic.getPropLabels().setStubShapeJump(masm, start, stubShapeJumpLabel);
        1230            9417 :         return Lookup_Cacheable;
        1231                 :     }
        1232                 :
        1233            9581 :     void linkerEpilogue(LinkerHelper &buffer, Label start, Vector<Jump, 8> &shapeMismatches)
        1234                 :     {
        1235                 :         // The guard exit jumps to the original slow case.
        1236           26539 :         for (Jump *pj = shapeMismatches.begin(); pj != shapeMismatches.end(); ++pj)
        1237           16958 :             buffer.link(*pj, pic.slowPathStart);
        1238                 :
        1239            9581 :         CodeLocationLabel cs = buffer.finalize(f);
        1240            9581 :         JaegerSpew(JSpew_PICs, "generated %s stub at %p\n", type, cs.executableAddress());
        1241                 :
        1242            9581 :         patchPreviousToHere(cs);
        1243                 :
        1244            9581 :         pic.stubsGenerated++;
        1245            9581 :         pic.updateLastPath(buffer, start);
        1246                 :
        1247            9581 :         if (pic.stubsGenerated == MAX_PIC_STUBS)
        1248              27 :             disable("max stubs reached");
        1249            9581 :         if (obj->isDenseArray())
        1250            1760 :             disable("dense array");
        1251            9581 :     }
        1252                 :
        1253           14849 :     void patchPreviousToHere(CodeLocationLabel cs)
        1254                 :     {
        1255           29698 :         Repatcher repatcher(pic.lastCodeBlock(f.chunk()));
        1256           14849 :         CodeLocationLabel label = pic.lastPathStart();
        1257                 :
        1258                 :         // Patch either the inline fast path or a generated stub. The stub
        1259                 :         // omits the prefix of the inline fast path that loads the shape, so
        1260                 :         // the offsets are different.
        1261                 :         int shapeGuardJumpOffset;
        1262           14849 :         if (pic.stubsGenerated)
        1263            1900 :             shapeGuardJumpOffset = pic.getPropLabels().getStubShapeJumpOffset();
        1264                 :         else
        1265           12949 :             shapeGuardJumpOffset = pic.shapeGuard + pic.getPropLabels().getInlineShapeJumpOffset();
        1266           14849 :         int secondGuardOffset = getLastStubSecondShapeGuard();
        1267                 :
        1268                 :         JaegerSpew(JSpew_PICs, "Patching previous (%d stubs) (start %p) (offset %d) (second %d)\n",
        1269                 :                    (int) pic.stubsGenerated, label.executableAddress(),
        1270           14849 :                    shapeGuardJumpOffset, secondGuardOffset);
        1271                 :
        1272           14849 :         repatcher.relink(label.jumpAtOffset(shapeGuardJumpOffset), cs);
        1273           14849 :         if (secondGuardOffset)
        1274            1259 :             repatcher.relink(label.jumpAtOffset(secondGuardOffset), cs);
        1275           14849 :     }
        1276                 :
        1277           25918 :     LookupStatus update()
        1278                 :     {
        1279           25918 :         JS_ASSERT(pic.hit);
        1280                 :
        1281           25918 :         GetPropHelper<GetPropCompiler> getprop(cx, obj, name, *this, f);
        1282           25918 :         LookupStatus status = getprop.lookupAndTest();
        1283           25918 :         if (status != Lookup_Cacheable)
        1284            2240 :             return status;
        1285           23678 :         if (hadGC())
        1286               0 :             return Lookup_Uncacheable;
        1287                 :
        1288           56124 :         if (obj == getprop.holder &&
        1289           16305 :             getprop.shape->hasDefaultGetter() &&
        1290           16141 :             !pic.inlinePathPatched) {
        1291           14097 :             return patchInline(getprop.holder, getprop.shape);
        1292                 :         }
        1293                 :
        1294            9581 :         return generateStub(getprop.holder, getprop.shape);
        1295                 :     }
        1296                 : };
        1297                 :
        1298                 : class ScopeNameCompiler : public PICStubCompiler
        1299                 : {
        1300                 :   private:
        1301                 :     typedef Vector<Jump, 8> JumpList;
        1302                 :
        1303                 :     JSObject *scopeChain;
        1304                 :     PropertyName *name;
        1305                 :     GetPropHelper<ScopeNameCompiler> getprop;
        1306           23193 :     ScopeNameCompiler *thisFromCtor() { return this; }
        1307                 :
        1308           22022 :     void patchPreviousToHere(CodeLocationLabel cs)
        1309                 :     {
        1310           22022 :         ScopeNameLabels &       labels = pic.scopeNameLabels();
        1311           44044 :         Repatcher               repatcher(pic.lastCodeBlock(f.chunk()));
        1312           22022 :         CodeLocationLabel       start = pic.lastPathStart();
        1313           22022 :         JSC::CodeLocationJump   jump;
        1314                 :
        1315                 :         // Patch either the inline fast path or a generated stub.
        1316           22022 :         if (pic.stubsGenerated)
        1317             689 :             jump = labels.getStubJump(start);
        1318                 :         else
        1319           21333 :             jump = labels.getInlineJump(start);
        1320           22022 :         repatcher.relink(jump, cs);
        1321           22022 :     }
        1322                 :
        1323           22132 :     LookupStatus walkScopeChain(Assembler &masm, JumpList &fails)
        1324                 :     {
        1325                 :         /* Walk the scope chain. */
        1326           22132 :         JSObject *tobj = scopeChain;
        1327                 :
        1328                 :         /* For GETXPROP, we'll never enter this loop. */
        1329           22132 :         JS_ASSERT_IF(pic.kind == ic::PICInfo::XNAME, tobj && tobj == getprop.holder);
        1330           22132 :         JS_ASSERT_IF(pic.kind == ic::PICInfo::XNAME, getprop.obj == tobj);
        1331                 :
        1332           69119 :         while (tobj && tobj != getprop.holder) {
        1333           24965 :             if (!IsCacheableNonGlobalScope(tobj))
        1334             110 :                 return disable("non-cacheable scope chain object");
        1335           24855 :             JS_ASSERT(tobj->isNative());
        1336                 :
        1337                 :             /* Guard on intervening shapes. */
        1338           24855 :             masm.loadShape(pic.objReg, pic.shapeReg);
        1339                 :             Jump j = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
        1340           24855 :                                     ImmPtr(tobj->lastProperty()));
        1341           24855 :             if (!fails.append(j))
        1342               0 :                 return error();
        1343                 :
        1344                 :             /* Load the next link in the scope chain. */
        1345           24855 :             Address parent(pic.objReg, ScopeObject::offsetOfEnclosingScope());
        1346           24855 :             masm.loadPayload(parent, pic.objReg);
        1347                 :
        1348           24855 :             tobj = &tobj->asScope().enclosingScope();
        1349                 :         }
        1350                 :
        1351           22022 :         if (tobj != getprop.holder)
        1352               0 :             return disable("scope chain walk terminated early");
        1353                 :
        1354           22022 :         return Lookup_Cacheable;
        1355                 :     }
        1356                 :
        1357                 :   public:
        1358           23193 :     ScopeNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
        1359                 :                       PropertyName *name, VoidStubPIC stub)
        1360                 :       : PICStubCompiler("name", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
        1361                 :         scopeChain(scopeChain), name(name),
        1362           23193 :         getprop(f.cx, NULL, name, *thisFromCtor(), f)
        1363           23193 :     { }
        1364                 :
        1365                 :     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
        1366                 :     {
        1367                 :         ScopeNameLabels &labels = pic.scopeNameLabels();
        1368                 :
        1369                 :         /* Link the inline path back to the slow path. */
        1370                 :         JSC::CodeLocationJump inlineJump = labels.getInlineJump(pic.fastPathStart);
        1371                 :         repatcher.relink(inlineJump, pic.slowPathStart);
        1372                 :
        1373                 :         VoidStubPIC stub;
        1374                 :         switch (pic.kind) {
        1375                 :           case ic::PICInfo::NAME:
        1376                 :             stub = ic::Name;
        1377                 :             break;
        1378                 :           case ic::PICInfo::XNAME:
        1379                 :             stub = ic::XName;
        1380                 :             break;
        1381                 :           default:
        1382                 :             JS_NOT_REACHED("Invalid pic kind in ScopeNameCompiler::reset");
        1383                 :             return;
        1384                 :         }
        1385                 :         FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, stub));
        1386                 :         repatcher.relink(pic.slowPathCall, target);
        1387                 :     }
        1388                 :
        1389           14762 :     LookupStatus generateGlobalStub(JSObject *obj)
        1390                 :     {
        1391           29524 :         Assembler masm;
        1392           29524 :         JumpList fails(cx);
        1393           14762 :         ScopeNameLabels &labels = pic.scopeNameLabels();
        1394                 :
        1395                 :         /* For GETXPROP, the object is already in objReg. */
        1396           14762 :         if (pic.kind == ic::PICInfo::NAME)
        1397           14756 :             masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), pic.objReg);
        1398                 :
        1399           14762 :         JS_ASSERT(obj == getprop.holder);
        1400           14762 :         JS_ASSERT(getprop.holder == &scopeChain->global());
        1401                 :
        1402           14762 :         LookupStatus status = walkScopeChain(masm, fails);
        1403           14762 :         if (status != Lookup_Cacheable)
        1404              64 :             return status;
        1405                 :
        1406                 :         /* If a scope chain walk was required, the final object needs a NULL test. */
        1407           14698 :         MaybeJump finalNull;
        1408           14698 :         if (pic.kind == ic::PICInfo::NAME)
        1409           14692 :             finalNull = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg);
        1410           14698 :         masm.loadShape(pic.objReg, pic.shapeReg);
        1411                 :         Jump finalShape = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
        1412           14698 :                                          ImmPtr(getprop.holder->lastProperty()));
        1413                 :
        1414           14698 :         masm.loadObjProp(obj, pic.objReg, getprop.shape, pic.shapeReg, pic.objReg);
        1415                 :
        1416           14698 :         Jump done = masm.jump();
        1417                 :
        1418                 :         /* All failures flow to here, so there is a common point to patch. */
        1419           29396 :         for (Jump *pj = fails.begin(); pj != fails.end(); ++pj)
        1420           14698 :             pj->linkTo(masm.label(), &masm);
        1421           14698 :         if (finalNull.isSet())
        1422           14692 :             finalNull.get().linkTo(masm.label(), &masm);
        1423           14698 :         finalShape.linkTo(masm.label(), &masm);
        1424           14698 :         Label failLabel = masm.label();
        1425           14698 :         Jump failJump = masm.jump();
        1426                 :
        1427           14698 :         pic.updatePCCounters(f, masm);
        1428                 :
        1429           29396 :         PICLinker buffer(masm, pic);
        1430           14698 :         if (!buffer.init(cx))
        1431               0 :             return error();
        1432                 :
        1433           29396 :         if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
        1434           14698 :             !buffer.verifyRange(f.chunk())) {
        1435               0 :             return disable("code memory is out of range");
        1436                 :         }
        1437                 :
        1438           14698 :         buffer.link(failJump, pic.slowPathStart);
        1439           14698 :         buffer.link(done, pic.fastPathRejoin);
        1440           14698 :         CodeLocationLabel cs = buffer.finalize(f);
        1441           14698 :         JaegerSpew(JSpew_PICs, "generated %s global stub at %p\n", type, cs.executableAddress());
        1442           14698 :         spew("NAME stub", "global");
        1443                 :
        1444           14698 :         patchPreviousToHere(cs);
        1445                 :
        1446           14698 :         pic.stubsGenerated++;
        1447           14698 :         pic.updateLastPath(buffer, failLabel);
        1448           14698 :         labels.setStubJump(masm, failLabel, failJump);
        1449                 :
        1450           14698 :         if (pic.stubsGenerated == MAX_PIC_STUBS)
        1451              13 :             disable("max stubs reached");
        1452                 :
        1453           14698 :         return Lookup_Cacheable;
        1454                 :     }
        1455                 :
        1456                 :     enum CallObjPropKind {
        1457                 :         ARG,
        1458                 :         VAR
        1459                 :     };
        1460                 :
        1461            7795 :     LookupStatus generateCallStub(JSObject *obj)
        1462                 :     {
        1463           15590 :         Assembler masm;
        1464           15590 :         Vector<Jump, 8> fails(cx);
        1465            7795 :         ScopeNameLabels &labels = pic.scopeNameLabels();
        1466                 :
        1467                 :         /* For GETXPROP, the object is already in objReg. */
        1468            7795 :         if (pic.kind == ic::PICInfo::NAME)
        1469            7554 :             masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), pic.objReg);
        1470                 :
        1471            7795 :         JS_ASSERT(obj == getprop.holder);
        1472            7795 :         JS_ASSERT(getprop.holder != &scopeChain->global());
        1473                 :
        1474                 :         CallObjPropKind kind;
        1475            7795 :         const Shape *shape = getprop.shape;
        1476            7795 :         if (shape->getterOp() == CallObject::getArgOp) {
        1477            1409 :             kind = ARG;
        1478            6386 :         } else if (shape->getterOp() == CallObject::getVarOp) {
        1479            5961 :             kind = VAR;
        1480                 :         } else {
        1481             425 :             return disable("unhandled callobj sprop getter");
        1482                 :         }
        1483                 :
        1484            7370 :         LookupStatus status = walkScopeChain(masm, fails);
        1485            7370 :         if (status != Lookup_Cacheable)
        1486              46 :             return status;
        1487                 :
        1488                 :         /* If a scope chain walk was required, the final object needs a NULL test. */
        1489            7324 :         MaybeJump finalNull;
        1490            7324 :         if (pic.kind == ic::PICInfo::NAME)
        1491            7083 :             finalNull = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg);
        1492            7324 :         masm.loadShape(pic.objReg, pic.shapeReg);
        1493                 :         Jump finalShape = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
        1494            7324 :                                          ImmPtr(getprop.holder->lastProperty()));
        1495                 :
        1496                 :         /* Get callobj's stack frame. */
        1497            7324 :         masm.loadObjPrivate(pic.objReg, pic.shapeReg, getprop.holder->numFixedSlots());
        1498                 :
        1499            7324 :         JSFunction *fun = getprop.holder->asCall().getCalleeFunction();
        1500            7324 :         uint16_t slot = uint16_t(shape->shortid());
        1501                 :
        1502            7324 :         Jump skipOver;
        1503            7324 :         Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg);
        1504                 :
        1505                 :         /* Not-escaped case. */
        1506                 :         {
        1507            1395 :             Address addr(pic.shapeReg, kind == ARG ? StackFrame::offsetOfFormalArg(fun, slot)
        1508            8719 :                                                    : StackFrame::offsetOfFixed(slot));
        1509            7324 :             masm.loadPayload(addr, pic.objReg);
        1510            7324 :             masm.loadTypeTag(addr, pic.shapeReg);
        1511            7324 :             skipOver = masm.jump();
        1512                 :         }
        1513                 :
        1514            7324 :         escapedFrame.linkTo(masm.label(), &masm);
        1515                 :
        1516                 :         {
        1517            7324 :             if (kind == VAR)
        1518            5929 :                 slot += fun->nargs;
        1519                 :
        1520            7324 :             slot += CallObject::RESERVED_SLOTS;
        1521            7324 :             Address address = masm.objPropAddress(obj, pic.objReg, slot);
        1522                 :
        1523                 :             /* Safe because type is loaded first. */
        1524            7324 :             masm.loadValueAsComponents(address, pic.shapeReg, pic.objReg);
        1525                 :         }
        1526                 :
        1527            7324 :         skipOver.linkTo(masm.label(), &masm);
        1528            7324 :         Jump done = masm.jump();
        1529                 :
        1530                 :         // All failures flow to here, so there is a common point to patch.
        1531           17473 :         for (Jump *pj = fails.begin(); pj != fails.end(); ++pj)
        1532           10149 :             pj->linkTo(masm.label(), &masm);
        1533            7324 :         if (finalNull.isSet())
        1534            7083 :             finalNull.get().linkTo(masm.label(), &masm);
        1535            7324 :         finalShape.linkTo(masm.label(), &masm);
        1536            7324 :         Label failLabel = masm.label();
        1537            7324 :         Jump failJump = masm.jump();
        1538                 :
        1539            7324 :         pic.updatePCCounters(f, masm);
        1540                 :
        1541           14648 :         PICLinker buffer(masm, pic);
        1542            7324 :         if (!buffer.init(cx))
        1543               0 :             return error();
        1544                 :
        1545           14648 :         if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
        1546            7324 :             !buffer.verifyRange(f.chunk())) {
        1547               0 :             return disable("code memory is out of range");
        1548                 :         }
        1549                 :
        1550            7324 :         buffer.link(failJump, pic.slowPathStart);
        1551            7324 :         buffer.link(done, pic.fastPathRejoin);
        1552            7324 :         CodeLocationLabel cs = buffer.finalize(f);
        1553            7324 :         JaegerSpew(JSpew_PICs, "generated %s call stub at %p\n", type, cs.executableAddress());
        1554                 :
        1555            7324 :         patchPreviousToHere(cs);
        1556                 :
        1557            7324 :         pic.stubsGenerated++;
        1558            7324 :         pic.updateLastPath(buffer, failLabel);
        1559            7324 :         labels.setStubJump(masm, failLabel, failJump);
        1560                 :
        1561            7324 :         if (pic.stubsGenerated == MAX_PIC_STUBS)
        1562               0 :             disable("max stubs reached");
        1563                 :
        1564            7324 :         return Lookup_Cacheable;
        1565                 :     }
        1566                 :
        1567           22938 :     LookupStatus updateForName()
        1568                 :     {
        1569                 :         // |getprop.obj| is filled by bind()
        1570           22938 :         LookupStatus status = getprop.bind();
        1571           22938 :         if (status != Lookup_Cacheable)
        1572              82 :             return status;
        1573                 :
        1574           22856 :         return update(getprop.obj);
        1575                 :     }
        1576                 :
        1577             255 :     LookupStatus updateForXName()
        1578                 :     {
        1579                 :         // |obj| and |getprop.obj| are NULL, but should be the given scopeChain.
        1580             255 :         getprop.obj = scopeChain;
        1581             255 :         LookupStatus status = getprop.lookup();
        1582             255 :         if (status != Lookup_Cacheable)
        1583               0 :             return status;
        1584                 :
        1585             255 :         return update(getprop.obj);
        1586                 :     }
        1587                 :
        1588           23111 :     LookupStatus update(JSObject *obj)
        1589                 :     {
        1590           23111 :         if (obj != getprop.holder)
        1591              44 :             return disable("property is on proto of a scope object");
        1592                 :
        1593           23067 :         if (obj->isCall())
        1594            7795 :             return generateCallStub(obj);
        1595                 :
        1596           15272 :         LookupStatus status = getprop.testForGet();
        1597           15272 :         if (status != Lookup_Cacheable)
        1598             303 :             return status;
        1599                 :
        1600           14969 :         if (obj->isGlobal())
        1601           14762 :             return generateGlobalStub(obj);
        1602                 :
        1603             207 :         return disable("scope object not handled yet");
        1604                 :     }
        1605                 :
        1606           23193 :     bool retrieve(Value *vp, PICInfo::Kind kind)
        1607                 :     {
        1608           23193 :         JSObject *obj = getprop.obj;
        1609           23193 :         JSObject *holder = getprop.holder;
        1610           23193 :         const JSProperty *prop = getprop.prop;
        1611                 :
        1612           23193 :         if (!prop) {
        1613                 :             /* Kludge to allow (typeof foo == "undefined") tests. */
        1614              78 :             if (kind == ic::PICInfo::NAME) {
        1615              78 :                 JSOp op2 = JSOp(f.pc()[JSOP_NAME_LENGTH]);
        1616              78 :                 if (op2 == JSOP_TYPEOF) {
        1617               2 :                     vp->setUndefined();
        1618               2 :                     return true;
        1619                 :                 }
        1620                 :             }
        1621              76 :             ReportAtomNotDefined(cx, name);
        1622              76 :             return false;
        1623                 :         }
        1624                 :
        1625                 :         // If the property was found, but we decided not to cache it, then
        1626                 :         // take a slow path and do a full property fetch.
        1627           23115 :         if (!getprop.shape) {
        1628               4 :             if (!obj->getProperty(cx, name, vp))
        1629               0 :                 return false;
        1630               4 :             return true;
        1631                 :         }
        1632                 :
        1633           23111 :         const Shape *shape = getprop.shape;
        1634           23111 :         JSObject *normalized = obj;
        1635           23111 :         if (obj->isWith() && !shape->hasDefaultGetter())
        1636               8 :             normalized = &obj->asWith().object();
        1637           23111 :         NATIVE_GET(cx, normalized, holder, shape, 0, vp, return false);
        1638           23102 :         return true;
        1639                 :     }
        1640                 : };
        1641                 :
        1642                 : class BindNameCompiler : public PICStubCompiler
        1643                 : {
        1644                 :     JSObject *scopeChain;
        1645                 :     PropertyName *name;
        1646                 :
        1647                 :   public:
        1648            2404 :     BindNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
        1649                 :                      PropertyName *name, VoidStubPIC stub)
        1650                 :       : PICStubCompiler("bind", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
        1651            2404 :         scopeChain(scopeChain), name(name)
        1652            2404 :     { }
        1653                 :
        1654                 :     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
        1655                 :     {
        1656                 :         BindNameLabels &labels = pic.bindNameLabels();
        1657                 :
        1658                 :         /* Link the inline jump back to the slow path. */
        1659                 :         JSC::CodeLocationJump inlineJump = labels.getInlineJump(pic.getFastShapeGuard());
        1660                 :         repatcher.relink(inlineJump, pic.slowPathStart);
        1661                 :
        1662                 :         /* Link the slow path to call the IC entry point. */
        1663                 :         FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, ic::BindName));
        1664                 :         repatcher.relink(pic.slowPathCall, target);
        1665                 :     }
        1666                 :
        1667             565 :     void patchPreviousToHere(CodeLocationLabel cs)
        1668                 :     {
        1669             565 :         BindNameLabels &labels = pic.bindNameLabels();
        1670            1130 :         Repatcher repatcher(pic.lastCodeBlock(f.chunk()));
        1671             565 :         JSC::CodeLocationJump jump;
        1672                 :
        1673                 :         /* Patch either the inline fast path or a generated stub. */
        1674             565 :         if (pic.stubsGenerated)
        1675               8 :             jump = labels.getStubJump(pic.lastPathStart());
        1676                 :         else
        1677             557 :             jump = labels.getInlineJump(pic.getFastShapeGuard());
        1678             565 :         repatcher.relink(jump, cs);
        1679             565 :     }
        1680                 :
        1681             732 :     LookupStatus generateStub(JSObject *obj)
        1682                 :     {
        1683            1464 :         Assembler masm;
        1684            1464 :         Vector<Jump, 8> fails(cx);
        1685                 :
        1686             732 :         BindNameLabels &labels = pic.bindNameLabels();
        1687                 :
        1688             732 :         if (!IsCacheableNonGlobalScope(scopeChain))
        1689               9 :             return disable("non-cacheable obj at start of scope chain");
        1690                 :
        1691                 :         /* Guard on the shape of the scope chain. */
        1692             723 :         masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), pic.objReg);
        1693             723 :         masm.loadShape(pic.objReg, pic.shapeReg);
        1694                 :         Jump firstShape = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
        1695             723 :                                          ImmPtr(scopeChain->lastProperty()));
        1696                 :
        1697             723 :         if (scopeChain != obj) {
        1698                 :             /* Walk up the scope chain. */
        1699             224 :             JSObject *tobj = &scopeChain->asScope().enclosingScope();
        1700             224 :             Address parent(pic.objReg, ScopeObject::offsetOfEnclosingScope());
        1701             494 :             while (tobj) {
        1702             270 :                 if (!IsCacheableNonGlobalScope(tobj))
        1703             158 :                     return disable("non-cacheable obj in scope chain");
        1704             112 :                 masm.loadPayload(parent, pic.objReg);
        1705             112 :                 masm.loadShape(pic.objReg, pic.shapeReg);
        1706                 :                 Jump shapeTest = masm.branchPtr(Assembler::NotEqual, pic.shapeReg,
        1707             112 :                                                 ImmPtr(tobj->lastProperty()));
        1708             112 :                 if (!fails.append(shapeTest))
        1709               0 :                     return error();
        1710             112 :                 if (tobj == obj)
        1711              66 :                     break;
        1712              46 :                 tobj = &tobj->asScope().enclosingScope();
        1713                 :             }
        1714              66 :             if (tobj != obj)
        1715               0 :                 return disable("indirect hit");
        1716                 :         }
        1717                 :
        1718             565 :         Jump done = masm.jump();
        1719                 :
        1720                 :         // All failures flow to here, so there is a common point to patch.
        1721             645 :         for (Jump *pj = fails.begin(); pj != fails.end(); ++pj)
        1722              80 :             pj->linkTo(masm.label(), &masm);
        1723             565 :         firstShape.linkTo(masm.label(), &masm);
        1724             565 :         Label failLabel = masm.label();
        1725             565 :         Jump failJump = masm.jump();
        1726                 :
        1727             565 :         pic.updatePCCounters(f, masm);
        1728                 :
        1729            1130 :         PICLinker buffer(masm, pic);
        1730             565 :         if (!buffer.init(cx))
        1731               0 :             return error();
        1732                 :
        1733            1130 :         if (!buffer.verifyRange(pic.lastCodeBlock(f.chunk())) ||
        1734             565 :             !buffer.verifyRange(f.chunk())) {
        1735               0 :             return disable("code memory is out of range");
        1736                 :         }
        1737                 :
        1738             565 :         buffer.link(failJump, pic.slowPathStart);
        1739             565 :         buffer.link(done, pic.fastPathRejoin);
        1740             565 :         CodeLocationLabel cs = buffer.finalize(f);
        1741             565 :         JaegerSpew(JSpew_PICs, "generated %s stub at %p\n", type, cs.executableAddress());
        1742                 :
        1743             565 :         patchPreviousToHere(cs);
        1744                 :
        1745             565 :         pic.stubsGenerated++;
        1746             565 :         pic.updateLastPath(buffer, failLabel);
        1747             565 :         labels.setStubJump(masm, failLabel, failJump);
        1748                 :
        1749             565 :         if (pic.stubsGenerated == MAX_PIC_STUBS)
        1750               0 :             disable("max stubs reached");
        1751                 :
        1752             565 :         return Lookup_Cacheable;
        1753                 :     }
        1754                 :
        1755            2404 :     JSObject *update()
        1756                 :     {
        1757            2404 :         RecompilationMonitor monitor(cx);
        1758                 :
        1759            2404 :         JSObject *obj = FindIdentifierBase(cx, scopeChain, name);
        1760            2404 :         if (!obj || monitor.recompiled())
        1761               2 :             return obj;
        1762                 :
        1763            2402 :         if (!pic.hit) {
        1764            1670 :             spew("first hit", "nop");
        1765            1670 :             pic.hit = true;
        1766            1670 :             return obj;
        1767                 :         }
        1768                 :
        1769             732 :         LookupStatus status = generateStub(obj);
        1770             732 :         if (status == Lookup_Error)
        1771               0 :             return NULL;
        1772                 :
        1773             732 :         return obj;
        1774                 :     }
        1775                 : };
        1776                 :
        1777                 : static void JS_FASTCALL
        1778          187080 : DisabledGetPropIC(VMFrame &f, ic::PICInfo *pic)
        1779                 : {
        1780          187080 :     stubs::GetProp(f, pic->name);
        1781          187080 : }
        1782                 :
        1783                 : static void JS_FASTCALL
        1784               0 : DisabledGetPropNoCacheIC(VMFrame &f, ic::PICInfo *pic)
        1785                 : {
        1786               0 :     stubs::GetPropNoCache(f, pic->name);
        1787               0 : }
        1788                 :
        1789                 : static inline void
        1790           68278 : GetPropMaybeCached(VMFrame &f, ic::PICInfo *pic, bool cached)
        1791                 : {
        1792           68278 :     VoidStubPIC stub = cached ? DisabledGetPropIC : DisabledGetPropNoCacheIC;
        1793                 :
        1794           68278 :     JSScript *script = f.fp()->script();
        1795                 :
        1796           68278 :     PropertyName *name = pic->name;
        1797           68278 :     if (name == f.cx->runtime->atomState.lengthAtom) {
        1798            6656 :         if (f.regs.sp[-1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
        1799              20 :             f.regs.sp[-1].setInt32(f.regs.fp()->numActualArgs());
        1800              20 :             return;
        1801                 :         }
        1802            6636 :         if (!f.regs.sp[-1].isPrimitive()) {
        1803            6503 :             JSObject *obj = &f.regs.sp[-1].toObject();
        1804            6503 :             if (obj->isArray() || obj->isString()) {
        1805            5268 :                 GetPropCompiler cc(f, script, obj, *pic, NULL, stub);
        1806            5268 :                 if (obj->isArray()) {
        1807            5199 :                     LookupStatus status = cc.generateArrayLengthStub();
        1808            5199 :                     if (status == Lookup_Error)
        1809               0 :                         THROW();
        1810            5199 :                     f.regs.sp[-1].setNumber(obj->getArrayLength());
        1811                 :                 } else {
        1812              69 :                     LookupStatus status = cc.generateStringObjLengthStub();
        1813              69 :                     if (status == Lookup_Error)
        1814               0 :                         THROW();
        1815              69 :                     JSString *str = obj->asString().unbox();
        1816              69 :                     f.regs.sp[-1].setInt32(str->length());
        1817                 :                 }
        1818            5268 :                 return;
        1819                 :             }
        1820                 :         }
        1821                 :     }
        1822                 :
        1823           62990 :     if (f.regs.sp[-1].isString()) {
        1824            1000 :         GetPropCompiler cc(f, script, NULL, *pic, name, stub);
        1825            1000 :         if (name == f.cx->runtime->atomState.lengthAtom) {
        1826             121 :             LookupStatus status = cc.generateStringLengthStub();
        1827             121 :             if (status == Lookup_Error)
        1828               0 :                 THROW();
        1829             121 :             JSString *str = f.regs.sp[-1].toString();
        1830             121 :             f.regs.sp[-1].setInt32(str->length());
        1831                 :         } else {
        1832             879 :             LookupStatus status = cc.generateStringPropertyStub();
        1833             879 :             if (status == Lookup_Error)
        1834               0 :                 THROW();
        1835             879 :             JSObject *obj = ValueToObject(f.cx, f.regs.sp[-1]);
        1836             879 :             if (!obj)
        1837               0 :                 THROW();
        1838             879 :             if (!obj->getProperty(f.cx, name, &f.regs.sp[-1]))
        1839               0 :                 THROW();
        1840                 :         }
        1841            1000 :         return;
        1842                 :     }
        1843                 :
        1844           61990 :     RecompilationMonitor monitor(f.cx);
        1845                 :
        1846           61990 :     JSObject *obj = ValueToObject(f.cx, f.regs.sp[-1]);
        1847           61990 :     if (!obj)
        1848              18 :         THROW();
        1849                 :
        1850           61972 :     if (!monitor.recompiled() && pic->shouldUpdate(f.cx)) {
        1851           25918 :         GetPropCompiler cc(f, script, obj, *pic, name, stub);
        1852           25918 :         if (!cc.update())
        1853               0 :             THROW();
        1854                 :     }
        1855                 :
        1856                 :     Value v;
        1857           61972 :     if (cached) {
        1858           60697 :         if (!GetPropertyOperation(f.cx, f.pc(), f.regs.sp[-1], &v))
        1859              23 :             THROW();
        1860                 :     } else {
        1861            1275 :         if (!obj->getProperty(f.cx, name, &v))
        1862               0 :             THROW();
        1863                 :     }
        1864                 :
        1865           61949 :     f.regs.sp[-1] = v;
        1866                 : }
        1867                 :
        1868                 : void JS_FASTCALL
        1869           67003 : ic::GetProp(VMFrame &f, ic::PICInfo *pic)
        1870                 : {
        1871           67003 :     GetPropMaybeCached(f, pic, /* cache = */ true);
        1872           67003 : }
        1873                 :
        1874                 : void JS_FASTCALL
        1875            1275 : ic::GetPropNoCache(VMFrame &f, ic::PICInfo *pic)
        1876                 : {
        1877            1275 :     GetPropMaybeCached(f, pic, /* cache = */ false);
        1878            1275 : }
        1879                 :
        1880                 : template <JSBool strict>
        1881                 : static void JS_FASTCALL
        1882           15267 : DisabledSetPropIC(VMFrame &f, ic::PICInfo *pic)
        1883                 : {
        1884           15267 :     stubs::SetName<strict>(f, pic->name);
        1885           15267 : }
        1886                 :
        1887                 : void JS_FASTCALL
        1888           13180 : ic::SetProp(VMFrame &f, ic::PICInfo *pic)
        1889                 : {
        1890           13180 :     JSScript *script = f.fp()->script();
        1891           13180 :     JS_ASSERT(pic->isSet());
        1892                 :
        1893           13180 :     VoidStubPIC stub = STRICT_VARIANT(DisabledSetPropIC);
        1894                 :
        1895                 :     // Save this in case the compiler triggers a recompilation of this script.
        1896           13180 :     PropertyName *name = pic->name;
        1897           13180 :     VoidStubName nstub = STRICT_VARIANT(stubs::SetName);
        1898                 :
        1899           13180 :     RecompilationMonitor monitor(f.cx);
        1900                 :
        1901           13180 :     JSObject *obj = ValueToObject(f.cx, f.regs.sp[-2]);
        1902           13180 :     if (!obj)
        1903               0 :         THROW();
        1904                 :
        1905                 :     // Note, we can't use SetName for PROPINC PICs because the property
        1906                 :     // cache can't handle a GET and SET from the same scripted PC.
        1907           13180 :     if (!monitor.recompiled() && pic->shouldUpdate(f.cx)) {
        1908            4900 :         SetPropCompiler cc(f, script, obj, *pic, name, stub);
        1909            4900 :         LookupStatus status = cc.update();
        1910            4900 :         if (status == Lookup_Error)
        1911               0 :             THROW();
        1912                 :     }
        1913                 :
        1914           13180 :     nstub(f, name);
        1915                 : }
        1916                 :
        1917                 : static void JS_FASTCALL
        1918            6858 : DisabledNameIC(VMFrame &f, ic::PICInfo *pic)
        1919                 : {
        1920            6858 :     stubs::Name(f);
        1921            6858 : }
        1922                 :
        1923                 : static void JS_FASTCALL
        1924               0 : DisabledXNameIC(VMFrame &f, ic::PICInfo *pic)
        1925                 : {
        1926               0 :     stubs::GetProp(f, pic->name);
        1927               0 : }
        1928                 :
        1929                 : void JS_FASTCALL
        1930             255 : ic::XName(VMFrame &f, ic::PICInfo *pic)
        1931                 : {
        1932             255 :     JSScript *script = f.fp()->script();
        1933                 :
        1934                 :     /* GETXPROP is guaranteed to have an object. */
        1935             255 :     JSObject *obj = &f.regs.sp[-1].toObject();
        1936                 :
        1937             255 :     ScopeNameCompiler cc(f, script, obj, *pic, pic->name, DisabledXNameIC);
        1938                 :
        1939             255 :     LookupStatus status = cc.updateForXName();
        1940             255 :     if (status == Lookup_Error)
        1941               0 :         THROW();
        1942                 :
        1943                 :     Value rval;
        1944             255 :     if (!cc.retrieve(&rval, PICInfo::XNAME))
        1945               0 :         THROW();
        1946             255 :     f.regs.sp[-1] = rval;
        1947                 : }
        1948                 :
        1949                 : void JS_FASTCALL
        1950           22938 : ic::Name(VMFrame &f, ic::PICInfo *pic)
        1951                 : {
        1952           22938 :     JSScript *script = f.fp()->script();
        1953                 :
        1954           22938 :     ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->name, DisabledNameIC);
        1955                 :
        1956           22938 :     LookupStatus status = cc.updateForName();
        1957           22938 :     if (status == Lookup_Error)
        1958               0 :         THROW();
        1959                 :
        1960                 :     Value rval;
        1961           22938 :     if (!cc.retrieve(&rval, PICInfo::NAME))
        1962              85 :         THROW();
        1963           22853 :     f.regs.sp[0] = rval;
        1964                 : }
        1965                 :
        1966                 : static void JS_FASTCALL
        1967            1180 : DisabledBindNameIC(VMFrame &f, ic::PICInfo *pic)
        1968                 : {
        1969            1180 :     stubs::BindName(f, pic->name);
        1970            1180 : }
        1971                 :
        1972                 : void JS_FASTCALL
        1973            2404 : ic::BindName(VMFrame &f, ic::PICInfo *pic)
        1974                 : {
        1975            2404 :     JSScript *script = f.fp()->script();
        1976                 :
        1977            2404 :     VoidStubPIC stub = DisabledBindNameIC;
        1978            2404 :     BindNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->name, stub);
        1979                 :
        1980            2404 :     JSObject *obj = cc.update();
        1981            2404 :     if (!obj)
        1982               0 :         THROW();
        1983                 :
        1984            2404 :     f.regs.sp[0].setObject(*obj);
        1985                 : }
        1986                 :
        1987                 : void
        1988           68728 : BaseIC::spew(JSContext *cx, const char *event, const char *message)
        1989                 : {
        1990                 : #ifdef JS_METHODJIT_SPEW
        1991                 :     JaegerSpew(JSpew_PICs, "%s %s: %s (%s: %d)\n",
        1992           68728 :                js_CodeName[op], event, message, cx->fp()->script()->filename, CurrentLine(cx));
        1993                 : #endif
        1994           68728 : }
        1995                 :
        1996                 : /* Total length of scripts preceding a frame. */
        1997               0 : inline uint32_t frameCountersOffset(VMFrame &f)
        1998                 : {
        1999               0 :     JSContext *cx = f.cx;
        2000                 :
        2001               0 :     uint32_t offset = 0;
        2002               0 :     if (cx->regs().inlined()) {
        2003               0 :         offset += cx->fp()->script()->length;
        2004               0 :         uint32_t index = cx->regs().inlined()->inlineIndex;
        2005               0 :         InlineFrame *frames = f.chunk()->inlineFrames();
        2006               0 :         for (unsigned i = 0; i < index; i++)
        2007               0 :             offset += frames[i].fun->script()->length;
        2008                 :     }
        2009                 :
        2010                 :     jsbytecode *pc;
        2011               0 :     JSScript *script = cx->stack.currentScript(&pc);
        2012               0 :     offset += pc - script->code;
        2013                 :
        2014               0 :     return offset;
        2015                 : }
        2016                 :
        2017                 : LookupStatus
        2018           17296 : BaseIC::disable(VMFrame &f, const char *reason, void *stub)
        2019                 : {
        2020           17296 :     if (f.chunk()->pcLengths) {
        2021               0 :         uint32_t offset = frameCountersOffset(f);
        2022               0 :         f.chunk()->pcLengths[offset].picsLength = 0;
        2023                 :     }
        2024                 :
        2025           17296 :     spew(f.cx, "disabled", reason);
        2026           34592 :     Repatcher repatcher(f.chunk());
        2027           17296 :     repatcher.relink(slowPathCall, FunctionPtr(stub));
        2028           17296 :     return Lookup_Uncacheable;
        2029                 : }
        2030                 :
        2031                 : void
        2032           47565 : BaseIC::updatePCCounters(VMFrame &f, Assembler &masm)
        2033                 : {
        2034           47565 :     if (f.chunk()->pcLengths) {
        2035               0 :         uint32_t offset = frameCountersOffset(f);
        2036               0 :         f.chunk()->pcLengths[offset].picsLength += masm.size();
        2037                 :     }
        2038           47565 : }
        2039                 :
        2040                 : bool
        2041           75152 : BaseIC::shouldUpdate(JSContext *cx)
        2042                 : {
        2043           75152 :     if (!hit) {
        2044           44334 :         hit = true;
        2045           44334 :         spew(cx, "ignored", "first hit");
        2046           44334 :         return false;
        2047                 :     }
        2048           30818 :     JS_ASSERT(stubsGenerated < MAX_PIC_STUBS);
        2049           30818 :     return true;
        2050                 : }
        2051                 :
        2052                 : static void JS_FASTCALL
        2053          820639 : DisabledGetElem(VMFrame &f, ic::GetElementIC *ic)
        2054                 : {
        2055          820639 :     stubs::GetElem(f);
        2056          820639 : }
        2057                 :
        2058                 : bool
        2059           13414 : GetElementIC::shouldUpdate(JSContext *cx)
        2060                 : {
        2061           13414 :     if (!hit) {
        2062            4826 :         hit = true;
        2063            4826 :         spew(cx, "ignored", "first hit");
        2064            4826 :         return false;
        2065                 :     }
        2066            8588 :     JS_ASSERT(stubsGenerated < MAX_GETELEM_IC_STUBS);
        2067            8588 :     return true;
        2068                 : }
        2069                 :
        2070                 : LookupStatus
        2071            2918 : GetElementIC::disable(VMFrame &f, const char *reason)
        2072                 : {
        2073            2918 :     slowCallPatched = true;
        2074            2918 :     void *stub = JS_FUNC_TO_DATA_PTR(void *, DisabledGetElem);
        2075            2918 :     BaseIC::disable(f, reason, stub);
        2076            2918 :     return Lookup_Uncacheable;
        2077                 : }
        2078                 :
        2079                 : LookupStatus
        2080               0 : GetElementIC::error(JSContext *cx)
        2081                 : {
        2082               0 :     return Lookup_Error;
        2083                 : }
        2084                 :
        2085                 : void
        2086               0 : GetElementIC::purge(Repatcher &repatcher)
        2087                 : {
        2088                 :     // Repatch the inline jumps.
        2089               0 :     if (inlineTypeGuardPatched)
        2090               0 :         repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), slowPathStart);
        2091               0 :     if (inlineShapeGuardPatched)
        2092               0 :         repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), slowPathStart);
        2093                 :
        2094               0 :     if (slowCallPatched) {
        2095                 :         repatcher.relink(slowPathCall,
        2096               0 :                          FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::GetElement)));
        2097                 :     }
        2098                 :
        2099               0 :     reset();
        2100               0 : }
        2101                 :
        2102                 : LookupStatus
        2103            6035 : GetElementIC::attachGetProp(VMFrame &f, JSObject *obj, const Value &v, PropertyName *name,
        2104                 :                             Value *vp)
        2105                 : {
        2106            6035 :     JS_ASSERT(v.isString());
        2107            6035 :     JSContext *cx = f.cx;
        2108                 :
        2109            6035 :     GetPropHelper<GetElementIC> getprop(cx, obj, name, *this, f);
        2110            6035 :     LookupStatus status = getprop.lookupAndTest();
        2111            6035 :     if (status != Lookup_Cacheable)
        2112              60 :         return status;
        2113                 :
        2114                 :     // With TI enabled, string property stubs can only be added to an opcode if
        2115                 :     // the value read will go through a type barrier afterwards. TI only
        2116                 :     // accounts for integer-valued properties accessed by GETELEM/CALLELEM.
        2117            5975 :     if (cx->typeInferenceEnabled() && !forcedTypeBarrier)
        2118              31 :         return disable(f, "string element access may not have type barrier");
        2119                 :
        2120           11888 :     Assembler masm;
        2121                 :
        2122                 :     // Guard on the string's type and identity.
        2123            5944 :     MaybeJump atomTypeGuard;
        2124            5944 :     if (hasInlineTypeGuard() && !inlineTypeGuardPatched) {
        2125                 :         // We link all string-key dependent stubs together, and store the
        2126                 :         // first set of guards in the IC, separately, from int-key dependent
        2127                 :         // stubs. As long as we guarantee that the first string-key dependent
        2128                 :         // stub guards on the key type, then all other string-key stubs can
        2129                 :         // omit the guard.
        2130             767 :         JS_ASSERT(!idRemat.isTypeKnown());
        2131             767 :         atomTypeGuard = masm.testString(Assembler::NotEqual, typeReg);
        2132                 :     } else {
        2133                 :         // If there was no inline type guard, then a string type is guaranteed.
        2134                 :         // Otherwise, we are guaranteed the type has already been checked, via
        2135                 :         // the comment above.
        2136            5177 :         JS_ASSERT_IF(!hasInlineTypeGuard(), idRemat.knownType() == JSVAL_TYPE_STRING);
        2137                 :     }
        2138                 :
        2139                 :     // Reify the shape before guards that could flow into shape guarding stubs.
        2140            5944 :     if (!obj->isDenseArray() && !typeRegHasBaseShape) {
        2141            1453 :         masm.loadShape(objReg, typeReg);
        2142            1453 :         typeRegHasBaseShape = true;
        2143                 :     }
        2144                 :
        2145            5944 :     MaybeJump atomIdGuard;
        2146            5944 :     if (!idRemat.isConstant())
        2147            5930 :         atomIdGuard = masm.branchPtr(Assembler::NotEqual, idRemat.dataReg(), ImmPtr(v.toString()));
        2148                 :
        2149                 :     // Guard on the base shape.
        2150            5944 :     Jump shapeGuard = masm.branchPtr(Assembler::NotEqual, typeReg, ImmPtr(obj->lastProperty()));
        2151                 :
        2152           11888 :     Vector<Jump, 8> otherGuards(cx);
        2153                 :
        2154                 :     // Guard on the prototype, if applicable.
        2155            5944 :     MaybeJump protoGuard;
        2156            5944 :     JSObject *holder = getprop.holder;
        2157            5944 :     RegisterID holderReg = objReg;
        2158            5944 :     if (obj != holder) {
        2159              81 :         if (!GeneratePrototypeGuards(cx, otherGuards, masm, obj, holder, objReg, typeReg))
        2160               0 :             return error(cx);
        2161                 :
        2162                 :         // Bake in the holder identity. Careful not to clobber |objReg|, since we can't remat it.
        2163              81 :         holderReg = typeReg;
        2164              81 :         masm.move(ImmPtr(holder), holderReg);
        2165              81 :         typeRegHasBaseShape = false;
        2166                 :
        2167                 :         // Guard on the holder's shape.
        2168              81 :         protoGuard = masm.guardShape(holderReg, holder);
        2169                 :     }
        2170                 :
        2171            5944 :     if (op == JSOP_CALLELEM) {
        2172                 :         // Emit a write of |obj| to the top of the stack, before we lose it.
        2173             135 :         Value *thisVp = &cx->regs().sp[-1];
        2174             135 :         Address thisSlot(JSFrameReg, StackFrame::offsetOfFixed(thisVp - cx->fp()->slots()));
        2175             135 :         masm.storeValueFromComponents(ImmType(JSVAL_TYPE_OBJECT), objReg, thisSlot);
        2176                 :     }
        2177                 :
        2178                 :     // Load the value.
        2179            5944 :     const Shape *shape = getprop.shape;
        2180            5944 :     masm.loadObjProp(holder, holderReg, shape, typeReg, objReg);
        2181                 :
        2182            5944 :     Jump done = masm.jump();
        2183                 :
        2184            5944 :     updatePCCounters(f, masm);
        2185                 :
        2186           11888 :     PICLinker buffer(masm, *this);
        2187            5944 :     if (!buffer.init(cx))
        2188               0 :         return error(cx);
        2189                 :
        2190            5944 :     if (hasLastStringStub && !buffer.verifyRange(lastStringStub))
        2191               0 :         return disable(f, "code memory is out of range");
        2192            5944 :     if (!buffer.verifyRange(f.chunk()))
        2193               0 :         return disable(f, "code memory is out of range");
        2194                 :
        2195                 :     // Patch all guards.
        2196            5944 :     buffer.maybeLink(atomIdGuard, slowPathStart);
        2197            5944 :     buffer.maybeLink(atomTypeGuard, slowPathStart);
        2198            5944 :     buffer.link(shapeGuard, slowPathStart);
        2199            5944 :     buffer.maybeLink(protoGuard, slowPathStart);
        2200            5944 :     for (Jump *pj = otherGuards.begin(); pj != otherGuards.end(); ++pj)
        2201               0 :         buffer.link(*pj, slowPathStart);
        2202            5944 :     buffer.link(done, fastPathRejoin);
        2203                 :
        2204            5944 :     CodeLocationLabel cs = buffer.finalize(f);
        2205                 : #if DEBUG
        2206            5944 :     char *chars = DeflateString(cx, v.toString()->getChars(cx), v.toString()->length());
        2207                 :     JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom %p (\"%s\") shape %p (%s: %d)\n",
        2208                 :                js_CodeName[op], cs.executableAddress(), (void*)name, chars,
        2209            5944 :                (void*)holder->lastProperty(), cx->fp()->script()->filename, CurrentLine(cx));
        2210            5944 :     cx->free_(chars);
        2211                 : #endif
        2212                 :
        2213                 :     // Update the inline guards, if needed.
        2214            5944 :     if (shouldPatchInlineTypeGuard() || shouldPatchUnconditionalShapeGuard()) {
        2215            2872 :         Repatcher repatcher(f.chunk());
        2216                 :
        2217            1436 :         if (shouldPatchInlineTypeGuard()) {
        2218                 :             // A type guard is present in the inline path, and this is the
        2219                 :             // first string stub, so patch it now.
        2220             767 :             JS_ASSERT(!inlineTypeGuardPatched);
        2221             767 :             JS_ASSERT(atomTypeGuard.isSet());
        2222                 :
        2223             767 :             repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), cs);
        2224             767 :             inlineTypeGuardPatched = true;
        2225                 :         }
        2226                 :
        2227            1436 :         if (shouldPatchUnconditionalShapeGuard()) {
        2228                 :             // The shape guard is unconditional, meaning there is no type
        2229                 :             // check. This is the first stub, so it has to be patched. Note
        2230                 :             // that it is wrong to patch the inline shape guard otherwise,
        2231                 :             // because it follows an integer-id guard.
        2232             669 :             JS_ASSERT(!hasInlineTypeGuard());
        2233                 :
        2234             669 :             repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
        2235             669 :             inlineShapeGuardPatched = true;
        2236                 :         }
        2237                 :     }
        2238                 :
        2239                 :     // If there were previous stub guards, patch them now.
        2240            5944 :     if (hasLastStringStub) {
        2241            9016 :         Repatcher repatcher(lastStringStub);
        2242            4508 :         CodeLocationLabel stub(lastStringStub.start());
        2243            4508 :         if (atomGuard)
        2244            4508 :             repatcher.relink(stub.jumpAtOffset(atomGuard), cs);
        2245            4508 :         repatcher.relink(stub.jumpAtOffset(firstShapeGuard), cs);
        2246            4508 :         if (secondShapeGuard)
        2247              57 :             repatcher.relink(stub.jumpAtOffset(secondShapeGuard), cs);
        2248                 :     }
        2249                 :
        2250                 :     // Update state.
        2251            5944 :     hasLastStringStub = true;
        2252            5944 :     lastStringStub = JITCode(cs.executableAddress(), buffer.size());
        2253            5944 :     if (atomIdGuard.isSet()) {
        2254            5930 :         atomGuard = buffer.locationOf(atomIdGuard.get()) - cs;
        2255            5930 :         JS_ASSERT(atomGuard == buffer.locationOf(atomIdGuard.get()) - cs);
        2256            5930 :         JS_ASSERT(atomGuard);
        2257                 :     } else {
        2258              14 :         atomGuard = 0;
        2259                 :     }
        2260            5944 :     if (protoGuard.isSet()) {
        2261              81 :         secondShapeGuard = buffer.locationOf(protoGuard.get()) - cs;
        2262              81 :         JS_ASSERT(secondShapeGuard == buffer.locationOf(protoGuard.get()) - cs);
        2263              81 :         JS_ASSERT(secondShapeGuard);
        2264                 :     } else {
        2265            5863 :         secondShapeGuard = 0;
        2266                 :     }
        2267            5944 :     firstShapeGuard = buffer.locationOf(shapeGuard) - cs;
        2268            5944 :     JS_ASSERT(firstShapeGuard == buffer.locationOf(shapeGuard) - cs);
        2269            5944 :     JS_ASSERT(firstShapeGuard);
        2270                 :
        2271            5944 :     stubsGenerated++;
        2272                 :
        2273            5944 :     if (stubsGenerated == MAX_GETELEM_IC_STUBS)
        2274              38 :         disable(f, "max stubs reached");
        2275                 :
        2276                 :     // Finally, fetch the value to avoid redoing the property lookup.
        2277            5944 :     *vp = holder->getSlot(shape->slot());
        2278                 :
        2279            5944 :     return Lookup_Cacheable;
        2280                 : }
        2281                 :
        2282                 : #if defined JS_METHODJIT_TYPED_ARRAY
        2283                 : LookupStatus
        2284             816 : GetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
        2285                 : {
        2286             816 :     JSContext *cx = f.cx;
        2287                 :
        2288             816 :     if (!v.isInt32())
        2289               0 :         return disable(f, "typed array with string key");
        2290                 :
        2291             816 :     if (op == JSOP_CALLELEM)
        2292               0 :         return disable(f, "typed array with call");
        2293                 :
        2294                 :     // The fast-path guarantees that after the dense shape guard, the type is
        2295                 :     // known to be int32, either via type inference or the inline type check.
        2296             816 :     JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32);
        2297                 :
        2298            1632 :     Assembler masm;
        2299                 :
        2300                 :     // Guard on this typed array's shape/class.
        2301             816 :     Jump shapeGuard = masm.guardShape(objReg, obj);
        2302                 :
        2303                 :     // Bounds check.
        2304             816 :     Jump outOfBounds;
        2305             816 :     Address typedArrayLength = masm.payloadOf(Address(objReg, TypedArray::lengthOffset()));
        2306             816 :     if (idRemat.isConstant()) {
        2307             643 :         JS_ASSERT(idRemat.value().toInt32() == v.toInt32());
        2308             643 :         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(v.toInt32()));
        2309                 :     } else {
        2310             173 :         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, idRemat.dataReg());
        2311                 :     }
        2312                 :
        2313                 :     // Load the array's packed data vector.
        2314             816 :     masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
        2315                 :
        2316             816 :     Int32Key key = idRemat.isConstant()
        2317             643 :                  ? Int32Key::FromConstant(v.toInt32())
        2318            1459 :                  : Int32Key::FromRegister(idRemat.dataReg());
        2319                 :
        2320             816 :     JSObject *tarray = js::TypedArray::getTypedArray(obj);
        2321             816 :     if (!masm.supportsFloatingPoint() &&
        2322               0 :         (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
        2323               0 :          TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64 ||
        2324               0 :          TypedArray::getType(tarray) == js::TypedArray::TYPE_UINT32))
        2325                 :     {
        2326               0 :         return disable(f, "fpu not supported");
        2327                 :     }
        2328                 :
        2329             816 :     MaybeRegisterID tempReg;
        2330             816 :     masm.loadFromTypedArray(TypedArray::getType(tarray), objReg, key, typeReg, objReg, tempReg);
        2331                 :
        2332             816 :     Jump done = masm.jump();
        2333                 :
        2334             816 :     updatePCCounters(f, masm);
        2335                 :
        2336            1632 :     PICLinker buffer(masm, *this);
        2337             816 :     if (!buffer.init(cx))
        2338               0 :         return error(cx);
        2339                 :
        2340             816 :     if (!buffer.verifyRange(f.chunk()))
        2341               0 :         return disable(f, "code memory is out of range");
        2342                 :
        2343             816 :     buffer.link(shapeGuard, slowPathStart);
        2344             816 :     buffer.link(outOfBounds, slowPathStart);
        2345             816 :     buffer.link(done, fastPathRejoin);
        2346                 :
        2347             816 :     CodeLocationLabel cs = buffer.finalizeCodeAddendum();
        2348             816 :     JaegerSpew(JSpew_PICs, "generated getelem typed array stub at %p\n", cs.executableAddress());
        2349                 :
        2350                 :     // If we can generate a typed array stub, the shape guard is conditional.
        2351                 :     // Also, we only support one typed array.
        2352             816 :     JS_ASSERT(!shouldPatchUnconditionalShapeGuard());
        2353             816 :     JS_ASSERT(!inlineShapeGuardPatched);
        2354                 :
        2355            1632 :     Repatcher repatcher(f.chunk());
        2356             816 :     repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
        2357             816 :     inlineShapeGuardPatched = true;
        2358                 :
        2359             816 :     stubsGenerated++;
        2360                 :
        2361                 :     // In the future, it might make sense to attach multiple typed array stubs.
        2362                 :     // For simplicitly, they are currently monomorphic.
        2363             816 :     if (stubsGenerated == MAX_GETELEM_IC_STUBS)
        2364               0 :         disable(f, "max stubs reached");
        2365                 :
        2366             816 :     disable(f, "generated typed array stub");
        2367                 :
        2368                 :     // Fetch the value as expected of Lookup_Cacheable for GetElement.
        2369             816 :     if (!obj->getGeneric(cx, id, vp))
        2370               0 :         return Lookup_Error;
        2371                 :
        2372             816 :     return Lookup_Cacheable;
        2373                 : }
        2374                 : #endif /* JS_METHODJIT_TYPED_ARRAY */
        2375                 :
        2376                 : LookupStatus
        2377            8588 : GetElementIC::update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
        2378                 : {
        2379                 :     /*
        2380                 :      * Only treat this as a GETPROP for non-numeric string identifiers. The
        2381                 :      * GETPROP IC assumes the id has already gone through filtering for string
        2382                 :      * indexes in the emitter, i.e. js_GetProtoIfDenseArray is only valid to
        2383                 :      * use when looking up non-integer identifiers.
        2384                 :      */
        2385                 :     uint32_t dummy;
        2386            8588 :     if (v.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy))
        2387            6035 :         return attachGetProp(f, obj, v, JSID_TO_ATOM(id)->asPropertyName(), vp);
        2388                 :
        2389                 : #if defined JS_METHODJIT_TYPED_ARRAY
        2390                 :     /*
        2391                 :      * Typed array ICs can make stub calls, and need to know which registers
        2392                 :      * are in use and need to be restored after the call. If type inference is
        2393                 :      * enabled then we don't necessarily know the full set of such registers
        2394                 :      * when generating the IC (loop-carried registers may be allocated later),
        2395                 :      * and additionally the push/pop instructions used to save/restore in the
        2396                 :      * IC are not compatible with carrying entries in floating point registers.
        2397                 :      * Since we can use type information to generate inline paths for typed
        2398                 :      * arrays, just don't generate these ICs with inference enabled.
        2399                 :      */
        2400            2553 :     if (!f.cx->typeInferenceEnabled() && js_IsTypedArray(obj))
        2401             816 :         return attachTypedArray(f, obj, v, id, vp);
        2402                 : #endif
        2403                 :
        2404            1737 :     return disable(f, "unhandled object and key type");
        2405                 : }
        2406                 :
        2407                 : void JS_FASTCALL
        2408           13650 : ic::GetElement(VMFrame &f, ic::GetElementIC *ic)
        2409                 : {
        2410           13650 :     JSContext *cx = f.cx;
        2411                 :
        2412                 :     // Right now, we don't optimize for strings or lazy arguments.
        2413           13650 :     if (!f.regs.sp[-2].isObject()) {
        2414             220 :         ic->disable(f, "non-object");
        2415             220 :         stubs::GetElem(f);
        2416             220 :         return;
        2417                 :     }
        2418                 :
        2419           13430 :     Value idval = f.regs.sp[-1];
        2420                 :
        2421           13430 :     RecompilationMonitor monitor(cx);
        2422                 :
        2423           13430 :     JSObject *obj = ValueToObject(cx, f.regs.sp[-2]);
        2424           13430 :     if (!obj)
        2425               0 :         THROW();
        2426                 :
        2427                 : #if JS_HAS_XML_SUPPORT
        2428                 :     // Some XML properties behave differently when accessed in a call vs. normal
        2429                 :     // context, so we fall back to stubs::GetElem.
        2430           13430 :     if (obj->isXML()) {
        2431              16 :         ic->disable(f, "XML object");
        2432              16 :         stubs::GetElem(f);
        2433              16 :         return;
        2434                 :     }
        2435                 : #endif
        2436                 :
        2437                 :     jsid id;
        2438           13414 :     if (idval.isInt32() && INT_FITS_IN_JSID(idval.toInt32())) {
        2439            4887 :         id = INT_TO_JSID(idval.toInt32());
        2440                 :     } else {
        2441            8527 :         if (!js_InternNonIntElementId(cx, obj, idval, &id))
        2442               0 :             THROW();
        2443                 :     }
        2444                 :
        2445           13414 :     if (!monitor.recompiled() && ic->shouldUpdate(cx)) {
        2446                 : #ifdef DEBUG
        2447            8588 :         f.regs.sp[-2] = MagicValue(JS_GENERIC_MAGIC);
        2448                 : #endif
        2449            8588 :         LookupStatus status = ic->update(f, obj, idval, id, &f.regs.sp[-2]);
        2450            8588 :         if (status != Lookup_Uncacheable) {
        2451            6760 :             if (status == Lookup_Error)
        2452               0 :                 THROW();
        2453                 :
        2454                 :             // If the result can be cached, the value was already retrieved.
        2455            6760 :             JS_ASSERT(!f.regs.sp[-2].isMagic());
        2456            6760 :             return;
        2457                 :         }
        2458                 :     }
        2459                 :
        2460            6654 :     if (!obj->getGeneric(cx, id, &f.regs.sp[-2]))
        2461               0 :         THROW();
        2462                 :
        2463                 : #if JS_HAS_NO_SUCH_METHOD
        2464            6654 :     if (*f.pc() == JSOP_CALLELEM && JS_UNLIKELY(f.regs.sp[-2].isPrimitive())) {
        2465              13 :         if (!OnUnknownMethod(cx, obj, idval, &f.regs.sp[-2]))
        2466               0 :             THROW();
        2467                 :     }
        2468                 : #endif
        2469                 : }
        2470                 :
        2471                 : #define APPLY_STRICTNESS(f, s)                          \
        2472                 :     (FunctionTemplateConditional(s, f<true>, f<false>))
        2473                 :
        2474                 : LookupStatus
        2475            1902 : SetElementIC::disable(VMFrame &f, const char *reason)
        2476                 : {
        2477            1902 :     slowCallPatched = true;
        2478            1902 :     VoidStub stub = APPLY_STRICTNESS(stubs::SetElem, strictMode);
        2479            1902 :     BaseIC::disable(f, reason, JS_FUNC_TO_DATA_PTR(void *, stub));
        2480            1902 :     return Lookup_Uncacheable;
        2481                 : }
        2482                 :
        2483                 : LookupStatus
        2484               0 : SetElementIC::error(JSContext *cx)
        2485                 : {
        2486               0 :     return Lookup_Error;
        2487                 : }
        2488                 :
        2489                 : void
        2490               0 : SetElementIC::purge(Repatcher &repatcher)
        2491                 : {
        2492                 :     // Repatch the inline jumps.
        2493               0 :     if (inlineShapeGuardPatched)
        2494               0 :         repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), slowPathStart);
        2495               0 :     if (inlineHoleGuardPatched)
        2496               0 :         repatcher.relink(fastPathStart.jumpAtOffset(inlineHoleGuard), slowPathStart);
        2497                 :
        2498               0 :     if (slowCallPatched) {
        2499               0 :         void *stub = JS_FUNC_TO_DATA_PTR(void *, APPLY_STRICTNESS(ic::SetElement, strictMode));
        2500               0 :         repatcher.relink(slowPathCall, FunctionPtr(stub));
        2501                 :     }
        2502                 :
        2503               0 :     reset();
        2504               0 : }
        2505                 :
        2506                 : LookupStatus
        2507             547 : SetElementIC::attachHoleStub(VMFrame &f, JSObject *obj, int32_t keyval)
        2508                 : {
        2509             547 :     JSContext *cx = f.cx;
        2510                 :
        2511             547 :     if (keyval < 0)
        2512               4 :         return disable(f, "negative key index");
        2513                 :
        2514                 :     // We may have failed a capacity check instead of a dense array check.
        2515                 :     // However we should still build the IC in this case, since it could
        2516                 :     // be in a loop that is filling in the array.
        2517                 :
        2518             543 :     if (js_PrototypeHasIndexedProperties(cx, obj))
        2519               4 :         return disable(f, "prototype has indexed properties");
        2520                 :
        2521            1078 :     Assembler masm;
        2522                 :
        2523            1078 :     Vector<Jump, 8> fails(cx);
        2524                 :
        2525             539 :     if (!GeneratePrototypeGuards(cx, fails, masm, obj, NULL, objReg, objReg))
        2526               0 :         return error(cx);
        2527                 :
        2528                 :     // Test for indexed properties in Array.prototype. We test each shape
        2529                 :     // along the proto chain. This affords us two optimizations:
        2530                 :     //  1) Loading the prototype can be avoided because the shape would change;
        2531                 :     //     instead we can bake in their identities.
        2532                 :     //  2) We only have to test the shape, rather than INDEXED.
        2533            1613 :     for (JSObject *pobj = obj->getProto(); pobj; pobj = pobj->getProto()) {
        2534            1074 :         if (!pobj->isNative())
        2535               0 :             return disable(f, "non-native array prototype");
        2536            1074 :         masm.move(ImmPtr(pobj), objReg);
        2537            1074 :         Jump j = masm.guardShape(objReg, pobj);
        2538            1074 :         if (!fails.append(j))
        2539               0 :             return error(cx);
        2540                 :     }
        2541                 :
        2542                 :     // Restore |obj|.
        2543             539 :     masm.rematPayload(StateRemat::FromInt32(objRemat), objReg);
        2544                 :
        2545                 :     // Load the elements.
        2546             539 :     masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), objReg);
        2547                 :
        2548             539 :     Int32Key key = hasConstantKey ? Int32Key::FromConstant(keyValue) : Int32Key::FromRegister(keyReg);
        2549                 :
        2550                 :     // Guard that the initialized length is being updated exactly.
        2551                 :     fails.append(masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
        2552             539 :                                        objReg, key, Assembler::NotEqual));
        2553                 :
        2554                 :     // Check the array capacity.
        2555                 :     fails.append(masm.guardArrayExtent(ObjectElements::offsetOfCapacity(),
        2556             539 :                                        objReg, key, Assembler::BelowOrEqual));
        2557                 :
        2558             539 :     masm.bumpKey(key, 1);
        2559                 :
        2560                 :     // Update the length and initialized length.
        2561             539 :     masm.storeKey(key, Address(objReg, ObjectElements::offsetOfInitializedLength()));
        2562                 :     Jump lengthGuard = masm.guardArrayExtent(ObjectElements::offsetOfLength(),
        2563             539 :                                              objReg, key, Assembler::AboveOrEqual);
        2564             539 :     masm.storeKey(key, Address(objReg, ObjectElements::offsetOfLength()));
        2565             539 :     lengthGuard.linkTo(masm.label(), &masm);
        2566                 :
        2567             539 :     masm.bumpKey(key, -1);
        2568                 :
        2569                 :     // Store the value back.
        2570             539 :     if (hasConstantKey) {
        2571              55 :         Address slot(objReg, keyValue * sizeof(Value));
        2572              55 :         masm.storeValue(vr, slot);
        2573                 :     } else {
        2574             484 :         BaseIndex slot(objReg, keyReg, Assembler::JSVAL_SCALE);
        2575             484 :         masm.storeValue(vr, slot);
        2576                 :     }
        2577                 :
        2578             539 :     Jump done = masm.jump();
        2579                 :
        2580             539 :     JS_ASSERT(!execPool);
        2581             539 :     JS_ASSERT(!inlineHoleGuardPatched);
        2582                 :
        2583            1078 :     LinkerHelper buffer(masm, JSC::METHOD_CODE);
        2584             539 :     execPool = buffer.init(cx);
        2585             539 :     if (!execPool)
        2586               0 :         return error(cx);
        2587                 :
        2588             539 :     if (!buffer.verifyRange(f.chunk()))
        2589               0 :         return disable(f, "code memory is out of range");
        2590                 :
        2591                 :     // Patch all guards.
        2592            3216 :     for (size_t i = 0; i < fails.length(); i++)
        2593            2677 :         buffer.link(fails[i], slowPathStart);
        2594             539 :     buffer.link(done, fastPathRejoin);
        2595                 :
        2596             539 :     CodeLocationLabel cs = buffer.finalize(f);
        2597             539 :     JaegerSpew(JSpew_PICs, "generated dense array hole stub at %p\n", cs.executableAddress());
        2598                 :
        2599            1078 :     Repatcher repatcher(f.chunk());
        2600             539 :     repatcher.relink(fastPathStart.jumpAtOffset(inlineHoleGuard), cs);
        2601             539 :     inlineHoleGuardPatched = true;
        2602                 :
        2603             539 :     disable(f, "generated dense array hole stub");
        2604                 :
        2605             539 :     return Lookup_Cacheable;
        2606                 : }
        2607                 :
        2608                 : #if defined JS_METHODJIT_TYPED_ARRAY
        2609                 : LookupStatus
        2610             640 : SetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, int32_t key)
        2611                 : {
        2612                 :     // Right now, only one shape guard extension is supported.
        2613             640 :     JS_ASSERT(!inlineShapeGuardPatched);
        2614                 :
        2615            1280 :     Assembler masm;
        2616             640 :     JSContext *cx = f.cx;
        2617                 :
        2618                 :     // Restore |obj|.
        2619             640 :     masm.rematPayload(StateRemat::FromInt32(objRemat), objReg);
        2620                 :
        2621                 :     // Guard on this typed array's shape.
        2622             640 :     Jump shapeGuard = masm.guardShape(objReg, obj);
        2623                 :
        2624                 :     // Bounds check.
        2625             640 :     Jump outOfBounds;
        2626             640 :     Address typedArrayLength = masm.payloadOf(Address(objReg, TypedArray::lengthOffset()));
        2627             640 :     if (hasConstantKey)
        2628             149 :         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(keyValue));
        2629                 :     else
        2630             491 :         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, keyReg);
        2631                 :
        2632                 :     // Load the array's packed data vector.
        2633             640 :     masm.loadPtr(Address(objReg, TypedArray::dataOffset()), objReg);
        2634                 :
        2635             640 :     JSObject *tarray = js::TypedArray::getTypedArray(obj);
        2636             640 :     if (!masm.supportsFloatingPoint() &&
        2637               0 :         (TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT32 ||
        2638               0 :          TypedArray::getType(tarray) == js::TypedArray::TYPE_FLOAT64))
        2639                 :     {
        2640               0 :         return disable(f, "fpu not supported");
        2641                 :     }
        2642                 :
        2643             640 :     int shift = js::TypedArray::slotWidth(obj);
        2644             640 :     if (hasConstantKey) {
        2645             149 :         Address addr(objReg, keyValue * shift);
        2646             149 :         if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask))
        2647               0 :             return error(cx);
        2648                 :     } else {
        2649             491 :         Assembler::Scale scale = Assembler::TimesOne;
        2650             491 :         switch (shift) {
        2651                 :           case 2:
        2652             104 :             scale = Assembler::TimesTwo;
        2653             104 :             break;
        2654                 :           case 4:
        2655             148 :             scale = Assembler::TimesFour;
        2656             148 :             break;
        2657                 :           case 8:
        2658              32 :             scale = Assembler::TimesEight;
        2659              32 :             break;
        2660                 :         }
        2661             491 :         BaseIndex addr(objReg, keyReg, scale);
        2662             491 :         if (!StoreToTypedArray(cx, masm, tarray, addr, vr, volatileMask))
        2663               0 :             return error(cx);
        2664                 :     }
        2665                 :
        2666             640 :     Jump done = masm.jump();
        2667                 :
        2668                 :     // The stub does not rely on any pointers or numbers that could be ruined
        2669                 :     // by a GC or shape regenerated GC. We let this stub live for the lifetime
        2670                 :     // of the script.
        2671             640 :     JS_ASSERT(!execPool);
        2672            1280 :     LinkerHelper buffer(masm, JSC::METHOD_CODE);
        2673             640 :     execPool = buffer.init(cx);
        2674             640 :     if (!execPool)
        2675               0 :         return error(cx);
        2676                 :
        2677             640 :     if (!buffer.verifyRange(f.chunk()))
        2678               0 :         return disable(f, "code memory is out of range");
        2679                 :
        2680                 :     // Note that the out-of-bounds path simply does nothing.
        2681             640 :     buffer.link(shapeGuard, slowPathStart);
        2682             640 :     buffer.link(outOfBounds, fastPathRejoin);
        2683             640 :     buffer.link(done, fastPathRejoin);
        2684             640 :     masm.finalize(buffer);
        2685                 :
        2686             640 :     CodeLocationLabel cs = buffer.finalizeCodeAddendum();
        2687             640 :     JaegerSpew(JSpew_PICs, "generated setelem typed array stub at %p\n", cs.executableAddress());
        2688                 :
        2689            1280 :     Repatcher repatcher(f.chunk());
        2690             640 :     repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
        2691             640 :     inlineShapeGuardPatched = true;
        2692                 :
        2693             640 :     stubsGenerated++;
        2694                 :
        2695                 :     // In the future, it might make sense to attach multiple typed array stubs.
        2696                 :     // For simplicitly, they are currently monomorphic.
        2697             640 :     if (stubsGenerated == MAX_GETELEM_IC_STUBS)
        2698               0 :         disable(f, "max stubs reached");
        2699                 :
        2700             640 :     disable(f, "generated typed array stub");
        2701                 :
        2702             640 :     return Lookup_Cacheable;
        2703                 : }
        2704                 : #endif /* JS_METHODJIT_TYPED_ARRAY */
        2705                 :
        2706                 : LookupStatus
        2707            1902 : SetElementIC::update(VMFrame &f, const Value &objval, const Value &idval)
        2708                 : {
        2709            1902 :     if (!objval.isObject())
        2710               0 :         return disable(f, "primitive lval");
        2711            1902 :     if (!idval.isInt32())
        2712             183 :         return disable(f, "non-int32 key");
        2713                 :
        2714            1719 :     JSObject *obj = &objval.toObject();
        2715            1719 :     int32_t key = idval.toInt32();
        2716                 :
        2717            1719 :     if (obj->isDenseArray())
        2718             547 :         return attachHoleStub(f, obj, key);
        2719                 :
        2720                 : #if defined JS_METHODJIT_TYPED_ARRAY
        2721                 :     /* Not attaching typed array stubs with linear scan allocator, see GetElementIC. */
        2722            1172 :     if (!f.cx->typeInferenceEnabled() && js_IsTypedArray(obj))
        2723             640 :         return attachTypedArray(f, obj, key);
        2724                 : #endif
        2725                 :
        2726             532 :     return disable(f, "unsupported object type");
        2727                 : }
        2728                 :
        2729                 : bool
        2730            4174 : SetElementIC::shouldUpdate(JSContext *cx)
        2731                 : {
        2732            4174 :     if (!hit) {
        2733            2272 :         hit = true;
        2734            2272 :         spew(cx, "ignored", "first hit");
        2735            2272 :         return false;
        2736                 :     }
        2737                 : #ifdef JSGC_INCREMENTAL_MJ
        2738            1902 :     JS_ASSERT(!cx->compartment->needsBarrier());
        2739                 : #endif
        2740            1902 :     JS_ASSERT(stubsGenerated < MAX_PIC_STUBS);
        2741            1902 :     return true;
        2742                 : }
        2743                 :
        2744                 : template<JSBool strict>
        2745                 : void JS_FASTCALL
        2746                 : ic::SetElement(VMFrame &f, ic::SetElementIC *ic)
        2747                 : {
        2748            4174 :     JSContext *cx = f.cx;
        2749                 :
        2750            4174 :     if (ic->shouldUpdate(cx)) {
        2751            1902 :         LookupStatus status = ic->update(f, f.regs.sp[-3], f.regs.sp[-2]);
        2752            1902 :         if (status == Lookup_Error)
        2753               0 :             THROW();
        2754                 :     }
        2755                 :
        2756            4174 :     stubs::SetElem<strict>(f);
        2757                 : }
        2758                 :
        2759                 : template void JS_FASTCALL ic::SetElement<true>(VMFrame &f, SetElementIC *ic);
        2760                 : template void JS_FASTCALL ic::SetElement<false>(VMFrame &f, SetElementIC *ic);
        2761                 :
        2762                 : #endif /* JS_POLYIC */
        2763                 :

Generated by: LCOV version 1.7