LCOV - code coverage report
Current view: top level - js/src/jit - BytecodeAnalysis.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 104 107 97.2 %
Date: 2017-07-14 16:53:18 Functions: 6 6 100.0 %
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/BytecodeAnalysis.h"
       8             : 
       9             : #include "jsopcode.h"
      10             : #include "jit/JitSpewer.h"
      11             : #include "jsopcodeinlines.h"
      12             : #include "jsscriptinlines.h"
      13             : 
      14             : using namespace js;
      15             : using namespace js::jit;
      16             : 
      17         957 : BytecodeAnalysis::BytecodeAnalysis(TempAllocator& alloc, JSScript* script)
      18             :   : script_(script),
      19             :     infos_(alloc),
      20             :     usesEnvironmentChain_(false),
      21             :     hasTryFinally_(false),
      22         957 :     hasSetArg_(false)
      23             : {
      24         957 : }
      25             : 
      26             : // Bytecode range containing only catch or finally code.
      27             : struct CatchFinallyRange
      28             : {
      29             :     uint32_t start; // Inclusive.
      30             :     uint32_t end;   // Exclusive.
      31             : 
      32         282 :     CatchFinallyRange(uint32_t start, uint32_t end)
      33         282 :       : start(start), end(end)
      34             :     {
      35         282 :         MOZ_ASSERT(end > start);
      36         282 :     }
      37             : 
      38         388 :     bool contains(uint32_t offset) const {
      39         388 :         return start <= offset && offset < end;
      40             :     }
      41             : };
      42             : 
      43             : bool
      44         957 : BytecodeAnalysis::init(TempAllocator& alloc, GSNCache& gsn)
      45             : {
      46         957 :     if (!infos_.growByUninitialized(script_->length()))
      47           0 :         return false;
      48             : 
      49             :     // Initialize the env chain slot if either the function needs some
      50             :     // EnvironmentObject (like a CallObject) or the script uses the env
      51             :     // chain. The latter case is handled below.
      52        1914 :     usesEnvironmentChain_ = script_->module() || script_->initialEnvironmentShape() ||
      53        1751 :                             (script_->functionDelazifying() &&
      54         873 :                              script_->functionDelazifying()->needsSomeEnvironmentObject());
      55             : 
      56         957 :     jsbytecode* end = script_->codeEnd();
      57             : 
      58             :     // Clear all BytecodeInfo.
      59         957 :     mozilla::PodZero(infos_.begin(), infos_.length());
      60         957 :     infos_[0].init(/*stackDepth=*/0);
      61             : 
      62        1914 :     Vector<CatchFinallyRange, 0, JitAllocPolicy> catchFinallyRanges(alloc);
      63             : 
      64             :     jsbytecode* nextpc;
      65      139052 :     for (jsbytecode* pc = script_->code(); pc < end; pc = nextpc) {
      66      138095 :         JSOp op = JSOp(*pc);
      67      138095 :         nextpc = pc + GetBytecodeLength(pc);
      68      138095 :         unsigned offset = script_->pcToOffset(pc);
      69             : 
      70      414285 :         JitSpew(JitSpew_BaselineOp, "Analyzing op @ %d (end=%d): %s",
      71      414285 :                 int(script_->pcToOffset(pc)), int(script_->length()), CodeName[op]);
      72             : 
      73             :         // If this bytecode info has not yet been initialized, it's not reachable.
      74      138095 :         if (!infos_[offset].initialized)
      75       33427 :             continue;
      76             : 
      77      104668 :         unsigned stackDepth = infos_[offset].stackDepth;
      78             : #ifdef DEBUG
      79      278155 :         for (jsbytecode* chkpc = pc + 1; chkpc < (pc + GetBytecodeLength(pc)); chkpc++)
      80      173487 :             MOZ_ASSERT(!infos_[script_->pcToOffset(chkpc)].initialized);
      81             : #endif
      82             : 
      83      104668 :         unsigned nuses = GetUseCount(script_, offset);
      84      104668 :         unsigned ndefs = GetDefCount(script_, offset);
      85             : 
      86      104668 :         MOZ_ASSERT(stackDepth >= nuses);
      87      104668 :         stackDepth -= nuses;
      88      104668 :         stackDepth += ndefs;
      89             : 
      90             :         // If stack depth exceeds max allowed by analysis, fail fast.
      91      104668 :         MOZ_ASSERT(stackDepth <= BytecodeInfo::MAX_STACK_DEPTH);
      92             : 
      93      104668 :         switch (op) {
      94             :           case JSOP_TABLESWITCH: {
      95          99 :             unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
      96          99 :             jsbytecode* pc2 = pc + JUMP_OFFSET_LEN;
      97          99 :             int32_t low = GET_JUMP_OFFSET(pc2);
      98          99 :             pc2 += JUMP_OFFSET_LEN;
      99          99 :             int32_t high = GET_JUMP_OFFSET(pc2);
     100          99 :             pc2 += JUMP_OFFSET_LEN;
     101             : 
     102          99 :             infos_[defaultOffset].init(stackDepth);
     103          99 :             infos_[defaultOffset].jumpTarget = true;
     104             : 
     105         674 :             for (int32_t i = low; i <= high; i++) {
     106         575 :                 unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
     107         575 :                 if (targetOffset != offset) {
     108         575 :                     infos_[targetOffset].init(stackDepth);
     109         575 :                     infos_[targetOffset].jumpTarget = true;
     110             :                 }
     111         575 :                 pc2 += JUMP_OFFSET_LEN;
     112             :             }
     113          99 :             break;
     114             :           }
     115             : 
     116             :           case JSOP_TRY: {
     117         282 :             JSTryNote* tn = script_->trynotes()->vector;
     118         282 :             JSTryNote* tnlimit = tn + script_->trynotes()->length;
     119        5220 :             for (; tn < tnlimit; tn++) {
     120        2469 :                 unsigned startOffset = script_->mainOffset() + tn->start;
     121        2469 :                 if (startOffset == offset + 1) {
     122         290 :                     unsigned catchOffset = startOffset + tn->length;
     123             : 
     124         290 :                     if (tn->kind != JSTRY_FOR_IN) {
     125         290 :                         infos_[catchOffset].init(stackDepth);
     126         290 :                         infos_[catchOffset].jumpTarget = true;
     127             :                     }
     128             :                 }
     129             :             }
     130             : 
     131             :             // Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
     132             :             // jump over the catch/finally blocks.
     133         282 :             jssrcnote* sn = GetSrcNote(gsn, script_, pc);
     134         282 :             MOZ_ASSERT(SN_TYPE(sn) == SRC_TRY);
     135             : 
     136         282 :             jsbytecode* endOfTry = pc + GetSrcNoteOffset(sn, 0);
     137         282 :             MOZ_ASSERT(JSOp(*endOfTry) == JSOP_GOTO);
     138             : 
     139         282 :             jsbytecode* afterTry = endOfTry + GET_JUMP_OFFSET(endOfTry);
     140         282 :             MOZ_ASSERT(afterTry > endOfTry);
     141             : 
     142             :             // Pop CatchFinallyRanges that are no longer needed.
     143          90 :             while (!catchFinallyRanges.empty() && catchFinallyRanges.back().end <= offset)
     144          90 :                 catchFinallyRanges.popBack();
     145             : 
     146         282 :             CatchFinallyRange range(script_->pcToOffset(endOfTry), script_->pcToOffset(afterTry));
     147         282 :             if (!catchFinallyRanges.append(range))
     148           0 :                 return false;
     149         282 :             break;
     150             :           }
     151             : 
     152             :           case JSOP_LOOPENTRY:
     153        1428 :             for (size_t i = 0; i < catchFinallyRanges.length(); i++) {
     154         388 :                 if (catchFinallyRanges[i].contains(offset))
     155           4 :                     infos_[offset].loopEntryInCatchOrFinally = true;
     156             :             }
     157        1040 :             break;
     158             : 
     159             :           case JSOP_GETNAME:
     160             :           case JSOP_BINDNAME:
     161             :           case JSOP_BINDVAR:
     162             :           case JSOP_SETNAME:
     163             :           case JSOP_STRICTSETNAME:
     164             :           case JSOP_DELNAME:
     165             :           case JSOP_GETALIASEDVAR:
     166             :           case JSOP_SETALIASEDVAR:
     167             :           case JSOP_LAMBDA:
     168             :           case JSOP_LAMBDA_ARROW:
     169             :           case JSOP_DEFFUN:
     170             :           case JSOP_DEFVAR:
     171             :           case JSOP_PUSHLEXICALENV:
     172             :           case JSOP_POPLEXICALENV:
     173        2649 :             usesEnvironmentChain_ = true;
     174        2649 :             break;
     175             : 
     176             :           case JSOP_GETGNAME:
     177             :           case JSOP_SETGNAME:
     178             :           case JSOP_STRICTSETGNAME:
     179        1736 :             if (script_->hasNonSyntacticScope())
     180           0 :                 usesEnvironmentChain_ = true;
     181        1736 :             break;
     182             : 
     183             :           case JSOP_FINALLY:
     184          12 :             hasTryFinally_ = true;
     185          12 :             break;
     186             : 
     187             :           case JSOP_SETARG:
     188         136 :             hasSetArg_ = true;
     189         136 :             break;
     190             : 
     191             :           default:
     192       98714 :             break;
     193             :         }
     194             : 
     195      104668 :         bool jump = IsJumpOpcode(op);
     196      104668 :         if (jump) {
     197             :             // Case instructions do not push the lvalue back when branching.
     198        6877 :             unsigned newStackDepth = stackDepth;
     199        6877 :             if (op == JSOP_CASE)
     200          23 :                 newStackDepth--;
     201             : 
     202        6877 :             unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
     203             : 
     204             :             // If this is a a backedge to an un-analyzed segment, analyze from there.
     205        6877 :             bool jumpBack = (targetOffset < offset) && !infos_[targetOffset].initialized;
     206             : 
     207        6877 :             infos_[targetOffset].init(newStackDepth);
     208        6877 :             infos_[targetOffset].jumpTarget = true;
     209             : 
     210        6877 :             if (jumpBack)
     211         522 :                 nextpc = script_->offsetToPC(targetOffset);
     212             :         }
     213             : 
     214             :         // Handle any fallthrough from this opcode.
     215      104668 :         if (BytecodeFallsThrough(op)) {
     216      100181 :             jsbytecode* fallthrough = pc + GetBytecodeLength(pc);
     217      100181 :             MOZ_ASSERT(fallthrough < end);
     218      100181 :             unsigned fallthroughOffset = script_->pcToOffset(fallthrough);
     219             : 
     220      100181 :             infos_[fallthroughOffset].init(stackDepth);
     221             : 
     222             :             // Treat the fallthrough of a branch instruction as a jump target.
     223      100181 :             if (jump)
     224        4852 :                 infos_[fallthroughOffset].jumpTarget = true;
     225             :         }
     226             :     }
     227             : 
     228         957 :     return true;
     229           9 : }

Generated by: LCOV version 1.13