LCOV - code coverage report
Current view: top level - js/src/jit - IonCaches.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 102 162 63.0 %
Date: 2017-07-14 16:53:18 Functions: 10 12 83.3 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "jit/IonCaches.h"
       8             : 
       9             : #include "mozilla/SizePrintfMacros.h"
      10             : #include "mozilla/TemplateLib.h"
      11             : 
      12             : #include "jstypes.h"
      13             : 
      14             : #include "builtin/TypedObject.h"
      15             : #include "jit/BaselineIC.h"
      16             : #include "jit/Ion.h"
      17             : #include "jit/JitcodeMap.h"
      18             : #include "jit/JitSpewer.h"
      19             : #include "jit/Linker.h"
      20             : #include "jit/Lowering.h"
      21             : #ifdef JS_ION_PERF
      22             : # include "jit/PerfSpewer.h"
      23             : #endif
      24             : #include "jit/VMFunctions.h"
      25             : #include "js/Proxy.h"
      26             : #include "proxy/Proxy.h"
      27             : #include "vm/Shape.h"
      28             : #include "vm/Stack.h"
      29             : 
      30             : #include "jit/JitFrames-inl.h"
      31             : #include "jit/MacroAssembler-inl.h"
      32             : #include "jit/shared/Lowering-shared-inl.h"
      33             : #include "vm/Interpreter-inl.h"
      34             : #include "vm/Shape-inl.h"
      35             : 
      36             : using namespace js;
      37             : using namespace js::jit;
      38             : 
      39             : using mozilla::tl::FloorLog2;
      40             : 
      41             : void
      42          21 : CodeLocationJump::repoint(JitCode* code, MacroAssembler* masm)
      43             : {
      44          21 :     MOZ_ASSERT(state_ == Relative);
      45          21 :     size_t new_off = (size_t)raw_;
      46             : #ifdef JS_SMALL_BRANCH
      47          21 :     size_t jumpTableEntryOffset = reinterpret_cast<size_t>(jumpTableEntry_);
      48             : #endif
      49          21 :     if (masm != nullptr) {
      50             : #ifdef JS_CODEGEN_X64
      51           0 :         MOZ_ASSERT((uint64_t)raw_ <= UINT32_MAX);
      52             : #endif
      53           0 :         new_off = (uintptr_t)raw_;
      54             : #ifdef JS_SMALL_BRANCH
      55           0 :         jumpTableEntryOffset = masm->actualIndex(jumpTableEntryOffset);
      56             : #endif
      57             :     }
      58          21 :     raw_ = code->raw() + new_off;
      59             : #ifdef JS_SMALL_BRANCH
      60          21 :     jumpTableEntry_ = Assembler::PatchableJumpAddress(code, (size_t) jumpTableEntryOffset);
      61             : #endif
      62          21 :     setAbsolute();
      63          21 : }
      64             : 
      65             : void
      66       20784 : CodeLocationLabel::repoint(JitCode* code, MacroAssembler* masm)
      67             : {
      68       20784 :      MOZ_ASSERT(state_ == Relative);
      69       20784 :      size_t new_off = (size_t)raw_;
      70       20784 :      if (masm != nullptr) {
      71             : #ifdef JS_CODEGEN_X64
      72          28 :         MOZ_ASSERT((uint64_t)raw_ <= UINT32_MAX);
      73             : #endif
      74          28 :         new_off = (uintptr_t)raw_;
      75             :      }
      76       20784 :      MOZ_ASSERT(new_off < code->instructionsSize());
      77             : 
      78       20784 :      raw_ = code->raw() + new_off;
      79       20784 :      setAbsolute();
      80       20784 : }
      81             : 
      82             : void
      83          21 : CodeOffsetJump::fixup(MacroAssembler* masm)
      84             : {
      85             : #ifdef JS_SMALL_BRANCH
      86          21 :      jumpTableIndex_ = masm->actualIndex(jumpTableIndex_);
      87             : #endif
      88          21 : }
      89             : 
      90             : void*
      91           0 : jit::GetReturnAddressToIonCode(JSContext* cx)
      92             : {
      93           0 :     JitFrameIterator iter(cx);
      94           0 :     MOZ_ASSERT(iter.type() == JitFrame_Exit,
      95             :                "An exit frame is expected as update functions are called with a VMFunction.");
      96             : 
      97           0 :     void* returnAddr = iter.returnAddress();
      98             : #ifdef DEBUG
      99           0 :     ++iter;
     100           0 :     MOZ_ASSERT(iter.isIonJS());
     101             : #endif
     102           0 :     return returnAddr;
     103             : }
     104             : 
     105             : // Note: This differs from IsCacheableProtoChain in BaselineIC.cpp in that
     106             : // Ion caches can deal with objects on the proto chain that have uncacheable
     107             : // prototypes.
     108             : bool
     109        6679 : jit::IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder)
     110             : {
     111        8557 :     while (obj != holder) {
     112             :         /*
     113             :          * We cannot assume that we find the holder object on the prototype
     114             :          * chain and must check for null proto. The prototype chain can be
     115             :          * altered during the lookupProperty call.
     116             :          */
     117        1878 :         JSObject* proto = obj->staticPrototype();
     118        1878 :         if (!proto || !proto->isNative())
     119           0 :             return false;
     120        1878 :         obj = proto;
     121             :     }
     122        4801 :     return true;
     123             : }
     124             : 
     125             : bool
     126        4166 : jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, PropertyResult prop)
     127             : {
     128        4166 :     if (!prop || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
     129         201 :         return false;
     130             : 
     131        3965 :     Shape* shape = prop.shape();
     132        3965 :     if (!shape->hasSlot() || !shape->hasDefaultGetter())
     133         230 :         return false;
     134             : 
     135        3735 :     return true;
     136             : }
     137             : 
     138             : bool
     139         348 : jit::IsCacheableGetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape)
     140             : {
     141         348 :     if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
     142           0 :         return false;
     143             : 
     144         348 :     if (!shape->hasGetterValue() || !shape->getterValue().isObject())
     145           5 :         return false;
     146             : 
     147         343 :     if (!shape->getterValue().toObject().is<JSFunction>())
     148           1 :         return false;
     149             : 
     150         342 :     JSFunction& getter = shape->getterValue().toObject().as<JSFunction>();
     151         342 :     if (!getter.isNative())
     152         115 :         return false;
     153             : 
     154         227 :     if (getter.isClassConstructor())
     155           0 :         return false;
     156             : 
     157             :     // Check for a getter that has jitinfo and whose jitinfo says it's
     158             :     // OK with both inner and outer objects.
     159         227 :     if (getter.jitInfo() && !getter.jitInfo()->needsOuterizedThisObject())
     160          82 :         return true;
     161             : 
     162             :     // For getters that need the WindowProxy (instead of the Window) as this
     163             :     // object, don't cache if obj is the Window, since our cache will pass that
     164             :     // instead of the WindowProxy.
     165         145 :     return !IsWindow(obj);
     166             : }
     167             : 
     168             : bool
     169         296 : jit::IsCacheableGetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
     170             :                                     bool* isTemporarilyUnoptimizable)
     171             : {
     172         296 :     if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
     173           0 :         return false;
     174             : 
     175         296 :     if (!shape->hasGetterValue() || !shape->getterValue().isObject())
     176           5 :         return false;
     177             : 
     178         291 :     if (!shape->getterValue().toObject().is<JSFunction>())
     179           0 :         return false;
     180             : 
     181             :     // See IsCacheableGetPropCallNative.
     182         291 :     if (IsWindow(obj))
     183           0 :         return false;
     184             : 
     185         291 :     JSFunction& getter = shape->getterValue().toObject().as<JSFunction>();
     186         291 :     if (getter.isNative())
     187         110 :         return false;
     188             : 
     189         181 :     if (!getter.hasJITCode()) {
     190          49 :         if (isTemporarilyUnoptimizable)
     191          49 :             *isTemporarilyUnoptimizable = true;
     192          49 :         return false;
     193             :     }
     194             : 
     195         132 :     if (getter.isClassConstructor())
     196           0 :         return false;
     197             : 
     198         132 :     return true;
     199             : }
     200             : 
     201             : bool
     202        6078 : jit::ValueToNameOrSymbolId(JSContext* cx, HandleValue idval, MutableHandleId id,
     203             :                            bool* nameOrSymbol)
     204             : {
     205        6078 :     *nameOrSymbol = false;
     206             : 
     207        6078 :     if (!idval.isString() && !idval.isSymbol())
     208         407 :         return true;
     209             : 
     210        5671 :     if (!ValueToId<CanGC>(cx, idval, id))
     211           0 :         return false;
     212             : 
     213        5671 :     if (!JSID_IS_STRING(id) && !JSID_IS_SYMBOL(id)) {
     214           2 :         id.set(JSID_VOID);
     215           2 :         return true;
     216             :     }
     217             : 
     218             :     uint32_t dummy;
     219        5669 :     if (JSID_IS_STRING(id) && JSID_TO_ATOM(id)->isIndex(&dummy)) {
     220           0 :         id.set(JSID_VOID);
     221           0 :         return true;
     222             :     }
     223             : 
     224        5669 :     *nameOrSymbol = true;
     225        5669 :     return true;
     226             : }
     227             : 
     228             : bool
     229         480 : jit::IsCacheableSetPropCallNative(JSObject* obj, JSObject* holder, Shape* shape)
     230             : {
     231         480 :     if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
     232         383 :         return false;
     233             : 
     234          97 :     if (!shape->hasSetterValue())
     235          55 :         return false;
     236             : 
     237          42 :     if (!shape->setterObject() || !shape->setterObject()->is<JSFunction>())
     238           0 :         return false;
     239             : 
     240          42 :     JSFunction& setter = shape->setterObject()->as<JSFunction>();
     241          42 :     if (!setter.isNative())
     242          30 :         return false;
     243             : 
     244          12 :     if (setter.isClassConstructor())
     245           0 :         return false;
     246             : 
     247          12 :     if (setter.jitInfo() && !setter.jitInfo()->needsOuterizedThisObject())
     248          12 :         return true;
     249             : 
     250           0 :     return !IsWindow(obj);
     251             : }
     252             : 
     253             : bool
     254         478 : jit::IsCacheableSetPropCallScripted(JSObject* obj, JSObject* holder, Shape* shape,
     255             :                                     bool* isTemporarilyUnoptimizable)
     256             : {
     257         478 :     if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
     258         383 :         return false;
     259             : 
     260          95 :     if (IsWindow(obj))
     261           0 :         return false;
     262             : 
     263          95 :     if (!shape->hasSetterValue())
     264          55 :         return false;
     265             : 
     266          40 :     if (!shape->setterObject() || !shape->setterObject()->is<JSFunction>())
     267           0 :         return false;
     268             : 
     269          40 :     JSFunction& setter = shape->setterObject()->as<JSFunction>();
     270          40 :     if (setter.isNative())
     271           6 :         return false;
     272             : 
     273          34 :     if (!setter.hasJITCode()) {
     274          26 :         if (isTemporarilyUnoptimizable)
     275          26 :             *isTemporarilyUnoptimizable = true;
     276          26 :         return false;
     277             :     }
     278             : 
     279           8 :     if (setter.isClassConstructor())
     280           0 :         return false;
     281             : 
     282           8 :     return true;
     283             : }
     284             : 
     285             : void
     286           0 : jit::EmitIonStoreDenseElement(MacroAssembler& masm, const ConstantOrRegister& value,
     287             :                               Register elements, BaseObjectElementIndex target)
     288             : {
     289             :     // If the ObjectElements::CONVERT_DOUBLE_ELEMENTS flag is set, int32 values
     290             :     // have to be converted to double first. If the value is not int32, it can
     291             :     // always be stored directly.
     292             : 
     293           0 :     Address elementsFlags(elements, ObjectElements::offsetOfFlags());
     294           0 :     if (value.constant()) {
     295           0 :         Value v = value.value();
     296           0 :         Label done;
     297           0 :         if (v.isInt32()) {
     298           0 :             Label dontConvert;
     299           0 :             masm.branchTest32(Assembler::Zero, elementsFlags,
     300             :                               Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
     301           0 :                               &dontConvert);
     302           0 :             masm.storeValue(DoubleValue(v.toInt32()), target);
     303           0 :             masm.jump(&done);
     304           0 :             masm.bind(&dontConvert);
     305             :         }
     306           0 :         masm.storeValue(v, target);
     307           0 :         masm.bind(&done);
     308           0 :         return;
     309             :     }
     310             : 
     311           0 :     TypedOrValueRegister reg = value.reg();
     312           0 :     if (reg.hasTyped() && reg.type() != MIRType::Int32) {
     313           0 :         masm.storeTypedOrValue(reg, target);
     314           0 :         return;
     315             :     }
     316             : 
     317           0 :     Label convert, storeValue, done;
     318           0 :     masm.branchTest32(Assembler::NonZero, elementsFlags,
     319             :                       Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
     320           0 :                       &convert);
     321           0 :     masm.bind(&storeValue);
     322           0 :     masm.storeTypedOrValue(reg, target);
     323           0 :     masm.jump(&done);
     324             : 
     325           0 :     masm.bind(&convert);
     326           0 :     if (reg.hasValue()) {
     327           0 :         masm.branchTestInt32(Assembler::NotEqual, reg.valueReg(), &storeValue);
     328           0 :         masm.int32ValueToDouble(reg.valueReg(), ScratchDoubleReg);
     329           0 :         masm.storeDouble(ScratchDoubleReg, target);
     330             :     } else {
     331           0 :         MOZ_ASSERT(reg.type() == MIRType::Int32);
     332           0 :         masm.convertInt32ToDouble(reg.typedReg().gpr(), ScratchDoubleReg);
     333           0 :         masm.storeDouble(ScratchDoubleReg, target);
     334             :     }
     335             : 
     336           0 :     masm.bind(&done);
     337             : }

Generated by: LCOV version 1.13