js/src/jit/BytecodeAnalysis.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/BytecodeAnalysis.h"
     9 #include "jsopcode.h"
    10 #include "jit/IonSpewer.h"
    11 #include "jsopcodeinlines.h"
    13 using namespace js;
    14 using namespace js::jit;
    16 BytecodeAnalysis::BytecodeAnalysis(TempAllocator &alloc, JSScript *script)
    17   : script_(script),
    18     infos_(alloc),
    19     usesScopeChain_(false),
    20     hasTryFinally_(false),
    21     hasSetArg_(false)
    22 {
    23 }
    25 // Bytecode range containing only catch or finally code.
    26 struct CatchFinallyRange
    27 {
    28     uint32_t start; // Inclusive.
    29     uint32_t end;   // Exclusive.
    31     CatchFinallyRange(uint32_t start, uint32_t end)
    32       : start(start), end(end)
    33     {
    34         JS_ASSERT(end > start);
    35     }
    37     bool contains(uint32_t offset) const {
    38         return start <= offset && offset < end;
    39     }
    40 };
    42 bool
    43 BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn)
    44 {
    45     if (!infos_.growByUninitialized(script_->length()))
    46         return false;
    48     jsbytecode *end = script_->codeEnd();
    50     // Clear all BytecodeInfo.
    51     mozilla::PodZero(infos_.begin(), infos_.length());
    52     infos_[0].init(/*stackDepth=*/0);
    54     Vector<CatchFinallyRange, 0, IonAllocPolicy> catchFinallyRanges(alloc);
    56     for (jsbytecode *pc = script_->code(); pc < end; pc += GetBytecodeLength(pc)) {
    57         JSOp op = JSOp(*pc);
    58         unsigned offset = script_->pcToOffset(pc);
    60         IonSpew(IonSpew_BaselineOp, "Analyzing op @ %d (end=%d): %s",
    61                 int(script_->pcToOffset(pc)), int(script_->length()), js_CodeName[op]);
    63         // If this bytecode info has not yet been initialized, it's not reachable.
    64         if (!infos_[offset].initialized)
    65             continue;
    68         unsigned stackDepth = infos_[offset].stackDepth;
    69 #ifdef DEBUG
    70         for (jsbytecode *chkpc = pc + 1; chkpc < (pc + GetBytecodeLength(pc)); chkpc++)
    71             JS_ASSERT(!infos_[script_->pcToOffset(chkpc)].initialized);
    72 #endif
    74         unsigned nuses = GetUseCount(script_, offset);
    75         unsigned ndefs = GetDefCount(script_, offset);
    77         JS_ASSERT(stackDepth >= nuses);
    78         stackDepth -= nuses;
    79         stackDepth += ndefs;
    81         // If stack depth exceeds max allowed by analysis, fail fast.
    82         JS_ASSERT(stackDepth <= BytecodeInfo::MAX_STACK_DEPTH);
    84         switch (op) {
    85           case JSOP_TABLESWITCH: {
    86             unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
    87             jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
    88             int32_t low = GET_JUMP_OFFSET(pc2);
    89             pc2 += JUMP_OFFSET_LEN;
    90             int32_t high = GET_JUMP_OFFSET(pc2);
    91             pc2 += JUMP_OFFSET_LEN;
    93             infos_[defaultOffset].init(stackDepth);
    94             infos_[defaultOffset].jumpTarget = true;
    96             for (int32_t i = low; i <= high; i++) {
    97                 unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
    98                 if (targetOffset != offset) {
    99                     infos_[targetOffset].init(stackDepth);
   100                     infos_[targetOffset].jumpTarget = true;
   101                 }
   102                 pc2 += JUMP_OFFSET_LEN;
   103             }
   104             break;
   105           }
   107           case JSOP_TRY: {
   108             JSTryNote *tn = script_->trynotes()->vector;
   109             JSTryNote *tnlimit = tn + script_->trynotes()->length;
   110             for (; tn < tnlimit; tn++) {
   111                 unsigned startOffset = script_->mainOffset() + tn->start;
   112                 if (startOffset == offset + 1) {
   113                     unsigned catchOffset = startOffset + tn->length;
   115                     if (tn->kind != JSTRY_ITER) {
   116                         infos_[catchOffset].init(stackDepth);
   117                         infos_[catchOffset].jumpTarget = true;
   118                     }
   119                 }
   120             }
   122             // Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
   123             // jump over the catch/finally blocks.
   124             jssrcnote *sn = GetSrcNote(gsn, script_, pc);
   125             JS_ASSERT(SN_TYPE(sn) == SRC_TRY);
   127             jsbytecode *endOfTry = pc + js_GetSrcNoteOffset(sn, 0);
   128             JS_ASSERT(JSOp(*endOfTry) == JSOP_GOTO);
   130             jsbytecode *afterTry = endOfTry + GET_JUMP_OFFSET(endOfTry);
   131             JS_ASSERT(afterTry > endOfTry);
   133             // Pop CatchFinallyRanges that are no longer needed.
   134             while (!catchFinallyRanges.empty() && catchFinallyRanges.back().end <= offset)
   135                 catchFinallyRanges.popBack();
   137             CatchFinallyRange range(script_->pcToOffset(endOfTry), script_->pcToOffset(afterTry));
   138             if (!catchFinallyRanges.append(range))
   139                 return false;
   140             break;
   141           }
   143           case JSOP_LOOPENTRY:
   144             for (size_t i = 0; i < catchFinallyRanges.length(); i++) {
   145                 if (catchFinallyRanges[i].contains(offset))
   146                     infos_[offset].loopEntryInCatchOrFinally = true;
   147             }
   148             break;
   150           case JSOP_NAME:
   151           case JSOP_BINDNAME:
   152           case JSOP_SETNAME:
   153           case JSOP_DELNAME:
   154           case JSOP_GETALIASEDVAR:
   155           case JSOP_SETALIASEDVAR:
   156           case JSOP_LAMBDA:
   157           case JSOP_LAMBDA_ARROW:
   158           case JSOP_DEFFUN:
   159           case JSOP_DEFVAR:
   160           case JSOP_DEFCONST:
   161           case JSOP_SETCONST:
   162             usesScopeChain_ = true;
   163             break;
   165           case JSOP_FINALLY:
   166             hasTryFinally_ = true;
   167             break;
   169           case JSOP_SETARG:
   170             hasSetArg_ = true;
   171             break;
   173           default:
   174             break;
   175         }
   177         bool jump = IsJumpOpcode(op);
   178         if (jump) {
   179             // Case instructions do not push the lvalue back when branching.
   180             unsigned newStackDepth = stackDepth;
   181             if (op == JSOP_CASE)
   182                 newStackDepth--;
   184             unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
   186             // If this is a a backedge to an un-analyzed segment, analyze from there.
   187             bool jumpBack = (targetOffset < offset) && !infos_[targetOffset].initialized;
   189             infos_[targetOffset].init(newStackDepth);
   190             infos_[targetOffset].jumpTarget = true;
   192             if (jumpBack)
   193                 pc = script_->offsetToPC(targetOffset);
   194         }
   196         // Handle any fallthrough from this opcode.
   197         if (BytecodeFallsThrough(op)) {
   198             jsbytecode *nextpc = pc + GetBytecodeLength(pc);
   199             JS_ASSERT(nextpc < end);
   200             unsigned nextOffset = script_->pcToOffset(nextpc);
   202             infos_[nextOffset].init(stackDepth);
   204             if (jump)
   205                 infos_[nextOffset].jumpFallthrough = true;
   207             // Treat the fallthrough of a branch instruction as a jump target.
   208             if (jump)
   209                 infos_[nextOffset].jumpTarget = true;
   210             else
   211                 infos_[nextOffset].fallthrough = true;
   212         }
   213     }
   215     return true;
   216 }

mercurial