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/Recover.h"
8 :
9 : #include "mozilla/SizePrintfMacros.h"
10 :
11 : #include "jsapi.h"
12 : #include "jscntxt.h"
13 : #include "jsiter.h"
14 : #include "jsmath.h"
15 : #include "jsobj.h"
16 : #include "jsstr.h"
17 :
18 : #include "builtin/RegExp.h"
19 : #include "builtin/SIMD.h"
20 : #include "builtin/TypedObject.h"
21 :
22 : #include "gc/Heap.h"
23 :
24 : #include "jit/JitFrameIterator.h"
25 : #include "jit/JitSpewer.h"
26 : #include "jit/MIR.h"
27 : #include "jit/MIRGraph.h"
28 : #include "jit/VMFunctions.h"
29 : #include "vm/Interpreter.h"
30 : #include "vm/String.h"
31 :
32 : #include "vm/Interpreter-inl.h"
33 : #include "vm/NativeObject-inl.h"
34 :
35 : using namespace js;
36 : using namespace js::jit;
37 :
38 : bool
39 0 : MNode::writeRecoverData(CompactBufferWriter& writer) const
40 : {
41 0 : MOZ_CRASH("This instruction is not serializable");
42 : }
43 :
44 : void
45 840 : RInstruction::readRecoverData(CompactBufferReader& reader, RInstructionStorage* raw)
46 : {
47 840 : uint32_t op = reader.readUnsigned();
48 840 : switch (Opcode(op)) {
49 : # define MATCH_OPCODES_(op) \
50 : case Recover_##op: \
51 : static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \
52 : "storage space must be big enough to store R" #op); \
53 : static_assert(alignof(R##op) <= alignof(RInstructionStorage), \
54 : "storage space must be aligned adequate to store R" #op); \
55 : new (raw->addr()) R##op(reader); \
56 : break;
57 :
58 840 : RECOVER_OPCODE_LIST(MATCH_OPCODES_)
59 : # undef MATCH_OPCODES_
60 :
61 : case Recover_Invalid:
62 : default:
63 0 : MOZ_CRASH("Bad decoding of the previous instruction?");
64 : }
65 840 : }
66 :
67 : bool
68 210 : MResumePoint::writeRecoverData(CompactBufferWriter& writer) const
69 : {
70 210 : writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint));
71 :
72 210 : MBasicBlock* bb = block();
73 210 : JSFunction* fun = bb->info().funMaybeLazy();
74 210 : JSScript* script = bb->info().script();
75 210 : uint32_t exprStack = stackDepth() - bb->info().ninvoke();
76 :
77 : #ifdef DEBUG
78 : // Ensure that all snapshot which are encoded can safely be used for
79 : // bailouts.
80 210 : if (GetJitContext()->cx) {
81 : uint32_t stackDepth;
82 : bool reachablePC;
83 0 : jsbytecode* bailPC = pc();
84 :
85 0 : if (mode() == MResumePoint::ResumeAfter)
86 0 : bailPC = GetNextPc(pc());
87 :
88 0 : if (!ReconstructStackDepth(GetJitContext()->cx, script,
89 : bailPC, &stackDepth, &reachablePC))
90 : {
91 0 : return false;
92 : }
93 :
94 0 : if (reachablePC) {
95 0 : if (JSOp(*bailPC) == JSOP_FUNCALL) {
96 : // For fun.call(this, ...); the reconstructStackDepth will
97 : // include the this. When inlining that is not included. So the
98 : // exprStackSlots will be one less.
99 0 : MOZ_ASSERT(stackDepth - exprStack <= 1);
100 0 : } else if (JSOp(*bailPC) != JSOP_FUNAPPLY &&
101 0 : !IsGetPropPC(bailPC) && !IsSetPropPC(bailPC))
102 : {
103 : // For fun.apply({}, arguments) the reconstructStackDepth will
104 : // have stackdepth 4, but it could be that we inlined the
105 : // funapply. In that case exprStackSlots, will have the real
106 : // arguments in the slots and not be 4.
107 :
108 : // With accessors, we have different stack depths depending on
109 : // whether or not we inlined the accessor, as the inlined stack
110 : // contains a callee function that should never have been there
111 : // and we might just be capturing an uneventful property site,
112 : // in which case there won't have been any violence.
113 0 : MOZ_ASSERT(exprStack == stackDepth);
114 : }
115 : }
116 : }
117 : #endif
118 :
119 : // Test if we honor the maximum of arguments at all times. This is a sanity
120 : // check and not an algorithm limit. So check might be a bit too loose. +4
121 : // to account for scope chain, return value, this value and maybe
122 : // arguments_object.
123 210 : MOZ_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4);
124 :
125 : #ifdef JS_JITSPEW
126 210 : uint32_t implicit = StartArgSlot(script);
127 : #endif
128 210 : uint32_t formalArgs = CountArgSlots(script, fun);
129 210 : uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
130 :
131 210 : JitSpew(JitSpew_IonSnapshots, "Starting frame; implicit %u, formals %u, fixed %" PRIuSIZE ", exprs %u",
132 210 : implicit, formalArgs - implicit, script->nfixed(), exprStack);
133 :
134 210 : uint32_t pcoff = script->pcToOffset(pc());
135 210 : JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs);
136 210 : writer.writeUnsigned(pcoff);
137 210 : writer.writeUnsigned(nallocs);
138 210 : return true;
139 : }
140 :
141 840 : RResumePoint::RResumePoint(CompactBufferReader& reader)
142 : {
143 840 : pcOffset_ = reader.readUnsigned();
144 840 : numOperands_ = reader.readUnsigned();
145 840 : JitSpew(JitSpew_IonSnapshots, "Read RResumePoint (pc offset %u, nslots %u)",
146 840 : pcOffset_, numOperands_);
147 840 : }
148 :
149 : bool
150 0 : RResumePoint::recover(JSContext* cx, SnapshotIterator& iter) const
151 : {
152 0 : MOZ_CRASH("This instruction is not recoverable.");
153 : }
154 :
155 : bool
156 0 : MBitNot::writeRecoverData(CompactBufferWriter& writer) const
157 : {
158 0 : MOZ_ASSERT(canRecoverOnBailout());
159 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_BitNot));
160 0 : return true;
161 : }
162 :
163 0 : RBitNot::RBitNot(CompactBufferReader& reader)
164 0 : { }
165 :
166 : bool
167 0 : RBitNot::recover(JSContext* cx, SnapshotIterator& iter) const
168 : {
169 0 : RootedValue operand(cx, iter.read());
170 :
171 : int32_t result;
172 0 : if (!js::BitNot(cx, operand, &result))
173 0 : return false;
174 :
175 0 : RootedValue rootedResult(cx, js::Int32Value(result));
176 0 : iter.storeInstructionResult(rootedResult);
177 0 : return true;
178 : }
179 :
180 : bool
181 0 : MBitAnd::writeRecoverData(CompactBufferWriter& writer) const
182 : {
183 0 : MOZ_ASSERT(canRecoverOnBailout());
184 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd));
185 0 : return true;
186 : }
187 :
188 0 : RBitAnd::RBitAnd(CompactBufferReader& reader)
189 0 : { }
190 :
191 : bool
192 0 : RBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const
193 : {
194 0 : RootedValue lhs(cx, iter.read());
195 0 : RootedValue rhs(cx, iter.read());
196 : int32_t result;
197 0 : MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
198 :
199 0 : if (!js::BitAnd(cx, lhs, rhs, &result))
200 0 : return false;
201 :
202 0 : RootedValue rootedResult(cx, js::Int32Value(result));
203 0 : iter.storeInstructionResult(rootedResult);
204 0 : return true;
205 : }
206 :
207 : bool
208 0 : MBitOr::writeRecoverData(CompactBufferWriter& writer) const
209 : {
210 0 : MOZ_ASSERT(canRecoverOnBailout());
211 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_BitOr));
212 0 : return true;
213 : }
214 :
215 0 : RBitOr::RBitOr(CompactBufferReader& reader)
216 0 : {}
217 :
218 : bool
219 0 : RBitOr::recover(JSContext* cx, SnapshotIterator& iter) const
220 : {
221 0 : RootedValue lhs(cx, iter.read());
222 0 : RootedValue rhs(cx, iter.read());
223 : int32_t result;
224 0 : MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
225 :
226 0 : if (!js::BitOr(cx, lhs, rhs, &result))
227 0 : return false;
228 :
229 0 : RootedValue asValue(cx, js::Int32Value(result));
230 0 : iter.storeInstructionResult(asValue);
231 0 : return true;
232 : }
233 :
234 : bool
235 0 : MBitXor::writeRecoverData(CompactBufferWriter& writer) const
236 : {
237 0 : MOZ_ASSERT(canRecoverOnBailout());
238 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_BitXor));
239 0 : return true;
240 : }
241 :
242 0 : RBitXor::RBitXor(CompactBufferReader& reader)
243 0 : { }
244 :
245 : bool
246 0 : RBitXor::recover(JSContext* cx, SnapshotIterator& iter) const
247 : {
248 0 : RootedValue lhs(cx, iter.read());
249 0 : RootedValue rhs(cx, iter.read());
250 :
251 : int32_t result;
252 0 : if (!js::BitXor(cx, lhs, rhs, &result))
253 0 : return false;
254 :
255 0 : RootedValue rootedResult(cx, js::Int32Value(result));
256 0 : iter.storeInstructionResult(rootedResult);
257 0 : return true;
258 : }
259 :
260 : bool
261 0 : MLsh::writeRecoverData(CompactBufferWriter& writer) const
262 : {
263 0 : MOZ_ASSERT(canRecoverOnBailout());
264 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Lsh));
265 0 : return true;
266 : }
267 :
268 0 : RLsh::RLsh(CompactBufferReader& reader)
269 0 : {}
270 :
271 : bool
272 0 : RLsh::recover(JSContext* cx, SnapshotIterator& iter) const
273 : {
274 0 : RootedValue lhs(cx, iter.read());
275 0 : RootedValue rhs(cx, iter.read());
276 : int32_t result;
277 0 : MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
278 :
279 0 : if (!js::BitLsh(cx, lhs, rhs, &result))
280 0 : return false;
281 :
282 0 : RootedValue asValue(cx, js::Int32Value(result));
283 0 : iter.storeInstructionResult(asValue);
284 0 : return true;
285 : }
286 :
287 : bool
288 0 : MRsh::writeRecoverData(CompactBufferWriter& writer) const
289 : {
290 0 : MOZ_ASSERT(canRecoverOnBailout());
291 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Rsh));
292 0 : return true;
293 : }
294 :
295 0 : RRsh::RRsh(CompactBufferReader& reader)
296 0 : { }
297 :
298 : bool
299 0 : RRsh::recover(JSContext* cx, SnapshotIterator& iter) const
300 : {
301 0 : RootedValue lhs(cx, iter.read());
302 0 : RootedValue rhs(cx, iter.read());
303 0 : MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
304 :
305 : int32_t result;
306 0 : if (!js::BitRsh(cx, lhs, rhs, &result))
307 0 : return false;
308 :
309 0 : RootedValue rootedResult(cx, js::Int32Value(result));
310 0 : iter.storeInstructionResult(rootedResult);
311 0 : return true;
312 : }
313 :
314 : bool
315 0 : MUrsh::writeRecoverData(CompactBufferWriter& writer) const
316 : {
317 0 : MOZ_ASSERT(canRecoverOnBailout());
318 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Ursh));
319 0 : return true;
320 : }
321 :
322 0 : RUrsh::RUrsh(CompactBufferReader& reader)
323 0 : { }
324 :
325 : bool
326 0 : RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const
327 : {
328 0 : RootedValue lhs(cx, iter.read());
329 0 : RootedValue rhs(cx, iter.read());
330 0 : MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
331 :
332 0 : RootedValue result(cx);
333 0 : if (!js::UrshOperation(cx, lhs, rhs, &result))
334 0 : return false;
335 :
336 0 : iter.storeInstructionResult(result);
337 0 : return true;
338 : }
339 :
340 : bool
341 0 : MSignExtend::writeRecoverData(CompactBufferWriter& writer) const
342 : {
343 0 : MOZ_ASSERT(canRecoverOnBailout());
344 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtend));
345 0 : MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
346 0 : writer.writeByte(uint8_t(mode_));
347 0 : return true;
348 : }
349 :
350 0 : RSignExtend::RSignExtend(CompactBufferReader& reader)
351 : {
352 0 : mode_ = reader.readByte();
353 0 : }
354 :
355 : bool
356 0 : RSignExtend::recover(JSContext* cx, SnapshotIterator& iter) const
357 : {
358 0 : RootedValue operand(cx, iter.read());
359 :
360 : int32_t result;
361 0 : switch (MSignExtend::Mode(mode_)) {
362 : case MSignExtend::Byte:
363 0 : if (!js::SignExtendOperation<int8_t>(cx, operand, &result))
364 0 : return false;
365 0 : break;
366 : case MSignExtend::Half:
367 0 : if (!js::SignExtendOperation<int16_t>(cx, operand, &result))
368 0 : return false;
369 0 : break;
370 : }
371 :
372 0 : RootedValue rootedResult(cx, js::Int32Value(result));
373 0 : iter.storeInstructionResult(rootedResult);
374 0 : return true;
375 : }
376 :
377 : bool
378 0 : MAdd::writeRecoverData(CompactBufferWriter& writer) const
379 : {
380 0 : MOZ_ASSERT(canRecoverOnBailout());
381 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Add));
382 0 : writer.writeByte(specialization_ == MIRType::Float32);
383 0 : return true;
384 : }
385 :
386 0 : RAdd::RAdd(CompactBufferReader& reader)
387 : {
388 0 : isFloatOperation_ = reader.readByte();
389 0 : }
390 :
391 : bool
392 0 : RAdd::recover(JSContext* cx, SnapshotIterator& iter) const
393 : {
394 0 : RootedValue lhs(cx, iter.read());
395 0 : RootedValue rhs(cx, iter.read());
396 0 : RootedValue result(cx);
397 :
398 0 : MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
399 0 : if (!js::AddValues(cx, &lhs, &rhs, &result))
400 0 : return false;
401 :
402 : // MIRType::Float32 is a specialization embedding the fact that the result is
403 : // rounded to a Float32.
404 0 : if (isFloatOperation_ && !RoundFloat32(cx, result, &result))
405 0 : return false;
406 :
407 0 : iter.storeInstructionResult(result);
408 0 : return true;
409 : }
410 :
411 : bool
412 0 : MSub::writeRecoverData(CompactBufferWriter& writer) const
413 : {
414 0 : MOZ_ASSERT(canRecoverOnBailout());
415 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub));
416 0 : writer.writeByte(specialization_ == MIRType::Float32);
417 0 : return true;
418 : }
419 :
420 0 : RSub::RSub(CompactBufferReader& reader)
421 : {
422 0 : isFloatOperation_ = reader.readByte();
423 0 : }
424 :
425 : bool
426 0 : RSub::recover(JSContext* cx, SnapshotIterator& iter) const
427 : {
428 0 : RootedValue lhs(cx, iter.read());
429 0 : RootedValue rhs(cx, iter.read());
430 0 : RootedValue result(cx);
431 :
432 0 : MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
433 0 : if (!js::SubValues(cx, &lhs, &rhs, &result))
434 0 : return false;
435 :
436 : // MIRType::Float32 is a specialization embedding the fact that the result is
437 : // rounded to a Float32.
438 0 : if (isFloatOperation_ && !RoundFloat32(cx, result, &result))
439 0 : return false;
440 :
441 0 : iter.storeInstructionResult(result);
442 0 : return true;
443 : }
444 :
445 : bool
446 0 : MMul::writeRecoverData(CompactBufferWriter& writer) const
447 : {
448 0 : MOZ_ASSERT(canRecoverOnBailout());
449 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul));
450 0 : writer.writeByte(specialization_ == MIRType::Float32);
451 0 : MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
452 0 : writer.writeByte(uint8_t(mode_));
453 0 : return true;
454 : }
455 :
456 0 : RMul::RMul(CompactBufferReader& reader)
457 : {
458 0 : isFloatOperation_ = reader.readByte();
459 0 : mode_ = reader.readByte();
460 0 : }
461 :
462 : bool
463 0 : RMul::recover(JSContext* cx, SnapshotIterator& iter) const
464 : {
465 0 : RootedValue lhs(cx, iter.read());
466 0 : RootedValue rhs(cx, iter.read());
467 0 : RootedValue result(cx);
468 :
469 0 : if (MMul::Mode(mode_) == MMul::Normal) {
470 0 : if (!js::MulValues(cx, &lhs, &rhs, &result))
471 0 : return false;
472 :
473 : // MIRType::Float32 is a specialization embedding the fact that the
474 : // result is rounded to a Float32.
475 0 : if (isFloatOperation_ && !RoundFloat32(cx, result, &result))
476 0 : return false;
477 : } else {
478 0 : MOZ_ASSERT(MMul::Mode(mode_) == MMul::Integer);
479 0 : if (!js::math_imul_handle(cx, lhs, rhs, &result))
480 0 : return false;
481 : }
482 :
483 0 : iter.storeInstructionResult(result);
484 0 : return true;
485 : }
486 :
487 : bool
488 0 : MDiv::writeRecoverData(CompactBufferWriter& writer) const
489 : {
490 0 : MOZ_ASSERT(canRecoverOnBailout());
491 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Div));
492 0 : writer.writeByte(specialization_ == MIRType::Float32);
493 0 : return true;
494 : }
495 :
496 0 : RDiv::RDiv(CompactBufferReader& reader)
497 : {
498 0 : isFloatOperation_ = reader.readByte();
499 0 : }
500 :
501 : bool
502 0 : RDiv::recover(JSContext* cx, SnapshotIterator& iter) const
503 : {
504 0 : RootedValue lhs(cx, iter.read());
505 0 : RootedValue rhs(cx, iter.read());
506 0 : RootedValue result(cx);
507 :
508 0 : if (!js::DivValues(cx, &lhs, &rhs, &result))
509 0 : return false;
510 :
511 : // MIRType::Float32 is a specialization embedding the fact that the result is
512 : // rounded to a Float32.
513 0 : if (isFloatOperation_ && !RoundFloat32(cx, result, &result))
514 0 : return false;
515 :
516 0 : iter.storeInstructionResult(result);
517 0 : return true;
518 : }
519 :
520 : bool
521 0 : MMod::writeRecoverData(CompactBufferWriter& writer) const
522 : {
523 0 : MOZ_ASSERT(canRecoverOnBailout());
524 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Mod));
525 0 : return true;
526 : }
527 :
528 0 : RMod::RMod(CompactBufferReader& reader)
529 0 : { }
530 :
531 : bool
532 0 : RMod::recover(JSContext* cx, SnapshotIterator& iter) const
533 : {
534 0 : RootedValue lhs(cx, iter.read());
535 0 : RootedValue rhs(cx, iter.read());
536 0 : RootedValue result(cx);
537 :
538 0 : MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
539 0 : if (!js::ModValues(cx, &lhs, &rhs, &result))
540 0 : return false;
541 :
542 0 : iter.storeInstructionResult(result);
543 0 : return true;
544 : }
545 :
546 : bool
547 0 : MNot::writeRecoverData(CompactBufferWriter& writer) const
548 : {
549 0 : MOZ_ASSERT(canRecoverOnBailout());
550 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Not));
551 0 : return true;
552 : }
553 :
554 0 : RNot::RNot(CompactBufferReader& reader)
555 0 : { }
556 :
557 : bool
558 0 : RNot::recover(JSContext* cx, SnapshotIterator& iter) const
559 : {
560 0 : RootedValue v(cx, iter.read());
561 0 : RootedValue result(cx);
562 :
563 0 : result.setBoolean(!ToBoolean(v));
564 :
565 0 : iter.storeInstructionResult(result);
566 0 : return true;
567 : }
568 :
569 : bool
570 0 : MConcat::writeRecoverData(CompactBufferWriter& writer) const
571 : {
572 0 : MOZ_ASSERT(canRecoverOnBailout());
573 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Concat));
574 0 : return true;
575 : }
576 :
577 0 : RConcat::RConcat(CompactBufferReader& reader)
578 0 : {}
579 :
580 : bool
581 0 : RConcat::recover(JSContext* cx, SnapshotIterator& iter) const
582 : {
583 0 : RootedValue lhs(cx, iter.read());
584 0 : RootedValue rhs(cx, iter.read());
585 0 : RootedValue result(cx);
586 :
587 0 : MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
588 0 : if (!js::AddValues(cx, &lhs, &rhs, &result))
589 0 : return false;
590 :
591 0 : iter.storeInstructionResult(result);
592 0 : return true;
593 : }
594 :
595 0 : RStringLength::RStringLength(CompactBufferReader& reader)
596 0 : {}
597 :
598 : bool
599 0 : RStringLength::recover(JSContext* cx, SnapshotIterator& iter) const
600 : {
601 0 : RootedValue operand(cx, iter.read());
602 0 : RootedValue result(cx);
603 :
604 0 : MOZ_ASSERT(!operand.isObject());
605 0 : if (!js::GetLengthProperty(operand, &result))
606 0 : return false;
607 :
608 0 : iter.storeInstructionResult(result);
609 0 : return true;
610 : }
611 :
612 : bool
613 0 : MStringLength::writeRecoverData(CompactBufferWriter& writer) const
614 : {
615 0 : MOZ_ASSERT(canRecoverOnBailout());
616 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_StringLength));
617 0 : return true;
618 : }
619 :
620 : bool
621 0 : MArgumentsLength::writeRecoverData(CompactBufferWriter& writer) const
622 : {
623 0 : MOZ_ASSERT(canRecoverOnBailout());
624 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength));
625 0 : return true;
626 : }
627 :
628 0 : RArgumentsLength::RArgumentsLength(CompactBufferReader& reader)
629 0 : { }
630 :
631 : bool
632 0 : RArgumentsLength::recover(JSContext* cx, SnapshotIterator& iter) const
633 : {
634 0 : RootedValue result(cx);
635 :
636 0 : result.setInt32(iter.readOuterNumActualArgs());
637 :
638 0 : iter.storeInstructionResult(result);
639 0 : return true;
640 : }
641 :
642 : bool
643 0 : MFloor::writeRecoverData(CompactBufferWriter& writer) const
644 : {
645 0 : MOZ_ASSERT(canRecoverOnBailout());
646 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
647 0 : return true;
648 : }
649 :
650 0 : RFloor::RFloor(CompactBufferReader& reader)
651 0 : { }
652 :
653 0 : bool RFloor::recover(JSContext* cx, SnapshotIterator& iter) const
654 : {
655 0 : RootedValue v(cx, iter.read());
656 0 : RootedValue result(cx);
657 :
658 0 : if (!js::math_floor_handle(cx, v, &result))
659 0 : return false;
660 :
661 0 : iter.storeInstructionResult(result);
662 0 : return true;
663 : }
664 :
665 : bool
666 0 : MCeil::writeRecoverData(CompactBufferWriter& writer) const
667 : {
668 0 : MOZ_ASSERT(canRecoverOnBailout());
669 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
670 0 : return true;
671 : }
672 :
673 0 : RCeil::RCeil(CompactBufferReader& reader)
674 0 : { }
675 :
676 :
677 : bool
678 0 : RCeil::recover(JSContext* cx, SnapshotIterator& iter) const
679 : {
680 0 : RootedValue v(cx, iter.read());
681 0 : RootedValue result(cx);
682 :
683 0 : if (!js::math_ceil_handle(cx, v, &result))
684 0 : return false;
685 :
686 0 : iter.storeInstructionResult(result);
687 0 : return true;
688 : }
689 :
690 : bool
691 0 : MRound::writeRecoverData(CompactBufferWriter& writer) const
692 : {
693 0 : MOZ_ASSERT(canRecoverOnBailout());
694 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
695 0 : return true;
696 : }
697 :
698 0 : RRound::RRound(CompactBufferReader& reader)
699 0 : {}
700 :
701 : bool
702 0 : RRound::recover(JSContext* cx, SnapshotIterator& iter) const
703 : {
704 0 : RootedValue arg(cx, iter.read());
705 0 : RootedValue result(cx);
706 :
707 0 : MOZ_ASSERT(!arg.isObject());
708 0 : if(!js::math_round_handle(cx, arg, &result))
709 0 : return false;
710 :
711 0 : iter.storeInstructionResult(result);
712 0 : return true;
713 : }
714 :
715 : bool
716 0 : MCharCodeAt::writeRecoverData(CompactBufferWriter& writer) const
717 : {
718 0 : MOZ_ASSERT(canRecoverOnBailout());
719 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt));
720 0 : return true;
721 : }
722 :
723 0 : RCharCodeAt::RCharCodeAt(CompactBufferReader& reader)
724 0 : {}
725 :
726 : bool
727 0 : RCharCodeAt::recover(JSContext* cx, SnapshotIterator& iter) const
728 : {
729 0 : RootedString lhs(cx, iter.read().toString());
730 0 : RootedValue rhs(cx, iter.read());
731 0 : RootedValue result(cx);
732 :
733 0 : if (!js::str_charCodeAt_impl(cx, lhs, rhs, &result))
734 0 : return false;
735 :
736 0 : iter.storeInstructionResult(result);
737 0 : return true;
738 : }
739 :
740 : bool
741 0 : MFromCharCode::writeRecoverData(CompactBufferWriter& writer) const
742 : {
743 0 : MOZ_ASSERT(canRecoverOnBailout());
744 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode));
745 0 : return true;
746 : }
747 :
748 0 : RFromCharCode::RFromCharCode(CompactBufferReader& reader)
749 0 : {}
750 :
751 : bool
752 0 : RFromCharCode::recover(JSContext* cx, SnapshotIterator& iter) const
753 : {
754 0 : RootedValue operand(cx, iter.read());
755 0 : RootedValue result(cx);
756 :
757 0 : MOZ_ASSERT(!operand.isObject());
758 0 : if (!js::str_fromCharCode_one_arg(cx, operand, &result))
759 0 : return false;
760 :
761 0 : iter.storeInstructionResult(result);
762 0 : return true;
763 : }
764 :
765 : bool
766 0 : MPow::writeRecoverData(CompactBufferWriter& writer) const
767 : {
768 0 : MOZ_ASSERT(canRecoverOnBailout());
769 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Pow));
770 0 : return true;
771 : }
772 :
773 0 : RPow::RPow(CompactBufferReader& reader)
774 0 : { }
775 :
776 : bool
777 0 : RPow::recover(JSContext* cx, SnapshotIterator& iter) const
778 : {
779 0 : RootedValue base(cx, iter.read());
780 0 : RootedValue power(cx, iter.read());
781 0 : RootedValue result(cx);
782 :
783 0 : MOZ_ASSERT(base.isNumber() && power.isNumber());
784 0 : if (!js::math_pow_handle(cx, base, power, &result))
785 0 : return false;
786 :
787 0 : iter.storeInstructionResult(result);
788 0 : return true;
789 : }
790 :
791 : bool
792 0 : MPowHalf::writeRecoverData(CompactBufferWriter& writer) const
793 : {
794 0 : MOZ_ASSERT(canRecoverOnBailout());
795 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf));
796 0 : return true;
797 : }
798 :
799 0 : RPowHalf::RPowHalf(CompactBufferReader& reader)
800 0 : { }
801 :
802 : bool
803 0 : RPowHalf::recover(JSContext* cx, SnapshotIterator& iter) const
804 : {
805 0 : RootedValue base(cx, iter.read());
806 0 : RootedValue power(cx);
807 0 : RootedValue result(cx);
808 0 : power.setNumber(0.5);
809 :
810 0 : MOZ_ASSERT(base.isNumber());
811 0 : if (!js::math_pow_handle(cx, base, power, &result))
812 0 : return false;
813 :
814 0 : iter.storeInstructionResult(result);
815 0 : return true;
816 : }
817 :
818 : bool
819 0 : MMinMax::writeRecoverData(CompactBufferWriter& writer) const
820 : {
821 0 : MOZ_ASSERT(canRecoverOnBailout());
822 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_MinMax));
823 0 : writer.writeByte(isMax_);
824 0 : return true;
825 : }
826 :
827 0 : RMinMax::RMinMax(CompactBufferReader& reader)
828 : {
829 0 : isMax_ = reader.readByte();
830 0 : }
831 :
832 : bool
833 0 : RMinMax::recover(JSContext* cx, SnapshotIterator& iter) const
834 : {
835 0 : RootedValue a(cx, iter.read());
836 0 : RootedValue b(cx, iter.read());
837 0 : RootedValue result(cx);
838 :
839 0 : if (!js::minmax_impl(cx, isMax_, a, b, &result))
840 0 : return false;
841 :
842 0 : iter.storeInstructionResult(result);
843 0 : return true;
844 : }
845 :
846 : bool
847 0 : MAbs::writeRecoverData(CompactBufferWriter& writer) const
848 : {
849 0 : MOZ_ASSERT(canRecoverOnBailout());
850 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Abs));
851 0 : return true;
852 : }
853 :
854 0 : RAbs::RAbs(CompactBufferReader& reader)
855 0 : { }
856 :
857 : bool
858 0 : RAbs::recover(JSContext* cx, SnapshotIterator& iter) const
859 : {
860 0 : RootedValue v(cx, iter.read());
861 0 : RootedValue result(cx);
862 :
863 0 : if (!js::math_abs_handle(cx, v, &result))
864 0 : return false;
865 :
866 0 : iter.storeInstructionResult(result);
867 0 : return true;
868 : }
869 :
870 : bool
871 0 : MSqrt::writeRecoverData(CompactBufferWriter& writer) const
872 : {
873 0 : MOZ_ASSERT(canRecoverOnBailout());
874 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt));
875 0 : writer.writeByte(type() == MIRType::Float32);
876 0 : return true;
877 : }
878 :
879 0 : RSqrt::RSqrt(CompactBufferReader& reader)
880 : {
881 0 : isFloatOperation_ = reader.readByte();
882 0 : }
883 :
884 : bool
885 0 : RSqrt::recover(JSContext* cx, SnapshotIterator& iter) const
886 : {
887 0 : RootedValue num(cx, iter.read());
888 0 : RootedValue result(cx);
889 :
890 0 : MOZ_ASSERT(num.isNumber());
891 0 : if (!math_sqrt_handle(cx, num, &result))
892 0 : return false;
893 :
894 : // MIRType::Float32 is a specialization embedding the fact that the result is
895 : // rounded to a Float32.
896 0 : if (isFloatOperation_ && !RoundFloat32(cx, result, &result))
897 0 : return false;
898 :
899 0 : iter.storeInstructionResult(result);
900 0 : return true;
901 : }
902 :
903 : bool
904 0 : MAtan2::writeRecoverData(CompactBufferWriter& writer) const
905 : {
906 0 : MOZ_ASSERT(canRecoverOnBailout());
907 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Atan2));
908 0 : return true;
909 : }
910 :
911 0 : RAtan2::RAtan2(CompactBufferReader& reader)
912 0 : { }
913 :
914 : bool
915 0 : RAtan2::recover(JSContext* cx, SnapshotIterator& iter) const
916 : {
917 0 : RootedValue y(cx, iter.read());
918 0 : RootedValue x(cx, iter.read());
919 0 : RootedValue result(cx);
920 :
921 0 : if(!math_atan2_handle(cx, y, x, &result))
922 0 : return false;
923 :
924 0 : iter.storeInstructionResult(result);
925 0 : return true;
926 : }
927 :
928 : bool
929 0 : MHypot::writeRecoverData(CompactBufferWriter& writer) const
930 : {
931 0 : MOZ_ASSERT(canRecoverOnBailout());
932 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot));
933 0 : writer.writeUnsigned(uint32_t(numOperands()));
934 0 : return true;
935 : }
936 :
937 0 : RHypot::RHypot(CompactBufferReader& reader)
938 0 : : numOperands_(reader.readUnsigned())
939 0 : { }
940 :
941 : bool
942 0 : RHypot::recover(JSContext* cx, SnapshotIterator& iter) const
943 : {
944 0 : JS::AutoValueVector vec(cx);
945 :
946 0 : if (!vec.reserve(numOperands_))
947 0 : return false;
948 :
949 0 : for (uint32_t i = 0 ; i < numOperands_ ; ++i)
950 0 : vec.infallibleAppend(iter.read());
951 :
952 0 : RootedValue result(cx);
953 :
954 0 : if(!js::math_hypot_handle(cx, vec, &result))
955 0 : return false;
956 :
957 0 : iter.storeInstructionResult(result);
958 0 : return true;
959 : }
960 :
961 : bool
962 0 : MMathFunction::writeRecoverData(CompactBufferWriter& writer) const
963 : {
964 0 : MOZ_ASSERT(canRecoverOnBailout());
965 0 : switch (function_) {
966 : case Round:
967 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
968 0 : return true;
969 : case Sin:
970 : case Log:
971 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction));
972 0 : writer.writeByte(function_);
973 0 : return true;
974 : default:
975 0 : MOZ_CRASH("Unknown math function.");
976 : }
977 : }
978 :
979 0 : RMathFunction::RMathFunction(CompactBufferReader& reader)
980 : {
981 0 : function_ = reader.readByte();
982 0 : }
983 :
984 : bool
985 0 : RMathFunction::recover(JSContext* cx, SnapshotIterator& iter) const
986 : {
987 0 : switch (function_) {
988 : case MMathFunction::Sin: {
989 0 : RootedValue arg(cx, iter.read());
990 0 : RootedValue result(cx);
991 :
992 0 : if (!js::math_sin_handle(cx, arg, &result))
993 0 : return false;
994 :
995 0 : iter.storeInstructionResult(result);
996 0 : return true;
997 : }
998 : case MMathFunction::Log: {
999 0 : RootedValue arg(cx, iter.read());
1000 0 : RootedValue result(cx);
1001 :
1002 0 : if (!js::math_log_handle(cx, arg, &result))
1003 0 : return false;
1004 :
1005 0 : iter.storeInstructionResult(result);
1006 0 : return true;
1007 : }
1008 : default:
1009 0 : MOZ_CRASH("Unknown math function.");
1010 : }
1011 : }
1012 :
1013 : bool
1014 0 : MRandom::writeRecoverData(CompactBufferWriter& writer) const
1015 : {
1016 0 : MOZ_ASSERT(this->canRecoverOnBailout());
1017 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Random));
1018 0 : return true;
1019 : }
1020 :
1021 0 : RRandom::RRandom(CompactBufferReader& reader)
1022 0 : {}
1023 :
1024 : bool
1025 0 : RRandom::recover(JSContext* cx, SnapshotIterator& iter) const
1026 : {
1027 0 : iter.storeInstructionResult(DoubleValue(math_random_impl(cx)));
1028 0 : return true;
1029 : }
1030 :
1031 : bool
1032 0 : MStringSplit::writeRecoverData(CompactBufferWriter& writer) const
1033 : {
1034 0 : MOZ_ASSERT(canRecoverOnBailout());
1035 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit));
1036 0 : return true;
1037 : }
1038 :
1039 0 : RStringSplit::RStringSplit(CompactBufferReader& reader)
1040 0 : {}
1041 :
1042 : bool
1043 0 : RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const
1044 : {
1045 0 : RootedString str(cx, iter.read().toString());
1046 0 : RootedString sep(cx, iter.read().toString());
1047 0 : RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx));
1048 0 : if (!group) {
1049 0 : return false;
1050 : }
1051 0 : RootedValue result(cx);
1052 :
1053 0 : JSObject* res = str_split_string(cx, group, str, sep, INT32_MAX);
1054 0 : if (!res)
1055 0 : return false;
1056 :
1057 0 : result.setObject(*res);
1058 0 : iter.storeInstructionResult(result);
1059 0 : return true;
1060 : }
1061 :
1062 : bool
1063 0 : MNaNToZero::writeRecoverData(CompactBufferWriter& writer) const
1064 : {
1065 0 : MOZ_ASSERT(canRecoverOnBailout());
1066 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero));
1067 0 : return true;
1068 : }
1069 :
1070 0 : RNaNToZero::RNaNToZero(CompactBufferReader& reader)
1071 0 : { }
1072 :
1073 :
1074 : bool
1075 0 : RNaNToZero::recover(JSContext* cx, SnapshotIterator& iter) const
1076 : {
1077 0 : RootedValue v(cx, iter.read());
1078 0 : RootedValue result(cx);
1079 0 : MOZ_ASSERT(v.isDouble() || v.isInt32());
1080 :
1081 : // x ? x : 0.0
1082 0 : if (ToBoolean(v))
1083 0 : result = v;
1084 : else
1085 0 : result.setDouble(0.0);
1086 :
1087 0 : iter.storeInstructionResult(result);
1088 0 : return true;
1089 : }
1090 :
1091 : bool
1092 0 : MRegExpMatcher::writeRecoverData(CompactBufferWriter& writer) const
1093 : {
1094 0 : MOZ_ASSERT(canRecoverOnBailout());
1095 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpMatcher));
1096 0 : return true;
1097 : }
1098 :
1099 0 : RRegExpMatcher::RRegExpMatcher(CompactBufferReader& reader)
1100 0 : {}
1101 :
1102 : bool
1103 0 : RRegExpMatcher::recover(JSContext* cx, SnapshotIterator& iter) const
1104 : {
1105 0 : RootedObject regexp(cx, &iter.read().toObject());
1106 0 : RootedString input(cx, iter.read().toString());
1107 0 : int32_t lastIndex = iter.read().toInt32();
1108 :
1109 0 : RootedValue result(cx);
1110 0 : if (!RegExpMatcherRaw(cx, regexp, input, lastIndex, nullptr, &result))
1111 0 : return false;
1112 :
1113 0 : iter.storeInstructionResult(result);
1114 0 : return true;
1115 : }
1116 :
1117 : bool
1118 0 : MRegExpSearcher::writeRecoverData(CompactBufferWriter& writer) const
1119 : {
1120 0 : MOZ_ASSERT(canRecoverOnBailout());
1121 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpSearcher));
1122 0 : return true;
1123 : }
1124 :
1125 0 : RRegExpSearcher::RRegExpSearcher(CompactBufferReader& reader)
1126 0 : {}
1127 :
1128 : bool
1129 0 : RRegExpSearcher::recover(JSContext* cx, SnapshotIterator& iter) const
1130 : {
1131 0 : RootedObject regexp(cx, &iter.read().toObject());
1132 0 : RootedString input(cx, iter.read().toString());
1133 0 : int32_t lastIndex = iter.read().toInt32();
1134 :
1135 : int32_t result;
1136 0 : if (!RegExpSearcherRaw(cx, regexp, input, lastIndex, nullptr, &result))
1137 0 : return false;
1138 :
1139 0 : RootedValue resultVal(cx);
1140 0 : resultVal.setInt32(result);
1141 0 : iter.storeInstructionResult(resultVal);
1142 0 : return true;
1143 : }
1144 :
1145 : bool
1146 0 : MRegExpTester::writeRecoverData(CompactBufferWriter& writer) const
1147 : {
1148 0 : MOZ_ASSERT(canRecoverOnBailout());
1149 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_RegExpTester));
1150 0 : return true;
1151 : }
1152 :
1153 0 : RRegExpTester::RRegExpTester(CompactBufferReader& reader)
1154 0 : { }
1155 :
1156 : bool
1157 0 : RRegExpTester::recover(JSContext* cx, SnapshotIterator& iter) const
1158 : {
1159 0 : RootedString string(cx, iter.read().toString());
1160 0 : RootedObject regexp(cx, &iter.read().toObject());
1161 0 : int32_t lastIndex = iter.read().toInt32();
1162 : int32_t endIndex;
1163 :
1164 0 : if (!js::RegExpTesterRaw(cx, regexp, string, lastIndex, &endIndex))
1165 0 : return false;
1166 :
1167 0 : RootedValue result(cx);
1168 0 : result.setInt32(endIndex);
1169 0 : iter.storeInstructionResult(result);
1170 0 : return true;
1171 : }
1172 :
1173 : bool
1174 0 : MTypeOf::writeRecoverData(CompactBufferWriter& writer) const
1175 : {
1176 0 : MOZ_ASSERT(canRecoverOnBailout());
1177 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf));
1178 0 : return true;
1179 : }
1180 :
1181 0 : RTypeOf::RTypeOf(CompactBufferReader& reader)
1182 0 : { }
1183 :
1184 : bool
1185 0 : RTypeOf::recover(JSContext* cx, SnapshotIterator& iter) const
1186 : {
1187 0 : RootedValue v(cx, iter.read());
1188 :
1189 0 : RootedValue result(cx, StringValue(TypeOfOperation(v, cx->runtime())));
1190 0 : iter.storeInstructionResult(result);
1191 0 : return true;
1192 : }
1193 :
1194 : bool
1195 0 : MToDouble::writeRecoverData(CompactBufferWriter& writer) const
1196 : {
1197 0 : MOZ_ASSERT(canRecoverOnBailout());
1198 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble));
1199 0 : return true;
1200 : }
1201 :
1202 0 : RToDouble::RToDouble(CompactBufferReader& reader)
1203 0 : { }
1204 :
1205 : bool
1206 0 : RToDouble::recover(JSContext* cx, SnapshotIterator& iter) const
1207 : {
1208 0 : RootedValue v(cx, iter.read());
1209 0 : RootedValue result(cx);
1210 :
1211 0 : MOZ_ASSERT(!v.isObject());
1212 0 : MOZ_ASSERT(!v.isSymbol());
1213 :
1214 : double dbl;
1215 0 : if (!ToNumber(cx, v, &dbl))
1216 0 : return false;
1217 :
1218 0 : result.setDouble(dbl);
1219 0 : iter.storeInstructionResult(result);
1220 0 : return true;
1221 : }
1222 :
1223 : bool
1224 0 : MToFloat32::writeRecoverData(CompactBufferWriter& writer) const
1225 : {
1226 0 : MOZ_ASSERT(canRecoverOnBailout());
1227 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32));
1228 0 : return true;
1229 : }
1230 :
1231 0 : RToFloat32::RToFloat32(CompactBufferReader& reader)
1232 0 : { }
1233 :
1234 : bool
1235 0 : RToFloat32::recover(JSContext* cx, SnapshotIterator& iter) const
1236 : {
1237 0 : RootedValue v(cx, iter.read());
1238 0 : RootedValue result(cx);
1239 :
1240 0 : MOZ_ASSERT(!v.isObject());
1241 0 : if (!RoundFloat32(cx, v, &result))
1242 0 : return false;
1243 :
1244 0 : iter.storeInstructionResult(result);
1245 0 : return true;
1246 : }
1247 :
1248 : bool
1249 0 : MTruncateToInt32::writeRecoverData(CompactBufferWriter& writer) const
1250 : {
1251 0 : MOZ_ASSERT(canRecoverOnBailout());
1252 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32));
1253 0 : return true;
1254 : }
1255 :
1256 0 : RTruncateToInt32::RTruncateToInt32(CompactBufferReader& reader)
1257 0 : { }
1258 :
1259 : bool
1260 0 : RTruncateToInt32::recover(JSContext* cx, SnapshotIterator& iter) const
1261 : {
1262 0 : RootedValue value(cx, iter.read());
1263 0 : RootedValue result(cx);
1264 :
1265 : int32_t trunc;
1266 0 : if (!JS::ToInt32(cx, value, &trunc))
1267 0 : return false;
1268 :
1269 0 : result.setInt32(trunc);
1270 0 : iter.storeInstructionResult(result);
1271 0 : return true;
1272 : }
1273 :
1274 : bool
1275 53 : MNewObject::writeRecoverData(CompactBufferWriter& writer) const
1276 : {
1277 53 : MOZ_ASSERT(canRecoverOnBailout());
1278 53 : writer.writeUnsigned(uint32_t(RInstruction::Recover_NewObject));
1279 53 : MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
1280 53 : writer.writeByte(uint8_t(mode_));
1281 53 : return true;
1282 : }
1283 :
1284 0 : RNewObject::RNewObject(CompactBufferReader& reader)
1285 : {
1286 0 : mode_ = MNewObject::Mode(reader.readByte());
1287 0 : }
1288 :
1289 : bool
1290 0 : RNewObject::recover(JSContext* cx, SnapshotIterator& iter) const
1291 : {
1292 0 : RootedObject templateObject(cx, &iter.read().toObject());
1293 0 : RootedValue result(cx);
1294 0 : JSObject* resultObject = nullptr;
1295 :
1296 : // See CodeGenerator::visitNewObjectVMCall
1297 0 : switch (mode_) {
1298 : case MNewObject::ObjectLiteral:
1299 0 : resultObject = NewObjectOperationWithTemplate(cx, templateObject);
1300 0 : break;
1301 : case MNewObject::ObjectCreate:
1302 0 : resultObject = ObjectCreateWithTemplate(cx, templateObject.as<PlainObject>());
1303 0 : break;
1304 : }
1305 :
1306 0 : if (!resultObject)
1307 0 : return false;
1308 :
1309 0 : result.setObject(*resultObject);
1310 0 : iter.storeInstructionResult(result);
1311 0 : return true;
1312 : }
1313 :
1314 : bool
1315 0 : MNewTypedArray::writeRecoverData(CompactBufferWriter& writer) const
1316 : {
1317 0 : MOZ_ASSERT(canRecoverOnBailout());
1318 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray));
1319 0 : return true;
1320 : }
1321 :
1322 0 : RNewTypedArray::RNewTypedArray(CompactBufferReader& reader)
1323 : {
1324 0 : }
1325 :
1326 : bool
1327 0 : RNewTypedArray::recover(JSContext* cx, SnapshotIterator& iter) const
1328 : {
1329 0 : RootedObject templateObject(cx, &iter.read().toObject());
1330 0 : RootedValue result(cx);
1331 :
1332 0 : uint32_t length = templateObject.as<TypedArrayObject>()->length();
1333 0 : JSObject* resultObject = TypedArrayCreateWithTemplate(cx, templateObject, length);
1334 0 : if (!resultObject)
1335 0 : return false;
1336 :
1337 0 : result.setObject(*resultObject);
1338 0 : iter.storeInstructionResult(result);
1339 0 : return true;
1340 : }
1341 :
1342 : bool
1343 0 : MNewArray::writeRecoverData(CompactBufferWriter& writer) const
1344 : {
1345 0 : MOZ_ASSERT(canRecoverOnBailout());
1346 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray));
1347 0 : writer.writeUnsigned(length());
1348 0 : return true;
1349 : }
1350 :
1351 0 : RNewArray::RNewArray(CompactBufferReader& reader)
1352 : {
1353 0 : count_ = reader.readUnsigned();
1354 0 : }
1355 :
1356 : bool
1357 0 : RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const
1358 : {
1359 0 : RootedObject templateObject(cx, &iter.read().toObject());
1360 0 : RootedValue result(cx);
1361 0 : RootedObjectGroup group(cx, templateObject->group());
1362 :
1363 0 : JSObject* resultObject = NewFullyAllocatedArrayTryUseGroup(cx, group, count_);
1364 0 : if (!resultObject)
1365 0 : return false;
1366 :
1367 0 : result.setObject(*resultObject);
1368 0 : iter.storeInstructionResult(result);
1369 0 : return true;
1370 : }
1371 :
1372 : bool
1373 45 : MNewIterator::writeRecoverData(CompactBufferWriter& writer) const
1374 : {
1375 45 : MOZ_ASSERT(canRecoverOnBailout());
1376 45 : writer.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator));
1377 45 : writer.writeByte(type_);
1378 45 : return true;
1379 : }
1380 :
1381 0 : RNewIterator::RNewIterator(CompactBufferReader& reader)
1382 : {
1383 0 : type_ = reader.readByte();
1384 0 : }
1385 :
1386 : bool
1387 0 : RNewIterator::recover(JSContext* cx, SnapshotIterator& iter) const
1388 : {
1389 0 : RootedObject templateObject(cx, &iter.read().toObject());
1390 0 : RootedValue result(cx);
1391 :
1392 0 : JSObject* resultObject = nullptr;
1393 0 : switch (MNewIterator::Type(type_)) {
1394 : case MNewIterator::ArrayIterator:
1395 0 : resultObject = NewArrayIteratorObject(cx);
1396 0 : break;
1397 : case MNewIterator::StringIterator:
1398 0 : resultObject = NewStringIteratorObject(cx);
1399 0 : break;
1400 : }
1401 :
1402 0 : if (!resultObject)
1403 0 : return false;
1404 :
1405 0 : result.setObject(*resultObject);
1406 0 : iter.storeInstructionResult(result);
1407 0 : return true;
1408 : }
1409 :
1410 : bool
1411 0 : MNewDerivedTypedObject::writeRecoverData(CompactBufferWriter& writer) const
1412 : {
1413 0 : MOZ_ASSERT(canRecoverOnBailout());
1414 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_NewDerivedTypedObject));
1415 0 : return true;
1416 : }
1417 :
1418 0 : RNewDerivedTypedObject::RNewDerivedTypedObject(CompactBufferReader& reader)
1419 0 : { }
1420 :
1421 : bool
1422 0 : RNewDerivedTypedObject::recover(JSContext* cx, SnapshotIterator& iter) const
1423 : {
1424 0 : Rooted<TypeDescr*> descr(cx, &iter.read().toObject().as<TypeDescr>());
1425 0 : Rooted<TypedObject*> owner(cx, &iter.read().toObject().as<TypedObject>());
1426 0 : int32_t offset = iter.read().toInt32();
1427 :
1428 0 : JSObject* obj = OutlineTypedObject::createDerived(cx, descr, owner, offset);
1429 0 : if (!obj)
1430 0 : return false;
1431 :
1432 0 : RootedValue result(cx, ObjectValue(*obj));
1433 0 : iter.storeInstructionResult(result);
1434 0 : return true;
1435 : }
1436 :
1437 : bool
1438 0 : MCreateThisWithTemplate::writeRecoverData(CompactBufferWriter& writer) const
1439 : {
1440 0 : MOZ_ASSERT(canRecoverOnBailout());
1441 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_CreateThisWithTemplate));
1442 0 : return true;
1443 : }
1444 :
1445 0 : RCreateThisWithTemplate::RCreateThisWithTemplate(CompactBufferReader& reader)
1446 : {
1447 0 : }
1448 :
1449 : bool
1450 0 : RCreateThisWithTemplate::recover(JSContext* cx, SnapshotIterator& iter) const
1451 : {
1452 0 : RootedObject templateObject(cx, &iter.read().toObject());
1453 :
1454 : // See CodeGenerator::visitCreateThisWithTemplate
1455 0 : JSObject* resultObject = NewObjectOperationWithTemplate(cx, templateObject);
1456 0 : if (!resultObject)
1457 0 : return false;
1458 :
1459 0 : RootedValue result(cx);
1460 0 : result.setObject(*resultObject);
1461 0 : iter.storeInstructionResult(result);
1462 0 : return true;
1463 : }
1464 :
1465 : bool
1466 0 : MLambda::writeRecoverData(CompactBufferWriter& writer) const
1467 : {
1468 0 : MOZ_ASSERT(canRecoverOnBailout());
1469 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_Lambda));
1470 0 : return true;
1471 : }
1472 :
1473 0 : RLambda::RLambda(CompactBufferReader& reader)
1474 : {
1475 0 : }
1476 :
1477 : bool
1478 0 : RLambda::recover(JSContext* cx, SnapshotIterator& iter) const
1479 : {
1480 0 : RootedObject scopeChain(cx, &iter.read().toObject());
1481 0 : RootedFunction fun(cx, &iter.read().toObject().as<JSFunction>());
1482 :
1483 0 : JSObject* resultObject = js::Lambda(cx, fun, scopeChain);
1484 0 : if (!resultObject)
1485 0 : return false;
1486 :
1487 0 : RootedValue result(cx);
1488 0 : result.setObject(*resultObject);
1489 0 : iter.storeInstructionResult(result);
1490 0 : return true;
1491 : }
1492 :
1493 : bool
1494 0 : MLambdaArrow::writeRecoverData(CompactBufferWriter& writer) const
1495 : {
1496 0 : MOZ_ASSERT(canRecoverOnBailout());
1497 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_LambdaArrow));
1498 0 : return true;
1499 : }
1500 :
1501 0 : RLambdaArrow::RLambdaArrow(CompactBufferReader& reader)
1502 : {
1503 0 : }
1504 :
1505 : bool
1506 0 : RLambdaArrow::recover(JSContext* cx, SnapshotIterator& iter) const
1507 : {
1508 0 : RootedObject scopeChain(cx, &iter.read().toObject());
1509 0 : RootedValue newTarget(cx, iter.read());
1510 0 : RootedFunction fun(cx, &iter.read().toObject().as<JSFunction>());
1511 :
1512 0 : JSObject* resultObject = js::LambdaArrow(cx, fun, scopeChain, newTarget);
1513 0 : if (!resultObject)
1514 0 : return false;
1515 :
1516 0 : RootedValue result(cx);
1517 0 : result.setObject(*resultObject);
1518 0 : iter.storeInstructionResult(result);
1519 0 : return true;
1520 : }
1521 :
1522 : bool
1523 0 : MSimdBox::writeRecoverData(CompactBufferWriter& writer) const
1524 : {
1525 0 : MOZ_ASSERT(canRecoverOnBailout());
1526 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_SimdBox));
1527 : static_assert(unsigned(SimdType::Count) < 0x100, "assuming SimdType fits in 8 bits");
1528 0 : writer.writeByte(uint8_t(simdType()));
1529 0 : return true;
1530 : }
1531 :
1532 0 : RSimdBox::RSimdBox(CompactBufferReader& reader)
1533 : {
1534 0 : type_ = reader.readByte();
1535 0 : }
1536 :
1537 : bool
1538 0 : RSimdBox::recover(JSContext* cx, SnapshotIterator& iter) const
1539 : {
1540 0 : JSObject* resultObject = nullptr;
1541 0 : RValueAllocation a = iter.readAllocation();
1542 0 : MOZ_ASSERT(iter.allocationReadable(a));
1543 0 : MOZ_ASSERT_IF(a.mode() == RValueAllocation::ANY_FLOAT_REG, a.fpuReg().isSimd128());
1544 0 : const FloatRegisters::RegisterContent* raw = iter.floatAllocationPointer(a);
1545 0 : switch (SimdType(type_)) {
1546 : case SimdType::Bool8x16:
1547 0 : resultObject = js::CreateSimd<Bool8x16>(cx, (const Bool8x16::Elem*) raw);
1548 0 : break;
1549 : case SimdType::Int8x16:
1550 0 : resultObject = js::CreateSimd<Int8x16>(cx, (const Int8x16::Elem*) raw);
1551 0 : break;
1552 : case SimdType::Uint8x16:
1553 0 : resultObject = js::CreateSimd<Uint8x16>(cx, (const Uint8x16::Elem*) raw);
1554 0 : break;
1555 : case SimdType::Bool16x8:
1556 0 : resultObject = js::CreateSimd<Bool16x8>(cx, (const Bool16x8::Elem*) raw);
1557 0 : break;
1558 : case SimdType::Int16x8:
1559 0 : resultObject = js::CreateSimd<Int16x8>(cx, (const Int16x8::Elem*) raw);
1560 0 : break;
1561 : case SimdType::Uint16x8:
1562 0 : resultObject = js::CreateSimd<Uint16x8>(cx, (const Uint16x8::Elem*) raw);
1563 0 : break;
1564 : case SimdType::Bool32x4:
1565 0 : resultObject = js::CreateSimd<Bool32x4>(cx, (const Bool32x4::Elem*) raw);
1566 0 : break;
1567 : case SimdType::Int32x4:
1568 0 : resultObject = js::CreateSimd<Int32x4>(cx, (const Int32x4::Elem*) raw);
1569 0 : break;
1570 : case SimdType::Uint32x4:
1571 0 : resultObject = js::CreateSimd<Uint32x4>(cx, (const Uint32x4::Elem*) raw);
1572 0 : break;
1573 : case SimdType::Float32x4:
1574 0 : resultObject = js::CreateSimd<Float32x4>(cx, (const Float32x4::Elem*) raw);
1575 0 : break;
1576 : case SimdType::Float64x2:
1577 0 : MOZ_CRASH("NYI, RSimdBox of Float64x2");
1578 : break;
1579 : case SimdType::Bool64x2:
1580 0 : MOZ_CRASH("NYI, RSimdBox of Bool64x2");
1581 : break;
1582 : case SimdType::Count:
1583 0 : MOZ_CRASH("RSimdBox of Count is unreachable");
1584 : }
1585 :
1586 0 : if (!resultObject)
1587 0 : return false;
1588 :
1589 0 : RootedValue result(cx);
1590 0 : result.setObject(*resultObject);
1591 0 : iter.storeInstructionResult(result);
1592 0 : return true;
1593 : }
1594 :
1595 : bool
1596 98 : MObjectState::writeRecoverData(CompactBufferWriter& writer) const
1597 : {
1598 98 : MOZ_ASSERT(canRecoverOnBailout());
1599 98 : writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState));
1600 98 : writer.writeUnsigned(numSlots());
1601 98 : return true;
1602 : }
1603 :
1604 0 : RObjectState::RObjectState(CompactBufferReader& reader)
1605 : {
1606 0 : numSlots_ = reader.readUnsigned();
1607 0 : }
1608 :
1609 : bool
1610 0 : RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const
1611 : {
1612 0 : RootedObject object(cx, &iter.read().toObject());
1613 0 : RootedValue val(cx);
1614 :
1615 0 : if (object->is<UnboxedPlainObject>()) {
1616 0 : const UnboxedLayout& layout = object->as<UnboxedPlainObject>().layout();
1617 :
1618 0 : RootedId id(cx);
1619 0 : RootedValue receiver(cx, ObjectValue(*object));
1620 0 : const UnboxedLayout::PropertyVector& properties = layout.properties();
1621 0 : for (size_t i = 0; i < properties.length(); i++) {
1622 0 : val = iter.read();
1623 :
1624 : // This is the default placeholder value of MObjectState, when no
1625 : // properties are defined yet.
1626 0 : if (val.isUndefined())
1627 0 : continue;
1628 :
1629 0 : id = NameToId(properties[i].name);
1630 0 : ObjectOpResult result;
1631 :
1632 : // SetProperty can only fail due to OOM.
1633 0 : if (!SetProperty(cx, object, id, val, receiver, result))
1634 0 : return false;
1635 0 : if (!result)
1636 0 : return result.reportError(cx, object, id);
1637 : }
1638 : } else {
1639 0 : RootedNativeObject nativeObject(cx, &object->as<NativeObject>());
1640 0 : MOZ_ASSERT(nativeObject->slotSpan() == numSlots());
1641 :
1642 0 : for (size_t i = 0; i < numSlots(); i++) {
1643 0 : val = iter.read();
1644 0 : nativeObject->setSlot(i, val);
1645 : }
1646 : }
1647 :
1648 0 : val.setObject(*object);
1649 0 : iter.storeInstructionResult(val);
1650 0 : return true;
1651 : }
1652 :
1653 : bool
1654 0 : MArrayState::writeRecoverData(CompactBufferWriter& writer) const
1655 : {
1656 0 : MOZ_ASSERT(canRecoverOnBailout());
1657 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState));
1658 0 : writer.writeUnsigned(numElements());
1659 0 : return true;
1660 : }
1661 :
1662 0 : RArrayState::RArrayState(CompactBufferReader& reader)
1663 : {
1664 0 : numElements_ = reader.readUnsigned();
1665 0 : }
1666 :
1667 : bool
1668 0 : RArrayState::recover(JSContext* cx, SnapshotIterator& iter) const
1669 : {
1670 0 : RootedValue result(cx);
1671 0 : ArrayObject* object = &iter.read().toObject().as<ArrayObject>();
1672 0 : uint32_t initLength = iter.read().toInt32();
1673 :
1674 0 : object->setDenseInitializedLength(initLength);
1675 0 : for (size_t index = 0; index < numElements(); index++) {
1676 0 : Value val = iter.read();
1677 :
1678 0 : if (index >= initLength) {
1679 0 : MOZ_ASSERT(val.isUndefined());
1680 0 : continue;
1681 : }
1682 :
1683 0 : object->initDenseElement(index, val);
1684 : }
1685 :
1686 0 : result.setObject(*object);
1687 0 : iter.storeInstructionResult(result);
1688 0 : return true;
1689 : }
1690 :
1691 : bool
1692 0 : MAssertRecoveredOnBailout::writeRecoverData(CompactBufferWriter& writer) const
1693 : {
1694 0 : MOZ_ASSERT(canRecoverOnBailout());
1695 0 : MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_,
1696 : "assertRecoveredOnBailout failed during compilation");
1697 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_AssertRecoveredOnBailout));
1698 0 : return true;
1699 : }
1700 :
1701 0 : RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(CompactBufferReader& reader)
1702 0 : { }
1703 :
1704 0 : bool RAssertRecoveredOnBailout::recover(JSContext* cx, SnapshotIterator& iter) const
1705 : {
1706 0 : RootedValue result(cx);
1707 0 : iter.read(); // skip the unused operand.
1708 0 : result.setUndefined();
1709 0 : iter.storeInstructionResult(result);
1710 0 : return true;
1711 : }
1712 :
1713 : bool
1714 0 : MStringReplace::writeRecoverData(CompactBufferWriter& writer) const
1715 : {
1716 0 : MOZ_ASSERT(canRecoverOnBailout());
1717 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace));
1718 0 : writer.writeByte(isFlatReplacement_);
1719 0 : return true;
1720 : }
1721 :
1722 0 : RStringReplace::RStringReplace(CompactBufferReader& reader)
1723 : {
1724 0 : isFlatReplacement_ = reader.readByte();
1725 0 : }
1726 :
1727 0 : bool RStringReplace::recover(JSContext* cx, SnapshotIterator& iter) const
1728 : {
1729 0 : RootedString string(cx, iter.read().toString());
1730 0 : RootedString pattern(cx, iter.read().toString());
1731 0 : RootedString replace(cx, iter.read().toString());
1732 :
1733 0 : JSString* result = isFlatReplacement_ ? js::str_flat_replace_string(cx, string, pattern, replace) :
1734 0 : js::str_replace_string_raw(cx, string, pattern, replace);
1735 :
1736 0 : if (!result)
1737 0 : return false;
1738 :
1739 0 : iter.storeInstructionResult(StringValue(result));
1740 0 : return true;
1741 : }
1742 :
1743 : bool
1744 0 : MAtomicIsLockFree::writeRecoverData(CompactBufferWriter& writer) const
1745 : {
1746 0 : MOZ_ASSERT(canRecoverOnBailout());
1747 0 : writer.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree));
1748 0 : return true;
1749 : }
1750 :
1751 0 : RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader& reader)
1752 0 : { }
1753 :
1754 : bool
1755 0 : RAtomicIsLockFree::recover(JSContext* cx, SnapshotIterator& iter) const
1756 : {
1757 0 : RootedValue operand(cx, iter.read());
1758 0 : MOZ_ASSERT(operand.isInt32());
1759 :
1760 : int32_t result;
1761 0 : if (!js::AtomicIsLockFree(cx, operand, &result))
1762 0 : return false;
1763 :
1764 0 : RootedValue rootedResult(cx, js::Int32Value(result));
1765 0 : iter.storeInstructionResult(rootedResult);
1766 0 : return true;
1767 9 : }
|