Sat, 03 Jan 2015 20:18:00 +0100
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/LIR.h"
9 #include <ctype.h>
11 #include "jsprf.h"
13 #include "jit/IonSpewer.h"
14 #include "jit/MIR.h"
15 #include "jit/MIRGenerator.h"
17 using namespace js;
18 using namespace js::jit;
20 LIRGraph::LIRGraph(MIRGraph *mir)
21 : blocks_(mir->alloc()),
22 constantPool_(mir->alloc()),
23 constantPoolMap_(mir->alloc()),
24 safepoints_(mir->alloc()),
25 nonCallSafepoints_(mir->alloc()),
26 numVirtualRegisters_(0),
27 numInstructions_(1), // First id is 1.
28 localSlotCount_(0),
29 argumentSlotCount_(0),
30 entrySnapshot_(nullptr),
31 osrBlock_(nullptr),
32 mir_(*mir)
33 {
34 }
36 bool
37 LIRGraph::addConstantToPool(const Value &v, uint32_t *index)
38 {
39 JS_ASSERT(constantPoolMap_.initialized());
41 ConstantPoolMap::AddPtr p = constantPoolMap_.lookupForAdd(v);
42 if (p) {
43 *index = p->value();
44 return true;
45 }
46 *index = constantPool_.length();
47 return constantPool_.append(v) && constantPoolMap_.add(p, v, *index);
48 }
50 bool
51 LIRGraph::noteNeedsSafepoint(LInstruction *ins)
52 {
53 // Instructions with safepoints must be in linear order.
54 JS_ASSERT_IF(!safepoints_.empty(), safepoints_.back()->id() < ins->id());
55 if (!ins->isCall() && !nonCallSafepoints_.append(ins))
56 return false;
57 return safepoints_.append(ins);
58 }
60 void
61 LIRGraph::removeBlock(size_t i)
62 {
63 blocks_.erase(blocks_.begin() + i);
64 }
66 uint32_t
67 LBlock::firstId()
68 {
69 if (phis_.length()) {
70 return phis_[0]->id();
71 } else {
72 for (LInstructionIterator i(instructions_.begin()); i != instructions_.end(); i++) {
73 if (i->id())
74 return i->id();
75 }
76 }
77 return 0;
78 }
79 uint32_t
80 LBlock::lastId()
81 {
82 LInstruction *last = *instructions_.rbegin();
83 JS_ASSERT(last->id());
84 // The last instruction is a control flow instruction which does not have
85 // any output.
86 JS_ASSERT(last->numDefs() == 0);
87 return last->id();
88 }
90 LMoveGroup *
91 LBlock::getEntryMoveGroup(TempAllocator &alloc)
92 {
93 if (entryMoveGroup_)
94 return entryMoveGroup_;
95 entryMoveGroup_ = LMoveGroup::New(alloc);
96 if (begin()->isLabel())
97 insertAfter(*begin(), entryMoveGroup_);
98 else
99 insertBefore(*begin(), entryMoveGroup_);
100 return entryMoveGroup_;
101 }
103 LMoveGroup *
104 LBlock::getExitMoveGroup(TempAllocator &alloc)
105 {
106 if (exitMoveGroup_)
107 return exitMoveGroup_;
108 exitMoveGroup_ = LMoveGroup::New(alloc);
109 insertBefore(*rbegin(), exitMoveGroup_);
110 return exitMoveGroup_;
111 }
113 static size_t
114 TotalOperandCount(MResumePoint *mir)
115 {
116 size_t accum = mir->numOperands();
117 while ((mir = mir->caller()))
118 accum += mir->numOperands();
119 return accum;
120 }
122 LRecoverInfo::LRecoverInfo(TempAllocator &alloc)
123 : instructions_(alloc),
124 recoverOffset_(INVALID_RECOVER_OFFSET)
125 { }
127 LRecoverInfo *
128 LRecoverInfo::New(MIRGenerator *gen, MResumePoint *mir)
129 {
130 LRecoverInfo *recoverInfo = new(gen->alloc()) LRecoverInfo(gen->alloc());
131 if (!recoverInfo || !recoverInfo->init(mir))
132 return nullptr;
134 IonSpew(IonSpew_Snapshots, "Generating LIR recover info %p from MIR (%p)",
135 (void *)recoverInfo, (void *)mir);
137 return recoverInfo;
138 }
140 bool
141 LRecoverInfo::init(MResumePoint *rp)
142 {
143 MResumePoint *it = rp;
145 // Sort operations in the order in which we need to restore the stack. This
146 // implies that outer frames, as well as operations needed to recover the
147 // current frame, are located before the current frame. The inner-most
148 // resume point should be the last element in the list.
149 do {
150 if (!instructions_.append(it))
151 return false;
152 it = it->caller();
153 } while (it);
155 Reverse(instructions_.begin(), instructions_.end());
156 MOZ_ASSERT(mir() == rp);
157 return true;
158 }
160 LSnapshot::LSnapshot(LRecoverInfo *recoverInfo, BailoutKind kind)
161 : numSlots_(TotalOperandCount(recoverInfo->mir()) * BOX_PIECES),
162 slots_(nullptr),
163 recoverInfo_(recoverInfo),
164 snapshotOffset_(INVALID_SNAPSHOT_OFFSET),
165 bailoutId_(INVALID_BAILOUT_ID),
166 bailoutKind_(kind)
167 { }
169 bool
170 LSnapshot::init(MIRGenerator *gen)
171 {
172 slots_ = gen->allocate<LAllocation>(numSlots_);
173 return !!slots_;
174 }
176 LSnapshot *
177 LSnapshot::New(MIRGenerator *gen, LRecoverInfo *recover, BailoutKind kind)
178 {
179 LSnapshot *snapshot = new(gen->alloc()) LSnapshot(recover, kind);
180 if (!snapshot || !snapshot->init(gen))
181 return nullptr;
183 IonSpew(IonSpew_Snapshots, "Generating LIR snapshot %p from recover (%p)",
184 (void *)snapshot, (void *)recover);
186 return snapshot;
187 }
189 void
190 LSnapshot::rewriteRecoveredInput(LUse input)
191 {
192 // Mark any operands to this snapshot with the same value as input as being
193 // equal to the instruction's result.
194 for (size_t i = 0; i < numEntries(); i++) {
195 if (getEntry(i)->isUse() && getEntry(i)->toUse()->virtualRegister() == input.virtualRegister())
196 setEntry(i, LUse(input.virtualRegister(), LUse::RECOVERED_INPUT));
197 }
198 }
200 LPhi *
201 LPhi::New(MIRGenerator *gen, MPhi *ins)
202 {
203 LPhi *phi = new (gen->alloc()) LPhi();
204 LAllocation *inputs = gen->allocate<LAllocation>(ins->numOperands());
205 if (!inputs)
206 return nullptr;
208 phi->inputs_ = inputs;
209 phi->setMir(ins);
210 return phi;
211 }
213 void
214 LInstruction::printName(FILE *fp, Opcode op)
215 {
216 static const char * const names[] =
217 {
218 #define LIROP(x) #x,
219 LIR_OPCODE_LIST(LIROP)
220 #undef LIROP
221 };
222 const char *name = names[op];
223 size_t len = strlen(name);
224 for (size_t i = 0; i < len; i++)
225 fprintf(fp, "%c", tolower(name[i]));
226 }
228 void
229 LInstruction::printName(FILE *fp)
230 {
231 printName(fp, op());
232 }
234 static const char * const TypeChars[] =
235 {
236 "g", // GENERAL
237 "i", // INT32
238 "o", // OBJECT
239 "s", // SLOTS
240 "f", // FLOAT32
241 "d", // DOUBLE
242 #ifdef JS_NUNBOX32
243 "t", // TYPE
244 "p" // PAYLOAD
245 #elif JS_PUNBOX64
246 "x" // BOX
247 #endif
248 };
250 static void
251 PrintDefinition(FILE *fp, const LDefinition &def)
252 {
253 fprintf(fp, "[%s", TypeChars[def.type()]);
254 if (def.virtualRegister())
255 fprintf(fp, ":%d", def.virtualRegister());
256 if (def.policy() == LDefinition::PRESET) {
257 fprintf(fp, " (%s)", def.output()->toString());
258 } else if (def.policy() == LDefinition::MUST_REUSE_INPUT) {
259 fprintf(fp, " (!)");
260 } else if (def.policy() == LDefinition::PASSTHROUGH) {
261 fprintf(fp, " (-)");
262 }
263 fprintf(fp, "]");
264 }
266 #ifdef DEBUG
267 static void
268 PrintUse(char *buf, size_t size, const LUse *use)
269 {
270 switch (use->policy()) {
271 case LUse::REGISTER:
272 JS_snprintf(buf, size, "v%d:r", use->virtualRegister());
273 break;
274 case LUse::FIXED:
275 // Unfortunately, we don't know here whether the virtual register is a
276 // float or a double. Should we steal a bit in LUse for help? For now,
277 // nothing defines any fixed xmm registers.
278 JS_snprintf(buf, size, "v%d:%s", use->virtualRegister(),
279 Registers::GetName(Registers::Code(use->registerCode())));
280 break;
281 case LUse::ANY:
282 JS_snprintf(buf, size, "v%d:r?", use->virtualRegister());
283 break;
284 case LUse::KEEPALIVE:
285 JS_snprintf(buf, size, "v%d:*", use->virtualRegister());
286 break;
287 case LUse::RECOVERED_INPUT:
288 JS_snprintf(buf, size, "v%d:**", use->virtualRegister());
289 break;
290 default:
291 MOZ_ASSUME_UNREACHABLE("invalid use policy");
292 }
293 }
295 const char *
296 LAllocation::toString() const
297 {
298 // Not reentrant!
299 static char buf[40];
301 switch (kind()) {
302 case LAllocation::CONSTANT_VALUE:
303 case LAllocation::CONSTANT_INDEX:
304 return "c";
305 case LAllocation::GPR:
306 JS_snprintf(buf, sizeof(buf), "=%s", toGeneralReg()->reg().name());
307 return buf;
308 case LAllocation::FPU:
309 JS_snprintf(buf, sizeof(buf), "=%s", toFloatReg()->reg().name());
310 return buf;
311 case LAllocation::STACK_SLOT:
312 JS_snprintf(buf, sizeof(buf), "stack:%d", toStackSlot()->slot());
313 return buf;
314 case LAllocation::ARGUMENT_SLOT:
315 JS_snprintf(buf, sizeof(buf), "arg:%d", toArgument()->index());
316 return buf;
317 case LAllocation::USE:
318 PrintUse(buf, sizeof(buf), toUse());
319 return buf;
320 default:
321 MOZ_ASSUME_UNREACHABLE("what?");
322 }
323 }
324 #endif // DEBUG
326 void
327 LAllocation::dump() const
328 {
329 fprintf(stderr, "%s\n", toString());
330 }
332 void
333 LInstruction::printOperands(FILE *fp)
334 {
335 for (size_t i = 0, e = numOperands(); i < e; i++) {
336 fprintf(fp, " (%s)", getOperand(i)->toString());
337 if (i != numOperands() - 1)
338 fprintf(fp, ",");
339 }
340 }
342 void
343 LInstruction::assignSnapshot(LSnapshot *snapshot)
344 {
345 JS_ASSERT(!snapshot_);
346 snapshot_ = snapshot;
348 #ifdef DEBUG
349 if (IonSpewEnabled(IonSpew_Snapshots)) {
350 IonSpewHeader(IonSpew_Snapshots);
351 fprintf(IonSpewFile, "Assigning snapshot %p to instruction %p (",
352 (void *)snapshot, (void *)this);
353 printName(IonSpewFile);
354 fprintf(IonSpewFile, ")\n");
355 }
356 #endif
357 }
359 void
360 LInstruction::dump(FILE *fp)
361 {
362 fprintf(fp, "{");
363 for (size_t i = 0; i < numDefs(); i++) {
364 PrintDefinition(fp, *getDef(i));
365 if (i != numDefs() - 1)
366 fprintf(fp, ", ");
367 }
368 fprintf(fp, "} <- ");
370 printName(fp);
373 printInfo(fp);
375 if (numTemps()) {
376 fprintf(fp, " t=(");
377 for (size_t i = 0; i < numTemps(); i++) {
378 PrintDefinition(fp, *getTemp(i));
379 if (i != numTemps() - 1)
380 fprintf(fp, ", ");
381 }
382 fprintf(fp, ")");
383 }
384 fprintf(fp, "\n");
385 }
387 void
388 LInstruction::dump()
389 {
390 return dump(stderr);
391 }
393 void
394 LInstruction::initSafepoint(TempAllocator &alloc)
395 {
396 JS_ASSERT(!safepoint_);
397 safepoint_ = new(alloc) LSafepoint(alloc);
398 JS_ASSERT(safepoint_);
399 }
401 bool
402 LMoveGroup::add(LAllocation *from, LAllocation *to, LDefinition::Type type)
403 {
404 #ifdef DEBUG
405 JS_ASSERT(*from != *to);
406 for (size_t i = 0; i < moves_.length(); i++)
407 JS_ASSERT(*to != *moves_[i].to());
408 #endif
409 return moves_.append(LMove(from, to, type));
410 }
412 bool
413 LMoveGroup::addAfter(LAllocation *from, LAllocation *to, LDefinition::Type type)
414 {
415 // Transform the operands to this move so that performing the result
416 // simultaneously with existing moves in the group will have the same
417 // effect as if the original move took place after the existing moves.
419 for (size_t i = 0; i < moves_.length(); i++) {
420 if (*moves_[i].to() == *from) {
421 from = moves_[i].from();
422 break;
423 }
424 }
426 if (*from == *to)
427 return true;
429 for (size_t i = 0; i < moves_.length(); i++) {
430 if (*to == *moves_[i].to()) {
431 moves_[i] = LMove(from, to, type);
432 return true;
433 }
434 }
436 return add(from, to, type);
437 }
439 void
440 LMoveGroup::printOperands(FILE *fp)
441 {
442 for (size_t i = 0; i < numMoves(); i++) {
443 const LMove &move = getMove(i);
444 // Use two printfs, as LAllocation::toString is not reentrant.
445 fprintf(fp, "[%s", move.from()->toString());
446 fprintf(fp, " -> %s]", move.to()->toString());
447 if (i != numMoves() - 1)
448 fprintf(fp, ", ");
449 }
450 }