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.

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

mercurial