]> git.saurik.com Git - apple/javascriptcore.git/blob - ftl/FTLLowerDFGToLLVM.cpp
JavaScriptCore-7600.1.4.13.1.tar.gz
[apple/javascriptcore.git] / ftl / FTLLowerDFGToLLVM.cpp
1 /*
2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "FTLLowerDFGToLLVM.h"
28
29 #if ENABLE(FTL_JIT)
30
31 #include "CodeBlockWithJITType.h"
32 #include "DFGAbstractInterpreterInlines.h"
33 #include "DFGInPlaceAbstractState.h"
34 #include "FTLAbstractHeapRepository.h"
35 #include "FTLAvailableRecovery.h"
36 #include "FTLForOSREntryJITCode.h"
37 #include "FTLFormattedValue.h"
38 #include "FTLInlineCacheSize.h"
39 #include "FTLLoweredNodeValue.h"
40 #include "FTLOutput.h"
41 #include "FTLThunks.h"
42 #include "FTLWeightedTarget.h"
43 #include "OperandsInlines.h"
44 #include "JSCInlines.h"
45 #include "VirtualRegister.h"
46 #include <atomic>
47 #include <wtf/ProcessID.h>
48
49 namespace JSC { namespace FTL {
50
51 using namespace DFG;
52
53 static std::atomic<int> compileCounter;
54
55 // Using this instead of typeCheck() helps to reduce the load on LLVM, by creating
56 // significantly less dead code.
57 #define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) do { \
58 FormattedValue _ftc_lowValue = (lowValue); \
59 Edge _ftc_highValue = (highValue); \
60 SpeculatedType _ftc_typesPassedThrough = (typesPassedThrough); \
61 if (!m_interpreter.needsTypeCheck(_ftc_highValue, _ftc_typesPassedThrough)) \
62 break; \
63 typeCheck(_ftc_lowValue, _ftc_highValue, _ftc_typesPassedThrough, (failCondition)); \
64 } while (false)
65
66 class LowerDFGToLLVM {
67 public:
68 LowerDFGToLLVM(State& state)
69 : m_graph(state.graph)
70 , m_ftlState(state)
71 , m_heaps(state.context)
72 , m_out(state.context)
73 , m_availability(OperandsLike, state.graph.block(0)->variablesAtHead)
74 , m_state(state.graph)
75 , m_interpreter(state.graph, m_state)
76 , m_stackmapIDs(0)
77 {
78 }
79
80 void lower()
81 {
82 CString name;
83 if (verboseCompilationEnabled()) {
84 name = toCString(
85 "jsBody_", ++compileCounter, "_", codeBlock()->inferredName(),
86 "_", codeBlock()->hash());
87 } else
88 name = "jsBody";
89
90 m_graph.m_dominators.computeIfNecessary(m_graph);
91
92 m_ftlState.module =
93 llvm->ModuleCreateWithNameInContext(name.data(), m_ftlState.context);
94
95 m_ftlState.function = addFunction(
96 m_ftlState.module, name.data(), functionType(m_out.int64));
97 setFunctionCallingConv(m_ftlState.function, LLVMCCallConv);
98 if (isX86() && Options::llvmDisallowAVX()) {
99 // AVX makes V8/raytrace 80% slower. It makes Kraken/audio-oscillator 4.5x
100 // slower. It should be disabled.
101 addTargetDependentFunctionAttr(m_ftlState.function, "target-features", "-avx");
102 }
103
104 if (verboseCompilationEnabled())
105 dataLog("Function ready, beginning lowering.\n");
106
107 m_out.initialize(m_ftlState.module, m_ftlState.function, m_heaps);
108
109 m_prologue = FTL_NEW_BLOCK(m_out, ("Prologue"));
110 LBasicBlock stackOverflow = FTL_NEW_BLOCK(m_out, ("Stack overflow"));
111 m_handleExceptions = FTL_NEW_BLOCK(m_out, ("Handle Exceptions"));
112
113 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
114 m_highBlock = m_graph.block(blockIndex);
115 if (!m_highBlock)
116 continue;
117 m_blocks.add(m_highBlock, FTL_NEW_BLOCK(m_out, ("Block ", *m_highBlock)));
118 }
119
120 m_out.appendTo(m_prologue, stackOverflow);
121 createPhiVariables();
122 LValue capturedAlloca = m_out.alloca(arrayType(m_out.int64, m_graph.m_nextMachineLocal));
123 m_captured = m_out.add(
124 m_out.ptrToInt(capturedAlloca, m_out.intPtr),
125 m_out.constIntPtr(m_graph.m_nextMachineLocal * sizeof(Register)));
126
127 // We should not create any alloca's after this point, since they will cease to
128 // be mem2reg candidates.
129
130 m_ftlState.capturedStackmapID = m_stackmapIDs++;
131 m_out.call(
132 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.capturedStackmapID),
133 m_out.int32Zero, capturedAlloca);
134
135 m_callFrame = m_out.ptrToInt(
136 m_out.call(m_out.frameAddressIntrinsic(), m_out.int32Zero), m_out.intPtr);
137 m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
138 m_tagMask = m_out.constInt64(TagMask);
139
140 m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock));
141
142 m_out.branch(
143 didOverflowStack(), rarely(stackOverflow), usually(lowBlock(m_graph.block(0))));
144
145 m_out.appendTo(stackOverflow, m_handleExceptions);
146 m_out.call(m_out.operation(operationThrowStackOverflowError), m_callFrame, m_out.constIntPtr(codeBlock()));
147 m_ftlState.handleStackOverflowExceptionStackmapID = m_stackmapIDs++;
148 m_out.call(
149 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleStackOverflowExceptionStackmapID),
150 m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
151 m_out.unreachable();
152
153 m_out.appendTo(m_handleExceptions, lowBlock(m_graph.block(0)));
154 m_ftlState.handleExceptionStackmapID = m_stackmapIDs++;
155 m_out.call(
156 m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleExceptionStackmapID),
157 m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
158 m_out.unreachable();
159
160 Vector<BasicBlock*> depthFirst;
161 m_graph.getBlocksInDepthFirstOrder(depthFirst);
162 for (unsigned i = 0; i < depthFirst.size(); ++i)
163 compileBlock(depthFirst[i]);
164
165 if (Options::dumpLLVMIR())
166 dumpModule(m_ftlState.module);
167
168 if (verboseCompilationEnabled())
169 m_ftlState.dumpState("after lowering");
170 if (validationEnabled())
171 verifyModule(m_ftlState.module);
172 }
173
174 private:
175
176 void createPhiVariables()
177 {
178 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
179 BasicBlock* block = m_graph.block(blockIndex);
180 if (!block)
181 continue;
182 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
183 Node* node = block->at(nodeIndex);
184 if (node->op() != Phi)
185 continue;
186 LType type;
187 switch (node->flags() & NodeResultMask) {
188 case NodeResultDouble:
189 type = m_out.doubleType;
190 break;
191 case NodeResultInt32:
192 type = m_out.int32;
193 break;
194 case NodeResultInt52:
195 type = m_out.int64;
196 break;
197 case NodeResultBoolean:
198 type = m_out.boolean;
199 break;
200 case NodeResultJS:
201 type = m_out.int64;
202 break;
203 default:
204 RELEASE_ASSERT_NOT_REACHED();
205 break;
206 }
207 m_phis.add(node, buildAlloca(m_out.m_builder, type));
208 }
209 }
210 }
211
212 void compileBlock(BasicBlock* block)
213 {
214 if (!block)
215 return;
216
217 if (verboseCompilationEnabled())
218 dataLog("Compiling block ", *block, "\n");
219
220 m_highBlock = block;
221
222 LBasicBlock lowBlock = m_blocks.get(m_highBlock);
223
224 m_nextHighBlock = 0;
225 for (BlockIndex nextBlockIndex = m_highBlock->index + 1; nextBlockIndex < m_graph.numBlocks(); ++nextBlockIndex) {
226 m_nextHighBlock = m_graph.block(nextBlockIndex);
227 if (m_nextHighBlock)
228 break;
229 }
230 m_nextLowBlock = m_nextHighBlock ? m_blocks.get(m_nextHighBlock) : 0;
231
232 // All of this effort to find the next block gives us the ability to keep the
233 // generated IR in roughly program order. This ought not affect the performance
234 // of the generated code (since we expect LLVM to reorder things) but it will
235 // make IR dumps easier to read.
236 m_out.appendTo(lowBlock, m_nextLowBlock);
237
238 if (Options::ftlCrashes())
239 m_out.crashNonTerminal();
240
241 if (!m_highBlock->cfaHasVisited) {
242 m_out.crash();
243 return;
244 }
245
246 initializeOSRExitStateForBlock();
247
248 m_state.reset();
249 m_state.beginBasicBlock(m_highBlock);
250
251 for (m_nodeIndex = 0; m_nodeIndex < m_highBlock->size(); ++m_nodeIndex) {
252 if (!compileNode(m_nodeIndex))
253 break;
254 }
255 }
256
257 bool compileNode(unsigned nodeIndex)
258 {
259 if (!m_state.isValid()) {
260 m_out.unreachable();
261 return false;
262 }
263
264 m_node = m_highBlock->at(nodeIndex);
265 m_codeOriginForExitProfile = m_node->origin.semantic;
266 m_codeOriginForExitTarget = m_node->origin.forExit;
267
268 if (verboseCompilationEnabled())
269 dataLog("Lowering ", m_node, "\n");
270
271 m_availableRecoveries.resize(0);
272
273 bool shouldExecuteEffects = m_interpreter.startExecuting(m_node);
274
275 switch (m_node->op()) {
276 case Upsilon:
277 compileUpsilon();
278 break;
279 case Phi:
280 compilePhi();
281 break;
282 case JSConstant:
283 break;
284 case DoubleConstant:
285 compileDoubleConstant();
286 break;
287 case Int52Constant:
288 compileInt52Constant();
289 break;
290 case WeakJSConstant:
291 compileWeakJSConstant();
292 break;
293 case PhantomArguments:
294 compilePhantomArguments();
295 break;
296 case DoubleRep:
297 compileDoubleRep();
298 break;
299 case ValueRep:
300 compileValueRep();
301 break;
302 case Int52Rep:
303 compileInt52Rep();
304 break;
305 case ValueToInt32:
306 compileValueToInt32();
307 break;
308 case BooleanToNumber:
309 compileBooleanToNumber();
310 break;
311 case GetArgument:
312 compileGetArgument();
313 break;
314 case ExtractOSREntryLocal:
315 compileExtractOSREntryLocal();
316 break;
317 case GetLocal:
318 compileGetLocal();
319 break;
320 case SetLocal:
321 compileSetLocal();
322 break;
323 case MovHint:
324 compileMovHint();
325 break;
326 case GetMyArgumentsLength:
327 compileGetMyArgumentsLength();
328 break;
329 case GetMyArgumentByVal:
330 compileGetMyArgumentByVal();
331 break;
332 case ZombieHint:
333 compileZombieHint();
334 break;
335 case Phantom:
336 case HardPhantom:
337 compilePhantom();
338 break;
339 case ToThis:
340 compileToThis();
341 break;
342 case ValueAdd:
343 compileValueAdd();
344 break;
345 case ArithAdd:
346 case ArithSub:
347 compileArithAddOrSub();
348 break;
349 case ArithMul:
350 compileArithMul();
351 break;
352 case ArithDiv:
353 compileArithDiv();
354 break;
355 case ArithMod:
356 compileArithMod();
357 break;
358 case ArithMin:
359 case ArithMax:
360 compileArithMinOrMax();
361 break;
362 case ArithAbs:
363 compileArithAbs();
364 break;
365 case ArithSin:
366 compileArithSin();
367 break;
368 case ArithCos:
369 compileArithCos();
370 break;
371 case ArithSqrt:
372 compileArithSqrt();
373 break;
374 case ArithFRound:
375 compileArithFRound();
376 break;
377 case ArithNegate:
378 compileArithNegate();
379 break;
380 case BitAnd:
381 compileBitAnd();
382 break;
383 case BitOr:
384 compileBitOr();
385 break;
386 case BitXor:
387 compileBitXor();
388 break;
389 case BitRShift:
390 compileBitRShift();
391 break;
392 case BitLShift:
393 compileBitLShift();
394 break;
395 case BitURShift:
396 compileBitURShift();
397 break;
398 case UInt32ToNumber:
399 compileUInt32ToNumber();
400 break;
401 case CheckStructure:
402 compileCheckStructure();
403 break;
404 case StructureTransitionWatchpoint:
405 compileStructureTransitionWatchpoint();
406 break;
407 case CheckFunction:
408 compileCheckFunction();
409 break;
410 case CheckExecutable:
411 compileCheckExecutable();
412 break;
413 case ArrayifyToStructure:
414 compileArrayifyToStructure();
415 break;
416 case PutStructure:
417 compilePutStructure();
418 break;
419 case PhantomPutStructure:
420 compilePhantomPutStructure();
421 break;
422 case GetById:
423 compileGetById();
424 break;
425 case PutByIdDirect:
426 case PutById:
427 compilePutById();
428 break;
429 case GetButterfly:
430 compileGetButterfly();
431 break;
432 case ConstantStoragePointer:
433 compileConstantStoragePointer();
434 break;
435 case GetIndexedPropertyStorage:
436 compileGetIndexedPropertyStorage();
437 break;
438 case CheckArray:
439 compileCheckArray();
440 break;
441 case GetArrayLength:
442 compileGetArrayLength();
443 break;
444 case CheckInBounds:
445 compileCheckInBounds();
446 break;
447 case GetByVal:
448 compileGetByVal();
449 break;
450 case PutByVal:
451 case PutByValAlias:
452 case PutByValDirect:
453 compilePutByVal();
454 break;
455 case ArrayPush:
456 compileArrayPush();
457 break;
458 case ArrayPop:
459 compileArrayPop();
460 break;
461 case NewObject:
462 compileNewObject();
463 break;
464 case NewArray:
465 compileNewArray();
466 break;
467 case NewArrayBuffer:
468 compileNewArrayBuffer();
469 break;
470 case NewArrayWithSize:
471 compileNewArrayWithSize();
472 break;
473 case GetTypedArrayByteOffset:
474 compileGetTypedArrayByteOffset();
475 break;
476 case AllocatePropertyStorage:
477 compileAllocatePropertyStorage();
478 break;
479 case ReallocatePropertyStorage:
480 compileReallocatePropertyStorage();
481 break;
482 case ToString:
483 compileToString();
484 break;
485 case ToPrimitive:
486 compileToPrimitive();
487 break;
488 case MakeRope:
489 compileMakeRope();
490 break;
491 case StringCharAt:
492 compileStringCharAt();
493 break;
494 case StringCharCodeAt:
495 compileStringCharCodeAt();
496 break;
497 case GetByOffset:
498 compileGetByOffset();
499 break;
500 case MultiGetByOffset:
501 compileMultiGetByOffset();
502 break;
503 case PutByOffset:
504 compilePutByOffset();
505 break;
506 case MultiPutByOffset:
507 compileMultiPutByOffset();
508 break;
509 case GetGlobalVar:
510 compileGetGlobalVar();
511 break;
512 case PutGlobalVar:
513 compilePutGlobalVar();
514 break;
515 case NotifyWrite:
516 compileNotifyWrite();
517 break;
518 case GetCallee:
519 compileGetCallee();
520 break;
521 case GetScope:
522 compileGetScope();
523 break;
524 case GetMyScope:
525 compileGetMyScope();
526 break;
527 case SkipScope:
528 compileSkipScope();
529 break;
530 case GetClosureRegisters:
531 compileGetClosureRegisters();
532 break;
533 case GetClosureVar:
534 compileGetClosureVar();
535 break;
536 case PutClosureVar:
537 compilePutClosureVar();
538 break;
539 case CompareEq:
540 compileCompareEq();
541 break;
542 case CompareEqConstant:
543 compileCompareEqConstant();
544 break;
545 case CompareStrictEq:
546 compileCompareStrictEq();
547 break;
548 case CompareLess:
549 compileCompareLess();
550 break;
551 case CompareLessEq:
552 compileCompareLessEq();
553 break;
554 case CompareGreater:
555 compileCompareGreater();
556 break;
557 case CompareGreaterEq:
558 compileCompareGreaterEq();
559 break;
560 case LogicalNot:
561 compileLogicalNot();
562 break;
563 case Call:
564 case Construct:
565 compileCallOrConstruct();
566 break;
567 case Jump:
568 compileJump();
569 break;
570 case Branch:
571 compileBranch();
572 break;
573 case Switch:
574 compileSwitch();
575 break;
576 case Return:
577 compileReturn();
578 break;
579 case ForceOSRExit:
580 compileForceOSRExit();
581 break;
582 case Throw:
583 case ThrowReferenceError:
584 compileThrow();
585 break;
586 case InvalidationPoint:
587 compileInvalidationPoint();
588 break;
589 case CheckArgumentsNotCreated:
590 compileCheckArgumentsNotCreated();
591 break;
592 case IsUndefined:
593 compileIsUndefined();
594 break;
595 case IsBoolean:
596 compileIsBoolean();
597 break;
598 case IsNumber:
599 compileIsNumber();
600 break;
601 case IsString:
602 compileIsString();
603 break;
604 case IsObject:
605 compileIsObject();
606 break;
607 case IsFunction:
608 compileIsFunction();
609 break;
610 case CheckHasInstance:
611 compileCheckHasInstance();
612 break;
613 case InstanceOf:
614 compileInstanceOf();
615 break;
616 case CountExecution:
617 compileCountExecution();
618 break;
619 case StoreBarrier:
620 compileStoreBarrier();
621 break;
622 case StoreBarrierWithNullCheck:
623 compileStoreBarrierWithNullCheck();
624 break;
625 case PhantomLocal:
626 case SetArgument:
627 case LoopHint:
628 case VariableWatchpoint:
629 case FunctionReentryWatchpoint:
630 case TypedArrayWatchpoint:
631 case AllocationProfileWatchpoint:
632 break;
633 default:
634 dataLog("Unrecognized node in FTL backend:\n");
635 m_graph.dump(WTF::dataFile(), " ", m_node);
636 dataLog("\n");
637 dataLog("Full graph dump:\n");
638 m_graph.dump();
639 RELEASE_ASSERT_NOT_REACHED();
640 break;
641 }
642
643 if (shouldExecuteEffects)
644 m_interpreter.executeEffects(nodeIndex);
645
646 return true;
647 }
648
649 void compileUpsilon()
650 {
651 LValue destination = m_phis.get(m_node->phi());
652
653 switch (m_node->child1().useKind()) {
654 case DoubleRepUse:
655 m_out.set(lowDouble(m_node->child1()), destination);
656 break;
657 case Int32Use:
658 m_out.set(lowInt32(m_node->child1()), destination);
659 break;
660 case Int52RepUse:
661 m_out.set(lowInt52(m_node->child1()), destination);
662 break;
663 case BooleanUse:
664 m_out.set(lowBoolean(m_node->child1()), destination);
665 break;
666 case CellUse:
667 m_out.set(lowCell(m_node->child1()), destination);
668 break;
669 case UntypedUse:
670 m_out.set(lowJSValue(m_node->child1()), destination);
671 break;
672 default:
673 RELEASE_ASSERT_NOT_REACHED();
674 break;
675 }
676 }
677
678 void compilePhi()
679 {
680 LValue source = m_phis.get(m_node);
681
682 switch (m_node->flags() & NodeResultMask) {
683 case NodeResultDouble:
684 setDouble(m_out.get(source));
685 break;
686 case NodeResultInt32:
687 setInt32(m_out.get(source));
688 break;
689 case NodeResultInt52:
690 setInt52(m_out.get(source));
691 break;
692 case NodeResultBoolean:
693 setBoolean(m_out.get(source));
694 break;
695 case NodeResultJS:
696 setJSValue(m_out.get(source));
697 break;
698 default:
699 RELEASE_ASSERT_NOT_REACHED();
700 break;
701 }
702 }
703
704 void compileDoubleConstant()
705 {
706 setDouble(m_out.constDouble(m_graph.valueOfNumberConstant(m_node)));
707 }
708
709 void compileInt52Constant()
710 {
711 int64_t value = m_graph.valueOfJSConstant(m_node).asMachineInt();
712
713 setInt52(m_out.constInt64(value << JSValue::int52ShiftAmount));
714 setStrictInt52(m_out.constInt64(value));
715 }
716
717 void compileWeakJSConstant()
718 {
719 setJSValue(weakPointer(m_node->weakConstant()));
720 }
721
722 void compilePhantomArguments()
723 {
724 setJSValue(m_out.constInt64(JSValue::encode(JSValue())));
725 }
726
727 void compileDoubleRep()
728 {
729 switch (m_node->child1().useKind()) {
730 case NumberUse: {
731 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
732 setDouble(jsValueToDouble(m_node->child1(), value));
733 return;
734 }
735
736 case Int52RepUse: {
737 setDouble(strictInt52ToDouble(lowStrictInt52(m_node->child1())));
738 return;
739 }
740
741 default:
742 RELEASE_ASSERT_NOT_REACHED();
743 }
744 }
745
746 void compileValueRep()
747 {
748 switch (m_node->child1().useKind()) {
749 case DoubleRepUse: {
750 LValue value = lowDouble(m_node->child1());
751
752 if (m_interpreter.needsTypeCheck(m_node->child1(), ~SpecDoubleImpureNaN)) {
753 value = m_out.select(
754 m_out.doubleEqual(value, value), value, m_out.constDouble(PNaN));
755 }
756
757 setJSValue(boxDouble(value));
758 return;
759 }
760
761 case Int52RepUse: {
762 setJSValue(strictInt52ToJSValue(lowStrictInt52(m_node->child1())));
763 return;
764 }
765
766 default:
767 RELEASE_ASSERT_NOT_REACHED();
768 }
769 }
770
771 void compileInt52Rep()
772 {
773 switch (m_node->child1().useKind()) {
774 case Int32Use:
775 setStrictInt52(m_out.signExt(lowInt32(m_node->child1()), m_out.int64));
776 return;
777
778 case MachineIntUse:
779 setStrictInt52(
780 jsValueToStrictInt52(
781 m_node->child1(), lowJSValue(m_node->child1(), ManualOperandSpeculation)));
782 return;
783
784 case DoubleRepMachineIntUse:
785 setStrictInt52(
786 doubleToStrictInt52(
787 m_node->child1(), lowDouble(m_node->child1())));
788 return;
789
790 default:
791 RELEASE_ASSERT_NOT_REACHED();
792 }
793 }
794
795 void compileValueToInt32()
796 {
797 switch (m_node->child1().useKind()) {
798 case Int52RepUse:
799 setInt32(m_out.castToInt32(lowStrictInt52(m_node->child1())));
800 break;
801
802 case DoubleRepUse:
803 setInt32(doubleToInt32(lowDouble(m_node->child1())));
804 break;
805
806 case NumberUse:
807 case NotCellUse: {
808 LoweredNodeValue value = m_int32Values.get(m_node->child1().node());
809 if (isValid(value)) {
810 setInt32(value.value());
811 break;
812 }
813
814 value = m_jsValueValues.get(m_node->child1().node());
815 if (isValid(value)) {
816 setInt32(numberOrNotCellToInt32(m_node->child1(), value.value()));
817 break;
818 }
819
820 // We'll basically just get here for constants. But it's good to have this
821 // catch-all since we often add new representations into the mix.
822 setInt32(
823 numberOrNotCellToInt32(
824 m_node->child1(),
825 lowJSValue(m_node->child1(), ManualOperandSpeculation)));
826 break;
827 }
828
829 default:
830 RELEASE_ASSERT_NOT_REACHED();
831 break;
832 }
833 }
834
835 void compileBooleanToNumber()
836 {
837 switch (m_node->child1().useKind()) {
838 case BooleanUse: {
839 setInt32(m_out.zeroExt(lowBoolean(m_node->child1()), m_out.int32));
840 return;
841 }
842
843 case UntypedUse: {
844 LValue value = lowJSValue(m_node->child1());
845
846 LBasicBlock booleanCase = FTL_NEW_BLOCK(m_out, ("BooleanToNumber boolean case"));
847 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("BooleanToNumber continuation"));
848
849 ValueFromBlock notBooleanResult = m_out.anchor(value);
850 m_out.branch(isBoolean(value), unsure(booleanCase), unsure(continuation));
851
852 LBasicBlock lastNext = m_out.appendTo(booleanCase, continuation);
853 ValueFromBlock booleanResult = m_out.anchor(m_out.bitOr(
854 m_out.zeroExt(unboxBoolean(value), m_out.int64), m_tagTypeNumber));
855 m_out.jump(continuation);
856
857 m_out.appendTo(continuation, lastNext);
858 setJSValue(m_out.phi(m_out.int64, booleanResult, notBooleanResult));
859 return;
860 }
861
862 default:
863 RELEASE_ASSERT_NOT_REACHED();
864 return;
865 }
866 }
867
868 void compileGetArgument()
869 {
870 VariableAccessData* variable = m_node->variableAccessData();
871 VirtualRegister operand = variable->machineLocal();
872 RELEASE_ASSERT(operand.isArgument());
873
874 LValue jsValue = m_out.load64(addressFor(operand));
875
876 switch (useKindFor(variable->flushFormat())) {
877 case Int32Use:
878 speculate(BadType, jsValueValue(jsValue), m_node, isNotInt32(jsValue));
879 setInt32(unboxInt32(jsValue));
880 break;
881 case CellUse:
882 speculate(BadType, jsValueValue(jsValue), m_node, isNotCell(jsValue));
883 setJSValue(jsValue);
884 break;
885 case BooleanUse:
886 speculate(BadType, jsValueValue(jsValue), m_node, isNotBoolean(jsValue));
887 setBoolean(unboxBoolean(jsValue));
888 break;
889 case UntypedUse:
890 setJSValue(jsValue);
891 break;
892 default:
893 RELEASE_ASSERT_NOT_REACHED();
894 break;
895 }
896 }
897
898 void compileExtractOSREntryLocal()
899 {
900 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(
901 m_ftlState.jitCode->ftlForOSREntry()->entryBuffer()->dataBuffer());
902 setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal())));
903 }
904
905 void compileGetLocal()
906 {
907 // GetLocals arise only for captured variables.
908
909 VariableAccessData* variable = m_node->variableAccessData();
910 AbstractValue& value = m_state.variables().operand(variable->local());
911
912 RELEASE_ASSERT(variable->isCaptured());
913
914 if (isInt32Speculation(value.m_type))
915 setInt32(m_out.load32(payloadFor(variable->machineLocal())));
916 else
917 setJSValue(m_out.load64(addressFor(variable->machineLocal())));
918 }
919
920 void compileSetLocal()
921 {
922 VariableAccessData* variable = m_node->variableAccessData();
923 switch (variable->flushFormat()) {
924 case FlushedJSValue:
925 case FlushedArguments: {
926 LValue value = lowJSValue(m_node->child1());
927 m_out.store64(value, addressFor(variable->machineLocal()));
928 break;
929 }
930
931 case FlushedDouble: {
932 LValue value = lowDouble(m_node->child1());
933 m_out.storeDouble(value, addressFor(variable->machineLocal()));
934 break;
935 }
936
937 case FlushedInt32: {
938 LValue value = lowInt32(m_node->child1());
939 m_out.store32(value, payloadFor(variable->machineLocal()));
940 break;
941 }
942
943 case FlushedInt52: {
944 LValue value = lowInt52(m_node->child1());
945 m_out.store64(value, addressFor(variable->machineLocal()));
946 break;
947 }
948
949 case FlushedCell: {
950 LValue value = lowCell(m_node->child1());
951 m_out.store64(value, addressFor(variable->machineLocal()));
952 break;
953 }
954
955 case FlushedBoolean: {
956 speculateBoolean(m_node->child1());
957 m_out.store64(
958 lowJSValue(m_node->child1(), ManualOperandSpeculation),
959 addressFor(variable->machineLocal()));
960 break;
961 }
962
963 default:
964 RELEASE_ASSERT_NOT_REACHED();
965 break;
966 }
967
968 m_availability.operand(variable->local()) = Availability(variable->flushedAt());
969 }
970
971 void compileMovHint()
972 {
973 ASSERT(m_node->containsMovHint());
974 ASSERT(m_node->op() != ZombieHint);
975
976 VirtualRegister operand = m_node->unlinkedLocal();
977 m_availability.operand(operand) = Availability(m_node->child1().node());
978 }
979
980 void compileZombieHint()
981 {
982 m_availability.operand(m_node->unlinkedLocal()) = Availability::unavailable();
983 }
984
985 void compilePhantom()
986 {
987 DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, speculate);
988 }
989
990 void compileToThis()
991 {
992 LValue value = lowJSValue(m_node->child1());
993
994 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("ToThis is cell case"));
995 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ToThis slow case"));
996 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToThis continuation"));
997
998 m_out.branch(isCell(value), usually(isCellCase), rarely(slowCase));
999
1000 LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase);
1001 ValueFromBlock fastResult = m_out.anchor(value);
1002 m_out.branch(isType(value, FinalObjectType), usually(continuation), rarely(slowCase));
1003
1004 m_out.appendTo(slowCase, continuation);
1005 J_JITOperation_EJ function;
1006 if (m_graph.isStrictModeFor(m_node->origin.semantic))
1007 function = operationToThisStrict;
1008 else
1009 function = operationToThis;
1010 ValueFromBlock slowResult = m_out.anchor(
1011 vmCall(m_out.operation(function), m_callFrame, value));
1012 m_out.jump(continuation);
1013
1014 m_out.appendTo(continuation, lastNext);
1015 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
1016 }
1017
1018 void compileValueAdd()
1019 {
1020 J_JITOperation_EJJ operation;
1021 if (!(m_state.forNode(m_node->child1()).m_type & SpecFullNumber)
1022 && !(m_state.forNode(m_node->child2()).m_type & SpecFullNumber))
1023 operation = operationValueAddNotNumber;
1024 else
1025 operation = operationValueAdd;
1026 setJSValue(vmCall(
1027 m_out.operation(operation), m_callFrame,
1028 lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
1029 }
1030
1031 void compileArithAddOrSub()
1032 {
1033 bool isSub = m_node->op() == ArithSub;
1034 switch (m_node->binaryUseKind()) {
1035 case Int32Use: {
1036 LValue left = lowInt32(m_node->child1());
1037 LValue right = lowInt32(m_node->child2());
1038
1039 if (!shouldCheckOverflow(m_node->arithMode())) {
1040 setInt32(isSub ? m_out.sub(left, right) : m_out.add(left, right));
1041 break;
1042 }
1043
1044 LValue result;
1045 if (!isSub) {
1046 result = m_out.addWithOverflow32(left, right);
1047
1048 if (doesKill(m_node->child2())) {
1049 addAvailableRecovery(
1050 m_node->child2(), SubRecovery,
1051 m_out.extractValue(result, 0), left, ValueFormatInt32);
1052 } else if (doesKill(m_node->child1())) {
1053 addAvailableRecovery(
1054 m_node->child1(), SubRecovery,
1055 m_out.extractValue(result, 0), right, ValueFormatInt32);
1056 }
1057 } else {
1058 result = m_out.subWithOverflow32(left, right);
1059
1060 if (doesKill(m_node->child2())) {
1061 // result = left - right
1062 // result - left = -right
1063 // right = left - result
1064 addAvailableRecovery(
1065 m_node->child2(), SubRecovery,
1066 left, m_out.extractValue(result, 0), ValueFormatInt32);
1067 } else if (doesKill(m_node->child1())) {
1068 // result = left - right
1069 // result + right = left
1070 addAvailableRecovery(
1071 m_node->child1(), AddRecovery,
1072 m_out.extractValue(result, 0), right, ValueFormatInt32);
1073 }
1074 }
1075
1076 speculate(Overflow, noValue(), 0, m_out.extractValue(result, 1));
1077 setInt32(m_out.extractValue(result, 0));
1078 break;
1079 }
1080
1081 case Int52RepUse: {
1082 if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)
1083 && !m_state.forNode(m_node->child2()).couldBeType(SpecInt52)) {
1084 Int52Kind kind;
1085 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1086 LValue right = lowInt52(m_node->child2(), kind);
1087 setInt52(isSub ? m_out.sub(left, right) : m_out.add(left, right), kind);
1088 break;
1089 }
1090
1091 LValue left = lowInt52(m_node->child1());
1092 LValue right = lowInt52(m_node->child2());
1093
1094 LValue result;
1095 if (!isSub) {
1096 result = m_out.addWithOverflow64(left, right);
1097
1098 if (doesKill(m_node->child2())) {
1099 addAvailableRecovery(
1100 m_node->child2(), SubRecovery,
1101 m_out.extractValue(result, 0), left, ValueFormatInt52);
1102 } else if (doesKill(m_node->child1())) {
1103 addAvailableRecovery(
1104 m_node->child1(), SubRecovery,
1105 m_out.extractValue(result, 0), right, ValueFormatInt52);
1106 }
1107 } else {
1108 result = m_out.subWithOverflow64(left, right);
1109
1110 if (doesKill(m_node->child2())) {
1111 // result = left - right
1112 // result - left = -right
1113 // right = left - result
1114 addAvailableRecovery(
1115 m_node->child2(), SubRecovery,
1116 left, m_out.extractValue(result, 0), ValueFormatInt52);
1117 } else if (doesKill(m_node->child1())) {
1118 // result = left - right
1119 // result + right = left
1120 addAvailableRecovery(
1121 m_node->child1(), AddRecovery,
1122 m_out.extractValue(result, 0), right, ValueFormatInt52);
1123 }
1124 }
1125
1126 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(result, 1));
1127 setInt52(m_out.extractValue(result, 0));
1128 break;
1129 }
1130
1131 case DoubleRepUse: {
1132 LValue C1 = lowDouble(m_node->child1());
1133 LValue C2 = lowDouble(m_node->child2());
1134
1135 setDouble(isSub ? m_out.doubleSub(C1, C2) : m_out.doubleAdd(C1, C2));
1136 break;
1137 }
1138
1139 default:
1140 RELEASE_ASSERT_NOT_REACHED();
1141 break;
1142 }
1143 }
1144
1145 void compileArithMul()
1146 {
1147 switch (m_node->binaryUseKind()) {
1148 case Int32Use: {
1149 LValue left = lowInt32(m_node->child1());
1150 LValue right = lowInt32(m_node->child2());
1151
1152 LValue result;
1153
1154 if (!shouldCheckOverflow(m_node->arithMode()))
1155 result = m_out.mul(left, right);
1156 else {
1157 LValue overflowResult = m_out.mulWithOverflow32(left, right);
1158 speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1159 result = m_out.extractValue(overflowResult, 0);
1160 }
1161
1162 if (shouldCheckNegativeZero(m_node->arithMode())) {
1163 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
1164 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
1165
1166 m_out.branch(
1167 m_out.notZero32(result), usually(continuation), rarely(slowCase));
1168
1169 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1170 LValue cond = m_out.bitOr(m_out.lessThan(left, m_out.int32Zero), m_out.lessThan(right, m_out.int32Zero));
1171 speculate(NegativeZero, noValue(), 0, cond);
1172 m_out.jump(continuation);
1173 m_out.appendTo(continuation, lastNext);
1174 }
1175
1176 setInt32(result);
1177 break;
1178 }
1179
1180 case Int52RepUse: {
1181 Int52Kind kind;
1182 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1183 LValue right = lowInt52(m_node->child2(), opposite(kind));
1184
1185 LValue overflowResult = m_out.mulWithOverflow64(left, right);
1186 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1187 LValue result = m_out.extractValue(overflowResult, 0);
1188
1189 if (shouldCheckNegativeZero(m_node->arithMode())) {
1190 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
1191 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
1192
1193 m_out.branch(
1194 m_out.notZero64(result), usually(continuation), rarely(slowCase));
1195
1196 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1197 LValue cond = m_out.bitOr(m_out.lessThan(left, m_out.int64Zero), m_out.lessThan(right, m_out.int64Zero));
1198 speculate(NegativeZero, noValue(), 0, cond);
1199 m_out.jump(continuation);
1200 m_out.appendTo(continuation, lastNext);
1201 }
1202
1203 setInt52(result);
1204 break;
1205 }
1206
1207 case DoubleRepUse: {
1208 setDouble(
1209 m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1210 break;
1211 }
1212
1213 default:
1214 RELEASE_ASSERT_NOT_REACHED();
1215 break;
1216 }
1217 }
1218
1219 void compileArithDiv()
1220 {
1221 switch (m_node->binaryUseKind()) {
1222 case Int32Use: {
1223 LValue numerator = lowInt32(m_node->child1());
1224 LValue denominator = lowInt32(m_node->child2());
1225
1226 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithDiv unsafe denominator"));
1227 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithDiv continuation"));
1228 LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithDiv done"));
1229
1230 Vector<ValueFromBlock, 3> results;
1231
1232 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1233
1234 m_out.branch(
1235 m_out.above(adjustedDenominator, m_out.int32One),
1236 usually(continuation), rarely(unsafeDenominator));
1237
1238 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1239
1240 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1241
1242 if (shouldCheckOverflow(m_node->arithMode())) {
1243 LValue cond = m_out.bitOr(m_out.isZero32(denominator), m_out.equal(numerator, neg2ToThe31));
1244 speculate(Overflow, noValue(), 0, cond);
1245 m_out.jump(continuation);
1246 } else {
1247 // This is the case where we convert the result to an int after we're done. So,
1248 // if the denominator is zero, then the result should be zero.
1249 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
1250 // check above) and the numerator is -2^31 then the result should be -2^31.
1251
1252 LBasicBlock divByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv divide by zero"));
1253 LBasicBlock notDivByZero = FTL_NEW_BLOCK(m_out, ("ArithDiv not divide by zero"));
1254 LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithDiv -2^31/-1"));
1255
1256 m_out.branch(
1257 m_out.isZero32(denominator), rarely(divByZero), usually(notDivByZero));
1258
1259 m_out.appendTo(divByZero, notDivByZero);
1260 results.append(m_out.anchor(m_out.int32Zero));
1261 m_out.jump(done);
1262
1263 m_out.appendTo(notDivByZero, neg2ToThe31ByNeg1);
1264 m_out.branch(
1265 m_out.equal(numerator, neg2ToThe31),
1266 rarely(neg2ToThe31ByNeg1), usually(continuation));
1267
1268 m_out.appendTo(neg2ToThe31ByNeg1, continuation);
1269 results.append(m_out.anchor(neg2ToThe31));
1270 m_out.jump(done);
1271 }
1272
1273 m_out.appendTo(continuation, done);
1274
1275 if (shouldCheckNegativeZero(m_node->arithMode())) {
1276 LBasicBlock zeroNumerator = FTL_NEW_BLOCK(m_out, ("ArithDiv zero numerator"));
1277 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithDiv numerator continuation"));
1278
1279 m_out.branch(
1280 m_out.isZero32(numerator),
1281 rarely(zeroNumerator), usually(numeratorContinuation));
1282
1283 LBasicBlock innerLastNext = m_out.appendTo(zeroNumerator, numeratorContinuation);
1284
1285 speculate(
1286 NegativeZero, noValue(), 0, m_out.lessThan(denominator, m_out.int32Zero));
1287
1288 m_out.jump(numeratorContinuation);
1289
1290 m_out.appendTo(numeratorContinuation, innerLastNext);
1291 }
1292
1293 LValue result = m_out.div(numerator, denominator);
1294
1295 if (shouldCheckOverflow(m_node->arithMode())) {
1296 speculate(
1297 Overflow, noValue(), 0,
1298 m_out.notEqual(m_out.mul(result, denominator), numerator));
1299 }
1300
1301 results.append(m_out.anchor(result));
1302 m_out.jump(done);
1303
1304 m_out.appendTo(done, lastNext);
1305
1306 setInt32(m_out.phi(m_out.int32, results));
1307 break;
1308 }
1309
1310 case DoubleRepUse: {
1311 setDouble(m_out.doubleDiv(
1312 lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1313 break;
1314 }
1315
1316 default:
1317 RELEASE_ASSERT_NOT_REACHED();
1318 break;
1319 }
1320 }
1321
1322 void compileArithMod()
1323 {
1324 switch (m_node->binaryUseKind()) {
1325 case Int32Use: {
1326 LValue numerator = lowInt32(m_node->child1());
1327 LValue denominator = lowInt32(m_node->child2());
1328
1329 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithMod unsafe denominator"));
1330 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMod continuation"));
1331 LBasicBlock done = FTL_NEW_BLOCK(m_out, ("ArithMod done"));
1332
1333 Vector<ValueFromBlock, 3> results;
1334
1335 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1336
1337 m_out.branch(
1338 m_out.above(adjustedDenominator, m_out.int32One),
1339 usually(continuation), rarely(unsafeDenominator));
1340
1341 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1342
1343 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1344
1345 // FIXME: -2^31 / -1 will actually yield negative zero, so we could have a
1346 // separate case for that. But it probably doesn't matter so much.
1347 if (shouldCheckOverflow(m_node->arithMode())) {
1348 LValue cond = m_out.bitOr(m_out.isZero32(denominator), m_out.equal(numerator, neg2ToThe31));
1349 speculate(Overflow, noValue(), 0, cond);
1350 m_out.jump(continuation);
1351 } else {
1352 // This is the case where we convert the result to an int after we're done. So,
1353 // if the denominator is zero, then the result should be result should be zero.
1354 // If the denominator is not zero (i.e. it's -1 because we're guarded by the
1355 // check above) and the numerator is -2^31 then the result should be -2^31.
1356
1357 LBasicBlock modByZero = FTL_NEW_BLOCK(m_out, ("ArithMod modulo by zero"));
1358 LBasicBlock notModByZero = FTL_NEW_BLOCK(m_out, ("ArithMod not modulo by zero"));
1359 LBasicBlock neg2ToThe31ByNeg1 = FTL_NEW_BLOCK(m_out, ("ArithMod -2^31/-1"));
1360
1361 m_out.branch(
1362 m_out.isZero32(denominator), rarely(modByZero), usually(notModByZero));
1363
1364 m_out.appendTo(modByZero, notModByZero);
1365 results.append(m_out.anchor(m_out.int32Zero));
1366 m_out.jump(done);
1367
1368 m_out.appendTo(notModByZero, neg2ToThe31ByNeg1);
1369 m_out.branch(
1370 m_out.equal(numerator, neg2ToThe31),
1371 rarely(neg2ToThe31ByNeg1), usually(continuation));
1372
1373 m_out.appendTo(neg2ToThe31ByNeg1, continuation);
1374 results.append(m_out.anchor(m_out.int32Zero));
1375 m_out.jump(done);
1376 }
1377
1378 m_out.appendTo(continuation, done);
1379
1380 LValue remainder = m_out.rem(numerator, denominator);
1381
1382 if (shouldCheckNegativeZero(m_node->arithMode())) {
1383 LBasicBlock negativeNumerator = FTL_NEW_BLOCK(m_out, ("ArithMod negative numerator"));
1384 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithMod numerator continuation"));
1385
1386 m_out.branch(
1387 m_out.lessThan(numerator, m_out.int32Zero),
1388 unsure(negativeNumerator), unsure(numeratorContinuation));
1389
1390 LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
1391
1392 speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
1393
1394 m_out.jump(numeratorContinuation);
1395
1396 m_out.appendTo(numeratorContinuation, innerLastNext);
1397 }
1398
1399 results.append(m_out.anchor(remainder));
1400 m_out.jump(done);
1401
1402 m_out.appendTo(done, lastNext);
1403
1404 setInt32(m_out.phi(m_out.int32, results));
1405 break;
1406 }
1407
1408 case DoubleRepUse: {
1409 setDouble(
1410 m_out.doubleRem(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1411 break;
1412 }
1413
1414 default:
1415 RELEASE_ASSERT_NOT_REACHED();
1416 break;
1417 }
1418 }
1419
1420 void compileArithMinOrMax()
1421 {
1422 switch (m_node->binaryUseKind()) {
1423 case Int32Use: {
1424 LValue left = lowInt32(m_node->child1());
1425 LValue right = lowInt32(m_node->child2());
1426
1427 setInt32(
1428 m_out.select(
1429 m_node->op() == ArithMin
1430 ? m_out.lessThan(left, right)
1431 : m_out.lessThan(right, left),
1432 left, right));
1433 break;
1434 }
1435
1436 case DoubleRepUse: {
1437 LValue left = lowDouble(m_node->child1());
1438 LValue right = lowDouble(m_node->child2());
1439
1440 LBasicBlock notLessThan = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax not less than"));
1441 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax continuation"));
1442
1443 Vector<ValueFromBlock, 2> results;
1444
1445 results.append(m_out.anchor(left));
1446 m_out.branch(
1447 m_node->op() == ArithMin
1448 ? m_out.doubleLessThan(left, right)
1449 : m_out.doubleGreaterThan(left, right),
1450 unsure(continuation), unsure(notLessThan));
1451
1452 LBasicBlock lastNext = m_out.appendTo(notLessThan, continuation);
1453 results.append(m_out.anchor(m_out.select(
1454 m_node->op() == ArithMin
1455 ? m_out.doubleGreaterThanOrEqual(left, right)
1456 : m_out.doubleLessThanOrEqual(left, right),
1457 right, m_out.constDouble(PNaN))));
1458 m_out.jump(continuation);
1459
1460 m_out.appendTo(continuation, lastNext);
1461 setDouble(m_out.phi(m_out.doubleType, results));
1462 break;
1463 }
1464
1465 default:
1466 RELEASE_ASSERT_NOT_REACHED();
1467 break;
1468 }
1469 }
1470
1471 void compileArithAbs()
1472 {
1473 switch (m_node->child1().useKind()) {
1474 case Int32Use: {
1475 LValue value = lowInt32(m_node->child1());
1476
1477 LValue mask = m_out.aShr(value, m_out.constInt32(31));
1478 LValue result = m_out.bitXor(mask, m_out.add(mask, value));
1479
1480 speculate(Overflow, noValue(), 0, m_out.equal(result, m_out.constInt32(1 << 31)));
1481
1482 setInt32(result);
1483 break;
1484 }
1485
1486 case DoubleRepUse: {
1487 setDouble(m_out.doubleAbs(lowDouble(m_node->child1())));
1488 break;
1489 }
1490
1491 default:
1492 RELEASE_ASSERT_NOT_REACHED();
1493 break;
1494 }
1495 }
1496
1497 void compileArithSin() { setDouble(m_out.doubleSin(lowDouble(m_node->child1()))); }
1498
1499 void compileArithCos() { setDouble(m_out.doubleCos(lowDouble(m_node->child1()))); }
1500
1501 void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); }
1502
1503 void compileArithFRound()
1504 {
1505 LValue floatValue = m_out.fpCast(lowDouble(m_node->child1()), m_out.floatType);
1506 setDouble(m_out.fpCast(floatValue, m_out.doubleType));
1507 }
1508
1509 void compileArithNegate()
1510 {
1511 switch (m_node->child1().useKind()) {
1512 case Int32Use: {
1513 LValue value = lowInt32(m_node->child1());
1514
1515 LValue result;
1516 if (!shouldCheckOverflow(m_node->arithMode()))
1517 result = m_out.neg(value);
1518 else if (!shouldCheckNegativeZero(m_node->arithMode())) {
1519 // We don't have a negate-with-overflow intrinsic. Hopefully this
1520 // does the trick, though.
1521 LValue overflowResult = m_out.subWithOverflow32(m_out.int32Zero, value);
1522 speculate(Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1523 result = m_out.extractValue(overflowResult, 0);
1524 } else {
1525 speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
1526 result = m_out.neg(value);
1527 }
1528
1529 setInt32(result);
1530 break;
1531 }
1532
1533 case Int52RepUse: {
1534 if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)) {
1535 Int52Kind kind;
1536 LValue value = lowWhicheverInt52(m_node->child1(), kind);
1537 LValue result = m_out.neg(value);
1538 if (shouldCheckNegativeZero(m_node->arithMode()))
1539 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1540 setInt52(result, kind);
1541 break;
1542 }
1543
1544 LValue value = lowInt52(m_node->child1());
1545 LValue overflowResult = m_out.subWithOverflow64(m_out.int64Zero, value);
1546 speculate(Int52Overflow, noValue(), 0, m_out.extractValue(overflowResult, 1));
1547 LValue result = m_out.extractValue(overflowResult, 0);
1548 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1549 setInt52(result);
1550 break;
1551 }
1552
1553 case DoubleRepUse: {
1554 setDouble(m_out.doubleNeg(lowDouble(m_node->child1())));
1555 break;
1556 }
1557
1558 default:
1559 RELEASE_ASSERT_NOT_REACHED();
1560 break;
1561 }
1562 }
1563
1564 void compileBitAnd()
1565 {
1566 setInt32(m_out.bitAnd(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1567 }
1568
1569 void compileBitOr()
1570 {
1571 setInt32(m_out.bitOr(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1572 }
1573
1574 void compileBitXor()
1575 {
1576 setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1577 }
1578
1579 void compileBitRShift()
1580 {
1581 setInt32(m_out.aShr(
1582 lowInt32(m_node->child1()),
1583 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
1584 }
1585
1586 void compileBitLShift()
1587 {
1588 setInt32(m_out.shl(
1589 lowInt32(m_node->child1()),
1590 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
1591 }
1592
1593 void compileBitURShift()
1594 {
1595 setInt32(m_out.lShr(
1596 lowInt32(m_node->child1()),
1597 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
1598 }
1599
1600 void compileUInt32ToNumber()
1601 {
1602 LValue value = lowInt32(m_node->child1());
1603
1604 if (doesOverflow(m_node->arithMode())) {
1605 setDouble(m_out.unsignedToDouble(value));
1606 return;
1607 }
1608
1609 speculate(Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero));
1610 setInt32(value);
1611 }
1612
1613 void compileCheckStructure()
1614 {
1615 LValue cell = lowCell(m_node->child1());
1616
1617 ExitKind exitKind;
1618 if (m_node->child1()->op() == WeakJSConstant)
1619 exitKind = BadWeakConstantCache;
1620 else
1621 exitKind = BadCache;
1622
1623 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
1624
1625 if (m_node->structureSet().size() == 1) {
1626 speculate(
1627 exitKind, jsValueValue(cell), 0,
1628 m_out.notEqual(structureID, weakStructure(m_node->structureSet()[0])));
1629 return;
1630 }
1631
1632 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CheckStructure continuation"));
1633
1634 LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation);
1635 for (unsigned i = 0; i < m_node->structureSet().size() - 1; ++i) {
1636 LBasicBlock nextStructure = FTL_NEW_BLOCK(m_out, ("CheckStructure nextStructure"));
1637 m_out.branch(
1638 m_out.equal(structureID, weakStructure(m_node->structureSet()[i])),
1639 unsure(continuation), unsure(nextStructure));
1640 m_out.appendTo(nextStructure);
1641 }
1642
1643 speculate(
1644 exitKind, jsValueValue(cell), 0,
1645 m_out.notEqual(structureID, weakStructure(m_node->structureSet().last())));
1646
1647 m_out.jump(continuation);
1648 m_out.appendTo(continuation, lastNext);
1649 }
1650
1651 void compileStructureTransitionWatchpoint()
1652 {
1653 addWeakReference(m_node->structure());
1654 speculateCell(m_node->child1());
1655 }
1656
1657 void compileCheckFunction()
1658 {
1659 LValue cell = lowCell(m_node->child1());
1660
1661 speculate(
1662 BadFunction, jsValueValue(cell), m_node->child1().node(),
1663 m_out.notEqual(cell, weakPointer(m_node->function())));
1664 }
1665
1666 void compileCheckExecutable()
1667 {
1668 LValue cell = lowCell(m_node->child1());
1669
1670 speculate(
1671 BadExecutable, jsValueValue(cell), m_node->child1().node(),
1672 m_out.notEqual(
1673 m_out.loadPtr(cell, m_heaps.JSFunction_executable),
1674 weakPointer(m_node->executable())));
1675 }
1676
1677 void compileArrayifyToStructure()
1678 {
1679 LValue cell = lowCell(m_node->child1());
1680 LValue property = !!m_node->child2() ? lowInt32(m_node->child2()) : 0;
1681
1682 LBasicBlock unexpectedStructure = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure unexpected structure"));
1683 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure continuation"));
1684
1685 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
1686
1687 m_out.branch(
1688 m_out.notEqual(structureID, weakStructure(m_node->structure())),
1689 rarely(unexpectedStructure), usually(continuation));
1690
1691 LBasicBlock lastNext = m_out.appendTo(unexpectedStructure, continuation);
1692
1693 if (property) {
1694 switch (m_node->arrayMode().type()) {
1695 case Array::Int32:
1696 case Array::Double:
1697 case Array::Contiguous:
1698 speculate(
1699 Uncountable, noValue(), 0,
1700 m_out.aboveOrEqual(property, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)));
1701 break;
1702 default:
1703 break;
1704 }
1705 }
1706
1707 switch (m_node->arrayMode().type()) {
1708 case Array::Int32:
1709 vmCall(m_out.operation(operationEnsureInt32), m_callFrame, cell);
1710 break;
1711 case Array::Double:
1712 vmCall(m_out.operation(operationEnsureDouble), m_callFrame, cell);
1713 break;
1714 case Array::Contiguous:
1715 if (m_node->arrayMode().conversion() == Array::RageConvert)
1716 vmCall(m_out.operation(operationRageEnsureContiguous), m_callFrame, cell);
1717 else
1718 vmCall(m_out.operation(operationEnsureContiguous), m_callFrame, cell);
1719 break;
1720 case Array::ArrayStorage:
1721 case Array::SlowPutArrayStorage:
1722 vmCall(m_out.operation(operationEnsureArrayStorage), m_callFrame, cell);
1723 break;
1724 default:
1725 RELEASE_ASSERT_NOT_REACHED();
1726 break;
1727 }
1728
1729 structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
1730 speculate(
1731 BadIndexingType, jsValueValue(cell), 0,
1732 m_out.notEqual(structureID, weakStructure(m_node->structure())));
1733 m_out.jump(continuation);
1734
1735 m_out.appendTo(continuation, lastNext);
1736 }
1737
1738 void compilePutStructure()
1739 {
1740 m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
1741
1742 Structure* oldStructure = m_node->structureTransitionData().previousStructure;
1743 Structure* newStructure = m_node->structureTransitionData().newStructure;
1744 ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType());
1745 ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags());
1746 ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type());
1747
1748 LValue cell = lowCell(m_node->child1());
1749 m_out.store32(
1750 weakStructure(newStructure),
1751 cell, m_heaps.JSCell_structureID);
1752 }
1753
1754 void compilePhantomPutStructure()
1755 {
1756 m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
1757 }
1758
1759 void compileGetById()
1760 {
1761 // Pretty much the only reason why we don't also support GetByIdFlush is because:
1762 // https://bugs.webkit.org/show_bug.cgi?id=125711
1763
1764 switch (m_node->child1().useKind()) {
1765 case CellUse: {
1766 setJSValue(getById(lowCell(m_node->child1())));
1767 return;
1768 }
1769
1770 case UntypedUse: {
1771 // This is pretty weird, since we duplicate the slow path both here and in the
1772 // code generated by the IC. We should investigate making this less bad.
1773 // https://bugs.webkit.org/show_bug.cgi?id=127830
1774 LValue value = lowJSValue(m_node->child1());
1775
1776 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("GetById untyped cell case"));
1777 LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("GetById untyped not cell case"));
1778 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetById untyped continuation"));
1779
1780 m_out.branch(isCell(value), unsure(cellCase), unsure(notCellCase));
1781
1782 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
1783 ValueFromBlock cellResult = m_out.anchor(getById(value));
1784 m_out.jump(continuation);
1785
1786 m_out.appendTo(notCellCase, continuation);
1787 ValueFromBlock notCellResult = m_out.anchor(vmCall(
1788 m_out.operation(operationGetById),
1789 m_callFrame, getUndef(m_out.intPtr), value,
1790 m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()])));
1791 m_out.jump(continuation);
1792
1793 m_out.appendTo(continuation, lastNext);
1794 setJSValue(m_out.phi(m_out.int64, cellResult, notCellResult));
1795 return;
1796 }
1797
1798 default:
1799 RELEASE_ASSERT_NOT_REACHED();
1800 return;
1801 }
1802 }
1803
1804 void compilePutById()
1805 {
1806 // See above; CellUse is easier so we do only that for now.
1807 ASSERT(m_node->child1().useKind() == CellUse);
1808
1809 LValue base = lowCell(m_node->child1());
1810 LValue value = lowJSValue(m_node->child2());
1811 StringImpl* uid = m_graph.identifiers()[m_node->identifierNumber()];
1812
1813 // Arguments: id, bytes, target, numArgs, args...
1814 unsigned stackmapID = m_stackmapIDs++;
1815
1816 if (Options::verboseCompilation())
1817 dataLog(" Emitting PutById patchpoint with stackmap #", stackmapID, "\n");
1818
1819 LValue call = m_out.call(
1820 m_out.patchpointVoidIntrinsic(),
1821 m_out.constInt64(stackmapID), m_out.constInt32(sizeOfPutById()),
1822 constNull(m_out.ref8), m_out.constInt32(2), base, value);
1823 setInstructionCallingConvention(call, LLVMAnyRegCallConv);
1824
1825 m_ftlState.putByIds.append(PutByIdDescriptor(
1826 stackmapID, m_node->origin.semantic, uid,
1827 m_graph.executableFor(m_node->origin.semantic)->ecmaMode(),
1828 m_node->op() == PutByIdDirect ? Direct : NotDirect));
1829 }
1830
1831 void compileGetButterfly()
1832 {
1833 setStorage(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSObject_butterfly));
1834 }
1835
1836 void compileConstantStoragePointer()
1837 {
1838 setStorage(m_out.constIntPtr(m_node->storagePointer()));
1839 }
1840
1841 void compileGetIndexedPropertyStorage()
1842 {
1843 LValue cell = lowCell(m_node->child1());
1844
1845 if (m_node->arrayMode().type() == Array::String) {
1846 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String slow case"));
1847 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String continuation"));
1848
1849 ValueFromBlock fastResult = m_out.anchor(
1850 m_out.loadPtr(cell, m_heaps.JSString_value));
1851
1852 m_out.branch(
1853 m_out.notNull(fastResult.value()), usually(continuation), rarely(slowPath));
1854
1855 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
1856
1857 ValueFromBlock slowResult = m_out.anchor(
1858 vmCall(m_out.operation(operationResolveRope), m_callFrame, cell));
1859
1860 m_out.jump(continuation);
1861
1862 m_out.appendTo(continuation, lastNext);
1863
1864 setStorage(m_out.loadPtr(m_out.phi(m_out.intPtr, fastResult, slowResult), m_heaps.StringImpl_data));
1865 return;
1866 }
1867
1868 setStorage(m_out.loadPtr(cell, m_heaps.JSArrayBufferView_vector));
1869 }
1870
1871 void compileCheckArray()
1872 {
1873 Edge edge = m_node->child1();
1874 LValue cell = lowCell(edge);
1875
1876 if (m_node->arrayMode().alreadyChecked(m_graph, m_node, m_state.forNode(edge)))
1877 return;
1878
1879 speculate(
1880 BadIndexingType, jsValueValue(cell), 0,
1881 m_out.bitNot(isArrayType(cell, m_node->arrayMode())));
1882 }
1883
1884 void compileGetTypedArrayByteOffset()
1885 {
1886 LValue basePtr = lowCell(m_node->child1());
1887
1888 LBasicBlock simpleCase = FTL_NEW_BLOCK(m_out, ("wasteless typed array"));
1889 LBasicBlock wastefulCase = FTL_NEW_BLOCK(m_out, ("wasteful typed array"));
1890 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("continuation branch"));
1891
1892 LValue baseAddress = m_out.addPtr(basePtr, JSArrayBufferView::offsetOfMode());
1893 m_out.branch(
1894 m_out.notEqual(baseAddress , m_out.constIntPtr(WastefulTypedArray)),
1895 unsure(simpleCase), unsure(wastefulCase));
1896
1897 // begin simple case
1898 LBasicBlock lastNext = m_out.appendTo(simpleCase, wastefulCase);
1899
1900 ValueFromBlock simpleOut = m_out.anchor(m_out.constIntPtr(0));
1901
1902 m_out.jump(continuation);
1903
1904 // begin wasteful case
1905 m_out.appendTo(wastefulCase, continuation);
1906
1907 LValue vectorPtr = m_out.loadPtr(basePtr, m_heaps.JSArrayBufferView_vector);
1908 LValue butterflyPtr = m_out.loadPtr(basePtr, m_heaps.JSObject_butterfly);
1909 LValue arrayBufferPtr = m_out.loadPtr(butterflyPtr, m_heaps.Butterfly_arrayBuffer);
1910 LValue dataPtr = m_out.loadPtr(arrayBufferPtr, m_heaps.ArrayBuffer_data);
1911
1912 ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(dataPtr, vectorPtr));
1913
1914 m_out.jump(continuation);
1915 m_out.appendTo(continuation, lastNext);
1916
1917 // output
1918 setInt32(m_out.castToInt32(m_out.phi(m_out.intPtr, simpleOut, wastefulOut)));
1919 }
1920
1921 void compileGetMyArgumentsLength()
1922 {
1923 checkArgumentsNotCreated();
1924
1925 RELEASE_ASSERT(!m_node->origin.semantic.inlineCallFrame);
1926 setInt32(m_out.add(m_out.load32NonNegative(payloadFor(JSStack::ArgumentCount)), m_out.constInt32(-1)));
1927 }
1928
1929 void compileGetMyArgumentByVal()
1930 {
1931 checkArgumentsNotCreated();
1932
1933 CodeOrigin codeOrigin = m_node->origin.semantic;
1934
1935 LValue zeroBasedIndex = lowInt32(m_node->child1());
1936 LValue oneBasedIndex = m_out.add(zeroBasedIndex, m_out.int32One);
1937
1938 LValue limit;
1939 if (codeOrigin.inlineCallFrame)
1940 limit = m_out.constInt32(codeOrigin.inlineCallFrame->arguments.size());
1941 else
1942 limit = m_out.load32(payloadFor(JSStack::ArgumentCount));
1943
1944 speculate(Uncountable, noValue(), 0, m_out.aboveOrEqual(oneBasedIndex, limit));
1945
1946 SymbolTable* symbolTable = m_graph.baselineCodeBlockFor(codeOrigin)->symbolTable();
1947 if (symbolTable->slowArguments()) {
1948 // FIXME: FTL should support activations.
1949 // https://bugs.webkit.org/show_bug.cgi?id=129576
1950
1951 RELEASE_ASSERT_NOT_REACHED();
1952 }
1953
1954 TypedPointer base;
1955 if (codeOrigin.inlineCallFrame)
1956 base = addressFor(codeOrigin.inlineCallFrame->arguments[1].virtualRegister());
1957 else
1958 base = addressFor(virtualRegisterForArgument(1));
1959
1960 LValue pointer = m_out.baseIndex(
1961 base.value(), m_out.zeroExt(zeroBasedIndex, m_out.intPtr), ScaleEight);
1962 setJSValue(m_out.load64(TypedPointer(m_heaps.variables.atAnyIndex(), pointer)));
1963 }
1964
1965 void compileGetArrayLength()
1966 {
1967 switch (m_node->arrayMode().type()) {
1968 case Array::Int32:
1969 case Array::Double:
1970 case Array::Contiguous: {
1971 setInt32(m_out.load32NonNegative(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
1972 return;
1973 }
1974
1975 case Array::String: {
1976 LValue string = lowCell(m_node->child1());
1977 setInt32(m_out.load32NonNegative(string, m_heaps.JSString_length));
1978 return;
1979 }
1980
1981 default:
1982 if (isTypedView(m_node->arrayMode().typedArrayType())) {
1983 setInt32(
1984 m_out.load32NonNegative(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
1985 return;
1986 }
1987
1988 RELEASE_ASSERT_NOT_REACHED();
1989 return;
1990 }
1991 }
1992
1993 void compileCheckInBounds()
1994 {
1995 speculate(
1996 OutOfBounds, noValue(), 0,
1997 m_out.aboveOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1998 }
1999
2000 void compileGetByVal()
2001 {
2002 switch (m_node->arrayMode().type()) {
2003 case Array::Int32:
2004 case Array::Contiguous: {
2005 LValue index = lowInt32(m_node->child2());
2006 LValue storage = lowStorage(m_node->child3());
2007
2008 IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ?
2009 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
2010
2011 if (m_node->arrayMode().isInBounds()) {
2012 LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
2013 speculate(LoadFromHole, noValue(), 0, m_out.isZero64(result));
2014 setJSValue(result);
2015 return;
2016 }
2017
2018 LValue base = lowCell(m_node->child1());
2019
2020 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous fast case"));
2021 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous slow case"));
2022 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous continuation"));
2023
2024 m_out.branch(
2025 m_out.aboveOrEqual(
2026 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2027 rarely(slowCase), usually(fastCase));
2028
2029 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
2030
2031 ValueFromBlock fastResult = m_out.anchor(
2032 m_out.load64(baseIndex(heap, storage, index, m_node->child2())));
2033 m_out.branch(
2034 m_out.isZero64(fastResult.value()), rarely(slowCase), usually(continuation));
2035
2036 m_out.appendTo(slowCase, continuation);
2037 ValueFromBlock slowResult = m_out.anchor(
2038 vmCall(m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2039 m_out.jump(continuation);
2040
2041 m_out.appendTo(continuation, lastNext);
2042 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2043 return;
2044 }
2045
2046 case Array::Double: {
2047 LValue index = lowInt32(m_node->child2());
2048 LValue storage = lowStorage(m_node->child3());
2049
2050 IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
2051
2052 if (m_node->arrayMode().isInBounds()) {
2053 LValue result = m_out.loadDouble(
2054 baseIndex(heap, storage, index, m_node->child2()));
2055
2056 if (!m_node->arrayMode().isSaneChain()) {
2057 speculate(
2058 LoadFromHole, noValue(), 0,
2059 m_out.doubleNotEqualOrUnordered(result, result));
2060 }
2061 setDouble(result);
2062 break;
2063 }
2064
2065 LValue base = lowCell(m_node->child1());
2066
2067 LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetByVal double in bounds"));
2068 LBasicBlock boxPath = FTL_NEW_BLOCK(m_out, ("GetByVal double boxing"));
2069 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal double slow case"));
2070 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal double continuation"));
2071
2072 m_out.branch(
2073 m_out.aboveOrEqual(
2074 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2075 rarely(slowCase), usually(inBounds));
2076
2077 LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath);
2078 LValue doubleValue = m_out.loadDouble(
2079 baseIndex(heap, storage, index, m_node->child2()));
2080 m_out.branch(
2081 m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue),
2082 rarely(slowCase), usually(boxPath));
2083
2084 m_out.appendTo(boxPath, slowCase);
2085 ValueFromBlock fastResult = m_out.anchor(boxDouble(doubleValue));
2086 m_out.jump(continuation);
2087
2088 m_out.appendTo(slowCase, continuation);
2089 ValueFromBlock slowResult = m_out.anchor(
2090 vmCall(m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2091 m_out.jump(continuation);
2092
2093 m_out.appendTo(continuation, lastNext);
2094 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2095 return;
2096 }
2097
2098 case Array::Generic: {
2099 setJSValue(vmCall(
2100 m_out.operation(operationGetByVal), m_callFrame,
2101 lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
2102 return;
2103 }
2104
2105 case Array::String: {
2106 compileStringCharAt();
2107 return;
2108 }
2109
2110 default: {
2111 LValue index = lowInt32(m_node->child2());
2112 LValue storage = lowStorage(m_node->child3());
2113
2114 TypedArrayType type = m_node->arrayMode().typedArrayType();
2115
2116 if (isTypedView(type)) {
2117 TypedPointer pointer = TypedPointer(
2118 m_heaps.typedArrayProperties,
2119 m_out.add(
2120 storage,
2121 m_out.shl(
2122 m_out.zeroExt(index, m_out.intPtr),
2123 m_out.constIntPtr(logElementSize(type)))));
2124
2125 if (isInt(type)) {
2126 LValue result;
2127 switch (elementSize(type)) {
2128 case 1:
2129 result = m_out.load8(pointer);
2130 break;
2131 case 2:
2132 result = m_out.load16(pointer);
2133 break;
2134 case 4:
2135 result = m_out.load32(pointer);
2136 break;
2137 default:
2138 RELEASE_ASSERT_NOT_REACHED();
2139 }
2140
2141 if (elementSize(type) < 4) {
2142 if (isSigned(type))
2143 result = m_out.signExt(result, m_out.int32);
2144 else
2145 result = m_out.zeroExt(result, m_out.int32);
2146 setInt32(result);
2147 return;
2148 }
2149
2150 if (isSigned(type)) {
2151 setInt32(result);
2152 return;
2153 }
2154
2155 if (m_node->shouldSpeculateInt32()) {
2156 speculate(
2157 Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero));
2158 setInt32(result);
2159 return;
2160 }
2161
2162 if (m_node->shouldSpeculateMachineInt()) {
2163 setStrictInt52(m_out.zeroExt(result, m_out.int64));
2164 return;
2165 }
2166
2167 setDouble(m_out.unsignedToFP(result, m_out.doubleType));
2168 return;
2169 }
2170
2171 ASSERT(isFloat(type));
2172
2173 LValue result;
2174 switch (type) {
2175 case TypeFloat32:
2176 result = m_out.fpCast(m_out.loadFloat(pointer), m_out.doubleType);
2177 break;
2178 case TypeFloat64:
2179 result = m_out.loadDouble(pointer);
2180 break;
2181 default:
2182 RELEASE_ASSERT_NOT_REACHED();
2183 }
2184
2185 setDouble(result);
2186 return;
2187 }
2188
2189 RELEASE_ASSERT_NOT_REACHED();
2190 return;
2191 } }
2192 }
2193
2194 void compilePutByVal()
2195 {
2196 Edge child1 = m_graph.varArgChild(m_node, 0);
2197 Edge child2 = m_graph.varArgChild(m_node, 1);
2198 Edge child3 = m_graph.varArgChild(m_node, 2);
2199 Edge child4 = m_graph.varArgChild(m_node, 3);
2200 Edge child5 = m_graph.varArgChild(m_node, 4);
2201
2202 switch (m_node->arrayMode().type()) {
2203 case Array::Generic: {
2204 V_JITOperation_EJJJ operation;
2205 if (m_node->op() == PutByValDirect) {
2206 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2207 operation = operationPutByValDirectStrict;
2208 else
2209 operation = operationPutByValDirectNonStrict;
2210 } else {
2211 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2212 operation = operationPutByValStrict;
2213 else
2214 operation = operationPutByValNonStrict;
2215 }
2216
2217 vmCall(
2218 m_out.operation(operation), m_callFrame,
2219 lowJSValue(child1), lowJSValue(child2), lowJSValue(child3));
2220 return;
2221 }
2222
2223 default:
2224 break;
2225 }
2226
2227 LValue base = lowCell(child1);
2228 LValue index = lowInt32(child2);
2229 LValue storage = lowStorage(child4);
2230
2231 switch (m_node->arrayMode().type()) {
2232 case Array::Int32:
2233 case Array::Double:
2234 case Array::Contiguous: {
2235 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal continuation"));
2236 LBasicBlock outerLastNext = m_out.appendTo(m_out.m_block, continuation);
2237
2238 switch (m_node->arrayMode().type()) {
2239 case Array::Int32:
2240 case Array::Contiguous: {
2241 LValue value = lowJSValue(child3, ManualOperandSpeculation);
2242
2243 if (m_node->arrayMode().type() == Array::Int32)
2244 FTL_TYPE_CHECK(jsValueValue(value), child3, SpecInt32, isNotInt32(value));
2245
2246 TypedPointer elementPointer = m_out.baseIndex(
2247 m_node->arrayMode().type() == Array::Int32 ?
2248 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties,
2249 storage, m_out.zeroExt(index, m_out.intPtr),
2250 m_state.forNode(child2).m_value);
2251
2252 if (m_node->op() == PutByValAlias) {
2253 m_out.store64(value, elementPointer);
2254 break;
2255 }
2256
2257 contiguousPutByValOutOfBounds(
2258 codeBlock()->isStrictMode()
2259 ? operationPutByValBeyondArrayBoundsStrict
2260 : operationPutByValBeyondArrayBoundsNonStrict,
2261 base, storage, index, value, continuation);
2262
2263 m_out.store64(value, elementPointer);
2264 break;
2265 }
2266
2267 case Array::Double: {
2268 LValue value = lowDouble(child3);
2269
2270 FTL_TYPE_CHECK(
2271 doubleValue(value), child3, SpecDoubleReal,
2272 m_out.doubleNotEqualOrUnordered(value, value));
2273
2274 TypedPointer elementPointer = m_out.baseIndex(
2275 m_heaps.indexedDoubleProperties,
2276 storage, m_out.zeroExt(index, m_out.intPtr),
2277 m_state.forNode(child2).m_value);
2278
2279 if (m_node->op() == PutByValAlias) {
2280 m_out.storeDouble(value, elementPointer);
2281 break;
2282 }
2283
2284 contiguousPutByValOutOfBounds(
2285 codeBlock()->isStrictMode()
2286 ? operationPutDoubleByValBeyondArrayBoundsStrict
2287 : operationPutDoubleByValBeyondArrayBoundsNonStrict,
2288 base, storage, index, value, continuation);
2289
2290 m_out.storeDouble(value, elementPointer);
2291 break;
2292 }
2293
2294 default:
2295 RELEASE_ASSERT_NOT_REACHED();
2296 }
2297
2298 m_out.jump(continuation);
2299 m_out.appendTo(continuation, outerLastNext);
2300 return;
2301 }
2302
2303 default:
2304 TypedArrayType type = m_node->arrayMode().typedArrayType();
2305
2306 if (isTypedView(type)) {
2307 TypedPointer pointer = TypedPointer(
2308 m_heaps.typedArrayProperties,
2309 m_out.add(
2310 storage,
2311 m_out.shl(
2312 m_out.zeroExt(index, m_out.intPtr),
2313 m_out.constIntPtr(logElementSize(type)))));
2314
2315 LType refType;
2316 LValue valueToStore;
2317
2318 if (isInt(type)) {
2319 LValue intValue;
2320 switch (child3.useKind()) {
2321 case Int52RepUse:
2322 case Int32Use: {
2323 if (child3.useKind() == Int32Use)
2324 intValue = lowInt32(child3);
2325 else
2326 intValue = m_out.castToInt32(lowStrictInt52(child3));
2327
2328 if (isClamped(type)) {
2329 ASSERT(elementSize(type) == 1);
2330
2331 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp atLeastZero"));
2332 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp continuation"));
2333
2334 Vector<ValueFromBlock, 2> intValues;
2335 intValues.append(m_out.anchor(m_out.int32Zero));
2336 m_out.branch(
2337 m_out.lessThan(intValue, m_out.int32Zero),
2338 unsure(continuation), unsure(atLeastZero));
2339
2340 LBasicBlock lastNext = m_out.appendTo(atLeastZero, continuation);
2341
2342 intValues.append(m_out.anchor(m_out.select(
2343 m_out.greaterThan(intValue, m_out.constInt32(255)),
2344 m_out.constInt32(255),
2345 intValue)));
2346 m_out.jump(continuation);
2347
2348 m_out.appendTo(continuation, lastNext);
2349 intValue = m_out.phi(m_out.int32, intValues);
2350 }
2351 break;
2352 }
2353
2354 case DoubleRepUse: {
2355 LValue doubleValue = lowDouble(child3);
2356
2357 if (isClamped(type)) {
2358 ASSERT(elementSize(type) == 1);
2359
2360 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp atLeastZero"));
2361 LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp withinRange"));
2362 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp continuation"));
2363
2364 Vector<ValueFromBlock, 3> intValues;
2365 intValues.append(m_out.anchor(m_out.int32Zero));
2366 m_out.branch(
2367 m_out.doubleLessThanOrUnordered(doubleValue, m_out.doubleZero),
2368 unsure(continuation), unsure(atLeastZero));
2369
2370 LBasicBlock lastNext = m_out.appendTo(atLeastZero, withinRange);
2371 intValues.append(m_out.anchor(m_out.constInt32(255)));
2372 m_out.branch(
2373 m_out.doubleGreaterThan(doubleValue, m_out.constDouble(255)),
2374 unsure(continuation), unsure(withinRange));
2375
2376 m_out.appendTo(withinRange, continuation);
2377 intValues.append(m_out.anchor(m_out.fpToInt32(doubleValue)));
2378 m_out.jump(continuation);
2379
2380 m_out.appendTo(continuation, lastNext);
2381 intValue = m_out.phi(m_out.int32, intValues);
2382 } else
2383 intValue = doubleToInt32(doubleValue);
2384 break;
2385 }
2386
2387 default:
2388 RELEASE_ASSERT_NOT_REACHED();
2389 }
2390
2391 switch (elementSize(type)) {
2392 case 1:
2393 valueToStore = m_out.intCast(intValue, m_out.int8);
2394 refType = m_out.ref8;
2395 break;
2396 case 2:
2397 valueToStore = m_out.intCast(intValue, m_out.int16);
2398 refType = m_out.ref16;
2399 break;
2400 case 4:
2401 valueToStore = intValue;
2402 refType = m_out.ref32;
2403 break;
2404 default:
2405 RELEASE_ASSERT_NOT_REACHED();
2406 }
2407 } else /* !isInt(type) */ {
2408 LValue value = lowDouble(child3);
2409 switch (type) {
2410 case TypeFloat32:
2411 valueToStore = m_out.fpCast(value, m_out.floatType);
2412 refType = m_out.refFloat;
2413 break;
2414 case TypeFloat64:
2415 valueToStore = value;
2416 refType = m_out.refDouble;
2417 break;
2418 default:
2419 RELEASE_ASSERT_NOT_REACHED();
2420 }
2421 }
2422
2423 if (m_node->arrayMode().isInBounds() || m_node->op() == PutByValAlias)
2424 m_out.store(valueToStore, pointer, refType);
2425 else {
2426 LBasicBlock isInBounds = FTL_NEW_BLOCK(m_out, ("PutByVal typed array in bounds case"));
2427 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal typed array continuation"));
2428
2429 m_out.branch(
2430 m_out.aboveOrEqual(index, lowInt32(child5)),
2431 unsure(continuation), unsure(isInBounds));
2432
2433 LBasicBlock lastNext = m_out.appendTo(isInBounds, continuation);
2434 m_out.store(valueToStore, pointer, refType);
2435 m_out.jump(continuation);
2436
2437 m_out.appendTo(continuation, lastNext);
2438 }
2439
2440 return;
2441 }
2442
2443 RELEASE_ASSERT_NOT_REACHED();
2444 break;
2445 }
2446 }
2447
2448 void compileArrayPush()
2449 {
2450 LValue base = lowCell(m_node->child1());
2451 LValue storage = lowStorage(m_node->child3());
2452
2453 switch (m_node->arrayMode().type()) {
2454 case Array::Int32:
2455 case Array::Contiguous:
2456 case Array::Double: {
2457 LValue value;
2458 LType refType;
2459
2460 if (m_node->arrayMode().type() != Array::Double) {
2461 value = lowJSValue(m_node->child2(), ManualOperandSpeculation);
2462 if (m_node->arrayMode().type() == Array::Int32) {
2463 FTL_TYPE_CHECK(
2464 jsValueValue(value), m_node->child2(), SpecInt32, isNotInt32(value));
2465 }
2466 refType = m_out.ref64;
2467 } else {
2468 value = lowDouble(m_node->child2());
2469 FTL_TYPE_CHECK(
2470 doubleValue(value), m_node->child2(), SpecDoubleReal,
2471 m_out.doubleNotEqualOrUnordered(value, value));
2472 refType = m_out.refDouble;
2473 }
2474
2475 IndexedAbstractHeap& heap = m_heaps.forArrayType(m_node->arrayMode().type());
2476
2477 LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
2478
2479 LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("ArrayPush fast path"));
2480 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("ArrayPush slow path"));
2481 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayPush continuation"));
2482
2483 m_out.branch(
2484 m_out.aboveOrEqual(
2485 prevLength, m_out.load32(storage, m_heaps.Butterfly_vectorLength)),
2486 rarely(slowPath), usually(fastPath));
2487
2488 LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
2489 m_out.store(
2490 value,
2491 m_out.baseIndex(heap, storage, m_out.zeroExt(prevLength, m_out.intPtr)),
2492 refType);
2493 LValue newLength = m_out.add(prevLength, m_out.int32One);
2494 m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
2495
2496 ValueFromBlock fastResult = m_out.anchor(boxInt32(newLength));
2497 m_out.jump(continuation);
2498
2499 m_out.appendTo(slowPath, continuation);
2500 LValue operation;
2501 if (m_node->arrayMode().type() != Array::Double)
2502 operation = m_out.operation(operationArrayPush);
2503 else
2504 operation = m_out.operation(operationArrayPushDouble);
2505 ValueFromBlock slowResult = m_out.anchor(
2506 vmCall(operation, m_callFrame, value, base));
2507 m_out.jump(continuation);
2508
2509 m_out.appendTo(continuation, lastNext);
2510 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2511 return;
2512 }
2513
2514 default:
2515 RELEASE_ASSERT_NOT_REACHED();
2516 return;
2517 }
2518 }
2519
2520 void compileArrayPop()
2521 {
2522 LValue base = lowCell(m_node->child1());
2523 LValue storage = lowStorage(m_node->child2());
2524
2525 switch (m_node->arrayMode().type()) {
2526 case Array::Int32:
2527 case Array::Double:
2528 case Array::Contiguous: {
2529 IndexedAbstractHeap& heap = m_heaps.forArrayType(m_node->arrayMode().type());
2530
2531 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("ArrayPop fast case"));
2532 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArrayPop slow case"));
2533 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayPop continuation"));
2534
2535 LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
2536
2537 Vector<ValueFromBlock, 3> results;
2538 results.append(m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined()))));
2539 m_out.branch(
2540 m_out.isZero32(prevLength), rarely(continuation), usually(fastCase));
2541
2542 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
2543 LValue newLength = m_out.sub(prevLength, m_out.int32One);
2544 m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength);
2545 TypedPointer pointer = m_out.baseIndex(
2546 heap, storage, m_out.zeroExt(newLength, m_out.intPtr));
2547 if (m_node->arrayMode().type() != Array::Double) {
2548 LValue result = m_out.load64(pointer);
2549 m_out.store64(m_out.int64Zero, pointer);
2550 results.append(m_out.anchor(result));
2551 m_out.branch(
2552 m_out.notZero64(result), usually(continuation), rarely(slowCase));
2553 } else {
2554 LValue result = m_out.loadDouble(pointer);
2555 m_out.store64(m_out.constInt64(bitwise_cast<int64_t>(PNaN)), pointer);
2556 results.append(m_out.anchor(boxDouble(result)));
2557 m_out.branch(
2558 m_out.doubleEqual(result, result),
2559 usually(continuation), rarely(slowCase));
2560 }
2561
2562 m_out.appendTo(slowCase, continuation);
2563 results.append(m_out.anchor(vmCall(
2564 m_out.operation(operationArrayPopAndRecoverLength), m_callFrame, base)));
2565 m_out.jump(continuation);
2566
2567 m_out.appendTo(continuation, lastNext);
2568 setJSValue(m_out.phi(m_out.int64, results));
2569 return;
2570 }
2571
2572 default:
2573 RELEASE_ASSERT_NOT_REACHED();
2574 return;
2575 }
2576 }
2577
2578 void compileNewObject()
2579 {
2580 Structure* structure = m_node->structure();
2581 size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity());
2582 MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize);
2583
2584 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("NewObject slow path"));
2585 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewObject continuation"));
2586
2587 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
2588
2589 ValueFromBlock fastResult = m_out.anchor(allocateObject(
2590 m_out.constIntPtr(allocator), structure, m_out.intPtrZero, slowPath));
2591
2592 m_out.jump(continuation);
2593
2594 m_out.appendTo(slowPath, continuation);
2595
2596 ValueFromBlock slowResult = m_out.anchor(vmCall(
2597 m_out.operation(operationNewObject), m_callFrame, m_out.constIntPtr(structure)));
2598 m_out.jump(continuation);
2599
2600 m_out.appendTo(continuation, lastNext);
2601 setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult));
2602 }
2603
2604 void compileNewArray()
2605 {
2606 // First speculate appropriately on all of the children. Do this unconditionally up here
2607 // because some of the slow paths may otherwise forget to do it. It's sort of arguable
2608 // that doing the speculations up here might be unprofitable for RA - so we can consider
2609 // sinking this to below the allocation fast path if we find that this has a lot of
2610 // register pressure.
2611 for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex)
2612 speculate(m_graph.varArgChild(m_node, operandIndex));
2613
2614 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
2615 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
2616 m_node->indexingType());
2617
2618 RELEASE_ASSERT(structure->indexingType() == m_node->indexingType());
2619
2620 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
2621 unsigned numElements = m_node->numChildren();
2622
2623 ArrayValues arrayValues = allocateJSArray(structure, numElements);
2624
2625 for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) {
2626 Edge edge = m_graph.varArgChild(m_node, operandIndex);
2627
2628 switch (m_node->indexingType()) {
2629 case ALL_BLANK_INDEXING_TYPES:
2630 case ALL_UNDECIDED_INDEXING_TYPES:
2631 CRASH();
2632 break;
2633
2634 case ALL_DOUBLE_INDEXING_TYPES:
2635 m_out.storeDouble(
2636 lowDouble(edge),
2637 arrayValues.butterfly, m_heaps.indexedDoubleProperties[operandIndex]);
2638 break;
2639
2640 case ALL_INT32_INDEXING_TYPES:
2641 case ALL_CONTIGUOUS_INDEXING_TYPES:
2642 m_out.store64(
2643 lowJSValue(edge, ManualOperandSpeculation),
2644 arrayValues.butterfly,
2645 m_heaps.forIndexingType(m_node->indexingType())->at(operandIndex));
2646 break;
2647
2648 default:
2649 CRASH();
2650 }
2651 }
2652
2653 setJSValue(arrayValues.array);
2654 return;
2655 }
2656
2657 if (!m_node->numChildren()) {
2658 setJSValue(vmCall(
2659 m_out.operation(operationNewEmptyArray), m_callFrame,
2660 m_out.constIntPtr(structure)));
2661 return;
2662 }
2663
2664 size_t scratchSize = sizeof(EncodedJSValue) * m_node->numChildren();
2665 ASSERT(scratchSize);
2666 ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize);
2667 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
2668
2669 for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) {
2670 Edge edge = m_graph.varArgChild(m_node, operandIndex);
2671 m_out.store64(
2672 lowJSValue(edge, ManualOperandSpeculation),
2673 m_out.absolute(buffer + operandIndex));
2674 }
2675
2676 m_out.storePtr(
2677 m_out.constIntPtr(scratchSize), m_out.absolute(scratchBuffer->activeLengthPtr()));
2678
2679 LValue result = vmCall(
2680 m_out.operation(operationNewArray), m_callFrame,
2681 m_out.constIntPtr(structure), m_out.constIntPtr(buffer),
2682 m_out.constIntPtr(m_node->numChildren()));
2683
2684 m_out.storePtr(m_out.intPtrZero, m_out.absolute(scratchBuffer->activeLengthPtr()));
2685
2686 setJSValue(result);
2687 }
2688
2689 void compileNewArrayBuffer()
2690 {
2691 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
2692 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
2693 m_node->indexingType());
2694
2695 RELEASE_ASSERT(structure->indexingType() == m_node->indexingType());
2696
2697 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
2698 unsigned numElements = m_node->numConstants();
2699
2700 ArrayValues arrayValues = allocateJSArray(structure, numElements);
2701
2702 JSValue* data = codeBlock()->constantBuffer(m_node->startConstant());
2703 for (unsigned index = 0; index < m_node->numConstants(); ++index) {
2704 int64_t value;
2705 if (hasDouble(m_node->indexingType()))
2706 value = bitwise_cast<int64_t>(data[index].asNumber());
2707 else
2708 value = JSValue::encode(data[index]);
2709
2710 m_out.store64(
2711 m_out.constInt64(value),
2712 arrayValues.butterfly,
2713 m_heaps.forIndexingType(m_node->indexingType())->at(index));
2714 }
2715
2716 setJSValue(arrayValues.array);
2717 return;
2718 }
2719
2720 setJSValue(vmCall(
2721 m_out.operation(operationNewArrayBuffer), m_callFrame,
2722 m_out.constIntPtr(structure), m_out.constIntPtr(m_node->startConstant()),
2723 m_out.constIntPtr(m_node->numConstants())));
2724 }
2725
2726 void compileNewArrayWithSize()
2727 {
2728 LValue publicLength = lowInt32(m_node->child1());
2729
2730 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
2731 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(
2732 m_node->indexingType());
2733
2734 if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) {
2735 ASSERT(
2736 hasUndecided(structure->indexingType())
2737 || hasInt32(structure->indexingType())
2738 || hasDouble(structure->indexingType())
2739 || hasContiguous(structure->indexingType()));
2740
2741 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize fast case"));
2742 LBasicBlock largeCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize large case"));
2743 LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize fail case"));
2744 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize slow case"));
2745 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize continuation"));
2746
2747 m_out.branch(
2748 m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)),
2749 rarely(largeCase), usually(fastCase));
2750
2751 LBasicBlock lastNext = m_out.appendTo(fastCase, largeCase);
2752
2753 // We don't round up to BASE_VECTOR_LEN for new Array(blah).
2754 LValue vectorLength = publicLength;
2755
2756 LValue payloadSize =
2757 m_out.shl(m_out.zeroExt(vectorLength, m_out.intPtr), m_out.constIntPtr(3));
2758
2759 LValue butterflySize = m_out.add(
2760 payloadSize, m_out.constIntPtr(sizeof(IndexingHeader)));
2761
2762 LValue endOfStorage = allocateBasicStorageAndGetEnd(butterflySize, failCase);
2763
2764 LValue butterfly = m_out.sub(endOfStorage, payloadSize);
2765
2766 LValue object = allocateObject<JSArray>(
2767 structure, butterfly, failCase);
2768
2769 m_out.store32(publicLength, butterfly, m_heaps.Butterfly_publicLength);
2770 m_out.store32(vectorLength, butterfly, m_heaps.Butterfly_vectorLength);
2771
2772 if (hasDouble(m_node->indexingType())) {
2773 LBasicBlock initLoop = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize double init loop"));
2774 LBasicBlock initDone = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize double init done"));
2775
2776 ValueFromBlock originalIndex = m_out.anchor(vectorLength);
2777 ValueFromBlock originalPointer = m_out.anchor(butterfly);
2778 m_out.branch(
2779 m_out.notZero32(vectorLength), unsure(initLoop), unsure(initDone));
2780
2781 LBasicBlock initLastNext = m_out.appendTo(initLoop, initDone);
2782 LValue index = m_out.phi(m_out.int32, originalIndex);
2783 LValue pointer = m_out.phi(m_out.intPtr, originalPointer);
2784
2785 m_out.store64(
2786 m_out.constInt64(bitwise_cast<int64_t>(PNaN)),
2787 TypedPointer(m_heaps.indexedDoubleProperties.atAnyIndex(), pointer));
2788
2789 LValue nextIndex = m_out.sub(index, m_out.int32One);
2790 addIncoming(index, m_out.anchor(nextIndex));
2791 addIncoming(pointer, m_out.anchor(m_out.add(pointer, m_out.intPtrEight)));
2792 m_out.branch(
2793 m_out.notZero32(nextIndex), unsure(initLoop), unsure(initDone));
2794
2795 m_out.appendTo(initDone, initLastNext);
2796 }
2797
2798 ValueFromBlock fastResult = m_out.anchor(object);
2799 m_out.jump(continuation);
2800
2801 m_out.appendTo(largeCase, failCase);
2802 ValueFromBlock largeStructure = m_out.anchor(m_out.constIntPtr(
2803 globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)));
2804 m_out.jump(slowCase);
2805
2806 m_out.appendTo(failCase, slowCase);
2807 ValueFromBlock failStructure = m_out.anchor(m_out.constIntPtr(structure));
2808 m_out.jump(slowCase);
2809
2810 m_out.appendTo(slowCase, continuation);
2811 LValue structureValue = m_out.phi(
2812 m_out.intPtr, largeStructure, failStructure);
2813 ValueFromBlock slowResult = m_out.anchor(vmCall(
2814 m_out.operation(operationNewArrayWithSize),
2815 m_callFrame, structureValue, publicLength));
2816 m_out.jump(continuation);
2817
2818 m_out.appendTo(continuation, lastNext);
2819 setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult));
2820 return;
2821 }
2822
2823 LValue structureValue = m_out.select(
2824 m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)),
2825 m_out.constIntPtr(
2826 globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)),
2827 m_out.constIntPtr(structure));
2828 setJSValue(vmCall(m_out.operation(operationNewArrayWithSize), m_callFrame, structureValue, publicLength));
2829 }
2830
2831 void compileAllocatePropertyStorage()
2832 {
2833 StructureTransitionData& data = m_node->structureTransitionData();
2834 LValue object = lowCell(m_node->child1());
2835
2836 setStorage(allocatePropertyStorage(object, data.previousStructure));
2837 }
2838
2839 void compileReallocatePropertyStorage()
2840 {
2841 StructureTransitionData& data = m_node->structureTransitionData();
2842 LValue object = lowCell(m_node->child1());
2843 LValue oldStorage = lowStorage(m_node->child2());
2844
2845 setStorage(
2846 reallocatePropertyStorage(
2847 object, oldStorage, data.previousStructure, data.newStructure));
2848 }
2849
2850 void compileToString()
2851 {
2852 switch (m_node->child1().useKind()) {
2853 case StringObjectUse: {
2854 LValue cell = lowCell(m_node->child1());
2855 speculateStringObjectForCell(m_node->child1(), cell);
2856 m_interpreter.filter(m_node->child1(), SpecStringObject);
2857
2858 setJSValue(m_out.loadPtr(cell, m_heaps.JSWrapperObject_internalValue));
2859 return;
2860 }
2861
2862 case StringOrStringObjectUse: {
2863 LValue cell = lowCell(m_node->child1());
2864 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2865
2866 LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("ToString StringOrStringObject not string case"));
2867 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToString StringOrStringObject continuation"));
2868
2869 ValueFromBlock simpleResult = m_out.anchor(cell);
2870 m_out.branch(
2871 m_out.equal(structureID, m_out.constInt32(vm().stringStructure->id())),
2872 unsure(continuation), unsure(notString));
2873
2874 LBasicBlock lastNext = m_out.appendTo(notString, continuation);
2875 speculateStringObjectForStructureID(m_node->child1(), structureID);
2876 ValueFromBlock unboxedResult = m_out.anchor(
2877 m_out.loadPtr(cell, m_heaps.JSWrapperObject_internalValue));
2878 m_out.jump(continuation);
2879
2880 m_out.appendTo(continuation, lastNext);
2881 setJSValue(m_out.phi(m_out.int64, simpleResult, unboxedResult));
2882
2883 m_interpreter.filter(m_node->child1(), SpecString | SpecStringObject);
2884 return;
2885 }
2886
2887 case CellUse:
2888 case UntypedUse: {
2889 LValue value;
2890 if (m_node->child1().useKind() == CellUse)
2891 value = lowCell(m_node->child1());
2892 else
2893 value = lowJSValue(m_node->child1());
2894
2895 LBasicBlock isCell = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse is cell"));
2896 LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse not string"));
2897 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToString CellUse/UntypedUse continuation"));
2898
2899 LValue isCellPredicate;
2900 if (m_node->child1().useKind() == CellUse)
2901 isCellPredicate = m_out.booleanTrue;
2902 else
2903 isCellPredicate = this->isCell(value);
2904 m_out.branch(isCellPredicate, unsure(isCell), unsure(notString));
2905
2906 LBasicBlock lastNext = m_out.appendTo(isCell, notString);
2907 ValueFromBlock simpleResult = m_out.anchor(value);
2908 LValue isStringPredicate;
2909 if (m_node->child1()->prediction() & SpecString) {
2910 isStringPredicate = m_out.equal(
2911 m_out.load32(value, m_heaps.JSCell_structureID),
2912 m_out.constInt32(vm().stringStructure->id()));
2913 } else
2914 isStringPredicate = m_out.booleanFalse;
2915 m_out.branch(isStringPredicate, unsure(continuation), unsure(notString));
2916
2917 m_out.appendTo(notString, continuation);
2918 LValue operation;
2919 if (m_node->child1().useKind() == CellUse)
2920 operation = m_out.operation(operationToStringOnCell);
2921 else
2922 operation = m_out.operation(operationToString);
2923 ValueFromBlock convertedResult = m_out.anchor(vmCall(operation, m_callFrame, value));
2924 m_out.jump(continuation);
2925
2926 m_out.appendTo(continuation, lastNext);
2927 setJSValue(m_out.phi(m_out.int64, simpleResult, convertedResult));
2928 return;
2929 }
2930
2931 default:
2932 RELEASE_ASSERT_NOT_REACHED();
2933 break;
2934 }
2935 }
2936
2937 void compileToPrimitive()
2938 {
2939 LValue value = lowJSValue(m_node->child1());
2940
2941 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("ToPrimitive cell case"));
2942 LBasicBlock isObjectCase = FTL_NEW_BLOCK(m_out, ("ToPrimitive object case"));
2943 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToPrimitive continuation"));
2944
2945 Vector<ValueFromBlock, 3> results;
2946
2947 results.append(m_out.anchor(value));
2948 m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation));
2949
2950 LBasicBlock lastNext = m_out.appendTo(isCellCase, isObjectCase);
2951 results.append(m_out.anchor(value));
2952 m_out.branch(isObject(value), unsure(isObjectCase), unsure(continuation));
2953
2954 m_out.appendTo(isObjectCase, continuation);
2955 results.append(m_out.anchor(vmCall(
2956 m_out.operation(operationToPrimitive), m_callFrame, value)));
2957 m_out.jump(continuation);
2958
2959 m_out.appendTo(continuation, lastNext);
2960 setJSValue(m_out.phi(m_out.int64, results));
2961 }
2962
2963 void compileMakeRope()
2964 {
2965 LValue kids[3];
2966 unsigned numKids;
2967 kids[0] = lowCell(m_node->child1());
2968 kids[1] = lowCell(m_node->child2());
2969 if (m_node->child3()) {
2970 kids[2] = lowCell(m_node->child3());
2971 numKids = 3;
2972 } else {
2973 kids[2] = 0;
2974 numKids = 2;
2975 }
2976
2977 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("MakeRope slow path"));
2978 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MakeRope continuation"));
2979
2980 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
2981
2982 MarkedAllocator& allocator =
2983 vm().heap.allocatorForObjectWithImmortalStructureDestructor(sizeof(JSRopeString));
2984
2985 LValue result = allocateCell(
2986 m_out.constIntPtr(&allocator),
2987 vm().stringStructure.get(),
2988 slowPath);
2989
2990 m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSString_value);
2991 for (unsigned i = 0; i < numKids; ++i)
2992 m_out.storePtr(kids[i], result, m_heaps.JSRopeString_fibers[i]);
2993 for (unsigned i = numKids; i < JSRopeString::s_maxInternalRopeLength; ++i)
2994 m_out.storePtr(m_out.intPtrZero, result, m_heaps.JSRopeString_fibers[i]);
2995 LValue flags = m_out.load32(kids[0], m_heaps.JSString_flags);
2996 LValue length = m_out.load32(kids[0], m_heaps.JSString_length);
2997 for (unsigned i = 1; i < numKids; ++i) {
2998 flags = m_out.bitAnd(flags, m_out.load32(kids[i], m_heaps.JSString_flags));
2999 LValue lengthAndOverflow = m_out.addWithOverflow32(
3000 length, m_out.load32(kids[i], m_heaps.JSString_length));
3001 speculate(Uncountable, noValue(), 0, m_out.extractValue(lengthAndOverflow, 1));
3002 length = m_out.extractValue(lengthAndOverflow, 0);
3003 }
3004 m_out.store32(
3005 m_out.bitAnd(m_out.constInt32(JSString::Is8Bit), flags),
3006 result, m_heaps.JSString_flags);
3007 m_out.store32(length, result, m_heaps.JSString_length);
3008
3009 ValueFromBlock fastResult = m_out.anchor(result);
3010 m_out.jump(continuation);
3011
3012 m_out.appendTo(slowPath, continuation);
3013 ValueFromBlock slowResult;
3014 switch (numKids) {
3015 case 2:
3016 slowResult = m_out.anchor(vmCall(
3017 m_out.operation(operationMakeRope2), m_callFrame, kids[0], kids[1]));
3018 break;
3019 case 3:
3020 slowResult = m_out.anchor(vmCall(
3021 m_out.operation(operationMakeRope3), m_callFrame, kids[0], kids[1], kids[2]));
3022 break;
3023 default:
3024 RELEASE_ASSERT_NOT_REACHED();
3025 break;
3026 }
3027 m_out.jump(continuation);
3028
3029 m_out.appendTo(continuation, lastNext);
3030 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
3031 }
3032
3033 void compileStringCharAt()
3034 {
3035 LValue base = lowCell(m_node->child1());
3036 LValue index = lowInt32(m_node->child2());
3037 LValue storage = lowStorage(m_node->child3());
3038
3039 LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("GetByVal String fast path"));
3040 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("GetByVal String slow path"));
3041 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal String continuation"));
3042
3043 m_out.branch(
3044 m_out.aboveOrEqual(
3045 index, m_out.load32NonNegative(base, m_heaps.JSString_length)),
3046 rarely(slowPath), usually(fastPath));
3047
3048 LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath);
3049
3050 LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
3051
3052 LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("GetByVal String 8-bit case"));
3053 LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("GetByVal String 16-bit case"));
3054 LBasicBlock bitsContinuation = FTL_NEW_BLOCK(m_out, ("GetByVal String bitness continuation"));
3055 LBasicBlock bigCharacter = FTL_NEW_BLOCK(m_out, ("GetByVal String big character"));
3056
3057 m_out.branch(
3058 m_out.testIsZero32(
3059 m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
3060 m_out.constInt32(StringImpl::flagIs8Bit())),
3061 unsure(is16Bit), unsure(is8Bit));
3062
3063 m_out.appendTo(is8Bit, is16Bit);
3064
3065 ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt(
3066 m_out.load8(m_out.baseIndex(
3067 m_heaps.characters8,
3068 storage, m_out.zeroExt(index, m_out.intPtr),
3069 m_state.forNode(m_node->child2()).m_value)),
3070 m_out.int32));
3071 m_out.jump(bitsContinuation);
3072
3073 m_out.appendTo(is16Bit, bigCharacter);
3074
3075 ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt(
3076 m_out.load16(m_out.baseIndex(
3077 m_heaps.characters16,
3078 storage, m_out.zeroExt(index, m_out.intPtr),
3079 m_state.forNode(m_node->child2()).m_value)),
3080 m_out.int32));
3081 m_out.branch(
3082 m_out.aboveOrEqual(char16Bit.value(), m_out.constInt32(0x100)),
3083 rarely(bigCharacter), usually(bitsContinuation));
3084
3085 m_out.appendTo(bigCharacter, bitsContinuation);
3086
3087 Vector<ValueFromBlock, 4> results;
3088 results.append(m_out.anchor(vmCall(
3089 m_out.operation(operationSingleCharacterString),
3090 m_callFrame, char16Bit.value())));
3091 m_out.jump(continuation);
3092
3093 m_out.appendTo(bitsContinuation, slowPath);
3094
3095 LValue character = m_out.phi(m_out.int32, char8Bit, char16Bit);
3096
3097 LValue smallStrings = m_out.constIntPtr(vm().smallStrings.singleCharacterStrings());
3098
3099 results.append(m_out.anchor(m_out.loadPtr(m_out.baseIndex(
3100 m_heaps.singleCharacterStrings, smallStrings,
3101 m_out.zeroExt(character, m_out.intPtr)))));
3102 m_out.jump(continuation);
3103
3104 m_out.appendTo(slowPath, continuation);
3105
3106 if (m_node->arrayMode().isInBounds()) {
3107 speculate(OutOfBounds, noValue(), 0, m_out.booleanTrue);
3108 results.append(m_out.anchor(m_out.intPtrZero));
3109 } else {
3110 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
3111
3112 if (globalObject->stringPrototypeChainIsSane()) {
3113 LBasicBlock negativeIndex = FTL_NEW_BLOCK(m_out, ("GetByVal String negative index"));
3114
3115 results.append(m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined()))));
3116 m_out.branch(
3117 m_out.lessThan(index, m_out.int32Zero),
3118 rarely(negativeIndex), usually(continuation));
3119
3120 m_out.appendTo(negativeIndex, continuation);
3121 }
3122
3123 results.append(m_out.anchor(vmCall(
3124 m_out.operation(operationGetByValStringInt), m_callFrame, base, index)));
3125 }
3126
3127 m_out.jump(continuation);
3128
3129 m_out.appendTo(continuation, lastNext);
3130 setJSValue(m_out.phi(m_out.int64, results));
3131 }
3132
3133 void compileStringCharCodeAt()
3134 {
3135 LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("StringCharCodeAt 8-bit case"));
3136 LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("StringCharCodeAt 16-bit case"));
3137 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("StringCharCodeAt continuation"));
3138
3139 LValue base = lowCell(m_node->child1());
3140 LValue index = lowInt32(m_node->child2());
3141 LValue storage = lowStorage(m_node->child3());
3142
3143 speculate(
3144 Uncountable, noValue(), 0,
3145 m_out.aboveOrEqual(
3146 index, m_out.load32NonNegative(base, m_heaps.JSString_length)));
3147
3148 LValue stringImpl = m_out.loadPtr(base, m_heaps.JSString_value);
3149
3150 m_out.branch(
3151 m_out.testIsZero32(
3152 m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
3153 m_out.constInt32(StringImpl::flagIs8Bit())),
3154 unsure(is16Bit), unsure(is8Bit));
3155
3156 LBasicBlock lastNext = m_out.appendTo(is8Bit, is16Bit);
3157
3158 ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt(
3159 m_out.load8(m_out.baseIndex(
3160 m_heaps.characters8,
3161 storage, m_out.zeroExt(index, m_out.intPtr),
3162 m_state.forNode(m_node->child2()).m_value)),
3163 m_out.int32));
3164 m_out.jump(continuation);
3165
3166 m_out.appendTo(is16Bit, continuation);
3167
3168 ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt(
3169 m_out.load16(m_out.baseIndex(
3170 m_heaps.characters16,
3171 storage, m_out.zeroExt(index, m_out.intPtr),
3172 m_state.forNode(m_node->child2()).m_value)),
3173 m_out.int32));
3174 m_out.jump(continuation);
3175
3176 m_out.appendTo(continuation, lastNext);
3177
3178 setInt32(m_out.phi(m_out.int32, char8Bit, char16Bit));
3179 }
3180
3181 void compileGetByOffset()
3182 {
3183 StorageAccessData& data =
3184 m_graph.m_storageAccessData[m_node->storageAccessDataIndex()];
3185
3186 setJSValue(loadProperty(
3187 lowStorage(m_node->child1()), data.identifierNumber, data.offset));
3188 }
3189
3190 void compileMultiGetByOffset()
3191 {
3192 LValue base = lowCell(m_node->child1());
3193
3194 MultiGetByOffsetData& data = m_node->multiGetByOffsetData();
3195
3196 Vector<LBasicBlock, 2> blocks(data.variants.size());
3197 for (unsigned i = data.variants.size(); i--;)
3198 blocks[i] = FTL_NEW_BLOCK(m_out, ("MultiGetByOffset case ", i));
3199 LBasicBlock exit = FTL_NEW_BLOCK(m_out, ("MultiGetByOffset fail"));
3200 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MultiGetByOffset continuation"));
3201
3202 Vector<SwitchCase, 2> cases;
3203 for (unsigned i = data.variants.size(); i--;) {
3204 GetByIdVariant variant = data.variants[i];
3205 for (unsigned j = variant.structureSet().size(); j--;) {
3206 cases.append(SwitchCase(
3207 weakStructure(variant.structureSet()[j]), blocks[i], Weight(1)));
3208 }
3209 }
3210 m_out.switchInstruction(
3211 m_out.load32(base, m_heaps.JSCell_structureID), cases, exit, Weight(0));
3212
3213 LBasicBlock lastNext = m_out.m_nextBlock;
3214
3215 Vector<ValueFromBlock, 2> results;
3216 for (unsigned i = data.variants.size(); i--;) {
3217 m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit);
3218
3219 GetByIdVariant variant = data.variants[i];
3220 LValue result;
3221 if (variant.specificValue())
3222 result = m_out.constInt64(JSValue::encode(variant.specificValue()));
3223 else {
3224 LValue propertyBase;
3225 if (variant.chain())
3226 propertyBase = weakPointer(variant.chain()->terminalPrototype());
3227 else
3228 propertyBase = base;
3229 if (!isInlineOffset(variant.offset()))
3230 propertyBase = m_out.loadPtr(propertyBase, m_heaps.JSObject_butterfly);
3231 result = loadProperty(propertyBase, data.identifierNumber, variant.offset());
3232 }
3233
3234 results.append(m_out.anchor(result));
3235 m_out.jump(continuation);
3236 }
3237
3238 m_out.appendTo(exit, continuation);
3239 terminate(BadCache);
3240 m_out.unreachable();
3241
3242 m_out.appendTo(continuation, lastNext);
3243 setJSValue(m_out.phi(m_out.int64, results));
3244 }
3245
3246 void compilePutByOffset()
3247 {
3248 StorageAccessData& data =
3249 m_graph.m_storageAccessData[m_node->storageAccessDataIndex()];
3250
3251 storeProperty(
3252 lowJSValue(m_node->child3()),
3253 lowStorage(m_node->child1()), data.identifierNumber, data.offset);
3254 }
3255
3256 void compileMultiPutByOffset()
3257 {
3258 LValue base = lowCell(m_node->child1());
3259 LValue value = lowJSValue(m_node->child2());
3260
3261 MultiPutByOffsetData& data = m_node->multiPutByOffsetData();
3262
3263 Vector<LBasicBlock, 2> blocks(data.variants.size());
3264 for (unsigned i = data.variants.size(); i--;)
3265 blocks[i] = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset case ", i));
3266 LBasicBlock exit = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset fail"));
3267 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset continuation"));
3268
3269 Vector<SwitchCase, 2> cases;
3270 for (unsigned i = data.variants.size(); i--;) {
3271 PutByIdVariant variant = data.variants[i];
3272 cases.append(
3273 SwitchCase(weakStructure(variant.oldStructure()), blocks[i], Weight(1)));
3274 }
3275 m_out.switchInstruction(
3276 m_out.load32(base, m_heaps.JSCell_structureID), cases, exit, Weight(0));
3277
3278 LBasicBlock lastNext = m_out.m_nextBlock;
3279
3280 for (unsigned i = data.variants.size(); i--;) {
3281 m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit);
3282
3283 PutByIdVariant variant = data.variants[i];
3284
3285 LValue storage;
3286 if (variant.kind() == PutByIdVariant::Replace) {
3287 if (isInlineOffset(variant.offset()))
3288 storage = base;
3289 else
3290 storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly);
3291 } else {
3292 m_graph.m_plan.transitions.addLazily(
3293 codeBlock(), m_node->origin.semantic.codeOriginOwner(),
3294 variant.oldStructure(), variant.newStructure());
3295
3296 storage = storageForTransition(
3297 base, variant.offset(), variant.oldStructure(), variant.newStructure());
3298
3299 ASSERT(variant.oldStructure()->indexingType() == variant.newStructure()->indexingType());
3300 ASSERT(variant.oldStructure()->typeInfo().inlineTypeFlags() == variant.newStructure()->typeInfo().inlineTypeFlags());
3301 ASSERT(variant.oldStructure()->typeInfo().type() == variant.newStructure()->typeInfo().type());
3302 m_out.store32(
3303 weakStructure(variant.newStructure()), base, m_heaps.JSCell_structureID);
3304 }
3305
3306 storeProperty(value, storage, data.identifierNumber, variant.offset());
3307 m_out.jump(continuation);
3308 }
3309
3310 m_out.appendTo(exit, continuation);
3311 terminate(BadCache);
3312 m_out.unreachable();
3313
3314 m_out.appendTo(continuation, lastNext);
3315 }
3316
3317 void compileGetGlobalVar()
3318 {
3319 setJSValue(m_out.load64(m_out.absolute(m_node->registerPointer())));
3320 }
3321
3322 void compilePutGlobalVar()
3323 {
3324 m_out.store64(
3325 lowJSValue(m_node->child1()), m_out.absolute(m_node->registerPointer()));
3326 }
3327
3328 void compileNotifyWrite()
3329 {
3330 VariableWatchpointSet* set = m_node->variableWatchpointSet();
3331
3332 LValue value = lowJSValue(m_node->child1());
3333
3334 LBasicBlock isNotInvalidated = FTL_NEW_BLOCK(m_out, ("NotifyWrite not invalidated case"));
3335 LBasicBlock notifySlow = FTL_NEW_BLOCK(m_out, ("NotifyWrite notify slow case"));
3336 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NotifyWrite continuation"));
3337
3338 LValue state = m_out.load8(m_out.absolute(set->addressOfState()));
3339
3340 m_out.branch(
3341 m_out.equal(state, m_out.constInt8(IsInvalidated)),
3342 usually(continuation), rarely(isNotInvalidated));
3343
3344 LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, notifySlow);
3345
3346 m_out.branch(
3347 m_out.equal(value, m_out.load64(m_out.absolute(set->addressOfInferredValue()))),
3348 unsure(continuation), unsure(notifySlow));
3349
3350 m_out.appendTo(notifySlow, continuation);
3351
3352 vmCall(m_out.operation(operationNotifyWrite), m_callFrame, m_out.constIntPtr(set), value);
3353 m_out.jump(continuation);
3354
3355 m_out.appendTo(continuation, lastNext);
3356 }
3357
3358 void compileGetCallee()
3359 {
3360 setJSValue(m_out.loadPtr(addressFor(JSStack::Callee)));
3361 }
3362
3363 void compileGetScope()
3364 {
3365 setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSFunction_scope));
3366 }
3367
3368 void compileGetMyScope()
3369 {
3370 setJSValue(m_out.loadPtr(addressFor(
3371 m_node->origin.semantic.stackOffset() + JSStack::ScopeChain)));
3372 }
3373
3374 void compileSkipScope()
3375 {
3376 setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSScope_next));
3377 }
3378
3379 void compileGetClosureRegisters()
3380 {
3381 if (WriteBarrierBase<Unknown>* registers = m_graph.tryGetRegisters(m_node->child1().node())) {
3382 setStorage(m_out.constIntPtr(registers));
3383 return;
3384 }
3385
3386 setStorage(m_out.loadPtr(
3387 lowCell(m_node->child1()), m_heaps.JSVariableObject_registers));
3388 }
3389
3390 void compileGetClosureVar()
3391 {
3392 setJSValue(m_out.load64(
3393 addressFor(lowStorage(m_node->child1()), m_node->varNumber())));
3394 }
3395
3396 void compilePutClosureVar()
3397 {
3398 m_out.store64(
3399 lowJSValue(m_node->child3()),
3400 addressFor(lowStorage(m_node->child2()), m_node->varNumber()));
3401 }
3402
3403 void compileCompareEq()
3404 {
3405 if (m_node->isBinaryUseKind(Int32Use)
3406 || m_node->isBinaryUseKind(Int52RepUse)
3407 || m_node->isBinaryUseKind(DoubleRepUse)
3408 || m_node->isBinaryUseKind(ObjectUse)
3409 || m_node->isBinaryUseKind(BooleanUse)
3410 || m_node->isBinaryUseKind(StringIdentUse)) {
3411 compileCompareStrictEq();
3412 return;
3413 }
3414
3415 if (m_node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse)) {
3416 compareEqObjectOrOtherToObject(m_node->child2(), m_node->child1());
3417 return;
3418 }
3419
3420 if (m_node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
3421 compareEqObjectOrOtherToObject(m_node->child1(), m_node->child2());
3422 return;
3423 }
3424
3425 if (m_node->isBinaryUseKind(UntypedUse)) {
3426 nonSpeculativeCompare(LLVMIntEQ, operationCompareEq);
3427 return;
3428 }
3429
3430 RELEASE_ASSERT_NOT_REACHED();
3431 }
3432
3433 void compileCompareEqConstant()
3434 {
3435 ASSERT(m_graph.valueOfJSConstant(m_node->child2().node()).isNull());
3436 setBoolean(
3437 equalNullOrUndefined(
3438 m_node->child1(), AllCellsAreFalse, EqualNullOrUndefined));
3439 }
3440
3441 void compileCompareStrictEq()
3442 {
3443 if (m_node->isBinaryUseKind(Int32Use)) {
3444 setBoolean(
3445 m_out.equal(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
3446 return;
3447 }
3448
3449 if (m_node->isBinaryUseKind(Int52RepUse)) {
3450 Int52Kind kind;
3451 LValue left = lowWhicheverInt52(m_node->child1(), kind);
3452 LValue right = lowInt52(m_node->child2(), kind);
3453 setBoolean(m_out.equal(left, right));
3454 return;
3455 }
3456
3457 if (m_node->isBinaryUseKind(DoubleRepUse)) {
3458 setBoolean(
3459 m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
3460 return;
3461 }
3462
3463 if (m_node->isBinaryUseKind(StringIdentUse)) {
3464 setBoolean(
3465 m_out.equal(lowStringIdent(m_node->child1()), lowStringIdent(m_node->child2())));
3466 return;
3467 }
3468
3469 if (m_node->isBinaryUseKind(ObjectUse)) {
3470 setBoolean(
3471 m_out.equal(
3472 lowNonNullObject(m_node->child1()),
3473 lowNonNullObject(m_node->child2())));
3474 return;
3475 }
3476
3477 if (m_node->isBinaryUseKind(BooleanUse)) {
3478 setBoolean(
3479 m_out.equal(lowBoolean(m_node->child1()), lowBoolean(m_node->child2())));
3480 return;
3481 }
3482
3483 if (m_node->isBinaryUseKind(MiscUse, UntypedUse)
3484 || m_node->isBinaryUseKind(UntypedUse, MiscUse)) {
3485 speculate(m_node->child1());
3486 speculate(m_node->child2());
3487 LValue left = lowJSValue(m_node->child1(), ManualOperandSpeculation);
3488 LValue right = lowJSValue(m_node->child2(), ManualOperandSpeculation);
3489 setBoolean(m_out.equal(left, right));
3490 return;
3491 }
3492
3493 if (m_node->isBinaryUseKind(StringIdentUse, NotStringVarUse)
3494 || m_node->isBinaryUseKind(NotStringVarUse, StringIdentUse)) {
3495 Edge leftEdge = m_node->childFor(StringIdentUse);
3496 Edge rightEdge = m_node->childFor(NotStringVarUse);
3497
3498 LValue left = lowStringIdent(leftEdge);
3499 LValue rightValue = lowJSValue(rightEdge, ManualOperandSpeculation);
3500
3501 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar is cell case"));
3502 LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar is string case"));
3503 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar continuation"));
3504
3505 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
3506 m_out.branch(isCell(rightValue), unsure(isCellCase), unsure(continuation));
3507
3508 LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
3509 ValueFromBlock notStringResult = m_out.anchor(m_out.booleanFalse);
3510 m_out.branch(isString(rightValue), unsure(isStringCase), unsure(continuation));
3511
3512 m_out.appendTo(isStringCase, continuation);
3513 LValue right = m_out.loadPtr(rightValue, m_heaps.JSString_value);
3514 speculateStringIdent(rightEdge, rightValue, right);
3515 ValueFromBlock isStringResult = m_out.anchor(m_out.equal(left, right));
3516 m_out.jump(continuation);
3517
3518 m_out.appendTo(continuation, lastNext);
3519 setBoolean(m_out.phi(m_out.boolean, notCellResult, notStringResult, isStringResult));
3520 return;
3521 }
3522
3523 RELEASE_ASSERT_NOT_REACHED();
3524 }
3525
3526 void compileCompareStrictEqConstant()
3527 {
3528 JSValue constant = m_graph.valueOfJSConstant(m_node->child2().node());
3529
3530 setBoolean(
3531 m_out.equal(
3532 lowJSValue(m_node->child1()),
3533 m_out.constInt64(JSValue::encode(constant))));
3534 }
3535
3536 void compileCompareLess()
3537 {
3538 compare(LLVMIntSLT, LLVMRealOLT, operationCompareLess);
3539 }
3540
3541 void compileCompareLessEq()
3542 {
3543 compare(LLVMIntSLE, LLVMRealOLE, operationCompareLessEq);
3544 }
3545
3546 void compileCompareGreater()
3547 {
3548 compare(LLVMIntSGT, LLVMRealOGT, operationCompareGreater);
3549 }
3550
3551 void compileCompareGreaterEq()
3552 {
3553 compare(LLVMIntSGE, LLVMRealOGE, operationCompareGreaterEq);
3554 }
3555
3556 void compileLogicalNot()
3557 {
3558 setBoolean(m_out.bitNot(boolify(m_node->child1())));
3559 }
3560
3561 void compileCallOrConstruct()
3562 {
3563 int dummyThisArgument = m_node->op() == Call ? 0 : 1;
3564 int numPassedArgs = m_node->numChildren() - 1;
3565 int numArgs = numPassedArgs + dummyThisArgument;
3566
3567 LValue callee = lowJSValue(m_graph.varArgChild(m_node, 0));
3568
3569 unsigned stackmapID = m_stackmapIDs++;
3570
3571 Vector<LValue> arguments;
3572 arguments.append(m_out.constInt64(stackmapID));
3573 arguments.append(m_out.constInt32(sizeOfCall()));
3574 arguments.append(constNull(m_out.ref8));
3575 arguments.append(m_out.constInt32(1 + JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + numArgs));
3576 arguments.append(callee); // callee -> %rax
3577 arguments.append(getUndef(m_out.int64)); // code block
3578 arguments.append(getUndef(m_out.int64)); // scope chain
3579 arguments.append(callee); // callee -> stack
3580 arguments.append(m_out.constInt64(numArgs)); // argument count and zeros for the tag
3581 if (dummyThisArgument)
3582 arguments.append(getUndef(m_out.int64));
3583 for (int i = 0; i < numPassedArgs; ++i)
3584 arguments.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i)));
3585
3586 callPreflight();
3587
3588 LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments);
3589 setInstructionCallingConvention(call, LLVMWebKitJSCallConv);
3590
3591 m_ftlState.jsCalls.append(JSCall(stackmapID, m_node));
3592
3593 setJSValue(call);
3594 }
3595
3596 void compileJump()
3597 {
3598 m_out.jump(lowBlock(m_node->targetBlock()));
3599 }
3600
3601 void compileBranch()
3602 {
3603 m_out.branch(
3604 boolify(m_node->child1()),
3605 WeightedTarget(
3606 lowBlock(m_node->branchData()->taken.block),
3607 m_node->branchData()->taken.count),
3608 WeightedTarget(
3609 lowBlock(m_node->branchData()->notTaken.block),
3610 m_node->branchData()->notTaken.count));
3611 }
3612
3613 void compileSwitch()
3614 {
3615 SwitchData* data = m_node->switchData();
3616 switch (data->kind) {
3617 case SwitchImm: {
3618 Vector<ValueFromBlock, 2> intValues;
3619 LBasicBlock switchOnInts = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm int case"));
3620
3621 LBasicBlock lastNext = m_out.appendTo(m_out.m_block, switchOnInts);
3622
3623 switch (m_node->child1().useKind()) {
3624 case Int32Use: {
3625 intValues.append(m_out.anchor(lowInt32(m_node->child1())));
3626 m_out.jump(switchOnInts);
3627 break;
3628 }
3629
3630 case UntypedUse: {
3631 LBasicBlock isInt = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is int"));
3632 LBasicBlock isNotInt = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is not int"));
3633 LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("Switch/SwitchImm is double"));
3634
3635 LValue boxedValue = lowJSValue(m_node->child1());
3636 m_out.branch(isNotInt32(boxedValue), unsure(isNotInt), unsure(isInt));
3637
3638 LBasicBlock innerLastNext = m_out.appendTo(isInt, isNotInt);
3639
3640 intValues.append(m_out.anchor(unboxInt32(boxedValue)));
3641 m_out.jump(switchOnInts);
3642
3643 m_out.appendTo(isNotInt, isDouble);
3644 m_out.branch(
3645 isCellOrMisc(boxedValue),
3646 usually(lowBlock(data->fallThrough.block)), rarely(isDouble));
3647
3648 m_out.appendTo(isDouble, innerLastNext);
3649 LValue doubleValue = unboxDouble(boxedValue);
3650 LValue intInDouble = m_out.fpToInt32(doubleValue);
3651 intValues.append(m_out.anchor(intInDouble));
3652 m_out.branch(
3653 m_out.doubleEqual(m_out.intToDouble(intInDouble), doubleValue),
3654 unsure(switchOnInts), unsure(lowBlock(data->fallThrough.block)));
3655 break;
3656 }
3657
3658 default:
3659 RELEASE_ASSERT_NOT_REACHED();
3660 break;
3661 }
3662
3663 m_out.appendTo(switchOnInts, lastNext);
3664 buildSwitch(data, m_out.int32, m_out.phi(m_out.int32, intValues));
3665 return;
3666 }
3667
3668 case SwitchChar: {
3669 LValue stringValue;
3670
3671 // FIXME: We should use something other than unsure() for the branch weight
3672 // of the fallThrough block. The main challenge is just that we have multiple
3673 // branches to fallThrough but a single count, so we would need to divvy it up
3674 // among the different lowered branches.
3675 // https://bugs.webkit.org/show_bug.cgi?id=129082
3676
3677 switch (m_node->child1().useKind()) {
3678 case StringUse: {
3679 stringValue = lowString(m_node->child1());
3680 break;
3681 }
3682
3683 case UntypedUse: {
3684 LValue unboxedValue = lowJSValue(m_node->child1());
3685
3686 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar is cell"));
3687 LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar is string"));
3688
3689 m_out.branch(
3690 isNotCell(unboxedValue),
3691 unsure(lowBlock(data->fallThrough.block)), unsure(isCellCase));
3692
3693 LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
3694 LValue cellValue = unboxedValue;
3695 m_out.branch(
3696 isNotString(cellValue),
3697 unsure(lowBlock(data->fallThrough.block)), unsure(isStringCase));
3698
3699 m_out.appendTo(isStringCase, lastNext);
3700 stringValue = cellValue;
3701 break;
3702 }
3703
3704 default:
3705 RELEASE_ASSERT_NOT_REACHED();
3706 break;
3707 }
3708
3709 LBasicBlock lengthIs1 = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar length is 1"));
3710 LBasicBlock needResolution = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar resolution"));
3711 LBasicBlock resolved = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar resolved"));
3712 LBasicBlock is8Bit = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar 8bit"));
3713 LBasicBlock is16Bit = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar 16bit"));
3714 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar continuation"));
3715
3716 m_out.branch(
3717 m_out.notEqual(
3718 m_out.load32NonNegative(stringValue, m_heaps.JSString_length),
3719 m_out.int32One),
3720 unsure(lowBlock(data->fallThrough.block)), unsure(lengthIs1));
3721
3722 LBasicBlock lastNext = m_out.appendTo(lengthIs1, needResolution);
3723 Vector<ValueFromBlock, 2> values;
3724 LValue fastValue = m_out.loadPtr(stringValue, m_heaps.JSString_value);
3725 values.append(m_out.anchor(fastValue));
3726 m_out.branch(m_out.isNull(fastValue), rarely(needResolution), usually(resolved));
3727
3728 m_out.appendTo(needResolution, resolved);
3729 values.append(m_out.anchor(
3730 vmCall(m_out.operation(operationResolveRope), m_callFrame, stringValue)));
3731 m_out.jump(resolved);
3732
3733 m_out.appendTo(resolved, is8Bit);
3734 LValue value = m_out.phi(m_out.intPtr, values);
3735 LValue characterData = m_out.loadPtr(value, m_heaps.StringImpl_data);
3736 m_out.branch(
3737 m_out.testNonZero32(
3738 m_out.load32(value, m_heaps.StringImpl_hashAndFlags),
3739 m_out.constInt32(StringImpl::flagIs8Bit())),
3740 unsure(is8Bit), unsure(is16Bit));
3741
3742 Vector<ValueFromBlock, 2> characters;
3743 m_out.appendTo(is8Bit, is16Bit);
3744 characters.append(m_out.anchor(
3745 m_out.zeroExt(m_out.load8(characterData, m_heaps.characters8[0]), m_out.int16)));
3746 m_out.jump(continuation);
3747
3748 m_out.appendTo(is16Bit, continuation);
3749 characters.append(m_out.anchor(m_out.load16(characterData, m_heaps.characters16[0])));
3750 m_out.jump(continuation);
3751
3752 m_out.appendTo(continuation, lastNext);
3753 buildSwitch(data, m_out.int16, m_out.phi(m_out.int16, characters));
3754 return;
3755 }
3756
3757 case SwitchString:
3758 RELEASE_ASSERT_NOT_REACHED();
3759 break;
3760 }
3761
3762 RELEASE_ASSERT_NOT_REACHED();
3763 }
3764
3765 void compileReturn()
3766 {
3767 m_out.ret(lowJSValue(m_node->child1()));
3768 }
3769
3770 void compileForceOSRExit()
3771 {
3772 terminate(InadequateCoverage);
3773 }
3774
3775 void compileThrow()
3776 {
3777 terminate(Uncountable);
3778 }
3779
3780 void compileInvalidationPoint()
3781 {
3782 if (verboseCompilationEnabled())
3783 dataLog(" Invalidation point with availability: ", m_availability, "\n");
3784
3785 m_ftlState.jitCode->osrExit.append(OSRExit(
3786 UncountableInvalidation, InvalidValueFormat, MethodOfGettingAValueProfile(),
3787 m_codeOriginForExitTarget, m_codeOriginForExitProfile,
3788 m_availability.numberOfArguments(), m_availability.numberOfLocals()));
3789 m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo());
3790
3791 OSRExit& exit = m_ftlState.jitCode->osrExit.last();
3792 OSRExitCompilationInfo& info = m_ftlState.finalizer->osrExit.last();
3793
3794 ExitArgumentList arguments;
3795
3796 buildExitArguments(exit, arguments, FormattedValue(), exit.m_codeOrigin);
3797 callStackmap(exit, arguments);
3798
3799 info.m_isInvalidationPoint = true;
3800 }
3801
3802 void compileCheckArgumentsNotCreated()
3803 {
3804 ASSERT(!isEmptySpeculation(
3805 m_state.variables().operand(
3806 m_graph.argumentsRegisterFor(m_node->origin.semantic)).m_type));
3807
3808 checkArgumentsNotCreated();
3809 }
3810
3811 void compileIsUndefined()
3812 {
3813 setBoolean(equalNullOrUndefined(m_node->child1(), AllCellsAreFalse, EqualUndefined));
3814 }
3815
3816 void compileIsBoolean()
3817 {
3818 setBoolean(isBoolean(lowJSValue(m_node->child1())));
3819 }
3820
3821 void compileIsNumber()
3822 {
3823 setBoolean(isNumber(lowJSValue(m_node->child1())));
3824 }
3825
3826 void compileIsString()
3827 {
3828 LValue value = lowJSValue(m_node->child1());
3829
3830 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("IsString cell case"));
3831 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsString continuation"));
3832
3833 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
3834 m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation));
3835
3836 LBasicBlock lastNext = m_out.appendTo(isCellCase, continuation);
3837 ValueFromBlock cellResult = m_out.anchor(isString(value));
3838 m_out.jump(continuation);
3839
3840 m_out.appendTo(continuation, lastNext);
3841 setBoolean(m_out.phi(m_out.boolean, notCellResult, cellResult));
3842 }
3843
3844 void compileIsObject()
3845 {
3846 LValue pointerResult = vmCall(
3847 m_out.operation(operationIsObject), m_callFrame, lowJSValue(m_node->child1()));
3848 setBoolean(m_out.notNull(pointerResult));
3849 }
3850
3851 void compileIsFunction()
3852 {
3853 LValue pointerResult = vmCall(
3854 m_out.operation(operationIsFunction), lowJSValue(m_node->child1()));
3855 setBoolean(m_out.notNull(pointerResult));
3856 }
3857
3858 void compileCheckHasInstance()
3859 {
3860 speculate(
3861 Uncountable, noValue(), 0,
3862 m_out.testIsZero8(
3863 m_out.load8(lowCell(m_node->child1()), m_heaps.JSCell_typeInfoFlags),
3864 m_out.constInt8(ImplementsDefaultHasInstance)));
3865 }
3866
3867 void compileInstanceOf()
3868 {
3869 LValue cell;
3870
3871 if (m_node->child1().useKind() == UntypedUse)
3872 cell = lowJSValue(m_node->child1());
3873 else
3874 cell = lowCell(m_node->child1());
3875
3876 LValue prototype = lowCell(m_node->child2());
3877
3878 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("InstanceOf cell case"));
3879 LBasicBlock loop = FTL_NEW_BLOCK(m_out, ("InstanceOf loop"));
3880 LBasicBlock notYetInstance = FTL_NEW_BLOCK(m_out, ("InstanceOf not yet instance"));
3881 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("InstanceOf continuation"));
3882
3883 LValue condition;
3884 if (m_node->child1().useKind() == UntypedUse)
3885 condition = isCell(cell);
3886 else
3887 condition = m_out.booleanTrue;
3888
3889 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
3890 m_out.branch(condition, unsure(isCellCase), unsure(continuation));
3891
3892 LBasicBlock lastNext = m_out.appendTo(isCellCase, loop);
3893
3894 speculate(BadType, noValue(), 0, isNotObject(prototype));
3895
3896 ValueFromBlock originalValue = m_out.anchor(cell);
3897 m_out.jump(loop);
3898
3899 m_out.appendTo(loop, notYetInstance);
3900 LValue value = m_out.phi(m_out.int64, originalValue);
3901 LValue structure = loadStructure(value);
3902 LValue currentPrototype = m_out.load64(structure, m_heaps.Structure_prototype);
3903 ValueFromBlock isInstanceResult = m_out.anchor(m_out.booleanTrue);
3904 m_out.branch(
3905 m_out.equal(currentPrototype, prototype),
3906 unsure(continuation), unsure(notYetInstance));
3907
3908 m_out.appendTo(notYetInstance, continuation);
3909 ValueFromBlock notInstanceResult = m_out.anchor(m_out.booleanFalse);
3910 addIncoming(value, m_out.anchor(currentPrototype));
3911 m_out.branch(isCell(currentPrototype), unsure(loop), unsure(continuation));
3912
3913 m_out.appendTo(continuation, lastNext);
3914 setBoolean(
3915 m_out.phi(m_out.boolean, notCellResult, isInstanceResult, notInstanceResult));
3916 }
3917
3918 void compileCountExecution()
3919 {
3920 TypedPointer counter = m_out.absolute(m_node->executionCounter()->address());
3921 m_out.store64(m_out.add(m_out.load64(counter), m_out.constInt64(1)), counter);
3922 }
3923
3924 void compileStoreBarrier()
3925 {
3926 emitStoreBarrier(lowCell(m_node->child1()));
3927 }
3928
3929 void compileStoreBarrierWithNullCheck()
3930 {
3931 #if ENABLE(GGC)
3932 LBasicBlock isNotNull = FTL_NEW_BLOCK(m_out, ("Store barrier with null check value not null"));
3933 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Store barrier continuation"));
3934
3935 LValue base = lowJSValue(m_node->child1());
3936 m_out.branch(m_out.isZero64(base), unsure(continuation), unsure(isNotNull));
3937 LBasicBlock lastNext = m_out.appendTo(isNotNull, continuation);
3938 emitStoreBarrier(base);
3939 m_out.appendTo(continuation, lastNext);
3940 #else
3941 speculate(m_node->child1());
3942 #endif
3943 }
3944
3945 LValue didOverflowStack()
3946 {
3947 // This does a very simple leaf function analysis. The invariant of FTL call
3948 // frames is that the caller had already done enough of a stack check to
3949 // prove that this call frame has enough stack to run, and also enough stack
3950 // to make runtime calls. So, we only need to stack check when making calls
3951 // to other JS functions. If we don't find such calls then we don't need to
3952 // do any stack checks.
3953
3954 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
3955 BasicBlock* block = m_graph.block(blockIndex);
3956 if (!block)
3957 continue;
3958
3959 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
3960 Node* node = block->at(nodeIndex);
3961
3962 switch (node->op()) {
3963 case GetById:
3964 case PutById:
3965 case Call:
3966 case Construct:
3967 return m_out.below(
3968 m_callFrame,
3969 m_out.loadPtr(
3970 m_out.absolute(vm().addressOfFTLStackLimit())));
3971
3972 default:
3973 break;
3974 }
3975 }
3976 }
3977
3978 return m_out.booleanFalse;
3979 }
3980
3981 LValue numberOrNotCellToInt32(Edge edge, LValue value)
3982 {
3983 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 int case"));
3984 LBasicBlock notIntCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 not int case"));
3985 LBasicBlock doubleCase = 0;
3986 LBasicBlock notNumberCase = 0;
3987 if (edge.useKind() == NotCellUse) {
3988 doubleCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 double case"));
3989 notNumberCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 not number case"));
3990 }
3991 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ValueToInt32 continuation"));
3992
3993 Vector<ValueFromBlock> results;
3994
3995 m_out.branch(isNotInt32(value), unsure(notIntCase), unsure(intCase));
3996
3997 LBasicBlock lastNext = m_out.appendTo(intCase, notIntCase);
3998 results.append(m_out.anchor(unboxInt32(value)));
3999 m_out.jump(continuation);
4000
4001 if (edge.useKind() == NumberUse) {
4002 m_out.appendTo(notIntCase, continuation);
4003 FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBytecodeNumber, isCellOrMisc(value));
4004 results.append(m_out.anchor(doubleToInt32(unboxDouble(value))));
4005 m_out.jump(continuation);
4006 } else {
4007 m_out.appendTo(notIntCase, doubleCase);
4008 m_out.branch(isCellOrMisc(value), unsure(notNumberCase), unsure(doubleCase));
4009
4010 m_out.appendTo(doubleCase, notNumberCase);
4011 results.append(m_out.anchor(doubleToInt32(unboxDouble(value))));
4012 m_out.jump(continuation);
4013
4014 m_out.appendTo(notNumberCase, continuation);
4015
4016 FTL_TYPE_CHECK(jsValueValue(value), edge, ~SpecCell, isCell(value));
4017
4018 LValue specialResult = m_out.select(
4019 m_out.equal(value, m_out.constInt64(JSValue::encode(jsBoolean(true)))),
4020 m_out.int32One, m_out.int32Zero);
4021 results.append(m_out.anchor(specialResult));
4022 m_out.jump(continuation);
4023 }
4024
4025 m_out.appendTo(continuation, lastNext);
4026 return m_out.phi(m_out.int32, results);
4027 }
4028
4029 LValue loadProperty(LValue storage, unsigned identifierNumber, PropertyOffset offset)
4030 {
4031 return m_out.load64(addressOfProperty(storage, identifierNumber, offset));
4032 }
4033
4034 void storeProperty(
4035 LValue value, LValue storage, unsigned identifierNumber, PropertyOffset offset)
4036 {
4037 m_out.store64(value, addressOfProperty(storage, identifierNumber, offset));
4038 }
4039
4040 TypedPointer addressOfProperty(
4041 LValue storage, unsigned identifierNumber, PropertyOffset offset)
4042 {
4043 return m_out.address(
4044 m_heaps.properties[identifierNumber], storage, offsetRelativeToBase(offset));
4045 }
4046
4047 LValue storageForTransition(
4048 LValue object, PropertyOffset offset,
4049 Structure* previousStructure, Structure* nextStructure)
4050 {
4051 if (isInlineOffset(offset))
4052 return object;
4053
4054 if (previousStructure->outOfLineCapacity() == nextStructure->outOfLineCapacity())
4055 return m_out.loadPtr(object, m_heaps.JSObject_butterfly);
4056
4057 LValue result;
4058 if (!previousStructure->outOfLineCapacity())
4059 result = allocatePropertyStorage(object, previousStructure);
4060 else {
4061 result = reallocatePropertyStorage(
4062 object, m_out.loadPtr(object, m_heaps.JSObject_butterfly),
4063 previousStructure, nextStructure);
4064 }
4065
4066 emitStoreBarrier(object);
4067
4068 return result;
4069 }
4070
4071 LValue allocatePropertyStorage(LValue object, Structure* previousStructure)
4072 {
4073 if (previousStructure->couldHaveIndexingHeader()) {
4074 return vmCall(
4075 m_out.operation(
4076 operationReallocateButterflyToHavePropertyStorageWithInitialCapacity),
4077 m_callFrame, object);
4078 }
4079
4080 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorage slow path"));
4081 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorage continuation"));
4082
4083 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
4084
4085 LValue endOfStorage = allocateBasicStorageAndGetEnd(
4086 m_out.constIntPtr(initialOutOfLineCapacity * sizeof(JSValue)), slowPath);
4087
4088 ValueFromBlock fastButterfly = m_out.anchor(
4089 m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage));
4090
4091 m_out.jump(continuation);
4092
4093 m_out.appendTo(slowPath, continuation);
4094
4095 ValueFromBlock slowButterfly = m_out.anchor(vmCall(
4096 m_out.operation(operationAllocatePropertyStorageWithInitialCapacity), m_callFrame));
4097
4098 m_out.jump(continuation);
4099
4100 m_out.appendTo(continuation, lastNext);
4101
4102 LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly);
4103 m_out.storePtr(result, object, m_heaps.JSObject_butterfly);
4104
4105 return result;
4106 }
4107
4108 LValue reallocatePropertyStorage(
4109 LValue object, LValue oldStorage, Structure* previous, Structure* next)
4110 {
4111 size_t oldSize = previous->outOfLineCapacity() * sizeof(JSValue);
4112 size_t newSize = oldSize * outOfLineGrowthFactor;
4113
4114 ASSERT_UNUSED(next, newSize == next->outOfLineCapacity() * sizeof(JSValue));
4115
4116 if (previous->couldHaveIndexingHeader()) {
4117 LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue));
4118 return vmCall(m_out.operation(operationReallocateButterflyToGrowPropertyStorage), m_callFrame, object, newAllocSize);
4119 }
4120
4121 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("reallocatePropertyStorage slow path"));
4122 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("reallocatePropertyStorage continuation"));
4123 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
4124
4125 LValue endOfStorage =
4126 allocateBasicStorageAndGetEnd(m_out.constIntPtr(newSize), slowPath);
4127
4128 ValueFromBlock fastButterfly = m_out.anchor(m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage));
4129
4130 m_out.jump(continuation);
4131
4132 m_out.appendTo(slowPath, continuation);
4133
4134 LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue));
4135
4136 LValue storageLocation = vmCall(m_out.operation(operationAllocatePropertyStorage), m_callFrame, newAllocSize);
4137
4138 ValueFromBlock slowButterfly = m_out.anchor(storageLocation);
4139
4140 m_out.jump(continuation);
4141
4142 m_out.appendTo(continuation, lastNext);
4143
4144 LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly);
4145
4146 ptrdiff_t headerSize = -sizeof(JSValue) - sizeof(void *);
4147 ptrdiff_t endStorage = headerSize - static_cast<ptrdiff_t>(oldSize);
4148
4149 for (ptrdiff_t offset = headerSize; offset > endStorage; offset -= sizeof(void*)) {
4150 LValue loaded =
4151 m_out.loadPtr(m_out.address(m_heaps.properties.atAnyNumber(), oldStorage, offset));
4152 m_out.storePtr(loaded, m_out.address(m_heaps.properties.atAnyNumber(), result, offset));
4153 }
4154
4155 m_out.storePtr(result, m_out.address(object, m_heaps.JSObject_butterfly));
4156
4157 return result;
4158 }
4159
4160 LValue getById(LValue base)
4161 {
4162 StringImpl* uid = m_graph.identifiers()[m_node->identifierNumber()];
4163
4164 // Arguments: id, bytes, target, numArgs, args...
4165 unsigned stackmapID = m_stackmapIDs++;
4166
4167 if (Options::verboseCompilation())
4168 dataLog(" Emitting GetById patchpoint with stackmap #", stackmapID, "\n");
4169
4170 LValue call = m_out.call(
4171 m_out.patchpointInt64Intrinsic(),
4172 m_out.constInt64(stackmapID), m_out.constInt32(sizeOfGetById()),
4173 constNull(m_out.ref8), m_out.constInt32(1), base);
4174 setInstructionCallingConvention(call, LLVMAnyRegCallConv);
4175
4176 m_ftlState.getByIds.append(GetByIdDescriptor(stackmapID, m_node->origin.semantic, uid));
4177
4178 return call;
4179 }
4180
4181 TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue storage, LValue index, Edge edge)
4182 {
4183 return m_out.baseIndex(
4184 heap, storage, m_out.zeroExt(index, m_out.intPtr),
4185 m_state.forNode(edge).m_value);
4186 }
4187
4188 void compare(
4189 LIntPredicate intCondition, LRealPredicate realCondition,
4190 S_JITOperation_EJJ helperFunction)
4191 {
4192 if (m_node->isBinaryUseKind(Int32Use)) {
4193 LValue left = lowInt32(m_node->child1());
4194 LValue right = lowInt32(m_node->child2());
4195 setBoolean(m_out.icmp(intCondition, left, right));
4196 return;
4197 }
4198
4199 if (m_node->isBinaryUseKind(Int52RepUse)) {
4200 Int52Kind kind;
4201 LValue left = lowWhicheverInt52(m_node->child1(), kind);
4202 LValue right = lowInt52(m_node->child2(), kind);
4203 setBoolean(m_out.icmp(intCondition, left, right));
4204 return;
4205 }
4206
4207 if (m_node->isBinaryUseKind(DoubleRepUse)) {
4208 LValue left = lowDouble(m_node->child1());
4209 LValue right = lowDouble(m_node->child2());
4210 setBoolean(m_out.fcmp(realCondition, left, right));
4211 return;
4212 }
4213
4214 if (m_node->isBinaryUseKind(UntypedUse)) {
4215 nonSpeculativeCompare(intCondition, helperFunction);
4216 return;
4217 }
4218
4219 RELEASE_ASSERT_NOT_REACHED();
4220 }
4221
4222 void compareEqObjectOrOtherToObject(Edge leftChild, Edge rightChild)
4223 {
4224 LValue rightCell = lowCell(rightChild);
4225 LValue leftValue = lowJSValue(leftChild, ManualOperandSpeculation);
4226
4227 speculateTruthyObject(rightChild, rightCell, SpecObject);
4228
4229 LBasicBlock leftCellCase = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject left cell case"));
4230 LBasicBlock leftNotCellCase = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject left not cell case"));
4231 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject continuation"));
4232
4233 m_out.branch(isCell(leftValue), unsure(leftCellCase), unsure(leftNotCellCase));
4234
4235 LBasicBlock lastNext = m_out.appendTo(leftCellCase, leftNotCellCase);
4236 speculateTruthyObject(leftChild, leftValue, SpecObject | (~SpecCell));
4237 ValueFromBlock cellResult = m_out.anchor(m_out.equal(rightCell, leftValue));
4238 m_out.jump(continuation);
4239
4240 m_out.appendTo(leftNotCellCase, continuation);
4241 FTL_TYPE_CHECK(
4242 jsValueValue(leftValue), leftChild, SpecOther | SpecCell, isNotOther(leftValue));
4243 ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
4244 m_out.jump(continuation);
4245
4246 m_out.appendTo(continuation, lastNext);
4247 setBoolean(m_out.phi(m_out.boolean, cellResult, notCellResult));
4248 }
4249
4250 void speculateTruthyObject(Edge edge, LValue cell, SpeculatedType filter)
4251 {
4252 if (masqueradesAsUndefinedWatchpointIsStillValid()) {
4253 FTL_TYPE_CHECK(jsValueValue(cell), edge, filter, isNotObject(cell));
4254 return;
4255 }
4256
4257 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
4258 FTL_TYPE_CHECK(
4259 jsValueValue(cell), edge, filter,
4260 m_out.equal(structureID, m_out.constInt32(vm().stringStructure->id())));
4261 speculate(
4262 BadType, jsValueValue(cell), edge.node(),
4263 m_out.testNonZero8(
4264 m_out.load8(cell, m_heaps.JSCell_typeInfoFlags),
4265 m_out.constInt8(MasqueradesAsUndefined)));
4266 }
4267
4268 void nonSpeculativeCompare(LIntPredicate intCondition, S_JITOperation_EJJ helperFunction)
4269 {
4270 LValue left = lowJSValue(m_node->child1());
4271 LValue right = lowJSValue(m_node->child2());
4272
4273 LBasicBlock leftIsInt = FTL_NEW_BLOCK(m_out, ("CompareEq untyped left is int"));
4274 LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("CompareEq untyped fast path"));
4275 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("CompareEq untyped slow path"));
4276 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareEq untyped continuation"));
4277
4278 m_out.branch(isNotInt32(left), rarely(slowPath), usually(leftIsInt));
4279
4280 LBasicBlock lastNext = m_out.appendTo(leftIsInt, fastPath);
4281 m_out.branch(isNotInt32(right), rarely(slowPath), usually(fastPath));
4282
4283 m_out.appendTo(fastPath, slowPath);
4284 ValueFromBlock fastResult = m_out.anchor(
4285 m_out.icmp(intCondition, unboxInt32(left), unboxInt32(right)));
4286 m_out.jump(continuation);
4287
4288 m_out.appendTo(slowPath, continuation);
4289 ValueFromBlock slowResult = m_out.anchor(m_out.notNull(vmCall(
4290 m_out.operation(helperFunction), m_callFrame, left, right)));
4291 m_out.jump(continuation);
4292
4293 m_out.appendTo(continuation, lastNext);
4294 setBoolean(m_out.phi(m_out.boolean, fastResult, slowResult));
4295 }
4296
4297 LValue allocateCell(LValue allocator, Structure* structure, LBasicBlock slowPath)
4298 {
4299 LBasicBlock success = FTL_NEW_BLOCK(m_out, ("object allocation success"));
4300
4301 LValue result = m_out.loadPtr(
4302 allocator, m_heaps.MarkedAllocator_freeListHead);
4303
4304 m_out.branch(m_out.notNull(result), usually(success), rarely(slowPath));
4305
4306 m_out.appendTo(success);
4307
4308 m_out.storePtr(
4309 m_out.loadPtr(result, m_heaps.JSCell_freeListNext),
4310 allocator, m_heaps.MarkedAllocator_freeListHead);
4311
4312 m_out.store32(m_out.constInt32(structure->id()), result, m_heaps.JSCell_structureID);
4313 m_out.store8(m_out.constInt8(structure->indexingType()), result, m_heaps.JSCell_indexingType);
4314 m_out.store8(m_out.constInt8(structure->typeInfo().type()), result, m_heaps.JSCell_typeInfoType);
4315 m_out.store8(m_out.constInt8(structure->typeInfo().inlineTypeFlags()), result, m_heaps.JSCell_typeInfoFlags);
4316 m_out.store8(m_out.constInt8(JSCell::NotMarked), result, m_heaps.JSCell_gcData);
4317
4318 return result;
4319 }
4320
4321 LValue allocateObject(
4322 LValue allocator, Structure* structure, LValue butterfly, LBasicBlock slowPath)
4323 {
4324 LValue result = allocateCell(allocator, structure, slowPath);
4325 m_out.storePtr(butterfly, result, m_heaps.JSObject_butterfly);
4326 return result;
4327 }
4328
4329 template<typename ClassType>
4330 LValue allocateObject(Structure* structure, LValue butterfly, LBasicBlock slowPath)
4331 {
4332 MarkedAllocator* allocator;
4333 size_t size = ClassType::allocationSize(0);
4334 if (ClassType::needsDestruction && ClassType::hasImmortalStructure)
4335 allocator = &vm().heap.allocatorForObjectWithImmortalStructureDestructor(size);
4336 else if (ClassType::needsDestruction)
4337 allocator = &vm().heap.allocatorForObjectWithNormalDestructor(size);
4338 else
4339 allocator = &vm().heap.allocatorForObjectWithoutDestructor(size);
4340 return allocateObject(m_out.constIntPtr(allocator), structure, butterfly, slowPath);
4341 }
4342
4343 // Returns a pointer to the end of the allocation.
4344 LValue allocateBasicStorageAndGetEnd(LValue size, LBasicBlock slowPath)
4345 {
4346 CopiedAllocator& allocator = vm().heap.storageAllocator();
4347
4348 LBasicBlock success = FTL_NEW_BLOCK(m_out, ("storage allocation success"));
4349
4350 LValue remaining = m_out.loadPtr(m_out.absolute(&allocator.m_currentRemaining));
4351 LValue newRemaining = m_out.sub(remaining, size);
4352
4353 m_out.branch(
4354 m_out.lessThan(newRemaining, m_out.intPtrZero),
4355 rarely(slowPath), usually(success));
4356
4357 m_out.appendTo(success);
4358
4359 m_out.storePtr(newRemaining, m_out.absolute(&allocator.m_currentRemaining));
4360 return m_out.sub(
4361 m_out.loadPtr(m_out.absolute(&allocator.m_currentPayloadEnd)), newRemaining);
4362 }
4363
4364 struct ArrayValues {
4365 ArrayValues()
4366 : array(0)
4367 , butterfly(0)
4368 {
4369 }
4370
4371 ArrayValues(LValue array, LValue butterfly)
4372 : array(array)
4373 , butterfly(butterfly)
4374 {
4375 }
4376
4377 LValue array;
4378 LValue butterfly;
4379 };
4380 ArrayValues allocateJSArray(
4381 Structure* structure, unsigned numElements, LBasicBlock slowPath)
4382 {
4383 ASSERT(
4384 hasUndecided(structure->indexingType())
4385 || hasInt32(structure->indexingType())
4386 || hasDouble(structure->indexingType())
4387 || hasContiguous(structure->indexingType()));
4388
4389 unsigned vectorLength = std::max(BASE_VECTOR_LEN, numElements);
4390
4391 LValue endOfStorage = allocateBasicStorageAndGetEnd(
4392 m_out.constIntPtr(sizeof(JSValue) * vectorLength + sizeof(IndexingHeader)),
4393 slowPath);
4394
4395 LValue butterfly = m_out.sub(
4396 endOfStorage, m_out.constIntPtr(sizeof(JSValue) * vectorLength));
4397
4398 LValue object = allocateObject<JSArray>(
4399 structure, butterfly, slowPath);
4400
4401 m_out.store32(m_out.constInt32(numElements), butterfly, m_heaps.Butterfly_publicLength);
4402 m_out.store32(m_out.constInt32(vectorLength), butterfly, m_heaps.Butterfly_vectorLength);
4403
4404 if (hasDouble(structure->indexingType())) {
4405 for (unsigned i = numElements; i < vectorLength; ++i) {
4406 m_out.store64(
4407 m_out.constInt64(bitwise_cast<int64_t>(PNaN)),
4408 butterfly, m_heaps.indexedDoubleProperties[i]);
4409 }
4410 }
4411
4412 return ArrayValues(object, butterfly);
4413 }
4414
4415 ArrayValues allocateJSArray(Structure* structure, unsigned numElements)
4416 {
4417 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("JSArray allocation slow path"));
4418 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("JSArray allocation continuation"));
4419
4420 LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
4421
4422 ArrayValues fastValues = allocateJSArray(structure, numElements, slowPath);
4423 ValueFromBlock fastArray = m_out.anchor(fastValues.array);
4424 ValueFromBlock fastButterfly = m_out.anchor(fastValues.butterfly);
4425
4426 m_out.jump(continuation);
4427
4428 m_out.appendTo(slowPath, continuation);
4429
4430 ValueFromBlock slowArray = m_out.anchor(vmCall(
4431 m_out.operation(operationNewArrayWithSize), m_callFrame,
4432 m_out.constIntPtr(structure), m_out.constInt32(numElements)));
4433 ValueFromBlock slowButterfly = m_out.anchor(
4434 m_out.loadPtr(slowArray.value(), m_heaps.JSObject_butterfly));
4435
4436 m_out.jump(continuation);
4437
4438 m_out.appendTo(continuation, lastNext);
4439
4440 return ArrayValues(
4441 m_out.phi(m_out.intPtr, fastArray, slowArray),
4442 m_out.phi(m_out.intPtr, fastButterfly, slowButterfly));
4443 }
4444
4445 LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode, LValue base)
4446 {
4447 if (JSArrayBufferView* view = m_graph.tryGetFoldableView(baseEdge.node(), arrayMode))
4448 return m_out.constInt32(view->length());
4449 return m_out.load32NonNegative(base, m_heaps.JSArrayBufferView_length);
4450 }
4451
4452 LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode)
4453 {
4454 return typedArrayLength(baseEdge, arrayMode, lowCell(baseEdge));
4455 }
4456
4457 LValue boolify(Edge edge)
4458 {
4459 switch (edge.useKind()) {
4460 case BooleanUse:
4461 return lowBoolean(m_node->child1());
4462 case Int32Use:
4463 return m_out.notZero32(lowInt32(m_node->child1()));
4464 case DoubleRepUse:
4465 return m_out.doubleNotEqual(lowDouble(edge), m_out.doubleZero);
4466 case ObjectOrOtherUse:
4467 return m_out.bitNot(
4468 equalNullOrUndefined(
4469 edge, CellCaseSpeculatesObject, SpeculateNullOrUndefined,
4470 ManualOperandSpeculation));
4471 case StringUse: {
4472 LValue stringValue = lowString(m_node->child1());
4473 LValue length = m_out.load32NonNegative(stringValue, m_heaps.JSString_length);
4474 return m_out.notEqual(length, m_out.int32Zero);
4475 }
4476 case UntypedUse: {
4477 LValue value = lowJSValue(m_node->child1());
4478
4479 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped slow case"));
4480 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped fast case"));
4481 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Boolify untyped continuation"));
4482
4483 m_out.branch(isNotBoolean(value), rarely(slowCase), usually(fastCase));
4484
4485 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
4486 ValueFromBlock fastResult = m_out.anchor(unboxBoolean(value));
4487 m_out.jump(continuation);
4488
4489 m_out.appendTo(slowCase, continuation);
4490 ValueFromBlock slowResult = m_out.anchor(m_out.notNull(vmCall(
4491 m_out.operation(operationConvertJSValueToBoolean), m_callFrame, value)));
4492 m_out.jump(continuation);
4493
4494 m_out.appendTo(continuation, lastNext);
4495 return m_out.phi(m_out.boolean, fastResult, slowResult);
4496 }
4497 default:
4498 RELEASE_ASSERT_NOT_REACHED();
4499 return 0;
4500 }
4501 }
4502
4503 enum StringOrObjectMode {
4504 AllCellsAreFalse,
4505 CellCaseSpeculatesObject
4506 };
4507 enum EqualNullOrUndefinedMode {
4508 EqualNull,
4509 EqualUndefined,
4510 EqualNullOrUndefined,
4511 SpeculateNullOrUndefined
4512 };
4513 LValue equalNullOrUndefined(
4514 Edge edge, StringOrObjectMode cellMode, EqualNullOrUndefinedMode primitiveMode,
4515 OperandSpeculationMode operandMode = AutomaticOperandSpeculation)
4516 {
4517 bool validWatchpoint = masqueradesAsUndefinedWatchpointIsStillValid();
4518
4519 LValue value = lowJSValue(edge, operandMode);
4520
4521 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined cell case"));
4522 LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined primitive case"));
4523 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined continuation"));
4524
4525 m_out.branch(isNotCell(value), unsure(primitiveCase), unsure(cellCase));
4526
4527 LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
4528
4529 Vector<ValueFromBlock, 3> results;
4530
4531 switch (cellMode) {
4532 case AllCellsAreFalse:
4533 break;
4534 case CellCaseSpeculatesObject:
4535 FTL_TYPE_CHECK(
4536 jsValueValue(value), edge, (~SpecCell) | SpecObject,
4537 m_out.equal(
4538 m_out.load32(value, m_heaps.JSCell_structureID),
4539 m_out.constInt32(vm().stringStructure->id())));
4540 break;
4541 }
4542
4543 if (validWatchpoint) {
4544 results.append(m_out.anchor(m_out.booleanFalse));
4545 m_out.jump(continuation);
4546 } else {
4547 LBasicBlock masqueradesCase =
4548 FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined masquerades case"));
4549
4550 results.append(m_out.anchor(m_out.booleanFalse));
4551
4552 m_out.branch(
4553 m_out.testNonZero8(
4554 m_out.load8(value, m_heaps.JSCell_typeInfoFlags),
4555 m_out.constInt8(MasqueradesAsUndefined)),
4556 rarely(masqueradesCase), usually(continuation));
4557
4558 m_out.appendTo(masqueradesCase, primitiveCase);
4559
4560 LValue structure = loadStructure(value);
4561
4562 results.append(m_out.anchor(
4563 m_out.equal(
4564 m_out.constIntPtr(m_graph.globalObjectFor(m_node->origin.semantic)),
4565 m_out.loadPtr(structure, m_heaps.Structure_globalObject))));
4566 m_out.jump(continuation);
4567 }
4568
4569 m_out.appendTo(primitiveCase, continuation);
4570
4571 LValue primitiveResult;
4572 switch (primitiveMode) {
4573 case EqualNull:
4574 primitiveResult = m_out.equal(value, m_out.constInt64(ValueNull));
4575 break;
4576 case EqualUndefined:
4577 primitiveResult = m_out.equal(value, m_out.constInt64(ValueUndefined));
4578 break;
4579 case EqualNullOrUndefined:
4580 primitiveResult = isOther(value);
4581 break;
4582 case SpeculateNullOrUndefined:
4583 FTL_TYPE_CHECK(
4584 jsValueValue(value), edge, SpecCell | SpecOther, isNotOther(value));
4585 primitiveResult = m_out.booleanTrue;
4586 break;
4587 }
4588 results.append(m_out.anchor(primitiveResult));
4589 m_out.jump(continuation);
4590
4591 m_out.appendTo(continuation, lastNext);
4592
4593 return m_out.phi(m_out.boolean, results);
4594 }
4595
4596 template<typename FunctionType>
4597 void contiguousPutByValOutOfBounds(
4598 FunctionType slowPathFunction, LValue base, LValue storage, LValue index, LValue value,
4599 LBasicBlock continuation)
4600 {
4601 LValue isNotInBounds = m_out.aboveOrEqual(
4602 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength));
4603 if (!m_node->arrayMode().isInBounds()) {
4604 LBasicBlock notInBoundsCase =
4605 FTL_NEW_BLOCK(m_out, ("PutByVal not in bounds"));
4606 LBasicBlock performStore =
4607 FTL_NEW_BLOCK(m_out, ("PutByVal perform store"));
4608
4609 m_out.branch(isNotInBounds, unsure(notInBoundsCase), unsure(performStore));
4610
4611 LBasicBlock lastNext = m_out.appendTo(notInBoundsCase, performStore);
4612
4613 LValue isOutOfBounds = m_out.aboveOrEqual(
4614 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_vectorLength));
4615
4616 if (!m_node->arrayMode().isOutOfBounds())
4617 speculate(OutOfBounds, noValue(), 0, isOutOfBounds);
4618 else {
4619 LBasicBlock outOfBoundsCase =
4620 FTL_NEW_BLOCK(m_out, ("PutByVal out of bounds"));
4621 LBasicBlock holeCase =
4622 FTL_NEW_BLOCK(m_out, ("PutByVal hole case"));
4623
4624 m_out.branch(isOutOfBounds, unsure(outOfBoundsCase), unsure(holeCase));
4625
4626 LBasicBlock innerLastNext = m_out.appendTo(outOfBoundsCase, holeCase);
4627
4628 vmCall(
4629 m_out.operation(slowPathFunction),
4630 m_callFrame, base, index, value);
4631
4632 m_out.jump(continuation);
4633
4634 m_out.appendTo(holeCase, innerLastNext);
4635 }
4636
4637 m_out.store32(
4638 m_out.add(index, m_out.int32One),
4639 storage, m_heaps.Butterfly_publicLength);
4640
4641 m_out.jump(performStore);
4642 m_out.appendTo(performStore, lastNext);
4643 }
4644 }
4645
4646 void buildSwitch(SwitchData* data, LType type, LValue switchValue)
4647 {
4648 Vector<SwitchCase> cases;
4649 for (unsigned i = 0; i < data->cases.size(); ++i) {
4650 cases.append(SwitchCase(
4651 constInt(type, data->cases[i].value.switchLookupValue()),
4652 lowBlock(data->cases[i].target.block), Weight(data->cases[i].target.count)));
4653 }
4654
4655 m_out.switchInstruction(
4656 switchValue, cases,
4657 lowBlock(data->fallThrough.block), Weight(data->fallThrough.count));
4658 }
4659
4660 LValue doubleToInt32(LValue doubleValue, double low, double high, bool isSigned = true)
4661 {
4662 LBasicBlock greatEnough = FTL_NEW_BLOCK(m_out, ("doubleToInt32 greatEnough"));
4663 LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("doubleToInt32 withinRange"));
4664 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("doubleToInt32 slowPath"));
4665 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("doubleToInt32 continuation"));
4666
4667 Vector<ValueFromBlock, 2> results;
4668
4669 m_out.branch(
4670 m_out.doubleGreaterThanOrEqual(doubleValue, m_out.constDouble(low)),
4671 unsure(greatEnough), unsure(slowPath));
4672
4673 LBasicBlock lastNext = m_out.appendTo(greatEnough, withinRange);
4674 m_out.branch(
4675 m_out.doubleLessThanOrEqual(doubleValue, m_out.constDouble(high)),
4676 unsure(withinRange), unsure(slowPath));
4677
4678 m_out.appendTo(withinRange, slowPath);
4679 LValue fastResult;
4680 if (isSigned)
4681 fastResult = m_out.fpToInt32(doubleValue);
4682 else
4683 fastResult = m_out.fpToUInt32(doubleValue);
4684 results.append(m_out.anchor(fastResult));
4685 m_out.jump(continuation);
4686
4687 m_out.appendTo(slowPath, continuation);
4688 results.append(m_out.anchor(m_out.call(m_out.operation(toInt32), doubleValue)));
4689 m_out.jump(continuation);
4690
4691 m_out.appendTo(continuation, lastNext);
4692 return m_out.phi(m_out.int32, results);
4693 }
4694
4695 LValue doubleToInt32(LValue doubleValue)
4696 {
4697 if (Output::hasSensibleDoubleToInt())
4698 return sensibleDoubleToInt32(doubleValue);
4699
4700 double limit = pow(2, 31) - 1;
4701 return doubleToInt32(doubleValue, -limit, limit);
4702 }
4703
4704 LValue sensibleDoubleToInt32(LValue doubleValue)
4705 {
4706 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("sensible doubleToInt32 slow path"));
4707 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("sensible doubleToInt32 continuation"));
4708
4709 ValueFromBlock fastResult = m_out.anchor(
4710 m_out.sensibleDoubleToInt(doubleValue));
4711 m_out.branch(
4712 m_out.equal(fastResult.value(), m_out.constInt32(0x80000000)),
4713 rarely(slowPath), usually(continuation));
4714
4715 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
4716 ValueFromBlock slowResult = m_out.anchor(
4717 m_out.call(m_out.operation(toInt32), doubleValue));
4718 m_out.jump(continuation);
4719
4720 m_out.appendTo(continuation, lastNext);
4721 return m_out.phi(m_out.int32, fastResult, slowResult);
4722 }
4723
4724 void checkArgumentsNotCreated()
4725 {
4726 CodeOrigin codeOrigin = m_node->origin.semantic;
4727 VirtualRegister argumentsRegister = m_graph.argumentsRegisterFor(codeOrigin);
4728 if (isEmptySpeculation(m_state.variables().operand(argumentsRegister).m_type))
4729 return;
4730
4731 VirtualRegister argsReg = m_graph.machineArgumentsRegisterFor(codeOrigin);
4732 speculate(
4733 ArgumentsEscaped, noValue(), 0,
4734 m_out.notZero64(m_out.load64(addressFor(argsReg))));
4735 }
4736
4737 void speculate(
4738 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
4739 {
4740 appendOSRExit(kind, lowValue, highValue, failCondition);
4741 }
4742
4743 void terminate(ExitKind kind)
4744 {
4745 speculate(kind, noValue(), 0, m_out.booleanTrue);
4746 }
4747
4748 void typeCheck(
4749 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
4750 LValue failCondition)
4751 {
4752 appendTypeCheck(lowValue, highValue, typesPassedThrough, failCondition);
4753 }
4754
4755 void appendTypeCheck(
4756 FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
4757 LValue failCondition)
4758 {
4759 if (!m_interpreter.needsTypeCheck(highValue, typesPassedThrough))
4760 return;
4761 ASSERT(mayHaveTypeCheck(highValue.useKind()));
4762 appendOSRExit(BadType, lowValue, highValue.node(), failCondition);
4763 m_interpreter.filter(highValue, typesPassedThrough);
4764 }
4765
4766 LValue lowInt32(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
4767 {
4768 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use));
4769
4770 if (edge->hasConstant()) {
4771 JSValue value = m_graph.valueOfJSConstant(edge.node());
4772 if (!value.isInt32()) {
4773 terminate(Uncountable);
4774 return m_out.int32Zero;
4775 }
4776 return m_out.constInt32(value.asInt32());
4777 }
4778
4779 LoweredNodeValue value = m_int32Values.get(edge.node());
4780 if (isValid(value))
4781 return value.value();
4782
4783 value = m_strictInt52Values.get(edge.node());
4784 if (isValid(value))
4785 return strictInt52ToInt32(edge, value.value());
4786
4787 value = m_int52Values.get(edge.node());
4788 if (isValid(value))
4789 return strictInt52ToInt32(edge, int52ToStrictInt52(value.value()));
4790
4791 value = m_jsValueValues.get(edge.node());
4792 if (isValid(value)) {
4793 LValue boxedResult = value.value();
4794 FTL_TYPE_CHECK(
4795 jsValueValue(boxedResult), edge, SpecInt32, isNotInt32(boxedResult));
4796 LValue result = unboxInt32(boxedResult);
4797 setInt32(edge.node(), result);
4798 return result;
4799 }
4800
4801 RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecInt32));
4802 terminate(Uncountable);
4803 return m_out.int32Zero;
4804 }
4805
4806 enum Int52Kind { StrictInt52, Int52 };
4807 LValue lowInt52(Edge edge, Int52Kind kind)
4808 {
4809 RELEASE_ASSERT(edge.useKind() == Int52RepUse);
4810
4811 LoweredNodeValue value;
4812
4813 switch (kind) {
4814 case Int52:
4815 value = m_int52Values.get(edge.node());
4816 if (isValid(value))
4817 return value.value();
4818
4819 value = m_strictInt52Values.get(edge.node());
4820 if (isValid(value))
4821 return strictInt52ToInt52(value.value());
4822 break;
4823
4824 case StrictInt52:
4825 value = m_strictInt52Values.get(edge.node());
4826 if (isValid(value))
4827 return value.value();
4828
4829 value = m_int52Values.get(edge.node());
4830 if (isValid(value))
4831 return int52ToStrictInt52(value.value());
4832 break;
4833 }
4834
4835 RELEASE_ASSERT(!m_state.forNode(edge).m_type);
4836 terminate(Uncountable);
4837 return m_out.int64Zero;
4838 }
4839
4840 LValue lowInt52(Edge edge)
4841 {
4842 return lowInt52(edge, Int52);
4843 }
4844
4845 LValue lowStrictInt52(Edge edge)
4846 {
4847 return lowInt52(edge, StrictInt52);
4848 }
4849
4850 bool betterUseStrictInt52(Node* node)
4851 {
4852 return !isValid(m_int52Values.get(node));
4853 }
4854 bool betterUseStrictInt52(Edge edge)
4855 {
4856 return betterUseStrictInt52(edge.node());
4857 }
4858 template<typename T>
4859 Int52Kind bestInt52Kind(T node)
4860 {
4861 return betterUseStrictInt52(node) ? StrictInt52 : Int52;
4862 }
4863 Int52Kind opposite(Int52Kind kind)
4864 {
4865 switch (kind) {
4866 case Int52:
4867 return StrictInt52;
4868 case StrictInt52:
4869 return Int52;
4870 }
4871 RELEASE_ASSERT_NOT_REACHED();
4872 return Int52;
4873 }
4874
4875 LValue lowWhicheverInt52(Edge edge, Int52Kind& kind)
4876 {
4877 kind = bestInt52Kind(edge);
4878 return lowInt52(edge, kind);
4879 }
4880
4881 LValue lowCell(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
4882 {
4883 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || DFG::isCell(edge.useKind()));
4884
4885 if (edge->op() == JSConstant) {
4886 JSValue value = m_graph.valueOfJSConstant(edge.node());
4887 if (!value.isCell()) {
4888 terminate(Uncountable);
4889 return m_out.intPtrZero;
4890 }
4891 return m_out.constIntPtr(value.asCell());
4892 }
4893
4894 LoweredNodeValue value = m_jsValueValues.get(edge.node());
4895 if (isValid(value)) {
4896 LValue uncheckedValue = value.value();
4897 FTL_TYPE_CHECK(
4898 jsValueValue(uncheckedValue), edge, SpecCell, isNotCell(uncheckedValue));
4899 return uncheckedValue;
4900 }
4901
4902 RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecCell));
4903 terminate(Uncountable);
4904 return m_out.intPtrZero;
4905 }
4906
4907 LValue lowObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
4908 {
4909 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
4910
4911 LValue result = lowCell(edge, mode);
4912 speculateObject(edge, result);
4913 return result;
4914 }
4915
4916 LValue lowString(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
4917 {
4918 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == StringUse || edge.useKind() == KnownStringUse || edge.useKind() == StringIdentUse);
4919
4920 LValue result = lowCell(edge, mode);
4921 speculateString(edge, result);
4922 return result;
4923 }
4924
4925 LValue lowStringIdent(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
4926 {
4927 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == StringIdentUse);
4928
4929 LValue string = lowString(edge, mode);
4930 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
4931 speculateStringIdent(edge, string, stringImpl);
4932 return stringImpl;
4933 }
4934
4935 LValue lowNonNullObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
4936 {
4937 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
4938
4939 LValue result = lowCell(edge, mode);
4940 speculateNonNullObject(edge, result);
4941 return result;
4942 }
4943
4944 LValue lowBoolean(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
4945 {
4946 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BooleanUse);
4947
4948 if (edge->hasConstant()) {
4949 JSValue value = m_graph.valueOfJSConstant(edge.node());
4950 if (!value.isBoolean()) {
4951 terminate(Uncountable);
4952 return m_out.booleanFalse;
4953 }
4954 return m_out.constBool(value.asBoolean());
4955 }
4956
4957 LoweredNodeValue value = m_booleanValues.get(edge.node());
4958 if (isValid(value))
4959 return value.value();
4960
4961 value = m_jsValueValues.get(edge.node());
4962 if (isValid(value)) {
4963 LValue unboxedResult = value.value();
4964 FTL_TYPE_CHECK(
4965 jsValueValue(unboxedResult), edge, SpecBoolean, isNotBoolean(unboxedResult));
4966 LValue result = unboxBoolean(unboxedResult);
4967 setBoolean(edge.node(), result);
4968 return result;
4969 }
4970
4971 RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecBoolean));
4972 terminate(Uncountable);
4973 return m_out.booleanFalse;
4974 }
4975
4976 LValue lowDouble(Edge edge)
4977 {
4978 RELEASE_ASSERT(isDouble(edge.useKind()));
4979
4980 LoweredNodeValue value = m_doubleValues.get(edge.node());
4981 if (isValid(value))
4982 return value.value();
4983
4984 RELEASE_ASSERT(!m_state.forNode(edge).m_type);
4985 terminate(Uncountable);
4986 return m_out.doubleZero;
4987 }
4988
4989 LValue lowJSValue(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
4990 {
4991 ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
4992 RELEASE_ASSERT(!isDouble(edge.useKind()));
4993 RELEASE_ASSERT(edge.useKind() != Int52RepUse);
4994
4995 if (edge->hasConstant())
4996 return m_out.constInt64(JSValue::encode(m_graph.valueOfJSConstant(edge.node())));
4997
4998 LoweredNodeValue value = m_jsValueValues.get(edge.node());
4999 if (isValid(value))
5000 return value.value();
5001
5002 value = m_int32Values.get(edge.node());
5003 if (isValid(value)) {
5004 LValue result = boxInt32(value.value());
5005 setJSValue(edge.node(), result);
5006 return result;
5007 }
5008
5009 value = m_booleanValues.get(edge.node());
5010 if (isValid(value)) {
5011 LValue result = boxBoolean(value.value());
5012 setJSValue(edge.node(), result);
5013 return result;
5014 }
5015
5016 RELEASE_ASSERT_NOT_REACHED();
5017 return 0;
5018 }
5019
5020 LValue lowStorage(Edge edge)
5021 {
5022 LoweredNodeValue value = m_storageValues.get(edge.node());
5023 if (isValid(value))
5024 return value.value();
5025
5026 LValue result = lowCell(edge);
5027 setStorage(edge.node(), result);
5028 return result;
5029 }
5030
5031 LValue strictInt52ToInt32(Edge edge, LValue value)
5032 {
5033 LValue result = m_out.castToInt32(value);
5034 FTL_TYPE_CHECK(
5035 noValue(), edge, SpecInt32,
5036 m_out.notEqual(m_out.signExt(result, m_out.int64), value));
5037 setInt32(edge.node(), result);
5038 return result;
5039 }
5040
5041 LValue strictInt52ToDouble(LValue value)
5042 {
5043 return m_out.intToDouble(value);
5044 }
5045
5046 LValue strictInt52ToJSValue(LValue value)
5047 {
5048 LBasicBlock isInt32 = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isInt32 case"));
5049 LBasicBlock isDouble = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue isDouble case"));
5050 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("strictInt52ToJSValue continuation"));
5051
5052 Vector<ValueFromBlock, 2> results;
5053
5054 LValue int32Value = m_out.castToInt32(value);
5055 m_out.branch(
5056 m_out.equal(m_out.signExt(int32Value, m_out.int64), value),
5057 unsure(isInt32), unsure(isDouble));
5058
5059 LBasicBlock lastNext = m_out.appendTo(isInt32, isDouble);
5060
5061 results.append(m_out.anchor(boxInt32(int32Value)));
5062 m_out.jump(continuation);
5063
5064 m_out.appendTo(isDouble, continuation);
5065
5066 results.append(m_out.anchor(boxDouble(m_out.intToDouble(value))));
5067 m_out.jump(continuation);
5068
5069 m_out.appendTo(continuation, lastNext);
5070 return m_out.phi(m_out.int64, results);
5071 }
5072
5073 LValue strictInt52ToInt52(LValue value)
5074 {
5075 return m_out.shl(value, m_out.constInt64(JSValue::int52ShiftAmount));
5076 }
5077
5078 LValue int52ToStrictInt52(LValue value)
5079 {
5080 return m_out.aShr(value, m_out.constInt64(JSValue::int52ShiftAmount));
5081 }
5082
5083 LValue isNotInt32(LValue jsValue)
5084 {
5085 return m_out.below(jsValue, m_tagTypeNumber);
5086 }
5087 LValue unboxInt32(LValue jsValue)
5088 {
5089 return m_out.castToInt32(jsValue);
5090 }
5091 LValue boxInt32(LValue value)
5092 {
5093 return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber);
5094 }
5095
5096 LValue isCellOrMisc(LValue jsValue)
5097 {
5098 return m_out.testIsZero64(jsValue, m_tagTypeNumber);
5099 }
5100 LValue isNotCellOrMisc(LValue jsValue)
5101 {
5102 return m_out.testNonZero64(jsValue, m_tagTypeNumber);
5103 }
5104
5105 LValue unboxDouble(LValue jsValue)
5106 {
5107 return m_out.bitCast(m_out.add(jsValue, m_tagTypeNumber), m_out.doubleType);
5108 }
5109 LValue boxDouble(LValue doubleValue)
5110 {
5111 return m_out.sub(m_out.bitCast(doubleValue, m_out.int64), m_tagTypeNumber);
5112 }
5113 LValue jsValueToDouble(Edge edge, LValue boxedValue)
5114 {
5115 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing int case"));
5116 LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing double case"));
5117 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing continuation"));
5118
5119 LValue isNotInt32;
5120 if (!m_interpreter.needsTypeCheck(edge, SpecInt32))
5121 isNotInt32 = m_out.booleanFalse;
5122 else if (!m_interpreter.needsTypeCheck(edge, ~SpecInt32))
5123 isNotInt32 = m_out.booleanTrue;
5124 else
5125 isNotInt32 = this->isNotInt32(boxedValue);
5126 m_out.branch(isNotInt32, unsure(doubleCase), unsure(intCase));
5127
5128 LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase);
5129
5130 ValueFromBlock intToDouble = m_out.anchor(
5131 m_out.intToDouble(unboxInt32(boxedValue)));
5132 m_out.jump(continuation);
5133
5134 m_out.appendTo(doubleCase, continuation);
5135
5136 FTL_TYPE_CHECK(
5137 jsValueValue(boxedValue), edge, SpecBytecodeNumber, isCellOrMisc(boxedValue));
5138
5139 ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(boxedValue));
5140 m_out.jump(continuation);
5141
5142 m_out.appendTo(continuation, lastNext);
5143
5144 return m_out.phi(m_out.doubleType, intToDouble, unboxedDouble);
5145 }
5146
5147 LValue jsValueToStrictInt52(Edge edge, LValue boxedValue)
5148 {
5149 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToInt52 unboxing int case"));
5150 LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToInt52 unboxing double case"));
5151 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToInt52 unboxing continuation"));
5152
5153 LValue isNotInt32;
5154 if (!m_interpreter.needsTypeCheck(edge, SpecInt32))
5155 isNotInt32 = m_out.booleanFalse;
5156 else if (!m_interpreter.needsTypeCheck(edge, ~SpecInt32))
5157 isNotInt32 = m_out.booleanTrue;
5158 else
5159 isNotInt32 = this->isNotInt32(boxedValue);
5160 m_out.branch(isNotInt32, unsure(doubleCase), unsure(intCase));
5161
5162 LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase);
5163
5164 ValueFromBlock intToInt52 = m_out.anchor(
5165 m_out.signExt(unboxInt32(boxedValue), m_out.int64));
5166 m_out.jump(continuation);
5167
5168 m_out.appendTo(doubleCase, continuation);
5169
5170 LValue possibleResult = m_out.call(
5171 m_out.operation(operationConvertBoxedDoubleToInt52), boxedValue);
5172 FTL_TYPE_CHECK(
5173 jsValueValue(boxedValue), edge, SpecInt32 | SpecInt52AsDouble,
5174 m_out.equal(possibleResult, m_out.constInt64(JSValue::notInt52)));
5175
5176 ValueFromBlock doubleToInt52 = m_out.anchor(possibleResult);
5177 m_out.jump(continuation);
5178
5179 m_out.appendTo(continuation, lastNext);
5180
5181 return m_out.phi(m_out.int64, intToInt52, doubleToInt52);
5182 }
5183
5184 LValue doubleToStrictInt52(Edge edge, LValue value)
5185 {
5186 LValue possibleResult = m_out.call(
5187 m_out.operation(operationConvertDoubleToInt52), value);
5188 FTL_TYPE_CHECK(
5189 doubleValue(value), edge, SpecInt52AsDouble,
5190 m_out.equal(possibleResult, m_out.constInt64(JSValue::notInt52)));
5191
5192 return possibleResult;
5193 }
5194
5195 LValue isNumber(LValue jsValue)
5196 {
5197 return isNotCellOrMisc(jsValue);
5198 }
5199 LValue isNotNumber(LValue jsValue)
5200 {
5201 return isCellOrMisc(jsValue);
5202 }
5203
5204 LValue isNotCell(LValue jsValue)
5205 {
5206 return m_out.testNonZero64(jsValue, m_tagMask);
5207 }
5208
5209 LValue isCell(LValue jsValue)
5210 {
5211 return m_out.testIsZero64(jsValue, m_tagMask);
5212 }
5213
5214 LValue isNotMisc(LValue value)
5215 {
5216 return m_out.above(value, m_out.constInt64(TagBitTypeOther | TagBitBool | TagBitUndefined));
5217 }
5218
5219 LValue isMisc(LValue value)
5220 {
5221 return m_out.bitNot(isNotMisc(value));
5222 }
5223
5224 LValue isNotBoolean(LValue jsValue)
5225 {
5226 return m_out.testNonZero64(
5227 m_out.bitXor(jsValue, m_out.constInt64(ValueFalse)),
5228 m_out.constInt64(~1));
5229 }
5230 LValue isBoolean(LValue jsValue)
5231 {
5232 return m_out.bitNot(isNotBoolean(jsValue));
5233 }
5234 LValue unboxBoolean(LValue jsValue)
5235 {
5236 // We want to use a cast that guarantees that LLVM knows that even the integer
5237 // value is just 0 or 1. But for now we do it the dumb way.
5238 return m_out.notZero64(m_out.bitAnd(jsValue, m_out.constInt64(1)));
5239 }
5240 LValue boxBoolean(LValue value)
5241 {
5242 return m_out.select(
5243 value, m_out.constInt64(ValueTrue), m_out.constInt64(ValueFalse));
5244 }
5245
5246 LValue isNotOther(LValue value)
5247 {
5248 return m_out.notEqual(
5249 m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
5250 m_out.constInt64(ValueNull));
5251 }
5252 LValue isOther(LValue value)
5253 {
5254 return m_out.equal(
5255 m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
5256 m_out.constInt64(ValueNull));
5257 }
5258
5259 void speculate(Edge edge)
5260 {
5261 switch (edge.useKind()) {
5262 case UntypedUse:
5263 break;
5264 case KnownInt32Use:
5265 case KnownStringUse:
5266 case DoubleRepUse:
5267 case Int52RepUse:
5268 ASSERT(!m_interpreter.needsTypeCheck(edge));
5269 break;
5270 case Int32Use:
5271 speculateInt32(edge);
5272 break;
5273 case CellUse:
5274 speculateCell(edge);
5275 break;
5276 case KnownCellUse:
5277 ASSERT(!m_interpreter.needsTypeCheck(edge));
5278 break;
5279 case MachineIntUse:
5280 speculateMachineInt(edge);
5281 break;
5282 case ObjectUse:
5283 speculateObject(edge);
5284 break;
5285 case ObjectOrOtherUse:
5286 speculateObjectOrOther(edge);
5287 break;
5288 case FinalObjectUse:
5289 speculateFinalObject(edge);
5290 break;
5291 case StringUse:
5292 speculateString(edge);
5293 break;
5294 case StringIdentUse:
5295 speculateStringIdent(edge);
5296 break;
5297 case StringObjectUse:
5298 speculateStringObject(edge);
5299 break;
5300 case StringOrStringObjectUse:
5301 speculateStringOrStringObject(edge);
5302 break;
5303 case NumberUse:
5304 speculateNumber(edge);
5305 break;
5306 case DoubleRepRealUse:
5307 speculateDoubleReal(edge);
5308 break;
5309 case DoubleRepMachineIntUse:
5310 speculateDoubleRepMachineInt(edge);
5311 break;
5312 case BooleanUse:
5313 speculateBoolean(edge);
5314 break;
5315 case NotStringVarUse:
5316 speculateNotStringVar(edge);
5317 break;
5318 case NotCellUse:
5319 speculateNotCell(edge);
5320 break;
5321 case OtherUse:
5322 speculateOther(edge);
5323 break;
5324 case MiscUse:
5325 speculateMisc(edge);
5326 break;
5327 default:
5328 dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n");
5329 RELEASE_ASSERT_NOT_REACHED();
5330 }
5331 }
5332
5333 void speculate(Node*, Edge edge)
5334 {
5335 speculate(edge);
5336 }
5337
5338 void speculateInt32(Edge edge)
5339 {
5340 lowInt32(edge);
5341 }
5342
5343 void speculateCell(Edge edge)
5344 {
5345 lowCell(edge);
5346 }
5347
5348 void speculateMachineInt(Edge edge)
5349 {
5350 if (!m_interpreter.needsTypeCheck(edge))
5351 return;
5352
5353 jsValueToStrictInt52(edge, lowJSValue(edge, ManualOperandSpeculation));
5354 }
5355
5356 LValue isObject(LValue cell)
5357 {
5358 return m_out.notEqual(
5359 m_out.load32(cell, m_heaps.JSCell_structureID),
5360 m_out.constInt32(vm().stringStructure->id()));
5361 }
5362
5363 LValue isNotString(LValue cell)
5364 {
5365 return isObject(cell);
5366 }
5367
5368 LValue isString(LValue cell)
5369 {
5370 return m_out.equal(
5371 m_out.load32(cell, m_heaps.JSCell_structureID),
5372 m_out.constInt32(vm().stringStructure->id()));
5373 }
5374
5375 LValue isNotObject(LValue cell)
5376 {
5377 return isString(cell);
5378 }
5379
5380 LValue isArrayType(LValue cell, ArrayMode arrayMode)
5381 {
5382 switch (arrayMode.type()) {
5383 case Array::Int32:
5384 case Array::Double:
5385 case Array::Contiguous: {
5386 LValue indexingType = m_out.load8(cell, m_heaps.JSCell_indexingType);
5387
5388 switch (arrayMode.arrayClass()) {
5389 case Array::OriginalArray:
5390 RELEASE_ASSERT_NOT_REACHED();
5391 return 0;
5392
5393 case Array::Array:
5394 return m_out.equal(
5395 m_out.bitAnd(indexingType, m_out.constInt8(IsArray | IndexingShapeMask)),
5396 m_out.constInt8(IsArray | arrayMode.shapeMask()));
5397
5398 case Array::NonArray:
5399 case Array::OriginalNonArray:
5400 return m_out.equal(
5401 m_out.bitAnd(indexingType, m_out.constInt8(IsArray | IndexingShapeMask)),
5402 m_out.constInt8(arrayMode.shapeMask()));
5403
5404 case Array::PossiblyArray:
5405 return m_out.equal(
5406 m_out.bitAnd(indexingType, m_out.constInt8(IndexingShapeMask)),
5407 m_out.constInt8(arrayMode.shapeMask()));
5408 }
5409
5410 RELEASE_ASSERT_NOT_REACHED();
5411 }
5412
5413 default:
5414 return m_out.equal(
5415 m_out.load8(cell, m_heaps.JSCell_typeInfoType),
5416 m_out.constInt8(typeForTypedArrayType(arrayMode.typedArrayType())));
5417 }
5418 }
5419
5420 LValue isType(LValue cell, JSType type)
5421 {
5422 return m_out.equal(
5423 m_out.load8(cell, m_heaps.JSCell_typeInfoType),
5424 m_out.constInt8(type));
5425 }
5426
5427 LValue isNotType(LValue cell, JSType type)
5428 {
5429 return m_out.bitNot(isType(cell, type));
5430 }
5431
5432 void speculateObject(Edge edge, LValue cell)
5433 {
5434 FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecObject, isNotObject(cell));
5435 }
5436
5437 void speculateObject(Edge edge)
5438 {
5439 speculateObject(edge, lowCell(edge));
5440 }
5441
5442 void speculateObjectOrOther(Edge edge)
5443 {
5444 if (!m_interpreter.needsTypeCheck(edge))
5445 return;
5446
5447 LValue value = lowJSValue(edge);
5448
5449 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther cell case"));
5450 LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther primitive case"));
5451 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther continuation"));
5452
5453 m_out.branch(isNotCell(value), unsure(primitiveCase), unsure(cellCase));
5454
5455 LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
5456
5457 FTL_TYPE_CHECK(
5458 jsValueValue(value), edge, (~SpecCell) | SpecObject, isNotObject(value));
5459
5460 m_out.jump(continuation);
5461
5462 m_out.appendTo(primitiveCase, continuation);
5463
5464 FTL_TYPE_CHECK(
5465 jsValueValue(value), edge, SpecCell | SpecOther, isNotOther(value));
5466
5467 m_out.jump(continuation);
5468
5469 m_out.appendTo(continuation, lastNext);
5470 }
5471
5472 void speculateFinalObject(Edge edge, LValue cell)
5473 {
5474 FTL_TYPE_CHECK(
5475 jsValueValue(cell), edge, SpecFinalObject, isNotType(cell, FinalObjectType));
5476 }
5477
5478 void speculateFinalObject(Edge edge)
5479 {
5480 speculateFinalObject(edge, lowCell(edge));
5481 }
5482
5483 void speculateString(Edge edge, LValue cell)
5484 {
5485 FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecString | ~SpecCell, isNotString(cell));
5486 }
5487
5488 void speculateString(Edge edge)
5489 {
5490 speculateString(edge, lowCell(edge));
5491 }
5492
5493 void speculateStringIdent(Edge edge, LValue string, LValue stringImpl)
5494 {
5495 if (!m_interpreter.needsTypeCheck(edge, SpecStringIdent | ~SpecString))
5496 return;
5497
5498 speculate(BadType, jsValueValue(string), edge.node(), m_out.isNull(stringImpl));
5499 speculate(
5500 BadType, jsValueValue(string), edge.node(),
5501 m_out.testIsZero32(
5502 m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
5503 m_out.constInt32(StringImpl::flagIsAtomic())));
5504 m_interpreter.filter(edge, SpecStringIdent | ~SpecString);
5505 }
5506
5507 void speculateStringIdent(Edge edge)
5508 {
5509 lowStringIdent(edge);
5510 }
5511
5512 void speculateStringObject(Edge edge)
5513 {
5514 if (!m_interpreter.needsTypeCheck(edge, SpecStringObject))
5515 return;
5516
5517 speculateStringObjectForCell(edge, lowCell(edge));
5518 m_interpreter.filter(edge, SpecStringObject);
5519 }
5520
5521 void speculateStringOrStringObject(Edge edge)
5522 {
5523 if (!m_interpreter.needsTypeCheck(edge, SpecString | SpecStringObject))
5524 return;
5525
5526 LBasicBlock notString = FTL_NEW_BLOCK(m_out, ("Speculate StringOrStringObject not string case"));
5527 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Speculate StringOrStringObject continuation"));
5528
5529 LValue structureID = m_out.load32(lowCell(edge), m_heaps.JSCell_structureID);
5530 m_out.branch(
5531 m_out.equal(structureID, m_out.constInt32(vm().stringStructure->id())),
5532 unsure(continuation), unsure(notString));
5533
5534 LBasicBlock lastNext = m_out.appendTo(notString, continuation);
5535 speculateStringObjectForStructureID(edge, structureID);
5536 m_out.jump(continuation);
5537
5538 m_out.appendTo(continuation, lastNext);
5539
5540 m_interpreter.filter(edge, SpecString | SpecStringObject);
5541 }
5542
5543 void speculateStringObjectForCell(Edge edge, LValue cell)
5544 {
5545 speculateStringObjectForStructureID(edge, m_out.load32(cell, m_heaps.JSCell_structureID));
5546 }
5547
5548 void speculateStringObjectForStructureID(Edge edge, LValue structureID)
5549 {
5550 Structure* stringObjectStructure =
5551 m_graph.globalObjectFor(m_node->origin.semantic)->stringObjectStructure();
5552
5553 if (m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(stringObjectStructure)))
5554 return;
5555
5556 speculate(
5557 NotStringObject, noValue(), 0,
5558 m_out.notEqual(structureID, weakStructure(stringObjectStructure)));
5559 }
5560
5561 void speculateNonNullObject(Edge edge, LValue cell)
5562 {
5563 FTL_TYPE_CHECK(
5564 jsValueValue(cell), edge, SpecObject,
5565 m_out.equal(
5566 m_out.load32(cell, m_heaps.JSCell_structureID),
5567 m_out.constInt32(vm().stringStructure->id())));
5568 if (masqueradesAsUndefinedWatchpointIsStillValid())
5569 return;
5570
5571 speculate(
5572 BadType, jsValueValue(cell), edge.node(),
5573 m_out.testNonZero8(
5574 m_out.load8(cell, m_heaps.JSCell_typeInfoFlags),
5575 m_out.constInt8(MasqueradesAsUndefined)));
5576 }
5577
5578 void speculateNumber(Edge edge)
5579 {
5580 LValue value = lowJSValue(edge, ManualOperandSpeculation);
5581 FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBytecodeNumber, isNotNumber(value));
5582 }
5583
5584 void speculateDoubleReal(Edge edge)
5585 {
5586 // Do an early return here because lowDouble() can create a lot of control flow.
5587 if (!m_interpreter.needsTypeCheck(edge))
5588 return;
5589
5590 LValue value = lowDouble(edge);
5591 FTL_TYPE_CHECK(
5592 doubleValue(value), edge, SpecDoubleReal,
5593 m_out.doubleNotEqualOrUnordered(value, value));
5594 }
5595
5596 void speculateDoubleRepMachineInt(Edge edge)
5597 {
5598 if (!m_interpreter.needsTypeCheck(edge))
5599 return;
5600
5601 doubleToStrictInt52(edge, lowDouble(edge));
5602 }
5603
5604 void speculateBoolean(Edge edge)
5605 {
5606 lowBoolean(edge);
5607 }
5608
5609 void speculateNotStringVar(Edge edge)
5610 {
5611 if (!m_interpreter.needsTypeCheck(edge, ~SpecStringVar))
5612 return;
5613
5614 LValue value = lowJSValue(edge, ManualOperandSpeculation);
5615
5616 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar is cell case"));
5617 LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar is string case"));
5618 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar continuation"));
5619
5620 m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation));
5621
5622 LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
5623 m_out.branch(isString(value), unsure(isStringCase), unsure(continuation));
5624
5625 m_out.appendTo(isStringCase, continuation);
5626 speculateStringIdent(edge, value, m_out.loadPtr(value, m_heaps.JSString_value));
5627 m_out.jump(continuation);
5628
5629 m_out.appendTo(continuation, lastNext);
5630 }
5631
5632 void speculateNotCell(Edge edge)
5633 {
5634 if (!m_interpreter.needsTypeCheck(edge))
5635 return;
5636
5637 LValue value = lowJSValue(edge, ManualOperandSpeculation);
5638 typeCheck(jsValueValue(value), edge, ~SpecCell, isCell(value));
5639 }
5640
5641 void speculateOther(Edge edge)
5642 {
5643 if (!m_interpreter.needsTypeCheck(edge))
5644 return;
5645
5646 LValue value = lowJSValue(edge, ManualOperandSpeculation);
5647 typeCheck(jsValueValue(value), edge, SpecOther, isNotOther(value));
5648 }
5649
5650 void speculateMisc(Edge edge)
5651 {
5652 if (!m_interpreter.needsTypeCheck(edge))
5653 return;
5654
5655 LValue value = lowJSValue(edge, ManualOperandSpeculation);
5656 typeCheck(jsValueValue(value), edge, SpecMisc, isNotMisc(value));
5657 }
5658
5659 bool masqueradesAsUndefinedWatchpointIsStillValid()
5660 {
5661 return m_graph.masqueradesAsUndefinedWatchpointIsStillValid(m_node->origin.semantic);
5662 }
5663
5664 LValue loadMarkByte(LValue base)
5665 {
5666 return m_out.load8(base, m_heaps.JSCell_gcData);
5667 }
5668
5669 void emitStoreBarrier(LValue base)
5670 {
5671 #if ENABLE(GGC)
5672 LBasicBlock isMarkedAndNotRemembered = FTL_NEW_BLOCK(m_out, ("Store barrier is marked block"));
5673 LBasicBlock bufferHasSpace = FTL_NEW_BLOCK(m_out, ("Store barrier buffer has space"));
5674 LBasicBlock bufferIsFull = FTL_NEW_BLOCK(m_out, ("Store barrier buffer is full"));
5675 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Store barrier continuation"));
5676
5677 // Check the mark byte.
5678 m_out.branch(
5679 m_out.notZero8(loadMarkByte(base)), usually(continuation), rarely(isMarkedAndNotRemembered));
5680
5681 // Append to the write barrier buffer.
5682 LBasicBlock lastNext = m_out.appendTo(isMarkedAndNotRemembered, bufferHasSpace);
5683 LValue currentBufferIndex = m_out.load32(m_out.absolute(&vm().heap.writeBarrierBuffer().m_currentIndex));
5684 LValue bufferCapacity = m_out.load32(m_out.absolute(&vm().heap.writeBarrierBuffer().m_capacity));
5685 m_out.branch(
5686 m_out.lessThan(currentBufferIndex, bufferCapacity),
5687 usually(bufferHasSpace), rarely(bufferIsFull));
5688
5689 // Buffer has space, store to it.
5690 m_out.appendTo(bufferHasSpace, bufferIsFull);
5691 LValue writeBarrierBufferBase = m_out.loadPtr(m_out.absolute(&vm().heap.writeBarrierBuffer().m_buffer));
5692 m_out.storePtr(base, m_out.baseIndex(m_heaps.WriteBarrierBuffer_bufferContents, writeBarrierBufferBase, m_out.zeroExt(currentBufferIndex, m_out.intPtr), ScalePtr));
5693 m_out.store32(m_out.add(currentBufferIndex, m_out.constInt32(1)), m_out.absolute(&vm().heap.writeBarrierBuffer().m_currentIndex));
5694 m_out.jump(continuation);
5695
5696 // Buffer is out of space, flush it.
5697 m_out.appendTo(bufferIsFull, continuation);
5698 vmCall(m_out.operation(operationFlushWriteBarrierBuffer), m_callFrame, base, NoExceptions);
5699 m_out.jump(continuation);
5700
5701 m_out.appendTo(continuation, lastNext);
5702 #else
5703 UNUSED_PARAM(base);
5704 #endif
5705 }
5706
5707 enum ExceptionCheckMode { NoExceptions, CheckExceptions };
5708
5709 LValue vmCall(LValue function, ExceptionCheckMode mode = CheckExceptions)
5710 {
5711 callPreflight();
5712 LValue result = m_out.call(function);
5713 callCheck(mode);
5714 return result;
5715 }
5716 LValue vmCall(LValue function, LValue arg1, ExceptionCheckMode mode = CheckExceptions)
5717 {
5718 callPreflight();
5719 LValue result = m_out.call(function, arg1);
5720 callCheck(mode);
5721 return result;
5722 }
5723 LValue vmCall(LValue function, LValue arg1, LValue arg2, ExceptionCheckMode mode = CheckExceptions)
5724 {
5725 callPreflight();
5726 LValue result = m_out.call(function, arg1, arg2);
5727 callCheck(mode);
5728 return result;
5729 }
5730 LValue vmCall(LValue function, LValue arg1, LValue arg2, LValue arg3, ExceptionCheckMode mode = CheckExceptions)
5731 {
5732 callPreflight();
5733 LValue result = m_out.call(function, arg1, arg2, arg3);
5734 callCheck(mode);
5735 return result;
5736 }
5737 LValue vmCall(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, ExceptionCheckMode mode = CheckExceptions)
5738 {
5739 callPreflight();
5740 LValue result = m_out.call(function, arg1, arg2, arg3, arg4);
5741 callCheck(mode);
5742 return result;
5743 }
5744
5745 void callPreflight(CodeOrigin codeOrigin)
5746 {
5747 m_out.store32(
5748 m_out.constInt32(
5749 CallFrame::Location::encodeAsCodeOriginIndex(
5750 m_ftlState.jitCode->common.addCodeOrigin(codeOrigin))),
5751 tagFor(JSStack::ArgumentCount));
5752 }
5753 void callPreflight()
5754 {
5755 callPreflight(m_node->origin.semantic);
5756 }
5757
5758 void callCheck(ExceptionCheckMode mode = CheckExceptions)
5759 {
5760 if (mode == NoExceptions)
5761 return;
5762
5763 if (Options::enableExceptionFuzz())
5764 m_out.call(m_out.operation(operationExceptionFuzz));
5765
5766 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Exception check continuation"));
5767
5768 m_out.branch(
5769 m_out.notZero64(m_out.load64(m_out.absolute(vm().addressOfException()))),
5770 rarely(m_handleExceptions), usually(continuation));
5771
5772 m_out.appendTo(continuation);
5773 }
5774
5775 LBasicBlock lowBlock(BasicBlock* block)
5776 {
5777 return m_blocks.get(block);
5778 }
5779
5780 void initializeOSRExitStateForBlock()
5781 {
5782 m_availability = m_highBlock->ssa->availabilityAtHead;
5783 }
5784
5785 void appendOSRExit(
5786 ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition)
5787 {
5788 if (verboseCompilationEnabled()) {
5789 dataLog(" OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", m_availability, "\n");
5790 if (!m_availableRecoveries.isEmpty())
5791 dataLog(" Available recoveries: ", listDump(m_availableRecoveries), "\n");
5792 }
5793
5794 ASSERT(m_ftlState.jitCode->osrExit.size() == m_ftlState.finalizer->osrExit.size());
5795
5796 m_ftlState.jitCode->osrExit.append(OSRExit(
5797 kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue),
5798 m_codeOriginForExitTarget, m_codeOriginForExitProfile,
5799 m_availability.numberOfArguments(), m_availability.numberOfLocals()));
5800 m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo());
5801
5802 OSRExit& exit = m_ftlState.jitCode->osrExit.last();
5803
5804 LBasicBlock lastNext = 0;
5805 LBasicBlock continuation = 0;
5806
5807 LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("OSR exit failCase for ", m_node));
5808 continuation = FTL_NEW_BLOCK(m_out, ("OSR exit continuation for ", m_node));
5809
5810 m_out.branch(failCondition, rarely(failCase), usually(continuation));
5811
5812 lastNext = m_out.appendTo(failCase, continuation);
5813
5814 emitOSRExitCall(exit, lowValue);
5815
5816 m_out.unreachable();
5817
5818 m_out.appendTo(continuation, lastNext);
5819 }
5820
5821 void emitOSRExitCall(OSRExit& exit, FormattedValue lowValue)
5822 {
5823 ExitArgumentList arguments;
5824
5825 CodeOrigin codeOrigin = exit.m_codeOrigin;
5826
5827 buildExitArguments(exit, arguments, lowValue, codeOrigin);
5828
5829 callStackmap(exit, arguments);
5830 }
5831
5832 void buildExitArguments(
5833 OSRExit& exit, ExitArgumentList& arguments, FormattedValue lowValue,
5834 CodeOrigin codeOrigin)
5835 {
5836 if (!!lowValue)
5837 arguments.append(lowValue.value());
5838
5839 for (unsigned i = 0; i < exit.m_values.size(); ++i) {
5840 int operand = exit.m_values.operandForIndex(i);
5841 bool isLive = m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin);
5842 if (!isLive) {
5843 exit.m_values[i] = ExitValue::dead();
5844 continue;
5845 }
5846
5847 Availability availability = m_availability[i];
5848 FlushedAt flush = availability.flushedAt();
5849 switch (flush.format()) {
5850 case DeadFlush:
5851 case ConflictingFlush:
5852 if (availability.hasNode()) {
5853 addExitArgumentForNode(exit, arguments, i, availability.node());
5854 break;
5855 }
5856
5857 if (Options::validateFTLOSRExitLiveness()) {
5858 dataLog("Expected r", operand, " to be available but it wasn't.\n");
5859 RELEASE_ASSERT_NOT_REACHED();
5860 }
5861
5862 // This means that the DFG's DCE proved that the value is dead in bytecode
5863 // even though the bytecode liveness analysis thinks it's live. This is
5864 // acceptable since the DFG's DCE is by design more aggressive while still
5865 // being sound.
5866 exit.m_values[i] = ExitValue::dead();
5867 break;
5868
5869 case FlushedJSValue:
5870 case FlushedCell:
5871 case FlushedBoolean:
5872 exit.m_values[i] = ExitValue::inJSStack(flush.virtualRegister());
5873 break;
5874
5875 case FlushedInt32:
5876 exit.m_values[i] = ExitValue::inJSStackAsInt32(flush.virtualRegister());
5877 break;
5878
5879 case FlushedInt52:
5880 exit.m_values[i] = ExitValue::inJSStackAsInt52(flush.virtualRegister());
5881 break;
5882
5883 case FlushedDouble:
5884 exit.m_values[i] = ExitValue::inJSStackAsDouble(flush.virtualRegister());
5885 break;
5886
5887 case FlushedArguments:
5888 exit.m_values[i] = ExitValue::argumentsObjectThatWasNotCreated();
5889 break;
5890 }
5891 }
5892
5893 if (verboseCompilationEnabled())
5894 dataLog(" Exit values: ", exit.m_values, "\n");
5895 }
5896
5897 void callStackmap(OSRExit& exit, ExitArgumentList& arguments)
5898 {
5899 exit.m_stackmapID = m_stackmapIDs++;
5900 arguments.insert(0, m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
5901 arguments.insert(0, m_out.constInt64(exit.m_stackmapID));
5902
5903 m_out.call(m_out.stackmapIntrinsic(), arguments);
5904 }
5905
5906 void addExitArgumentForNode(
5907 OSRExit& exit, ExitArgumentList& arguments, unsigned index, Node* node)
5908 {
5909 ASSERT(node->shouldGenerate());
5910 ASSERT(node->hasResult());
5911
5912 if (tryToSetConstantExitArgument(exit, index, node))
5913 return;
5914
5915 for (unsigned i = 0; i < m_availableRecoveries.size(); ++i) {
5916 AvailableRecovery recovery = m_availableRecoveries[i];
5917 if (recovery.node() != node)
5918 continue;
5919
5920 exit.m_values[index] = ExitValue::recovery(
5921 recovery.opcode(), arguments.size(), arguments.size() + 1,
5922 recovery.format());
5923 arguments.append(recovery.left());
5924 arguments.append(recovery.right());
5925 return;
5926 }
5927
5928 LoweredNodeValue value = m_int32Values.get(node);
5929 if (isValid(value)) {
5930 addExitArgument(exit, arguments, index, ValueFormatInt32, value.value());
5931 return;
5932 }
5933
5934 value = m_int52Values.get(node);
5935 if (isValid(value)) {
5936 addExitArgument(exit, arguments, index, ValueFormatInt52, value.value());
5937 return;
5938 }
5939
5940 value = m_strictInt52Values.get(node);
5941 if (isValid(value)) {
5942 addExitArgument(exit, arguments, index, ValueFormatStrictInt52, value.value());
5943 return;
5944 }
5945
5946 value = m_booleanValues.get(node);
5947 if (isValid(value)) {
5948 LValue valueToPass = m_out.zeroExt(value.value(), m_out.int32);
5949 addExitArgument(exit, arguments, index, ValueFormatBoolean, valueToPass);
5950 return;
5951 }
5952
5953 value = m_jsValueValues.get(node);
5954 if (isValid(value)) {
5955 addExitArgument(exit, arguments, index, ValueFormatJSValue, value.value());
5956 return;
5957 }
5958
5959 value = m_doubleValues.get(node);
5960 if (isValid(value)) {
5961 addExitArgument(exit, arguments, index, ValueFormatDouble, value.value());
5962 return;
5963 }
5964
5965 startCrashing();
5966 dataLog("Cannot find value for node: ", node, " while compiling exit at ", exit.m_codeOrigin, " in node ", m_node, "\n");
5967 m_graph.dump();
5968 RELEASE_ASSERT_NOT_REACHED();
5969 }
5970
5971 bool tryToSetConstantExitArgument(OSRExit& exit, unsigned index, Node* node)
5972 {
5973 if (!node)
5974 return false;
5975
5976 switch (node->op()) {
5977 case JSConstant:
5978 case Int52Constant:
5979 case DoubleConstant:
5980 case WeakJSConstant:
5981 exit.m_values[index] = ExitValue::constant(m_graph.valueOfJSConstant(node));
5982 return true;
5983 case PhantomArguments:
5984 exit.m_values[index] = ExitValue::argumentsObjectThatWasNotCreated();
5985 return true;
5986 default:
5987 return false;
5988 }
5989 }
5990
5991 void addExitArgument(
5992 OSRExit& exit, ExitArgumentList& arguments, unsigned index, ValueFormat format,
5993 LValue value)
5994 {
5995 exit.m_values[index] = ExitValue::exitArgument(ExitArgument(format, arguments.size()));
5996 arguments.append(value);
5997 }
5998
5999 bool doesKill(Edge edge)
6000 {
6001 if (edge.doesNotKill())
6002 return false;
6003
6004 if (edge->hasConstant())
6005 return false;
6006
6007 return true;
6008 }
6009
6010 void addAvailableRecovery(
6011 Node* node, RecoveryOpcode opcode, LValue left, LValue right, ValueFormat format)
6012 {
6013 m_availableRecoveries.append(AvailableRecovery(node, opcode, left, right, format));
6014 }
6015
6016 void addAvailableRecovery(
6017 Edge edge, RecoveryOpcode opcode, LValue left, LValue right, ValueFormat format)
6018 {
6019 addAvailableRecovery(edge.node(), opcode, left, right, format);
6020 }
6021
6022 void setInt32(Node* node, LValue value)
6023 {
6024 m_int32Values.set(node, LoweredNodeValue(value, m_highBlock));
6025 }
6026 void setInt52(Node* node, LValue value)
6027 {
6028 m_int52Values.set(node, LoweredNodeValue(value, m_highBlock));
6029 }
6030 void setStrictInt52(Node* node, LValue value)
6031 {
6032 m_strictInt52Values.set(node, LoweredNodeValue(value, m_highBlock));
6033 }
6034 void setInt52(Node* node, LValue value, Int52Kind kind)
6035 {
6036 switch (kind) {
6037 case Int52:
6038 setInt52(node, value);
6039 return;
6040
6041 case StrictInt52:
6042 setStrictInt52(node, value);
6043 return;
6044 }
6045
6046 RELEASE_ASSERT_NOT_REACHED();
6047 }
6048 void setJSValue(Node* node, LValue value)
6049 {
6050 m_jsValueValues.set(node, LoweredNodeValue(value, m_highBlock));
6051 }
6052 void setBoolean(Node* node, LValue value)
6053 {
6054 m_booleanValues.set(node, LoweredNodeValue(value, m_highBlock));
6055 }
6056 void setStorage(Node* node, LValue value)
6057 {
6058 m_storageValues.set(node, LoweredNodeValue(value, m_highBlock));
6059 }
6060 void setDouble(Node* node, LValue value)
6061 {
6062 m_doubleValues.set(node, LoweredNodeValue(value, m_highBlock));
6063 }
6064
6065 void setInt32(LValue value)
6066 {
6067 setInt32(m_node, value);
6068 }
6069 void setInt52(LValue value)
6070 {
6071 setInt52(m_node, value);
6072 }
6073 void setStrictInt52(LValue value)
6074 {
6075 setStrictInt52(m_node, value);
6076 }
6077 void setInt52(LValue value, Int52Kind kind)
6078 {
6079 setInt52(m_node, value, kind);
6080 }
6081 void setJSValue(LValue value)
6082 {
6083 setJSValue(m_node, value);
6084 }
6085 void setBoolean(LValue value)
6086 {
6087 setBoolean(m_node, value);
6088 }
6089 void setStorage(LValue value)
6090 {
6091 setStorage(m_node, value);
6092 }
6093 void setDouble(LValue value)
6094 {
6095 setDouble(m_node, value);
6096 }
6097
6098 bool isValid(const LoweredNodeValue& value)
6099 {
6100 if (!value)
6101 return false;
6102 if (!m_graph.m_dominators.dominates(value.block(), m_highBlock))
6103 return false;
6104 return true;
6105 }
6106
6107 void addWeakReference(JSCell* target)
6108 {
6109 m_graph.m_plan.weakReferences.addLazily(target);
6110 }
6111
6112 LValue loadStructure(LValue value)
6113 {
6114 LValue tableIndex = m_out.load32(value, m_heaps.JSCell_structureID);
6115 LValue tableBase = m_out.loadPtr(
6116 m_out.absolute(vm().heap.structureIDTable().base()));
6117 LValue pointerIntoTable = m_out.baseIndex(
6118 tableBase, m_out.zeroExt(tableIndex, m_out.intPtr), ScaleEight);
6119 return m_out.loadPtr(TypedPointer(m_heaps.structureTable, pointerIntoTable));
6120 }
6121
6122 LValue weakPointer(JSCell* pointer)
6123 {
6124 addWeakReference(pointer);
6125 return m_out.constIntPtr(pointer);
6126 }
6127
6128 LValue weakStructure(Structure* structure)
6129 {
6130 addWeakReference(structure);
6131 return m_out.constInt32(structure->id());
6132 }
6133
6134 TypedPointer addressFor(LValue base, int operand, ptrdiff_t offset = 0)
6135 {
6136 return m_out.address(base, m_heaps.variables[operand], offset);
6137 }
6138 TypedPointer payloadFor(LValue base, int operand)
6139 {
6140 return addressFor(base, operand, PayloadOffset);
6141 }
6142 TypedPointer tagFor(LValue base, int operand)
6143 {
6144 return addressFor(base, operand, TagOffset);
6145 }
6146 TypedPointer addressFor(int operand, ptrdiff_t offset = 0)
6147 {
6148 return addressFor(VirtualRegister(operand), offset);
6149 }
6150 TypedPointer addressFor(VirtualRegister operand, ptrdiff_t offset = 0)
6151 {
6152 if (operand.isLocal())
6153 return addressFor(m_captured, operand.offset(), offset);
6154 return addressFor(m_callFrame, operand.offset(), offset);
6155 }
6156 TypedPointer payloadFor(int operand)
6157 {
6158 return payloadFor(VirtualRegister(operand));
6159 }
6160 TypedPointer payloadFor(VirtualRegister operand)
6161 {
6162 return addressFor(operand, PayloadOffset);
6163 }
6164 TypedPointer tagFor(int operand)
6165 {
6166 return tagFor(VirtualRegister(operand));
6167 }
6168 TypedPointer tagFor(VirtualRegister operand)
6169 {
6170 return addressFor(operand, TagOffset);
6171 }
6172
6173 VM& vm() { return m_graph.m_vm; }
6174 CodeBlock* codeBlock() { return m_graph.m_codeBlock; }
6175
6176 Graph& m_graph;
6177 State& m_ftlState;
6178 AbstractHeapRepository m_heaps;
6179 Output m_out;
6180
6181 LBasicBlock m_prologue;
6182 LBasicBlock m_handleExceptions;
6183 HashMap<BasicBlock*, LBasicBlock> m_blocks;
6184
6185 LValue m_callFrame;
6186 LValue m_captured;
6187 LValue m_tagTypeNumber;
6188 LValue m_tagMask;
6189
6190 HashMap<Node*, LoweredNodeValue> m_int32Values;
6191 HashMap<Node*, LoweredNodeValue> m_strictInt52Values;
6192 HashMap<Node*, LoweredNodeValue> m_int52Values;
6193 HashMap<Node*, LoweredNodeValue> m_jsValueValues;
6194 HashMap<Node*, LoweredNodeValue> m_booleanValues;
6195 HashMap<Node*, LoweredNodeValue> m_storageValues;
6196 HashMap<Node*, LoweredNodeValue> m_doubleValues;
6197
6198 HashMap<Node*, LValue> m_phis;
6199
6200 Operands<Availability> m_availability;
6201
6202 Vector<AvailableRecovery, 3> m_availableRecoveries;
6203
6204 InPlaceAbstractState m_state;
6205 AbstractInterpreter<InPlaceAbstractState> m_interpreter;
6206 BasicBlock* m_highBlock;
6207 BasicBlock* m_nextHighBlock;
6208 LBasicBlock m_nextLowBlock;
6209
6210 CodeOrigin m_codeOriginForExitTarget;
6211 CodeOrigin m_codeOriginForExitProfile;
6212 unsigned m_nodeIndex;
6213 Node* m_node;
6214
6215 uint32_t m_stackmapIDs;
6216 };
6217
6218 void lowerDFGToLLVM(State& state)
6219 {
6220 LowerDFGToLLVM lowering(state);
6221 lowering.lower();
6222 }
6223
6224 } } // namespace JSC::FTL
6225
6226 #endif // ENABLE(FTL_JIT)
6227