2 * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "FTLLowerDFGToB3.h"
31 #include "AirGenerationContext.h"
32 #include "AllowMacroScratchRegisterUsage.h"
33 #include "B3StackmapGenerationParams.h"
34 #include "CallFrameShuffler.h"
35 #include "CodeBlockWithJITType.h"
36 #include "DFGAbstractInterpreterInlines.h"
37 #include "DFGDominators.h"
38 #include "DFGInPlaceAbstractState.h"
39 #include "DFGOSRAvailabilityAnalysisPhase.h"
40 #include "DFGOSRExitFuzz.h"
41 #include "DirectArguments.h"
42 #include "FTLAbstractHeapRepository.h"
43 #include "FTLAvailableRecovery.h"
44 #include "FTLExceptionTarget.h"
45 #include "FTLForOSREntryJITCode.h"
46 #include "FTLFormattedValue.h"
47 #include "FTLLazySlowPathCall.h"
48 #include "FTLLoweredNodeValue.h"
49 #include "FTLOperations.h"
50 #include "FTLOutput.h"
51 #include "FTLPatchpointExceptionHandle.h"
52 #include "FTLThunks.h"
53 #include "FTLWeightedTarget.h"
54 #include "JITAddGenerator.h"
55 #include "JITBitAndGenerator.h"
56 #include "JITBitOrGenerator.h"
57 #include "JITBitXorGenerator.h"
58 #include "JITDivGenerator.h"
59 #include "JITInlineCacheGenerator.h"
60 #include "JITLeftShiftGenerator.h"
61 #include "JITMulGenerator.h"
62 #include "JITRightShiftGenerator.h"
63 #include "JITSubGenerator.h"
64 #include "JSCInlines.h"
65 #include "JSGeneratorFunction.h"
66 #include "JSLexicalEnvironment.h"
67 #include "OperandsInlines.h"
68 #include "ScopedArguments.h"
69 #include "ScopedArgumentsTable.h"
70 #include "ScratchRegisterAllocator.h"
71 #include "SetupVarargsFrame.h"
72 #include "VirtualRegister.h"
78 #include <unordered_set>
80 #include <wtf/ProcessID.h>
82 namespace JSC { namespace FTL {
89 std::atomic<int> compileCounter;
92 NO_RETURN_DUE_TO_CRASH static void ftlUnreachable()
97 NO_RETURN_DUE_TO_CRASH static void ftlUnreachable(
98 CodeBlock* codeBlock, BlockIndex blockIndex, unsigned nodeIndex)
100 dataLog("Crashing in thought-to-be-unreachable FTL-generated code for ", pointerDump(codeBlock), " at basic block #", blockIndex);
101 if (nodeIndex != UINT_MAX)
102 dataLog(", node @", nodeIndex);
108 // Using this instead of typeCheck() helps to reduce the load on B3, by creating
109 // significantly less dead code.
110 #define FTL_TYPE_CHECK_WITH_EXIT_KIND(exitKind, lowValue, highValue, typesPassedThrough, failCondition) do { \
111 FormattedValue _ftc_lowValue = (lowValue); \
112 Edge _ftc_highValue = (highValue); \
113 SpeculatedType _ftc_typesPassedThrough = (typesPassedThrough); \
114 if (!m_interpreter.needsTypeCheck(_ftc_highValue, _ftc_typesPassedThrough)) \
116 typeCheck(_ftc_lowValue, _ftc_highValue, _ftc_typesPassedThrough, (failCondition), exitKind); \
119 #define FTL_TYPE_CHECK(lowValue, highValue, typesPassedThrough, failCondition) \
120 FTL_TYPE_CHECK_WITH_EXIT_KIND(BadType, lowValue, highValue, typesPassedThrough, failCondition)
123 WTF_MAKE_NONCOPYABLE(LowerDFGToB3);
125 LowerDFGToB3(State& state)
126 : m_graph(state.graph)
129 , m_proc(*state.proc)
130 , m_state(state.graph)
131 , m_interpreter(state.graph, m_state)
137 State* state = &m_ftlState;
140 if (verboseCompilationEnabled()) {
142 "jsBody_", ++compileCounter, "_", codeBlock()->inferredName(),
143 "_", codeBlock()->hash());
147 m_graph.ensureDominators();
149 if (verboseCompilationEnabled())
150 dataLog("Function ready, beginning lowering.\n");
152 m_out.initialize(m_heaps);
154 // We use prologue frequency for all of the initialization code.
155 m_out.setFrequency(1);
157 m_prologue = FTL_NEW_BLOCK(m_out, ("Prologue"));
158 LBasicBlock stackOverflow = FTL_NEW_BLOCK(m_out, ("Stack overflow"));
159 m_handleExceptions = FTL_NEW_BLOCK(m_out, ("Handle Exceptions"));
161 LBasicBlock checkArguments = FTL_NEW_BLOCK(m_out, ("Check arguments"));
163 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
164 m_highBlock = m_graph.block(blockIndex);
167 m_out.setFrequency(m_highBlock->executionCount);
168 m_blocks.add(m_highBlock, FTL_NEW_BLOCK(m_out, ("Block ", *m_highBlock)));
171 // Back to prologue frequency for any bocks that get sneakily created in the initialization code.
172 m_out.setFrequency(1);
174 m_out.appendTo(m_prologue, stackOverflow);
175 m_out.initializeConstants(m_proc, m_prologue);
176 createPhiVariables();
178 size_t sizeOfCaptured = sizeof(JSValue) * m_graph.m_nextMachineLocal;
179 B3::SlotBaseValue* capturedBase = m_out.lockedStackSlot(sizeOfCaptured);
180 m_captured = m_out.add(capturedBase, m_out.constIntPtr(sizeOfCaptured));
181 state->capturedValue = capturedBase->slot();
183 auto preOrder = m_graph.blocksInPreOrder();
185 // We should not create any alloca's after this point, since they will cease to
186 // be mem2reg candidates.
188 m_callFrame = m_out.framePointer();
189 m_tagTypeNumber = m_out.constInt64(TagTypeNumber);
190 m_tagMask = m_out.constInt64(TagMask);
192 // Make sure that B3 knows that we really care about the mask registers. This forces the
193 // constants to be materialized in registers.
194 m_proc.addFastConstant(m_tagTypeNumber->key());
195 m_proc.addFastConstant(m_tagMask->key());
197 m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock));
200 didOverflowStack(), rarely(stackOverflow), usually(checkArguments));
202 m_out.appendTo(stackOverflow, m_handleExceptions);
203 m_out.call(m_out.voidType, m_out.operation(operationThrowStackOverflowError), m_callFrame, m_out.constIntPtr(codeBlock()));
204 m_out.patchpoint(Void)->setGenerator(
205 [=] (CCallHelpers& jit, const StackmapGenerationParams&) {
206 // We are terminal, so we can clobber everything. That's why we don't claim to
208 AllowMacroScratchRegisterUsage allowScratch(jit);
210 jit.copyCalleeSavesToVMCalleeSavesBuffer();
211 jit.move(CCallHelpers::TrustedImmPtr(jit.vm()), GPRInfo::argumentGPR0);
212 jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
213 CCallHelpers::Call call = jit.call();
214 jit.jumpToExceptionHandler();
217 [=] (LinkBuffer& linkBuffer) {
218 linkBuffer.link(call, FunctionPtr(lookupExceptionHandlerFromCallerFrame));
223 m_out.appendTo(m_handleExceptions, checkArguments);
224 Box<CCallHelpers::Label> exceptionHandler = state->exceptionHandler;
225 m_out.patchpoint(Void)->setGenerator(
226 [=] (CCallHelpers& jit, const StackmapGenerationParams&) {
227 CCallHelpers::Jump jump = jit.jump();
229 [=] (LinkBuffer& linkBuffer) {
230 linkBuffer.link(jump, linkBuffer.locationOf(*exceptionHandler));
235 m_out.appendTo(checkArguments, lowBlock(m_graph.block(0)));
236 availabilityMap().clear();
237 availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0);
238 for (unsigned i = codeBlock()->numParameters(); i--;) {
239 availabilityMap().m_locals.argument(i) =
240 Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i)));
243 m_origin = NodeOrigin(CodeOrigin(0), CodeOrigin(0), true);
244 for (unsigned i = codeBlock()->numParameters(); i--;) {
245 Node* node = m_graph.m_arguments[i];
246 VirtualRegister operand = virtualRegisterForArgument(i);
248 LValue jsValue = m_out.load64(addressFor(operand));
251 DFG_ASSERT(m_graph, node, operand == node->stackAccessData()->machineLocal);
253 // This is a hack, but it's an effective one. It allows us to do CSE on the
254 // primordial load of arguments. This assumes that the GetLocal that got put in
255 // place of the original SetArgument doesn't have any effects before it. This
257 m_loadedArgumentValues.add(node, jsValue);
260 switch (m_graph.m_argumentFormats[i]) {
262 speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue));
265 speculate(BadType, jsValueValue(jsValue), node, isNotBoolean(jsValue));
268 speculate(BadType, jsValueValue(jsValue), node, isNotCell(jsValue));
273 DFG_CRASH(m_graph, node, "Bad flush format for argument");
277 m_out.jump(lowBlock(m_graph.block(0)));
279 for (DFG::BasicBlock* block : preOrder)
282 // Make sure everything is decorated. This does a bunch of deferred decorating. This has
283 // to happen last because our abstract heaps are generated lazily. They have to be
284 // generated lazily because we have an infiniten number of numbered, indexed, and
285 // absolute heaps. We only become aware of the ones we actually mention while lowering.
286 m_heaps.computeRangesAndDecorateInstructions();
288 // We create all Phi's up front, but we may then decide not to compile the basic block
289 // that would have contained one of them. So this creates orphans, which triggers B3
290 // validation failures. Calling this fixes the issue.
292 // Note that you should avoid the temptation to make this call conditional upon
293 // validation being enabled. B3 makes no guarantees of any kind of correctness when
294 // dealing with IR that would have failed validation. For example, it would be valid to
295 // write a B3 phase that so aggressively assumes the lack of orphans that it would crash
296 // if any orphans were around. We might even have such phases already.
297 m_proc.deleteOrphans();
299 // We put the blocks into the B3 procedure in a super weird order. Now we reorder them.
300 m_out.applyBlockOrder();
305 void createPhiVariables()
307 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
308 DFG::BasicBlock* block = m_graph.block(blockIndex);
311 for (unsigned nodeIndex = block->size(); nodeIndex--;) {
312 Node* node = block->at(nodeIndex);
313 if (node->op() != DFG::Phi)
316 switch (node->flags() & NodeResultMask) {
317 case NodeResultDouble:
318 type = m_out.doubleType;
320 case NodeResultInt32:
323 case NodeResultInt52:
326 case NodeResultBoolean:
327 type = m_out.boolean;
333 DFG_CRASH(m_graph, node, "Bad Phi node result type");
336 m_phis.add(node, m_proc.add<Value>(B3::Phi, type, Origin(node)));
341 void compileBlock(DFG::BasicBlock* block)
346 if (verboseCompilationEnabled())
347 dataLog("Compiling block ", *block, "\n");
351 // Make sure that any blocks created while lowering code in the high block have the frequency of
352 // the high block. This is appropriate because B3 doesn't need precise frequencies. It just needs
353 // something roughly approximate for things like register allocation.
354 m_out.setFrequency(m_highBlock->executionCount);
356 LBasicBlock lowBlock = m_blocks.get(m_highBlock);
359 for (BlockIndex nextBlockIndex = m_highBlock->index + 1; nextBlockIndex < m_graph.numBlocks(); ++nextBlockIndex) {
360 m_nextHighBlock = m_graph.block(nextBlockIndex);
364 m_nextLowBlock = m_nextHighBlock ? m_blocks.get(m_nextHighBlock) : 0;
366 // All of this effort to find the next block gives us the ability to keep the
367 // generated IR in roughly program order. This ought not affect the performance
368 // of the generated code (since we expect B3 to reorder things) but it will
369 // make IR dumps easier to read.
370 m_out.appendTo(lowBlock, m_nextLowBlock);
372 if (Options::ftlCrashes())
375 if (!m_highBlock->cfaHasVisited) {
376 if (verboseCompilationEnabled())
377 dataLog("Bailing because CFA didn't reach.\n");
378 crash(m_highBlock->index, UINT_MAX);
382 m_availabilityCalculator.beginBlock(m_highBlock);
385 m_state.beginBasicBlock(m_highBlock);
387 for (m_nodeIndex = 0; m_nodeIndex < m_highBlock->size(); ++m_nodeIndex) {
388 if (!compileNode(m_nodeIndex))
393 void safelyInvalidateAfterTermination()
395 if (verboseCompilationEnabled())
396 dataLog("Bailing.\n");
399 // Invalidate dominated blocks. Under normal circumstances we would expect
400 // them to be invalidated already. But you can have the CFA become more
401 // precise over time because the structures of objects change on the main
402 // thread. Failing to do this would result in weird crashes due to a value
403 // being used but not defined. Race conditions FTW!
404 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
405 DFG::BasicBlock* target = m_graph.block(blockIndex);
408 if (m_graph.m_dominators->dominates(m_highBlock, target)) {
409 if (verboseCompilationEnabled())
410 dataLog("Block ", *target, " will bail also.\n");
411 target->cfaHasVisited = false;
416 bool compileNode(unsigned nodeIndex)
418 if (!m_state.isValid()) {
419 safelyInvalidateAfterTermination();
423 m_node = m_highBlock->at(nodeIndex);
424 m_origin = m_node->origin;
425 m_out.setOrigin(m_node);
427 if (verboseCompilationEnabled())
428 dataLog("Lowering ", m_node, "\n");
430 m_availableRecoveries.resize(0);
432 m_interpreter.startExecuting();
434 switch (m_node->op()) {
444 compileDoubleConstant();
447 compileInt52Constant();
453 compileDoubleAsInt32();
462 compileValueToInt32();
464 case BooleanToNumber:
465 compileBooleanToNumber();
467 case ExtractOSREntryLocal:
468 compileExtractOSREntryLocal();
490 compileArithAddOrSub();
506 compileArithMinOrMax();
521 compileArithRandom();
533 compileArithFRound();
536 compileArithNegate();
557 compileUInt32ToNumber();
560 compileCheckStructure();
566 compileCheckNotEmpty();
569 compileCheckBadCell();
575 compileGetExecutable();
577 case ArrayifyToStructure:
578 compileArrayifyToStructure();
581 compilePutStructure();
597 compilePutAccessorById();
599 case PutGetterSetterById:
600 compilePutGetterSetterById();
604 compilePutAccessorByVal();
607 compileGetButterfly();
609 case GetButterflyReadOnly:
610 compileGetButterflyReadOnly();
612 case ConstantStoragePointer:
613 compileConstantStoragePointer();
615 case GetIndexedPropertyStorage:
616 compileGetIndexedPropertyStorage();
622 compileGetArrayLength();
625 compileCheckInBounds();
630 case GetMyArgumentByVal:
631 compileGetMyArgumentByVal();
644 case CreateActivation:
645 compileCreateActivation();
648 case NewArrowFunction:
649 case NewGeneratorFunction:
650 compileNewFunction();
652 case CreateDirectArguments:
653 compileCreateDirectArguments();
655 case CreateScopedArguments:
656 compileCreateScopedArguments();
658 case CreateClonedArguments:
659 compileCreateClonedArguments();
668 compileNewArrayBuffer();
670 case NewArrayWithSize:
671 compileNewArrayWithSize();
674 compileNewTypedArray();
676 case GetTypedArrayByteOffset:
677 compileGetTypedArrayByteOffset();
679 case AllocatePropertyStorage:
680 compileAllocatePropertyStorage();
682 case ReallocatePropertyStorage:
683 compileReallocatePropertyStorage();
686 case CallStringConstructor:
687 compileToStringOrCallStringConstructor();
690 compileToPrimitive();
696 compileStringCharAt();
698 case StringCharCodeAt:
699 compileStringCharCodeAt();
701 case StringFromCharCode:
702 compileStringFromCharCode();
705 case GetGetterSetterByOffset:
706 compileGetByOffset();
714 case MultiGetByOffset:
715 compileMultiGetByOffset();
718 compilePutByOffset();
720 case MultiPutByOffset:
721 compileMultiPutByOffset();
724 case GetGlobalLexicalVariable:
725 compileGetGlobalVariable();
727 case PutGlobalVariable:
728 compilePutGlobalVariable();
731 compileNotifyWrite();
736 case GetArgumentCount:
737 compileGetArgumentCount();
746 compileGetClosureVar();
749 compilePutClosureVar();
751 case GetFromArguments:
752 compileGetFromArguments();
755 compilePutToArguments();
760 case CompareStrictEq:
761 compileCompareStrictEq();
764 compileCompareLess();
767 compileCompareLessEq();
770 compileCompareGreater();
772 case CompareGreaterEq:
773 compileCompareGreaterEq();
779 case TailCallInlinedCaller:
781 compileCallOrConstruct();
787 case CallForwardVarargs:
788 case TailCallVarargs:
789 case TailCallVarargsInlinedCaller:
790 case TailCallForwardVarargs:
791 case TailCallForwardVarargsInlinedCaller:
792 case ConstructVarargs:
793 case ConstructForwardVarargs:
794 compileCallOrConstructVarargs();
797 compileLoadVarargs();
800 compileForwardVarargs();
815 compileForceOSRExit();
818 case ThrowReferenceError:
821 case InvalidationPoint:
822 compileInvalidationPoint();
825 compileIsUndefined();
840 compileIsObjectOrNull();
848 case CheckTypeInfoFlags:
849 compileCheckTypeInfoFlags();
851 case OverridesHasInstance:
852 compileOverridesHasInstance();
857 case InstanceOfCustom:
858 compileInstanceOfCustom();
861 compileCountExecution();
864 compileStoreBarrier();
866 case HasIndexedProperty:
867 compileHasIndexedProperty();
869 case HasGenericProperty:
870 compileHasGenericProperty();
872 case HasStructureProperty:
873 compileHasStructureProperty();
876 compileGetDirectPname();
878 case GetEnumerableLength:
879 compileGetEnumerableLength();
881 case GetPropertyEnumerator:
882 compileGetPropertyEnumerator();
884 case GetEnumeratorStructurePname:
885 compileGetEnumeratorStructurePname();
887 case GetEnumeratorGenericPname:
888 compileGetEnumeratorGenericPname();
891 compileToIndexString();
893 case CheckStructureImmediate:
894 compileCheckStructureImmediate();
896 case MaterializeNewObject:
897 compileMaterializeNewObject();
899 case MaterializeCreateActivation:
900 compileMaterializeCreateActivation();
902 case CheckWatchdogTimer:
903 compileCheckWatchdogTimer();
909 compileGetRestLength();
917 case PhantomNewObject:
918 case PhantomNewFunction:
919 case PhantomNewGeneratorFunction:
920 case PhantomCreateActivation:
921 case PhantomDirectArguments:
922 case PhantomClonedArguments:
928 DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend");
932 if (m_node->isTerminal())
935 if (!m_state.isValid()) {
936 safelyInvalidateAfterTermination();
940 m_availabilityCalculator.executeNode(m_node);
941 m_interpreter.executeEffects(nodeIndex);
946 void compileUpsilon()
948 LValue upsilonValue = nullptr;
949 switch (m_node->child1().useKind()) {
951 upsilonValue = lowDouble(m_node->child1());
955 upsilonValue = lowInt32(m_node->child1());
958 upsilonValue = lowInt52(m_node->child1());
961 case KnownBooleanUse:
962 upsilonValue = lowBoolean(m_node->child1());
966 upsilonValue = lowCell(m_node->child1());
969 upsilonValue = lowJSValue(m_node->child1());
972 DFG_CRASH(m_graph, m_node, "Bad use kind");
975 ValueFromBlock upsilon = m_out.anchor(upsilonValue);
976 LValue phiNode = m_phis.get(m_node->phi());
977 m_out.addIncomingToPhi(phiNode, upsilon);
982 LValue phi = m_phis.get(m_node);
983 m_out.m_block->append(phi);
985 switch (m_node->flags() & NodeResultMask) {
986 case NodeResultDouble:
989 case NodeResultInt32:
992 case NodeResultInt52:
995 case NodeResultBoolean:
1002 DFG_CRASH(m_graph, m_node, "Bad use kind");
1007 void compileDoubleConstant()
1009 setDouble(m_out.constDouble(m_node->asNumber()));
1012 void compileInt52Constant()
1014 int64_t value = m_node->asMachineInt();
1016 setInt52(m_out.constInt64(value << JSValue::int52ShiftAmount));
1017 setStrictInt52(m_out.constInt64(value));
1020 void compileDoubleRep()
1022 switch (m_node->child1().useKind()) {
1023 case RealNumberUse: {
1024 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
1026 LValue doubleValue = unboxDouble(value);
1028 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("DoubleRep RealNumberUse int case"));
1029 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("DoubleRep continuation"));
1031 ValueFromBlock fastResult = m_out.anchor(doubleValue);
1033 m_out.doubleEqual(doubleValue, doubleValue),
1034 usually(continuation), rarely(intCase));
1036 LBasicBlock lastNext = m_out.appendTo(intCase, continuation);
1039 jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber,
1040 isNotInt32(value, provenType(m_node->child1()) & ~SpecFullDouble));
1041 ValueFromBlock slowResult = m_out.anchor(m_out.intToDouble(unboxInt32(value)));
1042 m_out.jump(continuation);
1044 m_out.appendTo(continuation, lastNext);
1046 setDouble(m_out.phi(m_out.doubleType, fastResult, slowResult));
1052 bool shouldConvertNonNumber = m_node->child1().useKind() == NotCellUse;
1054 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
1056 LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing int case"));
1057 LBasicBlock doubleTesting = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing double case"));
1058 LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing double case"));
1059 LBasicBlock nonDoubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing undefined case"));
1060 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing continuation"));
1063 isNotInt32(value, provenType(m_node->child1())),
1064 unsure(doubleTesting), unsure(intCase));
1066 LBasicBlock lastNext = m_out.appendTo(intCase, doubleTesting);
1068 ValueFromBlock intToDouble = m_out.anchor(
1069 m_out.intToDouble(unboxInt32(value)));
1070 m_out.jump(continuation);
1072 m_out.appendTo(doubleTesting, doubleCase);
1073 LValue valueIsNumber = isNumber(value, provenType(m_node->child1()));
1074 m_out.branch(valueIsNumber, usually(doubleCase), rarely(nonDoubleCase));
1076 m_out.appendTo(doubleCase, nonDoubleCase);
1077 ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(value));
1078 m_out.jump(continuation);
1080 if (shouldConvertNonNumber) {
1081 LBasicBlock undefinedCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting undefined case"));
1082 LBasicBlock testNullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing null case"));
1083 LBasicBlock nullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting null case"));
1084 LBasicBlock testBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing boolean true case"));
1085 LBasicBlock convertBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean true case"));
1086 LBasicBlock convertBooleanFalseCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean false case"));
1088 m_out.appendTo(nonDoubleCase, undefinedCase);
1089 LValue valueIsUndefined = m_out.equal(value, m_out.constInt64(ValueUndefined));
1090 m_out.branch(valueIsUndefined, unsure(undefinedCase), unsure(testNullCase));
1092 m_out.appendTo(undefinedCase, testNullCase);
1093 ValueFromBlock convertedUndefined = m_out.anchor(m_out.constDouble(PNaN));
1094 m_out.jump(continuation);
1096 m_out.appendTo(testNullCase, nullCase);
1097 LValue valueIsNull = m_out.equal(value, m_out.constInt64(ValueNull));
1098 m_out.branch(valueIsNull, unsure(nullCase), unsure(testBooleanTrueCase));
1100 m_out.appendTo(nullCase, testBooleanTrueCase);
1101 ValueFromBlock convertedNull = m_out.anchor(m_out.constDouble(0));
1102 m_out.jump(continuation);
1104 m_out.appendTo(testBooleanTrueCase, convertBooleanTrueCase);
1105 LValue valueIsBooleanTrue = m_out.equal(value, m_out.constInt64(ValueTrue));
1106 m_out.branch(valueIsBooleanTrue, unsure(convertBooleanTrueCase), unsure(convertBooleanFalseCase));
1108 m_out.appendTo(convertBooleanTrueCase, convertBooleanFalseCase);
1109 ValueFromBlock convertedTrue = m_out.anchor(m_out.constDouble(1));
1110 m_out.jump(continuation);
1112 m_out.appendTo(convertBooleanFalseCase, continuation);
1114 LValue valueIsNotBooleanFalse = m_out.notEqual(value, m_out.constInt64(ValueFalse));
1115 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), ~SpecCell, valueIsNotBooleanFalse);
1116 ValueFromBlock convertedFalse = m_out.anchor(m_out.constDouble(0));
1117 m_out.jump(continuation);
1119 m_out.appendTo(continuation, lastNext);
1120 setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble, convertedUndefined, convertedNull, convertedTrue, convertedFalse));
1123 m_out.appendTo(nonDoubleCase, continuation);
1124 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecBytecodeNumber, m_out.booleanTrue);
1125 m_out.unreachable();
1127 m_out.appendTo(continuation, lastNext);
1129 setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble));
1134 setDouble(strictInt52ToDouble(lowStrictInt52(m_node->child1())));
1139 DFG_CRASH(m_graph, m_node, "Bad use kind");
1143 void compileDoubleAsInt32()
1145 LValue integerValue = convertDoubleToInt32(lowDouble(m_node->child1()), shouldCheckNegativeZero(m_node->arithMode()));
1146 setInt32(integerValue);
1149 void compileValueRep()
1151 switch (m_node->child1().useKind()) {
1152 case DoubleRepUse: {
1153 LValue value = lowDouble(m_node->child1());
1155 if (m_interpreter.needsTypeCheck(m_node->child1(), ~SpecDoubleImpureNaN)) {
1156 value = m_out.select(
1157 m_out.doubleEqual(value, value), value, m_out.constDouble(PNaN));
1160 setJSValue(boxDouble(value));
1165 setJSValue(strictInt52ToJSValue(lowStrictInt52(m_node->child1())));
1170 DFG_CRASH(m_graph, m_node, "Bad use kind");
1174 void compileInt52Rep()
1176 switch (m_node->child1().useKind()) {
1178 setStrictInt52(m_out.signExt32To64(lowInt32(m_node->child1())));
1183 jsValueToStrictInt52(
1184 m_node->child1(), lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1187 case DoubleRepMachineIntUse:
1189 doubleToStrictInt52(
1190 m_node->child1(), lowDouble(m_node->child1())));
1194 RELEASE_ASSERT_NOT_REACHED();
1198 void compileValueToInt32()
1200 switch (m_node->child1().useKind()) {
1202 setInt32(m_out.castToInt32(lowStrictInt52(m_node->child1())));
1206 setInt32(doubleToInt32(lowDouble(m_node->child1())));
1211 LoweredNodeValue value = m_int32Values.get(m_node->child1().node());
1212 if (isValid(value)) {
1213 setInt32(value.value());
1217 value = m_jsValueValues.get(m_node->child1().node());
1218 if (isValid(value)) {
1219 setInt32(numberOrNotCellToInt32(m_node->child1(), value.value()));
1223 // We'll basically just get here for constants. But it's good to have this
1224 // catch-all since we often add new representations into the mix.
1226 numberOrNotCellToInt32(
1228 lowJSValue(m_node->child1(), ManualOperandSpeculation)));
1233 DFG_CRASH(m_graph, m_node, "Bad use kind");
1238 void compileBooleanToNumber()
1240 switch (m_node->child1().useKind()) {
1242 setInt32(m_out.zeroExt(lowBoolean(m_node->child1()), m_out.int32));
1247 LValue value = lowJSValue(m_node->child1());
1249 if (!m_interpreter.needsTypeCheck(m_node->child1(), SpecBoolInt32 | SpecBoolean)) {
1250 setInt32(m_out.bitAnd(m_out.castToInt32(value), m_out.int32One));
1254 LBasicBlock booleanCase = FTL_NEW_BLOCK(m_out, ("BooleanToNumber boolean case"));
1255 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("BooleanToNumber continuation"));
1257 ValueFromBlock notBooleanResult = m_out.anchor(value);
1259 isBoolean(value, provenType(m_node->child1())),
1260 unsure(booleanCase), unsure(continuation));
1262 LBasicBlock lastNext = m_out.appendTo(booleanCase, continuation);
1263 ValueFromBlock booleanResult = m_out.anchor(m_out.bitOr(
1264 m_out.zeroExt(unboxBoolean(value), m_out.int64), m_tagTypeNumber));
1265 m_out.jump(continuation);
1267 m_out.appendTo(continuation, lastNext);
1268 setJSValue(m_out.phi(m_out.int64, booleanResult, notBooleanResult));
1273 RELEASE_ASSERT_NOT_REACHED();
1278 void compileExtractOSREntryLocal()
1280 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(
1281 m_ftlState.jitCode->ftlForOSREntry()->entryBuffer()->dataBuffer());
1282 setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal())));
1285 void compileGetStack()
1287 // GetLocals arise only for captured variables and arguments. For arguments, we might have
1288 // already loaded it.
1289 if (LValue value = m_loadedArgumentValues.get(m_node)) {
1294 StackAccessData* data = m_node->stackAccessData();
1295 AbstractValue& value = m_state.variables().operand(data->local);
1297 DFG_ASSERT(m_graph, m_node, isConcrete(data->format));
1298 DFG_ASSERT(m_graph, m_node, data->format != FlushedDouble); // This just happens to not arise for GetStacks, right now. It would be trivial to support.
1300 if (isInt32Speculation(value.m_type))
1301 setInt32(m_out.load32(payloadFor(data->machineLocal)));
1303 setJSValue(m_out.load64(addressFor(data->machineLocal)));
1306 void compilePutStack()
1308 StackAccessData* data = m_node->stackAccessData();
1309 switch (data->format) {
1310 case FlushedJSValue: {
1311 LValue value = lowJSValue(m_node->child1());
1312 m_out.store64(value, addressFor(data->machineLocal));
1316 case FlushedDouble: {
1317 LValue value = lowDouble(m_node->child1());
1318 m_out.storeDouble(value, addressFor(data->machineLocal));
1322 case FlushedInt32: {
1323 LValue value = lowInt32(m_node->child1());
1324 m_out.store32(value, payloadFor(data->machineLocal));
1328 case FlushedInt52: {
1329 LValue value = lowInt52(m_node->child1());
1330 m_out.store64(value, addressFor(data->machineLocal));
1335 LValue value = lowCell(m_node->child1());
1336 m_out.store64(value, addressFor(data->machineLocal));
1340 case FlushedBoolean: {
1341 speculateBoolean(m_node->child1());
1343 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1344 addressFor(data->machineLocal));
1349 DFG_CRASH(m_graph, m_node, "Bad flush format");
1356 DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, speculate);
1359 void compileToThis()
1361 LValue value = lowJSValue(m_node->child1());
1363 LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("ToThis is cell case"));
1364 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ToThis slow case"));
1365 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToThis continuation"));
1368 isCell(value, provenType(m_node->child1())), usually(isCellCase), rarely(slowCase));
1370 LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase);
1371 ValueFromBlock fastResult = m_out.anchor(value);
1372 m_out.branch(isType(value, FinalObjectType), usually(continuation), rarely(slowCase));
1374 m_out.appendTo(slowCase, continuation);
1375 J_JITOperation_EJ function;
1376 if (m_graph.isStrictModeFor(m_node->origin.semantic))
1377 function = operationToThisStrict;
1379 function = operationToThis;
1380 ValueFromBlock slowResult = m_out.anchor(
1381 vmCall(m_out.int64, m_out.operation(function), m_callFrame, value));
1382 m_out.jump(continuation);
1384 m_out.appendTo(continuation, lastNext);
1385 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
1388 void compileValueAdd()
1390 emitBinarySnippet<JITAddGenerator>(operationValueAdd);
1393 void compileStrCat()
1396 if (m_node->child3()) {
1398 m_out.int64, m_out.operation(operationStrCat3), m_callFrame,
1399 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1400 lowJSValue(m_node->child2(), ManualOperandSpeculation),
1401 lowJSValue(m_node->child3(), ManualOperandSpeculation));
1404 m_out.int64, m_out.operation(operationStrCat2), m_callFrame,
1405 lowJSValue(m_node->child1(), ManualOperandSpeculation),
1406 lowJSValue(m_node->child2(), ManualOperandSpeculation));
1411 void compileArithAddOrSub()
1413 bool isSub = m_node->op() == ArithSub;
1414 switch (m_node->binaryUseKind()) {
1416 LValue left = lowInt32(m_node->child1());
1417 LValue right = lowInt32(m_node->child2());
1419 if (!shouldCheckOverflow(m_node->arithMode())) {
1420 setInt32(isSub ? m_out.sub(left, right) : m_out.add(left, right));
1424 CheckValue* result =
1425 isSub ? m_out.speculateSub(left, right) : m_out.speculateAdd(left, right);
1426 blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
1432 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52)
1433 && !abstractValue(m_node->child2()).couldBeType(SpecInt52)) {
1435 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1436 LValue right = lowInt52(m_node->child2(), kind);
1437 setInt52(isSub ? m_out.sub(left, right) : m_out.add(left, right), kind);
1441 LValue left = lowInt52(m_node->child1());
1442 LValue right = lowInt52(m_node->child2());
1443 CheckValue* result =
1444 isSub ? m_out.speculateSub(left, right) : m_out.speculateAdd(left, right);
1445 blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
1450 case DoubleRepUse: {
1451 LValue C1 = lowDouble(m_node->child1());
1452 LValue C2 = lowDouble(m_node->child2());
1454 setDouble(isSub ? m_out.doubleSub(C1, C2) : m_out.doubleAdd(C1, C2));
1460 DFG_CRASH(m_graph, m_node, "Bad use kind");
1464 emitBinarySnippet<JITSubGenerator>(operationValueSub);
1469 DFG_CRASH(m_graph, m_node, "Bad use kind");
1474 void compileArithClz32()
1476 LValue operand = lowInt32(m_node->child1());
1477 setInt32(m_out.ctlz32(operand));
1480 void compileArithMul()
1482 switch (m_node->binaryUseKind()) {
1484 LValue left = lowInt32(m_node->child1());
1485 LValue right = lowInt32(m_node->child2());
1489 if (!shouldCheckOverflow(m_node->arithMode()))
1490 result = m_out.mul(left, right);
1492 CheckValue* speculation = m_out.speculateMul(left, right);
1493 blessSpeculation(speculation, Overflow, noValue(), nullptr, m_origin);
1494 result = speculation;
1497 if (shouldCheckNegativeZero(m_node->arithMode())) {
1498 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
1499 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
1502 m_out.notZero32(result), usually(continuation), rarely(slowCase));
1504 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1505 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(left, m_out.int32Zero));
1506 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(right, m_out.int32Zero));
1507 m_out.jump(continuation);
1508 m_out.appendTo(continuation, lastNext);
1517 LValue left = lowWhicheverInt52(m_node->child1(), kind);
1518 LValue right = lowInt52(m_node->child2(), opposite(kind));
1520 CheckValue* result = m_out.speculateMul(left, right);
1521 blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
1523 if (shouldCheckNegativeZero(m_node->arithMode())) {
1524 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ArithMul slow case"));
1525 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMul continuation"));
1528 m_out.notZero64(result), usually(continuation), rarely(slowCase));
1530 LBasicBlock lastNext = m_out.appendTo(slowCase, continuation);
1531 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(left, m_out.int64Zero));
1532 speculate(NegativeZero, noValue(), nullptr, m_out.lessThan(right, m_out.int64Zero));
1533 m_out.jump(continuation);
1534 m_out.appendTo(continuation, lastNext);
1541 case DoubleRepUse: {
1543 m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1548 emitBinarySnippet<JITMulGenerator>(operationValueMul);
1553 DFG_CRASH(m_graph, m_node, "Bad use kind");
1558 void compileArithDiv()
1560 switch (m_node->binaryUseKind()) {
1562 LValue numerator = lowInt32(m_node->child1());
1563 LValue denominator = lowInt32(m_node->child2());
1565 if (shouldCheckNegativeZero(m_node->arithMode())) {
1566 LBasicBlock zeroNumerator = FTL_NEW_BLOCK(m_out, ("ArithDiv zero numerator"));
1567 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithDiv numerator continuation"));
1570 m_out.isZero32(numerator),
1571 rarely(zeroNumerator), usually(numeratorContinuation));
1573 LBasicBlock innerLastNext = m_out.appendTo(zeroNumerator, numeratorContinuation);
1576 NegativeZero, noValue(), 0, m_out.lessThan(denominator, m_out.int32Zero));
1578 m_out.jump(numeratorContinuation);
1580 m_out.appendTo(numeratorContinuation, innerLastNext);
1583 if (shouldCheckOverflow(m_node->arithMode())) {
1584 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithDiv unsafe denominator"));
1585 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithDiv continuation"));
1587 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1589 m_out.above(adjustedDenominator, m_out.int32One),
1590 usually(continuation), rarely(unsafeDenominator));
1592 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1593 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1594 speculate(Overflow, noValue(), nullptr, m_out.isZero32(denominator));
1595 speculate(Overflow, noValue(), nullptr, m_out.equal(numerator, neg2ToThe31));
1596 m_out.jump(continuation);
1598 m_out.appendTo(continuation, lastNext);
1599 LValue result = m_out.div(numerator, denominator);
1601 Overflow, noValue(), 0,
1602 m_out.notEqual(m_out.mul(result, denominator), numerator));
1605 setInt32(m_out.chillDiv(numerator, denominator));
1610 case DoubleRepUse: {
1611 setDouble(m_out.doubleDiv(
1612 lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1617 emitBinarySnippet<JITDivGenerator, NeedScratchFPR>(operationValueDiv);
1622 DFG_CRASH(m_graph, m_node, "Bad use kind");
1627 void compileArithMod()
1629 switch (m_node->binaryUseKind()) {
1631 LValue numerator = lowInt32(m_node->child1());
1632 LValue denominator = lowInt32(m_node->child2());
1635 if (shouldCheckOverflow(m_node->arithMode())) {
1636 LBasicBlock unsafeDenominator = FTL_NEW_BLOCK(m_out, ("ArithMod unsafe denominator"));
1637 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMod continuation"));
1639 LValue adjustedDenominator = m_out.add(denominator, m_out.int32One);
1641 m_out.above(adjustedDenominator, m_out.int32One),
1642 usually(continuation), rarely(unsafeDenominator));
1644 LBasicBlock lastNext = m_out.appendTo(unsafeDenominator, continuation);
1645 LValue neg2ToThe31 = m_out.constInt32(-2147483647-1);
1646 speculate(Overflow, noValue(), nullptr, m_out.isZero32(denominator));
1647 speculate(Overflow, noValue(), nullptr, m_out.equal(numerator, neg2ToThe31));
1648 m_out.jump(continuation);
1650 m_out.appendTo(continuation, lastNext);
1651 LValue result = m_out.mod(numerator, denominator);
1654 remainder = m_out.chillMod(numerator, denominator);
1656 if (shouldCheckNegativeZero(m_node->arithMode())) {
1657 LBasicBlock negativeNumerator = FTL_NEW_BLOCK(m_out, ("ArithMod negative numerator"));
1658 LBasicBlock numeratorContinuation = FTL_NEW_BLOCK(m_out, ("ArithMod numerator continuation"));
1661 m_out.lessThan(numerator, m_out.int32Zero),
1662 unsure(negativeNumerator), unsure(numeratorContinuation));
1664 LBasicBlock innerLastNext = m_out.appendTo(negativeNumerator, numeratorContinuation);
1666 speculate(NegativeZero, noValue(), 0, m_out.isZero32(remainder));
1668 m_out.jump(numeratorContinuation);
1670 m_out.appendTo(numeratorContinuation, innerLastNext);
1673 setInt32(remainder);
1677 case DoubleRepUse: {
1679 m_out.doubleMod(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
1684 DFG_CRASH(m_graph, m_node, "Bad use kind");
1689 void compileArithMinOrMax()
1691 switch (m_node->binaryUseKind()) {
1693 LValue left = lowInt32(m_node->child1());
1694 LValue right = lowInt32(m_node->child2());
1698 m_node->op() == ArithMin
1699 ? m_out.lessThan(left, right)
1700 : m_out.lessThan(right, left),
1705 case DoubleRepUse: {
1706 LValue left = lowDouble(m_node->child1());
1707 LValue right = lowDouble(m_node->child2());
1709 LBasicBlock notLessThan = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax not less than"));
1710 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithMin/ArithMax continuation"));
1712 Vector<ValueFromBlock, 2> results;
1714 results.append(m_out.anchor(left));
1716 m_node->op() == ArithMin
1717 ? m_out.doubleLessThan(left, right)
1718 : m_out.doubleGreaterThan(left, right),
1719 unsure(continuation), unsure(notLessThan));
1721 LBasicBlock lastNext = m_out.appendTo(notLessThan, continuation);
1722 results.append(m_out.anchor(m_out.select(
1723 m_node->op() == ArithMin
1724 ? m_out.doubleGreaterThanOrEqual(left, right)
1725 : m_out.doubleLessThanOrEqual(left, right),
1726 right, m_out.constDouble(PNaN))));
1727 m_out.jump(continuation);
1729 m_out.appendTo(continuation, lastNext);
1730 setDouble(m_out.phi(m_out.doubleType, results));
1735 DFG_CRASH(m_graph, m_node, "Bad use kind");
1740 void compileArithAbs()
1742 switch (m_node->child1().useKind()) {
1744 LValue value = lowInt32(m_node->child1());
1746 LValue mask = m_out.aShr(value, m_out.constInt32(31));
1747 LValue result = m_out.bitXor(mask, m_out.add(mask, value));
1749 if (shouldCheckOverflow(m_node->arithMode()))
1750 speculate(Overflow, noValue(), 0, m_out.equal(result, m_out.constInt32(1 << 31)));
1756 case DoubleRepUse: {
1757 setDouble(m_out.doubleAbs(lowDouble(m_node->child1())));
1762 DFG_CRASH(m_graph, m_node, "Bad use kind");
1767 void compileArithSin() { setDouble(m_out.doubleSin(lowDouble(m_node->child1()))); }
1769 void compileArithCos() { setDouble(m_out.doubleCos(lowDouble(m_node->child1()))); }
1771 void compileArithPow()
1773 if (m_node->child2().useKind() == Int32Use)
1774 setDouble(m_out.doublePowi(lowDouble(m_node->child1()), lowInt32(m_node->child2())));
1776 LValue base = lowDouble(m_node->child1());
1777 LValue exponent = lowDouble(m_node->child2());
1779 LBasicBlock integerExponentIsSmallBlock = FTL_NEW_BLOCK(m_out, ("ArithPow test integer exponent is small."));
1780 LBasicBlock integerExponentPowBlock = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, (int)double)."));
1781 LBasicBlock doubleExponentPowBlockEntry = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, double)."));
1782 LBasicBlock nanExceptionExponentIsInfinity = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, check exponent is infinity."));
1783 LBasicBlock nanExceptionBaseIsOne = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, check base is one."));
1784 LBasicBlock powBlock = FTL_NEW_BLOCK(m_out, ("ArithPow regular pow"));
1785 LBasicBlock nanExceptionResultIsNaN = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, result is NaN."));
1786 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithPow continuation"));
1788 LValue integerExponent = m_out.doubleToInt(exponent);
1789 LValue integerExponentConvertedToDouble = m_out.intToDouble(integerExponent);
1790 LValue exponentIsInteger = m_out.doubleEqual(exponent, integerExponentConvertedToDouble);
1791 m_out.branch(exponentIsInteger, unsure(integerExponentIsSmallBlock), unsure(doubleExponentPowBlockEntry));
1793 LBasicBlock lastNext = m_out.appendTo(integerExponentIsSmallBlock, integerExponentPowBlock);
1794 LValue integerExponentBelow1000 = m_out.below(integerExponent, m_out.constInt32(1000));
1795 m_out.branch(integerExponentBelow1000, usually(integerExponentPowBlock), rarely(doubleExponentPowBlockEntry));
1797 m_out.appendTo(integerExponentPowBlock, doubleExponentPowBlockEntry);
1798 ValueFromBlock powDoubleIntResult = m_out.anchor(m_out.doublePowi(base, integerExponent));
1799 m_out.jump(continuation);
1801 // If y is NaN, the result is NaN.
1802 m_out.appendTo(doubleExponentPowBlockEntry, nanExceptionExponentIsInfinity);
1803 LValue exponentIsNaN;
1804 if (provenType(m_node->child2()) & SpecDoubleNaN)
1805 exponentIsNaN = m_out.doubleNotEqualOrUnordered(exponent, exponent);
1807 exponentIsNaN = m_out.booleanFalse;
1808 m_out.branch(exponentIsNaN, rarely(nanExceptionResultIsNaN), usually(nanExceptionExponentIsInfinity));
1810 // If abs(x) is 1 and y is +infinity, the result is NaN.
1811 // If abs(x) is 1 and y is -infinity, the result is NaN.
1812 m_out.appendTo(nanExceptionExponentIsInfinity, nanExceptionBaseIsOne);
1813 LValue absoluteExponent = m_out.doubleAbs(exponent);
1814 LValue absoluteExponentIsInfinity = m_out.doubleEqual(absoluteExponent, m_out.constDouble(std::numeric_limits<double>::infinity()));
1815 m_out.branch(absoluteExponentIsInfinity, rarely(nanExceptionBaseIsOne), usually(powBlock));
1817 m_out.appendTo(nanExceptionBaseIsOne, powBlock);
1818 LValue absoluteBase = m_out.doubleAbs(base);
1819 LValue absoluteBaseIsOne = m_out.doubleEqual(absoluteBase, m_out.constDouble(1));
1820 m_out.branch(absoluteBaseIsOne, unsure(nanExceptionResultIsNaN), unsure(powBlock));
1822 m_out.appendTo(powBlock, nanExceptionResultIsNaN);
1823 ValueFromBlock powResult = m_out.anchor(m_out.doublePow(base, exponent));
1824 m_out.jump(continuation);
1826 m_out.appendTo(nanExceptionResultIsNaN, continuation);
1827 ValueFromBlock pureNan = m_out.anchor(m_out.constDouble(PNaN));
1828 m_out.jump(continuation);
1830 m_out.appendTo(continuation, lastNext);
1831 setDouble(m_out.phi(m_out.doubleType, powDoubleIntResult, powResult, pureNan));
1835 void compileArithRandom()
1837 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
1839 // Inlined WeakRandom::advance().
1840 // uint64_t x = m_low;
1841 void* lowAddress = reinterpret_cast<uint8_t*>(globalObject) + JSGlobalObject::weakRandomOffset() + WeakRandom::lowOffset();
1842 LValue low = m_out.load64(m_out.absolute(lowAddress));
1843 // uint64_t y = m_high;
1844 void* highAddress = reinterpret_cast<uint8_t*>(globalObject) + JSGlobalObject::weakRandomOffset() + WeakRandom::highOffset();
1845 LValue high = m_out.load64(m_out.absolute(highAddress));
1847 m_out.store64(high, m_out.absolute(lowAddress));
1850 LValue phase1 = m_out.bitXor(m_out.shl(low, m_out.constInt64(23)), low);
1853 LValue phase2 = m_out.bitXor(m_out.lShr(phase1, m_out.constInt64(17)), phase1);
1855 // x ^= y ^ (y >> 26);
1856 LValue phase3 = m_out.bitXor(m_out.bitXor(high, m_out.lShr(high, m_out.constInt64(26))), phase2);
1859 m_out.store64(phase3, m_out.absolute(highAddress));
1862 LValue random64 = m_out.add(phase3, high);
1864 // Extract random 53bit. [0, 53] bit is safe integer number ranges in double representation.
1865 LValue random53 = m_out.bitAnd(random64, m_out.constInt64((1ULL << 53) - 1));
1867 LValue double53Integer = m_out.intToDouble(random53);
1869 // Convert `(53bit double integer value) / (1 << 53)` to `(53bit double integer value) * (1.0 / (1 << 53))`.
1870 // In latter case, `1.0 / (1 << 53)` will become a double value represented as (mantissa = 0 & exp = 970, it means 1e-(2**54)).
1871 static const double scale = 1.0 / (1ULL << 53);
1873 // Multiplying 1e-(2**54) with the double integer does not change anything of the mantissa part of the double integer.
1874 // It just reduces the exp part of the given 53bit double integer.
1875 // (Except for 0.0. This is specially handled and in this case, exp just becomes 0.)
1876 // Now we get 53bit precision random double value in [0, 1).
1877 LValue result = m_out.doubleMul(double53Integer, m_out.constDouble(scale));
1882 void compileArithRound()
1884 LBasicBlock realPartIsMoreThanHalf = FTL_NEW_BLOCK(m_out, ("ArithRound should round down"));
1885 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithRound continuation"));
1887 LValue value = lowDouble(m_node->child1());
1888 LValue integerValue = m_out.doubleCeil(value);
1889 ValueFromBlock integerValueResult = m_out.anchor(integerValue);
1891 LValue realPart = m_out.doubleSub(integerValue, value);
1893 m_out.branch(m_out.doubleGreaterThanOrUnordered(realPart, m_out.constDouble(0.5)), unsure(realPartIsMoreThanHalf), unsure(continuation));
1895 LBasicBlock lastNext = m_out.appendTo(realPartIsMoreThanHalf, continuation);
1896 LValue integerValueRoundedDown = m_out.doubleSub(integerValue, m_out.constDouble(1));
1897 ValueFromBlock integerValueRoundedDownResult = m_out.anchor(integerValueRoundedDown);
1898 m_out.jump(continuation);
1899 m_out.appendTo(continuation, lastNext);
1901 LValue result = m_out.phi(m_out.doubleType, integerValueResult, integerValueRoundedDownResult);
1903 if (producesInteger(m_node->arithRoundingMode())) {
1904 LValue integerValue = convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode()));
1905 setInt32(integerValue);
1910 void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); }
1912 void compileArithLog() { setDouble(m_out.doubleLog(lowDouble(m_node->child1()))); }
1914 void compileArithFRound()
1916 setDouble(m_out.fround(lowDouble(m_node->child1())));
1919 void compileArithNegate()
1921 switch (m_node->child1().useKind()) {
1923 LValue value = lowInt32(m_node->child1());
1926 if (!shouldCheckOverflow(m_node->arithMode()))
1927 result = m_out.neg(value);
1928 else if (!shouldCheckNegativeZero(m_node->arithMode())) {
1929 CheckValue* check = m_out.speculateSub(m_out.int32Zero, value);
1930 blessSpeculation(check, Overflow, noValue(), nullptr, m_origin);
1933 speculate(Overflow, noValue(), 0, m_out.testIsZero32(value, m_out.constInt32(0x7fffffff)));
1934 result = m_out.neg(value);
1942 if (!abstractValue(m_node->child1()).couldBeType(SpecInt52)) {
1944 LValue value = lowWhicheverInt52(m_node->child1(), kind);
1945 LValue result = m_out.neg(value);
1946 if (shouldCheckNegativeZero(m_node->arithMode()))
1947 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1948 setInt52(result, kind);
1952 LValue value = lowInt52(m_node->child1());
1953 CheckValue* result = m_out.speculateSub(m_out.int64Zero, value);
1954 blessSpeculation(result, Int52Overflow, noValue(), nullptr, m_origin);
1955 speculate(NegativeZero, noValue(), 0, m_out.isZero64(result));
1960 case DoubleRepUse: {
1961 setDouble(m_out.doubleNeg(lowDouble(m_node->child1())));
1966 DFG_CRASH(m_graph, m_node, "Bad use kind");
1971 void compileBitAnd()
1973 if (m_node->isBinaryUseKind(UntypedUse)) {
1974 emitBinaryBitOpSnippet<JITBitAndGenerator>(operationValueBitAnd);
1977 setInt32(m_out.bitAnd(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1982 if (m_node->isBinaryUseKind(UntypedUse)) {
1983 emitBinaryBitOpSnippet<JITBitOrGenerator>(operationValueBitOr);
1986 setInt32(m_out.bitOr(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1989 void compileBitXor()
1991 if (m_node->isBinaryUseKind(UntypedUse)) {
1992 emitBinaryBitOpSnippet<JITBitXorGenerator>(operationValueBitXor);
1995 setInt32(m_out.bitXor(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
1998 void compileBitRShift()
2000 if (m_node->isBinaryUseKind(UntypedUse)) {
2001 emitRightShiftSnippet(JITRightShiftGenerator::SignedShift);
2004 setInt32(m_out.aShr(
2005 lowInt32(m_node->child1()),
2006 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2009 void compileBitLShift()
2011 if (m_node->isBinaryUseKind(UntypedUse)) {
2012 emitBinaryBitOpSnippet<JITLeftShiftGenerator>(operationValueBitLShift);
2016 lowInt32(m_node->child1()),
2017 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2020 void compileBitURShift()
2022 if (m_node->isBinaryUseKind(UntypedUse)) {
2023 emitRightShiftSnippet(JITRightShiftGenerator::UnsignedShift);
2026 setInt32(m_out.lShr(
2027 lowInt32(m_node->child1()),
2028 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
2031 void compileUInt32ToNumber()
2033 LValue value = lowInt32(m_node->child1());
2035 if (doesOverflow(m_node->arithMode())) {
2036 setDouble(m_out.unsignedToDouble(value));
2040 speculate(Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero));
2044 void compileCheckStructure()
2047 if (m_node->child1()->hasConstant())
2048 exitKind = BadConstantCache;
2050 exitKind = BadCache;
2052 switch (m_node->child1().useKind()) {
2054 case KnownCellUse: {
2055 LValue cell = lowCell(m_node->child1());
2058 m_out.load32(cell, m_heaps.JSCell_structureID), jsValueValue(cell),
2059 exitKind, m_node->structureSet(),
2060 [&] (Structure* structure) {
2061 return weakStructureID(structure);
2066 case CellOrOtherUse: {
2067 LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
2069 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("CheckStructure CellOrOtherUse cell case"));
2070 LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("CheckStructure CellOrOtherUse not cell case"));
2071 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CheckStructure CellOrOtherUse continuation"));
2074 isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase));
2076 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
2078 m_out.load32(value, m_heaps.JSCell_structureID), jsValueValue(value),
2079 exitKind, m_node->structureSet(),
2080 [&] (Structure* structure) {
2081 return weakStructureID(structure);
2083 m_out.jump(continuation);
2085 m_out.appendTo(notCellCase, continuation);
2086 FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecCell | SpecOther, isNotOther(value));
2087 m_out.jump(continuation);
2089 m_out.appendTo(continuation, lastNext);
2094 DFG_CRASH(m_graph, m_node, "Bad use kind");
2099 void compileCheckCell()
2101 LValue cell = lowCell(m_node->child1());
2104 BadCell, jsValueValue(cell), m_node->child1().node(),
2105 m_out.notEqual(cell, weakPointer(m_node->cellOperand()->cell())));
2108 void compileCheckBadCell()
2113 void compileCheckNotEmpty()
2115 speculate(TDZFailure, noValue(), nullptr, m_out.isZero64(lowJSValue(m_node->child1())));
2118 void compileCheckIdent()
2120 UniquedStringImpl* uid = m_node->uidOperand();
2121 if (uid->isSymbol()) {
2122 LValue symbol = lowSymbol(m_node->child1());
2123 LValue stringImpl = m_out.loadPtr(symbol, m_heaps.Symbol_privateName);
2124 speculate(BadIdent, noValue(), nullptr, m_out.notEqual(stringImpl, m_out.constIntPtr(uid)));
2126 LValue string = lowStringIdent(m_node->child1());
2127 LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
2128 speculate(BadIdent, noValue(), nullptr, m_out.notEqual(stringImpl, m_out.constIntPtr(uid)));
2132 void compileGetExecutable()
2134 LValue cell = lowCell(m_node->child1());
2135 speculateFunction(m_node->child1(), cell);
2136 setJSValue(m_out.loadPtr(cell, m_heaps.JSFunction_executable));
2139 void compileArrayifyToStructure()
2141 LValue cell = lowCell(m_node->child1());
2142 LValue property = !!m_node->child2() ? lowInt32(m_node->child2()) : 0;
2144 LBasicBlock unexpectedStructure = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure unexpected structure"));
2145 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayifyToStructure continuation"));
2147 LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2150 m_out.notEqual(structureID, weakStructureID(m_node->structure())),
2151 rarely(unexpectedStructure), usually(continuation));
2153 LBasicBlock lastNext = m_out.appendTo(unexpectedStructure, continuation);
2156 switch (m_node->arrayMode().type()) {
2159 case Array::Contiguous:
2161 Uncountable, noValue(), 0,
2162 m_out.aboveOrEqual(property, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)));
2169 switch (m_node->arrayMode().type()) {
2171 vmCall(m_out.voidType, m_out.operation(operationEnsureInt32), m_callFrame, cell);
2174 vmCall(m_out.voidType, m_out.operation(operationEnsureDouble), m_callFrame, cell);
2176 case Array::Contiguous:
2177 vmCall(m_out.voidType, m_out.operation(operationEnsureContiguous), m_callFrame, cell);
2179 case Array::ArrayStorage:
2180 case Array::SlowPutArrayStorage:
2181 vmCall(m_out.voidType, m_out.operation(operationEnsureArrayStorage), m_callFrame, cell);
2184 DFG_CRASH(m_graph, m_node, "Bad array type");
2188 structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
2190 BadIndexingType, jsValueValue(cell), 0,
2191 m_out.notEqual(structureID, weakStructureID(m_node->structure())));
2192 m_out.jump(continuation);
2194 m_out.appendTo(continuation, lastNext);
2197 void compilePutStructure()
2199 m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
2201 Structure* oldStructure = m_node->transition()->previous;
2202 Structure* newStructure = m_node->transition()->next;
2203 ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType());
2204 ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags());
2205 ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type());
2207 LValue cell = lowCell(m_node->child1());
2209 weakStructureID(newStructure),
2210 cell, m_heaps.JSCell_structureID);
2213 void compileGetById()
2215 switch (m_node->child1().useKind()) {
2217 setJSValue(getById(lowCell(m_node->child1())));
2222 // This is pretty weird, since we duplicate the slow path both here and in the
2223 // code generated by the IC. We should investigate making this less bad.
2224 // https://bugs.webkit.org/show_bug.cgi?id=127830
2225 LValue value = lowJSValue(m_node->child1());
2227 LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("GetById untyped cell case"));
2228 LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("GetById untyped not cell case"));
2229 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetById untyped continuation"));
2232 isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase));
2234 LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase);
2235 ValueFromBlock cellResult = m_out.anchor(getById(value));
2236 m_out.jump(continuation);
2238 m_out.appendTo(notCellCase, continuation);
2239 ValueFromBlock notCellResult = m_out.anchor(vmCall(
2240 m_out.int64, m_out.operation(operationGetByIdGeneric),
2242 m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()])));
2243 m_out.jump(continuation);
2245 m_out.appendTo(continuation, lastNext);
2246 setJSValue(m_out.phi(m_out.int64, cellResult, notCellResult));
2251 DFG_CRASH(m_graph, m_node, "Bad use kind");
2256 void compilePutById()
2258 Node* node = m_node;
2260 // See above; CellUse is easier so we do only that for now.
2261 ASSERT(node->child1().useKind() == CellUse);
2263 LValue base = lowCell(node->child1());
2264 LValue value = lowJSValue(node->child2());
2265 auto uid = m_graph.identifiers()[node->identifierNumber()];
2267 B3::PatchpointValue* patchpoint = m_out.patchpoint(Void);
2268 patchpoint->appendSomeRegister(base);
2269 patchpoint->appendSomeRegister(value);
2270 patchpoint->clobber(RegisterSet::macroScratchRegisters());
2272 // FIXME: If this is a PutByIdFlush, we might want to late-clobber volatile registers.
2273 // https://bugs.webkit.org/show_bug.cgi?id=152848
2275 RefPtr<PatchpointExceptionHandle> exceptionHandle =
2276 preparePatchpointForExceptions(patchpoint);
2278 State* state = &m_ftlState;
2279 ECMAMode ecmaMode = m_graph.executableFor(node->origin.semantic)->ecmaMode();
2281 patchpoint->setGenerator(
2282 [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
2283 AllowMacroScratchRegisterUsage allowScratch(jit);
2285 CallSiteIndex callSiteIndex =
2286 state->jitCode->common.addUniqueCallSiteIndex(node->origin.semantic);
2288 Box<CCallHelpers::JumpList> exceptions =
2289 exceptionHandle->scheduleExitCreation(params)->jumps(jit);
2291 // JS setter call ICs generated by the PutById IC will need this.
2292 exceptionHandle->scheduleExitCreationForUnwind(params, callSiteIndex);
2294 auto generator = Box<JITPutByIdGenerator>::create(
2295 jit.codeBlock(), node->origin.semantic, callSiteIndex,
2296 params.unavailableRegisters(), JSValueRegs(params[0].gpr()),
2297 JSValueRegs(params[1].gpr()), GPRInfo::patchpointScratchRegister, ecmaMode,
2298 node->op() == PutByIdDirect ? Direct : NotDirect);
2300 generator->generateFastPath(jit);
2301 CCallHelpers::Label done = jit.label();
2304 [=] (CCallHelpers& jit) {
2305 AllowMacroScratchRegisterUsage allowScratch(jit);
2307 generator->slowPathJump().link(&jit);
2308 CCallHelpers::Label slowPathBegin = jit.label();
2309 CCallHelpers::Call slowPathCall = callOperation(
2310 *state, params.unavailableRegisters(), jit, node->origin.semantic,
2311 exceptions.get(), generator->slowPathFunction(), InvalidGPRReg,
2312 CCallHelpers::TrustedImmPtr(generator->stubInfo()), params[1].gpr(),
2313 params[0].gpr(), CCallHelpers::TrustedImmPtr(uid)).call();
2314 jit.jump().linkTo(done, &jit);
2316 generator->reportSlowPathCall(slowPathBegin, slowPathCall);
2319 [=] (LinkBuffer& linkBuffer) {
2320 generator->finalize(linkBuffer);
2326 void compileGetButterfly()
2328 setStorage(loadButterflyWithBarrier(lowCell(m_node->child1())));
2331 void compileGetButterflyReadOnly()
2333 setStorage(loadButterflyReadOnly(lowCell(m_node->child1())));
2336 void compileConstantStoragePointer()
2338 setStorage(m_out.constIntPtr(m_node->storagePointer()));
2341 void compileGetIndexedPropertyStorage()
2343 LValue cell = lowCell(m_node->child1());
2345 if (m_node->arrayMode().type() == Array::String) {
2346 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String slow case"));
2347 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetIndexedPropertyStorage String continuation"));
2349 LValue fastResultValue = m_out.loadPtr(cell, m_heaps.JSString_value);
2350 ValueFromBlock fastResult = m_out.anchor(fastResultValue);
2353 m_out.notNull(fastResultValue), usually(continuation), rarely(slowPath));
2355 LBasicBlock lastNext = m_out.appendTo(slowPath, continuation);
2357 ValueFromBlock slowResult = m_out.anchor(
2358 vmCall(m_out.intPtr, m_out.operation(operationResolveRope), m_callFrame, cell));
2360 m_out.jump(continuation);
2362 m_out.appendTo(continuation, lastNext);
2364 setStorage(m_out.loadPtr(m_out.phi(m_out.intPtr, fastResult, slowResult), m_heaps.StringImpl_data));
2368 setStorage(loadVectorWithBarrier(cell));
2371 void compileCheckArray()
2373 Edge edge = m_node->child1();
2374 LValue cell = lowCell(edge);
2376 if (m_node->arrayMode().alreadyChecked(m_graph, m_node, abstractValue(edge)))
2380 BadIndexingType, jsValueValue(cell), 0,
2381 m_out.logicalNot(isArrayType(cell, m_node->arrayMode())));
2384 void compileGetTypedArrayByteOffset()
2386 LValue basePtr = lowCell(m_node->child1());
2388 LBasicBlock simpleCase = FTL_NEW_BLOCK(m_out, ("GetTypedArrayByteOffset wasteless typed array"));
2389 LBasicBlock wastefulCase = FTL_NEW_BLOCK(m_out, ("GetTypedArrayByteOffset wasteful typed array"));
2390 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetTypedArrayByteOffset continuation"));
2392 LValue mode = m_out.load32(basePtr, m_heaps.JSArrayBufferView_mode);
2394 m_out.notEqual(mode, m_out.constInt32(WastefulTypedArray)),
2395 unsure(simpleCase), unsure(wastefulCase));
2397 LBasicBlock lastNext = m_out.appendTo(simpleCase, wastefulCase);
2399 ValueFromBlock simpleOut = m_out.anchor(m_out.constIntPtr(0));
2401 m_out.jump(continuation);
2403 m_out.appendTo(wastefulCase, continuation);
2405 LValue vectorPtr = loadVectorReadOnly(basePtr);
2406 LValue butterflyPtr = loadButterflyReadOnly(basePtr);
2407 LValue arrayBufferPtr = m_out.loadPtr(butterflyPtr, m_heaps.Butterfly_arrayBuffer);
2408 LValue dataPtr = m_out.loadPtr(arrayBufferPtr, m_heaps.ArrayBuffer_data);
2410 ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(vectorPtr, dataPtr));
2412 m_out.jump(continuation);
2413 m_out.appendTo(continuation, lastNext);
2415 setInt32(m_out.castToInt32(m_out.phi(m_out.intPtr, simpleOut, wastefulOut)));
2418 void compileGetArrayLength()
2420 switch (m_node->arrayMode().type()) {
2423 case Array::Contiguous: {
2424 setInt32(m_out.load32NonNegative(lowStorage(m_node->child2()), m_heaps.Butterfly_publicLength));
2428 case Array::String: {
2429 LValue string = lowCell(m_node->child1());
2430 setInt32(m_out.load32NonNegative(string, m_heaps.JSString_length));
2434 case Array::DirectArguments: {
2435 LValue arguments = lowCell(m_node->child1());
2437 ExoticObjectMode, noValue(), nullptr,
2438 m_out.notNull(m_out.loadPtr(arguments, m_heaps.DirectArguments_overrides)));
2439 setInt32(m_out.load32NonNegative(arguments, m_heaps.DirectArguments_length));
2443 case Array::ScopedArguments: {
2444 LValue arguments = lowCell(m_node->child1());
2446 ExoticObjectMode, noValue(), nullptr,
2447 m_out.notZero32(m_out.load8ZeroExt32(arguments, m_heaps.ScopedArguments_overrodeThings)));
2448 setInt32(m_out.load32NonNegative(arguments, m_heaps.ScopedArguments_totalLength));
2453 if (m_node->arrayMode().isSomeTypedArrayView()) {
2455 m_out.load32NonNegative(lowCell(m_node->child1()), m_heaps.JSArrayBufferView_length));
2459 DFG_CRASH(m_graph, m_node, "Bad array type");
2464 void compileCheckInBounds()
2467 OutOfBounds, noValue(), 0,
2468 m_out.aboveOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
2471 void compileGetByVal()
2473 switch (m_node->arrayMode().type()) {
2475 case Array::Contiguous: {
2476 LValue index = lowInt32(m_node->child2());
2477 LValue storage = lowStorage(m_node->child3());
2479 IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ?
2480 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
2482 if (m_node->arrayMode().isInBounds()) {
2483 LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
2484 LValue isHole = m_out.isZero64(result);
2485 if (m_node->arrayMode().isSaneChain()) {
2487 m_graph, m_node, m_node->arrayMode().type() == Array::Contiguous);
2488 result = m_out.select(
2489 isHole, m_out.constInt64(JSValue::encode(jsUndefined())), result);
2491 speculate(LoadFromHole, noValue(), 0, isHole);
2496 LValue base = lowCell(m_node->child1());
2498 LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous fast case"));
2499 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous slow case"));
2500 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal int/contiguous continuation"));
2504 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2505 rarely(slowCase), usually(fastCase));
2507 LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase);
2509 LValue fastResultValue = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
2510 ValueFromBlock fastResult = m_out.anchor(fastResultValue);
2512 m_out.isZero64(fastResultValue), rarely(slowCase), usually(continuation));
2514 m_out.appendTo(slowCase, continuation);
2515 ValueFromBlock slowResult = m_out.anchor(
2516 vmCall(m_out.int64, m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2517 m_out.jump(continuation);
2519 m_out.appendTo(continuation, lastNext);
2520 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2524 case Array::Double: {
2525 LValue index = lowInt32(m_node->child2());
2526 LValue storage = lowStorage(m_node->child3());
2528 IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
2530 if (m_node->arrayMode().isInBounds()) {
2531 LValue result = m_out.loadDouble(
2532 baseIndex(heap, storage, index, m_node->child2()));
2534 if (!m_node->arrayMode().isSaneChain()) {
2536 LoadFromHole, noValue(), 0,
2537 m_out.doubleNotEqualOrUnordered(result, result));
2543 LValue base = lowCell(m_node->child1());
2545 LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetByVal double in bounds"));
2546 LBasicBlock boxPath = FTL_NEW_BLOCK(m_out, ("GetByVal double boxing"));
2547 LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetByVal double slow case"));
2548 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal double continuation"));
2552 index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
2553 rarely(slowCase), usually(inBounds));
2555 LBasicBlock lastNext = m_out.appendTo(inBounds, boxPath);
2556 LValue doubleValue = m_out.loadDouble(
2557 baseIndex(heap, storage, index, m_node->child2()));
2559 m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue),
2560 rarely(slowCase), usually(boxPath));
2562 m_out.appendTo(boxPath, slowCase);
2563 ValueFromBlock fastResult = m_out.anchor(boxDouble(doubleValue));
2564 m_out.jump(continuation);
2566 m_out.appendTo(slowCase, continuation);
2567 ValueFromBlock slowResult = m_out.anchor(
2568 vmCall(m_out.int64, m_out.operation(operationGetByValArrayInt), m_callFrame, base, index));
2569 m_out.jump(continuation);
2571 m_out.appendTo(continuation, lastNext);
2572 setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
2576 case Array::Undecided: {
2577 LValue index = lowInt32(m_node->child2());
2579 speculate(OutOfBounds, noValue(), m_node, m_out.lessThan(index, m_out.int32Zero));
2580 setJSValue(m_out.constInt64(ValueUndefined));
2584 case Array::DirectArguments: {
2585 LValue base = lowCell(m_node->child1());
2586 LValue index = lowInt32(m_node->child2());
2589 ExoticObjectMode, noValue(), nullptr,
2590 m_out.notNull(m_out.loadPtr(base, m_heaps.DirectArguments_overrides)));
2592 ExoticObjectMode, noValue(), nullptr,
2595 m_out.load32NonNegative(base, m_heaps.DirectArguments_length)));
2597 TypedPointer address = m_out.baseIndex(
2598 m_heaps.DirectArguments_storage, base, m_out.zeroExtPtr(index));
2599 setJSValue(m_out.load64(address));
2603 case Array::ScopedArguments: {
2604 LValue base = lowCell(m_node->child1());
2605 LValue index = lowInt32(m_node->child2());
2608 ExoticObjectMode, noValue(), nullptr,
2611 m_out.load32NonNegative(base, m_heaps.ScopedArguments_totalLength)));
2613 LValue table = m_out.loadPtr(base, m_heaps.ScopedArguments_table);
2614 LValue namedLength = m_out.load32(table, m_heaps.ScopedArgumentsTable_length);
2616 LBasicBlock namedCase = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments named case"));
2617 LBasicBlock overflowCase = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments overflow case"));
2618 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments continuation"));
2621 m_out.aboveOrEqual(index, namedLength), unsure(overflowCase), unsure(namedCase));
2623 LBasicBlock lastNext = m_out.appendTo(namedCase, overflowCase);
2625 LValue scope = m_out.loadPtr(base, m_heaps.ScopedArguments_scope);
2626 LValue arguments = m_out.loadPtr(table, m_heaps.ScopedArgumentsTable_arguments);
2628 TypedPointer address = m_out.baseIndex(
2629 m_heaps.scopedArgumentsTableArguments, arguments, m_out.zeroExtPtr(index));
2630 LValue scopeOffset = m_out.load32(address);
2633 ExoticObjectMode, noValue(), nullptr,
2634 m_out.equal(scopeOffset, m_out.constInt32(ScopeOffset::invalidOffset)));
2636 address = m_out.baseIndex(
2637 m_heaps.JSEnvironmentRecord_variables, scope, m_out.zeroExtPtr(scopeOffset));
2638 ValueFromBlock namedResult = m_out.anchor(m_out.load64(address));
2639 m_out.jump(continuation);
2641 m_out.appendTo(overflowCase, continuation);
2643 address = m_out.baseIndex(
2644 m_heaps.ScopedArguments_overflowStorage, base,
2645 m_out.zeroExtPtr(m_out.sub(index, namedLength)));
2646 LValue overflowValue = m_out.load64(address);
2647 speculate(ExoticObjectMode, noValue(), nullptr, m_out.isZero64(overflowValue));
2648 ValueFromBlock overflowResult = m_out.anchor(overflowValue);
2649 m_out.jump(continuation);
2651 m_out.appendTo(continuation, lastNext);
2652 setJSValue(m_out.phi(m_out.int64, namedResult, overflowResult));
2656 case Array::Generic: {
2658 m_out.int64, m_out.operation(operationGetByVal), m_callFrame,
2659 lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
2663 case Array::String: {
2664 compileStringCharAt();
2669 LValue index = lowInt32(m_node->child2());
2670 LValue storage = lowStorage(m_node->child3());
2672 TypedArrayType type = m_node->arrayMode().typedArrayType();
2674 if (isTypedView(type)) {
2675 TypedPointer pointer = TypedPointer(
2676 m_heaps.typedArrayProperties,
2680 m_out.zeroExtPtr(index),
2681 m_out.constIntPtr(logElementSize(type)))));
2685 switch (elementSize(type)) {
2687 result = isSigned(type) ? m_out.load8SignExt32(pointer) : m_out.load8ZeroExt32(pointer);
2690 result = isSigned(type) ? m_out.load16SignExt32(pointer) : m_out.load16ZeroExt32(pointer);
2693 result = m_out.load32(pointer);
2696 DFG_CRASH(m_graph, m_node, "Bad element size");
2699 if (elementSize(type) < 4 || isSigned(type)) {
2704 if (m_node->shouldSpeculateInt32()) {
2706 Overflow, noValue(), 0, m_out.lessThan(result, m_out.int32Zero));
2711 if (m_node->shouldSpeculateMachineInt()) {
2712 setStrictInt52(m_out.zeroExt(result, m_out.int64));
2716 setDouble(m_out.unsignedToDouble(result));
2720 ASSERT(isFloat(type));
2725 result = m_out.floatToDouble(m_out.loadFloat(pointer));
2728 result = m_out.loadDouble(pointer);
2731 DFG_CRASH(m_graph, m_node, "Bad typed array type");
2738 DFG_CRASH(m_graph, m_node, "Bad array type");
2743 void compileGetMyArgumentByVal()
2745 InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame;
2747 LValue index = lowInt32(m_node->child2());
2750 if (inlineCallFrame && !inlineCallFrame->isVarargs())
2751 limit = m_out.constInt32(inlineCallFrame->arguments.size() - 1);
2753 VirtualRegister argumentCountRegister;
2754 if (!inlineCallFrame)
2755 argumentCountRegister = VirtualRegister(JSStack::ArgumentCount);
2757 argumentCountRegister = inlineCallFrame->argumentCountRegister;
2758 limit = m_out.sub(m_out.load32(payloadFor(argumentCountRegister)), m_out.int32One);
2761 speculate(ExoticObjectMode, noValue(), 0, m_out.aboveOrEqual(index, limit));
2764 if (inlineCallFrame) {
2765 if (inlineCallFrame->arguments.size() <= 1) {
2766 // We should have already exited due to the bounds check, above. Just tell the
2767 // compiler that anything dominated by this instruction is not reachable, so
2768 // that we don't waste time generating such code. This will also plant some
2769 // kind of crashing instruction so that if by some fluke the bounds check didn't
2770 // work, we'll crash in an easy-to-see way.
2771 didAlreadyTerminate();
2774 base = addressFor(inlineCallFrame->arguments[1].virtualRegister());
2776 base = addressFor(virtualRegisterForArgument(1));
2778 LValue pointer = m_out.baseIndex(
2779 base.value(), m_out.zeroExt(index, m_out.intPtr), ScaleEight);
2780 setJSValue(m_out.load64(TypedPointer(m_heaps.variables.atAnyIndex(), pointer)));
2783 void compilePutByVal()
2785 Edge child1 = m_graph.varArgChild(m_node, 0);
2786 Edge child2 = m_graph.varArgChild(m_node, 1);
2787 Edge child3 = m_graph.varArgChild(m_node, 2);
2788 Edge child4 = m_graph.varArgChild(m_node, 3);
2789 Edge child5 = m_graph.varArgChild(m_node, 4);
2791 switch (m_node->arrayMode().type()) {
2792 case Array::Generic: {
2793 V_JITOperation_EJJJ operation;
2794 if (m_node->op() == PutByValDirect) {
2795 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2796 operation = operationPutByValDirectStrict;
2798 operation = operationPutByValDirectNonStrict;
2800 if (m_graph.isStrictModeFor(m_node->origin.semantic))
2801 operation = operationPutByValStrict;
2803 operation = operationPutByValNonStrict;
2807 m_out.voidType, m_out.operation(operation), m_callFrame,
2808 lowJSValue(child1), lowJSValue(child2), lowJSValue(child3));
2816 LValue base = lowCell(child1);
2817 LValue index = lowInt32(child2);
2818 LValue storage = lowStorage(child4);
2820 switch (m_node->arrayMode().type()) {
2823 case Array::Contiguous: {
2824 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal continuation"));
2825 LBasicBlock outerLastNext = m_out.appendTo(m_out.m_block, continuation);
2827 switch (m_node->arrayMode().type()) {
2829 case Array::Contiguous: {
2830 LValue value = lowJSValue(child3, ManualOperandSpeculation);
2832 if (m_node->arrayMode().type() == Array::Int32)
2833 FTL_TYPE_CHECK(jsValueValue(value), child3, SpecInt32, isNotInt32(value));
2835 TypedPointer elementPointer = m_out.baseIndex(
2836 m_node->arrayMode().type() == Array::Int32 ?
2837 m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties,
2838 storage, m_out.zeroExtPtr(index), provenValue(child2));
2840 if (m_node->op() == PutByValAlias) {
2841 m_out.store64(value, elementPointer);
2845 contiguousPutByValOutOfBounds(
2846 codeBlock()->isStrictMode()
2847 ? operationPutByValBeyondArrayBoundsStrict
2848 : operationPutByValBeyondArrayBoundsNonStrict,
2849 base, storage, index, value, continuation);
2851 m_out.store64(value, elementPointer);
2855 case Array::Double: {
2856 LValue value = lowDouble(child3);
2859 doubleValue(value), child3, SpecDoubleReal,
2860 m_out.doubleNotEqualOrUnordered(value, value));
2862 TypedPointer elementPointer = m_out.baseIndex(
2863 m_heaps.indexedDoubleProperties, storage, m_out.zeroExtPtr(index),
2864 provenValue(child2));
2866 if (m_node->op() == PutByValAlias) {
2867 m_out.storeDouble(value, elementPointer);
2871 contiguousPutByValOutOfBounds(
2872 codeBlock()->isStrictMode()
2873 ? operationPutDoubleByValBeyondArrayBoundsStrict
2874 : operationPutDoubleByValBeyondArrayBoundsNonStrict,
2875 base, storage, index, value, continuation);
2877 m_out.storeDouble(value, elementPointer);
2882 DFG_CRASH(m_graph, m_node, "Bad array type");
2885 m_out.jump(continuation);
2886 m_out.appendTo(continuation, outerLastNext);
2891 TypedArrayType type = m_node->arrayMode().typedArrayType();
2893 if (isTypedView(type)) {
2894 TypedPointer pointer = TypedPointer(
2895 m_heaps.typedArrayProperties,
2899 m_out.zeroExt(index, m_out.intPtr),
2900 m_out.constIntPtr(logElementSize(type)))));
2902 Output::StoreType storeType;
2903 LValue valueToStore;
2907 switch (child3.useKind()) {
2910 if (child3.useKind() == Int32Use)
2911 intValue = lowInt32(child3);
2913 intValue = m_out.castToInt32(lowStrictInt52(child3));
2915 if (isClamped(type)) {
2916 ASSERT(elementSize(type) == 1);
2918 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp atLeastZero"));
2919 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal int clamp continuation"));
2921 Vector<ValueFromBlock, 2> intValues;
2922 intValues.append(m_out.anchor(m_out.int32Zero));
2924 m_out.lessThan(intValue, m_out.int32Zero),
2925 unsure(continuation), unsure(atLeastZero));
2927 LBasicBlock lastNext = m_out.appendTo(atLeastZero, continuation);
2929 intValues.append(m_out.anchor(m_out.select(
2930 m_out.greaterThan(intValue, m_out.constInt32(255)),
2931 m_out.constInt32(255),
2933 m_out.jump(continuation);
2935 m_out.appendTo(continuation, lastNext);
2936 intValue = m_out.phi(m_out.int32, intValues);
2941 case DoubleRepUse: {
2942 LValue doubleValue = lowDouble(child3);
2944 if (isClamped(type)) {
2945 ASSERT(elementSize(type) == 1);
2947 LBasicBlock atLeastZero = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp atLeastZero"));
2948 LBasicBlock withinRange = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp withinRange"));
2949 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal double clamp continuation"));
2951 Vector<ValueFromBlock, 3> intValues;
2952 intValues.append(m_out.anchor(m_out.int32Zero));
2954 m_out.doubleLessThanOrUnordered(doubleValue, m_out.doubleZero),
2955 unsure(continuation), unsure(atLeastZero));
2957 LBasicBlock lastNext = m_out.appendTo(atLeastZero, withinRange);
2958 intValues.append(m_out.anchor(m_out.constInt32(255)));
2960 m_out.doubleGreaterThan(doubleValue, m_out.constDouble(255)),
2961 unsure(continuation), unsure(withinRange));
2963 m_out.appendTo(withinRange, continuation);
2964 intValues.append(m_out.anchor(m_out.doubleToInt(doubleValue)));
2965 m_out.jump(continuation);
2967 m_out.appendTo(continuation, lastNext);
2968 intValue = m_out.phi(m_out.int32, intValues);
2970 intValue = doubleToInt32(doubleValue);
2975 DFG_CRASH(m_graph, m_node, "Bad use kind");
2978 valueToStore = intValue;
2979 switch (elementSize(type)) {
2981 storeType = Output::Store32As8;
2984 storeType = Output::Store32As16;
2987 storeType = Output::Store32;
2990 DFG_CRASH(m_graph, m_node, "Bad element size");
2992 } else /* !isInt(type) */ {
2993 LValue value = lowDouble(child3);
2996 valueToStore = m_out.doubleToFloat(value);
2997 storeType = Output::StoreFloat;
3000 valueToStore = value;
3001 storeType = Output::StoreDouble;
3004 DFG_CRASH(m_graph, m_node, "Bad typed array type");
3008 if (m_node->arrayMode().isInBounds() || m_node->op() == PutByValAlias)
3009 m_out.store(valueToStore, pointer, storeType);
3011 LBasicBlock isInBounds = FTL_NEW_BLOCK(m_out, ("PutByVal typed array in bounds case"));
3012 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("PutByVal typed array continuation"));
3015 m_out.aboveOrEqual(index, lowInt32(child5)),
3016 unsure(continuation), unsure(isInBounds));
3018 LBasicBlock lastNext = m_out.appendTo(isInBounds, continuation);
3019 m_out.store(valueToStore, pointer, storeType);
3020 m_out.jump(continuation);
3022 m_out.appendTo(continuation, lastNext);
3028 DFG_CRASH(m_graph, m_node, "Bad array type");
3033 void compilePutAccessorById()
3035 LValue base = lowCell(m_node->child1());
3036 LValue accessor = lowCell(m_node->child2());
3037 auto uid = m_graph.identifiers()[m_node->identifierNumber()];
3040 m_out.operation(m_node->op() == PutGetterById ? operationPutGetterById : operationPutSetterById),
3041 m_callFrame, base, m_out.constIntPtr(uid), m_out.constInt32(m_node->accessorAttributes()), accessor);
3044 void compilePutGetterSetterById()
3046 LValue base = lowCell(m_node->child1());
3047 LValue getter = lowJSValue(m_node->child2());
3048 LValue setter = lowJSValue(m_node->child3());
3049 auto uid = m_graph.identifiers()[m_node->identifierNumber()];
3051 m_out.voidType, m_out.operation(operationPutGetterSetter),
3052 m_callFrame, base, m_out.constIntPtr(uid), m_out.constInt32(m_node->accessorAttributes()), getter, setter);
3056 void compilePutAccessorByVal()
3058 LValue base = lowCell(m_node->child1());
3059 LValue subscript = lowJSValue(m_node->child2());
3060 LValue accessor = lowCell(m_node->child3());
3063 m_out.operation(m_node->op() == PutGetterByVal ? operationPutGetterByVal : operationPutSetterByVal),
3064 m_callFrame, base, subscript, m_out.constInt32(m_node->accessorAttributes()), accessor);
3067 void compileArrayPush()
3069 LValue base = lowCell(m_node->child1());
3070 LValue storage = lowStorage(m_node->child3());
3072 switch (m_node->arrayMode().type()) {
3074 case Array::Contiguous:
3075 case Array::Double: {
3077 Output::StoreType storeType;
3079 if (m_node->arrayMode().type() != Array::Double) {
3080 value = lowJSValue(m_node->child2(), ManualOperandSpeculation);
3081 if (m_node->arrayMode().type() == Array::Int32) {
3083 jsValueValue(value), m_node->child2(), SpecInt32, isNotInt32(value));
3085 storeType = Output::Store64;
3087 value = lowDouble(m_node->child2());
3089 doubleValue(value), m_node->child2(), SpecDoubleReal,
3090 m_out.doubleNotEqualOrUnordered(value, value));
3091 storeType = Output::StoreDouble;
3094 IndexedAbstractHeap& heap = m_heaps.forArrayType(m_node->arrayMode().type());
3096 LValue prevLength = m_out.load32(storage, m_heaps.Butterfly_publicLength);
3098 LBasicBlock fastPath = FTL_NEW_BLOCK(m_out, ("ArrayPush fast path"));
3099 LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("ArrayPush slow path"));
3100 LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArrayPush continuation"));