js/src/jit/BaselineInspector.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "jit/BaselineInspector.h"
     9 #include "mozilla/DebugOnly.h"
    11 #include "jit/BaselineIC.h"
    13 using namespace js;
    14 using namespace js::jit;
    16 using mozilla::DebugOnly;
    18 bool
    19 SetElemICInspector::sawOOBDenseWrite() const
    20 {
    21     if (!icEntry_)
    22         return false;
    24     // Check for a SetElem_DenseAdd stub.
    25     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
    26         if (stub->isSetElem_DenseAdd())
    27             return true;
    28     }
    30     // Check for a write hole bit on the SetElem_Fallback stub.
    31     ICStub *stub = icEntry_->fallbackStub();
    32     if (stub->isSetElem_Fallback())
    33         return stub->toSetElem_Fallback()->hasArrayWriteHole();
    35     return false;
    36 }
    38 bool
    39 SetElemICInspector::sawOOBTypedArrayWrite() const
    40 {
    41     if (!icEntry_)
    42         return false;
    44     // Check for SetElem_TypedArray stubs with expectOutOfBounds set.
    45     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
    46         if (!stub->isSetElem_TypedArray())
    47             continue;
    48         if (stub->toSetElem_TypedArray()->expectOutOfBounds())
    49             return true;
    50     }
    51     return false;
    52 }
    54 bool
    55 SetElemICInspector::sawDenseWrite() const
    56 {
    57     if (!icEntry_)
    58         return false;
    60     // Check for a SetElem_DenseAdd or SetElem_Dense stub.
    61     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
    62         if (stub->isSetElem_DenseAdd() || stub->isSetElem_Dense())
    63             return true;
    64     }
    65     return false;
    66 }
    68 bool
    69 SetElemICInspector::sawTypedArrayWrite() const
    70 {
    71     if (!icEntry_)
    72         return false;
    74     // Check for a SetElem_TypedArray stub.
    75     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
    76         if (stub->isSetElem_TypedArray())
    77             return true;
    78     }
    79     return false;
    80 }
    82 bool
    83 BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
    84 {
    85     // Return a list of shapes seen by the baseline IC for the current op.
    86     // An empty list indicates no shapes are known, or there was an uncacheable
    87     // access.
    88     JS_ASSERT(shapes.empty());
    90     if (!hasBaselineScript())
    91         return true;
    93     JS_ASSERT(isValidPC(pc));
    94     const ICEntry &entry = icEntryFromPC(pc);
    96     ICStub *stub = entry.firstStub();
    97     while (stub->next()) {
    98         Shape *shape;
    99         if (stub->isGetProp_Native()) {
   100             shape = stub->toGetProp_Native()->shape();
   101         } else if (stub->isSetProp_Native()) {
   102             shape = stub->toSetProp_Native()->shape();
   103         } else {
   104             shapes.clear();
   105             return true;
   106         }
   108         // Don't add the same shape twice (this can happen if there are multiple
   109         // SetProp_Native stubs with different TypeObject's).
   110         bool found = false;
   111         for (size_t i = 0; i < shapes.length(); i++) {
   112             if (shapes[i] == shape) {
   113                 found = true;
   114                 break;
   115             }
   116         }
   118         if (!found && !shapes.append(shape))
   119             return false;
   121         stub = stub->next();
   122     }
   124     if (stub->isGetProp_Fallback()) {
   125         if (stub->toGetProp_Fallback()->hadUnoptimizableAccess())
   126             shapes.clear();
   127     } else {
   128         if (stub->toSetProp_Fallback()->hadUnoptimizableAccess())
   129             shapes.clear();
   130     }
   132     // Don't inline if there are more than 5 shapes.
   133     if (shapes.length() > 5)
   134         shapes.clear();
   136     return true;
   137 }
   139 ICStub *
   140 BaselineInspector::monomorphicStub(jsbytecode *pc)
   141 {
   142     if (!hasBaselineScript())
   143         return nullptr;
   145     const ICEntry &entry = icEntryFromPC(pc);
   147     ICStub *stub = entry.firstStub();
   148     ICStub *next = stub->next();
   150     if (!next || !next->isFallback())
   151         return nullptr;
   153     return stub;
   154 }
   156 bool
   157 BaselineInspector::dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **psecond)
   158 {
   159     if (!hasBaselineScript())
   160         return false;
   162     const ICEntry &entry = icEntryFromPC(pc);
   164     ICStub *stub = entry.firstStub();
   165     ICStub *next = stub->next();
   166     ICStub *after = next ? next->next() : nullptr;
   168     if (!after || !after->isFallback())
   169         return false;
   171     *pfirst = stub;
   172     *psecond = next;
   173     return true;
   174 }
   176 MIRType
   177 BaselineInspector::expectedResultType(jsbytecode *pc)
   178 {
   179     // Look at the IC entries for this op to guess what type it will produce,
   180     // returning MIRType_None otherwise.
   182     ICStub *stub = monomorphicStub(pc);
   183     if (!stub)
   184         return MIRType_None;
   186     switch (stub->kind()) {
   187       case ICStub::BinaryArith_Int32:
   188         if (stub->toBinaryArith_Int32()->allowDouble())
   189             return MIRType_Double;
   190         return MIRType_Int32;
   191       case ICStub::BinaryArith_BooleanWithInt32:
   192       case ICStub::UnaryArith_Int32:
   193       case ICStub::BinaryArith_DoubleWithInt32:
   194         return MIRType_Int32;
   195       case ICStub::BinaryArith_Double:
   196       case ICStub::UnaryArith_Double:
   197         return MIRType_Double;
   198       case ICStub::BinaryArith_StringConcat:
   199       case ICStub::BinaryArith_StringObjectConcat:
   200         return MIRType_String;
   201       default:
   202         return MIRType_None;
   203     }
   204 }
   206 // Whether a baseline stub kind is suitable for a double comparison that
   207 // converts its operands to doubles.
   208 static bool
   209 CanUseDoubleCompare(ICStub::Kind kind)
   210 {
   211     return kind == ICStub::Compare_Double || kind == ICStub::Compare_NumberWithUndefined;
   212 }
   214 // Whether a baseline stub kind is suitable for an int32 comparison that
   215 // converts its operands to int32.
   216 static bool
   217 CanUseInt32Compare(ICStub::Kind kind)
   218 {
   219     return kind == ICStub::Compare_Int32 || kind == ICStub::Compare_Int32WithBoolean;
   220 }
   222 MCompare::CompareType
   223 BaselineInspector::expectedCompareType(jsbytecode *pc)
   224 {
   225     ICStub *first = monomorphicStub(pc), *second = nullptr;
   226     if (!first && !dimorphicStub(pc, &first, &second))
   227         return MCompare::Compare_Unknown;
   229     if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind()))) {
   230         ICCompare_Int32WithBoolean *coerce =
   231             first->isCompare_Int32WithBoolean()
   232             ? first->toCompare_Int32WithBoolean()
   233             : ((second && second->isCompare_Int32WithBoolean())
   234                ? second->toCompare_Int32WithBoolean()
   235                : nullptr);
   236         if (coerce) {
   237             return coerce->lhsIsInt32()
   238                    ? MCompare::Compare_Int32MaybeCoerceRHS
   239                    : MCompare::Compare_Int32MaybeCoerceLHS;
   240         }
   241         return MCompare::Compare_Int32;
   242     }
   244     if (CanUseDoubleCompare(first->kind()) && (!second || CanUseDoubleCompare(second->kind()))) {
   245         ICCompare_NumberWithUndefined *coerce =
   246             first->isCompare_NumberWithUndefined()
   247             ? first->toCompare_NumberWithUndefined()
   248             : (second && second->isCompare_NumberWithUndefined())
   249               ? second->toCompare_NumberWithUndefined()
   250               : nullptr;
   251         if (coerce) {
   252             return coerce->lhsIsUndefined()
   253                    ? MCompare::Compare_DoubleMaybeCoerceLHS
   254                    : MCompare::Compare_DoubleMaybeCoerceRHS;
   255         }
   256         return MCompare::Compare_Double;
   257     }
   259     return MCompare::Compare_Unknown;
   260 }
   262 static bool
   263 TryToSpecializeBinaryArithOp(ICStub **stubs,
   264                              uint32_t nstubs,
   265                              MIRType *result)
   266 {
   267     DebugOnly<bool> sawInt32 = false;
   268     bool sawDouble = false;
   269     bool sawOther = false;
   271     for (uint32_t i = 0; i < nstubs; i++) {
   272         switch (stubs[i]->kind()) {
   273           case ICStub::BinaryArith_Int32:
   274             sawInt32 = true;
   275             break;
   276           case ICStub::BinaryArith_BooleanWithInt32:
   277             sawInt32 = true;
   278             break;
   279           case ICStub::BinaryArith_Double:
   280             sawDouble = true;
   281             break;
   282           case ICStub::BinaryArith_DoubleWithInt32:
   283             sawDouble = true;
   284             break;
   285           default:
   286             sawOther = true;
   287             break;
   288         }
   289     }
   291     if (sawOther)
   292         return false;
   294     if (sawDouble) {
   295         *result = MIRType_Double;
   296         return true;
   297     }
   299     JS_ASSERT(sawInt32);
   300     *result = MIRType_Int32;
   301     return true;
   302 }
   304 MIRType
   305 BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc)
   306 {
   307     if (!hasBaselineScript())
   308         return MIRType_None;
   310     MIRType result;
   311     ICStub *stubs[2];
   313     const ICEntry &entry = icEntryFromPC(pc);
   314     ICStub *stub = entry.fallbackStub();
   315     if (stub->isBinaryArith_Fallback() &&
   316         stub->toBinaryArith_Fallback()->hadUnoptimizableOperands())
   317     {
   318         return MIRType_None;
   319     }
   321     stubs[0] = monomorphicStub(pc);
   322     if (stubs[0]) {
   323         if (TryToSpecializeBinaryArithOp(stubs, 1, &result))
   324             return result;
   325     }
   327     if (dimorphicStub(pc, &stubs[0], &stubs[1])) {
   328         if (TryToSpecializeBinaryArithOp(stubs, 2, &result))
   329             return result;
   330     }
   332     return MIRType_None;
   333 }
   335 bool
   336 BaselineInspector::hasSeenNonNativeGetElement(jsbytecode *pc)
   337 {
   338     if (!hasBaselineScript())
   339         return false;
   341     const ICEntry &entry = icEntryFromPC(pc);
   342     ICStub *stub = entry.fallbackStub();
   344     if (stub->isGetElem_Fallback())
   345         return stub->toGetElem_Fallback()->hasNonNativeAccess();
   346     return false;
   347 }
   349 bool
   350 BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode *pc)
   351 {
   352     if (!hasBaselineScript())
   353         return false;
   355     const ICEntry &entry = icEntryFromPC(pc);
   356     ICStub *stub = entry.fallbackStub();
   358     if (stub->isGetElem_Fallback())
   359         return stub->toGetElem_Fallback()->hasNegativeIndex();
   360     return false;
   361 }
   363 bool
   364 BaselineInspector::hasSeenAccessedGetter(jsbytecode *pc)
   365 {
   366     if (!hasBaselineScript())
   367         return false;
   369     const ICEntry &entry = icEntryFromPC(pc);
   370     ICStub *stub = entry.fallbackStub();
   372     if (stub->isGetProp_Fallback())
   373         return stub->toGetProp_Fallback()->hasAccessedGetter();
   374     return false;
   375 }
   377 bool
   378 BaselineInspector::hasSeenNonStringIterNext(jsbytecode *pc)
   379 {
   380     JS_ASSERT(JSOp(*pc) == JSOP_ITERNEXT);
   382     if (!hasBaselineScript())
   383         return false;
   385     const ICEntry &entry = icEntryFromPC(pc);
   386     ICStub *stub = entry.fallbackStub();
   388     return stub->toIteratorNext_Fallback()->hasNonStringResult();
   389 }
   391 bool
   392 BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
   393 {
   394     if (!hasBaselineScript())
   395         return false;
   397     const ICEntry &entry = icEntryFromPC(pc);
   398     ICStub *stub = entry.fallbackStub();
   400     JS_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback());
   402     if (stub->isUnaryArith_Fallback())
   403         return stub->toUnaryArith_Fallback()->sawDoubleResult();
   404     else
   405         return stub->toBinaryArith_Fallback()->sawDoubleResult();
   407     return false;
   408 }
   410 JSObject *
   411 BaselineInspector::getTemplateObject(jsbytecode *pc)
   412 {
   413     if (!hasBaselineScript())
   414         return nullptr;
   416     const ICEntry &entry = icEntryFromPC(pc);
   417     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
   418         switch (stub->kind()) {
   419           case ICStub::NewArray_Fallback:
   420             return stub->toNewArray_Fallback()->templateObject();
   421           case ICStub::NewObject_Fallback:
   422             return stub->toNewObject_Fallback()->templateObject();
   423           case ICStub::Rest_Fallback:
   424             return stub->toRest_Fallback()->templateObject();
   425           case ICStub::Call_Scripted:
   426             if (JSObject *obj = stub->toCall_Scripted()->templateObject())
   427                 return obj;
   428             break;
   429           default:
   430             break;
   431         }
   432     }
   434     return nullptr;
   435 }
   437 JSObject *
   438 BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
   439 {
   440     if (!hasBaselineScript())
   441         return nullptr;
   443     const ICEntry &entry = icEntryFromPC(pc);
   444     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
   445         if (stub->isCall_Native() && stub->toCall_Native()->callee()->native() == native)
   446             return stub->toCall_Native()->templateObject();
   447     }
   449     return nullptr;
   450 }
   452 DeclEnvObject *
   453 BaselineInspector::templateDeclEnvObject()
   454 {
   455     if (!hasBaselineScript())
   456         return nullptr;
   458     JSObject *res = &templateCallObject()->as<ScopeObject>().enclosingScope();
   459     JS_ASSERT(res);
   461     return &res->as<DeclEnvObject>();
   462 }
   464 CallObject *
   465 BaselineInspector::templateCallObject()
   466 {
   467     if (!hasBaselineScript())
   468         return nullptr;
   470     JSObject *res = baselineScript()->templateScope();
   471     JS_ASSERT(res);
   473     return &res->as<CallObject>();
   474 }
   476 JSObject *
   477 BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter)
   478 {
   479     if (!hasBaselineScript())
   480         return nullptr;
   482     const ICEntry &entry = icEntryFromPC(pc);
   483     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
   484         if (stub->isGetProp_CallScripted()  ||
   485             stub->isGetProp_CallNative()    ||
   486             stub->isGetProp_CallNativePrototype())
   487         {
   488             ICGetPropCallGetter *nstub = static_cast<ICGetPropCallGetter *>(stub);
   489             *lastProperty = nstub->holderShape();
   490             *commonGetter = nstub->getter();
   491             return nstub->holder();
   492         }
   493     }
   494     return nullptr;
   495 }
   497 JSObject *
   498 BaselineInspector::commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter)
   499 {
   500     if (!hasBaselineScript())
   501         return nullptr;
   503     const ICEntry &entry = icEntryFromPC(pc);
   504     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
   505         if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
   506             ICSetPropCallSetter *nstub = static_cast<ICSetPropCallSetter *>(stub);
   507             *lastProperty = nstub->holderShape();
   508             *commonSetter = nstub->setter();
   509             return nstub->holder();
   510         }
   511     }
   512     return nullptr;
   513 }

mercurial